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