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