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