xref: /dragonfly/stand/lib/ufs.c (revision 479ab7f0)
1 /* $FreeBSD: src/lib/libstand/ufs.c,v 1.5.6.1 2000/05/04 13:47:53 ps Exp $ */
2 /*	$NetBSD: ufs.c,v 1.20 1998/03/01 07:15:39 ross 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 
69 #include "stand.h"
70 
71 #include <vfs/ufs/dinode.h>
72 #include <vfs/ufs/dir.h>
73 #include <vfs/ufs/fs.h>
74 #include "string.h"
75 
76 static int	ufs_open(const char *path, struct open_file *f);
77 static int	ufs_close(struct open_file *f);
78 static int	ufs_read(struct open_file *f, void *buf, size_t size, size_t *resid);
79 static off_t	ufs_seek(struct open_file *f, off_t offset, int where);
80 static int	ufs_stat(struct open_file *f, struct stat *sb);
81 static int	ufs_readdir(struct open_file *f, struct dirent *d);
82 
83 struct fs_ops ufs_fsops = {
84 	"ufs",
85 	ufs_open,
86 	ufs_close,
87 	ufs_read,
88 	null_write,
89 	ufs_seek,
90 	ufs_stat,
91 	ufs_readdir
92 };
93 
94 /*
95  * In-core open file.
96  */
97 struct file {
98 	off_t		f_seekp;	/* seek pointer */
99 	struct fs	*f_fs;		/* pointer to super-block */
100 	struct ufs1_dinode f_di;	/* copy of on-disk inode */
101 	int		f_nindir[UFS_NIADDR];
102 					/* number of blocks mapped by
103 					   indirect block at level i */
104 	char		*f_blk[UFS_NIADDR];/* buffer for indirect block at
105 					   level i */
106 	size_t		f_blksize[UFS_NIADDR];
107 					/* size of buffer */
108 	daddr_t		f_blkno[UFS_NIADDR];/* disk address of block in buffer */
109 	char		*f_buf;		/* buffer for data block */
110 	size_t		f_buf_size;	/* size of data block */
111 	daddr_t		f_buf_blkno;	/* block number of data block */
112 };
113 
114 static int	read_inode(ino_t, struct open_file *);
115 static int	block_map(struct open_file *, daddr_t, daddr_t *);
116 static int	buf_read_file(struct open_file *, char **, size_t *);
117 static int	search_directory(char *, struct open_file *, ino_t *);
118 #ifdef COMPAT_UFS
119 static void	ffs_oldfscompat(struct fs *);
120 #endif
121 
122 /*
123  * Read a new inode into a file structure.
124  */
125 static int
read_inode(ino_t inumber,struct open_file * f)126 read_inode(ino_t inumber, struct open_file *f)
127 {
128 	struct file *fp = (struct file *)f->f_fsdata;
129 	struct fs *fs = fp->f_fs;
130 	char *buf;
131 	size_t rsize;
132 	int rc;
133 
134 	if (fs == NULL)
135 	    panic("fs == NULL");
136 
137 	/*
138 	 * Read inode and save it.
139 	 */
140 	buf = malloc(fs->fs_bsize);
141 	twiddle();
142 	rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
143 		fsbtodb(fs, ino_to_fsba(fs, inumber)), fs->fs_bsize,
144 		buf, &rsize);
145 	if (rc)
146 		goto out;
147 	if (rsize != fs->fs_bsize) {
148 		rc = EIO;
149 		goto out;
150 	}
151 
152 	{
153 		struct ufs1_dinode *dp;
154 
155 		dp = (struct ufs1_dinode *)buf;
156 		fp->f_di = dp[ino_to_fsbo(fs, inumber)];
157 	}
158 
159 	/*
160 	 * Clear out the old buffers
161 	 */
162 	{
163 		int level;
164 
165 		for (level = 0; level < UFS_NIADDR; level++)
166 			fp->f_blkno[level] = -1;
167 		fp->f_buf_blkno = -1;
168 	}
169 out:
170 	free(buf);
171 	return (rc);
172 }
173 
174 /*
175  * Given an offset in a file, find the disk block number that
176  * contains that block.
177  *
178  * Parameters:
179  *	disk_block_p:	out
180  */
181 static int
block_map(struct open_file * f,daddr_t file_block,daddr_t * disk_block_p)182 block_map(struct open_file *f, daddr_t file_block, daddr_t *disk_block_p)
183 {
184 	struct file *fp = (struct file *)f->f_fsdata;
185 	struct fs *fs = fp->f_fs;
186 	int level;
187 	int idx;
188 	daddr_t ind_block_num;
189 	daddr_t *ind_p;
190 	int rc;
191 
192 	/*
193 	 * Index structure of an inode:
194 	 *
195 	 * di_db[0..UFS_NDADDR-1] hold block numbers for blocks
196 	 *			0..UFS_NDADDR-1
197 	 *
198 	 * di_ib[0]		index block 0 is the single indirect block
199 	 *			holds block numbers for blocks
200 	 *			UFS_NDADDR .. UFS_NDADDR + NINDIR(fs)-1
201 	 *
202 	 * di_ib[1]		index block 1 is the double indirect block
203 	 *			holds block numbers for INDEX blocks for blocks
204 	 *			UFS_NDADDR + NINDIR(fs) ..
205 	 *			UFS_NDADDR + NINDIR(fs) + NINDIR(fs)**2 - 1
206 	 *
207 	 * di_ib[2]		index block 2 is the triple indirect block
208 	 *			holds block numbers for double-indirect
209 	 *			blocks for blocks
210 	 *			UFS_NDADDR + NINDIR(fs) + NINDIR(fs)**2 ..
211 	 *			UFS_NDADDR + NINDIR(fs) + NINDIR(fs)**2
212 	 *				+ NINDIR(fs)**3 - 1
213 	 */
214 
215 	if (file_block < UFS_NDADDR) {
216 		/* Direct block. */
217 		*disk_block_p = fp->f_di.di_db[file_block];
218 		return (0);
219 	}
220 
221 	file_block -= UFS_NDADDR;
222 
223 	/*
224 	 * nindir[0] = NINDIR
225 	 * nindir[1] = NINDIR**2
226 	 * nindir[2] = NINDIR**3
227 	 *	etc
228 	 */
229 	for (level = 0; level < UFS_NIADDR; level++) {
230 		if (file_block < fp->f_nindir[level])
231 			break;
232 		file_block -= fp->f_nindir[level];
233 	}
234 	if (level == UFS_NIADDR) {
235 		/* Block number too high */
236 		return (EFBIG);
237 	}
238 
239 	ind_block_num = fp->f_di.di_ib[level];
240 
241 	for (; level >= 0; level--) {
242 		if (ind_block_num == 0) {
243 			*disk_block_p = 0;	/* missing */
244 			return (0);
245 		}
246 
247 		if (fp->f_blkno[level] != ind_block_num) {
248 			if (fp->f_blk[level] == NULL)
249 				fp->f_blk[level] =
250 					malloc(fs->fs_bsize);
251 			twiddle();
252 			rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
253 				fsbtodb(fp->f_fs, ind_block_num),
254 				fs->fs_bsize,
255 				fp->f_blk[level],
256 				&fp->f_blksize[level]);
257 			if (rc)
258 				return (rc);
259 			if (fp->f_blksize[level] != fs->fs_bsize)
260 				return (EIO);
261 			fp->f_blkno[level] = ind_block_num;
262 		}
263 
264 		ind_p = (daddr_t *)fp->f_blk[level];
265 
266 		if (level > 0) {
267 			idx = file_block / fp->f_nindir[level - 1];
268 			file_block %= fp->f_nindir[level - 1];
269 		} else
270 			idx = file_block;
271 
272 		ind_block_num = ind_p[idx];
273 	}
274 
275 	*disk_block_p = ind_block_num;
276 
277 	return (0);
278 }
279 
280 /*
281  * Read a portion of a file into an internal buffer.  Return
282  * the location in the buffer and the amount in the buffer.
283  *
284  * Parameters:
285  *	buf_p:	out
286  *	size_p:	out
287  */
288 static int
buf_read_file(struct open_file * f,char ** buf_p,size_t * size_p)289 buf_read_file(struct open_file *f, char **buf_p, size_t *size_p)
290 {
291 	struct file *fp = (struct file *)f->f_fsdata;
292 	struct fs *fs = fp->f_fs;
293 	long off;
294 	daddr_t file_block;
295 	daddr_t	disk_block;
296 	size_t block_size;
297 	int rc;
298 
299 	off = blkoff(fs, fp->f_seekp);
300 	file_block = lblkno(fs, fp->f_seekp);
301 	block_size = dblksize(fs, &fp->f_di, file_block);
302 
303 	if (file_block != fp->f_buf_blkno) {
304 		rc = block_map(f, file_block, &disk_block);
305 		if (rc)
306 			return (rc);
307 
308 		if (fp->f_buf == NULL)
309 			fp->f_buf = malloc(fs->fs_bsize);
310 
311 		if (disk_block == 0) {
312 			bzero(fp->f_buf, block_size);
313 			fp->f_buf_size = block_size;
314 		} else {
315 			twiddle();
316 			rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
317 				fsbtodb(fs, disk_block),
318 				block_size, fp->f_buf, &fp->f_buf_size);
319 			if (rc)
320 				return (rc);
321 		}
322 
323 		fp->f_buf_blkno = file_block;
324 	}
325 
326 	/*
327 	 * Return address of byte in buffer corresponding to
328 	 * offset, and size of remainder of buffer after that
329 	 * byte.
330 	 */
331 	*buf_p = fp->f_buf + off;
332 	*size_p = block_size - off;
333 
334 	/*
335 	 * But truncate buffer at end of file.
336 	 */
337 	if (*size_p > fp->f_di.di_size - fp->f_seekp)
338 		*size_p = fp->f_di.di_size - fp->f_seekp;
339 
340 	return (0);
341 }
342 
343 /*
344  * Search a directory for a name and return its
345  * i_number.
346  *
347  * Parameters:
348  *	inumber_p:	out
349  */
350 static int
search_directory(char * name,struct open_file * f,ino_t * inumber_p)351 search_directory(char *name, struct open_file *f, ino_t *inumber_p)
352 {
353 	struct file *fp = (struct file *)f->f_fsdata;
354 	struct direct *dp;
355 	struct direct *edp;
356 	char *buf;
357 	size_t buf_size;
358 	int namlen, length;
359 	int rc;
360 
361 	length = strlen(name);
362 
363 	fp->f_seekp = 0;
364 	while (fp->f_seekp < fp->f_di.di_size) {
365 		rc = buf_read_file(f, &buf, &buf_size);
366 		if (rc)
367 			return (rc);
368 
369 		dp = (struct direct *)buf;
370 		edp = (struct direct *)(buf + buf_size);
371 		while (dp < edp) {
372 			if (dp->d_ino == (ino_t)0)
373 				goto next;
374 			if (dp->d_type == DT_WHT)
375 				goto next;
376 #if BYTE_ORDER == LITTLE_ENDIAN
377 			if (fp->f_fs->fs_maxsymlinklen <= 0)
378 				namlen = dp->d_type;
379 			else
380 #endif
381 				namlen = dp->d_namlen;
382 			if (namlen == length &&
383 			    !strcmp(name, dp->d_name)) {
384 				/* found entry */
385 				*inumber_p = dp->d_ino;
386 				return (0);
387 			}
388 		next:
389 			dp = (struct direct *)((char *)dp + dp->d_reclen);
390 		}
391 		fp->f_seekp += buf_size;
392 	}
393 	return (ENOENT);
394 }
395 
396 /*
397  * Open a file.
398  */
399 static int
ufs_open(const char * upath,struct open_file * f)400 ufs_open(const char *upath, struct open_file *f)
401 {
402 	char *cp, *ncp;
403 	int c;
404 	ino_t inumber, parent_inumber;
405 	struct file *fp;
406 	struct fs *fs;
407 	int rc;
408 	size_t buf_size;
409 	int nlinks = 0;
410 	char namebuf[MAXPATHLEN+1];
411 	char *buf = NULL;
412 	char *path = NULL;
413 
414 	/* allocate file system specific data structure */
415 	fp = malloc(sizeof(struct file));
416 	bzero(fp, sizeof(struct file));
417 	f->f_fsdata = (void *)fp;
418 
419 	/* allocate space and read super block */
420 	fs = malloc(SBSIZE);
421 	fp->f_fs = fs;
422 	twiddle();
423 	rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
424 		SBOFF / DEV_BSIZE, SBSIZE, (char *)fs, &buf_size);
425 	if (rc)
426 		goto out;
427 
428 	if (buf_size != SBSIZE || fs->fs_magic != FS_MAGIC ||
429 	    fs->fs_bsize > MAXBSIZE || fs->fs_bsize < sizeof(struct fs)) {
430 		rc = EINVAL;
431 		goto out;
432 	}
433 #ifdef COMPAT_UFS
434 	ffs_oldfscompat(fs);
435 #endif
436 
437 	/*
438 	 * Calculate indirect block levels.
439 	 */
440 	{
441 		int omult;
442 		int mult;
443 		int level;
444 
445 		omult = 0;
446 		mult = 1;
447 		for (level = 0; level < UFS_NIADDR; level++) {
448 			mult *= NINDIR(fs);
449 			if (mult < omult)
450 				mult = 0x7FFFFFFF;
451 			fp->f_nindir[level] = mult;
452 			omult = mult;
453 		}
454 	}
455 
456 	inumber = UFS_ROOTINO;
457 	if ((rc = read_inode(inumber, f)) != 0)
458 		goto out;
459 
460 	cp = path = strdup(upath);
461 	if (path == NULL) {
462 	    rc = ENOMEM;
463 	    goto out;
464 	}
465 	while (*cp) {
466 
467 		/*
468 		 * Remove extra separators
469 		 */
470 		while (*cp == '/')
471 			cp++;
472 		if (*cp == '\0')
473 			break;
474 
475 		/*
476 		 * Check that current node is a directory.
477 		 */
478 		if ((fp->f_di.di_mode & IFMT) != IFDIR) {
479 			rc = ENOTDIR;
480 			goto out;
481 		}
482 
483 		/*
484 		 * Get next component of path name.
485 		 */
486 		{
487 			int len = 0;
488 
489 			ncp = cp;
490 			while ((c = *cp) != '\0' && c != '/') {
491 				if (++len > MAXNAMLEN) {
492 					rc = ENOENT;
493 					goto out;
494 				}
495 				cp++;
496 			}
497 			*cp = '\0';
498 		}
499 
500 		/*
501 		 * Look up component in current directory.
502 		 * Save directory inumber in case we find a
503 		 * symbolic link.
504 		 */
505 		parent_inumber = inumber;
506 		rc = search_directory(ncp, f, &inumber);
507 		*cp = c;
508 		if (rc)
509 			goto out;
510 
511 		/*
512 		 * Open next component.
513 		 */
514 		if ((rc = read_inode(inumber, f)) != 0)
515 			goto out;
516 
517 		/*
518 		 * Check for symbolic link.
519 		 */
520 		if ((fp->f_di.di_mode & IFMT) == IFLNK) {
521 			int link_len = fp->f_di.di_size;
522 			int len;
523 
524 			len = strlen(cp);
525 
526 			if (link_len + len > MAXPATHLEN ||
527 			    ++nlinks > MAXSYMLINKS) {
528 				rc = ENOENT;
529 				goto out;
530 			}
531 
532 			bcopy(cp, &namebuf[link_len], len + 1);
533 
534 			if (link_len < fs->fs_maxsymlinklen) {
535 				bcopy(fp->f_di.di_shortlink, namebuf,
536 				      (unsigned) link_len);
537 			} else {
538 				/*
539 				 * Read file for symbolic link
540 				 */
541 				size_t buf_size;
542 				daddr_t	disk_block;
543 				struct fs *fs = fp->f_fs;
544 
545 				if (!buf)
546 					buf = malloc(fs->fs_bsize);
547 				rc = block_map(f, (daddr_t)0, &disk_block);
548 				if (rc)
549 					goto out;
550 
551 				twiddle();
552 				rc = (f->f_dev->dv_strategy)(f->f_devdata,
553 					F_READ, fsbtodb(fs, disk_block),
554 					fs->fs_bsize, buf, &buf_size);
555 				if (rc)
556 					goto out;
557 
558 				bcopy((char *)buf, namebuf, (unsigned)link_len);
559 			}
560 
561 			/*
562 			 * If relative pathname, restart at parent directory.
563 			 * If absolute pathname, restart at root.
564 			 */
565 			cp = namebuf;
566 			if (*cp != '/')
567 				inumber = parent_inumber;
568 			else
569 				inumber = (ino_t)UFS_ROOTINO;
570 
571 			if ((rc = read_inode(inumber, f)) != 0)
572 				goto out;
573 		}
574 	}
575 
576 	/*
577 	 * Found terminal component.
578 	 */
579 	fp->f_seekp = 0;
580 	rc = 0;
581 out:
582 	if (buf)
583 		free(buf);
584 	if (path)
585 		free(path);
586 	if (rc) {
587 		f->f_fsdata = NULL;
588 		if (fp->f_buf)
589 			free(fp->f_buf);
590 		free(fp->f_fs);
591 		free(fp);
592 	}
593 	return (rc);
594 }
595 
596 static int
ufs_close(struct open_file * f)597 ufs_close(struct open_file *f)
598 {
599 	struct file *fp = (struct file *)f->f_fsdata;
600 	int level;
601 
602 	f->f_fsdata = NULL;
603 	if (fp == NULL)
604 		return (0);
605 
606 	for (level = 0; level < UFS_NIADDR; level++) {
607 		if (fp->f_blk[level])
608 			free(fp->f_blk[level]);
609 	}
610 	if (fp->f_buf)
611 		free(fp->f_buf);
612 	free(fp->f_fs);
613 	free(fp);
614 	return (0);
615 }
616 
617 /*
618  * Copy a portion of a file into kernel memory.
619  * Cross block boundaries when necessary.
620  *
621  * Parameters:
622  *	resid:	out
623  */
624 static int
ufs_read(struct open_file * f,void * start,size_t size,size_t * resid)625 ufs_read(struct open_file *f, void *start, size_t size, size_t *resid)
626 {
627 	struct file *fp = (struct file *)f->f_fsdata;
628 	size_t csize;
629 	char *buf;
630 	size_t buf_size;
631 	int rc = 0;
632 	char *addr = start;
633 
634 	while (size != 0) {
635 		if (fp->f_seekp >= fp->f_di.di_size)
636 			break;
637 
638 		rc = buf_read_file(f, &buf, &buf_size);
639 		if (rc)
640 			break;
641 
642 		csize = size;
643 		if (csize > buf_size)
644 			csize = buf_size;
645 
646 		bcopy(buf, addr, csize);
647 
648 		fp->f_seekp += csize;
649 		addr += csize;
650 		size -= csize;
651 	}
652 	if (resid)
653 		*resid = size;
654 	return (rc);
655 }
656 
657 static off_t
ufs_seek(struct open_file * f,off_t offset,int where)658 ufs_seek(struct open_file *f, off_t offset, int where)
659 {
660 	struct file *fp = (struct file *)f->f_fsdata;
661 
662 	switch (where) {
663 	case SEEK_SET:
664 		fp->f_seekp = offset;
665 		break;
666 	case SEEK_CUR:
667 		fp->f_seekp += offset;
668 		break;
669 	case SEEK_END:
670 		fp->f_seekp = fp->f_di.di_size - offset;
671 		break;
672 	default:
673 		return (-1);
674 	}
675 	return (fp->f_seekp);
676 }
677 
678 static int
ufs_stat(struct open_file * f,struct stat * sb)679 ufs_stat(struct open_file *f, struct stat *sb)
680 {
681 	struct file *fp = (struct file *)f->f_fsdata;
682 
683 	/* only important stuff */
684 	sb->st_mode = fp->f_di.di_mode;
685 	sb->st_uid = fp->f_di.di_uid;
686 	sb->st_gid = fp->f_di.di_gid;
687 	sb->st_size = fp->f_di.di_size;
688 	return (0);
689 }
690 
691 static int
ufs_readdir(struct open_file * f,struct dirent * d)692 ufs_readdir(struct open_file *f, struct dirent *d)
693 {
694 	struct file *fp = (struct file *)f->f_fsdata;
695 	struct direct *dp;
696 	char *buf;
697 	size_t buf_size;
698 	int error;
699 
700 	/*
701 	 * assume that a directory entry will not be split across blocks
702 	 */
703 again:
704 	if (fp->f_seekp >= fp->f_di.di_size)
705 		return (ENOENT);
706 	error = buf_read_file(f, &buf, &buf_size);
707 	if (error)
708 		return (error);
709 	dp = (struct direct *)buf;
710 	fp->f_seekp += dp->d_reclen;
711 	if (dp->d_ino == (ino_t)0)
712 		goto again;
713 	d->d_type = dp->d_type;
714 	strcpy(d->d_name, dp->d_name);
715 	return (0);
716 }
717 
718 #ifdef COMPAT_UFS
719 /*
720  * Sanity checks for old file systems.
721  *
722  * XXX - goes away some day.
723  */
724 static void
ffs_oldfscompat(struct fs * fs)725 ffs_oldfscompat(struct fs *fs)
726 {
727 	int i;
728 
729 	fs->fs_npsect = max(fs->fs_npsect, fs->fs_nsect);	/* XXX */
730 	fs->fs_interleave = max(fs->fs_interleave, 1);		/* XXX */
731 	if (fs->fs_postblformat == FS_42POSTBLFMT)		/* XXX */
732 		fs->fs_nrpos = 8;				/* XXX */
733 	if (fs->fs_inodefmt < FS_44INODEFMT) {			/* XXX */
734 		quad_t sizepb = fs->fs_bsize;			/* XXX */
735 								/* XXX */
736 		fs->fs_maxfilesize = fs->fs_bsize * UFS_NDADDR - 1; /* XXX */
737 		for (i = 0; i < UFS_NIADDR; i++) {		/* XXX */
738 			sizepb *= NINDIR(fs);			/* XXX */
739 			fs->fs_maxfilesize += sizepb;		/* XXX */
740 		}						/* XXX */
741 		fs->fs_qbmask = ~fs->fs_bmask;			/* XXX */
742 		fs->fs_qfmask = ~fs->fs_fmask;			/* XXX */
743 	}							/* XXX */
744 }
745 #endif
746