Home | History | Annotate | Line # | Download | only in libsa
ufs.c revision 1.35
      1 /*	$NetBSD: ufs.c,v 1.35 2003/04/11 11:24:49 dsl 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. All advertising materials mentioning features or use of this software
     19  *    must display the following acknowledgement:
     20  *	This product includes software developed by the University of
     21  *	California, Berkeley and its contributors.
     22  * 4. Neither the name of the University nor the names of its contributors
     23  *    may be used to endorse or promote products derived from this software
     24  *    without specific prior written permission.
     25  *
     26  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     27  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     28  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     29  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     30  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     31  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     32  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     33  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     34  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     35  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     36  * SUCH DAMAGE.
     37  *
     38  *
     39  * Copyright (c) 1990, 1991 Carnegie Mellon University
     40  * All Rights Reserved.
     41  *
     42  * Author: David Golub
     43  *
     44  * Permission to use, copy, modify and distribute this software and its
     45  * documentation is hereby granted, provided that both the copyright
     46  * notice and this permission notice appear in all copies of the
     47  * software, derivative works or modified versions, and any portions
     48  * thereof, and that both notices appear in supporting documentation.
     49  *
     50  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
     51  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
     52  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
     53  *
     54  * Carnegie Mellon requests users of this software to return to
     55  *
     56  *  Software Distribution Coordinator  or  Software.Distribution (at) CS.CMU.EDU
     57  *  School of Computer Science
     58  *  Carnegie Mellon University
     59  *  Pittsburgh PA 15213-3890
     60  *
     61  * any improvements or extensions that they make and grant Carnegie the
     62  * rights to redistribute these changes.
     63  */
     64 
     65 /*
     66  * XXX NOTE: ufs.c (FFS) and lfs.c (LFS) should eventually use much common
     67  * XXX code.  until then, the two files should be easily diffable.
     68  */
     69 
     70 /*
     71  *	Stand-alone file reading package.
     72  */
     73 
     74 #include <sys/param.h>
     75 #include <sys/time.h>
     76 #include <ufs/ufs/dinode.h>
     77 #include <ufs/ufs/dir.h>
     78 #ifdef LIBSA_LFS
     79 #include <sys/queue.h>
     80 #include <sys/mount.h>			/* XXX for MNAMELEN */
     81 #include <ufs/lfs/lfs.h>
     82 #else
     83 #include <ufs/ffs/fs.h>
     84 #endif
     85 #ifdef _STANDALONE
     86 #include <lib/libkern/libkern.h>
     87 #else
     88 #include <string.h>
     89 #endif
     90 
     91 #include "stand.h"
     92 #ifdef LIBSA_LFS
     93 #include "lfs.h"
     94 #else
     95 #include "ufs.h"
     96 #endif
     97 
     98 /* If this file is compiled by itself, build ufs (aka ffsv1) support */
     99 #if !defined(LIBSA_FFSv2) && !defined(LIBSA_LFS)
    100 #define LIBSA_FFSv1
    101 #endif
    102 
    103 #if defined(LIBSA_FS_SINGLECOMPONENT) && !defined(LIBSA_NO_FS_SYMLINK)
    104 #define LIBSA_NO_FS_SYMLINK
    105 #endif
    106 #if defined(COMPAT_UFS) && defined(LIBSA_NO_COMPAT_UFS)
    107 #undef COMPAT_UFS
    108 #endif
    109 
    110 #ifdef LIBSA_LFS
    111 /*
    112  * In-core LFS superblock.  This exists only to placate the macros in lfs.h,
    113  */
    114 struct fs {
    115 	struct dlfs	lfs_dlfs;
    116 };
    117 #define fs_magic	lfs_magic
    118 #define fs_maxsymlinklen lfs_maxsymlinklen
    119 
    120 #define FS_MAGIC	LFS_MAGIC
    121 #define SBLOCKSIZE	LFS_SBPAD
    122 #define SBLOCKOFFSET	LFS_LABELPAD
    123 #else
    124 /* NB ufs2 doesn't use the common suberblock code... */
    125 #define FS_MAGIC	FS_UFS1_MAGIC
    126 #define SBLOCKOFFSET	SBLOCK_UFS1
    127 #endif
    128 
    129 #if defined(LIBSA_NO_TWIDDLE)
    130 #define twiddle()
    131 #endif
    132 
    133 #ifndef ufs_dinode
    134 #define ufs_dinode	ufs1_dinode
    135 #endif
    136 #ifndef indp_t
    137 #define indp_t		uint32_t
    138 #endif
    139 #ifndef FSBTODB
    140 #define FSBTODB(fs, daddr) fsbtodb(fs, daddr)
    141 #endif
    142 
    143 /*
    144  * In-core open file.
    145  */
    146 struct file {
    147 	off_t		f_seekp;	/* seek pointer */
    148 	struct fs	*f_fs;		/* pointer to super-block */
    149 	struct ufs_dinode	f_di;		/* copy of on-disk inode */
    150 	daddr_t		f_nindir[NIADDR];
    151 					/* number of blocks mapped by
    152 					   indirect block at level i */
    153 	int		f_l2indir[NIADDR]; /* log2(f_nindir) */
    154 	char		*f_blk[NIADDR];	/* buffer for indirect block at
    155 					   level i */
    156 	size_t		f_blksize[NIADDR];
    157 					/* size of buffer */
    158 	daddr_t		f_blkno[NIADDR];/* disk address of block in buffer */
    159 	char		*f_buf;		/* buffer for data block */
    160 	size_t		f_buf_size;	/* size of data block */
    161 	daddr_t		f_buf_blkno;	/* block number of data block */
    162 };
    163 
    164 static int	read_inode __P((ino_t, struct open_file *));
    165 static int	block_map __P((struct open_file *, daddr_t, daddr_t *));
    166 static int	buf_read_file __P((struct open_file *, char **, size_t *));
    167 static int	search_directory __P((char *, struct open_file *, ino_t *));
    168 #ifdef LIBSA_FFSv1
    169 static void	ffs_oldfscompat __P((struct fs *));
    170 #endif
    171 #ifdef LIBSA_FFSv2
    172 static int	ffs_find_superblock __P((struct open_file *, struct fs *));
    173 #endif
    174 
    175 #ifdef LIBSA_LFS
    176 /*
    177  * Find an inode's block.  Look it up in the ifile.  Whee!
    178  */
    179 static int
    180 find_inode_sector(ino_t inumber, struct open_file *f, daddr_t *isp)
    181 {
    182 	struct file *fp = (struct file *)f->f_fsdata;
    183 	struct fs *fs = fp->f_fs;
    184 	daddr_t ifileent_blkno;
    185 	char *ent_in_buf;
    186 	size_t buf_after_ent;
    187 	int rc;
    188 
    189 	rc = read_inode(fs->lfs_ifile, f);
    190 	if (rc)
    191 		return (rc);
    192 
    193 	ifileent_blkno =
    194 	    (inumber / fs->lfs_ifpb) + fs->lfs_cleansz + fs->lfs_segtabsz;
    195 	fp->f_seekp = (off_t)ifileent_blkno * fs->fs_bsize +
    196 	    (inumber % fs->lfs_ifpb) * sizeof (IFILE_Vx);
    197 	rc = buf_read_file(f, &ent_in_buf, &buf_after_ent);
    198 	if (rc)
    199 		return (rc);
    200 	/* make sure something's not badly wrong, but don't panic. */
    201 	if (buf_after_ent < sizeof (IFILE_Vx))
    202 		return (EINVAL);
    203 
    204 	*isp = FSBTODB(fs, ((IFILE_Vx *)ent_in_buf)->if_daddr);
    205 	if (*isp == LFS_UNUSED_DADDR)	/* again, something badly wrong */
    206 		return (EINVAL);
    207 	return (0);
    208 }
    209 #endif
    210 
    211 /*
    212  * Read a new inode into a file structure.
    213  */
    214 static int
    215 read_inode(inumber, f)
    216 	ino_t inumber;
    217 	struct open_file *f;
    218 {
    219 	struct file *fp = (struct file *)f->f_fsdata;
    220 	struct fs *fs = fp->f_fs;
    221 	char *buf;
    222 	size_t rsize;
    223 	int rc;
    224 	daddr_t inode_sector;
    225 #ifdef LIBSA_LFS
    226 	struct ufs_dinode *dip;
    227 	int cnt;
    228 #endif
    229 
    230 #ifdef LIBSA_LFS
    231 	if (inumber == fs->lfs_ifile)
    232 		inode_sector = FSBTODB(fs, fs->lfs_idaddr);
    233 	else if ((rc = find_inode_sector(inumber, f, &inode_sector)) != 0)
    234 		return (rc);
    235 #else
    236 	inode_sector = FSBTODB(fs, ino_to_fsba(fs, inumber));
    237 #endif
    238 
    239 	/*
    240 	 * Read inode and save it.
    241 	 */
    242 	buf = alloc(fs->fs_bsize);
    243 	twiddle();
    244 	rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
    245 		inode_sector, fs->fs_bsize,
    246 		buf, &rsize);
    247 	if (rc)
    248 		goto out;
    249 	if (rsize != fs->fs_bsize) {
    250 		rc = EIO;
    251 		goto out;
    252 	}
    253 
    254 #ifdef LIBSA_LFS
    255 	rc = EINVAL;
    256 	cnt = INOPBx(fs);
    257 	for (dip = (struct ufs_dinode *)buf + (cnt - 1); cnt--; --dip) {
    258                 if (dip->di_inumber == inumber) {
    259                         rc = 0;
    260 			break;
    261 		}
    262 	}
    263 	/* kernel code panics, but boot blocks which panic are Bad. */
    264 	if (rc)
    265 		goto out;
    266 	fp->f_di = *dip;
    267 #else
    268 	fp->f_di = ((struct ufs_dinode *)buf)[ino_to_fsbo(fs, inumber)];
    269 #endif
    270 
    271 	/*
    272 	 * Clear out the old buffers
    273 	 */
    274 	{
    275 		int level;
    276 
    277 		for (level = 0; level < NIADDR; level++)
    278 			fp->f_blkno[level] = -1;
    279 		fp->f_buf_blkno = -1;
    280 	}
    281 out:
    282 	free(buf, fs->fs_bsize);
    283 	return (rc);
    284 }
    285 
    286 /*
    287  * Given an offset in a file, find the disk block number that
    288  * contains that block.
    289  */
    290 static int
    291 block_map(f, file_block, disk_block_p)
    292 	struct open_file *f;
    293 	daddr_t file_block;
    294 	daddr_t *disk_block_p;	/* out */
    295 {
    296 	struct file *fp = (struct file *)f->f_fsdata;
    297 	struct fs *fs = fp->f_fs;
    298 	int level;
    299 	int idx;
    300 	daddr_t ind_block_num;
    301 	indp_t *ind_p;
    302 	int rc;
    303 
    304 	/*
    305 	 * Index structure of an inode:
    306 	 *
    307 	 * di_db[0..NDADDR-1]	hold block numbers for blocks
    308 	 *			0..NDADDR-1
    309 	 *
    310 	 * di_ib[0]		index block 0 is the single indirect block
    311 	 *			holds block numbers for blocks
    312 	 *			NDADDR .. NDADDR + NINDIR(fs)-1
    313 	 *
    314 	 * di_ib[1]		index block 1 is the double indirect block
    315 	 *			holds block numbers for INDEX blocks for blocks
    316 	 *			NDADDR + NINDIR(fs) ..
    317 	 *			NDADDR + NINDIR(fs) + NINDIR(fs)**2 - 1
    318 	 *
    319 	 * di_ib[2]		index block 2 is the triple indirect block
    320 	 *			holds block numbers for double-indirect
    321 	 *			blocks for blocks
    322 	 *			NDADDR + NINDIR(fs) + NINDIR(fs)**2 ..
    323 	 *			NDADDR + NINDIR(fs) + NINDIR(fs)**2
    324 	 *				+ NINDIR(fs)**3 - 1
    325 	 */
    326 
    327 	if (file_block < NDADDR) {
    328 		/* Direct block. */
    329 		*disk_block_p = fp->f_di.di_db[file_block];
    330 		return (0);
    331 	}
    332 
    333 	file_block -= NDADDR;
    334 
    335 	/*
    336 	 * nindir[0] = NINDIR
    337 	 * nindir[1] = NINDIR**2
    338 	 * nindir[2] = NINDIR**3
    339 	 *	etc
    340 	 */
    341 	for (level = 0; level < NIADDR; level++) {
    342 		if (file_block < fp->f_nindir[level])
    343 			break;
    344 		file_block -= fp->f_nindir[level];
    345 	}
    346 	if (level == NIADDR) {
    347 		/* Block number too high */
    348 		return (EFBIG);
    349 	}
    350 
    351 	ind_block_num = fp->f_di.di_ib[level];
    352 
    353 	for (; level >= 0; level--) {
    354 		if (ind_block_num == 0) {
    355 			*disk_block_p = 0;	/* missing */
    356 			return (0);
    357 		}
    358 
    359 		if (fp->f_blkno[level] != ind_block_num) {
    360 			if (fp->f_blk[level] == (char *)0)
    361 				fp->f_blk[level] =
    362 					alloc(fs->fs_bsize);
    363 			twiddle();
    364 			rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
    365 				FSBTODB(fp->f_fs, ind_block_num),
    366 				fs->fs_bsize,
    367 				fp->f_blk[level],
    368 				&fp->f_blksize[level]);
    369 			if (rc)
    370 				return (rc);
    371 			if (fp->f_blksize[level] != fs->fs_bsize)
    372 				return (EIO);
    373 			fp->f_blkno[level] = ind_block_num;
    374 		}
    375 
    376 		if (level > 0) {
    377 			idx = file_block >> fp->f_l2indir[level - 1];
    378 			file_block &= fp->f_nindir[level - 1] - 1;
    379 		} else
    380 			idx = file_block;
    381 
    382 		ind_p = (void *)fp->f_blk[level];
    383 		ind_block_num = ind_p[idx];
    384 	}
    385 
    386 	*disk_block_p = ind_block_num;
    387 
    388 	return (0);
    389 }
    390 
    391 /*
    392  * Read a portion of a file into an internal buffer.  Return
    393  * the location in the buffer and the amount in the buffer.
    394  */
    395 static int
    396 buf_read_file(f, buf_p, size_p)
    397 	struct open_file *f;
    398 	char **buf_p;		/* out */
    399 	size_t *size_p;		/* out */
    400 {
    401 	struct file *fp = (struct file *)f->f_fsdata;
    402 	struct fs *fs = fp->f_fs;
    403 	long off;
    404 	daddr_t file_block;
    405 	daddr_t	disk_block;
    406 	size_t block_size;
    407 	int rc;
    408 
    409 	off = blkoff(fs, fp->f_seekp);
    410 	file_block = lblkno(fs, fp->f_seekp);
    411 #ifdef LIBSA_LFS
    412 	block_size = dblksize(fs, &fp->f_di, file_block);
    413 #else
    414 	block_size = sblksize(fs, fp->f_di.di_size, file_block);
    415 #endif
    416 
    417 	if (file_block != fp->f_buf_blkno) {
    418 		rc = block_map(f, file_block, &disk_block);
    419 		if (rc)
    420 			return (rc);
    421 
    422 		if (fp->f_buf == (char *)0)
    423 			fp->f_buf = alloc(fs->fs_bsize);
    424 
    425 		if (disk_block == 0) {
    426 			bzero(fp->f_buf, block_size);
    427 			fp->f_buf_size = block_size;
    428 		} else {
    429 			twiddle();
    430 			rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
    431 				FSBTODB(fs, disk_block),
    432 				block_size, fp->f_buf, &fp->f_buf_size);
    433 			if (rc)
    434 				return (rc);
    435 		}
    436 
    437 		fp->f_buf_blkno = file_block;
    438 	}
    439 
    440 	/*
    441 	 * Return address of byte in buffer corresponding to
    442 	 * offset, and size of remainder of buffer after that
    443 	 * byte.
    444 	 */
    445 	*buf_p = fp->f_buf + off;
    446 	*size_p = block_size - off;
    447 
    448 	/*
    449 	 * But truncate buffer at end of file.
    450 	 */
    451 	if (*size_p > fp->f_di.di_size - fp->f_seekp)
    452 		*size_p = fp->f_di.di_size - fp->f_seekp;
    453 
    454 	return (0);
    455 }
    456 
    457 /*
    458  * Search a directory for a name and return its
    459  * i_number.
    460  */
    461 static int
    462 search_directory(name, f, inumber_p)
    463 	char *name;
    464 	struct open_file *f;
    465 	ino_t *inumber_p;		/* out */
    466 {
    467 	struct file *fp = (struct file *)f->f_fsdata;
    468 	struct direct *dp;
    469 	struct direct *edp;
    470 	char *buf;
    471 	size_t buf_size;
    472 	int namlen, length;
    473 	int rc;
    474 
    475 	length = strlen(name);
    476 
    477 	fp->f_seekp = 0;
    478 	while (fp->f_seekp < fp->f_di.di_size) {
    479 		rc = buf_read_file(f, &buf, &buf_size);
    480 		if (rc)
    481 			return (rc);
    482 
    483 		dp = (struct direct *)buf;
    484 		edp = (struct direct *)(buf + buf_size);
    485 		while (dp < edp) {
    486 			if (dp->d_ino == (ino_t)0)
    487 				goto next;
    488 #if BYTE_ORDER == LITTLE_ENDIAN
    489 			if (fp->f_fs->fs_maxsymlinklen <= 0)
    490 				namlen = dp->d_type;
    491 			else
    492 #endif
    493 				namlen = dp->d_namlen;
    494 			if (namlen == length &&
    495 			    !strcmp(name, dp->d_name)) {
    496 				/* found entry */
    497 				*inumber_p = dp->d_ino;
    498 				return (0);
    499 			}
    500 		next:
    501 			dp = (struct direct *)((char *)dp + dp->d_reclen);
    502 		}
    503 		fp->f_seekp += buf_size;
    504 	}
    505 	return (ENOENT);
    506 }
    507 
    508 #ifdef LIBSA_FFSv2
    509 
    510 daddr_t sblock_try[] = SBLOCKSEARCH;
    511 
    512 static int
    513 ffs_find_superblock(f, fs)
    514 	struct open_file *f;
    515 	struct fs *fs;
    516 {
    517 	int i, rc;
    518 	size_t buf_size;
    519 
    520 	for (i = 0; sblock_try[i] != -1; i++) {
    521 		rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
    522 		    sblock_try[i] / DEV_BSIZE, SBLOCKSIZE, (char *)fs,
    523 		    &buf_size);
    524 		if (rc != 0 || buf_size != SBLOCKSIZE)
    525 			return rc;
    526 		if (fs->fs_magic == FS_UFS2_MAGIC) {
    527 			return 0;
    528 		}
    529 	}
    530 	return EINVAL;
    531 }
    532 
    533 #endif
    534 
    535 /*
    536  * Open a file.
    537  */
    538 int
    539 ufs_open(path, f)
    540 	char *path;
    541 	struct open_file *f;
    542 {
    543 #ifndef LIBSA_FS_SINGLECOMPONENT
    544 	char *cp, *ncp;
    545 	int c;
    546 #endif
    547 	ino_t inumber;
    548 	struct file *fp;
    549 	struct fs *fs;
    550 	int rc;
    551 #ifndef LIBSA_NO_FS_SYMLINK
    552 	ino_t parent_inumber;
    553 	int nlinks = 0;
    554 	char namebuf[MAXPATHLEN+1];
    555 	char *buf = NULL;
    556 #endif
    557 
    558 	/* allocate file system specific data structure */
    559 	fp = alloc(sizeof(struct file));
    560 	bzero(fp, sizeof(struct file));
    561 	f->f_fsdata = (void *)fp;
    562 
    563 	/* allocate space and read super block */
    564 	fs = alloc(SBLOCKSIZE);
    565 	fp->f_fs = fs;
    566 	twiddle();
    567 
    568 #ifdef LIBSA_FFSv2
    569 	rc = ffs_find_superblock(f, fs);
    570 	if (rc)
    571 		goto out;
    572 #else
    573 	{
    574 		size_t buf_size;
    575 		rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
    576 			SBLOCKOFFSET / DEV_BSIZE,
    577 			SBLOCKSIZE, (char *)fs, &buf_size);
    578 		if (rc)
    579 			goto out;
    580 		if (buf_size != SBLOCKSIZE ||
    581 #ifdef LIBSA_FFS
    582 		    fs->lfs_version != REQUIRED_LFS_VERSION ||
    583 #endif
    584 		    fs->fs_magic != FS_MAGIC) {
    585 			rc = EINVAL;
    586 			goto out;
    587 		}
    588 	}
    589 #if defined(LIBSA_LFS) && REQUIRED_LFS_VERSION == 2
    590 	/*
    591 	 * XXX	We should check the second superblock and use the eldest
    592 	 *	of the two.  See comments near the top of lfs_mountfs()
    593 	 *	in sys/ufs/lfs/lfs_vfsops.c.
    594 	 *      This may need a LIBSA_LFS_SMALL check as well.
    595 	 */
    596 #endif
    597 #endif
    598 
    599 #ifdef LIBSA_FFSv1
    600 	ffs_oldfscompat(fs);
    601 #endif
    602 
    603 	if (fs->fs_bsize > MAXBSIZE || fs->fs_bsize < sizeof(struct fs)) {
    604 		rc = EINVAL;
    605 		goto out;
    606 	}
    607 
    608 	/*
    609 	 * Calculate indirect block levels.
    610 	 */
    611 	{
    612 		daddr_t mult;
    613 		int level;
    614 		int ln2;
    615 
    616 		/*
    617 		 * We note that the number of indirect blocks is always
    618 		 * a power of 2.  This lets us use shifts and masks instead
    619 		 * of divide and remainder and avoinds pulling in the
    620 		 * 64bit division routine into the boot code.
    621 		 */
    622 		mult = NINDIR(fs);
    623 #ifdef DEBUG
    624 		if (mult & (mult - 1)) {
    625 			/* Hummm was't a power of 2 */
    626 			rc = EINVAL;
    627 			goto out;
    628 		}
    629 #endif
    630 		for (ln2 = 0; mult != 1; ln2++)
    631 			mult >>= 1;
    632 
    633 		for (level = 0; level < NIADDR; level++) {
    634 			mult *= NINDIR(fs);
    635 			fp->f_nindir[level] = mult;
    636 			fp->f_l2indir[level] = ln2 * (level + 1);
    637 		}
    638 	}
    639 
    640 	inumber = ROOTINO;
    641 	if ((rc = read_inode(inumber, f)) != 0)
    642 		goto out;
    643 
    644 #ifndef LIBSA_FS_SINGLECOMPONENT
    645 	cp = path;
    646 	while (*cp) {
    647 
    648 		/*
    649 		 * Remove extra separators
    650 		 */
    651 		while (*cp == '/')
    652 			cp++;
    653 		if (*cp == '\0')
    654 			break;
    655 
    656 		/*
    657 		 * Check that current node is a directory.
    658 		 */
    659 		if ((fp->f_di.di_mode & IFMT) != IFDIR) {
    660 			rc = ENOTDIR;
    661 			goto out;
    662 		}
    663 
    664 		/*
    665 		 * Get next component of path name.
    666 		 */
    667 		{
    668 			int len = 0;
    669 
    670 			ncp = cp;
    671 			while ((c = *cp) != '\0' && c != '/') {
    672 				if (++len > MAXNAMLEN) {
    673 					rc = ENOENT;
    674 					goto out;
    675 				}
    676 				cp++;
    677 			}
    678 			*cp = '\0';
    679 		}
    680 
    681 		/*
    682 		 * Look up component in current directory.
    683 		 * Save directory inumber in case we find a
    684 		 * symbolic link.
    685 		 */
    686 #ifndef LIBSA_NO_FS_SYMLINK
    687 		parent_inumber = inumber;
    688 #endif
    689 		rc = search_directory(ncp, f, &inumber);
    690 		*cp = c;
    691 		if (rc)
    692 			goto out;
    693 
    694 		/*
    695 		 * Open next component.
    696 		 */
    697 		if ((rc = read_inode(inumber, f)) != 0)
    698 			goto out;
    699 
    700 #ifndef LIBSA_NO_FS_SYMLINK
    701 		/*
    702 		 * Check for symbolic link.
    703 		 */
    704 		if ((fp->f_di.di_mode & IFMT) == IFLNK) {
    705 			int link_len = fp->f_di.di_size;
    706 			int len;
    707 
    708 			len = strlen(cp);
    709 
    710 			if (link_len + len > MAXPATHLEN ||
    711 			    ++nlinks > MAXSYMLINKS) {
    712 				rc = ENOENT;
    713 				goto out;
    714 			}
    715 
    716 			bcopy(cp, &namebuf[link_len], len + 1);
    717 
    718 			if (link_len < fs->fs_maxsymlinklen) {
    719 				bcopy(fp->f_di.di_db, namebuf,
    720 				      (unsigned)link_len);
    721 			} else {
    722 				/*
    723 				 * Read file for symbolic link
    724 				 */
    725 				size_t buf_size;
    726 				daddr_t	disk_block;
    727 
    728 				if (!buf)
    729 					buf = alloc(fs->fs_bsize);
    730 				rc = block_map(f, (daddr_t)0, &disk_block);
    731 				if (rc)
    732 					goto out;
    733 
    734 				twiddle();
    735 				rc = DEV_STRATEGY(f->f_dev)(f->f_devdata,
    736 					F_READ, FSBTODB(fs, disk_block),
    737 					fs->fs_bsize, buf, &buf_size);
    738 				if (rc)
    739 					goto out;
    740 
    741 				bcopy(buf, namebuf, (unsigned)link_len);
    742 			}
    743 
    744 			/*
    745 			 * If relative pathname, restart at parent directory.
    746 			 * If absolute pathname, restart at root.
    747 			 */
    748 			cp = namebuf;
    749 			if (*cp != '/')
    750 				inumber = parent_inumber;
    751 			else
    752 				inumber = (ino_t)ROOTINO;
    753 
    754 			if ((rc = read_inode(inumber, f)) != 0)
    755 				goto out;
    756 		}
    757 #endif	/* !LIBSA_NO_FS_SYMLINK */
    758 	}
    759 
    760 	/*
    761 	 * Found terminal component.
    762 	 */
    763 	rc = 0;
    764 
    765 #else /* !LIBSA_FS_SINGLECOMPONENT */
    766 
    767 	/* look up component in the current (root) directory */
    768 	rc = search_directory(path, f, &inumber);
    769 	if (rc)
    770 		goto out;
    771 
    772 	/* open it */
    773 	rc = read_inode(inumber, f);
    774 
    775 #endif /* !LIBSA_FS_SINGLECOMPONENT */
    776 
    777         fp->f_seekp = 0;		/* reset seek pointer */
    778 
    779 out:
    780 #ifndef LIBSA_NO_FS_SYMLINK
    781 	if (buf)
    782 		free(buf, fs->fs_bsize);
    783 #endif
    784 	if (rc) {
    785 		if (fp->f_buf)
    786 			free(fp->f_buf, fp->f_fs->fs_bsize);
    787 		free(fp->f_fs, SBLOCKSIZE);
    788 		free(fp, sizeof(struct file));
    789 	}
    790 	return (rc);
    791 }
    792 
    793 #ifndef LIBSA_NO_FS_CLOSE
    794 int
    795 ufs_close(f)
    796 	struct open_file *f;
    797 {
    798 	struct file *fp = (struct file *)f->f_fsdata;
    799 	int level;
    800 
    801 	f->f_fsdata = (void *)0;
    802 	if (fp == (struct file *)0)
    803 		return (0);
    804 
    805 	for (level = 0; level < NIADDR; level++) {
    806 		if (fp->f_blk[level])
    807 			free(fp->f_blk[level], fp->f_fs->fs_bsize);
    808 	}
    809 	if (fp->f_buf)
    810 		free(fp->f_buf, fp->f_fs->fs_bsize);
    811 	free(fp->f_fs, SBLOCKSIZE);
    812 	free(fp, sizeof(struct file));
    813 	return (0);
    814 }
    815 #endif /* !LIBSA_NO_FS_CLOSE */
    816 
    817 /*
    818  * Copy a portion of a file into kernel memory.
    819  * Cross block boundaries when necessary.
    820  */
    821 int
    822 ufs_read(f, start, size, resid)
    823 	struct open_file *f;
    824 	void *start;
    825 	size_t size;
    826 	size_t *resid;	/* out */
    827 {
    828 	struct file *fp = (struct file *)f->f_fsdata;
    829 	size_t csize;
    830 	char *buf;
    831 	size_t buf_size;
    832 	int rc = 0;
    833 	char *addr = start;
    834 
    835 	while (size != 0) {
    836 		if (fp->f_seekp >= fp->f_di.di_size)
    837 			break;
    838 
    839 		rc = buf_read_file(f, &buf, &buf_size);
    840 		if (rc)
    841 			break;
    842 
    843 		csize = size;
    844 		if (csize > buf_size)
    845 			csize = buf_size;
    846 
    847 		bcopy(buf, addr, csize);
    848 
    849 		fp->f_seekp += csize;
    850 		addr += csize;
    851 		size -= csize;
    852 	}
    853 	if (resid)
    854 		*resid = size;
    855 	return (rc);
    856 }
    857 
    858 /*
    859  * Not implemented.
    860  */
    861 #ifndef LIBSA_NO_FS_WRITE
    862 int
    863 ufs_write(f, start, size, resid)
    864 	struct open_file *f;
    865 	void *start;
    866 	size_t size;
    867 	size_t *resid;	/* out */
    868 {
    869 
    870 	return (EROFS);
    871 }
    872 #endif /* !LIBSA_NO_FS_WRITE */
    873 
    874 #ifndef LIBSA_NO_FS_SEEK
    875 off_t
    876 ufs_seek(f, offset, where)
    877 	struct open_file *f;
    878 	off_t offset;
    879 	int where;
    880 {
    881 	struct file *fp = (struct file *)f->f_fsdata;
    882 
    883 	switch (where) {
    884 	case SEEK_SET:
    885 		fp->f_seekp = offset;
    886 		break;
    887 	case SEEK_CUR:
    888 		fp->f_seekp += offset;
    889 		break;
    890 	case SEEK_END:
    891 		fp->f_seekp = fp->f_di.di_size - offset;
    892 		break;
    893 	default:
    894 		return (-1);
    895 	}
    896 	return (fp->f_seekp);
    897 }
    898 #endif /* !LIBSA_NO_FS_SEEK */
    899 
    900 int
    901 ufs_stat(f, sb)
    902 	struct open_file *f;
    903 	struct stat *sb;
    904 {
    905 	struct file *fp = (struct file *)f->f_fsdata;
    906 
    907 	/* only important stuff */
    908 	sb->st_mode = fp->f_di.di_mode;
    909 	sb->st_uid = fp->f_di.di_uid;
    910 	sb->st_gid = fp->f_di.di_gid;
    911 	sb->st_size = fp->f_di.di_size;
    912 	return (0);
    913 }
    914 
    915 #ifdef LIBSA_FFSv1
    916 /*
    917  * Sanity checks for old file systems.
    918  *
    919  * XXX - goes away some day.
    920  */
    921 static void
    922 ffs_oldfscompat(fs)
    923 	struct fs *fs;
    924 {
    925 #ifdef COMPAT_UFS
    926 	int i;
    927 #endif
    928 
    929 	if (fs->fs_magic == FS_UFS1_MAGIC && fs->fs_size != fs->fs_old_size) {
    930 		fs->fs_maxbsize = fs->fs_bsize;
    931 		fs->fs_time = fs->fs_old_time;
    932 		fs->fs_size = fs->fs_old_size;
    933 		fs->fs_dsize = fs->fs_old_dsize;
    934 		fs->fs_csaddr = fs->fs_old_csaddr;
    935 		fs->fs_cstotal.cs_ndir = fs->fs_old_cstotal.cs_ndir;
    936 		fs->fs_cstotal.cs_nbfree = fs->fs_old_cstotal.cs_nbfree;
    937 		fs->fs_cstotal.cs_nifree = fs->fs_old_cstotal.cs_nifree;
    938 		fs->fs_cstotal.cs_nffree = fs->fs_old_cstotal.cs_nffree;
    939 	}
    940 #ifdef COMPAT_UFS
    941 	if (fs->fs_magic == FS_UFS1_MAGIC &&
    942 	    fs->fs_old_inodefmt < FS_44INODEFMT) {
    943 		quad_t sizepb = fs->fs_bsize;
    944 		fs->fs_maxfilesize = fs->fs_bsize * NDADDR - 1;
    945 		for (i = 0; i < NIADDR; i++) {
    946 			sizepb *= NINDIR(fs);
    947 			fs->fs_maxfilesize += sizepb;
    948 		}
    949 		fs->fs_qbmask = ~fs->fs_bmask;
    950 		fs->fs_qfmask = ~fs->fs_fmask;
    951 	}
    952 #endif
    953 }
    954 #endif
    955