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