]> git.ipfire.org Git - thirdparty/e2fsprogs.git/commitdiff
debugfs: fix set_inode_field so it can set the checksum field
authorTheodore Ts'o <tytso@mit.edu>
Thu, 13 Dec 2018 05:53:16 +0000 (00:53 -0500)
committerTheodore Ts'o <tytso@mit.edu>
Sat, 15 Dec 2018 23:31:40 +0000 (18:31 -0500)
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 <tytso@mit.edu>
debugfs/debugfs.c
debugfs/debugfs.h
debugfs/set_fields.c
debugfs/util.c

index e03519c42cf6b70973562c4db6e2c00322b49dad..1e99fa6cb01b54fba55ba8d2bf1d6d33be662176 100644 (file)
@@ -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;
 }
 
index d1d13b455bf721958d58e615f791edc0c546010f..477d9bbb44ece992722476abbe47859831ba03c7 100644 (file)
@@ -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);
index b19d1a7d11f923912fe910ba8e22bb69462db258..a7dd34f7c5e5ebea71d044a4c1f4a94963e709eb 100644 (file)
@@ -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);
        }
 }
 
index 452de749bc2a499962496c13b512d098d27d3256..759bb3924874b5e016860e6924c49a3004ae9724 100644 (file)
@@ -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;