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