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