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