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