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