xref: /netbsd-src/sys/arch/x68k/stand/boot_ufs/readufs.c (revision 96230fab84e26a6435963032070e916a951a8b2e)
1 /*	$NetBSD: readufs.c,v 1.8 2007/03/04 06:01:07 christos 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@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, void **buf,
20 		unsigned *poff, size_t count));
21 
22 #ifdef DEBUG_WITH_STDIO
23 void ufs_list_dir __P((ino32_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 	void *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 	void **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 ino32_t
236 ufs_lookup(dirino, fn)
237 	ino32_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 ino32_t
271 ufs_lookup_path(path)
272 	const char *path;
273 {
274 	char fn[FFS_MAXNAMLEN + 1];
275 	char *p;
276 	ino32_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 	ino32_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 	ino32_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 		ino32_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