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