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