Whamcloud - gitweb
Merge branch 'maint' into next
authorTheodore Ts'o <tytso@mit.edu>
Sun, 10 Aug 2014 23:33:31 +0000 (19:33 -0400)
committerTheodore Ts'o <tytso@mit.edu>
Sun, 10 Aug 2014 23:33:31 +0000 (19:33 -0400)
Conflicts:
e2fsck/unix.c

264 files changed:
.gitignore
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.c
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/e2fuzz.c [new file with mode: 0644]
misc/e2fuzz.sh [new file with mode: 0755]
misc/e2image.c
misc/ext4.5.in
misc/mke2fs.8.in
misc/mke2fs.c
misc/mke2fs.conf.5.in
misc/mke2fs.conf.in
misc/tune2fs.c
resize/Makefile.in
resize/resize2fs.c
tests/d_inline_dump/expect [new file with mode: 0644]
tests/d_inline_dump/image.gz [new file with mode: 0644]
tests/d_inline_dump/name [new file with mode: 0644]
tests/d_inline_dump/script [new file with mode: 0644]
tests/d_special_files/expect
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_bbitmap/expect.1 [new file with mode: 0644]
tests/f_bad_bbitmap/expect.2 [new file with mode: 0644]
tests/f_bad_bbitmap/image.gz [new file with mode: 0644]
tests/f_bad_bbitmap/name [new file with mode: 0644]
tests/f_bad_bmap_csum/expect.1 [new file with mode: 0644]
tests/f_bad_bmap_csum/expect.2 [new file with mode: 0644]
tests/f_bad_bmap_csum/image.gz [new file with mode: 0644]
tests/f_bad_bmap_csum/name [new file with mode: 0644]
tests/f_bad_disconnected_inode/expect.1
tests/f_bad_gdt_csum/expect.1 [new file with mode: 0644]
tests/f_bad_gdt_csum/expect.2 [new file with mode: 0644]
tests/f_bad_gdt_csum/image.gz [new file with mode: 0644]
tests/f_bad_gdt_csum/name [new file with mode: 0644]
tests/f_bad_ibitmap/expect.1 [new file with mode: 0644]
tests/f_bad_ibitmap/expect.2 [new file with mode: 0644]
tests/f_bad_ibitmap/image.gz [new file with mode: 0644]
tests/f_bad_ibitmap/name [new file with mode: 0644]
tests/f_bad_inode_csum/expect.1 [new file with mode: 0644]
tests/f_bad_inode_csum/expect.2 [new file with mode: 0644]
tests/f_bad_inode_csum/image.gz [new file with mode: 0644]
tests/f_bad_inode_csum/name [new file with mode: 0644]
tests/f_badcluster/expect
tests/f_bbfile/expect.1
tests/f_corrupt_dirent_tail/expect.1 [new file with mode: 0644]
tests/f_corrupt_dirent_tail/expect.2 [new file with mode: 0644]
tests/f_corrupt_dirent_tail/image.gz [new file with mode: 0644]
tests/f_corrupt_dirent_tail/name [new file with mode: 0644]
tests/f_deleted_inode_bad_csum/expect.1 [new file with mode: 0644]
tests/f_deleted_inode_bad_csum/expect.2 [new file with mode: 0644]
tests/f_deleted_inode_bad_csum/image.gz [new file with mode: 0644]
tests/f_deleted_inode_bad_csum/name [new file with mode: 0644]
tests/f_dir_bad_csum/expect.1 [new file with mode: 0644]
tests/f_dir_bad_csum/expect.2 [new file with mode: 0644]
tests/f_dir_bad_csum/image.gz [new file with mode: 0644]
tests/f_dir_bad_csum/name [new file with mode: 0644]
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_ea_bad_csum/expect.1 [new file with mode: 0644]
tests/f_ea_bad_csum/expect.2 [new file with mode: 0644]
tests/f_ea_bad_csum/image.gz [new file with mode: 0644]
tests/f_ea_bad_csum/name [new file with mode: 0644]
tests/f_extent_bad_node/name
tests/f_extent_int_bad_csum/expect.1 [new file with mode: 0644]
tests/f_extent_int_bad_csum/expect.2 [new file with mode: 0644]
tests/f_extent_int_bad_csum/image.gz [new file with mode: 0644]
tests/f_extent_int_bad_csum/name [new file with mode: 0644]
tests/f_extent_int_bad_extent/expect.1 [new file with mode: 0644]
tests/f_extent_int_bad_extent/expect.2 [new file with mode: 0644]
tests/f_extent_int_bad_extent/image.gz [new file with mode: 0644]
tests/f_extent_int_bad_extent/name [new file with mode: 0644]
tests/f_extent_int_bad_magic/expect.1 [new file with mode: 0644]
tests/f_extent_int_bad_magic/expect.2 [new file with mode: 0644]
tests/f_extent_int_bad_magic/image.gz [new file with mode: 0644]
tests/f_extent_int_bad_magic/name [new file with mode: 0644]
tests/f_extent_leaf_bad_csum/expect.1 [new file with mode: 0644]
tests/f_extent_leaf_bad_csum/expect.2 [new file with mode: 0644]
tests/f_extent_leaf_bad_csum/image.gz [new file with mode: 0644]
tests/f_extent_leaf_bad_csum/name [new file with mode: 0644]
tests/f_extent_leaf_bad_extent/expect.1 [new file with mode: 0644]
tests/f_extent_leaf_bad_extent/expect.2 [new file with mode: 0644]
tests/f_extent_leaf_bad_extent/image.gz [new file with mode: 0644]
tests/f_extent_leaf_bad_extent/name [new file with mode: 0644]
tests/f_extent_leaf_bad_magic/expect.1 [new file with mode: 0644]
tests/f_extent_leaf_bad_magic/expect.2 [new file with mode: 0644]
tests/f_extent_leaf_bad_magic/image.gz [new file with mode: 0644]
tests/f_extent_leaf_bad_magic/name [new file with mode: 0644]
tests/f_extents/expect.1
tests/f_htree_bad_csum/expect.1 [new file with mode: 0644]
tests/f_htree_bad_csum/expect.2 [new file with mode: 0644]
tests/f_htree_bad_csum/image.gz [new file with mode: 0644]
tests/f_htree_bad_csum/name [new file with mode: 0644]
tests/f_idata_and_extents/expect.1 [new file with mode: 0644]
tests/f_idata_and_extents/expect.2 [new file with mode: 0644]
tests/f_idata_and_extents/image.gz [new file with mode: 0644]
tests/f_idata_and_extents/name [new file with mode: 0644]
tests/f_inlinedata_repair/expect.1 [new file with mode: 0644]
tests/f_inlinedata_repair/expect.2 [new file with mode: 0644]
tests/f_inlinedata_repair/image.gz [new file with mode: 0644]
tests/f_inlinedata_repair/name [new file with mode: 0644]
tests/f_inode_ea_collision/expect.1 [new file with mode: 0644]
tests/f_inode_ea_collision/expect.2 [new file with mode: 0644]
tests/f_inode_ea_collision/image.gz [new file with mode: 0644]
tests/f_inode_ea_collision/name [new file with mode: 0644]
tests/f_itable_collision/expect.1 [new file with mode: 0644]
tests/f_itable_collision/expect.2 [new file with mode: 0644]
tests/f_itable_collision/image.gz [new file with mode: 0644]
tests/f_itable_collision/name [new file with mode: 0644]
tests/f_itable_collision/script [new file with mode: 0755]
tests/f_jnl_64bit/expect.0
tests/f_no_cache_corrupt_inode/expect.1 [new file with mode: 0644]
tests/f_no_cache_corrupt_inode/expect.2 [new file with mode: 0644]
tests/f_no_cache_corrupt_inode/image.gz [new file with mode: 0644]
tests/f_no_cache_corrupt_inode/name [new file with mode: 0644]
tests/f_nospc_create_lnf/expect.1 [new file with mode: 0644]
tests/f_nospc_create_lnf/expect.2 [new file with mode: 0644]
tests/f_nospc_create_lnf/image.gz [new file with mode: 0644]
tests/f_nospc_create_lnf/name [new file with mode: 0644]
tests/f_rebuild_csum_rootdir/expect.1 [new file with mode: 0644]
tests/f_rebuild_csum_rootdir/expect.2 [new file with mode: 0644]
tests/f_rebuild_csum_rootdir/image.gz [new file with mode: 0644]
tests/f_rebuild_csum_rootdir/name [new file with mode: 0644]
tests/f_super_bad_csum/expect.1 [new file with mode: 0644]
tests/f_super_bad_csum/expect.2 [new file with mode: 0644]
tests/f_super_bad_csum/image.bz2 [new file with mode: 0644]
tests/f_super_bad_csum/name [new file with mode: 0644]
tests/f_super_bad_csum/script [new file with mode: 0755]
tests/filter.sed
tests/m_mmp_bad_csum/expect [new file with mode: 0644]
tests/m_mmp_bad_csum/image.gz [new file with mode: 0644]
tests/m_mmp_bad_csum/name [new file with mode: 0644]
tests/m_mmp_bad_csum/script [new file with mode: 0644]
tests/m_mmp_bad_magic/.log [new file with mode: 0644]
tests/m_mmp_bad_magic/expect [new file with mode: 0644]
tests/m_mmp_bad_magic/image.gz [new file with mode: 0644]
tests/m_mmp_bad_magic/name [new file with mode: 0644]
tests/m_mmp_bad_magic/script [new file with mode: 0644]
tests/progs/Makefile.in
tests/r_inline_xattr/expect
tests/t_mke2fs_errors/expect [new file with mode: 0644]
tests/t_mke2fs_errors/script [new file with mode: 0755]
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 ac0fd2b..baf9b1a 100644 (file)
@@ -154,6 +154,7 @@ misc/dumpe2fs
 misc/dumpe2fs.8
 misc/e2freefrag
 misc/e2freefrag.8
+misc/e2fuzz
 misc/e2image
 misc/e2image.8
 misc/e2initrd_helper
index 7393379..97758f3 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 cdbfe17..dad9970 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.11 (July 9, 2014)
 ================================
 
index b9ce43d..65449c9 100755 (executable)
--- a/configure
+++ b/configure
@@ -879,6 +879,9 @@ enable_fsck
 enable_e2initrd_helper
 enable_tls
 enable_uuidd
+enable_mmp
+enable_bmap_stats
+enable_bmap_stats_ops
 enable_nls
 enable_threads
 with_gnu_ld
@@ -1539,6 +1542,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
   --enable-threads={posix|solaris|pth|windows}
                           specify multithreading API
@@ -5982,6 +5988,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
@@ -12327,7 +12404,7 @@ fi
 done
 
 fi
-for ac_header in       dirent.h        errno.h         execinfo.h      getopt.h        malloc.h        mntent.h        paths.h         semaphore.h     setjmp.h        signal.h        stdarg.h        stdint.h        stdlib.h        termios.h       termio.h        unistd.h        utime.h         linux/falloc.h  linux/fd.h      linux/major.h   linux/loop.h    net/if_dl.h     netinet/in.h    sys/disklabel.h         sys/disk.h      sys/file.h      sys/ioctl.h     sys/mkdev.h     sys/mman.h      sys/mount.h     sys/prctl.h     sys/resource.h  sys/select.h    sys/socket.h    sys/sockio.h    sys/stat.h      sys/syscall.h   sys/sysmacros.h         sys/time.h      sys/types.h     sys/un.h        sys/wait.h
+for ac_header in       dirent.h        errno.h         execinfo.h      getopt.h        malloc.h        mntent.h        paths.h         semaphore.h     setjmp.h        signal.h        stdarg.h        stdint.h        stdlib.h        termios.h       termio.h        unistd.h        utime.h         attr/xattr.h    linux/falloc.h  linux/fd.h      linux/major.h   linux/loop.h    net/if_dl.h     netinet/in.h    sys/disklabel.h         sys/disk.h      sys/file.h      sys/ioctl.h     sys/mkdev.h     sys/mman.h      sys/mount.h     sys/prctl.h     sys/resource.h  sys/select.h    sys/socket.h    sys/sockio.h    sys/stat.h      sys/syscall.h   sys/sysmacros.h         sys/time.h      sys/types.h     sys/un.h        sys/wait.h
 do :
   as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
 ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
@@ -12994,7 +13071,7 @@ if test "$ac_res" != no; then :
 fi
 
 fi
-for ac_func in         __secure_getenv         backtrace       blkid_probe_get_topology        blkid_probe_enable_partitions   chflags         fadvise64       fallocate       fallocate64     fchown  fdatasync       fstat64         ftruncate64     futimes         getcwd  getdtablesize   getmntinfo      getpwuid_r      getrlimit       getrusage       jrand48         llseek  lseek64         mallinfo        mbstowcs        memalign        mempcpy         mmap    msync   nanosleep       open64  pathconf        posix_fadvise   posix_fadvise64         posix_memalign  prctl   pread   pwrite  pread64         pwrite64        secure_getenv   setmntent       setresgid       setresuid       snprintf        srandom         stpcpy  strcasecmp      strdup  strnlen         strptime        strtoull        sync_file_range         sysconf         usleep  utime   valloc
+for ac_func in         __secure_getenv         backtrace       blkid_probe_get_topology        blkid_probe_enable_partitions   chflags         fadvise64       fallocate       fallocate64     fchown  fdatasync       fstat64         ftruncate64     futimes         getcwd  getdtablesize   getmntinfo      getpwuid_r      getrlimit       getrusage       jrand48         llistxattr      llseek  lseek64         mallinfo        mbstowcs        memalign        mempcpy         mmap    msync   nanosleep       open64  pathconf        posix_fadvise   posix_fadvise64         posix_memalign  prctl   pread   pwrite  pread64         pwrite64        secure_getenv   setmntent       setresgid       setresuid       snprintf        srandom         stpcpy  strcasecmp      strdup  strnlen         strptime        strtoull        sync_file_range         sysconf         usleep  utime   valloc
 do :
   as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
 ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
index 2e59fde..97a58c5 100644 (file)
@@ -788,6 +788,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
@@ -866,6 +920,7 @@ AC_CHECK_HEADERS(m4_flatten([
        termio.h
        unistd.h
        utime.h
+       attr/xattr.h
        linux/falloc.h
        linux/fd.h
        linux/major.h
@@ -1044,6 +1099,7 @@ AC_CHECK_FUNCS(m4_flatten([
        getrlimit
        getrusage
        jrand48
+       llistxattr
        llseek
        lseek64
        mallinfo
index f01607b..87aefdc 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.10-1)
+
+ -- Theodore Y. Ts'o <tytso@mit.edu>  Wed, 04 Feb 2014 23:31:56 -0500
+
 e2fsprogs (1.42.11-2) unstable; urgency=low
 
   * Don't try to build lib/ext2fs/tst_ext2fs unless running "make
@@ -271,6 +277,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 1c76912..2c43f57 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
@@ -123,7 +127,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
@@ -143,14 +149,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
@@ -251,6 +265,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
@@ -301,12 +316,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
@@ -339,11 +361,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
@@ -355,6 +380,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
@@ -383,8 +409,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
@@ -421,6 +449,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
@@ -517,6 +547,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
@@ -525,8 +556,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 3dd06f0..0f23595 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 ed3728f..5bd3fe1 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, bdump, 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 bae14db..7934f13 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
@@ -387,7 +392,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
@@ -418,11 +423,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 00c2d38..6366465 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;
 
@@ -373,8 +361,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, "
@@ -506,27 +493,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)),
@@ -544,34 +510,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)
@@ -720,6 +658,56 @@ 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\n", prefix, size);
+}
+
+static void dump_fast_link(FILE *out, ext2_ino_t inode_num,
+                          struct ext2_inode *inode, const char *prefix)
+{
+       errcode_t retval = 0;
+       char *buf;
+       size_t size;
+
+       if (inode->i_flags & EXT4_INLINE_DATA_FL) {
+               retval = ext2fs_inline_data_size(current_fs, inode_num, &size);
+               if (retval)
+                       goto out;
+
+               retval = ext2fs_get_memzero(size + 1, &buf);
+               if (retval)
+                       goto out;
+
+               retval = ext2fs_inline_data_get(current_fs, inode_num,
+                                               inode, buf, &size);
+               if (retval)
+                       goto out;
+               fprintf(out, "%sFast link dest: \"%.*s\"\n", prefix,
+                       (int)size, buf);
+
+               retval = ext2fs_free_mem(&buf);
+               if (retval)
+                       goto out;
+       } else {
+               int sz = EXT2_I_SIZE(inode);
+
+               if (sz > sizeof(inode->i_block))
+                       sz = sizeof(inode->i_block);
+               fprintf(out, "%sFast link dest: \"%.*s\"\n", prefix, sz,
+                       (char *)inode->i_block);
+       }
+out:
+       if (retval)
+               com_err(__func__, retval, "while dumping link destination");
 }
 
 void internal_dump_inode(FILE *out, const char *prefix,
@@ -819,9 +807,23 @@ void internal_dump_inode(FILE *out, const char *prefix,
        if (EXT2_INODE_SIZE(current_fs->super) > EXT2_GOOD_OLD_INODE_SIZE)
                internal_dump_inode_extra(out, prefix, inode_num,
                                          (struct ext2_inode_large *) inode);
-       if (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);
+       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)
+               dump_fast_link(out, inode_num, inode, prefix);
        else if (LINUX_S_ISBLK(inode->i_mode) || LINUX_S_ISCHR(inode->i_mode)) {
                int major, minor;
                const char *devnote;
@@ -842,6 +844,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);
        }
@@ -1576,195 +1580,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, close_ret;
-       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");
-               goto out_close;
-       }
-
-       /* 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 zero buffer\n");
-               goto out_free_buf;
-       }
-
-       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;
-               }
-       }
-
-fail:
-       ext2fs_free_mem(&zero_buf);
-out_free_buf:
-       ext2fs_free_mem(&buf);
-out_close:
-       close_ret = ext2fs_file_close(e2_file);
-       if (retval == 0)
-               retval = close_ret;
-       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;
-       retval = ext2fs_inode_size_set(current_fs, &inode, statbuf.st_size);
-       if (retval) {
-               com_err(argv[2], retval, 0);
-               close(fd);
-               return;
-       }
-       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;
@@ -1773,115 +1607,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);
 
 }
 
@@ -1907,11 +1678,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));
@@ -1978,9 +1748,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;
@@ -2309,49 +2079,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 mmp_struct *mmp_s;
        time_t t;
        errcode_t retval = 0;
@@ -2387,6 +2129,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)
@@ -2451,9 +2198,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)
@@ -2480,6 +2227,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 0e75cee..6eb5732 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 8d97886..1dc6154 100644 (file)
@@ -312,7 +312,7 @@ static int rdump_dirent(struct ext2_dir_entry *dirent,
        const char *dumproot = private;
        struct ext2_inode inode;
 
-       thislen = dirent->name_len & 0xFF;
+       thislen = ext2fs_dirent_name_len(dirent);
        strncpy(name, dirent->name, thislen);
        name[thislen] = 0;
 
index 0adea40..49345ad 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 24f8250..4f0118d 100644 (file)
@@ -44,6 +44,11 @@ static void htree_dump_leaf_node(ext2_filsys fs, ext2_ino_t ino,
        ext2_dirhash_t  hash, minor_hash;
        unsigned int    rec_len;
        int             hash_alg;
+       int             csum_size = 0;
+
+       if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+                                      EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
+               csum_size = sizeof(struct ext2_dir_entry_tail);
 
        errcode = ext2fs_bmap2(fs, ino, inode, buf, 0, blk, 0, &pblk);
        if (errcode) {
@@ -53,7 +58,7 @@ static void htree_dump_leaf_node(ext2_filsys fs, ext2_ino_t ino,
        }
 
        fprintf(pager, "Reading directory block %llu, phys %llu\n", blk, pblk);
-       errcode = ext2fs_read_dir_block2(current_fs, pblk, buf, 0);
+       errcode = ext2fs_read_dir_block4(current_fs, pblk, buf, 0, ino);
        if (errcode) {
                com_err("htree_dump_leaf_node", errcode,
                        "while reading block %llu (%llu)\n",
@@ -74,15 +79,15 @@ static void htree_dump_leaf_node(ext2_filsys fs, ext2_ino_t ino,
                                (unsigned long) blk);
                        return;
                }
+               thislen = ext2fs_dirent_name_len(dirent);
                if (((offset + rec_len) > fs->blocksize) ||
                    (rec_len < 8) ||
                    ((rec_len % 4) != 0) ||
-                   ((((unsigned) dirent->name_len & 0xFF)+8) > rec_len)) {
+                   (thislen + 8 > rec_len)) {
                        fprintf(pager, "Corrupted directory block (%llu)!\n",
                                blk);
                        break;
                }
-               thislen = dirent->name_len & 0xFF;
                strncpy(name, dirent->name, thislen);
                name[thislen] = '\0';
                errcode = ext2fs_dirhash(hash_alg, name,
@@ -91,8 +96,23 @@ static void htree_dump_leaf_node(ext2_filsys fs, ext2_ino_t ino,
                if (errcode)
                        com_err("htree_dump_leaf_node", errcode,
                                "while calculating hash");
-               snprintf(tmp, EXT2_NAME_LEN + 64, "%u 0x%08x-%08x (%d) %s   ",
-                       dirent->inode, hash, minor_hash, rec_len, name);
+               if ((offset == fs->blocksize - csum_size) &&
+                   (dirent->inode == 0) &&
+                   (dirent->rec_len == csum_size) &&
+                   (dirent->name_len == EXT2_DIR_NAME_LEN_CSUM)) {
+                       struct ext2_dir_entry_tail *t;
+
+                       t = (struct ext2_dir_entry_tail *) dirent;
+
+                       snprintf(tmp, EXT2_NAME_LEN + 64,
+                                "leaf block checksum: 0x%08x  ",
+                                t->det_checksum);
+               } else {
+                       snprintf(tmp, EXT2_NAME_LEN + 64,
+                                "%u 0x%08x-%08x (%d) %s   ",
+                                dirent->inode, hash, minor_hash,
+                                rec_len, name);
+               }
                thislen = strlen(tmp);
                if (col + thislen > 80) {
                        fprintf(pager, "\n");
@@ -120,8 +140,9 @@ static void htree_dump_int_node(ext2_filsys fs, ext2_ino_t ino,
 {
        struct ext2_dx_countlimit       limit;
        struct ext2_dx_entry            e;
+       struct ext2_dx_tail             *tail;
        int                             hash, i;
-
+       int                             remainder;
 
        limit = *((struct ext2_dx_countlimit *) ent);
        limit.count = ext2fs_le16_to_cpu(limit.count);
@@ -130,6 +151,20 @@ static void htree_dump_int_node(ext2_filsys fs, ext2_ino_t ino,
        fprintf(pager, "Number of entries (count): %d\n", limit.count);
        fprintf(pager, "Number of entries (limit): %d\n", limit.limit);
 
+       remainder = fs->blocksize - (limit.limit *
+                                    sizeof(struct ext2_dx_entry));
+       if (ent == (struct ext2_dx_entry *)(rootnode + 1))
+               remainder -= sizeof(struct ext2_dx_root_info) + 24;
+       else
+               remainder -= 8;
+       if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+                                      EXT4_FEATURE_RO_COMPAT_METADATA_CSUM) &&
+           remainder == sizeof(struct ext2_dx_tail)) {
+               tail = (struct ext2_dx_tail *)(ent + limit.limit);
+               fprintf(pager, "Checksum: 0x%08x\n",
+                       ext2fs_le32_to_cpu(tail->dt_checksum));
+       }
+
        for (i=0; i < limit.count; i++) {
                hash = i ? ext2fs_le32_to_cpu(ent[i].hash) : 0;
                fprintf(pager, "Entry #%d: Hash 0x%08x%s, block %u\n", i,
@@ -393,7 +428,7 @@ static int search_dir_block(ext2_filsys fs, blk64_t *blocknr,
                        return BLOCK_ABORT;
                }
                if (dirent->inode &&
-                   p->len == (dirent->name_len & 0xFF) &&
+                   p->len == ext2fs_dirent_name_len(dirent) &&
                    strncmp(p->search_name, dirent->name,
                            p->len) == 0) {
                        printf("Entry found at logical block %lld, "
index d2c3b30..9f9594f 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 b4036de..69c7897 100644 (file)
@@ -30,8 +30,7 @@ extern char *optarg;
  */
 
 #define LONG_OPT       0x0001
-#define DELETED_OPT    0x0002
-#define PARSE_OPT      0x0004
+#define PARSE_OPT      0x0002
 
 struct list_dir_struct {
        FILE    *f;
@@ -60,8 +59,9 @@ static int list_dir_proc(ext2_ino_t dir EXT2FS_ATTR((unused)),
        char                    lbr, rbr;
        int                     thislen;
        struct list_dir_struct *ls = (struct list_dir_struct *) private;
+       struct ext2_dir_entry_tail *t = (struct ext2_dir_entry_tail *) dirent;
 
-       thislen = dirent->name_len & 0xFF;
+       thislen = ext2fs_dirent_name_len(dirent);
        strncpy(name, dirent->name, thislen);
        name[thislen] = '\0';
        ino = dirent->inode;
@@ -99,8 +99,14 @@ static int list_dir_proc(ext2_ino_t dir EXT2FS_ATTR((unused)),
                        strcpy(datestr, "                 ");
                        memset(&inode, 0, sizeof(struct ext2_inode));
                }
-               fprintf(ls->f, "%c%6u%c %6o (%d)  %5d  %5d   ", lbr, ino, rbr,
-                       inode.i_mode, dirent->name_len >> 8,
+               fprintf(ls->f, "%c%6u%c %6o ", lbr, ino, rbr, inode.i_mode);
+               if (entry == DIRENT_CHECKSUM) {
+                       fprintf(ls->f, "(dirblock checksum: 0x%08x)\n",
+                               t->det_checksum);
+                       return 0;
+               }
+               fprintf(ls->f, "(%d)  %5d  %5d   ",
+                       ext2fs_dirent_file_type(dirent),
                        inode_uid(inode), inode_gid(inode));
                if (LINUX_S_ISDIR(inode.i_mode))
                        fprintf(ls->f, "%5d", inode.i_size);
@@ -108,8 +114,13 @@ static int list_dir_proc(ext2_ino_t dir EXT2FS_ATTR((unused)),
                        fprintf(ls->f, "%5llu", EXT2_I_SIZE(&inode));
                fprintf (ls->f, " %s %s\n", datestr, name);
        } else {
-               sprintf(tmp, "%c%u%c (%d) %s   ", lbr, dirent->inode, rbr,
-                       dirent->rec_len, name);
+               if (entry == DIRENT_CHECKSUM)
+                       sprintf(tmp, "%c%u%c (dirblock checksum: 0x%08x)   ",
+                               lbr, dirent->inode, rbr, t->det_checksum);
+               else
+                       sprintf(tmp, "%c%u%c (%d) %s   ",
+                               lbr, dirent->inode, rbr,
+                               dirent->rec_len, name);
                thislen = strlen(tmp);
 
                if (ls->col + thislen > 80) {
@@ -127,7 +138,7 @@ void do_list_dir(int argc, char *argv[])
        ext2_ino_t      inode;
        int             retval;
        int             c;
-       int             flags;
+       int             flags = DIRENT_FLAG_INCLUDE_EMPTY;
        struct list_dir_struct ls;
 
        ls.options = 0;
@@ -135,13 +146,16 @@ void do_list_dir(int argc, char *argv[])
                return;
 
        reset_getopt();
-       while ((c = getopt (argc, argv, "dlp")) != EOF) {
+       while ((c = getopt (argc, argv, "cdlp")) != EOF) {
                switch (c) {
+               case 'c':
+                       flags |= DIRENT_FLAG_INCLUDE_CSUM;
+                       break;
                case 'l':
                        ls.options |= LONG_OPT;
                        break;
                case 'd':
-                       ls.options |= DELETED_OPT;
+                       flags |= DIRENT_FLAG_INCLUDE_REMOVED;
                        break;
                case 'p':
                        ls.options |= PARSE_OPT;
@@ -166,9 +180,6 @@ void do_list_dir(int argc, char *argv[])
 
        ls.f = open_pager();
        ls.col = 0;
-       flags = DIRENT_FLAG_INCLUDE_EMPTY;
-       if (ls.options & DELETED_OPT)
-               flags |= DIRENT_FLAG_INCLUDE_REMOVED;
 
        retval = ext2fs_dir_iterate2(current_fs, inode, flags,
                                    0, list_dir_proc, &ls);
index e5b2d20..a7c30b3 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 58f3a50..5d9b5d2 100644 (file)
@@ -45,7 +45,7 @@ static int ncheck_proc(struct ext2_dir_entry *dirent,
        struct inode_walk_struct *iw = (struct inode_walk_struct *) private;
        struct ext2_inode inode;
        errcode_t       retval;
-       int             filetype = dirent->name_len >> 8;
+       int             filetype = ext2fs_dirent_file_type(dirent);
        int             i;
 
        iw->position++;
@@ -66,11 +66,13 @@ static int ncheck_proc(struct ext2_dir_entry *dirent,
                        if (iw->parent)
                                printf("%u\t%s/%.*s", iw->iarray[i],
                                       iw->parent,
-                                      (dirent->name_len & 0xFF), dirent->name);
+                                      ext2fs_dirent_name_len(dirent),
+                                      dirent->name);
                        else
                                printf("%u\t<%u>/%.*s", iw->iarray[i],
                                       iw->dir,
-                                      (dirent->name_len & 0xFF), dirent->name);
+                                      ext2fs_dirent_name_len(dirent),
+                                      dirent->name);
                        if (iw->check_dirent && filetype) {
                                if (!debugfs_read_inode(dirent->inode, &inode,
                                                        "ncheck") &&
index 40dc5e7..c5f865e 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 },
        { "error_count", &set_sb.s_error_count, NULL, 4, parse_uint },
        { "first_error_time", &set_sb.s_first_error_time, NULL, 4, parse_time },
        { "first_error_ino", &set_sb.s_first_error_ino, NULL, 4, parse_uint },
@@ -268,6 +269,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)
@@ -783,6 +785,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.";
@@ -837,5 +840,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 20c6c61..6c48fba 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..1c19b2f
--- /dev/null
@@ -0,0 +1,306 @@
+/*
+ * 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));
+       if (strcmp(name, "system.data") != 0) {
+               fprintf(out, " = \"");
+               dump_xattr_string(out, value, value_len);
+               fprintf(out, "\"");
+       }
+       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':
+                       if (fp)
+                               fclose(fp);
+                       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':
+                       if (fp)
+                               fclose(fp);
+                       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 9a2f8f5..c40b188 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 $<
 
 #
@@ -57,7 +58,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 \
@@ -71,12 +72,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 \
@@ -127,15 +126,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) \
@@ -147,10 +137,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 \
@@ -167,10 +153,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
@@ -267,9 +252,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
@@ -288,20 +272,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 0ec1540..fcda7d7 100644 (file)
@@ -108,6 +108,10 @@ errcode_t e2fsck_reset_context(e2fsck_t ctx)
                ext2fs_free_block_bitmap(ctx->block_ea_map);
                ctx->block_ea_map = 0;
        }
+       if (ctx->block_metadata_map) {
+               ext2fs_free_block_bitmap(ctx->block_metadata_map);
+               ctx->block_metadata_map = 0;
+       }
        if (ctx->inode_bb_map) {
                ext2fs_free_inode_bitmap(ctx->inode_bb_map);
                ctx->inode_bb_map = 0;
index f904026..8f16218 100644 (file)
@@ -377,6 +377,7 @@ struct e2fsck_struct {
         * e2fsck functions themselves.
         */
        void *priv_data;
+       ext2fs_block_bitmap block_metadata_map; /* Metadata blocks */
 };
 
 /* Used by the region allocation code */
@@ -410,9 +411,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);
@@ -499,6 +497,8 @@ extern void region_free(region_t region);
 extern int region_allocate(region_t region, region_addr_t start, int n);
 
 /* rehash.c */
+void e2fsck_rehash_dir_later(e2fsck_t ctx, ext2_ino_t ino);
+int e2fsck_dir_will_be_rehashed(e2fsck_t ctx, ext2_ino_t ino);
 errcode_t e2fsck_rehash_dir(e2fsck_t ctx, ext2_ino_t ino);
 void e2fsck_rehash_directories(e2fsck_t ctx);
 
diff --git a/e2fsck/gen_crc32table.c b/e2fsck/gen_crc32table.c
deleted file mode 100644 (file)
index 2c1aa8e..0000000
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * gen_crc32table.c --- Generate CRC32 tables.
- *
- * Copyright (C) 2008 Theodore Ts'o.
- *
- * %Begin-Header%
- * This file may be redistributed under the terms of the GNU Public
- * License.
- * %End-Header%
- */
-
-#include <stdio.h>
-#include "crc32defs.h"
-#include <inttypes.h>
-
-#define ENTRIES_PER_LINE 4
-
-#define LE_TABLE_SIZE (1 << CRC_LE_BITS)
-#define BE_TABLE_SIZE (1 << CRC_BE_BITS)
-
-static uint32_t crc32table_le[LE_TABLE_SIZE];
-static uint32_t crc32table_be[BE_TABLE_SIZE];
-
-/**
- * crc32init_le() - allocate and initialize LE table data
- *
- * crc is the crc of the byte i; other entries are filled in based on the
- * fact that crctable[i^j] = crctable[i] ^ crctable[j].
- *
- */
-static void crc32init_le(void)
-{
-       unsigned i, j;
-       uint32_t crc = 1;
-
-       crc32table_le[0] = 0;
-
-       for (i = 1 << (CRC_LE_BITS - 1); i; i >>= 1) {
-               crc = (crc >> 1) ^ ((crc & 1) ? CRCPOLY_LE : 0);
-               for (j = 0; j < LE_TABLE_SIZE; j += 2 * i)
-                       crc32table_le[i + j] = crc ^ crc32table_le[j];
-       }
-}
-
-/**
- * crc32init_be() - allocate and initialize BE table data
- */
-static void crc32init_be(void)
-{
-       unsigned i, j;
-       uint32_t crc = 0x80000000;
-
-       crc32table_be[0] = 0;
-
-       for (i = 1; i < BE_TABLE_SIZE; i <<= 1) {
-               crc = (crc << 1) ^ ((crc & 0x80000000) ? CRCPOLY_BE : 0);
-               for (j = 0; j < i; j++)
-                       crc32table_be[i + j] = crc ^ crc32table_be[j];
-       }
-}
-
-static void output_table(uint32_t table[], int len, const char *trans)
-{
-       int i;
-
-       for (i = 0; i < len - 1; i++) {
-               if (i % ENTRIES_PER_LINE == 0)
-                       printf("\n");
-               printf("%s(0x%8.8xL), ", trans, table[i]);
-       }
-       printf("%s(0x%8.8xL)\n", trans, table[len - 1]);
-}
-
-#ifdef __GNUC__
-#define ATTR(x) __attribute__(x)
-#else
-#define ATTR(x)
-#endif
-
-int main(int argc ATTR((unused)), char** argv ATTR((unused)))
-{
-       printf("/* this file is generated - do not edit */\n\n");
-
-       printf("#ifdef UNITTEST\n");
-       if (CRC_LE_BITS > 1) {
-               crc32init_le();
-               printf("static const __u32 crc32table_le[] = {");
-               output_table(crc32table_le, LE_TABLE_SIZE, "tole");
-               printf("};\n");
-       }
-       printf("#endif /* UNITTEST */\n");
-
-       if (CRC_BE_BITS > 1) {
-               crc32init_be();
-               printf("static const __u32 crc32table_be[] = {");
-               output_table(crc32table_be, BE_TABLE_SIZE, "tobe");
-               printf("};\n");
-       }
-
-       return 0;
-}
index bfc1bcd..3cccd3f 100644 (file)
@@ -115,17 +115,6 @@ _INLINE_ void do_cache_destroy(lkmem_cache_t *cache)
        free(cache);
 }
 
-/*
- * helper functions to deal with 32 or 64bit block numbers.
- */
-_INLINE_ size_t journal_tag_bytes(journal_t *journal)
-{
-       if (JFS_HAS_INCOMPAT_FEATURE(journal, JFS_FEATURE_INCOMPAT_64BIT))
-               return JBD_TAG_SIZE64;
-       else
-               return JBD_TAG_SIZE32;
-}
-
 #undef _INLINE_
 #endif
 
index 3b40e00..206685a 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.
@@ -573,6 +623,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. */
@@ -640,6 +699,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);
@@ -680,6 +740,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);
@@ -824,6 +885,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 97f53fa..9c1433f 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 50a8b99..a473bd7 100644 (file)
@@ -93,6 +93,7 @@ struct process_block_struct {
        struct problem_context *pctx;
        ext2fs_block_bitmap fs_meta_blocks;
        e2fsck_t        ctx;
+       blk64_t         bad_ref;
 };
 
 struct process_inode_block {
@@ -182,6 +183,8 @@ int e2fsck_pass1_check_symlink(ext2_filsys fs, ext2_ino_t ino,
                return 0;
 
        if (inode->i_flags & EXT4_EXTENTS_FL) {
+               if (inode->i_flags & EXT4_INLINE_DATA_FL)
+                       return 0;
                if (inode->i_size > fs->blocksize)
                        return 0;
                if (ext2fs_extent_open2(fs, ino, inode, &handle))
@@ -203,8 +206,21 @@ int e2fsck_pass1_check_symlink(ext2_filsys fs, ext2_ino_t ino,
                return i;
        }
 
+       if (inode->i_flags & EXT4_INLINE_DATA_FL) {
+               size_t inline_size;
+
+               if (ext2fs_inline_data_size(fs, ino, &inline_size))
+                       return 0;
+               if (inode->i_size != inline_size)
+                       return 0;
+
+               return 1;
+       }
+
        blocks = ext2fs_inode_data_blocks2(fs, inode);
        if (blocks) {
+               if (inode->i_flags & EXT4_INLINE_DATA_FL)
+                       return 0;
                if ((inode->i_size >= fs->blocksize) ||
                    (blocks != fs->blocksize >> 9) ||
                    (inode->i_block[0] < fs->super->s_first_data_block) ||
@@ -221,6 +237,27 @@ int e2fsck_pass1_check_symlink(ext2_filsys fs, ext2_ino_t ino,
                len = strnlen(buf, fs->blocksize);
                if (len == fs->blocksize)
                        return 0;
+       } else if (inode->i_flags & EXT4_INLINE_DATA_FL) {
+               char *inline_buf = NULL;
+               size_t inline_sz = 0;
+
+               if (ext2fs_inline_data_size(fs, ino, &inline_sz))
+                       return 0;
+               if (inode->i_size != inline_sz)
+                       return 0;
+               if (ext2fs_get_mem(inline_sz + 1, &inline_buf))
+                       return 0;
+               i = 0;
+               if (ext2fs_inline_data_get(fs, ino, inode, inline_buf, NULL))
+                       goto exit_inline;
+               inline_buf[inline_sz] = 0;
+               len = strnlen(inline_buf, inline_sz);
+               if (len != inline_sz)
+                       goto exit_inline;
+               i = 1;
+exit_inline:
+               ext2fs_free_mem(&inline_buf);
+               return i;
        } else {
                if (inode->i_size >= sizeof(inode->i_block))
                        return 0;
@@ -235,6 +272,24 @@ int e2fsck_pass1_check_symlink(ext2_filsys fs, ext2_ino_t ino,
 }
 
 /*
+ * If the extents or inlinedata flags are set on the inode, offer to clear 'em.
+ */
+#define BAD_SPECIAL_FLAGS (EXT4_EXTENTS_FL | EXT4_INLINE_DATA_FL)
+static void check_extents_inlinedata(e2fsck_t ctx,
+                                    struct problem_context *pctx)
+{
+       if (!(pctx->inode->i_flags & BAD_SPECIAL_FLAGS))
+               return;
+
+       if (!fix_problem(ctx, PR_1_SPECIAL_EXTENTS_IDATA, pctx))
+               return;
+
+       pctx->inode->i_flags &= ~BAD_SPECIAL_FLAGS;
+       e2fsck_write_inode(ctx, pctx->ino, pctx->inode, "pass1");
+}
+#undef BAD_SPECIAL_FLAGS
+
+/*
  * If the immutable (or append-only) flag is set on the inode, offer
  * to clear it.
  */
@@ -274,15 +329,17 @@ static void check_ea_in_inode(e2fsck_t ctx, struct problem_context *pctx)
        struct ext2_super_block *sb = ctx->fs->super;
        struct ext2_inode_large *inode;
        struct ext2_ext_attr_entry *entry;
-       char *start;
+       char *start, *header;
        unsigned int storage_size, remain;
        problem_t problem = 0;
+       region_t region = 0;
 
        inode = (struct ext2_inode_large *) pctx->inode;
        storage_size = EXT2_INODE_SIZE(ctx->fs->super) - EXT2_GOOD_OLD_INODE_SIZE -
                inode->i_extra_isize;
-       start = ((char *) inode) + EXT2_GOOD_OLD_INODE_SIZE +
-               inode->i_extra_isize + sizeof(__u32);
+       header = ((char *) inode) + EXT2_GOOD_OLD_INODE_SIZE +
+                inode->i_extra_isize;
+       start = header + sizeof(__u32);
        entry = (struct ext2_ext_attr_entry *) start;
 
        /* scan all entry's headers first */
@@ -290,9 +347,28 @@ static void check_ea_in_inode(e2fsck_t ctx, struct problem_context *pctx)
        /* take finish entry 0UL into account */
        remain = storage_size - sizeof(__u32);
 
-       while (!EXT2_EXT_IS_LAST_ENTRY(entry)) {
+       region = region_create(0, storage_size);
+       if (!region) {
+               fix_problem(ctx, PR_1_EA_ALLOC_REGION_ABORT, pctx);
+               problem = 0;
+               ctx->flags |= E2F_FLAG_ABORT;
+               return;
+       }
+       if (region_allocate(region, 0, sizeof(__u32))) {
+               problem = PR_1_INODE_EA_ALLOC_COLLISION;
+               goto fix;
+       }
+
+       while (remain >= sizeof(struct ext2_ext_attr_entry) &&
+              !EXT2_EXT_IS_LAST_ENTRY(entry)) {
                __u32 hash;
 
+               if (region_allocate(region, (char *)entry - (char *)header,
+                                   EXT2_EXT_ATTR_LEN(entry->e_name_len))) {
+                       problem = PR_1_INODE_EA_ALLOC_COLLISION;
+                       goto fix;
+               }
+
                /* header eats this space */
                remain -= sizeof(struct ext2_ext_attr_entry);
 
@@ -320,6 +396,13 @@ static void check_ea_in_inode(e2fsck_t ctx, struct problem_context *pctx)
                        goto fix;
                }
 
+               if (entry->e_value_size &&
+                   region_allocate(region, sizeof(__u32) + entry->e_value_offs,
+                                   EXT2_EXT_ATTR_SIZE(entry->e_value_size))) {
+                       problem = PR_1_INODE_EA_ALLOC_COLLISION;
+                       goto fix;
+               }
+
                hash = ext2fs_ext_attr_hash_entry(entry,
                                                  start + entry->e_value_offs);
 
@@ -334,7 +417,15 @@ static void check_ea_in_inode(e2fsck_t ctx, struct problem_context *pctx)
 
                entry = EXT2_EXT_ATTR_NEXT(entry);
        }
+
+       if (region_allocate(region, (char *)entry - (char *)header,
+                           sizeof(__u32))) {
+               problem = PR_1_INODE_EA_ALLOC_COLLISION;
+               goto fix;
+       }
 fix:
+       if (region)
+               region_free(region);
        /*
         * it seems like a corruption. it's very unlikely we could repair
         * EA(s) in automatic fashion -bzzz
@@ -343,7 +434,7 @@ fix:
                return;
 
        /* simply remove all possible EA(s) */
-       *((__u32 *)start) = 0UL;
+       *((__u32 *)header) = 0UL;
        e2fsck_write_inode_full(ctx, pctx->ino, pctx->inode,
                                EXT2_INODE_SIZE(sb), "pass1");
 }
@@ -407,6 +498,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 +526,29 @@ 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;
+               /*
+                * If the size isn't a multiple of 4, it's probably not a
+                * directory??
+                */
+               if (size & 3)
+                       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 +583,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 +592,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 +604,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 +651,37 @@ 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));
+       return retval;
+}
+
 static void reserve_block_for_root_repair(e2fsck_t ctx)
 {
        blk64_t         blk = 0;
@@ -576,6 +718,155 @@ static void reserve_block_for_lnf_repair(e2fsck_t ctx)
        ctx->lnf_repair_block = blk;
 }
 
+static errcode_t get_inline_data_ea_size(ext2_filsys fs, ext2_ino_t ino,
+                                        size_t *sz)
+{
+       void *p;
+       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_get(handle, "system.data", &p, sz);
+       if (retval)
+               goto err;
+       ext2fs_free_mem(&p);
+err:
+       (void) ext2fs_xattrs_close(&handle);
+       return retval;
+}
+
+static void finish_processing_inode(e2fsck_t ctx, ext2_ino_t ino,
+                                   struct problem_context *pctx,
+                                   int failed_csum)
+{
+       if (!failed_csum)
+               return;
+
+       /*
+        * 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.
+        */
+       pctx->errcode = recheck_bad_inode_checksum(ctx->fs, ino, ctx, pctx);
+       if (pctx->errcode)
+               ctx->flags |= E2F_FLAG_ABORT;
+}
+#define FINISH_INODE_LOOP(ctx, ino, pctx, failed_csum) \
+       do { \
+               finish_processing_inode((ctx), (ino), (pctx), (failed_csum)); \
+               if ((ctx)->flags & E2F_FLAG_ABORT) \
+                       return; \
+       } while (0)
+
+static int could_be_block_map(ext2_filsys fs, struct ext2_inode *inode)
+{
+       __u32 x;
+       int i;
+
+       for (i = 0; i < EXT2_N_BLOCKS; i++) {
+               x = inode->i_block[i];
+#ifdef WORDS_BIGENDIAN
+               x = ext2fs_swab32(x);
+#endif
+               if (x >= ext2fs_blocks_count(fs->super))
+                       return 0;
+       }
+
+       return 1;
+}
+
+/*
+ * Figure out what to do with an inode that has both extents and inline data
+ * inode flags set.  Returns -1 if we decide to erase the inode, 0 otherwise.
+ */
+static int fix_inline_data_extents_file(e2fsck_t ctx,
+                                       ext2_ino_t ino,
+                                       struct ext2_inode *inode,
+                                       int inode_size,
+                                       struct problem_context *pctx)
+{
+       size_t max_inline_ea_size;
+       ext2_filsys fs = ctx->fs;
+       int dirty = 0;
+
+       /* Both feature flags not set?  Just run the regular checks */
+       if (!EXT2_HAS_INCOMPAT_FEATURE(fs->super,
+                                      EXT3_FEATURE_INCOMPAT_EXTENTS) &&
+           !EXT2_HAS_INCOMPAT_FEATURE(fs->super,
+                                      EXT4_FEATURE_INCOMPAT_INLINE_DATA))
+               return 0;
+
+       /* Clear both flags if it's a special file */
+       if (LINUX_S_ISCHR(inode->i_mode) ||
+           LINUX_S_ISBLK(inode->i_mode) ||
+           LINUX_S_ISFIFO(inode->i_mode) ||
+           LINUX_S_ISSOCK(inode->i_mode)) {
+               check_extents_inlinedata(ctx, pctx);
+               return 0;
+       }
+
+       /* If it looks like an extent tree, try to clear inlinedata */
+       if (ext2fs_extent_header_verify(inode->i_block,
+                                sizeof(inode->i_block)) == 0 &&
+           fix_problem(ctx, PR_1_CLEAR_INLINE_DATA_FOR_EXTENT, pctx)) {
+               inode->i_flags &= ~EXT4_INLINE_DATA_FL;
+               dirty = 1;
+               goto out;
+       }
+
+       /* If it looks short enough to be inline data, try to clear extents */
+       if (EXT2_INODE_SIZE(fs->super) > EXT2_GOOD_OLD_INODE_SIZE)
+               max_inline_ea_size = EXT2_INODE_SIZE(fs->super) -
+                                    (EXT2_GOOD_OLD_INODE_SIZE +
+                                     ((struct ext2_inode_large *)inode)->i_extra_isize);
+       else
+               max_inline_ea_size = 0;
+       if (EXT2_I_SIZE(inode) <
+           EXT4_MIN_INLINE_DATA_SIZE + max_inline_ea_size &&
+           fix_problem(ctx, PR_1_CLEAR_EXTENT_FOR_INLINE_DATA, pctx)) {
+               inode->i_flags &= ~EXT4_EXTENTS_FL;
+               dirty = 1;
+               goto out;
+       }
+
+       /*
+        * Too big for inline data, but no evidence of extent tree -
+        * maybe it's a block map file?  If the mappings all look valid?
+        */
+       if (could_be_block_map(fs, inode) &&
+           fix_problem(ctx, PR_1_CLEAR_EXTENT_INLINE_DATA_FLAGS, pctx)) {
+#ifdef WORDS_BIGENDIAN
+               int i;
+
+               for (i = 0; i < EXT2_N_BLOCKS; i++)
+                       inode->i_block[i] = ext2fs_swab32(inode->i_block[i]);
+#endif
+
+               inode->i_flags &= ~(EXT4_EXTENTS_FL | EXT4_INLINE_DATA_FL);
+               dirty = 1;
+               goto out;
+       }
+
+       /* Oh well, just clear the busted inode. */
+       if (fix_problem(ctx, PR_1_CLEAR_EXTENT_INLINE_DATA_INODE, pctx)) {
+               e2fsck_clear_inode(ctx, ino, inode, 0, "pass1");
+               return -1;
+       }
+
+out:
+       if (dirty)
+               e2fsck_write_inode(ctx, ino, inode, "pass1");
+
+       return 0;
+}
+
 void e2fsck_pass1(e2fsck_t ctx)
 {
        int     i;
@@ -594,9 +885,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);
@@ -627,6 +919,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
@@ -669,6 +963,15 @@ void e2fsck_pass1(e2fsck_t ctx)
                ctx->flags |= E2F_FLAG_ABORT;
                return;
        }
+       pctx.errcode = e2fsck_allocate_block_bitmap(fs,
+                       _("metadata block map"), EXT2FS_BMAP64_RBTREE,
+                       "block_metadata_map", &ctx->block_metadata_map);
+       if (pctx.errcode) {
+               pctx.num = 1;
+               fix_problem(ctx, PR_1_ALLOCATE_BBITMAP_ERROR, &pctx);
+               ctx->flags |= E2F_FLAG_ABORT;
+               return;
+       }
        e2fsck_setup_tdb_icount(ctx, 0, &ctx->inode_link_info);
        if (!ctx->inode_link_info) {
                e2fsck_set_bitmap_type(fs, EXT2FS_BMAP64_RBTREE,
@@ -725,7 +1028,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);
        e2fsck_intercept_block_allocations(ctx);
        old_op = ehandler_operation(_("opening inode scan"));
        pctx.errcode = ext2fs_open_inode_scan(fs, ctx->inode_buffer_blocks,
@@ -736,7 +1040,8 @@ void e2fsck_pass1(e2fsck_t ctx)
                ctx->flags |= E2F_FLAG_ABORT;
                goto endit;
        }
-       ext2fs_inode_scan_flags(scan, EXT2_SF_SKIP_MISSING_ITABLE, 0);
+       ext2fs_inode_scan_flags(scan, EXT2_SF_SKIP_MISSING_ITABLE |
+                                     EXT2_SF_WARN_GARBAGE_INODES, 0);
        ctx->stashed_inode = inode;
        scan_struct.ctx = ctx;
        scan_struct.block_buf = block_buf;
@@ -756,6 +1061,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))
@@ -774,7 +1082,9 @@ 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 &&
+                   pctx.errcode != EXT2_ET_INODE_IS_GARBAGE) {
                        fix_problem(ctx, PR_1_ISCAN_ERROR, &pctx);
                        ctx->flags |= E2F_FLAG_ABORT;
                        goto endit;
@@ -784,6 +1094,16 @@ void e2fsck_pass1(e2fsck_t ctx)
                pctx.ino = ino;
                pctx.inode = inode;
                ctx->stashed_ino = ino;
+
+               /* Clear trashed inode? */
+               if (pctx.errcode == EXT2_ET_INODE_IS_GARBAGE &&
+                   inode->i_links_count > 0 &&
+                   fix_problem(ctx, PR_1_INODE_IS_GARBAGE, &pctx)) {
+                       pctx.errcode = 0;
+                       e2fsck_clear_inode(ctx, ino, inode, 0, "pass1");
+               }
+               failed_csum = pctx.errcode != 0;
+
                if (inode->i_links_count) {
                        pctx.errcode = ext2fs_icount_store(ctx->inode_link_info,
                                           ino, inode->i_links_count);
@@ -795,6 +1115,93 @@ void e2fsck_pass1(e2fsck_t ctx)
                        }
                }
 
+               /* Conflicting inlinedata/extents inode flags? */
+               if ((inode->i_flags & EXT4_INLINE_DATA_FL) &&
+                   (inode->i_flags & EXT4_EXTENTS_FL)) {
+                       int res = fix_inline_data_extents_file(ctx, ino, inode,
+                                                              inode_size,
+                                                              &pctx);
+                       if (res < 0) {
+                               /* skip FINISH_INODE_LOOP */
+                               continue;
+                       }
+               }
+
+               /* 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");
+                               /* skip FINISH_INODE_LOOP */
+                               continue;
+                       }
+               }
+
+               /* Test for inline data flag but no attr */
+               if ((inode->i_flags & EXT4_INLINE_DATA_FL) && inlinedata_fs &&
+                   EXT2_I_SIZE(inode) > EXT4_MIN_INLINE_DATA_SIZE &&
+                   (ino >= EXT2_FIRST_INODE(fs->super))) {
+                       size_t size = 0;
+                       errcode_t err;
+                       int flags;
+
+                       flags = fs->flags;
+                       if (failed_csum)
+                               fs->flags |= EXT2_FLAG_IGNORE_CSUM_ERRORS;
+                       err = get_inline_data_ea_size(fs, ino, &size);
+                       fs->flags = (flags & EXT2_FLAG_IGNORE_CSUM_ERRORS) |
+                                   (fs->flags & ~EXT2_FLAG_IGNORE_CSUM_ERRORS);
+
+                       switch (err) {
+                       case 0:
+                               /* Everything is awesome... */
+                               break;
+                       case EXT2_ET_BAD_EA_BLOCK_NUM:
+                       case EXT2_ET_BAD_EA_HASH:
+                       case EXT2_ET_BAD_EA_HEADER:
+                       case EXT2_ET_EA_BAD_NAME_LEN:
+                       case EXT2_ET_EA_BAD_VALUE_SIZE:
+                       case EXT2_ET_EA_KEY_NOT_FOUND:
+                       case EXT2_ET_EA_NO_SPACE:
+                       case EXT2_ET_MISSING_EA_FEATURE:
+                       case EXT2_ET_INLINE_DATA_CANT_ITERATE:
+                       case EXT2_ET_INLINE_DATA_NO_BLOCK:
+                       case EXT2_ET_INLINE_DATA_NO_SPACE:
+                       case EXT2_ET_NO_INLINE_DATA:
+                       case EXT2_ET_EXT_ATTR_CSUM_INVALID:
+                       case EXT2_ET_EA_BAD_VALUE_OFFSET:
+                               /* broken EA or no system.data EA; truncate */
+                               if (fix_problem(ctx, PR_1_INLINE_DATA_NO_ATTR,
+                                               &pctx)) {
+                                       err = ext2fs_inode_size_set(fs, inode,
+                                                       sizeof(inode->i_block));
+                                       if (err) {
+                                               pctx.errcode = err;
+                                               ctx->flags |= E2F_FLAG_ABORT;
+                                               goto endit;
+                                       }
+                                       e2fsck_write_inode(ctx, ino, inode,
+                                                          "pass1");
+                                       failed_csum = 0;
+                               }
+                               break;
+                       default:
+                               /* Some other kind of non-xattr error? */
+                               pctx.errcode = err;
+                               ctx->flags |= E2F_FLAG_ABORT;
+                               goto endit;
+                       }
+               }
+
                /*
                 * Test for incorrect extent flag settings.
                 *
@@ -825,6 +1232,7 @@ void e2fsck_pass1(e2fsck_t ctx)
                                if (ino == EXT2_BAD_INO)
                                        ext2fs_mark_inode_bitmap2(ctx->inode_used_map,
                                                                 ino);
+                               /* skip FINISH_INODE_LOOP */
                                continue;
                        }
                }
@@ -861,18 +1269,22 @@ void e2fsck_pass1(e2fsck_t ctx)
                                       sizeof(inode->i_block));
 #endif
                                e2fsck_write_inode(ctx, ino, inode, "pass1");
+                               failed_csum = 0;
                        }
                }
 
                if (ino == EXT2_BAD_INO) {
                        struct process_block_struct pb;
 
-                       if ((inode->i_mode || inode->i_uid || inode->i_gid ||
-                            inode->i_links_count || inode->i_file_acl) &&
+                       if ((failed_csum || inode->i_mode || inode->i_uid ||
+                            inode->i_gid || inode->i_links_count ||
+                            (inode->i_flags & EXT4_INLINE_DATA_FL) ||
+                            inode->i_file_acl) &&
                            fix_problem(ctx, PR_1_INVALID_BAD_INODE, &pctx)) {
                                memset(inode, 0, sizeof(struct ext2_inode));
                                e2fsck_write_inode(ctx, ino, inode,
                                                   "clear bad inode");
+                               failed_csum = 0;
                        }
 
                        pctx.errcode = ext2fs_copy_bitmap(ctx->block_found_map,
@@ -907,6 +1319,7 @@ void e2fsck_pass1(e2fsck_t ctx)
                        }
                        ext2fs_mark_inode_bitmap2(ctx->inode_used_map, ino);
                        clear_problem_context(&pctx);
+                       FINISH_INODE_LOOP(ctx, ino, &pctx, failed_csum);
                        continue;
                } else if (ino == EXT2_ROOT_INO) {
                        /*
@@ -932,6 +1345,7 @@ void e2fsck_pass1(e2fsck_t ctx)
                                        inode->i_dtime = 0;
                                        e2fsck_write_inode(ctx, ino, inode,
                                                           "pass1");
+                                       failed_csum = 0;
                                }
                        }
                } else if (ino == EXT2_JOURNAL_INO) {
@@ -943,8 +1357,10 @@ void e2fsck_pass1(e2fsck_t ctx)
                                        inode->i_mode = LINUX_S_IFREG;
                                        e2fsck_write_inode(ctx, ino, inode,
                                                           "pass1");
+                                       failed_csum = 0;
                                }
                                check_blocks(ctx, &pctx, block_buf);
+                               FINISH_INODE_LOOP(ctx, ino, &pctx, failed_csum);
                                continue;
                        }
                        if ((inode->i_links_count ||
@@ -956,6 +1372,7 @@ void e2fsck_pass1(e2fsck_t ctx)
                                                    ino, 0);
                                e2fsck_write_inode_full(ctx, ino, inode,
                                                        inode_size, "pass1");
+                               failed_csum = 0;
                        }
                } else if ((ino == EXT4_USR_QUOTA_INO) ||
                           (ino == EXT4_GRP_QUOTA_INO)) {
@@ -970,8 +1387,10 @@ void e2fsck_pass1(e2fsck_t ctx)
                                        inode->i_mode = LINUX_S_IFREG;
                                        e2fsck_write_inode(ctx, ino, inode,
                                                        "pass1");
+                                       failed_csum = 0;
                                }
                                check_blocks(ctx, &pctx, block_buf);
+                               FINISH_INODE_LOOP(ctx, ino, &pctx, failed_csum);
                                continue;
                        }
                        if ((inode->i_links_count ||
@@ -983,6 +1402,7 @@ void e2fsck_pass1(e2fsck_t ctx)
                                                    ino, 0);
                                e2fsck_write_inode_full(ctx, ino, inode,
                                                        inode_size, "pass1");
+                               failed_csum = 0;
                        }
                } else if (ino < EXT2_FIRST_INODE(fs->super)) {
                        problem_t problem = 0;
@@ -1004,9 +1424,11 @@ void e2fsck_pass1(e2fsck_t ctx)
                                        inode->i_mode = 0;
                                        e2fsck_write_inode(ctx, ino, inode,
                                                           "pass1");
+                                       failed_csum = 0;
                                }
                        }
                        check_blocks(ctx, &pctx, block_buf);
+                       FINISH_INODE_LOOP(ctx, ino, &pctx, failed_csum);
                        continue;
                }
 
@@ -1034,6 +1456,7 @@ void e2fsck_pass1(e2fsck_t ctx)
                                        0 : ctx->now;
                                e2fsck_write_inode(ctx, ino, inode,
                                                   "pass1");
+                               failed_csum = 0;
                        }
                }
 
@@ -1048,8 +1471,10 @@ void e2fsck_pass1(e2fsck_t ctx)
                                        inode->i_dtime = ctx->now;
                                        e2fsck_write_inode(ctx, ino, inode,
                                                           "pass1");
+                                       failed_csum = 0;
                                }
                        }
+                       FINISH_INODE_LOOP(ctx, ino, &pctx, failed_csum);
                        continue;
                }
                /*
@@ -1066,6 +1491,7 @@ void e2fsck_pass1(e2fsck_t ctx)
                        if (fix_problem(ctx, PR_1_SET_DTIME, &pctx)) {
                                inode->i_dtime = 0;
                                e2fsck_write_inode(ctx, ino, inode, "pass1");
+                               failed_csum = 0;
                        }
                }
 
@@ -1102,6 +1528,7 @@ void e2fsck_pass1(e2fsck_t ctx)
                                        inode->i_flags &= ~EXT2_IMAGIC_FL;
                                        e2fsck_write_inode(ctx, ino,
                                                           inode, "pass1");
+                                       failed_csum = 0;
                                }
                        }
                }
@@ -1119,6 +1546,7 @@ void e2fsck_pass1(e2fsck_t ctx)
                    fix_problem(ctx, PR_1_FAST_SYMLINK_EXTENT_FL, &pctx)) {
                        inode->i_flags &= ~EXT4_EXTENTS_FL;
                        e2fsck_write_inode(ctx, ino, inode, "pass1");
+                       failed_csum = 0;
                }
 
                if (LINUX_S_ISDIR(inode->i_mode)) {
@@ -1130,11 +1558,13 @@ void e2fsck_pass1(e2fsck_t ctx)
                        ctx->fs_regular_count++;
                } else if (LINUX_S_ISCHR (inode->i_mode) &&
                           e2fsck_pass1_check_device_inode(fs, inode)) {
+                       check_extents_inlinedata(ctx, &pctx);
                        check_immutable(ctx, &pctx);
                        check_size(ctx, &pctx);
                        ctx->fs_chardev_count++;
                } else if (LINUX_S_ISBLK (inode->i_mode) &&
                           e2fsck_pass1_check_device_inode(fs, inode)) {
+                       check_extents_inlinedata(ctx, &pctx);
                        check_immutable(ctx, &pctx);
                        check_size(ctx, &pctx);
                        ctx->fs_blockdev_count++;
@@ -1143,25 +1573,32 @@ void e2fsck_pass1(e2fsck_t ctx)
                                                      block_buf)) {
                        check_immutable(ctx, &pctx);
                        ctx->fs_symlinks_count++;
-                       if (ext2fs_inode_data_blocks(fs, inode) == 0) {
+                       if (inode->i_flags & EXT4_INLINE_DATA_FL) {
+                               FINISH_INODE_LOOP(ctx, ino, &pctx, failed_csum);
+                               continue;
+                       } else if (ext2fs_inode_data_blocks(fs, inode) == 0) {
                                ctx->fs_fast_symlinks_count++;
                                check_blocks(ctx, &pctx, block_buf);
+                               FINISH_INODE_LOOP(ctx, ino, &pctx, failed_csum);
                                continue;
                        }
                }
                else if (LINUX_S_ISFIFO (inode->i_mode) &&
                         e2fsck_pass1_check_device_inode(fs, inode)) {
+                       check_extents_inlinedata(ctx, &pctx);
                        check_immutable(ctx, &pctx);
                        check_size(ctx, &pctx);
                        ctx->fs_fifo_count++;
                } else if ((LINUX_S_ISSOCK (inode->i_mode)) &&
                           e2fsck_pass1_check_device_inode(fs, inode)) {
+                       check_extents_inlinedata(ctx, &pctx);
                        check_immutable(ctx, &pctx);
                        check_size(ctx, &pctx);
                        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])
@@ -1170,6 +1607,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] ||
@@ -1180,6 +1618,8 @@ void e2fsck_pass1(e2fsck_t ctx)
                } else
                        check_blocks(ctx, &pctx, block_buf);
 
+               FINISH_INODE_LOOP(ctx, ino, &pctx, failed_csum);
+
                if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
                        goto endit;
 
@@ -1274,9 +1714,16 @@ 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);
 }
+#undef FINISH_INODE_LOOP
 
 /*
  * When the inode_scan routines call this callback at the end of the
@@ -1504,7 +1951,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;
@@ -1515,8 +1963,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);
@@ -1541,6 +1990,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)
@@ -1614,9 +2064,18 @@ 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);
-       if (pctx->errcode && fix_problem(ctx, PR_1_READ_EA_BLOCK, pctx))
+       pctx->errcode = ext2fs_read_ext_attr3(fs, blk, block_buf, pctx->ino);
+       if (pctx->errcode == EXT2_ET_EXT_ATTR_CSUM_INVALID) {
+               pctx->errcode = 0;
+               failed_csum = 1;
+       } else if (pctx->errcode == EXT2_ET_BAD_EA_HEADER)
+               pctx->errcode = 0;
+
+       if (pctx->errcode &&
+           fix_problem(ctx, PR_1_READ_EA_BLOCK, pctx)) {
+               pctx->errcode = 0;
                goto clear_extattr;
+       }
        header = (struct ext2_ext_attr_header *) block_buf;
        pctx->blk = ext2fs_file_acl_block(fs, inode);
        if (((ctx->ext_attr_ver == 1) &&
@@ -1632,6 +2091,9 @@ static int check_ext_attr(e2fsck_t ctx, struct problem_context *pctx,
                        goto clear_extattr;
        }
 
+       if (pctx->errcode && fix_problem(ctx, PR_1_READ_EA_BLOCK, pctx))
+               goto clear_extattr;
+
        region = region_create(0, fs->blocksize);
        if (!region) {
                fix_problem(ctx, PR_1_EA_ALLOC_REGION_ABORT, pctx);
@@ -1696,6 +2158,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);
@@ -1835,7 +2309,8 @@ static void scan_extent_node(e2fsck_t ctx, struct problem_context *pctx,
                             struct process_block_struct *pb,
                             blk64_t start_block, blk64_t end_block,
                             blk64_t eof_block,
-                            ext2_extent_handle_t ehandle)
+                            ext2_extent_handle_t ehandle,
+                            int try_repairs)
 {
        struct ext2fs_extent    extent;
        blk64_t                 blk, last_lblk;
@@ -1844,6 +2319,10 @@ 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 = 0;
+
+       if (pctx->errcode == EXT2_ET_EXTENT_CSUM_INVALID)
+               failed_csum = 1;
 
        pctx->errcode = ext2fs_extent_get_info(ehandle, &info);
        if (pctx->errcode)
@@ -1851,12 +2330,19 @@ 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) {
                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;
+               pctx->blk = extent.e_pblk;
+               pctx->blk2 = extent.e_lblk;
+               pctx->num = extent.e_len;
+               pctx->blkcount = extent.e_lblk + extent.e_len;
+
                if (extent.e_pblk == 0 ||
                    extent.e_pblk < ctx->fs->super->s_first_data_block ||
                    extent.e_pblk >= ext2fs_blocks_count(ctx->fs->super))
@@ -1882,7 +2368,7 @@ static void scan_extent_node(e2fsck_t ctx, struct problem_context *pctx,
                 * Uninitialized blocks in a directory?  Clear the flag and
                 * we'll interpret the blocks later.
                 */
-               if (is_dir && problem == 0 &&
+               if (try_repairs && is_dir && problem == 0 &&
                    (extent.e_flags & EXT2_EXTENT_FLAGS_UNINIT) &&
                    fix_problem(ctx, PR_1_UNINIT_DBLOCK, pctx)) {
                        extent.e_flags &= ~EXT2_EXTENT_FLAGS_UNINIT;
@@ -1891,15 +2377,13 @@ static void scan_extent_node(e2fsck_t ctx, struct problem_context *pctx,
                                                              &extent);
                        if (pctx->errcode)
                                return;
+                       failed_csum = 0;
                }
 
-               if (problem) {
+               if (try_repairs && problem) {
 report_problem:
-                       pctx->blk = extent.e_pblk;
-                       pctx->blk2 = extent.e_lblk;
-                       pctx->num = extent.e_len;
-                       pctx->blkcount = extent.e_lblk + extent.e_len;
                        if (fix_problem(ctx, problem, pctx)) {
+fix_problem_now:
                                if (ctx->invalid_bitmaps) {
                                        /*
                                         * If fsck knows the bitmaps are bad,
@@ -1941,6 +2425,7 @@ report_problem:
                                        pctx->errcode = 0;
                                        break;
                                }
+                               failed_csum = 0;
                                continue;
                        }
                        goto next;
@@ -1948,13 +2433,33 @@ report_problem:
 
                if (!is_leaf) {
                        blk64_t lblk = extent.e_lblk;
+                       int next_try_repairs = 1;
 
                        blk = extent.e_pblk;
+
+                       /*
+                        * If this lower extent block collides with critical
+                        * metadata, don't try to repair the damage.  Pass 1b
+                        * will reallocate the block; then we can try again.
+                        */
+                       if (pb->ino != EXT2_RESIZE_INO &&
+                           ext2fs_test_block_bitmap2(ctx->block_metadata_map,
+                                                     extent.e_pblk)) {
+                               next_try_repairs = 0;
+                               pctx->blk = blk;
+                               fix_problem(ctx,
+                                           PR_1_CRITICAL_METADATA_COLLISION,
+                                           pctx);
+                               ctx->flags |= E2F_FLAG_RESTART_LATER;
+                       }
                        pctx->errcode = ext2fs_extent_get(ehandle,
                                                  EXT2_EXTENT_DOWN, &extent);
-                       if (pctx->errcode) {
+                       if (pctx->errcode &&
+                           pctx->errcode != EXT2_ET_EXTENT_CSUM_INVALID) {
                                pctx->str = "EXT2_EXTENT_DOWN";
                                problem = PR_1_EXTENT_HEADER_INVALID;
+                               if (!next_try_repairs)
+                                       return;
                                if (pctx->errcode == EXT2_ET_EXTENT_HEADER_BAD)
                                        goto report_problem;
                                return;
@@ -1979,7 +2484,8 @@ report_problem:
                                }
                        }
                        scan_extent_node(ctx, pctx, pb, extent.e_lblk,
-                                        last_lblk, eof_block, ehandle);
+                                        last_lblk, eof_block, ehandle,
+                                        next_try_repairs);
                        if (pctx->errcode)
                                return;
                        pctx->errcode = ext2fs_extent_get(ehandle,
@@ -2020,7 +2526,7 @@ report_problem:
                 * moving the logical block down, otherwise we'll go mad in
                 * pass 3 allocating empty directory blocks to fill the hole.
                 */
-               if (is_dir &&
+               if (try_repairs && is_dir &&
                    pb->last_block + 1 < (e2_blkcnt_t)extent.e_lblk) {
                        blk64_t new_lblk;
 
@@ -2050,6 +2556,7 @@ report_problem:
                                if (pctx->errcode)
                                        goto failed_add_dir_block;
                                last_lblk = extent.e_lblk + extent.e_len - 1;
+                               failed_csum = 0;
                        }
                }
 alloc_later:
@@ -2117,6 +2624,16 @@ alloc_later:
                                                  EXT2_EXTENT_NEXT_SIB,
                                                  &extent);
        }
+
+       /* Failed csum but passes checks?  Ask to fix checksum. */
+       if (failed_csum &&
+           fix_problem(ctx, PR_1_EXTENT_ONLY_CSUM_INVALID, pctx)) {
+               pb->inode_modified = 1;
+               pctx->errcode = ext2fs_extent_replace(ehandle, 0, &extent);
+               if (pctx->errcode)
+                       return;
+       }
+
        if (pctx->errcode == EXT2_ET_EXTENT_NO_NEXT)
                pctx->errcode = 0;
 }
@@ -2150,7 +2667,7 @@ static void check_blocks_extents(e2fsck_t ctx, struct problem_context *pctx,
 
        eof_lblk = ((EXT2_I_SIZE(inode) + fs->blocksize - 1) >>
                EXT2_BLOCK_SIZE_BITS(fs->super)) - 1;
-       scan_extent_node(ctx, pctx, pb, 0, 0, eof_lblk, ehandle);
+       scan_extent_node(ctx, pctx, pb, 0, 0, eof_lblk, ehandle, 1);
        if (pctx->errcode &&
            fix_problem(ctx, PR_1_EXTENT_ITERATE_FAILURE, pctx)) {
                pb->num_blocks = 0;
@@ -2163,6 +2680,28 @@ static void check_blocks_extents(e2fsck_t ctx, struct problem_context *pctx,
 }
 
 /*
+ * 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.
  */
@@ -2176,6 +2715,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;
@@ -2195,11 +2735,14 @@ static void check_blocks(e2fsck_t ctx, struct problem_context *pctx,
        pb.pctx = pctx;
        pb.ctx = ctx;
        pb.inode_modified = 0;
+       pb.bad_ref = 0;
        pctx->ino = ino;
        pctx->errcode = 0;
 
        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 &
@@ -2213,17 +2756,19 @@ static void check_blocks(e2fsck_t ctx, struct problem_context *pctx,
                }
        }
 
-       if (ext2fs_file_acl_block(fs, inode) &&
-           check_ext_attr(ctx, pctx, block_buf)) {
+       if (check_ext_attr(ctx, pctx, block_buf)) {
                if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
                        goto out;
                pb.num_blocks++;
        }
 
-       if (ext2fs_inode_has_valid_blocks2(fs, inode)) {
+       if (inlinedata_fs && (inode->i_flags & EXT4_INLINE_DATA_FL))
+               check_blocks_inline_data(ctx, pctx, &pb);
+       else if (ext2fs_inode_has_valid_blocks2(fs, inode)) {
                if (extent_fs && (inode->i_flags & EXT4_EXTENTS_FL))
                        check_blocks_extents(ctx, pctx, &pb);
                else {
+                       int flags;
                        /*
                         * If we've modified the inode, write it out before
                         * iterate() tries to use it.
@@ -2233,6 +2778,8 @@ static void check_blocks(e2fsck_t ctx, struct problem_context *pctx,
                                                   "check_blocks");
                                dirty_inode = 0;
                        }
+                       flags = fs->flags;
+                       fs->flags |= EXT2_FLAG_IGNORE_CSUM_ERRORS;
                        pctx->errcode = ext2fs_block_iterate3(fs, ino,
                                                pb.is_dir ? BLOCK_FLAG_HOLE : 0,
                                                block_buf, process_block, &pb);
@@ -2250,6 +2797,8 @@ static void check_blocks(e2fsck_t ctx, struct problem_context *pctx,
                        if (pb.inode_modified)
                                e2fsck_read_inode(ctx, ino, inode,
                                                  "check_blocks");
+                       fs->flags = (flags & EXT2_FLAG_IGNORE_CSUM_ERRORS) |
+                                   (fs->flags & ~EXT2_FLAG_IGNORE_CSUM_ERRORS);
                }
        }
        end_problem_latch(ctx, PR_LATCH_BLOCK);
@@ -2283,7 +2832,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--;
@@ -2309,7 +2859,25 @@ 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) {
+                       int flags;
+                       size_t size;
+                       errcode_t err;
+
+                       size = 0;
+                       flags = ctx->fs->flags;
+                       ctx->fs->flags |= EXT2_FLAG_IGNORE_CSUM_ERRORS;
+                       err = ext2fs_inline_data_size(ctx->fs, pctx->ino,
+                                                     &size);
+                       ctx->fs->flags = (flags &
+                                         EXT2_FLAG_IGNORE_CSUM_ERRORS) |
+                                        (ctx->fs->flags &
+                                         ~EXT2_FLAG_IGNORE_CSUM_ERRORS);
+                       if (err || size != inode->i_size) {
+                               bad_size = 7;
+                               pctx->num = size;
+                       }
+               } else if (inode->i_size & (fs->blocksize - 1))
                        bad_size = 5;
                else if (nblock > (pb.last_block + 1))
                        bad_size = 1;
@@ -2341,12 +2909,20 @@ static void check_blocks(e2fsck_t ctx, struct problem_context *pctx,
        }
        /* i_size for symlinks is checked elsewhere */
        if (bad_size && !LINUX_S_ISLNK(inode->i_mode)) {
-               pctx->num = (pb.last_block+1) * fs->blocksize;
+               /* Did inline_data set pctx->num earlier? */
+               if (bad_size != 7)
+                       pctx->num = (pb.last_block + 1) * fs->blocksize;
                pctx->group = bad_size;
                if (fix_problem(ctx, PR_1_BAD_I_SIZE, pctx)) {
                        if (LINUX_S_ISDIR(inode->i_mode))
                                pctx->num &= 0xFFFFFFFFULL;
                        ext2fs_inode_size_set(fs, inode, pctx->num);
+                       if (EXT2_I_SIZE(inode) == 0 &&
+                           (inode->i_flags & EXT4_INLINE_DATA_FL)) {
+                               memset(inode->i_block, 0,
+                                      sizeof(inode->i_block));
+                               inode->i_flags &= ~EXT4_INLINE_DATA_FL;
+                       }
                        dirty_inode++;
                }
                pctx->num = 0;
@@ -2369,9 +2945,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)
@@ -2533,8 +3110,35 @@ static int process_block(ext2_filsys fs,
            blk >= ext2fs_blocks_count(fs->super))
                problem = PR_1_ILLEGAL_BLOCK_NUM;
 
+       /*
+        * If this IND/DIND/TIND block is squatting atop some critical metadata
+        * (group descriptors, superblock, bitmap, inode table), any write to
+        * "fix" mapping problems will destroy the metadata.  We'll let pass 1b
+        * fix that and restart fsck.
+        */
+       if (blockcnt < 0 &&
+           p->ino != EXT2_RESIZE_INO &&
+           ext2fs_test_block_bitmap2(ctx->block_metadata_map, blk)) {
+               p->bad_ref = blk;
+               pctx->blk = blk;
+               fix_problem(ctx, PR_1_CRITICAL_METADATA_COLLISION, pctx);
+               ctx->flags |= E2F_FLAG_RESTART_LATER;
+       }
+
        if (problem) {
                p->num_illegal_blocks++;
+               /*
+                * A bit of subterfuge here -- we're trying to fix a block
+                * mapping, but know that the IND/DIND/TIND block has collided
+                * with some critical metadata.  So, fix the in-core mapping so
+                * iterate won't go insane, but return 0 instead of
+                * BLOCK_CHANGED so that it won't write the remapping out to
+                * our multiply linked block.
+                */
+               if (p->bad_ref && ref_block == p->bad_ref) {
+                       *block_nr = 0;
+                       return 0;
+               }
                if (!p->suppress && (p->num_illegal_blocks % 12) == 0) {
                        if (fix_problem(ctx, PR_1_TOO_MANY_BAD_BLOCKS, pctx)) {
                                p->clear = 1;
@@ -2933,6 +3537,7 @@ static void mark_table_blocks(e2fsck_t ctx)
                pctx.group = i;
 
                ext2fs_reserve_super_and_bgd(fs, i, ctx->block_found_map);
+               ext2fs_reserve_super_and_bgd(fs, i, ctx->block_metadata_map);
 
                /*
                 * Mark the blocks used for the inode table
@@ -2951,8 +3556,10 @@ static void mark_table_blocks(e2fsck_t ctx)
                                                ctx->invalid_bitmaps++;
                                        }
                                } else {
-                                   ext2fs_mark_block_bitmap2(ctx->block_found_map,
-                                                            b);
+                                   ext2fs_mark_block_bitmap2(
+                                               ctx->block_found_map, b);
+                                   ext2fs_mark_block_bitmap2(
+                                               ctx->block_metadata_map, b);
                                }
                        }
                }
@@ -2971,8 +3578,9 @@ static void mark_table_blocks(e2fsck_t ctx)
                        } else {
                            ext2fs_mark_block_bitmap2(ctx->block_found_map,
                                     ext2fs_block_bitmap_loc(fs, i));
-                   }
-
+                           ext2fs_mark_block_bitmap2(ctx->block_metadata_map,
+                                    ext2fs_block_bitmap_loc(fs, i));
+                       }
                }
                /*
                 * Mark block used for the inode bitmap
@@ -2986,6 +3594,8 @@ static void mark_table_blocks(e2fsck_t ctx)
                                        ctx->invalid_bitmaps++;
                                }
                        } else {
+                           ext2fs_mark_block_bitmap2(ctx->block_metadata_map,
+                                    ext2fs_inode_bitmap_loc(fs, i));
                            ext2fs_mark_block_bitmap2(ctx->block_found_map,
                                     ext2fs_inode_bitmap_loc(fs, i));
                        }
@@ -3083,6 +3693,13 @@ static void e2fsck_block_alloc_stats(ext2_filsys fs, blk64_t blk, int inuse)
 {
        e2fsck_t ctx = (e2fsck_t) fs->priv_data;
 
+       /* Never free a critical metadata block */
+       if (ctx->block_found_map &&
+           ctx->block_metadata_map &&
+           inuse < 0 &&
+           ext2fs_test_block_bitmap2(ctx->block_metadata_map, blk))
+               return;
+
        if (ctx->block_found_map) {
                if (inuse > 0)
                        ext2fs_mark_block_bitmap2(ctx->block_found_map, blk);
index bb81d5e..2d1b448 100644 (file)
@@ -262,6 +262,7 @@ struct process_block_struct {
        ext2_ino_t      ino;
        int             dup_blocks;
        blk64_t         cur_cluster, phys_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);
 
@@ -316,6 +318,8 @@ static void pass1b(e2fsck_t ctx, char *block_buf)
                pb.inode = &inode;
                pb.cur_cluster = ~0;
                pb.phys_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))
@@ -331,6 +335,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)
@@ -353,6 +362,7 @@ static int process_pass1b_block(ext2_filsys fs EXT2FS_ATTR((unused)),
        struct process_block_struct *p;
        e2fsck_t ctx;
        blk64_t lc, pc;
+       problem_t op;
 
        if (HOLE_BLKADDR(*block_nr))
                return 0;
@@ -366,8 +376,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);
@@ -669,9 +688,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 2b7bff4..fb98af5 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 */
 
@@ -642,15 +665,16 @@ clear_and_exit:
 static void salvage_directory(ext2_filsys fs,
                              struct ext2_dir_entry *dirent,
                              struct ext2_dir_entry *prev,
-                             unsigned int *offset)
+                             unsigned int *offset,
+                             unsigned int block_len)
 {
        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;
+       left = block_len - *offset - rec_len;
 
        /*
         * Special case of directory entry of size 8: copy what's left
@@ -680,7 +704,7 @@ static void salvage_directory(ext2_filsys fs,
         * previous directory entry absorb the invalid one.
         */
        if (prev && rec_len && (rec_len % 4) == 0 &&
-           (*offset + rec_len <= fs->blocksize)) {
+           (*offset + rec_len <= block_len)) {
                (void) ext2fs_get_rec_len(fs, prev, &prev_rec_len);
                prev_rec_len += rec_len;
                (void) ext2fs_set_rec_len(fs, prev_rec_len, prev);
@@ -695,17 +719,112 @@ static void salvage_directory(ext2_filsys fs,
         */
        if (prev) {
                (void) ext2fs_get_rec_len(fs, prev, &prev_rec_len);
-               prev_rec_len += fs->blocksize - *offset;
+               prev_rec_len += block_len - *offset;
                (void) ext2fs_set_rec_len(fs, prev_rec_len, prev);
                *offset = fs->blocksize;
        } else {
-               rec_len = fs->blocksize - *offset;
+               rec_len = block_len - *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);
+}
+
+#define NEXT_DIRENT(d) ((void *)((char *)(d) + (d)->rec_len))
+static errcode_t insert_dirent_tail(ext2_filsys fs, void *dirbuf)
+{
+       struct ext2_dir_entry *d;
+       void *top;
+       struct ext2_dir_entry_tail *t;
+       unsigned int rec_len;
+
+       d = dirbuf;
+       top = EXT2_DIRENT_TAIL(dirbuf, fs->blocksize);
+
+       while (d->rec_len && !(d->rec_len & 0x3) && NEXT_DIRENT(d) <= top)
+               d = NEXT_DIRENT(d);
+
+       if (d != top) {
+               size_t min_size = EXT2_DIR_REC_LEN(
+                               ext2fs_dirent_name_len(dirbuf));
+               if (min_size > top - (void *)d)
+                       return EXT2_ET_DIR_NO_SPACE_FOR_CSUM;
+               d->rec_len = top - (void *)d;
+       }
+
+       t = (struct ext2_dir_entry_tail *)top;
+       if (t->det_reserved_zero1 ||
+           t->det_rec_len != sizeof(struct ext2_dir_entry_tail) ||
+           t->det_reserved_name_len != EXT2_DIR_NAME_LEN_CSUM)
+               ext2fs_initialize_dirent_tail(fs, t);
+
+       return 0;
+}
+#undef NEXT_DIRENT
+
+static errcode_t fix_inline_dir_size(e2fsck_t ctx, ext2_ino_t ino,
+                                    size_t *inline_data_size,
+                                    struct problem_context *pctx,
+                                    char *buf)
+{
+       ext2_filsys fs = ctx->fs;
+       struct ext2_inode inode;
+       size_t new_size, old_size;
+       errcode_t retval;
+
+       old_size = *inline_data_size;
+       new_size = old_size + (4 - (old_size & 3));
+       memset(buf + old_size, 0, new_size - old_size);
+       retval = ext2fs_inline_data_set(fs, ino, 0, buf, new_size);
+       if (retval == EXT2_ET_INLINE_DATA_NO_SPACE) {
+               new_size -= 4;
+               retval = ext2fs_inline_data_set(fs, ino, 0, buf, new_size);
+               if (retval) {
+                       if (fix_problem(ctx, PR_2_FIX_INLINE_DIR_FAILED,
+                                       pctx)) {
+                               new_size = 0;
+                               goto write_inode;
+                       }
+                       goto err;
+               }
+       } else if (retval) {
+               if (fix_problem(ctx, PR_2_FIX_INLINE_DIR_FAILED,
+                               pctx)) {
+                       new_size = 0;
+                       goto write_inode;
+               }
+               goto err;
+       }
+
+write_inode:
+       retval = ext2fs_read_inode(fs, ino, &inode);
+       if (retval)
+               goto err;
+
+       retval = ext2fs_inode_size_set(fs, &inode, new_size);
+       if (retval)
+               goto err;
+       if (new_size == 0)
+               inode.i_flags &= ~EXT4_INLINE_DATA_FL;
+       retval = ext2fs_write_inode(fs, ino, &inode);
+       if (retval)
+               goto err;
+       *inline_data_size = new_size;
+
+err:
+       return retval;
+}
+
 static int check_dir_block(ext2_filsys fs,
                           struct ext2_db_entry2 *db,
                           void *priv_data)
@@ -714,7 +833,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 +853,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 +869,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 +893,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 +923,49 @@ 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);
+               if (cd->pctx.errcode)
+                       goto inline_read_fail;
+#ifdef WORDS_BIGENDIAN
+               *((__u32 *)buf) = ext2fs_le32_to_cpu(*((__u32 *)buf));
+               cd->pctx.errcode = ext2fs_dirent_swab_in2(fs,
+                               buf + EXT4_INLINE_DATA_DOTDOT_SIZE,
+                               inline_data_size - EXT4_INLINE_DATA_DOTDOT_SIZE,
+                               0);
+#endif
+       } else
+               cd->pctx.errcode = ext2fs_read_dir_block4(fs, block_nr,
+                                                         buf, 0, ino);
+inline_read_fail:
+       pctx.ino = ino;
+       pctx.num = inline_data_size;
+       if ((inline_data_size & 3) &&
+           fix_problem(ctx, PR_2_BAD_INLINE_DIR_SIZE, &pctx)) {
+               errcode_t err = fix_inline_dir_size(ctx, ino,
+                                                   &inline_data_size, &pctx,
+                                                   buf);
+               if (err)
+                       return DIRENT_ABORT;
+
+       }
        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 +1008,87 @@ 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 */
 
+       /* Leaf node with no space for csum?  Rebuild dirs in pass 3A. */
+       if (is_leaf && !inline_data_size && failed_csum &&
+           !ext2fs_dirent_has_tail(fs, (struct ext2_dir_entry *)buf)) {
+               de_csum_size = 0;
+               if (e2fsck_dir_will_be_rehashed(ctx, ino) ||
+                   !fix_problem(cd->ctx, PR_2_LEAF_NODE_MISSING_CSUM,
+                                &cd->pctx))
+                       goto skip_checksum;
+               e2fsck_rehash_dir_later(ctx, ino);
+               goto skip_checksum;
+       }
+       /* 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) {
+                       size_t max_block_size = fs->blocksize - de_csum_size;
+
+                       if (inline_data_size)
+                               max_block_size = inline_data_size;
+                       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) ||
+                           (inline_data_size > 0 &&
+                            (offset + rec_len) > inline_data_size) ||
+                           (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,
+                                                         max_block_size);
+                                       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 +1114,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 +1127,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 +1135,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 +1153,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 +1266,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 +1313,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 +1327,25 @@ 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;
+                               /*
+                                * If we get here, we're checking an inline
+                                * directory and we've just checked a (fake)
+                                * dotdot entry that we created on the stack.
+                                * Therefore set 'prev' to NULL so that if we
+                                * call salvage_directory on the next entry,
+                                * it won't try to absorb the next entry into
+                                * the on-stack dotdot entry.
+                                */
+                               prev = NULL;
+                       }
+               }
                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 +1359,84 @@ 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);
+               int     flags, will_rehash;
+               /* leaf block with no tail?  Rehash dirs later. */
+               if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+                               EXT4_FEATURE_RO_COMPAT_METADATA_CSUM) &&
+                   is_leaf &&
+                   !inline_data_size &&
+                   !ext2fs_dirent_has_tail(fs, (struct ext2_dir_entry *)buf)) {
+                       if (insert_dirent_tail(fs, buf) == 0)
+                               goto write_and_fix;
+                       e2fsck_rehash_dir_later(ctx, ino);
+               }
+
+write_and_fix:
+               will_rehash = e2fsck_dir_will_be_rehashed(ctx, ino);
+               if (will_rehash) {
+                       flags = ctx->fs->flags;
+                       ctx->fs->flags |= EXT2_FLAG_IGNORE_CSUM_ERRORS;
+               }
+               if (inline_data_size) {
+#ifdef WORDS_BIGENDIAN
+                       *((__u32 *)buf) = ext2fs_le32_to_cpu(*((__u32 *)buf));
+                       cd->pctx.errcode = ext2fs_dirent_swab_out2(fs,
+                                       buf + EXT4_INLINE_DATA_DOTDOT_SIZE,
+                                       inline_data_size -
+                                       EXT4_INLINE_DATA_DOTDOT_SIZE,
+                                       0);
+                       if (cd->pctx.errcode &&
+                           !fix_problem(ctx, PR_2_WRITE_DIRBLOCK, &cd->pctx))
+                               goto abort_free_dict;
+#endif
+                       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 (will_rehash)
+                       ctx->fs->flags = (flags &
+                                         EXT2_FLAG_IGNORE_CSUM_ERRORS) |
+                                        (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 +1498,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;
@@ -1223,6 +1521,10 @@ static void deallocate_inode(e2fsck_t ctx, ext2_ino_t ino, char* block_buf)
        if (!ext2fs_inode_has_valid_blocks2(fs, &inode))
                goto clear_inode;
 
+       /* Inline data inodes don't have blocks to iterate */
+       if (inode.i_flags & EXT4_INLINE_DATA_FL)
+               goto clear_inode;
+
        if (LINUX_S_ISREG(inode.i_mode) &&
            ext2fs_needs_large_file_feature(EXT2_I_SIZE(&inode)))
                ctx->large_files--;
@@ -1400,7 +1702,6 @@ int e2fsck_process_bad_inode(e2fsck_t ctx, ext2_ino_t dir,
        return 0;
 }
 
-
 /*
  * allocate_dir_block --- this function allocates a new directory
  *     block for a particular inode; this is done if a directory has
@@ -1460,7 +1761,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 0274213..63b1d70 100644 (file)
@@ -205,27 +205,6 @@ skip_new_block:
        ext2fs_mark_bb_dirty(fs);
 
        /*
-        * Now let's create the actual data block for the inode
-        */
-       pctx.errcode = ext2fs_new_dir_block(fs, EXT2_ROOT_INO, EXT2_ROOT_INO,
-                                           &block);
-       if (pctx.errcode) {
-               pctx.str = "ext2fs_new_dir_block";
-               fix_problem(ctx, PR_3_CREATE_ROOT_ERROR, &pctx);
-               ctx->flags |= E2F_FLAG_ABORT;
-               return;
-       }
-
-       pctx.errcode = ext2fs_write_dir_block3(fs, blk, block, 0);
-       if (pctx.errcode) {
-               pctx.str = "ext2fs_write_dir_block3";
-               fix_problem(ctx, PR_3_CREATE_ROOT_ERROR, &pctx);
-               ctx->flags |= E2F_FLAG_ABORT;
-               return;
-       }
-       ext2fs_free_mem(&block);
-
-       /*
         * Set up the inode structure
         */
        memset(&inode, 0, sizeof(inode));
@@ -248,6 +227,30 @@ skip_new_block:
        }
 
        /*
+        * Now let's create the actual data block for the inode.
+        * Due to metadata_csum, we must write the dir blocks AFTER
+        * the inode has been written to disk!
+        */
+       pctx.errcode = ext2fs_new_dir_block(fs, EXT2_ROOT_INO, EXT2_ROOT_INO,
+                                           &block);
+       if (pctx.errcode) {
+               pctx.str = "ext2fs_new_dir_block";
+               fix_problem(ctx, PR_3_CREATE_ROOT_ERROR, &pctx);
+               ctx->flags |= E2F_FLAG_ABORT;
+               return;
+       }
+
+       pctx.errcode = ext2fs_write_dir_block4(fs, blk, block, 0,
+                                              EXT2_ROOT_INO);
+       ext2fs_free_mem(&block);
+       if (pctx.errcode) {
+               pctx.str = "ext2fs_write_dir_block4";
+               fix_problem(ctx, PR_3_CREATE_ROOT_ERROR, &pctx);
+               ctx->flags |= E2F_FLAG_ABORT;
+               return;
+       }
+
+       /*
         * Miscellaneous bookkeeping...
         */
        e2fsck_add_dir_info(ctx, EXT2_ROOT_INO, EXT2_ROOT_INO);
@@ -392,7 +395,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;
                }
@@ -404,6 +418,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) {
@@ -435,6 +450,12 @@ ext2_ino_t e2fsck_get_lost_and_found(e2fsck_t ctx, int fix)
                goto skip_new_block;
        }
        retval = ext2fs_new_block2(fs, 0, ctx->block_found_map, &blk);
+       if (retval == EXT2_ET_BLOCK_ALLOC_FAIL &&
+           fix_problem(ctx, PR_3_LPF_NO_SPACE, &pctx)) {
+               fix_problem(ctx, PR_3_NO_SPACE_TO_RECOVER, &pctx);
+               ctx->lost_and_found = EXT2_ROOT_INO;
+               return 0;
+       }
        if (retval) {
                pctx.errcode = retval;
                fix_problem(ctx, PR_3_ERR_LPF_NEW_BLOCK, &pctx);
@@ -449,6 +470,12 @@ skip_new_block:
         */
        retval = ext2fs_new_inode(fs, EXT2_ROOT_INO, 040700,
                                  ctx->inode_used_map, &ino);
+       if (retval == EXT2_ET_INODE_ALLOC_FAIL &&
+           fix_problem(ctx, PR_3_LPF_NO_SPACE, &pctx)) {
+               fix_problem(ctx, PR_3_NO_SPACE_TO_RECOVER, &pctx);
+               ctx->lost_and_found = EXT2_ROOT_INO;
+               return 0;
+       }
        if (retval) {
                pctx.errcode = retval;
                fix_problem(ctx, PR_3_ERR_LPF_NEW_INODE, &pctx);
@@ -459,24 +486,6 @@ skip_new_block:
        ext2fs_inode_alloc_stats2(fs, ino, +1, 1);
 
        /*
-        * Now let's create the actual data block for the inode
-        */
-       retval = ext2fs_new_dir_block(fs, ino, EXT2_ROOT_INO, &block);
-       if (retval) {
-               pctx.errcode = retval;
-               fix_problem(ctx, PR_3_ERR_LPF_NEW_DIR_BLOCK, &pctx);
-               return 0;
-       }
-
-       retval = ext2fs_write_dir_block3(fs, blk, block, 0);
-       ext2fs_free_mem(&block);
-       if (retval) {
-               pctx.errcode = retval;
-               fix_problem(ctx, PR_3_ERR_LPF_WRITE_BLOCK, &pctx);
-               return 0;
-       }
-
-       /*
         * Set up the inode structure
         */
        memset(&inode, 0, sizeof(inode));
@@ -496,6 +505,27 @@ skip_new_block:
                fix_problem(ctx, PR_3_CREATE_LPF_ERROR, &pctx);
                return 0;
        }
+
+       /*
+        * Now let's create the actual data block for the inode.
+        * Due to metadata_csum, the directory block MUST be written
+        * after the inode is written to disk!
+        */
+       retval = ext2fs_new_dir_block(fs, ino, EXT2_ROOT_INO, &block);
+       if (retval) {
+               pctx.errcode = retval;
+               fix_problem(ctx, PR_3_ERR_LPF_NEW_DIR_BLOCK, &pctx);
+               return 0;
+       }
+
+       retval = ext2fs_write_dir_block4(fs, blk, block, 0, ino);
+       ext2fs_free_mem(&block);
+       if (retval) {
+               pctx.errcode = retval;
+               fix_problem(ctx, PR_3_ERR_LPF_WRITE_BLOCK, &pctx);
+               return 0;
+       }
+
        /*
         * Finally, create the directory link
         */
@@ -635,7 +665,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;
@@ -655,10 +685,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;
@@ -670,6 +699,7 @@ static void fix_dotdot(e2fsck_t ctx, ext2_ino_t ino, ext2_ino_t parent)
        errcode_t       retval;
        struct fix_dotdot_struct fp;
        struct problem_context pctx;
+       int             flags, will_rehash;
 
        fp.fs = fs;
        fp.parent = parent;
@@ -682,8 +712,16 @@ static void fix_dotdot(e2fsck_t ctx, ext2_ino_t ino, ext2_ino_t parent)
 
        clear_problem_context(&pctx);
        pctx.ino = ino;
+       will_rehash = e2fsck_dir_will_be_rehashed(ctx, ino);
+       if (will_rehash) {
+               flags = ctx->fs->flags;
+               ctx->fs->flags |= EXT2_FLAG_IGNORE_CSUM_ERRORS;
+       }
        retval = ext2fs_dir_iterate(fs, ino, DIRENT_FLAG_INCLUDE_EMPTY,
                                    0, fix_dotdot_proc, &fp);
+       if (will_rehash)
+               ctx->fs->flags = (flags & EXT2_FLAG_IGNORE_CSUM_ERRORS) |
+                       (ctx->fs->flags & ~EXT2_FLAG_IGNORE_CSUM_ERRORS);
        if (retval || !fp.done) {
                pctx.errcode = retval;
                fix_problem(ctx, retval ? PR_3_FIX_PARENT_ERR :
@@ -709,6 +747,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,
@@ -760,7 +799,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) {
@@ -812,6 +852,7 @@ errcode_t e2fsck_expand_directory(e2fsck_t ctx, ext2_ino_t dir,
        es.err = 0;
        es.newblocks = 0;
        es.ctx = ctx;
+       es.dir = dir;
 
        retval = ext2fs_block_iterate3(fs, dir, BLOCK_FLAG_APPEND,
                                       0, expand_dir_proc, &es);
index bc9a32a..bf3f733 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,16 +66,135 @@ 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);
        ctx->inode_dir_map = 0;
        ext2fs_free_block_bitmap(ctx->block_found_map);
        ctx->block_found_map = 0;
+       ext2fs_free_block_bitmap(ctx->block_metadata_map);
+       ctx->block_metadata_map = 0;
 
        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, "%s",
+                   _("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, "%s",
+                   _("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)
 {
@@ -502,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 be4bd0c..8533585 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.  "),
@@ -958,6 +972,38 @@ 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 seems to contain garbage */
+       { PR_1_INODE_IS_GARBAGE,
+         N_("@i %i seems to contain garbage.  "),
+         PROMPT_CLEAR, 0 },
+
+       /* 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 extended attribute is corrupt (allocation collision) */
+       { PR_1_INODE_EA_ALLOC_COLLISION,
+         N_("@i %i @a is corrupt (allocation collision).  "),
+         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 },
+
+       /*
+        * Inode extended attribute block passes checks, but checksum does not
+        * match block.
+        */
+       { PR_1_EA_BLOCK_ONLY_CSUM_INVALID,
+         N_("@i %i @a @b %b passes checks, but checksum does not match @b.  "),
+         PROMPT_FIX, 0 },
+
        /*
         * Interior extent node logical offset doesn't match first node below it
         */
@@ -971,6 +1017,23 @@ 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 },
+
+       /*
+        * Inode block conflicts with critical metadata, skipping
+        * block checks
+        */
+       { PR_1_CRITICAL_METADATA_COLLISION,
+         N_("@i %i block %b conflicts with critical metadata, skipping block checks.\n"),
+         PROMPT_NONE, 0 },
 
        /* Directory inode block <block> should be at block <otherblock> */
        { PR_1_COLLAPSE_DBLOCK,
@@ -987,6 +1050,37 @@ static struct e2fsck_problem problem_table[] = {
          N_("@i %i logical @b %b (physical @b %c) violates cluster allocation rules.\nWill fix in pass 1B.\n"),
          PROMPT_NONE, 0 },
 
+       /* Inode has INLINE_DATA_FL flag but extended attribute not found */
+       { PR_1_INLINE_DATA_NO_ATTR,
+         N_("@i %i has INLINE_DATA_FL flag but @a not found.  "),
+         PROMPT_TRUNCATE, 0 },
+
+       /* Extents/inlinedata flag set on a device or socket inode */
+       { PR_1_SPECIAL_EXTENTS_IDATA,
+         N_("Special (@v/socket/fifo) file (@i %i) has extents\n"
+            "or inline-data flag set.  "),
+         PROMPT_CLEAR, PR_PREEN_OK | PR_PREEN_NO | PR_NO_OK },
+
+       /* Inode has extent header but inline data flag is set */
+       { PR_1_CLEAR_INLINE_DATA_FOR_EXTENT,
+         N_("@i %i has @x header but inline data flag is set.\n"),
+         PROMPT_FIX, 0 },
+
+       /* Inode seems to have inline data but extent flag is set */
+       { PR_1_CLEAR_EXTENT_FOR_INLINE_DATA,
+         N_("@i %i seems to have inline data but @x flag is set.\n"),
+         PROMPT_FIX, 0 },
+
+       /* Inode seems to have block map but inline data and extent flags set */
+       { PR_1_CLEAR_EXTENT_INLINE_DATA_FLAGS,
+         N_("@i %i seems to have @b map but inline data and @x flags set.\n"),
+         PROMPT_FIX, 0 },
+
+       /* Inode has inline data and extent flags but i_block contains junk */
+       { PR_1_CLEAR_EXTENT_INLINE_DATA_INODE,
+         N_("@i %i has inline data and @x flags set but i_block contains junk.\n"),
+         PROMPT_CLEAR_INODE, 0 },
+
        /* Pass 1b errors */
 
        /* Pass 1B: Rescan for duplicate/bad blocks */
@@ -1030,6 +1124,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"),
@@ -1409,6 +1508,36 @@ 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 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 },
+
+       /* inline directory inode size must be a multiple of 4 */
+       { PR_2_BAD_INLINE_DIR_SIZE,
+         N_("Inline @d @i %i size (%N) must be a multiple of 4.\n"),
+         PROMPT_FIX, 0 },
+
+       /* fixing size of inline directory inode failed */
+       { PR_2_FIX_INLINE_DIR_FAILED,
+         N_("Fixing size of inline @d @i %i failed.\n"),
+         PROMPT_TRUNCATE, 0 },
+
        /* Pass 3 errors */
 
        /* Pass 3: Checking directory connectivity */
@@ -1531,6 +1660,21 @@ 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 },
+
+       /* Cannot allocate /lost+found. */
+       { PR_3_LPF_NO_SPACE,
+         N_("Cannot allocate space for /@l.\nPlace lost files in root directory instead"),
+         PROMPT_NULL, 0 },
+
+       /* Delete some files and re-run e2fsck. */
+       { PR_3_NO_SPACE_TO_RECOVER,
+         N_("Insufficient space to recover lost files!\nMove data off the @f and re-run e2fsck.\n\n"),
+         PROMPT_NONE, 0 },
+
        /* Pass 3A Directory Optimization       */
 
        /* Pass 3A: Optimizing directories */
@@ -1725,6 +1869,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 @B 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 @B 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 212ed35..5c92d0a 100644 (file)
@@ -249,6 +249,15 @@ struct problem_context {
 /* Checking group descriptor failed */
 #define PR_0_CHECK_DESC_FAILED                 0x000045
 
+/*
+ * 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
+
 /* 64bit is set but extents are not set. */
 #define PR_0_64BIT_WITHOUT_EXTENTS             0x000048
 
@@ -564,6 +573,21 @@ struct problem_context {
 /* Extent has zero length */
 #define PR_1_EXTENT_LENGTH_ZERO                0x010066
 
+/* inode seems to contain garbage */
+#define PR_1_INODE_IS_GARBAGE          0x010067
+
+/* inode passes checks, but checksum does not match inode */
+#define PR_1_INODE_ONLY_CSUM_INVALID   0x010068
+
+/* Inode EA allocation collision */
+#define PR_1_INODE_EA_ALLOC_COLLISION  0x010069
+
+/* extent block passes checks, but checksum does not match extent block */
+#define PR_1_EXTENT_ONLY_CSUM_INVALID  0x01006A
+
+/* 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
 
@@ -587,6 +611,24 @@ struct problem_context {
 /* Inode logical block is misaligned */
 #define PR_1_MISALIGNED_CLUSTER                0x010074
 
+/* Inode has INLINE_DATA_FL flag but extended attribute not found */
+#define PR_1_INLINE_DATA_NO_ATTR       0x010075
+
+/* extents/inlinedata set on fifo/socket/device */
+#define PR_1_SPECIAL_EXTENTS_IDATA     0x010076
+
+/* idata/extent flag set and extent header found, clear idata flag */
+#define PR_1_CLEAR_INLINE_DATA_FOR_EXTENT      0x010077
+
+/* inlinedata/extent set and no extent header found, clear extent flag */
+#define PR_1_CLEAR_EXTENT_FOR_INLINE_DATA      0x010078
+
+/* inlinedata/extent set, clear both flags */
+#define PR_1_CLEAR_EXTENT_INLINE_DATA_FLAGS    0x010079
+
+/* inlinedata/extent set, clear inode */
+#define PR_1_CLEAR_EXTENT_INLINE_DATA_INODE    0x01007A
+
 /*
  * Pass 1b errors
  */
@@ -615,6 +657,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
 
@@ -851,6 +896,24 @@ 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
+
+/* 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
+
+/* bad inline directory size */
+#define PR_2_BAD_INLINE_DIR_SIZE       0x02004E
+
+/* fixing inline dir size failed */
+#define PR_2_FIX_INLINE_DIR_FAILED     0x02004F
+
 /*
  * Pass 3 errors
  */
@@ -927,6 +990,15 @@ 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
+
+/* Cannot allocate lost+found */
+#define PR_3_LPF_NO_SPACE              0x030019
+
+/* Insufficient space to recover lost files */
+#define PR_3_NO_SPACE_TO_RECOVER       0x03001A
+
 /*
  * Pass 3a --- rehashing diretories
  */
@@ -1049,6 +1121,12 @@ struct problem_context {
 /* Inode in use but group is marked INODE_UNINIT */
 #define PR_5_INODE_UNINIT              0x050019
 
+/* Inode bitmap checksum does not match */
+#define PR_5_INODE_BITMAP_CSUM_INVALID 0x05001A
+
+/* Block bitmap checksum does not match */
+#define PR_5_BLOCK_BITMAP_CSUM_INVALID 0x05001B
+
 /*
  * Post-Pass 5 errors
  */
index e4e5ae1..66d02b2 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,19 @@ 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;
+                               brelse(bh);
+                               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 +557,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 +592,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 +746,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 +815,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 +850,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 4b669f0..aaaaa19 100644 (file)
@@ -203,6 +203,8 @@ int main(int argc, char **argv)
                        break;
                }
        }
+       if (r)
+               region_free(r);
 }
 
 #endif /* TEST_PROGRAM */
index 8ff4883..e37e871 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,12 @@ 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);
+               int flags = fs->flags;
+               fs->flags |= EXT2_FLAG_IGNORE_CSUM_ERRORS;
+               fd->err = ext2fs_read_dir_block4(fs, *block_nr, dir, 0,
+                                                fd->dir);
+               fs->flags = (flags & EXT2_FLAG_IGNORE_CSUM_ERRORS) |
+                           (fs->flags & ~EXT2_FLAG_IGNORE_CSUM_ERRORS);
                if (fd->err)
                        return BLOCK_ABORT;
        }
@@ -119,20 +144,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 +175,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 +206,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 +303,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 +323,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 +366,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 +381,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 +394,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 +434,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 +446,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 +464,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 +481,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 +500,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 +524,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 +540,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 +567,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 +584,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 +687,7 @@ struct write_dir_struct {
        errcode_t       err;
        e2fsck_t        ctx;
        blk64_t         cleared;
+       ext2_ino_t      dir;
 };
 
 /*
@@ -641,11 +702,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;
                /*
@@ -660,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;
@@ -686,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);
@@ -723,6 +797,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);
@@ -741,6 +820,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;
@@ -844,7 +924,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);
 
@@ -872,8 +952,7 @@ void e2fsck_rehash_directories(e2fsck_t ctx)
                        if (!ext2fs_u32_list_iterate(iter, &ino))
                                break;
                }
-               if (ino == ctx->lost_and_found)
-                       continue;
+
                pctx.dir = ino;
                if (first) {
                        fix_problem(ctx, PR_3A_PASS_HEADER, &pctx);
index e4d60ce..421cd3e 100644 (file)
@@ -392,6 +392,7 @@ void sigcatcher_setup(void)
        sigaction(SIGILL, &sa, 0);
        sigaction(SIGBUS, &sa, 0);
        sigaction(SIGSEGV, &sa, 0);
+       sigaction(SIGABRT, &sa, 0);
 }      
 
 
index 768316a..1e7e749 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;
@@ -570,7 +570,9 @@ void check_super_block(e2fsck_t ctx)
                return;
        }
 
-       should_be = sb->s_inodes_per_group * fs->group_desc_count;
+       should_be = (blk64_t)sb->s_inodes_per_group * fs->group_desc_count;
+       if (should_be > UINT_MAX)
+               should_be = UINT_MAX;
        if (sb->s_inodes_count != should_be) {
                pctx.ino = sb->s_inodes_count;
                pctx.ino2 = should_be;
@@ -580,6 +582,19 @@ void check_super_block(e2fsck_t ctx)
                }
        }
 
+       /* Are metadata_csum and uninit_bg both set? */
+       if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+                                      EXT4_FEATURE_RO_COMPAT_METADATA_CSUM) &&
+           EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
+                                      EXT4_FEATURE_RO_COMPAT_GDT_CSUM) &&
+           fix_problem(ctx, PR_0_META_AND_GDT_CSUM_SET, &pctx)) {
+               fs->super->s_feature_ro_compat &=
+                       ~EXT4_FEATURE_RO_COMPAT_GDT_CSUM;
+               ext2fs_mark_super_dirty(fs);
+               for (i = 0; i < fs->group_desc_count; i++)
+                       ext2fs_group_desc_csum_set(fs, i);
+       }
+
        /* Is 64bit set and extents unset? */
        if (EXT2_HAS_INCOMPAT_FEATURE(fs->super,
                                      EXT4_FEATURE_INCOMPAT_64BIT) &&
@@ -609,8 +624,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;
 
@@ -741,6 +755,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 628faeb..c1d5b62 100644 (file)
@@ -1161,7 +1161,14 @@ 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;
+               }
+       } else
+               com_err(ctx->program_name, retval, "%s",
+                       _("while reading MMP block"));
        return retval;
 }
 
@@ -1280,6 +1287,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) {
index fa529b4..8237328 100644 (file)
@@ -267,6 +267,7 @@ void e2fsck_read_bitmaps(e2fsck_t ctx)
        errcode_t       retval;
        const char      *old_op;
        unsigned int    save_type;
+       int             flags;
 
        if (ctx->invalid_bitmaps) {
                com_err(ctx->program_name, 0,
@@ -278,7 +279,11 @@ 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);
+       flags = ctx->fs->flags;
+       ctx->fs->flags |= EXT2_FLAG_IGNORE_CSUM_ERRORS;
        retval = ext2fs_read_bitmaps(fs);
+       ctx->fs->flags = (flags & EXT2_FLAG_IGNORE_CSUM_ERRORS) |
+                        (ctx->fs->flags & ~EXT2_FLAG_IGNORE_CSUM_ERRORS);
        fs->default_bitmap_type = save_type;
        ehandler_operation(old_op);
        if (retval) {
index 5f4cc69..0697431 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 87d081f..db6d7d7 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 6cabd36..e020a77 100644 (file)
@@ -55,6 +55,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 $<
 @ELF_CMT@      $(Q) $(CC) $(ALL_CFLAGS) -fPIC -o elfshared/$*.o -c $<
 @BSDLIB_CMT@   $(Q) $(CC) $(ALL_CFLAGS) $(BSDLIB_PIC_FLAG) -o pic/$*.o -c $<
index 37e80ef..d6809e1 100644 (file)
@@ -110,6 +110,7 @@ struct ext2_super_block {
 #define EXT4_FEATURE_RO_COMPAT_DIR_NLINK       0x0020
 #define EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE     0x0040
 #define EXT4_FEATURE_RO_COMPAT_QUOTA           0x0100
+#define EXT4_FEATURE_RO_COMPAT_METADATA_CSUM   0x0400
 
 /* for s_feature_incompat */
 #define EXT2_FEATURE_INCOMPAT_FILETYPE         0x0002
index 50cf312..4dcc966 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
 
@@ -61,6 +70,9 @@
 /* Define to 1 if you have the `asprintf' function. */
 #undef HAVE_ASPRINTF
 
+/* Define to 1 if you have the <attr/xattr.h> header file. */
+#undef HAVE_ATTR_XATTR_H
+
 /* Define to 1 if you have the `backtrace' function. */
 #undef HAVE_BACKTRACE
 
 /* Define to 1 if you have the <linux/major.h> header file. */
 #undef HAVE_LINUX_MAJOR_H
 
+/* Define to 1 if you have the `llistxattr' function. */
+#undef HAVE_LLISTXATTR
+
 /* Define to 1 if you have the `llseek' function. */
 #undef HAVE_LLSEEK
 
index 1c71c1c..7286552 100644 (file)
@@ -55,6 +55,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 $<
 @ELF_CMT@      $(Q) $(CC) $(ALL_CFLAGS) -fPIC -o elfshared/$*.o -c $<
 @BSDLIB_CMT@   $(Q) $(CC) $(ALL_CFLAGS) $(BSDLIB_PIC_FLAG) -o pic/$*.o -c $<
index 1d3e689..d0e29b8 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 6f741c0..a7ea38a 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 e2f8ce5..f116ac3 100644 (file)
@@ -50,6 +50,7 @@ static struct flags_name flags_array[] = {
        { EXT4_EXTENTS_FL, "e", "Extents" },
        { EXT4_HUGE_FILE_FL, "h", "Huge_file" },
        { FS_NOCOW_FL, "C", "No_COW" },
+       { EXT4_INLINE_DATA_FL, "N", "Inline_Data" },
        { 0, NULL, NULL }
 };
 
index 68c3baf..dbf7c1a 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 $<
 @ELF_CMT@      $(Q) $(CC) $(ALL_CFLAGS) -fPIC -o elfshared/$*.o -c $<
 @BSDLIB_CMT@   $(Q) $(CC) $(ALL_CFLAGS) $(BSDLIB_PIC_FLAG) -o pic/$*.o -c $<
index 4fc149a..f88545d 100644 (file)
@@ -19,7 +19,7 @@ MK_CMDS=      _SS_DIR_OVERRIDE=../ss ../ss/mk_cmds
 DEBUG_OBJS= debug_cmds.o extent_cmds.o tst_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_inode.o zap.o \
-       quota.o tst_libext2fs.o
+       xattrs.o quota.o tst_libext2fs.o create_inode.o
 
 DEBUG_SRCS= debug_cmds.c extent_cmds.c tst_cmds.c \
        $(top_srcdir)/debugfs/debugfs.c \
@@ -37,7 +37,9 @@ DEBUG_SRCS= debug_cmds.c extent_cmds.c tst_cmds.c \
        $(top_srcdir)/debugfs/extent_inode.c \
        $(top_srcdir)/debugfs/zap.c \
        $(top_srcdir)/debugfs/quota.c \
-       $(top_srcdir)/misc/e2freefrag.c
+       $(top_srcdir)/debugfs/xattrs.c \
+       $(top_srcdir)/misc/e2freefrag.c \
+       $(top_srcdir)/misc/create_inode.c
 
 OBJS= $(DEBUGFS_LIB_OBJS) $(RESIZE_LIB_OBJS) $(E2IMAGE_LIB_OBJS) \
        $(TEST_IO_LIB_OBJS) \
@@ -74,6 +76,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 \
@@ -82,6 +85,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 \
@@ -147,6 +151,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 \
@@ -155,6 +160,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 \
@@ -226,6 +232,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 $<
 @ELF_CMT@      $(Q) $(CC) $(ALL_CFLAGS) -fPIC -o elfshared/$*.o -c $<
 @BSDLIB_CMT@   $(Q) $(CC) $(ALL_CFLAGS) $(BSDLIB_PIC_FLAG) -o pic/$*.o -c $<
@@ -384,10 +391,18 @@ quota.o: $(top_srcdir)/debugfs/quota.c
        $(E) "  CC $<"
        $(Q) $(CC) $(ALL_CFLAGS) -c $< -o $@
 
+xattrs.o: $(top_srcdir)/debugfs/xattrs.c
+       $(E) "  CC $<"
+       $(Q) $(CC) $(ALL_CFLAGS) -c $< -o $@
+
 e2freefrag.o: $(top_srcdir)/misc/e2freefrag.c
        $(E) "  CC $<"
        $(Q) $(CC) $(ALL_CFLAGS) -DDEBUGFS -I$(top_srcdir)/debugfs -c $< -o $@
 
+create_inode.o: $(top_srcdir)/misc/create_inode.c
+       $(E) "  CC $<"
+       $(Q) $(CC) $(ALL_CFLAGS) -DDEBUGFS -c $< -o $@
+
 filefrag.o: $(top_srcdir)/debugfs/filefrag.c
        $(E) "  CC $<"
        $(Q) $(CC) $(ALL_CFLAGS) -c $< -o $@
@@ -433,6 +448,11 @@ tst_inline: $(srcdir)/inline.c $(STATIC_LIBEXT2FS) $(DEPSTATIC_LIBCOM_ERR)
                $(ALL_LDFLAGS) -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 $@"
@@ -452,7 +472,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_libext2fs
+    tst_inline tst_inline_data tst_libext2fs
        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
@@ -462,6 +482,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
@@ -701,7 +722,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 \
@@ -755,6 +776,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 \
@@ -803,6 +831,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 \
@@ -854,7 +889,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 \
@@ -904,7 +939,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 \
@@ -1030,8 +1065,10 @@ tst_libext2fs.o: $(srcdir)/tst_libext2fs.c $(top_builddir)/lib/config.h \
  $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/ext2_ext_attr.h \
  $(srcdir)/bitops.h $(top_srcdir)/lib/ss/ss.h $(top_builddir)/lib/ss/ss_err.h \
  $(top_srcdir)/debugfs/debugfs.h $(srcdir)/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
+ $(top_srcdir)/debugfs/../misc/create_inode.h $(top_srcdir)/lib/e2p/e2p.h \
+ $(top_srcdir)/debugfs/../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
 debug_cmds.o: debug_cmds.c $(top_srcdir)/lib/ss/ss.h \
  $(top_builddir)/lib/ss/ss_err.h $(top_srcdir)/lib/et/com_err.h
 extent_cmds.o: extent_cmds.c $(top_srcdir)/lib/ss/ss.h \
@@ -1045,9 +1082,10 @@ debugfs.o: $(top_srcdir)/debugfs/debugfs.c $(top_builddir)/lib/config.h \
  $(top_builddir)/lib/ext2fs/ext2_types.h $(srcdir)/ext2fs.h \
  $(srcdir)/ext3_extents.h $(srcdir)/ext2_io.h \
  $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/ext2_ext_attr.h \
- $(srcdir)/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 \
+ $(srcdir)/bitops.h $(top_srcdir)/debugfs/../misc/create_inode.h \
+ $(top_srcdir)/lib/e2p/e2p.h $(top_srcdir)/debugfs/../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)/debugfs/../version.h $(top_srcdir)/debugfs/jfs_user.h \
  $(srcdir)/kernel-jbd.h $(srcdir)/jfs_compat.h $(srcdir)/kernel-list.h
 util.o: $(top_srcdir)/debugfs/util.c $(top_builddir)/lib/config.h \
@@ -1057,9 +1095,10 @@ util.o: $(top_srcdir)/debugfs/util.c $(top_builddir)/lib/config.h \
  $(top_builddir)/lib/ext2fs/ext2_types.h $(srcdir)/ext2fs.h \
  $(srcdir)/ext3_extents.h $(srcdir)/ext2_io.h \
  $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/ext2_ext_attr.h \
- $(srcdir)/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
+ $(srcdir)/bitops.h $(top_srcdir)/debugfs/../misc/create_inode.h \
+ $(top_srcdir)/lib/e2p/e2p.h $(top_srcdir)/debugfs/../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: $(top_srcdir)/debugfs/ncheck.c $(top_builddir)/lib/config.h \
  $(top_builddir)/lib/dirpaths.h $(top_srcdir)/debugfs/debugfs.h \
  $(top_srcdir)/lib/ss/ss.h $(top_builddir)/lib/ss/ss_err.h \
@@ -1067,9 +1106,10 @@ ncheck.o: $(top_srcdir)/debugfs/ncheck.c $(top_builddir)/lib/config.h \
  $(top_builddir)/lib/ext2fs/ext2_types.h $(srcdir)/ext2fs.h \
  $(srcdir)/ext3_extents.h $(srcdir)/ext2_io.h \
  $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/ext2_ext_attr.h \
- $(srcdir)/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
+ $(srcdir)/bitops.h $(top_srcdir)/debugfs/../misc/create_inode.h \
+ $(top_srcdir)/lib/e2p/e2p.h $(top_srcdir)/debugfs/../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: $(top_srcdir)/debugfs/icheck.c $(top_builddir)/lib/config.h \
  $(top_builddir)/lib/dirpaths.h $(top_srcdir)/debugfs/debugfs.h \
  $(top_srcdir)/lib/ss/ss.h $(top_builddir)/lib/ss/ss_err.h \
@@ -1077,9 +1117,10 @@ icheck.o: $(top_srcdir)/debugfs/icheck.c $(top_builddir)/lib/config.h \
  $(top_builddir)/lib/ext2fs/ext2_types.h $(srcdir)/ext2fs.h \
  $(srcdir)/ext3_extents.h $(srcdir)/ext2_io.h \
  $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/ext2_ext_attr.h \
- $(srcdir)/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
+ $(srcdir)/bitops.h $(top_srcdir)/debugfs/../misc/create_inode.h \
+ $(top_srcdir)/lib/e2p/e2p.h $(top_srcdir)/debugfs/../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: $(top_srcdir)/debugfs/ls.c $(top_builddir)/lib/config.h \
  $(top_builddir)/lib/dirpaths.h $(top_srcdir)/debugfs/debugfs.h \
  $(top_srcdir)/lib/ss/ss.h $(top_builddir)/lib/ss/ss_err.h \
@@ -1087,9 +1128,10 @@ ls.o: $(top_srcdir)/debugfs/ls.c $(top_builddir)/lib/config.h \
  $(top_builddir)/lib/ext2fs/ext2_types.h $(srcdir)/ext2fs.h \
  $(srcdir)/ext3_extents.h $(srcdir)/ext2_io.h \
  $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/ext2_ext_attr.h \
- $(srcdir)/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
+ $(srcdir)/bitops.h $(top_srcdir)/debugfs/../misc/create_inode.h \
+ $(top_srcdir)/lib/e2p/e2p.h $(top_srcdir)/debugfs/../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: $(top_srcdir)/debugfs/lsdel.c $(top_builddir)/lib/config.h \
  $(top_builddir)/lib/dirpaths.h $(top_srcdir)/debugfs/debugfs.h \
  $(top_srcdir)/lib/ss/ss.h $(top_builddir)/lib/ss/ss_err.h \
@@ -1097,9 +1139,10 @@ lsdel.o: $(top_srcdir)/debugfs/lsdel.c $(top_builddir)/lib/config.h \
  $(top_builddir)/lib/ext2fs/ext2_types.h $(srcdir)/ext2fs.h \
  $(srcdir)/ext3_extents.h $(srcdir)/ext2_io.h \
  $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/ext2_ext_attr.h \
- $(srcdir)/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
+ $(srcdir)/bitops.h $(top_srcdir)/debugfs/../misc/create_inode.h \
+ $(top_srcdir)/lib/e2p/e2p.h $(top_srcdir)/debugfs/../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: $(top_srcdir)/debugfs/dump.c $(top_builddir)/lib/config.h \
  $(top_builddir)/lib/dirpaths.h $(top_srcdir)/debugfs/debugfs.h \
  $(top_srcdir)/lib/ss/ss.h $(top_builddir)/lib/ss/ss_err.h \
@@ -1107,9 +1150,10 @@ dump.o: $(top_srcdir)/debugfs/dump.c $(top_builddir)/lib/config.h \
  $(top_builddir)/lib/ext2fs/ext2_types.h $(srcdir)/ext2fs.h \
  $(srcdir)/ext3_extents.h $(srcdir)/ext2_io.h \
  $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/ext2_ext_attr.h \
- $(srcdir)/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
+ $(srcdir)/bitops.h $(top_srcdir)/debugfs/../misc/create_inode.h \
+ $(top_srcdir)/lib/e2p/e2p.h $(top_srcdir)/debugfs/../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: $(top_srcdir)/debugfs/set_fields.c $(top_builddir)/lib/config.h \
  $(top_builddir)/lib/dirpaths.h $(top_srcdir)/debugfs/debugfs.h \
  $(top_srcdir)/lib/ss/ss.h $(top_builddir)/lib/ss/ss_err.h \
@@ -1117,9 +1161,10 @@ set_fields.o: $(top_srcdir)/debugfs/set_fields.c $(top_builddir)/lib/config.h \
  $(top_builddir)/lib/ext2fs/ext2_types.h $(srcdir)/ext2fs.h \
  $(srcdir)/ext3_extents.h $(srcdir)/ext2_io.h \
  $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/ext2_ext_attr.h \
- $(srcdir)/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
+ $(srcdir)/bitops.h $(top_srcdir)/debugfs/../misc/create_inode.h \
+ $(top_srcdir)/lib/e2p/e2p.h $(top_srcdir)/debugfs/../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
 logdump.o: $(top_srcdir)/debugfs/logdump.c $(top_builddir)/lib/config.h \
  $(top_builddir)/lib/dirpaths.h $(top_srcdir)/debugfs/debugfs.h \
  $(top_srcdir)/lib/ss/ss.h $(top_builddir)/lib/ss/ss_err.h \
@@ -1127,10 +1172,12 @@ logdump.o: $(top_srcdir)/debugfs/logdump.c $(top_builddir)/lib/config.h \
  $(top_builddir)/lib/ext2fs/ext2_types.h $(srcdir)/ext2fs.h \
  $(srcdir)/ext3_extents.h $(srcdir)/ext2_io.h \
  $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/ext2_ext_attr.h \
- $(srcdir)/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)/debugfs/jfs_user.h \
- $(srcdir)/kernel-jbd.h $(srcdir)/jfs_compat.h $(srcdir)/kernel-list.h
+ $(srcdir)/bitops.h $(top_srcdir)/debugfs/../misc/create_inode.h \
+ $(top_srcdir)/lib/e2p/e2p.h $(top_srcdir)/debugfs/../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)/debugfs/jfs_user.h $(srcdir)/kernel-jbd.h \
+ $(srcdir)/jfs_compat.h $(srcdir)/kernel-list.h
 htree.o: $(top_srcdir)/debugfs/htree.c $(top_builddir)/lib/config.h \
  $(top_builddir)/lib/dirpaths.h $(top_srcdir)/debugfs/debugfs.h \
  $(top_srcdir)/lib/ss/ss.h $(top_builddir)/lib/ss/ss_err.h \
@@ -1138,9 +1185,10 @@ htree.o: $(top_srcdir)/debugfs/htree.c $(top_builddir)/lib/config.h \
  $(top_builddir)/lib/ext2fs/ext2_types.h $(srcdir)/ext2fs.h \
  $(srcdir)/ext3_extents.h $(srcdir)/ext2_io.h \
  $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/ext2_ext_attr.h \
- $(srcdir)/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
+ $(srcdir)/bitops.h $(top_srcdir)/debugfs/../misc/create_inode.h \
+ $(top_srcdir)/lib/e2p/e2p.h $(top_srcdir)/debugfs/../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
 unused.o: $(top_srcdir)/debugfs/unused.c $(top_builddir)/lib/config.h \
  $(top_builddir)/lib/dirpaths.h $(top_srcdir)/debugfs/debugfs.h \
  $(top_srcdir)/lib/ss/ss.h $(top_builddir)/lib/ss/ss_err.h \
@@ -1148,9 +1196,10 @@ unused.o: $(top_srcdir)/debugfs/unused.c $(top_builddir)/lib/config.h \
  $(top_builddir)/lib/ext2fs/ext2_types.h $(srcdir)/ext2fs.h \
  $(srcdir)/ext3_extents.h $(srcdir)/ext2_io.h \
  $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/ext2_ext_attr.h \
- $(srcdir)/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
+ $(srcdir)/bitops.h $(top_srcdir)/debugfs/../misc/create_inode.h \
+ $(top_srcdir)/lib/e2p/e2p.h $(top_srcdir)/debugfs/../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
 filefrag.o: $(top_srcdir)/debugfs/filefrag.c $(top_builddir)/lib/config.h \
  $(top_builddir)/lib/dirpaths.h $(top_srcdir)/debugfs/debugfs.h \
  $(top_srcdir)/lib/ss/ss.h $(top_builddir)/lib/ss/ss_err.h \
@@ -1158,9 +1207,10 @@ filefrag.o: $(top_srcdir)/debugfs/filefrag.c $(top_builddir)/lib/config.h \
  $(top_builddir)/lib/ext2fs/ext2_types.h $(srcdir)/ext2fs.h \
  $(srcdir)/ext3_extents.h $(srcdir)/ext2_io.h \
  $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/ext2_ext_attr.h \
- $(srcdir)/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
+ $(srcdir)/bitops.h $(top_srcdir)/debugfs/../misc/create_inode.h \
+ $(top_srcdir)/lib/e2p/e2p.h $(top_srcdir)/debugfs/../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
 extent_inode.o: $(top_srcdir)/debugfs/extent_inode.c \
  $(top_builddir)/lib/config.h $(top_builddir)/lib/dirpaths.h \
  $(top_srcdir)/debugfs/debugfs.h $(top_srcdir)/lib/ss/ss.h \
@@ -1168,9 +1218,10 @@ extent_inode.o: $(top_srcdir)/debugfs/extent_inode.c \
  $(srcdir)/ext2_fs.h $(top_builddir)/lib/ext2fs/ext2_types.h \
  $(srcdir)/ext2fs.h $(srcdir)/ext3_extents.h $(srcdir)/ext2_io.h \
  $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/ext2_ext_attr.h \
- $(srcdir)/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
+ $(srcdir)/bitops.h $(top_srcdir)/debugfs/../misc/create_inode.h \
+ $(top_srcdir)/lib/e2p/e2p.h $(top_srcdir)/debugfs/../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
 zap.o: $(top_srcdir)/debugfs/zap.c $(top_builddir)/lib/config.h \
  $(top_builddir)/lib/dirpaths.h $(top_srcdir)/debugfs/debugfs.h \
  $(top_srcdir)/lib/ss/ss.h $(top_builddir)/lib/ss/ss_err.h \
@@ -1178,9 +1229,10 @@ zap.o: $(top_srcdir)/debugfs/zap.c $(top_builddir)/lib/config.h \
  $(top_builddir)/lib/ext2fs/ext2_types.h $(srcdir)/ext2fs.h \
  $(srcdir)/ext3_extents.h $(srcdir)/ext2_io.h \
  $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/ext2_ext_attr.h \
- $(srcdir)/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
+ $(srcdir)/bitops.h $(top_srcdir)/debugfs/../misc/create_inode.h \
+ $(top_srcdir)/lib/e2p/e2p.h $(top_srcdir)/debugfs/../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
 quota.o: $(top_srcdir)/debugfs/quota.c $(top_builddir)/lib/config.h \
  $(top_builddir)/lib/dirpaths.h $(top_srcdir)/debugfs/debugfs.h \
  $(top_srcdir)/lib/ss/ss.h $(top_builddir)/lib/ss/ss_err.h \
@@ -1188,12 +1240,31 @@ quota.o: $(top_srcdir)/debugfs/quota.c $(top_builddir)/lib/config.h \
  $(top_builddir)/lib/ext2fs/ext2_types.h $(srcdir)/ext2fs.h \
  $(srcdir)/ext3_extents.h $(srcdir)/ext2_io.h \
  $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/ext2_ext_attr.h \
- $(srcdir)/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
+ $(srcdir)/bitops.h $(top_srcdir)/debugfs/../misc/create_inode.h \
+ $(top_srcdir)/lib/e2p/e2p.h $(top_srcdir)/debugfs/../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
+xattrs.o: $(top_srcdir)/debugfs/xattrs.c $(top_builddir)/lib/config.h \
+ $(top_builddir)/lib/dirpaths.h $(top_srcdir)/debugfs/debugfs.h \
+ $(top_srcdir)/lib/ss/ss.h $(top_builddir)/lib/ss/ss_err.h \
+ $(top_srcdir)/lib/et/com_err.h $(srcdir)/ext2_fs.h \
+ $(top_builddir)/lib/ext2fs/ext2_types.h $(srcdir)/ext2fs.h \
+ $(srcdir)/ext3_extents.h $(srcdir)/ext2_io.h \
+ $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/ext2_ext_attr.h \
+ $(srcdir)/bitops.h $(top_srcdir)/debugfs/../misc/create_inode.h \
+ $(top_srcdir)/lib/e2p/e2p.h $(top_srcdir)/debugfs/../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
 e2freefrag.o: $(top_srcdir)/misc/e2freefrag.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 \
  $(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 $(top_srcdir)/misc/e2freefrag.h
+create_inode.o: $(top_srcdir)/misc/create_inode.c \
+ $(top_srcdir)/misc/create_inode.h $(top_srcdir)/lib/et/com_err.h \
+ $(top_srcdir)/lib/e2p/e2p.h $(srcdir)/ext2_fs.h \
+ $(top_builddir)/lib/ext2fs/ext2_types.h $(srcdir)/ext2fs.h \
+ $(srcdir)/ext3_extents.h $(srcdir)/ext2_io.h \
+ $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/ext2_ext_attr.h \
+ $(srcdir)/bitops.h $(top_srcdir)/misc/nls-enable.h
index 2f7b654..89082a7 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 2061b9d..578fd7f 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 a449dc3..3d3697c 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 3760d61..3e1952f 100644 (file)
@@ -241,16 +241,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 894293a..87946c7 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 fdbd330..8d1778d 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
@@ -329,7 +327,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;
@@ -394,7 +392,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;
@@ -891,7 +889,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;
@@ -902,7 +900,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
@@ -926,7 +924,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)
@@ -953,7 +951,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 3367335..93b64ce 100644 (file)
@@ -200,6 +200,21 @@ static struct ext4_group_desc *ext4fs_group_desc(ext2_filsys fs,
 }
 
 /*
+ * Return the block bitmap checksum of a group
+ */
+__u32 ext2fs_block_bitmap_checksum(ext2_filsys fs, dgrp_t group)
+{
+       struct ext4_group_desc *gdp;
+       __u32 csum;
+
+       gdp = ext4fs_group_desc(fs, fs->group_desc, group);
+       csum = gdp->bg_block_bitmap_csum_lo;
+       if (fs->super->s_desc_size >= EXT4_BG_BLOCK_BITMAP_CSUM_HI_LOCATION)
+               csum |= ((__u32)gdp->bg_block_bitmap_csum_hi << 16);
+       return csum;
+}
+
+/*
  * Return the block bitmap block of a group
  */
 blk64_t ext2fs_block_bitmap_loc(ext2_filsys fs, dgrp_t group)
@@ -227,6 +242,21 @@ void ext2fs_block_bitmap_loc_set(ext2_filsys fs, dgrp_t group, blk64_t blk)
 }
 
 /*
+ * Return the inode bitmap checksum of a group
+ */
+__u32 ext2fs_inode_bitmap_checksum(ext2_filsys fs, dgrp_t group)
+{
+       struct ext4_group_desc *gdp;
+       __u32 csum;
+
+       gdp = ext4fs_group_desc(fs, fs->group_desc, group);
+       csum = gdp->bg_inode_bitmap_csum_lo;
+       if (fs->super->s_desc_size >= EXT4_BG_INODE_BITMAP_CSUM_HI_END)
+               csum |= ((__u32)gdp->bg_inode_bitmap_csum_hi << 16);
+       return csum;
+}
+
+/*
  * Return the inode bitmap block of a group
  */
 blk64_t ext2fs_inode_bitmap_loc(ext2_filsys fs, dgrp_t group)
index b8c6879..601129d 100644 (file)
@@ -345,6 +345,13 @@ errcode_t ext2fs_block_iterate3(ext2_filsys fs,
                return ctx.errcode;
 
        /*
+        * An inode with inline data has no blocks over which to
+        * iterate, so return an error code indicating this fact.
+        */
+       if (inode.i_flags & EXT4_INLINE_DATA_FL)
+               return EXT2_ET_INLINE_DATA_CANT_ITERATE;
+
+       /*
         * Check to see if we need to limit large files
         */
        if (flags & BLOCK_FLAG_NO_LARGE) {
index db2fd72..c1d0e6f 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 9deba46..d8c7a3c 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 1f99113..4f2f195 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
@@ -351,14 +369,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);
 
@@ -387,19 +407,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:
        /*
@@ -418,6 +427,10 @@ write_primary_superblock_only:
        ext2fs_swap_super(super_shadow);
 #endif
 
+       retval = ext2fs_superblock_csum_set(fs, super_shadow);
+       if (retval)
+               return retval;
+
        if (!(flags & EXT2_FLAG_FLUSH_NO_SYNC))
                retval = io_channel_flush(fs->io);
        retval = write_primary_superblock(fs, super_shadow);
index 2512528..624ad77 100644 (file)
@@ -32,7 +32,6 @@
 #include <stdint.h>
 #include <stdlib.h>
 #include <stdio.h>
-#define __force
 #define min(x, y)              ((x) > (y) ? (y) : (x))
 #define __ALIGN_KERNEL_MASK(x, mask)   (((x) + (mask)) & ~(mask))
 #define __ALIGN_KERNEL(x, a)   __ALIGN_KERNEL_MASK(x, (__typeof__(x))(a) - 1)
 #endif
 
 #if CRC_LE_BITS > 8
-# define tole(x) (__force uint32_t) __constant_cpu_to_le32(x)
+# define tole(x) __constant_cpu_to_le32(x)
 #else
 # define tole(x) (x)
 #endif
 
 #if CRC_BE_BITS > 8
-# define tobe(x) (__force uint32_t) __constant_cpu_to_be32(x)
+# define tobe(x) __constant_cpu_to_be32(x)
 #else
 # define tobe(x) (x)
 #endif
 
 #include "crc32c_table.h"
 
-#if CRC_LE_BITS == 32
-/* slice by 4 algorithm */
-static uint32_t crc32c_le_body(uint32_t crc, uint8_t const *buf, size_t len)
-{
-       const uint8_t *p8;
-       const uint32_t *p32;
-       size_t init_bytes;
-       size_t words;
-       size_t end_bytes;
-       size_t i;
-       uint32_t q;
-       uint8_t i0, i1, i2, i3;
-
-       crc = (__force uint32_t) __cpu_to_le32(crc);
-
-       /* unroll loop into 'init_bytes' odd bytes followed by
-        * 'words' aligned 4 byte words followed by
-        * 'end_bytes' odd bytes at the end */
-       p8 = buf;
-       p32 = (uint32_t *)PTR_ALIGN(p8, 4);
-       init_bytes = min((uintptr_t)p32 - (uintptr_t)p8, len);
-       words = (len - init_bytes) >> 2;
-       end_bytes = (len - init_bytes) & 3;
-
-       for (i = 0; i < init_bytes; i++) {
-#ifndef WORDS_BIGENDIAN
-               i0 = *p8++ ^ crc;
-               crc = t0_le[i0] ^ (crc >> 8);
-#else
-               i0 = *p8++ ^ (crc >> 24);
-               crc = t0_le[i0] ^ (crc << 8);
-#endif
-       }
-
-       /* using pre-increment below slightly faster */
-       p32--;
-
-       for (i = 0; i < words; i++) {
-#ifndef WORDS_BIGENDIAN
-               q = *++p32 ^ crc;
-               i3 = q;
-               i2 = q >> 8;
-               i1 = q >> 16;
-               i0 = q >> 24;
-               crc = t3_le[i3] ^ t2_le[i2] ^ t1_le[i1] ^ t0_le[i0];
-#else
-               q = *++p32 ^ crc;
-               i3 = q >> 24;
-               i2 = q >> 16;
-               i1 = q >> 8;
-               i0 = q;
-               crc = t3_le[i3] ^ t2_le[i2] ^ t1_le[i1] ^ t0_le[i0];
-#endif
-       }
+#if CRC_LE_BITS > 8 || CRC_BE_BITS > 8
 
-       p8 = (uint8_t *)(++p32);
-
-       for (i = 0; i < end_bytes; i++) {
-#ifndef WORDS_BIGENDIAN
-               i0 = *p8++ ^ crc;
-               crc = t0_le[i0] ^ (crc >> 8);
-#else
-               i0 = *p8++ ^ (crc >> 24);
-               crc = t0_le[i0] ^ (crc << 8);
-#endif
-       }
-
-       return __le32_to_cpu((__force __le32)crc);
-}
-#endif
-
-#if CRC_BE_BITS == 32
-static uint32_t crc32c_be_body(uint32_t crc, uint8_t const *buf, size_t len)
+/* implements slicing-by-4 or slicing-by-8 algorithm */
+static inline uint32_t
+crc32_body(uint32_t crc, unsigned char const *buf, size_t len,
+          const uint32_t (*tab)[256])
 {
-       const uint8_t *p8;
-       const uint32_t *p32;
-       size_t init_bytes;
-       size_t words;
-       size_t end_bytes;
-       size_t i;
-       uint32_t q;
-       uint8_t i0, i1, i2, i3;
-
-       crc = (__force uint32_t) __cpu_to_be32(crc);
-
-       p8 = buf;
-       p32 = (uint32_t *)PTR_ALIGN(p8, 4);
-       init_bytes = min((uintptr_t)p32 - (uintptr_t)p8, len);
-       words = (len - init_bytes) >> 2;
-       end_bytes = (len - init_bytes) & 3;
-
-       for (i = 0; i < init_bytes; i++) {
-#ifndef WORDS_BIGENDIAN
-               i0 = *p8++ ^ crc;
-               crc = t0_be[i0] ^ (crc >> 8);
-#else
-               i0 = *p8++ ^ (crc >> 24);
-               crc = t0_be[i0] ^ (crc << 8);
-#endif
-       }
-
-       p32--;
-
-       for (i = 0; i < words; i++) {
-#ifndef WORDS_BIGENDIAN
-               q = *++p32 ^ crc;
-               i3 = q;
-               i2 = q >> 8;
-               i1 = q >> 16;
-               i0 = q >> 24;
-               crc = t3_be[i3] ^ t2_be[i2] ^ t1_be[i1] ^ t0_be[i0];
-#else
-               q = *++p32 ^ crc;
-               i3 = q >> 24;
-               i2 = q >> 16;
-               i1 = q >> 8;
-               i0 = q;
-               crc = t3_be[i3] ^ t2_be[i2] ^ t1_be[i1] ^ t0_be[i0];
-#endif
-       }
-
-       p8 = (uint8_t *)(++p32);
-
-       for (i = 0; i < end_bytes; i++) {
-#ifndef WORDS_BIGENDIAN
-               i0 = *p8++ ^ crc;
-               crc = t0_be[i0] ^ (crc >> 8);
-#else
-               i0 = *p8++ ^ (crc >> 24);
-               crc = t0_be[i0] ^ (crc << 8);
-#endif
-       }
-
-       return __be32_to_cpu((__force __be32)crc);
-}
-#endif
-
-#if CRC_LE_BITS == 64
-/* slice by 8 algorithm */
-static uint32_t crc32c_le_body(uint32_t crc, uint8_t const *buf, size_t len)
-{
-       const uint8_t *p8;
-       const uint32_t *p32;
-       size_t init_bytes;
-       size_t words;
-       size_t end_bytes;
-       size_t i;
-       uint32_t q;
-       uint8_t i0, i1, i2, i3;
-
-       crc = (__force uint32_t) __cpu_to_le32(crc);
-
-       p8 = buf;
-       p32 = (const uint32_t *)PTR_ALIGN(p8, 8);
-       init_bytes = min((uintptr_t)p32 - (uintptr_t)p8, len);
-       words = (len - init_bytes) >> 3;
-       end_bytes = (len - init_bytes) & 7;
-
-       for (i = 0; i < init_bytes; i++) {
-#ifndef WORDS_BIGENDIAN
-               i0 = *p8++ ^ crc;
-               crc = t0_le[i0] ^ (crc >> 8);
-#else
-               i0 = *p8++ ^ (crc >> 24);
-               crc = t0_le[i0] ^ (crc << 8);
-#endif
-       }
-
-       p32--;
-
-       for (i = 0; i < words; i++) {
-#ifndef WORDS_BIGENDIAN
-               q = *++p32 ^ crc;
-               i3 = q;
-               i2 = q >> 8;
-               i1 = q >> 16;
-               i0 = q >> 24;
-               crc = t7_le[i3] ^ t6_le[i2] ^ t5_le[i1] ^ t4_le[i0];
-
-               q = *++p32;
-               i3 = q;
-               i2 = q >> 8;
-               i1 = q >> 16;
-               i0 = q >> 24;
-               crc ^= t3_le[i3] ^ t2_le[i2] ^ t1_le[i1] ^ t0_le[i0];
-#else
-               q = *++p32 ^ crc;
-               i3 = q >> 24;
-               i2 = q >> 16;
-               i1 = q >> 8;
-               i0 = q;
-               crc = t7_le[i3] ^ t6_le[i2] ^ t5_le[i1] ^ t4_le[i0];
-
-               q = *++p32;
-               i3 = q >> 24;
-               i2 = q >> 16;
-               i1 = q >> 8;
-               i0 = q;
-               crc ^= t3_le[i3] ^ t2_le[i2] ^ t1_le[i1] ^ t0_le[i0];
-#endif
-       }
-
-       p8 = (const uint8_t *)(++p32);
-
-       for (i = 0; i < end_bytes; i++) {
-#ifndef WORDS_BIGENDIAN
-               i0 = *p8++ ^ crc;
-               crc = t0_le[i0] ^ (crc >> 8);
-#else
-               i0 = *p8++ ^ (crc >> 24);
-               crc = t0_le[i0] ^ (crc << 8);
-#endif
-       }
-
-       return __le32_to_cpu(crc);
-}
-#endif
-
-#if CRC_BE_BITS == 64
-static uint32_t crc32c_be_body(uint32_t crc, uint8_t const *buf, size_t len)
-{
-       const uint8_t *p8;
-       const uint32_t *p32;
-       size_t init_bytes;
-       size_t words;
-       size_t end_bytes;
-       size_t i;
+# ifndef WORDS_BIGENDIAN
+#  define DO_CRC(x) (crc = t0[(crc ^ (x)) & 255] ^ (crc >> 8))
+#  define DO_CRC4 (t3[(q) & 255] ^ t2[(q >> 8) & 255] ^ \
+                  t1[(q >> 16) & 255] ^ t0[(q >> 24) & 255])
+#  define DO_CRC8 (t7[(q) & 255] ^ t6[(q >> 8) & 255] ^ \
+                  t5[(q >> 16) & 255] ^ t4[(q >> 24) & 255])
+# else
+#  define DO_CRC(x) (crc = t0[((crc >> 24) ^ (x)) & 255] ^ (crc << 8))
+#  define DO_CRC4 (t0[(q) & 255] ^ t1[(q >> 8) & 255] ^ \
+                  t2[(q >> 16) & 255] ^ t3[(q >> 24) & 255])
+#  define DO_CRC8 (t4[(q) & 255] ^ t5[(q >> 8) & 255] ^ \
+                  t6[(q >> 16) & 255] ^ t7[(q >> 24) & 255])
+# endif
+       const uint32_t *b;
+       size_t rem_len;
+       const uint32_t *t0 = tab[0], *t1 = tab[1], *t2 = tab[2], *t3 = tab[3];
+       const uint32_t *t4 = tab[4], *t5 = tab[5], *t6 = tab[6], *t7 = tab[7];
        uint32_t q;
-       uint8_t i0, i1, i2, i3;
-
-       crc = (__force uint32_t) __cpu_to_be32(crc);
 
-       p8 = buf;
-       p32 = (const uint32_t *)PTR_ALIGN(p8, 8);
-       init_bytes = min((uintptr_t)p32 - (uintptr_t)p8, len);
-       words = (len - init_bytes) >> 3;
-       end_bytes = (len - init_bytes) & 7;
-
-       for (i = 0; i < init_bytes; i++) {
-#ifndef WORDS_BIGENDIAN
-               i0 = *p8++ ^ crc;
-               crc = t0_be[i0] ^ (crc >> 8);
-#else
-               i0 = *p8++ ^ (crc >> 24);
-               crc = t0_be[i0] ^ (crc << 8);
-#endif
+       /* Align it */
+       if (unlikely((long)buf & 3 && len)) {
+               do {
+                       DO_CRC(*buf++);
+               } while ((--len) && ((long)buf)&3);
        }
 
-       p32--;
-
-       for (i = 0; i < words; i++) {
-#ifndef WORDS_BIGENDIAN
-               q = *++p32 ^ crc;
-               i3 = q;
-               i2 = q >> 8;
-               i1 = q >> 16;
-               i0 = q >> 24;
-               crc = t7_be[i3] ^ t6_be[i2] ^ t5_be[i1] ^ t4_be[i0];
-
-               q = *++p32;
-               i3 = q;
-               i2 = q >> 8;
-               i1 = q >> 16;
-               i0 = q >> 24;
-               crc ^= t3_be[i3] ^ t2_be[i2] ^ t1_be[i1] ^ t0_be[i0];
-#else
-               q = *++p32 ^ crc;
-               i3 = q >> 24;
-               i2 = q >> 16;
-               i1 = q >> 8;
-               i0 = q;
-               crc = t7_be[i3] ^ t6_be[i2] ^ t5_be[i1] ^ t4_be[i0];
+# if CRC_LE_BITS == 32
+       rem_len = len & 3;
+       len = len >> 2;
+# else
+       rem_len = len & 7;
+       len = len >> 3;
+# endif
 
-               q = *++p32;
-               i3 = q >> 24;
-               i2 = q >> 16;
-               i1 = q >> 8;
-               i0 = q;
-               crc ^= t3_be[i3] ^ t2_be[i2] ^ t1_be[i1] ^ t0_be[i0];
-#endif
+       b = (const uint32_t *)buf;
+       for (--b; len; --len) {
+               q = crc ^ *++b; /* use pre increment for speed */
+# if CRC_LE_BITS == 32
+               crc = DO_CRC4;
+# else
+               crc = DO_CRC8;
+               q = *++b;
+               crc ^= DO_CRC4;
+# endif
        }
-
-       p8 = (const uint8_t *)(++p32);
-
-       for (i = 0; i < end_bytes; i++) {
-#ifndef WORDS_BIGENDIAN
-               i0 = *p8++ ^ crc;
-               crc = t0_be[i0] ^ (crc >> 8);
-#else
-               i0 = *p8++ ^ (crc >> 24);
-               crc = t0_be[i0] ^ (crc << 8);
-#endif
+       len = rem_len;
+       /* And the last few bytes */
+       if (len) {
+               const uint8_t *p = (const uint8_t *)(b + 1) - 1;
+               do {
+                       DO_CRC(*++p); /* use pre increment for speed */
+               } while (--len);
        }
-
-       return __be32_to_cpu(crc);
+       return crc;
+#undef DO_CRC
+#undef DO_CRC4
+#undef DO_CRC8
 }
 #endif
 
 /**
- * crc32c_le() - Calculate bitwise little-endian CRC32c.
- * @crc: seed value for computation.  ~0 for ext4, sometimes 0 for
- *     other uses, or the previous crc32c value if computing incrementally.
+ * crc32_le() - Calculate bitwise little-endian Ethernet AUTODIN II CRC32
+ * @crc: seed value for computation.  ~0 for Ethernet, sometimes 0 for
+ *     other uses, or the previous crc32 value if computing incrementally.
  * @p: pointer to buffer over which CRC is run
  * @len: length of buffer @p
  */
-uint32_t ext2fs_crc32c_le(uint32_t crc, unsigned char const *p, size_t len)
+static inline uint32_t crc32_le_generic(uint32_t crc, unsigned char const *p,
+                                       size_t len, const uint32_t (*tab)[256],
+                                       uint32_t polynomial EXT2FS_ATTR((unused)))
 {
 #if CRC_LE_BITS == 1
        int i;
        while (len--) {
                crc ^= *p++;
                for (i = 0; i < 8; i++)
-                       crc = (crc >> 1) ^ ((crc & 1) ? CRCPOLY_LE : 0);
+                       crc = (crc >> 1) ^ ((crc & 1) ? polynomial : 0);
        }
 # elif CRC_LE_BITS == 2
        while (len--) {
                crc ^= *p++;
-               crc = (crc >> 2) ^ t0_le[crc & 0x03];
-               crc = (crc >> 2) ^ t0_le[crc & 0x03];
-               crc = (crc >> 2) ^ t0_le[crc & 0x03];
-               crc = (crc >> 2) ^ t0_le[crc & 0x03];
+               crc = (crc >> 2) ^ tab[0][crc & 3];
+               crc = (crc >> 2) ^ tab[0][crc & 3];
+               crc = (crc >> 2) ^ tab[0][crc & 3];
+               crc = (crc >> 2) ^ tab[0][crc & 3];
        }
 # elif CRC_LE_BITS == 4
        while (len--) {
                crc ^= *p++;
-               crc = (crc >> 4) ^ t0_le[crc & 0x0f];
-               crc = (crc >> 4) ^ t0_le[crc & 0x0f];
+               crc = (crc >> 4) ^ tab[0][crc & 15];
+               crc = (crc >> 4) ^ tab[0][crc & 15];
        }
 # elif CRC_LE_BITS == 8
+       /* aka Sarwate algorithm */
        while (len--) {
                crc ^= *p++;
-               crc = (crc >> 8) ^ t0_le[crc & 0xff];
+               crc = (crc >> 8) ^ tab[0][crc & 255];
        }
 # else
-       crc = crc32c_le_body(crc, p, len);
-# endif
+       crc = __cpu_to_le32(crc);
+       crc = crc32_body(crc, p, len, tab);
+       crc = __le32_to_cpu(crc);
+#endif
        return crc;
 }
 
+uint32_t ext2fs_crc32c_le(uint32_t crc, unsigned char const *p, size_t len)
+{
+       return crc32_le_generic(crc, p, len, crc32ctable_le, CRC32C_POLY_LE);
+}
+
 /**
- * crc32c_be() - Calculate bitwise big-endian CRC32c.
- * @crc: seed value for computation.  ~0 for ext4, sometimes 0 for
- *     other uses, or the previous crc32c value if computing incrementally.
+ * crc32_be() - Calculate bitwise big-endian Ethernet AUTODIN II CRC32
+ * @crc: seed value for computation.  ~0 for Ethernet, sometimes 0 for
+ *     other uses, or the previous crc32 value if computing incrementally.
  * @p: pointer to buffer over which CRC is run
  * @len: length of buffer @p
  */
-uint32_t ext2fs_crc32c_be(uint32_t crc, unsigned char const *p, size_t len)
+static inline uint32_t crc32_be_generic(uint32_t crc, unsigned char const *p,
+                                       size_t len, const uint32_t (*tab)[256],
+                                       uint32_t polynomial EXT2FS_ATTR((unused)))
 {
 #if CRC_BE_BITS == 1
        int i;
        while (len--) {
                crc ^= *p++ << 24;
                for (i = 0; i < 8; i++)
-                       crc = (crc << 1) ^
-                             ((crc & 0x80000000) ? CRCPOLY_BE : 0);
+                       crc =
+                           (crc << 1) ^ ((crc & 0x80000000) ? polynomial :
+                                         0);
        }
 # elif CRC_BE_BITS == 2
        while (len--) {
                crc ^= *p++ << 24;
-               crc = (crc << 2) ^ t0_be[crc >> 30];
-               crc = (crc << 2) ^ t0_be[crc >> 30];
-               crc = (crc << 2) ^ t0_be[crc >> 30];
-               crc = (crc << 2) ^ t0_be[crc >> 30];
+               crc = (crc << 2) ^ tab[0][crc >> 30];
+               crc = (crc << 2) ^ tab[0][crc >> 30];
+               crc = (crc << 2) ^ tab[0][crc >> 30];
+               crc = (crc << 2) ^ tab[0][crc >> 30];
        }
 # elif CRC_BE_BITS == 4
        while (len--) {
                crc ^= *p++ << 24;
-               crc = (crc << 4) ^ t0_be[crc >> 28];
-               crc = (crc << 4) ^ t0_be[crc >> 28];
+               crc = (crc << 4) ^ tab[0][crc >> 28];
+               crc = (crc << 4) ^ tab[0][crc >> 28];
        }
 # elif CRC_BE_BITS == 8
        while (len--) {
                crc ^= *p++ << 24;
-               crc = (crc << 8) ^ t0_be[crc >> 24];
+               crc = (crc << 8) ^ tab[0][crc >> 24];
        }
 # else
-       crc = crc32c_be_body(crc, p, len);
+       crc = __cpu_to_be32(crc);
+       crc = crc32_body(crc, p, len, tab);
+       crc = __be32_to_cpu(crc);
 # endif
        return crc;
 }
 
+uint32_t ext2fs_crc32_be(uint32_t crc, unsigned char const *p, size_t len)
+{
+       return crc32_be_generic(crc, p, len, crc32table_be, CRCPOLY_BE);
+}
+
 #ifdef UNITTEST
 static uint8_t test_buf[] = {
        0xd9, 0xd7, 0x6a, 0x13, 0x3a, 0xb1, 0x05, 0x48,
@@ -972,137 +760,137 @@ static struct crc_test {
        uint32_t crc;           /* random starting crc */
        uint32_t start;         /* random offset in buf */
        uint32_t length;        /* random length of test */
-       uint32_t crc_le;        /* expected crc32_le result */
-       uint32_t crc_be;        /* expected crc32_be result */
+       uint32_t crc32c_le;     /* expected crc32c_le result */
+       uint32_t crc32_be;      /* expected crc32_be result */
 } test[] = {
-       {0xffffffff, 0x00000000, 0x00001000, 0x13934bef, 0x14f3b75f},
-       {0xfe7328ea, 0x00000763, 0x00000717, 0xed2c0d70, 0x57531214},
-       {0x4c40684e, 0x00000721, 0x0000011e, 0xd7f46ccc, 0xedf12ec3},
-       {0x6b487f90, 0x00000264, 0x000007bc, 0x759e9939, 0x9af8e387},
-       {0x9f5810db, 0x00000afa, 0x00000255, 0x2685197f, 0x716de6ed},
-       {0xb15c4755, 0x00000d5b, 0x000002a4, 0xd8fadcb5, 0xfc34ae3f},
-       {0x06518253, 0x00000ffb, 0x00000004, 0xabee2433, 0xfa30ac9e},
-       {0xd9e71c55, 0x00000a2a, 0x00000259, 0x96682af2, 0xe5907ea3},
-       {0x0c1ae843, 0x00000ce4, 0x0000031b, 0x7b637c43, 0xe7f71b04},
-       {0xec3cd517, 0x000002ff, 0x00000566, 0x5d719a77, 0xed16e045},
-       {0x77828e95, 0x0000067f, 0x0000038f, 0x43ee5b6c, 0x35999927},
-       {0xec87b4e3, 0x00000d1c, 0x000002e3, 0x2ddd2eee, 0x9452d3f8},
-       {0x412158bb, 0x00000eee, 0x00000111, 0x67b38ba2, 0x177976d0},
-       {0x2e52de3e, 0x00000c4a, 0x000003b5, 0xbcc5d61d, 0xf60fee71},
-       {0x6ddaae8b, 0x00000d99, 0x00000266, 0x8b535544, 0x1dab8596},
-       {0x049b6cb1, 0x000009c5, 0x000000b0, 0xfc22cabc, 0x47ebc954},
-       {0x77d4b954, 0x0000028a, 0x000007fa, 0x71d00923, 0x905585ef},
-       {0x5e192355, 0x00000ac1, 0x000001fa, 0xb966b81a, 0x33c12903},
-       {0x7d80b71d, 0x00000213, 0x000001e0, 0x2bba371a, 0x5f4bd8d9},
-       {0x01f6f1e4, 0x000001d6, 0x00000395, 0xb7e8a647, 0x2a7943a1},
-       {0x1dfabb13, 0x00000e14, 0x000001eb, 0x53917fba, 0x8dee1e5d},
-       {0xb00a4449, 0x00000bf6, 0x00000409, 0xedecb577, 0x628e087d},
-       {0x7ecd3981, 0x0000083f, 0x0000016b, 0xefef62b9, 0xda4f94e6},
-       {0xf8f330d2, 0x000004be, 0x00000757, 0x9357c9f3, 0x8e2d5c2f},
-       {0x03c38af2, 0x00000d23, 0x000002dc, 0x360fa8c0, 0x6294c0d6},
-       {0x687bb79b, 0x00000f3d, 0x000000c2, 0x448d3be2, 0x08f48f3a},
-       {0x6710f550, 0x000009e9, 0x00000603, 0xdbfd1998, 0xc950ac29},
-       {0x873171d1, 0x00000787, 0x000004d5, 0xab7f1b62, 0xe66896ab},
-       {0x373b1314, 0x00000f0f, 0x000000f0, 0x184098ab, 0x4038e674},
-       {0x90fad9cd, 0x00000ead, 0x00000152, 0x23ce52ff, 0x9eff3974},
-       {0x19676fe7, 0x0000007d, 0x0000070d, 0xf8a76f1e, 0xfbc5c8a9},
-       {0x89facd45, 0x000005f3, 0x00000473, 0x4331a006, 0xb8f0f0cc},
-       {0x6f173747, 0x00000fc3, 0x0000003c, 0xb012f08e, 0x5126e378},
-       {0x4b44a106, 0x0000075a, 0x0000008b, 0xf6f7ac38, 0xf9b1781b},
-       {0xb620ad06, 0x00000774, 0x0000017e, 0xd34558e6, 0xb175edd3},
-       {0x976f21e9, 0x000008d7, 0x0000034a, 0xe533aa3a, 0x1e4367b9},
-       {0x687628c0, 0x000006c5, 0x0000061b, 0x3a840b15, 0xfb5989a0},
-       {0xe24ac108, 0x00000cd0, 0x0000032f, 0x51010ae8, 0xcdd8f182},
-       {0x361c44a3, 0x00000304, 0x00000719, 0xfd7bd481, 0x12de540f},
-       {0xd93ff95e, 0x00000db7, 0x0000008e, 0xcfbbc304, 0x42eecd5a},
-       {0xed752d12, 0x00000883, 0x00000091, 0x65a6c868, 0x9ebfa578},
-       {0xb4ff4b54, 0x000003d3, 0x000001c1, 0xf82597e7, 0xa8ad2b19},
-       {0x111b520f, 0x00000708, 0x000000eb, 0xc3e109f3, 0x323ace17},
-       {0x62c806f2, 0x00000ba3, 0x0000045c, 0x874d3a72, 0xaf1a1360},
-       {0x40d97470, 0x000005e1, 0x0000058d, 0x87a9684f, 0x524244a8},
-       {0x4312179c, 0x00000056, 0x0000070e, 0x809a00f5, 0xf9e940b0},
-       {0x13d5f84c, 0x00000a2d, 0x00000104, 0xf3d27578, 0x5d33341c},
-       {0x1f302cb2, 0x00000151, 0x00000014, 0x1e162693, 0x53c3cfc3},
-       {0xe491db24, 0x00000600, 0x000006f6, 0x7ff09615, 0xa300ecf7},
-       {0xf9a98069, 0x000002ba, 0x000002ad, 0x01af7387, 0x31c0911e},
-       {0xe9c477ad, 0x0000015f, 0x00000778, 0x6facf9a0, 0x1993b688},
-       {0x353f32b2, 0x0000087c, 0x00000783, 0x6cc964ea, 0x418db561},
-       {0x78e1b24f, 0x00000650, 0x000006a8, 0xb3bb7c27, 0xf2aad006},
-       {0x61aa400e, 0x00000049, 0x00000254, 0xb8cd1681, 0x79150b15},
-       {0xb84b10b0, 0x00000f73, 0x0000008c, 0x406a6450, 0x0c705222},
-       {0x9fa99c9c, 0x00000a7c, 0x000004d7, 0xfb3d21b4, 0xe4e789df},
-       {0x3fc9ebe3, 0x00000cd9, 0x000000d6, 0x43803f9c, 0x5a152be5},
-       {0x529879cd, 0x000002f2, 0x00000595, 0x78b4c6a6, 0xf7236ec4},
-       {0x3a933019, 0x00000516, 0x00000266, 0xdcb45436, 0x2c7935f5},
-       {0x887b4977, 0x00000227, 0x0000038d, 0xc5f7c3d9, 0x0d6d7df6},
-       {0x770745de, 0x000008c6, 0x00000739, 0xf69145e8, 0x47d5efc9},
-       {0x28be3b47, 0x00000c46, 0x0000032b, 0x764c028f, 0x1eb70d64},
-       {0x5013a050, 0x00000cf6, 0x00000309, 0xea8fe164, 0x186affa4},
-       {0x2ec4c9ba, 0x000006e8, 0x0000078d, 0xa35557a9, 0xb41f49ec},
-       {0xa9f950c9, 0x00000d33, 0x000002cc, 0x41ea8618, 0xab8dfae3},
-       {0x5b520229, 0x000007b2, 0x00000484, 0x44569f1f, 0x607a8052},
-       {0xd8dcbbfc, 0x0000002f, 0x0000048c, 0xdb88ab8b, 0xf1c411f1},
-       {0x25529792, 0x00000d1d, 0x000002e2, 0x20cda404, 0x32683a2d},
-       {0x9f3f6d71, 0x00000238, 0x0000079a, 0x0720443e, 0x4b8ba2ff},
-       {0x64121215, 0x000007ff, 0x0000038f, 0x6aacff2c, 0x3b84233b},
-       {0xfb6cdde0, 0x00000ef8, 0x00000107, 0xbd43a0f1, 0x926624d0},
-       {0x221c9d6f, 0x000007b6, 0x0000014f, 0xb67f834b, 0x2bdedda4},
-       {0x030e1de4, 0x00000836, 0x000004b4, 0x0d67d26a, 0x75a73b73},
-       {0xb56fa6cf, 0x00000c07, 0x000003f8, 0x60601ac1, 0x10a43f35},
-       {0xb55c89f5, 0x0000098e, 0x000001d4, 0x2400efbe, 0x006e28eb},
-       {0x5e90b6d5, 0x0000070b, 0x000003ea, 0x3bb5d6ea, 0xb175fa6b},
-       {0x2a7045ae, 0x00000961, 0x00000633, 0xfca89e4b, 0x962cd6d2},
-       {0x8b374ea9, 0x000006ba, 0x00000780, 0xbce036ed, 0x4dc8279b},
-       {0x8bd90bc9, 0x00000562, 0x00000369, 0xcb26a24b, 0x50dee743},
-       {0x5b1b1762, 0x000000fd, 0x0000051a, 0x33cdda07, 0xee75ff7b},
-       {0xa4153555, 0x0000058f, 0x000005c7, 0xbe50eeca, 0xe73fffcc},
-       {0x0be1f931, 0x00000651, 0x00000672, 0x95a25753, 0x4ad6270f},
-       {0xb7e78618, 0x00000a7f, 0x000002bb, 0xe06bcc1c, 0x1a35ee59},
-       {0x4a9bc41b, 0x00000e51, 0x000001ae, 0x709e8d2c, 0x75080ca8},
-       {0xfc359d13, 0x00000440, 0x000002f8, 0x0a58451f, 0x6fa3cfbf},
-       {0x5aa48619, 0x000006d1, 0x00000284, 0x928ead83, 0xbd600efc},
-       {0xa609afa8, 0x0000053e, 0x00000272, 0xb048c141, 0x184f80bb},
-       {0x3f108afb, 0x00000949, 0x00000150, 0x9a6bb5bc, 0x0ea02be1},
-       {0x79bec2d3, 0x000008ed, 0x00000712, 0x32692d57, 0x2eb13289},
-       {0x9429e067, 0x00000bc3, 0x0000043c, 0x5295ceff, 0x8a9014a7},
-       {0xae58b96a, 0x0000082d, 0x000007d2, 0xc2a681ba, 0x6af94089},
-       {0x95df24be, 0x00000985, 0x000004c1, 0x3a287765, 0x379fcb42},
-       {0x5e94976f, 0x00000596, 0x000004ed, 0xff00c489, 0x991fc1f5},
-       {0xf5e5f1de, 0x00000d31, 0x000002ce, 0x35f28e91, 0x543def1a},
-       {0xa2c219cf, 0x00000a3c, 0x00000374, 0x707d21eb, 0xa6d28bc1},
-       {0xf21b6ceb, 0x00000919, 0x00000135, 0x0847fb8b, 0x224468c2},
-       {0xaa988728, 0x00000787, 0x00000771, 0x885aeaa4, 0x814db00b},
-       {0xaa5dfaac, 0x000003e5, 0x0000051b, 0x52c48ab7, 0x725bef8a},
-       {0x0a053968, 0x00000d2a, 0x000002d5, 0x7a90256d, 0xc53b9402},
-       {0x1421dc20, 0x00000eef, 0x00000110, 0x97d6da24, 0x10846935},
-       {0xb47c2166, 0x00000a6a, 0x00000209, 0xcfd6cc52, 0x46e2797e},
-       {0x77dd1955, 0x000000de, 0x00000266, 0xba74bcaa, 0x4fa3fe9c},
-       {0x68a03cc2, 0x0000082f, 0x000007b0, 0x752bd5d8, 0x4f760c63},
-       {0x0226b0a3, 0x00000a5f, 0x000005a0, 0x82de4970, 0x8ee1310e},
-       {0x637bf3b1, 0x00000d93, 0x0000026c, 0x5c7115cb, 0x9f6a0ced},
-       {0x3b120edf, 0x00000c13, 0x000003ec, 0x80d7d20f, 0x241657d5},
-       {0xe2456780, 0x000002eb, 0x00000641, 0xc0a5d289, 0x74df96b4},
-       {0x9b2e7125, 0x00000c0c, 0x000003f3, 0xcc15f57e, 0x03e290bf},
-       {0x153033ef, 0x00000787, 0x000006b6, 0x3cde443b, 0x7bf1d121},
-       {0x18458b3f, 0x0000066c, 0x00000561, 0x9a2bd8c6, 0x9d564bef},
-       {0x4ff9d4b9, 0x00000c8f, 0x0000033a, 0xd0ee6d6d, 0xee00aa0b},
-       {0xdf84b5d9, 0x00000802, 0x0000029a, 0xdab0d74a, 0xd0cb63dc},
-       {0x81ee15df, 0x000003ce, 0x00000725, 0x9942e2de, 0xe48fb26b},
-       {0x5c768e04, 0x00000afd, 0x00000160, 0x36110831, 0x8dc74483},
-       {0xe5e18094, 0x00000b4b, 0x000000a0, 0xffa3e4a7, 0xc0145e1b},
-       {0xed7263b6, 0x00000d0d, 0x000002f2, 0xb0006a35, 0x5468ae3a},
-       {0x5bfde7d7, 0x000006fb, 0x00000554, 0xa4193b76, 0xb73d34b2},
-       {0x67f4a743, 0x00000b85, 0x0000047a, 0xf05c8d8f, 0x4f843e49},
-       {0xf13bdf22, 0x00000ff7, 0x00000008, 0x816351eb, 0x41f537f6},
-       {0x08ecc608, 0x00000d5d, 0x00000098, 0x90492772, 0xf5172204},
-       {0x296f52ba, 0x000004f9, 0x00000788, 0x5e5a4896, 0xe01d5b46},
-       {0xbe4624c2, 0x00000427, 0x000004ef, 0xcd267b94, 0x7b9069f4},
-       {0x906f7c7c, 0x00000a05, 0x0000003f, 0x03fcfc33, 0x7b6ff563},
-       {0x8f7b323e, 0x00000458, 0x000004c7, 0xcd4969c8, 0xd4c22ada},
-       {0x88d6593d, 0x00000597, 0x000005b5, 0xf199cd3b, 0x5c3e8ca2},
-       {0x978a7768, 0x00000268, 0x000001d3, 0xb28c95bd, 0x49a2cc67},
-       {0x857a621e, 0x000007a7, 0x000003a8, 0xf4bf84ab, 0xde26f369},
-       {0xb0e121ef, 0x000005be, 0x00000644, 0x28747c14, 0x61d4dc6b},
+       {0xffffffff, 0x00000000, 0x00001000, 0x13934bef, 0xd8ddcdc3},
+       {0xfe7328ea, 0x00000763, 0x00000717, 0xed2c0d70, 0xc863aef8},
+       {0x4c40684e, 0x00000721, 0x0000011e, 0xd7f46ccc, 0x173a11c4},
+       {0x6b487f90, 0x00000264, 0x000007bc, 0x759e9939, 0xd6307c56},
+       {0x9f5810db, 0x00000afa, 0x00000255, 0x2685197f, 0x2e5c9201},
+       {0xb15c4755, 0x00000d5b, 0x000002a4, 0xd8fadcb5, 0xf682c4be},
+       {0x06518253, 0x00000ffb, 0x00000004, 0xabee2433, 0x3d8abdf9},
+       {0xd9e71c55, 0x00000a2a, 0x00000259, 0x96682af2, 0x47b4d26c},
+       {0x0c1ae843, 0x00000ce4, 0x0000031b, 0x7b637c43, 0x62b47e8b},
+       {0xec3cd517, 0x000002ff, 0x00000566, 0x5d719a77, 0xff5bc5b7},
+       {0x77828e95, 0x0000067f, 0x0000038f, 0x43ee5b6c, 0x1a0cfacd},
+       {0xec87b4e3, 0x00000d1c, 0x000002e3, 0x2ddd2eee, 0x275118a7},
+       {0x412158bb, 0x00000eee, 0x00000111, 0x67b38ba2, 0xa74ecff5},
+       {0x2e52de3e, 0x00000c4a, 0x000003b5, 0xbcc5d61d, 0xbd800707},
+       {0x6ddaae8b, 0x00000d99, 0x00000266, 0x8b535544, 0xecbde1a1},
+       {0x049b6cb1, 0x000009c5, 0x000000b0, 0xfc22cabc, 0xfb78eb9f},
+       {0x77d4b954, 0x0000028a, 0x000007fa, 0x71d00923, 0x8c116f85},
+       {0x5e192355, 0x00000ac1, 0x000001fa, 0xb966b81a, 0x5aa17bbe},
+       {0x7d80b71d, 0x00000213, 0x000001e0, 0x2bba371a, 0xb5906aa6},
+       {0x01f6f1e4, 0x000001d6, 0x00000395, 0xb7e8a647, 0x3ad112b1},
+       {0x1dfabb13, 0x00000e14, 0x000001eb, 0x53917fba, 0xbaee0339},
+       {0xb00a4449, 0x00000bf6, 0x00000409, 0xedecb577, 0x6f3a3979},
+       {0x7ecd3981, 0x0000083f, 0x0000016b, 0xefef62b9, 0xe3e52eed},
+       {0xf8f330d2, 0x000004be, 0x00000757, 0x9357c9f3, 0x0835bc1b},
+       {0x03c38af2, 0x00000d23, 0x000002dc, 0x360fa8c0, 0x2ca885e6},
+       {0x687bb79b, 0x00000f3d, 0x000000c2, 0x448d3be2, 0x79be2f78},
+       {0x6710f550, 0x000009e9, 0x00000603, 0xdbfd1998, 0x1d25f627},
+       {0x873171d1, 0x00000787, 0x000004d5, 0xab7f1b62, 0xa76a5656},
+       {0x373b1314, 0x00000f0f, 0x000000f0, 0x184098ab, 0xba273974},
+       {0x90fad9cd, 0x00000ead, 0x00000152, 0x23ce52ff, 0xb7bc958c},
+       {0x19676fe7, 0x0000007d, 0x0000070d, 0xf8a76f1e, 0xf882b644},
+       {0x89facd45, 0x000005f3, 0x00000473, 0x4331a006, 0xe9dc1396},
+       {0x6f173747, 0x00000fc3, 0x0000003c, 0xb012f08e, 0xc6b888ee},
+       {0x4b44a106, 0x0000075a, 0x0000008b, 0xf6f7ac38, 0x60cd2b74},
+       {0xb620ad06, 0x00000774, 0x0000017e, 0xd34558e6, 0x3a0a615b},
+       {0x976f21e9, 0x000008d7, 0x0000034a, 0xe533aa3a, 0xa99e60be},
+       {0x687628c0, 0x000006c5, 0x0000061b, 0x3a840b15, 0x9bfcaef2},
+       {0xe24ac108, 0x00000cd0, 0x0000032f, 0x51010ae8, 0x20958672},
+       {0x361c44a3, 0x00000304, 0x00000719, 0xfd7bd481, 0xd70ff2b2},
+       {0xd93ff95e, 0x00000db7, 0x0000008e, 0xcfbbc304, 0xad716acd},
+       {0xed752d12, 0x00000883, 0x00000091, 0x65a6c868, 0x95c71c7b},
+       {0xb4ff4b54, 0x000003d3, 0x000001c1, 0xf82597e7, 0x44b7f99b},
+       {0x111b520f, 0x00000708, 0x000000eb, 0xc3e109f3, 0x71bc01ee},
+       {0x62c806f2, 0x00000ba3, 0x0000045c, 0x874d3a72, 0xc539b753},
+       {0x40d97470, 0x000005e1, 0x0000058d, 0x87a9684f, 0xea6073a5},
+       {0x4312179c, 0x00000056, 0x0000070e, 0x809a00f5, 0x209aea3b},
+       {0x13d5f84c, 0x00000a2d, 0x00000104, 0xf3d27578, 0xe087a8b6},
+       {0x1f302cb2, 0x00000151, 0x00000014, 0x1e162693, 0x95e4b90e},
+       {0xe491db24, 0x00000600, 0x000006f6, 0x7ff09615, 0x77611523},
+       {0xf9a98069, 0x000002ba, 0x000002ad, 0x01af7387, 0xea925faa},
+       {0xe9c477ad, 0x0000015f, 0x00000778, 0x6facf9a0, 0x1130f736},
+       {0x353f32b2, 0x0000087c, 0x00000783, 0x6cc964ea, 0x32459994},
+       {0x78e1b24f, 0x00000650, 0x000006a8, 0xb3bb7c27, 0x5a632f78},
+       {0x61aa400e, 0x00000049, 0x00000254, 0xb8cd1681, 0xdf2652d5},
+       {0xb84b10b0, 0x00000f73, 0x0000008c, 0x406a6450, 0x3619d31b},
+       {0x9fa99c9c, 0x00000a7c, 0x000004d7, 0xfb3d21b4, 0xea31c743},
+       {0x3fc9ebe3, 0x00000cd9, 0x000000d6, 0x43803f9c, 0x1f76a809},
+       {0x529879cd, 0x000002f2, 0x00000595, 0x78b4c6a6, 0x63b9b93f},
+       {0x3a933019, 0x00000516, 0x00000266, 0xdcb45436, 0x8f99c98c},
+       {0x887b4977, 0x00000227, 0x0000038d, 0xc5f7c3d9, 0xaf5e3091},
+       {0x770745de, 0x000008c6, 0x00000739, 0xf69145e8, 0x53d0dce1},
+       {0x28be3b47, 0x00000c46, 0x0000032b, 0x764c028f, 0x106d0905},
+       {0x5013a050, 0x00000cf6, 0x00000309, 0xea8fe164, 0x62180b57},
+       {0x2ec4c9ba, 0x000006e8, 0x0000078d, 0xa35557a9, 0xf44430a4},
+       {0xa9f950c9, 0x00000d33, 0x000002cc, 0x41ea8618, 0x587b4eb3},
+       {0x5b520229, 0x000007b2, 0x00000484, 0x44569f1f, 0x92406c32},
+       {0xd8dcbbfc, 0x0000002f, 0x0000048c, 0xdb88ab8b, 0x13bfe70e},
+       {0x25529792, 0x00000d1d, 0x000002e2, 0x20cda404, 0x19d3b4e4},
+       {0x9f3f6d71, 0x00000238, 0x0000079a, 0x0720443e, 0x3c107021},
+       {0x64121215, 0x000007ff, 0x0000038f, 0x6aacff2c, 0xb82fdc3e},
+       {0xfb6cdde0, 0x00000ef8, 0x00000107, 0xbd43a0f1, 0xab0d3c1d},
+       {0x221c9d6f, 0x000007b6, 0x0000014f, 0xb67f834b, 0x1371ad05},
+       {0x030e1de4, 0x00000836, 0x000004b4, 0x0d67d26a, 0xe2e72df1},
+       {0xb56fa6cf, 0x00000c07, 0x000003f8, 0x60601ac1, 0x039de73e},
+       {0xb55c89f5, 0x0000098e, 0x000001d4, 0x2400efbe, 0xfe39a2bb},
+       {0x5e90b6d5, 0x0000070b, 0x000003ea, 0x3bb5d6ea, 0xf0f794a0},
+       {0x2a7045ae, 0x00000961, 0x00000633, 0xfca89e4b, 0xe66ce41c},
+       {0x8b374ea9, 0x000006ba, 0x00000780, 0xbce036ed, 0x4cb28ef7},
+       {0x8bd90bc9, 0x00000562, 0x00000369, 0xcb26a24b, 0x40236d1d},
+       {0x5b1b1762, 0x000000fd, 0x0000051a, 0x33cdda07, 0xc32e420a},
+       {0xa4153555, 0x0000058f, 0x000005c7, 0xbe50eeca, 0x83a67f35},
+       {0x0be1f931, 0x00000651, 0x00000672, 0x95a25753, 0x88f1aac1},
+       {0xb7e78618, 0x00000a7f, 0x000002bb, 0xe06bcc1c, 0x74274f66},
+       {0x4a9bc41b, 0x00000e51, 0x000001ae, 0x709e8d2c, 0x54eff534},
+       {0xfc359d13, 0x00000440, 0x000002f8, 0x0a58451f, 0x55e9363f},
+       {0x5aa48619, 0x000006d1, 0x00000284, 0x928ead83, 0x31041c06},
+       {0xa609afa8, 0x0000053e, 0x00000272, 0xb048c141, 0x4704efba},
+       {0x3f108afb, 0x00000949, 0x00000150, 0x9a6bb5bc, 0x4e4430c8},
+       {0x79bec2d3, 0x000008ed, 0x00000712, 0x32692d57, 0x11d52a7b},
+       {0x9429e067, 0x00000bc3, 0x0000043c, 0x5295ceff, 0x04640f4d},
+       {0xae58b96a, 0x0000082d, 0x000007d2, 0xc2a681ba, 0xf7ca4a2c},
+       {0x95df24be, 0x00000985, 0x000004c1, 0x3a287765, 0x2c4af003},
+       {0x5e94976f, 0x00000596, 0x000004ed, 0xff00c489, 0x5ae11687},
+       {0xf5e5f1de, 0x00000d31, 0x000002ce, 0x35f28e91, 0x30d47957},
+       {0xa2c219cf, 0x00000a3c, 0x00000374, 0x707d21eb, 0x2a14a255},
+       {0xf21b6ceb, 0x00000919, 0x00000135, 0x0847fb8b, 0xcb8d3b93},
+       {0xaa988728, 0x00000787, 0x00000771, 0x885aeaa4, 0x6531b509},
+       {0xaa5dfaac, 0x000003e5, 0x0000051b, 0x52c48ab7, 0xe43cc5e9},
+       {0x0a053968, 0x00000d2a, 0x000002d5, 0x7a90256d, 0x8004765c},
+       {0x1421dc20, 0x00000eef, 0x00000110, 0x97d6da24, 0x1378f6ff},
+       {0xb47c2166, 0x00000a6a, 0x00000209, 0xcfd6cc52, 0x676e14a5},
+       {0x77dd1955, 0x000000de, 0x00000266, 0xba74bcaa, 0xc71b429c},
+       {0x68a03cc2, 0x0000082f, 0x000007b0, 0x752bd5d8, 0x19ed14aa},
+       {0x0226b0a3, 0x00000a5f, 0x000005a0, 0x82de4970, 0xf654d3ed},
+       {0x637bf3b1, 0x00000d93, 0x0000026c, 0x5c7115cb, 0x3cccb57e},
+       {0x3b120edf, 0x00000c13, 0x000003ec, 0x80d7d20f, 0x92132798},
+       {0xe2456780, 0x000002eb, 0x00000641, 0xc0a5d289, 0x6160c87a},
+       {0x9b2e7125, 0x00000c0c, 0x000003f3, 0xcc15f57e, 0x6f00f637},
+       {0x153033ef, 0x00000787, 0x000006b6, 0x3cde443b, 0xb46caa6e},
+       {0x18458b3f, 0x0000066c, 0x00000561, 0x9a2bd8c6, 0xb6c29121},
+       {0x4ff9d4b9, 0x00000c8f, 0x0000033a, 0xd0ee6d6d, 0xc81cf380},
+       {0xdf84b5d9, 0x00000802, 0x0000029a, 0xdab0d74a, 0xb2464559},
+       {0x81ee15df, 0x000003ce, 0x00000725, 0x9942e2de, 0x4ccf571b},
+       {0x5c768e04, 0x00000afd, 0x00000160, 0x36110831, 0xae0b305a},
+       {0xe5e18094, 0x00000b4b, 0x000000a0, 0xffa3e4a7, 0x6c8a4f09},
+       {0xed7263b6, 0x00000d0d, 0x000002f2, 0xb0006a35, 0x7e04af8c},
+       {0x5bfde7d7, 0x000006fb, 0x00000554, 0xa4193b76, 0xb3a91d12},
+       {0x67f4a743, 0x00000b85, 0x0000047a, 0xf05c8d8f, 0xfb472fdf},
+       {0xf13bdf22, 0x00000ff7, 0x00000008, 0x816351eb, 0xf347f235},
+       {0x08ecc608, 0x00000d5d, 0x00000098, 0x90492772, 0x0b7f1521},
+       {0x296f52ba, 0x000004f9, 0x00000788, 0x5e5a4896, 0x1cc67088},
+       {0xbe4624c2, 0x00000427, 0x000004ef, 0xcd267b94, 0x550caefd},
+       {0x906f7c7c, 0x00000a05, 0x0000003f, 0x03fcfc33, 0x9ed82a02},
+       {0x8f7b323e, 0x00000458, 0x000004c7, 0xcd4969c8, 0x633c38a8},
+       {0x88d6593d, 0x00000597, 0x000005b5, 0xf199cd3b, 0x0491452f},
+       {0x978a7768, 0x00000268, 0x000001d3, 0xb28c95bd, 0x1a42fe61},
+       {0x857a621e, 0x000007a7, 0x000003a8, 0xf4bf84ab, 0xcd0694c6},
+       {0xb0e121ef, 0x000005be, 0x00000644, 0x28747c14, 0xf0510c72},
        {0, 0, 0, 0, 0},
 };
 
@@ -1114,15 +902,15 @@ static int test_crc32c(void)
        while (t->length) {
                uint32_t be, le;
                le = ext2fs_crc32c_le(t->crc, test_buf + t->start, t->length);
-               be = ext2fs_crc32c_be(t->crc, test_buf + t->start, t->length);
-               if (le != t->crc_le) {
+               be = ext2fs_crc32_be(t->crc, test_buf + t->start, t->length);
+               if (le != t->crc32c_le) {
                        printf("Test %d LE fails, %x != %x\n",
-                              (int) (t - test), le, t->crc_le);
+                              (int) (t - test), le, t->crc32c_le);
                        failures++;
                }
-               if (be != t->crc_be) {
+               if (be != t->crc32_be) {
                        printf("Test %d BE fails, %x != %x\n",
-                              (int) (t - test), be, t->crc_be);
+                              (int) (t - test), be, t->crc32_be);
                        failures++;
                }
                t++;
index 023f2c0..3f9a09e 100644 (file)
@@ -1,10 +1,18 @@
 /*
+ * There are multiple 16-bit CRC polynomials in common use, but this is
+ * *the* standard CRC-32 polynomial, first popularized by Ethernet.
+ * x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x^1+x^0
+ */
+#define CRCPOLY_LE 0xedb88320
+#define CRCPOLY_BE 0x04c11db7
+
+/*
  * This is the CRC32c polynomial, as outlined by Castagnoli.
  * x^32+x^28+x^27+x^26+x^25+x^23+x^22+x^20+x^19+x^18+x^14+x^13+x^11+x^10+x^9+
  * x^8+x^6+x^0
  */
-#define CRCPOLY_LE 0x82F63B78
-#define CRCPOLY_BE 0x1EDC6F41
+#define CRC32C_POLY_LE 0x82F63B78
+#define CRC32C_POLY_BE 0x1EDC6F41
 
 /* How many bits at a time to use.  Valid values are 1, 2, 4, 8, 32 and 64. */
 /* For less performance-sensitive, use 4 */
index 669f806..d7dbca8 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 3f6ea50..942c4f0 100644 (file)
@@ -25,34 +25,6 @@ static EXT2_QSORT_TYPE dir_block_cmp2(const void *a, const void *b);
 static EXT2_QSORT_TYPE (*sortfunc32)(const void *a, const void *b);
 
 /*
- * Returns the number of directories in the filesystem as reported by
- * the group descriptors.  Of course, the group descriptors could be
- * wrong!
- */
-errcode_t ext2fs_get_num_dirs(ext2_filsys fs, ext2_ino_t *ret_num_dirs)
-{
-       dgrp_t  i;
-       ext2_ino_t      num_dirs, max_dirs;
-
-       EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
-
-       num_dirs = 0;
-       max_dirs = fs->super->s_inodes_per_group;
-       for (i = 0; i < fs->group_desc_count; i++) {
-               if (ext2fs_bg_used_dirs_count(fs, i) > max_dirs)
-                       num_dirs += max_dirs / 8;
-               else
-                       num_dirs += ext2fs_bg_used_dirs_count(fs, i);
-       }
-       if (num_dirs > fs->super->s_inodes_count)
-               num_dirs = fs->super->s_inodes_count;
-
-       *ret_num_dirs = num_dirs;
-
-       return 0;
-}
-
-/*
  * helper function for making a new directory block list (for
  * initialize and copy).
  */
index d4d5111..864a3ca 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 589af69..67152cc 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 cb3a104..54b2777 100644 (file)
 #include "ext2_fs.h"
 #include "ext2fs.h"
 
-errcode_t ext2fs_read_dir_block3(ext2_filsys fs, blk64_t block,
-                                void *buf, int flags EXT2FS_ATTR((unused)))
+errcode_t ext2fs_read_dir_block4(ext2_filsys fs, blk64_t block,
+                                void *buf, int flags EXT2FS_ATTR((unused)),
+                                ext2_ino_t ino)
 {
        errcode_t       retval;
-       char            *p, *end;
-       struct ext2_dir_entry *dirent;
-       unsigned int    name_len, rec_len;
-
+       int             corrupt = 0;
 
        retval = io_channel_read_blk64(fs->io, block, 1, buf);
        if (retval)
                return retval;
 
-       p = (char *) buf;
-       end = (char *) buf + fs->blocksize;
-       while (p < end-8) {
-               dirent = (struct ext2_dir_entry *) p;
-#ifdef WORDS_BIGENDIAN
-               dirent->inode = ext2fs_swab32(dirent->inode);
-               dirent->rec_len = ext2fs_swab16(dirent->rec_len);
-               dirent->name_len = ext2fs_swab16(dirent->name_len);
-#endif
-               name_len = dirent->name_len;
+       if (!(fs->flags & EXT2_FLAG_IGNORE_CSUM_ERRORS) &&
+           !ext2fs_dir_block_csum_verify(fs, ino,
+                                         (struct ext2_dir_entry *)buf))
+               corrupt = 1;
+
 #ifdef WORDS_BIGENDIAN
-               if (flags & EXT2_DIRBLOCK_V2_STRUCT)
-                       dirent->name_len = ext2fs_swab16(dirent->name_len);
+       retval = ext2fs_dirent_swab_in(fs, buf, flags);
 #endif
-               if ((retval = ext2fs_get_rec_len(fs, dirent, &rec_len)) != 0)
-                       return retval;
-               if ((rec_len < 8) || (rec_len % 4)) {
-                       rec_len = 8;
-                       retval = EXT2_ET_DIR_CORRUPTED;
-               } else if (((name_len & 0xFF) + 8) > rec_len)
-                       retval = EXT2_ET_DIR_CORRUPTED;
-               p += rec_len;
-       }
+       if (!retval && corrupt)
+               retval = EXT2_ET_DIR_CSUM_INVALID;
        return retval;
 }
 
+errcode_t ext2fs_read_dir_block3(ext2_filsys fs, blk64_t block,
+                                void *buf, int flags EXT2FS_ATTR((unused)))
+{
+       return ext2fs_read_dir_block4(fs, block, buf, flags, 0);
+}
+
 errcode_t ext2fs_read_dir_block2(ext2_filsys fs, blk_t block,
                                 void *buf, int flags EXT2FS_ATTR((unused)))
 {
@@ -72,45 +63,40 @@ errcode_t ext2fs_read_dir_block(ext2_filsys fs, blk_t block,
 }
 
 
-errcode_t ext2fs_write_dir_block3(ext2_filsys fs, blk64_t block,
-                                 void *inbuf, int flags EXT2FS_ATTR((unused)))
+errcode_t ext2fs_write_dir_block4(ext2_filsys fs, blk64_t block,
+                                 void *inbuf, int flags EXT2FS_ATTR((unused)),
+                                 ext2_ino_t ino)
 {
-#ifdef WORDS_BIGENDIAN
        errcode_t       retval;
-       char            *p, *end;
-       char            *buf = 0;
-       unsigned int    rec_len;
-       struct ext2_dir_entry *dirent;
+       char            *buf = inbuf;
 
+#ifdef WORDS_BIGENDIAN
        retval = ext2fs_get_mem(fs->blocksize, &buf);
        if (retval)
                return retval;
        memcpy(buf, inbuf, fs->blocksize);
-       p = buf;
-       end = buf + fs->blocksize;
-       while (p < end) {
-               dirent = (struct ext2_dir_entry *) p;
-               if ((retval = ext2fs_get_rec_len(fs, dirent, &rec_len)) != 0)
-                       return retval;
-               if ((rec_len < 8) ||
-                   (rec_len % 4)) {
-                       ext2fs_free_mem(&buf);
-                       return (EXT2_ET_DIR_CORRUPTED);
-               }
-               p += rec_len;
-               dirent->inode = ext2fs_swab32(dirent->inode);
-               dirent->rec_len = ext2fs_swab16(dirent->rec_len);
-               dirent->name_len = ext2fs_swab16(dirent->name_len);
-
-               if (flags & EXT2_DIRBLOCK_V2_STRUCT)
-                       dirent->name_len = ext2fs_swab16(dirent->name_len);
-       }
+       retval = ext2fs_dirent_swab_out(fs, buf, flags);
+       if (retval)
+               return retval;
+#endif
+       retval = ext2fs_dir_block_csum_set(fs, ino,
+                                          (struct ext2_dir_entry *)buf);
+       if (retval)
+               goto out;
+
        retval = io_channel_write_blk64(fs->io, block, 1, buf);
+
+out:
+#ifdef WORDS_BIGENDIAN
        ext2fs_free_mem(&buf);
-       return retval;
-#else
-       return io_channel_write_blk64(fs->io, block, 1, (char *) inbuf);
 #endif
+       return retval;
+}
+
+errcode_t ext2fs_write_dir_block3(ext2_filsys fs, blk64_t block,
+                                 void *inbuf, int flags EXT2FS_ATTR((unused)))
+{
+       return ext2fs_write_dir_block4(fs, block, inbuf, flags, 0);
 }
 
 errcode_t ext2fs_write_dir_block2(ext2_filsys fs, blk_t block,
index 153b838..d0f7287 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 87812ab..6b6d8b8 100644 (file)
@@ -476,4 +476,49 @@ 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"
+
+ec     EXT2_ET_INODE_IS_GARBAGE,
+       "Inode seems to contain garbage"
+
+ec     EXT2_ET_EA_BAD_VALUE_OFFSET,
+       "Extended attribute has an invalid value offset"
+
        end
index ed548d1..bbb0aaa 100644 (file)
@@ -20,7 +20,9 @@ struct ext2_ext_attr_header {
        __u32   h_refcount;     /* reference count */
        __u32   h_blocks;       /* number of disk blocks used */
        __u32   h_hash;         /* hash value of all attributes */
-       __u32   h_reserved[4];  /* zero right now */
+       __u32   h_checksum;     /* crc32c(uuid+id+xattrs) */
+                               /* id = inum if refcount = 1, else blknum */
+       __u32   h_reserved[3];  /* zero right now */
 };
 
 struct ext2_ext_attr_entry {
index 6c3620c..f9a4bdb 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
@@ -310,6 +324,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 */
@@ -459,8 +474,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
@@ -540,6 +561,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
  */
@@ -625,7 +649,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 */
@@ -715,6 +739,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
 
@@ -731,7 +760,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| \
@@ -781,6 +810,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 */
@@ -791,6 +828,17 @@ struct ext2_dir_entry_2 {
 };
 
 /*
+ * This is a bogus directory entry at the end of each leaf block that
+ * records checksums.
+ */
+struct ext2_dir_entry_tail {
+       __u32   det_reserved_zero1;     /* Pretend to be unused */
+       __u16   det_rec_len;            /* 12 */
+       __u16   det_reserved_name_len;  /* 0xDE00, fake namelen/filetype */
+       __u32   det_checksum;           /* crc32c(uuid+inode+dirent) */
+};
+
+/*
  * Ext2 directory file types.  Only the low 3 bits are used.  The
  * other bits are reserved for now.
  */
@@ -806,6 +854,14 @@ struct ext2_dir_entry_2 {
 #define EXT2_FT_MAX            8
 
 /*
+ * Annoyingly, e2fsprogs always swab16s ext2_dir_entry.name_len, so we
+ * have to build ext2_dir_entry_tail with that assumption too.  This
+ * constant helps to build the dir_entry_tail to look like it has an
+ * "invalid" file type.
+ */
+#define EXT2_DIR_NAME_LEN_CSUM 0xDE00
+
+/*
  * EXT2_DIR_PAD defines the directory entries boundaries
  *
  * NOTE: It must be a multiple of 4
@@ -846,7 +902,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) */
 };
 
 /*
@@ -864,4 +921,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 d3a34d5..b4a9f84 100644 (file)
@@ -193,6 +193,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
@@ -275,6 +276,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
@@ -293,9 +300,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
@@ -432,11 +440,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
@@ -451,6 +462,7 @@ typedef struct ext2_struct_inode_scan *ext2_inode_scan;
 #define EXT2_SF_BAD_EXTRA_BYTES        0x0004
 #define EXT2_SF_SKIP_MISSING_ITABLE    0x0008
 #define EXT2_SF_DO_LAZY                0x0010
+#define EXT2_SF_WARN_GARBAGE_INODES    0x0020
 
 /*
  * ext2fs_check_if_mounted flags
@@ -563,26 +575,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|\
@@ -590,22 +610,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)
 
 
@@ -632,8 +644,21 @@ 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)
@@ -809,6 +834,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);
@@ -836,9 +863,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);
@@ -950,18 +979,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);
@@ -1016,12 +1092,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,
@@ -1072,16 +1152,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);
@@ -1190,10 +1300,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,
@@ -1222,6 +1328,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);
@@ -1283,7 +1392,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,
@@ -1359,6 +1482,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,
@@ -1423,6 +1548,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);
 
@@ -1447,6 +1573,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,
@@ -1486,6 +1618,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,
@@ -1536,6 +1669,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>
 /*
@@ -1752,6 +1895,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 a88db93..f8c61e6 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 88fabc9..4163436 100644 (file)
  */
 
 /*
+ * This is extent tail on-disk structure.
+ * All other extent structures are 12 bytes long.  It turns out that
+ * block_size % 12 >= 4 for at least all powers of 2 greater than 512, which
+ * covers all valid ext4 block sizes.  Therefore, this tail structure can be
+ * crammed into the end of the block without having to rebalance the tree.
+ */
+struct ext3_extent_tail {
+       __u32   et_checksum;    /* crc32c(uuid+inum+extent_block) */
+};
+
+/*
  * this is extent on-disk structure
  * it's used at the bottom of the tree
  */
index 1889824..fc191f5 100644 (file)
@@ -58,20 +58,47 @@ __u32 ext2fs_ext_attr_hash_entry(struct ext2_ext_attr_entry *entry, void *data)
        return hash;
 }
 
+static errcode_t check_ext_attr_header(struct ext2_ext_attr_header *header)
+{
+       if ((header->h_magic != EXT2_EXT_ATTR_MAGIC_v1 &&
+            header->h_magic != EXT2_EXT_ATTR_MAGIC) ||
+           header->h_blocks != 1)
+               return EXT2_ET_BAD_EA_HEADER;
+
+       return 0;
+}
+
 #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)
 {
+       int             csum_failed = 0;
        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))
+               csum_failed = 1;
+
 #ifdef WORDS_BIGENDIAN
        ext2fs_swap_ext_attr(buf, buf, fs->blocksize, 1);
 #endif
-       return 0;
+
+       retval = check_ext_attr_header(buf);
+       if (retval == 0 && csum_failed)
+               retval = EXT2_ET_EXT_ATTR_CSUM_INVALID;
+
+       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 +106,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 +148,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 +167,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 +176,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 +186,896 @@ 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;
+
+       /* We only know how to deal with v2 EA blocks */
+       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;
+
+               /* We only know how to deal with v2 EA blocks */
+               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;
+       unsigned int values_size = storage_size +
+                       ((char *)entries - (char *)value_start);
+
+       x = handle->attrs;
+       while (x->name)
+               x++;
+
+       entry = entries;
+       remain = storage_size;
+       while (remain >= sizeof(struct ext2_ext_attr_entry) &&
+              !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;
+
+               if (entry->e_value_offs + entry->e_value_size > values_size)
+                       return EXT2_ET_EA_BAD_VALUE_OFFSET;
+
+               /* 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;
+
+               /* We only know how to deal with v2 EA blocks */
+               header = (struct ext2_ext_attr_header *) block_buf;
+               if (header->h_magic != EXT2_EXT_ATTR_MAGIC) {
+                       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;
+               }
+       }
+
+       /* no key found, success! */
+       return 0;
+}
+
+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 c12bc93..c9ef701 100644 (file)
@@ -60,6 +60,7 @@ struct ext2_extent_handle {
        int                     type;
        int                     level;
        int                     max_depth;
+       int                     max_paths;
        struct extent_path      *path;
 };
 
@@ -198,7 +199,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);
                }
@@ -272,11 +273,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 =
@@ -313,6 +313,7 @@ errcode_t ext2fs_extent_get(ext2_extent_handle_t handle,
        blk64_t                         blk;
        blk64_t                         end_blk;
        int                             orig_op, op;
+       int                             failed_csum = 0;
 
        EXT2_CHECK_MAGIC(handle, EXT2_ET_MAGIC_EXTENT_HANDLE);
 
@@ -485,6 +486,11 @@ retry:
                        return retval;
                }
 
+               if (!(handle->fs->flags & EXT2_FLAG_IGNORE_CSUM_ERRORS) &&
+                   !ext2fs_extent_block_csum_verify(handle->fs, handle->ino,
+                                                    eh))
+                       failed_csum = 1;
+
                newpath->left = newpath->entries =
                        ext2fs_le16_to_cpu(eh->eh_entries);
                newpath->max_entries = ext2fs_le16_to_cpu(eh->eh_max);
@@ -563,6 +569,9 @@ retry:
             (path->left != 0)))
                goto retry;
 
+       if (failed_csum)
+               return EXT2_ET_EXTENT_CSUM_INVALID;
+
        return 0;
 }
 
@@ -571,6 +580,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,
@@ -580,6 +590,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);
        }
@@ -734,7 +752,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)
 {
@@ -954,13 +979,11 @@ static errcode_t 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 {
                if (no_balance)
                        tocopy = 1;
@@ -1024,6 +1047,11 @@ static errcode_t 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);
@@ -1036,13 +1064,14 @@ static errcode_t 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;
@@ -1424,17 +1453,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;
@@ -1467,6 +1504,9 @@ errcode_t ext2fs_extent_set_bmap(ext2_extent_handle_t handle,
                                                              0, &newextent);
                        if (retval)
                                goto done;
+                       retval = ext2fs_extent_fix_parents(handle);
+                       if (retval)
+                               goto done;
                        retval = ext2fs_extent_get(handle,
                                                   EXT2_EXTENT_NEXT_LEAF,
                                                   &extent);
@@ -1509,7 +1549,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;
                        }
@@ -1525,11 +1565,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 0ddb245..1d5032a 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 1ad2d91..89a157b 100644 (file)
@@ -18,8 +18,6 @@
 #include "ext2_fs.h"
 #include "ext2fsP.h"
 
-static void ext2fs_free_inode_cache(struct ext2_inode_cache *icache);
-
 void ext2fs_free(ext2_filsys fs)
 {
        if (!fs || (fs->magic != EXT2_ET_MAGIC_EXT2FS_FILSYS))
@@ -67,21 +65,6 @@ void ext2fs_free(ext2_filsys fs)
 }
 
 /*
- * Free the inode cache structure
- */
-static void ext2fs_free_inode_cache(struct ext2_inode_cache *icache)
-{
-       if (--icache->refcount)
-               return;
-       if (icache->buffer)
-               ext2fs_free_mem(&icache->buffer);
-       if (icache->cache)
-               ext2fs_free_mem(&icache->cache);
-       icache->buffer_blk = 0;
-       ext2fs_free_mem(&icache);
-}
-
-/*
  * This procedure frees a badblocks list.
  */
 void ext2fs_u32_list_free(ext2_u32_list bb)
index af55097..3fc7349 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 9996e9d..a0742ee 100644 (file)
@@ -4,23 +4,27 @@
 
 #define ENTRIES_PER_LINE 4
 
-#if CRC_LE_BITS <= 8
-#define LE_TABLE_SIZE (1 << CRC_LE_BITS)
+#if CRC_LE_BITS > 8
+# define LE_TABLE_ROWS (CRC_LE_BITS/8)
+# define LE_TABLE_SIZE 256
 #else
-#define LE_TABLE_SIZE 256
+# define LE_TABLE_ROWS 1
+# define LE_TABLE_SIZE (1 << CRC_LE_BITS)
 #endif
 
-#if CRC_BE_BITS <= 8
-#define BE_TABLE_SIZE (1 << CRC_BE_BITS)
+#if CRC_BE_BITS > 8
+# define BE_TABLE_ROWS (CRC_BE_BITS/8)
+# define BE_TABLE_SIZE 256
 #else
-#define BE_TABLE_SIZE 256
+# define BE_TABLE_ROWS 1
+# define BE_TABLE_SIZE (1 << CRC_BE_BITS)
 #endif
 
-static uint32_t crc32ctable_le[8][256];
-static uint32_t crc32ctable_be[8][256];
+static uint32_t crc32table_be[BE_TABLE_ROWS][256];
+static uint32_t crc32ctable_le[LE_TABLE_ROWS][256];
 
 /**
- * crc32cinit_le() - allocate and initialize LE table data
+ * crc32init_le() - allocate and initialize LE table data
  *
  * crc is the crc of the byte i; other entries are filled in based on the
  * fact that crctable[i^j] = crctable[i] ^ crctable[j].
@@ -34,13 +38,13 @@ static void crc32cinit_le(void)
        crc32ctable_le[0][0] = 0;
 
        for (i = LE_TABLE_SIZE >> 1; i; i >>= 1) {
-               crc = (crc >> 1) ^ ((crc & 1) ? CRCPOLY_LE : 0);
+               crc = (crc >> 1) ^ ((crc & 1) ? CRC32C_POLY_LE : 0);
                for (j = 0; j < LE_TABLE_SIZE; j += 2 * i)
                        crc32ctable_le[0][i + j] = crc ^ crc32ctable_le[0][j];
        }
        for (i = 0; i < LE_TABLE_SIZE; i++) {
                crc = crc32ctable_le[0][i];
-               for (j = 1; j < 8; j++) {
+               for (j = 1; j < LE_TABLE_ROWS; j++) {
                        crc = crc32ctable_le[0][crc & 0xff] ^ (crc >> 8);
                        crc32ctable_le[j][i] = crc;
                }
@@ -48,75 +52,65 @@ static void crc32cinit_le(void)
 }
 
 /**
- * crc32cinit_be() - allocate and initialize BE table data
+ * crc32init_be() - allocate and initialize BE table data
  */
-static void crc32cinit_be(void)
+static void crc32init_be(void)
 {
        unsigned i, j;
        uint32_t crc = 0x80000000;
 
-       crc32ctable_be[0][0] = 0;
+       crc32table_be[0][0] = 0;
 
        for (i = 1; i < BE_TABLE_SIZE; i <<= 1) {
                crc = (crc << 1) ^ ((crc & 0x80000000) ? CRCPOLY_BE : 0);
                for (j = 0; j < i; j++)
-                       crc32ctable_be[0][i + j] = crc ^ crc32ctable_be[0][j];
+                       crc32table_be[0][i + j] = crc ^ crc32table_be[0][j];
        }
        for (i = 0; i < BE_TABLE_SIZE; i++) {
-               crc = crc32ctable_be[0][i];
-               for (j = 1; j < 8; j++) {
-                       crc = crc32ctable_be[0][(crc >> 24) & 0xff] ^
-                             (crc << 8);
-                       crc32ctable_be[j][i] = crc;
+               crc = crc32table_be[0][i];
+               for (j = 1; j < BE_TABLE_ROWS; j++) {
+                       crc = crc32table_be[0][(crc >> 24) & 0xff] ^ (crc << 8);
+                       crc32table_be[j][i] = crc;
                }
        }
 }
 
-static void output_table(uint32_t table[8][256], int len, char trans)
+static void output_table(uint32_t (*table)[256], int rows, int len, char *trans)
 {
        int i, j;
 
-       for (j = 0 ; j < 8; j++) {
-               printf("static const uint32_t t%d_%ce[] = {", j, trans);
+       for (j = 0 ; j < rows; j++) {
+               printf("{");
                for (i = 0; i < len - 1; i++) {
-                       if ((i % ENTRIES_PER_LINE) == 0)
+                       if (i % ENTRIES_PER_LINE == 0)
                                printf("\n");
-                       printf("to%ce(0x%8.8xL),", trans, table[j][i]);
-                       if ((i % ENTRIES_PER_LINE) != (ENTRIES_PER_LINE - 1))
-                               printf(" ");
-               }
-               printf("to%ce(0x%8.8xL)};\n\n", trans, table[j][len - 1]);
-
-               if (trans == 'l') {
-                       if ((j+1)*8 >= CRC_LE_BITS)
-                               break;
-               } else {
-                       if ((j+1)*8 >= CRC_BE_BITS)
-                               break;
+                       printf("%s(0x%8.8xL), ", trans, table[j][i]);
                }
+               printf("%s(0x%8.8xL)},\n", trans, table[j][len - 1]);
        }
 }
 
 int main(int argc, char **argv)
 {
-       printf("/*\n");
-       printf(" * crc32ctable.h - CRC32c tables\n");
-       printf(" *    this file is generated - do not edit\n");
-       printf(" *      # gen_crc32ctable > crc32c_table.h\n");
-       printf(" *    with\n");
-       printf(" *      CRC_LE_BITS = %d\n", CRC_LE_BITS);
-       printf(" *      CRC_BE_BITS = %d\n", CRC_BE_BITS);
-       printf(" */\n");
-       printf("#include <stdint.h>\n");
+       printf("/* this file is generated - do not edit */\n\n");
 
+       if (CRC_BE_BITS > 1) {
+               crc32init_be();
+               printf("static const uint32_t "
+                      "crc32table_be[%d][%d] = {",
+                      BE_TABLE_ROWS, BE_TABLE_SIZE);
+               output_table(crc32table_be, LE_TABLE_ROWS,
+                            BE_TABLE_SIZE, "tobe");
+               printf("};\n");
+       }
        if (CRC_LE_BITS > 1) {
                crc32cinit_le();
-               output_table(crc32ctable_le, LE_TABLE_SIZE, 'l');
-       }
-
-       if (CRC_BE_BITS > 1) {
-               crc32cinit_be();
-               output_table(crc32ctable_be, BE_TABLE_SIZE, 'b');
+               printf("static const uint32_t "
+                      "crc32ctable_le[%d][%d] = {",
+                      LE_TABLE_ROWS, LE_TABLE_SIZE);
+               output_table(crc32ctable_le, LE_TABLE_ROWS,
+                            LE_TABLE_SIZE, "tole");
+               printf("};\n");
        }
 
        return 0;
diff --git a/lib/ext2fs/get_num_dirs.c b/lib/ext2fs/get_num_dirs.c
new file mode 100644 (file)
index 0000000..f5644f8
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * get_num_dirs.c -- calculate number of directories
+ *
+ * Copyright 1997 by Theodore Ts'o
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Library
+ * General Public License, version 2.
+ * %End-Header%
+ */
+
+#include "config.h"
+#include <stdio.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <string.h>
+#include <time.h>
+
+#include "ext2_fs.h"
+#include "ext2fsP.h"
+
+/*
+ * Returns the number of directories in the filesystem as reported by
+ * the group descriptors.  Of course, the group descriptors could be
+ * wrong!
+ */
+errcode_t ext2fs_get_num_dirs(ext2_filsys fs, ext2_ino_t *ret_num_dirs)
+{
+       dgrp_t  i;
+       ext2_ino_t      num_dirs, max_dirs;
+
+       EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
+
+       num_dirs = 0;
+       max_dirs = fs->super->s_inodes_per_group;
+       for (i = 0; i < fs->group_desc_count; i++) {
+               if (ext2fs_bg_used_dirs_count(fs, i) > max_dirs)
+                       num_dirs += max_dirs / 8;
+               else
+                       num_dirs += ext2fs_bg_used_dirs_count(fs, i);
+       }
+       if (num_dirs > fs->super->s_inodes_count)
+               num_dirs = fs->super->s_inodes_count;
+
+       *ret_num_dirs = num_dirs;
+
+       return 0;
+}
+
index 52aea62..4c9c765 100644 (file)
@@ -49,21 +49,20 @@ static int get_pathname_proc(struct ext2_dir_entry *dirent,
 {
        struct get_pathname_struct      *gp;
        errcode_t                       retval;
+       int name_len = ext2fs_dirent_name_len(dirent);
 
        gp = (struct get_pathname_struct *) priv_data;
 
-       if (((dirent->name_len & 0xFF) == 2) &&
-           !strncmp(dirent->name, "..", 2))
+       if ((name_len == 2) && !strncmp(dirent->name, "..", 2))
                gp->parent = dirent->inode;
        if (dirent->inode == gp->search_ino) {
-               retval = ext2fs_get_mem((dirent->name_len & 0xFF) + 1,
-                                       &gp->name);
+               retval = ext2fs_get_mem(name_len + 1, &gp->name);
                if (retval) {
                        gp->errcode = retval;
                        return DIRENT_ABORT;
                }
-               strncpy(gp->name, dirent->name, (dirent->name_len & 0xFF));
-               gp->name[dirent->name_len & 0xFF] = '\0';
+               strncpy(gp->name, dirent->name, name_len);
+               gp->name[name_len] = '\0';
                return DIRENT_ABORT;
        }
        return 0;
index a3b20f0..5e1f5c6 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 36c94a9..75fbf8e 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..7eb8b94
--- /dev/null
@@ -0,0 +1,858 @@
+/*
+ * 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 <limits.h> /* for PATH_MAX */
+
+#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 == EXT2_ET_EA_KEY_NOT_FOUND) {
+               data->ea_size = 0;
+               data->ea_data = NULL;
+               retval = 0;
+       } else 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 out1;
+
+       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 out1;
+       }
+#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, rec_len;
+       int csum_size = 0;
+       int filetype = 0;
+
+       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 + EXT4_INLINE_DATA_DOTDOT_SIZE,
+                                       size, 0);
+       if (retval)
+               goto errout;
+#endif
+
+       /* Adjust the rec_len */
+       retval = ext2fs_inline_data_convert_dir(fs, ino, blk_buf, buf, size);
+       if (retval)
+               goto errout;
+       /* 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) {
+               retval = ext2fs_inline_data_ea_remove(fs, ino);
+               if (retval)
+                       return retval;
+               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 &&
+           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 %u\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 (%u) != tmp (%u)\n",
+                       parent, tmp);
+               return 1;
+       }
+
+       for (i = 0, dir = 13; i < 4; i++, dir++) {
+               tmp = 0;
+               snprintf(dirname, sizeof(dirname), "%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 (%u) != tmp (%u)\n",
+                               dir, tmp);
+                       return 1;
+               }
+       }
+
+       snprintf(dirname, sizeof(dirname), "%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 573a8fa..6c766af 100644 (file)
 #include "ext2fsP.h"
 #include "e2image.h"
 
+#define IBLOCK_STATUS_CSUMS_OK 1
+#define IBLOCK_STATUS_INSANE   2
+#define SCAN_BLOCK_STATUS(scan)        ((scan)->temp_buffer + (scan)->inode_size)
+
 struct ext2_struct_inode_scan {
        errcode_t               magic;
        ext2_filsys             fs;
@@ -72,8 +76,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 +108,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 +180,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 =
@@ -166,16 +197,17 @@ errcode_t ext2fs_open_inode_scan(ext2_filsys fs, int buffer_blocks,
                ext2fs_free_mem(&scan);
                return retval;
        }
-       retval = ext2fs_get_mem(scan->inode_size, &scan->temp_buffer);
+       retval = ext2fs_get_mem(scan->inode_size + scan->inode_buffer_blocks,
+                               &scan->temp_buffer);
        if (retval) {
                ext2fs_free_mem(&scan->inode_buffer);
                ext2fs_free_mem(&scan);
                return retval;
        }
+       memset(SCAN_BLOCK_STATUS(scan), 0, scan->inode_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 +273,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 =
@@ -323,6 +354,114 @@ static errcode_t check_for_inode_bad_blocks(ext2_inode_scan scan,
        return 0;
 }
 
+static int block_map_looks_insane(ext2_filsys fs,
+                                 struct ext2_inode_large *inode)
+{
+       unsigned int i, bad;
+
+       /* We're only interested in block mapped files, dirs, and symlinks */
+       if ((inode->i_flags & EXT4_INLINE_DATA_FL) ||
+           (inode->i_flags & EXT4_EXTENTS_FL))
+               return 0;
+       if (!LINUX_S_ISREG(inode->i_mode) &&
+           !LINUX_S_ISLNK(inode->i_mode) &&
+           !LINUX_S_ISDIR(inode->i_mode))
+               return 0;
+       if (LINUX_S_ISLNK(inode->i_mode) &&
+           EXT2_I_SIZE(inode) <= sizeof(inode->i_block))
+               return 0;
+
+       /* Unused inodes probably aren't insane */
+       if (inode->i_links_count == 0)
+               return 0;
+
+       /* See if more than half the block maps are insane */
+       for (i = 0, bad = 0; i < EXT2_N_BLOCKS; i++)
+               if (inode->i_block[i] != 0 &&
+                   (inode->i_block[i] < fs->super->s_first_data_block ||
+                    inode->i_block[i] >= ext2fs_blocks_count(fs->super)))
+                       bad++;
+       return bad > EXT2_N_BLOCKS / 2;
+}
+
+static int extent_head_looks_insane(struct ext2_inode_large *inode)
+{
+       if (!(inode->i_flags & EXT4_EXTENTS_FL) ||
+           ext2fs_extent_header_verify(inode->i_block,
+                                       sizeof(inode->i_block)) == 0)
+               return 0;
+       return 1;
+}
+
+/*
+ * Check all the inodes that we just read into the buffer.  Record what we
+ * find here -- currently, we can observe that all checksums are ok; more
+ * than half the inodes are insane; or no conclusions at all.
+ */
+static void check_inode_block_sanity(ext2_inode_scan scan, blk64_t num_blocks)
+{
+       ext2_ino_t      ino, inodes_to_scan;
+       unsigned int    badness, checksum_failures;
+       unsigned int    inodes_in_buf, inodes_per_block;
+       void            *p;
+       struct ext2_inode_large *inode;
+       char            *block_status;
+       unsigned int    blk;
+
+       if (!(scan->scan_flags & EXT2_SF_WARN_GARBAGE_INODES))
+               return;
+
+       inodes_to_scan = scan->inodes_left;
+       inodes_in_buf = num_blocks * scan->fs->blocksize / scan->inode_size;
+       if (inodes_to_scan > inodes_in_buf)
+               inodes_to_scan = inodes_in_buf;
+
+       p = scan->inode_buffer;
+       ino = scan->current_inode + 1;
+       checksum_failures = badness = 0;
+       block_status = SCAN_BLOCK_STATUS(scan);
+       memset(block_status, 0, scan->inode_buffer_blocks);
+       inodes_per_block = EXT2_INODES_PER_BLOCK(scan->fs->super);
+
+       while (inodes_to_scan > 0) {
+               blk = (p - (void *)scan->inode_buffer) / scan->fs->blocksize;
+               inode = p;
+
+               /* Is this inode insane? */
+               if (!ext2fs_inode_csum_verify(scan->fs, ino, inode)) {
+                       checksum_failures++;
+                       badness++;
+               } else if (extent_head_looks_insane(inode) ||
+                          block_map_looks_insane(scan->fs, inode))
+                       badness++;
+
+               /* If more than half are insane, declare the whole block bad */
+               if (badness > inodes_per_block / 2) {
+                       unsigned int ino_adj;
+
+                       block_status[blk] |= IBLOCK_STATUS_INSANE;
+                       ino_adj = inodes_per_block -
+                                               ((ino - 1) % inodes_per_block);
+                       if (ino_adj > inodes_to_scan)
+                               ino_adj = inodes_to_scan;
+                       inodes_to_scan -= ino_adj;
+                       p += scan->inode_size * ino_adj;
+                       ino += ino_adj;
+                       checksum_failures = badness = 0;
+                       continue;
+               }
+
+               if ((ino % inodes_per_block) == 0) {
+                       if (checksum_failures == 0)
+                               block_status[blk] |= IBLOCK_STATUS_CSUMS_OK;
+                       checksum_failures = badness = 0;
+               }
+               inodes_to_scan--;
+               p += scan->inode_size;
+               ino++;
+       };
+}
+
 /*
  * This function is called by ext2fs_get_next_inode when it needs to
  * read in more blocks from the current blockgroup's inode table.
@@ -372,12 +511,15 @@ static errcode_t get_next_blocks(ext2_inode_scan scan)
                if (retval)
                        return EXT2_ET_NEXT_INODE_READ;
        }
+       check_inode_block_sanity(scan, num_blocks);
+
        scan->ptr = scan->inode_buffer;
        scan->bytes_left = num_blocks * scan->fs->blocksize;
 
        scan->blocks_left -= num_blocks;
        if (scan->current_block)
                scan->current_block += num_blocks;
+
        return 0;
 }
 
@@ -407,8 +549,14 @@ errcode_t ext2fs_get_next_inode_full(ext2_inode_scan scan, ext2_ino_t *ino,
 {
        errcode_t       retval;
        int             extra_bytes = 0;
+       int             length;
+       struct ext2_inode_large *iptr = (struct ext2_inode_large *)inode;
+       char            *iblock_status;
+       unsigned int    iblk;
 
        EXT2_CHECK_MAGIC(scan, EXT2_ET_MAGIC_INODE_SCAN);
+       length = EXT2_INODE_SIZE(scan->fs->super);
+       iblock_status = SCAN_BLOCK_STATUS(scan);
 
        /*
         * Do we need to start reading a new block group?
@@ -469,44 +617,74 @@ 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;
+       iblk = scan->current_inode % EXT2_INODES_PER_GROUP(scan->fs->super) /
+                               EXT2_INODES_PER_BLOCK(scan->fs->super) %
+                               scan->inode_buffer_blocks;
        if (extra_bytes) {
                memcpy(scan->temp_buffer+extra_bytes, scan->ptr,
                       scan->inode_size - extra_bytes);
                scan->ptr += scan->inode_size - extra_bytes;
                scan->bytes_left -= scan->inode_size - extra_bytes;
 
+               /* Verify the inode checksum. */
+               if (!(iblock_status[iblk] & IBLOCK_STATUS_CSUMS_OK) &&
+                   !(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 (!(iblock_status[iblk] & IBLOCK_STATUS_CSUMS_OK) &&
+                   !(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;
                if (scan->scan_flags & EXT2_SF_BAD_INODE_BLK)
                        retval = EXT2_ET_BAD_BLOCK_IN_INODE_TABLE;
        }
+       if ((iblock_status[iblk] & IBLOCK_STATUS_INSANE) &&
+           (retval == 0 || retval == EXT2_ET_INODE_CSUM_INVALID))
+               retval = EXT2_ET_INODE_IS_GARBAGE;
 
        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 +705,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, fail_csum;
 
        EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
 
@@ -544,18 +725,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 +759,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 +784,26 @@ 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. */
+       fail_csum = !ext2fs_inode_csum_verify(fs, ino, iptr);
 
 #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 */
+       if (!fail_csum) {
+               fs->icache->cache_last = cache_slot;
+               fs->icache->cache[cache_slot].ino = ino;
+       }
+       memcpy(inode, iptr, (bufsize > length) ? length : bufsize);
+
+       if (!(fs->flags & EXT2_FLAG_IGNORE_CSUM_ERRORS) && fail_csum)
+               return EXT2_ET_INODE_CSUM_INVALID;
 
        return 0;
 }
@@ -635,9 +821,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 +835,55 @@ 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 & EXT2_FLAG_IGNORE_CSUM_ERRORS) |
+                           (fs->flags & ~EXT2_FLAG_IGNORE_CSUM_ERRORS);
+               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 +896,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 +928,7 @@ errcode_t ext2fs_write_inode_full(ext2_filsys fs, ext2_ino_t ino,
 
        fs->flags |= EXT2_FLAG_CHANGED;
 errout:
-       if (w_inode && w_inode != &temp_inode)
-               free(w_inode);
+       ext2fs_free_mem(&w_inode);
        return retval;
 }
 
index 7b8aafd..7947ef5 100644 (file)
@@ -17,6 +17,8 @@
 
 #define cpu_to_be32(n) htonl(n)
 #define be32_to_cpu(n) ntohl(n)
+#define cpu_to_be16(n) htons(n)
+#define be16_to_cpu(n) ntohs(n)
 
 typedef unsigned int tid_t;
 typedef struct journal_s journal_t;
index 2baae73..a9cdc30 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 */
@@ -208,7 +230,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[JFS_USERS_SIZE];                /* ids of all fs'es sharing the log */
@@ -228,18 +253,56 @@ typedef struct journal_superblock_s
 
 #define JFS_FEATURE_COMPAT_CHECKSUM    0x00000001
 
-#define JFS_FEATURE_INCOMPAT_REVOKE    0x00000001
-
 #define JFS_FEATURE_INCOMPAT_REVOKE            0x00000001
 #define JFS_FEATURE_INCOMPAT_64BIT             0x00000002
 #define JFS_FEATURE_INCOMPAT_ASYNC_COMMIT      0x00000004
+#define JFS_FEATURE_INCOMPAT_CSUM_V2           0x00000008
 
 /* Features known to this kernel version: */
 #define JFS_KNOWN_COMPAT_FEATURES      0
 #define JFS_KNOWN_ROCOMPAT_FEATURES    0
 #define JFS_KNOWN_INCOMPAT_FEATURES    (JFS_FEATURE_INCOMPAT_REVOKE|\
                                         JFS_FEATURE_INCOMPAT_ASYNC_COMMIT|\
-                                        JFS_FEATURE_INCOMPAT_64BIT)
+                                        JFS_FEATURE_INCOMPAT_64BIT|\
+                                        JFS_FEATURE_INCOMPAT_CSUM_V2)
+
+#if (defined(E2FSCK_INCLUDE_INLINE_FUNCS) || !defined(NO_INLINE_FUNCS))
+#ifdef E2FSCK_INCLUDE_INLINE_FUNCS
+#if (__STDC_VERSION__ >= 199901L)
+#define _INLINE_ extern inline
+#else
+#define _INLINE_ inline
+#endif
+#else /* !E2FSCK_INCLUDE_INLINE FUNCS */
+#if (__STDC_VERSION__ >= 199901L)
+#define _INLINE_ inline
+#else /* not C99 */
+#ifdef __GNUC__
+#define _INLINE_ extern __inline__
+#else                          /* For Watcom C */
+#define _INLINE_ extern inline
+#endif /* __GNUC__ */
+#endif /* __STDC_VERSION__ >= 199901L */
+#endif /* INCLUDE_INLINE_FUNCS */
+
+/*
+ * helper functions to deal with 32 or 64bit block numbers.
+ */
+_INLINE_ size_t journal_tag_bytes(journal_t *journal)
+{
+       journal_block_tag_t tag;
+       size_t x = 0;
+
+       if (JFS_HAS_INCOMPAT_FEATURE(journal, JFS_FEATURE_INCOMPAT_CSUM_V2))
+               x += sizeof(tag.t_checksum);
+
+       if (JFS_HAS_INCOMPAT_FEATURE(journal, JFS_FEATURE_INCOMPAT_64BIT))
+               return x + JBD_TAG_SIZE64;
+       else
+               return x + JBD_TAG_SIZE32;
+}
+#undef _INLINE_
+#endif
 
 #ifdef __KERNEL__
 
index bf3c859..09e6cb4 100644 (file)
@@ -41,6 +41,8 @@ static int link_proc(struct ext2_dir_entry *dirent,
        struct ext2_dir_entry *next;
        unsigned int rec_len, min_rec_len, curr_rec_len;
        int ret = 0;
+       int csum_size = 0;
+       struct ext2_dir_entry_tail *t;
 
        if (ls->done)
                return DIRENT_ABORT;
@@ -51,12 +53,15 @@ static int link_proc(struct ext2_dir_entry *dirent,
        if (ls->err)
                return DIRENT_ABORT;
 
+       if (EXT2_HAS_RO_COMPAT_FEATURE(ls->fs->super,
+                                      EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
+               csum_size = sizeof(struct ext2_dir_entry_tail);
        /*
         * See if the following directory entry (if any) is unused;
         * if so, absorb it into this one.
         */
        next = (struct ext2_dir_entry *) (buf + offset + curr_rec_len);
-       if ((offset + (int) curr_rec_len < blocksize - 8) &&
+       if ((offset + (int) curr_rec_len < blocksize - (8 + csum_size)) &&
            (next->inode == 0) &&
            (offset + (int) curr_rec_len + (int) next->rec_len <= blocksize)) {
                curr_rec_len += next->rec_len;
@@ -67,12 +72,46 @@ static int link_proc(struct ext2_dir_entry *dirent,
        }
 
        /*
+        * Since ext2fs_link blows away htree data, we need to be
+        * careful -- if metadata_csum is enabled and we're passed in
+        * a dirent that contains htree data, we need to create the
+        * fake entry at the end of the block that hides the checksum.
+        */
+
+       /* De-convert a dx_node block */
+       if (csum_size &&
+           curr_rec_len == ls->fs->blocksize &&
+           !dirent->inode) {
+               curr_rec_len -= csum_size;
+               ls->err = ext2fs_set_rec_len(ls->fs, curr_rec_len, dirent);
+               if (ls->err)
+                       return DIRENT_ABORT;
+               t = EXT2_DIRENT_TAIL(buf, ls->fs->blocksize);
+               ext2fs_initialize_dirent_tail(ls->fs, t);
+               ret = DIRENT_CHANGED;
+       }
+
+       /* De-convert a dx_root block */
+       if (csum_size &&
+           curr_rec_len == ls->fs->blocksize - EXT2_DIR_REC_LEN(1) &&
+           offset == EXT2_DIR_REC_LEN(1) &&
+           dirent->name[0] == '.' && dirent->name[1] == '.') {
+               curr_rec_len -= csum_size;
+               ls->err = ext2fs_set_rec_len(ls->fs, curr_rec_len, dirent);
+               if (ls->err)
+                       return DIRENT_ABORT;
+               t = EXT2_DIRENT_TAIL(buf, ls->fs->blocksize);
+               ext2fs_initialize_dirent_tail(ls->fs, t);
+               ret = DIRENT_CHANGED;
+       }
+
+       /*
         * If the directory entry is used, see if we can split the
         * directory entry to make room for the new name.  If so,
         * truncate it and return.
         */
        if (dirent->inode) {
-               min_rec_len = EXT2_DIR_REC_LEN(dirent->name_len & 0xFF);
+               min_rec_len = EXT2_DIR_REC_LEN(ext2fs_dirent_name_len(dirent));
                if (curr_rec_len < (min_rec_len + rec_len))
                        return ret;
                rec_len = curr_rec_len - min_rec_len;
@@ -82,7 +121,8 @@ static int link_proc(struct ext2_dir_entry *dirent,
                next = (struct ext2_dir_entry *) (buf + offset +
                                                  dirent->rec_len);
                next->inode = 0;
-               next->name_len = 0;
+               ext2fs_dirent_set_name_len(next, 0);
+               ext2fs_dirent_set_file_type(next, 0);
                ls->err = ext2fs_set_rec_len(ls->fs, rec_len, next);
                if (ls->err)
                        return DIRENT_ABORT;
@@ -96,10 +136,10 @@ static int link_proc(struct ext2_dir_entry *dirent,
        if (curr_rec_len < rec_len)
                return ret;
        dirent->inode = ls->inode;
-       dirent->name_len = ls->namelen;
+       ext2fs_dirent_set_name_len(dirent, ls->namelen);
        strncpy(dirent->name, ls->name, ls->namelen);
        if (ls->sb->s_feature_incompat & EXT2_FEATURE_INCOMPAT_FILETYPE)
-               dirent->name_len |= (ls->flags & 0x7) << 8;
+               ext2fs_dirent_set_file_type(dirent, ls->flags & 0x7);
 
        ls->done++;
        return DIRENT_ABORT|DIRENT_CHANGED;
@@ -147,6 +187,11 @@ errcode_t ext2fs_link(ext2_filsys fs, ext2_ino_t dir, const char *name,
        if ((retval = ext2fs_read_inode(fs, dir, &inode)) != 0)
                return retval;
 
+       /*
+        * If this function changes to preserve the htree, remove the
+        * two hunks in link_proc that shove checksum tails into the
+        * former dx_root/dx_node blocks.
+        */
        if (inode.i_flags & EXT2_INDEX_FL) {
                inode.i_flags &= ~EXT2_INDEX_FL;
                if ((retval = ext2fs_write_inode(fs, dir, &inode)) != 0)
index 0e66e71..c1d802c 100644 (file)
@@ -37,9 +37,9 @@ static int lookup_proc(struct ext2_dir_entry *dirent,
 {
        struct lookup_struct *ls = (struct lookup_struct *) priv_data;
 
-       if (ls->len != (dirent->name_len & 0xFF))
+       if (ls->len != ext2fs_dirent_name_len(dirent))
                return 0;
-       if (strncmp(ls->name, dirent->name, (dirent->name_len & 0xFF)))
+       if (strncmp(ls->name, dirent->name, ext2fs_dirent_name_len(dirent)))
                return 0;
        *ls->inode = dirent->inode;
        ls->found++;
index b12bf2d..c4c7967 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,10 +42,20 @@ 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
         */
        if (!ino) {
@@ -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 e4c7dcc..afb825c 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 3e2c0db..506d609 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,51 @@ 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);
+       if (retval)
+               goto errout;
+
+#ifdef WORDS_BIGENDIAN
+       retval = ext2fs_dirent_swab_out2(fs, (char *)dir, rec_len, 0);
+       if (retval)
+               goto errout;
+#endif
+
+errout:
+       return retval;
+}
index ba501e6..00320f3 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
@@ -420,8 +447,7 @@ errcode_t ext2fs_open2(const char *name, const char *io_options,
         * If recovery is from backup superblock, Clear _UNININT flags &
         * reset bg_itable_unused to zero
         */
-       if (superblock > 1 && EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
-                                       EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) {
+       if (superblock > 1 && ext2fs_has_group_desc_csum(fs)) {
                dgrp_t group;
 
                for (group = 0; group < fs->group_desc_count; group++) {
index 8c9a6f1..83556b1 100644 (file)
 static char spaces[80], backspaces[80];
 static time_t last_update;
 
+struct ext2fs_progress_ops ext2fs_numeric_progress_ops = {
+       .init           = ext2fs_numeric_progress_init,
+       .update         = ext2fs_numeric_progress_update,
+       .close          = ext2fs_numeric_progress_close,
+};
+
 static int int_log10(unsigned int arg)
 {
        int     l;
index a3d020e..3cce1f8 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;
                } 
@@ -395,8 +402,12 @@ static errcode_t ext2fs_punch_extent(ext2_filsys fs, ext2_ino_t ino,
                                goto errout;
                        retval = 0;
 
-                       /* Jump forward to the next extent. */
-                       ext2fs_extent_goto(handle, next_lblk);
+                       /*
+                        * Jump forward to the next extent.  If there are
+                        * errors, the ext2fs_extent_get down below will
+                        * capture them for us.
+                        */
+                       (void)ext2fs_extent_goto(handle, next_lblk);
                        op = EXT2_EXTENT_CURRENT;
                }
                if (retval)
@@ -423,6 +434,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 +480,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 a07ecd5..ae593d4 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 2a7b768..e2aa41d 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]);
 }
@@ -195,7 +196,9 @@ void ext2fs_swap_ext_attr(char *to, char *from, int bufsize, int has_header)
                to_entry   = (struct ext2_ext_attr_entry *)to_header;
        }
 
-       while ((char *)from_entry < from_end && *(__u32 *)from_entry) {
+       while ((char *)from_entry < from_end &&
+              (char *)EXT2_EXT_ATTR_NEXT(from_entry) <= from_end &&
+              *(__u32 *)from_entry) {
                ext2fs_swap_ext_attr_entry(to_entry, from_entry);
                from_entry = EXT2_EXT_ATTR_NEXT(from_entry);
                to_entry   = EXT2_EXT_ATTR_NEXT(to_entry);
@@ -208,6 +211,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 +238,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 +360,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 f9cec8a..b085bbb 100644 (file)
@@ -113,7 +113,7 @@ int main(int argc, char **argv)
        check_field(s_mmp_block, 8);
        check_field(s_raid_stripe_width, 4);
        check_field(s_log_groups_per_flex, 1);
-       check_field(s_reserved_char_pad, 1);
+       check_field(s_checksum_type, 1);
        check_field(s_reserved_pad, 2);
        check_field(s_kbytes_written, 8);
        check_field(s_snapshot_inum, 4);
index d2d31cc..8ab27ee 100644 (file)
@@ -44,9 +44,9 @@ static int unlink_proc(struct ext2_dir_entry *dirent,
        ls->prev = dirent;
 
        if (ls->name) {
-               if ((dirent->name_len & 0xFF) != ls->namelen)
+               if (ext2fs_dirent_name_len(dirent) != ls->namelen)
                        return 0;
-               if (strncmp(ls->name, dirent->name, dirent->name_len & 0xFF))
+               if (strncmp(ls->name, dirent->name, ext2fs_dirent_name_len(dirent)))
                        return 0;
        }
        if (ls->inode) {
index 895e36e..db5d90a 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 4dd42ed..7efe39c 100644 (file)
@@ -44,6 +44,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 $<
 #ELF_CMT#      $(Q) $(CC) $(ALL_CFLAGS) -fPIC -o elfshared/$*.o -c $<
 #BSDLIB_CMT#   $(Q) $(CC) $(ALL_CFLAGS) $(BSDLIB_PIC_FLAG) -o pic/$*.o -c $<
index 24c5e37..44edc0d 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 $<
 @ELF_CMT@      $(Q) $(CC) $(ALL_CFLAGS) -DSHARED_ELF_LIB -fPIC -o elfshared/$*.o -c $<
 @BSDLIB_CMT@   $(Q) $(CC) $(ALL_CFLAGS) $(BSDLIB_PIC_FLAG) -o pic/$*.o -c $<
index 74ca478..f51714b 100644 (file)
@@ -62,6 +62,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 $<
 @ELF_CMT@      $(Q) $(CC) $(ALL_CFLAGS) -fPIC -o elfshared/$*.o -c $<
 @BSDLIB_CMT@   $(Q) $(CC) $(ALL_CFLAGS) $(BSDLIB_PIC_FLAG) -o pic/$*.o -c $<
index a68edff..925846e 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
@@ -57,12 +57,14 @@ FILEFRAG_OBJS=      filefrag.o
 E2UNDO_OBJS=  e2undo.o
 E4DEFRAG_OBJS= e4defrag.o
 E2FREEFRAG_OBJS= e2freefrag.o
+E2FUZZ_OBJS=   e2fuzz.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/mk_hugefiles.o
+                       profiled/mk_hugefiles.o profiled/create_inode.o
+
 PROFILED_CHATTR_OBJS=  profiled/chattr.o
 PROFILED_LSATTR_OBJS=  profiled/lsattr.o
 PROFILED_UUIDGEN_OBJS= profiled/uuidgen.o
@@ -84,7 +86,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)
@@ -103,10 +105,11 @@ 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) \
-       $(FMANPAGES) $(LPROGS) $(E4DEFRAG_PROG)
+       $(FMANPAGES) $(LPROGS) $(E4DEFRAG_PROG) e2fuzz
 
 @PROFILE_CMT@all:: tune2fs.profiled blkid.profiled e2image.profiled \
        e2undo.profiled mke2fs.profiled dumpe2fs.profiled fsck.profiled \
@@ -343,6 +346,12 @@ e2freefrag.profiled: $(E2FREEFRAG_OBJS) $(PROFILED_DEPLIBS)
        $(Q) $(CC) $(ALL_LDFLAGS) -g -pg -o e2freefrag.profiled \
                $(PROFILED_E2FREEFRAG_OBJS) $(PROFILED_LIBS) $(SYSLIBS)
 
+e2fuzz: $(E2FUZZ_OBJS) $(DEPLIBS) $(DEPLIBBLKID) $(DEPLIBUUID) \
+               $(DEPLIBQUOTA) $(LIBEXT2FS)
+       $(E) "  LD $@"
+       $(Q) $(CC) $(ALL_LDFLAGS) -o e2fuzz $(E2FUZZ_OBJS) $(LIBS) \
+               $(LIBBLKID) $(LIBUUID) $(LIBEXT2FS)
+
 filefrag: $(FILEFRAG_OBJS)
        $(E) "  LD $@"
        $(Q) $(CC) $(ALL_LDFLAGS) -o filefrag $(FILEFRAG_OBJS) $(SYSLIBS)
@@ -609,7 +618,7 @@ clean::
                blkid.profiled tune2fs.profiled e2image.profiled \
                e2undo.profiled mke2fs.profiled dumpe2fs.profiled \
                logsave.profiled filefrag.profiled uuidgen.profiled \
-               uuidd.profiled e2image.profiled mke2fs.conf \
+               uuidd.profiled e2image.profiled e2fuzz mke2fs.conf \
                profiled/*.o \#* *.s *.o *.a *~ core gmon.out
 
 mostlyclean: clean
@@ -644,11 +653,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 \
@@ -736,3 +746,18 @@ 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
+e2fuzz.o: $(srcdir)/e2fuzz.c $(top_builddir)/lib/config.h \
+ $(top_builddir)/lib/dirpaths.h $(top_srcdir)/lib/ext2fs/tdb.h \
+ $(top_srcdir)/lib/ext2fs/ext2fs.h $(top_builddir)/lib/ext2fs/ext2_types.h \
+ $(top_srcdir)/lib/ext2fs/ext2_fs.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)/nls-enable.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..4d56719
--- /dev/null
@@ -0,0 +1,771 @@
+/*
+ * create_inode.c --- create an inode
+ *
+ * Copyright (C) 2014 Robert Yang <liezhi.yang@windriver.com>
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU library
+ * General Public License, version 2.
+ * %End-Header%
+ */
+
+#include <time.h>
+#include <unistd.h>
+#include <limits.h> /* for PATH_MAX */
+#ifdef HAVE_ATTR_XATTR_H
+#include <attr/xattr.h>
+#endif
+
+#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;
+}
+
+static errcode_t set_inode_xattr(ext2_filsys fs, ext2_ino_t ino, const char *filename)
+{
+#ifdef HAVE_LLISTXATTR
+       errcode_t                       retval, close_retval;
+       struct ext2_inode               inode;
+       struct ext2_xattr_handle        *handle;
+       ssize_t                         size, value_size;
+       char                            *list;
+       int                             i;
+
+       size = llistxattr(filename, NULL, 0);
+       if (size == -1) {
+               com_err(__func__, errno, "llistxattr failed on %s", filename);
+               return errno;
+       } else if (size == 0) {
+               return 0;
+       }
+
+       retval = ext2fs_xattrs_open(fs, ino, &handle);
+       if (retval) {
+               if (retval == EXT2_ET_MISSING_EA_FEATURE)
+                       return 0;
+               com_err(__func__, retval, "while opening inode %u", ino);
+               return retval;
+       }
+
+       retval = ext2fs_get_mem(size, &list);
+       if (retval) {
+               com_err(__func__, retval, "whilst allocating memory");
+               goto out;
+       }
+
+       size = llistxattr(filename, list, size);
+       if (size == -1) {
+               com_err(__func__, errno, "llistxattr failed on %s", filename);
+               retval = errno;
+               goto out;
+        }
+
+       for (i = 0; i < size; i += strlen(&list[i]) + 1) {
+               const char *name = &list[i];
+               char *value;
+
+               value_size = getxattr(filename, name, NULL, 0);
+               if (value_size == -1) {
+                       com_err(__func__, errno, "getxattr failed on %s",
+                               filename);
+                       retval = errno;
+                       break;
+               }
+
+               retval = ext2fs_get_mem(value_size, &value);
+               if (retval) {
+                       com_err(__func__, retval, "whilst allocating memory");
+                       break;
+               }
+
+               value_size = getxattr(filename, name, value, value_size);
+               if (value_size == -1) {
+                       ext2fs_free_mem(&value);
+                       com_err(__func__, errno, "getxattr failed on %s",
+                               filename);
+                       retval = errno;
+                       break;
+               }
+
+               retval = ext2fs_xattr_set(handle, name, value, value_size);
+               ext2fs_free_mem(&value);
+               if (retval) {
+                       com_err(__func__, retval,
+                               "while writing xattr %u", ino);
+                       break;
+               }
+
+       }
+ out:
+       ext2fs_free_mem(&list);
+       close_retval = ext2fs_xattrs_close(&handle);
+       if (close_retval) {
+               com_err(__func__, retval, "while closing inode %u", ino);
+               retval = retval ? retval : close_retval;
+       }
+       return retval;
+#else /* HAVE_LLISTXATTR */
+       return 0;
+#endif  /* HAVE_LLISTXATTR */
+}
+
+/* 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           devmajor, devminor, 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;
+               break;
+       default:
+               return EXT2_ET_INVALID_ARGUMENT;
+       }
+
+       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 retval;
+       }
+       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);
+
+       if (filetype != S_IFIFO) {
+               devmajor = major(st->st_rdev);
+               devminor = minor(st->st_rdev);
+
+               if ((devmajor < 256) && (devminor < 256)) {
+                       inode.i_block[0] = devmajor * 256 + devminor;
+                       inode.i_block[1] = 0;
+               } else {
+                       inode.i_block[0] = 0;
+                       inode.i_block[1] = (devminor & 0xff) | (devmajor << 8) |
+                                          ((devminor & ~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, close_ret;
+       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");
+               goto out_close;
+       }
+
+       /* 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 zero buffer\n");
+               goto out_free_buf;
+       }
+
+       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;
+               }
+       }
+
+fail:
+       ext2fs_free_mem(&zero_buf);
+out_free_buf:
+       ext2fs_free_mem(&buf);
+out_close:
+       close_ret = ext2fs_file_close(e2_file);
+       if (retval == 0)
+               retval = close_ret;
+       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 = ext2fs_open_file(src, O_RDONLY, 0);
+       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;
+       retval = ext2fs_inode_size_set(fs, &inode, statbuf.st_size);
+       if (retval) {
+               com_err(dest, retval, 0);
+               close(fd);
+               return retval;
+       }
+       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);
+                               retval = errno;
+                               goto out;
+                       }
+                       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;
+               }
+
+               retval = set_inode_xattr(fs, ino, name);
+               if (retval) {
+                       com_err(__func__, retval,
+                               _("while setting xattrs 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 cc18ad8..7cbb99b 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("%s", _("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("%s", _("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"
@@ -583,7 +620,7 @@ int main (int argc, char ** argv)
                flags |= EXT2_FLAG_FORCE;
        if (image_dump)
                flags |= EXT2_FLAG_IMAGE_FILE;
-
+try_open_again:
        if (use_superblock && !use_blocksize) {
                for (use_blocksize = EXT2_MIN_BLOCK_SIZE;
                     use_blocksize <= EXT2_MAX_BLOCK_SIZE;
@@ -598,6 +635,13 @@ int main (int argc, char ** argv)
        } else
                retval = ext2fs_open (device_name, flags, use_superblock,
                                      use_blocksize, unix_io_manager, &fs);
+       if (retval && !(flags & EXT2_FLAG_IGNORE_CSUM_ERRORS)) {
+               flags |= EXT2_FLAG_IGNORE_CSUM_ERRORS;
+               goto try_open_again;
+       }
+       if (!retval && (fs->flags & EXT2_FLAG_IGNORE_CSUM_ERRORS))
+               printf("%s", _("\n*** Checksum errors detected in filesystem!  Run e2fsck now!\n\n"));
+       flags |= EXT2_FLAG_IGNORE_CSUM_ERRORS;
        if (retval) {
                com_err (program_name, retval, _("while trying to open %s"),
                         device_name);
@@ -626,7 +670,15 @@ int main (int argc, char ** argv)
                        ext2fs_close_free(&fs);
                        exit (0);
                }
+               fs->flags &= ~EXT2_FLAG_IGNORE_CSUM_ERRORS;
+try_bitmaps_again:
                retval = ext2fs_read_bitmaps (fs);
+               if (retval && !(fs->flags & EXT2_FLAG_IGNORE_CSUM_ERRORS)) {
+                       fs->flags |= EXT2_FLAG_IGNORE_CSUM_ERRORS;
+                       goto try_bitmaps_again;
+               }
+               if (!retval && (fs->flags & EXT2_FLAG_IGNORE_CSUM_ERRORS))
+                       printf("%s", _("\n*** Checksum errors detected in bitmaps!  Run e2fsck now!\n\n"));
                list_desc (fs);
                if (retval) {
                        printf(_("\n%s: %s: error reading bitmaps: %s\n"),
diff --git a/misc/e2fuzz.c b/misc/e2fuzz.c
new file mode 100644 (file)
index 0000000..91aafe5
--- /dev/null
@@ -0,0 +1,354 @@
+/*
+ * e2fuzz.c -- Fuzz an ext4 image, for testing purposes.
+ *
+ * Copyright (C) 2014 Oracle.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Library
+ * General Public License, version 2.
+ * %End-Header%
+ */
+#define _XOPEN_SOURCE          600
+#define _FILE_OFFSET_BITS       64
+#define _LARGEFILE64_SOURCE     1
+#define _GNU_SOURCE            1
+
+#include "config.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdint.h>
+#include <unistd.h>
+#ifdef HAVE_GETOPT_H
+#include <getopt.h>
+#endif
+
+#include "ext2fs/ext2_fs.h"
+#include "ext2fs/ext2fs.h"
+
+static int dryrun = 0;
+static int verbose = 0;
+static int metadata_only = 1;
+static unsigned long long user_corrupt_bytes = 0;
+static double user_corrupt_pct = 0.0;
+
+#ifndef HAVE_PWRITE
+ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset)
+{
+       if (lseek(fd, offset, SEEK_SET) < 0)
+               return 0;
+
+       return write(fd, buf, count);
+}
+#endif /* HAVE_PWRITE */
+
+int getseed(void)
+{
+       int r;
+       int fd;
+
+       fd = open("/dev/urandom", O_RDONLY);
+       if (fd < 0) {
+               perror("open");
+               exit(0);
+       }
+       read(fd, &r, sizeof(r));
+       close(fd);
+       return r;
+}
+
+struct find_block {
+       ext2_ino_t ino;
+       ext2fs_block_bitmap bmap;
+       struct ext2_inode *inode;
+       blk64_t corrupt_blocks;
+};
+
+int find_block_helper(ext2_filsys fs, blk64_t *blocknr, e2_blkcnt_t blockcnt,
+                     blk64_t ref_blk, int ref_offset, void *priv_data)
+{
+       struct find_block *fb = (struct find_block *)priv_data;
+
+       if (S_ISDIR(fb->inode->i_mode) || !metadata_only || blockcnt < 0) {
+               ext2fs_mark_block_bitmap2(fb->bmap, *blocknr);
+               fb->corrupt_blocks++;
+       }
+
+       return 0;
+}
+
+errcode_t find_metadata_blocks(ext2_filsys fs, ext2fs_block_bitmap bmap,
+                              off_t *corrupt_bytes)
+{
+       dgrp_t i;
+       blk64_t b, c;
+       ext2_inode_scan scan;
+       ext2_ino_t ino;
+       struct ext2_inode inode;
+       struct find_block fb;
+       errcode_t retval;
+
+       *corrupt_bytes = 0;
+       fb.corrupt_blocks = 0;
+
+       /* Construct bitmaps of super/descriptor blocks */
+       for (i = 0; i < fs->group_desc_count; i++) {
+               ext2fs_reserve_super_and_bgd(fs, i, bmap);
+
+               /* bitmaps and inode table */
+               b = ext2fs_block_bitmap_loc(fs, i);
+               ext2fs_mark_block_bitmap2(bmap, b);
+               fb.corrupt_blocks++;
+
+               b = ext2fs_inode_bitmap_loc(fs, i);
+               ext2fs_mark_block_bitmap2(bmap, b);
+               fb.corrupt_blocks++;
+
+               c = ext2fs_inode_table_loc(fs, i);
+               ext2fs_mark_block_bitmap_range2(bmap, c,
+                                               fs->inode_blocks_per_group);
+               fb.corrupt_blocks += fs->inode_blocks_per_group;
+       }
+
+       /* Scan inodes */
+       fb.bmap = bmap;
+       fb.inode = &inode;
+       memset(&inode, 0, sizeof(inode));
+       retval = ext2fs_open_inode_scan(fs, 0, &scan);
+       if (retval)
+               goto out;
+
+       retval = ext2fs_get_next_inode_full(scan, &ino, &inode, sizeof(inode));
+       if (retval)
+               goto out2;
+       while (ino) {
+               if (inode.i_links_count == 0)
+                       goto next_loop;
+
+               b = ext2fs_file_acl_block(fs, &inode);
+               if (b) {
+                       ext2fs_mark_block_bitmap2(bmap, b);
+                       fb.corrupt_blocks++;
+               }
+
+               /*
+                * Inline data, sockets, devices, and symlinks have
+                * no blocks to iterate.
+                */
+               if ((inode.i_flags & EXT4_INLINE_DATA_FL) ||
+                   S_ISLNK(inode.i_mode) || S_ISFIFO(inode.i_mode) ||
+                   S_ISCHR(inode.i_mode) || S_ISBLK(inode.i_mode) ||
+                   S_ISSOCK(inode.i_mode))
+                       goto next_loop;
+               fb.ino = ino;
+               retval = ext2fs_block_iterate3(fs, ino, BLOCK_FLAG_READ_ONLY,
+                                              NULL, find_block_helper, &fb);
+               if (retval)
+                       goto out2;
+next_loop:
+               retval = ext2fs_get_next_inode_full(scan, &ino, &inode,
+                                                   sizeof(inode));
+               if (retval)
+                       goto out2;
+       }
+out2:
+       ext2fs_close_inode_scan(scan);
+out:
+       if (!retval)
+               *corrupt_bytes = fb.corrupt_blocks * fs->blocksize;
+       return retval;
+}
+
+uint64_t rand_num(uint64_t min, uint64_t max)
+{
+       uint64_t x;
+       int i;
+       uint8_t *px = (uint8_t *)&x;
+
+       for (i = 0; i < sizeof(x); i++)
+               px[i] = random();
+
+       return min + (uint64_t)((double)(max - min) * (x / (UINT64_MAX + 1.0)));
+}
+
+int process_fs(const char *fsname)
+{
+       errcode_t ret;
+       int flags, fd;
+       ext2_filsys fs = NULL;
+       ext2fs_block_bitmap corrupt_map;
+       off_t hsize, count, off, offset, corrupt_bytes;
+       unsigned char c;
+       unsigned long i;
+
+       /* If mounted rw, force dryrun mode */
+       ret = ext2fs_check_if_mounted(fsname, &flags);
+       if (ret) {
+               fprintf(stderr, "%s: failed to determine filesystem mount "
+                       "state.\n", fsname);
+               return 1;
+       }
+
+       if (!dryrun && (flags & EXT2_MF_MOUNTED) &&
+           !(flags & EXT2_MF_READONLY)) {
+               fprintf(stderr, "%s: is mounted rw, performing dry run.\n",
+                       fsname);
+               dryrun = 1;
+       }
+
+       /* Ensure the fs is clean and does not have errors */
+       ret = ext2fs_open(fsname, EXT2_FLAG_64BITS, 0, 0, unix_io_manager,
+                         &fs);
+       if (ret) {
+               fprintf(stderr, "%s: failed to open filesystem.\n",
+                       fsname);
+               return 1;
+       }
+
+       if ((fs->super->s_state & EXT2_ERROR_FS)) {
+               fprintf(stderr, "%s: errors detected, run fsck.\n",
+                       fsname);
+               goto fail;
+       }
+
+       if (!dryrun && (fs->super->s_state & EXT2_VALID_FS) == 0) {
+               fprintf(stderr, "%s: unclean shutdown, performing dry run.\n",
+                       fsname);
+               dryrun = 1;
+       }
+
+       /* Construct a bitmap of whatever we're corrupting */
+       if (!metadata_only) {
+               /* Load block bitmap */
+               ret = ext2fs_read_block_bitmap(fs);
+               if (ret) {
+                       fprintf(stderr, "%s: error while reading block bitmap\n",
+                               fsname);
+                       goto fail;
+               }
+               corrupt_map = fs->block_map;
+               corrupt_bytes = (ext2fs_blocks_count(fs->super) -
+                                ext2fs_free_blocks_count(fs->super)) *
+                               fs->blocksize;
+       } else {
+               ret = ext2fs_allocate_block_bitmap(fs, "metadata block map",
+                                                  &corrupt_map);
+               if (ret) {
+                       fprintf(stderr, "%s: unable to create block bitmap\n",
+                               fsname);
+                       goto fail;
+               }
+
+               /* Iterate everything... */
+               ret = find_metadata_blocks(fs, corrupt_map, &corrupt_bytes);
+               if (ret) {
+                       fprintf(stderr, "%s: while finding metadata\n",
+                               fsname);
+                       goto fail;
+               }
+       }
+
+       /* Run around corrupting things */
+       fd = open(fsname, O_RDWR);
+       if (fd < 0) {
+               perror(fsname);
+               goto fail;
+       }
+       srandom(getseed());
+       hsize = fs->blocksize * ext2fs_blocks_count(fs->super);
+       if (user_corrupt_bytes > 0)
+               count = user_corrupt_bytes;
+       else if (user_corrupt_pct > 0.0)
+               count = user_corrupt_pct * corrupt_bytes / 100;
+       else
+               count = rand_num(0, corrupt_bytes / 100);
+       offset = 4096; /* never corrupt superblock */
+       for (i = 0; i < count; i++) {
+               do
+                       off = rand_num(offset, hsize);
+               while (!ext2fs_test_block_bitmap2(corrupt_map,
+                                                   off / fs->blocksize));
+               c = rand() % 256;
+               if ((rand() % 2) && c < 128)
+                       c |= 0x80;
+               if (verbose)
+                       printf("Corrupting byte %jd in block %jd to 0x%x\n",
+                              off % fs->blocksize, off / fs->blocksize, c);
+               if (dryrun)
+                       continue;
+               if (pwrite(fd, &c, sizeof(c), off) != sizeof(c)) {
+                       perror(fsname);
+                       goto fail3;
+               }
+       }
+       close(fd);
+
+       /* Clean up */
+       ret = ext2fs_close_free(&fs);
+       if (ret) {
+               fprintf(stderr, "%s: error while closing filesystem\n",
+                       fsname);
+               return 1;
+       }
+
+       return 0;
+fail3:
+       close(fd);
+       if (corrupt_map != fs->block_map)
+               ext2fs_free_block_bitmap(corrupt_map);
+fail:
+       ext2fs_close_free(&fs);
+       return 1;
+}
+
+void print_help(const char *progname)
+{
+       printf("Usage: %s OPTIONS device\n", progname);
+       printf("-b:     Corrupt this many bytes.\n");
+       printf("-d:     Fuzz data blocks too.\n");
+       printf("-n:     Dry run only.\n");
+       printf("-v:     Verbose output.\n");
+       exit(0);
+}
+
+int main(int argc, char *argv[])
+{
+       int c;
+
+       while ((c = getopt(argc, argv, "b:dnv")) != -1) {
+               switch (c) {
+               case 'b':
+                       if (optarg[strlen(optarg) - 1] == '%') {
+                               user_corrupt_pct = strtod(optarg, NULL);
+                               if (user_corrupt_pct > 100 ||
+                                   user_corrupt_pct < 0) {
+                                       fprintf(stderr, "%s: Invalid percentage.\n",
+                                               optarg);
+                                       return 1;
+                               }
+                       } else
+                               user_corrupt_bytes = strtoull(optarg, NULL, 0);
+                       if (errno) {
+                               perror(optarg);
+                               return 1;
+                       }
+                       break;
+               case 'd':
+                       metadata_only = 0;
+                       break;
+               case 'n':
+                       dryrun = 1;
+                       break;
+               case 'v':
+                       verbose = 1;
+                       break;
+               default:
+                       print_help(argv[0]);
+               }
+       }
+
+       for (c = optind; c < argc; c++)
+               if (process_fs(argv[c]))
+                       return 1;
+       return 0;
+}
diff --git a/misc/e2fuzz.sh b/misc/e2fuzz.sh
new file mode 100755 (executable)
index 0000000..a261d5a
--- /dev/null
@@ -0,0 +1,262 @@
+#!/bin/bash
+
+# Test harness to fuzz a filesystem over and over...
+# Copyright (C) 2014 Oracle.
+
+DIR=/tmp
+PASSES=10000
+SZ=32m
+SCRIPT_DIR="$(dirname "$0")"
+FEATURES="has_journal,extent,huge_file,flex_bg,uninit_bg,dir_nlink,extra_isize,64bit,metadata_csum,bigalloc,sparse_super2,inline_data"
+BLK_SZ=4096
+INODE_SZ=256
+EXTENDED_OPTS="discard"
+EXTENDED_FSCK_OPTIONS=""
+RUN_FSCK=1
+OVERRIDE_PATH=1
+HAS_FUSE2FS=0
+USE_FUSE2FS=0
+MAX_FSCK=10
+SRCDIR=/etc
+test -x "${SCRIPT_DIR}/fuse2fs" && HAS_FUSE2FS=1
+
+print_help() {
+       echo "Usage: $0 OPTIONS"
+       echo "-b:       FS block size is this. (${BLK_SZ})"
+       echo "-B:       Corrupt this many bytes per run."
+       echo "-d:       Create test files in this directory. (${DIR})"
+       echo "-E:       Extended mke2fs options."
+       echo "-f:       Do not run e2fsck after each pass."
+       echo "-F:       Extended e2fsck options."
+       echo "-I:       Create inodes of this size. (${INODE_SZ})"
+       echo "-n:       Run this many passes. (${PASSES})"
+       echo "-O:       Create FS with these features."
+       echo "-p:       Use system's mke2fs/e2fsck/tune2fs tools."
+       echo "-s:       Create FS images of this size. (${SZ})"
+       echo "-S:       Copy files from this dir. (${SRCDIR})"
+       echo "-x:       Run e2fck at most this many times. (${MAX_FSCK})"
+       test "${HAS_FUSE2FS}" -gt 0 && echo "-u:        Use fuse2fs instead of the kernel."
+       exit 0
+}
+
+GETOPT="d:n:s:O:I:b:B:E:F:fpx:S:"
+test "${HAS_FUSE2FS}" && GETOPT="${GETOPT}u"
+
+while getopts "${GETOPT}" opt; do
+       case "${opt}" in
+       "B")
+               E2FUZZ_ARGS="${E2FUZZ_ARGS} -b ${OPTARG}"
+               ;;
+       "d")
+               DIR="${OPTARG}"
+               ;;
+       "n")
+               PASSES="${OPTARG}"
+               ;;
+       "s")
+               SZ="${OPTARG}"
+               ;;
+       "O")
+               FEATURES="${FEATURES},${OPTARG}"
+               ;;
+       "I")
+               INODE_SZ="${OPTARG}"
+               ;;
+       "b")
+               BLK_SZ="${OPTARG}"
+               ;;
+       "E")
+               EXTENDED_OPTS="${OPTARG}"
+               ;;
+       "F")
+               EXTENDED_FSCK_OPTS="-E ${OPTARG}"
+               ;;
+       "f")
+               RUN_FSCK=0
+               ;;
+       "p")
+               OVERRIDE_PATH=0
+               ;;
+       "u")
+               USE_FUSE2FS=1
+               ;;
+       "x")
+               MAX_FSCK="${OPTARG}"
+               ;;
+       "S")
+               SRCDIR="${OPTARG}"
+               ;;
+       *)
+               print_help
+               ;;
+       esac
+done
+
+if [ "${OVERRIDE_PATH}" -gt 0 ]; then
+       PATH="${SCRIPT_DIR}:${SCRIPT_DIR}/../e2fsck/:${PATH}"
+       export PATH
+fi
+
+TESTDIR="${DIR}/tests/"
+TESTMNT="${DIR}/mnt/"
+BASE_IMG="${DIR}/e2fuzz.img"
+
+cat > /tmp/mke2fs.conf << ENDL
+[defaults]
+        base_features = ${FEATURES}
+        default_mntopts = acl,user_xattr,block_validity
+        enable_periodic_fsck = 0
+        blocksize = ${BLK_SZ}
+        inode_size = ${INODE_SZ}
+        inode_ratio = 4096
+       cluster_size = $((BLK_SZ * 2))
+       options = ${EXTENDED_OPTS}
+ENDL
+MKE2FS_CONFIG=/tmp/mke2fs.conf
+export MKE2FS_CONFIG
+
+# Set up FS image
+echo "+ create fs image"
+umount "${TESTDIR}"
+umount "${TESTMNT}"
+rm -rf "${TESTDIR}"
+rm -rf "${TESTMNT}"
+mkdir -p "${TESTDIR}"
+mkdir -p "${TESTMNT}"
+rm -rf "${BASE_IMG}"
+truncate -s "${SZ}" "${BASE_IMG}"
+mke2fs -F -v "${BASE_IMG}"
+if [ $? -ne 0 ]; then
+       exit $?
+fi
+
+# Populate FS image
+echo "+ populate fs image"
+modprobe loop
+mount "${BASE_IMG}" "${TESTMNT}" -o loop
+if [ $? -ne 0 ]; then
+       exit $?
+fi
+SRC_SZ="$(du -ks "${SRCDIR}" | awk '{print $1}')"
+FS_SZ="$(( $(stat -f "${TESTMNT}" -c '%a * %S') / 1024 ))"
+NR="$(( (FS_SZ * 6 / 10) / SRC_SZ ))"
+if [ "${NR}" -lt 1 ]; then
+       NR=1
+fi
+echo "+ make ${NR} copies"
+seq 1 "${NR}" | while read nr; do
+       cp -pRdu "${SRCDIR}" "${TESTMNT}/test.${nr}" 2> /dev/null
+done
+umount "${TESTMNT}"
+e2fsck -fn "${BASE_IMG}"
+if [ $? -ne 0 ]; then
+       echo "fsck failed??"
+       exit 1
+fi
+
+# Run tests
+echo "+ run test"
+ret=0
+seq 1 "${PASSES}" | while read pass; do
+       echo "+ pass ${pass}"
+       PASS_IMG="${TESTDIR}/e2fuzz-${pass}.img"
+       FSCK_IMG="${TESTDIR}/e2fuzz-${pass}.fsck"
+       FUZZ_LOG="${TESTDIR}/e2fuzz-${pass}.fuzz.log"
+       OPS_LOG="${TESTDIR}/e2fuzz-${pass}.ops.log"
+
+       echo "++ corrupt image"
+       cp "${BASE_IMG}" "${PASS_IMG}"
+       if [ $? -ne 0 ]; then
+               exit $?
+       fi
+       tune2fs -L "e2fuzz-${pass}" "${PASS_IMG}"
+       e2fuzz -v "${PASS_IMG}" ${E2FUZZ_ARGS} > "${FUZZ_LOG}"
+       if [ $? -ne 0 ]; then
+               exit $?
+       fi
+
+       echo "++ mount image"
+       if [ "${USE_FUSE2FS}" -gt 0 ]; then
+               "${SCRIPT_DIR}/fuse2fs" "${PASS_IMG}" "${TESTMNT}"
+               res=$?
+       else
+               mount "${PASS_IMG}" "${TESTMNT}" -o loop
+               res=$?
+       fi
+
+       if [ "${res}" -eq 0 ]; then
+               echo "+++ ls -laR"
+               ls -laR "${TESTMNT}/test.1/" > /dev/null 2> "${OPS_LOG}"
+
+               echo "+++ cat files"
+               find "${TESTMNT}/test.1/" -type f -size -1048576k -print0 | xargs -0 cat > /dev/null 2>> "${OPS_LOG}"
+
+               echo "+++ expand"
+               find "${TESTMNT}/test.1/" -type f 2> /dev/null | while read f; do
+                       attr -l "$f" > /dev/null 2>> "${OPS_LOG}"
+                       mv "$f" "$f.longer" > /dev/null 2>> "${OPS_LOG}"
+                       if [ -f "$f" -a -w "$f" ]; then
+                               dd if=/dev/zero bs="${BLK_SZ}" count=1 >> "$f" 2>> "${OPS_LOG}"
+                       fi
+               done
+               sync
+
+               echo "+++ create files"
+               cp -pRdu "${SRCDIR}" "${TESTMNT}/test.moo" 2>> "${OPS_LOG}"
+               sync
+
+               echo "+++ remove files"
+               rm -rf "${TESTMNT}/test.moo" 2>> "${OPS_LOG}"
+
+               umount "${TESTMNT}"
+               res=$?
+               if [ "${res}" -ne 0 ]; then
+                       ret=1
+                       break
+               fi
+               sync
+               test "${USE_FUSE2FS}" -gt 0 && sleep 2
+       fi
+       if [ "${RUN_FSCK}" -gt 0 ]; then
+               cp "${PASS_IMG}" "${FSCK_IMG}"
+
+               seq 1 "${MAX_FSCK}" | while read fsck_pass; do
+                       echo "++ fsck pass ${fsck_pass}: $(which e2fsck) -fy ${FSCK_IMG} ${EXTENDED_FSCK_OPTS}"
+                       FSCK_LOG="${TESTDIR}/e2fuzz-${pass}-${fsck_pass}.log"
+                       e2fsck -fy "${FSCK_IMG}" ${EXTENDED_FSCK_OPTS} > "${FSCK_LOG}" 2>&1
+                       res=$?
+                       echo "++ fsck returns ${res}"
+                       if [ "${res}" -eq 0 ]; then
+                               exit 0
+                       elif [ "${fsck_pass}" -eq "${MAX_FSCK}" ]; then
+                               echo "++ fsck did not fix in ${MAX_FSCK} passes."
+                               exit 1
+                       fi
+                       if [ "${res}" -gt 0 -a \
+                            "$(grep 'Memory allocation failed' "${FSCK_LOG}" | wc -l)" -gt 0 ]; then
+                               echo "++ Ran out of memory, get more RAM"
+                               exit 0
+                       fi
+                       if [ "${res}" -gt 0 -a \
+                            "$(grep 'Could not allocate block' "${FSCK_LOG}" | wc -l)" -gt 0 -a \
+                            "$(dumpe2fs -h "${FSCK_IMG}" | grep '^Free blocks:' | awk '{print $3}')0" -eq 0 ]; then
+                               echo "++ Ran out of space, get a bigger image"
+                               exit 0
+                       fi
+                       if [ "${fsck_pass}" -gt 1 ]; then
+                               diff -u "${TESTDIR}/e2fuzz-${pass}-$((fsck_pass - 1)).log" "${FSCK_LOG}"
+                               if [ $? -eq 0 ]; then
+                                       echo "++ fsck makes no progress"
+                                       exit 2
+                               fi
+                       fi
+               done
+               fsck_loop_ret=$?
+               if [ "${fsck_loop_ret}" -gt 0 ]; then
+                       break;
+               fi
+       fi
+       rm -rf "${FSCK_IMG}" "${PASS_IMG}" "${FUZZ_LOG}" "${TESTDIR}"/e2fuzz*.log
+done
+
+exit $ret
index 82fe3e8..e1c63a7 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 9112b3d..ca197cb 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 9c38e20..bad76bb 100644 (file)
@@ -52,6 +52,10 @@ mke2fs \- create an ext2/ext3/ext4 filesystem
 .I number-of-inodes
 ]
 [
+.B \-d
+.I root-directory
+]
+[
 .B \-n
 ]
 [
@@ -109,6 +113,10 @@ mke2fs \- create an ext2/ext3/ext4 filesystem
 [
 .B \-V
 ]
+[
+.B \-e
+.I errors-behavior
+]
 .I device
 [
 .I blocks-count
@@ -202,6 +210,25 @@ lot of buffer cache memory, which may impact other applications running
 on a busy server.  This option will cause mke2fs to run much more
 slowly, however, so there is a tradeoff to using direct I/O.
 .TP
+.BI \-e " error-behavior"
+Change the behavior of the kernel code when errors are detected.
+In all cases, a filesystem error will cause
+.BR e2fsck (8)
+to check the filesystem on the next boot.
+.I error-behavior
+can be one of the following:
+.RS 1.2i
+.TP 1.2i
+.B continue
+Continue normal execution.
+.TP
+.B remount-ro
+Remount filesystem read-only.
+.TP
+.B panic
+Cause a kernel panic.
+.RE
+.TP
 .BI \-E " extended-options"
 Set extended options for the filesystem.  Extended options are comma
 separated, and may take an argument using the equals ('=') sign.  The
@@ -529,6 +556,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 da77e3a..792c754 100644 (file)
  * enforced (but it's not much fun on a character device :-).
  */
 
-#define _XOPEN_SOURCE 600 /* for inclusion of PATH_MAX in Solaris */
+#define _XOPEN_SOURCE 600 /* for inclusion of PATH_MAX */
 
 #include "config.h"
 #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,22 +107,26 @@ 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;
 
 static int sys_page_size = 4096;
 
+static int errors_behavior = 0;
+
 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[,...]] "
        "[-r fs-revision] [-E extended-option[,...]]\n"
-       "\t[-t fs-type] [-T usage-type ] [-U UUID] "
+       "\t[-t fs-type] [-T usage-type ] [-U UUID] [-e errors_behavior]"
        "[-jnqvDFKSV] device [blocks-count]\n"),
                program_name);
        exit(1);
@@ -339,6 +337,25 @@ _("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_memzero(EXT2_INODE_SIZE(fs->super), &inode);
+       if (retval) {
+               com_err("inode_init", retval, _("while allocating memory"));
+               exit(1);
+       }
+
+       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;
@@ -419,6 +436,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)
@@ -707,6 +730,23 @@ skip_details:
 }
 
 /*
+ * 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.
  */
@@ -1033,7 +1073,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|
@@ -1045,7 +1086,7 @@ static __u32 ok_features[3] = {
 #ifdef CONFIG_QUOTA
                EXT4_FEATURE_RO_COMPAT_QUOTA|
 #endif
-               0
+               EXT4_FEATURE_RO_COMPAT_METADATA_CSUM
 };
 
 
@@ -1174,15 +1215,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)
@@ -1512,7 +1549,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:ce:g: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);
@@ -1555,6 +1592,20 @@ profile_error:
                case 'E':
                        extended_opts = optarg;
                        break;
+               case 'e':
+                       if (strcmp(optarg, "continue") == 0)
+                               errors_behavior = EXT2_ERRORS_CONTINUE;
+                       else if (strcmp(optarg, "remount-ro") == 0)
+                               errors_behavior = EXT2_ERRORS_RO;
+                       else if (strcmp(optarg, "panic") == 0)
+                               errors_behavior = EXT2_ERRORS_PANIC;
+                       else {
+                               com_err(program_name, 0,
+                                       _("bad error behavior - %s"),
+                                       optarg);
+                               usage();
+                       }
+                       break;
                case 'F':
                        force++;
                        break;
@@ -1711,6 +1762,9 @@ profile_error:
                case 'U':
                        fs_uuid = optarg;
                        break;
+               case 'd':
+                       root_dir = optarg;
+                       break;
                case 'v':
                        verbose = 1;
                        break;
@@ -1894,10 +1948,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, "%s", _("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, "%s", _("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, "%s", _("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);
@@ -2171,6 +2255,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)) {
@@ -2196,7 +2287,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) &&
@@ -2255,6 +2347,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;
@@ -2324,7 +2429,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;
@@ -2532,6 +2638,38 @@ static int create_quota_inodes(ext2_filsys fs)
        return 0;
 }
 
+static errcode_t set_error_behavior(ext2_filsys fs)
+{
+       char    *arg = NULL;
+       short   errors = fs->super->s_errors;
+
+       arg = get_string_from_profile(fs_types, "errors", NULL);
+       if (arg == NULL)
+               goto try_user;
+
+       if (strcmp(arg, "continue") == 0)
+               errors = EXT2_ERRORS_CONTINUE;
+       else if (strcmp(arg, "remount-ro") == 0)
+               errors = EXT2_ERRORS_RO;
+       else if (strcmp(arg, "panic") == 0)
+               errors = EXT2_ERRORS_PANIC;
+       else {
+               com_err(program_name, 0,
+                       _("bad error behavior in profile - %s"),
+                       arg);
+               free(arg);
+               return EXT2_ET_INVALID_ARGUMENT;
+       }
+       free(arg);
+
+try_user:
+       if (errors_behavior)
+               errors = errors_behavior;
+
+       fs->super->s_errors = errors;
+       return 0;
+}
+
 int main (int argc, char *argv[])
 {
        errcode_t       retval = 0;
@@ -2594,6 +2732,33 @@ int main (int argc, char *argv[])
                        _("while setting up superblock"));
                exit(1);
        }
+       fs->progress_ops = &ext2fs_numeric_progress_ops;
+
+       /* Set the error behavior */
+       retval = set_error_behavior(fs);
+       if (retval)
+               usage();
+
+       /* 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("%s",
+                              _("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("%s",
+                              _("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) ||
@@ -2631,6 +2796,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;
 
@@ -2651,6 +2817,7 @@ int main (int argc, char *argv[])
                }
        } else
                uuid_generate(fs->super->s_uuid);
+       ext2fs_init_csum_seed(fs);
 
        /*
         * Initialize the directory index variables
@@ -2727,6 +2894,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);
 
@@ -2777,8 +2948,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);
                }
@@ -2916,6 +3086,20 @@ no_journal:
        retval = mk_hugefiles(fs, device_name);
        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 19458ac..ad6c11b 100644 (file)
@@ -317,6 +317,25 @@ whose subsections define the
 relation, only the last will be used by
 .BR mke2fs (8).
 .TP
+.I errors
+Change the behavior of the kernel code when errors are detected.
+In all cases, a filesystem error will cause
+.BR e2fsck (8)
+to check the filesystem on the next boot.
+.I errors
+can be one of the following:
+.RS 1.2i
+.TP 1.2i
+.B continue
+Continue normal execution.
+.TP
+.B remount-ro
+Remount filesystem read-only.
+.TP
+.B panic
+Cause a kernel panic.
+.RE
+.TP
 .I features
 This relation specifies a comma-separated list of features edit
 requests which modify the feature set
index 0871f77..4c5dba7 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 b65dab9..75a2735 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
 };
 
 /**
@@ -405,6 +410,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("%s", _("(and reboot afterwards!)\n"));
+}
+
 static void request_fsck_afterwards(ext2_filsys fs)
 {
        static int requested = 0;
@@ -417,15 +434,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;
 
@@ -605,36 +1084,68 @@ mmp_error:
        }
 
        if (FEATURE_ON(E2P_FEATURE_RO_INCOMPAT,
-                      EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) {
-               for (i = 0; i < fs->group_desc_count; i++) {
-                       gd = ext2fs_group_desc(fs, fs->group_desc, i);
-                       gd->bg_itable_unused = 0;
-                       gd->bg_flags = EXT2_BG_INODE_ZEROED;
-                       ext2fs_group_desc_csum_set(fs, i);
-               }
-               fs->flags &= ~EXT2_FLAG_SUPER_ONLY;
+                      EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) {
+               if (check_fsck_needed(fs))
+                       exit(1);
+               rewrite_checksums = 1;
+               /* metadata_csum supersedes uninit_bg */
+               fs->super->s_feature_ro_compat &=
+                       ~EXT4_FEATURE_RO_COMPAT_GDT_CSUM;
+
+               /* if uninit_bg was previously off, rewrite group desc */
+               if (!(old_features[E2P_FEATURE_RO_INCOMPAT] &
+                     EXT4_FEATURE_RO_COMPAT_GDT_CSUM))
+                       enable_uninit_bg(fs);
+
+               /*
+                * Since metadata_csum supersedes uninit_bg, pretend like
+                * uninit_bg has been off all along.
+                */
+               old_features[E2P_FEATURE_RO_INCOMPAT] &=
+                       ~EXT4_FEATURE_RO_COMPAT_GDT_CSUM;
        }
 
        if (FEATURE_OFF(E2P_FEATURE_RO_INCOMPAT,
-                       EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) {
-               for (i = 0; i < fs->group_desc_count; i++) {
-                       gd = ext2fs_group_desc(fs, fs->group_desc, i);
-                       if ((gd->bg_flags & EXT2_BG_INODE_ZEROED) == 0) {
-                               /* 
-                                * XXX what we really should do is zap
-                                * uninitialized inode tables instead.
-                                */
-                               request_fsck_afterwards(fs);
-                               break;
-                       }
-                       gd->bg_itable_unused = 0;
-                       gd->bg_flags = 0;
-                       gd->bg_checksum = 0;
-               }
-               fs->flags &= ~EXT2_FLAG_SUPER_ONLY;
+                       EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) {
+               if (check_fsck_needed(fs))
+                       exit(1);
+               rewrite_checksums = 1;
+               /*
+                * If we're turning off metadata_csum and not turning on
+                * uninit_bg, rewrite group desc.
+                */
+               if (!(fs->super->s_feature_ro_compat &
+                     EXT4_FEATURE_RO_COMPAT_GDT_CSUM))
+                       disable_uninit_bg(fs,
+                               EXT4_FEATURE_RO_COMPAT_METADATA_CSUM);
+               else
+                       /*
+                        * metadata_csum previously provided uninit_bg, so if
+                        * we're also setting the uninit_bg feature bit,
+                        * pretend like it was previously enabled.  Checksums
+                        * will be rewritten with crc16 later.
+                        */
+                       old_features[E2P_FEATURE_RO_INCOMPAT] |=
+                               EXT4_FEATURE_RO_COMPAT_GDT_CSUM;
        }
 
        if (FEATURE_ON(E2P_FEATURE_RO_INCOMPAT,
+                      EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) {
+               /* Do not enable uninit_bg when metadata_csum enabled */
+               if (fs->super->s_feature_ro_compat &
+                   EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)
+                       fs->super->s_feature_ro_compat &=
+                               ~EXT4_FEATURE_RO_COMPAT_GDT_CSUM;
+               else
+                       enable_uninit_bg(fs);
+       }
+
+       if (FEATURE_OFF(E2P_FEATURE_RO_INCOMPAT,
+                       EXT4_FEATURE_RO_COMPAT_GDT_CSUM))
+               disable_uninit_bg(fs,
+                               EXT4_FEATURE_RO_COMPAT_GDT_CSUM);
+
+       if (FEATURE_ON(E2P_FEATURE_RO_INCOMPAT,
                                EXT4_FEATURE_RO_COMPAT_QUOTA)) {
                /*
                 * Set the Q_flag here and handle the quota options in the code
@@ -2280,8 +2791,7 @@ retry_open:
                char buf[SUPERBLOCK_SIZE];
                __u8 old_uuid[UUID_SIZE];
 
-               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.
@@ -2321,6 +2831,7 @@ 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);
@@ -2350,7 +2861,12 @@ retry_open:
                }
 
                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 f7b80ef..201e268 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 b3755f6..b59f482 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++) {
@@ -572,8 +571,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)
@@ -731,9 +729,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;
        }
@@ -889,9 +885,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.
@@ -987,8 +983,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
@@ -1461,10 +1456,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,
@@ -1488,11 +1485,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);
@@ -1532,6 +1541,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;
@@ -1542,7 +1591,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 <=
@@ -1605,37 +1653,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)
@@ -1643,16 +1673,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)
@@ -1664,6 +1690,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);
 
@@ -1706,6 +1770,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);
@@ -1716,17 +1781,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
 
@@ -1738,10 +1812,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)
@@ -1768,9 +1842,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_inline_dump/expect b/tests/d_inline_dump/expect
new file mode 100644 (file)
index 0000000..ead47f9
--- /dev/null
@@ -0,0 +1,101 @@
+*** long file
+debugfs 1.43-WIP (09-Jul-2014)
+Inode: 13   Type: regular    Mode:  0644   Flags: 0x10000000
+Generation: 3289262644    Version: 0x00000000:00000001
+User:     0   Group:     0   Size: 80
+File ACL: 0    Directory ACL: 0
+Links: 1   Blockcount: 0
+Fragment:  Address: 0    Number: 0    Size: 0
+ ctime: 0x53cec6b4:c72e3c00 -- Tue Jul 22 20:16:52 2014
+ atime: 0x53cec3c8:4a3fd000 -- Tue Jul 22 20:04:24 2014
+ mtime: 0x53cec3c8:4c281800 -- Tue Jul 22 20:04:24 2014
+crtime: 0x53cec3c8:4a3fd000 -- Tue Jul 22 20:04:24 2014
+Size of extra inode fields: 28
+Extended attributes:
+  system.data (20)
+  user.a = "b" (1)
+Size of inline data: 80
+*** short file
+debugfs 1.43-WIP (09-Jul-2014)
+Inode: 18   Type: regular    Mode:  0644   Flags: 0x10000000
+Generation: 3842229473    Version: 0x00000000:00000001
+User:     0   Group:     0   Size: 20
+File ACL: 0    Directory ACL: 0
+Links: 1   Blockcount: 0
+Fragment:  Address: 0    Number: 0    Size: 0
+ ctime: 0x53cec6b4:cafecc00 -- Tue Jul 22 20:16:52 2014
+ atime: 0x53cec443:bda4d400 -- Tue Jul 22 20:06:27 2014
+ mtime: 0x53cec443:bf8d1c00 -- Tue Jul 22 20:06:27 2014
+crtime: 0x53cec443:bda4d400 -- Tue Jul 22 20:06:27 2014
+Size of extra inode fields: 28
+Extended attributes:
+  system.data (0)
+  user.a = "b" (1)
+Size of inline data: 60
+
+*** long dir
+debugfs 1.43-WIP (09-Jul-2014)
+Inode: 16   Type: directory    Mode:  0755   Flags: 0x10000000
+Generation: 3842229469    Version: 0x00000000:00000004
+User:     0   Group:     0   Size: 132
+File ACL: 7    Directory ACL: 0
+Links: 2   Blockcount: 8
+Fragment:  Address: 0    Number: 0    Size: 0
+ ctime: 0x53cec6e3:27eac000 -- Tue Jul 22 20:17:39 2014
+ atime: 0x53cec410:ed53dc00 -- Tue Jul 22 20:05:36 2014
+ mtime: 0x53cec42b:241a3000 -- Tue Jul 22 20:06:03 2014
+crtime: 0x53cec3fe:c8226000 -- Tue Jul 22 20:05:18 2014
+Size of extra inode fields: 28
+Extended attributes:
+  system.data (72)
+  user.a = "b" (1)
+Size of inline data: 132
+*** short dir
+debugfs 1.43-WIP (09-Jul-2014)
+Inode: 20   Type: directory    Mode:  0755   Flags: 0x10000000
+Generation: 3710818931    Version: 0x00000000:00000001
+User:     0   Group:     0   Size: 60
+File ACL: 0    Directory ACL: 0
+Links: 2   Blockcount: 0
+Fragment:  Address: 0    Number: 0    Size: 0
+ ctime: 0x53cec6b4:ca0aa800 -- Tue Jul 22 20:16:52 2014
+ atime: 0x53cec477:9a5ba000 -- Tue Jul 22 20:07:19 2014
+ mtime: 0x53cec477:9a5ba000 -- Tue Jul 22 20:07:19 2014
+crtime: 0x53cec477:9a5ba000 -- Tue Jul 22 20:07:19 2014
+Size of extra inode fields: 28
+Extended attributes:
+  system.data (0)
+  user.a = "b" (1)
+Size of inline data: 60
+
+*** long link
+debugfs 1.43-WIP (09-Jul-2014)
+Inode: 12   Type: symlink    Mode:  0777   Flags: 0x10000000
+Generation: 3289262643    Version: 0x00000000:00000001
+User:     0   Group:     0   Size: 80
+File ACL: 0    Directory ACL: 0
+Links: 1   Blockcount: 0
+Fragment:  Address: 0    Number: 0    Size: 0
+ ctime: 0x53cec47f:724db800 -- Tue Jul 22 20:07:27 2014
+ atime: 0x53cec665:27eac000 -- Tue Jul 22 20:15:33 2014
+ mtime: 0x53cec3b6:82841c00 -- Tue Jul 22 20:04:06 2014
+crtime: 0x53cec3b6:82841c00 -- Tue Jul 22 20:04:06 2014
+Size of extra inode fields: 28
+Extended attributes:
+  system.data (20)
+Fast link dest: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
+*** short link
+debugfs 1.43-WIP (09-Jul-2014)
+Inode: 19   Type: symlink    Mode:  0777   Flags: 0x0
+Generation: 3842229474    Version: 0x00000000:00000001
+User:     0   Group:     0   Size: 20
+File ACL: 0    Directory ACL: 0
+Links: 1   Blockcount: 0
+Fragment:  Address: 0    Number: 0    Size: 0
+ ctime: 0x53cec44c:a1fcc000 -- Tue Jul 22 20:06:36 2014
+ atime: 0x53cec44d:11fb8400 -- Tue Jul 22 20:06:37 2014
+ mtime: 0x53cec44c:a1fcc000 -- Tue Jul 22 20:06:36 2014
+crtime: 0x53cec44c:a1fcc000 -- Tue Jul 22 20:06:36 2014
+Size of extra inode fields: 28
+Fast link dest: "xxxxxxxxxxxxxxxxxxxx"
+*** end test
diff --git a/tests/d_inline_dump/image.gz b/tests/d_inline_dump/image.gz
new file mode 100644 (file)
index 0000000..598a495
Binary files /dev/null and b/tests/d_inline_dump/image.gz differ
diff --git a/tests/d_inline_dump/name b/tests/d_inline_dump/name
new file mode 100644 (file)
index 0000000..dfc1a9c
--- /dev/null
@@ -0,0 +1 @@
+debugfs dump inline data test
diff --git a/tests/d_inline_dump/script b/tests/d_inline_dump/script
new file mode 100644 (file)
index 0000000..8d97729
--- /dev/null
@@ -0,0 +1,43 @@
+if ! test -x $DEBUGFS_EXE; then
+       echo "$test_name: $test_description: skipped"
+       exit 0
+fi
+
+OUT=$test_name.log
+EXP=$test_dir/expect
+VERIFY_FSCK_OPT=-yf
+
+ZIMAGE=$test_dir/image.gz
+gzip -d < $ZIMAGE > $TMPFILE
+
+echo "*** long file" > $OUT
+$DEBUGFS -R 'stat /file' $TMPFILE >> $OUT 2>&1
+echo "*** short file" >> $OUT
+$DEBUGFS -R 'stat /shortfile' $TMPFILE >> $OUT 2>&1
+echo >> $OUT
+
+echo "*** long dir" >> $OUT
+$DEBUGFS -R 'stat /dir' $TMPFILE >> $OUT 2>&1
+echo "*** short dir" >> $OUT
+$DEBUGFS -R 'stat /shortdir' $TMPFILE >> $OUT 2>&1
+echo >> $OUT
+
+echo "*** long link" >> $OUT
+$DEBUGFS -R 'stat /link' $TMPFILE >> $OUT 2>&1
+echo "*** short link" >> $OUT
+$DEBUGFS -R 'stat /shortlink' $TMPFILE >> $OUT 2>&1
+
+echo "*** end test" >> $OUT
+
+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 ZIMAGE
index 2b2dbfa..f729b0f 100644 (file)
@@ -11,7 +11,7 @@ Fragment:  Address: 0    Number: 0    Size: 0
 ctime: 0x50f560e0 -- Tue Jan 15 14:00:00 2013
 atime: 0x50f560e0 -- Tue Jan 15 14:00:00 2013
 mtime: 0x50f560e0 -- Tue Jan 15 14:00:00 2013
-Fast_link_dest: bar
+Fast link dest: "bar"
 Exit status is 0
 debugfs -R ''stat foo2'' -w test.img
 Inode: 13   Type: symlink    Mode:  0777   Flags: 0x0
diff --git a/tests/d_xattr_edits/expect b/tests/d_xattr_edits/expect
new file mode 100644 (file)
index 0000000..44ce5e4
--- /dev/null
@@ -0,0 +1,50 @@
+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
+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
diff --git a/tests/f_bad_bbitmap/expect.1 b/tests/f_bad_bbitmap/expect.1
new file mode 100644 (file)
index 0000000..71ad1bb
--- /dev/null
@@ -0,0 +1,15 @@
+One or more block group descriptor checksums are invalid.  Fix? yes
+
+Group descriptor 0 checksum is 0x49ff, should be 0x4972.  FIXED.
+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
+Block bitmap differences:  -(8--10) -(12--17) -(19--31)
+Fix? yes
+
+
+test_filesys: ***** FILE SYSTEM WAS MODIFIED *****
+test_filesys: 11/128 files (0.0% non-contiguous), 18/512 blocks
+Exit status is 1
diff --git a/tests/f_bad_bbitmap/expect.2 b/tests/f_bad_bbitmap/expect.2
new file mode 100644 (file)
index 0000000..411e656
--- /dev/null
@@ -0,0 +1,7 @@
+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/128 files (0.0% non-contiguous), 18/512 blocks
+Exit status is 0
diff --git a/tests/f_bad_bbitmap/image.gz b/tests/f_bad_bbitmap/image.gz
new file mode 100644 (file)
index 0000000..c488ecd
Binary files /dev/null and b/tests/f_bad_bbitmap/image.gz differ
diff --git a/tests/f_bad_bbitmap/name b/tests/f_bad_bbitmap/name
new file mode 100644 (file)
index 0000000..923ddcb
--- /dev/null
@@ -0,0 +1 @@
+corrupt block bitmap (metadata_csum)
diff --git a/tests/f_bad_bmap_csum/expect.1 b/tests/f_bad_bmap_csum/expect.1
new file mode 100644 (file)
index 0000000..ca8f77f
--- /dev/null
@@ -0,0 +1,16 @@
+One or more block group descriptor checksums are invalid.  Fix? yes
+
+Group descriptor 0 checksum is 0x4972, should be 0x7074.  FIXED.
+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
+Inode bitmap differences: Group 0 inode bitmap does not match checksum.
+FIXED.
+Block bitmap differences: Group 0 block bitmap does not match checksum.
+FIXED.
+
+test_filesys: ***** FILE SYSTEM WAS MODIFIED *****
+test_filesys: 11/128 files (0.0% non-contiguous), 18/512 blocks
+Exit status is 1
diff --git a/tests/f_bad_bmap_csum/expect.2 b/tests/f_bad_bmap_csum/expect.2
new file mode 100644 (file)
index 0000000..411e656
--- /dev/null
@@ -0,0 +1,7 @@
+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/128 files (0.0% non-contiguous), 18/512 blocks
+Exit status is 0
diff --git a/tests/f_bad_bmap_csum/image.gz b/tests/f_bad_bmap_csum/image.gz
new file mode 100644 (file)
index 0000000..70a0d18
Binary files /dev/null and b/tests/f_bad_bmap_csum/image.gz differ
diff --git a/tests/f_bad_bmap_csum/name b/tests/f_bad_bmap_csum/name
new file mode 100644 (file)
index 0000000..df19fe3
--- /dev/null
@@ -0,0 +1 @@
+bad block/inode bitmap csum (metadata_csum)
index 11862f6..9f9b447 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
 
diff --git a/tests/f_bad_gdt_csum/expect.1 b/tests/f_bad_gdt_csum/expect.1
new file mode 100644 (file)
index 0000000..e14c897
--- /dev/null
@@ -0,0 +1,10 @@
+One or more block group descriptor checksums are invalid.  Fix? yes
+
+Group descriptor 0 checksum is 0xffff, should be 0x4972.  FIXED.
+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/128 files (0.0% non-contiguous), 18/512 blocks
+Exit status is 0
diff --git a/tests/f_bad_gdt_csum/expect.2 b/tests/f_bad_gdt_csum/expect.2
new file mode 100644 (file)
index 0000000..411e656
--- /dev/null
@@ -0,0 +1,7 @@
+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/128 files (0.0% non-contiguous), 18/512 blocks
+Exit status is 0
diff --git a/tests/f_bad_gdt_csum/image.gz b/tests/f_bad_gdt_csum/image.gz
new file mode 100644 (file)
index 0000000..c3fdafe
Binary files /dev/null and b/tests/f_bad_gdt_csum/image.gz differ
diff --git a/tests/f_bad_gdt_csum/name b/tests/f_bad_gdt_csum/name
new file mode 100644 (file)
index 0000000..fe2c601
--- /dev/null
@@ -0,0 +1 @@
+bad group descriptor csum (metadata_csum)
diff --git a/tests/f_bad_ibitmap/expect.1 b/tests/f_bad_ibitmap/expect.1
new file mode 100644 (file)
index 0000000..ea17523
--- /dev/null
@@ -0,0 +1,15 @@
+One or more block group descriptor checksums are invalid.  Fix? yes
+
+Group descriptor 0 checksum is 0xffff, should be 0x4972.  FIXED.
+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
+Inode bitmap differences:  -(12--32)
+Fix? yes
+
+
+test_filesys: ***** FILE SYSTEM WAS MODIFIED *****
+test_filesys: 11/128 files (0.0% non-contiguous), 18/512 blocks
+Exit status is 1
diff --git a/tests/f_bad_ibitmap/expect.2 b/tests/f_bad_ibitmap/expect.2
new file mode 100644 (file)
index 0000000..411e656
--- /dev/null
@@ -0,0 +1,7 @@
+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/128 files (0.0% non-contiguous), 18/512 blocks
+Exit status is 0
diff --git a/tests/f_bad_ibitmap/image.gz b/tests/f_bad_ibitmap/image.gz
new file mode 100644 (file)
index 0000000..3a52398
Binary files /dev/null and b/tests/f_bad_ibitmap/image.gz differ
diff --git a/tests/f_bad_ibitmap/name b/tests/f_bad_ibitmap/name
new file mode 100644 (file)
index 0000000..76ec12d
--- /dev/null
@@ -0,0 +1 @@
+corrupt inode bitmap (metadata_csum)
diff --git a/tests/f_bad_inode_csum/expect.1 b/tests/f_bad_inode_csum/expect.1
new file mode 100644 (file)
index 0000000..b3c628d
--- /dev/null
@@ -0,0 +1,126 @@
+Pass 1: Checking inodes, blocks, and sizes
+Inode 33 has a extra size (65535) which is invalid
+Fix? yes
+
+Inode 49 passes checks, but checksum does not match inode.  Fix? yes
+
+Inode 65 passes checks, but checksum does not match inode.  Fix? yes
+
+Inode 81 passes checks, but checksum does not match inode.  Fix? yes
+
+Inode 97 seems to contain garbage.  Clear? yes
+
+Inode 98 seems to contain garbage.  Clear? yes
+
+Inode 99 seems to contain garbage.  Clear? yes
+
+Inode 100 seems to contain garbage.  Clear? yes
+
+Inode 101 seems to contain garbage.  Clear? yes
+
+Inode 102 seems to contain garbage.  Clear? yes
+
+Inode 103 seems to contain garbage.  Clear? yes
+
+Inode 104 seems to contain garbage.  Clear? yes
+
+Inode 105 seems to contain garbage.  Clear? yes
+
+Inode 106 seems to contain garbage.  Clear? yes
+
+Inode 107 seems to contain garbage.  Clear? yes
+
+Inode 108 seems to contain garbage.  Clear? yes
+
+Inode 109 seems to contain garbage.  Clear? yes
+
+Inode 110 seems to contain garbage.  Clear? yes
+
+Inode 111 seems to contain garbage.  Clear? yes
+
+Inode 112 seems to contain garbage.  Clear? yes
+
+Pass 2: Checking directory structure
+Extended attribute block for inode 49 (/38) is invalid (4294967295).
+Clear? yes
+
+Entry '86' in / (2) has deleted/unused inode 97.  Clear? yes
+
+Entry '87' in / (2) has deleted/unused inode 98.  Clear? yes
+
+Entry '88' in / (2) has deleted/unused inode 99.  Clear? yes
+
+Entry '89' in / (2) has deleted/unused inode 100.  Clear? yes
+
+Entry '90' in / (2) has deleted/unused inode 101.  Clear? yes
+
+Entry '91' in / (2) has deleted/unused inode 102.  Clear? yes
+
+Entry '92' in / (2) has deleted/unused inode 103.  Clear? yes
+
+Entry '93' in / (2) has deleted/unused inode 104.  Clear? yes
+
+Entry '94' in / (2) has deleted/unused inode 105.  Clear? yes
+
+Entry '95' in / (2) has deleted/unused inode 106.  Clear? yes
+
+Entry '96' in / (2) has deleted/unused inode 107.  Clear? yes
+
+Entry '97' in / (2) has deleted/unused inode 108.  Clear? yes
+
+Entry '98' in / (2) has deleted/unused inode 109.  Clear? yes
+
+Entry '99' in / (2) has deleted/unused inode 110.  Clear? yes
+
+Entry '100' in / (2) has deleted/unused inode 111.  Clear? yes
+
+Entry '101' in / (2) has deleted/unused inode 112.  Clear? yes
+
+Entry '102' in / (2) has deleted/unused inode 113.  Clear? yes
+
+Entry '103' in / (2) has deleted/unused inode 114.  Clear? yes
+
+Entry '104' in / (2) has deleted/unused inode 115.  Clear? yes
+
+Entry '105' in / (2) has deleted/unused inode 116.  Clear? yes
+
+Entry '106' in / (2) has deleted/unused inode 117.  Clear? yes
+
+Entry '107' in / (2) has deleted/unused inode 118.  Clear? yes
+
+Entry '108' in / (2) has deleted/unused inode 119.  Clear? yes
+
+Entry '109' in / (2) has deleted/unused inode 120.  Clear? yes
+
+Entry '110' in / (2) has deleted/unused inode 121.  Clear? yes
+
+Entry '111' in / (2) has deleted/unused inode 122.  Clear? yes
+
+Entry '112' in / (2) has deleted/unused inode 123.  Clear? yes
+
+Entry '113' in / (2) has deleted/unused inode 124.  Clear? yes
+
+Entry '114' in / (2) has deleted/unused inode 125.  Clear? yes
+
+Entry '115' in / (2) has deleted/unused inode 126.  Clear? yes
+
+Entry '116' in / (2) has deleted/unused inode 127.  Clear? yes
+
+Entry '117' in / (2) has deleted/unused inode 128.  Clear? yes
+
+Pass 3: Checking directory connectivity
+Pass 4: Checking reference counts
+Pass 5: Checking group summary information
+Inode bitmap differences:  -(97--128)
+Fix? yes
+
+Free inodes count wrong for group #0 (0, counted=32).
+Fix? yes
+
+Free inodes count wrong (0, counted=32).
+Fix? yes
+
+
+test_filesys: ***** FILE SYSTEM WAS MODIFIED *****
+test_filesys: 96/128 files (0.0% non-contiguous), 18/512 blocks
+Exit status is 1
diff --git a/tests/f_bad_inode_csum/expect.2 b/tests/f_bad_inode_csum/expect.2
new file mode 100644 (file)
index 0000000..b97a902
--- /dev/null
@@ -0,0 +1,7 @@
+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: 96/128 files (0.0% non-contiguous), 18/512 blocks
+Exit status is 0
diff --git a/tests/f_bad_inode_csum/image.gz b/tests/f_bad_inode_csum/image.gz
new file mode 100644 (file)
index 0000000..221920b
Binary files /dev/null and b/tests/f_bad_inode_csum/image.gz differ
diff --git a/tests/f_bad_inode_csum/name b/tests/f_bad_inode_csum/name
new file mode 100644 (file)
index 0000000..68bf7ce
--- /dev/null
@@ -0,0 +1 @@
+inode table corruption (metadata_csum)
index 6cfffb7..b8ce19d 100644 (file)
@@ -23,8 +23,8 @@ Inode 18, i_blocks is 32, should be 64.  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: 1154
-Multiply-claimed block(s) in inode 13: 1152 1153 1154
-Multiply-claimed block(s) in inode 14: 1648 1649 1650
+Multiply-claimed block(s) in inode 13: 1152--1154
+Multiply-claimed block(s) in inode 14: 1648--1650
 Multiply-claimed block(s) in inode 15: 1650
 Multiply-claimed block(s) in inode 16: 1173
 Multiply-claimed block(s) in inode 17: 1186 1185 1184
index 1d639f6..ec1a36e 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.)
diff --git a/tests/f_corrupt_dirent_tail/expect.1 b/tests/f_corrupt_dirent_tail/expect.1
new file mode 100644 (file)
index 0000000..0813755
--- /dev/null
@@ -0,0 +1,16 @@
+Pass 1: Checking inodes, blocks, and sizes
+Pass 2: Checking directory structure
+Directory inode 2, block #0, offset 0: directory has no checksum.
+Fix? yes
+
+Directory inode 2, block #0, offset 1012: directory corrupted
+Salvage? yes
+
+Pass 3: Checking directory connectivity
+Pass 3A: Optimizing directories
+Pass 4: Checking reference counts
+Pass 5: Checking group summary information
+
+test_filesys: ***** FILE SYSTEM WAS MODIFIED *****
+test_filesys: 11/128 files (9.1% non-contiguous), 1090/2048 blocks
+Exit status is 1
diff --git a/tests/f_corrupt_dirent_tail/expect.2 b/tests/f_corrupt_dirent_tail/expect.2
new file mode 100644 (file)
index 0000000..c42466d
--- /dev/null
@@ -0,0 +1,7 @@
+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/128 files (9.1% non-contiguous), 1090/2048 blocks
+Exit status is 0
diff --git a/tests/f_corrupt_dirent_tail/image.gz b/tests/f_corrupt_dirent_tail/image.gz
new file mode 100644 (file)
index 0000000..f275308
Binary files /dev/null and b/tests/f_corrupt_dirent_tail/image.gz differ
diff --git a/tests/f_corrupt_dirent_tail/name b/tests/f_corrupt_dirent_tail/name
new file mode 100644 (file)
index 0000000..08259a3
--- /dev/null
@@ -0,0 +1 @@
+rebuild a directory with corrupt dirent tail
diff --git a/tests/f_deleted_inode_bad_csum/expect.1 b/tests/f_deleted_inode_bad_csum/expect.1
new file mode 100644 (file)
index 0000000..8420361
--- /dev/null
@@ -0,0 +1,11 @@
+Pass 1: Checking inodes, blocks, and sizes
+Inode 12 passes checks, but checksum does not match inode.  Fix? yes
+
+Pass 2: Checking directory structure
+Pass 3: Checking directory connectivity
+Pass 4: Checking reference counts
+Pass 5: Checking group summary information
+
+test_filesys: ***** FILE SYSTEM WAS MODIFIED *****
+test_filesys: 12/128 files (0.0% non-contiguous), 18/512 blocks
+Exit status is 1
diff --git a/tests/f_deleted_inode_bad_csum/expect.2 b/tests/f_deleted_inode_bad_csum/expect.2
new file mode 100644 (file)
index 0000000..eb48b40
--- /dev/null
@@ -0,0 +1,7 @@
+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: 12/128 files (0.0% non-contiguous), 18/512 blocks
+Exit status is 0
diff --git a/tests/f_deleted_inode_bad_csum/image.gz b/tests/f_deleted_inode_bad_csum/image.gz
new file mode 100644 (file)
index 0000000..a27e50e
Binary files /dev/null and b/tests/f_deleted_inode_bad_csum/image.gz differ
diff --git a/tests/f_deleted_inode_bad_csum/name b/tests/f_deleted_inode_bad_csum/name
new file mode 100644 (file)
index 0000000..516701a
--- /dev/null
@@ -0,0 +1 @@
+deleted inode with a bad csum that wasn't getting fixed (metadata_csum)
diff --git a/tests/f_dir_bad_csum/expect.1 b/tests/f_dir_bad_csum/expect.1
new file mode 100644 (file)
index 0000000..bbcbfcb
--- /dev/null
@@ -0,0 +1,62 @@
+Pass 1: Checking inodes, blocks, and sizes
+Pass 2: Checking directory structure
+Directory inode 12, block #0, offset 12: directory passes checks but fails checksum.
+Fix? yes
+
+Directory inode 13, block #0, offset 0: directory has no checksum.
+Fix? yes
+
+Directory inode 13, block #0, offset 1012: directory passes checks but fails checksum.
+Fix? yes
+
+Directory inode 14, block #0, offset 0: directory has no checksum.
+Fix? yes
+
+Directory inode 14, block #0, offset 12: directory passes checks but fails checksum.
+Fix? yes
+
+Directory inode 15, block #0, offset 0: directory has no checksum.
+Fix? yes
+
+Directory inode 15, block #0, offset 1000: directory corrupted
+Salvage? yes
+
+Directory inode 16, block #0, offset 0: directory has no checksum.
+Fix? yes
+
+Directory inode 16, block #0, offset 12: directory corrupted
+Salvage? yes
+
+Directory inode 17, block #0, offset 0: directory has no checksum.
+Fix? yes
+
+Directory inode 17, block #0, offset 0: directory corrupted
+Salvage? yes
+
+Missing '.' in directory inode 17.
+Fix? yes
+
+Setting filetype for entry '.' in ??? (17) to 2.
+Missing '..' in directory inode 17.
+Fix? yes
+
+Setting filetype for entry '..' in ??? (17) to 2.
+Entry 'file' in ??? (18) has invalid inode #: 4294967295.
+Clear? yes
+
+Pass 3: Checking directory connectivity
+'..' in /6 (17) is <The NULL inode> (0), should be / (2).
+Fix? yes
+
+Pass 3A: Optimizing directories
+Pass 4: Checking reference counts
+Unattached inode 19
+Connect to /lost+found? yes
+
+Inode 19 ref count is 2, should be 1.  Fix? yes
+
+Pass 5: Checking group summary information
+
+test_filesys: ***** FILE SYSTEM WAS MODIFIED *****
+test_filesys: 19/128 files (5.3% non-contiguous), 1098/2048 blocks
+Exit status is 1
diff --git a/tests/f_dir_bad_csum/expect.2 b/tests/f_dir_bad_csum/expect.2
new file mode 100644 (file)
index 0000000..f5a3e5f
--- /dev/null
@@ -0,0 +1,7 @@
+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: 19/128 files (5.3% non-contiguous), 1098/2048 blocks
+Exit status is 0
diff --git a/tests/f_dir_bad_csum/image.gz b/tests/f_dir_bad_csum/image.gz
new file mode 100644 (file)
index 0000000..4b58187
Binary files /dev/null and b/tests/f_dir_bad_csum/image.gz differ
diff --git a/tests/f_dir_bad_csum/name b/tests/f_dir_bad_csum/name
new file mode 100644 (file)
index 0000000..140ae45
--- /dev/null
@@ -0,0 +1 @@
+dir block w/ missing/bad csum, no tail, or dir block corruption (metadata_csum)
index e7128f3..075e62c 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 0476005..69aa21b 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 f0ad457..f4581c4 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 dd8fe05..aaf7769 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 3f70109..6751986 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 830370a..2107e2d 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.)
diff --git a/tests/f_ea_bad_csum/expect.1 b/tests/f_ea_bad_csum/expect.1
new file mode 100644 (file)
index 0000000..4fc365f
--- /dev/null
@@ -0,0 +1,29 @@
+Pass 1: Checking inodes, blocks, and sizes
+Inode 12 has a bad extended attribute block 1074.  Clear? yes
+
+Inode 12, i_blocks is 2, should be 0.  Fix? yes
+
+Extended attribute in inode 13 has a hash (1631637196) which is invalid
+Clear? yes
+
+Inode 13, i_blocks is 2, should be 0.  Fix? yes
+
+Inode 14 extended attribute block 1076 passes checks, but checksum does not match block.  Fix? yes
+
+Pass 2: Checking directory structure
+Pass 3: Checking directory connectivity
+Pass 4: Checking reference counts
+Pass 5: Checking group summary information
+Block bitmap differences:  -(1074--1075)
+Fix? yes
+
+Free blocks count wrong for group #0 (971, counted=973).
+Fix? yes
+
+Free blocks count wrong (971, counted=973).
+Fix? yes
+
+
+test_filesys: ***** FILE SYSTEM WAS MODIFIED *****
+test_filesys: 14/128 files (7.1% non-contiguous), 1075/2048 blocks
+Exit status is 1
diff --git a/tests/f_ea_bad_csum/expect.2 b/tests/f_ea_bad_csum/expect.2
new file mode 100644 (file)
index 0000000..d83fdfb
--- /dev/null
@@ -0,0 +1,7 @@
+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: 14/128 files (7.1% non-contiguous), 1075/2048 blocks
+Exit status is 0
diff --git a/tests/f_ea_bad_csum/image.gz b/tests/f_ea_bad_csum/image.gz
new file mode 100644 (file)
index 0000000..e7a25c5
Binary files /dev/null and b/tests/f_ea_bad_csum/image.gz differ
diff --git a/tests/f_ea_bad_csum/name b/tests/f_ea_bad_csum/name
new file mode 100644 (file)
index 0000000..958b244
--- /dev/null
@@ -0,0 +1 @@
+EA block with bad checksum (metadata_csum)
index 9c9d79f..0b4ab8c 100644 (file)
@@ -1 +1 @@
-bad interior node in extent tree
+bad interior node in extent tree (metadata_csum)
diff --git a/tests/f_extent_int_bad_csum/expect.1 b/tests/f_extent_int_bad_csum/expect.1
new file mode 100644 (file)
index 0000000..57a2a61
--- /dev/null
@@ -0,0 +1,11 @@
+Pass 1: Checking inodes, blocks, and sizes
+Inode 12 extent block passes checks, but checksum does not match extent
+       (logical block 698, invalid physical block 1788, len 1)
+Fix? yes
+
+Pass 2: Checking directory structure
+Pass 3: Checking directory connectivity
+Pass 4: Checking reference counts
+Pass 5: Checking group summary information
+test_filesys: 12/128 files (16.7% non-contiguous), 1446/2048 blocks
+Exit status is 0
diff --git a/tests/f_extent_int_bad_csum/expect.2 b/tests/f_extent_int_bad_csum/expect.2
new file mode 100644 (file)
index 0000000..6f73d98
--- /dev/null
@@ -0,0 +1,7 @@
+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: 12/128 files (16.7% non-contiguous), 1446/2048 blocks
+Exit status is 0
diff --git a/tests/f_extent_int_bad_csum/image.gz b/tests/f_extent_int_bad_csum/image.gz
new file mode 100644 (file)
index 0000000..f387898
Binary files /dev/null and b/tests/f_extent_int_bad_csum/image.gz differ
diff --git a/tests/f_extent_int_bad_csum/name b/tests/f_extent_int_bad_csum/name
new file mode 100644 (file)
index 0000000..87317e3
--- /dev/null
@@ -0,0 +1 @@
+bad csum in internal extent (metadata_csum)
diff --git a/tests/f_extent_int_bad_extent/expect.1 b/tests/f_extent_int_bad_extent/expect.1
new file mode 100644 (file)
index 0000000..3d2fb58
--- /dev/null
@@ -0,0 +1,24 @@
+Pass 1: Checking inodes, blocks, and sizes
+Inode 12 has an invalid extent
+       (logical block 0, invalid physical block 4294967295, len 168)
+Clear? yes
+
+Inode 12, i_blocks is 712, should be 542.  Fix? yes
+
+Pass 2: Checking directory structure
+Pass 3: Checking directory connectivity
+Pass 4: Checking reference counts
+Pass 5: Checking group summary information
+Block bitmap differences:  -(1090--1091) -1093 -1095 -1097 -1099 -1101 -1103 -1105 -1107 -1109 -1111 -1113 -1115 -1117 -1119 -1121 -1123 -1125 -1127 -1129 -1131 -1133 -1135 -1137 -1139 -1141 -1143 -1145 -1147 -1149 -1151 -1153 -1155 -1157 -1159 -1161 -1163 -1165 -1167 -1169 -1171 -1173 -1175 -1177 -1179 -1181 -1183 -1185 -1187 -1189 -1191 -1193 -1195 -1197 -1199 -1201 -1203 -1205 -1207 -1209 -1211 -1213 -1215 -1217 -1219 -1221 -1223 -1225 -1227 -1229 -1231 -1233 -1235 -1237 -1239 -1241 -1243 -1245 -1247 -1249 -1251 -1253 -1255 -1257
+Fix? yes
+
+Free blocks count wrong for group #0 (602, counted=687).
+Fix? yes
+
+Free blocks count wrong (602, counted=687).
+Fix? yes
+
+
+test_filesys: ***** FILE SYSTEM WAS MODIFIED *****
+test_filesys: 12/128 files (16.7% non-contiguous), 1361/2048 blocks
+Exit status is 1
diff --git a/tests/f_extent_int_bad_extent/expect.2 b/tests/f_extent_int_bad_extent/expect.2
new file mode 100644 (file)
index 0000000..4e72e41
--- /dev/null
@@ -0,0 +1,7 @@
+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: 12/128 files (16.7% non-contiguous), 1361/2048 blocks
+Exit status is 0
diff --git a/tests/f_extent_int_bad_extent/image.gz b/tests/f_extent_int_bad_extent/image.gz
new file mode 100644 (file)
index 0000000..e8745bf
Binary files /dev/null and b/tests/f_extent_int_bad_extent/image.gz differ
diff --git a/tests/f_extent_int_bad_extent/name b/tests/f_extent_int_bad_extent/name
new file mode 100644 (file)
index 0000000..e22f6b4
--- /dev/null
@@ -0,0 +1 @@
+bad extent in internal extent (metadata_csum)
diff --git a/tests/f_extent_int_bad_magic/expect.1 b/tests/f_extent_int_bad_magic/expect.1
new file mode 100644 (file)
index 0000000..0e82e2b
--- /dev/null
@@ -0,0 +1,23 @@
+Pass 1: Checking inodes, blocks, and sizes
+Inode 12 has an invalid extent node (blk 1295, lblk 0)
+Clear? yes
+
+Inode 12, i_blocks is 712, should be 0.  Fix? yes
+
+Pass 2: Checking directory structure
+Pass 3: Checking directory connectivity
+Pass 4: Checking reference counts
+Pass 5: Checking group summary information
+Block bitmap differences:  -(1090--1093) -1095 -1097 -1099 -1101 -1103 -1105 -1107 -1109 -1111 -1113 -1115 -1117 -1119 -1121 -1123 -1125 -1127 -1129 -1131 -1133 -1135 -1137 -1139 -1141 -1143 -1145 -1147 -1149 -1151 -1153 -1155 -1157 -1159 -1161 -1163 -1165 -1167 -1169 -1171 -1173 -1175 -1177 -1179 -1181 -1183 -1185 -1187 -1189 -1191 -1193 -1195 -1197 -1199 -1201 -1203 -1205 -1207 -1209 -1211 -1213 -1215 -1217 -1219 -1221 -1223 -1225 -1227 -1229 -1231 -1233 -1235 -1237 -1239 -1241 -1243 -1245 -1247 -1249 -1251 -1253 -1255 -1257 -1259 -1261 -1263 -1265 -1267 -1269 -1271 -1273 -1275 -1277 -1279 -1281 -1283 -1285 -1287 -(1289--1298) -1300 -1302 -1304 -1306 -1308 -1310 -1312 -1314 -1316 -1318 -1320 -1322 -1324 -1326 -1328 -1330 -1332 -1334 -1336 -1338 -1340 -1342 -1344 -1346 -1348 -1350 -1352 -1354 -1356 -1358 -1360 -1362 -1364 -1366 -1368 -1370 -1372 -1374 -1376 -1378 -1380 -1382 -1384 -1386 -1388 -1390 -1392 -1394 -1396 -1398 -1400 -1402 -1404 -1406 -1408 -1410 -1412 -1414 -1416 -1418 -1420 -1422 -1424 -1426 -1428 -1430 -1432 -1434 -1436 -1438 -1440 -1442 -1444 -1446 -1448 -1450 -1452 -1454 -1456 -1458 -1460 -1462 -1464 -1466 -1468 -1470 -1472 -1474 -1476 -1478 -1480 -1482 -1484 -1486 -1488 -1490 -1492 -1494 -1496 -1498 -1500 -1502 -1504 -1506 -1508 -1510 -1512 -1514 -1516 -1518 -1520 -1522 -1524 -1526 -1528 -1530 -1532 -1534 -1536 -1538 -1540 -1542 -1544 -1546 -1548 -1550 -1552 -1554 -1556 -1558 -1560 -1562 -1564 -1566 -1568 -1570 -1572 -1574 -1576 -1578 -1580 -1582 -1584 -1586 -1588 -1590 -1592 -1594 -1596 -1598 -1600 -1602 -1604 -1606 -1608 -1610 -1612 -1614 -1616 -1618 -1620 -1622 -1624 -1626 -1628 -1630 -1632 -1634 -1636 -1638 -1640 -1642 -1644 -1646 -1648 -1650 -1652 -1654 -1656 -1658 -1660 -1662 -1664 -1666 -1668 -1670 -1672 -1674 -1676 -1678 -1680 -1682 -1684 -1686 -1688 -1690 -1692 -1694 -1696 -1698 -1700 -1702 -1704 -1706 -1708 -1710 -1712 -1714 -1716 -1718 -1720 -1722 -1724 -1726 -1728 -1730 -1732 -1734 -1736 -1738 -1740 -1742 -1744 -1746 -1748 -1750 -1752 -1754 -1756 -1758 -1760 -1762 -1764 -1766 -1768 -1770 -1772 -1774 -1776 -1778 -1780 -1782 -1784 -1786 -1788
+Fix? yes
+
+Free blocks count wrong for group #0 (602, counted=958).
+Fix? yes
+
+Free blocks count wrong (602, counted=958).
+Fix? yes
+
+
+test_filesys: ***** FILE SYSTEM WAS MODIFIED *****
+test_filesys: 12/128 files (8.3% non-contiguous), 1090/2048 blocks
+Exit status is 1
diff --git a/tests/f_extent_int_bad_magic/expect.2 b/tests/f_extent_int_bad_magic/expect.2
new file mode 100644 (file)
index 0000000..283cc1f
--- /dev/null
@@ -0,0 +1,7 @@
+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: 12/128 files (8.3% non-contiguous), 1090/2048 blocks
+Exit status is 0
diff --git a/tests/f_extent_int_bad_magic/image.gz b/tests/f_extent_int_bad_magic/image.gz
new file mode 100644 (file)
index 0000000..e00f887
Binary files /dev/null and b/tests/f_extent_int_bad_magic/image.gz differ
diff --git a/tests/f_extent_int_bad_magic/name b/tests/f_extent_int_bad_magic/name
new file mode 100644 (file)
index 0000000..a451e9a
--- /dev/null
@@ -0,0 +1 @@
+bad magic number in internal extent (metadata_csum)
diff --git a/tests/f_extent_leaf_bad_csum/expect.1 b/tests/f_extent_leaf_bad_csum/expect.1
new file mode 100644 (file)
index 0000000..0dc78ad
--- /dev/null
@@ -0,0 +1,11 @@
+Pass 1: Checking inodes, blocks, and sizes
+Inode 12 extent block passes checks, but checksum does not match extent
+       (logical block 7, invalid physical block 1090, len 1)
+Fix? yes
+
+Pass 2: Checking directory structure
+Pass 3: Checking directory connectivity
+Pass 4: Checking reference counts
+Pass 5: Checking group summary information
+test_filesys: 12/128 files (16.7% non-contiguous), 1099/2048 blocks
+Exit status is 0
diff --git a/tests/f_extent_leaf_bad_csum/expect.2 b/tests/f_extent_leaf_bad_csum/expect.2
new file mode 100644 (file)
index 0000000..a564763
--- /dev/null
@@ -0,0 +1,7 @@
+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: 12/128 files (16.7% non-contiguous), 1099/2048 blocks
+Exit status is 0
diff --git a/tests/f_extent_leaf_bad_csum/image.gz b/tests/f_extent_leaf_bad_csum/image.gz
new file mode 100644 (file)
index 0000000..6c778f6
Binary files /dev/null and b/tests/f_extent_leaf_bad_csum/image.gz differ
diff --git a/tests/f_extent_leaf_bad_csum/name b/tests/f_extent_leaf_bad_csum/name
new file mode 100644 (file)
index 0000000..62a2285
--- /dev/null
@@ -0,0 +1 @@
+bad csum in leaf extent (metadata_csum)
diff --git a/tests/f_extent_leaf_bad_extent/expect.1 b/tests/f_extent_leaf_bad_extent/expect.1
new file mode 100644 (file)
index 0000000..f96a8a9
--- /dev/null
@@ -0,0 +1,24 @@
+Pass 1: Checking inodes, blocks, and sizes
+Inode 12 has an invalid extent
+       (logical block 2, invalid physical block 4294967295, len 1)
+Clear? yes
+
+Inode 12, i_blocks is 18, should be 16.  Fix? yes
+
+Pass 2: Checking directory structure
+Pass 3: Checking directory connectivity
+Pass 4: Checking reference counts
+Pass 5: Checking group summary information
+Block bitmap differences:  -1096
+Fix? yes
+
+Free blocks count wrong for group #0 (949, counted=950).
+Fix? yes
+
+Free blocks count wrong (949, counted=950).
+Fix? yes
+
+
+test_filesys: ***** FILE SYSTEM WAS MODIFIED *****
+test_filesys: 12/128 files (16.7% non-contiguous), 1098/2048 blocks
+Exit status is 1
diff --git a/tests/f_extent_leaf_bad_extent/expect.2 b/tests/f_extent_leaf_bad_extent/expect.2
new file mode 100644 (file)
index 0000000..de1727c
--- /dev/null
@@ -0,0 +1,7 @@
+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: 12/128 files (16.7% non-contiguous), 1098/2048 blocks
+Exit status is 0
diff --git a/tests/f_extent_leaf_bad_extent/image.gz b/tests/f_extent_leaf_bad_extent/image.gz
new file mode 100644 (file)
index 0000000..d34d4d4
Binary files /dev/null and b/tests/f_extent_leaf_bad_extent/image.gz differ
diff --git a/tests/f_extent_leaf_bad_extent/name b/tests/f_extent_leaf_bad_extent/name
new file mode 100644 (file)
index 0000000..1bd8bd1
--- /dev/null
@@ -0,0 +1 @@
+bad extent in leaf extent (metadata_csum)
diff --git a/tests/f_extent_leaf_bad_magic/expect.1 b/tests/f_extent_leaf_bad_magic/expect.1
new file mode 100644 (file)
index 0000000..7b6dbf1
--- /dev/null
@@ -0,0 +1,23 @@
+Pass 1: Checking inodes, blocks, and sizes
+Inode 12 has an invalid extent node (blk 1604, lblk 0)
+Clear? yes
+
+Inode 12, i_blocks is 18, should be 0.  Fix? yes
+
+Pass 2: Checking directory structure
+Pass 3: Checking directory connectivity
+Pass 4: Checking reference counts
+Pass 5: Checking group summary information
+Block bitmap differences:  -(1090--1097) -1604
+Fix? yes
+
+Free blocks count wrong for group #0 (949, counted=958).
+Fix? yes
+
+Free blocks count wrong (949, counted=958).
+Fix? yes
+
+
+test_filesys: ***** FILE SYSTEM WAS MODIFIED *****
+test_filesys: 12/128 files (8.3% non-contiguous), 1090/2048 blocks
+Exit status is 1
diff --git a/tests/f_extent_leaf_bad_magic/expect.2 b/tests/f_extent_leaf_bad_magic/expect.2
new file mode 100644 (file)
index 0000000..283cc1f
--- /dev/null
@@ -0,0 +1,7 @@
+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: 12/128 files (8.3% non-contiguous), 1090/2048 blocks
+Exit status is 0
diff --git a/tests/f_extent_leaf_bad_magic/image.gz b/tests/f_extent_leaf_bad_magic/image.gz
new file mode 100644 (file)
index 0000000..7dd044f
Binary files /dev/null and b/tests/f_extent_leaf_bad_magic/image.gz differ
diff --git a/tests/f_extent_leaf_bad_magic/name b/tests/f_extent_leaf_bad_magic/name
new file mode 100644 (file)
index 0000000..e9f756e
--- /dev/null
@@ -0,0 +1 @@
+bad magic number in leaf extent (metadata_csum)
index 2abe32e..953162c 100644 (file)
@@ -22,6 +22,9 @@ Clear inode? yes
 
 Inode 18, i_blocks is 2, should be 0.  Fix? yes
 
+Special (device/socket/fifo) file (inode 19) has extents
+or inline-data flag set.  Clear? yes
+
 Pass 2: Checking directory structure
 Entry 'fbad-flag' in / (2) has deleted/unused inode 18.  Clear? yes
 
diff --git a/tests/f_htree_bad_csum/expect.1 b/tests/f_htree_bad_csum/expect.1
new file mode 100644 (file)
index 0000000..258362b
--- /dev/null
@@ -0,0 +1,28 @@
+Pass 1: Checking inodes, blocks, and sizes
+Pass 2: Checking directory structure
+Problem in HTREE directory inode 12: root node fails checksum.
+Clear HTree index? yes
+
+Problem in HTREE directory inode 18: root node fails checksum.
+Clear HTree index? yes
+
+Directory inode 24, block #0, offset 1020: directory corrupted
+Salvage? yes
+
+Problem in HTREE directory inode 24: root node fails checksum.
+Clear HTree index? yes
+
+Problem in HTREE directory inode 30: root node fails checksum.
+Clear HTree index? yes
+
+Problem in HTREE directory inode 36: root node fails checksum.
+Clear HTree index? yes
+
+Pass 3: Checking directory connectivity
+Pass 3A: Optimizing directories
+Pass 4: Checking reference counts
+Pass 5: Checking group summary information
+
+test_filesys: ***** FILE SYSTEM WAS MODIFIED *****
+test_filesys: 47/128 files (2.1% non-contiguous), 1108/2048 blocks
+Exit status is 1
diff --git a/tests/f_htree_bad_csum/expect.2 b/tests/f_htree_bad_csum/expect.2
new file mode 100644 (file)
index 0000000..7e3523b
--- /dev/null
@@ -0,0 +1,7 @@
+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: 47/128 files (2.1% non-contiguous), 1108/2048 blocks
+Exit status is 0
diff --git a/tests/f_htree_bad_csum/image.gz b/tests/f_htree_bad_csum/image.gz
new file mode 100644 (file)
index 0000000..def571c
Binary files /dev/null and b/tests/f_htree_bad_csum/image.gz differ
diff --git a/tests/f_htree_bad_csum/name b/tests/f_htree_bad_csum/name
new file mode 100644 (file)
index 0000000..ebfc3ea
--- /dev/null
@@ -0,0 +1 @@
+htree block w/ missing/bad csum, bad protective dirent, or htree index corruption (metadata_csum)
diff --git a/tests/f_idata_and_extents/expect.1 b/tests/f_idata_and_extents/expect.1
new file mode 100644 (file)
index 0000000..7f7fbf3
--- /dev/null
@@ -0,0 +1,35 @@
+Pass 1: Checking inodes, blocks, and sizes
+Special (device/socket/fifo) file (inode 19) has extents
+or inline-data flag set.  Clear? yes
+
+Inode 20 has extent header but inline data flag is set.
+Fix? yes
+
+Inode 21 has inline data and extent flags set but i_block contains junk.
+Clear inode? yes
+
+Inode 22 seems to have block map but inline data and extent flags set.
+Fix? yes
+
+Inode 23 seems to have inline data but extent flag is set.
+Fix? yes
+
+Pass 2: Checking directory structure
+Entry 'garbage' in /bad (18) has deleted/unused inode 21.  Clear? yes
+
+Pass 3: Checking directory connectivity
+Pass 4: Checking reference counts
+Pass 5: Checking group summary information
+Inode bitmap differences:  -21
+Fix? yes
+
+Free inodes count wrong for group #0 (105, counted=106).
+Fix? yes
+
+Free inodes count wrong (105, counted=106).
+Fix? yes
+
+
+test_filesys: ***** FILE SYSTEM WAS MODIFIED *****
+test_filesys: 22/128 files (0.0% non-contiguous), 21/512 blocks
+Exit status is 1
diff --git a/tests/f_idata_and_extents/expect.2 b/tests/f_idata_and_extents/expect.2
new file mode 100644 (file)
index 0000000..307d3f6
--- /dev/null
@@ -0,0 +1,7 @@
+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: 22/128 files (0.0% non-contiguous), 21/512 blocks
+Exit status is 0
diff --git a/tests/f_idata_and_extents/image.gz b/tests/f_idata_and_extents/image.gz
new file mode 100644 (file)
index 0000000..5187ba1
Binary files /dev/null and b/tests/f_idata_and_extents/image.gz differ
diff --git a/tests/f_idata_and_extents/name b/tests/f_idata_and_extents/name
new file mode 100644 (file)
index 0000000..362ce0e
--- /dev/null
@@ -0,0 +1 @@
+conflicting extents and inline_data inode flags
diff --git a/tests/f_inlinedata_repair/expect.1 b/tests/f_inlinedata_repair/expect.1
new file mode 100644 (file)
index 0000000..faba192
--- /dev/null
@@ -0,0 +1,75 @@
+Pass 1: Checking inodes, blocks, and sizes
+Inode 12 has INLINE_DATA_FL flag but extended attribute not found.  Truncate? yes
+
+Inode 16, i_size is 56, should be 60.  Fix? yes
+
+Inode 24, i_size is 59, should be 60.  Fix? yes
+
+Inode 28 is a unknown file type with mode 00 but it looks like it is really a directory.
+Fix? yes
+
+Inode 36 is a unknown file type with mode 00 but it looks like it is really a directory.
+Fix? yes
+
+Inode 36, i_size is 5, should be 60.  Fix? yes
+
+Pass 2: Checking directory structure
+Directory inode 20, block #0, offset 4: directory corrupted
+Salvage? yes
+
+Directory inode 28, block #0, offset 4: directory corrupted
+Salvage? yes
+
+Directory inode 32, block #0, offset 4: directory corrupted
+Salvage? yes
+
+Directory inode 32, block #0, offset 4: directory corrupted
+Salvage? yes
+
+Entry '..' in ??? (36) has invalid inode #: 1633774699.
+Clear? yes
+
+Directory inode 36, block #0, offset 4: directory corrupted
+Salvage? yes
+
+Symlink /3 (inode #14) is invalid.
+Clear? yes
+
+Inode 38 (/B) has invalid mode (00).
+Clear? yes
+
+Entry 'A' in / (2) has an incorrect filetype (was 1, should be 2).
+Fix? yes
+
+Pass 3: Checking directory connectivity
+'..' in /A (36) is ??? (1633774699), should be / (2).
+Fix? yes
+
+Error while adjusting inode count on inode 0
+Pass 4: Checking reference counts
+Unattached zero-length inode 22.  Clear? yes
+
+Unattached zero-length inode 23.  Clear? yes
+
+Unattached zero-length inode 29.  Clear? yes
+
+Unattached zero-length inode 30.  Clear? yes
+
+Unattached zero-length inode 31.  Clear? yes
+
+Unattached zero-length inode 33.  Clear? yes
+
+Unattached zero-length inode 34.  Clear? yes
+
+Unattached zero-length inode 35.  Clear? yes
+
+Inode 36 ref count is 1, should be 2.  Fix? yes
+
+Pass 5: Checking group summary information
+Directories count wrong for group #0 (7, counted=8).
+Fix? yes
+
+
+test_filesys: ***** FILE SYSTEM WAS MODIFIED *****
+test_filesys: 28/128 files (0.0% non-contiguous), 18/512 blocks
+Exit status is 1
diff --git a/tests/f_inlinedata_repair/expect.2 b/tests/f_inlinedata_repair/expect.2
new file mode 100644 (file)
index 0000000..519f21d
--- /dev/null
@@ -0,0 +1,7 @@
+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: 28/128 files (0.0% non-contiguous), 18/512 blocks
+Exit status is 0
diff --git a/tests/f_inlinedata_repair/image.gz b/tests/f_inlinedata_repair/image.gz
new file mode 100644 (file)
index 0000000..c33d81d
Binary files /dev/null and b/tests/f_inlinedata_repair/image.gz differ
diff --git a/tests/f_inlinedata_repair/name b/tests/f_inlinedata_repair/name
new file mode 100644 (file)
index 0000000..7e7e898
--- /dev/null
@@ -0,0 +1 @@
+repair corrupt inline data files
diff --git a/tests/f_inode_ea_collision/expect.1 b/tests/f_inode_ea_collision/expect.1
new file mode 100644 (file)
index 0000000..a67a5f1
--- /dev/null
@@ -0,0 +1,15 @@
+Pass 1: Checking inodes, blocks, and sizes
+Inode 12 extended attribute is corrupt (allocation collision).  Clear? yes
+
+Inode 13 extended attribute is corrupt (allocation collision).  Clear? yes
+
+Inode 14 extended attribute is corrupt (allocation collision).  Clear? yes
+
+Pass 2: Checking directory structure
+Pass 3: Checking directory connectivity
+Pass 4: Checking reference counts
+Pass 5: Checking group summary information
+
+test_filesys: ***** FILE SYSTEM WAS MODIFIED *****
+test_filesys: 14/128 files (0.0% non-contiguous), 18/512 blocks
+Exit status is 1
diff --git a/tests/f_inode_ea_collision/expect.2 b/tests/f_inode_ea_collision/expect.2
new file mode 100644 (file)
index 0000000..5a7ca86
--- /dev/null
@@ -0,0 +1,7 @@
+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: 14/128 files (0.0% non-contiguous), 18/512 blocks
+Exit status is 0
diff --git a/tests/f_inode_ea_collision/image.gz b/tests/f_inode_ea_collision/image.gz
new file mode 100644 (file)
index 0000000..5217f65
Binary files /dev/null and b/tests/f_inode_ea_collision/image.gz differ
diff --git a/tests/f_inode_ea_collision/name b/tests/f_inode_ea_collision/name
new file mode 100644 (file)
index 0000000..b64119e
--- /dev/null
@@ -0,0 +1 @@
+collisions in the inode ea area
diff --git a/tests/f_itable_collision/expect.1 b/tests/f_itable_collision/expect.1
new file mode 100644 (file)
index 0000000..00cdced
--- /dev/null
@@ -0,0 +1,101 @@
+Pass 1: Checking inodes, blocks, and sizes
+Inode 12 block 37 conflicts with critical metadata, skipping block checks.
+Illegal block number passed to ext2fs_test_block_bitmap #268435455 for in-use block map
+Illegal block number passed to ext2fs_mark_block_bitmap #268435455 for in-use block map
+Inode 12, i_blocks is 48, should be 56.  Fix? yes
+
+Inode 13 has a bad extended attribute block 34.  Clear? yes
+
+Deleted inode 33 has zero dtime.  Fix? yes
+
+Inodes that were part of a corrupted orphan linked list found.  Fix? yes
+
+Inode 49 was part of the orphaned inode list.  FIXED.
+Inode 14 block 36 conflicts with critical metadata, skipping block checks.
+Illegal block number passed to ext2fs_test_block_bitmap #4294967295 for metadata block map
+Inode 14 has illegal block(s).  Clear? yes
+
+Illegal indirect block (4294967295) in inode 14.  CLEARED.
+Illegal block number passed to ext2fs_test_block_bitmap #4294967295 for metadata block map
+Illegal indirect block (4294967295) in inode 14.  CLEARED.
+Illegal block number passed to ext2fs_test_block_bitmap #4294967295 for metadata block map
+Illegal indirect block (4294967295) in inode 14.  CLEARED.
+Illegal block number passed to ext2fs_test_block_bitmap #4294967295 for metadata block map
+Illegal indirect block (4294967295) in inode 14.  CLEARED.
+Illegal block number passed to ext2fs_test_block_bitmap #4294967295 for metadata block map
+Illegal indirect block (4294967295) in inode 14.  CLEARED.
+Illegal block number passed to ext2fs_test_block_bitmap #4294967295 for metadata block map
+Illegal indirect block (4294967295) in inode 14.  CLEARED.
+Illegal block number passed to ext2fs_test_block_bitmap #4294967295 for metadata block map
+Illegal indirect block (4294967295) in inode 14.  CLEARED.
+Illegal block number passed to ext2fs_test_block_bitmap #4294967295 for metadata block map
+Too many illegal blocks in inode 14.
+Clear inode? yes
+
+Restarting e2fsck from the beginning...
+Pass 1: Checking inodes, blocks, and sizes
+Inode 12 block 37 conflicts with critical metadata, skipping block checks.
+Illegal block number passed to ext2fs_test_block_bitmap #4294967294 for in-use block map
+Illegal block number passed to ext2fs_mark_block_bitmap #4294967294 for in-use block map
+Illegal block number passed to ext2fs_test_block_bitmap #268435455 for in-use block map
+Illegal block number passed to ext2fs_mark_block_bitmap #268435455 for in-use block map
+
+Running additional passes to resolve blocks claimed by more than one inode...
+Pass 1B: Rescanning for multiply-claimed blocks
+Illegal block number passed to ext2fs_test_block_bitmap #4294967294 for multiply claimed block map
+Illegal block number passed to ext2fs_test_block_bitmap #268435455 for multiply claimed block map
+Multiply-claimed block(s) in inode 12: 37
+Pass 1C: Scanning directories for inodes with multiply-claimed blocks
+Pass 1D: Reconciling multiply-claimed blocks
+(There are 1 inodes containing multiply-claimed blocks.)
+
+File /a (inode #12, mod time Fri Jun 27 18:34:44 2014) 
+  has 1 multiply-claimed block(s), shared with 1 file(s):
+       <filesystem metadata>
+Clone multiply-claimed blocks? yes
+
+Illegal block number passed to ext2fs_test_block_bitmap #4294967294 for multiply claimed block map
+Illegal block number passed to ext2fs_test_block_bitmap #268435455 for multiply claimed block map
+Pass 2: Checking directory structure
+Setting filetype for entry 'bad1' in / (2) to 1.
+Setting filetype for entry 'bad2' in / (2) to 1.
+Restarting e2fsck from the beginning...
+Pass 1: Checking inodes, blocks, and sizes
+Inode 12 has an invalid extent
+       (logical block 0, invalid physical block 4294967294, len 1)
+Clear? yes
+
+Inode 12 has an invalid extent
+       (logical block 5, invalid physical block 268435455, len 1)
+Clear? yes
+
+Inode 12, i_blocks is 56, should be 40.  Fix? yes
+
+Pass 2: Checking directory structure
+Entry 'b' in / (2) has deleted/unused inode 14.  Clear? yes
+
+Pass 3: Checking directory connectivity
+Pass 4: Checking reference counts
+Pass 5: Checking group summary information
+Block bitmap differences:  -9 -13 -42
+Fix? yes
+
+Free blocks count wrong for group #0 (485, counted=488).
+Fix? yes
+
+Free blocks count wrong (485, counted=488).
+Fix? yes
+
+Inode bitmap differences:  -14 +34 +50
+Fix? yes
+
+Free inodes count wrong for group #0 (114, counted=113).
+Fix? yes
+
+Free inodes count wrong (114, counted=113).
+Fix? yes
+
+
+test_filesys: ***** FILE SYSTEM WAS MODIFIED *****
+test_filesys: 15/128 files (6.7% non-contiguous), 24/512 blocks
+Exit status is 0
diff --git a/tests/f_itable_collision/expect.2 b/tests/f_itable_collision/expect.2
new file mode 100644 (file)
index 0000000..4abc600
--- /dev/null
@@ -0,0 +1,7 @@
+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: 15/128 files (6.7% non-contiguous), 24/512 blocks
+Exit status is 0
diff --git a/tests/f_itable_collision/image.gz b/tests/f_itable_collision/image.gz
new file mode 100644 (file)
index 0000000..6218b14
Binary files /dev/null and b/tests/f_itable_collision/image.gz differ
diff --git a/tests/f_itable_collision/name b/tests/f_itable_collision/name
new file mode 100644 (file)
index 0000000..dab3d45
--- /dev/null
@@ -0,0 +1 @@
+collision between IND/extent tree blocks and inode table
diff --git a/tests/f_itable_collision/script b/tests/f_itable_collision/script
new file mode 100755 (executable)
index 0000000..7eedfd3
--- /dev/null
@@ -0,0 +1,38 @@
+#!/bin/bash
+
+# Run this test with a specific time, because we're crosslinking an extent tree
+# block with the inode table.  When fsck sets dtime to now, we want "now" to be
+# our preprogrammed value.
+
+FSCK_OPT=-fy
+IMAGE=$test_dir/image.gz
+E2FSCK_TIME=4294967294
+export E2FSCK_TIME
+
+gzip -d < $IMAGE > $TMPFILE
+e2label $TMPFILE test_filesys
+
+# Run fsck to fix things?
+EXP1=$test_dir/expect.1
+OUT1=$test_name.1.log
+rm -rf $test_name.failed $test_name.ok
+
+$FSCK $FSCK_OPT $TMPFILE 2>&1 | tail -n +2 > $OUT1
+echo "Exit status is $?" >> $OUT1
+
+# Run a second time
+EXP2=$test_dir/expect.2
+OUT2=$test_name.2.log
+
+$FSCK $FSCK_OPT $TMPFILE 2>&1 | tail -n +2 > $OUT2
+echo "Exit status is $?" >> $OUT2
+
+# Figure out what happened
+if cmp -s $EXP1 $OUT1 && cmp -s $EXP2 $OUT2; then
+       echo "$test_name: $test_description: ok"
+       touch $test_name.ok
+else
+       echo "$test_name: $test_description: failed"
+       diff -u $EXP1 $OUT1 >> $test_name.failed
+       diff -u $EXP2 $OUT2 >> $test_name.failed
+fi
index 2007f03..5cef2d8 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:
diff --git a/tests/f_no_cache_corrupt_inode/expect.1 b/tests/f_no_cache_corrupt_inode/expect.1
new file mode 100644 (file)
index 0000000..4f82f75
--- /dev/null
@@ -0,0 +1,11 @@
+Pass 1: Checking inodes, blocks, and sizes
+Inode 12 passes checks, but checksum does not match inode.  Fix? yes
+
+Pass 2: Checking directory structure
+Pass 3: Checking directory connectivity
+Pass 4: Checking reference counts
+Pass 5: Checking group summary information
+
+test_filesys: ***** FILE SYSTEM WAS MODIFIED *****
+test_filesys: 12/128 files (0.0% non-contiguous), 19/512 blocks
+Exit status is 1
diff --git a/tests/f_no_cache_corrupt_inode/expect.2 b/tests/f_no_cache_corrupt_inode/expect.2
new file mode 100644 (file)
index 0000000..1b43315
--- /dev/null
@@ -0,0 +1,7 @@
+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: 12/128 files (0.0% non-contiguous), 19/512 blocks
+Exit status is 0
diff --git a/tests/f_no_cache_corrupt_inode/image.gz b/tests/f_no_cache_corrupt_inode/image.gz
new file mode 100644 (file)
index 0000000..e17e921
Binary files /dev/null and b/tests/f_no_cache_corrupt_inode/image.gz differ
diff --git a/tests/f_no_cache_corrupt_inode/name b/tests/f_no_cache_corrupt_inode/name
new file mode 100644 (file)
index 0000000..fb213e2
--- /dev/null
@@ -0,0 +1 @@
+don't cache inodes that fail checksum verification
diff --git a/tests/f_nospc_create_lnf/expect.1 b/tests/f_nospc_create_lnf/expect.1
new file mode 100644 (file)
index 0000000..986fe12
--- /dev/null
@@ -0,0 +1,29 @@
+Pass 1: Checking inodes, blocks, and sizes
+Pass 2: Checking directory structure
+Pass 3: Checking directory connectivity
+/lost+found not found.  Create? yes
+
+Cannot allocate space for /lost+found.
+Place lost files in root directory instead? yes
+
+Insufficient space to recover lost files!
+Move data off the filesystem and re-run e2fsck.
+
+Pass 3A: Optimizing directories
+Pass 4: Checking reference counts
+Unattached inode 125
+Connect to /lost+found? yes
+
+Inode 125 ref count is 2, should be 1.  Fix? yes
+
+Pass 5: Checking group summary information
+Free blocks count wrong for group #0 (496, counted=495).
+Fix? yes
+
+Free blocks count wrong (496, counted=495).
+Fix? yes
+
+
+test_filesys: ***** FILE SYSTEM WAS MODIFIED *****
+test_filesys: 128/128 files (0.0% non-contiguous), 17/512 blocks
+Exit status is 1
diff --git a/tests/f_nospc_create_lnf/expect.2 b/tests/f_nospc_create_lnf/expect.2
new file mode 100644 (file)
index 0000000..e9757f8
--- /dev/null
@@ -0,0 +1,26 @@
+Pass 1: Checking inodes, blocks, and sizes
+Pass 2: Checking directory structure
+Pass 3: Checking directory connectivity
+/lost+found not found.  Create? yes
+
+Cannot allocate space for /lost+found.
+Place lost files in root directory instead? yes
+
+Insufficient space to recover lost files!
+Move data off the filesystem and re-run e2fsck.
+
+Pass 4: Checking reference counts
+Pass 5: Checking group summary information
+Block bitmap differences:  -9
+Fix? yes
+
+Free blocks count wrong for group #0 (494, counted=495).
+Fix? yes
+
+Free blocks count wrong (494, counted=495).
+Fix? yes
+
+
+test_filesys: ***** FILE SYSTEM WAS MODIFIED *****
+test_filesys: 128/128 files (0.0% non-contiguous), 17/512 blocks
+Exit status is 1
diff --git a/tests/f_nospc_create_lnf/image.gz b/tests/f_nospc_create_lnf/image.gz
new file mode 100644 (file)
index 0000000..dc71b61
Binary files /dev/null and b/tests/f_nospc_create_lnf/image.gz differ
diff --git a/tests/f_nospc_create_lnf/name b/tests/f_nospc_create_lnf/name
new file mode 100644 (file)
index 0000000..df6c932
--- /dev/null
@@ -0,0 +1 @@
+no space to create lost+found
diff --git a/tests/f_rebuild_csum_rootdir/expect.1 b/tests/f_rebuild_csum_rootdir/expect.1
new file mode 100644 (file)
index 0000000..4df58f9
--- /dev/null
@@ -0,0 +1,311 @@
+Pass 1: Checking inodes, blocks, and sizes
+Pass 2: Checking directory structure
+Directory inode 2, block #0, offset 0: directory has no checksum.
+Fix? yes
+
+Directory inode 2, block #0, offset 0: directory corrupted
+Salvage? yes
+
+Missing '.' in directory inode 2.
+Fix? yes
+
+Setting filetype for entry '.' in ??? (2) to 2.
+Missing '..' in directory inode 2.
+Fix? yes
+
+Setting filetype for entry '..' in ??? (2) to 2.
+Pass 3: Checking directory connectivity
+'..' in / (2) is <The NULL inode> (0), should be / (2).
+Fix? yes
+
+Unconnected directory inode 11 (/???)
+Connect to /lost+found? yes
+
+/lost+found not found.  Create? yes
+
+Pass 3A: Optimizing directories
+Pass 4: Checking reference counts
+Inode 11 ref count is 3, should be 2.  Fix? yes
+
+Unattached inode 12
+Connect to /lost+found? yes
+
+Inode 12 ref count is 2, should be 1.  Fix? yes
+
+Unattached inode 13
+Connect to /lost+found? yes
+
+Inode 13 ref count is 2, should be 1.  Fix? yes
+
+Unattached inode 14
+Connect to /lost+found? yes
+
+Inode 14 ref count is 2, should be 1.  Fix? yes
+
+Unattached inode 15
+Connect to /lost+found? yes
+
+Inode 15 ref count is 2, should be 1.  Fix? yes
+
+Unattached inode 16
+Connect to /lost+found? yes
+
+Inode 16 ref count is 2, should be 1.  Fix? yes
+
+Unattached inode 17
+Connect to /lost+found? yes
+
+Inode 17 ref count is 2, should be 1.  Fix? yes
+
+Unattached inode 18
+Connect to /lost+found? yes
+
+Inode 18 ref count is 2, should be 1.  Fix? yes
+
+Unattached inode 19
+Connect to /lost+found? yes
+
+Inode 19 ref count is 2, should be 1.  Fix? yes
+
+Unattached inode 20
+Connect to /lost+found? yes
+
+Inode 20 ref count is 2, should be 1.  Fix? yes
+
+Unattached inode 21
+Connect to /lost+found? yes
+
+Inode 21 ref count is 2, should be 1.  Fix? yes
+
+Unattached inode 22
+Connect to /lost+found? yes
+
+Inode 22 ref count is 2, should be 1.  Fix? yes
+
+Unattached inode 23
+Connect to /lost+found? yes
+
+Inode 23 ref count is 2, should be 1.  Fix? yes
+
+Unattached inode 24
+Connect to /lost+found? yes
+
+Inode 24 ref count is 2, should be 1.  Fix? yes
+
+Unattached inode 25
+Connect to /lost+found? yes
+
+Inode 25 ref count is 2, should be 1.  Fix? yes
+
+Unattached inode 26
+Connect to /lost+found? yes
+
+Inode 26 ref count is 2, should be 1.  Fix? yes
+
+Unattached inode 27
+Connect to /lost+found? yes
+
+Inode 27 ref count is 2, should be 1.  Fix? yes
+
+Unattached inode 28
+Connect to /lost+found? yes
+
+Inode 28 ref count is 2, should be 1.  Fix? yes
+
+Unattached inode 29
+Connect to /lost+found? yes
+
+Inode 29 ref count is 2, should be 1.  Fix? yes
+
+Unattached inode 30
+Connect to /lost+found? yes
+
+Inode 30 ref count is 2, should be 1.  Fix? yes
+
+Unattached inode 31
+Connect to /lost+found? yes
+
+Inode 31 ref count is 2, should be 1.  Fix? yes
+
+Unattached inode 32
+Connect to /lost+found? yes
+
+Inode 32 ref count is 2, should be 1.  Fix? yes
+
+Unattached inode 33
+Connect to /lost+found? yes
+
+Inode 33 ref count is 2, should be 1.  Fix? yes
+
+Unattached inode 34
+Connect to /lost+found? yes
+
+Inode 34 ref count is 2, should be 1.  Fix? yes
+
+Unattached inode 35
+Connect to /lost+found? yes
+
+Inode 35 ref count is 2, should be 1.  Fix? yes
+
+Unattached inode 36
+Connect to /lost+found? yes
+
+Inode 36 ref count is 2, should be 1.  Fix? yes
+
+Unattached inode 37
+Connect to /lost+found? yes
+
+Inode 37 ref count is 2, should be 1.  Fix? yes
+
+Unattached inode 38
+Connect to /lost+found? yes
+
+Inode 38 ref count is 2, should be 1.  Fix? yes
+
+Unattached inode 39
+Connect to /lost+found? yes
+
+Inode 39 ref count is 2, should be 1.  Fix? yes
+
+Unattached inode 40
+Connect to /lost+found? yes
+
+Inode 40 ref count is 2, should be 1.  Fix? yes
+
+Unattached inode 41
+Connect to /lost+found? yes
+
+Inode 41 ref count is 2, should be 1.  Fix? yes
+
+Unattached inode 42
+Connect to /lost+found? yes
+
+Inode 42 ref count is 2, should be 1.  Fix? yes
+
+Unattached inode 43
+Connect to /lost+found? yes
+
+Inode 43 ref count is 2, should be 1.  Fix? yes
+
+Unattached inode 44
+Connect to /lost+found? yes
+
+Inode 44 ref count is 2, should be 1.  Fix? yes
+
+Unattached inode 45
+Connect to /lost+found? yes
+
+Inode 45 ref count is 2, should be 1.  Fix? yes
+
+Unattached inode 46
+Connect to /lost+found? yes
+
+Inode 46 ref count is 2, should be 1.  Fix? yes
+
+Unattached inode 47
+Connect to /lost+found? yes
+
+Inode 47 ref count is 2, should be 1.  Fix? yes
+
+Unattached inode 48
+Connect to /lost+found? yes
+
+Inode 48 ref count is 2, should be 1.  Fix? yes
+
+Unattached inode 49
+Connect to /lost+found? yes
+
+Inode 49 ref count is 2, should be 1.  Fix? yes
+
+Unattached inode 50
+Connect to /lost+found? yes
+
+Inode 50 ref count is 2, should be 1.  Fix? yes
+
+Unattached inode 51
+Connect to /lost+found? yes
+
+Inode 51 ref count is 2, should be 1.  Fix? yes
+
+Unattached inode 52
+Connect to /lost+found? yes
+
+Inode 52 ref count is 2, should be 1.  Fix? yes
+
+Unattached inode 53
+Connect to /lost+found? yes
+
+Inode 53 ref count is 2, should be 1.  Fix? yes
+
+Unattached inode 54
+Connect to /lost+found? yes
+
+Inode 54 ref count is 2, should be 1.  Fix? yes
+
+Unattached inode 55
+Connect to /lost+found? yes
+
+Inode 55 ref count is 2, should be 1.  Fix? yes
+
+Unattached inode 56
+Connect to /lost+found? yes
+
+Inode 56 ref count is 2, should be 1.  Fix? yes
+
+Unattached inode 57
+Connect to /lost+found? yes
+
+Inode 57 ref count is 2, should be 1.  Fix? yes
+
+Unattached inode 58
+Connect to /lost+found? yes
+
+Inode 58 ref count is 2, should be 1.  Fix? yes
+
+Unattached inode 59
+Connect to /lost+found? yes
+
+Inode 59 ref count is 2, should be 1.  Fix? yes
+
+Unattached inode 60
+Connect to /lost+found? yes
+
+Inode 60 ref count is 2, should be 1.  Fix? yes
+
+Unattached inode 61
+Connect to /lost+found? yes
+
+Inode 61 ref count is 2, should be 1.  Fix? yes
+
+Unattached inode 62
+Connect to /lost+found? yes
+
+Inode 62 ref count is 2, should be 1.  Fix? yes
+
+Unattached inode 63
+Connect to /lost+found? yes
+
+Inode 63 ref count is 2, should be 1.  Fix? yes
+
+Unattached inode 64
+Connect to /lost+found? yes
+
+Inode 64 ref count is 2, should be 1.  Fix? yes
+
+Unattached zero-length inode 65.  Clear? yes
+
+Unattached inode 66
+Connect to /lost+found? yes
+
+Inode 66 ref count is 2, should be 1.  Fix? yes
+
+Unattached inode 67
+Connect to /lost+found? yes
+
+Inode 67 ref count is 2, should be 1.  Fix? yes
+
+Pass 5: Checking group summary information
+
+test_filesys: ***** FILE SYSTEM WAS MODIFIED *****
+test_filesys: 67/512 files (1.5% non-contiguous), 1127/2048 blocks
+Exit status is 1
diff --git a/tests/f_rebuild_csum_rootdir/expect.2 b/tests/f_rebuild_csum_rootdir/expect.2
new file mode 100644 (file)
index 0000000..033f1bf
--- /dev/null
@@ -0,0 +1,7 @@
+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: 67/512 files (1.5% non-contiguous), 1127/2048 blocks
+Exit status is 0
diff --git a/tests/f_rebuild_csum_rootdir/image.gz b/tests/f_rebuild_csum_rootdir/image.gz
new file mode 100644 (file)
index 0000000..a32fd44
Binary files /dev/null and b/tests/f_rebuild_csum_rootdir/image.gz differ
diff --git a/tests/f_rebuild_csum_rootdir/name b/tests/f_rebuild_csum_rootdir/name
new file mode 100644 (file)
index 0000000..b246f48
--- /dev/null
@@ -0,0 +1 @@
+force fsck to rebuild a corrupted rootdir w/ metadata_csum
diff --git a/tests/f_super_bad_csum/expect.1 b/tests/f_super_bad_csum/expect.1
new file mode 100644 (file)
index 0000000..25ced5c
--- /dev/null
@@ -0,0 +1,13 @@
+ext2fs_open2: Superblock checksum does not match superblock
+../e2fsck/e2fsck: Superblock invalid, trying backup blocks...
+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
+Inode bitmap differences: Group 1 inode bitmap does not match checksum.
+FIXED.
+
+test_filesys: ***** FILE SYSTEM WAS MODIFIED *****
+test_filesys: 11/1024 files (0.0% non-contiguous), 1557/16384 blocks
+Exit status is 0
diff --git a/tests/f_super_bad_csum/expect.2 b/tests/f_super_bad_csum/expect.2
new file mode 100644 (file)
index 0000000..dd20919
--- /dev/null
@@ -0,0 +1,7 @@
+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/1024 files (0.0% non-contiguous), 1557/16384 blocks
+Exit status is 0
diff --git a/tests/f_super_bad_csum/image.bz2 b/tests/f_super_bad_csum/image.bz2
new file mode 100644 (file)
index 0000000..cd80d4b
Binary files /dev/null and b/tests/f_super_bad_csum/image.bz2 differ
diff --git a/tests/f_super_bad_csum/name b/tests/f_super_bad_csum/name
new file mode 100644 (file)
index 0000000..745562f
--- /dev/null
@@ -0,0 +1 @@
+bad csum in superblock (metadata_csum)
diff --git a/tests/f_super_bad_csum/script b/tests/f_super_bad_csum/script
new file mode 100755 (executable)
index 0000000..cfd4189
--- /dev/null
@@ -0,0 +1,33 @@
+#!/bin/bash
+
+FSCK_OPT=-fy
+IMAGE=$test_dir/image.bz2
+
+bzip2 -d < $IMAGE > $TMPFILE
+#e2label $TMPFILE test_filesys
+
+# Run fsck to fix things?
+EXP1=$test_dir/expect.1
+OUT1=$test_name.1.log
+rm -rf $test_name.failed $test_name.ok
+
+$FSCK $FSCK_OPT $TMPFILE 2>&1 | head -n 1000 | tail -n +2 > $OUT1
+echo "Exit status is $?" >> $OUT1
+
+# Run a second time
+EXP2=$test_dir/expect.2
+OUT2=$test_name.2.log
+
+$FSCK $FSCK_OPT $TMPFILE 2>&1 | head -n 1000 | tail -n +2 > $OUT2
+echo "Exit status is $?" >> $OUT2
+
+# Figure out what happened
+if cmp -s $EXP1 $OUT1 && cmp -s $EXP2 $OUT2; then
+       echo "$test_name: $test_description: ok"
+       touch $test_name.ok
+else
+       echo "$test_name: $test_description: failed"
+       diff -u $EXP1 $OUT1 >> $test_name.failed
+       diff -u $EXP2 $OUT2 >> $test_name.failed
+fi
+unset EXP1 OUT1 EXP2 OUT2 FSCK_OPT IMAGE
index 91b956b..59fad4e 100644 (file)
@@ -1,4 +1,9 @@
-/^[dbgumpe2fsckrsiz]* [1-9]\.[0-9]*[.-][^ ]* ([0-9]*-[A-Za-z]*-[0-9]*)/d
+/^debugfs [1-9]\.[0-9]*[.-][^ ]* ([0-9]*-[A-Za-z]*-[0-9]*)/d
+/^dumpe2fs [1-9]\.[0-9]*[.-][^ ]* ([0-9]*-[A-Za-z]*-[0-9]*)/d
+/^e2fsck [1-9]\.[0-9]*[.-][^ ]* ([0-9]*-[A-Za-z]*-[0-9]*)/d
+/^mke2fs [1-9]\.[0-9]*[.-][^ ]* ([0-9]*-[A-Za-z]*-[0-9]*)/d
+/^resize2fs [1-9]\.[0-9]*[.-][^ ]* ([0-9]*-[A-Za-z]*-[0-9]*)/d
+/^tune2fs [1-9]\.[0-9]*[.-][^ ]* ([0-9]*-[A-Za-z]*-[0-9]*)/d
 s/\\015//g
 /automatically checked/d
 /^Directory Hash Seed:/d
diff --git a/tests/m_mmp_bad_csum/expect b/tests/m_mmp_bad_csum/expect
new file mode 100644 (file)
index 0000000..e15e7b4
--- /dev/null
@@ -0,0 +1,9 @@
+Superblock MMP block checksum does not match MMP block.  Fix? yes
+
+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/128 files (0.0% non-contiguous), 19/512 blocks
+Exit status is 0
diff --git a/tests/m_mmp_bad_csum/image.gz b/tests/m_mmp_bad_csum/image.gz
new file mode 100644 (file)
index 0000000..c896ff6
Binary files /dev/null and b/tests/m_mmp_bad_csum/image.gz differ
diff --git a/tests/m_mmp_bad_csum/name b/tests/m_mmp_bad_csum/name
new file mode 100644 (file)
index 0000000..61c31d4
--- /dev/null
@@ -0,0 +1 @@
+mmp with bad csum (metadata_csum)
diff --git a/tests/m_mmp_bad_csum/script b/tests/m_mmp_bad_csum/script
new file mode 100644 (file)
index 0000000..d101294
--- /dev/null
@@ -0,0 +1,30 @@
+# use current directory instead of /tmp becase tmpfs doesn't support DIO
+rm -f $TMPFILE
+TMPFILE=$(mktemp ./tmp-$test_name.XXXXXX)
+
+stat -f $TMPFILE | grep -q "Type: tmpfs"
+if [ $? = 0 ]; then
+       rm -f $TMPFILE
+       echo "$test_name: $test_description: skipped for tmpfs (no O_DIRECT)"
+       return 0
+fi
+gzip -dc < $test_dir/image.gz > $TMPFILE
+
+OUT=$test_dir.log
+EXP=$test_dir/expect
+$FSCK -fy $TMPFILE 2>&1 | sed -f $cmd_dir/filter.sed > $OUT
+echo Exit status is $? >> $OUT
+
+rm -f $TMPFILE
+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
+       rm -f $test_name.tmp
+fi
+unset OUT EXP
diff --git a/tests/m_mmp_bad_magic/.log b/tests/m_mmp_bad_magic/.log
new file mode 100644 (file)
index 0000000..b5dfb89
--- /dev/null
@@ -0,0 +1,9 @@
+Superblock has invalid MMP magic.  Fix? yes
+
+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/128 files (0.0% non-contiguous), 19/512 blocks
+Exit status is 0
diff --git a/tests/m_mmp_bad_magic/expect b/tests/m_mmp_bad_magic/expect
new file mode 100644 (file)
index 0000000..b5dfb89
--- /dev/null
@@ -0,0 +1,9 @@
+Superblock has invalid MMP magic.  Fix? yes
+
+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/128 files (0.0% non-contiguous), 19/512 blocks
+Exit status is 0
diff --git a/tests/m_mmp_bad_magic/image.gz b/tests/m_mmp_bad_magic/image.gz
new file mode 100644 (file)
index 0000000..2d57fbf
Binary files /dev/null and b/tests/m_mmp_bad_magic/image.gz differ
diff --git a/tests/m_mmp_bad_magic/name b/tests/m_mmp_bad_magic/name
new file mode 100644 (file)
index 0000000..15a2d4d
--- /dev/null
@@ -0,0 +1 @@
+mmp with bad magic (metadata_csum)
diff --git a/tests/m_mmp_bad_magic/script b/tests/m_mmp_bad_magic/script
new file mode 100644 (file)
index 0000000..d101294
--- /dev/null
@@ -0,0 +1,30 @@
+# use current directory instead of /tmp becase tmpfs doesn't support DIO
+rm -f $TMPFILE
+TMPFILE=$(mktemp ./tmp-$test_name.XXXXXX)
+
+stat -f $TMPFILE | grep -q "Type: tmpfs"
+if [ $? = 0 ]; then
+       rm -f $TMPFILE
+       echo "$test_name: $test_description: skipped for tmpfs (no O_DIRECT)"
+       return 0
+fi
+gzip -dc < $test_dir/image.gz > $TMPFILE
+
+OUT=$test_dir.log
+EXP=$test_dir/expect
+$FSCK -fy $TMPFILE 2>&1 | sed -f $cmd_dir/filter.sed > $OUT
+echo Exit status is $? >> $OUT
+
+rm -f $TMPFILE
+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
+       rm -f $test_name.tmp
+fi
+unset OUT EXP
index 44d04b5..22d9417 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 9e71264..c7aa088 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
diff --git a/tests/t_mke2fs_errors/expect b/tests/t_mke2fs_errors/expect
new file mode 100644 (file)
index 0000000..78514bd
--- /dev/null
@@ -0,0 +1,24 @@
+error default
+Errors behavior:          Continue
+error continue
+Errors behavior:          Continue
+error panic
+Errors behavior:          Panic
+error remount-ro
+Errors behavior:          Remount read-only
+error garbage
+error default profile continue
+Errors behavior:          Continue
+error default profile panic
+Errors behavior:          Panic
+error default profile remount-ro
+Errors behavior:          Remount read-only
+error default profile broken
+error fs_types profile continue
+Errors behavior:          Continue
+error fs_types profile panic
+Errors behavior:          Panic
+error fs_types profile remount-ro
+Errors behavior:          Remount read-only
+error fs_types profile remount-ro
+Errors behavior:          Panic
diff --git a/tests/t_mke2fs_errors/script b/tests/t_mke2fs_errors/script
new file mode 100755 (executable)
index 0000000..d09e926
--- /dev/null
@@ -0,0 +1,110 @@
+test_description="mke2fs with error behavior"
+
+conf=$TMPFILE.conf
+write_defaults_conf()
+{
+       errors="$1"
+       cat > $conf << ENDL
+[defaults]
+       errors = $errors
+ENDL
+}
+
+write_section_conf()
+{
+       errors="$1"
+       cat > $conf << ENDL
+[defaults]
+       errors = broken
+
+[fs_types]
+       test_suite = {
+               errors = $errors
+       }
+ENDL
+}
+
+trap "rm -rf $TMPFILE $TMPFILE.conf" EXIT INT QUIT
+dd if=/dev/zero of=$TMPFILE bs=1k count=512 > /dev/null 2>&1
+OUT=$test_name.log
+EXP=$test_dir/expect
+rm -rf $OUT
+
+# Test command line option
+echo "error default" >> $OUT
+$MKE2FS -F $TMPFILE > /dev/null 2>&1
+$DUMPE2FS $TMPFILE 2>&1 | grep 'Errors behavior' >> $OUT
+
+echo "error continue" >> $OUT
+$MKE2FS -e continue -F $TMPFILE > /dev/null 2>&1
+$DUMPE2FS $TMPFILE 2>&1 | grep 'Errors behavior' >> $OUT
+
+echo "error panic" >> $OUT
+$MKE2FS -e panic -F $TMPFILE > /dev/null 2>&1
+$DUMPE2FS $TMPFILE 2>&1 | grep 'Errors behavior' >> $OUT
+
+echo "error remount-ro" >> $OUT
+$MKE2FS -e remount-ro -F $TMPFILE > /dev/null 2>&1
+$DUMPE2FS $TMPFILE 2>&1 | grep 'Errors behavior' >> $OUT
+
+echo "error garbage" >> $OUT
+dd if=/dev/zero of=$TMPFILE bs=1k count=512 > /dev/null 2>&1
+$MKE2FS -e broken -F $TMPFILE > /dev/null 2>&1
+$DUMPE2FS $TMPFILE 2>&1 | grep 'Errors behavior' >> $OUT
+
+# Test errors= in default
+echo "error default profile continue" >> $OUT
+write_defaults_conf continue
+MKE2FS_CONFIG=$conf $MKE2FS -F $TMPFILE > /dev/null 2>&1
+$DUMPE2FS $TMPFILE 2>&1 | grep 'Errors behavior' >> $OUT
+
+echo "error default profile panic" >> $OUT
+write_defaults_conf panic
+MKE2FS_CONFIG=$conf $MKE2FS -F $TMPFILE > /dev/null 2>&1
+$DUMPE2FS $TMPFILE 2>&1 | grep 'Errors behavior' >> $OUT
+
+echo "error default profile remount-ro" >> $OUT
+write_defaults_conf remount-ro
+MKE2FS_CONFIG=$conf $MKE2FS -F $TMPFILE > /dev/null 2>&1
+$DUMPE2FS $TMPFILE 2>&1 | grep 'Errors behavior' >> $OUT
+
+echo "error default profile broken" >> $OUT
+write_defaults_conf broken
+dd if=/dev/zero of=$TMPFILE bs=1k count=512 > /dev/null 2>&1
+MKE2FS_CONFIG=$conf $MKE2FS -F $TMPFILE > /dev/null 2>&1
+$DUMPE2FS $TMPFILE 2>&1 | grep 'Errors behavior' >> $OUT
+
+# Test errors= in a fs type
+echo "error fs_types profile continue" >> $OUT
+write_section_conf continue
+MKE2FS_CONFIG=$conf $MKE2FS -F $TMPFILE -T test_suite > /dev/null 2>&1
+$DUMPE2FS $TMPFILE 2>&1 | grep 'Errors behavior' >> $OUT
+
+echo "error fs_types profile panic" >> $OUT
+write_section_conf panic
+MKE2FS_CONFIG=$conf $MKE2FS -F $TMPFILE -T test_suite > /dev/null 2>&1
+$DUMPE2FS $TMPFILE 2>&1 | grep 'Errors behavior' >> $OUT
+
+echo "error fs_types profile remount-ro" >> $OUT
+write_section_conf remount-ro
+MKE2FS_CONFIG=$conf $MKE2FS -F $TMPFILE -T test_suite > /dev/null 2>&1
+$DUMPE2FS $TMPFILE 2>&1 | grep 'Errors behavior' >> $OUT
+
+# Test command line override
+echo "error fs_types profile remount-ro" >> $OUT
+write_section_conf remount-ro
+MKE2FS_CONFIG=$conf $MKE2FS -F $TMPFILE -T test_suite -e panic > /dev/null 2>&1
+$DUMPE2FS $TMPFILE 2>&1 | grep 'Errors behavior' >> $OUT
+
+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
+       rm -f $test_name.tmp
+fi
+
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 d235fff..5171c1c 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 36eaa94..5c9b142 100644 (file)
@@ -22,6 +22,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>
@@ -431,6 +434,8 @@ int main(int argc, char **argv)
        }
        if (old)
                fclose(old);
+       if (newfn)
+               free(newfn);
        return (0);
 }
 
index f38b6f3..1cdd954 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.11"
+#define E2FSPROGS_VERSION "1.43-WIP"
 #define E2FSPROGS_DATE "09-Jul-2014"