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