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