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