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