xref: /netbsd/sys/arch/x68k/stand/boot_ufs/readufs.c (revision bf9ec67e)
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@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, ufs_daddr_t blkpos, size_t bytelen));
22 static int ufs_read_indirect __P((ufs_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 	ufs_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 	ufs_daddr_t blkpos;
55 	size_t bytelen;		/* must be DEV_BSIZE aligned */
56 {
57 	static ufs_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 	ufs_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 	ufs_daddr_t *idbuf = alloca(bsize);
142 	unsigned off = *poff;
143 	unsigned b;
144 
145 #ifdef DEBUG_WITH_STDIO
146 	printf("ufs_read_indirect: off: %d, count %u\n", off, count);
147 #endif
148 	if (off) {
149 		unsigned subindirsize = 1, indirsize;
150 		int i;
151 
152 		for (i = level; i > 0; i--)
153 			subindirsize *= fs.nindir;
154 		indirsize = subindirsize * fs.nindir;
155 		if (off >= indirsize) {
156 			/* no need to read any data */
157 			*poff = off - indirsize;
158 			return 0;
159 		}
160 
161 		b = off / subindirsize;
162 		off -= b * subindirsize;
163 		*poff = 0;
164 	} else
165 		b = 0;
166 
167 	/* read the indirect block */
168 	RAW_READ(idbuf, blk << fs.fsbtodb, bsize);
169 
170 	for ( ; b < fs.nindir && count > 0; b++) {
171 		if (level)
172 			count = ufs_read_indirect(idbuf[b], level - 1, buf, &off, count);
173 		else {
174 #if 0
175 			printf("ufs_read: read: blk: %d\n",
176 				idbuf[b] << fs.fsbtodb);
177 #endif
178 			raw_read_queue(*buf, idbuf[b] << fs.fsbtodb, bsize);
179 			*buf += bsize;
180 			count -= bsize;
181 		}
182 	}
183 
184 	return count;
185 }
186 
187 /*
188  * look-up fn in directory dirino
189  */
190 ino_t
191 ufs_lookup(dirino, fn)
192 	ino_t dirino;
193 	const char *fn;
194 {
195 	struct dinode dirdi;
196 	struct direct *pdir;
197 	char *p, *endp;
198 
199 	if (ufs_get_inode(dirino, &dirdi))
200 		return 0;
201 
202 	if ((dirdi.di_mode & IFMT) != IFDIR)
203 		return 0;			/* Not a directory */
204 
205 #if 0
206 	p = alloca(((size_t) dirdi.di_size + fs.bsize - 1) & ~(fs.bsize - 1));
207 #else	/* simplify calculation to reduce code size */
208 	p = alloca((size_t) dirdi.di_size + fs.bsize);
209 #endif
210 	ufs_read(&dirdi, p, 0, (size_t) dirdi.di_size);
211 	endp = p + dirdi.di_size;
212 	for ( ; pdir = (void *) p, p < endp; p += pdir->d_reclen) {
213 		if (pdir->d_ino && !strcmp(fn, pdir->d_name))
214 			return pdir->d_ino;
215 	}
216 	return 0;				/* No such file or directory */
217 }
218 
219 /*
220  * look-up a file in absolute pathname from the root directory
221  */
222 ino_t
223 ufs_lookup_path(path)
224 	const char *path;
225 {
226 	char fn[MAXNAMLEN + 1];
227 	char *p;
228 	ino_t ino = ROOTINO;
229 
230 	do {
231 		while (*path == '/')
232 			path++;
233 		for (p = fn; *path && *path != '/'; )
234 			*p++ = *path++;
235 		*p++ = '\0';
236 		ino = ufs_lookup(ino, fn);
237 	} while (ino && *path);
238 
239 	return ino;
240 }
241 
242 #if 0
243 size_t
244 ufs_load_file(buf, dirino, fn)
245 	void *buf;
246 	ino_t dirino;
247 	const char *fn;
248 {
249 	size_t cnt;
250 	struct dinode dinode;
251 
252 	if (ufs_fn_inode(dirino, fn, &dinode))
253 		return (unsigned) 0;
254 	cnt = ufs_read(&dinode, buf, 0, (size_t) dinode.di_size);
255 
256 	return cnt;
257 }
258 #endif
259 
260 int
261 ufs_init()
262 {
263 	return 1
264 #ifdef USE_FFS
265 		&& try_ffs()
266 #endif
267 #ifdef USE_LFS
268 		&& try_lfs()
269 #endif
270 		;
271 }
272 
273 #ifdef DEBUG_WITH_STDIO
274 void
275 ufs_list_dir(dirino)
276 	ino_t dirino;
277 {
278 	struct dinode dirdi;
279 	struct direct *pdir;
280 	char *p, *endp;
281 
282 	if (ufs_get_inode(dirino, &dirdi))
283 		errx(1, "ino = %d: not found", dirino);
284 
285 	p = alloca(((size_t) dirdi.di_size + fs.bsize - 1) & ~(fs.bsize - 1));
286 	ufs_read(&dirdi, p, 0, (size_t) dirdi.di_size);
287 	endp = p + dirdi.di_size;
288 	for ( ; pdir = (void *) p, p < endp; p += pdir->d_reclen) {
289 		if (pdir->d_ino)
290 			printf("%6d %s\n", pdir->d_ino, pdir->d_name);
291 	}
292 }
293 #endif
294 
295 #ifdef DEBUG_WITH_STDIO
296 int
297 main(argc, argv)
298 	int argc __attribute__((unused));
299 	char *argv[];
300 {
301 	struct dinode dinode;
302 
303 	if ((fd = open(argv[1], O_RDONLY)) < 0)
304 		err(1, "open: %s", argv[1]);
305 
306 	if (ufs_init())
307 		errx(1, "%s: unknown fs", argv[1]);
308 
309 #if 1
310 	ufs_list_dir(ROOTINO);
311 	{
312 		void *p;
313 		size_t cnt;
314 		ino_t ino;
315 
316 		if ((ino = ufs_lookup_path(argv[2])) == 0)
317 			errx(1, "%s: not found", argv[2]);
318 		ufs_get_inode(ino, &dinode);
319 		p = malloc(((size_t) dinode.di_size + fs.bsize - 1) & ~(fs.bsize - 1));
320 		cnt = ufs_read(&dinode, p, 0, (size_t) dinode.di_size);
321 		write(3, p, cnt);
322 		free(p);
323 	}
324 #endif
325 
326 	return 0;
327 }
328 #endif
329