readufs.c revision 1.5 1 /* $NetBSD: readufs.c,v 1.5 2003/12/04 13:05:17 keihan Exp $ */
2 /* from Id: readufs.c,v 1.8 2003/04/08 09:19:32 itohy Exp */
3
4 /*
5 * Read UFS (FFS / LFS)
6 *
7 * Written in 1999, 2002, 2003 by ITOH Yasufumi (itohy (at) NetBSD.org).
8 * Public domain.
9 *
10 * Intended to be used for boot programs (first stage).
11 * DON'T ADD ANY FANCY FEATURE. THIS SHALL BE COMPACT.
12 */
13
14 #include "readufs.h"
15
16 #define fs ufs_info
17
18 static void raw_read_queue __P((void *buf, daddr_t blkpos, size_t bytelen));
19 static int ufs_read_indirect __P((daddr_t blk, int level, caddr_t *buf,
20 unsigned *poff, size_t count));
21
22 #ifdef DEBUG_WITH_STDIO
23 void ufs_list_dir __P((ino_t dirino));
24 int main __P((int argc, char *argv[]));
25 #endif
26
27 #ifdef DEBUG_WITH_STDIO
28 int fd;
29
30 void
31 RAW_READ(buf, blkpos, bytelen)
32 void *buf;
33 daddr_t blkpos;
34 size_t bytelen;
35 {
36
37 if (pread(fd, buf, bytelen, (off_t)dbtob(blkpos)) != (ssize_t) bytelen)
38 err(1, "pread: buf %p, blk %d, len %u",
39 buf, (int) blkpos, bytelen);
40 }
41 #endif
42
43 struct ufs_info fs;
44
45 /*
46 * Read contiguous sectors at once for speedup.
47 */
48 static size_t rq_len;
49
50 static void
51 raw_read_queue(buf, blkpos, bytelen)
52 void *buf;
53 daddr_t blkpos;
54 size_t bytelen; /* must be DEV_BSIZE aligned */
55 {
56 static daddr_t rq_start;
57 static char *rq_buf;
58
59 if (rq_len) {
60 if (bytelen && blkpos == rq_start + (ssize_t) btodb(rq_len)
61 && buf == rq_buf + rq_len) {
62 rq_len += bytelen;
63 return;
64 } else {
65 #ifdef DEBUG_WITH_STDIO
66 printf("raw_read_queue: read: buf %p, blk %d, len %d\n",
67 rq_buf, (int) rq_start, rq_len);
68 #endif
69 RAW_READ(rq_buf, rq_start, rq_len);
70 }
71 }
72 rq_buf = buf;
73 rq_start = blkpos;
74 rq_len = bytelen;
75 }
76
77 #define RAW_READ_QUEUE_INIT() (rq_len = 0)
78 #define RAW_READ_QUEUE_FLUSH() \
79 raw_read_queue((void *) 0, (daddr_t) 0, (size_t) 0)
80
81
82 /*
83 * Read a file, specified by dinode.
84 * No support for holes or (short) symbolic links.
85 */
86 size_t
87 ufs_read(di, buf, off, count)
88 union ufs_dinode *di;
89 void *buf;
90 unsigned off; /* position in block */
91 size_t count;
92 {
93 struct ufs_info *ufsinfo = &fs;
94 size_t bsize = ufsinfo->bsize;
95 caddr_t b = buf;
96 int i;
97 size_t disize, nread;
98 daddr_t pos;
99 #if defined(USE_UFS1) && defined(USE_UFS2)
100 enum ufs_ufstype uver = ufsinfo->ufstype;
101 #endif
102
103 #ifdef DEBUG_WITH_STDIO
104 printf("ufs_read: off: %d, count %u\n", off, count);
105 #endif
106
107 disize = DI_SIZE(di);
108
109 if (disize < count + off * bsize)
110 count = disize - off * bsize;
111
112 /* FS block size alignment. */
113 nread = count;
114 count = (count + bsize - 1) & ~(bsize - 1);
115
116 RAW_READ_QUEUE_INIT();
117
118 /* Read direct blocks. */
119 for ( ; off < NDADDR && count > 0; off++) {
120 #if defined(USE_UFS1) && defined(USE_UFS2)
121 if (uver == UFSTYPE_UFS1)
122 pos = di->di1.di_db[off];
123 else
124 pos = di->di2.di_db[off];
125 #else
126 pos = di->di_thisver.di_db[off];
127 #endif
128 #if 0
129 printf("ufs_read: read: blk: %d\n",
130 (int) pos << ufsinfo->fsbtodb);
131 #endif
132 raw_read_queue(b, pos << ufsinfo->fsbtodb, bsize);
133 b += bsize;
134 count -= bsize;
135 }
136 off -= NDADDR;
137
138 /* Read indirect blocks. */
139 for (i = 0; i < NIADDR && count > 0; i++) {
140 #if defined(USE_UFS1) && defined(USE_UFS2)
141 if (uver == UFSTYPE_UFS1)
142 pos = di->di1.di_ib[i];
143 else
144 pos = di->di2.di_ib[i];
145 #else
146 pos = di->di_thisver.di_ib[i];
147 #endif
148 count = ufs_read_indirect(pos, i, &b, &off, count);
149 }
150
151 RAW_READ_QUEUE_FLUSH();
152
153 return nread;
154 }
155
156 static int
157 ufs_read_indirect(blk, level, buf, poff, count)
158 daddr_t blk;
159 int level;
160 caddr_t *buf;
161 unsigned *poff; /* position in block */
162 size_t count;
163 {
164 struct ufs_info *ufsinfo = &fs;
165 size_t bsize = ufsinfo->bsize;
166 void *idbuf = alloca(bsize);
167 #ifdef USE_UFS1
168 int32_t *idbuf1 = idbuf;
169 #endif
170 #ifdef USE_UFS2
171 int64_t *idbuf2 = idbuf;
172 #endif
173 daddr_t pos;
174 unsigned off = *poff;
175 unsigned b;
176
177 #ifdef DEBUG_WITH_STDIO
178 printf("ufs_read_indirect: off: %d, count %u\n", off, count);
179 #endif
180 if (off) {
181 unsigned subindirsize = 1, indirsize;
182 int i;
183
184 for (i = level; i > 0; i--)
185 subindirsize *= ufsinfo->nindir;
186 indirsize = subindirsize * ufsinfo->nindir;
187 if (off >= indirsize) {
188 /* no need to read any data */
189 *poff = off - indirsize;
190 return 0;
191 }
192
193 b = off / subindirsize;
194 off -= b * subindirsize;
195 *poff = 0;
196 } else
197 b = 0;
198
199 /* read the indirect block */
200 RAW_READ(idbuf, blk << ufsinfo->fsbtodb, bsize);
201
202 for ( ; b < ufsinfo->nindir && count > 0; b++) {
203 #if defined(USE_UFS1) && defined(USE_UFS2)
204 if (ufsinfo->ufstype == UFSTYPE_UFS1)
205 #endif
206 #ifdef USE_UFS1
207 pos = idbuf1[b];
208 #endif
209 #if defined(USE_UFS1) && defined(USE_UFS2)
210 else
211 #endif
212 #ifdef USE_UFS2
213 pos = idbuf2[b];
214 #endif
215
216 if (level)
217 count = ufs_read_indirect(pos, level - 1, buf, &off, count);
218 else {
219 #if 0
220 printf("ufs_read: read: blk: %d\n",
221 (int) pos << ufsinfo->fsbtodb);
222 #endif
223 raw_read_queue(*buf, pos << ufsinfo->fsbtodb, bsize);
224 *buf += bsize;
225 count -= bsize;
226 }
227 }
228
229 return count;
230 }
231
232 /*
233 * look-up fn in directory dirino
234 */
235 ino_t
236 ufs_lookup(dirino, fn)
237 ino_t dirino;
238 const char *fn;
239 {
240 union ufs_dinode dirdi;
241 struct direct *pdir;
242 char *p, *endp;
243 size_t disize;
244
245 if (ufs_get_inode(dirino, &dirdi))
246 return 0;
247
248 if ((dirdi.di_common.di_mode & IFMT) != IFDIR)
249 return 0; /* Not a directory */
250
251 disize = DI_SIZE(&dirdi);
252
253 #if 0
254 p = alloca((disize + fs.bsize - 1) & ~(fs.bsize - 1));
255 #else /* simplify calculation to reduce code size */
256 p = alloca(disize + fs.bsize);
257 #endif
258 ufs_read(&dirdi, p, 0, disize);
259 endp = p + disize;
260 for ( ; pdir = (void *) p, p < endp; p += pdir->d_reclen) {
261 if (pdir->d_ino && !strcmp(fn, pdir->d_name))
262 return pdir->d_ino;
263 }
264 return 0; /* No such file or directory */
265 }
266
267 /*
268 * look-up a file in absolute pathname from the root directory
269 */
270 ino_t
271 ufs_lookup_path(path)
272 const char *path;
273 {
274 char fn[MAXNAMLEN + 1];
275 char *p;
276 ino_t ino = ROOTINO;
277
278 do {
279 while (*path == '/')
280 path++;
281 for (p = fn; *path && *path != '/'; )
282 *p++ = *path++;
283 *p++ = '\0';
284 ino = ufs_lookup(ino, fn);
285 } while (ino && *path);
286
287 return ino;
288 }
289
290 #if 0
291 size_t
292 ufs_load_file(buf, dirino, fn)
293 void *buf;
294 ino_t dirino;
295 const char *fn;
296 {
297 size_t cnt, disize;
298 union ufs_dinode dinode;
299
300 if (ufs_fn_inode(dirino, fn, &dinode))
301 return (unsigned) 0;
302 disize = DI_SIZE(&dinode);
303 cnt = ufs_read(&dinode, buf, 0, disize);
304
305 return cnt;
306 }
307 #endif
308
309 int
310 ufs_init()
311 {
312 return 1
313 #ifdef USE_FFS
314 && try_ffs()
315 #endif
316 #ifdef USE_LFS
317 && try_lfs()
318 #endif
319 ;
320 }
321
322 #ifdef DEBUG_WITH_STDIO
323 void
324 ufs_list_dir(dirino)
325 ino_t dirino;
326 {
327 union ufs_dinode dirdi;
328 struct direct *pdir;
329 char *p, *endp;
330 size_t disize;
331
332 if (ufs_get_inode(dirino, &dirdi))
333 errx(1, "ino = %d: not found", dirino);
334
335 disize = DI_SIZE(&dirdi);
336 p = alloca((disize + fs.bsize - 1) & ~(fs.bsize - 1));
337 ufs_read(&dirdi, p, 0, disize);
338 endp = p + disize;
339 for ( ; pdir = (void *) p, p < endp; p += pdir->d_reclen) {
340 if (pdir->d_ino)
341 printf("%6d %s\n", pdir->d_ino, pdir->d_name);
342 }
343 }
344 #endif
345
346 #ifdef DEBUG_WITH_STDIO
347 int
348 main(argc, argv)
349 int argc __attribute__((unused));
350 char *argv[];
351 {
352 union ufs_dinode dinode;
353
354 if ((fd = open(argv[1], O_RDONLY)) < 0)
355 err(1, "open: %s", argv[1]);
356
357 if (ufs_init())
358 errx(1, "%s: unknown fs", argv[1]);
359
360 #if 1
361 ufs_list_dir(ROOTINO);
362 {
363 void *p;
364 size_t cnt;
365 ino_t ino;
366 size_t disize;
367
368 if ((ino = ufs_lookup_path(argv[2])) == 0)
369 errx(1, "%s: not found", argv[2]);
370 ufs_get_inode(ino, &dinode);
371 disize = DI_SIZE(&dinode);
372 p = malloc((disize + fs.bsize - 1) & ~(fs.bsize - 1));
373 cnt = ufs_read(&dinode, p, 0, disize);
374 write(3, p, cnt);
375 free(p);
376 }
377 #endif
378
379 return 0;
380 }
381 #endif
382