Home | History | Annotate | Line # | Download | only in libsa
ext2fs.c revision 1.18
      1 /*	$NetBSD: ext2fs.c,v 1.18 2013/06/23 07:28:36 dholland 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) EXT2_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..EXT2FS_NDADDR-1]
    244 	 *		hold block numbers for blocks
    245 	 *		0..EXT2FS_NDADDR-1
    246 	 *
    247 	 * e2di_blocks[EXT2FS_NDADDR+0]
    248 	 *		block EXT2FS_NDADDR+0 is the single indirect block
    249 	 *		holds block numbers for blocks
    250 	 *		EXT2FS_NDADDR .. EXT2FS_NDADDR + EXT2_NINDIR(fs)-1
    251 	 *
    252 	 * e2di_blocks[EXT2FS_NDADDR+1]
    253 	 *		block EXT2FS_NDADDR+1 is the double indirect block
    254 	 *		holds block numbers for INDEX blocks for blocks
    255 	 *		EXT2FS_NDADDR + EXT2_NINDIR(fs) ..
    256 	 *		EXT2FS_NDADDR + EXT2_NINDIR(fs) + EXT2_NINDIR(fs)**2 - 1
    257 	 *
    258 	 * e2di_blocks[EXT2FS_NDADDR+2]
    259 	 *		block EXT2FS_NDADDR+2 is the triple indirect block
    260 	 *		holds block numbers for	double-indirect
    261 	 *		blocks for blocks
    262 	 *		EXT2FS_NDADDR + EXT2_NINDIR(fs) + EXT2_NINDIR(fs)**2 ..
    263 	 *		EXT2FS_NDADDR + EXT2_NINDIR(fs) + EXT2_NINDIR(fs)**2
    264 	 *			+ EXT2_NINDIR(fs)**3 - 1
    265 	 */
    266 
    267 	if (file_block < EXT2FS_NDADDR) {
    268 		/* Direct block. */
    269 		*disk_block_p = fs2h32(fp->f_di.e2di_blocks[file_block]);
    270 		return 0;
    271 	}
    272 
    273 	file_block -= EXT2FS_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 > EXT2FS_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[EXT2FS_NDADDR +
    294 	    (level / fp->f_nishift - 1)]);
    295 
    296 	for (;;) {
    297 		level -= fp->f_nishift;
    298 		if (ind_block_num == 0) {
    299 			*disk_block_p = 0;	/* missing */
    300 			return 0;
    301 		}
    302 
    303 		twiddle();
    304 		/*
    305 		 * If we were feeling brave, we could work out the number
    306 		 * of the disk sector and read a single disk sector instead
    307 		 * of a filesystem block.
    308 		 * However we don't do this very often anyway...
    309 		 */
    310 		rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
    311 			FSBTODB(fp->f_fs, ind_block_num), fs->e2fs_bsize,
    312 			buf, &rsize);
    313 		if (rc)
    314 			return rc;
    315 		if (rsize != fs->e2fs_bsize)
    316 			return EIO;
    317 		ind_block_num = fs2h32(buf[file_block >> level]);
    318 		if (level == 0)
    319 			break;
    320 		file_block &= (1 << level) - 1;
    321 	}
    322 
    323 	/* Save the part of the block that contains this sector */
    324 	memcpy(fp->f_ind_cache, &buf[file_block & ~IND_CACHE_MASK],
    325 	    IND_CACHE_SZ * sizeof fp->f_ind_cache[0]);
    326 	fp->f_ind_cache_block = ind_cache;
    327 
    328 	*disk_block_p = ind_block_num;
    329 
    330 	return 0;
    331 }
    332 
    333 /*
    334  * Read a portion of a file into an internal buffer.
    335  * Return the location in the buffer and the amount in the buffer.
    336  */
    337 static int
    338 buf_read_file(struct open_file *f, char **buf_p, size_t *size_p)
    339 {
    340 	struct file *fp = (struct file *)f->f_fsdata;
    341 	struct m_ext2fs *fs = fp->f_fs;
    342 	long off;
    343 	indp_t file_block;
    344 	indp_t disk_block;
    345 	size_t block_size;
    346 	int rc;
    347 
    348 	off = ext2_blkoff(fs, fp->f_seekp);
    349 	file_block = ext2_lblkno(fs, fp->f_seekp);
    350 	block_size = fs->e2fs_bsize;	/* no fragment */
    351 
    352 	if (file_block != fp->f_buf_blkno) {
    353 		rc = block_map(f, file_block, &disk_block);
    354 		if (rc)
    355 			return rc;
    356 
    357 		if (disk_block == 0) {
    358 			memset(fp->f_buf, 0, block_size);
    359 			fp->f_buf_size = block_size;
    360 		} else {
    361 			twiddle();
    362 			rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
    363 				FSBTODB(fs, disk_block),
    364 				block_size, fp->f_buf, &fp->f_buf_size);
    365 			if (rc)
    366 				return rc;
    367 		}
    368 
    369 		fp->f_buf_blkno = file_block;
    370 	}
    371 
    372 	/*
    373 	 * Return address of byte in buffer corresponding to
    374 	 * offset, and size of remainder of buffer after that
    375 	 * byte.
    376 	 */
    377 	*buf_p = fp->f_buf + off;
    378 	*size_p = block_size - off;
    379 
    380 	/*
    381 	 * But truncate buffer at end of file.
    382 	 */
    383 	/* XXX should handle LARGEFILE */
    384 	if (*size_p > fp->f_di.e2di_size - fp->f_seekp)
    385 		*size_p = fp->f_di.e2di_size - fp->f_seekp;
    386 
    387 	return 0;
    388 }
    389 
    390 /*
    391  * Search a directory for a name and return its
    392  * inode number.
    393  */
    394 static int
    395 search_directory(const char *name, int length, struct open_file *f,
    396 	ino32_t *inumber_p)
    397 {
    398 	struct file *fp = (struct file *)f->f_fsdata;
    399 	struct ext2fs_direct *dp;
    400 	struct ext2fs_direct *edp;
    401 	char *buf;
    402 	size_t buf_size;
    403 	int namlen;
    404 	int rc;
    405 
    406 	fp->f_seekp = 0;
    407 	/* XXX should handle LARGEFILE */
    408 	while (fp->f_seekp < (off_t)fp->f_di.e2di_size) {
    409 		rc = buf_read_file(f, &buf, &buf_size);
    410 		if (rc)
    411 			return rc;
    412 
    413 		dp = (struct ext2fs_direct *)buf;
    414 		edp = (struct ext2fs_direct *)(buf + buf_size);
    415 		for (; dp < edp;
    416 		    dp = (void *)((char *)dp + fs2h16(dp->e2d_reclen))) {
    417 			if (fs2h16(dp->e2d_reclen) <= 0)
    418 				break;
    419 			if (fs2h32(dp->e2d_ino) == (ino32_t)0)
    420 				continue;
    421 			namlen = dp->e2d_namlen;
    422 			if (namlen == length &&
    423 			    !memcmp(name, dp->e2d_name, length)) {
    424 				/* found entry */
    425 				*inumber_p = fs2h32(dp->e2d_ino);
    426 				return 0;
    427 			}
    428 		}
    429 		fp->f_seekp += buf_size;
    430 	}
    431 	return ENOENT;
    432 }
    433 
    434 int
    435 read_sblock(struct open_file *f, struct m_ext2fs *fs)
    436 {
    437 	static uint8_t sbbuf[SBSIZE];
    438 	struct ext2fs ext2fs;
    439 	size_t buf_size;
    440 	int rc;
    441 
    442 	rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
    443 	    SBOFF / DEV_BSIZE, SBSIZE, sbbuf, &buf_size);
    444 	if (rc)
    445 		return rc;
    446 
    447 	if (buf_size != SBSIZE)
    448 		return EIO;
    449 
    450 	e2fs_sbload((void *)sbbuf, &ext2fs);
    451 	if (ext2fs.e2fs_magic != E2FS_MAGIC)
    452 		return EINVAL;
    453 	if (ext2fs.e2fs_rev > E2FS_REV1 ||
    454 	    (ext2fs.e2fs_rev == E2FS_REV1 &&
    455 	     (ext2fs.e2fs_first_ino != EXT2_FIRSTINO ||
    456 	     (ext2fs.e2fs_inode_size != 128 && ext2fs.e2fs_inode_size != 256) ||
    457 	      ext2fs.e2fs_features_incompat & ~EXT2F_INCOMPAT_SUPP))) {
    458 		return ENODEV;
    459 	}
    460 
    461 	e2fs_sbload((void *)sbbuf, &fs->e2fs);
    462 	/* compute in-memory m_ext2fs values */
    463 	fs->e2fs_ncg =
    464 	    howmany(fs->e2fs.e2fs_bcount - fs->e2fs.e2fs_first_dblock,
    465 	    fs->e2fs.e2fs_bpg);
    466 	/* XXX assume hw bsize = 512 */
    467 	fs->e2fs_fsbtodb = fs->e2fs.e2fs_log_bsize + 1;
    468 	fs->e2fs_bsize = MINBSIZE << fs->e2fs.e2fs_log_bsize;
    469 	fs->e2fs_bshift = LOG_MINBSIZE + fs->e2fs.e2fs_log_bsize;
    470 	fs->e2fs_qbmask = fs->e2fs_bsize - 1;
    471 	fs->e2fs_bmask = ~fs->e2fs_qbmask;
    472 	fs->e2fs_ngdb =
    473 	    howmany(fs->e2fs_ncg, fs->e2fs_bsize / sizeof(struct ext2_gd));
    474 	fs->e2fs_ipb = fs->e2fs_bsize / ext2fs.e2fs_inode_size;
    475 	fs->e2fs_itpg = fs->e2fs.e2fs_ipg / fs->e2fs_ipb;
    476 
    477 	return 0;
    478 }
    479 
    480 int
    481 read_gdblock(struct open_file *f, struct m_ext2fs *fs)
    482 {
    483 	struct file *fp = (struct file *)f->f_fsdata;
    484 	size_t rsize;
    485 	uint gdpb;
    486 	int i, rc;
    487 
    488 	gdpb = fs->e2fs_bsize / sizeof(struct ext2_gd);
    489 
    490 	for (i = 0; i < fs->e2fs_ngdb; i++) {
    491 		rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
    492 		    FSBTODB(fs, fs->e2fs.e2fs_first_dblock +
    493 		    1 /* superblock */ + i),
    494 		    fs->e2fs_bsize, fp->f_buf, &rsize);
    495 		if (rc)
    496 			return rc;
    497 		if (rsize != fs->e2fs_bsize)
    498 			return EIO;
    499 
    500 		e2fs_cgload((struct ext2_gd *)fp->f_buf,
    501 		    &fs->e2fs_gd[i * gdpb],
    502 		    (i == (fs->e2fs_ngdb - 1)) ?
    503 		    (fs->e2fs_ncg - gdpb * i) * sizeof(struct ext2_gd):
    504 		    fs->e2fs_bsize);
    505 	}
    506 
    507 	return 0;
    508 }
    509 
    510 
    511 /*
    512  * Open a file.
    513  */
    514 __compactcall int
    515 ext2fs_open(const char *path, struct open_file *f)
    516 {
    517 #ifndef LIBSA_FS_SINGLECOMPONENT
    518 	const char *cp, *ncp;
    519 	int c;
    520 #endif
    521 	ino32_t inumber;
    522 	struct file *fp;
    523 	struct m_ext2fs *fs;
    524 	int rc;
    525 #ifndef LIBSA_NO_FS_SYMLINK
    526 	ino32_t parent_inumber;
    527 	int nlinks = 0;
    528 	char namebuf[MAXPATHLEN+1];
    529 	char *buf;
    530 #endif
    531 
    532 	/* allocate file system specific data structure */
    533 	fp = alloc(sizeof(struct file));
    534 	memset(fp, 0, sizeof(struct file));
    535 	f->f_fsdata = (void *)fp;
    536 
    537 	/* allocate space and read super block */
    538 	fs = alloc(sizeof(*fs));
    539 	memset(fs, 0, sizeof(*fs));
    540 	fp->f_fs = fs;
    541 	twiddle();
    542 
    543 	rc = read_sblock(f, fs);
    544 	if (rc)
    545 		goto out;
    546 
    547 #ifdef EXT2FS_DEBUG
    548 	dump_sblock(fs);
    549 #endif
    550 
    551 	/* alloc a block sized buffer used for all fs transfers */
    552 	fp->f_buf = alloc(fs->e2fs_bsize);
    553 
    554 	/* read group descriptor blocks */
    555 	fs->e2fs_gd = alloc(sizeof(struct ext2_gd) * fs->e2fs_ncg);
    556 	rc = read_gdblock(f, fs);
    557 	if (rc)
    558 		goto out;
    559 
    560 	/*
    561 	 * Calculate indirect block levels.
    562 	 */
    563 	{
    564 		indp_t mult;
    565 		int ln2;
    566 
    567 		/*
    568 		 * We note that the number of indirect blocks is always
    569 		 * a power of 2.  This lets us use shifts and masks instead
    570 		 * of divide and remainder and avoinds pulling in the
    571 		 * 64bit division routine into the boot code.
    572 		 */
    573 		mult = EXT2_NINDIR(fs);
    574 #ifdef DEBUG
    575 		if (!powerof2(mult)) {
    576 			/* Hummm was't a power of 2 */
    577 			rc = EINVAL;
    578 			goto out;
    579 		}
    580 #endif
    581 		for (ln2 = 0; mult != 1; ln2++)
    582 			mult >>= 1;
    583 
    584 		fp->f_nishift = ln2;
    585 	}
    586 
    587 	inumber = EXT2_ROOTINO;
    588 	if ((rc = read_inode(inumber, f)) != 0)
    589 		goto out;
    590 
    591 #ifndef LIBSA_FS_SINGLECOMPONENT
    592 	cp = path;
    593 	while (*cp) {
    594 
    595 		/*
    596 		 * Remove extra separators
    597 		 */
    598 		while (*cp == '/')
    599 			cp++;
    600 		if (*cp == '\0')
    601 			break;
    602 
    603 		/*
    604 		 * Check that current node is a directory.
    605 		 */
    606 		if ((fp->f_di.e2di_mode & EXT2_IFMT) != EXT2_IFDIR) {
    607 			rc = ENOTDIR;
    608 			goto out;
    609 		}
    610 
    611 		/*
    612 		 * Get next component of path name.
    613 		 */
    614 		ncp = cp;
    615 		while ((c = *cp) != '\0' && c != '/')
    616 			cp++;
    617 
    618 		/*
    619 		 * Look up component in current directory.
    620 		 * Save directory inumber in case we find a
    621 		 * symbolic link.
    622 		 */
    623 #ifndef LIBSA_NO_FS_SYMLINK
    624 		parent_inumber = inumber;
    625 #endif
    626 		rc = search_directory(ncp, cp - ncp, f, &inumber);
    627 		if (rc)
    628 			goto out;
    629 
    630 		/*
    631 		 * Open next component.
    632 		 */
    633 		if ((rc = read_inode(inumber, f)) != 0)
    634 			goto out;
    635 
    636 #ifndef LIBSA_NO_FS_SYMLINK
    637 		/*
    638 		 * Check for symbolic link.
    639 		 */
    640 		if ((fp->f_di.e2di_mode & EXT2_IFMT) == EXT2_IFLNK) {
    641 			/* XXX should handle LARGEFILE */
    642 			int link_len = fp->f_di.e2di_size;
    643 			int len;
    644 
    645 			len = strlen(cp);
    646 
    647 			if (link_len + len > MAXPATHLEN ||
    648 			    ++nlinks > MAXSYMLINKS) {
    649 				rc = ENOENT;
    650 				goto out;
    651 			}
    652 
    653 			memmove(&namebuf[link_len], cp, len + 1);
    654 
    655 			if (link_len < EXT2_MAXSYMLINKLEN) {
    656 				memcpy(namebuf, fp->f_di.e2di_blocks, link_len);
    657 			} else {
    658 				/*
    659 				 * Read file for symbolic link
    660 				 */
    661 				size_t buf_size;
    662 				indp_t	disk_block;
    663 
    664 				buf = fp->f_buf;
    665 				rc = block_map(f, (indp_t)0, &disk_block);
    666 				if (rc)
    667 					goto out;
    668 
    669 				twiddle();
    670 				rc = DEV_STRATEGY(f->f_dev)(f->f_devdata,
    671 					F_READ, FSBTODB(fs, disk_block),
    672 					fs->e2fs_bsize, buf, &buf_size);
    673 				if (rc)
    674 					goto out;
    675 
    676 				memcpy(namebuf, buf, link_len);
    677 			}
    678 
    679 			/*
    680 			 * If relative pathname, restart at parent directory.
    681 			 * If absolute pathname, restart at root.
    682 			 */
    683 			cp = namebuf;
    684 			if (*cp != '/')
    685 				inumber = parent_inumber;
    686 			else
    687 				inumber = (ino32_t)EXT2_ROOTINO;
    688 
    689 			if ((rc = read_inode(inumber, f)) != 0)
    690 				goto out;
    691 		}
    692 #endif	/* !LIBSA_NO_FS_SYMLINK */
    693 	}
    694 
    695 	/*
    696 	 * Found terminal component.
    697 	 */
    698 	rc = 0;
    699 
    700 #else /* !LIBSA_FS_SINGLECOMPONENT */
    701 
    702 	/* look up component in the current (root) directory */
    703 	rc = search_directory(path, strlen(path), f, &inumber);
    704 	if (rc)
    705 		goto out;
    706 
    707 	/* open it */
    708 	rc = read_inode(inumber, f);
    709 
    710 #endif /* !LIBSA_FS_SINGLECOMPONENT */
    711 
    712 	fp->f_seekp = 0;		/* reset seek pointer */
    713 
    714 out:
    715 	if (rc)
    716 		ext2fs_close(f);
    717 	else
    718 		fsmod = "ext2fs";
    719 	return rc;
    720 }
    721 
    722 __compactcall int
    723 ext2fs_close(struct open_file *f)
    724 {
    725 	struct file *fp = (struct file *)f->f_fsdata;
    726 
    727 	f->f_fsdata = NULL;
    728 	if (fp == NULL)
    729 		return 0;
    730 
    731 	if (fp->f_fs->e2fs_gd)
    732 		dealloc(fp->f_fs->e2fs_gd,
    733 		    sizeof(struct ext2_gd) * fp->f_fs->e2fs_ncg);
    734 	if (fp->f_buf)
    735 		dealloc(fp->f_buf, fp->f_fs->e2fs_bsize);
    736 	dealloc(fp->f_fs, sizeof(*fp->f_fs));
    737 	dealloc(fp, sizeof(struct file));
    738 	return 0;
    739 }
    740 
    741 /*
    742  * Copy a portion of a file into kernel memory.
    743  * Cross block boundaries when necessary.
    744  */
    745 __compactcall int
    746 ext2fs_read(struct open_file *f, void *start, size_t size, size_t *resid)
    747 {
    748 	struct file *fp = (struct file *)f->f_fsdata;
    749 	size_t csize;
    750 	char *buf;
    751 	size_t buf_size;
    752 	int rc = 0;
    753 	char *addr = start;
    754 
    755 	while (size != 0) {
    756 		/* XXX should handle LARGEFILE */
    757 		if (fp->f_seekp >= (off_t)fp->f_di.e2di_size)
    758 			break;
    759 
    760 		rc = buf_read_file(f, &buf, &buf_size);
    761 		if (rc)
    762 			break;
    763 
    764 		csize = size;
    765 		if (csize > buf_size)
    766 			csize = buf_size;
    767 
    768 		memcpy(addr, buf, csize);
    769 
    770 		fp->f_seekp += csize;
    771 		addr += csize;
    772 		size -= csize;
    773 	}
    774 	if (resid)
    775 		*resid = size;
    776 	return rc;
    777 }
    778 
    779 /*
    780  * Not implemented.
    781  */
    782 #ifndef LIBSA_NO_FS_WRITE
    783 __compactcall int
    784 ext2fs_write(struct open_file *f, void *start, size_t size, size_t *resid)
    785 {
    786 
    787 	return EROFS;
    788 }
    789 #endif /* !LIBSA_NO_FS_WRITE */
    790 
    791 #ifndef LIBSA_NO_FS_SEEK
    792 __compactcall off_t
    793 ext2fs_seek(struct open_file *f, off_t offset, int where)
    794 {
    795 	struct file *fp = (struct file *)f->f_fsdata;
    796 
    797 	switch (where) {
    798 	case SEEK_SET:
    799 		fp->f_seekp = offset;
    800 		break;
    801 	case SEEK_CUR:
    802 		fp->f_seekp += offset;
    803 		break;
    804 	case SEEK_END:
    805 		/* XXX should handle LARGEFILE */
    806 		fp->f_seekp = fp->f_di.e2di_size - offset;
    807 		break;
    808 	default:
    809 		return -1;
    810 	}
    811 	return fp->f_seekp;
    812 }
    813 #endif /* !LIBSA_NO_FS_SEEK */
    814 
    815 __compactcall int
    816 ext2fs_stat(struct open_file *f, struct stat *sb)
    817 {
    818 	struct file *fp = (struct file *)f->f_fsdata;
    819 
    820 	/* only important stuff */
    821 	memset(sb, 0, sizeof *sb);
    822 	sb->st_mode = fp->f_di.e2di_mode;
    823 	sb->st_uid = fp->f_di.e2di_uid;
    824 	sb->st_gid = fp->f_di.e2di_gid;
    825 	/* XXX should handle LARGEFILE */
    826 	sb->st_size = fp->f_di.e2di_size;
    827 	return 0;
    828 }
    829 
    830 #if defined(LIBSA_ENABLE_LS_OP)
    831 __compactcall void
    832 ext2fs_ls(struct open_file *f, const char *pattern)
    833 {
    834 	struct file *fp = (struct file *)f->f_fsdata;
    835 	size_t block_size = fp->f_fs->e2fs_bsize;
    836 	char *buf;
    837 	size_t buf_size;
    838 	entry_t	*names = 0, *n, **np;
    839 
    840 	fp->f_seekp = 0;
    841 	while (fp->f_seekp < (off_t)fp->f_di.e2di_size) {
    842 		struct ext2fs_direct  *dp, *edp;
    843 		int rc = buf_read_file(f, &buf, &buf_size);
    844 		if (rc)
    845 			goto out;
    846 		if (buf_size != block_size || buf_size == 0)
    847 			goto out;
    848 
    849 		dp = (struct ext2fs_direct *)buf;
    850 		edp = (struct ext2fs_direct *)(buf + buf_size);
    851 
    852 		for (; dp < edp;
    853 		     dp = (void *)((char *)dp + fs2h16(dp->e2d_reclen))) {
    854 			const char *t;
    855 
    856 			if (fs2h16(dp->e2d_reclen) <= 0)
    857 				goto out;
    858 
    859 			if (fs2h32(dp->e2d_ino) == 0)
    860 				continue;
    861 
    862 			if (dp->e2d_type >= NELEM(typestr) ||
    863 			    !(t = typestr[dp->e2d_type])) {
    864 				/*
    865 				 * This does not handle "old"
    866 				 * filesystems properly. On little
    867 				 * endian machines, we get a bogus
    868 				 * type name if the namlen matches a
    869 				 * valid type identifier. We could
    870 				 * check if we read namlen "0" and
    871 				 * handle this case specially, if
    872 				 * there were a pressing need...
    873 				 */
    874 				printf("bad dir entry\n");
    875 				goto out;
    876 			}
    877 			if (pattern && !fnmatch(dp->e2d_name, pattern))
    878 				continue;
    879 			n = alloc(sizeof *n + strlen(dp->e2d_name));
    880 			if (!n) {
    881 				printf("%d: %s (%s)\n",
    882 					fs2h32(dp->e2d_ino), dp->e2d_name, t);
    883 				continue;
    884 			}
    885 			n->e_ino = fs2h32(dp->e2d_ino);
    886 			n->e_type = dp->e2d_type;
    887 			strcpy(n->e_name, dp->e2d_name);
    888 			for (np = &names; *np; np = &(*np)->e_next) {
    889 				if (strcmp(n->e_name, (*np)->e_name) < 0)
    890 					break;
    891 			}
    892 			n->e_next = *np;
    893 			*np = n;
    894 		}
    895 		fp->f_seekp += buf_size;
    896 	}
    897 
    898 	if (names) {
    899 		entry_t *p_names = names;
    900 		do {
    901 			n = p_names;
    902 			printf("%d: %s (%s)\n",
    903 				n->e_ino, n->e_name, typestr[n->e_type]);
    904 			p_names = n->e_next;
    905 		} while (p_names);
    906 	} else {
    907 		printf("not found\n");
    908 	}
    909 out:
    910 	if (names) {
    911 		do {
    912 			n = names;
    913 			names = n->e_next;
    914 			dealloc(n, 0);
    915 		} while (names);
    916 	}
    917 	return;
    918 }
    919 #endif
    920 
    921 /*
    922  * byte swap functions for big endian machines
    923  * (ext2fs is always little endian)
    924  *
    925  * XXX: We should use src/sys/ufs/ext2fs/ext2fs_bswap.c
    926  */
    927 
    928 /* These functions are only needed if native byte order is not big endian */
    929 #if BYTE_ORDER == BIG_ENDIAN
    930 void
    931 e2fs_sb_bswap(struct ext2fs *old, struct ext2fs *new)
    932 {
    933 
    934 	/* preserve unused fields */
    935 	memcpy(new, old, sizeof(struct ext2fs));
    936 	new->e2fs_icount	=	bswap32(old->e2fs_icount);
    937 	new->e2fs_bcount	=	bswap32(old->e2fs_bcount);
    938 	new->e2fs_rbcount	=	bswap32(old->e2fs_rbcount);
    939 	new->e2fs_fbcount	=	bswap32(old->e2fs_fbcount);
    940 	new->e2fs_ficount	=	bswap32(old->e2fs_ficount);
    941 	new->e2fs_first_dblock	=	bswap32(old->e2fs_first_dblock);
    942 	new->e2fs_log_bsize	=	bswap32(old->e2fs_log_bsize);
    943 	new->e2fs_fsize		=	bswap32(old->e2fs_fsize);
    944 	new->e2fs_bpg		=	bswap32(old->e2fs_bpg);
    945 	new->e2fs_fpg		=	bswap32(old->e2fs_fpg);
    946 	new->e2fs_ipg		=	bswap32(old->e2fs_ipg);
    947 	new->e2fs_mtime		=	bswap32(old->e2fs_mtime);
    948 	new->e2fs_wtime		=	bswap32(old->e2fs_wtime);
    949 	new->e2fs_mnt_count	=	bswap16(old->e2fs_mnt_count);
    950 	new->e2fs_max_mnt_count	=	bswap16(old->e2fs_max_mnt_count);
    951 	new->e2fs_magic		=	bswap16(old->e2fs_magic);
    952 	new->e2fs_state		=	bswap16(old->e2fs_state);
    953 	new->e2fs_beh		=	bswap16(old->e2fs_beh);
    954 	new->e2fs_minrev	=	bswap16(old->e2fs_minrev);
    955 	new->e2fs_lastfsck	=	bswap32(old->e2fs_lastfsck);
    956 	new->e2fs_fsckintv	=	bswap32(old->e2fs_fsckintv);
    957 	new->e2fs_creator	=	bswap32(old->e2fs_creator);
    958 	new->e2fs_rev		=	bswap32(old->e2fs_rev);
    959 	new->e2fs_ruid		=	bswap16(old->e2fs_ruid);
    960 	new->e2fs_rgid		=	bswap16(old->e2fs_rgid);
    961 	new->e2fs_first_ino	=	bswap32(old->e2fs_first_ino);
    962 	new->e2fs_inode_size	=	bswap16(old->e2fs_inode_size);
    963 	new->e2fs_block_group_nr =	bswap16(old->e2fs_block_group_nr);
    964 	new->e2fs_features_compat =	bswap32(old->e2fs_features_compat);
    965 	new->e2fs_features_incompat =	bswap32(old->e2fs_features_incompat);
    966 	new->e2fs_features_rocompat =	bswap32(old->e2fs_features_rocompat);
    967 	new->e2fs_algo		=	bswap32(old->e2fs_algo);
    968 	new->e2fs_reserved_ngdb	=	bswap16(old->e2fs_reserved_ngdb);
    969 }
    970 
    971 void e2fs_cg_bswap(struct ext2_gd *old, struct ext2_gd *new, int size)
    972 {
    973 	int i;
    974 
    975 	for (i = 0; i < (size / sizeof(struct ext2_gd)); i++) {
    976 		new[i].ext2bgd_b_bitmap	= bswap32(old[i].ext2bgd_b_bitmap);
    977 		new[i].ext2bgd_i_bitmap	= bswap32(old[i].ext2bgd_i_bitmap);
    978 		new[i].ext2bgd_i_tables	= bswap32(old[i].ext2bgd_i_tables);
    979 		new[i].ext2bgd_nbfree	= bswap16(old[i].ext2bgd_nbfree);
    980 		new[i].ext2bgd_nifree	= bswap16(old[i].ext2bgd_nifree);
    981 		new[i].ext2bgd_ndirs	= bswap16(old[i].ext2bgd_ndirs);
    982 	}
    983 }
    984 
    985 void e2fs_i_bswap(struct ext2fs_dinode *old, struct ext2fs_dinode *new)
    986 {
    987 
    988 	new->e2di_mode		=	bswap16(old->e2di_mode);
    989 	new->e2di_uid		=	bswap16(old->e2di_uid);
    990 	new->e2di_gid		=	bswap16(old->e2di_gid);
    991 	new->e2di_nlink		=	bswap16(old->e2di_nlink);
    992 	new->e2di_size		=	bswap32(old->e2di_size);
    993 	new->e2di_atime		=	bswap32(old->e2di_atime);
    994 	new->e2di_ctime		=	bswap32(old->e2di_ctime);
    995 	new->e2di_mtime		=	bswap32(old->e2di_mtime);
    996 	new->e2di_dtime		=	bswap32(old->e2di_dtime);
    997 	new->e2di_nblock	=	bswap32(old->e2di_nblock);
    998 	new->e2di_flags		=	bswap32(old->e2di_flags);
    999 	new->e2di_gen		=	bswap32(old->e2di_gen);
   1000 	new->e2di_facl		=	bswap32(old->e2di_facl);
   1001 	new->e2di_dacl		=	bswap32(old->e2di_dacl);
   1002 	new->e2di_faddr		=	bswap32(old->e2di_faddr);
   1003 	memcpy(&new->e2di_blocks[0], &old->e2di_blocks[0],
   1004 	    (EXT2FS_NDADDR + EXT2FS_NIADDR) * sizeof(uint32_t));
   1005 }
   1006 #endif
   1007 
   1008 #ifdef EXT2FS_DEBUG
   1009 void
   1010 dump_sblock(struct m_ext2fs *fs)
   1011 {
   1012 
   1013 	printf("fs->e2fs.e2fs_bcount = %u\n", fs->e2fs.e2fs_bcount);
   1014 	printf("fs->e2fs.e2fs_first_dblock = %u\n", fs->e2fs.e2fs_first_dblock);
   1015 	printf("fs->e2fs.e2fs_log_bsize = %u\n", fs->e2fs.e2fs_log_bsize);
   1016 	printf("fs->e2fs.e2fs_bpg = %u\n", fs->e2fs.e2fs_bpg);
   1017 	printf("fs->e2fs.e2fs_ipg = %u\n", fs->e2fs.e2fs_ipg);
   1018 	printf("fs->e2fs.e2fs_magic = 0x%x\n", fs->e2fs.e2fs_magic);
   1019 	printf("fs->e2fs.e2fs_rev = %u\n", fs->e2fs.e2fs_rev);
   1020 
   1021 	if (fs->e2fs.e2fs_rev == E2FS_REV1) {
   1022 		printf("fs->e2fs.e2fs_first_ino = %u\n",
   1023 		    fs->e2fs.e2fs_first_ino);
   1024 		printf("fs->e2fs.e2fs_inode_size = %u\n",
   1025 		    fs->e2fs.e2fs_inode_size);
   1026 		printf("fs->e2fs.e2fs_features_compat = %u\n",
   1027 		    fs->e2fs.e2fs_features_compat);
   1028 		printf("fs->e2fs.e2fs_features_incompat = %u\n",
   1029 		    fs->e2fs.e2fs_features_incompat);
   1030 		printf("fs->e2fs.e2fs_features_rocompat = %u\n",
   1031 		    fs->e2fs.e2fs_features_rocompat);
   1032 		printf("fs->e2fs.e2fs_reserved_ngdb = %u\n",
   1033 		    fs->e2fs.e2fs_reserved_ngdb);
   1034 	}
   1035 
   1036 	printf("fs->e2fs_bsize = %u\n", fs->e2fs_bsize);
   1037 	printf("fs->e2fs_fsbtodb = %u\n", fs->e2fs_fsbtodb);
   1038 	printf("fs->e2fs_ncg = %u\n", fs->e2fs_ncg);
   1039 	printf("fs->e2fs_ngdb = %u\n", fs->e2fs_ngdb);
   1040 	printf("fs->e2fs_ipb = %u\n", fs->e2fs_ipb);
   1041 	printf("fs->e2fs_itpg = %u\n", fs->e2fs_itpg);
   1042 }
   1043 #endif
   1044