From ea822eeba373bd0bed6e58a35ce123a9f2768113 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Sun, 20 Mar 2005 18:03:58 -0500 Subject: [PATCH] Enhance debugfs's stat command so it can dump extended attributes which are stored in the inode body. --- debugfs/ChangeLog | 7 ++++ debugfs/debugfs.c | 93 +++++++++++++++++++++++++++++++++++++++++++--- debugfs/util.c | 13 +++++++ lib/ext2fs/ext2_ext_attr.h | 3 ++ 4 files changed, 110 insertions(+), 6 deletions(-) diff --git a/debugfs/ChangeLog b/debugfs/ChangeLog index 0a12584..3b9e7df 100644 --- a/debugfs/ChangeLog +++ b/debugfs/ChangeLog @@ -1,3 +1,10 @@ +2005-03-20 Theodore Ts'o + + * debugfs.c (do_stat): Add support for dumping extended attributes + which are stored in the inode body. + + * util.c (debugfs_read_inode_full): new function + 2006-02-05 Theodore Ts'o * Release of E2fsprogs 1.36 diff --git a/debugfs/debugfs.c b/debugfs/debugfs.c index e4a8b8f..9fa85cb 100644 --- a/debugfs/debugfs.c +++ b/debugfs/debugfs.c @@ -33,6 +33,8 @@ extern char *optarg; #include "uuid/uuid.h" #include "e2p/e2p.h" +#include + #include "../version.h" extern ss_request_table debug_cmds; @@ -401,6 +403,69 @@ static int list_blocks_proc(ext2_filsys fs EXT2FS_ATTR((unused)), return 0; } +void dump_xattr_string(FILE *out, const unsigned char *str, int len) +{ + int printable = 1; + int i; + + /* check is string printable? */ + for (i = 0; i < len; i++) + if (!isprint(str[i])) { + printable = 0; + break; + } + + for (i = 0; i < len; i++) + if (printable) + fprintf(out, "%c", str[i]); + else + fprintf(out, "%02x ", str[i]); +} + +void internal_dump_inode_extra(FILE *out, const char *prefix, + ext2_ino_t inode_num, struct ext2_inode_large *inode) +{ + struct ext2_ext_attr_entry *entry; + __u32 *magic; + char *start, *end; + int storage_size; + int i; + + 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, "\" (%d)\n", entry->e_value_size); + entry = next; + } + } +} static void dump_blocks(FILE *f, const char *prefix, ext2_ino_t inode) { @@ -488,6 +553,9 @@ void internal_dump_inode(FILE *out, const char *prefix, 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); @@ -512,27 +580,40 @@ void internal_dump_inode(FILE *out, const char *prefix, 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)) + 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 (debugfs_read_inode(inode, &inode_buf, argv[0])) + 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); + dump_inode(inode, inode_buf); + free(inode_buf); return; } diff --git a/debugfs/util.c b/debugfs/util.c index b1a66e8..b74a7bd 100644 --- a/debugfs/util.c +++ b/debugfs/util.c @@ -307,6 +307,19 @@ int common_block_args_process(int argc, char *argv[], return 0; } +int debugfs_read_inode_full(ext2_ino_t ino, struct ext2_inode * inode, + const char *cmd, int bufsize) +{ + int retval; + + retval = ext2fs_read_inode_full(current_fs, ino, inode, bufsize); + if (retval) { + com_err(cmd, retval, "while reading inode %u", ino); + return 1; + } + return 0; +} + int debugfs_read_inode(ext2_ino_t ino, struct ext2_inode * inode, const char *cmd) { diff --git a/lib/ext2fs/ext2_ext_attr.h b/lib/ext2fs/ext2_ext_attr.h index d0a44f3..85ad490 100644 --- a/lib/ext2fs/ext2_ext_attr.h +++ b/lib/ext2fs/ext2_ext_attr.h @@ -44,6 +44,9 @@ struct ext2_ext_attr_entry { (char *)(entry) + EXT2_EXT_ATTR_LEN((entry)->e_name_len)) ) #define EXT2_EXT_ATTR_SIZE(size) \ (((size) + EXT2_EXT_ATTR_ROUND) & ~EXT2_EXT_ATTR_ROUND) +#define EXT2_EXT_IS_LAST_ENTRY(entry) (*((__u32 *)(entry)) == 0UL) +#define EXT2_EXT_ATTR_NAME(entry) \ + (((char *) (entry)) + sizeof(struct ext2_ext_attr_entry)) #ifdef __KERNEL__ # ifdef CONFIG_EXT2_FS_EXT_ATTR -- 1.8.3.1