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