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