From 1ad54a940c499a66241f624882f1ffa03ce56d90 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Wed, 28 Jul 2004 21:11:48 -0400 Subject: [PATCH] Add ability for debugfs to use a separate source of data blocks when reading from an e2image file. (New -d option) Add new functions ext2fs_get_data_io, ext2fs_set_data_io, ext2fs_rewrite_to_io to libext2fs library. --- debugfs/ChangeLog | 6 ++++++ debugfs/debugfs.8.in | 31 +++++++++++++++++------------- debugfs/debugfs.c | 49 +++++++++++++++++++++++++++++++++++++++++------ lib/ext2fs/ChangeLog | 23 ++++++++++++++++++++++ lib/ext2fs/block.c | 9 ++++++--- lib/ext2fs/ext2_err.et.in | 3 +++ lib/ext2fs/ext2fs.h | 4 ++++ lib/ext2fs/freefs.c | 3 +++ lib/ext2fs/initialize.c | 1 + lib/ext2fs/inode.c | 7 +++++-- lib/ext2fs/openfs.c | 34 ++++++++++++++++++++++++++++++++ lib/ext2fs/rw_bitmaps.c | 4 ++-- 12 files changed, 148 insertions(+), 26 deletions(-) diff --git a/debugfs/ChangeLog b/debugfs/ChangeLog index 4c96929..34e16c1 100644 --- a/debugfs/ChangeLog +++ b/debugfs/ChangeLog @@ -1,3 +1,9 @@ +2004-07-28 Theodore Ts'o + + * debugfs.c, debugfs.8.in: Add new option -d which allows the + system administrator to specify data source of a + filesystem being opened via an e2image file. + 2004-04-11 Theodore Ts'o * util.c (open_pager): Use DEBUGFS_PAGER in preference to PAGER diff --git a/debugfs/debugfs.8.in b/debugfs/debugfs.8.in index d39bae9..9bb3354 100644 --- a/debugfs/debugfs.8.in +++ b/debugfs/debugfs.8.in @@ -8,6 +8,9 @@ debugfs \- ext2/ext3 file system debugger .SH SYNOPSIS .B debugfs [ +.B \-Vwci +] +[ .B \-b blocksize ] @@ -24,22 +27,12 @@ cmd_file request ] [ -.B \-V -] -[ -[ -.B \-w -] -[ -.B \-c -] -[ -.B \-i +.B \-d +data_source_device ] [ device ] -] .SH DESCRIPTION The .B debugfs @@ -76,10 +69,22 @@ no safety checks are in place, and .B debugfs may fail in interesting ways if commands such as .IR ls ", " dump ", " -etc. are tried. +etc. are tried without specifying the +.I data_source_device +using the +.I \-d +option. .B debugfs is a debugging tool. It has rough edges! .TP +.I -d data_source_device +Used with the +.I \-i +option, specifies that +.I data_source_device +should be used when reading blocks not found in the ext2 image file. +This includes data, directory, and indirect blocks. +.TP .I -b blocksize Forces the use of the given block size for the file system, rather than detecting the correct block size as normal. diff --git a/debugfs/debugfs.c b/debugfs/debugfs.c index e16ac84..89b9d6c 100644 --- a/debugfs/debugfs.c +++ b/debugfs/debugfs.c @@ -41,9 +41,11 @@ ext2_filsys current_fs = NULL; ext2_ino_t root, cwd; static void open_filesystem(char *device, int open_flags, blk_t superblock, - blk_t blocksize, int catastrophic) + blk_t blocksize, int catastrophic, + char *data_filename) { int retval; + io_channel data_io = 0; if (superblock != 0 && blocksize == 0) { com_err(device, 0, "if you specify the superblock, you must also specify the block size"); @@ -51,6 +53,21 @@ static void open_filesystem(char *device, int open_flags, blk_t superblock, return; } + if (data_filename) { + if ((open_flags & EXT2_FLAG_IMAGE_FILE) == 0) { + com_err(device, 0, + "The -d option is only valid when reading an e2image file"); + current_fs = NULL; + return; + } + retval = unix_io_manager->open(data_filename, 0, &data_io); + if (retval) { + com_err(data_filename, 0, "while opening data source"); + current_fs = NULL; + return; + } + } + if (catastrophic && (open_flags & EXT2_FLAG_RW)) { com_err(device, 0, "opening read-only because of catastrophic mode"); @@ -79,6 +96,16 @@ static void open_filesystem(char *device, int open_flags, blk_t superblock, goto errout; } } + + if (data_io) { + retval = ext2fs_set_data_io(current_fs, data_io); + if (retval) { + com_err(device, retval, + "while setting data source"); + goto errout; + } + } + root = cwd = EXT2_ROOT_INO; return; @@ -96,10 +123,11 @@ void do_open_filesys(int argc, char **argv) int catastrophic = 0; blk_t superblock = 0; blk_t blocksize = 0; - int open_flags = 0; + int open_flags = 0; + char *data_filename; reset_getopt(); - while ((c = getopt (argc, argv, "iwfcb:s:")) != EOF) { + while ((c = getopt (argc, argv, "iwfcb:s:d:")) != EOF) { switch (c) { case 'i': open_flags |= EXT2_FLAG_IMAGE_FILE; @@ -113,6 +141,9 @@ void do_open_filesys(int argc, char **argv) case 'c': catastrophic = 1; break; + case 'd': + data_filename = optarg; + break; case 'b': blocksize = parse_ulong(optarg, argv[0], "block size", &err); @@ -137,7 +168,8 @@ void do_open_filesys(int argc, char **argv) if (check_fs_not_open(argv[0])) return; open_filesystem(argv[optind], open_flags, - superblock, blocksize, catastrophic); + superblock, blocksize, catastrophic, + data_filename); } void do_lcd(int argc, char **argv) @@ -1631,12 +1663,13 @@ int main(int argc, char **argv) blk_t superblock = 0; blk_t blocksize = 0; int catastrophic = 0; + char *data_filename = 0; initialize_ext2_error_table(); fprintf (stderr, "debugfs %s (%s)\n", E2FSPROGS_VERSION, E2FSPROGS_DATE); - while ((c = getopt (argc, argv, "iwcR:f:b:s:V")) != EOF) { + while ((c = getopt (argc, argv, "iwcR:f:b:s:Vd:")) != EOF) { switch (c) { case 'R': request = optarg; @@ -1644,6 +1677,9 @@ int main(int argc, char **argv) case 'f': cmd_file = optarg; break; + case 'd': + data_filename = optarg; + break; case 'i': open_flags |= EXT2_FLAG_IMAGE_FILE; break; @@ -1673,7 +1709,8 @@ int main(int argc, char **argv) } if (optind < argc) open_filesystem(argv[optind], open_flags, - superblock, blocksize, catastrophic); + superblock, blocksize, catastrophic, + data_filename); sci_idx = ss_create_invocation("debugfs", "0.0", (char *) NULL, &debug_cmds, &retval); diff --git a/lib/ext2fs/ChangeLog b/lib/ext2fs/ChangeLog index 751aa9d..9bbf393 100644 --- a/lib/ext2fs/ChangeLog +++ b/lib/ext2fs/ChangeLog @@ -1,3 +1,26 @@ +2004-07-28 Theodore Ts'o + + * rw_bitmaps.c (read_bitmaps), block.c (block_iterate_ind, + block_iterate_dind, block_iterate_tind), inode.c + (ext2fs_read_inode): If EXT2_FLAG_IMAGE_FILE is set, so + read the metadata from fs->image_io instead of fs->io. + + * initialize.c (ext2fs_initialize), openfs.c (ext2fs_open): + Initialize fs->image_io to be the same as fs->io. + + * ext2_err.et.in (EXT2_ET_NOT_IMAGE_FILE): Add new error code. + + * openfs.c (ext2fs_get_data_io, ext2fs_set_data_io, + ext2fs_rewrite_to_io): New functions that allow + applications to manipulate fs->image_io and fs->io safely. + + * freefs.c (ext2fs_free): If fs->image_io is different fs->io, + then call io_channel_close on fs->image_io. + + * ext2fs.h: Add image_io element to the ext2_filsys data + structure. Add ext2fs_get_data_io() ext2fs_set_data_io(), + and ext2fs_rewrite_to_io() prototypes. + 2004-05-26 Theodore Ts'o * closefs.c (ext2fs_flush): Make sure the master superblock is diff --git a/lib/ext2fs/block.c b/lib/ext2fs/block.c index f64c0af..88ce286 100644 --- a/lib/ext2fs/block.c +++ b/lib/ext2fs/block.c @@ -59,7 +59,8 @@ static int block_iterate_ind(blk_t *ind_block, blk_t ref_block, ret |= BLOCK_ERROR; return ret; } - if (ctx->fs->flags & EXT2_FLAG_IMAGE_FILE) { + if ((ctx->fs->flags & EXT2_FLAG_IMAGE_FILE) && + (ctx->fs->io != ctx->fs->image_io)) { ctx->errcode = 0; memset(ctx->ind_buf, 0, ctx->fs->blocksize); } else @@ -153,7 +154,8 @@ static int block_iterate_dind(blk_t *dind_block, blk_t ref_block, ret |= BLOCK_ERROR; return ret; } - if (ctx->fs->flags & EXT2_FLAG_IMAGE_FILE) { + if ((ctx->fs->flags & EXT2_FLAG_IMAGE_FILE) && + (ctx->fs->io != ctx->fs->image_io)) { ctx->errcode = 0; memset(ctx->dind_buf, 0, ctx->fs->blocksize); } else @@ -249,7 +251,8 @@ static int block_iterate_tind(blk_t *tind_block, blk_t ref_block, ret |= BLOCK_ERROR; return ret; } - if (ctx->fs->flags & EXT2_FLAG_IMAGE_FILE) { + if ((ctx->fs->flags & EXT2_FLAG_IMAGE_FILE) && + (ctx->fs->io != ctx->fs->image_io)) { ctx->errcode = 0; memset(ctx->tind_buf, 0, ctx->fs->blocksize); } else diff --git a/lib/ext2fs/ext2_err.et.in b/lib/ext2fs/ext2_err.et.in index b9ad5f0..b3ada29 100644 --- a/lib/ext2fs/ext2_err.et.in +++ b/lib/ext2fs/ext2_err.et.in @@ -284,5 +284,8 @@ ec EXT2_ET_BAD_EA_BLOCK_NUM, ec EXT2_ET_TOO_MANY_INODES, "Cannot create filesystem with requested number of inodes" +ec EXT2_ET_NOT_IMAGE_FILE, + "E2image snapshot not in use" + end diff --git a/lib/ext2fs/ext2fs.h b/lib/ext2fs/ext2fs.h index 2536c92..19be9c5 100644 --- a/lib/ext2fs/ext2fs.h +++ b/lib/ext2fs/ext2fs.h @@ -242,6 +242,7 @@ struct struct_ext2_filsys { * Inode cache */ struct ext2_inode_cache *icache; + io_channel image_io; }; #if EXT2_FLAT_INCLUDES @@ -852,6 +853,9 @@ extern errcode_t ext2fs_open(const char *name, int flags, int superblock, ext2_filsys *ret_fs); extern blk_t ext2fs_descriptor_block_loc(ext2_filsys fs, blk_t group_block, dgrp_t i); +errcode_t ext2fs_get_data_io(ext2_filsys fs, io_channel *old_io); +errcode_t ext2fs_set_data_io(ext2_filsys fs, io_channel new_io); +errcode_t ext2fs_rewrite_to_io(ext2_filsys fs, io_channel new_io); /* get_pathname.c */ extern errcode_t ext2fs_get_pathname(ext2_filsys fs, ext2_ino_t dir, ext2_ino_t ino, diff --git a/lib/ext2fs/freefs.c b/lib/ext2fs/freefs.c index 78c64bf..9dda403 100644 --- a/lib/ext2fs/freefs.c +++ b/lib/ext2fs/freefs.c @@ -23,6 +23,9 @@ void ext2fs_free(ext2_filsys fs) { if (!fs || (fs->magic != EXT2_ET_MAGIC_EXT2FS_FILSYS)) return; + if (fs->image_io != fs->io) { + io_channel_close(fs->image_io); + } if (fs->io) { io_channel_close(fs->io); } diff --git a/lib/ext2fs/initialize.c b/lib/ext2fs/initialize.c index 74f20a7..2ee06b5 100644 --- a/lib/ext2fs/initialize.c +++ b/lib/ext2fs/initialize.c @@ -91,6 +91,7 @@ errcode_t ext2fs_initialize(const char *name, int flags, retval = manager->open(name, IO_FLAG_RW, &fs->io); if (retval) goto cleanup; + fs->image_io = fs->io; fs->io->app_data = fs; retval = ext2fs_get_mem(strlen(name)+1, &fs->device_name); if (retval) diff --git a/lib/ext2fs/inode.c b/lib/ext2fs/inode.c index 50420b7..a1179d2 100644 --- a/lib/ext2fs/inode.c +++ b/lib/ext2fs/inode.c @@ -485,6 +485,7 @@ errcode_t ext2fs_read_inode (ext2_filsys fs, ext2_ino_t ino, errcode_t retval; int clen, i, inodes_per_block; unsigned int length; + io_channel io; EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); @@ -515,6 +516,7 @@ errcode_t ext2fs_read_inode (ext2_filsys fs, ext2_ino_t ino, block_nr += (ino - 1) / inodes_per_block; offset = ((ino - 1) % inodes_per_block) * EXT2_INODE_SIZE(fs->super); + io = fs->image_io; } else { group = (ino - 1) / EXT2_INODES_PER_GROUP(fs->super); offset = ((ino - 1) % EXT2_INODES_PER_GROUP(fs->super)) * @@ -524,9 +526,10 @@ errcode_t ext2fs_read_inode (ext2_filsys fs, ext2_ino_t ino, return EXT2_ET_MISSING_INODE_TABLE; block_nr = fs->group_desc[(unsigned)group].bg_inode_table + block; + io = fs->io; } if (block_nr != fs->icache->buffer_blk) { - retval = io_channel_read_blk(fs->io, block_nr, 1, + retval = io_channel_read_blk(io, block_nr, 1, fs->icache->buffer); if (retval) return retval; @@ -545,7 +548,7 @@ errcode_t ext2fs_read_inode (ext2_filsys fs, ext2_ino_t ino, memcpy((char *) inode, ptr, clen); length -= clen; - retval = io_channel_read_blk(fs->io, block_nr+1, 1, + retval = io_channel_read_blk(io, block_nr+1, 1, fs->icache->buffer); if (retval) { fs->icache->buffer_blk = 0; diff --git a/lib/ext2fs/openfs.c b/lib/ext2fs/openfs.c index bc7c5bb..dac8a38 100644 --- a/lib/ext2fs/openfs.c +++ b/lib/ext2fs/openfs.c @@ -96,6 +96,7 @@ errcode_t ext2fs_open(const char *name, int flags, int superblock, &fs->io); if (retval) goto cleanup; + fs->image_io = fs->io; fs->io->app_data = fs; retval = ext2fs_get_mem(strlen(name)+1, &fs->device_name); if (retval) @@ -271,3 +272,36 @@ cleanup: return retval; } +/* + * Set/get the filesystem data I/O channel. + * + * These functions are only valid if EXT2_FLAG_IMAGE_FILE is true. + */ +errcode_t ext2fs_get_data_io(ext2_filsys fs, io_channel *old_io) +{ + if ((fs->flags & EXT2_FLAG_IMAGE_FILE) == 0) + return EXT2_ET_NOT_IMAGE_FILE; + if (old_io) { + *old_io = (fs->image_io == fs->io) ? 0 : fs->io; + } + return 0; +} + +errcode_t ext2fs_set_data_io(ext2_filsys fs, io_channel new_io) +{ + if ((fs->flags & EXT2_FLAG_IMAGE_FILE) == 0) + return EXT2_ET_NOT_IMAGE_FILE; + fs->io = new_io ? new_io : fs->image_io; + return 0; +} + +errcode_t ext2fs_rewrite_to_io(ext2_filsys fs, io_channel new_io) +{ + if ((fs->flags & EXT2_FLAG_IMAGE_FILE) == 0) + return EXT2_ET_NOT_IMAGE_FILE; + fs->io = fs->image_io = new_io; + fs->flags |= EXT2_FLAG_DIRTY | EXT2_FLAG_RW | + EXT2_FLAG_BB_DIRTY | EXT2_FLAG_IB_DIRTY; + fs->flags &= ~EXT2_FLAG_IMAGE_FILE; + return 0; +} diff --git a/lib/ext2fs/rw_bitmaps.c b/lib/ext2fs/rw_bitmaps.c index ff3dd59..b67a925 100644 --- a/lib/ext2fs/rw_bitmaps.c +++ b/lib/ext2fs/rw_bitmaps.c @@ -186,7 +186,7 @@ static errcode_t read_bitmaps(ext2_filsys fs, int do_inode, int do_block) if (inode_bitmap) { blk = (fs->image_header->offset_inodemap / fs->blocksize); - retval = io_channel_read_blk(fs->io, blk, + retval = io_channel_read_blk(fs->image_io, blk, -(inode_nbytes * fs->group_desc_count), inode_bitmap); if (retval) @@ -195,7 +195,7 @@ static errcode_t read_bitmaps(ext2_filsys fs, int do_inode, int do_block) if (block_bitmap) { blk = (fs->image_header->offset_blockmap / fs->blocksize); - retval = io_channel_read_blk(fs->io, blk, + retval = io_channel_read_blk(fs->image_io, blk, -(block_nbytes * fs->group_desc_count), block_bitmap); if (retval) -- 1.8.3.1