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