Whamcloud - gitweb
Merge branch 'maint' into next
authorTheodore Ts'o <tytso@mit.edu>
Mon, 9 Dec 2013 19:15:04 +0000 (14:15 -0500)
committerTheodore Ts'o <tytso@mit.edu>
Mon, 9 Dec 2013 19:15:04 +0000 (14:15 -0500)
99 files changed:
RELEASE-NOTES
configure
configure.in
debian/changelog
debian/e2fslibs.symbols
debugfs/debugfs.8.in
debugfs/debugfs.c
debugfs/dump.c
debugfs/filefrag.c
debugfs/htree.c
debugfs/logdump.c
debugfs/ls.c
debugfs/ncheck.c
debugfs/set_fields.c
e2fsck/Makefile.in
e2fsck/crc32.c [deleted file]
e2fsck/crc32defs.h [deleted file]
e2fsck/e2fsck.h
e2fsck/gen_crc32table.c [deleted file]
e2fsck/jfs_user.h
e2fsck/journal.c
e2fsck/message.c
e2fsck/pass1.c
e2fsck/pass1b.c
e2fsck/pass2.c
e2fsck/pass3.c
e2fsck/pass5.c
e2fsck/problem.c
e2fsck/problem.h
e2fsck/recovery.c
e2fsck/rehash.c
e2fsck/sigcatcher.c
e2fsck/super.c
e2fsck/unix.c
e2fsck/util.c
lib/blkid/probe.h
lib/config.h.in
lib/e2p/feature.c
lib/e2p/ls.c
lib/e2p/pf.c
lib/ext2fs/Makefile.in
lib/ext2fs/alloc.c
lib/ext2fs/alloc_stats.c
lib/ext2fs/alloc_tables.c
lib/ext2fs/blkmap64_ba.c
lib/ext2fs/blkmap64_rb.c
lib/ext2fs/blknum.c
lib/ext2fs/block.c
lib/ext2fs/bmap64.h
lib/ext2fs/closefs.c
lib/ext2fs/crc32c.c
lib/ext2fs/crc32c_defs.h
lib/ext2fs/csum.c
lib/ext2fs/dblist.c
lib/ext2fs/dir_iterate.c
lib/ext2fs/dirblock.c
lib/ext2fs/expanddir.c
lib/ext2fs/ext2_err.et.in
lib/ext2fs/ext2_ext_attr.h
lib/ext2fs/ext2_fs.h
lib/ext2fs/ext2fs.h
lib/ext2fs/ext2fsP.h
lib/ext2fs/ext3_extents.h
lib/ext2fs/ext_attr.c
lib/ext2fs/extent.c
lib/ext2fs/freefs.c
lib/ext2fs/gen_bitmap64.c
lib/ext2fs/gen_crc32ctable.c
lib/ext2fs/get_num_dirs.c [new file with mode: 0644]
lib/ext2fs/get_pathname.c
lib/ext2fs/initialize.c
lib/ext2fs/inode.c
lib/ext2fs/jfs_compat.h
lib/ext2fs/kernel-jbd.h
lib/ext2fs/link.c
lib/ext2fs/lookup.c
lib/ext2fs/mkdir.c
lib/ext2fs/mmp.c
lib/ext2fs/newdir.c
lib/ext2fs/openfs.c
lib/ext2fs/progress.c
lib/ext2fs/rw_bitmaps.c
lib/ext2fs/swapfs.c
lib/ext2fs/tst_super_size.c
lib/ext2fs/unlink.c
misc/dumpe2fs.c
misc/mke2fs.c
misc/mke2fs.conf.in
misc/tune2fs.c
resize/resize2fs.c
tests/f_mmp/script
tests/f_mmp_garbage/script
tests/filter.sed
tests/m_mmp/script
tests/t_mmp_1on/script
tests/t_mmp_2off/script
tests/t_uninit_bg_rm/expect [new file with mode: 0644]
tests/t_uninit_bg_rm/script [new file with mode: 0644]
version.h

index e51b1f5..fea2b63 100644 (file)
@@ -1,5 +1,24 @@
+E2fsprogs 1.43-WIP (July 8, 2013) -- 38cc555a5fc
+=================================
+
+Add support for the ext4 metadata checksum feature.
+
+Check to make sure file system features which can not be supported by
+HURD are not enabled if the file system is created to be
+HURD-compatible.
+
+
+Programmer's Notes
+------------------
+
+Reduce the use of libc functions in libext2fs that may not be present
+in the boot loader environment, at least for those functions that are
+needed by boot loadsers such as yaboot.
+
+Support for the MMP feature can now be disabled at compile time.
+
+
 E2fsprogs 1.42.8 (June 20, 2013)
-================================
 
 As a part of mke2fs's option parsing cleanup, the use of the -R option
 will give a warning that it is depreated (it has been so documented
index 738bd89..2338fbe 100755 (executable)
--- a/configure
+++ b/configure
@@ -852,6 +852,9 @@ enable_fsck
 enable_e2initrd_helper
 enable_tls
 enable_uuidd
+enable_mmp
+enable_bmap_stats
+enable_bmap_stats_ops
 enable_nls
 with_gnu_ld
 enable_rpath
@@ -1508,6 +1511,9 @@ Optional Features:
   --enable-e2initrd-helper build e2initrd-helper program
   --disable-tls           disable use of thread local support
   --disable-uuidd         disable building the uuid daemon
+  --disable-mmp           disable support mmp, Multi Mount Protection
+  --disable-bmap-stats    disable collection of bitmap stats.
+  --enable-bmap-stats-ops enable collection of additional bitmap stats
   --disable-nls           do not use Native Language Support
   --disable-rpath         do not hardcode runtime library paths
 
@@ -5606,6 +5612,77 @@ $as_echo "Building uuidd by default" >&6; }
 fi
 
 
+
+# Check whether --enable-mmp was given.
+if test "${enable_mmp+set}" = set; then :
+  enableval=$enable_mmp; if test "$enableval" = "no"
+then
+       { $as_echo "$as_me:${as_lineno-$LINENO}: result: Disabling mmp support" >&5
+$as_echo "Disabling mmp support" >&6; }
+else
+       { $as_echo "$as_me:${as_lineno-$LINENO}: result: Enabling mmp support" >&5
+$as_echo "Enabling mmp support" >&6; }
+       $as_echo "#define CONFIG_MMP 1" >>confdefs.h
+
+fi
+
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: Enabling mmp support by default" >&5
+$as_echo "Enabling mmp support by default" >&6; }
+$as_echo "#define CONFIG_MMP 1" >>confdefs.h
+
+
+fi
+
+
+# Check whether --enable-bmap-stats was given.
+if test "${enable_bmap_stats+set}" = set; then :
+  enableval=$enable_bmap_stats; if test "$enableval" = "no"
+then
+       { $as_echo "$as_me:${as_lineno-$LINENO}: result: Disabling bitmap statistics support" >&5
+$as_echo "Disabling bitmap statistics support" >&6; }
+else
+       { $as_echo "$as_me:${as_lineno-$LINENO}: result: Enabling bitmap statistics support" >&5
+$as_echo "Enabling bitmap statistics support" >&6; }
+       $as_echo "#define ENABLE_BMAP_STATS 1" >>confdefs.h
+
+fi
+
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: Enabling bitmap statistics support by default" >&5
+$as_echo "Enabling bitmap statistics support by default" >&6; }
+$as_echo "#define ENABLE_BMAP_STATS 1" >>confdefs.h
+
+
+fi
+
+
+# Check whether --enable-bmap-stats-ops was given.
+if test "${enable_bmap_stats_ops+set}" = set; then :
+  enableval=$enable_bmap_stats_ops; if test "$enableval" = "no"
+then
+       { $as_echo "$as_me:${as_lineno-$LINENO}: result: Disabling additional bitmap statistics" >&5
+$as_echo "Disabling additional bitmap statistics" >&6; }
+else
+               if test "x${enable_bmap_stats}" = "xno"; then :
+  { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "Error --enable-bmap-stats-ops requires bmap-stats
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+
+       { $as_echo "$as_me:${as_lineno-$LINENO}: result: Enabling additional bitmap statistics" >&5
+$as_echo "Enabling additional bitmap statistics" >&6; }
+       $as_echo "#define ENABLE_BMAP_STATS_OPS 1" >>confdefs.h
+
+fi
+
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: Disabling additional bitmap statistics by default" >&5
+$as_echo "Disabling additional bitmap statistics by default" >&6; }
+
+fi
+
 MAKEFILE_LIBRARY=$srcdir/lib/Makefile.library
 
 GETTEXT_PACKAGE=e2fsprogs
index 87d73e4..049dc11 100644 (file)
@@ -785,6 +785,60 @@ AC_MSG_RESULT([Building uuidd by default])
 )
 AC_SUBST(UUIDD_CMT)
 dnl
+dnl handle --disable-mmp
+dnl
+AH_TEMPLATE([CONFIG_MMP], [Define to 1 to enable mmp support])
+AC_ARG_ENABLE([mmp],
+[  --disable-mmp           disable support mmp, Multi Mount Protection],
+if test "$enableval" = "no"
+then
+       AC_MSG_RESULT([Disabling mmp support])
+else
+       AC_MSG_RESULT([Enabling mmp support])
+       AC_DEFINE(CONFIG_MMP, 1)
+fi
+,
+AC_MSG_RESULT([Enabling mmp support by default])
+AC_DEFINE(CONFIG_MMP, 1)
+)
+dnl
+dnl handle --disable-bmap-stats
+dnl
+AH_TEMPLATE([ENABLE_BMAP_STATS], [Define to 1 to enable bitmap stats.])
+AC_ARG_ENABLE([bmap-stats],
+[  --disable-bmap-stats    disable collection of bitmap stats.],
+if test "$enableval" = "no"
+then
+       AC_MSG_RESULT([Disabling bitmap statistics support])
+else
+       AC_MSG_RESULT([Enabling bitmap statistics support])
+       AC_DEFINE(ENABLE_BMAP_STATS, 1)
+fi
+,
+AC_MSG_RESULT([Enabling bitmap statistics support by default])
+AC_DEFINE(ENABLE_BMAP_STATS, 1)
+)
+dnl
+dnl handle --enable-bmap-stats-ops
+dnl
+AH_TEMPLATE([ENABLE_BMAP_STATS_OPS], [Define to 1 to enable bitmap stats.])
+AC_ARG_ENABLE([bmap-stats-ops],
+[  --enable-bmap-stats-ops enable collection of additional bitmap stats],
+if test "$enableval" = "no"
+then
+       AC_MSG_RESULT([Disabling additional bitmap statistics])
+else
+       dnl There has to be a better way!
+       AS_IF([test "x${enable_bmap_stats}" = "xno"],
+        AC_MSG_FAILURE([Error --enable-bmap-stats-ops requires bmap-stats]))
+
+       AC_MSG_RESULT([Enabling additional bitmap statistics])
+       AC_DEFINE(ENABLE_BMAP_STATS_OPS, 1)
+fi
+,
+AC_MSG_RESULT([Disabling additional bitmap statistics by default])
+)
+dnl
 dnl
 dnl
 MAKEFILE_LIBRARY=$srcdir/lib/Makefile.library
index c54af0d..12a5d8c 100644 (file)
@@ -1,3 +1,9 @@
+e2fsprogs (1.43~WIP-2013-07-08-1) unstable; urgency=low
+
+  * Add metadata checksum feature
+
+ -- Theodore Y. Ts'o <tytso@mit.edu>  Mon, 8 Jul 2013 16:13:56 -0400
+
 e2fsprogs (1.42.8-1) unstable; urgency=low
 
   * New upstream version
@@ -92,6 +98,12 @@ e2fsprogs (1.42.7-1) unstable; urgency=low
 
  -- Theodore Y. Ts'o <tytso@mit.edu>  Tue, 21 Jan 2013 21:52:58 -0500
 
+e2fsprogs (1.43~WIP-2012-09-22-1) unstable; urgency=low
+
+  * Add metadata checksum feature
+
+ -- Theodore Y. Ts'o <tytso@mit.edu>  Sat, 22 Sep 2012 21:50:20 -0400
+
 e2fsprogs (1.42.6-1) unstable; urgency=low
 
   * New upstream version
index 5784a25..eea3500 100644 (file)
@@ -46,6 +46,7 @@ libext2fs.so.2 e2fslibs #MINVER#
  ext2fs_add_journal_device@Base 1.37
  ext2fs_add_journal_inode@Base 1.37
  ext2fs_adjust_ea_refcount2@Base 1.42
+ ext2fs_adjust_ea_refcount3@Base 1.43~WIP-2012-08-01
  ext2fs_adjust_ea_refcount@Base 1.37
  ext2fs_alloc_block2@Base 1.42
  ext2fs_alloc_block@Base 1.37
@@ -87,6 +88,9 @@ libext2fs.so.2 e2fslibs #MINVER#
  ext2fs_blkmap64_rbtree@Base 1.42.1
  ext2fs_block_alloc_stats2@Base 1.42
  ext2fs_block_alloc_stats@Base 1.37
+ ext2fs_block_bitmap_checksum@Base 1.43~WIP-2012-08-01
+ ext2fs_block_bitmap_csum_set@Base 1.43~WIP-2012-08-01
+ ext2fs_block_bitmap_csum_verify@Base 1.43~WIP-2012-08-01
  ext2fs_block_bitmap_loc@Base 1.42
  ext2fs_block_bitmap_loc_set@Base 1.42
  ext2fs_block_iterate2@Base 1.37
@@ -120,7 +124,9 @@ libext2fs.so.2 e2fslibs #MINVER#
  ext2fs_copy_generic_bitmap@Base 1.41.0
  ext2fs_copy_generic_bmap@Base 1.42
  ext2fs_crc16@Base 1.41.1
- ext2fs_crc32c_be@Base 1.42
+ ext2fs_crc32_be@Base 1.43~WIP-2012-08-01
+#Removed in e2fsprogs 1.43
+#ext2fs_crc32c_be@Base 1.42
  ext2fs_crc32c_le@Base 1.42
  ext2fs_create_icount2@Base 1.37
  ext2fs_create_icount@Base 1.37
@@ -140,14 +146,22 @@ libext2fs.so.2 e2fslibs #MINVER#
  ext2fs_default_journal_size@Base 1.40
  ext2fs_descriptor_block_loc2@Base 1.42
  ext2fs_descriptor_block_loc@Base 1.37
+ ext2fs_dir_block_csum_set@Base 1.43~WIP-2012-08-01
+ ext2fs_dir_block_csum_verify@Base 1.43~WIP-2012-08-01
  ext2fs_dir_iterate2@Base 1.37
  ext2fs_dir_iterate@Base 1.37
+ ext2fs_dirent_csum_verify@Base 1.43~WIP-2012-08-01
+ ext2fs_dirent_has_tail@Base 1.43~WIP-2012-08-01
  ext2fs_dirhash@Base 1.37
  ext2fs_div64_ceil@Base 1.42
  ext2fs_div_ceil@Base 1.40
  ext2fs_dup_handle@Base 1.37
  ext2fs_expand_dir@Base 1.37
+ ext2fs_ext_attr_block_csum_set@Base 1.43~WIP-2012-08-01
+ ext2fs_ext_attr_block_csum_verify@Base 1.43~WIP-2012-08-01
  ext2fs_ext_attr_hash_entry@Base 1.41.0
+ ext2fs_extent_block_csum_set@Base 1.43~WIP-2012-08-01
+ ext2fs_extent_block_csum_verify@Base 1.43~WIP-2012-08-01
  ext2fs_extent_delete@Base 1.41.0
  ext2fs_extent_fix_parents@Base 1.42.7
  ext2fs_extent_free@Base 1.41.0
@@ -243,6 +257,7 @@ libext2fs.so.2 e2fslibs #MINVER#
  ext2fs_get_device_size2@Base 1.41.4
  ext2fs_get_device_size@Base 1.37
  ext2fs_get_dio_alignment@Base 1.42.3
+ ext2fs_get_dx_countlimit@Base 1.43~WIP-2012-08-01
  ext2fs_get_free_blocks2@Base 1.42
  ext2fs_get_free_blocks@Base 1.37
  ext2fs_get_generic_bitmap_end@Base 1.41.0
@@ -293,12 +308,19 @@ libext2fs.so.2 e2fslibs #MINVER#
  ext2fs_image_inode_write@Base 1.37
  ext2fs_image_super_read@Base 1.37
  ext2fs_image_super_write@Base 1.37
+ ext2fs_init_csum_seed@Base 1.43~WIP-2012-08-01
  ext2fs_init_dblist@Base 1.37
  ext2fs_initialize@Base 1.37
+ ext2fs_initialize_dirent_tail@Base 1.43~WIP-2012-08-01
  ext2fs_inode_alloc_stats2@Base 1.37
  ext2fs_inode_alloc_stats@Base 1.37
+ ext2fs_inode_bitmap_checksum@Base 1.43~WIP-2012-08-01
+ ext2fs_inode_bitmap_csum_set@Base 1.43~WIP-2012-08-01
+ ext2fs_inode_bitmap_csum_verify@Base 1.43~WIP-2012-08-01
  ext2fs_inode_bitmap_loc@Base 1.42
  ext2fs_inode_bitmap_loc_set@Base 1.42
+ ext2fs_inode_csum_set@Base 1.43~WIP-2012-08-01
+ ext2fs_inode_csum_verify@Base 1.43~WIP-2012-08-01
  ext2fs_inode_data_blocks2@Base 1.42
  ext2fs_inode_data_blocks@Base 1.37
  ext2fs_inode_has_valid_blocks@Base 1.37
@@ -330,11 +352,14 @@ libext2fs.so.2 e2fslibs #MINVER#
  ext2fs_mem_is_zero@Base 1.42
  ext2fs_mkdir@Base 1.37
  ext2fs_mmp_clear@Base 1.42
+ ext2fs_mmp_csum_set@Base 1.43~WIP-2012-08-01
+ ext2fs_mmp_csum_verify@Base 1.43~WIP-2012-08-01
  ext2fs_mmp_init@Base 1.42
  ext2fs_mmp_new_seq@Base 1.42
  ext2fs_mmp_read@Base 1.42
  ext2fs_mmp_start@Base 1.42
  ext2fs_mmp_stop@Base 1.42
+ ext2fs_mmp_update2@Base 1.43~WIP-2012-08-01
  ext2fs_mmp_update@Base 1.42
  ext2fs_mmp_write@Base 1.42
  ext2fs_namei@Base 1.37
@@ -346,6 +371,7 @@ libext2fs.so.2 e2fslibs #MINVER#
  ext2fs_new_inode@Base 1.37
  ext2fs_numeric_progress_close@Base 1.42
  ext2fs_numeric_progress_init@Base 1.42
+ ext2fs_numeric_progress_ops@Base 1.43~WIP-2012-08-01
  ext2fs_numeric_progress_update@Base 1.42
  ext2fs_open2@Base 1.37
  ext2fs_open@Base 1.37
@@ -374,8 +400,10 @@ libext2fs.so.2 e2fslibs #MINVER#
  ext2fs_read_block_bitmap@Base 1.37
  ext2fs_read_dir_block2@Base 1.37
  ext2fs_read_dir_block3@Base 1.42
+ ext2fs_read_dir_block4@Base 1.43~WIP-2012-08-01
  ext2fs_read_dir_block@Base 1.37
  ext2fs_read_ext_attr2@Base 1.42
+ ext2fs_read_ext_attr3@Base 1.43~WIP-2012-08-01
  ext2fs_read_ext_attr@Base 1.37
  ext2fs_read_ind_block@Base 1.37
  ext2fs_read_inode@Base 1.37
@@ -412,6 +440,8 @@ libext2fs.so.2 e2fslibs #MINVER#
  ext2fs_stat@Base 1.42
  ext2fs_super_and_bgd_loc2@Base 1.42
  ext2fs_super_and_bgd_loc@Base 1.37
+ ext2fs_superblock_csum_set@Base 1.43~WIP-2012-08-01
+ ext2fs_superblock_csum_verify@Base 1.43~WIP-2012-08-01
  ext2fs_swab16@Base 1.37
  ext2fs_swab32@Base 1.37
  ext2fs_swab64@Base 1.40
@@ -508,6 +538,7 @@ libext2fs.so.2 e2fslibs #MINVER#
  ext2fs_unmark_valid@Base 1.37
  ext2fs_update_bb_inode@Base 1.37
  ext2fs_update_dynamic_rev@Base 1.37
+ ext2fs_verify_csum_type@Base 1.43~WIP-2012-08-01
  ext2fs_warn_bitmap2@Base 1.37
  ext2fs_warn_bitmap32@Base 1.42
  ext2fs_warn_bitmap@Base 1.37
@@ -516,8 +547,10 @@ libext2fs.so.2 e2fslibs #MINVER#
  ext2fs_write_block_bitmap@Base 1.37
  ext2fs_write_dir_block2@Base 1.37
  ext2fs_write_dir_block3@Base 1.42
+ ext2fs_write_dir_block4@Base 1.43~WIP-2012-08-01
  ext2fs_write_dir_block@Base 1.37
  ext2fs_write_ext_attr2@Base 1.42
+ ext2fs_write_ext_attr3@Base 1.43~WIP-2012-08-01
  ext2fs_write_ext_attr@Base 1.37
  ext2fs_write_ind_block@Base 1.37
  ext2fs_write_inode@Base 1.37
index e563b0d..65a30d5 100644 (file)
@@ -8,7 +8,7 @@ debugfs \- ext2/ext3/ext4 file system debugger
 .SH SYNOPSIS
 .B debugfs
 [
-.B \-DVwci
+.B \-DVwcin
 ]
 [
 .B \-b
@@ -48,6 +48,11 @@ file system (e.g /dev/hdXX).
 Specifies that the file system should be opened in read-write mode.
 Without this option, the file system is opened in read-only mode.
 .TP
+.I \-n
+Disables metadata checksum verification.  This should only be used if
+you believe the metadata to be correct despite the complaints of
+e2fsprogs.
+.TP
 .I \-c
 Specifies that the file system should be opened in catastrophic mode, in
 which the inode and group bitmaps are not read initially.  This can be
@@ -404,13 +409,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 
index 902ee66..4ecf474 100644 (file)
@@ -371,8 +371,7 @@ void do_show_super_stats(int argc, char *argv[])
                return;
        }
 
-       gdt_csum = EXT2_HAS_RO_COMPAT_FEATURE(current_fs->super,
-                                             EXT4_FEATURE_RO_COMPAT_GDT_CSUM);
+       gdt_csum = ext2fs_has_group_desc_csum(current_fs);
        for (i = 0; i < current_fs->group_desc_count; i++) {
                fprintf(out, " Group %2d: block bitmap at %llu, "
                        "inode bitmap at %llu, "
@@ -817,6 +816,19 @@ void internal_dump_inode(FILE *out, const char *prefix,
        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 (current_fs->super->s_creator_os == EXT2_OS_LINUX &&
+           current_fs->super->s_feature_ro_compat &
+               EXT4_FEATURE_RO_COMPAT_METADATA_CSUM) {
+               __u32 crc = inode->i_checksum_lo;
+               if (is_large_inode &&
+                   large_inode->i_extra_isize >=
+                               (offsetof(struct ext2_inode_large,
+                                         i_checksum_hi) -
+                                EXT2_GOOD_OLD_INODE_SIZE))
+                       crc |= ((__u32)large_inode->i_checksum_hi) << 16;
+               fprintf(out, "Inode checksum: 0x%08x\n", crc);
+       }
+
        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);
@@ -1969,9 +1981,9 @@ static int rmdir_proc(ext2_ino_t dir EXT2FS_ATTR((unused)),
 
        if (dirent->inode == 0)
                return 0;
-       if (((dirent->name_len&0xFF) == 1) && (dirent->name[0] == '.'))
+       if ((ext2fs_dirent_name_len(dirent) == 1) && (dirent->name[0] == '.'))
                return 0;
-       if (((dirent->name_len&0xFF) == 2) && (dirent->name[0] == '.') &&
+       if ((ext2fs_dirent_name_len(dirent) == 2) && (dirent->name[0] == '.') &&
            (dirent->name[1] == '.')) {
                rds->parent = dirent->inode;
                return 0;
@@ -2304,6 +2316,7 @@ try_again:
 
 void do_dump_mmp(int argc EXT2FS_ATTR((unused)), char *argv[])
 {
+#if CONFIG_MMP
        struct ext2_super_block *sb;
        struct mmp_struct *mmp_s;
        time_t t;
@@ -2342,6 +2355,11 @@ void do_dump_mmp(int argc EXT2FS_ATTR((unused)), char *argv[])
        fprintf(stdout, "node_name: %s\n", mmp_s->mmp_nodename);
        fprintf(stdout, "device_name: %s\n", mmp_s->mmp_bdevname);
        fprintf(stdout, "magic: 0x%x\n", mmp_s->mmp_magic);
+       fprintf(stdout, "checksum: 0x%08x\n", mmp_s->mmp_checksum);
+#else
+       fprintf(stdout, "MMP is unsupported, please recompile with "
+                       "--enable-mmp\n");
+#endif
 }
 
 static int source_file(const char *cmd_file, int ss_idx)
@@ -2406,9 +2424,9 @@ int main(int argc, char **argv)
        int             catastrophic = 0;
        char            *data_filename = 0;
 #ifdef READ_ONLY
-       const char      *opt_string = "icR:f:b:s:Vd:D";
+       const char      *opt_string = "nicR:f:b:s:Vd:D";
 #else
-       const char      *opt_string = "iwcR:f:b:s:Vd:D";
+       const char      *opt_string = "niwcR:f:b:s:Vd:D";
 #endif
 
        if (debug_prog_name == 0)
@@ -2435,6 +2453,9 @@ int main(int argc, char **argv)
                case 'i':
                        open_flags |= EXT2_FLAG_IMAGE_FILE;
                        break;
+               case 'n':
+                       open_flags |= EXT2_FLAG_IGNORE_CSUM_ERRORS;
+                       break;
 #ifndef READ_ONLY
                case 'w':
                        open_flags |= EXT2_FLAG_RW;
index 9409ab6..c75b9f1 100644 (file)
@@ -308,7 +308,7 @@ static int rdump_dirent(struct ext2_dir_entry *dirent,
        const char *dumproot = private;
        struct ext2_inode inode;
 
-       thislen = dirent->name_len & 0xFF;
+       thislen = ext2fs_dirent_name_len(dirent);
        strncpy(name, dirent->name, thislen);
        name[thislen] = 0;
 
index 0adea40..6219d7c 100644 (file)
@@ -183,7 +183,7 @@ static int filefrag_dir_proc(ext2_ino_t dir EXT2FS_ATTR((unused)),
        if (entry == DIRENT_DELETED_FILE)
                return 0;
 
-       thislen = dirent->name_len & 0xFF;
+       thislen = ext2fs_dirent_name_len(dirent);
        strncpy(name, dirent->name, thislen);
        name[thislen] = '\0';
        ino = dirent->inode;
index 24f8250..4f0118d 100644 (file)
@@ -44,6 +44,11 @@ static void htree_dump_leaf_node(ext2_filsys fs, ext2_ino_t ino,
        ext2_dirhash_t  hash, minor_hash;
        unsigned int    rec_len;
        int             hash_alg;
+       int             csum_size = 0;
+
+       if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+                                      EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
+               csum_size = sizeof(struct ext2_dir_entry_tail);
 
        errcode = ext2fs_bmap2(fs, ino, inode, buf, 0, blk, 0, &pblk);
        if (errcode) {
@@ -53,7 +58,7 @@ static void htree_dump_leaf_node(ext2_filsys fs, ext2_ino_t ino,
        }
 
        fprintf(pager, "Reading directory block %llu, phys %llu\n", blk, pblk);
-       errcode = ext2fs_read_dir_block2(current_fs, pblk, buf, 0);
+       errcode = ext2fs_read_dir_block4(current_fs, pblk, buf, 0, ino);
        if (errcode) {
                com_err("htree_dump_leaf_node", errcode,
                        "while reading block %llu (%llu)\n",
@@ -74,15 +79,15 @@ static void htree_dump_leaf_node(ext2_filsys fs, ext2_ino_t ino,
                                (unsigned long) blk);
                        return;
                }
+               thislen = ext2fs_dirent_name_len(dirent);
                if (((offset + rec_len) > fs->blocksize) ||
                    (rec_len < 8) ||
                    ((rec_len % 4) != 0) ||
-                   ((((unsigned) dirent->name_len & 0xFF)+8) > rec_len)) {
+                   (thislen + 8 > rec_len)) {
                        fprintf(pager, "Corrupted directory block (%llu)!\n",
                                blk);
                        break;
                }
-               thislen = dirent->name_len & 0xFF;
                strncpy(name, dirent->name, thislen);
                name[thislen] = '\0';
                errcode = ext2fs_dirhash(hash_alg, name,
@@ -91,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");
@@ -120,8 +140,9 @@ static void htree_dump_int_node(ext2_filsys fs, ext2_ino_t ino,
 {
        struct ext2_dx_countlimit       limit;
        struct ext2_dx_entry            e;
+       struct ext2_dx_tail             *tail;
        int                             hash, i;
-
+       int                             remainder;
 
        limit = *((struct ext2_dx_countlimit *) ent);
        limit.count = ext2fs_le16_to_cpu(limit.count);
@@ -130,6 +151,20 @@ static void htree_dump_int_node(ext2_filsys fs, ext2_ino_t ino,
        fprintf(pager, "Number of entries (count): %d\n", limit.count);
        fprintf(pager, "Number of entries (limit): %d\n", limit.limit);
 
+       remainder = fs->blocksize - (limit.limit *
+                                    sizeof(struct ext2_dx_entry));
+       if (ent == (struct ext2_dx_entry *)(rootnode + 1))
+               remainder -= sizeof(struct ext2_dx_root_info) + 24;
+       else
+               remainder -= 8;
+       if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+                                      EXT4_FEATURE_RO_COMPAT_METADATA_CSUM) &&
+           remainder == sizeof(struct ext2_dx_tail)) {
+               tail = (struct ext2_dx_tail *)(ent + limit.limit);
+               fprintf(pager, "Checksum: 0x%08x\n",
+                       ext2fs_le32_to_cpu(tail->dt_checksum));
+       }
+
        for (i=0; i < limit.count; i++) {
                hash = i ? ext2fs_le32_to_cpu(ent[i].hash) : 0;
                fprintf(pager, "Entry #%d: Hash 0x%08x%s, block %u\n", i,
@@ -393,7 +428,7 @@ static int search_dir_block(ext2_filsys fs, blk64_t *blocknr,
                        return BLOCK_ABORT;
                }
                if (dirent->inode &&
-                   p->len == (dirent->name_len & 0xFF) &&
+                   p->len == ext2fs_dirent_name_len(dirent) &&
                    strncmp(p->search_name, dirent->name,
                            p->len) == 0) {
                        printf("Entry found at logical block %lld, "
index a61d553..db085cb 100644 (file)
@@ -501,7 +501,7 @@ static void dump_descriptor_block(FILE *out_file,
                        break;
 
                tag_block = be32_to_cpu(tag->t_blocknr);
-               tag_flags = be32_to_cpu(tag->t_flags);
+               tag_flags = be16_to_cpu(tag->t_flags);
 
                if (!(tag_flags & JFS_FLAG_SAME_UUID))
                        offset += 16;
index b4036de..69c7897 100644 (file)
@@ -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,8 +59,9 @@ 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;
+       thislen = ext2fs_dirent_name_len(dirent);
        strncpy(name, dirent->name, thislen);
        name[thislen] = '\0';
        ino = dirent->inode;
@@ -99,8 +99,14 @@ 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   ",
+                       ext2fs_dirent_file_type(dirent),
                        inode_uid(inode), inode_gid(inode));
                if (LINUX_S_ISDIR(inode.i_mode))
                        fprintf(ls->f, "%5d", inode.i_size);
@@ -108,8 +114,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 +138,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 +146,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 +180,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);
index 58f3a50..5d9b5d2 100644 (file)
@@ -45,7 +45,7 @@ static int ncheck_proc(struct ext2_dir_entry *dirent,
        struct inode_walk_struct *iw = (struct inode_walk_struct *) private;
        struct ext2_inode inode;
        errcode_t       retval;
-       int             filetype = dirent->name_len >> 8;
+       int             filetype = ext2fs_dirent_file_type(dirent);
        int             i;
 
        iw->position++;
@@ -66,11 +66,13 @@ static int ncheck_proc(struct ext2_dir_entry *dirent,
                        if (iw->parent)
                                printf("%u\t%s/%.*s", iw->iarray[i],
                                       iw->parent,
-                                      (dirent->name_len & 0xFF), dirent->name);
+                                      ext2fs_dirent_name_len(dirent),
+                                      dirent->name);
                        else
                                printf("%u\t<%u>/%.*s", iw->iarray[i],
                                       iw->dir,
-                                      (dirent->name_len & 0xFF), dirent->name);
+                                      ext2fs_dirent_name_len(dirent),
+                                      dirent->name);
                        if (iw->check_dirent && filetype) {
                                if (!debugfs_read_inode(dirent->inode, &inode,
                                                        "ncheck") &&
index b09e2f8..aad1cd8 100644 (file)
@@ -151,6 +151,7 @@ static struct field_set_info super_fields[] = {
        { "grp_quota_inum", &set_sb.s_grp_quota_inum, NULL, 4, parse_uint },
        { "overhead_blocks", &set_sb.s_overhead_blocks, NULL, 4, parse_uint },
        { "checksum", &set_sb.s_checksum, NULL, 4, parse_uint },
+       { "checksum_type", &set_sb.s_checksum_type, NULL, 1, parse_uint },
        { 0, 0, 0, 0 }
 };
 
@@ -255,6 +256,7 @@ static struct field_set_info mmp_fields[] = {
        { "bdevname", &set_mmp.mmp_bdevname, NULL, sizeof(set_mmp.mmp_bdevname),
                parse_string },
        { "check_interval", &set_mmp.mmp_check_interval, NULL, 2, parse_uint },
+       { "checksum", &set_mmp.mmp_checksum, NULL, 4, parse_uint },
 };
 
 static int check_suffix(const char *field)
@@ -766,6 +768,7 @@ static errcode_t parse_mmp_clear(struct field_set_info *info,
 
 void do_set_mmp_value(int argc, char *argv[])
 {
+#ifdef CONFIG_MMP
        const char *usage = "<field> <value>\n"
                "\t\"set_mmp_value -l\" will list the names of "
                "MMP fields\n\twhich can be set.";
@@ -820,5 +823,9 @@ void do_set_mmp_value(int argc, char *argv[])
                                 &set_mmp);
                *mmp_s = set_mmp;
        }
+#else
+       fprintf(stdout, "MMP is unsupported, please recompile with "
+                       "--enable-mmp\n");
+#endif
 }
 
index 8e1c891..6ecfcd9 100644 (file)
@@ -65,7 +65,7 @@ COMPILE_ET=$(top_builddir)/lib/et/compile_et --build-tree
 #
 #MCHECK= -DMCHECK
 
-OBJS= crc32.o dict.o unix.o e2fsck.o super.o pass1.o pass1b.o pass2.o \
+OBJS= dict.o unix.o e2fsck.o super.o pass1.o pass1b.o pass2.o \
        pass3.o pass4.o pass5.o journal.o badblocks.o util.o dirinfo.o \
        dx_dirinfo.o ehandler.o problem.o message.o quota.o recovery.o \
        region.o revoke.o ea_refcount.o rehash.o profile.o prof_err.o \
@@ -79,12 +79,10 @@ PROFILED_OBJS= profiled/dict.o profiled/unix.o profiled/e2fsck.o \
        profiled/message.o profiled/problem.o profiled/quota.o \
        profiled/recovery.o profiled/region.o profiled/revoke.o \
        profiled/ea_refcount.o profiled/rehash.o profiled/profile.o \
-       profiled/crc32.o profiled/prof_err.o profiled/logfile.o \
+       profiled/prof_err.o profiled/logfile.o \
        profiled/sigcatcher.o
 
 SRCS= $(srcdir)/e2fsck.c \
-       $(srcdir)/crc32.c \
-       $(srcdir)/gen_crc32table.c \
        $(srcdir)/dict.c \
        $(srcdir)/super.c \
        $(srcdir)/pass1.c \
@@ -135,15 +133,6 @@ e2fsck.profiled: $(OBJS)  $(PROFILED_DEPLIBS)
        $(Q) $(LD) $(ALL_LDFLAGS) -g -pg -o e2fsck.profiled $(PROFILED_OBJS) \
                $(PROFILED_LIBS) 
 
-gen_crc32table: $(srcdir)/gen_crc32table.c
-       $(E) "  CC $@"
-       $(Q) $(BUILD_CC) $(BUILD_CFLAGS) $(BUILD_LDFLAGS) -o gen_crc32table \
-               $(srcdir)/gen_crc32table.c
-
-crc32table.h: gen_crc32table
-       $(E) "  GEN32TABLE $@"
-       $(Q) ./gen_crc32table > crc32table.h
-
 tst_sigcatcher: $(srcdir)/sigcatcher.c sigcatcher.o
        $(E) "  CC $@"
        $(Q) $(CC) $(BUILD_LDFLAGS) $(ALL_CFLAGS) $(RDYNAMIC) \
@@ -155,10 +144,6 @@ tst_problem: $(srcdir)/problem.c $(srcdir)/problem.h $(LIBEXT2FS) \
                $(srcdir)/problem.c -DUNITTEST $(LIBEXT2FS) $(LIBCOM_ERR) \
                $(LIBINTL)
 
-tst_crc32: $(srcdir)/crc32.c $(LIBEXT2FS) $(DEPLIBCOM_ERR)
-       $(Q) $(CC) $(BUILD_LDFLAGS) $(ALL_CFLAGS) -o tst_crc32 $(srcdir)/crc32.c \
-               -DUNITTEST $(LIBEXT2FS) $(LIBCOM_ERR)
-
 tst_refcount: ea_refcount.c $(DEPLIBCOM_ERR)
        $(E) "  LD $@"
        $(Q) $(CC) -o tst_refcount $(srcdir)/ea_refcount.c \
@@ -174,10 +159,9 @@ tst_region: region.c $(DEPLIBCOM_ERR)
        $(Q) $(CC) -o tst_region $(srcdir)/region.c \
                $(ALL_CFLAGS) -DTEST_PROGRAM $(LIBCOM_ERR)
 
-check:: tst_refcount tst_region tst_crc32 tst_problem
+check:: tst_refcount tst_region tst_problem
        LD_LIBRARY_PATH=$(LIB) DYLD_LIBRARY_PATH=$(LIB) ./tst_refcount
        LD_LIBRARY_PATH=$(LIB) DYLD_LIBRARY_PATH=$(LIB) ./tst_region
-       LD_LIBRARY_PATH=$(LIB) DYLD_LIBRARY_PATH=$(LIB) ./tst_crc32
        LD_LIBRARY_PATH=$(LIB) DYLD_LIBRARY_PATH=$(LIB) ./tst_problem
 
 extend: extend.o
@@ -274,9 +258,8 @@ uninstall:
 clean:
        $(RM) -f $(PROGS) \#* *\# *.s *.o *.a *~ core e2fsck.static \
                e2fsck.shared e2fsck.profiled flushb e2fsck.8 \
-               tst_problem tst_crc32 tst_region tst_refcount gen_crc32table \
-               crc32table.h e2fsck.conf.5 prof_err.c prof_err.h \
-               test_profile
+               tst_problem tst_region tst_refcount e2fsck.conf.5 \
+               prof_err.c prof_err.h test_profile
        $(RM) -rf profiled
 
 mostlyclean: clean
@@ -299,18 +282,6 @@ e2fsck.o: $(srcdir)/e2fsck.c $(top_builddir)/lib/config.h \
  $(top_srcdir)/lib/quota/quotaio.h $(top_srcdir)/lib/quota/dqblk_v2.h \
  $(top_srcdir)/lib/quota/quotaio_tree.h $(top_srcdir)/lib/../e2fsck/dict.h \
  $(srcdir)/problem.h
-crc32.o: $(srcdir)/crc32.c $(top_builddir)/lib/config.h \
- $(top_builddir)/lib/dirpaths.h $(srcdir)/e2fsck.h \
- $(top_srcdir)/lib/ext2fs/ext2_fs.h $(top_builddir)/lib/ext2fs/ext2_types.h \
- $(top_srcdir)/lib/ext2fs/ext2fs.h $(top_srcdir)/lib/ext2fs/ext3_extents.h \
- $(top_srcdir)/lib/et/com_err.h $(top_srcdir)/lib/ext2fs/ext2_io.h \
- $(top_builddir)/lib/ext2fs/ext2_err.h \
- $(top_srcdir)/lib/ext2fs/ext2_ext_attr.h $(top_srcdir)/lib/ext2fs/bitops.h \
- $(srcdir)/profile.h prof_err.h $(top_srcdir)/lib/quota/mkquota.h \
- $(top_srcdir)/lib/quota/quotaio.h $(top_srcdir)/lib/quota/dqblk_v2.h \
- $(top_srcdir)/lib/quota/quotaio_tree.h $(top_srcdir)/lib/../e2fsck/dict.h \
- $(srcdir)/crc32defs.h crc32table.h
-gen_crc32table.o: $(srcdir)/gen_crc32table.c $(srcdir)/crc32defs.h
 dict.o: $(srcdir)/dict.c $(top_builddir)/lib/config.h \
  $(top_builddir)/lib/dirpaths.h $(srcdir)/dict.h
 super.o: $(srcdir)/super.c $(top_builddir)/lib/config.h \
diff --git a/e2fsck/crc32.c b/e2fsck/crc32.c
deleted file mode 100644 (file)
index 0497a38..0000000
+++ /dev/null
@@ -1,570 +0,0 @@
-/*
- * crc32.c --- CRC32 function
- *
- * Copyright (C) 2008 Theodore Ts'o.
- *
- * %Begin-Header%
- * This file may be redistributed under the terms of the GNU Public
- * License.
- * %End-Header%
- */
-
-/*
- * Oct 15, 2000 Matt Domsch <Matt_Domsch@dell.com>
- * Nicer crc32 functions/docs submitted by linux@horizon.com.  Thanks!
- * Code was from the public domain, copyright abandoned.  Code was
- * subsequently included in the kernel, thus was re-licensed under the
- * GNU GPL v2.
- *
- * Oct 12, 2000 Matt Domsch <Matt_Domsch@dell.com>
- * Same crc32 function was used in 5 other places in the kernel.
- * I made one version, and deleted the others.
- * There are various incantations of crc32().  Some use a seed of 0 or ~0.
- * Some xor at the end with ~0.  The generic crc32() function takes
- * seed as an argument, and doesn't xor at the end.  Then individual
- * users can do whatever they need.
- *   drivers/net/smc9194.c uses seed ~0, doesn't xor with ~0.
- *   fs/jffs2 uses seed 0, doesn't xor with ~0.
- *   fs/partitions/efi.c uses seed ~0, xor's with ~0.
- *
- * This source code is licensed under the GNU General Public License,
- * Version 2.  See the file COPYING for more details.
- */
-
-#include "config.h"
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <ctype.h>
-
-#ifdef UNITTEST
-#undef ENABLE_NLS
-#endif
-#include "e2fsck.h"
-
-#include "crc32defs.h"
-#if CRC_LE_BITS == 8
-#define tole(x) __constant_cpu_to_le32(x)
-#define tobe(x) __constant_cpu_to_be32(x)
-#else
-#define tole(x) (x)
-#define tobe(x) (x)
-#endif
-#include "crc32table.h"
-
-#ifdef UNITTEST
-
-/**
- * crc32_le() - Calculate bitwise little-endian Ethernet AUTODIN II CRC32
- * @crc: seed value for computation.  ~0 for Ethernet, sometimes 0 for
- *     other uses, or the previous crc32 value if computing incrementally.
- * @p: pointer to buffer over which CRC is run
- * @len: length of buffer @p
- */
-__u32 crc32_le(__u32 crc, unsigned char const *p, size_t len);
-
-#if CRC_LE_BITS == 1
-/*
- * In fact, the table-based code will work in this case, but it can be
- * simplified by inlining the table in ?: form.
- */
-
-__u32 crc32_le(__u32 crc, unsigned char const *p, size_t len)
-{
-       int i;
-       while (len--) {
-               crc ^= *p++;
-               for (i = 0; i < 8; i++)
-                       crc = (crc >> 1) ^ ((crc & 1) ? CRCPOLY_LE : 0);
-       }
-       return crc;
-}
-#else                          /* Table-based approach */
-
-__u32 crc32_le(__u32 crc, unsigned char const *p, size_t len)
-{
-# if CRC_LE_BITS == 8
-       const __u32      *b =(__u32 *)p;
-       const __u32      *tab = crc32table_le;
-
-# ifdef WORDS_BIGENDIAN
-#  define DO_CRC(x) crc = tab[ ((crc >> 24) ^ (x)) & 255] ^ (crc<<8)
-# else
-#  define DO_CRC(x) crc = tab[ (crc ^ (x)) & 255 ] ^ (crc>>8)
-# endif
-
-       crc = __cpu_to_le32(crc);
-       /* Align it */
-       if(unlikely(((long)b)&3 && len)){
-               do {
-                       __u8 *p = (__u8 *)b;
-                       DO_CRC(*p++);
-                       b = (void *)p;
-               } while ((--len) && ((long)b)&3 );
-       }
-       if(likely(len >= 4)){
-               /* load data 32 bits wide, xor data 32 bits wide. */
-               size_t save_len = len & 3;
-               len = len >> 2;
-               --b; /* use pre increment below(*++b) for speed */
-               do {
-                       crc ^= *++b;
-                       DO_CRC(0);
-                       DO_CRC(0);
-                       DO_CRC(0);
-                       DO_CRC(0);
-               } while (--len);
-               b++; /* point to next byte(s) */
-               len = save_len;
-       }
-       /* And the last few bytes */
-       if(len){
-               do {
-                       __u8 *p = (__u8 *)b;
-                       DO_CRC(*p++);
-                       b = (void *)p;
-               } while (--len);
-       }
-
-       return __le32_to_cpu(crc);
-#undef ENDIAN_SHIFT
-#undef DO_CRC
-
-# elif CRC_LE_BITS == 4
-       while (len--) {
-               crc ^= *p++;
-               crc = (crc >> 4) ^ crc32table_le[crc & 15];
-               crc = (crc >> 4) ^ crc32table_le[crc & 15];
-       }
-       return crc;
-# elif CRC_LE_BITS == 2
-       while (len--) {
-               crc ^= *p++;
-               crc = (crc >> 2) ^ crc32table_le[crc & 3];
-               crc = (crc >> 2) ^ crc32table_le[crc & 3];
-               crc = (crc >> 2) ^ crc32table_le[crc & 3];
-               crc = (crc >> 2) ^ crc32table_le[crc & 3];
-       }
-       return crc;
-# endif
-}
-#endif
-
-#endif /* UNITTEST */
-
-/**
- * crc32_be() - Calculate bitwise big-endian Ethernet AUTODIN II CRC32
- * @crc: seed value for computation.  ~0 for Ethernet, sometimes 0 for
- *     other uses, or the previous crc32 value if computing incrementally.
- * @p: pointer to buffer over which CRC is run
- * @len: length of buffer @p
- */
-__u32 crc32_be(__u32 crc, unsigned char const *p, size_t len);
-
-#if CRC_BE_BITS == 1
-/*
- * In fact, the table-based code will work in this case, but it can be
- * simplified by inlining the table in ?: form.
- */
-
-__u32 crc32_be(__u32 crc, unsigned char const *p, size_t len)
-{
-       int i;
-       while (len--) {
-               crc ^= *p++ << 24;
-               for (i = 0; i < 8; i++)
-                       crc =
-                           (crc << 1) ^ ((crc & 0x80000000) ? CRCPOLY_BE :
-                                         0);
-       }
-       return crc;
-}
-
-#else                          /* Table-based approach */
-__u32 crc32_be(__u32 crc, unsigned char const *p, size_t len)
-{
-# if CRC_BE_BITS == 8
-       const __u32      *b =(const __u32 *)p;
-       const __u32      *tab = crc32table_be;
-
-# ifdef WORDS_BIGENDIAN
-#  define DO_CRC(x) crc = tab[ ((crc >> 24) ^ (x)) & 255] ^ (crc<<8)
-# else
-#  define DO_CRC(x) crc = tab[ (crc ^ (x)) & 255 ] ^ (crc>>8)
-# endif
-
-       crc = __cpu_to_be32(crc);
-       /* Align it */
-       if(unlikely(((long)b)&3 && len)){
-               do {
-                       const __u8 *q = (const __u8 *)b;
-                       DO_CRC(*q++);
-                       b = (const __u32 *)q;
-               } while ((--len) && ((long)b)&3 );
-       }
-       if(likely(len >= 4)){
-               /* load data 32 bits wide, xor data 32 bits wide. */
-               size_t save_len = len & 3;
-               len = len >> 2;
-               --b; /* use pre increment below(*++b) for speed */
-               do {
-                       crc ^= *++b;
-                       DO_CRC(0);
-                       DO_CRC(0);
-                       DO_CRC(0);
-                       DO_CRC(0);
-               } while (--len);
-               b++; /* point to next byte(s) */
-               len = save_len;
-       }
-       /* And the last few bytes */
-       if(len){
-               do {
-                       const __u8 *q = (const __u8 *)b;
-                       DO_CRC(*q++);
-                       b = (const void *)q;
-               } while (--len);
-       }
-       return __be32_to_cpu(crc);
-#undef ENDIAN_SHIFT
-#undef DO_CRC
-
-# elif CRC_BE_BITS == 4
-       while (len--) {
-               crc ^= *p++ << 24;
-               crc = (crc << 4) ^ crc32table_be[crc >> 28];
-               crc = (crc << 4) ^ crc32table_be[crc >> 28];
-       }
-       return crc;
-# elif CRC_BE_BITS == 2
-       while (len--) {
-               crc ^= *p++ << 24;
-               crc = (crc << 2) ^ crc32table_be[crc >> 30];
-               crc = (crc << 2) ^ crc32table_be[crc >> 30];
-               crc = (crc << 2) ^ crc32table_be[crc >> 30];
-               crc = (crc << 2) ^ crc32table_be[crc >> 30];
-       }
-       return crc;
-# endif
-}
-#endif
-
-/*
- * A brief CRC tutorial.
- *
- * A CRC is a long-division remainder.  You add the CRC to the message,
- * and the whole thing (message+CRC) is a multiple of the given
- * CRC polynomial.  To check the CRC, you can either check that the
- * CRC matches the recomputed value, *or* you can check that the
- * remainder computed on the message+CRC is 0.  This latter approach
- * is used by a lot of hardware implementations, and is why so many
- * protocols put the end-of-frame flag after the CRC.
- *
- * It's actually the same long division you learned in school, except that
- * - We're working in binary, so the digits are only 0 and 1, and
- * - When dividing polynomials, there are no carries.  Rather than add and
- *   subtract, we just xor.  Thus, we tend to get a bit sloppy about
- *   the difference between adding and subtracting.
- *
- * A 32-bit CRC polynomial is actually 33 bits long.  But since it's
- * 33 bits long, bit 32 is always going to be set, so usually the CRC
- * is written in hex with the most significant bit omitted.  (If you're
- * familiar with the IEEE 754 floating-point format, it's the same idea.)
- *
- * Note that a CRC is computed over a string of *bits*, so you have
- * to decide on the endianness of the bits within each byte.  To get
- * the best error-detecting properties, this should correspond to the
- * order they're actually sent.  For example, standard RS-232 serial is
- * little-endian; the most significant bit (sometimes used for parity)
- * is sent last.  And when appending a CRC word to a message, you should
- * do it in the right order, matching the endianness.
- *
- * Just like with ordinary division, the remainder is always smaller than
- * the divisor (the CRC polynomial) you're dividing by.  Each step of the
- * division, you take one more digit (bit) of the dividend and append it
- * to the current remainder.  Then you figure out the appropriate multiple
- * of the divisor to subtract to being the remainder back into range.
- * In binary, it's easy - it has to be either 0 or 1, and to make the
- * XOR cancel, it's just a copy of bit 32 of the remainder.
- *
- * When computing a CRC, we don't care about the quotient, so we can
- * throw the quotient bit away, but subtract the appropriate multiple of
- * the polynomial from the remainder and we're back to where we started,
- * ready to process the next bit.
- *
- * A big-endian CRC written this way would be coded like:
- * for (i = 0; i < input_bits; i++) {
- *     multiple = remainder & 0x80000000 ? CRCPOLY : 0;
- *     remainder = (remainder << 1 | next_input_bit()) ^ multiple;
- * }
- * Notice how, to get at bit 32 of the shifted remainder, we look
- * at bit 31 of the remainder *before* shifting it.
- *
- * But also notice how the next_input_bit() bits we're shifting into
- * the remainder don't actually affect any decision-making until
- * 32 bits later.  Thus, the first 32 cycles of this are pretty boring.
- * Also, to add the CRC to a message, we need a 32-bit-long hole for it at
- * the end, so we have to add 32 extra cycles shifting in zeros at the
- * end of every message,
- *
- * So the standard trick is to rearrage merging in the next_input_bit()
- * until the moment it's needed.  Then the first 32 cycles can be precomputed,
- * and merging in the final 32 zero bits to make room for the CRC can be
- * skipped entirely.
- * This changes the code to:
- * for (i = 0; i < input_bits; i++) {
- *      remainder ^= next_input_bit() << 31;
- *     multiple = (remainder & 0x80000000) ? CRCPOLY : 0;
- *     remainder = (remainder << 1) ^ multiple;
- * }
- * With this optimization, the little-endian code is simpler:
- * for (i = 0; i < input_bits; i++) {
- *      remainder ^= next_input_bit();
- *     multiple = (remainder & 1) ? CRCPOLY : 0;
- *     remainder = (remainder >> 1) ^ multiple;
- * }
- *
- * Note that the other details of endianness have been hidden in CRCPOLY
- * (which must be bit-reversed) and next_input_bit().
- *
- * However, as long as next_input_bit is returning the bits in a sensible
- * order, we can actually do the merging 8 or more bits at a time rather
- * than one bit at a time:
- * for (i = 0; i < input_bytes; i++) {
- *     remainder ^= next_input_byte() << 24;
- *     for (j = 0; j < 8; j++) {
- *             multiple = (remainder & 0x80000000) ? CRCPOLY : 0;
- *             remainder = (remainder << 1) ^ multiple;
- *     }
- * }
- * Or in little-endian:
- * for (i = 0; i < input_bytes; i++) {
- *     remainder ^= next_input_byte();
- *     for (j = 0; j < 8; j++) {
- *             multiple = (remainder & 1) ? CRCPOLY : 0;
- *             remainder = (remainder << 1) ^ multiple;
- *     }
- * }
- * If the input is a multiple of 32 bits, you can even XOR in a 32-bit
- * word at a time and increase the inner loop count to 32.
- *
- * You can also mix and match the two loop styles, for example doing the
- * bulk of a message byte-at-a-time and adding bit-at-a-time processing
- * for any fractional bytes at the end.
- *
- * The only remaining optimization is to the byte-at-a-time table method.
- * Here, rather than just shifting one bit of the remainder to decide
- * in the correct multiple to subtract, we can shift a byte at a time.
- * This produces a 40-bit (rather than a 33-bit) intermediate remainder,
- * but again the multiple of the polynomial to subtract depends only on
- * the high bits, the high 8 bits in this case.
- *
- * The multiple we need in that case is the low 32 bits of a 40-bit
- * value whose high 8 bits are given, and which is a multiple of the
- * generator polynomial.  This is simply the CRC-32 of the given
- * one-byte message.
- *
- * Two more details: normally, appending zero bits to a message which
- * is already a multiple of a polynomial produces a larger multiple of that
- * polynomial.  To enable a CRC to detect this condition, it's common to
- * invert the CRC before appending it.  This makes the remainder of the
- * message+crc come out not as zero, but some fixed non-zero value.
- *
- * The same problem applies to zero bits prepended to the message, and
- * a similar solution is used.  Instead of starting with a remainder of
- * 0, an initial remainder of all ones is used.  As long as you start
- * the same way on decoding, it doesn't make a difference.
- */
-
-#ifdef UNITTEST
-
-#include <stdlib.h>
-#include <stdio.h>
-
-const __u8 byte_rev_table[256] = {
-       0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
-       0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
-       0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
-       0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
-       0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
-       0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
-       0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
-       0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
-       0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
-       0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
-       0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
-       0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
-       0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
-       0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
-       0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
-       0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
-       0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
-       0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
-       0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
-       0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
-       0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
-       0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
-       0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
-       0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
-       0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
-       0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
-       0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
-       0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
-       0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
-       0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
-       0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
-       0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff,
-};
-
-static inline __u8 bitrev8(__u8 byte)
-{
-       return byte_rev_table[byte];
-}
-
-static inline __u16 bitrev16(__u16 x)
-{
-       return (bitrev8(x & 0xff) << 8) | bitrev8(x >> 8);
-}
-
-/**
- * bitrev32 - reverse the order of bits in a u32 value
- * @x: value to be bit-reversed
- */
-static __u32 bitrev32(__u32 x)
-{
-       return (bitrev16(x & 0xffff) << 16) | bitrev16(x >> 16);
-}
-
-#if 0                          /*Not used at present */
-
-static void
-buf_dump(char const *prefix, unsigned char const *buf, size_t len)
-{
-       fputs(prefix, stdout);
-       while (len--)
-               printf(" %02x", *buf++);
-       putchar('\n');
-
-}
-#endif
-
-static void bytereverse(unsigned char *buf, size_t len)
-{
-       while (len--) {
-               unsigned char x = bitrev8(*buf);
-               *buf++ = x;
-       }
-}
-
-static void random_garbage(unsigned char *buf, size_t len)
-{
-       while (len--)
-               *buf++ = (unsigned char) random();
-}
-
-#if 0                          /* Not used at present */
-static void store_le(__u32 x, unsigned char *buf)
-{
-       buf[0] = (unsigned char) x;
-       buf[1] = (unsigned char) (x >> 8);
-       buf[2] = (unsigned char) (x >> 16);
-       buf[3] = (unsigned char) (x >> 24);
-}
-#endif
-
-static void store_be(__u32 x, unsigned char *buf)
-{
-       buf[0] = (unsigned char) (x >> 24);
-       buf[1] = (unsigned char) (x >> 16);
-       buf[2] = (unsigned char) (x >> 8);
-       buf[3] = (unsigned char) x;
-}
-
-/*
- * This checks that CRC(buf + CRC(buf)) = 0, and that
- * CRC commutes with bit-reversal.  This has the side effect
- * of bytewise bit-reversing the input buffer, and returns
- * the CRC of the reversed buffer.
- */
-static __u32 test_step(__u32 init, unsigned char *buf, size_t len)
-{
-       __u32 crc1, crc2;
-       size_t i;
-
-       crc1 = crc32_be(init, buf, len);
-       store_be(crc1, buf + len);
-       crc2 = crc32_be(init, buf, len + 4);
-       if (crc2)
-               printf("\nCRC cancellation fail: 0x%08x should be 0\n",
-                      crc2);
-
-       for (i = 0; i <= len + 4; i++) {
-               crc2 = crc32_be(init, buf, i);
-               crc2 = crc32_be(crc2, buf + i, len + 4 - i);
-               if (crc2)
-                       printf("\nCRC split fail: 0x%08x\n", crc2);
-       }
-
-       /* Now swap it around for the other test */
-
-       bytereverse(buf, len + 4);
-       init = bitrev32(init);
-       crc2 = bitrev32(crc1);
-       if (crc1 != bitrev32(crc2))
-               printf("\nBit reversal fail: 0x%08x -> 0x%08x -> 0x%08x\n",
-                      crc1, crc2, bitrev32(crc2));
-       crc1 = crc32_le(init, buf, len);
-       if (crc1 != crc2)
-               printf("\nCRC endianness fail: 0x%08x != 0x%08x\n", crc1,
-                      crc2);
-       crc2 = crc32_le(init, buf, len + 4);
-       if (crc2)
-               printf("\nCRC cancellation fail: 0x%08x should be 0\n",
-                      crc2);
-
-       for (i = 0; i <= len + 4; i++) {
-               crc2 = crc32_le(init, buf, i);
-               crc2 = crc32_le(crc2, buf + i, len + 4 - i);
-               if (crc2)
-                       printf("\nCRC split fail: 0x%08x\n", crc2);
-       }
-
-       return crc1;
-}
-
-#define SIZE 64
-#define INIT1 0
-#define INIT2 0
-
-int main(int argc, char **argv)
-{
-       unsigned char buf1[SIZE + 4];
-       unsigned char buf2[SIZE + 4];
-       unsigned char buf3[SIZE + 4];
-       int i, j;
-       __u32 crc1, crc2, crc3;
-       int exit_status = 0;
-
-       for (i = 0; i <= SIZE; i++) {
-               printf("\rTesting length %d...", i);
-               fflush(stdout);
-               random_garbage(buf1, i);
-               random_garbage(buf2, i);
-               for (j = 0; j < i; j++)
-                       buf3[j] = buf1[j] ^ buf2[j];
-
-               crc1 = test_step(INIT1, buf1, i);
-               crc2 = test_step(INIT2, buf2, i);
-               /* Now check that CRC(buf1 ^ buf2) = CRC(buf1) ^ CRC(buf2) */
-               crc3 = test_step(INIT1 ^ INIT2, buf3, i);
-               if (crc3 != (crc1 ^ crc2)) {
-                       printf("CRC XOR fail: 0x%08x != 0x%08x ^ 0x%08x\n",
-                              crc3, crc1, crc2);
-                       exit_status++;
-               }
-       }
-       printf("\nAll test complete.  No failures expected.\n");
-       return 0;
-}
-
-#endif                         /* UNITTEST */
diff --git a/e2fsck/crc32defs.h b/e2fsck/crc32defs.h
deleted file mode 100644 (file)
index 27414d2..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * There are multiple 16-bit CRC polynomials in common use, but this is
- * *the* standard CRC-32 polynomial, first popularized by Ethernet.
- * x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x^1+x^0
- */
-#define CRCPOLY_LE 0xedb88320
-#define CRCPOLY_BE 0x04c11db7
-
-/* How many bits at a time to use.  Requires a table of 4<<CRC_xx_BITS bytes. */
-/* For less performance-sensitive, use 4 */
-#ifndef CRC_LE_BITS
-# define CRC_LE_BITS 8
-#endif
-#ifndef CRC_BE_BITS
-# define CRC_BE_BITS 8
-#endif
-
-/*
- * Little-endian CRC computation.  Used with serial bit streams sent
- * lsbit-first.  Be sure to use cpu_to_le32() to append the computed CRC.
- */
-#if CRC_LE_BITS > 8 || CRC_LE_BITS < 1 || CRC_LE_BITS & CRC_LE_BITS-1
-# error CRC_LE_BITS must be a power of 2 between 1 and 8
-#endif
-
-/*
- * Big-endian CRC computation.  Used with serial bit streams sent
- * msbit-first.  Be sure to use cpu_to_be32() to append the computed CRC.
- */
-#if CRC_BE_BITS > 8 || CRC_BE_BITS < 1 || CRC_BE_BITS & CRC_BE_BITS-1
-# error CRC_BE_BITS must be a power of 2 between 1 and 8
-#endif
-
-#define ___constant_swab32(x) \
-       ((__u32)( \
-               (((__u32)(x) & (__u32)0x000000ffUL) << 24) | \
-               (((__u32)(x) & (__u32)0x0000ff00UL) <<  8) | \
-               (((__u32)(x) & (__u32)0x00ff0000UL) >>  8) | \
-               (((__u32)(x) & (__u32)0xff000000UL) >> 24) ))
-
-
-#ifdef WORDS_BIGENDIAN
-#define __constant_cpu_to_le32(x) ___constant_swab32((x))
-#define __constant_cpu_to_be32(x) (x)
-#define __be32_to_cpu(x) (x)
-#define __cpu_to_be32(x) (x)
-#define __cpu_to_le32(x) (ext2fs_swab32((x)))
-#define __le32_to_cpu(x) (ext2fs_swab32((x)))
-#else
-#define __constant_cpu_to_le32(x) (x)
-#define __constant_cpu_to_be32(x) ___constant_swab32((x))
-#define __be32_to_cpu(x) (ext2fs_swab32((x)))
-#define __cpu_to_be32(x) (ext2fs_swab32((x)))
-#define __cpu_to_le32(x) (x)
-#define __le32_to_cpu(x) (x)
-#endif
-
-#if (__GNUC__ >= 3)
-#define likely(x)      __builtin_expect(!!(x), 1)
-#define unlikely(x)    __builtin_expect(!!(x), 0)
-#else
-#define likely(x)      (x)
-#define unlikely(x)    (x)
-#endif
index 913a596..dbd6ea8 100644 (file)
@@ -405,9 +405,6 @@ extern int e2fsck_run(e2fsck_t ctx);
 extern void read_bad_blocks_file(e2fsck_t ctx, const char *bad_blocks_file,
                                 int replace_bad_blocks);
 
-/* crc32.c */
-extern __u32 crc32_be(__u32 crc, unsigned char const *p, size_t len);
-
 /* dirinfo.c */
 extern void e2fsck_add_dir_info(e2fsck_t ctx, ext2_ino_t ino, ext2_ino_t parent);
 extern void e2fsck_free_dir_info(e2fsck_t ctx);
@@ -493,6 +490,8 @@ extern void region_free(region_t region);
 extern int region_allocate(region_t region, region_addr_t start, int n);
 
 /* rehash.c */
+void e2fsck_rehash_dir_later(e2fsck_t ctx, ext2_ino_t ino);
+int e2fsck_dir_will_be_rehashed(e2fsck_t ctx, ext2_ino_t ino);
 errcode_t e2fsck_rehash_dir(e2fsck_t ctx, ext2_ino_t ino);
 void e2fsck_rehash_directories(e2fsck_t ctx);
 
diff --git a/e2fsck/gen_crc32table.c b/e2fsck/gen_crc32table.c
deleted file mode 100644 (file)
index 2c1aa8e..0000000
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * gen_crc32table.c --- Generate CRC32 tables.
- *
- * Copyright (C) 2008 Theodore Ts'o.
- *
- * %Begin-Header%
- * This file may be redistributed under the terms of the GNU Public
- * License.
- * %End-Header%
- */
-
-#include <stdio.h>
-#include "crc32defs.h"
-#include <inttypes.h>
-
-#define ENTRIES_PER_LINE 4
-
-#define LE_TABLE_SIZE (1 << CRC_LE_BITS)
-#define BE_TABLE_SIZE (1 << CRC_BE_BITS)
-
-static uint32_t crc32table_le[LE_TABLE_SIZE];
-static uint32_t crc32table_be[BE_TABLE_SIZE];
-
-/**
- * crc32init_le() - allocate and initialize LE table data
- *
- * crc is the crc of the byte i; other entries are filled in based on the
- * fact that crctable[i^j] = crctable[i] ^ crctable[j].
- *
- */
-static void crc32init_le(void)
-{
-       unsigned i, j;
-       uint32_t crc = 1;
-
-       crc32table_le[0] = 0;
-
-       for (i = 1 << (CRC_LE_BITS - 1); i; i >>= 1) {
-               crc = (crc >> 1) ^ ((crc & 1) ? CRCPOLY_LE : 0);
-               for (j = 0; j < LE_TABLE_SIZE; j += 2 * i)
-                       crc32table_le[i + j] = crc ^ crc32table_le[j];
-       }
-}
-
-/**
- * crc32init_be() - allocate and initialize BE table data
- */
-static void crc32init_be(void)
-{
-       unsigned i, j;
-       uint32_t crc = 0x80000000;
-
-       crc32table_be[0] = 0;
-
-       for (i = 1; i < BE_TABLE_SIZE; i <<= 1) {
-               crc = (crc << 1) ^ ((crc & 0x80000000) ? CRCPOLY_BE : 0);
-               for (j = 0; j < i; j++)
-                       crc32table_be[i + j] = crc ^ crc32table_be[j];
-       }
-}
-
-static void output_table(uint32_t table[], int len, const char *trans)
-{
-       int i;
-
-       for (i = 0; i < len - 1; i++) {
-               if (i % ENTRIES_PER_LINE == 0)
-                       printf("\n");
-               printf("%s(0x%8.8xL), ", trans, table[i]);
-       }
-       printf("%s(0x%8.8xL)\n", trans, table[len - 1]);
-}
-
-#ifdef __GNUC__
-#define ATTR(x) __attribute__(x)
-#else
-#define ATTR(x)
-#endif
-
-int main(int argc ATTR((unused)), char** argv ATTR((unused)))
-{
-       printf("/* this file is generated - do not edit */\n\n");
-
-       printf("#ifdef UNITTEST\n");
-       if (CRC_LE_BITS > 1) {
-               crc32init_le();
-               printf("static const __u32 crc32table_le[] = {");
-               output_table(crc32table_le, LE_TABLE_SIZE, "tole");
-               printf("};\n");
-       }
-       printf("#endif /* UNITTEST */\n");
-
-       if (CRC_BE_BITS > 1) {
-               crc32init_be();
-               printf("static const __u32 crc32table_be[] = {");
-               output_table(crc32table_be, BE_TABLE_SIZE, "tobe");
-               printf("};\n");
-       }
-
-       return 0;
-}
index bfc1bcd..3cccd3f 100644 (file)
@@ -115,17 +115,6 @@ _INLINE_ void do_cache_destroy(lkmem_cache_t *cache)
        free(cache);
 }
 
-/*
- * helper functions to deal with 32 or 64bit block numbers.
- */
-_INLINE_ size_t journal_tag_bytes(journal_t *journal)
-{
-       if (JFS_HAS_INCOMPAT_FEATURE(journal, JFS_FEATURE_INCOMPAT_64BIT))
-               return JBD_TAG_SIZE64;
-       else
-               return JBD_TAG_SIZE32;
-}
-
 #undef _INLINE_
 #endif
 
index eb891ca..e3f80bc 100644 (file)
@@ -40,6 +40,56 @@ static int bh_count = 0;
  */
 #undef USE_INODE_IO
 
+/* Checksumming functions */
+static int e2fsck_journal_verify_csum_type(journal_t *j,
+                                          journal_superblock_t *jsb)
+{
+       if (!JFS_HAS_INCOMPAT_FEATURE(j, JFS_FEATURE_INCOMPAT_CSUM_V2))
+               return 1;
+
+       return jsb->s_checksum_type == JBD2_CRC32C_CHKSUM;
+}
+
+static __u32 e2fsck_journal_sb_csum(journal_superblock_t *jsb)
+{
+       __u32 crc, old_crc;
+
+       old_crc = jsb->s_checksum;
+       jsb->s_checksum = 0;
+       crc = ext2fs_crc32c_le(~0, (unsigned char *)jsb,
+                              sizeof(journal_superblock_t));
+       jsb->s_checksum = old_crc;
+
+       return crc;
+}
+
+static int e2fsck_journal_sb_csum_verify(journal_t *j,
+                                        journal_superblock_t *jsb)
+{
+       __u32 provided, calculated;
+
+       if (!JFS_HAS_INCOMPAT_FEATURE(j, JFS_FEATURE_INCOMPAT_CSUM_V2))
+               return 1;
+
+       provided = ext2fs_be32_to_cpu(jsb->s_checksum);
+       calculated = e2fsck_journal_sb_csum(jsb);
+
+       return provided == calculated;
+}
+
+static errcode_t e2fsck_journal_sb_csum_set(journal_t *j,
+                                           journal_superblock_t *jsb)
+{
+       __u32 crc;
+
+       if (!JFS_HAS_INCOMPAT_FEATURE(j, JFS_FEATURE_INCOMPAT_CSUM_V2))
+               return 0;
+
+       crc = e2fsck_journal_sb_csum(jsb);
+       jsb->s_checksum = ext2fs_cpu_to_be32(crc);
+       return 0;
+}
+
 /* Kernel compatibility functions for handling the journal.  These allow us
  * to use the recovery.c file virtually unchanged from the kernel, so we
  * don't have to do much to keep kernel and user recovery in sync.
@@ -574,6 +624,15 @@ static errcode_t e2fsck_journal_load(journal_t *journal)
        if (JFS_HAS_RO_COMPAT_FEATURE(journal, ~JFS_KNOWN_ROCOMPAT_FEATURES))
                return EXT2_ET_RO_UNSUPP_FEATURE;
 
+       /* Checksum v1 and v2 are mutually exclusive features. */
+       if (JFS_HAS_INCOMPAT_FEATURE(journal, JFS_FEATURE_INCOMPAT_CSUM_V2) &&
+           JFS_HAS_COMPAT_FEATURE(journal, JFS_FEATURE_COMPAT_CHECKSUM))
+               return EXT2_ET_CORRUPT_SUPERBLOCK;
+
+       if (!e2fsck_journal_verify_csum_type(journal, jsb) ||
+           !e2fsck_journal_sb_csum_verify(journal, jsb))
+               return EXT2_ET_CORRUPT_SUPERBLOCK;
+
        /* We have now checked whether we know enough about the journal
         * format to be able to proceed safely, so any other checks that
         * fail we should attempt to recover from. */
@@ -641,6 +700,7 @@ static void e2fsck_journal_reset_super(e2fsck_t ctx, journal_superblock_t *jsb,
        for (i = 0; i < 4; i ++)
                new_seq ^= u.val[i];
        jsb->s_sequence = htonl(new_seq);
+       e2fsck_journal_sb_csum_set(journal, jsb);
 
        mark_buffer_dirty(journal->j_sb_buffer);
        ll_rw_block(WRITE, 1, &journal->j_sb_buffer);
@@ -681,6 +741,7 @@ static void e2fsck_journal_release(e2fsck_t ctx, journal_t *journal,
                jsb->s_sequence = htonl(journal->j_transaction_sequence);
                if (reset)
                        jsb->s_start = 0; /* this marks the journal as empty */
+               e2fsck_journal_sb_csum_set(journal, jsb);
                mark_buffer_dirty(journal->j_sb_buffer);
        }
        brelse(journal->j_sb_buffer);
@@ -826,6 +887,7 @@ no_has_journal:
                ctx->fs->super->s_state |= EXT2_ERROR_FS;
                ext2fs_mark_super_dirty(ctx->fs);
                journal->j_superblock->s_errno = 0;
+               e2fsck_journal_sb_csum_set(journal, journal->j_superblock);
                mark_buffer_dirty(journal->j_sb_buffer);
        }
 
index 7b2cb62..2a49f74 100644 (file)
@@ -373,7 +373,7 @@ static _INLINE_ void expand_dirent_expression(FILE *f, ext2_filsys fs, char ch,
                fprintf(f, "%u", dirent->inode);
                break;
        case 'n':
-               len = dirent->name_len & 0xFF;
+               len = ext2fs_dirent_name_len(dirent);
                if ((ext2fs_get_rec_len(fs, dirent, &rec_len) == 0) &&
                    (len > rec_len))
                        len = rec_len;
@@ -384,10 +384,10 @@ static _INLINE_ void expand_dirent_expression(FILE *f, ext2_filsys fs, char ch,
                fprintf(f, "%u", rec_len);
                break;
        case 'l':
-               fprintf(f, "%u", dirent->name_len & 0xFF);
+               fprintf(f, "%u", ext2fs_dirent_name_len(dirent));
                break;
        case 't':
-               fprintf(f, "%u", dirent->name_len >> 8);
+               fprintf(f, "%u", ext2fs_dirent_file_type(dirent));
                break;
        default:
        no_dirent:
index 20157fa..9a5dac7 100644 (file)
@@ -473,7 +473,7 @@ static void check_is_really_dir(e2fsck_t ctx, struct problem_context *pctx,
 
        /* read the first block */
        ehandler_operation(_("reading directory block"));
-       retval = ext2fs_read_dir_block3(ctx->fs, blk, buf, 0);
+       retval = ext2fs_read_dir_block4(ctx->fs, blk, buf, 0, pctx->ino);
        ehandler_operation(0);
        if (retval)
                return;
@@ -482,7 +482,7 @@ static void check_is_really_dir(e2fsck_t ctx, struct problem_context *pctx,
        retval = ext2fs_get_rec_len(ctx->fs, dirent, &rec_len);
        if (retval)
                return;
-       if (((dirent->name_len & 0xFF) != 1) ||
+       if ((ext2fs_dirent_name_len(dirent) != 1) ||
            (dirent->name[0] != '.') ||
            (dirent->inode != pctx->ino) ||
            (rec_len < 12) ||
@@ -494,7 +494,7 @@ static void check_is_really_dir(e2fsck_t ctx, struct problem_context *pctx,
        retval = ext2fs_get_rec_len(ctx->fs, dirent, &rec_len);
        if (retval)
                return;
-       if (((dirent->name_len & 0xFF) != 2) ||
+       if ((ext2fs_dirent_name_len(dirent) != 2) ||
            (dirent->name[0] != '.') ||
            (dirent->name[1] != '.') ||
            (rec_len < 12) ||
@@ -540,6 +540,40 @@ extern void e2fsck_setup_tdb_icount(e2fsck_t ctx, int flags,
                *ret = 0;
 }
 
+static errcode_t recheck_bad_inode_checksum(ext2_filsys fs, ext2_ino_t ino,
+                                           e2fsck_t ctx,
+                                           struct problem_context *pctx)
+{
+       errcode_t retval;
+       struct ext2_inode_large inode;
+
+       /*
+        * Reread inode.  If we don't see checksum error, then this inode
+        * has been fixed elsewhere.
+        */
+       retval = ext2fs_read_inode_full(fs, ino, (struct ext2_inode *)&inode,
+                                       sizeof(inode));
+       if (retval && retval != EXT2_ET_INODE_CSUM_INVALID)
+               return retval;
+       if (!retval)
+               return 0;
+
+       /*
+        * Checksum still doesn't match.  That implies that the inode passes
+        * all the sanity checks, so maybe the checksum is simply corrupt.
+        * See if the user will go for fixing that.
+        */
+       if (!fix_problem(ctx, PR_1_INODE_ONLY_CSUM_INVALID, pctx))
+               return 0;
+
+       retval = ext2fs_write_inode_full(fs, ino, (struct ext2_inode *)&inode,
+                                        sizeof(inode));
+       if (retval)
+               return retval;
+
+       return 0;
+}
+
 void e2fsck_pass1(e2fsck_t ctx)
 {
        int     i;
@@ -561,6 +595,7 @@ void e2fsck_pass1(e2fsck_t ctx)
        int             imagic_fs, extent_fs;
        int             busted_fs_time = 0;
        int             inode_size;
+       int             failed_csum = 0;
 
        init_resource_track(&rtrack, ctx->fs->io);
        clear_problem_context(&pctx);
@@ -691,7 +726,8 @@ void e2fsck_pass1(e2fsck_t ctx)
        }
        block_buf = (char *) e2fsck_allocate_memory(ctx, fs->blocksize * 3,
                                                    "block interate buffer");
-       e2fsck_use_inode_shortcuts(ctx, 1);
+       if (EXT2_INODE_SIZE(fs->super) == EXT2_GOOD_OLD_INODE_SIZE)
+               e2fsck_use_inode_shortcuts(ctx, 1);
        old_op = ehandler_operation(_("opening inode scan"));
        pctx.errcode = ext2fs_open_inode_scan(fs, ctx->inode_buffer_blocks,
                                              &scan);
@@ -721,6 +757,9 @@ void e2fsck_pass1(e2fsck_t ctx)
                ext2fs_mark_block_bitmap2(ctx->block_found_map,
                                          fs->super->s_mmp_block);
 
+       /* Set up ctx->lost_and_found if possible */
+       (void) e2fsck_get_lost_and_found(ctx, 0);
+
        while (1) {
                if (ino % (fs->super->s_inodes_per_group * 4) == 1) {
                        if (e2fsck_mmp_update(fs))
@@ -739,7 +778,8 @@ void e2fsck_pass1(e2fsck_t ctx)
                        ext2fs_mark_inode_bitmap2(ctx->inode_used_map, ino);
                        continue;
                }
-               if (pctx.errcode) {
+               if (pctx.errcode &&
+                   pctx.errcode != EXT2_ET_INODE_CSUM_INVALID) {
                        fix_problem(ctx, PR_1_ISCAN_ERROR, &pctx);
                        ctx->flags |= E2F_FLAG_ABORT;
                        return;
@@ -749,6 +789,14 @@ void e2fsck_pass1(e2fsck_t ctx)
                pctx.ino = ino;
                pctx.inode = inode;
                ctx->stashed_ino = ino;
+
+               /* Clear corrupt inode? */
+               if (pctx.errcode == EXT2_ET_INODE_CSUM_INVALID) {
+                       if (fix_problem(ctx, PR_1_INODE_CSUM_INVALID, &pctx))
+                               goto clear_inode;
+                       failed_csum = 1;
+               }
+
                if (inode->i_links_count) {
                        pctx.errcode = ext2fs_icount_store(ctx->inode_link_info,
                                           ino, inode->i_links_count);
@@ -1145,6 +1193,20 @@ void e2fsck_pass1(e2fsck_t ctx)
                } else
                        check_blocks(ctx, &pctx, block_buf);
 
+               /*
+                * If the inode failed the checksum and the user didn't
+                * clear the inode, test the checksum again -- if it still
+                * fails, ask the user if the checksum should be corrected.
+                */
+               if (failed_csum) {
+                       pctx.errcode = recheck_bad_inode_checksum(fs, ino, ctx,
+                                                                 &pctx);
+                       if (pctx.errcode) {
+                               ctx->flags |= E2F_FLAG_ABORT;
+                               return;
+                       }
+               }
+
                if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
                        return;
 
@@ -1236,6 +1298,12 @@ endit:
        ext2fs_free_mem(&block_buf);
        ext2fs_free_mem(&inode);
 
+       /*
+        * The l+f inode may have been cleared, so zap it now and
+        * later passes will recalculate it if necessary
+        */
+       ctx->lost_and_found = 0;
+
        print_resource_track(ctx, _("Pass 1"), &rtrack, ctx->fs->io);
 }
 
@@ -1465,7 +1533,8 @@ static void adjust_extattr_refcount(e2fsck_t ctx, ext2_refcount_t refcount,
                if ((blk = ea_refcount_intr_next(refcount, &count)) == 0)
                        break;
                pctx.blk = blk;
-               pctx.errcode = ext2fs_read_ext_attr2(fs, blk, block_buf);
+               pctx.errcode = ext2fs_read_ext_attr3(fs, blk, block_buf,
+                                                    pctx.ino);
                if (pctx.errcode) {
                        fix_problem(ctx, PR_1_EXTATTR_READ_ABORT, &pctx);
                        return;
@@ -1476,8 +1545,9 @@ static void adjust_extattr_refcount(e2fsck_t ctx, ext2_refcount_t refcount,
                pctx.num = should_be;
                if (fix_problem(ctx, PR_1_EXTATTR_REFCOUNT, &pctx)) {
                        header->h_refcount = should_be;
-                       pctx.errcode = ext2fs_write_ext_attr2(fs, blk,
-                                                            block_buf);
+                       pctx.errcode = ext2fs_write_ext_attr3(fs, blk,
+                                                            block_buf,
+                                                            pctx.ino);
                        if (pctx.errcode) {
                                fix_problem(ctx, PR_1_EXTATTR_WRITE_ABORT,
                                            &pctx);
@@ -1502,6 +1572,7 @@ static int check_ext_attr(e2fsck_t ctx, struct problem_context *pctx,
        struct ext2_ext_attr_entry *entry;
        int             count;
        region_t        region = 0;
+       int             failed_csum = 0;
 
        blk = ext2fs_file_acl_block(fs, inode);
        if (blk == 0)
@@ -1575,7 +1646,12 @@ static int check_ext_attr(e2fsck_t ctx, struct problem_context *pctx,
         * validate it
         */
        pctx->blk = blk;
-       pctx->errcode = ext2fs_read_ext_attr2(fs, blk, block_buf);
+       pctx->errcode = ext2fs_read_ext_attr3(fs, blk, block_buf, pctx->ino);
+       if (pctx->errcode == EXT2_ET_EXT_ATTR_CSUM_INVALID) {
+               if (fix_problem(ctx, PR_1_EA_BLOCK_CSUM_INVALID, pctx))
+                       goto clear_extattr;
+               failed_csum = 1;
+       }
        if (pctx->errcode && fix_problem(ctx, PR_1_READ_EA_BLOCK, pctx))
                goto clear_extattr;
        header = (struct ext2_ext_attr_header *) block_buf;
@@ -1657,6 +1733,18 @@ static int check_ext_attr(e2fsck_t ctx, struct problem_context *pctx,
        }
        region_free(region);
 
+       /*
+        * We only get here if there was no other errors that were fixed.
+        * If there was a checksum fail, ask to correct it.
+        */
+       if (failed_csum &&
+           fix_problem(ctx, PR_1_EA_BLOCK_ONLY_CSUM_INVALID, pctx)) {
+               pctx->errcode = ext2fs_write_ext_attr3(fs, blk, block_buf,
+                                                      pctx->ino);
+               if (pctx->errcode)
+                       return 0;
+       }
+
        count = header->h_refcount - 1;
        if (count)
                ea_refcount_store(ctx->refcount, blk, count);
@@ -1771,6 +1859,7 @@ static void scan_extent_node(e2fsck_t ctx, struct problem_context *pctx,
        int                     is_dir, is_leaf;
        problem_t               problem;
        struct ext2_extent_info info;
+       int                     failed_csum;
 
        pctx->errcode = ext2fs_extent_get_info(ehandle, &info);
        if (pctx->errcode)
@@ -1778,12 +1867,26 @@ static void scan_extent_node(e2fsck_t ctx, struct problem_context *pctx,
 
        pctx->errcode = ext2fs_extent_get(ehandle, EXT2_EXTENT_FIRST_SIB,
                                          &extent);
-       while (!pctx->errcode && info.num_entries-- > 0) {
+       while ((pctx->errcode == 0 ||
+               pctx->errcode == EXT2_ET_EXTENT_CSUM_INVALID) &&
+              info.num_entries-- > 0) {
+               failed_csum = 0;
                is_leaf = extent.e_flags & EXT2_EXTENT_FLAGS_LEAF;
                is_dir = LINUX_S_ISDIR(pctx->inode->i_mode);
                last_lblk = extent.e_lblk + extent.e_len - 1;
 
                problem = 0;
+               /* Ask to clear a corrupt extent block */
+               if (pctx->errcode == EXT2_ET_EXTENT_CSUM_INVALID) {
+                       pctx->blk = extent.e_pblk;
+                       pctx->blk2 = extent.e_lblk;
+                       pctx->num = extent.e_len;
+                       problem = PR_1_EXTENT_CSUM_INVALID;
+                       if (fix_problem(ctx, problem, pctx))
+                               goto fix_problem_now;
+                       failed_csum = 1;
+               }
+
                if (extent.e_pblk == 0 ||
                    extent.e_pblk < ctx->fs->super->s_first_data_block ||
                    extent.e_pblk >= ext2fs_blocks_count(ctx->fs->super))
@@ -1805,6 +1908,17 @@ static void scan_extent_node(e2fsck_t ctx, struct problem_context *pctx,
                          (1 << (21 - ctx->fs->super->s_log_block_size))))
                        problem = PR_1_TOOBIG_DIR;
 
+               /* Corrupt but passes checks?  Ask to fix checksum. */
+               if (failed_csum) {
+                       pctx->blk = extent.e_pblk;
+                       pctx->blk2 = extent.e_lblk;
+                       pctx->num = extent.e_len;
+                       problem = 0;
+                       if (fix_problem(ctx, PR_1_EXTENT_ONLY_CSUM_INVALID,
+                                       pctx))
+                               ext2fs_extent_replace(ehandle, 0, &extent);
+               }
+
                if (problem) {
 report_problem:
                        pctx->blk = extent.e_pblk;
@@ -1812,6 +1926,7 @@ report_problem:
                        pctx->num = extent.e_len;
                        pctx->blkcount = extent.e_lblk + extent.e_len;
                        if (fix_problem(ctx, problem, pctx)) {
+fix_problem_now:
                                e2fsck_read_bitmaps(ctx);
                                pctx->errcode =
                                        ext2fs_extent_delete(ehandle, 0);
@@ -1841,7 +1956,10 @@ report_problem:
                        if (pctx->errcode) {
                                pctx->str = "EXT2_EXTENT_DOWN";
                                problem = PR_1_EXTENT_HEADER_INVALID;
-                               if (pctx->errcode == EXT2_ET_EXTENT_HEADER_BAD)
+                               if (pctx->errcode ==
+                                       EXT2_ET_EXTENT_HEADER_BAD ||
+                                   pctx->errcode ==
+                                       EXT2_ET_EXTENT_CSUM_INVALID)
                                        goto report_problem;
                                return;
                        }
@@ -2180,9 +2298,10 @@ static void check_blocks(e2fsck_t ctx, struct problem_context *pctx,
        }
 
        if (ctx->dirs_to_hash && pb.is_dir &&
+           !(ctx->lost_and_found && ctx->lost_and_found == ino) &&
            !(inode->i_flags & EXT2_INDEX_FL) &&
            ((inode->i_size / fs->blocksize) >= 3))
-               ext2fs_u32_list_add(ctx->dirs_to_hash, ino);
+               e2fsck_rehash_dir_later(ctx, ino);
 
 out:
        if (dirty_inode)
index a3b880c..967820b 100644 (file)
@@ -654,9 +654,9 @@ static void delete_file(e2fsck_t ctx, ext2_ino_t ino,
        if (ext2fs_file_acl_block(fs, &dp->inode) &&
            (fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_EXT_ATTR)) {
                count = 1;
-               pctx.errcode = ext2fs_adjust_ea_refcount2(fs,
+               pctx.errcode = ext2fs_adjust_ea_refcount3(fs,
                                        ext2fs_file_acl_block(fs, &dp->inode),
-                                                  block_buf, -1, &count);
+                                       block_buf, -1, &count, ino);
                if (pctx.errcode == EXT2_ET_BAD_EA_BLOCK_NUM) {
                        pctx.errcode = 0;
                        count = 1;
index 65d8de4..81a0f4b 100644 (file)
@@ -302,9 +302,9 @@ static int dict_de_cmp(const void *a, const void *b)
        int     a_len, b_len;
 
        de_a = (const struct ext2_dir_entry *) a;
-       a_len = de_a->name_len & 0xFF;
+       a_len = ext2fs_dirent_name_len(de_a);
        de_b = (const struct ext2_dir_entry *) b;
-       b_len = de_b->name_len & 0xFF;
+       b_len = ext2fs_dirent_name_len(de_b);
 
        if (a_len != b_len)
                return (a_len - b_len);
@@ -357,7 +357,7 @@ static int check_dot(e2fsck_t ctx,
 
        if (!dirent->inode)
                problem = PR_2_MISSING_DOT;
-       else if (((dirent->name_len & 0xFF) != 1) ||
+       else if ((ext2fs_dirent_name_len(dirent) != 1) ||
                 (dirent->name[0] != '.'))
                problem = PR_2_1ST_NOT_DOT;
        else if (dirent->name[1] != '\0')
@@ -369,7 +369,8 @@ static int check_dot(e2fsck_t ctx,
                        if (rec_len < 12)
                                rec_len = dirent->rec_len = 12;
                        dirent->inode = ino;
-                       dirent->name_len = 1;
+                       ext2fs_dirent_set_name_len(dirent, 1);
+                       ext2fs_dirent_set_file_type(dirent, EXT2_FT_UNKNOWN);
                        dirent->name[0] = '.';
                        dirent->name[1] = '\0';
                        status = 1;
@@ -393,7 +394,9 @@ static int check_dot(e2fsck_t ctx,
                                (void) ext2fs_set_rec_len(ctx->fs, new_len,
                                                          nextdir);
                                nextdir->inode = 0;
-                               nextdir->name_len = 0;
+                               ext2fs_dirent_set_name_len(nextdir, 0);
+                               ext2fs_dirent_set_file_type(nextdir,
+                                                           EXT2_FT_UNKNOWN);
                                status = 1;
                        }
                }
@@ -415,7 +418,7 @@ static int check_dotdot(e2fsck_t ctx,
 
        if (!dirent->inode)
                problem = PR_2_MISSING_DOT_DOT;
-       else if (((dirent->name_len & 0xFF) != 2) ||
+       else if ((ext2fs_dirent_name_len(dirent) != 2) ||
                 (dirent->name[0] != '.') ||
                 (dirent->name[1] != '.'))
                problem = PR_2_2ND_NOT_DOT_DOT;
@@ -433,7 +436,8 @@ static int check_dotdot(e2fsck_t ctx,
                         * inode.  This will get fixed in pass 3.
                         */
                        dirent->inode = EXT2_ROOT_INO;
-                       dirent->name_len = 2;
+                       ext2fs_dirent_set_name_len(dirent, 2);
+                       ext2fs_dirent_set_file_type(dirent, EXT2_FT_UNKNOWN);
                        dirent->name[0] = '.';
                        dirent->name[1] = '.';
                        dirent->name[2] = '\0';
@@ -461,7 +465,7 @@ static int check_name(e2fsck_t ctx,
        int     fixup = -1;
        int     ret = 0;
 
-       for ( i = 0; i < (dirent->name_len & 0xFF); i++) {
+       for ( i = 0; i < ext2fs_dirent_name_len(dirent); i++) {
                if (dirent->name[i] == '/' || dirent->name[i] == '\0') {
                        if (fixup < 0) {
                                fixup = fix_problem(ctx, PR_2_BAD_NAME, pctx);
@@ -483,7 +487,7 @@ static _INLINE_ int check_filetype(e2fsck_t ctx,
                                   ext2_ino_t dir_ino EXT2FS_ATTR((unused)),
                                   struct problem_context *pctx)
 {
-       int     filetype = dirent->name_len >> 8;
+       int     filetype = ext2fs_dirent_file_type(dirent);
        int     should_be = EXT2_FT_UNKNOWN;
        struct ext2_inode       inode;
 
@@ -492,7 +496,7 @@ static _INLINE_ int check_filetype(e2fsck_t ctx,
                if (filetype == 0 ||
                    !fix_problem(ctx, PR_2_CLEAR_FILETYPE, pctx))
                        return 0;
-               dirent->name_len = dirent->name_len & 0xFF;
+               ext2fs_dirent_set_file_type(dirent, EXT2_FT_UNKNOWN);
                return 1;
        }
 
@@ -518,7 +522,7 @@ static _INLINE_ int check_filetype(e2fsck_t ctx,
                        pctx) == 0)
                return 0;
 
-       dirent->name_len = (dirent->name_len & 0xFF) | should_be << 8;
+       ext2fs_dirent_set_file_type(dirent, should_be);
        return 1;
 }
 
@@ -527,7 +531,7 @@ static void parse_int_node(ext2_filsys fs,
                           struct ext2_db_entry2 *db,
                           struct check_dir_struct *cd,
                           struct dx_dir_info   *dx_dir,
-                          char *block_buf)
+                          char *block_buf, int failed_csum)
 {
        struct          ext2_dx_root_info  *root;
        struct          ext2_dx_entry *ent;
@@ -538,6 +542,7 @@ static void parse_int_node(ext2_filsys fs,
        ext2_dirhash_t  min_hash = 0xffffffff;
        ext2_dirhash_t  max_hash = 0;
        ext2_dirhash_t  hash = 0, prev_hash;
+       int             csum_size = 0;
 
        if (db->blockcnt == 0) {
                root = (struct ext2_dx_root_info *) (block_buf + 24);
@@ -552,9 +557,22 @@ static void parse_int_node(ext2_filsys fs,
 #endif
 
                ent = (struct ext2_dx_entry *) (block_buf + 24 + root->info_length);
+
+               if (failed_csum &&
+                   (e2fsck_dir_will_be_rehashed(cd->ctx, cd->pctx.ino) ||
+                    fix_problem(cd->ctx, PR_2_HTREE_ROOT_CSUM_INVALID,
+                               &cd->pctx)))
+                       goto clear_and_exit;
        } else {
                ent = (struct ext2_dx_entry *) (block_buf+8);
+
+               if (failed_csum &&
+                   (e2fsck_dir_will_be_rehashed(cd->ctx, cd->pctx.ino) ||
+                    fix_problem(cd->ctx, PR_2_HTREE_NODE_CSUM_INVALID,
+                               &cd->pctx)))
+                       goto clear_and_exit;
        }
+
        limit = (struct ext2_dx_countlimit *) ent;
 
 #ifdef DX_DEBUG
@@ -565,8 +583,12 @@ static void parse_int_node(ext2_filsys fs,
 #endif
 
        count = ext2fs_le16_to_cpu(limit->count);
-       expect_limit = (fs->blocksize - ((char *) ent - block_buf)) /
-               sizeof(struct ext2_dx_entry);
+       if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+                                      EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
+               csum_size = sizeof(struct ext2_dx_tail);
+       expect_limit = (fs->blocksize -
+                       (csum_size + ((char *) ent - block_buf))) /
+                      sizeof(struct ext2_dx_entry);
        if (ext2fs_le16_to_cpu(limit->limit) != expect_limit) {
                cd->pctx.num = ext2fs_le16_to_cpu(limit->limit);
                if (fix_problem(cd->ctx, PR_2_HTREE_BAD_LIMIT, &cd->pctx))
@@ -632,6 +654,7 @@ static void parse_int_node(ext2_filsys fs,
 clear_and_exit:
        clear_htree(cd->ctx, cd->pctx.ino);
        dx_dir->numblocks = 0;
+       e2fsck_rehash_dir_later(cd->ctx, cd->pctx.ino);
 }
 #endif /* ENABLE_HTREE */
 
@@ -647,7 +670,7 @@ static void salvage_directory(ext2_filsys fs,
        char    *cp = (char *) dirent;
        int left;
        unsigned int rec_len, prev_rec_len;
-       unsigned int name_len = dirent->name_len & 0xFF;
+       unsigned int name_len = ext2fs_dirent_name_len(dirent);
 
        (void) ext2fs_get_rec_len(fs, dirent, &rec_len);
        left = fs->blocksize - *offset - rec_len;
@@ -701,7 +724,8 @@ static void salvage_directory(ext2_filsys fs,
        } else {
                rec_len = fs->blocksize - *offset;
                (void) ext2fs_set_rec_len(fs, rec_len, dirent);
-               dirent->name_len = 0;
+               ext2fs_dirent_set_name_len(dirent, 0);
+               ext2fs_dirent_set_file_type(dirent, EXT2_FT_UNKNOWN);
                dirent->inode = 0;
        }
 }
@@ -734,6 +758,9 @@ static int check_dir_block(ext2_filsys fs,
        struct problem_context  pctx;
        int     dups_found = 0;
        int     ret;
+       int     dx_csum_size = 0, de_csum_size = 0;
+       int     failed_csum = 0;
+       int     is_leaf = 1;
 
        cd = (struct check_dir_struct *) priv_data;
        buf = cd->buf;
@@ -745,6 +772,12 @@ static int check_dir_block(ext2_filsys fs,
        if (ctx->progress && (ctx->progress)(ctx, 2, cd->count++, cd->max))
                return DIRENT_ABORT;
 
+       if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+                                      EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) {
+               dx_csum_size = sizeof(struct ext2_dx_tail);
+               de_csum_size = sizeof(struct ext2_dir_entry_tail);
+       }
+
        /*
         * Make sure the inode is still in use (could have been
         * deleted in the duplicate/bad blocks pass.
@@ -780,16 +813,24 @@ static int check_dir_block(ext2_filsys fs,
 #endif
 
        ehandler_operation(_("reading directory block"));
-       cd->pctx.errcode = ext2fs_read_dir_block3(fs, block_nr, buf, 0);
+       cd->pctx.errcode = ext2fs_read_dir_block4(fs, block_nr, buf, 0, ino);
        ehandler_operation(0);
        if (cd->pctx.errcode == EXT2_ET_DIR_CORRUPTED)
                cd->pctx.errcode = 0; /* We'll handle this ourselves */
+       else if (cd->pctx.errcode == EXT2_ET_DIR_CSUM_INVALID) {
+               cd->pctx.errcode = 0; /* We'll handle this ourselves */
+               failed_csum = 1;
+       }
        if (cd->pctx.errcode) {
+               char *buf2;
                if (!fix_problem(ctx, PR_2_READ_DIRBLOCK, &cd->pctx)) {
                        ctx->flags |= E2F_FLAG_ABORT;
                        return DIRENT_ABORT;
                }
-               memset(buf, 0, fs->blocksize);
+               ext2fs_new_dir_block(fs, db->blockcnt == 0 ? ino : 0,
+                                    EXT2_ROOT_INO, &buf2);
+               memcpy(buf, buf2, fs->blocksize);
+               ext2fs_free_mem(&buf2);
        }
 #ifdef ENABLE_HTREE
        dx_dir = e2fsck_get_dx_dir_info(ctx, ino);
@@ -832,20 +873,54 @@ static int check_dir_block(ext2_filsys fs,
                        dx_dir->depth = root->indirect_levels + 1;
                } else if ((dirent->inode == 0) &&
                           (rec_len == fs->blocksize) &&
-                          (dirent->name_len == 0) &&
+                          (ext2fs_dirent_name_len(dirent) == 0) &&
                           (ext2fs_le16_to_cpu(limit->limit) ==
-                           ((fs->blocksize-8) /
+                           ((fs->blocksize - (8 + dx_csum_size)) /
                             sizeof(struct ext2_dx_entry))))
                        dx_db->type = DX_DIRBLOCK_NODE;
+               is_leaf = 0;
        }
 out_htree:
 #endif /* ENABLE_HTREE */
 
+       /* Verify checksum. */
+       if (is_leaf && de_csum_size) {
+               /* No space for csum?  Rebuild dirs in pass 3A. */
+               if (!ext2fs_dirent_has_tail(fs, (struct ext2_dir_entry *)buf)) {
+                       de_csum_size = 0;
+                       if (e2fsck_dir_will_be_rehashed(ctx, ino))
+                               goto skip_checksum;
+                       if (!fix_problem(cd->ctx, PR_2_LEAF_NODE_MISSING_CSUM,
+                                        &cd->pctx))
+                               goto skip_checksum;
+                       e2fsck_rehash_dir_later(ctx, ino);
+                       goto skip_checksum;
+               }
+               if (failed_csum) {
+                       char *buf2;
+                       if (!fix_problem(cd->ctx, PR_2_LEAF_NODE_CSUM_INVALID,
+                                        &cd->pctx))
+                               goto skip_checksum;
+                       ext2fs_new_dir_block(fs,
+                                            db->blockcnt == 0 ? ino : 0,
+                                            EXT2_ROOT_INO, &buf2);
+                       memcpy(buf, buf2, fs->blocksize);
+                       ext2fs_free_mem(&buf2);
+                       dir_modified++;
+                       failed_csum = 0;
+               }
+       }
+       /* htree nodes don't use fake dirents to store checksums */
+       if (!is_leaf)
+               de_csum_size = 0;
+
+skip_checksum:
        dict_init(&de_dict, DICTCOUNT_T_MAX, dict_de_cmp);
        prev = 0;
        do {
                dgrp_t group;
                ext2_ino_t first_unused_inode;
+               unsigned int name_len;
 
                problem = 0;
                dirent = (struct ext2_dir_entry *) (buf + offset);
@@ -855,7 +930,7 @@ out_htree:
                if (((offset + rec_len) > fs->blocksize) ||
                    (rec_len < 12) ||
                    ((rec_len % 4) != 0) ||
-                   (((dirent->name_len & (unsigned) 0xFF)+8) > rec_len)) {
+                   ((ext2fs_dirent_name_len(dirent) + 8) > rec_len)) {
                        if (fix_problem(ctx, PR_2_DIR_CORRUPTED, &cd->pctx)) {
                                salvage_directory(fs, dirent, prev, &offset);
                                dir_modified++;
@@ -887,6 +962,7 @@ out_htree:
                /*
                 * Make sure the inode listed is a legal one.
                 */
+               name_len = ext2fs_dirent_name_len(dirent);
                if (((dirent->inode != EXT2_ROOT_INO) &&
                     (dirent->inode < EXT2_FIRST_INODE(fs->super))) ||
                    (dirent->inode > fs->super->s_inodes_count)) {
@@ -899,8 +975,7 @@ out_htree:
                         * clear it.
                         */
                        problem = PR_2_BB_INODE;
-               } else if ((dot_state > 1) &&
-                          ((dirent->name_len & 0xFF) == 1) &&
+               } else if ((dot_state > 1) && (name_len == 1) &&
                           (dirent->name[0] == '.')) {
                        /*
                         * If there's a '.' entry in anything other
@@ -908,8 +983,7 @@ out_htree:
                         * duplicate entry that should be removed.
                         */
                        problem = PR_2_DUP_DOT;
-               } else if ((dot_state > 1) &&
-                          ((dirent->name_len & 0xFF) == 2) &&
+               } else if ((dot_state > 1) && (name_len == 2) &&
                           (dirent->name[0] == '.') &&
                           (dirent->name[1] == '.')) {
                        /*
@@ -927,8 +1001,7 @@ out_htree:
                         * directory hasn't been created yet.
                         */
                        problem = PR_2_LINK_ROOT;
-               } else if ((dot_state > 1) &&
-                          (dirent->name_len & 0xFF) == 0) {
+               } else if ((dot_state > 1) && (name_len == 0)) {
                        /*
                         * Don't allow zero-length directory names.
                         */
@@ -1041,7 +1114,7 @@ out_htree:
 #ifdef ENABLE_HTREE
                if (dx_db) {
                        ext2fs_dirhash(dx_dir->hashversion, dirent->name,
-                                      (dirent->name_len & 0xFF),
+                                      ext2fs_dirent_name_len(dirent),
                                       fs->super->s_hash_seed, &hash, 0);
                        if (hash < dx_db->min_hash)
                                dx_db->min_hash = hash;
@@ -1088,10 +1161,7 @@ out_htree:
                        pctx.ino = ino;
                        pctx.dirent = dirent;
                        fix_problem(ctx, PR_2_REPORT_DUP_DIRENT, &pctx);
-                       if (!ctx->dirs_to_hash)
-                               ext2fs_u32_list_create(&ctx->dirs_to_hash, 50);
-                       if (ctx->dirs_to_hash)
-                               ext2fs_u32_list_add(ctx->dirs_to_hash, ino);
+                       e2fsck_rehash_dir_later(ctx, ino);
                        dups_found++;
                } else
                        dict_alloc_insert(&de_dict, dirent, dirent);
@@ -1107,7 +1177,7 @@ out_htree:
                        (void) ext2fs_get_rec_len(fs, dirent, &rec_len);
                offset += rec_len;
                dot_state++;
-       } while (offset < fs->blocksize);
+       } while (offset < fs->blocksize - de_csum_size);
 #if 0
        printf("\n");
 #endif
@@ -1121,24 +1191,47 @@ out_htree:
                cd->pctx.dir = cd->pctx.ino;
                if ((dx_db->type == DX_DIRBLOCK_ROOT) ||
                    (dx_db->type == DX_DIRBLOCK_NODE))
-                       parse_int_node(fs, db, cd, dx_dir, buf);
+                       parse_int_node(fs, db, cd, dx_dir, buf, failed_csum);
        }
 #endif /* ENABLE_HTREE */
-       if (offset != fs->blocksize) {
-               cd->pctx.num = rec_len - fs->blocksize + offset;
+
+       if (offset != fs->blocksize - de_csum_size) {
+               cd->pctx.num = rec_len - (fs->blocksize - de_csum_size) +
+                              offset;
                if (fix_problem(ctx, PR_2_FINAL_RECLEN, &cd->pctx)) {
                        dirent->rec_len = cd->pctx.num;
                        dir_modified++;
                }
        }
        if (dir_modified) {
-               cd->pctx.errcode = ext2fs_write_dir_block3(fs, block_nr, buf, 0);
+               /* leaf block with no tail?  Rehash dirs later. */
+               if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+                               EXT4_FEATURE_RO_COMPAT_METADATA_CSUM) &&
+                   is_leaf &&
+                   !ext2fs_dirent_has_tail(fs, (struct ext2_dir_entry *)buf))
+                       e2fsck_rehash_dir_later(ctx, ino);
+
+write_and_fix:
+               if (e2fsck_dir_will_be_rehashed(ctx, ino))
+                       ctx->fs->flags |= EXT2_FLAG_IGNORE_CSUM_ERRORS;
+               cd->pctx.errcode = ext2fs_write_dir_block4(fs, block_nr, buf,
+                                                          0, ino);
+               if (e2fsck_dir_will_be_rehashed(ctx, ino))
+                       ctx->fs->flags &= ~EXT2_FLAG_IGNORE_CSUM_ERRORS;
                if (cd->pctx.errcode) {
                        if (!fix_problem(ctx, PR_2_WRITE_DIRBLOCK,
                                         &cd->pctx))
                                goto abort_free_dict;
                }
                ext2fs_mark_changed(fs);
+       } else if (is_leaf && failed_csum && !dir_modified) {
+               /*
+                * If a leaf node that fails csum makes it this far without
+                * alteration, ask the user if the checksum should be fixed.
+                */
+               if (fix_problem(ctx, PR_2_LEAF_NODE_ONLY_CSUM_INVALID,
+                               &cd->pctx))
+                       goto write_and_fix;
        }
        dict_free_nodes(&de_dict);
        return 0;
@@ -1200,9 +1293,9 @@ static void deallocate_inode(e2fsck_t ctx, ext2_ino_t ino, char* block_buf)
 
        if (ext2fs_file_acl_block(fs, &inode) &&
            (fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_EXT_ATTR)) {
-               pctx.errcode = ext2fs_adjust_ea_refcount2(fs,
-                                       ext2fs_file_acl_block(fs, &inode),
-                                       block_buf, -1, &count);
+               pctx.errcode = ext2fs_adjust_ea_refcount3(fs,
+                               ext2fs_file_acl_block(fs, &inode),
+                               block_buf, -1, &count, ino);
                if (pctx.errcode == EXT2_ET_BAD_EA_BLOCK_NUM) {
                        pctx.errcode = 0;
                        count = 1;
@@ -1455,7 +1548,7 @@ static int allocate_dir_block(e2fsck_t ctx,
                return 1;
        }
 
-       pctx->errcode = ext2fs_write_dir_block3(fs, blk, block, 0);
+       pctx->errcode = ext2fs_write_dir_block4(fs, blk, block, 0, db->ino);
        ext2fs_free_mem(&block);
        if (pctx->errcode) {
                pctx->str = "ext2fs_write_dir_block";
index 926f462..fbaadcf 100644 (file)
@@ -198,9 +198,10 @@ static void check_root(e2fsck_t ctx)
                return;
        }
 
-       pctx.errcode = ext2fs_write_dir_block3(fs, blk, block, 0);
+       pctx.errcode = ext2fs_write_dir_block4(fs, blk, block, 0,
+                                              EXT2_ROOT_INO);
        if (pctx.errcode) {
-               pctx.str = "ext2fs_write_dir_block3";
+               pctx.str = "ext2fs_write_dir_block4";
                fix_problem(ctx, PR_3_CREATE_ROOT_ERROR, &pctx);
                ctx->flags |= E2F_FLAG_ABORT;
                return;
@@ -374,7 +375,7 @@ ext2_ino_t e2fsck_get_lost_and_found(e2fsck_t ctx, int fix)
        if (retval && !fix)
                return 0;
        if (!retval) {
-               if (ext2fs_test_inode_bitmap2(ctx->inode_dir_map, ino)) {
+               if (ext2fs_check_directory(fs, ino) == 0) {
                        ctx->lost_and_found = ino;
                        return ino;
                }
@@ -444,7 +445,7 @@ ext2_ino_t e2fsck_get_lost_and_found(e2fsck_t ctx, int fix)
                return 0;
        }
 
-       retval = ext2fs_write_dir_block3(fs, blk, block, 0);
+       retval = ext2fs_write_dir_block4(fs, blk, block, 0, ino);
        ext2fs_free_mem(&block);
        if (retval) {
                pctx.errcode = retval;
@@ -611,7 +612,7 @@ static int fix_dotdot_proc(struct ext2_dir_entry *dirent,
        errcode_t       retval;
        struct problem_context pctx;
 
-       if ((dirent->name_len & 0xFF) != 2)
+       if (ext2fs_dirent_name_len(dirent) != 2)
                return 0;
        if (strncmp(dirent->name, "..", 2))
                return 0;
@@ -631,10 +632,9 @@ static int fix_dotdot_proc(struct ext2_dir_entry *dirent,
        dirent->inode = fp->parent;
        if (fp->ctx->fs->super->s_feature_incompat &
            EXT2_FEATURE_INCOMPAT_FILETYPE)
-               dirent->name_len = (dirent->name_len & 0xFF) |
-                       (EXT2_FT_DIR << 8);
+               ext2fs_dirent_set_file_type(dirent, EXT2_FT_DIR);
        else
-               dirent->name_len = dirent->name_len & 0xFF;
+               ext2fs_dirent_set_file_type(dirent, EXT2_FT_UNKNOWN);
 
        fp->done++;
        return DIRENT_ABORT | DIRENT_CHANGED;
@@ -658,8 +658,12 @@ static void fix_dotdot(e2fsck_t ctx, ext2_ino_t ino, ext2_ino_t parent)
 
        clear_problem_context(&pctx);
        pctx.ino = ino;
+       if (e2fsck_dir_will_be_rehashed(ctx, ino))
+               ctx->fs->flags |= EXT2_FLAG_IGNORE_CSUM_ERRORS;
        retval = ext2fs_dir_iterate(fs, ino, DIRENT_FLAG_INCLUDE_EMPTY,
                                    0, fix_dotdot_proc, &fp);
+       if (e2fsck_dir_will_be_rehashed(ctx, ino))
+               ctx->fs->flags &= ~EXT2_FLAG_IGNORE_CSUM_ERRORS;
        if (retval || !fp.done) {
                pctx.errcode = retval;
                fix_problem(ctx, retval ? PR_3_FIX_PARENT_ERR :
@@ -685,6 +689,7 @@ struct expand_dir_struct {
        blk64_t                 last_block;
        errcode_t               err;
        e2fsck_t                ctx;
+       ext2_ino_t              dir;
 };
 
 static int expand_dir_proc(ext2_filsys fs,
@@ -725,7 +730,8 @@ static int expand_dir_proc(ext2_filsys fs,
                        return BLOCK_ABORT;
                }
                es->num--;
-               retval = ext2fs_write_dir_block3(fs, new_blk, block, 0);
+               retval = ext2fs_write_dir_block4(fs, new_blk, block, 0,
+                                                es->dir);
        } else {
                retval = ext2fs_get_mem(fs->blocksize, &block);
                if (retval) {
@@ -779,6 +785,7 @@ errcode_t e2fsck_expand_directory(e2fsck_t ctx, ext2_ino_t dir,
        es.err = 0;
        es.newblocks = 0;
        es.ctx = ctx;
+       es.dir = dir;
 
        retval = ext2fs_block_iterate3(fs, dir, BLOCK_FLAG_APPEND,
                                       0, expand_dir_proc, &es);
index d4bdbd8..498c041 100644 (file)
@@ -27,6 +27,8 @@ static void check_block_bitmaps(e2fsck_t ctx);
 static void check_inode_bitmaps(e2fsck_t ctx);
 static void check_inode_end(e2fsck_t ctx);
 static void check_block_end(e2fsck_t ctx);
+static void check_inode_bitmap_checksum(e2fsck_t ctx);
+static void check_block_bitmap_checksum(e2fsck_t ctx);
 
 void e2fsck_pass5(e2fsck_t ctx)
 {
@@ -64,6 +66,9 @@ void e2fsck_pass5(e2fsck_t ctx)
        if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
                return;
 
+       check_inode_bitmap_checksum(ctx);
+       check_block_bitmap_checksum(ctx);
+
        ext2fs_free_inode_bitmap(ctx->inode_used_map);
        ctx->inode_used_map = 0;
        ext2fs_free_inode_bitmap(ctx->inode_dir_map);
@@ -74,6 +79,120 @@ void e2fsck_pass5(e2fsck_t ctx)
        print_resource_track(ctx, _("Pass 5"), &rtrack, ctx->fs->io);
 }
 
+static void check_inode_bitmap_checksum(e2fsck_t ctx)
+{
+       struct problem_context  pctx;
+       char            *buf;
+       dgrp_t          i;
+       int             nbytes;
+       ext2_ino_t      ino_itr;
+       errcode_t       retval;
+
+       if (!EXT2_HAS_RO_COMPAT_FEATURE(ctx->fs->super,
+                                       EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
+               return;
+
+       /* If bitmap is dirty from being fixed, checksum will be corrected */
+       if (ext2fs_test_ib_dirty(ctx->fs))
+               return;
+
+       nbytes = (size_t)(EXT2_INODES_PER_GROUP(ctx->fs->super) / 8);
+       retval = ext2fs_get_memalign(ctx->fs->blocksize, ctx->fs->blocksize,
+                                    &buf);
+       if (retval) {
+               com_err(ctx->program_name, 0,
+                   _("check_inode_bitmap_checksum: Memory allocation error"));
+               fatal_error(ctx, 0);
+       }
+
+       clear_problem_context(&pctx);
+       for (i = 0; i < ctx->fs->group_desc_count; i++) {
+               if (ext2fs_bg_flags_test(ctx->fs, i, EXT2_BG_INODE_UNINIT))
+                       continue;
+
+               ino_itr = 1 + (i * (nbytes << 3));
+               retval = ext2fs_get_inode_bitmap_range2(ctx->fs->inode_map,
+                                                       ino_itr, nbytes << 3,
+                                                       buf);
+               if (retval)
+                       break;
+
+               if (ext2fs_inode_bitmap_csum_verify(ctx->fs, i, buf, nbytes))
+                       continue;
+               pctx.group = i;
+               if (!fix_problem(ctx, PR_5_INODE_BITMAP_CSUM_INVALID, &pctx))
+                       continue;
+
+               /*
+                * Fixing one checksum will rewrite all of them.  The bitmap
+                * will be checked against the one we made during pass1 for
+                * discrepancies, and fixed if need be.
+                */
+               ext2fs_mark_ib_dirty(ctx->fs);
+               break;
+       }
+
+       ext2fs_free_mem(&buf);
+}
+
+static void check_block_bitmap_checksum(e2fsck_t ctx)
+{
+       struct problem_context  pctx;
+       char            *buf;
+       dgrp_t          i;
+       int             nbytes;
+       blk64_t         blk_itr;
+       errcode_t       retval;
+
+       if (!EXT2_HAS_RO_COMPAT_FEATURE(ctx->fs->super,
+                                       EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
+               return;
+
+       /* If bitmap is dirty from being fixed, checksum will be corrected */
+       if (ext2fs_test_bb_dirty(ctx->fs))
+               return;
+
+       nbytes = (size_t)(EXT2_CLUSTERS_PER_GROUP(ctx->fs->super) / 8);
+       retval = ext2fs_get_memalign(ctx->fs->blocksize, ctx->fs->blocksize,
+                                    &buf);
+       if (retval) {
+               com_err(ctx->program_name, 0,
+                   _("check_block_bitmap_checksum: Memory allocation error"));
+               fatal_error(ctx, 0);
+       }
+
+       clear_problem_context(&pctx);
+       for (i = 0; i < ctx->fs->group_desc_count; i++) {
+               if (ext2fs_bg_flags_test(ctx->fs, i, EXT2_BG_BLOCK_UNINIT))
+                       continue;
+
+               blk_itr = EXT2FS_B2C(ctx->fs,
+                                    ctx->fs->super->s_first_data_block) +
+                         ((blk64_t) i * (nbytes << 3));
+               retval = ext2fs_get_block_bitmap_range2(ctx->fs->block_map,
+                                                       blk_itr, nbytes << 3,
+                                                       buf);
+               if (retval)
+                       break;
+
+               if (ext2fs_block_bitmap_csum_verify(ctx->fs, i, buf, nbytes))
+                       continue;
+               pctx.group = i;
+               if (!fix_problem(ctx, PR_5_BLOCK_BITMAP_CSUM_INVALID, &pctx))
+                       continue;
+
+               /*
+                * Fixing one checksum will rewrite all of them.  The bitmap
+                * will be checked against the one we made during pass1 for
+                * discrepancies, and fixed if need be.
+                */
+               ext2fs_mark_bb_dirty(ctx->fs);
+               break;
+       }
+
+       ext2fs_free_mem(&buf);
+}
+
 static void e2fsck_discard_blocks(e2fsck_t ctx, blk64_t start,
                                  blk64_t count)
 {
@@ -254,8 +373,7 @@ static void check_block_bitmaps(e2fsck_t ctx)
                goto errout;
        }
 
-       csum_flag = EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
-                                              EXT4_FEATURE_RO_COMPAT_GDT_CSUM);
+       csum_flag = ext2fs_has_group_desc_csum(fs);
 redo_counts:
        had_problem = 0;
        save_problem = 0;
@@ -584,8 +702,7 @@ static void check_inode_bitmaps(e2fsck_t ctx)
                goto errout;
        }
 
-       csum_flag = EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
-                                              EXT4_FEATURE_RO_COMPAT_GDT_CSUM);
+       csum_flag = ext2fs_has_group_desc_csum(fs);
 redo_counts:
        had_problem = 0;
        save_problem = 0;
index 66e2e05..897693a 100644 (file)
@@ -433,6 +433,20 @@ static struct e2fsck_problem problem_table[] = {
          N_("ext2fs_check_desc: %m\n"),
          PROMPT_NONE, 0 },
 
+       /*
+        * metadata_csum implies uninit_bg; both feature bits cannot
+        * be set simultaneously.
+        */
+       { PR_0_META_AND_GDT_CSUM_SET,
+         N_("@S metadata_csum supersedes uninit_bg; both feature "
+            "bits cannot be set simultaneously."),
+         PROMPT_FIX, PR_PREEN_OK | PR_NO_OK},
+
+       /* Superblock has invalid MMP checksum. */
+       { PR_0_MMP_CSUM_INVALID,
+         N_("@S MMP block checksum does not match MMP block.  "),
+         PROMPT_FIX, PR_PREEN_OK | PR_NO_OK},
+
        /* 64bit is set but extents is unset. */
        { PR_0_64BIT_WITHOUT_EXTENTS,
          N_("@S 64bit filesystems needs extents to access the whole disk.  "),
@@ -951,6 +965,46 @@ static struct e2fsck_problem problem_table[] = {
          N_("@i %i has zero length extent\n\t(@n logical @b %c, physical @b %b)\n"),
          PROMPT_CLEAR, 0 },
 
+       /* inode checksum does not match inode */
+       { PR_1_INODE_CSUM_INVALID,
+         N_("@i %i checksum does not match @i.  "),
+         PROMPT_CLEAR, PR_PREEN_OK },
+
+       /* inode passes checks, but checksum does not match inode */
+       { PR_1_INODE_ONLY_CSUM_INVALID,
+         N_("@i %i passes checks, but checksum does not match @i.  "),
+         PROMPT_FIX, PR_PREEN_OK },
+
+       /* Inode extent block checksum does not match extent */
+       { PR_1_EXTENT_CSUM_INVALID,
+         N_("@i %i extent block checksum does not match extent\n\t(logical @b "
+            "%c, @n physical @b %b, len %N)\n"),
+         PROMPT_CLEAR, 0 },
+
+       /*
+        * Inode extent block passes checks, but checksum does not match
+        * extent
+        */
+       { PR_1_EXTENT_ONLY_CSUM_INVALID,
+         N_("@i %i extent block passes checks, but checksum does not match "
+            "extent\n\t(logical @b %c, @n physical @b %b, len %N)\n"),
+         PROMPT_FIX, 0 },
+
+       /* Extended attribute block checksum for inode does not match. */
+       { PR_1_EA_BLOCK_CSUM_INVALID,
+         N_("Extended attribute @a @b %b checksum for @i %i does not "
+            "match.  "),
+         PROMPT_CLEAR, 0 },
+
+       /*
+        * Extended attribute block passes checks, but checksum for inode does
+        * not match.
+        */
+       { PR_1_EA_BLOCK_ONLY_CSUM_INVALID,
+         N_("Extended attribute @a @b %b passes checks, but checksum for "
+            "@i %i does not match.  "),
+         PROMPT_FIX, 0 },
+
        /*
         * Interior extent node logical offset doesn't match first node below it
         */
@@ -1387,6 +1441,31 @@ static struct e2fsck_problem problem_table[] = {
          N_("i_file_acl_hi @F %N, @s zero.\n"),
          PROMPT_CLEAR, PR_PREEN_OK },
 
+       /* htree root node fails checksum */
+       { PR_2_HTREE_ROOT_CSUM_INVALID,
+         N_("@p @h %d: root node fails checksum\n"),
+         PROMPT_CLEAR_HTREE, PR_PREEN_OK },
+
+       /* htree internal node fails checksum */
+       { PR_2_HTREE_NODE_CSUM_INVALID,
+         N_("@p @h %d: internal node fails checksum\n"),
+         PROMPT_CLEAR_HTREE, PR_PREEN_OK },
+
+       /* leaf node fails checksum */
+       { PR_2_LEAF_NODE_CSUM_INVALID,
+         N_("@d @i %i, %B, offset %N: @d fails checksum\n"),
+         PROMPT_SALVAGE, PR_PREEN_OK },
+
+       /* leaf node has no checksum */
+       { PR_2_LEAF_NODE_MISSING_CSUM,
+         N_("@d @i %i, %B, offset %N: @d has no checksum\n"),
+         PROMPT_FIX, PR_PREEN_OK },
+
+       /* leaf node passes checks but fails checksum */
+       { PR_2_LEAF_NODE_ONLY_CSUM_INVALID,
+         N_("@d @i %i, %B, offset %N: @d passes checks but fails checksum\n"),
+         PROMPT_FIX, PR_PREEN_OK },
+
        /* Pass 3 errors */
 
        /* Pass 3: Checking directory connectivity */
@@ -1703,6 +1782,16 @@ static struct e2fsck_problem problem_table[] = {
          N_("@g %g @i(s) in use but @g is marked INODE_UNINIT\n"),
          PROMPT_FIX, PR_PREEN_OK },
 
+       /* Group N inode bitmap does not match checksum */
+       { PR_5_INODE_BITMAP_CSUM_INVALID,
+         N_("@g %g @i bitmap does not match checksum\n"),
+         PROMPT_FIX, PR_LATCH_IBITMAP | PR_PREEN_OK },
+
+       /* Group N block bitmap does not match checksum */
+       { PR_5_BLOCK_BITMAP_CSUM_INVALID,
+         N_("@g %g @b bitmap does not match checksum\n"),
+         PROMPT_FIX, PR_LATCH_BBITMAP | PR_PREEN_OK },
+
        /* Post-Pass 5 errors */
 
        /* Recreate journal if E2F_FLAG_JOURNAL_INODE flag is set */
index 6cb09cf..8999a64 100644 (file)
@@ -253,6 +253,16 @@ struct problem_context {
 #define PR_0_64BIT_WITHOUT_EXTENTS             0x000048
 
 /*
+ * metadata_csum supersedes uninit_bg; both feature bits cannot be set
+ * simultaneously.
+ */
+#define PR_0_META_AND_GDT_CSUM_SET             0x000046
+
+/* Superblock has invalid MMP checksum. */
+#define PR_0_MMP_CSUM_INVALID                  0x000047
+
+
+/*
  * Pass 1 errors
  */
 
@@ -561,6 +571,24 @@ struct problem_context {
 /* Extent has zero length */
 #define PR_1_EXTENT_LENGTH_ZERO                0x010066
 
+/* inode checksum does not match inode */
+#define PR_1_INODE_CSUM_INVALID                0x010067
+
+/* inode passes checks, but checksum does not match inode */
+#define PR_1_INODE_ONLY_CSUM_INVALID   0x010068
+
+/* extent block checksum does not match extent block */
+#define PR_1_EXTENT_CSUM_INVALID       0x010069
+
+/* extent block passes checks, but checksum does not match extent block */
+#define PR_1_EXTENT_ONLY_CSUM_INVALID  0x01006A
+
+/* ea block checksum invalid */
+#define PR_1_EA_BLOCK_CSUM_INVALID     0x01006B
+
+/* ea block passes checks, but checksum invalid */
+#define PR_1_EA_BLOCK_ONLY_CSUM_INVALID        0x01006C
+
 /* Index start doesn't match start of next extent down */
 #define PR_1_EXTENT_INDEX_START_INVALID        0x01006D
 
@@ -829,6 +857,21 @@ struct problem_context {
 /* i_file_acl_hi should be zero */
 #define PR_2_I_FILE_ACL_HI_ZERO                0x020048
 
+/* htree root node fails checksum */
+#define PR_2_HTREE_ROOT_CSUM_INVALID   0x020049
+
+/* htree node fails checksum */
+#define PR_2_HTREE_NODE_CSUM_INVALID   0x02004A
+
+/* dir leaf node fails checksum */
+#define PR_2_LEAF_NODE_CSUM_INVALID    0x02004B
+
+/* no space in leaf for checksum */
+#define PR_2_LEAF_NODE_MISSING_CSUM    0x02004C
+
+/* dir leaf node passes checks, but fails checksum */
+#define PR_2_LEAF_NODE_ONLY_CSUM_INVALID       0x02004D
+
 /*
  * Pass 3 errors
  */
@@ -1027,6 +1070,12 @@ struct problem_context {
 /* Inode in use but group is marked INODE_UNINIT */
 #define PR_5_INODE_UNINIT              0x050019
 
+/* Inode bitmap checksum does not match */
+#define PR_5_INODE_BITMAP_CSUM_INVALID 0x05001A
+
+/* Block bitmap checksum does not match */
+#define PR_5_BLOCK_BITMAP_CSUM_INVALID 0x05001B
+
 /*
  * Post-Pass 5 errors
  */
index e4e5ae1..54579c2 100644 (file)
@@ -174,6 +174,27 @@ static int jread(struct buffer_head **bhp, journal_t *journal,
        return 0;
 }
 
+static int jbd2_descr_block_csum_verify(journal_t *j,
+                                       void *buf)
+{
+       struct journal_block_tail *tail;
+       __u32 provided, calculated;
+
+       if (!JFS_HAS_INCOMPAT_FEATURE(j, JFS_FEATURE_INCOMPAT_CSUM_V2))
+               return 1;
+
+       tail = (struct journal_block_tail *)((char *)buf + j->j_blocksize -
+                       sizeof(struct journal_block_tail));
+       provided = tail->t_checksum;
+       tail->t_checksum = 0;
+       calculated = ext2fs_crc32c_le(~0, j->j_superblock->s_uuid,
+                                     sizeof(j->j_superblock->s_uuid));
+       calculated = ext2fs_crc32c_le(calculated, buf, j->j_blocksize);
+       tail->t_checksum = provided;
+
+       provided = ext2fs_be32_to_cpu(provided);
+       return provided == calculated;
+}
 
 /*
  * Count the number of in-use tags in a journal descriptor block.
@@ -186,6 +207,9 @@ static int count_tags(journal_t *journal, struct buffer_head *bh)
        int                     nr = 0, size = journal->j_blocksize;
        int                     tag_bytes = journal_tag_bytes(journal);
 
+       if (JFS_HAS_INCOMPAT_FEATURE(journal, JFS_FEATURE_INCOMPAT_CSUM_V2))
+               size -= sizeof(struct journal_block_tail);
+
        tagp = &bh->b_data[sizeof(journal_header_t)];
 
        while ((tagp - bh->b_data + tag_bytes) <= size) {
@@ -193,10 +217,10 @@ static int count_tags(journal_t *journal, struct buffer_head *bh)
 
                nr++;
                tagp += tag_bytes;
-               if (!(tag->t_flags & cpu_to_be32(JFS_FLAG_SAME_UUID)))
+               if (!(tag->t_flags & cpu_to_be16(JFS_FLAG_SAME_UUID)))
                        tagp += 16;
 
-               if (tag->t_flags & cpu_to_be32(JFS_FLAG_LAST_TAG))
+               if (tag->t_flags & cpu_to_be16(JFS_FLAG_LAST_TAG))
                        break;
        }
 
@@ -329,7 +353,8 @@ static int calc_chksums(journal_t *journal, struct buffer_head *bh,
 
        num_blks = count_tags(journal, bh);
        /* Calculate checksum of the descriptor block. */
-       *crc32_sum = crc32_be(*crc32_sum, (void *)bh->b_data, bh->b_size);
+       *crc32_sum = ext2fs_crc32_be(*crc32_sum, (void *)bh->b_data,
+                                    bh->b_size);
 
        for (i = 0; i < num_blks; i++) {
                io_block = (*next_log_block)++;
@@ -340,14 +365,56 @@ static int calc_chksums(journal_t *journal, struct buffer_head *bh,
                                "%llu in log\n", err, io_block);
                        return 1;
                } else {
-                       *crc32_sum = crc32_be(*crc32_sum, (void *)obh->b_data,
-                                    obh->b_size);
+                       *crc32_sum = ext2fs_crc32_be(*crc32_sum,
+                                                    (void *)obh->b_data,
+                                                    obh->b_size);
                }
                brelse(obh);
        }
        return 0;
 }
 
+static int jbd2_commit_block_csum_verify(journal_t *j, void *buf)
+{
+       struct commit_header *h;
+       __u32 provided, calculated;
+
+       if (!JFS_HAS_INCOMPAT_FEATURE(j, JFS_FEATURE_INCOMPAT_CSUM_V2))
+               return 1;
+
+       h = buf;
+       provided = h->h_chksum[0];
+       h->h_chksum[0] = 0;
+       calculated = ext2fs_crc32c_le(~0, j->j_superblock->s_uuid,
+                                     sizeof(j->j_superblock->s_uuid));
+       calculated = ext2fs_crc32c_le(calculated, buf, j->j_blocksize);
+       h->h_chksum[0] = provided;
+
+       provided = ext2fs_be32_to_cpu(provided);
+       return provided == calculated;
+}
+
+static int jbd2_block_tag_csum_verify(journal_t *j, journal_block_tag_t *tag,
+                                     void *buf, __u32 sequence)
+{
+       __u32 calculated;
+       __u16 provided, crc;
+
+       if (!JFS_HAS_INCOMPAT_FEATURE(j, JFS_FEATURE_INCOMPAT_CSUM_V2))
+               return 1;
+
+       sequence = ext2fs_cpu_to_be32(sequence);
+       calculated = ext2fs_crc32c_le(~0, j->j_superblock->s_uuid,
+                                     sizeof(j->j_superblock->s_uuid));
+       calculated = ext2fs_crc32c_le(calculated, (__u8 *)&sequence,
+                                     sizeof(sequence));
+       calculated = ext2fs_crc32c_le(calculated, buf, j->j_blocksize) & 0xffff;
+       crc = calculated & 0xFFFF;
+       provided = ext2fs_be16_to_cpu(tag->t_checksum);
+
+       return provided == crc;
+}
+
 static int do_one_pass(journal_t *journal,
                        struct recovery_info *info, enum passtype pass)
 {
@@ -361,6 +428,7 @@ static int do_one_pass(journal_t *journal,
        int                     blocktype;
        int                     tag_bytes = journal_tag_bytes(journal);
        __u32                   crc32_sum = ~0; /* Transactional Checksums */
+       int                     descr_csum_size = 0;
 
        /*
         * First thing is to establish what we expect to find in the log
@@ -446,6 +514,18 @@ static int do_one_pass(journal_t *journal,
 
                switch(blocktype) {
                case JFS_DESCRIPTOR_BLOCK:
+                       /* Verify checksum first */
+                       if (JFS_HAS_INCOMPAT_FEATURE(journal,
+                                       JFS_FEATURE_INCOMPAT_CSUM_V2))
+                               descr_csum_size =
+                                       sizeof(struct journal_block_tail);
+                       if (descr_csum_size > 0 &&
+                           !jbd2_descr_block_csum_verify(journal,
+                                                         bh->b_data)) {
+                               err = -EIO;
+                               goto failed;
+                       }
+
                        /* If it is a valid descriptor block, replay it
                         * in pass REPLAY; if journal_checksums enabled, then
                         * calculate checksums in PASS_SCAN, otherwise,
@@ -476,11 +556,11 @@ static int do_one_pass(journal_t *journal,
 
                        tagp = &bh->b_data[sizeof(journal_header_t)];
                        while ((tagp - bh->b_data + tag_bytes)
-                              <= journal->j_blocksize) {
+                              <= journal->j_blocksize - descr_csum_size) {
                                unsigned long long io_block;
 
                                tag = (journal_block_tag_t *) tagp;
-                               flags = be32_to_cpu(tag->t_flags);
+                               flags = be16_to_cpu(tag->t_flags);
 
                                io_block = next_log_block++;
                                wrap(journal, next_log_block);
@@ -511,6 +591,19 @@ static int do_one_pass(journal_t *journal,
                                                goto skip_write;
                                        }
 
+                                       /* Look for block corruption */
+                                       if (!jbd2_block_tag_csum_verify(
+                                               journal, tag, obh->b_data,
+                                               be32_to_cpu(tmp->h_sequence))) {
+                                               brelse(obh);
+                                               success = -EIO;
+                                               printk(KERN_ERR "JBD: Invalid "
+                                                      "checksum recovering "
+                                                      "block %lld in log\n",
+                                                      blocknr);
+                                               continue;
+                                       }
+
                                        /* Find a buffer for the new
                                         * data being restored */
                                        nbh = __getblk(journal->j_fs_dev,
@@ -652,6 +745,19 @@ static int do_one_pass(journal_t *journal,
                                }
                                crc32_sum = ~0;
                        }
+                       if (pass == PASS_SCAN &&
+                           !jbd2_commit_block_csum_verify(journal,
+                                                          bh->b_data)) {
+                               info->end_transaction = next_commit_ID;
+
+                               if (!JFS_HAS_INCOMPAT_FEATURE(journal,
+                                    JFS_FEATURE_INCOMPAT_ASYNC_COMMIT)) {
+                                       journal->j_failed_commit =
+                                               next_commit_ID;
+                                       brelse(bh);
+                                       break;
+                               }
+                       }
                        brelse(bh);
                        next_commit_ID++;
                        continue;
@@ -708,6 +814,27 @@ static int do_one_pass(journal_t *journal,
        return err;
 }
 
+static int jbd2_revoke_block_csum_verify(journal_t *j,
+                                        void *buf)
+{
+       struct journal_revoke_tail *tail;
+       __u32 provided, calculated;
+
+       if (!JFS_HAS_INCOMPAT_FEATURE(j, JFS_FEATURE_INCOMPAT_CSUM_V2))
+               return 1;
+
+       tail = (struct journal_revoke_tail *)((char *)buf + j->j_blocksize -
+                       sizeof(struct journal_revoke_tail));
+       provided = tail->r_checksum;
+       tail->r_checksum = 0;
+       calculated = ext2fs_crc32c_le(~0, j->j_superblock->s_uuid,
+                                     sizeof(j->j_superblock->s_uuid));
+       calculated = ext2fs_crc32c_le(calculated, buf, j->j_blocksize);
+       tail->r_checksum = provided;
+
+       provided = ext2fs_be32_to_cpu(provided);
+       return provided == calculated;
+}
 
 /* Scan a revoke record, marking all blocks mentioned as revoked. */
 
@@ -722,6 +849,9 @@ static int scan_revoke_records(journal_t *journal, struct buffer_head *bh,
        offset = sizeof(journal_revoke_header_t);
        max = be32_to_cpu(header->r_count);
 
+       if (!jbd2_revoke_block_csum_verify(journal, header))
+               return -EINVAL;
+
        if (JFS_HAS_INCOMPAT_FEATURE(journal, JFS_FEATURE_INCOMPAT_64BIT))
                record_len = 8;
 
index ac0ff31..20704a9 100644 (file)
 #include "e2fsck.h"
 #include "problem.h"
 
+/* Schedule a dir to be rebuilt during pass 3A. */
+void e2fsck_rehash_dir_later(e2fsck_t ctx, ext2_ino_t ino)
+{
+       if (!ctx->dirs_to_hash)
+               ext2fs_u32_list_create(&ctx->dirs_to_hash, 50);
+       if (ctx->dirs_to_hash)
+               ext2fs_u32_list_add(ctx->dirs_to_hash, ino);
+}
+
+/* Ask if a dir will be rebuilt during pass 3A. */
+int e2fsck_dir_will_be_rehashed(e2fsck_t ctx, ext2_ino_t ino)
+{
+       if (ctx->options & E2F_OPT_COMPRESS_DIRS)
+               return 1;
+       if (!ctx->dirs_to_hash)
+               return 0;
+       return ext2fs_u32_list_test(ctx->dirs_to_hash, ino);
+}
+
 struct fill_dir_struct {
        char *buf;
        struct ext2_inode *inode;
@@ -62,6 +81,7 @@ struct fill_dir_struct {
        unsigned int dir_size;
        int compress;
        ino_t parent;
+       ext2_ino_t dir;
 };
 
 struct hash_entry {
@@ -89,7 +109,7 @@ static int fill_dir_block(ext2_filsys fs,
        struct hash_entry       *new_array, *ent;
        struct ext2_dir_entry   *dirent;
        char                    *dir;
-       unsigned int            offset, dir_offset, rec_len;
+       unsigned int            offset, dir_offset, rec_len, name_len;
        int                     hash_alg;
 
        if (blockcnt < 0)
@@ -106,7 +126,10 @@ static int fill_dir_block(ext2_filsys fs,
                dirent = (struct ext2_dir_entry *) dir;
                (void) ext2fs_set_rec_len(fs, fs->blocksize, dirent);
        } else {
-               fd->err = ext2fs_read_dir_block3(fs, *block_nr, dir, 0);
+               fs->flags |= EXT2_FLAG_IGNORE_CSUM_ERRORS;
+               fd->err = ext2fs_read_dir_block4(fs, *block_nr, dir, 0,
+                                                fd->dir);
+               fs->flags &= ~EXT2_FLAG_IGNORE_CSUM_ERRORS;
                if (fd->err)
                        return BLOCK_ABORT;
        }
@@ -119,20 +142,21 @@ static int fill_dir_block(ext2_filsys fs,
        while (dir_offset < fs->blocksize) {
                dirent = (struct ext2_dir_entry *) (dir + dir_offset);
                (void) ext2fs_get_rec_len(fs, dirent, &rec_len);
+               name_len = ext2fs_dirent_name_len(dirent);
                if (((dir_offset + rec_len) > fs->blocksize) ||
                    (rec_len < 8) ||
                    ((rec_len % 4) != 0) ||
-                   (((dirent->name_len & 0xFF)+8U) > rec_len)) {
+                   (name_len + 8 > rec_len)) {
                        fd->err = EXT2_ET_DIR_CORRUPTED;
                        return BLOCK_ABORT;
                }
                dir_offset += rec_len;
                if (dirent->inode == 0)
                        continue;
-               if (!fd->compress && ((dirent->name_len&0xFF) == 1) &&
+               if (!fd->compress && (name_len == 1) &&
                    (dirent->name[0] == '.'))
                        continue;
-               if (!fd->compress && ((dirent->name_len&0xFF) == 2) &&
+               if (!fd->compress && (name_len == 2) &&
                    (dirent->name[0] == '.') && (dirent->name[1] == '.')) {
                        fd->parent = dirent->inode;
                        continue;
@@ -149,13 +173,13 @@ static int fill_dir_block(ext2_filsys fs,
                }
                ent = fd->harray + fd->num_array++;
                ent->dir = dirent;
-               fd->dir_size += EXT2_DIR_REC_LEN(dirent->name_len & 0xFF);
+               fd->dir_size += EXT2_DIR_REC_LEN(name_len);
                ent->ino = dirent->inode;
                if (fd->compress)
                        ent->hash = ent->minor_hash = 0;
                else {
                        fd->err = ext2fs_dirhash(hash_alg, dirent->name,
-                                                dirent->name_len & 0xFF,
+                                                name_len,
                                                 fs->super->s_hash_seed,
                                                 &ent->hash, &ent->minor_hash);
                        if (fd->err)
@@ -180,18 +204,21 @@ static EXT2_QSORT_TYPE name_cmp(const void *a, const void *b)
 {
        const struct hash_entry *he_a = (const struct hash_entry *) a;
        const struct hash_entry *he_b = (const struct hash_entry *) b;
+       unsigned int he_a_len, he_b_len;
        int     ret;
        int     min_len;
 
-       min_len = he_a->dir->name_len;
-       if (min_len > he_b->dir->name_len)
-               min_len = he_b->dir->name_len;
+       he_a_len = ext2fs_dirent_name_len(he_a->dir);
+       he_b_len = ext2fs_dirent_name_len(he_b->dir);
+       min_len = he_a_len;
+       if (min_len > he_b_len)
+               min_len = he_b_len;
 
        ret = strncmp(he_a->dir->name, he_b->dir->name, min_len);
        if (ret == 0) {
-               if (he_a->dir->name_len > he_b->dir->name_len)
+               if (he_a_len > he_b_len)
                        ret = 1;
-               else if (he_a->dir->name_len < he_b->dir->name_len)
+               else if (he_a_len < he_b_len)
                        ret = -1;
                else
                        ret = he_b->dir->inode - he_a->dir->inode;
@@ -274,10 +301,10 @@ static errcode_t get_next_block(ext2_filsys fs, struct out_dir *outdir,
  * expand the length of the filename beyond the padding available in
  * the directory entry.
  */
-static void mutate_name(char *str, __u16 *len)
+static void mutate_name(char *str, unsigned int *len)
 {
        int     i;
-       __u16   l = *len & 0xFF, h = *len & 0xff00;
+       unsigned int l = *len;
 
        /*
         * First check to see if it looks the name has been mutated
@@ -294,7 +321,7 @@ static void mutate_name(char *str, __u16 *len)
                        l = (l+3) & ~3;
                str[l-2] = '~';
                str[l-1] = '0';
-               *len = l | h;
+               *len = l;
                return;
        }
        for (i = l-1; i >= 0; i--) {
@@ -337,7 +364,7 @@ static int duplicate_search_and_fix(e2fsck_t ctx, ext2_filsys fs,
        int                     i, j;
        int                     fixed = 0;
        char                    new_name[256];
-       __u16                   new_len;
+       unsigned int            new_len;
        int                     hash_alg;
 
        clear_problem_context(&pctx);
@@ -352,10 +379,10 @@ static int duplicate_search_and_fix(e2fsck_t ctx, ext2_filsys fs,
                ent = fd->harray + i;
                prev = ent - 1;
                if (!ent->dir->inode ||
-                   ((ent->dir->name_len & 0xFF) !=
-                    (prev->dir->name_len & 0xFF)) ||
-                   (strncmp(ent->dir->name, prev->dir->name,
-                            ent->dir->name_len & 0xFF)))
+                   (ext2fs_dirent_name_len(ent->dir) !=
+                    ext2fs_dirent_name_len(prev->dir)) ||
+                   strncmp(ent->dir->name, prev->dir->name,
+                            ext2fs_dirent_name_len(ent->dir)))
                        continue;
                pctx.dirent = ent->dir;
                if ((ent->dir->inode == prev->dir->inode) &&
@@ -365,27 +392,25 @@ static int duplicate_search_and_fix(e2fsck_t ctx, ext2_filsys fs,
                        fixed++;
                        continue;
                }
-               memcpy(new_name, ent->dir->name, ent->dir->name_len & 0xFF);
-               new_len = ent->dir->name_len;
+               new_len = ext2fs_dirent_name_len(ent->dir);
+               memcpy(new_name, ent->dir->name, new_len);
                mutate_name(new_name, &new_len);
                for (j=0; j < fd->num_array; j++) {
                        if ((i==j) ||
-                           ((new_len & 0xFF) !=
-                            (fd->harray[j].dir->name_len & 0xFF)) ||
-                           (strncmp(new_name, fd->harray[j].dir->name,
-                                    new_len & 0xFF)))
+                           (new_len !=
+                            ext2fs_dirent_name_len(fd->harray[j].dir)) ||
+                           strncmp(new_name, fd->harray[j].dir->name, new_len))
                                continue;
                        mutate_name(new_name, &new_len);
 
                        j = -1;
                }
-               new_name[new_len & 0xFF] = 0;
+               new_name[new_len] = 0;
                pctx.str = new_name;
                if (fix_problem(ctx, PR_2_NON_UNIQUE_FILE, &pctx)) {
-                       memcpy(ent->dir->name, new_name, new_len & 0xFF);
-                       ent->dir->name_len = new_len;
-                       ext2fs_dirhash(hash_alg, ent->dir->name,
-                                      ent->dir->name_len & 0xFF,
+                       memcpy(ent->dir->name, new_name, new_len);
+                       ext2fs_dirent_set_name_len(ent->dir, new_len);
+                       ext2fs_dirhash(hash_alg, ent->dir->name, new_len,
                                       fs->super->s_hash_seed,
                                       &ent->hash, &ent->minor_hash);
                        fixed++;
@@ -407,6 +432,8 @@ static errcode_t copy_dir_entries(e2fsck_t ctx,
        unsigned int            rec_len, prev_rec_len, left, slack, offset;
        int                     i;
        ext2_dirhash_t          prev_hash;
+       int                     csum_size = 0;
+       struct                  ext2_dir_entry_tail *t;
 
        if (ctx->htree_slack_percentage == 255) {
                profile_get_uint(ctx->profile, "options",
@@ -417,6 +444,10 @@ static errcode_t copy_dir_entries(e2fsck_t ctx,
                        ctx->htree_slack_percentage = 20;
        }
 
+       if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+                                      EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
+               csum_size = sizeof(struct ext2_dir_entry_tail);
+
        outdir->max = 0;
        retval = alloc_size_dir(fs, outdir,
                                (fd->dir_size / fs->blocksize) + 2);
@@ -431,16 +462,16 @@ static errcode_t copy_dir_entries(e2fsck_t ctx,
        dirent = (struct ext2_dir_entry *) block_start;
        prev_rec_len = 0;
        rec_len = 0;
-       left = fs->blocksize;
+       left = fs->blocksize - csum_size;
        slack = fd->compress ? 12 :
-               (fs->blocksize * ctx->htree_slack_percentage)/100;
+               ((fs->blocksize - csum_size) * ctx->htree_slack_percentage)/100;
        if (slack < 12)
                slack = 12;
        for (i = 0; i < fd->num_array; i++) {
                ent = fd->harray + i;
                if (ent->dir->inode == 0)
                        continue;
-               rec_len = EXT2_DIR_REC_LEN(ent->dir->name_len & 0xFF);
+               rec_len = EXT2_DIR_REC_LEN(ext2fs_dirent_name_len(ent->dir));
                if (rec_len > left) {
                        if (left) {
                                left += prev_rec_len;
@@ -448,12 +479,17 @@ static errcode_t copy_dir_entries(e2fsck_t ctx,
                                if (retval)
                                        return retval;
                        }
+                       if (csum_size) {
+                               t = EXT2_DIRENT_TAIL(block_start,
+                                                    fs->blocksize);
+                               ext2fs_initialize_dirent_tail(fs, t);
+                       }
                        if ((retval = get_next_block(fs, outdir,
                                                      &block_start)))
                                return retval;
                        offset = 0;
                }
-               left = fs->blocksize - offset;
+               left = (fs->blocksize - csum_size) - offset;
                dirent = (struct ext2_dir_entry *) (block_start + offset);
                if (offset == 0) {
                        if (ent->hash == prev_hash)
@@ -462,12 +498,16 @@ static errcode_t copy_dir_entries(e2fsck_t ctx,
                                outdir->hashes[outdir->num-1] = ent->hash;
                }
                dirent->inode = ent->dir->inode;
-               dirent->name_len = ent->dir->name_len;
+               ext2fs_dirent_set_name_len(dirent,
+                                          ext2fs_dirent_name_len(ent->dir));
+               ext2fs_dirent_set_file_type(dirent,
+                                           ext2fs_dirent_file_type(ent->dir));
                retval = ext2fs_set_rec_len(fs, rec_len, dirent);
                if (retval)
                        return retval;
                prev_rec_len = rec_len;
-               memcpy(dirent->name, ent->dir->name, dirent->name_len & 0xFF);
+               memcpy(dirent->name, ent->dir->name,
+                      ext2fs_dirent_name_len(dirent));
                offset += rec_len;
                left -= rec_len;
                if (left < slack) {
@@ -482,6 +522,10 @@ static errcode_t copy_dir_entries(e2fsck_t ctx,
        }
        if (left)
                retval = ext2fs_set_rec_len(fs, rec_len + left, dirent);
+       if (csum_size) {
+               t = EXT2_DIRENT_TAIL(block_start, fs->blocksize);
+               ext2fs_initialize_dirent_tail(fs, t);
+       }
 
        return retval;
 }
@@ -494,21 +538,24 @@ static struct ext2_dx_root_info *set_root_node(ext2_filsys fs, char *buf,
        struct ext2_dx_root_info        *root;
        struct ext2_dx_countlimit       *limits;
        int                             filetype = 0;
+       int                             csum_size = 0;
 
        if (fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_FILETYPE)
-               filetype = EXT2_FT_DIR << 8;
+               filetype = EXT2_FT_DIR;
 
        memset(buf, 0, fs->blocksize);
        dir = (struct ext2_dir_entry *) buf;
        dir->inode = ino;
        dir->name[0] = '.';
-       dir->name_len = 1 | filetype;
+       ext2fs_dirent_set_name_len(dir, 1);
+       ext2fs_dirent_set_file_type(dir, filetype);
        dir->rec_len = 12;
        dir = (struct ext2_dir_entry *) (buf + 12);
        dir->inode = parent;
        dir->name[0] = '.';
        dir->name[1] = '.';
-       dir->name_len = 2 | filetype;
+       ext2fs_dirent_set_name_len(dir, 2);
+       ext2fs_dirent_set_file_type(dir, filetype);
        dir->rec_len = fs->blocksize - 12;
 
        root = (struct ext2_dx_root_info *) (buf+24);
@@ -518,8 +565,13 @@ static struct ext2_dx_root_info *set_root_node(ext2_filsys fs, char *buf,
        root->indirect_levels = 0;
        root->unused_flags = 0;
 
+       if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+                                       EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
+               csum_size = sizeof(struct ext2_dx_tail);
+
        limits = (struct ext2_dx_countlimit *) (buf+32);
-       limits->limit = (fs->blocksize - 32) / sizeof(struct ext2_dx_entry);
+       limits->limit = (fs->blocksize - (32 + csum_size)) /
+                       sizeof(struct ext2_dx_entry);
        limits->count = 0;
 
        return root;
@@ -530,14 +582,20 @@ static struct ext2_dx_entry *set_int_node(ext2_filsys fs, char *buf)
 {
        struct ext2_dir_entry           *dir;
        struct ext2_dx_countlimit       *limits;
+       int                             csum_size = 0;
 
        memset(buf, 0, fs->blocksize);
        dir = (struct ext2_dir_entry *) buf;
        dir->inode = 0;
        (void) ext2fs_set_rec_len(fs, fs->blocksize, dir);
 
+       if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+                                       EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
+               csum_size = sizeof(struct ext2_dx_tail);
+
        limits = (struct ext2_dx_countlimit *) (buf+8);
-       limits->limit = (fs->blocksize - 8) / sizeof(struct ext2_dx_entry);
+       limits->limit = (fs->blocksize - (8 + csum_size)) /
+                       sizeof(struct ext2_dx_entry);
        limits->count = 0;
 
        return (struct ext2_dx_entry *) limits;
@@ -627,6 +685,7 @@ struct write_dir_struct {
        errcode_t       err;
        e2fsck_t        ctx;
        blk64_t         cleared;
+       ext2_ino_t      dir;
 };
 
 /*
@@ -641,11 +700,23 @@ static int write_dir_block(ext2_filsys fs,
 {
        struct write_dir_struct *wd = (struct write_dir_struct *) priv_data;
        blk64_t blk;
-       char    *dir;
+       char    *dir, *buf = 0;
 
        if (*block_nr == 0)
                return 0;
-       if (blockcnt >= wd->outdir->num) {
+       if (blockcnt < 0)
+               return 0;
+       if (blockcnt < wd->outdir->num)
+               dir = wd->outdir->buf + (blockcnt * fs->blocksize);
+       else if (wd->ctx->lost_and_found == wd->dir) {
+               /* Don't release any extra directory blocks for lost+found */
+               wd->err = ext2fs_new_dir_block(fs, 0, 0, &buf);
+               if (wd->err)
+                       return BLOCK_ABORT;
+               dir = buf;
+               wd->outdir->num++;
+       } else {
+               /* We don't need this block, so release it */
                e2fsck_read_bitmaps(wd->ctx);
                blk = *block_nr;
                ext2fs_unmark_block_bitmap2(wd->ctx->block_found_map, blk);
@@ -654,11 +725,11 @@ static int write_dir_block(ext2_filsys fs,
                wd->cleared++;
                return BLOCK_CHANGED;
        }
-       if (blockcnt < 0)
-               return 0;
 
-       dir = wd->outdir->buf + (blockcnt * fs->blocksize);
-       wd->err = ext2fs_write_dir_block3(fs, *block_nr, dir, 0);
+       wd->err = ext2fs_write_dir_block4(fs, *block_nr, dir, 0, wd->dir);
+       if (buf)
+               ext2fs_free_mem(&buf);
+
        if (wd->err)
                return BLOCK_ABORT;
        return 0;
@@ -680,6 +751,7 @@ static errcode_t write_directory(e2fsck_t ctx, ext2_filsys fs,
        wd.err = 0;
        wd.ctx = ctx;
        wd.cleared = 0;
+       wd.dir = ino;
 
        retval = ext2fs_block_iterate3(fs, ino, 0, 0,
                                       write_dir_block, &wd);
@@ -732,6 +804,7 @@ errcode_t e2fsck_rehash_dir(e2fsck_t ctx, ext2_ino_t ino)
        fd.err = 0;
        fd.dir_size = 0;
        fd.compress = 0;
+       fd.dir = ino;
        if (!(fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX) ||
            (inode.i_size / fs->blocksize) < 2)
                fd.compress = 1;
@@ -835,7 +908,7 @@ void e2fsck_rehash_directories(e2fsck_t ctx)
        if (!ctx->dirs_to_hash && !all_dirs)
                return;
 
-       e2fsck_get_lost_and_found(ctx, 0);
+       (void) e2fsck_get_lost_and_found(ctx, 0);
 
        clear_problem_context(&pctx);
 
@@ -863,8 +936,7 @@ void e2fsck_rehash_directories(e2fsck_t ctx)
                        if (!ext2fs_u32_list_iterate(iter, &ino))
                                break;
                }
-               if (ino == ctx->lost_and_found)
-                       continue;
+
                pctx.dir = ino;
                if (first) {
                        fix_problem(ctx, PR_3A_PASS_HEADER, &pctx);
index e4d60ce..421cd3e 100644 (file)
@@ -392,6 +392,7 @@ void sigcatcher_setup(void)
        sigaction(SIGILL, &sa, 0);
        sigaction(SIGBUS, &sa, 0);
        sigaction(SIGSEGV, &sa, 0);
+       sigaction(SIGABRT, &sa, 0);
 }      
 
 
index 56a3381..dcfd247 100644 (file)
@@ -199,9 +199,9 @@ static int release_inode_blocks(e2fsck_t ctx, ext2_ino_t ino,
                ext2fs_iblk_sub_blocks(fs, inode, pb.truncated_blocks);
 
        if (ext2fs_file_acl_block(fs, inode)) {
-               retval = ext2fs_adjust_ea_refcount2(fs,
-                                       ext2fs_file_acl_block(fs, inode),
-                                       block_buf, -1, &count);
+               retval = ext2fs_adjust_ea_refcount3(fs,
+                               ext2fs_file_acl_block(fs, inode),
+                               block_buf, -1, &count, ino);
                if (retval == EXT2_ET_BAD_EA_BLOCK_NUM) {
                        retval = 0;
                        count = 1;
@@ -582,6 +582,19 @@ void check_super_block(e2fsck_t ctx)
                }
        }
 
+       /* Are metadata_csum and uninit_bg both set? */
+       if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+                                      EXT4_FEATURE_RO_COMPAT_METADATA_CSUM) &&
+           EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+                                      EXT4_FEATURE_RO_COMPAT_GDT_CSUM) &&
+           fix_problem(ctx, PR_0_META_AND_GDT_CSUM_SET, &pctx)) {
+               fs->super->s_feature_ro_compat &=
+                       ~EXT4_FEATURE_RO_COMPAT_GDT_CSUM;
+               ext2fs_mark_super_dirty(fs);
+               for (i = 0; i < fs->group_desc_count; i++)
+                       ext2fs_group_desc_csum_set(fs, i);
+       }
+
        /* Is 64bit set and extents unset? */
        if (EXT2_HAS_INCOMPAT_FEATURE(fs->super,
                                      EXT4_FEATURE_INCOMPAT_64BIT) &&
@@ -599,8 +612,7 @@ void check_super_block(e2fsck_t ctx)
        first_block = sb->s_first_data_block;
        last_block = ext2fs_blocks_count(sb)-1;
 
-       csum_flag = EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
-                                              EXT4_FEATURE_RO_COMPAT_GDT_CSUM);
+       csum_flag = ext2fs_has_group_desc_csum(fs);
        for (i = 0; i < fs->group_desc_count; i++) {
                pctx.group = i;
 
@@ -728,6 +740,7 @@ void check_super_block(e2fsck_t ctx)
        if (!(ctx->options & E2F_OPT_READONLY) && uuid_is_null(sb->s_uuid)) {
                if (fix_problem(ctx, PR_0_ADD_UUID, &pctx)) {
                        uuid_generate(sb->s_uuid);
+                       ext2fs_init_csum_seed(fs);
                        fs->flags |= EXT2_FLAG_DIRTY;
                        fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY;
                }
index bacb86a..a6c8d25 100644 (file)
@@ -1149,6 +1149,11 @@ check_error:
                        ext2fs_mmp_clear(fs);
                        retval = 0;
                }
+       } else if (retval == EXT2_ET_MMP_CSUM_INVALID) {
+               if (fix_problem(ctx, PR_0_MMP_CSUM_INVALID, &pctx)) {
+                       ext2fs_mmp_clear(fs);
+                       retval = 0;
+               }
        }
        return retval;
 }
@@ -1267,6 +1272,7 @@ restart:
        if (!ctx->superblock && !(ctx->options & E2F_OPT_PREEN) &&
            !(ctx->flags & E2F_FLAG_SB_SPECIFIED) &&
            ((retval == EXT2_ET_BAD_MAGIC) ||
+            (retval == EXT2_ET_SB_CSUM_INVALID) ||
             (retval == EXT2_ET_CORRUPT_SUPERBLOCK) ||
             ((retval == 0) && (retval2 = ext2fs_check_desc(fs))))) {
                if (retval) {
@@ -1744,7 +1750,7 @@ no_journal:
        }
 
        if ((run_result & E2F_FLAG_CANCEL) == 0 &&
-           sb->s_feature_ro_compat & EXT4_FEATURE_RO_COMPAT_GDT_CSUM &&
+           ext2fs_has_group_desc_csum(ctx->fs) &&
            !(ctx->options & E2F_OPT_READONLY)) {
                retval = ext2fs_set_gdt_csum(ctx->fs);
                if (retval) {
index c9e2ca1..2d961f2 100644 (file)
@@ -278,7 +278,9 @@ void e2fsck_read_bitmaps(e2fsck_t ctx)
        old_op = ehandler_operation(_("reading inode and block bitmaps"));
        e2fsck_set_bitmap_type(fs, EXT2FS_BMAP64_RBTREE, "fs_bitmaps",
                               &save_type);
+       ctx->fs->flags |= EXT2_FLAG_IGNORE_CSUM_ERRORS;
        retval = ext2fs_read_bitmaps(fs);
+       ctx->fs->flags &= ~EXT2_FLAG_IGNORE_CSUM_ERRORS;
        fs->default_bitmap_type = save_type;
        ehandler_operation(old_op);
        if (retval) {
index 37e80ef..d6809e1 100644 (file)
@@ -110,6 +110,7 @@ struct ext2_super_block {
 #define EXT4_FEATURE_RO_COMPAT_DIR_NLINK       0x0020
 #define EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE     0x0040
 #define EXT4_FEATURE_RO_COMPAT_QUOTA           0x0100
+#define EXT4_FEATURE_RO_COMPAT_METADATA_CSUM   0x0400
 
 /* for s_feature_incompat */
 #define EXT2_FEATURE_INCOMPAT_FILETYPE         0x0002
index b500a2c..fc65dde 100644 (file)
@@ -12,6 +12,9 @@
 /* Define to 1 if debugging ext3/4 journal code */
 #undef CONFIG_JBD_DEBUG
 
+/* Define to 1 to enable mmp support */
+#undef CONFIG_MMP
+
 /* Define to 1 to enable quota support */
 #undef CONFIG_QUOTA
 
 /* Define to 1 to disable use of backtrace */
 #undef DISABLE_BACKTRACE
 
+/* Define to 1 to enable bitmap stats. */
+#undef ENABLE_BMAP_STATS
+
+/* Define to 1 to enable bitmap stats. */
+#undef ENABLE_BMAP_STATS_OPS
+
 /* Define to 1 if ext2 compression enabled */
 #undef ENABLE_COMPRESSION
 
index 9691263..70815ef 100644 (file)
@@ -93,7 +93,7 @@ static struct feature feature_list[] = {
                        "dirdata"},
        {       E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_LARGEDIR,
                        "large_dir"},
-       {       E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_INLINEDATA,
+       {       E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_INLINE_DATA,
                        "inline_data"},
        {       0, 0, 0 },
 };
@@ -108,6 +108,8 @@ static struct feature jrnl_feature_list[] = {
                        "journal_64bit" },
        {       E2P_FEATURE_INCOMPAT, JFS_FEATURE_INCOMPAT_ASYNC_COMMIT,
                        "journal_async_commit" },
+       {       E2P_FEATURE_INCOMPAT, JFS_FEATURE_INCOMPAT_CSUM_V2,
+                       "journal_checksum_v2" },
        {       0, 0, 0 },
 };
 
index f05e16d..d2e84eb 100644 (file)
@@ -196,6 +196,16 @@ static __u64 e2p_free_blocks_count(struct ext2_super_block *super)
 #define EXT2_GOOD_OLD_REV 0
 #endif
 
+static const char *checksum_type(__u8 type)
+{
+       switch (type) {
+       case EXT2_CRC32C_CHKSUM:
+               return "crc32c";
+       default:
+               return "unknown";
+       }
+}
+
 void list_super2(struct ext2_super_block * sb, FILE *f)
 {
        int inode_blocks_per_group;
@@ -421,9 +431,12 @@ void list_super2(struct ext2_super_block * sb, FILE *f)
                fprintf(f, "Group quota inode:        %u\n",
                        sb->s_grp_quota_inum);
 
-       if (sb->s_feature_ro_compat & EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)
+       if (sb->s_feature_ro_compat & EXT4_FEATURE_RO_COMPAT_METADATA_CSUM) {
+               fprintf(f, "Checksum type:            %s\n",
+                       checksum_type(sb->s_checksum_type));
                fprintf(f, "Checksum:                 0x%08x\n",
                        sb->s_checksum);
+       }
 }
 
 void list_super (struct ext2_super_block * s)
index e2f8ce5..f116ac3 100644 (file)
@@ -50,6 +50,7 @@ static struct flags_name flags_array[] = {
        { EXT4_EXTENTS_FL, "e", "Extents" },
        { EXT4_HUGE_FILE_FL, "h", "Huge_file" },
        { FS_NOCOW_FL, "C", "No_COW" },
+       { EXT4_INLINE_DATA_FL, "N", "Inline_Data" },
        { 0, NULL, NULL }
 };
 
index abe2124..e1e6216 100644 (file)
@@ -50,6 +50,7 @@ OBJS= $(DEBUGFS_LIB_OBJS) $(RESIZE_LIB_OBJS) $(E2IMAGE_LIB_OBJS) \
        freefs.o \
        gen_bitmap.o \
        gen_bitmap64.o \
+       get_num_dirs.o \
        get_pathname.o \
        getsize.o \
        getsectsize.o \
@@ -123,6 +124,7 @@ SRCS= ext2_err.c \
        $(srcdir)/freefs.c \
        $(srcdir)/gen_bitmap.c \
        $(srcdir)/gen_bitmap64.c \
+       $(srcdir)/get_num_dirs.c \
        $(srcdir)/get_pathname.c \
        $(srcdir)/getsize.c \
        $(srcdir)/getsectsize.c \
@@ -701,6 +703,13 @@ gen_bitmap64.o: $(srcdir)/gen_bitmap64.c $(top_builddir)/lib/config.h \
  $(top_srcdir)/lib/et/com_err.h $(srcdir)/ext2_io.h \
  $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/ext2_ext_attr.h \
  $(srcdir)/bitops.h $(srcdir)/bmap64.h
+get_num_dirs.o: $(srcdir)/get_num_dirs.c $(top_builddir)/lib/config.h \
+ $(top_builddir)/lib/dirpaths.h $(srcdir)/ext2_fs.h \
+ $(top_builddir)/lib/ext2fs/ext2_types.h $(srcdir)/ext2fsP.h \
+ $(srcdir)/ext2fs.h $(srcdir)/ext2_fs.h $(srcdir)/ext3_extents.h \
+ $(top_srcdir)/lib/et/com_err.h $(srcdir)/ext2_io.h \
+ $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/ext2_ext_attr.h \
+ $(srcdir)/bitops.h
 get_pathname.o: $(srcdir)/get_pathname.c $(top_builddir)/lib/config.h \
  $(top_builddir)/lib/dirpaths.h $(srcdir)/ext2_fs.h \
  $(top_builddir)/lib/ext2fs/ext2_types.h $(srcdir)/ext2fs.h \
index 0c829ed..ce72ffe 100644 (file)
@@ -36,8 +36,7 @@ static void check_block_uninit(ext2_filsys fs, ext2fs_block_bitmap map,
        blk64_t         blk, super_blk, old_desc_blk, new_desc_blk;
        int             old_desc_blocks;
 
-       if (!(EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
-                                        EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) ||
+       if (!ext2fs_has_group_desc_csum(fs) ||
            !(ext2fs_bg_flags_test(fs, group, EXT2_BG_BLOCK_UNINIT)))
                return;
 
@@ -83,8 +82,7 @@ static void check_inode_uninit(ext2_filsys fs, ext2fs_inode_bitmap map,
 {
        ext2_ino_t      i, ino;
 
-       if (!(EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
-                                        EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) ||
+       if (!ext2fs_has_group_desc_csum(fs) ||
            !(ext2fs_bg_flags_test(fs, group, EXT2_BG_INODE_UNINIT)))
                return;
 
index adec363..4229084 100644 (file)
@@ -38,8 +38,7 @@ void ext2fs_inode_alloc_stats2(ext2_filsys fs, ext2_ino_t ino,
        /* We don't strictly need to be clearing the uninit flag if inuse < 0
         * (i.e. freeing inodes) but it also means something is bad. */
        ext2fs_bg_flags_clear(fs, group, EXT2_BG_INODE_UNINIT);
-       if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
-                                      EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) {
+       if (ext2fs_has_group_desc_csum(fs)) {
                ext2_ino_t first_unused_inode = fs->super->s_inodes_per_group -
                        ext2fs_bg_itable_unused(fs, group) +
                        group * fs->super->s_inodes_per_group + 1;
index 9f3d4e0..5e6e556 100644 (file)
@@ -230,16 +230,19 @@ errcode_t ext2fs_allocate_tables(ext2_filsys fs)
        dgrp_t          i;
        struct ext2fs_numeric_progress_struct progress;
 
-       ext2fs_numeric_progress_init(fs, &progress, NULL,
-                                    fs->group_desc_count);
+       if (fs->progress_ops && fs->progress_ops->init)
+               (fs->progress_ops->init)(fs, &progress, NULL,
+                                        fs->group_desc_count);
 
        for (i = 0; i < fs->group_desc_count; i++) {
-               ext2fs_numeric_progress_update(fs, &progress, i);
+               if (fs->progress_ops && fs->progress_ops->update)
+                       (fs->progress_ops->update)(fs, &progress, i);
                retval = ext2fs_allocate_group_table(fs, i, fs->block_map);
                if (retval)
                        return retval;
        }
-       ext2fs_numeric_progress_close(fs, &progress, NULL);
+       if (fs->progress_ops && fs->progress_ops->close)
+               (fs->progress_ops->close)(fs, &progress, NULL);
        return 0;
 }
 
index 8eddde9..73180b0 100644 (file)
@@ -310,12 +310,16 @@ static void ba_clear_bmap(ext2fs_generic_bitmap bitmap)
               (size_t) (((bitmap->real_end - bitmap->start) / 8) + 1));
 }
 
+#ifdef ENABLE_BMAP_STATS
 static void ba_print_stats(ext2fs_generic_bitmap bitmap)
 {
        fprintf(stderr, "%16llu Bytes used by bitarray\n",
                ((bitmap->real_end - bitmap->start) >> 3) + 1 +
                sizeof(struct ext2fs_ba_private_struct));
 }
+#else
+static void ba_print_stats(ext2fs_generic_bitmap bitmap) {}
+#endif
 
 /* Find the first zero bit between start and end, inclusive. */
 static errcode_t ba_find_first_zero(ext2fs_generic_bitmap bitmap,
index a22682e..d6442fc 100644 (file)
@@ -41,7 +41,7 @@ struct ext2fs_rb_private {
        struct bmap_rb_extent *wcursor;
        struct bmap_rb_extent *rcursor;
        struct bmap_rb_extent *rcursor_next;
-#ifdef BMAP_STATS_OPS
+#ifdef ENABLE_BMAP_STATS_OPS
        __u64 mark_hit;
        __u64 test_hit;
 #endif
@@ -146,10 +146,8 @@ static void rb_get_new_extent(struct bmap_rb_extent **ext, __u64 start,
 
        retval = ext2fs_get_mem(sizeof (struct bmap_rb_extent),
                                &new_ext);
-       if (retval) {
-               perror("ext2fs_get_mem");
-               exit(1);
-       }
+       if (retval)
+               abort();
 
        new_ext->start = start;
        new_ext->count = count;
@@ -183,7 +181,7 @@ static errcode_t rb_alloc_private_data (ext2fs_generic_bitmap bitmap)
        bp->rcursor_next = NULL;
        bp->wcursor = NULL;
 
-#ifdef BMAP_STATS_OPS
+#ifdef ENABLE_BMAP_STATS_OPS
        bp->test_hit = 0;
        bp->mark_hit = 0;
 #endif
@@ -331,7 +329,7 @@ rb_test_bit(struct ext2fs_rb_private *bp, __u64 bit)
                goto search_tree;
 
        if (bit >= rcursor->start && bit < rcursor->start + rcursor->count) {
-#ifdef BMAP_STATS_OPS
+#ifdef ENABLE_BMAP_STATS_OPS
                bp->test_hit++;
 #endif
                return 1;
@@ -396,7 +394,7 @@ static int rb_insert_extent(__u64 start, __u64 count,
        if (ext) {
                if (start >= ext->start &&
                    start <= (ext->start + ext->count)) {
-#ifdef BMAP_STATS_OPS
+#ifdef ENABLE_BMAP_STATS_OPS
                        bp->mark_hit++;
 #endif
                        goto got_extent;
@@ -801,7 +799,7 @@ static void rb_clear_bmap(ext2fs_generic_bitmap bitmap)
        bp->wcursor = NULL;
 }
 
-#ifdef BMAP_STATS
+#ifdef ENABLE_BMAP_STATS
 static void rb_print_stats(ext2fs_generic_bitmap bitmap)
 {
        struct ext2fs_rb_private *bp;
@@ -812,7 +810,7 @@ static void rb_print_stats(ext2fs_generic_bitmap bitmap)
        __u64 min_size = ULONG_MAX;
        __u64 size = 0, avg_size = 0;
        double eff;
-#ifdef BMAP_STATS_OPS
+#ifdef ENABLE_BMAP_STATS_OPS
        __u64 mark_all, test_all;
        double m_hit = 0.0, t_hit = 0.0;
 #endif
@@ -837,7 +835,7 @@ static void rb_print_stats(ext2fs_generic_bitmap bitmap)
                min_size = 0;
        eff = (double)((count * sizeof(struct bmap_rb_extent)) << 3) /
              (bitmap->real_end - bitmap->start);
-#ifdef BMAP_STATS_OPS
+#ifdef ENABLE_BMAP_STATS_OPS
        mark_all = bitmap->stats.mark_count + bitmap->stats.mark_ext_count;
        test_all = bitmap->stats.test_count + bitmap->stats.test_ext_count;
        if (mark_all)
@@ -864,7 +862,9 @@ static void rb_print_stats(ext2fs_generic_bitmap bitmap)
                eff);
 }
 #else
-static void rb_print_stats(ext2fs_generic_bitmap bitmap){}
+static void rb_print_stats(ext2fs_generic_bitmap bitmap EXT2FS_ATTR((unused)))
+{
+}
 #endif
 
 struct ext2_bitmap_ops ext2fs_blkmap64_rbtree = {
index 33da7d6..b3eef6c 100644 (file)
@@ -203,6 +203,21 @@ static struct ext4_group_desc *ext4fs_group_desc(ext2_filsys fs,
 }
 
 /*
+ * Return the block bitmap checksum of a group
+ */
+__u32 ext2fs_block_bitmap_checksum(ext2_filsys fs, dgrp_t group)
+{
+       struct ext4_group_desc *gdp;
+       __u32 csum;
+
+       gdp = ext4fs_group_desc(fs, fs->group_desc, group);
+       csum = gdp->bg_block_bitmap_csum_lo;
+       if (fs->super->s_desc_size >= EXT4_BG_BLOCK_BITMAP_CSUM_HI_LOCATION)
+               csum |= ((__u32)gdp->bg_block_bitmap_csum_hi << 16);
+       return csum;
+}
+
+/*
  * Return the block bitmap block of a group
  */
 blk64_t ext2fs_block_bitmap_loc(ext2_filsys fs, dgrp_t group)
@@ -230,6 +245,21 @@ void ext2fs_block_bitmap_loc_set(ext2_filsys fs, dgrp_t group, blk64_t blk)
 }
 
 /*
+ * Return the inode bitmap checksum of a group
+ */
+__u32 ext2fs_inode_bitmap_checksum(ext2_filsys fs, dgrp_t group)
+{
+       struct ext4_group_desc *gdp;
+       __u32 csum;
+
+       gdp = ext4fs_group_desc(fs, fs->group_desc, group);
+       csum = gdp->bg_inode_bitmap_csum_lo;
+       if (fs->super->s_desc_size >= EXT4_BG_INODE_BITMAP_CSUM_HI_END)
+               csum |= ((__u32)gdp->bg_inode_bitmap_csum_hi << 16);
+       return csum;
+}
+
+/*
  * Return the inode bitmap block of a group
  */
 blk64_t ext2fs_inode_bitmap_loc(ext2_filsys fs, dgrp_t group)
index b8c6879..601129d 100644 (file)
@@ -345,6 +345,13 @@ errcode_t ext2fs_block_iterate3(ext2_filsys fs,
                return ctx.errcode;
 
        /*
+        * An inode with inline data has no blocks over which to
+        * iterate, so return an error code indicating this fact.
+        */
+       if (inode.i_flags & EXT4_INLINE_DATA_FL)
+               return EXT2_ET_INLINE_DATA_CANT_ITERATE;
+
+       /*
         * Check to see if we need to limit large files
         */
        if (flags & BLOCK_FLAG_NO_LARGE) {
index f44d379..c5384c9 100644 (file)
@@ -13,7 +13,7 @@ struct ext2_bmap_statistics {
        int             type;
        struct timeval  created;
 
-#ifdef BMAP_STATS_OPS
+#ifdef ENABLE_BMAP_STATS_OPS
        unsigned long   copy_count;
        unsigned long   resize_count;
        unsigned long   mark_count;
@@ -33,7 +33,7 @@ struct ext2_bmap_statistics {
 
        unsigned long   mark_seq;
        unsigned long   test_seq;
-#endif /* BMAP_STATS_OPS */
+#endif /* ENABLE_BMAP_STATS_OPS */
 };
 
 
@@ -48,7 +48,7 @@ struct ext2fs_struct_generic_bitmap {
        char                    *description;
        void                    *private;
        errcode_t               base_error_code;
-#ifdef BMAP_STATS
+#ifdef ENABLE_BMAP_STATS
        struct ext2_bmap_statistics     stats;
 #endif
 };
index 3a80424..db05637 100644 (file)
@@ -247,15 +247,19 @@ static errcode_t write_backup_super(ext2_filsys fs, dgrp_t group,
                                    blk64_t group_block,
                                    struct ext2_super_block *super_shadow)
 {
+       errcode_t retval;
        dgrp_t  sgrp = group;
 
        if (sgrp > ((1 << 16) - 1))
                sgrp = (1 << 16) - 1;
+
+       super_shadow->s_block_group_nr = sgrp;
 #ifdef WORDS_BIGENDIAN
-       super_shadow->s_block_group_nr = ext2fs_swab16(sgrp);
-#else
-       fs->super->s_block_group_nr = sgrp;
+       ext2fs_swap_super(super_shadow);
 #endif
+       retval = ext2fs_superblock_csum_set(fs, super_shadow);
+       if (retval)
+               return retval;
 
        return io_channel_write_blk64(fs->io, group_block, -SUPERBLOCK_SIZE,
                                    super_shadow);
@@ -289,6 +293,23 @@ errcode_t ext2fs_flush2(ext2_filsys fs, int flags)
 
        fs->super->s_wtime = fs->now ? fs->now : time(NULL);
        fs->super->s_block_group_nr = 0;
+
+       /*
+        * If the write_bitmaps() function is present, call it to
+        * flush the bitmaps.  This is done this way so that a simple
+        * program that doesn't mess with the bitmaps doesn't need to
+        * drag in the bitmaps.c code.
+        *
+        * Bitmap checksums live in the group descriptor, so the
+        * bitmaps need to be written before the descriptors.
+        */
+       if (fs->write_bitmaps) {
+               retval = fs->write_bitmaps(fs);
+               if (retval)
+                       goto errout;
+       }
+
+       /* Prepare the group descriptors for writing */
 #ifdef WORDS_BIGENDIAN
        retval = EXT2_ET_NO_MEMORY;
        retval = ext2fs_get_mem(SUPERBLOCK_SIZE, &super_shadow);
@@ -298,6 +319,7 @@ errcode_t ext2fs_flush2(ext2_filsys fs, int flags)
                                  &group_shadow);
        if (retval)
                goto errout;
+       memcpy(super_shadow, fs->super, sizeof(struct ext2_super_block));
        memcpy(group_shadow, fs->group_desc, (size_t) fs->blocksize *
               fs->desc_blocks);
 
@@ -318,10 +340,6 @@ errcode_t ext2fs_flush2(ext2_filsys fs, int flags)
         */
        fs->super->s_state &= ~EXT2_VALID_FS;
        fs->super->s_feature_incompat &= ~EXT3_FEATURE_INCOMPAT_RECOVER;
-#ifdef WORDS_BIGENDIAN
-       *super_shadow = *fs->super;
-       ext2fs_swap_super(super_shadow);
-#endif
 
        /*
         * If this is an external journal device, don't write out the
@@ -341,14 +359,16 @@ errcode_t ext2fs_flush2(ext2_filsys fs, int flags)
        else
                old_desc_blocks = fs->desc_blocks;
 
-       ext2fs_numeric_progress_init(fs, &progress, NULL,
-                                    fs->group_desc_count);
+       if (fs->progress_ops && fs->progress_ops->init)
+               (fs->progress_ops->init)(fs, &progress, NULL,
+                                        fs->group_desc_count);
 
 
        for (i = 0; i < fs->group_desc_count; i++) {
                blk64_t super_blk, old_desc_blk, new_desc_blk;
 
-               ext2fs_numeric_progress_update(fs, &progress, i);
+               if (fs->progress_ops && fs->progress_ops->update)
+                       (fs->progress_ops->update)(fs, &progress, i);
                ext2fs_super_and_bgd_loc2(fs, i, &super_blk, &old_desc_blk,
                                         &new_desc_blk, 0);
 
@@ -377,19 +397,8 @@ errcode_t ext2fs_flush2(ext2_filsys fs, int flags)
                }
        }
 
-       ext2fs_numeric_progress_close(fs, &progress, NULL);
-
-       /*
-        * If the write_bitmaps() function is present, call it to
-        * flush the bitmaps.  This is done this way so that a simple
-        * program that doesn't mess with the bitmaps doesn't need to
-        * drag in the bitmaps.c code.
-        */
-       if (fs->write_bitmaps) {
-               retval = fs->write_bitmaps(fs);
-               if (retval)
-                       goto errout;
-       }
+       if (fs->progress_ops && fs->progress_ops->close)
+               (fs->progress_ops->close)(fs, &progress, NULL);
 
 write_primary_superblock_only:
        /*
@@ -408,6 +417,10 @@ write_primary_superblock_only:
        ext2fs_swap_super(super_shadow);
 #endif
 
+       retval = ext2fs_superblock_csum_set(fs, super_shadow);
+       if (retval)
+               return retval;
+
        if (!(flags & EXT2_FLAG_FLUSH_NO_SYNC))
                retval = io_channel_flush(fs->io);
        retval = write_primary_superblock(fs, super_shadow);
index 2512528..624ad77 100644 (file)
@@ -32,7 +32,6 @@
 #include <stdint.h>
 #include <stdlib.h>
 #include <stdio.h>
-#define __force
 #define min(x, y)              ((x) > (y) ? (y) : (x))
 #define __ALIGN_KERNEL_MASK(x, mask)   (((x) + (mask)) & ~(mask))
 #define __ALIGN_KERNEL(x, a)   __ALIGN_KERNEL_MASK(x, (__typeof__(x))(a) - 1)
 #endif
 
 #if CRC_LE_BITS > 8
-# define tole(x) (__force uint32_t) __constant_cpu_to_le32(x)
+# define tole(x) __constant_cpu_to_le32(x)
 #else
 # define tole(x) (x)
 #endif
 
 #if CRC_BE_BITS > 8
-# define tobe(x) (__force uint32_t) __constant_cpu_to_be32(x)
+# define tobe(x) __constant_cpu_to_be32(x)
 #else
 # define tobe(x) (x)
 #endif
 
 #include "crc32c_table.h"
 
-#if CRC_LE_BITS == 32
-/* slice by 4 algorithm */
-static uint32_t crc32c_le_body(uint32_t crc, uint8_t const *buf, size_t len)
-{
-       const uint8_t *p8;
-       const uint32_t *p32;
-       size_t init_bytes;
-       size_t words;
-       size_t end_bytes;
-       size_t i;
-       uint32_t q;
-       uint8_t i0, i1, i2, i3;
-
-       crc = (__force uint32_t) __cpu_to_le32(crc);
-
-       /* unroll loop into 'init_bytes' odd bytes followed by
-        * 'words' aligned 4 byte words followed by
-        * 'end_bytes' odd bytes at the end */
-       p8 = buf;
-       p32 = (uint32_t *)PTR_ALIGN(p8, 4);
-       init_bytes = min((uintptr_t)p32 - (uintptr_t)p8, len);
-       words = (len - init_bytes) >> 2;
-       end_bytes = (len - init_bytes) & 3;
-
-       for (i = 0; i < init_bytes; i++) {
-#ifndef WORDS_BIGENDIAN
-               i0 = *p8++ ^ crc;
-               crc = t0_le[i0] ^ (crc >> 8);
-#else
-               i0 = *p8++ ^ (crc >> 24);
-               crc = t0_le[i0] ^ (crc << 8);
-#endif
-       }
-
-       /* using pre-increment below slightly faster */
-       p32--;
-
-       for (i = 0; i < words; i++) {
-#ifndef WORDS_BIGENDIAN
-               q = *++p32 ^ crc;
-               i3 = q;
-               i2 = q >> 8;
-               i1 = q >> 16;
-               i0 = q >> 24;
-               crc = t3_le[i3] ^ t2_le[i2] ^ t1_le[i1] ^ t0_le[i0];
-#else
-               q = *++p32 ^ crc;
-               i3 = q >> 24;
-               i2 = q >> 16;
-               i1 = q >> 8;
-               i0 = q;
-               crc = t3_le[i3] ^ t2_le[i2] ^ t1_le[i1] ^ t0_le[i0];
-#endif
-       }
+#if CRC_LE_BITS > 8 || CRC_BE_BITS > 8
 
-       p8 = (uint8_t *)(++p32);
-
-       for (i = 0; i < end_bytes; i++) {
-#ifndef WORDS_BIGENDIAN
-               i0 = *p8++ ^ crc;
-               crc = t0_le[i0] ^ (crc >> 8);
-#else
-               i0 = *p8++ ^ (crc >> 24);
-               crc = t0_le[i0] ^ (crc << 8);
-#endif
-       }
-
-       return __le32_to_cpu((__force __le32)crc);
-}
-#endif
-
-#if CRC_BE_BITS == 32
-static uint32_t crc32c_be_body(uint32_t crc, uint8_t const *buf, size_t len)
+/* implements slicing-by-4 or slicing-by-8 algorithm */
+static inline uint32_t
+crc32_body(uint32_t crc, unsigned char const *buf, size_t len,
+          const uint32_t (*tab)[256])
 {
-       const uint8_t *p8;
-       const uint32_t *p32;
-       size_t init_bytes;
-       size_t words;
-       size_t end_bytes;
-       size_t i;
-       uint32_t q;
-       uint8_t i0, i1, i2, i3;
-
-       crc = (__force uint32_t) __cpu_to_be32(crc);
-
-       p8 = buf;
-       p32 = (uint32_t *)PTR_ALIGN(p8, 4);
-       init_bytes = min((uintptr_t)p32 - (uintptr_t)p8, len);
-       words = (len - init_bytes) >> 2;
-       end_bytes = (len - init_bytes) & 3;
-
-       for (i = 0; i < init_bytes; i++) {
-#ifndef WORDS_BIGENDIAN
-               i0 = *p8++ ^ crc;
-               crc = t0_be[i0] ^ (crc >> 8);
-#else
-               i0 = *p8++ ^ (crc >> 24);
-               crc = t0_be[i0] ^ (crc << 8);
-#endif
-       }
-
-       p32--;
-
-       for (i = 0; i < words; i++) {
-#ifndef WORDS_BIGENDIAN
-               q = *++p32 ^ crc;
-               i3 = q;
-               i2 = q >> 8;
-               i1 = q >> 16;
-               i0 = q >> 24;
-               crc = t3_be[i3] ^ t2_be[i2] ^ t1_be[i1] ^ t0_be[i0];
-#else
-               q = *++p32 ^ crc;
-               i3 = q >> 24;
-               i2 = q >> 16;
-               i1 = q >> 8;
-               i0 = q;
-               crc = t3_be[i3] ^ t2_be[i2] ^ t1_be[i1] ^ t0_be[i0];
-#endif
-       }
-
-       p8 = (uint8_t *)(++p32);
-
-       for (i = 0; i < end_bytes; i++) {
-#ifndef WORDS_BIGENDIAN
-               i0 = *p8++ ^ crc;
-               crc = t0_be[i0] ^ (crc >> 8);
-#else
-               i0 = *p8++ ^ (crc >> 24);
-               crc = t0_be[i0] ^ (crc << 8);
-#endif
-       }
-
-       return __be32_to_cpu((__force __be32)crc);
-}
-#endif
-
-#if CRC_LE_BITS == 64
-/* slice by 8 algorithm */
-static uint32_t crc32c_le_body(uint32_t crc, uint8_t const *buf, size_t len)
-{
-       const uint8_t *p8;
-       const uint32_t *p32;
-       size_t init_bytes;
-       size_t words;
-       size_t end_bytes;
-       size_t i;
-       uint32_t q;
-       uint8_t i0, i1, i2, i3;
-
-       crc = (__force uint32_t) __cpu_to_le32(crc);
-
-       p8 = buf;
-       p32 = (const uint32_t *)PTR_ALIGN(p8, 8);
-       init_bytes = min((uintptr_t)p32 - (uintptr_t)p8, len);
-       words = (len - init_bytes) >> 3;
-       end_bytes = (len - init_bytes) & 7;
-
-       for (i = 0; i < init_bytes; i++) {
-#ifndef WORDS_BIGENDIAN
-               i0 = *p8++ ^ crc;
-               crc = t0_le[i0] ^ (crc >> 8);
-#else
-               i0 = *p8++ ^ (crc >> 24);
-               crc = t0_le[i0] ^ (crc << 8);
-#endif
-       }
-
-       p32--;
-
-       for (i = 0; i < words; i++) {
-#ifndef WORDS_BIGENDIAN
-               q = *++p32 ^ crc;
-               i3 = q;
-               i2 = q >> 8;
-               i1 = q >> 16;
-               i0 = q >> 24;
-               crc = t7_le[i3] ^ t6_le[i2] ^ t5_le[i1] ^ t4_le[i0];
-
-               q = *++p32;
-               i3 = q;
-               i2 = q >> 8;
-               i1 = q >> 16;
-               i0 = q >> 24;
-               crc ^= t3_le[i3] ^ t2_le[i2] ^ t1_le[i1] ^ t0_le[i0];
-#else
-               q = *++p32 ^ crc;
-               i3 = q >> 24;
-               i2 = q >> 16;
-               i1 = q >> 8;
-               i0 = q;
-               crc = t7_le[i3] ^ t6_le[i2] ^ t5_le[i1] ^ t4_le[i0];
-
-               q = *++p32;
-               i3 = q >> 24;
-               i2 = q >> 16;
-               i1 = q >> 8;
-               i0 = q;
-               crc ^= t3_le[i3] ^ t2_le[i2] ^ t1_le[i1] ^ t0_le[i0];
-#endif
-       }
-
-       p8 = (const uint8_t *)(++p32);
-
-       for (i = 0; i < end_bytes; i++) {
-#ifndef WORDS_BIGENDIAN
-               i0 = *p8++ ^ crc;
-               crc = t0_le[i0] ^ (crc >> 8);
-#else
-               i0 = *p8++ ^ (crc >> 24);
-               crc = t0_le[i0] ^ (crc << 8);
-#endif
-       }
-
-       return __le32_to_cpu(crc);
-}
-#endif
-
-#if CRC_BE_BITS == 64
-static uint32_t crc32c_be_body(uint32_t crc, uint8_t const *buf, size_t len)
-{
-       const uint8_t *p8;
-       const uint32_t *p32;
-       size_t init_bytes;
-       size_t words;
-       size_t end_bytes;
-       size_t i;
+# ifndef WORDS_BIGENDIAN
+#  define DO_CRC(x) (crc = t0[(crc ^ (x)) & 255] ^ (crc >> 8))
+#  define DO_CRC4 (t3[(q) & 255] ^ t2[(q >> 8) & 255] ^ \
+                  t1[(q >> 16) & 255] ^ t0[(q >> 24) & 255])
+#  define DO_CRC8 (t7[(q) & 255] ^ t6[(q >> 8) & 255] ^ \
+                  t5[(q >> 16) & 255] ^ t4[(q >> 24) & 255])
+# else
+#  define DO_CRC(x) (crc = t0[((crc >> 24) ^ (x)) & 255] ^ (crc << 8))
+#  define DO_CRC4 (t0[(q) & 255] ^ t1[(q >> 8) & 255] ^ \
+                  t2[(q >> 16) & 255] ^ t3[(q >> 24) & 255])
+#  define DO_CRC8 (t4[(q) & 255] ^ t5[(q >> 8) & 255] ^ \
+                  t6[(q >> 16) & 255] ^ t7[(q >> 24) & 255])
+# endif
+       const uint32_t *b;
+       size_t rem_len;
+       const uint32_t *t0 = tab[0], *t1 = tab[1], *t2 = tab[2], *t3 = tab[3];
+       const uint32_t *t4 = tab[4], *t5 = tab[5], *t6 = tab[6], *t7 = tab[7];
        uint32_t q;
-       uint8_t i0, i1, i2, i3;
-
-       crc = (__force uint32_t) __cpu_to_be32(crc);
 
-       p8 = buf;
-       p32 = (const uint32_t *)PTR_ALIGN(p8, 8);
-       init_bytes = min((uintptr_t)p32 - (uintptr_t)p8, len);
-       words = (len - init_bytes) >> 3;
-       end_bytes = (len - init_bytes) & 7;
-
-       for (i = 0; i < init_bytes; i++) {
-#ifndef WORDS_BIGENDIAN
-               i0 = *p8++ ^ crc;
-               crc = t0_be[i0] ^ (crc >> 8);
-#else
-               i0 = *p8++ ^ (crc >> 24);
-               crc = t0_be[i0] ^ (crc << 8);
-#endif
+       /* Align it */
+       if (unlikely((long)buf & 3 && len)) {
+               do {
+                       DO_CRC(*buf++);
+               } while ((--len) && ((long)buf)&3);
        }
 
-       p32--;
-
-       for (i = 0; i < words; i++) {
-#ifndef WORDS_BIGENDIAN
-               q = *++p32 ^ crc;
-               i3 = q;
-               i2 = q >> 8;
-               i1 = q >> 16;
-               i0 = q >> 24;
-               crc = t7_be[i3] ^ t6_be[i2] ^ t5_be[i1] ^ t4_be[i0];
-
-               q = *++p32;
-               i3 = q;
-               i2 = q >> 8;
-               i1 = q >> 16;
-               i0 = q >> 24;
-               crc ^= t3_be[i3] ^ t2_be[i2] ^ t1_be[i1] ^ t0_be[i0];
-#else
-               q = *++p32 ^ crc;
-               i3 = q >> 24;
-               i2 = q >> 16;
-               i1 = q >> 8;
-               i0 = q;
-               crc = t7_be[i3] ^ t6_be[i2] ^ t5_be[i1] ^ t4_be[i0];
+# if CRC_LE_BITS == 32
+       rem_len = len & 3;
+       len = len >> 2;
+# else
+       rem_len = len & 7;
+       len = len >> 3;
+# endif
 
-               q = *++p32;
-               i3 = q >> 24;
-               i2 = q >> 16;
-               i1 = q >> 8;
-               i0 = q;
-               crc ^= t3_be[i3] ^ t2_be[i2] ^ t1_be[i1] ^ t0_be[i0];
-#endif
+       b = (const uint32_t *)buf;
+       for (--b; len; --len) {
+               q = crc ^ *++b; /* use pre increment for speed */
+# if CRC_LE_BITS == 32
+               crc = DO_CRC4;
+# else
+               crc = DO_CRC8;
+               q = *++b;
+               crc ^= DO_CRC4;
+# endif
        }
-
-       p8 = (const uint8_t *)(++p32);
-
-       for (i = 0; i < end_bytes; i++) {
-#ifndef WORDS_BIGENDIAN
-               i0 = *p8++ ^ crc;
-               crc = t0_be[i0] ^ (crc >> 8);
-#else
-               i0 = *p8++ ^ (crc >> 24);
-               crc = t0_be[i0] ^ (crc << 8);
-#endif
+       len = rem_len;
+       /* And the last few bytes */
+       if (len) {
+               const uint8_t *p = (const uint8_t *)(b + 1) - 1;
+               do {
+                       DO_CRC(*++p); /* use pre increment for speed */
+               } while (--len);
        }
-
-       return __be32_to_cpu(crc);
+       return crc;
+#undef DO_CRC
+#undef DO_CRC4
+#undef DO_CRC8
 }
 #endif
 
 /**
- * crc32c_le() - Calculate bitwise little-endian CRC32c.
- * @crc: seed value for computation.  ~0 for ext4, sometimes 0 for
- *     other uses, or the previous crc32c value if computing incrementally.
+ * crc32_le() - Calculate bitwise little-endian Ethernet AUTODIN II CRC32
+ * @crc: seed value for computation.  ~0 for Ethernet, sometimes 0 for
+ *     other uses, or the previous crc32 value if computing incrementally.
  * @p: pointer to buffer over which CRC is run
  * @len: length of buffer @p
  */
-uint32_t ext2fs_crc32c_le(uint32_t crc, unsigned char const *p, size_t len)
+static inline uint32_t crc32_le_generic(uint32_t crc, unsigned char const *p,
+                                       size_t len, const uint32_t (*tab)[256],
+                                       uint32_t polynomial EXT2FS_ATTR((unused)))
 {
 #if CRC_LE_BITS == 1
        int i;
        while (len--) {
                crc ^= *p++;
                for (i = 0; i < 8; i++)
-                       crc = (crc >> 1) ^ ((crc & 1) ? CRCPOLY_LE : 0);
+                       crc = (crc >> 1) ^ ((crc & 1) ? polynomial : 0);
        }
 # elif CRC_LE_BITS == 2
        while (len--) {
                crc ^= *p++;
-               crc = (crc >> 2) ^ t0_le[crc & 0x03];
-               crc = (crc >> 2) ^ t0_le[crc & 0x03];
-               crc = (crc >> 2) ^ t0_le[crc & 0x03];
-               crc = (crc >> 2) ^ t0_le[crc & 0x03];
+               crc = (crc >> 2) ^ tab[0][crc & 3];
+               crc = (crc >> 2) ^ tab[0][crc & 3];
+               crc = (crc >> 2) ^ tab[0][crc & 3];
+               crc = (crc >> 2) ^ tab[0][crc & 3];
        }
 # elif CRC_LE_BITS == 4
        while (len--) {
                crc ^= *p++;
-               crc = (crc >> 4) ^ t0_le[crc & 0x0f];
-               crc = (crc >> 4) ^ t0_le[crc & 0x0f];
+               crc = (crc >> 4) ^ tab[0][crc & 15];
+               crc = (crc >> 4) ^ tab[0][crc & 15];
        }
 # elif CRC_LE_BITS == 8
+       /* aka Sarwate algorithm */
        while (len--) {
                crc ^= *p++;
-               crc = (crc >> 8) ^ t0_le[crc & 0xff];
+               crc = (crc >> 8) ^ tab[0][crc & 255];
        }
 # else
-       crc = crc32c_le_body(crc, p, len);
-# endif
+       crc = __cpu_to_le32(crc);
+       crc = crc32_body(crc, p, len, tab);
+       crc = __le32_to_cpu(crc);
+#endif
        return crc;
 }
 
+uint32_t ext2fs_crc32c_le(uint32_t crc, unsigned char const *p, size_t len)
+{
+       return crc32_le_generic(crc, p, len, crc32ctable_le, CRC32C_POLY_LE);
+}
+
 /**
- * crc32c_be() - Calculate bitwise big-endian CRC32c.
- * @crc: seed value for computation.  ~0 for ext4, sometimes 0 for
- *     other uses, or the previous crc32c value if computing incrementally.
+ * crc32_be() - Calculate bitwise big-endian Ethernet AUTODIN II CRC32
+ * @crc: seed value for computation.  ~0 for Ethernet, sometimes 0 for
+ *     other uses, or the previous crc32 value if computing incrementally.
  * @p: pointer to buffer over which CRC is run
  * @len: length of buffer @p
  */
-uint32_t ext2fs_crc32c_be(uint32_t crc, unsigned char const *p, size_t len)
+static inline uint32_t crc32_be_generic(uint32_t crc, unsigned char const *p,
+                                       size_t len, const uint32_t (*tab)[256],
+                                       uint32_t polynomial EXT2FS_ATTR((unused)))
 {
 #if CRC_BE_BITS == 1
        int i;
        while (len--) {
                crc ^= *p++ << 24;
                for (i = 0; i < 8; i++)
-                       crc = (crc << 1) ^
-                             ((crc & 0x80000000) ? CRCPOLY_BE : 0);
+                       crc =
+                           (crc << 1) ^ ((crc & 0x80000000) ? polynomial :
+                                         0);
        }
 # elif CRC_BE_BITS == 2
        while (len--) {
                crc ^= *p++ << 24;
-               crc = (crc << 2) ^ t0_be[crc >> 30];
-               crc = (crc << 2) ^ t0_be[crc >> 30];
-               crc = (crc << 2) ^ t0_be[crc >> 30];
-               crc = (crc << 2) ^ t0_be[crc >> 30];
+               crc = (crc << 2) ^ tab[0][crc >> 30];
+               crc = (crc << 2) ^ tab[0][crc >> 30];
+               crc = (crc << 2) ^ tab[0][crc >> 30];
+               crc = (crc << 2) ^ tab[0][crc >> 30];
        }
 # elif CRC_BE_BITS == 4
        while (len--) {
                crc ^= *p++ << 24;
-               crc = (crc << 4) ^ t0_be[crc >> 28];
-               crc = (crc << 4) ^ t0_be[crc >> 28];
+               crc = (crc << 4) ^ tab[0][crc >> 28];
+               crc = (crc << 4) ^ tab[0][crc >> 28];
        }
 # elif CRC_BE_BITS == 8
        while (len--) {
                crc ^= *p++ << 24;
-               crc = (crc << 8) ^ t0_be[crc >> 24];
+               crc = (crc << 8) ^ tab[0][crc >> 24];
        }
 # else
-       crc = crc32c_be_body(crc, p, len);
+       crc = __cpu_to_be32(crc);
+       crc = crc32_body(crc, p, len, tab);
+       crc = __be32_to_cpu(crc);
 # endif
        return crc;
 }
 
+uint32_t ext2fs_crc32_be(uint32_t crc, unsigned char const *p, size_t len)
+{
+       return crc32_be_generic(crc, p, len, crc32table_be, CRCPOLY_BE);
+}
+
 #ifdef UNITTEST
 static uint8_t test_buf[] = {
        0xd9, 0xd7, 0x6a, 0x13, 0x3a, 0xb1, 0x05, 0x48,
@@ -972,137 +760,137 @@ static struct crc_test {
        uint32_t crc;           /* random starting crc */
        uint32_t start;         /* random offset in buf */
        uint32_t length;        /* random length of test */
-       uint32_t crc_le;        /* expected crc32_le result */
-       uint32_t crc_be;        /* expected crc32_be result */
+       uint32_t crc32c_le;     /* expected crc32c_le result */
+       uint32_t crc32_be;      /* expected crc32_be result */
 } test[] = {
-       {0xffffffff, 0x00000000, 0x00001000, 0x13934bef, 0x14f3b75f},
-       {0xfe7328ea, 0x00000763, 0x00000717, 0xed2c0d70, 0x57531214},
-       {0x4c40684e, 0x00000721, 0x0000011e, 0xd7f46ccc, 0xedf12ec3},
-       {0x6b487f90, 0x00000264, 0x000007bc, 0x759e9939, 0x9af8e387},
-       {0x9f5810db, 0x00000afa, 0x00000255, 0x2685197f, 0x716de6ed},
-       {0xb15c4755, 0x00000d5b, 0x000002a4, 0xd8fadcb5, 0xfc34ae3f},
-       {0x06518253, 0x00000ffb, 0x00000004, 0xabee2433, 0xfa30ac9e},
-       {0xd9e71c55, 0x00000a2a, 0x00000259, 0x96682af2, 0xe5907ea3},
-       {0x0c1ae843, 0x00000ce4, 0x0000031b, 0x7b637c43, 0xe7f71b04},
-       {0xec3cd517, 0x000002ff, 0x00000566, 0x5d719a77, 0xed16e045},
-       {0x77828e95, 0x0000067f, 0x0000038f, 0x43ee5b6c, 0x35999927},
-       {0xec87b4e3, 0x00000d1c, 0x000002e3, 0x2ddd2eee, 0x9452d3f8},
-       {0x412158bb, 0x00000eee, 0x00000111, 0x67b38ba2, 0x177976d0},
-       {0x2e52de3e, 0x00000c4a, 0x000003b5, 0xbcc5d61d, 0xf60fee71},
-       {0x6ddaae8b, 0x00000d99, 0x00000266, 0x8b535544, 0x1dab8596},
-       {0x049b6cb1, 0x000009c5, 0x000000b0, 0xfc22cabc, 0x47ebc954},
-       {0x77d4b954, 0x0000028a, 0x000007fa, 0x71d00923, 0x905585ef},
-       {0x5e192355, 0x00000ac1, 0x000001fa, 0xb966b81a, 0x33c12903},
-       {0x7d80b71d, 0x00000213, 0x000001e0, 0x2bba371a, 0x5f4bd8d9},
-       {0x01f6f1e4, 0x000001d6, 0x00000395, 0xb7e8a647, 0x2a7943a1},
-       {0x1dfabb13, 0x00000e14, 0x000001eb, 0x53917fba, 0x8dee1e5d},
-       {0xb00a4449, 0x00000bf6, 0x00000409, 0xedecb577, 0x628e087d},
-       {0x7ecd3981, 0x0000083f, 0x0000016b, 0xefef62b9, 0xda4f94e6},
-       {0xf8f330d2, 0x000004be, 0x00000757, 0x9357c9f3, 0x8e2d5c2f},
-       {0x03c38af2, 0x00000d23, 0x000002dc, 0x360fa8c0, 0x6294c0d6},
-       {0x687bb79b, 0x00000f3d, 0x000000c2, 0x448d3be2, 0x08f48f3a},
-       {0x6710f550, 0x000009e9, 0x00000603, 0xdbfd1998, 0xc950ac29},
-       {0x873171d1, 0x00000787, 0x000004d5, 0xab7f1b62, 0xe66896ab},
-       {0x373b1314, 0x00000f0f, 0x000000f0, 0x184098ab, 0x4038e674},
-       {0x90fad9cd, 0x00000ead, 0x00000152, 0x23ce52ff, 0x9eff3974},
-       {0x19676fe7, 0x0000007d, 0x0000070d, 0xf8a76f1e, 0xfbc5c8a9},
-       {0x89facd45, 0x000005f3, 0x00000473, 0x4331a006, 0xb8f0f0cc},
-       {0x6f173747, 0x00000fc3, 0x0000003c, 0xb012f08e, 0x5126e378},
-       {0x4b44a106, 0x0000075a, 0x0000008b, 0xf6f7ac38, 0xf9b1781b},
-       {0xb620ad06, 0x00000774, 0x0000017e, 0xd34558e6, 0xb175edd3},
-       {0x976f21e9, 0x000008d7, 0x0000034a, 0xe533aa3a, 0x1e4367b9},
-       {0x687628c0, 0x000006c5, 0x0000061b, 0x3a840b15, 0xfb5989a0},
-       {0xe24ac108, 0x00000cd0, 0x0000032f, 0x51010ae8, 0xcdd8f182},
-       {0x361c44a3, 0x00000304, 0x00000719, 0xfd7bd481, 0x12de540f},
-       {0xd93ff95e, 0x00000db7, 0x0000008e, 0xcfbbc304, 0x42eecd5a},
-       {0xed752d12, 0x00000883, 0x00000091, 0x65a6c868, 0x9ebfa578},
-       {0xb4ff4b54, 0x000003d3, 0x000001c1, 0xf82597e7, 0xa8ad2b19},
-       {0x111b520f, 0x00000708, 0x000000eb, 0xc3e109f3, 0x323ace17},
-       {0x62c806f2, 0x00000ba3, 0x0000045c, 0x874d3a72, 0xaf1a1360},
-       {0x40d97470, 0x000005e1, 0x0000058d, 0x87a9684f, 0x524244a8},
-       {0x4312179c, 0x00000056, 0x0000070e, 0x809a00f5, 0xf9e940b0},
-       {0x13d5f84c, 0x00000a2d, 0x00000104, 0xf3d27578, 0x5d33341c},
-       {0x1f302cb2, 0x00000151, 0x00000014, 0x1e162693, 0x53c3cfc3},
-       {0xe491db24, 0x00000600, 0x000006f6, 0x7ff09615, 0xa300ecf7},
-       {0xf9a98069, 0x000002ba, 0x000002ad, 0x01af7387, 0x31c0911e},
-       {0xe9c477ad, 0x0000015f, 0x00000778, 0x6facf9a0, 0x1993b688},
-       {0x353f32b2, 0x0000087c, 0x00000783, 0x6cc964ea, 0x418db561},
-       {0x78e1b24f, 0x00000650, 0x000006a8, 0xb3bb7c27, 0xf2aad006},
-       {0x61aa400e, 0x00000049, 0x00000254, 0xb8cd1681, 0x79150b15},
-       {0xb84b10b0, 0x00000f73, 0x0000008c, 0x406a6450, 0x0c705222},
-       {0x9fa99c9c, 0x00000a7c, 0x000004d7, 0xfb3d21b4, 0xe4e789df},
-       {0x3fc9ebe3, 0x00000cd9, 0x000000d6, 0x43803f9c, 0x5a152be5},
-       {0x529879cd, 0x000002f2, 0x00000595, 0x78b4c6a6, 0xf7236ec4},
-       {0x3a933019, 0x00000516, 0x00000266, 0xdcb45436, 0x2c7935f5},
-       {0x887b4977, 0x00000227, 0x0000038d, 0xc5f7c3d9, 0x0d6d7df6},
-       {0x770745de, 0x000008c6, 0x00000739, 0xf69145e8, 0x47d5efc9},
-       {0x28be3b47, 0x00000c46, 0x0000032b, 0x764c028f, 0x1eb70d64},
-       {0x5013a050, 0x00000cf6, 0x00000309, 0xea8fe164, 0x186affa4},
-       {0x2ec4c9ba, 0x000006e8, 0x0000078d, 0xa35557a9, 0xb41f49ec},
-       {0xa9f950c9, 0x00000d33, 0x000002cc, 0x41ea8618, 0xab8dfae3},
-       {0x5b520229, 0x000007b2, 0x00000484, 0x44569f1f, 0x607a8052},
-       {0xd8dcbbfc, 0x0000002f, 0x0000048c, 0xdb88ab8b, 0xf1c411f1},
-       {0x25529792, 0x00000d1d, 0x000002e2, 0x20cda404, 0x32683a2d},
-       {0x9f3f6d71, 0x00000238, 0x0000079a, 0x0720443e, 0x4b8ba2ff},
-       {0x64121215, 0x000007ff, 0x0000038f, 0x6aacff2c, 0x3b84233b},
-       {0xfb6cdde0, 0x00000ef8, 0x00000107, 0xbd43a0f1, 0x926624d0},
-       {0x221c9d6f, 0x000007b6, 0x0000014f, 0xb67f834b, 0x2bdedda4},
-       {0x030e1de4, 0x00000836, 0x000004b4, 0x0d67d26a, 0x75a73b73},
-       {0xb56fa6cf, 0x00000c07, 0x000003f8, 0x60601ac1, 0x10a43f35},
-       {0xb55c89f5, 0x0000098e, 0x000001d4, 0x2400efbe, 0x006e28eb},
-       {0x5e90b6d5, 0x0000070b, 0x000003ea, 0x3bb5d6ea, 0xb175fa6b},
-       {0x2a7045ae, 0x00000961, 0x00000633, 0xfca89e4b, 0x962cd6d2},
-       {0x8b374ea9, 0x000006ba, 0x00000780, 0xbce036ed, 0x4dc8279b},
-       {0x8bd90bc9, 0x00000562, 0x00000369, 0xcb26a24b, 0x50dee743},
-       {0x5b1b1762, 0x000000fd, 0x0000051a, 0x33cdda07, 0xee75ff7b},
-       {0xa4153555, 0x0000058f, 0x000005c7, 0xbe50eeca, 0xe73fffcc},
-       {0x0be1f931, 0x00000651, 0x00000672, 0x95a25753, 0x4ad6270f},
-       {0xb7e78618, 0x00000a7f, 0x000002bb, 0xe06bcc1c, 0x1a35ee59},
-       {0x4a9bc41b, 0x00000e51, 0x000001ae, 0x709e8d2c, 0x75080ca8},
-       {0xfc359d13, 0x00000440, 0x000002f8, 0x0a58451f, 0x6fa3cfbf},
-       {0x5aa48619, 0x000006d1, 0x00000284, 0x928ead83, 0xbd600efc},
-       {0xa609afa8, 0x0000053e, 0x00000272, 0xb048c141, 0x184f80bb},
-       {0x3f108afb, 0x00000949, 0x00000150, 0x9a6bb5bc, 0x0ea02be1},
-       {0x79bec2d3, 0x000008ed, 0x00000712, 0x32692d57, 0x2eb13289},
-       {0x9429e067, 0x00000bc3, 0x0000043c, 0x5295ceff, 0x8a9014a7},
-       {0xae58b96a, 0x0000082d, 0x000007d2, 0xc2a681ba, 0x6af94089},
-       {0x95df24be, 0x00000985, 0x000004c1, 0x3a287765, 0x379fcb42},
-       {0x5e94976f, 0x00000596, 0x000004ed, 0xff00c489, 0x991fc1f5},
-       {0xf5e5f1de, 0x00000d31, 0x000002ce, 0x35f28e91, 0x543def1a},
-       {0xa2c219cf, 0x00000a3c, 0x00000374, 0x707d21eb, 0xa6d28bc1},
-       {0xf21b6ceb, 0x00000919, 0x00000135, 0x0847fb8b, 0x224468c2},
-       {0xaa988728, 0x00000787, 0x00000771, 0x885aeaa4, 0x814db00b},
-       {0xaa5dfaac, 0x000003e5, 0x0000051b, 0x52c48ab7, 0x725bef8a},
-       {0x0a053968, 0x00000d2a, 0x000002d5, 0x7a90256d, 0xc53b9402},
-       {0x1421dc20, 0x00000eef, 0x00000110, 0x97d6da24, 0x10846935},
-       {0xb47c2166, 0x00000a6a, 0x00000209, 0xcfd6cc52, 0x46e2797e},
-       {0x77dd1955, 0x000000de, 0x00000266, 0xba74bcaa, 0x4fa3fe9c},
-       {0x68a03cc2, 0x0000082f, 0x000007b0, 0x752bd5d8, 0x4f760c63},
-       {0x0226b0a3, 0x00000a5f, 0x000005a0, 0x82de4970, 0x8ee1310e},
-       {0x637bf3b1, 0x00000d93, 0x0000026c, 0x5c7115cb, 0x9f6a0ced},
-       {0x3b120edf, 0x00000c13, 0x000003ec, 0x80d7d20f, 0x241657d5},
-       {0xe2456780, 0x000002eb, 0x00000641, 0xc0a5d289, 0x74df96b4},
-       {0x9b2e7125, 0x00000c0c, 0x000003f3, 0xcc15f57e, 0x03e290bf},
-       {0x153033ef, 0x00000787, 0x000006b6, 0x3cde443b, 0x7bf1d121},
-       {0x18458b3f, 0x0000066c, 0x00000561, 0x9a2bd8c6, 0x9d564bef},
-       {0x4ff9d4b9, 0x00000c8f, 0x0000033a, 0xd0ee6d6d, 0xee00aa0b},
-       {0xdf84b5d9, 0x00000802, 0x0000029a, 0xdab0d74a, 0xd0cb63dc},
-       {0x81ee15df, 0x000003ce, 0x00000725, 0x9942e2de, 0xe48fb26b},
-       {0x5c768e04, 0x00000afd, 0x00000160, 0x36110831, 0x8dc74483},
-       {0xe5e18094, 0x00000b4b, 0x000000a0, 0xffa3e4a7, 0xc0145e1b},
-       {0xed7263b6, 0x00000d0d, 0x000002f2, 0xb0006a35, 0x5468ae3a},
-       {0x5bfde7d7, 0x000006fb, 0x00000554, 0xa4193b76, 0xb73d34b2},
-       {0x67f4a743, 0x00000b85, 0x0000047a, 0xf05c8d8f, 0x4f843e49},
-       {0xf13bdf22, 0x00000ff7, 0x00000008, 0x816351eb, 0x41f537f6},
-       {0x08ecc608, 0x00000d5d, 0x00000098, 0x90492772, 0xf5172204},
-       {0x296f52ba, 0x000004f9, 0x00000788, 0x5e5a4896, 0xe01d5b46},
-       {0xbe4624c2, 0x00000427, 0x000004ef, 0xcd267b94, 0x7b9069f4},
-       {0x906f7c7c, 0x00000a05, 0x0000003f, 0x03fcfc33, 0x7b6ff563},
-       {0x8f7b323e, 0x00000458, 0x000004c7, 0xcd4969c8, 0xd4c22ada},
-       {0x88d6593d, 0x00000597, 0x000005b5, 0xf199cd3b, 0x5c3e8ca2},
-       {0x978a7768, 0x00000268, 0x000001d3, 0xb28c95bd, 0x49a2cc67},
-       {0x857a621e, 0x000007a7, 0x000003a8, 0xf4bf84ab, 0xde26f369},
-       {0xb0e121ef, 0x000005be, 0x00000644, 0x28747c14, 0x61d4dc6b},
+       {0xffffffff, 0x00000000, 0x00001000, 0x13934bef, 0xd8ddcdc3},
+       {0xfe7328ea, 0x00000763, 0x00000717, 0xed2c0d70, 0xc863aef8},
+       {0x4c40684e, 0x00000721, 0x0000011e, 0xd7f46ccc, 0x173a11c4},
+       {0x6b487f90, 0x00000264, 0x000007bc, 0x759e9939, 0xd6307c56},
+       {0x9f5810db, 0x00000afa, 0x00000255, 0x2685197f, 0x2e5c9201},
+       {0xb15c4755, 0x00000d5b, 0x000002a4, 0xd8fadcb5, 0xf682c4be},
+       {0x06518253, 0x00000ffb, 0x00000004, 0xabee2433, 0x3d8abdf9},
+       {0xd9e71c55, 0x00000a2a, 0x00000259, 0x96682af2, 0x47b4d26c},
+       {0x0c1ae843, 0x00000ce4, 0x0000031b, 0x7b637c43, 0x62b47e8b},
+       {0xec3cd517, 0x000002ff, 0x00000566, 0x5d719a77, 0xff5bc5b7},
+       {0x77828e95, 0x0000067f, 0x0000038f, 0x43ee5b6c, 0x1a0cfacd},
+       {0xec87b4e3, 0x00000d1c, 0x000002e3, 0x2ddd2eee, 0x275118a7},
+       {0x412158bb, 0x00000eee, 0x00000111, 0x67b38ba2, 0xa74ecff5},
+       {0x2e52de3e, 0x00000c4a, 0x000003b5, 0xbcc5d61d, 0xbd800707},
+       {0x6ddaae8b, 0x00000d99, 0x00000266, 0x8b535544, 0xecbde1a1},
+       {0x049b6cb1, 0x000009c5, 0x000000b0, 0xfc22cabc, 0xfb78eb9f},
+       {0x77d4b954, 0x0000028a, 0x000007fa, 0x71d00923, 0x8c116f85},
+       {0x5e192355, 0x00000ac1, 0x000001fa, 0xb966b81a, 0x5aa17bbe},
+       {0x7d80b71d, 0x00000213, 0x000001e0, 0x2bba371a, 0xb5906aa6},
+       {0x01f6f1e4, 0x000001d6, 0x00000395, 0xb7e8a647, 0x3ad112b1},
+       {0x1dfabb13, 0x00000e14, 0x000001eb, 0x53917fba, 0xbaee0339},
+       {0xb00a4449, 0x00000bf6, 0x00000409, 0xedecb577, 0x6f3a3979},
+       {0x7ecd3981, 0x0000083f, 0x0000016b, 0xefef62b9, 0xe3e52eed},
+       {0xf8f330d2, 0x000004be, 0x00000757, 0x9357c9f3, 0x0835bc1b},
+       {0x03c38af2, 0x00000d23, 0x000002dc, 0x360fa8c0, 0x2ca885e6},
+       {0x687bb79b, 0x00000f3d, 0x000000c2, 0x448d3be2, 0x79be2f78},
+       {0x6710f550, 0x000009e9, 0x00000603, 0xdbfd1998, 0x1d25f627},
+       {0x873171d1, 0x00000787, 0x000004d5, 0xab7f1b62, 0xa76a5656},
+       {0x373b1314, 0x00000f0f, 0x000000f0, 0x184098ab, 0xba273974},
+       {0x90fad9cd, 0x00000ead, 0x00000152, 0x23ce52ff, 0xb7bc958c},
+       {0x19676fe7, 0x0000007d, 0x0000070d, 0xf8a76f1e, 0xf882b644},
+       {0x89facd45, 0x000005f3, 0x00000473, 0x4331a006, 0xe9dc1396},
+       {0x6f173747, 0x00000fc3, 0x0000003c, 0xb012f08e, 0xc6b888ee},
+       {0x4b44a106, 0x0000075a, 0x0000008b, 0xf6f7ac38, 0x60cd2b74},
+       {0xb620ad06, 0x00000774, 0x0000017e, 0xd34558e6, 0x3a0a615b},
+       {0x976f21e9, 0x000008d7, 0x0000034a, 0xe533aa3a, 0xa99e60be},
+       {0x687628c0, 0x000006c5, 0x0000061b, 0x3a840b15, 0x9bfcaef2},
+       {0xe24ac108, 0x00000cd0, 0x0000032f, 0x51010ae8, 0x20958672},
+       {0x361c44a3, 0x00000304, 0x00000719, 0xfd7bd481, 0xd70ff2b2},
+       {0xd93ff95e, 0x00000db7, 0x0000008e, 0xcfbbc304, 0xad716acd},
+       {0xed752d12, 0x00000883, 0x00000091, 0x65a6c868, 0x95c71c7b},
+       {0xb4ff4b54, 0x000003d3, 0x000001c1, 0xf82597e7, 0x44b7f99b},
+       {0x111b520f, 0x00000708, 0x000000eb, 0xc3e109f3, 0x71bc01ee},
+       {0x62c806f2, 0x00000ba3, 0x0000045c, 0x874d3a72, 0xc539b753},
+       {0x40d97470, 0x000005e1, 0x0000058d, 0x87a9684f, 0xea6073a5},
+       {0x4312179c, 0x00000056, 0x0000070e, 0x809a00f5, 0x209aea3b},
+       {0x13d5f84c, 0x00000a2d, 0x00000104, 0xf3d27578, 0xe087a8b6},
+       {0x1f302cb2, 0x00000151, 0x00000014, 0x1e162693, 0x95e4b90e},
+       {0xe491db24, 0x00000600, 0x000006f6, 0x7ff09615, 0x77611523},
+       {0xf9a98069, 0x000002ba, 0x000002ad, 0x01af7387, 0xea925faa},
+       {0xe9c477ad, 0x0000015f, 0x00000778, 0x6facf9a0, 0x1130f736},
+       {0x353f32b2, 0x0000087c, 0x00000783, 0x6cc964ea, 0x32459994},
+       {0x78e1b24f, 0x00000650, 0x000006a8, 0xb3bb7c27, 0x5a632f78},
+       {0x61aa400e, 0x00000049, 0x00000254, 0xb8cd1681, 0xdf2652d5},
+       {0xb84b10b0, 0x00000f73, 0x0000008c, 0x406a6450, 0x3619d31b},
+       {0x9fa99c9c, 0x00000a7c, 0x000004d7, 0xfb3d21b4, 0xea31c743},
+       {0x3fc9ebe3, 0x00000cd9, 0x000000d6, 0x43803f9c, 0x1f76a809},
+       {0x529879cd, 0x000002f2, 0x00000595, 0x78b4c6a6, 0x63b9b93f},
+       {0x3a933019, 0x00000516, 0x00000266, 0xdcb45436, 0x8f99c98c},
+       {0x887b4977, 0x00000227, 0x0000038d, 0xc5f7c3d9, 0xaf5e3091},
+       {0x770745de, 0x000008c6, 0x00000739, 0xf69145e8, 0x53d0dce1},
+       {0x28be3b47, 0x00000c46, 0x0000032b, 0x764c028f, 0x106d0905},
+       {0x5013a050, 0x00000cf6, 0x00000309, 0xea8fe164, 0x62180b57},
+       {0x2ec4c9ba, 0x000006e8, 0x0000078d, 0xa35557a9, 0xf44430a4},
+       {0xa9f950c9, 0x00000d33, 0x000002cc, 0x41ea8618, 0x587b4eb3},
+       {0x5b520229, 0x000007b2, 0x00000484, 0x44569f1f, 0x92406c32},
+       {0xd8dcbbfc, 0x0000002f, 0x0000048c, 0xdb88ab8b, 0x13bfe70e},
+       {0x25529792, 0x00000d1d, 0x000002e2, 0x20cda404, 0x19d3b4e4},
+       {0x9f3f6d71, 0x00000238, 0x0000079a, 0x0720443e, 0x3c107021},
+       {0x64121215, 0x000007ff, 0x0000038f, 0x6aacff2c, 0xb82fdc3e},
+       {0xfb6cdde0, 0x00000ef8, 0x00000107, 0xbd43a0f1, 0xab0d3c1d},
+       {0x221c9d6f, 0x000007b6, 0x0000014f, 0xb67f834b, 0x1371ad05},
+       {0x030e1de4, 0x00000836, 0x000004b4, 0x0d67d26a, 0xe2e72df1},
+       {0xb56fa6cf, 0x00000c07, 0x000003f8, 0x60601ac1, 0x039de73e},
+       {0xb55c89f5, 0x0000098e, 0x000001d4, 0x2400efbe, 0xfe39a2bb},
+       {0x5e90b6d5, 0x0000070b, 0x000003ea, 0x3bb5d6ea, 0xf0f794a0},
+       {0x2a7045ae, 0x00000961, 0x00000633, 0xfca89e4b, 0xe66ce41c},
+       {0x8b374ea9, 0x000006ba, 0x00000780, 0xbce036ed, 0x4cb28ef7},
+       {0x8bd90bc9, 0x00000562, 0x00000369, 0xcb26a24b, 0x40236d1d},
+       {0x5b1b1762, 0x000000fd, 0x0000051a, 0x33cdda07, 0xc32e420a},
+       {0xa4153555, 0x0000058f, 0x000005c7, 0xbe50eeca, 0x83a67f35},
+       {0x0be1f931, 0x00000651, 0x00000672, 0x95a25753, 0x88f1aac1},
+       {0xb7e78618, 0x00000a7f, 0x000002bb, 0xe06bcc1c, 0x74274f66},
+       {0x4a9bc41b, 0x00000e51, 0x000001ae, 0x709e8d2c, 0x54eff534},
+       {0xfc359d13, 0x00000440, 0x000002f8, 0x0a58451f, 0x55e9363f},
+       {0x5aa48619, 0x000006d1, 0x00000284, 0x928ead83, 0x31041c06},
+       {0xa609afa8, 0x0000053e, 0x00000272, 0xb048c141, 0x4704efba},
+       {0x3f108afb, 0x00000949, 0x00000150, 0x9a6bb5bc, 0x4e4430c8},
+       {0x79bec2d3, 0x000008ed, 0x00000712, 0x32692d57, 0x11d52a7b},
+       {0x9429e067, 0x00000bc3, 0x0000043c, 0x5295ceff, 0x04640f4d},
+       {0xae58b96a, 0x0000082d, 0x000007d2, 0xc2a681ba, 0xf7ca4a2c},
+       {0x95df24be, 0x00000985, 0x000004c1, 0x3a287765, 0x2c4af003},
+       {0x5e94976f, 0x00000596, 0x000004ed, 0xff00c489, 0x5ae11687},
+       {0xf5e5f1de, 0x00000d31, 0x000002ce, 0x35f28e91, 0x30d47957},
+       {0xa2c219cf, 0x00000a3c, 0x00000374, 0x707d21eb, 0x2a14a255},
+       {0xf21b6ceb, 0x00000919, 0x00000135, 0x0847fb8b, 0xcb8d3b93},
+       {0xaa988728, 0x00000787, 0x00000771, 0x885aeaa4, 0x6531b509},
+       {0xaa5dfaac, 0x000003e5, 0x0000051b, 0x52c48ab7, 0xe43cc5e9},
+       {0x0a053968, 0x00000d2a, 0x000002d5, 0x7a90256d, 0x8004765c},
+       {0x1421dc20, 0x00000eef, 0x00000110, 0x97d6da24, 0x1378f6ff},
+       {0xb47c2166, 0x00000a6a, 0x00000209, 0xcfd6cc52, 0x676e14a5},
+       {0x77dd1955, 0x000000de, 0x00000266, 0xba74bcaa, 0xc71b429c},
+       {0x68a03cc2, 0x0000082f, 0x000007b0, 0x752bd5d8, 0x19ed14aa},
+       {0x0226b0a3, 0x00000a5f, 0x000005a0, 0x82de4970, 0xf654d3ed},
+       {0x637bf3b1, 0x00000d93, 0x0000026c, 0x5c7115cb, 0x3cccb57e},
+       {0x3b120edf, 0x00000c13, 0x000003ec, 0x80d7d20f, 0x92132798},
+       {0xe2456780, 0x000002eb, 0x00000641, 0xc0a5d289, 0x6160c87a},
+       {0x9b2e7125, 0x00000c0c, 0x000003f3, 0xcc15f57e, 0x6f00f637},
+       {0x153033ef, 0x00000787, 0x000006b6, 0x3cde443b, 0xb46caa6e},
+       {0x18458b3f, 0x0000066c, 0x00000561, 0x9a2bd8c6, 0xb6c29121},
+       {0x4ff9d4b9, 0x00000c8f, 0x0000033a, 0xd0ee6d6d, 0xc81cf380},
+       {0xdf84b5d9, 0x00000802, 0x0000029a, 0xdab0d74a, 0xb2464559},
+       {0x81ee15df, 0x000003ce, 0x00000725, 0x9942e2de, 0x4ccf571b},
+       {0x5c768e04, 0x00000afd, 0x00000160, 0x36110831, 0xae0b305a},
+       {0xe5e18094, 0x00000b4b, 0x000000a0, 0xffa3e4a7, 0x6c8a4f09},
+       {0xed7263b6, 0x00000d0d, 0x000002f2, 0xb0006a35, 0x7e04af8c},
+       {0x5bfde7d7, 0x000006fb, 0x00000554, 0xa4193b76, 0xb3a91d12},
+       {0x67f4a743, 0x00000b85, 0x0000047a, 0xf05c8d8f, 0xfb472fdf},
+       {0xf13bdf22, 0x00000ff7, 0x00000008, 0x816351eb, 0xf347f235},
+       {0x08ecc608, 0x00000d5d, 0x00000098, 0x90492772, 0x0b7f1521},
+       {0x296f52ba, 0x000004f9, 0x00000788, 0x5e5a4896, 0x1cc67088},
+       {0xbe4624c2, 0x00000427, 0x000004ef, 0xcd267b94, 0x550caefd},
+       {0x906f7c7c, 0x00000a05, 0x0000003f, 0x03fcfc33, 0x9ed82a02},
+       {0x8f7b323e, 0x00000458, 0x000004c7, 0xcd4969c8, 0x633c38a8},
+       {0x88d6593d, 0x00000597, 0x000005b5, 0xf199cd3b, 0x0491452f},
+       {0x978a7768, 0x00000268, 0x000001d3, 0xb28c95bd, 0x1a42fe61},
+       {0x857a621e, 0x000007a7, 0x000003a8, 0xf4bf84ab, 0xcd0694c6},
+       {0xb0e121ef, 0x000005be, 0x00000644, 0x28747c14, 0xf0510c72},
        {0, 0, 0, 0, 0},
 };
 
@@ -1114,15 +902,15 @@ static int test_crc32c(void)
        while (t->length) {
                uint32_t be, le;
                le = ext2fs_crc32c_le(t->crc, test_buf + t->start, t->length);
-               be = ext2fs_crc32c_be(t->crc, test_buf + t->start, t->length);
-               if (le != t->crc_le) {
+               be = ext2fs_crc32_be(t->crc, test_buf + t->start, t->length);
+               if (le != t->crc32c_le) {
                        printf("Test %d LE fails, %x != %x\n",
-                              (int) (t - test), le, t->crc_le);
+                              (int) (t - test), le, t->crc32c_le);
                        failures++;
                }
-               if (be != t->crc_be) {
+               if (be != t->crc32_be) {
                        printf("Test %d BE fails, %x != %x\n",
-                              (int) (t - test), be, t->crc_be);
+                              (int) (t - test), be, t->crc32_be);
                        failures++;
                }
                t++;
index 023f2c0..3f9a09e 100644 (file)
@@ -1,10 +1,18 @@
 /*
+ * There are multiple 16-bit CRC polynomials in common use, but this is
+ * *the* standard CRC-32 polynomial, first popularized by Ethernet.
+ * x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x^1+x^0
+ */
+#define CRCPOLY_LE 0xedb88320
+#define CRCPOLY_BE 0x04c11db7
+
+/*
  * This is the CRC32c polynomial, as outlined by Castagnoli.
  * x^32+x^28+x^27+x^26+x^25+x^23+x^22+x^20+x^19+x^18+x^14+x^13+x^11+x^10+x^9+
  * x^8+x^6+x^0
  */
-#define CRCPOLY_LE 0x82F63B78
-#define CRCPOLY_BE 0x1EDC6F41
+#define CRC32C_POLY_LE 0x82F63B78
+#define CRC32C_POLY_BE 0x1EDC6F41
 
 /* How many bits at a time to use.  Valid values are 1, 2, 4, 8, 32 and 64. */
 /* For less performance-sensitive, use 4 */
index 5ee3445..607f74a 100644 (file)
 #define STATIC static
 #endif
 
+static __u32 ext2fs_mmp_csum(ext2_filsys fs, struct mmp_struct *mmp)
+{
+       int offset = offsetof(struct mmp_struct, mmp_checksum);
+
+       return ext2fs_crc32c_le(fs->csum_seed, (unsigned char *)mmp, offset);
+}
+
+int ext2fs_mmp_csum_verify(ext2_filsys fs, struct mmp_struct *mmp)
+{
+       __u32 calculated;
+
+       if (!EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+                                       EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
+               return 1;
+
+       calculated = ext2fs_mmp_csum(fs, mmp);
+
+       return ext2fs_le32_to_cpu(mmp->mmp_checksum) == calculated;
+}
+
+errcode_t ext2fs_mmp_csum_set(ext2_filsys fs, struct mmp_struct *mmp)
+{
+       __u32 crc;
+
+       if (!EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+               EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
+               return 0;
+
+       crc = ext2fs_mmp_csum(fs, mmp);
+       mmp->mmp_checksum = ext2fs_cpu_to_le32(crc);
+
+       return 0;
+}
+
+int ext2fs_verify_csum_type(ext2_filsys fs, struct ext2_super_block *sb)
+{
+       if (!EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+                                       EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
+               return 1;
+
+       return sb->s_checksum_type == EXT2_CRC32C_CHKSUM;
+}
+
+static __u32 ext2fs_superblock_csum(ext2_filsys fs EXT2FS_ATTR((unused)),
+                                   struct ext2_super_block *sb)
+{
+       int offset = offsetof(struct ext2_super_block, s_checksum);
+
+       return ext2fs_crc32c_le(~0, (unsigned char *)sb, offset);
+}
+
+int ext2fs_superblock_csum_verify(ext2_filsys fs, struct ext2_super_block *sb)
+{
+       __u32 calculated;
+
+       if (!EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+                                       EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
+               return 1;
+
+       calculated = ext2fs_superblock_csum(fs, sb);
+
+       return ext2fs_le32_to_cpu(sb->s_checksum) == calculated;
+}
+
+errcode_t ext2fs_superblock_csum_set(ext2_filsys fs,
+                                    struct ext2_super_block *sb)
+{
+       __u32 crc;
+
+       if (!EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+               EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
+               return 0;
+
+       crc = ext2fs_superblock_csum(fs, sb);
+       sb->s_checksum = ext2fs_cpu_to_le32(crc);
+
+       return 0;
+}
+
+static errcode_t ext2fs_ext_attr_block_csum(ext2_filsys fs,
+                                           ext2_ino_t inum EXT2FS_ATTR((unused)),
+                                           blk64_t block,
+                                           struct ext2_ext_attr_header *hdr,
+                                           __u32 *crc)
+{
+       char *buf = (char *)hdr;
+       __u32 old_crc = hdr->h_checksum;
+
+       hdr->h_checksum = 0;
+       block = ext2fs_cpu_to_le64(block);
+       *crc = ext2fs_crc32c_le(fs->csum_seed, (unsigned char *)&block,
+                               sizeof(block));
+       *crc = ext2fs_crc32c_le(*crc, (unsigned char *)buf, fs->blocksize);
+       hdr->h_checksum = old_crc;
+
+       return 0;
+}
+
+int ext2fs_ext_attr_block_csum_verify(ext2_filsys fs, ext2_ino_t inum,
+                                     blk64_t block,
+                                     struct ext2_ext_attr_header *hdr)
+{
+       __u32 calculated;
+       errcode_t retval;
+
+       if (!EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+                                       EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
+               return 1;
+
+       retval = ext2fs_ext_attr_block_csum(fs, inum, block, hdr, &calculated);
+       if (retval)
+               return 0;
+
+       return ext2fs_le32_to_cpu(hdr->h_checksum) == calculated;
+}
+
+errcode_t ext2fs_ext_attr_block_csum_set(ext2_filsys fs, ext2_ino_t inum,
+                                        blk64_t block,
+                                        struct ext2_ext_attr_header *hdr)
+{
+       errcode_t retval;
+       __u32 crc;
+
+       if (!EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+               EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
+               return 0;
+
+       retval = ext2fs_ext_attr_block_csum(fs, inum, block, hdr, &crc);
+       if (retval)
+               return retval;
+       hdr->h_checksum = ext2fs_cpu_to_le32(crc);
+       return 0;
+}
+
+static __u16 do_nothing16(__u16 x)
+{
+       return x;
+}
+
+static __u16 disk_to_host16(__u16 x)
+{
+       return ext2fs_le16_to_cpu(x);
+}
+
+static errcode_t __get_dx_countlimit(ext2_filsys fs,
+                                    struct ext2_dir_entry *dirent,
+                                    struct ext2_dx_countlimit **cc,
+                                    int *offset,
+                                    int need_swab)
+{
+       struct ext2_dir_entry *dp;
+       struct ext2_dx_root_info *root;
+       struct ext2_dx_countlimit *c;
+       int count_offset, max_sane_entries;
+       unsigned int rec_len;
+       __u16 (*translate)(__u16) = (need_swab ? disk_to_host16 : do_nothing16);
+
+       rec_len = translate(dirent->rec_len);
+
+       if (rec_len == fs->blocksize && translate(dirent->name_len) == 0)
+               count_offset = 8;
+       else if (rec_len == 12) {
+               dp = (struct ext2_dir_entry *)(((char *)dirent) + rec_len);
+               rec_len = translate(dp->rec_len);
+               if (rec_len != fs->blocksize - 12)
+                       return EXT2_ET_DB_NOT_FOUND;
+               root = (struct ext2_dx_root_info *)(((char *)dp + 12));
+               if (root->reserved_zero ||
+                   root->info_length != sizeof(struct ext2_dx_root_info))
+                       return EXT2_ET_DB_NOT_FOUND;
+               count_offset = 32;
+       } else
+               return EXT2_ET_DB_NOT_FOUND;
+
+       c = (struct ext2_dx_countlimit *)(((char *)dirent) + count_offset);
+       max_sane_entries = (fs->blocksize - count_offset) /
+                          sizeof(struct ext2_dx_entry);
+       if (ext2fs_le16_to_cpu(c->limit) > max_sane_entries ||
+           ext2fs_le16_to_cpu(c->count) > max_sane_entries)
+               return EXT2_ET_DIR_NO_SPACE_FOR_CSUM;
+
+       if (offset)
+               *offset = count_offset;
+       if (cc)
+               *cc = c;
+
+       return 0;
+}
+
+errcode_t ext2fs_get_dx_countlimit(ext2_filsys fs,
+                                  struct ext2_dir_entry *dirent,
+                                  struct ext2_dx_countlimit **cc,
+                                  int *offset)
+{
+       return __get_dx_countlimit(fs, dirent, cc, offset, 0);
+}
+
+void ext2fs_initialize_dirent_tail(ext2_filsys fs,
+                                  struct ext2_dir_entry_tail *t)
+{
+       memset(t, 0, sizeof(struct ext2_dir_entry_tail));
+       ext2fs_set_rec_len(fs, sizeof(struct ext2_dir_entry_tail),
+                          (struct ext2_dir_entry *)t);
+       t->det_reserved_name_len = EXT2_DIR_NAME_LEN_CSUM;
+}
+
+static errcode_t __get_dirent_tail(ext2_filsys fs,
+                                  struct ext2_dir_entry *dirent,
+                                  struct ext2_dir_entry_tail **tt,
+                                  int need_swab)
+{
+       struct ext2_dir_entry *d;
+       void *top;
+       struct ext2_dir_entry_tail *t;
+       unsigned int rec_len;
+       errcode_t retval = 0;
+       __u16 (*translate)(__u16) = (need_swab ? disk_to_host16 : do_nothing16);
+
+       d = dirent;
+       top = EXT2_DIRENT_TAIL(dirent, fs->blocksize);
+
+       rec_len = translate(d->rec_len);
+       while (rec_len && !(rec_len & 0x3)) {
+               d = (struct ext2_dir_entry *)(((char *)d) + rec_len);
+               if ((void *)d >= top)
+                       break;
+               rec_len = translate(d->rec_len);
+       }
+
+       if (d != top)
+               return EXT2_ET_DIR_NO_SPACE_FOR_CSUM;
+
+       t = (struct ext2_dir_entry_tail *)d;
+       if (t->det_reserved_zero1 ||
+           translate(t->det_rec_len) != sizeof(struct ext2_dir_entry_tail) ||
+           translate(t->det_reserved_name_len) != EXT2_DIR_NAME_LEN_CSUM)
+               return EXT2_ET_DIR_NO_SPACE_FOR_CSUM;
+
+       if (tt)
+               *tt = t;
+       return retval;
+}
+
+int ext2fs_dirent_has_tail(ext2_filsys fs, struct ext2_dir_entry *dirent)
+{
+       return __get_dirent_tail(fs, dirent, NULL, 0) == 0;
+}
+
+static errcode_t ext2fs_dirent_csum(ext2_filsys fs, ext2_ino_t inum,
+                                   struct ext2_dir_entry *dirent, __u32 *crc,
+                                   int size)
+{
+       errcode_t retval;
+       char *buf = (char *)dirent;
+       __u32 gen;
+       struct ext2_inode inode;
+
+       retval = ext2fs_read_inode(fs, inum, &inode);
+       if (retval)
+               return retval;
+
+       inum = ext2fs_cpu_to_le32(inum);
+       gen = ext2fs_cpu_to_le32(inode.i_generation);
+       *crc = ext2fs_crc32c_le(fs->csum_seed, (unsigned char *)&inum,
+                               sizeof(inum));
+       *crc = ext2fs_crc32c_le(*crc, (unsigned char *)&gen, sizeof(gen));
+       *crc = ext2fs_crc32c_le(*crc, (unsigned char *)buf, size);
+
+       return 0;
+}
+
+int ext2fs_dirent_csum_verify(ext2_filsys fs, ext2_ino_t inum,
+                             struct ext2_dir_entry *dirent)
+{
+       errcode_t retval;
+       __u32 calculated;
+       struct ext2_dir_entry_tail *t;
+
+       retval = __get_dirent_tail(fs, dirent, &t, 1);
+       if (retval)
+               return 1;
+
+       /*
+        * The checksum field is overlaid with the dirent->name field
+        * so the swapfs.c functions won't change the endianness.
+        */
+       retval = ext2fs_dirent_csum(fs, inum, dirent, &calculated,
+                                   (char *)t - (char *)dirent);
+       if (retval)
+               return 0;
+       return ext2fs_le32_to_cpu(t->det_checksum) == calculated;
+}
+
+static errcode_t ext2fs_dirent_csum_set(ext2_filsys fs, ext2_ino_t inum,
+                                       struct ext2_dir_entry *dirent)
+{
+       errcode_t retval;
+       __u32 crc;
+       struct ext2_dir_entry_tail *t;
+
+       retval = __get_dirent_tail(fs, dirent, &t, 1);
+       if (retval)
+               return retval;
+
+       /* swapfs.c functions don't change the checksum endianness */
+       retval = ext2fs_dirent_csum(fs, inum, dirent, &crc,
+                                   (char *)t - (char *)dirent);
+       if (retval)
+               return retval;
+       t->det_checksum = ext2fs_cpu_to_le32(crc);
+       return 0;
+}
+
+static errcode_t ext2fs_dx_csum(ext2_filsys fs, ext2_ino_t inum,
+                               struct ext2_dir_entry *dirent,
+                               __u32 *crc, int count_offset, int count,
+                               struct ext2_dx_tail *t)
+{
+       errcode_t retval;
+       char *buf = (char *)dirent;
+       int size;
+       __u32 old_csum, gen;
+       struct ext2_inode inode;
+
+       size = count_offset + (count * sizeof(struct ext2_dx_entry));
+       old_csum = t->dt_checksum;
+       t->dt_checksum = 0;
+
+       retval = ext2fs_read_inode(fs, inum, &inode);
+       if (retval)
+               return retval;
+
+       inum = ext2fs_cpu_to_le32(inum);
+       gen = ext2fs_cpu_to_le32(inode.i_generation);
+       *crc = ext2fs_crc32c_le(fs->csum_seed, (unsigned char *)&inum,
+                               sizeof(inum));
+       *crc = ext2fs_crc32c_le(*crc, (unsigned char *)&gen, sizeof(gen));
+       *crc = ext2fs_crc32c_le(*crc, (unsigned char *)buf, size);
+       *crc = ext2fs_crc32c_le(*crc, (unsigned char *)t,
+                               sizeof(struct ext2_dx_tail));
+       t->dt_checksum = old_csum;
+
+       return 0;
+}
+
+static int ext2fs_dx_csum_verify(ext2_filsys fs, ext2_ino_t inum,
+                                struct ext2_dir_entry *dirent)
+{
+       __u32 calculated;
+       errcode_t retval;
+       struct ext2_dx_countlimit *c;
+       struct ext2_dx_tail *t;
+       int count_offset, limit, count;
+
+       retval = __get_dx_countlimit(fs, dirent, &c, &count_offset, 1);
+       if (retval)
+               return 1;
+       limit = ext2fs_le16_to_cpu(c->limit);
+       count = ext2fs_le16_to_cpu(c->count);
+       if (count_offset + (limit * sizeof(struct ext2_dx_entry)) >
+           fs->blocksize - sizeof(struct ext2_dx_tail))
+               return 0;
+       /* htree structs are accessed in LE order */
+       t = (struct ext2_dx_tail *)(((struct ext2_dx_entry *)c) + limit);
+       retval = ext2fs_dx_csum(fs, inum, dirent, &calculated, count_offset,
+                               count, t);
+       if (retval)
+               return 0;
+
+       return ext2fs_le32_to_cpu(t->dt_checksum) == calculated;
+}
+
+static errcode_t ext2fs_dx_csum_set(ext2_filsys fs, ext2_ino_t inum,
+                                   struct ext2_dir_entry *dirent)
+{
+       __u32 crc;
+       errcode_t retval = 0;
+       struct ext2_dx_countlimit *c;
+       struct ext2_dx_tail *t;
+       int count_offset, limit, count;
+
+       retval = __get_dx_countlimit(fs, dirent, &c, &count_offset, 1);
+       if (retval)
+               return retval;
+       limit = ext2fs_le16_to_cpu(c->limit);
+       count = ext2fs_le16_to_cpu(c->count);
+       if (count_offset + (limit * sizeof(struct ext2_dx_entry)) >
+           fs->blocksize - sizeof(struct ext2_dx_tail))
+               return EXT2_ET_DIR_NO_SPACE_FOR_CSUM;
+       t = (struct ext2_dx_tail *)(((struct ext2_dx_entry *)c) + limit);
+
+       /* htree structs are accessed in LE order */
+       retval = ext2fs_dx_csum(fs, inum, dirent, &crc, count_offset, count, t);
+       if (retval)
+               return retval;
+       t->dt_checksum = ext2fs_cpu_to_le32(crc);
+       return retval;
+}
+
+int ext2fs_dir_block_csum_verify(ext2_filsys fs, ext2_ino_t inum,
+                                struct ext2_dir_entry *dirent)
+{
+       if (!EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+                                       EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
+               return 1;
+
+       if (__get_dirent_tail(fs, dirent, NULL, 1) == 0)
+               return ext2fs_dirent_csum_verify(fs, inum, dirent);
+       if (__get_dx_countlimit(fs, dirent, NULL, NULL, 1) == 0)
+               return ext2fs_dx_csum_verify(fs, inum, dirent);
+
+       return 0;
+}
+
+errcode_t ext2fs_dir_block_csum_set(ext2_filsys fs, ext2_ino_t inum,
+                                   struct ext2_dir_entry *dirent)
+{
+       if (!EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+                                       EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
+               return 0;
+
+       if (__get_dirent_tail(fs, dirent, NULL, 1) == 0)
+               return ext2fs_dirent_csum_set(fs, inum, dirent);
+       if (__get_dx_countlimit(fs, dirent, NULL, NULL, 1) == 0)
+               return ext2fs_dx_csum_set(fs, inum, dirent);
+
+       if (fs->flags & EXT2_FLAG_IGNORE_CSUM_ERRORS)
+               return 0;
+       return EXT2_ET_DIR_NO_SPACE_FOR_CSUM;
+}
+
+#define EXT3_EXTENT_TAIL_OFFSET(hdr)   (sizeof(struct ext3_extent_header) + \
+       (sizeof(struct ext3_extent) * ext2fs_le16_to_cpu((hdr)->eh_max)))
+
+static struct ext3_extent_tail *get_extent_tail(struct ext3_extent_header *h)
+{
+       return (struct ext3_extent_tail *)(((char *)h) +
+                                          EXT3_EXTENT_TAIL_OFFSET(h));
+}
+
+static errcode_t ext2fs_extent_block_csum(ext2_filsys fs, ext2_ino_t inum,
+                                         struct ext3_extent_header *eh,
+                                         __u32 *crc)
+{
+       int size;
+       __u32 gen;
+       errcode_t retval;
+       struct ext2_inode inode;
+
+       size = EXT3_EXTENT_TAIL_OFFSET(eh) + offsetof(struct ext3_extent_tail,
+                                                     et_checksum);
+
+       retval = ext2fs_read_inode(fs, inum, &inode);
+       if (retval)
+               return retval;
+       inum = ext2fs_cpu_to_le32(inum);
+       gen = ext2fs_cpu_to_le32(inode.i_generation);
+       *crc = ext2fs_crc32c_le(fs->csum_seed, (unsigned char *)&inum,
+                               sizeof(inum));
+       *crc = ext2fs_crc32c_le(*crc, (unsigned char *)&gen, sizeof(gen));
+       *crc = ext2fs_crc32c_le(*crc, (unsigned char *)eh, size);
+
+       return 0;
+}
+
+int ext2fs_extent_block_csum_verify(ext2_filsys fs, ext2_ino_t inum,
+                                   struct ext3_extent_header *eh)
+{
+       errcode_t retval;
+       __u32 provided, calculated;
+       struct ext3_extent_tail *t = get_extent_tail(eh);
+
+       /*
+        * The extent tree structures are accessed in LE order, so we must
+        * swap the checksum bytes here.
+        */
+       if (!EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+                                       EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
+               return 1;
+
+       provided = ext2fs_le32_to_cpu(t->et_checksum);
+       retval = ext2fs_extent_block_csum(fs, inum, eh, &calculated);
+       if (retval)
+               return 0;
+
+       return provided == calculated;
+}
+
+errcode_t ext2fs_extent_block_csum_set(ext2_filsys fs, ext2_ino_t inum,
+                                      struct ext3_extent_header *eh)
+{
+       errcode_t retval;
+       __u32 crc;
+       struct ext3_extent_tail *t = get_extent_tail(eh);
+
+       if (!EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+                                       EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
+               return 0;
+
+       /*
+        * The extent tree structures are accessed in LE order, so we must
+        * swap the checksum bytes here.
+        */
+       retval = ext2fs_extent_block_csum(fs, inum, eh, &crc);
+       if (retval)
+               return retval;
+       t->et_checksum = ext2fs_cpu_to_le32(crc);
+       return retval;
+}
+
+int ext2fs_inode_bitmap_csum_verify(ext2_filsys fs, dgrp_t group,
+                                   char *bitmap, int size)
+{
+       struct ext4_group_desc *gdp = (struct ext4_group_desc *)
+                       ext2fs_group_desc(fs, fs->group_desc, group);
+       __u32 provided, calculated;
+
+       if (!EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+                                       EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
+               return 1;
+       provided = gdp->bg_inode_bitmap_csum_lo;
+       calculated = ext2fs_crc32c_le(fs->csum_seed, (unsigned char *)bitmap,
+                                     size);
+       if (fs->super->s_desc_size >= EXT4_BG_INODE_BITMAP_CSUM_HI_END)
+               provided |= (__u32)gdp->bg_inode_bitmap_csum_hi << 16;
+       else
+               calculated &= 0xFFFF;
+
+       return provided == calculated;
+}
+
+errcode_t ext2fs_inode_bitmap_csum_set(ext2_filsys fs, dgrp_t group,
+                                      char *bitmap, int size)
+{
+       __u32 crc;
+       struct ext4_group_desc *gdp = (struct ext4_group_desc *)
+                       ext2fs_group_desc(fs, fs->group_desc, group);
+
+       if (!EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+                                       EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
+               return 0;
+
+       crc = ext2fs_crc32c_le(fs->csum_seed, (unsigned char *)bitmap, size);
+       gdp->bg_inode_bitmap_csum_lo = crc & 0xFFFF;
+       if (fs->super->s_desc_size >= EXT4_BG_INODE_BITMAP_CSUM_HI_END)
+               gdp->bg_inode_bitmap_csum_hi = crc >> 16;
+
+       return 0;
+}
+
+int ext2fs_block_bitmap_csum_verify(ext2_filsys fs, dgrp_t group,
+                                   char *bitmap, int size)
+{
+       struct ext4_group_desc *gdp = (struct ext4_group_desc *)
+                       ext2fs_group_desc(fs, fs->group_desc, group);
+       __u32 provided, calculated;
+
+       if (!EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+                                       EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
+               return 1;
+       provided = gdp->bg_block_bitmap_csum_lo;
+       calculated = ext2fs_crc32c_le(fs->csum_seed, (unsigned char *)bitmap,
+                                     size);
+       if (fs->super->s_desc_size >= EXT4_BG_BLOCK_BITMAP_CSUM_HI_LOCATION)
+               provided |= (__u32)gdp->bg_block_bitmap_csum_hi << 16;
+       else
+               calculated &= 0xFFFF;
+
+       return provided == calculated;
+}
+
+errcode_t ext2fs_block_bitmap_csum_set(ext2_filsys fs, dgrp_t group,
+                                      char *bitmap, int size)
+{
+       __u32 crc;
+       struct ext4_group_desc *gdp = (struct ext4_group_desc *)
+                       ext2fs_group_desc(fs, fs->group_desc, group);
+
+       if (!EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+                                       EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
+               return 0;
+
+       crc = ext2fs_crc32c_le(fs->csum_seed, (unsigned char *)bitmap, size);
+       gdp->bg_block_bitmap_csum_lo = crc & 0xFFFF;
+       if (fs->super->s_desc_size >= EXT4_BG_BLOCK_BITMAP_CSUM_HI_LOCATION)
+               gdp->bg_block_bitmap_csum_hi = crc >> 16;
+
+       return 0;
+}
+
+static errcode_t ext2fs_inode_csum(ext2_filsys fs, ext2_ino_t inum,
+                              struct ext2_inode_large *inode,
+                              __u32 *crc, int has_hi)
+{
+       __u32 gen;
+       struct ext2_inode_large *desc = inode;
+       size_t size = fs->super->s_inode_size;
+       __u16 old_lo;
+       __u16 old_hi = 0;
+
+       old_lo = inode->i_checksum_lo;
+       inode->i_checksum_lo = 0;
+       if (has_hi) {
+               old_hi = inode->i_checksum_hi;
+               inode->i_checksum_hi = 0;
+       }
+
+       inum = ext2fs_cpu_to_le32(inum);
+       gen = inode->i_generation;
+       *crc = ext2fs_crc32c_le(fs->csum_seed, (unsigned char *)&inum,
+                               sizeof(inum));
+       *crc = ext2fs_crc32c_le(*crc, (unsigned char *)&gen, sizeof(gen));
+       *crc = ext2fs_crc32c_le(*crc, (unsigned char *)desc, size);
+
+       inode->i_checksum_lo = old_lo;
+       if (has_hi)
+               inode->i_checksum_hi = old_hi;
+       return 0;
+}
+
+int ext2fs_inode_csum_verify(ext2_filsys fs, ext2_ino_t inum,
+                            struct ext2_inode_large *inode)
+{
+       errcode_t retval;
+       __u32 provided, calculated;
+       unsigned int i, has_hi;
+       char *cp;
+
+       if (fs->super->s_creator_os != EXT2_OS_LINUX ||
+           !EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+                                       EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
+               return 1;
+
+       has_hi = (EXT2_INODE_SIZE(fs->super) > EXT2_GOOD_OLD_INODE_SIZE &&
+                 inode->i_extra_isize >= EXT4_INODE_CSUM_HI_EXTRA_END);
+
+       provided = ext2fs_le16_to_cpu(inode->i_checksum_lo);
+       retval = ext2fs_inode_csum(fs, inum, inode, &calculated, has_hi);
+       if (retval)
+               return 0;
+       if (has_hi) {
+               __u32 hi = ext2fs_le16_to_cpu(inode->i_checksum_hi);
+               provided |= hi << 16;
+       } else
+               calculated &= 0xFFFF;
+
+       if (provided == calculated)
+               return 1;
+
+       /*
+        * If the checksum didn't match, it's possible it was due to
+        * the inode being all zero's.  It's unlikely this is the
+        * case, but it can happen.  So check for it here.  (We only
+        * check the base inode since that's good enough, and it's not
+        * worth the bother to figure out how much of the extended
+        * inode, if any, is present.)
+        */
+       for (cp = (char *) inode, i = 0;
+            i < sizeof(struct ext2_inode);
+            cp++, i++)
+               if (*cp)
+                       return 0;
+       return 1;               /* Inode must have been all zero's */
+}
+
+errcode_t ext2fs_inode_csum_set(ext2_filsys fs, ext2_ino_t inum,
+                          struct ext2_inode_large *inode)
+{
+       errcode_t retval;
+       __u32 crc;
+       int has_hi;
+
+       if (fs->super->s_creator_os != EXT2_OS_LINUX ||
+           !EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+                                       EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
+               return 0;
+
+       has_hi = (EXT2_INODE_SIZE(fs->super) > EXT2_GOOD_OLD_INODE_SIZE &&
+                 inode->i_extra_isize >= EXT4_INODE_CSUM_HI_EXTRA_END);
+
+       retval = ext2fs_inode_csum(fs, inum, inode, &crc, has_hi);
+       if (retval)
+               return retval;
+       inode->i_checksum_lo = ext2fs_cpu_to_le16(crc & 0xFFFF);
+       if (has_hi)
+               inode->i_checksum_hi = ext2fs_cpu_to_le16(crc >> 16);
+       return 0;
+}
+
 __u16 ext2fs_group_desc_csum(ext2_filsys fs, dgrp_t group)
 {
        __u16 crc = 0;
@@ -40,45 +729,62 @@ __u16 ext2fs_group_desc_csum(ext2_filsys fs, dgrp_t group)
        if (size < EXT2_MIN_DESC_SIZE)
                size = EXT2_MIN_DESC_SIZE;
        if (size > sizeof(struct ext4_group_desc)) {
-               printf("%s: illegal s_desc_size(%zd)\n", __func__, size);
+               /* This should never happen, but cap it for safety's sake */
                size = sizeof(struct ext4_group_desc);
        }
 
        desc = ext2fs_group_desc(fs, fs->group_desc, group);
 
-       if (fs->super->s_feature_ro_compat & EXT4_FEATURE_RO_COMPAT_GDT_CSUM) {
-               size_t offset = offsetof(struct ext2_group_desc, bg_checksum);
-
 #ifdef WORDS_BIGENDIAN
-               struct ext4_group_desc swabdesc;
+       struct ext4_group_desc swabdesc;
 
-               /* Have to swab back to little-endian to do the checksum */
-               memcpy(&swabdesc, desc, size);
-               ext2fs_swap_group_desc2(fs,
-                                       (struct ext2_group_desc *) &swabdesc);
-               desc = (struct ext2_group_desc *) &swabdesc;
+       /* Have to swab back to little-endian to do the checksum */
+       memcpy(&swabdesc, desc, size);
+       ext2fs_swap_group_desc2(fs,
+                               (struct ext2_group_desc *) &swabdesc);
+       desc = (struct ext2_group_desc *) &swabdesc;
 
-               group = ext2fs_swab32(group);
+       group = ext2fs_swab32(group);
 #endif
-               crc = ext2fs_crc16(~0, fs->super->s_uuid,
-                                  sizeof(fs->super->s_uuid));
-               crc = ext2fs_crc16(crc, &group, sizeof(group));
-               crc = ext2fs_crc16(crc, desc, offset);
-               offset += sizeof(desc->bg_checksum); /* skip checksum */
-               /* for checksum of struct ext4_group_desc do the rest...*/
-               if (offset < size) {
-                       crc = ext2fs_crc16(crc, (char *)desc + offset,
-                                          size - offset);
-               }
+
+       if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+                       EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) {
+               /* new metadata csum code */
+               __u16 old_crc;
+               __u32 crc32;
+
+               old_crc = desc->bg_checksum;
+               desc->bg_checksum = 0;
+               crc32 = ext2fs_crc32c_le(fs->csum_seed, (unsigned char *)&group,
+                                        sizeof(group));
+               crc32 = ext2fs_crc32c_le(crc32, (unsigned char *)desc,
+                                        size);
+               desc->bg_checksum = old_crc;
+
+               crc = crc32 & 0xFFFF;
+               goto out;
        }
 
+       /* old crc16 code */
+       size_t offset = offsetof(struct ext2_group_desc, bg_checksum);
+       crc = ext2fs_crc16(~0, fs->super->s_uuid,
+                          sizeof(fs->super->s_uuid));
+       crc = ext2fs_crc16(crc, &group, sizeof(group));
+       crc = ext2fs_crc16(crc, desc, offset);
+       offset += sizeof(desc->bg_checksum); /* skip checksum */
+       /* for checksum of struct ext4_group_desc do the rest...*/
+       if (offset < size) {
+               crc = ext2fs_crc16(crc, (char *)desc + offset,
+                                  size - offset);
+       }
+
+out:
        return crc;
 }
 
 int ext2fs_group_desc_csum_verify(ext2_filsys fs, dgrp_t group)
 {
-       if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
-                                      EXT4_FEATURE_RO_COMPAT_GDT_CSUM) &&
+       if (ext2fs_has_group_desc_csum(fs) &&
            (ext2fs_bg_checksum(fs, group) !=
             ext2fs_group_desc_csum(fs, group)))
                return 0;
@@ -88,8 +794,7 @@ int ext2fs_group_desc_csum_verify(ext2_filsys fs, dgrp_t group)
 
 void ext2fs_group_desc_csum_set(ext2_filsys fs, dgrp_t group)
 {
-       if (!EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
-                                       EXT4_FEATURE_RO_COMPAT_GDT_CSUM))
+       if (!ext2fs_has_group_desc_csum(fs))
                return;
 
        /* ext2fs_bg_checksum_set() sets the actual checksum field but
@@ -123,8 +828,7 @@ errcode_t ext2fs_set_gdt_csum(ext2_filsys fs)
        if (!fs->inode_map)
                return EXT2_ET_NO_INODE_BITMAP;
 
-       if (!EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
-                                       EXT4_FEATURE_RO_COMPAT_GDT_CSUM))
+       if (!ext2fs_has_group_desc_csum(fs))
                return 0;
 
        for (i = 0; i < fs->group_desc_count; i++) {
index 4cb7ca1..3503615 100644 (file)
@@ -25,34 +25,6 @@ static EXT2_QSORT_TYPE dir_block_cmp2(const void *a, const void *b);
 static EXT2_QSORT_TYPE (*sortfunc32)(const void *a, const void *b);
 
 /*
- * Returns the number of directories in the filesystem as reported by
- * the group descriptors.  Of course, the group descriptors could be
- * wrong!
- */
-errcode_t ext2fs_get_num_dirs(ext2_filsys fs, ext2_ino_t *ret_num_dirs)
-{
-       dgrp_t  i;
-       ext2_ino_t      num_dirs, max_dirs;
-
-       EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
-
-       num_dirs = 0;
-       max_dirs = fs->super->s_inodes_per_group;
-       for (i = 0; i < fs->group_desc_count; i++) {
-               if (ext2fs_bg_used_dirs_count(fs, i) > max_dirs)
-                       num_dirs += max_dirs / 8;
-               else
-                       num_dirs += ext2fs_bg_used_dirs_count(fs, i);
-       }
-       if (num_dirs > fs->super->s_inodes_count)
-               num_dirs = fs->super->s_inodes_count;
-
-       *ret_num_dirs = num_dirs;
-
-       return 0;
-}
-
-/*
  * helper function for making a new directory block list (for
  * initialize and copy).
  */
index 5125d19..8be0ac2 100644 (file)
@@ -83,7 +83,7 @@ static int ext2fs_validate_entry(ext2_filsys fs, char *buf,
                offset += rec_len;
                if ((rec_len < 8) ||
                    ((rec_len % 4) != 0) ||
-                   ((((unsigned) dirent->name_len & 0xFF)+8) > rec_len))
+                   ((ext2fs_dirent_name_len(dirent)+8) > rec_len))
                        return 0;
        }
        return (offset == final_offset);
@@ -192,16 +192,22 @@ int ext2fs_process_dir_block(ext2_filsys fs,
        unsigned int    rec_len, size;
        int             entry;
        struct ext2_dir_entry *dirent;
+       int             csum_size = 0;
 
        if (blockcnt < 0)
                return 0;
 
        entry = blockcnt ? DIRENT_OTHER_FILE : DIRENT_DOT_FILE;
 
-       ctx->errcode = ext2fs_read_dir_block3(fs, *blocknr, ctx->buf, 0);
+       ctx->errcode = ext2fs_read_dir_block4(fs, *blocknr, ctx->buf, 0,
+                                             ctx->dir);
        if (ctx->errcode)
                return BLOCK_ABORT;
 
+       if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+                                       EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
+               csum_size = sizeof(struct ext2_dir_entry_tail);
+
        while (offset < fs->blocksize) {
                dirent = (struct ext2_dir_entry *) (ctx->buf + offset);
                if (ext2fs_get_rec_len(fs, dirent, &rec_len))
@@ -209,13 +215,20 @@ int ext2fs_process_dir_block(ext2_filsys fs,
                if (((offset + rec_len) > fs->blocksize) ||
                    (rec_len < 8) ||
                    ((rec_len % 4) != 0) ||
-                   ((((unsigned) dirent->name_len & 0xFF)+8) > rec_len)) {
+                   ((ext2fs_dirent_name_len(dirent)+8) > rec_len)) {
                        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) ?
@@ -240,7 +253,7 @@ next:
                        next_real_entry += rec_len;
 
                if (ctx->flags & DIRENT_FLAG_INCLUDE_REMOVED) {
-                       size = ((dirent->name_len & 0xFF) + 11) & ~3;
+                       size = (ext2fs_dirent_name_len(dirent) + 11) & ~3;
 
                        if (rec_len != size)  {
                                unsigned int final_offset;
@@ -259,8 +272,8 @@ next:
        }
 
        if (changed) {
-               ctx->errcode = ext2fs_write_dir_block3(fs, *blocknr, ctx->buf,
-                                                      0);
+               ctx->errcode = ext2fs_write_dir_block4(fs, *blocknr, ctx->buf,
+                                                      0, ctx->dir);
                if (ctx->errcode)
                        return BLOCK_ABORT;
        }
index cb3a104..54b2777 100644 (file)
 #include "ext2_fs.h"
 #include "ext2fs.h"
 
-errcode_t ext2fs_read_dir_block3(ext2_filsys fs, blk64_t block,
-                                void *buf, int flags EXT2FS_ATTR((unused)))
+errcode_t ext2fs_read_dir_block4(ext2_filsys fs, blk64_t block,
+                                void *buf, int flags EXT2FS_ATTR((unused)),
+                                ext2_ino_t ino)
 {
        errcode_t       retval;
-       char            *p, *end;
-       struct ext2_dir_entry *dirent;
-       unsigned int    name_len, rec_len;
-
+       int             corrupt = 0;
 
        retval = io_channel_read_blk64(fs->io, block, 1, buf);
        if (retval)
                return retval;
 
-       p = (char *) buf;
-       end = (char *) buf + fs->blocksize;
-       while (p < end-8) {
-               dirent = (struct ext2_dir_entry *) p;
-#ifdef WORDS_BIGENDIAN
-               dirent->inode = ext2fs_swab32(dirent->inode);
-               dirent->rec_len = ext2fs_swab16(dirent->rec_len);
-               dirent->name_len = ext2fs_swab16(dirent->name_len);
-#endif
-               name_len = dirent->name_len;
+       if (!(fs->flags & EXT2_FLAG_IGNORE_CSUM_ERRORS) &&
+           !ext2fs_dir_block_csum_verify(fs, ino,
+                                         (struct ext2_dir_entry *)buf))
+               corrupt = 1;
+
 #ifdef WORDS_BIGENDIAN
-               if (flags & EXT2_DIRBLOCK_V2_STRUCT)
-                       dirent->name_len = ext2fs_swab16(dirent->name_len);
+       retval = ext2fs_dirent_swab_in(fs, buf, flags);
 #endif
-               if ((retval = ext2fs_get_rec_len(fs, dirent, &rec_len)) != 0)
-                       return retval;
-               if ((rec_len < 8) || (rec_len % 4)) {
-                       rec_len = 8;
-                       retval = EXT2_ET_DIR_CORRUPTED;
-               } else if (((name_len & 0xFF) + 8) > rec_len)
-                       retval = EXT2_ET_DIR_CORRUPTED;
-               p += rec_len;
-       }
+       if (!retval && corrupt)
+               retval = EXT2_ET_DIR_CSUM_INVALID;
        return retval;
 }
 
+errcode_t ext2fs_read_dir_block3(ext2_filsys fs, blk64_t block,
+                                void *buf, int flags EXT2FS_ATTR((unused)))
+{
+       return ext2fs_read_dir_block4(fs, block, buf, flags, 0);
+}
+
 errcode_t ext2fs_read_dir_block2(ext2_filsys fs, blk_t block,
                                 void *buf, int flags EXT2FS_ATTR((unused)))
 {
@@ -72,45 +63,40 @@ errcode_t ext2fs_read_dir_block(ext2_filsys fs, blk_t block,
 }
 
 
-errcode_t ext2fs_write_dir_block3(ext2_filsys fs, blk64_t block,
-                                 void *inbuf, int flags EXT2FS_ATTR((unused)))
+errcode_t ext2fs_write_dir_block4(ext2_filsys fs, blk64_t block,
+                                 void *inbuf, int flags EXT2FS_ATTR((unused)),
+                                 ext2_ino_t ino)
 {
-#ifdef WORDS_BIGENDIAN
        errcode_t       retval;
-       char            *p, *end;
-       char            *buf = 0;
-       unsigned int    rec_len;
-       struct ext2_dir_entry *dirent;
+       char            *buf = inbuf;
 
+#ifdef WORDS_BIGENDIAN
        retval = ext2fs_get_mem(fs->blocksize, &buf);
        if (retval)
                return retval;
        memcpy(buf, inbuf, fs->blocksize);
-       p = buf;
-       end = buf + fs->blocksize;
-       while (p < end) {
-               dirent = (struct ext2_dir_entry *) p;
-               if ((retval = ext2fs_get_rec_len(fs, dirent, &rec_len)) != 0)
-                       return retval;
-               if ((rec_len < 8) ||
-                   (rec_len % 4)) {
-                       ext2fs_free_mem(&buf);
-                       return (EXT2_ET_DIR_CORRUPTED);
-               }
-               p += rec_len;
-               dirent->inode = ext2fs_swab32(dirent->inode);
-               dirent->rec_len = ext2fs_swab16(dirent->rec_len);
-               dirent->name_len = ext2fs_swab16(dirent->name_len);
-
-               if (flags & EXT2_DIRBLOCK_V2_STRUCT)
-                       dirent->name_len = ext2fs_swab16(dirent->name_len);
-       }
+       retval = ext2fs_dirent_swab_out(fs, buf, flags);
+       if (retval)
+               return retval;
+#endif
+       retval = ext2fs_dir_block_csum_set(fs, ino,
+                                          (struct ext2_dir_entry *)buf);
+       if (retval)
+               goto out;
+
        retval = io_channel_write_blk64(fs->io, block, 1, buf);
+
+out:
+#ifdef WORDS_BIGENDIAN
        ext2fs_free_mem(&buf);
-       return retval;
-#else
-       return io_channel_write_blk64(fs->io, block, 1, (char *) inbuf);
 #endif
+       return retval;
+}
+
+errcode_t ext2fs_write_dir_block3(ext2_filsys fs, blk64_t block,
+                                 void *inbuf, int flags EXT2FS_ATTR((unused)))
+{
+       return ext2fs_write_dir_block4(fs, block, inbuf, flags, 0);
 }
 
 errcode_t ext2fs_write_dir_block2(ext2_filsys fs, blk_t block,
index 41c4088..22558d6 100644 (file)
@@ -24,6 +24,7 @@ struct expand_dir_struct {
        int             newblocks;
        blk64_t         goal;
        errcode_t       err;
+       ext2_ino_t      dir;
 };
 
 static int expand_dir_proc(ext2_filsys fs,
@@ -62,7 +63,8 @@ static int expand_dir_proc(ext2_filsys        fs,
                        return BLOCK_ABORT;
                }
                es->done = 1;
-               retval = ext2fs_write_dir_block(fs, new_blk, block);
+               retval = ext2fs_write_dir_block4(fs, new_blk, block, 0,
+                                                es->dir);
        } else {
                retval = ext2fs_get_mem(fs->blocksize, &block);
                if (retval) {
@@ -110,6 +112,7 @@ errcode_t ext2fs_expand_dir(ext2_filsys fs, ext2_ino_t dir)
        es.err = 0;
        es.goal = 0;
        es.newblocks = 0;
+       es.dir = dir;
 
        retval = ext2fs_block_iterate3(fs, dir, BLOCK_FLAG_APPEND,
                                       0, expand_dir_proc, &es);
index e719864..9cc1bd1 100644 (file)
@@ -476,4 +476,10 @@ ec EXT2_ET_MMP_CSUM_INVALID,
 ec     EXT2_ET_FILE_EXISTS,
        "Ext2 file already exists"
 
+ec     EXT2_ET_BLOCK_BITMAP_CSUM_INVALID,
+       "Block bitmap checksum does not match bitmap"
+
+ec     EXT2_ET_INLINE_DATA_CANT_ITERATE,
+       "Cannot block iterate on an inode containing inline data"
+
        end
index ed548d1..bbb0aaa 100644 (file)
@@ -20,7 +20,9 @@ struct ext2_ext_attr_header {
        __u32   h_refcount;     /* reference count */
        __u32   h_blocks;       /* number of disk blocks used */
        __u32   h_hash;         /* hash value of all attributes */
-       __u32   h_reserved[4];  /* zero right now */
+       __u32   h_checksum;     /* crc32c(uuid+id+xattrs) */
+                               /* id = inum if refcount = 1, else blknum */
+       __u32   h_reserved[3];  /* zero right now */
 };
 
 struct ext2_ext_attr_entry {
index fb3f7cc..6a28d55 100644 (file)
@@ -192,6 +192,13 @@ struct ext4_group_desc
        __u32   bg_reserved;
 };
 
+#define EXT4_BG_INODE_BITMAP_CSUM_HI_END       \
+       (offsetof(struct ext4_group_desc, bg_inode_bitmap_csum_hi) + \
+        sizeof(__u16))
+#define EXT4_BG_BLOCK_BITMAP_CSUM_HI_LOCATION  \
+       (offsetof(struct ext4_group_desc, bg_block_bitmap_csum_hi) + \
+        sizeof(__u16))
+
 #define EXT2_BG_INODE_UNINIT   0x0001 /* Inode table/bitmap not initialized */
 #define EXT2_BG_BLOCK_UNINIT   0x0002 /* Block bitmap not initialized */
 #define EXT2_BG_INODE_ZEROED   0x0004 /* On-disk itable initialized to zero */
@@ -235,6 +242,13 @@ struct ext2_dx_countlimit {
        __u16 count;
 };
 
+/*
+ * This goes at the end of each htree block.
+ */
+struct ext2_dx_tail {
+       __u32 dt_reserved;
+       __u32 dt_checksum;      /* crc32c(uuid+inum+dxblock) */
+};
 
 /*
  * Macro-instructions used to manage group descriptors
@@ -305,6 +319,7 @@ struct ext2_dx_countlimit {
 #define EXT4_SNAPFILE_FL               0x01000000  /* Inode is a snapshot */
 #define EXT4_SNAPFILE_DELETED_FL       0x04000000  /* Snapshot is being deleted */
 #define EXT4_SNAPFILE_SHRUNK_FL                0x08000000  /* Snapshot shrink has completed */
+#define EXT4_INLINE_DATA_FL            0x10000000 /* Inode has inline data */
 #define EXT2_RESERVED_FL               0x80000000 /* reserved for ext2 lib */
 
 #define EXT2_FL_USER_VISIBLE           0x004BDFFF /* User visible flags */
@@ -454,8 +469,14 @@ struct ext2_inode_large {
        __u32   i_version_hi;   /* high 32 bits for 64-bit version */
 };
 
+#define EXT4_INODE_CSUM_HI_EXTRA_END   \
+       (offsetof(struct ext2_inode_large, i_checksum_hi) + sizeof(__u16) - \
+        EXT2_GOOD_OLD_INODE_SIZE)
+
 #define i_dir_acl      i_size_high
 
+#define i_checksum_lo  osd2.linux2.l_i_checksum_lo
+
 #if defined(__KERNEL__) || defined(__linux__)
 #define i_reserved1    osd1.linux1.l_i_reserved1
 #define i_frag         osd2.linux2.l_i_frag
@@ -535,6 +556,9 @@ struct ext2_inode_large {
 #define ext4_offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
 #endif
 
+/* Metadata checksum algorithms */
+#define EXT2_CRC32C_CHKSUM             1
+
 /*
  * Structure of the super block
  */
@@ -620,7 +644,7 @@ struct ext2_super_block {
        __u64   s_mmp_block;            /* Block for multi-mount protection */
        __u32   s_raid_stripe_width;    /* blocks on all data disks (N*stride)*/
        __u8    s_log_groups_per_flex;  /* FLEX_BG group size */
-       __u8    s_reserved_char_pad;
+       __u8    s_checksum_type;        /* metadata checksum algorithm */
        __u16   s_reserved_pad;         /* Padding to next 32bits */
        __u64   s_kbytes_written;       /* nr of lifetime kilobytes written */
        __u32   s_snapshot_inum;        /* Inode number of active snapshot */
@@ -708,6 +732,11 @@ struct ext2_super_block {
 #define EXT4_FEATURE_RO_COMPAT_HAS_SNAPSHOT    0x0080
 #define EXT4_FEATURE_RO_COMPAT_QUOTA           0x0100
 #define EXT4_FEATURE_RO_COMPAT_BIGALLOC                0x0200
+/*
+ * METADATA_CSUM implies GDT_CSUM.  When METADATA_CSUM is set, group
+ * descriptor checksums use the same algorithm as all other data
+ * structures' checksums.
+ */
 #define EXT4_FEATURE_RO_COMPAT_METADATA_CSUM   0x0400
 #define EXT4_FEATURE_RO_COMPAT_REPLICA         0x0800
 
@@ -724,7 +753,7 @@ struct ext2_super_block {
 #define EXT4_FEATURE_INCOMPAT_DIRDATA          0x1000
 /* 0x2000 was EXT4_FEATURE_INCOMPAT_BG_USE_META_CSUM but this was never used */
 #define EXT4_FEATURE_INCOMPAT_LARGEDIR         0x4000 /* >2GB or 3-lvl htree */
-#define EXT4_FEATURE_INCOMPAT_INLINEDATA       0x8000 /* data in inode */
+#define EXT4_FEATURE_INCOMPAT_INLINE_DATA      0x8000 /* data in inode */
 
 #define EXT2_FEATURE_COMPAT_SUPP       0
 #define EXT2_FEATURE_INCOMPAT_SUPP    (EXT2_FEATURE_INCOMPAT_FILETYPE| \
@@ -774,6 +803,14 @@ struct ext2_dir_entry {
  * stored in intel byte order, and the name_len field could never be
  * bigger than 255 chars, it's safe to reclaim the extra byte for the
  * file_type field.
+ *
+ * This structure is deprecated due to endianity issues. Please use struct
+ * ext2_dir_entry and accessor functions
+ *   ext2fs_dirent_name_len
+ *   ext2fs_dirent_set_name_len
+ *   ext2fs_dirent_file_type
+ *   ext2fs_dirent_set_file_type
+ * to get and set name_len and file_type fields.
  */
 struct ext2_dir_entry_2 {
        __u32   inode;                  /* Inode number */
@@ -784,6 +821,17 @@ struct ext2_dir_entry_2 {
 };
 
 /*
+ * This is a bogus directory entry at the end of each leaf block that
+ * records checksums.
+ */
+struct ext2_dir_entry_tail {
+       __u32   det_reserved_zero1;     /* Pretend to be unused */
+       __u16   det_rec_len;            /* 12 */
+       __u16   det_reserved_name_len;  /* 0xDE00, fake namelen/filetype */
+       __u32   det_checksum;           /* crc32c(uuid+inode+dirent) */
+};
+
+/*
  * Ext2 directory file types.  Only the low 3 bits are used.  The
  * other bits are reserved for now.
  */
@@ -799,6 +847,14 @@ struct ext2_dir_entry_2 {
 #define EXT2_FT_MAX            8
 
 /*
+ * Annoyingly, e2fsprogs always swab16s ext2_dir_entry.name_len, so we
+ * have to build ext2_dir_entry_tail with that assumption too.  This
+ * constant helps to build the dir_entry_tail to look like it has an
+ * "invalid" file type.
+ */
+#define EXT2_DIR_NAME_LEN_CSUM 0xDE00
+
+/*
  * EXT2_DIR_PAD defines the directory entries boundaries
  *
  * NOTE: It must be a multiple of 4
@@ -839,7 +895,8 @@ struct mmp_struct {
        char    mmp_bdevname[32];       /* Bdev which last updated MMP block */
        __u16   mmp_check_interval;     /* Changed mmp_check_interval */
        __u16   mmp_pad1;
-       __u32   mmp_pad2[227];
+       __u32   mmp_pad2[226];
+       __u32   mmp_checksum;           /* crc32c(uuid+mmp_block) */
 };
 
 /*
index b27fb74..654247a 100644 (file)
@@ -191,6 +191,7 @@ typedef struct ext2_file *ext2_file_t;
 #define EXT2_FLAG_PRINT_PROGRESS       0x40000
 #define EXT2_FLAG_DIRECT_IO            0x80000
 #define EXT2_FLAG_SKIP_MMP             0x100000
+#define EXT2_FLAG_IGNORE_CSUM_ERRORS   0x200000
 
 /*
  * Special flag in the ext2 inode i_flag field that means that this is
@@ -273,6 +274,12 @@ struct struct_ext2_filsys {
         * Time at which e2fsck last updated the MMP block.
         */
        long mmp_last_written;
+
+       /* progress operation functions */
+       struct ext2fs_progress_ops *progress_ops;
+
+       /* Precomputed FS UUID checksum for seeding other checksums */
+       __u32 csum_seed;
 };
 
 #if EXT2_FLAT_INCLUDES
@@ -430,11 +437,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
@@ -560,26 +569,33 @@ typedef struct ext2_icount *ext2_icount_t;
    environment at configure time. */
  #warning "Compression support is experimental"
 #endif
-#define EXT2_LIB_FEATURE_INCOMPAT_SUPP (EXT2_FEATURE_INCOMPAT_FILETYPE|\
-                                        EXT2_FEATURE_INCOMPAT_COMPRESSION|\
-                                        EXT3_FEATURE_INCOMPAT_JOURNAL_DEV|\
-                                        EXT2_FEATURE_INCOMPAT_META_BG|\
-                                        EXT3_FEATURE_INCOMPAT_RECOVER|\
-                                        EXT3_FEATURE_INCOMPAT_EXTENTS|\
-                                        EXT4_FEATURE_INCOMPAT_FLEX_BG|\
-                                        EXT4_FEATURE_INCOMPAT_MMP|\
-                                        EXT4_FEATURE_INCOMPAT_64BIT)
+#define EXT2_LIB_INCOMPAT_COMPRESSION  EXT2_FEATURE_INCOMPAT_COMPRESSION
+#else
+#define EXT2_LIB_INCOMPAT_COMPRESSION  (0)
+#endif
+
+#ifdef CONFIG_MMP
+#define EXT4_LIB_INCOMPAT_MMP          EXT4_FEATURE_INCOMPAT_MMP
+#else
+#define EXT4_LIB_INCOMPAT_MMP          (0)
+#endif
+
+#ifdef CONFIG_QUOTA
+#define EXT4_LIB_RO_COMPAT_QUOTA       EXT4_FEATURE_RO_COMPAT_QUOTA
 #else
+#define EXT4_LIB_RO_COMPAT_QUOTA       (0)
+#endif
+
 #define EXT2_LIB_FEATURE_INCOMPAT_SUPP (EXT2_FEATURE_INCOMPAT_FILETYPE|\
+                                        EXT2_LIB_INCOMPAT_COMPRESSION|\
                                         EXT3_FEATURE_INCOMPAT_JOURNAL_DEV|\
                                         EXT2_FEATURE_INCOMPAT_META_BG|\
                                         EXT3_FEATURE_INCOMPAT_RECOVER|\
                                         EXT3_FEATURE_INCOMPAT_EXTENTS|\
                                         EXT4_FEATURE_INCOMPAT_FLEX_BG|\
-                                        EXT4_FEATURE_INCOMPAT_MMP|\
+                                        EXT4_LIB_INCOMPAT_MMP|\
                                         EXT4_FEATURE_INCOMPAT_64BIT)
-#endif
-#ifdef CONFIG_QUOTA
+
 #define EXT2_LIB_FEATURE_RO_COMPAT_SUPP        (EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER|\
                                         EXT4_FEATURE_RO_COMPAT_HUGE_FILE|\
                                         EXT2_FEATURE_RO_COMPAT_LARGE_FILE|\
@@ -587,22 +603,14 @@ typedef struct ext2_icount *ext2_icount_t;
                                         EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE|\
                                         EXT4_FEATURE_RO_COMPAT_GDT_CSUM|\
                                         EXT4_FEATURE_RO_COMPAT_BIGALLOC|\
-                                        EXT4_FEATURE_RO_COMPAT_QUOTA)
-#else
-#define EXT2_LIB_FEATURE_RO_COMPAT_SUPP        (EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER|\
-                                        EXT4_FEATURE_RO_COMPAT_HUGE_FILE|\
-                                        EXT2_FEATURE_RO_COMPAT_LARGE_FILE|\
-                                        EXT4_FEATURE_RO_COMPAT_DIR_NLINK|\
-                                        EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE|\
-                                        EXT4_FEATURE_RO_COMPAT_GDT_CSUM|\
-                                        EXT4_FEATURE_RO_COMPAT_BIGALLOC)
-#endif
+                                        EXT4_LIB_RO_COMPAT_QUOTA|\
+                                        EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)
 
 /*
  * These features are only allowed if EXT2_FLAG_SOFTSUPP_FEATURES is passed
  * to ext2fs_openfs()
  */
-#define EXT2_LIB_SOFTSUPP_INCOMPAT     (0)
+#define EXT2_LIB_SOFTSUPP_INCOMPAT     (EXT4_FEATURE_INCOMPAT_INLINE_DATA)
 #define EXT2_LIB_SOFTSUPP_RO_COMPAT    (EXT4_FEATURE_RO_COMPAT_REPLICA)
 
 
@@ -631,6 +639,12 @@ typedef struct stat ext2fs_struct_stat;
 /*
  * function prototypes
  */
+static inline int ext2fs_has_group_desc_csum(ext2_filsys fs)
+{
+       return EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+                       EXT4_FEATURE_RO_COMPAT_GDT_CSUM |
+                       EXT4_FEATURE_RO_COMPAT_METADATA_CSUM);
+}
 
 /* alloc.c */
 extern errcode_t ext2fs_new_inode(ext2_filsys fs, ext2_ino_t dir, int mode,
@@ -798,6 +812,8 @@ extern errcode_t ext2fs_get_block_bitmap_range2(ext2fs_block_bitmap bmap,
                                         void *out);
 
 /* blknum.c */
+extern __u32 ext2fs_inode_bitmap_checksum(ext2_filsys fs, dgrp_t group);
+extern __u32 ext2fs_block_bitmap_checksum(ext2_filsys fs, dgrp_t group);
 extern dgrp_t ext2fs_group_of_blk2(ext2_filsys fs, blk64_t);
 extern blk64_t ext2fs_group_first_block2(ext2_filsys fs, dgrp_t group);
 extern blk64_t ext2fs_group_last_block2(ext2_filsys fs, dgrp_t group);
@@ -825,9 +841,11 @@ extern void ext2fs_free_blocks_count_add(struct ext2_super_block *super,
 extern struct ext2_group_desc *ext2fs_group_desc(ext2_filsys fs,
                                          struct opaque_ext2_group_desc *gdp,
                                          dgrp_t group);
+extern blk64_t ext2fs_block_bitmap_csum(ext2_filsys fs, dgrp_t group);
 extern blk64_t ext2fs_block_bitmap_loc(ext2_filsys fs, dgrp_t group);
 extern void ext2fs_block_bitmap_loc_set(ext2_filsys fs, dgrp_t group,
                                        blk64_t blk);
+extern __u32 ext2fs_inode_bitmap_csum(ext2_filsys fs, dgrp_t group);
 extern blk64_t ext2fs_inode_bitmap_loc(ext2_filsys fs, dgrp_t group);
 extern void ext2fs_inode_bitmap_loc_set(ext2_filsys fs, dgrp_t group,
                                        blk64_t blk);
@@ -933,18 +951,65 @@ extern int ext2fs_super_and_bgd_loc(ext2_filsys fs,
 extern void ext2fs_update_dynamic_rev(ext2_filsys fs);
 
 /* crc32c.c */
-extern __u32 ext2fs_crc32c_be(__u32 crc, unsigned char const *p, size_t len);
+extern __u32 ext2fs_crc32_be(__u32 crc, unsigned char const *p, size_t len);
 extern __u32 ext2fs_crc32c_le(__u32 crc, unsigned char const *p, size_t len);
 
 /* csum.c */
+extern errcode_t ext2fs_mmp_csum_set(ext2_filsys fs, struct mmp_struct *mmp);
+extern int ext2fs_mmp_csum_verify(ext2_filsys, struct mmp_struct *mmp);
+extern int ext2fs_verify_csum_type(ext2_filsys fs, struct ext2_super_block *sb);
+extern errcode_t ext2fs_superblock_csum_set(ext2_filsys fs,
+                                           struct ext2_super_block *sb);
+extern int ext2fs_superblock_csum_verify(ext2_filsys fs,
+                                        struct ext2_super_block *sb);
+extern errcode_t ext2fs_ext_attr_block_csum_set(ext2_filsys fs,
+                                       ext2_ino_t inum, blk64_t block,
+                                       struct ext2_ext_attr_header *hdr);
+extern int ext2fs_ext_attr_block_csum_verify(ext2_filsys fs, ext2_ino_t inum,
+                                            blk64_t block,
+                                            struct ext2_ext_attr_header *hdr);
+#define EXT2_DIRENT_TAIL(block, blocksize) \
+       ((struct ext2_dir_entry_tail *)(((char *)(block)) + \
+       (blocksize) - sizeof(struct ext2_dir_entry_tail)))
+
+extern void ext2fs_initialize_dirent_tail(ext2_filsys fs,
+                                         struct ext2_dir_entry_tail *t);
+extern int ext2fs_dirent_has_tail(ext2_filsys fs,
+                                 struct ext2_dir_entry *dirent);
+extern int ext2fs_dirent_csum_verify(ext2_filsys fs, ext2_ino_t inum,
+                                    struct ext2_dir_entry *dirent);
+extern int ext2fs_dir_block_csum_verify(ext2_filsys fs, ext2_ino_t inum,
+                                       struct ext2_dir_entry *dirent);
+extern errcode_t ext2fs_dir_block_csum_set(ext2_filsys fs, ext2_ino_t inum,
+                                          struct ext2_dir_entry *dirent);
+extern errcode_t ext2fs_get_dx_countlimit(ext2_filsys fs,
+                                         struct ext2_dir_entry *dirent,
+                                         struct ext2_dx_countlimit **cc,
+                                         int *offset);
+extern errcode_t ext2fs_extent_block_csum_set(ext2_filsys fs,
+                                             ext2_ino_t inum,
+                                             struct ext3_extent_header *eh);
+extern int ext2fs_extent_block_csum_verify(ext2_filsys fs,
+                                          ext2_ino_t inum,
+                                          struct ext3_extent_header *eh);
+extern errcode_t ext2fs_block_bitmap_csum_set(ext2_filsys fs, dgrp_t group,
+                                             char *bitmap, int size);
+extern int ext2fs_block_bitmap_csum_verify(ext2_filsys fs, dgrp_t group,
+                                          char *bitmap, int size);
+extern errcode_t ext2fs_inode_bitmap_csum_set(ext2_filsys fs, dgrp_t group,
+                                             char *bitmap, int size);
+extern int ext2fs_inode_bitmap_csum_verify(ext2_filsys fs, dgrp_t group,
+                                          char *bitmap, int size);
+extern errcode_t ext2fs_inode_csum_set(ext2_filsys fs, ext2_ino_t inum,
+                                      struct ext2_inode_large *inode);
+extern int ext2fs_inode_csum_verify(ext2_filsys fs, ext2_ino_t inum,
+                                   struct ext2_inode_large *inode);
 extern void ext2fs_group_desc_csum_set(ext2_filsys fs, dgrp_t group);
 extern int ext2fs_group_desc_csum_verify(ext2_filsys fs, dgrp_t group);
 extern errcode_t ext2fs_set_gdt_csum(ext2_filsys fs);
 extern __u16 ext2fs_group_desc_csum(ext2_filsys fs, dgrp_t group);
 
 /* dblist.c */
-
-extern errcode_t ext2fs_get_num_dirs(ext2_filsys fs, ext2_ino_t *ret_num_dirs);
 extern errcode_t ext2fs_init_dblist(ext2_filsys fs, ext2_dblist *ret_dblist);
 extern errcode_t ext2fs_add_dir_block(ext2_dblist dblist, ext2_ino_t ino,
                                      blk_t blk, int blockcnt);
@@ -999,12 +1064,16 @@ extern errcode_t ext2fs_read_dir_block2(ext2_filsys fs, blk_t block,
                                        void *buf, int flags);
 extern errcode_t ext2fs_read_dir_block3(ext2_filsys fs, blk64_t block,
                                        void *buf, int flags);
+extern errcode_t ext2fs_read_dir_block4(ext2_filsys fs, blk64_t block,
+                                       void *buf, int flags, ext2_ino_t ino);
 extern errcode_t ext2fs_write_dir_block(ext2_filsys fs, blk_t block,
                                        void *buf);
 extern errcode_t ext2fs_write_dir_block2(ext2_filsys fs, blk_t block,
                                         void *buf, int flags);
 extern errcode_t ext2fs_write_dir_block3(ext2_filsys fs, blk64_t block,
                                         void *buf, int flags);
+extern errcode_t ext2fs_write_dir_block4(ext2_filsys fs, blk64_t block,
+                                        void *buf, int flags, ext2_ino_t ino);
 
 /* dirhash.c */
 extern errcode_t ext2fs_dirhash(int version, const char *name, int len,
@@ -1055,16 +1124,24 @@ extern __u32 ext2fs_ext_attr_hash_entry(struct ext2_ext_attr_entry *entry,
 extern errcode_t ext2fs_read_ext_attr(ext2_filsys fs, blk_t block, void *buf);
 extern errcode_t ext2fs_read_ext_attr2(ext2_filsys fs, blk64_t block,
                                       void *buf);
+extern errcode_t ext2fs_read_ext_attr3(ext2_filsys fs, blk64_t block,
+                                      void *buf, ext2_ino_t inum);
 extern errcode_t ext2fs_write_ext_attr(ext2_filsys fs, blk_t block,
                                       void *buf);
 extern errcode_t ext2fs_write_ext_attr2(ext2_filsys fs, blk64_t block,
                                       void *buf);
+extern errcode_t ext2fs_write_ext_attr3(ext2_filsys fs, blk64_t block,
+                                      void *buf, ext2_ino_t inum);
 extern errcode_t ext2fs_adjust_ea_refcount(ext2_filsys fs, blk_t blk,
                                           char *block_buf,
                                           int adjust, __u32 *newcount);
 extern errcode_t ext2fs_adjust_ea_refcount2(ext2_filsys fs, blk64_t blk,
                                           char *block_buf,
                                           int adjust, __u32 *newcount);
+extern errcode_t ext2fs_adjust_ea_refcount3(ext2_filsys fs, blk64_t blk,
+                                          char *block_buf,
+                                          int adjust, __u32 *newcount,
+                                          ext2_ino_t inum);
 
 /* extent.c */
 extern errcode_t ext2fs_extent_header_verify(void *ptr, int size);
@@ -1170,10 +1247,6 @@ extern errcode_t ext2fs_find_first_zero_generic_bitmap(ext2fs_generic_bitmap bit
                                                       __u32 *out);
 
 /* gen_bitmap64.c */
-
-/* Generate and print bitmap usage statistics */
-#define BMAP_STATS
-
 void ext2fs_free_generic_bmap(ext2fs_generic_bitmap bmap);
 errcode_t ext2fs_alloc_generic_bmap(ext2_filsys fs, errcode_t magic,
                                    int type, __u64 start, __u64 end,
@@ -1202,6 +1275,9 @@ errcode_t ext2fs_set_generic_bmap_range(ext2fs_generic_bitmap bmap,
 errcode_t ext2fs_convert_subcluster_bitmap(ext2_filsys fs,
                                           ext2fs_block_bitmap *bitmap);
 
+/* get_num_dirs.c */
+extern errcode_t ext2fs_get_num_dirs(ext2_filsys fs, ext2_ino_t *ret_num_dirs);
+
 /* getsize.c */
 extern errcode_t ext2fs_get_device_size(const char *file, int blocksize,
                                        blk_t *retblocks);
@@ -1264,6 +1340,7 @@ extern errcode_t ext2fs_get_memalign(unsigned long size,
                                     unsigned long align, void *ptr);
 
 /* inode.c */
+extern void ext2fs_free_inode_cache(struct ext2_inode_cache *icache);
 extern errcode_t ext2fs_flush_icache(ext2_filsys fs);
 extern errcode_t ext2fs_get_next_inode_full(ext2_inode_scan scan,
                                            ext2_ino_t *ino,
@@ -1395,6 +1472,7 @@ errcode_t ext2fs_mmp_clear(ext2_filsys fs);
 errcode_t ext2fs_mmp_init(ext2_filsys fs);
 errcode_t ext2fs_mmp_start(ext2_filsys fs);
 errcode_t ext2fs_mmp_update(ext2_filsys fs);
+errcode_t ext2fs_mmp_update2(ext2_filsys fs, int immediately);
 errcode_t ext2fs_mmp_stop(ext2_filsys fs);
 unsigned ext2fs_mmp_new_seq(void);
 
@@ -1419,6 +1497,8 @@ extern errcode_t ext2fs_read_bb_FILE(ext2_filsys fs, FILE *f,
 extern errcode_t ext2fs_create_resize_inode(ext2_filsys fs);
 
 /* swapfs.c */
+extern errcode_t ext2fs_dirent_swab_in(ext2_filsys fs, char *buf, int flags);
+extern errcode_t ext2fs_dirent_swab_out(ext2_filsys fs, char *buf, int flags);
 extern void ext2fs_swap_ext_attr(char *to, char *from, int bufsize,
                                 int has_header);
 extern void ext2fs_swap_ext_attr_header(struct ext2_ext_attr_header *to_header,
@@ -1458,6 +1538,7 @@ extern errcode_t ext2fs_write_bb_FILE(ext2_badblocks_list bb_list,
 
 /* inline functions */
 #ifdef NO_INLINE_FUNCS
+extern void ext2fs_init_csum_seed(ext2_filsys fs);
 extern errcode_t ext2fs_get_mem(unsigned long size, void *ptr);
 extern errcode_t ext2fs_get_memzero(unsigned long size, void *ptr);
 extern errcode_t ext2fs_get_array(unsigned long count,
@@ -1508,6 +1589,16 @@ extern __u64 ext2fs_div64_ceil(__u64 a, __u64 b);
 #endif /* __STDC_VERSION__ >= 199901L */
 #endif
 
+_INLINE_ void ext2fs_init_csum_seed(ext2_filsys fs)
+{
+       if (!EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+                                       EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
+               return;
+
+       fs->csum_seed = ext2fs_crc32c_le(~0, fs->super->s_uuid,
+                                        sizeof(fs->super->s_uuid));
+}
+
 #ifndef EXT2_CUSTOM_MEMORY_ROUTINES
 #include <string.h>
 /*
@@ -1724,6 +1815,26 @@ _INLINE_ __u64 ext2fs_div64_ceil(__u64 a, __u64 b)
        return ((a - 1) / b) + 1;
 }
 
+_INLINE_ int ext2fs_dirent_name_len(const struct ext2_dir_entry *entry)
+{
+       return entry->name_len & 0xff;
+}
+
+_INLINE_ void ext2fs_dirent_set_name_len(struct ext2_dir_entry *entry, int len)
+{
+       entry->name_len = (entry->name_len & 0xff00) | (len & 0xff);
+}
+
+_INLINE_ int ext2fs_dirent_file_type(const struct ext2_dir_entry *entry)
+{
+       return entry->name_len >> 8;
+}
+
+_INLINE_ void ext2fs_dirent_set_file_type(struct ext2_dir_entry *entry, int type)
+{
+       entry->name_len = (entry->name_len & 0xff) | (type << 8);
+}
+
 #undef _INLINE_
 #endif
 
index 46a6767..80d2d0a 100644 (file)
@@ -75,7 +75,7 @@ struct ext2_inode_cache {
 
 struct ext2_inode_cache_ent {
        ext2_ino_t              ino;
-       struct ext2_inode       inode;
+       struct ext2_inode       *inode;
 };
 
 /* Function prototypes */
@@ -95,6 +95,23 @@ struct ext2fs_numeric_progress_struct {
        int             skip_progress;
 };
 
+/*
+ * progress callback functions
+ */
+struct ext2fs_progress_ops {
+       void (*init)(ext2_filsys fs,
+                    struct ext2fs_numeric_progress_struct * progress,
+                    const char *label, __u64 max);
+       void (*update)(ext2_filsys fs,
+                      struct ext2fs_numeric_progress_struct * progress,
+                      __u64 val);
+       void (*close)(ext2_filsys fs,
+                     struct ext2fs_numeric_progress_struct * progress,
+                     const char *message);
+};
+
+extern struct ext2fs_progress_ops ext2fs_numeric_progress_ops;
+
 extern void ext2fs_numeric_progress_init(ext2_filsys fs,
                                         struct ext2fs_numeric_progress_struct * progress,
                                         const char *label, __u64 max);
index 88fabc9..4163436 100644 (file)
  */
 
 /*
+ * This is extent tail on-disk structure.
+ * All other extent structures are 12 bytes long.  It turns out that
+ * block_size % 12 >= 4 for at least all powers of 2 greater than 512, which
+ * covers all valid ext4 block sizes.  Therefore, this tail structure can be
+ * crammed into the end of the block without having to rebalance the tree.
+ */
+struct ext3_extent_tail {
+       __u32   et_checksum;    /* crc32c(uuid+inum+extent_block) */
+};
+
+/*
  * this is extent on-disk structure
  * it's used at the bottom of the tree
  */
index 1889824..9649a14 100644 (file)
@@ -61,17 +61,29 @@ __u32 ext2fs_ext_attr_hash_entry(struct ext2_ext_attr_entry *entry, void *data)
 #undef NAME_HASH_SHIFT
 #undef VALUE_HASH_SHIFT
 
-errcode_t ext2fs_read_ext_attr2(ext2_filsys fs, blk64_t block, void *buf)
+errcode_t ext2fs_read_ext_attr3(ext2_filsys fs, blk64_t block, void *buf,
+                               ext2_ino_t inum)
 {
        errcode_t       retval;
 
        retval = io_channel_read_blk64(fs->io, block, 1, buf);
        if (retval)
                return retval;
+
+       if (!(fs->flags & EXT2_FLAG_IGNORE_CSUM_ERRORS) &&
+           !ext2fs_ext_attr_block_csum_verify(fs, inum, block, buf))
+               retval = EXT2_ET_EXT_ATTR_CSUM_INVALID;
+
 #ifdef WORDS_BIGENDIAN
        ext2fs_swap_ext_attr(buf, buf, fs->blocksize, 1);
 #endif
-       return 0;
+
+       return retval;
+}
+
+errcode_t ext2fs_read_ext_attr2(ext2_filsys fs, blk64_t block, void *buf)
+{
+       return ext2fs_read_ext_attr3(fs, block, buf, 0);
 }
 
 errcode_t ext2fs_read_ext_attr(ext2_filsys fs, blk_t block, void *buf)
@@ -79,30 +91,40 @@ errcode_t ext2fs_read_ext_attr(ext2_filsys fs, blk_t block, void *buf)
        return ext2fs_read_ext_attr2(fs, block, buf);
 }
 
-errcode_t ext2fs_write_ext_attr2(ext2_filsys fs, blk64_t block, void *inbuf)
+errcode_t ext2fs_write_ext_attr3(ext2_filsys fs, blk64_t block, void *inbuf,
+                                ext2_ino_t inum)
 {
        errcode_t       retval;
        char            *write_buf;
-#ifdef WORDS_BIGENDIAN
-       char            *buf = NULL;
 
-       retval = ext2fs_get_mem(fs->blocksize, &buf);
+#ifdef WORDS_BIGENDIAN
+       retval = ext2fs_get_mem(fs->blocksize, &write_buf);
        if (retval)
                return retval;
-       write_buf = buf;
-       ext2fs_swap_ext_attr(buf, inbuf, fs->blocksize, 1);
+       ext2fs_swap_ext_attr(write_buf, inbuf, fs->blocksize, 1);
 #else
        write_buf = (char *) inbuf;
 #endif
+
+       retval = ext2fs_ext_attr_block_csum_set(fs, inum, block,
+                       (struct ext2_ext_attr_header *)write_buf);
+       if (retval)
+               return retval;
+
        retval = io_channel_write_blk64(fs->io, block, 1, write_buf);
 #ifdef WORDS_BIGENDIAN
-       ext2fs_free_mem(&buf);
+       ext2fs_free_mem(&write_buf);
 #endif
        if (!retval)
                ext2fs_mark_changed(fs);
        return retval;
 }
 
+errcode_t ext2fs_write_ext_attr2(ext2_filsys fs, blk64_t block, void *inbuf)
+{
+       return ext2fs_write_ext_attr3(fs, block, inbuf, 0);
+}
+
 errcode_t ext2fs_write_ext_attr(ext2_filsys fs, blk_t block, void *inbuf)
 {
        return ext2fs_write_ext_attr2(fs, block, inbuf);
@@ -111,9 +133,9 @@ errcode_t ext2fs_write_ext_attr(ext2_filsys fs, blk_t block, void *inbuf)
 /*
  * This function adjusts the reference count of the EA block.
  */
-errcode_t ext2fs_adjust_ea_refcount2(ext2_filsys fs, blk64_t blk,
+errcode_t ext2fs_adjust_ea_refcount3(ext2_filsys fs, blk64_t blk,
                                    char *block_buf, int adjust,
-                                   __u32 *newcount)
+                                   __u32 *newcount, ext2_ino_t inum)
 {
        errcode_t       retval;
        struct ext2_ext_attr_header *header;
@@ -130,7 +152,7 @@ errcode_t ext2fs_adjust_ea_refcount2(ext2_filsys fs, blk64_t blk,
                block_buf = buf;
        }
 
-       retval = ext2fs_read_ext_attr2(fs, blk, block_buf);
+       retval = ext2fs_read_ext_attr3(fs, blk, block_buf, inum);
        if (retval)
                goto errout;
 
@@ -139,7 +161,7 @@ errcode_t ext2fs_adjust_ea_refcount2(ext2_filsys fs, blk64_t blk,
        if (newcount)
                *newcount = header->h_refcount;
 
-       retval = ext2fs_write_ext_attr2(fs, blk, block_buf);
+       retval = ext2fs_write_ext_attr3(fs, blk, block_buf, inum);
        if (retval)
                goto errout;
 
@@ -149,9 +171,18 @@ errout:
        return retval;
 }
 
+errcode_t ext2fs_adjust_ea_refcount2(ext2_filsys fs, blk64_t blk,
+                                   char *block_buf, int adjust,
+                                   __u32 *newcount)
+{
+       return ext2fs_adjust_ea_refcount3(fs, blk, block_buf, adjust,
+                                         newcount, 0);
+}
+
 errcode_t ext2fs_adjust_ea_refcount(ext2_filsys fs, blk_t blk,
                                        char *block_buf, int adjust,
                                        __u32 *newcount)
 {
-       return ext2fs_adjust_ea_refcount(fs, blk, block_buf, adjust, newcount);
+       return ext2fs_adjust_ea_refcount2(fs, blk, block_buf, adjust,
+                                         newcount);
 }
index f3ee49d..fbb0a74 100644 (file)
@@ -455,6 +455,13 @@ retry:
                        return retval;
                }
 
+               if (!(handle->fs->flags & EXT2_FLAG_IGNORE_CSUM_ERRORS) &&
+                   !ext2fs_extent_block_csum_verify(handle->fs, handle->ino,
+                                                    eh)) {
+                       handle->level--;
+                       return EXT2_ET_EXTENT_CSUM_INVALID;
+               }
+
                newpath->left = newpath->entries =
                        ext2fs_le16_to_cpu(eh->eh_entries);
                newpath->max_entries = ext2fs_le16_to_cpu(eh->eh_max);
@@ -541,6 +548,7 @@ static errcode_t update_path(ext2_extent_handle_t handle)
        blk64_t                         blk;
        errcode_t                       retval;
        struct ext3_extent_idx          *ix;
+       struct ext3_extent_header       *eh;
 
        if (handle->level == 0) {
                retval = ext2fs_write_inode(handle->fs, handle->ino,
@@ -550,6 +558,14 @@ static errcode_t update_path(ext2_extent_handle_t handle)
                blk = ext2fs_le32_to_cpu(ix->ei_leaf) +
                        ((__u64) ext2fs_le16_to_cpu(ix->ei_leaf_hi) << 32);
 
+               /* then update the checksum */
+               eh = (struct ext3_extent_header *)
+                               handle->path[handle->level].buf;
+               retval = ext2fs_extent_block_csum_set(handle->fs, handle->ino,
+                                                     eh);
+               if (retval)
+                       return retval;
+
                retval = io_channel_write_blk64(handle->fs->io,
                                      blk, 1, handle->path[handle->level].buf);
        }
@@ -963,6 +979,11 @@ errcode_t ext2fs_extent_node_split(ext2_extent_handle_t handle)
 
        new_node_start = ext2fs_le32_to_cpu(EXT_FIRST_INDEX(neweh)->ei_block);
 
+       /* then update the checksum */
+       retval = ext2fs_extent_block_csum_set(handle->fs, handle->ino, neweh);
+       if (retval)
+               goto done;
+
        /* ...and write the new node block out to disk. */
        retval = io_channel_write_blk64(handle->fs->io, new_node_pblk, 1,
                                        block_buf);
index 1ad2d91..89a157b 100644 (file)
@@ -18,8 +18,6 @@
 #include "ext2_fs.h"
 #include "ext2fsP.h"
 
-static void ext2fs_free_inode_cache(struct ext2_inode_cache *icache);
-
 void ext2fs_free(ext2_filsys fs)
 {
        if (!fs || (fs->magic != EXT2_ET_MAGIC_EXT2FS_FILSYS))
@@ -67,21 +65,6 @@ void ext2fs_free(ext2_filsys fs)
 }
 
 /*
- * Free the inode cache structure
- */
-static void ext2fs_free_inode_cache(struct ext2_inode_cache *icache)
-{
-       if (--icache->refcount)
-               return;
-       if (icache->buffer)
-               ext2fs_free_mem(&icache->buffer);
-       if (icache->cache)
-               ext2fs_free_mem(&icache->cache);
-       icache->buffer_blk = 0;
-       ext2fs_free_mem(&icache);
-}
-
-/*
  * This procedure frees a badblocks list.
  */
 void ext2fs_u32_list_free(ext2_u32_list bb)
index d02488c..2880afa 100644 (file)
@@ -80,7 +80,7 @@ static void warn_bitmap(ext2fs_generic_bitmap bitmap,
 #endif
 }
 
-#ifdef BMAP_STATS_OPS
+#ifdef ENABLE_BMAP_STATS_OPS
 #define INC_STAT(map, name) map->stats.name
 #else
 #define INC_STAT(map, name) ;;
@@ -124,7 +124,7 @@ errcode_t ext2fs_alloc_generic_bmap(ext2_filsys fs, errcode_t magic,
        if (retval)
                return retval;
 
-#ifdef BMAP_STATS
+#ifdef ENABLE_BMAP_STATS
        if (gettimeofday(&bitmap->stats.created,
                         (struct timezone *) NULL) == -1) {
                perror("gettimeofday");
@@ -173,18 +173,18 @@ errcode_t ext2fs_alloc_generic_bmap(ext2_filsys fs, errcode_t magic,
        return 0;
 }
 
-#ifdef BMAP_STATS
+#ifdef ENABLE_BMAP_STATS
 static void ext2fs_print_bmap_statistics(ext2fs_generic_bitmap bitmap)
 {
        struct ext2_bmap_statistics *stats = &bitmap->stats;
-#ifdef BMAP_STATS_OPS
+#ifdef ENABLE_BMAP_STATS_OPS
        float mark_seq_perc = 0.0, test_seq_perc = 0.0;
        float mark_back_perc = 0.0, test_back_perc = 0.0;
 #endif
        double inuse;
        struct timeval now;
 
-#ifdef BMAP_STATS_OPS
+#ifdef ENABLE_BMAP_STATS_OPS
        if (stats->test_count) {
                test_seq_perc = ((float)stats->test_seq /
                                 stats->test_count) * 100;
@@ -213,7 +213,7 @@ static void ext2fs_print_bmap_statistics(ext2fs_generic_bitmap bitmap)
        fprintf(stderr, "\n[+] %s bitmap (type %d)\n", bitmap->description,
                stats->type);
        fprintf(stderr, "=================================================\n");
-#ifdef BMAP_STATS_OPS
+#ifdef ENABLE_BMAP_STATS_OPS
        fprintf(stderr, "%16llu bits long\n",
                bitmap->real_end - bitmap->start);
        fprintf(stderr, "%16lu copy_bmap\n%16lu resize_bmap\n",
@@ -236,7 +236,7 @@ static void ext2fs_print_bmap_statistics(ext2fs_generic_bitmap bitmap)
        fprintf(stderr, "%16llu bits marked backwards (%.2f%%)\n"
                "%16.2f seconds in use\n",
                stats->mark_back, mark_back_perc, inuse);
-#endif /* BMAP_STATS_OPS */
+#endif /* ENABLE_BMAP_STATS_OPS */
 }
 #endif
 
@@ -253,7 +253,7 @@ void ext2fs_free_generic_bmap(ext2fs_generic_bitmap bmap)
        if (!EXT2FS_IS_64_BITMAP(bmap))
                return;
 
-#ifdef BMAP_STATS
+#ifdef ENABLE_BMAP_STATS
        if (getenv("E2FSPROGS_BITMAP_STATS")) {
                ext2fs_print_bmap_statistics(bmap);
                bmap->bitmap_ops->print_stats(bmap);
@@ -293,10 +293,10 @@ errcode_t ext2fs_copy_generic_bmap(ext2fs_generic_bitmap src,
                return retval;
 
 
-#ifdef BMAP_STATS_OPS
+#ifdef ENABLE_BMAP_STATS_OPS
        src->stats.copy_count++;
 #endif
-#ifdef BMAP_STATS
+#ifdef ENABLE_BMAP_STATS
        if (gettimeofday(&new_bmap->stats.created,
                         (struct timezone *) NULL) == -1) {
                perror("gettimeofday");
@@ -322,7 +322,8 @@ errcode_t ext2fs_copy_generic_bmap(ext2fs_generic_bitmap src,
                        ext2fs_free_mem(&new_bmap);
                        return retval;
                }
-               sprintf(new_descr, "copy of %s", descr);
+               strcpy(new_descr, "copy of ");
+               strcat(new_descr, descr);
                new_bmap->description = new_descr;
        }
 
@@ -442,7 +443,7 @@ int ext2fs_mark_generic_bmap(ext2fs_generic_bitmap bitmap,
 
        arg >>= bitmap->cluster_bits;
 
-#ifdef BMAP_STATS_OPS
+#ifdef ENABLE_BMAP_STATS_OPS
        if (arg == bitmap->stats.last_marked + 1)
                bitmap->stats.mark_seq++;
        if (arg < bitmap->stats.last_marked)
@@ -509,7 +510,7 @@ int ext2fs_test_generic_bmap(ext2fs_generic_bitmap bitmap,
 
        arg >>= bitmap->cluster_bits;
 
-#ifdef BMAP_STATS_OPS
+#ifdef ENABLE_BMAP_STATS_OPS
        bitmap->stats.test_count++;
        if (arg == bitmap->stats.last_tested + 1)
                bitmap->stats.test_seq++;
index 9996e9d..a0742ee 100644 (file)
@@ -4,23 +4,27 @@
 
 #define ENTRIES_PER_LINE 4
 
-#if CRC_LE_BITS <= 8
-#define LE_TABLE_SIZE (1 << CRC_LE_BITS)
+#if CRC_LE_BITS > 8
+# define LE_TABLE_ROWS (CRC_LE_BITS/8)
+# define LE_TABLE_SIZE 256
 #else
-#define LE_TABLE_SIZE 256
+# define LE_TABLE_ROWS 1
+# define LE_TABLE_SIZE (1 << CRC_LE_BITS)
 #endif
 
-#if CRC_BE_BITS <= 8
-#define BE_TABLE_SIZE (1 << CRC_BE_BITS)
+#if CRC_BE_BITS > 8
+# define BE_TABLE_ROWS (CRC_BE_BITS/8)
+# define BE_TABLE_SIZE 256
 #else
-#define BE_TABLE_SIZE 256
+# define BE_TABLE_ROWS 1
+# define BE_TABLE_SIZE (1 << CRC_BE_BITS)
 #endif
 
-static uint32_t crc32ctable_le[8][256];
-static uint32_t crc32ctable_be[8][256];
+static uint32_t crc32table_be[BE_TABLE_ROWS][256];
+static uint32_t crc32ctable_le[LE_TABLE_ROWS][256];
 
 /**
- * crc32cinit_le() - allocate and initialize LE table data
+ * crc32init_le() - allocate and initialize LE table data
  *
  * crc is the crc of the byte i; other entries are filled in based on the
  * fact that crctable[i^j] = crctable[i] ^ crctable[j].
@@ -34,13 +38,13 @@ static void crc32cinit_le(void)
        crc32ctable_le[0][0] = 0;
 
        for (i = LE_TABLE_SIZE >> 1; i; i >>= 1) {
-               crc = (crc >> 1) ^ ((crc & 1) ? CRCPOLY_LE : 0);
+               crc = (crc >> 1) ^ ((crc & 1) ? CRC32C_POLY_LE : 0);
                for (j = 0; j < LE_TABLE_SIZE; j += 2 * i)
                        crc32ctable_le[0][i + j] = crc ^ crc32ctable_le[0][j];
        }
        for (i = 0; i < LE_TABLE_SIZE; i++) {
                crc = crc32ctable_le[0][i];
-               for (j = 1; j < 8; j++) {
+               for (j = 1; j < LE_TABLE_ROWS; j++) {
                        crc = crc32ctable_le[0][crc & 0xff] ^ (crc >> 8);
                        crc32ctable_le[j][i] = crc;
                }
@@ -48,75 +52,65 @@ static void crc32cinit_le(void)
 }
 
 /**
- * crc32cinit_be() - allocate and initialize BE table data
+ * crc32init_be() - allocate and initialize BE table data
  */
-static void crc32cinit_be(void)
+static void crc32init_be(void)
 {
        unsigned i, j;
        uint32_t crc = 0x80000000;
 
-       crc32ctable_be[0][0] = 0;
+       crc32table_be[0][0] = 0;
 
        for (i = 1; i < BE_TABLE_SIZE; i <<= 1) {
                crc = (crc << 1) ^ ((crc & 0x80000000) ? CRCPOLY_BE : 0);
                for (j = 0; j < i; j++)
-                       crc32ctable_be[0][i + j] = crc ^ crc32ctable_be[0][j];
+                       crc32table_be[0][i + j] = crc ^ crc32table_be[0][j];
        }
        for (i = 0; i < BE_TABLE_SIZE; i++) {
-               crc = crc32ctable_be[0][i];
-               for (j = 1; j < 8; j++) {
-                       crc = crc32ctable_be[0][(crc >> 24) & 0xff] ^
-                             (crc << 8);
-                       crc32ctable_be[j][i] = crc;
+               crc = crc32table_be[0][i];
+               for (j = 1; j < BE_TABLE_ROWS; j++) {
+                       crc = crc32table_be[0][(crc >> 24) & 0xff] ^ (crc << 8);
+                       crc32table_be[j][i] = crc;
                }
        }
 }
 
-static void output_table(uint32_t table[8][256], int len, char trans)
+static void output_table(uint32_t (*table)[256], int rows, int len, char *trans)
 {
        int i, j;
 
-       for (j = 0 ; j < 8; j++) {
-               printf("static const uint32_t t%d_%ce[] = {", j, trans);
+       for (j = 0 ; j < rows; j++) {
+               printf("{");
                for (i = 0; i < len - 1; i++) {
-                       if ((i % ENTRIES_PER_LINE) == 0)
+                       if (i % ENTRIES_PER_LINE == 0)
                                printf("\n");
-                       printf("to%ce(0x%8.8xL),", trans, table[j][i]);
-                       if ((i % ENTRIES_PER_LINE) != (ENTRIES_PER_LINE - 1))
-                               printf(" ");
-               }
-               printf("to%ce(0x%8.8xL)};\n\n", trans, table[j][len - 1]);
-
-               if (trans == 'l') {
-                       if ((j+1)*8 >= CRC_LE_BITS)
-                               break;
-               } else {
-                       if ((j+1)*8 >= CRC_BE_BITS)
-                               break;
+                       printf("%s(0x%8.8xL), ", trans, table[j][i]);
                }
+               printf("%s(0x%8.8xL)},\n", trans, table[j][len - 1]);
        }
 }
 
 int main(int argc, char **argv)
 {
-       printf("/*\n");
-       printf(" * crc32ctable.h - CRC32c tables\n");
-       printf(" *    this file is generated - do not edit\n");
-       printf(" *      # gen_crc32ctable > crc32c_table.h\n");
-       printf(" *    with\n");
-       printf(" *      CRC_LE_BITS = %d\n", CRC_LE_BITS);
-       printf(" *      CRC_BE_BITS = %d\n", CRC_BE_BITS);
-       printf(" */\n");
-       printf("#include <stdint.h>\n");
+       printf("/* this file is generated - do not edit */\n\n");
 
+       if (CRC_BE_BITS > 1) {
+               crc32init_be();
+               printf("static const uint32_t "
+                      "crc32table_be[%d][%d] = {",
+                      BE_TABLE_ROWS, BE_TABLE_SIZE);
+               output_table(crc32table_be, LE_TABLE_ROWS,
+                            BE_TABLE_SIZE, "tobe");
+               printf("};\n");
+       }
        if (CRC_LE_BITS > 1) {
                crc32cinit_le();
-               output_table(crc32ctable_le, LE_TABLE_SIZE, 'l');
-       }
-
-       if (CRC_BE_BITS > 1) {
-               crc32cinit_be();
-               output_table(crc32ctable_be, BE_TABLE_SIZE, 'b');
+               printf("static const uint32_t "
+                      "crc32ctable_le[%d][%d] = {",
+                      LE_TABLE_ROWS, LE_TABLE_SIZE);
+               output_table(crc32ctable_le, LE_TABLE_ROWS,
+                            LE_TABLE_SIZE, "tole");
+               printf("};\n");
        }
 
        return 0;
diff --git a/lib/ext2fs/get_num_dirs.c b/lib/ext2fs/get_num_dirs.c
new file mode 100644 (file)
index 0000000..f5644f8
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * get_num_dirs.c -- calculate number of directories
+ *
+ * Copyright 1997 by Theodore Ts'o
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Library
+ * General Public License, version 2.
+ * %End-Header%
+ */
+
+#include "config.h"
+#include <stdio.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <string.h>
+#include <time.h>
+
+#include "ext2_fs.h"
+#include "ext2fsP.h"
+
+/*
+ * Returns the number of directories in the filesystem as reported by
+ * the group descriptors.  Of course, the group descriptors could be
+ * wrong!
+ */
+errcode_t ext2fs_get_num_dirs(ext2_filsys fs, ext2_ino_t *ret_num_dirs)
+{
+       dgrp_t  i;
+       ext2_ino_t      num_dirs, max_dirs;
+
+       EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
+
+       num_dirs = 0;
+       max_dirs = fs->super->s_inodes_per_group;
+       for (i = 0; i < fs->group_desc_count; i++) {
+               if (ext2fs_bg_used_dirs_count(fs, i) > max_dirs)
+                       num_dirs += max_dirs / 8;
+               else
+                       num_dirs += ext2fs_bg_used_dirs_count(fs, i);
+       }
+       if (num_dirs > fs->super->s_inodes_count)
+               num_dirs = fs->super->s_inodes_count;
+
+       *ret_num_dirs = num_dirs;
+
+       return 0;
+}
+
index 52aea62..4c9c765 100644 (file)
@@ -49,21 +49,20 @@ static int get_pathname_proc(struct ext2_dir_entry *dirent,
 {
        struct get_pathname_struct      *gp;
        errcode_t                       retval;
+       int name_len = ext2fs_dirent_name_len(dirent);
 
        gp = (struct get_pathname_struct *) priv_data;
 
-       if (((dirent->name_len & 0xFF) == 2) &&
-           !strncmp(dirent->name, "..", 2))
+       if ((name_len == 2) && !strncmp(dirent->name, "..", 2))
                gp->parent = dirent->inode;
        if (dirent->inode == gp->search_ino) {
-               retval = ext2fs_get_mem((dirent->name_len & 0xFF) + 1,
-                                       &gp->name);
+               retval = ext2fs_get_mem(name_len + 1, &gp->name);
                if (retval) {
                        gp->errcode = retval;
                        return DIRENT_ABORT;
                }
-               strncpy(gp->name, dirent->name, (dirent->name_len & 0xFF));
-               gp->name[dirent->name_len & 0xFF] = '\0';
+               strncpy(gp->name, dirent->name, name_len);
+               gp->name[name_len] = '\0';
                return DIRENT_ABORT;
        }
        return 0;
index 5afdc27..62a19b3 100644 (file)
@@ -458,8 +458,7 @@ ipg_retry:
         * bitmaps will be accounted for when allocated).
         */
        free_blocks = 0;
-       csum_flag = EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
-                                              EXT4_FEATURE_RO_COMPAT_GDT_CSUM);
+       csum_flag = ext2fs_has_group_desc_csum(fs);
        reserved_inos = super->s_first_ino;
        for (i = 0; i < fs->group_desc_count; i++) {
                /*
index 573a8fa..46c1c58 100644 (file)
@@ -72,8 +72,28 @@ errcode_t ext2fs_flush_icache(ext2_filsys fs)
        return 0;
 }
 
+/*
+ * Free the inode cache structure
+ */
+void ext2fs_free_inode_cache(struct ext2_inode_cache *icache)
+{
+       int i;
+
+       if (--icache->refcount)
+               return;
+       if (icache->buffer)
+               ext2fs_free_mem(&icache->buffer);
+       for (i = 0; i < icache->cache_size; i++)
+               ext2fs_free_mem(&icache->cache[i].inode);
+       if (icache->cache)
+               ext2fs_free_mem(&icache->cache);
+       icache->buffer_blk = 0;
+       ext2fs_free_mem(&icache);
+}
+
 static errcode_t create_icache(ext2_filsys fs)
 {
+       int             i;
        errcode_t       retval;
 
        if (fs->icache)
@@ -84,10 +104,9 @@ static errcode_t create_icache(ext2_filsys fs)
 
        memset(fs->icache, 0, sizeof(struct ext2_inode_cache));
        retval = ext2fs_get_mem(fs->blocksize, &fs->icache->buffer);
-       if (retval) {
-               ext2fs_free_mem(&fs->icache);
-               return retval;
-       }
+       if (retval)
+               goto errout;
+
        fs->icache->buffer_blk = 0;
        fs->icache->cache_last = -1;
        fs->icache->cache_size = 4;
@@ -95,13 +114,22 @@ static errcode_t create_icache(ext2_filsys fs)
        retval = ext2fs_get_array(fs->icache->cache_size,
                                  sizeof(struct ext2_inode_cache_ent),
                                  &fs->icache->cache);
-       if (retval) {
-               ext2fs_free_mem(&fs->icache->buffer);
-               ext2fs_free_mem(&fs->icache);
-               return retval;
+       if (retval)
+               goto errout;
+
+       for (i = 0; i < fs->icache->cache_size; i++) {
+               retval = ext2fs_get_mem(EXT2_INODE_SIZE(fs->super),
+                                       &fs->icache->cache[i].inode);
+               if (retval)
+                       goto errout;
        }
+
        ext2fs_flush_icache(fs);
        return 0;
+errout:
+       ext2fs_free_inode_cache(fs->icache);
+       fs->icache = 0;
+       return retval;
 }
 
 errcode_t ext2fs_open_inode_scan(ext2_filsys fs, int buffer_blocks,
@@ -148,8 +176,7 @@ errcode_t ext2fs_open_inode_scan(ext2_filsys fs, int buffer_blocks,
                                                     scan->current_group);
        scan->inodes_left = EXT2_INODES_PER_GROUP(scan->fs->super);
        scan->blocks_left = scan->fs->inode_blocks_per_group;
-       if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
-                                      EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) {
+       if (ext2fs_has_group_desc_csum(fs)) {
                scan->inodes_left -=
                        ext2fs_bg_itable_unused(fs, scan->current_group);
                scan->blocks_left =
@@ -174,8 +201,7 @@ errcode_t ext2fs_open_inode_scan(ext2_filsys fs, int buffer_blocks,
        }
        if (scan->fs->badblocks && scan->fs->badblocks->num)
                scan->scan_flags |= EXT2_SF_CHK_BADBLOCKS;
-       if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
-                                      EXT4_FEATURE_RO_COMPAT_GDT_CSUM))
+       if (ext2fs_has_group_desc_csum(fs))
                scan->scan_flags |= EXT2_SF_DO_LAZY;
        *ret_scan = scan;
        return 0;
@@ -241,8 +267,7 @@ static errcode_t get_next_blockgroup(ext2_inode_scan scan)
        scan->bytes_left = 0;
        scan->inodes_left = EXT2_INODES_PER_GROUP(fs->super);
        scan->blocks_left = fs->inode_blocks_per_group;
-       if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
-                                      EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) {
+       if (ext2fs_has_group_desc_csum(fs)) {
                scan->inodes_left -=
                        ext2fs_bg_itable_unused(fs, scan->current_group);
                scan->blocks_left =
@@ -407,6 +432,8 @@ errcode_t ext2fs_get_next_inode_full(ext2_inode_scan scan, ext2_ino_t *ino,
 {
        errcode_t       retval;
        int             extra_bytes = 0;
+       const int       length = EXT2_INODE_SIZE(scan->fs->super);
+       struct ext2_inode_large *iptr = (struct ext2_inode_large *)inode;
 
        EXT2_CHECK_MAGIC(scan, EXT2_ET_MAGIC_INODE_SCAN);
 
@@ -469,6 +496,12 @@ errcode_t ext2fs_get_next_inode_full(ext2_inode_scan scan, ext2_ino_t *ino,
 #endif
        }
 
+       if (bufsize < length) {
+               retval = ext2fs_get_mem(length, &iptr);
+               if (retval)
+                       return retval;
+       }
+
        retval = 0;
        if (extra_bytes) {
                memcpy(scan->temp_buffer+extra_bytes, scan->ptr,
@@ -476,27 +509,39 @@ errcode_t ext2fs_get_next_inode_full(ext2_inode_scan scan, ext2_ino_t *ino,
                scan->ptr += scan->inode_size - extra_bytes;
                scan->bytes_left -= scan->inode_size - extra_bytes;
 
+               /* Verify the inode checksum. */
+               if (!(scan->fs->flags & EXT2_FLAG_IGNORE_CSUM_ERRORS) &&
+                   !ext2fs_inode_csum_verify(scan->fs, scan->current_inode + 1,
+                               (struct ext2_inode_large *)scan->temp_buffer))
+                       retval = EXT2_ET_INODE_CSUM_INVALID;
+
 #ifdef WORDS_BIGENDIAN
-               memset(inode, 0, bufsize);
+               memset(iptr, 0, length);
                ext2fs_swap_inode_full(scan->fs,
-                              (struct ext2_inode_large *) inode,
+                              (struct ext2_inode_large *) iptr,
                               (struct ext2_inode_large *) scan->temp_buffer,
-                              0, bufsize);
+                              0, length);
 #else
-               *inode = *((struct ext2_inode *) scan->temp_buffer);
+               memcpy(iptr, scan->temp_buffer, length);
 #endif
                if (scan->scan_flags & EXT2_SF_BAD_EXTRA_BYTES)
                        retval = EXT2_ET_BAD_BLOCK_IN_INODE_TABLE;
                scan->scan_flags &= ~EXT2_SF_BAD_EXTRA_BYTES;
        } else {
+               /* Verify the inode checksum. */
+               if (!(scan->fs->flags & EXT2_FLAG_IGNORE_CSUM_ERRORS) &&
+                   !ext2fs_inode_csum_verify(scan->fs, scan->current_inode + 1,
+                               (struct ext2_inode_large *)scan->ptr))
+                       retval = EXT2_ET_INODE_CSUM_INVALID;
+
 #ifdef WORDS_BIGENDIAN
-               memset(inode, 0, bufsize);
+               memset(iptr, 0, length);
                ext2fs_swap_inode_full(scan->fs,
-                               (struct ext2_inode_large *) inode,
+                               (struct ext2_inode_large *) iptr,
                                (struct ext2_inode_large *) scan->ptr,
-                               0, bufsize);
+                               0, length);
 #else
-               memcpy(inode, scan->ptr, bufsize);
+               memcpy(iptr, scan->ptr, length);
 #endif
                scan->ptr += scan->inode_size;
                scan->bytes_left -= scan->inode_size;
@@ -507,6 +552,10 @@ errcode_t ext2fs_get_next_inode_full(ext2_inode_scan scan, ext2_ino_t *ino,
        scan->inodes_left--;
        scan->current_inode++;
        *ino = scan->current_inode;
+       if (iptr != (struct ext2_inode_large *)inode) {
+               memcpy(inode, iptr, bufsize);
+               ext2fs_free_mem(&iptr);
+       }
        return retval;
 }
 
@@ -527,8 +576,11 @@ errcode_t ext2fs_read_inode_full(ext2_filsys fs, ext2_ino_t ino,
        unsigned long   group, block, offset;
        char            *ptr;
        errcode_t       retval;
-       int             clen, i, inodes_per_block, length;
+       int             clen, i, inodes_per_block;
        io_channel      io;
+       int             length = EXT2_INODE_SIZE(fs->super);
+       struct ext2_inode_large *iptr;
+       int             cache_slot;
 
        EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
 
@@ -549,13 +601,11 @@ errcode_t ext2fs_read_inode_full(ext2_filsys fs, ext2_ino_t ino,
                        return retval;
        }
        /* Check to see if it's in the inode cache */
-       if (bufsize == sizeof(struct ext2_inode)) {
-               /* only old good inode can be retrieved from the cache */
-               for (i=0; i < fs->icache->cache_size; i++) {
-                       if (fs->icache->cache[i].ino == ino) {
-                               *inode = fs->icache->cache[i].inode;
-                               return 0;
-                       }
+       for (i = 0; i < fs->icache->cache_size; i++) {
+               if (fs->icache->cache[i].ino == ino) {
+                       memcpy(inode, fs->icache->cache[i].inode,
+                              (bufsize > length) ? length : bufsize);
+                       return 0;
                }
        }
        if (fs->flags & EXT2_FLAG_IMAGE_FILE) {
@@ -580,11 +630,10 @@ errcode_t ext2fs_read_inode_full(ext2_filsys fs, ext2_ino_t ino,
        }
        offset &= (EXT2_BLOCK_SIZE(fs->super) - 1);
 
-       length = EXT2_INODE_SIZE(fs->super);
-       if (bufsize < length)
-               length = bufsize;
+       cache_slot = (fs->icache->cache_last + 1) % fs->icache->cache_size;
+       iptr = (struct ext2_inode_large *)fs->icache->cache[cache_slot].inode;
 
-       ptr = (char *) inode;
+       ptr = (char *) iptr;
        while (length) {
                clen = length;
                if ((offset + length) > fs->blocksize)
@@ -606,18 +655,23 @@ errcode_t ext2fs_read_inode_full(ext2_filsys fs, ext2_ino_t ino,
                ptr += clen;
                block_nr++;
        }
+       length = EXT2_INODE_SIZE(fs->super);
+
+       /* Verify the inode checksum. */
+       if (!(fs->flags & EXT2_FLAG_IGNORE_CSUM_ERRORS) &&
+           !ext2fs_inode_csum_verify(fs, ino, iptr))
+               return EXT2_ET_INODE_CSUM_INVALID;
 
 #ifdef WORDS_BIGENDIAN
-       ext2fs_swap_inode_full(fs, (struct ext2_inode_large *) inode,
-                              (struct ext2_inode_large *) inode,
-                              0, bufsize);
+       ext2fs_swap_inode_full(fs, (struct ext2_inode_large *) iptr,
+                              (struct ext2_inode_large *) iptr,
+                              0, length);
 #endif
 
-       /* Update the inode cache */
-       fs->icache->cache_last = (fs->icache->cache_last + 1) %
-               fs->icache->cache_size;
-       fs->icache->cache[fs->icache->cache_last].ino = ino;
-       fs->icache->cache[fs->icache->cache_last].inode = *inode;
+       /* Update the inode cache bookkeeping */
+       fs->icache->cache_last = cache_slot;
+       fs->icache->cache[cache_slot].ino = ino;
+       memcpy(inode, iptr, (bufsize > length) ? length : bufsize);
 
        return 0;
 }
@@ -635,9 +689,10 @@ errcode_t ext2fs_write_inode_full(ext2_filsys fs, ext2_ino_t ino,
        blk64_t block_nr;
        unsigned long group, block, offset;
        errcode_t retval = 0;
-       struct ext2_inode_large temp_inode, *w_inode;
+       struct ext2_inode_large *w_inode;
        char *ptr;
-       int clen, i, length;
+       int clen, i;
+       int length = EXT2_INODE_SIZE(fs->super);
 
        EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
 
@@ -648,48 +703,54 @@ errcode_t ext2fs_write_inode_full(ext2_filsys fs, ext2_ino_t ino,
                        return retval;
        }
 
+       if ((ino == 0) || (ino > fs->super->s_inodes_count))
+               return EXT2_ET_BAD_INODE_NUM;
+
+       /* Prepare our shadow buffer for read/modify/byteswap/write */
+       retval = ext2fs_get_mem(length, &w_inode);
+       if (retval)
+               return retval;
+
+       if (bufsize < length) {
+               int old_flags = fs->flags;
+               fs->flags |= EXT2_FLAG_IGNORE_CSUM_ERRORS;
+               retval = ext2fs_read_inode_full(fs, ino,
+                                               (struct ext2_inode *)w_inode,
+                                               length);
+               fs->flags = old_flags;
+               if (retval)
+                       goto errout;
+       }
+
        /* Check to see if the inode cache needs to be updated */
        if (fs->icache) {
                for (i=0; i < fs->icache->cache_size; i++) {
                        if (fs->icache->cache[i].ino == ino) {
-                               fs->icache->cache[i].inode = *inode;
+                               memcpy(fs->icache->cache[i].inode, inode,
+                                      (bufsize > length) ? length : bufsize);
                                break;
                        }
                }
        } else {
                retval = create_icache(fs);
                if (retval)
-                       return retval;
+                       goto errout;
        }
+       memcpy(w_inode, inode, (bufsize > length) ? length : bufsize);
 
-       if (!(fs->flags & EXT2_FLAG_RW))
-               return EXT2_ET_RO_FILSYS;
-
-       if ((ino == 0) || (ino > fs->super->s_inodes_count))
-               return EXT2_ET_BAD_INODE_NUM;
-
-       length = bufsize;
-       if (length < EXT2_INODE_SIZE(fs->super))
-               length = EXT2_INODE_SIZE(fs->super);
-
-       if (length > (int) sizeof(struct ext2_inode_large)) {
-               w_inode = malloc(length);
-               if (!w_inode) {
-                       retval = ENOMEM;
-                       goto errout;
-               }
-       } else
-               w_inode = &temp_inode;
-       memset(w_inode, 0, length);
+       if (!(fs->flags & EXT2_FLAG_RW)) {
+               retval = EXT2_ET_RO_FILSYS;
+               goto errout;
+       }
 
 #ifdef WORDS_BIGENDIAN
-       ext2fs_swap_inode_full(fs, w_inode,
-                              (struct ext2_inode_large *) inode,
-                              1, bufsize);
-#else
-       memcpy(w_inode, inode, bufsize);
+       ext2fs_swap_inode_full(fs, w_inode, w_inode, 1, length);
 #endif
 
+       retval = ext2fs_inode_csum_set(fs, ino, w_inode);
+       if (retval)
+               goto errout;
+
        group = (ino - 1) / EXT2_INODES_PER_GROUP(fs->super);
        offset = ((ino - 1) % EXT2_INODES_PER_GROUP(fs->super)) *
                EXT2_INODE_SIZE(fs->super);
@@ -702,10 +763,6 @@ errcode_t ext2fs_write_inode_full(ext2_filsys fs, ext2_ino_t ino,
 
        offset &= (EXT2_BLOCK_SIZE(fs->super) - 1);
 
-       length = EXT2_INODE_SIZE(fs->super);
-       if (length > bufsize)
-               length = bufsize;
-
        ptr = (char *) w_inode;
 
        while (length) {
@@ -738,8 +795,7 @@ errcode_t ext2fs_write_inode_full(ext2_filsys fs, ext2_ino_t ino,
 
        fs->flags |= EXT2_FLAG_CHANGED;
 errout:
-       if (w_inode && w_inode != &temp_inode)
-               free(w_inode);
+       ext2fs_free_mem(&w_inode);
        return retval;
 }
 
index 7b8aafd..7947ef5 100644 (file)
@@ -17,6 +17,8 @@
 
 #define cpu_to_be32(n) htonl(n)
 #define be32_to_cpu(n) ntohl(n)
+#define cpu_to_be16(n) htons(n)
+#define be16_to_cpu(n) ntohs(n)
 
 typedef unsigned int tid_t;
 typedef struct journal_s journal_t;
index 059bf8f..130c3a2 100644 (file)
@@ -114,12 +114,24 @@ typedef struct journal_header_s
 #define JBD2_CRC32_CHKSUM   1
 #define JBD2_MD5_CHKSUM     2
 #define JBD2_SHA1_CHKSUM    3
+#define JBD2_CRC32C_CHKSUM  4
 
 #define JBD2_CRC32_CHKSUM_SIZE 4
 
 #define JBD2_CHECKSUM_BYTES (32 / sizeof(__u32))
 /*
  * Commit block header for storing transactional checksums:
+ *
+ * NOTE: If FEATURE_COMPAT_CHECKSUM (checksum v1) is set, the h_chksum*
+ * fields are used to store a checksum of the descriptor and data blocks.
+ *
+ * If FEATURE_INCOMPAT_CSUM_V2 (checksum v2) is set, then the h_chksum
+ * field is used to store crc32c(uuid+commit_block).  Each journal metadata
+ * block gets its own checksum, and data block checksums are stored in
+ * journal_block_tag (in the descriptor).  The other h_chksum* fields are
+ * not used.
+ *
+ * Checksum v1 and v2 are mutually exclusive features.
  */
 struct commit_header {
        __u32           h_magic;
@@ -139,13 +151,19 @@ struct commit_header {
 typedef struct journal_block_tag_s
 {
        __u32           t_blocknr;      /* The on-disk block number */
-       __u32           t_flags;        /* See below */
+       __u16           t_checksum;     /* truncated crc32c(uuid+seq+block) */
+       __u16           t_flags;        /* See below */
        __u32           t_blocknr_high; /* most-significant high 32bits. */
 } journal_block_tag_t;
 
 #define JBD_TAG_SIZE64 (sizeof(journal_block_tag_t))
 #define JBD_TAG_SIZE32 (8)
 
+/* Tail of descriptor block, for checksumming */
+struct journal_block_tail {
+       __u32           t_checksum;
+};
+
 /*
  * The revoke descriptor: used on disk to describe a series of blocks to
  * be revoked from the log
@@ -156,6 +174,10 @@ typedef struct journal_revoke_header_s
        int              r_count;       /* Count of bytes used in the block */
 } journal_revoke_header_t;
 
+/* Tail of revoke block, for checksumming */
+struct journal_revoke_tail {
+       __u32           r_checksum;
+};
 
 /* Definitions for the journal tag flags word: */
 #define JFS_FLAG_ESCAPE                1       /* on-disk block is escaped */
@@ -205,7 +227,10 @@ typedef struct journal_superblock_s
        __u32   s_max_trans_data;       /* Limit of data blocks per trans. */
 
 /* 0x0050 */
-       __u32   s_padding[44];
+       __u8    s_checksum_type;        /* checksum type */
+       __u8    s_padding2[3];
+       __u32   s_padding[42];
+       __u32   s_checksum;             /* crc32c(superblock) */
 
 /* 0x0100 */
        __u8    s_users[16*48];         /* ids of all fs'es sharing the log */
@@ -224,18 +249,56 @@ typedef struct journal_superblock_s
 
 #define JFS_FEATURE_COMPAT_CHECKSUM    0x00000001
 
-#define JFS_FEATURE_INCOMPAT_REVOKE    0x00000001
-
 #define JFS_FEATURE_INCOMPAT_REVOKE            0x00000001
 #define JFS_FEATURE_INCOMPAT_64BIT             0x00000002
 #define JFS_FEATURE_INCOMPAT_ASYNC_COMMIT      0x00000004
+#define JFS_FEATURE_INCOMPAT_CSUM_V2           0x00000008
 
 /* Features known to this kernel version: */
 #define JFS_KNOWN_COMPAT_FEATURES      0
 #define JFS_KNOWN_ROCOMPAT_FEATURES    0
 #define JFS_KNOWN_INCOMPAT_FEATURES    (JFS_FEATURE_INCOMPAT_REVOKE|\
                                         JFS_FEATURE_INCOMPAT_ASYNC_COMMIT|\
-                                        JFS_FEATURE_INCOMPAT_64BIT)
+                                        JFS_FEATURE_INCOMPAT_64BIT|\
+                                        JFS_FEATURE_INCOMPAT_CSUM_V2)
+
+#if (defined(E2FSCK_INCLUDE_INLINE_FUNCS) || !defined(NO_INLINE_FUNCS))
+#ifdef E2FSCK_INCLUDE_INLINE_FUNCS
+#if (__STDC_VERSION__ >= 199901L)
+#define _INLINE_ extern inline
+#else
+#define _INLINE_ inline
+#endif
+#else /* !E2FSCK_INCLUDE_INLINE FUNCS */
+#if (__STDC_VERSION__ >= 199901L)
+#define _INLINE_ inline
+#else /* not C99 */
+#ifdef __GNUC__
+#define _INLINE_ extern __inline__
+#else                          /* For Watcom C */
+#define _INLINE_ extern inline
+#endif /* __GNUC__ */
+#endif /* __STDC_VERSION__ >= 199901L */
+#endif /* INCLUDE_INLINE_FUNCS */
+
+/*
+ * helper functions to deal with 32 or 64bit block numbers.
+ */
+_INLINE_ size_t journal_tag_bytes(journal_t *journal)
+{
+       journal_block_tag_t tag;
+       size_t x = 0;
+
+       if (JFS_HAS_INCOMPAT_FEATURE(journal, JFS_FEATURE_INCOMPAT_CSUM_V2))
+               x += sizeof(tag.t_checksum);
+
+       if (JFS_HAS_INCOMPAT_FEATURE(journal, JFS_FEATURE_INCOMPAT_64BIT))
+               return x + JBD_TAG_SIZE64;
+       else
+               return x + JBD_TAG_SIZE32;
+}
+#undef _INLINE_
+#endif
 
 #ifdef __KERNEL__
 
index bf3c859..09e6cb4 100644 (file)
@@ -41,6 +41,8 @@ static int link_proc(struct ext2_dir_entry *dirent,
        struct ext2_dir_entry *next;
        unsigned int rec_len, min_rec_len, curr_rec_len;
        int ret = 0;
+       int csum_size = 0;
+       struct ext2_dir_entry_tail *t;
 
        if (ls->done)
                return DIRENT_ABORT;
@@ -51,12 +53,15 @@ static int link_proc(struct ext2_dir_entry *dirent,
        if (ls->err)
                return DIRENT_ABORT;
 
+       if (EXT2_HAS_RO_COMPAT_FEATURE(ls->fs->super,
+                                      EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
+               csum_size = sizeof(struct ext2_dir_entry_tail);
        /*
         * See if the following directory entry (if any) is unused;
         * if so, absorb it into this one.
         */
        next = (struct ext2_dir_entry *) (buf + offset + curr_rec_len);
-       if ((offset + (int) curr_rec_len < blocksize - 8) &&
+       if ((offset + (int) curr_rec_len < blocksize - (8 + csum_size)) &&
            (next->inode == 0) &&
            (offset + (int) curr_rec_len + (int) next->rec_len <= blocksize)) {
                curr_rec_len += next->rec_len;
@@ -67,12 +72,46 @@ static int link_proc(struct ext2_dir_entry *dirent,
        }
 
        /*
+        * Since ext2fs_link blows away htree data, we need to be
+        * careful -- if metadata_csum is enabled and we're passed in
+        * a dirent that contains htree data, we need to create the
+        * fake entry at the end of the block that hides the checksum.
+        */
+
+       /* De-convert a dx_node block */
+       if (csum_size &&
+           curr_rec_len == ls->fs->blocksize &&
+           !dirent->inode) {
+               curr_rec_len -= csum_size;
+               ls->err = ext2fs_set_rec_len(ls->fs, curr_rec_len, dirent);
+               if (ls->err)
+                       return DIRENT_ABORT;
+               t = EXT2_DIRENT_TAIL(buf, ls->fs->blocksize);
+               ext2fs_initialize_dirent_tail(ls->fs, t);
+               ret = DIRENT_CHANGED;
+       }
+
+       /* De-convert a dx_root block */
+       if (csum_size &&
+           curr_rec_len == ls->fs->blocksize - EXT2_DIR_REC_LEN(1) &&
+           offset == EXT2_DIR_REC_LEN(1) &&
+           dirent->name[0] == '.' && dirent->name[1] == '.') {
+               curr_rec_len -= csum_size;
+               ls->err = ext2fs_set_rec_len(ls->fs, curr_rec_len, dirent);
+               if (ls->err)
+                       return DIRENT_ABORT;
+               t = EXT2_DIRENT_TAIL(buf, ls->fs->blocksize);
+               ext2fs_initialize_dirent_tail(ls->fs, t);
+               ret = DIRENT_CHANGED;
+       }
+
+       /*
         * If the directory entry is used, see if we can split the
         * directory entry to make room for the new name.  If so,
         * truncate it and return.
         */
        if (dirent->inode) {
-               min_rec_len = EXT2_DIR_REC_LEN(dirent->name_len & 0xFF);
+               min_rec_len = EXT2_DIR_REC_LEN(ext2fs_dirent_name_len(dirent));
                if (curr_rec_len < (min_rec_len + rec_len))
                        return ret;
                rec_len = curr_rec_len - min_rec_len;
@@ -82,7 +121,8 @@ static int link_proc(struct ext2_dir_entry *dirent,
                next = (struct ext2_dir_entry *) (buf + offset +
                                                  dirent->rec_len);
                next->inode = 0;
-               next->name_len = 0;
+               ext2fs_dirent_set_name_len(next, 0);
+               ext2fs_dirent_set_file_type(next, 0);
                ls->err = ext2fs_set_rec_len(ls->fs, rec_len, next);
                if (ls->err)
                        return DIRENT_ABORT;
@@ -96,10 +136,10 @@ static int link_proc(struct ext2_dir_entry *dirent,
        if (curr_rec_len < rec_len)
                return ret;
        dirent->inode = ls->inode;
-       dirent->name_len = ls->namelen;
+       ext2fs_dirent_set_name_len(dirent, ls->namelen);
        strncpy(dirent->name, ls->name, ls->namelen);
        if (ls->sb->s_feature_incompat & EXT2_FEATURE_INCOMPAT_FILETYPE)
-               dirent->name_len |= (ls->flags & 0x7) << 8;
+               ext2fs_dirent_set_file_type(dirent, ls->flags & 0x7);
 
        ls->done++;
        return DIRENT_ABORT|DIRENT_CHANGED;
@@ -147,6 +187,11 @@ errcode_t ext2fs_link(ext2_filsys fs, ext2_ino_t dir, const char *name,
        if ((retval = ext2fs_read_inode(fs, dir, &inode)) != 0)
                return retval;
 
+       /*
+        * If this function changes to preserve the htree, remove the
+        * two hunks in link_proc that shove checksum tails into the
+        * former dx_root/dx_node blocks.
+        */
        if (inode.i_flags & EXT2_INDEX_FL) {
                inode.i_flags &= ~EXT2_INDEX_FL;
                if ((retval = ext2fs_write_inode(fs, dir, &inode)) != 0)
index 0e66e71..c1d802c 100644 (file)
@@ -37,9 +37,9 @@ static int lookup_proc(struct ext2_dir_entry *dirent,
 {
        struct lookup_struct *ls = (struct lookup_struct *) priv_data;
 
-       if (ls->len != (dirent->name_len & 0xFF))
+       if (ls->len != ext2fs_dirent_name_len(dirent))
                return 0;
-       if (strncmp(ls->name, dirent->name, (dirent->name_len & 0xFF)))
+       if (strncmp(ls->name, dirent->name, ext2fs_dirent_name_len(dirent)))
                return 0;
        *ls->inode = dirent->inode;
        ls->found++;
index b12bf2d..4a85439 100644 (file)
@@ -93,12 +93,14 @@ errcode_t ext2fs_mkdir(ext2_filsys fs, ext2_ino_t parent, ext2_ino_t inum,
        inode.i_size = fs->blocksize;
 
        /*
-        * Write out the inode and inode data block
+        * Write out the inode and inode data block.  The inode generation
+        * number is assigned by write_new_inode, which means that the call
+        * to write_dir_block must come after that.
         */
-       retval = ext2fs_write_dir_block(fs, blk, block);
+       retval = ext2fs_write_new_inode(fs, ino, &inode);
        if (retval)
                goto cleanup;
-       retval = ext2fs_write_new_inode(fs, ino, &inode);
+       retval = ext2fs_write_dir_block4(fs, blk, block, 0, ino);
        if (retval)
                goto cleanup;
 
index fb266d1..12bfc0f 100644 (file)
@@ -33,6 +33,7 @@
 
 errcode_t ext2fs_mmp_read(ext2_filsys fs, blk64_t mmp_blk, void *buf)
 {
+#ifdef CONFIG_MMP
        struct mmp_struct *mmp_cmp;
        errcode_t retval = 0;
 
@@ -75,6 +76,11 @@ errcode_t ext2fs_mmp_read(ext2_filsys fs, blk64_t mmp_blk, void *buf)
        }
 
        mmp_cmp = fs->mmp_cmp;
+
+       if (!(fs->flags & EXT2_FLAG_IGNORE_CSUM_ERRORS) &&
+           !ext2fs_mmp_csum_verify(fs, mmp_cmp))
+               retval = EXT2_ET_MMP_CSUM_INVALID;
+
 #ifdef WORDS_BIGENDIAN
        ext2fs_swap_mmp(mmp_cmp);
 #endif
@@ -89,10 +95,14 @@ errcode_t ext2fs_mmp_read(ext2_filsys fs, blk64_t mmp_blk, void *buf)
 
 out:
        return retval;
+#else
+       return EXT2_ET_OP_NOT_SUPPORTED;
+#endif
 }
 
 errcode_t ext2fs_mmp_write(ext2_filsys fs, blk64_t mmp_blk, void *buf)
 {
+#ifdef CONFIG_MMP
        struct mmp_struct *mmp_s = buf;
        struct timeval tv;
        errcode_t retval = 0;
@@ -109,6 +119,10 @@ errcode_t ext2fs_mmp_write(ext2_filsys fs, blk64_t mmp_blk, void *buf)
        ext2fs_swap_mmp(mmp_s);
 #endif
 
+       retval = ext2fs_mmp_csum_set(fs, mmp_s);
+       if (retval)
+               return retval;
+
        /* I was tempted to make this use O_DIRECT and the mmp_fd, but
         * this caused no end of grief, while leaving it as-is works. */
        retval = io_channel_write_blk64(fs->io, mmp_blk, -(int)sizeof(struct mmp_struct), buf);
@@ -120,6 +134,9 @@ errcode_t ext2fs_mmp_write(ext2_filsys fs, blk64_t mmp_blk, void *buf)
        /* Make sure the block gets to disk quickly */
        io_channel_flush(fs->io);
        return retval;
+#else
+       return EXT2_ET_OP_NOT_SUPPORTED;
+#endif
 }
 
 #ifdef HAVE_SRANDOM
@@ -129,6 +146,7 @@ errcode_t ext2fs_mmp_write(ext2_filsys fs, blk64_t mmp_blk, void *buf)
 
 unsigned ext2fs_mmp_new_seq()
 {
+#ifdef CONFIG_MMP
        unsigned new_seq;
        struct timeval tv;
 
@@ -145,6 +163,9 @@ unsigned ext2fs_mmp_new_seq()
        } while (new_seq > EXT4_MMP_SEQ_MAX);
 
        return new_seq;
+#else
+       return EXT2_ET_OP_NOT_SUPPORTED;
+#endif
 }
 
 static errcode_t ext2fs_mmp_reset(ext2_filsys fs)
@@ -181,8 +202,14 @@ out:
        return retval;
 }
 
+errcode_t ext2fs_mmp_update(ext2_filsys fs)
+{
+       return ext2fs_mmp_update2(fs, 0);
+}
+
 errcode_t ext2fs_mmp_clear(ext2_filsys fs)
 {
+#ifdef CONFIG_MMP
        errcode_t retval = 0;
 
        if (!(fs->flags & EXT2_FLAG_RW))
@@ -191,10 +218,14 @@ errcode_t ext2fs_mmp_clear(ext2_filsys fs)
        retval = ext2fs_mmp_reset(fs);
 
        return retval;
+#else
+       return EXT2_ET_OP_NOT_SUPPORTED;
+#endif
 }
 
 errcode_t ext2fs_mmp_init(ext2_filsys fs)
 {
+#ifdef CONFIG_MMP
        struct ext2_super_block *sb = fs->super;
        blk64_t mmp_block;
        errcode_t retval;
@@ -223,6 +254,9 @@ errcode_t ext2fs_mmp_init(ext2_filsys fs)
 
 out:
        return retval;
+#else
+       return EXT2_ET_OP_NOT_SUPPORTED;
+#endif
 }
 
 /*
@@ -230,6 +264,7 @@ out:
  */
 errcode_t ext2fs_mmp_start(ext2_filsys fs)
 {
+#ifdef CONFIG_MMP
        struct mmp_struct *mmp_s;
        unsigned seq;
        unsigned int mmp_check_interval;
@@ -319,6 +354,9 @@ clean_seq:
 
 mmp_error:
        return retval;
+#else
+       return EXT2_ET_OP_NOT_SUPPORTED;
+#endif
 }
 
 /*
@@ -329,6 +367,7 @@ mmp_error:
  */
 errcode_t ext2fs_mmp_stop(ext2_filsys fs)
 {
+#ifdef CONFIG_MMP
        struct mmp_struct *mmp, *mmp_cmp;
        errcode_t retval = 0;
 
@@ -358,6 +397,9 @@ mmp_error:
        }
 
        return retval;
+#else
+       return EXT2_ET_OP_NOT_SUPPORTED;
+#endif
 }
 
 #define EXT2_MIN_MMP_UPDATE_INTERVAL 60
@@ -365,8 +407,9 @@ mmp_error:
 /*
  * Update the on-disk mmp buffer, after checking that it hasn't been changed.
  */
-errcode_t ext2fs_mmp_update(ext2_filsys fs)
+errcode_t ext2fs_mmp_update2(ext2_filsys fs, int immediately)
 {
+#ifdef CONFIG_MMP
        struct mmp_struct *mmp, *mmp_cmp;
        struct timeval tv;
        errcode_t retval = 0;
@@ -376,7 +419,8 @@ errcode_t ext2fs_mmp_update(ext2_filsys fs)
                return 0;
 
        gettimeofday(&tv, 0);
-       if (tv.tv_sec - fs->mmp_last_written < EXT2_MIN_MMP_UPDATE_INTERVAL)
+       if (!immediately &&
+           tv.tv_sec - fs->mmp_last_written < EXT2_MIN_MMP_UPDATE_INTERVAL)
                return 0;
 
        retval = ext2fs_mmp_read(fs, fs->super->s_mmp_block, NULL);
@@ -395,4 +439,7 @@ errcode_t ext2fs_mmp_update(ext2_filsys fs)
 
 mmp_error:
        return retval;
+#else
+       return EXT2_ET_OP_NOT_SUPPORTED;
+#endif
 }
index b0a1e47..d134bdf 100644 (file)
@@ -34,6 +34,8 @@ errcode_t ext2fs_new_dir_block(ext2_filsys fs, ext2_ino_t dir_ino,
        char                    *buf;
        int                     rec_len;
        int                     filetype = 0;
+       struct ext2_dir_entry_tail      *t;
+       int                     csum_size = 0;
 
        EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
 
@@ -43,21 +45,26 @@ errcode_t ext2fs_new_dir_block(ext2_filsys fs, ext2_ino_t dir_ino,
        memset(buf, 0, fs->blocksize);
        dir = (struct ext2_dir_entry *) buf;
 
-       retval = ext2fs_set_rec_len(fs, fs->blocksize, dir);
+       if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+                                      EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
+               csum_size = sizeof(struct ext2_dir_entry_tail);
+
+       retval = ext2fs_set_rec_len(fs, fs->blocksize - csum_size, dir);
        if (retval)
                return retval;
 
        if (dir_ino) {
                if (fs->super->s_feature_incompat &
                    EXT2_FEATURE_INCOMPAT_FILETYPE)
-                       filetype = EXT2_FT_DIR << 8;
+                       filetype = EXT2_FT_DIR;
                /*
                 * Set up entry for '.'
                 */
                dir->inode = dir_ino;
-               dir->name_len = 1 | filetype;
+               ext2fs_dirent_set_name_len(dir, 1);
+               ext2fs_dirent_set_file_type(dir, filetype);
                dir->name[0] = '.';
-               rec_len = fs->blocksize - EXT2_DIR_REC_LEN(1);
+               rec_len = (fs->blocksize - csum_size) - EXT2_DIR_REC_LEN(1);
                dir->rec_len = EXT2_DIR_REC_LEN(1);
 
                /*
@@ -68,11 +75,17 @@ errcode_t ext2fs_new_dir_block(ext2_filsys fs, ext2_ino_t dir_ino,
                if (retval)
                        return retval;
                dir->inode = parent_ino;
-               dir->name_len = 2 | filetype;
+               ext2fs_dirent_set_name_len(dir, 2);
+               ext2fs_dirent_set_file_type(dir, filetype);
                dir->name[0] = '.';
                dir->name[1] = '.';
 
        }
+
+       if (csum_size) {
+               t = EXT2_DIRENT_TAIL(buf, fs->blocksize);
+               ext2fs_initialize_dirent_tail(fs, t);
+       }
        *block = buf;
        return 0;
 }
index 4cdbde1..b2a8abb 100644 (file)
@@ -196,6 +196,16 @@ errcode_t ext2fs_open2(const char *name, const char *io_options,
        if (fs->orig_super)
                memcpy(fs->orig_super, fs->super, SUPERBLOCK_SIZE);
 
+       if (!(fs->flags & EXT2_FLAG_IGNORE_CSUM_ERRORS)) {
+               retval = 0;
+               if (!ext2fs_verify_csum_type(fs, fs->super))
+                       retval = EXT2_ET_UNKNOWN_CSUM;
+               if (!ext2fs_superblock_csum_verify(fs, fs->super))
+                       retval = EXT2_ET_SB_CSUM_INVALID;
+               if (retval)
+                       goto cleanup;
+       }
+
 #ifdef WORDS_BIGENDIAN
        fs->flags |= EXT2_FLAG_SWAP_BYTES;
        ext2fs_swap_super(fs->super);
@@ -276,6 +286,21 @@ errcode_t ext2fs_open2(const char *name, const char *io_options,
                retval = EXT2_ET_CORRUPT_SUPERBLOCK;
                goto cleanup;
        }
+
+       /* Enforce the block group descriptor size */
+       if (fs->super->s_feature_incompat & EXT4_FEATURE_INCOMPAT_64BIT) {
+               if (fs->super->s_desc_size != EXT2_MIN_DESC_SIZE_64BIT) {
+                       retval = EXT2_ET_BAD_DESC_SIZE;
+                       goto cleanup;
+               }
+       } else {
+               if (fs->super->s_desc_size &&
+                   fs->super->s_desc_size != EXT2_MIN_DESC_SIZE) {
+                       retval = EXT2_ET_BAD_DESC_SIZE;
+                       goto cleanup;
+               }
+       }
+
        fs->cluster_ratio_bits = fs->super->s_log_cluster_size -
                fs->super->s_log_block_size;
        if (EXT2_BLOCKS_PER_GROUP(fs->super) !=
@@ -313,6 +338,8 @@ errcode_t ext2fs_open2(const char *name, const char *io_options,
                retval = EXT2_ET_CORRUPT_SUPERBLOCK;
                goto cleanup;
        }
+       /* Precompute the FS UUID to seed other checksums */
+       ext2fs_init_csum_seed(fs);
 
        /*
         * Read group descriptors
@@ -387,8 +414,7 @@ errcode_t ext2fs_open2(const char *name, const char *io_options,
         * If recovery is from backup superblock, Clear _UNININT flags &
         * reset bg_itable_unused to zero
         */
-       if (superblock > 1 && EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
-                                       EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) {
+       if (superblock > 1 && ext2fs_has_group_desc_csum(fs)) {
                dgrp_t group;
 
                for (group = 0; group < fs->group_desc_count; group++) {
index 8c9a6f1..83556b1 100644 (file)
 static char spaces[80], backspaces[80];
 static time_t last_update;
 
+struct ext2fs_progress_ops ext2fs_numeric_progress_ops = {
+       .init           = ext2fs_numeric_progress_init,
+       .update         = ext2fs_numeric_progress_update,
+       .close          = ext2fs_numeric_progress_close,
+};
+
 static int int_log10(unsigned int arg)
 {
        int     l;
index b7d65a9..386cbeb 100644 (file)
@@ -36,7 +36,7 @@ static errcode_t write_bitmaps(ext2_filsys fs, int do_inode, int do_block)
        unsigned int    nbits;
        errcode_t       retval;
        char            *block_buf = NULL, *inode_buf = NULL;
-       int             csum_flag = 0;
+       int             csum_flag;
        blk64_t         blk;
        blk64_t         blk_itr = EXT2FS_B2C(fs, fs->super->s_first_data_block);
        ext2_ino_t      ino_itr = 1;
@@ -46,9 +46,7 @@ static errcode_t write_bitmaps(ext2_filsys fs, int do_inode, int do_block)
        if (!(fs->flags & EXT2_FLAG_RW))
                return EXT2_ET_RO_FILSYS;
 
-       if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
-                                      EXT4_FEATURE_RO_COMPAT_GDT_CSUM))
-               csum_flag = 1;
+       csum_flag = ext2fs_has_group_desc_csum(fs);
 
        inode_nbytes = block_nbytes = 0;
        if (do_block) {
@@ -90,6 +88,13 @@ static errcode_t write_bitmaps(ext2_filsys fs, int do_inode, int do_block)
                                for (j = nbits; j < fs->blocksize * 8; j++)
                                        ext2fs_set_bit(j, block_buf);
                }
+
+               retval = ext2fs_block_bitmap_csum_set(fs, i, block_buf,
+                                                     block_nbytes);
+               if (retval)
+                       return retval;
+               ext2fs_group_desc_csum_set(fs, i);
+
                blk = ext2fs_block_bitmap_loc(fs, i);
                if (blk) {
                        retval = io_channel_write_blk64(fs->io, blk, 1,
@@ -115,6 +120,12 @@ static errcode_t write_bitmaps(ext2_filsys fs, int do_inode, int do_block)
                if (retval)
                        goto errout;
 
+               retval = ext2fs_inode_bitmap_csum_set(fs, i, inode_buf,
+                                                     inode_nbytes);
+               if (retval)
+                       goto errout;
+               ext2fs_group_desc_csum_set(fs, i);
+
                blk = ext2fs_inode_bitmap_loc(fs, i);
                if (blk) {
                        retval = io_channel_write_blk64(fs->io, blk, 1,
@@ -153,7 +164,7 @@ static errcode_t read_bitmaps(ext2_filsys fs, int do_inode, int do_block)
        errcode_t retval;
        int block_nbytes = EXT2_CLUSTERS_PER_GROUP(fs->super) / 8;
        int inode_nbytes = EXT2_INODES_PER_GROUP(fs->super) / 8;
-       int csum_flag = 0;
+       int csum_flag;
        unsigned int    cnt;
        blk64_t blk;
        blk64_t blk_itr = EXT2FS_B2C(fs, fs->super->s_first_data_block);
@@ -169,9 +180,7 @@ static errcode_t read_bitmaps(ext2_filsys fs, int do_inode, int do_block)
 
        fs->write_bitmaps = ext2fs_write_bitmaps;
 
-       if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
-                                      EXT4_FEATURE_RO_COMPAT_GDT_CSUM))
-               csum_flag = 1;
+       csum_flag = ext2fs_has_group_desc_csum(fs);
 
        retval = ext2fs_get_mem(strlen(fs->device_name) + 80, &buf);
        if (retval)
@@ -260,6 +269,15 @@ static errcode_t read_bitmaps(ext2_filsys fs, int do_inode, int do_block)
                                        retval = EXT2_ET_BLOCK_BITMAP_READ;
                                        goto cleanup;
                                }
+                               /* verify block bitmap checksum */
+                               if (!(fs->flags &
+                                     EXT2_FLAG_IGNORE_CSUM_ERRORS) &&
+                                   !ext2fs_block_bitmap_csum_verify(fs, i,
+                                               block_bitmap, block_nbytes)) {
+                                       retval =
+                                       EXT2_ET_BLOCK_BITMAP_CSUM_INVALID;
+                                       goto cleanup;
+                               }
                        } else
                                memset(block_bitmap, 0, block_nbytes);
                        cnt = block_nbytes << 3;
@@ -282,6 +300,16 @@ static errcode_t read_bitmaps(ext2_filsys fs, int do_inode, int do_block)
                                        retval = EXT2_ET_INODE_BITMAP_READ;
                                        goto cleanup;
                                }
+
+                               /* verify inode bitmap checksum */
+                               if (!(fs->flags &
+                                     EXT2_FLAG_IGNORE_CSUM_ERRORS) &&
+                                   !ext2fs_inode_bitmap_csum_verify(fs, i,
+                                               inode_bitmap, inode_nbytes)) {
+                                       retval =
+                                       EXT2_ET_INODE_BITMAP_CSUM_INVALID;
+                                       goto cleanup;
+                               }
                        } else
                                memset(inode_bitmap, 0, inode_nbytes);
                        cnt = inode_nbytes << 3;
index 7c99373..1295e81 100644 (file)
@@ -157,7 +157,8 @@ void ext2fs_swap_ext_attr_header(struct ext2_ext_attr_header *to_header,
        to_header->h_blocks   = ext2fs_swab32(from_header->h_blocks);
        to_header->h_refcount = ext2fs_swab32(from_header->h_refcount);
        to_header->h_hash     = ext2fs_swab32(from_header->h_hash);
-       for (n = 0; n < 4; n++)
+       to_header->h_checksum = ext2fs_swab32(from_header->h_checksum);
+       for (n = 0; n < 3; n++)
                to_header->h_reserved[n] =
                        ext2fs_swab32(from_header->h_reserved[n]);
 }
@@ -348,6 +349,69 @@ void ext2fs_swap_mmp(struct mmp_struct *mmp)
        mmp->mmp_seq = ext2fs_swab32(mmp->mmp_seq);
        mmp->mmp_time = ext2fs_swab64(mmp->mmp_time);
        mmp->mmp_check_interval = ext2fs_swab16(mmp->mmp_check_interval);
+       mmp->mmp_checksum = ext2fs_swab32(mmp->mmp_checksum);
+}
+
+errcode_t ext2fs_dirent_swab_in(ext2_filsys fs, char *buf, int flags)
+{
+       errcode_t       retval;
+       char            *p, *end;
+       struct ext2_dir_entry *dirent;
+       unsigned int    name_len, rec_len;
+
+       p = (char *) buf;
+       end = (char *) buf + fs->blocksize;
+       while (p < end-8) {
+               dirent = (struct ext2_dir_entry *) p;
+               dirent->inode = ext2fs_swab32(dirent->inode);
+               dirent->rec_len = ext2fs_swab16(dirent->rec_len);
+               dirent->name_len = ext2fs_swab16(dirent->name_len);
+               name_len = dirent->name_len;
+               if (flags & EXT2_DIRBLOCK_V2_STRUCT)
+                       dirent->name_len = ext2fs_swab16(dirent->name_len);
+               retval = ext2fs_get_rec_len(fs, dirent, &rec_len);
+               if (retval)
+                       return retval;
+               if ((rec_len < 8) || (rec_len % 4)) {
+                       rec_len = 8;
+                       retval = EXT2_ET_DIR_CORRUPTED;
+               } else if (((name_len & 0xFF) + 8) > rec_len)
+                       retval = EXT2_ET_DIR_CORRUPTED;
+               p += rec_len;
+       }
+
+       return 0;
+}
+
+errcode_t ext2fs_dirent_swab_out(ext2_filsys fs, char *buf, int flags)
+{
+       errcode_t       retval;
+       char            *p, *end;
+       unsigned int    rec_len;
+       struct ext2_dir_entry *dirent;
+
+       p = buf;
+       end = buf + fs->blocksize;
+       while (p < end) {
+               dirent = (struct ext2_dir_entry *) p;
+               retval = ext2fs_get_rec_len(fs, dirent, &rec_len);
+               if (retval)
+                       return retval;
+               if ((rec_len < 8) ||
+                   (rec_len % 4)) {
+                       ext2fs_free_mem(&buf);
+                       return EXT2_ET_DIR_CORRUPTED;
+               }
+               p += rec_len;
+               dirent->inode = ext2fs_swab32(dirent->inode);
+               dirent->rec_len = ext2fs_swab16(dirent->rec_len);
+               dirent->name_len = ext2fs_swab16(dirent->name_len);
+
+               if (flags & EXT2_DIRBLOCK_V2_STRUCT)
+                       dirent->name_len = ext2fs_swab16(dirent->name_len);
+       }
+
+       return 0;
 }
 
 #endif
index 85d87e1..50644b3 100644 (file)
@@ -113,7 +113,7 @@ int main(int argc, char **argv)
        check_field(s_mmp_block, 8);
        check_field(s_raid_stripe_width, 4);
        check_field(s_log_groups_per_flex, 1);
-       check_field(s_reserved_char_pad, 1);
+       check_field(s_checksum_type, 1);
        check_field(s_reserved_pad, 2);
        check_field(s_kbytes_written, 8);
        check_field(s_snapshot_inum, 4);
index d2d31cc..8ab27ee 100644 (file)
@@ -44,9 +44,9 @@ static int unlink_proc(struct ext2_dir_entry *dirent,
        ls->prev = dirent;
 
        if (ls->name) {
-               if ((dirent->name_len & 0xFF) != ls->namelen)
+               if (ext2fs_dirent_name_len(dirent) != ls->namelen)
                        return 0;
-               if (strncmp(ls->name, dirent->name, dirent->name_len & 0xFF))
+               if (strncmp(ls->name, dirent->name, ext2fs_dirent_name_len(dirent)))
                        return 0;
        }
        if (ls->inode) {
index 2464100..8be7ce2 100644 (file)
@@ -121,7 +121,7 @@ static void print_bg_opts(ext2_filsys fs, dgrp_t i)
 {
        int first = 1, bg_flags = 0;
 
-       if (fs->super->s_feature_ro_compat & EXT4_FEATURE_RO_COMPAT_GDT_CSUM)
+       if (ext2fs_has_group_desc_csum(fs))
                bg_flags = ext2fs_bg_flags(fs, i);
 
        print_bg_opt(bg_flags, EXT2_BG_INODE_UNINIT, "INODE_UNINIT",
@@ -197,7 +197,7 @@ static void list_desc (ext2_filsys fs)
                print_range(first_block, last_block);
                fputs(")", stdout);
                print_bg_opts(fs, i);
-               if (fs->super->s_feature_ro_compat & EXT4_FEATURE_RO_COMPAT_GDT_CSUM) {
+               if (ext2fs_has_group_desc_csum(fs)) {
                        unsigned csum = ext2fs_bg_checksum(fs, i);
                        unsigned exp_csum = ext2fs_group_desc_csum(fs, i);
 
@@ -235,10 +235,18 @@ static void list_desc (ext2_filsys fs)
                print_number(ext2fs_block_bitmap_loc(fs, i));
                print_bg_rel_offset(fs, ext2fs_block_bitmap_loc(fs, i), 0,
                                    first_block, last_block);
+               if (fs->super->s_feature_ro_compat &
+                   EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)
+                       printf(_(", csum 0x%08x"),
+                              ext2fs_block_bitmap_checksum(fs, i));
                fputs(_(", Inode bitmap at "), stdout);
                print_number(ext2fs_inode_bitmap_loc(fs, i));
                print_bg_rel_offset(fs, ext2fs_inode_bitmap_loc(fs, i), 0,
                                    first_block, last_block);
+               if (fs->super->s_feature_ro_compat &
+                   EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)
+                       printf(_(", csum 0x%08x"),
+                              ext2fs_inode_bitmap_checksum(fs, i));
                fputs(_("\n  Inode table at "), stdout);
                print_range(ext2fs_inode_table_loc(fs, i),
                            ext2fs_inode_table_loc(fs, i) +
@@ -316,6 +324,16 @@ static void list_bad_blocks(ext2_filsys fs, int dump)
        ext2fs_badblocks_list_free(bb_list);
 }
 
+static const char *journal_checksum_type_str(__u8 type)
+{
+       switch (type) {
+       case JBD2_CRC32C_CHKSUM:
+               return "crc32c";
+       default:
+               return "unknown";
+       }
+}
+
 static void print_inline_journal_information(ext2_filsys fs)
 {
        journal_superblock_t    *jsb;
@@ -382,6 +400,15 @@ static void print_inline_journal_information(ext2_filsys fs)
               (unsigned int)ntohl(jsb->s_maxlen),
               (unsigned int)ntohl(jsb->s_sequence),
               (unsigned int)ntohl(jsb->s_start));
+       if (jsb->s_feature_compat &
+           ext2fs_cpu_to_be32(JFS_FEATURE_COMPAT_CHECKSUM))
+               printf(_("Journal checksum type:    crc32\n"));
+       if (jsb->s_feature_incompat &
+           ext2fs_cpu_to_be32(JFS_FEATURE_INCOMPAT_CSUM_V2))
+               printf(_("Journal checksum type:    %s\n"
+                        "Journal checksum:         0x%08x\n"),
+                      journal_checksum_type_str(jsb->s_checksum_type),
+                      ext2fs_be32_to_cpu(jsb->s_checksum));
        if (jsb->s_errno != 0)
                printf(_("Journal errno:            %d\n"),
                       (int) ntohl(jsb->s_errno));
@@ -410,6 +437,16 @@ static void print_journal_information(ext2_filsys fs)
                exit(1);
        }
 
+       if (jsb->s_feature_compat &
+           ext2fs_cpu_to_be32(JFS_FEATURE_COMPAT_CHECKSUM))
+               printf(_("Journal checksum type:    crc32\n"));
+       if (jsb->s_feature_incompat &
+           ext2fs_cpu_to_be32(JFS_FEATURE_INCOMPAT_CSUM_V2))
+               printf(_("Journal checksum type:    %s\n"
+                        "Journal checksum:         0x%08x\n"),
+                      journal_checksum_type_str(jsb->s_checksum_type),
+                      ext2fs_be32_to_cpu(jsb->s_checksum));
+
        printf(_("\nJournal block size:       %u\n"
                 "Journal length:           %u\n"
                 "Journal first block:      %u\n"
index 64d923a..67c9225 100644 (file)
@@ -308,6 +308,27 @@ _("Warning: the backup superblock/group descriptors at block %u contain\n"
        ext2fs_badblocks_list_iterate_end(bb_iter);
 }
 
+static void write_reserved_inodes(ext2_filsys fs)
+{
+       errcode_t       retval;
+       ext2_ino_t      ino;
+       struct ext2_inode *inode;
+
+       retval = ext2fs_get_mem(EXT2_INODE_SIZE(fs->super), &inode);
+       if (retval) {
+               com_err("inode_init", retval,
+                       "while allocating memory");
+               exit(1);
+       }
+       bzero(inode, EXT2_INODE_SIZE(fs->super));
+
+       for (ino = 1; ino < EXT2_FIRST_INO(fs->super); ino++)
+               ext2fs_write_inode_full(fs, ino, inode,
+                                       EXT2_INODE_SIZE(fs->super));
+
+       ext2fs_free_mem(&inode);
+}
+
 static void write_inode_tables(ext2_filsys fs, int lazy_flag, int itable_zeroed)
 {
        errcode_t       retval;
@@ -353,6 +374,12 @@ static void write_inode_tables(ext2_filsys fs, int lazy_flag, int itable_zeroed)
        ext2fs_zero_blocks2(0, 0, 0, 0, 0);
        ext2fs_numeric_progress_close(fs, &progress,
                                      _("done                            \n"));
+
+       /* Reserved inodes must always have correct checksums */
+       if (fs->super->s_creator_os == EXT2_OS_LINUX &&
+           fs->super->s_feature_ro_compat &
+           EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)
+               write_reserved_inodes(fs);
 }
 
 static void create_root_dir(ext2_filsys fs)
@@ -630,6 +657,23 @@ static void show_stats(ext2_filsys fs)
 }
 
 /*
+ * Returns true if making a file system for the Hurd, else 0
+ */
+static int for_hurd(const char *os)
+{
+       if (!os) {
+#ifdef __GNU__
+               return 1;
+#else
+               return 0;
+#endif
+       }
+       if (isdigit(*os))
+               return (atoi(os) == EXT2_OS_HURD);
+       return (strcasecmp(os, "GNU") == 0 || strcasecmp(os, "hurd") == 0);
+}
+
+/*
  * Set the S_CREATOR_OS field.  Return true if OS is known,
  * otherwise, 0.
  */
@@ -897,7 +941,7 @@ static __u32 ok_features[3] = {
 #ifdef CONFIG_QUOTA
                EXT4_FEATURE_RO_COMPAT_QUOTA|
 #endif
-               0
+               EXT4_FEATURE_RO_COMPAT_METADATA_CSUM
 };
 
 
@@ -1026,15 +1070,11 @@ static char **parse_fs_type(const char *fs_type,
        const char      *size_type;
        struct str_list list;
        unsigned long long meg;
-       int             is_hurd = 0;
+       int             is_hurd = for_hurd(creator_os);
 
        if (init_list(&list))
                return 0;
 
-       if (creator_os && (!strcasecmp(creator_os, "GNU") ||
-                          !strcasecmp(creator_os, "hurd")))
-               is_hurd = 1;
-
        if (fs_type)
                ext_type = fs_type;
        else if (is_hurd)
@@ -1705,10 +1745,40 @@ profile_error:
                tmp = get_string_from_profile(fs_types, "default_features",
                                              "");
        }
+       /* Mask off features which aren't supported by the Hurd */
+       if (for_hurd(creator_os)) {
+               fs_param.s_feature_incompat &= ~EXT2_FEATURE_INCOMPAT_FILETYPE;
+               fs_param.s_feature_ro_compat &=
+                       ~(EXT4_FEATURE_RO_COMPAT_HUGE_FILE |
+                         EXT4_FEATURE_RO_COMPAT_METADATA_CSUM);
+       }
        edit_feature(fs_features ? fs_features : tmp,
                     &fs_param.s_feature_compat);
        if (tmp)
                free(tmp);
+       /*
+        * If the user specified features incompatible with the Hurd, complain
+        */
+       if (for_hurd(creator_os)) {
+               if (fs_param.s_feature_incompat &
+                   EXT2_FEATURE_INCOMPAT_FILETYPE) {
+                       fprintf(stderr, _("The HURD does not support the "
+                                         "filetype feature.\n"));
+                       exit(1);
+               }
+               if (fs_param.s_feature_ro_compat &
+                   EXT4_FEATURE_RO_COMPAT_HUGE_FILE) {
+                       fprintf(stderr, _("The HURD does not support the "
+                                         "huge_file feature.\n"));
+                       exit(1);
+               }
+               if (fs_param.s_feature_ro_compat &
+                   EXT4_FEATURE_RO_COMPAT_METADATA_CSUM) {
+                       fprintf(stderr, _("The HURD does not support the "
+                                         "metadata_csum feature.\n"));
+                       exit(1);
+               }
+       }
 
        /*
         * We now need to do a sanity check of fs_blocks_count for
@@ -1960,6 +2030,13 @@ profile_error:
        if (extended_opts)
                parse_extended_opts(&fs_param, extended_opts);
 
+       /* Don't allow user to set both metadata_csum and uninit_bg bits. */
+       if ((fs_param.s_feature_ro_compat &
+            EXT4_FEATURE_RO_COMPAT_METADATA_CSUM) &&
+           (fs_param.s_feature_ro_compat & EXT4_FEATURE_RO_COMPAT_GDT_CSUM))
+               fs_param.s_feature_ro_compat &=
+                               ~EXT4_FEATURE_RO_COMPAT_GDT_CSUM;
+
        /* Can't support bigalloc feature without extents feature */
        if ((fs_param.s_feature_ro_compat & EXT4_FEATURE_RO_COMPAT_BIGALLOC) &&
            !(fs_param.s_feature_incompat & EXT3_FEATURE_INCOMPAT_EXTENTS)) {
@@ -2113,7 +2190,8 @@ static int should_do_undo(const char *name)
        int csum_flag, force_undo;
 
        csum_flag = EXT2_HAS_RO_COMPAT_FEATURE(&fs_param,
-                                              EXT4_FEATURE_RO_COMPAT_GDT_CSUM);
+                               EXT4_FEATURE_RO_COMPAT_GDT_CSUM |
+                               EXT4_FEATURE_RO_COMPAT_METADATA_CSUM);
        force_undo = get_int_from_profile(fs_types, "force_undo", 0);
        if (!force_undo && (!csum_flag || !lazy_itable_init))
                return 0;
@@ -2368,6 +2446,26 @@ int main (int argc, char *argv[])
                com_err(device_name, retval, _("while setting up superblock"));
                exit(1);
        }
+       fs->progress_ops = &ext2fs_numeric_progress_ops;
+
+       /* Check the user's mkfs options for metadata checksumming */
+       if (!quiet &&
+           EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+                                      EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) {
+               if (!EXT2_HAS_INCOMPAT_FEATURE(fs->super,
+                               EXT3_FEATURE_INCOMPAT_EXTENTS))
+                       printf(_("Extents are not enabled.  The file extent "
+                                "tree can be checksummed, whereas block maps "
+                                "cannot.  Not enabling extents reduces the "
+                                "coverage of metadata checksumming.  "
+                                "Pass -O extents to rectify.\n"));
+               if (!EXT2_HAS_INCOMPAT_FEATURE(fs->super,
+                               EXT4_FEATURE_INCOMPAT_64BIT))
+                       printf(_("64-bit filesystem support is not "
+                                "enabled.  The larger fields afforded by "
+                                "this feature enable full-strength "
+                                "checksumming.  Pass -O 64bit to rectify.\n"));
+       }
 
        /* Calculate journal blocks */
        if (!journal_device && ((journal_size) ||
@@ -2399,6 +2497,7 @@ int main (int argc, char *argv[])
            (fs_param.s_feature_ro_compat &
             (EXT4_FEATURE_RO_COMPAT_HUGE_FILE|EXT4_FEATURE_RO_COMPAT_GDT_CSUM|
              EXT4_FEATURE_RO_COMPAT_DIR_NLINK|
+             EXT4_FEATURE_RO_COMPAT_METADATA_CSUM|
              EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE)))
                fs->super->s_kbytes_written = 1;
 
@@ -2419,6 +2518,7 @@ int main (int argc, char *argv[])
                }
        } else
                uuid_generate(fs->super->s_uuid);
+       ext2fs_init_csum_seed(fs);
 
        /*
         * Initialize the directory index variables
@@ -2495,6 +2595,10 @@ int main (int argc, char *argv[])
                        sizeof(fs->super->s_last_mounted));
        }
 
+       if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+                                      EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
+               fs->super->s_checksum_type = EXT2_CRC32C_CHKSUM;
+
        if (!quiet || noaction)
                show_stats(fs);
 
@@ -2541,8 +2645,7 @@ int main (int argc, char *argv[])
                 * inodes as unused; we want e2fsck to consider all
                 * inodes as potentially containing recoverable data.
                 */
-               if (fs->super->s_feature_ro_compat &
-                   EXT4_FEATURE_RO_COMPAT_GDT_CSUM) {
+               if (ext2fs_has_group_desc_csum(fs)) {
                        for (i = 0; i < fs->group_desc_count; i++)
                                ext2fs_bg_itable_unused_set(fs, i, 0);
                }
index 0871f77..178733f 100644 (file)
@@ -16,7 +16,7 @@
                inode_size = 256
        }
        ext4dev = {
-               features = has_journal,extent,huge_file,flex_bg,uninit_bg,dir_nlink,extra_isize
+               features = has_journal,extent,huge_file,flex_bg,metadata_csum,64bit,dir_nlink,extra_isize
                inode_size = 256
                options = test_fs=1
        }
index 822df74..1ae0ee6 100644 (file)
@@ -91,6 +91,7 @@ static char *extended_cmd;
 static unsigned long new_inode_size;
 static char *ext_mount_opts;
 static int usrquota, grpquota;
+static int rewrite_checksums;
 
 int journal_size, journal_flags;
 char *journal_device;
@@ -105,6 +106,8 @@ struct blk_move {
 
 
 static const char *please_fsck = N_("Please run e2fsck on the filesystem.\n");
+static const char *please_dir_fsck =
+               N_("Please run e2fsck -D on the filesystem.\n");
 
 #ifdef CONFIG_BUILD_FINDFS
 void do_findfs(int argc, char **argv);
@@ -144,10 +147,11 @@ static __u32 ok_features[3] = {
                EXT4_FEATURE_RO_COMPAT_DIR_NLINK|
                EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE|
                EXT4_FEATURE_RO_COMPAT_GDT_CSUM |
+               EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER |
 #ifdef CONFIG_QUOTA
                EXT4_FEATURE_RO_COMPAT_QUOTA |
 #endif
-               EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER
+               EXT4_FEATURE_RO_COMPAT_METADATA_CSUM
 };
 
 static __u32 clear_ok_features[3] = {
@@ -164,10 +168,11 @@ static __u32 clear_ok_features[3] = {
                EXT4_FEATURE_RO_COMPAT_HUGE_FILE|
                EXT4_FEATURE_RO_COMPAT_DIR_NLINK|
                EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE|
+               EXT4_FEATURE_RO_COMPAT_GDT_CSUM |
 #ifdef CONFIG_QUOTA
                EXT4_FEATURE_RO_COMPAT_QUOTA |
 #endif
-               EXT4_FEATURE_RO_COMPAT_GDT_CSUM
+               EXT4_FEATURE_RO_COMPAT_METADATA_CSUM
 };
 
 /*
@@ -358,6 +363,28 @@ static int update_mntopts(ext2_filsys fs, char *mntopts)
        return 0;
 }
 
+static int check_fsck_needed(ext2_filsys fs)
+{
+       if (fs->super->s_state & EXT2_VALID_FS)
+               return 0;
+       printf("\n%s\n", _(please_fsck));
+       if (mount_flags & EXT2_MF_READONLY)
+               printf(_("(and reboot afterwards!)\n"));
+       return 1;
+}
+
+static void request_dir_fsck_afterwards(ext2_filsys fs)
+{
+       static int requested;
+
+       if (requested++)
+               return;
+       fs->super->s_state &= ~EXT2_VALID_FS;
+       printf("\n%s\n", _(please_dir_fsck));
+       if (mount_flags & EXT2_MF_READONLY)
+               printf(_("(and reboot afterwards!)\n"));
+}
+
 static void request_fsck_afterwards(ext2_filsys fs)
 {
        static int requested = 0;
@@ -370,15 +397,465 @@ static void request_fsck_afterwards(ext2_filsys fs)
                printf(_("(and reboot afterwards!)\n"));
 }
 
+/* Rewrite extents */
+static errcode_t rewrite_extents(ext2_filsys fs, ext2_ino_t ino,
+                                struct ext2_inode *inode)
+{
+       ext2_extent_handle_t    handle;
+       struct ext2fs_extent    extent;
+       int                     op = EXT2_EXTENT_ROOT;
+       errcode_t               errcode;
+
+       if (!(inode->i_flags & EXT4_EXTENTS_FL))
+               return 0;
+
+       errcode = ext2fs_extent_open(fs, ino, &handle);
+       if (errcode)
+               return errcode;
+
+       while (1) {
+               errcode = ext2fs_extent_get(handle, op, &extent);
+               if (errcode)
+                       break;
+
+               /* Root node is in the separately checksummed inode */
+               if (op == EXT2_EXTENT_ROOT) {
+                       op = EXT2_EXTENT_NEXT;
+                       continue;
+               }
+               op = EXT2_EXTENT_NEXT;
+
+               /* Only visit the first extent in each extent block */
+               if (extent.e_flags & EXT2_EXTENT_FLAGS_SECOND_VISIT)
+                       continue;
+               errcode = ext2fs_extent_replace(handle, 0, &extent);
+               if (errcode)
+                       break;
+       }
+
+       /* Ok if we run off the end */
+       if (errcode == EXT2_ET_EXTENT_NO_NEXT)
+               errcode = 0;
+       return errcode;
+}
+
+/*
+ * Rewrite directory blocks with checksums
+ */
+struct rewrite_dir_context {
+       char *buf;
+       errcode_t errcode;
+       ext2_ino_t dir;
+       int is_htree;
+};
+
+static int rewrite_dir_block(ext2_filsys fs,
+                            blk64_t    *blocknr,
+                            e2_blkcnt_t blockcnt EXT2FS_ATTR((unused)),
+                            blk64_t    ref_block EXT2FS_ATTR((unused)),
+                            int        ref_offset EXT2FS_ATTR((unused)),
+                            void       *priv_data)
+{
+       struct ext2_dx_countlimit *dcl = NULL;
+       struct rewrite_dir_context *ctx = priv_data;
+       int dcl_offset, changed = 0;
+
+       ctx->errcode = ext2fs_read_dir_block4(fs, *blocknr, ctx->buf, 0,
+                                             ctx->dir);
+       if (ctx->errcode)
+               return BLOCK_ABORT;
+
+       /* if htree node... */
+       if (ctx->is_htree)
+               ext2fs_get_dx_countlimit(fs, (struct ext2_dir_entry *)ctx->buf,
+                                        &dcl, &dcl_offset);
+       if (dcl) {
+               if (!EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+                               EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) {
+                       /* Ensure limit is the max size */
+                       int max_entries = (fs->blocksize - dcl_offset) /
+                                         sizeof(struct ext2_dx_entry);
+                       if (ext2fs_le16_to_cpu(dcl->limit) != max_entries) {
+                               changed = 1;
+                               dcl->limit = ext2fs_cpu_to_le16(max_entries);
+                       }
+               } else {
+                       /* If htree block is full then rebuild the dir */
+                       if (ext2fs_le16_to_cpu(dcl->count) ==
+                           ext2fs_le16_to_cpu(dcl->limit)) {
+                               request_dir_fsck_afterwards(fs);
+                               return 0;
+                       }
+                       /*
+                        * Ensure dcl->limit is small enough to leave room for
+                        * the checksum tail.
+                        */
+                       int max_entries = (fs->blocksize - (dcl_offset +
+                                               sizeof(struct ext2_dx_tail))) /
+                                         sizeof(struct ext2_dx_entry);
+                       if (ext2fs_le16_to_cpu(dcl->limit) != max_entries)
+                               dcl->limit = ext2fs_cpu_to_le16(max_entries);
+                       /* Always rewrite checksum */
+                       changed = 1;
+               }
+       } else {
+               unsigned int rec_len, name_size;
+               char *top = ctx->buf + fs->blocksize;
+               struct ext2_dir_entry *de = (struct ext2_dir_entry *)ctx->buf;
+               struct ext2_dir_entry *last_de = NULL, *penultimate_de = NULL;
+
+               /* Find last and penultimate dirent */
+               while ((char *)de < top) {
+                       penultimate_de = last_de;
+                       last_de = de;
+                       ctx->errcode = ext2fs_get_rec_len(fs, de, &rec_len);
+                       if (!ctx->errcode && !rec_len)
+                               ctx->errcode = EXT2_ET_DIR_CORRUPTED;
+                       if (ctx->errcode)
+                               return BLOCK_ABORT;
+                       de = (struct ext2_dir_entry *)(((char *)de) + rec_len);
+               }
+               ctx->errcode = ext2fs_get_rec_len(fs, last_de, &rec_len);
+               if (ctx->errcode)
+                       return BLOCK_ABORT;
+               name_size = ext2fs_dirent_name_len(last_de);
+
+               if (!EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+                               EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) {
+                       if (!penultimate_de)
+                               return 0;
+                       if (last_de->inode ||
+                           name_size ||
+                           rec_len != sizeof(struct ext2_dir_entry_tail))
+                               return 0;
+                       /*
+                        * The last dirent is unused and the right length to
+                        * have stored a checksum.  Erase it.
+                        */
+                       ctx->errcode = ext2fs_get_rec_len(fs, penultimate_de,
+                                                         &rec_len);
+                       if (!rec_len)
+                               ctx->errcode = EXT2_ET_DIR_CORRUPTED;
+                       if (ctx->errcode)
+                               return BLOCK_ABORT;
+                       ext2fs_set_rec_len(fs, rec_len +
+                                       sizeof(struct ext2_dir_entry_tail),
+                                       penultimate_de);
+                       changed = 1;
+               } else {
+                       unsigned csum_size = sizeof(struct ext2_dir_entry_tail);
+                       struct ext2_dir_entry_tail *t;
+
+                       /*
+                        * If the last dirent looks like the tail, just update
+                        * the checksum.
+                        */
+                       if (!last_de->inode &&
+                           rec_len == csum_size) {
+                               t = (struct ext2_dir_entry_tail *)last_de;
+                               t->det_reserved_name_len =
+                                               EXT2_DIR_NAME_LEN_CSUM;
+                               changed = 1;
+                               goto out;
+                       }
+                       if (name_size & 3)
+                               name_size = (name_size & ~3) + 4;
+                       /* If there's not enough space for the tail, e2fsck */
+                       if (rec_len <= (8 + name_size + csum_size)) {
+                               request_dir_fsck_afterwards(fs);
+                               return 0;
+                       }
+                       /* Shorten that last de and insert the tail */
+                       ext2fs_set_rec_len(fs, rec_len - csum_size, last_de);
+                       t = EXT2_DIRENT_TAIL(ctx->buf, fs->blocksize);
+                       ext2fs_initialize_dirent_tail(fs, t);
+
+                       /* Always update checksum */
+                       changed = 1;
+               }
+       }
+
+out:
+       if (!changed)
+               return 0;
+
+       ctx->errcode = ext2fs_write_dir_block4(fs, *blocknr, ctx->buf,
+                                              0, ctx->dir);
+       if (ctx->errcode)
+               return BLOCK_ABORT;
+
+       return 0;
+}
+
+static errcode_t rewrite_directory(ext2_filsys fs, ext2_ino_t dir,
+                                  struct ext2_inode *inode)
+{
+       errcode_t       retval;
+       struct rewrite_dir_context ctx;
+
+       retval = ext2fs_get_mem(fs->blocksize, &ctx.buf);
+       if (retval)
+               return retval;
+
+       ctx.is_htree = (inode->i_flags & EXT2_INDEX_FL);
+       ctx.dir = dir;
+       ctx.errcode = 0;
+       retval = ext2fs_block_iterate3(fs, dir, BLOCK_FLAG_READ_ONLY |
+                                               BLOCK_FLAG_DATA_ONLY,
+                                      0, rewrite_dir_block, &ctx);
+
+       ext2fs_free_mem(&ctx.buf);
+       if (retval)
+               return retval;
+
+       return ctx.errcode;
+}
+
+/*
+ * Forcibly set checksums in all inodes.
+ */
+static void rewrite_inodes(ext2_filsys fs)
+{
+       int length = EXT2_INODE_SIZE(fs->super);
+       struct ext2_inode *inode, *zero;
+       char            *ea_buf;
+       ext2_inode_scan scan;
+       errcode_t       retval;
+       ext2_ino_t      ino;
+       blk64_t         file_acl_block;
+       int             inode_dirty;
+
+       if (fs->super->s_creator_os != EXT2_OS_LINUX)
+               return;
+
+       retval = ext2fs_open_inode_scan(fs, 0, &scan);
+       if (retval) {
+               com_err("set_csum", retval, "while opening inode scan");
+               exit(1);
+       }
+
+       retval = ext2fs_get_mem(length, &inode);
+       if (retval) {
+               com_err("set_csum", retval, "while allocating memory");
+               exit(1);
+       }
+
+       retval = ext2fs_get_memzero(length, &zero);
+       if (retval) {
+               com_err("set_csum", retval, "while allocating memory");
+               exit(1);
+       }
+
+       retval = ext2fs_get_mem(fs->blocksize, &ea_buf);
+       if (retval) {
+               com_err("set_csum", retval, "while allocating memory");
+               exit(1);
+       }
+
+       do {
+               retval = ext2fs_get_next_inode_full(scan, &ino, inode, length);
+               if (retval) {
+                       com_err("set_csum", retval, "while getting next inode");
+                       exit(1);
+               }
+               if (!ino)
+                       break;
+               if (ext2fs_test_inode_bitmap2(fs->inode_map, ino)) {
+                       inode_dirty = 1;
+               } else {
+                       if (memcmp(inode, zero, length) != 0) {
+                               memset(inode, 0, length);
+                               inode_dirty = 1;
+                       } else {
+                               inode_dirty = 0;
+                       }
+               }
+
+               if (inode_dirty) {
+                       retval = ext2fs_write_inode_full(fs, ino, inode,
+                                                        length);
+                       if (retval) {
+                               com_err("set_csum", retval, "while writing "
+                                       "inode");
+                               exit(1);
+                       }
+               }
+
+               retval = rewrite_extents(fs, ino, inode);
+               if (retval) {
+                       com_err("rewrite_extents", retval,
+                               "while rewriting extents");
+                       exit(1);
+               }
+
+               if (LINUX_S_ISDIR(inode->i_mode)) {
+                       retval = rewrite_directory(fs, ino, inode);
+                       if (retval) {
+                               com_err("rewrite_directory", retval,
+                                       "while rewriting directories");
+                               exit(1);
+                       }
+               }
+
+               file_acl_block = ext2fs_file_acl_block(fs, inode);
+               if (!file_acl_block)
+                       continue;
+               retval = ext2fs_read_ext_attr3(fs, file_acl_block, ea_buf, ino);
+               if (retval) {
+                       com_err("rewrite_eablock", retval,
+                               "while rewriting extended attribute");
+                       exit(1);
+               }
+               retval = ext2fs_write_ext_attr3(fs, file_acl_block, ea_buf,
+                                               ino);
+               if (retval) {
+                       com_err("rewrite_eablock", retval,
+                               "while rewriting extended attribute");
+                       exit(1);
+               }
+       } while (ino);
+
+       ext2fs_free_mem(&zero);
+       ext2fs_free_mem(&inode);
+       ext2fs_free_mem(&ea_buf);
+       ext2fs_close_inode_scan(scan);
+}
+
+static void rewrite_metadata_checksums(ext2_filsys fs)
+{
+       dgrp_t i;
+
+       fs->flags |= EXT2_FLAG_IGNORE_CSUM_ERRORS;
+       ext2fs_init_csum_seed(fs);
+       for (i = 0; i < fs->group_desc_count; i++)
+               ext2fs_group_desc_csum_set(fs, i);
+       ext2fs_read_bitmaps(fs);
+       rewrite_inodes(fs);
+       ext2fs_mark_ib_dirty(fs);
+       ext2fs_mark_bb_dirty(fs);
+       ext2fs_mmp_update2(fs, 1);
+       fs->flags &= ~EXT2_FLAG_SUPER_ONLY;
+       fs->flags &= ~EXT2_FLAG_IGNORE_CSUM_ERRORS;
+       if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+                                      EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
+               fs->super->s_checksum_type = EXT2_CRC32C_CHKSUM;
+       else
+               fs->super->s_checksum_type = 0;
+       ext2fs_mark_super_dirty(fs);
+}
+
+static void enable_uninit_bg(ext2_filsys fs)
+{
+       struct ext2_group_desc *gd;
+       dgrp_t i;
+
+       for (i = 0; i < fs->group_desc_count; i++) {
+               gd = ext2fs_group_desc(fs, fs->group_desc, i);
+               gd->bg_itable_unused = 0;
+               gd->bg_flags = EXT2_BG_INODE_ZEROED;
+               ext2fs_group_desc_csum_set(fs, i);
+       }
+       fs->flags &= ~EXT2_FLAG_SUPER_ONLY;
+}
+
+static errcode_t zero_empty_inodes(ext2_filsys fs)
+{
+       int length = EXT2_INODE_SIZE(fs->super);
+       struct ext2_inode *inode;
+       ext2_inode_scan scan;
+       errcode_t       retval;
+       ext2_ino_t      ino;
+
+       retval = ext2fs_open_inode_scan(fs, 0, &scan);
+       if (retval)
+               goto out;
+
+       retval = ext2fs_get_mem(length, &inode);
+       if (retval)
+               goto out;
+
+       do {
+               retval = ext2fs_get_next_inode_full(scan, &ino, inode, length);
+               if (retval)
+                       goto out;
+               if (!ino)
+                       break;
+               if (!ext2fs_test_inode_bitmap2(fs->inode_map, ino)) {
+                       memset(inode, 0, length);
+                       retval = ext2fs_write_inode_full(fs, ino, inode,
+                                                        length);
+                       if (retval)
+                               goto out;
+               }
+       } while (1);
+
+out:
+       ext2fs_free_mem(&inode);
+       ext2fs_close_inode_scan(scan);
+       return retval;
+}
+
+static void disable_uninit_bg(ext2_filsys fs, __u32 csum_feature_flag)
+{
+       struct ext2_group_desc *gd;
+       dgrp_t i;
+       errcode_t retval;
+       blk64_t b, c, d;
+       int has_super;
+
+       /* Load bitmaps to ensure that the uninit ones get written out */
+       fs->super->s_feature_ro_compat |= csum_feature_flag;
+       ext2fs_read_bitmaps(fs);
+       ext2fs_mark_ib_dirty(fs);
+       ext2fs_mark_bb_dirty(fs);
+       fs->super->s_feature_ro_compat &= ~csum_feature_flag;
+
+       /* If we're only turning off uninit_bg, zero the inodes */
+       if (csum_feature_flag == EXT4_FEATURE_RO_COMPAT_GDT_CSUM) {
+               retval = zero_empty_inodes(fs);
+               if (retval) {
+                       com_err("disable_uninit_bg", retval,
+                               "while zeroing unused inodes");
+                       request_fsck_afterwards(fs);
+               }
+       }
+
+       /* The bbitmap is zeroed; we must mark group metadata blocks in use */
+       for (i = 0; i < fs->group_desc_count; i++) {
+               b = ext2fs_block_bitmap_loc(fs, i);
+               ext2fs_mark_block_bitmap2(fs->block_map, b);
+               b = ext2fs_inode_bitmap_loc(fs, i);
+               ext2fs_mark_block_bitmap2(fs->block_map, b);
+
+               retval = ext2fs_super_and_bgd_loc2(fs, i, &b, &c, &d, NULL);
+               if (retval == 0 && b)
+                       ext2fs_mark_block_bitmap2(fs->block_map, b);
+               if (retval == 0 && c)
+                       ext2fs_mark_block_bitmap2(fs->block_map, c);
+               if (retval == 0 && d)
+                       ext2fs_mark_block_bitmap2(fs->block_map, d);
+               if (retval) {
+                       com_err("disable_uninit_bg", retval,
+                               "while initializing block bitmaps");
+                       request_fsck_afterwards(fs);
+               }
+
+               gd = ext2fs_group_desc(fs, fs->group_desc, i);
+               gd->bg_itable_unused = 0;
+               gd->bg_flags = 0;
+               ext2fs_group_desc_csum_set(fs, i);
+       }
+       fs->flags &= ~EXT2_FLAG_SUPER_ONLY;
+       ext2fs_mark_super_dirty(fs);
+}
+
 /*
  * Update the feature set as provided by the user.
  */
 static int update_feature_set(ext2_filsys fs, char *features)
 {
        struct ext2_super_block *sb = fs->super;
-       struct ext2_group_desc *gd;
        __u32           old_features[3];
-       dgrp_t          i;
        int             type_err;
        unsigned int    mask_err;
 
@@ -544,36 +1021,68 @@ mmp_error:
        }
 
        if (FEATURE_ON(E2P_FEATURE_RO_INCOMPAT,
-                      EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) {
-               for (i = 0; i < fs->group_desc_count; i++) {
-                       gd = ext2fs_group_desc(fs, fs->group_desc, i);
-                       gd->bg_itable_unused = 0;
-                       gd->bg_flags = EXT2_BG_INODE_ZEROED;
-                       ext2fs_group_desc_csum_set(fs, i);
-               }
-               fs->flags &= ~EXT2_FLAG_SUPER_ONLY;
+                      EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) {
+               if (check_fsck_needed(fs))
+                       exit(1);
+               rewrite_checksums = 1;
+               /* metadata_csum supersedes uninit_bg */
+               fs->super->s_feature_ro_compat &=
+                       ~EXT4_FEATURE_RO_COMPAT_GDT_CSUM;
+
+               /* if uninit_bg was previously off, rewrite group desc */
+               if (!(old_features[E2P_FEATURE_RO_INCOMPAT] &
+                     EXT4_FEATURE_RO_COMPAT_GDT_CSUM))
+                       enable_uninit_bg(fs);
+
+               /*
+                * Since metadata_csum supersedes uninit_bg, pretend like
+                * uninit_bg has been off all along.
+                */
+               old_features[E2P_FEATURE_RO_INCOMPAT] &=
+                       ~EXT4_FEATURE_RO_COMPAT_GDT_CSUM;
        }
 
        if (FEATURE_OFF(E2P_FEATURE_RO_INCOMPAT,
-                       EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) {
-               for (i = 0; i < fs->group_desc_count; i++) {
-                       gd = ext2fs_group_desc(fs, fs->group_desc, i);
-                       if ((gd->bg_flags & EXT2_BG_INODE_ZEROED) == 0) {
-                               /* 
-                                * XXX what we really should do is zap
-                                * uninitialized inode tables instead.
-                                */
-                               request_fsck_afterwards(fs);
-                               break;
-                       }
-                       gd->bg_itable_unused = 0;
-                       gd->bg_flags = 0;
-                       gd->bg_checksum = 0;
-               }
-               fs->flags &= ~EXT2_FLAG_SUPER_ONLY;
+                       EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) {
+               if (check_fsck_needed(fs))
+                       exit(1);
+               rewrite_checksums = 1;
+               /*
+                * If we're turning off metadata_csum and not turning on
+                * uninit_bg, rewrite group desc.
+                */
+               if (!(fs->super->s_feature_ro_compat &
+                     EXT4_FEATURE_RO_COMPAT_GDT_CSUM))
+                       disable_uninit_bg(fs,
+                               EXT4_FEATURE_RO_COMPAT_METADATA_CSUM);
+               else
+                       /*
+                        * metadata_csum previously provided uninit_bg, so if
+                        * we're also setting the uninit_bg feature bit,
+                        * pretend like it was previously enabled.  Checksums
+                        * will be rewritten with crc16 later.
+                        */
+                       old_features[E2P_FEATURE_RO_INCOMPAT] |=
+                               EXT4_FEATURE_RO_COMPAT_GDT_CSUM;
        }
 
        if (FEATURE_ON(E2P_FEATURE_RO_INCOMPAT,
+                      EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) {
+               /* Do not enable uninit_bg when metadata_csum enabled */
+               if (fs->super->s_feature_ro_compat &
+                   EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)
+                       fs->super->s_feature_ro_compat &=
+                               ~EXT4_FEATURE_RO_COMPAT_GDT_CSUM;
+               else
+                       enable_uninit_bg(fs);
+       }
+
+       if (FEATURE_OFF(E2P_FEATURE_RO_INCOMPAT,
+                       EXT4_FEATURE_RO_COMPAT_GDT_CSUM))
+               disable_uninit_bg(fs,
+                               EXT4_FEATURE_RO_COMPAT_GDT_CSUM);
+
+       if (FEATURE_ON(E2P_FEATURE_RO_INCOMPAT,
                                EXT4_FEATURE_RO_COMPAT_QUOTA)) {
                /*
                 * Set the Q_flag here and handle the quota options in the code
@@ -2144,8 +2653,24 @@ retry_open:
                int set_csum = 0;
                dgrp_t i;
 
-               if (sb->s_feature_ro_compat &
-                   EXT4_FEATURE_RO_COMPAT_GDT_CSUM) {
+               if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+                               EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) {
+                       /*
+                        * Changing the UUID requires rewriting all metadata,
+                        * which can race with a mounted fs.  Don't allow that.
+                        */
+                       if (mount_flags & EXT2_MF_MOUNTED) {
+                               fputs(_("The UUID may only be "
+                                       "changed when the filesystem is "
+                                       "unmounted.\n"), stderr);
+                               exit(1);
+                       }
+
+                       if (check_fsck_needed(fs))
+                               exit(1);
+               }
+
+               if (ext2fs_has_group_desc_csum(fs)) {
                        /*
                         * Determine if the block group checksums are
                         * correct so we know whether or not to set
@@ -2169,13 +2694,19 @@ retry_open:
                        rc = 1;
                        goto closefs;
                }
+               ext2fs_init_csum_seed(fs);
                if (set_csum) {
                        for (i = 0; i < fs->group_desc_count; i++)
                                ext2fs_group_desc_csum_set(fs, i);
                        fs->flags &= ~EXT2_FLAG_SUPER_ONLY;
                }
                ext2fs_mark_super_dirty(fs);
+               if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+                               EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
+                       rewrite_checksums = 1;
        }
+       if (rewrite_checksums)
+               rewrite_metadata_checksums(fs);
        if (I_flag) {
                if (mount_flags & EXT2_MF_MOUNTED) {
                        fputs(_("The inode size may only be "
index ec1594e..0feff0f 100644 (file)
@@ -230,8 +230,7 @@ static void fix_uninit_block_bitmaps(ext2_filsys fs)
        dgrp_t          g;
        int             i;
 
-       if (!(EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
-                                        EXT4_FEATURE_RO_COMPAT_GDT_CSUM)))
+       if (!ext2fs_has_group_desc_csum(fs))
                return;
 
        for (g=0; g < fs->group_desc_count; g++) {
@@ -510,8 +509,7 @@ retry:
         */
        group_block = ext2fs_group_first_block2(fs,
                                                old_fs->group_desc_count);
-       csum_flag = EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
-                                              EXT4_FEATURE_RO_COMPAT_GDT_CSUM);
+       csum_flag = ext2fs_has_group_desc_csum(fs);
        if (access("/sys/fs/ext4/features/lazy_itable_init", F_OK) == 0)
                lazy_itable_init = 1;
        if (fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_META_BG)
@@ -828,9 +826,9 @@ static void mark_fs_metablock(ext2_resize_t rfs,
                        }
                }
        }
-       if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
-                                      EXT4_FEATURE_RO_COMPAT_GDT_CSUM) &&
-                  (ext2fs_bg_flags_test(fs, group, EXT2_BG_BLOCK_UNINIT))) {
+
+       if (ext2fs_has_group_desc_csum(fs) &&
+           (ext2fs_bg_flags_test(fs, group, EXT2_BG_BLOCK_UNINIT))) {
                /*
                 * If the block bitmap is uninitialized, which means
                 * nothing other than standard metadata in use.
@@ -926,8 +924,7 @@ static errcode_t blocks_to_move(ext2_resize_t rfs)
        for (blk = ext2fs_blocks_count(fs->super);
             blk < ext2fs_blocks_count(old_fs->super); blk++) {
                g = ext2fs_group_of_blk2(fs, blk);
-               if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
-                                              EXT4_FEATURE_RO_COMPAT_GDT_CSUM) &&
+               if (ext2fs_has_group_desc_csum(fs) &&
                    ext2fs_bg_flags_test(old_fs, g, EXT2_BG_BLOCK_UNINIT)) {
                        /*
                         * The block bitmap is uninitialized, so skip
@@ -1630,7 +1627,7 @@ static int check_and_change_inodes(ext2_ino_t dir,
 #ifdef RESIZE2FS_DEBUG
        if (is->rfs->flags & RESIZE_DEBUG_INODEMAP)
                printf("Inode translate (dir=%u, name=%.*s, %u->%u)\n",
-                      dir, dirent->name_len&0xFF, dirent->name,
+                      dir, ext2fs_dirent_name_len(dirent), dirent->name,
                       dirent->inode, new_inode);
 #endif
 
index d921672..105a305 100644 (file)
@@ -1,5 +1,6 @@
 FSCK_OPT=-yf
 
+[ -f "$TMPFILE" ] && rm -f $TMPFILE
 TMPFILE=$test_name.tmp
 > $TMPFILE
 
index 02cc12a..d4d2cb3 100644 (file)
@@ -1,5 +1,6 @@
 FSCK_OPT=-yf
 
+[ -f "$TMPFILE" ] && rm -f $TMPFILE
 TMPFILE=$test_name.tmp
 > $TMPFILE
 
index 91b956b..59fad4e 100644 (file)
@@ -1,4 +1,9 @@
-/^[dbgumpe2fsckrsiz]* [1-9]\.[0-9]*[.-][^ ]* ([0-9]*-[A-Za-z]*-[0-9]*)/d
+/^debugfs [1-9]\.[0-9]*[.-][^ ]* ([0-9]*-[A-Za-z]*-[0-9]*)/d
+/^dumpe2fs [1-9]\.[0-9]*[.-][^ ]* ([0-9]*-[A-Za-z]*-[0-9]*)/d
+/^e2fsck [1-9]\.[0-9]*[.-][^ ]* ([0-9]*-[A-Za-z]*-[0-9]*)/d
+/^mke2fs [1-9]\.[0-9]*[.-][^ ]* ([0-9]*-[A-Za-z]*-[0-9]*)/d
+/^resize2fs [1-9]\.[0-9]*[.-][^ ]* ([0-9]*-[A-Za-z]*-[0-9]*)/d
+/^tune2fs [1-9]\.[0-9]*[.-][^ ]* ([0-9]*-[A-Za-z]*-[0-9]*)/d
 s/\\015//g
 /automatically checked/d
 /^Directory Hash Seed:/d
index 02b0b4b..dff98f0 100644 (file)
@@ -2,6 +2,7 @@ DESCRIPTION="enable MMP during mke2fs"
 FS_SIZE=65536
 MKE2FS_DEVICE_SECTSIZE=2048
 export MKE2FS_DEVICE_SECTSIZE
+[ -f "$TMPFILE" ] && rm -f $TMPFILE
 TMPFILE=$test_name.tmp
 > $TMPFILE
 stat -f $TMPFILE | grep -q "Type: tmpfs"
index 8fc8158..d15b1e3 100644 (file)
@@ -1,5 +1,6 @@
 FSCK_OPT=-yf
 
+[ -f "$TMPFILE" ] && rm -f $TMPFILE
 TMPFILE=$test_name.tmp
 > $TMPFILE
 
index 1dee14e..572730b 100644 (file)
@@ -1,5 +1,6 @@
 FSCK_OPT=-yf
 
+[ -f "$TMPFILE" ] && rm -f $TMPFILE
 TMPFILE=$test_name.tmp
 > $TMPFILE
 
diff --git a/tests/t_uninit_bg_rm/expect b/tests/t_uninit_bg_rm/expect
new file mode 100644 (file)
index 0000000..61e9eaa
--- /dev/null
@@ -0,0 +1,21 @@
+mke2fs -q -t ext4 -F -o Linux -b 1024 test.img 1G
+tune2fs -f -O ^uninit_bg test.img
+fsck -yf -N test_filesys test.img
+Pass 1: Checking inodes, blocks, and sizes
+Pass 2: Checking directory structure
+Pass 3: Checking directory connectivity
+Pass 4: Checking reference counts
+Pass 5: Checking group summary information
+test_filesys: 11/65536 files (0.0% non-contiguous), 52294/1048576 blocks
+mke2fs -q -t ext4 -O bigalloc -F -o Linux -b 1024 -C 8192 test.img 10G
+tune2fs -f -O ^uninit_bg test.img
+fsck -yf -N test_filesys test.img
+Pass 1: Checking inodes, blocks, and sizes
+Pass 2: Checking directory structure
+Pass 3: Checking directory connectivity
+Pass 4: Checking reference counts
+Pass 5: Checking group summary information
+test_filesys: 11/655360 files (0.0% non-contiguous), 199864/10485760 blocks
diff --git a/tests/t_uninit_bg_rm/script b/tests/t_uninit_bg_rm/script
new file mode 100644 (file)
index 0000000..cd397c5
--- /dev/null
@@ -0,0 +1,50 @@
+test_description="remove uninit_bg"
+OUT=$test_name.log
+FSCK_OPT=-yf
+EXP=$test_dir/expect
+
+cp /dev/null $TMPFILE
+rm -f $OUT.new
+
+echo mke2fs -q -t ext4 -F -o Linux -b 1024 $TMPFILE 1G >> $OUT.new
+$MKE2FS -q -t ext4 -F -o Linux -b 1024 $TMPFILE 1G >> $OUT.new 2>&1
+
+echo "tune2fs -f -O ^uninit_bg $TMPFILE" >> $OUT.new
+$TUNE2FS -f -O ^uninit_bg $TMPFILE >> $OUT.new 2>&1
+
+echo " " >> $OUT.new
+echo fsck $FSCK_OPT -N test_filesys test.img >> $OUT.new
+$FSCK $FSCK_OPT -N test_filesys $TMPFILE >> $OUT.new 2>&1
+
+echo " " >> $OUT.new
+cp /dev/null $TMPFILE
+echo mke2fs -q -t ext4 -O bigalloc -F -o Linux -b 1024 -C 8192 $TMPFILE 10G >> $OUT.new
+$MKE2FS -q -t ext4 -O bigalloc -F -o Linux -b 1024 -C 8192 $TMPFILE 10G >> $OUT.new 2>&1
+
+echo "tune2fs -f -O ^uninit_bg $TMPFILE" >> $OUT.new
+$TUNE2FS -f -O ^uninit_bg $TMPFILE >> $OUT.new 2>&1
+
+echo " " >> $OUT.new
+echo fsck $FSCK_OPT -N test_filesys test.img >> $OUT.new
+$FSCK $FSCK_OPT -N test_filesys $TMPFILE >> $OUT.new 2>&1
+
+sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new > $OUT
+
+rm -f $OUT.new $TMPFILE
+
+#
+# Do the verification
+#
+
+cmp -s $OUT $EXP
+status=$?
+
+if [ "$status" = 0 ] ; then
+       echo "$test_name: $test_description: ok"
+       touch $test_name.ok
+else
+       echo "$test_name: $test_description: failed"
+       diff $DIFF_OPTS $EXP $OUT > $test_name.failed
+fi
+
+unset IMAGE FSCK_OPT OUT EXP
index 50d5879..c90a6c6 100644 (file)
--- a/version.h
+++ b/version.h
@@ -7,5 +7,5 @@
  * file may be redistributed under the GNU Public License v2.
  */
 
-#define E2FSPROGS_VERSION "1.42.8"
-#define E2FSPROGS_DATE "20-Jun-2013"
+#define E2FSPROGS_VERSION "1.43-WIP"
+#define E2FSPROGS_DATE "8-Jul-2013"