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