Home | History | Annotate | Line # | Download | only in libsa
ufs.c revision 1.66
      1 /*	$NetBSD: ufs.c,v 1.66 2015/07/24 06:53:24 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 typedef struct dlfs FS;
    107 #define fs_magic	dlfs_magic
    108 #define fs_maxsymlinklen dlfs_maxsymlinklen
    109 
    110 /* XXX these will go away in the near future */
    111 #undef lfs_bmask
    112 #define lfs_bmask dlfs_bmask
    113 #undef lfs_ifile
    114 #define lfs_ifile dlfs_ifile
    115 #undef lfs_ifpb
    116 #define lfs_ifpb dlfs_ifpb
    117 #undef lfs_cleansz
    118 #define lfs_cleansz dlfs_cleansz
    119 #undef lfs_segtabsz
    120 #define lfs_segtabsz dlfs_segtabsz
    121 #undef lfs_idaddr
    122 #define lfs_idaddr dlfs_idaddr
    123 #undef lfs_inopb
    124 #define lfs_inopb dlfs_inopb
    125 #undef lfs_bshift
    126 #define lfs_bshift dlfs_bshift
    127 #undef lfs_bsize
    128 #define lfs_bsize dlfs_bsize
    129 #undef lfs_ffmask
    130 #define lfs_ffmask dlfs_ffmask
    131 #undef lfs_fsbtodb
    132 #define lfs_fsbtodb dlfs_fsbtodb
    133 
    134 #define FS_MAGIC	LFS_MAGIC
    135 #define SBLOCKSIZE	LFS_SBPAD
    136 #define SBLOCKOFFSET	LFS_LABELPAD
    137 #else
    138 /* NB ufs2 doesn't use the common superblock code... */
    139 typedef struct fs FS;
    140 #define FS_MAGIC	FS_UFS1_MAGIC
    141 #define SBLOCKOFFSET	SBLOCK_UFS1
    142 #endif
    143 
    144 #if defined(LIBSA_NO_TWIDDLE)
    145 #define twiddle()
    146 #endif
    147 
    148 #undef cgstart
    149 #if defined(LIBSA_FFSv2)
    150 #define cgstart(fc, c) cgstart_ufs2((fs), (c))
    151 #else
    152 #define cgstart(fc, c) cgstart_ufs1((fs), (c))
    153 #endif
    154 
    155 #ifndef ufs_dinode
    156 #define ufs_dinode	ufs1_dinode
    157 #endif
    158 #ifndef indp_t
    159 #define indp_t		int32_t
    160 #endif
    161 typedef uint32_t	ino32_t;
    162 
    163 #ifndef FSBTODB
    164 #define FSBTODB(fs, indp) FFS_FSBTODB(fs, indp)
    165 #endif
    166 #ifndef UFS_NINDIR
    167 #define UFS_NINDIR FFS_NINDIR
    168 #endif
    169 #ifndef ufs_blkoff
    170 #define ufs_blkoff ffs_blkoff
    171 #endif
    172 #ifndef ufs_lblkno
    173 #define ufs_lblkno ffs_lblkno
    174 #endif
    175 
    176 /*
    177  * To avoid having a lot of filesystem-block sized buffers lurking (which
    178  * could be 32k) we only keep a few entries of the indirect block map.
    179  * With 8k blocks, 2^8 blocks is ~500k so we reread the indirect block
    180  * ~13 times pulling in a 6M kernel.
    181  * The cache size must be smaller than the smallest filesystem block,
    182  * so LN2_IND_CACHE_SZ <= 9 (UFS2 and 4k blocks).
    183  */
    184 #define LN2_IND_CACHE_SZ	6
    185 #define IND_CACHE_SZ		(1 << LN2_IND_CACHE_SZ)
    186 #define IND_CACHE_MASK		(IND_CACHE_SZ - 1)
    187 
    188 /*
    189  * In-core open file.
    190  */
    191 struct file {
    192 	off_t		f_seekp;	/* seek pointer */
    193 	FS		*f_fs;		/* pointer to super-block */
    194 	struct ufs_dinode	f_di;		/* copy of on-disk inode */
    195 	uint		f_nishift;	/* for blocks in indirect block */
    196 	indp_t		f_ind_cache_block;
    197 	indp_t		f_ind_cache[IND_CACHE_SZ];
    198 
    199 	char		*f_buf;		/* buffer for data block */
    200 	size_t		f_buf_size;	/* size of data block */
    201 	daddr_t		f_buf_blkno;	/* block number of data block */
    202 };
    203 
    204 static int read_inode(ino32_t, struct open_file *);
    205 static int block_map(struct open_file *, indp_t, indp_t *);
    206 static int buf_read_file(struct open_file *, char **, size_t *);
    207 static int search_directory(const char *, int, struct open_file *, ino32_t *);
    208 #ifdef LIBSA_FFSv1
    209 static void ffs_oldfscompat(FS *);
    210 #endif
    211 #ifdef LIBSA_FFSv2
    212 static int ffs_find_superblock(struct open_file *, FS *);
    213 #endif
    214 
    215 
    216 #ifdef LIBSA_LFS
    217 /*
    218  * Find an inode's block.  Look it up in the ifile.  Whee!
    219  */
    220 static int
    221 find_inode_sector(ino32_t inumber, struct open_file *f, daddr_t *isp)
    222 {
    223 	struct file *fp = (struct file *)f->f_fsdata;
    224 	FS *fs = fp->f_fs;
    225 	daddr_t ifileent_blkno;
    226 	char *ent_in_buf;
    227 	size_t buf_after_ent;
    228 	int rc;
    229 
    230 	rc = read_inode(fs->lfs_ifile, f);
    231 	if (rc)
    232 		return rc;
    233 
    234 	ifileent_blkno =
    235 	    (inumber / fs->lfs_ifpb) + fs->lfs_cleansz + fs->lfs_segtabsz;
    236 	fp->f_seekp = (off_t)ifileent_blkno * fs->fs_bsize +
    237 	    (inumber % fs->lfs_ifpb) * sizeof (IFILE_Vx);
    238 	rc = buf_read_file(f, &ent_in_buf, &buf_after_ent);
    239 	if (rc)
    240 		return rc;
    241 	/* make sure something's not badly wrong, but don't panic. */
    242 	if (buf_after_ent < sizeof (IFILE_Vx))
    243 		return EINVAL;
    244 
    245 	*isp = FSBTODB(fs, ((IFILE_Vx *)ent_in_buf)->if_daddr);
    246 	if (*isp == LFS_UNUSED_DADDR)	/* again, something badly wrong */
    247 		return EINVAL;
    248 	return 0;
    249 }
    250 #endif
    251 
    252 /*
    253  * Read a new inode into a file structure.
    254  */
    255 static int
    256 read_inode(ino32_t inumber, struct open_file *f)
    257 {
    258 	struct file *fp = (struct file *)f->f_fsdata;
    259 	FS *fs = fp->f_fs;
    260 	char *buf;
    261 	size_t rsize;
    262 	int rc;
    263 	daddr_t inode_sector = 0; /* XXX: gcc */
    264 #ifdef LIBSA_LFS
    265 	struct ufs_dinode *dip;
    266 	int cnt;
    267 #endif
    268 
    269 #ifdef LIBSA_LFS
    270 	if (inumber == fs->lfs_ifile)
    271 		inode_sector = FSBTODB(fs, fs->lfs_idaddr);
    272 	else if ((rc = find_inode_sector(inumber, f, &inode_sector)) != 0)
    273 		return rc;
    274 #else
    275 	inode_sector = FSBTODB(fs, ino_to_fsba(fs, inumber));
    276 #endif
    277 
    278 	/*
    279 	 * Read inode and save it.
    280 	 */
    281 	buf = fp->f_buf;
    282 	twiddle();
    283 	rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
    284 	    inode_sector, fs->fs_bsize, buf, &rsize);
    285 	if (rc)
    286 		return rc;
    287 	if (rsize != fs->fs_bsize)
    288 		return EIO;
    289 
    290 #ifdef LIBSA_LFS
    291 	cnt = INOPBx(fs);
    292 	dip = (struct ufs_dinode *)buf + (cnt - 1);
    293 	for (; dip->di_inumber != inumber; --dip) {
    294 		/* kernel code panics, but boot blocks which panic are Bad. */
    295 		if (--cnt == 0)
    296 			return EINVAL;
    297 	}
    298 	fp->f_di = *dip;
    299 #else
    300 	fp->f_di = ((struct ufs_dinode *)buf)[ino_to_fsbo(fs, inumber)];
    301 #endif
    302 
    303 	/*
    304 	 * Clear out the old buffers
    305 	 */
    306 	fp->f_ind_cache_block = ~0;
    307 	fp->f_buf_blkno = -1;
    308 	return rc;
    309 }
    310 
    311 /*
    312  * Given an offset in a file, find the disk block number that
    313  * contains that block.
    314  */
    315 static int
    316 block_map(struct open_file *f, indp_t file_block, indp_t *disk_block_p)
    317 {
    318 	struct file *fp = (struct file *)f->f_fsdata;
    319 	FS *fs = fp->f_fs;
    320 	uint level;
    321 	indp_t ind_cache;
    322 	indp_t ind_block_num;
    323 	size_t rsize;
    324 	int rc;
    325 	indp_t *buf = (void *)fp->f_buf;
    326 
    327 	/*
    328 	 * Index structure of an inode:
    329 	 *
    330 	 * di_db[0..UFS_NDADDR-1]	hold block numbers for blocks
    331 	 *			0..UFS_NDADDR-1
    332 	 *
    333 	 * di_ib[0]		index block 0 is the single indirect block
    334 	 *			holds block numbers for blocks
    335 	 *			UFS_NDADDR .. UFS_NDADDR + UFS_NINDIR(fs)-1
    336 	 *
    337 	 * di_ib[1]		index block 1 is the double indirect block
    338 	 *			holds block numbers for INDEX blocks for blocks
    339 	 *			UFS_NDADDR + UFS_NINDIR(fs) ..
    340 	 *			UFS_NDADDR + UFS_NINDIR(fs) + UFS_NINDIR(fs)**2 - 1
    341 	 *
    342 	 * di_ib[2]		index block 2 is the triple indirect block
    343 	 *			holds block numbers for double-indirect
    344 	 *			blocks for blocks
    345 	 *			UFS_NDADDR + UFS_NINDIR(fs) + UFS_NINDIR(fs)**2 ..
    346 	 *			UFS_NDADDR + UFS_NINDIR(fs) + UFS_NINDIR(fs)**2
    347 	 *				+ UFS_NINDIR(fs)**3 - 1
    348 	 */
    349 
    350 	if (file_block < UFS_NDADDR) {
    351 		/* Direct block. */
    352 		*disk_block_p = fp->f_di.di_db[file_block];
    353 		return 0;
    354 	}
    355 
    356 	file_block -= UFS_NDADDR;
    357 
    358 	ind_cache = file_block >> LN2_IND_CACHE_SZ;
    359 	if (ind_cache == fp->f_ind_cache_block) {
    360 		*disk_block_p = fp->f_ind_cache[file_block & IND_CACHE_MASK];
    361 		return 0;
    362 	}
    363 
    364 	for (level = 0;;) {
    365 		level += fp->f_nishift;
    366 		if (file_block < (indp_t)1 << level)
    367 			break;
    368 		if (level > UFS_NIADDR * fp->f_nishift)
    369 			/* Block number too high */
    370 			return EFBIG;
    371 		file_block -= (indp_t)1 << level;
    372 	}
    373 
    374 	ind_block_num = fp->f_di.di_ib[level / fp->f_nishift - 1];
    375 
    376 	for (;;) {
    377 		level -= fp->f_nishift;
    378 		if (ind_block_num == 0) {
    379 			*disk_block_p = 0;	/* missing */
    380 			return 0;
    381 		}
    382 
    383 		twiddle();
    384 		/*
    385 		 * If we were feeling brave, we could work out the number
    386 		 * of the disk sector and read a single disk sector instead
    387 		 * of a filesystem block.
    388 		 * However we don't do this very often anyway...
    389 		 */
    390 		rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
    391 			FSBTODB(fp->f_fs, ind_block_num), fs->fs_bsize,
    392 			buf, &rsize);
    393 		if (rc)
    394 			return rc;
    395 		if (rsize != fs->fs_bsize)
    396 			return EIO;
    397 		ind_block_num = buf[file_block >> level];
    398 		if (level == 0)
    399 			break;
    400 		file_block &= (1 << level) - 1;
    401 	}
    402 
    403 	/* Save the part of the block that contains this sector */
    404 	memcpy(fp->f_ind_cache, &buf[file_block & ~IND_CACHE_MASK],
    405 	    IND_CACHE_SZ * sizeof fp->f_ind_cache[0]);
    406 	fp->f_ind_cache_block = ind_cache;
    407 
    408 	*disk_block_p = ind_block_num;
    409 
    410 	return 0;
    411 }
    412 
    413 /*
    414  * Read a portion of a file into an internal buffer.
    415  * Return the location in the buffer and the amount in the buffer.
    416  */
    417 static int
    418 buf_read_file(struct open_file *f, char **buf_p, size_t *size_p)
    419 {
    420 	struct file *fp = (struct file *)f->f_fsdata;
    421 	FS *fs = fp->f_fs;
    422 	long off;
    423 	indp_t file_block;
    424 	size_t block_size;
    425 	int rc;
    426 
    427 	off = ufs_blkoff(fs, fp->f_seekp);
    428 	file_block = ufs_lblkno(fs, fp->f_seekp);
    429 #ifdef LIBSA_LFS
    430 	block_size = dblksize(fs, &fp->f_di, file_block);
    431 #else
    432 	block_size = ffs_sblksize(fs, (int64_t)fp->f_di.di_size, file_block);
    433 #endif
    434 
    435 	if (file_block != fp->f_buf_blkno) {
    436 		indp_t disk_block = 0; /* XXX: gcc */
    437 		rc = block_map(f, file_block, &disk_block);
    438 		if (rc)
    439 			return rc;
    440 
    441 		if (disk_block == 0) {
    442 			memset(fp->f_buf, 0, block_size);
    443 			fp->f_buf_size = block_size;
    444 		} else {
    445 			twiddle();
    446 			rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
    447 				FSBTODB(fs, disk_block),
    448 				block_size, fp->f_buf, &fp->f_buf_size);
    449 			if (rc)
    450 				return rc;
    451 		}
    452 
    453 		fp->f_buf_blkno = file_block;
    454 	}
    455 
    456 	/*
    457 	 * Return address of byte in buffer corresponding to
    458 	 * offset, and size of remainder of buffer after that
    459 	 * byte.
    460 	 */
    461 	*buf_p = fp->f_buf + off;
    462 	*size_p = block_size - off;
    463 
    464 	/*
    465 	 * But truncate buffer at end of file.
    466 	 */
    467 	if (*size_p > fp->f_di.di_size - fp->f_seekp)
    468 		*size_p = fp->f_di.di_size - fp->f_seekp;
    469 
    470 	return 0;
    471 }
    472 
    473 /*
    474  * Search a directory for a name and return its
    475  * inode number.
    476  */
    477 static int
    478 search_directory(const char *name, int length, struct open_file *f,
    479 	ino32_t *inumber_p)
    480 {
    481 	struct file *fp = (struct file *)f->f_fsdata;
    482 	struct direct *dp;
    483 	struct direct *edp;
    484 	char *buf;
    485 	size_t buf_size;
    486 	int namlen;
    487 	int rc;
    488 
    489 	fp->f_seekp = 0;
    490 	while (fp->f_seekp < (off_t)fp->f_di.di_size) {
    491 		rc = buf_read_file(f, &buf, &buf_size);
    492 		if (rc)
    493 			return rc;
    494 
    495 		dp = (struct direct *)buf;
    496 		edp = (struct direct *)(buf + buf_size);
    497 		for (;dp < edp; dp = (void *)((char *)dp + dp->d_reclen)) {
    498 			if (dp->d_reclen <= 0)
    499 				break;
    500 			if (dp->d_ino == (ino32_t)0)
    501 				continue;
    502 #if BYTE_ORDER == LITTLE_ENDIAN
    503 			if (fp->f_fs->fs_maxsymlinklen <= 0)
    504 				namlen = dp->d_type;
    505 			else
    506 #endif
    507 				namlen = dp->d_namlen;
    508 			if (namlen == length &&
    509 			    !memcmp(name, dp->d_name, length)) {
    510 				/* found entry */
    511 				*inumber_p = dp->d_ino;
    512 				return 0;
    513 			}
    514 		}
    515 		fp->f_seekp += buf_size;
    516 	}
    517 	return ENOENT;
    518 }
    519 
    520 #ifdef LIBSA_FFSv2
    521 
    522 daddr_t sblock_try[] = SBLOCKSEARCH;
    523 
    524 static int
    525 ffs_find_superblock(struct open_file *f, FS *fs)
    526 {
    527 	int i, rc;
    528 	size_t buf_size;
    529 
    530 	for (i = 0; sblock_try[i] != -1; i++) {
    531 		rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
    532 		    sblock_try[i] / DEV_BSIZE, SBLOCKSIZE, fs, &buf_size);
    533 		if (rc != 0 || buf_size != SBLOCKSIZE)
    534 			return rc;
    535 		if (fs->fs_sblockloc != sblock_try[i])
    536 			/* an alternate superblock - try again */
    537 			continue;
    538 		if (fs->fs_magic == FS_UFS2_MAGIC) {
    539 			return 0;
    540 		}
    541 	}
    542 	return EINVAL;
    543 }
    544 
    545 #endif
    546 
    547 /*
    548  * Open a file.
    549  */
    550 __compactcall int
    551 ufs_open(const char *path, struct open_file *f)
    552 {
    553 #ifndef LIBSA_FS_SINGLECOMPONENT
    554 	const char *cp, *ncp;
    555 	int c;
    556 #endif
    557 	ino32_t inumber;
    558 	struct file *fp;
    559 	FS *fs;
    560 	int rc;
    561 #ifndef LIBSA_NO_FS_SYMLINK
    562 	ino32_t parent_inumber;
    563 	int nlinks = 0;
    564 	char namebuf[MAXPATHLEN+1];
    565 	char *buf;
    566 #endif
    567 
    568 	/* allocate file system specific data structure */
    569 	fp = alloc(sizeof(struct file));
    570 	memset(fp, 0, sizeof(struct file));
    571 	f->f_fsdata = (void *)fp;
    572 
    573 	/* allocate space and read super block */
    574 	fs = alloc(SBLOCKSIZE);
    575 	fp->f_fs = fs;
    576 	twiddle();
    577 
    578 #ifdef LIBSA_FFSv2
    579 	rc = ffs_find_superblock(f, fs);
    580 	if (rc)
    581 		goto out;
    582 #else
    583 	{
    584 		size_t buf_size;
    585 		rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
    586 			SBLOCKOFFSET / DEV_BSIZE, SBLOCKSIZE, fs, &buf_size);
    587 		if (rc)
    588 			goto out;
    589 		if (buf_size != SBLOCKSIZE ||
    590 #ifdef LIBSA_FFS
    591 		    fs->lfs_version != REQUIRED_LFS_VERSION ||
    592 #endif
    593 		    fs->fs_magic != FS_MAGIC) {
    594 			rc = EINVAL;
    595 			goto out;
    596 		}
    597 	}
    598 #if defined(LIBSA_LFS) && REQUIRED_LFS_VERSION == 2
    599 	/*
    600 	 * XXX	We should check the second superblock and use the eldest
    601 	 *	of the two.  See comments near the top of lfs_mountfs()
    602 	 *	in sys/ufs/lfs/lfs_vfsops.c.
    603 	 *      This may need a LIBSA_LFS_SMALL check as well.
    604 	 */
    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