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