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