Home | History | Annotate | Line # | Download | only in libsa
      1 /*	$NetBSD: ufs.c,v 1.88 2022/12/01 18:06:09 christos Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 1993
      5  *	The Regents of the University of California.  All rights reserved.
      6  *
      7  * This code is derived from software contributed to Berkeley by
      8  * The Mach Operating System project at Carnegie-Mellon University.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  * 3. Neither the name of the University nor the names of its contributors
     19  *    may be used to endorse or promote products derived from this software
     20  *    without specific prior written permission.
     21  *
     22  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     32  * SUCH DAMAGE.
     33  *
     34  *
     35  * Copyright (c) 1990, 1991 Carnegie Mellon University
     36  * All Rights Reserved.
     37  *
     38  * Author: David Golub
     39  *
     40  * Permission to use, copy, modify and distribute this software and its
     41  * documentation is hereby granted, provided that both the copyright
     42  * notice and this permission notice appear in all copies of the
     43  * software, derivative works or modified versions, and any portions
     44  * thereof, and that both notices appear in supporting documentation.
     45  *
     46  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
     47  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
     48  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
     49  *
     50  * Carnegie Mellon requests users of this software to return to
     51  *
     52  *  Software Distribution Coordinator  or  Software.Distribution (at) CS.CMU.EDU
     53  *  School of Computer Science
     54  *  Carnegie Mellon University
     55  *  Pittsburgh PA 15213-3890
     56  *
     57  * any improvements or extensions that they make and grant Carnegie the
     58  * rights to redistribute these changes.
     59  */
     60 
     61 /*
     62  *	Stand-alone file reading package for UFS and LFS filesystems.
     63  */
     64 
     65 #include <sys/param.h>
     66 #include <sys/time.h>
     67 #include <ufs/ufs/dinode.h>
     68 #include <ufs/ufs/dir.h>
     69 #ifdef LIBSA_LFS
     70 #include <sys/queue.h>
     71 #include <sys/condvar.h>
     72 #include <sys/mount.h>			/* XXX for MNAMELEN */
     73 #include <ufs/lfs/lfs.h>
     74 #else
     75 #include <ufs/ffs/fs.h>
     76 #endif
     77 #ifdef _STANDALONE
     78 #include <lib/libkern/libkern.h>
     79 #else
     80 #include <string.h>
     81 #endif
     82 
     83 #include "stand.h"
     84 #ifdef LIBSA_LFS
     85 #include "lfs.h"
     86 #else
     87 #include "ufs.h"
     88 #endif
     89 
     90 /* If this file is compiled by itself, build ufs (aka ffsv1) support */
     91 #if !defined(LIBSA_FFSv2) && !defined(LIBSA_LFS)
     92 #define LIBSA_FFSv1
     93 #endif
     94 
     95 #if defined(LIBSA_FS_SINGLECOMPONENT) && !defined(LIBSA_NO_FS_SYMLINK)
     96 #define LIBSA_NO_FS_SYMLINK
     97 #endif
     98 #if defined(COMPAT_UFS) && defined(LIBSA_NO_COMPAT_UFS)
     99 #undef COMPAT_UFS
    100 #endif
    101 
    102 #ifdef LIBSA_LFS
    103 /* Do not (yet) support FFS_EI on LFS. */
    104 #undef LIBSA_FFS_EI
    105 /*
    106  * In-core LFS superblock - just the on-disk one.
    107  */
    108 struct salfs {
    109 	union {
    110 		struct dlfs u_32;
    111 		struct dlfs64 u_64;
    112 	} lfs_dlfs_u;
    113 	unsigned lfs_is64 : 1,
    114 		lfs_dobyteswap : 1,
    115 		lfs_hasolddirfmt : 1;
    116 };
    117 /* Get lfs accessors that use struct salfs. */
    118 #define STRUCT_LFS struct salfs
    119 #include <ufs/lfs/lfs_accessors.h>
    120 
    121 /* override this to avoid a mess with the dinode accessors */
    122 #define lfs_dino_getsize(fs, dp) ((dp)->di_size)
    123 
    124 typedef struct salfs FS;
    125 #define fs_magic	lfs_dlfs_u.u_32.dlfs_magic
    126 #define fs_maxsymlinklen lfs_dlfs_u.u_32.dlfs_maxsymlinklen
    127 #define lfs_version	lfs_dlfs_u.u_32.dlfs_version
    128 
    129 #define SBLOCKSIZE	LFS_SBPAD
    130 #define SBLOCKOFFSET	LFS_LABELPAD
    131 #else
    132 /* NB ufs2 doesn't use the common superblock code... */
    133 typedef struct fs FS;
    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 #ifndef ufs_dinode_swap
    169 #define ufs_dinode_swap ffs_dinode1_swap
    170 #endif
    171 #ifndef ufs_indp_swap
    172 #define ufs_indp_swap bswap32
    173 #endif
    174 
    175 /*
    176  * To avoid having a lot of filesystem-block sized buffers lurking (which
    177  * could be 32k) we only keep a few entries of the indirect block map.
    178  * With 8k blocks, 2^8 blocks is ~500k so we reread the indirect block
    179  * ~13 times pulling in a 6M kernel.
    180  * The cache size must be smaller than the smallest filesystem block,
    181  * so LN2_IND_CACHE_SZ <= 9 (UFS2 and 4k blocks).
    182  */
    183 #define LN2_IND_CACHE_SZ	6
    184 #define IND_CACHE_SZ		(1 << LN2_IND_CACHE_SZ)
    185 #define IND_CACHE_MASK		(IND_CACHE_SZ - 1)
    186 
    187 /*
    188  * In-core open file.
    189  */
    190 struct file {
    191 	off_t		f_seekp;	/* seek pointer */
    192 	FS		*f_fs;		/* pointer to super-block */
    193 	struct ufs_dinode	f_di;		/* copy of on-disk inode */
    194 	uint		f_nishift;	/* for blocks in indirect block */
    195 	indp_t		f_ind_cache_block;
    196 	indp_t		f_ind_cache[IND_CACHE_SZ];
    197 
    198 	char		*f_buf;		/* buffer for data block */
    199 	size_t		f_buf_size;	/* size of data block */
    200 	daddr_t		f_buf_blkno;	/* block number of data block */
    201 #if defined(LIBSA_FFS_EI)
    202 	bool		f_swapped;	/* FFS is other endian */
    203 #endif
    204 };
    205 
    206 static int read_inode(ino32_t, struct open_file *);
    207 static int block_map(struct open_file *, indp_t, indp_t *);
    208 static int buf_read_file(struct open_file *, char **, size_t *);
    209 static int search_directory(const char *, int, struct open_file *, ino32_t *);
    210 #ifdef LIBSA_FFSv1
    211 static void ffs_oldfscompat(FS *);
    212 #endif
    213 
    214 #ifdef LIBSA_FFSv1
    215 static __inline__ bool
    216 ffs_is_magic(FS *fs)
    217 {
    218 	return fs->fs_magic == FS_UFS1_MAGIC;
    219 }
    220 
    221 #ifdef LIBSA_FFS_EI
    222 static __inline__ bool
    223 ffs_is_magic_swapped(FS *fs)
    224 {
    225 	return fs->fs_magic == bswap32(FS_UFS1_MAGIC);
    226 }
    227 #endif
    228 
    229 #endif
    230 
    231 #ifdef LIBSA_FFSv2
    232 static __inline__ bool
    233 ffs_is_magic(FS *fs)
    234 {
    235 	return fs->fs_magic == FS_UFS2_MAGIC || fs->fs_magic == FS_UFS2EA_MAGIC;
    236 }
    237 
    238 #ifdef LIBSA_FFS_EI
    239 static __inline__ bool
    240 ffs_is_magic_swapped(FS *fs)
    241 {
    242 	return fs->fs_magic == bswap32(FS_UFS2_MAGIC) ||
    243 		fs->fs_magic == bswap32(FS_UFS2EA_MAGIC);
    244 }
    245 #endif
    246 
    247 #endif
    248 
    249 #ifdef LIBSA_LFS
    250 static __inline__ bool
    251 ffs_is_magic(FS *fs)
    252 {
    253 	return fs->fs_magic == LFS_MAGIC;
    254 }
    255 
    256 #ifdef LIBSA_FFS_EI
    257 static __inline__ bool
    258 ffs_is_magic_swapped(FS *fs)
    259 {
    260 	return fs->fs_magic == bswap32(LFS_MAGIC);
    261 }
    262 #endif
    263 
    264 #endif
    265 
    266 static __inline__ void
    267 ffs_fix_magic_swapped(struct file *fp, FS *fs)
    268 {
    269 #ifdef LIBSA_FFS_EI
    270 	fp->f_swapped = ffs_is_magic_swapped(fs);
    271 	if (fp->f_swapped)
    272 {
    273 		ffs_sb_swap(fs, fs);
    274 }
    275 #endif
    276 }
    277 
    278 #ifdef LIBSA_FFS_EI
    279 static __inline__ bool
    280 ffs_swapped(struct file *fp)
    281 {
    282 	return fp->f_swapped;
    283 }
    284 #endif
    285 
    286 static __inline__ uint16_t
    287 ffs_get_reclen(struct file *fp, struct direct *dp)
    288 {
    289 #ifdef LIBSA_FFS_EI
    290 	if (ffs_swapped(fp))
    291 		return bswap16(dp->d_reclen);
    292 #endif
    293 	return dp->d_reclen;
    294 }
    295 
    296 static __inline__ uint32_t
    297 ffs_get_ino(struct file *fp, struct direct *dp)
    298 {
    299 #ifdef LIBSA_FFS_EI
    300 	if (ffs_swapped(fp))
    301 		return bswap32(dp->d_ino);
    302 #endif
    303 	return dp->d_ino;
    304 }
    305 
    306 
    307 #ifdef LIBSA_LFS
    308 /*
    309  * Find an inode's block.  Look it up in the ifile.  Whee!
    310  */
    311 static int
    312 find_inode_sector(ino32_t inumber, struct open_file *f, daddr_t *isp)
    313 {
    314 	struct file *fp = (struct file *)f->f_fsdata;
    315 	FS *fs = fp->f_fs;
    316 	daddr_t ifileent_blkno;
    317 	char *ent_in_buf;
    318 	size_t buf_after_ent;
    319 	size_t entsize;
    320 	int rc;
    321 
    322 	rc = read_inode(LFS_IFILE_INUM, f);
    323 	if (rc)
    324 		return rc;
    325 
    326 	entsize = fs->lfs_is64 ? sizeof(IFILE64) :
    327 		(lfs_sb_getversion(fs) > 1 ? sizeof(IFILE32) : sizeof(IFILE_V1));
    328 	ifileent_blkno =
    329 	    (inumber / lfs_sb_getifpb(fs)) + lfs_sb_getcleansz(fs) + lfs_sb_getsegtabsz(fs);
    330 	fp->f_seekp = (off_t)ifileent_blkno * lfs_sb_getbsize(fs) +
    331 	    (inumber % lfs_sb_getifpb(fs)) * entsize;
    332 	rc = buf_read_file(f, &ent_in_buf, &buf_after_ent);
    333 	if (rc)
    334 		return rc;
    335 	/* make sure something's not badly wrong, but don't panic. */
    336 	if (buf_after_ent < entsize)
    337 		return EINVAL;
    338 
    339 	*isp = FSBTODB(fs, lfs_if_getdaddr(fs, (IFILE *)ent_in_buf));
    340 	if (*isp == LFS_UNUSED_DADDR)	/* again, something badly wrong */
    341 		return EINVAL;
    342 	return 0;
    343 }
    344 #endif
    345 
    346 /*
    347  * Read a new inode into a file structure.
    348  */
    349 static int
    350 read_inode(ino32_t inumber, struct open_file *f)
    351 {
    352 	struct file *fp = (struct file *)f->f_fsdata;
    353 	FS *fs = fp->f_fs;
    354 	char *buf;
    355 	size_t rsize;
    356 	int rc;
    357 	daddr_t inode_sector = 0; /* XXX: gcc */
    358 #ifdef LIBSA_LFS
    359 	struct ufs_dinode *dip;
    360 	int cnt;
    361 #endif
    362 
    363 #ifdef LIBSA_LFS
    364 	if (inumber == LFS_IFILE_INUM)
    365 		inode_sector = FSBTODB(fs, lfs_sb_getidaddr(fs));
    366 	else if ((rc = find_inode_sector(inumber, f, &inode_sector)) != 0)
    367 		return rc;
    368 #else
    369 	inode_sector = FSBTODB(fs, ino_to_fsba(fs, inumber));
    370 #endif
    371 
    372 	/*
    373 	 * Read inode and save it.
    374 	 */
    375 	buf = fp->f_buf;
    376 	twiddle();
    377 	rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
    378 	    inode_sector, fs->fs_bsize, buf, &rsize);
    379 	if (rc)
    380 		return rc;
    381 	if (rsize != (size_t)fs->fs_bsize)
    382 		return EIO;
    383 
    384 #ifdef LIBSA_LFS
    385 	cnt = INOPBx(fs);
    386 	dip = (struct ufs_dinode *)buf + (cnt - 1);
    387 	for (; dip->di_inumber != inumber; --dip) {
    388 		/* kernel code panics, but boot blocks which panic are Bad. */
    389 		if (--cnt == 0)
    390 			return EINVAL;
    391 	}
    392 	fp->f_di = *dip;
    393 #else
    394 	fp->f_di = ((struct ufs_dinode *)buf)[ino_to_fsbo(fs, inumber)];
    395 #ifdef LIBSA_FFS_EI
    396 	if (ffs_swapped(fp))
    397 		ufs_dinode_swap(&fp->f_di, &fp->f_di);
    398 #endif
    399 #endif
    400 
    401 	/*
    402 	 * Clear out the old buffers
    403 	 */
    404 	fp->f_ind_cache_block = ~0;
    405 	fp->f_buf_blkno = -1;
    406 	return rc;
    407 }
    408 
    409 /*
    410  * Given an offset in a file, find the disk block number that
    411  * contains that block.
    412  */
    413 static int
    414 block_map(struct open_file *f, indp_t file_block, indp_t *disk_block_p)
    415 {
    416 	struct file *fp = (struct file *)f->f_fsdata;
    417 	FS *fs = fp->f_fs;
    418 	uint level;
    419 	indp_t ind_cache;
    420 	indp_t ind_block_num;
    421 	size_t rsize;
    422 	int rc;
    423 	indp_t *buf = (void *)fp->f_buf;
    424 
    425 	/*
    426 	 * Index structure of an inode:
    427 	 *
    428 	 * di_db[0..UFS_NDADDR-1]	hold block numbers for blocks
    429 	 *			0..UFS_NDADDR-1
    430 	 *
    431 	 * di_ib[0]		index block 0 is the single indirect block
    432 	 *			holds block numbers for blocks
    433 	 *			UFS_NDADDR .. UFS_NDADDR + UFS_NINDIR(fs)-1
    434 	 *
    435 	 * di_ib[1]		index block 1 is the double indirect block
    436 	 *			holds block numbers for INDEX blocks for blocks
    437 	 *			UFS_NDADDR + UFS_NINDIR(fs) ..
    438 	 *			UFS_NDADDR + UFS_NINDIR(fs) + UFS_NINDIR(fs)**2 - 1
    439 	 *
    440 	 * di_ib[2]		index block 2 is the triple indirect block
    441 	 *			holds block numbers for double-indirect
    442 	 *			blocks for blocks
    443 	 *			UFS_NDADDR + UFS_NINDIR(fs) + UFS_NINDIR(fs)**2 ..
    444 	 *			UFS_NDADDR + UFS_NINDIR(fs) + UFS_NINDIR(fs)**2
    445 	 *				+ UFS_NINDIR(fs)**3 - 1
    446 	 */
    447 
    448 	if (file_block < UFS_NDADDR) {
    449 		/* Direct block. */
    450 		*disk_block_p = fp->f_di.di_db[file_block];
    451 		return 0;
    452 	}
    453 
    454 	file_block -= UFS_NDADDR;
    455 
    456 	ind_cache = file_block >> LN2_IND_CACHE_SZ;
    457 	if (ind_cache == fp->f_ind_cache_block) {
    458 		*disk_block_p = fp->f_ind_cache[file_block & IND_CACHE_MASK];
    459 		return 0;
    460 	}
    461 
    462 	for (level = 0;;) {
    463 		level += fp->f_nishift;
    464 		if (file_block < (indp_t)1 << level)
    465 			break;
    466 		if (level > UFS_NIADDR * fp->f_nishift)
    467 			/* Block number too high */
    468 			return EFBIG;
    469 		file_block -= (indp_t)1 << level;
    470 	}
    471 
    472 	ind_block_num = fp->f_di.di_ib[level / fp->f_nishift - 1];
    473 
    474 	for (;;) {
    475 		level -= fp->f_nishift;
    476 		if (ind_block_num == 0) {
    477 			*disk_block_p = 0;	/* missing */
    478 			return 0;
    479 		}
    480 
    481 		twiddle();
    482 		/*
    483 		 * If we were feeling brave, we could work out the number
    484 		 * of the disk sector and read a single disk sector instead
    485 		 * of a filesystem block.
    486 		 * However we don't do this very often anyway...
    487 		 */
    488 		rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
    489 			FSBTODB(fp->f_fs, ind_block_num), fs->fs_bsize,
    490 			buf, &rsize);
    491 		if (rc)
    492 			return rc;
    493 		if (rsize != (size_t)fs->fs_bsize)
    494 			return EIO;
    495 #ifdef LIBSA_FFS_EI
    496 		if (ffs_swapped(fp))
    497 			ind_block_num = ufs_indp_swap(buf[file_block >> level]);
    498 		else
    499 #endif
    500 			ind_block_num = buf[file_block >> level];
    501 		if (level == 0)
    502 			break;
    503 		file_block &= (1 << level) - 1;
    504 	}
    505 
    506 	/* Save the part of the block that contains this sector */
    507 #if defined(LIBSA_FFS_EI)
    508 	if (ffs_swapped(fp)) {
    509 		size_t i;
    510 
    511 		for (i = 0; i < IND_CACHE_SZ; i++) {
    512 			fp->f_ind_cache[i] = ufs_indp_swap(
    513 			    buf[(file_block & ~IND_CACHE_MASK) + i]);
    514 		}
    515 	} else
    516 #endif
    517 		memcpy(fp->f_ind_cache, &buf[file_block & ~IND_CACHE_MASK],
    518 		    IND_CACHE_SZ * sizeof fp->f_ind_cache[0]);
    519 	fp->f_ind_cache_block = ind_cache;
    520 
    521 	*disk_block_p = ind_block_num;
    522 
    523 	return 0;
    524 }
    525 
    526 /*
    527  * Read a portion of a file into an internal buffer.
    528  * Return the location in the buffer and the amount in the buffer.
    529  */
    530 static int
    531 buf_read_file(struct open_file *f, char **buf_p, size_t *size_p)
    532 {
    533 	struct file *fp = (struct file *)f->f_fsdata;
    534 	FS *fs = fp->f_fs;
    535 	long off;
    536 	indp_t file_block;
    537 	size_t block_size;
    538 	int rc;
    539 
    540 	off = ufs_blkoff(fs, fp->f_seekp);
    541 	file_block = ufs_lblkno(fs, fp->f_seekp);
    542 #ifdef LIBSA_LFS
    543 	block_size = (size_t)dblksize(fs, &fp->f_di, (uint64_t)file_block);
    544 #else
    545 	block_size = (size_t)ffs_sblksize(fs, (int64_t)fp->f_di.di_size, file_block);
    546 #endif
    547 
    548 	if (file_block != fp->f_buf_blkno) {
    549 		indp_t disk_block = 0; /* XXX: gcc */
    550 		rc = block_map(f, file_block, &disk_block);
    551 		if (rc)
    552 			return rc;
    553 
    554 		if (disk_block == 0) {
    555 			memset(fp->f_buf, 0, block_size);
    556 			fp->f_buf_size = block_size;
    557 		} else {
    558 			twiddle();
    559 			rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
    560 				FSBTODB(fs, disk_block),
    561 				block_size, fp->f_buf, &fp->f_buf_size);
    562 			if (rc)
    563 				return rc;
    564 		}
    565 
    566 		fp->f_buf_blkno = file_block;
    567 	}
    568 
    569 	/*
    570 	 * Return address of byte in buffer corresponding to
    571 	 * offset, and size of remainder of buffer after that
    572 	 * byte.
    573 	 */
    574 	*buf_p = fp->f_buf + off;
    575 	*size_p = block_size - off;
    576 
    577 	/*
    578 	 * But truncate buffer at end of file.
    579 	 */
    580 	if (*size_p > fp->f_di.di_size - fp->f_seekp)
    581 		*size_p = fp->f_di.di_size - fp->f_seekp;
    582 
    583 	return 0;
    584 }
    585 
    586 /*
    587  * Search a directory for a name and return its
    588  * inode number.
    589  */
    590 static int
    591 search_directory(const char *name, int length, struct open_file *f,
    592 	ino32_t *inumber_p)
    593 {
    594 	struct file *fp = (struct file *)f->f_fsdata;
    595 	struct direct *dp;
    596 	struct direct *edp;
    597 	char *buf;
    598 	size_t buf_size;
    599 	int namlen;
    600 	int rc;
    601 
    602 	fp->f_seekp = 0;
    603 	while (fp->f_seekp < (off_t)fp->f_di.di_size) {
    604 		rc = buf_read_file(f, &buf, &buf_size);
    605 		if (rc)
    606 			return rc;
    607 
    608 		dp = (struct direct *)buf;
    609 		edp = (struct direct *)(buf + buf_size);
    610 		for (; dp < edp;
    611 		     dp = (void *)((char *)dp + ffs_get_reclen(fp, dp))) {
    612 			if (ffs_get_reclen(fp, dp) <= 0)
    613 				break;
    614 			if (ffs_get_ino(fp, dp) == (ino32_t)0)
    615 				continue;
    616 #if BYTE_ORDER == LITTLE_ENDIAN
    617 			if (fp->f_fs->fs_maxsymlinklen <= 0)
    618 				namlen = dp->d_type;
    619 			else
    620 #endif
    621 				namlen = dp->d_namlen;
    622 			if (namlen == length &&
    623 			    !memcmp(name, dp->d_name, length)) {
    624 				/* found entry */
    625 				*inumber_p = ffs_get_ino(fp, dp);
    626 				return 0;
    627 			}
    628 		}
    629 		fp->f_seekp += buf_size;
    630 	}
    631 	return ENOENT;
    632 }
    633 
    634 static __inline__ int
    635 ffs_find_superblock(struct open_file *f, FS *fs)
    636 {
    637 	struct file *fp = (struct file *)f->f_fsdata;
    638 	int rc;
    639 	size_t buf_size;
    640 #ifdef LIBSA_FFSv2
    641 	static daddr_t sblock_try[] = SBLOCKSEARCH;
    642 	int i;
    643 #endif
    644 
    645 #ifdef LIBSA_FFSv2
    646 	for (i = 0; sblock_try[i] != -1; i++) {
    647 		rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
    648 		    sblock_try[i] / GETSECSIZE(f), SBLOCKSIZE, fs, &buf_size);
    649 		if (rc)
    650 			return rc;
    651 		if (buf_size != SBLOCKSIZE)
    652 			return EINVAL;
    653 		ffs_fix_magic_swapped(fp, fs);
    654 		if (fs->fs_sblockloc != sblock_try[i])
    655 			/* an alternate superblock - try again */
    656 			continue;
    657 		if (ffs_is_magic(fs))
    658 			return 0;
    659 	}
    660 	return EINVAL;
    661 #else /* LIBSA_FFSv2 */
    662 	rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
    663 		SBLOCKOFFSET / GETSECSIZE(f), SBLOCKSIZE, fs, &buf_size);
    664 	if (rc)
    665 		return rc;
    666 	if (buf_size != SBLOCKSIZE)
    667 		return EINVAL;
    668 	ffs_fix_magic_swapped(fp, fs);
    669 
    670 #ifdef LIBSA_LFS
    671 	if (fs->lfs_version != REQUIRED_LFS_VERSION)
    672 		return EINVAL;
    673 #endif
    674 	if (!ffs_is_magic(fs))
    675 		return EINVAL;
    676 
    677 	return 0;
    678 #endif /* !LIBSA_FFSv2 */
    679 }
    680 
    681 /*
    682  * Open a file.
    683  */
    684 __compactcall int
    685 ufs_open(const char *path, struct open_file *f)
    686 {
    687 #ifndef LIBSA_FS_SINGLECOMPONENT
    688 	const char *cp, *ncp;
    689 	int c;
    690 #endif
    691 	ino32_t inumber;
    692 	struct file *fp;
    693 	FS *fs;
    694 	int rc;
    695 #ifndef LIBSA_NO_FS_SYMLINK
    696 	ino32_t parent_inumber;
    697 	int nlinks = 0;
    698 	char namebuf[MAXPATHLEN+1];
    699 	char *buf;
    700 #endif
    701 
    702 	/* allocate file system specific data structure */
    703 	fp = alloc(sizeof(struct file));
    704 	memset(fp, 0, sizeof(struct file));
    705 	f->f_fsdata = (void *)fp;
    706 
    707 	/* allocate space and read super block */
    708 	fs = alloc(SBLOCKSIZE);
    709 	fp->f_fs = fs;
    710 	twiddle();
    711 
    712 	rc = ffs_find_superblock(f, fs);
    713 	if (rc)
    714 		goto out;
    715 
    716 #if defined(LIBSA_LFS) && REQUIRED_LFS_VERSION == 2
    717 	/*
    718 	 * XXX	We should check the second superblock and use the eldest
    719 	 *	of the two.  See comments near the top of lfs_mountfs()
    720 	 *	in sys/ufs/lfs/lfs_vfsops.c.
    721 	 *      This may need a LIBSA_LFS_SMALL check as well.
    722 	 */
    723 #endif
    724 #if defined(LIBSA_LFS)
    725 	fs->lfs_is64 = 0;
    726 	fs->lfs_dobyteswap = 0;
    727 	fs->lfs_hasolddirfmt = (fs->fs_maxsymlinklen <= 0);
    728 #endif
    729 #ifdef LIBSA_FFSv1
    730 	ffs_oldfscompat(fs);
    731 #endif
    732 
    733 	if (fs->fs_bsize > MAXBSIZE ||
    734 	    (size_t)fs->fs_bsize < sizeof(FS)) {
    735 		rc = EINVAL;
    736 		goto out;
    737 	}
    738 
    739 	/*
    740 	 * Calculate indirect block levels.
    741 	 */
    742 	{
    743 		indp_t mult;
    744 		int ln2;
    745 
    746 		/*
    747 		 * We note that the number of indirect blocks is always
    748 		 * a power of 2.  This lets us use shifts and masks instead
    749 		 * of divide and remainder and avoids pulling in the
    750 		 * 64bit division routine into the boot code.
    751 		 */
    752 		mult = UFS_NINDIR(fs);
    753 #ifdef DEBUG
    754 		if (mult & (mult - 1)) {
    755 			/* Hummm was't a power of 2 */
    756 			rc = EINVAL;
    757 			goto out;
    758 		}
    759 #endif
    760 		for (ln2 = 0; mult != 1; ln2++)
    761 			mult >>= 1;
    762 
    763 		fp->f_nishift = ln2;
    764 	}
    765 
    766 	/* alloc a block sized buffer used for all fs transfers */
    767 	fp->f_buf = alloc(fs->fs_bsize);
    768 	inumber = UFS_ROOTINO;
    769 	if ((rc = read_inode(inumber, f)) != 0)
    770 		goto out;
    771 
    772 #ifndef LIBSA_FS_SINGLECOMPONENT
    773 	cp = path;
    774 	while (*cp) {
    775 
    776 		/*
    777 		 * Remove extra separators
    778 		 */
    779 		while (*cp == '/')
    780 			cp++;
    781 		if (*cp == '\0')
    782 			break;
    783 
    784 		/*
    785 		 * Check that current node is a directory.
    786 		 */
    787 		if ((fp->f_di.di_mode & IFMT) != IFDIR) {
    788 			rc = ENOTDIR;
    789 			goto out;
    790 		}
    791 
    792 		/*
    793 		 * Get next component of path name.
    794 		 */
    795 		ncp = cp;
    796 		while ((c = *cp) != '\0' && c != '/')
    797 			cp++;
    798 
    799 		/*
    800 		 * Look up component in current directory.
    801 		 * Save directory inumber in case we find a
    802 		 * symbolic link.
    803 		 */
    804 #ifndef LIBSA_NO_FS_SYMLINK
    805 		parent_inumber = inumber;
    806 #endif
    807 		rc = search_directory(ncp, cp - ncp, f, &inumber);
    808 		if (rc)
    809 			goto out;
    810 
    811 		/*
    812 		 * Open next component.
    813 		 */
    814 		if ((rc = read_inode(inumber, f)) != 0)
    815 			goto out;
    816 
    817 #ifndef LIBSA_NO_FS_SYMLINK
    818 		/*
    819 		 * Check for symbolic link.
    820 		 */
    821 		if ((fp->f_di.di_mode & IFMT) == IFLNK) {
    822 			int link_len = fp->f_di.di_size;
    823 			int len;
    824 
    825 			len = strlen(cp);
    826 
    827 			if (link_len + len > MAXPATHLEN ||
    828 			    ++nlinks > MAXSYMLINKS) {
    829 				rc = ENOENT;
    830 				goto out;
    831 			}
    832 
    833 			memmove(&namebuf[link_len], cp, len + 1);
    834 
    835 			if (link_len < fs->fs_maxsymlinklen) {
    836 				memcpy(namebuf, fp->f_di.di_db, link_len);
    837 			} else {
    838 				/*
    839 				 * Read file for symbolic link
    840 				 */
    841 				size_t buf_size;
    842 				indp_t	disk_block;
    843 
    844 				buf = fp->f_buf;
    845 				rc = block_map(f, (indp_t)0, &disk_block);
    846 				if (rc)
    847 					goto out;
    848 
    849 				twiddle();
    850 				rc = DEV_STRATEGY(f->f_dev)(f->f_devdata,
    851 					F_READ, FSBTODB(fs, disk_block),
    852 					fs->fs_bsize, buf, &buf_size);
    853 				if (rc)
    854 					goto out;
    855 
    856 				memcpy(namebuf, buf, link_len);
    857 			}
    858 
    859 			/*
    860 			 * If relative pathname, restart at parent directory.
    861 			 * If absolute pathname, restart at root.
    862 			 */
    863 			cp = namebuf;
    864 			if (*cp != '/')
    865 				inumber = parent_inumber;
    866 			else
    867 				inumber = (ino32_t)UFS_ROOTINO;
    868 
    869 			if ((rc = read_inode(inumber, f)) != 0)
    870 				goto out;
    871 		}
    872 #endif	/* !LIBSA_NO_FS_SYMLINK */
    873 	}
    874 
    875 	/*
    876 	 * Found terminal component.
    877 	 */
    878 	rc = 0;
    879 
    880 #else /* !LIBSA_FS_SINGLECOMPONENT */
    881 
    882 	/* look up component in the current (root) directory */
    883 	rc = search_directory(path, strlen(path), f, &inumber);
    884 	if (rc)
    885 		goto out;
    886 
    887 	/* open it */
    888 	rc = read_inode(inumber, f);
    889 
    890 #endif /* !LIBSA_FS_SINGLECOMPONENT */
    891 
    892 	fp->f_seekp = 0;		/* reset seek pointer */
    893 
    894 out:
    895 	if (rc)
    896 		ufs_close(f);
    897 	else
    898 #ifdef FSMOD
    899 		fsmod = FSMOD;
    900 #else
    901 		fsmod = NULL;
    902 #endif
    903 	return rc;
    904 }
    905 
    906 __compactcall int
    907 ufs_close(struct open_file *f)
    908 {
    909 	struct file *fp = (struct file *)f->f_fsdata;
    910 
    911 	f->f_fsdata = NULL;
    912 	if (fp == NULL)
    913 		return 0;
    914 
    915 	if (fp->f_buf)
    916 		dealloc(fp->f_buf, fp->f_fs->fs_bsize);
    917 	dealloc(fp->f_fs, SBLOCKSIZE);
    918 	dealloc(fp, sizeof(struct file));
    919 	return 0;
    920 }
    921 
    922 /*
    923  * Copy a portion of a file into kernel memory.
    924  * Cross block boundaries when necessary.
    925  */
    926 __compactcall int
    927 ufs_read(struct open_file *f, void *start, size_t size, size_t *resid)
    928 {
    929 	struct file *fp = (struct file *)f->f_fsdata;
    930 	size_t csize;
    931 	char *buf;
    932 	size_t buf_size;
    933 	int rc = 0;
    934 	char *addr = start;
    935 
    936 	while (size != 0) {
    937 		if (fp->f_seekp >= (off_t)fp->f_di.di_size)
    938 			break;
    939 
    940 		rc = buf_read_file(f, &buf, &buf_size);
    941 		if (rc)
    942 			break;
    943 
    944 		csize = size;
    945 		if (csize > buf_size)
    946 			csize = buf_size;
    947 
    948 		memcpy(addr, buf, csize);
    949 
    950 		fp->f_seekp += csize;
    951 		addr += csize;
    952 		size -= csize;
    953 	}
    954 	if (resid)
    955 		*resid = size;
    956 	return rc;
    957 }
    958 
    959 /*
    960  * Not implemented.
    961  */
    962 #ifndef LIBSA_NO_FS_WRITE
    963 __compactcall int
    964 ufs_write(struct open_file *f, void *start, size_t size, size_t *resid)
    965 {
    966 
    967 	return EROFS;
    968 }
    969 #endif /* !LIBSA_NO_FS_WRITE */
    970 
    971 #ifndef LIBSA_NO_FS_SEEK
    972 __compactcall off_t
    973 ufs_seek(struct open_file *f, off_t offset, int where)
    974 {
    975 	struct file *fp = (struct file *)f->f_fsdata;
    976 
    977 	switch (where) {
    978 	case SEEK_SET:
    979 		fp->f_seekp = offset;
    980 		break;
    981 	case SEEK_CUR:
    982 		fp->f_seekp += offset;
    983 		break;
    984 	case SEEK_END:
    985 		fp->f_seekp = fp->f_di.di_size - offset;
    986 		break;
    987 	default:
    988 		return -1;
    989 	}
    990 	return fp->f_seekp;
    991 }
    992 #endif /* !LIBSA_NO_FS_SEEK */
    993 
    994 __compactcall int
    995 ufs_stat(struct open_file *f, struct stat *sb)
    996 {
    997 	struct file *fp = (struct file *)f->f_fsdata;
    998 
    999 	/* only important stuff */
   1000 	memset(sb, 0, sizeof *sb);
   1001 	sb->st_mode = fp->f_di.di_mode;
   1002 	sb->st_uid = fp->f_di.di_uid;
   1003 	sb->st_gid = fp->f_di.di_gid;
   1004 	sb->st_size = fp->f_di.di_size;
   1005 	return 0;
   1006 }
   1007 
   1008 #if defined(LIBSA_ENABLE_LS_OP)
   1009 
   1010 #include "ls.h"
   1011 
   1012 static const char    *const typestr[] = {
   1013 	"unknown",
   1014 	"FIFO",
   1015 	"CHR",
   1016 	0,
   1017 	"DIR",
   1018 	0,
   1019 	"BLK",
   1020 	0,
   1021 	"REG",
   1022 	0,
   1023 	"LNK",
   1024 	0,
   1025 	"SOCK",
   1026 	0,
   1027 	"WHT"
   1028 };
   1029 
   1030 __compactcall void
   1031 ufs_ls(struct open_file *f, const char *pattern)
   1032 {
   1033 	struct file *fp = (struct file *)f->f_fsdata;
   1034 	char *buf;
   1035 	size_t buf_size;
   1036 	lsentry_t *names = NULL;
   1037 
   1038 	fp->f_seekp = 0;
   1039 	while (fp->f_seekp < (off_t)fp->f_di.di_size) {
   1040 		struct direct  *dp, *edp;
   1041 		int rc = buf_read_file(f, &buf, &buf_size);
   1042 		if (rc)
   1043 			goto out;
   1044 		/* some firmware might use block size larger than DEV_BSIZE */
   1045 		if (buf_size < UFS_DIRBLKSIZ)
   1046 			goto out;
   1047 
   1048 		dp = (struct direct *)buf;
   1049 		edp = (struct direct *)(buf + buf_size);
   1050 
   1051 		for (; dp < edp;
   1052 		     dp = (void *)((char *)dp + ffs_get_reclen(fp, dp))) {
   1053 			const char *t;
   1054 			if (ffs_get_ino(fp, dp) == 0)
   1055 				continue;
   1056 
   1057 			if (dp->d_type >= NELEM(typestr) ||
   1058 			    !(t = typestr[dp->d_type])) {
   1059 				/*
   1060 				 * This does not handle "old"
   1061 				 * filesystems properly. On little
   1062 				 * endian machines, we get a bogus
   1063 				 * type name if the namlen matches a
   1064 				 * valid type identifier. We could
   1065 				 * check if we read namlen "0" and
   1066 				 * handle this case specially, if
   1067 				 * there were a pressing need...
   1068 				 */
   1069 				printf("bad dir entry\n");
   1070 				goto out;
   1071 			}
   1072 			lsadd(&names, pattern, dp->d_name, strlen(dp->d_name),
   1073 			    ffs_get_ino(fp, dp), t);
   1074 		}
   1075 		fp->f_seekp += buf_size;
   1076 	}
   1077 	lsprint(names);
   1078 out:	lsfree(names);
   1079 }
   1080 #endif /* LIBSA_ENABLE_LS_OP */
   1081 
   1082 #ifdef LIBSA_FFSv1
   1083 /*
   1084  * Sanity checks for old file systems.
   1085  *
   1086  * XXX - goes away some day.
   1087  * Stripped of stuff libsa doesn't need.....
   1088  */
   1089 static void
   1090 ffs_oldfscompat(FS *fs)
   1091 {
   1092 
   1093 #ifdef COMPAT_UFS
   1094 	/*
   1095 	 * Newer Solaris versions have a slightly incompatible
   1096 	 * superblock - so always calculate this values on the fly, which
   1097 	 * is good enough for libsa purposes
   1098 	 */
   1099 	if (fs->fs_magic == FS_UFS1_MAGIC
   1100 #ifndef COMPAT_SOLARIS_UFS
   1101 	    && fs->fs_old_inodefmt < FS_44INODEFMT
   1102 #endif
   1103 	    ) {
   1104 		fs->fs_qbmask = ~fs->fs_bmask;
   1105 		fs->fs_qfmask = ~fs->fs_fmask;
   1106 	}
   1107 #endif
   1108 }
   1109 #endif
   1110