xref: /minix3/usr.sbin/installboot/ext2fs.c (revision 84d9c625bfea59e274550651111ae9edfdc40fbd)
1*84d9c625SLionel Sambuc /*	$NetBSD: ext2fs.c,v 1.9 2013/06/23 02:06:06 dholland Exp $	*/
29f8e6353SEvgeniy Ivanov 
39f8e6353SEvgeniy Ivanov /*
49f8e6353SEvgeniy Ivanov  * Copyright (c) 1997 Manuel Bouyer.
59f8e6353SEvgeniy Ivanov  *
69f8e6353SEvgeniy Ivanov  * Redistribution and use in source and binary forms, with or without
79f8e6353SEvgeniy Ivanov  * modification, are permitted provided that the following conditions
89f8e6353SEvgeniy Ivanov  * are met:
99f8e6353SEvgeniy Ivanov  * 1. Redistributions of source code must retain the above copyright
109f8e6353SEvgeniy Ivanov  *    notice, this list of conditions and the following disclaimer.
119f8e6353SEvgeniy Ivanov  * 2. Redistributions in binary form must reproduce the above copyright
129f8e6353SEvgeniy Ivanov  *    notice, this list of conditions and the following disclaimer in the
139f8e6353SEvgeniy Ivanov  *    documentation and/or other materials provided with the distribution.
149f8e6353SEvgeniy Ivanov  *
159f8e6353SEvgeniy Ivanov  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
169f8e6353SEvgeniy Ivanov  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
179f8e6353SEvgeniy Ivanov  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
189f8e6353SEvgeniy Ivanov  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
199f8e6353SEvgeniy Ivanov  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
209f8e6353SEvgeniy Ivanov  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
219f8e6353SEvgeniy Ivanov  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
229f8e6353SEvgeniy Ivanov  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
239f8e6353SEvgeniy Ivanov  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
249f8e6353SEvgeniy Ivanov  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
259f8e6353SEvgeniy Ivanov  */
269f8e6353SEvgeniy Ivanov 
279f8e6353SEvgeniy Ivanov /*-
289f8e6353SEvgeniy Ivanov  * Copyright (c) 2002 The NetBSD Foundation, Inc.
299f8e6353SEvgeniy Ivanov  * All rights reserved.
309f8e6353SEvgeniy Ivanov  *
319f8e6353SEvgeniy Ivanov  * This code is derived from software contributed to The NetBSD Foundation
329f8e6353SEvgeniy Ivanov  * by Matt Fredette.
339f8e6353SEvgeniy Ivanov  *
349f8e6353SEvgeniy Ivanov  * Redistribution and use in source and binary forms, with or without
359f8e6353SEvgeniy Ivanov  * modification, are permitted provided that the following conditions
369f8e6353SEvgeniy Ivanov  * are met:
379f8e6353SEvgeniy Ivanov  * 1. Redistributions of source code must retain the above copyright
389f8e6353SEvgeniy Ivanov  *    notice, this list of conditions and the following disclaimer.
399f8e6353SEvgeniy Ivanov  * 2. Redistributions in binary form must reproduce the above copyright
409f8e6353SEvgeniy Ivanov  *    notice, this list of conditions and the following disclaimer in the
419f8e6353SEvgeniy Ivanov  *    documentation and/or other materials provided with the distribution.
429f8e6353SEvgeniy Ivanov  *
439f8e6353SEvgeniy Ivanov  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
449f8e6353SEvgeniy Ivanov  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
459f8e6353SEvgeniy Ivanov  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
469f8e6353SEvgeniy Ivanov  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
479f8e6353SEvgeniy Ivanov  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
489f8e6353SEvgeniy Ivanov  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
499f8e6353SEvgeniy Ivanov  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
509f8e6353SEvgeniy Ivanov  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
519f8e6353SEvgeniy Ivanov  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
529f8e6353SEvgeniy Ivanov  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
539f8e6353SEvgeniy Ivanov  * POSSIBILITY OF SUCH DAMAGE.
549f8e6353SEvgeniy Ivanov  */
559f8e6353SEvgeniy Ivanov 
569f8e6353SEvgeniy Ivanov #if HAVE_NBTOOL_CONFIG_H
579f8e6353SEvgeniy Ivanov #include "nbtool_config.h"
589f8e6353SEvgeniy Ivanov #endif
599f8e6353SEvgeniy Ivanov 
609f8e6353SEvgeniy Ivanov #include <sys/cdefs.h>
619f8e6353SEvgeniy Ivanov #if !defined(__lint)
62*84d9c625SLionel Sambuc __RCSID("$NetBSD: ext2fs.c,v 1.9 2013/06/23 02:06:06 dholland Exp $");
639f8e6353SEvgeniy Ivanov #endif	/* !__lint */
649f8e6353SEvgeniy Ivanov 
659f8e6353SEvgeniy Ivanov #include <sys/param.h>
669f8e6353SEvgeniy Ivanov 
679f8e6353SEvgeniy Ivanov #if !HAVE_NBTOOL_CONFIG_H
689f8e6353SEvgeniy Ivanov #include <sys/mount.h>
699f8e6353SEvgeniy Ivanov #endif
709f8e6353SEvgeniy Ivanov 
719f8e6353SEvgeniy Ivanov #include <assert.h>
729f8e6353SEvgeniy Ivanov #include <err.h>
739f8e6353SEvgeniy Ivanov #include <errno.h>
749f8e6353SEvgeniy Ivanov #include <fcntl.h>
759f8e6353SEvgeniy Ivanov #include <stdarg.h>
769f8e6353SEvgeniy Ivanov #include <stdio.h>
779f8e6353SEvgeniy Ivanov #include <stdlib.h>
789f8e6353SEvgeniy Ivanov #include <string.h>
799f8e6353SEvgeniy Ivanov #include <unistd.h>
809f8e6353SEvgeniy Ivanov 
819f8e6353SEvgeniy Ivanov #include "installboot.h"
829f8e6353SEvgeniy Ivanov 
839f8e6353SEvgeniy Ivanov #include <ufs/ext2fs/ext2fs_dinode.h>
849f8e6353SEvgeniy Ivanov #include <ufs/ext2fs/ext2fs_dir.h>
859f8e6353SEvgeniy Ivanov #include <ufs/ext2fs/ext2fs.h>
869f8e6353SEvgeniy Ivanov 
879f8e6353SEvgeniy Ivanov static int	ext2fs_read_disk_block(ib_params *, uint64_t, int, uint8_t []);
889f8e6353SEvgeniy Ivanov static int	ext2fs_read_sblock(ib_params *, struct m_ext2fs *fs);
899f8e6353SEvgeniy Ivanov static int	ext2fs_read_gdblock(ib_params *, struct m_ext2fs *fs);
909f8e6353SEvgeniy Ivanov static int	ext2fs_find_disk_blocks(ib_params *, ino_t,
919f8e6353SEvgeniy Ivanov 		    int (*)(ib_params *, void *, uint64_t, uint32_t), void *);
929f8e6353SEvgeniy Ivanov static int	ext2fs_findstage2_ino(ib_params *, void *, uint64_t, uint32_t);
939f8e6353SEvgeniy Ivanov static int	ext2fs_findstage2_blocks(ib_params *, void *, uint64_t,
949f8e6353SEvgeniy Ivanov 		    uint32_t);
959f8e6353SEvgeniy Ivanov 
969f8e6353SEvgeniy Ivanov 
979f8e6353SEvgeniy Ivanov /* This reads a disk block from the file system. */
989f8e6353SEvgeniy Ivanov /* XXX: should be shared with ffs.c? */
999f8e6353SEvgeniy Ivanov static int
ext2fs_read_disk_block(ib_params * params,uint64_t blkno,int size,uint8_t blk[])1009f8e6353SEvgeniy Ivanov ext2fs_read_disk_block(ib_params *params, uint64_t blkno, int size,
1019f8e6353SEvgeniy Ivanov     uint8_t blk[])
1029f8e6353SEvgeniy Ivanov {
1039f8e6353SEvgeniy Ivanov 	int rv;
1049f8e6353SEvgeniy Ivanov 
1059f8e6353SEvgeniy Ivanov 	assert(params != NULL);
1069f8e6353SEvgeniy Ivanov 	assert(params->filesystem != NULL);
1079f8e6353SEvgeniy Ivanov 	assert(params->fsfd != -1);
1089f8e6353SEvgeniy Ivanov 	assert(size > 0);
1099f8e6353SEvgeniy Ivanov 	assert(blk != NULL);
1109f8e6353SEvgeniy Ivanov 
1119f8e6353SEvgeniy Ivanov 	rv = pread(params->fsfd, blk, size, blkno * params->sectorsize);
1129f8e6353SEvgeniy Ivanov 	if (rv == -1) {
1139f8e6353SEvgeniy Ivanov 		warn("Reading block %llu in `%s'",
1149f8e6353SEvgeniy Ivanov 		    (unsigned long long)blkno, params->filesystem);
1159f8e6353SEvgeniy Ivanov 		return 0;
1169f8e6353SEvgeniy Ivanov 	} else if (rv != size) {
1179f8e6353SEvgeniy Ivanov 		warnx("Reading block %llu in `%s': short read",
1189f8e6353SEvgeniy Ivanov 		    (unsigned long long)blkno, params->filesystem);
1199f8e6353SEvgeniy Ivanov 		return 0;
1209f8e6353SEvgeniy Ivanov 	}
1219f8e6353SEvgeniy Ivanov 
1229f8e6353SEvgeniy Ivanov 	return 1;
1239f8e6353SEvgeniy Ivanov }
1249f8e6353SEvgeniy Ivanov 
1259f8e6353SEvgeniy Ivanov static int
ext2fs_read_sblock(ib_params * params,struct m_ext2fs * fs)1269f8e6353SEvgeniy Ivanov ext2fs_read_sblock(ib_params *params, struct m_ext2fs *fs)
1279f8e6353SEvgeniy Ivanov {
1289f8e6353SEvgeniy Ivanov 	uint8_t sbbuf[SBSIZE];
1299f8e6353SEvgeniy Ivanov 
1309f8e6353SEvgeniy Ivanov 	if (ext2fs_read_disk_block(params, SBOFF / params->sectorsize, SBSIZE,
1319f8e6353SEvgeniy Ivanov 	    sbbuf) == 0)
1329f8e6353SEvgeniy Ivanov 
1339f8e6353SEvgeniy Ivanov 	e2fs_sbload((void *)sbbuf, &fs->e2fs);
1349f8e6353SEvgeniy Ivanov 
1359f8e6353SEvgeniy Ivanov 	if (fs->e2fs.e2fs_magic != E2FS_MAGIC)
1369f8e6353SEvgeniy Ivanov 		return 0;
1379f8e6353SEvgeniy Ivanov 
1389f8e6353SEvgeniy Ivanov 	if (fs->e2fs.e2fs_rev > E2FS_REV1 ||
1399f8e6353SEvgeniy Ivanov 	    (fs->e2fs.e2fs_rev == E2FS_REV1 &&
1409f8e6353SEvgeniy Ivanov 	     (fs->e2fs.e2fs_first_ino != EXT2_FIRSTINO ||
1419f8e6353SEvgeniy Ivanov 	      fs->e2fs.e2fs_inode_size != EXT2_DINODE_SIZE ||
1429f8e6353SEvgeniy Ivanov 	      (fs->e2fs.e2fs_features_incompat & ~EXT2F_INCOMPAT_SUPP) != 0)))
1439f8e6353SEvgeniy Ivanov 		return 0;
1449f8e6353SEvgeniy Ivanov 
1459f8e6353SEvgeniy Ivanov 	fs->e2fs_ncg =
1469f8e6353SEvgeniy Ivanov 	    howmany(fs->e2fs.e2fs_bcount - fs->e2fs.e2fs_first_dblock,
1479f8e6353SEvgeniy Ivanov 	    fs->e2fs.e2fs_bpg);
1489f8e6353SEvgeniy Ivanov 	/* XXX assume hw bsize = 512 */
1499f8e6353SEvgeniy Ivanov 	fs->e2fs_fsbtodb = fs->e2fs.e2fs_log_bsize + 1;
1509f8e6353SEvgeniy Ivanov 	fs->e2fs_bsize = MINBSIZE << fs->e2fs.e2fs_log_bsize;
1519f8e6353SEvgeniy Ivanov 	fs->e2fs_bshift = LOG_MINBSIZE + fs->e2fs.e2fs_log_bsize;
1529f8e6353SEvgeniy Ivanov 	fs->e2fs_qbmask = fs->e2fs_bsize - 1;
1539f8e6353SEvgeniy Ivanov 	fs->e2fs_bmask = ~fs->e2fs_qbmask;
1549f8e6353SEvgeniy Ivanov 	fs->e2fs_ngdb =
1559f8e6353SEvgeniy Ivanov 	    howmany(fs->e2fs_ncg, fs->e2fs_bsize / sizeof(struct ext2_gd));
1569f8e6353SEvgeniy Ivanov 	fs->e2fs_ipb = fs->e2fs_bsize / EXT2_DINODE_SIZE;
1579f8e6353SEvgeniy Ivanov 	fs->e2fs_itpg = fs->e2fs.e2fs_ipg / fs->e2fs_ipb;
1589f8e6353SEvgeniy Ivanov 
1599f8e6353SEvgeniy Ivanov 	return 1;
1609f8e6353SEvgeniy Ivanov }
1619f8e6353SEvgeniy Ivanov 
1629f8e6353SEvgeniy Ivanov static int
ext2fs_read_gdblock(ib_params * params,struct m_ext2fs * fs)1639f8e6353SEvgeniy Ivanov ext2fs_read_gdblock(ib_params *params, struct m_ext2fs *fs)
1649f8e6353SEvgeniy Ivanov {
1659f8e6353SEvgeniy Ivanov 	uint8_t gdbuf[MAXBSIZE];
1669f8e6353SEvgeniy Ivanov 	uint32_t gdpb;
1679f8e6353SEvgeniy Ivanov 	int i;
1689f8e6353SEvgeniy Ivanov 
1699f8e6353SEvgeniy Ivanov 	gdpb = fs->e2fs_bsize / sizeof(struct ext2_gd);
1709f8e6353SEvgeniy Ivanov 
1719f8e6353SEvgeniy Ivanov 	for (i = 0; i < fs->e2fs_ngdb; i++) {
172*84d9c625SLionel Sambuc 		if (ext2fs_read_disk_block(params, EXT2_FSBTODB(fs,
1739f8e6353SEvgeniy Ivanov 		    fs->e2fs.e2fs_first_dblock + 1 /* superblock */ + i),
1749f8e6353SEvgeniy Ivanov 		    SBSIZE, gdbuf) == 0)
1759f8e6353SEvgeniy Ivanov 			return 0;
1769f8e6353SEvgeniy Ivanov 
1779f8e6353SEvgeniy Ivanov 		e2fs_cgload((struct ext2_gd *)gdbuf, &fs->e2fs_gd[gdpb * i],
1789f8e6353SEvgeniy Ivanov 		    (i == (fs->e2fs_ngdb - 1)) ?
1799f8e6353SEvgeniy Ivanov 		    (fs->e2fs_ncg - gdpb * i) * sizeof(struct ext2_gd):
1809f8e6353SEvgeniy Ivanov 		    fs->e2fs_bsize);
1819f8e6353SEvgeniy Ivanov 	}
1829f8e6353SEvgeniy Ivanov 
1839f8e6353SEvgeniy Ivanov 	return 1;
1849f8e6353SEvgeniy Ivanov }
1859f8e6353SEvgeniy Ivanov 
1869f8e6353SEvgeniy Ivanov /*
1879f8e6353SEvgeniy Ivanov  * This iterates over the data blocks belonging to an inode,
1889f8e6353SEvgeniy Ivanov  * making a callback each iteration with the disk block number
1899f8e6353SEvgeniy Ivanov  * and the size.
1909f8e6353SEvgeniy Ivanov  */
1919f8e6353SEvgeniy Ivanov static int
ext2fs_find_disk_blocks(ib_params * params,ino_t ino,int (* callback)(ib_params *,void *,uint64_t,uint32_t),void * state)1929f8e6353SEvgeniy Ivanov ext2fs_find_disk_blocks(ib_params *params, ino_t ino,
1939f8e6353SEvgeniy Ivanov 	int (*callback)(ib_params *, void *, uint64_t, uint32_t),
1949f8e6353SEvgeniy Ivanov 	void *state)
1959f8e6353SEvgeniy Ivanov {
1969f8e6353SEvgeniy Ivanov 	uint8_t sbbuf[sizeof(struct m_ext2fs)];
1979f8e6353SEvgeniy Ivanov 	struct m_ext2fs *fs;
1989f8e6353SEvgeniy Ivanov 	uint8_t inodebuf[MAXBSIZE];
1999f8e6353SEvgeniy Ivanov 	struct ext2fs_dinode inode_store, *inode;
2009f8e6353SEvgeniy Ivanov 	int level_i;
2019f8e6353SEvgeniy Ivanov 	int32_t blk, lblk, nblk;
2029f8e6353SEvgeniy Ivanov 	int rv;
2039f8e6353SEvgeniy Ivanov #define LEVELS 4
2049f8e6353SEvgeniy Ivanov 	struct {
2059f8e6353SEvgeniy Ivanov 		uint32_t *blknums;
2069f8e6353SEvgeniy Ivanov 		unsigned long blkcount;
2079f8e6353SEvgeniy Ivanov 		uint8_t diskbuf[MAXBSIZE];
2089f8e6353SEvgeniy Ivanov 	} level[LEVELS];
2099f8e6353SEvgeniy Ivanov 
2109f8e6353SEvgeniy Ivanov 	assert(params != NULL);
2119f8e6353SEvgeniy Ivanov 	assert(params->fstype != NULL);
2129f8e6353SEvgeniy Ivanov 	assert(callback != NULL);
2139f8e6353SEvgeniy Ivanov 	assert(state != NULL);
2149f8e6353SEvgeniy Ivanov 
2159f8e6353SEvgeniy Ivanov 	/* Read the superblock. */
2169f8e6353SEvgeniy Ivanov 	fs = (void *)sbbuf;
2179f8e6353SEvgeniy Ivanov 	if (ext2fs_read_sblock(params, fs) == 0)
2189f8e6353SEvgeniy Ivanov 		return 0;
2199f8e6353SEvgeniy Ivanov 
2209f8e6353SEvgeniy Ivanov 	fs->e2fs_gd = malloc(sizeof(struct ext2_gd) * fs->e2fs_ncg);
2219f8e6353SEvgeniy Ivanov 	if (fs->e2fs_gd == NULL) {
2229f8e6353SEvgeniy Ivanov 		warnx("Can't allocate memofy for group descriptors");
2239f8e6353SEvgeniy Ivanov 		return 0;
2249f8e6353SEvgeniy Ivanov 	}
2259f8e6353SEvgeniy Ivanov 
2269f8e6353SEvgeniy Ivanov 	if (ext2fs_read_gdblock(params, fs) == 0) {
2279f8e6353SEvgeniy Ivanov 		warnx("Can't read group descriptors");
2289f8e6353SEvgeniy Ivanov 		return 0;
2299f8e6353SEvgeniy Ivanov 	}
2309f8e6353SEvgeniy Ivanov 
2319f8e6353SEvgeniy Ivanov 	if (fs->e2fs_ipb <= 0) {
2329f8e6353SEvgeniy Ivanov 		warnx("Bad ipb %d in superblock in `%s'",
2339f8e6353SEvgeniy Ivanov 		    fs->e2fs_ipb, params->filesystem);
2349f8e6353SEvgeniy Ivanov 		return 0;
2359f8e6353SEvgeniy Ivanov 	}
2369f8e6353SEvgeniy Ivanov 
2379f8e6353SEvgeniy Ivanov 	/* Read the inode. */
2389f8e6353SEvgeniy Ivanov 	if (ext2fs_read_disk_block(params,
239*84d9c625SLionel Sambuc 		EXT2_FSBTODB(fs, ino_to_fsba(fs, ino)) + params->fstype->offset,
2409f8e6353SEvgeniy Ivanov 		fs->e2fs_bsize, inodebuf))
2419f8e6353SEvgeniy Ivanov 		return 0;
2429f8e6353SEvgeniy Ivanov 	inode = (void *)inodebuf;
2439f8e6353SEvgeniy Ivanov 	e2fs_iload(&inode[ino_to_fsbo(fs, ino)], &inode_store);
2449f8e6353SEvgeniy Ivanov 	inode = &inode_store;
2459f8e6353SEvgeniy Ivanov 
2469f8e6353SEvgeniy Ivanov 	/* Get the block count and initialize for our block walk. */
2479f8e6353SEvgeniy Ivanov 	nblk = howmany(inode->e2di_size, fs->e2fs_bsize);
2489f8e6353SEvgeniy Ivanov 	lblk = 0;
2499f8e6353SEvgeniy Ivanov 	level_i = 0;
2509f8e6353SEvgeniy Ivanov 	level[0].blknums = &inode->e2di_blocks[0];
251*84d9c625SLionel Sambuc 	level[0].blkcount = UFS_NDADDR;
252*84d9c625SLionel Sambuc 	level[1].blknums = &inode->e2di_blocks[UFS_NDADDR + 0];
2539f8e6353SEvgeniy Ivanov 	level[1].blkcount = 1;
254*84d9c625SLionel Sambuc 	level[2].blknums = &inode->e2di_blocks[UFS_NDADDR + 1];
2559f8e6353SEvgeniy Ivanov 	level[2].blkcount = 1;
256*84d9c625SLionel Sambuc 	level[3].blknums = &inode->e2di_blocks[UFS_NDADDR + 2];
2579f8e6353SEvgeniy Ivanov 	level[3].blkcount = 1;
2589f8e6353SEvgeniy Ivanov 
2599f8e6353SEvgeniy Ivanov 	/* Walk the data blocks. */
2609f8e6353SEvgeniy Ivanov 	while (nblk > 0) {
2619f8e6353SEvgeniy Ivanov 
2629f8e6353SEvgeniy Ivanov 		/*
2639f8e6353SEvgeniy Ivanov 		 * If there are no more blocks at this indirection
2649f8e6353SEvgeniy Ivanov 		 * level, move up one indirection level and loop.
2659f8e6353SEvgeniy Ivanov 		 */
2669f8e6353SEvgeniy Ivanov 		if (level[level_i].blkcount == 0) {
2679f8e6353SEvgeniy Ivanov 			if (++level_i == LEVELS)
2689f8e6353SEvgeniy Ivanov 				break;
2699f8e6353SEvgeniy Ivanov 			continue;
2709f8e6353SEvgeniy Ivanov 		}
2719f8e6353SEvgeniy Ivanov 
2729f8e6353SEvgeniy Ivanov 		/* Get the next block at this level. */
2739f8e6353SEvgeniy Ivanov 		blk = fs2h32(*(level[level_i].blknums++));
2749f8e6353SEvgeniy Ivanov 		level[level_i].blkcount--;
2759f8e6353SEvgeniy Ivanov 
2769f8e6353SEvgeniy Ivanov #if 0
2779f8e6353SEvgeniy Ivanov 		fprintf(stderr, "ino %lu blk %lu level %d\n", ino, blk,
2789f8e6353SEvgeniy Ivanov 		    level_i);
2799f8e6353SEvgeniy Ivanov #endif
2809f8e6353SEvgeniy Ivanov 
2819f8e6353SEvgeniy Ivanov 		/*
2829f8e6353SEvgeniy Ivanov 		 * If we're not at the direct level, descend one
2839f8e6353SEvgeniy Ivanov 		 * level, read in that level's new block list,
2849f8e6353SEvgeniy Ivanov 		 * and loop.
2859f8e6353SEvgeniy Ivanov 		 */
2869f8e6353SEvgeniy Ivanov 		if (level_i > 0) {
2879f8e6353SEvgeniy Ivanov 			level_i--;
2889f8e6353SEvgeniy Ivanov 			if (blk == 0)
2899f8e6353SEvgeniy Ivanov 				memset(level[level_i].diskbuf, 0, MAXBSIZE);
2909f8e6353SEvgeniy Ivanov 			else if (ext2fs_read_disk_block(params,
291*84d9c625SLionel Sambuc 				EXT2_FSBTODB(fs, blk) + params->fstype->offset,
2929f8e6353SEvgeniy Ivanov 				fs->e2fs_bsize, level[level_i].diskbuf) == 0)
2939f8e6353SEvgeniy Ivanov 				return 0;
2949f8e6353SEvgeniy Ivanov 			/* XXX ondisk32 */
2959f8e6353SEvgeniy Ivanov 			level[level_i].blknums =
2969f8e6353SEvgeniy Ivanov 			    (uint32_t *)level[level_i].diskbuf;
297*84d9c625SLionel Sambuc 			level[level_i].blkcount = EXT2_NINDIR(fs);
2989f8e6353SEvgeniy Ivanov 			continue;
2999f8e6353SEvgeniy Ivanov 		}
3009f8e6353SEvgeniy Ivanov 
3019f8e6353SEvgeniy Ivanov 		/* blk is the next direct level block. */
3029f8e6353SEvgeniy Ivanov #if 0
3039f8e6353SEvgeniy Ivanov 		fprintf(stderr, "ino %lu db %lu blksize %lu\n", ino,
304*84d9c625SLionel Sambuc 		    EXT2_FSBTODB(fs, blk), ext2_sblksize(fs, inode->di_size, lblk));
3059f8e6353SEvgeniy Ivanov #endif
3069f8e6353SEvgeniy Ivanov 		rv = (*callback)(params, state,
307*84d9c625SLionel Sambuc 		    EXT2_FSBTODB(fs, blk) + params->fstype->offset, fs->e2fs_bsize);
3089f8e6353SEvgeniy Ivanov 		lblk++;
3099f8e6353SEvgeniy Ivanov 		nblk--;
3109f8e6353SEvgeniy Ivanov 		if (rv != 1)
3119f8e6353SEvgeniy Ivanov 			return rv;
3129f8e6353SEvgeniy Ivanov 	}
3139f8e6353SEvgeniy Ivanov 
3149f8e6353SEvgeniy Ivanov 	if (nblk != 0) {
3159f8e6353SEvgeniy Ivanov 		warnx("Inode %llu in `%s' ran out of blocks?",
3169f8e6353SEvgeniy Ivanov 		    (unsigned long long)ino, params->filesystem);
3179f8e6353SEvgeniy Ivanov 		return 0;
3189f8e6353SEvgeniy Ivanov 	}
3199f8e6353SEvgeniy Ivanov 
3209f8e6353SEvgeniy Ivanov 	return 1;
3219f8e6353SEvgeniy Ivanov }
3229f8e6353SEvgeniy Ivanov 
3239f8e6353SEvgeniy Ivanov /*
3249f8e6353SEvgeniy Ivanov  * This callback reads a block of the root directory,
3259f8e6353SEvgeniy Ivanov  * searches for an entry for the secondary bootstrap,
3269f8e6353SEvgeniy Ivanov  * and saves the inode number if one is found.
3279f8e6353SEvgeniy Ivanov  */
3289f8e6353SEvgeniy Ivanov static int
ext2fs_findstage2_ino(ib_params * params,void * _ino,uint64_t blk,uint32_t blksize)3299f8e6353SEvgeniy Ivanov ext2fs_findstage2_ino(ib_params *params, void *_ino,
3309f8e6353SEvgeniy Ivanov 	uint64_t blk, uint32_t blksize)
3319f8e6353SEvgeniy Ivanov {
3329f8e6353SEvgeniy Ivanov 	uint8_t dirbuf[MAXBSIZE];
3339f8e6353SEvgeniy Ivanov 	struct ext2fs_direct *de, *ede;
3349f8e6353SEvgeniy Ivanov 	uint32_t ino;
3359f8e6353SEvgeniy Ivanov 
3369f8e6353SEvgeniy Ivanov 	assert(params != NULL);
3379f8e6353SEvgeniy Ivanov 	assert(params->fstype != NULL);
3389f8e6353SEvgeniy Ivanov 	assert(params->stage2 != NULL);
3399f8e6353SEvgeniy Ivanov 	assert(_ino != NULL);
3409f8e6353SEvgeniy Ivanov 
3419f8e6353SEvgeniy Ivanov 	/* Skip directory holes. */
3429f8e6353SEvgeniy Ivanov 	if (blk == 0)
3439f8e6353SEvgeniy Ivanov 		return 1;
3449f8e6353SEvgeniy Ivanov 
3459f8e6353SEvgeniy Ivanov 	/* Read the directory block. */
3469f8e6353SEvgeniy Ivanov 	if (ext2fs_read_disk_block(params, blk, blksize, dirbuf) == 0)
3479f8e6353SEvgeniy Ivanov 		return 0;
3489f8e6353SEvgeniy Ivanov 
3499f8e6353SEvgeniy Ivanov 	/* Loop over the directory entries. */
3509f8e6353SEvgeniy Ivanov 	de = (struct ext2fs_direct *)&dirbuf[0];
3519f8e6353SEvgeniy Ivanov 	ede = (struct ext2fs_direct *)&dirbuf[blksize];
3529f8e6353SEvgeniy Ivanov 	while (de < ede) {
3539f8e6353SEvgeniy Ivanov 		ino = fs2h32(de->e2d_ino);
3549f8e6353SEvgeniy Ivanov 		if (ino != 0 && strcmp(de->e2d_name, params->stage2) == 0) {
3559f8e6353SEvgeniy Ivanov 			*((uint32_t *)_ino) = ino;
3569f8e6353SEvgeniy Ivanov 			return (2);
3579f8e6353SEvgeniy Ivanov 		}
3589f8e6353SEvgeniy Ivanov 		if (fs2h16(de->e2d_reclen) == 0)
3599f8e6353SEvgeniy Ivanov 			break;
3609f8e6353SEvgeniy Ivanov 		de = (struct ext2fs_direct *)((char *)de +
3619f8e6353SEvgeniy Ivanov 		    fs2h16(de->e2d_reclen));
3629f8e6353SEvgeniy Ivanov 	}
3639f8e6353SEvgeniy Ivanov 
3649f8e6353SEvgeniy Ivanov 	return 1;
3659f8e6353SEvgeniy Ivanov }
3669f8e6353SEvgeniy Ivanov 
3679f8e6353SEvgeniy Ivanov struct findblks_state {
3689f8e6353SEvgeniy Ivanov 	uint32_t	maxblk;
3699f8e6353SEvgeniy Ivanov 	uint32_t	nblk;
3709f8e6353SEvgeniy Ivanov 	ib_block	*blocks;
3719f8e6353SEvgeniy Ivanov };
3729f8e6353SEvgeniy Ivanov 
3739f8e6353SEvgeniy Ivanov /* This callback records the blocks of the secondary bootstrap. */
3749f8e6353SEvgeniy Ivanov static int
ext2fs_findstage2_blocks(ib_params * params,void * _state,uint64_t blk,uint32_t blksize)3759f8e6353SEvgeniy Ivanov ext2fs_findstage2_blocks(ib_params *params, void *_state,
3769f8e6353SEvgeniy Ivanov 	uint64_t blk, uint32_t blksize)
3779f8e6353SEvgeniy Ivanov {
3789f8e6353SEvgeniy Ivanov 	struct findblks_state *state = _state;
3799f8e6353SEvgeniy Ivanov 
3809f8e6353SEvgeniy Ivanov 	assert(params != NULL);
3819f8e6353SEvgeniy Ivanov 	assert(params->stage2 != NULL);
3829f8e6353SEvgeniy Ivanov 	assert(_state != NULL);
3839f8e6353SEvgeniy Ivanov 
3849f8e6353SEvgeniy Ivanov 	if (state->nblk == state->maxblk) {
3859f8e6353SEvgeniy Ivanov 		warnx("Secondary bootstrap `%s' has too many blocks (max %d)",
3869f8e6353SEvgeniy Ivanov 		    params->stage2, state->maxblk);
3879f8e6353SEvgeniy Ivanov 		return (0);
3889f8e6353SEvgeniy Ivanov 	}
3899f8e6353SEvgeniy Ivanov 	state->blocks[state->nblk].block = blk;
3909f8e6353SEvgeniy Ivanov 	state->blocks[state->nblk].blocksize = blksize;
3919f8e6353SEvgeniy Ivanov 	state->nblk++;
3929f8e6353SEvgeniy Ivanov 	return 1;
3939f8e6353SEvgeniy Ivanov }
3949f8e6353SEvgeniy Ivanov 
3959f8e6353SEvgeniy Ivanov /*
3969f8e6353SEvgeniy Ivanov  *	publicly visible functions
3979f8e6353SEvgeniy Ivanov  */
3989f8e6353SEvgeniy Ivanov 
3999f8e6353SEvgeniy Ivanov int
ext2fs_match(ib_params * params)4009f8e6353SEvgeniy Ivanov ext2fs_match(ib_params *params)
4019f8e6353SEvgeniy Ivanov {
4029f8e6353SEvgeniy Ivanov 	uint8_t sbbuf[sizeof(struct m_ext2fs)];
4039f8e6353SEvgeniy Ivanov 	struct m_ext2fs *fs;
4049f8e6353SEvgeniy Ivanov 
4059f8e6353SEvgeniy Ivanov 	assert(params != NULL);
4069f8e6353SEvgeniy Ivanov 	assert(params->fstype != NULL);
4079f8e6353SEvgeniy Ivanov 
4089f8e6353SEvgeniy Ivanov 	/* Read the superblock. */
4099f8e6353SEvgeniy Ivanov 	fs = (void *)sbbuf;
4109f8e6353SEvgeniy Ivanov 	if (ext2fs_read_sblock(params, fs) == 0)
4119f8e6353SEvgeniy Ivanov 		return 0;
4129f8e6353SEvgeniy Ivanov 
4139f8e6353SEvgeniy Ivanov 	params->fstype->needswap = 0;
4149f8e6353SEvgeniy Ivanov 	params->fstype->blocksize = fs->e2fs_bsize;
4159f8e6353SEvgeniy Ivanov 	params->fstype->offset = 0;
4169f8e6353SEvgeniy Ivanov 
4179f8e6353SEvgeniy Ivanov 	return 1;
4189f8e6353SEvgeniy Ivanov }
4199f8e6353SEvgeniy Ivanov 
4209f8e6353SEvgeniy Ivanov int
ext2fs_findstage2(ib_params * params,uint32_t * maxblk,ib_block * blocks)4219f8e6353SEvgeniy Ivanov ext2fs_findstage2(ib_params *params, uint32_t *maxblk, ib_block *blocks)
4229f8e6353SEvgeniy Ivanov {
4239f8e6353SEvgeniy Ivanov 	int rv;
4249f8e6353SEvgeniy Ivanov 	uint32_t ino;
4259f8e6353SEvgeniy Ivanov 	struct findblks_state state;
4269f8e6353SEvgeniy Ivanov 
4279f8e6353SEvgeniy Ivanov 	assert(params != NULL);
4289f8e6353SEvgeniy Ivanov 	assert(params->stage2 != NULL);
4299f8e6353SEvgeniy Ivanov 	assert(maxblk != NULL);
4309f8e6353SEvgeniy Ivanov 	assert(blocks != NULL);
4319f8e6353SEvgeniy Ivanov 
4329f8e6353SEvgeniy Ivanov 	if (params->flags & IB_STAGE2START)
4339f8e6353SEvgeniy Ivanov 		return hardcode_stage2(params, maxblk, blocks);
4349f8e6353SEvgeniy Ivanov 
4359f8e6353SEvgeniy Ivanov 	/* The secondary bootstrap must be clearly in /. */
4369f8e6353SEvgeniy Ivanov 	if (params->stage2[0] == '/')
4379f8e6353SEvgeniy Ivanov 		params->stage2++;
4389f8e6353SEvgeniy Ivanov 	if (strchr(params->stage2, '/') != NULL) {
4399f8e6353SEvgeniy Ivanov 		warnx("The secondary bootstrap `%s' must be in /",
4409f8e6353SEvgeniy Ivanov 		    params->stage2);
4419f8e6353SEvgeniy Ivanov 		warnx("(Path must be relative to the file system in `%s')",
4429f8e6353SEvgeniy Ivanov 		    params->filesystem);
4439f8e6353SEvgeniy Ivanov 		return 0;
4449f8e6353SEvgeniy Ivanov 	}
4459f8e6353SEvgeniy Ivanov 
4469f8e6353SEvgeniy Ivanov 	/* Get the inode number of the secondary bootstrap. */
4479f8e6353SEvgeniy Ivanov 	rv = ext2fs_find_disk_blocks(params, EXT2_ROOTINO,
4489f8e6353SEvgeniy Ivanov 	    ext2fs_findstage2_ino, &ino);
4499f8e6353SEvgeniy Ivanov 	if (rv != 2) {
4509f8e6353SEvgeniy Ivanov 		warnx("Could not find secondary bootstrap `%s' in `%s'",
4519f8e6353SEvgeniy Ivanov 		    params->stage2, params->filesystem);
4529f8e6353SEvgeniy Ivanov 		warnx("(Path must be relative to the file system in `%s')",
4539f8e6353SEvgeniy Ivanov 		    params->filesystem);
4549f8e6353SEvgeniy Ivanov 		return 0;
4559f8e6353SEvgeniy Ivanov 	}
4569f8e6353SEvgeniy Ivanov 
4579f8e6353SEvgeniy Ivanov 	/* Record the disk blocks of the secondary bootstrap. */
4589f8e6353SEvgeniy Ivanov 	state.maxblk = *maxblk;
4599f8e6353SEvgeniy Ivanov 	state.nblk = 0;
4609f8e6353SEvgeniy Ivanov 	state.blocks = blocks;
4619f8e6353SEvgeniy Ivanov 		rv = ext2fs_find_disk_blocks(params, ino,
4629f8e6353SEvgeniy Ivanov 		    ext2fs_findstage2_blocks, &state);
4639f8e6353SEvgeniy Ivanov 	if (rv == 0)
4649f8e6353SEvgeniy Ivanov 		return 0;
4659f8e6353SEvgeniy Ivanov 
4669f8e6353SEvgeniy Ivanov 	*maxblk = state.nblk;
4679f8e6353SEvgeniy Ivanov 	return 1;
4689f8e6353SEvgeniy Ivanov }
469