From: Theodore Ts'o Date: Thu, 13 Dec 2018 05:53:16 +0000 (-0500) Subject: debugfs: fix set_inode_field so it can set the checksum field X-Git-Tag: v1.45.0~16 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=32917350a4f957f93259e90b28471d18def54b24;p=thirdparty%2Fe2fsprogs.git debugfs: fix set_inode_field so it can set the checksum field Previously, setting the inode field was a no-op, since the library function ext2fs_write_inode_full() would override whatever value was set by debugfs. Use the new ext2fs_write_inode2() interface so we can in fact set the checksum to a potentially wrong value. Also, ignore the inode checksum failures if we are setting the checksum, and if the checksum value is "calc", set the inode checksum to the correct value. Signed-off-by: Theodore Ts'o --- diff --git a/debugfs/debugfs.c b/debugfs/debugfs.c index e03519c42..1e99fa6cb 100644 --- a/debugfs/debugfs.c +++ b/debugfs/debugfs.c @@ -994,8 +994,8 @@ void do_stat(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)), return; } - if (debugfs_read_inode_full(inode, inode_buf, argv[0], - EXT2_INODE_SIZE(current_fs->super))) { + if (debugfs_read_inode2(inode, inode_buf, argv[0], + EXT2_INODE_SIZE(current_fs->super), 0)) { free(inode_buf); return; } @@ -1636,12 +1636,12 @@ void do_copy_inode(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)), if (!dest_ino) return; - if (debugfs_read_inode_full(src_ino, (struct ext2_inode *) buf, - argv[0], sizeof(buf))) + if (debugfs_read_inode2(src_ino, (struct ext2_inode *) buf, + argv[0], sizeof(buf), 0)) return; - if (debugfs_write_inode_full(dest_ino, (struct ext2_inode *) buf, - argv[0], sizeof(buf))) + if (debugfs_write_inode2(dest_ino, (struct ext2_inode *) buf, + argv[0], sizeof(buf), 0)) return; } diff --git a/debugfs/debugfs.h b/debugfs/debugfs.h index d1d13b455..477d9bbb4 100644 --- a/debugfs/debugfs.h +++ b/debugfs/debugfs.h @@ -54,12 +54,12 @@ extern int common_block_args_process(int argc, char *argv[], blk64_t *block, blk64_t *count); extern int debugfs_read_inode(ext2_ino_t ino, struct ext2_inode * inode, const char *cmd); -extern int debugfs_read_inode_full(ext2_ino_t ino, struct ext2_inode * inode, - const char *cmd, int bufsize); +extern int debugfs_read_inode2(ext2_ino_t ino, struct ext2_inode * inode, + const char *cmd, int bufsize, int flags); extern int debugfs_write_inode(ext2_ino_t ino, struct ext2_inode * inode, const char *cmd); -extern int debugfs_write_inode_full(ext2_ino_t ino, struct ext2_inode * inode, - const char *cmd, int bufsize); +extern int debugfs_write_inode2(ext2_ino_t ino, struct ext2_inode * inode, + const char *cmd, int bufsize, int flags); extern int debugfs_write_new_inode(ext2_ino_t ino, struct ext2_inode * inode, const char *cmd); extern int ext2_file_type(unsigned int mode); diff --git a/debugfs/set_fields.c b/debugfs/set_fields.c index b19d1a7d1..a7dd34f7c 100644 --- a/debugfs/set_fields.c +++ b/debugfs/set_fields.c @@ -53,6 +53,7 @@ static int array_idx; #define FLAG_ARRAY 0x0001 #define FLAG_ALIAS 0x0002 /* Data intersects with other field */ +#define FLAG_CSUM 0x0004 struct field_set_info { const char *name; @@ -72,6 +73,8 @@ static errcode_t parse_hashalg(struct field_set_info *info, char *field, char *a static errcode_t parse_time(struct field_set_info *info, char *field, char *arg); static errcode_t parse_bmap(struct field_set_info *info, char *field, char *arg); static errcode_t parse_gd_csum(struct field_set_info *info, char *field, char *arg); +static errcode_t parse_inode_csum(struct field_set_info *info, char *field, + char *arg); static errcode_t parse_mmp_clear(struct field_set_info *info, char *field, char *arg); @@ -218,7 +221,7 @@ static struct field_set_info inode_fields[] = { { "frag", &set_inode.osd2.hurd2.h_i_frag, NULL, 1, parse_uint, FLAG_ALIAS }, { "fsize", &set_inode.osd2.hurd2.h_i_fsize, NULL, 1, parse_uint }, { "checksum", &set_inode.osd2.linux2.l_i_checksum_lo, - &set_inode.i_checksum_hi, 2, parse_uint }, + &set_inode.i_checksum_hi, 2, parse_inode_csum, FLAG_CSUM }, { "author", &set_inode.osd2.hurd2.h_i_author, NULL, 4, parse_uint, FLAG_ALIAS }, { "extra_isize", &set_inode.i_extra_isize, NULL, @@ -665,6 +668,68 @@ static errcode_t parse_gd_csum(struct field_set_info *info, char *field, return parse_uint(info, field, arg); } +static errcode_t parse_inode_csum(struct field_set_info *info, char *field, + char *arg) +{ + errcode_t retval = 0; + __u32 crc; + int is_large_inode = 0; + struct ext2_inode_large *tmp_inode; + + if (strcmp(arg, "calc") == 0) { + size_t sz = EXT2_INODE_SIZE(current_fs->super); + struct ext2_inode_large *tmp_inode = NULL; + + retval = ext2fs_get_mem(sz, &tmp_inode); + if (retval) + goto out; + + retval = ext2fs_read_inode_full(current_fs, set_ino, + (struct ext2_inode *) tmp_inode, + sz); + if (retval) + goto out; + +#ifdef WORDS_BIGENDIAN + ext2fs_swap_inode_full(current_fs, tmp_inode, + tmp_inode, 1, sz); +#endif + + if (sz > EXT2_GOOD_OLD_INODE_SIZE) + is_large_inode = 1; + + retval = ext2fs_inode_csum_set(current_fs, set_ino, + tmp_inode); + if (retval) + goto out; +#ifdef WORDS_BIGENDIAN + crc = set_inode.i_checksum_lo = + ext2fs_swab16(tmp_inode->i_checksum_lo); + +#else + crc = set_inode.i_checksum_lo = tmp_inode->i_checksum_lo; +#endif + if (is_large_inode && + set_inode.i_extra_isize >= + (offsetof(struct ext2_inode_large, + i_checksum_hi) - + EXT2_GOOD_OLD_INODE_SIZE)) { +#ifdef WORDS_BIGENDIAN + set_inode.i_checksum_lo = + ext2fs_swab16(tmp_inode->i_checksum_lo); +#else + set_inode.i_checksum_hi = tmp_inode->i_checksum_hi; +#endif + crc |= ((__u32)set_inode.i_checksum_hi) << 16; + } + printf("Checksum set to 0x%08x\n", crc); + out: + ext2fs_free_mem(&tmp_inode); + return retval; + } + return parse_uint(info, field, arg); +} + static void print_possible_fields(struct field_set_info *fields) { struct field_set_info *ss; @@ -777,16 +842,19 @@ void do_set_inode(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)), if (!set_ino) return; - if (debugfs_read_inode_full(set_ino, - (struct ext2_inode *) &set_inode, argv[1], - sizeof(set_inode))) + if (debugfs_read_inode2(set_ino, + (struct ext2_inode *) &set_inode, argv[1], + sizeof(set_inode), + (ss->flags & FLAG_CSUM) ? + READ_INODE_NOCSUM : 0)) return; if (ss->func(ss, argv[2], argv[3]) == 0) { - if (debugfs_write_inode_full(set_ino, - (struct ext2_inode *) &set_inode, - argv[1], sizeof(set_inode))) - return; + debugfs_write_inode2(set_ino, + (struct ext2_inode *) &set_inode, + argv[1], sizeof(set_inode), + (ss->flags & FLAG_CSUM) ? + WRITE_INODE_NOCSUM : 0); } } diff --git a/debugfs/util.c b/debugfs/util.c index 452de749b..759bb3924 100644 --- a/debugfs/util.c +++ b/debugfs/util.c @@ -420,12 +420,12 @@ 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 debugfs_read_inode2(ext2_ino_t ino, struct ext2_inode * inode, + const char *cmd, int bufsize, int flags) { int retval; - retval = ext2fs_read_inode_full(current_fs, ino, inode, bufsize); + retval = ext2fs_read_inode2(current_fs, ino, inode, bufsize, flags); if (retval) { com_err(cmd, retval, "while reading inode %u", ino); return 1; @@ -446,15 +446,14 @@ int debugfs_read_inode(ext2_ino_t ino, struct ext2_inode * inode, return 0; } -int debugfs_write_inode_full(ext2_ino_t ino, - struct ext2_inode *inode, - const char *cmd, - int bufsize) +int debugfs_write_inode2(ext2_ino_t ino, + struct ext2_inode *inode, + const char *cmd, + int bufsize, int flags) { int retval; - retval = ext2fs_write_inode_full(current_fs, ino, - inode, bufsize); + retval = ext2fs_write_inode2(current_fs, ino, inode, bufsize, flags); if (retval) { com_err(cmd, retval, "while writing inode %u", ino); return 1;