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