From 41bf599391faaf6523c9997eb467a86888542339 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Sun, 14 Oct 2012 06:34:09 -0400 Subject: [PATCH] debugfs: teach the htree and ls commands to show directory checksums In addition, make the directory interator more robust in the case where the file system has the metadata checksum feature enabled, but the directory checksum is not present in a directory block. Signed-off-by: "Theodore Ts'o" --- debugfs/debugfs.8.in | 5 ++++- debugfs/htree.c | 21 ++++++++++++++++++--- debugfs/ls.c | 34 ++++++++++++++++++++++------------ lib/ext2fs/dir_iterate.c | 15 +++++++++++---- lib/ext2fs/ext2fs.h | 2 ++ 5 files changed, 57 insertions(+), 20 deletions(-) diff --git a/debugfs/debugfs.8.in b/debugfs/debugfs.8.in index cc5742f..bfcb1a8 100644 --- a/debugfs/debugfs.8.in +++ b/debugfs/debugfs.8.in @@ -405,13 +405,16 @@ and .I \-b options. .TP -.I ls [-l] [-d] [-p] filespec +.I ls [-l] [-c] [-d] [-p] filespec Print a listing of the files in the directory .IR filespec . The .I \-l flag will list files using a more verbose format. The +.I \-c +flag causes directory block checksums (if present) to be displayed. +The .I \-d flag will list deleted entries in the directory. The diff --git a/debugfs/htree.c b/debugfs/htree.c index 2971812..ffa858e 100644 --- a/debugfs/htree.c +++ b/debugfs/htree.c @@ -70,7 +70,7 @@ static void htree_dump_leaf_node(ext2_filsys fs, ext2_ino_t ino, (fs->super->s_flags & EXT2_FLAGS_UNSIGNED_HASH)) hash_alg += 3; - while (offset < (fs->blocksize - csum_size)) { + while (offset < fs->blocksize) { dirent = (struct ext2_dir_entry *) (buf + offset); errcode = ext2fs_get_rec_len(fs, dirent, &rec_len); if (errcode) { @@ -96,8 +96,23 @@ static void htree_dump_leaf_node(ext2_filsys fs, ext2_ino_t ino, if (errcode) com_err("htree_dump_leaf_node", errcode, "while calculating hash"); - snprintf(tmp, EXT2_NAME_LEN + 64, "%u 0x%08x-%08x (%d) %s ", - dirent->inode, hash, minor_hash, rec_len, name); + if ((offset == fs->blocksize - csum_size) && + (dirent->inode == 0) && + (dirent->rec_len == csum_size) && + (dirent->name_len == EXT2_DIR_NAME_LEN_CSUM)) { + struct ext2_dir_entry_tail *t; + + t = (struct ext2_dir_entry_tail *) dirent; + + snprintf(tmp, EXT2_NAME_LEN + 64, + "leaf block checksum: 0x%08x ", + t->det_checksum); + } else { + snprintf(tmp, EXT2_NAME_LEN + 64, + "%u 0x%08x-%08x (%d) %s ", + dirent->inode, hash, minor_hash, + rec_len, name); + } thislen = strlen(tmp); if (col + thislen > 80) { fprintf(pager, "\n"); diff --git a/debugfs/ls.c b/debugfs/ls.c index b4036de..032d12d 100644 --- a/debugfs/ls.c +++ b/debugfs/ls.c @@ -30,8 +30,7 @@ extern char *optarg; */ #define LONG_OPT 0x0001 -#define DELETED_OPT 0x0002 -#define PARSE_OPT 0x0004 +#define PARSE_OPT 0x0002 struct list_dir_struct { FILE *f; @@ -60,6 +59,7 @@ static int list_dir_proc(ext2_ino_t dir EXT2FS_ATTR((unused)), char lbr, rbr; int thislen; struct list_dir_struct *ls = (struct list_dir_struct *) private; + struct ext2_dir_entry_tail *t = (struct ext2_dir_entry_tail *) dirent; thislen = dirent->name_len & 0xFF; strncpy(name, dirent->name, thislen); @@ -99,8 +99,13 @@ static int list_dir_proc(ext2_ino_t dir EXT2FS_ATTR((unused)), strcpy(datestr, " "); memset(&inode, 0, sizeof(struct ext2_inode)); } - fprintf(ls->f, "%c%6u%c %6o (%d) %5d %5d ", lbr, ino, rbr, - inode.i_mode, dirent->name_len >> 8, + fprintf(ls->f, "%c%6u%c %6o ", lbr, ino, rbr, inode.i_mode); + if (entry == DIRENT_CHECKSUM) { + fprintf(ls->f, "(dirblock checksum: 0x%08x)\n", + t->det_checksum); + return 0; + } + fprintf(ls->f, "(%d) %5d %5d ", dirent->name_len >> 8, inode_uid(inode), inode_gid(inode)); if (LINUX_S_ISDIR(inode.i_mode)) fprintf(ls->f, "%5d", inode.i_size); @@ -108,8 +113,13 @@ static int list_dir_proc(ext2_ino_t dir EXT2FS_ATTR((unused)), fprintf(ls->f, "%5llu", EXT2_I_SIZE(&inode)); fprintf (ls->f, " %s %s\n", datestr, name); } else { - sprintf(tmp, "%c%u%c (%d) %s ", lbr, dirent->inode, rbr, - dirent->rec_len, name); + if (entry == DIRENT_CHECKSUM) + sprintf(tmp, "%c%u%c (dirblock checksum: 0x%08x) ", + lbr, dirent->inode, rbr, t->det_checksum); + else + sprintf(tmp, "%c%u%c (%d) %s ", + lbr, dirent->inode, rbr, + dirent->rec_len, name); thislen = strlen(tmp); if (ls->col + thislen > 80) { @@ -127,7 +137,7 @@ void do_list_dir(int argc, char *argv[]) ext2_ino_t inode; int retval; int c; - int flags; + int flags = DIRENT_FLAG_INCLUDE_EMPTY; struct list_dir_struct ls; ls.options = 0; @@ -135,13 +145,16 @@ void do_list_dir(int argc, char *argv[]) return; reset_getopt(); - while ((c = getopt (argc, argv, "dlp")) != EOF) { + while ((c = getopt (argc, argv, "cdlp")) != EOF) { switch (c) { + case 'c': + flags |= DIRENT_FLAG_INCLUDE_CSUM; + break; case 'l': ls.options |= LONG_OPT; break; case 'd': - ls.options |= DELETED_OPT; + flags |= DIRENT_FLAG_INCLUDE_REMOVED; break; case 'p': ls.options |= PARSE_OPT; @@ -166,9 +179,6 @@ void do_list_dir(int argc, char *argv[]) ls.f = open_pager(); ls.col = 0; - flags = DIRENT_FLAG_INCLUDE_EMPTY; - if (ls.options & DELETED_OPT) - flags |= DIRENT_FLAG_INCLUDE_REMOVED; retval = ext2fs_dir_iterate2(current_fs, inode, flags, 0, list_dir_proc, &ls); diff --git a/lib/ext2fs/dir_iterate.c b/lib/ext2fs/dir_iterate.c index c24015c..1a4bf5c 100644 --- a/lib/ext2fs/dir_iterate.c +++ b/lib/ext2fs/dir_iterate.c @@ -208,7 +208,7 @@ int ext2fs_process_dir_block(ext2_filsys fs, EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) csum_size = sizeof(struct ext2_dir_entry_tail); - while (offset < (fs->blocksize - csum_size)) { + while (offset < fs->blocksize) { dirent = (struct ext2_dir_entry *) (ctx->buf + offset); if (ext2fs_get_rec_len(fs, dirent, &rec_len)) return BLOCK_ABORT; @@ -219,9 +219,16 @@ int ext2fs_process_dir_block(ext2_filsys fs, ctx->errcode = EXT2_ET_DIR_CORRUPTED; return BLOCK_ABORT; } - if (!dirent->inode && - !(ctx->flags & DIRENT_FLAG_INCLUDE_EMPTY)) - goto next; + if (!dirent->inode) { + if ((offset == fs->blocksize - csum_size) && + (dirent->rec_len == csum_size) && + (dirent->name_len == EXT2_DIR_NAME_LEN_CSUM)) { + if (!(ctx->flags & DIRENT_FLAG_INCLUDE_CSUM)) + goto next; + entry = DIRENT_CHECKSUM; + } else if (!(ctx->flags & DIRENT_FLAG_INCLUDE_EMPTY)) + goto next; + } ret = (ctx->func)(ctx->dir, (next_real_entry > offset) ? diff --git a/lib/ext2fs/ext2fs.h b/lib/ext2fs/ext2fs.h index 31ada47..9148d4e 100644 --- a/lib/ext2fs/ext2fs.h +++ b/lib/ext2fs/ext2fs.h @@ -431,11 +431,13 @@ struct ext2_extent_info { #define DIRENT_FLAG_INCLUDE_EMPTY 1 #define DIRENT_FLAG_INCLUDE_REMOVED 2 +#define DIRENT_FLAG_INCLUDE_CSUM 4 #define DIRENT_DOT_FILE 1 #define DIRENT_DOT_DOT_FILE 2 #define DIRENT_OTHER_FILE 3 #define DIRENT_DELETED_FILE 4 +#define DIRENT_CHECKSUM 5 /* * Inode scan definitions -- 1.8.3.1