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