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