xref: /openbsd/sys/lib/libsa/ufs2.c (revision 044dcf88)
1 /*	$OpenBSD: ufs2.c,v 1.8 2019/08/03 15:22:17 deraadt Exp $	*/
2 
3 /*-
4  * Copyright (c) 1993
5  *	The Regents of the University of California.  All rights reserved.
6  *
7  * This code is derived from software contributed to Berkeley by
8  * The Mach Operating System project at Carnegie-Mellon University.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. Neither the name of the University nor the names of its contributors
19  *    may be used to endorse or promote products derived from this software
20  *    without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  *
34  *
35  * Copyright (c) 1990, 1991 Carnegie Mellon University
36  * All Rights Reserved.
37  *
38  * Author: David Golub
39  *
40  * Permission to use, copy, modify and distribute this software and its
41  * documentation is hereby granted, provided that both the copyright
42  * notice and this permission notice appear in all copies of the
43  * software, derivative works or modified versions, and any portions
44  * thereof, and that both notices appear in supporting documentation.
45  *
46  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
47  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
48  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
49  *
50  * Carnegie Mellon requests users of this software to return to
51  *
52  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
53  *  School of Computer Science
54  *  Carnegie Mellon University
55  *  Pittsburgh PA 15213-3890
56  *
57  * any improvements or extensions that they make and grant Carnegie the
58  * rights to redistribute these changes.
59  */
60 
61 /*
62  *	Stand-alone file reading package.
63  */
64 
65 #include <sys/param.h>
66 #include <sys/time.h>
67 #include <sys/stat.h>
68 #include <ufs/ffs/fs.h>
69 #include <ufs/ufs/dinode.h>
70 #include <ufs/ufs/dir.h>
71 #include <lib/libkern/libkern.h>
72 
73 #include "stand.h"
74 #include "ufs2.h"
75 
76 /*
77  * In-core open file.
78  */
79 struct file {
80 	off_t		f_seekp;	/* seek pointer */
81 	struct fs	*f_fs;		/* pointer to super-block */
82 	struct ufs2_dinode	f_di;		/* copy of on-disk inode */
83 	ufsino_t	f_ino;		/* our inode number */
84 	int		f_nindir[NIADDR];
85 					/* number of blocks mapped by
86 					   indirect block at level i */
87 	char		*f_blk[NIADDR];	/* buffer for indirect block at
88 					   level i */
89 	size_t		f_blksize[NIADDR];
90 					/* size of buffer */
91 	daddr_t		f_blkno[NIADDR];/* disk address of block in buffer */
92 	char		*f_buf;		/* buffer for data block */
93 	size_t		f_buf_size;	/* size of data block */
94 	daddr_t		f_buf_blkno;	/* block number of data block */
95 };
96 
97 static int	read_inode(ufsino_t, struct open_file *);
98 static int	chmod_inode(ufsino_t, struct open_file *, mode_t);
99 static int	block_map(struct open_file *, daddr_t, daddr_t *);
100 static int	buf_read_file(struct open_file *, char **, size_t *);
101 static int	search_directory(char *, struct open_file *, ufsino_t *);
102 static int	ufs2_close_internal(struct file *);
103 #ifdef COMPAT_UFS
104 static void	ffs_oldfscompat(struct fs *);
105 #endif
106 
107 /*
108  * Read a new inode into a file structure.
109  */
110 static int
read_inode(ufsino_t inumber,struct open_file * f)111 read_inode(ufsino_t inumber, struct open_file *f)
112 {
113 	struct file *fp = (struct file *)f->f_fsdata;
114 	struct fs *fs = fp->f_fs;
115 	char *buf;
116 	size_t rsize;
117 	int rc;
118 
119 	/*
120 	 * Read inode and save it.
121 	 */
122 	buf = alloc(fs->fs_bsize);
123 	twiddle();
124 	rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
125 	    fsbtodb(fs, ino_to_fsba(fs, inumber)), fs->fs_bsize, buf, &rsize);
126 	if (rc)
127 		goto out;
128 	if (rsize != (size_t)fs->fs_bsize) {
129 		rc = EIO;
130 		goto out;
131 	}
132 
133 	{
134 		struct ufs2_dinode *dp;
135 
136 		dp = (struct ufs2_dinode *)buf;
137 		fp->f_di = dp[ino_to_fsbo(fs, inumber)];
138 	}
139 
140 	/*
141 	 * Clear out the old buffers
142 	 */
143 	{
144 		int level;
145 
146 		for (level = 0; level < NIADDR; level++)
147 			fp->f_blkno[level] = -1;
148 		fp->f_buf_blkno = -1;
149 		fp->f_seekp = 0;
150 	}
151 out:
152 	free(buf, fs->fs_bsize);
153 	return (rc);
154 }
155 
156 /*
157  * Read a new inode into a file structure.
158  */
159 static int
chmod_inode(ufsino_t inumber,struct open_file * f,mode_t mode)160 chmod_inode(ufsino_t inumber, struct open_file *f, mode_t mode)
161 {
162 	struct file *fp = (struct file *)f->f_fsdata;
163 	struct fs *fs = fp->f_fs;
164 	char *buf;
165 	size_t rsize;
166 	int rc;
167 
168 	/*
169 	 * Read inode and save it.
170 	 */
171 	buf = alloc(fs->fs_bsize);
172 	twiddle();
173 	rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
174 	    fsbtodb(fs, ino_to_fsba(fs, inumber)), fs->fs_bsize, buf, &rsize);
175 	if (rc)
176 		goto out;
177 	if (rsize != (size_t)fs->fs_bsize) {
178 		rc = EIO;
179 		goto out;
180 	}
181 
182 	{
183 		struct ufs2_dinode *dp;
184 
185 		dp = &((struct ufs2_dinode *)buf)[ino_to_fsbo(fs, inumber)];
186 		dp->di_mode = mode;
187 	}
188 
189 	twiddle();
190 	rc = (f->f_dev->dv_strategy)(f->f_devdata, F_WRITE,
191 	    fsbtodb(fs, ino_to_fsba(fs, inumber)), fs->fs_bsize, buf, NULL);
192 
193 out:
194 	free(buf, fs->fs_bsize);
195 	return (rc);
196 }
197 
198 /*
199  * Given an offset in a file, find the disk block number that
200  * contains that block.
201  */
202 static int
block_map(struct open_file * f,daddr_t file_block,daddr_t * disk_block_p)203 block_map(struct open_file *f, daddr_t file_block, daddr_t *disk_block_p)
204 {
205 	struct file *fp = (struct file *)f->f_fsdata;
206 	daddr_t ind_block_num, *ind_p;
207 	struct fs *fs = fp->f_fs;
208 	int level, idx, rc;
209 
210 	/*
211 	 * Index structure of an inode:
212 	 *
213 	 * di_db[0..NDADDR-1]	hold block numbers for blocks
214 	 *			0..NDADDR-1
215 	 *
216 	 * di_ib[0]		index block 0 is the single indirect block
217 	 *			holds block numbers for blocks
218 	 *			NDADDR .. NDADDR + NINDIR(fs)-1
219 	 *
220 	 * di_ib[1]		index block 1 is the double indirect block
221 	 *			holds block numbers for INDEX blocks for blocks
222 	 *			NDADDR + NINDIR(fs) ..
223 	 *			NDADDR + NINDIR(fs) + NINDIR(fs)**2 - 1
224 	 *
225 	 * di_ib[2]		index block 2 is the triple indirect block
226 	 *			holds block numbers for double-indirect
227 	 *			blocks for blocks
228 	 *			NDADDR + NINDIR(fs) + NINDIR(fs)**2 ..
229 	 *			NDADDR + NINDIR(fs) + NINDIR(fs)**2
230 	 *				+ NINDIR(fs)**3 - 1
231 	 */
232 
233 	if (file_block < NDADDR) {
234 		/* Direct block. */
235 		*disk_block_p = fp->f_di.di_db[file_block];
236 		return (0);
237 	}
238 
239 	file_block -= NDADDR;
240 
241 	/*
242 	 * nindir[0] = NINDIR
243 	 * nindir[1] = NINDIR**2
244 	 * nindir[2] = NINDIR**3
245 	 *	etc
246 	 */
247 	for (level = 0; level < NIADDR; level++) {
248 		if (file_block < fp->f_nindir[level])
249 			break;
250 		file_block -= fp->f_nindir[level];
251 	}
252 	if (level == NIADDR) {
253 		/* Block number too high */
254 		return (EFBIG);
255 	}
256 
257 	ind_block_num = fp->f_di.di_ib[level];
258 
259 	for (; level >= 0; level--) {
260 		if (ind_block_num == 0) {
261 			*disk_block_p = 0;	/* missing */
262 			return (0);
263 		}
264 
265 		if (fp->f_blkno[level] != ind_block_num) {
266 			if (fp->f_blk[level] == NULL)
267 				fp->f_blk[level] =
268 				    alloc(fs->fs_bsize);
269 			twiddle();
270 			rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
271 			    fsbtodb(fp->f_fs, ind_block_num), fs->fs_bsize,
272 			    fp->f_blk[level], &fp->f_blksize[level]);
273 			if (rc)
274 				return (rc);
275 			if (fp->f_blksize[level] != (size_t)fs->fs_bsize)
276 				return (EIO);
277 			fp->f_blkno[level] = ind_block_num;
278 		}
279 
280 		ind_p = (daddr_t *)fp->f_blk[level];
281 
282 		if (level > 0) {
283 			idx = file_block / fp->f_nindir[level - 1];
284 			file_block %= fp->f_nindir[level - 1];
285 		} else
286 			idx = file_block;
287 
288 		ind_block_num = ind_p[idx];
289 	}
290 
291 	*disk_block_p = ind_block_num;
292 	return (0);
293 }
294 
295 /*
296  * Read a portion of a file into an internal buffer.  Return
297  * the location in the buffer and the amount in the buffer.
298  */
299 static int
buf_read_file(struct open_file * f,char ** buf_p,size_t * size_p)300 buf_read_file(struct open_file *f, char **buf_p, size_t *size_p)
301 {
302 	struct file *fp = (struct file *)f->f_fsdata;
303 	struct fs *fs = fp->f_fs;
304 	daddr_t file_block, disk_block;
305 	size_t block_size;
306 	long off;
307 	int rc;
308 
309 	off = blkoff(fs, fp->f_seekp);
310 	file_block = lblkno(fs, fp->f_seekp);
311 	block_size = dblksize(fs, &fp->f_di, (u_int64_t)file_block);
312 
313 	if (file_block != fp->f_buf_blkno) {
314 		rc = block_map(f, file_block, &disk_block);
315 		if (rc)
316 			return (rc);
317 
318 		if (fp->f_buf == NULL)
319 			fp->f_buf = alloc(fs->fs_bsize);
320 
321 		if (disk_block == 0) {
322 			bzero(fp->f_buf, block_size);
323 			fp->f_buf_size = block_size;
324 		} else {
325 			twiddle();
326 			rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
327 			    fsbtodb(fs, disk_block),
328 			    block_size, fp->f_buf, &fp->f_buf_size);
329 			if (rc)
330 				return (rc);
331 		}
332 
333 		fp->f_buf_blkno = file_block;
334 	}
335 
336 	/*
337 	 * Return address of byte in buffer corresponding to
338 	 * offset, and size of remainder of buffer after that
339 	 * byte.
340 	 */
341 	*buf_p = fp->f_buf + off;
342 	*size_p = block_size - off;
343 
344 	/*
345 	 * But truncate buffer at end of file.
346 	 */
347 	if (*size_p > fp->f_di.di_size - fp->f_seekp)
348 		*size_p = fp->f_di.di_size - fp->f_seekp;
349 
350 	return (0);
351 }
352 
353 /*
354  * Search a directory for a name and return its
355  * i_number.
356  */
357 static int
search_directory(char * name,struct open_file * f,ufsino_t * inumber_p)358 search_directory(char *name, struct open_file *f, ufsino_t *inumber_p)
359 {
360 	struct file *fp = (struct file *)f->f_fsdata;
361 	int namlen, length, rc;
362 	struct direct *dp, *edp;
363 	size_t buf_size;
364 	char *buf;
365 
366 	length = strlen(name);
367 
368 	fp->f_seekp = 0;
369 	while ((u_int64_t)fp->f_seekp < fp->f_di.di_size) {
370 		rc = buf_read_file(f, &buf, &buf_size);
371 		if (rc)
372 			return (rc);
373 
374 		dp = (struct direct *)buf;
375 		edp = (struct direct *)(buf + buf_size);
376 		while (dp < edp) {
377 			if (dp->d_ino == 0)
378 				goto next;
379 #if BYTE_ORDER == LITTLE_ENDIAN
380 			if (fp->f_fs->fs_maxsymlinklen <= 0)
381 				namlen = dp->d_type;
382 			else
383 #endif
384 				namlen = dp->d_namlen;
385 			if (namlen == length &&
386 			    !strcmp(name, dp->d_name)) {
387 				/* found entry */
388 				*inumber_p = dp->d_ino;
389 				return (0);
390 			}
391 		next:
392 			dp = (struct direct *)((char *)dp + dp->d_reclen);
393 		}
394 		fp->f_seekp += buf_size;
395 	}
396 	return (ENOENT);
397 }
398 
399 /*
400  * Open a file.
401  */
402 int
ufs2_open(char * path,struct open_file * f)403 ufs2_open(char *path, struct open_file *f)
404 {
405 	char namebuf[MAXPATHLEN+1], *cp, *ncp, *buf = NULL;
406 	ufsino_t inumber, parent_inumber;
407 	int rc, c, nlinks = 0;
408 	struct file *fp;
409 	size_t buf_size;
410 	struct fs *fs;
411 
412 	/* allocate file system specific data structure */
413 	fp = alloc(sizeof(struct file));
414 	bzero(fp, sizeof(struct file));
415 	f->f_fsdata = (void *)fp;
416 
417 	/* allocate space and read super block */
418 	fs = alloc(SBSIZE);
419 	fp->f_fs = fs;
420 	twiddle();
421 	rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
422 	    SBLOCK_UFS2 / DEV_BSIZE, SBSIZE, (char *)fs, &buf_size);
423 	if (rc)
424 		goto out;
425 
426 	if (buf_size != SBSIZE || fs->fs_magic != FS_UFS2_MAGIC ||
427 	    (u_int64_t)fs->fs_bsize > MAXBSIZE ||
428 	    (u_int64_t)fs->fs_bsize < sizeof(struct fs)) {
429 		rc = EINVAL;
430 		goto out;
431 	}
432 #ifdef COMPAT_UFS
433 	ffs_oldfscompat(fs);
434 #endif
435 
436 	/*
437 	 * Calculate indirect block levels.
438 	 */
439 	{
440 		int mult;
441 		int level;
442 
443 		mult = 1;
444 		for (level = 0; level < NIADDR; level++) {
445 			mult *= NINDIR(fs);
446 			fp->f_nindir[level] = mult;
447 		}
448 	}
449 
450 	inumber = ROOTINO;
451 	if ((rc = read_inode(inumber, f)) != 0)
452 		goto out;
453 
454 	cp = path;
455 	while (*cp) {
456 
457 		/*
458 		 * Remove extra separators
459 		 */
460 		while (*cp == '/')
461 			cp++;
462 		if (*cp == '\0')
463 			break;
464 
465 		/*
466 		 * Check that current node is a directory.
467 		 */
468 		if ((fp->f_di.di_mode & IFMT) != IFDIR) {
469 			rc = ENOTDIR;
470 			goto out;
471 		}
472 
473 		/*
474 		 * Get next component of path name.
475 		 */
476 		{
477 			int len = 0;
478 
479 			ncp = cp;
480 			while ((c = *cp) != '\0' && c != '/') {
481 				if (++len > MAXNAMLEN) {
482 					rc = ENOENT;
483 					goto out;
484 				}
485 				cp++;
486 			}
487 			*cp = '\0';
488 		}
489 
490 		/*
491 		 * Look up component in current directory.
492 		 * Save directory inumber in case we find a
493 		 * symbolic link.
494 		 */
495 		parent_inumber = inumber;
496 		rc = search_directory(ncp, f, &inumber);
497 		*cp = c;
498 		if (rc)
499 			goto out;
500 
501 		/*
502 		 * Open next component.
503 		 */
504 		if ((rc = read_inode(inumber, f)) != 0)
505 			goto out;
506 
507 		/*
508 		 * Check for symbolic link.
509 		 */
510 		if ((fp->f_di.di_mode & IFMT) == IFLNK) {
511 			u_int64_t link_len = fp->f_di.di_size;
512 			size_t len;
513 
514 			len = strlen(cp);
515 
516 			if (link_len + len > MAXPATHLEN ||
517 			    ++nlinks > MAXSYMLINKS) {
518 				rc = ENOENT;
519 				goto out;
520 			}
521 
522 			bcopy(cp, &namebuf[link_len], len + 1);
523 
524 			if (link_len < (u_int64_t)fs->fs_maxsymlinklen) {
525 				bcopy(fp->f_di.di_shortlink, namebuf, link_len);
526 			} else {
527 				/*
528 				 * Read file for symbolic link
529 				 */
530 				daddr_t disk_block;
531 				fs = fp->f_fs;
532 
533 				if (!buf)
534 					buf = alloc(fs->fs_bsize);
535 				rc = block_map(f, 0, &disk_block);
536 				if (rc)
537 					goto out;
538 
539 				twiddle();
540 				rc = (f->f_dev->dv_strategy)(f->f_devdata,
541 				    F_READ, fsbtodb(fs, disk_block),
542 				    fs->fs_bsize, buf, &buf_size);
543 				if (rc)
544 					goto out;
545 
546 				bcopy(buf, namebuf, link_len);
547 			}
548 
549 			/*
550 			 * If relative pathname, restart at parent directory.
551 			 * If absolute pathname, restart at root.
552 			 */
553 			cp = namebuf;
554 			if (*cp != '/')
555 				inumber = parent_inumber;
556 			else
557 				inumber = ROOTINO;
558 
559 			if ((rc = read_inode(inumber, f)) != 0)
560 				goto out;
561 		}
562 	}
563 
564 	/*
565 	 * Found terminal component.
566 	 */
567 	fp->f_ino = inumber;
568 	rc = 0;
569 out:
570 	if (buf)
571 		free(buf, fs->fs_bsize);
572 	if (rc)
573 		(void)ufs2_close_internal(fp);
574 
575 	return (rc);
576 }
577 
578 int
ufs2_close(struct open_file * f)579 ufs2_close(struct open_file *f)
580 {
581 	struct file *fp = (struct file *)f->f_fsdata;
582 
583 	f->f_fsdata = NULL;
584 	if (fp == NULL)
585 		return (0);
586 
587 	return (ufs2_close_internal(fp));
588 }
589 
590 static int
ufs2_close_internal(struct file * fp)591 ufs2_close_internal(struct file *fp)
592 {
593 	int level;
594 
595 	for (level = 0; level < NIADDR; level++) {
596 		if (fp->f_blk[level])
597 			free(fp->f_blk[level], fp->f_fs->fs_bsize);
598 	}
599 	if (fp->f_buf)
600 		free(fp->f_buf, fp->f_fs->fs_bsize);
601 	free(fp->f_fs, SBSIZE);
602 	free(fp, sizeof(struct file));
603 	return (0);
604 }
605 
606 /*
607  * Copy a portion of a file into kernel memory.
608  * Cross block boundaries when necessary.
609  */
610 int
ufs2_read(struct open_file * f,void * start,size_t size,size_t * resid)611 ufs2_read(struct open_file *f, void *start, size_t size, size_t *resid)
612 {
613 	struct file *fp = (struct file *)f->f_fsdata;
614 	char *buf, *addr = start;
615 	size_t csize, buf_size;
616 	int rc = 0;
617 
618 	while (size != 0) {
619 		if ((u_int64_t)fp->f_seekp >= fp->f_di.di_size)
620 			break;
621 
622 		rc = buf_read_file(f, &buf, &buf_size);
623 		if (rc)
624 			break;
625 
626 		csize = size;
627 		if (csize > buf_size)
628 			csize = buf_size;
629 
630 		bcopy(buf, addr, csize);
631 
632 		fp->f_seekp += csize;
633 		addr += csize;
634 		size -= csize;
635 	}
636 	if (resid)
637 		*resid = size;
638 	return (rc);
639 }
640 
641 /*
642  * Not implemented.
643  */
644 int
ufs2_write(struct open_file * f,void * start,size_t size,size_t * resid)645 ufs2_write(struct open_file *f, void *start, size_t size, size_t *resid)
646 {
647 
648 	return (EROFS);
649 }
650 
651 off_t
ufs2_seek(struct open_file * f,off_t offset,int where)652 ufs2_seek(struct open_file *f, off_t offset, int where)
653 {
654 	struct file *fp = (struct file *)f->f_fsdata;
655 
656 	switch (where) {
657 	case SEEK_SET:
658 		fp->f_seekp = offset;
659 		break;
660 	case SEEK_CUR:
661 		fp->f_seekp += offset;
662 		break;
663 	case SEEK_END:
664 		fp->f_seekp = fp->f_di.di_size - offset;
665 		break;
666 	default:
667 		return (-1);
668 	}
669 	return (fp->f_seekp);
670 }
671 
672 int
ufs2_stat(struct open_file * f,struct stat * sb)673 ufs2_stat(struct open_file *f, struct stat *sb)
674 {
675 	struct file *fp = (struct file *)f->f_fsdata;
676 
677 	/* only important stuff */
678 	sb->st_mode = fp->f_di.di_mode;
679 	sb->st_uid = fp->f_di.di_uid;
680 	sb->st_gid = fp->f_di.di_gid;
681 	sb->st_size = fp->f_di.di_size;
682 	return (0);
683 }
684 
685 int
ufs2_fchmod(struct open_file * f,mode_t mode)686 ufs2_fchmod(struct open_file *f, mode_t mode)
687 {
688 	struct file *fp = (struct file *)f->f_fsdata;
689 
690 	return chmod_inode(fp->f_ino, f, mode);
691 }
692 
693 #ifndef	NO_READDIR
694 int
ufs2_readdir(struct open_file * f,char * name)695 ufs2_readdir(struct open_file *f, char *name)
696 {
697 	struct file *fp = (struct file *)f->f_fsdata;
698 	struct direct *dp, *edp;
699 	size_t buf_size;
700 	int rc, namlen;
701 	char *buf;
702 
703 	if (name == NULL)
704 		fp->f_seekp = 0;
705 	else {
706 			/* end of dir */
707 		if ((u_int64_t)fp->f_seekp >= fp->f_di.di_size) {
708 			*name = '\0';
709 			return -1;
710 		}
711 
712 		do {
713 			if ((rc = buf_read_file(f, &buf, &buf_size)) != 0)
714 				return rc;
715 
716 			dp = (struct direct *)buf;
717 			edp = (struct direct *)(buf + buf_size);
718 			while (dp < edp && dp->d_ino == 0)
719 				dp = (struct direct *)((char *)dp + dp->d_reclen);
720 			fp->f_seekp += buf_size -
721 			    ((u_int8_t *)edp - (u_int8_t *)dp);
722 		} while (dp >= edp);
723 
724 #if BYTE_ORDER == LITTLE_ENDIAN
725 		if (fp->f_fs->fs_maxsymlinklen <= 0)
726 			namlen = dp->d_type;
727 		else
728 #endif
729 			namlen = dp->d_namlen;
730 		strncpy(name, dp->d_name, namlen + 1);
731 
732 		fp->f_seekp += dp->d_reclen;
733 	}
734 
735 	return 0;
736 }
737 #endif
738 
739 #ifdef COMPAT_UFS
740 /*
741  * Sanity checks for old file systems.
742  *
743  * XXX - goes away some day.
744  */
745 static void
ffs_oldfscompat(struct fs * fs)746 ffs_oldfscompat(struct fs *fs)
747 {
748 	int i;
749 
750 	fs->fs_npsect = max(fs->fs_npsect, fs->fs_nsect);	/* XXX */
751 	fs->fs_interleave = max(fs->fs_interleave, 1);		/* XXX */
752 	if (fs->fs_postblformat == FS_42POSTBLFMT)		/* XXX */
753 		fs->fs_nrpos = 8;				/* XXX */
754 	if (fs->fs_inodefmt < FS_44INODEFMT) {			/* XXX */
755 		quad_t sizepb = fs->fs_bsize;			/* XXX */
756 								/* XXX */
757 		fs->fs_maxfilesize = fs->fs_bsize * NDADDR - 1;	/* XXX */
758 		for (i = 0; i < NIADDR; i++) {			/* XXX */
759 			sizepb *= NINDIR(fs);			/* XXX */
760 			fs->fs_maxfilesize += sizepb;		/* XXX */
761 		}						/* XXX */
762 		fs->fs_qbmask = ~fs->fs_bmask;			/* XXX */
763 		fs->fs_qfmask = ~fs->fs_fmask;			/* XXX */
764 	}							/* XXX */
765 }
766 #endif
767