X-Git-Url: https://git.whamcloud.com/?a=blobdiff_plain;f=debugfs%2Fdebugfs.c;h=be95e2093502c33b7b2dd219bd7f700cc825948f;hb=2291fbb0358be8251df0d611913f49fbb9beb740;hp=dab49d4809fa894e2150e1bd0bcb6a234e6dcd7e;hpb=9c92d848a8125c554b469440fbe72bb0ad740456;p=tools%2Fe2fsprogs.git diff --git a/debugfs/debugfs.c b/debugfs/debugfs.c index dab49d4..be95e20 100644 --- a/debugfs/debugfs.c +++ b/debugfs/debugfs.c @@ -4,7 +4,7 @@ * * Copyright (C) 1993 Theodore Ts'o. This file may be redistributed * under the terms of the GNU Public License. - * + * * Modifications by Robert Sanders */ @@ -16,7 +16,7 @@ #include #ifdef HAVE_GETOPT_H #include -#else +#else extern int optind; extern char *optarg; #endif @@ -33,15 +33,20 @@ extern char *optarg; #include "uuid/uuid.h" #include "e2p/e2p.h" +#include + #include "../version.h" +#include "jfs_user.h" extern ss_request_table debug_cmds; +ss_request_table *extra_cmds; +const char *debug_prog_name; 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; @@ -55,7 +60,7 @@ static void open_filesystem(char *device, int open_flags, blk_t superblock, if (data_filename) { if ((open_flags & EXT2_FLAG_IMAGE_FILE) == 0) { - com_err(device, 0, + com_err(device, 0, "The -d option is only valid when reading an e2image file"); current_fs = NULL; return; @@ -73,7 +78,7 @@ static void open_filesystem(char *device, int open_flags, blk_t superblock, "opening read-only because of catastrophic mode"); open_flags &= ~EXT2_FLAG_RW; } - + retval = ext2fs_open(device, open_flags, superblock, blocksize, unix_io_manager, ¤t_fs); if (retval) { @@ -100,7 +105,7 @@ static void open_filesystem(char *device, int open_flags, blk_t superblock, if (data_io) { retval = ext2fs_set_data_io(current_fs, data_io); if (retval) { - com_err(device, retval, + com_err(device, retval, "while setting data source"); goto errout; } @@ -118,16 +123,15 @@ errout: void do_open_filesys(int argc, char **argv) { - const char *usage = "Usage: open [-s superblock] [-b blocksize] [-c] [-w] "; int c, err; int catastrophic = 0; blk_t superblock = 0; blk_t blocksize = 0; - int open_flags = 0; - char *data_filename; - + int open_flags = EXT2_FLAG_SOFTSUPP_FEATURES; + char *data_filename = 0; + reset_getopt(); - while ((c = getopt (argc, argv, "iwfcb:s:d:")) != EOF) { + while ((c = getopt (argc, argv, "iwfecb:s:d:")) != EOF) { switch (c) { case 'i': open_flags |= EXT2_FLAG_IMAGE_FILE; @@ -138,6 +142,9 @@ void do_open_filesys(int argc, char **argv) case 'f': open_flags |= EXT2_FLAG_FORCE; break; + case 'e': + open_flags |= EXT2_FLAG_EXCLUSIVE; + break; case 'c': catastrophic = 1; break; @@ -157,26 +164,30 @@ void do_open_filesys(int argc, char **argv) return; break; default: - com_err(argv[0], 0, usage); - return; + goto print_usage; } } if (optind != argc-1) { - com_err(argv[0], 0, usage); - return; + goto print_usage; } if (check_fs_not_open(argv[0])) return; open_filesystem(argv[optind], open_flags, - superblock, blocksize, catastrophic, + superblock, blocksize, catastrophic, data_filename); + return; + +print_usage: + fprintf(stderr, "%s: Usage: open [-s superblock] [-b blocksize] " + "[-c] [-w] \n", argv[0]); } void do_lcd(int argc, char **argv) { - if (common_args_process(argc, argv, 2, 2, "lcd", - "", 0)) + if (argc != 2) { + com_err(argv[0], 0, "Usage: %s %s", argv[0], ""); return; + } if (chdir(argv[1]) == -1) { com_err(argv[0], errno, @@ -189,28 +200,48 @@ void do_lcd(int argc, char **argv) static void close_filesystem(NOARGS) { int retval; - + if (current_fs->flags & EXT2_FLAG_IB_DIRTY) { retval = ext2fs_write_inode_bitmap(current_fs); if (retval) - com_err("ext2fs_write_inode_bitmap", retval, ""); + com_err("ext2fs_write_inode_bitmap", retval, 0); } if (current_fs->flags & EXT2_FLAG_BB_DIRTY) { retval = ext2fs_write_block_bitmap(current_fs); if (retval) - com_err("ext2fs_write_block_bitmap", retval, ""); + com_err("ext2fs_write_block_bitmap", retval, 0); } retval = ext2fs_close(current_fs); if (retval) - com_err("ext2fs_close", retval, ""); + com_err("ext2fs_close", retval, 0); current_fs = NULL; return; } void do_close_filesys(int argc, char **argv) { - if (common_args_process(argc, argv, 1, 1, "close_filesys", "", 0)) + int c; + + if (check_fs_open(argv[0])) return; + + reset_getopt(); + while ((c = getopt (argc, argv, "a")) != EOF) { + switch (c) { + case 'a': + current_fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY; + break; + default: + goto print_usage; + } + } + + if (argc > optind) { + print_usage: + com_err(0, 0, "Usage: close_filesys [-a]"); + return; + } + close_filesystem(); } @@ -219,7 +250,7 @@ void do_init_filesys(int argc, char **argv) struct ext2_super_block param; errcode_t retval; int err; - + if (common_args_process(argc, argv, 3, 3, "initialize", " ", CHECK_FS_NOTOPEN)) return; @@ -259,14 +290,26 @@ static void print_features(struct ext2_super_block * s, FILE *f) fputs("\n", f); } +static void print_bg_opts(struct ext2_group_desc *gdp, int mask, + const char *str, int *first, FILE *f) +{ + if (gdp->bg_flags & mask) { + if (*first) { + fputs(" [", f); + *first = 0; + } else + fputs(", ", f); + fputs(str, f); + } +} + void do_show_super_stats(int argc, char *argv[]) { dgrp_t i; FILE *out; struct ext2_group_desc *gdp; int c, header_only = 0; - int numdirs = 0; - const char *usage = "Usage: show_super [-h]"; + int numdirs = 0, first, gdt_csum; reset_getopt(); while ((c = getopt (argc, argv, "h")) != EOF) { @@ -275,13 +318,11 @@ void do_show_super_stats(int argc, char *argv[]) header_only++; break; default: - com_err(argv[0], 0, usage); - return; + goto print_usage; } } if (optind != argc) { - com_err(argv[0], 0, usage); - return; + goto print_usage; } if (check_fs_open(argv[0])) return; @@ -291,20 +332,22 @@ void do_show_super_stats(int argc, char *argv[]) for (i=0; i < current_fs->group_desc_count; i++) numdirs += current_fs->group_desc[i].bg_used_dirs_count; fprintf(out, "Directories: %d\n", numdirs); - + if (header_only) { close_pager(out); return; } - + + gdt_csum = EXT2_HAS_RO_COMPAT_FEATURE(current_fs->super, + EXT4_FEATURE_RO_COMPAT_GDT_CSUM); gdp = ¤t_fs->group_desc[0]; - for (i = 0; i < current_fs->group_desc_count; i++, gdp++) - fprintf(out, " Group %2d: block bitmap at %d, " - "inode bitmap at %d, " - "inode table at %d\n" + for (i = 0; i < current_fs->group_desc_count; i++, gdp++) { + fprintf(out, " Group %2d: block bitmap at %u, " + "inode bitmap at %u, " + "inode table at %u\n" " %d free %s, " "%d free %s, " - "%d used %s\n", + "%d used %s%s", i, gdp->bg_block_bitmap, gdp->bg_inode_bitmap, gdp->bg_inode_table, gdp->bg_free_blocks_count, @@ -313,11 +356,31 @@ void do_show_super_stats(int argc, char *argv[]) gdp->bg_free_inodes_count != 1 ? "inodes" : "inode", gdp->bg_used_dirs_count, gdp->bg_used_dirs_count != 1 ? "directories" - : "directory"); + : "directory", gdt_csum ? ", " : "\n"); + if (gdt_csum) + fprintf(out, "%d unused %s\n", + gdp->bg_itable_unused, + gdp->bg_itable_unused != 1 ? "inodes":"inode"); + first = 1; + print_bg_opts(gdp, EXT2_BG_INODE_UNINIT, "Inode not init", + &first, out); + print_bg_opts(gdp, EXT2_BG_BLOCK_UNINIT, "Block not init", + &first, out); + if (gdt_csum) { + fprintf(out, "%sChecksum 0x%04x", + first ? " [":", ", gdp->bg_checksum); + first = 0; + } + if (!first) + fputs("]\n", out); + } close_pager(out); + return; +print_usage: + fprintf(stderr, "%s: Usage: show_super [-h]\n", argv[0]); } -void do_dirty_filesys(int argc EXT2FS_ATTR((unused)), +void do_dirty_filesys(int argc EXT2FS_ATTR((unused)), char **argv EXT2FS_ATTR((unused))) { if (check_fs_open(argv[0])) @@ -349,17 +412,19 @@ static void finish_range(struct list_blocks_struct *lb) else fprintf(lb->f, ", "); if (lb->first_block == lb->last_block) - fprintf(lb->f, "(%lld):%d", lb->first_bcnt, lb->first_block); + fprintf(lb->f, "(%lld):%u", + (long long)lb->first_bcnt, lb->first_block); else - fprintf(lb->f, "(%lld-%lld):%d-%d", lb->first_bcnt, - lb->last_bcnt, lb->first_block, lb->last_block); + fprintf(lb->f, "(%lld-%lld):%u-%u", + (long long)lb->first_bcnt, (long long)lb->last_bcnt, + lb->first_block, lb->last_block); lb->first_block = 0; } -static int list_blocks_proc(ext2_filsys fs EXT2FS_ATTR((unused)), - blk_t *blocknr, e2_blkcnt_t blockcnt, +static int list_blocks_proc(ext2_filsys fs EXT2FS_ATTR((unused)), + blk_t *blocknr, e2_blkcnt_t blockcnt, blk_t ref_block EXT2FS_ATTR((unused)), - int ref_offset EXT2FS_ATTR((unused)), + int ref_offset EXT2FS_ATTR((unused)), void *private) { struct list_blocks_struct *lb = (struct list_blocks_struct *) private; @@ -393,14 +458,81 @@ static int list_blocks_proc(ext2_filsys fs EXT2FS_ATTR((unused)), else fprintf(lb->f, ", "); if (blockcnt == -1) - fprintf(lb->f, "(IND):%d", *blocknr); + fprintf(lb->f, "(IND):%u", *blocknr); else if (blockcnt == -2) - fprintf(lb->f, "(DIND):%d", *blocknr); + fprintf(lb->f, "(DIND):%u", *blocknr); else if (blockcnt == -3) - fprintf(lb->f, "(TIND):%d", *blocknr); + fprintf(lb->f, "(TIND):%u", *blocknr); return 0; } +static void dump_xattr_string(FILE *out, const char *str, int len) +{ + int printable = 0; + int i; + + /* check: is string "printable enough?" */ + for (i = 0; i < len; i++) + if (isprint(str[i])) + printable++; + + if (printable <= len*7/8) + printable = 0; + + for (i = 0; i < len; i++) + if (printable) + fprintf(out, isprint(str[i]) ? "%c" : "\\%03o", + (unsigned char)str[i]); + else + fprintf(out, "%02x ", (unsigned char)str[i]); +} + +static void internal_dump_inode_extra(FILE *out, + const char *prefix EXT2FS_ATTR((unused)), + ext2_ino_t inode_num EXT2FS_ATTR((unused)), + struct ext2_inode_large *inode) +{ + struct ext2_ext_attr_entry *entry; + __u32 *magic; + char *start, *end; + unsigned int storage_size; + + fprintf(out, "Size of extra inode fields: %u\n", inode->i_extra_isize); + if (inode->i_extra_isize > EXT2_INODE_SIZE(current_fs->super) - + EXT2_GOOD_OLD_INODE_SIZE) { + fprintf(stderr, "invalid inode->i_extra_isize (%u)\n", + inode->i_extra_isize); + return; + } + storage_size = EXT2_INODE_SIZE(current_fs->super) - + EXT2_GOOD_OLD_INODE_SIZE - + inode->i_extra_isize; + magic = (__u32 *)((char *)inode + EXT2_GOOD_OLD_INODE_SIZE + + inode->i_extra_isize); + if (*magic == EXT2_EXT_ATTR_MAGIC) { + fprintf(out, "Extended attributes stored in inode body: \n"); + end = (char *) inode + EXT2_INODE_SIZE(current_fs->super); + start = (char *) magic + sizeof(__u32); + entry = (struct ext2_ext_attr_entry *) start; + while (!EXT2_EXT_IS_LAST_ENTRY(entry)) { + struct ext2_ext_attr_entry *next = + EXT2_EXT_ATTR_NEXT(entry); + if (entry->e_value_size > storage_size || + (char *) next >= end) { + fprintf(out, "invalid EA entry in inode\n"); + return; + } + fprintf(out, " "); + dump_xattr_string(out, EXT2_EXT_ATTR_NAME(entry), + entry->e_name_len); + fprintf(out, " = \""); + dump_xattr_string(out, start + entry->e_value_offs, + entry->e_value_size); + fprintf(out, "\" (%u)\n", entry->e_value_size); + entry = next; + } + } +} static void dump_blocks(FILE *f, const char *prefix, ext2_ino_t inode) { @@ -411,14 +543,147 @@ static void dump_blocks(FILE *f, const char *prefix, ext2_ino_t inode) lb.first_block = 0; lb.f = f; lb.first = 1; - ext2fs_block_iterate2(current_fs, inode, 0, NULL, + ext2fs_block_iterate2(current_fs, inode, BLOCK_FLAG_READ_ONLY, NULL, list_blocks_proc, (void *)&lb); finish_range(&lb); if (lb.total) - fprintf(f, "\n%sTOTAL: %lld\n", prefix, lb.total); + fprintf(f, "\n%sTOTAL: %lld\n", prefix, (long long)lb.total); fprintf(f,"\n"); } +static int int_log10(unsigned long long arg) +{ + int l = 0; + + arg = arg / 10; + while (arg) { + l++; + arg = arg / 10; + } + return l; +} + +#define DUMP_LEAF_EXTENTS 0x01 +#define DUMP_NODE_EXTENTS 0x02 +#define DUMP_EXTENT_TABLE 0x04 + +static void dump_extents(FILE *f, const char *prefix, ext2_ino_t ino, + int flags, int logical_width, int physical_width) +{ + ext2_extent_handle_t handle; + struct ext2fs_extent extent; + struct ext2_extent_info info; + int op = EXT2_EXTENT_ROOT; + unsigned int printed = 0; + errcode_t errcode; + + errcode = ext2fs_extent_open(current_fs, ino, &handle); + if (errcode) + return; + + if (flags & DUMP_EXTENT_TABLE) + fprintf(f, "Level Entries %*s %*s Length Flags\n", + (logical_width*2)+3, "Logical", + (physical_width*2)+3, "Physical"); + else + fprintf(f, "%sEXTENTS:\n%s", prefix, prefix); + + while (1) { + errcode = ext2fs_extent_get(handle, op, &extent); + + if (errcode) + break; + + op = EXT2_EXTENT_NEXT; + + if (extent.e_flags & EXT2_EXTENT_FLAGS_SECOND_VISIT) + continue; + + if (extent.e_flags & EXT2_EXTENT_FLAGS_LEAF) { + if ((flags & DUMP_LEAF_EXTENTS) == 0) + continue; + } else { + if ((flags & DUMP_NODE_EXTENTS) == 0) + continue; + } + + errcode = ext2fs_extent_get_info(handle, &info); + if (errcode) + continue; + + if (!(extent.e_flags & EXT2_EXTENT_FLAGS_LEAF)) { + if (extent.e_flags & EXT2_EXTENT_FLAGS_SECOND_VISIT) + continue; + + if (flags & DUMP_EXTENT_TABLE) { + fprintf(f, "%2d/%2d %3d/%3d %*llu - %*llu " + "%*llu%*s %6u\n", + info.curr_level, info.max_depth, + info.curr_entry, info.num_entries, + logical_width, + extent.e_lblk, + logical_width, + extent.e_lblk + (extent.e_len - 1), + physical_width, + extent.e_pblk, + physical_width+3, "", extent.e_len); + continue; + } + + fprintf(f, "%s(NODE #%d, %lld-%lld, blk %lld)", + printed ? ", " : "", + info.curr_entry, + extent.e_lblk, + extent.e_lblk + (extent.e_len - 1), + extent.e_pblk); + printed = 1; + continue; + } + + if (flags & DUMP_EXTENT_TABLE) { + fprintf(f, "%2d/%2d %3d/%3d %*llu - %*llu " + "%*llu - %*llu %6u %s\n", + info.curr_level, info.max_depth, + info.curr_entry, info.num_entries, + logical_width, + extent.e_lblk, + logical_width, + extent.e_lblk + (extent.e_len - 1), + physical_width, + extent.e_pblk, + physical_width, + extent.e_pblk + (extent.e_len - 1), + extent.e_len, + extent.e_flags & EXT2_EXTENT_FLAGS_UNINIT ? + "Uninit" : ""); + continue; + } + + if (extent.e_len == 0) + continue; + else if (extent.e_len == 1) + fprintf(f, + "%s(%lld%s): %lld", + printed ? ", " : "", + extent.e_lblk, + extent.e_flags & EXT2_EXTENT_FLAGS_UNINIT ? + " [uninit]" : "", + extent.e_pblk); + else + fprintf(f, + "%s(%lld-%lld%s): %lld-%lld", + printed ? ", " : "", + extent.e_lblk, + extent.e_lblk + (extent.e_len - 1), + extent.e_flags & EXT2_EXTENT_FLAGS_UNINIT ? + " [uninit]" : "", + extent.e_pblk, + extent.e_pblk + (extent.e_len - 1)); + printed = 1; + } + if (printed) + fprintf(f, "\n"); +} void internal_dump_inode(FILE *out, const char *prefix, ext2_ino_t inode_num, struct ext2_inode *inode, @@ -427,7 +692,13 @@ void internal_dump_inode(FILE *out, const char *prefix, const char *i_type; char frag, fsize; int os = current_fs->super->s_creator_os; - + struct ext2_inode_large *large_inode; + int is_large_inode = 0; + + if (EXT2_INODE_SIZE(current_fs->super) > EXT2_GOOD_OLD_INODE_SIZE) + is_large_inode = 1; + large_inode = (struct ext2_inode_large *) inode; + if (LINUX_S_ISDIR(inode->i_mode)) i_type = "directory"; else if (LINUX_S_ISREG(inode->i_mode)) i_type = "regular"; else if (LINUX_S_ISLNK(inode->i_mode)) i_type = "symlink"; @@ -437,57 +708,83 @@ void internal_dump_inode(FILE *out, const char *prefix, else if (LINUX_S_ISSOCK(inode->i_mode)) i_type = "socket"; else i_type = "bad type"; fprintf(out, "%sInode: %u Type: %s ", prefix, inode_num, i_type); - fprintf(out, "%sMode: %04o Flags: 0x%x Generation: %u\n", - prefix, - inode->i_mode & 0777, inode->i_flags, inode->i_generation); + fprintf(out, "%sMode: %04o Flags: 0x%x\n", + prefix, inode->i_mode & 0777, inode->i_flags); + if (is_large_inode && large_inode->i_extra_isize >= 24) { + fprintf(out, "%sGeneration: %u Version: 0x%08x:%08x\n", + prefix, inode->i_generation, large_inode->i_version_hi, + inode->osd1.linux1.l_i_version); + } else { + fprintf(out, "%sGeneration: %u Version: 0x%08x\n", prefix, + inode->i_generation, inode->osd1.linux1.l_i_version); + } fprintf(out, "%sUser: %5d Group: %5d Size: ", - prefix, inode->i_uid, inode->i_gid); + prefix, inode_uid(*inode), inode_gid(*inode)); if (LINUX_S_ISREG(inode->i_mode)) { - __u64 i_size = (inode->i_size | - ((unsigned long long)inode->i_size_high << 32)); + unsigned long long i_size = (inode->i_size | + ((unsigned long long)inode->i_size_high << 32)); - fprintf(out, "%lld\n", i_size); + fprintf(out, "%llu\n", i_size); } else fprintf(out, "%d\n", inode->i_size); - if (current_fs->super->s_creator_os == EXT2_OS_HURD) + if (os == EXT2_OS_HURD) fprintf(out, "%sFile ACL: %d Directory ACL: %d Translator: %d\n", prefix, inode->i_file_acl, LINUX_S_ISDIR(inode->i_mode) ? inode->i_dir_acl : 0, inode->osd1.hurd1.h_i_translator); else - fprintf(out, "%sFile ACL: %d Directory ACL: %d\n", + fprintf(out, "%sFile ACL: %llu Directory ACL: %d\n", prefix, - inode->i_file_acl, LINUX_S_ISDIR(inode->i_mode) ? inode->i_dir_acl : 0); - fprintf(out, "%sLinks: %d Blockcount: %d\n", - prefix, inode->i_links_count, inode->i_blocks); + inode->i_file_acl | ((long long) + (inode->osd2.linux2.l_i_file_acl_high) << 32), + LINUX_S_ISDIR(inode->i_mode) ? inode->i_dir_acl : 0); + if (os == EXT2_OS_LINUX) + fprintf(out, "%sLinks: %d Blockcount: %llu\n", + prefix, inode->i_links_count, + (((unsigned long long) + inode->osd2.linux2.l_i_blocks_hi << 32)) + + inode->i_blocks); + else + fprintf(out, "%sLinks: %d Blockcount: %u\n", + prefix, inode->i_links_count, inode->i_blocks); switch (os) { - case EXT2_OS_LINUX: - frag = inode->osd2.linux2.l_i_frag; - fsize = inode->osd2.linux2.l_i_fsize; - break; case EXT2_OS_HURD: frag = inode->osd2.hurd2.h_i_frag; fsize = inode->osd2.hurd2.h_i_fsize; break; - case EXT2_OS_MASIX: - frag = inode->osd2.masix2.m_i_frag; - fsize = inode->osd2.masix2.m_i_fsize; - break; default: frag = fsize = 0; } fprintf(out, "%sFragment: Address: %d Number: %d Size: %d\n", prefix, inode->i_faddr, frag, fsize); - fprintf(out, "%sctime: 0x%08x -- %s", prefix, inode->i_ctime, - time_to_string(inode->i_ctime)); - fprintf(out, "%satime: 0x%08x -- %s", prefix, inode->i_atime, - time_to_string(inode->i_atime)); - fprintf(out, "%smtime: 0x%08x -- %s", prefix, inode->i_mtime, - time_to_string(inode->i_mtime)); - if (inode->i_dtime) + if (is_large_inode && large_inode->i_extra_isize >= 24) { + fprintf(out, "%s ctime: 0x%08x:%08x -- %s", prefix, + inode->i_ctime, large_inode->i_ctime_extra, + time_to_string(inode->i_ctime)); + fprintf(out, "%s atime: 0x%08x:%08x -- %s", prefix, + inode->i_atime, large_inode->i_atime_extra, + time_to_string(inode->i_atime)); + fprintf(out, "%s mtime: 0x%08x:%08x -- %s", prefix, + inode->i_mtime, large_inode->i_mtime_extra, + time_to_string(inode->i_mtime)); + fprintf(out, "%scrtime: 0x%08x:%08x -- %s", prefix, + large_inode->i_crtime, large_inode->i_crtime_extra, + time_to_string(large_inode->i_crtime)); + } else { + fprintf(out, "%sctime: 0x%08x -- %s", prefix, inode->i_ctime, + time_to_string(inode->i_ctime)); + fprintf(out, "%satime: 0x%08x -- %s", prefix, inode->i_atime, + time_to_string(inode->i_atime)); + fprintf(out, "%smtime: 0x%08x -- %s", prefix, inode->i_mtime, + time_to_string(inode->i_mtime)); + } + if (inode->i_dtime) fprintf(out, "%sdtime: 0x%08x -- %s", prefix, inode->i_dtime, time_to_string(inode->i_dtime)); + if (EXT2_INODE_SIZE(current_fs->super) > EXT2_GOOD_OLD_INODE_SIZE) + internal_dump_inode_extra(out, prefix, inode_num, + (struct ext2_inode_large *) inode); if (LINUX_S_ISLNK(inode->i_mode) && ext2fs_inode_data_blocks(current_fs,inode) == 0) fprintf(out, "%sFast_link_dest: %.*s\n", prefix, (int) inode->i_size, (char *)inode->i_block); @@ -501,38 +798,121 @@ void internal_dump_inode(FILE *out, const char *prefix, devnote = ""; } else { major = (inode->i_block[1] & 0xfff00) >> 8; - minor = ((inode->i_block[1] & 0xff) | + minor = ((inode->i_block[1] & 0xff) | ((inode->i_block[1] >> 12) & 0xfff00)); devnote = "(New-style) "; } - fprintf(out, "%sDevice major/minor number: %02d:%02d (hex %02x:%02x)\n", + fprintf(out, "%sDevice major/minor number: %02d:%02d (hex %02x:%02x)\n", devnote, major, minor, major, minor); + } else if (do_dump_blocks) { + if (inode->i_flags & EXT4_EXTENTS_FL) + dump_extents(out, prefix, inode_num, + DUMP_LEAF_EXTENTS, 0, 0); + else + dump_blocks(out, prefix, inode_num); } - else if (do_dump_blocks) - dump_blocks(out, prefix, inode_num); } -static void dump_inode(ext2_ino_t inode_num, struct ext2_inode inode) +static void dump_inode(ext2_ino_t inode_num, struct ext2_inode *inode) { FILE *out; - + out = open_pager(); - internal_dump_inode(out, "", inode_num, &inode, 1); + internal_dump_inode(out, "", inode_num, inode, 1); close_pager(out); } void do_stat(int argc, char *argv[]) { ext2_ino_t inode; - struct ext2_inode inode_buf; + struct ext2_inode * inode_buf; - if (common_inode_args_process(argc, argv, &inode, 0)) + if (check_fs_open(argv[0])) return; - if (debugfs_read_inode(inode, &inode_buf, argv[0])) + inode_buf = (struct ext2_inode *) + malloc(EXT2_INODE_SIZE(current_fs->super)); + if (!inode_buf) { + fprintf(stderr, "do_stat: can't allocate buffer\n"); + return; + } + + if (common_inode_args_process(argc, argv, &inode, 0)) { + free(inode_buf); + return; + } + + if (debugfs_read_inode_full(inode, inode_buf, argv[0], + EXT2_INODE_SIZE(current_fs->super))) { + free(inode_buf); return; + } + + dump_inode(inode, inode_buf); + free(inode_buf); + return; +} + +void do_dump_extents(int argc, char *argv[]) +{ + struct ext2_inode inode; + ext2_ino_t ino; + FILE *out; + int c, flags = 0; + int logical_width; + int physical_width; + + reset_getopt(); + while ((c = getopt(argc, argv, "nl")) != EOF) { + switch (c) { + case 'n': + flags |= DUMP_NODE_EXTENTS; + break; + case 'l': + flags |= DUMP_LEAF_EXTENTS; + break; + } + } + + if (argc != optind+1) { + print_usage: + com_err(0, 0, "Usage: dump_extents [-n] [-l] file"); + return; + } + + if (flags == 0) + flags = DUMP_NODE_EXTENTS | DUMP_LEAF_EXTENTS; + flags |= DUMP_EXTENT_TABLE; + + if (check_fs_open(argv[0])) + return; + + ino = string_to_inode(argv[optind]); + if (ino == 0) + return; + + if (debugfs_read_inode(ino, &inode, argv[0])) + return; + + if ((inode.i_flags & EXT4_EXTENTS_FL) == 0) { + fprintf(stderr, "%s: does not uses extent block maps\n", + argv[optind]); + return; + } - dump_inode(inode,inode_buf); + logical_width = int_log10(((inode.i_size | + (__u64) inode.i_size_high << 32) + + current_fs->blocksize - 1) / + current_fs->blocksize) + 1; + if (logical_width < 5) + logical_width = 5; + physical_width = int_log10(current_fs->super->s_blocks_count) + 1; + if (physical_width < 5) + physical_width = 5; + + out = open_pager(); + dump_extents(out, "", ino, flags, logical_width, physical_width); + close_pager(out); return; } @@ -546,7 +926,7 @@ void do_chroot(int argc, char *argv[]) retval = ext2fs_check_directory(current_fs, inode); if (retval) { - com_err(argv[1], retval, ""); + com_err(argv[1], retval, 0); return; } root = inode; @@ -611,7 +991,7 @@ void do_testi(int argc, char *argv[]) void do_freeb(int argc, char *argv[]) { blk_t block; - int count = 1; + blk_t count = 1; if (common_block_args_process(argc, argv, &block, &count)) return; @@ -619,7 +999,7 @@ void do_freeb(int argc, char *argv[]) return; while (count-- > 0) { if (!ext2fs_test_block_bitmap(current_fs->block_map,block)) - com_err(argv[0], 0, "Warning: block %d already clear", + com_err(argv[0], 0, "Warning: block %u already clear", block); ext2fs_unmark_block_bitmap(current_fs->block_map,block); block++; @@ -630,7 +1010,7 @@ void do_freeb(int argc, char *argv[]) void do_setb(int argc, char *argv[]) { blk_t block; - int count = 1; + blk_t count = 1; if (common_block_args_process(argc, argv, &block, &count)) return; @@ -638,7 +1018,7 @@ void do_setb(int argc, char *argv[]) return; while (count-- > 0) { if (ext2fs_test_block_bitmap(current_fs->block_map,block)) - com_err(argv[0], 0, "Warning: block %d already set", + com_err(argv[0], 0, "Warning: block %u already set", block); ext2fs_mark_block_bitmap(current_fs->block_map,block); block++; @@ -649,15 +1029,15 @@ void do_setb(int argc, char *argv[]) void do_testb(int argc, char *argv[]) { blk_t block; - int count = 1; + blk_t count = 1; if (common_block_args_process(argc, argv, &block, &count)) return; while (count-- > 0) { if (ext2fs_test_block_bitmap(current_fs->block_map,block)) - printf("Block %d marked in use\n", block); + printf("Block %u marked in use\n", block); else - printf("Block %d not in use\n", block); + printf("Block %u not in use\n", block); block++; } } @@ -671,7 +1051,8 @@ static void modify_u8(char *com, const char *prompt, sprintf(buf, format, *val); printf("%30s [%s] ", prompt, buf); - fgets(buf, sizeof(buf), stdin); + if (!fgets(buf, sizeof(buf), stdin)) + return; if (buf[strlen (buf) - 1] == '\n') buf[strlen (buf) - 1] = '\0'; if (!buf[0]) @@ -692,7 +1073,8 @@ static void modify_u16(char *com, const char *prompt, sprintf(buf, format, *val); printf("%30s [%s] ", prompt, buf); - fgets(buf, sizeof(buf), stdin); + if (!fgets(buf, sizeof(buf), stdin)) + return; if (buf[strlen (buf) - 1] == '\n') buf[strlen (buf) - 1] = '\0'; if (!buf[0]) @@ -713,7 +1095,8 @@ static void modify_u32(char *com, const char *prompt, sprintf(buf, format, *val); printf("%30s [%s] ", prompt, buf); - fgets(buf, sizeof(buf), stdin); + if (!fgets(buf, sizeof(buf), stdin)) + return; if (buf[strlen (buf) - 1] == '\n') buf[strlen (buf) - 1] = '\0'; if (!buf[0]) @@ -737,7 +1120,8 @@ void do_modify_inode(int argc, char *argv[]) const char *hex_format = "0x%x"; const char *octal_format = "0%o"; const char *decimal_format = "%d"; - + const char *unsignedlong_format = "%lu"; + if (common_inode_args_process(argc, argv, &inode_num, CHECK_FS_RW)) return; @@ -745,17 +1129,20 @@ void do_modify_inode(int argc, char *argv[]) if (debugfs_read_inode(inode_num, &inode, argv[1])) return; - + modify_u16(argv[0], "Mode", octal_format, &inode.i_mode); modify_u16(argv[0], "User ID", decimal_format, &inode.i_uid); modify_u16(argv[0], "Group ID", decimal_format, &inode.i_gid); - modify_u32(argv[0], "Size", decimal_format, &inode.i_size); + modify_u32(argv[0], "Size", unsignedlong_format, &inode.i_size); modify_u32(argv[0], "Creation time", decimal_format, &inode.i_ctime); modify_u32(argv[0], "Modification time", decimal_format, &inode.i_mtime); modify_u32(argv[0], "Access time", decimal_format, &inode.i_atime); modify_u32(argv[0], "Deletion time", decimal_format, &inode.i_dtime); modify_u16(argv[0], "Link count", decimal_format, &inode.i_links_count); - modify_u32(argv[0], "Block count", decimal_format, &inode.i_blocks); + if (os == EXT2_OS_LINUX) + modify_u16(argv[0], "Block count high", unsignedlong_format, + &inode.osd2.linux2.l_i_blocks_hi); + modify_u32(argv[0], "Block count", unsignedlong_format, &inode.i_blocks); modify_u32(argv[0], "File flags", hex_format, &inode.i_flags); modify_u32(argv[0], "Generation", hex_format, &inode.i_generation); #if 0 @@ -767,24 +1154,16 @@ void do_modify_inode(int argc, char *argv[]) else modify_u32(argv[0], "High 32bits of size", decimal_format, &inode.i_size_high); - if (current_fs->super->s_creator_os == EXT2_OS_HURD) + if (os == EXT2_OS_HURD) modify_u32(argv[0], "Translator Block", decimal_format, &inode.osd1.hurd1.h_i_translator); - + modify_u32(argv[0], "Fragment address", decimal_format, &inode.i_faddr); switch (os) { - case EXT2_OS_LINUX: - frag = &inode.osd2.linux2.l_i_frag; - fsize = &inode.osd2.linux2.l_i_fsize; - break; case EXT2_OS_HURD: frag = &inode.osd2.hurd2.h_i_frag; fsize = &inode.osd2.hurd2.h_i_fsize; break; - case EXT2_OS_MASIX: - frag = &inode.osd2.masix2.m_i_frag; - fsize = &inode.osd2.masix2.m_i_fsize; - break; default: frag = fsize = 0; } @@ -798,7 +1177,7 @@ void do_modify_inode(int argc, char *argv[]) modify_u32(argv[0], buf, decimal_format, &inode.i_block[i]); } modify_u32(argv[0], "Indirect Block", decimal_format, - &inode.i_block[EXT2_IND_BLOCK]); + &inode.i_block[EXT2_IND_BLOCK]); modify_u32(argv[0], "Double Indirect Block", decimal_format, &inode.i_block[EXT2_DIND_BLOCK]); modify_u32(argv[0], "Triple Indirect Block", decimal_format, @@ -811,13 +1190,13 @@ void do_change_working_dir(int argc, char *argv[]) { ext2_ino_t inode; int retval; - + if (common_inode_args_process(argc, argv, &inode, 0)) return; retval = ext2fs_check_directory(current_fs, inode); if (retval) { - com_err(argv[1], retval, ""); + com_err(argv[1], retval, 0); return; } cwd = inode; @@ -828,7 +1207,7 @@ void do_print_working_directory(int argc, char *argv[]) { int retval; char *pathname = NULL; - + if (common_args_process(argc, argv, 1, 1, "print_working_directory", "", 0)) return; @@ -838,15 +1217,23 @@ void do_print_working_directory(int argc, char *argv[]) com_err(argv[0], retval, "while trying to get pathname of cwd"); } - printf("[pwd] INODE: %6u PATH: %s\n", cwd, pathname); - free(pathname); + printf("[pwd] INODE: %6u PATH: %s\n", + cwd, pathname ? pathname : "NULL"); + if (pathname) { + free(pathname); + pathname = NULL; + } retval = ext2fs_get_pathname(current_fs, root, 0, &pathname); if (retval) { com_err(argv[0], retval, "while trying to get pathname of root"); } - printf("[root] INODE: %6u PATH: %s\n", root, pathname); - free(pathname); + printf("[root] INODE: %6u PATH: %s\n", + root, pathname ? pathname : "NULL"); + if (pathname) { + free(pathname); + pathname = NULL; + } return; } @@ -860,22 +1247,22 @@ static int ext2_file_type(unsigned int mode) if (LINUX_S_ISDIR(mode)) return EXT2_FT_DIR; - + if (LINUX_S_ISCHR(mode)) return EXT2_FT_CHRDEV; - + if (LINUX_S_ISBLK(mode)) return EXT2_FT_BLKDEV; - + if (LINUX_S_ISLNK(mode)) return EXT2_FT_SYMLINK; if (LINUX_S_ISFIFO(mode)) return EXT2_FT_FIFO; - + if (LINUX_S_ISSOCK(mode)) return EXT2_FT_SOCK; - + return 0; } @@ -885,7 +1272,7 @@ static void make_link(char *sourcename, char *destname) struct ext2_inode inode; int retval; ext2_ino_t dir; - char *dest, *cp, *basename; + char *dest, *cp, *base_name; /* * Get the source inode @@ -893,17 +1280,17 @@ static void make_link(char *sourcename, char *destname) ino = string_to_inode(sourcename); if (!ino) return; - basename = strrchr(sourcename, '/'); - if (basename) - basename++; + base_name = strrchr(sourcename, '/'); + if (base_name) + base_name++; else - basename = sourcename; + base_name = sourcename; /* * Figure out the destination. First see if it exists and is - * a directory. + * a directory. */ if (! (retval=ext2fs_namei(current_fs, root, cwd, destname, &dir))) - dest = basename; + dest = base_name; else { /* * OK, it doesn't exist. See if it is @@ -924,11 +1311,11 @@ static void make_link(char *sourcename, char *destname) if (debugfs_read_inode(ino, &inode, sourcename)) return; - - retval = ext2fs_link(current_fs, dir, dest, ino, + + retval = ext2fs_link(current_fs, dir, dest, ino, ext2_file_type(inode.i_mode)); if (retval) - com_err("make_link", retval, ""); + com_err("make_link", retval, 0); return; } @@ -943,7 +1330,7 @@ void do_link(int argc, char *argv[]) } static int mark_blocks_proc(ext2_filsys fs, blk_t *blocknr, - int blockcnt EXT2FS_ATTR((unused)), + int blockcnt EXT2FS_ATTR((unused)), void *private EXT2FS_ATTR((unused))) { blk_t block; @@ -958,8 +1345,8 @@ void do_undel(int argc, char *argv[]) ext2_ino_t ino; struct ext2_inode inode; - if (common_args_process(argc, argv, 3, 3, "undelete", - " ", + if (common_args_process(argc, argv, 2, 3, "undelete", + " [dest_name]", CHECK_FS_RW | CHECK_FS_BITMAPS)) return; @@ -977,7 +1364,7 @@ void do_undel(int argc, char *argv[]) /* * XXX this function doesn't handle changing the links count on the - * parent directory when undeleting a directory. + * parent directory when undeleting a directory. */ inode.i_links_count = LINUX_S_ISDIR(inode.i_mode) ? 2 : 1; inode.i_dtime = 0; @@ -985,33 +1372,34 @@ void do_undel(int argc, char *argv[]) if (debugfs_write_inode(ino, &inode, argv[0])) return; - ext2fs_block_iterate(current_fs, ino, 0, NULL, + ext2fs_block_iterate(current_fs, ino, BLOCK_FLAG_READ_ONLY, NULL, mark_blocks_proc, NULL); ext2fs_inode_alloc_stats2(current_fs, ino, +1, 0); - make_link(argv[1], argv[2]); + if (argc > 2) + make_link(argv[1], argv[2]); } static void unlink_file_by_name(char *filename) { int retval; ext2_ino_t dir; - char *basename; - - basename = strrchr(filename, '/'); - if (basename) { - *basename++ = '\0'; + char *base_name; + + base_name = strrchr(filename, '/'); + if (base_name) { + *base_name++ = '\0'; dir = string_to_inode(filename); if (!dir) return; } else { dir = cwd; - basename = filename; + base_name = filename; } - retval = ext2fs_unlink(current_fs, dir, basename, 0, 0); + retval = ext2fs_unlink(current_fs, dir, base_name, 0, 0); if (retval) - com_err("unlink_file_by_name", retval, ""); + com_err("unlink_file_by_name", retval, 0); return; } @@ -1026,11 +1414,11 @@ void do_unlink(int argc, char *argv[]) void do_find_free_block(int argc, char *argv[]) { - blk_t free_blk, goal; + blk_t free_blk, goal, first_free = 0; int count; errcode_t retval; char *tmp; - + if ((argc > 3) || (argc==2 && *argv[1] == '?')) { com_err(argv[0], 0, "Usage: find_free_block [count [goal]]"); return; @@ -1058,15 +1446,20 @@ void do_find_free_block(int argc, char *argv[]) goal = current_fs->super->s_first_data_block; printf("Free blocks found: "); - free_blk = goal - 1; + free_blk = goal - 1; while (count-- > 0) { retval = ext2fs_new_block(current_fs, free_blk + 1, 0, &free_blk); + if (first_free) { + if (first_free == free_blk) + break; + } else + first_free = free_blk; if (retval) { - com_err("ext2fs_new_block", retval, ""); + com_err("ext2fs_new_block", retval, 0); return; } else - printf("%d ", free_blk); + printf("%u ", free_blk); } printf("\n"); } @@ -1077,7 +1470,7 @@ void do_find_free_inode(int argc, char *argv[]) int mode; int retval; char *tmp; - + if (argc > 3 || (argc>1 && *argv[1] == '?')) { com_err(argv[0], 0, "Usage: find_free_inode [dir] [mode]"); return; @@ -1105,7 +1498,7 @@ void do_find_free_inode(int argc, char *argv[]) retval = ext2fs_new_inode(current_fs, dir, mode, 0, &free_inode); if (retval) - com_err("ext2fs_new_inode", retval, ""); + com_err("ext2fs_new_inode", retval, 0); else printf("Free inode found: %u\n", free_inode); } @@ -1166,11 +1559,11 @@ void do_write(int argc, char *argv[]) fd = open(argv[1], O_RDONLY); if (fd < 0) { - com_err(argv[1], errno, ""); + com_err(argv[1], errno, 0); return; } if (fstat(fd, &statbuf) < 0) { - com_err(argv[1], errno, ""); + com_err(argv[1], errno, 0); close(fd); return; } @@ -1184,7 +1577,7 @@ void do_write(int argc, char *argv[]) retval = ext2fs_new_inode(current_fs, cwd, 010755, 0, &newfile); if (retval) { - com_err(argv[0], retval, ""); + com_err(argv[0], retval, 0); close(fd); return; } @@ -1195,13 +1588,14 @@ void do_write(int argc, char *argv[]) retval = ext2fs_expand_dir(current_fs, cwd); if (retval) { com_err(argv[0], retval, "while expanding directory"); + close(fd); return; } retval = ext2fs_link(current_fs, cwd, argv[2], newfile, EXT2_FT_REG_FILE); } if (retval) { - com_err(argv[2], retval, ""); + com_err(argv[2], retval, 0); close(fd); return; } @@ -1210,17 +1604,21 @@ void do_write(int argc, char *argv[]) ext2fs_inode_alloc_stats2(current_fs, newfile, +1, 0); memset(&inode, 0, sizeof(inode)); inode.i_mode = (statbuf.st_mode & ~LINUX_S_IFMT) | LINUX_S_IFREG; - inode.i_atime = inode.i_ctime = inode.i_mtime = time(NULL); + inode.i_atime = inode.i_ctime = inode.i_mtime = + current_fs->now ? current_fs->now : time(0); inode.i_links_count = 1; inode.i_size = statbuf.st_size; - if (debugfs_write_inode(newfile, &inode, argv[0])) { + if (current_fs->super->s_feature_incompat & + EXT3_FEATURE_INCOMPAT_EXTENTS) + inode.i_flags |= EXT4_EXTENTS_FL; + if (debugfs_write_new_inode(newfile, &inode, argv[0])) { close(fd); return; } if (LINUX_S_ISREG(inode.i_mode)) { retval = copy_file(fd, newfile); if (retval) - com_err("copy_file", retval, ""); + com_err("copy_file", retval, 0); } close(fd); } @@ -1273,7 +1671,7 @@ void do_mknod(int argc, char *argv[]) return; retval = ext2fs_new_inode(current_fs, cwd, 010755, 0, &newfile); if (retval) { - com_err(argv[0], retval, ""); + com_err(argv[0], retval, 0); return; } printf("Allocated inode: %u\n", newfile); @@ -1288,7 +1686,7 @@ void do_mknod(int argc, char *argv[]) filetype); } if (retval) { - com_err(argv[1], retval, ""); + com_err(argv[1], retval, 0); return; } if (ext2fs_test_inode_bitmap(current_fs->inode_map,newfile)) @@ -1297,7 +1695,8 @@ void do_mknod(int argc, char *argv[]) ext2fs_mark_ib_dirty(current_fs); memset(&inode, 0, sizeof(inode)); inode.i_mode = mode; - inode.i_atime = inode.i_ctime = inode.i_mtime = time(NULL); + inode.i_atime = inode.i_ctime = inode.i_mtime = + current_fs->now ? current_fs->now : time(0); if ((major < 256) && (minor < 256)) { inode.i_block[0] = major*256+minor; inode.i_block[1] = 0; @@ -1306,7 +1705,7 @@ void do_mknod(int argc, char *argv[]) inode.i_block[1] = (minor & 0xff) | (major << 8) | ((minor & ~0xff) << 12); } inode.i_links_count = 1; - if (debugfs_write_inode(newfile, &inode, argv[0])) + if (debugfs_write_new_inode(newfile, &inode, argv[0])) return; } @@ -1326,7 +1725,7 @@ void do_mkdir(int argc, char *argv[]) *cp = 0; parent = string_to_inode(argv[1]); if (!parent) { - com_err(argv[1], ENOENT, ""); + com_err(argv[1], ENOENT, 0); return; } name = cp+1; @@ -1340,20 +1739,20 @@ try_again: if (retval == EXT2_ET_DIR_NO_SPACE) { retval = ext2fs_expand_dir(current_fs, parent); if (retval) { - com_err("argv[0]", retval, "while expanding directory"); + com_err(argv[0], retval, "while expanding directory"); return; } goto try_again; } if (retval) { - com_err("ext2fs_mkdir", retval, ""); + com_err("ext2fs_mkdir", retval, 0); return; } } static int release_blocks_proc(ext2_filsys fs, blk_t *blocknr, - int blockcnt EXT2FS_ATTR((unused)), + int blockcnt EXT2FS_ATTR((unused)), void *private EXT2FS_ATTR((unused))) { blk_t block; @@ -1369,13 +1768,13 @@ static void kill_file_by_inode(ext2_ino_t inode) if (debugfs_read_inode(inode, &inode_buf, 0)) return; - inode_buf.i_dtime = time(NULL); + inode_buf.i_dtime = current_fs->now ? current_fs->now : time(0); if (debugfs_write_inode(inode, &inode_buf, 0)) return; if (!ext2fs_inode_has_valid_blocks(&inode_buf)) return; - ext2fs_block_iterate(current_fs, inode, 0, NULL, + ext2fs_block_iterate(current_fs, inode, BLOCK_FLAG_READ_ONLY, NULL, release_blocks_proc, NULL); printf("\n"); ext2fs_inode_alloc_stats2(current_fs, inode, -1, @@ -1453,7 +1852,7 @@ static int rmdir_proc(ext2_ino_t dir EXT2FS_ATTR((unused)), rds->empty = 0; return 0; } - + void do_rmdir(int argc, char *argv[]) { int retval; @@ -1510,7 +1909,7 @@ void do_rmdir(int argc, char *argv[]) } } -void do_show_debugfs_params(int argc EXT2FS_ATTR((unused)), +void do_show_debugfs_params(int argc EXT2FS_ATTR((unused)), char *argv[] EXT2FS_ATTR((unused))) { FILE *out = stdout; @@ -1532,14 +1931,14 @@ void do_expand_dir(int argc, char *argv[]) retval = ext2fs_expand_dir(current_fs, inode); if (retval) - com_err("ext2fs_expand_dir", retval, ""); + com_err("ext2fs_expand_dir", retval, 0); return; } void do_features(int argc, char *argv[]) { int i; - + if (check_fs_open(argv[0])) return; @@ -1562,7 +1961,7 @@ void do_bmap(int argc, char *argv[]) blk_t blk, pblk; int err; errcode_t errcode; - + if (common_args_process(argc, argv, 3, 3, argv[0], " logical_blk", 0)) return; @@ -1575,10 +1974,10 @@ void do_bmap(int argc, char *argv[]) errcode = ext2fs_bmap(current_fs, ino, 0, 0, 0, blk, &pblk); if (errcode) { com_err("argv[0]", errcode, - "while mapping logical block %d\n", blk); + "while mapping logical block %u\n", blk); return; } - printf("%d\n", pblk); + printf("%u\n", pblk); } void do_imap(int argc, char *argv[]) @@ -1602,7 +2001,7 @@ void do_imap(int argc, char *argv[]) group); return; } - block_nr = current_fs->group_desc[(unsigned)group].bg_inode_table + + block_nr = current_fs->group_desc[(unsigned)group].bg_inode_table + block; offset &= (EXT2_BLOCK_SIZE(current_fs->super) - 1); @@ -1612,7 +2011,90 @@ void do_imap(int argc, char *argv[]) } +void do_set_current_time(int argc, char *argv[]) +{ + time_t now; + if (common_args_process(argc, argv, 2, 2, argv[0], + "