]> git.ipfire.org Git - thirdparty/e2fsprogs.git/commitdiff
Merge branch 'maint' into next
authorTheodore Ts'o <tytso@mit.edu>
Tue, 13 May 2014 15:01:07 +0000 (11:01 -0400)
committerTheodore Ts'o <tytso@mit.edu>
Tue, 13 May 2014 15:01:07 +0000 (11:01 -0400)
Conflicts:
debugfs/Makefile.in
debugfs/debug_cmds.ct
debugfs/debugfs.c
debugfs/debugfs.h
e2fsck/Makefile.in
misc/Makefile.in
misc/mke2fs.c

147 files changed:
MCONFIG.in
RELEASE-NOTES
configure
configure.in
debian/changelog
debian/e2fslibs.symbols
debugfs/Makefile.in
debugfs/debug_cmds.ct
debugfs/debugfs.8.in
debugfs/debugfs.c
debugfs/debugfs.h
debugfs/dump.c
debugfs/filefrag.c
debugfs/htree.c
debugfs/logdump.c
debugfs/ls.c
debugfs/lsdel.c
debugfs/ncheck.c
debugfs/set_fields.c
debugfs/util.c
debugfs/xattrs.c [new file with mode: 0644]
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/region.c
e2fsck/rehash.c
e2fsck/sigcatcher.c
e2fsck/super.c
e2fsck/unix.c
e2fsck/util.c
ext2ed/Makefile.in
intl/Makefile.in
lib/blkid/Makefile.in
lib/blkid/probe.h
lib/config.h.in
lib/e2p/Makefile.in
lib/e2p/feature.c
lib/e2p/ls.c
lib/e2p/pf.c
lib/et/Makefile.in
lib/ext2fs/Makefile.in
lib/ext2fs/Makefile.pq
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/bmap.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/dblist_dir.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/fileio.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/icount.c
lib/ext2fs/initialize.c
lib/ext2fs/inline_data.c [new file with mode: 0644]
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/punch.c
lib/ext2fs/rw_bitmaps.c
lib/ext2fs/swapfs.c
lib/ext2fs/tst_super_size.c
lib/ext2fs/unlink.c
lib/ext2fs/valid_blk.c
lib/quota/Makefile.in
lib/ss/Makefile.in
lib/uuid/Makefile.in
misc/Makefile.in
misc/create_inode.c [new file with mode: 0644]
misc/create_inode.h [new file with mode: 0644]
misc/dumpe2fs.c
misc/e2image.c
misc/ext4.5.in
misc/mke2fs.8.in
misc/mke2fs.c
misc/mke2fs.conf.in
misc/tune2fs.c
resize/Makefile.in
resize/resize2fs.c
tests/d_xattr_edits/expect [new file with mode: 0644]
tests/d_xattr_edits/name [new file with mode: 0644]
tests/d_xattr_edits/script [new file with mode: 0644]
tests/f_bad_disconnected_inode/expect.1
tests/f_bbfile/expect.1
tests/f_dup/expect.1
tests/f_dup2/expect.1
tests/f_dup_ba/expect.1
tests/f_dup_resize/expect.1
tests/f_dupfsblks/expect.1
tests/f_dupsuper/expect.1
tests/f_jnl_64bit/expect.0
tests/f_mmp/script
tests/f_mmp_garbage/script
tests/filter.sed
tests/m_mmp/script
tests/progs/Makefile.in
tests/r_inline_xattr/expect
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]
util/Makefile.in
util/static-analysis-cleanup [new file with mode: 0644]
util/subst.c
version.h

index 2ba2aa99df3365bd3794375965f3e1b59b0ec63a..044f256b3aac50f391d2e942d592218a348e4f9c 100644 (file)
@@ -53,17 +53,23 @@ pkgconfigdir = $(libdir)/pkgconfig
 
 @ifGNUmake@ CHECK=sparse
 @ifGNUmake@ CHECK_OPTS=-Wsparse-all -Wno-transparent-union -Wno-return-void -Wno-undef -Wno-non-pointer-null
+@ifGNUmake@ CPPCHECK=cppcheck
+@ifGNUmake@ CPPCHECK_OPTS=--force --enable=all --quiet
 @ifGNUmake@ ifeq ("$(C)", "2")
 @ifGNUmake@   CHECK_CMD=$(CHECK) $(CHECK_OPTS) -Wbitwise -D__CHECK_ENDIAN__
+@ifGNUmake@   CPPCHECK_CMD=$(CPPCHECK) $(CPPCHECK_OPTS)
 @ifGNUmake@ else
 @ifGNUmake@   ifeq ("$(C)", "1")
 @ifGNUmake@     CHECK_CMD=$(CHECK) $(CHECK_OPTS)
+@ifGNUmake@     CPPCHECK_CMD=$(CPPCHECK) $(CPPCHECK_OPTS)
 @ifGNUmake@    else
 @ifGNUmake@     CHECK_CMD=@true
+@ifGNUmake@     CPPCHECK_CMD=@true
 @ifGNUmake@   endif
 @ifGNUmake@ endif
 
 @ifNotGNUmake@ CHECK_CMD=@true
+@ifNotGNUmake@ CPPHECK_CMD=@true
 
 CC = @CC@
 BUILD_CC = @BUILD_CC@
@@ -178,7 +184,7 @@ DEP_INSTALL_SYMLINK = $(top_builddir)/util/install-symlink \
 # Run make gcc-wall to do a build with warning messages.
 #
 #
-WFLAGS=                -std=c99 -D_XOPEN_SOURCE=600 -D_GNU_SOURCE \
+WFLAGS=                -std=gnu99 -D_XOPEN_SOURCE=600 -D_GNU_SOURCE \
                        -pedantic $(WFLAGS_EXTRA) \
                        -Wall -W -Wwrite-strings -Wpointer-arith \
                        -Wcast-qual -Wcast-align -Wno-variadic-macros \
@@ -189,11 +195,18 @@ WFLAGS=           -std=c99 -D_XOPEN_SOURCE=600 -D_GNU_SOURCE \
                        -UENABLE_NLS
 
 gcc-wall-new:
-       (make CFLAGS="@CFLAGS@ $(WFLAGS)" > /dev/null) 2>&1 | sed -f $(top_srcdir)/util/gcc-wall-cleanup 
+       ($(MAKE) CFLAGS="@CFLAGS@ $(WFLAGS)" > /dev/null) 2>&1 | sed -f $(top_srcdir)/util/gcc-wall-cleanup
 
 gcc-wall:
-       make clean > /dev/null
-       make gcc-wall-new
+       $(MAKE) clean > /dev/null
+       $(MAKE) gcc-wall-new
+
+static-check:
+       ($(MAKE) C=1 V=1 CFLAGS="@CFLAGS@ $(WFLAGS)") 2>&1 | sed -f $(top_srcdir)/util/static-analysis-cleanup
+
+static-check-all:
+       $(MAKE) clean > /dev/null
+       $(MAKE) static-check
 
 #
 # Installation user and groups
index e3db1b0fda4bdea5d1a5342e812c0ab41497c768..3ec2eab2616b3dded60ee8894aea5736c821bca9 100644 (file)
@@ -1,3 +1,23 @@
+E2fsprogs 1.43-WIP (December 28, 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.9 (December 28, 2013)
 ====================================
 
index 1b0ee6206fae0742b8f1be92b07fcd39055c2ffe..53405aa6ff541d86a69efd9a6907d58aec8361cd 100755 (executable)
--- a/configure
+++ b/configure
@@ -853,6 +853,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
@@ -1510,6 +1513,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
 
@@ -5633,6 +5639,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 6592e707512eda8e3325e8bf49a83a8e6454611c..448a2926776ae8305f5ff79685660f056232977f 100644 (file)
@@ -810,6 +810,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 ce5020f781ab6086558641066e21b3cd8f85447d..2d00c309a3bfdfb4d6c25fa9ad1793f4a03242ca 100644 (file)
@@ -1,3 +1,9 @@
+e2fsprogs (1.43~WIP-2014-02-04-1) unstable; urgency=low
+
+  * Merge in updates from the maint branch (changes from 1.42.9-3)
+
+ -- Theodore Y. Ts'o <tytso@mit.edu>  Wed, 04 Feb 2014 23:31:56 -0500
+
 e2fsprogs (1.42.9-3) unstable; urgency=medium
 
   * Add the ability for mke2fs to create hugefiles
@@ -175,6 +181,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 5422544f9cfd541404d26b17f35fbe5998704539..8a88efe3a3d9f2c6f913ae23b72efd74e48f2170 100644 (file)
@@ -47,6 +47,7 @@ libext2fs.so.2 e2fslibs #MINVER#
  ext2fs_add_journal_inode2@Base 1.42.9-3~
  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
@@ -88,6 +89,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_alloc_stats_range@Base 1.42.9-3~
  ext2fs_block_bitmap_loc@Base 1.42
  ext2fs_block_bitmap_loc_set@Base 1.42
@@ -122,7 +126,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
@@ -142,14 +148,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
@@ -250,6 +264,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
@@ -300,12 +315,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_blocks2@Base 1.42
@@ -338,11 +360,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
@@ -354,6 +379,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
@@ -382,8 +408,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
@@ -420,6 +448,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
@@ -516,6 +546,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
@@ -524,8 +555,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 3dd06f03f1398fa20da9edcdcab6a4c6ce7fa0ad..0f235959af4f2d6d99bfd3000c85e33515ba2b57 100644 (file)
@@ -18,18 +18,19 @@ MK_CMDS=    _SS_DIR_OVERRIDE=../lib/ss ../lib/ss/mk_cmds
 
 DEBUG_OBJS= debug_cmds.o debugfs.o util.o ncheck.o icheck.o ls.o \
        lsdel.o dump.o set_fields.o logdump.o htree.o unused.o e2freefrag.o \
-       filefrag.o extent_cmds.o extent_inode.o zap.o quota.o
+       filefrag.o extent_cmds.o extent_inode.o zap.o create_inode.o \
+       quota.o xattrs.o
 
 RO_DEBUG_OBJS= ro_debug_cmds.o ro_debugfs.o util.o ncheck.o icheck.o ls.o \
        lsdel.o logdump.o htree.o e2freefrag.o filefrag.o extent_cmds.o \
-       extent_inode.o quota.o
+       extent_inode.o quota.o xattrs.o
 
 SRCS= debug_cmds.c $(srcdir)/debugfs.c $(srcdir)/util.c $(srcdir)/ls.c \
        $(srcdir)/ncheck.c $(srcdir)/icheck.c $(srcdir)/lsdel.c \
        $(srcdir)/dump.c $(srcdir)/set_fields.c ${srcdir}/logdump.c \
        $(srcdir)/htree.c $(srcdir)/unused.c ${srcdir}/../misc/e2freefrag.c \
        $(srcdir)/filefrag.c $(srcdir)/extent_inode.c $(srcdir)/zap.c \
-       $(srcdir)/quota.c
+       $(srcdir)/../misc/create_inode.c $(srcdir)/xattrs.c $(srcdir)/quota.c
 
 LIBS= $(LIBQUOTA) $(LIBEXT2FS) $(LIBE2P) $(LIBSS) $(LIBCOM_ERR) $(LIBBLKID) \
        $(LIBUUID) $(SYSLIBS)
@@ -47,6 +48,7 @@ STATIC_DEPLIBS= $(STATIC_LIBEXT2FS) $(DEPSTATIC_LIBSS) \
        $(E) "  CC $<"
        $(Q) $(CC) -c $(ALL_CFLAGS) $< -o $@
        $(Q) $(CHECK_CMD) $(ALL_CFLAGS) $<
+       $(Q) $(CPPCHECK_CMD) $(CPPFLAGS) $<
 
 all:: $(PROGS) $(MANPAGES)
 
@@ -83,6 +85,11 @@ e2freefrag.o: $(srcdir)/../misc/e2freefrag.c
        $(E) "  CC $@"
        $(Q) $(CC) -c $(ALL_CFLAGS) -I$(srcdir) $< -DDEBUGFS -o $@
 
+create_inode.o: $(srcdir)/../misc/create_inode.c
+       $(E) "  CC $@"
+       $(Q) $(CC) -c $(ALL_CFLAGS) -I$(srcdir) \
+                $(srcdir)/../misc/create_inode.c -DDEBUGFS -o $@
+
 debugfs.8: $(DEP_SUBSTITUTE) $(srcdir)/debugfs.8.in
        $(E) "  SUBST $@"
        $(Q) $(SUBSTITUTE_UPTIME) $(srcdir)/debugfs.8.in debugfs.8
@@ -142,6 +149,8 @@ debugfs.o: $(srcdir)/debugfs.c $(top_builddir)/lib/config.h \
  $(top_srcdir)/lib/ext2fs/ext2fs.h $(top_srcdir)/lib/ext2fs/ext3_extents.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)/../misc/create_inode.h \
+ $(srcdir)/../misc/nls-enable.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 \
  $(top_srcdir)/lib/e2p/e2p.h $(top_srcdir)/version.h $(srcdir)/jfs_user.h \
@@ -155,6 +164,8 @@ util.o: $(srcdir)/util.c $(top_builddir)/lib/config.h \
  $(top_srcdir)/lib/ext2fs/ext3_extents.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)/../misc/create_inode.h $(top_srcdir)/lib/e2p/e2p.h \
+ $(srcdir)/../misc/nls-enable.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
 ls.o: $(srcdir)/ls.c $(top_builddir)/lib/config.h \
@@ -164,6 +175,8 @@ ls.o: $(srcdir)/ls.c $(top_builddir)/lib/config.h \
  $(top_srcdir)/lib/ext2fs/ext2fs.h $(top_srcdir)/lib/ext2fs/ext3_extents.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)/../misc/create_inode.h $(top_srcdir)/lib/e2p/e2p.h \
+ $(srcdir)/../misc/nls-enable.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
 ncheck.o: $(srcdir)/ncheck.c $(top_builddir)/lib/config.h \
@@ -173,6 +186,8 @@ ncheck.o: $(srcdir)/ncheck.c $(top_builddir)/lib/config.h \
  $(top_srcdir)/lib/ext2fs/ext2fs.h $(top_srcdir)/lib/ext2fs/ext3_extents.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)/../misc/create_inode.h $(top_srcdir)/lib/e2p/e2p.h \
+ $(srcdir)/../misc/nls-enable.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
 icheck.o: $(srcdir)/icheck.c $(top_builddir)/lib/config.h \
@@ -182,6 +197,8 @@ icheck.o: $(srcdir)/icheck.c $(top_builddir)/lib/config.h \
  $(top_srcdir)/lib/ext2fs/ext2fs.h $(top_srcdir)/lib/ext2fs/ext3_extents.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)/../misc/create_inode.h $(top_srcdir)/lib/e2p/e2p.h \
+ $(srcdir)/../misc/nls-enable.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
 lsdel.o: $(srcdir)/lsdel.c $(top_builddir)/lib/config.h \
@@ -191,6 +208,8 @@ lsdel.o: $(srcdir)/lsdel.c $(top_builddir)/lib/config.h \
  $(top_srcdir)/lib/ext2fs/ext2fs.h $(top_srcdir)/lib/ext2fs/ext3_extents.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)/../misc/create_inode.h $(top_srcdir)/lib/e2p/e2p.h \
+ $(srcdir)/../misc/nls-enable.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
 dump.o: $(srcdir)/dump.c $(top_builddir)/lib/config.h \
@@ -200,6 +219,8 @@ dump.o: $(srcdir)/dump.c $(top_builddir)/lib/config.h \
  $(top_srcdir)/lib/ext2fs/ext2fs.h $(top_srcdir)/lib/ext2fs/ext3_extents.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)/../misc/create_inode.h $(top_srcdir)/lib/e2p/e2p.h \
+ $(srcdir)/../misc/nls-enable.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
 set_fields.o: $(srcdir)/set_fields.c $(top_builddir)/lib/config.h \
@@ -209,6 +230,8 @@ set_fields.o: $(srcdir)/set_fields.c $(top_builddir)/lib/config.h \
  $(top_srcdir)/lib/ext2fs/ext2fs.h $(top_srcdir)/lib/ext2fs/ext3_extents.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)/../misc/create_inode.h $(top_srcdir)/lib/e2p/e2p.h \
+ $(srcdir)/../misc/nls-enable.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 \
  $(top_srcdir)/lib/e2p/e2p.h
@@ -219,6 +242,10 @@ logdump.o: $(srcdir)/logdump.c $(top_builddir)/lib/config.h \
  $(top_srcdir)/lib/ext2fs/ext2fs.h $(top_srcdir)/lib/ext2fs/ext3_extents.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)/../misc/create_inode.h $(top_srcdir)/lib/e2p/e2p.h \
+ $(srcdir)/../misc/nls-enable.h $(srcdir)/jfs_user.h \
+ $(top_srcdir)/lib/ext2fs/kernel-jbd.h $(top_srcdir)/lib/ext2fs/jfs_compat.h \
+ $(top_srcdir)/lib/ext2fs/kernel-list.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)/jfs_user.h $(top_srcdir)/lib/ext2fs/kernel-jbd.h \
@@ -230,6 +257,68 @@ htree.o: $(srcdir)/htree.c $(top_builddir)/lib/config.h \
  $(top_srcdir)/lib/ext2fs/ext2fs.h $(top_srcdir)/lib/ext2fs/ext3_extents.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)/../misc/create_inode.h $(top_srcdir)/lib/e2p/e2p.h \
+ $(srcdir)/../misc/nls-enable.h
+unused.o: $(srcdir)/unused.c $(top_builddir)/lib/config.h \
+ $(top_builddir)/lib/dirpaths.h $(srcdir)/debugfs.h $(top_srcdir)/lib/ss/ss.h \
+ $(top_builddir)/lib/ss/ss_err.h $(top_srcdir)/lib/et/com_err.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/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)/../misc/create_inode.h $(top_srcdir)/lib/e2p/e2p.h \
+ $(srcdir)/../misc/nls-enable.h
+e2freefrag.o: $(srcdir)/../misc/e2freefrag.c $(top_builddir)/lib/config.h \
+ $(top_builddir)/lib/dirpaths.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)/../misc/e2freefrag.h
+filefrag.o: $(srcdir)/filefrag.c $(top_builddir)/lib/config.h \
+ $(top_builddir)/lib/dirpaths.h $(srcdir)/debugfs.h $(top_srcdir)/lib/ss/ss.h \
+ $(top_builddir)/lib/ss/ss_err.h $(top_srcdir)/lib/et/com_err.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/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)/../misc/create_inode.h $(top_srcdir)/lib/e2p/e2p.h \
+ $(srcdir)/../misc/nls-enable.h
+extent_inode.o: $(srcdir)/extent_inode.c $(top_builddir)/lib/config.h \
+ $(top_builddir)/lib/dirpaths.h $(srcdir)/debugfs.h $(top_srcdir)/lib/ss/ss.h \
+ $(top_builddir)/lib/ss/ss_err.h $(top_srcdir)/lib/et/com_err.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/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)/../misc/create_inode.h $(top_srcdir)/lib/e2p/e2p.h \
+ $(srcdir)/../misc/nls-enable.h
+zap.o: $(srcdir)/zap.c $(top_builddir)/lib/config.h \
+ $(top_builddir)/lib/dirpaths.h $(srcdir)/debugfs.h $(top_srcdir)/lib/ss/ss.h \
+ $(top_builddir)/lib/ss/ss_err.h $(top_srcdir)/lib/et/com_err.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/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)/../misc/create_inode.h $(top_srcdir)/lib/e2p/e2p.h \
+ $(srcdir)/../misc/nls-enable.h
+create_inode.o: $(srcdir)/../misc/create_inode.c \
+ $(srcdir)/../misc/create_inode.h $(top_srcdir)/lib/et/com_err.h \
+ $(top_srcdir)/lib/e2p/e2p.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/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)/../misc/nls-enable.h
+xattrs.o: $(srcdir)/xattrs.c $(srcdir)/debugfs.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)/jfs_user.h $(top_srcdir)/lib/ext2fs/kernel-jbd.h \
+ $(top_srcdir)/lib/ext2fs/jfs_compat.h $(top_srcdir)/lib/ext2fs/kernel-list.h \
+ $(top_srcdir)/lib/ext2fs/ext2_ext_attr.h $(top_srcdir)/lib/ext2fs/bitops.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 \
  $(top_srcdir)/lib/e2p/e2p.h
index 6a18df67c83f92d3700d4496eed09e4bc671ea7a..814fd529f545a372e5001f4693ae495c5dce4860 100644 (file)
@@ -190,6 +190,18 @@ request do_zap_block, "Zap block: fill with 0, pattern, flip bits etc.",
 request do_block_dump, "Dump contents of a block",
        block_dump, bd;
 
+request do_list_xattr, "List extended attributes of an inode",
+       ea_list;
+
+request do_get_xattr, "Get an extended attribute of an inode",
+       ea_get;
+
+request do_set_xattr, "Set an extended attribute of an inode",
+       ea_set;
+
+request do_rm_xattr, "Remove an extended attribute of an inode",
+       ea_rm;
+
 request do_list_quota, "List quota",
        list_quota, lq;
 
index 73254d31068b0e33cc98cbcf9c7e575226237009..aacb223e4571431969f8fc438c21bab993c065db 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
@@ -384,7 +389,7 @@ which is a hard link to
 .IR filespec .
 Note this does not adjust the inode reference counts.
 .TP
-.BI logdump " [-acs] [-b block] [-i filespec] [-f journal_file] [output_file]"
+.BI logdump " [-acsO] [-b block] [-i filespec] [-f journal_file] [output_file]"
 Dump the contents of the ext3 journal.  By default, dump the journal inode as
 specified in the superblock.  However, this can be overridden with the
 .I \-i
@@ -415,11 +420,20 @@ the
 and
 .I \-b
 options.
+.IP
+The
+.I \-O
+option causes logdump to display old (checkpointed) journal entries.
+This can be used to try to track down journal problems even after the
+journal has been replayed.
 .TP
-.BI ls " [-d] [-l] [-p] filespec"
+.BI ls " [-l] [-c] [-d] [-p] filespec"
 Print a listing of the files in the directory
 .IR filespec .
 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 326f41e8f5cd932b656f4e7bad0086419274068b..23a7ca39285dcab55d0731a60a7aca814360a315 100644 (file)
@@ -25,8 +25,6 @@ extern char *optarg;
 #include <errno.h>
 #endif
 #include <fcntl.h>
-#include <sys/types.h>
-#include <sys/stat.h>
 
 #include "debugfs.h"
 #include "uuid/uuid.h"
@@ -41,21 +39,11 @@ extern char *optarg;
 #define BUFSIZ 8192
 #endif
 
-/* 64KiB is the minimium blksize to best minimize system call overhead. */
-#ifndef IO_BUFSIZE
-#define IO_BUFSIZE 64*1024
-#endif
-
-/* Block size for `st_blocks' */
-#ifndef S_BLKSIZE
-#define S_BLKSIZE 512
-#endif
-
 ss_request_table *extra_cmds;
 const char *debug_prog_name;
 int sci_idx;
 
-ext2_filsys    current_fs = NULL;
+ext2_filsys    current_fs;
 quota_ctx_t    current_qctx;
 ext2_ino_t     root, cwd;
 
@@ -375,8 +363,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, "
@@ -508,27 +495,6 @@ static int list_blocks_proc(ext2_filsys fs EXT2FS_ATTR((unused)),
        return 0;
 }
 
-static void dump_xattr_string(FILE *out, const char *str, int len)
-{
-       int printable = 0;
-       int i;
-
-       /* check: is string "printable enough?" */
-       for (i = 0; i < len; i++)
-               if (isprint(str[i]))
-                       printable++;
-
-       if (printable <= len*7/8)
-               printable = 0;
-
-       for (i = 0; i < len; i++)
-               if (printable)
-                       fprintf(out, isprint(str[i]) ? "%c" : "\\%03o",
-                               (unsigned char)str[i]);
-               else
-                       fprintf(out, "%02x ", (unsigned char)str[i]);
-}
-
 static void internal_dump_inode_extra(FILE *out,
                                      const char *prefix EXT2FS_ATTR((unused)),
                                      ext2_ino_t inode_num EXT2FS_ATTR((unused)),
@@ -546,34 +512,6 @@ static void internal_dump_inode_extra(FILE *out,
                                inode->i_extra_isize);
                return;
        }
-       storage_size = EXT2_INODE_SIZE(current_fs->super) -
-                       EXT2_GOOD_OLD_INODE_SIZE -
-                       inode->i_extra_isize;
-       magic = (__u32 *)((char *)inode + EXT2_GOOD_OLD_INODE_SIZE +
-                       inode->i_extra_isize);
-       if (*magic == EXT2_EXT_ATTR_MAGIC) {
-               fprintf(out, "Extended attributes stored in inode body: \n");
-               end = (char *) inode + EXT2_INODE_SIZE(current_fs->super);
-               start = (char *) magic + sizeof(__u32);
-               entry = (struct ext2_ext_attr_entry *) start;
-               while (!EXT2_EXT_IS_LAST_ENTRY(entry)) {
-                       struct ext2_ext_attr_entry *next =
-                               EXT2_EXT_ATTR_NEXT(entry);
-                       if (entry->e_value_size > storage_size ||
-                                       (char *) next >= end) {
-                               fprintf(out, "invalid EA entry in inode\n");
-                               return;
-                       }
-                       fprintf(out, "  ");
-                       dump_xattr_string(out, EXT2_EXT_ATTR_NAME(entry),
-                                         entry->e_name_len);
-                       fprintf(out, " = \"");
-                       dump_xattr_string(out, start + entry->e_value_offs,
-                                               entry->e_value_size);
-                       fprintf(out, "\" (%u)\n", entry->e_value_size);
-                       entry = next;
-               }
-       }
 }
 
 static void dump_blocks(FILE *f, const char *prefix, ext2_ino_t inode)
@@ -722,6 +660,17 @@ static void dump_extents(FILE *f, const char *prefix, ext2_ino_t ino,
        }
        if (printed)
                fprintf(f, "\n");
+       ext2fs_extent_free(handle);
+}
+
+static void dump_inline_data(FILE *out, const char *prefix, ext2_ino_t inode_num)
+{
+       errcode_t retval;
+       size_t size;
+
+       retval = ext2fs_inline_data_size(current_fs, inode_num, &size);
+       if (!retval)
+               fprintf(out, "%sSize of inline data: %zu", prefix, size);
 }
 
 void internal_dump_inode(FILE *out, const char *prefix,
@@ -821,6 +770,20 @@ 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);
+       dump_inode_attributes(out, inode_num);
+       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);
@@ -844,6 +807,8 @@ void internal_dump_inode(FILE *out, const char *prefix,
                if (inode->i_flags & EXT4_EXTENTS_FL)
                        dump_extents(out, prefix, inode_num,
                                     DUMP_LEAF_EXTENTS|DUMP_NODE_EXTENTS, 0, 0);
+               else if (inode->i_flags & EXT4_INLINE_DATA_FL)
+                       dump_inline_data(out, prefix, inode_num);
                else
                        dump_blocks(out, prefix, inode_num);
        }
@@ -1578,189 +1543,25 @@ void do_find_free_inode(int argc, char *argv[])
 }
 
 #ifndef READ_ONLY
-static errcode_t copy_file(int fd, ext2_ino_t newfile, int bufsize, int make_holes)
-{
-       ext2_file_t     e2_file;
-       errcode_t       retval;
-       int             got;
-       unsigned int    written;
-       char            *buf;
-       char            *ptr;
-       char            *zero_buf;
-       int             cmp;
-
-       retval = ext2fs_file_open(current_fs, newfile,
-                                 EXT2_FILE_WRITE, &e2_file);
-       if (retval)
-               return retval;
-
-       retval = ext2fs_get_mem(bufsize, &buf);
-       if (retval) {
-               com_err("copy_file", retval, "can't allocate buffer\n");
-               return retval;
-       }
-
-       /* This is used for checking whether the whole block is zero */
-       retval = ext2fs_get_memzero(bufsize, &zero_buf);
-       if (retval) {
-               com_err("copy_file", retval, "can't allocate buffer\n");
-               ext2fs_free_mem(&buf);
-               return retval;
-       }
-
-       while (1) {
-               got = read(fd, buf, bufsize);
-               if (got == 0)
-                       break;
-               if (got < 0) {
-                       retval = errno;
-                       goto fail;
-               }
-               ptr = buf;
-
-               /* Sparse copy */
-               if (make_holes) {
-                       /* Check whether all is zero */
-                       cmp = memcmp(ptr, zero_buf, got);
-                       if (cmp == 0) {
-                                /* The whole block is zero, make a hole */
-                               retval = ext2fs_file_lseek(e2_file, got, EXT2_SEEK_CUR, NULL);
-                               if (retval)
-                                       goto fail;
-                               got = 0;
-                       }
-               }
-
-               /* Normal copy */
-               while (got > 0) {
-                       retval = ext2fs_file_write(e2_file, ptr,
-                                                  got, &written);
-                       if (retval)
-                               goto fail;
-
-                       got -= written;
-                       ptr += written;
-               }
-       }
-       ext2fs_free_mem(&buf);
-       ext2fs_free_mem(&zero_buf);
-       retval = ext2fs_file_close(e2_file);
-       return retval;
-
-fail:
-       ext2fs_free_mem(&buf);
-       ext2fs_free_mem(&zero_buf);
-       (void) ext2fs_file_close(e2_file);
-       return retval;
-}
-
-
 void do_write(int argc, char *argv[])
 {
-       int             fd;
-       struct stat     statbuf;
-       ext2_ino_t      newfile;
        errcode_t       retval;
-       struct ext2_inode inode;
-       int             bufsize = IO_BUFSIZE;
-       int             make_holes = 0;
 
        if (common_args_process(argc, argv, 3, 3, "write",
                                "<native file> <new file>", CHECK_FS_RW))
                return;
 
-       fd = open(argv[1], O_RDONLY);
-       if (fd < 0) {
-               com_err(argv[1], errno, 0);
-               return;
-       }
-       if (fstat(fd, &statbuf) < 0) {
-               com_err(argv[1], errno, 0);
-               close(fd);
-               return;
-       }
-
-       retval = ext2fs_namei(current_fs, root, cwd, argv[2], &newfile);
-       if (retval == 0) {
-               com_err(argv[0], 0, "The file '%s' already exists\n", argv[2]);
-               close(fd);
-               return;
-       }
-
-       retval = ext2fs_new_inode(current_fs, cwd, 010755, 0, &newfile);
-       if (retval) {
+       retval = do_write_internal(current_fs, cwd, argv[1], argv[2], root);
+       if (retval)
                com_err(argv[0], retval, 0);
-               close(fd);
-               return;
-       }
-       printf("Allocated inode: %u\n", newfile);
-       retval = ext2fs_link(current_fs, cwd, argv[2], newfile,
-                            EXT2_FT_REG_FILE);
-       if (retval == EXT2_ET_DIR_NO_SPACE) {
-               retval = ext2fs_expand_dir(current_fs, cwd);
-               if (retval) {
-                       com_err(argv[0], retval, "while expanding directory");
-                       close(fd);
-                       return;
-               }
-               retval = ext2fs_link(current_fs, cwd, argv[2], newfile,
-                                    EXT2_FT_REG_FILE);
-       }
-       if (retval) {
-               com_err(argv[2], retval, 0);
-               close(fd);
-               return;
-       }
-        if (ext2fs_test_inode_bitmap2(current_fs->inode_map,newfile))
-               com_err(argv[0], 0, "Warning: inode already set");
-       ext2fs_inode_alloc_stats2(current_fs, newfile, +1, 0);
-       memset(&inode, 0, sizeof(inode));
-       inode.i_mode = (statbuf.st_mode & ~LINUX_S_IFMT) | LINUX_S_IFREG;
-       inode.i_atime = inode.i_ctime = inode.i_mtime =
-               current_fs->now ? current_fs->now : time(0);
-       inode.i_links_count = 1;
-       inode.i_size = statbuf.st_size;
-       if (current_fs->super->s_feature_incompat &
-           EXT3_FEATURE_INCOMPAT_EXTENTS) {
-               int i;
-               struct ext3_extent_header *eh;
-
-               eh = (struct ext3_extent_header *) &inode.i_block[0];
-               eh->eh_depth = 0;
-               eh->eh_entries = 0;
-               eh->eh_magic = ext2fs_cpu_to_le16(EXT3_EXT_MAGIC);
-               i = (sizeof(inode.i_block) - sizeof(*eh)) /
-                       sizeof(struct ext3_extent);
-               eh->eh_max = ext2fs_cpu_to_le16(i);
-               inode.i_flags |= EXT4_EXTENTS_FL;
-       }
-       if (debugfs_write_new_inode(newfile, &inode, argv[0])) {
-               close(fd);
-               return;
-       }
-       if (LINUX_S_ISREG(inode.i_mode)) {
-               if (statbuf.st_blocks < statbuf.st_size / S_BLKSIZE) {
-                       make_holes = 1;
-                       /*
-                        * Use I/O blocksize as buffer size when
-                        * copying sparse files.
-                        */
-                       bufsize = statbuf.st_blksize;
-               }
-               retval = copy_file(fd, newfile, bufsize, make_holes);
-               if (retval)
-                       com_err("copy_file", retval, 0);
-       }
-       close(fd);
 }
 
 void do_mknod(int argc, char *argv[])
 {
        unsigned long   mode, major, minor;
-       ext2_ino_t      newfile;
        errcode_t       retval;
-       struct ext2_inode inode;
        int             filetype, nr;
+       struct stat     st;
 
        if (check_fs_open(argv[0]))
                return;
@@ -1769,115 +1570,52 @@ void do_mknod(int argc, char *argv[])
                com_err(argv[0], 0, "Usage: mknod <name> [p| [c|b] <major> <minor>]");
                return;
        }
+
        mode = minor = major = 0;
        switch (argv[2][0]) {
                case 'p':
-                       mode = LINUX_S_IFIFO;
-                       filetype = EXT2_FT_FIFO;
+                       st.st_mode = S_IFIFO;
                        nr = 3;
                        break;
                case 'c':
-                       mode = LINUX_S_IFCHR;
-                       filetype = EXT2_FT_CHRDEV;
+                       st.st_mode = S_IFCHR;
                        nr = 5;
                        break;
                case 'b':
-                       mode = LINUX_S_IFBLK;
-                       filetype = EXT2_FT_BLKDEV;
+                       st.st_mode = S_IFBLK;
                        nr = 5;
                        break;
                default:
-                       filetype = 0;
                        nr = 0;
        }
+
        if (nr == 5) {
                major = strtoul(argv[3], argv+3, 0);
                minor = strtoul(argv[4], argv+4, 0);
                if (major > 65535 || minor > 65535 || argv[3][0] || argv[4][0])
                        nr = 0;
        }
+
        if (argc != nr)
                goto usage;
-       if (check_fs_read_write(argv[0]))
-               return;
-       retval = ext2fs_new_inode(current_fs, cwd, 010755, 0, &newfile);
-       if (retval) {
+
+       st.st_rdev = makedev(major, minor);
+       retval = do_mknod_internal(current_fs, cwd, argv[1], &st);
+       if (retval)
                com_err(argv[0], retval, 0);
-               return;
-       }
-       printf("Allocated inode: %u\n", newfile);
-       retval = ext2fs_link(current_fs, cwd, argv[1], newfile, filetype);
-       if (retval == EXT2_ET_DIR_NO_SPACE) {
-               retval = ext2fs_expand_dir(current_fs, cwd);
-               if (retval) {
-                       com_err(argv[0], retval, "while expanding directory");
-                       return;
-               }
-               retval = ext2fs_link(current_fs, cwd, argv[1], newfile,
-                                    filetype);
-       }
-       if (retval) {
-               com_err(argv[1], retval, 0);
-               return;
-       }
-        if (ext2fs_test_inode_bitmap2(current_fs->inode_map,newfile))
-               com_err(argv[0], 0, "Warning: inode already set");
-       ext2fs_inode_alloc_stats2(current_fs, newfile, +1, 0);
-       memset(&inode, 0, sizeof(inode));
-       inode.i_mode = mode;
-       inode.i_atime = inode.i_ctime = inode.i_mtime =
-               current_fs->now ? current_fs->now : time(0);
-       if ((major < 256) && (minor < 256)) {
-               inode.i_block[0] = major*256+minor;
-               inode.i_block[1] = 0;
-       } else {
-               inode.i_block[0] = 0;
-               inode.i_block[1] = (minor & 0xff) | (major << 8) | ((minor & ~0xff) << 12);
-       }
-       inode.i_links_count = 1;
-       if (debugfs_write_new_inode(newfile, &inode, argv[0]))
-               return;
 }
 
 void do_mkdir(int argc, char *argv[])
 {
-       char    *cp;
-       ext2_ino_t      parent;
-       char    *name;
        errcode_t retval;
 
        if (common_args_process(argc, argv, 2, 2, "mkdir",
                                "<filename>", CHECK_FS_RW))
                return;
 
-       cp = strrchr(argv[1], '/');
-       if (cp) {
-               *cp = 0;
-               parent = string_to_inode(argv[1]);
-               if (!parent) {
-                       com_err(argv[1], ENOENT, 0);
-                       return;
-               }
-               name = cp+1;
-       } else {
-               parent = cwd;
-               name = argv[1];
-       }
-
-try_again:
-       retval = ext2fs_mkdir(current_fs, parent, 0, name);
-       if (retval == EXT2_ET_DIR_NO_SPACE) {
-               retval = ext2fs_expand_dir(current_fs, parent);
-               if (retval) {
-                       com_err(argv[0], retval, "while expanding directory");
-                       return;
-               }
-               goto try_again;
-       }
-       if (retval) {
-               com_err("ext2fs_mkdir", retval, 0);
-               return;
-       }
+       retval = do_mkdir_internal(current_fs, cwd, argv[1], NULL, root);
+       if (retval)
+               com_err(argv[0], retval, 0);
 
 }
 
@@ -1903,11 +1641,10 @@ static void kill_file_by_inode(ext2_ino_t inode)
        inode_buf.i_dtime = current_fs->now ? current_fs->now : time(0);
        if (debugfs_write_inode(inode, &inode_buf, 0))
                return;
-       if (!ext2fs_inode_has_valid_blocks2(current_fs, &inode_buf))
-               return;
-
-       ext2fs_block_iterate3(current_fs, inode, BLOCK_FLAG_READ_ONLY, NULL,
-                             release_blocks_proc, NULL);
+       if (ext2fs_inode_has_valid_blocks2(current_fs, &inode_buf)) {
+               ext2fs_block_iterate3(current_fs, inode, BLOCK_FLAG_READ_ONLY,
+                                     NULL, release_blocks_proc, NULL);
+       }
        printf("\n");
        ext2fs_inode_alloc_stats2(current_fs, inode, -1,
                                  LINUX_S_ISDIR(inode_buf.i_mode));
@@ -1974,9 +1711,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;
@@ -2272,49 +2009,21 @@ void do_punch(int argc, char *argv[])
 
 void do_symlink(int argc, char *argv[])
 {
-       char            *cp;
-       ext2_ino_t      parent;
-       char            *name, *target;
        errcode_t       retval;
 
        if (common_args_process(argc, argv, 3, 3, "symlink",
                                "<filename> <target>", CHECK_FS_RW))
                return;
 
-       cp = strrchr(argv[1], '/');
-       if (cp) {
-               *cp = 0;
-               parent = string_to_inode(argv[1]);
-               if (!parent) {
-                       com_err(argv[1], ENOENT, 0);
-                       return;
-               }
-               name = cp+1;
-       } else {
-               parent = cwd;
-               name = argv[1];
-       }
-       target = argv[2];
-
-try_again:
-       retval = ext2fs_symlink(current_fs, parent, 0, name, target);
-       if (retval == EXT2_ET_DIR_NO_SPACE) {
-               retval = ext2fs_expand_dir(current_fs, parent);
-               if (retval) {
-                       com_err(argv[0], retval, "while expanding directory");
-                       return;
-               }
-               goto try_again;
-       }
-       if (retval) {
-               com_err("ext2fs_symlink", retval, 0);
-               return;
-       }
+       retval = do_symlink_internal(current_fs, cwd, argv[1], argv[2], root);
+       if (retval)
+               com_err(argv[0], retval, 0);
 
 }
 
 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;
@@ -2353,6 +2062,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)
@@ -2417,9 +2131,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)
@@ -2446,6 +2160,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 9b67f69c043fed9005f1291f56085d1b2492d742..df51aa06f9a9f4aa9d2cdee2ec0cba716fe1be08 100644 (file)
@@ -5,6 +5,7 @@
 #include "ss/ss.h"
 #include "ext2fs/ext2_fs.h"
 #include "ext2fs/ext2fs.h"
+#include "../misc/create_inode.h"
 #include "quota/quotaio.h"
 
 #ifdef __STDC__
@@ -180,6 +181,13 @@ extern void do_get_quota(int argc, char *argv[]);
 /* util.c */
 extern time_t string_to_time(const char *arg);
 
+/* xattrs.c */
+void dump_inode_attributes(FILE *out, ext2_ino_t ino);
+void do_get_xattr(int argc, char **argv);
+void do_set_xattr(int argc, char **argv);
+void do_rm_xattr(int argc, char **argv);
+void do_list_xattr(int argc, char **argv);
+
 /* zap.c */
 extern void do_zap_block(int argc, char **argv);
 extern void do_block_dump(int argc, char **argv);
index 51bc734aae938f55e21595f4ae34ca304c7fe99a..952a752d5ab870f2d9863d5ee2dcaa55d7ac47ed 100644 (file)
@@ -315,7 +315,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 0adea40582cf044f73905f8942d6e8adbf164c08..49345ad1fcea469fb517f08d0f71124e1d033067 100644 (file)
@@ -154,11 +154,13 @@ static void filefrag(ext2_ino_t ino, struct ext2_inode *inode,
                        fs->name, num_blocks, EXT2_I_SIZE(inode));
        }
        print_header(fs);
-       retval = ext2fs_block_iterate3(current_fs, ino,
-                                      BLOCK_FLAG_READ_ONLY, NULL,
-                                      filefrag_blocks_proc, fs);
-       if (retval)
-               com_err("ext2fs_block_iterate3", retval, 0);
+       if (ext2fs_inode_has_valid_blocks2(current_fs, inode)) {
+               retval = ext2fs_block_iterate3(current_fs, ino,
+                                              BLOCK_FLAG_READ_ONLY, NULL,
+                                              filefrag_blocks_proc, fs);
+               if (retval)
+                       com_err("ext2fs_block_iterate3", retval, 0);
+       }
 
        report_filefrag(fs);
        fprintf(fs->f, "%s: %d contiguous extents%s\n", fs->name, fs->ext,
@@ -183,7 +185,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 24f8250cad734e8db09b92be14aba5a1a309a5fd..4f0118dad09c7a7251ff7074b527398808dfe196 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 d2c3b301ac3e37b9657cd02e996a91136f05953a..9f9594f1fb0516ca5ad5a67fa79fa7840f8f6f98 100644 (file)
@@ -39,7 +39,7 @@ enum journal_location {JOURNAL_IS_INTERNAL, JOURNAL_IS_EXTERNAL};
 
 #define ANY_BLOCK ((blk64_t) -1)
 
-static int             dump_all, dump_contents, dump_descriptors;
+static int             dump_all, dump_old, dump_contents, dump_descriptors;
 static blk64_t         block_to_dump, bitmap_to_dump, inode_block_to_dump;
 static unsigned int    group_to_dump, inode_offset_to_dump;
 static ext2_ino_t      inode_to_dump;
@@ -94,6 +94,7 @@ void do_logdump(int argc, char **argv)
        journal_source.fd = 0;
        journal_source.file = 0;
        dump_all = 0;
+       dump_old = 0;
        dump_contents = 0;
        dump_descriptors = 1;
        block_to_dump = ANY_BLOCK;
@@ -102,7 +103,7 @@ void do_logdump(int argc, char **argv)
        inode_to_dump = -1;
 
        reset_getopt();
-       while ((c = getopt (argc, argv, "ab:ci:f:s")) != EOF) {
+       while ((c = getopt (argc, argv, "ab:ci:f:Os")) != EOF) {
                switch (c) {
                case 'a':
                        dump_all++;
@@ -126,6 +127,9 @@ void do_logdump(int argc, char **argv)
                        inode_spec = optarg;
                        dump_descriptors = 0;
                        break;
+               case 'O':
+                       dump_old++;
+                       break;
                case 's':
                        use_sb++;
                        break;
@@ -267,7 +271,7 @@ errout:
        return;
 
 print_usage:
-       fprintf(stderr, "%s: Usage: logdump [-acs] [-b<block>] [-i<filespec>]\n\t"
+       fprintf(stderr, "%s: Usage: logdump [-acsO] [-b<block>] [-i<filespec>]\n\t"
                "[-f<journal_file>] [output_file]\n", argv[0]);
 }
 
@@ -393,9 +397,13 @@ static void dump_journal(char *cmdname, FILE *out_file,
        fprintf(out_file, "Journal starts at block %u, transaction %u\n",
                blocknr, transaction);
 
-       if (!blocknr)
+       if (!blocknr) {
                /* Empty journal, nothing to do. */
-               return;
+               if (!dump_old)
+                       return;
+               else
+                       blocknr = 1;
+       }
 
        while (1) {
                retval = read_journal_block(cmdname, source,
@@ -420,7 +428,8 @@ static void dump_journal(char *cmdname, FILE *out_file,
                        fprintf (out_file, "Found sequence %u (not %u) at "
                                 "block %u: end of journal.\n",
                                 sequence, transaction, blocknr);
-                       return;
+                       if (!dump_old)
+                               return;
                }
 
                if (dump_descriptors) {
@@ -500,7 +509,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;
@@ -526,28 +535,37 @@ static void dump_revoke_block(FILE *out_file, char *buf,
 {
        int                     offset, max;
        journal_revoke_header_t *header;
-       unsigned int            *entry, rblock;
+       unsigned long long      rblock;
+       int                     tag_size = sizeof(__u32);
 
        if (dump_all)
                fprintf(out_file, "Dumping revoke block, sequence %u, at "
                        "block %u:\n", transaction, blocknr);
 
+       if (be32_to_cpu(jsb->s_feature_incompat) & JFS_FEATURE_INCOMPAT_64BIT)
+               tag_size = sizeof(__u64);
+
        header = (journal_revoke_header_t *) buf;
        offset = sizeof(journal_revoke_header_t);
        max = be32_to_cpu(header->r_count);
 
        while (offset < max) {
-               entry = (unsigned int *) (buf + offset);
-               rblock = be32_to_cpu(*entry);
+               if (tag_size == sizeof(__u32)) {
+                       __u32 *entry = (__u32 *) (buf + offset);
+                       rblock = be32_to_cpu(*entry);
+               } else {
+                       __u64 *entry = (__u64 *) (buf + offset);
+                       rblock = ext2fs_be64_to_cpu(*entry);
+               }
                if (dump_all || rblock == block_to_dump) {
-                       fprintf(out_file, "  Revoke FS block %u", rblock);
+                       fprintf(out_file, "  Revoke FS block %llu", rblock);
                        if (dump_all)
                                fprintf(out_file, "\n");
                        else
                                fprintf(out_file," at block %u, sequence %u\n",
                                        blocknr, transaction);
                }
-               offset += 4;
+               offset += tag_size;
        }
 }
 
index b4036de0c9303ad1f709342788db362d5d658474..69c7897379fa3c4c59fab9f743020db86f8e5777 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 e5b2d203bacb8207984cdf858cb40e1ece98720b..5276014f00cdce9c4581706facaec495bdb99328 100644 (file)
@@ -141,15 +141,19 @@ void do_lsdel(int argc, char **argv)
                lsd.free_blocks = 0;
                lsd.bad_blocks = 0;
 
-               retval = ext2fs_block_iterate3(current_fs, ino,
-                                              BLOCK_FLAG_READ_ONLY, block_buf,
-                                              lsdel_proc, &lsd);
-               if (retval) {
-                       com_err("ls_deleted_inodes", retval,
-                               "while calling ext2fs_block_iterate2");
-                       goto next;
+               if (ext2fs_inode_has_valid_blocks2(current_fs, &inode)) {
+                       retval = ext2fs_block_iterate3(current_fs, ino,
+                                                      BLOCK_FLAG_READ_ONLY,
+                                                      block_buf,
+                                                      lsdel_proc, &lsd);
+                       if (retval) {
+                               com_err("ls_deleted_inodes", retval,
+                                       "while calling ext2fs_block_iterate2");
+                               goto next;
+                       }
                }
-               if (lsd.free_blocks && !lsd.bad_blocks) {
+               if (lsd.free_blocks && !lsd.bad_blocks ||
+                   inode.i_flags & EXT4_INLINE_DATA_FL) {
                        if (num_delarray >= max_delarray) {
                                max_delarray += 50;
                                delarray = realloc(delarray,
index 58f3a503d83b7977a629606a1ff6f31861dee1ee..5d9b5d21c27e0630125f23e18b6e5fd4320c0197 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 ffbda74671d838da0679ed7aa8ad22efbe84058a..762e6558265c9b6fd5f57a34490a41365eced144 100644 (file)
@@ -153,6 +153,7 @@ static struct field_set_info super_fields[] = {
        { "backup_bgs", &set_sb.s_backup_bgs[0], NULL, 4, parse_uint,
          FLAG_ARRAY, 2 },
        { "checksum", &set_sb.s_checksum, NULL, 4, parse_uint },
+       { "checksum_type", &set_sb.s_checksum_type, NULL, 1, parse_uint },
        { 0, 0, 0, 0 }
 };
 
@@ -257,6 +258,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)
@@ -771,6 +773,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.";
@@ -825,5 +828,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 9ddfe0ba089a989d3c8980e2b938b007a13f641d..5cc4e22b58af16b13c398248f68d33e9c7e45664 100644 (file)
@@ -201,7 +201,7 @@ char *time_to_string(__u32 cl)
                tz = ss_safe_getenv("TZ");
                if (!tz)
                        tz = "";
-               do_gmt = !strcmp(tz, "GMT") | !strcmp(tz, "GMT0");
+               do_gmt = !strcmp(tz, "GMT") || !strcmp(tz, "GMT0");
        }
 
        return asctime((do_gmt) ? gmtime(&t) : localtime(&t));
diff --git a/debugfs/xattrs.c b/debugfs/xattrs.c
new file mode 100644 (file)
index 0000000..7109719
--- /dev/null
@@ -0,0 +1,299 @@
+/*
+ * xattrs.c --- Modify extended attributes via debugfs.
+ *
+ * Copyright (C) 2014 Oracle.  This file may be redistributed
+ * under the terms of the GNU Public License.
+ */
+
+#include "config.h"
+#include <stdio.h>
+#ifdef HAVE_GETOPT_H
+#include <getopt.h>
+#else
+extern int optind;
+extern char *optarg;
+#endif
+#include <ctype.h>
+
+#include "debugfs.h"
+
+/* Dump extended attributes */
+static void dump_xattr_string(FILE *out, const char *str, int len)
+{
+       int printable = 0;
+       int i;
+
+       /* check: is string "printable enough?" */
+       for (i = 0; i < len; i++)
+               if (isprint(str[i]))
+                       printable++;
+
+       if (printable <= len*7/8)
+               printable = 0;
+
+       for (i = 0; i < len; i++)
+               if (printable)
+                       fprintf(out, isprint(str[i]) ? "%c" : "\\%03o",
+                               (unsigned char)str[i]);
+               else
+                       fprintf(out, "%02x ", (unsigned char)str[i]);
+}
+
+static int dump_attr(char *name, char *value, size_t value_len, void *data)
+{
+       FILE *out = data;
+
+       fprintf(out, "  ");
+       dump_xattr_string(out, name, strlen(name));
+       fprintf(out, " = \"");
+       dump_xattr_string(out, value, value_len);
+       fprintf(out, "\" (%zu)\n", value_len);
+
+       return 0;
+}
+
+void dump_inode_attributes(FILE *out, ext2_ino_t ino)
+{
+       struct ext2_xattr_handle *h;
+       size_t sz;
+       errcode_t err;
+
+       err = ext2fs_xattrs_open(current_fs, ino, &h);
+       if (err)
+               return;
+
+       err = ext2fs_xattrs_read(h);
+       if (err)
+               goto out;
+
+       err = ext2fs_xattrs_count(h, &sz);
+       if (err || sz == 0)
+               goto out;
+
+       fprintf(out, "Extended attributes:\n");
+       err = ext2fs_xattrs_iterate(h, dump_attr, out);
+       if (err)
+               goto out;
+
+out:
+       err = ext2fs_xattrs_close(&h);
+}
+
+void do_list_xattr(int argc, char **argv)
+{
+       ext2_ino_t ino;
+
+       if (argc != 2) {
+               printf("%s: Usage: %s <file>\n", argv[0],
+                      argv[0]);
+               return;
+       }
+
+       if (check_fs_open(argv[0]))
+               return;
+
+       ino = string_to_inode(argv[1]);
+       if (!ino)
+               return;
+
+       dump_inode_attributes(stdout, ino);
+}
+
+void do_get_xattr(int argc, char **argv)
+{
+       ext2_ino_t ino;
+       struct ext2_xattr_handle *h;
+       FILE *fp = NULL;
+       char *buf = NULL;
+       size_t buflen;
+       int i;
+       errcode_t err;
+
+       reset_getopt();
+       while ((i = getopt(argc, argv, "f:")) != -1) {
+               switch (i) {
+               case 'f':
+                       fp = fopen(optarg, "w");
+                       if (fp == NULL) {
+                               perror(optarg);
+                               return;
+                       }
+                       break;
+               default:
+                       printf("%s: Usage: %s <file> <attr> [-f outfile]\n",
+                              argv[0], argv[0]);
+                       goto out2;
+               }
+       }
+
+       if (optind != argc - 2) {
+               printf("%s: Usage: %s <file> <attr> [-f outfile]\n", argv[0],
+                      argv[0]);
+               goto out2;
+       }
+
+       if (check_fs_open(argv[0]))
+               goto out2;
+
+       ino = string_to_inode(argv[optind]);
+       if (!ino)
+               goto out2;
+
+       err = ext2fs_xattrs_open(current_fs, ino, &h);
+       if (err)
+               goto out2;
+
+       err = ext2fs_xattrs_read(h);
+       if (err)
+               goto out;
+
+       err = ext2fs_xattr_get(h, argv[optind + 1], (void **)&buf, &buflen);
+       if (err)
+               goto out;
+
+       if (fp) {
+               fwrite(buf, buflen, 1, fp);
+       } else {
+               dump_xattr_string(stdout, buf, buflen);
+               printf("\n");
+       }
+
+       ext2fs_free_mem(&buf);
+out:
+       ext2fs_xattrs_close(&h);
+       if (err)
+               com_err(argv[0], err, "while getting extended attribute");
+out2:
+       if (fp)
+               fclose(fp);
+}
+
+void do_set_xattr(int argc, char **argv)
+{
+       ext2_ino_t ino;
+       struct ext2_xattr_handle *h;
+       FILE *fp = NULL;
+       char *buf = NULL;
+       size_t buflen;
+       int i;
+       errcode_t err;
+
+       reset_getopt();
+       while ((i = getopt(argc, argv, "f:")) != -1) {
+               switch (i) {
+               case 'f':
+                       fp = fopen(optarg, "r");
+                       if (fp == NULL) {
+                               perror(optarg);
+                               return;
+                       }
+                       break;
+               default:
+                       printf("%s: Usage: %s <file> <attr> [-f infile | "
+                              "value]\n", argv[0], argv[0]);
+                       goto out2;
+               }
+       }
+
+       if (optind != argc - 2 && optind != argc - 3) {
+               printf("%s: Usage: %s <file> <attr> [-f infile | value>]\n",
+                      argv[0], argv[0]);
+               goto out2;
+       }
+
+       if (check_fs_open(argv[0]))
+               goto out2;
+       if (check_fs_read_write(argv[0]))
+               goto out2;
+       if (check_fs_bitmaps(argv[0]))
+               goto out2;
+
+       ino = string_to_inode(argv[optind]);
+       if (!ino)
+               goto out2;
+
+       err = ext2fs_xattrs_open(current_fs, ino, &h);
+       if (err)
+               goto out2;
+
+       err = ext2fs_xattrs_read(h);
+       if (err)
+               goto out;
+
+       if (fp) {
+               err = ext2fs_get_mem(current_fs->blocksize, &buf);
+               if (err)
+                       goto out;
+               buflen = fread(buf, 1, current_fs->blocksize, fp);
+       } else {
+               buf = argv[optind + 2];
+               buflen = strlen(argv[optind + 2]);
+       }
+
+       err = ext2fs_xattr_set(h, argv[optind + 1], buf, buflen);
+       if (err)
+               goto out;
+
+       err = ext2fs_xattrs_write(h);
+       if (err)
+               goto out;
+
+out:
+       ext2fs_xattrs_close(&h);
+       if (err)
+               com_err(argv[0], err, "while setting extended attribute");
+out2:
+       if (fp) {
+               fclose(fp);
+               ext2fs_free_mem(&buf);
+       }
+}
+
+void do_rm_xattr(int argc, char **argv)
+{
+       ext2_ino_t ino;
+       struct ext2_xattr_handle *h;
+       int i;
+       errcode_t err;
+
+       if (argc < 3) {
+               printf("%s: Usage: %s <file> <attrs>...\n", argv[0], argv[0]);
+               return;
+       }
+
+       if (check_fs_open(argv[0]))
+               return;
+       if (check_fs_read_write(argv[0]))
+               return;
+       if (check_fs_bitmaps(argv[0]))
+               return;
+
+       ino = string_to_inode(argv[1]);
+       if (!ino)
+               return;
+
+       err = ext2fs_xattrs_open(current_fs, ino, &h);
+       if (err)
+               return;
+
+       err = ext2fs_xattrs_read(h);
+       if (err)
+               goto out;
+
+       for (i = 2; i < argc; i++) {
+               size_t buflen;
+               char *buf;
+
+               err = ext2fs_xattr_remove(h, argv[i]);
+               if (err)
+                       goto out;
+       }
+
+       err = ext2fs_xattrs_write(h);
+       if (err)
+               goto out;
+out:
+       ext2fs_xattrs_close(&h);
+       if (err)
+               com_err(argv[0], err, "while removing extended attribute");
+}
index 4b10f6fdd8dcabdddf265829186ca83c6bf5346e..9134957993732f870fdc690cc67ed38f30bef46d 100644 (file)
@@ -40,6 +40,7 @@ COMPILE_ET=$(top_builddir)/lib/et/compile_et --build-tree
        $(E) "  CC $<"
        $(Q) $(CC) -c $(ALL_CFLAGS) $< -o $@
        $(Q) $(CHECK_CMD) $(ALL_CFLAGS) $<
+       $(Q) $(CPPCHECK_CMD) $(CPPFLAGS) $<
 @PROFILE_CMT@  $(Q) $(CC) $(ALL_CFLAGS) -g -pg -o profiled/$*.o -c $<
 
 #
@@ -66,7 +67,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 \
@@ -80,12 +81,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 \
@@ -136,15 +135,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) \
@@ -156,10 +146,6 @@ tst_problem: $(srcdir)/problem.c $(srcdir)/problem.h $(LIBEXT2FS) \
                $(srcdir)/problem.c -DUNITTEST $(LIBEXT2FS) $(LIBCOM_ERR) \
                $(LIBINTL) $(SYSLIBS)
 
-tst_crc32: $(srcdir)/crc32.c $(LIBEXT2FS) $(DEPLIBCOM_ERR)
-       $(Q) $(CC) $(BUILD_LDFLAGS) $(ALL_CFLAGS) -o tst_crc32 $(srcdir)/crc32.c \
-               -DUNITTEST $(LIBEXT2FS) $(LIBCOM_ERR) $(SYSLIBS)
-
 tst_refcount: ea_refcount.c $(DEPLIBCOM_ERR)
        $(E) "  LD $@"
        $(Q) $(CC) -o tst_refcount $(srcdir)/ea_refcount.c \
@@ -176,10 +162,9 @@ tst_region: region.c $(DEPLIBCOM_ERR)
        $(Q) $(CC) -o tst_region $(srcdir)/region.c \
                $(ALL_CFLAGS) -DTEST_PROGRAM $(LIBCOM_ERR) $(SYSLIBS)
 
-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
@@ -276,9 +261,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
@@ -297,20 +281,10 @@ e2fsck.o: $(srcdir)/e2fsck.c $(top_builddir)/lib/config.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/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/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
+ $(srcdir)/profile.h prof_err.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
 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 c71a0a5471e0101fc61fbe1a466c76e238aeef99..331306f12d86c1f308b787745b90459495348d78 100644 (file)
@@ -406,9 +406,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);
@@ -494,6 +491,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 bfc1bcdee518973887fa17804518693d6c4a990e..3cccd3fad650538ab26a670a7e3a4f4e0259ad06 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 11ccec586f8e37a9fb286be2022ff22db730e08e..a7b1150e9b77185b70e43cc52f70e3fde1886048 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 7b8435945f0a6eb12b0f7216a73ad8f8d606465e..6c1d0bf05ddb7820d91dc5a529c00022c3ea71c5 100644 (file)
@@ -374,7 +374,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;
@@ -385,10 +385,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 9ef724ade750332618e79770332cb81703672ce0..180ecc8303078e99bfead58268fdb265b24bb153 100644 (file)
@@ -177,7 +177,8 @@ int e2fsck_pass1_check_symlink(ext2_filsys fs, ext2_ino_t ino,
        struct ext2fs_extent    extent;
 
        if ((inode->i_size_high || inode->i_size == 0) ||
-           (inode->i_flags & EXT2_INDEX_FL))
+           (inode->i_flags & EXT2_INDEX_FL) ||
+           (inode->i_flags & EXT4_INLINE_DATA_FL))
                return 0;
 
        if (inode->i_flags & EXT4_EXTENTS_FL) {
@@ -407,6 +408,7 @@ static void check_is_really_dir(e2fsck_t ctx, struct problem_context *pctx,
        blk64_t                 blk;
        unsigned int            i, rec_len, not_device = 0;
        int                     extent_fs;
+       int                     inlinedata_fs;
 
        /*
         * If the mode looks OK, we believe it.  If the first block in
@@ -434,11 +436,23 @@ static void check_is_really_dir(e2fsck_t ctx, struct problem_context *pctx,
         * For extent mapped files, we don't do any sanity checking:
         * just try to get the phys block of logical block 0 and run
         * with it.
+        *
+        * For inline data files, we just try to get the size of inline
+        * data.  If it's true, we will treat it as a directory.
         */
 
        extent_fs = (ctx->fs->super->s_feature_incompat &
                     EXT3_FEATURE_INCOMPAT_EXTENTS);
-       if (extent_fs && (inode->i_flags & EXT4_EXTENTS_FL)) {
+       inlinedata_fs = (ctx->fs->super->s_feature_incompat &
+                        EXT4_FEATURE_INCOMPAT_INLINE_DATA);
+       if (inlinedata_fs && (inode->i_flags & EXT4_INLINE_DATA_FL)) {
+               size_t size;
+
+               if (ext2fs_inline_data_size(ctx->fs, pctx->ino, &size))
+                       return;
+               /* device files never have a "system.data" entry */
+               goto isdir;
+       } else if (extent_fs && (inode->i_flags & EXT4_EXTENTS_FL)) {
                /* extent mapped */
                if  (ext2fs_bmap2(ctx->fs, pctx->ino, inode, 0, 0, 0, 0,
                                 &blk))
@@ -473,7 +487,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 +496,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,13 +508,14 @@ 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) ||
            (rec_len % 4))
                return;
 
+isdir:
        if (fix_problem(ctx, PR_1_TREAT_AS_DIRECTORY, pctx)) {
                inode->i_mode = (inode->i_mode & 07777) | LINUX_S_IFDIR;
                e2fsck_write_inode_full(ctx, pctx->ino, inode,
@@ -540,6 +555,40 @@ 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;
@@ -558,9 +607,10 @@ void e2fsck_pass1(e2fsck_t ctx)
        struct ext2_super_block *sb = ctx->fs->super;
        const char      *old_op;
        unsigned int    save_type;
-       int             imagic_fs, extent_fs;
+       int             imagic_fs, extent_fs, inlinedata_fs;
        int             low_dtime_check = 1;
        int             inode_size;
+       int             failed_csum = 0;
 
        init_resource_track(&rtrack, ctx->fs->io);
        clear_problem_context(&pctx);
@@ -591,6 +641,8 @@ void e2fsck_pass1(e2fsck_t ctx)
 
        imagic_fs = (sb->s_feature_compat & EXT2_FEATURE_COMPAT_IMAGIC_INODES);
        extent_fs = (sb->s_feature_incompat & EXT3_FEATURE_INCOMPAT_EXTENTS);
+       inlinedata_fs = (sb->s_feature_incompat &
+                       EXT4_FEATURE_INCOMPAT_INLINE_DATA);
 
        /*
         * Allocate bitmaps structures
@@ -689,7 +741,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);
@@ -719,6 +772,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))
@@ -737,7 +793,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;
                        goto endit;
@@ -747,6 +804,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);
@@ -758,6 +823,24 @@ void e2fsck_pass1(e2fsck_t ctx)
                        }
                }
 
+               /* Test for incorrect inline_data flags settings. */
+               if ((inode->i_flags & EXT4_INLINE_DATA_FL) && !inlinedata_fs &&
+                   (ino >= EXT2_FIRST_INODE(fs->super))) {
+                       size_t size = 0;
+
+                       pctx.errcode = ext2fs_inline_data_size(fs, ino, &size);
+                       if (!pctx.errcode && size &&
+                           !fix_problem(ctx, PR_1_INLINE_DATA_FEATURE, &pctx)) {
+                               sb->s_feature_incompat |=
+                                       EXT4_FEATURE_INCOMPAT_INLINE_DATA;
+                               ext2fs_mark_super_dirty(fs);
+                               inlinedata_fs = 1;
+                       } else if (!fix_problem(ctx, PR_1_INLINE_DATA_SET, &pctx)) {
+                               e2fsck_clear_inode(ctx, ino, inode, 0, "pass1");
+                               continue;
+                       }
+               }
+
                /*
                 * Test for incorrect extent flag settings.
                 *
@@ -1124,7 +1207,8 @@ void e2fsck_pass1(e2fsck_t ctx)
                        ctx->fs_sockets_count++;
                } else
                        mark_inode_bad(ctx, ino);
-               if (!(inode->i_flags & EXT4_EXTENTS_FL)) {
+               if (!(inode->i_flags & EXT4_EXTENTS_FL) &&
+                   !(inode->i_flags & EXT4_INLINE_DATA_FL)) {
                        if (inode->i_block[EXT2_IND_BLOCK])
                                ctx->fs_ind_count++;
                        if (inode->i_block[EXT2_DIND_BLOCK])
@@ -1133,6 +1217,7 @@ void e2fsck_pass1(e2fsck_t ctx)
                                ctx->fs_tind_count++;
                }
                if (!(inode->i_flags & EXT4_EXTENTS_FL) &&
+                   !(inode->i_flags & EXT4_INLINE_DATA_FL) &&
                    (inode->i_block[EXT2_IND_BLOCK] ||
                     inode->i_block[EXT2_DIND_BLOCK] ||
                     inode->i_block[EXT2_TIND_BLOCK] ||
@@ -1143,6 +1228,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)
                        goto endit;
 
@@ -1239,6 +1338,12 @@ endit:
        if (inode)
                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;
+
        if ((ctx->flags & E2F_FLAG_SIGNAL_MASK) == 0)
                print_resource_track(ctx, _("Pass 1"), &rtrack, ctx->fs->io);
 }
@@ -1469,7 +1574,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;
@@ -1480,8 +1586,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);
@@ -1506,6 +1613,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)
@@ -1579,7 +1687,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;
@@ -1661,6 +1774,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);
@@ -1775,6 +1900,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)
@@ -1782,12 +1908,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))
@@ -1809,6 +1949,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;
@@ -1816,6 +1967,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);
@@ -1845,7 +1997,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;
                        }
@@ -1997,6 +2152,28 @@ static void check_blocks_extents(e2fsck_t ctx, struct problem_context *pctx,
        ext2fs_extent_free(ehandle);
 }
 
+/*
+ * In fact we don't need to check blocks for an inode with inline data
+ * because this inode doesn't have any blocks.  In this function all
+ * we need to do is add this inode into dblist when it is a directory.
+ */
+static void check_blocks_inline_data(e2fsck_t ctx, struct problem_context *pctx,
+                                    struct process_block_struct *pb)
+{
+       if (!pb->is_dir) {
+               pctx->errcode = 0;
+               return;
+       }
+
+       pctx->errcode = ext2fs_add_dir_block2(ctx->fs->dblist, pb->ino, 0, 0);
+       if (pctx->errcode) {
+               pctx->blk = 0;
+               pctx->num = 0;
+               fix_problem(ctx, PR_1_ADD_DBLOCK, pctx);
+               ctx->flags |= E2F_FLAG_ABORT;
+       }
+}
+
 /*
  * This subroutine is called on each inode to account for all of the
  * blocks used by that inode.
@@ -2011,6 +2188,7 @@ static void check_blocks(e2fsck_t ctx, struct problem_context *pctx,
        unsigned        bad_size = 0;
        int             dirty_inode = 0;
        int             extent_fs;
+       int             inlinedata_fs;
        __u64           size;
 
        pb.ino = ino;
@@ -2034,6 +2212,8 @@ static void check_blocks(e2fsck_t ctx, struct problem_context *pctx,
 
        extent_fs = (ctx->fs->super->s_feature_incompat &
                      EXT3_FEATURE_INCOMPAT_EXTENTS);
+       inlinedata_fs = (ctx->fs->super->s_feature_incompat &
+                        EXT4_FEATURE_INCOMPAT_INLINE_DATA);
 
        if (inode->i_flags & EXT2_COMPRBLK_FL) {
                if (fs->super->s_feature_incompat &
@@ -2067,6 +2247,10 @@ static void check_blocks(e2fsck_t ctx, struct problem_context *pctx,
                         */
                        pb.last_init_lblock = pb.last_block;
                }
+       } else {
+               /* check inline data */
+               if (inlinedata_fs && (inode->i_flags & EXT4_INLINE_DATA_FL))
+                       check_blocks_inline_data(ctx, pctx, &pb);
        }
        end_problem_latch(ctx, PR_LATCH_BLOCK);
        end_problem_latch(ctx, PR_LATCH_TOOBIG);
@@ -2099,7 +2283,8 @@ static void check_blocks(e2fsck_t ctx, struct problem_context *pctx,
                }
        }
 
-       if (!pb.num_blocks && pb.is_dir) {
+       if (!pb.num_blocks && pb.is_dir &&
+           !(inode->i_flags & EXT4_INLINE_DATA_FL)) {
                if (fix_problem(ctx, PR_1_ZERO_LENGTH_DIR, pctx)) {
                        e2fsck_clear_inode(ctx, ino, inode, 0, "check_blocks");
                        ctx->fs_directory_count--;
@@ -2125,7 +2310,14 @@ static void check_blocks(e2fsck_t ctx, struct problem_context *pctx,
 #endif
        if (pb.is_dir) {
                int nblock = inode->i_size >> EXT2_BLOCK_SIZE_BITS(fs->super);
-               if (inode->i_size & (fs->blocksize - 1))
+               if (inode->i_flags & EXT4_INLINE_DATA_FL) {
+                       size_t size;
+
+                       if (ext2fs_inline_data_size(ctx->fs, pctx->ino, &size))
+                               bad_size = 5;
+                       if (size != inode->i_size)
+                               bad_size = 5;
+               } else if (inode->i_size & (fs->blocksize - 1))
                        bad_size = 5;
                else if (nblock > (pb.last_block + 1))
                        bad_size = 1;
@@ -2185,9 +2377,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 13bd9e98150eb89c6599fdb793cdd8fc78767acd..d7c5e551d18841c045a395ae660e3b248d14a83f 100644 (file)
@@ -262,6 +262,7 @@ struct process_block_struct {
        ext2_ino_t      ino;
        int             dup_blocks;
        blk64_t         cur_cluster;
+       blk64_t         last_blk;
        struct ext2_inode *inode;
        struct problem_context *pctx;
 };
@@ -274,6 +275,7 @@ static void pass1b(e2fsck_t ctx, char *block_buf)
        ext2_inode_scan scan;
        struct process_block_struct pb;
        struct problem_context pctx;
+       problem_t op;
 
        clear_problem_context(&pctx);
 
@@ -314,6 +316,8 @@ static void pass1b(e2fsck_t ctx, char *block_buf)
                pb.dup_blocks = 0;
                pb.inode = &inode;
                pb.cur_cluster = ~0;
+               pb.last_blk = 0;
+               pb.pctx->blk = pb.pctx->blk2 = 0;
 
                if (ext2fs_inode_has_valid_blocks2(fs, &inode) ||
                    (ino == EXT2_BAD_INO))
@@ -329,6 +333,11 @@ static void pass1b(e2fsck_t ctx, char *block_buf)
                        ext2fs_file_acl_block_set(fs, &inode, blk);
                }
                if (pb.dup_blocks) {
+                       if (ino != EXT2_BAD_INO) {
+                               op = pctx.blk == pctx.blk2 ?
+                                       PR_1B_DUP_BLOCK : PR_1B_DUP_RANGE;
+                               fix_problem(ctx, op, pb.pctx);
+                       }
                        end_problem_latch(ctx, PR_LATCH_DBLOCK);
                        if (ino >= EXT2_FIRST_INODE(fs->super) ||
                            ino == EXT2_ROOT_INO)
@@ -351,6 +360,7 @@ static int process_pass1b_block(ext2_filsys fs EXT2FS_ATTR((unused)),
        struct process_block_struct *p;
        e2fsck_t ctx;
        blk64_t lc;
+       problem_t op;
 
        if (HOLE_BLKADDR(*block_nr))
                return 0;
@@ -363,8 +373,17 @@ static int process_pass1b_block(ext2_filsys fs EXT2FS_ATTR((unused)),
 
        /* OK, this is a duplicate block */
        if (p->ino != EXT2_BAD_INO) {
-               p->pctx->blk = *block_nr;
-               fix_problem(ctx, PR_1B_DUP_BLOCK, p->pctx);
+               if (p->last_blk + 1 != *block_nr) {
+                       if (p->last_blk) {
+                               op = p->pctx->blk == p->pctx->blk2 ?
+                                               PR_1B_DUP_BLOCK :
+                                               PR_1B_DUP_RANGE;
+                               fix_problem(ctx, op, p->pctx);
+                       }
+                       p->pctx->blk = *block_nr;
+               }
+               p->pctx->blk2 = *block_nr;
+               p->last_blk = *block_nr;
        }
        p->dup_blocks++;
        ext2fs_mark_inode_bitmap2(inode_dup_map, p->ino);
@@ -654,9 +673,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 7277a7b3f3c5f62c8dcae4e488ac4913b5de479a..5488c73ee8328159aac1cf7d9073c696e3bd03a7 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,11 +724,21 @@ 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;
        }
 }
 
+static int is_last_entry(ext2_filsys fs, int inline_data_size,
+                        unsigned int offset, int csum_size)
+{
+       if (inline_data_size)
+               return (offset < inline_data_size);
+       else
+               return (offset < fs->blocksize - csum_size);
+}
+
 static int check_dir_block(ext2_filsys fs,
                           struct ext2_db_entry2 *db,
                           void *priv_data)
@@ -714,7 +747,7 @@ static int check_dir_block(ext2_filsys fs,
 #ifdef ENABLE_HTREE
        struct dx_dirblock_info *dx_db = 0;
 #endif /* ENABLE_HTREE */
-       struct ext2_dir_entry   *dirent, *prev;
+       struct ext2_dir_entry   *dirent, *prev, dot, dotdot;
        ext2_dirhash_t          hash;
        unsigned int            offset = 0;
        int                     dir_modified = 0;
@@ -734,6 +767,11 @@ 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;
+       size_t  inline_data_size = 0;
+       int     filetype = 0;
 
        cd = (struct check_dir_struct *) priv_data;
        buf = cd->buf;
@@ -745,6 +783,16 @@ 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);
+       }
+
+       if (EXT2_HAS_INCOMPAT_FEATURE(fs->super,
+                                     EXT2_FEATURE_INCOMPAT_FILETYPE))
+               filetype = EXT2_FT_DIR << 8;
+
        /*
         * Make sure the inode is still in use (could have been
         * deleted in the duplicate/bad blocks pass.
@@ -759,7 +807,16 @@ static int check_dir_block(ext2_filsys fs,
        cd->pctx.dirent = 0;
        cd->pctx.num = 0;
 
-       if (db->blk == 0) {
+       if (EXT2_HAS_INCOMPAT_FEATURE(fs->super,
+                                     EXT4_FEATURE_INCOMPAT_INLINE_DATA)) {
+               errcode_t ec;
+
+               ec = ext2fs_inline_data_size(fs, ino, &inline_data_size);
+               if (ec && ec != EXT2_ET_NO_INLINE_DATA)
+                       return DIRENT_ABORT;
+       }
+
+       if (db->blk == 0 && !inline_data_size) {
                if (allocate_dir_block(ctx, db, buf, &cd->pctx))
                        return 0;
                block_nr = db->blk;
@@ -780,16 +837,28 @@ 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);
+       if (inline_data_size)
+               cd->pctx.errcode = ext2fs_inline_data_get(fs, ino, 0, buf, 0);
+       else
+               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,36 +901,94 @@ 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 && !inline_data_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);
-               (void) ext2fs_get_rec_len(fs, dirent, &rec_len);
-               cd->pctx.dirent = dirent;
-               cd->pctx.num = offset;
-               if (((offset + rec_len) > fs->blocksize) ||
-                   (rec_len < 12) ||
-                   ((rec_len % 4) != 0) ||
-                   (((dirent->name_len & (unsigned) 0xFF)+8) > rec_len)) {
-                       if (fix_problem(ctx, PR_2_DIR_CORRUPTED, &cd->pctx)) {
-                               salvage_directory(fs, dirent, prev, &offset);
-                               dir_modified++;
-                               continue;
-                       } else
-                               goto abort_free_dict;
+               if (!inline_data_size || dot_state > 1) {
+                       dirent = (struct ext2_dir_entry *) (buf + offset);
+                       (void) ext2fs_get_rec_len(fs, dirent, &rec_len);
+                       cd->pctx.dirent = dirent;
+                       cd->pctx.num = offset;
+                       if (((offset + rec_len) > fs->blocksize) ||
+                           (rec_len < 12) ||
+                           ((rec_len % 4) != 0) ||
+                           ((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++;
+                                       continue;
+                               } else
+                                       goto abort_free_dict;
+                       }
+               } else {
+                       if (dot_state == 0) {
+                               memset(&dot, 0, sizeof(dot));
+                               dirent = &dot;
+                               dirent->inode = ino;
+                               dirent->rec_len = EXT2_DIR_REC_LEN(1);
+                               dirent->name_len = 1 | filetype;
+                               dirent->name[0] = '.';
+                       } else if (dot_state == 1) {
+                               memset(&dotdot, 0, sizeof(dotdot));
+                               dirent = &dotdot;
+                               dirent->inode =
+                                       ((struct ext2_dir_entry *)buf)->inode;
+                               dirent->rec_len = EXT2_DIR_REC_LEN(2);
+                               dirent->name_len = 2 | filetype;
+                               dirent->name[0] = '.';
+                               dirent->name[1] = '.';
+                       } else {
+                               fatal_error(ctx, _("Can not continue."));
+                       }
+                       cd->pctx.dirent = dirent;
+                       cd->pctx.num = offset;
                }
 
                if (dot_state == 0) {
@@ -887,6 +1014,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 +1027,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 +1035,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 +1053,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 +1166,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 +1213,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);
@@ -1105,9 +1227,14 @@ out_htree:
                prev = dirent;
                if (dir_modified)
                        (void) ext2fs_get_rec_len(fs, dirent, &rec_len);
-               offset += rec_len;
+               if (!inline_data_size || dot_state > 1) {
+                       offset += rec_len;
+               } else {
+                       if (dot_state == 1)
+                               offset = 4;
+               }
                dot_state++;
-       } while (offset < fs->blocksize);
+       } while (is_last_entry(fs, inline_data_size, offset, de_csum_size));
 #if 0
        printf("\n");
 #endif
@@ -1121,24 +1248,62 @@ 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 (fix_problem(ctx, PR_2_FINAL_RECLEN, &cd->pctx)) {
-                       dirent->rec_len = cd->pctx.num;
-                       dir_modified++;
+
+       if (inline_data_size) {
+               if (offset != inline_data_size) {
+                       cd->pctx.num = rec_len + offset - inline_data_size;
+                       if (fix_problem(ctx, PR_2_FINAL_RECLEN, &cd->pctx)) {
+                               dirent->rec_len = cd->pctx.num;
+                               dir_modified++;
+                       }
+               }
+       } else {
+               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;
+               if (inline_data_size) {
+                       cd->pctx.errcode =
+                               ext2fs_inline_data_set(fs, ino, 0, buf,
+                                                      inline_data_size);
+               } else
+                       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 +1365,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;
@@ -1456,7 +1621,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 32c05b5b7c3fcf4d86bb0696319e7d45d4c963de..6f7f8559eaf17bca82914d30e5a55c40eb88c0b1 100644 (file)
@@ -199,9 +199,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;
@@ -375,7 +376,18 @@ 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)) {
+               /* Lost+found shouldn't have inline data */
+               retval = ext2fs_read_inode(fs, ino, &inode);
+               if (fix && retval)
+                       return 0;
+
+               if (fix && (inode.i_flags & EXT4_INLINE_DATA_FL)) {
+                       if (!fix_problem(ctx, PR_3_LPF_INLINE_DATA, &pctx))
+                               return 0;
+                       goto unlink;
+               }
+
+               if (ext2fs_check_directory(fs, ino) == 0) {
                        ctx->lost_and_found = ino;
                        return ino;
                }
@@ -387,6 +399,7 @@ ext2_ino_t e2fsck_get_lost_and_found(e2fsck_t ctx, int fix)
                if (!fix_problem(ctx, PR_3_LPF_NOTDIR, &pctx))
                        return 0;
 
+unlink:
                /* OK, unlink the old /lost+found file. */
                pctx.errcode = ext2fs_unlink(fs, EXT2_ROOT_INO, name, ino, 0);
                if (pctx.errcode) {
@@ -445,7 +458,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;
@@ -612,7 +625,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;
@@ -632,10 +645,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;
@@ -659,8 +671,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 :
@@ -686,6 +702,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,
@@ -737,7 +754,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) {
@@ -810,6 +828,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;
 
        before = ext2fs_free_blocks_count(fs->super);
        retval = ext2fs_block_iterate3(fs, dir, BLOCK_FLAG_APPEND,
index b31490fe588d200b48182b1f8e416fa4df5568d4..04d8843b0455e273b71e0d6ebcd92d07ef8011b2 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)
 {
@@ -253,8 +372,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;
@@ -505,8 +623,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 2296c97008e774cab6a13eab7e63788bc222e465..2b564a83c801952562ee074003aeb81e6f63ce48 100644 (file)
@@ -435,6 +435,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.  "),
@@ -953,6 +967,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
         */
@@ -966,6 +1020,15 @@ static struct e2fsck_problem problem_table[] = {
          N_("@i %i, end of extent exceeds allowed value\n\t(logical @b %c, physical @b %b, len %N)\n"),
          PROMPT_CLEAR, 0 },
 
+       /* Inode has inline data, but superblock is missing INLINE_DATA feature. */
+       { PR_1_INLINE_DATA_FEATURE,
+         N_("@i %i has inline data, but @S is missing INLINE_DATA feature\n"),
+         PROMPT_CLEAR, PR_PREEN_OK },
+
+       /* INLINE_DATA feature is set in a non-inline-data filesystem */
+       { PR_1_INLINE_DATA_SET,
+         N_("@i %i has INLINE_DATA_FL flag on @f without inline data support.\n"),
+         PROMPT_CLEAR, 0 },
 
        /* Pass 1b errors */
 
@@ -1010,6 +1073,11 @@ static struct e2fsck_problem problem_table[] = {
          N_("Error adjusting refcount for @a @b %b (@i %i): %m\n"),
          PROMPT_NONE, 0 },
 
+       /* Duplicate/bad block range in inode */
+       { PR_1B_DUP_RANGE,
+         " %b--%c",
+         PROMPT_NONE, PR_LATCH_DBLOCK | PR_PREEN_NOHDR },
+
        /* Pass 1C: Scan directories for inodes with multiply-claimed blocks. */
        { PR_1C_PASS_HEADER,
          N_("Pass 1C: Scanning directories for @is with @m @bs\n"),
@@ -1389,6 +1457,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 */
@@ -1511,6 +1604,11 @@ static struct e2fsck_problem problem_table[] = {
          N_("/@l is not a @d (ino=%i)\n"),
          PROMPT_UNLINK, 0 },
 
+       /* Lost+found has inline data */
+       { PR_3_LPF_INLINE_DATA,
+         N_("/@l has inline data\n"),
+         PROMPT_CLEAR, 0 },
+
        /* Pass 3A Directory Optimization       */
 
        /* Pass 3A: Optimizing directories */
@@ -1705,6 +1803,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 6cb09cfbc388ec617e9ba166f1d0d215c30c86de..bc9fa9c8cd35edc9ef38a43945ab1fa22d884d6c 100644 (file)
@@ -252,6 +252,16 @@ struct problem_context {
 /* 64bit is set but extents are not set. */
 #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,10 +571,35 @@ 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
 
 #define PR_1_EXTENT_END_OUT_OF_BOUNDS  0x01006E
+
+/* Inode has inline data, but superblock is missing INLINE_DATA feature. */
+#define PR_1_INLINE_DATA_FEATURE       0x01006F
+
+/* INLINE_DATA feature is set in a non-inline-data filesystem */
+#define PR_1_INLINE_DATA_SET          0x010070
+
 /*
  * Pass 1b errors
  */
@@ -593,6 +628,9 @@ struct problem_context {
 /* Error adjusting EA refcount */
 #define PR_1B_ADJ_EA_REFCOUNT  0x011007
 
+/* Duplicate/bad block range in inode */
+#define PR_1B_DUP_RANGE                0x011008
+
 /* Pass 1C: Scan directories for inodes with dup blocks. */
 #define PR_1C_PASS_HEADER      0x012000
 
@@ -829,6 +867,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
  */
@@ -905,6 +958,9 @@ struct problem_context {
 /* Lost+found is not a directory */
 #define PR_3_LPF_NOTDIR                        0x030017
 
+/* Lost+found has inline data */
+#define PR_3_LPF_INLINE_DATA           0x030018
+
 /*
  * Pass 3a --- rehashing diretories
  */
@@ -1027,6 +1083,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 e4e5ae1d9a6810f8d6450b2d7f473a3809363ade..54579c2ef02ba0f447405b600f4b4d8de616acad 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 4b669f08cf48f4e0159286bbddf9c7582a8abcc0..aaaaa19054cb943ddff98a8f83ca3edb13eef4b4 100644 (file)
@@ -203,6 +203,8 @@ int main(int argc, char **argv)
                        break;
                }
        }
+       if (r)
+               region_free(r);
 }
 
 #endif /* TEST_PROGRAM */
index 3aafbb12833ba5aca5848443014202e69d4a69e1..3b05715881e39d8bae4fab3e62df9c8269093be7 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;
                /*
@@ -662,11 +733,11 @@ static int write_dir_block(ext2_filsys fs,
                *block_nr = 0;
                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;
@@ -688,6 +759,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);
@@ -722,6 +794,11 @@ errcode_t e2fsck_rehash_dir(e2fsck_t ctx, ext2_ino_t ino)
        outdir.hashes = 0;
        e2fsck_read_inode(ctx, ino, &inode, "rehash_dir");
 
+       if (EXT2_HAS_INCOMPAT_FEATURE(fs->super,
+                                     EXT4_FEATURE_INCOMPAT_INLINE_DATA) &&
+          (inode.i_flags & EXT4_INLINE_DATA_FL))
+               return 0;
+
        retval = ENOMEM;
        fd.harray = 0;
        dir_buf = malloc(inode.i_size);
@@ -740,6 +817,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;
@@ -843,7 +921,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);
 
@@ -871,8 +949,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 e4d60ce8be93238f9bc96601eda8b5506ba51d36..421cd3e1ebb7b68d1f4952097744424c7845832b 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 81503d4b9b70755cf1313dd86207d1800625e7a8..e9892e2db6b35bef8375d5d1cce3f92c5e430f62 100644 (file)
@@ -201,9 +201,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;
@@ -580,6 +580,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) &&
@@ -597,8 +610,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;
 
@@ -729,6 +741,7 @@ void check_super_block(e2fsck_t ctx)
            (!csum_flag || !(ctx->mount_flags & EXT2_MF_MOUNTED))) {
                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 74ef32d4b50266c7be730a1549414b96c9dabc11..2267a02dee7d2ad157040d156837ae3eb7664af8 100644 (file)
@@ -1158,6 +1158,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;
 }
@@ -1276,6 +1281,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) {
@@ -1757,7 +1763,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 434863137ce960afed7173354eb47b8652f5be54..fec6179871064e7dbd8c089e3ef80182c441a795 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 5f4cc69a5c63eadea281731ea12e56b0112ea899..0697431ebf7ec6817300214596468d5ad6a6ae0f 100644 (file)
@@ -34,6 +34,7 @@ DOCS=   doc/ext2ed-design.pdf doc/user-guide.pdf doc/ext2fs-overview.pdf \
 .c.o:
        $(CC) -c $(ALL_CFLAGS) $< -o $@
        $(CHECK_CMD) $(ALL_CFLAGS) $<
+       $(CPPCHECK_CMD) $(CPPFLAGS) $<
 
 .SUFFIXES: .sgml .ps .pdf .html
 
index 87d081f847a0c1c2827f603e4c5233a3f7b4d869..db6d7d71876677a30538cb2dc69ecf0aff5c35b1 100644 (file)
@@ -61,17 +61,23 @@ mkinstalldirs = $(SHELL) $(MKINSTALLDIRS)
 
 @ifGNUmake@ CHECK=sparse
 @ifGNUmake@ CHECK_OPTS=-Wsparse-all -Wno-transparent-union -Wno-return-void -Wno-undef -Wno-non-pointer-null
+@ifGNUmake@ CPPCHECK=cppcheck
+@ifGNUmake@ CPPCHECK_OPTS=--force --enable=all --quiet --check-config
 @ifGNUmake@ ifeq ("$(C)", "2")
 @ifGNUmake@   CHECK_CMD=$(CHECK) $(CHECK_OPTS) -Wbitwise -D__CHECK_ENDIAN__
+@ifGNUmake@   CPPCHECK_CMD=$(CPPCHECK) $(CPPCHECK_OPTS)
 @ifGNUmake@ else
 @ifGNUmake@   ifeq ("$(C)", "1")
 @ifGNUmake@     CHECK_CMD=$(CHECK) $(CHECK_OPTS)
+@ifGNUmake@     CPPCHECK_CMD=$(CPPCHECK) $(CPPCHECK_OPTS)
 @ifGNUmake@    else
 @ifGNUmake@     CHECK_CMD=@true
+@ifGNUmake@     CPPCHECK_CMD=@true
 @ifGNUmake@   endif
 @ifGNUmake@ endif
 
 @ifNotGNUmake@ CHECK_CMD=@true
+@ifNotGNUmake@ CPPCHECK_CMD=@true
 
 l = @INTL_LIBTOOL_SUFFIX_PREFIX@
 
@@ -206,6 +212,7 @@ LTV_AGE=4
        $(E) "  CC $<"
        $(Q) $(COMPILE) $<
        $(Q) $(CHECK_CMD) $(ALL_CFLAGS) $<
+       $(Q) $(CPPCHECK_CMD) $(CPPFLAGS) $<
 
 .y.c:
        $(YACC) $(YFLAGS) --output $@ $<
index 147243255a087474dc96b403ab989221f2b2dded..a27b20c1472f808bae9ca33108b87aa8b7ac4dcb 100644 (file)
@@ -56,6 +56,7 @@ DEPLIBS_BLKID=        $(DEPSTATIC_LIBBLKID) $(DEPSTATIC_LIBUUID)
        $(E) "  CC $<"
        $(Q) $(CC) $(ALL_CFLAGS) -c $< -o $@
        $(Q) $(CHECK_CMD) $(ALL_CFLAGS) $<
+       $(Q) $(CPPCHECK_CMD) $(CPPFLAGS) $<
 @PROFILE_CMT@  $(Q) $(CC) $(ALL_CFLAGS) -g -pg -o profiled/$*.o -c $<
 @CHECKER_CMT@  $(Q) $(CC) $(ALL_CFLAGS) -checker -g -o checker/$*.o -c $<
 @ELF_CMT@      $(Q) $(CC) $(ALL_CFLAGS) -fPIC -o elfshared/$*.o -c $<
index 37e80effb4545c946d6b666ad05b195147b2fb6f..d6809e10b57982548ceb3424e07d815aeb162510 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 92b3c49b5b73f73148b6bedb2ec14f4a02aab594..d971021eef1d2a6b530125a1ccab82e5c02a3d8a 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 7cdb88cb1d7719eb47c67a8d55f97e2045c7c483..c8925cfd3484bfda0220ee190a6971348059679a 100644 (file)
@@ -56,6 +56,7 @@ BSDLIB_INSTALL_DIR = $(root_libdir)
        $(E) "  CC $<"
        $(Q) $(CC) $(ALL_CFLAGS) -c $< -o $@
        $(Q) $(CHECK_CMD) $(ALL_CFLAGS) $<
+       $(Q) $(CPPCHECK_CMD) $(CPPFLAGS) $<
 @PROFILE_CMT@  $(Q) $(CC) $(ALL_CFLAGS) -g -pg -o profiled/$*.o -c $<
 @CHECKER_CMT@  $(Q) $(CC) $(ALL_CFLAGS) -checker -g -o checker/$*.o -c $<
 @ELF_CMT@      $(Q) $(CC) $(ALL_CFLAGS) -fPIC -o elfshared/$*.o -c $<
index 1d3e6896473251cfc3f9e5b955faa957b07677d0..d0e29b894bfd8685929fa7f524efd22599c154aa 100644 (file)
@@ -95,7 +95,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 },
 };
@@ -110,6 +110,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 6f741c065610f70f295707d676f63cfb14e78510..a7ea38a44136f8cc0abc7dad551c072a0c589e76 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;
@@ -431,9 +441,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 e2f8ce50a3855a5499482f3692d794d8198221f3..f116ac3c1fb1795e1a6803cf7bd5dd205625dac9 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 4441e1f8e6faee6f6a21df685b1fb4b78e1dcc87..f9a79c0713261c2f1a3b914c57e41428343ff2fb 100644 (file)
@@ -44,6 +44,7 @@ BSDLIB_INSTALL_DIR = $(root_libdir)
        $(E) "  CC $<"
        $(Q) $(CC) $(ALL_CFLAGS) -c $< -o $@
        $(Q) $(CHECK_CMD) $(ALL_CFLAGS) $<
+       $(Q) $(CPPCHECK_CMD) $(CPPFLAGS) $<
 @PROFILE_CMT@  $(Q) $(CC) $(ALL_CFLAGS) -g -pg -o profiled/$*.o -c $<
 @CHECKER_CMT@  $(Q) $(CC) $(ALL_CFLAGS) -checker -g -o checker/$*.o -c $<
 @ELF_CMT@      $(Q) $(CC) $(ALL_CFLAGS) -fPIC -o elfshared/$*.o -c $<
index c4a832981512e8740f0a9e451351d6f113acd4ff..ba2b2c4e3c847cab7b2264ac9070666cab67a1ae 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 \
@@ -58,6 +59,7 @@ OBJS= $(DEBUGFS_LIB_OBJS) $(RESIZE_LIB_OBJS) $(E2IMAGE_LIB_OBJS) \
        ind_block.o \
        initialize.o \
        inline.o \
+       inline_data.o \
        inode.o \
        io_manager.o \
        ismounted.o \
@@ -123,6 +125,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 \
@@ -131,6 +134,7 @@ SRCS= ext2_err.c \
        $(srcdir)/ind_block.c \
        $(srcdir)/initialize.c \
        $(srcdir)/inline.c \
+       $(srcdir)/inline_data.c \
        $(srcdir)/inode.c \
        $(srcdir)/inode_io.c \
        $(srcdir)/imager.c \
@@ -201,6 +205,7 @@ all:: ext2fs.pc
        $(E) "  CC $<"
        $(Q) $(CC) $(ALL_CFLAGS) -c $< -o $@
        $(Q) $(CHECK_CMD) $(ALL_CFLAGS) $<
+       $(Q) $(CPPCHECK_CMD) $(CPPFLAGS) $<
 @PROFILE_CMT@  $(Q) $(CC) $(ALL_CFLAGS) -g -pg -o profiled/$*.o -c $<
 @CHECKER_CMT@  $(Q) $(CC) $(ALL_CFLAGS) -checker -g -o checker/$*.o -c $<
 @ELF_CMT@      $(Q) $(CC) $(ALL_CFLAGS) -fPIC -o elfshared/$*.o -c $<
@@ -393,6 +398,11 @@ tst_inline: $(srcdir)/inline.c $(STATIC_LIBEXT2FS) $(DEPSTATIC_LIBCOM_ERR)
        $(Q) $(CC) -o tst_inline $(srcdir)/inline.c $(ALL_CFLAGS) -DDEBUG \
                $(STATIC_LIBEXT2FS) $(STATIC_LIBCOM_ERR) $(SYSLIBS)
 
+tst_inline_data: inline_data.c $(STATIC_LIBEXT2FS) $(DEPSTATIC_LIBCOM_ERR)
+       $(E) "  LD $@"
+       $(Q) $(CC) -o tst_inline_data $(srcdir)/inline_data.c $(ALL_CFLAGS) \
+       -DDEBUG $(STATIC_LIBEXT2FS) $(STATIC_LIBCOM_ERR)
+
 tst_csum: csum.c $(STATIC_LIBEXT2FS) $(DEPSTATIC_LIBCOM_ERR) $(STATIC_LIBE2P) \
                $(top_srcdir)/lib/e2p/e2p.h
        $(E) "  LD $@"
@@ -412,7 +422,7 @@ mkjournal: mkjournal.c $(STATIC_LIBEXT2FS) $(DEPLIBCOM_ERR)
 
 check:: tst_bitops tst_badblocks tst_iscan tst_types tst_icount \
     tst_super_size tst_types tst_inode_size tst_csum tst_crc32c tst_bitmaps \
-    tst_inline
+    tst_inline tst_inline_data
        LD_LIBRARY_PATH=$(LIB) DYLD_LIBRARY_PATH=$(LIB) ./tst_bitops
        LD_LIBRARY_PATH=$(LIB) DYLD_LIBRARY_PATH=$(LIB) ./tst_badblocks
        LD_LIBRARY_PATH=$(LIB) DYLD_LIBRARY_PATH=$(LIB) ./tst_iscan
@@ -422,6 +432,7 @@ check:: tst_bitops tst_badblocks tst_iscan tst_types tst_icount \
        LD_LIBRARY_PATH=$(LIB) DYLD_LIBRARY_PATH=$(LIB) ./tst_inode_size
        LD_LIBRARY_PATH=$(LIB) DYLD_LIBRARY_PATH=$(LIB) ./tst_csum
        LD_LIBRARY_PATH=$(LIB) DYLD_LIBRARY_PATH=$(LIB) ./tst_inline
+       LD_LIBRARY_PATH=$(LIB) DYLD_LIBRARY_PATH=$(LIB) ./tst_inline_data
        LD_LIBRARY_PATH=$(LIB) DYLD_LIBRARY_PATH=$(LIB) ./tst_crc32c
        LD_LIBRARY_PATH=$(LIB) DYLD_LIBRARY_PATH=$(LIB) \
                ./tst_bitmaps -f $(srcdir)/tst_bitmaps_cmds > tst_bitmaps_out
@@ -656,7 +667,7 @@ expanddir.o: $(srcdir)/expanddir.c $(top_builddir)/lib/config.h \
  $(top_builddir)/lib/ext2fs/ext2_types.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
+ $(srcdir)/ext2_ext_attr.h $(srcdir)/bitops.h $(srcdir)/ext2fsP.h
 ext_attr.o: $(srcdir)/ext_attr.c $(top_builddir)/lib/config.h \
  $(top_builddir)/lib/dirpaths.h $(srcdir)/ext2_fs.h \
  $(top_builddir)/lib/ext2fs/ext2_types.h $(srcdir)/ext2_ext_attr.h \
@@ -710,6 +721,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 \
@@ -758,6 +776,13 @@ inline.o: $(srcdir)/inline.c $(top_builddir)/lib/config.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
+inline_data.o: $(srcdir)/inline_data.c $(top_builddir)/lib/config.h \
+ $(top_builddir)/lib/dirpaths.h $(srcdir)/ext2_fs.h \
+ $(top_builddir)/lib/ext2fs/ext2_types.h $(srcdir)/ext2_ext_attr.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 $(srcdir)/ext2fsP.h
 inode.o: $(srcdir)/inode.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 \
@@ -809,7 +834,7 @@ mkdir.o: $(srcdir)/mkdir.c $(top_builddir)/lib/config.h \
  $(top_builddir)/lib/ext2fs/ext2_types.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
+ $(srcdir)/ext2_ext_attr.h $(srcdir)/bitops.h $(srcdir)/ext2fsP.h
 mkjournal.o: $(srcdir)/mkjournal.c $(top_builddir)/lib/config.h \
  $(top_builddir)/lib/dirpaths.h $(srcdir)/ext2_fs.h \
  $(top_builddir)/lib/ext2fs/ext2_types.h $(top_srcdir)/lib/e2p/e2p.h \
@@ -859,7 +884,7 @@ punch.o: $(srcdir)/punch.c $(top_builddir)/lib/config.h \
  $(top_builddir)/lib/ext2fs/ext2_types.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
+ $(srcdir)/ext2_ext_attr.h $(srcdir)/bitops.h $(srcdir)/ext2fsP.h
 qcow2.o: $(srcdir)/qcow2.c $(top_builddir)/lib/config.h \
  $(top_builddir)/lib/dirpaths.h $(srcdir)/ext2fs.h \
  $(top_builddir)/lib/ext2fs/ext2_types.h $(srcdir)/ext2_fs.h \
index 2f7b654b9145ef3d98f1b13e9017562c417b3af7..89082a7e543876ff41115d07099eebfd2fe3ea68 100644 (file)
@@ -27,6 +27,7 @@ OBJS=         alloc.obj \
        icount.obj \
        initialize.obj \
        inline.obj \
+       inline_data.obj \
        inode.obj \
        ismounted.obj \
        link.obj \
index 0acbc4e6b41fca4e9ac50b7c4d3e105eb1cadc45..b36d288d249f9404df0fafbea254add6c621b833 100644 (file)
@@ -31,8 +31,7 @@
  */
 static void clear_block_uninit(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_flags_test(fs, group, EXT2_BG_BLOCK_UNINIT)))
                return;
 
@@ -52,8 +51,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 1f58e001f6491b8e8a8fff27d541d3cda4a15263..4feb24d6a95de8746029f62b77a7922ffa3f7185 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;
@@ -130,7 +129,7 @@ void ext2fs_block_alloc_stats_range(ext2_filsys fs, blk64_t blk,
        while (num) {
                int group = ext2fs_group_of_blk2(fs, blk);
                blk64_t last_blk = ext2fs_group_last_block2(fs, group);
-               blk_t n = num;
+               blk64_t n = num;
 
                if (blk + num > last_blk)
                        n = last_blk - blk + 1;
index bc99943c3727da161b0baaa642da4d49d104542e..2fd8f5d8b1f0bd13decf239087f216a818a50a65 100644 (file)
@@ -222,16 +222,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 894293a1812a398495320108e7c916572f13140c..87946c7a6b145aad72b1a5925e7559374a16a5fa 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 4dcb03f957fd622ae2da275969b5e80f3bb914ab..8ab0e0d534f284e0a31f6488f465827537067a75 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;
@@ -893,7 +891,7 @@ static errcode_t rb_find_first_set(ext2fs_generic_bitmap bitmap,
        return ENOENT;
 }
 
-#ifdef BMAP_STATS
+#ifdef ENABLE_BMAP_STATS
 static void rb_print_stats(ext2fs_generic_bitmap bitmap)
 {
        struct ext2fs_rb_private *bp;
@@ -904,7 +902,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
@@ -928,7 +926,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)
@@ -955,7 +953,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 8ced1eec683855b444699f02df717e49988cfad5..aced8972a7be4a65362c3b33282f7fc41c21b3b5 100644 (file)
@@ -199,6 +199,21 @@ static struct ext4_group_desc *ext4fs_group_desc(ext2_filsys fs,
        return (struct ext4_group_desc *)ext2fs_group_desc(fs, gdp, group);
 }
 
+/*
+ * 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
  */
@@ -226,6 +241,21 @@ void ext2fs_block_bitmap_loc_set(ext2_filsys fs, dgrp_t group, blk64_t blk)
                gdp->bg_block_bitmap_hi = (__u64) blk >> 32;
 }
 
+/*
+ * 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
  */
index b8c68798bd6c74ff1c3785c7b976f0082fac1086..601129d48e9cd2238f64685e6b89d8d23873d9ac 100644 (file)
@@ -344,6 +344,13 @@ errcode_t ext2fs_block_iterate3(ext2_filsys fs,
        if (ctx.errcode)
                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
         */
index db2fd726b3fae91ddd9b91e5f527053f0b81aead..c1d0e6f5ca4f336d6ff6a41770a4a011ec385bc4 100644 (file)
@@ -321,6 +321,13 @@ errcode_t ext2fs_bmap2(ext2_filsys fs, ext2_ino_t ino, struct ext2_inode *inode,
        if (ext2fs_file_block_offset_too_big(fs, inode, block))
                return EXT2_ET_FILE_TOO_BIG;
 
+       /*
+        * If an inode has inline data, that means that it doesn't have
+        * any blocks and we shouldn't map any blocks for it.
+        */
+       if (inode->i_flags & EXT4_INLINE_DATA_FL)
+               return EXT2_ET_INLINE_DATA_NO_BLOCK;
+
        if (!block_buf) {
                retval = ext2fs_get_array(2, fs->blocksize, &buf);
                if (retval)
index 9deba46c88cc1aac0a0306c02946496aa36d0f3d..d8c7a3c38c9076c1411c52cb38871ff3ece7e640 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 4e91778ada00c9a8266ee095393bd7c94c92a16f..c2eaec1e455435977c0bebabbc9b116eed56f130 100644 (file)
@@ -255,15 +255,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);
@@ -297,6 +301,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);
@@ -306,6 +327,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);
 
@@ -326,10 +348,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
@@ -349,14 +367,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);
 
@@ -385,19 +405,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:
        /*
@@ -416,6 +425,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 2512528a4c383956ba620dc342591b50b6ecfc84..624ad77623bc913a82ed9d89fec9c6abf98b78b5 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 023f2c01428bc25f83f2db31520b9a0679095669..3f9a09e5f3cfeef407f880375c4a3d3cd1ca82c1 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 669f8068cfdf03caf2eaa83866a89d504da5d424..d7dbca83339430912bbf5b71e217accb3d6e8814 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)
 {
        struct ext2_group_desc *desc = ext2fs_group_desc(fs, fs->group_desc,
                                                         group);
-       size_t size = EXT2_DESC_SIZE(fs->super);
+       size_t offset, size = EXT2_DESC_SIZE(fs->super);
        __u16 crc = 0;
-
-       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;
-               size_t save_size = size;
-               const size_t ext4_bg_size = sizeof(struct ext4_group_desc);
-               struct ext2_group_desc *save_desc = desc;
-
-               /* Have to swab back to little-endian to do the checksum */
-               if (size > ext4_bg_size)
-                       size = ext4_bg_size;
-               memcpy(&swabdesc, desc, size);
-               ext2fs_swap_group_desc2(fs,
-                                       (struct ext2_group_desc *) &swabdesc);
-               desc = (struct ext2_group_desc *) &swabdesc;
-
-               group = ext2fs_swab32(group);
+       struct ext4_group_desc swabdesc;
+       size_t save_size = size;
+       const size_t ext4_bg_size = sizeof(struct ext4_group_desc);
+       struct ext2_group_desc *save_desc = desc;
+
+       /* Have to swab back to little-endian to do the checksum */
+       if (size > ext4_bg_size)
+               size = ext4_bg_size;
+       memcpy(&swabdesc, desc, size);
+       ext2fs_swap_group_desc2(fs, (struct ext2_group_desc *) &swabdesc);
+       desc = (struct ext2_group_desc *) &swabdesc;
+       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;
 #ifdef WORDS_BIGENDIAN
-               /*
-                * If the size of the bg descriptor is greater than 64
-                * bytes, which is the size of the traditional ext4 bg
-                * descriptor, checksum the rest of the descriptor here
-                */
                if (save_size > ext4_bg_size)
-                       crc = ext2fs_crc16(crc,
+                       crc32 = ext2fs_crc32c_le(crc32,
                                           (char *)save_desc + ext4_bg_size,
                                           save_size - ext4_bg_size);
 #endif
+               crc = crc32 & 0xFFFF;
+               goto out;
+       }
+
+       /* old crc16 code */
+       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);
        }
+#ifdef WORDS_BIGENDIAN
+       /*
+        * If the size of the bg descriptor is greater than 64
+        * bytes, which is the size of the traditional ext4 bg
+        * descriptor, checksum the rest of the descriptor here
+        */
+       if (save_size > ext4_bg_size)
+               crc = ext2fs_crc16(crc, (char *)save_desc + ext4_bg_size,
+                                  save_size - ext4_bg_size);
+#endif
 
+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;
@@ -95,8 +802,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
@@ -130,8 +836,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 3f6ea50d05df1b91c75be5534b469bf0b37ed18b..942c4f04aa24068be0ef651cf0f488c5d2d17949 100644 (file)
@@ -24,34 +24,6 @@ static EXT2_QSORT_TYPE dir_block_cmp(const void *a, const void *b);
 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 d4d511140683827377095051cd52aded194a88d0..864a3ca0288ec00596bd0b0abbdf8816608adb6a 100644 (file)
@@ -65,6 +65,7 @@ errcode_t ext2fs_dblist_dir_iterate(ext2_dblist dblist,
 static int db_dir_proc(ext2_filsys fs, struct ext2_db_entry2 *db_info,
                       void *priv_data)
 {
+       struct ext2_inode       inode;
        struct dir_context      *ctx;
        int                     ret;
 
@@ -72,8 +73,15 @@ static int db_dir_proc(ext2_filsys fs, struct ext2_db_entry2 *db_info,
        ctx->dir = db_info->ino;
        ctx->errcode = 0;
 
-       ret = ext2fs_process_dir_block(fs, &db_info->blk,
-                                      db_info->blockcnt, 0, 0, priv_data);
+       ctx->errcode = ext2fs_read_inode(fs, ctx->dir, &inode);
+       if (ctx->errcode)
+               return DBLIST_ABORT;
+       if (inode.i_flags & EXT4_INLINE_DATA_FL)
+               ret = ext2fs_inline_data_dir_iterate(fs, ctx->dir, ctx);
+       else
+               ret = ext2fs_process_dir_block(fs, &db_info->blk,
+                                              db_info->blockcnt, 0, 0,
+                                              priv_data);
        if ((ret & BLOCK_ABORT) && !ctx->errcode)
                return DBLIST_ABORT;
        return 0;
index 589af692eabf97039c1c9a49b72b04372837d427..67152cc7f6ea4a4777aeaa94b041abd37a0a4a05 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);
@@ -127,6 +127,10 @@ errcode_t ext2fs_dir_iterate2(ext2_filsys fs,
                                       ext2fs_process_dir_block, &ctx);
        if (!block_buf)
                ext2fs_free_mem(&ctx.buf);
+       if (retval == EXT2_ET_INLINE_DATA_CANT_ITERATE) {
+               (void) ext2fs_inline_data_dir_iterate(fs, dir, &ctx);
+               retval = 0;
+       }
        if (retval)
                return retval;
        return ctx.errcode;
@@ -189,39 +193,68 @@ int ext2fs_process_dir_block(ext2_filsys fs,
        int             ret = 0;
        int             changed = 0;
        int             do_abort = 0;
-       unsigned int    rec_len, size;
+       unsigned int    rec_len, size, buflen;
        int             entry;
        struct ext2_dir_entry *dirent;
+       int             csum_size = 0;
+       int             inline_data;
+       errcode_t       retval = 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);
-       if (ctx->errcode)
-               return BLOCK_ABORT;
+       /* If a dir has inline data, we don't need to read block */
+       inline_data = !!(ctx->flags & DIRENT_FLAG_INCLUDE_INLINE_DATA);
+       if (!inline_data) {
+               ctx->errcode = ext2fs_read_dir_block4(fs, *blocknr, ctx->buf, 0,
+                                                     ctx->dir);
+               if (ctx->errcode)
+                       return BLOCK_ABORT;
+               /* If we handle a normal dir, we traverse the entire block */
+               buflen = fs->blocksize;
+       } else {
+               buflen = ctx->buflen;
+       }
+
+       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) {
+       while (offset < buflen) {
                dirent = (struct ext2_dir_entry *) (ctx->buf + offset);
                if (ext2fs_get_rec_len(fs, dirent, &rec_len))
                        return BLOCK_ABORT;
-               if (((offset + rec_len) > fs->blocksize) ||
+               if (((offset + rec_len) > buflen) ||
                    (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) {
+                       /*
+                        * We just need to check metadata_csum when this
+                        * dir hasn't inline data.  That means that 'buflen'
+                        * should be blocksize.
+                        */
+                       if (!inline_data &&
+                           (offset == buflen - 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) ?
                                  DIRENT_DELETED_FILE : entry,
                                  dirent, offset,
-                                 fs->blocksize, ctx->buf,
+                                 buflen, ctx->buf,
                                  ctx->priv_data);
                if (entry < DIRENT_OTHER_FILE)
                        entry++;
@@ -240,7 +273,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,13 +292,21 @@ next:
        }
 
        if (changed) {
-               ctx->errcode = ext2fs_write_dir_block3(fs, *blocknr, ctx->buf,
-                                                      0);
-               if (ctx->errcode)
-                       return BLOCK_ABORT;
+               if (!inline_data) {
+                       ctx->errcode = ext2fs_write_dir_block4(fs, *blocknr,
+                                                              ctx->buf,
+                                                              0, ctx->dir);
+                       if (ctx->errcode)
+                               return BLOCK_ABORT;
+               } else {
+                       /*
+                        * return BLOCK_INLINE_DATA_CHANGED to notify caller
+                        * that inline data has been changed.
+                        */
+                       retval = BLOCK_INLINE_DATA_CHANGED;
+               }
        }
        if (do_abort)
-               return BLOCK_ABORT;
-       return 0;
+               return retval | BLOCK_ABORT;
+       return retval;
 }
-
index cb3a104c781854fe3575484a98d338a8e89016b4..54b2777285150db4fcf198ff5aa7875484b1841a 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 153b838c11db4e9f3d8ef89eb909f993b8d03c6f..d0f7287933510a83b956f1646787afe7517b5f45 100644 (file)
 
 #include "ext2_fs.h"
 #include "ext2fs.h"
+#include "ext2fsP.h"
 
 struct expand_dir_struct {
        int             done;
        int             newblocks;
        blk64_t         goal;
        errcode_t       err;
+       ext2_ino_t      dir;
 };
 
 static int expand_dir_proc(ext2_filsys fs,
@@ -63,7 +65,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,9 +113,12 @@ 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);
+       if (retval == EXT2_ET_INLINE_DATA_CANT_ITERATE)
+               return ext2fs_inline_data_expand(fs, dir);
 
        if (es.err)
                return es.err;
index 87812ab483c3ee26f508d68308904e3cf56876f7..51c88d033cb7c6ddd4ef78a177f2122fcafc962f 100644 (file)
@@ -476,4 +476,43 @@ 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 iterate data blocks of an inode containing inline data"
+
+ec     EXT2_ET_EA_BAD_NAME_LEN,
+       "Extended attribute has an invalid name length"
+
+ec     EXT2_ET_EA_BAD_VALUE_SIZE,
+       "Extended attribute has an invalid value length"
+
+ec     EXT2_ET_BAD_EA_HASH,
+       "Extended attribute has an incorrect hash"
+
+ec     EXT2_ET_BAD_EA_HEADER,
+       "Extended attribute block has a bad header"
+
+ec     EXT2_ET_EA_KEY_NOT_FOUND,
+       "Extended attribute key not found"
+
+ec     EXT2_ET_EA_NO_SPACE,
+       "Insufficient space to store extended attribute data"
+
+ec     EXT2_ET_MISSING_EA_FEATURE,
+       "Filesystem is missing ext_attr or inline_data feature"
+
+ec     EXT2_ET_NO_INLINE_DATA,
+       "Inode doesn't have inline data"
+
+ec     EXT2_ET_INLINE_DATA_NO_BLOCK,
+       "No block for an inode with inline data"
+
+ec     EXT2_ET_INLINE_DATA_NO_SPACE,
+       "No free space in inline data"
+
+ec     EXT2_ET_MAGIC_EA_HANDLE,
+       "Wrong magic number for extended attribute structure"
+
        end
index ed548d1264e6356a523c33f334c8fd7ccc6217ae..bbb0aaa97bcabdd66ad76b74e3e96dd7c6979869 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 d9e14d7cee6c430b5f1aba578a902984aa08980e..21a8187bb1f6599236faa892e86d51771cdcbd29 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 */
@@ -710,6 +734,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
 
@@ -726,7 +755,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| \
@@ -776,6 +805,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 */
@@ -785,6 +822,17 @@ struct ext2_dir_entry_2 {
        char    name[EXT2_NAME_LEN];    /* File name */
 };
 
+/*
+ * 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.
@@ -800,6 +848,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
  *
@@ -841,7 +897,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) */
 };
 
 /*
@@ -859,4 +916,14 @@ struct mmp_struct {
  */
 #define EXT4_MMP_MIN_CHECK_INTERVAL     5
 
+/*
+ * Minimum size of inline data.
+ */
+#define EXT4_MIN_INLINE_DATA_SIZE      ((sizeof(__u32) * EXT2_N_BLOCKS))
+
+/*
+ * Size of a parent inode in inline data directory.
+ */
+#define EXT4_INLINE_DATA_DOTDOT_SIZE   (4)
+
 #endif /* _LINUX_EXT2_FS_H */
index 1491c622ba3782bfac28bb7ceb686f814b5c5a83..599c97231224565f28b970dfee5b5dc4d93a8e10 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
@@ -291,9 +298,10 @@ struct struct_ext2_filsys {
 /*
  * Return flags for the block iterator functions
  */
-#define BLOCK_CHANGED  1
-#define BLOCK_ABORT    2
-#define BLOCK_ERROR    4
+#define BLOCK_CHANGED                  1
+#define BLOCK_ABORT                    2
+#define BLOCK_ERROR                    4
+#define BLOCK_INLINE_DATA_CHANGED      8
 
 /*
  * Block interate flags
@@ -430,11 +438,14 @@ struct ext2_extent_info {
 
 #define DIRENT_FLAG_INCLUDE_EMPTY      1
 #define DIRENT_FLAG_INCLUDE_REMOVED    2
+#define DIRENT_FLAG_INCLUDE_CSUM       4
+#define DIRENT_FLAG_INCLUDE_INLINE_DATA 8
 
 #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
@@ -561,26 +572,34 @@ 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_FEATURE_INCOMPAT_64BIT)
-#endif
-#ifdef CONFIG_QUOTA
+                                        EXT4_LIB_INCOMPAT_MMP|\
+                                        EXT4_FEATURE_INCOMPAT_64BIT|\
+                                        EXT4_FEATURE_INCOMPAT_INLINE_DATA)
+
 #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|\
@@ -588,22 +607,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)
 
 
@@ -629,9 +640,22 @@ typedef struct stat ext2fs_struct_stat;
  */
 #define EXT2_FLAG_FLUSH_NO_SYNC          1
 
+/*
+ * Modify and iterate extended attributes
+ */
+struct ext2_xattr_handle;
+#define XATTR_ABORT    1
+#define XATTR_CHANGED  2
+
 /*
  * 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);
+}
 
 /* The LARGE_FILE feature should be set if we have stored files 2GB+ in size */
 static inline int ext2fs_needs_large_file_feature(unsigned long long file_size)
@@ -807,6 +831,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);
@@ -834,9 +860,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);
@@ -945,18 +973,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);
@@ -1011,12 +1086,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,
@@ -1067,16 +1146,46 @@ 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);
+errcode_t ext2fs_xattrs_write(struct ext2_xattr_handle *handle);
+errcode_t ext2fs_xattrs_read(struct ext2_xattr_handle *handle);
+errcode_t ext2fs_xattrs_iterate(struct ext2_xattr_handle *h,
+                               int (*func)(char *name, char *value,
+                                           size_t value_len, void *data),
+                               void *data);
+errcode_t ext2fs_xattr_get(struct ext2_xattr_handle *h, const char *key,
+                          void **value, size_t *value_len);
+errcode_t ext2fs_xattr_set(struct ext2_xattr_handle *handle,
+                          const char *key,
+                          const void *value,
+                          size_t value_len);
+errcode_t ext2fs_xattr_remove(struct ext2_xattr_handle *handle,
+                             const char *key);
+errcode_t ext2fs_xattrs_open(ext2_filsys fs, ext2_ino_t ino,
+                            struct ext2_xattr_handle **handle);
+errcode_t ext2fs_xattrs_close(struct ext2_xattr_handle **handle);
+errcode_t ext2fs_free_ext_attr(ext2_filsys fs, ext2_ino_t ino,
+                              struct ext2_inode_large *inode);
+errcode_t ext2fs_xattrs_count(struct ext2_xattr_handle *handle, size_t *count);
+errcode_t ext2fs_xattr_inode_max_size(ext2_filsys fs, ext2_ino_t ino,
+                                     size_t *size);
 
 /* extent.c */
 extern errcode_t ext2fs_extent_header_verify(void *ptr, int size);
@@ -1185,10 +1294,6 @@ extern errcode_t ext2fs_find_first_set_generic_bitmap(ext2fs_generic_bitmap bitm
                                                       __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,
@@ -1217,6 +1322,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);
@@ -1278,7 +1386,21 @@ errcode_t ext2fs_icount_validate(ext2_icount_t icount, FILE *);
 extern errcode_t ext2fs_get_memalign(unsigned long size,
                                     unsigned long align, void *ptr);
 
+/* inline_data.c */
+extern errcode_t ext2fs_inline_data_init(ext2_filsys fs, ext2_ino_t ino);
+extern errcode_t ext2fs_inline_data_size(ext2_filsys fs, ext2_ino_t ino,
+                                        size_t *size);
+extern errcode_t ext2fs_inline_data_get(ext2_filsys fs, ext2_ino_t ino,
+                                       struct ext2_inode *inode,
+                                       void *buf, size_t *size);
+extern errcode_t ext2fs_inline_data_set(ext2_filsys fs, ext2_ino_t ino,
+                                       struct ext2_inode *inode,
+                                       void *buf, size_t size);
+
 /* inode.c */
+extern errcode_t ext2fs_create_inode_cache(ext2_filsys fs,
+                                          unsigned int cache_size);
+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,
@@ -1354,6 +1476,8 @@ int ext2fs_native_flag(void);
 /* newdir.c */
 extern errcode_t ext2fs_new_dir_block(ext2_filsys fs, ext2_ino_t dir_ino,
                                ext2_ino_t parent_ino, char **block);
+extern errcode_t ext2fs_new_dir_inline_data(ext2_filsys fs, ext2_ino_t dir_ino,
+                               ext2_ino_t parent_ino, __u32 *iblock);
 
 /* mkdir.c */
 extern errcode_t ext2fs_mkdir(ext2_filsys fs, ext2_ino_t parent, ext2_ino_t inum,
@@ -1417,6 +1541,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);
 
@@ -1441,6 +1566,12 @@ 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_in2(ext2_filsys fs, char *buf, size_t size,
+                                       int flags);
+extern errcode_t ext2fs_dirent_swab_in(ext2_filsys fs, char *buf, int flags);
+extern errcode_t ext2fs_dirent_swab_out2(ext2_filsys fs, char *buf, size_t size,
+                                        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,
@@ -1480,6 +1611,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,
@@ -1530,6 +1662,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>
 /*
@@ -1746,6 +1888,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 a88db93e2937538f76ae0f954aea2781aa5ae094..f8c61e6573539f7870c47c61795876d39c1f55f9 100644 (file)
@@ -50,6 +50,7 @@ struct dir_context {
        ext2_ino_t              dir;
        int             flags;
        char            *buf;
+       unsigned int    buflen;
        int (*func)(ext2_ino_t  dir,
                    int entry,
                    struct ext2_dir_entry *dirent,
@@ -68,14 +69,14 @@ struct ext2_inode_cache {
        void *                          buffer;
        blk64_t                         buffer_blk;
        int                             cache_last;
-       int                             cache_size;
+       unsigned int                    cache_size;
        int                             refcount;
        struct ext2_inode_cache_ent     *cache;
 };
 
 struct ext2_inode_cache_ent {
        ext2_ino_t              ino;
-       struct ext2_inode       inode;
+       struct ext2_inode       *inode;
 };
 
 /* Function prototypes */
@@ -87,6 +88,12 @@ extern int ext2fs_process_dir_block(ext2_filsys      fs,
                                    int                 ref_offset,
                                    void                *priv_data);
 
+extern errcode_t ext2fs_inline_data_ea_remove(ext2_filsys fs, ext2_ino_t ino);
+extern errcode_t ext2fs_inline_data_expand(ext2_filsys fs, ext2_ino_t ino);
+extern int ext2fs_inline_data_dir_iterate(ext2_filsys fs,
+                                         ext2_ino_t ino,
+                                         void *priv_data);
+
 /* Generic numeric progress meter */
 
 struct ext2fs_numeric_progress_struct {
@@ -95,6 +102,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 88fabc9dced810a4891d4b0ca1f83a5101cb678c..4163436e20eb4249a00bca5944c84fff8c420038 100644 (file)
  *  - number of alive extents in the inode
  */
 
+/*
+ * 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 1889824c359ed85fd1f973885fc72e2ebc49a795..308d21dcae1b2ecd34f21277998ff5699f343a56 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,891 @@ 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);
+}
+
+/* Manipulate the contents of extended attribute regions */
+struct ext2_xattr {
+       char *name;
+       void *value;
+       size_t value_len;
+};
+
+struct ext2_xattr_handle {
+       errcode_t magic;
+       ext2_filsys fs;
+       struct ext2_xattr *attrs;
+       size_t length, count;
+       ext2_ino_t ino;
+       int dirty;
+};
+
+static errcode_t ext2fs_xattrs_expand(struct ext2_xattr_handle *h,
+                                     unsigned int expandby)
+{
+       struct ext2_xattr *new_attrs;
+       errcode_t err;
+
+       err = ext2fs_get_arrayzero(h->length + expandby,
+                                  sizeof(struct ext2_xattr), &new_attrs);
+       if (err)
+               return err;
+
+       memcpy(new_attrs, h->attrs, h->length * sizeof(struct ext2_xattr));
+       ext2fs_free_mem(&h->attrs);
+       h->length += expandby;
+       h->attrs = new_attrs;
+
+       return 0;
+}
+
+struct ea_name_index {
+       int index;
+       const char *name;
+};
+
+/* Keep these names sorted in order of decreasing specificity. */
+static struct ea_name_index ea_names[] = {
+       {3, "system.posix_acl_default"},
+       {2, "system.posix_acl_access"},
+       {8, "system.richacl"},
+       {6, "security."},
+       {4, "trusted."},
+       {7, "system."},
+       {1, "user."},
+       {0, NULL},
+};
+
+static void move_inline_data_to_front(struct ext2_xattr_handle *h)
+{
+       struct ext2_xattr *x;
+       struct ext2_xattr tmp;
+
+       for (x = h->attrs + 1; x < h->attrs + h->length; x++) {
+               if (!x->name)
+                       continue;
+
+               if (strcmp(x->name, "system.data") == 0) {
+                       memcpy(&tmp, x, sizeof(tmp));
+                       memcpy(x, h->attrs, sizeof(tmp));
+                       memcpy(h->attrs, &tmp, sizeof(tmp));
+                       return;
+               }
+       }
+}
+
+static const char *find_ea_prefix(int index)
+{
+       struct ea_name_index *e;
+
+       for (e = ea_names; e->name; e++)
+               if (e->index == index)
+                       return e->name;
+
+       return NULL;
+}
+
+static int find_ea_index(const char *fullname, char **name, int *index)
+{
+       struct ea_name_index *e;
+
+       for (e = ea_names; e->name; e++) {
+               if (memcmp(fullname, e->name, strlen(e->name)) == 0) {
+                       *name = (char *)fullname + strlen(e->name);
+                       *index = e->index;
+                       return 1;
+               }
+       }
+       return 0;
+}
+
+errcode_t ext2fs_free_ext_attr(ext2_filsys fs, ext2_ino_t ino,
+                              struct ext2_inode_large *inode)
+{
+       struct ext2_ext_attr_header *header;
+       void *block_buf = NULL;
+       dgrp_t grp;
+       blk64_t blk, goal;
+       errcode_t err;
+       struct ext2_inode_large i;
+
+       /* Read inode? */
+       if (inode == NULL) {
+               err = ext2fs_read_inode_full(fs, ino, (struct ext2_inode *)&i,
+                                            sizeof(struct ext2_inode_large));
+               if (err)
+                       return err;
+               inode = &i;
+       }
+
+       /* Do we already have an EA block? */
+       blk = ext2fs_file_acl_block(fs, (struct ext2_inode *)inode);
+       if (blk == 0)
+               return 0;
+
+       /* Find block, zero it, write back */
+       if ((blk < fs->super->s_first_data_block) ||
+           (blk >= ext2fs_blocks_count(fs->super))) {
+               err = EXT2_ET_BAD_EA_BLOCK_NUM;
+               goto out;
+       }
+
+       err = ext2fs_get_mem(fs->blocksize, &block_buf);
+       if (err)
+               goto out;
+
+       err = ext2fs_read_ext_attr3(fs, blk, block_buf, ino);
+       if (err)
+               goto out2;
+
+       header = (struct ext2_ext_attr_header *) block_buf;
+       if (header->h_magic != EXT2_EXT_ATTR_MAGIC) {
+               err = EXT2_ET_BAD_EA_HEADER;
+               goto out2;
+       }
+
+       header->h_refcount--;
+       err = ext2fs_write_ext_attr3(fs, blk, block_buf, ino);
+       if (err)
+               goto out2;
+
+       /* Erase link to block */
+       ext2fs_file_acl_block_set(fs, (struct ext2_inode *)inode, 0);
+       if (header->h_refcount == 0)
+               ext2fs_block_alloc_stats2(fs, blk, -1);
+       err = ext2fs_iblk_sub_blocks(fs, (struct ext2_inode *)inode, 1);
+       if (err)
+               goto out2;
+
+       /* Write inode? */
+       if (inode == &i) {
+               err = ext2fs_write_inode_full(fs, ino, (struct ext2_inode *)&i,
+                                             sizeof(struct ext2_inode_large));
+               if (err)
+                       goto out2;
+       }
+
+out2:
+       ext2fs_free_mem(&block_buf);
+out:
+       return err;
+}
+
+static errcode_t prep_ea_block_for_write(ext2_filsys fs, ext2_ino_t ino,
+                                        struct ext2_inode_large *inode)
+{
+       struct ext2_ext_attr_header *header;
+       void *block_buf = NULL;
+       dgrp_t grp;
+       blk64_t blk, goal;
+       errcode_t err;
+
+       /* Do we already have an EA block? */
+       blk = ext2fs_file_acl_block(fs, (struct ext2_inode *)inode);
+       if (blk != 0) {
+               if ((blk < fs->super->s_first_data_block) ||
+                   (blk >= ext2fs_blocks_count(fs->super))) {
+                       err = EXT2_ET_BAD_EA_BLOCK_NUM;
+                       goto out;
+               }
+
+               err = ext2fs_get_mem(fs->blocksize, &block_buf);
+               if (err)
+                       goto out;
+
+               err = ext2fs_read_ext_attr3(fs, blk, block_buf, ino);
+               if (err)
+                       goto out2;
+
+               header = (struct ext2_ext_attr_header *) block_buf;
+               if (header->h_magic != EXT2_EXT_ATTR_MAGIC) {
+                       err = EXT2_ET_BAD_EA_HEADER;
+                       goto out2;
+               }
+
+               /* Single-user block.  We're done here. */
+               if (header->h_refcount == 1)
+                       goto out2;
+
+               /* We need to CoW the block. */
+               header->h_refcount--;
+               err = ext2fs_write_ext_attr3(fs, blk, block_buf, ino);
+               if (err)
+                       goto out2;
+       } else {
+               /* No block, we must increment i_blocks */
+               err = ext2fs_iblk_add_blocks(fs, (struct ext2_inode *)inode,
+                                            1);
+               if (err)
+                       goto out;
+       }
+
+       /* Allocate a block */
+       grp = ext2fs_group_of_ino(fs, ino);
+       goal = ext2fs_inode_table_loc(fs, grp);
+       err = ext2fs_alloc_block2(fs, goal, NULL, &blk);
+       if (err)
+               goto out2;
+       ext2fs_file_acl_block_set(fs, (struct ext2_inode *)inode, blk);
+out2:
+       if (block_buf)
+               ext2fs_free_mem(&block_buf);
+out:
+       return err;
+}
+
+
+static errcode_t write_xattrs_to_buffer(struct ext2_xattr_handle *handle,
+                                       struct ext2_xattr **pos,
+                                       void *entries_start,
+                                       unsigned int storage_size,
+                                       unsigned int value_offset_correction)
+{
+       struct ext2_xattr *x = *pos;
+       struct ext2_ext_attr_entry *e = entries_start;
+       void *end = entries_start + storage_size;
+       char *shortname;
+       unsigned int entry_size, value_size;
+       int idx, ret;
+
+       memset(entries_start, 0, storage_size);
+       /* For all remaining x...  */
+       for (; x < handle->attrs + handle->length; x++) {
+               if (!x->name)
+                       continue;
+
+               /* Calculate index and shortname position */
+               shortname = x->name;
+               ret = find_ea_index(x->name, &shortname, &idx);
+
+               /* Calculate entry and value size */
+               entry_size = (sizeof(*e) + strlen(shortname) +
+                             EXT2_EXT_ATTR_PAD - 1) &
+                            ~(EXT2_EXT_ATTR_PAD - 1);
+               value_size = ((x->value_len + EXT2_EXT_ATTR_PAD - 1) /
+                             EXT2_EXT_ATTR_PAD) * EXT2_EXT_ATTR_PAD;
+
+               /*
+                * Would entry collide with value?
+                * Note that we must leave sufficient room for a (u32)0 to
+                * mark the end of the entries.
+                */
+               if ((void *)e + entry_size + sizeof(__u32) > end - value_size)
+                       break;
+
+               /* Fill out e appropriately */
+               e->e_name_len = strlen(shortname);
+               e->e_name_index = (ret ? idx : 0);
+               e->e_value_offs = end - value_size - (void *)entries_start +
+                               value_offset_correction;
+               e->e_value_block = 0;
+               e->e_value_size = x->value_len;
+
+               /* Store name and value */
+               end -= value_size;
+               memcpy((void *)e + sizeof(*e), shortname, e->e_name_len);
+               memcpy(end, x->value, e->e_value_size);
+
+               e->e_hash = ext2fs_ext_attr_hash_entry(e, end);
+
+               e = EXT2_EXT_ATTR_NEXT(e);
+               *(__u32 *)e = 0;
+       }
+       *pos = x;
+
+       return 0;
+}
+
+errcode_t ext2fs_xattrs_write(struct ext2_xattr_handle *handle)
+{
+       struct ext2_xattr *x;
+       struct ext2_inode_large *inode;
+       void *start, *block_buf = NULL;
+       struct ext2_ext_attr_header *header;
+       __u32 ea_inode_magic;
+       blk64_t blk;
+       unsigned int storage_size;
+       unsigned int i;
+       errcode_t err;
+
+       EXT2_CHECK_MAGIC(handle, EXT2_ET_MAGIC_EA_HANDLE);
+       i = EXT2_INODE_SIZE(handle->fs->super);
+       if (i < sizeof(*inode))
+               i = sizeof(*inode);
+       err = ext2fs_get_memzero(i, &inode);
+       if (err)
+               return err;
+
+       err = ext2fs_read_inode_full(handle->fs, handle->ino,
+                                    (struct ext2_inode *)inode,
+                                    EXT2_INODE_SIZE(handle->fs->super));
+       if (err)
+               goto out;
+
+       move_inline_data_to_front(handle);
+
+       x = handle->attrs;
+       /* Does the inode have size for EA? */
+       if (EXT2_INODE_SIZE(handle->fs->super) <= EXT2_GOOD_OLD_INODE_SIZE +
+                                                 inode->i_extra_isize +
+                                                 sizeof(__u32))
+               goto write_ea_block;
+
+       /* Write the inode EA */
+       ea_inode_magic = EXT2_EXT_ATTR_MAGIC;
+       memcpy(((char *) inode) + EXT2_GOOD_OLD_INODE_SIZE +
+              inode->i_extra_isize, &ea_inode_magic, sizeof(__u32));
+       storage_size = EXT2_INODE_SIZE(handle->fs->super) -
+               EXT2_GOOD_OLD_INODE_SIZE - inode->i_extra_isize -
+               sizeof(__u32);
+       start = ((char *) inode) + EXT2_GOOD_OLD_INODE_SIZE +
+               inode->i_extra_isize + sizeof(__u32);
+
+       err = write_xattrs_to_buffer(handle, &x, start, storage_size, 0);
+       if (err)
+               goto out;
+
+       /* Are we done? */
+       if (x == handle->attrs + handle->length)
+               goto skip_ea_block;
+
+write_ea_block:
+       /* Write the EA block */
+       err = ext2fs_get_mem(handle->fs->blocksize, &block_buf);
+       if (err)
+               goto out;
+
+       storage_size = handle->fs->blocksize -
+               sizeof(struct ext2_ext_attr_header);
+       start = block_buf + sizeof(struct ext2_ext_attr_header);
+
+       err = write_xattrs_to_buffer(handle, &x, start, storage_size,
+                                    (void *)start - block_buf);
+       if (err)
+               goto out2;
+
+       if (x < handle->attrs + handle->length) {
+               err = EXT2_ET_EA_NO_SPACE;
+               goto out2;
+       }
+
+       /* Write a header on the EA block */
+       header = block_buf;
+       header->h_magic = EXT2_EXT_ATTR_MAGIC;
+       header->h_refcount = 1;
+       header->h_blocks = 1;
+
+       /* Get a new block for writing */
+       err = prep_ea_block_for_write(handle->fs, handle->ino, inode);
+       if (err)
+               goto out2;
+
+       /* Finally, write the new EA block */
+       blk = ext2fs_file_acl_block(handle->fs,
+                                   (struct ext2_inode *)inode);
+       err = ext2fs_write_ext_attr3(handle->fs, blk, block_buf,
+                                    handle->ino);
+       if (err)
+               goto out2;
+
+skip_ea_block:
+       blk = ext2fs_file_acl_block(handle->fs, (struct ext2_inode *)inode);
+       if (!block_buf && blk) {
+               /* xattrs shrunk, free the block */
+               err = ext2fs_free_ext_attr(handle->fs, handle->ino, inode);
+               if (err)
+                       goto out;
+       }
+
+       /* Write the inode */
+       err = ext2fs_write_inode_full(handle->fs, handle->ino,
+                                     (struct ext2_inode *)inode,
+                                     EXT2_INODE_SIZE(handle->fs->super));
+       if (err)
+               goto out2;
+
+out2:
+       ext2fs_free_mem(&block_buf);
+out:
+       ext2fs_free_mem(&inode);
+       handle->dirty = 0;
+       return err;
+}
+
+static errcode_t read_xattrs_from_buffer(struct ext2_xattr_handle *handle,
+                                        struct ext2_ext_attr_entry *entries,
+                                        unsigned int storage_size,
+                                        void *value_start,
+                                        size_t *nr_read)
+{
+       struct ext2_xattr *x;
+       struct ext2_ext_attr_entry *entry;
+       const char *prefix;
+       void *ptr;
+       unsigned int remain, prefix_len;
+       errcode_t err;
+
+       x = handle->attrs;
+       while (x->name)
+               x++;
+
+       entry = entries;
+       remain = storage_size;
+       while (!EXT2_EXT_IS_LAST_ENTRY(entry)) {
+               __u32 hash;
+
+               /* header eats this space */
+               remain -= sizeof(struct ext2_ext_attr_entry);
+
+               /* is attribute name valid? */
+               if (EXT2_EXT_ATTR_SIZE(entry->e_name_len) > remain)
+                       return EXT2_ET_EA_BAD_NAME_LEN;
+
+               /* attribute len eats this space */
+               remain -= EXT2_EXT_ATTR_SIZE(entry->e_name_len);
+
+               /* check value size */
+               if (entry->e_value_size > remain)
+                       return EXT2_ET_EA_BAD_VALUE_SIZE;
+
+               /* e_value_block must be 0 in inode's ea */
+               if (entry->e_value_block != 0)
+                       return EXT2_ET_BAD_EA_BLOCK_NUM;
+
+               hash = ext2fs_ext_attr_hash_entry(entry, value_start +
+                                                        entry->e_value_offs);
+
+               /* e_hash may be 0 in older inode's ea */
+               if (entry->e_hash != 0 && entry->e_hash != hash)
+                       return EXT2_ET_BAD_EA_HASH;
+
+               remain -= entry->e_value_size;
+
+               /* Allocate space for more attrs? */
+               if (x == handle->attrs + handle->length) {
+                       err = ext2fs_xattrs_expand(handle, 4);
+                       if (err)
+                               return err;
+                       x = handle->attrs + handle->length - 4;
+               }
+
+               /* Extract name/value */
+               prefix = find_ea_prefix(entry->e_name_index);
+               prefix_len = (prefix ? strlen(prefix) : 0);
+               err = ext2fs_get_memzero(entry->e_name_len + prefix_len + 1,
+                                        &x->name);
+               if (err)
+                       return err;
+               if (prefix)
+                       memcpy(x->name, prefix, prefix_len);
+               if (entry->e_name_len)
+                       memcpy(x->name + prefix_len,
+                              (void *)entry + sizeof(*entry),
+                              entry->e_name_len);
+
+               err = ext2fs_get_mem(entry->e_value_size, &x->value);
+               if (err)
+                       return err;
+               x->value_len = entry->e_value_size;
+               memcpy(x->value, value_start + entry->e_value_offs,
+                      entry->e_value_size);
+               x++;
+               (*nr_read)++;
+               entry = EXT2_EXT_ATTR_NEXT(entry);
+       }
+
+       return 0;
+}
+
+static void xattrs_free_keys(struct ext2_xattr_handle *h)
+{
+       struct ext2_xattr *a = h->attrs;
+       size_t i;
+
+       for (i = 0; i < h->length; i++) {
+               if (a[i].name)
+                       ext2fs_free_mem(&a[i].name);
+               if (a[i].value)
+                       ext2fs_free_mem(&a[i].value);
+       }
+       h->count = 0;
+}
+
+errcode_t ext2fs_xattrs_read(struct ext2_xattr_handle *handle)
+{
+       struct ext2_xattr *attrs = NULL, *x;
+       struct ext2_inode_large *inode;
+       struct ext2_ext_attr_header *header;
+       __u32 ea_inode_magic;
+       unsigned int storage_size;
+       void *start, *block_buf = NULL;
+       blk64_t blk;
+       int i;
+       errcode_t err;
+
+       EXT2_CHECK_MAGIC(handle, EXT2_ET_MAGIC_EA_HANDLE);
+       i = EXT2_INODE_SIZE(handle->fs->super);
+       if (i < sizeof(*inode))
+               i = sizeof(*inode);
+       err = ext2fs_get_memzero(i, &inode);
+       if (err)
+               return err;
+
+       err = ext2fs_read_inode_full(handle->fs, handle->ino,
+                                    (struct ext2_inode *)inode,
+                                    EXT2_INODE_SIZE(handle->fs->super));
+       if (err)
+               goto out;
+
+       xattrs_free_keys(handle);
+
+       /* Does the inode have size for EA? */
+       if (EXT2_INODE_SIZE(handle->fs->super) <= EXT2_GOOD_OLD_INODE_SIZE +
+                                                 inode->i_extra_isize +
+                                                 sizeof(__u32))
+               goto read_ea_block;
+
+       /* Look for EA in the inode */
+       memcpy(&ea_inode_magic, ((char *) inode) + EXT2_GOOD_OLD_INODE_SIZE +
+              inode->i_extra_isize, sizeof(__u32));
+       if (ea_inode_magic == EXT2_EXT_ATTR_MAGIC) {
+               storage_size = EXT2_INODE_SIZE(handle->fs->super) -
+                       EXT2_GOOD_OLD_INODE_SIZE - inode->i_extra_isize -
+                       sizeof(__u32);
+               start = ((char *) inode) + EXT2_GOOD_OLD_INODE_SIZE +
+                       inode->i_extra_isize + sizeof(__u32);
+
+               err = read_xattrs_from_buffer(handle, start, storage_size,
+                                             start, &handle->count);
+               if (err)
+                       goto out;
+       }
+
+read_ea_block:
+       /* Look for EA in a separate EA block */
+       blk = ext2fs_file_acl_block(handle->fs, (struct ext2_inode *)inode);
+       if (blk != 0) {
+               if ((blk < handle->fs->super->s_first_data_block) ||
+                   (blk >= ext2fs_blocks_count(handle->fs->super))) {
+                       err = EXT2_ET_BAD_EA_BLOCK_NUM;
+                       goto out;
+               }
+
+               err = ext2fs_get_mem(handle->fs->blocksize, &block_buf);
+               if (err)
+                       goto out;
+
+               err = ext2fs_read_ext_attr3(handle->fs, blk, block_buf,
+                                           handle->ino);
+               if (err)
+                       goto out3;
+
+               header = (struct ext2_ext_attr_header *) block_buf;
+               if (header->h_magic != EXT2_EXT_ATTR_MAGIC) {
+                       err = EXT2_ET_BAD_EA_HEADER;
+                       goto out3;
+               }
+
+               if (header->h_blocks != 1) {
+                       err = EXT2_ET_BAD_EA_HEADER;
+                       goto out3;
+               }
+
+               /* Read EAs */
+               storage_size = handle->fs->blocksize -
+                       sizeof(struct ext2_ext_attr_header);
+               start = block_buf + sizeof(struct ext2_ext_attr_header);
+               err = read_xattrs_from_buffer(handle, start, storage_size,
+                                             block_buf, &handle->count);
+               if (err)
+                       goto out3;
+
+               ext2fs_free_mem(&block_buf);
+       }
+
+       ext2fs_free_mem(&block_buf);
+       ext2fs_free_mem(&inode);
+       return 0;
+
+out3:
+       ext2fs_free_mem(&block_buf);
+out:
+       ext2fs_free_mem(&inode);
+       return err;
+}
+
+errcode_t ext2fs_xattrs_iterate(struct ext2_xattr_handle *h,
+                               int (*func)(char *name, char *value,
+                                           size_t value_len, void *data),
+                               void *data)
+{
+       struct ext2_xattr *x;
+       errcode_t err;
+       int ret;
+
+       EXT2_CHECK_MAGIC(h, EXT2_ET_MAGIC_EA_HANDLE);
+       for (x = h->attrs; x < h->attrs + h->length; x++) {
+               if (!x->name)
+                       continue;
+
+               ret = func(x->name, x->value, x->value_len, data);
+               if (ret & XATTR_CHANGED)
+                       h->dirty = 1;
+               if (ret & XATTR_ABORT)
+                       return 0;
+       }
+
+       return 0;
+}
+
+errcode_t ext2fs_xattr_get(struct ext2_xattr_handle *h, const char *key,
+                          void **value, size_t *value_len)
+{
+       struct ext2_xattr *x;
+       void *val;
+       errcode_t err;
+
+       EXT2_CHECK_MAGIC(h, EXT2_ET_MAGIC_EA_HANDLE);
+       for (x = h->attrs; x < h->attrs + h->length; x++) {
+               if (!x->name)
+                       continue;
+
+               if (strcmp(x->name, key) == 0) {
+                       err = ext2fs_get_mem(x->value_len, &val);
+                       if (err)
+                               return err;
+                       memcpy(val, x->value, x->value_len);
+                       *value = val;
+                       *value_len = x->value_len;
+                       return 0;
+               }
+       }
+
+       return EXT2_ET_EA_KEY_NOT_FOUND;
+}
+
+errcode_t ext2fs_xattr_inode_max_size(ext2_filsys fs, ext2_ino_t ino,
+                                     size_t *size)
+{
+       struct ext2_ext_attr_header *header;
+       struct ext2_ext_attr_entry *entry;
+       struct ext2_inode_large *inode;
+       __u32 ea_inode_magic;
+       unsigned int storage_size, freesize, minoff;
+       void *start;
+       int i;
+       errcode_t err;
+
+       i = EXT2_INODE_SIZE(fs->super);
+       if (i < sizeof(*inode))
+               i = sizeof(*inode);
+       err = ext2fs_get_memzero(i, &inode);
+       if (err)
+               return err;
+
+       err = ext2fs_read_inode_full(fs, ino, (struct ext2_inode *)inode,
+                                    EXT2_INODE_SIZE(fs->super));
+       if (err)
+               goto out;
+
+       /* Does the inode have size for EA? */
+       if (EXT2_INODE_SIZE(fs->super) <= EXT2_GOOD_OLD_INODE_SIZE +
+                                                 inode->i_extra_isize +
+                                                 sizeof(__u32)) {
+               err = EXT2_ET_INLINE_DATA_NO_SPACE;
+               goto out;
+       }
+
+       minoff = EXT2_INODE_SIZE(fs->super) - sizeof(*inode) - sizeof(__u32);
+       memcpy(&ea_inode_magic, ((char *) inode) + EXT2_GOOD_OLD_INODE_SIZE +
+              inode->i_extra_isize, sizeof(__u32));
+       if (ea_inode_magic == EXT2_EXT_ATTR_MAGIC) {
+               /* has xattrs.  calculate the size */
+               storage_size = EXT2_INODE_SIZE(fs->super) -
+                       EXT2_GOOD_OLD_INODE_SIZE - inode->i_extra_isize -
+                       sizeof(__u32);
+               start= ((char *) inode) + EXT2_GOOD_OLD_INODE_SIZE +
+                       inode->i_extra_isize + sizeof(__u32);
+               entry = start;
+               while (!EXT2_EXT_IS_LAST_ENTRY(entry)) {
+                       if (!entry->e_value_block && entry->e_value_size) {
+                               unsigned int offs = entry->e_value_offs;
+                               if (offs < minoff)
+                                       minoff = offs;
+                       }
+                       entry = EXT2_EXT_ATTR_NEXT(entry);
+               }
+               *size = minoff - ((char *)entry - (char *)start) - sizeof(__u32);
+       } else {
+               /* no xattr.  return a maximum size */
+               *size = EXT2_EXT_ATTR_SIZE(minoff -
+                                          EXT2_EXT_ATTR_LEN(strlen("data")) -
+                                          EXT2_EXT_ATTR_ROUND - sizeof(__u32));
+       }
+
+out:
+       ext2fs_free_mem(&inode);
+       return err;
+}
+
+errcode_t ext2fs_xattr_set(struct ext2_xattr_handle *handle,
+                          const char *key,
+                          const void *value,
+                          size_t value_len)
+{
+       struct ext2_xattr *x, *last_empty;
+       char *new_value;
+       errcode_t err;
+
+       EXT2_CHECK_MAGIC(handle, EXT2_ET_MAGIC_EA_HANDLE);
+       last_empty = NULL;
+       for (x = handle->attrs; x < handle->attrs + handle->length; x++) {
+               if (!x->name) {
+                       last_empty = x;
+                       continue;
+               }
+
+               /* Replace xattr */
+               if (strcmp(x->name, key) == 0) {
+                       err = ext2fs_get_mem(value_len, &new_value);
+                       if (err)
+                               return err;
+                       memcpy(new_value, value, value_len);
+                       ext2fs_free_mem(&x->value);
+                       x->value = new_value;
+                       x->value_len = value_len;
+                       handle->dirty = 1;
+                       return 0;
+               }
+       }
+
+       /* Add attr to empty slot */
+       if (last_empty) {
+               err = ext2fs_get_mem(strlen(key) + 1, &last_empty->name);
+               if (err)
+                       return err;
+               strcpy(last_empty->name, key);
+
+               err = ext2fs_get_mem(value_len, &last_empty->value);
+               if (err)
+                       return err;
+               memcpy(last_empty->value, value, value_len);
+               last_empty->value_len = value_len;
+               handle->dirty = 1;
+               handle->count++;
+               return 0;
+       }
+
+       /* Expand array, append slot */
+       err = ext2fs_xattrs_expand(handle, 4);
+       if (err)
+               return err;
+
+       x = handle->attrs + handle->length - 4;
+       err = ext2fs_get_mem(strlen(key) + 1, &x->name);
+       if (err)
+               return err;
+       strcpy(x->name, key);
+
+       err = ext2fs_get_mem(value_len, &x->value);
+       if (err)
+               return err;
+       memcpy(x->value, value, value_len);
+       x->value_len = value_len;
+       handle->dirty = 1;
+       handle->count++;
+       return 0;
+}
+
+errcode_t ext2fs_xattr_remove(struct ext2_xattr_handle *handle,
+                             const char *key)
+{
+       struct ext2_xattr *x;
+       errcode_t err;
+
+       EXT2_CHECK_MAGIC(handle, EXT2_ET_MAGIC_EA_HANDLE);
+       for (x = handle->attrs; x < handle->attrs + handle->length; x++) {
+               if (!x->name)
+                       continue;
+
+               if (strcmp(x->name, key) == 0) {
+                       ext2fs_free_mem(&x->name);
+                       ext2fs_free_mem(&x->value);
+                       x->value_len = 0;
+                       handle->dirty = 1;
+                       handle->count--;
+                       return 0;
+               }
+       }
+
+       return EXT2_ET_EA_KEY_NOT_FOUND;
+}
+
+errcode_t ext2fs_xattrs_open(ext2_filsys fs, ext2_ino_t ino,
+                            struct ext2_xattr_handle **handle)
+{
+       struct ext2_xattr_handle *h;
+       errcode_t err;
+
+       if (!EXT2_HAS_COMPAT_FEATURE(fs->super,
+                                    EXT2_FEATURE_COMPAT_EXT_ATTR) &&
+           !EXT2_HAS_INCOMPAT_FEATURE(fs->super,
+                                    EXT4_FEATURE_INCOMPAT_INLINE_DATA))
+               return EXT2_ET_MISSING_EA_FEATURE;
+
+       err = ext2fs_get_memzero(sizeof(*h), &h);
+       if (err)
+               return err;
+
+       h->magic = EXT2_ET_MAGIC_EA_HANDLE;
+       h->length = 4;
+       err = ext2fs_get_arrayzero(h->length, sizeof(struct ext2_xattr),
+                                  &h->attrs);
+       if (err) {
+               ext2fs_free_mem(&h);
+               return err;
+       }
+       h->count = 0;
+       h->ino = ino;
+       h->fs = fs;
+       *handle = h;
+       return 0;
+}
+
+errcode_t ext2fs_xattrs_close(struct ext2_xattr_handle **handle)
+{
+       struct ext2_xattr_handle *h = *handle;
+       errcode_t err;
+
+       EXT2_CHECK_MAGIC(h, EXT2_ET_MAGIC_EA_HANDLE);
+       if (h->dirty) {
+               err = ext2fs_xattrs_write(h);
+               if (err)
+                       return err;
+       }
+
+       xattrs_free_keys(h);
+       ext2fs_free_mem(&h->attrs);
+       ext2fs_free_mem(handle);
+       return 0;
+}
+
+errcode_t ext2fs_xattrs_count(struct ext2_xattr_handle *handle, size_t *count)
+{
+       EXT2_CHECK_MAGIC(handle, EXT2_ET_MAGIC_EA_HANDLE);
+       *count = handle->count;
+       return 0;
 }
index 0bf82ea4b9a88bb624b2f27eacb6c4c1da173264..30673b549117b3c7082069e5e254436c350e3248 100644 (file)
@@ -58,6 +58,7 @@ struct ext2_extent_handle {
        int                     type;
        int                     level;
        int                     max_depth;
+       int                     max_paths;
        struct extent_path      *path;
 };
 
@@ -168,7 +169,7 @@ void ext2fs_extent_free(ext2_extent_handle_t handle)
                return;
 
        if (handle->path) {
-               for (i=1; i <= handle->max_depth; i++) {
+               for (i = 1; i < handle->max_paths; i++) {
                        if (handle->path[i].buf)
                                ext2fs_free_mem(&handle->path[i].buf);
                }
@@ -242,11 +243,10 @@ errcode_t ext2fs_extent_open2(ext2_filsys fs, ext2_ino_t ino,
        handle->max_depth = ext2fs_le16_to_cpu(eh->eh_depth);
        handle->type = ext2fs_le16_to_cpu(eh->eh_magic);
 
-       retval = ext2fs_get_mem(((handle->max_depth+1) *
-                                sizeof(struct extent_path)),
-                               &handle->path);
-       memset(handle->path, 0,
-              (handle->max_depth+1) * sizeof(struct extent_path));
+       handle->max_paths = handle->max_depth + 1;
+       retval = ext2fs_get_memzero(handle->max_paths *
+                                   sizeof(struct extent_path),
+                                   &handle->path);
        handle->path[0].buf = (char *) handle->inode->i_block;
 
        handle->path[0].left = handle->path[0].entries =
@@ -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);
        }
@@ -704,7 +720,14 @@ errcode_t ext2fs_extent_goto(ext2_extent_handle_t handle,
  * and so on.
  *
  * Safe to call for any position in node; if not at the first entry,
- * will  simply return.
+ * it will simply return.
+ *
+ * Note a subtlety of this function -- if there happen to be two extents
+ * mapping the same lblk and someone calls fix_parents on the second of the two
+ * extents, the position of the extent handle after the call will be the second
+ * extent if nothing happened, or the first extent if something did.  A caller
+ * in this situation must use ext2fs_extent_goto() after calling this function.
+ * Or simply don't map the same lblk with two extents, ever.
  */
 errcode_t ext2fs_extent_fix_parents(ext2_extent_handle_t handle)
 {
@@ -896,13 +919,11 @@ errcode_t ext2fs_extent_node_split(ext2_extent_handle_t handle)
        if (handle->level == 0) {
                new_root = 1;
                tocopy = ext2fs_le16_to_cpu(eh->eh_entries);
-               retval = ext2fs_get_mem(((handle->max_depth+2) *
-                                        sizeof(struct extent_path)),
-                                       &newpath);
+               retval = ext2fs_get_memzero((handle->max_paths + 1) *
+                                           sizeof(struct extent_path),
+                                           &newpath);
                if (retval)
                        goto done;
-               memset(newpath, 0,
-                      ((handle->max_depth+2) * sizeof(struct extent_path)));
        } else {
                tocopy = ext2fs_le16_to_cpu(eh->eh_entries) / 2;
        }
@@ -963,6 +984,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);
@@ -975,13 +1001,14 @@ errcode_t ext2fs_extent_node_split(ext2_extent_handle_t handle)
        /* current path now has fewer active entries, we copied some out */
        if (handle->level == 0) {
                memcpy(newpath, path,
-                      sizeof(struct extent_path) * (handle->max_depth+1));
+                      sizeof(struct extent_path) * handle->max_paths);
                handle->path = newpath;
                newpath = path;
                path = handle->path;
                path->entries = 1;
                path->left = path->max_entries - 1;
                handle->max_depth++;
+               handle->max_paths++;
                eh->eh_depth = ext2fs_cpu_to_le16(handle->max_depth);
        } else {
                path->entries -= tocopy;
@@ -1359,17 +1386,25 @@ errcode_t ext2fs_extent_set_bmap(ext2_extent_handle_t handle,
                                                               &next_extent);
                                if (retval)
                                        goto done;
-                               retval = ext2fs_extent_fix_parents(handle);
-                               if (retval)
-                                       goto done;
                        } else
                                retval = ext2fs_extent_insert(handle,
                                      EXT2_EXTENT_INSERT_AFTER, &newextent);
                        if (retval)
                                goto done;
-                       /* Now pointing at inserted extent; move back to prev */
+                       retval = ext2fs_extent_fix_parents(handle);
+                       if (retval)
+                               goto done;
+                       /*
+                        * Now pointing at inserted extent; move back to prev.
+                        *
+                        * We cannot use EXT2_EXTENT_PREV to go back; note the
+                        * subtlety in the comment for fix_parents().
+                        */
+                       retval = ext2fs_extent_goto(handle, logical);
+                       if (retval)
+                               goto done;
                        retval = ext2fs_extent_get(handle,
-                                                  EXT2_EXTENT_PREV_LEAF,
+                                                  EXT2_EXTENT_CURRENT,
                                                   &extent);
                        if (retval)
                                goto done;
@@ -1400,6 +1435,9 @@ errcode_t ext2fs_extent_set_bmap(ext2_extent_handle_t handle,
                        } else
                                retval = ext2fs_extent_insert(handle,
                                                              0, &newextent);
+                       if (retval)
+                               goto done;
+                       retval = ext2fs_extent_fix_parents(handle);
                        if (retval)
                                goto done;
                        retval = ext2fs_extent_get(handle,
@@ -1444,7 +1482,7 @@ errcode_t ext2fs_extent_set_bmap(ext2_extent_handle_t handle,
                        if (retval) {
                                r2 = ext2fs_extent_goto(handle, orig_lblk);
                                if (r2 == 0)
-                                       ext2fs_extent_replace(handle, 0,
+                                       (void)ext2fs_extent_replace(handle, 0,
                                                              &orig_extent);
                                goto done;
                        }
@@ -1460,11 +1498,12 @@ errcode_t ext2fs_extent_set_bmap(ext2_extent_handle_t handle,
                                r2 = ext2fs_extent_goto(handle,
                                                        newextent.e_lblk);
                                if (r2 == 0)
-                                       ext2fs_extent_delete(handle, 0);
+                                       (void)ext2fs_extent_delete(handle, 0);
                        }
                        r2 = ext2fs_extent_goto(handle, orig_lblk);
                        if (r2 == 0)
-                               ext2fs_extent_replace(handle, 0, &orig_extent);
+                               (void)ext2fs_extent_replace(handle, 0,
+                                                           &orig_extent);
                        goto done;
                }
        }
index 5a39c321aa788e080b2dfacc92e54c9aba309f29..14eaed34075e5b8e81e790bc06feaabe07f66c61 100644 (file)
@@ -224,6 +224,38 @@ errcode_t ext2fs_file_close(ext2_file_t file)
 }
 
 
+static errcode_t
+ext2fs_file_read_inline_data(ext2_file_t file, void *buf,
+                            unsigned int wanted, unsigned int *got)
+{
+       ext2_filsys fs;
+       errcode_t retval;
+       unsigned int count = 0;
+       size_t size;
+
+       fs = file->fs;
+       retval = ext2fs_inline_data_get(fs, file->ino, &file->inode,
+                                       file->buf, &size);
+       if (retval)
+               return retval;
+
+       if (file->pos >= size)
+               goto out;
+
+       count = size - file->pos;
+       if (count > wanted)
+               count = wanted;
+       memcpy(buf, file->buf + file->pos, count);
+       file->pos += count;
+       buf += count;
+
+out:
+       if (got)
+               *got = count;
+       return retval;
+}
+
+
 errcode_t ext2fs_file_read(ext2_file_t file, void *buf,
                           unsigned int wanted, unsigned int *got)
 {
@@ -236,6 +268,10 @@ errcode_t ext2fs_file_read(ext2_file_t file, void *buf,
        EXT2_CHECK_MAGIC(file, EXT2_ET_MAGIC_EXT2_FILE);
        fs = file->fs;
 
+       /* If an inode has inline data, things get complicated. */
+       if (file->inode.i_flags & EXT4_INLINE_DATA_FL)
+               return ext2fs_file_read_inline_data(file, buf, wanted, got);
+
        while ((file->pos < EXT2_I_SIZE(&file->inode)) && (wanted > 0)) {
                retval = sync_buffer_position(file);
                if (retval)
@@ -266,6 +302,66 @@ fail:
 }
 
 
+static errcode_t
+ext2fs_file_write_inline_data(ext2_file_t file, const void *buf,
+                             unsigned int nbytes, unsigned int *written)
+{
+       ext2_filsys fs;
+       errcode_t retval;
+       unsigned int count = 0;
+       size_t size;
+
+       fs = file->fs;
+       retval = ext2fs_inline_data_get(fs, file->ino, &file->inode,
+                                       file->buf, &size);
+       if (retval)
+               return retval;
+
+       if (file->pos < size) {
+               count = nbytes - file->pos;
+               memcpy(file->buf + file->pos, buf, count);
+
+               retval = ext2fs_inline_data_set(fs, file->ino, &file->inode,
+                                               file->buf, count);
+               if (retval == EXT2_ET_INLINE_DATA_NO_SPACE)
+                       goto expand;
+               if (retval)
+                       return retval;
+
+               file->pos += count;
+
+               /* Update inode size */
+               if (count != 0 && EXT2_I_SIZE(&file->inode) < file->pos) {
+                       errcode_t       rc;
+
+                       rc = ext2fs_file_set_size2(file, file->pos);
+                       if (retval == 0)
+                               retval = rc;
+               }
+
+               if (written)
+                       *written = count;
+               return 0;
+       }
+
+expand:
+       retval = ext2fs_inline_data_expand(fs, file->ino);
+       if (retval)
+               return retval;
+       /*
+        * reload inode and return no space error
+        *
+        * XXX: file->inode could be copied from the outside
+        * in ext2fs_file_open2().  We have no way to modify
+        * the outside inode.
+        */
+       retval = ext2fs_read_inode(fs, file->ino, &file->inode);
+       if (retval)
+               return retval;
+       return EXT2_ET_INLINE_DATA_NO_SPACE;
+}
+
+
 errcode_t ext2fs_file_write(ext2_file_t file, const void *buf,
                            unsigned int nbytes, unsigned int *written)
 {
@@ -280,6 +376,16 @@ errcode_t ext2fs_file_write(ext2_file_t file, const void *buf,
        if (!(file->flags & EXT2_FILE_WRITE))
                return EXT2_ET_FILE_RO;
 
+       /* If an inode has inline data, things get complicated. */
+       if (file->inode.i_flags & EXT4_INLINE_DATA_FL) {
+               retval = ext2fs_file_write_inline_data(file, buf, nbytes,
+                                                      written);
+               if (retval != EXT2_ET_INLINE_DATA_NO_SPACE)
+                       return retval;
+               /* fall through to read data from the block */
+               retval = 0;
+       }
+
        while (nbytes > 0) {
                retval = sync_buffer_position(file);
                if (retval)
index 1ad2d916f490c931c76b1da42e266480b994adf0..89a157bb8a9571259c0495b71758ec400956d5c3 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))
@@ -66,21 +64,6 @@ void ext2fs_free(ext2_filsys fs)
        ext2fs_free_mem(&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.
  */
index af5509725abd497fc3edc4188047a17962888979..3fc734981c185bb3cd97e046e45472ead06e16d8 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");
@@ -174,18 +174,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;
@@ -214,7 +214,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",
@@ -237,7 +237,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
 
@@ -254,7 +254,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);
@@ -294,10 +294,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");
@@ -324,7 +324,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;
        }
 
@@ -444,7 +445,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)
@@ -511,7 +512,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 9996e9d89ce5f754ef52a1dd26cb6e85df129372..a0742ee24b1017131802033599e7562e9aa4b6af 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 52aea624db52e59ab2607063a446d6afdfd43251..4c9c765530aef9a0af96f1ef5b02887327c0e70d 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 a3b20f0658b0d609db8442bb5e0641b00a60733c..5e1f5c65479101eb2d7c9d670e19d9a1aa133222 100644 (file)
@@ -193,13 +193,14 @@ errcode_t ext2fs_create_icount_tdb(ext2_filsys fs, char *tdb_dir,
                goto errout;
        uuid_unparse(fs->super->s_uuid, uuid);
        sprintf(fn, "%s/%s-icount-XXXXXX", tdb_dir, uuid);
-       icount->tdb_fn = fn;
        save_umask = umask(077);
        fd = mkstemp(fn);
        if (fd < 0) {
                retval = errno;
+               ext2fs_free_mem(&fn);
                goto errout;
        }
+       icount->tdb_fn = fn;
        umask(save_umask);
        /*
         * This is an overestimate of the size that we will need; the
index 36c94a9a4d8633ada857bd7bdedad92a358aefe1..75fbf8ee00614a82fd15b98e400364ad74203052 100644 (file)
@@ -476,8 +476,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++) {
                /*
diff --git a/lib/ext2fs/inline_data.c b/lib/ext2fs/inline_data.c
new file mode 100644 (file)
index 0000000..7a81da0
--- /dev/null
@@ -0,0 +1,846 @@
+/*
+ * inline_data.c --- data in inode
+ *
+ * Copyright (C) 2012 Zheng Liu <wenqing.lz@taobao.com>
+ *
+ * %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>
+#include <time.h>
+
+#include "ext2_fs.h"
+#include "ext2_ext_attr.h"
+
+#include "ext2fs.h"
+#include "ext2fsP.h"
+
+struct ext2_inline_data {
+       ext2_filsys fs;
+       ext2_ino_t ino;
+       size_t ea_size; /* the size of inline data in ea area */
+       void *ea_data;
+};
+
+static errcode_t ext2fs_inline_data_ea_set(struct ext2_inline_data *data)
+{
+       struct ext2_xattr_handle *handle;
+       errcode_t retval;
+
+       retval = ext2fs_xattrs_open(data->fs, data->ino, &handle);
+       if (retval)
+               return retval;
+
+       retval = ext2fs_xattrs_read(handle);
+       if (retval)
+               goto err;
+
+       retval = ext2fs_xattr_set(handle, "system.data",
+                                 data->ea_data, data->ea_size);
+       if (retval)
+               goto err;
+
+       retval = ext2fs_xattrs_write(handle);
+
+err:
+       (void) ext2fs_xattrs_close(&handle);
+       return retval;
+}
+
+static errcode_t ext2fs_inline_data_ea_get(struct ext2_inline_data *data)
+{
+       struct ext2_xattr_handle *handle;
+       errcode_t retval;
+
+       data->ea_size = 0;
+       data->ea_data = 0;
+
+       retval = ext2fs_xattrs_open(data->fs, data->ino, &handle);
+       if (retval)
+               return retval;
+
+       retval = ext2fs_xattrs_read(handle);
+       if (retval)
+               goto err;
+
+       retval = ext2fs_xattr_get(handle, "system.data",
+                                 (void **)&data->ea_data, &data->ea_size);
+       if (retval)
+               goto err;
+
+err:
+       (void) ext2fs_xattrs_close(&handle);
+       return retval;
+}
+
+errcode_t ext2fs_inline_data_init(ext2_filsys fs, ext2_ino_t ino)
+{
+       struct ext2_inline_data data;
+
+       data.fs = fs;
+       data.ino = ino;
+       data.ea_size = 0;
+       data.ea_data = "";
+       return ext2fs_inline_data_ea_set(&data);
+}
+
+errcode_t ext2fs_inline_data_size(ext2_filsys fs, ext2_ino_t ino, size_t *size)
+{
+       struct ext2_inode inode;
+       struct ext2_inline_data data;
+       errcode_t retval;
+
+       retval = ext2fs_read_inode(fs, ino, &inode);
+       if (retval)
+               return retval;
+
+       if (!(inode.i_flags & EXT4_INLINE_DATA_FL))
+               return EXT2_ET_NO_INLINE_DATA;
+
+       data.fs = fs;
+       data.ino = ino;
+       retval = ext2fs_inline_data_ea_get(&data);
+       if (retval)
+               return retval;
+
+       *size = EXT4_MIN_INLINE_DATA_SIZE + data.ea_size;
+       return ext2fs_free_mem(&data.ea_data);
+}
+
+int ext2fs_inline_data_dir_iterate(ext2_filsys fs, ext2_ino_t ino,
+                                  void *priv_data)
+{
+       struct dir_context *ctx;
+       struct ext2_inode inode;
+       struct ext2_dir_entry dirent;
+       struct ext2_inline_data data;
+       int ret = BLOCK_ABORT;
+       e2_blkcnt_t blockcnt = 0;
+       char *old_buf;
+       unsigned int old_buflen;
+       int old_flags;
+
+       ctx = (struct dir_context *)priv_data;
+       old_buf = ctx->buf;
+       old_buflen = ctx->buflen;
+       old_flags = ctx->flags;
+       ctx->flags |= DIRENT_FLAG_INCLUDE_INLINE_DATA;
+
+       ctx->errcode = ext2fs_read_inode(fs, ino, &inode);
+       if (ctx->errcode)
+               goto out;
+
+       if (!(inode.i_flags & EXT4_INLINE_DATA_FL)) {
+               ctx->errcode = EXT2_ET_NO_INLINE_DATA;
+               goto out;
+       }
+
+       if (!LINUX_S_ISDIR(inode.i_mode)) {
+               ctx->errcode = EXT2_ET_NO_DIRECTORY;
+               goto out;
+       }
+       ret = 0;
+
+       /* we first check '.' and '..' dir */
+       dirent.inode = ino;
+       dirent.name_len = 1;
+       ext2fs_set_rec_len(fs, EXT2_DIR_REC_LEN(2), &dirent);
+       dirent.name[0] = '.';
+       dirent.name[1] = '\0';
+       ctx->buf = (char *)&dirent;
+       ext2fs_get_rec_len(fs, &dirent, &ctx->buflen);
+       ret |= ext2fs_process_dir_block(fs, 0, blockcnt++, 0, 0, priv_data);
+       if (ret & BLOCK_ABORT)
+               goto out;
+
+       dirent.inode = ext2fs_le32_to_cpu(inode.i_block[0]);
+       dirent.name_len = 2;
+       ext2fs_set_rec_len(fs, EXT2_DIR_REC_LEN(3), &dirent);
+       dirent.name[0] = '.';
+       dirent.name[1] = '.';
+       dirent.name[2] = '\0';
+       ctx->buf = (char *)&dirent;
+       ext2fs_get_rec_len(fs, &dirent, &ctx->buflen);
+       ret |= ext2fs_process_dir_block(fs, 0, blockcnt++, 0, 0, priv_data);
+       if (ret & BLOCK_INLINE_DATA_CHANGED) {
+               errcode_t err;
+
+               inode.i_block[0] = ext2fs_cpu_to_le32(dirent.inode);
+               err = ext2fs_write_inode(fs, ino, &inode);
+               if (err)
+                       goto out;
+               ret &= ~BLOCK_INLINE_DATA_CHANGED;
+       }
+       if (ret & BLOCK_ABORT)
+               goto out;
+
+       ctx->buf = (char *)inode.i_block + EXT4_INLINE_DATA_DOTDOT_SIZE;
+       ctx->buflen = EXT4_MIN_INLINE_DATA_SIZE - EXT4_INLINE_DATA_DOTDOT_SIZE;
+#ifdef WORDS_BIGENDIAN
+       ctx->errcode = ext2fs_dirent_swab_in2(fs, ctx->buf, ctx->buflen, 0);
+       if (ctx->errcode) {
+               ret |= BLOCK_ABORT;
+               goto out;
+       }
+#endif
+       ret |= ext2fs_process_dir_block(fs, 0, blockcnt++, 0, 0, priv_data);
+       if (ret & BLOCK_INLINE_DATA_CHANGED) {
+#ifdef WORDS_BIGENDIAN
+               ctx->errcode = ext2fs_dirent_swab_out2(fs, ctx->buf,
+                                                      ctx->buflen, 0);
+               if (ctx->errcode) {
+                       ret |= BLOCK_ABORT;
+                       goto out;
+               }
+#endif
+               ctx->errcode = ext2fs_write_inode(fs, ino, &inode);
+               if (ctx->errcode)
+                       ret |= BLOCK_ABORT;
+               ret &= ~BLOCK_INLINE_DATA_CHANGED;
+       }
+       if (ret & BLOCK_ABORT)
+               goto out;
+
+       data.fs = fs;
+       data.ino = ino;
+       ctx->errcode = ext2fs_inline_data_ea_get(&data);
+       if (ctx->errcode) {
+               ret |= BLOCK_ABORT;
+               goto out;
+       }
+       if (data.ea_size <= 0)
+               goto out;
+
+       ctx->buf = data.ea_data;
+       ctx->buflen = data.ea_size;
+#ifdef WORDS_BIGENDIAN
+       ctx->errcode = ext2fs_dirent_swab_in2(fs, ctx->buf, ctx->buflen, 0);
+       if (ctx->errcode) {
+               ret |= BLOCK_ABORT;
+               goto out;
+       }
+#endif
+
+       ret |= ext2fs_process_dir_block(fs, 0, blockcnt++, 0, 0, priv_data);
+       if (ret & BLOCK_INLINE_DATA_CHANGED) {
+#ifdef WORDS_BIGENDIAN
+               ctx->errcode = ext2fs_dirent_swab_out2(fs, ctx->buf,
+                                                     ctx->buflen, 0);
+               if (ctx->errcode) {
+                       ret |= BLOCK_ABORT;
+                       goto out1;
+               }
+#endif
+               ctx->errcode = ext2fs_inline_data_ea_set(&data);
+               if (ctx->errcode)
+                       ret |= BLOCK_ABORT;
+       }
+
+out1:
+       ext2fs_free_mem(&data.ea_data);
+out:
+       ctx->buf = old_buf;
+       ctx->buflen = old_buflen;
+       ctx->flags = old_flags;
+       ret &= ~(BLOCK_ABORT | BLOCK_INLINE_DATA_CHANGED);
+       return ret;
+}
+
+errcode_t ext2fs_inline_data_ea_remove(ext2_filsys fs, ext2_ino_t ino)
+{
+       struct ext2_xattr_handle *handle;
+       errcode_t retval;
+
+       retval = ext2fs_xattrs_open(fs, ino, &handle);
+       if (retval)
+               return retval;
+
+       retval = ext2fs_xattrs_read(handle);
+       if (retval)
+               goto err;
+
+       retval = ext2fs_xattr_remove(handle, "system.data");
+       if (retval)
+               goto err;
+
+       retval = ext2fs_xattrs_write(handle);
+
+err:
+       (void) ext2fs_xattrs_close(&handle);
+       return retval;
+}
+
+static errcode_t ext2fs_inline_data_convert_dir(ext2_filsys fs, ext2_ino_t ino,
+                                               char *bbuf, char *ibuf, int size)
+{
+       struct ext2_dir_entry *dir, *dir2;
+       struct ext2_dir_entry_tail *t;
+       errcode_t retval;
+       unsigned int offset;
+       int csum_size = 0;
+       int filetype = 0;
+       int rec_len;
+
+       if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+                                      EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
+               csum_size = sizeof(struct ext2_dir_entry_tail);
+
+       /* Create '.' and '..' */
+       if (EXT2_HAS_INCOMPAT_FEATURE(fs->super,
+                                     EXT2_FEATURE_INCOMPAT_FILETYPE))
+               filetype = EXT2_FT_DIR;
+
+       /*
+        * Set up entry for '.'
+        */
+       dir = (struct ext2_dir_entry *) bbuf;
+       dir->inode = ino;
+       ext2fs_dirent_set_name_len(dir, 1);
+       ext2fs_dirent_set_file_type(dir, filetype);
+       dir->name[0] = '.';
+       rec_len = (fs->blocksize - csum_size) - EXT2_DIR_REC_LEN(1);
+       dir->rec_len = EXT2_DIR_REC_LEN(1);
+
+       /*
+        * Set up entry for '..'
+        */
+       dir = (struct ext2_dir_entry *) (bbuf + dir->rec_len);
+       dir->rec_len = EXT2_DIR_REC_LEN(2);
+       dir->inode = ext2fs_le32_to_cpu(((__u32 *)ibuf)[0]);
+       ext2fs_dirent_set_name_len(dir, 2);
+       ext2fs_dirent_set_file_type(dir, filetype);
+       dir->name[0] = '.';
+       dir->name[1] = '.';
+
+       /*
+        * Ajust the last rec_len
+        */
+       offset = EXT2_DIR_REC_LEN(1) + EXT2_DIR_REC_LEN(2);
+       dir = (struct ext2_dir_entry *) (bbuf + offset);
+       memcpy(bbuf + offset, ibuf + EXT4_INLINE_DATA_DOTDOT_SIZE,
+              size - EXT4_INLINE_DATA_DOTDOT_SIZE);
+       size += EXT2_DIR_REC_LEN(1) + EXT2_DIR_REC_LEN(2) -
+               EXT4_INLINE_DATA_DOTDOT_SIZE;
+
+       do {
+               dir2 = dir;
+               retval = ext2fs_get_rec_len(fs, dir, &rec_len);
+               if (retval)
+                       goto err;
+               offset += rec_len;
+               dir = (struct ext2_dir_entry *) (bbuf + offset);
+       } while (offset < size);
+       rec_len += fs->blocksize - csum_size - offset;
+       retval = ext2fs_set_rec_len(fs, rec_len, dir2);
+       if (retval)
+               goto err;
+
+       if (csum_size) {
+               t = EXT2_DIRENT_TAIL(bbuf, fs->blocksize);
+               ext2fs_initialize_dirent_tail(fs, t);
+       }
+
+err:
+       return retval;
+}
+
+static errcode_t
+ext2fs_inline_data_dir_expand(ext2_filsys fs, ext2_ino_t ino,
+                             struct ext2_inode *inode, char *buf, size_t size)
+{
+       errcode_t retval;
+       blk64_t blk;
+       char *blk_buf;
+
+       retval = ext2fs_get_memzero(fs->blocksize, &blk_buf);
+       if (retval)
+               return retval;
+
+#ifdef WORDS_BIGENDIAN
+       retval = ext2fs_dirent_swab_in2(fs, buf, size, 0);
+       if (retval)
+               goto errout;
+#endif
+
+       /* Adjust the rec_len */
+       retval = ext2fs_inline_data_convert_dir(fs, ino, blk_buf, buf, size);
+       /* Allocate a new block */
+       retval = ext2fs_new_block2(fs, 0, 0, &blk);
+       if (retval)
+               goto errout;
+       retval = ext2fs_write_dir_block4(fs, blk, blk_buf, 0, ino);
+       if (retval)
+               goto errout;
+
+       /* Update inode */
+       if (EXT2_HAS_INCOMPAT_FEATURE(fs->super, EXT3_FEATURE_INCOMPAT_EXTENTS))
+               inode->i_flags |= EXT4_EXTENTS_FL;
+       inode->i_flags &= ~EXT4_INLINE_DATA_FL;
+       retval = ext2fs_iblk_add_blocks(fs, inode, 1);
+       if (retval)
+               goto errout;
+       inode->i_size = fs->blocksize;
+       retval = ext2fs_bmap2(fs, ino, inode, 0, BMAP_SET, 0, 0, &blk);
+       if (retval)
+               goto errout;
+       retval = ext2fs_write_inode(fs, ino, inode);
+       if (retval)
+               goto errout;
+       ext2fs_block_alloc_stats(fs, blk, +1);
+
+errout:
+       ext2fs_free_mem(&blk_buf);
+       return retval;
+}
+
+static errcode_t
+ext2fs_inline_data_file_expand(ext2_filsys fs, ext2_ino_t ino,
+                              struct ext2_inode *inode, char *buf, size_t size)
+{
+       ext2_file_t e2_file;
+       errcode_t retval;
+
+       /* Update inode */
+       if (EXT2_HAS_INCOMPAT_FEATURE(fs->super,
+                                     EXT3_FEATURE_INCOMPAT_EXTENTS)) {
+               int i;
+               struct ext3_extent_header *eh;
+
+               eh = (struct ext3_extent_header *) &inode->i_block[0];
+               eh->eh_depth = 0;
+               eh->eh_entries = 0;
+               eh->eh_magic = EXT3_EXT_MAGIC;
+               i = (sizeof(inode->i_block) - sizeof(*eh)) /
+                       sizeof(struct ext3_extent);
+               eh->eh_max = ext2fs_cpu_to_le16(i);
+               inode->i_flags |= EXT4_EXTENTS_FL;
+       }
+       inode->i_flags &= ~EXT4_INLINE_DATA_FL;
+       inode->i_size = 0;
+       retval = ext2fs_write_inode(fs, ino, inode);
+       if (retval)
+               return retval;
+
+       /* Write out the block buffer */
+       retval = ext2fs_file_open(fs, ino, EXT2_FILE_WRITE, &e2_file);
+       if (retval)
+               return retval;
+       retval = ext2fs_file_write(e2_file, buf, size, 0);
+       ext2fs_file_close(e2_file);
+       return retval;
+}
+
+errcode_t ext2fs_inline_data_expand(ext2_filsys fs, ext2_ino_t ino)
+{
+       struct ext2_inode inode;
+       struct ext2_inline_data data;
+       errcode_t retval;
+       size_t inline_size;
+       char *inline_buf = 0;
+
+       EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
+
+       retval = ext2fs_read_inode(fs, ino, &inode);
+       if (retval)
+               return retval;
+
+       if (!(inode.i_flags & EXT4_INLINE_DATA_FL))
+               return EXT2_ET_NO_INLINE_DATA;
+
+       data.fs = fs;
+       data.ino = ino;
+       retval = ext2fs_inline_data_ea_get(&data);
+       if (retval)
+               return retval;
+       inline_size = data.ea_size + EXT4_MIN_INLINE_DATA_SIZE;
+       retval = ext2fs_get_mem(inline_size, &inline_buf);
+       if (retval)
+               goto errout;
+
+       memcpy(inline_buf, (void *)inode.i_block, EXT4_MIN_INLINE_DATA_SIZE);
+       if (data.ea_size > 0) {
+               memcpy(inline_buf + EXT4_MIN_INLINE_DATA_SIZE,
+                      data.ea_data, data.ea_size);
+       }
+
+       memset((void *)inode.i_block, 0, EXT4_MIN_INLINE_DATA_SIZE);
+       /*
+        * NOTE: We must do this write -> ea_remove -> read cycle here because
+        * removing the inline data EA can free the EA block, which is a change
+        * that our stack copy of the inode will never see.  If that happens,
+        * we can end up with the EA block and lblk 0 pointing to the same
+        * pblk, which is bad news.
+        */
+       retval = ext2fs_write_inode(fs, ino, &inode);
+       if (retval)
+               goto errout;
+       retval = ext2fs_inline_data_ea_remove(fs, ino);
+       if (retval)
+               goto errout;
+       retval = ext2fs_read_inode(fs, ino, &inode);
+       if (retval)
+               goto errout;
+
+       if (LINUX_S_ISDIR(inode.i_mode)) {
+               retval = ext2fs_inline_data_dir_expand(fs, ino, &inode,
+                                               inline_buf, inline_size);
+       } else {
+               retval = ext2fs_inline_data_file_expand(fs, ino, &inode,
+                                               inline_buf, inline_size);
+       }
+
+errout:
+       if (inline_buf)
+               ext2fs_free_mem(&inline_buf);
+       ext2fs_free_mem(&data.ea_data);
+       return retval;
+}
+
+/*
+ * When caller uses this function to retrieve the inline data, it must
+ * allocate a buffer which has the size of inline data.  The size of
+ * inline data can be know by ext2fs_inline_data_get_size().
+ */
+errcode_t ext2fs_inline_data_get(ext2_filsys fs, ext2_ino_t ino,
+                                struct ext2_inode *inode,
+                                void *buf, size_t *size)
+{
+       struct ext2_inode inode_buf;
+       struct ext2_inline_data data;
+       errcode_t retval;
+
+       if (!inode) {
+               retval = ext2fs_read_inode(fs, ino, &inode_buf);
+               if (retval)
+                       return retval;
+               inode = &inode_buf;
+       }
+
+       data.fs = fs;
+       data.ino = ino;
+       retval = ext2fs_inline_data_ea_get(&data);
+       if (retval)
+               return retval;
+
+       memcpy(buf, (void *)inode->i_block, EXT4_MIN_INLINE_DATA_SIZE);
+       if (data.ea_size > 0)
+               memcpy(buf + EXT4_MIN_INLINE_DATA_SIZE,
+                      data.ea_data, data.ea_size);
+
+       if (size)
+               *size = EXT4_MIN_INLINE_DATA_SIZE + data.ea_size;
+       ext2fs_free_mem(&data.ea_data);
+       return 0;
+}
+
+errcode_t ext2fs_inline_data_set(ext2_filsys fs, ext2_ino_t ino,
+                                struct ext2_inode *inode,
+                                void *buf, size_t size)
+{
+       struct ext2_inode inode_buf;
+       struct ext2_inline_data data;
+       errcode_t retval;
+       size_t free_ea_size, existing_size, free_inode_size;
+
+       if (!inode) {
+               retval = ext2fs_read_inode(fs, ino, &inode_buf);
+               if (retval)
+                       return retval;
+               inode = &inode_buf;
+       }
+
+       if (size <= EXT4_MIN_INLINE_DATA_SIZE) {
+               memcpy((void *)inode->i_block, buf, size);
+               return ext2fs_write_inode(fs, ino, inode);
+       }
+
+       retval = ext2fs_xattr_inode_max_size(fs, ino, &free_ea_size);
+       if (retval)
+               return retval;
+
+       retval = ext2fs_inline_data_size(fs, ino, &existing_size);
+       if (retval)
+               return retval;
+
+       if (existing_size < EXT4_MIN_INLINE_DATA_SIZE)
+               free_inode_size = EXT4_MIN_INLINE_DATA_SIZE - existing_size;
+       else
+               free_inode_size = 0;
+
+       if (size > existing_size + free_ea_size + free_inode_size)
+               return EXT2_ET_INLINE_DATA_NO_SPACE;
+
+       memcpy((void *)inode->i_block, buf, EXT4_MIN_INLINE_DATA_SIZE);
+       retval = ext2fs_write_inode(fs, ino, inode);
+       if (retval)
+               return retval;
+       data.fs = fs;
+       data.ino = ino;
+       data.ea_size = size - EXT4_MIN_INLINE_DATA_SIZE;
+       data.ea_data = buf + EXT4_MIN_INLINE_DATA_SIZE;
+       return ext2fs_inline_data_ea_set(&data);
+}
+
+#ifdef DEBUG
+#include "e2p/e2p.h"
+
+/*
+ * The length of buffer is set to 64 because in inode's i_block member it only
+ * can save 60 bytes.  Thus this value can let the data being saved in extra
+ * space.
+ */
+#define BUFF_SIZE (64)
+
+static errcode_t file_test(ext2_filsys fs)
+{
+       struct ext2_inode inode;
+       ext2_ino_t newfile;
+       errcode_t retval;
+       size_t size;
+       char *buf = 0, *cmpbuf = 0;
+       int i;
+
+       /* create a new file */
+       retval = ext2fs_new_inode(fs, 2, 010755, 0, &newfile);
+       if (retval) {
+               com_err("file_test", retval, "while allocaing a new inode");
+               return 1;
+       }
+
+       memset(&inode, 0, sizeof(inode));
+       inode.i_flags |= EXT4_INLINE_DATA_FL;
+       inode.i_size = EXT4_MIN_INLINE_DATA_SIZE;
+       inode.i_mode = LINUX_S_IFREG;
+       retval = ext2fs_write_new_inode(fs, newfile, &inode);
+       if (retval) {
+               com_err("file_test", retval, "while writting a new inode");
+               return 1;
+       }
+
+       retval = ext2fs_inline_data_init(fs, newfile);
+       if (retval) {
+               com_err("file_test", retval, "while init 'system.data'");
+               return 1;
+       }
+
+       retval = ext2fs_inline_data_size(fs, newfile, &size);
+       if (retval) {
+               com_err("file_test", retval, "while getting size");
+               return 1;
+       }
+
+       if (size != EXT4_MIN_INLINE_DATA_SIZE) {
+               fprintf(stderr,
+                       "tst_inline_data: size of inline data is wrong\n");
+               return 1;
+       }
+
+       ext2fs_get_mem(BUFF_SIZE, &buf);
+       memset(buf, 'a', BUFF_SIZE);
+       retval = ext2fs_inline_data_set(fs, newfile, 0, buf, BUFF_SIZE);
+       if (retval) {
+               com_err("file_test", retval,
+                       "while setting inline data %s", buf);
+               goto err;
+       }
+
+       ext2fs_get_mem(BUFF_SIZE, &cmpbuf);
+       retval = ext2fs_inline_data_get(fs, newfile, 0, cmpbuf, &size);
+       if (retval) {
+               com_err("file_test", retval, "while getting inline data");
+               goto err;
+       }
+
+       if (size != BUFF_SIZE) {
+               fprintf(stderr,
+                       "tst_inline_data: size %lu != buflen %lu\n",
+                       size, BUFF_SIZE);
+               retval = 1;
+               goto err;
+       }
+
+       if (memcmp(buf, cmpbuf, BUFF_SIZE)) {
+               fprintf(stderr, "tst_inline_data: buf != cmpbuf\n");
+               retval = 1;
+               goto err;
+       }
+
+       retval = ext2fs_punch(fs, newfile, 0, 0, 0, ~0ULL);
+       if (retval) {
+               com_err("file_test", retval, "while truncating inode");
+               goto err;
+       }
+
+       /* reload inode and check isize */
+       ext2fs_read_inode(fs, newfile, &inode);
+       if (inode.i_size != 0) {
+               fprintf(stderr, "tst_inline_data: i_size should be 0\n");
+               retval = 1;
+       }
+
+err:
+       if (cmpbuf)
+               ext2fs_free_mem(&cmpbuf);
+       if (buf)
+               ext2fs_free_mem(&buf);
+       return retval;
+}
+
+static errcode_t dir_test(ext2_filsys fs)
+{
+       const char *dot_name = ".";
+       const char *stub_name = "stub";
+       const char *parent_name = "test";
+       ext2_ino_t parent, dir, tmp;
+       errcode_t retval;
+       char dirname[PATH_MAX];
+       int i;
+
+       retval = ext2fs_mkdir(fs, 11, 11, stub_name);
+       if (retval) {
+               com_err("dir_test", retval, "while creating %s dir", stub_name);
+               return retval;
+       }
+
+       retval = ext2fs_mkdir(fs, 11, 0, parent_name);
+       if (retval) {
+               com_err("dir_test", retval,
+                       "while creating %s dir", parent_name);
+               return retval;
+       }
+
+       retval = ext2fs_lookup(fs, 11, parent_name, strlen(parent_name),
+                              0, &parent);
+       if (retval) {
+               com_err("dir_test", retval,
+                       "while looking up %s dir", parent_name);
+               return retval;
+       }
+
+       retval = ext2fs_lookup(fs, parent, dot_name, strlen(dot_name),
+                              0, &tmp);
+       if (retval) {
+               com_err("dir_test", retval,
+                       "while looking up %s dir", parent_name);
+               return retval;
+       }
+
+       if (parent != tmp) {
+               fprintf(stderr, "tst_inline_data: parent (%lu) != tmp (%lu)\n",
+                       parent, tmp);
+               return 1;
+       }
+
+       for (i = 0, dir = 13; i < 4; i++, dir++) {
+               tmp = 0;
+               snprintf(dirname, PATH_MAX, "%d", i);
+               retval = ext2fs_mkdir(fs, parent, 0, dirname);
+               if (retval) {
+                       com_err("dir_test", retval,
+                               "while creating %s dir", dirname);
+                       return retval;
+               }
+
+               retval = ext2fs_lookup(fs, parent, dirname, strlen(dirname),
+                                      0, &tmp);
+               if (retval) {
+                       com_err("dir_test", retval,
+                               "while looking up %s dir", parent_name);
+                       return retval;
+               }
+
+               if (dir != tmp) {
+                       fprintf(stderr, "tst_inline_data: dir (%lu) != tmp (%lu)\n",
+                               dir, tmp);
+                       return 1;
+               }
+       }
+
+       snprintf(dirname, PATH_MAX, "%d", i);
+       retval = ext2fs_mkdir(fs, parent, 0, dirname);
+       if (retval && retval != EXT2_ET_DIR_NO_SPACE) {
+               com_err("dir_test", retval, "while creating %s dir", dirname);
+               return retval;
+       }
+
+       retval = ext2fs_expand_dir(fs, parent);
+       if (retval) {
+               com_err("dir_test", retval, "while expanding %s dir", parent_name);
+               return retval;
+       }
+
+       return 0;
+}
+
+int main(int argc, char *argv[])
+{
+       ext2_filsys             fs;
+       struct ext2_super_block param;
+       errcode_t               retval;
+       int                     i;
+
+       /* setup */
+       initialize_ext2_error_table();
+
+       memset(&param, 0, sizeof(param));
+       ext2fs_blocks_count_set(&param, 32768);
+       param.s_inodes_count = 100;
+
+       param.s_feature_incompat |= EXT4_FEATURE_INCOMPAT_INLINE_DATA;
+       param.s_rev_level = EXT2_DYNAMIC_REV;
+       param.s_inode_size = 256;
+
+       retval = ext2fs_initialize("test fs", EXT2_FLAG_64BITS, &param,
+                                  test_io_manager, &fs);
+       if (retval) {
+               com_err("setup", retval,
+                       "while initializing filesystem");
+               exit(1);
+       }
+
+       retval = ext2fs_allocate_tables(fs);
+       if (retval) {
+               com_err("setup", retval,
+                       "while allocating tables for test filesysmte");
+               exit(1);
+       }
+
+       /* initialize inode cache */
+       if (!fs->icache) {
+               struct ext2_inode inode;
+               ext2_ino_t first_ino = EXT2_FIRST_INO(fs->super);
+               int i;
+
+               /* we just want to init inode cache.  So ignore error */
+               ext2fs_create_inode_cache(fs, 16);
+               if (!fs->icache) {
+                       fprintf(stderr,
+                               "tst_inline_data: init inode cache failed\n");
+                       exit(1);
+               }
+
+               /* setup inode cache */
+               for (i = 0; i < fs->icache->cache_size; i++)
+                       fs->icache->cache[i].ino = first_ino++;
+       }
+
+       /* test */
+       if (file_test(fs)) {
+               fprintf(stderr, "tst_inline_data(FILE): FAILED\n");
+               return 1;
+       }
+       printf("tst_inline_data(FILE): OK\n");
+
+       if (dir_test(fs)) {
+               fprintf(stderr, "tst_inline_data(DIR): FAILED\n");
+               return 1;
+       }
+       printf("tst_inline_data(DIR): OK\n");
+
+       return 0;
+}
+#endif
index 573a8fa5e0423a0a21440cbff1e4c2779fdaf2db..0cea9f0215f1c3d6b05737698f02caadbb1cc474 100644 (file)
@@ -72,8 +72,28 @@ errcode_t ext2fs_flush_icache(ext2_filsys fs)
        return 0;
 }
 
-static errcode_t create_icache(ext2_filsys fs)
+/*
+ * 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);
+}
+
+errcode_t ext2fs_create_inode_cache(ext2_filsys fs, unsigned int cache_size)
 {
+       int             i;
        errcode_t       retval;
 
        if (fs->icache)
@@ -84,24 +104,32 @@ 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;
+       fs->icache->cache_size = cache_size;
        fs->icache->refcount = 1;
        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);
 
@@ -544,18 +596,16 @@ errcode_t ext2fs_read_inode_full(ext2_filsys fs, ext2_ino_t ino,
                return EXT2_ET_BAD_INODE_NUM;
        /* Create inode cache if not present */
        if (!fs->icache) {
-               retval = create_icache(fs);
+               retval = ext2fs_create_inode_cache(fs, 4);
                if (retval)
                        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);
+               retval = ext2fs_create_inode_cache(fs, 4);
                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 7b8aafd755a21efb9cd0f325544f1aa86c9695ae..7947ef5aefb35887a52f48bb3fa1aa5d028e10ba 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 059bf8facde4ed662d0e3e60dd78f7c7670ec734..130c3a2ba1b9b0a224f695bd9dce5b13f94698c5 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 bf3c859a51398e495fdbae4cee26ca545524b0f5..09e6cb450fbbadab8b8e5884a34cc33f295d3eb0 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;
@@ -66,13 +71,47 @@ static int link_proc(struct ext2_dir_entry *dirent,
                ret = DIRENT_CHANGED;
        }
 
+       /*
+        * 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 0e66e71203ad240c604aae9a68a876b60b0f5c30..c1d802c0a45b59a774b49772ab5f850731b39074 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 b12bf2dda97e2eadd7dfa6a0b21cf15f477d7426..c4c79679b6366ca6593ecb25346dfdf6398d86e5 100644 (file)
@@ -26,6 +26,7 @@
 
 #include "ext2_fs.h"
 #include "ext2fs.h"
+#include "ext2fsP.h"
 
 #ifndef EXT2_FT_DIR
 #define EXT2_FT_DIR            2
@@ -41,9 +42,19 @@ errcode_t ext2fs_mkdir(ext2_filsys fs, ext2_ino_t parent, ext2_ino_t inum,
        ext2_ino_t              scratch_ino;
        blk64_t                 blk;
        char                    *block = 0;
+       int                     inline_data = 0;
 
        EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
 
+       /*
+        * Create a new dir with inline data iff this feature is enabled
+        * and ino >= EXT2_FIRST_INO.
+        */
+       if ((!ino || ino >= EXT2_FIRST_INO(fs->super)) &&
+           EXT2_HAS_INCOMPAT_FEATURE(fs->super,
+                                     EXT4_FEATURE_INCOMPAT_INLINE_DATA))
+               inline_data = 1;
+
        /*
         * Allocate an inode, if necessary
         */
@@ -57,14 +68,21 @@ errcode_t ext2fs_mkdir(ext2_filsys fs, ext2_ino_t parent, ext2_ino_t inum,
        /*
         * Allocate a data block for the directory
         */
-       retval = ext2fs_new_block2(fs, 0, 0, &blk);
-       if (retval)
-               goto cleanup;
+       if (!inline_data) {
+               retval = ext2fs_new_block2(fs, 0, 0, &blk);
+               if (retval)
+                       goto cleanup;
+       }
 
        /*
         * Create a scratch template for the directory
         */
-       retval = ext2fs_new_dir_block(fs, ino, parent, &block);
+       memset(&inode, 0, sizeof(struct ext2_inode));
+       if (inline_data)
+               retval = ext2fs_new_dir_inline_data(fs, ino, parent,
+                                                   inode.i_block);
+       else
+               retval = ext2fs_new_dir_block(fs, ino, parent, &block);
        if (retval)
                goto cleanup;
 
@@ -81,35 +99,48 @@ errcode_t ext2fs_mkdir(ext2_filsys fs, ext2_ino_t parent, ext2_ino_t inum,
        /*
         * Create the inode structure....
         */
-       memset(&inode, 0, sizeof(struct ext2_inode));
        inode.i_mode = LINUX_S_IFDIR | (0777 & ~fs->umask);
        inode.i_uid = inode.i_gid = 0;
-       ext2fs_iblk_set(fs, &inode, 1);
-       if (fs->super->s_feature_incompat & EXT3_FEATURE_INCOMPAT_EXTENTS)
-               inode.i_flags |= EXT4_EXTENTS_FL;
-       else
-               inode.i_block[0] = blk;
+       if (inline_data) {
+               inode.i_flags |= EXT4_INLINE_DATA_FL;
+               inode.i_size = EXT4_MIN_INLINE_DATA_SIZE;
+       } else {
+               if (fs->super->s_feature_incompat &
+                   EXT3_FEATURE_INCOMPAT_EXTENTS)
+                       inode.i_flags |= EXT4_EXTENTS_FL;
+               else
+                       inode.i_block[0] = blk;
+               inode.i_size = fs->blocksize;
+               ext2fs_iblk_set(fs, &inode, 1);
+       }
        inode.i_links_count = 2;
-       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);
-       if (retval)
-               goto cleanup;
        retval = ext2fs_write_new_inode(fs, ino, &inode);
        if (retval)
                goto cleanup;
-
-       if (fs->super->s_feature_incompat & EXT3_FEATURE_INCOMPAT_EXTENTS) {
-               retval = ext2fs_extent_open2(fs, ino, &inode, &handle);
-               if (retval)
-                       goto cleanup;
-               retval = ext2fs_extent_set_bmap(handle, 0, blk, 0);
-               ext2fs_extent_free(handle);
+       if (inline_data) {
+               /* init "system.data" for new dir */
+               retval = ext2fs_inline_data_init(fs, ino);
+       } else {
+               retval = ext2fs_write_dir_block4(fs, blk, block, 0, ino);
                if (retval)
                        goto cleanup;
+
+               if (fs->super->s_feature_incompat &
+                   EXT3_FEATURE_INCOMPAT_EXTENTS) {
+                       retval = ext2fs_extent_open2(fs, ino, &inode, &handle);
+                       if (retval)
+                               goto cleanup;
+                       retval = ext2fs_extent_set_bmap(handle, 0, blk, 0);
+                       ext2fs_extent_free(handle);
+                       if (retval)
+                               goto cleanup;
+               }
        }
 
        /*
@@ -134,6 +165,10 @@ errcode_t ext2fs_mkdir(ext2_filsys fs, ext2_ino_t parent, ext2_ino_t inum,
         * Update parent inode's counts
         */
        if (parent != ino) {
+               /* reload parent inode due to inline data */
+               retval = ext2fs_read_inode(fs, parent, &parent_inode);
+               if (retval)
+                       goto cleanup;
                parent_inode.i_links_count++;
                retval = ext2fs_write_inode(fs, parent, &parent_inode);
                if (retval)
@@ -143,7 +178,8 @@ errcode_t ext2fs_mkdir(ext2_filsys fs, ext2_ino_t parent, ext2_ino_t inum,
        /*
         * Update accounting....
         */
-       ext2fs_block_alloc_stats2(fs, blk, +1);
+       if (!inline_data)
+               ext2fs_block_alloc_stats2(fs, blk, +1);
        ext2fs_inode_alloc_stats2(fs, ino, +1, 1);
 
 cleanup:
index e4c7dccd21f87d55b1766f19d9c63ec734b99cd9..afb825c3cbedc98366e50a4b030bdefda115b6e7 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(void)
 {
+#ifdef CONFIG_MMP
        unsigned new_seq;
        struct timeval tv;
 
@@ -145,6 +163,9 @@ unsigned ext2fs_mmp_new_seq(void)
        } 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 3e2c0dbec9a8e2658c9ab4aae1a8abff91427123..cd32d0a1d415e539103714f16ed84c33352ac503 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,7 +45,11 @@ 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) {
                ext2fs_free_mem(&buf);
                return retval;
@@ -52,14 +58,15 @@ errcode_t ext2fs_new_dir_block(ext2_filsys fs, ext2_ino_t dir_ino,
        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);
 
                /*
@@ -72,11 +79,42 @@ errcode_t ext2fs_new_dir_block(ext2_filsys fs, ext2_ino_t dir_ino,
                        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;
 }
+
+/*
+ * Create new directory on inline data
+ */
+errcode_t ext2fs_new_dir_inline_data(ext2_filsys fs, ext2_ino_t dir_ino,
+                                    ext2_ino_t parent_ino, __u32 *iblock)
+{
+       struct ext2_dir_entry   *dir = NULL;
+       errcode_t               retval;
+       char                    *buf;
+       int                     rec_len;
+       int                     filetype = 0;
+
+       EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
+
+       iblock[0] = ext2fs_cpu_to_le32(parent_ino);
+
+       dir = (struct ext2_dir_entry *)((char *)iblock +
+                                       EXT4_INLINE_DATA_DOTDOT_SIZE);
+       dir->inode = 0;
+       rec_len = EXT4_MIN_INLINE_DATA_SIZE - EXT4_INLINE_DATA_DOTDOT_SIZE;
+       retval = ext2fs_set_rec_len(fs, rec_len, dir);
+
+       return retval;
+}
index a1a35176a823e0bc58b1593b3bf052ce4ffa0996..b4122de16264bcae2652d0b75b6e27e0181e753c 100644 (file)
@@ -215,6 +215,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);
@@ -295,6 +305,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) !=
@@ -332,6 +357,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
@@ -418,8 +445,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 8c9a6f1d22758ed6009a8ea790ddaeba1730232e..83556b1ae6c511ede6bc6890675e0920114c9d1d 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 a3d020ece6a36f51c4e9313aaca2fe3e40c15aa7..a43beb4cae814fab99d76072d7bf2b92dc4c8104 100644 (file)
@@ -19,6 +19,7 @@
 
 #include "ext2_fs.h"
 #include "ext2fs.h"
+#include "ext2fsP.h"
 
 #undef PUNCH_DEBUG
 
@@ -343,10 +344,16 @@ static errcode_t ext2fs_punch_extent(ext2_filsys fs, ext2_ino_t ino,
                                        EXT2_EXTENT_INSERT_AFTER, &newex);
                        if (retval)
                                goto errout;
-                       /* Now pointing at inserted extent; so go back */
-                       retval = ext2fs_extent_get(handle,
-                                                  EXT2_EXTENT_PREV_LEAF,
-                                                  &newex);
+                       retval = ext2fs_extent_fix_parents(handle);
+                       if (retval)
+                               goto errout;
+                       /*
+                        * Now pointing at inserted extent; so go back.
+                        *
+                        * We cannot use EXT2_EXTENT_PREV to go back; note the
+                        * subtlety in the comment for fix_parents().
+                        */
+                       retval = ext2fs_extent_goto(handle, extent.e_lblk);
                        if (retval)
                                goto errout;
                } 
@@ -396,7 +403,7 @@ static errcode_t ext2fs_punch_extent(ext2_filsys fs, ext2_ino_t ino,
                        retval = 0;
 
                        /* Jump forward to the next extent. */
-                       ext2fs_extent_goto(handle, next_lblk);
+                       (void) ext2fs_extent_goto(handle, next_lblk);
                        op = EXT2_EXTENT_CURRENT;
                }
                if (retval)
@@ -423,6 +430,30 @@ errout:
        return retval;
 }
        
+static errcode_t ext2fs_punch_inline_data(ext2_filsys fs, ext2_ino_t ino,
+                                         struct ext2_inode *inode,
+                                         blk64_t start, blk64_t end)
+{
+       errcode_t retval;
+
+       /*
+        * In libext2fs ext2fs_punch is based on block unit.  So that
+        * means that if start > 0 we don't need to do nothing.  Due
+        * to this we will remove all inline data in ext2fs_punch()
+        * now.
+        */
+       if (start > 0)
+               return 0;
+
+       memset((char *)inode->i_block, 0, EXT4_MIN_INLINE_DATA_SIZE);
+       inode->i_size = 0;
+       retval = ext2fs_write_inode(fs, ino, inode);
+       if (retval)
+               return retval;
+
+       return ext2fs_inline_data_ea_remove(fs, ino);
+}
+
 /*
  * Deallocate all logical blocks starting at start to end, inclusive.
  * If end is ~0, then this is effectively truncate.
@@ -445,7 +476,9 @@ errcode_t ext2fs_punch(ext2_filsys fs, ext2_ino_t ino,
                        return retval;
                inode = &inode_buf;
        }
-       if (inode->i_flags & EXT4_EXTENTS_FL)
+       if (inode->i_flags & EXT4_INLINE_DATA_FL)
+               return ext2fs_punch_inline_data(fs, ino, inode, start, end);
+       else if (inode->i_flags & EXT4_EXTENTS_FL)
                retval = ext2fs_punch_extent(fs, ino, inode, start, end);
        else {
                blk_t   count;
index d24ba9a3feca56c38b176d3718ffce6cdfbc5b50..ad6cfc1183ccdcb129f72d0781777065f16449ef 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,
@@ -190,7 +201,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);
@@ -206,9 +217,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)
@@ -297,6 +306,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;
@@ -319,6 +337,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 2a7b768cedb10cacd0be33f16cc0e501e29e561c..f08859b5722dfa93188a0ab2cafae6c9cb448263 100644 (file)
@@ -159,7 +159,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]);
 }
@@ -208,6 +209,7 @@ void ext2fs_swap_inode_full(ext2_filsys fs, struct ext2_inode_large *t,
 {
        unsigned i, has_data_blocks, extra_isize, attr_magic;
        int has_extents = 0;
+       int has_inline_data = 0;
        int islnk = 0;
        __u32 *eaf, *eat;
 
@@ -234,12 +236,18 @@ void ext2fs_swap_inode_full(ext2_filsys fs, struct ext2_inode_large *t,
                                           (struct ext2_inode *) t);
        if (hostorder && (f->i_flags & EXT4_EXTENTS_FL))
                has_extents = 1;
+       if (hostorder && (f->i_flags & EXT4_INLINE_DATA_FL))
+               has_inline_data = 1;
        t->i_flags = ext2fs_swab32(f->i_flags);
        if (!hostorder && (t->i_flags & EXT4_EXTENTS_FL))
                has_extents = 1;
+       if (!hostorder && (f->i_flags & EXT4_INLINE_DATA_FL))
+               has_inline_data = 1;
        t->i_dir_acl = ext2fs_swab32(f->i_dir_acl);
-       /* extent data are swapped on access, not here */
-       if (!has_extents && (!islnk || has_data_blocks)) {
+       /*
+        * Extent data and inline data are swapped on access, not here
+        */
+       if (!has_extents && !has_inline_data && (!islnk || has_data_blocks)) {
                for (i = 0; i < EXT2_N_BLOCKS; i++)
                        t->i_block[i] = ext2fs_swab32(f->i_block[i]);
        } else if (t != f) {
@@ -350,6 +358,81 @@ 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)
+{
+       return ext2fs_dirent_swab_in2(fs, buf, fs->blocksize, flags);
+}
+
+errcode_t ext2fs_dirent_swab_in2(ext2_filsys fs, char *buf,
+                                size_t size, 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 + size;
+       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)
+{
+       return ext2fs_dirent_swab_out2(fs, buf, fs->blocksize, flags);
+}
+
+errcode_t ext2fs_dirent_swab_out2(ext2_filsys fs, char *buf,
+                                 size_t size, int flags)
+{
+       errcode_t       retval;
+       char            *p, *end;
+       unsigned int    rec_len;
+       struct ext2_dir_entry *dirent;
+
+       p = buf;
+       end = buf + size;
+       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 f9cec8afe0b37b3a73f0d05ca7b51d612e77ffd9..b085bbb830dfcdf474c497570c5a6d8a00e2113e 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 d2d31cc43cc738579fcdd12b4f572eca29310a5e..8ab27ee24da9db7b60be8d3e2d50117ab9154cd9 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 895e36ef0f5d818f3a54c55cfcfc49c8b06b8bb2..db5d90ae4076d035020af61ab927417d17811bf6 100644 (file)
@@ -52,6 +52,13 @@ int ext2fs_inode_has_valid_blocks2(ext2_filsys fs, struct ext2_inode *inode)
                        return 0; /* Probably a fast symlink */
                }
        }
+
+       /*
+        * If this inode has inline data, it shouldn't have valid block
+        * entries.
+        */
+       if (inode->i_flags & EXT4_INLINE_DATA_FL)
+               return 0;
        return 1;
 }
 
index 92df2681469ee01f51c495e6621b7735b861849f..87fa08f88de7c8c37cf1e50c797abaeb065dc51b 100644 (file)
@@ -45,6 +45,7 @@ LIBDIR= quota
        $(E) "  CC $<"
        $(Q) $(CC) $(ALL_CFLAGS) -c $< -o $@
        $(Q) $(CHECK_CMD) $(ALL_CFLAGS) $<
+       $(Q) $(CPPCHECK_CMD) $(CPPFLAGS) $<
 @PROFILE_CMT@  $(Q) $(CC) $(ALL_CFLAGS) -g -pg -o profiled/$*.o -c $<
 @CHECKER_CMT@  $(Q) $(CC) $(ALL_CFLAGS) -checker -g -o checker/$*.o -c $<
 #ELF_CMT#      $(Q) $(CC) $(ALL_CFLAGS) -fPIC -o elfshared/$*.o -c $<
index 8f85bf1bd2f93ddd6e61eba94a9e40acd5830d67..0647f6c163418ba852eeb0d809d95fe28692afe8 100644 (file)
@@ -35,6 +35,7 @@ MK_CMDS=_SS_DIR_OVERRIDE=. ./mk_cmds
        $(E) "  CC $<"
        $(Q) $(CC) $(ALL_CFLAGS) -c $<
        $(Q) $(CHECK_CMD) $(ALL_CFLAGS) $<
+       $(Q) $(CPPCHECK_CMD) $(CPPFLAGS) $<
 @PROFILE_CMT@  $(Q) $(CC) $(ALL_CFLAGS) -g -pg -o profiled/$*.o -c $<
 @CHECKER_CMT@  $(Q) $(CC) $(ALL_CFLAGS) -checker -g -o checker/$*.o -c $<
 @ELF_CMT@      $(Q) $(CC) $(ALL_CFLAGS) -DSHARED_ELF_LIB -fPIC -o elfshared/$*.o -c $<
index a23e6520a6cbea98ffd743a7c2a3e5dad5731097..f22ab26b5a55a32cff55411908211b3b3a54230d 100644 (file)
@@ -63,6 +63,7 @@ BSDLIB_INSTALL_DIR = $(root_libdir)
        $(E) "  CC $<"
        $(Q) $(CC) $(ALL_CFLAGS) -c $< -o $@
        $(Q) $(CHECK_CMD) $(ALL_CFLAGS) $<
+       $(Q) $(CPPCHECK_CMD) $(CPPFLAGS) $<
 @PROFILE_CMT@  $(Q) $(CC) $(ALL_CFLAGS) -g -pg -o profiled/$*.o -c $<
 @CHECKER_CMT@  $(Q) $(CC) $(ALL_CFLAGS) -checker -g -o checker/$*.o -c $<
 @ELF_CMT@      $(Q) $(CC) $(ALL_CFLAGS) -fPIC -o elfshared/$*.o -c $<
index 8d3318beec04f42eb5ae0902dde8ad2013e1d2bb..94fac2261cb229514a8e47afe5b9688f36c38805 100644 (file)
@@ -43,7 +43,7 @@ LPROGS=               @E2INITRD_PROG@
 TUNE2FS_OBJS=  tune2fs.o util.o
 MKLPF_OBJS=    mklost+found.o
 MKE2FS_OBJS=   mke2fs.o util.o profile.o prof_err.o default_profile.o \
-                       mk_hugefiles.o
+                       mk_hugefiles.o create_inode.o
 CHATTR_OBJS=   chattr.o
 LSATTR_OBJS=   lsattr.o
 UUIDGEN_OBJS=  uuidgen.o
@@ -61,7 +61,8 @@ E2FREEFRAG_OBJS= e2freefrag.o
 PROFILED_TUNE2FS_OBJS= profiled/tune2fs.o profiled/util.o
 PROFILED_MKLPF_OBJS=   profiled/mklost+found.o
 PROFILED_MKE2FS_OBJS=  profiled/mke2fs.o profiled/util.o profiled/profile.o \
-                       profiled/prof_err.o profiled/default_profile.o
+                       profiled/prof_err.o profiled/default_profile.o \
+                       profiled/create_inode.o
 PROFILED_CHATTR_OBJS=  profiled/chattr.o
 PROFILED_LSATTR_OBJS=  profiled/lsattr.o
 PROFILED_UUIDGEN_OBJS= profiled/uuidgen.o
@@ -83,7 +84,7 @@ SRCS= $(srcdir)/tune2fs.c $(srcdir)/mklost+found.c $(srcdir)/mke2fs.c $(srcdir)/
                $(srcdir)/uuidgen.c $(srcdir)/blkid.c $(srcdir)/logsave.c \
                $(srcdir)/filefrag.c $(srcdir)/base_device.c \
                $(srcdir)/ismounted.c $(srcdir)/../e2fsck/profile.c \
-               $(srcdir)/e2undo.c $(srcdir)/e2freefrag.c
+               $(srcdir)/e2undo.c $(srcdir)/e2freefrag.c $(srcdir)/create_inode.c
 
 LIBS= $(LIBEXT2FS) $(LIBCOM_ERR)
 DEPLIBS= $(LIBEXT2FS) $(DEPLIBCOM_ERR)
@@ -102,6 +103,7 @@ COMPILE_ET=$(top_builddir)/lib/et/compile_et --build-tree
        $(E) "  CC $<"
        $(Q) $(CC) -c $(ALL_CFLAGS) $< -o $@
        $(Q) $(CHECK_CMD) $(ALL_CFLAGS) $<
+       $(Q) $(CPPCHECK_CMD) $(CPPFLAGS) $<
 @PROFILE_CMT@  $(Q) $(CC) $(ALL_CFLAGS) -g -pg -o profiled/$*.o -c $<
 
 all:: profiled $(SPROGS) $(UPROGS) $(USPROGS) $(SMANPAGES) $(UMANPAGES) \
@@ -643,11 +645,12 @@ mke2fs.o: $(srcdir)/mke2fs.c $(top_builddir)/lib/config.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 \
- $(top_srcdir)/lib/e2p/e2p.h $(top_srcdir)/lib/ext2fs/ext2fs.h \
  $(srcdir)/util.h profile.h prof_err.h $(top_srcdir)/version.h \
- $(srcdir)/nls-enable.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)/mke2fs.h
+ $(top_srcdir)/lib/ext2fs/ext2fs.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)/mke2fs.h $(srcdir)/create_inode.h $(top_srcdir)/lib/e2p/e2p.h \
+ $(srcdir)/nls-enable.h
 mk_hugefiles.o: $(srcdir)/mk_hugefiles.c $(top_builddir)/lib/config.h \
  $(top_builddir)/lib/dirpaths.h $(top_srcdir)/lib/ext2fs/ext2_fs.h \
  $(top_builddir)/lib/ext2fs/ext2_types.h $(top_srcdir)/lib/ext2fs/ext2fsP.h \
@@ -735,3 +738,10 @@ e2freefrag.o: $(srcdir)/e2freefrag.c $(top_builddir)/lib/config.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)/e2freefrag.h
+create_inode.o: $(srcdir)/create_inode.c $(srcdir)/create_inode.h \
+ $(top_srcdir)/lib/et/com_err.h $(top_srcdir)/lib/e2p/e2p.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/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)/nls-enable.h
diff --git a/misc/create_inode.c b/misc/create_inode.c
new file mode 100644 (file)
index 0000000..0b1e74e
--- /dev/null
@@ -0,0 +1,654 @@
+#include <time.h>
+#include <unistd.h>
+
+#include "create_inode.h"
+
+#if __STDC_VERSION__ < 199901L
+# if __GNUC__ >= 2
+#  define __func__ __FUNCTION__
+# else
+#  define __func__ "<unknown>"
+# endif
+#endif
+
+/* 64KiB is the minimium blksize to best minimize system call overhead. */
+#ifndef IO_BUFSIZE
+#define IO_BUFSIZE 64*1024
+#endif
+
+/* Block size for `st_blocks' */
+#ifndef S_BLKSIZE
+#define S_BLKSIZE 512
+#endif
+
+/* Link an inode number to a directory */
+static errcode_t add_link(ext2_filsys fs, ext2_ino_t parent_ino,
+                         ext2_ino_t ino, const char *name)
+{
+       struct ext2_inode       inode;
+       errcode_t               retval;
+
+       retval = ext2fs_read_inode(fs, ino, &inode);
+        if (retval) {
+               com_err(__func__, retval, "while reading inode %u", ino);
+               return retval;
+       }
+
+       retval = ext2fs_link(fs, parent_ino, name, ino, inode.i_flags);
+       if (retval == EXT2_ET_DIR_NO_SPACE) {
+               retval = ext2fs_expand_dir(fs, parent_ino);
+               if (retval) {
+                       com_err(__func__, retval, "while expanding directory");
+                       return retval;
+               }
+               retval = ext2fs_link(fs, parent_ino, name, ino, inode.i_flags);
+       }
+       if (retval) {
+               com_err(__func__, retval, "while linking %s", name);
+               return retval;
+       }
+
+       inode.i_links_count++;
+
+       retval = ext2fs_write_inode(fs, ino, &inode);
+       if (retval)
+               com_err(__func__, retval, "while writing inode %u", ino);
+
+       return retval;
+}
+
+/* Fill the uid, gid, mode and time for the inode */
+static void fill_inode(struct ext2_inode *inode, struct stat *st)
+{
+       if (st != NULL) {
+               inode->i_uid = st->st_uid;
+               inode->i_gid = st->st_gid;
+               inode->i_mode |= st->st_mode;
+               inode->i_atime = st->st_atime;
+               inode->i_mtime = st->st_mtime;
+               inode->i_ctime = st->st_ctime;
+       }
+}
+
+/* Set the uid, gid, mode and time for the inode */
+static errcode_t set_inode_extra(ext2_filsys fs, ext2_ino_t cwd,
+                                ext2_ino_t ino, struct stat *st)
+{
+       errcode_t               retval;
+       struct ext2_inode       inode;
+
+       retval = ext2fs_read_inode(fs, ino, &inode);
+        if (retval) {
+               com_err(__func__, retval, "while reading inode %u", ino);
+               return retval;
+       }
+
+       fill_inode(&inode, st);
+
+       retval = ext2fs_write_inode(fs, ino, &inode);
+       if (retval)
+               com_err(__func__, retval, "while writing inode %u", ino);
+       return retval;
+}
+
+/* Make a special files (block and character devices), fifo's, and sockets  */
+errcode_t do_mknod_internal(ext2_filsys fs, ext2_ino_t cwd, const char *name,
+                           struct stat *st)
+{
+       ext2_ino_t              ino;
+       errcode_t               retval;
+       struct ext2_inode       inode;
+       unsigned long           major, minor, mode;
+       int                     filetype;
+
+       switch(st->st_mode & S_IFMT) {
+       case S_IFCHR:
+               mode = LINUX_S_IFCHR;
+               filetype = EXT2_FT_CHRDEV;
+               break;
+       case S_IFBLK:
+               mode = LINUX_S_IFBLK;
+               filetype =  EXT2_FT_BLKDEV;
+               break;
+       case S_IFIFO:
+               mode = LINUX_S_IFIFO;
+               filetype = EXT2_FT_FIFO;
+               break;
+       case S_IFSOCK:
+               mode = LINUX_S_IFSOCK;
+               filetype = EXT2_FT_SOCK;
+       default:
+               abort();
+               /* NOTREACHED */
+       }
+
+       if (!(fs->flags & EXT2_FLAG_RW)) {
+               com_err(__func__, 0, "Filesystem opened read/only");
+               return EROFS;
+       }
+       retval = ext2fs_new_inode(fs, cwd, 010755, 0, &ino);
+       if (retval) {
+               com_err(__func__, retval, 0);
+               return retval;
+       }
+
+#ifdef DEBUGFS
+       printf("Allocated inode: %u\n", ino);
+#endif
+       retval = ext2fs_link(fs, cwd, name, ino, filetype);
+       if (retval == EXT2_ET_DIR_NO_SPACE) {
+               retval = ext2fs_expand_dir(fs, cwd);
+               if (retval) {
+                       com_err(__func__, retval, "while expanding directory");
+                       return retval;
+               }
+               retval = ext2fs_link(fs, cwd, name, ino, filetype);
+       }
+       if (retval) {
+               com_err(name, retval, 0);
+               return -1;
+       }
+       if (ext2fs_test_inode_bitmap2(fs->inode_map, ino))
+               com_err(__func__, 0, "Warning: inode already set");
+       ext2fs_inode_alloc_stats2(fs, ino, +1, 0);
+       memset(&inode, 0, sizeof(inode));
+       inode.i_mode = mode;
+       inode.i_atime = inode.i_ctime = inode.i_mtime =
+               fs->now ? fs->now : time(0);
+
+       major = major(st->st_rdev);
+       minor = minor(st->st_rdev);
+
+       if ((major < 256) && (minor < 256)) {
+               inode.i_block[0] = major * 256 + minor;
+               inode.i_block[1] = 0;
+       } else {
+               inode.i_block[0] = 0;
+               inode.i_block[1] = (minor & 0xff) | (major << 8) |
+                                  ((minor & ~0xff) << 12);
+       }
+       inode.i_links_count = 1;
+
+       retval = ext2fs_write_new_inode(fs, ino, &inode);
+       if (retval)
+               com_err(__func__, retval, "while creating inode %u", ino);
+
+       return retval;
+}
+
+/* Make a symlink name -> target */
+errcode_t do_symlink_internal(ext2_filsys fs, ext2_ino_t cwd, const char *name,
+                             char *target, ext2_ino_t root)
+{
+       char                    *cp;
+       ext2_ino_t              parent_ino;
+       errcode_t               retval;
+       struct ext2_inode       inode;
+       struct stat             st;
+
+       cp = strrchr(name, '/');
+       if (cp) {
+               *cp = 0;
+               retval = ext2fs_namei(fs, root, cwd, name, &parent_ino);
+               if (retval) {
+                       com_err(name, retval, 0);
+                       return retval;
+               }
+               name = cp+1;
+       } else
+               parent_ino = cwd;
+
+try_again:
+       retval = ext2fs_symlink(fs, parent_ino, 0, name, target);
+       if (retval == EXT2_ET_DIR_NO_SPACE) {
+               retval = ext2fs_expand_dir(fs, parent_ino);
+               if (retval) {
+                       com_err("do_symlink_internal", retval,
+                               "while expanding directory");
+                       return retval;
+               }
+               goto try_again;
+       }
+       if (retval)
+               com_err("ext2fs_symlink", retval, 0);
+       return retval;
+}
+
+/* Make a directory in the fs */
+errcode_t do_mkdir_internal(ext2_filsys fs, ext2_ino_t cwd, const char *name,
+                           struct stat *st, ext2_ino_t root)
+{
+       char                    *cp;
+       ext2_ino_t              parent_ino, ino;
+       errcode_t               retval;
+       struct ext2_inode       inode;
+
+
+       cp = strrchr(name, '/');
+       if (cp) {
+               *cp = 0;
+               retval = ext2fs_namei(fs, root, cwd, name, &parent_ino);
+               if (retval) {
+                       com_err(name, retval, 0);
+                       return retval;
+               }
+               name = cp+1;
+       } else
+               parent_ino = cwd;
+
+try_again:
+       retval = ext2fs_mkdir(fs, parent_ino, 0, name);
+       if (retval == EXT2_ET_DIR_NO_SPACE) {
+               retval = ext2fs_expand_dir(fs, parent_ino);
+               if (retval) {
+                       com_err(__func__, retval, "while expanding directory");
+                       return retval;
+               }
+               goto try_again;
+       }
+       if (retval)
+               com_err("ext2fs_mkdir", retval, 0);
+       return retval;
+}
+
+static errcode_t copy_file(ext2_filsys fs, int fd, ext2_ino_t newfile,
+                          int bufsize, int make_holes)
+{
+       ext2_file_t     e2_file;
+       errcode_t       retval;
+       int             got;
+       unsigned int    written;
+       char            *buf;
+       char            *ptr;
+       char            *zero_buf;
+       int             cmp;
+
+       retval = ext2fs_file_open(fs, newfile,
+                                 EXT2_FILE_WRITE, &e2_file);
+       if (retval)
+               return retval;
+
+       retval = ext2fs_get_mem(bufsize, &buf);
+       if (retval) {
+               com_err("copy_file", retval, "can't allocate buffer\n");
+               return retval;
+       }
+
+       /* This is used for checking whether the whole block is zero */
+       retval = ext2fs_get_memzero(bufsize, &zero_buf);
+       if (retval) {
+               com_err("copy_file", retval, "can't allocate buffer\n");
+               ext2fs_free_mem(&buf);
+               return retval;
+       }
+
+       while (1) {
+               got = read(fd, buf, bufsize);
+               if (got == 0)
+                       break;
+               if (got < 0) {
+                       retval = errno;
+                       goto fail;
+               }
+               ptr = buf;
+
+               /* Sparse copy */
+               if (make_holes) {
+                       /* Check whether all is zero */
+                       cmp = memcmp(ptr, zero_buf, got);
+                       if (cmp == 0) {
+                                /* The whole block is zero, make a hole */
+                               retval = ext2fs_file_lseek(e2_file, got,
+                                                          EXT2_SEEK_CUR,
+                                                          NULL);
+                               if (retval)
+                                       goto fail;
+                               got = 0;
+                       }
+               }
+
+               /* Normal copy */
+               while (got > 0) {
+                       retval = ext2fs_file_write(e2_file, ptr,
+                                                  got, &written);
+                       if (retval)
+                               goto fail;
+
+                       got -= written;
+                       ptr += written;
+               }
+       }
+       ext2fs_free_mem(&buf);
+       ext2fs_free_mem(&zero_buf);
+       retval = ext2fs_file_close(e2_file);
+       return retval;
+
+fail:
+       ext2fs_free_mem(&buf);
+       ext2fs_free_mem(&zero_buf);
+       (void) ext2fs_file_close(e2_file);
+       return retval;
+}
+
+static int is_hardlink(struct hdlinks_s *hdlinks, dev_t dev, ino_t ino)
+{
+       int i;
+
+       for (i = 0; i < hdlinks->count; i++) {
+               if (hdlinks->hdl[i].src_dev == dev &&
+                   hdlinks->hdl[i].src_ino == ino)
+                       return i;
+       }
+       return -1;
+}
+
+/* Copy the native file to the fs */
+errcode_t do_write_internal(ext2_filsys fs, ext2_ino_t cwd, const char *src,
+                           const char *dest, ext2_ino_t root)
+{
+       int             fd;
+       struct stat     statbuf;
+       ext2_ino_t      newfile;
+       errcode_t       retval;
+       struct ext2_inode inode;
+       int             bufsize = IO_BUFSIZE;
+       int             make_holes = 0;
+
+       fd = open(src, O_RDONLY);
+       if (fd < 0) {
+               com_err(src, errno, 0);
+               return errno;
+       }
+       if (fstat(fd, &statbuf) < 0) {
+               com_err(src, errno, 0);
+               close(fd);
+               return errno;
+       }
+
+       retval = ext2fs_namei(fs, root, cwd, dest, &newfile);
+       if (retval == 0) {
+               close(fd);
+               return EXT2_ET_FILE_EXISTS;
+       }
+
+       retval = ext2fs_new_inode(fs, cwd, 010755, 0, &newfile);
+       if (retval) {
+               com_err(__func__, retval, 0);
+               close(fd);
+               return retval;
+       }
+#ifdef DEBUGFS
+       printf("Allocated inode: %u\n", newfile);
+#endif
+       retval = ext2fs_link(fs, cwd, dest, newfile,
+                               EXT2_FT_REG_FILE);
+       if (retval == EXT2_ET_DIR_NO_SPACE) {
+               retval = ext2fs_expand_dir(fs, cwd);
+               if (retval) {
+                       com_err(__func__, retval, "while expanding directory");
+                       close(fd);
+                       return retval;
+               }
+               retval = ext2fs_link(fs, cwd, dest, newfile,
+                                       EXT2_FT_REG_FILE);
+       }
+       if (retval) {
+               com_err(dest, retval, 0);
+               close(fd);
+               return errno;
+       }
+       if (ext2fs_test_inode_bitmap2(fs->inode_map, newfile))
+               com_err(__func__, 0, "Warning: inode already set");
+       ext2fs_inode_alloc_stats2(fs, newfile, +1, 0);
+       memset(&inode, 0, sizeof(inode));
+       inode.i_mode = (statbuf.st_mode & ~LINUX_S_IFMT) | LINUX_S_IFREG;
+       inode.i_atime = inode.i_ctime = inode.i_mtime =
+               fs->now ? fs->now : time(0);
+       inode.i_links_count = 1;
+       inode.i_size = statbuf.st_size;
+       if (EXT2_HAS_INCOMPAT_FEATURE(fs->super,
+                                     EXT4_FEATURE_INCOMPAT_INLINE_DATA)) {
+               inode.i_flags |= EXT4_INLINE_DATA_FL;
+       } else if (fs->super->s_feature_incompat &
+                  EXT3_FEATURE_INCOMPAT_EXTENTS) {
+               int i;
+               struct ext3_extent_header *eh;
+
+               eh = (struct ext3_extent_header *) &inode.i_block[0];
+               eh->eh_depth = 0;
+               eh->eh_entries = 0;
+               eh->eh_magic = ext2fs_cpu_to_le16(EXT3_EXT_MAGIC);
+               i = (sizeof(inode.i_block) - sizeof(*eh)) /
+                       sizeof(struct ext3_extent);
+               eh->eh_max = ext2fs_cpu_to_le16(i);
+               inode.i_flags |= EXT4_EXTENTS_FL;
+       }
+
+       retval = ext2fs_write_new_inode(fs, newfile, &inode);
+       if (retval) {
+               com_err(__func__, retval, "while creating inode %u", newfile);
+               close(fd);
+               return retval;
+       }
+       if (inode.i_flags & EXT4_INLINE_DATA_FL) {
+               retval = ext2fs_inline_data_init(fs, newfile);
+               if (retval) {
+                       com_err("copy_file", retval, 0);
+                       close(fd);
+                       return retval;
+               }
+       }
+       if (LINUX_S_ISREG(inode.i_mode)) {
+               if (statbuf.st_blocks < statbuf.st_size / S_BLKSIZE) {
+                       make_holes = 1;
+                       /*
+                        * Use I/O blocksize as buffer size when
+                        * copying sparse files.
+                        */
+                       bufsize = statbuf.st_blksize;
+               }
+               retval = copy_file(fs, fd, newfile, bufsize, make_holes);
+               if (retval)
+                       com_err("copy_file", retval, 0);
+       }
+       close(fd);
+
+       return retval;
+}
+
+/* Copy files from source_dir to fs */
+static errcode_t __populate_fs(ext2_filsys fs, ext2_ino_t parent_ino,
+                              const char *source_dir, ext2_ino_t root,
+                              struct hdlinks_s *hdlinks)
+{
+       const char      *name;
+       DIR             *dh;
+       struct dirent   *dent;
+       struct stat     st;
+       char            ln_target[PATH_MAX];
+       unsigned int    save_inode;
+       ext2_ino_t      ino;
+       errcode_t       retval = 0;
+       int             read_cnt;
+       int             hdlink;
+
+       if (chdir(source_dir) < 0) {
+               com_err(__func__, errno,
+                       _("while changing working directory to \"%s\""),
+                       source_dir);
+               return errno;
+       }
+
+       if (!(dh = opendir("."))) {
+               com_err(__func__, errno,
+                       _("while opening directory \"%s\""), source_dir);
+               return errno;
+       }
+
+       while ((dent = readdir(dh))) {
+               if ((!strcmp(dent->d_name, ".")) ||
+                   (!strcmp(dent->d_name, "..")))
+                       continue;
+               if (lstat(dent->d_name, &st)) {
+                       com_err(__func__, errno, _("while lstat \"%s\""),
+                               dent->d_name);
+                       goto out;
+               }
+               name = dent->d_name;
+
+               /* Check for hardlinks */
+               save_inode = 0;
+               if (!S_ISDIR(st.st_mode) && !S_ISLNK(st.st_mode) &&
+                   st.st_nlink > 1) {
+                       hdlink = is_hardlink(hdlinks, st.st_dev, st.st_ino);
+                       if (hdlink >= 0) {
+                               retval = add_link(fs, parent_ino,
+                                                 hdlinks->hdl[hdlink].dst_ino,
+                                                 name);
+                               if (retval) {
+                                       com_err(__func__, retval,
+                                               "while linking %s", name);
+                                       goto out;
+                               }
+                               continue;
+                       } else
+                               save_inode = 1;
+               }
+
+               switch(st.st_mode & S_IFMT) {
+               case S_IFCHR:
+               case S_IFBLK:
+               case S_IFIFO:
+               case S_IFSOCK:
+                       retval = do_mknod_internal(fs, parent_ino, name, &st);
+                       if (retval) {
+                               com_err(__func__, retval,
+                                       _("while creating special file "
+                                         "\"%s\""), name);
+                               goto out;
+                       }
+                       break;
+               case S_IFLNK:
+                       read_cnt = readlink(name, ln_target,
+                                           sizeof(ln_target) - 1);
+                       if (read_cnt == -1) {
+                               com_err(__func__, errno,
+                                       _("while trying to readlink \"%s\""),
+                                       name);
+                               return errno;
+                       }
+                       ln_target[read_cnt] = '\0';
+                       retval = do_symlink_internal(fs, parent_ino, name,
+                                                    ln_target, root);
+                       if (retval) {
+                               com_err(__func__, retval,
+                                       _("while writing symlink\"%s\""),
+                                       name);
+                               goto out;
+                       }
+                       break;
+               case S_IFREG:
+                       retval = do_write_internal(fs, parent_ino, name, name,
+                                                  root);
+                       if (retval) {
+                               com_err(__func__, retval,
+                                       _("while writing file \"%s\""), name);
+                               goto out;
+                       }
+                       break;
+               case S_IFDIR:
+                       retval = do_mkdir_internal(fs, parent_ino, name, &st,
+                                                  root);
+                       if (retval) {
+                               com_err(__func__, retval,
+                                       _("while making dir \"%s\""), name);
+                               goto out;
+                       }
+                       retval = ext2fs_namei(fs, root, parent_ino,
+                                             name, &ino);
+                       if (retval) {
+                               com_err(name, retval, 0);
+                                       goto out;
+                       }
+                       /* Populate the dir recursively*/
+                       retval = __populate_fs(fs, ino, name, root, hdlinks);
+                       if (retval) {
+                               com_err(__func__, retval,
+                                       _("while adding dir \"%s\""), name);
+                               goto out;
+                       }
+                       if (chdir("..")) {
+                               com_err(__func__, errno, _("during cd .."));
+                               retval = errno;
+                               goto out;
+                       }
+                       break;
+               default:
+                       com_err(__func__, 0,
+                               _("ignoring entry \"%s\""), name);
+               }
+
+               retval =  ext2fs_namei(fs, root, parent_ino, name, &ino);
+               if (retval) {
+                       com_err(name, retval, 0);
+                       goto out;
+               }
+
+               retval = set_inode_extra(fs, parent_ino, ino, &st);
+               if (retval) {
+                       com_err(__func__, retval,
+                               _("while setting inode for \"%s\""), name);
+                       goto out;
+               }
+
+               /* Save the hardlink ino */
+               if (save_inode) {
+                       /*
+                        * Check whether need more memory, and we don't need
+                        * free() since the lifespan will be over after the fs
+                        * populated.
+                        */
+                       if (hdlinks->count == hdlinks->size) {
+                               void *p = realloc(hdlinks->hdl,
+                                               (hdlinks->size + HDLINK_CNT) *
+                                               sizeof(struct hdlink_s));
+                               if (p == NULL) {
+                                       com_err(name, errno,
+                                               _("Not enough memory"));
+                                       retval = EXT2_ET_NO_MEMORY;
+                                       goto out;
+                               }
+                               hdlinks->hdl = p;
+                               hdlinks->size += HDLINK_CNT;
+                       }
+                       hdlinks->hdl[hdlinks->count].src_dev = st.st_dev;
+                       hdlinks->hdl[hdlinks->count].src_ino = st.st_ino;
+                       hdlinks->hdl[hdlinks->count].dst_ino = ino;
+                       hdlinks->count++;
+               }
+       }
+
+out:
+       closedir(dh);
+       return retval;
+}
+
+errcode_t populate_fs(ext2_filsys fs, ext2_ino_t parent_ino,
+                     const char *source_dir, ext2_ino_t root)
+{
+       struct hdlinks_s hdlinks;
+       errcode_t retval;
+
+       hdlinks.count = 0;
+       hdlinks.size = HDLINK_CNT;
+       hdlinks.hdl = realloc(NULL, hdlinks.size * sizeof(struct hdlink_s));
+       if (hdlinks.hdl == NULL) {
+               com_err(__func__, errno, "Not enough memory");
+               return errno;
+       }
+
+       retval = __populate_fs(fs, parent_ino, source_dir, root, &hdlinks);
+
+       free(hdlinks.hdl);
+       return retval;
+}
diff --git a/misc/create_inode.h b/misc/create_inode.h
new file mode 100644 (file)
index 0000000..067bf96
--- /dev/null
@@ -0,0 +1,43 @@
+#ifndef _CREATE_INODE_H
+#define _CREATE_INODE_H
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include "et/com_err.h"
+#include "e2p/e2p.h"
+#include "ext2fs/ext2fs.h"
+#include "nls-enable.h"
+
+struct hdlink_s
+{
+       dev_t src_dev;
+       ino_t src_ino;
+       ext2_ino_t dst_ino;
+};
+
+struct hdlinks_s
+{
+       int count;
+       int size;
+       struct hdlink_s *hdl;
+};
+
+#define HDLINK_CNT     (4)
+
+/* For populating the filesystem */
+extern errcode_t populate_fs(ext2_filsys fs, ext2_ino_t parent_ino,
+                            const char *source_dir, ext2_ino_t root);
+extern errcode_t do_mknod_internal(ext2_filsys fs, ext2_ino_t cwd,
+                                  const char *name, struct stat *st);
+extern errcode_t do_symlink_internal(ext2_filsys fs, ext2_ino_t cwd,
+                                    const char *name, char *target,
+                                    ext2_ino_t root);
+extern errcode_t do_mkdir_internal(ext2_filsys fs, ext2_ino_t cwd,
+                                  const char *name, struct stat *st,
+                                  ext2_ino_t root);
+extern errcode_t do_write_internal(ext2_filsys fs, ext2_ino_t cwd,
+                                  const char *src, const char *dest,
+                                  ext2_ino_t root);
+
+#endif /* _CREATE_INODE_H */
index d4bde8e5104bcea704ad015a52cc9ac59d2ac027..ae54f8a9e6dd8753c249aa0f7bd5d3df385046aa 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",
@@ -198,7 +198,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);
 
@@ -236,10 +236,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) +
@@ -326,6 +334,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;
@@ -394,6 +412,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));
@@ -424,6 +451,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 338d239c78359b3189d70872a2506b62b541a881..b0ce71f6bd9990fcb8c0e84273d71c8f10d11a83 100644 (file)
@@ -419,9 +419,7 @@ static void mark_table_blocks(ext2_filsys fs)
                    ext2fs_inode_table_loc(fs, i)) {
                        unsigned int end = (unsigned) fs->inode_blocks_per_group;
                        /* skip unused blocks */
-                       if (!output_is_blk &&
-                           EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
-                                                      EXT4_FEATURE_RO_COMPAT_GDT_CSUM))
+                       if (!output_is_blk && ext2fs_has_group_desc_csum(fs))
                                end -= (ext2fs_bg_itable_unused(fs, i) /
                                        EXT2_INODES_PER_BLOCK(fs->super));
                        for (j = 0, b = ext2fs_inode_table_loc(fs, i);
index 134c19f9149b85f3cd29c2705199e7f0ccc0bc93..f08210e21f5a4971b91ca64d0e3d0978a5288ba9 100644 (file)
@@ -149,6 +149,9 @@ option to
 or
 .BR tune2fs(8).
 .TP
+.B inline_data
+Allow data to be stored in the inode and extended attribute area
+.TP
 .B large_file
 .br
 This feature flag is set automatically by modern kernels when a file
index 9c38e2038f0cc76945ef820e147e725296ce7e96..bf17eaefd27644b73db274dc3889c2527d039eb9 100644 (file)
@@ -52,6 +52,10 @@ mke2fs \- create an ext2/ext3/ext4 filesystem
 .I number-of-inodes
 ]
 [
+.B \-d
+.I root-directory
+]
+[
 .B \-n
 ]
 [
@@ -529,6 +533,9 @@ the
 ratio).  This allows the user to specify the number
 of desired inodes directly.
 .TP
+.BI \-d " root-directory"
+Add the files from the root-directory to the filesystem.
+.TP
 .BI \-o " creator-os"
 Overrides the default value of the "creator operating system" field of the
 filesystem.  The creator field is set by default to the name of the OS the
index eb9846a758c29e6a893b1ab202043d14c535c850..522df1baa6edf9241522d0e2838d6f40362f565d 100644 (file)
@@ -22,7 +22,6 @@
 #include <stdio.h>
 #include <string.h>
 #include <strings.h>
-#include <fcntl.h>
 #include <ctype.h>
 #include <time.h>
 #ifdef __linux__
@@ -45,25 +44,20 @@ extern int optind;
 #include <errno.h>
 #endif
 #include <sys/ioctl.h>
-#include <sys/types.h>
-#include <sys/stat.h>
 #include <libgen.h>
 #include <limits.h>
 #include <blkid/blkid.h>
 
 #include "ext2fs/ext2_fs.h"
 #include "ext2fs/ext2fsP.h"
-#include "et/com_err.h"
 #include "uuid/uuid.h"
-#include "e2p/e2p.h"
-#include "ext2fs/ext2fs.h"
 #include "util.h"
 #include "profile.h"
 #include "prof_err.h"
 #include "../version.h"
-#include "nls-enable.h"
 #include "quota/quotaio.h"
 #include "mke2fs.h"
+#include "create_inode.h"
 
 #define STRIDE_LENGTH 8
 
@@ -113,6 +107,7 @@ static char *mount_dir;
 char *journal_device;
 static int sync_kludge;        /* Set using the MKE2FS_SYNC env. option */
 char **fs_types;
+const char *root_dir;  /* Copy files from the specified directory */
 
 static profile_t       profile;
 
@@ -123,7 +118,8 @@ static void usage(void)
        fprintf(stderr, _("Usage: %s [-c|-l filename] [-b block-size] "
        "[-C cluster-size]\n\t[-i bytes-per-inode] [-I inode-size] "
        "[-J journal-options]\n"
-       "\t[-G flex-group-size] [-N number-of-inodes]\n"
+       "\t[-G flex-group-size] [-N number-of-inodes] "
+       "[-d root-directory]\n"
        "\t[-m reserved-blocks-percentage] [-o creator-os]\n"
        "\t[-g blocks-per-group] [-L volume-label] "
        "[-M last-mounted-directory]\n\t[-O feature[,...]] "
@@ -337,6 +333,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 errcode_t packed_allocate_tables(ext2_filsys fs)
 {
        errcode_t       retval;
@@ -417,6 +434,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)
@@ -704,6 +727,23 @@ skip_details:
        printf("\n\n");
 }
 
+/*
+ * 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.
@@ -1031,7 +1071,8 @@ static __u32 ok_features[3] = {
                EXT2_FEATURE_INCOMPAT_META_BG|
                EXT4_FEATURE_INCOMPAT_FLEX_BG|
                EXT4_FEATURE_INCOMPAT_MMP |
-               EXT4_FEATURE_INCOMPAT_64BIT,
+               EXT4_FEATURE_INCOMPAT_64BIT|
+               EXT4_FEATURE_INCOMPAT_INLINE_DATA,
        /* R/O compat */
        EXT2_FEATURE_RO_COMPAT_LARGE_FILE|
                EXT4_FEATURE_RO_COMPAT_HUGE_FILE|
@@ -1043,7 +1084,7 @@ static __u32 ok_features[3] = {
 #ifdef CONFIG_QUOTA
                EXT4_FEATURE_RO_COMPAT_QUOTA|
 #endif
-               0
+               EXT4_FEATURE_RO_COMPAT_METADATA_CSUM
 };
 
 
@@ -1172,15 +1213,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)
@@ -1498,7 +1535,7 @@ profile_error:
        }
 
        while ((c = getopt (argc, argv,
-                   "b:cg:i:jl:m:no:qr:s:t:vC:DE:FG:I:J:KL:M:N:O:R:ST:U:V")) != EOF) {
+                   "b:cg:i:jl:m:no:qr:s:t:d:vC:DE:FG:I:J:KL:M:N:O:R:ST:U:V")) != EOF) {
                switch (c) {
                case 'b':
                        blocksize = parse_num_blocks2(optarg, -1);
@@ -1686,6 +1723,9 @@ profile_error:
                case 'U':
                        fs_uuid = optarg;
                        break;
+               case 'd':
+                       root_dir = optarg;
+                       break;
                case 'v':
                        verbose = 1;
                        break;
@@ -1869,10 +1909,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);
+               }
+       }
 
        /* Get the hardware sector sizes, if available */
        retval = ext2fs_get_device_sectsize(device_name, &lsector_size);
@@ -2138,6 +2208,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)) {
@@ -2163,7 +2240,8 @@ profile_error:
                                  "See https://ext4.wiki.kernel.org/"
                                  "index.php/Bigalloc for more information\n\n"));
 
-       /* Since sparse_super is the default, we would only have a problem
+       /*
+        * Since sparse_super is the default, we would only have a problem
         * here if it was explicitly disabled.
         */
        if ((fs_param.s_feature_compat & EXT2_FEATURE_COMPAT_RESIZE_INODE) &&
@@ -2222,6 +2300,19 @@ profile_error:
                fs_param.s_inode_size = inode_size;
        }
 
+       /*
+        * If inode size is 128 and inline data is enabled, we need
+        * to notify users that inline data will never be useful.
+        */
+       if ((fs_param.s_feature_incompat &
+            EXT4_FEATURE_INCOMPAT_INLINE_DATA) &&
+           fs_param.s_inode_size == EXT2_GOOD_OLD_INODE_SIZE) {
+               com_err(program_name, 0,
+                       _("inode size is %d, inline data is useless"),
+                       fs_param.s_inode_size);
+               exit(1);
+       }
+
        /* Make sure number of inodes specified will fit in 32 bits */
        if (num_inodes == 0) {
                unsigned long long n;
@@ -2291,7 +2382,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;
@@ -2561,6 +2653,26 @@ int main (int argc, char *argv[])
                        _("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) ||
@@ -2598,6 +2710,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;
 
@@ -2618,6 +2731,7 @@ int main (int argc, char *argv[])
                }
        } else
                uuid_generate(fs->super->s_uuid);
+       ext2fs_init_csum_seed(fs);
 
        /*
         * Initialize the directory index variables
@@ -2694,6 +2808,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);
 
@@ -2744,8 +2862,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);
                }
@@ -2883,6 +3000,20 @@ no_journal:
        retval = mk_hugefiles(fs);
        if (retval)
                com_err(program_name, retval, "while creating huge files");
+       /* Copy files from the specified directory */
+       if (root_dir) {
+               if (!quiet)
+                       printf("%s", _("Copying files into the device: "));
+
+               retval = populate_fs(fs, EXT2_ROOT_INO, root_dir,
+                                    EXT2_ROOT_INO);
+               if (retval) {
+                       com_err(program_name, retval, "%s",
+                               _("\nError while populating file system\n"));
+                       exit(1);
+               } else if (!quiet)
+                       printf("%s", _("done\n"));
+       }
 
        if (!quiet)
                printf("%s", _("Writing superblocks and "
index 0871f7778734d7e4ed452486c20697c606f77de3..4c5dba72d35e6ab9221c713f46615056b5bac0bf 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,inline_data,64bit,dir_nlink,extra_isize
                inode_size = 256
                options = test_fs=1
        }
index 9ba32a1c1a381677798af098bac5352dc3816c79..f2fe916d3e81139b2a91acc4f9aa085ceb1489c0 100644 (file)
@@ -95,6 +95,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;
@@ -110,6 +111,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);
@@ -149,10 +152,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] = {
@@ -169,10 +173,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
 };
 
 /*
@@ -373,6 +378,18 @@ static int check_fsck_needed(ext2_filsys fs)
        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;
@@ -385,15 +402,477 @@ static void request_fsck_afterwards(ext2_filsys fs)
                printf("%s", _("(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) &&
+                   ext2fs_inode_has_valid_blocks2(fs, inode)) {
+                       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)
+{
+       errcode_t retval;
+       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);
+       retval = ext2fs_read_bitmaps(fs);
+       if (retval) {
+               com_err("rewrite_metadata_checksums", retval,
+                       "while reading bitmaps");
+               exit(1);
+       }
+       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;
+       retval = ext2fs_read_bitmaps(fs);
+       if (retval) {
+               com_err("disable_uninit_bg", retval,
+                       "while reading bitmaps");
+               return;
+       }
+       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;
 
@@ -573,35 +1052,67 @@ 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)) {
                /*
@@ -2181,8 +2692,7 @@ retry_open:
                int set_csum = 0;
                dgrp_t i;
 
-               if (sb->s_feature_ro_compat &
-                   EXT4_FEATURE_RO_COMPAT_GDT_CSUM) {
+               if (ext2fs_has_group_desc_csum(fs)) {
                        /*
                         * Changing the UUID requires rewriting all metadata,
                         * which can race with a mounted fs.  Don't allow that.
@@ -2220,13 +2730,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 f7b80ef719dba140f6f7c80245b9be40be1ddfbc..201e2683beab0973a479f8e98488527a8f8800af 100644 (file)
@@ -39,6 +39,7 @@ DEPSTATIC_LIBS= $(STATIC_LIBE2P) $(STATIC_LIBEXT2FS) $(DEPSTATIC_LIBCOM_ERR)
        $(E) "  CC $<"
        $(Q) $(CC) -c $(ALL_CFLAGS) $< -o $@
        $(Q) $(CHECK_CMD) $(ALL_CFLAGS) $<
+       $(Q) $(CPPCHECK_CMD) $(CPPFLAGS) $<
 
 all:: $(PROGS) $(TEST_PROGS) $(MANPAGES) 
 
index e528f6274014053a8f704fecff3a3ad4075f3475..a8af969b1073fb05e41408156f32cf5a2c157967 100644 (file)
@@ -240,8 +240,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++) {
@@ -566,8 +565,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)
@@ -725,9 +723,7 @@ static errcode_t adjust_superblock(ext2_resize_t rfs, blk64_t new_size)
         * supports lazy inode initialization, we can skip
         * initializing the inode table.
         */
-       if (lazy_itable_init &&
-           EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
-                                      EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) {
+       if (lazy_itable_init && ext2fs_has_group_desc_csum(fs)) {
                retval = 0;
                goto errout;
        }
@@ -883,9 +879,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.
@@ -981,8 +977,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
@@ -1453,10 +1448,12 @@ static __u64 extent_translate(ext2_filsys fs, ext2_extent extent, __u64 old_loc)
 struct process_block_struct {
        ext2_resize_t           rfs;
        ext2_ino_t              ino;
+       ext2_ino_t              old_ino;
        struct ext2_inode *     inode;
        errcode_t               error;
        int                     is_dir;
        int                     changed;
+       int                     has_extents;
 };
 
 static int process_block(ext2_filsys fs, blk64_t       *block_nr,
@@ -1480,11 +1477,23 @@ static int process_block(ext2_filsys fs, blk64_t        *block_nr,
 #ifdef RESIZE2FS_DEBUG
                        if (pb->rfs->flags & RESIZE_DEBUG_BMOVE)
                                printf("ino=%u, blockcnt=%lld, %llu->%llu\n",
-                                      pb->ino, blockcnt, block, new_block);
+                                      pb->old_ino, blockcnt, block,
+                                      new_block);
 #endif
                        block = new_block;
                }
        }
+
+       /*
+        * If we moved inodes and metadata_csum is enabled, we must force the
+        * extent block to be rewritten with new checksum.
+        */
+       if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+                                      EXT4_FEATURE_RO_COMPAT_METADATA_CSUM) &&
+           pb->has_extents &&
+           pb->old_ino != pb->ino)
+               ret |= BLOCK_CHANGED;
+
        if (pb->is_dir) {
                retval = ext2fs_add_dir_block2(fs->dblist, pb->ino,
                                               block, (int) blockcnt);
@@ -1524,6 +1533,46 @@ static errcode_t progress_callback(ext2_filsys fs,
        return 0;
 }
 
+static errcode_t migrate_ea_block(ext2_resize_t rfs, ext2_ino_t ino,
+                                 struct ext2_inode *inode, int *changed)
+{
+       char *buf;
+       blk64_t new_block;
+       errcode_t err = 0;
+
+       /* No EA block or no remapping?  Quit early. */
+       if (ext2fs_file_acl_block(rfs->old_fs, inode) == 0 && !rfs->bmap)
+               return 0;
+       new_block = extent_translate(rfs->old_fs, rfs->bmap,
+               ext2fs_file_acl_block(rfs->old_fs, inode));
+       if (new_block == 0)
+               return 0;
+
+       /* Set the new ACL block */
+       ext2fs_file_acl_block_set(rfs->old_fs, inode, new_block);
+
+       /* Update checksum */
+       if (EXT2_HAS_RO_COMPAT_FEATURE(rfs->new_fs->super,
+                       EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) {
+               err = ext2fs_get_mem(rfs->old_fs->blocksize, &buf);
+               if (err)
+                       return err;
+               rfs->old_fs->flags |= EXT2_FLAG_IGNORE_CSUM_ERRORS;
+               err = ext2fs_read_ext_attr3(rfs->old_fs, new_block, buf, ino);
+               rfs->old_fs->flags &= ~EXT2_FLAG_IGNORE_CSUM_ERRORS;
+               if (err)
+                       goto out;
+               err = ext2fs_write_ext_attr3(rfs->old_fs, new_block, buf, ino);
+               if (err)
+                       goto out;
+       }
+       *changed = 1;
+
+out:
+       ext2fs_free_mem(&buf);
+       return err;
+}
+
 static errcode_t inode_scan_and_fix(ext2_resize_t rfs)
 {
        struct process_block_struct     pb;
@@ -1534,7 +1583,6 @@ static errcode_t inode_scan_and_fix(ext2_resize_t rfs)
        char                    *block_buf = 0;
        ext2_ino_t              start_to_move;
        blk64_t                 orig_size;
-       blk64_t                 new_block;
        int                     inode_size;
 
        if ((rfs->old_fs->group_desc_count <=
@@ -1597,37 +1645,19 @@ static errcode_t inode_scan_and_fix(ext2_resize_t rfs)
                pb.is_dir = LINUX_S_ISDIR(inode->i_mode);
                pb.changed = 0;
 
-               if (ext2fs_file_acl_block(rfs->old_fs, inode) && rfs->bmap) {
-                       new_block = extent_translate(rfs->old_fs, rfs->bmap,
-                               ext2fs_file_acl_block(rfs->old_fs, inode));
-                       if (new_block) {
-                               ext2fs_file_acl_block_set(rfs->old_fs, inode,
-                                                         new_block);
-                               retval = ext2fs_write_inode_full(rfs->old_fs,
-                                                           ino, inode, inode_size);
-                               if (retval) goto errout;
-                       }
-               }
-
-               if (ext2fs_inode_has_valid_blocks2(rfs->old_fs, inode) &&
-                   (rfs->bmap || pb.is_dir)) {
-                       pb.ino = ino;
-                       retval = ext2fs_block_iterate3(rfs->old_fs,
-                                                      ino, 0, block_buf,
-                                                      process_block, &pb);
-                       if (retval)
-                               goto errout;
-                       if (pb.error) {
-                               retval = pb.error;
-                               goto errout;
-                       }
-               }
+               /* Remap EA block */
+               retval = migrate_ea_block(rfs, ino, inode, &pb.changed);
+               if (retval)
+                       goto errout;
 
+               new_inode = ino;
                if (ino <= start_to_move)
-                       continue; /* Don't need to move it. */
+                       goto remap_blocks; /* Don't need to move inode. */
 
                /*
-                * Find a new inode
+                * Find a new inode.  Now that extents and directory blocks
+                * are tied to the inode number through the checksum, we must
+                * set up the new inode before we start rewriting blocks.
                 */
                retval = ext2fs_new_inode(rfs->new_fs, 0, 0, 0, &new_inode);
                if (retval)
@@ -1635,16 +1665,12 @@ static errcode_t inode_scan_and_fix(ext2_resize_t rfs)
 
                ext2fs_inode_alloc_stats2(rfs->new_fs, new_inode, +1,
                                          pb.is_dir);
-               if (pb.changed) {
-                       /* Get the new version of the inode */
-                       retval = ext2fs_read_inode_full(rfs->old_fs, ino,
-                                               inode, inode_size);
-                       if (retval) goto errout;
-               }
                inode->i_ctime = time(0);
                retval = ext2fs_write_inode_full(rfs->old_fs, new_inode,
                                                inode, inode_size);
-               if (retval) goto errout;
+               if (retval)
+                       goto errout;
+               pb.changed = 0;
 
 #ifdef RESIZE2FS_DEBUG
                if (rfs->flags & RESIZE_DEBUG_INODEMAP)
@@ -1656,6 +1682,44 @@ static errcode_t inode_scan_and_fix(ext2_resize_t rfs)
                                goto errout;
                }
                ext2fs_add_extent_entry(rfs->imap, ino, new_inode);
+
+remap_blocks:
+               if (pb.changed)
+                       retval = ext2fs_write_inode_full(rfs->old_fs,
+                                                        new_inode,
+                                                        inode, inode_size);
+               if (retval)
+                       goto errout;
+
+               /*
+                * Update inodes to point to new blocks; schedule directory
+                * blocks for inode remapping.  Need to write out dir blocks
+                * with new inode numbers if we have metadata_csum enabled.
+                */
+               if (ext2fs_inode_has_valid_blocks2(rfs->old_fs, inode) &&
+                   (rfs->bmap || pb.is_dir)) {
+                       pb.ino = new_inode;
+                       pb.old_ino = ino;
+                       pb.has_extents = inode->i_flags & EXT4_EXTENTS_FL;
+                       rfs->old_fs->flags |= EXT2_FLAG_IGNORE_CSUM_ERRORS;
+                       retval = ext2fs_block_iterate3(rfs->old_fs,
+                                                      new_inode, 0, block_buf,
+                                                      process_block, &pb);
+                       rfs->old_fs->flags &= ~EXT2_FLAG_IGNORE_CSUM_ERRORS;
+                       if (retval)
+                               goto errout;
+                       if (pb.error) {
+                               retval = pb.error;
+                               goto errout;
+                       }
+               } else if ((inode->i_flags & EXT4_INLINE_DATA_FL) &&
+                          (rfs->bmap || pb.is_dir)) {
+                       /* inline data dir; update it too */
+                       retval = ext2fs_add_dir_block2(rfs->old_fs->dblist,
+                                                      new_inode, 0, 0);
+                       if (retval)
+                               goto errout;
+               }
        }
        io_channel_flush(rfs->old_fs->io);
 
@@ -1698,6 +1762,7 @@ static int check_and_change_inodes(ext2_ino_t dir,
        struct ext2_inode       inode;
        ext2_ino_t              new_inode;
        errcode_t               retval;
+       int                     ret = 0;
 
        if (is->rfs->progress && offset == 0) {
                io_channel_flush(is->rfs->old_fs->io);
@@ -1708,17 +1773,26 @@ static int check_and_change_inodes(ext2_ino_t dir,
                        return DIRENT_ABORT;
        }
 
+       /*
+        * If we have checksums enabled and the inode wasn't present in the
+        * old fs, then we must rewrite all dir blocks with new checksums.
+        */
+       if (EXT2_HAS_RO_COMPAT_FEATURE(is->rfs->old_fs->super,
+                                      EXT4_FEATURE_RO_COMPAT_METADATA_CSUM) &&
+           !ext2fs_test_inode_bitmap2(is->rfs->old_fs->inode_map, dir))
+               ret |= DIRENT_CHANGED;
+
        if (!dirent->inode)
-               return 0;
+               return ret;
 
        new_inode = ext2fs_extent_translate(is->rfs->imap, dirent->inode);
 
        if (!new_inode)
-               return 0;
+               return ret;
 #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
 
@@ -1730,10 +1804,10 @@ static int check_and_change_inodes(ext2_ino_t dir,
                inode.i_mtime = inode.i_ctime = time(0);
                is->err = ext2fs_write_inode(is->rfs->old_fs, dir, &inode);
                if (is->err)
-                       return DIRENT_ABORT;
+                       return ret | DIRENT_ABORT;
        }
 
-       return DIRENT_CHANGED;
+       return ret | DIRENT_CHANGED;
 }
 
 static errcode_t inode_ref_fix(ext2_resize_t rfs)
@@ -1760,9 +1834,11 @@ static errcode_t inode_ref_fix(ext2_resize_t rfs)
                        goto errout;
        }
 
+       rfs->old_fs->flags |= EXT2_FLAG_IGNORE_CSUM_ERRORS;
        retval = ext2fs_dblist_dir_iterate(rfs->old_fs->dblist,
                                           DIRENT_FLAG_INCLUDE_EMPTY, 0,
                                           check_and_change_inodes, &is);
+       rfs->old_fs->flags &= ~EXT2_FLAG_IGNORE_CSUM_ERRORS;
        if (retval)
                goto errout;
        if (is.err) {
diff --git a/tests/d_xattr_edits/expect b/tests/d_xattr_edits/expect
new file mode 100644 (file)
index 0000000..10e30c1
--- /dev/null
@@ -0,0 +1,51 @@
+debugfs edit extended attributes
+mke2fs -Fq -b 1024 test.img 512
+Exit status is 0
+ea_set / user.joe smith
+Exit status is 0
+ea_set / user.moo FEE_FIE_FOE_FUMMMMMM
+Exit status is 0
+ea_list /
+Extended attributes:
+  user.joe = "smith" (5)
+  user.moo = "FEE_FIE_FOE_FUMMMMMM" (20)
+Exit status is 0
+ea_get / user.moo
+FEE_FIE_FOE_FUMMMMMM
+Exit status is 0
+ea_get / nosuchea
+ea_get: Extended attribute key not found while getting extended attribute
+Exit status is 0
+ea_rm / user.moo
+Exit status is 0
+ea_rm / nosuchea
+ea_rm: Extended attribute key not found while removing extended attribute
+Exit status is 0
+ea_list /
+Extended attributes:
+  user.joe = "smith" (5)
+Exit status is 0
+ea_get / user.moo
+ea_get: Extended attribute key not found while getting extended attribute
+Exit status is 0
+ea_rm / user.joe
+Exit status is 0
+ea_list /
+Exit status is 0
+ea_set / user.file_based_xattr -f d_xattr_edits.tmp
+Exit status is 0
+ea_list /
+Extended attributes:
+  user.file_based_xattr = "12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567\012" (108)
+Exit status is 0
+ea_get / user.file_based_xattr -f d_xattr_edits.ver.tmp
+Exit status is 0
+Compare big attribute
+e2fsck -yf -N test_filesys
+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/64 files (0.0% non-contiguous), 29/512 blocks
+Exit status is 0
diff --git a/tests/d_xattr_edits/name b/tests/d_xattr_edits/name
new file mode 100644 (file)
index 0000000..c0c428c
--- /dev/null
@@ -0,0 +1 @@
+edit extended attributes in debugfs
diff --git a/tests/d_xattr_edits/script b/tests/d_xattr_edits/script
new file mode 100644 (file)
index 0000000..1e33716
--- /dev/null
@@ -0,0 +1,135 @@
+if test -x $DEBUGFS_EXE; then
+
+OUT=$test_name.log
+EXP=$test_dir/expect
+VERIFY_FSCK_OPT=-yf
+
+TEST_DATA=$test_name.tmp
+VERIFY_DATA=$test_name.ver.tmp
+
+echo "debugfs edit extended attributes" > $OUT
+
+dd if=/dev/zero of=$TMPFILE bs=1k count=512 > /dev/null 2>&1
+
+echo "mke2fs -Fq -b 1024 test.img 512" >> $OUT
+
+$MKE2FS -Fq $TMPFILE 512 > /dev/null 2>&1
+status=$?
+echo Exit status is $status >> $OUT
+
+echo "ea_set / user.joe smith" > $OUT.new
+$DEBUGFS -w $TMPFILE -R "ea_set / user.joe smith" >> $OUT.new 2>&1
+status=$?
+echo Exit status is $status >> $OUT.new
+sed -f $cmd_dir/filter.sed $OUT.new >> $OUT
+
+echo "ea_set / user.moo FEE_FIE_FOE_FUMMMMMM" > $OUT.new
+$DEBUGFS -w $TMPFILE -R "ea_set / user.moo FEE_FIE_FOE_FUMMMMMM" >> $OUT.new 2>&1
+status=$?
+echo Exit status is $status >> $OUT.new
+sed -f $cmd_dir/filter.sed $OUT.new >> $OUT
+
+echo "ea_list /" > $OUT.new
+$DEBUGFS -w $TMPFILE -R "ea_list /" >> $OUT.new 2>&1
+status=$?
+echo Exit status is $status >> $OUT.new
+sed -f $cmd_dir/filter.sed $OUT.new >> $OUT
+
+echo "ea_get / user.moo" > $OUT.new
+$DEBUGFS -w $TMPFILE -R "ea_get / user.moo" >> $OUT.new 2>&1
+status=$?
+echo Exit status is $status >> $OUT.new
+sed -f $cmd_dir/filter.sed $OUT.new >> $OUT
+
+echo "ea_get / nosuchea" > $OUT.new
+$DEBUGFS -w $TMPFILE -R "ea_get / nosuchea" >> $OUT.new 2>&1
+status=$?
+echo Exit status is $status >> $OUT.new
+sed -f $cmd_dir/filter.sed $OUT.new >> $OUT
+
+echo "ea_rm / user.moo" > $OUT.new
+$DEBUGFS -w $TMPFILE -R "ea_rm / user.moo" >> $OUT.new 2>&1
+status=$?
+echo Exit status is $status >> $OUT.new
+sed -f $cmd_dir/filter.sed $OUT.new >> $OUT
+
+echo "ea_rm / nosuchea" > $OUT.new
+$DEBUGFS -w $TMPFILE -R "ea_rm / nosuchea" >> $OUT.new 2>&1
+status=$?
+echo Exit status is $status >> $OUT.new
+sed -f $cmd_dir/filter.sed $OUT.new >> $OUT
+
+echo "ea_list /" > $OUT.new
+$DEBUGFS -w $TMPFILE -R "ea_list /" >> $OUT.new 2>&1
+status=$?
+echo Exit status is $status >> $OUT.new
+sed -f $cmd_dir/filter.sed $OUT.new >> $OUT
+
+echo "ea_get / user.moo" > $OUT.new
+$DEBUGFS -w $TMPFILE -R "ea_get / user.moo" >> $OUT.new 2>&1
+status=$?
+echo Exit status is $status >> $OUT.new
+sed -f $cmd_dir/filter.sed $OUT.new >> $OUT
+
+echo "ea_rm / user.joe" > $OUT.new
+$DEBUGFS -w $TMPFILE -R "ea_rm / user.joe" >> $OUT.new 2>&1
+status=$?
+echo Exit status is $status >> $OUT.new
+sed -f $cmd_dir/filter.sed $OUT.new >> $OUT
+
+echo "ea_list /" > $OUT.new
+$DEBUGFS -w $TMPFILE -R "ea_list /" >> $OUT.new 2>&1
+status=$?
+echo Exit status is $status >> $OUT.new
+sed -f $cmd_dir/filter.sed $OUT.new >> $OUT
+
+echo "12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567" > $TEST_DATA
+echo "ea_set / user.file_based_xattr -f $TEST_DATA" > $OUT.new
+$DEBUGFS -w $TMPFILE -R "ea_set / user.file_based_xattr -f $TEST_DATA" >> $OUT.new 2>&1
+status=$?
+echo Exit status is $status >> $OUT.new
+sed -f $cmd_dir/filter.sed $OUT.new >> $OUT
+
+echo "ea_list /" > $OUT.new
+$DEBUGFS -w $TMPFILE -R "ea_list /" >> $OUT.new 2>&1
+status=$?
+echo Exit status is $status >> $OUT.new
+sed -f $cmd_dir/filter.sed $OUT.new >> $OUT
+
+echo "ea_get / user.file_based_xattr -f $VERIFY_DATA" > $OUT.new
+$DEBUGFS -w $TMPFILE -R "ea_get / user.file_based_xattr -f $VERIFY_DATA" >> $OUT.new 2>&1
+status=$?
+echo Exit status is $status >> $OUT.new
+sed -f $cmd_dir/filter.sed $OUT.new >> $OUT
+
+echo "Compare big attribute" > $OUT.new
+diff -u $TEST_DATA $VERIFY_DATA >> $OUT.new
+sed -f $cmd_dir/filter.sed $OUT.new >> $OUT
+
+echo e2fsck $VERIFY_FSCK_OPT -N test_filesys > $OUT.new
+$FSCK $VERIFY_FSCK_OPT -N test_filesys $TMPFILE >> $OUT.new 2>&1
+status=$?
+echo Exit status is $status >> $OUT.new
+sed -f $cmd_dir/filter.sed $OUT.new >> $OUT
+
+#
+# Do the verification
+#
+
+rm -f $TMPFILE $OUT.new
+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 VERIFY_FSCK_OPT NATIVE_FSCK_OPT OUT EXP TEST_DATA VERIFY_DATA
+
+else #if test -x $DEBUGFS_EXE; then
+       echo "$test_name: $test_description: skipped"
+fi
index 11862f65fdc1bb1af1cf80c80e8762fb07836c82..9f9b447d58448926a5995b4faa3d45b02443093e 100644 (file)
@@ -2,9 +2,18 @@ Pass 1: Checking inodes, blocks, and sizes
 Inode 1 has EXTENTS_FL flag set on filesystem without extents support.
 Clear? yes
 
+Inode 14 has INLINE_DATA_FL flag on filesystem without inline data support.
+Clear? yes
+
+Inode 15 has INLINE_DATA_FL flag on filesystem without inline data support.
+Clear? yes
+
 Inode 15 has EXTENTS_FL flag set on filesystem without extents support.
 Clear? yes
 
+Inode 16 has INLINE_DATA_FL flag on filesystem without inline data support.
+Clear? yes
+
 Inode 16 has EXTENTS_FL flag set on filesystem without extents support.
 Clear? yes
 
index 1d639f6cc05c9164f19c807d144bd08338803ce9..ec1a36edb54d6ecbacdbefa0f80923961f15656f 100644 (file)
@@ -8,8 +8,8 @@ Relocating group 0's inode bitmap from 4 to 43...
 Running additional passes to resolve blocks claimed by more than one inode...
 Pass 1B: Rescanning for multiply-claimed blocks
 Multiply-claimed block(s) in inode 2: 21
-Multiply-claimed block(s) in inode 11: 9 10 11 12 13 14 15 16 17 18 19 20
-Multiply-claimed block(s) in inode 12: 25 26
+Multiply-claimed block(s) in inode 11: 9--20
+Multiply-claimed block(s) in inode 12: 25--26
 Pass 1C: Scanning directories for inodes with multiply-claimed blocks
 Pass 1D: Reconciling multiply-claimed blocks
 (There are 3 inodes containing multiply-claimed blocks.)
index e7128f34b8c9c06450e4eec2fbc81c91359ca3e9..075e62c13a21febddd640d1866103ad591485b3e 100644 (file)
@@ -4,8 +4,8 @@ Pass 1: Checking inodes, blocks, and sizes
 
 Running additional passes to resolve blocks claimed by more than one inode...
 Pass 1B: Rescanning for multiply-claimed blocks
-Multiply-claimed block(s) in inode 12: 25 26
-Multiply-claimed block(s) in inode 13: 25 26
+Multiply-claimed block(s) in inode 12: 25--26
+Multiply-claimed block(s) in inode 13: 25--26
 Pass 1C: Scanning directories for inodes with multiply-claimed blocks
 Pass 1D: Reconciling multiply-claimed blocks
 (There are 2 inodes containing multiply-claimed blocks.)
index 0476005da5b6ced132187df391b73b8b937d1f41..69aa21b4b743a41c872d2727f35936a101d381df 100644 (file)
@@ -4,9 +4,9 @@ Pass 1: Checking inodes, blocks, and sizes
 
 Running additional passes to resolve blocks claimed by more than one inode...
 Pass 1B: Rescanning for multiply-claimed blocks
-Multiply-claimed block(s) in inode 12: 25 26
-Multiply-claimed block(s) in inode 13: 25 26 57 58
-Multiply-claimed block(s) in inode 14: 57 58
+Multiply-claimed block(s) in inode 12: 25--26
+Multiply-claimed block(s) in inode 13: 25--26 57--58
+Multiply-claimed block(s) in inode 14: 57--58
 Pass 1C: Scanning directories for inodes with multiply-claimed blocks
 Pass 1D: Reconciling multiply-claimed blocks
 (There are 3 inodes containing multiply-claimed blocks.)
index f0ad4570827064b764451231565beced293a0738..f4581c4e7d87b228b925ef71a684c3da6d1064d3 100644 (file)
@@ -6,12 +6,12 @@ Inode 16, i_blocks is 128, should be 896.  Fix? yes
 
 Running additional passes to resolve blocks claimed by more than one inode...
 Pass 1B: Rescanning for multiply-claimed blocks
-Multiply-claimed block(s) in inode 16: 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239
-Multiply-claimed block(s) in inode 17: 160 161
-Multiply-claimed block(s) in inode 18: 176 177
-Multiply-claimed block(s) in inode 19: 192 193
-Multiply-claimed block(s) in inode 20: 208 209
-Multiply-claimed block(s) in inode 21: 224 225
+Multiply-claimed block(s) in inode 16: 160--239
+Multiply-claimed block(s) in inode 17: 160--161
+Multiply-claimed block(s) in inode 18: 176--177
+Multiply-claimed block(s) in inode 19: 192--193
+Multiply-claimed block(s) in inode 20: 208--209
+Multiply-claimed block(s) in inode 21: 224--225
 Pass 1C: Scanning directories for inodes with multiply-claimed blocks
 Pass 1D: Reconciling multiply-claimed blocks
 (There are 6 inodes containing multiply-claimed blocks.)
index dd8fe05c9a251545d85d8f3839aa2bae85ea21f3..aaf7769cbcd7088bd9d22b8f38865b41d66ac9b8 100644 (file)
@@ -4,8 +4,8 @@ Pass 1: Checking inodes, blocks, and sizes
 
 Running additional passes to resolve blocks claimed by more than one inode...
 Pass 1B: Rescanning for multiply-claimed blocks
-Multiply-claimed block(s) in inode 7: 4 5 6 7
-Multiply-claimed block(s) in inode 12: 4 5 6 7
+Multiply-claimed block(s) in inode 7: 4--7
+Multiply-claimed block(s) in inode 12: 4--7
 Pass 1C: Scanning directories for inodes with multiply-claimed blocks
 Pass 1D: Reconciling multiply-claimed blocks
 (There are 1 inodes containing multiply-claimed blocks.)
index 3f70109128e6b847fad2a456c4a6d3184e30b984..675198679a3696e7f4e8440302f66e9d1b14fdf4 100644 (file)
@@ -8,8 +8,8 @@ Inode 13, i_size is 0, should be 2048.  Fix? yes
 
 Running additional passes to resolve blocks claimed by more than one inode...
 Pass 1B: Rescanning for multiply-claimed blocks
-Multiply-claimed block(s) in inode 12: 3 4 6 1
-Multiply-claimed block(s) in inode 13: 2 3
+Multiply-claimed block(s) in inode 12: 3--4 6 1
+Multiply-claimed block(s) in inode 13: 2--3
 Multiply-claimed block(s) in inode 14: 2
 Pass 1C: Scanning directories for inodes with multiply-claimed blocks
 Pass 1D: Reconciling multiply-claimed blocks
index 830370a67758353350242f517b893285599a514f..2107e2d3a5183c1ba11bfa0c530d22371833d5aa 100644 (file)
@@ -4,7 +4,7 @@ Pass 1: Checking inodes, blocks, and sizes
 
 Running additional passes to resolve blocks claimed by more than one inode...
 Pass 1B: Rescanning for multiply-claimed blocks
-Multiply-claimed block(s) in inode 12: 2 3 1
+Multiply-claimed block(s) in inode 12: 2--3 1
 Pass 1C: Scanning directories for inodes with multiply-claimed blocks
 Pass 1D: Reconciling multiply-claimed blocks
 (There are 1 inodes containing multiply-claimed blocks.)
index 2007f0391d47203479e0f11a67d74eee57a3bdb1..5cef2d890842003c36f89794b61ec6ea5a38f29c 100644 (file)
 Journal starts at block 67, transaction 32
 Found expected sequence 32, type 5 (revoke table) at block 67
 Dumping revoke block, sequence 32, at block 67:
-  Revoke FS block 0
   Revoke FS block 1536
-  Revoke FS block 0
   Revoke FS block 1472
-  Revoke FS block 0
   Revoke FS block 1473
-  Revoke FS block 0
   Revoke FS block 1474
-  Revoke FS block 0
   Revoke FS block 1475
-  Revoke FS block 0
   Revoke FS block 1476
-  Revoke FS block 0
   Revoke FS block 1541
-  Revoke FS block 0
   Revoke FS block 1477
-  Revoke FS block 0
   Revoke FS block 1478
-  Revoke FS block 0
   Revoke FS block 1479
-  Revoke FS block 0
   Revoke FS block 1480
-  Revoke FS block 0
   Revoke FS block 1481
-  Revoke FS block 0
   Revoke FS block 1482
-  Revoke FS block 0
   Revoke FS block 1483
-  Revoke FS block 0
   Revoke FS block 1484
-  Revoke FS block 0
   Revoke FS block 1485
-  Revoke FS block 0
   Revoke FS block 1486
-  Revoke FS block 0
   Revoke FS block 1487
-  Revoke FS block 0
   Revoke FS block 1488
-  Revoke FS block 0
   Revoke FS block 1489
-  Revoke FS block 0
   Revoke FS block 1490
-  Revoke FS block 0
   Revoke FS block 1491
-  Revoke FS block 0
   Revoke FS block 1556
-  Revoke FS block 0
   Revoke FS block 1492
-  Revoke FS block 0
   Revoke FS block 1493
-  Revoke FS block 0
   Revoke FS block 1429
-  Revoke FS block 0
   Revoke FS block 1494
-  Revoke FS block 0
   Revoke FS block 1495
-  Revoke FS block 0
   Revoke FS block 1496
-  Revoke FS block 0
   Revoke FS block 1432
-  Revoke FS block 0
   Revoke FS block 1497
-  Revoke FS block 0
   Revoke FS block 1498
-  Revoke FS block 0
   Revoke FS block 1434
-  Revoke FS block 0
   Revoke FS block 1499
-  Revoke FS block 0
   Revoke FS block 1435
-  Revoke FS block 0
   Revoke FS block 1500
-  Revoke FS block 0
   Revoke FS block 1501
-  Revoke FS block 0
   Revoke FS block 1502
-  Revoke FS block 0
   Revoke FS block 1503
-  Revoke FS block 0
   Revoke FS block 1504
-  Revoke FS block 0
   Revoke FS block 1505
-  Revoke FS block 0
   Revoke FS block 1506
-  Revoke FS block 0
   Revoke FS block 1442
-  Revoke FS block 0
   Revoke FS block 1507
-  Revoke FS block 0
   Revoke FS block 1508
-  Revoke FS block 0
   Revoke FS block 1444
-  Revoke FS block 0
   Revoke FS block 1509
-  Revoke FS block 0
   Revoke FS block 1445
-  Revoke FS block 0
   Revoke FS block 1510
-  Revoke FS block 0
   Revoke FS block 1511
-  Revoke FS block 0
   Revoke FS block 1512
-  Revoke FS block 0
   Revoke FS block 1513
-  Revoke FS block 0
   Revoke FS block 1449
-  Revoke FS block 0
   Revoke FS block 1514
-  Revoke FS block 0
   Revoke FS block 1515
-  Revoke FS block 0
   Revoke FS block 1516
-  Revoke FS block 0
   Revoke FS block 1517
-  Revoke FS block 0
   Revoke FS block 1453
-  Revoke FS block 0
   Revoke FS block 1518
-  Revoke FS block 0
   Revoke FS block 1519
-  Revoke FS block 0
   Revoke FS block 1520
-  Revoke FS block 0
   Revoke FS block 1456
-  Revoke FS block 0
   Revoke FS block 1521
-  Revoke FS block 0
   Revoke FS block 1457
-  Revoke FS block 0
   Revoke FS block 1522
-  Revoke FS block 0
   Revoke FS block 1458
-  Revoke FS block 0
   Revoke FS block 1523
-  Revoke FS block 0
   Revoke FS block 1459
-  Revoke FS block 0
   Revoke FS block 1524
-  Revoke FS block 0
   Revoke FS block 1460
-  Revoke FS block 0
   Revoke FS block 1525
-  Revoke FS block 0
   Revoke FS block 1461
-  Revoke FS block 0
   Revoke FS block 1526
-  Revoke FS block 0
   Revoke FS block 1462
-  Revoke FS block 0
   Revoke FS block 1527
-  Revoke FS block 0
   Revoke FS block 1463
-  Revoke FS block 0
   Revoke FS block 1528
-  Revoke FS block 0
   Revoke FS block 1464
-  Revoke FS block 0
   Revoke FS block 1529
-  Revoke FS block 0
   Revoke FS block 1465
-  Revoke FS block 0
   Revoke FS block 1530
-  Revoke FS block 0
   Revoke FS block 1466
-  Revoke FS block 0
   Revoke FS block 1531
-  Revoke FS block 0
   Revoke FS block 1467
-  Revoke FS block 0
   Revoke FS block 1532
-  Revoke FS block 0
   Revoke FS block 1468
-  Revoke FS block 0
   Revoke FS block 1533
-  Revoke FS block 0
   Revoke FS block 1469
-  Revoke FS block 0
   Revoke FS block 1534
-  Revoke FS block 0
   Revoke FS block 1470
-  Revoke FS block 0
   Revoke FS block 1535
-  Revoke FS block 0
   Revoke FS block 1471
 Found expected sequence 32, type 1 (descriptor block) at block 68
 Dumping descriptor block, sequence 32, at block 68:
@@ -323,163 +231,84 @@ Dumping descriptor block, sequence 32, at block 150:
 Found expected sequence 32, type 2 (commit block) at block 201
 Found expected sequence 33, type 5 (revoke table) at block 202
 Dumping revoke block, sequence 33, at block 202:
-  Revoke FS block 0
   Revoke FS block 1600
-  Revoke FS block 0
   Revoke FS block 1601
-  Revoke FS block 0
   Revoke FS block 1537
-  Revoke FS block 0
   Revoke FS block 1602
-  Revoke FS block 0
   Revoke FS block 1538
-  Revoke FS block 0
   Revoke FS block 1603
-  Revoke FS block 0
   Revoke FS block 1539
-  Revoke FS block 0
   Revoke FS block 1604
-  Revoke FS block 0
   Revoke FS block 1540
-  Revoke FS block 0
   Revoke FS block 1605
-  Revoke FS block 0
   Revoke FS block 1606
-  Revoke FS block 0
   Revoke FS block 1542
-  Revoke FS block 0
   Revoke FS block 1607
-  Revoke FS block 0
   Revoke FS block 1543
-  Revoke FS block 0
   Revoke FS block 1608
-  Revoke FS block 0
   Revoke FS block 1544
-  Revoke FS block 0
   Revoke FS block 1609
-  Revoke FS block 0
   Revoke FS block 1545
-  Revoke FS block 0
   Revoke FS block 1610
-  Revoke FS block 0
   Revoke FS block 1546
-  Revoke FS block 0
   Revoke FS block 1611
-  Revoke FS block 0
   Revoke FS block 1547
-  Revoke FS block 0
   Revoke FS block 1612
-  Revoke FS block 0
   Revoke FS block 1548
-  Revoke FS block 0
   Revoke FS block 1613
-  Revoke FS block 0
   Revoke FS block 1549
-  Revoke FS block 0
   Revoke FS block 1614
-  Revoke FS block 0
   Revoke FS block 1550
-  Revoke FS block 0
   Revoke FS block 1615
-  Revoke FS block 0
   Revoke FS block 1551
-  Revoke FS block 0
   Revoke FS block 1616
-  Revoke FS block 0
   Revoke FS block 1552
-  Revoke FS block 0
   Revoke FS block 1617
-  Revoke FS block 0
   Revoke FS block 1553
-  Revoke FS block 0
   Revoke FS block 1554
-  Revoke FS block 0
   Revoke FS block 1555
-  Revoke FS block 0
   Revoke FS block 1557
-  Revoke FS block 0
   Revoke FS block 1558
-  Revoke FS block 0
   Revoke FS block 1559
-  Revoke FS block 0
   Revoke FS block 1560
-  Revoke FS block 0
   Revoke FS block 1561
-  Revoke FS block 0
   Revoke FS block 1562
-  Revoke FS block 0
   Revoke FS block 1563
-  Revoke FS block 0
   Revoke FS block 1564
-  Revoke FS block 0
   Revoke FS block 1565
-  Revoke FS block 0
   Revoke FS block 1566
-  Revoke FS block 0
   Revoke FS block 1567
-  Revoke FS block 0
   Revoke FS block 1568
-  Revoke FS block 0
   Revoke FS block 1569
-  Revoke FS block 0
   Revoke FS block 1570
-  Revoke FS block 0
   Revoke FS block 1571
-  Revoke FS block 0
   Revoke FS block 1572
-  Revoke FS block 0
   Revoke FS block 1573
-  Revoke FS block 0
   Revoke FS block 1574
-  Revoke FS block 0
   Revoke FS block 1575
-  Revoke FS block 0
   Revoke FS block 1576
-  Revoke FS block 0
   Revoke FS block 1577
-  Revoke FS block 0
   Revoke FS block 1578
-  Revoke FS block 0
   Revoke FS block 1579
-  Revoke FS block 0
   Revoke FS block 1580
-  Revoke FS block 0
   Revoke FS block 1581
-  Revoke FS block 0
   Revoke FS block 1582
-  Revoke FS block 0
   Revoke FS block 1583
-  Revoke FS block 0
   Revoke FS block 1584
-  Revoke FS block 0
   Revoke FS block 1585
-  Revoke FS block 0
   Revoke FS block 1586
-  Revoke FS block 0
   Revoke FS block 1587
-  Revoke FS block 0
   Revoke FS block 1588
-  Revoke FS block 0
   Revoke FS block 1589
-  Revoke FS block 0
   Revoke FS block 1590
-  Revoke FS block 0
   Revoke FS block 1591
-  Revoke FS block 0
   Revoke FS block 1592
-  Revoke FS block 0
   Revoke FS block 1593
-  Revoke FS block 0
   Revoke FS block 1594
-  Revoke FS block 0
   Revoke FS block 1595
-  Revoke FS block 0
   Revoke FS block 1596
-  Revoke FS block 0
   Revoke FS block 1597
-  Revoke FS block 0
   Revoke FS block 1598
-  Revoke FS block 0
   Revoke FS block 1599
 Found expected sequence 33, type 1 (descriptor block) at block 203
 Dumping descriptor block, sequence 33, at block 203:
index d921672eea1a404a56d15fe56ec698f09baff5fe..105a305821a1313192cc056adfa7afae9ad24b53 100644 (file)
@@ -1,5 +1,6 @@
 FSCK_OPT=-yf
 
+[ -f "$TMPFILE" ] && rm -f $TMPFILE
 TMPFILE=$test_name.tmp
 > $TMPFILE
 
index 02cc12a4280b4ad8002d527c35eeae2309e9e5e0..d4d2cb3c441abcd3344528dae66f07d14bb8438d 100644 (file)
@@ -1,5 +1,6 @@
 FSCK_OPT=-yf
 
+[ -f "$TMPFILE" ] && rm -f $TMPFILE
 TMPFILE=$test_name.tmp
 > $TMPFILE
 
index 91b956b7b48dbecf2c46446ec48420f1bcc86d17..59fad4e82204562f8cc8c4e7aa35dbf25ca2ee86 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 02b0b4b84c08d59313514034a4b4063cf646f020..dff98f05c030efb701a65e091e722dfb789d2e0d 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 44d04b5106e27683c7a39f991a8adafce488389f..22d941799ae6990d07bcef070b45b4082ba353aa 100644 (file)
@@ -28,6 +28,7 @@ DEPLIBS= $(LIBEXT2FS) $(DEPLIBSS) $(DEPLIBCOM_ERR)
        $(E) "  CC $<"
        $(Q) $(CC) -c $(ALL_CFLAGS) $< -o $@
        $(Q) $(CHECK_CMD) $(ALL_CFLAGS) $<
+       $(Q) $(CPPCHECK_CMD) $(CPPFLAGS) $<
 
 all:: $(PROGS)
 
index 9e7126469cc91295cb19dbda2357fa221b5a9c6b..c7aa088c9d59d88e5319d2a51f1d76d8dfdd08e5 100644 (file)
@@ -1,8 +1,7 @@
 resize2fs test
 debugfs -R ''stat file'' test.img 2>&1 | grep ''^Inode\|in inode body\|name = ''
 Inode: 1550   Type: regular    Mode:  0644   Flags: 0x0
-Extended attributes stored in inode body: 
-  name = "propervalue" (11)
+  user.name = "propervalue" (11)
 Exit status is 0
 resize2fs test.img 5M
 Resizing the filesystem on test.img to 5120 (1k) blocks.
@@ -11,6 +10,5 @@ The filesystem on test.img is now 5120 blocks long.
 Exit status is 0
 debugfs -R ''stat file'' test.img 2>&1 | grep ''^Inode\|in inode body\|name = ''
 Inode: 12   Type: regular    Mode:  0644   Flags: 0x0
-Extended attributes stored in inode body: 
-  name = "propervalue" (11)
+  user.name = "propervalue" (11)
 Exit status is 0
index 8fc8158ff60d23e1d480eb42b8a9fe91701d0d29..d15b1e33bb8d13cd201db2b51400ece45da39dc9 100644 (file)
@@ -1,5 +1,6 @@
 FSCK_OPT=-yf
 
+[ -f "$TMPFILE" ] && rm -f $TMPFILE
 TMPFILE=$test_name.tmp
 > $TMPFILE
 
index 1dee14ed53ccb9d3baa90541534420e593300055..572730b4eca7921ead4839adfc359b891c8a45f3 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 d235fffc5db5e2e15eb8900283966c881bf2490c..5171c1ccf706218f8427122029f77085cca2047b 100644 (file)
@@ -17,6 +17,7 @@ SRCS = $(srcdir)/subst.c
        $(E) "  CC $<"
        $(Q) $(BUILD_CC) -c $(BUILD_CFLAGS) $< -o $@
        $(Q) $(CHECK_CMD) $(ALL_CFLAGS) $<
+       $(Q) $(CPPCHECK_CMD) $(CPPFLAGS) $<
 
 PROGS=         subst symlinks
 
diff --git a/util/static-analysis-cleanup b/util/static-analysis-cleanup
new file mode 100644 (file)
index 0000000..6749259
--- /dev/null
@@ -0,0 +1,20 @@
+#!/bin/sed -f
+#
+# This script filters out gcc-wall crud that we're not interested in seeing.
+#
+/^cc /d
+/^kcc /d
+/^gcc /d
+/does not support `long long'/d
+/forbids long long integer constants/d
+/does not support the `ll' length modifier/d
+/does not support the `ll' printf length modifier/d
+/ANSI C forbids long long integer constants/d
+/traditional C rejects string concatenation/d
+/integer constant is unsigned in ANSI C, signed with -traditional/d
+/warning: missing initializer/d
+/warning: (near initialization for/d
+/^[    ]*from/d
+/unused parameter/d
+/e2_types.h" not found.$/d
+/e2_bitops.h" not found.$/d
index 6a5eab1bc72c4beef84abc76a4857f0fc972998f..32d5293207c77c4aca74ba5a628fcebcaf2614a7 100644 (file)
@@ -17,6 +17,9 @@
 #include <fcntl.h>
 #include <time.h>
 #include <utime.h>
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
 
 #ifdef HAVE_GETOPT_H
 #include <getopt.h>
@@ -426,6 +429,8 @@ int main(int argc, char **argv)
        }
        if (old)
                fclose(old);
+       if (newfn)
+               free(newfn);
        return (0);
 }
 
index f99ce493df0429dc921921ea828d1e3adda1ca45..9eb6e94c47273dc422815321769b062d08d870a3 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.9"
+#define E2FSPROGS_VERSION "1.43-WIP"
 #define E2FSPROGS_DATE "4-Feb-2014"