diff -Nru e2fsprogs-1.42.13/debian/changelog e2fsprogs-1.42.13/debian/changelog --- e2fsprogs-1.42.13/debian/changelog 2015-11-29 18:45:17.000000000 +0000 +++ e2fsprogs-1.42.13/debian/changelog 2015-11-30 15:01:52.000000000 +0000 @@ -1,10 +1,26 @@ -e2fsprogs (1.42.13-1ubuntu1~eugenesan~trusty2) trusty; urgency=medium +e2fsprogs (1.42.13-1ubuntu1+20151129~eugenesan~trusty1) trusty; urgency=medium - * Backport from Xenial + * Merge WIP * Update up to 20151129 (956b0f18a5ddb6815a9dff4f10a1e3125cdca9ba) + * Enable e4encrypt (http://askubuntu.com/questions/643577/how-to-create-ext4-encrypted-partition-on-ubuntu-15-04-with-new-4-1-kernel) -- Eugene San (eugenesan) Sun, 29 Nov 2015 09:47:21 -0500 +e2fsprogs (1.43~WIP-2015-05-18-1) unstable; urgency=low + + * Merge in updates from the maint branch (changes from 1.42.13) + * Add support for file encryption feature + * Mke2fs will now create file systems with metadata_csum and 64bit + enabled by default. + * The resize2fs command can now convert file systems between 64-bit + and 32-bit mode. + * The new undo file format is much faster/efficent than before + * E2fsck now has readahead support to speed up its behavior on RAID + arrays. + * E2fsck can now rebuild/optimize inode extent trees + + -- Theodore Y. Ts'o Mon, 18 May 2015 01:47:43 -0400 + e2fsprogs (1.42.13-1ubuntu1) xenial; urgency=medium * Merge from Debian unstable. Remaining changes: diff -Nru e2fsprogs-1.42.13/debian/e2fslibs.symbols e2fsprogs-1.42.13/debian/e2fslibs.symbols --- e2fsprogs-1.42.13/debian/e2fslibs.symbols 2014-12-27 04:25:56.000000000 +0000 +++ e2fsprogs-1.42.13/debian/e2fslibs.symbols 2015-11-30 14:58:25.000000000 +0000 @@ -2,6 +2,7 @@ e2p_edit_feature2@Base 1.40.7 e2p_edit_feature@Base 1.37 e2p_edit_mntopts@Base 1.37 + e2p_encmode2string@Base 1.43~WIP-2015-05-18 e2p_feature2string@Base 1.37 e2p_hash2string@Base 1.37 e2p_is_null_uuid@Base 1.37 @@ -10,6 +11,7 @@ e2p_mntopt2string@Base 1.37 e2p_os2string@Base 1.37 e2p_percent@Base 1.40 + e2p_string2encmode@Base 1.43~WIP-2015-05-18 e2p_string2feature@Base 1.37 e2p_string2hash@Base 1.37 e2p_string2mntopt@Base 1.37 @@ -43,14 +45,17 @@ et_ext2_error_table@Base 1.37 ext2fs_add_dir_block2@Base 1.42 ext2fs_add_dir_block@Base 1.37 + ext2fs_add_exit_fn@Base 1.43~WIP-2015-05-18 ext2fs_add_journal_device@Base 1.37 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 ext2fs_alloc_generic_bmap@Base 1.42 + ext2fs_alloc_range@Base 1.43~WIP-2015-05-18 ext2fs_allocate_block_bitmap@Base 1.37 ext2fs_allocate_generic_bitmap@Base 1.37 ext2fs_allocate_group_table@Base 1.37 @@ -89,6 +94,9 @@ ext2fs_block_alloc_stats2@Base 1.42 ext2fs_block_alloc_stats@Base 1.37 ext2fs_block_alloc_stats_range@Base 1.42.9-3~ + ext2fs_block_bitmap_checksum@Base 1.43~WIP-2012-08-01 + ext2fs_block_bitmap_csum_set@Base 1.43~WIP-2012-08-01 + ext2fs_block_bitmap_csum_verify@Base 1.43~WIP-2012-08-01 ext2fs_block_bitmap_loc@Base 1.42 ext2fs_block_bitmap_loc_set@Base 1.42 ext2fs_block_iterate2@Base 1.37 @@ -123,11 +131,12 @@ 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 ext2fs_crc32c_le@Base 1.42 ext2fs_create_icount2@Base 1.37 ext2fs_create_icount@Base 1.37 ext2fs_create_icount_tdb@Base 1.40 + ext2fs_create_inode_cache@Base 1.43~WIP-2015-05-18 ext2fs_create_journal_superblock@Base 1.37 ext2fs_create_resize_inode@Base 1.37 ext2fs_dblist_count2@Base 1.42 @@ -137,20 +146,33 @@ ext2fs_dblist_get_last2@Base 1.42 ext2fs_dblist_get_last@Base 1.40.8 ext2fs_dblist_iterate2@Base 1.42 + ext2fs_dblist_iterate3@Base 1.43~WIP-2015-05-18 ext2fs_dblist_iterate@Base 1.37 ext2fs_dblist_sort2@Base 1.42 ext2fs_dblist_sort@Base 1.37 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_file_type@Base 1.43~WIP-2015-05-18 + ext2fs_dirent_has_tail@Base 1.43~WIP-2012-08-01 + ext2fs_dirent_name_len@Base 1.43~WIP-2015-05-18 + ext2fs_dirent_set_file_type@Base 1.43~WIP-2015-05-18 + ext2fs_dirent_set_name_len@Base 1.43~WIP-2015-05-18 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 @@ -214,6 +236,7 @@ ext2fs_find_first_zero_generic_bitmap@Base 1.42.3 ext2fs_find_first_zero_generic_bmap@Base 1.42.2 ext2fs_find_first_zero_inode_bitmap2@Base 1.42.2 + ext2fs_find_inode_goal@Base 1.43~WIP-2015-05-18 ext2fs_flush2@Base 1.42 ext2fs_flush@Base 1.37 ext2fs_flush_icache@Base 1.37 @@ -224,10 +247,12 @@ ext2fs_free_blocks_count_add@Base 1.42 ext2fs_free_blocks_count_set@Base 1.42 ext2fs_free_dblist@Base 1.37 + ext2fs_free_ext_attr@Base 1.43~WIP-2015-05-18 ext2fs_free_generic_bitmap@Base 1.37 ext2fs_free_generic_bmap@Base 1.42 ext2fs_free_icount@Base 1.37 ext2fs_free_inode_bitmap@Base 1.37 + ext2fs_free_inode_cache@Base 1.43~WIP-2015-05-18 ext2fs_free_mem@Base 1.37 ext2fs_fstat@Base 1.42 ext2fs_fudge_block_bitmap_end2@Base 1.42 @@ -251,6 +276,7 @@ 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 +327,26 @@ 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_inline_data_dir_iterate@Base 1.43~WIP-2015-05-18 + ext2fs_inline_data_ea_remove@Base 1.43~WIP-2015-05-18 + ext2fs_inline_data_expand@Base 1.43~WIP-2015-05-18 + ext2fs_inline_data_get@Base 1.43~WIP-2015-05-18 + ext2fs_inline_data_init@Base 1.43~WIP-2015-05-18 + ext2fs_inline_data_set@Base 1.43~WIP-2015-05-18 + ext2fs_inline_data_size@Base 1.43~WIP-2015-05-18 ext2fs_inode_alloc_stats2@Base 1.37 ext2fs_inode_alloc_stats@Base 1.37 + ext2fs_inode_bitmap_checksum@Base 1.43~WIP-2012-08-01 + ext2fs_inode_bitmap_csum_set@Base 1.43~WIP-2012-08-01 + ext2fs_inode_bitmap_csum_verify@Base 1.43~WIP-2012-08-01 ext2fs_inode_bitmap_loc@Base 1.42 ext2fs_inode_bitmap_loc_set@Base 1.42 + ext2fs_inode_csum_set@Base 1.43~WIP-2012-08-01 + ext2fs_inode_csum_verify@Base 1.43~WIP-2012-08-01 ext2fs_inode_data_blocks2@Base 1.42 ext2fs_inode_data_blocks@Base 1.37 ext2fs_inode_has_valid_blocks2@Base 1.42 @@ -338,14 +378,18 @@ ext2fs_mark_inode_bitmap@Base 1.37 ext2fs_mark_super_dirty@Base 1.37 ext2fs_mark_valid@Base 1.37 + ext2fs_max_extent_depth@Base 1.43~WIP-2015-05-18 ext2fs_mem_is_zero@Base 1.42 ext2fs_mkdir@Base 1.37 ext2fs_mmp_clear@Base 1.42 + ext2fs_mmp_csum_set@Base 1.43~WIP-2012-08-01 + ext2fs_mmp_csum_verify@Base 1.43~WIP-2012-08-01 ext2fs_mmp_init@Base 1.42 ext2fs_mmp_new_seq@Base 1.42 ext2fs_mmp_read@Base 1.42 ext2fs_mmp_start@Base 1.42 ext2fs_mmp_stop@Base 1.42 + ext2fs_mmp_update2@Base 1.43~WIP-2012-08-01 ext2fs_mmp_update@Base 1.42 ext2fs_mmp_write@Base 1.42 ext2fs_namei@Base 1.37 @@ -354,9 +398,12 @@ ext2fs_new_block2@Base 1.42 ext2fs_new_block@Base 1.37 ext2fs_new_dir_block@Base 1.37 + ext2fs_new_dir_inline_data@Base 1.43~WIP-2015-05-18 ext2fs_new_inode@Base 1.37 + ext2fs_new_range@Base 1.43~WIP-2015-05-18 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 @@ -385,13 +432,16 @@ 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 ext2fs_read_inode_bitmap@Base 1.37 ext2fs_read_inode_full@Base 1.37 + ext2fs_remove_exit_fn@Base 1.43~WIP-2015-05-18 ext2fs_reserve_super_and_bgd@Base 1.37 ext2fs_resize_block_bitmap2@Base 1.42 ext2fs_resize_block_bitmap@Base 1.37 @@ -420,9 +470,12 @@ ext2fs_set_inode_bitmap_range@Base 1.41.0 ext2fs_set_inode_callback@Base 1.37 ext2fs_set_rec_len@Base 1.41.7 + ext2fs_sha512@Base 1.43~WIP-2015-05-18 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 @@ -446,6 +499,7 @@ ext2fs_tdb_fd@Base 1.40 ext2fs_tdb_fetch@Base 1.40 ext2fs_tdb_firstkey@Base 1.40 + ext2fs_tdb_flush@Base 1.43~WIP-2015-05-18 ext2fs_tdb_get_flags@Base 1.40 ext2fs_tdb_get_logging_private@Base 1.40 ext2fs_tdb_get_seqnum@Base 1.40 @@ -519,6 +573,7 @@ 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 @@ -527,25 +582,39 @@ 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 ext2fs_write_inode_bitmap@Base 1.37 ext2fs_write_inode_full@Base 1.37 ext2fs_write_new_inode@Base 1.37 + ext2fs_xattr_get@Base 1.43~WIP-2015-05-18 + ext2fs_xattr_inode_max_size@Base 1.43~WIP-2015-05-18 + ext2fs_xattr_remove@Base 1.43~WIP-2015-05-18 + ext2fs_xattr_set@Base 1.43~WIP-2015-05-18 + ext2fs_xattrs_close@Base 1.43~WIP-2015-05-18 + ext2fs_xattrs_count@Base 1.43~WIP-2015-05-18 + ext2fs_xattrs_iterate@Base 1.43~WIP-2015-05-18 + ext2fs_xattrs_open@Base 1.43~WIP-2015-05-18 + ext2fs_xattrs_read@Base 1.43~WIP-2015-05-18 + ext2fs_xattrs_write@Base 1.43~WIP-2015-05-18 ext2fs_zero_blocks2@Base 1.42 ext2fs_zero_blocks@Base 1.41.0 initialize_ext2_error_table@Base 1.37 initialize_ext2_error_table_r@Base 1.37 inode_io_manager@Base 1.37 io_channel_alloc_buf@Base 1.42.3 + io_channel_cache_readahead@Base 1.43~WIP-2015-05-18 io_channel_discard@Base 1.42 io_channel_read_blk64@Base 1.41.1 io_channel_set_options@Base 1.37 io_channel_write_blk64@Base 1.41.1 io_channel_write_byte@Base 1.37 + io_channel_zeroout@Base 1.43~WIP-2015-05-18 qcow2_read_header@Base 1.42 qcow2_write_raw_image@Base 1.42 set_undo_io_backing_manager@Base 1.41.0 diff -Nru e2fsprogs-1.42.13/debian/patches/01-20151129.patch e2fsprogs-1.42.13/debian/patches/01-20151129.patch --- e2fsprogs-1.42.13/debian/patches/01-20151129.patch 1970-01-01 00:00:00.000000000 +0000 +++ e2fsprogs-1.42.13/debian/patches/01-20151129.patch 2015-11-30 15:00:15.000000000 +0000 @@ -0,0 +1,81354 @@ +--- /dev/null ++++ b/Android.mk +@@ -0,0 +1 @@ ++include $(call all-subdir-makefiles) +--- /dev/null ++++ b/CleanSpec.mk +@@ -0,0 +1,51 @@ ++# Copyright (C) 2007 The Android Open Source Project ++# ++# Licensed under the Apache License, Version 2.0 (the "License"); ++# you may not use this file except in compliance with the License. ++# You may obtain a copy of the License at ++# ++# http://www.apache.org/licenses/LICENSE-2.0 ++# ++# Unless required by applicable law or agreed to in writing, software ++# distributed under the License is distributed on an "AS IS" BASIS, ++# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++# See the License for the specific language governing permissions and ++# limitations under the License. ++# ++ ++# If you don't need to do a full clean build but would like to touch ++# a file or delete some intermediate files, add a clean step to the end ++# of the list. These steps will only be run once, if they haven't been ++# run before. ++# ++# E.g.: ++# $(call add-clean-step, touch -c external/sqlite/sqlite3.h) ++# $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libz_intermediates) ++# ++# Always use "touch -c" and "rm -f" or "rm -rf" to gracefully deal with ++# files that are missing or have been moved. ++# ++# Use $(PRODUCT_OUT) to get to the "out/target/product/blah/" directory. ++# Use $(OUT_DIR) to refer to the "out" directory. ++# ++# If you need to re-do something that's already mentioned, just copy ++# the command and add it to the bottom of the list. E.g., if a change ++# that you made last week required touching a file and a change you ++# made today requires touching the same file, just copy the old ++# touch step and add it to the end of the list. ++# ++# ************************************************ ++# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST ++# ************************************************ ++ ++# For example: ++#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/AndroidTests_intermediates) ++#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/core_intermediates) ++#$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f) ++#$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*) ++ ++# ************************************************ ++# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST ++# ************************************************ ++ ++$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libext2_uuid_intermediates) +--- a/config/config.guess ++++ b/config/config.guess +@@ -1,8 +1,8 @@ + #! /bin/sh + # Attempt to guess a canonical system name. +-# Copyright 1992-2014 Free Software Foundation, Inc. ++# Copyright 1992-2015 Free Software Foundation, Inc. + +-timestamp='2014-03-23' ++timestamp='2015-03-04' + + # This file is free software; you can redistribute it and/or modify it + # under the terms of the GNU General Public License as published by +@@ -24,12 +24,12 @@ + # program. This Exception is an additional permission under section 7 + # of the GNU General Public License, version 3 ("GPLv3"). + # +-# Originally written by Per Bothner. ++# Originally written by Per Bothner; maintained since 2000 by Ben Elliston. + # + # You can get the latest version of this script from: + # http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD + # +-# Please send patches with a ChangeLog entry to config-patches@gnu.org. ++# Please send patches to . + + + me=`echo "$0" | sed -e 's,.*/,,'` +@@ -50,7 +50,7 @@ + GNU config.guess ($timestamp) + + Originally written by Per Bothner. +-Copyright 1992-2014 Free Software Foundation, Inc. ++Copyright 1992-2015 Free Software Foundation, Inc. + + This is free software; see the source for copying conditions. There is NO + warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." +@@ -168,20 +168,27 @@ + # Note: NetBSD doesn't particularly care about the vendor + # portion of the name. We always set it to "unknown". + sysctl="sysctl -n hw.machine_arch" +- UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ +- /usr/sbin/$sysctl 2>/dev/null || echo unknown)` ++ UNAME_MACHINE_ARCH=`(uname -p 2>/dev/null || \ ++ /sbin/$sysctl 2>/dev/null || \ ++ /usr/sbin/$sysctl 2>/dev/null || \ ++ echo unknown)` + case "${UNAME_MACHINE_ARCH}" in + armeb) machine=armeb-unknown ;; + arm*) machine=arm-unknown ;; + sh3el) machine=shl-unknown ;; + sh3eb) machine=sh-unknown ;; + sh5el) machine=sh5le-unknown ;; ++ earmv*) ++ arch=`echo ${UNAME_MACHINE_ARCH} | sed -e 's,^e\(armv[0-9]\).*$,\1,'` ++ endian=`echo ${UNAME_MACHINE_ARCH} | sed -ne 's,^.*\(eb\)$,\1,p'` ++ machine=${arch}${endian}-unknown ++ ;; + *) machine=${UNAME_MACHINE_ARCH}-unknown ;; + esac + # The Operating System including object format, if it has switched + # to ELF recently, or will in the future. + case "${UNAME_MACHINE_ARCH}" in +- arm*|i386|m68k|ns32k|sh3*|sparc|vax) ++ arm*|earm*|i386|m68k|ns32k|sh3*|sparc|vax) + eval $set_cc_for_build + if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ELF__ +@@ -197,6 +204,13 @@ + os=netbsd + ;; + esac ++ # Determine ABI tags. ++ case "${UNAME_MACHINE_ARCH}" in ++ earm*) ++ expr='s/^earmv[0-9]/-eabi/;s/eb$//' ++ abi=`echo ${UNAME_MACHINE_ARCH} | sed -e "$expr"` ++ ;; ++ esac + # The OS release + # Debian GNU/NetBSD machines have a different userland, and + # thus, need a distinct triplet. However, they do not need +@@ -213,7 +227,7 @@ + # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: + # contains redundant information, the shorter form: + # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. +- echo "${machine}-${os}${release}" ++ echo "${machine}-${os}${release}${abi}" + exit ;; + *:Bitrig:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'` +@@ -579,8 +593,9 @@ + else + IBM_ARCH=powerpc + fi +- if [ -x /usr/bin/oslevel ] ; then +- IBM_REV=`/usr/bin/oslevel` ++ if [ -x /usr/bin/lslpp ] ; then ++ IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc | ++ awk -F: '{ print $3 }' | sed s/[0-9]*$/0/` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi +@@ -932,6 +947,9 @@ + crisv32:Linux:*:*) + echo ${UNAME_MACHINE}-axis-linux-${LIBC} + exit ;; ++ e2k:Linux:*:*) ++ echo ${UNAME_MACHINE}-unknown-linux-${LIBC} ++ exit ;; + frv:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; +--- a/config/config.rpath ++++ b/config/config.rpath +@@ -2,7 +2,7 @@ + # Output a system dependent set of variables, describing how to set the + # run time search path of shared libraries in an executable. + # +-# Copyright 1996-2013 Free Software Foundation, Inc. ++# Copyright 1996-2014 Free Software Foundation, Inc. + # Taken from GNU libtool, 2001 + # Originally by Gordon Matzigkeit , 1996 + # +@@ -367,11 +367,7 @@ + dgux*) + hardcode_libdir_flag_spec='-L$libdir' + ;; +- freebsd2.2*) +- hardcode_libdir_flag_spec='-R$libdir' +- hardcode_direct=yes +- ;; +- freebsd2*) ++ freebsd2.[01]*) + hardcode_direct=yes + hardcode_minus_L=yes + ;; +@@ -548,13 +544,11 @@ + dgux*) + library_names_spec='$libname$shrext' + ;; ++ freebsd[23].*) ++ library_names_spec='$libname$shrext$versuffix' ++ ;; + freebsd* | dragonfly*) +- case "$host_os" in +- freebsd[123]*) +- library_names_spec='$libname$shrext$versuffix' ;; +- *) +- library_names_spec='$libname$shrext' ;; +- esac ++ library_names_spec='$libname$shrext' + ;; + gnu*) + library_names_spec='$libname$shrext' +--- a/config/config.sub ++++ b/config/config.sub +@@ -1,8 +1,8 @@ + #! /bin/sh + # Configuration validation subroutine script. +-# Copyright 1992-2014 Free Software Foundation, Inc. ++# Copyright 1992-2015 Free Software Foundation, Inc. + +-timestamp='2014-05-01' ++timestamp='2015-03-08' + + # This file is free software; you can redistribute it and/or modify it + # under the terms of the GNU General Public License as published by +@@ -25,7 +25,7 @@ + # of the GNU General Public License, version 3 ("GPLv3"). + + +-# Please send patches with a ChangeLog entry to config-patches@gnu.org. ++# Please send patches to . + # + # Configuration subroutine to validate and canonicalize a configuration type. + # Supply the specified configuration type as an argument. +@@ -68,7 +68,7 @@ + version="\ + GNU config.sub ($timestamp) + +-Copyright 1992-2014 Free Software Foundation, Inc. ++Copyright 1992-2015 Free Software Foundation, Inc. + + This is free software; see the source for copying conditions. There is NO + warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." +@@ -117,7 +117,7 @@ + case $maybe_os in + nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \ + linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \ +- knetbsd*-gnu* | netbsd*-gnu* | \ ++ knetbsd*-gnu* | netbsd*-gnu* | netbsd*-eabi* | \ + kopensolaris*-gnu* | \ + storm-chaos* | os2-emx* | rtmk-nova*) + os=-$maybe_os +@@ -259,8 +259,8 @@ + | bfin \ + | c4x | c8051 | clipper \ + | d10v | d30v | dlx | dsp16xx \ +- | epiphany \ +- | fido | fr30 | frv \ ++ | e2k | epiphany \ ++ | fido | fr30 | frv | ft32 \ + | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ + | hexagon \ + | i370 | i860 | i960 | ia64 \ +@@ -302,6 +302,7 @@ + | pdp10 | pdp11 | pj | pjl \ + | powerpc | powerpc64 | powerpc64le | powerpcle \ + | pyramid \ ++ | riscv32 | riscv64 \ + | rl78 | rx \ + | score \ + | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ +@@ -312,6 +313,7 @@ + | tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \ + | ubicom32 \ + | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \ ++ | visium \ + | we32k \ + | x86 | xc16x | xstormy16 | xtensa \ + | z8k | z80) +@@ -326,6 +328,9 @@ + c6x) + basic_machine=tic6x-unknown + ;; ++ leon|leon[3-9]) ++ basic_machine=sparc-$basic_machine ++ ;; + m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | nvptx | picochip) + basic_machine=$basic_machine-unknown + os=-none +@@ -376,7 +381,7 @@ + | c[123]* | c30-* | [cjt]90-* | c4x-* \ + | c8051-* | clipper-* | craynv-* | cydra-* \ + | d10v-* | d30v-* | dlx-* \ +- | elxsi-* \ ++ | e2k-* | elxsi-* \ + | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ + | h8300-* | h8500-* \ + | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ +@@ -436,6 +441,7 @@ + | ubicom32-* \ + | v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \ + | vax-* \ ++ | visium-* \ + | we32k-* \ + | x86-* | x86_64-* | xc16x-* | xps100-* \ + | xstormy16-* | xtensa*-* \ +@@ -512,6 +518,9 @@ + basic_machine=i386-pc + os=-aros + ;; ++ asmjs) ++ basic_machine=asmjs-unknown ++ ;; + aux) + basic_machine=m68k-apple + os=-aux +@@ -773,6 +782,9 @@ + basic_machine=m68k-isi + os=-sysv + ;; ++ leon-*|leon[3-9]-*) ++ basic_machine=sparc-`echo $basic_machine | sed 's/-.*//'` ++ ;; + m68knommu) + basic_machine=m68k-unknown + os=-linux +@@ -828,6 +840,10 @@ + basic_machine=powerpc-unknown + os=-morphos + ;; ++ moxiebox) ++ basic_machine=moxie-unknown ++ os=-moxiebox ++ ;; + msdos) + basic_machine=i386-pc + os=-msdos +@@ -1360,7 +1376,7 @@ + | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \ + | -sym* | -kopensolaris* | -plan9* \ + | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ +- | -aos* | -aros* \ ++ | -aos* | -aros* | -cloudabi* \ + | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ + | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ + | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ +@@ -1373,7 +1389,7 @@ + | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ + | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \ + | -linux-newlib* | -linux-musl* | -linux-uclibc* \ +- | -uxpv* | -beos* | -mpeix* | -udk* \ ++ | -uxpv* | -beos* | -mpeix* | -udk* | -moxiebox* \ + | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ + | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ + | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ +--- a/configure ++++ b/configure +@@ -643,6 +643,9 @@ + LINUX_CMT + UNI_DIFF_OPTS + SEM_INIT_LIB ++FUSE_CMT ++FUSE_LIB ++MAGIC_LIB + SOCKET_LIB + SIZEOF_OFF_T + SIZEOF_LONG_LONG +@@ -733,14 +736,6 @@ + RESIZER_CMT + IMAGER_CMT + DEBUGFS_CMT +-QUOTA_CMT +-DEPPROFILED_LIBQUOTA +-PROFILED_LIBQUOTA +-DEPSTATIC_LIBQUOTA +-STATIC_LIBQUOTA +-DEPLIBQUOTA +-LIBQUOTA +-QUOTA_MAN_COMMENT + BLKID_CMT + DEPPROFILED_LIBBLKID + PROFILED_LIBBLKID +@@ -767,7 +762,6 @@ + PROFILE_CMT + BSDLIB_CMT + ELF_CMT +-HTREE_CMT + Q + ES + E +@@ -858,8 +852,6 @@ + enable_symlink_relative_symlinks + enable_symlink_build + enable_verbose_makecmds +-enable_compression +-enable_htree + enable_elf_shlibs + enable_bsd_shlibs + enable_profile +@@ -869,7 +861,6 @@ + enable_testio_debug + enable_libuuid + enable_libblkid +-enable_quota + enable_backtrace + enable_debugfs + enable_imager +@@ -879,6 +870,9 @@ + enable_e2initrd_helper + enable_tls + enable_uuidd ++enable_mmp ++enable_bmap_stats ++enable_bmap_stats_ops + enable_nls + enable_threads + with_gnu_ld +@@ -887,6 +881,7 @@ + with_libiconv_prefix + with_included_gettext + with_libintl_prefix ++enable_fuse2fs + with_multiarch + ' + ac_precious_vars='build_alias +@@ -1518,8 +1513,6 @@ + + --enable-symlink-build use symlinks while building instead of hard links + --enable-verbose-makecmds enable verbose make command output +- --enable-compression enable EXPERIMENTAL compression support +- --enable-htree enable EXPERIMENTAL htree directory support + --enable-elf-shlibs select ELF shared libraries + --enable-bsd-shlibs select BSD shared libraries + --enable-profile build profiling libraries +@@ -1527,9 +1520,8 @@ + --enable-jbd-debug enable journal debugging + --enable-blkid-debug enable blkid debugging + --disable-testio-debug disable the use of the test I/O manager for debugging +- --disable-libuuid do not build private uuid library +- --disable-libblkid do not build private blkid library +- --enable-quota enable quota support ++ --enable-libuuid build and use private uuid library ++ --enable-libblkid build and use private blkid library + --disable-backtrace disable use backtrace + --disable-debugfs disable support of debugfs program + --disable-imager disable support of e2image program +@@ -1539,11 +1531,15 @@ + --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 + --disable-threads build without multithread safety + --disable-rpath do not hardcode runtime library paths ++ --disable-fuse2fs do not build fuse2fs + + Optional Packages: + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] +@@ -4895,54 +4891,6 @@ + + + +-# Check whether --enable-compression was given. +-if test "${enable_compression+set}" = set; then : +- enableval=$enable_compression; if test "$enableval" = "no" +-then +- { $as_echo "$as_me:${as_lineno-$LINENO}: result: Disabling compression support" >&5 +-$as_echo "Disabling compression support" >&6; } +-else +- +-$as_echo "#define ENABLE_COMPRESSION 1" >>confdefs.h +- +- { $as_echo "$as_me:${as_lineno-$LINENO}: result: Enabling compression support" >&5 +-$as_echo "Enabling compression support" >&6; } +- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Compression support is experimental" >&5 +-$as_echo "$as_me: WARNING: Compression support is experimental" >&2;} +-fi +- +-else +- { $as_echo "$as_me:${as_lineno-$LINENO}: result: Disabling compression support by default" >&5 +-$as_echo "Disabling compression support by default" >&6; } +- +-fi +- +- +-# Check whether --enable-htree was given. +-if test "${enable_htree+set}" = set; then : +- enableval=$enable_htree; if test "$enableval" = "no" +-then +- HTREE_CMT=# +- { $as_echo "$as_me:${as_lineno-$LINENO}: result: Disabling htree directory support" >&5 +-$as_echo "Disabling htree directory support" >&6; } +-else +- HTREE_CMT= +- $as_echo "#define ENABLE_HTREE 1" >>confdefs.h +- +- { $as_echo "$as_me:${as_lineno-$LINENO}: result: Enabling htree directory support" >&5 +-$as_echo "Enabling htree directory support" >&6; } +-fi +- +-else +- HTREE_CMT= +-$as_echo "#define ENABLE_HTREE 1" >>confdefs.h +- +-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: Enabling htree directory support by default" >&5 +-$as_echo "Enabling htree directory support by default" >&6; } +- +-fi +- +- + E2_PKG_CONFIG_STATIC=--static + LDFLAG_DYNAMIC= + PRIVATE_LIBS_CMT= +@@ -5318,14 +5266,64 @@ + fi + + else +- LIBUUID='$(LIB)/libuuid'$LIB_EXT +-DEPLIBUUID=$LIBUUID +-STATIC_LIBUUID='$(LIB)/libuuid'$STATIC_LIB_EXT +-DEPSTATIC_LIBUUID=$STATIC_LIBUUID +-PROFILED_LIBUUID='$(LIB)/libuuid'$PROFILED_LIB_EXT +-DEPPROFILED_LIBUUID=$PROFILED_LIBUUID +-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: Enabling private uuid library by default" >&5 ++ if test -n "$PKG_CONFIG"; then ++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for uuid_generate in -luuid" >&5 ++$as_echo_n "checking for uuid_generate in -luuid... " >&6; } ++if ${ac_cv_lib_uuid_uuid_generate+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ ac_check_lib_save_LIBS=$LIBS ++LIBS="-luuid $LIBS" ++cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++/* end confdefs.h. */ ++ ++/* Override any GCC internal prototype to avoid an error. ++ Use char because int might match the return type of a GCC ++ builtin and then its argument prototype would still apply. */ ++#ifdef __cplusplus ++extern "C" ++#endif ++char uuid_generate (); ++int ++main () ++{ ++return uuid_generate (); ++ ; ++ return 0; ++} ++_ACEOF ++if ac_fn_c_try_link "$LINENO"; then : ++ ac_cv_lib_uuid_uuid_generate=yes ++else ++ ac_cv_lib_uuid_uuid_generate=no ++fi ++rm -f core conftest.err conftest.$ac_objext \ ++ conftest$ac_exeext conftest.$ac_ext ++LIBS=$ac_check_lib_save_LIBS ++fi ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_uuid_uuid_generate" >&5 ++$as_echo "$ac_cv_lib_uuid_uuid_generate" >&6; } ++if test "x$ac_cv_lib_uuid_uuid_generate" = xyes; then : ++ LIBUUID=`$PKG_CONFIG --libs uuid`; ++ STATIC_LIBUUID=`$PKG_CONFIG --static --libs uuid` ++fi ++ ++fi ++if test -n "$LIBUUID"; then ++ PROFILED_LIBUUID=$LIBUUID ++ UUID_CMT=# ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: Using system uuid by default" >&5 ++$as_echo "Using system uuid by default" >&6; } ++else ++ LIBUUID='$(LIB)/libuuid'$LIB_EXT ++ DEPLIBUUID=$LIBUUID ++ STATIC_LIBUUID='$(LIB)/libuuid'$STATIC_LIB_EXT ++ DEPSTATIC_LIBUUID=$STATIC_LIBUUID ++ PROFILED_LIBUUID='$(LIB)/libuuid'$PROFILED_LIB_EXT ++ DEPPROFILED_LIBUUID=$PROFILED_LIBUUID ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: Enabling private uuid library by default" >&5 + $as_echo "Enabling private uuid library by default" >&6; } ++fi + + fi + +@@ -5533,180 +5531,69 @@ + fi + + else +- LIBBLKID='$(LIB)/libblkid'$LIB_EXT +-DEPLIBBLKID=$LIBBLKID +-STATIC_LIBBLKID='$(LIB)/libblkid'$STATIC_LIB_EXT +-DEPSTATIC_LIBBLKID=$STATIC_LIBBLKID +-PROFILED_LIBBLKID='$(LIB)/libblkid'$PROFILED_LIB_EXT +-DEPPROFILED_LIBBLKID=$PROFILED_LIBBLKID +-$as_echo "#define CONFIG_BUILD_FINDFS 1" >>confdefs.h +- +-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: Enabling private blkid library by default" >&5 +-$as_echo "Enabling private blkid library by default" >&6; } +- +-fi +- +- +- +- +- +- +- +- +-QUOTA_MAN_COMMENT='.\"' +-QUOTA_CMT= +- +- +- +- +- +- +- +- +-if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then +- if test -n "$ac_tool_prefix"; then +- # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args. +-set dummy ${ac_tool_prefix}pkg-config; ac_word=$2 +-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +-$as_echo_n "checking for $ac_word... " >&6; } +-if ${ac_cv_path_PKG_CONFIG+:} false; then : ++ if test -n "$PKG_CONFIG"; then ++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for blkid_get_cache in -lblkid" >&5 ++$as_echo_n "checking for blkid_get_cache in -lblkid... " >&6; } ++if ${ac_cv_lib_blkid_blkid_get_cache+:} false; then : + $as_echo_n "(cached) " >&6 + else +- case $PKG_CONFIG in +- [\\/]* | ?:[\\/]*) +- ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path. +- ;; +- *) +- as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +-for as_dir in $PATH +-do +- IFS=$as_save_IFS +- test -z "$as_dir" && as_dir=. +- for ac_exec_ext in '' $ac_executable_extensions; do +- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then +- ac_cv_path_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext" +- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 +- break 2 +- fi +-done +- done +-IFS=$as_save_IFS +- +- ;; +-esac +-fi +-PKG_CONFIG=$ac_cv_path_PKG_CONFIG +-if test -n "$PKG_CONFIG"; then +- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5 +-$as_echo "$PKG_CONFIG" >&6; } +-else +- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +-$as_echo "no" >&6; } +-fi +- ++ ac_check_lib_save_LIBS=$LIBS ++LIBS="-lblkid $LIBS" ++cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++/* end confdefs.h. */ + +-fi +-if test -z "$ac_cv_path_PKG_CONFIG"; then +- ac_pt_PKG_CONFIG=$PKG_CONFIG +- # Extract the first word of "pkg-config", so it can be a program name with args. +-set dummy pkg-config; ac_word=$2 +-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +-$as_echo_n "checking for $ac_word... " >&6; } +-if ${ac_cv_path_ac_pt_PKG_CONFIG+:} false; then : +- $as_echo_n "(cached) " >&6 ++/* Override any GCC internal prototype to avoid an error. ++ Use char because int might match the return type of a GCC ++ builtin and then its argument prototype would still apply. */ ++#ifdef __cplusplus ++extern "C" ++#endif ++char blkid_get_cache (); ++int ++main () ++{ ++return blkid_get_cache (); ++ ; ++ return 0; ++} ++_ACEOF ++if ac_fn_c_try_link "$LINENO"; then : ++ ac_cv_lib_blkid_blkid_get_cache=yes + else +- case $ac_pt_PKG_CONFIG in +- [\\/]* | ?:[\\/]*) +- ac_cv_path_ac_pt_PKG_CONFIG="$ac_pt_PKG_CONFIG" # Let the user override the test with a path. +- ;; +- *) +- as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +-for as_dir in $PATH +-do +- IFS=$as_save_IFS +- test -z "$as_dir" && as_dir=. +- for ac_exec_ext in '' $ac_executable_extensions; do +- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then +- ac_cv_path_ac_pt_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext" +- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 +- break 2 +- fi +-done +- done +-IFS=$as_save_IFS +- +- ;; +-esac ++ ac_cv_lib_blkid_blkid_get_cache=no + fi +-ac_pt_PKG_CONFIG=$ac_cv_path_ac_pt_PKG_CONFIG +-if test -n "$ac_pt_PKG_CONFIG"; then +- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKG_CONFIG" >&5 +-$as_echo "$ac_pt_PKG_CONFIG" >&6; } +-else +- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +-$as_echo "no" >&6; } ++rm -f core conftest.err conftest.$ac_objext \ ++ conftest$ac_exeext conftest.$ac_ext ++LIBS=$ac_check_lib_save_LIBS + fi +- +- if test "x$ac_pt_PKG_CONFIG" = x; then +- PKG_CONFIG="" +- else +- case $cross_compiling:$ac_tool_warned in +-yes:) +-{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +-$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +-ac_tool_warned=yes ;; +-esac +- PKG_CONFIG=$ac_pt_PKG_CONFIG +- fi +-else +- PKG_CONFIG="$ac_cv_path_PKG_CONFIG" ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_blkid_blkid_get_cache" >&5 ++$as_echo "$ac_cv_lib_blkid_blkid_get_cache" >&6; } ++if test "x$ac_cv_lib_blkid_blkid_get_cache" = xyes; then : ++ LIBBLKID=`$PKG_CONFIG --libs blkid`; ++ STATIC_LIBBLKID=`$PKG_CONFIG --static --libs blkid` + fi + + fi +-if test -n "$PKG_CONFIG"; then +- _pkg_min_version=0.9.0 +- { $as_echo "$as_me:${as_lineno-$LINENO}: checking pkg-config is at least version $_pkg_min_version" >&5 +-$as_echo_n "checking pkg-config is at least version $_pkg_min_version... " >&6; } +- if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then +- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +-$as_echo "yes" >&6; } +- else +- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +-$as_echo "no" >&6; } +- PKG_CONFIG="" +- fi +-fi +- +-# Check whether --enable-quota was given. +-if test "${enable_quota+set}" = set; then : +- enableval=$enable_quota; if test "$enableval" = "no" +-then +- QUOTA_CMT=# +- { $as_echo "$as_me:${as_lineno-$LINENO}: result: Disabling quota support" >&5 +-$as_echo "Disabling quota support" >&6; } ++if test -n "$LIBBLKID"; then ++ BLKID_CMT=# ++ PROFILED_LIBBLKID=$LIBBLKID ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: Using system blkid library by default" >&5 ++$as_echo "Using system blkid library by default" >&6; } + else +- QUOTA_CMT= +- $as_echo "#define CONFIG_QUOTA 1" >>confdefs.h +- +- { $as_echo "$as_me:${as_lineno-$LINENO}: result: Enabling quota support" >&5 +-$as_echo "Enabling quota support" >&6; } +- QUOTA_MAN_COMMENT="" ++ LIBBLKID='$(LIB)/libblkid'$LIB_EXT ++ DEPLIBBLKID=$LIBBLKID ++ STATIC_LIBBLKID='$(LIB)/libblkid'$STATIC_LIB_EXT ++ DEPSTATIC_LIBBLKID=$STATIC_LIBBLKID ++ PROFILED_LIBBLKID='$(LIB)/libblkid'$PROFILED_LIB_EXT ++ DEPPROFILED_LIBBLKID=$PROFILED_LIBBLKID ++ $as_echo "#define CONFIG_BUILD_FINDFS 1" >>confdefs.h + ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: Enabling private blkid library by default" >&5 ++$as_echo "Enabling private blkid library by default" >&6; } + fi + +-else +- QUOTA_CMT=# +-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: Disabling quota support by default" >&5 +-$as_echo "Disabling quota support by default" >&6; } +- + fi + +-LIBQUOTA='$(LIB)/libquota'$LIB_EXT +-DEPLIBQUOTA=$LIBQUOTA +-STATIC_LIBQUOTA='$(LIB)/libquota'$STATIC_LIB_EXT +-DEPSTATIC_LIBQUOTA=$STATIC_LIBQUOTA +-PROFILED_LIBQUOTA='$(LIB)/libquota'$PROFILED_LIB_EXT +-DEPPROFILED_LIBQUOTA=$PROFILED_LIBQUOTA + + + +@@ -5991,6 +5878,77 @@ + 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 +@@ -12336,7 +12294,7 @@ + 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/acl.h sys/disklabel.h sys/disk.h sys/file.h sys/ioctl.h sys/key.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/sysctl.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" +@@ -13003,7 +12961,7 @@ + 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 utimes valloc ++for ac_func in __secure_getenv add_key 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 keyctl 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 utimes 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" +@@ -13057,6 +13015,329 @@ + fi + + ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for magic_file in -lmagic" >&5 ++$as_echo_n "checking for magic_file in -lmagic... " >&6; } ++if ${ac_cv_lib_magic_magic_file+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ ac_check_lib_save_LIBS=$LIBS ++LIBS="-lmagic $LIBS" ++cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++/* end confdefs.h. */ ++ ++/* Override any GCC internal prototype to avoid an error. ++ Use char because int might match the return type of a GCC ++ builtin and then its argument prototype would still apply. */ ++#ifdef __cplusplus ++extern "C" ++#endif ++char magic_file (); ++int ++main () ++{ ++return magic_file (); ++ ; ++ return 0; ++} ++_ACEOF ++if ac_fn_c_try_link "$LINENO"; then : ++ ac_cv_lib_magic_magic_file=yes ++else ++ ac_cv_lib_magic_magic_file=no ++fi ++rm -f core conftest.err conftest.$ac_objext \ ++ conftest$ac_exeext conftest.$ac_ext ++LIBS=$ac_check_lib_save_LIBS ++fi ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_magic_magic_file" >&5 ++$as_echo "$ac_cv_lib_magic_magic_file" >&6; } ++if test "x$ac_cv_lib_magic_magic_file" = xyes; then : ++ MAGIC_LIB=-lmagic ++for ac_header in magic.h ++do : ++ ac_fn_c_check_header_mongrel "$LINENO" "magic.h" "ac_cv_header_magic_h" "$ac_includes_default" ++if test "x$ac_cv_header_magic_h" = xyes; then : ++ cat >>confdefs.h <<_ACEOF ++#define HAVE_MAGIC_H 1 ++_ACEOF ++ ++fi ++ ++done ++ ++fi ++ ++if test "$ac_cv_lib_dl_dlopen" = yes ; then ++ MAGIC_LIB=$DLOPEN_LIB ++fi ++ ++FUSE_CMT= ++FUSE_LIB= ++# Check whether --enable-fuse2fs was given. ++if test "${enable_fuse2fs+set}" = set; then : ++ enableval=$enable_fuse2fs; if test "$enableval" = "no" ++then ++ FUSE_CMT="#" ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: Disabling fuse2fs" >&5 ++$as_echo "Disabling fuse2fs" >&6; } ++else ++ for ac_header in pthread.h fuse.h ++do : ++ as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ++ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "#define _FILE_OFFSET_BITS 64 ++#define FUSE_USE_VERSION 29 ++" ++if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : ++ cat >>confdefs.h <<_ACEOF ++#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 ++_ACEOF ++ ++else ++ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 ++$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} ++as_fn_error $? "Cannot find fuse2fs headers. ++See \`config.log' for more details" "$LINENO" 5; } ++fi ++ ++done ++ ++ ++ cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++/* end confdefs.h. */ ++#define FUSE_USE_VERSION 29 ++#ifdef __linux__ ++#include ++#include ++#include ++#endif ++ ++int ++main () ++{ ++ ++ ; ++ return 0; ++} ++_ACEOF ++if ac_fn_c_try_cpp "$LINENO"; then : ++ ++else ++ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 ++$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} ++as_fn_error $? "Cannot find fuse2fs Linux headers. ++See \`config.log' for more details" "$LINENO" 5; } ++fi ++rm -f conftest.err conftest.i conftest.$ac_ext ++ ++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for fuse_main in -losxfuse" >&5 ++$as_echo_n "checking for fuse_main in -losxfuse... " >&6; } ++if ${ac_cv_lib_osxfuse_fuse_main+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ ac_check_lib_save_LIBS=$LIBS ++LIBS="-losxfuse $LIBS" ++cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++/* end confdefs.h. */ ++ ++/* Override any GCC internal prototype to avoid an error. ++ Use char because int might match the return type of a GCC ++ builtin and then its argument prototype would still apply. */ ++#ifdef __cplusplus ++extern "C" ++#endif ++char fuse_main (); ++int ++main () ++{ ++return fuse_main (); ++ ; ++ return 0; ++} ++_ACEOF ++if ac_fn_c_try_link "$LINENO"; then : ++ ac_cv_lib_osxfuse_fuse_main=yes ++else ++ ac_cv_lib_osxfuse_fuse_main=no ++fi ++rm -f core conftest.err conftest.$ac_objext \ ++ conftest$ac_exeext conftest.$ac_ext ++LIBS=$ac_check_lib_save_LIBS ++fi ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_osxfuse_fuse_main" >&5 ++$as_echo "$ac_cv_lib_osxfuse_fuse_main" >&6; } ++if test "x$ac_cv_lib_osxfuse_fuse_main" = xyes; then : ++ FUSE_LIB=-losxfuse ++else ++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for fuse_main in -lfuse" >&5 ++$as_echo_n "checking for fuse_main in -lfuse... " >&6; } ++if ${ac_cv_lib_fuse_fuse_main+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ ac_check_lib_save_LIBS=$LIBS ++LIBS="-lfuse $LIBS" ++cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++/* end confdefs.h. */ ++ ++/* Override any GCC internal prototype to avoid an error. ++ Use char because int might match the return type of a GCC ++ builtin and then its argument prototype would still apply. */ ++#ifdef __cplusplus ++extern "C" ++#endif ++char fuse_main (); ++int ++main () ++{ ++return fuse_main (); ++ ; ++ return 0; ++} ++_ACEOF ++if ac_fn_c_try_link "$LINENO"; then : ++ ac_cv_lib_fuse_fuse_main=yes ++else ++ ac_cv_lib_fuse_fuse_main=no ++fi ++rm -f core conftest.err conftest.$ac_objext \ ++ conftest$ac_exeext conftest.$ac_ext ++LIBS=$ac_check_lib_save_LIBS ++fi ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_fuse_fuse_main" >&5 ++$as_echo "$ac_cv_lib_fuse_fuse_main" >&6; } ++if test "x$ac_cv_lib_fuse_fuse_main" = xyes; then : ++ FUSE_LIB=-lfuse ++else ++ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 ++$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} ++as_fn_error $? "Cannot find fuse library. ++See \`config.log' for more details" "$LINENO" 5; } ++fi ++ ++fi ++ ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: Enabling fuse2fs" >&5 ++$as_echo "Enabling fuse2fs" >&6; } ++fi ++ ++else ++ for ac_header in pthread.h fuse.h ++do : ++ as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ++ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "#define _FILE_OFFSET_BITS 64 ++#define FUSE_USE_VERSION 29 ++#ifdef __linux__ ++# include ++# include ++# include ++#endif ++" ++if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : ++ cat >>confdefs.h <<_ACEOF ++#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 ++_ACEOF ++ ++else ++ FUSE_CMT="#" ++fi ++ ++done ++ ++if test -z "$FUSE_CMT" ++then ++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for fuse_main in -losxfuse" >&5 ++$as_echo_n "checking for fuse_main in -losxfuse... " >&6; } ++if ${ac_cv_lib_osxfuse_fuse_main+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ ac_check_lib_save_LIBS=$LIBS ++LIBS="-losxfuse $LIBS" ++cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++/* end confdefs.h. */ ++ ++/* Override any GCC internal prototype to avoid an error. ++ Use char because int might match the return type of a GCC ++ builtin and then its argument prototype would still apply. */ ++#ifdef __cplusplus ++extern "C" ++#endif ++char fuse_main (); ++int ++main () ++{ ++return fuse_main (); ++ ; ++ return 0; ++} ++_ACEOF ++if ac_fn_c_try_link "$LINENO"; then : ++ ac_cv_lib_osxfuse_fuse_main=yes ++else ++ ac_cv_lib_osxfuse_fuse_main=no ++fi ++rm -f core conftest.err conftest.$ac_objext \ ++ conftest$ac_exeext conftest.$ac_ext ++LIBS=$ac_check_lib_save_LIBS ++fi ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_osxfuse_fuse_main" >&5 ++$as_echo "$ac_cv_lib_osxfuse_fuse_main" >&6; } ++if test "x$ac_cv_lib_osxfuse_fuse_main" = xyes; then : ++ FUSE_LIB=-losxfuse ++else ++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for fuse_main in -lfuse" >&5 ++$as_echo_n "checking for fuse_main in -lfuse... " >&6; } ++if ${ac_cv_lib_fuse_fuse_main+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ ac_check_lib_save_LIBS=$LIBS ++LIBS="-lfuse $LIBS" ++cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++/* end confdefs.h. */ ++ ++/* Override any GCC internal prototype to avoid an error. ++ Use char because int might match the return type of a GCC ++ builtin and then its argument prototype would still apply. */ ++#ifdef __cplusplus ++extern "C" ++#endif ++char fuse_main (); ++int ++main () ++{ ++return fuse_main (); ++ ; ++ return 0; ++} ++_ACEOF ++if ac_fn_c_try_link "$LINENO"; then : ++ ac_cv_lib_fuse_fuse_main=yes ++else ++ ac_cv_lib_fuse_fuse_main=no ++fi ++rm -f core conftest.err conftest.$ac_objext \ ++ conftest$ac_exeext conftest.$ac_ext ++LIBS=$ac_check_lib_save_LIBS ++fi ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_fuse_fuse_main" >&5 ++$as_echo "$ac_cv_lib_fuse_fuse_main" >&6; } ++if test "x$ac_cv_lib_fuse_fuse_main" = xyes; then : ++ FUSE_LIB=-lfuse ++else ++ FUSE_CMT="#" ++fi ++ ++fi ++ ++fi ++if test -z "$FUSE_CMT" ++then ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: Enabling fuse2fs by default." >&5 ++$as_echo "Enabling fuse2fs by default." >&6; } ++fi ++ ++fi ++ ++ ++ + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for optreset" >&5 + $as_echo_n "checking for optreset... " >&6; } + if ${ac_cv_have_optreset+:} false; then : +@@ -13419,14 +13700,20 @@ + test -d include || mkdir include + test -d include/linux || mkdir include/linux + test -d include/asm || mkdir include/asm ++if test -z "$UUID_CMT" ; then ++ uuid_out_list="lib/uuid/Makefile lib/uuid/uuid.pc \ ++ lib/uuid/uuid_types.h" ++fi ++if test -z "$BLKID_CMT" ; then ++ blkid_out_list="lib/blkid/Makefile lib/blkid/blkid.pc \ ++ lib/blkid/blkid_types.h" ++fi + for i in MCONFIG Makefile e2fsprogs.spec \ + util/Makefile util/subst.conf util/gen-tarball util/install-symlink \ + lib/et/Makefile lib/ss/Makefile lib/e2p/Makefile \ + lib/ext2fs/Makefile lib/ext2fs/ext2_types.h \ +- lib/uuid/Makefile lib/uuid/uuid_types.h \ +- lib/blkid/Makefile lib/blkid/blkid_types.h lib/quota/Makefile \ +- lib/ss/ss.pc lib/uuid/uuid.pc lib/et/com_err.pc \ +- lib/e2p/e2p.pc lib/blkid/blkid.pc lib/ext2fs/ext2fs.pc \ ++ $uuid_out_list $blkid_out_list lib/support/Makefile \ ++ lib/ss/ss.pc lib/et/com_err.pc lib/e2p/e2p.pc lib/ext2fs/ext2fs.pc \ + misc/Makefile ext2ed/Makefile e2fsck/Makefile \ + debugfs/Makefile tests/Makefile tests/progs/Makefile \ + resize/Makefile doc/Makefile intl/Makefile \ +--- /dev/null ++++ b/configure.ac +@@ -0,0 +1,1418 @@ ++AC_INIT(version.h) ++AC_PREREQ(2.54) ++AC_CONFIG_AUX_DIR(config) ++AC_CONFIG_HEADERS([lib/config.h]) ++AH_BOTTOM([#include ]) ++MCONFIG=./MCONFIG ++AC_SUBST_FILE(MCONFIG) ++BINARY_TYPE=bin ++dnl ++dnl This is to figure out the version number and the date.... ++dnl ++E2FSPROGS_VERSION=`grep E2FSPROGS_VERSION ${srcdir}/version.h \ ++ | awk '{print $3}' | tr \" " " | awk '{print $1}'` ++DATE=`grep E2FSPROGS_DATE ${srcdir}/version.h | awk '{print $3}' \ ++ | tr \" " "` ++E2FSPROGS_DAY=`echo $DATE | awk -F- '{print $1}'` ++MONTH=`echo $DATE | awk -F- '{print $2}'` ++YEAR=`echo $DATE | awk -F- '{print $3}'` ++ ++if expr $YEAR ">" 1900 > /dev/null ; then ++ E2FSPROGS_YEAR=$YEAR ++elif expr $YEAR ">" 90 >/dev/null ; then ++ E2FSPROGS_YEAR=19$YEAR ++else ++ E2FSPROGS_YEAR=20$YEAR ++fi ++ ++case $MONTH in ++Jan) MONTH_NUM=01; E2FSPROGS_MONTH="January" ;; ++Feb) MONTH_NUM=02; E2FSPROGS_MONTH="February" ;; ++Mar) MONTH_NUM=03; E2FSPROGS_MONTH="March" ;; ++Apr) MONTH_NUM=04; E2FSPROGS_MONTH="April" ;; ++May) MONTH_NUM=05; E2FSPROGS_MONTH="May" ;; ++Jun) MONTH_NUM=06; E2FSPROGS_MONTH="June" ;; ++Jul) MONTH_NUM=07; E2FSPROGS_MONTH="July" ;; ++Aug) MONTH_NUM=08; E2FSPROGS_MONTH="August" ;; ++Sep) MONTH_NUM=09; E2FSPROGS_MONTH="September" ;; ++Oct) MONTH_NUM=10; E2FSPROGS_MONTH="October" ;; ++Nov) MONTH_NUM=11; E2FSPROGS_MONTH="November" ;; ++Dec) MONTH_NUM=12; E2FSPROGS_MONTH="December" ;; ++*) AC_MSG_WARN([Unknown month $MONTH??]) ;; ++esac ++ ++base_ver=`echo $E2FSPROGS_VERSION | \ ++ sed -e 's/-WIP//' -e 's/pre-//' -e 's/-PLUS//'` ++ ++date_spec=${E2FSPROGS_YEAR}.${MONTH_NUM}.${E2FSPROGS_DAY} ++ ++case $E2FSPROGS_VERSION in ++*-WIP|pre-*) ++ E2FSPROGS_PKGVER="$base_ver~WIP-$E2FSPROGS_YEAR-$MONTH_NUM-$E2FSPROGS_DAY" ++ ;; ++*) ++ E2FSPROGS_PKGVER="$base_ver" ++ ;; ++esac ++ ++unset DATE MONTH YEAR base_ver pre_vers date_spec ++AC_MSG_RESULT([Generating configuration file for e2fsprogs version $E2FSPROGS_VERSION]) ++AC_MSG_RESULT([Release date is ${E2FSPROGS_MONTH}, ${E2FSPROGS_YEAR}]) ++AC_SUBST(E2FSPROGS_YEAR) ++AC_SUBST(E2FSPROGS_MONTH) ++AC_SUBST(E2FSPROGS_DAY) ++AC_SUBST(E2FSPROGS_VERSION) ++AC_SUBST(E2FSPROGS_PKGVER) ++dnl ++dnl Use diet libc ++dnl ++WITH_DIET_LIBC= ++AC_ARG_WITH([diet-libc], ++[ --with-diet-libc use diet libc], ++CC="diet cc -nostdinc" ++WITH_DIET_LIBC=yes ++if test -z "$LIBS" ++then ++ LIBS="-lcompat" ++else ++ LIBS="$LIBS -lcompat" ++fi ++AC_MSG_RESULT(CC=$CC))dnl ++dnl ++AC_CANONICAL_HOST ++dnl ++dnl Check to see if libdl exists for the sake of dlopen ++dnl ++DLOPEN_LIB='' ++AC_CHECK_LIB(dl, dlopen, ++[DLOPEN_LIB=-ldl ++AC_DEFINE(HAVE_DLOPEN, 1, [Define to 1 if dlopen/libdl exists])]) ++AC_SUBST(DLOPEN_LIB) ++dnl ++AC_ARG_WITH([cc], ++AC_HELP_STRING([--with-cc],[no longer supported, use CC= instead]), ++AC_MSG_ERROR([--with-cc no longer supported; use CC= instead])) ++dnl ++AC_ARG_WITH([ccopts], ++AC_HELP_STRING([--with-ccopts],[no longer supported, use CFLAGS= instead]), ++AC_MSG_ERROR([--with-ccopts no longer supported; use CFLAGS= instead])) ++dnl ++AC_ARG_WITH([ldopts], ++AC_HELP_STRING([--with-ldopts],[no longer supported, use LDFLAGS= instead]), ++AC_MSG_ERROR([--with-ldopts no longer supported; use LDFLAGS= instead])) ++dnl ++AC_PROG_CC ++if test "$GCC" = yes; then ++ RDYNAMIC="-rdynamic" ++ AC_SUBST(RDYNAMIC) ++fi ++AC_PROG_CPP ++dnl ++dnl Alpha computers use fast and imprecise floating point code that may ++dnl miss exceptions by default. Force sane options if we're using GCC. ++AC_MSG_CHECKING(for additional special compiler flags) ++if test "$GCC" = yes ++then ++ case "$host_cpu" in ++ alpha) addcflags="-mieee" ;; ++ esac ++fi ++if test "x$addcflags" != x ++then ++ AC_MSG_RESULT($addcflags) ++ CFLAGS="$addcflags $CFLAGS" ++else ++ AC_MSG_RESULT([[(none)]]) ++fi ++AC_USE_SYSTEM_EXTENSIONS ++dnl ++dnl Set default values for library extentions. Will be dealt with after ++dnl parsing configuration opions, which may modify these ++dnl ++LIB_EXT=.a ++STATIC_LIB_EXT=.a ++PROFILED_LIB_EXT=.a ++dnl ++dnl Allow separate `root_prefix' to be specified ++dnl ++AC_ARG_WITH([root-prefix], ++[ --with-root-prefix=PREFIX override prefix variable for files to be placed in the root], ++root_prefix=$withval, ++root_prefix=NONE)dnl ++dnl ++dnl handle --enable-maintainer-mode ++dnl ++AC_ARG_ENABLE([maintainer-mode], ++[ --enable-maintainer-mode enable makefile rules useful for maintainers], ++if test "$enableval" = "no" ++then ++ MAINTAINER_CMT=# ++ AC_MSG_RESULT([Disabling maintainer mode]) ++else ++ MAINTAINER_CMT= ++ AC_MSG_RESULT([Enabling maintainer mode]) ++fi ++, ++MAINTAINER_CMT=# ++AC_MSG_RESULT([Disabling maintainer mode by default]) ++) ++AC_SUBST(MAINTAINER_CMT) ++dnl ++dnl handle --enable-symlink-install ++dnl ++AC_ARG_ENABLE([symlink-install], ++[ --enable-symlink-install use symlinks when installing instead of hard links], ++if test "$enableval" = "no" ++then ++ LINK_INSTALL_FLAGS=-f ++ AC_MSG_RESULT([Disabling symlinks for install]) ++else ++ LINK_INSTALL_FLAGS=-sf ++ AC_MSG_RESULT([Enabling symlinks for install]) ++fi ++, ++LINK_INSTALL_FLAGS=-f ++AC_MSG_RESULT([Disabling symlinks for install by default]) ++) ++AC_SUBST(LINK_INSTALL_FLAGS) ++dnl ++dnl handle --enable-relative-symlinks ++dnl ++relative_symlink_defined= ++AC_ARG_ENABLE([relative-symlinks], ++[ --enable-relative-symlinks use relative symlinks when installing], ++if test "$enableval" = "no" ++then ++ SYMLINK_RELATIVE= ++ relative_symlink_defined=yes ++ AC_MSG_RESULT([Disabling relative symlinks for install]) ++else ++ SYMLINK_RELATIVE=--relative ++ relative_symlink_defined=yes ++ AC_MSG_RESULT([Enabling relative symlinks for install]) ++fi) ++AC_ARG_ENABLE([symlink-relative-symlinks],, ++if test "$enableval" = "no" ++then ++ SYMLINK_RELATIVE=yes ++ AC_MSG_RESULT([Disabling relative symlinks for install]) ++else ++ SYMLINK_RELATIVE=--relative ++ AC_MSG_RESULT([Enabling relative symlinks for install]) ++fi ++, ++if test -z "$relative_symlink_defined" ++then ++ SYMLINK_RELATIVE= ++AC_MSG_RESULT([Disabling relative symlinks for install by default]) ++fi ++) ++AC_SUBST(SYMLINK_RELATIVE) ++dnl ++dnl handle --enable-symlink-build ++dnl ++AC_ARG_ENABLE([symlink-build], ++[ --enable-symlink-build use symlinks while building instead of hard links], ++if test "$enableval" = "no" ++then ++ LINK_BUILD_FLAGS= ++ AC_MSG_RESULT([Disabling symlinks for build]) ++else ++ LINK_BUILD_FLAGS=-s ++ AC_MSG_RESULT([Enabling symlinks for build]) ++fi ++, ++LINK_BUILD_FLAGS= ++AC_MSG_RESULT([Disabling symlinks for build by default]) ++) ++AC_SUBST(LINK_BUILD_FLAGS) ++dnl ++dnl handle --enable-verbose-makecmds ++dnl ++AC_ARG_ENABLE([verbose-makecmds], ++[ --enable-verbose-makecmds enable verbose make command output], ++if test "$enableval" = "no" ++then ++ AC_MSG_RESULT([Disabling verbose make commands]) ++ E=@echo ++ ES=echo ++ Q=@ ++else ++ AC_MSG_RESULT([Enabling verbose make commands]) ++ E=@\\# ++ ES=\\# ++ Q= ++fi ++, ++AC_MSG_RESULT([Disabling verbose make commands]) ++E=@echo ++ES=echo ++Q=@ ++) ++AC_SUBST(E) ++AC_SUBST(ES) ++AC_SUBST(Q) ++dnl ++dnl This needs to be before all of the --enable-*-shlibs options ++dnl ++E2_PKG_CONFIG_STATIC=--static ++LDFLAG_DYNAMIC= ++PRIVATE_LIBS_CMT= ++dnl ++dnl handle --enable-elf-shlibs ++dnl ++AC_ARG_ENABLE([elf-shlibs], ++[ --enable-elf-shlibs select ELF shared libraries], ++if test "$enableval" = "no" ++then ++ ELF_CMT=# ++ MAKEFILE_ELF=/dev/null ++ AC_MSG_RESULT([Disabling ELF shared libraries]) ++else ++ E2_PKG_CONFIG_STATIC= ++ ELF_CMT= ++ MAKEFILE_ELF=$srcdir/lib/Makefile.elf-lib ++ [case "$host_os" in ++ solaris2.*) ++ MAKEFILE_ELF=$srcdir/lib/Makefile.solaris-lib ++ ;; ++ esac] ++ BINARY_TYPE=elfbin ++ LIB_EXT=.so ++ PRIVATE_LIBS_CMT=# ++ LDFLAG_DYNAMIC=['-Wl,-rpath-link,$(top_builddir)/lib'] ++ AC_MSG_RESULT([Enabling ELF shared libraries]) ++fi ++, ++MAKEFILE_ELF=/dev/null ++ELF_CMT=# ++AC_MSG_RESULT([Disabling ELF shared libraries by default]) ++) ++AC_SUBST(ELF_CMT) ++AC_SUBST_FILE(MAKEFILE_ELF) ++dnl ++dnl handle --enable-bsd-shlibs ++dnl ++AC_ARG_ENABLE([bsd-shlibs], ++[ --enable-bsd-shlibs select BSD shared libraries], ++if test "$enableval" = "no" ++then ++ BSDLIB_CMT=# ++ MAKEFILE_BSDLIB=/dev/null ++ AC_MSG_RESULT([Disabling BSD shared libraries]) ++else ++ E2_PKG_CONFIG_STATIC= ++ BSDLIB_CMT= ++ MAKEFILE_BSDLIB=$srcdir/lib/Makefile.bsd-lib ++ LIB_EXT=.so ++ [case "$host_os" in ++ darwin*) ++ MAKEFILE_BSDLIB=$srcdir/lib/Makefile.darwin-lib ++ LIB_EXT=.dylib ++ ;; ++ esac] ++ AC_MSG_RESULT([Enabling BSD shared libraries]) ++fi ++, ++MAKEFILE_BSDLIB=/dev/null ++BSDLIB_CMT=# ++AC_MSG_RESULT([Disabling BSD shared libraries by default]) ++) ++AC_SUBST(BSDLIB_CMT) ++AC_SUBST_FILE(MAKEFILE_BSDLIB) ++dnl ++dnl handle --enable-profile ++dnl ++AC_ARG_ENABLE([profile], ++[ --enable-profile build profiling libraries], ++if test "$enableval" = "no" ++then ++ PROFILE_CMT=# ++ MAKEFILE_PROFILE=/dev/null ++ AC_MSG_RESULT([Disabling profiling libraries]) ++else ++ PROFILE_CMT= ++ MAKEFILE_PROFILE=$srcdir/lib/Makefile.profile ++ PROFILED_LIB_EXT=_p.a ++ AC_MSG_RESULT([Building profiling libraries]) ++fi ++, ++PROFILE_CMT=# ++MAKEFILE_PROFILE=/dev/null ++AC_MSG_RESULT([Disabling profiling libraries by default]) ++) ++AC_SUBST(PROFILE_CMT) ++AC_SUBST_FILE(MAKEFILE_PROFILE) ++dnl ++dnl handle --enable-gcov ++dnl ++AC_ARG_ENABLE([gcov], ++[ --enable-gcov build for coverage testing using gcov], ++if test "$enableval" = "yes" ++then ++ CFLAGS="-g -fprofile-arcs -ftest-coverage" ++ LDFLAGS="-fprofile-arcs -ftest-coverage" ++ AC_MSG_RESULT([Enabling gcov support]) ++fi ++) ++ ++dnl ++dnl Substitute library extensions ++dnl ++AC_SUBST(LIB_EXT) ++AC_SUBST(STATIC_LIB_EXT) ++AC_SUBST(PROFILED_LIB_EXT) ++AC_SUBST(LDFLAG_DYNAMIC) ++AC_SUBST(PRIVATE_LIBS_CMT) ++dnl ++dnl handle --enable-jbd-debug ++dnl ++AC_ARG_ENABLE([jbd-debug], ++[ --enable-jbd-debug enable journal debugging], ++if test "$enableval" = "no" ++then ++ AC_MSG_RESULT([Disabling journal debugging]) ++else ++ AC_DEFINE(CONFIG_JBD_DEBUG, 1, ++ [Define to 1 if debugging ext3/4 journal code]) ++ AC_MSG_RESULT([Enabling journal debugging]) ++fi ++, ++AC_MSG_RESULT([Disabling journal debugging by default]) ++) ++dnl ++dnl handle --enable-blkid-debug ++dnl ++AC_ARG_ENABLE([blkid-debug], ++[ --enable-blkid-debug enable blkid debugging], ++if test "$enableval" = "no" ++then ++ AC_MSG_RESULT([Disabling blkid debugging]) ++else ++ AC_DEFINE(CONFIG_BLKID_DEBUG, 1, ++ [Define to 1 if debugging the blkid library]) ++ AC_MSG_RESULT([Enabling blkid debugging]) ++fi ++, ++AC_MSG_RESULT([Disabling blkid debugging by default]) ++) ++dnl ++dnl handle --enable-testio-debug ++dnl ++AC_ARG_ENABLE([testio-debug], ++[ --disable-testio-debug disable the use of the test I/O manager for debugging], ++AH_TEMPLATE([CONFIG_TESTIO_DEBUG], ++ [Define to 1 if the testio I/O manager should be enabled]) ++if test "$enableval" = "no" ++then ++ AC_MSG_RESULT([Disabling testio debugging]) ++ TEST_IO_CMT="#" ++else ++ TEST_IO_CMT= ++ AC_DEFINE(CONFIG_TESTIO_DEBUG, 1) ++ AC_MSG_RESULT([Enabling testio debugging]) ++fi ++, ++AC_MSG_RESULT([Enabling testio debugging by default]) ++AC_DEFINE(CONFIG_TESTIO_DEBUG, 1) ++TEST_IO_CMT= ++) ++AC_SUBST(TEST_IO_CMT) ++dnl ++dnl handle --disable-libuuid ++dnl ++PKG_PROG_PKG_CONFIG ++LIBUUID= ++DEPLIBUUID= ++STATIC_LIBUUID= ++DEPSTATIC_LIBUUID= ++PROFILED_LIBUUID= ++DEPPROFILED_LIBUUID= ++UUID_CMT= ++AC_ARG_ENABLE([libuuid], ++[ --enable-libuuid build and use private uuid library], ++if test "$enableval" = "no" ++then ++ if test -z "$PKG_CONFIG"; then ++ AC_MSG_ERROR([pkg-config not installed; please install it.]) ++ fi ++ ++ AC_CHECK_LIB(uuid, uuid_generate, ++ [LIBUUID=`$PKG_CONFIG --libs uuid`; ++ STATIC_LIBUUID=`$PKG_CONFIG --static --libs uuid`], ++ [AC_MSG_ERROR([external uuid library not found])]) ++ PROFILED_LIBUUID=$LIBUUID ++ UUID_CMT=# ++ AC_MSG_RESULT([Disabling private uuid library]) ++else ++ LIBUUID='$(LIB)/libuuid'$LIB_EXT ++ DEPLIBUUID=$LIBUUID ++ STATIC_LIBUUID='$(LIB)/libuuid'$STATIC_LIB_EXT ++ DEPSTATIC_LIBUUID=$STATIC_LIBUUID ++ PROFILED_LIBUUID='$(LIB)/libuuid'$PROFILED_LIB_EXT ++ DEPPROFILED_LIBUUID=$PROFILED_LIBUUID ++ AC_MSG_RESULT([Enabling private uuid library]) ++fi ++, ++if test -n "$PKG_CONFIG"; then ++ AC_CHECK_LIB(uuid, uuid_generate, ++ [LIBUUID=`$PKG_CONFIG --libs uuid`; ++ STATIC_LIBUUID=`$PKG_CONFIG --static --libs uuid`]) ++fi ++if test -n "$LIBUUID"; then ++ PROFILED_LIBUUID=$LIBUUID ++ UUID_CMT=# ++ AC_MSG_RESULT([Using system uuid by default]) ++else ++ LIBUUID='$(LIB)/libuuid'$LIB_EXT ++ DEPLIBUUID=$LIBUUID ++ STATIC_LIBUUID='$(LIB)/libuuid'$STATIC_LIB_EXT ++ DEPSTATIC_LIBUUID=$STATIC_LIBUUID ++ PROFILED_LIBUUID='$(LIB)/libuuid'$PROFILED_LIB_EXT ++ DEPPROFILED_LIBUUID=$PROFILED_LIBUUID ++ AC_MSG_RESULT([Enabling private uuid library by default]) ++fi ++) ++AC_SUBST(LIBUUID) ++AC_SUBST(DEPLIBUUID) ++AC_SUBST(STATIC_LIBUUID) ++AC_SUBST(DEPSTATIC_LIBUUID) ++AC_SUBST(PROFILED_LIBUUID) ++AC_SUBST(DEPPROFILED_LIBUUID) ++AC_SUBST(UUID_CMT) ++dnl ++dnl handle --disable-libblkid ++dnl ++PKG_PROG_PKG_CONFIG ++LIBBLKID= ++DEPLIBBLKID= ++STATIC_LIBBLKID= ++DEPSTATIC_LIBBLKID= ++PROFILED_LIBBLKID= ++DEPPROFILED_LIBBLKID= ++BLKID_CMT= ++AH_TEMPLATE([CONFIG_BUILD_FINDFS], [Define to 1 to compile findfs]) ++AC_ARG_ENABLE([libblkid], ++[ --enable-libblkid build and use private blkid library], ++if test "$enableval" = "no" ++then ++ if test -z "$PKG_CONFIG"; then ++ AC_MSG_ERROR([pkg-config not installed; please install it.]) ++ fi ++ ++ AC_CHECK_LIB(blkid, blkid_get_cache, ++ [LIBBLKID=`$PKG_CONFIG --libs blkid`; ++ STATIC_LIBBLKID=`$PKG_CONFIG --static --libs blkid`], ++ [AC_MSG_ERROR([external blkid library not found])], -luuid) ++ BLKID_CMT=# ++ PROFILED_LIBBLKID=$LIBBLKID ++ AC_MSG_RESULT([Disabling private blkid library]) ++else ++ LIBBLKID='$(LIB)/libblkid'$LIB_EXT ++ DEPLIBBLKID=$LIBBLKID ++ STATIC_LIBBLKID='$(LIB)/libblkid'$STATIC_LIB_EXT ++ DEPSTATIC_LIBBLKID=$STATIC_LIBBLKID ++ PROFILED_LIBBLKID='$(LIB)/libblkid'$PROFILED_LIB_EXT ++ DEPPROFILED_LIBBLKID=$PROFILED_LIBBLKID ++ AC_DEFINE(CONFIG_BUILD_FINDFS, 1) ++ AC_MSG_RESULT([Enabling private blkid library]) ++fi ++, ++if test -n "$PKG_CONFIG"; then ++ AC_CHECK_LIB(blkid, blkid_get_cache, ++ [LIBBLKID=`$PKG_CONFIG --libs blkid`; ++ STATIC_LIBBLKID=`$PKG_CONFIG --static --libs blkid`]) ++fi ++if test -n "$LIBBLKID"; then ++ BLKID_CMT=# ++ PROFILED_LIBBLKID=$LIBBLKID ++ AC_MSG_RESULT([Using system blkid library by default]) ++else ++ LIBBLKID='$(LIB)/libblkid'$LIB_EXT ++ DEPLIBBLKID=$LIBBLKID ++ STATIC_LIBBLKID='$(LIB)/libblkid'$STATIC_LIB_EXT ++ DEPSTATIC_LIBBLKID=$STATIC_LIBBLKID ++ PROFILED_LIBBLKID='$(LIB)/libblkid'$PROFILED_LIB_EXT ++ DEPPROFILED_LIBBLKID=$PROFILED_LIBBLKID ++ AC_DEFINE(CONFIG_BUILD_FINDFS, 1) ++ AC_MSG_RESULT([Enabling private blkid library by default]) ++fi ++) ++AC_SUBST(LIBBLKID) ++AC_SUBST(DEPLIBBLKID) ++AC_SUBST(STATIC_LIBBLKID) ++AC_SUBST(DEPSTATIC_LIBBLKID) ++AC_SUBST(PROFILED_LIBBLKID) ++AC_SUBST(DEPPROFILED_LIBBLKID) ++AC_SUBST(BLKID_CMT) ++dnl ++dnl handle --disable-backtrace ++dnl ++AH_TEMPLATE([DISABLE_BACKTRACE], [Define to 1 to disable use of backtrace]) ++AC_ARG_ENABLE([backtrace], ++[ --disable-backtrace disable use backtrace], ++if test "$enableval" = "no" ++then ++ AC_MSG_RESULT([Disabling use of backtrace]) ++ AC_DEFINE(DISABLE_BACKTRACE, 1) ++else ++ AC_MSG_RESULT([Enabling use of backtrace]) ++fi ++, ++AC_MSG_RESULT([Enabling use of backtrace by default]) ++) ++dnl ++dnl handle --enable-debugfs ++dnl ++AC_ARG_ENABLE([debugfs], ++[ --disable-debugfs disable support of debugfs program], ++if test "$enableval" = "no" ++then ++ AC_MSG_RESULT([Disabling debugfs support]) ++ DEBUGFS_CMT="#" ++else ++ DEBUGFS_CMT= ++ AC_MSG_RESULT([Enabling debugfs support]) ++fi ++, ++AC_MSG_RESULT([Enabling debugfs support by default]) ++DEBUGFS_CMT= ++) ++AC_SUBST(DEBUGFS_CMT) ++dnl ++dnl handle --enable-imager ++dnl ++AC_ARG_ENABLE([imager], ++[ --disable-imager disable support of e2image program], ++if test "$enableval" = "no" ++then ++ AC_MSG_RESULT([Disabling e2image support]) ++ IMAGER_CMT="#" ++else ++ IMAGER_CMT= ++ AC_MSG_RESULT([Enabling e2image support]) ++fi ++, ++AC_MSG_RESULT([Enabling e2image support by default]) ++IMAGER_CMT= ++) ++AC_SUBST(IMAGER_CMT) ++dnl ++dnl handle --enable-resizer ++dnl ++AC_ARG_ENABLE([resizer], ++[ --disable-resizer disable support of e2resize program], ++if test "$enableval" = "no" ++then ++ AC_MSG_RESULT([Disabling e2resize support]) ++ RESIZER_CMT="#" ++else ++ RESIZER_CMT= ++ AC_MSG_RESULT([Enabling e2resize support]) ++fi ++, ++AC_MSG_RESULT([Enabling e2resize support by default]) ++RESIZER_CMT= ++) ++AC_SUBST(RESIZER_CMT) ++dnl ++dnl handle --enable-defrag ++dnl ++AC_ARG_ENABLE([defrag], ++[ --disable-defrag disable support of e4defrag program], ++if test "$enableval" = "no" ++then ++ AC_MSG_RESULT([Disabling e4defrag support]) ++ DEFRAG_CMT="#" ++else ++ DEFRAG_CMT= ++ AC_MSG_RESULT([Enabling e4defrag support]) ++fi ++, ++if test -z "$WITH_DIET_LIBC" ++then ++ AC_MSG_RESULT([Enabling e4defrag support by default]) ++ DEFRAG_CMT= ++else ++ AC_MSG_RESULT([Disabling e4defrag support by default]) ++ DEFRAG_CMT="#" ++fi ++) ++AC_SUBST(DEFRAG_CMT) ++dnl ++dnl See whether to install the `fsck' wrapper program (that calls e2fsck) ++dnl ++AC_ARG_ENABLE([fsck], ++[ --enable-fsck build fsck wrapper program], ++[if test "$enableval" = "no" ++then ++ FSCK_PROG='' FSCK_MAN='' ++ AC_MSG_RESULT([Not building fsck wrapper]) ++else ++ FSCK_PROG=fsck FSCK_MAN=fsck.8 ++ AC_MSG_RESULT([Building fsck wrapper]) ++fi] ++, ++[case "$host_os" in ++ gnu*) ++ FSCK_PROG='' FSCK_MAN='' ++ AC_MSG_RESULT([Not building fsck wrapper by default]) ++ ;; ++ *) ++ FSCK_PROG=fsck FSCK_MAN=fsck.8 ++ AC_MSG_RESULT([Building fsck wrapper by default]) ++esac] ++) ++AC_SUBST(FSCK_PROG) ++AC_SUBST(FSCK_MAN) ++dnl ++dnl See whether to install the `e2initrd-helper' program ++dnl ++AC_ARG_ENABLE([e2initrd-helper], ++[ --enable-e2initrd-helper build e2initrd-helper program], ++[if test "$enableval" = "no" ++then ++ E2INITRD_PROG='' E2INITRD_MAN='' ++ AC_MSG_RESULT([Not building e2initrd helper]) ++else ++ E2INITRD_PROG=e2initrd_helper E2INITRD_MAN=e2initrd_helper.8 ++ AC_MSG_RESULT([Building e2initrd helper]) ++fi] ++, ++E2INITRD_PROG=e2initrd_helper E2INITRD_MAN=e2initrd_helper.8 ++AC_MSG_RESULT([Building e2initrd helper by default]) ++) ++AC_SUBST(E2INITRD_PROG) ++AC_SUBST(E2INITRD_MAN) ++dnl ++dnl ++dnl ++AC_ARG_ENABLE([tls], ++[ --disable-tls disable use of thread local support], ++[if test "$enableval" = "no" ++then ++ try_tls="" ++ AC_MSG_RESULT([Disabling thread local support]) ++else ++ try_tls="yes" ++ AC_MSG_RESULT([Enabling thread local support]) ++fi] ++, ++if test -n "$WITH_DIET_LIBC" ++then ++ try_tls="" ++ AC_MSG_RESULT([Diet libc does not support thread local support]) ++else ++ try_tls="yes" ++ AC_MSG_RESULT([Try using thread local support by default]) ++fi ++) ++if test "$try_tls" = "yes" ++then ++AX_TLS ++fi ++dnl ++dnl ++dnl ++AH_TEMPLATE([USE_UUIDD], [Define to 1 to build uuidd]) ++AC_ARG_ENABLE([uuidd], ++[ --disable-uuidd disable building the uuid daemon], ++[if test "$enableval" = "no" ++then ++ AC_MSG_RESULT([Not building uuidd]) ++ UUIDD_CMT="#" ++else ++ AC_DEFINE(USE_UUIDD, 1) ++ UUIDD_CMT="" ++ AC_MSG_RESULT([Building uuidd]) ++fi] ++, ++AC_DEFINE(USE_UUIDD, 1) ++if test -z "$UUID_CMT" ++then ++ UUIDD_CMT="" ++ AC_MSG_RESULT([Building uuidd by default]) ++else ++ UUIDD_CMT="#" ++ AC_MSG_RESULT([Disabling uuidd by default]) ++fi ++) ++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 ++AC_SUBST_FILE(MAKEFILE_LIBRARY) ++dnl ++dnl Add internationalization support, using gettext. ++dnl ++GETTEXT_PACKAGE=e2fsprogs ++PACKAGE=e2fsprogs ++VERSION="$E2FSPROGS_VERSION" ++VERSION=0.14.1 ++AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [package name for gettext]) ++AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [version for gettext]) ++AC_SUBST(GETTEXT_PACKAGE) ++AC_SUBST(PACKAGE) ++AC_SUBST(VERSION) ++ ++AM_GNU_GETTEXT ++dnl ++dnl End of configuration options ++dnl ++AC_SUBST(BINARY_TYPE) ++AC_PROG_MAKE_SET ++CHECK_GNU_MAKE ++AC_PATH_PROG(LN, ln, ln) ++AC_PROG_LN_S ++AC_PATH_PROG(MV, mv, mv) ++AC_PATH_PROG(CP, cp, cp) ++AC_PATH_PROG(RM, rm, rm) ++AC_PATH_PROG(CHMOD, chmod, :) ++AC_PROG_AWK ++AC_PROG_EGREP ++AC_PATH_PROG(SED, sed, sed) ++AC_PATH_PROG(PERL, perl, perl) ++AC_PATH_PROG(LDCONFIG, ldconfig, :) ++AC_CHECK_TOOL(AR, ar, ar) ++AC_CHECK_TOOL(RANLIB, ranlib, :) ++AC_CHECK_TOOL(STRIP, strip, :) ++AC_CHECK_PROG(MAKEINFO, makeinfo, makeinfo, ) ++if test "_$MAKEINFO" = "_"; then ++ MAKEINFO="@echo Makeinfo is missing. Info documentation will not be built.;true" ++else ++ case "$MAKEINFO" in ++ */missing.*) ++ AC_MSG_WARN([ ++*** Makeinfo is missing. Info documentation will not be built.]) ++ ;; ++ *) ++ ;; ++ esac ++fi ++AC_SUBST(MAKEINFO) ++AC_PROG_INSTALL ++# See if we need a separate native compiler. ++if test $cross_compiling = no; then ++ BUILD_CC="$CC" ++ AC_SUBST(BUILD_CC) ++else ++ AC_CHECK_PROGS(BUILD_CC, gcc cc) ++fi ++AC_CHECK_HEADERS(m4_flatten([ ++ 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/acl.h ++ sys/disklabel.h ++ sys/disk.h ++ sys/file.h ++ sys/ioctl.h ++ sys/key.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/sysctl.h ++ sys/sysmacros.h ++ sys/time.h ++ sys/types.h ++ sys/un.h ++ sys/wait.h ++])) ++AC_CHECK_HEADERS(net/if.h,,, ++[[ ++#if HAVE_SYS_TYPES_H ++#include ++#endif ++#if HAVE_SYS_SOCKET ++#include ++#endif ++]]) ++AC_FUNC_VPRINTF ++dnl Check to see if dirent has member d_reclen. On cygwin those d_reclen ++dnl is not decleared. ++AC_CHECK_MEMBER(struct dirent.d_reclen,[AC_DEFINE(HAVE_RECLEN_DIRENT, 1, ++ [Define to 1 if dirent has d_reclen])],, ++ [#include ]) ++AC_CHECK_MEMBERS([struct stat.st_atim]) ++dnl Check to see if ssize_t was declared ++AC_CHECK_TYPE(ssize_t,[AC_DEFINE(HAVE_TYPE_SSIZE_T, 1, ++ [Define to 1 if ssize_t declared])],, ++ [#include ]) ++dnl ++dnl Check to see if llseek() is declared in unistd.h. On some libc's ++dnl it is, and on others it isn't..... Thank you glibc developers.... ++dnl ++AC_CHECK_DECL(llseek,[AC_DEFINE(HAVE_LLSEEK_PROTOTYPE, 1, ++ [Define to 1 if llseek declared in unistd.h])],, ++ [#include ]) ++dnl ++dnl Check to see if lseek64() is declared in unistd.h. Glibc's header files ++dnl are so convoluted that I can't tell whether it will always be defined, ++dnl and if it isn't defined while lseek64 is defined in the library, ++dnl disaster will strike. ++dnl ++dnl Warning! Use of --enable-gcc-wall may throw off this test. ++dnl ++dnl ++AC_CHECK_DECL(lseek64,[AC_DEFINE(HAVE_LSEEK64_PROTOTYPE, 1, ++ [Define to 1 if lseek64 declared in unistd.h])],, ++ [#define _LARGEFILE_SOURCE ++ #define _LARGEFILE64_SOURCE ++ #include ]) ++dnl ++dnl Word sizes... ++dnl ++AC_CHECK_SIZEOF(short) ++AC_CHECK_SIZEOF(int) ++AC_CHECK_SIZEOF(long) ++AC_CHECK_SIZEOF(long long) ++AC_CHECK_SIZEOF(off_t) ++SIZEOF_SHORT=$ac_cv_sizeof_short ++SIZEOF_INT=$ac_cv_sizeof_int ++SIZEOF_LONG=$ac_cv_sizeof_long ++SIZEOF_LONG_LONG=$ac_cv_sizeof_long_long ++SIZEOF_OFF_T=$ac_cv_sizeof_off_t ++AC_SUBST(SIZEOF_SHORT) ++AC_SUBST(SIZEOF_INT) ++AC_SUBST(SIZEOF_LONG) ++AC_SUBST(SIZEOF_LONG_LONG) ++AC_SUBST(SIZEOF_OFF_T) ++AC_C_BIGENDIAN ++if test $cross_compiling = no; then ++ BUILD_CC="$BUILD_CC" CPP="$CPP" /bin/sh $ac_aux_dir/parse-types.sh ++else ++ CROSS_COMPILE="1" BUILD_CC="$BUILD_CC" CPP="$CPP" /bin/sh $ac_aux_dir/parse-types.sh ++fi ++ASM_TYPES_HEADER=./asm_types.h ++AC_SUBST_FILE(ASM_TYPES_HEADER) ++dnl ++dnl Save the configuration #defines needed for the public ext2fs.h ++dnl header file ++dnl ++echo "/* These defines are needed for the public ext2fs.h header file */" \ ++ > public_config.h ++if grep HAVE_SYS_TYPES_H confdefs.h > tmp_config.$$; then ++ uniq tmp_config.$$ >> public_config.h ++else ++ echo "#undef HAVE_SYS_TYPES_H" >> public_config.h ++fi ++if grep WORDS_BIGENDIAN confdefs.h > tmp_config.$$; then ++ uniq tmp_config.$$ >> public_config.h ++else ++ echo "#undef WORDS_BIGENDIAN" >> public_config.h ++fi ++rm -f tmp_config.$$ ++PUBLIC_CONFIG_HEADER=./public_config.h ++AC_SUBST_FILE(PUBLIC_CONFIG_HEADER) ++dnl ++dnl See if we have inttypes.h and if intptr_t is defined ++dnl ++AC_CHECK_HEADERS([inttypes.h]) ++AC_CHECK_TYPES(intptr_t) ++dnl ++dnl See if struct stat has a st_flags field, in which case we can get file ++dnl flags somewhat portably. Also check for the analogous setter, chflags(). ++dnl ++AC_MSG_CHECKING(whether struct stat has a st_flags field) ++AC_CACHE_VAL(e2fsprogs_cv_struct_st_flags, ++ AC_TRY_COMPILE([#include ], ++ [struct stat stat; stat.st_flags = 0;], ++ [e2fsprogs_cv_struct_st_flags=yes], ++ [e2fsprogs_cv_struct_st_flags=no])) ++AC_MSG_RESULT($e2fsprogs_cv_struct_st_flags) ++if test "$e2fsprogs_cv_struct_st_flags" = yes; then ++ AC_MSG_CHECKING(whether st_flags field is useful) ++ AC_CACHE_VAL(e2fsprogs_cv_struct_st_flags_immut, ++ AC_TRY_COMPILE([#include ], ++ [struct stat stat; stat.st_flags |= UF_IMMUTABLE;], ++ [e2fsprogs_cv_struct_st_flags_immut=yes], ++ [e2fsprogs_cv_struct_st_flags_immut=no])) ++ AC_MSG_RESULT($e2fsprogs_cv_struct_st_flags_immut) ++ if test "$e2fsprogs_cv_struct_st_flags_immut" = yes; then ++ AC_DEFINE(HAVE_STAT_FLAGS, 1, ++ [Define to 1 if struct stat has st_flags]) ++ fi ++fi ++dnl ++dnl Check for the presence of SA_LEN ++dnl ++AC_CHECK_MEMBER(struct sockaddr.sa_len, ++ AC_DEFINE_UNQUOTED(HAVE_SA_LEN,1, ++ [Define to 1 if if struct sockaddr contains sa_len]),, ++ [#include ++ #include ]) ++dnl ++dnl This will add -lblkid to the AC_CHECK_FUNCS search if we are using ++dnl the system-provided blkid library ++dnl ++if test -n "$BLKID_CMT"; then ++ AC_SEARCH_LIBS([blkid_probe_all], [blkid]) ++fi ++dnl ++AC_CHECK_FUNCS(m4_flatten([ ++ __secure_getenv ++ add_key ++ 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 ++ keyctl ++ 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 ++ utimes ++ valloc ++])) ++dnl ++dnl Check to see if -lsocket is required (solaris) to make something ++dnl that uses socket() to compile; this is needed for the UUID library ++dnl ++SOCKET_LIB='' ++AC_CHECK_LIB(socket, socket, [SOCKET_LIB=-lsocket]) ++AC_SUBST(SOCKET_LIB) ++dnl ++dnl See if libmagic exists ++dnl ++AC_CHECK_LIB(magic, magic_file, [MAGIC_LIB=-lmagic ++AC_CHECK_HEADERS([magic.h])]) ++if test "$ac_cv_lib_dl_dlopen" = yes ; then ++ MAGIC_LIB=$DLOPEN_LIB ++fi ++AC_SUBST(MAGIC_LIB) ++dnl ++dnl Check to see if the FUSE library is -lfuse or -losxfuse ++dnl ++FUSE_CMT= ++FUSE_LIB= ++dnl osxfuse.dylib supersedes fuselib.dylib ++AC_ARG_ENABLE([fuse2fs], ++[ --disable-fuse2fs do not build fuse2fs], ++if test "$enableval" = "no" ++then ++ FUSE_CMT="#" ++ AC_MSG_RESULT([Disabling fuse2fs]) ++else ++ AC_CHECK_HEADERS([pthread.h fuse.h], [], ++[AC_MSG_FAILURE([Cannot find fuse2fs headers.])], ++[#define _FILE_OFFSET_BITS 64 ++#define FUSE_USE_VERSION 29]) ++ ++ AC_PREPROC_IFELSE( ++[AC_LANG_PROGRAM([[#define FUSE_USE_VERSION 29 ++#ifdef __linux__ ++#include ++#include ++#include ++#endif ++]], [])], [], [AC_MSG_FAILURE([Cannot find fuse2fs Linux headers.])]) ++ ++ AC_CHECK_LIB(osxfuse, fuse_main, [FUSE_LIB=-losxfuse], ++ [AC_CHECK_LIB(fuse, fuse_main, [FUSE_LIB=-lfuse], ++ [AC_MSG_FAILURE([Cannot find fuse library.])])]) ++ AC_MSG_RESULT([Enabling fuse2fs]) ++fi ++, ++AC_CHECK_HEADERS([pthread.h fuse.h], [], [FUSE_CMT="#"], ++[#define _FILE_OFFSET_BITS 64 ++#define FUSE_USE_VERSION 29 ++#ifdef __linux__ ++# include ++# include ++# include ++#endif]) ++if test -z "$FUSE_CMT" ++then ++ AC_CHECK_LIB(osxfuse, fuse_main, [FUSE_LIB=-losxfuse], ++[AC_CHECK_LIB(fuse, fuse_main, [FUSE_LIB=-lfuse], [FUSE_CMT="#"])]) ++fi ++if test -z "$FUSE_CMT" ++then ++ AC_MSG_RESULT([Enabling fuse2fs by default.]) ++fi ++) ++AC_SUBST(FUSE_LIB) ++AC_SUBST(FUSE_CMT) ++dnl ++dnl See if optreset exists ++dnl ++AC_MSG_CHECKING(for optreset) ++AC_CACHE_VAL(ac_cv_have_optreset, ++[AC_EGREP_HEADER(optreset, unistd.h, ++ ac_cv_have_optreset=yes, ac_cv_have_optreset=no)])dnl ++AC_MSG_RESULT($ac_cv_have_optreset) ++if test $ac_cv_have_optreset = yes; then ++ AC_DEFINE(HAVE_OPTRESET, 1, [Define to 1 if optreset for getopt is present]) ++fi ++dnl ++dnl Test for sem_init, and which library it might require: ++dnl ++AH_TEMPLATE([HAVE_SEM_INIT], [Define to 1 if sem_init() exists]) ++SEM_INIT_LIB='' ++AC_CHECK_FUNC(sem_init, , ++ AC_CHECK_LIB(pthread, sem_init, ++ AC_DEFINE(HAVE_SEM_INIT, 1) ++ SEM_INIT_LIB=-lpthread, ++ AC_CHECK_LIB(rt, sem_init, ++ AC_DEFINE(HAVE_SEM_INIT, 1) ++ SEM_INIT_LIB=-lrt, ++ AC_CHECK_LIB(posix4, sem_init, ++ AC_DEFINE(HAVE_SEM_INIT, 1) ++ SEM_INIT_LIB=-lposix4))))dnl ++AC_SUBST(SEM_INIT_LIB) ++dnl ++dnl Check for unified diff ++dnl ++AC_MSG_CHECKING(for unified diff option) ++if diff -u $0 $0 > /dev/null 2>&1 ; then ++ UNI_DIFF_OPTS=-u ++else ++ UNI_DIFF_OPTS=-c ++fi ++AC_MSG_RESULT($UNI_DIFF_OPTS) ++AC_SUBST(UNI_DIFF_OPTS) ++dnl ++dnl We use the EXT2 ioctls only under Linux ++dnl ++case "$host_os" in ++linux*) ++ AC_DEFINE(HAVE_EXT2_IOCTLS, 1, [Define to 1 if Ext2 ioctls present]) ++ ;; ++esac ++dnl ++dnl OS-specific uncomment control ++dnl ++LINUX_CMT="#" ++CYGWIN_CMT="#" ++UNIX_CMT= ++case "$host_os" in ++linux*) ++ LINUX_CMT= ++ ;; ++cygwin) ++ CYGWIN_CMT= ++ UNIX_CMT="#" ++ ;; ++esac ++AC_SUBST(LINUX_CMT) ++AC_SUBST(CYGWIN_CMT) ++AC_SUBST(UNIX_CMT) ++dnl ++dnl Linux and Hurd places root files in the / by default ++dnl ++case "$host_os" in ++linux* | gnu* | k*bsd*-gnu) ++ if test "$prefix" = NONE -a "$root_prefix" = NONE ; then ++ root_prefix=""; ++ AC_MSG_RESULT([On $host_os systems, root_prefix defaults to '']) ++ fi ++ ;; ++esac ++dnl ++dnl On Linux/hurd, force the prefix to be /usr ++dnl ++case "$host_os" in ++linux* | gnu* | k*bsd*-gnu) ++ if test "$prefix" = NONE ; then ++ prefix="/usr"; ++ AC_MSG_RESULT([On $host_os systems, prefix defaults to /usr]) ++ if test "$mandir" = '${prefix}/man' ; then ++ AC_MSG_RESULT([...and mandir defaults to /usr/share/man]) ++ mandir=/usr/share/man ++ fi ++ fi ++;; ++esac ++if test "$root_prefix" = NONE ; then ++ if test "$prefix" = NONE ; then ++ root_prefix="$ac_default_prefix" ++ else ++ root_prefix="$prefix" ++ fi ++ root_bindir=$bindir ++ root_sbindir=$sbindir ++ root_libdir=$libdir ++ root_sysconfdir=$sysconfdir ++else ++ root_bindir='${root_prefix}/bin' ++ root_sbindir='${root_prefix}/sbin' ++ root_libdir='${root_prefix}/lib' ++ root_sysconfdir='${root_prefix}/etc' ++fi ++if test "$bindir" != '${exec_prefix}/bin'; then ++ root_bindir=$bindir ++ AC_MSG_RESULT([Setting root_bindir to $root_bindir]) ++fi ++if test "$sbindir" != '${exec_prefix}/sbin'; then ++ root_sbindir=$sbindir ++ AC_MSG_RESULT([Setting root_sbindir to $root_sbindir]) ++fi ++if test "$libdir" != '${exec_prefix}/lib'; then ++ root_libdir=$libdir ++ AC_MSG_RESULT([Setting root_libdir to $root_libdir]) ++fi ++if test "$sysconfdir" != '${prefix}/etc'; then ++ root_sysconfdir=$sysconfdir ++ AC_MSG_RESULT([Setting root_sysconfdir to $root_sysconfdir]) ++fi ++AC_SUBST(root_prefix) ++AC_SUBST(root_bindir) ++AC_SUBST(root_sbindir) ++AC_SUBST(root_libdir) ++AC_SUBST(root_sysconfdir) ++dnl ++dnl Allow specification of the multiarch arch ++dnl ++AC_ARG_WITH([multiarch], ++[ --with-multiarch=ARCH specify the multiarch triplet], ++if test "$withval" = "lib64"; then ++ libdir=/usr/lib64 ++ root_libdir=/lib64 ++else ++ libdir=$libdir/$withval ++ root_libdir=$root_libdir/$withval ++fi ++)dnl ++dnl ++dnl See if -static works. This could fail if the linker does not ++dnl support -static, or if required external libraries are not available ++dnl in static form. ++dnl ++AC_MSG_CHECKING([whether we can link with -static]) ++AC_CACHE_VAL(ac_cv_e2fsprogs_use_static, ++[SAVE_LDFLAGS=$LDFLAGS; LDFLAGS="$LDFLAGS -static" ++AC_TRY_LINK([#include ],[fflush(stdout);], ++ ac_cv_e2fsprogs_use_static=yes, ac_cv_e2fsprogs_use_static=no) ++LDFLAGS=$SAVE_LDFLAGS]) ++dnl ++dnl Regardless of how the test turns out, Solaris doesn't handle -static ++dnl This is caused by the socket library requiring the nsl library, which ++dnl requires the -dl library, which only works for dynamically linked ++dnl programs. It basically means you can't have statically linked programs ++dnl which use the network under Solaris. ++dnl ++case "$host_os" in ++solaris2.*) ++ ac_cv_e2fsprogs_use_static=no ++;; ++esac ++AC_MSG_RESULT($ac_cv_e2fsprogs_use_static) ++LDFLAG_STATIC= ++if test $ac_cv_e2fsprogs_use_static = yes; then ++ LDFLAG_STATIC=-static ++fi ++AC_SUBST(LDFLAG_STATIC) ++dnl ++dnl Work around mysterious Darwin / GNU libintl problem ++dnl (__asm__ redirection doesn't work for some mysterious reason. Looks like ++dnl Apple hacked gcc somehow?) ++dnl ++case "$host_os" in ++darwin*) ++ AC_MSG_RESULT([Using Apple Darwin / GNU libintl workaround]) ++ AC_DEFINE(_INTL_REDIRECT_MACROS, 1, ++ [Define to 1 if Apple Darwin libintl workaround is needed]) ++ ;; ++esac ++dnl ++dnl Make the ss and et directories work correctly. ++dnl ++SS_DIR=`cd ${srcdir}/lib/ss; pwd` ++ET_DIR=`cd ${srcdir}/lib/et; pwd` ++AC_SUBST(SS_DIR) ++AC_SUBST(ET_DIR) ++dnl ++dnl Only try to run the test suite if we're not cross compiling. ++dnl ++if test "$cross_compiling" = yes ; then ++ DO_TEST_SUITE= ++else ++ DO_TEST_SUITE=check ++fi ++AC_SUBST(DO_TEST_SUITE) ++dnl ++dnl Only include the intl include files if we're building with them ++dnl ++INCLUDES='-I. -I$(top_builddir)/lib -I$(top_srcdir)/lib' ++if test -n "$CPPFLAGS" ; then ++ INCLUDES="$INCLUDES $CPPFLAGS" ++fi ++if test "$USE_INCLUDED_LIBINTL" = "yes" ; then ++ INCLUDES=$INCLUDES' -I$(top_builddir)/intl -I$(top_srcdir)/intl' ++fi ++if test -n "$WITH_DIET_LIBC" ; then ++ INCLUDES="$INCLUDES -D_REENTRANT" ++fi ++AC_SUBST(INCLUDES) ++AM_MKINSTALLDIRS ++dnl ++dnl Build CFLAGS ++dnl ++if test $cross_compiling = no; then ++ BUILD_CFLAGS="$CFLAGS $CPPFLAGS $INCLUDES -DHAVE_CONFIG_H" ++ BUILD_LDFLAGS="$LDFLAGS" ++fi ++AC_SUBST(BUILD_CFLAGS) ++AC_SUBST(BUILD_LDFLAGS) ++dnl ++dnl Make our output files, being sure that we create the some miscellaneous ++dnl directories ++dnl ++test -d lib || mkdir lib ++test -d include || mkdir include ++test -d include/linux || mkdir include/linux ++test -d include/asm || mkdir include/asm ++if test -z "$UUID_CMT" ; then ++ uuid_out_list="lib/uuid/Makefile lib/uuid/uuid.pc \ ++ lib/uuid/uuid_types.h" ++fi ++if test -z "$BLKID_CMT" ; then ++ blkid_out_list="lib/blkid/Makefile lib/blkid/blkid.pc \ ++ lib/blkid/blkid_types.h" ++fi ++for i in MCONFIG Makefile e2fsprogs.spec \ ++ util/Makefile util/subst.conf util/gen-tarball util/install-symlink \ ++ lib/et/Makefile lib/ss/Makefile lib/e2p/Makefile \ ++ lib/ext2fs/Makefile lib/ext2fs/ext2_types.h \ ++ $uuid_out_list $blkid_out_list lib/support/Makefile \ ++ lib/ss/ss.pc lib/et/com_err.pc lib/e2p/e2p.pc lib/ext2fs/ext2fs.pc \ ++ misc/Makefile ext2ed/Makefile e2fsck/Makefile \ ++ debugfs/Makefile tests/Makefile tests/progs/Makefile \ ++ resize/Makefile doc/Makefile intl/Makefile \ ++ intl/libgnuintl.h po/Makefile.in ; do ++ if test -d `dirname ${srcdir}/$i` ; then ++ outlist="$outlist $i" ++ fi ++done ++AC_OUTPUT($outlist) ++if test -f util/gen-tarball; then chmod +x util/gen-tarball; fi +--- a/configure.in ++++ /dev/null +@@ -1,1346 +0,0 @@ +-AC_INIT(version.h) +-AC_PREREQ(2.54) +-AC_CONFIG_AUX_DIR(config) +-AC_CONFIG_HEADERS([lib/config.h]) +-AH_BOTTOM([#include ]) +-MCONFIG=./MCONFIG +-AC_SUBST_FILE(MCONFIG) +-BINARY_TYPE=bin +-dnl +-dnl This is to figure out the version number and the date.... +-dnl +-E2FSPROGS_VERSION=`grep E2FSPROGS_VERSION ${srcdir}/version.h \ +- | awk '{print $3}' | tr \" " " | awk '{print $1}'` +-DATE=`grep E2FSPROGS_DATE ${srcdir}/version.h | awk '{print $3}' \ +- | tr \" " "` +-E2FSPROGS_DAY=`echo $DATE | awk -F- '{print $1}'` +-MONTH=`echo $DATE | awk -F- '{print $2}'` +-YEAR=`echo $DATE | awk -F- '{print $3}'` +- +-if expr $YEAR ">" 1900 > /dev/null ; then +- E2FSPROGS_YEAR=$YEAR +-elif expr $YEAR ">" 90 >/dev/null ; then +- E2FSPROGS_YEAR=19$YEAR +-else +- E2FSPROGS_YEAR=20$YEAR +-fi +- +-case $MONTH in +-Jan) MONTH_NUM=01; E2FSPROGS_MONTH="January" ;; +-Feb) MONTH_NUM=02; E2FSPROGS_MONTH="February" ;; +-Mar) MONTH_NUM=03; E2FSPROGS_MONTH="March" ;; +-Apr) MONTH_NUM=04; E2FSPROGS_MONTH="April" ;; +-May) MONTH_NUM=05; E2FSPROGS_MONTH="May" ;; +-Jun) MONTH_NUM=06; E2FSPROGS_MONTH="June" ;; +-Jul) MONTH_NUM=07; E2FSPROGS_MONTH="July" ;; +-Aug) MONTH_NUM=08; E2FSPROGS_MONTH="August" ;; +-Sep) MONTH_NUM=09; E2FSPROGS_MONTH="September" ;; +-Oct) MONTH_NUM=10; E2FSPROGS_MONTH="October" ;; +-Nov) MONTH_NUM=11; E2FSPROGS_MONTH="November" ;; +-Dec) MONTH_NUM=12; E2FSPROGS_MONTH="December" ;; +-*) AC_MSG_WARN([Unknown month $MONTH??]) ;; +-esac +- +-base_ver=`echo $E2FSPROGS_VERSION | \ +- sed -e 's/-WIP//' -e 's/pre-//' -e 's/-PLUS//'` +- +-date_spec=${E2FSPROGS_YEAR}.${MONTH_NUM}.${E2FSPROGS_DAY} +- +-case $E2FSPROGS_VERSION in +-*-WIP|pre-*) +- E2FSPROGS_PKGVER="$base_ver~WIP-$E2FSPROGS_YEAR-$MONTH_NUM-$E2FSPROGS_DAY" +- ;; +-*) +- E2FSPROGS_PKGVER="$base_ver" +- ;; +-esac +- +-unset DATE MONTH YEAR base_ver pre_vers date_spec +-AC_MSG_RESULT([Generating configuration file for e2fsprogs version $E2FSPROGS_VERSION]) +-AC_MSG_RESULT([Release date is ${E2FSPROGS_MONTH}, ${E2FSPROGS_YEAR}]) +-AC_SUBST(E2FSPROGS_YEAR) +-AC_SUBST(E2FSPROGS_MONTH) +-AC_SUBST(E2FSPROGS_DAY) +-AC_SUBST(E2FSPROGS_VERSION) +-AC_SUBST(E2FSPROGS_PKGVER) +-dnl +-dnl Use diet libc +-dnl +-WITH_DIET_LIBC= +-AC_ARG_WITH([diet-libc], +-[ --with-diet-libc use diet libc], +-CC="diet cc -nostdinc" +-WITH_DIET_LIBC=yes +-if test -z "$LIBS" +-then +- LIBS="-lcompat" +-else +- LIBS="$LIBS -lcompat" +-fi +-AC_MSG_RESULT(CC=$CC))dnl +-dnl +-AC_CANONICAL_HOST +-dnl +-dnl Check to see if libdl exists for the sake of dlopen +-dnl +-DLOPEN_LIB='' +-AC_CHECK_LIB(dl, dlopen, +-[DLOPEN_LIB=-ldl +-AC_DEFINE(HAVE_DLOPEN, 1, [Define to 1 if dlopen/libdl exists])]) +-AC_SUBST(DLOPEN_LIB) +-dnl +-AC_ARG_WITH([cc], +-AC_HELP_STRING([--with-cc],[no longer supported, use CC= instead]), +-AC_MSG_ERROR([--with-cc no longer supported; use CC= instead])) +-dnl +-AC_ARG_WITH([ccopts], +-AC_HELP_STRING([--with-ccopts],[no longer supported, use CFLAGS= instead]), +-AC_MSG_ERROR([--with-ccopts no longer supported; use CFLAGS= instead])) +-dnl +-AC_ARG_WITH([ldopts], +-AC_HELP_STRING([--with-ldopts],[no longer supported, use LDFLAGS= instead]), +-AC_MSG_ERROR([--with-ldopts no longer supported; use LDFLAGS= instead])) +-dnl +-AC_PROG_CC +-if test "$GCC" = yes; then +- RDYNAMIC="-rdynamic" +- AC_SUBST(RDYNAMIC) +-fi +-AC_PROG_CPP +-dnl +-dnl Alpha computers use fast and imprecise floating point code that may +-dnl miss exceptions by default. Force sane options if we're using GCC. +-AC_MSG_CHECKING(for additional special compiler flags) +-if test "$GCC" = yes +-then +- case "$host_cpu" in +- alpha) addcflags="-mieee" ;; +- esac +-fi +-if test "x$addcflags" != x +-then +- AC_MSG_RESULT($addcflags) +- CFLAGS="$addcflags $CFLAGS" +-else +- AC_MSG_RESULT([[(none)]]) +-fi +-AC_USE_SYSTEM_EXTENSIONS +-dnl +-dnl Set default values for library extentions. Will be dealt with after +-dnl parsing configuration opions, which may modify these +-dnl +-LIB_EXT=.a +-STATIC_LIB_EXT=.a +-PROFILED_LIB_EXT=.a +-dnl +-dnl Allow separate `root_prefix' to be specified +-dnl +-AC_ARG_WITH([root-prefix], +-[ --with-root-prefix=PREFIX override prefix variable for files to be placed in the root], +-root_prefix=$withval, +-root_prefix=NONE)dnl +-dnl +-dnl handle --enable-maintainer-mode +-dnl +-AC_ARG_ENABLE([maintainer-mode], +-[ --enable-maintainer-mode enable makefile rules useful for maintainers], +-if test "$enableval" = "no" +-then +- MAINTAINER_CMT=# +- AC_MSG_RESULT([Disabling maintainer mode]) +-else +- MAINTAINER_CMT= +- AC_MSG_RESULT([Enabling maintainer mode]) +-fi +-, +-MAINTAINER_CMT=# +-AC_MSG_RESULT([Disabling maintainer mode by default]) +-) +-AC_SUBST(MAINTAINER_CMT) +-dnl +-dnl handle --enable-symlink-install +-dnl +-AC_ARG_ENABLE([symlink-install], +-[ --enable-symlink-install use symlinks when installing instead of hard links], +-if test "$enableval" = "no" +-then +- LINK_INSTALL_FLAGS=-f +- AC_MSG_RESULT([Disabling symlinks for install]) +-else +- LINK_INSTALL_FLAGS=-sf +- AC_MSG_RESULT([Enabling symlinks for install]) +-fi +-, +-LINK_INSTALL_FLAGS=-f +-AC_MSG_RESULT([Disabling symlinks for install by default]) +-) +-AC_SUBST(LINK_INSTALL_FLAGS) +-dnl +-dnl handle --enable-relative-symlinks +-dnl +-relative_symlink_defined= +-AC_ARG_ENABLE([relative-symlinks], +-[ --enable-relative-symlinks use relative symlinks when installing], +-if test "$enableval" = "no" +-then +- SYMLINK_RELATIVE= +- relative_symlink_defined=yes +- AC_MSG_RESULT([Disabling relative symlinks for install]) +-else +- SYMLINK_RELATIVE=--relative +- relative_symlink_defined=yes +- AC_MSG_RESULT([Enabling relative symlinks for install]) +-fi) +-AC_ARG_ENABLE([symlink-relative-symlinks],, +-if test "$enableval" = "no" +-then +- SYMLINK_RELATIVE=yes +- AC_MSG_RESULT([Disabling relative symlinks for install]) +-else +- SYMLINK_RELATIVE=--relative +- AC_MSG_RESULT([Enabling relative symlinks for install]) +-fi +-, +-if test -z "$relative_symlink_defined" +-then +- SYMLINK_RELATIVE= +-AC_MSG_RESULT([Disabling relative symlinks for install by default]) +-fi +-) +-AC_SUBST(SYMLINK_RELATIVE) +-dnl +-dnl handle --enable-symlink-build +-dnl +-AC_ARG_ENABLE([symlink-build], +-[ --enable-symlink-build use symlinks while building instead of hard links], +-if test "$enableval" = "no" +-then +- LINK_BUILD_FLAGS= +- AC_MSG_RESULT([Disabling symlinks for build]) +-else +- LINK_BUILD_FLAGS=-s +- AC_MSG_RESULT([Enabling symlinks for build]) +-fi +-, +-LINK_BUILD_FLAGS= +-AC_MSG_RESULT([Disabling symlinks for build by default]) +-) +-AC_SUBST(LINK_BUILD_FLAGS) +-dnl +-dnl handle --enable-verbose-makecmds +-dnl +-AC_ARG_ENABLE([verbose-makecmds], +-[ --enable-verbose-makecmds enable verbose make command output], +-if test "$enableval" = "no" +-then +- AC_MSG_RESULT([Disabling verbose make commands]) +- E=@echo +- ES=echo +- Q=@ +-else +- AC_MSG_RESULT([Enabling verbose make commands]) +- E=@\\# +- ES=\\# +- Q= +-fi +-, +-AC_MSG_RESULT([Disabling verbose make commands]) +-E=@echo +-ES=echo +-Q=@ +-) +-AC_SUBST(E) +-AC_SUBST(ES) +-AC_SUBST(Q) +-dnl +-dnl handle --enable-compression +-dnl +-AC_ARG_ENABLE([compression], +-[ --enable-compression enable EXPERIMENTAL compression support], +-if test "$enableval" = "no" +-then +- AC_MSG_RESULT([Disabling compression support]) +-else +- AC_DEFINE(ENABLE_COMPRESSION, 1, +- [Define to 1 if ext2 compression enabled]) +- AC_MSG_RESULT([Enabling compression support]) +- AC_MSG_WARN([Compression support is experimental]) +-fi +-, +-AC_MSG_RESULT([Disabling compression support by default]) +-) +-dnl +-dnl handle --enable-htree +-dnl +-AH_TEMPLATE([ENABLE_HTREE], [Define to 1 if ext3/4 htree support enabled]) +-AC_ARG_ENABLE([htree], +-[ --enable-htree enable EXPERIMENTAL htree directory support], +-if test "$enableval" = "no" +-then +- HTREE_CMT=# +- AC_MSG_RESULT([Disabling htree directory support]) +-else +- HTREE_CMT= +- AC_DEFINE(ENABLE_HTREE, 1) +- AC_MSG_RESULT([Enabling htree directory support]) +-fi +-, +-HTREE_CMT= +-AC_DEFINE(ENABLE_HTREE, 1) +-AC_MSG_RESULT([Enabling htree directory support by default]) +-) +-AC_SUBST(HTREE_CMT) +-dnl +-dnl This needs to be before all of the --enable-*-shlibs options +-dnl +-E2_PKG_CONFIG_STATIC=--static +-LDFLAG_DYNAMIC= +-PRIVATE_LIBS_CMT= +-dnl +-dnl handle --enable-elf-shlibs +-dnl +-AC_ARG_ENABLE([elf-shlibs], +-[ --enable-elf-shlibs select ELF shared libraries], +-if test "$enableval" = "no" +-then +- ELF_CMT=# +- MAKEFILE_ELF=/dev/null +- AC_MSG_RESULT([Disabling ELF shared libraries]) +-else +- E2_PKG_CONFIG_STATIC= +- ELF_CMT= +- MAKEFILE_ELF=$srcdir/lib/Makefile.elf-lib +- [case "$host_os" in +- solaris2.*) +- MAKEFILE_ELF=$srcdir/lib/Makefile.solaris-lib +- ;; +- esac] +- BINARY_TYPE=elfbin +- LIB_EXT=.so +- PRIVATE_LIBS_CMT=# +- LDFLAG_DYNAMIC=['-Wl,-rpath-link,$(top_builddir)/lib'] +- AC_MSG_RESULT([Enabling ELF shared libraries]) +-fi +-, +-MAKEFILE_ELF=/dev/null +-ELF_CMT=# +-AC_MSG_RESULT([Disabling ELF shared libraries by default]) +-) +-AC_SUBST(ELF_CMT) +-AC_SUBST_FILE(MAKEFILE_ELF) +-dnl +-dnl handle --enable-bsd-shlibs +-dnl +-AC_ARG_ENABLE([bsd-shlibs], +-[ --enable-bsd-shlibs select BSD shared libraries], +-if test "$enableval" = "no" +-then +- BSDLIB_CMT=# +- MAKEFILE_BSDLIB=/dev/null +- AC_MSG_RESULT([Disabling BSD shared libraries]) +-else +- E2_PKG_CONFIG_STATIC= +- BSDLIB_CMT= +- MAKEFILE_BSDLIB=$srcdir/lib/Makefile.bsd-lib +- LIB_EXT=.so +- [case "$host_os" in +- darwin*) +- MAKEFILE_BSDLIB=$srcdir/lib/Makefile.darwin-lib +- LIB_EXT=.dylib +- ;; +- esac] +- AC_MSG_RESULT([Enabling BSD shared libraries]) +-fi +-, +-MAKEFILE_BSDLIB=/dev/null +-BSDLIB_CMT=# +-AC_MSG_RESULT([Disabling BSD shared libraries by default]) +-) +-AC_SUBST(BSDLIB_CMT) +-AC_SUBST_FILE(MAKEFILE_BSDLIB) +-dnl +-dnl handle --enable-profile +-dnl +-AC_ARG_ENABLE([profile], +-[ --enable-profile build profiling libraries], +-if test "$enableval" = "no" +-then +- PROFILE_CMT=# +- MAKEFILE_PROFILE=/dev/null +- AC_MSG_RESULT([Disabling profiling libraries]) +-else +- PROFILE_CMT= +- MAKEFILE_PROFILE=$srcdir/lib/Makefile.profile +- PROFILED_LIB_EXT=_p.a +- AC_MSG_RESULT([Building profiling libraries]) +-fi +-, +-PROFILE_CMT=# +-MAKEFILE_PROFILE=/dev/null +-AC_MSG_RESULT([Disabling profiling libraries by default]) +-) +-AC_SUBST(PROFILE_CMT) +-AC_SUBST_FILE(MAKEFILE_PROFILE) +-dnl +-dnl handle --enable-gcov +-dnl +-AC_ARG_ENABLE([gcov], +-[ --enable-gcov build for coverage testing using gcov], +-if test "$enableval" = "yes" +-then +- CFLAGS="-g -fprofile-arcs -ftest-coverage" +- LDFLAGS="-fprofile-arcs -ftest-coverage" +- AC_MSG_RESULT([Enabling gcov support]) +-fi +-) +- +-dnl +-dnl Substitute library extensions +-dnl +-AC_SUBST(LIB_EXT) +-AC_SUBST(STATIC_LIB_EXT) +-AC_SUBST(PROFILED_LIB_EXT) +-AC_SUBST(LDFLAG_DYNAMIC) +-AC_SUBST(PRIVATE_LIBS_CMT) +-dnl +-dnl handle --enable-jbd-debug +-dnl +-AC_ARG_ENABLE([jbd-debug], +-[ --enable-jbd-debug enable journal debugging], +-if test "$enableval" = "no" +-then +- AC_MSG_RESULT([Disabling journal debugging]) +-else +- AC_DEFINE(CONFIG_JBD_DEBUG, 1, +- [Define to 1 if debugging ext3/4 journal code]) +- AC_MSG_RESULT([Enabling journal debugging]) +-fi +-, +-AC_MSG_RESULT([Disabling journal debugging by default]) +-) +-dnl +-dnl handle --enable-blkid-debug +-dnl +-AC_ARG_ENABLE([blkid-debug], +-[ --enable-blkid-debug enable blkid debugging], +-if test "$enableval" = "no" +-then +- AC_MSG_RESULT([Disabling blkid debugging]) +-else +- AC_DEFINE(CONFIG_BLKID_DEBUG, 1, +- [Define to 1 if debugging the blkid library]) +- AC_MSG_RESULT([Enabling blkid debugging]) +-fi +-, +-AC_MSG_RESULT([Disabling blkid debugging by default]) +-) +-dnl +-dnl handle --enable-testio-debug +-dnl +-AC_ARG_ENABLE([testio-debug], +-[ --disable-testio-debug disable the use of the test I/O manager for debugging], +-AH_TEMPLATE([CONFIG_TESTIO_DEBUG], +- [Define to 1 if the testio I/O manager should be enabled]) +-if test "$enableval" = "no" +-then +- AC_MSG_RESULT([Disabling testio debugging]) +- TEST_IO_CMT="#" +-else +- TEST_IO_CMT= +- AC_DEFINE(CONFIG_TESTIO_DEBUG, 1) +- AC_MSG_RESULT([Enabling testio debugging]) +-fi +-, +-AC_MSG_RESULT([Enabling testio debugging by default]) +-AC_DEFINE(CONFIG_TESTIO_DEBUG, 1) +-TEST_IO_CMT= +-) +-AC_SUBST(TEST_IO_CMT) +-dnl +-dnl handle --disable-libuuid +-dnl +-PKG_PROG_PKG_CONFIG +-LIBUUID= +-DEPLIBUUID= +-STATIC_LIBUUID= +-DEPSTATIC_LIBUUID= +-PROFILED_LIBUUID= +-DEPPROFILED_LIBUUID= +-UUID_CMT= +-AC_ARG_ENABLE([libuuid], +-[ --disable-libuuid do not build private uuid library], +-if test "$enableval" = "no" +-then +- if test -z "$PKG_CONFIG"; then +- AC_MSG_ERROR([pkg-config not installed; please install it.]) +- fi +- +- AC_CHECK_LIB(uuid, uuid_generate, +- [LIBUUID=`$PKG_CONFIG --libs uuid`; +- STATIC_LIBUUID=`$PKG_CONFIG --static --libs uuid`], +- [AC_MSG_ERROR([external uuid library not found])]) +- PROFILED_LIBUUID=$LIBUUID +- UUID_CMT=# +- AC_MSG_RESULT([Disabling private uuid library]) +-else +- LIBUUID='$(LIB)/libuuid'$LIB_EXT +- DEPLIBUUID=$LIBUUID +- STATIC_LIBUUID='$(LIB)/libuuid'$STATIC_LIB_EXT +- DEPSTATIC_LIBUUID=$STATIC_LIBUUID +- PROFILED_LIBUUID='$(LIB)/libuuid'$PROFILED_LIB_EXT +- DEPPROFILED_LIBUUID=$PROFILED_LIBUUID +- AC_MSG_RESULT([Enabling private uuid library]) +-fi +-, +-LIBUUID='$(LIB)/libuuid'$LIB_EXT +-DEPLIBUUID=$LIBUUID +-STATIC_LIBUUID='$(LIB)/libuuid'$STATIC_LIB_EXT +-DEPSTATIC_LIBUUID=$STATIC_LIBUUID +-PROFILED_LIBUUID='$(LIB)/libuuid'$PROFILED_LIB_EXT +-DEPPROFILED_LIBUUID=$PROFILED_LIBUUID +-AC_MSG_RESULT([Enabling private uuid library by default]) +-) +-AC_SUBST(LIBUUID) +-AC_SUBST(DEPLIBUUID) +-AC_SUBST(STATIC_LIBUUID) +-AC_SUBST(DEPSTATIC_LIBUUID) +-AC_SUBST(PROFILED_LIBUUID) +-AC_SUBST(DEPPROFILED_LIBUUID) +-AC_SUBST(UUID_CMT) +-dnl +-dnl handle --disable-libblkid +-dnl +-PKG_PROG_PKG_CONFIG +-LIBBLKID= +-DEPLIBBLKID= +-STATIC_LIBBLKID= +-DEPSTATIC_LIBBLKID= +-PROFILED_LIBBLKID= +-DEPPROFILED_LIBBLKID= +-BLKID_CMT= +-AH_TEMPLATE([CONFIG_BUILD_FINDFS], [Define to 1 to compile findfs]) +-AC_ARG_ENABLE([libblkid], +-[ --disable-libblkid do not build private blkid library], +-if test "$enableval" = "no" +-then +- if test -z "$PKG_CONFIG"; then +- AC_MSG_ERROR([pkg-config not installed; please install it.]) +- fi +- +- AC_CHECK_LIB(blkid, blkid_get_cache, +- [LIBBLKID=`$PKG_CONFIG --libs blkid`; +- STATIC_LIBBLKID=`$PKG_CONFIG --static --libs blkid`], +- [AC_MSG_ERROR([external blkid library not found])], -luuid) +- BLKID_CMT=# +- PROFILED_LIBBLKID=$LIBBLKID +- AC_MSG_RESULT([Disabling private blkid library]) +-else +- LIBBLKID='$(LIB)/libblkid'$LIB_EXT +- DEPLIBBLKID=$LIBBLKID +- STATIC_LIBBLKID='$(LIB)/libblkid'$STATIC_LIB_EXT +- DEPSTATIC_LIBBLKID=$STATIC_LIBBLKID +- PROFILED_LIBBLKID='$(LIB)/libblkid'$PROFILED_LIB_EXT +- DEPPROFILED_LIBBLKID=$PROFILED_LIBBLKID +- AC_DEFINE(CONFIG_BUILD_FINDFS, 1) +- AC_MSG_RESULT([Enabling private blkid library]) +-fi +-, +-LIBBLKID='$(LIB)/libblkid'$LIB_EXT +-DEPLIBBLKID=$LIBBLKID +-STATIC_LIBBLKID='$(LIB)/libblkid'$STATIC_LIB_EXT +-DEPSTATIC_LIBBLKID=$STATIC_LIBBLKID +-PROFILED_LIBBLKID='$(LIB)/libblkid'$PROFILED_LIB_EXT +-DEPPROFILED_LIBBLKID=$PROFILED_LIBBLKID +-AC_DEFINE(CONFIG_BUILD_FINDFS, 1) +-AC_MSG_RESULT([Enabling private blkid library by default]) +-) +-AC_SUBST(LIBBLKID) +-AC_SUBST(DEPLIBBLKID) +-AC_SUBST(STATIC_LIBBLKID) +-AC_SUBST(DEPSTATIC_LIBBLKID) +-AC_SUBST(PROFILED_LIBBLKID) +-AC_SUBST(DEPPROFILED_LIBBLKID) +-AC_SUBST(BLKID_CMT) +-dnl +-dnl handle --enable-quota +-dnl +-QUOTA_MAN_COMMENT='.\"' +-QUOTA_CMT= +-AC_SUBST(QUOTA_MAN_COMMENT) +-PKG_PROG_PKG_CONFIG +-AH_TEMPLATE([CONFIG_QUOTA], [Define to 1 to enable quota support]) +-AC_ARG_ENABLE([quota], +-[ --enable-quota enable quota support], +-if test "$enableval" = "no" +-then +- QUOTA_CMT=# +- AC_MSG_RESULT([Disabling quota support]) +-else +- QUOTA_CMT= +- AC_DEFINE(CONFIG_QUOTA, 1) +- AC_MSG_RESULT([Enabling quota support]) +- QUOTA_MAN_COMMENT="" +- AC_SUBST(QUOTA_MAN_COMMENT) +-fi +-, +-QUOTA_CMT=# +-AC_MSG_RESULT([Disabling quota support by default]) +-) +-dnl +-dnl Define stuff expected for quota library +-dnl +-LIBQUOTA='$(LIB)/libquota'$LIB_EXT +-DEPLIBQUOTA=$LIBQUOTA +-STATIC_LIBQUOTA='$(LIB)/libquota'$STATIC_LIB_EXT +-DEPSTATIC_LIBQUOTA=$STATIC_LIBQUOTA +-PROFILED_LIBQUOTA='$(LIB)/libquota'$PROFILED_LIB_EXT +-DEPPROFILED_LIBQUOTA=$PROFILED_LIBQUOTA +-AC_SUBST(LIBQUOTA) +-AC_SUBST(DEPLIBQUOTA) +-AC_SUBST(STATIC_LIBQUOTA) +-AC_SUBST(DEPSTATIC_LIBQUOTA) +-AC_SUBST(PROFILED_LIBQUOTA) +-AC_SUBST(DEPPROFILED_LIBQUOTA) +-AC_SUBST(QUOTA_CMT) +-dnl +-dnl handle --disable-backtrace +-dnl +-AH_TEMPLATE([DISABLE_BACKTRACE], [Define to 1 to disable use of backtrace]) +-AC_ARG_ENABLE([backtrace], +-[ --disable-backtrace disable use backtrace], +-if test "$enableval" = "no" +-then +- AC_MSG_RESULT([Disabling use of backtrace]) +- AC_DEFINE(DISABLE_BACKTRACE, 1) +-else +- AC_MSG_RESULT([Enabling use of backtrace]) +-fi +-, +-AC_MSG_RESULT([Enabling use of backtrace by default]) +-) +-dnl +-dnl handle --enable-debugfs +-dnl +-AC_ARG_ENABLE([debugfs], +-[ --disable-debugfs disable support of debugfs program], +-if test "$enableval" = "no" +-then +- AC_MSG_RESULT([Disabling debugfs support]) +- DEBUGFS_CMT="#" +-else +- DEBUGFS_CMT= +- AC_MSG_RESULT([Enabling debugfs support]) +-fi +-, +-AC_MSG_RESULT([Enabling debugfs support by default]) +-DEBUGFS_CMT= +-) +-AC_SUBST(DEBUGFS_CMT) +-dnl +-dnl handle --enable-imager +-dnl +-AC_ARG_ENABLE([imager], +-[ --disable-imager disable support of e2image program], +-if test "$enableval" = "no" +-then +- AC_MSG_RESULT([Disabling e2image support]) +- IMAGER_CMT="#" +-else +- IMAGER_CMT= +- AC_MSG_RESULT([Enabling e2image support]) +-fi +-, +-AC_MSG_RESULT([Enabling e2image support by default]) +-IMAGER_CMT= +-) +-AC_SUBST(IMAGER_CMT) +-dnl +-dnl handle --enable-resizer +-dnl +-AC_ARG_ENABLE([resizer], +-[ --disable-resizer disable support of e2resize program], +-if test "$enableval" = "no" +-then +- AC_MSG_RESULT([Disabling e2resize support]) +- RESIZER_CMT="#" +-else +- RESIZER_CMT= +- AC_MSG_RESULT([Enabling e2resize support]) +-fi +-, +-AC_MSG_RESULT([Enabling e2resize support by default]) +-RESIZER_CMT= +-) +-AC_SUBST(RESIZER_CMT) +-dnl +-dnl handle --enable-defrag +-dnl +-AC_ARG_ENABLE([defrag], +-[ --disable-defrag disable support of e4defrag program], +-if test "$enableval" = "no" +-then +- AC_MSG_RESULT([Disabling e4defrag support]) +- DEFRAG_CMT="#" +-else +- DEFRAG_CMT= +- AC_MSG_RESULT([Enabling e4defrag support]) +-fi +-, +-if test -z "$WITH_DIET_LIBC" +-then +- AC_MSG_RESULT([Enabling e4defrag support by default]) +- DEFRAG_CMT= +-else +- AC_MSG_RESULT([Disabling e4defrag support by default]) +- DEFRAG_CMT="#" +-fi +-) +-AC_SUBST(DEFRAG_CMT) +-dnl +-dnl See whether to install the `fsck' wrapper program (that calls e2fsck) +-dnl +-AC_ARG_ENABLE([fsck], +-[ --enable-fsck build fsck wrapper program], +-[if test "$enableval" = "no" +-then +- FSCK_PROG='' FSCK_MAN='' +- AC_MSG_RESULT([Not building fsck wrapper]) +-else +- FSCK_PROG=fsck FSCK_MAN=fsck.8 +- AC_MSG_RESULT([Building fsck wrapper]) +-fi] +-, +-[case "$host_os" in +- gnu*) +- FSCK_PROG='' FSCK_MAN='' +- AC_MSG_RESULT([Not building fsck wrapper by default]) +- ;; +- *) +- FSCK_PROG=fsck FSCK_MAN=fsck.8 +- AC_MSG_RESULT([Building fsck wrapper by default]) +-esac] +-) +-AC_SUBST(FSCK_PROG) +-AC_SUBST(FSCK_MAN) +-dnl +-dnl See whether to install the `e2initrd-helper' program +-dnl +-AC_ARG_ENABLE([e2initrd-helper], +-[ --enable-e2initrd-helper build e2initrd-helper program], +-[if test "$enableval" = "no" +-then +- E2INITRD_PROG='' E2INITRD_MAN='' +- AC_MSG_RESULT([Not building e2initrd helper]) +-else +- E2INITRD_PROG=e2initrd_helper E2INITRD_MAN=e2initrd_helper.8 +- AC_MSG_RESULT([Building e2initrd helper]) +-fi] +-, +-E2INITRD_PROG=e2initrd_helper E2INITRD_MAN=e2initrd_helper.8 +-AC_MSG_RESULT([Building e2initrd helper by default]) +-) +-AC_SUBST(E2INITRD_PROG) +-AC_SUBST(E2INITRD_MAN) +-dnl +-dnl +-dnl +-AC_ARG_ENABLE([tls], +-[ --disable-tls disable use of thread local support], +-[if test "$enableval" = "no" +-then +- try_tls="" +- AC_MSG_RESULT([Disabling thread local support]) +-else +- try_tls="yes" +- AC_MSG_RESULT([Enabling thread local support]) +-fi] +-, +-if test -n "$WITH_DIET_LIBC" +-then +- try_tls="" +- AC_MSG_RESULT([Diet libc does not support thread local support]) +-else +- try_tls="yes" +- AC_MSG_RESULT([Try using thread local support by default]) +-fi +-) +-if test "$try_tls" = "yes" +-then +-AX_TLS +-fi +-dnl +-dnl +-dnl +-AH_TEMPLATE([USE_UUIDD], [Define to 1 to build uuidd]) +-AC_ARG_ENABLE([uuidd], +-[ --disable-uuidd disable building the uuid daemon], +-[if test "$enableval" = "no" +-then +- AC_MSG_RESULT([Not building uuidd]) +- UUIDD_CMT="#" +-else +- AC_DEFINE(USE_UUIDD, 1) +- UUIDD_CMT="" +- AC_MSG_RESULT([Building uuidd]) +-fi] +-, +-AC_DEFINE(USE_UUIDD, 1) +-if test -z "$UUID_CMT" +-then +- UUIDD_CMT="" +- AC_MSG_RESULT([Building uuidd by default]) +-else +- UUIDD_CMT="#" +- AC_MSG_RESULT([Disabling uuidd by default]) +-fi +-) +-AC_SUBST(UUIDD_CMT) +-dnl +-dnl +-dnl +-MAKEFILE_LIBRARY=$srcdir/lib/Makefile.library +-AC_SUBST_FILE(MAKEFILE_LIBRARY) +-dnl +-dnl Add internationalization support, using gettext. +-dnl +-GETTEXT_PACKAGE=e2fsprogs +-PACKAGE=e2fsprogs +-VERSION="$E2FSPROGS_VERSION" +-VERSION=0.14.1 +-AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [package name for gettext]) +-AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [version for gettext]) +-AC_SUBST(GETTEXT_PACKAGE) +-AC_SUBST(PACKAGE) +-AC_SUBST(VERSION) +- +-AM_GNU_GETTEXT +-dnl +-dnl End of configuration options +-dnl +-AC_SUBST(BINARY_TYPE) +-AC_PROG_MAKE_SET +-CHECK_GNU_MAKE +-AC_PATH_PROG(LN, ln, ln) +-AC_PROG_LN_S +-AC_PATH_PROG(MV, mv, mv) +-AC_PATH_PROG(CP, cp, cp) +-AC_PATH_PROG(RM, rm, rm) +-AC_PATH_PROG(CHMOD, chmod, :) +-AC_PROG_AWK +-AC_PROG_EGREP +-AC_PATH_PROG(SED, sed, sed) +-AC_PATH_PROG(PERL, perl, perl) +-AC_PATH_PROG(LDCONFIG, ldconfig, :) +-AC_CHECK_TOOL(AR, ar, ar) +-AC_CHECK_TOOL(RANLIB, ranlib, :) +-AC_CHECK_TOOL(STRIP, strip, :) +-AC_CHECK_PROG(MAKEINFO, makeinfo, makeinfo, ) +-if test "_$MAKEINFO" = "_"; then +- MAKEINFO="@echo Makeinfo is missing. Info documentation will not be built.;true" +-else +- case "$MAKEINFO" in +- */missing.*) +- AC_MSG_WARN([ +-*** Makeinfo is missing. Info documentation will not be built.]) +- ;; +- *) +- ;; +- esac +-fi +-AC_SUBST(MAKEINFO) +-AC_PROG_INSTALL +-# See if we need a separate native compiler. +-if test $cross_compiling = no; then +- BUILD_CC="$CC" +- AC_SUBST(BUILD_CC) +-else +- AC_CHECK_PROGS(BUILD_CC, gcc cc) +-fi +-AC_CHECK_HEADERS(m4_flatten([ +- 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 +-])) +-AC_CHECK_HEADERS(net/if.h,,, +-[[ +-#if HAVE_SYS_TYPES_H +-#include +-#endif +-#if HAVE_SYS_SOCKET +-#include +-#endif +-]]) +-AC_FUNC_VPRINTF +-dnl Check to see if dirent has member d_reclen. On cygwin those d_reclen +-dnl is not decleared. +-AC_CHECK_MEMBER(struct dirent.d_reclen,[AC_DEFINE(HAVE_RECLEN_DIRENT, 1, +- [Define to 1 if dirent has d_reclen])],, +- [#include ]) +-AC_CHECK_MEMBERS([struct stat.st_atim]) +-dnl Check to see if ssize_t was declared +-AC_CHECK_TYPE(ssize_t,[AC_DEFINE(HAVE_TYPE_SSIZE_T, 1, +- [Define to 1 if ssize_t declared])],, +- [#include ]) +-dnl +-dnl Check to see if llseek() is declared in unistd.h. On some libc's +-dnl it is, and on others it isn't..... Thank you glibc developers.... +-dnl +-AC_CHECK_DECL(llseek,[AC_DEFINE(HAVE_LLSEEK_PROTOTYPE, 1, +- [Define to 1 if llseek declared in unistd.h])],, +- [#include ]) +-dnl +-dnl Check to see if lseek64() is declared in unistd.h. Glibc's header files +-dnl are so convoluted that I can't tell whether it will always be defined, +-dnl and if it isn't defined while lseek64 is defined in the library, +-dnl disaster will strike. +-dnl +-dnl Warning! Use of --enable-gcc-wall may throw off this test. +-dnl +-dnl +-AC_CHECK_DECL(lseek64,[AC_DEFINE(HAVE_LSEEK64_PROTOTYPE, 1, +- [Define to 1 if lseek64 declared in unistd.h])],, +- [#define _LARGEFILE_SOURCE +- #define _LARGEFILE64_SOURCE +- #include ]) +-dnl +-dnl Word sizes... +-dnl +-AC_CHECK_SIZEOF(short) +-AC_CHECK_SIZEOF(int) +-AC_CHECK_SIZEOF(long) +-AC_CHECK_SIZEOF(long long) +-AC_CHECK_SIZEOF(off_t) +-SIZEOF_SHORT=$ac_cv_sizeof_short +-SIZEOF_INT=$ac_cv_sizeof_int +-SIZEOF_LONG=$ac_cv_sizeof_long +-SIZEOF_LONG_LONG=$ac_cv_sizeof_long_long +-SIZEOF_OFF_T=$ac_cv_sizeof_off_t +-AC_SUBST(SIZEOF_SHORT) +-AC_SUBST(SIZEOF_INT) +-AC_SUBST(SIZEOF_LONG) +-AC_SUBST(SIZEOF_LONG_LONG) +-AC_SUBST(SIZEOF_OFF_T) +-AC_C_BIGENDIAN +-if test $cross_compiling = no; then +- BUILD_CC="$BUILD_CC" CPP="$CPP" /bin/sh $ac_aux_dir/parse-types.sh +-else +- CROSS_COMPILE="1" BUILD_CC="$BUILD_CC" CPP="$CPP" /bin/sh $ac_aux_dir/parse-types.sh +-fi +-ASM_TYPES_HEADER=./asm_types.h +-AC_SUBST_FILE(ASM_TYPES_HEADER) +-dnl +-dnl Save the configuration #defines needed for the public ext2fs.h +-dnl header file +-dnl +-echo "/* These defines are needed for the public ext2fs.h header file */" \ +- > public_config.h +-if grep HAVE_SYS_TYPES_H confdefs.h > tmp_config.$$; then +- uniq tmp_config.$$ >> public_config.h +-else +- echo "#undef HAVE_SYS_TYPES_H" >> public_config.h +-fi +-if grep WORDS_BIGENDIAN confdefs.h > tmp_config.$$; then +- uniq tmp_config.$$ >> public_config.h +-else +- echo "#undef WORDS_BIGENDIAN" >> public_config.h +-fi +-rm -f tmp_config.$$ +-PUBLIC_CONFIG_HEADER=./public_config.h +-AC_SUBST_FILE(PUBLIC_CONFIG_HEADER) +-dnl +-dnl See if we have inttypes.h and if intptr_t is defined +-dnl +-AC_CHECK_HEADERS([inttypes.h]) +-AC_CHECK_TYPES(intptr_t) +-dnl +-dnl See if struct stat has a st_flags field, in which case we can get file +-dnl flags somewhat portably. Also check for the analogous setter, chflags(). +-dnl +-AC_MSG_CHECKING(whether struct stat has a st_flags field) +-AC_CACHE_VAL(e2fsprogs_cv_struct_st_flags, +- AC_TRY_COMPILE([#include ], +- [struct stat stat; stat.st_flags = 0;], +- [e2fsprogs_cv_struct_st_flags=yes], +- [e2fsprogs_cv_struct_st_flags=no])) +-AC_MSG_RESULT($e2fsprogs_cv_struct_st_flags) +-if test "$e2fsprogs_cv_struct_st_flags" = yes; then +- AC_MSG_CHECKING(whether st_flags field is useful) +- AC_CACHE_VAL(e2fsprogs_cv_struct_st_flags_immut, +- AC_TRY_COMPILE([#include ], +- [struct stat stat; stat.st_flags |= UF_IMMUTABLE;], +- [e2fsprogs_cv_struct_st_flags_immut=yes], +- [e2fsprogs_cv_struct_st_flags_immut=no])) +- AC_MSG_RESULT($e2fsprogs_cv_struct_st_flags_immut) +- if test "$e2fsprogs_cv_struct_st_flags_immut" = yes; then +- AC_DEFINE(HAVE_STAT_FLAGS, 1, +- [Define to 1 if struct stat has st_flags]) +- fi +-fi +-dnl +-dnl Check for the presence of SA_LEN +-dnl +-AC_CHECK_MEMBER(struct sockaddr.sa_len, +- AC_DEFINE_UNQUOTED(HAVE_SA_LEN,1, +- [Define to 1 if if struct sockaddr contains sa_len]),, +- [#include +- #include ]) +-dnl +-dnl This will add -lblkid to the AC_CHECK_FUNCS search if we are using +-dnl the system-provided blkid library +-dnl +-if test -n "$BLKID_CMT"; then +- AC_SEARCH_LIBS([blkid_probe_all], [blkid]) +-fi +-dnl +-AC_CHECK_FUNCS(m4_flatten([ +- __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 +- utimes +- valloc +-])) +-dnl +-dnl Check to see if -lsocket is required (solaris) to make something +-dnl that uses socket() to compile; this is needed for the UUID library +-dnl +-SOCKET_LIB='' +-AC_CHECK_LIB(socket, socket, [SOCKET_LIB=-lsocket]) +-AC_SUBST(SOCKET_LIB) +-dnl +-dnl See if optreset exists +-dnl +-AC_MSG_CHECKING(for optreset) +-AC_CACHE_VAL(ac_cv_have_optreset, +-[AC_EGREP_HEADER(optreset, unistd.h, +- ac_cv_have_optreset=yes, ac_cv_have_optreset=no)])dnl +-AC_MSG_RESULT($ac_cv_have_optreset) +-if test $ac_cv_have_optreset = yes; then +- AC_DEFINE(HAVE_OPTRESET, 1, [Define to 1 if optreset for getopt is present]) +-fi +-dnl +-dnl Test for sem_init, and which library it might require: +-dnl +-AH_TEMPLATE([HAVE_SEM_INIT], [Define to 1 if sem_init() exists]) +-SEM_INIT_LIB='' +-AC_CHECK_FUNC(sem_init, , +- AC_CHECK_LIB(pthread, sem_init, +- AC_DEFINE(HAVE_SEM_INIT, 1) +- SEM_INIT_LIB=-lpthread, +- AC_CHECK_LIB(rt, sem_init, +- AC_DEFINE(HAVE_SEM_INIT, 1) +- SEM_INIT_LIB=-lrt, +- AC_CHECK_LIB(posix4, sem_init, +- AC_DEFINE(HAVE_SEM_INIT, 1) +- SEM_INIT_LIB=-lposix4))))dnl +-AC_SUBST(SEM_INIT_LIB) +-dnl +-dnl Check for unified diff +-dnl +-AC_MSG_CHECKING(for unified diff option) +-if diff -u $0 $0 > /dev/null 2>&1 ; then +- UNI_DIFF_OPTS=-u +-else +- UNI_DIFF_OPTS=-c +-fi +-AC_MSG_RESULT($UNI_DIFF_OPTS) +-AC_SUBST(UNI_DIFF_OPTS) +-dnl +-dnl We use the EXT2 ioctls only under Linux +-dnl +-case "$host_os" in +-linux*) +- AC_DEFINE(HAVE_EXT2_IOCTLS, 1, [Define to 1 if Ext2 ioctls present]) +- ;; +-esac +-dnl +-dnl OS-specific uncomment control +-dnl +-LINUX_CMT="#" +-CYGWIN_CMT="#" +-UNIX_CMT= +-case "$host_os" in +-linux*) +- LINUX_CMT= +- ;; +-cygwin) +- CYGWIN_CMT= +- UNIX_CMT="#" +- ;; +-esac +-AC_SUBST(LINUX_CMT) +-AC_SUBST(CYGWIN_CMT) +-AC_SUBST(UNIX_CMT) +-dnl +-dnl Linux and Hurd places root files in the / by default +-dnl +-case "$host_os" in +-linux* | gnu* | k*bsd*-gnu) +- if test "$prefix" = NONE -a "$root_prefix" = NONE ; then +- root_prefix=""; +- AC_MSG_RESULT([On $host_os systems, root_prefix defaults to '']) +- fi +- ;; +-esac +-dnl +-dnl On Linux/hurd, force the prefix to be /usr +-dnl +-case "$host_os" in +-linux* | gnu* | k*bsd*-gnu) +- if test "$prefix" = NONE ; then +- prefix="/usr"; +- AC_MSG_RESULT([On $host_os systems, prefix defaults to /usr]) +- if test "$mandir" = '${prefix}/man' ; then +- AC_MSG_RESULT([...and mandir defaults to /usr/share/man]) +- mandir=/usr/share/man +- fi +- fi +-;; +-esac +-if test "$root_prefix" = NONE ; then +- if test "$prefix" = NONE ; then +- root_prefix="$ac_default_prefix" +- else +- root_prefix="$prefix" +- fi +- root_bindir=$bindir +- root_sbindir=$sbindir +- root_libdir=$libdir +- root_sysconfdir=$sysconfdir +-else +- root_bindir='${root_prefix}/bin' +- root_sbindir='${root_prefix}/sbin' +- root_libdir='${root_prefix}/lib' +- root_sysconfdir='${root_prefix}/etc' +-fi +-if test "$bindir" != '${exec_prefix}/bin'; then +- root_bindir=$bindir +- AC_MSG_RESULT([Setting root_bindir to $root_bindir]) +-fi +-if test "$sbindir" != '${exec_prefix}/sbin'; then +- root_sbindir=$sbindir +- AC_MSG_RESULT([Setting root_sbindir to $root_sbindir]) +-fi +-if test "$libdir" != '${exec_prefix}/lib'; then +- root_libdir=$libdir +- AC_MSG_RESULT([Setting root_libdir to $root_libdir]) +-fi +-if test "$sysconfdir" != '${prefix}/etc'; then +- root_sysconfdir=$sysconfdir +- AC_MSG_RESULT([Setting root_sysconfdir to $root_sysconfdir]) +-fi +-AC_SUBST(root_prefix) +-AC_SUBST(root_bindir) +-AC_SUBST(root_sbindir) +-AC_SUBST(root_libdir) +-AC_SUBST(root_sysconfdir) +-dnl +-dnl Allow specification of the multiarch arch +-dnl +-AC_ARG_WITH([multiarch], +-[ --with-multiarch=ARCH specify the multiarch triplet], +-if test "$withval" = "lib64"; then +- libdir=/usr/lib64 +- root_libdir=/lib64 +-else +- libdir=$libdir/$withval +- root_libdir=$root_libdir/$withval +-fi +-)dnl +-dnl +-dnl See if -static works. This could fail if the linker does not +-dnl support -static, or if required external libraries are not available +-dnl in static form. +-dnl +-AC_MSG_CHECKING([whether we can link with -static]) +-AC_CACHE_VAL(ac_cv_e2fsprogs_use_static, +-[SAVE_LDFLAGS=$LDFLAGS; LDFLAGS="$LDFLAGS -static" +-AC_TRY_LINK([#include ],[fflush(stdout);], +- ac_cv_e2fsprogs_use_static=yes, ac_cv_e2fsprogs_use_static=no) +-LDFLAGS=$SAVE_LDFLAGS]) +-dnl +-dnl Regardless of how the test turns out, Solaris doesn't handle -static +-dnl This is caused by the socket library requiring the nsl library, which +-dnl requires the -dl library, which only works for dynamically linked +-dnl programs. It basically means you can't have statically linked programs +-dnl which use the network under Solaris. +-dnl +-case "$host_os" in +-solaris2.*) +- ac_cv_e2fsprogs_use_static=no +-;; +-esac +-AC_MSG_RESULT($ac_cv_e2fsprogs_use_static) +-LDFLAG_STATIC= +-if test $ac_cv_e2fsprogs_use_static = yes; then +- LDFLAG_STATIC=-static +-fi +-AC_SUBST(LDFLAG_STATIC) +-dnl +-dnl Work around mysterious Darwin / GNU libintl problem +-dnl (__asm__ redirection doesn't work for some mysterious reason. Looks like +-dnl Apple hacked gcc somehow?) +-dnl +-case "$host_os" in +-darwin*) +- AC_MSG_RESULT([Using Apple Darwin / GNU libintl workaround]) +- AC_DEFINE(_INTL_REDIRECT_MACROS, 1, +- [Define to 1 if Apple Darwin libintl workaround is needed]) +- ;; +-esac +-dnl +-dnl Make the ss and et directories work correctly. +-dnl +-SS_DIR=`cd ${srcdir}/lib/ss; pwd` +-ET_DIR=`cd ${srcdir}/lib/et; pwd` +-AC_SUBST(SS_DIR) +-AC_SUBST(ET_DIR) +-dnl +-dnl Only try to run the test suite if we're not cross compiling. +-dnl +-if test "$cross_compiling" = yes ; then +- DO_TEST_SUITE= +-else +- DO_TEST_SUITE=check +-fi +-AC_SUBST(DO_TEST_SUITE) +-dnl +-dnl Only include the intl include files if we're building with them +-dnl +-INCLUDES='-I. -I$(top_builddir)/lib -I$(top_srcdir)/lib' +-if test -n "$CPPFLAGS" ; then +- INCLUDES="$INCLUDES $CPPFLAGS" +-fi +-if test "$USE_INCLUDED_LIBINTL" = "yes" ; then +- INCLUDES=$INCLUDES' -I$(top_builddir)/intl -I$(top_srcdir)/intl' +-fi +-if test -n "$WITH_DIET_LIBC" ; then +- INCLUDES="$INCLUDES -D_REENTRANT" +-fi +-AC_SUBST(INCLUDES) +-AM_MKINSTALLDIRS +-dnl +-dnl Build CFLAGS +-dnl +-if test $cross_compiling = no; then +- BUILD_CFLAGS="$CFLAGS $CPPFLAGS $INCLUDES -DHAVE_CONFIG_H" +- BUILD_LDFLAGS="$LDFLAGS" +-fi +-AC_SUBST(BUILD_CFLAGS) +-AC_SUBST(BUILD_LDFLAGS) +-dnl +-dnl Make our output files, being sure that we create the some miscellaneous +-dnl directories +-dnl +-test -d lib || mkdir lib +-test -d include || mkdir include +-test -d include/linux || mkdir include/linux +-test -d include/asm || mkdir include/asm +-for i in MCONFIG Makefile e2fsprogs.spec \ +- util/Makefile util/subst.conf util/gen-tarball util/install-symlink \ +- lib/et/Makefile lib/ss/Makefile lib/e2p/Makefile \ +- lib/ext2fs/Makefile lib/ext2fs/ext2_types.h \ +- lib/uuid/Makefile lib/uuid/uuid_types.h \ +- lib/blkid/Makefile lib/blkid/blkid_types.h lib/quota/Makefile \ +- lib/ss/ss.pc lib/uuid/uuid.pc lib/et/com_err.pc \ +- lib/e2p/e2p.pc lib/blkid/blkid.pc lib/ext2fs/ext2fs.pc \ +- misc/Makefile ext2ed/Makefile e2fsck/Makefile \ +- debugfs/Makefile tests/Makefile tests/progs/Makefile \ +- resize/Makefile doc/Makefile intl/Makefile \ +- intl/libgnuintl.h po/Makefile.in ; do +- if test -d `dirname ${srcdir}/$i` ; then +- outlist="$outlist $i" +- fi +-done +-AC_OUTPUT($outlist) +-if test -f util/gen-tarball; then chmod +x util/gen-tarball; fi +--- /dev/null ++++ b/contrib/add_ext4_encrypt.c +@@ -0,0 +1,65 @@ ++/* ++ * Basic progam to add ext4 encryption to a file system ++ * ++ * Copyright 2015, Google, Inc. ++ * ++ * %Begin-Header% ++ * This file may be redistributed under the terms of the GNU Public ++ * License. ++ * %End-Header% ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++int main (int argc, char *argv[]) ++{ ++ errcode_t retval = 0; ++ ext2_filsys fs; ++ ++ setbuf(stdout, NULL); ++ setbuf(stderr, NULL); ++ initialize_ext2_error_table(); ++ ++ if (argc != 2) { ++ fprintf(stderr, "%s: Usage \n", argv[0]); ++ exit(1); ++ } ++ ++ retval = ext2fs_open(argv[1], EXT2_FLAG_RW, 0, 0, ++ unix_io_manager, &fs); ++ ++ if (retval) { ++ com_err(argv[0], retval, "while trying to open '%s'", ++ argv[1]); ++ exit(1); ++ } ++ if (!EXT2_HAS_INCOMPAT_FEATURE(fs->super, ++ EXT4_FEATURE_INCOMPAT_ENCRYPT)) { ++ fs->super->s_feature_incompat |= EXT4_FEATURE_INCOMPAT_ENCRYPT; ++ fs->super->s_encrypt_algos[0] = ++ EXT4_ENCRYPTION_MODE_AES_256_XTS; ++ fs->super->s_encrypt_algos[1] = ++ EXT4_ENCRYPTION_MODE_AES_256_CTS; ++ ext2fs_mark_super_dirty(fs); ++ printf("Ext4 encryption enabled on %s\n", argv[1]); ++ } else ++ printf("Ext4 encryption already enabled on %s\n", argv[1]); ++ ++ retval = ext2fs_close(fs); ++ if (retval) { ++ com_err(argv[0], retval, "while trying to close '%s'", ++ argv[1]); ++ exit(1); ++ } ++ return (0); ++} ++ +--- /dev/null ++++ b/contrib/Android.mk +@@ -0,0 +1,79 @@ ++LOCAL_PATH := $(call my-dir) ++ ++########################################################################### ++# Build fsstress ++# ++fsstress_src_files := \ ++ fsstress.c ++ ++fsstress_c_includes := ++ ++fsstress_cflags := -O2 -g -W -Wall ++ ++fsstress_shared_libraries := ++ ++fsstress_system_shared_libraries := libc ++ ++include $(CLEAR_VARS) ++ ++LOCAL_SRC_FILES := $(fsstress_src_files) ++mke2fs_c_includesLOCAL_CFLAGS := $(fsstress_cflags) ++LOCAL_SYSTEM_SHARED_LIBRARIES := $(fsstress_system_shared_libraries) ++LOCAL_MODULE := fsstress ++LOCAL_MODULE_TAGS := optional ++ ++include $(BUILD_EXECUTABLE) ++ ++include $(CLEAR_VARS) ++ ++LOCAL_SRC_FILES := $(fsstress_src_files) ++LOCAL_CFLAGS := $(fsstress_cflags) ++LOCAL_MODULE := fsstress_host ++LOCAL_MODULE_STEM := fsstress ++LOCAL_MODULE_TAGS := optional ++ ++include $(BUILD_HOST_EXECUTABLE) ++ ++######################################################################### ++# Build add_ext4_encrypt ++# ++include $(CLEAR_VARS) ++ ++add_ext4_encrypt_src_files := \ ++ add_ext4_encrypt.c ++ ++add_ext4_encrypt_c_includes := \ ++ external/e2fsprogs/lib ++ ++add_ext4_encrypt_cflags := -O2 -g -W -Wall ++ ++add_ext4_encrypt_shared_libraries := \ ++ libext2fs \ ++ libext2_com_err ++ ++add_ext4_encrypt_system_shared_libraries := libc ++ ++include $(CLEAR_VARS) ++ ++LOCAL_SRC_FILES := $(add_ext4_encrypt_src_files) ++LOCAL_C_INCLUDES := $(add_ext4_encrypt_c_includes) ++LOCAL_CFLAGS := $(add_ext4_encrypt_cflags) ++LOCAL_SHARED_LIBRARIES := $(add_ext4_encrypt_shared_libraries) ++LOCAL_SYSTEM_SHARED_LIBRARIES := $(add_ext4_encrypt_system_shared_libraries) ++LOCAL_MODULE := add_ext4_encrypt ++LOCAL_MODULE_TAGS := optional ++ ++include $(BUILD_EXECUTABLE) ++ ++include $(CLEAR_VARS) ++ ++LOCAL_SRC_FILES := $(add_ext4_encrypt_src_files) ++LOCAL_C_INCLUDES := $(add_ext4_encrypt_c_includes) ++LOCAL_CFLAGS := $(add_ext4_encrypt_cflags) ++LOCAL_SHARED_LIBRARIES := $(addsuffix _host, $(add_ext4_encrypt_shared_libraries)) ++LOCAL_MODULE := add_ext4_encrypt_host ++LOCAL_MODULE_STEM := add_ext4_encrypt ++LOCAL_MODULE_TAGS := optional ++ ++include $(BUILD_HOST_EXECUTABLE) ++ +--- /dev/null ++++ b/contrib/dir2fs +@@ -0,0 +1,66 @@ ++#!/bin/sh ++ ++dir="$1" ++dev="$2" ++ ++if [ "$1" = "--help" ] || [ ! -d "${dir}" ]; then ++ echo "Usage: $0 dir [mke2fs args] dev" ++ exit 1 ++fi ++ ++shift ++ ++# Goal: Put all the files at the beginning (which mke2fs does) and minimize ++# the number of free inodes given the minimum number of blocks required. ++# Hence all this math to get the inode ratio just right. ++ ++bytes="$(du -ks "${dir}" | awk '{print $1}')" ++bytes="$((bytes * 1024))" ++inodes="$(find "${dir}" -print0 | xargs -0 stat -c '%i' | sort -g | uniq | wc -l)" ++block_sz=4096 ++inode_sz=256 ++sb_overhead=4096 ++blocks_per_group="$((block_sz * 8))" ++bytes_per_group="$((blocks_per_group * block_sz))" ++inode_bytes="$((inodes * inode_sz))" ++ ++# Estimate overhead with the minimum number of groups... ++nr_groups="$(( (bytes + inode_bytes + bytes_per_group - 1) / bytes_per_group))" ++inode_bytes_per_group="$((inode_bytes / nr_groups))" ++inode_blocks_per_group="$(( (inode_bytes_per_group + (block_sz - 1)) / block_sz ))" ++per_grp_overhead="$(( ((3 + inode_blocks_per_group) * block_sz) + 64 ))" ++overhead="$(( sb_overhead + (per_grp_overhead * nr_groups) ))" ++used_bytes="$((bytes + overhead))" ++ ++# Then do it again with the real number of groups. ++nr_groups="$(( (used_bytes + (bytes_per_group - 1)) / bytes_per_group))" ++tot_blocks="$((nr_groups * blocks_per_group))" ++tot_bytes="$((tot_blocks * block_sz))" ++ ++ratio="$((bytes / inodes))" ++mkfs_blocks="$((tot_blocks * 4 / 3))" ++ ++mke2fs -i "${ratio}" -T ext4 -d "${dir}" -O ^resize_inode,sparse_super2,metadata_csum,64bit,^has_journal -E packed_meta_blocks=1,num_backup_sb=0 -b "${block_sz}" -I "${inodesz}" -F "${dev}" "${mkfs_blocks}" || exit ++ ++e2fsck -fyD "${dev}" ++ ++blocks="$(dumpe2fs -h "${dev}" 2>&1 | grep 'Block count:' | awk '{print $3}')" ++while resize2fs -f -M "${dev}"; do ++ new_blocks="$(dumpe2fs -h "${dev}" 2>&1 | grep 'Block count:' | awk '{print $3}')" ++ if [ "${new_blocks}" -eq "${blocks}" ]; then ++ break; ++ fi ++ blocks="${new_blocks}" ++done ++ ++if [ ! -b "${dev}" ]; then ++ truncate -s "$((blocks * block_sz))" "${dev}" || (e2image -ar "${dev}" "${dev}.min"; mv "${dev}.min" "${dev}") ++fi ++ ++e2fsck -fy "${dev}" ++ ++dir_blocks="$((bytes / block_sz))" ++overhead="$((blocks - dir_blocks))" ++echo "Minimized image overhead: $((100 * overhead / dir_blocks))%" ++ ++exit 0 +--- a/contrib/fallocate.c ++++ b/contrib/fallocate.c +@@ -21,8 +21,12 @@ + * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + ++#ifndef _LARGEFILE_SOURCE + #define _LARGEFILE_SOURCE ++#endif ++#ifndef _LARGEFILE64_SOURCE + #define _LARGEFILE64_SOURCE ++#endif + + #include + #include +@@ -36,6 +40,8 @@ + // #include + #define FALLOC_FL_KEEP_SIZE 0x01 + #define FALLOC_FL_PUNCH_HOLE 0x02 /* de-allocates range */ ++#define FALLOC_FL_COLLAPSE_RANGE 0x08 ++#define FALLOC_FL_ZERO_RANGE 0x10 + + void usage(void) + { +@@ -95,7 +101,7 @@ + int error; + int tflag = 0; + +- while ((opt = getopt(argc, argv, "npl:o:t")) != -1) { ++ while ((opt = getopt(argc, argv, "npl:o:tzc")) != -1) { + switch(opt) { + case 'n': + /* do not change filesize */ +@@ -106,6 +112,16 @@ + falloc_mode = (FALLOC_FL_PUNCH_HOLE | + FALLOC_FL_KEEP_SIZE); + break; ++ case 'c': ++ /* collapse range mode */ ++ falloc_mode = (FALLOC_FL_COLLAPSE_RANGE | ++ FALLOC_FL_KEEP_SIZE); ++ break; ++ case 'z': ++ /* zero range mode */ ++ falloc_mode = (FALLOC_FL_ZERO_RANGE | ++ FALLOC_FL_KEEP_SIZE); ++ break; + case 'l': + length = cvtnum(optarg); + break; +--- /dev/null ++++ b/contrib/fsstress.c +@@ -0,0 +1,2701 @@ ++/* ++ * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of version 2 of the GNU General Public License as ++ * published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it would be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ++ * ++ * Further, this software is distributed without any warranty that it is ++ * free of the rightful claim of any third person regarding infringement ++ * or the like. Any license provided herein, whether implied or ++ * otherwise, applies only to this software file. Patent licenses, if ++ * any, provided herein do not apply to combinations of this program with ++ * other software, or any other product whatsoever. ++ * ++ * You should have received a copy of the GNU General Public License along ++ * with this program; if not, write the Free Software Foundation, Inc., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, ++ * Mountain View, CA 94043, or: ++ * ++ * http://www.sgi.com ++ * ++ * For further information regarding this notice, see: ++ * ++ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ ++ */ ++ ++#define NO_XFS ++#define HAVE_SYS_PRCTL_H ++#define _LARGEFILE64_SOURCE ++ ++#define MAXNAMELEN 1024 ++struct dioattr { ++ int d_miniosz, d_maxiosz, d_mem; ++}; ++ ++#define MIN(a,b) ((a)<(b) ? (a):(b)) ++#define MAX(a,b) ((a)>(b) ? (a):(b)) ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#ifndef O_DIRECT ++#define O_DIRECT 040000 ++#endif ++ ++#ifdef HAVE_SYS_PRCTL_H ++# include ++#endif ++ ++#define XFS_ERRTAG_MAX 17 ++ ++typedef enum { ++#ifndef NO_XFS ++ OP_ALLOCSP, ++ OP_ATTR_REMOVE, ++ OP_ATTR_SET, ++ OP_BULKSTAT, ++ OP_BULKSTAT1, ++#endif ++ OP_CHOWN, ++ OP_CREAT, ++ OP_DREAD, ++ OP_DWRITE, ++ OP_FDATASYNC, ++#ifndef NO_XFS ++ OP_FREESP, ++#endif ++ OP_FSYNC, ++ OP_GETDENTS, ++ OP_LINK, ++ OP_MKDIR, ++ OP_MKNOD, ++ OP_READ, ++ OP_READLINK, ++ OP_RENAME, ++#ifndef NO_XFS ++ OP_RESVSP, ++#endif ++ OP_RMDIR, ++ OP_STAT, ++ OP_SYMLINK, ++ OP_SYNC, ++ OP_TRUNCATE, ++ OP_UNLINK, ++#ifndef NO_XFS ++ OP_UNRESVSP, ++#endif ++ OP_WRITE, ++ OP_LAST ++} opty_t; ++ ++typedef void (*opfnc_t) (int, long); ++ ++typedef struct opdesc { ++ opty_t op; ++ char *name; ++ opfnc_t func; ++ int freq; ++ int iswrite; ++ int isxfs; ++} opdesc_t; ++ ++typedef struct fent { ++ int id; ++ int parent; ++} fent_t; ++ ++typedef struct flist { ++ int nfiles; ++ int nslots; ++ int tag; ++ fent_t *fents; ++} flist_t; ++ ++typedef struct pathname { ++ int len; ++ char *path; ++} pathname_t; ++ ++#define FT_DIR 0 ++#define FT_DIRm (1 << FT_DIR) ++#define FT_REG 1 ++#define FT_REGm (1 << FT_REG) ++#define FT_SYM 2 ++#define FT_SYMm (1 << FT_SYM) ++#define FT_DEV 3 ++#define FT_DEVm (1 << FT_DEV) ++#define FT_RTF 4 ++#define FT_RTFm (1 << FT_RTF) ++#define FT_nft 5 ++#define FT_ANYm ((1 << FT_nft) - 1) ++#define FT_REGFILE (FT_REGm | FT_RTFm) ++#define FT_NOTDIR (FT_ANYm & ~FT_DIRm) ++ ++#define FLIST_SLOT_INCR 16 ++#define NDCACHE 64 ++ ++#define MAXFSIZE ((1ULL << 63) - 1ULL) ++#define MAXFSIZE32 ((1ULL << 40) - 1ULL) ++ ++void allocsp_f(int, long); ++void attr_remove_f(int, long); ++void attr_set_f(int, long); ++void bulkstat_f(int, long); ++void bulkstat1_f(int, long); ++void chown_f(int, long); ++void creat_f(int, long); ++void dread_f(int, long); ++void dwrite_f(int, long); ++void fdatasync_f(int, long); ++void freesp_f(int, long); ++void fsync_f(int, long); ++void getdents_f(int, long); ++void link_f(int, long); ++void mkdir_f(int, long); ++void mknod_f(int, long); ++void read_f(int, long); ++void readlink_f(int, long); ++void rename_f(int, long); ++void resvsp_f(int, long); ++void rmdir_f(int, long); ++void stat_f(int, long); ++void symlink_f(int, long); ++void sync_f(int, long); ++void truncate_f(int, long); ++void unlink_f(int, long); ++void unresvsp_f(int, long); ++void write_f(int, long); ++ ++opdesc_t ops[] = { ++#ifndef NO_XFS ++ {OP_ALLOCSP, "allocsp", allocsp_f, 1, 1, 1}, ++ {OP_ATTR_REMOVE, "attr_remove", attr_remove_f, /* 1 */ 0, 1, 1}, ++ {OP_ATTR_SET, "attr_set", attr_set_f, /* 2 */ 0, 1, 1}, ++ {OP_BULKSTAT, "bulkstat", bulkstat_f, 1, 0, 1}, ++ {OP_BULKSTAT1, "bulkstat1", bulkstat1_f, 1, 0, 1}, ++#endif ++ {OP_CHOWN, "chown", chown_f, 3, 1, 0}, ++ {OP_CREAT, "creat", creat_f, 4, 1, 0}, ++ {OP_DREAD, "dread", dread_f, 4, 0, 0}, ++ {OP_DWRITE, "dwrite", dwrite_f, 4, 1, 0}, ++ {OP_FDATASYNC, "fdatasync", fdatasync_f, 1, 1, 0}, ++#ifndef NO_XFS ++ {OP_FREESP, "freesp", freesp_f, 1, 1, 1}, ++#endif ++ {OP_FSYNC, "fsync", fsync_f, 1, 1, 0}, ++ {OP_GETDENTS, "getdents", getdents_f, 1, 0, 0}, ++ {OP_LINK, "link", link_f, 1, 1, 0}, ++ {OP_MKDIR, "mkdir", mkdir_f, 2, 1, 0}, ++ {OP_MKNOD, "mknod", mknod_f, 2, 1, 0}, ++ {OP_READ, "read", read_f, 1, 0, 0}, ++ {OP_READLINK, "readlink", readlink_f, 1, 0, 0}, ++ {OP_RENAME, "rename", rename_f, 2, 1, 0}, ++#ifndef NO_XFS ++ {OP_RESVSP, "resvsp", resvsp_f, 1, 1, 1}, ++#endif ++ {OP_RMDIR, "rmdir", rmdir_f, 1, 1, 0}, ++ {OP_STAT, "stat", stat_f, 1, 0, 0}, ++ {OP_SYMLINK, "symlink", symlink_f, 2, 1, 0}, ++ {OP_SYNC, "sync", sync_f, 1, 0, 0}, ++ {OP_TRUNCATE, "truncate", truncate_f, 2, 1, 0}, ++ {OP_UNLINK, "unlink", unlink_f, 1, 1, 0}, ++#ifndef NO_XFS ++ {OP_UNRESVSP, "unresvsp", unresvsp_f, 1, 1, 1}, ++#endif ++ {OP_WRITE, "write", write_f, 4, 1, 0}, ++}, *ops_end; ++ ++flist_t flist[FT_nft] = { ++ {0, 0, 'd', NULL}, ++ {0, 0, 'f', NULL}, ++ {0, 0, 'l', NULL}, ++ {0, 0, 'c', NULL}, ++ {0, 0, 'r', NULL}, ++}; ++ ++int dcache[NDCACHE]; ++int errrange; ++int errtag; ++opty_t *freq_table; ++int freq_table_size; ++#ifndef NO_XFS ++xfs_fsop_geom_t geom; ++#endif ++char *homedir; ++int *ilist; ++int ilistlen; ++off64_t maxfsize; ++char *myprog; ++int namerand; ++int nameseq; ++int nops; ++int nproc = 1; ++int operations = 1; ++int procid; ++int rtpct; ++unsigned long seed = 0; ++ino_t top_ino; ++int verbose = 0; ++#ifndef NO_XFS ++int no_xfs = 0; ++#else ++int no_xfs = 1; ++#endif ++sig_atomic_t should_stop = 0; ++ ++void add_to_flist(int, int, int); ++void append_pathname(pathname_t *, char *); ++#ifndef NO_XFS ++int attr_list_path(pathname_t *, char *, const int, int, attrlist_cursor_t *); ++int attr_remove_path(pathname_t *, const char *, int); ++int attr_set_path(pathname_t *, const char *, const char *, const int, int); ++#endif ++void check_cwd(void); ++int creat_path(pathname_t *, mode_t); ++void dcache_enter(int, int); ++void dcache_init(void); ++fent_t *dcache_lookup(int); ++void dcache_purge(int); ++void del_from_flist(int, int); ++int dirid_to_name(char *, int); ++void doproc(void); ++void fent_to_name(pathname_t *, flist_t *, fent_t *); ++void fix_parent(int, int); ++void free_pathname(pathname_t *); ++int generate_fname(fent_t *, int, pathname_t *, int *, int *); ++int get_fname(int, long, pathname_t *, flist_t **, fent_t **, int *); ++void init_pathname(pathname_t *); ++int lchown_path(pathname_t *, uid_t, gid_t); ++int link_path(pathname_t *, pathname_t *); ++int lstat64_path(pathname_t *, struct stat64 *); ++void make_freq_table(void); ++int mkdir_path(pathname_t *, mode_t); ++int mknod_path(pathname_t *, mode_t, dev_t); ++void namerandpad(int, char *, int); ++int open_path(pathname_t *, int); ++DIR *opendir_path(pathname_t *); ++void process_freq(char *); ++int readlink_path(pathname_t *, char *, size_t); ++int rename_path(pathname_t *, pathname_t *); ++int rmdir_path(pathname_t *); ++void separate_pathname(pathname_t *, char *, pathname_t *); ++void show_ops(int, char *); ++int stat64_path(pathname_t *, struct stat64 *); ++int symlink_path(const char *, pathname_t *); ++int truncate64_path(pathname_t *, off64_t); ++int unlink_path(pathname_t *); ++void usage(void); ++void write_freq(void); ++void zero_freq(void); ++ ++void sg_handler(int signum) ++{ ++ should_stop = 1; ++} ++ ++int main(int argc, char **argv) ++{ ++ char buf[10]; ++ int c; ++ char *dirname = NULL; ++ int fd; ++ int i; ++ int cleanup = 0; ++ int loops = 1; ++ int loopcntr = 1; ++ char cmd[256]; ++#ifndef NO_XFS ++ int j; ++#endif ++ char *p; ++ int stat; ++ struct timeval t; ++#ifndef NO_XFS ++ ptrdiff_t srval; ++#endif ++ int nousage = 0; ++#ifndef NO_XFS ++ xfs_error_injection_t err_inj; ++#endif ++ struct sigaction action; ++ ++ errrange = errtag = 0; ++ umask(0); ++ nops = sizeof(ops) / sizeof(ops[0]); ++ ops_end = &ops[nops]; ++ myprog = argv[0]; ++ while ((c = getopt(argc, argv, "cd:e:f:i:l:n:p:rs:vwzHSX")) != -1) { ++ switch (c) { ++ case 'c': ++ /*Don't cleanup */ ++ cleanup = 1; ++ break; ++ case 'd': ++ dirname = optarg; ++ break; ++ case 'e': ++ sscanf(optarg, "%d", &errtag); ++ if (errtag < 0) { ++ errtag = -errtag; ++ errrange = 1; ++ } else if (errtag == 0) ++ errtag = -1; ++ if (errtag >= XFS_ERRTAG_MAX) { ++ fprintf(stderr, ++ "error tag %d too large (max %d)\n", ++ errtag, XFS_ERRTAG_MAX - 1); ++ exit(1); ++ } ++ break; ++ case 'f': ++ process_freq(optarg); ++ break; ++ case 'i': ++ ilist = realloc(ilist, ++ilistlen * sizeof(*ilist)); ++ ilist[ilistlen - 1] = strtol(optarg, &p, 16); ++ break; ++ case 'l': ++ loops = atoi(optarg); ++ break; ++ case 'n': ++ operations = atoi(optarg); ++ break; ++ case 'p': ++ nproc = atoi(optarg); ++ break; ++ case 'r': ++ namerand = 1; ++ break; ++ case 's': ++ seed = strtoul(optarg, NULL, 0); ++ break; ++ case 'v': ++ verbose = 1; ++ break; ++ case 'w': ++ write_freq(); ++ break; ++ case 'z': ++ zero_freq(); ++ break; ++ case 'S': ++ show_ops(0, NULL); ++ printf("\n"); ++ nousage = 1; ++ break; ++ case '?': ++ fprintf(stderr, "%s - invalid parameters\n", myprog); ++ /* fall through */ ++ case 'H': ++ usage(); ++ exit(1); ++ case 'X': ++ no_xfs = 1; ++ break; ++ } ++ } ++ ++ if (no_xfs && errtag) { ++ fprintf(stderr, "error injection only works on XFS\n"); ++ exit(1); ++ } ++ ++ if (no_xfs) { ++ int i; ++ for (i = 0; ops + i < ops_end; ++i) { ++ if (ops[i].isxfs) ++ ops[i].freq = 0; ++ } ++ } ++ ++ make_freq_table(); ++ ++ while (((loopcntr <= loops) || (loops == 0)) && !should_stop) { ++ if (!dirname) { ++ /* no directory specified */ ++ if (!nousage) ++ usage(); ++ exit(1); ++ } ++ ++ (void)mkdir(dirname, 0777); ++ if (chdir(dirname) < 0) { ++ perror(dirname); ++ exit(1); ++ } ++ sprintf(buf, "fss%x", getpid()); ++ fd = creat(buf, 0666); ++ if (lseek64(fd, (off64_t) (MAXFSIZE32 + 1ULL), SEEK_SET) < 0) ++ maxfsize = (off64_t) MAXFSIZE32; ++ else ++ maxfsize = (off64_t) MAXFSIZE; ++ dcache_init(); ++ setlinebuf(stdout); ++ if (!seed) { ++ gettimeofday(&t, NULL); ++ seed = (int)t.tv_sec ^ (int)t.tv_usec; ++ printf("seed = %ld\n", seed); ++ } ++#ifndef NO_XFS ++ if (!no_xfs) { ++ memset(&geom, 0, sizeof(geom)); ++ i = ioctl(fd, XFS_IOC_FSGEOMETRY, &geom); ++ if (i >= 0 && geom.rtblocks) ++ rtpct = MIN(MAX(geom.rtblocks * 100 / ++ (geom.rtblocks + ++ geom.datablocks), 1), 99); ++ else ++ rtpct = 0; ++ } ++ if (errtag != 0) { ++ if (errrange == 0) { ++ if (errtag <= 0) { ++ srandom(seed); ++ j = random() % 100; ++ ++ for (i = 0; i < j; i++) ++ (void)random(); ++ ++ errtag = ++ (random() % (XFS_ERRTAG_MAX - 1)) + ++ 1; ++ } ++ } else { ++ srandom(seed); ++ j = random() % 100; ++ ++ for (i = 0; i < j; i++) ++ (void)random(); ++ ++ errtag += ++ (random() % (XFS_ERRTAG_MAX - errtag)); ++ } ++ printf("Injecting failure on tag #%d\n", errtag); ++ memset(&err_inj, 0, sizeof(err_inj)); ++ err_inj.errtag = errtag; ++ err_inj.fd = fd; ++ srval = ioctl(fd, XFS_IOC_ERROR_INJECTION, &err_inj); ++ if (srval < -1) { ++ perror ++ ("fsstress - XFS_SYSSGI error injection call"); ++ close(fd); ++ unlink(buf); ++ exit(1); ++ } ++ } else ++#endif ++ close(fd); ++ unlink(buf); ++ ++ ++ if (nproc == 1) { ++ procid = 0; ++ doproc(); ++ } else { ++ setpgid(0, 0); ++ action.sa_handler = sg_handler; ++ sigemptyset(&action.sa_mask); ++ action.sa_flags = 0; ++ if (sigaction(SIGTERM, &action, 0)) { ++ perror("sigaction failed"); ++ exit(1); ++ } ++ ++ for (i = 0; i < nproc; i++) { ++ if (fork() == 0) { ++ ++ action.sa_handler = SIG_DFL; ++ sigemptyset(&action.sa_mask); ++ if (sigaction(SIGTERM, &action, 0)) ++ return 1; ++#ifdef HAVE_SYS_PRCTL_H ++ prctl(PR_SET_PDEATHSIG, SIGKILL); ++ if (getppid() == 1) /* parent died already? */ ++ return 0; ++#endif ++ procid = i; ++ doproc(); ++ return 0; ++ } ++ } ++ while (wait(&stat) > 0 && !should_stop) { ++ continue; ++ } ++ if (should_stop) { ++ action.sa_flags = SA_RESTART; ++ sigaction(SIGTERM, &action, 0); ++ kill(-getpid(), SIGTERM); ++ while (wait(&stat) > 0) ++ continue; ++ } ++ } ++#ifndef NO_XFS ++ if (errtag != 0) { ++ memset(&err_inj, 0, sizeof(err_inj)); ++ err_inj.errtag = 0; ++ err_inj.fd = fd; ++ if ((srval = ++ ioctl(fd, XFS_IOC_ERROR_CLEARALL, ++ &err_inj)) != 0) { ++ fprintf(stderr, "Bad ej clear on %d (%d).\n", ++ fd, errno); ++ perror ++ ("fsstress - XFS_SYSSGI clear error injection call"); ++ close(fd); ++ exit(1); ++ } ++ close(fd); ++ } ++#endif ++ if (cleanup == 0) { ++ sprintf(cmd, "rm -rf %s/*", dirname); ++ system(cmd); ++ for (i = 0; i < FT_nft; i++) { ++ flist[i].nslots = 0; ++ flist[i].nfiles = 0; ++ free(flist[i].fents); ++ flist[i].fents = NULL; ++ } ++ } ++ loopcntr++; ++ } ++ return 0; ++} ++ ++void add_to_flist(int ft, int id, int parent) ++{ ++ fent_t *fep; ++ flist_t *ftp; ++ ++ ftp = &flist[ft]; ++ if (ftp->nfiles == ftp->nslots) { ++ ftp->nslots += FLIST_SLOT_INCR; ++ ftp->fents = realloc(ftp->fents, ftp->nslots * sizeof(fent_t)); ++ } ++ fep = &ftp->fents[ftp->nfiles++]; ++ fep->id = id; ++ fep->parent = parent; ++} ++ ++void append_pathname(pathname_t * name, char *str) ++{ ++ int len; ++ ++ len = strlen(str); ++#ifdef DEBUG ++ if (len && *str == '/' && name->len == 0) { ++ fprintf(stderr, "fsstress: append_pathname failure\n"); ++ chdir(homedir); ++ abort(); ++ ++ } ++#endif ++ name->path = realloc(name->path, name->len + 1 + len); ++ strcpy(&name->path[name->len], str); ++ name->len += len; ++} ++ ++#ifndef NO_XFS ++int ++attr_list_path(pathname_t * name, char *buffer, const int buffersize, int flags, ++ attrlist_cursor_t * cursor) ++{ ++ char buf[MAXNAMELEN]; ++ pathname_t newname; ++ int rval; ++ ++ rval = attr_list(name->path, buffer, buffersize, flags, cursor); ++ if (rval >= 0 || errno != ENAMETOOLONG) ++ return rval; ++ separate_pathname(name, buf, &newname); ++ if (chdir(buf) == 0) { ++ rval = attr_list_path(&newname, buffer, buffersize, flags, ++ cursor); ++ chdir(".."); ++ } ++ free_pathname(&newname); ++ return rval; ++} ++ ++int attr_remove_path(pathname_t * name, const char *attrname, int flags) ++{ ++ char buf[MAXNAMELEN]; ++ pathname_t newname; ++ int rval; ++ ++ rval = attr_remove(name->path, attrname, flags); ++ if (rval >= 0 || errno != ENAMETOOLONG) ++ return rval; ++ separate_pathname(name, buf, &newname); ++ if (chdir(buf) == 0) { ++ rval = attr_remove_path(&newname, attrname, flags); ++ chdir(".."); ++ } ++ free_pathname(&newname); ++ return rval; ++} ++ ++int ++attr_set_path(pathname_t * name, const char *attrname, const char *attrvalue, ++ const int valuelength, int flags) ++{ ++ char buf[MAXNAMELEN]; ++ pathname_t newname; ++ int rval; ++ ++ rval = attr_set(name->path, attrname, attrvalue, valuelength, flags); ++ if (rval >= 0 || errno != ENAMETOOLONG) ++ return rval; ++ separate_pathname(name, buf, &newname); ++ if (chdir(buf) == 0) { ++ rval = attr_set_path(&newname, attrname, attrvalue, valuelength, ++ flags); ++ chdir(".."); ++ } ++ free_pathname(&newname); ++ return rval; ++} ++#endif ++ ++void check_cwd(void) ++{ ++#ifdef DEBUG ++ struct stat64 statbuf; ++ ++ if (stat64(".", &statbuf) == 0 && statbuf.st_ino == top_ino) ++ return; ++ chdir(homedir); ++ fprintf(stderr, "fsstress: check_cwd failure\n"); ++ abort(); ++ ++#endif ++} ++ ++int creat_path(pathname_t * name, mode_t mode) ++{ ++ char buf[MAXNAMELEN]; ++ pathname_t newname; ++ int rval; ++ ++ rval = creat(name->path, mode); ++ if (rval >= 0 || errno != ENAMETOOLONG) ++ return rval; ++ separate_pathname(name, buf, &newname); ++ if (chdir(buf) == 0) { ++ rval = creat_path(&newname, mode); ++ chdir(".."); ++ } ++ free_pathname(&newname); ++ return rval; ++} ++ ++void dcache_enter(int dirid, int slot) ++{ ++ dcache[dirid % NDCACHE] = slot; ++} ++ ++void dcache_init(void) ++{ ++ int i; ++ ++ for (i = 0; i < NDCACHE; i++) ++ dcache[i] = -1; ++} ++ ++fent_t *dcache_lookup(int dirid) ++{ ++ fent_t *fep; ++ int i; ++ ++ i = dcache[dirid % NDCACHE]; ++ if (i >= 0 && (fep = &flist[FT_DIR].fents[i])->id == dirid) ++ return fep; ++ return NULL; ++} ++ ++void dcache_purge(int dirid) ++{ ++ int *dcp; ++ ++ dcp = &dcache[dirid % NDCACHE]; ++ if (*dcp >= 0 && flist[FT_DIR].fents[*dcp].id == dirid) ++ *dcp = -1; ++} ++ ++void del_from_flist(int ft, int slot) ++{ ++ flist_t *ftp; ++ ++ ftp = &flist[ft]; ++ if (ft == FT_DIR) ++ dcache_purge(ftp->fents[slot].id); ++ if (slot != ftp->nfiles - 1) { ++ if (ft == FT_DIR) ++ dcache_purge(ftp->fents[ftp->nfiles - 1].id); ++ ftp->fents[slot] = ftp->fents[--ftp->nfiles]; ++ } else ++ ftp->nfiles--; ++} ++ ++fent_t *dirid_to_fent(int dirid) ++{ ++ fent_t *efep; ++ fent_t *fep; ++ flist_t *flp; ++ ++ if ((fep = dcache_lookup(dirid))) ++ return fep; ++ flp = &flist[FT_DIR]; ++ for (fep = flp->fents, efep = &fep[flp->nfiles]; fep < efep; fep++) { ++ if (fep->id == dirid) { ++ dcache_enter(dirid, fep - flp->fents); ++ return fep; ++ } ++ } ++ return NULL; ++} ++ ++void doproc(void) ++{ ++ struct stat64 statbuf; ++ char buf[10]; ++ int opno; ++ int rval; ++ opdesc_t *p; ++ ++ sprintf(buf, "p%x", procid); ++ (void)mkdir(buf, 0777); ++ if (chdir(buf) < 0 || stat64(".", &statbuf) < 0) { ++ perror(buf); ++ _exit(1); ++ } ++ top_ino = statbuf.st_ino; ++ homedir = getcwd(NULL, -1); ++ seed += procid; ++ srandom(seed); ++ if (namerand) ++ namerand = random(); ++ for (opno = 0; opno < operations; opno++) { ++ p = &ops[freq_table[random() % freq_table_size]]; ++ if ((unsigned long)p->func < 4096) ++ abort(); ++ ++ p->func(opno, random()); ++ /* ++ * test for forced shutdown by stat'ing the test ++ * directory. If this stat returns EIO, assume ++ * the forced shutdown happened. ++ */ ++ if (errtag != 0 && opno % 100 == 0) { ++ rval = stat64(".", &statbuf); ++ if (rval == EIO) { ++ fprintf(stderr, "Detected EIO\n"); ++ return; ++ } ++ } ++ } ++} ++ ++void fent_to_name(pathname_t * name, flist_t * flp, fent_t * fep) ++{ ++ char buf[MAXNAMELEN]; ++ int i; ++ fent_t *pfep; ++ ++ if (fep == NULL) ++ return; ++ if (fep->parent != -1) { ++ pfep = dirid_to_fent(fep->parent); ++ fent_to_name(name, &flist[FT_DIR], pfep); ++ append_pathname(name, "/"); ++ } ++ i = sprintf(buf, "%c%x", flp->tag, fep->id); ++ namerandpad(fep->id, buf, i); ++ append_pathname(name, buf); ++} ++ ++void fix_parent(int oldid, int newid) ++{ ++ fent_t *fep; ++ flist_t *flp; ++ int i; ++ int j; ++ ++ for (i = 0, flp = flist; i < FT_nft; i++, flp++) { ++ for (j = 0, fep = flp->fents; j < flp->nfiles; j++, fep++) { ++ if (fep->parent == oldid) ++ fep->parent = newid; ++ } ++ } ++} ++ ++void free_pathname(pathname_t * name) ++{ ++ if (name->path) { ++ free(name->path); ++ name->path = NULL; ++ name->len = 0; ++ } ++} ++ ++int generate_fname(fent_t * fep, int ft, pathname_t * name, int *idp, int *v) ++{ ++ char buf[MAXNAMELEN]; ++ flist_t *flp; ++ int id; ++ int j; ++ int len; ++ ++ flp = &flist[ft]; ++ len = sprintf(buf, "%c%x", flp->tag, id = nameseq++); ++ namerandpad(id, buf, len); ++ if (fep) { ++ fent_to_name(name, &flist[FT_DIR], fep); ++ append_pathname(name, "/"); ++ } ++ append_pathname(name, buf); ++ *idp = id; ++ *v = verbose; ++ for (j = 0; !*v && j < ilistlen; j++) { ++ if (ilist[j] == id) { ++ *v = 1; ++ break; ++ } ++ } ++ return 1; ++} ++ ++int ++get_fname(int which, long r, pathname_t * name, flist_t ** flpp, fent_t ** fepp, ++ int *v) ++{ ++ int c; ++ fent_t *fep; ++ flist_t *flp; ++ int i; ++ int j; ++ int x; ++ ++ for (i = 0, c = 0, flp = flist; i < FT_nft; i++, flp++) { ++ if (which & (1 << i)) ++ c += flp->nfiles; ++ } ++ if (c == 0) { ++ if (flpp) ++ *flpp = NULL; ++ if (fepp) ++ *fepp = NULL; ++ *v = verbose; ++ return 0; ++ } ++ x = (int)(r % c); ++ for (i = 0, c = 0, flp = flist; i < FT_nft; i++, flp++) { ++ if (which & (1 << i)) { ++ if (x < c + flp->nfiles) { ++ fep = &flp->fents[x - c]; ++ if (name) ++ fent_to_name(name, flp, fep); ++ if (flpp) ++ *flpp = flp; ++ if (fepp) ++ *fepp = fep; ++ *v = verbose; ++ for (j = 0; !*v && j < ilistlen; j++) { ++ if (ilist[j] == fep->id) { ++ *v = 1; ++ break; ++ } ++ } ++ return 1; ++ } ++ c += flp->nfiles; ++ } ++ } ++#ifdef DEBUG ++ fprintf(stderr, "fsstress: get_fname failure\n"); ++ abort(); ++#endif ++ return -1; ++ ++} ++ ++void init_pathname(pathname_t * name) ++{ ++ name->len = 0; ++ name->path = NULL; ++} ++ ++int lchown_path(pathname_t * name, uid_t owner, gid_t group) ++{ ++ char buf[MAXNAMELEN]; ++ pathname_t newname; ++ int rval; ++ ++ rval = lchown(name->path, owner, group); ++ if (rval >= 0 || errno != ENAMETOOLONG) ++ return rval; ++ separate_pathname(name, buf, &newname); ++ if (chdir(buf) == 0) { ++ rval = lchown_path(&newname, owner, group); ++ chdir(".."); ++ } ++ free_pathname(&newname); ++ return rval; ++} ++ ++int link_path(pathname_t * name1, pathname_t * name2) ++{ ++ char buf1[MAXNAMELEN]; ++ char buf2[MAXNAMELEN]; ++ int down1; ++ pathname_t newname1; ++ pathname_t newname2; ++ int rval; ++ ++ rval = link(name1->path, name2->path); ++ if (rval >= 0 || errno != ENAMETOOLONG) ++ return rval; ++ separate_pathname(name1, buf1, &newname1); ++ separate_pathname(name2, buf2, &newname2); ++ if (strcmp(buf1, buf2) == 0) { ++ if (chdir(buf1) == 0) { ++ rval = link_path(&newname1, &newname2); ++ chdir(".."); ++ } ++ } else { ++ if (strcmp(buf1, "..") == 0) ++ down1 = 0; ++ else if (strcmp(buf2, "..") == 0) ++ down1 = 1; ++ else if (strlen(buf1) == 0) ++ down1 = 0; ++ else if (strlen(buf2) == 0) ++ down1 = 1; ++ else ++ down1 = MAX(newname1.len, 3 + name2->len) <= ++ MAX(3 + name1->len, newname2.len); ++ if (down1) { ++ free_pathname(&newname2); ++ append_pathname(&newname2, "../"); ++ append_pathname(&newname2, name2->path); ++ if (chdir(buf1) == 0) { ++ rval = link_path(&newname1, &newname2); ++ chdir(".."); ++ } ++ } else { ++ free_pathname(&newname1); ++ append_pathname(&newname1, "../"); ++ append_pathname(&newname1, name1->path); ++ if (chdir(buf2) == 0) { ++ rval = link_path(&newname1, &newname2); ++ chdir(".."); ++ } ++ } ++ } ++ free_pathname(&newname1); ++ free_pathname(&newname2); ++ return rval; ++} ++ ++int lstat64_path(pathname_t * name, struct stat64 *sbuf) ++{ ++ char buf[MAXNAMELEN]; ++ pathname_t newname; ++ int rval; ++ ++ rval = lstat64(name->path, sbuf); ++ if (rval >= 0 || errno != ENAMETOOLONG) ++ return rval; ++ separate_pathname(name, buf, &newname); ++ if (chdir(buf) == 0) { ++ rval = lstat64_path(&newname, sbuf); ++ chdir(".."); ++ } ++ free_pathname(&newname); ++ return rval; ++} ++ ++void make_freq_table(void) ++{ ++ int f; ++ int i; ++ opdesc_t *p; ++ ++ for (p = ops, f = 0; p < ops_end; p++) ++ f += p->freq; ++ freq_table = malloc(f * sizeof(*freq_table)); ++ freq_table_size = f; ++ for (p = ops, i = 0; p < ops_end; p++) { ++ for (f = 0; f < p->freq; f++, i++) ++ freq_table[i] = p->op; ++ } ++} ++ ++int mkdir_path(pathname_t * name, mode_t mode) ++{ ++ char buf[MAXNAMELEN]; ++ pathname_t newname; ++ int rval; ++ ++ rval = mkdir(name->path, mode); ++ if (rval >= 0 || errno != ENAMETOOLONG) ++ return rval; ++ separate_pathname(name, buf, &newname); ++ if (chdir(buf) == 0) { ++ rval = mkdir_path(&newname, mode); ++ chdir(".."); ++ } ++ free_pathname(&newname); ++ return rval; ++} ++ ++int mknod_path(pathname_t * name, mode_t mode, dev_t dev) ++{ ++ char buf[MAXNAMELEN]; ++ pathname_t newname; ++ int rval; ++ ++ rval = mknod(name->path, mode, dev); ++ if (rval >= 0 || errno != ENAMETOOLONG) ++ return rval; ++ separate_pathname(name, buf, &newname); ++ if (chdir(buf) == 0) { ++ rval = mknod_path(&newname, mode, dev); ++ chdir(".."); ++ } ++ free_pathname(&newname); ++ return rval; ++} ++ ++void namerandpad(int id, char *buf, int i) ++{ ++ int bucket; ++ static int buckets[] = { 2, 4, 8, 16, 32, 64, 128, MAXNAMELEN - 1 }; ++ int padlen; ++ int padmod; ++ ++ if (namerand == 0) ++ return; ++ bucket = (id ^ namerand) % (sizeof(buckets) / sizeof(buckets[0])); ++ padmod = buckets[bucket] + 1 - i; ++ if (padmod <= 0) ++ return; ++ padlen = (id ^ namerand) % padmod; ++ if (padlen) { ++ memset(&buf[i], 'X', padlen); ++ buf[i + padlen] = '\0'; ++ } ++} ++ ++int open_path(pathname_t * name, int oflag) ++{ ++ char buf[MAXNAMELEN]; ++ pathname_t newname; ++ int rval; ++ ++ rval = open(name->path, oflag); ++ if (rval >= 0 || errno != ENAMETOOLONG) ++ return rval; ++ separate_pathname(name, buf, &newname); ++ if (chdir(buf) == 0) { ++ rval = open_path(&newname, oflag); ++ chdir(".."); ++ } ++ free_pathname(&newname); ++ return rval; ++} ++ ++DIR *opendir_path(pathname_t * name) ++{ ++ char buf[MAXNAMELEN]; ++ pathname_t newname; ++ DIR *rval; ++ ++ rval = opendir(name->path); ++ if (rval || errno != ENAMETOOLONG) ++ return rval; ++ separate_pathname(name, buf, &newname); ++ if (chdir(buf) == 0) { ++ rval = opendir_path(&newname); ++ chdir(".."); ++ } ++ free_pathname(&newname); ++ return rval; ++} ++ ++void process_freq(char *arg) ++{ ++ opdesc_t *p; ++ char *s; ++ ++ s = strchr(arg, '='); ++ if (s == NULL) { ++ fprintf(stderr, "bad argument '%s'\n", arg); ++ exit(1); ++ } ++ *s++ = '\0'; ++ for (p = ops; p < ops_end; p++) { ++ if (strcmp(arg, p->name) == 0) { ++ p->freq = atoi(s); ++ return; ++ } ++ } ++ fprintf(stderr, "can't find op type %s for -f\n", arg); ++ exit(1); ++} ++ ++int readlink_path(pathname_t * name, char *lbuf, size_t lbufsiz) ++{ ++ char buf[MAXNAMELEN]; ++ pathname_t newname; ++ int rval; ++ ++ rval = readlink(name->path, lbuf, lbufsiz); ++ if (rval >= 0 || errno != ENAMETOOLONG) ++ return rval; ++ separate_pathname(name, buf, &newname); ++ if (chdir(buf) == 0) { ++ rval = readlink_path(&newname, lbuf, lbufsiz); ++ chdir(".."); ++ } ++ free_pathname(&newname); ++ return rval; ++} ++ ++int rename_path(pathname_t * name1, pathname_t * name2) ++{ ++ char buf1[MAXNAMELEN]; ++ char buf2[MAXNAMELEN]; ++ int down1; ++ pathname_t newname1; ++ pathname_t newname2; ++ int rval; ++ ++ rval = rename(name1->path, name2->path); ++ if (rval >= 0 || errno != ENAMETOOLONG) ++ return rval; ++ separate_pathname(name1, buf1, &newname1); ++ separate_pathname(name2, buf2, &newname2); ++ if (strcmp(buf1, buf2) == 0) { ++ if (chdir(buf1) == 0) { ++ rval = rename_path(&newname1, &newname2); ++ chdir(".."); ++ } ++ } else { ++ if (strcmp(buf1, "..") == 0) ++ down1 = 0; ++ else if (strcmp(buf2, "..") == 0) ++ down1 = 1; ++ else if (strlen(buf1) == 0) ++ down1 = 0; ++ else if (strlen(buf2) == 0) ++ down1 = 1; ++ else ++ down1 = MAX(newname1.len, 3 + name2->len) <= ++ MAX(3 + name1->len, newname2.len); ++ if (down1) { ++ free_pathname(&newname2); ++ append_pathname(&newname2, "../"); ++ append_pathname(&newname2, name2->path); ++ if (chdir(buf1) == 0) { ++ rval = rename_path(&newname1, &newname2); ++ chdir(".."); ++ } ++ } else { ++ free_pathname(&newname1); ++ append_pathname(&newname1, "../"); ++ append_pathname(&newname1, name1->path); ++ if (chdir(buf2) == 0) { ++ rval = rename_path(&newname1, &newname2); ++ chdir(".."); ++ } ++ } ++ } ++ free_pathname(&newname1); ++ free_pathname(&newname2); ++ return rval; ++} ++ ++int rmdir_path(pathname_t * name) ++{ ++ char buf[MAXNAMELEN]; ++ pathname_t newname; ++ int rval; ++ ++ rval = rmdir(name->path); ++ if (rval >= 0 || errno != ENAMETOOLONG) ++ return rval; ++ separate_pathname(name, buf, &newname); ++ if (chdir(buf) == 0) { ++ rval = rmdir_path(&newname); ++ chdir(".."); ++ } ++ free_pathname(&newname); ++ return rval; ++} ++ ++void separate_pathname(pathname_t * name, char *buf, pathname_t * newname) ++{ ++ char *slash; ++ ++ init_pathname(newname); ++ slash = strchr(name->path, '/'); ++ if (slash == NULL) { ++ buf[0] = '\0'; ++ return; ++ } ++ *slash = '\0'; ++ strcpy(buf, name->path); ++ *slash = '/'; ++ append_pathname(newname, slash + 1); ++} ++ ++#define WIDTH 80 ++ ++void show_ops(int flag, char *lead_str) ++{ ++ opdesc_t *p; ++ ++ if (flag < 0) { ++ /* print in list form */ ++ int x = WIDTH; ++ ++ for (p = ops; p < ops_end; p++) { ++ if (lead_str != NULL ++ && x + strlen(p->name) >= WIDTH - 5) ++ x = printf("%s%s", (p == ops) ? "" : "\n", ++ lead_str); ++ x += printf("%s ", p->name); ++ } ++ printf("\n"); ++ } else { ++ int f; ++ for (f = 0, p = ops; p < ops_end; p++) ++ f += p->freq; ++ ++ if (f == 0) ++ flag = 1; ++ ++ for (p = ops; p < ops_end; p++) { ++ if (flag != 0 || p->freq > 0) { ++ if (lead_str != NULL) ++ printf("%s", lead_str); ++ printf("%20s %d/%d %s\n", ++ p->name, p->freq, f, ++ (p->iswrite == 0) ? " " : "write op"); ++ } ++ } ++ } ++} ++ ++int stat64_path(pathname_t * name, struct stat64 *sbuf) ++{ ++ char buf[MAXNAMELEN]; ++ pathname_t newname; ++ int rval; ++ ++ rval = stat64(name->path, sbuf); ++ if (rval >= 0 || errno != ENAMETOOLONG) ++ return rval; ++ separate_pathname(name, buf, &newname); ++ if (chdir(buf) == 0) { ++ rval = stat64_path(&newname, sbuf); ++ chdir(".."); ++ } ++ free_pathname(&newname); ++ return rval; ++} ++ ++int symlink_path(const char *name1, pathname_t * name) ++{ ++ char buf[MAXNAMELEN]; ++ pathname_t newname; ++ int rval; ++ ++ if (!strcmp(name1, name->path)) { ++ printf("yikes! %s %s\n", name1, name->path); ++ return 0; ++ } ++ ++ rval = symlink(name1, name->path); ++ if (rval >= 0 || errno != ENAMETOOLONG) ++ return rval; ++ separate_pathname(name, buf, &newname); ++ if (chdir(buf) == 0) { ++ rval = symlink_path(name1, &newname); ++ chdir(".."); ++ } ++ free_pathname(&newname); ++ return rval; ++} ++ ++int truncate64_path(pathname_t * name, off64_t length) ++{ ++ char buf[MAXNAMELEN]; ++ pathname_t newname; ++ int rval; ++ ++ rval = truncate64(name->path, length); ++ if (rval >= 0 || errno != ENAMETOOLONG) ++ return rval; ++ separate_pathname(name, buf, &newname); ++ if (chdir(buf) == 0) { ++ rval = truncate64_path(&newname, length); ++ chdir(".."); ++ } ++ free_pathname(&newname); ++ return rval; ++} ++ ++int unlink_path(pathname_t * name) ++{ ++ char buf[MAXNAMELEN]; ++ pathname_t newname; ++ int rval; ++ ++ rval = unlink(name->path); ++ if (rval >= 0 || errno != ENAMETOOLONG) ++ return rval; ++ separate_pathname(name, buf, &newname); ++ if (chdir(buf) == 0) { ++ rval = unlink_path(&newname); ++ chdir(".."); ++ } ++ free_pathname(&newname); ++ return rval; ++} ++ ++void usage(void) ++{ ++ printf("Usage: %s -H or\n", myprog); ++ printf ++ (" %s [-c][-d dir][-e errtg][-f op_name=freq][-l loops][-n nops]\n", ++ myprog); ++ printf(" [-p nproc][-r len][-s seed][-v][-w][-z][-S]\n"); ++ printf("where\n"); ++ printf ++ (" -c specifies not to remove files(cleanup) after execution\n"); ++ printf ++ (" -d dir specifies the base directory for operations\n"); ++ printf(" -e errtg specifies error injection stuff\n"); ++ printf ++ (" -f op_name=freq changes the frequency of option name to freq\n"); ++ printf(" the valid operation names are:\n"); ++ show_ops(-1, " "); ++ printf ++ (" -l loops specifies the no. of times the testrun should loop.\n"); ++ printf(" *use 0 for infinite (default 1)\n"); ++ printf ++ (" -n nops specifies the no. of operations per process (default 1)\n"); ++ printf ++ (" -p nproc specifies the no. of processes (default 1)\n"); ++ printf(" -r specifies random name padding\n"); ++ printf ++ (" -s seed specifies the seed for the random generator (default random)\n"); ++ printf(" -v specifies verbose mode\n"); ++ printf ++ (" -w zeros frequencies of non-write operations\n"); ++ printf(" -z zeros frequencies of all operations\n"); ++ printf ++ (" -S prints the table of operations (omitting zero frequency)\n"); ++ printf(" -H prints usage and exits\n"); ++ printf ++ (" -X don't do anything XFS specific (default with -DNO_XFS)\n"); ++} ++ ++void write_freq(void) ++{ ++ opdesc_t *p; ++ ++ for (p = ops; p < ops_end; p++) { ++ if (!p->iswrite) ++ p->freq = 0; ++ } ++} ++ ++void zero_freq(void) ++{ ++ opdesc_t *p; ++ ++ for (p = ops; p < ops_end; p++) ++ p->freq = 0; ++} ++ ++#ifndef NO_XFS ++ ++void allocsp_f(int opno, long r) ++{ ++ int e; ++ pathname_t f; ++ int fd; ++ struct xfs_flock64 fl; ++ __s64 lr; ++ __s64 off; ++ struct stat64 stb; ++ int v; ++ ++ init_pathname(&f); ++ if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) { ++ if (v) ++ printf("%d/%d: allocsp - no filename\n", procid, opno); ++ free_pathname(&f); ++ return; ++ } ++ fd = open_path(&f, O_RDWR); ++ e = fd < 0 ? errno : 0; ++ check_cwd(); ++ if (fd < 0) { ++ if (v) ++ printf("%d/%d: allocsp - open %s failed %d\n", ++ procid, opno, f.path, e); ++ free_pathname(&f); ++ return; ++ } ++ if (fstat64(fd, &stb) < 0) { ++ if (v) ++ printf("%d/%d: allocsp - fstat64 %s failed %d\n", ++ procid, opno, f.path, errno); ++ free_pathname(&f); ++ close(fd); ++ return; ++ } ++ lr = ((__s64) random() << 32) + random(); ++ off = lr % MIN(stb.st_size + (1024 * 1024), MAXFSIZE); ++ off %= maxfsize; ++ memset(&fl, 0, sizeof(fl)); ++ fl.l_whence = SEEK_SET; ++ fl.l_start = off; ++ fl.l_len = 0; ++ e = ioctl(fd, XFS_IOC_ALLOCSP64, &fl) < 0 ? errno : 0; ++ if (v) ++ printf("%d/%d: ioctl(XFS_IOC_ALLOCSP64) %s %lld 0 %d\n", ++ procid, opno, f.path, (long long)off, e); ++ free_pathname(&f); ++ close(fd); ++} ++ ++void attr_remove_f(int opno, long r) ++{ ++ attrlist_ent_t *aep; ++ attrlist_t *alist; ++ char *aname; ++ char buf[4096]; ++ attrlist_cursor_t cursor; ++ int e; ++ int ent; ++ pathname_t f; ++ int total; ++ int v; ++ int which; ++ ++ init_pathname(&f); ++ if (!get_fname(FT_ANYm, r, &f, NULL, NULL, &v)) ++ append_pathname(&f, "."); ++ total = 0; ++ memset(&cursor, 0x00, sizeof(cursor)); ++ do { ++ e = attr_list_path(&f, buf, sizeof(buf), ATTR_DONTFOLLOW, ++ &cursor); ++ check_cwd(); ++ if (e) ++ break; ++ alist = (attrlist_t *) buf; ++ total += alist->al_count; ++ } while (alist->al_more); ++ if (total == 0) { ++ if (v) ++ printf("%d/%d: attr_remove - no attrs for %s\n", ++ procid, opno, f.path); ++ free_pathname(&f); ++ return; ++ } ++ which = (int)(random() % total); ++ memset(&cursor, 0x00, sizeof(cursor)); ++ ent = 0; ++ aname = NULL; ++ do { ++ e = attr_list_path(&f, buf, sizeof(buf), ATTR_DONTFOLLOW, ++ &cursor); ++ check_cwd(); ++ if (e) ++ break; ++ alist = (attrlist_t *) buf; ++ if (which < ent + alist->al_count) { ++ aep = (attrlist_ent_t *) ++ & buf[alist->al_offset[which - ent]]; ++ aname = aep->a_name; ++ break; ++ } ++ ent += alist->al_count; ++ } while (alist->al_more); ++ if (aname == NULL) { ++ if (v) ++ printf("%d/%d: attr_remove - name %d not found at %s\n", ++ procid, opno, which, f.path); ++ free_pathname(&f); ++ return; ++ } ++ e = attr_remove_path(&f, aname, ATTR_DONTFOLLOW) < 0 ? errno : 0; ++ check_cwd(); ++ if (v) ++ printf("%d/%d: attr_remove %s %s %d\n", ++ procid, opno, f.path, aname, e); ++ free_pathname(&f); ++} ++ ++void attr_set_f(int opno, long r) ++{ ++ char aname[10]; ++ char *aval; ++ int e; ++ pathname_t f; ++ int len; ++ static int lengths[] = { 10, 100, 1000, 10000 }; ++ int li; ++ int v; ++ ++ init_pathname(&f); ++ if (!get_fname(FT_ANYm, r, &f, NULL, NULL, &v)) ++ append_pathname(&f, "."); ++ sprintf(aname, "a%x", nameseq++); ++ li = (int)(random() % (sizeof(lengths) / sizeof(lengths[0]))); ++ len = (int)(random() % lengths[li]); ++ if (len == 0) ++ len = 1; ++ aval = malloc(len); ++ memset(aval, nameseq & 0xff, len); ++ e = attr_set_path(&f, aname, aval, len, ATTR_DONTFOLLOW) < 0 ? ++ errno : 0; ++ check_cwd(); ++ free(aval); ++ if (v) ++ printf("%d/%d: attr_set %s %s %d\n", procid, opno, f.path, ++ aname, e); ++ free_pathname(&f); ++} ++ ++void bulkstat_f(int opno, long r) ++{ ++ __s32 count; ++ int fd; ++ __u64 last; ++ __s32 nent; ++ xfs_bstat_t *t; ++ __int64_t total; ++ xfs_fsop_bulkreq_t bsr; ++ ++ last = 0; ++ nent = (r % 999) + 2; ++ t = malloc(nent * sizeof(*t)); ++ fd = open(".", O_RDONLY); ++ total = 0; ++ ++ memset(&bsr, 0, sizeof(bsr)); ++ bsr.lastip = &last; ++ bsr.icount = nent; ++ bsr.ubuffer = t; ++ bsr.ocount = &count; ++ ++ while (ioctl(fd, XFS_IOC_FSBULKSTAT, &bsr) == 0 && count > 0) ++ total += count; ++ free(t); ++ if (verbose) ++ printf("%d/%d: bulkstat nent %d total %lld\n", ++ procid, opno, (int)nent, (long long)total); ++ close(fd); ++} ++ ++void bulkstat1_f(int opno, long r) ++{ ++ int e; ++ pathname_t f; ++ int fd; ++ int good; ++ __u64 ino; ++ struct stat64 s; ++ xfs_bstat_t t; ++ int v; ++ xfs_fsop_bulkreq_t bsr; ++ ++ good = random() & 1; ++ if (good) { ++ /* use an inode we know exists */ ++ init_pathname(&f); ++ if (!get_fname(FT_ANYm, r, &f, NULL, NULL, &v)) ++ append_pathname(&f, "."); ++ ino = stat64_path(&f, &s) < 0 ? (ino64_t) r : s.st_ino; ++ check_cwd(); ++ free_pathname(&f); ++ } else { ++ /* ++ * pick a random inode ++ * ++ * note this can generate kernel warning messages ++ * since bulkstat_one will read the disk block that ++ * would contain a given inode even if that disk ++ * block doesn't contain inodes. ++ * ++ * this is detected later, but not until after the ++ * warning is displayed. ++ * ++ * "XFS: device 0x825- bad inode magic/vsn daddr 0x0 #0" ++ * ++ */ ++ ino = (ino64_t) r; ++ v = verbose; ++ } ++ fd = open(".", O_RDONLY); ++ ++ memset(&bsr, 0, sizeof(bsr)); ++ bsr.lastip = &ino; ++ bsr.icount = 1; ++ bsr.ubuffer = &t; ++ bsr.ocount = NULL; ++ ++ e = ioctl(fd, XFS_IOC_FSBULKSTAT_SINGLE, &bsr) < 0 ? errno : 0; ++ if (v) ++ printf("%d/%d: bulkstat1 %s ino %lld %d\n", ++ procid, opno, good ? "real" : "random", ++ (long long)ino, e); ++ close(fd); ++} ++ ++#endif ++ ++void chown_f(int opno, long r) ++{ ++ int e; ++ pathname_t f; ++ int nbits; ++ uid_t u; ++ int v; ++ ++ init_pathname(&f); ++ if (!get_fname(FT_ANYm, r, &f, NULL, NULL, &v)) ++ append_pathname(&f, "."); ++ u = (uid_t) random(); ++ nbits = (int)(random() % 32); ++ u &= (1 << nbits) - 1; ++ e = lchown_path(&f, u, -1) < 0 ? errno : 0; ++ check_cwd(); ++ if (v) ++ printf("%d/%d: chown %s %d %d\n", procid, opno, f.path, u, e); ++ free_pathname(&f); ++} ++ ++void creat_f(int opno, long r) ++{ ++ int e; ++ int e1; ++ int extsize; ++ pathname_t f; ++ int fd; ++ fent_t *fep; ++ int id; ++ int parid; ++ int type; ++ int v; ++ int v1; ++ int esz = 0; ++ ++ if (!get_fname(FT_DIRm, r, NULL, NULL, &fep, &v1)) ++ parid = -1; ++ else ++ parid = fep->id; ++ init_pathname(&f); ++ type = rtpct ? ((random() % 100) > rtpct ? FT_REG : FT_RTF) : FT_REG; ++ if (type == FT_RTF) ++ extsize = (random() % 10) + 1; ++ else ++ extsize = 0; ++ e = generate_fname(fep, type, &f, &id, &v); ++ v |= v1; ++ if (!e) { ++ if (v) { ++ fent_to_name(&f, &flist[FT_DIR], fep); ++ printf("%d/%d: creat - no filename from %s\n", ++ procid, opno, f.path); ++ } ++ free_pathname(&f); ++ return; ++ } ++ fd = creat_path(&f, 0666); ++ e = fd < 0 ? errno : 0; ++ e1 = 0; ++ check_cwd(); ++ esz = 0; ++ if (fd >= 0) { ++#ifndef NO_XFS ++ struct fsxattr a; ++ memset(&a, 0, sizeof(a)); ++ if (extsize && ioctl(fd, XFS_IOC_FSGETXATTR, &a) >= 0) { ++ a.fsx_xflags |= XFS_XFLAG_REALTIME; ++ a.fsx_extsize = ++ geom.rtextsize * geom.blocksize * extsize; ++ if (ioctl(fd, XFS_IOC_FSSETXATTR, &a) < 0) ++ e1 = errno; ++ esz = a.fsx_extsize; ++ ++ } ++#endif ++ add_to_flist(type, id, parid); ++ close(fd); ++ } ++ if (v) ++ printf("%d/%d: creat %s x:%d %d %d\n", procid, opno, f.path, ++ esz, e, e1); ++ free_pathname(&f); ++} ++ ++int setdirect(int fd) ++{ ++ static int no_direct; ++ int flags; ++ ++ if (no_direct) ++ return 0; ++ ++ flags = fcntl(fd, F_GETFL, 0); ++ if (flags < 0) ++ return 0; ++ ++ if (fcntl(fd, F_SETFL, flags | O_DIRECT) < 0) { ++ if (no_xfs) { ++ no_direct = 1; ++ return 0; ++ } ++ printf("cannot set O_DIRECT: %s\n", strerror(errno)); ++ return 0; ++ } ++ ++ return 1; ++} ++ ++void dread_f(int opno, long r) ++{ ++ __int64_t align; ++ char *buf = NULL; ++ struct dioattr diob; ++ int e; ++ pathname_t f; ++ int fd; ++ size_t len; ++ __int64_t lr; ++ off64_t off; ++ struct stat64 stb; ++ int v; ++ ++ init_pathname(&f); ++ if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) { ++ if (v) ++ printf("%d/%d: dread - no filename\n", procid, opno); ++ free_pathname(&f); ++ return; ++ } ++ fd = open_path(&f, O_RDONLY); ++ ++ e = fd < 0 ? errno : 0; ++ check_cwd(); ++ if (fd < 0) { ++ if (v) ++ printf("%d/%d: dread - open %s failed %d\n", ++ procid, opno, f.path, e); ++ free_pathname(&f); ++ return; ++ } ++ ++ if (!setdirect(fd)) { ++ close(fd); ++ free_pathname(&f); ++ return; ++ } ++ ++ if (fstat64(fd, &stb) < 0) { ++ if (v) ++ printf("%d/%d: dread - fstat64 %s failed %d\n", ++ procid, opno, f.path, errno); ++ free_pathname(&f); ++ close(fd); ++ return; ++ } ++ if (stb.st_size == 0) { ++ if (v) ++ printf("%d/%d: dread - %s zero size\n", procid, opno, ++ f.path); ++ free_pathname(&f); ++ close(fd); ++ return; ++ } ++ ++ memset(&diob, 0, sizeof(diob)); ++ if (no_xfs) { ++ diob.d_miniosz = stb.st_blksize; ++ diob.d_maxiosz = stb.st_blksize * 256; /* good number ? */ ++ diob.d_mem = stb.st_blksize; ++ } ++#ifndef NO_XFS ++ else if (ioctl(fd, XFS_IOC_DIOINFO, &diob) < 0) { ++ if (v) ++ printf ++ ("%d/%d: dread - ioctl(fd, XFS_IOC_DIOINFO) %s failed %d\n", ++ procid, opno, f.path, errno); ++ free_pathname(&f); ++ close(fd); ++ return; ++ } ++#endif ++ align = (__int64_t) diob.d_miniosz; ++ lr = ((__int64_t) random() << 32) + random(); ++ off = (off64_t) (lr % stb.st_size); ++ off -= (off % align); ++ lseek64(fd, off, SEEK_SET); ++ len = (random() % (getpagesize() * 32)) + 1; ++ len -= (len % align); ++ if (len <= 0) ++ len = align; ++ else if (len > diob.d_maxiosz) ++ len = diob.d_maxiosz; ++ if ((e = posix_memalign((void **)&buf, diob.d_mem, len)) != 0) { ++ fprintf(stderr, "posix_memalign: %s\n", strerror(e)); ++ exit(1); ++ } ++ if (buf == NULL) { ++ fprintf(stderr, "posix_memalign: buf is NULL\n"); ++ exit(1); ++ } ++ e = read(fd, buf, len) < 0 ? errno : 0; ++ free(buf); ++ if (v) ++ printf("%d/%d: dread %s [%lld,%ld] %d\n", ++ procid, opno, f.path, (long long int)off, (long)len, e); ++ free_pathname(&f); ++ close(fd); ++} ++ ++void dwrite_f(int opno, long r) ++{ ++ __int64_t align; ++ char *buf = NULL; ++ struct dioattr diob; ++ int e; ++ pathname_t f; ++ int fd; ++ size_t len; ++ __int64_t lr; ++ off64_t off; ++ struct stat64 stb; ++ int v; ++ ++ init_pathname(&f); ++ if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) { ++ if (v) ++ printf("%d/%d: dwrite - no filename\n", procid, opno); ++ free_pathname(&f); ++ return; ++ } ++ fd = open_path(&f, O_WRONLY); ++ e = fd < 0 ? errno : 0; ++ check_cwd(); ++ if (fd < 0) { ++ if (v) ++ printf("%d/%d: dwrite - open %s failed %d\n", ++ procid, opno, f.path, e); ++ free_pathname(&f); ++ return; ++ } ++ ++ if (!setdirect(fd)) { ++ close(fd); ++ free_pathname(&f); ++ return; ++ } ++ if (fstat64(fd, &stb) < 0) { ++ if (v) ++ printf("%d/%d: dwrite - fstat64 %s failed %d\n", ++ procid, opno, f.path, errno); ++ free_pathname(&f); ++ close(fd); ++ return; ++ } ++ memset(&diob, 0, sizeof(diob)); ++ if (no_xfs) { ++ diob.d_miniosz = stb.st_blksize; ++ diob.d_maxiosz = stb.st_blksize * 256; /* good number ? */ ++ diob.d_mem = stb.st_blksize; ++ } ++#ifndef NO_XFS ++ else if (ioctl(fd, XFS_IOC_DIOINFO, &diob) < 0) { ++ if (v) ++ printf ++ ("%d/%d: dwrite - ioctl(fd, XFS_IOC_DIOINFO) %s failed %d\n", ++ procid, opno, f.path, errno); ++ free_pathname(&f); ++ close(fd); ++ return; ++ } ++#endif ++ align = (__int64_t) diob.d_miniosz; ++ lr = ((__int64_t) random() << 32) + random(); ++ off = (off64_t) (lr % MIN(stb.st_size + (1024 * 1024), MAXFSIZE)); ++ off -= (off % align); ++ lseek64(fd, off, SEEK_SET); ++ len = (random() % (getpagesize() * 32)) + 1; ++ len -= (len % align); ++ if (len <= 0) ++ len = align; ++ else if (len > diob.d_maxiosz) ++ len = diob.d_maxiosz; ++ if ((e = posix_memalign((void **)&buf, diob.d_mem, len)) != 0) { ++ fprintf(stderr, "posix_memalign: %s\n", strerror(e)); ++ exit(1); ++ } ++ if (buf == NULL) { ++ fprintf(stderr, "posix_memalign: buf is NULL\n"); ++ exit(1); ++ } ++ off %= maxfsize; ++ lseek64(fd, off, SEEK_SET); ++ memset(buf, nameseq & 0xff, len); ++ e = write(fd, buf, len) < 0 ? errno : 0; ++ free(buf); ++ if (v) ++ printf("%d/%d: dwrite %s [%lld,%ld] %d\n", ++ procid, opno, f.path, (long long)off, (long int)len, e); ++ free_pathname(&f); ++ close(fd); ++} ++ ++void fdatasync_f(int opno, long r) ++{ ++ int e; ++ pathname_t f; ++ int fd; ++ int v; ++ ++ init_pathname(&f); ++ if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) { ++ if (v) ++ printf("%d/%d: fdatasync - no filename\n", ++ procid, opno); ++ free_pathname(&f); ++ return; ++ } ++ fd = open_path(&f, O_WRONLY); ++ e = fd < 0 ? errno : 0; ++ check_cwd(); ++ if (fd < 0) { ++ if (v) ++ printf("%d/%d: fdatasync - open %s failed %d\n", ++ procid, opno, f.path, e); ++ free_pathname(&f); ++ return; ++ } ++ e = fdatasync(fd) < 0 ? errno : 0; ++ if (v) ++ printf("%d/%d: fdatasync %s %d\n", procid, opno, f.path, e); ++ free_pathname(&f); ++ close(fd); ++} ++ ++#ifndef NO_XFS ++void freesp_f(int opno, long r) ++{ ++ int e; ++ pathname_t f; ++ int fd; ++ struct xfs_flock64 fl; ++ __s64 lr; ++ __s64 off; ++ struct stat64 stb; ++ int v; ++ ++ init_pathname(&f); ++ if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) { ++ if (v) ++ printf("%d/%d: freesp - no filename\n", procid, opno); ++ free_pathname(&f); ++ return; ++ } ++ fd = open_path(&f, O_RDWR); ++ e = fd < 0 ? errno : 0; ++ check_cwd(); ++ if (fd < 0) { ++ if (v) ++ printf("%d/%d: freesp - open %s failed %d\n", ++ procid, opno, f.path, e); ++ free_pathname(&f); ++ return; ++ } ++ if (fstat64(fd, &stb) < 0) { ++ if (v) ++ printf("%d/%d: freesp - fstat64 %s failed %d\n", ++ procid, opno, f.path, errno); ++ free_pathname(&f); ++ close(fd); ++ return; ++ } ++ lr = ((__s64) random() << 32) + random(); ++ off = lr % MIN(stb.st_size + (1024 * 1024), MAXFSIZE); ++ off %= maxfsize; ++ memset(&fl, 0, sizeof(fl)); ++ fl.l_whence = SEEK_SET; ++ fl.l_start = off; ++ fl.l_len = 0; ++ e = ioctl(fd, XFS_IOC_FREESP64, &fl) < 0 ? errno : 0; ++ if (v) ++ printf("%d/%d: ioctl(XFS_IOC_FREESP64) %s %lld 0 %d\n", ++ procid, opno, f.path, (long long)off, e); ++ free_pathname(&f); ++ close(fd); ++} ++ ++#endif ++ ++void fsync_f(int opno, long r) ++{ ++ int e; ++ pathname_t f; ++ int fd; ++ int v; ++ ++ init_pathname(&f); ++ if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) { ++ if (v) ++ printf("%d/%d: fsync - no filename\n", procid, opno); ++ free_pathname(&f); ++ return; ++ } ++ fd = open_path(&f, O_WRONLY); ++ e = fd < 0 ? errno : 0; ++ check_cwd(); ++ if (fd < 0) { ++ if (v) ++ printf("%d/%d: fsync - open %s failed %d\n", ++ procid, opno, f.path, e); ++ free_pathname(&f); ++ return; ++ } ++ e = fsync(fd) < 0 ? errno : 0; ++ if (v) ++ printf("%d/%d: fsync %s %d\n", procid, opno, f.path, e); ++ free_pathname(&f); ++ close(fd); ++} ++ ++void getdents_f(int opno, long r) ++{ ++ DIR *dir; ++ pathname_t f; ++ int v; ++ ++ init_pathname(&f); ++ if (!get_fname(FT_DIRm, r, &f, NULL, NULL, &v)) ++ append_pathname(&f, "."); ++ dir = opendir_path(&f); ++ check_cwd(); ++ if (dir == NULL) { ++ if (v) ++ printf("%d/%d: getdents - can't open %s\n", ++ procid, opno, f.path); ++ free_pathname(&f); ++ return; ++ } ++ while (readdir64(dir) != NULL) ++ continue; ++ if (v) ++ printf("%d/%d: getdents %s 0\n", procid, opno, f.path); ++ free_pathname(&f); ++ closedir(dir); ++} ++ ++void link_f(int opno, long r) ++{ ++ int e; ++ pathname_t f; ++ fent_t *fep; ++ flist_t *flp; ++ int id; ++ pathname_t l; ++ int parid; ++ int v; ++ int v1; ++ ++ init_pathname(&f); ++ if (!get_fname(FT_NOTDIR, r, &f, &flp, NULL, &v1)) { ++ if (v1) ++ printf("%d/%d: link - no file\n", procid, opno); ++ free_pathname(&f); ++ return; ++ } ++ if (!get_fname(FT_DIRm, random(), NULL, NULL, &fep, &v)) ++ parid = -1; ++ else ++ parid = fep->id; ++ v |= v1; ++ init_pathname(&l); ++ e = generate_fname(fep, flp - flist, &l, &id, &v1); ++ v |= v1; ++ if (!e) { ++ if (v) { ++ fent_to_name(&l, &flist[FT_DIR], fep); ++ printf("%d/%d: link - no filename from %s\n", ++ procid, opno, l.path); ++ } ++ free_pathname(&l); ++ free_pathname(&f); ++ return; ++ } ++ e = link_path(&f, &l) < 0 ? errno : 0; ++ check_cwd(); ++ if (e == 0) ++ add_to_flist(flp - flist, id, parid); ++ if (v) ++ printf("%d/%d: link %s %s %d\n", procid, opno, f.path, l.path, ++ e); ++ free_pathname(&l); ++ free_pathname(&f); ++} ++ ++void mkdir_f(int opno, long r) ++{ ++ int e; ++ pathname_t f; ++ fent_t *fep; ++ int id; ++ int parid; ++ int v; ++ int v1; ++ ++ if (!get_fname(FT_DIRm, r, NULL, NULL, &fep, &v)) ++ parid = -1; ++ else ++ parid = fep->id; ++ init_pathname(&f); ++ e = generate_fname(fep, FT_DIR, &f, &id, &v1); ++ v |= v1; ++ if (!e) { ++ if (v) { ++ fent_to_name(&f, &flist[FT_DIR], fep); ++ printf("%d/%d: mkdir - no filename from %s\n", ++ procid, opno, f.path); ++ } ++ free_pathname(&f); ++ return; ++ } ++ e = mkdir_path(&f, 0777) < 0 ? errno : 0; ++ check_cwd(); ++ if (e == 0) ++ add_to_flist(FT_DIR, id, parid); ++ if (v) ++ printf("%d/%d: mkdir %s %d\n", procid, opno, f.path, e); ++ free_pathname(&f); ++} ++ ++void mknod_f(int opno, long r) ++{ ++ int e; ++ pathname_t f; ++ fent_t *fep; ++ int id; ++ int parid; ++ int v; ++ int v1; ++ ++ if (!get_fname(FT_DIRm, r, NULL, NULL, &fep, &v)) ++ parid = -1; ++ else ++ parid = fep->id; ++ init_pathname(&f); ++ e = generate_fname(fep, FT_DEV, &f, &id, &v1); ++ v |= v1; ++ if (!e) { ++ if (v) { ++ fent_to_name(&f, &flist[FT_DIR], fep); ++ printf("%d/%d: mknod - no filename from %s\n", ++ procid, opno, f.path); ++ } ++ free_pathname(&f); ++ return; ++ } ++ e = mknod_path(&f, S_IFCHR | 0444, 0) < 0 ? errno : 0; ++ check_cwd(); ++ if (e == 0) ++ add_to_flist(FT_DEV, id, parid); ++ if (v) ++ printf("%d/%d: mknod %s %d\n", procid, opno, f.path, e); ++ free_pathname(&f); ++} ++ ++void read_f(int opno, long r) ++{ ++ char *buf; ++ int e; ++ pathname_t f; ++ int fd; ++ size_t len; ++ __int64_t lr; ++ off64_t off; ++ struct stat64 stb; ++ int v; ++ ++ init_pathname(&f); ++ if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) { ++ if (v) ++ printf("%d/%d: read - no filename\n", procid, opno); ++ free_pathname(&f); ++ return; ++ } ++ fd = open_path(&f, O_RDONLY); ++ e = fd < 0 ? errno : 0; ++ check_cwd(); ++ if (fd < 0) { ++ if (v) ++ printf("%d/%d: read - open %s failed %d\n", ++ procid, opno, f.path, e); ++ free_pathname(&f); ++ return; ++ } ++ if (fstat64(fd, &stb) < 0) { ++ if (v) ++ printf("%d/%d: read - fstat64 %s failed %d\n", ++ procid, opno, f.path, errno); ++ free_pathname(&f); ++ close(fd); ++ return; ++ } ++ if (stb.st_size == 0) { ++ if (v) ++ printf("%d/%d: read - %s zero size\n", procid, opno, ++ f.path); ++ free_pathname(&f); ++ close(fd); ++ return; ++ } ++ lr = ((__int64_t) random() << 32) + random(); ++ off = (off64_t) (lr % stb.st_size); ++ lseek64(fd, off, SEEK_SET); ++ len = (random() % (getpagesize() * 32)) + 1; ++ buf = malloc(len); ++ e = read(fd, buf, len) < 0 ? errno : 0; ++ free(buf); ++ if (v) ++ printf("%d/%d: read %s [%lld,%ld] %d\n", ++ procid, opno, f.path, (long long)off, (long int)len, e); ++ free_pathname(&f); ++ close(fd); ++} ++ ++void readlink_f(int opno, long r) ++{ ++ char buf[PATH_MAX]; ++ int e; ++ pathname_t f; ++ int v; ++ ++ init_pathname(&f); ++ if (!get_fname(FT_SYMm, r, &f, NULL, NULL, &v)) { ++ if (v) ++ printf("%d/%d: readlink - no filename\n", procid, opno); ++ free_pathname(&f); ++ return; ++ } ++ e = readlink_path(&f, buf, PATH_MAX) < 0 ? errno : 0; ++ check_cwd(); ++ if (v) ++ printf("%d/%d: readlink %s %d\n", procid, opno, f.path, e); ++ free_pathname(&f); ++} ++ ++void rename_f(int opno, long r) ++{ ++ fent_t *dfep; ++ int e; ++ pathname_t f; ++ fent_t *fep; ++ flist_t *flp; ++ int id; ++ pathname_t newf; ++ int oldid; ++ int parid; ++ int v; ++ int v1; ++ ++ init_pathname(&f); ++ if (!get_fname(FT_ANYm, r, &f, &flp, &fep, &v1)) { ++ if (v1) ++ printf("%d/%d: rename - no filename\n", procid, opno); ++ free_pathname(&f); ++ return; ++ } ++ if (!get_fname(FT_DIRm, random(), NULL, NULL, &dfep, &v)) ++ parid = -1; ++ else ++ parid = dfep->id; ++ v |= v1; ++ init_pathname(&newf); ++ e = generate_fname(dfep, flp - flist, &newf, &id, &v1); ++ v |= v1; ++ if (!e) { ++ if (v) { ++ fent_to_name(&f, &flist[FT_DIR], dfep); ++ printf("%d/%d: rename - no filename from %s\n", ++ procid, opno, f.path); ++ } ++ free_pathname(&newf); ++ free_pathname(&f); ++ return; ++ } ++ e = rename_path(&f, &newf) < 0 ? errno : 0; ++ check_cwd(); ++ if (e == 0) { ++ if (flp - flist == FT_DIR) { ++ oldid = fep->id; ++ fix_parent(oldid, id); ++ } ++ del_from_flist(flp - flist, fep - flp->fents); ++ add_to_flist(flp - flist, id, parid); ++ } ++ if (v) ++ printf("%d/%d: rename %s to %s %d\n", procid, opno, f.path, ++ newf.path, e); ++ free_pathname(&newf); ++ free_pathname(&f); ++} ++ ++#ifndef NO_XFS ++void resvsp_f(int opno, long r) ++{ ++ int e; ++ pathname_t f; ++ int fd; ++ struct xfs_flock64 fl; ++ __s64 lr; ++ __s64 off; ++ struct stat64 stb; ++ int v; ++ ++ init_pathname(&f); ++ if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) { ++ if (v) ++ printf("%d/%d: resvsp - no filename\n", procid, opno); ++ free_pathname(&f); ++ return; ++ } ++ fd = open_path(&f, O_RDWR); ++ e = fd < 0 ? errno : 0; ++ check_cwd(); ++ if (fd < 0) { ++ if (v) ++ printf("%d/%d: resvsp - open %s failed %d\n", ++ procid, opno, f.path, e); ++ free_pathname(&f); ++ return; ++ } ++ if (fstat64(fd, &stb) < 0) { ++ if (v) ++ printf("%d/%d: resvsp - fstat64 %s failed %d\n", ++ procid, opno, f.path, errno); ++ free_pathname(&f); ++ close(fd); ++ return; ++ } ++ lr = ((__s64) random() << 32) + random(); ++ off = lr % MIN(stb.st_size + (1024 * 1024), MAXFSIZE); ++ off %= maxfsize; ++ memset(&fl, 0, sizeof(fl)); ++ fl.l_whence = SEEK_SET; ++ fl.l_start = off; ++ fl.l_len = (__s64) (random() % (1024 * 1024)); ++ e = ioctl(fd, XFS_IOC_RESVSP64, &fl) < 0 ? errno : 0; ++ if (v) ++ printf("%d/%d: ioctl(XFS_IOC_RESVSP64) %s %lld %lld %d\n", ++ procid, opno, f.path, (long long)off, ++ (long long)fl.l_len, e); ++ free_pathname(&f); ++ close(fd); ++} ++#endif ++ ++void rmdir_f(int opno, long r) ++{ ++ int e; ++ pathname_t f; ++ fent_t *fep; ++ int v; ++ ++ init_pathname(&f); ++ if (!get_fname(FT_DIRm, r, &f, NULL, &fep, &v)) { ++ if (v) ++ printf("%d/%d: rmdir - no directory\n", procid, opno); ++ free_pathname(&f); ++ return; ++ } ++ e = rmdir_path(&f) < 0 ? errno : 0; ++ check_cwd(); ++ if (e == 0) ++ del_from_flist(FT_DIR, fep - flist[FT_DIR].fents); ++ if (v) ++ printf("%d/%d: rmdir %s %d\n", procid, opno, f.path, e); ++ free_pathname(&f); ++} ++ ++void stat_f(int opno, long r) ++{ ++ int e; ++ pathname_t f; ++ struct stat64 stb; ++ int v; ++ ++ init_pathname(&f); ++ if (!get_fname(FT_ANYm, r, &f, NULL, NULL, &v)) { ++ if (v) ++ printf("%d/%d: stat - no entries\n", procid, opno); ++ free_pathname(&f); ++ return; ++ } ++ e = lstat64_path(&f, &stb) < 0 ? errno : 0; ++ check_cwd(); ++ if (v) ++ printf("%d/%d: stat %s %d\n", procid, opno, f.path, e); ++ free_pathname(&f); ++} ++ ++void symlink_f(int opno, long r) ++{ ++ int e; ++ pathname_t f; ++ fent_t *fep; ++ int i; ++ int id; ++ int len; ++ int parid; ++ int v; ++ int v1; ++ char *val; ++ ++ if (!get_fname(FT_DIRm, r, NULL, NULL, &fep, &v)) ++ parid = -1; ++ else ++ parid = fep->id; ++ init_pathname(&f); ++ e = generate_fname(fep, FT_SYM, &f, &id, &v1); ++ v |= v1; ++ if (!e) { ++ if (v) { ++ fent_to_name(&f, &flist[FT_DIR], fep); ++ printf("%d/%d: symlink - no filename from %s\n", ++ procid, opno, f.path); ++ } ++ free_pathname(&f); ++ return; ++ } ++ len = (int)(random() % PATH_MAX); ++ val = malloc(len + 1); ++ if (len) ++ memset(val, 'x', len); ++ val[len] = '\0'; ++ for (i = 10; i < len - 1; i += 10) ++ val[i] = '/'; ++ e = symlink_path(val, &f) < 0 ? errno : 0; ++ check_cwd(); ++ if (e == 0) ++ add_to_flist(FT_SYM, id, parid); ++ free(val); ++ if (v) ++ printf("%d/%d: symlink %s %d\n", procid, opno, f.path, e); ++ free_pathname(&f); ++} ++ ++/* ARGSUSED */ ++void sync_f(int opno, long r) ++{ ++ sync(); ++ if (verbose) ++ printf("%d/%d: sync\n", procid, opno); ++} ++ ++void truncate_f(int opno, long r) ++{ ++ int e; ++ pathname_t f; ++ __int64_t lr; ++ off64_t off; ++ struct stat64 stb; ++ int v; ++ ++ init_pathname(&f); ++ if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) { ++ if (v) ++ printf("%d/%d: truncate - no filename\n", procid, opno); ++ free_pathname(&f); ++ return; ++ } ++ e = stat64_path(&f, &stb) < 0 ? errno : 0; ++ check_cwd(); ++ if (e > 0) { ++ if (v) ++ printf("%d/%d: truncate - stat64 %s failed %d\n", ++ procid, opno, f.path, e); ++ free_pathname(&f); ++ return; ++ } ++ lr = ((__int64_t) random() << 32) + random(); ++ off = lr % MIN(stb.st_size + (1024 * 1024), MAXFSIZE); ++ off %= maxfsize; ++ e = truncate64_path(&f, off) < 0 ? errno : 0; ++ check_cwd(); ++ if (v) ++ printf("%d/%d: truncate %s %lld %d\n", procid, opno, f.path, ++ (long long)off, e); ++ free_pathname(&f); ++} ++ ++void unlink_f(int opno, long r) ++{ ++ int e; ++ pathname_t f; ++ fent_t *fep; ++ flist_t *flp; ++ int v; ++ ++ init_pathname(&f); ++ if (!get_fname(FT_NOTDIR, r, &f, &flp, &fep, &v)) { ++ if (v) ++ printf("%d/%d: unlink - no file\n", procid, opno); ++ free_pathname(&f); ++ return; ++ } ++ e = unlink_path(&f) < 0 ? errno : 0; ++ check_cwd(); ++ if (e == 0) ++ del_from_flist(flp - flist, fep - flp->fents); ++ if (v) ++ printf("%d/%d: unlink %s %d\n", procid, opno, f.path, e); ++ free_pathname(&f); ++} ++ ++#ifndef NO_XFS ++void unresvsp_f(int opno, long r) ++{ ++ int e; ++ pathname_t f; ++ int fd; ++ struct xfs_flock64 fl; ++ __s64 lr; ++ __s64 off; ++ struct stat64 stb; ++ int v; ++ ++ init_pathname(&f); ++ if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) { ++ if (v) ++ printf("%d/%d: unresvsp - no filename\n", procid, opno); ++ free_pathname(&f); ++ return; ++ } ++ fd = open_path(&f, O_RDWR); ++ e = fd < 0 ? errno : 0; ++ check_cwd(); ++ if (fd < 0) { ++ if (v) ++ printf("%d/%d: unresvsp - open %s failed %d\n", ++ procid, opno, f.path, e); ++ free_pathname(&f); ++ return; ++ } ++ if (fstat64(fd, &stb) < 0) { ++ if (v) ++ printf("%d/%d: unresvsp - fstat64 %s failed %d\n", ++ procid, opno, f.path, errno); ++ free_pathname(&f); ++ close(fd); ++ return; ++ } ++ lr = ((__s64) random() << 32) + random(); ++ off = lr % MIN(stb.st_size + (1024 * 1024), MAXFSIZE); ++ off %= maxfsize; ++ memset(&fl, 0, sizeof(fl)); ++ fl.l_whence = SEEK_SET; ++ fl.l_start = off; ++ fl.l_len = (__s64) (random() % (1 << 20)); ++ e = ioctl(fd, XFS_IOC_UNRESVSP64, &fl) < 0 ? errno : 0; ++ if (v) ++ printf("%d/%d: ioctl(XFS_IOC_UNRESVSP64) %s %lld %lld %d\n", ++ procid, opno, f.path, (long long)off, ++ (long long)fl.l_len, e); ++ free_pathname(&f); ++ close(fd); ++} ++#endif ++ ++void write_f(int opno, long r) ++{ ++ char *buf; ++ int e; ++ pathname_t f; ++ int fd; ++ size_t len; ++ __int64_t lr; ++ off64_t off; ++ struct stat64 stb; ++ int v; ++ ++ init_pathname(&f); ++ if (!get_fname(FT_REGm, r, &f, NULL, NULL, &v)) { ++ if (v) ++ printf("%d/%d: write - no filename\n", procid, opno); ++ free_pathname(&f); ++ return; ++ } ++ fd = open_path(&f, O_WRONLY); ++ e = fd < 0 ? errno : 0; ++ check_cwd(); ++ if (fd < 0) { ++ if (v) ++ printf("%d/%d: write - open %s failed %d\n", ++ procid, opno, f.path, e); ++ free_pathname(&f); ++ return; ++ } ++ if (fstat64(fd, &stb) < 0) { ++ if (v) ++ printf("%d/%d: write - fstat64 %s failed %d\n", ++ procid, opno, f.path, errno); ++ free_pathname(&f); ++ close(fd); ++ return; ++ } ++ lr = ((__int64_t) random() << 32) + random(); ++ off = (off64_t) (lr % MIN(stb.st_size + (1024 * 1024), MAXFSIZE)); ++ off %= maxfsize; ++ lseek64(fd, off, SEEK_SET); ++ len = (random() % (getpagesize() * 32)) + 1; ++ buf = malloc(len); ++ memset(buf, nameseq & 0xff, len); ++ e = write(fd, buf, len) < 0 ? errno : 0; ++ free(buf); ++ if (v) ++ printf("%d/%d: write %s [%lld,%ld] %d\n", ++ procid, opno, f.path, (long long)off, (long int)len, e); ++ free_pathname(&f); ++ close(fd); ++} +--- /dev/null ++++ b/contrib/jbd2-resync.sh +@@ -0,0 +1,19 @@ ++#!/bin/bash ++ ++if [ -z "$1" -o -z "$2" ]; then ++ echo "Usage: $0 kernel-file e2fsprogs-file" ++ exit 0 ++fi ++ ++# Transform a few things to fit the compatibility things defined in jfs_user.h. ++# Use the ext2fs_ endian conversion functions because they truncate oversized ++# inputs (e.g. passing a u32 to cpu_to_be16()) like the kernel versions and ++# unlike the libc6 versions. ++exec sed -e 's/JBD_/JFS_/g' \ ++ -e 's/JBD2_/JFS_/g' \ ++ -e 's/jbd2_journal_/journal_/g' \ ++ -e 's/__be/__u/g' \ ++ -e 's/struct kmem_cache/lkmem_cache_t/g' \ ++ -e 's/cpu_to_be/ext2fs_cpu_to_be/g' \ ++ -e 's/be\([0-9][0-9]\)_to_cpu/ext2fs_be\1_to_cpu/g' \ ++ < "$1" > "$2" +--- a/contrib/make-sparse.c ++++ b/contrib/make-sparse.c +@@ -9,8 +9,12 @@ + * %End-Header% + */ + ++#ifndef _LARGEFILE_SOURCE + #define _LARGEFILE_SOURCE ++#endif ++#ifndef _LARGEFILE64_SOURCE + #define _LARGEFILE64_SOURCE ++#endif + + #include + #include +--- /dev/null ++++ b/debugfs/Android.mk +@@ -0,0 +1,71 @@ ++LOCAL_PATH := $(call my-dir) ++ ++######################### ++# Build the debugfs binary ++ ++debugfs_src_files := \ ++ debug_cmds.c \ ++ debugfs.c \ ++ util.c \ ++ ncheck.c\ ++ icheck.c \ ++ ls.c \ ++ lsdel.c \ ++ dump.c \ ++ set_fields.c \ ++ logdump.c \ ++ htree.c \ ++ unused.c \ ++ e2freefrag.c \ ++ filefrag.c \ ++ extent_cmds.c \ ++ extent_inode.c \ ++ zap.c \ ++ create_inode.c \ ++ quota.c \ ++ xattrs.c \ ++ journal.c \ ++ revoke.c \ ++ recovery.c \ ++ do_journal.c ++ ++debugfs_shared_libraries := \ ++ libext2fs \ ++ libext2_blkid \ ++ libext2_uuid \ ++ libext2_ss \ ++ libext2_quota \ ++ libext2_com_err \ ++ libext2_e2p ++ ++debugfs_system_shared_libraries := libc ++ ++debugfs_c_includes := \ ++ external/e2fsprogs/e2fsck \ ++ external/e2fsprogs/misc \ ++ external/e2fsprogs/lib ++ ++debugfs_cflags := -O2 -g -W -Wall -fno-strict-aliasing -DDEBUGFS ++ ++include $(CLEAR_VARS) ++ ++LOCAL_SRC_FILES := $(debugfs_src_files) ++LOCAL_C_INCLUDES := $(debugfs_c_includes) ++LOCAL_CFLAGS := $(debugfs_cflags) ++LOCAL_SYSTEM_SHARED_LIBRARIES := $(debugfs_system_shared_libraries) ++LOCAL_SHARED_LIBRARIES := $(debugfs_shared_libraries) ++LOCAL_MODULE := debugfs ++LOCAL_MODULE_TAGS := optional ++include $(BUILD_EXECUTABLE) ++ ++include $(CLEAR_VARS) ++ ++LOCAL_SRC_FILES := $(debugfs_src_files) ++LOCAL_C_INCLUDES := $(debugfs_c_includes) ++LOCAL_CFLAGS := $(debugfs_cflags) ++LOCAL_SHARED_LIBRARIES := $(addsuffix _host, $(debugfs_shared_libraries)) ++LOCAL_MODULE := debugfs_host ++LOCAL_MODULE_STEM := debugfs ++LOCAL_MODULE_TAGS := optional ++ ++include $(BUILD_HOST_EXECUTABLE) +--- a/debugfs/debug_cmds.ct ++++ b/debugfs/debug_cmds.ct +@@ -157,6 +157,9 @@ + request do_bmap, "Calculate the logical->physical block mapping for an inode", + bmap; + ++request do_fallocate, "Allocate uninitialized blocks to an inode", ++ fallocate; ++ + request do_punch, "Punch (or truncate) blocks from an inode by deallocating them", + punch, truncate; + +@@ -190,6 +193,18 @@ + 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; + +@@ -199,6 +214,17 @@ + request do_idump, "Dump the inode structure in hex", + inode_dump, idump, id; + ++request do_journal_open, "Open the journal", ++ journal_open, jo; ++ ++request do_journal_close, "Close the journal", ++ journal_close, jc; ++ ++request do_journal_write, "Write a transaction to the journal", ++ journal_write, jw; ++ ++request do_journal_run, "Recover the journal", ++ journal_run, jr; + + end; + +--- a/debugfs/debugfs.8.in ++++ b/debugfs/debugfs.8.in +@@ -8,7 +8,7 @@ + .SH SYNOPSIS + .B debugfs + [ +-.B \-DVwci ++.B \-DVwcin + ] + [ + .B \-b +@@ -31,6 +31,10 @@ + data_source_device + ] + [ ++.B \-z ++.I undo_file ++] ++[ + device + ] + .SH DESCRIPTION +@@ -48,6 +52,11 @@ + 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 +@@ -125,6 +134,16 @@ + print the version number of + .B debugfs + and exit. ++.TP ++.BI \-z " undo_file" ++Before overwriting a file system block, write the old contents of the block to ++an undo file. This undo file can be used with e2undo(8) to restore the old ++contents of the file system should something go wrong. If the empty string is ++passed as the undo_file argument, the undo file will be written to a file named ++resize2fs-\fIdevice\fR.e2undo in the directory specified via the ++\fIE2FSPROGS_UNDO_DIR\fR environment variable. ++ ++WARNING: The undo file cannot be used to recover from a power or system crash. + .SH SPECIFYING FILES + Many + .B debugfs +@@ -162,11 +181,14 @@ + .I filespec + to stdout. + .TP +-.BI bmap " filespec logical_block" +-Print the physical block number corresponding to the logical block number ++.BI bmap " [ -a ] filespec logical_block [physical_block]" ++Print or set the physical block number corresponding to the logical block number + .I logical_block + in the inode + .IR filespec . ++If the ++.I -a ++flag is specified, try to allocate a block if necessary. + .TP + .BI block_dump " [-f filespec] block_num" + Dump the filesystem block given by +@@ -254,10 +276,43 @@ + may not necessarily by accurate and does not indicate a problem or + corruption in the file system.) + .TP ++.BI ea_get " [-f outfile] filespec attr_name" ++Retrieve the value of the extended attribute ++.I attr_name ++in the file ++.I filespec ++and write it either to stdout or to \fIoutfile\fR. ++.TP ++.BI ea_list " filespec ++List the extended attributes associated with the file ++.I filespec ++to standard output. ++.TP ++.BI ea_set " [-f infile] filespec attr_name attr_value ++Set the value of the extended attribute ++.I attr_name ++in the file ++.I filespec ++to the string value ++.I attr_value ++or read it from \fIinfile\fR. ++.TP ++.BI ea_rm " filespec attr_names... ++Remove the extended attribute ++.I attr_name ++from the file \fIfilespec\fR. ++.TP + .BI expand_dir " filespec" + Expand the directory + .IR filespec . + .TP ++.BI fallocate " filespec start_block [end_block] ++Allocate and map uninitialized blocks into \fIfilespec\fR between ++logical block \fIstart_block\fR and \fIend_block\fR, inclusive. If ++\fIend_block\fR is not supplied, this function maps until it runs out ++of free disk blocks or the maximum file size is reached. Existing ++mappings are left alone. ++.TP + .BI feature " [fs_feature] [-fs_feature] ..." + Set or clear various filesystem features in the superblock. After setting + or clearing any filesystem features that were requested, print the current +@@ -365,6 +420,26 @@ + program. This is just a call to the low-level library, which sets up + the superblock and block descriptors. + .TP ++.BI journal_close ++Close the open journal. ++.TP ++.BI journal_open " [-c] [-v ver] [-j ext_jnl] ++Opens the journal for reading and writing. Journal checksumming can ++be enabled by supplying \fI-c\fR; checksum formats 2 and 3 can be ++selected with the \fI-v\fR option. An external journal can be loaded ++from \fIext_jnl\fR. ++.TP ++.BI journal_run ++Replay all transactions in the open journal. ++.TP ++.BI journal_write " [-b blocks] [-r revoke] [-c] file ++Write a transaction to the open journal. The list of blocks to write ++should be supplied as a comma-separated list in \fIblocks\fR; the ++blocks themselves should be readable from \fIfile\fR. A list of ++blocks to revoke can be supplied as a comma-separated list in ++\fIrevoke\fR. By default, a commit record is written at the end; the ++\fI-c\fR switch writes an uncommitted transaction. ++.TP + .BI kill_file " filespec" + Deallocate the inode + .I filespec +@@ -387,7 +462,7 @@ + .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 +493,20 @@ + 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] [-r] 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 +@@ -433,6 +517,9 @@ + flag will list the files in a format which is more easily parsable by + scripts, as well as making it more clear when there are spaces or other + non-printing characters at the end of filenames. ++The ++.I \-r ++flag will force the printing of the filename, even if it is encrypted. + .TP + .BI list_deleted_inodes " [limit]" + List deleted inodes, optionally limited to those deleted within +@@ -469,7 +556,7 @@ + flag will enable checking the file type information in the directory + entry to make sure it matches the inode's type. + .TP +-.BI open " [-weficD] [-b blocksize] [-s superblock] device" ++.BI open " [-weficD] [-b blocksize] [-s superblock] [-z undo_file] device" + Open a filesystem for editing. The + .I -f + flag forces the filesystem to be opened even if there are some unknown +@@ -650,7 +737,6 @@ + .IR out_file . + .TP + .BI zap_block " [-f filespec] [-o offset] [-l length] [-p pattern] block_num" +-.TP + Overwrite the block specified by + .I block_num + with zero (NUL) bytes, or if +--- a/debugfs/debugfs.c ++++ b/debugfs/debugfs.c +@@ -15,6 +15,7 @@ + #include + #include + #include ++#include + #ifdef HAVE_GETOPT_H + #include + #else +@@ -25,8 +26,6 @@ + #include + #endif + #include +-#include +-#include + + #include "debugfs.h" + #include "uuid/uuid.h" +@@ -36,35 +35,101 @@ + + #include "../version.h" + #include "jfs_user.h" ++#include "support/plausible.h" + + #ifndef BUFSIZ + #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; + ++static int debugfs_setup_tdb(const char *device_name, char *undo_file, ++ io_manager *io_ptr) ++{ ++ errcode_t retval = ENOMEM; ++ char *tdb_dir = NULL, *tdb_file = NULL; ++ char *dev_name, *tmp_name; ++ ++ /* (re)open a specific undo file */ ++ if (undo_file && undo_file[0] != 0) { ++ retval = set_undo_io_backing_manager(*io_ptr); ++ if (retval) ++ goto err; ++ *io_ptr = undo_io_manager; ++ retval = set_undo_io_backup_file(undo_file); ++ if (retval) ++ goto err; ++ printf("Overwriting existing filesystem; this can be undone " ++ "using the command:\n" ++ " e2undo %s %s\n\n", ++ undo_file, device_name); ++ return retval; ++ } ++ ++ /* ++ * Configuration via a conf file would be ++ * nice ++ */ ++ tdb_dir = getenv("E2FSPROGS_UNDO_DIR"); ++ if (!tdb_dir) ++ tdb_dir = "/var/lib/e2fsprogs"; ++ ++ if (!strcmp(tdb_dir, "none") || (tdb_dir[0] == 0) || ++ access(tdb_dir, W_OK)) ++ return 0; ++ ++ tmp_name = strdup(device_name); ++ if (!tmp_name) ++ goto errout; ++ dev_name = basename(tmp_name); ++ tdb_file = malloc(strlen(tdb_dir) + 9 + strlen(dev_name) + 7 + 1); ++ if (!tdb_file) { ++ free(tmp_name); ++ goto errout; ++ } ++ sprintf(tdb_file, "%s/debugfs-%s.e2undo", tdb_dir, dev_name); ++ free(tmp_name); ++ ++ if ((unlink(tdb_file) < 0) && (errno != ENOENT)) { ++ retval = errno; ++ com_err("debugfs", retval, ++ "while trying to delete %s", tdb_file); ++ goto errout; ++ } ++ ++ retval = set_undo_io_backing_manager(*io_ptr); ++ if (retval) ++ goto errout; ++ *io_ptr = undo_io_manager; ++ retval = set_undo_io_backup_file(tdb_file); ++ if (retval) ++ goto errout; ++ printf("Overwriting existing filesystem; this can be undone " ++ "using the command:\n" ++ " e2undo %s %s\n\n", tdb_file, device_name); ++ ++ free(tdb_file); ++ return 0; ++errout: ++ free(tdb_file); ++err: ++ com_err("debugfs", retval, "while trying to setup undo file\n"); ++ return retval; ++} ++ + static void open_filesystem(char *device, int open_flags, blk64_t superblock, + blk64_t blocksize, int catastrophic, +- char *data_filename) ++ char *data_filename, char *undo_file) + { + int retval; + io_channel data_io = 0; ++ io_manager io_ptr = unix_io_manager; + + if (superblock != 0 && blocksize == 0) { + com_err(device, 0, "if you specify the superblock, you must also specify the block size"); +@@ -95,10 +160,18 @@ + if (catastrophic) + open_flags |= EXT2_FLAG_SKIP_MMP; + ++ if (undo_file) { ++ retval = debugfs_setup_tdb(device, undo_file, &io_ptr); ++ if (retval) ++ exit(1); ++ } ++ + retval = ext2fs_open(device, open_flags, superblock, blocksize, +- unix_io_manager, ¤t_fs); ++ io_ptr, ¤t_fs); + if (retval) { + com_err(device, retval, "while opening filesystem"); ++ if (retval == EXT2_ET_BAD_MAGIC) ++ check_plausibility(device, CHECK_FS_EXIST, NULL); + current_fs = NULL; + return; + } +@@ -145,9 +218,10 @@ + blk64_t blocksize = 0; + int open_flags = EXT2_FLAG_SOFTSUPP_FEATURES | EXT2_FLAG_64BITS; + char *data_filename = 0; ++ char *undo_file = NULL; + + reset_getopt(); +- while ((c = getopt (argc, argv, "iwfecb:s:d:D")) != EOF) { ++ while ((c = getopt(argc, argv, "iwfecb:s:d:Dz:")) != EOF) { + switch (c) { + case 'i': + open_flags |= EXT2_FLAG_IMAGE_FILE; +@@ -186,6 +260,9 @@ + if (err) + return; + break; ++ case 'z': ++ undo_file = optarg; ++ break; + default: + goto print_usage; + } +@@ -197,7 +274,7 @@ + return; + open_filesystem(argv[optind], open_flags, + superblock, blocksize, catastrophic, +- data_filename); ++ data_filename, undo_file); + return; + + print_usage: +@@ -373,8 +450,7 @@ + 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,36 +582,11 @@ + 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)), + struct ext2_inode_large *inode) + { +- struct ext2_ext_attr_entry *entry; +- __u32 *magic; +- char *start, *end; +- + fprintf(out, "Size of extra inode fields: %u\n", inode->i_extra_isize); + if (inode->i_extra_isize > EXT2_INODE_SIZE(current_fs->super) - + EXT2_GOOD_OLD_INODE_SIZE) { +@@ -543,33 +594,6 @@ + inode->i_extra_isize); + return; + } +- 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); +- char *name = EXT2_EXT_ATTR_NAME(entry); +- char *value = start + entry->e_value_offs; +- +- if (name + entry->e_name_len >= end || +- value + entry->e_value_size >= end || +- (char *) next >= end) { +- fprintf(out, "invalid EA entry in inode\n"); +- return; +- } +- fprintf(out, " "); +- dump_xattr_string(out, name, entry->e_name_len); +- fprintf(out, " = \""); +- dump_xattr_string(out, value, 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) +@@ -718,6 +742,56 @@ + } + 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 { ++ size_t sz = EXT2_I_SIZE(inode); ++ ++ if (sz > sizeof(inode->i_block)) ++ sz = sizeof(inode->i_block); ++ fprintf(out, "%sFast link dest: \"%.*s\"\n", prefix, (int) 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, +@@ -817,9 +891,23 @@ + 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; +@@ -840,6 +928,8 @@ + 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); + } +@@ -1574,195 +1664,25 @@ + } + + #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", + " ", 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; ++ unsigned long major, minor; + errcode_t retval; +- struct ext2_inode inode; +- int filetype, nr; ++ int nr; ++ struct stat st; + + if (check_fs_open(argv[0])) + return; +@@ -1771,115 +1691,52 @@ + com_err(argv[0], 0, "Usage: mknod [p| [c|b] ]"); + return; + } +- mode = minor = major = 0; ++ ++ 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", + "", 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], root); ++ if (retval) ++ com_err(argv[0], retval, 0); + + } + +@@ -1905,11 +1762,10 @@ + 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)); +@@ -1976,9 +1832,9 @@ + + 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; +@@ -2093,28 +1949,64 @@ + void do_bmap(int argc, char *argv[]) + { + ext2_ino_t ino; +- blk64_t blk, pblk; +- int err; ++ blk64_t blk, pblk = 0; ++ int c, err, flags = 0, ret_flags = 0; + errcode_t errcode; + +- if (common_args_process(argc, argv, 3, 3, argv[0], +- " logical_blk", 0)) ++ if (check_fs_open(argv[0])) + return; + +- ino = string_to_inode(argv[1]); ++ reset_getopt(); ++ while ((c = getopt (argc, argv, "a")) != EOF) { ++ switch (c) { ++ case 'a': ++ flags |= BMAP_ALLOC; ++ break; ++ default: ++ goto print_usage; ++ } ++ } ++ ++ if (argc <= optind+1) { ++ print_usage: ++ com_err(0, 0, ++ "Usage: bmap [-a] logical_blk [physical_blk]"); ++ return; ++ } ++ ++ ino = string_to_inode(argv[optind++]); + if (!ino) + return; +- err = strtoblk(argv[0], argv[2], "logical block", &blk); ++ err = strtoblk(argv[0], argv[optind++], "logical block", &blk); + if (err) + return; + +- errcode = ext2fs_bmap2(current_fs, ino, 0, 0, 0, blk, 0, &pblk); ++ if (argc > optind+1) ++ goto print_usage; ++ ++ if (argc == optind+1) { ++ err = strtoblk(argv[0], argv[optind++], ++ "physical block", &pblk); ++ if (err) ++ return; ++ if (flags & BMAP_ALLOC) { ++ com_err(0, 0, "Can't set and allocate a block"); ++ return; ++ } ++ flags |= BMAP_SET; ++ } ++ ++ errcode = ext2fs_bmap2(current_fs, ino, 0, 0, flags, blk, ++ &ret_flags, &pblk); + if (errcode) { + com_err(argv[0], errcode, + "while mapping logical block %llu\n", blk); + return; + } +- printf("%llu\n", pblk); ++ printf("%llu", pblk); ++ if (ret_flags & BMAP_RET_UNINIT) ++ fputs(" (uninit)", stdout); ++ fputc('\n', stdout); + } + + void do_imap(int argc, char *argv[]) +@@ -2303,51 +2195,59 @@ + return; + } + } ++ ++void do_fallocate(int argc, char *argv[]) ++{ ++ ext2_ino_t ino; ++ blk64_t start, end; ++ int err; ++ errcode_t errcode; ++ ++ if (common_args_process(argc, argv, 3, 4, argv[0], ++ " start_blk [end_blk]", ++ CHECK_FS_RW | CHECK_FS_BITMAPS)) ++ return; ++ ++ ino = string_to_inode(argv[1]); ++ if (!ino) ++ return; ++ err = strtoblk(argv[0], argv[2], "logical block", &start); ++ if (err) ++ return; ++ if (argc == 4) { ++ err = strtoblk(argv[0], argv[3], "logical block", &end); ++ if (err) ++ return; ++ } else ++ end = ~0; ++ ++ errcode = ext2fs_fallocate(current_fs, EXT2_FALLOCATE_INIT_BEYOND_EOF, ++ ino, NULL, ~0ULL, start, end - start + 1); ++ ++ if (errcode) { ++ com_err(argv[0], errcode, ++ "while fallocating inode %u from %llu to %llu\n", ino, ++ (unsigned long long) start, (unsigned long long) end); ++ return; ++ } ++} + #endif /* READ_ONLY */ + + 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", + " ", 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); + + } + ++#if CONFIG_MMP + void do_dump_mmp(int argc EXT2FS_ATTR((unused)), char *argv[]) + { + struct mmp_struct *mmp_s; +@@ -2385,7 +2285,18 @@ + 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); ++ fprintf(stdout, "MMP is unsupported, please recompile with " ++ "--enable-mmp\n"); ++} ++#else ++void do_dump_mmp(int argc EXT2FS_ATTR((unused)), ++ char *argv[] EXT2FS_ATTR((unused))) ++{ ++ fprintf(stdout, "MMP is unsupported, please recompile with " ++ "--enable-mmp\n"); + } ++#endif + + static int source_file(const char *cmd_file, int ss_idx) + { +@@ -2436,7 +2347,7 @@ + "Usage: %s [-b blocksize] [-s superblock] [-f cmd_file] " + "[-R request] [-V] [" + #ifndef READ_ONLY +- "[-w] " ++ "[-w] [-z undo_file] " + #endif + "[-c] device]"; + int c; +@@ -2449,9 +2360,10 @@ + 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:Dz:"; ++ char *undo_file = NULL; + #endif + + if (debug_prog_name == 0) +@@ -2478,6 +2390,9 @@ + 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; +@@ -2505,6 +2420,9 @@ + fprintf(stderr, "\tUsing %s\n", + error_message(EXT2_ET_BASE)); + exit(0); ++ case 'z': ++ undo_file = optarg; ++ break; + default: + com_err(argv[0], 0, usage, debug_prog_name); + return 1; +@@ -2513,7 +2431,7 @@ + if (optind < argc) + open_filesystem(argv[optind], open_flags, + superblock, blocksize, catastrophic, +- data_filename); ++ data_filename, undo_file); + + sci_idx = ss_create_invocation(debug_prog_name, "0.0", (char *) NULL, + &debug_cmds, &retval); +--- a/debugfs/debugfs.h ++++ b/debugfs/debugfs.h +@@ -5,7 +5,8 @@ + #include "ss/ss.h" + #include "ext2fs/ext2_fs.h" + #include "ext2fs/ext2fs.h" +-#include "quota/quotaio.h" ++#include "../misc/create_inode.h" ++#include "support/quotaio.h" + + #ifdef __STDC__ + #define NOARGS void +@@ -162,9 +163,11 @@ + extern void do_features(int argc, char **argv); + extern void do_bmap(int argc, char **argv); + extern void do_imap(int argc, char **argv); ++extern void do_idump(int argc, char *argv[]); + extern void do_set_current_time(int argc, char **argv); + extern void do_supported_features(int argc, char **argv); + extern void do_punch(int argc, char **argv); ++extern void do_fallocate(int argc, char **argv); + extern void do_symlink(int argc, char **argv); + + extern void do_dump_mmp(int argc, char **argv); +@@ -173,12 +176,27 @@ + extern void do_freefrag(int argc, char **argv); + extern void do_filefrag(int argc, char *argv[]); + ++/* do_journal.c */ ++ ++extern void do_journal_write(int argc, char *argv[]); ++extern void do_journal_open(int argc, char *argv[]); ++extern void do_journal_close(int argc, char *argv[]); ++extern void do_journal_run(int argc, char *argv[]); ++ + /* quota.c */ + extern void do_list_quota(int argc, char *argv[]); + extern void do_get_quota(int argc, char *argv[]); + + /* util.c */ + extern time_t string_to_time(const char *arg); ++errcode_t read_list(char *str, blk64_t **list, size_t *len); ++ ++/* 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); +--- /dev/null ++++ b/debugfs/do_journal.c +@@ -0,0 +1,985 @@ ++/* ++ * do_journal.c --- Scribble onto the journal! ++ * ++ * Copyright (C) 2014 Oracle. This file may be redistributed ++ * under the terms of the GNU Public License. ++ */ ++ ++#include "config.h" ++#include ++#ifdef HAVE_GETOPT_H ++#include ++#else ++extern int optind; ++extern char *optarg; ++#endif ++#include ++#include ++#ifdef HAVE_SYS_TIME_H ++#include ++#endif ++ ++#include "debugfs.h" ++#include "ext2fs/kernel-jbd.h" ++#include "journal.h" ++ ++#undef DEBUG ++ ++#ifdef DEBUG ++# define dbg_printf(f, a...) do {printf("JFS DEBUG: " f, ## a); \ ++ fflush(stdout); \ ++} while (0) ++#else ++# define dbg_printf(f, a...) ++#endif ++ ++#define JOURNAL_CHECK_TRANS_MAGIC(x) \ ++ do { \ ++ if ((x)->magic != J_TRANS_MAGIC) \ ++ return EXT2_ET_INVALID_ARGUMENT; \ ++ } while (0) ++ ++#define J_TRANS_MAGIC 0xD15EA5ED ++#define J_TRANS_OPEN 1 ++#define J_TRANS_COMMITTED 2 ++struct journal_transaction_s { ++ unsigned int magic; ++ ext2_filsys fs; ++ journal_t *journal; ++ blk64_t block; ++ blk64_t start, end; ++ tid_t tid; ++ int flags; ++}; ++ ++typedef struct journal_transaction_s journal_transaction_t; ++ ++static journal_t *current_journal = NULL; ++ ++static void journal_dump_trans(journal_transaction_t *trans EXT2FS_ATTR((unused)), ++ const char *tag EXT2FS_ATTR((unused))) ++{ ++ dbg_printf("TRANS %p(%s): tid=%d start=%llu block=%llu end=%llu " ++ "flags=0x%x\n", trans, tag, trans->tid, trans->start, ++ trans->block, trans->end, trans->flags); ++} ++ ++static errcode_t journal_commit_trans(journal_transaction_t *trans) ++{ ++ struct buffer_head *bh, *cbh = NULL; ++ struct commit_header *commit; ++#ifdef HAVE_SYS_TIME_H ++ struct timeval tv; ++#endif ++ errcode_t err; ++ ++ JOURNAL_CHECK_TRANS_MAGIC(trans); ++ ++ if ((trans->flags & J_TRANS_COMMITTED) || ++ !(trans->flags & J_TRANS_OPEN)) ++ return EXT2_ET_INVALID_ARGUMENT; ++ ++ bh = getblk(trans->journal->j_dev, 0, trans->journal->j_blocksize); ++ if (bh == NULL) ++ return ENOMEM; ++ ++ /* write the descriptor block header */ ++ commit = (struct commit_header *)bh->b_data; ++ commit->h_magic = ext2fs_cpu_to_be32(JFS_MAGIC_NUMBER); ++ commit->h_blocktype = ext2fs_cpu_to_be32(JFS_COMMIT_BLOCK); ++ commit->h_sequence = ext2fs_cpu_to_be32(trans->tid); ++ if (JFS_HAS_COMPAT_FEATURE(trans->journal, ++ JFS_FEATURE_COMPAT_CHECKSUM)) { ++ __u32 csum_v1 = ~0; ++ blk64_t cblk; ++ ++ cbh = getblk(trans->journal->j_dev, 0, ++ trans->journal->j_blocksize); ++ if (cbh == NULL) { ++ err = ENOMEM; ++ goto error; ++ } ++ ++ for (cblk = trans->start; cblk < trans->block; cblk++) { ++ err = journal_bmap(trans->journal, cblk, ++ &cbh->b_blocknr); ++ if (err) ++ goto error; ++ mark_buffer_uptodate(cbh, 0); ++ ll_rw_block(READ, 1, &cbh); ++ err = cbh->b_err; ++ if (err) ++ goto error; ++ csum_v1 = ext2fs_crc32_be(csum_v1, ++ (unsigned char const *)cbh->b_data, ++ cbh->b_size); ++ } ++ ++ commit->h_chksum_type = JFS_CRC32_CHKSUM; ++ commit->h_chksum_size = JFS_CRC32_CHKSUM_SIZE; ++ commit->h_chksum[0] = ext2fs_cpu_to_be32(csum_v1); ++ } else { ++ commit->h_chksum_type = 0; ++ commit->h_chksum_size = 0; ++ commit->h_chksum[0] = 0; ++ } ++#ifdef HAVE_SYS_TIME_H ++ gettimeofday(&tv, NULL); ++ commit->h_commit_sec = ext2fs_cpu_to_be32(tv.tv_sec); ++ commit->h_commit_nsec = ext2fs_cpu_to_be32(tv.tv_usec * 1000); ++#else ++ commit->h_commit_sec = 0; ++ commit->h_commit_nsec = 0; ++#endif ++ ++ /* Write block */ ++ jbd2_commit_block_csum_set(trans->journal, bh); ++ err = journal_bmap(trans->journal, trans->block, &bh->b_blocknr); ++ if (err) ++ goto error; ++ ++ dbg_printf("Writing commit block at %llu:%llu\n", trans->block, ++ bh->b_blocknr); ++ mark_buffer_dirty(bh); ++ ll_rw_block(WRITE, 1, &bh); ++ err = bh->b_err; ++ if (err) ++ goto error; ++ trans->flags |= J_TRANS_COMMITTED; ++ trans->flags &= ~J_TRANS_OPEN; ++ trans->block++; ++ ++ trans->fs->super->s_feature_incompat |= EXT3_FEATURE_INCOMPAT_RECOVER; ++ ext2fs_mark_super_dirty(trans->fs); ++error: ++ if (cbh) ++ brelse(cbh); ++ brelse(bh); ++ return err; ++} ++ ++static errcode_t journal_add_revoke_to_trans(journal_transaction_t *trans, ++ blk64_t *revoke_list, ++ size_t revoke_len) ++{ ++ journal_revoke_header_t *jrb; ++ void *buf; ++ size_t i, offset; ++ blk64_t curr_blk; ++ int sz, csum_size = 0; ++ struct buffer_head *bh; ++ errcode_t err; ++ ++ JOURNAL_CHECK_TRANS_MAGIC(trans); ++ ++ if ((trans->flags & J_TRANS_COMMITTED) || ++ !(trans->flags & J_TRANS_OPEN)) ++ return EXT2_ET_INVALID_ARGUMENT; ++ ++ if (revoke_len == 0) ++ return 0; ++ ++ /* Do we need to leave space at the end for a checksum? */ ++ if (journal_has_csum_v2or3(trans->journal)) ++ csum_size = sizeof(struct journal_revoke_tail); ++ ++ curr_blk = trans->block; ++ ++ bh = getblk(trans->journal->j_dev, curr_blk, ++ trans->journal->j_blocksize); ++ if (bh == NULL) ++ return ENOMEM; ++ jrb = buf = bh->b_data; ++ jrb->r_header.h_magic = ext2fs_cpu_to_be32(JFS_MAGIC_NUMBER); ++ jrb->r_header.h_blocktype = ext2fs_cpu_to_be32(JFS_REVOKE_BLOCK); ++ jrb->r_header.h_sequence = ext2fs_cpu_to_be32(trans->tid); ++ offset = sizeof(*jrb); ++ ++ if (JFS_HAS_INCOMPAT_FEATURE(trans->journal, ++ JFS_FEATURE_INCOMPAT_64BIT)) ++ sz = 8; ++ else ++ sz = 4; ++ ++ for (i = 0; i < revoke_len; i++) { ++ /* Block full, write to journal */ ++ if (offset + sz > trans->journal->j_blocksize - csum_size) { ++ jrb->r_count = ext2fs_cpu_to_be32(offset); ++ jbd2_revoke_csum_set(trans->journal, bh); ++ ++ err = journal_bmap(trans->journal, curr_blk, ++ &bh->b_blocknr); ++ if (err) ++ goto error; ++ dbg_printf("Writing revoke block at %llu:%llu\n", ++ curr_blk, bh->b_blocknr); ++ mark_buffer_dirty(bh); ++ ll_rw_block(WRITE, 1, &bh); ++ err = bh->b_err; ++ if (err) ++ goto error; ++ ++ offset = sizeof(*jrb); ++ curr_blk++; ++ } ++ ++ if (revoke_list[i] >= ++ ext2fs_blocks_count(trans->journal->j_fs_dev->k_fs->super)) { ++ err = EXT2_ET_BAD_BLOCK_NUM; ++ goto error; ++ } ++ ++ if (JFS_HAS_INCOMPAT_FEATURE(trans->journal, ++ JFS_FEATURE_INCOMPAT_64BIT)) ++ *((__u64 *)(&((char *)buf)[offset])) = ++ ext2fs_cpu_to_be64(revoke_list[i]); ++ else ++ *((__u32 *)(&((char *)buf)[offset])) = ++ ext2fs_cpu_to_be32(revoke_list[i]); ++ offset += sz; ++ } ++ ++ if (offset > 0) { ++ jrb->r_count = ext2fs_cpu_to_be32(offset); ++ jbd2_revoke_csum_set(trans->journal, bh); ++ ++ err = journal_bmap(trans->journal, curr_blk, &bh->b_blocknr); ++ if (err) ++ goto error; ++ dbg_printf("Writing revoke block at %llu:%llu\n", ++ curr_blk, bh->b_blocknr); ++ mark_buffer_dirty(bh); ++ ll_rw_block(WRITE, 1, &bh); ++ err = bh->b_err; ++ if (err) ++ goto error; ++ curr_blk++; ++ } ++ ++error: ++ trans->block = curr_blk; ++ brelse(bh); ++ return err; ++} ++ ++static errcode_t journal_add_blocks_to_trans(journal_transaction_t *trans, ++ blk64_t *block_list, size_t block_len, ++ FILE *fp) ++{ ++ blk64_t curr_blk, jdb_blk; ++ size_t i, j; ++ int csum_size = 0; ++ journal_header_t *jdb; ++ journal_block_tag_t *jdbt; ++ int tag_bytes; ++ void *buf = NULL, *jdb_buf = NULL; ++ struct buffer_head *bh = NULL, *data_bh; ++ errcode_t err; ++ ++ JOURNAL_CHECK_TRANS_MAGIC(trans); ++ ++ if ((trans->flags & J_TRANS_COMMITTED) || ++ !(trans->flags & J_TRANS_OPEN)) ++ return EXT2_ET_INVALID_ARGUMENT; ++ ++ if (block_len == 0) ++ return 0; ++ ++ /* Do we need to leave space at the end for a checksum? */ ++ if (journal_has_csum_v2or3(trans->journal)) ++ csum_size = sizeof(struct journal_block_tail); ++ ++ curr_blk = jdb_blk = trans->block; ++ ++ data_bh = getblk(trans->journal->j_dev, curr_blk, ++ trans->journal->j_blocksize); ++ if (data_bh == NULL) ++ return ENOMEM; ++ buf = data_bh->b_data; ++ ++ /* write the descriptor block header */ ++ bh = getblk(trans->journal->j_dev, curr_blk, ++ trans->journal->j_blocksize); ++ if (bh == NULL) { ++ err = ENOMEM; ++ goto error; ++ } ++ jdb = jdb_buf = bh->b_data; ++ jdb->h_magic = ext2fs_cpu_to_be32(JFS_MAGIC_NUMBER); ++ jdb->h_blocktype = ext2fs_cpu_to_be32(JFS_DESCRIPTOR_BLOCK); ++ jdb->h_sequence = ext2fs_cpu_to_be32(trans->tid); ++ jdbt = (journal_block_tag_t *)(jdb + 1); ++ ++ curr_blk++; ++ for (i = 0; i < block_len; i++) { ++ j = fread(data_bh->b_data, trans->journal->j_blocksize, 1, fp); ++ if (j != 1) { ++ err = errno; ++ goto error; ++ } ++ ++ tag_bytes = journal_tag_bytes(trans->journal); ++ ++ /* No space left in descriptor block, write it out */ ++ if ((char *)jdbt + tag_bytes > ++ (char *)jdb_buf + trans->journal->j_blocksize - csum_size) { ++ jbd2_descr_block_csum_set(trans->journal, bh); ++ err = journal_bmap(trans->journal, jdb_blk, ++ &bh->b_blocknr); ++ if (err) ++ goto error; ++ dbg_printf("Writing descriptor block at %llu:%llu\n", ++ jdb_blk, bh->b_blocknr); ++ mark_buffer_dirty(bh); ++ ll_rw_block(WRITE, 1, &bh); ++ err = bh->b_err; ++ if (err) ++ goto error; ++ ++ jdbt = (journal_block_tag_t *)(jdb + 1); ++ jdb_blk = curr_blk; ++ curr_blk++; ++ } ++ ++ if (block_list[i] >= ++ ext2fs_blocks_count(trans->journal->j_fs_dev->k_fs->super)) { ++ err = EXT2_ET_BAD_BLOCK_NUM; ++ goto error; ++ } ++ ++ /* Fill out the block tag */ ++ jdbt->t_blocknr = ext2fs_cpu_to_be32(block_list[i] & 0xFFFFFFFF); ++ jdbt->t_flags = 0; ++ if (jdbt != (journal_block_tag_t *)(jdb + 1)) ++ jdbt->t_flags |= ext2fs_cpu_to_be16(JFS_FLAG_SAME_UUID); ++ else { ++ memcpy(jdbt + tag_bytes, ++ trans->journal->j_superblock->s_uuid, ++ sizeof(trans->journal->j_superblock->s_uuid)); ++ tag_bytes += 16; ++ } ++ if (i == block_len - 1) ++ jdbt->t_flags |= ext2fs_cpu_to_be16(JFS_FLAG_LAST_TAG); ++ if (*((__u32 *)buf) == ext2fs_cpu_to_be32(JFS_MAGIC_NUMBER)) { ++ *((__u32 *)buf) = 0; ++ jdbt->t_flags |= ext2fs_cpu_to_be16(JFS_FLAG_ESCAPE); ++ } ++ if (JFS_HAS_INCOMPAT_FEATURE(trans->journal, ++ JFS_FEATURE_INCOMPAT_64BIT)) ++ jdbt->t_blocknr_high = ext2fs_cpu_to_be32(block_list[i] >> 32); ++ jbd2_block_tag_csum_set(trans->journal, jdbt, data_bh, ++ trans->tid); ++ ++ /* Write the data block */ ++ err = journal_bmap(trans->journal, curr_blk, ++ &data_bh->b_blocknr); ++ if (err) ++ goto error; ++ dbg_printf("Writing data block %llu at %llu:%llu tag %d\n", ++ block_list[i], curr_blk, data_bh->b_blocknr, ++ tag_bytes); ++ mark_buffer_dirty(data_bh); ++ ll_rw_block(WRITE, 1, &data_bh); ++ err = data_bh->b_err; ++ if (err) ++ goto error; ++ ++ curr_blk++; ++ jdbt = (journal_block_tag_t *)(((char *)jdbt) + tag_bytes); ++ } ++ ++ /* Write out the last descriptor block */ ++ if (jdbt != (journal_block_tag_t *)(jdb + 1)) { ++ jbd2_descr_block_csum_set(trans->journal, bh); ++ err = journal_bmap(trans->journal, jdb_blk, &bh->b_blocknr); ++ if (err) ++ goto error; ++ dbg_printf("Writing descriptor block at %llu:%llu\n", ++ jdb_blk, bh->b_blocknr); ++ mark_buffer_dirty(bh); ++ ll_rw_block(WRITE, 1, &bh); ++ err = bh->b_err; ++ if (err) ++ goto error; ++ } ++ ++error: ++ trans->block = curr_blk; ++ if (bh) ++ brelse(bh); ++ brelse(data_bh); ++ return err; ++} ++ ++static blk64_t journal_guess_blocks(journal_t *journal, blk64_t data_blocks, ++ blk64_t revoke_blocks) ++{ ++ blk64_t ret = 1; ++ unsigned int bs, sz; ++ ++ /* Estimate # of revoke blocks */ ++ bs = journal->j_blocksize; ++ if (journal_has_csum_v2or3(journal)) ++ bs -= sizeof(struct journal_revoke_tail); ++ sz = JFS_HAS_INCOMPAT_FEATURE(journal, JFS_FEATURE_INCOMPAT_64BIT) ? ++ sizeof(__u64) : sizeof(__u32); ++ ret += revoke_blocks * sz / bs; ++ ++ /* Estimate # of data blocks */ ++ bs = journal->j_blocksize - 16; ++ if (journal_has_csum_v2or3(journal)) ++ bs -= sizeof(struct journal_block_tail); ++ sz = journal_tag_bytes(journal); ++ ret += data_blocks * sz / bs; ++ ++ ret += data_blocks; ++ ++ return ret; ++} ++ ++static errcode_t journal_open_trans(journal_t *journal, ++ journal_transaction_t *trans, ++ blk64_t blocks) ++{ ++ trans->fs = journal->j_fs_dev->k_fs; ++ trans->journal = journal; ++ trans->flags = J_TRANS_OPEN; ++ ++ if (journal->j_tail == 0) { ++ /* Clean journal, start at the tail */ ++ trans->tid = journal->j_tail_sequence; ++ trans->start = journal->j_first; ++ } else { ++ /* Put new transaction at the head of the list */ ++ trans->tid = journal->j_transaction_sequence; ++ trans->start = journal->j_head; ++ } ++ ++ trans->block = trans->start; ++ if (trans->start + blocks > journal->j_last) ++ return ENOSPC; ++ trans->end = trans->block + blocks; ++ journal_dump_trans(trans, "new transaction"); ++ ++ trans->magic = J_TRANS_MAGIC; ++ return 0; ++} ++ ++static errcode_t journal_close_trans(journal_transaction_t *trans) ++{ ++ journal_t *journal; ++ ++ JOURNAL_CHECK_TRANS_MAGIC(trans); ++ ++ if (!(trans->flags & J_TRANS_COMMITTED)) ++ return 0; ++ ++ journal = trans->journal; ++ if (journal->j_tail == 0) { ++ /* Update the tail */ ++ journal->j_tail_sequence = trans->tid; ++ journal->j_tail = trans->start; ++ journal->j_superblock->s_start = ext2fs_cpu_to_be32(trans->start); ++ } ++ ++ /* Update the head */ ++ journal->j_head = trans->end + 1; ++ journal->j_transaction_sequence = trans->tid + 1; ++ ++ trans->magic = 0; ++ ++ /* Mark ourselves as needing recovery */ ++ if (!(EXT2_HAS_INCOMPAT_FEATURE(trans->fs->super, ++ EXT3_FEATURE_INCOMPAT_RECOVER))) { ++ trans->fs->super->s_feature_incompat |= ++ EXT3_FEATURE_INCOMPAT_RECOVER; ++ ext2fs_mark_super_dirty(trans->fs); ++ } ++ ++ return 0; ++} ++ ++#define JOURNAL_WRITE_NO_COMMIT 1 ++static errcode_t journal_write(journal_t *journal, ++ int flags, blk64_t *block_list, ++ size_t block_len, blk64_t *revoke_list, ++ size_t revoke_len, FILE *fp) ++{ ++ blk64_t blocks; ++ journal_transaction_t trans; ++ errcode_t err; ++ ++ if (revoke_len > 0) { ++ journal->j_superblock->s_feature_incompat |= ++ ext2fs_cpu_to_be32(JFS_FEATURE_INCOMPAT_REVOKE); ++ mark_buffer_dirty(journal->j_sb_buffer); ++ } ++ ++ blocks = journal_guess_blocks(journal, block_len, revoke_len); ++ err = journal_open_trans(journal, &trans, blocks); ++ if (err) ++ goto error; ++ ++ err = journal_add_blocks_to_trans(&trans, block_list, block_len, fp); ++ if (err) ++ goto error; ++ ++ err = journal_add_revoke_to_trans(&trans, revoke_list, revoke_len); ++ if (err) ++ goto error; ++ ++ if (!(flags & JOURNAL_WRITE_NO_COMMIT)) { ++ err = journal_commit_trans(&trans); ++ if (err) ++ goto error; ++ } ++ ++ err = journal_close_trans(&trans); ++ if (err) ++ goto error; ++error: ++ return err; ++} ++ ++void do_journal_write(int argc, char *argv[]) ++{ ++ blk64_t *blist = NULL, *rlist = NULL; ++ size_t bn = 0, rn = 0; ++ FILE *fp = NULL; ++ int opt; ++ int flags = 0; ++ errcode_t err; ++ ++ if (current_journal == NULL) { ++ printf("Journal not open.\n"); ++ return; ++ } ++ ++ reset_getopt(); ++ while ((opt = getopt(argc, argv, "b:r:c")) != -1) { ++ switch (opt) { ++ case 'b': ++ err = read_list(optarg, &blist, &bn); ++ if (err) ++ com_err(argv[0], err, ++ "while reading block list"); ++ break; ++ case 'r': ++ err = read_list(optarg, &rlist, &rn); ++ if (err) ++ com_err(argv[0], err, ++ "while reading revoke list"); ++ break; ++ case 'c': ++ flags |= JOURNAL_WRITE_NO_COMMIT; ++ break; ++ default: ++ printf("%s [-b blocks] [-r revoke] [-c] file\n", ++ argv[0]); ++ printf("-b: Write these blocks into transaction.\n"); ++ printf("-c: Do not commit transaction.\n"); ++ printf("-r: Revoke these blocks from transaction.\n"); ++ ++ goto out; ++ } ++ } ++ ++ if (bn > 0 && optind != argc - 1) { ++ printf("Need a file to read blocks from.\n"); ++ return; ++ } ++ ++ if (bn > 0) { ++ fp = fopen(argv[optind], "r"); ++ if (fp == NULL) { ++ com_err(argv[0], errno, ++ "while opening journal data file"); ++ goto out; ++ } ++ } ++ ++ err = journal_write(current_journal, flags, blist, bn, ++ rlist, rn, fp); ++ if (err) ++ com_err("journal_write", err, "while writing journal"); ++ ++ if (fp) ++ fclose(fp); ++out: ++ if (blist) ++ free(blist); ++ if (rlist) ++ free(rlist); ++} ++ ++/* Make sure we wrap around the log correctly! */ ++#define wrap(journal, var) \ ++do { \ ++ if (var >= (journal)->j_last) \ ++ var -= ((journal)->j_last - (journal)->j_first); \ ++} while (0) ++ ++/* ++ * Count the number of in-use tags in a journal descriptor block. ++ */ ++ ++static int count_tags(journal_t *journal, char *buf) ++{ ++ char *tagp; ++ journal_block_tag_t *tag; ++ int nr = 0, size = journal->j_blocksize; ++ int tag_bytes = journal_tag_bytes(journal); ++ ++ if (journal_has_csum_v2or3(journal)) ++ size -= sizeof(struct journal_block_tail); ++ ++ tagp = buf + sizeof(journal_header_t); ++ ++ while ((tagp - buf + tag_bytes) <= size) { ++ tag = (journal_block_tag_t *) tagp; ++ ++ nr++; ++ tagp += tag_bytes; ++ if (!(tag->t_flags & ext2fs_cpu_to_be16(JFS_FLAG_SAME_UUID))) ++ tagp += 16; ++ ++ if (tag->t_flags & ext2fs_cpu_to_be16(JFS_FLAG_LAST_TAG)) ++ break; ++ } ++ ++ return nr; ++} ++ ++static errcode_t journal_find_head(journal_t *journal) ++{ ++ unsigned int next_commit_ID; ++ blk64_t next_log_block, head_block; ++ int err; ++ journal_superblock_t *sb; ++ journal_header_t *tmp; ++ struct buffer_head *bh; ++ unsigned int sequence; ++ int blocktype; ++ ++ /* ++ * First thing is to establish what we expect to find in the log ++ * (in terms of transaction IDs), and where (in terms of log ++ * block offsets): query the superblock. ++ */ ++ ++ sb = journal->j_superblock; ++ next_commit_ID = ext2fs_be32_to_cpu(sb->s_sequence); ++ next_log_block = ext2fs_be32_to_cpu(sb->s_start); ++ head_block = next_log_block; ++ ++ if (next_log_block == 0) ++ return 0; ++ ++ bh = getblk(journal->j_dev, 0, journal->j_blocksize); ++ if (bh == NULL) ++ return ENOMEM; ++ ++ /* ++ * Now we walk through the log, transaction by transaction, ++ * making sure that each transaction has a commit block in the ++ * expected place. Each complete transaction gets replayed back ++ * into the main filesystem. ++ */ ++ while (1) { ++ dbg_printf("Scanning for sequence ID %u at %lu/%lu\n", ++ next_commit_ID, (unsigned long)next_log_block, ++ journal->j_last); ++ ++ /* Skip over each chunk of the transaction looking ++ * either the next descriptor block or the final commit ++ * record. */ ++ err = journal_bmap(journal, next_log_block, &bh->b_blocknr); ++ if (err) ++ goto err; ++ mark_buffer_uptodate(bh, 0); ++ ll_rw_block(READ, 1, &bh); ++ err = bh->b_err; ++ if (err) ++ goto err; ++ ++ next_log_block++; ++ wrap(journal, next_log_block); ++ ++ /* What kind of buffer is it? ++ * ++ * If it is a descriptor block, check that it has the ++ * expected sequence number. Otherwise, we're all done ++ * here. */ ++ ++ tmp = (journal_header_t *)bh->b_data; ++ ++ if (tmp->h_magic != ext2fs_cpu_to_be32(JFS_MAGIC_NUMBER)) { ++ dbg_printf("JBD2: wrong magic 0x%x\n", tmp->h_magic); ++ goto err; ++ } ++ ++ blocktype = ext2fs_be32_to_cpu(tmp->h_blocktype); ++ sequence = ext2fs_be32_to_cpu(tmp->h_sequence); ++ dbg_printf("Found magic %d, sequence %d\n", ++ blocktype, sequence); ++ ++ if (sequence != next_commit_ID) { ++ dbg_printf("JBD2: Wrong sequence %d (wanted %d)\n", ++ sequence, next_commit_ID); ++ goto err; ++ } ++ ++ /* OK, we have a valid descriptor block which matches ++ * all of the sequence number checks. What are we going ++ * to do with it? That depends on the pass... */ ++ ++ switch (blocktype) { ++ case JFS_DESCRIPTOR_BLOCK: ++ next_log_block += count_tags(journal, bh->b_data); ++ wrap(journal, next_log_block); ++ continue; ++ ++ case JFS_COMMIT_BLOCK: ++ head_block = next_log_block; ++ next_commit_ID++; ++ continue; ++ ++ case JFS_REVOKE_BLOCK: ++ continue; ++ ++ default: ++ dbg_printf("Unrecognised magic %d, end of scan.\n", ++ blocktype); ++ err = -EINVAL; ++ goto err; ++ } ++ } ++ ++err: ++ if (err == 0) { ++ dbg_printf("head seq=%d blk=%llu\n", next_commit_ID, ++ head_block); ++ journal->j_transaction_sequence = next_commit_ID; ++ journal->j_head = head_block; ++ } ++ brelse(bh); ++ return err; ++} ++ ++static void update_journal_csum(journal_t *journal, int ver) ++{ ++ journal_superblock_t *jsb; ++ ++ if (journal->j_format_version < 2) ++ return; ++ ++ if (journal->j_tail != 0 || ++ EXT2_HAS_INCOMPAT_FEATURE(journal->j_fs_dev->k_fs->super, ++ EXT3_FEATURE_INCOMPAT_RECOVER)) { ++ printf("Journal needs recovery, will not add csums.\n"); ++ return; ++ } ++ ++ /* metadata_csum implies journal csum v3 */ ++ jsb = journal->j_superblock; ++ if (EXT2_HAS_RO_COMPAT_FEATURE(journal->j_fs_dev->k_fs->super, ++ EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) { ++ printf("Setting csum v%d\n", ver); ++ switch (ver) { ++ case 2: ++ journal->j_superblock->s_feature_incompat &= ++ ext2fs_cpu_to_be32(~JFS_FEATURE_INCOMPAT_CSUM_V3); ++ journal->j_superblock->s_feature_incompat |= ++ ext2fs_cpu_to_be32(JFS_FEATURE_INCOMPAT_CSUM_V2); ++ journal->j_superblock->s_feature_compat &= ++ ext2fs_cpu_to_be32(~JFS_FEATURE_COMPAT_CHECKSUM); ++ break; ++ case 3: ++ journal->j_superblock->s_feature_incompat &= ++ ext2fs_cpu_to_be32(~JFS_FEATURE_INCOMPAT_CSUM_V2); ++ journal->j_superblock->s_feature_incompat |= ++ ext2fs_cpu_to_be32(JFS_FEATURE_INCOMPAT_CSUM_V3); ++ journal->j_superblock->s_feature_compat &= ++ ext2fs_cpu_to_be32(~JFS_FEATURE_COMPAT_CHECKSUM); ++ break; ++ default: ++ printf("Unknown checksum v%d\n", ver); ++ break; ++ } ++ journal->j_superblock->s_checksum_type = JBD2_CRC32C_CHKSUM; ++ journal->j_csum_seed = jbd2_chksum(journal, ~0, jsb->s_uuid, ++ sizeof(jsb->s_uuid)); ++ } else { ++ journal->j_superblock->s_feature_compat |= ++ ext2fs_cpu_to_be32(JFS_FEATURE_COMPAT_CHECKSUM); ++ journal->j_superblock->s_feature_incompat &= ++ ext2fs_cpu_to_be32(~(JFS_FEATURE_INCOMPAT_CSUM_V2 | ++ JFS_FEATURE_INCOMPAT_CSUM_V3)); ++ } ++} ++ ++static void update_uuid(journal_t *journal) ++{ ++ size_t z; ++ ext2_filsys fs; ++ ++ if (journal->j_format_version < 2) ++ return; ++ ++ for (z = 0; z < sizeof(journal->j_superblock->s_uuid); z++) ++ if (journal->j_superblock->s_uuid[z]) ++ break; ++ if (z == 0) ++ return; ++ ++ fs = journal->j_fs_dev->k_fs; ++ if (!EXT2_HAS_INCOMPAT_FEATURE(fs->super, ++ EXT4_FEATURE_INCOMPAT_64BIT)) ++ return; ++ ++ if (JFS_HAS_INCOMPAT_FEATURE(journal, JFS_FEATURE_INCOMPAT_64BIT) && ++ EXT2_HAS_INCOMPAT_FEATURE(fs->super, ++ EXT4_FEATURE_INCOMPAT_64BIT)) ++ return; ++ ++ if (journal->j_tail != 0 || ++ EXT2_HAS_INCOMPAT_FEATURE(fs->super, ++ EXT3_FEATURE_INCOMPAT_RECOVER)) { ++ printf("Journal needs recovery, will not set 64bit.\n"); ++ return; ++ } ++ ++ memcpy(journal->j_superblock->s_uuid, fs->super->s_uuid, ++ sizeof(fs->super->s_uuid)); ++} ++ ++static void update_64bit_flag(journal_t *journal) ++{ ++ if (journal->j_format_version < 2) ++ return; ++ ++ if (!EXT2_HAS_INCOMPAT_FEATURE(journal->j_fs_dev->k_fs->super, ++ EXT4_FEATURE_INCOMPAT_64BIT)) ++ return; ++ ++ if (JFS_HAS_INCOMPAT_FEATURE(journal, JFS_FEATURE_INCOMPAT_64BIT) && ++ EXT2_HAS_INCOMPAT_FEATURE(journal->j_fs_dev->k_fs->super, ++ EXT4_FEATURE_INCOMPAT_64BIT)) ++ return; ++ ++ if (journal->j_tail != 0 || ++ EXT2_HAS_INCOMPAT_FEATURE(journal->j_fs_dev->k_fs->super, ++ EXT3_FEATURE_INCOMPAT_RECOVER)) { ++ printf("Journal needs recovery, will not set 64bit.\n"); ++ return; ++ } ++ ++ journal->j_superblock->s_feature_incompat |= ++ ext2fs_cpu_to_be32(JFS_FEATURE_INCOMPAT_64BIT); ++} ++ ++void do_journal_open(int argc, char *argv[]) ++{ ++ int opt, enable_csum = 0, csum_ver = 3; ++ journal_t *journal; ++ errcode_t err; ++ ++ if (check_fs_open(argv[0])) ++ return; ++ if (check_fs_read_write(argv[0])) ++ return; ++ if (check_fs_bitmaps(argv[0])) ++ return; ++ if (current_journal) { ++ printf("Journal is already open.\n"); ++ return; ++ } ++ if (!EXT2_HAS_COMPAT_FEATURE(current_fs->super, ++ EXT3_FEATURE_COMPAT_HAS_JOURNAL)) { ++ printf("Journalling is not enabled on this filesystem.\n"); ++ return; ++ } ++ ++ reset_getopt(); ++ while ((opt = getopt(argc, argv, "cv:f:")) != -1) { ++ switch (opt) { ++ case 'c': ++ enable_csum = 1; ++ break; ++ case 'f': ++ if (current_fs->journal_name) ++ free(current_fs->journal_name); ++ current_fs->journal_name = strdup(optarg); ++ break; ++ case 'v': ++ csum_ver = atoi(optarg); ++ if (csum_ver != 2 && csum_ver != 3) { ++ printf("Unknown journal csum v%d\n", csum_ver); ++ csum_ver = 3; ++ } ++ break; ++ default: ++ printf("%s: [-c] [-v ver] [-f ext_jnl]\n", argv[0]); ++ printf("-c: Enable journal checksumming.\n"); ++ printf("-v: Use this version checksum format.\n"); ++ printf("-j: Load this external journal.\n"); ++ } ++ } ++ ++ err = ext2fs_open_journal(current_fs, ¤t_journal); ++ if (err) { ++ com_err(argv[0], err, "while opening journal"); ++ return; ++ } ++ journal = current_journal; ++ ++ dbg_printf("JOURNAL: seq=%d tailseq=%d start=%lu first=%lu " ++ "maxlen=%lu\n", journal->j_tail_sequence, ++ journal->j_transaction_sequence, journal->j_tail, ++ journal->j_first, journal->j_last); ++ ++ update_uuid(journal); ++ update_64bit_flag(journal); ++ if (enable_csum) ++ update_journal_csum(journal, csum_ver); ++ ++ err = journal_find_head(journal); ++ if (err) ++ com_err(argv[0], err, "while examining journal"); ++} ++ ++void do_journal_close(int argc EXT2FS_ATTR((unused)), ++ char *argv[] EXT2FS_ATTR((unused))) ++{ ++ if (current_journal == NULL) { ++ printf("Journal not open.\n"); ++ return; ++ } ++ ++ ext2fs_close_journal(current_fs, ¤t_journal); ++} ++ ++void do_journal_run(int argc EXT2FS_ATTR((unused)), char *argv[]) ++{ ++ errcode_t err; ++ ++ if (check_fs_open(argv[0])) ++ return; ++ if (check_fs_read_write(argv[0])) ++ return; ++ if (check_fs_bitmaps(argv[0])) ++ return; ++ if (current_journal) { ++ printf("Please close the journal before recovering it.\n"); ++ return; ++ } ++ ++ err = ext2fs_run_ext3_journal(¤t_fs); ++ if (err) ++ com_err("journal_run", err, "while recovering journal"); ++ else { ++ current_fs->super->s_feature_incompat &= ++ ~EXT3_FEATURE_INCOMPAT_RECOVER; ++ ext2fs_mark_super_dirty(current_fs); ++ } ++} +--- a/debugfs/dump.c ++++ b/debugfs/dump.c +@@ -312,7 +312,7 @@ + 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; + +--- a/debugfs/extent_inode.c ++++ b/debugfs/extent_inode.c +@@ -97,6 +97,11 @@ + + orig_prompt = ss_get_prompt(sci_idx); + extent_prompt = malloc(strlen(orig_prompt) + 32); ++ if (extent_prompt == NULL) { ++ com_err(argv[1], retval, "out of memory"); ++ return; ++ } ++ + strcpy(extent_prompt, orig_prompt); + cp = strchr(extent_prompt, ':'); + if (cp) +--- a/debugfs/filefrag.c ++++ b/debugfs/filefrag.c +@@ -154,11 +154,13 @@ + 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 @@ + 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; +--- a/debugfs/htree.c ++++ b/debugfs/htree.c +@@ -44,6 +44,11 @@ + 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 @@ + } + + 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 @@ + (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)) { ++ ((unsigned) 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 @@ + 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"); +@@ -118,19 +138,33 @@ + struct ext2_dx_entry *ent, + char *buf, int level) + { +- struct ext2_dx_countlimit limit; +- struct ext2_dx_entry e; ++ struct ext2_dx_countlimit dx_countlimit; ++ struct ext2_dx_tail *tail; + int hash, i; ++ int limit, count; ++ int remainder; + ++ dx_countlimit = *((struct ext2_dx_countlimit *) ent); ++ count = ext2fs_le16_to_cpu(dx_countlimit.count); ++ limit = ext2fs_le16_to_cpu(dx_countlimit.limit); ++ ++ fprintf(pager, "Number of entries (count): %d\n", count); ++ fprintf(pager, "Number of entries (limit): %d\n", limit); ++ ++ remainder = fs->blocksize - (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); ++ fprintf(pager, "Checksum: 0x%08x\n", ++ ext2fs_le32_to_cpu(tail->dt_checksum)); ++ } + +- limit = *((struct ext2_dx_countlimit *) ent); +- limit.count = ext2fs_le16_to_cpu(limit.count); +- limit.limit = ext2fs_le16_to_cpu(limit.limit); +- +- fprintf(pager, "Number of entries (count): %d\n", limit.count); +- fprintf(pager, "Number of entries (limit): %d\n", limit.limit); +- +- for (i=0; i < limit.count; i++) { ++ for (i=0; i < count; i++) { + hash = i ? ext2fs_le32_to_cpu(ent[i].hash) : 0; + fprintf(pager, "Entry #%d: Hash 0x%08x%s, block %u\n", i, + hash, (hash & 1) ? " (**)" : "", +@@ -139,17 +173,19 @@ + + fprintf(pager, "\n"); + +- for (i=0; i < limit.count; i++) { +- e.hash = ext2fs_le32_to_cpu(ent[i].hash); +- e.block = ext2fs_le32_to_cpu(ent[i].block); ++ for (i=0; i < count; i++) { ++ unsigned int hashval, block; ++ ++ hashval = ext2fs_le32_to_cpu(ent[i].hash); ++ block = ext2fs_le32_to_cpu(ent[i].block); + fprintf(pager, "Entry #%d: Hash 0x%08x, block %u\n", i, +- i ? e.hash : 0, e.block); ++ i ? hashval : 0, block); + if (level) + htree_dump_int_block(fs, ino, inode, rootnode, +- e.block, buf, level-1); ++ block, buf, level-1); + else + htree_dump_leaf_node(fs, ino, inode, rootnode, +- e.block, buf); ++ block, buf); + } + + fprintf(pager, "---------------------\n"); +@@ -393,7 +429,7 @@ + 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, " +--- a/debugfs/jfs_user.h ++++ /dev/null +@@ -1,8 +0,0 @@ +-#ifndef _JFS_USER_H +-#define _JFS_USER_H +- +-typedef unsigned short kdev_t; +- +-#include +- +-#endif /* _JFS_USER_H */ +--- /dev/null ++++ b/debugfs/journal.c +@@ -0,0 +1,937 @@ ++/* ++ * journal.c --- code for handling the "ext3" journal ++ * ++ * Copyright (C) 2000 Andreas Dilger ++ * Copyright (C) 2000 Theodore Ts'o ++ * ++ * Parts of the code are based on fs/jfs/journal.c by Stephen C. Tweedie ++ * Copyright (C) 1999 Red Hat Software ++ * ++ * This file may be redistributed under the terms of the ++ * GNU General Public License version 2 or at your discretion ++ * any later version. ++ */ ++ ++#include "config.h" ++#ifdef HAVE_SYS_MOUNT_H ++#include ++#include ++#define MNT_FL (MS_MGC_VAL | MS_RDONLY) ++#endif ++#ifdef HAVE_SYS_STAT_H ++#include ++#endif ++ ++#define E2FSCK_INCLUDE_INLINE_FUNCS ++#include "uuid/uuid.h" ++#include "journal.h" ++ ++#ifdef CONFIG_JBD_DEBUG /* Enabled by configure --enable-jfs-debug */ ++static int bh_count = 0; ++#endif ++ ++#if EXT2_FLAT_INCLUDES ++#include "blkid.h" ++#else ++#include "blkid/blkid.h" ++#endif ++ ++/* ++ * Define USE_INODE_IO to use the inode_io.c / fileio.c codepaths. ++ * This creates a larger static binary, and a smaller binary using ++ * shared libraries. It's also probably slightly less CPU-efficient, ++ * which is why it's not on by default. But, it's a good way of ++ * testing the functions in inode_io.c and fileio.c. ++ */ ++#undef USE_INODE_IO ++ ++/* Checksumming functions */ ++static int ext2fs_journal_verify_csum_type(journal_t *j, ++ journal_superblock_t *jsb) ++{ ++ if (!journal_has_csum_v2or3(j)) ++ return 1; ++ ++ return jsb->s_checksum_type == JBD2_CRC32C_CHKSUM; ++} ++ ++static __u32 ext2fs_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 ext2fs_journal_sb_csum_verify(journal_t *j, ++ journal_superblock_t *jsb) ++{ ++ __u32 provided, calculated; ++ ++ if (!journal_has_csum_v2or3(j)) ++ return 1; ++ ++ provided = ext2fs_be32_to_cpu(jsb->s_checksum); ++ calculated = ext2fs_journal_sb_csum(jsb); ++ ++ return provided == calculated; ++} ++ ++static errcode_t ext2fs_journal_sb_csum_set(journal_t *j, ++ journal_superblock_t *jsb) ++{ ++ __u32 crc; ++ ++ if (!journal_has_csum_v2or3(j)) ++ return 0; ++ ++ crc = ext2fs_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. ++ */ ++int journal_bmap(journal_t *journal, blk64_t block, unsigned long long *phys) ++{ ++#ifdef USE_INODE_IO ++ *phys = block; ++ return 0; ++#else ++ struct inode *inode = journal->j_inode; ++ errcode_t retval; ++ blk64_t pblk; ++ ++ if (!inode) { ++ *phys = block; ++ return 0; ++ } ++ ++ retval = ext2fs_bmap2(inode->i_fs, inode->i_ino, ++ &inode->i_ext2, NULL, 0, block, 0, &pblk); ++ *phys = pblk; ++ return (int) retval; ++#endif ++} ++ ++struct buffer_head *getblk(kdev_t kdev, blk64_t blocknr, int blocksize) ++{ ++ struct buffer_head *bh; ++ int bufsize = sizeof(*bh) + kdev->k_fs->blocksize - ++ sizeof(bh->b_data); ++ errcode_t retval; ++ ++ retval = ext2fs_get_memzero(bufsize, &bh); ++ if (retval) ++ return NULL; ++ ++#ifdef CONFIG_JBD_DEBUG ++ if (journal_enable_debug >= 3) ++ bh_count++; ++#endif ++ jfs_debug(4, "getblk for block %llu (%d bytes)(total %d)\n", ++ (unsigned long long) blocknr, blocksize, bh_count); ++ ++ bh->b_fs = kdev->k_fs; ++ if (kdev->k_dev == K_DEV_FS) ++ bh->b_io = kdev->k_fs->io; ++ else ++ bh->b_io = kdev->k_fs->journal_io; ++ bh->b_size = blocksize; ++ bh->b_blocknr = blocknr; ++ ++ return bh; ++} ++ ++int sync_blockdev(kdev_t kdev) ++{ ++ io_channel io; ++ ++ if (kdev->k_dev == K_DEV_FS) ++ io = kdev->k_fs->io; ++ else ++ io = kdev->k_fs->journal_io; ++ ++ return io_channel_flush(io) ? EIO : 0; ++} ++ ++void ll_rw_block(int rw, int nr, struct buffer_head *bhp[]) ++{ ++ errcode_t retval; ++ struct buffer_head *bh; ++ ++ for (; nr > 0; --nr) { ++ bh = *bhp++; ++ if (rw == READ && !bh->b_uptodate) { ++ jfs_debug(3, "reading block %llu/%p\n", ++ bh->b_blocknr, (void *) bh); ++ retval = io_channel_read_blk64(bh->b_io, ++ bh->b_blocknr, ++ 1, bh->b_data); ++ if (retval) { ++ com_err(bh->b_fs->device_name, retval, ++ "while reading block %llu\n", ++ bh->b_blocknr); ++ bh->b_err = (int) retval; ++ continue; ++ } ++ bh->b_uptodate = 1; ++ } else if (rw == WRITE && bh->b_dirty) { ++ jfs_debug(3, "writing block %llu/%p\n", ++ bh->b_blocknr, ++ (void *) bh); ++ retval = io_channel_write_blk64(bh->b_io, ++ bh->b_blocknr, ++ 1, bh->b_data); ++ if (retval) { ++ com_err(bh->b_fs->device_name, retval, ++ "while writing block %llu\n", ++ bh->b_blocknr); ++ bh->b_err = (int) retval; ++ continue; ++ } ++ bh->b_dirty = 0; ++ bh->b_uptodate = 1; ++ } else { ++ jfs_debug(3, "no-op %s for block %llu\n", ++ rw == READ ? "read" : "write", ++ bh->b_blocknr); ++ } ++ } ++} ++ ++void mark_buffer_dirty(struct buffer_head *bh) ++{ ++ bh->b_dirty = 1; ++} ++ ++static void mark_buffer_clean(struct buffer_head *bh) ++{ ++ bh->b_dirty = 0; ++} ++ ++void brelse(struct buffer_head *bh) ++{ ++ if (bh->b_dirty) ++ ll_rw_block(WRITE, 1, &bh); ++ jfs_debug(3, "freeing block %llu/%p (total %d)\n", ++ bh->b_blocknr, (void *) bh, --bh_count); ++ ext2fs_free_mem(&bh); ++} ++ ++int buffer_uptodate(struct buffer_head *bh) ++{ ++ return bh->b_uptodate; ++} ++ ++void mark_buffer_uptodate(struct buffer_head *bh, int val) ++{ ++ bh->b_uptodate = val; ++} ++ ++void wait_on_buffer(struct buffer_head *bh) ++{ ++ if (!bh->b_uptodate) ++ ll_rw_block(READ, 1, &bh); ++} ++ ++ ++static void ext2fs_clear_recover(ext2_filsys fs, int error) ++{ ++ fs->super->s_feature_incompat &= ~EXT3_FEATURE_INCOMPAT_RECOVER; ++ ++ /* if we had an error doing journal recovery, we need a full fsck */ ++ if (error) ++ fs->super->s_state &= ~EXT2_VALID_FS; ++ ext2fs_mark_super_dirty(fs); ++} ++ ++/* ++ * This is a helper function to check the validity of the journal. ++ */ ++struct process_block_struct { ++ e2_blkcnt_t last_block; ++}; ++ ++static int process_journal_block(ext2_filsys fs, ++ blk64_t *block_nr, ++ e2_blkcnt_t blockcnt, ++ blk64_t ref_block EXT2FS_ATTR((unused)), ++ int ref_offset EXT2FS_ATTR((unused)), ++ void *priv_data) ++{ ++ struct process_block_struct *p; ++ blk64_t blk = *block_nr; ++ ++ p = (struct process_block_struct *) priv_data; ++ ++ if (!blk || blk < fs->super->s_first_data_block || ++ blk >= ext2fs_blocks_count(fs->super)) ++ return BLOCK_ABORT; ++ ++ if (blockcnt >= 0) ++ p->last_block = blockcnt; ++ return 0; ++} ++ ++static errcode_t ext2fs_get_journal(ext2_filsys fs, journal_t **ret_journal) ++{ ++ struct process_block_struct pb; ++ struct ext2_super_block *sb = fs->super; ++ struct ext2_super_block jsuper; ++ struct buffer_head *bh; ++ struct inode *j_inode = NULL; ++ struct kdev_s *dev_fs = NULL, *dev_journal; ++ const char *journal_name = 0; ++ journal_t *journal = NULL; ++ errcode_t retval = 0; ++ io_manager io_ptr = 0; ++ unsigned long long start = 0; ++ int ext_journal = 0; ++ int tried_backup_jnl = 0; ++ ++ retval = ext2fs_get_memzero(sizeof(journal_t), &journal); ++ if (retval) ++ return retval; ++ ++ retval = ext2fs_get_memzero(2 * sizeof(struct kdev_s), &dev_fs); ++ if (retval) ++ goto errout; ++ dev_journal = dev_fs+1; ++ ++ dev_fs->k_fs = dev_journal->k_fs = fs; ++ dev_fs->k_dev = K_DEV_FS; ++ dev_journal->k_dev = K_DEV_JOURNAL; ++ ++ journal->j_dev = dev_journal; ++ journal->j_fs_dev = dev_fs; ++ journal->j_inode = NULL; ++ journal->j_blocksize = fs->blocksize; ++ ++ if (uuid_is_null(sb->s_journal_uuid)) { ++ if (!sb->s_journal_inum) { ++ retval = EXT2_ET_BAD_INODE_NUM; ++ goto errout; ++ } ++ retval = ext2fs_get_memzero(sizeof(*j_inode), &j_inode); ++ if (retval) ++ goto errout; ++ ++ j_inode->i_fs = fs; ++ j_inode->i_ino = sb->s_journal_inum; ++ ++ retval = ext2fs_read_inode(fs, sb->s_journal_inum, ++ &j_inode->i_ext2); ++ if (retval) { ++try_backup_journal: ++ if (sb->s_jnl_backup_type != EXT3_JNL_BACKUP_BLOCKS || ++ tried_backup_jnl) ++ goto errout; ++ memset(&j_inode->i_ext2, 0, sizeof(struct ext2_inode)); ++ memcpy(&j_inode->i_ext2.i_block[0], sb->s_jnl_blocks, ++ EXT2_N_BLOCKS*4); ++ j_inode->i_ext2.i_size_high = sb->s_jnl_blocks[15]; ++ j_inode->i_ext2.i_size = sb->s_jnl_blocks[16]; ++ j_inode->i_ext2.i_links_count = 1; ++ j_inode->i_ext2.i_mode = LINUX_S_IFREG | 0600; ++ tried_backup_jnl++; ++ } ++ if (!j_inode->i_ext2.i_links_count || ++ !LINUX_S_ISREG(j_inode->i_ext2.i_mode)) { ++ retval = EXT2_ET_NO_JOURNAL; ++ goto try_backup_journal; ++ } ++ if (EXT2_I_SIZE(&j_inode->i_ext2) / journal->j_blocksize < ++ JFS_MIN_JOURNAL_BLOCKS) { ++ retval = EXT2_ET_JOURNAL_TOO_SMALL; ++ goto try_backup_journal; ++ } ++ pb.last_block = -1; ++ retval = ext2fs_block_iterate3(fs, j_inode->i_ino, ++ BLOCK_FLAG_HOLE, 0, ++ process_journal_block, &pb); ++ if ((pb.last_block + 1) * fs->blocksize < ++ (int) EXT2_I_SIZE(&j_inode->i_ext2)) { ++ retval = EXT2_ET_JOURNAL_TOO_SMALL; ++ goto try_backup_journal; ++ } ++ if (tried_backup_jnl && (fs->flags & EXT2_FLAG_RW)) { ++ retval = ext2fs_write_inode(fs, sb->s_journal_inum, ++ &j_inode->i_ext2); ++ if (retval) ++ goto errout; ++ } ++ ++ journal->j_maxlen = EXT2_I_SIZE(&j_inode->i_ext2) / ++ journal->j_blocksize; ++ ++#ifdef USE_INODE_IO ++ retval = ext2fs_inode_io_intern2(fs, sb->s_journal_inum, ++ &j_inode->i_ext2, ++ &journal_name); ++ if (retval) ++ goto errout; ++ ++ io_ptr = inode_io_manager; ++#else ++ journal->j_inode = j_inode; ++ fs->journal_io = fs->io; ++ retval = (errcode_t)journal_bmap(journal, 0, &start); ++ if (retval) ++ goto errout; ++#endif ++ } else { ++ ext_journal = 1; ++ if (!fs->journal_name) { ++ char uuid[37]; ++ blkid_cache blkid; ++ ++ blkid_get_cache(&blkid, NULL); ++ uuid_unparse(sb->s_journal_uuid, uuid); ++ fs->journal_name = blkid_get_devname(blkid, ++ "UUID", uuid); ++ if (!fs->journal_name) ++ fs->journal_name = blkid_devno_to_devname(sb->s_journal_dev); ++ blkid_put_cache(blkid); ++ } ++ journal_name = fs->journal_name; ++ ++ if (!journal_name) { ++ retval = EXT2_ET_LOAD_EXT_JOURNAL; ++ goto errout; ++ } ++ ++ jfs_debug(1, "Using journal file %s\n", journal_name); ++ io_ptr = unix_io_manager; ++ } ++ ++#if 0 ++ test_io_backing_manager = io_ptr; ++ io_ptr = test_io_manager; ++#endif ++#ifndef USE_INODE_IO ++ if (ext_journal) ++#endif ++ { ++ retval = io_ptr->open(journal_name, fs->flags & EXT2_FLAG_RW, ++ &fs->journal_io); ++ } ++ if (retval) ++ goto errout; ++ ++ io_channel_set_blksize(fs->journal_io, fs->blocksize); ++ ++ if (ext_journal) { ++ blk64_t maxlen; ++ ++ start = ext2fs_journal_sb_start(fs->blocksize) - 1; ++ bh = getblk(dev_journal, start, fs->blocksize); ++ if (!bh) { ++ retval = EXT2_ET_NO_MEMORY; ++ goto errout; ++ } ++ ll_rw_block(READ, 1, &bh); ++ retval = bh->b_err; ++ if (retval) { ++ brelse(bh); ++ goto errout; ++ } ++ memcpy(&jsuper, start ? bh->b_data : ++ bh->b_data + SUPERBLOCK_OFFSET, ++ sizeof(jsuper)); ++#ifdef WORDS_BIGENDIAN ++ if (jsuper.s_magic == ext2fs_swab16(EXT2_SUPER_MAGIC)) ++ ext2fs_swap_super(&jsuper); ++#endif ++ if (jsuper.s_magic != EXT2_SUPER_MAGIC || ++ !(jsuper.s_feature_incompat & ++ EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)) { ++ retval = EXT2_ET_LOAD_EXT_JOURNAL; ++ brelse(bh); ++ goto errout; ++ } ++ /* Make sure the journal UUID is correct */ ++ if (memcmp(jsuper.s_uuid, fs->super->s_journal_uuid, ++ sizeof(jsuper.s_uuid))) { ++ retval = EXT2_ET_LOAD_EXT_JOURNAL; ++ brelse(bh); ++ goto errout; ++ } ++ ++ /* Check the superblock checksum */ ++ if (jsuper.s_feature_ro_compat & ++ EXT4_FEATURE_RO_COMPAT_METADATA_CSUM) { ++ struct struct_ext2_filsys fsx; ++ struct ext2_super_block superx; ++ void *p; ++ ++ p = start ? bh->b_data : bh->b_data + SUPERBLOCK_OFFSET; ++ memcpy(&fsx, fs, sizeof(fsx)); ++ memcpy(&superx, fs->super, sizeof(superx)); ++ fsx.super = &superx; ++ fsx.super->s_feature_ro_compat |= ++ EXT4_FEATURE_RO_COMPAT_METADATA_CSUM; ++ if (!ext2fs_superblock_csum_verify(&fsx, p)) { ++ retval = EXT2_ET_LOAD_EXT_JOURNAL; ++ brelse(bh); ++ goto errout; ++ } ++ } ++ brelse(bh); ++ ++ maxlen = ext2fs_blocks_count(&jsuper); ++ journal->j_maxlen = (maxlen < 1ULL << 32) ? maxlen : ++ (1ULL << 32) - 1; ++ start++; ++ } ++ ++ bh = getblk(dev_journal, start, journal->j_blocksize); ++ if (!bh) { ++ retval = EXT2_ET_NO_MEMORY; ++ goto errout; ++ } ++ ++ journal->j_sb_buffer = bh; ++ journal->j_superblock = (journal_superblock_t *)bh->b_data; ++ ++#ifdef USE_INODE_IO ++ if (j_inode) ++ ext2fs_free_mem(&j_inode); ++#endif ++ ++ *ret_journal = journal; ++ return 0; ++ ++errout: ++ if (dev_fs) ++ ext2fs_free_mem(&dev_fs); ++ if (j_inode) ++ ext2fs_free_mem(&j_inode); ++ if (journal) ++ ext2fs_free_mem(&journal); ++ return retval; ++} ++ ++static errcode_t ext2fs_journal_fix_bad_inode(ext2_filsys fs) ++{ ++ struct ext2_super_block *sb = fs->super; ++ int recover = fs->super->s_feature_incompat & ++ EXT3_FEATURE_INCOMPAT_RECOVER; ++ int has_journal = fs->super->s_feature_compat & ++ EXT3_FEATURE_COMPAT_HAS_JOURNAL; ++ ++ if (has_journal || sb->s_journal_inum) { ++ /* The journal inode is bogus, remove and force full fsck */ ++ return EXT2_ET_BAD_INODE_NUM; ++ } else if (recover) { ++ return EXT2_ET_UNSUPP_FEATURE; ++ } ++ return 0; ++} ++ ++#define V1_SB_SIZE 0x0024 ++static void clear_v2_journal_fields(journal_t *journal) ++{ ++ ext2_filsys fs = journal->j_dev->k_fs; ++ ++ memset(((char *) journal->j_superblock) + V1_SB_SIZE, 0, ++ fs->blocksize-V1_SB_SIZE); ++ mark_buffer_dirty(journal->j_sb_buffer); ++} ++ ++ ++static errcode_t ext2fs_journal_load(journal_t *journal) ++{ ++ ext2_filsys fs = journal->j_dev->k_fs; ++ journal_superblock_t *jsb; ++ struct buffer_head *jbh = journal->j_sb_buffer; ++ ++ ll_rw_block(READ, 1, &jbh); ++ if (jbh->b_err) ++ return jbh->b_err; ++ ++ jsb = journal->j_superblock; ++ /* If we don't even have JFS_MAGIC, we probably have a wrong inode */ ++ if (jsb->s_header.h_magic != htonl(JFS_MAGIC_NUMBER)) ++ return ext2fs_journal_fix_bad_inode(fs); ++ ++ switch (ntohl(jsb->s_header.h_blocktype)) { ++ case JFS_SUPERBLOCK_V1: ++ journal->j_format_version = 1; ++ if (jsb->s_feature_compat || ++ jsb->s_feature_incompat || ++ jsb->s_feature_ro_compat || ++ jsb->s_nr_users) ++ clear_v2_journal_fields(journal); ++ break; ++ ++ case JFS_SUPERBLOCK_V2: ++ journal->j_format_version = 2; ++ if (ntohl(jsb->s_nr_users) > 1 && ++ uuid_is_null(fs->super->s_journal_uuid)) ++ clear_v2_journal_fields(journal); ++ if (ntohl(jsb->s_nr_users) > 1) ++ return EXT2_ET_JOURNAL_UNSUPP_VERSION; ++ break; ++ ++ /* ++ * These should never appear in a journal super block, so if ++ * they do, the journal is badly corrupted. ++ */ ++ case JFS_DESCRIPTOR_BLOCK: ++ case JFS_COMMIT_BLOCK: ++ case JFS_REVOKE_BLOCK: ++ return EXT2_ET_CORRUPT_SUPERBLOCK; ++ ++ /* If we don't understand the superblock major type, but there ++ * is a magic number, then it is likely to be a new format we ++ * just don't understand, so leave it alone. */ ++ default: ++ return EXT2_ET_JOURNAL_UNSUPP_VERSION; ++ } ++ ++ if (JFS_HAS_INCOMPAT_FEATURE(journal, ~JFS_KNOWN_INCOMPAT_FEATURES)) ++ return EXT2_ET_UNSUPP_FEATURE; ++ ++ if (JFS_HAS_RO_COMPAT_FEATURE(journal, ~JFS_KNOWN_ROCOMPAT_FEATURES)) ++ return EXT2_ET_RO_UNSUPP_FEATURE; ++ ++ /* Checksum v1-3 are mutually exclusive features. */ ++ if (JFS_HAS_INCOMPAT_FEATURE(journal, JFS_FEATURE_INCOMPAT_CSUM_V2) && ++ JFS_HAS_INCOMPAT_FEATURE(journal, JFS_FEATURE_INCOMPAT_CSUM_V3)) ++ return EXT2_ET_CORRUPT_SUPERBLOCK; ++ ++ if (journal_has_csum_v2or3(journal) && ++ JFS_HAS_COMPAT_FEATURE(journal, JFS_FEATURE_COMPAT_CHECKSUM)) ++ return EXT2_ET_CORRUPT_SUPERBLOCK; ++ ++ if (!ext2fs_journal_verify_csum_type(journal, jsb) || ++ !ext2fs_journal_sb_csum_verify(journal, jsb)) ++ return EXT2_ET_CORRUPT_SUPERBLOCK; ++ ++ if (journal_has_csum_v2or3(journal)) ++ journal->j_csum_seed = jbd2_chksum(journal, ~0, jsb->s_uuid, ++ sizeof(jsb->s_uuid)); ++ ++ /* 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. */ ++ if (jsb->s_blocksize != htonl(journal->j_blocksize)) ++ return EXT2_ET_CORRUPT_SUPERBLOCK; ++ ++ if (ntohl(jsb->s_maxlen) < journal->j_maxlen) ++ journal->j_maxlen = ntohl(jsb->s_maxlen); ++ else if (ntohl(jsb->s_maxlen) > journal->j_maxlen) ++ return EXT2_ET_CORRUPT_SUPERBLOCK; ++ ++ journal->j_tail_sequence = ntohl(jsb->s_sequence); ++ journal->j_transaction_sequence = journal->j_tail_sequence; ++ journal->j_tail = ntohl(jsb->s_start); ++ journal->j_first = ntohl(jsb->s_first); ++ journal->j_last = ntohl(jsb->s_maxlen); ++ ++ return 0; ++} ++ ++static void ext2fs_journal_release(ext2_filsys fs, journal_t *journal, ++ int reset, int drop) ++{ ++ journal_superblock_t *jsb; ++ ++ if (drop) ++ mark_buffer_clean(journal->j_sb_buffer); ++ else if (fs->flags & EXT2_FLAG_RW) { ++ jsb = journal->j_superblock; ++ jsb->s_sequence = htonl(journal->j_tail_sequence); ++ if (reset) ++ jsb->s_start = 0; /* this marks the journal as empty */ ++ ext2fs_journal_sb_csum_set(journal, jsb); ++ mark_buffer_dirty(journal->j_sb_buffer); ++ } ++ brelse(journal->j_sb_buffer); ++ ++ if (fs && fs->journal_io) { ++ if (fs->io != fs->journal_io) ++ io_channel_close(fs->journal_io); ++ fs->journal_io = NULL; ++ } ++ ++#ifndef USE_INODE_IO ++ if (journal->j_inode) ++ ext2fs_free_mem(&journal->j_inode); ++#endif ++ if (journal->j_fs_dev) ++ ext2fs_free_mem(&journal->j_fs_dev); ++ ext2fs_free_mem(&journal); ++} ++ ++/* ++ * This function makes sure that the superblock fields regarding the ++ * journal are consistent. ++ */ ++static errcode_t ext2fs_check_ext3_journal(ext2_filsys fs) ++{ ++ struct ext2_super_block *sb = fs->super; ++ journal_t *journal; ++ int recover = fs->super->s_feature_incompat & ++ EXT3_FEATURE_INCOMPAT_RECOVER; ++ errcode_t retval; ++ ++ /* If we don't have any journal features, don't do anything more */ ++ if (!(sb->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL) && ++ !recover && sb->s_journal_inum == 0 && sb->s_journal_dev == 0 && ++ uuid_is_null(sb->s_journal_uuid)) ++ return 0; ++ ++ retval = ext2fs_get_journal(fs, &journal); ++ if (retval) ++ return retval; ++ ++ retval = ext2fs_journal_load(journal); ++ if (retval) ++ goto err; ++ ++ /* ++ * We want to make the flags consistent here. We will not leave with ++ * needs_recovery set but has_journal clear. We can't get in a loop ++ * with -y, -n, or -p, only if a user isn't making up their mind. ++ */ ++ if (!(sb->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL)) { ++ retval = EXT2_ET_JOURNAL_FLAGS_WRONG; ++ goto err; ++ } ++ ++ if (sb->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL && ++ !(sb->s_feature_incompat & EXT3_FEATURE_INCOMPAT_RECOVER) && ++ journal->j_superblock->s_start != 0) { ++ retval = EXT2_ET_JOURNAL_FLAGS_WRONG; ++ goto err; ++ } ++ ++ /* ++ * If we don't need to do replay the journal, check to see if ++ * the journal's errno is set; if so, we need to mark the file ++ * system as being corrupt and clear the journal's s_errno. ++ */ ++ if (!(sb->s_feature_incompat & EXT3_FEATURE_INCOMPAT_RECOVER) && ++ journal->j_superblock->s_errno) { ++ fs->super->s_state |= EXT2_ERROR_FS; ++ ext2fs_mark_super_dirty(fs); ++ journal->j_superblock->s_errno = 0; ++ ext2fs_journal_sb_csum_set(journal, journal->j_superblock); ++ mark_buffer_dirty(journal->j_sb_buffer); ++ } ++ ++err: ++ ext2fs_journal_release(fs, journal, 0, retval ? 1 : 0); ++ return retval; ++} ++ ++static errcode_t recover_ext3_journal(ext2_filsys fs) ++{ ++ journal_t *journal; ++ errcode_t retval; ++ ++ journal_init_revoke_caches(); ++ retval = ext2fs_get_journal(fs, &journal); ++ if (retval) ++ return retval; ++ ++ retval = ext2fs_journal_load(journal); ++ if (retval) ++ goto errout; ++ ++ retval = journal_init_revoke(journal, 1024); ++ if (retval) ++ goto errout; ++ ++ retval = -journal_recover(journal); ++ if (retval) ++ goto errout; ++ ++ if (journal->j_failed_commit) { ++ journal->j_superblock->s_errno = -EINVAL; ++ mark_buffer_dirty(journal->j_sb_buffer); ++ } ++ ++errout: ++ journal_destroy_revoke(journal); ++ journal_destroy_revoke_caches(); ++ ext2fs_journal_release(fs, journal, 1, 0); ++ return retval; ++} ++ ++errcode_t ext2fs_run_ext3_journal(ext2_filsys *fsp) ++{ ++ ext2_filsys fs = *fsp; ++ io_manager io_ptr = fs->io->manager; ++ errcode_t retval, recover_retval; ++ io_stats stats = 0; ++ unsigned long long kbytes_written = 0; ++ char *fsname; ++ int fsflags; ++ int fsblocksize; ++ ++ if (!(fs->flags & EXT2_FLAG_RW)) ++ return EXT2_ET_FILE_RO; ++ ++ if (fs->flags & EXT2_FLAG_DIRTY) ++ ext2fs_flush(fs); /* Force out any modifications */ ++ ++ recover_retval = recover_ext3_journal(fs); ++ ++ /* ++ * Reload the filesystem context to get up-to-date data from disk ++ * because journal recovery will change the filesystem under us. ++ */ ++ if (fs->super->s_kbytes_written && ++ fs->io->manager->get_stats) ++ fs->io->manager->get_stats(fs->io, &stats); ++ if (stats && stats->bytes_written) ++ kbytes_written = stats->bytes_written >> 10; ++ ++ ext2fs_mmp_stop(fs); ++ fsname = strdup(fs->device_name); ++ fsflags = fs->flags; ++ fsblocksize = fs->blocksize; ++ ext2fs_free(fs); ++ retval = ext2fs_open(fsname, fsflags, ++ 0, fsblocksize, io_ptr, ++ fsp); ++ free(fsname); ++ if (retval) ++ return retval; ++ ++ fs = *fsp; ++ fs->flags |= EXT2_FLAG_MASTER_SB_ONLY; ++ fs->super->s_kbytes_written += kbytes_written; ++ ++ /* Set the superblock flags */ ++ ext2fs_clear_recover(fs, recover_retval != 0); ++ ++ /* ++ * Do one last sanity check, and propagate journal->s_errno to ++ * the EXT2_ERROR_FS flag in the fs superblock if needed. ++ */ ++ retval = ext2fs_check_ext3_journal(fs); ++ return retval ? retval : recover_retval; ++} ++ ++errcode_t ext2fs_open_journal(ext2_filsys fs, journal_t **j) ++{ ++ journal_t *journal; ++ errcode_t retval; ++ ++ journal_init_revoke_caches(); ++ retval = ext2fs_get_journal(fs, &journal); ++ if (retval) ++ return retval; ++ ++ retval = ext2fs_journal_load(journal); ++ if (retval) ++ goto errout; ++ ++ retval = journal_init_revoke(journal, 1024); ++ if (retval) ++ goto errout; ++ ++ if (journal->j_failed_commit) { ++ journal->j_superblock->s_errno = -EINVAL; ++ mark_buffer_dirty(journal->j_sb_buffer); ++ } ++ ++ *j = journal; ++ return 0; ++ ++errout: ++ journal_destroy_revoke(journal); ++ journal_destroy_revoke_caches(); ++ ext2fs_journal_release(fs, journal, 1, 0); ++ return retval; ++} ++ ++errcode_t ext2fs_close_journal(ext2_filsys fs, journal_t **j) ++{ ++ journal_t *journal = *j; ++ ++ journal_destroy_revoke(journal); ++ journal_destroy_revoke_caches(); ++ ext2fs_journal_release(fs, journal, 0, 0); ++ *j = NULL; ++ ++ return 0; ++} ++ ++void jbd2_commit_block_csum_set(journal_t *j, struct buffer_head *bh) ++{ ++ struct commit_header *h; ++ __u32 csum; ++ ++ if (!journal_has_csum_v2or3(j)) ++ return; ++ ++ h = (struct commit_header *)(bh->b_data); ++ h->h_chksum_type = 0; ++ h->h_chksum_size = 0; ++ h->h_chksum[0] = 0; ++ csum = jbd2_chksum(j, j->j_csum_seed, bh->b_data, j->j_blocksize); ++ h->h_chksum[0] = ext2fs_cpu_to_be32(csum); ++} ++ ++void jbd2_revoke_csum_set(journal_t *j, struct buffer_head *bh) ++{ ++ struct journal_revoke_tail *tail; ++ __u32 csum; ++ ++ if (!journal_has_csum_v2or3(j)) ++ return; ++ ++ tail = (struct journal_revoke_tail *)(bh->b_data + j->j_blocksize - ++ sizeof(struct journal_revoke_tail)); ++ tail->r_checksum = 0; ++ csum = jbd2_chksum(j, j->j_csum_seed, bh->b_data, j->j_blocksize); ++ tail->r_checksum = ext2fs_cpu_to_be32(csum); ++} ++ ++void jbd2_descr_block_csum_set(journal_t *j, struct buffer_head *bh) ++{ ++ struct journal_block_tail *tail; ++ __u32 csum; ++ ++ if (!journal_has_csum_v2or3(j)) ++ return; ++ ++ tail = (struct journal_block_tail *)(bh->b_data + j->j_blocksize - ++ sizeof(struct journal_block_tail)); ++ tail->t_checksum = 0; ++ csum = jbd2_chksum(j, j->j_csum_seed, bh->b_data, j->j_blocksize); ++ tail->t_checksum = ext2fs_cpu_to_be32(csum); ++} ++ ++void jbd2_block_tag_csum_set(journal_t *j, journal_block_tag_t *tag, ++ struct buffer_head *bh, __u32 sequence) ++{ ++ journal_block_tag3_t *tag3 = (journal_block_tag3_t *)tag; ++ __u32 csum32; ++ __be32 seq; ++ ++ if (!journal_has_csum_v2or3(j)) ++ return; ++ ++ seq = ext2fs_cpu_to_be32(sequence); ++ csum32 = jbd2_chksum(j, j->j_csum_seed, (__u8 *)&seq, sizeof(seq)); ++ csum32 = jbd2_chksum(j, csum32, bh->b_data, bh->b_size); ++ ++ if (JFS_HAS_INCOMPAT_FEATURE(j, JFS_FEATURE_INCOMPAT_CSUM_V3)) ++ tag3->t_checksum = ext2fs_cpu_to_be32(csum32); ++ else ++ tag->t_checksum = ext2fs_cpu_to_be16(csum32); ++} ++ +--- /dev/null ++++ b/debugfs/journal.h +@@ -0,0 +1,25 @@ ++/* ++ * journal.h ++ * ++ * Copyright (C) 2000 Andreas Dilger ++ * Copyright (C) 2000 Theodore Ts'o ++ * ++ * Parts of the code are based on fs/jfs/journal.c by Stephen C. Tweedie ++ * Copyright (C) 1999 Red Hat Software ++ * ++ * This file may be redistributed under the terms of the ++ * GNU General Public License version 2 or at your discretion ++ * any later version. ++ */ ++ ++#include "jfs_user.h" ++ ++/* journal.c */ ++errcode_t ext2fs_open_journal(ext2_filsys fs, journal_t **j); ++errcode_t ext2fs_close_journal(ext2_filsys fs, journal_t **j); ++errcode_t ext2fs_run_ext3_journal(ext2_filsys *fs); ++void jbd2_commit_block_csum_set(journal_t *j, struct buffer_head *bh); ++void jbd2_revoke_csum_set(journal_t *j, struct buffer_head *bh); ++void jbd2_descr_block_csum_set(journal_t *j, struct buffer_head *bh); ++void jbd2_block_tag_csum_set(journal_t *j, journal_block_tag_t *tag, ++ struct buffer_head *bh, __u32 sequence); +--- a/debugfs/logdump.c ++++ b/debugfs/logdump.c +@@ -39,7 +39,7 @@ + + #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 @@ + 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 @@ + 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 @@ + inode_spec = optarg; + dump_descriptors = 0; + break; ++ case 'O': ++ dump_old++; ++ break; + case 's': + use_sb++; + break; +@@ -267,7 +271,7 @@ + return; + + print_usage: +- fprintf(stderr, "%s: Usage: logdump [-acs] [-b] [-i]\n\t" ++ fprintf(stderr, "%s: Usage: logdump [-acsO] [-b] [-i]\n\t" + "[-f] [output_file]\n", argv[0]); + } + +@@ -393,9 +397,13 @@ + 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 @@ + 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) { +@@ -459,6 +468,23 @@ + } + } + ++static inline size_t journal_super_tag_bytes(journal_superblock_t *jsb) ++{ ++ size_t sz; ++ ++ if (JSB_HAS_INCOMPAT_FEATURE(jsb, JFS_FEATURE_INCOMPAT_CSUM_V3)) ++ return sizeof(journal_block_tag3_t); ++ ++ sz = sizeof(journal_block_tag_t); ++ ++ if (JSB_HAS_INCOMPAT_FEATURE(jsb, JFS_FEATURE_INCOMPAT_CSUM_V2)) ++ sz += sizeof(__u16); ++ ++ if (JSB_HAS_INCOMPAT_FEATURE(jsb, JFS_FEATURE_INCOMPAT_64BIT)) ++ return sz; ++ ++ return sz - sizeof(__u32); ++} + + static void dump_descriptor_block(FILE *out_file, + struct journal_source *source, +@@ -467,19 +493,21 @@ + unsigned int *blockp, int blocksize, + tid_t transaction) + { +- int offset, tag_size = JBD_TAG_SIZE32; ++ int offset, tag_size, csum_size = 0; + char *tagp; + journal_block_tag_t *tag; + unsigned int blocknr; + __u32 tag_block; + __u32 tag_flags; + +- if (be32_to_cpu(jsb->s_feature_incompat) & JFS_FEATURE_INCOMPAT_64BIT) +- tag_size = JBD_TAG_SIZE64; +- ++ tag_size = journal_super_tag_bytes(jsb); + offset = sizeof(journal_header_t); + blocknr = *blockp; + ++ if (JSB_HAS_INCOMPAT_FEATURE(jsb, JFS_FEATURE_INCOMPAT_CSUM_V3) || ++ JSB_HAS_INCOMPAT_FEATURE(jsb, JFS_FEATURE_INCOMPAT_CSUM_V2)) ++ csum_size = sizeof(struct journal_block_tail); ++ + if (dump_all) + fprintf(out_file, "Dumping descriptor block, sequence %u, at " + "block %u:\n", transaction, blocknr); +@@ -496,11 +524,11 @@ + + /* ... and if we have gone too far, then we've reached the + end of this block. */ +- if (offset > blocksize) ++ if (offset > blocksize - csum_size) + 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 +554,37 @@ + { + 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; + } + } + +--- a/debugfs/ls.c ++++ b/debugfs/ls.c +@@ -30,18 +30,57 @@ + */ + + #define LONG_OPT 0x0001 +-#define DELETED_OPT 0x0002 +-#define PARSE_OPT 0x0004 ++#define PARSE_OPT 0x0002 ++#define RAW_OPT 0x0004 ++#define ENCRYPT_OPT 0x8000 + + struct list_dir_struct { + FILE *f; + int col; + int options; ++ int state; + }; + + static const char *monstr[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; + ++static int print_filename(FILE *f, struct ext2_dir_entry *dirent, int options) ++{ ++ unsigned char ch; ++ const char *cp = dirent->name; ++ int len = ext2fs_dirent_name_len(dirent); ++ int retlen = 0; ++ ++ if ((options & ENCRYPT_OPT) && !(options & RAW_OPT)) { ++ if (f) ++ return fprintf(f, "", len); ++ else { ++ char tmp[1]; ++ return snprintf(tmp, sizeof(tmp), ++ "", len); ++ } ++ } ++ while (len--) { ++ ch = *cp++; ++ if (ch > 128) { ++ if (f) ++ fputs("M-", f); ++ ch -= 128; ++ retlen += 2; ++ } ++ if ((ch < 32) || (ch == 0x7f)) { ++ if (f) ++ fputc('^', f); ++ ch ^= 0x40; /* ^@, ^A, ^B; ^? for DEL */ ++ retlen++; ++ } ++ if (f) ++ fputc(ch, f); ++ retlen++; ++ } ++ return retlen; ++} ++ + static int list_dir_proc(ext2_ino_t dir EXT2FS_ATTR((unused)), + int entry, + struct ext2_dir_entry *dirent, +@@ -54,17 +93,21 @@ + ext2_ino_t ino; + struct tm *tm_p; + time_t modtime; +- char name[EXT2_NAME_LEN + 1]; + char tmp[EXT2_NAME_LEN + 16]; + char datestr[80]; + char lbr, rbr; + int thislen; ++ int options; + 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; +- strncpy(name, dirent->name, thislen); +- name[thislen] = '\0'; ++ thislen = ext2fs_dirent_name_len(dirent); + ino = dirent->inode; ++ options = ls->options; ++ if (ls->state < 2) { ++ ls->state++; ++ options |= RAW_OPT; ++ } + + if (entry == DIRENT_DELETED_FILE) { + lbr = '<'; +@@ -73,21 +116,22 @@ + } else { + lbr = rbr = ' '; + } +- if (ls->options & PARSE_OPT) { ++ if (options & PARSE_OPT) { + if (ino) { +- if (debugfs_read_inode(ino, &inode, name)) ++ if (debugfs_read_inode(ino, &inode, "ls")) + return 0; + } else + memset(&inode, 0, sizeof(struct ext2_inode)); +- fprintf(ls->f,"/%u/%06o/%d/%d/%s/",ino,inode.i_mode,inode.i_uid, inode.i_gid,name); ++ fprintf(ls->f,"/%u/%06o/%d/%d/%*s/", ino, inode.i_mode, ++ inode.i_uid, inode.i_gid, thislen, dirent->name); + if (LINUX_S_ISDIR(inode.i_mode)) + fprintf(ls->f, "/"); + else + fprintf(ls->f, "%lld/", EXT2_I_SIZE(&inode)); + fprintf(ls->f, "\n"); +- } else if (ls->options & LONG_OPT) { ++ } else if (options & LONG_OPT) { + if (ino) { +- if (debugfs_read_inode(ino, &inode, name)) ++ if (debugfs_read_inode(ino, &inode, "ls")) + return 0; + modtime = inode.i_mtime; + tm_p = localtime(&modtime); +@@ -99,24 +143,48 @@ + 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); + else + fprintf(ls->f, "%5llu", EXT2_I_SIZE(&inode)); +- fprintf (ls->f, " %s %s\n", datestr, name); ++ fputs(datestr, ls->f); ++ fputc(' ', ls->f); ++ print_filename(ls->f, dirent, options); ++ fputc('\n', ls->f); + } else { +- sprintf(tmp, "%c%u%c (%d) %s ", lbr, dirent->inode, rbr, +- dirent->rec_len, name); +- thislen = strlen(tmp); ++ if (entry == DIRENT_CHECKSUM) { ++ sprintf(tmp, "%c%u%c (dirblock checksum: 0x%08x) ", ++ lbr, dirent->inode, rbr, t->det_checksum); ++ thislen = strlen(tmp); ++ if (ls->col + thislen > 80) { ++ fputc('\n', ls->f); ++ ls->col = 0; ++ } ++ fprintf(ls->f, "%s", tmp); ++ ls->col += thislen; ++ return 0; ++ } ++ sprintf(tmp, "%c%u%c (%d) ", lbr, dirent->inode, rbr, ++ dirent->rec_len); ++ thislen = strlen(tmp) + 3; ++ thislen += print_filename(NULL, dirent, options); + + if (ls->col + thislen > 80) { +- fprintf(ls->f, "\n"); ++ fputc('\n', ls->f); + ls->col = 0; + } + fprintf(ls->f, "%s", tmp); ++ print_filename(ls->f, dirent, options); ++ fputs(" ", ls->f); + ls->col += thislen; + } + return 0; +@@ -124,28 +192,36 @@ + + void do_list_dir(int argc, char *argv[]) + { +- ext2_ino_t inode; ++ struct ext2_inode inode; ++ ext2_ino_t ino; + int retval; + int c; +- int flags; ++ int flags = DIRENT_FLAG_INCLUDE_EMPTY; + struct list_dir_struct ls; + + ls.options = 0; ++ ls.state = 0; + if (check_fs_open(argv[0])) + return; + + reset_getopt(); +- while ((c = getopt (argc, argv, "dlp")) != EOF) { ++ while ((c = getopt (argc, argv, "cdlpr")) != 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; + break; ++ case 'r': ++ ls.options |= RAW_OPT; ++ break; + default: + goto print_usage; + } +@@ -158,19 +234,22 @@ + } + + if (argc == optind) +- inode = cwd; ++ ino = cwd; + else +- inode = string_to_inode(argv[optind]); +- if (!inode) ++ ino = string_to_inode(argv[optind]); ++ if (!ino) + return; + + 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, ++ if (debugfs_read_inode(ino, &inode, argv[0])) ++ return; ++ ++ if (inode.i_flags & EXT4_ENCRYPT_FL) ++ ls.options |= ENCRYPT_OPT; ++ ++ retval = ext2fs_dir_iterate2(current_fs, ino, flags, + 0, list_dir_proc, &ls); + fprintf(ls.f, "\n"); + close_pager(ls.f); +--- a/debugfs/lsdel.c ++++ b/debugfs/lsdel.c +@@ -141,15 +141,19 @@ + 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, +--- a/debugfs/Makefile.in ++++ b/debugfs/Makefile.in +@@ -18,35 +18,44 @@ + + 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 journal.o revoke.o recovery.o do_journal.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 +- +-LIBS= $(LIBQUOTA) $(LIBEXT2FS) $(LIBE2P) $(LIBSS) $(LIBCOM_ERR) $(LIBBLKID) \ +- $(LIBUUID) $(SYSLIBS) +-DEPLIBS= $(DEPLIBQUOTA) $(LIBEXT2FS) $(LIBE2P) $(DEPLIBSS) $(DEPLIBCOM_ERR) \ ++ $(srcdir)/../misc/create_inode.c $(srcdir)/xattrs.c $(srcdir)/quota.c \ ++ $(srcdir)/journal.c $(srcdir)/../e2fsck/revoke.c \ ++ $(srcdir)/../e2fsck/recovery.c $(srcdir)/do_journal.c ++ ++LIBS= $(LIBSUPPORT) $(LIBEXT2FS) $(LIBE2P) $(LIBSS) $(LIBCOM_ERR) $(LIBBLKID) \ ++ $(LIBUUID) $(LIBMAGIC) $(SYSLIBS) ++DEPLIBS= $(DEPLIBSUPPORT) $(LIBEXT2FS) $(LIBE2P) $(DEPLIBSS) $(DEPLIBCOM_ERR) \ + $(DEPLIBBLKID) $(DEPLIBUUID) + +-STATIC_LIBS= $(STATIC_LIBQUOTA) $(STATIC_LIBEXT2FS) $(STATIC_LIBSS) \ ++STATIC_LIBS= $(STATIC_LIBSUPPORT) $(STATIC_LIBEXT2FS) $(STATIC_LIBSS) \ + $(STATIC_LIBCOM_ERR) $(STATIC_LIBBLKID) $(STATIC_LIBUUID) \ +- $(STATIC_LIBE2P) $(SYSLIBS) ++ $(STATIC_LIBE2P) $(LIBMAGIC) $(SYSLIBS) + STATIC_DEPLIBS= $(STATIC_LIBEXT2FS) $(DEPSTATIC_LIBSS) \ + $(DEPSTATIC_LIBCOM_ERR) $(DEPSTATIC_LIBUUID) \ + $(DEPSTATIC_LIBE2P) + ++# This nastyness is needed because of jfs_user.h hackery; when we finally ++# clean up this mess, we should be able to drop it ++LOCAL_CFLAGS = -I$(srcdir)/../e2fsck -DDEBUGFS ++DEPEND_CFLAGS = -I$(srcdir) ++ + .c.o: + $(E) " CC $<" + $(Q) $(CC) -c $(ALL_CFLAGS) $< -o $@ + $(Q) $(CHECK_CMD) $(ALL_CFLAGS) $< ++ $(Q) $(CPPCHECK_CMD) $(CPPFLAGS) $< + + all:: $(PROGS) $(MANPAGES) + +@@ -81,7 +90,22 @@ + + e2freefrag.o: $(srcdir)/../misc/e2freefrag.c + $(E) " CC $@" +- $(Q) $(CC) -c $(ALL_CFLAGS) -I$(srcdir) $< -DDEBUGFS -o $@ ++ $(Q) $(CC) -c $(ALL_CFLAGS) -I$(srcdir) $< -o $@ ++ ++recovery.o: $(srcdir)/../e2fsck/recovery.c ++ $(E) " CC $@" ++ $(Q) $(CC) -c $(ALL_CFLAGS) -I$(srcdir) \ ++ $(srcdir)/../e2fsck/recovery.c -o $@ ++ ++revoke.o: $(srcdir)/../e2fsck/revoke.c ++ $(E) " CC $@" ++ $(Q) $(CC) -c $(ALL_CFLAGS) -I$(srcdir) \ ++ $(srcdir)/../e2fsck/revoke.c -o $@ ++ ++create_inode.o: $(srcdir)/../misc/create_inode.c ++ $(E) " CC $@" ++ $(Q) $(CC) -c $(ALL_CFLAGS) -I$(srcdir) \ ++ $(srcdir)/../misc/create_inode.c -o $@ + + debugfs.8: $(DEP_SUBSTITUTE) $(srcdir)/debugfs.8.in + $(E) " SUBST $@" +@@ -121,12 +145,22 @@ + + clean:: + $(RM) -f $(PROGS) debugfs.8 \#* *.s *.o *.a *~ debug_cmds.c \ +- extent_cmds.c ro_debug_cmds.c core rdebugfs debugfs.static ++ extent_cmds.c ro_debug_cmds.c core rdebugfs debugfs.static \ ++ tst_set_fields + + mostlyclean: clean + distclean: clean + $(RM) -f debug_cmds.c .depend Makefile $(srcdir)/TAGS \ +- $(srcdir)/Makefile.in.old ++ $(srcdir)/Makefile.in.old $(srcdir)/recovery.c \ ++ $(srcdir)/revoke.c ++ ++tst_set_fields: set_fields.c util.c ++ $(E) " LD $@" ++ $(Q) $(CC) $(ALL_CFLAGS) $(ALL_LDFLAGS) $(SYSLIBS) -DUNITTEST \ ++ -o tst_set_fields $(srcdir)/set_fields.c $(srcdir)/util.c $(LIBS) ++ ++check:: tst_set_fields ++ $(TESTENV) ./tst_set_fields + + # +++ Dependency line eater +++ + # +@@ -142,11 +176,12 @@ + $(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 \ +- $(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 \ +- $(top_srcdir)/lib/ext2fs/kernel-jbd.h $(top_srcdir)/lib/ext2fs/jfs_compat.h \ +- $(top_srcdir)/lib/ext2fs/kernel-list.h ++ $(srcdir)/../misc/create_inode.h $(top_srcdir)/lib/e2p/e2p.h \ ++ $(top_srcdir)/lib/support/quotaio.h $(top_srcdir)/lib/support/dqblk_v2.h \ ++ $(top_srcdir)/lib/support/quotaio_tree.h $(top_srcdir)/version.h \ ++ $(srcdir)/../e2fsck/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/support/plausible.h + util.o: $(srcdir)/util.c $(top_builddir)/lib/config.h \ + $(top_builddir)/lib/dirpaths.h $(top_srcdir)/lib/ss/ss.h \ + $(top_builddir)/lib/ss/ss_err.h $(top_srcdir)/lib/et/com_err.h \ +@@ -155,8 +190,9 @@ + $(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 \ +- $(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)/../misc/create_inode.h $(top_srcdir)/lib/e2p/e2p.h \ ++ $(top_srcdir)/lib/support/quotaio.h $(top_srcdir)/lib/support/dqblk_v2.h \ ++ $(top_srcdir)/lib/support/quotaio_tree.h + ls.o: $(srcdir)/ls.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 \ +@@ -164,8 +200,9 @@ + $(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 \ +- $(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)/../misc/create_inode.h $(top_srcdir)/lib/e2p/e2p.h \ ++ $(top_srcdir)/lib/support/quotaio.h $(top_srcdir)/lib/support/dqblk_v2.h \ ++ $(top_srcdir)/lib/support/quotaio_tree.h + ncheck.o: $(srcdir)/ncheck.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 \ +@@ -173,8 +210,9 @@ + $(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 \ +- $(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)/../misc/create_inode.h $(top_srcdir)/lib/e2p/e2p.h \ ++ $(top_srcdir)/lib/support/quotaio.h $(top_srcdir)/lib/support/dqblk_v2.h \ ++ $(top_srcdir)/lib/support/quotaio_tree.h + icheck.o: $(srcdir)/icheck.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 \ +@@ -182,8 +220,9 @@ + $(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 \ +- $(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)/../misc/create_inode.h $(top_srcdir)/lib/e2p/e2p.h \ ++ $(top_srcdir)/lib/support/quotaio.h $(top_srcdir)/lib/support/dqblk_v2.h \ ++ $(top_srcdir)/lib/support/quotaio_tree.h + lsdel.o: $(srcdir)/lsdel.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 \ +@@ -191,8 +230,9 @@ + $(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 \ +- $(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)/../misc/create_inode.h $(top_srcdir)/lib/e2p/e2p.h \ ++ $(top_srcdir)/lib/support/quotaio.h $(top_srcdir)/lib/support/dqblk_v2.h \ ++ $(top_srcdir)/lib/support/quotaio_tree.h + dump.o: $(srcdir)/dump.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 \ +@@ -200,8 +240,9 @@ + $(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 \ +- $(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)/../misc/create_inode.h $(top_srcdir)/lib/e2p/e2p.h \ ++ $(top_srcdir)/lib/support/quotaio.h $(top_srcdir)/lib/support/dqblk_v2.h \ ++ $(top_srcdir)/lib/support/quotaio_tree.h + set_fields.o: $(srcdir)/set_fields.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 \ +@@ -209,9 +250,9 @@ + $(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 \ +- $(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)/../misc/create_inode.h $(top_srcdir)/lib/e2p/e2p.h \ ++ $(top_srcdir)/lib/support/quotaio.h $(top_srcdir)/lib/support/dqblk_v2.h \ ++ $(top_srcdir)/lib/support/quotaio_tree.h + logdump.o: $(srcdir)/logdump.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 \ +@@ -219,10 +260,11 @@ + $(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 \ +- $(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 \ +- $(top_srcdir)/lib/ext2fs/jfs_compat.h $(top_srcdir)/lib/ext2fs/kernel-list.h ++ $(srcdir)/../misc/create_inode.h $(top_srcdir)/lib/e2p/e2p.h \ ++ $(top_srcdir)/lib/support/quotaio.h $(top_srcdir)/lib/support/dqblk_v2.h \ ++ $(top_srcdir)/lib/support/quotaio_tree.h $(srcdir)/../e2fsck/jfs_user.h \ ++ $(top_srcdir)/lib/ext2fs/kernel-jbd.h $(top_srcdir)/lib/ext2fs/jfs_compat.h \ ++ $(top_srcdir)/lib/ext2fs/kernel-list.h + htree.o: $(srcdir)/htree.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 \ +@@ -230,9 +272,9 @@ + $(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 \ +- $(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)/../misc/create_inode.h $(top_srcdir)/lib/e2p/e2p.h \ ++ $(top_srcdir)/lib/support/quotaio.h $(top_srcdir)/lib/support/dqblk_v2.h \ ++ $(top_srcdir)/lib/support/quotaio_tree.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 \ +@@ -240,15 +282,20 @@ + $(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 \ +- $(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)/../misc/create_inode.h $(top_srcdir)/lib/e2p/e2p.h \ ++ $(top_srcdir)/lib/support/quotaio.h $(top_srcdir)/lib/support/dqblk_v2.h \ ++ $(top_srcdir)/lib/support/quotaio_tree.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 ++ $(srcdir)/../misc/e2freefrag.h $(srcdir)/debugfs.h $(top_srcdir)/lib/ss/ss.h \ ++ $(top_builddir)/lib/ss/ss_err.h $(srcdir)/../misc/create_inode.h \ ++ $(top_srcdir)/lib/e2p/e2p.h $(top_srcdir)/lib/support/quotaio.h \ ++ $(top_srcdir)/lib/support/dqblk_v2.h \ ++ $(top_srcdir)/lib/support/quotaio_tree.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 \ +@@ -256,8 +303,9 @@ + $(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 \ +- $(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)/../misc/create_inode.h $(top_srcdir)/lib/e2p/e2p.h \ ++ $(top_srcdir)/lib/support/quotaio.h $(top_srcdir)/lib/support/dqblk_v2.h \ ++ $(top_srcdir)/lib/support/quotaio_tree.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 \ +@@ -265,8 +313,9 @@ + $(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 \ +- $(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)/../misc/create_inode.h $(top_srcdir)/lib/e2p/e2p.h \ ++ $(top_srcdir)/lib/support/quotaio.h $(top_srcdir)/lib/support/dqblk_v2.h \ ++ $(top_srcdir)/lib/support/quotaio_tree.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 \ +@@ -274,8 +323,27 @@ + $(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 \ +- $(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)/../misc/create_inode.h $(top_srcdir)/lib/e2p/e2p.h \ ++ $(top_srcdir)/lib/support/quotaio.h $(top_srcdir)/lib/support/dqblk_v2.h \ ++ $(top_srcdir)/lib/support/quotaio_tree.h ++create_inode.o: $(srcdir)/../misc/create_inode.c $(top_builddir)/lib/config.h \ ++ $(top_builddir)/lib/dirpaths.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 \ ++ $(top_srcdir)/lib/ext2fs/fiemap.h $(srcdir)/../misc/create_inode.h \ ++ $(top_srcdir)/lib/e2p/e2p.h $(top_srcdir)/lib/support/nls-enable.h ++xattrs.o: $(srcdir)/xattrs.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 \ ++ $(top_srcdir)/lib/support/quotaio.h $(top_srcdir)/lib/support/dqblk_v2.h \ ++ $(top_srcdir)/lib/support/quotaio_tree.h + quota.o: $(srcdir)/quota.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 \ +@@ -283,5 +351,43 @@ + $(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 \ +- $(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)/../misc/create_inode.h $(top_srcdir)/lib/e2p/e2p.h \ ++ $(top_srcdir)/lib/support/quotaio.h $(top_srcdir)/lib/support/dqblk_v2.h \ ++ $(top_srcdir)/lib/support/quotaio_tree.h ++journal.o: $(srcdir)/journal.c $(top_builddir)/lib/config.h \ ++ $(top_builddir)/lib/dirpaths.h $(srcdir)/../e2fsck/jfs_user.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 \ ++ $(top_srcdir)/lib/ext2fs/kernel-jbd.h $(top_srcdir)/lib/ext2fs/jfs_compat.h \ ++ $(top_srcdir)/lib/ext2fs/kernel-list.h ++revoke.o: $(srcdir)/../e2fsck/revoke.c $(srcdir)/../e2fsck/jfs_user.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 \ ++ $(top_srcdir)/lib/ext2fs/kernel-jbd.h $(top_srcdir)/lib/ext2fs/jfs_compat.h \ ++ $(top_srcdir)/lib/ext2fs/kernel-list.h ++recovery.o: $(srcdir)/../e2fsck/recovery.c $(srcdir)/../e2fsck/jfs_user.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 \ ++ $(top_srcdir)/lib/ext2fs/kernel-jbd.h $(top_srcdir)/lib/ext2fs/jfs_compat.h \ ++ $(top_srcdir)/lib/ext2fs/kernel-list.h ++do_journal.o: $(srcdir)/do_journal.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 \ ++ $(top_srcdir)/lib/support/quotaio.h $(top_srcdir)/lib/support/dqblk_v2.h \ ++ $(top_srcdir)/lib/support/quotaio_tree.h $(srcdir)/../e2fsck/jfs_user.h \ ++ $(top_srcdir)/lib/ext2fs/kernel-jbd.h $(top_srcdir)/lib/ext2fs/jfs_compat.h \ ++ $(top_srcdir)/lib/ext2fs/kernel-list.h +--- a/debugfs/ncheck.c ++++ b/debugfs/ncheck.c +@@ -45,7 +45,7 @@ + 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 @@ + 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") && +--- a/debugfs/quota.c ++++ b/debugfs/quota.c +@@ -90,7 +90,8 @@ + } + + +-static int list_quota_callback(struct dquot *dq, void *cb_data) ++static int list_quota_callback(struct dquot *dq, ++ void *cb_data EXT2FS_ATTR((unused))) + { + printf("%8u %8lld %8lld %8lld %8lld %8lld %8lld\n", + dq->dq_id, (long long)dq->dq_dqb.dqb_curspace, +--- a/debugfs/set_fields.c ++++ b/debugfs/set_fields.c +@@ -30,6 +30,7 @@ + #ifdef HAVE_ERRNO_H + #include + #endif ++#include + #if HAVE_STRINGS_H + #include + #endif +@@ -50,6 +51,7 @@ + static int array_idx; + + #define FLAG_ARRAY 0x0001 ++#define FLAG_ALIAS 0x0002 /* Data intersects with other field */ + + struct field_set_info { + const char *name; +@@ -72,6 +74,9 @@ + static errcode_t parse_mmp_clear(struct field_set_info *info, char *field, + char *arg); + ++#pragma GCC diagnostic push ++#pragma GCC diagnostic ignored "-Wmissing-field-initializers" ++ + static struct field_set_info super_fields[] = { + { "inodes_count", &set_sb.s_inodes_count, NULL, 4, parse_uint }, + { "blocks_count", &set_sb.s_blocks_count, &set_sb.s_blocks_count_hi, +@@ -110,7 +115,6 @@ + { "uuid", &set_sb.s_uuid, NULL, 16, parse_uuid }, + { "volume_name", &set_sb.s_volume_name, NULL, 16, parse_string }, + { "last_mounted", &set_sb.s_last_mounted, NULL, 64, parse_string }, +- { "lastcheck", &set_sb.s_lastcheck, NULL, 4, parse_uint }, + { "algorithm_usage_bitmap", &set_sb.s_algorithm_usage_bitmap, NULL, + 4, parse_uint }, + { "prealloc_blocks", &set_sb.s_prealloc_blocks, NULL, 1, parse_uint }, +@@ -135,7 +139,6 @@ + { "want_extra_isize", &set_sb.s_want_extra_isize, NULL, 2, parse_uint }, + { "flags", &set_sb.s_flags, NULL, 4, parse_uint }, + { "raid_stride", &set_sb.s_raid_stride, NULL, 2, parse_uint }, +- { "min_extra_isize", &set_sb.s_min_extra_isize, NULL, 4, parse_uint }, + { "mmp_interval", &set_sb.s_mmp_update_interval, NULL, 2, parse_uint }, + { "mmp_block", &set_sb.s_mmp_block, NULL, 8, parse_uint }, + { "raid_stripe_width", &set_sb.s_raid_stripe_width, NULL, 4, parse_uint }, +@@ -153,22 +156,27 @@ + { "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 }, ++ { "encryption_level", &set_sb.s_encryption_level, 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 }, + { "first_error_block", &set_sb.s_first_error_block, NULL, 8, parse_uint }, + { "first_error_func", &set_sb.s_first_error_func, NULL, 32, parse_string }, +- { "first_error_line", &set_sb.s_first_error_ino, NULL, 4, parse_uint }, ++ { "first_error_line", &set_sb.s_first_error_line, NULL, 4, parse_uint }, + { "last_error_time", &set_sb.s_last_error_time, NULL, 4, parse_time }, + { "last_error_ino", &set_sb.s_last_error_ino, NULL, 4, parse_uint }, + { "last_error_block", &set_sb.s_last_error_block, NULL, 8, parse_uint }, + { "last_error_func", &set_sb.s_last_error_func, NULL, 32, parse_string }, +- { "last_error_line", &set_sb.s_last_error_ino, NULL, 4, parse_uint }, ++ { "last_error_line", &set_sb.s_last_error_line, NULL, 4, parse_uint }, ++ { "encrypt_algos", &set_sb.s_encrypt_algos, NULL, 1, parse_uint, ++ FLAG_ARRAY, 4 }, ++ { "encrypt_pw_salt", &set_sb.s_encrypt_pw_salt, NULL, 16, parse_uuid }, ++ { "lpf_ino", &set_sb.s_lpf_ino, NULL, 4, parse_uint }, + { 0, 0, 0, 0 } + }; + + static struct field_set_info inode_fields[] = { +- { "inodes_count", &set_sb.s_inodes_count, NULL, 4, parse_uint }, + { "mode", &set_inode.i_mode, NULL, 2, parse_uint }, + { "uid", &set_inode.i_uid, &set_inode.osd2.linux2.l_i_uid_high, + 2, parse_uint }, +@@ -186,7 +194,8 @@ + { "flags", &set_inode.i_flags, NULL, 4, parse_uint }, + { "version", &set_inode.osd1.linux1.l_i_version, + &set_inode.i_version_hi, 4, parse_uint }, +- { "translator", &set_inode.osd1.hurd1.h_i_translator, NULL, 4, parse_uint }, ++ { "translator", &set_inode.osd1.hurd1.h_i_translator, NULL, ++ 4, parse_uint, FLAG_ALIAS }, + { "block", &set_inode.i_block[0], NULL, 4, parse_uint, FLAG_ARRAY, + EXT2_NDIR_BLOCKS }, + { "block[IND]", &set_inode.i_block[EXT2_IND_BLOCK], NULL, 4, parse_uint }, +@@ -196,14 +205,14 @@ + /* Special case: i_file_acl_high is 2 bytes */ + { "file_acl", &set_inode.i_file_acl, + &set_inode.osd2.linux2.l_i_file_acl_high, 6, parse_uint }, +- { "dir_acl", &set_inode.i_dir_acl, NULL, 4, parse_uint }, ++ { "dir_acl", &set_inode.i_dir_acl, NULL, 4, parse_uint, FLAG_ALIAS }, + { "faddr", &set_inode.i_faddr, NULL, 4, parse_uint }, +- { "frag", &set_inode.osd2.hurd2.h_i_frag, NULL, 1, parse_uint }, ++ { "frag", &set_inode.osd2.hurd2.h_i_frag, NULL, 1, parse_uint, FLAG_ALIAS }, + { "fsize", &set_inode.osd2.hurd2.h_i_fsize, NULL, 1, parse_uint }, + { "checksum", &set_inode.osd2.linux2.l_i_checksum_lo, + &set_inode.i_checksum_hi, 2, parse_uint }, + { "author", &set_inode.osd2.hurd2.h_i_author, NULL, +- 4, parse_uint }, ++ 4, parse_uint, FLAG_ALIAS }, + { "extra_isize", &set_inode.i_extra_isize, NULL, + 2, parse_uint }, + { "ctime_extra", &set_inode.i_ctime_extra, NULL, +@@ -259,7 +268,8 @@ + }; + + static struct field_set_info mmp_fields[] = { +- { "clear", &set_mmp.mmp_magic, NULL, sizeof(set_mmp), parse_mmp_clear }, ++ { "clear", &set_mmp.mmp_magic, NULL, sizeof(set_mmp), ++ parse_mmp_clear, FLAG_ALIAS }, + { "magic", &set_mmp.mmp_magic, NULL, 4, parse_uint }, + { "seq", &set_mmp.mmp_seq, NULL, 4, parse_uint }, + { "time", &set_mmp.mmp_time, NULL, 8, parse_uint }, +@@ -268,7 +278,62 @@ + { "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 }, ++ { 0, 0, 0, 0 } + }; ++#pragma GCC diagnostic pop ++ ++#ifdef UNITTEST ++ ++ ++static void do_verify_field_set_info(struct field_set_info *fields, ++ const void *data, size_t size) ++{ ++ struct field_set_info *ss, *ss2; ++ const char *begin = (char *)data; ++ const char *end = begin + size; ++ ++ for (ss = fields ; ss->name ; ss++) { ++ const char *ptr; ++ ++ /* Check pointers */ ++ ptr = ss->ptr; ++ assert(!ptr || (ptr >= begin && ptr < end)); ++ ptr = ss->ptr2; ++ assert(!ptr || (ptr >= begin && ptr < end)); ++ ++ /* Check function */ ++ assert(ss->func); ++ ++ for (ss2 = fields ; ss2 != ss ; ss2++) { ++ /* Check duplicate names */ ++ assert(strcmp(ss->name, ss2->name)); ++ ++ if (ss->flags & FLAG_ALIAS || ss2->flags & FLAG_ALIAS) ++ continue; ++ /* Check false aliases, might be copy-n-paste error */ ++ assert(!ss->ptr || (ss->ptr != ss2->ptr && ++ ss->ptr != ss2->ptr2)); ++ assert(!ss->ptr2 || (ss->ptr2 != ss2->ptr && ++ ss->ptr2 != ss2->ptr2)); ++ } ++ } ++} ++ ++int main(int argc, char **argv) ++{ ++ do_verify_field_set_info(super_fields, &set_sb, sizeof(set_sb)); ++ do_verify_field_set_info(inode_fields, &set_inode, sizeof(set_inode)); ++ do_verify_field_set_info(ext2_bg_fields, &set_gd, sizeof(set_gd)); ++ do_verify_field_set_info(ext4_bg_fields, &set_gd4, sizeof(set_gd4)); ++ do_verify_field_set_info(mmp_fields, &set_mmp, sizeof(set_mmp)); ++ return 0; ++} ++ ++ext2_filsys current_fs; ++ext2_ino_t root, cwd; ++ ++#endif /* UNITTEST */ + + static int check_suffix(const char *field) + { +@@ -784,6 +849,7 @@ + return 1; /* we don't need the MMP block written again */ + } + ++#ifdef CONFIG_MMP + void do_set_mmp_value(int argc, char *argv[]) + { + const char *usage = " \n" +@@ -841,4 +907,12 @@ + *mmp_s = set_mmp; + } + } ++#else ++void do_set_mmp_value(int argc EXT2FS_ATTR((unused)), ++ char *argv[] EXT2FS_ATTR((unused))) ++{ ++ fprintf(stdout, "MMP is unsupported, please recompile with " ++ "--enable-mmp\n"); ++} ++#endif + +--- a/debugfs/util.c ++++ b/debugfs/util.c +@@ -201,7 +201,7 @@ + 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)); +@@ -390,7 +390,7 @@ + return 1; + if (*block == 0) { + com_err(argv[0], 0, "Invalid block number 0"); +- err = 1; ++ return 1; + } + + if (argc > 2) { +@@ -497,3 +497,50 @@ + + return 0; + } ++ ++errcode_t read_list(char *str, blk64_t **list, size_t *len) ++{ ++ blk64_t *lst = *list; ++ size_t ln = *len; ++ char *tok, *p = str; ++ errcode_t retval; ++ ++ while ((tok = strtok(p, ","))) { ++ blk64_t *l; ++ blk64_t x, y; ++ char *e; ++ ++ errno = 0; ++ y = x = strtoull(tok, &e, 0); ++ if (errno) ++ return errno; ++ if (*e == '-') { ++ y = strtoull(e + 1, NULL, 0); ++ if (errno) ++ return errno; ++ } else if (*e != 0) { ++ retval = EINVAL; ++ goto err; ++ } ++ if (y < x) { ++ retval = EINVAL; ++ goto err; ++ } ++ l = realloc(lst, sizeof(blk64_t) * (ln + y - x + 1)); ++ if (l == NULL) { ++ retval = ENOMEM; ++ goto err; ++ } ++ lst = l; ++ for (; x <= y; x++) ++ lst[ln++] = x; ++ p = NULL; ++ } ++ ++ *list = lst; ++ *len = ln; ++ return 0; ++err: ++ free(lst); ++ return retval; ++} +--- /dev/null ++++ b/debugfs/xattrs.c +@@ -0,0 +1,303 @@ ++/* ++ * 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 ++#ifdef HAVE_GETOPT_H ++#include ++#else ++extern int optind; ++extern char *optarg; ++#endif ++#include ++ ++#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 \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 [-f outfile]\n", ++ argv[0], argv[0]); ++ goto out2; ++ } ++ } ++ ++ if (optind != argc - 2) { ++ printf("%s: Usage: %s [-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 [-f infile | " ++ "value]\n", argv[0], argv[0]); ++ goto out2; ++ } ++ } ++ ++ if (!(fp && optind == argc - 2) && !(!fp && optind == argc - 3)) { ++ printf("%s: Usage: %s [-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 ...\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++) { ++ 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"); ++} +--- a/debugfs/zap.c ++++ b/debugfs/zap.c +@@ -174,7 +174,6 @@ + errcode_t errcode; + blk64_t block; + char *file = NULL; +- unsigned int i, j; + int c, err; + + if (check_fs_open(argv[0])) +--- /dev/null ++++ b/e2fsck/Android.mk +@@ -0,0 +1,69 @@ ++LOCAL_PATH := $(call my-dir) ++ ++######################### ++# Build the e2fsck binary ++ ++e2fsck_src_files := \ ++ e2fsck.c \ ++ super.c \ ++ pass1.c \ ++ pass1b.c \ ++ pass2.c \ ++ pass3.c \ ++ pass4.c \ ++ pass5.c \ ++ logfile.c \ ++ journal.c \ ++ recovery.c \ ++ revoke.c \ ++ badblocks.c \ ++ util.c \ ++ unix.c \ ++ dirinfo.c \ ++ dx_dirinfo.c \ ++ ehandler.c \ ++ problem.c \ ++ message.c \ ++ ea_refcount.c \ ++ quota.c \ ++ rehash.c \ ++ region.c \ ++ sigcatcher.c \ ++ readahead.c \ ++ extents.c ++ ++e2fsck_shared_libraries := \ ++ libext2fs \ ++ libext2_blkid \ ++ libext2_uuid \ ++ libext2_quota \ ++ libext2_com_err \ ++ libext2_e2p ++e2fsck_system_shared_libraries := libc ++ ++e2fsck_c_includes := external/e2fsprogs/lib ++ ++e2fsck_cflags := -O2 -g -W -Wall -fno-strict-aliasing ++ ++include $(CLEAR_VARS) ++ ++LOCAL_SRC_FILES := $(e2fsck_src_files) ++LOCAL_C_INCLUDES := $(e2fsck_c_includes) ++LOCAL_CFLAGS := $(e2fsck_cflags) ++LOCAL_SYSTEM_SHARED_LIBRARIES := $(e2fsck_system_shared_libraries) ++LOCAL_SHARED_LIBRARIES := $(e2fsck_shared_libraries) ++LOCAL_MODULE := e2fsck ++LOCAL_MODULE_TAGS := optional ++include $(BUILD_EXECUTABLE) ++ ++include $(CLEAR_VARS) ++ ++LOCAL_SRC_FILES := $(e2fsck_src_files) ++LOCAL_C_INCLUDES := $(e2fsck_c_includes) ++LOCAL_CFLAGS := $(e2fsck_cflags) ++LOCAL_SHARED_LIBRARIES := $(addsuffix _host, $(e2fsck_shared_libraries)) ++LOCAL_MODULE := e2fsck_host ++LOCAL_MODULE_STEM := e2fsck ++LOCAL_MODULE_TAGS := optional ++ ++include $(BUILD_HOST_EXECUTABLE) +--- a/e2fsck/argv_parse.c ++++ /dev/null +@@ -1,166 +0,0 @@ +-/* +- * argv_parse.c --- utility function for parsing a string into a +- * argc, argv array. +- * +- * This file defines a function argv_parse() which parsing a +- * passed-in string, handling double quotes and backslashes, and +- * creates an allocated argv vector which can be freed using the +- * argv_free() function. +- * +- * See argv_parse.h for the formal definition of the functions. +- * +- * Copyright 1999 by Theodore Ts'o. +- * +- * Permission to use, copy, modify, and distribute this software for +- * any purpose with or without fee is hereby granted, provided that +- * the above copyright notice and this permission notice appear in all +- * copies. THE SOFTWARE IS PROVIDED "AS IS" AND THEODORE TS'O (THE +- * AUTHOR) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +- * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. +- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +- * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER +- * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION +- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR +- * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. (Isn't +- * it sick that the U.S. culture of lawsuit-happy lawyers requires +- * this kind of disclaimer?) +- * +- * Version 1.1, modified 2/27/1999 +- */ +- +-#include "config.h" +-#ifdef HAVE_STDLIB_H +-#include +-#endif +-#include +-#include +-#include "argv_parse.h" +- +-#define STATE_WHITESPACE 1 +-#define STATE_TOKEN 2 +-#define STATE_QUOTED 3 +- +-/* +- * Returns 0 on success, -1 on failure. +- */ +-int argv_parse(char *in_buf, int *ret_argc, char ***ret_argv) +-{ +- int argc = 0, max_argc = 0; +- char **argv, **new_argv, *buf, ch; +- char *cp = 0, *outcp = 0; +- int state = STATE_WHITESPACE; +- +- buf = malloc(strlen(in_buf)+1); +- if (!buf) +- return -1; +- +- max_argc = 0; argc = 0; argv = 0; +- outcp = buf; +- for (cp = in_buf; (ch = *cp); cp++) { +- if (state == STATE_WHITESPACE) { +- if (isspace((int) ch)) +- continue; +- /* Not whitespace, so start a new token */ +- state = STATE_TOKEN; +- if (argc >= max_argc) { +- max_argc += 3; +- new_argv = realloc(argv, +- (max_argc+1)*sizeof(char *)); +- if (!new_argv) { +- free(argv); +- free(buf); +- return -1; +- } +- argv = new_argv; +- } +- argv[argc++] = outcp; +- } +- if (state == STATE_QUOTED) { +- if (ch == '"') +- state = STATE_TOKEN; +- else +- *outcp++ = ch; +- continue; +- } +- /* Must be processing characters in a word */ +- if (isspace((int) ch)) { +- /* +- * Terminate the current word and start +- * looking for the beginning of the next word. +- */ +- *outcp++ = 0; +- state = STATE_WHITESPACE; +- continue; +- } +- if (ch == '"') { +- state = STATE_QUOTED; +- continue; +- } +- if (ch == '\\') { +- ch = *++cp; +- switch (ch) { +- case '\0': +- ch = '\\'; cp--; break; +- case 'n': +- ch = '\n'; break; +- case 't': +- ch = '\t'; break; +- case 'b': +- ch = '\b'; break; +- } +- } +- *outcp++ = ch; +- } +- if (state != STATE_WHITESPACE) +- *outcp++ = '\0'; +- if (argv == 0) { +- argv = malloc(sizeof(char *)); +- free(buf); +- } +- argv[argc] = 0; +- if (ret_argc) +- *ret_argc = argc; +- if (ret_argv) +- *ret_argv = argv; +- return 0; +-} +- +-void argv_free(char **argv) +-{ +- free(*argv); +- free(argv); +-} +- +-#ifdef DEBUG +-/* +- * For debugging +- */ +- +-#include +- +-int main(int argc, char **argv) +-{ +- int ac, ret; +- char **av, **cpp; +- char buf[256]; +- +- while (!feof(stdin)) { +- if (fgets(buf, sizeof(buf), stdin) == NULL) +- break; +- ret = argv_parse(buf, &ac, &av); +- if (ret != 0) { +- printf("Argv_parse returned %d!\n", ret); +- continue; +- } +- printf("Argv_parse returned %d arguments...\n", ac); +- for (cpp = av; *cpp; cpp++) { +- if (cpp != av) +- printf(", "); +- printf("'%s'", *cpp); +- } +- printf("\n"); +- argv_free(av); +- } +- exit(0); +-} +-#endif /* DEBUG */ +--- a/e2fsck/argv_parse.h ++++ /dev/null +@@ -1,43 +0,0 @@ +-/* +- * argv_parse.h --- header file for the argv parser. +- * +- * This file defines the interface for the functions argv_parse() and +- * argv_free(). +- * +- *********************************************************************** +- * int argv_parse(char *in_buf, int *ret_argc, char ***ret_argv) +- * +- * This function takes as its first argument a string which it will +- * parse into an argv argument vector, with each white-space separated +- * word placed into its own slot in the argv. This function handles +- * double quotes and backslashes so that the parsed words can contain +- * special characters. The count of the number words found in the +- * parsed string, as well as the argument vector, are returned into +- * ret_argc and ret_argv, respectively. +- *********************************************************************** +- * extern void argv_free(char **argv); +- * +- * This function frees the argument vector created by argv_parse(). +- *********************************************************************** +- * +- * Copyright 1999 by Theodore Ts'o. +- * +- * Permission to use, copy, modify, and distribute this software for +- * any purpose with or without fee is hereby granted, provided that +- * the above copyright notice and this permission notice appear in all +- * copies. THE SOFTWARE IS PROVIDED "AS IS" AND THEODORE TS'O (THE +- * AUTHOR) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +- * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. +- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +- * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER +- * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION +- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR +- * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. (Isn't +- * it sick that the U.S. culture of lawsuit-happy lawyers requires +- * this kind of disclaimer?) +- * +- * Version 1.1, modified 2/27/1999 +- */ +- +-extern int argv_parse(char *in_buf, int *ret_argc, char ***ret_argv); +-extern void argv_free(char **argv); +--- a/e2fsck/crc32.c ++++ /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 +- * 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 +- * 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 +-#include +-#include +-#include +- +-#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 +-#include +- +-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 */ +--- a/e2fsck/crc32defs.h ++++ /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< 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 +--- a/e2fsck/dict.c ++++ /dev/null +@@ -1,1522 +0,0 @@ +-/* +- * Dictionary Abstract Data Type +- * Copyright (C) 1997 Kaz Kylheku +- * +- * Free Software License: +- * +- * All rights are reserved by the author, with the following exceptions: +- * Permission is granted to freely reproduce and distribute this software, +- * possibly in exchange for a fee, provided that this copyright notice appears +- * intact. Permission is also granted to adapt this software to produce +- * derivative works, as long as the modified versions carry this copyright +- * notice and additional notices stating that the work has been modified. +- * This source code may be translated into executable form and incorporated +- * into proprietary software; there is no requirement for such software to +- * contain a copyright notice related to this source. +- * +- * $Id: dict.c,v 1.40.2.7 2000/11/13 01:36:44 kaz Exp $ +- * $Name: kazlib_1_20 $ +- */ +- +-#define NDEBUG +- +-#ifdef __GNUC__ +-#define EXT2FS_ATTR(x) __attribute__(x) +-#else +-#define EXT2FS_ATTR(x) +-#endif +- +-#include "config.h" +-#include +-#include +-#include +-#define DICT_IMPLEMENTATION +-#include "dict.h" +- +-#ifdef KAZLIB_RCSID +-static const char rcsid[] = "$Id: dict.c,v 1.40.2.7 2000/11/13 01:36:44 kaz Exp $"; +-#endif +- +-/* +- * These macros provide short convenient names for structure members, +- * which are embellished with dict_ prefixes so that they are +- * properly confined to the documented namespace. It's legal for a +- * program which uses dict to define, for instance, a macro called ``parent''. +- * Such a macro would interfere with the dnode_t struct definition. +- * In general, highly portable and reusable C modules which expose their +- * structures need to confine structure member names to well-defined spaces. +- * The resulting identifiers aren't necessarily convenient to use, nor +- * readable, in the implementation, however! +- */ +- +-#define left dict_left +-#define right dict_right +-#define parent dict_parent +-#define color dict_color +-#define key dict_key +-#define data dict_data +- +-#define nilnode dict_nilnode +-#define nodecount dict_nodecount +-#define maxcount dict_maxcount +-#define compare dict_compare +-#define allocnode dict_allocnode +-#define freenode dict_freenode +-#define context dict_context +-#define dupes dict_dupes +- +-#define dictptr dict_dictptr +- +-#define dict_root(D) ((D)->nilnode.left) +-#define dict_nil(D) (&(D)->nilnode) +-#define DICT_DEPTH_MAX 64 +- +-static dnode_t *dnode_alloc(void *context); +-static void dnode_free(dnode_t *node, void *context); +- +-/* +- * Perform a ``left rotation'' adjustment on the tree. The given node P and +- * its right child C are rearranged so that the P instead becomes the left +- * child of C. The left subtree of C is inherited as the new right subtree +- * for P. The ordering of the keys within the tree is thus preserved. +- */ +- +-static void rotate_left(dnode_t *upper) +-{ +- dnode_t *lower, *lowleft, *upparent; +- +- lower = upper->right; +- upper->right = lowleft = lower->left; +- lowleft->parent = upper; +- +- lower->parent = upparent = upper->parent; +- +- /* don't need to check for root node here because root->parent is +- the sentinel nil node, and root->parent->left points back to root */ +- +- if (upper == upparent->left) { +- upparent->left = lower; +- } else { +- assert (upper == upparent->right); +- upparent->right = lower; +- } +- +- lower->left = upper; +- upper->parent = lower; +-} +- +-/* +- * This operation is the ``mirror'' image of rotate_left. It is +- * the same procedure, but with left and right interchanged. +- */ +- +-static void rotate_right(dnode_t *upper) +-{ +- dnode_t *lower, *lowright, *upparent; +- +- lower = upper->left; +- upper->left = lowright = lower->right; +- lowright->parent = upper; +- +- lower->parent = upparent = upper->parent; +- +- if (upper == upparent->right) { +- upparent->right = lower; +- } else { +- assert (upper == upparent->left); +- upparent->left = lower; +- } +- +- lower->right = upper; +- upper->parent = lower; +-} +- +-/* +- * Do a postorder traversal of the tree rooted at the specified +- * node and free everything under it. Used by dict_free(). +- */ +- +-static void free_nodes(dict_t *dict, dnode_t *node, dnode_t *nil) +-{ +- if (node == nil) +- return; +- free_nodes(dict, node->left, nil); +- free_nodes(dict, node->right, nil); +- dict->freenode(node, dict->context); +-} +- +-/* +- * This procedure performs a verification that the given subtree is a binary +- * search tree. It performs an inorder traversal of the tree using the +- * dict_next() successor function, verifying that the key of each node is +- * strictly lower than that of its successor, if duplicates are not allowed, +- * or lower or equal if duplicates are allowed. This function is used for +- * debugging purposes. +- */ +-#ifndef NDEBUG +-static int verify_bintree(dict_t *dict) +-{ +- dnode_t *first, *next; +- +- first = dict_first(dict); +- +- if (dict->dupes) { +- while (first && (next = dict_next(dict, first))) { +- if (dict->compare(first->key, next->key) > 0) +- return 0; +- first = next; +- } +- } else { +- while (first && (next = dict_next(dict, first))) { +- if (dict->compare(first->key, next->key) >= 0) +- return 0; +- first = next; +- } +- } +- return 1; +-} +- +-/* +- * This function recursively verifies that the given binary subtree satisfies +- * three of the red black properties. It checks that every red node has only +- * black children. It makes sure that each node is either red or black. And it +- * checks that every path has the same count of black nodes from root to leaf. +- * It returns the blackheight of the given subtree; this allows blackheights to +- * be computed recursively and compared for left and right siblings for +- * mismatches. It does not check for every nil node being black, because there +- * is only one sentinel nil node. The return value of this function is the +- * black height of the subtree rooted at the node ``root'', or zero if the +- * subtree is not red-black. +- */ +- +-static unsigned int verify_redblack(dnode_t *nil, dnode_t *root) +-{ +- unsigned height_left, height_right; +- +- if (root != nil) { +- height_left = verify_redblack(nil, root->left); +- height_right = verify_redblack(nil, root->right); +- if (height_left == 0 || height_right == 0) +- return 0; +- if (height_left != height_right) +- return 0; +- if (root->color == dnode_red) { +- if (root->left->color != dnode_black) +- return 0; +- if (root->right->color != dnode_black) +- return 0; +- return height_left; +- } +- if (root->color != dnode_black) +- return 0; +- return height_left + 1; +- } +- return 1; +-} +- +-/* +- * Compute the actual count of nodes by traversing the tree and +- * return it. This could be compared against the stored count to +- * detect a mismatch. +- */ +- +-static dictcount_t verify_node_count(dnode_t *nil, dnode_t *root) +-{ +- if (root == nil) +- return 0; +- else +- return 1 + verify_node_count(nil, root->left) +- + verify_node_count(nil, root->right); +-} +-#endif +- +-/* +- * Verify that the tree contains the given node. This is done by +- * traversing all of the nodes and comparing their pointers to the +- * given pointer. Returns 1 if the node is found, otherwise +- * returns zero. It is intended for debugging purposes. +- */ +- +-static int verify_dict_has_node(dnode_t *nil, dnode_t *root, dnode_t *node) +-{ +- if (root != nil) { +- return root == node +- || verify_dict_has_node(nil, root->left, node) +- || verify_dict_has_node(nil, root->right, node); +- } +- return 0; +-} +- +- +-#ifdef E2FSCK_NOTUSED +-/* +- * Dynamically allocate and initialize a dictionary object. +- */ +- +-dict_t *dict_create(dictcount_t maxcount, dict_comp_t comp) +-{ +- dict_t *new = malloc(sizeof *new); +- +- if (new) { +- new->compare = comp; +- new->allocnode = dnode_alloc; +- new->freenode = dnode_free; +- new->context = NULL; +- new->nodecount = 0; +- new->maxcount = maxcount; +- new->nilnode.left = &new->nilnode; +- new->nilnode.right = &new->nilnode; +- new->nilnode.parent = &new->nilnode; +- new->nilnode.color = dnode_black; +- new->dupes = 0; +- } +- return new; +-} +-#endif /* E2FSCK_NOTUSED */ +- +-/* +- * Select a different set of node allocator routines. +- */ +- +-void dict_set_allocator(dict_t *dict, dnode_alloc_t al, +- dnode_free_t fr, void *context) +-{ +- assert (dict_count(dict) == 0); +- assert ((al == NULL && fr == NULL) || (al != NULL && fr != NULL)); +- +- dict->allocnode = al ? al : dnode_alloc; +- dict->freenode = fr ? fr : dnode_free; +- dict->context = context; +-} +- +-#ifdef E2FSCK_NOTUSED +-/* +- * Free a dynamically allocated dictionary object. Removing the nodes +- * from the tree before deleting it is required. +- */ +- +-void dict_destroy(dict_t *dict) +-{ +- assert (dict_isempty(dict)); +- free(dict); +-} +-#endif +- +-/* +- * Free all the nodes in the dictionary by using the dictionary's +- * installed free routine. The dictionary is emptied. +- */ +- +-void dict_free_nodes(dict_t *dict) +-{ +- dnode_t *nil = dict_nil(dict), *root = dict_root(dict); +- free_nodes(dict, root, nil); +- dict->nodecount = 0; +- dict->nilnode.left = &dict->nilnode; +- dict->nilnode.right = &dict->nilnode; +-} +- +-#ifdef E2FSCK_NOTUSED +-/* +- * Obsolescent function, equivalent to dict_free_nodes +- */ +-void dict_free(dict_t *dict) +-{ +-#ifdef KAZLIB_OBSOLESCENT_DEBUG +- assert ("call to obsolescent function dict_free()" && 0); +-#endif +- dict_free_nodes(dict); +-} +-#endif +- +-/* +- * Initialize a user-supplied dictionary object. +- */ +- +-dict_t *dict_init(dict_t *dict, dictcount_t maxcount, dict_comp_t comp) +-{ +- dict->compare = comp; +- dict->allocnode = dnode_alloc; +- dict->freenode = dnode_free; +- dict->context = NULL; +- dict->nodecount = 0; +- dict->maxcount = maxcount; +- dict->nilnode.left = &dict->nilnode; +- dict->nilnode.right = &dict->nilnode; +- dict->nilnode.parent = &dict->nilnode; +- dict->nilnode.color = dnode_black; +- dict->dupes = 0; +- return dict; +-} +- +-#ifdef E2FSCK_NOTUSED +-/* +- * Initialize a dictionary in the likeness of another dictionary +- */ +- +-void dict_init_like(dict_t *dict, const dict_t *template) +-{ +- dict->compare = template->compare; +- dict->allocnode = template->allocnode; +- dict->freenode = template->freenode; +- dict->context = template->context; +- dict->nodecount = 0; +- dict->maxcount = template->maxcount; +- dict->nilnode.left = &dict->nilnode; +- dict->nilnode.right = &dict->nilnode; +- dict->nilnode.parent = &dict->nilnode; +- dict->nilnode.color = dnode_black; +- dict->dupes = template->dupes; +- +- assert (dict_similar(dict, template)); +-} +- +-/* +- * Remove all nodes from the dictionary (without freeing them in any way). +- */ +- +-static void dict_clear(dict_t *dict) +-{ +- dict->nodecount = 0; +- dict->nilnode.left = &dict->nilnode; +- dict->nilnode.right = &dict->nilnode; +- dict->nilnode.parent = &dict->nilnode; +- assert (dict->nilnode.color == dnode_black); +-} +- +- +-/* +- * Verify the integrity of the dictionary structure. This is provided for +- * debugging purposes, and should be placed in assert statements. Just because +- * this function succeeds doesn't mean that the tree is not corrupt. Certain +- * corruptions in the tree may simply cause undefined behavior. +- */ +- +-int dict_verify(dict_t *dict) +-{ +-#ifndef NDEBUG +- dnode_t *nil = dict_nil(dict), *root = dict_root(dict); +- +- /* check that the sentinel node and root node are black */ +- if (root->color != dnode_black) +- return 0; +- if (nil->color != dnode_black) +- return 0; +- if (nil->right != nil) +- return 0; +- /* nil->left is the root node; check that its parent pointer is nil */ +- if (nil->left->parent != nil) +- return 0; +- /* perform a weak test that the tree is a binary search tree */ +- if (!verify_bintree(dict)) +- return 0; +- /* verify that the tree is a red-black tree */ +- if (!verify_redblack(nil, root)) +- return 0; +- if (verify_node_count(nil, root) != dict_count(dict)) +- return 0; +-#endif +- return 1; +-} +- +-/* +- * Determine whether two dictionaries are similar: have the same comparison and +- * allocator functions, and same status as to whether duplicates are allowed. +- */ +- +-int dict_similar(const dict_t *left, const dict_t *right) +-{ +- if (left->compare != right->compare) +- return 0; +- +- if (left->allocnode != right->allocnode) +- return 0; +- +- if (left->freenode != right->freenode) +- return 0; +- +- if (left->context != right->context) +- return 0; +- +- if (left->dupes != right->dupes) +- return 0; +- +- return 1; +-} +-#endif /* E2FSCK_NOTUSED */ +- +-/* +- * Locate a node in the dictionary having the given key. +- * If the node is not found, a null a pointer is returned (rather than +- * a pointer that dictionary's nil sentinel node), otherwise a pointer to the +- * located node is returned. +- */ +- +-dnode_t *dict_lookup(dict_t *dict, const void *key) +-{ +- dnode_t *root = dict_root(dict); +- dnode_t *nil = dict_nil(dict); +- dnode_t *saved; +- int result; +- +- /* simple binary search adapted for trees that contain duplicate keys */ +- +- while (root != nil) { +- result = dict->compare(key, root->key); +- if (result < 0) +- root = root->left; +- else if (result > 0) +- root = root->right; +- else { +- if (!dict->dupes) { /* no duplicates, return match */ +- return root; +- } else { /* could be dupes, find leftmost one */ +- do { +- saved = root; +- root = root->left; +- while (root != nil && dict->compare(key, root->key)) +- root = root->right; +- } while (root != nil); +- return saved; +- } +- } +- } +- +- return NULL; +-} +- +-#ifdef E2FSCK_NOTUSED +-/* +- * Look for the node corresponding to the lowest key that is equal to or +- * greater than the given key. If there is no such node, return null. +- */ +- +-dnode_t *dict_lower_bound(dict_t *dict, const void *key) +-{ +- dnode_t *root = dict_root(dict); +- dnode_t *nil = dict_nil(dict); +- dnode_t *tentative = 0; +- +- while (root != nil) { +- int result = dict->compare(key, root->key); +- +- if (result > 0) { +- root = root->right; +- } else if (result < 0) { +- tentative = root; +- root = root->left; +- } else { +- if (!dict->dupes) { +- return root; +- } else { +- tentative = root; +- root = root->left; +- } +- } +- } +- +- return tentative; +-} +- +-/* +- * Look for the node corresponding to the greatest key that is equal to or +- * lower than the given key. If there is no such node, return null. +- */ +- +-dnode_t *dict_upper_bound(dict_t *dict, const void *key) +-{ +- dnode_t *root = dict_root(dict); +- dnode_t *nil = dict_nil(dict); +- dnode_t *tentative = 0; +- +- while (root != nil) { +- int result = dict->compare(key, root->key); +- +- if (result < 0) { +- root = root->left; +- } else if (result > 0) { +- tentative = root; +- root = root->right; +- } else { +- if (!dict->dupes) { +- return root; +- } else { +- tentative = root; +- root = root->right; +- } +- } +- } +- +- return tentative; +-} +-#endif +- +-/* +- * Insert a node into the dictionary. The node should have been +- * initialized with a data field. All other fields are ignored. +- * The behavior is undefined if the user attempts to insert into +- * a dictionary that is already full (for which the dict_isfull() +- * function returns true). +- */ +- +-void dict_insert(dict_t *dict, dnode_t *node, const void *key) +-{ +- dnode_t *where = dict_root(dict), *nil = dict_nil(dict); +- dnode_t *parent = nil, *uncle, *grandpa; +- int result = -1; +- +- node->key = key; +- +- assert (!dict_isfull(dict)); +- assert (!dict_contains(dict, node)); +- assert (!dnode_is_in_a_dict(node)); +- +- /* basic binary tree insert */ +- +- while (where != nil) { +- parent = where; +- result = dict->compare(key, where->key); +- /* trap attempts at duplicate key insertion unless it's explicitly allowed */ +- assert (dict->dupes || result != 0); +- if (result < 0) +- where = where->left; +- else +- where = where->right; +- } +- +- assert (where == nil); +- +- if (result < 0) +- parent->left = node; +- else +- parent->right = node; +- +- node->parent = parent; +- node->left = nil; +- node->right = nil; +- +- dict->nodecount++; +- +- /* red black adjustments */ +- +- node->color = dnode_red; +- +- while (parent->color == dnode_red) { +- grandpa = parent->parent; +- if (parent == grandpa->left) { +- uncle = grandpa->right; +- if (uncle->color == dnode_red) { /* red parent, red uncle */ +- parent->color = dnode_black; +- uncle->color = dnode_black; +- grandpa->color = dnode_red; +- node = grandpa; +- parent = grandpa->parent; +- } else { /* red parent, black uncle */ +- if (node == parent->right) { +- rotate_left(parent); +- parent = node; +- assert (grandpa == parent->parent); +- /* rotation between parent and child preserves grandpa */ +- } +- parent->color = dnode_black; +- grandpa->color = dnode_red; +- rotate_right(grandpa); +- break; +- } +- } else { /* symmetric cases: parent == parent->parent->right */ +- uncle = grandpa->left; +- if (uncle->color == dnode_red) { +- parent->color = dnode_black; +- uncle->color = dnode_black; +- grandpa->color = dnode_red; +- node = grandpa; +- parent = grandpa->parent; +- } else { +- if (node == parent->left) { +- rotate_right(parent); +- parent = node; +- assert (grandpa == parent->parent); +- } +- parent->color = dnode_black; +- grandpa->color = dnode_red; +- rotate_left(grandpa); +- break; +- } +- } +- } +- +- dict_root(dict)->color = dnode_black; +- +- assert (dict_verify(dict)); +-} +- +-#ifdef E2FSCK_NOTUSED +-/* +- * Delete the given node from the dictionary. If the given node does not belong +- * to the given dictionary, undefined behavior results. A pointer to the +- * deleted node is returned. +- */ +- +-dnode_t *dict_delete(dict_t *dict, dnode_t *delete) +-{ +- dnode_t *nil = dict_nil(dict), *child, *delparent = delete->parent; +- +- /* basic deletion */ +- +- assert (!dict_isempty(dict)); +- assert (dict_contains(dict, delete)); +- +- /* +- * If the node being deleted has two children, then we replace it with its +- * successor (i.e. the leftmost node in the right subtree.) By doing this, +- * we avoid the traditional algorithm under which the successor's key and +- * value *only* move to the deleted node and the successor is spliced out +- * from the tree. We cannot use this approach because the user may hold +- * pointers to the successor, or nodes may be inextricably tied to some +- * other structures by way of embedding, etc. So we must splice out the +- * node we are given, not some other node, and must not move contents from +- * one node to another behind the user's back. +- */ +- +- if (delete->left != nil && delete->right != nil) { +- dnode_t *next = dict_next(dict, delete); +- dnode_t *nextparent = next->parent; +- dnode_color_t nextcolor = next->color; +- +- assert (next != nil); +- assert (next->parent != nil); +- assert (next->left == nil); +- +- /* +- * First, splice out the successor from the tree completely, by +- * moving up its right child into its place. +- */ +- +- child = next->right; +- child->parent = nextparent; +- +- if (nextparent->left == next) { +- nextparent->left = child; +- } else { +- assert (nextparent->right == next); +- nextparent->right = child; +- } +- +- /* +- * Now that the successor has been extricated from the tree, install it +- * in place of the node that we want deleted. +- */ +- +- next->parent = delparent; +- next->left = delete->left; +- next->right = delete->right; +- next->left->parent = next; +- next->right->parent = next; +- next->color = delete->color; +- delete->color = nextcolor; +- +- if (delparent->left == delete) { +- delparent->left = next; +- } else { +- assert (delparent->right == delete); +- delparent->right = next; +- } +- +- } else { +- assert (delete != nil); +- assert (delete->left == nil || delete->right == nil); +- +- child = (delete->left != nil) ? delete->left : delete->right; +- +- child->parent = delparent = delete->parent; +- +- if (delete == delparent->left) { +- delparent->left = child; +- } else { +- assert (delete == delparent->right); +- delparent->right = child; +- } +- } +- +- delete->parent = NULL; +- delete->right = NULL; +- delete->left = NULL; +- +- dict->nodecount--; +- +- assert (verify_bintree(dict)); +- +- /* red-black adjustments */ +- +- if (delete->color == dnode_black) { +- dnode_t *parent, *sister; +- +- dict_root(dict)->color = dnode_red; +- +- while (child->color == dnode_black) { +- parent = child->parent; +- if (child == parent->left) { +- sister = parent->right; +- assert (sister != nil); +- if (sister->color == dnode_red) { +- sister->color = dnode_black; +- parent->color = dnode_red; +- rotate_left(parent); +- sister = parent->right; +- assert (sister != nil); +- } +- if (sister->left->color == dnode_black +- && sister->right->color == dnode_black) { +- sister->color = dnode_red; +- child = parent; +- } else { +- if (sister->right->color == dnode_black) { +- assert (sister->left->color == dnode_red); +- sister->left->color = dnode_black; +- sister->color = dnode_red; +- rotate_right(sister); +- sister = parent->right; +- assert (sister != nil); +- } +- sister->color = parent->color; +- sister->right->color = dnode_black; +- parent->color = dnode_black; +- rotate_left(parent); +- break; +- } +- } else { /* symmetric case: child == child->parent->right */ +- assert (child == parent->right); +- sister = parent->left; +- assert (sister != nil); +- if (sister->color == dnode_red) { +- sister->color = dnode_black; +- parent->color = dnode_red; +- rotate_right(parent); +- sister = parent->left; +- assert (sister != nil); +- } +- if (sister->right->color == dnode_black +- && sister->left->color == dnode_black) { +- sister->color = dnode_red; +- child = parent; +- } else { +- if (sister->left->color == dnode_black) { +- assert (sister->right->color == dnode_red); +- sister->right->color = dnode_black; +- sister->color = dnode_red; +- rotate_left(sister); +- sister = parent->left; +- assert (sister != nil); +- } +- sister->color = parent->color; +- sister->left->color = dnode_black; +- parent->color = dnode_black; +- rotate_right(parent); +- break; +- } +- } +- } +- +- child->color = dnode_black; +- dict_root(dict)->color = dnode_black; +- } +- +- assert (dict_verify(dict)); +- +- return delete; +-} +-#endif /* E2FSCK_NOTUSED */ +- +-/* +- * Allocate a node using the dictionary's allocator routine, give it +- * the data item. +- */ +- +-int dict_alloc_insert(dict_t *dict, const void *key, void *data) +-{ +- dnode_t *node = dict->allocnode(dict->context); +- +- if (node) { +- dnode_init(node, data); +- dict_insert(dict, node, key); +- return 1; +- } +- return 0; +-} +- +-#ifdef E2FSCK_NOTUSED +-void dict_delete_free(dict_t *dict, dnode_t *node) +-{ +- dict_delete(dict, node); +- dict->freenode(node, dict->context); +-} +-#endif +- +-/* +- * Return the node with the lowest (leftmost) key. If the dictionary is empty +- * (that is, dict_isempty(dict) returns 1) a null pointer is returned. +- */ +- +-dnode_t *dict_first(dict_t *dict) +-{ +- dnode_t *nil = dict_nil(dict), *root = dict_root(dict), *left; +- +- if (root != nil) +- while ((left = root->left) != nil) +- root = left; +- +- return (root == nil) ? NULL : root; +-} +- +-/* +- * Return the node with the highest (rightmost) key. If the dictionary is empty +- * (that is, dict_isempty(dict) returns 1) a null pointer is returned. +- */ +- +-dnode_t *dict_last(dict_t *dict) +-{ +- dnode_t *nil = dict_nil(dict), *root = dict_root(dict), *right; +- +- if (root != nil) +- while ((right = root->right) != nil) +- root = right; +- +- return (root == nil) ? NULL : root; +-} +- +-/* +- * Return the given node's successor node---the node which has the +- * next key in the the left to right ordering. If the node has +- * no successor, a null pointer is returned rather than a pointer to +- * the nil node. +- */ +- +-dnode_t *dict_next(dict_t *dict, dnode_t *curr) +-{ +- dnode_t *nil = dict_nil(dict), *parent, *left; +- +- if (curr->right != nil) { +- curr = curr->right; +- while ((left = curr->left) != nil) +- curr = left; +- return curr; +- } +- +- parent = curr->parent; +- +- while (parent != nil && curr == parent->right) { +- curr = parent; +- parent = curr->parent; +- } +- +- return (parent == nil) ? NULL : parent; +-} +- +-/* +- * Return the given node's predecessor, in the key order. +- * The nil sentinel node is returned if there is no predecessor. +- */ +- +-dnode_t *dict_prev(dict_t *dict, dnode_t *curr) +-{ +- dnode_t *nil = dict_nil(dict), *parent, *right; +- +- if (curr->left != nil) { +- curr = curr->left; +- while ((right = curr->right) != nil) +- curr = right; +- return curr; +- } +- +- parent = curr->parent; +- +- while (parent != nil && curr == parent->left) { +- curr = parent; +- parent = curr->parent; +- } +- +- return (parent == nil) ? NULL : parent; +-} +- +-void dict_allow_dupes(dict_t *dict) +-{ +- dict->dupes = 1; +-} +- +-#undef dict_count +-#undef dict_isempty +-#undef dict_isfull +-#undef dnode_get +-#undef dnode_put +-#undef dnode_getkey +- +-dictcount_t dict_count(dict_t *dict) +-{ +- return dict->nodecount; +-} +- +-int dict_isempty(dict_t *dict) +-{ +- return dict->nodecount == 0; +-} +- +-int dict_isfull(dict_t *dict) +-{ +- return dict->nodecount == dict->maxcount; +-} +- +-int dict_contains(dict_t *dict, dnode_t *node) +-{ +- return verify_dict_has_node(dict_nil(dict), dict_root(dict), node); +-} +- +-static dnode_t *dnode_alloc(void *context EXT2FS_ATTR((unused))) +-{ +- return malloc(sizeof *dnode_alloc(NULL)); +-} +- +-static void dnode_free(dnode_t *node, void *context EXT2FS_ATTR((unused))) +-{ +- free(node); +-} +- +-dnode_t *dnode_create(void *data) +-{ +- dnode_t *new = malloc(sizeof *new); +- if (new) { +- new->data = data; +- new->parent = NULL; +- new->left = NULL; +- new->right = NULL; +- } +- return new; +-} +- +-dnode_t *dnode_init(dnode_t *dnode, void *data) +-{ +- dnode->data = data; +- dnode->parent = NULL; +- dnode->left = NULL; +- dnode->right = NULL; +- return dnode; +-} +- +-void dnode_destroy(dnode_t *dnode) +-{ +- assert (!dnode_is_in_a_dict(dnode)); +- free(dnode); +-} +- +-void *dnode_get(dnode_t *dnode) +-{ +- return dnode->data; +-} +- +-const void *dnode_getkey(dnode_t *dnode) +-{ +- return dnode->key; +-} +- +-#ifdef E2FSCK_NOTUSED +-void dnode_put(dnode_t *dnode, void *data) +-{ +- dnode->data = data; +-} +- +-int dnode_is_in_a_dict(dnode_t *dnode) +-{ +- return (dnode->parent && dnode->left && dnode->right); +-} +- +-void dict_process(dict_t *dict, void *context, dnode_process_t function) +-{ +- dnode_t *node = dict_first(dict), *next; +- +- while (node != NULL) { +- /* check for callback function deleting */ +- /* the next node from under us */ +- assert (dict_contains(dict, node)); +- next = dict_next(dict, node); +- function(dict, node, context); +- node = next; +- } +-} +- +-static void load_begin_internal(dict_load_t *load, dict_t *dict) +-{ +- load->dictptr = dict; +- load->nilnode.left = &load->nilnode; +- load->nilnode.right = &load->nilnode; +-} +- +-void dict_load_begin(dict_load_t *load, dict_t *dict) +-{ +- assert (dict_isempty(dict)); +- load_begin_internal(load, dict); +-} +- +-void dict_load_next(dict_load_t *load, dnode_t *newnode, const void *key) +-{ +- dict_t *dict = load->dictptr; +- dnode_t *nil = &load->nilnode; +- +- assert (!dnode_is_in_a_dict(newnode)); +- assert (dict->nodecount < dict->maxcount); +- +-#ifndef NDEBUG +- if (dict->nodecount > 0) { +- if (dict->dupes) +- assert (dict->compare(nil->left->key, key) <= 0); +- else +- assert (dict->compare(nil->left->key, key) < 0); +- } +-#endif +- +- newnode->key = key; +- nil->right->left = newnode; +- nil->right = newnode; +- newnode->left = nil; +- dict->nodecount++; +-} +- +-void dict_load_end(dict_load_t *load) +-{ +- dict_t *dict = load->dictptr; +- dnode_t *tree[DICT_DEPTH_MAX] = { 0 }; +- dnode_t *curr, *dictnil = dict_nil(dict), *loadnil = &load->nilnode, *next; +- dnode_t *complete = 0; +- dictcount_t fullcount = DICTCOUNT_T_MAX, nodecount = dict->nodecount; +- dictcount_t botrowcount; +- unsigned baselevel = 0, level = 0, i; +- +- assert (dnode_red == 0 && dnode_black == 1); +- +- while (fullcount >= nodecount && fullcount) +- fullcount >>= 1; +- +- botrowcount = nodecount - fullcount; +- +- for (curr = loadnil->left; curr != loadnil; curr = next) { +- next = curr->left; +- +- if (complete == NULL && botrowcount-- == 0) { +- assert (baselevel == 0); +- assert (level == 0); +- baselevel = level = 1; +- complete = tree[0]; +- +- if (complete != 0) { +- tree[0] = 0; +- complete->right = dictnil; +- while (tree[level] != 0) { +- tree[level]->right = complete; +- complete->parent = tree[level]; +- complete = tree[level]; +- tree[level++] = 0; +- } +- } +- } +- +- if (complete == NULL) { +- curr->left = dictnil; +- curr->right = dictnil; +- curr->color = level % 2; +- complete = curr; +- +- assert (level == baselevel); +- while (tree[level] != 0) { +- tree[level]->right = complete; +- complete->parent = tree[level]; +- complete = tree[level]; +- tree[level++] = 0; +- } +- } else { +- curr->left = complete; +- curr->color = (level + 1) % 2; +- complete->parent = curr; +- tree[level] = curr; +- complete = 0; +- level = baselevel; +- } +- } +- +- if (complete == NULL) +- complete = dictnil; +- +- for (i = 0; i < DICT_DEPTH_MAX; i++) { +- if (tree[i] != 0) { +- tree[i]->right = complete; +- complete->parent = tree[i]; +- complete = tree[i]; +- } +- } +- +- dictnil->color = dnode_black; +- dictnil->right = dictnil; +- complete->parent = dictnil; +- complete->color = dnode_black; +- dict_root(dict) = complete; +- +- assert (dict_verify(dict)); +-} +- +-void dict_merge(dict_t *dest, dict_t *source) +-{ +- dict_load_t load; +- dnode_t *leftnode = dict_first(dest), *rightnode = dict_first(source); +- +- assert (dict_similar(dest, source)); +- +- if (source == dest) +- return; +- +- dest->nodecount = 0; +- load_begin_internal(&load, dest); +- +- for (;;) { +- if (leftnode != NULL && rightnode != NULL) { +- if (dest->compare(leftnode->key, rightnode->key) < 0) +- goto copyleft; +- else +- goto copyright; +- } else if (leftnode != NULL) { +- goto copyleft; +- } else if (rightnode != NULL) { +- goto copyright; +- } else { +- assert (leftnode == NULL && rightnode == NULL); +- break; +- } +- +- copyleft: +- { +- dnode_t *next = dict_next(dest, leftnode); +-#ifndef NDEBUG +- leftnode->left = NULL; /* suppress assertion in dict_load_next */ +-#endif +- dict_load_next(&load, leftnode, leftnode->key); +- leftnode = next; +- continue; +- } +- +- copyright: +- { +- dnode_t *next = dict_next(source, rightnode); +-#ifndef NDEBUG +- rightnode->left = NULL; +-#endif +- dict_load_next(&load, rightnode, rightnode->key); +- rightnode = next; +- continue; +- } +- } +- +- dict_clear(source); +- dict_load_end(&load); +-} +-#endif /* E2FSCK_NOTUSED */ +- +-#ifdef KAZLIB_TEST_MAIN +- +-#include +-#include +-#include +-#include +- +-typedef char input_t[256]; +- +-static int tokenize(char *string, ...) +-{ +- char **tokptr; +- va_list arglist; +- int tokcount = 0; +- +- va_start(arglist, string); +- tokptr = va_arg(arglist, char **); +- while (tokptr) { +- while (*string && isspace((unsigned char) *string)) +- string++; +- if (!*string) +- break; +- *tokptr = string; +- while (*string && !isspace((unsigned char) *string)) +- string++; +- tokptr = va_arg(arglist, char **); +- tokcount++; +- if (!*string) +- break; +- *string++ = 0; +- } +- va_end(arglist); +- +- return tokcount; +-} +- +-static int comparef(const void *key1, const void *key2) +-{ +- return strcmp(key1, key2); +-} +- +-static char *dupstring(char *str) +-{ +- int sz = strlen(str) + 1; +- char *new = malloc(sz); +- if (new) +- memcpy(new, str, sz); +- return new; +-} +- +-static dnode_t *new_node(void *c) +-{ +- static dnode_t few[5]; +- static int count; +- +- if (count < 5) +- return few + count++; +- +- return NULL; +-} +- +-static void del_node(dnode_t *n, void *c) +-{ +-} +- +-static int prompt = 0; +- +-static void construct(dict_t *d) +-{ +- input_t in; +- int done = 0; +- dict_load_t dl; +- dnode_t *dn; +- char *tok1, *tok2, *val; +- const char *key; +- char *help = +- "p turn prompt on\n" +- "q finish construction\n" +- "a add new entry\n"; +- +- if (!dict_isempty(d)) +- puts("warning: dictionary not empty!"); +- +- dict_load_begin(&dl, d); +- +- while (!done) { +- if (prompt) +- putchar('>'); +- fflush(stdout); +- +- if (!fgets(in, sizeof(input_t), stdin)) +- break; +- +- switch (in[0]) { +- case '?': +- puts(help); +- break; +- case 'p': +- prompt = 1; +- break; +- case 'q': +- done = 1; +- break; +- case 'a': +- if (tokenize(in+1, &tok1, &tok2, (char **) 0) != 2) { +- puts("what?"); +- break; +- } +- key = dupstring(tok1); +- val = dupstring(tok2); +- dn = dnode_create(val); +- +- if (!key || !val || !dn) { +- puts("out of memory"); +- free((void *) key); +- free(val); +- if (dn) +- dnode_destroy(dn); +- } +- +- dict_load_next(&dl, dn, key); +- break; +- default: +- putchar('?'); +- putchar('\n'); +- break; +- } +- } +- +- dict_load_end(&dl); +-} +- +-int main(void) +-{ +- input_t in; +- dict_t darray[10]; +- dict_t *d = &darray[0]; +- dnode_t *dn; +- int i; +- char *tok1, *tok2, *val; +- const char *key; +- +- char *help = +- "a add value to dictionary\n" +- "d delete value from dictionary\n" +- "l lookup value in dictionary\n" +- "( lookup lower bound\n" +- ") lookup upper bound\n" +- "# switch to alternate dictionary (0-9)\n" +- "j merge two dictionaries\n" +- "f free the whole dictionary\n" +- "k allow duplicate keys\n" +- "c show number of entries\n" +- "t dump whole dictionary in sort order\n" +- "m make dictionary out of sorted items\n" +- "p turn prompt on\n" +- "s switch to non-functioning allocator\n" +- "q quit"; +- +- for (i = 0; i < sizeof darray / sizeof *darray; i++) +- dict_init(&darray[i], DICTCOUNT_T_MAX, comparef); +- +- for (;;) { +- if (prompt) +- putchar('>'); +- fflush(stdout); +- +- if (!fgets(in, sizeof(input_t), stdin)) +- break; +- +- switch(in[0]) { +- case '?': +- puts(help); +- break; +- case 'a': +- if (tokenize(in+1, &tok1, &tok2, (char **) 0) != 2) { +- puts("what?"); +- break; +- } +- key = dupstring(tok1); +- val = dupstring(tok2); +- +- if (!key || !val) { +- puts("out of memory"); +- free((void *) key); +- free(val); +- } +- +- if (!dict_alloc_insert(d, key, val)) { +- puts("dict_alloc_insert failed"); +- free((void *) key); +- free(val); +- break; +- } +- break; +- case 'd': +- if (tokenize(in+1, &tok1, (char **) 0) != 1) { +- puts("what?"); +- break; +- } +- dn = dict_lookup(d, tok1); +- if (!dn) { +- puts("dict_lookup failed"); +- break; +- } +- val = dnode_get(dn); +- key = dnode_getkey(dn); +- dict_delete_free(d, dn); +- +- free(val); +- free((void *) key); +- break; +- case 'f': +- dict_free(d); +- break; +- case 'l': +- case '(': +- case ')': +- if (tokenize(in+1, &tok1, (char **) 0) != 1) { +- puts("what?"); +- break; +- } +- dn = 0; +- switch (in[0]) { +- case 'l': +- dn = dict_lookup(d, tok1); +- break; +- case '(': +- dn = dict_lower_bound(d, tok1); +- break; +- case ')': +- dn = dict_upper_bound(d, tok1); +- break; +- } +- if (!dn) { +- puts("lookup failed"); +- break; +- } +- val = dnode_get(dn); +- puts(val); +- break; +- case 'm': +- construct(d); +- break; +- case 'k': +- dict_allow_dupes(d); +- break; +- case 'c': +- printf("%lu\n", (unsigned long) dict_count(d)); +- break; +- case 't': +- for (dn = dict_first(d); dn; dn = dict_next(d, dn)) { +- printf("%s\t%s\n", (char *) dnode_getkey(dn), +- (char *) dnode_get(dn)); +- } +- break; +- case 'q': +- exit(0); +- break; +- case '\0': +- break; +- case 'p': +- prompt = 1; +- break; +- case 's': +- dict_set_allocator(d, new_node, del_node, NULL); +- break; +- case '#': +- if (tokenize(in+1, &tok1, (char **) 0) != 1) { +- puts("what?"); +- break; +- } else { +- int dictnum = atoi(tok1); +- if (dictnum < 0 || dictnum > 9) { +- puts("invalid number"); +- break; +- } +- d = &darray[dictnum]; +- } +- break; +- case 'j': +- if (tokenize(in+1, &tok1, &tok2, (char **) 0) != 2) { +- puts("what?"); +- break; +- } else { +- int dict1 = atoi(tok1), dict2 = atoi(tok2); +- if (dict1 < 0 || dict1 > 9 || dict2 < 0 || dict2 > 9) { +- puts("invalid number"); +- break; +- } +- dict_merge(&darray[dict1], &darray[dict2]); +- } +- break; +- default: +- putchar('?'); +- putchar('\n'); +- break; +- } +- } +- +- return 0; +-} +- +-#endif +--- a/e2fsck/dict.h ++++ /dev/null +@@ -1,144 +0,0 @@ +-/* +- * Dictionary Abstract Data Type +- * Copyright (C) 1997 Kaz Kylheku +- * +- * Free Software License: +- * +- * All rights are reserved by the author, with the following exceptions: +- * Permission is granted to freely reproduce and distribute this software, +- * possibly in exchange for a fee, provided that this copyright notice appears +- * intact. Permission is also granted to adapt this software to produce +- * derivative works, as long as the modified versions carry this copyright +- * notice and additional notices stating that the work has been modified. +- * This source code may be translated into executable form and incorporated +- * into proprietary software; there is no requirement for such software to +- * contain a copyright notice related to this source. +- * +- * $Id: dict.h,v 1.22.2.6 2000/11/13 01:36:44 kaz Exp $ +- * $Name: kazlib_1_20 $ +- */ +- +-#ifndef DICT_H +-#define DICT_H +- +-#include +-#ifdef KAZLIB_SIDEEFFECT_DEBUG +-#include "sfx.h" +-#endif +- +-/* +- * Blurb for inclusion into C++ translation units +- */ +- +-#ifdef __cplusplus +-extern "C" { +-#endif +- +-typedef unsigned long dictcount_t; +-#define DICTCOUNT_T_MAX ULONG_MAX +- +-/* +- * The dictionary is implemented as a red-black tree +- */ +- +-typedef enum { dnode_red, dnode_black } dnode_color_t; +- +-typedef struct dnode_t { +-#if defined(DICT_IMPLEMENTATION) || !defined(KAZLIB_OPAQUE_DEBUG) +- struct dnode_t *dict_left; +- struct dnode_t *dict_right; +- struct dnode_t *dict_parent; +- dnode_color_t dict_color; +- const void *dict_key; +- void *dict_data; +-#else +- int dict_dummy; +-#endif +-} dnode_t; +- +-typedef int (*dict_comp_t)(const void *, const void *); +-typedef dnode_t *(*dnode_alloc_t)(void *); +-typedef void (*dnode_free_t)(dnode_t *, void *); +- +-typedef struct dict_t { +-#if defined(DICT_IMPLEMENTATION) || !defined(KAZLIB_OPAQUE_DEBUG) +- dnode_t dict_nilnode; +- dictcount_t dict_nodecount; +- dictcount_t dict_maxcount; +- dict_comp_t dict_compare; +- dnode_alloc_t dict_allocnode; +- dnode_free_t dict_freenode; +- void *dict_context; +- int dict_dupes; +-#else +- int dict_dummmy; +-#endif +-} dict_t; +- +-typedef void (*dnode_process_t)(dict_t *, dnode_t *, void *); +- +-typedef struct dict_load_t { +-#if defined(DICT_IMPLEMENTATION) || !defined(KAZLIB_OPAQUE_DEBUG) +- dict_t *dict_dictptr; +- dnode_t dict_nilnode; +-#else +- int dict_dummmy; +-#endif +-} dict_load_t; +- +-extern dict_t *dict_create(dictcount_t, dict_comp_t); +-extern void dict_set_allocator(dict_t *, dnode_alloc_t, dnode_free_t, void *); +-extern void dict_destroy(dict_t *); +-extern void dict_free_nodes(dict_t *); +-extern void dict_free(dict_t *); +-extern dict_t *dict_init(dict_t *, dictcount_t, dict_comp_t); +-extern void dict_init_like(dict_t *, const dict_t *); +-extern int dict_verify(dict_t *); +-extern int dict_similar(const dict_t *, const dict_t *); +-extern dnode_t *dict_lookup(dict_t *, const void *); +-extern dnode_t *dict_lower_bound(dict_t *, const void *); +-extern dnode_t *dict_upper_bound(dict_t *, const void *); +-extern void dict_insert(dict_t *, dnode_t *, const void *); +-extern dnode_t *dict_delete(dict_t *, dnode_t *); +-extern int dict_alloc_insert(dict_t *, const void *, void *); +-extern void dict_delete_free(dict_t *, dnode_t *); +-extern dnode_t *dict_first(dict_t *); +-extern dnode_t *dict_last(dict_t *); +-extern dnode_t *dict_next(dict_t *, dnode_t *); +-extern dnode_t *dict_prev(dict_t *, dnode_t *); +-extern dictcount_t dict_count(dict_t *); +-extern int dict_isempty(dict_t *); +-extern int dict_isfull(dict_t *); +-extern int dict_contains(dict_t *, dnode_t *); +-extern void dict_allow_dupes(dict_t *); +-extern int dnode_is_in_a_dict(dnode_t *); +-extern dnode_t *dnode_create(void *); +-extern dnode_t *dnode_init(dnode_t *, void *); +-extern void dnode_destroy(dnode_t *); +-extern void *dnode_get(dnode_t *); +-extern const void *dnode_getkey(dnode_t *); +-extern void dnode_put(dnode_t *, void *); +-extern void dict_process(dict_t *, void *, dnode_process_t); +-extern void dict_load_begin(dict_load_t *, dict_t *); +-extern void dict_load_next(dict_load_t *, dnode_t *, const void *); +-extern void dict_load_end(dict_load_t *); +-extern void dict_merge(dict_t *, dict_t *); +- +-#if defined(DICT_IMPLEMENTATION) || !defined(KAZLIB_OPAQUE_DEBUG) +-#ifdef KAZLIB_SIDEEFFECT_DEBUG +-#define dict_isfull(D) (SFX_CHECK(D)->dict_nodecount == (D)->dict_maxcount) +-#else +-#define dict_isfull(D) ((D)->dict_nodecount == (D)->dict_maxcount) +-#endif +-#define dict_count(D) ((D)->dict_nodecount) +-#define dict_isempty(D) ((D)->dict_nodecount == 0) +-#define dnode_get(N) ((N)->dict_data) +-#define dnode_getkey(N) ((N)->dict_key) +-#define dnode_put(N, X) ((N)->dict_data = (X)) +-#endif +- +-#ifdef __cplusplus +-} +-#endif +- +-#endif +--- a/e2fsck/dirinfo.c ++++ b/e2fsck/dirinfo.c +@@ -13,6 +13,7 @@ + #include + #include "uuid/uuid.h" + ++#include "ext2fs/ext2fs.h" + #include + + struct dir_info_db { +--- a/e2fsck/dx_dirinfo.c ++++ b/e2fsck/dx_dirinfo.c +@@ -7,7 +7,6 @@ + + #include "config.h" + #include "e2fsck.h" +-#ifdef ENABLE_HTREE + + /* + * This subroutine is called during pass1 to create a directory info +@@ -151,5 +150,3 @@ + + return(ctx->dx_dir_info + (*control)++); + } +- +-#endif /* ENABLE_HTREE */ +--- a/e2fsck/e2fsck.8.in ++++ b/e2fsck/e2fsck.8.in +@@ -68,6 +68,19 @@ + asks whether or not you should check a filesystem which is mounted, + the only correct answer is ``no''. Only experts who really know what + they are doing should consider answering this question in any other way. ++.PP ++If ++.B e2fsck ++is run in interactive mode (meaning that none of ++.BR \-y , ++.BR \-n , ++or ++.BR \-p ++are specified), the program will ask the user to fix each problem found in the ++filesystem. A response of 'y' will fix the error; 'n' will leave the error ++unfixed; and 'a' will fix the problem and all subsequent problems; pressing ++Enter will proceed with the default response, which is printed before the ++question mark. Pressing Control-C terminates e2fsck immediately. + .SH OPTIONS + .TP + .B \-a +@@ -207,6 +220,21 @@ + .BI nodiscard + Do not attempt to discard free blocks and unused inode blocks. This option is + exactly the opposite of discard option. This is set as default. ++.TP ++.BI readahead_kb ++Use this many KiB of memory to pre-fetch metadata in the hopes of reducing ++e2fsck runtime. By default, this is set to the size of two block groups' inode ++tables (typically 4MiB on a regular ext4 filesystem); if this amount is more ++than 1/50th of total physical memory, readahead is disabled. Set this to zero ++to disable readahead entirely. ++.TP ++.BI bmap2extent ++Convert block-mapped files to extent-mapped files. ++.TP ++.BI fixes_only ++Only fix damaged metadata; do not optimize htree directories or compress ++extent trees. This option is incompatible with the -D and -E bmap2extent ++options. + .RE + .TP + .B \-f +@@ -311,6 +339,16 @@ + or + .B \-p + options. ++.TP ++.BI \-z " undo_file" ++Before overwriting a file system block, write the old contents of the block to ++an undo file. This undo file can be used with e2undo(8) to restore the old ++contents of the file system should something go wrong. If the empty string is ++passed as the undo_file argument, the undo file will be written to a file named ++e2fsck-\fIdevice\fR.e2undo in the directory specified via the ++\fIE2FSPROGS_UNDO_DIR\fR environment variable. ++ ++WARNING: The undo file cannot be used to recover from a power or system crash. + .SH EXIT CODE + The exit code returned by + .B e2fsck +--- a/e2fsck/e2fsck.c ++++ b/e2fsck/e2fsck.c +@@ -89,9 +89,7 @@ + ctx->fs->dblist = 0; + } + e2fsck_free_dir_info(ctx); +-#ifdef ENABLE_HTREE + e2fsck_free_dx_dir_info(ctx); +-#endif + if (ctx->refcount) { + ea_refcount_free(ctx->refcount); + ctx->refcount = 0; +@@ -108,6 +106,10 @@ + 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; +@@ -140,6 +142,10 @@ + ext2fs_free_mem(&ctx->invalid_inode_table_flag); + ctx->invalid_inode_table_flag = 0; + } ++ if (ctx->encrypted_dirs) { ++ ext2fs_u32_list_free(ctx->encrypted_dirs); ++ ctx->encrypted_dirs = 0; ++ } + + /* Clear statistic counters */ + ctx->fs_directory_count = 0; +@@ -200,8 +206,8 @@ + typedef void (*pass_t)(e2fsck_t ctx); + + static pass_t e2fsck_passes[] = { +- e2fsck_pass1, e2fsck_pass2, e2fsck_pass3, e2fsck_pass4, +- e2fsck_pass5, 0 }; ++ e2fsck_pass1, e2fsck_pass1e, e2fsck_pass2, e2fsck_pass3, ++ e2fsck_pass4, e2fsck_pass5, 0 }; + + #define E2F_FLAG_RUN_RETURN (E2F_FLAG_SIGNAL_MASK|E2F_FLAG_RESTART) + +--- a/e2fsck/e2fsck.conf.5.in ++++ b/e2fsck/e2fsck.conf.5.in +@@ -205,6 +205,21 @@ + (i.e., connected to a serial port) and so a large amount of output could + end up delaying the boot process for a long time (potentially hours). + .TP ++.I readahead_mem_pct ++Use this percentage of memory to try to read in metadata blocks ahead of the ++main e2fsck thread. This should reduce run times, depending on the speed of ++the underlying storage and the amount of free memory. There is no default, but ++see ++.B readahead_mem_pct ++for more details. ++.TP ++.I readahead_kb ++Use this amount of memory to read in metadata blocks ahead of the main checking ++thread. Setting this value to zero disables readahead entirely. By default, ++this is set the size of two block groups' inode tables (typically 4MiB on a ++regular ext4 filesystem); if this amount is more than 1/50th of total physical ++memory, readahead is disabled. ++.TP + .I report_features + If this boolean relation is true, e2fsck will print the file system + features as part of its verbose reporting (i.e., if the +--- a/e2fsck/e2fsck.h ++++ b/e2fsck/e2fsck.h +@@ -36,8 +36,8 @@ + #include "blkid/blkid.h" + #endif + +-#include "profile.h" +-#include "prof_err.h" ++#include "support/profile.h" ++#include "support/prof_err.h" + + #ifdef ENABLE_NLS + #include +@@ -67,7 +67,7 @@ + #define E2FSCK_ATTR(x) + #endif + +-#include "quota/quotaio.h" ++#include "support/quotaio.h" + + /* + * Exit codes used by fsck-type programs +@@ -167,6 +167,8 @@ + #define E2F_OPT_FRAGCHECK 0x0800 + #define E2F_OPT_JOURNAL_ONLY 0x1000 /* only replay the journal */ + #define E2F_OPT_DISCARD 0x2000 ++#define E2F_OPT_CONVERT_BMAP 0x4000 /* convert blockmap to extent */ ++#define E2F_OPT_FIXES_ONLY 0x8000 /* skip all optimizations */ + + /* + * E2fsck flags +@@ -190,6 +192,7 @@ + #define E2F_FLAG_EXITING 0x1000 /* E2fsck exiting due to errors */ + #define E2F_FLAG_TIME_INSANE 0x2000 /* Time is insane */ + #define E2F_FLAG_PROBLEMS_FIXED 0x4000 /* At least one problem was fixed */ ++#define E2F_FLAG_ALLOC_OK 0x8000 /* Can we allocate blocks? */ + + #define E2F_RESET_FLAGS (E2F_FLAG_TIME_INSANE | E2F_FLAG_PROBLEMS_FIXED) + +@@ -368,6 +371,7 @@ + int ext_attr_ver; + profile_t profile; + int blocks_per_page; ++ ext2_u32_list encrypted_dirs; + + /* Reserve blocks for root and l+f re-creation */ + blk64_t root_repair_block, lnf_repair_block; +@@ -377,10 +381,34 @@ + * e2fsck functions themselves. + */ + void *priv_data; ++ ext2fs_block_bitmap block_metadata_map; /* Metadata blocks */ ++ ++ /* How much are we allowed to readahead? */ ++ unsigned long long readahead_kb; ++ ++ /* ++ * Inodes to rebuild extent trees ++ */ ++ ext2fs_inode_bitmap inodes_to_rebuild; ++ ++ /* Undo file */ ++ char *undo_file; ++}; ++ ++/* Data structures to evaluate whether an extent tree needs rebuilding. */ ++struct extent_tree_level { ++ unsigned int num_extents; ++ unsigned int max_extents; ++}; ++ ++struct extent_tree_info { ++ ext2_ino_t ino; ++ int force_rebuild; ++ struct extent_tree_level ext_info[MAX_EXTENT_DEPTH_COUNT]; + }; + + /* Used by the region allocation code */ +-typedef __u32 region_addr_t; ++typedef __u64 region_addr_t; + typedef struct region_struct *region_t; + + #ifndef HAVE_STRNLEN +@@ -410,9 +438,6 @@ + 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); +@@ -455,6 +480,19 @@ + extern const char *ehandler_operation(const char *op); + extern void ehandler_init(io_channel channel); + ++/* extents.c */ ++struct problem_context; ++errcode_t e2fsck_rebuild_extents_later(e2fsck_t ctx, ext2_ino_t ino); ++int e2fsck_ino_will_be_rebuilt(e2fsck_t ctx, ext2_ino_t ino); ++void e2fsck_pass1e(e2fsck_t ctx); ++errcode_t e2fsck_check_rebuild_extents(e2fsck_t ctx, ext2_ino_t ino, ++ struct ext2_inode *inode, ++ struct problem_context *pctx); ++errcode_t e2fsck_should_rebuild_extents(e2fsck_t ctx, ++ struct problem_context *pctx, ++ struct extent_tree_info *eti, ++ struct ext2_extent_info *info); ++ + /* journal.c */ + extern errcode_t e2fsck_check_ext3_journal(e2fsck_t ctx); + extern errcode_t e2fsck_run_ext3_journal(e2fsck_t ctx); +@@ -483,6 +521,10 @@ + /* pass2.c */ + extern int e2fsck_process_bad_inode(e2fsck_t ctx, ext2_ino_t dir, + ext2_ino_t ino, char *buf); ++extern int get_filename_hash(ext2_filsys fs, int encrypted, int version, ++ const char *name, int len, ++ ext2_dirhash_t *ret_hash, ++ ext2_dirhash_t *ret_minor_hash); + + /* pass3.c */ + extern int e2fsck_reconnect_file(e2fsck_t ctx, ext2_ino_t inode); +@@ -492,6 +534,23 @@ + extern errcode_t e2fsck_adjust_inode_count(e2fsck_t ctx, ext2_ino_t ino, + int adj); + ++/* readahead.c */ ++#define E2FSCK_READA_SUPER (0x01) ++#define E2FSCK_READA_GDT (0x02) ++#define E2FSCK_READA_BBITMAP (0x04) ++#define E2FSCK_READA_IBITMAP (0x08) ++#define E2FSCK_READA_ITABLE (0x10) ++#define E2FSCK_READA_ALL_FLAGS (0x1F) ++errcode_t e2fsck_readahead(ext2_filsys fs, int flags, dgrp_t start, ++ dgrp_t ngroups); ++#define E2FSCK_RA_DBLIST_IGNORE_BLOCKCNT (0x01) ++#define E2FSCK_RA_DBLIST_ALL_FLAGS (0x01) ++errcode_t e2fsck_readahead_dblist(ext2_filsys fs, int flags, ++ ext2_dblist dblist, ++ unsigned long long start, ++ unsigned long long count); ++int e2fsck_can_readahead(ext2_filsys fs); ++unsigned long long e2fsck_guess_readahead(ext2_filsys fs); + + /* region.c */ + extern region_t region_create(region_addr_t min, region_addr_t max); +@@ -499,7 +558,10 @@ + extern int region_allocate(region_t region, region_addr_t start, int n); + + /* rehash.c */ +-errcode_t e2fsck_rehash_dir(e2fsck_t ctx, ext2_ino_t ino); ++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, ++ struct problem_context *pctx); + void e2fsck_rehash_directories(e2fsck_t ctx); + + /* sigcatcher.c */ +@@ -524,8 +586,6 @@ + extern void e2fsck_write_bitmaps(e2fsck_t ctx); + extern void preenhalt(e2fsck_t ctx); + extern char *string_copy(e2fsck_t ctx, const char *str, int len); +-extern errcode_t e2fsck_zero_blocks(ext2_filsys fs, blk_t blk, int num, +- blk_t *ret_blk, int *ret_count); + extern int fs_proc_check(const char *fs_name); + extern int check_for_modules(const char *fs_name); + #ifdef RESOURCE_TRACK +@@ -579,6 +639,7 @@ + int default_type, + const char *profile_name, + ext2fs_block_bitmap *ret); ++unsigned long long get_memory_size(void); + + /* unix.c */ + extern void e2fsck_clear_progbar(e2fsck_t ctx); +--- a/e2fsck/ehandler.c ++++ b/e2fsck/ehandler.c +@@ -58,6 +58,11 @@ + printf(_("Error reading block %lu (%s). "), block, + error_message(error)); + preenhalt(ctx); ++ ++ /* Don't rewrite a block past the end of the FS. */ ++ if (block >= ext2fs_blocks_count(fs->super)) ++ return 0; ++ + if (ask(ctx, _("Ignore error"), 1)) { + if (ask(ctx, _("Force rewrite"), 1)) + io_channel_write_blk64(channel, block, count, data); +--- /dev/null ++++ b/e2fsck/extents.c +@@ -0,0 +1,543 @@ ++/* ++ * extents.c --- rebuild extent tree ++ * ++ * Copyright (C) 2014 Oracle. ++ * ++ * %Begin-Header% ++ * This file may be redistributed under the terms of the GNU Public ++ * License, version 2. ++ * %End-Header% ++ */ ++ ++#include "config.h" ++#include ++#include ++#include ++#include "e2fsck.h" ++#include "problem.h" ++ ++#undef DEBUG ++#undef DEBUG_SUMMARY ++#undef DEBUG_FREE ++ ++#define NUM_EXTENTS 341 /* about one ETB' worth of extents */ ++ ++static errcode_t e2fsck_rebuild_extents(e2fsck_t ctx, ext2_ino_t ino); ++ ++/* Schedule an inode to have its extent tree rebuilt during pass 1E. */ ++errcode_t e2fsck_rebuild_extents_later(e2fsck_t ctx, ext2_ino_t ino) ++{ ++ errcode_t retval = 0; ++ ++ if (!EXT2_HAS_INCOMPAT_FEATURE(ctx->fs->super, ++ EXT3_FEATURE_INCOMPAT_EXTENTS) || ++ (ctx->options & E2F_OPT_NO) || ++ (ino != EXT2_ROOT_INO && ino < ctx->fs->super->s_first_ino)) ++ return 0; ++ ++ if (ctx->flags & E2F_FLAG_ALLOC_OK) ++ return e2fsck_rebuild_extents(ctx, ino); ++ ++ if (!ctx->inodes_to_rebuild) ++ retval = e2fsck_allocate_inode_bitmap(ctx->fs, ++ _("extent rebuild inode map"), ++ EXT2FS_BMAP64_RBTREE, ++ "inodes_to_rebuild", ++ &ctx->inodes_to_rebuild); ++ if (retval) ++ return retval; ++ ++ ext2fs_mark_inode_bitmap2(ctx->inodes_to_rebuild, ino); ++ return 0; ++} ++ ++/* Ask if an inode will have its extents rebuilt during pass 1E. */ ++int e2fsck_ino_will_be_rebuilt(e2fsck_t ctx, ext2_ino_t ino) ++{ ++ if (!ctx->inodes_to_rebuild) ++ return 0; ++ return ext2fs_test_inode_bitmap2(ctx->inodes_to_rebuild, ino); ++} ++ ++struct extent_list { ++ blk64_t blocks_freed; ++ struct ext2fs_extent *extents; ++ unsigned int count; ++ unsigned int size; ++ unsigned int ext_read; ++ errcode_t retval; ++ ext2_ino_t ino; ++}; ++ ++static errcode_t load_extents(e2fsck_t ctx, struct extent_list *list) ++{ ++ ext2_filsys fs = ctx->fs; ++ ext2_extent_handle_t handle; ++ struct ext2fs_extent extent; ++ errcode_t retval; ++ ++ retval = ext2fs_extent_open(fs, list->ino, &handle); ++ if (retval) ++ return retval; ++ ++ retval = ext2fs_extent_get(handle, EXT2_EXTENT_ROOT, &extent); ++ if (retval) ++ goto out; ++ ++ do { ++ if (extent.e_flags & EXT2_EXTENT_FLAGS_SECOND_VISIT) ++ goto next; ++ ++ /* Internal node; free it and we'll re-allocate it later */ ++ if (!(extent.e_flags & EXT2_EXTENT_FLAGS_LEAF)) { ++#if defined(DEBUG) || defined(DEBUG_FREE) ++ printf("ino=%d free=%llu bf=%llu\n", list->ino, ++ extent.e_pblk, list->blocks_freed + 1); ++#endif ++ list->blocks_freed++; ++ ext2fs_block_alloc_stats2(fs, extent.e_pblk, -1); ++ goto next; ++ } ++ ++ list->ext_read++; ++ /* Can we attach it to the previous extent? */ ++ if (list->count) { ++ struct ext2fs_extent *last = list->extents + ++ list->count - 1; ++ blk64_t end = last->e_len + extent.e_len; ++ ++ if (last->e_pblk + last->e_len == extent.e_pblk && ++ last->e_lblk + last->e_len == extent.e_lblk && ++ (last->e_flags & EXT2_EXTENT_FLAGS_UNINIT) == ++ (extent.e_flags & EXT2_EXTENT_FLAGS_UNINIT) && ++ end < (1ULL << 32)) { ++ last->e_len += extent.e_len; ++#ifdef DEBUG ++ printf("R: ino=%d len=%u\n", list->ino, ++ last->e_len); ++#endif ++ goto next; ++ } ++ } ++ ++ /* Do we need to expand? */ ++ if (list->count == list->size) { ++ unsigned int new_size = (list->size + NUM_EXTENTS) * ++ sizeof(struct ext2fs_extent); ++ retval = ext2fs_resize_mem(0, new_size, &list->extents); ++ if (retval) ++ goto out; ++ list->size += NUM_EXTENTS; ++ } ++ ++ /* Add a new extent */ ++ memcpy(list->extents + list->count, &extent, sizeof(extent)); ++#ifdef DEBUG ++ printf("R: ino=%d pblk=%llu lblk=%llu len=%u\n", list->ino, ++ extent.e_pblk, extent.e_lblk, extent.e_len); ++#endif ++ list->count++; ++next: ++ retval = ext2fs_extent_get(handle, EXT2_EXTENT_NEXT, &extent); ++ } while (retval == 0); ++ ++out: ++ /* Ok if we run off the end */ ++ if (retval == EXT2_ET_EXTENT_NO_NEXT) ++ retval = 0; ++ ext2fs_extent_free(handle); ++ return retval; ++} ++ ++static int find_blocks(ext2_filsys fs, blk64_t *blocknr, e2_blkcnt_t blockcnt, ++ blk64_t ref_blk EXT2FS_ATTR((unused)), ++ int ref_offset EXT2FS_ATTR((unused)), void *priv_data) ++{ ++ struct extent_list *list = priv_data; ++ ++ /* Internal node? */ ++ if (blockcnt < 0) { ++#if defined(DEBUG) || defined(DEBUG_FREE) ++ printf("ino=%d free=%llu bf=%llu\n", list->ino, *blocknr, ++ list->blocks_freed + 1); ++#endif ++ list->blocks_freed++; ++ ext2fs_block_alloc_stats2(fs, *blocknr, -1); ++ return 0; ++ } ++ ++ /* Can we attach it to the previous extent? */ ++ if (list->count) { ++ struct ext2fs_extent *last = list->extents + ++ list->count - 1; ++ blk64_t end = last->e_len + 1; ++ ++ if (last->e_pblk + last->e_len == *blocknr && ++ end < (1ULL << 32)) { ++ last->e_len++; ++#ifdef DEBUG ++ printf("R: ino=%d len=%u\n", list->ino, last->e_len); ++#endif ++ return 0; ++ } ++ } ++ ++ /* Do we need to expand? */ ++ if (list->count == list->size) { ++ unsigned int new_size = (list->size + NUM_EXTENTS) * ++ sizeof(struct ext2fs_extent); ++ list->retval = ext2fs_resize_mem(0, new_size, &list->extents); ++ if (list->retval) ++ return BLOCK_ABORT; ++ list->size += NUM_EXTENTS; ++ } ++ ++ /* Add a new extent */ ++ list->extents[list->count].e_pblk = *blocknr; ++ list->extents[list->count].e_lblk = blockcnt; ++ list->extents[list->count].e_len = 1; ++ list->extents[list->count].e_flags = 0; ++#ifdef DEBUG ++ printf("R: ino=%d pblk=%llu lblk=%llu len=%u\n", list->ino, *blocknr, ++ blockcnt, 1); ++#endif ++ list->count++; ++ ++ return 0; ++} ++ ++static errcode_t rebuild_extent_tree(e2fsck_t ctx, struct extent_list *list, ++ ext2_ino_t ino) ++{ ++ struct ext2_inode inode; ++ errcode_t retval; ++ ext2_extent_handle_t handle; ++ unsigned int i, ext_written; ++ struct ext2fs_extent *ex, extent; ++ ++ list->count = 0; ++ list->blocks_freed = 0; ++ list->ino = ino; ++ list->ext_read = 0; ++ e2fsck_read_inode(ctx, ino, &inode, "rebuild_extents"); ++ ++ /* Skip deleted inodes and inline data files */ ++ if (inode.i_links_count == 0 || ++ inode.i_flags & EXT4_INLINE_DATA_FL) ++ return 0; ++ ++ /* Collect lblk->pblk mappings */ ++ if (inode.i_flags & EXT4_EXTENTS_FL) { ++ retval = load_extents(ctx, list); ++ if (retval) ++ goto err; ++ goto extents_loaded; ++ } ++ ++ retval = ext2fs_block_iterate3(ctx->fs, ino, BLOCK_FLAG_READ_ONLY, 0, ++ find_blocks, list); ++ if (retval) ++ goto err; ++ if (list->retval) { ++ retval = list->retval; ++ goto err; ++ } ++ ++extents_loaded: ++ /* Reset extent tree */ ++ inode.i_flags &= ~EXT4_EXTENTS_FL; ++ memset(inode.i_block, 0, sizeof(inode.i_block)); ++ ++ /* Make a note of freed blocks */ ++ retval = ext2fs_iblk_sub_blocks(ctx->fs, &inode, list->blocks_freed); ++ if (retval) ++ goto err; ++ ++ /* Now stuff extents into the file */ ++ retval = ext2fs_extent_open2(ctx->fs, ino, &inode, &handle); ++ if (retval) ++ goto err; ++ ++ ext_written = 0; ++ for (i = 0, ex = list->extents; i < list->count; i++, ex++) { ++ memcpy(&extent, ex, sizeof(struct ext2fs_extent)); ++ extent.e_flags &= EXT2_EXTENT_FLAGS_UNINIT; ++ if (extent.e_flags & EXT2_EXTENT_FLAGS_UNINIT) { ++ if (extent.e_len > EXT_UNINIT_MAX_LEN) { ++ extent.e_len = EXT_UNINIT_MAX_LEN; ++ ex->e_pblk += EXT_UNINIT_MAX_LEN; ++ ex->e_lblk += EXT_UNINIT_MAX_LEN; ++ ex->e_len -= EXT_UNINIT_MAX_LEN; ++ ex--; ++ i--; ++ } ++ } else { ++ if (extent.e_len > EXT_INIT_MAX_LEN) { ++ extent.e_len = EXT_INIT_MAX_LEN; ++ ex->e_pblk += EXT_INIT_MAX_LEN; ++ ex->e_lblk += EXT_INIT_MAX_LEN; ++ ex->e_len -= EXT_INIT_MAX_LEN; ++ ex--; ++ i--; ++ } ++ } ++ ++#ifdef DEBUG ++ printf("W: ino=%d pblk=%llu lblk=%llu len=%u\n", ino, ++ extent.e_pblk, extent.e_lblk, extent.e_len); ++#endif ++ retval = ext2fs_extent_insert(handle, EXT2_EXTENT_INSERT_AFTER, ++ &extent); ++ if (retval) ++ goto err2; ++ retval = ext2fs_extent_fix_parents(handle); ++ if (retval) ++ goto err2; ++ ext_written++; ++ } ++ ++#if defined(DEBUG) || defined(DEBUG_SUMMARY) ++ printf("rebuild: ino=%d extents=%d->%d\n", ino, list->ext_read, ++ ext_written); ++#endif ++ e2fsck_write_inode(ctx, ino, &inode, "rebuild_extents"); ++ ++err2: ++ ext2fs_extent_free(handle); ++err: ++ return retval; ++} ++ ++/* Rebuild the extents immediately */ ++static errcode_t e2fsck_rebuild_extents(e2fsck_t ctx, ext2_ino_t ino) ++{ ++ struct extent_list list; ++ errcode_t err; ++ ++ if (!EXT2_HAS_INCOMPAT_FEATURE(ctx->fs->super, ++ EXT3_FEATURE_INCOMPAT_EXTENTS) || ++ (ctx->options & E2F_OPT_NO) || ++ (ino != EXT2_ROOT_INO && ino < ctx->fs->super->s_first_ino)) ++ return 0; ++ ++ e2fsck_read_bitmaps(ctx); ++ memset(&list, 0, sizeof(list)); ++ err = ext2fs_get_mem(sizeof(struct ext2fs_extent) * NUM_EXTENTS, ++ &list.extents); ++ if (err) ++ return err; ++ list.size = NUM_EXTENTS; ++ err = rebuild_extent_tree(ctx, &list, ino); ++ ext2fs_free_mem(&list.extents); ++ ++ return err; ++} ++ ++static void rebuild_extents(e2fsck_t ctx, const char *pass_name, int pr_header) ++{ ++ struct problem_context pctx; ++#ifdef RESOURCE_TRACK ++ struct resource_track rtrack; ++#endif ++ struct extent_list list; ++ int first = 1; ++ ext2_ino_t ino = 0; ++ errcode_t retval; ++ ++ if (!EXT2_HAS_INCOMPAT_FEATURE(ctx->fs->super, ++ EXT3_FEATURE_INCOMPAT_EXTENTS) || ++ !ext2fs_test_valid(ctx->fs) || ++ ctx->invalid_bitmaps) { ++ if (ctx->inodes_to_rebuild) ++ ext2fs_free_inode_bitmap(ctx->inodes_to_rebuild); ++ ctx->inodes_to_rebuild = NULL; ++ } ++ ++ if (ctx->inodes_to_rebuild == NULL) ++ return; ++ ++ init_resource_track(&rtrack, ctx->fs->io); ++ clear_problem_context(&pctx); ++ e2fsck_read_bitmaps(ctx); ++ ++ memset(&list, 0, sizeof(list)); ++ retval = ext2fs_get_mem(sizeof(struct ext2fs_extent) * NUM_EXTENTS, ++ &list.extents); ++ list.size = NUM_EXTENTS; ++ while (1) { ++ retval = ext2fs_find_first_set_inode_bitmap2( ++ ctx->inodes_to_rebuild, ino + 1, ++ ctx->fs->super->s_inodes_count, &ino); ++ if (retval) ++ break; ++ pctx.ino = ino; ++ if (first) { ++ fix_problem(ctx, pr_header, &pctx); ++ first = 0; ++ } ++ pctx.errcode = rebuild_extent_tree(ctx, &list, ino); ++ if (pctx.errcode) { ++ end_problem_latch(ctx, PR_LATCH_OPTIMIZE_EXT); ++ fix_problem(ctx, PR_1E_OPTIMIZE_EXT_ERR, &pctx); ++ } ++ if (ctx->progress && !ctx->progress_fd) ++ e2fsck_simple_progress(ctx, "Rebuilding extents", ++ 100.0 * (float) ino / ++ (float) ctx->fs->super->s_inodes_count, ++ ino); ++ } ++ end_problem_latch(ctx, PR_LATCH_OPTIMIZE_EXT); ++ ++ ext2fs_free_inode_bitmap(ctx->inodes_to_rebuild); ++ ctx->inodes_to_rebuild = NULL; ++ ext2fs_free_mem(&list.extents); ++ ++ print_resource_track(ctx, pass_name, &rtrack, ctx->fs->io); ++} ++ ++/* Scan a file to see if we should rebuild its extent tree */ ++errcode_t e2fsck_check_rebuild_extents(e2fsck_t ctx, ext2_ino_t ino, ++ struct ext2_inode *inode, ++ struct problem_context *pctx) ++{ ++ struct extent_tree_info eti; ++ struct ext2_extent_info info, top_info; ++ struct ext2fs_extent extent; ++ ext2_extent_handle_t ehandle; ++ ext2_filsys fs = ctx->fs; ++ errcode_t retval; ++ ++ /* block map file and we want extent conversion */ ++ if (!(inode->i_flags & EXT4_EXTENTS_FL) && ++ !(inode->i_flags & EXT4_INLINE_DATA_FL) && ++ (ctx->options & E2F_OPT_CONVERT_BMAP)) { ++ return e2fsck_rebuild_extents_later(ctx, ino); ++ } ++ ++ if (!(inode->i_flags & EXT4_EXTENTS_FL)) ++ return 0; ++ memset(&eti, 0, sizeof(eti)); ++ eti.ino = ino; ++ ++ /* Otherwise, go scan the extent tree... */ ++ retval = ext2fs_extent_open2(fs, ino, inode, &ehandle); ++ if (retval) ++ return 0; ++ ++ retval = ext2fs_extent_get_info(ehandle, &top_info); ++ if (retval) ++ goto out; ++ ++ /* Check maximum extent depth */ ++ pctx->ino = ino; ++ pctx->blk = top_info.max_depth; ++ pctx->blk2 = ext2fs_max_extent_depth(ehandle); ++ if (pctx->blk2 < pctx->blk && ++ fix_problem(ctx, PR_1_EXTENT_BAD_MAX_DEPTH, pctx)) ++ eti.force_rebuild = 1; ++ ++ /* Can we collect extent tree level stats? */ ++ pctx->blk = MAX_EXTENT_DEPTH_COUNT; ++ if (pctx->blk2 > pctx->blk) ++ fix_problem(ctx, PR_1E_MAX_EXTENT_TREE_DEPTH, pctx); ++ ++ /* We need to fix tree depth problems, but the scan isn't a fix. */ ++ if (ctx->options & E2F_OPT_FIXES_ONLY) ++ goto out; ++ ++ retval = ext2fs_extent_get(ehandle, EXT2_EXTENT_ROOT, &extent); ++ if (retval) ++ goto out; ++ ++ do { ++ retval = ext2fs_extent_get_info(ehandle, &info); ++ if (retval) ++ break; ++ ++ /* ++ * If this is the first extent in an extent block that we ++ * haven't visited, collect stats on the block. ++ */ ++ if (info.curr_entry == 1 && ++ !(extent.e_flags & EXT2_EXTENT_FLAGS_SECOND_VISIT) && ++ !eti.force_rebuild) { ++ struct extent_tree_level *etl; ++ ++ etl = eti.ext_info + info.curr_level; ++ etl->num_extents += info.num_entries; ++ etl->max_extents += info.max_entries; ++ /* ++ * Implementation wart: Splitting extent blocks when ++ * appending will leave the old block with one free ++ * entry. Therefore unless the node is totally full, ++ * pretend that a non-root extent block can hold one ++ * fewer entry than it actually does, so that we don't ++ * repeatedly rebuild the extent tree. ++ */ ++ if (info.curr_level && ++ info.num_entries < info.max_entries) ++ etl->max_extents--; ++ } ++ ++ /* Skip to the end of a block of leaf nodes */ ++ if (extent.e_flags & EXT2_EXTENT_FLAGS_LEAF) { ++ retval = ext2fs_extent_get(ehandle, ++ EXT2_EXTENT_LAST_SIB, ++ &extent); ++ if (retval) ++ break; ++ } ++ ++ retval = ext2fs_extent_get(ehandle, EXT2_EXTENT_NEXT, &extent); ++ } while (retval == 0); ++out: ++ ext2fs_extent_free(ehandle); ++ return e2fsck_should_rebuild_extents(ctx, pctx, &eti, &top_info); ++} ++ ++/* Having scanned a file's extent tree, decide if we should rebuild it */ ++errcode_t e2fsck_should_rebuild_extents(e2fsck_t ctx, ++ struct problem_context *pctx, ++ struct extent_tree_info *eti, ++ struct ext2_extent_info *info) ++{ ++ struct extent_tree_level *ei; ++ int i, j, op; ++ unsigned int extents_per_block; ++ ++ if (eti->force_rebuild) ++ goto rebuild; ++ ++ extents_per_block = (ctx->fs->blocksize - ++ sizeof(struct ext3_extent_header)) / ++ sizeof(struct ext3_extent); ++ /* ++ * If we can consolidate a level or shorten the tree, schedule the ++ * extent tree to be rebuilt. ++ */ ++ for (i = 0, ei = eti->ext_info; i < info->max_depth + 1; i++, ei++) { ++ if (ei->max_extents - ei->num_extents > extents_per_block) { ++ pctx->blk = i; ++ op = PR_1E_CAN_NARROW_EXTENT_TREE; ++ goto rebuild; ++ } ++ for (j = 0; j < i; j++) { ++ if (ei->num_extents < eti->ext_info[j].max_extents) { ++ pctx->blk = i; ++ op = PR_1E_CAN_COLLAPSE_EXTENT_TREE; ++ goto rebuild; ++ } ++ } ++ } ++ return 0; ++ ++rebuild: ++ if (eti->force_rebuild || fix_problem(ctx, op, pctx)) ++ return e2fsck_rebuild_extents_later(ctx, eti->ino); ++ return 0; ++} ++ ++void e2fsck_pass1e(e2fsck_t ctx) ++{ ++ rebuild_extents(ctx, "Pass 1E", PR_1E_PASS_HEADER); ++} +--- a/e2fsck/gen_crc32table.c ++++ /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 +-#include "crc32defs.h" +-#include +- +-#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; +-} +--- a/e2fsck/jfs_user.h ++++ b/e2fsck/jfs_user.h +@@ -8,62 +8,83 @@ + * GNU General Public License version 2 or at your discretion + * any later version. + */ ++#ifndef _JFS_USER_H ++#define _JFS_USER_H + ++#ifdef DEBUGFS ++#include ++#include ++#if EXT2_FLAT_INCLUDES ++#include "ext2_fs.h" ++#include "ext2fs.h" ++#include "blkid.h" ++#else ++#include "ext2fs/ext2_fs.h" ++#include "ext2fs/ext2fs.h" ++#include "blkid/blkid.h" ++#endif ++#else + /* + * Pull in the definition of the e2fsck context structure + */ + #include "e2fsck.h" ++#endif + + struct buffer_head { ++#ifdef DEBUGFS ++ ext2_filsys b_fs; ++#else + e2fsck_t b_ctx; +- io_channel b_io; +- int b_size; ++#endif ++ io_channel b_io; ++ int b_size; + unsigned long long b_blocknr; +- int b_dirty; +- int b_uptodate; +- int b_err; ++ int b_dirty; ++ int b_uptodate; ++ int b_err; + char b_data[1024]; + }; + + struct inode { ++#ifdef DEBUGFS ++ ext2_filsys i_fs; ++#else + e2fsck_t i_ctx; ++#endif + ext2_ino_t i_ino; + struct ext2_inode i_ext2; + }; + + struct kdev_s { ++#ifdef DEBUGFS ++ ext2_filsys k_fs; ++#else + e2fsck_t k_ctx; ++#endif + int k_dev; + }; + + #define K_DEV_FS 1 + #define K_DEV_JOURNAL 2 + +-typedef struct kdev_s *kdev_t; +- +-#define lock_buffer(bh) do {} while(0) +-#define unlock_buffer(bh) do {} while(0) ++#define lock_buffer(bh) do {} while (0) ++#define unlock_buffer(bh) do {} while (0) + #define buffer_req(bh) 1 +-#define do_readahead(journal, start) do {} while(0) +- +-extern e2fsck_t e2fsck_global_ctx; /* Try your very best not to use this! */ ++#define do_readahead(journal, start) do {} while (0) + + typedef struct { + int object_length; + } lkmem_cache_t; + +-#define kmem_cache_alloc(cache,flags) malloc((cache)->object_length) +-#define kmem_cache_free(cache,obj) free(obj) +-#define kmem_cache_create(name,len,a,b,c,d) do_cache_create(len) ++#define kmem_cache_alloc(cache, flags) malloc((cache)->object_length) ++#define kmem_cache_free(cache, obj) free(obj) ++#define kmem_cache_create(name, len, a, b, c) do_cache_create(len) + #define kmem_cache_destroy(cache) do_cache_destroy(cache) +-#define kmalloc(len,flags) malloc(len) ++#define kmalloc(len, flags) malloc(len) + #define kfree(p) free(p) + + #define cond_resched() do { } while (0) + +-typedef unsigned int __be32; +-typedef __u64 __be64; +- + #define __init + + /* +@@ -76,7 +97,7 @@ + * functions. + */ + #ifdef NO_INLINE_FUNCS +-extern lkmem_cache_t * do_cache_create(int len); ++extern lkmem_cache_t *do_cache_create(int len); + extern void do_cache_destroy(lkmem_cache_t *cache); + extern size_t journal_tag_bytes(journal_t *journal); + #endif +@@ -101,9 +122,10 @@ + #endif /* E2FSCK_INCLUDE_INLINE_FUNCS */ + + +-_INLINE_ lkmem_cache_t * do_cache_create(int len) ++_INLINE_ lkmem_cache_t *do_cache_create(int len) + { + lkmem_cache_t *new_cache; ++ + new_cache = malloc(sizeof(*new_cache)); + if (new_cache) + new_cache->object_length = len; +@@ -115,17 +137,6 @@ + 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 + +@@ -134,7 +145,7 @@ + */ + int journal_bmap(journal_t *journal, blk64_t block, unsigned long long *phys); + struct buffer_head *getblk(kdev_t ctx, blk64_t blocknr, int blocksize); +-void sync_blockdev(kdev_t kdev); ++int sync_blockdev(kdev_t kdev); + void ll_rw_block(int rw, int dummy, struct buffer_head *bh[]); + void mark_buffer_dirty(struct buffer_head *bh); + void mark_buffer_uptodate(struct buffer_head *bh, int val); +@@ -147,3 +158,41 @@ + */ + #define __getblk(dev, blocknr, blocksize) getblk(dev, blocknr, blocksize) + #define set_buffer_uptodate(bh) mark_buffer_uptodate(bh, 1) ++ ++#ifdef DEBUGFS ++#include ++#undef J_ASSERT ++#define J_ASSERT(x) assert(x) ++ ++#define JSB_HAS_INCOMPAT_FEATURE(jsb, mask) \ ++ ((jsb)->s_header.h_blocktype == ext2fs_cpu_to_be32(JFS_SUPERBLOCK_V2) && \ ++ ((jsb)->s_feature_incompat & ext2fs_cpu_to_be32((mask)))) ++#else /* !DEBUGFS */ ++ ++extern e2fsck_t e2fsck_global_ctx; /* Try your very best not to use this! */ ++ ++#define J_ASSERT(assert) \ ++ do { if (!(assert)) { \ ++ printf ("Assertion failure in %s() at %s line %d: " \ ++ "\"%s\"\n", \ ++ __FUNCTION__, __FILE__, __LINE__, # assert); \ ++ fatal_error(e2fsck_global_ctx, 0); \ ++ } } while (0) ++ ++#endif /* DEBUGFS */ ++ ++/* recovery.c */ ++extern int journal_recover (journal_t *journal); ++extern int journal_skip_recovery (journal_t *); ++ ++/* revoke.c */ ++extern int journal_init_revoke(journal_t *, int); ++extern void journal_destroy_revoke(journal_t *); ++extern void journal_destroy_revoke_caches(void); ++extern int journal_init_revoke_caches(void); ++ ++extern int journal_set_revoke(journal_t *, unsigned long long, tid_t); ++extern int journal_test_revoke(journal_t *, unsigned long long, tid_t); ++extern void journal_clear_revoke(journal_t *); ++ ++#endif /* _JFS_USER_H */ +--- a/e2fsck/journal.c ++++ b/e2fsck/journal.c +@@ -40,6 +40,56 @@ + */ + #undef USE_INODE_IO + ++/* Checksumming functions */ ++static int e2fsck_journal_verify_csum_type(journal_t *j, ++ journal_superblock_t *jsb) ++{ ++ if (!journal_has_csum_v2or3(j)) ++ 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 (!journal_has_csum_v2or3(j)) ++ 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 (!journal_has_csum_v2or3(j)) ++ 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. +@@ -94,7 +144,7 @@ + return bh; + } + +-void sync_blockdev(kdev_t kdev) ++int sync_blockdev(kdev_t kdev) + { + io_channel io; + +@@ -103,7 +153,7 @@ + else + io = kdev->k_ctx->journal_io; + +- io_channel_flush(io); ++ return io_channel_flush(io) ? EIO : 0; + } + + void ll_rw_block(int rw, int nr, struct buffer_head *bhp[]) +@@ -406,7 +456,6 @@ + } + memcpy(&jsuper, start ? bh->b_data : bh->b_data + SUPERBLOCK_OFFSET, + sizeof(jsuper)); +- brelse(bh); + #ifdef WORDS_BIGENDIAN + if (jsuper.s_magic == ext2fs_swab16(EXT2_SUPER_MAGIC)) + ext2fs_swap_super(&jsuper); +@@ -415,6 +464,7 @@ + !(jsuper.s_feature_incompat & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)) { + fix_problem(ctx, PR_0_EXT_JOURNAL_BAD_SUPER, &pctx); + retval = EXT2_ET_LOAD_EXT_JOURNAL; ++ brelse(bh); + goto errout; + } + /* Make sure the journal UUID is correct */ +@@ -422,9 +472,32 @@ + sizeof(jsuper.s_uuid))) { + fix_problem(ctx, PR_0_JOURNAL_BAD_UUID, &pctx); + retval = EXT2_ET_LOAD_EXT_JOURNAL; ++ brelse(bh); + goto errout; + } + ++ /* Check the superblock checksum */ ++ if (jsuper.s_feature_ro_compat & ++ EXT4_FEATURE_RO_COMPAT_METADATA_CSUM) { ++ struct struct_ext2_filsys fsx; ++ struct ext2_super_block superx; ++ void *p; ++ ++ p = start ? bh->b_data : bh->b_data + SUPERBLOCK_OFFSET; ++ memcpy(&fsx, ctx->fs, sizeof(fsx)); ++ memcpy(&superx, ctx->fs->super, sizeof(superx)); ++ fsx.super = &superx; ++ fsx.super->s_feature_ro_compat |= ++ EXT4_FEATURE_RO_COMPAT_METADATA_CSUM; ++ if (!ext2fs_superblock_csum_verify(&fsx, p) && ++ fix_problem(ctx, PR_0_EXT_JOURNAL_SUPER_CSUM_INVALID, ++ &pctx)) { ++ ext2fs_superblock_csum_set(&fsx, p); ++ mark_buffer_dirty(bh); ++ } ++ } ++ brelse(bh); ++ + maxlen = ext2fs_blocks_count(&jsuper); + journal->j_maxlen = (maxlen < 1ULL << 32) ? maxlen : (1ULL << 32) - 1; + start++; +@@ -472,10 +545,10 @@ + pctx->ino = sb->s_journal_inum; + if (fix_problem(ctx, PR_0_JOURNAL_BAD_INODE, pctx)) { + if (has_journal && sb->s_journal_inum) +- printf("*** ext3 journal has been deleted - " +- "filesystem is now ext2 only ***\n\n"); ++ printf("*** journal has been deleted ***\n\n"); + sb->s_feature_compat &= ~EXT3_FEATURE_COMPAT_HAS_JOURNAL; + sb->s_journal_inum = 0; ++ memset(sb->s_jnl_blocks, 0, sizeof(sb->s_jnl_blocks)); + ctx->flags |= E2F_FLAG_JOURNAL_INODE; + ctx->fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY; + e2fsck_clear_recover(ctx, 1); +@@ -573,6 +646,23 @@ + if (JFS_HAS_RO_COMPAT_FEATURE(journal, ~JFS_KNOWN_ROCOMPAT_FEATURES)) + return EXT2_ET_RO_UNSUPP_FEATURE; + ++ /* Checksum v1-3 are mutually exclusive features. */ ++ if (JFS_HAS_INCOMPAT_FEATURE(journal, JFS_FEATURE_INCOMPAT_CSUM_V2) && ++ JFS_HAS_INCOMPAT_FEATURE(journal, JFS_FEATURE_INCOMPAT_CSUM_V3)) ++ return EXT2_ET_CORRUPT_SUPERBLOCK; ++ ++ if (journal_has_csum_v2or3(journal) && ++ 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; ++ ++ if (journal_has_csum_v2or3(journal)) ++ journal->j_csum_seed = jbd2_chksum(journal, ~0, jsb->s_uuid, ++ sizeof(jsb->s_uuid)); ++ + /* 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 +730,7 @@ + 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); +@@ -677,9 +768,10 @@ + mark_buffer_clean(journal->j_sb_buffer); + else if (!(ctx->options & E2F_OPT_READONLY)) { + jsb = journal->j_superblock; +- jsb->s_sequence = htonl(journal->j_transaction_sequence); ++ jsb->s_sequence = htonl(journal->j_tail_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 +916,7 @@ + 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); + } + +--- a/e2fsck/Makefile.in ++++ b/e2fsck/Makefile.in +@@ -15,22 +15,22 @@ + MANPAGES= e2fsck.8 + FMANPAGES= e2fsck.conf.5 + +-LIBS= $(LIBQUOTA) $(LIBEXT2FS) $(LIBCOM_ERR) $(LIBBLKID) $(LIBUUID) \ +- $(LIBINTL) $(LIBE2P) $(SYSLIBS) +-DEPLIBS= $(DEPLIBQUOTA) $(LIBEXT2FS) $(DEPLIBCOM_ERR) $(DEPLIBBLKID) \ ++LIBS= $(LIBSUPPORT) $(LIBEXT2FS) $(LIBCOM_ERR) $(LIBBLKID) $(LIBUUID) \ ++ $(LIBINTL) $(LIBE2P) $(LIBMAGIC) $(SYSLIBS) ++DEPLIBS= $(DEPLIBSUPPORT) $(LIBEXT2FS) $(DEPLIBCOM_ERR) $(DEPLIBBLKID) \ + $(DEPLIBUUID) $(DEPLIBE2P) + +-STATIC_LIBS= $(STATIC_LIBQUOTA) $(STATIC_LIBEXT2FS) $(STATIC_LIBCOM_ERR) \ ++STATIC_LIBS= $(STATIC_LIBSUPPORT) $(STATIC_LIBEXT2FS) $(STATIC_LIBCOM_ERR) \ + $(STATIC_LIBBLKID) $(STATIC_LIBUUID) $(LIBINTL) $(STATIC_LIBE2P) \ +- $(SYSLIBS) +-STATIC_DEPLIBS= $(DEPSTATIC_LIBQUOTA) $(STATIC_LIBEXT2FS) \ ++ $(LIBMAGIC) $(SYSLIBS) ++STATIC_DEPLIBS= $(DEPSTATIC_LIBSUPPORT) $(STATIC_LIBEXT2FS) \ + $(DEPSTATIC_LIBCOM_ERR) $(DEPSTATIC_LIBBLKID) \ + $(DEPSTATIC_LIBUUID) $(DEPSTATIC_LIBE2P) + +-PROFILED_LIBS= $(PROFILED_LIBQUOTA) $(PROFILED_LIBEXT2FS) \ ++PROFILED_LIBS= $(PROFILED_LIBSUPPORT) $(PROFILED_LIBEXT2FS) \ + $(PROFILED_LIBCOM_ERR) $(PROFILED_LIBBLKID) $(PROFILED_LIBUUID) \ +- $(PROFILED_LIBE2P) $(LIBINTL) $(SYSLIBS) +-PROFILED_DEPLIBS= $(DEPPROFILED_LIBQUOTA) $(PROFILED_LIBEXT2FS) \ ++ $(PROFILED_LIBE2P) $(LIBINTL) $(LIBMAGIC) $(SYSLIBS) ++PROFILED_DEPLIBS= $(DEPPROFILED_LIBSUPPORT) $(PROFILED_LIBEXT2FS) \ + $(DEPPROFILED_LIBCOM_ERR) $(DEPPROFILED_LIBBLKID) \ + $(DEPPROFILED_LIBUUID) $(DEPPROFILED_LIBE2P) + +@@ -40,6 +40,7 @@ + $(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,27 +58,25 @@ + # + #MCHECK= -DMCHECK + +-OBJS= crc32.o dict.o unix.o e2fsck.o super.o pass1.o pass1b.o pass2.o \ ++OBJS= 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 \ +- logfile.o sigcatcher.o $(MTRACE_OBJ) ++ region.o revoke.o ea_refcount.o rehash.o \ ++ logfile.o sigcatcher.o $(MTRACE_OBJ) readahead.o \ ++ extents.o + +-PROFILED_OBJS= profiled/dict.o profiled/unix.o profiled/e2fsck.o \ ++PROFILED_OBJS= profiled/unix.o profiled/e2fsck.o \ + profiled/super.o profiled/pass1.o profiled/pass1b.o \ + profiled/pass2.o profiled/pass3.o profiled/pass4.o profiled/pass5.o \ + profiled/journal.o profiled/badblocks.o profiled/util.o \ + profiled/dirinfo.o profiled/dx_dirinfo.o profiled/ehandler.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/sigcatcher.o ++ profiled/ea_refcount.o profiled/rehash.o \ ++ profiled/logfile.o profiled/sigcatcher.o \ ++ profiled/readahead.o profiled/extents.o + + SRCS= $(srcdir)/e2fsck.c \ +- $(srcdir)/crc32.c \ +- $(srcdir)/gen_crc32table.c \ +- $(srcdir)/dict.c \ + $(srcdir)/super.c \ + $(srcdir)/pass1.c \ + $(srcdir)/pass1b.c \ +@@ -98,22 +97,18 @@ + $(srcdir)/message.c \ + $(srcdir)/ea_refcount.c \ + $(srcdir)/rehash.c \ ++ $(srcdir)/readahead.c \ + $(srcdir)/region.c \ +- $(srcdir)/profile.c \ + $(srcdir)/sigcatcher.c \ + $(srcdir)/logfile.c \ +- prof_err.c \ + $(srcdir)/quota.c \ ++ $(srcdir)/extents.c \ + $(MTRACE_SRC) + + all:: profiled $(PROGS) e2fsck $(MANPAGES) $(FMANPAGES) + + @PROFILE_CMT@all:: e2fsck.profiled + +-prof_err.c prof_err.h: prof_err.et +- $(E) " COMPILE_ET prof_err.et" +- $(Q) $(COMPILE_ET) $(srcdir)/prof_err.et +- + e2fsck: $(OBJS) $(DEPLIBS) + $(E) " LD $@" + $(Q) $(LD) $(ALL_LDFLAGS) $(RDYNAMIC) -o e2fsck $(OBJS) $(LIBS) +@@ -127,15 +122,6 @@ + $(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) $(ALL_CFLAGS) $(ALL_LDFLAGS) $(RDYNAMIC) \ +@@ -147,10 +133,6 @@ + $(srcdir)/problem.c -DUNITTEST $(LIBEXT2FS) $(LIBCOM_ERR) \ + $(LIBINTL) $(SYSLIBS) + +-tst_crc32: $(srcdir)/crc32.c $(LIBEXT2FS) $(DEPLIBCOM_ERR) +- $(Q) $(CC) $(ALL_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 \ +@@ -168,10 +150,9 @@ + $(ALL_CFLAGS) $(ALL_LDFLAGS) -DTEST_PROGRAM \ + $(LIBCOM_ERR) $(SYSLIBS) + +-check:: tst_refcount tst_region tst_crc32 tst_problem ++check:: tst_refcount tst_region tst_problem + $(TESTENV) ./tst_refcount + $(TESTENV) ./tst_region +- $(TESTENV) ./tst_crc32 + $(TESTENV) ./tst_problem + + extend: extend.o +@@ -268,9 +249,9 @@ + 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 tst_crc32 \ ++ gen_crc32table e2fsck.conf.5 \ ++ prof_err.c prof_err.h test_profile + $(RM) -rf profiled + + mostlyclean: clean +@@ -289,22 +270,9 @@ + $(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 +-dict.o: $(srcdir)/dict.c $(top_builddir)/lib/config.h \ +- $(top_builddir)/lib/dirpaths.h $(srcdir)/dict.h ++ $(top_srcdir)/lib/support/profile.h $(top_builddir)/lib/support/prof_err.h \ ++ $(top_srcdir)/lib/support/quotaio.h $(top_srcdir)/lib/support/dqblk_v2.h \ ++ $(top_srcdir)/lib/support/quotaio_tree.h $(srcdir)/problem.h + super.o: $(srcdir)/super.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 \ +@@ -312,9 +280,9 @@ + $(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 ++ $(top_srcdir)/lib/support/profile.h $(top_builddir)/lib/support/prof_err.h \ ++ $(top_srcdir)/lib/support/quotaio.h $(top_srcdir)/lib/support/dqblk_v2.h \ ++ $(top_srcdir)/lib/support/quotaio_tree.h $(srcdir)/problem.h + pass1.o: $(srcdir)/pass1.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 \ +@@ -322,9 +290,9 @@ + $(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 ++ $(top_srcdir)/lib/support/profile.h $(top_builddir)/lib/support/prof_err.h \ ++ $(top_srcdir)/lib/support/quotaio.h $(top_srcdir)/lib/support/dqblk_v2.h \ ++ $(top_srcdir)/lib/support/quotaio_tree.h $(srcdir)/problem.h + pass1b.o: $(srcdir)/pass1b.c $(top_builddir)/lib/config.h \ + $(top_builddir)/lib/dirpaths.h $(top_srcdir)/lib/et/com_err.h \ + $(srcdir)/e2fsck.h $(top_srcdir)/lib/ext2fs/ext2_fs.h \ +@@ -332,9 +300,10 @@ + $(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)/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 $(srcdir)/dict.h ++ $(top_srcdir)/lib/support/profile.h $(top_builddir)/lib/support/prof_err.h \ ++ $(top_srcdir)/lib/support/quotaio.h $(top_srcdir)/lib/support/dqblk_v2.h \ ++ $(top_srcdir)/lib/support/quotaio_tree.h $(srcdir)/problem.h \ ++ $(top_srcdir)/lib/support/dict.h + pass2.o: $(srcdir)/pass2.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 \ +@@ -342,9 +311,10 @@ + $(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 $(srcdir)/dict.h ++ $(top_srcdir)/lib/support/profile.h $(top_builddir)/lib/support/prof_err.h \ ++ $(top_srcdir)/lib/support/quotaio.h $(top_srcdir)/lib/support/dqblk_v2.h \ ++ $(top_srcdir)/lib/support/quotaio_tree.h $(srcdir)/problem.h \ ++ $(top_srcdir)/lib/support/dict.h + pass3.o: $(srcdir)/pass3.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 \ +@@ -352,9 +322,9 @@ + $(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 ++ $(top_srcdir)/lib/support/profile.h $(top_builddir)/lib/support/prof_err.h \ ++ $(top_srcdir)/lib/support/quotaio.h $(top_srcdir)/lib/support/dqblk_v2.h \ ++ $(top_srcdir)/lib/support/quotaio_tree.h $(srcdir)/problem.h + pass4.o: $(srcdir)/pass4.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 \ +@@ -362,9 +332,9 @@ + $(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 ++ $(top_srcdir)/lib/support/profile.h $(top_builddir)/lib/support/prof_err.h \ ++ $(top_srcdir)/lib/support/quotaio.h $(top_srcdir)/lib/support/dqblk_v2.h \ ++ $(top_srcdir)/lib/support/quotaio_tree.h $(srcdir)/problem.h + pass5.o: $(srcdir)/pass5.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 \ +@@ -372,9 +342,9 @@ + $(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 ++ $(top_srcdir)/lib/support/profile.h $(top_builddir)/lib/support/prof_err.h \ ++ $(top_srcdir)/lib/support/quotaio.h $(top_srcdir)/lib/support/dqblk_v2.h \ ++ $(top_srcdir)/lib/support/quotaio_tree.h $(srcdir)/problem.h + journal.o: $(srcdir)/journal.c $(top_builddir)/lib/config.h \ + $(top_builddir)/lib/dirpaths.h $(srcdir)/jfs_user.h $(srcdir)/e2fsck.h \ + $(top_srcdir)/lib/ext2fs/ext2_fs.h $(top_builddir)/lib/ext2fs/ext2_types.h \ +@@ -382,33 +352,33 @@ + $(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 $(top_srcdir)/lib/ext2fs/kernel-jbd.h \ +- $(top_srcdir)/lib/ext2fs/jfs_compat.h $(top_srcdir)/lib/ext2fs/kernel-list.h \ +- $(srcdir)/problem.h +-recovery.o: $(srcdir)/recovery.c $(top_builddir)/lib/config.h \ +- $(top_builddir)/lib/dirpaths.h $(srcdir)/jfs_user.h $(srcdir)/e2fsck.h \ ++ $(top_srcdir)/lib/support/profile.h $(top_builddir)/lib/support/prof_err.h \ ++ $(top_srcdir)/lib/support/quotaio.h $(top_srcdir)/lib/support/dqblk_v2.h \ ++ $(top_srcdir)/lib/support/quotaio_tree.h \ ++ $(top_srcdir)/lib/ext2fs/kernel-jbd.h $(top_srcdir)/lib/ext2fs/jfs_compat.h \ ++ $(top_srcdir)/lib/ext2fs/kernel-list.h $(srcdir)/problem.h ++recovery.o: $(srcdir)/recovery.c $(srcdir)/jfs_user.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 $(top_srcdir)/lib/ext2fs/kernel-jbd.h \ +- $(top_srcdir)/lib/ext2fs/jfs_compat.h $(top_srcdir)/lib/ext2fs/kernel-list.h +-revoke.o: $(srcdir)/revoke.c $(top_builddir)/lib/config.h \ +- $(top_builddir)/lib/dirpaths.h $(srcdir)/jfs_user.h $(srcdir)/e2fsck.h \ ++ $(top_srcdir)/lib/support/profile.h $(top_builddir)/lib/support/prof_err.h \ ++ $(top_srcdir)/lib/support/quotaio.h $(top_srcdir)/lib/support/dqblk_v2.h \ ++ $(top_srcdir)/lib/support/quotaio_tree.h \ ++ $(top_srcdir)/lib/ext2fs/kernel-jbd.h $(top_srcdir)/lib/ext2fs/jfs_compat.h \ ++ $(top_srcdir)/lib/ext2fs/kernel-list.h ++revoke.o: $(srcdir)/revoke.c $(srcdir)/jfs_user.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 $(top_srcdir)/lib/ext2fs/kernel-jbd.h \ +- $(top_srcdir)/lib/ext2fs/jfs_compat.h $(top_srcdir)/lib/ext2fs/kernel-list.h ++ $(top_srcdir)/lib/support/profile.h $(top_builddir)/lib/support/prof_err.h \ ++ $(top_srcdir)/lib/support/quotaio.h $(top_srcdir)/lib/support/dqblk_v2.h \ ++ $(top_srcdir)/lib/support/quotaio_tree.h \ ++ $(top_srcdir)/lib/ext2fs/kernel-jbd.h $(top_srcdir)/lib/ext2fs/jfs_compat.h \ ++ $(top_srcdir)/lib/ext2fs/kernel-list.h + badblocks.o: $(srcdir)/badblocks.c $(top_builddir)/lib/config.h \ + $(top_builddir)/lib/dirpaths.h $(top_srcdir)/lib/et/com_err.h \ + $(srcdir)/e2fsck.h $(top_srcdir)/lib/ext2fs/ext2_fs.h \ +@@ -416,9 +386,9 @@ + $(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)/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 ++ $(top_srcdir)/lib/support/profile.h $(top_builddir)/lib/support/prof_err.h \ ++ $(top_srcdir)/lib/support/quotaio.h $(top_srcdir)/lib/support/dqblk_v2.h \ ++ $(top_srcdir)/lib/support/quotaio_tree.h + util.o: $(srcdir)/util.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 \ +@@ -426,19 +396,20 @@ + $(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 ++ $(top_srcdir)/lib/support/profile.h $(top_builddir)/lib/support/prof_err.h \ ++ $(top_srcdir)/lib/support/quotaio.h $(top_srcdir)/lib/support/dqblk_v2.h \ ++ $(top_srcdir)/lib/support/quotaio_tree.h + unix.o: $(srcdir)/unix.c $(top_builddir)/lib/config.h \ + $(top_builddir)/lib/dirpaths.h $(top_srcdir)/lib/e2p/e2p.h \ + $(top_srcdir)/lib/ext2fs/ext2_fs.h $(top_builddir)/lib/ext2fs/ext2_types.h \ +- $(top_srcdir)/lib/et/com_err.h $(srcdir)/e2fsck.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/et/com_err.h $(top_srcdir)/lib/support/plausible.h \ ++ $(srcdir)/e2fsck.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)/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 \ ++ $(top_srcdir)/lib/support/profile.h $(top_builddir)/lib/support/prof_err.h \ ++ $(top_srcdir)/lib/support/quotaio.h $(top_srcdir)/lib/support/dqblk_v2.h \ ++ $(top_srcdir)/lib/support/quotaio_tree.h $(srcdir)/problem.h \ + $(top_srcdir)/version.h + dirinfo.o: $(srcdir)/dirinfo.c $(top_builddir)/lib/config.h \ + $(top_builddir)/lib/dirpaths.h $(srcdir)/e2fsck.h \ +@@ -447,9 +418,9 @@ + $(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 $(top_srcdir)/lib/ext2fs/tdb.h ++ $(top_srcdir)/lib/support/profile.h $(top_builddir)/lib/support/prof_err.h \ ++ $(top_srcdir)/lib/support/quotaio.h $(top_srcdir)/lib/support/dqblk_v2.h \ ++ $(top_srcdir)/lib/support/quotaio_tree.h $(top_srcdir)/lib/ext2fs/tdb.h + dx_dirinfo.o: $(srcdir)/dx_dirinfo.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 \ +@@ -457,9 +428,9 @@ + $(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 ++ $(top_srcdir)/lib/support/profile.h $(top_builddir)/lib/support/prof_err.h \ ++ $(top_srcdir)/lib/support/quotaio.h $(top_srcdir)/lib/support/dqblk_v2.h \ ++ $(top_srcdir)/lib/support/quotaio_tree.h + ehandler.o: $(srcdir)/ehandler.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 \ +@@ -467,9 +438,9 @@ + $(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 ++ $(top_srcdir)/lib/support/profile.h $(top_builddir)/lib/support/prof_err.h \ ++ $(top_srcdir)/lib/support/quotaio.h $(top_srcdir)/lib/support/dqblk_v2.h \ ++ $(top_srcdir)/lib/support/quotaio_tree.h + problem.o: $(srcdir)/problem.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 \ +@@ -477,9 +448,10 @@ + $(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 $(srcdir)/problemP.h ++ $(top_srcdir)/lib/support/profile.h $(top_builddir)/lib/support/prof_err.h \ ++ $(top_srcdir)/lib/support/quotaio.h $(top_srcdir)/lib/support/dqblk_v2.h \ ++ $(top_srcdir)/lib/support/quotaio_tree.h $(srcdir)/problem.h \ ++ $(srcdir)/problemP.h + message.o: $(srcdir)/message.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 \ +@@ -487,9 +459,9 @@ + $(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 ++ $(top_srcdir)/lib/support/profile.h $(top_builddir)/lib/support/prof_err.h \ ++ $(top_srcdir)/lib/support/quotaio.h $(top_srcdir)/lib/support/dqblk_v2.h \ ++ $(top_srcdir)/lib/support/quotaio_tree.h $(srcdir)/problem.h + ea_refcount.o: $(srcdir)/ea_refcount.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 \ +@@ -497,9 +469,9 @@ + $(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 ++ $(top_srcdir)/lib/support/profile.h $(top_builddir)/lib/support/prof_err.h \ ++ $(top_srcdir)/lib/support/quotaio.h $(top_srcdir)/lib/support/dqblk_v2.h \ ++ $(top_srcdir)/lib/support/quotaio_tree.h + rehash.o: $(srcdir)/rehash.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 \ +@@ -507,9 +479,19 @@ + $(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 ++ $(top_srcdir)/lib/support/profile.h $(top_builddir)/lib/support/prof_err.h \ ++ $(top_srcdir)/lib/support/quotaio.h $(top_srcdir)/lib/support/dqblk_v2.h \ ++ $(top_srcdir)/lib/support/quotaio_tree.h $(srcdir)/problem.h ++readahead.o: $(srcdir)/readahead.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 \ ++ $(top_srcdir)/lib/support/profile.h $(top_builddir)/lib/support/prof_err.h \ ++ $(top_srcdir)/lib/support/quotaio.h $(top_srcdir)/lib/support/dqblk_v2.h \ ++ $(top_srcdir)/lib/support/quotaio_tree.h + region.o: $(srcdir)/region.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 \ +@@ -517,12 +499,9 @@ + $(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 +-profile.o: $(srcdir)/profile.c $(top_builddir)/lib/config.h \ +- $(top_builddir)/lib/dirpaths.h $(top_srcdir)/lib/et/com_err.h \ +- $(srcdir)/profile.h prof_err.h ++ $(top_srcdir)/lib/support/profile.h $(top_builddir)/lib/support/prof_err.h \ ++ $(top_srcdir)/lib/support/quotaio.h $(top_srcdir)/lib/support/dqblk_v2.h \ ++ $(top_srcdir)/lib/support/quotaio_tree.h + sigcatcher.o: $(srcdir)/sigcatcher.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 \ +@@ -530,9 +509,9 @@ + $(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 ++ $(top_srcdir)/lib/support/profile.h $(top_builddir)/lib/support/prof_err.h \ ++ $(top_srcdir)/lib/support/quotaio.h $(top_srcdir)/lib/support/dqblk_v2.h \ ++ $(top_srcdir)/lib/support/quotaio_tree.h + logfile.o: $(srcdir)/logfile.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 \ +@@ -540,10 +519,9 @@ + $(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 +-prof_err.o: prof_err.c ++ $(top_srcdir)/lib/support/profile.h $(top_builddir)/lib/support/prof_err.h \ ++ $(top_srcdir)/lib/support/quotaio.h $(top_srcdir)/lib/support/dqblk_v2.h \ ++ $(top_srcdir)/lib/support/quotaio_tree.h + quota.o: $(srcdir)/quota.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 \ +@@ -551,6 +529,16 @@ + $(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 ++ $(top_srcdir)/lib/support/profile.h $(top_builddir)/lib/support/prof_err.h \ ++ $(top_srcdir)/lib/support/quotaio.h $(top_srcdir)/lib/support/dqblk_v2.h \ ++ $(top_srcdir)/lib/support/quotaio_tree.h $(srcdir)/problem.h ++extents.o: $(srcdir)/extents.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 \ ++ $(top_srcdir)/lib/support/profile.h $(top_builddir)/lib/support/prof_err.h \ ++ $(top_srcdir)/lib/support/quotaio.h $(top_srcdir)/lib/support/dqblk_v2.h \ ++ $(top_srcdir)/lib/support/quotaio_tree.h $(srcdir)/problem.h +--- /dev/null ++++ b/e2fsck/Makefile.pq +@@ -0,0 +1,9 @@ ++TOPSRC=.. ++LIBNAME=E2FSCK.LIB ++OBJFILE=E2FSCK.LST ++ ++OBJS= e2fsck.obj super.obj pass1.obj pass2.obj pass3.obj \ ++ pass4.obj pass5.obj dirinfo.obj ++ ++!include $(TOPSRC)\powerquest\MCONFIG ++ +--- a/e2fsck/message.c ++++ b/e2fsck/message.c +@@ -374,7 +374,7 @@ + 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 @@ + 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: +--- a/e2fsck/pass1b.c ++++ b/e2fsck/pass1b.c +@@ -49,7 +49,7 @@ + #include "e2fsck.h" + + #include "problem.h" +-#include "dict.h" ++#include "support/dict.h" + + /* Define an extension to the ext2 library's block count information */ + #define BLOCK_COUNT_EXTATTR (-5) +@@ -262,6 +262,7 @@ + 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 @@ + ext2_inode_scan scan; + struct process_block_struct pb; + struct problem_context pctx; ++ problem_t op; + + clear_problem_context(&pctx); + +@@ -316,6 +318,8 @@ + 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 @@ + 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,8 +362,9 @@ + struct process_block_struct *p; + e2fsck_t ctx; + blk64_t lc, pc; ++ problem_t op; + +- if (HOLE_BLKADDR(*block_nr)) ++ if (*block_nr == 0) + return 0; + p = (struct process_block_struct *) priv_data; + ctx = p->ctx; +@@ -366,8 +376,17 @@ + + /* 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); +@@ -609,7 +628,7 @@ + pb = (struct process_block_struct *) priv_data; + ctx = pb->ctx; + +- if (HOLE_BLKADDR(*block_nr)) ++ if (*block_nr == 0) + return 0; + + c = EXT2FS_B2C(fs, *block_nr); +@@ -669,9 +688,9 @@ + 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; +@@ -706,8 +725,30 @@ + char *buf; + e2fsck_t ctx; + struct ext2_inode *inode; ++ ++ struct dup_cluster *save_dup_cluster; ++ blk64_t save_blocknr; + }; + ++/* ++ * Decrement the bad count *after* we've shown that (a) we can allocate a ++ * replacement block and (b) remap the file blocks. Unfortunately, there's no ++ * way to find out if the remap succeeded until either the next ++ * clone_file_block() call (an error when remapping the block after returning ++ * BLOCK_CHANGED will halt the iteration) or after block_iterate() returns. ++ * Otherwise, it's possible that we decrease the badcount once in preparation ++ * to remap, then the remap fails (either we can't find a replacement block or ++ * we have to split the extent tree and can't find a new extent block), so we ++ * delete the file, which decreases the badcount again. ++ */ ++static void deferred_dec_badcount(struct clone_struct *cs) ++{ ++ if (!cs->save_dup_cluster) ++ return; ++ decrement_badcount(cs->ctx, cs->save_blocknr, cs->save_dup_cluster); ++ cs->save_dup_cluster = NULL; ++} ++ + static int clone_file_block(ext2_filsys fs, + blk64_t *block_nr, + e2_blkcnt_t blockcnt, +@@ -715,7 +756,7 @@ + int ref_offset EXT2FS_ATTR((unused)), + void *priv_data) + { +- struct dup_cluster *p; ++ struct dup_cluster *p = NULL; + blk64_t new_block; + errcode_t retval; + struct clone_struct *cs = (struct clone_struct *) priv_data; +@@ -725,8 +766,9 @@ + int is_meta = 0; + + ctx = cs->ctx; ++ deferred_dec_badcount(cs); + +- if (HOLE_BLKADDR(*block_nr)) ++ if (*block_nr == 0) + return 0; + + c = EXT2FS_B2C(fs, blockcnt); +@@ -749,8 +791,6 @@ + } + + p = (struct dup_cluster *) dnode_get(n); +- if (!is_meta) +- decrement_badcount(ctx, *block_nr, p); + + cs->dup_cluster = c; + /* +@@ -800,6 +840,8 @@ + cs->errcode = retval; + return BLOCK_ABORT; + } ++ cs->save_dup_cluster = (is_meta ? NULL : p); ++ cs->save_blocknr = *block_nr; + *block_nr = new_block; + ext2fs_mark_block_bitmap2(ctx->block_found_map, new_block); + ext2fs_mark_block_bitmap2(fs->block_map, new_block); +@@ -829,6 +871,8 @@ + cs.ctx = ctx; + cs.ino = ino; + cs.inode = &dp->inode; ++ cs.save_dup_cluster = NULL; ++ cs.save_blocknr = 0; + retval = ext2fs_get_mem(fs->blocksize, &cs.buf); + if (retval) + return retval; +@@ -841,6 +885,7 @@ + if (ext2fs_inode_has_valid_blocks2(fs, &dp->inode)) + pctx.errcode = ext2fs_block_iterate3(fs, ino, 0, block_buf, + clone_file_block, &cs); ++ deferred_dec_badcount(&cs); + ext2fs_mark_bb_dirty(fs); + if (pctx.errcode) { + fix_problem(ctx, PR_1B_BLOCK_ITERATE, &pctx); +--- a/e2fsck/pass1.c ++++ b/e2fsck/pass1.c +@@ -56,6 +56,8 @@ + #define _INLINE_ inline + #endif + ++#undef DEBUG ++ + static int process_block(ext2_filsys fs, blk64_t *blocknr, + e2_blkcnt_t blockcnt, blk64_t ref_blk, + int ref_offset, void *priv_data); +@@ -68,6 +70,7 @@ + static void alloc_bb_map(e2fsck_t ctx); + static void alloc_imagic_map(e2fsck_t ctx); + static void mark_inode_bad(e2fsck_t ctx, ino_t ino); ++static void add_encrypted_dir(e2fsck_t ctx, ino_t ino); + static void handle_fs_bad_blocks(e2fsck_t ctx); + static void process_inodes(e2fsck_t ctx, char *block_buf); + static EXT2_QSORT_TYPE process_inode_cmp(const void *a, const void *b); +@@ -93,6 +96,8 @@ + struct problem_context *pctx; + ext2fs_block_bitmap fs_meta_blocks; + e2fsck_t ctx; ++ region_t region; ++ struct extent_tree_info eti; + }; + + struct process_inode_block { +@@ -182,6 +187,8 @@ + 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 +210,21 @@ + 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) || +@@ -218,9 +238,34 @@ + if (io_channel_read_blk64(fs->io, inode->i_block[0], 1, buf)) + return 0; + +- len = strnlen(buf, fs->blocksize); ++ if (inode->i_flags & EXT4_ENCRYPT_FL) { ++ len = ext2fs_le32_to_cpu(*((__u32 *)buf)) + 4; ++ } else { ++ 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; +@@ -230,11 +275,30 @@ + return 0; + } + if (len != inode->i_size) +- return 0; ++ if ((inode->i_flags & EXT4_ENCRYPT_FL) == 0) ++ return 0; + return 1; + } + + /* ++ * 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 +338,17 @@ + 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 +356,28 @@ + /* 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 +405,13 @@ + 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 +426,15 @@ + + 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 +443,7 @@ + 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 +507,7 @@ + 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 +535,52 @@ + * 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; ++ __u32 dotdot; ++ unsigned int rec_len; ++ struct ext2_dir_entry de; ++ ++ 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; ++ /* ++ * If the first 10 bytes don't look like a directory entry, ++ * it's probably not a directory. ++ */ ++ memcpy(&dotdot, inode->i_block, sizeof(dotdot)); ++ memcpy(&de, ((char *)inode->i_block) + EXT4_INLINE_DATA_DOTDOT_SIZE, ++ EXT2_DIR_REC_LEN(0)); ++ dotdot = ext2fs_le32_to_cpu(dotdot); ++ de.inode = ext2fs_le32_to_cpu(de.inode); ++ de.rec_len = ext2fs_le16_to_cpu(de.rec_len); ++ ext2fs_get_rec_len(ctx->fs, &de, &rec_len); ++ if (dotdot >= ctx->fs->super->s_inodes_count || ++ (dotdot < EXT2_FIRST_INO(ctx->fs->super) && ++ dotdot != EXT2_ROOT_INO) || ++ de.inode >= ctx->fs->super->s_inodes_count || ++ (de.inode < EXT2_FIRST_INO(ctx->fs->super) && ++ de.inode != 0) || ++ rec_len > EXT4_MIN_INLINE_DATA_SIZE - ++ EXT4_INLINE_DATA_DOTDOT_SIZE) ++ return; ++ /* device files never have a "system.data" entry */ ++ goto isdir; ++ } else if (extent_fs && (inode->i_flags & EXT4_EXTENTS_FL)) { + /* extent mapped */ + if (ext2fs_bmap2(ctx->fs, pctx->ino, inode, 0, 0, 0, 0, + &blk)) +@@ -473,7 +615,7 @@ + + /* 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 +624,7 @@ + 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 +636,14 @@ + 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 +683,38 @@ + *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. ++ */ ++ ctx->stashed_ino = 0; ++ 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 +751,209 @@ + 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 (inode_size > EXT2_GOOD_OLD_INODE_SIZE) ++ max_inline_ea_size = inode_size - ++ (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; ++} ++ ++static void pass1_readahead(e2fsck_t ctx, dgrp_t *group, ext2_ino_t *next_ino) ++{ ++ ext2_ino_t inodes_in_group = 0, inodes_per_block, inodes_per_buffer; ++ dgrp_t start = *group, grp; ++ blk64_t blocks_to_read = 0; ++ errcode_t err = EXT2_ET_INVALID_ARGUMENT; ++ ++ if (ctx->readahead_kb == 0) ++ goto out; ++ ++ /* Keep iterating groups until we have enough to readahead */ ++ inodes_per_block = EXT2_INODES_PER_BLOCK(ctx->fs->super); ++ for (grp = start; grp < ctx->fs->group_desc_count; grp++) { ++ if (ext2fs_bg_flags_test(ctx->fs, grp, EXT2_BG_INODE_UNINIT)) ++ continue; ++ inodes_in_group = ctx->fs->super->s_inodes_per_group - ++ ext2fs_bg_itable_unused(ctx->fs, grp); ++ blocks_to_read += (inodes_in_group + inodes_per_block - 1) / ++ inodes_per_block; ++ if (blocks_to_read * ctx->fs->blocksize > ++ ctx->readahead_kb * 1024) ++ break; ++ } ++ ++ err = e2fsck_readahead(ctx->fs, E2FSCK_READA_ITABLE, start, ++ grp - start + 1); ++ if (err == EAGAIN) { ++ ctx->readahead_kb /= 2; ++ err = 0; ++ } ++ ++out: ++ if (err) { ++ /* Error; disable itable readahead */ ++ *group = ctx->fs->group_desc_count; ++ *next_ino = ctx->fs->super->s_inodes_count; ++ } else { ++ /* ++ * Don't do more readahead until we've reached the first inode ++ * of the last inode scan buffer block for the last group. ++ */ ++ *group = grp + 1; ++ inodes_per_buffer = (ctx->inode_buffer_blocks ? ++ ctx->inode_buffer_blocks : ++ EXT2_INODE_SCAN_DEFAULT_BUFFER_BLOCKS) * ++ ctx->fs->blocksize / ++ EXT2_INODE_SIZE(ctx->fs->super); ++ inodes_in_group--; ++ *next_ino = inodes_in_group - ++ (inodes_in_group % inodes_per_buffer) + 1 + ++ (grp * ctx->fs->super->s_inodes_per_group); ++ } ++} ++ + void e2fsck_pass1(e2fsck_t ctx) + { + int i; +@@ -594,13 +972,23 @@ + 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 inode_size = EXT2_INODE_SIZE(fs->super); ++ int failed_csum = 0; ++ ext2_ino_t ino_threshold = 0; ++ dgrp_t ra_group = 0; + + init_resource_track(&rtrack, ctx->fs->io); + clear_problem_context(&pctx); + ++ /* If we can do readahead, figure out how many groups to pull in. */ ++ if (!e2fsck_can_readahead(ctx->fs)) ++ ctx->readahead_kb = 0; ++ else if (ctx->readahead_kb == ~0ULL) ++ ctx->readahead_kb = e2fsck_guess_readahead(ctx->fs); ++ pass1_readahead(ctx, &ra_group, &ino_threshold); ++ + if (!(ctx->options & E2F_OPT_PREEN)) + fix_problem(ctx, PR_1_PASS_HEADER, &pctx); + +@@ -627,6 +1015,8 @@ + + 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 +1059,15 @@ + 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, +@@ -683,7 +1082,6 @@ + ctx->flags |= E2F_FLAG_ABORT; + return; + } +- inode_size = EXT2_INODE_SIZE(fs->super); + inode = (struct ext2_inode *) + e2fsck_allocate_memory(ctx, inode_size, "scratch inode"); + +@@ -725,7 +1123,8 @@ + } + 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 +1135,8 @@ + 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 +1156,9 @@ + 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)) +@@ -764,17 +1167,52 @@ + old_op = ehandler_operation(_("getting next inode from scan")); + pctx.errcode = ext2fs_get_next_inode_full(scan, &ino, + inode, inode_size); ++ if (ino > ino_threshold) ++ pass1_readahead(ctx, &ra_group, &ino_threshold); + ehandler_operation(old_op); + if (ctx->flags & E2F_FLAG_SIGNAL_MASK) + return; + if (pctx.errcode == EXT2_ET_BAD_BLOCK_IN_INODE_TABLE) { ++ /* ++ * If badblocks says badblocks is bad, offer to clear ++ * the list, update the in-core bb list, and restart ++ * the inode scan. ++ */ ++ if (ino == EXT2_BAD_INO && ++ fix_problem(ctx, PR_1_BADBLOCKS_IN_BADBLOCKS, ++ &pctx)) { ++ errcode_t err; ++ ++ e2fsck_clear_inode(ctx, ino, inode, 0, "pass1"); ++ ext2fs_badblocks_list_free(ctx->fs->badblocks); ++ ctx->fs->badblocks = NULL; ++ err = ext2fs_read_bb_inode(ctx->fs, ++ &ctx->fs->badblocks); ++ if (err) { ++ fix_problem(ctx, PR_1_ISCAN_ERROR, ++ &pctx); ++ ctx->flags |= E2F_FLAG_ABORT; ++ goto endit; ++ } ++ err = ext2fs_inode_scan_goto_blockgroup(scan, ++ 0); ++ if (err) { ++ fix_problem(ctx, PR_1_ISCAN_ERROR, ++ &pctx); ++ ctx->flags |= E2F_FLAG_ABORT; ++ goto endit; ++ } ++ continue; ++ } + if (!ctx->inode_bb_map) + alloc_bb_map(ctx); + ext2fs_mark_inode_bitmap2(ctx->inode_bb_map, ino); + 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 +1222,16 @@ + 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 +1243,95 @@ + } + } + ++ /* 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; ++ } ++ if (LINUX_S_ISLNK(inode->i_mode)) ++ inode->i_flags &= ~EXT4_INLINE_DATA_FL; ++ 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 +1362,7 @@ + if (ino == EXT2_BAD_INO) + ext2fs_mark_inode_bitmap2(ctx->inode_used_map, + ino); ++ /* skip FINISH_INODE_LOOP */ + continue; + } + } +@@ -861,18 +1399,22 @@ + 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 +1449,7 @@ + } + 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 +1475,7 @@ + inode->i_dtime = 0; + e2fsck_write_inode(ctx, ino, inode, + "pass1"); ++ failed_csum = 0; + } + } + } else if (ino == EXT2_JOURNAL_INO) { +@@ -943,8 +1487,10 @@ + 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 +1502,7 @@ + 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 +1517,10 @@ + 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 +1532,7 @@ + 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 +1554,11 @@ + 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 +1586,7 @@ + 0 : ctx->now; + e2fsck_write_inode(ctx, ino, inode, + "pass1"); ++ failed_csum = 0; + } + } + +@@ -1048,8 +1601,10 @@ + 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 +1621,7 @@ + if (fix_problem(ctx, PR_1_SET_DTIME, &pctx)) { + inode->i_dtime = 0; + e2fsck_write_inode(ctx, ino, inode, "pass1"); ++ failed_csum = 0; + } + } + +@@ -1103,6 +1659,7 @@ + inode->i_flags &= ~EXT2_IMAGIC_FL; + e2fsck_write_inode(ctx, ino, + inode, "pass1"); ++ failed_csum = 0; + } + } + } +@@ -1120,22 +1677,27 @@ + 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)) { + ext2fs_mark_inode_bitmap2(ctx->inode_dir_map, ino); + e2fsck_add_dir_info(ctx, ino, 0); + ctx->fs_directory_count++; ++ if (inode->i_flags & EXT4_ENCRYPT_FL) ++ add_encrypted_dir(ctx, ino); + } else if (LINUX_S_ISREG (inode->i_mode)) { + ext2fs_mark_inode_bitmap2(ctx->inode_reg_map, ino); + 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++; +@@ -1144,25 +1706,32 @@ + 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]) +@@ -1171,6 +1740,7 @@ + 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] || +@@ -1181,6 +1751,8 @@ + } else + check_blocks(ctx, &pctx, block_buf); + ++ FINISH_INODE_LOOP(ctx, ino, &pctx, failed_csum); ++ + if (ctx->flags & E2F_FLAG_SIGNAL_MASK) + goto endit; + +@@ -1264,6 +1836,7 @@ + } + e2fsck_pass1_dupblocks(ctx, block_buf); + } ++ ctx->flags |= E2F_FLAG_ALLOC_OK; + ext2fs_free_mem(&inodes_to_process); + endit: + e2fsck_use_inode_shortcuts(ctx, 0); +@@ -1275,9 +1848,16 @@ + 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 +@@ -1396,6 +1976,23 @@ + ext2fs_mark_inode_bitmap2(ctx->inode_bad_map, ino); + } + ++static void add_encrypted_dir(e2fsck_t ctx, ino_t ino) ++{ ++ struct problem_context pctx; ++ ++ if (!ctx->encrypted_dirs) { ++ pctx.errcode = ext2fs_u32_list_create(&ctx->encrypted_dirs, 0); ++ if (pctx.errcode) ++ goto error; ++ } ++ pctx.errcode = ext2fs_u32_list_add(ctx->encrypted_dirs, ino); ++ if (pctx.errcode == 0) ++ return; ++error: ++ fix_problem(ctx, PR_1_ALLOCATE_ENCRYPTED_DIRLIST, &pctx); ++ /* Should never get here */ ++ ctx->flags |= E2F_FLAG_ABORT; ++} + + /* + * This procedure will allocate the inode "bb" (badblock) map table +@@ -1505,7 +2102,8 @@ + 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; +@@ -1516,8 +2114,9 @@ + 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); +@@ -1542,6 +2141,7 @@ + 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) +@@ -1615,9 +2215,18 @@ + * 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) && +@@ -1633,6 +2242,9 @@ + 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); +@@ -1697,6 +2309,18 @@ + } + 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); +@@ -1779,6 +2403,16 @@ + ext2fs_icount_store(ctx->inode_link_info, ino, 0); + inode->i_dtime = ctx->now; + ++ /* ++ * If a special inode has such rotten block mappings that we ++ * want to clear the whole inode, be sure to actually zap ++ * the block maps because i_links_count isn't checked for ++ * special inodes, and we'll end up right back here the next ++ * time we run fsck. ++ */ ++ if (ino < EXT2_FIRST_INODE(ctx->fs->super)) ++ memset(inode->i_block, 0, sizeof(inode->i_block)); ++ + ext2fs_unmark_inode_bitmap2(ctx->inode_dir_map, ino); + ext2fs_unmark_inode_bitmap2(ctx->inode_used_map, ino); + if (ctx->inode_reg_map) +@@ -1836,7 +2470,8 @@ + 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; +@@ -1845,19 +2480,47 @@ + 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) + return; ++ if (!(ctx->options & E2F_OPT_FIXES_ONLY) && ++ !pb->eti.force_rebuild) { ++ struct extent_tree_level *etl; ++ ++ etl = pb->eti.ext_info + info.curr_level; ++ etl->num_extents += info.num_entries; ++ etl->max_extents += info.max_entries; ++ /* ++ * Implementation wart: Splitting extent blocks when appending ++ * will leave the old block with one free entry. Therefore ++ * unless the node is totally full, pretend that a non-root ++ * extent block can hold one fewer entry than it actually does, ++ * so that we don't repeatedly rebuild the extent tree. ++ */ ++ if (info.curr_level && info.num_entries < info.max_entries) ++ etl->max_extents--; ++ } + + 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)) +@@ -1879,11 +2542,15 @@ + (1 << (21 - ctx->fs->super->s_log_block_size)))) + problem = PR_1_TOOBIG_DIR; + ++ if (is_leaf && problem == 0 && extent.e_len > 0 && ++ region_allocate(pb->region, extent.e_lblk, extent.e_len)) ++ problem = PR_1_EXTENT_COLLISION; ++ + /* + * 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; +@@ -1892,14 +2559,11 @@ + &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)) { + if (ctx->invalid_bitmaps) { + /* +@@ -1942,6 +2606,7 @@ + pctx->errcode = 0; + break; + } ++ failed_csum = 0; + continue; + } + goto next; +@@ -1949,13 +2614,33 @@ + + 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; +@@ -1980,7 +2665,8 @@ + } + } + 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, +@@ -2021,16 +2707,16 @@ + * 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; + + new_lblk = pb->last_block + 1; + if (EXT2FS_CLUSTER_RATIO(ctx->fs) > 1) + new_lblk = ((new_lblk + +- EXT2FS_CLUSTER_RATIO(ctx->fs)) & +- EXT2FS_CLUSTER_MASK(ctx->fs)) | +- (extent.e_lblk & ++ EXT2FS_CLUSTER_RATIO(ctx->fs) - 1) & ++ ~EXT2FS_CLUSTER_MASK(ctx->fs)) | ++ (extent.e_pblk & + EXT2FS_CLUSTER_MASK(ctx->fs)); + pctx->blk = extent.e_lblk; + pctx->blk2 = new_lblk; +@@ -2051,6 +2737,7 @@ + if (pctx->errcode) + goto failed_add_dir_block; + last_lblk = extent.e_lblk + extent.e_len - 1; ++ failed_csum = 0; + } + } + alloc_later: +@@ -2118,6 +2805,16 @@ + 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; + } +@@ -2144,14 +2841,38 @@ + + retval = ext2fs_extent_get_info(ehandle, &info); + if (retval == 0) { +- if (info.max_depth >= MAX_EXTENT_DEPTH_COUNT) +- info.max_depth = MAX_EXTENT_DEPTH_COUNT-1; +- ctx->extent_depth_count[info.max_depth]++; ++ int max_depth = info.max_depth; ++ ++ if (max_depth >= MAX_EXTENT_DEPTH_COUNT) ++ max_depth = MAX_EXTENT_DEPTH_COUNT-1; ++ ctx->extent_depth_count[max_depth]++; ++ } ++ ++ /* Check maximum extent depth */ ++ pctx->blk = info.max_depth; ++ pctx->blk2 = ext2fs_max_extent_depth(ehandle); ++ if (pctx->blk2 < pctx->blk && ++ fix_problem(ctx, PR_1_EXTENT_BAD_MAX_DEPTH, pctx)) ++ pb->eti.force_rebuild = 1; ++ ++ /* Can we collect extent tree level stats? */ ++ pctx->blk = MAX_EXTENT_DEPTH_COUNT; ++ if (pctx->blk2 > pctx->blk) ++ fix_problem(ctx, PR_1E_MAX_EXTENT_TREE_DEPTH, pctx); ++ memset(pb->eti.ext_info, 0, sizeof(pb->eti.ext_info)); ++ pb->eti.ino = pb->ino; ++ ++ pb->region = region_create(0, info.max_lblk); ++ if (!pb->region) { ++ ext2fs_extent_free(ehandle); ++ fix_problem(ctx, PR_1_EXTENT_ALLOC_REGION_ABORT, pctx); ++ ctx->flags |= E2F_FLAG_ABORT; ++ return; + } + + 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; +@@ -2160,7 +2881,67 @@ + "check_blocks_extents"); + pctx->errcode = 0; + } ++ region_free(pb->region); ++ pb->region = NULL; + ext2fs_extent_free(ehandle); ++ ++ /* Rebuild unless it's a dir and we're rehashing it */ ++ if (LINUX_S_ISDIR(inode->i_mode) && ++ e2fsck_dir_will_be_rehashed(ctx, ino)) ++ return; ++ ++ if (ctx->options & E2F_OPT_CONVERT_BMAP) ++ e2fsck_rebuild_extents_later(ctx, ino); ++ else ++ e2fsck_should_rebuild_extents(ctx, pctx, &pb->eti, &info); ++} ++ ++/* ++ * 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) ++{ ++ int flags; ++ size_t inline_data_size = 0; ++ ++ if (!pb->is_dir) { ++ pctx->errcode = 0; ++ return; ++ } ++ ++ /* Process the dirents in i_block[] as the "first" block. */ ++ pctx->errcode = ext2fs_add_dir_block2(ctx->fs->dblist, pb->ino, 0, 0); ++ if (pctx->errcode) ++ goto err; ++ ++ /* Process the dirents in the EA as a "second" block. */ ++ flags = ctx->fs->flags; ++ ctx->fs->flags |= EXT2_FLAG_IGNORE_CSUM_ERRORS; ++ pctx->errcode = ext2fs_inline_data_size(ctx->fs, pb->ino, ++ &inline_data_size); ++ ctx->fs->flags = (flags & EXT2_FLAG_IGNORE_CSUM_ERRORS) | ++ (ctx->fs->flags & ~EXT2_FLAG_IGNORE_CSUM_ERRORS); ++ if (pctx->errcode) { ++ pctx->errcode = 0; ++ return; ++ } ++ ++ if (inline_data_size <= EXT4_MIN_INLINE_DATA_SIZE) ++ return; ++ ++ pctx->errcode = ext2fs_add_dir_block2(ctx->fs->dblist, pb->ino, 0, 1); ++ if (pctx->errcode) ++ goto err; ++ ++ return; ++err: ++ pctx->blk = 0; ++ pctx->num = 0; ++ fix_problem(ctx, PR_1_ADD_DBLOCK, pctx); ++ ctx->flags |= E2F_FLAG_ABORT; + } + + /* +@@ -2177,6 +2958,7 @@ + unsigned bad_size = 0; + int dirty_inode = 0; + int extent_fs; ++ int inlinedata_fs; + __u64 size; + + pb.ino = ino; +@@ -2196,35 +2978,28 @@ + pb.pctx = pctx; + pb.ctx = ctx; + pb.inode_modified = 0; ++ pb.eti.force_rebuild = 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 & +- EXT2_FEATURE_INCOMPAT_COMPRESSION) +- pb.compressed = 1; +- else { +- if (fix_problem(ctx, PR_1_COMPR_SET, pctx)) { +- inode->i_flags &= ~EXT2_COMPRBLK_FL; +- dirty_inode++; +- } +- } +- } +- +- 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. +@@ -2234,6 +3009,8 @@ + "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); +@@ -2251,6 +3028,17 @@ + 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); ++ ++ if (ctx->options & E2F_OPT_CONVERT_BMAP) { ++#ifdef DEBUG ++ printf("bmap rebuild ino=%d\n", ino); ++#endif ++ if (!LINUX_S_ISDIR(inode->i_mode) || ++ !e2fsck_dir_will_be_rehashed(ctx, ino)) ++ e2fsck_rebuild_extents_later(ctx, ino); ++ } + } + } + end_problem_latch(ctx, PR_LATCH_BLOCK); +@@ -2278,13 +3066,12 @@ + inode->i_flags &= ~EXT2_INDEX_FL; + dirty_inode++; + } else { +-#ifdef ENABLE_HTREE + e2fsck_add_dx_dir(ctx, ino, pb.last_block+1); +-#endif + } + } + +- 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--; +@@ -2310,7 +3097,25 @@ + #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; +@@ -2342,12 +3147,20 @@ + } + /* 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; +@@ -2370,10 +3183,28 @@ + pctx->num = 0; + } + ++ /* ++ * The kernel gets mad if we ask it to allocate bigalloc clusters to ++ * a block mapped file, so rebuild it as an extent file. We can skip ++ * symlinks because they're never rewritten. ++ */ ++ if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super, ++ EXT4_FEATURE_RO_COMPAT_BIGALLOC) && ++ (LINUX_S_ISREG(inode->i_mode) || LINUX_S_ISDIR(inode->i_mode)) && ++ ext2fs_inode_data_blocks2(fs, inode) > 0 && ++ (ino == EXT2_ROOT_INO || ino >= EXT2_FIRST_INO(fs->super)) && ++ !(inode->i_flags & (EXT4_EXTENTS_FL | EXT4_INLINE_DATA_FL)) && ++ fix_problem(ctx, PR_1_NO_BIGALLOC_BLOCKMAP_FILES, pctx)) { ++ pctx->errcode = e2fsck_rebuild_extents_later(ctx, ino); ++ if (pctx->errcode) ++ goto out; ++ } ++ + 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) +@@ -2453,28 +3284,6 @@ + pctx = p->pctx; + ctx = p->ctx; + +- if (p->compressed && (blk == EXT2FS_COMPRESSED_BLKADDR)) { +- /* todo: Check that the comprblk_fl is high, that the +- blkaddr pattern looks right (all non-holes up to +- first EXT2FS_COMPRESSED_BLKADDR, then all +- EXT2FS_COMPRESSED_BLKADDR up to end of cluster), +- that the feature_incompat bit is high, and that the +- inode is a regular file. If we're doing a "full +- check" (a concept introduced to e2fsck by e2compr, +- meaning that we look at data blocks as well as +- metadata) then call some library routine that +- checks the compressed data. I'll have to think +- about this, because one particularly important +- problem to be able to fix is to recalculate the +- cluster size if necessary. I think that perhaps +- we'd better do most/all e2compr-specific checks +- separately, after the non-e2compr checks. If not +- doing a full check, it may be useful to test that +- the personality is linux; e.g. if it isn't then +- perhaps this really is just an illegal block. */ +- return 0; +- } +- + /* + * For a directory, add logical block zero for processing even if it's + * not mapped or we'll be perennially stuck with broken "." and ".." +@@ -2503,7 +3312,7 @@ + * file be contiguous. (Which can never be true for really + * big files that are greater than a block group.) + */ +- if (!HOLE_BLKADDR(p->previous_block) && p->ino != EXT2_RESIZE_INO) { ++ if (p->previous_block && p->ino != EXT2_RESIZE_INO) { + if (p->previous_block+1 != blk) { + if (ctx->options & E2F_OPT_FRAGCHECK) { + char type = '?'; +@@ -2535,8 +3344,44 @@ + 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)) { ++ 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 the IND/DIND/TIND block could have 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. ++ * ++ * Even if we previously determined that an *IND block ++ * conflicts with critical metadata, we must still try to ++ * iterate the *IND block as if it is an *IND block to find and ++ * mark the blocks it points to. Better to be overly cautious ++ * with the used_blocks map so that we don't move the *IND ++ * block to a block that's really in use! ++ */ ++ if (p->ino != EXT2_RESIZE_INO && ++ ref_block != 0 && ++ ext2fs_test_block_bitmap2(ctx->block_metadata_map, ++ ref_block)) { ++ *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; +@@ -2641,11 +3486,6 @@ + struct problem_context *pctx; + e2fsck_t ctx; + +- /* +- * Note: This function processes blocks for the bad blocks +- * inode, which is never compressed. So we don't use HOLE_BLKADDR(). +- */ +- + if (!blk) + return 0; + +@@ -2864,12 +3704,15 @@ + old_block + i, 1, buf); + if (pctx.errcode) + fix_problem(ctx, PR_1_RELOC_READ_ERR, &pctx); +- } else +- memset(buf, 0, fs->blocksize); ++ pctx.blk = (*new_block) + i; ++ pctx.errcode = io_channel_write_blk64(fs->io, pctx.blk, ++ 1, buf); ++ } else { ++ pctx.blk = (*new_block) + i; ++ pctx.errcode = ext2fs_zero_blocks2(fs, pctx.blk, 1, ++ NULL, NULL); ++ } + +- pctx.blk = (*new_block) + i; +- pctx.errcode = io_channel_write_blk64(fs->io, pctx.blk, +- 1, buf); + if (pctx.errcode) + fix_problem(ctx, PR_1_RELOC_WRITE_ERR, &pctx); + } +@@ -2935,6 +3778,7 @@ + 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 +@@ -2953,8 +3797,10 @@ + 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); + } + } + } +@@ -2973,8 +3819,9 @@ + } 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 +@@ -2988,6 +3835,8 @@ + 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)); + } +@@ -3072,7 +3921,7 @@ + return retval; + } + +- retval = ext2fs_new_block2(fs, goal, 0, &new_block); ++ retval = ext2fs_new_block2(fs, goal, fs->block_map, &new_block); + if (retval) + return retval; + } +@@ -3081,10 +3930,37 @@ + return (0); + } + ++static errcode_t e2fsck_new_range(ext2_filsys fs, int flags, blk64_t goal, ++ blk64_t len, blk64_t *pblk, blk64_t *plen) ++{ ++ e2fsck_t ctx = (e2fsck_t) fs->priv_data; ++ errcode_t retval; ++ ++ if (ctx->block_found_map) ++ return ext2fs_new_range(fs, flags, goal, len, ++ ctx->block_found_map, pblk, plen); ++ ++ if (!fs->block_map) { ++ retval = ext2fs_read_block_bitmap(fs); ++ if (retval) ++ return retval; ++ } ++ ++ return ext2fs_new_range(fs, flags, goal, len, fs->block_map, ++ pblk, plen); ++} ++ + 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); +@@ -3093,6 +3969,28 @@ + } + } + ++static void e2fsck_block_alloc_stats_range(ext2_filsys fs, blk64_t blk, ++ blk_t num, 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_bitmap_range2(ctx->block_metadata_map, blk, num)) ++ return; ++ ++ if (ctx->block_found_map) { ++ if (inuse > 0) ++ ext2fs_mark_block_bitmap_range2(ctx->block_found_map, ++ blk, num); ++ else ++ ext2fs_unmark_block_bitmap_range2(ctx->block_found_map, ++ blk, num); ++ } ++} ++ + void e2fsck_use_inode_shortcuts(e2fsck_t ctx, int use_shortcuts) + { + ext2_filsys fs = ctx->fs; +@@ -3116,4 +4014,7 @@ + ext2fs_set_alloc_block_callback(ctx->fs, e2fsck_get_alloc_block, 0); + ext2fs_set_block_alloc_stats_callback(ctx->fs, + e2fsck_block_alloc_stats, 0); ++ ext2fs_set_new_range_callback(ctx->fs, e2fsck_new_range, NULL); ++ ext2fs_set_block_alloc_stats_range_callback(ctx->fs, ++ e2fsck_block_alloc_stats_range, NULL); + } +--- a/e2fsck/pass2.c ++++ b/e2fsck/pass2.c +@@ -47,7 +47,7 @@ + + #include "e2fsck.h" + #include "problem.h" +-#include "dict.h" ++#include "support/dict.h" + + #ifdef NO_INLINE_FUNCS + #define _INLINE_ +@@ -61,6 +61,9 @@ + * Keeps track of how many times an inode is referenced. + */ + static void deallocate_inode(e2fsck_t ctx, ext2_ino_t ino, char* block_buf); ++static int check_dir_block2(ext2_filsys fs, ++ struct ext2_db_entry2 *dir_blocks_info, ++ void *priv_data); + static int check_dir_block(ext2_filsys fs, + struct ext2_db_entry2 *dir_blocks_info, + void *priv_data); +@@ -77,6 +80,9 @@ + struct problem_context pctx; + int count, max; + e2fsck_t ctx; ++ unsigned long long list_offset; ++ unsigned long long ra_entries; ++ unsigned long long next_ra_off; + }; + + void e2fsck_pass2(e2fsck_t ctx) +@@ -96,6 +102,9 @@ + int i, depth; + problem_t code; + int bad_dir; ++ int (*check_dir_func)(ext2_filsys fs, ++ struct ext2_db_entry2 *dir_blocks_info, ++ void *priv_data); + + init_resource_track(&rtrack, ctx->fs->io); + clear_problem_context(&cd.pctx); +@@ -139,6 +148,9 @@ + cd.ctx = ctx; + cd.count = 1; + cd.max = ext2fs_dblist_count2(fs->dblist); ++ cd.list_offset = 0; ++ cd.ra_entries = ctx->readahead_kb * 1024 / ctx->fs->blocksize; ++ cd.next_ra_off = 0; + + if (ctx->progress) + (void) (ctx->progress)(ctx, 2, 0, cd.max); +@@ -146,7 +158,8 @@ + if (fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX) + ext2fs_dblist_sort2(fs->dblist, special_dir_block_cmp); + +- cd.pctx.errcode = ext2fs_dblist_iterate2(fs->dblist, check_dir_block, ++ check_dir_func = cd.ra_entries ? check_dir_block2 : check_dir_block; ++ cd.pctx.errcode = ext2fs_dblist_iterate2(fs->dblist, check_dir_func, + &cd); + if (ctx->flags & E2F_FLAG_SIGNAL_MASK || ctx->flags & E2F_FLAG_RESTART) + return; +@@ -162,11 +175,11 @@ + return; + } + +-#ifdef ENABLE_HTREE + for (i=0; (dx_dir = e2fsck_dx_dir_info_iter(ctx, &i)) != 0;) { + if (ctx->flags & E2F_FLAG_SIGNAL_MASK) + return; +- if (dx_dir->numblocks == 0) ++ if (e2fsck_dir_will_be_rehashed(ctx, dx_dir->ino) || ++ dx_dir->numblocks == 0) + continue; + clear_problem_context(&pctx); + bad_dir = 0; +@@ -250,7 +263,7 @@ + } + } + e2fsck_free_dx_dir_info(ctx); +-#endif ++ + ext2fs_free_mem(&buf); + ext2fs_free_dblist(fs->dblist); + +@@ -262,6 +275,10 @@ + ext2fs_free_inode_bitmap(ctx->inode_reg_map); + ctx->inode_reg_map = 0; + } ++ if (ctx->encrypted_dirs) { ++ ext2fs_u32_list_free(ctx->encrypted_dirs); ++ ctx->encrypted_dirs = 0; ++ } + + clear_problem_context(&pctx); + if (ctx->large_files) { +@@ -302,14 +319,14 @@ + 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); + +- return strncmp(de_a->name, de_b->name, a_len); ++ return memcmp(de_a->name, de_b->name, a_len); + } + + /* +@@ -357,7 +374,7 @@ + + 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 +386,8 @@ + 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 +411,9 @@ + (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 +435,7 @@ + + 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 +453,8 @@ + * 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'; +@@ -454,27 +475,39 @@ + */ + static int check_name(e2fsck_t ctx, + struct ext2_dir_entry *dirent, +- ext2_ino_t dir_ino EXT2FS_ATTR((unused)), + struct problem_context *pctx) + { + int i; + int fixup = -1; + int ret = 0; + +- for ( i = 0; i < (dirent->name_len & 0xFF); i++) { +- if (dirent->name[i] == '/' || dirent->name[i] == '\0') { +- if (fixup < 0) { +- fixup = fix_problem(ctx, PR_2_BAD_NAME, pctx); +- } +- if (fixup) { +- dirent->name[i] = '.'; +- ret = 1; +- } +- } ++ for ( i = 0; i < ext2fs_dirent_name_len(dirent); i++) { ++ if (dirent->name[i] != '/' && dirent->name[i] != '\0') ++ continue; ++ if (fixup < 0) ++ fixup = fix_problem(ctx, PR_2_BAD_NAME, pctx); ++ if (fixup == 0) ++ return 0; ++ dirent->name[i] = '.'; ++ ret = 1; + } + return ret; + } + ++static int encrypted_check_name(e2fsck_t ctx, ++ struct ext2_dir_entry *dirent, ++ struct problem_context *pctx) ++{ ++ if (ext2fs_dirent_name_len(dirent) < EXT4_CRYPTO_BLOCK_SIZE) { ++ if (fix_problem(ctx, PR_2_BAD_ENCRYPTED_NAME, pctx)) { ++ dirent->inode = 0; ++ return 1; ++ } ++ ext2fs_unmark_valid(ctx->fs); ++ } ++ return 0; ++} ++ + /* + * Check the directory filetype (if present) + */ +@@ -483,7 +516,7 @@ + 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 +525,7 @@ + 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,16 +551,15 @@ + pctx) == 0) + return 0; + +- dirent->name_len = (dirent->name_len & 0xFF) | should_be << 8; ++ ext2fs_dirent_set_file_type(dirent, should_be); + return 1; + } + +-#ifdef ENABLE_HTREE + 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 +570,7 @@ + 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 +585,22 @@ + #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 +611,12 @@ + #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,8 +682,8 @@ + 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 */ + + /* + * Given a busted directory, try to salvage it somehow. +@@ -642,23 +692,35 @@ + 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; + +- (void) ext2fs_get_rec_len(fs, dirent, &rec_len); +- left = fs->blocksize - *offset - rec_len; ++ /* ++ * If the space left for the entry is too small to be an entry, ++ * we can't access dirent's fields, so plumb in the values needed ++ * so that the previous entry absorbs this one. ++ */ ++ if (block_len - *offset < EXT2_DIR_ENTRY_HEADER_LEN) { ++ name_len = 0; ++ rec_len = block_len - *offset; ++ } else { ++ name_len = ext2fs_dirent_name_len(dirent); ++ (void) ext2fs_get_rec_len(fs, dirent, &rec_len); ++ } ++ left = block_len - *offset - rec_len; + + /* + * Special case of directory entry of size 8: copy what's left + * of the directory block up to cover up the invalid hole. + */ +- if ((left >= 12) && (rec_len == 8)) { +- memmove(cp, cp+8, left); +- memset(cp + left, 0, 8); ++ if ((left >= 12) && (rec_len == EXT2_DIR_ENTRY_HEADER_LEN)) { ++ memmove(cp, cp+EXT2_DIR_ENTRY_HEADER_LEN, left); ++ memset(cp + left, 0, EXT2_DIR_ENTRY_HEADER_LEN); + return; + } + /* +@@ -667,8 +729,8 @@ + * record length. + */ + if ((left < 0) && +- ((int) rec_len + left > 8) && +- ((int) name_len + 8 <= (int) rec_len + left) && ++ ((int) rec_len + left > EXT2_DIR_ENTRY_HEADER_LEN) && ++ ((int) name_len + EXT2_DIR_ENTRY_HEADER_LEN <= (int) rec_len + left) && + dirent->inode <= fs->super->s_inodes_count && + strnlen(dirent->name, name_len) == name_len) { + (void) ext2fs_set_rec_len(fs, (int) rec_len + left, dirent); +@@ -680,7 +742,7 @@ + * 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,26 +757,144 @@ + */ + 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; + } + } + ++#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; ++ ++ 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; ++ /* ++ * If there's not enough bytes to start the "second" dir block ++ * (in the EA space) then truncate everything to the first block. ++ */ ++ if (old_size > EXT4_MIN_INLINE_DATA_SIZE && ++ old_size < EXT4_MIN_INLINE_DATA_SIZE + ++ EXT2_DIR_REC_LEN(1)) { ++ old_size = EXT4_MIN_INLINE_DATA_SIZE; ++ new_size = old_size; ++ } else ++ /* Increase to the next four-byte boundary for salvaging */ ++ 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) { ++ /* Or we can't, so truncate. */ ++ 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_block2(ext2_filsys fs, ++ struct ext2_db_entry2 *db, ++ void *priv_data) ++{ ++ int err; ++ struct check_dir_struct *cd = priv_data; ++ ++ if (cd->ra_entries && cd->list_offset >= cd->next_ra_off) { ++ err = e2fsck_readahead_dblist(fs, ++ E2FSCK_RA_DBLIST_IGNORE_BLOCKCNT, ++ fs->dblist, ++ cd->list_offset + cd->ra_entries / 8, ++ cd->ra_entries); ++ if (err) ++ cd->ra_entries = 0; ++ cd->next_ra_off = cd->list_offset + (cd->ra_entries * 7 / 8); ++ } ++ ++ err = check_dir_block(fs, db, priv_data); ++ cd->list_offset++; ++ return err; ++} ++ + static int check_dir_block(ext2_filsys fs, + struct ext2_db_entry2 *db, + void *priv_data) + { + struct dx_dir_info *dx_dir; +-#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; +@@ -725,7 +905,7 @@ + ext2_ino_t subdir_parent; + __u16 links; + struct check_dir_struct *cd; +- char *buf; ++ char *buf, *ibuf; + e2fsck_t ctx; + problem_t problem; + struct ext2_dx_root_info *root; +@@ -734,9 +914,16 @@ + 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; ++ int encrypted = 0; ++ size_t max_block_size; + + cd = (struct check_dir_struct *) priv_data; +- buf = cd->buf; ++ ibuf = buf = cd->buf; + ctx = cd->ctx; + + if (ctx->flags & E2F_FLAG_SIGNAL_MASK || ctx->flags & E2F_FLAG_RESTART) +@@ -745,6 +932,16 @@ + 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 +956,16 @@ + 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,18 +986,66 @@ + #endif + + ehandler_operation(_("reading directory block")); +- cd->pctx.errcode = ext2fs_read_dir_block3(fs, block_nr, buf, 0); ++ if (inline_data_size) { ++ memset(buf, 0, fs->blocksize - 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 ++ if (db->blockcnt) ++ goto skip_first_read_swab; ++ *((__u32 *)buf) = ext2fs_le32_to_cpu(*((__u32 *)buf)); ++ cd->pctx.errcode = ext2fs_dirent_swab_in2(fs, ++ buf + EXT4_INLINE_DATA_DOTDOT_SIZE, ++ EXT4_MIN_INLINE_DATA_SIZE - EXT4_INLINE_DATA_DOTDOT_SIZE, ++ 0); ++ if (cd->pctx.errcode) ++ goto inline_read_fail; ++skip_first_read_swab: ++ if (inline_data_size <= EXT4_MIN_INLINE_DATA_SIZE || ++ !db->blockcnt) ++ goto inline_read_fail; ++ cd->pctx.errcode = ext2fs_dirent_swab_in2(fs, ++ buf + EXT4_MIN_INLINE_DATA_SIZE, ++ inline_data_size - EXT4_MIN_INLINE_DATA_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) || ++ (inline_data_size > EXT4_MIN_INLINE_DATA_SIZE && ++ inline_data_size < EXT4_MIN_INLINE_DATA_SIZE + ++ EXT2_DIR_REC_LEN(1))) && ++ 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); + if (dx_dir && dx_dir->numblocks) { + if (db->blockcnt >= dx_dir->numblocks) { +@@ -833,36 +1087,145 @@ + 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 = (dx_db->type == DX_DIRBLOCK_LEAF); + } + 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)) { ++ failed_csum = 0; ++ goto skip_checksum; ++ } ++ if (!fix_problem(cd->ctx, PR_2_LEAF_NODE_MISSING_CSUM, ++ &cd->pctx)) ++ goto skip_checksum; ++ e2fsck_rehash_dir_later(ctx, ino); ++ failed_csum = 0; ++ goto skip_checksum; ++ } ++ /* htree nodes don't use fake dirents to store checksums */ ++ if (!is_leaf) ++ de_csum_size = 0; ++ ++skip_checksum: ++ if (inline_data_size) { ++ if (db->blockcnt) { ++ buf += EXT4_MIN_INLINE_DATA_SIZE; ++ max_block_size = inline_data_size - EXT4_MIN_INLINE_DATA_SIZE; ++ /* Zero-length second block, just exit */ ++ if (max_block_size == 0) ++ return 0; ++ } else { ++ max_block_size = EXT4_MIN_INLINE_DATA_SIZE; ++ } ++ } else ++ max_block_size = fs->blocksize - de_csum_size; ++ ++ if (ctx->encrypted_dirs) ++ encrypted = ext2fs_u32_list_test(ctx->encrypted_dirs, ino); + + dict_init(&de_dict, DICTCOUNT_T_MAX, dict_de_cmp); + prev = 0; + do { + dgrp_t group; + ext2_ino_t first_unused_inode; ++ unsigned int name_len; + + problem = 0; +- dirent = (struct ext2_dir_entry *) (buf + offset); +- (void) ext2fs_get_rec_len(fs, dirent, &rec_len); +- cd->pctx.dirent = dirent; +- cd->pctx.num = offset; +- if (((offset + rec_len) > fs->blocksize) || +- (rec_len < 12) || +- ((rec_len % 4) != 0) || +- (((dirent->name_len & (unsigned) 0xFF)+8) > rec_len)) { +- if (fix_problem(ctx, PR_2_DIR_CORRUPTED, &cd->pctx)) { +- salvage_directory(fs, dirent, prev, &offset); +- dir_modified++; +- continue; +- } else +- goto abort_free_dict; ++ if (!inline_data_size || dot_state > 1) { ++ dirent = (struct ext2_dir_entry *) (buf + offset); ++ /* ++ * If there's not even space for the entry header, ++ * force salvaging this dir. ++ */ ++ if (max_block_size - offset < EXT2_DIR_ENTRY_HEADER_LEN) ++ rec_len = EXT2_DIR_REC_LEN(1); ++ else ++ (void) ext2fs_get_rec_len(fs, dirent, &rec_len); ++ cd->pctx.dirent = dirent; ++ cd->pctx.num = offset; ++ if ((offset + rec_len > max_block_size) || ++ (rec_len < 12) || ++ ((rec_len % 4) != 0) || ++ ((ext2fs_dirent_name_len(dirent) + EXT2_DIR_ENTRY_HEADER_LEN) > rec_len)) { ++ if (fix_problem(ctx, PR_2_DIR_CORRUPTED, ++ &cd->pctx)) { ++#ifdef WORDS_BIGENDIAN ++ /* ++ * On big-endian systems, if the dirent ++ * swap routine finds a rec_len that it ++ * doesn't like, it continues ++ * processing the block as if rec_len ++ * == EXT2_DIR_ENTRY_HEADER_LEN. This means that the name ++ * field gets byte swapped, which means ++ * that salvage will not detect the ++ * correct name length (unless the name ++ * has a length that's an exact ++ * multiple of four bytes), and it'll ++ * discard the entry (unnecessarily) ++ * and the rest of the dirent block. ++ * Therefore, swap the rest of the ++ * block back to disk order, run ++ * salvage, and re-swap anything after ++ * the salvaged dirent. ++ */ ++ int need_reswab = 0; ++ if (rec_len < EXT2_DIR_ENTRY_HEADER_LEN || rec_len % 4) { ++ need_reswab = 1; ++ ext2fs_dirent_swab_in2(fs, ++ ((char *)dirent) + EXT2_DIR_ENTRY_HEADER_LEN, ++ max_block_size - offset - EXT2_DIR_ENTRY_HEADER_LEN, ++ 0); ++ } ++#endif ++ salvage_directory(fs, dirent, prev, ++ &offset, ++ max_block_size); ++#ifdef WORDS_BIGENDIAN ++ if (need_reswab) { ++ (void) ext2fs_get_rec_len(fs, ++ dirent, &rec_len); ++ ext2fs_dirent_swab_in2(fs, ++ ((char *)dirent) + offset + rec_len, ++ max_block_size - offset - rec_len, ++ 0); ++ } ++#endif ++ dir_modified++; ++ continue; ++ } else ++ goto abort_free_dict; ++ } ++ } else { ++ if (dot_state == 0) { ++ memset(&dot, 0, sizeof(dot)); ++ dirent = ˙ ++ 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) { +@@ -888,6 +1251,7 @@ + /* + * 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)) { +@@ -900,8 +1264,7 @@ + * 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 +@@ -909,8 +1272,7 @@ + * 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] == '.')) { + /* +@@ -928,8 +1290,7 @@ + * 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. + */ +@@ -1033,23 +1394,27 @@ + } + } + +- if (check_name(ctx, dirent, ino, &cd->pctx)) ++ if (!encrypted && check_name(ctx, dirent, &cd->pctx)) ++ dir_modified++; ++ ++ if (encrypted && (dot_state) > 1 && ++ encrypted_check_name(ctx, dirent, &cd->pctx)) { + dir_modified++; ++ goto next; ++ } + + if (check_filetype(ctx, dirent, ino, &cd->pctx)) + dir_modified++; + +-#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; + if (hash > dx_db->max_hash) + dx_db->max_hash = hash; + } +-#endif + + /* + * If this is a directory, then mark its parent in its +@@ -1089,10 +1454,7 @@ + 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); +@@ -1106,13 +1468,28 @@ + 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 (offset < max_block_size); + #if 0 + printf("\n"); + #endif +-#ifdef ENABLE_HTREE + if (dx_db) { + #ifdef DX_DEBUG + printf("db_block %d, type %d, min_hash 0x%0x, max_hash 0x%0x\n", +@@ -1122,24 +1499,87 @@ + cd->pctx.dir = cd->pctx.ino; + if ((dx_db->type == DX_DIRBLOCK_ROOT) || + (dx_db->type == DX_DIRBLOCK_NODE)) +- parse_int_node(fs, db, cd, dx_dir, buf); ++ parse_int_node(fs, db, cd, dx_dir, buf, failed_csum); + } +-#endif /* ENABLE_HTREE */ +- if (offset != fs->blocksize) { +- cd->pctx.num = rec_len - fs->blocksize + offset; ++ ++ if (offset != max_block_size) { ++ cd->pctx.num = rec_len + offset - max_block_size; + 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) { ++ buf = ibuf; ++#ifdef WORDS_BIGENDIAN ++ if (db->blockcnt) ++ goto skip_first_write_swab; ++ *((__u32 *)buf) = ext2fs_le32_to_cpu(*((__u32 *)buf)); ++ cd->pctx.errcode = ext2fs_dirent_swab_out2(fs, ++ buf + EXT4_INLINE_DATA_DOTDOT_SIZE, ++ EXT4_MIN_INLINE_DATA_SIZE - ++ EXT4_INLINE_DATA_DOTDOT_SIZE, ++ 0); ++ if (cd->pctx.errcode) ++ goto skip_second_write_swab; ++skip_first_write_swab: ++ if (inline_data_size <= EXT4_MIN_INLINE_DATA_SIZE || ++ !db->blockcnt) ++ goto skip_second_write_swab; ++ cd->pctx.errcode = ext2fs_dirent_swab_out2(fs, ++ buf + EXT4_MIN_INLINE_DATA_SIZE, ++ inline_data_size - ++ EXT4_MIN_INLINE_DATA_SIZE, ++ 0); ++skip_second_write_swab: ++ 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; +@@ -1167,7 +1607,7 @@ + { + struct del_block *p = priv_data; + +- if (HOLE_BLKADDR(*block_nr)) ++ if (*block_nr == 0) + return 0; + if ((*block_nr < fs->super->s_first_data_block) || + (*block_nr >= ext2fs_blocks_count(fs->super))) +@@ -1201,9 +1641,9 @@ + + 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; +@@ -1224,6 +1664,10 @@ + 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--; +@@ -1402,7 +1846,6 @@ + return 0; + } + +- + /* + * allocate_dir_block --- this function allocates a new directory + * block for a particular inode; this is done if a directory has +@@ -1435,7 +1878,8 @@ + pctx->errcode = ext2fs_map_cluster_block(fs, db->ino, &inode, + db->blockcnt, &blk); + if (pctx->errcode || blk == 0) { +- pctx->errcode = ext2fs_new_block2(fs, 0, ++ blk = ext2fs_find_inode_goal(fs, db->ino, &inode, db->blockcnt); ++ pctx->errcode = ext2fs_new_block2(fs, blk, + ctx->block_found_map, &blk); + if (pctx->errcode) { + pctx->str = "ext2fs_new_block"; +@@ -1462,7 +1906,7 @@ + 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"; +--- a/e2fsck/pass3.c ++++ b/e2fsck/pass3.c +@@ -100,7 +100,8 @@ + + iter = e2fsck_dir_info_iter_begin(ctx); + while ((dir = e2fsck_dir_info_iter(ctx, iter)) != 0) { +- if (ctx->flags & E2F_FLAG_SIGNAL_MASK) ++ if (ctx->flags & E2F_FLAG_SIGNAL_MASK || ++ ctx->flags & E2F_FLAG_RESTART) + goto abort_exit; + if (ctx->progress && (ctx->progress)(ctx, 3, count++, maxdirs)) + goto abort_exit; +@@ -205,27 +206,6 @@ + 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 +228,30 @@ + } + + /* ++ * 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); +@@ -381,18 +385,44 @@ + char * block; + static const char name[] = "lost+found"; + struct problem_context pctx; ++ int will_rehash, flags; + + if (ctx->lost_and_found) + return ctx->lost_and_found; + + clear_problem_context(&pctx); + ++ will_rehash = e2fsck_dir_will_be_rehashed(ctx, EXT2_ROOT_INO); ++ if (will_rehash) { ++ flags = ctx->fs->flags; ++ ctx->fs->flags |= EXT2_FLAG_IGNORE_CSUM_ERRORS; ++ } + retval = ext2fs_lookup(fs, EXT2_ROOT_INO, name, + sizeof(name)-1, 0, &ino); ++ if (will_rehash) ++ ctx->fs->flags = (flags & EXT2_FLAG_IGNORE_CSUM_ERRORS) | ++ (ctx->fs->flags & ~EXT2_FLAG_IGNORE_CSUM_ERRORS); + 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 (fix && (inode.i_flags & EXT4_ENCRYPT_FL)) { ++ if (!fix_problem(ctx, PR_3_LPF_ENCRYPTED, &pctx)) ++ return 0; ++ goto unlink; ++ } ++ ++ if (ext2fs_check_directory(fs, ino) == 0) { + ctx->lost_and_found = ino; + return ino; + } +@@ -404,6 +434,7 @@ + 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) { +@@ -413,6 +444,15 @@ + } + (void) e2fsck_dir_info_set_parent(ctx, ino, 0); + e2fsck_adjust_inode_count(ctx, ino, -1); ++ /* ++ * If the old lost+found was a directory, we've just ++ * disconnected it from the directory tree, which ++ * means we need to restart the directory tree scan. ++ * The simplest way to do this is restart the whole ++ * e2fsck operation. ++ */ ++ if (LINUX_S_ISDIR(inode.i_mode)) ++ ctx->flags |= E2F_FLAG_RESTART; + } else if (retval != EXT2_ET_FILE_NOT_FOUND) { + pctx.errcode = retval; + fix_problem(ctx, PR_3_ERR_FIND_LPF, &pctx); +@@ -435,6 +475,12 @@ + 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 +495,12 @@ + */ + 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 +511,6 @@ + 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,11 +530,40 @@ + 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 + */ + pctx.errcode = ext2fs_link(fs, EXT2_ROOT_INO, name, ino, EXT2_FT_DIR); ++ if (pctx.errcode == EXT2_ET_DIR_NO_SPACE) { ++ pctx.errcode = ext2fs_expand_dir(fs, EXT2_ROOT_INO); ++ if (pctx.errcode) ++ goto link_error; ++ pctx.errcode = ext2fs_link(fs, EXT2_ROOT_INO, name, ino, ++ EXT2_FT_DIR); ++ } + if (pctx.errcode) { ++link_error: + pctx.str = "ext2fs_link"; + fix_problem(ctx, PR_3_CREATE_LPF_ERROR, &pctx); + return 0; +@@ -635,7 +698,7 @@ + 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 +718,9 @@ + 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 +732,7 @@ + errcode_t retval; + struct fix_dotdot_struct fp; + struct problem_context pctx; ++ int flags, will_rehash; + + fp.fs = fs; + fp.parent = parent; +@@ -682,8 +745,16 @@ + + 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 +780,7 @@ + blk64_t last_block; + errcode_t err; + e2fsck_t ctx; ++ ext2_ino_t dir; + }; + + static int expand_dir_proc(ext2_filsys fs, +@@ -760,21 +832,15 @@ + return BLOCK_ABORT; + } + es->num--; +- retval = ext2fs_write_dir_block3(fs, new_blk, block, 0); +- } else { +- retval = ext2fs_get_mem(fs->blocksize, &block); +- if (retval) { +- es->err = retval; +- return BLOCK_ABORT; +- } +- memset(block, 0, fs->blocksize); +- retval = io_channel_write_blk64(fs->io, new_blk, 1, block); +- } ++ retval = ext2fs_write_dir_block4(fs, new_blk, block, 0, ++ es->dir); ++ ext2fs_free_mem(&block); ++ } else ++ retval = ext2fs_zero_blocks2(fs, new_blk, 1, NULL, NULL); + if (retval) { + es->err = retval; + return BLOCK_ABORT; + } +- ext2fs_free_mem(&block); + *blocknr = new_blk; + ext2fs_mark_block_bitmap2(ctx->block_found_map, new_blk); + +@@ -791,7 +857,7 @@ + errcode_t retval; + struct expand_dir_struct es; + struct ext2_inode inode; +- blk64_t sz, before, after; ++ blk64_t sz; + + if (!(fs->flags & EXT2_FLAG_RW)) + return EXT2_ET_RO_FILSYS; +@@ -812,6 +878,7 @@ + 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); +--- a/e2fsck/pass4.c ++++ b/e2fsck/pass4.c +@@ -106,6 +106,15 @@ + #ifdef MTRACE + mtrace_print("Pass 4"); + #endif ++ /* ++ * Since pass4 is mostly CPU bound, start readahead of bitmaps ++ * ahead of pass 5 if we haven't already loaded them. ++ */ ++ if (ctx->readahead_kb && ++ (fs->block_map == NULL || fs->inode_map == NULL)) ++ e2fsck_readahead(fs, E2FSCK_READA_BBITMAP | ++ E2FSCK_READA_IBITMAP, ++ 0, fs->group_desc_count); + + clear_problem_context(&pctx); + +--- a/e2fsck/pass5.c ++++ b/e2fsck/pass5.c +@@ -27,6 +27,8 @@ + 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,133 @@ + 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 = NULL; ++ 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_mem(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 = NULL; ++ 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_mem(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) + { +@@ -206,11 +325,7 @@ + problem_t problem, save_problem; + int fixit, had_problem; + errcode_t retval; +- int old_desc_blocks = 0; +- int count = 0; +- int cmp_block = 0; + int redo_flag = 0; +- blk64_t super_blk, old_desc_blk, new_desc_blk; + char *actual_buf, *bitmap_buf; + + actual_buf = (char *) e2fsck_allocate_memory(ctx, fs->blocksize, +@@ -502,8 +617,7 @@ + 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; +--- a/e2fsck/problem.c ++++ b/e2fsck/problem.c +@@ -99,6 +99,9 @@ + "", /* 20 */ + }; + ++#pragma GCC diagnostic push ++#pragma GCC diagnostic ignored "-Wmissing-field-initializers" ++ + static struct e2fsck_problem problem_table[] = { + + /* Pre-Pass 1 errors */ +@@ -126,7 +129,7 @@ + " e2fsck -b 8193 <@v>\n" + " or\n" + " e2fsck -b 32768 <@v>\n\n"), +- PROMPT_NONE, PR_FATAL }, ++ PROMPT_NONE, 0 }, + + /* Filesystem size is wrong */ + { PR_0_FS_SIZE_WRONG, +@@ -435,6 +438,20 @@ + 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. "), +@@ -445,6 +462,11 @@ + N_("First_meta_bg is too big. (%N, max value %g). "), + PROMPT_CLEAR, 0 }, + ++ /* External journal has corrupt superblock */ ++ { PR_0_EXT_JOURNAL_SUPER_CSUM_INVALID, ++ N_("External @j @S checksum does not match @S. "), ++ PROMPT_FIX, PR_PREEN_OK }, ++ + /* Pass 1 errors */ + + /* Pass 1: Checking inodes, blocks, and sizes */ +@@ -692,11 +714,6 @@ + "or append-only flag set. "), + PROMPT_CLEAR, PR_PREEN_OK | PR_PREEN_NO | PR_NO_OK }, + +- /* Compression flag set on an inode when filesystem doesn't support it */ +- { PR_1_COMPR_SET, +- N_("@i %i has @cion flag set on @f without @cion support. "), +- PROMPT_CLEAR, 0 }, +- + /* Non-zero size for device, fifo or socket inode */ + { PR_1_SET_NONZSIZE, + N_("Special (@v/socket/fifo) @i %i has non-zero size. "), +@@ -765,7 +782,7 @@ + + /* Error allocating EA region allocation structure */ + { PR_1_EA_ALLOC_REGION_ABORT, +- N_("@A @a @b %b. "), ++ N_("@A @a region allocation structure. "), + PROMPT_NONE, PR_FATAL}, + + /* Error EA allocation collision */ +@@ -958,6 +975,38 @@ + 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, 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 +1020,23 @@ + 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 should be at block */ + { PR_1_COLLAPSE_DBLOCK, +@@ -987,6 +1053,67 @@ + 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 }, ++ ++ /* Bad block list says the bad block list inode is bad */ ++ { PR_1_BADBLOCKS_IN_BADBLOCKS, ++ N_("Bad block list says the bad block list @i is bad. "), ++ PROMPT_CLEAR_INODE, 0 }, ++ ++ /* Error allocating extent region allocation structure */ ++ { PR_1_EXTENT_ALLOC_REGION_ABORT, ++ N_("@A @x region allocation structure. "), ++ PROMPT_NONE, PR_FATAL}, ++ ++ /* Inode has a duplicate extent mapping */ ++ { PR_1_EXTENT_COLLISION, ++ N_("@i %i has a duplicate @x mapping\n\t(logical @b %c, @n physical @b %b, len %N)\n"), ++ PROMPT_CLEAR, 0 }, ++ ++ /* Error allocating memory for encrypted directory list */ ++ { PR_1_ALLOCATE_ENCRYPTED_DIRLIST, ++ N_("@A memory for encrypted @d list\n"), ++ PROMPT_NONE, PR_FATAL }, ++ ++ /* Inode extent tree could be more shallow */ ++ { PR_1_EXTENT_BAD_MAX_DEPTH, ++ N_("@i %i @x tree could be more shallow (%b; could be <= %c)\n"), ++ PROMPT_FIX, PR_NO_OK | PR_PREEN_NO | PR_PREEN_OK }, ++ ++ /* Inode extent tree could be more shallow */ ++ { PR_1_NO_BIGALLOC_BLOCKMAP_FILES, ++ N_("@i %i on bigalloc @f cannot be @b mapped. "), ++ PROMPT_FIX, 0 }, ++ + /* Pass 1b errors */ + + /* Pass 1B: Rescan for duplicate/bad blocks */ +@@ -1030,6 +1157,11 @@ + 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"), +@@ -1079,6 +1211,48 @@ + { PR_1D_CLONE_ERROR, + N_("Couldn't clone file: %m\n"), PROMPT_NONE, 0 }, + ++ /* Pass 1E Extent tree optimization */ ++ ++ /* Pass 1E: Optimizing extent trees */ ++ { PR_1E_PASS_HEADER, ++ N_("Pass 1E: Optimizing @x trees\n"), ++ PROMPT_NONE, PR_PREEN_NOMSG }, ++ ++ /* Failed to optimize extent tree */ ++ { PR_1E_OPTIMIZE_EXT_ERR, ++ N_("Failed to optimize @x tree %p (%i): %m\n"), ++ PROMPT_NONE, 0 }, ++ ++ /* Optimizing extent trees */ ++ { PR_1E_OPTIMIZE_EXT_HEADER, ++ N_("Optimizing @x trees: "), ++ PROMPT_NONE, PR_MSG_ONLY }, ++ ++ /* Rebuilding extent tree %d */ ++ { PR_1E_OPTIMIZE_EXT, ++ " %i", ++ PROMPT_NONE, PR_LATCH_OPTIMIZE_EXT | PR_PREEN_NOHDR}, ++ ++ /* Rebuilding extent tree end */ ++ { PR_1E_OPTIMIZE_EXT_END, ++ "\n", ++ PROMPT_NONE, PR_PREEN_NOHDR }, ++ ++ /* Internal error: extent tree depth too large */ ++ { PR_1E_MAX_EXTENT_TREE_DEPTH, ++ N_("Internal error: max extent tree depth too large (%b; expected=%c).\n"), ++ PROMPT_NONE, PR_FATAL }, ++ ++ /* Inode extent tree could be shorter */ ++ { PR_1E_CAN_COLLAPSE_EXTENT_TREE, ++ N_("@i %i @x tree (at level %b) could be shorter. "), ++ PROMPT_FIX, PR_NO_OK | PR_PREEN_NO | PR_PREEN_OK }, ++ ++ /* Inode extent tree could be narrower */ ++ { PR_1E_CAN_NARROW_EXTENT_TREE, ++ N_("@i %i @x tree (at (level %b) could be narrower. "), ++ PROMPT_FIX, PR_NO_OK | PR_PREEN_NO | PR_PREEN_OK }, ++ + /* Pass 2 errors */ + + /* Pass 2: Checking directory structure */ +@@ -1409,6 +1583,41 @@ + 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: @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 }, ++ ++ /* Encrypted directory entry is too short */ ++ { PR_2_BAD_ENCRYPTED_NAME, ++ N_("Encrypted @E is too short.\n"), ++ PROMPT_CLEAR, 0 }, ++ + /* Pass 3 errors */ + + /* Pass 3: Checking directory connectivity */ +@@ -1531,6 +1740,26 @@ + 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 }, ++ ++ /* Lost+found is encrypted */ ++ { PR_3_LPF_ENCRYPTED, ++ N_("/@l is encrypted\n"), ++ PROMPT_CLEAR, 0 }, ++ + /* Pass 3A Directory Optimization */ + + /* Pass 3A: Optimizing directories */ +@@ -1725,6 +1954,16 @@ + 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 */ +@@ -1772,8 +2011,10 @@ + { PR_LATCH_TOOBIG, PR_1_INODE_TOOBIG, 0 }, + { PR_LATCH_OPTIMIZE_DIR, PR_3A_OPTIMIZE_DIR_HEADER, PR_3A_OPTIMIZE_DIR_END }, + { PR_LATCH_BG_CHECKSUM, PR_0_GDT_CSUM_LATCH, 0 }, ++ { PR_LATCH_OPTIMIZE_EXT, PR_1E_OPTIMIZE_EXT_HEADER, PR_1E_OPTIMIZE_EXT_END }, + { -1, 0, 0 }, + }; ++#pragma GCC diagnostic pop + + static struct e2fsck_problem *find_problem(problem_t code) + { +--- a/e2fsck/problem.h ++++ b/e2fsck/problem.h +@@ -40,6 +40,7 @@ + #define PR_LATCH_TOOBIG 0x0080 /* Latch for file to big errors */ + #define PR_LATCH_OPTIMIZE_DIR 0x0090 /* Latch for optimize directories */ + #define PR_LATCH_BG_CHECKSUM 0x00A0 /* Latch for block group checksums */ ++#define PR_LATCH_OPTIMIZE_EXT 0x00B0 /* Latch for rebuild extents */ + + #define PR_LATCH(x) ((((x) & PR_LATCH_MASK) >> 4) - 1) + +@@ -249,12 +250,24 @@ + /* 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 + + /* The first_meta_bg is too big */ + #define PR_0_FIRST_META_BG_TOO_BIG 0x000049 + ++/* External journal has corrupt superblock */ ++#define PR_0_EXT_JOURNAL_SUPER_CSUM_INVALID 0x00004A ++ + /* + * Pass 1 errors + */ +@@ -403,8 +416,8 @@ + /* Immutable flag set on a device or socket inode */ + #define PR_1_SET_IMMUTABLE 0x010030 + +-/* Compression flag set on a non-compressed filesystem */ +-#define PR_1_COMPR_SET 0x010031 ++/* Compression flag set on a non-compressed filesystem -- no longer used*/ ++/* #define PR_1_COMPR_SET 0x010031 */ + + /* Non-zero size on on device, fifo or socket inode */ + #define PR_1_SET_NONZSIZE 0x010032 +@@ -564,6 +577,21 @@ + /* 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 +615,42 @@ + /* 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 ++ ++/* badblocks is in badblocks */ ++#define PR_1_BADBLOCKS_IN_BADBLOCKS 0x01007B ++ ++/* can't allocate extent region */ ++#define PR_1_EXTENT_ALLOC_REGION_ABORT 0x01007C ++ ++/* leaf extent collision */ ++#define PR_1_EXTENT_COLLISION 0x01007D ++ ++/* Error allocating memory for encrypted directory list */ ++#define PR_1_ALLOCATE_ENCRYPTED_DIRLIST 0x01007E ++ ++/* extent tree max depth too big */ ++#define PR_1_EXTENT_BAD_MAX_DEPTH 0x01007F ++ ++/* bigalloc fs cannot have blockmap files */ ++#define PR_1_NO_BIGALLOC_BLOCKMAP_FILES 0x010080 ++ + /* + * Pass 1b errors + */ +@@ -615,6 +679,9 @@ + /* 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 + +@@ -647,6 +714,33 @@ + #define PR_1D_CLONE_ERROR 0x013008 + + /* ++ * Pass 1e --- rebuilding extent trees ++ */ ++/* Pass 1e: Rebuilding extent trees */ ++#define PR_1E_PASS_HEADER 0x014000 ++ ++/* Error rehash directory */ ++#define PR_1E_OPTIMIZE_EXT_ERR 0x014001 ++ ++/* Rebuilding extent trees */ ++#define PR_1E_OPTIMIZE_EXT_HEADER 0x014002 ++ ++/* Rebuilding extent %d */ ++#define PR_1E_OPTIMIZE_EXT 0x014003 ++ ++/* Rebuilding extent tree end */ ++#define PR_1E_OPTIMIZE_EXT_END 0x014004 ++ ++/* Internal error: extent tree depth too large */ ++#define PR_1E_MAX_EXTENT_TREE_DEPTH 0x014005 ++ ++/* Inode extent tree could be shorter */ ++#define PR_1E_CAN_COLLAPSE_EXTENT_TREE 0x014006 ++ ++/* Inode extent tree could be narrower */ ++#define PR_1E_CAN_NARROW_EXTENT_TREE 0x014007 ++ ++/* + * Pass 2 errors + */ + +@@ -851,6 +945,27 @@ + /* 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 ++ ++/* Encrypted directory entry is too short */ ++#define PR_2_BAD_ENCRYPTED_NAME 0x020050 ++ + /* + * Pass 3 errors + */ +@@ -927,6 +1042,18 @@ + /* 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 ++ ++/* Lost+found is encrypted */ ++#define PR_3_LPF_ENCRYPTED 0x03001B ++ + /* + * Pass 3a --- rehashing diretories + */ +@@ -948,6 +1075,8 @@ + /* Rehashing dir end */ + #define PR_3A_OPTIMIZE_DIR_END 0x031005 + ++/* Pass 3B is really just 1E */ ++ + /* + * Pass 4 errors + */ +@@ -1049,6 +1178,12 @@ + /* 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 + */ +--- a/e2fsck/prof_err.et ++++ /dev/null +@@ -1,66 +0,0 @@ +-error_table prof +- +-error_code PROF_VERSION, "Profile version 0.0" +- +-# +-# generated by prof_tree.c +-# +-error_code PROF_MAGIC_NODE, "Bad magic value in profile_node" +-error_code PROF_NO_SECTION, "Profile section not found" +-error_code PROF_NO_RELATION, "Profile relation not found" +-error_code PROF_ADD_NOT_SECTION, +- "Attempt to add a relation to node which is not a section" +-error_code PROF_SECTION_WITH_VALUE, +- "A profile section header has a non-zero value" +-error_code PROF_BAD_LINK_LIST, "Bad linked list in profile structures" +-error_code PROF_BAD_GROUP_LVL, "Bad group level in profile structures" +-error_code PROF_BAD_PARENT_PTR, +- "Bad parent pointer in profile structures" +-error_code PROF_MAGIC_ITERATOR, "Bad magic value in profile iterator" +-error_code PROF_SET_SECTION_VALUE, "Can't set value on section node" +-error_code PROF_EINVAL, "Invalid argument passed to profile library" +-error_code PROF_READ_ONLY, "Attempt to modify read-only profile" +- +-# +-# generated by prof_parse.c +-# +- +-error_code PROF_SECTION_NOTOP, "Profile section header not at top level" +-error_code PROF_SECTION_SYNTAX, "Syntax error in profile section header" +-error_code PROF_RELATION_SYNTAX, "Syntax error in profile relation" +-error_code PROF_EXTRA_CBRACE, "Extra closing brace in profile" +-error_code PROF_MISSING_OBRACE, "Missing open brace in profile" +- +-# +-# generated by prof_init.c +-# +-error_code PROF_MAGIC_PROFILE, "Bad magic value in profile_t" +-error_code PROF_MAGIC_SECTION, "Bad magic value in profile_section_t" +-error_code PROF_TOPSECTION_ITER_NOSUPP, +- "Iteration through all top level section not supported" +-error_code PROF_INVALID_SECTION, "Invalid profile_section object" +-error_code PROF_END_OF_SECTIONS, "No more sections" +-error_code PROF_BAD_NAMESET, "Bad nameset passed to query routine" +-error_code PROF_NO_PROFILE, "No profile file open" +- +-# +-# generated by prof_file.c +-# +-error_code PROF_MAGIC_FILE, "Bad magic value in profile_file_t" +-error_code PROF_FAIL_OPEN, "Couldn't open profile file" +- +-# +-# generated by prof_set.c +-# +-error_code PROF_EXISTS, "Section already exists" +- +-# +-# generated by prof_get.c +-# +-error_code PROF_BAD_BOOLEAN, "Invalid boolean value" +-error_code PROF_BAD_INTEGER, "Invalid integer value" +- +-error_code PROF_MAGIC_FILE_DATA, "Bad magic value in profile_file_data_t" +- +- +-end +--- a/e2fsck/profile.c ++++ /dev/null +@@ -1,1905 +0,0 @@ +-/* +- * profile.c -- A simple configuration file parsing "library in a file" +- * +- * The profile library was originally written by Theodore Ts'o in 1995 +- * for use in the MIT Kerberos v5 library. It has been +- * modified/enhanced/bug-fixed over time by other members of the MIT +- * Kerberos team. This version was originally taken from the Kerberos +- * v5 distribution, version 1.4.2, and radically simplified for use in +- * e2fsprogs. (Support for locking for multi-threaded operations, +- * being able to modify and update the configuration file +- * programmatically, and Mac/Windows portability have been removed. +- * It has been folded into a single C source file to make it easier to +- * fold into an application program.) +- * +- * Copyright (C) 2005, 2006 by Theodore Ts'o. +- * +- * %Begin-Header% +- * This file may be redistributed under the terms of the GNU Public +- * License. +- * %End-Header% +- * +- * Copyright (C) 1985-2005 by the Massachusetts Institute of Technology. +- * +- * All rights reserved. +- * +- * Export of this software from the United States of America may require +- * a specific license from the United States Government. It is the +- * responsibility of any person or organization contemplating export to +- * obtain such a license before exporting. +- * +- * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and +- * distribute this software and its documentation for any purpose and +- * without fee is hereby granted, provided that the above copyright +- * notice appear in all copies and that both that copyright notice and +- * this permission notice appear in supporting documentation, and that +- * the name of M.I.T. not be used in advertising or publicity pertaining +- * to distribution of the software without specific, written prior +- * permission. Furthermore if you modify this software you must label +- * your software as modified software and not distribute it in such a +- * fashion that it might be confused with the original MIT software. +- * M.I.T. makes no representations about the suitability of this software +- * for any purpose. It is provided "as is" without express or implied +- * warranty. +- * +- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR +- * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED +- * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. +- * +- */ +- +-#include "config.h" +-#ifdef HAVE_UNISTD_H +-#include +-#endif +-#include +-#ifdef HAVE_STDLIB_H +-#include +-#endif +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#ifdef HAVE_PWD_H +-#include +-#endif +- +-#include +-#include "profile.h" +-#include "prof_err.h" +- +-#undef STAT_ONCE_PER_SECOND +-#undef HAVE_STAT +- +-/* +- * prof_int.h +- */ +- +-typedef long prf_magic_t; +- +-/* +- * This is the structure which stores the profile information for a +- * particular configuration file. +- */ +-struct _prf_file_t { +- prf_magic_t magic; +- char *filespec; +-#ifdef STAT_ONCE_PER_SECOND +- time_t last_stat; +-#endif +- time_t timestamp; /* time tree was last updated from file */ +- int flags; /* r/w, dirty */ +- int upd_serial; /* incremented when data changes */ +- struct profile_node *root; +- struct _prf_file_t *next; +-}; +- +-typedef struct _prf_file_t *prf_file_t; +- +-/* +- * The profile flags +- */ +-#define PROFILE_FILE_RW 0x0001 +-#define PROFILE_FILE_DIRTY 0x0002 +-#define PROFILE_FILE_NO_RELOAD 0x0004 +- +-/* +- * This structure defines the high-level, user visible profile_t +- * object, which is used as a handle by users who need to query some +- * configuration file(s) +- */ +-struct _profile_t { +- prf_magic_t magic; +- prf_file_t first_file; +-}; +- +-/* +- * Used by the profile iterator in prof_get.c +- */ +-#define PROFILE_ITER_LIST_SECTION 0x0001 +-#define PROFILE_ITER_SECTIONS_ONLY 0x0002 +-#define PROFILE_ITER_RELATIONS_ONLY 0x0004 +- +-#define PROFILE_ITER_FINAL_SEEN 0x0100 +- +-/* +- * Check if a filespec is last in a list (NULL on UNIX, invalid FSSpec on MacOS +- */ +- +-#define PROFILE_LAST_FILESPEC(x) (((x) == NULL) || ((x)[0] == '\0')) +- +-struct profile_node { +- errcode_t magic; +- char *name; +- char *value; +- int group_level; +- unsigned int final:1; /* Indicate don't search next file */ +- unsigned int deleted:1; +- struct profile_node *first_child; +- struct profile_node *parent; +- struct profile_node *next, *prev; +-}; +- +-#define CHECK_MAGIC(node) \ +- if ((node)->magic != PROF_MAGIC_NODE) \ +- return PROF_MAGIC_NODE; +- +-/* profile parser declarations */ +-struct parse_state { +- int state; +- int group_level; +- int line_num; +- struct profile_node *root_section; +- struct profile_node *current_section; +-}; +- +-static const char *default_filename = ""; +- +-static profile_syntax_err_cb_t syntax_err_cb; +- +-static errcode_t parse_line(char *line, struct parse_state *state); +- +-#ifdef DEBUG_PROGRAM +-static errcode_t profile_write_tree_file +- (struct profile_node *root, FILE *dstfile); +- +-static errcode_t profile_write_tree_to_buffer +- (struct profile_node *root, char **buf); +-#endif +- +- +-static void profile_free_node +- (struct profile_node *relation); +- +-static errcode_t profile_create_node +- (const char *name, const char *value, +- struct profile_node **ret_node); +- +-#ifdef DEBUG_PROGRAM +-static errcode_t profile_verify_node +- (struct profile_node *node); +-#endif +- +-static errcode_t profile_add_node +- (struct profile_node *section, +- const char *name, const char *value, +- struct profile_node **ret_node); +- +-static errcode_t profile_find_node +- (struct profile_node *section, +- const char *name, const char *value, +- int section_flag, void **state, +- struct profile_node **node); +- +-static errcode_t profile_node_iterator +- (void **iter_p, struct profile_node **ret_node, +- char **ret_name, char **ret_value); +- +-static errcode_t profile_open_file +- (const char * file, prf_file_t *ret_prof); +- +-static errcode_t profile_update_file +- (prf_file_t prf); +- +-static void profile_free_file +- (prf_file_t profile); +- +-static errcode_t profile_get_value(profile_t profile, const char *name, +- const char *subname, const char *subsubname, +- const char **ret_value); +- +- +-/* +- * prof_init.c --- routines that manipulate the user-visible profile_t +- * object. +- */ +- +-static int compstr(const void *m1, const void *m2) +-{ +- const char *s1 = *((const char * const *) m1); +- const char *s2 = *((const char * const *) m2); +- +- return strcmp(s1, s2); +-} +- +-static void free_list(char **list) +-{ +- char **cp; +- +- if (list == 0) +- return; +- +- for (cp = list; *cp; cp++) +- free(*cp); +- free(list); +-} +- +-static errcode_t get_dirlist(const char *dirname, char***ret_array) +-{ +- DIR *dir; +- struct dirent *de; +- struct stat st; +- errcode_t retval; +- char *fn, *cp; +- char **array = 0, **new_array; +- int max = 0, num = 0; +- +- dir = opendir(dirname); +- if (!dir) +- return errno; +- +- while ((de = readdir(dir)) != NULL) { +- for (cp = de->d_name; *cp; cp++) { +- if (!isalnum(*cp) && +- (*cp != '-') && +- (*cp != '_')) +- break; +- } +- if (*cp) +- continue; +- fn = malloc(strlen(dirname) + strlen(de->d_name) + 2); +- if (!fn) { +- retval = ENOMEM; +- goto errout; +- } +- sprintf(fn, "%s/%s", dirname, de->d_name); +- if ((stat(fn, &st) < 0) || !S_ISREG(st.st_mode)) { +- free(fn); +- continue; +- } +- if (num >= max) { +- max += 10; +- new_array = realloc(array, sizeof(char *) * (max+1)); +- if (!new_array) { +- retval = ENOMEM; +- free(fn); +- goto errout; +- } +- array = new_array; +- } +- array[num++] = fn; +- } +- if (array) { +- qsort(array, num, sizeof(char *), compstr); +- array[num++] = 0; +- } +- *ret_array = array; +- closedir(dir); +- return 0; +-errout: +- if (array) +- array[num] = 0; +- closedir(dir); +- free_list(array); +- return retval; +-} +- +-errcode_t +-profile_init(const char **files, profile_t *ret_profile) +-{ +- const char **fs; +- profile_t profile; +- prf_file_t new_file, *last; +- errcode_t retval = 0; +- char **cpp, *cp, **array = 0; +- +- profile = malloc(sizeof(struct _profile_t)); +- if (!profile) +- return ENOMEM; +- memset(profile, 0, sizeof(struct _profile_t)); +- profile->magic = PROF_MAGIC_PROFILE; +- last = &profile->first_file; +- +- /* if the filenames list is not specified return an empty profile */ +- if ( files ) { +- for (fs = files; !PROFILE_LAST_FILESPEC(*fs); fs++) { +- if (array) +- free_list(array); +- array = NULL; +- retval = get_dirlist(*fs, &array); +- if (retval == 0) { +- if (!array) +- continue; +- for (cpp = array; (cp = *cpp); cpp++) { +- retval = profile_open_file(cp, &new_file); +- if (retval == EACCES) +- continue; +- if (retval) +- goto errout; +- *last = new_file; +- last = &new_file->next; +- } +- } else if ((retval != ENOTDIR) && +- strcmp(*fs, default_filename)) +- goto errout; +- +- retval = profile_open_file(*fs, &new_file); +- /* if this file is missing, skip to the next */ +- if (retval == ENOENT || retval == EACCES) { +- continue; +- } +- if (retval) +- goto errout; +- *last = new_file; +- last = &new_file->next; +- } +- /* +- * If all the files were not found, return the appropriate error. +- */ +- if (!profile->first_file) { +- retval = ENOENT; +- goto errout; +- } +- } +- +- free_list(array); +- *ret_profile = profile; +- return 0; +-errout: +- free_list(array); +- profile_release(profile); +- return retval; +-} +- +-void +-profile_release(profile_t profile) +-{ +- prf_file_t p, next; +- +- if (!profile || profile->magic != PROF_MAGIC_PROFILE) +- return; +- +- for (p = profile->first_file; p; p = next) { +- next = p->next; +- profile_free_file(p); +- } +- profile->magic = 0; +- free(profile); +-} +- +-/* +- * This function sets the value of the pseudo file "". If +- * the file "" had previously been passed to profile_init(), +- * then def_string parameter will be parsed and used as the profile +- * information for the "" file. +- */ +-errcode_t profile_set_default(profile_t profile, const char *def_string) +-{ +- struct parse_state state; +- prf_file_t prf; +- errcode_t retval; +- const char *in; +- char *line, *p, *end; +- int line_size, len; +- +- if (!def_string || !profile || profile->magic != PROF_MAGIC_PROFILE) +- return PROF_MAGIC_PROFILE; +- +- for (prf = profile->first_file; prf; prf = prf->next) { +- if (strcmp(prf->filespec, default_filename) == 0) +- break; +- } +- if (!prf) +- return 0; +- +- if (prf->root) { +- profile_free_node(prf->root); +- prf->root = 0; +- } +- +- memset(&state, 0, sizeof(struct parse_state)); +- retval = profile_create_node("(root)", 0, &state.root_section); +- if (retval) +- return retval; +- +- line = 0; +- line_size = 0; +- in = def_string; +- while (*in) { +- end = strchr(in, '\n'); +- len = end ? (end - in) : (int) strlen(in); +- if (len >= line_size) { +- line_size = len+1; +- p = realloc(line, line_size); +- if (!p) { +- retval = ENOMEM; +- goto errout; +- } +- line = p; +- } +- memcpy(line, in, len); +- line[len] = 0; +- retval = parse_line(line, &state); +- if (retval) { +- errout: +- if (syntax_err_cb) +- (syntax_err_cb)(prf->filespec, retval, +- state.line_num); +- free(line); +- if (prf->root) +- profile_free_node(prf->root); +- return retval; +- } +- if (!end) +- break; +- in = end+1; +- } +- prf->root = state.root_section; +- free(line); +- +- return 0; +-} +- +-/* +- * prof_file.c ---- routines that manipulate an individual profile file. +- */ +- +-errcode_t profile_open_file(const char * filespec, +- prf_file_t *ret_prof) +-{ +- prf_file_t prf; +- errcode_t retval; +- char *home_env = 0; +- unsigned int len; +- char *expanded_filename; +- +- prf = malloc(sizeof(struct _prf_file_t)); +- if (!prf) +- return ENOMEM; +- memset(prf, 0, sizeof(struct _prf_file_t)); +- prf->magic = PROF_MAGIC_FILE; +- +- len = strlen(filespec)+1; +- if (filespec[0] == '~' && filespec[1] == '/') { +- home_env = getenv("HOME"); +-#ifdef HAVE_PWD_H +- if (home_env == NULL) { +-#ifdef HAVE_GETWUID_R +- struct passwd *pw, pwx; +- uid_t uid; +- char pwbuf[BUFSIZ]; +- +- uid = getuid(); +- if (!getpwuid_r(uid, &pwx, pwbuf, sizeof(pwbuf), &pw) +- && pw != NULL && pw->pw_dir[0] != 0) +- home_env = pw->pw_dir; +-#else +- struct passwd *pw; +- +- pw = getpwuid(getuid()); +- home_env = pw->pw_dir; +-#endif +- } +-#endif +- if (home_env) +- len += strlen(home_env); +- } +- expanded_filename = malloc(len); +- if (expanded_filename == 0) { +- profile_free_file(prf); +- return errno; +- } +- if (home_env) { +- strcpy(expanded_filename, home_env); +- strcat(expanded_filename, filespec+1); +- } else +- memcpy(expanded_filename, filespec, len); +- +- prf->filespec = expanded_filename; +- +- if (strcmp(prf->filespec, default_filename) != 0) { +- retval = profile_update_file(prf); +- if (retval) { +- profile_free_file(prf); +- return retval; +- } +- } +- +- *ret_prof = prf; +- return 0; +-} +- +-errcode_t profile_update_file(prf_file_t prf) +-{ +- errcode_t retval; +-#ifdef HAVE_STAT +- struct stat st; +-#ifdef STAT_ONCE_PER_SECOND +- time_t now; +-#endif +-#endif +- FILE *f; +- char buf[2048]; +- struct parse_state state; +- +- if (prf->flags & PROFILE_FILE_NO_RELOAD) +- return 0; +- +-#ifdef HAVE_STAT +-#ifdef STAT_ONCE_PER_SECOND +- now = time(0); +- if (now == prf->last_stat && prf->root != NULL) { +- return 0; +- } +-#endif +- if (stat(prf->filespec, &st)) { +- retval = errno; +- return retval; +- } +-#ifdef STAT_ONCE_PER_SECOND +- prf->last_stat = now; +-#endif +- if (st.st_mtime == prf->timestamp && prf->root != NULL) { +- return 0; +- } +- if (prf->root) { +- profile_free_node(prf->root); +- prf->root = 0; +- } +-#else +- /* +- * If we don't have the stat() call, assume that our in-core +- * memory image is correct. That is, we won't reread the +- * profile file if it changes. +- */ +- if (prf->root) { +- return 0; +- } +-#endif +- memset(&state, 0, sizeof(struct parse_state)); +- retval = profile_create_node("(root)", 0, &state.root_section); +- if (retval) +- return retval; +- errno = 0; +- f = fopen(prf->filespec, "r"); +- if (f == NULL) { +- retval = errno; +- if (retval == 0) +- retval = ENOENT; +- return retval; +- } +- prf->upd_serial++; +- while (!feof(f)) { +- if (fgets(buf, sizeof(buf), f) == NULL) +- break; +- retval = parse_line(buf, &state); +- if (retval) { +- if (syntax_err_cb) +- (syntax_err_cb)(prf->filespec, retval, +- state.line_num); +- fclose(f); +- return retval; +- } +- } +- prf->root = state.root_section; +- +- fclose(f); +- +-#ifdef HAVE_STAT +- prf->timestamp = st.st_mtime; +-#endif +- return 0; +-} +- +-void profile_free_file(prf_file_t prf) +-{ +- if (prf->root) +- profile_free_node(prf->root); +- free(prf->filespec); +- free(prf); +-} +- +-/* Begin the profile parser */ +- +-profile_syntax_err_cb_t profile_set_syntax_err_cb(profile_syntax_err_cb_t hook) +-{ +- profile_syntax_err_cb_t old; +- +- old = syntax_err_cb; +- syntax_err_cb = hook; +- return(old); +-} +- +-#define STATE_INIT_COMMENT 0 +-#define STATE_STD_LINE 1 +-#define STATE_GET_OBRACE 2 +- +-static char *skip_over_blanks(char *cp) +-{ +- while (*cp && isspace((int) (*cp))) +- cp++; +- return cp; +-} +- +-static int end_or_comment(char ch) +-{ +- return (ch == 0 || ch == '#' || ch == ';'); +-} +- +-static char *skip_over_nonblanks(char *cp) +-{ +- while (!end_or_comment(*cp) && !isspace(*cp)) +- cp++; +- return cp; +-} +- +-static void strip_line(char *line) +-{ +- char *p = line + strlen(line); +- while (p > line && (p[-1] == '\n' || p[-1] == '\r')) +- *p-- = 0; +-} +- +-static void parse_quoted_string(char *str) +-{ +- char *to, *from; +- +- to = from = str; +- +- for (to = from = str; *from && *from != '"'; to++, from++) { +- if (*from == '\\') { +- from++; +- switch (*from) { +- case 'n': +- *to = '\n'; +- break; +- case 't': +- *to = '\t'; +- break; +- case 'b': +- *to = '\b'; +- break; +- default: +- *to = *from; +- } +- continue; +- } +- *to = *from; +- } +- *to = '\0'; +-} +- +-static errcode_t parse_line(char *line, struct parse_state *state) +-{ +- char *cp, ch, *tag, *value; +- char *p; +- errcode_t retval; +- struct profile_node *node; +- int do_subsection = 0; +- void *iter = 0; +- +- state->line_num++; +- if (state->state == STATE_GET_OBRACE) { +- cp = skip_over_blanks(line); +- if (*cp != '{') +- return PROF_MISSING_OBRACE; +- state->state = STATE_STD_LINE; +- return 0; +- } +- if (state->state == STATE_INIT_COMMENT) { +- if (line[0] != '[') +- return 0; +- state->state = STATE_STD_LINE; +- } +- +- if (*line == 0) +- return 0; +- strip_line(line); +- cp = skip_over_blanks(line); +- ch = *cp; +- if (end_or_comment(ch)) +- return 0; +- if (ch == '[') { +- if (state->group_level > 0) +- return PROF_SECTION_NOTOP; +- cp++; +- cp = skip_over_blanks(cp); +- p = strchr(cp, ']'); +- if (p == NULL) +- return PROF_SECTION_SYNTAX; +- if (*cp == '"') { +- cp++; +- parse_quoted_string(cp); +- } else { +- *p-- = '\0'; +- while (isspace(*p) && (p > cp)) +- *p-- = '\0'; +- if (*cp == 0) +- return PROF_SECTION_SYNTAX; +- } +- retval = profile_find_node(state->root_section, cp, 0, 1, +- &iter, &state->current_section); +- if (retval == PROF_NO_SECTION) { +- retval = profile_add_node(state->root_section, +- cp, 0, +- &state->current_section); +- if (retval) +- return retval; +- } else if (retval) +- return retval; +- +- /* +- * Finish off the rest of the line. +- */ +- cp = p+1; +- if (*cp == '*') { +- state->current_section->final = 1; +- cp++; +- } +- /* +- * Spaces or comments after ']' should not be fatal +- */ +- cp = skip_over_blanks(cp); +- if (!end_or_comment(*cp)) +- return PROF_SECTION_SYNTAX; +- return 0; +- } +- if (ch == '}') { +- if (state->group_level == 0) +- return PROF_EXTRA_CBRACE; +- if (*(cp+1) == '*') +- state->current_section->final = 1; +- state->current_section = state->current_section->parent; +- state->group_level--; +- return 0; +- } +- /* +- * Parse the relations +- */ +- tag = cp; +- cp = strchr(cp, '='); +- if (!cp) +- return PROF_RELATION_SYNTAX; +- if (cp == tag) +- return PROF_RELATION_SYNTAX; +- *cp = '\0'; +- if (*tag == '"') { +- tag++; +- parse_quoted_string(tag); +- } else { +- /* Look for whitespace on left-hand side. */ +- p = skip_over_nonblanks(tag); +- if (*p) +- *p++ = 0; +- p = skip_over_blanks(p); +- /* If we have more non-whitespace, it's an error. */ +- if (*p) +- return PROF_RELATION_SYNTAX; +- } +- +- cp = skip_over_blanks(cp+1); +- value = cp; +- ch = value[0]; +- if (ch == '"') { +- value++; +- parse_quoted_string(value); +- } else if (end_or_comment(ch)) { +- do_subsection++; +- state->state = STATE_GET_OBRACE; +- } else if (value[0] == '{') { +- cp = skip_over_blanks(value+1); +- ch = *cp; +- if (end_or_comment(ch)) +- do_subsection++; +- else +- return PROF_RELATION_SYNTAX; +- } else { +- cp = skip_over_nonblanks(value); +- p = skip_over_blanks(cp); +- ch = *p; +- *cp = 0; +- if (!end_or_comment(ch)) +- return PROF_RELATION_SYNTAX; +- } +- if (do_subsection) { +- p = strchr(tag, '*'); +- if (p) +- *p = '\0'; +- retval = profile_add_node(state->current_section, +- tag, 0, &state->current_section); +- if (retval) +- return retval; +- if (p) +- state->current_section->final = 1; +- state->group_level++; +- return 0; +- } +- p = strchr(tag, '*'); +- if (p) +- *p = '\0'; +- profile_add_node(state->current_section, tag, value, &node); +- if (p) +- node->final = 1; +- return 0; +-} +- +-#ifdef DEBUG_PROGRAM +-/* +- * Return TRUE if the string begins or ends with whitespace +- */ +-static int need_double_quotes(char *str) +-{ +- if (!str || !*str) +- return 0; +- if (isspace((int) (*str)) ||isspace((int) (*(str + strlen(str) - 1)))) +- return 1; +- if (strchr(str, '\n') || strchr(str, '\t') || strchr(str, '\b') || +- strchr(str, ' ') || strchr(str, '#') || strchr(str, ';')) +- return 1; +- return 0; +-} +- +-/* +- * Output a string with double quotes, doing appropriate backquoting +- * of characters as necessary. +- */ +-static void output_quoted_string(char *str, void (*cb)(const char *,void *), +- void *data) +-{ +- char ch; +- char buf[2]; +- +- cb("\"", data); +- if (!str) { +- cb("\"", data); +- return; +- } +- buf[1] = 0; +- while ((ch = *str++)) { +- switch (ch) { +- case '\\': +- cb("\\\\", data); +- break; +- case '\n': +- cb("\\n", data); +- break; +- case '\t': +- cb("\\t", data); +- break; +- case '\b': +- cb("\\b", data); +- break; +- default: +- /* This would be a lot faster if we scanned +- forward for the next "interesting" +- character. */ +- buf[0] = ch; +- cb(buf, data); +- break; +- } +- } +- cb("\"", data); +-} +- +-#ifndef EOL +-#define EOL "\n" +-#endif +- +-/* Errors should be returned, not ignored! */ +-static void dump_profile(struct profile_node *root, int level, +- void (*cb)(const char *, void *), void *data) +-{ +- int i; +- struct profile_node *p; +- void *iter; +- long retval; +- +- iter = 0; +- do { +- retval = profile_find_node(root, 0, 0, 0, &iter, &p); +- if (retval) +- break; +- for (i=0; i < level; i++) +- cb("\t", data); +- if (need_double_quotes(p->name)) +- output_quoted_string(p->name, cb, data); +- else +- cb(p->name, data); +- cb(" = ", data); +- if (need_double_quotes(p->value)) +- output_quoted_string(p->value, cb, data); +- else +- cb(p->value, data); +- cb(EOL, data); +- } while (iter != 0); +- +- iter = 0; +- do { +- retval = profile_find_node(root, 0, 0, 1, &iter, &p); +- if (retval) +- break; +- if (level == 0) { /* [xxx] */ +- cb("[", data); +- if (need_double_quotes(p->name)) +- output_quoted_string(p->name, cb, data); +- else +- cb(p->name, data); +- cb("]", data); +- cb(p->final ? "*" : "", data); +- cb(EOL, data); +- dump_profile(p, level+1, cb, data); +- cb(EOL, data); +- } else { /* xxx = { ... } */ +- for (i=0; i < level; i++) +- cb("\t", data); +- if (need_double_quotes(p->name)) +- output_quoted_string(p->name, cb, data); +- else +- cb(p->name, data); +- cb(" = {", data); +- cb(EOL, data); +- dump_profile(p, level+1, cb, data); +- for (i=0; i < level; i++) +- cb("\t", data); +- cb("}", data); +- cb(p->final ? "*" : "", data); +- cb(EOL, data); +- } +- } while (iter != 0); +-} +- +-static void dump_profile_to_file_cb(const char *str, void *data) +-{ +- fputs(str, data); +-} +- +-errcode_t profile_write_tree_file(struct profile_node *root, FILE *dstfile) +-{ +- dump_profile(root, 0, dump_profile_to_file_cb, dstfile); +- return 0; +-} +- +-struct prof_buf { +- char *base; +- size_t cur, max; +- int err; +-}; +- +-static void add_data_to_buffer(struct prof_buf *b, const void *d, size_t len) +-{ +- if (b->err) +- return; +- if (b->max - b->cur < len) { +- size_t newsize; +- char *newptr; +- +- newsize = b->max + (b->max >> 1) + len + 1024; +- newptr = realloc(b->base, newsize); +- if (newptr == NULL) { +- b->err = 1; +- return; +- } +- b->base = newptr; +- b->max = newsize; +- } +- memcpy(b->base + b->cur, d, len); +- b->cur += len; /* ignore overflow */ +-} +- +-static void dump_profile_to_buffer_cb(const char *str, void *data) +-{ +- add_data_to_buffer((struct prof_buf *)data, str, strlen(str)); +-} +- +-errcode_t profile_write_tree_to_buffer(struct profile_node *root, +- char **buf) +-{ +- struct prof_buf prof_buf = { 0, 0, 0, 0 }; +- +- dump_profile(root, 0, dump_profile_to_buffer_cb, &prof_buf); +- if (prof_buf.err) { +- *buf = NULL; +- return ENOMEM; +- } +- add_data_to_buffer(&prof_buf, "", 1); /* append nul */ +- if (prof_buf.max - prof_buf.cur > (prof_buf.max >> 3)) { +- char *newptr = realloc(prof_buf.base, prof_buf.cur); +- if (newptr) +- prof_buf.base = newptr; +- } +- *buf = prof_buf.base; +- return 0; +-} +-#endif +- +-/* +- * prof_tree.c --- these routines maintain the parse tree of the +- * config file. +- * +- * All of the details of how the tree is stored is abstracted away in +- * this file; all of the other profile routines build, access, and +- * modify the tree via the accessor functions found in this file. +- * +- * Each node may represent either a relation or a section header. +- * +- * A section header must have its value field set to 0, and may a one +- * or more child nodes, pointed to by first_child. +- * +- * A relation has as its value a pointer to allocated memory +- * containing a string. Its first_child pointer must be null. +- * +- */ +- +-/* +- * Free a node, and any children +- */ +-void profile_free_node(struct profile_node *node) +-{ +- struct profile_node *child, *next; +- +- if (node->magic != PROF_MAGIC_NODE) +- return; +- +- free(node->name); +- free(node->value); +- +- for (child=node->first_child; child; child = next) { +- next = child->next; +- profile_free_node(child); +- } +- node->magic = 0; +- +- free(node); +-} +- +-#ifndef HAVE_STRDUP +-#undef strdup +-#define strdup MYstrdup +-static char *MYstrdup (const char *s) +-{ +- size_t sz = strlen(s) + 1; +- char *p = malloc(sz); +- if (p != 0) +- memcpy(p, s, sz); +- return p; +-} +-#endif +- +-/* +- * Create a node +- */ +-errcode_t profile_create_node(const char *name, const char *value, +- struct profile_node **ret_node) +-{ +- struct profile_node *new; +- +- new = malloc(sizeof(struct profile_node)); +- if (!new) +- return ENOMEM; +- memset(new, 0, sizeof(struct profile_node)); +- new->name = strdup(name); +- if (new->name == 0) { +- profile_free_node(new); +- return ENOMEM; +- } +- if (value) { +- new->value = strdup(value); +- if (new->value == 0) { +- profile_free_node(new); +- return ENOMEM; +- } +- } +- new->magic = PROF_MAGIC_NODE; +- +- *ret_node = new; +- return 0; +-} +- +-/* +- * This function verifies that all of the representation invarients of +- * the profile are true. If not, we have a programming bug somewhere, +- * probably in this file. +- */ +-#ifdef DEBUG_PROGRAM +-errcode_t profile_verify_node(struct profile_node *node) +-{ +- struct profile_node *p, *last; +- errcode_t retval; +- +- CHECK_MAGIC(node); +- +- if (node->value && node->first_child) +- return PROF_SECTION_WITH_VALUE; +- +- last = 0; +- for (p = node->first_child; p; last = p, p = p->next) { +- if (p->prev != last) +- return PROF_BAD_LINK_LIST; +- if (last && (last->next != p)) +- return PROF_BAD_LINK_LIST; +- if (node->group_level+1 != p->group_level) +- return PROF_BAD_GROUP_LVL; +- if (p->parent != node) +- return PROF_BAD_PARENT_PTR; +- retval = profile_verify_node(p); +- if (retval) +- return retval; +- } +- return 0; +-} +-#endif +- +-/* +- * Add a node to a particular section +- */ +-errcode_t profile_add_node(struct profile_node *section, const char *name, +- const char *value, struct profile_node **ret_node) +-{ +- errcode_t retval; +- struct profile_node *p, *last, *new; +- +- CHECK_MAGIC(section); +- +- if (section->value) +- return PROF_ADD_NOT_SECTION; +- +- /* +- * Find the place to insert the new node. We look for the +- * place *after* the last match of the node name, since +- * order matters. +- */ +- for (p=section->first_child, last = 0; p; last = p, p = p->next) { +- int cmp; +- cmp = strcmp(p->name, name); +- if (cmp > 0) +- break; +- } +- retval = profile_create_node(name, value, &new); +- if (retval) +- return retval; +- new->group_level = section->group_level+1; +- new->deleted = 0; +- new->parent = section; +- new->prev = last; +- new->next = p; +- if (p) +- p->prev = new; +- if (last) +- last->next = new; +- else +- section->first_child = new; +- if (ret_node) +- *ret_node = new; +- return 0; +-} +- +-/* +- * Iterate through the section, returning the nodes which match +- * the given name. If name is NULL, then interate through all the +- * nodes in the section. If section_flag is non-zero, only return the +- * section which matches the name; don't return relations. If value +- * is non-NULL, then only return relations which match the requested +- * value. (The value argument is ignored if section_flag is non-zero.) +- * +- * The first time this routine is called, the state pointer must be +- * null. When this profile_find_node_relation() returns, if the state +- * pointer is non-NULL, then this routine should be called again. +- * (This won't happen if section_flag is non-zero, obviously.) +- * +- */ +-errcode_t profile_find_node(struct profile_node *section, const char *name, +- const char *value, int section_flag, void **state, +- struct profile_node **node) +-{ +- struct profile_node *p; +- +- CHECK_MAGIC(section); +- p = *state; +- if (p) { +- CHECK_MAGIC(p); +- } else +- p = section->first_child; +- +- for (; p; p = p->next) { +- if (name && (strcmp(p->name, name))) +- continue; +- if (section_flag) { +- if (p->value) +- continue; +- } else { +- if (!p->value) +- continue; +- if (value && (strcmp(p->value, value))) +- continue; +- } +- if (p->deleted) +- continue; +- /* A match! */ +- if (node) +- *node = p; +- break; +- } +- if (p == 0) { +- *state = 0; +- return section_flag ? PROF_NO_SECTION : PROF_NO_RELATION; +- } +- /* +- * OK, we've found one match; now let's try to find another +- * one. This way, if we return a non-zero state pointer, +- * there's guaranteed to be another match that's returned. +- */ +- for (p = p->next; p; p = p->next) { +- if (name && (strcmp(p->name, name))) +- continue; +- if (section_flag) { +- if (p->value) +- continue; +- } else { +- if (!p->value) +- continue; +- if (value && (strcmp(p->value, value))) +- continue; +- } +- /* A match! */ +- break; +- } +- *state = p; +- return 0; +-} +- +-/* +- * This is a general-purpose iterator for returning all nodes that +- * match the specified name array. +- */ +-struct profile_iterator { +- prf_magic_t magic; +- profile_t profile; +- int flags; +- const char *const *names; +- const char *name; +- prf_file_t file; +- int file_serial; +- int done_idx; +- struct profile_node *node; +- int num; +-}; +- +-errcode_t +-profile_iterator_create(profile_t profile, const char *const *names, int flags, +- void **ret_iter) +-{ +- struct profile_iterator *iter; +- int done_idx = 0; +- +- if (profile == 0) +- return PROF_NO_PROFILE; +- if (profile->magic != PROF_MAGIC_PROFILE) +- return PROF_MAGIC_PROFILE; +- if (!names) +- return PROF_BAD_NAMESET; +- if (!(flags & PROFILE_ITER_LIST_SECTION)) { +- if (!names[0]) +- return PROF_BAD_NAMESET; +- done_idx = 1; +- } +- +- if ((iter = malloc(sizeof(struct profile_iterator))) == NULL) +- return ENOMEM; +- +- iter->magic = PROF_MAGIC_ITERATOR; +- iter->profile = profile; +- iter->names = names; +- iter->flags = flags; +- iter->file = profile->first_file; +- iter->done_idx = done_idx; +- iter->node = 0; +- iter->num = 0; +- *ret_iter = iter; +- return 0; +-} +- +-void profile_iterator_free(void **iter_p) +-{ +- struct profile_iterator *iter; +- +- if (!iter_p) +- return; +- iter = *iter_p; +- if (!iter || iter->magic != PROF_MAGIC_ITERATOR) +- return; +- free(iter); +- *iter_p = 0; +-} +- +-/* +- * Note: the returned character strings in ret_name and ret_value +- * points to the stored character string in the parse string. Before +- * this string value is returned to a calling application +- * (profile_node_iterator is not an exported interface), it should be +- * strdup()'ed. +- */ +-errcode_t profile_node_iterator(void **iter_p, struct profile_node **ret_node, +- char **ret_name, char **ret_value) +-{ +- struct profile_iterator *iter = *iter_p; +- struct profile_node *section, *p; +- const char *const *cpp; +- errcode_t retval; +- int skip_num = 0; +- +- if (!iter || iter->magic != PROF_MAGIC_ITERATOR) +- return PROF_MAGIC_ITERATOR; +- if (iter->file && iter->file->magic != PROF_MAGIC_FILE) +- return PROF_MAGIC_FILE; +- /* +- * If the file has changed, then the node pointer is invalid, +- * so we'll have search the file again looking for it. +- */ +- if (iter->node && (iter->file && +- iter->file->upd_serial != iter->file_serial)) { +- iter->flags &= ~PROFILE_ITER_FINAL_SEEN; +- skip_num = iter->num; +- iter->node = 0; +- } +- if (iter->node && iter->node->magic != PROF_MAGIC_NODE) { +- return PROF_MAGIC_NODE; +- } +-get_new_file: +- if (iter->node == 0) { +- if (iter->file == 0 || +- (iter->flags & PROFILE_ITER_FINAL_SEEN)) { +- profile_iterator_free(iter_p); +- if (ret_node) +- *ret_node = 0; +- if (ret_name) +- *ret_name = 0; +- if (ret_value) +- *ret_value =0; +- return 0; +- } +- if ((retval = profile_update_file(iter->file))) { +- if (retval == ENOENT || retval == EACCES) { +- /* XXX memory leak? */ +- iter->file = iter->file->next; +- skip_num = 0; +- retval = 0; +- goto get_new_file; +- } else { +- profile_iterator_free(iter_p); +- return retval; +- } +- } +- iter->file_serial = iter->file->upd_serial; +- /* +- * Find the section to list if we are a LIST_SECTION, +- * or find the containing section if not. +- */ +- section = iter->file->root; +- for (cpp = iter->names; cpp[iter->done_idx]; cpp++) { +- for (p=section->first_child; p; p = p->next) { +- if (!strcmp(p->name, *cpp) && !p->value) +- break; +- } +- if (!p) { +- section = 0; +- break; +- } +- section = p; +- if (p->final) +- iter->flags |= PROFILE_ITER_FINAL_SEEN; +- } +- if (!section) { +- iter->file = iter->file->next; +- skip_num = 0; +- goto get_new_file; +- } +- iter->name = *cpp; +- iter->node = section->first_child; +- } +- /* +- * OK, now we know iter->node is set up correctly. Let's do +- * the search. +- */ +- for (p = iter->node; p; p = p->next) { +- if (iter->name && strcmp(p->name, iter->name)) +- continue; +- if ((iter->flags & PROFILE_ITER_SECTIONS_ONLY) && +- p->value) +- continue; +- if ((iter->flags & PROFILE_ITER_RELATIONS_ONLY) && +- !p->value) +- continue; +- if (skip_num > 0) { +- skip_num--; +- continue; +- } +- if (p->deleted) +- continue; +- break; +- } +- iter->num++; +- if (!p) { +- iter->file = iter->file->next; +- iter->node = 0; +- skip_num = 0; +- goto get_new_file; +- } +- if ((iter->node = p->next) == NULL) +- iter->file = iter->file->next; +- if (ret_node) +- *ret_node = p; +- if (ret_name) +- *ret_name = p->name; +- if (ret_value) +- *ret_value = p->value; +- return 0; +-} +- +- +-/* +- * prof_get.c --- routines that expose the public interfaces for +- * querying items from the profile. +- * +- */ +- +-/* +- * This function only gets the first value from the file; it is a +- * helper function for profile_get_string, profile_get_integer, etc. +- */ +-errcode_t profile_get_value(profile_t profile, const char *name, +- const char *subname, const char *subsubname, +- const char **ret_value) +-{ +- errcode_t retval; +- void *state; +- char *value; +- const char *names[4]; +- +- names[0] = name; +- names[1] = subname; +- names[2] = subsubname; +- names[3] = 0; +- +- if ((retval = profile_iterator_create(profile, names, +- PROFILE_ITER_RELATIONS_ONLY, +- &state))) +- return retval; +- +- if ((retval = profile_node_iterator(&state, 0, 0, &value))) +- goto cleanup; +- +- if (value) +- *ret_value = value; +- else +- retval = PROF_NO_RELATION; +- +-cleanup: +- profile_iterator_free(&state); +- return retval; +-} +- +-errcode_t +-profile_get_string(profile_t profile, const char *name, const char *subname, +- const char *subsubname, const char *def_val, +- char **ret_string) +-{ +- const char *value; +- errcode_t retval; +- +- if (profile) { +- retval = profile_get_value(profile, name, subname, +- subsubname, &value); +- if (retval == PROF_NO_SECTION || retval == PROF_NO_RELATION) +- value = def_val; +- else if (retval) +- return retval; +- } else +- value = def_val; +- +- if (value) { +- *ret_string = malloc(strlen(value)+1); +- if (*ret_string == 0) +- return ENOMEM; +- strcpy(*ret_string, value); +- } else +- *ret_string = 0; +- return 0; +-} +- +-errcode_t +-profile_get_integer(profile_t profile, const char *name, const char *subname, +- const char *subsubname, int def_val, int *ret_int) +-{ +- const char *value; +- errcode_t retval; +- char *end_value; +- long ret_long; +- +- *ret_int = def_val; +- if (profile == 0) +- return 0; +- +- retval = profile_get_value(profile, name, subname, subsubname, &value); +- if (retval == PROF_NO_SECTION || retval == PROF_NO_RELATION) { +- *ret_int = def_val; +- return 0; +- } else if (retval) +- return retval; +- +- if (value[0] == 0) +- /* Empty string is no good. */ +- return PROF_BAD_INTEGER; +- errno = 0; +- ret_long = strtol(value, &end_value, 0); +- +- /* Overflow or underflow. */ +- if ((ret_long == LONG_MIN || ret_long == LONG_MAX) && errno != 0) +- return PROF_BAD_INTEGER; +- /* Value outside "int" range. */ +- if ((long) (int) ret_long != ret_long) +- return PROF_BAD_INTEGER; +- /* Garbage in string. */ +- if (end_value != value + strlen (value)) +- return PROF_BAD_INTEGER; +- +- +- *ret_int = ret_long; +- return 0; +-} +- +-errcode_t +-profile_get_uint(profile_t profile, const char *name, const char *subname, +- const char *subsubname, unsigned int def_val, +- unsigned int *ret_int) +-{ +- const char *value; +- errcode_t retval; +- char *end_value; +- unsigned long ret_long; +- +- *ret_int = def_val; +- if (profile == 0) +- return 0; +- +- retval = profile_get_value(profile, name, subname, subsubname, &value); +- if (retval == PROF_NO_SECTION || retval == PROF_NO_RELATION) { +- *ret_int = def_val; +- return 0; +- } else if (retval) +- return retval; +- +- if (value[0] == 0) +- /* Empty string is no good. */ +- return PROF_BAD_INTEGER; +- errno = 0; +- ret_long = strtoul(value, &end_value, 0); +- +- /* Overflow or underflow. */ +- if ((ret_long == ULONG_MAX) && errno != 0) +- return PROF_BAD_INTEGER; +- /* Value outside "int" range. */ +- if ((unsigned long) (unsigned int) ret_long != ret_long) +- return PROF_BAD_INTEGER; +- /* Garbage in string. */ +- if (end_value != value + strlen (value)) +- return PROF_BAD_INTEGER; +- +- *ret_int = ret_long; +- return 0; +-} +- +-errcode_t +-profile_get_double(profile_t profile, const char *name, const char *subname, +- const char *subsubname, double def_val, double *ret_double) +-{ +- const char *value; +- errcode_t retval; +- char *end_value; +- double double_val; +- +- *ret_double = def_val; +- if (profile == 0) +- return 0; +- +- retval = profile_get_value(profile, name, subname, subsubname, &value); +- if (retval == PROF_NO_SECTION || retval == PROF_NO_RELATION) { +- *ret_double = def_val; +- return 0; +- } else if (retval) +- return retval; +- +- if (value[0] == 0) +- /* Empty string is no good. */ +- return PROF_BAD_INTEGER; +- errno = 0; +- double_val = strtod(value, &end_value); +- +- /* Overflow or underflow. */ +- if (errno != 0) +- return PROF_BAD_INTEGER; +- /* Garbage in string. */ +- if (end_value != value + strlen(value)) +- return PROF_BAD_INTEGER; +- +- *ret_double = double_val; +- return 0; +-} +- +-static const char *const conf_yes[] = { +- "y", "yes", "true", "t", "1", "on", +- 0, +-}; +- +-static const char *const conf_no[] = { +- "n", "no", "false", "nil", "0", "off", +- 0, +-}; +- +-static errcode_t +-profile_parse_boolean(const char *s, int *ret_boolean) +-{ +- const char *const *p; +- +- if (ret_boolean == NULL) +- return PROF_EINVAL; +- +- for(p=conf_yes; *p; p++) { +- if (!strcasecmp(*p,s)) { +- *ret_boolean = 1; +- return 0; +- } +- } +- +- for(p=conf_no; *p; p++) { +- if (!strcasecmp(*p,s)) { +- *ret_boolean = 0; +- return 0; +- } +- } +- +- return PROF_BAD_BOOLEAN; +-} +- +-errcode_t +-profile_get_boolean(profile_t profile, const char *name, const char *subname, +- const char *subsubname, int def_val, int *ret_boolean) +-{ +- const char *value; +- errcode_t retval; +- +- if (profile == 0) { +- *ret_boolean = def_val; +- return 0; +- } +- +- retval = profile_get_value(profile, name, subname, subsubname, &value); +- if (retval == PROF_NO_SECTION || retval == PROF_NO_RELATION) { +- *ret_boolean = def_val; +- return 0; +- } else if (retval) +- return retval; +- +- return profile_parse_boolean (value, ret_boolean); +-} +- +-errcode_t +-profile_iterator(void **iter_p, char **ret_name, char **ret_value) +-{ +- char *name, *value; +- errcode_t retval; +- +- retval = profile_node_iterator(iter_p, 0, &name, &value); +- if (retval) +- return retval; +- +- if (ret_name) { +- if (name) { +- *ret_name = malloc(strlen(name)+1); +- if (!*ret_name) +- return ENOMEM; +- strcpy(*ret_name, name); +- } else +- *ret_name = 0; +- } +- if (ret_value) { +- if (value) { +- *ret_value = malloc(strlen(value)+1); +- if (!*ret_value) { +- if (ret_name) { +- free(*ret_name); +- *ret_name = 0; +- } +- return ENOMEM; +- } +- strcpy(*ret_value, value); +- } else +- *ret_value = 0; +- } +- return 0; +-} +- +-#ifdef DEBUG_PROGRAM +- +-/* +- * test_profile.c --- testing program for the profile routine +- */ +- +-#include "argv_parse.h" +-#include "profile_helpers.h" +- +-const char *program_name = "test_profile"; +- +-#define PRINT_VALUE 1 +-#define PRINT_VALUES 2 +- +-static void do_cmd(profile_t profile, char **argv) +-{ +- errcode_t retval; +- const char **names, *value; +- char **values, **cpp; +- char *cmd; +- int print_status; +- +- cmd = *(argv); +- names = (const char **) argv + 1; +- print_status = 0; +- retval = 0; +- if (cmd == 0) +- return; +- if (!strcmp(cmd, "query")) { +- retval = profile_get_values(profile, names, &values); +- print_status = PRINT_VALUES; +- } else if (!strcmp(cmd, "query1")) { +- const char *name = 0; +- const char *subname = 0; +- const char *subsubname = 0; +- +- name = names[0]; +- if (name) +- subname = names[1]; +- if (subname) +- subsubname = names[2]; +- if (subsubname && names[3]) { +- fprintf(stderr, +- "Only 3 levels are allowed with query1\n"); +- retval = EINVAL; +- } else +- retval = profile_get_value(profile, name, subname, +- subsubname, &value); +- print_status = PRINT_VALUE; +- } else if (!strcmp(cmd, "list_sections")) { +- retval = profile_get_subsection_names(profile, names, +- &values); +- print_status = PRINT_VALUES; +- } else if (!strcmp(cmd, "list_relations")) { +- retval = profile_get_relation_names(profile, names, +- &values); +- print_status = PRINT_VALUES; +- } else if (!strcmp(cmd, "dump")) { +- retval = profile_write_tree_file +- (profile->first_file->root, stdout); +-#if 0 +- } else if (!strcmp(cmd, "clear")) { +- retval = profile_clear_relation(profile, names); +- } else if (!strcmp(cmd, "update")) { +- retval = profile_update_relation(profile, names+2, +- *names, *(names+1)); +-#endif +- } else if (!strcmp(cmd, "verify")) { +- retval = profile_verify_node +- (profile->first_file->root); +-#if 0 +- } else if (!strcmp(cmd, "rename_section")) { +- retval = profile_rename_section(profile, names+1, *names); +- } else if (!strcmp(cmd, "add")) { +- value = *names; +- if (strcmp(value, "NULL") == 0) +- value = NULL; +- retval = profile_add_relation(profile, names+1, value); +- } else if (!strcmp(cmd, "flush")) { +- retval = profile_flush(profile); +-#endif +- } else { +- printf("Invalid command.\n"); +- } +- if (retval) { +- com_err(cmd, retval, ""); +- print_status = 0; +- } +- switch (print_status) { +- case PRINT_VALUE: +- printf("%s\n", value); +- break; +- case PRINT_VALUES: +- for (cpp = values; *cpp; cpp++) +- printf("%s\n", *cpp); +- profile_free_list(values); +- break; +- } +-} +- +-static void do_batchmode(profile_t profile) +-{ +- int argc, ret; +- char **argv; +- char buf[256]; +- +- while (!feof(stdin)) { +- if (fgets(buf, sizeof(buf), stdin) == NULL) +- break; +- printf(">%s", buf); +- ret = argv_parse(buf, &argc, &argv); +- if (ret != 0) { +- printf("Argv_parse returned %d!\n", ret); +- continue; +- } +- do_cmd(profile, argv); +- printf("\n"); +- argv_free(argv); +- } +- profile_release(profile); +- exit(0); +- +-} +- +-void syntax_err_report(const char *filename, long err, int line_num) +-{ +- fprintf(stderr, "Syntax error in %s, line number %d: %s\n", +- filename, line_num, error_message(err)); +- exit(1); +-} +- +-const char *default_str = "[foo]\n\tbar=quux\n\tsub = {\n\t\twin = true\n}\n"; +- +-int main(int argc, char **argv) +-{ +- profile_t profile; +- long retval; +- char *cmd; +- +- if (argc < 2) { +- fprintf(stderr, "Usage: %s filename [cmd argset]\n", program_name); +- exit(1); +- } +- +- initialize_prof_error_table(); +- +- profile_set_syntax_err_cb(syntax_err_report); +- +- retval = profile_init_path(argv[1], &profile); +- if (retval) { +- com_err(program_name, retval, "while initializing profile"); +- exit(1); +- } +- retval = profile_set_default(profile, default_str); +- if (retval) { +- com_err(program_name, retval, "while setting default"); +- exit(1); +- } +- +- cmd = *(argv+2); +- if (!cmd || !strcmp(cmd, "batch")) +- do_batchmode(profile); +- else +- do_cmd(profile, argv+2); +- profile_release(profile); +- +- return 0; +-} +- +-#endif +--- a/e2fsck/profile.h ++++ /dev/null +@@ -1,107 +0,0 @@ +-/* +- * profile.h +- * +- * Copyright (C) 2005 by Theodore Ts'o. +- * +- * %Begin-Header% +- * This file may be redistributed under the terms of the GNU Public +- * License. +- * %End-Header% +- * +- * Copyright (C) 1985-2005 by the Massachusetts Institute of Technology. +- * +- * All rights reserved. +- * +- * Export of this software from the United States of America may require +- * a specific license from the United States Government. It is the +- * responsibility of any person or organization contemplating export to +- * obtain such a license before exporting. +- * +- * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and +- * distribute this software and its documentation for any purpose and +- * without fee is hereby granted, provided that the above copyright +- * notice appear in all copies and that both that copyright notice and +- * this permission notice appear in supporting documentation, and that +- * the name of M.I.T. not be used in advertising or publicity pertaining +- * to distribution of the software without specific, written prior +- * permission. Furthermore if you modify this software you must label +- * your software as modified software and not distribute it in such a +- * fashion that it might be confused with the original MIT software. +- * M.I.T. makes no representations about the suitability of this software +- * for any purpose. It is provided "as is" without express or implied +- * warranty. +- * +- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR +- * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED +- * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. +- */ +- +-#ifndef _PROFILE_H +-#define _PROFILE_H +- +-typedef struct _profile_t *profile_t; +- +-typedef void (*profile_syntax_err_cb_t)(const char *file, long err, +- int line_num); +- +-/* +- * Used by the profile iterator in prof_get.c +- */ +-#define PROFILE_ITER_LIST_SECTION 0x0001 +-#define PROFILE_ITER_SECTIONS_ONLY 0x0002 +-#define PROFILE_ITER_RELATIONS_ONLY 0x0004 +- +-#ifdef __cplusplus +-extern "C" { +-#endif /* __cplusplus */ +- +-long profile_init +- (const char * *files, profile_t *ret_profile); +- +-void profile_release +- (profile_t profile); +- +-long profile_set_default +- (profile_t profile, const char *def_string); +- +-long profile_get_string +- (profile_t profile, const char *name, const char *subname, +- const char *subsubname, const char *def_val, +- char **ret_string); +-long profile_get_integer +- (profile_t profile, const char *name, const char *subname, +- const char *subsubname, int def_val, +- int *ret_default); +- +-long profile_get_uint +- (profile_t profile, const char *name, const char *subname, +- const char *subsubname, unsigned int def_val, +- unsigned int *ret_int); +- +-long profile_get_double +- (profile_t profile, const char *name, const char *subname, +- const char *subsubname, double def_val, +- double *ret_float); +- +-long profile_get_boolean +- (profile_t profile, const char *name, const char *subname, +- const char *subsubname, int def_val, +- int *ret_default); +- +-long profile_iterator_create +- (profile_t profile, const char *const *names, +- int flags, void **ret_iter); +- +-void profile_iterator_free +- (void **iter_p); +- +-long profile_iterator +- (void **iter_p, char **ret_name, char **ret_value); +- +-profile_syntax_err_cb_t profile_set_syntax_err_cb(profile_syntax_err_cb_t hook); +- +-#ifdef __cplusplus +-} +-#endif /* __cplusplus */ +- +-#endif /* _KRB5_H */ +--- a/e2fsck/profile_helpers.c ++++ /dev/null +@@ -1,310 +0,0 @@ +-/* +- * profile_helpers.c -- Helper functions for the profile library +- * +- * These functions are not part of the "core" profile library, and do +- * not require access to the internal functions and data structures of +- * the profile library. They are mainly convenience functions for +- * programs that want to do something unusual such as obtaining the +- * list of sections or relations, or accessing multiple values from a +- * relation that is listed more than once. This functionality can all +- * be done using the profile_iterator abstraction, but it is less +- * convenient. +- * +- * Copyright (C) 2006 by Theodore Ts'o. +- * +- * %Begin-Header% +- * This file may be redistributed under the terms of the GNU Public +- * License. +- * %End-Header% +- */ +- +-#include "config.h" +-#include +-#include +-#include +- +-#include +-#include "profile.h" +-#include "prof_err.h" +- +-/* +- * These functions --- init_list(), end_list(), and add_to_list() are +- * internal functions used to build up a null-terminated char ** list +- * of strings to be returned by functions like profile_get_values. +- * +- * The profile_string_list structure is used for internal booking +- * purposes to build up the list, which is returned in *ret_list by +- * the end_list() function. +- * +- * The publicly exported interface for freeing char** list is +- * profile_free_list(). +- */ +- +-struct profile_string_list { +- char **list; +- int num; +- int max; +-}; +- +-/* +- * Initialize the string list abstraction. +- */ +-static errcode_t init_list(struct profile_string_list *list) +-{ +- list->num = 0; +- list->max = 10; +- list->list = malloc(list->max * sizeof(char *)); +- if (list->list == 0) +- return ENOMEM; +- list->list[0] = 0; +- return 0; +-} +- +-/* +- * Free any memory left over in the string abstraction, returning the +- * built up list in *ret_list if it is non-null. +- */ +-static void end_list(struct profile_string_list *list, char ***ret_list) +-{ +- char **cp; +- +- if (list == 0) +- return; +- +- if (ret_list) { +- *ret_list = list->list; +- return; +- } else { +- for (cp = list->list; *cp; cp++) +- free(*cp); +- free(list->list); +- } +- list->num = list->max = 0; +- list->list = 0; +-} +- +-/* +- * Add a string to the list. +- */ +-static errcode_t add_to_list(struct profile_string_list *list, char *str) +-{ +- char **newlist; +- int newmax; +- +- if (list->num+1 >= list->max) { +- newmax = list->max + 10; +- newlist = realloc(list->list, newmax * sizeof(char *)); +- if (newlist == 0) +- return ENOMEM; +- list->max = newmax; +- list->list = newlist; +- } +- +- list->list[list->num++] = str; +- list->list[list->num] = 0; +- return 0; +-} +- +-/* +- * Return TRUE if the string is already a member of the list. +- */ +-static int is_list_member(struct profile_string_list *list, const char *str) +-{ +- char **cpp; +- +- if (!list->list) +- return 0; +- +- for (cpp = list->list; *cpp; cpp++) { +- if (!strcmp(*cpp, str)) +- return 1; +- } +- return 0; +-} +- +-/* +- * This function frees a null-terminated list as returned by +- * profile_get_values. +- */ +-void profile_free_list(char **list) +-{ +- char **cp; +- +- if (list == 0) +- return; +- +- for (cp = list; *cp; cp++) +- free(*cp); +- free(list); +-} +- +-errcode_t +-profile_get_values(profile_t profile, const char *const *names, +- char ***ret_values) +-{ +- errcode_t retval; +- void *state; +- char *value; +- struct profile_string_list values; +- +- if ((retval = profile_iterator_create(profile, names, +- PROFILE_ITER_RELATIONS_ONLY, +- &state))) +- return retval; +- +- if ((retval = init_list(&values))) +- return retval; +- +- do { +- if ((retval = profile_iterator(&state, 0, &value))) +- goto cleanup; +- if (value) +- add_to_list(&values, value); +- } while (state); +- +- if (values.num == 0) { +- retval = PROF_NO_RELATION; +- goto cleanup; +- } +- +- end_list(&values, ret_values); +- return 0; +- +-cleanup: +- end_list(&values, 0); +- return retval; +-} +- +-/* +- * This function will return the list of the names of subections in the +- * under the specified section name. +- */ +-errcode_t +-profile_get_subsection_names(profile_t profile, const char **names, +- char ***ret_names) +-{ +- errcode_t retval; +- void *state; +- char *name; +- struct profile_string_list values; +- +- if ((retval = profile_iterator_create(profile, names, +- PROFILE_ITER_LIST_SECTION | PROFILE_ITER_SECTIONS_ONLY, +- &state))) +- return retval; +- +- if ((retval = init_list(&values))) +- return retval; +- +- do { +- if ((retval = profile_iterator(&state, &name, 0))) +- goto cleanup; +- if (name) +- add_to_list(&values, name); +- } while (state); +- +- end_list(&values, ret_names); +- return 0; +- +-cleanup: +- end_list(&values, 0); +- return retval; +-} +- +-/* +- * This function will return the list of the names of relations in the +- * under the specified section name. +- */ +-errcode_t +-profile_get_relation_names(profile_t profile, const char **names, +- char ***ret_names) +-{ +- errcode_t retval; +- void *state; +- char *name; +- struct profile_string_list values; +- +- if ((retval = profile_iterator_create(profile, names, +- PROFILE_ITER_LIST_SECTION | PROFILE_ITER_RELATIONS_ONLY, +- &state))) +- return retval; +- +- if ((retval = init_list(&values))) +- return retval; +- +- do { +- if ((retval = profile_iterator(&state, &name, 0))) +- goto cleanup; +- if (name) { +- if (is_list_member(&values, name)) +- free(name); +- else +- add_to_list(&values, name); +- } +- } while (state); +- +- end_list(&values, ret_names); +- return 0; +- +-cleanup: +- end_list(&values, 0); +- return retval; +-} +- +- +-void +-profile_release_string(char *str) +-{ +- free(str); +-} +- +-errcode_t +-profile_init_path(const char * filepath, +- profile_t *ret_profile) +-{ +- int n_entries, i; +- unsigned int ent_len; +- const char *s, *t; +- char **filenames; +- errcode_t retval; +- +- /* count the distinct filename components */ +- for(s = filepath, n_entries = 1; *s; s++) { +- if (*s == ':') +- n_entries++; +- } +- +- /* the array is NULL terminated */ +- filenames = (char **) malloc((n_entries+1) * sizeof(char*)); +- if (filenames == 0) +- return ENOMEM; +- +- /* measure, copy, and skip each one */ +- for(s = filepath, i=0; (t = strchr(s, ':')) || (t=s+strlen(s)); s=t+1, i++) { +- ent_len = t-s; +- filenames[i] = (char*) malloc(ent_len + 1); +- if (filenames[i] == 0) { +- /* if malloc fails, free the ones that worked */ +- while(--i >= 0) free(filenames[i]); +- free(filenames); +- return ENOMEM; +- } +- strncpy(filenames[i], s, ent_len); +- filenames[i][ent_len] = 0; +- if (*t == 0) { +- i++; +- break; +- } +- } +- /* cap the array */ +- filenames[i] = 0; +- +- retval = profile_init((const char **) filenames, +- ret_profile); +- +- /* count back down and free the entries */ +- while(--i >= 0) free(filenames[i]); +- free(filenames); +- +- return retval; +-} +--- a/e2fsck/profile_helpers.h ++++ /dev/null +@@ -1,28 +0,0 @@ +-/* +- * profile_helpers.h -- Function prototypes for profile helper functions +- * +- * Copyright (C) 2006 by Theodore Ts'o. +- * +- * %Begin-Header% +- * This file may be redistributed under the terms of the GNU Public +- * License. +- * %End-Header% +- */ +- +-long profile_get_values +- (profile_t profile, const char *const *names, char ***ret_values); +- +-void profile_free_list +- (char **list); +- +-long profile_get_relation_names +- (profile_t profile, const char **names, char ***ret_names); +- +-long profile_get_subsection_names +- (profile_t profile, const char **names, char ***ret_names); +- +-void profile_release_string (char *str); +- +-long profile_init_path +- (const char * filelist, profile_t *ret_profile); +- +--- a/e2fsck/quota.c ++++ b/e2fsck/quota.c +@@ -15,7 +15,6 @@ + + #include "e2fsck.h" + #include "problem.h" +-#include "quota/quotaio.h" + + static void move_quota_inode(ext2_filsys fs, ext2_ino_t from_ino, + ext2_ino_t to_ino, int qtype) +--- /dev/null ++++ b/e2fsck/readahead.c +@@ -0,0 +1,252 @@ ++/* ++ * readahead.c -- Prefetch filesystem metadata to speed up fsck. ++ * ++ * 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% ++ */ ++ ++#include "config.h" ++#include ++ ++#include "e2fsck.h" ++ ++#undef DEBUG ++ ++#ifdef DEBUG ++# define dbg_printf(f, a...) do {printf(f, ## a); fflush(stdout); } while (0) ++#else ++# define dbg_printf(f, a...) ++#endif ++ ++struct read_dblist { ++ errcode_t err; ++ blk64_t run_start; ++ blk64_t run_len; ++ int flags; ++}; ++ ++static int readahead_dir_block(ext2_filsys fs, struct ext2_db_entry2 *db, ++ void *priv_data) ++{ ++ struct read_dblist *pr = priv_data; ++ e2_blkcnt_t count = (pr->flags & E2FSCK_RA_DBLIST_IGNORE_BLOCKCNT ? ++ 1 : db->blockcnt); ++ ++ if (!pr->run_len || db->blk != pr->run_start + pr->run_len) { ++ if (pr->run_len) { ++ pr->err = io_channel_cache_readahead(fs->io, ++ pr->run_start, ++ pr->run_len); ++ dbg_printf("readahead start=%llu len=%llu err=%d\n", ++ pr->run_start, pr->run_len, ++ (int)pr->err); ++ } ++ pr->run_start = db->blk; ++ pr->run_len = 0; ++ } ++ pr->run_len += count; ++ ++ return pr->err ? DBLIST_ABORT : 0; ++} ++ ++errcode_t e2fsck_readahead_dblist(ext2_filsys fs, int flags, ++ ext2_dblist dblist, ++ unsigned long long start, ++ unsigned long long count) ++{ ++ errcode_t err; ++ struct read_dblist pr; ++ ++ dbg_printf("%s: flags=0x%x\n", __func__, flags); ++ if (flags & ~E2FSCK_RA_DBLIST_ALL_FLAGS) ++ return EXT2_ET_INVALID_ARGUMENT; ++ ++ memset(&pr, 0, sizeof(pr)); ++ pr.flags = flags; ++ err = ext2fs_dblist_iterate3(dblist, readahead_dir_block, start, ++ count, &pr); ++ if (pr.err) ++ return pr.err; ++ if (err) ++ return err; ++ ++ if (pr.run_len) ++ err = io_channel_cache_readahead(fs->io, pr.run_start, ++ pr.run_len); ++ ++ return err; ++} ++ ++static errcode_t e2fsck_readahead_bitmap(ext2_filsys fs, ++ ext2fs_block_bitmap ra_map) ++{ ++ blk64_t start, end, out; ++ errcode_t err; ++ ++ start = 1; ++ end = ext2fs_blocks_count(fs->super) - 1; ++ ++ err = ext2fs_find_first_set_block_bitmap2(ra_map, start, end, &out); ++ while (err == 0) { ++ start = out; ++ err = ext2fs_find_first_zero_block_bitmap2(ra_map, start, end, ++ &out); ++ if (err == ENOENT) { ++ out = end; ++ err = 0; ++ } else if (err) ++ break; ++ ++ err = io_channel_cache_readahead(fs->io, start, out - start); ++ if (err) ++ break; ++ start = out; ++ err = ext2fs_find_first_set_block_bitmap2(ra_map, start, end, ++ &out); ++ } ++ ++ if (err == ENOENT) ++ err = 0; ++ ++ return err; ++} ++ ++/* Try not to spew bitmap range errors for readahead */ ++static errcode_t mark_bmap_range(ext2fs_block_bitmap map, ++ blk64_t blk, unsigned int num) ++{ ++ if (blk >= ext2fs_get_generic_bmap_start(map) && ++ blk + num <= ext2fs_get_generic_bmap_end(map)) ++ ext2fs_mark_block_bitmap_range2(map, blk, num); ++ else ++ return EXT2_ET_INVALID_ARGUMENT; ++ return 0; ++} ++ ++static errcode_t mark_bmap(ext2fs_block_bitmap map, blk64_t blk) ++{ ++ if (blk >= ext2fs_get_generic_bmap_start(map) && ++ blk <= ext2fs_get_generic_bmap_end(map)) ++ ext2fs_mark_block_bitmap2(map, blk); ++ else ++ return EXT2_ET_INVALID_ARGUMENT; ++ return 0; ++} ++ ++errcode_t e2fsck_readahead(ext2_filsys fs, int flags, dgrp_t start, ++ dgrp_t ngroups) ++{ ++ blk64_t super, old_gdt, new_gdt; ++ blk_t blocks; ++ dgrp_t i; ++ ext2fs_block_bitmap ra_map = NULL; ++ dgrp_t end = start + ngroups; ++ errcode_t err = 0; ++ ++ dbg_printf("%s: flags=0x%x start=%d groups=%d\n", __func__, flags, ++ start, ngroups); ++ if (flags & ~E2FSCK_READA_ALL_FLAGS) ++ return EXT2_ET_INVALID_ARGUMENT; ++ ++ if (end > fs->group_desc_count) ++ end = fs->group_desc_count; ++ ++ if (flags == 0) ++ return 0; ++ ++ err = ext2fs_allocate_block_bitmap(fs, "readahead bitmap", ++ &ra_map); ++ if (err) ++ return err; ++ ++ for (i = start; i < end; i++) { ++ err = ext2fs_super_and_bgd_loc2(fs, i, &super, &old_gdt, ++ &new_gdt, &blocks); ++ if (err) ++ break; ++ ++ if (flags & E2FSCK_READA_SUPER) { ++ err = mark_bmap(ra_map, super); ++ if (err) ++ break; ++ } ++ ++ if (flags & E2FSCK_READA_GDT) { ++ err = mark_bmap_range(ra_map, ++ old_gdt ? old_gdt : new_gdt, ++ blocks); ++ if (err) ++ break; ++ } ++ ++ if ((flags & E2FSCK_READA_BBITMAP) && ++ !ext2fs_bg_flags_test(fs, i, EXT2_BG_BLOCK_UNINIT) && ++ ext2fs_bg_free_blocks_count(fs, i) < ++ fs->super->s_blocks_per_group) { ++ super = ext2fs_block_bitmap_loc(fs, i); ++ err = mark_bmap(ra_map, super); ++ if (err) ++ break; ++ } ++ ++ if ((flags & E2FSCK_READA_IBITMAP) && ++ !ext2fs_bg_flags_test(fs, i, EXT2_BG_INODE_UNINIT) && ++ ext2fs_bg_free_inodes_count(fs, i) < ++ fs->super->s_inodes_per_group) { ++ super = ext2fs_inode_bitmap_loc(fs, i); ++ err = mark_bmap(ra_map, super); ++ if (err) ++ break; ++ } ++ ++ if ((flags & E2FSCK_READA_ITABLE) && ++ ext2fs_bg_free_inodes_count(fs, i) < ++ fs->super->s_inodes_per_group) { ++ super = ext2fs_inode_table_loc(fs, i); ++ blocks = fs->inode_blocks_per_group - ++ (ext2fs_bg_itable_unused(fs, i) * ++ EXT2_INODE_SIZE(fs->super) / fs->blocksize); ++ err = mark_bmap_range(ra_map, super, blocks); ++ if (err) ++ break; ++ } ++ } ++ ++ if (!err) ++ err = e2fsck_readahead_bitmap(fs, ra_map); ++ ++ ext2fs_free_block_bitmap(ra_map); ++ return err; ++} ++ ++int e2fsck_can_readahead(ext2_filsys fs) ++{ ++ errcode_t err; ++ ++ err = io_channel_cache_readahead(fs->io, 0, 1); ++ dbg_printf("%s: supp=%d\n", __func__, err != EXT2_ET_OP_NOT_SUPPORTED); ++ return err != EXT2_ET_OP_NOT_SUPPORTED; ++} ++ ++unsigned long long e2fsck_guess_readahead(ext2_filsys fs) ++{ ++ unsigned long long guess; ++ ++ /* ++ * The optimal readahead sizes were experimentally determined by ++ * djwong in August 2014. Setting the RA size to two block groups' ++ * worth of inode table blocks seems to yield the largest reductions ++ * in e2fsck runtime. ++ */ ++ guess = 2ULL * fs->blocksize * fs->inode_blocks_per_group; ++ ++ /* Disable RA if it'd use more 1/50th of RAM. */ ++ if (get_memory_size() > (guess * 50)) ++ return guess / 1024; ++ ++ return 0; ++} +--- a/e2fsck/recovery.c ++++ b/e2fsck/recovery.c +@@ -1,5 +1,5 @@ + /* +- * linux/fs/jbd/recovery.c ++ * linux/fs/jbd2/recovery.c + * + * Written by Stephen C. Tweedie , 1999 + * +@@ -14,14 +14,14 @@ + */ + + #ifndef __KERNEL__ +-#include "config.h" + #include "jfs_user.h" + #else + #include + #include +-#include ++#include + #include +-#include ++#include ++#include + #endif + + /* +@@ -90,7 +90,7 @@ + err = journal_bmap(journal, next, &blocknr); + + if (err) { +- printk (KERN_ERR "JBD: bad block at offset %u\n", ++ printk(KERN_ERR "JBD2: bad block at offset %u\n", + next); + goto failed; + } +@@ -139,14 +139,14 @@ + *bhp = NULL; + + if (offset >= journal->j_maxlen) { +- printk(KERN_ERR "JBD: corrupted journal superblock\n"); ++ printk(KERN_ERR "JBD2: corrupted journal superblock\n"); + return -EIO; + } + + err = journal_bmap(journal, offset, &blocknr); + + if (err) { +- printk (KERN_ERR "JBD: bad block at offset %u\n", ++ printk(KERN_ERR "JBD2: bad block at offset %u\n", + offset); + return err; + } +@@ -164,7 +164,7 @@ + } + + if (!buffer_uptodate(bh)) { +- printk (KERN_ERR "JBD: Failed to read block at offset %u\n", ++ printk(KERN_ERR "JBD2: Failed to read block at offset %u\n", + offset); + brelse(bh); + return -EIO; +@@ -174,6 +174,25 @@ + return 0; + } + ++static int jbd2_descr_block_csum_verify(journal_t *j, ++ void *buf) ++{ ++ struct journal_block_tail *tail; ++ __u32 provided; ++ __u32 calculated; ++ ++ if (!journal_has_csum_v2or3(j)) ++ return 1; ++ ++ tail = (struct journal_block_tail *)(buf + j->j_blocksize - ++ sizeof(struct journal_block_tail)); ++ provided = tail->t_checksum; ++ tail->t_checksum = 0; ++ calculated = jbd2_chksum(j, j->j_csum_seed, buf, j->j_blocksize); ++ tail->t_checksum = provided; ++ ++ return provided == ext2fs_cpu_to_be32(calculated); ++} + + /* + * Count the number of in-use tags in a journal descriptor block. +@@ -186,6 +205,9 @@ + int nr = 0, size = journal->j_blocksize; + int tag_bytes = journal_tag_bytes(journal); + ++ if (journal_has_csum_v2or3(journal)) ++ size -= sizeof(struct journal_block_tail); ++ + tagp = &bh->b_data[sizeof(journal_header_t)]; + + while ((tagp - bh->b_data + tag_bytes) <= size) { +@@ -193,10 +215,10 @@ + + nr++; + tagp += tag_bytes; +- if (!(tag->t_flags & cpu_to_be32(JFS_FLAG_SAME_UUID))) ++ if (!(tag->t_flags & ext2fs_cpu_to_be16(JFS_FLAG_SAME_UUID))) + tagp += 16; + +- if (tag->t_flags & cpu_to_be32(JFS_FLAG_LAST_TAG)) ++ if (tag->t_flags & ext2fs_cpu_to_be16(JFS_FLAG_LAST_TAG)) + break; + } + +@@ -225,7 +247,7 @@ + */ + int journal_recover(journal_t *journal) + { +- int err; ++ int err, err2; + journal_superblock_t * sb; + + struct recovery_info info; +@@ -241,8 +263,8 @@ + + if (!sb->s_start) { + jbd_debug(1, "No recovery required, last transaction %d\n", +- be32_to_cpu(sb->s_sequence)); +- journal->j_transaction_sequence = be32_to_cpu(sb->s_sequence) + 1; ++ ext2fs_be32_to_cpu(sb->s_sequence)); ++ journal->j_transaction_sequence = ext2fs_be32_to_cpu(sb->s_sequence) + 1; + return 0; + } + +@@ -252,10 +274,10 @@ + if (!err) + err = do_one_pass(journal, &info, PASS_REPLAY); + +- jbd_debug(1, "JBD: recovery, exit status %d, " ++ jbd_debug(1, "JBD2: recovery, exit status %d, " + "recovered transactions %u to %u\n", + err, info.start_transaction, info.end_transaction); +- jbd_debug(1, "JBD: Replayed %d and revoked %d/%d blocks\n", ++ jbd_debug(1, "JBD2: Replayed %d and revoked %d/%d blocks\n", + info.nr_replays, info.nr_revoke_hits, info.nr_revokes); + + /* Restart the log at the next transaction ID, thus invalidating +@@ -263,7 +285,15 @@ + journal->j_transaction_sequence = ++info.end_transaction; + + journal_clear_revoke(journal); +- sync_blockdev(journal->j_fs_dev); ++ err2 = sync_blockdev(journal->j_fs_dev); ++ if (!err) ++ err = err2; ++ /* Make sure all replayed data is on permanent storage */ ++ if (journal->j_flags & JFS_BARRIER) { ++ err2 = blkdev_issue_flush(journal->j_fs_dev, GFP_KERNEL, NULL); ++ if (!err) ++ err = err2; ++ } + return err; + } + +@@ -283,6 +313,7 @@ + int journal_skip_recovery(journal_t *journal) + { + int err; ++ + struct recovery_info info; + + memset (&info, 0, sizeof(info)); +@@ -290,17 +321,16 @@ + err = do_one_pass(journal, &info, PASS_SCAN); + + if (err) { +- printk(KERN_ERR "JBD: error %d scanning journal\n", err); ++ printk(KERN_ERR "JBD2: error %d scanning journal\n", err); + ++journal->j_transaction_sequence; + } else { +-#ifdef CONFIG_JBD_DEBUG +- journal_superblock_t *sb = journal->j_superblock; +- +- int dropped = info.end_transaction - be32_to_cpu(sb->s_sequence); +-#endif ++#ifdef CONFIG_JFS_DEBUG ++ int dropped = info.end_transaction - ++ ext2fs_be32_to_cpu(journal->j_superblock->s_sequence); + jbd_debug(1, +- "JBD: ignoring %d transaction%s from the journal.\n", ++ "JBD2: ignoring %d transaction%s from the journal.\n", + dropped, (dropped == 1) ? "" : "s"); ++#endif + journal->j_transaction_sequence = ++info.end_transaction; + } + +@@ -308,11 +338,12 @@ + return err; + } + +-static inline unsigned long long read_tag_block(int tag_bytes, journal_block_tag_t *tag) ++static inline unsigned long long read_tag_block(journal_t *journal, ++ journal_block_tag_t *tag) + { +- unsigned long long block = be32_to_cpu(tag->t_blocknr); +- if (tag_bytes > JBD_TAG_SIZE32) +- block |= (__u64)be32_to_cpu(tag->t_blocknr_high) << 32; ++ unsigned long long block = ext2fs_be32_to_cpu(tag->t_blocknr); ++ if (JFS_HAS_INCOMPAT_FEATURE(journal, JFS_FEATURE_INCOMPAT_64BIT)) ++ block |= (u64)ext2fs_be32_to_cpu(tag->t_blocknr_high) << 32; + return block; + } + +@@ -321,10 +352,10 @@ + * descriptor block. + */ + static int calc_chksums(journal_t *journal, struct buffer_head *bh, +- unsigned long long *next_log_block, __u32 *crc32_sum) ++ unsigned long *next_log_block, __u32 *crc32_sum) + { + int i, num_blks, err; +- unsigned long long io_block; ++ unsigned long io_block; + struct buffer_head *obh; + + num_blks = count_tags(journal, bh); +@@ -336,23 +367,61 @@ + wrap(journal, *next_log_block); + err = jread(&obh, journal, io_block); + if (err) { +- printk(KERN_ERR "JBD: IO error %d recovering block " +- "%llu in log\n", err, io_block); ++ printk(KERN_ERR "JBD2: IO error %d recovering block " ++ "%lu in log\n", err, io_block); + return 1; + } else { + *crc32_sum = crc32_be(*crc32_sum, (void *)obh->b_data, + obh->b_size); + } +- brelse(obh); ++ put_bh(obh); + } + return 0; + } + ++static int jbd2_commit_block_csum_verify(journal_t *j, void *buf) ++{ ++ struct commit_header *h; ++ __u32 provided; ++ __u32 calculated; ++ ++ if (!journal_has_csum_v2or3(j)) ++ return 1; ++ ++ h = buf; ++ provided = h->h_chksum[0]; ++ h->h_chksum[0] = 0; ++ calculated = jbd2_chksum(j, j->j_csum_seed, buf, j->j_blocksize); ++ h->h_chksum[0] = provided; ++ ++ return provided == ext2fs_cpu_to_be32(calculated); ++} ++ ++static int jbd2_block_tag_csum_verify(journal_t *j, journal_block_tag_t *tag, ++ void *buf, __u32 sequence) ++{ ++ journal_block_tag3_t *tag3 = (journal_block_tag3_t *)tag; ++ __u32 csum32; ++ __u32 seq; ++ ++ if (!journal_has_csum_v2or3(j)) ++ return 1; ++ ++ seq = ext2fs_cpu_to_be32(sequence); ++ csum32 = jbd2_chksum(j, j->j_csum_seed, (__u8 *)&seq, sizeof(seq)); ++ csum32 = jbd2_chksum(j, csum32, buf, j->j_blocksize); ++ ++ if (JFS_HAS_INCOMPAT_FEATURE(j, JFS_FEATURE_INCOMPAT_CSUM_V3)) ++ return tag3->t_checksum == ext2fs_cpu_to_be32(csum32); ++ ++ return tag->t_checksum == ext2fs_cpu_to_be16(csum32); ++} ++ + static int do_one_pass(journal_t *journal, + struct recovery_info *info, enum passtype pass) + { + unsigned int first_commit_ID, next_commit_ID; +- unsigned long long next_log_block; ++ unsigned long next_log_block; + int err, success = 0; + journal_superblock_t * sb; + journal_header_t * tmp; +@@ -361,6 +430,8 @@ + int blocktype; + int tag_bytes = journal_tag_bytes(journal); + __u32 crc32_sum = ~0; /* Transactional Checksums */ ++ int descr_csum_size = 0; ++ int block_error = 0; + + /* + * First thing is to establish what we expect to find in the log +@@ -369,8 +440,8 @@ + */ + + sb = journal->j_superblock; +- next_commit_ID = be32_to_cpu(sb->s_sequence); +- next_log_block = be32_to_cpu(sb->s_start); ++ next_commit_ID = ext2fs_be32_to_cpu(sb->s_sequence); ++ next_log_block = ext2fs_be32_to_cpu(sb->s_start); + + first_commit_ID = next_commit_ID; + if (pass == PASS_SCAN) +@@ -402,14 +473,14 @@ + if (tid_geq(next_commit_ID, info->end_transaction)) + break; + +- jbd_debug(2, "Scanning for sequence ID %u at %llu/%lu\n", ++ jbd_debug(2, "Scanning for sequence ID %u at %lu/%lu\n", + next_commit_ID, next_log_block, journal->j_last); + + /* Skip over each chunk of the transaction looking + * either the next descriptor block or the final commit + * record. */ + +- jbd_debug(3, "JBD: checking block %llu\n", next_log_block); ++ jbd_debug(3, "JBD2: checking block %ld\n", next_log_block); + err = jread(&bh, journal, next_log_block); + if (err) + goto failed; +@@ -425,13 +496,13 @@ + + tmp = (journal_header_t *)bh->b_data; + +- if (tmp->h_magic != cpu_to_be32(JFS_MAGIC_NUMBER)) { ++ if (tmp->h_magic != ext2fs_cpu_to_be32(JFS_MAGIC_NUMBER)) { + brelse(bh); + break; + } + +- blocktype = be32_to_cpu(tmp->h_blocktype); +- sequence = be32_to_cpu(tmp->h_sequence); ++ blocktype = ext2fs_be32_to_cpu(tmp->h_blocktype); ++ sequence = ext2fs_be32_to_cpu(tmp->h_sequence); + jbd_debug(3, "Found magic %d, sequence %d\n", + blocktype, sequence); + +@@ -446,6 +517,18 @@ + + switch(blocktype) { + case JFS_DESCRIPTOR_BLOCK: ++ /* Verify checksum first */ ++ if (journal_has_csum_v2or3(journal)) ++ 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, +@@ -458,15 +541,15 @@ + if (calc_chksums(journal, bh, + &next_log_block, + &crc32_sum)) { +- brelse(bh); ++ put_bh(bh); + break; + } +- brelse(bh); ++ put_bh(bh); + continue; + } + next_log_block += count_tags(journal, bh); + wrap(journal, next_log_block); +- brelse(bh); ++ put_bh(bh); + continue; + } + +@@ -476,11 +559,11 @@ + + tagp = &bh->b_data[sizeof(journal_header_t)]; + while ((tagp - bh->b_data + tag_bytes) +- <= journal->j_blocksize) { +- unsigned long long io_block; ++ <= journal->j_blocksize - descr_csum_size) { ++ unsigned long io_block; + + tag = (journal_block_tag_t *) tagp; +- flags = be32_to_cpu(tag->t_flags); ++ flags = ext2fs_be16_to_cpu(tag->t_flags); + + io_block = next_log_block++; + wrap(journal, next_log_block); +@@ -489,15 +572,15 @@ + /* Recover what we can, but + * report failure at the end. */ + success = err; +- printk (KERN_ERR +- "JBD: IO error %d recovering " +- "block %llu in log\n", ++ printk(KERN_ERR ++ "JBD2: IO error %d recovering " ++ "block %ld in log\n", + err, io_block); + } else { + unsigned long long blocknr; + + J_ASSERT(obh != NULL); +- blocknr = read_tag_block(tag_bytes, ++ blocknr = read_tag_block(journal, + tag); + + /* If the block has been +@@ -511,6 +594,20 @@ + goto skip_write; + } + ++ /* Look for block corruption */ ++ if (!jbd2_block_tag_csum_verify( ++ journal, tag, obh->b_data, ++ ext2fs_be32_to_cpu(tmp->h_sequence))) { ++ brelse(obh); ++ success = -EIO; ++ printk(KERN_ERR "JBD2: Invalid " ++ "checksum recovering " ++ "block %llu in log\n", ++ blocknr); ++ block_error = 1; ++ goto skip_write; ++ } ++ + /* Find a buffer for the new + * data being restored */ + nbh = __getblk(journal->j_fs_dev, +@@ -518,7 +615,7 @@ + journal->j_blocksize); + if (nbh == NULL) { + printk(KERN_ERR +- "JBD: Out of memory " ++ "JBD2: Out of memory " + "during recovery.\n"); + err = -ENOMEM; + brelse(bh); +@@ -530,10 +627,8 @@ + memcpy(nbh->b_data, obh->b_data, + journal->j_blocksize); + if (flags & JFS_FLAG_ESCAPE) { +- journal_header_t *header; +- +- header = (journal_header_t *) &nbh->b_data[0]; +- header->h_magic = cpu_to_be32(JFS_MAGIC_NUMBER); ++ *((__u32 *)nbh->b_data) = ++ ext2fs_cpu_to_be32(JFS_MAGIC_NUMBER); + } + + BUFFER_TRACE(nbh, "marking dirty"); +@@ -560,8 +655,6 @@ + continue; + + case JFS_COMMIT_BLOCK: +- jbd_debug(3, "Commit block for #%u found\n", +- next_commit_ID); + /* How to differentiate between interrupted commit + * and journal corruption ? + * +@@ -604,12 +697,10 @@ + struct commit_header *cbh = + (struct commit_header *)bh->b_data; + unsigned found_chksum = +- be32_to_cpu(cbh->h_chksum[0]); ++ ext2fs_be32_to_cpu(cbh->h_chksum[0]); + + chksum_err = chksum_seen = 0; + +- jbd_debug(3, "Checksums %x %x\n", +- crc32_sum, found_chksum); + if (info->end_transaction) { + journal->j_failed_commit = + info->end_transaction; +@@ -618,9 +709,9 @@ + } + + if (crc32_sum == found_chksum && +- cbh->h_chksum_type == JBD2_CRC32_CHKSUM && ++ cbh->h_chksum_type == JFS_CRC32_CHKSUM && + cbh->h_chksum_size == +- JBD2_CRC32_CHKSUM_SIZE) ++ JFS_CRC32_CHKSUM_SIZE) + chksum_seen = 1; + else if (!(cbh->h_chksum_type == 0 && + cbh->h_chksum_size == 0 && +@@ -640,8 +731,7 @@ + + if (chksum_err) { + info->end_transaction = next_commit_ID; +- jbd_debug(1, "Checksum_err %x %x\n", +- crc32_sum, found_chksum); ++ + if (!JFS_HAS_INCOMPAT_FEATURE(journal, + JFS_FEATURE_INCOMPAT_ASYNC_COMMIT)){ + journal->j_failed_commit = +@@ -652,6 +742,19 @@ + } + 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; +@@ -694,20 +797,40 @@ + /* It's really bad news if different passes end up at + * different places (but possible due to IO errors). */ + if (info->end_transaction != next_commit_ID) { +- printk (KERN_ERR "JBD: recovery pass %d ended at " ++ printk(KERN_ERR "JBD2: recovery pass %d ended at " + "transaction %u, expected %u\n", + pass, next_commit_ID, info->end_transaction); + if (!success) + success = -EIO; + } + } +- ++ if (block_error && success == 0) ++ success = -EIO; + return success; + + failed: + return err; + } + ++static int jbd2_revoke_block_csum_verify(journal_t *j, ++ void *buf) ++{ ++ struct journal_revoke_tail *tail; ++ __u32 provided; ++ __u32 calculated; ++ ++ if (!journal_has_csum_v2or3(j)) ++ return 1; ++ ++ tail = (struct journal_revoke_tail *)(buf + j->j_blocksize - ++ sizeof(struct journal_revoke_tail)); ++ provided = tail->r_checksum; ++ tail->r_checksum = 0; ++ calculated = jbd2_chksum(j, j->j_csum_seed, buf, j->j_blocksize); ++ tail->r_checksum = provided; ++ ++ return provided == ext2fs_cpu_to_be32(calculated); ++} + + /* Scan a revoke record, marking all blocks mentioned as revoked. */ + +@@ -716,29 +839,34 @@ + { + journal_revoke_header_t *header; + int offset, max; ++ int csum_size = 0; ++ __u32 rcount; + int record_len = 4; + + header = (journal_revoke_header_t *) bh->b_data; + offset = sizeof(journal_revoke_header_t); +- max = be32_to_cpu(header->r_count); ++ rcount = ext2fs_be32_to_cpu(header->r_count); ++ ++ if (!jbd2_revoke_block_csum_verify(journal, header)) ++ return -EINVAL; ++ ++ if (journal_has_csum_v2or3(journal)) ++ csum_size = sizeof(struct journal_revoke_tail); ++ if (rcount > journal->j_blocksize - csum_size) ++ return -EINVAL; ++ max = rcount; + + if (JFS_HAS_INCOMPAT_FEATURE(journal, JFS_FEATURE_INCOMPAT_64BIT)) + record_len = 8; + +- while (offset < max) { ++ while (offset + record_len <= max) { + unsigned long long blocknr; + int err; + +- if (record_len == 4) { +- __be32 b; +- memcpy(&b, bh->b_data + offset, sizeof(__be32)); +- blocknr = ext2fs_be32_to_cpu(b); +- } else { +- __be64 b; +- memcpy(&b, bh->b_data + offset, sizeof(__be64)); +- blocknr = ext2fs_be64_to_cpu(b); +- } +- ++ if (record_len == 4) ++ blocknr = ext2fs_be32_to_cpu(* ((__u32 *) (bh->b_data+offset))); ++ else ++ blocknr = ext2fs_be64_to_cpu(* ((__u64 *) (bh->b_data+offset))); + offset += record_len; + err = journal_set_revoke(journal, blocknr, sequence); + if (err) +--- a/e2fsck/region.c ++++ b/e2fsck/region.c +@@ -159,10 +159,10 @@ + struct region_el *r; + int i = 0; + +- fprintf(f, "Printing region (min=%d. max=%d)\n\t", region->min, ++ fprintf(f, "Printing region (min=%llu. max=%llu)\n\t", region->min, + region->max); + for (r = region->allocated; r; r = r->next) { +- fprintf(f, "(%d, %d) ", r->start, r->end); ++ fprintf(f, "(%llu, %llu) ", r->start, r->end); + if (++i >= 8) + fprintf(f, "\n\t"); + } +@@ -183,7 +183,7 @@ + case BCODE_CREATE: + start = bcode_program[pc++]; + end = bcode_program[pc++]; +- printf("Creating region with args(%d, %d)\n", ++ printf("Creating region with args(%llu, %llu)\n", + start, end); + r = region_create(start, end); + if (!r) { +@@ -195,7 +195,7 @@ + start = bcode_program[pc++]; + end = bcode_program[pc++]; + ret = region_allocate(r, start, end); +- printf("Region_allocate(%d, %d) returns %d\n", ++ printf("Region_allocate(%llu, %llu) returns %d\n", + start, end, ret); + break; + case BCODE_PRINT: +@@ -203,6 +203,8 @@ + break; + } + } ++ if (r) ++ region_free(r); + } + + #endif /* TEST_PROGRAM */ +--- a/e2fsck/rehash.c ++++ b/e2fsck/rehash.c +@@ -52,9 +52,29 @@ + #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; ++ ext2_ino_t ino; + errcode_t err; + e2fsck_t ctx; + struct hash_entry *harray; +@@ -62,6 +82,7 @@ + unsigned int dir_size; + int compress; + ino_t parent; ++ ext2_ino_t dir; + }; + + struct hash_entry { +@@ -89,7 +110,7 @@ + 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) +@@ -100,13 +121,19 @@ + fd->err = EXT2_ET_DIR_CORRUPTED; + return BLOCK_ABORT; + } ++ + dir = (fd->buf+offset); +- if (HOLE_BLKADDR(*block_nr)) { ++ if (*block_nr == 0) { + memset(dir, 0, fs->blocksize); + 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 +146,21 @@ + 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 +177,13 @@ + } + 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 +208,21 @@ + { + 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 +305,10 @@ + * 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 +325,7 @@ + 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 +368,7 @@ + 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 +383,10 @@ + 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 +396,25 @@ + 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, new_name, new_len, + fs->super->s_hash_seed, + &ent->hash, &ent->minor_hash); + fixed++; +@@ -407,6 +436,8 @@ + 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 +448,10 @@ + 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 +466,16 @@ + 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 +483,17 @@ + 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 +502,16 @@ + 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 +526,10 @@ + } + 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 +542,24 @@ + 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 +569,13 @@ + 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 +586,20 @@ + { + 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 +689,7 @@ + errcode_t err; + e2fsck_t ctx; + blk64_t cleared; ++ ext2_ino_t dir; + }; + + /* +@@ -641,11 +704,23 @@ + { + 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 +735,11 @@ + *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; +@@ -672,11 +747,11 @@ + + static errcode_t write_directory(e2fsck_t ctx, ext2_filsys fs, + struct out_dir *outdir, +- ext2_ino_t ino, int compress) ++ ext2_ino_t ino, struct ext2_inode *inode, ++ int compress) + { + struct write_dir_struct wd; + errcode_t retval; +- struct ext2_inode inode; + + retval = e2fsck_expand_directory(ctx, ino, -1, outdir->num); + if (retval) +@@ -686,6 +761,7 @@ + wd.err = 0; + wd.ctx = ctx; + wd.cleared = 0; ++ wd.dir = ino; + + retval = ext2fs_block_iterate3(fs, ino, 0, 0, + write_dir_block, &wd); +@@ -694,22 +770,23 @@ + if (wd.err) + return wd.err; + +- e2fsck_read_inode(ctx, ino, &inode, "rehash_dir"); ++ e2fsck_read_inode(ctx, ino, inode, "rehash_dir"); + if (compress) +- inode.i_flags &= ~EXT2_INDEX_FL; ++ inode->i_flags &= ~EXT2_INDEX_FL; + else +- inode.i_flags |= EXT2_INDEX_FL; +- retval = ext2fs_inode_size_set(fs, &inode, ++ inode->i_flags |= EXT2_INDEX_FL; ++ retval = ext2fs_inode_size_set(fs, inode, + outdir->num * fs->blocksize); + if (retval) + return retval; +- ext2fs_iblk_sub_blocks(fs, &inode, wd.cleared); +- e2fsck_write_inode(ctx, ino, &inode, "rehash_dir"); ++ ext2fs_iblk_sub_blocks(fs, inode, wd.cleared); ++ e2fsck_write_inode(ctx, ino, inode, "rehash_dir"); + + return 0; + } + +-errcode_t e2fsck_rehash_dir(e2fsck_t ctx, ext2_ino_t ino) ++errcode_t e2fsck_rehash_dir(e2fsck_t ctx, ext2_ino_t ino, ++ struct problem_context *pctx) + { + ext2_filsys fs = ctx->fs; + errcode_t retval; +@@ -723,6 +800,11 @@ + 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); +@@ -738,9 +820,11 @@ + fd.ctx = ctx; + fd.buf = dir_buf; + fd.inode = &inode; ++ fd.ino = 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; +@@ -813,10 +897,14 @@ + goto errout; + } + +- retval = write_directory(ctx, fs, &outdir, ino, fd.compress); ++ retval = write_directory(ctx, fs, &outdir, ino, &inode, fd.compress); + if (retval) + goto errout; + ++ if (ctx->options & E2F_OPT_CONVERT_BMAP) ++ retval = e2fsck_rebuild_extents_later(ctx, ino); ++ else ++ retval = e2fsck_check_rebuild_extents(ctx, ino, &inode, pctx); + errout: + free(dir_buf); + free(fd.harray); +@@ -844,7 +932,7 @@ + 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 +960,7 @@ + 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); +@@ -882,7 +969,7 @@ + #if 0 + fix_problem(ctx, PR_3A_OPTIMIZE_DIR, &pctx); + #endif +- pctx.errcode = e2fsck_rehash_dir(ctx, ino); ++ pctx.errcode = e2fsck_rehash_dir(ctx, ino, &pctx); + if (pctx.errcode) { + end_problem_latch(ctx, PR_LATCH_OPTIMIZE_DIR); + fix_problem(ctx, PR_3A_OPTIMIZE_DIR_ERR, &pctx); +--- a/e2fsck/revoke.c ++++ b/e2fsck/revoke.c +@@ -1,5 +1,5 @@ + /* +- * linux/fs/revoke.c ++ * linux/fs/jbd2/revoke.c + * + * Written by Stephen C. Tweedie , 2000 + * +@@ -47,6 +47,10 @@ + * overwriting the new data. We don't even need to clear the revoke + * bit here. + * ++ * We cache revoke status of a buffer in the current transaction in b_states ++ * bits. As the name says, revokevalid flag indicates that the cached revoke ++ * status of a buffer is valid and we can rely on the cached status. ++ * + * Revoke information on buffers is a tri-state value: + * + * RevokeValid clear: no cached revoke status, need to look it up +@@ -55,40 +59,58 @@ + * need do nothing. + * RevokeValid set, Revoked set: + * buffer has been revoked. ++ * ++ * Locking rules: ++ * We keep two hash tables of revoke records. One hashtable belongs to the ++ * running transaction (is pointed to by journal->j_revoke), the other one ++ * belongs to the committing transaction. Accesses to the second hash table ++ * happen only from the kjournald and no other thread touches this table. Also ++ * journal_switch_revoke_table() which switches which hashtable belongs to the ++ * running and which to the committing transaction is called only from ++ * kjournald. Therefore we need no locks when accessing the hashtable belonging ++ * to the committing transaction. ++ * ++ * All users operating on the hash table belonging to the running transaction ++ * have a handle to the transaction. Therefore they are safe from kjournald ++ * switching hash tables under them. For operations on the lists of entries in ++ * the hash table j_revoke_lock is used. ++ * ++ * Finally, also replay code uses the hash tables but at this moment no one else ++ * can touch them (filesystem isn't mounted yet) and hence no locking is ++ * needed. + */ + + #ifndef __KERNEL__ +-#include "config.h" + #include "jfs_user.h" + #else +-#include ++#include + #include +-#include ++#include + #include + #include +-#include + #include +-#include + #include ++#include ++#include + #endif + +-static lkmem_cache_t *revoke_record_cache; +-static lkmem_cache_t *revoke_table_cache; ++static lkmem_cache_t *jbd2_revoke_record_cache; ++static lkmem_cache_t *jbd2_revoke_table_cache; + + /* Each revoke record represents one single revoked block. During + journal replay, this involves recording the transaction ID of the + last transaction to revoke this block. */ + +-struct jbd_revoke_record_s ++struct jbd2_revoke_record_s + { + struct list_head hash; + tid_t sequence; /* Used for recovery only */ +- unsigned long blocknr; ++ unsigned long long blocknr; + }; + + + /* The revoke table is just a simple hash table of revoke records. */ +-struct jbd_revoke_table_s ++struct jbd2_revoke_table_s + { + /* It is conceivable that we might want a larger hash table + * for recovery. Must be a power of two. */ +@@ -100,159 +122,187 @@ + + #ifdef __KERNEL__ + static void write_one_revoke_record(journal_t *, transaction_t *, +- struct journal_head **, int *, +- struct jbd_revoke_record_s *); +-static void flush_descriptor(journal_t *, struct journal_head *, int); ++ struct list_head *, ++ struct buffer_head **, int *, ++ struct jbd2_revoke_record_s *, int); ++static void flush_descriptor(journal_t *, struct buffer_head *, int, int); + #endif + + /* Utility functions to maintain the revoke table */ + + /* Borrowed from buffer.c: this is a tried and tested block hash function */ +-static inline int hash(journal_t *journal, unsigned long block) ++static inline int hash(journal_t *journal, unsigned long long block) + { +- struct jbd_revoke_table_s *table = journal->j_revoke; ++ struct jbd2_revoke_table_s *table = journal->j_revoke; + int hash_shift = table->hash_shift; ++ int hash = (int)block ^ (int)((block >> 31) >> 1); + +- return ((block << (hash_shift - 6)) ^ +- (block >> 13) ^ +- (block << (hash_shift - 12))) & (table->hash_size - 1); ++ return ((hash << (hash_shift - 6)) ^ ++ (hash >> 13) ^ ++ (hash << (hash_shift - 12))) & (table->hash_size - 1); + } + +-static int insert_revoke_hash(journal_t *journal, unsigned long blocknr, ++static int insert_revoke_hash(journal_t *journal, unsigned long long blocknr, + tid_t seq) + { + struct list_head *hash_list; +- struct jbd_revoke_record_s *record; ++ struct jbd2_revoke_record_s *record; + +-#ifdef __KERNEL__ + repeat: +-#endif +- record = kmem_cache_alloc(revoke_record_cache, GFP_NOFS); ++ record = kmem_cache_alloc(jbd2_revoke_record_cache, GFP_NOFS); + if (!record) + goto oom; + + record->sequence = seq; + record->blocknr = blocknr; + hash_list = &journal->j_revoke->hash_table[hash(journal, blocknr)]; ++ spin_lock(&journal->j_revoke_lock); + list_add(&record->hash, hash_list); ++ spin_unlock(&journal->j_revoke_lock); + return 0; + + oom: +-#ifdef __KERNEL__ + if (!journal_oom_retry) + return -ENOMEM; +- jbd_debug(1, "ENOMEM in " __FUNCTION__ ", retrying.\n"); +- current->policy |= SCHED_YIELD; +- schedule(); ++ jbd_debug(1, "ENOMEM in %s, retrying\n", __func__); ++ yield(); + goto repeat; +-#else +- return -ENOMEM; +-#endif + } + + /* Find a revoke record in the journal's hash table. */ + +-static struct jbd_revoke_record_s *find_revoke_record(journal_t *journal, +- unsigned long blocknr) ++static struct jbd2_revoke_record_s *find_revoke_record(journal_t *journal, ++ unsigned long long blocknr) + { + struct list_head *hash_list; +- struct jbd_revoke_record_s *record; ++ struct jbd2_revoke_record_s *record; + + hash_list = &journal->j_revoke->hash_table[hash(journal, blocknr)]; + +- record = (struct jbd_revoke_record_s *) hash_list->next; ++ spin_lock(&journal->j_revoke_lock); ++ record = (struct jbd2_revoke_record_s *) hash_list->next; + while (&(record->hash) != hash_list) { +- if (record->blocknr == blocknr) ++ if (record->blocknr == blocknr) { ++ spin_unlock(&journal->j_revoke_lock); + return record; +- record = (struct jbd_revoke_record_s *) record->hash.next; ++ } ++ record = (struct jbd2_revoke_record_s *) record->hash.next; + } ++ spin_unlock(&journal->j_revoke_lock); + return NULL; + } + +-int __init journal_init_revoke_caches(void) +-{ +- revoke_record_cache = kmem_cache_create("revoke_record", +- sizeof(struct jbd_revoke_record_s), +- 0, SLAB_HWCACHE_ALIGN, NULL, NULL); +- if (revoke_record_cache == 0) +- return -ENOMEM; +- +- revoke_table_cache = kmem_cache_create("revoke_table", +- sizeof(struct jbd_revoke_table_s), +- 0, 0, NULL, NULL); +- if (revoke_table_cache == 0) { +- kmem_cache_destroy(revoke_record_cache); +- revoke_record_cache = NULL; +- return -ENOMEM; +- } +- return 0; +-} +- + void journal_destroy_revoke_caches(void) + { +- kmem_cache_destroy(revoke_record_cache); +- revoke_record_cache = 0; +- kmem_cache_destroy(revoke_table_cache); +- revoke_table_cache = 0; ++ if (jbd2_revoke_record_cache) { ++ kmem_cache_destroy(jbd2_revoke_record_cache); ++ jbd2_revoke_record_cache = NULL; ++ } ++ if (jbd2_revoke_table_cache) { ++ kmem_cache_destroy(jbd2_revoke_table_cache); ++ jbd2_revoke_table_cache = NULL; ++ } + } + +-/* Initialise the revoke table for a given journal to a given size. */ +- +-int journal_init_revoke(journal_t *journal, int hash_size) ++int __init journal_init_revoke_caches(void) + { +- int shift, tmp; +- +- J_ASSERT (journal->j_revoke == NULL); ++ J_ASSERT(!jbd2_revoke_record_cache); ++ J_ASSERT(!jbd2_revoke_table_cache); + +- journal->j_revoke = kmem_cache_alloc(revoke_table_cache, GFP_KERNEL); +- if (!journal->j_revoke) ++ jbd2_revoke_record_cache = KMEM_CACHE(jbd2_revoke_record_s, ++ SLAB_HWCACHE_ALIGN|SLAB_TEMPORARY); ++ if (!jbd2_revoke_record_cache) ++ goto record_cache_failure; ++ ++ jbd2_revoke_table_cache = KMEM_CACHE(jbd2_revoke_table_s, ++ SLAB_TEMPORARY); ++ if (!jbd2_revoke_table_cache) ++ goto table_cache_failure; ++ return 0; ++table_cache_failure: ++ journal_destroy_revoke_caches(); ++record_cache_failure: + return -ENOMEM; ++} + +- /* Check that the hash_size is a power of two */ +- J_ASSERT ((hash_size & (hash_size-1)) == 0); ++static struct jbd2_revoke_table_s *journal_init_revoke_table(int hash_size) ++{ ++ int shift = 0; ++ int tmp = hash_size; ++ struct jbd2_revoke_table_s *table; + +- journal->j_revoke->hash_size = hash_size; ++ table = kmem_cache_alloc(jbd2_revoke_table_cache, GFP_KERNEL); ++ if (!table) ++ goto out; + +- shift = 0; +- tmp = hash_size; + while((tmp >>= 1UL) != 0UL) + shift++; +- journal->j_revoke->hash_shift = shift; + +- journal->j_revoke->hash_table = ++ table->hash_size = hash_size; ++ table->hash_shift = shift; ++ table->hash_table = + kmalloc(hash_size * sizeof(struct list_head), GFP_KERNEL); +- if (!journal->j_revoke->hash_table) { +- kmem_cache_free(revoke_table_cache, journal->j_revoke); +- journal->j_revoke = NULL; +- return -ENOMEM; ++ if (!table->hash_table) { ++ kmem_cache_free(jbd2_revoke_table_cache, table); ++ table = NULL; ++ goto out; + } + + for (tmp = 0; tmp < hash_size; tmp++) +- INIT_LIST_HEAD(&journal->j_revoke->hash_table[tmp]); ++ INIT_LIST_HEAD(&table->hash_table[tmp]); + +- return 0; ++out: ++ return table; + } + +-/* Destoy a journal's revoke table. The table must already be empty! */ +- +-void journal_destroy_revoke(journal_t *journal) ++static void journal_destroy_revoke_table(struct jbd2_revoke_table_s *table) + { +- struct jbd_revoke_table_s *table; +- struct list_head *hash_list; + int i; ++ struct list_head *hash_list; + +- table = journal->j_revoke; +- if (!table) +- return; +- +- for (i=0; ihash_size; i++) { ++ for (i = 0; i < table->hash_size; i++) { + hash_list = &table->hash_table[i]; +- J_ASSERT (list_empty(hash_list)); ++ J_ASSERT(list_empty(hash_list)); + } + + kfree(table->hash_table); +- kmem_cache_free(revoke_table_cache, table); ++ kmem_cache_free(jbd2_revoke_table_cache, table); ++} ++ ++/* Initialise the revoke table for a given journal to a given size. */ ++int journal_init_revoke(journal_t *journal, int hash_size) ++{ ++ J_ASSERT(journal->j_revoke_table[0] == NULL); ++ J_ASSERT(is_power_of_2(hash_size)); ++ ++ journal->j_revoke_table[0] = journal_init_revoke_table(hash_size); ++ if (!journal->j_revoke_table[0]) ++ goto fail0; ++ ++ journal->j_revoke_table[1] = journal_init_revoke_table(hash_size); ++ if (!journal->j_revoke_table[1]) ++ goto fail1; ++ ++ journal->j_revoke = journal->j_revoke_table[1]; ++ ++ spin_lock_init(&journal->j_revoke_lock); ++ ++ return 0; ++ ++fail1: ++ journal_destroy_revoke_table(journal->j_revoke_table[0]); ++fail0: ++ return -ENOMEM; ++} ++ ++/* Destroy a journal's revoke table. The table must already be empty! */ ++void journal_destroy_revoke(journal_t *journal) ++{ + journal->j_revoke = NULL; ++ if (journal->j_revoke_table[0]) ++ journal_destroy_revoke_table(journal->j_revoke_table[0]); ++ if (journal->j_revoke_table[1]) ++ journal_destroy_revoke_table(journal->j_revoke_table[1]); + } + + +@@ -282,14 +332,15 @@ + * by one. + */ + +-int journal_revoke(handle_t *handle, unsigned long blocknr, ++int journal_revoke(handle_t *handle, unsigned long long blocknr, + struct buffer_head *bh_in) + { + struct buffer_head *bh = NULL; + journal_t *journal; +- kdev_t dev; ++ struct block_device *bdev; + int err; + ++ might_sleep(); + if (bh_in) + BUFFER_TRACE(bh_in, "enter"); + +@@ -299,34 +350,32 @@ + return -EINVAL; + } + +- dev = journal->j_fs_dev; ++ bdev = journal->j_fs_dev; + bh = bh_in; + + if (!bh) { +- bh = get_hash_table(dev, blocknr, journal->j_blocksize); ++ bh = __find_get_block(bdev, blocknr, journal->j_blocksize); + if (bh) + BUFFER_TRACE(bh, "found on hash"); + } +-#ifdef JBD_EXPENSIVE_CHECKING ++#ifdef JFS_EXPENSIVE_CHECKING + else { + struct buffer_head *bh2; + + /* If there is a different buffer_head lying around in + * memory anywhere... */ +- bh2 = get_hash_table(dev, blocknr, journal->j_blocksize); ++ bh2 = __find_get_block(bdev, blocknr, journal->j_blocksize); + if (bh2) { + /* ... and it has RevokeValid status... */ +- if ((bh2 != bh) && +- test_bit(BH_RevokeValid, &bh2->b_state)) ++ if (bh2 != bh && buffer_revokevalid(bh2)) + /* ...then it better be revoked too, + * since it's illegal to create a revoke + * record against a buffer_head which is + * not marked revoked --- that would + * risk missing a subsequent revoke + * cancel. */ +- J_ASSERT_BH(bh2, test_bit(BH_Revoked, & +- bh2->b_state)); +- __brelse(bh2); ++ J_ASSERT_BH(bh2, buffer_revoked(bh2)); ++ put_bh(bh2); + } + } + #endif +@@ -335,9 +384,14 @@ + first having the revoke cancelled: it's illegal to free a + block twice without allocating it in between! */ + if (bh) { +- J_ASSERT_BH(bh, !test_bit(BH_Revoked, &bh->b_state)); +- set_bit(BH_Revoked, &bh->b_state); +- set_bit(BH_RevokeValid, &bh->b_state); ++ if (!J_EXPECT_BH(bh, !buffer_revoked(bh), ++ "inconsistent data on disk")) { ++ if (!bh_in) ++ brelse(bh); ++ return -EIO; ++ } ++ set_buffer_revoked(bh); ++ set_buffer_revokevalid(bh); + if (bh_in) { + BUFFER_TRACE(bh_in, "call journal_forget"); + journal_forget(handle, bh_in); +@@ -347,11 +401,9 @@ + } + } + +- lock_journal(journal); +- jbd_debug(2, "insert revoke for block %lu, bh_in=%p\n", blocknr, bh_in); ++ jbd_debug(2, "insert revoke for block %llu, bh_in=%p\n",blocknr, bh_in); + err = insert_revoke_hash(journal, blocknr, + handle->h_transaction->t_tid); +- unlock_journal(journal); + BUFFER_TRACE(bh_in, "exit"); + return err; + } +@@ -360,7 +412,7 @@ + * Cancel an outstanding revoke. For use only internally by the + * journaling code (called from journal_get_write_access). + * +- * We trust the BH_Revoked bit on the buffer if the buffer is already ++ * We trust buffer_revoked() on the buffer if the buffer is already + * being journaled: if there is no revoke pending on the buffer, then we + * don't do anything here. + * +@@ -370,12 +422,10 @@ + * the second time we would still have a pending revoke to cancel. So, + * do not trust the Revoked bit on buffers unless RevokeValid is also + * set. +- * +- * The caller must have the journal locked. + */ + int journal_cancel_revoke(handle_t *handle, struct journal_head *jh) + { +- struct jbd_revoke_record_s *record; ++ struct jbd2_revoke_record_s *record; + journal_t *journal = handle->h_transaction->t_journal; + int need_cancel; + int did_revoke = 0; /* akpm: debug */ +@@ -387,25 +437,27 @@ + * only perform the full cancel if the revoke bit is set. If + * not, we can't trust the revoke bit, and we need to do the + * full search for a revoke record. */ +- if (test_and_set_bit(BH_RevokeValid, &bh->b_state)) +- need_cancel = (test_and_clear_bit(BH_Revoked, &bh->b_state)); +- else { ++ if (test_set_buffer_revokevalid(bh)) { ++ need_cancel = test_clear_buffer_revoked(bh); ++ } else { + need_cancel = 1; +- clear_bit(BH_Revoked, &bh->b_state); ++ clear_buffer_revoked(bh); + } + + if (need_cancel) { + record = find_revoke_record(journal, bh->b_blocknr); + if (record) { + jbd_debug(4, "cancelled existing revoke on " +- "blocknr %lu\n", bh->b_blocknr); ++ "blocknr %llu\n", (unsigned long long)bh->b_blocknr); ++ spin_lock(&journal->j_revoke_lock); + list_del(&record->hash); +- kmem_cache_free(revoke_record_cache, record); ++ spin_unlock(&journal->j_revoke_lock); ++ kmem_cache_free(jbd2_revoke_record_cache, record); + did_revoke = 1; + } + } + +-#ifdef JBD_EXPENSIVE_CHECKING ++#ifdef JFS_EXPENSIVE_CHECKING + /* There better not be one left behind by now! */ + record = find_revoke_record(journal, bh->b_blocknr); + J_ASSERT_JH(jh, record == NULL); +@@ -415,56 +467,104 @@ + * buffer_head? If so, we'd better make sure we clear the + * revoked status on any hashed alias too, otherwise the revoke + * state machine will get very upset later on. */ +- if (need_cancel && !bh->b_pprev) { ++ if (need_cancel) { + struct buffer_head *bh2; +- bh2 = get_hash_table(bh->b_dev, bh->b_blocknr, bh->b_size); ++ bh2 = __find_get_block(bh->b_bdev, bh->b_blocknr, bh->b_size); + if (bh2) { +- clear_bit(BH_Revoked, &bh2->b_state); ++ if (bh2 != bh) ++ clear_buffer_revoked(bh2); + __brelse(bh2); + } + } +- + return did_revoke; + } + ++/* ++ * journal_clear_revoked_flag clears revoked flag of buffers in ++ * revoke table to reflect there is no revoked buffers in the next ++ * transaction which is going to be started. ++ */ ++void jbd2_clear_buffer_revoked_flags(journal_t *journal) ++{ ++ struct jbd2_revoke_table_s *revoke = journal->j_revoke; ++ int i = 0; ++ ++ for (i = 0; i < revoke->hash_size; i++) { ++ struct list_head *hash_list; ++ struct list_head *list_entry; ++ hash_list = &revoke->hash_table[i]; ++ ++ list_for_each(list_entry, hash_list) { ++ struct jbd2_revoke_record_s *record; ++ struct buffer_head *bh; ++ record = (struct jbd2_revoke_record_s *)list_entry; ++ bh = __find_get_block(journal->j_fs_dev, ++ record->blocknr, ++ journal->j_blocksize); ++ if (bh) { ++ clear_buffer_revoked(bh); ++ __brelse(bh); ++ } ++ } ++ } ++} ++ ++/* journal_switch_revoke table select j_revoke for next transaction ++ * we do not want to suspend any processing until all revokes are ++ * written -bzzz ++ */ ++void journal_switch_revoke_table(journal_t *journal) ++{ ++ int i; ++ ++ if (journal->j_revoke == journal->j_revoke_table[0]) ++ journal->j_revoke = journal->j_revoke_table[1]; ++ else ++ journal->j_revoke = journal->j_revoke_table[0]; ++ ++ for (i = 0; i < journal->j_revoke->hash_size; i++) ++ INIT_LIST_HEAD(&journal->j_revoke->hash_table[i]); ++} + + /* + * Write revoke records to the journal for all entries in the current + * revoke hash, deleting the entries as we go. +- * +- * Called with the journal lock held. + */ +- + void journal_write_revoke_records(journal_t *journal, +- transaction_t *transaction) +-{ +- struct journal_head *descriptor; +- struct jbd_revoke_record_s *record; +- struct jbd_revoke_table_s *revoke; ++ transaction_t *transaction, ++ struct list_head *log_bufs, ++ int write_op) ++{ ++ struct buffer_head *descriptor; ++ struct jbd2_revoke_record_s *record; ++ struct jbd2_revoke_table_s *revoke; + struct list_head *hash_list; + int i, offset, count; + + descriptor = NULL; + offset = 0; + count = 0; +- revoke = journal->j_revoke; ++ ++ /* select revoke table for committing transaction */ ++ revoke = journal->j_revoke == journal->j_revoke_table[0] ? ++ journal->j_revoke_table[1] : journal->j_revoke_table[0]; + + for (i = 0; i < revoke->hash_size; i++) { + hash_list = &revoke->hash_table[i]; + + while (!list_empty(hash_list)) { +- record = (struct jbd_revoke_record_s *) ++ record = (struct jbd2_revoke_record_s *) + hash_list->next; +- write_one_revoke_record(journal, transaction, ++ write_one_revoke_record(journal, transaction, log_bufs, + &descriptor, &offset, +- record); ++ record, write_op); + count++; + list_del(&record->hash); +- kmem_cache_free(revoke_record_cache, record); ++ kmem_cache_free(jbd2_revoke_record_cache, record); + } + } + if (descriptor) +- flush_descriptor(journal, descriptor, offset); ++ flush_descriptor(journal, descriptor, offset, write_op); + jbd_debug(1, "Wrote %d revoke records\n", count); + } + +@@ -475,12 +575,15 @@ + + static void write_one_revoke_record(journal_t *journal, + transaction_t *transaction, +- struct journal_head **descriptorp, ++ struct list_head *log_bufs, ++ struct buffer_head **descriptorp, + int *offsetp, +- struct jbd_revoke_record_s *record) ++ struct jbd2_revoke_record_s *record, ++ int write_op) + { +- struct journal_head *descriptor; +- int offset; ++ int csum_size = 0; ++ struct buffer_head *descriptor; ++ int sz, offset; + journal_header_t *header; + + /* If we are already aborting, this all becomes a noop. We +@@ -493,10 +596,19 @@ + descriptor = *descriptorp; + offset = *offsetp; + ++ /* Do we need to leave space at the end for a checksum? */ ++ if (journal_has_csum_v2or3(journal)) ++ csum_size = sizeof(struct journal_revoke_tail); ++ ++ if (JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_64BIT)) ++ sz = 8; ++ else ++ sz = 4; ++ + /* Make sure we have a descriptor with space left for the record */ + if (descriptor) { +- if (offset == journal->j_blocksize) { +- flush_descriptor(journal, descriptor, offset); ++ if (offset + sz > journal->j_blocksize - csum_size) { ++ flush_descriptor(journal, descriptor, offset, write_op); + descriptor = NULL; + } + } +@@ -505,25 +617,45 @@ + descriptor = journal_get_descriptor_buffer(journal); + if (!descriptor) + return; +- header = (journal_header_t *) &jh2bh(descriptor)->b_data[0]; +- header->h_magic = htonl(JFS_MAGIC_NUMBER); +- header->h_blocktype = htonl(JFS_REVOKE_BLOCK); +- header->h_sequence = htonl(transaction->t_tid); ++ header = (journal_header_t *)descriptor->b_data; ++ header->h_magic = ext2fs_cpu_to_be32(JFS_MAGIC_NUMBER); ++ header->h_blocktype = ext2fs_cpu_to_be32(JFS_REVOKE_BLOCK); ++ header->h_sequence = ext2fs_cpu_to_be32(transaction->t_tid); + + /* Record it so that we can wait for IO completion later */ +- JBUFFER_TRACE(descriptor, "file as BJ_LogCtl"); +- journal_file_buffer(descriptor, transaction, BJ_LogCtl); ++ BUFFER_TRACE(descriptor, "file in log_bufs"); ++ jbd2_file_log_bh(log_bufs, descriptor); + + offset = sizeof(journal_revoke_header_t); + *descriptorp = descriptor; + } + +- * ((unsigned int *)(&jh2bh(descriptor)->b_data[offset])) = +- htonl(record->blocknr); +- offset += 4; ++ if (JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_64BIT)) { ++ * ((__be64 *)(&descriptor->b_data[offset])) = ++ cpu_to_be64(record->blocknr); ++ else ++ * ((__be32 *)(&descriptor->b_data[offset])) = ++ cpu_to_be32(record->blocknr); ++ offset += sz; ++ + *offsetp = offset; + } + ++static void jbd2_revoke_csum_set(journal_t *j, struct buffer_head *bh) ++{ ++ struct journal_revoke_tail *tail; ++ __u32 csum; ++ ++ if (!journal_has_csum_v2or3(j)) ++ return; ++ ++ tail = (struct journal_revoke_tail *)(bh->b_data + j->j_blocksize - ++ sizeof(struct journal_revoke_tail)); ++ tail->r_checksum = 0; ++ csum = jbd2_chksum(j, j->j_csum_seed, bh->b_data, j->j_blocksize); ++ tail->r_checksum = ext2fs_cpu_to_be32(csum); ++} ++ + /* + * Flush a revoke descriptor out to the journal. If we are aborting, + * this is a noop; otherwise we are generating a buffer which needs to +@@ -532,27 +664,25 @@ + */ + + static void flush_descriptor(journal_t *journal, +- struct journal_head *descriptor, +- int offset) ++ struct buffer_head *descriptor, ++ int offset, int write_op) + { + journal_revoke_header_t *header; + + if (is_journal_aborted(journal)) { +- JBUFFER_TRACE(descriptor, "brelse"); +- __brelse(jh2bh(descriptor)); ++ put_bh(descriptor); + return; + } + +- header = (journal_revoke_header_t *) jh2bh(descriptor)->b_data; +- header->r_count = htonl(offset); +- set_bit(BH_JWrite, &jh2bh(descriptor)->b_state); +- { +- struct buffer_head *bh = jh2bh(descriptor); +- BUFFER_TRACE(bh, "write"); +- ll_rw_block (WRITE, 1, &bh); +- } ++ header = (journal_revoke_header_t *)descriptor->b_data; ++ header->r_count = ext2fs_cpu_to_be32(offset); ++ jbd2_revoke_csum_set(journal, descriptor); ++ ++ set_buffer_jwrite(descriptor); ++ BUFFER_TRACE(descriptor, "write"); ++ set_buffer_dirty(descriptor); ++ write_dirty_buffer(descriptor, write_op); + } +- + #endif + + /* +@@ -578,14 +708,14 @@ + */ + + int journal_set_revoke(journal_t *journal, +- unsigned long blocknr, ++ unsigned long long blocknr, + tid_t sequence) + { +- struct jbd_revoke_record_s *record; ++ struct jbd2_revoke_record_s *record; + + record = find_revoke_record(journal, blocknr); + if (record) { +- /* If we have multiple occurences, only record the ++ /* If we have multiple occurrences, only record the + * latest sequence number in the hashed record */ + if (tid_gt(sequence, record->sequence)) + record->sequence = sequence; +@@ -602,10 +732,10 @@ + */ + + int journal_test_revoke(journal_t *journal, +- unsigned long blocknr, ++ unsigned long long blocknr, + tid_t sequence) + { +- struct jbd_revoke_record_s *record; ++ struct jbd2_revoke_record_s *record; + + record = find_revoke_record(journal, blocknr); + if (!record) +@@ -624,18 +754,17 @@ + { + int i; + struct list_head *hash_list; +- struct jbd_revoke_record_s *record; +- struct jbd_revoke_table_s *revoke; ++ struct jbd2_revoke_record_s *record; ++ struct jbd2_revoke_table_s *revoke; + + revoke = journal->j_revoke; + + for (i = 0; i < revoke->hash_size; i++) { + hash_list = &revoke->hash_table[i]; + while (!list_empty(hash_list)) { +- record = (struct jbd_revoke_record_s*) hash_list->next; ++ record = (struct jbd2_revoke_record_s*) hash_list->next; + list_del(&record->hash); +- kmem_cache_free(revoke_record_cache, record); ++ kmem_cache_free(jbd2_revoke_record_cache, record); + } + } + } +- +--- a/e2fsck/sigcatcher.c ++++ b/e2fsck/sigcatcher.c +@@ -334,8 +334,6 @@ + static void die_signal_handler(int signum, siginfo_t *siginfo, + void *context EXT2FS_ATTR((unused))) + { +- void *stack_syms[32]; +- int frames; + const char *cp; + + fprintf(stderr, "Signal (%d) %s ", signum, +@@ -374,8 +372,13 @@ + fprintf(stderr, "\n"); + + #if defined(HAVE_BACKTRACE) && !defined(DISABLE_BACKTRACE) +- frames = backtrace(stack_syms, 32); +- backtrace_symbols_fd(stack_syms, frames, 2); ++ { ++ void *stack_syms[32]; ++ int frames; ++ ++ frames = backtrace(stack_syms, 32); ++ backtrace_symbols_fd(stack_syms, frames, 2); ++ } + #endif + exit(FSCK_ERROR); + } +@@ -392,6 +395,7 @@ + sigaction(SIGILL, &sa, 0); + sigaction(SIGBUS, &sa, 0); + sigaction(SIGSEGV, &sa, 0); ++ sigaction(SIGABRT, &sa, 0); + } + + +--- a/e2fsck/super.c ++++ b/e2fsck/super.c +@@ -76,7 +76,7 @@ + pctx->blk = blk; + pctx->blkcount = blockcnt; + +- if (HOLE_BLKADDR(blk)) ++ if (blk == 0) + return 0; + + if ((blk < fs->super->s_first_data_block) || +@@ -201,9 +201,9 @@ + 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 @@ + 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 @@ + } + } + ++ /* 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) && +@@ -591,6 +606,13 @@ + ext2fs_mark_super_dirty(fs); + } + ++ /* Did user ask us to convert files to extents? */ ++ if (ctx->options & E2F_OPT_CONVERT_BMAP) { ++ fs->super->s_feature_incompat |= ++ EXT3_FEATURE_INCOMPAT_EXTENTS; ++ ext2fs_mark_super_dirty(fs); ++ } ++ + if ((fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_META_BG) && + (fs->super->s_first_meta_bg > fs->desc_blocks)) { + pctx.group = fs->desc_blocks; +@@ -609,8 +631,7 @@ + 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 +762,7 @@ + (!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; + } +--- a/e2fsck/unix.c ++++ b/e2fsck/unix.c +@@ -45,10 +45,12 @@ + #ifdef HAVE_DIRENT_H + #include + #endif ++#include + + #include "e2p/e2p.h" + #include "et/com_err.h" + #include "e2p/e2p.h" ++#include "support/plausible.h" + #include "e2fsck.h" + #include "problem.h" + #include "../version.h" +@@ -74,7 +76,7 @@ + _("Usage: %s [-panyrcdfvtDFV] [-b superblock] [-B blocksize]\n" + "\t\t[-I inode_buffer_blocks] [-P process_inode_size]\n" + "\t\t[-l|-L bad_blocks_file] [-C fd] [-j external_journal]\n" +- "\t\t[-E extended-options] device\n"), ++ "\t\t[-E extended-options] [-z undo_file] device\n"), + ctx->program_name); + + fprintf(stderr, "%s", _("\nEmergency help:\n" +@@ -90,6 +92,7 @@ + " -j external_journal Set location of the external journal\n" + " -l bad_blocks_file Add to badblocks list\n" + " -L bad_blocks_file Set badblocks list\n" ++ " -z undo_file Create an undo file\n" + )); + + exit(FSCK_USAGE); +@@ -649,6 +652,7 @@ + char *buf, *token, *next, *p, *arg; + int ea_ver; + int extended_usage = 0; ++ unsigned long long reada_kb; + + buf = string_copy(ctx, opts, 0); + for (token = buf; token && *token; token = next) { +@@ -677,6 +681,19 @@ + continue; + } + ctx->ext_attr_ver = ea_ver; ++ } else if (strcmp(token, "readahead_kb") == 0) { ++ if (!arg) { ++ extended_usage++; ++ continue; ++ } ++ reada_kb = strtoull(arg, &p, 0); ++ if (*p) { ++ fprintf(stderr, "%s", ++ _("Invalid readahead buffer size.\n")); ++ extended_usage++; ++ continue; ++ } ++ ctx->readahead_kb = reada_kb; + } else if (strcmp(token, "fragcheck") == 0) { + ctx->options |= E2F_OPT_FRAGCHECK; + continue; +@@ -698,6 +715,12 @@ + else + ctx->log_fn = string_copy(ctx, arg, 0); + continue; ++ } else if (strcmp(token, "bmap2extent") == 0) { ++ ctx->options |= E2F_OPT_CONVERT_BMAP; ++ continue; ++ } else if (strcmp(token, "fixes_only") == 0) { ++ ctx->options |= E2F_OPT_FIXES_ONLY; ++ continue; + } else { + fprintf(stderr, _("Unknown extended option: %s\n"), + token); +@@ -716,6 +739,8 @@ + fputs(("\tjournal_only\n"), stderr); + fputs(("\tdiscard\n"), stderr); + fputs(("\tnodiscard\n"), stderr); ++ fputs(("\treadahead_kb=\n"), stderr); ++ fputs(("\tbmap2extent\n"), stderr); + fputc('\n', stderr); + exit(1); + } +@@ -749,6 +774,7 @@ + #ifdef CONFIG_JBD_DEBUG + char *jbd_debug; + #endif ++ unsigned long long phys_mem_kb; + + retval = e2fsck_allocate_context(&ctx); + if (retval) +@@ -759,7 +785,7 @@ + + setvbuf(stdout, NULL, _IONBF, BUFSIZ); + setvbuf(stderr, NULL, _IONBF, BUFSIZ); +- if (isatty(0) && isatty(1)) { ++ if (getenv("E2FSCK_FORCE_INTERACTIVE") || (isatty(0) && isatty(1))) { + ctx->interactive = 1; + } else { + ctx->start_meta[0] = '\001'; +@@ -776,7 +802,9 @@ + else + ctx->program_name = "e2fsck"; + +- while ((c = getopt (argc, argv, "panyrcC:B:dE:fvtFVM:b:I:j:P:l:L:N:SsDk")) != EOF) ++ phys_mem_kb = get_memory_size() / 1024; ++ ctx->readahead_kb = ~0ULL; ++ while ((c = getopt(argc, argv, "panyrcC:B:dE:fvtFVM:b:I:j:P:l:L:N:SsDkz:")) != EOF) + switch (c) { + case 'C': + ctx->progress = e2fsck_update_progress; +@@ -908,6 +936,9 @@ + case 'k': + keep_bad_blocks++; + break; ++ case 'z': ++ ctx->undo_file = optarg; ++ break; + default: + usage(ctx); + } +@@ -946,6 +977,22 @@ + if (extended_opts) + parse_extended_opts(ctx, extended_opts); + ++ /* Complain about mutually exclusive rebuilding activities */ ++ if (getenv("E2FSCK_FIXES_ONLY")) ++ ctx->options |= E2F_OPT_FIXES_ONLY; ++ if ((ctx->options & E2F_OPT_COMPRESS_DIRS) && ++ (ctx->options & E2F_OPT_FIXES_ONLY)) { ++ com_err(ctx->program_name, 0, "%s", ++ _("The -D and -E fixes_only options are incompatible.")); ++ fatal_error(ctx, 0); ++ } ++ if ((ctx->options & E2F_OPT_CONVERT_BMAP) && ++ (ctx->options & E2F_OPT_FIXES_ONLY)) { ++ com_err(ctx->program_name, 0, "%s", ++ _("The -E bmap2extent and fixes_only options are incompatible.")); ++ fatal_error(ctx, 0); ++ } ++ + if ((cp = getenv("E2FSCK_CONFIG")) != NULL) + config_fn[0] = cp; + profile_set_syntax_err_cb(syntax_err_report); +@@ -960,6 +1007,20 @@ + if (c) + verbose = 1; + ++ if (ctx->readahead_kb == ~0ULL) { ++ profile_get_integer(ctx->profile, "options", ++ "readahead_mem_pct", 0, -1, &c); ++ if (c >= 0 && c <= 100) ++ ctx->readahead_kb = phys_mem_kb * c / 100; ++ profile_get_integer(ctx->profile, "options", ++ "readahead_kb", 0, -1, &c); ++ if (c >= 0) ++ ctx->readahead_kb = c; ++ if (ctx->readahead_kb != ~0ULL && ++ ctx->readahead_kb > phys_mem_kb) ++ ctx->readahead_kb = phys_mem_kb; ++ } ++ + /* Turn off discard in read-only mode */ + if ((ctx->options & E2F_OPT_NO) && + (ctx->options & E2F_OPT_DISCARD)) +@@ -1161,7 +1222,101 @@ + 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; ++} ++ ++static int e2fsck_setup_tdb(e2fsck_t ctx, io_manager *io_ptr) ++{ ++ errcode_t retval = ENOMEM; ++ char *tdb_dir = NULL, *tdb_file = NULL; ++ char *dev_name, *tmp_name; ++ int free_tdb_dir = 0; ++ ++ /* (re)open a specific undo file */ ++ if (ctx->undo_file && ctx->undo_file[0] != 0) { ++ retval = set_undo_io_backing_manager(*io_ptr); ++ if (retval) ++ goto err; ++ *io_ptr = undo_io_manager; ++ retval = set_undo_io_backup_file(ctx->undo_file); ++ if (retval) ++ goto err; ++ printf(_("Overwriting existing filesystem; this can be undone " ++ "using the command:\n" ++ " e2undo %s %s\n\n"), ++ ctx->undo_file, ctx->filesystem_name); ++ return retval; + } ++ ++ /* ++ * Configuration via a conf file would be ++ * nice ++ */ ++ tdb_dir = getenv("E2FSPROGS_UNDO_DIR"); ++ if (!tdb_dir) { ++ profile_get_string(ctx->profile, "defaults", ++ "undo_dir", 0, "/var/lib/e2fsprogs", ++ &tdb_dir); ++ free_tdb_dir = 1; ++ } ++ ++ if (!strcmp(tdb_dir, "none") || (tdb_dir[0] == 0) || ++ access(tdb_dir, W_OK)) { ++ if (free_tdb_dir) ++ free(tdb_dir); ++ return 0; ++ } ++ ++ tmp_name = strdup(ctx->filesystem_name); ++ if (!tmp_name) ++ goto errout; ++ dev_name = basename(tmp_name); ++ tdb_file = malloc(strlen(tdb_dir) + 8 + strlen(dev_name) + 7 + 1); ++ if (!tdb_file) { ++ free(tmp_name); ++ goto errout; ++ } ++ sprintf(tdb_file, "%s/e2fsck-%s.e2undo", tdb_dir, dev_name); ++ free(tmp_name); ++ ++ if ((unlink(tdb_file) < 0) && (errno != ENOENT)) { ++ retval = errno; ++ com_err(ctx->program_name, retval, ++ _("while trying to delete %s"), tdb_file); ++ goto errout; ++ } ++ ++ retval = set_undo_io_backing_manager(*io_ptr); ++ if (retval) ++ goto errout; ++ *io_ptr = undo_io_manager; ++ retval = set_undo_io_backup_file(tdb_file); ++ if (retval) ++ goto errout; ++ printf(_("Overwriting existing filesystem; this can be undone " ++ "using the command:\n" ++ " e2undo %s %s\n\n"), tdb_file, ctx->filesystem_name); ++ ++ if (free_tdb_dir) ++ free(tdb_dir); ++ free(tdb_file); ++ return 0; ++ ++errout: ++ if (free_tdb_dir) ++ free(tdb_dir); ++ free(tdb_file); ++err: ++ com_err(ctx->program_name, retval, "%s", ++ _("while trying to setup undo file\n")); + return retval; + } + +@@ -1274,12 +1429,19 @@ + flags &= ~EXT2_FLAG_EXCLUSIVE; + } + ++ if (ctx->undo_file) { ++ retval = e2fsck_setup_tdb(ctx, &io_ptr); ++ if (retval) ++ exit(FSCK_ERROR); ++ } ++ + ctx->openfs_flags = flags; + retval = try_open_fs(ctx, flags, io_ptr, &fs); + + 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) { +@@ -1374,8 +1536,12 @@ + "-n option to do a read-only\n" + "check of the device.\n")); + #endif +- else ++ else { + fix_problem(ctx, PR_0_SB_CORRUPT, &pctx); ++ if (retval == EXT2_ET_BAD_MAGIC) ++ check_plausibility(ctx->filesystem_name, ++ CHECK_FS_EXIST, NULL); ++ } + fatal_error(ctx, 0); + } + /* +@@ -1474,12 +1640,14 @@ + /* + * Make sure the ext3 superblock fields are consistent. + */ +- retval = e2fsck_check_ext3_journal(ctx); +- if (retval) { +- com_err(ctx->program_name, retval, +- _("while checking ext3 journal for %s"), +- ctx->device_name); +- fatal_error(ctx, 0); ++ if ((ctx->mount_flags & (EXT2_MF_MOUNTED | EXT2_MF_BUSY)) == 0) { ++ retval = e2fsck_check_ext3_journal(ctx); ++ if (retval) { ++ com_err(ctx->program_name, retval, ++ _("while checking ext3 journal for %s"), ++ ctx->device_name); ++ fatal_error(ctx, 0); ++ } + } + + /* +@@ -1544,20 +1712,6 @@ + log_err(ctx, "\n"); + goto get_newer; + } +-#ifdef ENABLE_COMPRESSION +- if (sb->s_feature_incompat & EXT2_FEATURE_INCOMPAT_COMPRESSION) +- log_err(ctx, _("%s: warning: compression support " +- "is experimental.\n"), +- ctx->program_name); +-#endif +-#ifndef ENABLE_HTREE +- if (sb->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX) { +- log_err(ctx, _("%s: e2fsck not compiled with HTREE support,\n\t" +- "but filesystem %s has HTREE directories.\n"), +- ctx->program_name, ctx->device_name); +- goto get_newer; +- } +-#endif + + /* + * If the user specified a specific superblock, presumably the +@@ -1661,8 +1815,7 @@ + } + log_out(ctx, "%s", _(" Done.\n")); + log_out(ctx, "%s", +- _("\n*** journal has been re-created - " +- "filesystem is now ext3 again ***\n")); ++ _("\n*** journal has been regenerated ***\n")); + } + } + no_journal: +--- a/e2fsck/util.c ++++ b/e2fsck/util.c +@@ -37,6 +37,10 @@ + #include + #endif + ++#ifdef HAVE_SYS_SYSCTL_H ++#include ++#endif ++ + #include "e2fsck.h" + + extern e2fsck_t e2fsck_global_ctx; /* Try your very best not to use this! */ +@@ -189,6 +193,10 @@ + const char *defstr; + const char *short_yes = _("yY"); + const char *short_no = _("nN"); ++ const char *short_yesall = _("aA"); ++ const char *yesall_prompt = _(" ('a' enables 'yes' to all) "); ++ const char *extra_prompt = ""; ++ static int yes_answers; + + #ifdef HAVE_TERMIOS_H + struct termios termios, tmp; +@@ -207,7 +215,16 @@ + defstr = _(_("")); + else + defstr = _(" (y/n)"); +- log_out(ctx, "%s%s? ", string, defstr); ++ /* ++ * If the user presses 'y' more than 8 (but less than 12) times in ++ * succession without pressing anything else, display a hint about ++ * yes-to-all mode. ++ */ ++ if (yes_answers > 12) ++ yes_answers = -1; ++ else if (yes_answers > 8) ++ extra_prompt = yesall_prompt; ++ log_out(ctx, "%s%s%s? ", string, extra_prompt, defstr); + while (1) { + fflush (stdout); + if ((c = read_a_char()) == EOF) +@@ -221,20 +238,31 @@ + longjmp(e2fsck_global_ctx->abort_loc, 1); + } + log_out(ctx, "%s", _("cancelled!\n")); ++ yes_answers = 0; + return 0; + } + if (strchr(short_yes, (char) c)) { + def = 1; ++ if (yes_answers >= 0) ++ yes_answers++; + break; +- } +- else if (strchr(short_no, (char) c)) { ++ } else if (strchr(short_no, (char) c)) { + def = 0; ++ yes_answers = -1; + break; +- } +- else if ((c == 27 || c == ' ' || c == '\n') && (def != -1)) ++ } else if (strchr(short_yesall, (char)c)) { ++ def = 2; ++ yes_answers = -1; ++ ctx->options |= E2F_OPT_YES; + break; ++ } else if ((c == 27 || c == ' ' || c == '\n') && (def != -1)) { ++ yes_answers = -1; ++ break; ++ } + } +- if (def) ++ if (def == 2) ++ log_out(ctx, "%s", _("yes to all\n")); ++ else if (def) + log_out(ctx, "%s", _("yes\n")); + else + log_out(ctx, "%s", _("no\n")); +@@ -267,6 +295,7 @@ + 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 +307,11 @@ + 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) { +@@ -603,59 +636,6 @@ + return 0; + } + +-#define STRIDE_LENGTH 8 +-/* +- * Helper function which zeros out _num_ blocks starting at _blk_. In +- * case of an error, the details of the error is returned via _ret_blk_ +- * and _ret_count_ if they are non-NULL pointers. Returns 0 on +- * success, and an error code on an error. +- * +- * As a special case, if the first argument is NULL, then it will +- * attempt to free the static zeroizing buffer. (This is to keep +- * programs that check for memory leaks happy.) +- */ +-errcode_t e2fsck_zero_blocks(ext2_filsys fs, blk_t blk, int num, +- blk_t *ret_blk, int *ret_count) +-{ +- int j, count; +- static char *buf; +- errcode_t retval; +- +- /* If fs is null, clean up the static buffer and return */ +- if (!fs) { +- if (buf) { +- free(buf); +- buf = 0; +- } +- return 0; +- } +- /* Allocate the zeroizing buffer if necessary */ +- if (!buf) { +- buf = malloc(fs->blocksize * STRIDE_LENGTH); +- if (!buf) { +- com_err("malloc", ENOMEM, "%s", +- _("while allocating zeroizing buffer")); +- exit(1); +- } +- memset(buf, 0, fs->blocksize * STRIDE_LENGTH); +- } +- /* OK, do the write loop */ +- for (j = 0; j < num; j += STRIDE_LENGTH, blk += STRIDE_LENGTH) { +- count = num - j; +- if (count > STRIDE_LENGTH) +- count = STRIDE_LENGTH; +- retval = io_channel_write_blk64(fs->io, blk, count, buf); +- if (retval) { +- if (ret_count) +- *ret_count = count; +- if (ret_blk) +- *ret_blk = blk; +- return retval; +- } +- } +- return 0; +-} +- + /* + * Check to see if a filesystem is in /proc/filesystems. + * Returns 1 if found, 0 if not +@@ -843,3 +823,50 @@ + fs->default_bitmap_type = save_type; + return retval; + } ++ ++/* Return memory size in bytes */ ++unsigned long long get_memory_size(void) ++{ ++#if defined(_SC_PHYS_PAGES) ++# if defined(_SC_PAGESIZE) ++ return (unsigned long long)sysconf(_SC_PHYS_PAGES) * ++ (unsigned long long)sysconf(_SC_PAGESIZE); ++# elif defined(_SC_PAGE_SIZE) ++ return (unsigned long long)sysconf(_SC_PHYS_PAGES) * ++ (unsigned long long)sysconf(_SC_PAGE_SIZE); ++# endif ++#elif defined(CTL_HW) ++# if (defined(HW_MEMSIZE) || defined(HW_PHYSMEM64)) ++# define CTL_HW_INT64 ++# elif (defined(HW_PHYSMEM) || defined(HW_REALMEM)) ++# define CTL_HW_UINT ++# endif ++ int mib[2]; ++ ++ mib[0] = CTL_HW; ++# if defined(HW_MEMSIZE) ++ mib[1] = HW_MEMSIZE; ++# elif defined(HW_PHYSMEM64) ++ mib[1] = HW_PHYSMEM64; ++# elif defined(HW_REALMEM) ++ mib[1] = HW_REALMEM; ++# elif defined(HW_PYSMEM) ++ mib[1] = HW_PHYSMEM; ++# endif ++# if defined(CTL_HW_INT64) ++ unsigned long long size = 0; ++# elif defined(CTL_HW_UINT) ++ unsigned int size = 0; ++# endif ++# if defined(CTL_HW_INT64) || defined(CTL_HW_UINT) ++ size_t len = sizeof(size); ++ ++ if (sysctl(mib, 2, &size, &len, NULL, 0) == 0) ++ return (unsigned long long)size; ++# endif ++ return 0; ++#else ++# warning "Don't know how to detect memory on your platform?" ++ return 0; ++#endif ++} +--- a/e2fsprogs.spec ++++ /dev/null +@@ -1,242 +0,0 @@ +-%define _root_sbindir /sbin +-%define _root_libdir /%{_lib} +-%define _root_localedir /usr/share/locale +-%define _root_etcdir /etc +- +-Summary: Utilities for managing ext2/ext3/ext4 filesystems +-Name: e2fsprogs +-Version: 1.42.11 +-Release: 0 +-License: GPLv2 +-Group: System Environment/Base +-Source: ftp://download.sourceforge.net/pub/sourceforge/e2fsprogs/e2fsprogs-%{version}.tar.gz +-Url: http://e2fsprogs.sourceforge.net/ +-Prereq: /sbin/ldconfig +-BuildRoot: %{_tmppath}/%{name}-root +- +-%description +-The e2fsprogs package contains a number of utilities for creating, +-checking, modifying, and correcting any inconsistencies in ext2, ext3, +-and ext4 filesystems. E2fsprogs contains e2fsck (used to repair +-filesystem inconsistencies after an unclean shutdown), mke2fs (used to +-initialize a partition to contain an empty ext2 filesystem), debugfs +-(used to examine the internal structure of a filesystem, to manually +-repair a corrupted filesystem or to create test cases for e2fsck), +-tune2fs (used to modify filesystem parameters), resize2fs to grow and +-shrink unmounted ext2 filesystems, and most of the other core ext2fs +-filesystem utilities. +- +-You should install the e2fsprogs package if you are using any ext2, +-ext3, or ext4 filesystems (if you're not sure, you probably should +-install this package). You may also need to install it (even if you +-don't use ext2/ext3/ext4) for the libuuid and libblkid libraries and +-fsck tool that are included here. +- +-%package devel +-Summary: Ext2 filesystem-specific static libraries and headers. +-Group: Development/Libraries +-Requires: e2fsprogs = %{version} +-Prereq: /sbin/install-info +- +-%description devel +-E2fsprogs-devel contains the libraries and header files needed to +-develop ext2, ext3, or ext4 filesystem-specific programs. +- +-You should install e2fsprogs-devel if you want to develop +-ext2. ext3. or ext4 filesystem-specific programs. If you install +-e2fsprogs-devel, you'll also want to install e2fsprogs. +- +-%package -n uuidd +-Summary: helper daemon to guarantee uniqueness of time-based UUIDs +-Group: System Environment/Daemons +-License: GPLv2 +-Requires: e2fsprogs = %{version} +-Requires(pre): shadow-utils +- +-%description -n uuidd +-The uuidd package contains a userspace daemon (uuidd) which guarantees +-uniqueness of time-based UUID generation even at very high rates on +-SMP systems. +- +-%prep +-%setup +- +-%build +-%configure --enable-elf-shlibs --enable-nls \ +- %{?extra_config_flags:%extra_config_flags} +-make +-make check +- +-%install +-rm -rf $RPM_BUILD_ROOT +-export PATH=/sbin:$PATH +-make install install-libs DESTDIR="$RPM_BUILD_ROOT" \ +- root_sbindir=%{_root_sbindir} root_libdir=%{_root_libdir} +-/sbin/ldconfig -n ${RPM_BUILD_ROOT}%{_libdir} +- +-# Add a dir that uuidd needs that the Makefiles don't create +-install -d $RPM_BUILD_ROOT/var/lib/libuuid +- +-%find_lang %{name} +- +-%clean +-rm -rf $RPM_BUILD_ROOT +- +-%post -p /sbin/ldconfig +- +-%postun -p /sbin/ldconfig +- +-%post devel +-if [ -x /sbin/install-info -a -f %{_infodir}/libext2fs.info.gz ]; then +- /sbin/install-info %{_infodir}/libext2fs.info.gz %{_infodir}/dir +-fi +-exit 0 +- +-%postun devel +-if [ $1 = 0 -a -x /sbin/install-info -a -f %{_infodir}/libext2fs.info.gz ]; then +- /sbin/install-info --delete %{_infodir}/libext2fs.info.gz %{_infodir}/dir +-fi +-exit 0 +- +-%pre -n uuidd +-getent group uuidd >/dev/null || groupadd -r uuidd +-getent passwd uuidd >/dev/null || \ +-useradd -r -g uuidd -d /var/lib/libuuid -s /sbin/nologin \ +- -c "UUID generator helper daemon" uuidd +-exit 0 +- +-%files -f %{name}.lang +-%defattr(-,root,root) +-%doc README RELEASE-NOTES +- +-%{_root_sbindir}/badblocks +-%{_root_sbindir}/blkid +-%{_root_sbindir}/debugfs +-%{_root_sbindir}/dumpe2fs +-%{_root_sbindir}/e2fsck +-%{_root_sbindir}/e2image +-%{_root_sbindir}/e2label +-%{_root_sbindir}/e2undo +-%{_root_sbindir}/findfs +-%{_root_sbindir}/fsck +-%{_root_sbindir}/fsck.ext2 +-%{_root_sbindir}/fsck.ext3 +-%{_root_sbindir}/fsck.ext4 +-%{_root_sbindir}/fsck.ext4dev +-%{_root_sbindir}/logsave +-%{_root_sbindir}/mke2fs +-%{_root_etcdir}/mke2fs.conf +-%{_root_sbindir}/mkfs.ext2 +-%{_root_sbindir}/mkfs.ext3 +-%{_root_sbindir}/mkfs.ext4 +-%{_root_sbindir}/mkfs.ext4dev +-%{_root_sbindir}/resize2fs +-%{_root_sbindir}/tune2fs +-%{_sbindir}/filefrag +-%{_sbindir}/mklost+found +-%{_sbindir}/e2freefrag +- +-%{_root_libdir}/libblkid.so.* +-%{_root_libdir}/libcom_err.so.* +-%{_root_libdir}/libe2p.so.* +-%{_root_libdir}/libext2fs.so.* +-%{_root_libdir}/libss.so.* +-%{_root_libdir}/libuuid.so.* +- +-%{_libdir}/e2initrd_helper +- +-%{_bindir}/chattr +-%{_bindir}/lsattr +-%{_bindir}/uuidgen +-%{_mandir}/man1/chattr.1* +-%{_mandir}/man1/lsattr.1* +-%{_mandir}/man1/uuidgen.1* +- +-%{_mandir}/man5/e2fsck.conf.5* +-%{_mandir}/man5/mke2fs.conf.5* +- +-%{_mandir}/man8/badblocks.8* +-%{_mandir}/man8/blkid.8* +-%{_mandir}/man8/debugfs.8* +-%{_mandir}/man8/dumpe2fs.8* +-%{_mandir}/man8/e2fsck.8* +-%{_mandir}/man8/findfs.8* +-%{_mandir}/man8/fsck.ext2.8* +-%{_mandir}/man8/fsck.ext3.8* +-%{_mandir}/man8/fsck.ext4.8* +-%{_mandir}/man8/fsck.ext4dev.8* +-%{_mandir}/man8/e2image.8* +-%{_mandir}/man8/e2label.8* +-%{_mandir}/man8/e2undo.8* +-%{_mandir}/man8/fsck.8* +-%{_mandir}/man8/logsave.8* +-%{_mandir}/man8/mke2fs.8* +-%{_mandir}/man8/mkfs.ext2.8* +-%{_mandir}/man8/mkfs.ext3.8* +-%{_mandir}/man8/mkfs.ext4.8* +-%{_mandir}/man8/mkfs.ext4dev.8* +-%{_mandir}/man8/mklost+found.8* +-%{_mandir}/man8/resize2fs.8* +-%{_mandir}/man8/tune2fs.8* +-%{_mandir}/man8/filefrag.8* +-%{_mandir}/man8/e2freefrag.8* +- +-%files devel +-%defattr(-,root,root) +-%{_infodir}/libext2fs.info* +-%{_bindir}/compile_et +-%{_bindir}/mk_cmds +- +-%{_libdir}/libblkid.a +-%{_libdir}/libblkid.so +-%{_libdir}/libcom_err.a +-%{_libdir}/libcom_err.so +-%{_libdir}/libe2p.a +-%{_libdir}/libe2p.so +-%{_libdir}/libext2fs.a +-%{_libdir}/libext2fs.so +-%{_libdir}/libss.a +-%{_libdir}/libss.so +-%{_libdir}/libuuid.a +-%{_libdir}/libuuid.so +- +-%{_libdir}/pkgconfig/blkid.pc +-%{_libdir}/pkgconfig/com_err.pc +-%{_libdir}/pkgconfig/e2p.pc +-%{_libdir}/pkgconfig/ext2fs.pc +-%{_libdir}/pkgconfig/ss.pc +-%{_libdir}/pkgconfig/uuid.pc +- +-%{_datadir}/et +-%{_datadir}/ss +-%{_includedir}/blkid +-%{_includedir}/e2p +-%{_includedir}/et +-%{_includedir}/com_err.h +-%{_includedir}/ext2fs +-%{_includedir}/ss +-%{_includedir}/uuid +-%{_mandir}/man1/compile_et.1* +-%{_mandir}/man1/mk_cmds.1* +-%{_mandir}/man3/com_err.3* +-%{_mandir}/man3/libblkid.3* +-%{_mandir}/man3/uuid.3* +-%{_mandir}/man3/uuid_clear.3* +-%{_mandir}/man3/uuid_compare.3* +-%{_mandir}/man3/uuid_copy.3* +-%{_mandir}/man3/uuid_generate.3* +-%{_mandir}/man3/uuid_generate_random.3* +-%{_mandir}/man3/uuid_generate_time.3* +-%{_mandir}/man3/uuid_is_null.3* +-%{_mandir}/man3/uuid_parse.3* +-%{_mandir}/man3/uuid_time.3* +-%{_mandir}/man3/uuid_unparse.3* +- +-%files -n uuidd +-%defattr(-,root,root) +-# if you want to run via init +-# /etc/init.d/uuidd +-%{_mandir}/man8/uuidd.8* +-%attr(6755, uuidd, uuidd) %{_sbindir}/uuidd +-%dir %attr(2775, uuidd, uuidd) /var/lib/libuuid +- +--- a/ext2ed/Makefile.in ++++ b/ext2ed/Makefile.in +@@ -34,6 +34,7 @@ + .c.o: + $(CC) -c $(ALL_CFLAGS) $< -o $@ + $(CHECK_CMD) $(ALL_CFLAGS) $< ++ $(CPPCHECK_CMD) $(CPPFLAGS) $< + + .SUFFIXES: .sgml .ps .pdf .html + +--- a/.gitignore ++++ b/.gitignore +@@ -154,6 +154,7 @@ + misc/dumpe2fs.8 + misc/e2freefrag + misc/e2freefrag.8 ++misc/e2fuzz + misc/e2image + misc/e2image.8 + misc/e2initrd_helper +--- /dev/null ++++ b/.hgignore +@@ -0,0 +1,7 @@ ++^autom4te.cache ++^build ++^FILES ++^core ++~$ ++^.pc ++^patches +--- a/intl/Makefile.in ++++ b/intl/Makefile.in +@@ -61,17 +61,23 @@ + + @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 @@ + $(E) " CC $<" + $(Q) $(COMPILE) $< + $(Q) $(CHECK_CMD) $(ALL_CFLAGS) $< ++ $(Q) $(CPPCHECK_CMD) $(CPPFLAGS) $< + + .y.c: + $(YACC) $(YFLAGS) --output $@ $< +--- /dev/null ++++ b/lib/Android.mk +@@ -0,0 +1 @@ ++include $(call all-subdir-makefiles) +--- /dev/null ++++ b/lib/blkid/Android.mk +@@ -0,0 +1,63 @@ ++LOCAL_PATH := $(call my-dir) ++ ++libext2_blkid_src_files := \ ++ cache.c \ ++ dev.c \ ++ devname.c \ ++ devno.c \ ++ getsize.c \ ++ llseek.c \ ++ probe.c \ ++ read.c \ ++ resolve.c \ ++ save.c \ ++ tag.c \ ++ version.c \ ++ ++ ++libext2_blkid_shared_libraries := libext2_uuid ++ ++libext2_blkid_system_shared_libraries := libc ++ ++libext2_blkid_static_libraries := libext2_uuid_static ++ ++libext2_blkid_system_static_libraries := libc ++ ++libext2_blkid_c_includes := external/e2fsprogs/lib ++ ++libext2_blkid_cflags := -O2 -g -W -Wall -fno-strict-aliasing ++ ++include $(CLEAR_VARS) ++ ++LOCAL_SRC_FILES := $(libext2_blkid_src_files) ++LOCAL_SYSTEM_SHARED_LIBRARIES := $(libext2_blkid_system_shared_libraries) ++LOCAL_SHARED_LIBRARIES := $(libext2_blkid_shared_libraries) ++LOCAL_C_INCLUDES := $(libext2_blkid_c_includes) ++LOCAL_CFLAGS := $(libext2_blkid_cflags) ++LOCAL_MODULE := libext2_blkid ++LOCAL_MODULE_TAGS := optional ++ ++include $(BUILD_SHARED_LIBRARY) ++ ++include $(CLEAR_VARS) ++ ++LOCAL_SRC_FILES := $(libext2_blkid_src_files) ++LOCAL_STATIC_LIBRARIES := $(libext2_blkid_static_libraries) $(libext2_blkid_system_static_libraries) ++LOCAL_C_INCLUDES := $(libext2_blkid_c_includes) ++LOCAL_CFLAGS := $(libext2_blkid_cflags) $(libext2_blkid_cflags_linux) -fno-strict-aliasing ++LOCAL_PRELINK_MODULE := false ++LOCAL_MODULE := libext2_blkid ++LOCAL_MODULE_TAGS := optional ++ ++include $(BUILD_STATIC_LIBRARY) ++ ++include $(CLEAR_VARS) ++ ++LOCAL_SRC_FILES := $(libext2_blkid_src_files) ++LOCAL_SHARED_LIBRARIES := $(addsuffix _host, $(libext2_blkid_shared_libraries)) ++LOCAL_C_INCLUDES := $(libext2_blkid_c_includes) ++LOCAL_CFLAGS := $(libext2_blkid_cflags) ++LOCAL_MODULE := libext2_blkid_host ++LOCAL_MODULE_TAGS := optional ++ ++include $(BUILD_HOST_SHARED_LIBRARY) +--- a/lib/blkid/getsize.c ++++ b/lib/blkid/getsize.c +@@ -9,8 +9,12 @@ + * %End-Header% + */ + ++#ifndef _LARGEFILE_SOURCE + #define _LARGEFILE_SOURCE ++#endif ++#ifndef _LARGEFILE64_SOURCE + #define _LARGEFILE64_SOURCE ++#endif + + #include "config.h" + #include "blkidP.h" +--- a/lib/blkid/llseek.c ++++ b/lib/blkid/llseek.c +@@ -9,8 +9,12 @@ + * %End-Header% + */ + ++#ifndef _LARGEFILE_SOURCE + #define _LARGEFILE_SOURCE ++#endif ++#ifndef _LARGEFILE64_SOURCE + #define _LARGEFILE64_SOURCE ++#endif + + #include "config.h" + #if HAVE_SYS_TYPES_H +--- a/lib/blkid/Makefile.in ++++ b/lib/blkid/Makefile.in +@@ -55,6 +55,7 @@ + $(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 $< +@@ -178,7 +179,7 @@ + tst_tag tst_types tests/*.out tests/*.ok \ + tests/*.img results test_probe core profiled/* \ + blkid.h blkid_types.h ../libblkid.a ../libblkid_p.a \ +- $(SMANPAGES) blkid ++ $(SMANPAGES) blkid blkid.pc + @echo rmdir tests/tmp tests + @(rmdir tests/tmp tests 2> /dev/null ; exit 0) + +--- a/lib/blkid/probe.c ++++ b/lib/blkid/probe.c +@@ -874,8 +874,9 @@ + return 0; + } + +-static int probe_zfs(struct blkid_probe *probe, struct blkid_magic *id, +- unsigned char *buf) ++static int probe_zfs(struct blkid_probe *probe __BLKID_ATTR((unused)), ++ struct blkid_magic *id __BLKID_ATTR((unused)), ++ unsigned char *buf __BLKID_ATTR((unused))) + { + #if 0 + char *vdev_label; +@@ -1376,7 +1377,7 @@ + } + + static int probe_btrfs(struct blkid_probe *probe, +- struct blkid_magic *id, ++ struct blkid_magic *id __BLKID_ATTR((unused)), + unsigned char *buf) + { + struct btrfs_super_block *bs; +--- a/lib/blkid/probe.h ++++ b/lib/blkid/probe.h +@@ -110,6 +110,7 @@ + #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 +--- a/lib/config.h.in ++++ b/lib/config.h.in +@@ -1,4 +1,4 @@ +-/* lib/config.h.in. Generated from configure.in by autoheader. */ ++/* lib/config.h.in. Generated from configure.ac by autoheader. */ + + /* Define if building universal (internal helper macro) */ + #undef AC_APPLE_UNIVERSAL_BUILD +@@ -12,8 +12,8 @@ + /* Define to 1 if debugging ext3/4 journal code */ + #undef CONFIG_JBD_DEBUG + +-/* Define to 1 to enable quota support */ +-#undef CONFIG_QUOTA ++/* Define to 1 to enable mmp support */ ++#undef CONFIG_MMP + + /* Define to 1 if the testio I/O manager should be enabled */ + #undef CONFIG_TESTIO_DEBUG +@@ -29,16 +29,19 @@ + /* Define to 1 to disable use of backtrace */ + #undef DISABLE_BACKTRACE + +-/* Define to 1 if ext2 compression enabled */ +-#undef ENABLE_COMPRESSION ++/* Define to 1 to enable bitmap stats. */ ++#undef ENABLE_BMAP_STATS + +-/* Define to 1 if ext3/4 htree support enabled */ +-#undef ENABLE_HTREE ++/* Define to 1 to enable bitmap stats. */ ++#undef ENABLE_BMAP_STATS_OPS + + /* Define to 1 if translation of program messages to the user's native + language is requested. */ + #undef ENABLE_NLS + ++/* Define to 1 if you have the `add_key' function. */ ++#undef HAVE_ADD_KEY ++ + /* Define to 1 if you have `alloca', as a function or macro. */ + #undef HAVE_ALLOCA + +@@ -61,6 +64,9 @@ + /* Define to 1 if you have the `asprintf' function. */ + #undef HAVE_ASPRINTF + ++/* Define to 1 if you have the header file. */ ++#undef HAVE_ATTR_XATTR_H ++ + /* Define to 1 if you have the `backtrace' function. */ + #undef HAVE_BACKTRACE + +@@ -150,6 +156,9 @@ + /* Define to 1 if you have the `ftruncate64' function. */ + #undef HAVE_FTRUNCATE64 + ++/* Define to 1 if you have the header file. */ ++#undef HAVE_FUSE_H ++ + /* Define to 1 if you have the `futimes' function. */ + #undef HAVE_FUTIMES + +@@ -214,6 +223,9 @@ + /* Define to 1 if you have the `jrand48' function. */ + #undef HAVE_JRAND48 + ++/* Define to 1 if you have the `keyctl' function. */ ++#undef HAVE_KEYCTL ++ + /* Define if you have and nl_langinfo(CODESET). */ + #undef HAVE_LANGINFO_CODESET + +@@ -235,6 +247,9 @@ + /* Define to 1 if you have the 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 + +@@ -250,6 +265,9 @@ + /* Define to 1 if lseek64 declared in unistd.h */ + #undef HAVE_LSEEK64_PROTOTYPE + ++/* Define to 1 if you have the header file. */ ++#undef HAVE_MAGIC_H ++ + /* Define to 1 if you have the `mallinfo' function. */ + #undef HAVE_MALLINFO + +@@ -331,6 +349,9 @@ + /* Define to 1 if you have the `pread64' function. */ + #undef HAVE_PREAD64 + ++/* Define to 1 if you have the header file. */ ++#undef HAVE_PTHREAD_H ++ + /* Define if the defines PTHREAD_MUTEX_RECURSIVE. */ + #undef HAVE_PTHREAD_MUTEX_RECURSIVE + +@@ -446,6 +467,9 @@ + /* Define to 1 if you have the `sysconf' function. */ + #undef HAVE_SYSCONF + ++/* Define to 1 if you have the header file. */ ++#undef HAVE_SYS_ACL_H ++ + /* Define to 1 if you have the header file. */ + #undef HAVE_SYS_DISKLABEL_H + +@@ -458,6 +482,9 @@ + /* Define to 1 if you have the header file. */ + #undef HAVE_SYS_IOCTL_H + ++/* Define to 1 if you have the header file. */ ++#undef HAVE_SYS_KEY_H ++ + /* Define to 1 if you have the header file. */ + #undef HAVE_SYS_MKDEV_H + +@@ -491,6 +518,9 @@ + /* Define to 1 if you have the header file. */ + #undef HAVE_SYS_SYSCALL_H + ++/* Define to 1 if you have the header file. */ ++#undef HAVE_SYS_SYSCTL_H ++ + /* Define to 1 if you have the header file. */ + #undef HAVE_SYS_SYSMACROS_H + +--- /dev/null ++++ b/lib/e2p/Android.mk +@@ -0,0 +1,64 @@ ++LOCAL_PATH := $(call my-dir) ++ ++libext2_e2p_src_files := \ ++ feature.c \ ++ fgetflags.c \ ++ fsetflags.c \ ++ fgetversion.c \ ++ fsetversion.c \ ++ getflags.c \ ++ getversion.c \ ++ hashstr.c \ ++ iod.c \ ++ ls.c \ ++ mntopts.c \ ++ parse_num.c \ ++ pe.c \ ++ pf.c \ ++ ps.c \ ++ setflags.c \ ++ setversion.c \ ++ uuid.c \ ++ ostype.c \ ++ percent.c ++ ++libext2_e2p_c_includes := external/e2fsprogs/lib ++ ++libext2_e2p_cflags := -O2 -g -W -Wall ++ ++libext2_e2p_system_shared_libraries := libc ++ ++libext2_e2p_system_static_libraries := libc ++ ++include $(CLEAR_VARS) ++ ++LOCAL_SRC_FILES := $(libext2_e2p_src_files) ++LOCAL_C_INCLUDES := $(libext2_e2p_c_includes) ++LOCAL_CFLAGS := $(libext2_e2p_cflags) ++LOCAL_SYSTEM_SHARED_LIBRARIES := $(libext2_e2p_system_shared_libraries) ++LOCAL_MODULE := libext2_e2p ++LOCAL_MODULE_TAGS := optional ++ ++include $(BUILD_SHARED_LIBRARY) ++ ++include $(CLEAR_VARS) ++ ++LOCAL_SRC_FILES := $(libext2_e2p_src_files) ++LOCAL_C_INCLUDES := $(libext2_e2p_c_includes) ++LOCAL_CFLAGS := $(libext2_e2p_cflags) ++LOCAL_STATIC_LIBRARIES := $(libext2_e2p_system_static_libraries) ++LOCAL_PRELINK_MODULE := false ++LOCAL_MODULE := libext2_e2p ++LOCAL_MODULE_TAGS := optional ++ ++include $(BUILD_STATIC_LIBRARY) ++ ++include $(CLEAR_VARS) ++ ++LOCAL_SRC_FILES := $(libext2_e2p_src_files) ++LOCAL_C_INCLUDES := $(libext2_e2p_c_includes) ++LOCAL_CFLAGS := $(libext2_e2p_cflags) ++LOCAL_MODULE := libext2_e2p_host ++LOCAL_MODULE_TAGS := optional ++ ++include $(BUILD_HOST_SHARED_LIBRARY) +--- /dev/null ++++ b/lib/e2p/crypto_mode.c +@@ -0,0 +1,73 @@ ++/* ++ * crypto_mode.c --- convert between encryption modes and strings ++ * ++ * Copyright (C) 1999 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 ++#include ++#include ++#include ++#include ++ ++#include "e2p.h" ++ ++struct mode { ++ unsigned int num; ++ const char *string; ++}; ++ ++static struct mode mode_list[] = { ++ { EXT4_ENCRYPTION_MODE_INVALID, "Invalid"}, ++ { EXT4_ENCRYPTION_MODE_AES_256_XTS, "AES-256-XTS"}, ++ { EXT4_ENCRYPTION_MODE_AES_256_GCM, "AES-256-GCM"}, ++ { EXT4_ENCRYPTION_MODE_AES_256_CBC, "AES-256-CBC"}, ++ { 0, 0 }, ++}; ++ ++const char *e2p_encmode2string(int num) ++{ ++ struct mode *p; ++ static char buf[20]; ++ ++ for (p = mode_list; p->string; p++) { ++ if (num == p->num) ++ return p->string; ++ } ++ sprintf(buf, "ENC_MODE_%d", num); ++ return buf; ++} ++ ++/* ++ * Returns the hash algorithm, or -1 on error ++ */ ++int e2p_string2encmode(char *string) ++{ ++ struct mode *p; ++ char *eptr; ++ int num; ++ ++ for (p = mode_list; p->string; p++) { ++ if (!strcasecmp(string, p->string)) { ++ return p->num; ++ } ++ } ++ if (strncasecmp(string, "ENC_MODE_", 9)) ++ return -1; ++ ++ if (string[9] == 0) ++ return -1; ++ num = strtol(string+9, &eptr, 10); ++ if (num > 255 || num < 0) ++ return -1; ++ if (*eptr) ++ return -1; ++ return num; ++} ++ +--- a/lib/e2p/feature.c ++++ b/lib/e2p/feature.c +@@ -18,7 +18,7 @@ + + #include "e2p.h" + #include +-#include ++#include + + struct feature { + int compat; +@@ -68,6 +68,8 @@ + "metadata_csum"}, + { E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_REPLICA, + "replica" }, ++ { E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_READONLY, ++ "read-only" }, + + { E2P_FEATURE_INCOMPAT, EXT2_FEATURE_INCOMPAT_COMPRESSION, + "compression" }, +@@ -95,8 +97,10 @@ + "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"}, ++ { E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_ENCRYPT, ++ "encrypt"}, + { 0, 0, 0 }, + }; + +@@ -110,6 +114,10 @@ + "journal_64bit" }, + { E2P_FEATURE_INCOMPAT, JFS_FEATURE_INCOMPAT_ASYNC_COMMIT, + "journal_async_commit" }, ++ { E2P_FEATURE_INCOMPAT, JFS_FEATURE_INCOMPAT_CSUM_V2, ++ "journal_checksum_v2" }, ++ { E2P_FEATURE_INCOMPAT, JFS_FEATURE_INCOMPAT_CSUM_V3, ++ "journal_checksum_v3" }, + { 0, 0, 0 }, + }; + +@@ -179,7 +187,7 @@ + if (string[9] == 0) + return 1; + num = strtol(string+9, &eptr, 10); +- if (num > 32 || num < 0) ++ if (num > 31 || num < 0) + return 1; + if (*eptr) + return 1; +@@ -253,7 +261,7 @@ + if (string[9] == 0) + return 1; + num = strtol(string+9, &eptr, 10); +- if (num > 32 || num < 0) ++ if (num > 31 || num < 0) + return 1; + if (*eptr) + return 1; +--- a/lib/e2p/fgetflags.c ++++ b/lib/e2p/fgetflags.c +@@ -16,8 +16,12 @@ + * 93/10/30 - Creation + */ + ++#ifndef _LARGEFILE_SOURCE + #define _LARGEFILE_SOURCE ++#endif ++#ifndef _LARGEFILE64_SOURCE + #define _LARGEFILE64_SOURCE ++#endif + + #include "config.h" + #if HAVE_ERRNO_H +--- a/lib/e2p/fgetversion.c ++++ b/lib/e2p/fgetversion.c +@@ -16,8 +16,12 @@ + * 93/10/30 - Creation + */ + ++#ifndef _LARGEFILE_SOURCE + #define _LARGEFILE_SOURCE ++#endif ++#ifndef _LARGEFILE64_SOURCE + #define _LARGEFILE64_SOURCE ++#endif + + #include "config.h" + #if HAVE_ERRNO_H +--- a/lib/e2p/fsetflags.c ++++ b/lib/e2p/fsetflags.c +@@ -16,8 +16,12 @@ + * 93/10/30 - Creation + */ + ++#ifndef _LARGEFILE_SOURCE + #define _LARGEFILE_SOURCE ++#endif ++#ifndef _LARGEFILE64_SOURCE + #define _LARGEFILE64_SOURCE ++#endif + + #include "config.h" + #if HAVE_ERRNO_H +--- a/lib/e2p/fsetversion.c ++++ b/lib/e2p/fsetversion.c +@@ -16,8 +16,12 @@ + * 93/10/30 - Creation + */ + ++#ifndef _LARGEFILE_SOURCE + #define _LARGEFILE_SOURCE ++#endif ++#ifndef _LARGEFILE64_SOURCE + #define _LARGEFILE64_SOURCE ++#endif + + #include "config.h" + #if HAVE_ERRNO_H +--- a/lib/e2p/ls.c ++++ b/lib/e2p/ls.c +@@ -196,6 +196,16 @@ + #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,15 @@ + 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); ++ } ++ if (!e2p_is_null_uuid(sb->s_encrypt_pw_salt)) ++ fprintf(f, "Encryption PW Salt: %s\n", ++ e2p_uuid2str(sb->s_encrypt_pw_salt)); + } + + void list_super (struct ext2_super_block * s) +--- a/lib/e2p/Makefile.in ++++ b/lib/e2p/Makefile.in +@@ -19,7 +19,7 @@ + OBJS= feature.o fgetflags.o fsetflags.o fgetversion.o fsetversion.o \ + getflags.o getversion.o hashstr.o iod.o ls.o mntopts.o \ + parse_num.o pe.o pf.o ps.o setflags.o setversion.o uuid.o \ +- ostype.o percent.o ++ ostype.o percent.o crypto_mode.o + + SRCS= $(srcdir)/feature.c $(srcdir)/fgetflags.c \ + $(srcdir)/fsetflags.c $(srcdir)/fgetversion.c \ +@@ -28,7 +28,7 @@ + $(srcdir)/ls.c $(srcdir)/mntopts.c $(srcdir)/parse_num.c \ + $(srcdir)/pe.c $(srcdir)/pf.c $(srcdir)/ps.c \ + $(srcdir)/setflags.c $(srcdir)/setversion.c $(srcdir)/uuid.c \ +- $(srcdir)/ostype.c $(srcdir)/percent.c ++ $(srcdir)/ostype.c $(srcdir)/percent.c $(srcdir)/crypto_mode.c + HFILES= e2p.h + + LIBRARY= libe2p +@@ -55,6 +55,7 @@ + $(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 $< +@@ -101,7 +102,7 @@ + + clean:: + $(RM) -f \#* *.s *.o *.a *~ *.bak core profiled/* +- $(RM) -f ../libe2p.a ../libe2p_p.a tst_ostype tst_feature ++ $(RM) -f ../libe2p.a ../libe2p_p.a tst_ostype tst_feature e2p.pc + + mostlyclean:: clean + distclean:: clean +@@ -122,8 +123,8 @@ + $(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/ext2fs/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/kernel-jbd.h $(top_srcdir)/lib/ext2fs/jfs_compat.h \ ++ $(top_srcdir)/lib/ext2fs/kernel-list.h + fgetflags.o: $(srcdir)/fgetflags.c $(top_builddir)/lib/config.h \ + $(top_builddir)/lib/dirpaths.h $(srcdir)/e2p.h \ + $(top_srcdir)/lib/ext2fs/ext2_fs.h $(top_builddir)/lib/ext2fs/ext2_types.h +@@ -181,3 +182,6 @@ + percent.o: $(srcdir)/percent.c $(top_builddir)/lib/config.h \ + $(top_builddir)/lib/dirpaths.h $(srcdir)/e2p.h \ + $(top_srcdir)/lib/ext2fs/ext2_fs.h $(top_builddir)/lib/ext2fs/ext2_types.h ++crypto_mode.o: $(srcdir)/crypto_mode.c $(top_builddir)/lib/config.h \ ++ $(top_builddir)/lib/dirpaths.h $(srcdir)/e2p.h \ ++ $(top_srcdir)/lib/ext2fs/ext2_fs.h $(top_builddir)/lib/ext2fs/ext2_types.h +--- a/lib/e2p/mntopts.c ++++ b/lib/e2p/mntopts.c +@@ -72,7 +72,7 @@ + if (string[8] == 0) + return 1; + num = strtol(string+8, &eptr, 10); +- if (num > 32 || num < 0) ++ if (num > 31 || num < 0) + return 1; + if (*eptr) + return 1; +--- a/lib/e2p/pf.c ++++ b/lib/e2p/pf.c +@@ -37,12 +37,7 @@ + { EXT2_NODUMP_FL, "d", "No_Dump" }, + { EXT2_NOATIME_FL, "A", "No_Atime" }, + { EXT2_COMPR_FL, "c", "Compression_Requested" }, +-#ifdef ENABLE_COMPRESSION +- { EXT2_COMPRBLK_FL, "B", "Compressed_File" }, +- { EXT2_DIRTY_FL, "Z", "Compressed_Dirty_File" }, +- { EXT2_NOCOMPR_FL, "X", "Compression_Raw_Access" }, +- { EXT2_ECOMPR_FL, "E", "Compression_Error" }, +-#endif ++ { EXT4_ENCRYPT_FL, "E", "Encrypted" }, + { EXT3_JOURNAL_DATA_FL, "j", "Journaled_Data" }, + { EXT2_INDEX_FL, "I", "Indexed_directory" }, + { EXT2_NOTAIL_FL, "t", "No_Tailmerging" }, +@@ -50,6 +45,7 @@ + { 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 } + }; + +--- /dev/null ++++ b/lib/et/Android.mk +@@ -0,0 +1,47 @@ ++LOCAL_PATH := $(call my-dir) ++ ++libext2_com_err_src_files := \ ++ error_message.c \ ++ et_name.c \ ++ init_et.c \ ++ com_err.c \ ++ com_right.c ++ ++libext2_com_err_c_includes := external/e2fsprogs/lib ++ ++libext2_com_err_cflags := -O2 -g -W -Wall ++ ++libext2_com_err_system_shared_libraries := libc ++ ++include $(CLEAR_VARS) ++ ++LOCAL_SRC_FILES := $(libext2_com_err_src_files) ++LOCAL_C_INCLUDES := $(libext2_com_err_c_includes) ++LOCAL_CFLAGS := $(libext2_com_err_cflags) ++LOCAL_SYSTEM_SHARED_LIBRARIES := libc ++LOCAL_MODULE := libext2_com_err ++LOCAL_MODULE_TAGS := optional ++ ++include $(BUILD_SHARED_LIBRARY) ++ ++include $(CLEAR_VARS) ++ ++LOCAL_SRC_FILES := $(libext2_com_err_src_files) ++LOCAL_C_INCLUDES := $(libext2_com_err_c_includes) ++LOCAL_CFLAGS := $(libext2_com_err_cflags) ++LOCAL_STATIC_LIBRARIES := libc ++LOCAL_MODULE := libext2_com_err ++LOCAL_MODULE_TAGS := optional ++LOCAL_PRELINK_MODULE := false ++ ++include $(BUILD_STATIC_LIBRARY) ++ ++include $(CLEAR_VARS) ++ ++LOCAL_SRC_FILES := $(libext2_com_err_src_files) ++LOCAL_C_INCLUDES := $(libext2_com_err_c_includes) ++LOCAL_CFLAGS := $(libext2_com_err_cflags) ++LOCAL_MODULE := libext2_com_err_host ++LOCAL_MODULE_TAGS := optional ++ ++include $(BUILD_HOST_SHARED_LIBRARY) +--- a/lib/et/Makefile.in ++++ b/lib/et/Makefile.in +@@ -44,6 +44,7 @@ + $(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 $< +--- a/lib/ext2fs/alloc.c ++++ b/lib/ext2fs/alloc.c +@@ -26,13 +26,22 @@ + #include "ext2_fs.h" + #include "ext2fs.h" + ++#define min(a, b) ((a) < (b) ? (a) : (b)) ++ ++#undef DEBUG ++ ++#ifdef DEBUG ++# define dbg_printf(f, a...) do {printf(f, ## a); fflush(stdout); } while (0) ++#else ++# define dbg_printf(f, a...) ++#endif ++ + /* + * Clear the uninit block bitmap flag if necessary + */ + 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 +61,7 @@ + { + 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; + +@@ -139,9 +147,23 @@ + { + errcode_t retval; + blk64_t b = 0; ++ errcode_t (*gab)(ext2_filsys fs, blk64_t goal, blk64_t *ret); + + EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); + ++ if (!map && fs->get_alloc_block) { ++ /* ++ * In case there are clients out there whose get_alloc_block ++ * handlers call ext2fs_new_block2 with a NULL block map, ++ * temporarily swap out the function pointer so that we don't ++ * end up in an infinite loop. ++ */ ++ gab = fs->get_alloc_block; ++ fs->get_alloc_block = NULL; ++ retval = gab(fs, goal, &b); ++ fs->get_alloc_block = gab; ++ goto allocated; ++ } + if (!map) + map = fs->block_map; + if (!map) +@@ -155,6 +177,7 @@ + if ((retval == ENOENT) && (goal != fs->super->s_first_data_block)) + retval = ext2fs_find_first_zero_block_bitmap2(map, + fs->super->s_first_data_block, goal - 1, &b); ++allocated: + if (retval == ENOENT) + return EXT2_ET_BLOCK_ALLOC_FAIL; + if (retval) +@@ -185,15 +208,6 @@ + { + errcode_t retval; + blk64_t block; +- char *buf = 0; +- +- if (!block_buf) { +- retval = ext2fs_get_mem(fs->blocksize, &buf); +- if (retval) +- return retval; +- block_buf = buf; +- } +- memset(block_buf, 0, fs->blocksize); + + if (fs->get_alloc_block) { + retval = (fs->get_alloc_block)(fs, goal, &block); +@@ -211,7 +225,11 @@ + goto fail; + } + +- retval = io_channel_write_blk64(fs->io, block, 1, block_buf); ++ if (block_buf) { ++ memset(block_buf, 0, fs->blocksize); ++ retval = io_channel_write_blk64(fs->io, block, 1, block_buf); ++ } else ++ retval = ext2fs_zero_blocks2(fs, block, 1, NULL, NULL); + if (retval) + goto fail; + +@@ -219,8 +237,6 @@ + *ret = block; + + fail: +- if (buf) +- ext2fs_free_mem(&buf); + return retval; + } + +@@ -298,3 +314,211 @@ + + fs->get_alloc_block = func; + } ++ ++blk64_t ext2fs_find_inode_goal(ext2_filsys fs, ext2_ino_t ino, ++ struct ext2_inode *inode, blk64_t lblk) ++{ ++ dgrp_t group; ++ __u8 log_flex; ++ struct ext2fs_extent extent; ++ ext2_extent_handle_t handle = NULL; ++ errcode_t err; ++ ++ if (inode == NULL || ext2fs_inode_data_blocks2(fs, inode) == 0) ++ goto no_blocks; ++ ++ if (inode->i_flags & EXT4_INLINE_DATA_FL) ++ goto no_blocks; ++ ++ if (inode->i_flags & EXT4_EXTENTS_FL) { ++ err = ext2fs_extent_open2(fs, ino, inode, &handle); ++ if (err) ++ goto no_blocks; ++ err = ext2fs_extent_goto2(handle, 0, lblk); ++ if (err) ++ goto no_blocks; ++ err = ext2fs_extent_get(handle, EXT2_EXTENT_CURRENT, &extent); ++ if (err) ++ goto no_blocks; ++ ext2fs_extent_free(handle); ++ return extent.e_pblk + (lblk - extent.e_lblk); ++ } ++ ++ /* block mapped file; see if block zero is mapped? */ ++ if (inode->i_block[0]) ++ return inode->i_block[0]; ++ ++no_blocks: ++ ext2fs_extent_free(handle); ++ log_flex = fs->super->s_log_groups_per_flex; ++ group = ext2fs_group_of_ino(fs, ino); ++ if (log_flex) ++ group = group & ~((1 << (log_flex)) - 1); ++ return ext2fs_group_first_block2(fs, group); ++} ++ ++/* ++ * Starting at _goal_, scan around the filesystem to find a run of free blocks ++ * that's at least _len_ blocks long. Possible flags: ++ * - EXT2_NEWRANGE_EXACT_GOAL: The range of blocks must start at _goal_. ++ * - EXT2_NEWRANGE_MIN_LENGTH: do not return a allocation shorter than _len_. ++ * - EXT2_NEWRANGE_ZERO_BLOCKS: Zero blocks pblk to pblk+plen before returning. ++ * ++ * The starting block is returned in _pblk_ and the length is returned via ++ * _plen_. The blocks are not marked in the bitmap; the caller must mark ++ * however much of the returned run they actually use, hopefully via ++ * ext2fs_block_alloc_stats_range(). ++ * ++ * This function can return a range that is longer than what was requested. ++ */ ++errcode_t ext2fs_new_range(ext2_filsys fs, int flags, blk64_t goal, ++ blk64_t len, ext2fs_block_bitmap map, blk64_t *pblk, ++ blk64_t *plen) ++{ ++ errcode_t retval; ++ blk64_t start, end, b; ++ int looped = 0; ++ blk64_t max_blocks = ext2fs_blocks_count(fs->super); ++ errcode_t (*nrf)(ext2_filsys fs, int flags, blk64_t goal, ++ blk64_t len, blk64_t *pblk, blk64_t *plen); ++ ++ dbg_printf("%s: flags=0x%x goal=%llu len=%llu\n", __func__, flags, ++ goal, len); ++ EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); ++ if (len == 0 || (flags & ~EXT2_NEWRANGE_ALL_FLAGS)) ++ return EXT2_ET_INVALID_ARGUMENT; ++ ++ if (!map && fs->new_range) { ++ /* ++ * In case there are clients out there whose new_range ++ * handlers call ext2fs_new_range with a NULL block map, ++ * temporarily swap out the function pointer so that we don't ++ * end up in an infinite loop. ++ */ ++ nrf = fs->new_range; ++ fs->new_range = NULL; ++ retval = nrf(fs, flags, goal, len, pblk, plen); ++ fs->new_range = nrf; ++ if (retval) ++ return retval; ++ start = *pblk; ++ end = *pblk + *plen; ++ goto allocated; ++ } ++ if (!map) ++ map = fs->block_map; ++ if (!map) ++ return EXT2_ET_NO_BLOCK_BITMAP; ++ if (!goal || goal >= ext2fs_blocks_count(fs->super)) ++ goal = fs->super->s_first_data_block; ++ ++ start = goal; ++ while (!looped || start <= goal) { ++ retval = ext2fs_find_first_zero_block_bitmap2(map, start, ++ max_blocks - 1, ++ &start); ++ if (retval == ENOENT) { ++ /* ++ * If there are no free blocks beyond the starting ++ * point, try scanning the whole filesystem, unless the ++ * user told us only to allocate from _goal_, or if ++ * we're already scanning the whole filesystem. ++ */ ++ if (flags & EXT2_NEWRANGE_FIXED_GOAL || ++ start == fs->super->s_first_data_block) ++ goto fail; ++ start = fs->super->s_first_data_block; ++ continue; ++ } else if (retval) ++ goto errout; ++ ++ if (flags & EXT2_NEWRANGE_FIXED_GOAL && start != goal) ++ goto fail; ++ ++ b = min(start + len - 1, max_blocks - 1); ++ retval = ext2fs_find_first_set_block_bitmap2(map, start, b, ++ &end); ++ if (retval == ENOENT) ++ end = b + 1; ++ else if (retval) ++ goto errout; ++ ++ if (!(flags & EXT2_NEWRANGE_MIN_LENGTH) || ++ (end - start) >= len) { ++ /* Success! */ ++ *pblk = start; ++ *plen = end - start; ++ dbg_printf("%s: new_range goal=%llu--%llu " ++ "blk=%llu--%llu %llu\n", ++ __func__, goal, goal + len - 1, ++ *pblk, *pblk + *plen - 1, *plen); ++allocated: ++ for (b = start; b < end; ++ b += fs->super->s_blocks_per_group) ++ clear_block_uninit(fs, ++ ext2fs_group_of_blk2(fs, b)); ++ return 0; ++ } ++ ++ if (flags & EXT2_NEWRANGE_FIXED_GOAL) ++ goto fail; ++ start = end; ++ if (start >= max_blocks) { ++ if (looped) ++ goto fail; ++ looped = 1; ++ start = fs->super->s_first_data_block; ++ } ++ } ++ ++fail: ++ retval = EXT2_ET_BLOCK_ALLOC_FAIL; ++errout: ++ return retval; ++} ++ ++void ext2fs_set_new_range_callback(ext2_filsys fs, ++ errcode_t (*func)(ext2_filsys fs, int flags, blk64_t goal, ++ blk64_t len, blk64_t *pblk, blk64_t *plen), ++ errcode_t (**old)(ext2_filsys fs, int flags, blk64_t goal, ++ blk64_t len, blk64_t *pblk, blk64_t *plen)) ++{ ++ if (!fs || fs->magic != EXT2_ET_MAGIC_EXT2FS_FILSYS) ++ return; ++ ++ if (old) ++ *old = fs->new_range; ++ ++ fs->new_range = func; ++} ++ ++errcode_t ext2fs_alloc_range(ext2_filsys fs, int flags, blk64_t goal, ++ blk_t len, blk64_t *ret) ++{ ++ int newr_flags = EXT2_NEWRANGE_MIN_LENGTH; ++ errcode_t retval; ++ blk64_t plen; ++ ++ EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); ++ if (len == 0 || (flags & ~EXT2_ALLOCRANGE_ALL_FLAGS)) ++ return EXT2_ET_INVALID_ARGUMENT; ++ ++ if (flags & EXT2_ALLOCRANGE_FIXED_GOAL) ++ newr_flags |= EXT2_NEWRANGE_FIXED_GOAL; ++ ++ retval = ext2fs_new_range(fs, newr_flags, goal, len, NULL, ret, &plen); ++ if (retval) ++ return retval; ++ ++ if (plen < len) ++ return EXT2_ET_BLOCK_ALLOC_FAIL; ++ ++ if (flags & EXT2_ALLOCRANGE_ZERO_BLOCKS) { ++ retval = ext2fs_zero_blocks2(fs, *ret, len, NULL, NULL); ++ if (retval) ++ return retval; ++ } ++ ++ ext2fs_block_alloc_stats_range(fs, *ret, len, +1); ++ return retval; ++} +--- a/lib/ext2fs/alloc_stats.c ++++ b/lib/ext2fs/alloc_stats.c +@@ -38,8 +38,7 @@ + /* 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 @@ + 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; +@@ -146,4 +145,20 @@ + } + ext2fs_mark_super_dirty(fs); + ext2fs_mark_bb_dirty(fs); ++ if (fs->block_alloc_stats_range) ++ (fs->block_alloc_stats_range)(fs, blk, num, inuse); ++} ++ ++void ext2fs_set_block_alloc_stats_range_callback(ext2_filsys fs, ++ void (*func)(ext2_filsys fs, blk64_t blk, ++ blk_t num, int inuse), ++ void (**old)(ext2_filsys fs, blk64_t blk, ++ blk_t num, int inuse)) ++{ ++ if (!fs || fs->magic != EXT2_ET_MAGIC_EXT2FS_FILSYS) ++ return; ++ if (old) ++ *old = fs->block_alloc_stats_range; ++ ++ fs->block_alloc_stats_range = func; + } +--- a/lib/ext2fs/alloc_tables.c ++++ b/lib/ext2fs/alloc_tables.c +@@ -241,16 +241,19 @@ + 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; + } + +--- /dev/null ++++ b/lib/ext2fs/Android.mk +@@ -0,0 +1,140 @@ ++LOCAL_PATH := $(call my-dir) ++ ++libext2fs_src_files := \ ++ ext2_err.c \ ++ alloc.c \ ++ alloc_sb.c \ ++ alloc_stats.c \ ++ alloc_tables.c \ ++ atexit.c \ ++ badblocks.c \ ++ bb_inode.c \ ++ bitmaps.c \ ++ bitops.c \ ++ blkmap64_ba.c \ ++ blkmap64_rb.c \ ++ blknum.c \ ++ block.c \ ++ bmap.c \ ++ check_desc.c \ ++ crc16.c \ ++ crc32c.c \ ++ csum.c \ ++ closefs.c \ ++ dblist.c \ ++ dblist_dir.c \ ++ digest_encode.c \ ++ dirblock.c \ ++ dirhash.c \ ++ dir_iterate.c \ ++ dupfs.c \ ++ expanddir.c \ ++ ext_attr.c \ ++ extent.c \ ++ fallocate.c \ ++ fileio.c \ ++ finddev.c \ ++ flushb.c \ ++ freefs.c \ ++ gen_bitmap.c \ ++ gen_bitmap64.c \ ++ get_num_dirs.c \ ++ get_pathname.c \ ++ getsize.c \ ++ getsectsize.c \ ++ i_block.c \ ++ icount.c \ ++ imager.c \ ++ ind_block.c \ ++ initialize.c \ ++ inline.c \ ++ inline_data.c \ ++ inode.c \ ++ io_manager.c \ ++ ismounted.c \ ++ link.c \ ++ llseek.c \ ++ lookup.c \ ++ mmp.c \ ++ mkdir.c \ ++ mkjournal.c \ ++ namei.c \ ++ native.c \ ++ newdir.c \ ++ openfs.c \ ++ progress.c \ ++ punch.c \ ++ qcow2.c \ ++ rbtree.c \ ++ read_bb.c \ ++ read_bb_file.c \ ++ res_gdt.c \ ++ rw_bitmaps.c \ ++ sha256.c \ ++ sha512.c \ ++ swapfs.c \ ++ symlink.c \ ++ tdb.c \ ++ undo_io.c \ ++ unix_io.c \ ++ unlink.c \ ++ valid_blk.c \ ++ version.c ++ ++# get rid of this?! ++libext2fs_src_files += test_io.c ++ ++libext2fs_shared_libraries := \ ++ libext2_com_err \ ++ libext2_uuid \ ++ libext2_blkid \ ++ libext2_e2p ++ ++libext2fs_system_shared_libraries := libc ++ ++libext2fs_static_libraries := \ ++ libext2_com_err \ ++ libext2_uuid_static \ ++ libext2_blkid \ ++ libext2_e2p ++ ++libext2fs_system_static_libraries := libc ++ ++libext2fs_c_includes := external/e2fsprogs/lib ++ ++libext2fs_cflags := -O2 -g -W -Wall ++ ++include $(CLEAR_VARS) ++ ++LOCAL_SRC_FILES := $(libext2fs_src_files) ++LOCAL_SYSTEM_SHARED_LIBRARIES := $(libext2fs_system_shared_libraries) ++LOCAL_SHARED_LIBRARIES := $(libext2fs_shared_libraries) ++LOCAL_C_INCLUDES := $(libext2fs_c_includes) ++LOCAL_CFLAGS := $(libext2fs_cflags) ++LOCAL_MODULE := libext2fs ++LOCAL_MODULE_TAGS := optional ++ ++include $(BUILD_SHARED_LIBRARY) ++ ++include $(CLEAR_VARS) ++ ++LOCAL_SRC_FILES := $(libext2fs_src_files) ++LOCAL_STATIC_LIBRARIES := $(libext2fs_static_libraries) $(libext2fs_system_static_libraries) ++LOCAL_C_INCLUDES := $(libext2fs_c_includes) ++LOCAL_CFLAGS := $(libext2fs_cflags) $(libext2fs_cflags_linux) ++LOCAL_PRELINK_MODULE := false ++LOCAL_MODULE := libext2fs ++LOCAL_MODULE_TAGS := optional ++ ++include $(BUILD_STATIC_LIBRARY) ++ ++include $(CLEAR_VARS) ++ ++LOCAL_SRC_FILES := $(libext2fs_src_files) ++LOCAL_SHARED_LIBRARIES := $(addsuffix _host, $(libext2fs_shared_libraries)) ++LOCAL_C_INCLUDES := $(libext2fs_c_includes) ++LOCAL_CFLAGS := $(libext2fs_cflags) ++LOCAL_MODULE := libext2fs_host ++LOCAL_MODULE_TAGS := optional ++ ++include $(BUILD_HOST_SHARED_LIBRARY) +--- /dev/null ++++ b/lib/ext2fs/atexit.c +@@ -0,0 +1,116 @@ ++/* ++ * atexit.c --- Clean things up when we exit normally. ++ * ++ * Copyright Oracle, 2014 ++ * Author Darrick J. Wong ++ * ++ * %Begin-Header% ++ * This file may be redistributed under the terms of the GNU Library ++ * General Public License, version 2. ++ * %End-Header% ++ */ ++ ++#ifndef _LARGEFILE_SOURCE ++#define _LARGEFILE_SOURCE ++#endif ++#ifndef _LARGEFILE64_SOURCE ++#define _LARGEFILE64_SOURCE ++#endif ++ ++#include "config.h" ++#include ++ ++#include "ext2_fs.h" ++#include "ext2fs.h" ++#include "ext2fsP.h" ++ ++struct exit_data { ++ ext2_exit_fn func; ++ void *data; ++}; ++ ++static struct exit_data *items; ++static size_t nr_items; ++ ++static void handle_exit(void) ++{ ++ struct exit_data *ed; ++ ++ for (ed = items + nr_items - 1; ed >= items; ed--) { ++ if (ed->func == NULL) ++ continue; ++ ed->func(ed->data); ++ } ++ ++ ext2fs_free_mem(&items); ++ nr_items = 0; ++} ++ ++/* ++ * Schedule a function to be called at (normal) program termination. ++ * If you want this to be called during a signal exit, you must capture ++ * the signal and call exit() yourself! ++ */ ++errcode_t ext2fs_add_exit_fn(ext2_exit_fn func, void *data) ++{ ++ struct exit_data *ed, *free_ed = NULL; ++ size_t x; ++ errcode_t ret; ++ ++ if (func == NULL) ++ return EXT2_ET_INVALID_ARGUMENT; ++ ++ for (x = 0, ed = items; x < nr_items; x++, ed++) { ++ if (ed->func == func && ed->data == data) ++ return EXT2_ET_FILE_EXISTS; ++ if (ed->func == NULL) ++ free_ed = ed; ++ } ++ ++ if (free_ed) { ++ free_ed->func = func; ++ free_ed->data = data; ++ return 0; ++ } ++ ++ if (nr_items == 0) { ++ ret = atexit(handle_exit); ++ if (ret) ++ return ret; ++ } ++ ++ ret = ext2fs_resize_mem(0, (nr_items + 1) * sizeof(struct exit_data), ++ &items); ++ if (ret) ++ return ret; ++ ++ items[nr_items].func = func; ++ items[nr_items].data = data; ++ nr_items++; ++ ++ return 0; ++} ++ ++/* Remove a function from the exit cleanup list. */ ++errcode_t ext2fs_remove_exit_fn(ext2_exit_fn func, void *data) ++{ ++ struct exit_data *ed; ++ size_t x; ++ ++ if (func == NULL) ++ return EXT2_ET_INVALID_ARGUMENT; ++ ++ for (x = 0, ed = items; x < nr_items; x++, ed++) { ++ if (ed->func == NULL) ++ return 0; ++ if (ed->func == func && ed->data == data) { ++ size_t sz = (nr_items - (x + 1)) * ++ sizeof(struct exit_data); ++ memmove(ed, ed + 1, sz); ++ memset(items + nr_items - 1, 0, ++ sizeof(struct exit_data)); ++ } ++ } ++ ++ return 0; ++} +--- a/lib/ext2fs/bitops.h ++++ b/lib/ext2fs/bitops.h +@@ -11,31 +11,33 @@ + */ + + #ifdef WORDS_BIGENDIAN +-#define ext2fs_cpu_to_le64(x) ext2fs_swab64((x)) +-#define ext2fs_le64_to_cpu(x) ext2fs_swab64((x)) +-#define ext2fs_cpu_to_le32(x) ext2fs_swab32((x)) +-#define ext2fs_le32_to_cpu(x) ext2fs_swab32((x)) +-#define ext2fs_cpu_to_le16(x) ext2fs_swab16((x)) +-#define ext2fs_le16_to_cpu(x) ext2fs_swab16((x)) +-#define ext2fs_cpu_to_be64(x) ((__u64)(x)) +-#define ext2fs_be64_to_cpu(x) ((__u64)(x)) +-#define ext2fs_cpu_to_be32(x) ((__u32)(x)) +-#define ext2fs_be32_to_cpu(x) ((__u32)(x)) +-#define ext2fs_cpu_to_be16(x) ((__u16)(x)) +-#define ext2fs_be16_to_cpu(x) ((__u16)(x)) ++#define ext2fs_cpu_to_le64(x) ((__force __le64)ext2fs_swab64((__u64)(x))) ++#define ext2fs_le64_to_cpu(x) ext2fs_swab64((__force __u64)(__le64)(x)) ++#define ext2fs_cpu_to_le32(x) ((__force __le32)ext2fs_swab32((__u32)(x))) ++#define ext2fs_le32_to_cpu(x) ext2fs_swab32((__force __u32)(__le32)(x)) ++#define ext2fs_cpu_to_le16(x) ((__force __le16)ext2fs_swab16((__u16)(x))) ++#define ext2fs_le16_to_cpu(x) ext2fs_swab16((__force __u16)(__le16)(x)) ++ ++#define ext2fs_cpu_to_be64(x) ((__force __be64)(__u64)(x)) ++#define ext2fs_be64_to_cpu(x) ((__force __u64)(__be64)(x)) ++#define ext2fs_cpu_to_be32(x) ((__force __be32)(__u32)(x)) ++#define ext2fs_be32_to_cpu(x) ((__force __u32)(__be32)(x)) ++#define ext2fs_cpu_to_be16(x) ((__force __be16)(__u16)(x)) ++#define ext2fs_be16_to_cpu(x) ((__force __u16)(__be16)(x)) + #else +-#define ext2fs_cpu_to_le64(x) ((__u64)(x)) +-#define ext2fs_le64_to_cpu(x) ((__u64)(x)) +-#define ext2fs_cpu_to_le32(x) ((__u32)(x)) +-#define ext2fs_le32_to_cpu(x) ((__u32)(x)) +-#define ext2fs_cpu_to_le16(x) ((__u16)(x)) +-#define ext2fs_le16_to_cpu(x) ((__u16)(x)) +-#define ext2fs_cpu_to_be64(x) ext2fs_swab64((x)) +-#define ext2fs_be64_to_cpu(x) ext2fs_swab64((x)) +-#define ext2fs_cpu_to_be32(x) ext2fs_swab32((x)) +-#define ext2fs_be32_to_cpu(x) ext2fs_swab32((x)) +-#define ext2fs_cpu_to_be16(x) ext2fs_swab16((x)) +-#define ext2fs_be16_to_cpu(x) ext2fs_swab16((x)) ++#define ext2fs_cpu_to_le64(x) ((__force __le64)(__u64)(x)) ++#define ext2fs_le64_to_cpu(x) ((__force __u64)(__le64)(x)) ++#define ext2fs_cpu_to_le32(x) ((__force __le32)(__u32)(x)) ++#define ext2fs_le32_to_cpu(x) ((__force __u32)(__le32)(x)) ++#define ext2fs_cpu_to_le16(x) ((__force __le16)(__u16)(x)) ++#define ext2fs_le16_to_cpu(x) ((__force __u16)(__le16)(x)) ++ ++#define ext2fs_cpu_to_be64(x) ((__force __be64)ext2fs_swab64((__u64)(x))) ++#define ext2fs_be64_to_cpu(x) ext2fs_swab64((__force __u64)(__be64)(x)) ++#define ext2fs_cpu_to_be32(x) ((__force __be32)ext2fs_swab32((__u32)(x))) ++#define ext2fs_be32_to_cpu(x) ext2fs_swab32((__force __u32)(__be32)(x)) ++#define ext2fs_cpu_to_be16(x) ((__force __be16)ext2fs_swab16((__u16)(x))) ++#define ext2fs_be16_to_cpu(x) ext2fs_swab16((__force __u16)(__be16)(x)) + #endif + + /* +--- a/lib/ext2fs/blkmap64_ba.c ++++ b/lib/ext2fs/blkmap64_ba.c +@@ -310,12 +310,18 @@ + (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 EXT2FS_ATTR((unused))) ++{ ++} ++#endif + + /* Find the first zero bit between start and end, inclusive. */ + static errcode_t ba_find_first_zero(ext2fs_generic_bitmap bitmap, +--- a/lib/ext2fs/blkmap64_rb.c ++++ b/lib/ext2fs/blkmap64_rb.c +@@ -41,7 +41,7 @@ + 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 @@ + + 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 @@ + 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 @@ + 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 @@ + 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; +@@ -735,8 +733,7 @@ + struct rb_node *parent = NULL, *next, **n; + struct ext2fs_rb_private *bp; + struct bmap_rb_extent *ext; +- int count; +- __u64 pos; ++ __u64 count, pos; + + bp = (struct ext2fs_rb_private *) bitmap->private; + n = &bp->root.rb_node; +@@ -767,9 +764,9 @@ + if (pos >= start + num) + break; + if (pos < start) { +- count -= start - pos; +- if (count < 0) ++ if (pos + count < start) + continue; ++ count -= start - pos; + pos = start; + } + if (pos + count > start + num) +@@ -891,7 +888,7 @@ + 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 +899,7 @@ + __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 +923,7 @@ + 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 +950,9 @@ + 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 = { +--- a/lib/ext2fs/blknum.c ++++ b/lib/ext2fs/blknum.c +@@ -200,6 +200,21 @@ + } + + /* ++ * 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 @@ + } + + /* ++ * 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) +--- a/lib/ext2fs/block.c ++++ b/lib/ext2fs/block.c +@@ -345,6 +345,13 @@ + 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) { +--- a/lib/ext2fs/bmap64.h ++++ b/lib/ext2fs/bmap64.h +@@ -13,7 +13,7 @@ + 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 @@ + + unsigned long mark_seq; + unsigned long test_seq; +-#endif /* BMAP_STATS_OPS */ ++#endif /* ENABLE_BMAP_STATS_OPS */ + }; + + +@@ -48,7 +48,7 @@ + char *description; + void *private; + errcode_t base_error_code; +-#ifdef BMAP_STATS ++#ifdef ENABLE_BMAP_STATS + struct ext2_bmap_statistics stats; + #endif + }; +--- a/lib/ext2fs/bmap.c ++++ b/lib/ext2fs/bmap.c +@@ -214,10 +214,13 @@ + errcode_t retval = 0; + blk64_t blk64 = 0; + int alloc = 0; ++ int set_flags; ++ ++ set_flags = bmap_flags & BMAP_UNINIT ? EXT2_EXTENT_SET_BMAP_UNINIT : 0; + + if (bmap_flags & BMAP_SET) { + retval = ext2fs_extent_set_bmap(handle, block, +- *phys_blk, 0); ++ *phys_blk, set_flags); + return retval; + } + retval = ext2fs_extent_goto(handle, block); +@@ -244,7 +247,7 @@ + retval = extent_bmap(fs, ino, inode, handle, block_buf, + 0, block-1, 0, blocks_alloc, &blk64); + if (retval) +- blk64 = 0; ++ blk64 = ext2fs_find_inode_goal(fs, ino, inode, block); + retval = ext2fs_alloc_block2(fs, blk64, block_buf, + &blk64); + if (retval) +@@ -254,7 +257,7 @@ + alloc++; + set_extent: + retval = ext2fs_extent_set_bmap(handle, block, +- blk64, 0); ++ blk64, set_flags); + if (retval) { + ext2fs_block_alloc_stats2(fs, blk64, -1); + return retval; +@@ -321,6 +324,13 @@ + 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) +@@ -347,7 +357,8 @@ + } + + *phys_blk = inode_bmap(inode, block); +- b = block ? inode_bmap(inode, block-1) : 0; ++ b = block ? inode_bmap(inode, block - 1) : ++ ext2fs_find_inode_goal(fs, ino, inode, block); + + if ((*phys_blk == 0) && (bmap_flags & BMAP_ALLOC)) { + retval = ext2fs_alloc_block(fs, b, block_buf, &b); +@@ -433,6 +444,8 @@ + if (retval == 0) + *phys_blk = blk32; + done: ++ if (*phys_blk && retval == 0 && (bmap_flags & BMAP_ZERO)) ++ retval = ext2fs_zero_blocks2(fs, *phys_blk, 1, NULL, NULL); + if (buf) + ext2fs_free_mem(&buf); + if (handle) +--- a/lib/ext2fs/closefs.c ++++ b/lib/ext2fs/closefs.c +@@ -255,15 +255,19 @@ + 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 @@ + + 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 @@ + &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 @@ + */ + 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 @@ + } 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 @@ + } + } + +- 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 @@ + 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); +--- a/lib/ext2fs/crc32c.c ++++ b/lib/ext2fs/crc32c.c +@@ -32,7 +32,6 @@ + #include + #include + #include +-#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) +@@ -58,400 +57,189 @@ + #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 @@ + 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 @@ + 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++; +--- a/lib/ext2fs/crc32c_defs.h ++++ b/lib/ext2fs/crc32c_defs.h +@@ -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 */ +--- a/lib/ext2fs/csum.c ++++ b/lib/ext2fs/csum.c +@@ -30,62 +30,779 @@ + #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); ++} ++ ++/* NOTE: The input to this function MUST be in LE order */ ++int ext2fs_superblock_csum_verify(ext2_filsys fs, struct ext2_super_block *sb) ++{ ++ __u32 flag, calculated; ++ ++ if (fs->flags & EXT2_FLAG_SWAP_BYTES) ++ flag = EXT4_FEATURE_RO_COMPAT_METADATA_CSUM; ++ else ++ flag = ext2fs_cpu_to_le32(EXT4_FEATURE_RO_COMPAT_METADATA_CSUM); ++ ++ if (!EXT2_HAS_RO_COMPAT_FEATURE(fs->super, flag)) ++ return 1; ++ ++ calculated = ext2fs_superblock_csum(fs, sb); ++ ++ return ext2fs_le32_to_cpu(sb->s_checksum) == calculated; ++} ++ ++/* NOTE: The input to this function MUST be in LE order */ ++errcode_t ext2fs_superblock_csum_set(ext2_filsys fs, ++ struct ext2_super_block *sb) ++{ ++ __u32 flag, crc; ++ ++ if (fs->flags & EXT2_FLAG_SWAP_BYTES) ++ flag = EXT4_FEATURE_RO_COMPAT_METADATA_CSUM; ++ else ++ flag = ext2fs_cpu_to_le32(EXT4_FEATURE_RO_COMPAT_METADATA_CSUM); ++ ++ if (!EXT2_HAS_RO_COMPAT_FEATURE(fs->super, flag)) ++ 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, +- (char *)save_desc + ext4_bg_size, +- save_size - ext4_bg_size); ++ crc32 = ext2fs_crc32c_le(crc32, ++ (unsigned 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 +812,7 @@ + + 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 +846,7 @@ + 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++) { +@@ -139,6 +854,11 @@ + __u32 old_unused = ext2fs_bg_itable_unused(fs, i); + __u32 old_flags = ext2fs_bg_flags(fs, i); + __u32 old_free_inodes_count = ext2fs_bg_free_inodes_count(fs, i); ++ __u32 old_free_blocks_count = ext2fs_bg_free_blocks_count(fs, i); ++ ++ if (old_free_blocks_count == sb->s_blocks_per_group && ++ i != fs->group_desc_count - 1) ++ ext2fs_bg_flags_set(fs, i, EXT2_BG_BLOCK_UNINIT); + + if (old_free_inodes_count == sb->s_inodes_per_group) { + ext2fs_bg_flags_set(fs, i, EXT2_BG_INODE_UNINIT); +--- a/lib/ext2fs/dblist.c ++++ b/lib/ext2fs/dblist.c +@@ -25,34 +25,6 @@ + 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). + */ +@@ -222,20 +194,25 @@ + /* + * This function iterates over the directory block list + */ +-errcode_t ext2fs_dblist_iterate2(ext2_dblist dblist, ++errcode_t ext2fs_dblist_iterate3(ext2_dblist dblist, + int (*func)(ext2_filsys fs, + struct ext2_db_entry2 *db_info, + void *priv_data), ++ unsigned long long start, ++ unsigned long long count, + void *priv_data) + { +- unsigned long long i; ++ unsigned long long i, end; + int ret; + + EXT2_CHECK_MAGIC(dblist, EXT2_ET_MAGIC_DBLIST); + ++ end = start + count; + if (!dblist->sorted) + ext2fs_dblist_sort2(dblist, 0); +- for (i=0; i < dblist->count; i++) { ++ if (end > dblist->count) ++ end = dblist->count; ++ for (i = start; i < end; i++) { + ret = (*func)(dblist->fs, &dblist->list[i], priv_data); + if (ret & DBLIST_ABORT) + return 0; +@@ -243,6 +220,16 @@ + return 0; + } + ++errcode_t ext2fs_dblist_iterate2(ext2_dblist dblist, ++ int (*func)(ext2_filsys fs, ++ struct ext2_db_entry2 *db_info, ++ void *priv_data), ++ void *priv_data) ++{ ++ return ext2fs_dblist_iterate3(dblist, func, 0, dblist->count, ++ priv_data); ++} ++ + static EXT2_QSORT_TYPE dir_block_cmp2(const void *a, const void *b) + { + const struct ext2_db_entry2 *db_a = +--- a/lib/ext2fs/dblist_dir.c ++++ b/lib/ext2fs/dblist_dir.c +@@ -65,6 +65,7 @@ + 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 @@ + 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; +--- /dev/null ++++ b/lib/ext2fs/digest_encode.c +@@ -0,0 +1,186 @@ ++/* ++ * lib/ext2fs/digest_encode.c ++ * ++ * A function to encode a digest using 64 characters that are valid in a ++ * filename per ext2fs rules. ++ * ++ * Written by Uday Savagaonkar, 2014. ++ * ++ * Copyright 2014 Google Inc. All Rights Reserved. ++ * ++ * %Begin-Header% ++ * This file may be redistributed under the terms of the GNU Library ++ * General Public License, version 2. ++ * %End-Header% ++ */ ++ ++#include "config.h" ++#if HAVE_SYS_TYPES_H ++#include ++#endif ++#include "ext2fs.h" ++ ++static const char *lookup_table = ++ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+,"; ++ ++/** ++ * ext2fs_digest_encode() - ++ * ++ * Encodes the input digest using characters from the set [a-zA-Z0-9_+]. ++ * The encoded string is roughly 4/3 times the size of the input string. ++ */ ++int ext2fs_digest_encode(const char *src, int len, char *dst) ++{ ++ int i = 0, bits = 0, ac = 0; ++ char *cp = dst; ++ ++ while (i < len) { ++ ac += (((unsigned char) src[i]) << bits); ++ bits += 8; ++ do { ++ *cp++ = lookup_table[ac & 0x3f]; ++ ac >>= 6; ++ bits -= 6; ++ } while (bits >= 6); ++ i++; ++ } ++ if (bits) ++ *cp++ = lookup_table[ac & 0x3f]; ++ return cp - dst; ++} ++ ++int ext2fs_digest_decode(const char *src, int len, char *dst) ++{ ++ int i = 0, bits = 0, ac = 0; ++ const char *p; ++ char *cp = dst; ++ ++ while (i < len) { ++ p = strchr(lookup_table, src[i]); ++ if (p == NULL || src[i] == 0) ++ return -1; ++ ac += (p - lookup_table) << bits; ++ bits += 6; ++ if (bits >= 8) { ++ *cp++ = ac & 0xff; ++ ac >>= 8; ++ bits -= 8; ++ } ++ i++; ++ } ++ if (ac) ++ return -1; ++ return cp - dst; ++} ++ ++ ++#ifdef UNITTEST ++static const struct { ++ unsigned char d[32]; ++ unsigned int len; ++ const unsigned char *ed; ++} tests[] = { ++ { { 0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, ++ 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24, ++ 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, ++ 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55 }, 32, ++ "jDLxChJ,cQhm7TPyZ+WukcirBROZbOJTkWZmbgnU4WF" ++ }, ++ { { 0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea, ++ 0x41, 0x41, 0x40, 0xde, 0x5d, 0xae, 0x22, 0x23, ++ 0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c, ++ 0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad }, 32, ++ "6inF,+YAPreQBBk3d5qIjA7AhNqlXoHn0Cx,hJPAV0K" ++ }, ++ { { 0x24, 0x8d, 0x6a, 0x61, 0xd2, 0x06, 0x38, 0xb8, ++ 0xe5, 0xc0, 0x26, 0x93, 0x0c, 0x3e, 0x60, 0x39, ++ 0xa3, 0x3c, 0xe4, 0x59, 0x64, 0xff, 0x21, 0x67, ++ 0xf6, 0xec, 0xed, 0xd4, 0x19, 0xdb, 0x06, 0xc1 }, 32, ++ "k0oahJtB4gb5AbykM4DY5MKPknFZ,HyZ2ze7Unx2GEM" ++ }, ++ { { 0x00, }, 1, ++ "AA" ++ }, ++ { { 0x01, }, 1, ++ "BA" ++ }, ++ { { 0x01, 0x02 }, 2, ++ "BIA" ++ }, ++ { { 0x01, 0x02, 0x03 }, 3, ++ "BIwA" ++ }, ++ { { 0x01, 0x02, 0x03, 0x04 }, 4, ++ "BIwAEA" ++ }, ++ { { 0x01, 0x02, 0x03, 0x04, 0xff }, 5, ++ "BIwAE8P" ++ }, ++ { { 0x01, 0x02, 0x03, 0x04, 0xff, 0xfe }, 6, ++ "BIwAE8v," ++ }, ++ { { 0x01, 0x02, 0x03, 0x04, 0xff, 0xfe, 0xfd }, 7, ++ "BIwAE8v,9D" ++ }, ++}; ++ ++int main(int argc, char **argv) ++{ ++ int i, ret, len, len2; ++ int errors = 0; ++ unsigned char tmp[1024], tmp2[1024]; ++ ++ if (argc == 3 && !strcmp(argv[1], "encode")) { ++ memset(tmp, 0, sizeof(tmp)); ++ ext2fs_digest_encode(argv[2], strlen(argv[2]), tmp); ++ puts(tmp); ++ exit(0); ++ } ++ if (argc == 3 && !strcmp(argv[1], "decode")) { ++ memset(tmp, 0, sizeof(tmp)); ++ ret = ext2fs_digest_decode(argv[2], strlen(argv[2]), tmp); ++ puts(tmp); ++ fprintf(stderr, "returned %d\n", ret); ++ exit(0); ++ } ++ for (i = 0; i < (int)(sizeof(tests) / sizeof(tests[0])); i++) { ++ memset(tmp, 0, sizeof(tmp)); ++ ret = ext2fs_digest_encode(tests[i].d, tests[i].len, tmp); ++ len = strlen(tmp); ++ printf("Test Digest %d (returned %d): ", i, ret); ++ if (ret != len) { ++ printf("FAILED returned %d, string length was %d\n", ++ ret, len); ++ errors++; ++ continue; ++ } else if (strcmp(tmp, tests[i].ed) != 0) { ++ printf("FAILED: got %s, expected %s\n", tmp, ++ tests[i].ed); ++ errors++; ++ continue; ++ } ++ ret = ext2fs_digest_decode(tmp, len, tmp2); ++ if (ret != tests[i].len) { ++ printf("FAILED decode returned %d, expected %d\n", ++ ret, tests[i].len); ++ errors++; ++ continue; ++ } ++ if (memcmp(tmp2, tests[i].d, ret) != 0) { ++ puts("FAILED: decode mismatched"); ++ errors++; ++ continue; ++ } ++ printf("OK\n"); ++ } ++ for (i = 1; i < argc; i++) { ++ memset(tmp, 0, sizeof(tmp)); ++ ret = ext2fs_digest_encode(argv[i], strlen(argv[i]), tmp); ++ len = strlen(tmp); ++ printf("Digest of '%s' is '%s' (returned %d, length %d)\n", ++ argv[i], tmp, ret, len); ++ } ++ return errors; ++} ++ ++#endif /* UNITTEST */ +--- a/lib/ext2fs/dirblock.c ++++ b/lib/ext2fs/dirblock.c +@@ -20,45 +20,36 @@ + #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_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, +--- a/lib/ext2fs/dir_iterate.c ++++ b/lib/ext2fs/dir_iterate.c +@@ -83,7 +83,7 @@ + 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) > (int) rec_len)) + return 0; + } + return (offset == final_offset); +@@ -127,6 +127,10 @@ + 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 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 - 8) { ++ while (offset < buflen - 8) { + 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) > (int) 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_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 @@ + } + + 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; + } +- +--- a/lib/ext2fs/expanddir.c ++++ b/lib/ext2fs/expanddir.c +@@ -18,12 +18,14 @@ + + #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,23 +65,17 @@ + return BLOCK_ABORT; + } + es->done = 1; +- retval = ext2fs_write_dir_block(fs, new_blk, block); +- } else { +- retval = ext2fs_get_mem(fs->blocksize, &block); +- if (retval) { +- es->err = retval; +- return BLOCK_ABORT; +- } +- memset(block, 0, fs->blocksize); +- retval = io_channel_write_blk64(fs->io, new_blk, 1, block); +- } ++ retval = ext2fs_write_dir_block4(fs, new_blk, block, 0, ++ es->dir); ++ ext2fs_free_mem(&block); ++ } else ++ retval = ext2fs_zero_blocks2(fs, new_blk, 1, NULL, NULL); + if (blockcnt >= 0) + es->goal = new_blk; + if (retval) { + es->err = retval; + return BLOCK_ABORT; + } +- ext2fs_free_mem(&block); + *blocknr = new_blk; + + if (es->done) +@@ -106,13 +102,20 @@ + if (retval) + return retval; + ++ retval = ext2fs_read_inode(fs, dir, &inode); ++ if (retval) ++ return retval; ++ + es.done = 0; + es.err = 0; +- es.goal = 0; ++ es.goal = ext2fs_find_inode_goal(fs, dir, &inode, 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; +--- a/lib/ext2fs/ext2_err.et.in ++++ b/lib/ext2fs/ext2_err.et.in +@@ -476,4 +476,58 @@ + 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" ++ ++ec EXT2_ET_JOURNAL_FLAGS_WRONG, ++ "Journal flags inconsistent" ++ ++ec EXT2_ET_UNDO_FILE_CORRUPT, ++ "Undo file corrupt" ++ ++ec EXT2_ET_UNDO_FILE_WRONG, ++ "Wrong undo file for this filesystem" ++ + end +--- a/lib/ext2fs/ext2_ext_attr.h ++++ b/lib/ext2fs/ext2_ext_attr.h +@@ -20,7 +20,9 @@ + __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 { +--- a/lib/ext2fs/ext2_fs.h ++++ b/lib/ext2fs/ext2_fs.h +@@ -192,6 +192,13 @@ + __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 */ +@@ -226,15 +233,22 @@ + #define EXT2_HASH_FLAG_INCOMPAT 0x1 + + struct ext2_dx_entry { +- __u32 hash; +- __u32 block; ++ __le32 hash; ++ __le32 block; + }; + + struct ext2_dx_countlimit { +- __u16 limit; +- __u16 count; ++ __le16 limit; ++ __le16 count; + }; + ++/* ++ * This goes at the end of each htree block. ++ */ ++struct ext2_dx_tail { ++ __le32 dt_reserved; ++ __le32 dt_checksum; /* crc32c(uuid+inum+dxblock) */ ++}; + + /* + * Macro-instructions used to manage group descriptors +@@ -293,7 +307,8 @@ + #define EXT2_DIRTY_FL 0x00000100 + #define EXT2_COMPRBLK_FL 0x00000200 /* One or more compressed clusters */ + #define EXT2_NOCOMPR_FL 0x00000400 /* Access raw compressed data */ +-#define EXT2_ECOMPR_FL 0x00000800 /* Compression error */ ++ /* nb: was previously EXT2_ECOMPR_FL */ ++#define EXT4_ENCRYPT_FL 0x00000800 /* encrypted inode */ + /* End compression flags --- maybe not all used */ + #define EXT2_BTREE_FL 0x00001000 /* btree format dir */ + #define EXT2_INDEX_FL 0x00001000 /* hash-indexed directory */ +@@ -310,6 +325,7 @@ + #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 +475,14 @@ + __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 +562,48 @@ + #define ext4_offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) + #endif + ++/* Metadata checksum algorithms */ ++#define EXT2_CRC32C_CHKSUM 1 ++ ++/* Encryption algorithms, key size and key reference len */ ++#define EXT4_ENCRYPTION_MODE_INVALID 0 ++#define EXT4_ENCRYPTION_MODE_AES_256_XTS 1 ++#define EXT4_ENCRYPTION_MODE_AES_256_GCM 2 ++#define EXT4_ENCRYPTION_MODE_AES_256_CBC 3 ++#define EXT4_ENCRYPTION_MODE_AES_256_CTS 4 ++ ++#define EXT4_AES_256_XTS_KEY_SIZE 64 ++#define EXT4_AES_256_GCM_KEY_SIZE 32 ++#define EXT4_AES_256_CBC_KEY_SIZE 32 ++#define EXT4_AES_256_CTS_KEY_SIZE 32 ++#define EXT4_MAX_KEY_SIZE 64 ++ ++#define EXT4_KEY_DESCRIPTOR_SIZE 8 ++#define EXT4_CRYPTO_BLOCK_SIZE 16 ++ ++/* Password derivation constants */ ++#define EXT4_MAX_PASSPHRASE_SIZE 1024 ++#define EXT4_MAX_SALT_SIZE 256 ++#define EXT4_PBKDF2_ITERATIONS 0xFFFF ++ ++/* ++ * Policy provided via an ioctl on the topmost directory. This ++ * structure is also in the kernel. ++ */ ++struct ext4_encryption_policy { ++ char version; ++ char contents_encryption_mode; ++ char filenames_encryption_mode; ++ char flags; ++ char master_key_descriptor[EXT4_KEY_DESCRIPTOR_SIZE]; ++} __attribute__((__packed__)); ++ ++struct ext4_encryption_key { ++ __u32 mode; ++ char raw[EXT4_MAX_KEY_SIZE]; ++ __u32 size; ++} __attribute__((__packed__)); ++ + /* + * Structure of the super block + */ +@@ -625,8 +689,9 @@ + __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; +- __u16 s_reserved_pad; /* Padding to next 32bits */ ++ __u8 s_checksum_type; /* metadata checksum algorithm */ ++ __u8 s_encryption_level; /* versioning level for encryption */ ++ __u8 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 */ + __u32 s_snapshot_id; /* sequential ID of active snapshot */ +@@ -651,7 +716,10 @@ + __u32 s_grp_quota_inum; /* inode number of group quota file */ + __u32 s_overhead_blocks; /* overhead blocks/clusters in fs */ + __u32 s_backup_bgs[2]; /* If sparse_super2 enabled */ +- __u32 s_reserved[106]; /* Padding to the end of the block */ ++ __u8 s_encrypt_algos[4]; /* Encryption algorithms in use */ ++ __u8 s_encrypt_pw_salt[16]; /* Salt used for string2key algorithm */ ++ __le32 s_lpf_ino; /* Location of the lost+found inode */ ++ __le32 s_reserved[100]; /* Padding to the end of the block */ + __u32 s_checksum; /* crc32c(superblock) */ + }; + +@@ -715,8 +783,15 @@ + #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 ++#define EXT4_FEATURE_RO_COMPAT_READONLY 0x1000 ++ + + #define EXT2_FEATURE_INCOMPAT_COMPRESSION 0x0001 + #define EXT2_FEATURE_INCOMPAT_FILETYPE 0x0002 +@@ -731,7 +806,8 @@ + #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 EXT4_FEATURE_INCOMPAT_ENCRYPT 0x10000 + + #define EXT2_FEATURE_COMPAT_SUPP 0 + #define EXT2_FEATURE_INCOMPAT_SUPP (EXT2_FEATURE_INCOMPAT_FILETYPE| \ +@@ -781,6 +857,14 @@ + * 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 +875,17 @@ + }; + + /* ++ * 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,13 +901,24 @@ + #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 + */ ++#define EXT2_DIR_ENTRY_HEADER_LEN 8 + #define EXT2_DIR_PAD 4 + #define EXT2_DIR_ROUND (EXT2_DIR_PAD - 1) +-#define EXT2_DIR_REC_LEN(name_len) (((name_len) + 8 + EXT2_DIR_ROUND) & \ ++#define EXT2_DIR_REC_LEN(name_len) (((name_len) + \ ++ EXT2_DIR_ENTRY_HEADER_LEN + \ ++ EXT2_DIR_ROUND) & \ + ~EXT2_DIR_ROUND) + + /* +@@ -838,6 +944,7 @@ + #define EXT4_MMP_SEQ_FSCK 0xE24D4D50U /* mmp_seq value when being fscked */ + #define EXT4_MMP_SEQ_MAX 0xE24D4D4FU /* maximum valid mmp_seq value */ + ++/* Not endian-annotated; it's swapped at read/write time */ + struct mmp_struct { + __u32 mmp_magic; /* Magic number for MMP */ + __u32 mmp_seq; /* Sequence no. updated periodically */ +@@ -846,7 +953,8 @@ + 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 +972,14 @@ + */ + #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 */ +--- a/lib/ext2fs/ext2fs.h ++++ b/lib/ext2fs/ext2fs.h +@@ -66,12 +66,6 @@ + #include + #endif /* EXT2_FLAT_INCLUDES */ + +-#ifdef __CHECK_ENDIAN__ +-#define __bitwise __attribute__((bitwise)) +-#else +-#define __bitwise +-#endif +- + typedef __u32 __bitwise ext2_ino_t; + typedef __u32 __bitwise blk_t; + typedef __u64 __bitwise blk64_t; +@@ -193,6 +187,7 @@ + #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 +270,21 @@ + * 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; ++ ++ io_channel journal_io; ++ char *journal_name; ++ ++ /* New block range allocation hooks */ ++ errcode_t (*new_range)(ext2_filsys fs, int flags, blk64_t goal, ++ blk64_t len, blk64_t *pblk, blk64_t *plen); ++ void (*block_alloc_stats_range)(ext2_filsys fs, blk64_t blk, blk_t num, ++ int inuse); + }; + + #if EXT2_FLAT_INCLUDES +@@ -293,9 +303,10 @@ + /* + * 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 +443,14 @@ + + #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 +465,7 @@ + #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 +@@ -518,6 +533,8 @@ + */ + #define BMAP_ALLOC 0x0001 + #define BMAP_SET 0x0002 ++#define BMAP_UNINIT 0x0004 ++#define BMAP_ZERO 0x0008 + + /* + * Returned flags from ext2fs_bmap +@@ -537,13 +554,6 @@ + #define EXT2_CHECK_MAGIC(struct, code) \ + if ((struct)->magic != (code)) return (code) + +- +-/* +- * For ext2 compression support +- */ +-#define EXT2FS_COMPRESSED_BLKADDR ((blk_t) -1) +-#define HOLE_BLKADDR(_b) ((_b) == 0 || (_b) == EXT2FS_COMPRESSED_BLKADDR) +- + /* + * Features supported by this version of the library + */ +@@ -555,34 +565,23 @@ + EXT2_FEATURE_COMPAT_EXT_ATTR|\ + EXT4_FEATURE_COMPAT_SPARSE_SUPER2) + +-/* This #ifdef is temporary until compression is fully supported */ +-#ifdef ENABLE_COMPRESSION +-#ifndef I_KNOW_THAT_COMPRESSION_IS_EXPERIMENTAL +-/* If the below warning bugs you, then have +- `CPPFLAGS=-DI_KNOW_THAT_COMPRESSION_IS_EXPERIMENTAL' in your +- 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) ++#ifdef CONFIG_MMP ++#define EXT4_LIB_INCOMPAT_MMP EXT4_FEATURE_INCOMPAT_MMP + #else ++#define EXT4_LIB_INCOMPAT_MMP (0) ++#endif ++ + #define EXT2_LIB_FEATURE_INCOMPAT_SUPP (EXT2_FEATURE_INCOMPAT_FILETYPE|\ + 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|\ ++ EXT4_FEATURE_INCOMPAT_ENCRYPT) ++ + #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,16 +589,9 @@ + 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_FEATURE_RO_COMPAT_QUOTA|\ ++ EXT4_FEATURE_RO_COMPAT_METADATA_CSUM|\ ++ EXT4_FEATURE_RO_COMPAT_READONLY) + + /* + * These features are only allowed if EXT2_FLAG_SOFTSUPP_FEATURES is passed +@@ -632,8 +624,21 @@ + #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) +@@ -667,6 +672,29 @@ + errcode_t (**old)(ext2_filsys fs, + blk64_t goal, + blk64_t *ret)); ++blk64_t ext2fs_find_inode_goal(ext2_filsys fs, ext2_ino_t ino, ++ struct ext2_inode *inode, blk64_t lblk); ++extern void ext2fs_set_new_range_callback(ext2_filsys fs, ++ errcode_t (*func)(ext2_filsys fs, int flags, blk64_t goal, ++ blk64_t len, blk64_t *pblk, blk64_t *plen), ++ errcode_t (**old)(ext2_filsys fs, int flags, blk64_t goal, ++ blk64_t len, blk64_t *pblk, blk64_t *plen)); ++extern void ext2fs_set_block_alloc_stats_range_callback(ext2_filsys fs, ++ void (*func)(ext2_filsys fs, blk64_t blk, ++ blk_t num, int inuse), ++ void (**old)(ext2_filsys fs, blk64_t blk, ++ blk_t num, int inuse)); ++#define EXT2_NEWRANGE_FIXED_GOAL (0x1) ++#define EXT2_NEWRANGE_MIN_LENGTH (0x2) ++#define EXT2_NEWRANGE_ALL_FLAGS (0x3) ++errcode_t ext2fs_new_range(ext2_filsys fs, int flags, blk64_t goal, ++ blk64_t len, ext2fs_block_bitmap map, blk64_t *pblk, ++ blk64_t *plen); ++#define EXT2_ALLOCRANGE_FIXED_GOAL (0x1) ++#define EXT2_ALLOCRANGE_ZERO_BLOCKS (0x2) ++#define EXT2_ALLOCRANGE_ALL_FLAGS (0x3) ++errcode_t ext2fs_alloc_range(ext2_filsys fs, int flags, blk64_t goal, ++ blk_t len, blk64_t *ret); + + /* alloc_sb.c */ + extern int ext2fs_reserve_super_and_bgd(ext2_filsys fs, +@@ -809,6 +837,8 @@ + 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 +866,11 @@ + 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 +982,65 @@ + 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); +@@ -976,11 +1055,17 @@ + extern errcode_t ext2fs_dblist_iterate(ext2_dblist dblist, + int (*func)(ext2_filsys fs, struct ext2_db_entry *db_info, + void *priv_data), +- void *priv_data); ++ void *priv_data); + extern errcode_t ext2fs_dblist_iterate2(ext2_dblist dblist, + int (*func)(ext2_filsys fs, struct ext2_db_entry2 *db_info, + void *priv_data), +- void *priv_data); ++ void *priv_data); ++extern errcode_t ext2fs_dblist_iterate3(ext2_dblist dblist, ++ int (*func)(ext2_filsys fs, struct ext2_db_entry2 *db_info, ++ void *priv_data), ++ unsigned long long start, ++ unsigned long long count, ++ void *priv_data); + extern errcode_t ext2fs_set_dir_block(ext2_dblist dblist, ext2_ino_t ino, + blk_t blk, int blockcnt); + extern errcode_t ext2fs_set_dir_block2(ext2_dblist dblist, ext2_ino_t ino, +@@ -1009,6 +1094,13 @@ + void *priv_data), + void *priv_data); + ++#if 0 ++/* digest_encode.c */ ++#define EXT2FS_DIGEST_SIZE EXT2FS_SHA256_LENGTH ++extern int ext2fs_digest_encode(const char *src, int len, char *dst); ++extern int ext2fs_digest_decode(const char *src, int len, char *dst); ++#endif ++ + /* dirblock.c */ + extern errcode_t ext2fs_read_dir_block(ext2_filsys fs, blk_t block, + void *buf); +@@ -1016,12 +1108,16 @@ + 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 +1168,46 @@ + 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); +@@ -1109,6 +1235,17 @@ + extern errcode_t ext2fs_extent_goto2(ext2_extent_handle_t handle, + int leaf_level, blk64_t blk); + extern errcode_t ext2fs_extent_fix_parents(ext2_extent_handle_t handle); ++size_t ext2fs_max_extent_depth(ext2_extent_handle_t handle); ++ ++/* fallocate.c */ ++#define EXT2_FALLOCATE_ZERO_BLOCKS (0x1) ++#define EXT2_FALLOCATE_FORCE_INIT (0x2) ++#define EXT2_FALLOCATE_FORCE_UNINIT (0x4) ++#define EXT2_FALLOCATE_INIT_BEYOND_EOF (0x8) ++#define EXT2_FALLOCATE_ALL_FLAGS (0xF) ++errcode_t ext2fs_fallocate(ext2_filsys fs, int flags, ext2_ino_t ino, ++ struct ext2_inode *inode, blk64_t goal, ++ blk64_t start, blk64_t len); + + /* fileio.c */ + extern errcode_t ext2fs_file_open2(ext2_filsys fs, ext2_ino_t ino, +@@ -1190,10 +1327,6 @@ + __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 +1355,9 @@ + 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,12 +1419,27 @@ + 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, + struct ext2_inode *inode, + int bufsize); ++#define EXT2_INODE_SCAN_DEFAULT_BUFFER_BLOCKS 8 + extern errcode_t ext2fs_open_inode_scan(ext2_filsys fs, int buffer_blocks, + ext2_inode_scan *ret_scan); + extern void ext2fs_close_inode_scan(ext2_inode_scan scan); +@@ -1359,6 +1510,8 @@ + /* 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, +@@ -1414,7 +1567,7 @@ + + /* symlink.c */ + errcode_t ext2fs_symlink(ext2_filsys fs, ext2_ino_t parent, ext2_ino_t ino, +- const char *name, char *target); ++ const char *name, const char *target); + + /* mmp.c */ + errcode_t ext2fs_mmp_read(ext2_filsys fs, blk64_t mmp_blk, void *buf); +@@ -1423,6 +1576,7 @@ + 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); + +@@ -1446,7 +1600,25 @@ + /* res_gdt.c */ + extern errcode_t ext2fs_create_resize_inode(ext2_filsys fs); + ++/*sha256.c */ ++#define EXT2FS_SHA256_LENGTH 32 ++#if 0 ++extern void ext2fs_sha256(const unsigned char *in, unsigned long in_size, ++ unsigned char out[EXT2FS_SHA256_LENGTH]); ++#endif ++ ++/* sha512.c */ ++#define EXT2FS_SHA512_LENGTH 64 ++extern void ext2fs_sha512(const unsigned char *in, unsigned long in_size, ++ unsigned char out[EXT2FS_SHA512_LENGTH]); ++ + /* 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 +1658,7 @@ + + /* 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, +@@ -1513,6 +1686,11 @@ + struct ext2_inode *inode); + extern unsigned int ext2fs_div_ceil(unsigned int a, unsigned int b); + extern __u64 ext2fs_div64_ceil(__u64 a, __u64 b); ++extern int ext2fs_dirent_name_len(const struct ext2_dir_entry *entry); ++extern void ext2fs_dirent_set_name_len(struct ext2_dir_entry *entry, int len); ++extern int ext2fs_dirent_file_type(const struct ext2_dir_entry *entry); ++extern void ext2fs_dirent_set_file_type(struct ext2_dir_entry *entry, int type); ++ + #endif + + /* +@@ -1536,6 +1714,16 @@ + #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 + /* +@@ -1566,7 +1754,7 @@ + + _INLINE_ errcode_t ext2fs_get_array(unsigned long count, unsigned long size, void *ptr) + { +- if (count && (-1UL)/countname_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 + +--- a/lib/ext2fs/ext2fsP.h ++++ b/lib/ext2fs/ext2fsP.h +@@ -50,6 +50,7 @@ + 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 @@ + 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 @@ + 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 @@ + 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); +@@ -145,3 +169,8 @@ + extern int ext2fs_file_block_offset_too_big(ext2_filsys fs, + struct ext2_inode *inode, + blk64_t offset); ++ ++/* atexit support */ ++typedef void (*ext2_exit_fn)(void *); ++errcode_t ext2fs_add_exit_fn(ext2_exit_fn fn, void *data); ++errcode_t ext2fs_remove_exit_fn(ext2_exit_fn fn, void *data); +--- a/lib/ext2fs/ext2_io.h ++++ b/lib/ext2fs/ext2_io.h +@@ -90,7 +90,12 @@ + int count, const void *data); + errcode_t (*discard)(io_channel channel, unsigned long long block, + unsigned long long count); +- long reserved[16]; ++ errcode_t (*cache_readahead)(io_channel channel, ++ unsigned long long block, ++ unsigned long long count); ++ errcode_t (*zeroout)(io_channel channel, unsigned long long block, ++ unsigned long long count); ++ long reserved[14]; + }; + + #define IO_FLAG_RW 0x0001 +@@ -122,8 +127,14 @@ + extern errcode_t io_channel_discard(io_channel channel, + unsigned long long block, + unsigned long long count); ++extern errcode_t io_channel_zeroout(io_channel channel, ++ unsigned long long block, ++ unsigned long long count); + extern errcode_t io_channel_alloc_buf(io_channel channel, + int count, void *ptr); ++extern errcode_t io_channel_cache_readahead(io_channel io, ++ unsigned long long block, ++ unsigned long long count); + + /* unix_io.c */ + extern io_manager unix_io_manager; +--- a/lib/ext2fs/ext2_types.h.in ++++ b/lib/ext2fs/ext2_types.h.in +@@ -166,4 +166,25 @@ + + #endif /* _*_TYPES_H */ + ++/* endian checking stuff */ ++#ifndef EXT2_ENDIAN_H_ ++#define EXT2_ENDIAN_H_ ++ ++#ifdef __CHECKER__ ++#define __bitwise __attribute__((bitwise)) ++#define __force __attribute__((force)) ++#else ++#define __bitwise ++#define __force ++#endif ++ ++typedef __u16 __bitwise __le16; ++typedef __u32 __bitwise __le32; ++typedef __u64 __bitwise __le64; ++typedef __u16 __bitwise __be16; ++typedef __u32 __bitwise __be32; ++typedef __u64 __bitwise __be64; ++ ++#endif /* EXT2_ENDIAN_H_ */ ++ + @PUBLIC_CONFIG_HEADER@ +--- a/lib/ext2fs/ext3_extents.h ++++ b/lib/ext2fs/ext3_extents.h +@@ -19,14 +19,25 @@ + */ + + /* ++ * 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 { ++ __le32 et_checksum; /* crc32c(uuid+inum+extent_block) */ ++}; ++ ++/* + * this is extent on-disk structure + * it's used at the bottom of the tree + */ + struct ext3_extent { +- __u32 ee_block; /* first logical block extent covers */ +- __u16 ee_len; /* number of blocks covered by extent */ +- __u16 ee_start_hi; /* high 16 bits of physical block */ +- __u32 ee_start; /* low 32 bigs of physical block */ ++ __le32 ee_block; /* first logical block extent covers */ ++ __le16 ee_len; /* number of blocks covered by extent */ ++ __le16 ee_start_hi; /* high 16 bits of physical block */ ++ __le32 ee_start; /* low 32 bigs of physical block */ + }; + + /* +@@ -34,22 +45,22 @@ + * it's used at all the levels, but the bottom + */ + struct ext3_extent_idx { +- __u32 ei_block; /* index covers logical blocks from 'block' */ +- __u32 ei_leaf; /* pointer to the physical block of the next * ++ __le32 ei_block; /* index covers logical blocks from 'block' */ ++ __le32 ei_leaf; /* pointer to the physical block of the next * + * level. leaf or next index could bet here */ +- __u16 ei_leaf_hi; /* high 16 bits of physical block */ +- __u16 ei_unused; ++ __le16 ei_leaf_hi; /* high 16 bits of physical block */ ++ __le16 ei_unused; + }; + + /* + * each block (leaves and indexes), even inode-stored has header + */ + struct ext3_extent_header { +- __u16 eh_magic; /* probably will support different formats */ +- __u16 eh_entries; /* number of valid entries */ +- __u16 eh_max; /* capacity of store in entries */ +- __u16 eh_depth; /* has tree real underlaying blocks? */ +- __u32 eh_generation; /* generation of the tree */ ++ __le16 eh_magic; /* probably will support different formats */ ++ __le16 eh_entries; /* number of valid entries */ ++ __le16 eh_max; /* capacity of store in entries */ ++ __le16 eh_depth; /* has tree real underlaying blocks? */ ++ __le32 eh_generation; /* generation of the tree */ + }; + + #define EXT3_EXT_MAGIC 0xf30a +@@ -87,6 +98,8 @@ + */ + #define EXT_INIT_MAX_LEN (1UL << 15) + #define EXT_UNINIT_MAX_LEN (EXT_INIT_MAX_LEN - 1) ++#define EXT_MAX_EXTENT_LBLK (((__u64) 1 << 32) - 1) ++#define EXT_MAX_EXTENT_PBLK (((__u64) 1 << 48) - 1) + + #define EXT_FIRST_EXTENT(__hdr__) \ + ((struct ext3_extent *) (((char *) (__hdr__)) + \ +--- a/lib/ext2fs/ext_attr.c ++++ b/lib/ext2fs/ext_attr.c +@@ -58,20 +58,47 @@ + 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 @@ + 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 @@ + /* + * 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 @@ + 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 @@ + 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,926 @@ + 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}, ++}; ++ ++/* Push empty attributes to the end and inlinedata to the front. */ ++static int attr_compare(const void *a, const void *b) ++{ ++ const struct ext2_xattr *xa = a, *xb = b; ++ ++ if (xa->name == NULL) ++ return +1; ++ else if (xb->name == NULL) ++ return -1; ++ else if (!strcmp(xa->name, "system.data")) ++ return -1; ++ else if (!strcmp(xb->name, "system.data")) ++ return +1; ++ return 0; ++} ++ ++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(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; ++ blk64_t blk; ++ 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; ++ 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 */ ++ goal = ext2fs_find_inode_goal(fs, ino, (struct ext2_inode *)inode, 0); ++ 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, ++ int write_hash) ++{ ++ struct ext2_xattr *x = *pos; ++ struct ext2_ext_attr_entry *e = entries_start; ++ char *end = (char *) 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 ((char *)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 - (char *)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((char *)e + sizeof(*e), shortname, e->e_name_len); ++ memcpy(end, x->value, e->e_value_size); ++ ++ if (write_hash) ++ e->e_hash = ext2fs_ext_attr_hash_entry(e, end); ++ else ++ e->e_hash = 0; ++ ++ 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; ++ char *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; ++ ++ /* If extra_isize isn't set, we need to set it now */ ++ if (inode->i_extra_isize == 0 && ++ EXT2_INODE_SIZE(handle->fs->super) > EXT2_GOOD_OLD_INODE_SIZE) { ++ char *p = (char *)inode; ++ size_t extra = handle->fs->super->s_want_extra_isize; ++ ++ if (extra == 0) ++ extra = sizeof(__u32); ++ memset(p + EXT2_GOOD_OLD_INODE_SIZE, 0, extra); ++ inode->i_extra_isize = extra; ++ } ++ ++ /* ++ * Force the inlinedata attr to the front and the empty entries ++ * to the end. ++ */ ++ x = handle->attrs; ++ qsort(x, handle->length, sizeof(struct ext2_xattr), attr_compare); ++ ++ /* Does the inode have space for EA? */ ++ if (inode->i_extra_isize < sizeof(inode->i_extra_isize) || ++ 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, 0); ++ if (err) ++ goto out; ++ ++write_ea_block: ++ /* Are we done? */ ++ if (x >= handle->attrs + handle->count) ++ goto skip_ea_block; ++ ++ /* Write the EA block */ ++ err = ext2fs_get_memzero(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, ++ start - block_buf, 1); ++ 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 = (struct ext2_ext_attr_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, ++ char *value_start, ++ size_t *nr_read) ++{ ++ struct ext2_xattr *x; ++ struct ext2_ext_attr_entry *entry, *end; ++ const char *prefix; ++ unsigned int remain, prefix_len; ++ errcode_t err; ++ unsigned int values_size = storage_size + ++ ((char *)entries - value_start); ++ ++ x = handle->attrs; ++ while (x->name) ++ x++; ++ ++ /* find the end */ ++ end = entries; ++ remain = storage_size; ++ while (remain >= sizeof(struct ext2_ext_attr_entry) && ++ !EXT2_EXT_IS_LAST_ENTRY(end)) { ++ ++ /* header eats this space */ ++ remain -= sizeof(struct ext2_ext_attr_entry); ++ ++ /* is attribute name valid? */ ++ if (EXT2_EXT_ATTR_SIZE(end->e_name_len) > remain) ++ return EXT2_ET_EA_BAD_NAME_LEN; ++ ++ /* attribute len eats this space */ ++ remain -= EXT2_EXT_ATTR_SIZE(end->e_name_len); ++ end = EXT2_EXT_ATTR_NEXT(end); ++ } ++ ++ 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); ++ ++ /* 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; ++ ++ if (entry->e_value_size > 0 && ++ value_start + entry->e_value_offs < ++ (char *)end + sizeof(__u32)) ++ 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, ++ (char *)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_inode_large *inode; ++ struct ext2_ext_attr_header *header; ++ __u32 ea_inode_magic; ++ unsigned int storage_size; ++ char *start, *block_buf = NULL; ++ blk64_t blk; ++ size_t 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 space for EA? */ ++ if (inode->i_extra_isize < sizeof(inode->i_extra_isize) || ++ 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, ++ (struct ext2_ext_attr_entry *) 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, ++ (struct ext2_ext_attr_entry *) 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; ++ 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; ++ char *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_entry *entry; ++ struct ext2_inode_large *inode; ++ __u32 ea_inode_magic; ++ unsigned int minoff; ++ char *start; ++ size_t 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 */ ++ start= ((char *) inode) + EXT2_GOOD_OLD_INODE_SIZE + ++ inode->i_extra_isize + sizeof(__u32); ++ entry = (struct ext2_ext_attr_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; ++ ++ 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; + } +--- a/lib/ext2fs/extent.c ++++ b/lib/ext2fs/extent.c +@@ -60,6 +60,7 @@ + int type; + int level; + int max_depth; ++ int max_paths; + struct extent_path *path; + }; + +@@ -198,7 +199,7 @@ + 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 @@ + 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 @@ + 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 @@ + 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 @@ + (path->left != 0))) + goto retry; + ++ if (failed_csum) ++ return EXT2_ET_EXTENT_CSUM_INVALID; ++ + return 0; + } + +@@ -571,6 +580,7 @@ + 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 @@ + 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 @@ + * 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) + { +@@ -909,6 +934,25 @@ + orig_height = info.max_depth - info.curr_level; + orig_lblk = extent.e_lblk; + ++ /* Try to put the index block before the first extent */ ++ path = handle->path + handle->level; ++ eh = (struct ext3_extent_header *) path->buf; ++ if (handle->level == handle->max_depth) { ++ struct ext3_extent *ex; ++ ++ ex = EXT_FIRST_EXTENT(eh); ++ goal_blk = ext2fs_le32_to_cpu(ex->ee_start) + ++ ((__u64) ext2fs_le16_to_cpu(ex->ee_start_hi) << 32); ++ } else { ++ struct ext3_extent_idx *ix; ++ ++ ix = EXT_FIRST_INDEX(eh); ++ goal_blk = ext2fs_le32_to_cpu(ix->ei_leaf) + ++ ((__u64) ext2fs_le16_to_cpu(ix->ei_leaf_hi) << 32); ++ } ++ goal_blk -= EXT2FS_CLUSTER_RATIO(handle->fs); ++ goal_blk &= ~EXT2FS_CLUSTER_MASK(handle->fs); ++ + /* Is there room in the parent for a new entry? */ + if (handle->level && + (handle->path[handle->level - 1].entries >= +@@ -922,7 +966,6 @@ + retval = ext2fs_extent_get(handle, EXT2_EXTENT_UP, &extent); + if (retval) + goto done; +- goal_blk = extent.e_pblk; + + retval = extent_node_split(handle, expand_allowed); + if (retval) +@@ -954,13 +997,11 @@ + 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; +@@ -989,14 +1030,9 @@ + goto done; + } + +- if (!goal_blk) { +- dgrp_t group = ext2fs_group_of_ino(handle->fs, handle->ino); +- __u8 log_flex = handle->fs->super->s_log_groups_per_flex; +- +- if (log_flex) +- group = group & ~((1 << (log_flex)) - 1); +- goal_blk = ext2fs_group_first_block2(handle->fs, group); +- } ++ if (!goal_blk) ++ goal_blk = ext2fs_find_inode_goal(handle->fs, handle->ino, ++ handle->inode, 0); + retval = ext2fs_alloc_block2(handle->fs, goal_blk, block_buf, + &new_node_pblk); + if (retval) +@@ -1024,6 +1060,11 @@ + + 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 +1077,14 @@ + /* 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 +1466,25 @@ + &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 +1517,9 @@ + 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); +@@ -1483,18 +1536,18 @@ + if (retval) + goto done; + } else { +- __u32 orig_length; +- blk64_t orig_lblk; +- struct ext2fs_extent orig_extent; ++ __u32 save_length; ++ blk64_t save_lblk; ++ struct ext2fs_extent save_extent; + errcode_t r2; + + #ifdef DEBUG + printf("(re/un)mapping in middle of extent\n"); + #endif + /* need to split this extent; later */ +- orig_lblk = extent.e_lblk; +- orig_length = extent.e_len; +- orig_extent = extent; ++ save_lblk = extent.e_lblk; ++ save_length = extent.e_len; ++ save_extent = extent; + + /* shorten pre-split extent */ + extent.e_len = (logical - extent.e_lblk); +@@ -1507,17 +1560,17 @@ + retval = ext2fs_extent_insert(handle, + EXT2_EXTENT_INSERT_AFTER, &newextent); + if (retval) { +- r2 = ext2fs_extent_goto(handle, orig_lblk); ++ r2 = ext2fs_extent_goto(handle, save_lblk); + if (r2 == 0) +- ext2fs_extent_replace(handle, 0, +- &orig_extent); ++ (void)ext2fs_extent_replace(handle, 0, ++ &save_extent); + goto done; + } + } + /* add post-split extent */ + extent.e_pblk += extent.e_len + 1; + extent.e_lblk += extent.e_len + 1; +- extent.e_len = orig_length - extent.e_len - 1; ++ extent.e_len = save_length - extent.e_len - 1; + retval = ext2fs_extent_insert(handle, + EXT2_EXTENT_INSERT_AFTER, &extent); + if (retval) { +@@ -1525,11 +1578,12 @@ + 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); ++ r2 = ext2fs_extent_goto(handle, save_lblk); + if (r2 == 0) +- ext2fs_extent_replace(handle, 0, &orig_extent); ++ (void)ext2fs_extent_replace(handle, 0, ++ &save_extent); + goto done; + } + } +@@ -1610,8 +1664,10 @@ + } else { + eh = (struct ext3_extent_header *) path->buf; + eh->eh_entries = ext2fs_cpu_to_le16(path->entries); +- if ((path->entries == 0) && (handle->level == 0)) +- eh->eh_depth = handle->max_depth = 0; ++ if ((path->entries == 0) && (handle->level == 0)) { ++ eh->eh_depth = 0; ++ handle->max_depth = 0; ++ } + retval = update_path(handle); + } + return retval; +@@ -1641,14 +1697,46 @@ + + info->curr_level = handle->level; + info->max_depth = handle->max_depth; +- info->max_lblk = ((__u64) 1 << 32) - 1; +- info->max_pblk = ((__u64) 1 << 48) - 1; +- info->max_len = (1UL << 15); +- info->max_uninit_len = (1UL << 15) - 1; ++ info->max_lblk = EXT_MAX_EXTENT_LBLK; ++ info->max_pblk = EXT_MAX_EXTENT_PBLK; ++ info->max_len = EXT_INIT_MAX_LEN; ++ info->max_uninit_len = EXT_UNINIT_MAX_LEN; + + return 0; + } + ++static int ul_log2(unsigned long arg) ++{ ++ int l = 0; ++ ++ arg >>= 1; ++ while (arg) { ++ l++; ++ arg >>= 1; ++ } ++ return l; ++} ++ ++size_t ext2fs_max_extent_depth(ext2_extent_handle_t handle) ++{ ++ size_t iblock_sz = sizeof(((struct ext2_inode *)NULL)->i_block); ++ size_t iblock_extents = (iblock_sz - sizeof(struct ext3_extent_header)) / ++ sizeof(struct ext3_extent); ++ size_t extents_per_block = (handle->fs->blocksize - ++ sizeof(struct ext3_extent_header)) / ++ sizeof(struct ext3_extent); ++ static unsigned int last_blocksize = 0; ++ static size_t last_result = 0; ++ ++ if (last_blocksize && last_blocksize == handle->fs->blocksize) ++ return last_result; ++ ++ last_result = 1 + ((ul_log2(EXT_MAX_EXTENT_LBLK) - ul_log2(iblock_extents)) / ++ ul_log2(extents_per_block)); ++ last_blocksize = handle->fs->blocksize; ++ return last_result; ++} ++ + #ifdef DEBUG + /* + * Override debugfs's prompt +--- /dev/null ++++ b/lib/ext2fs/fallocate.c +@@ -0,0 +1,858 @@ ++/* ++ * fallocate.c -- Allocate large chunks of file. ++ * ++ * 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% ++ */ ++ ++#include "config.h" ++ ++#if HAVE_SYS_TYPES_H ++#include ++#endif ++ ++#include "ext2_fs.h" ++#include "ext2fs.h" ++#define min(a, b) ((a) < (b) ? (a) : (b)) ++ ++#undef DEBUG ++ ++#ifdef DEBUG ++# define dbg_printf(f, a...) do {printf(f, ## a); fflush(stdout); } while (0) ++#else ++# define dbg_printf(f, a...) ++#endif ++ ++/* ++ * Extent-based fallocate code. ++ * ++ * Find runs of unmapped logical blocks by starting at start and walking the ++ * extents until we reach the end of the range we want. ++ * ++ * For each run of unmapped blocks, try to find the extents on either side of ++ * the range. If there's a left extent that can grow by at least a cluster and ++ * there are lblocks between start and the next lcluster after start, see if ++ * there's an implied cluster allocation; if so, zero the blocks (if the left ++ * extent is initialized) and adjust the extent. Ditto for the blocks between ++ * the end of the last full lcluster and end, if there's a right extent. ++ * ++ * Try to attach as much as we can to the left extent, then try to attach as ++ * much as we can to the right extent. For the remainder, try to allocate the ++ * whole range; map in whatever we get; and repeat until we're done. ++ * ++ * To attach to a left extent, figure out the maximum amount we can add to the ++ * extent and try to allocate that much, and append if successful. To attach ++ * to a right extent, figure out the max we can add to the extent, try to ++ * allocate that much, and prepend if successful. ++ * ++ * We need an alloc_range function that tells us how much we can allocate given ++ * a maximum length and one of a suggested start, a fixed start, or a fixed end ++ * point. ++ * ++ * Every time we modify the extent tree we also need to update the block stats. ++ * ++ * At the end, update i_blocks and i_size appropriately. ++ */ ++ ++static void dbg_print_extent(const char *desc EXT2FS_ATTR((unused)), ++ const struct ext2fs_extent *extent EXT2FS_ATTR((unused))) ++{ ++#ifdef DEBUG ++ if (desc) ++ printf("%s: ", desc); ++ printf("extent: lblk %llu--%llu, len %u, pblk %llu, flags: ", ++ extent->e_lblk, extent->e_lblk + extent->e_len - 1, ++ extent->e_len, extent->e_pblk); ++ if (extent->e_flags & EXT2_EXTENT_FLAGS_LEAF) ++ fputs("LEAF ", stdout); ++ if (extent->e_flags & EXT2_EXTENT_FLAGS_UNINIT) ++ fputs("UNINIT ", stdout); ++ if (extent->e_flags & EXT2_EXTENT_FLAGS_SECOND_VISIT) ++ fputs("2ND_VISIT ", stdout); ++ if (!extent->e_flags) ++ fputs("(none)", stdout); ++ fputc('\n', stdout); ++ fflush(stdout); ++#endif ++} ++ ++static errcode_t claim_range(ext2_filsys fs, struct ext2_inode *inode, ++ blk64_t blk, blk64_t len) ++{ ++ blk64_t clusters; ++ ++ clusters = (len + EXT2FS_CLUSTER_RATIO(fs) - 1) / ++ EXT2FS_CLUSTER_RATIO(fs); ++ ext2fs_block_alloc_stats_range(fs, blk, ++ clusters * EXT2FS_CLUSTER_RATIO(fs), +1); ++ return ext2fs_iblk_add_blocks(fs, inode, clusters); ++} ++ ++static errcode_t ext_falloc_helper(ext2_filsys fs, ++ int flags, ++ ext2_ino_t ino, ++ struct ext2_inode *inode, ++ ext2_extent_handle_t handle, ++ struct ext2fs_extent *left_ext, ++ struct ext2fs_extent *right_ext, ++ blk64_t range_start, blk64_t range_len, ++ blk64_t alloc_goal) ++{ ++ struct ext2fs_extent newex, ex; ++ int op; ++ blk64_t fillable, pblk, plen, x, y; ++ blk64_t eof_blk = 0, cluster_fill = 0; ++ errcode_t err; ++ blk_t max_extent_len, max_uninit_len, max_init_len; ++ ++#ifdef DEBUG ++ printf("%s: ", __func__); ++ if (left_ext) ++ printf("left_ext=%llu--%llu, ", left_ext->e_lblk, ++ left_ext->e_lblk + left_ext->e_len - 1); ++ if (right_ext) ++ printf("right_ext=%llu--%llu, ", right_ext->e_lblk, ++ right_ext->e_lblk + right_ext->e_len - 1); ++ printf("start=%llu len=%llu, goal=%llu\n", range_start, range_len, ++ alloc_goal); ++ fflush(stdout); ++#endif ++ /* Can't create initialized extents past EOF? */ ++ if (!(flags & EXT2_FALLOCATE_INIT_BEYOND_EOF)) ++ eof_blk = EXT2_I_SIZE(inode) / fs->blocksize; ++ ++ /* The allocation goal must be as far into a cluster as range_start. */ ++ alloc_goal = (alloc_goal & ~EXT2FS_CLUSTER_MASK(fs)) | ++ (range_start & EXT2FS_CLUSTER_MASK(fs)); ++ ++ max_uninit_len = EXT_UNINIT_MAX_LEN & ~EXT2FS_CLUSTER_MASK(fs); ++ max_init_len = EXT_INIT_MAX_LEN & ~EXT2FS_CLUSTER_MASK(fs); ++ ++ /* We must lengthen the left extent to the end of the cluster */ ++ if (left_ext && EXT2FS_CLUSTER_RATIO(fs) > 1) { ++ /* How many more blocks can be attached to left_ext? */ ++ if (left_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT) ++ fillable = max_uninit_len - left_ext->e_len; ++ else ++ fillable = max_init_len - left_ext->e_len; ++ ++ if (fillable > range_len) ++ fillable = range_len; ++ if (fillable == 0) ++ goto expand_right; ++ ++ /* ++ * If range_start isn't on a cluster boundary, try an ++ * implied cluster allocation for left_ext. ++ */ ++ cluster_fill = EXT2FS_CLUSTER_RATIO(fs) - ++ (range_start & EXT2FS_CLUSTER_MASK(fs)); ++ cluster_fill &= EXT2FS_CLUSTER_MASK(fs); ++ if (cluster_fill == 0) ++ goto expand_right; ++ ++ if (cluster_fill > fillable) ++ cluster_fill = fillable; ++ ++ /* Don't expand an initialized left_ext beyond EOF */ ++ if (!(flags & EXT2_FALLOCATE_INIT_BEYOND_EOF)) { ++ x = left_ext->e_lblk + left_ext->e_len - 1; ++ dbg_printf("%s: lend=%llu newlend=%llu eofblk=%llu\n", ++ __func__, x, x + cluster_fill, eof_blk); ++ if (eof_blk >= x && eof_blk <= x + cluster_fill) ++ cluster_fill = eof_blk - x; ++ if (cluster_fill == 0) ++ goto expand_right; ++ } ++ ++ err = ext2fs_extent_goto(handle, left_ext->e_lblk); ++ if (err) ++ goto expand_right; ++ left_ext->e_len += cluster_fill; ++ range_start += cluster_fill; ++ range_len -= cluster_fill; ++ alloc_goal += cluster_fill; ++ ++ dbg_print_extent("ext_falloc clus left+", left_ext); ++ err = ext2fs_extent_replace(handle, 0, left_ext); ++ if (err) ++ goto out; ++ err = ext2fs_extent_fix_parents(handle); ++ if (err) ++ goto out; ++ ++ /* Zero blocks */ ++ if (!(left_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT)) { ++ err = ext2fs_zero_blocks2(fs, left_ext->e_pblk + ++ left_ext->e_len - ++ cluster_fill, cluster_fill, ++ NULL, NULL); ++ if (err) ++ goto out; ++ } ++ } ++ ++expand_right: ++ /* We must lengthen the right extent to the beginning of the cluster */ ++ if (right_ext && EXT2FS_CLUSTER_RATIO(fs) > 1) { ++ /* How much can we attach to right_ext? */ ++ if (right_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT) ++ fillable = max_uninit_len - right_ext->e_len; ++ else ++ fillable = max_init_len - right_ext->e_len; ++ ++ if (fillable > range_len) ++ fillable = range_len; ++ if (fillable == 0) ++ goto try_merge; ++ ++ /* ++ * If range_end isn't on a cluster boundary, try an implied ++ * cluster allocation for right_ext. ++ */ ++ cluster_fill = right_ext->e_lblk & EXT2FS_CLUSTER_MASK(fs); ++ if (cluster_fill == 0) ++ goto try_merge; ++ ++ err = ext2fs_extent_goto(handle, right_ext->e_lblk); ++ if (err) ++ goto out; ++ ++ if (cluster_fill > fillable) ++ cluster_fill = fillable; ++ right_ext->e_lblk -= cluster_fill; ++ right_ext->e_pblk -= cluster_fill; ++ right_ext->e_len += cluster_fill; ++ range_len -= cluster_fill; ++ ++ dbg_print_extent("ext_falloc clus right+", right_ext); ++ err = ext2fs_extent_replace(handle, 0, right_ext); ++ if (err) ++ goto out; ++ err = ext2fs_extent_fix_parents(handle); ++ if (err) ++ goto out; ++ ++ /* Zero blocks if necessary */ ++ if (!(right_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT)) { ++ err = ext2fs_zero_blocks2(fs, right_ext->e_pblk, ++ cluster_fill, NULL, NULL); ++ if (err) ++ goto out; ++ } ++ } ++ ++try_merge: ++ /* Merge both extents together, perhaps? */ ++ if (left_ext && right_ext) { ++ /* Are the two extents mergeable? */ ++ if ((left_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT) != ++ (right_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT)) ++ goto try_left; ++ ++ /* User requires init/uninit but extent is uninit/init. */ ++ if (((flags & EXT2_FALLOCATE_FORCE_INIT) && ++ (left_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT)) || ++ ((flags & EXT2_FALLOCATE_FORCE_UNINIT) && ++ !(left_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT))) ++ goto try_left; ++ ++ /* ++ * Skip initialized extent unless user wants to zero blocks ++ * or requires init extent. ++ */ ++ if (!(left_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT) && ++ (!(flags & EXT2_FALLOCATE_ZERO_BLOCKS) || ++ !(flags & EXT2_FALLOCATE_FORCE_INIT))) ++ goto try_left; ++ ++ /* Will it even fit? */ ++ x = left_ext->e_len + range_len + right_ext->e_len; ++ if (x > (left_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT ? ++ max_uninit_len : max_init_len)) ++ goto try_left; ++ ++ err = ext2fs_extent_goto(handle, left_ext->e_lblk); ++ if (err) ++ goto try_left; ++ ++ /* Allocate blocks */ ++ y = left_ext->e_pblk + left_ext->e_len; ++ err = ext2fs_new_range(fs, EXT2_NEWRANGE_FIXED_GOAL | ++ EXT2_NEWRANGE_MIN_LENGTH, y, ++ right_ext->e_pblk - y + 1, NULL, ++ &pblk, &plen); ++ if (err) ++ goto try_left; ++ if (pblk + plen != right_ext->e_pblk) ++ goto try_left; ++ err = claim_range(fs, inode, pblk, plen); ++ if (err) ++ goto out; ++ ++ /* Modify extents */ ++ left_ext->e_len = x; ++ dbg_print_extent("ext_falloc merge", left_ext); ++ err = ext2fs_extent_replace(handle, 0, left_ext); ++ if (err) ++ goto out; ++ err = ext2fs_extent_fix_parents(handle); ++ if (err) ++ goto out; ++ err = ext2fs_extent_get(handle, EXT2_EXTENT_NEXT_LEAF, &newex); ++ if (err) ++ goto out; ++ err = ext2fs_extent_delete(handle, 0); ++ if (err) ++ goto out; ++ err = ext2fs_extent_fix_parents(handle); ++ if (err) ++ goto out; ++ *right_ext = *left_ext; ++ ++ /* Zero blocks */ ++ if (!(left_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT) && ++ (flags & EXT2_FALLOCATE_ZERO_BLOCKS)) { ++ err = ext2fs_zero_blocks2(fs, range_start, range_len, ++ NULL, NULL); ++ if (err) ++ goto out; ++ } ++ ++ return 0; ++ } ++ ++try_left: ++ /* Extend the left extent */ ++ if (left_ext) { ++ /* How many more blocks can be attached to left_ext? */ ++ if (left_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT) ++ fillable = max_uninit_len - left_ext->e_len; ++ else if (flags & EXT2_FALLOCATE_ZERO_BLOCKS) ++ fillable = max_init_len - left_ext->e_len; ++ else ++ fillable = 0; ++ ++ /* User requires init/uninit but extent is uninit/init. */ ++ if (((flags & EXT2_FALLOCATE_FORCE_INIT) && ++ (left_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT)) || ++ ((flags & EXT2_FALLOCATE_FORCE_UNINIT) && ++ !(left_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT))) ++ goto try_right; ++ ++ if (fillable > range_len) ++ fillable = range_len; ++ ++ /* Don't expand an initialized left_ext beyond EOF */ ++ x = left_ext->e_lblk + left_ext->e_len - 1; ++ if (!(flags & EXT2_FALLOCATE_INIT_BEYOND_EOF)) { ++ dbg_printf("%s: lend=%llu newlend=%llu eofblk=%llu\n", ++ __func__, x, x + fillable, eof_blk); ++ if (eof_blk >= x && eof_blk <= x + fillable) ++ fillable = eof_blk - x; ++ } ++ ++ if (fillable == 0) ++ goto try_right; ++ ++ /* Test if the right edge of the range is already mapped? */ ++ if (EXT2FS_CLUSTER_RATIO(fs) > 1) { ++ err = ext2fs_map_cluster_block(fs, ino, inode, ++ x + fillable, &pblk); ++ if (err) ++ goto out; ++ if (pblk) ++ fillable -= 1 + ((x + fillable) ++ & EXT2FS_CLUSTER_MASK(fs)); ++ if (fillable == 0) ++ goto try_right; ++ } ++ ++ /* Allocate range of blocks */ ++ x = left_ext->e_pblk + left_ext->e_len; ++ err = ext2fs_new_range(fs, EXT2_NEWRANGE_FIXED_GOAL | ++ EXT2_NEWRANGE_MIN_LENGTH, ++ x, fillable, NULL, &pblk, &plen); ++ if (err) ++ goto try_right; ++ err = claim_range(fs, inode, pblk, plen); ++ if (err) ++ goto out; ++ ++ /* Modify left_ext */ ++ err = ext2fs_extent_goto(handle, left_ext->e_lblk); ++ if (err) ++ goto out; ++ range_start += plen; ++ range_len -= plen; ++ left_ext->e_len += plen; ++ dbg_print_extent("ext_falloc left+", left_ext); ++ err = ext2fs_extent_replace(handle, 0, left_ext); ++ if (err) ++ goto out; ++ err = ext2fs_extent_fix_parents(handle); ++ if (err) ++ goto out; ++ ++ /* Zero blocks if necessary */ ++ if (!(left_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT) && ++ (flags & EXT2_FALLOCATE_ZERO_BLOCKS)) { ++ err = ext2fs_zero_blocks2(fs, pblk, plen, NULL, NULL); ++ if (err) ++ goto out; ++ } ++ } ++ ++try_right: ++ /* Extend the right extent */ ++ if (right_ext) { ++ /* How much can we attach to right_ext? */ ++ if (right_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT) ++ fillable = max_uninit_len - right_ext->e_len; ++ else if (flags & EXT2_FALLOCATE_ZERO_BLOCKS) ++ fillable = max_init_len - right_ext->e_len; ++ else ++ fillable = 0; ++ ++ /* User requires init/uninit but extent is uninit/init. */ ++ if (((flags & EXT2_FALLOCATE_FORCE_INIT) && ++ (right_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT)) || ++ ((flags & EXT2_FALLOCATE_FORCE_UNINIT) && ++ !(right_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT))) ++ goto try_anywhere; ++ ++ if (fillable > range_len) ++ fillable = range_len; ++ if (fillable == 0) ++ goto try_anywhere; ++ ++ /* Test if the left edge of the range is already mapped? */ ++ if (EXT2FS_CLUSTER_RATIO(fs) > 1) { ++ err = ext2fs_map_cluster_block(fs, ino, inode, ++ right_ext->e_lblk - fillable, &pblk); ++ if (err) ++ goto out; ++ if (pblk) ++ fillable -= EXT2FS_CLUSTER_RATIO(fs) - ++ ((right_ext->e_lblk - fillable) ++ & EXT2FS_CLUSTER_MASK(fs)); ++ if (fillable == 0) ++ goto try_anywhere; ++ } ++ ++ /* ++ * FIXME: It would be nice if we could handle allocating a ++ * variable range from a fixed end point instead of just ++ * skipping to the general allocator if the whole range is ++ * unavailable. ++ */ ++ err = ext2fs_new_range(fs, EXT2_NEWRANGE_FIXED_GOAL | ++ EXT2_NEWRANGE_MIN_LENGTH, ++ right_ext->e_pblk - fillable, ++ fillable, NULL, &pblk, &plen); ++ if (err) ++ goto try_anywhere; ++ err = claim_range(fs, inode, ++ pblk & ~EXT2FS_CLUSTER_MASK(fs), ++ plen + (pblk & EXT2FS_CLUSTER_MASK(fs))); ++ if (err) ++ goto out; ++ ++ /* Modify right_ext */ ++ err = ext2fs_extent_goto(handle, right_ext->e_lblk); ++ if (err) ++ goto out; ++ range_len -= plen; ++ right_ext->e_lblk -= plen; ++ right_ext->e_pblk -= plen; ++ right_ext->e_len += plen; ++ dbg_print_extent("ext_falloc right+", right_ext); ++ err = ext2fs_extent_replace(handle, 0, right_ext); ++ if (err) ++ goto out; ++ err = ext2fs_extent_fix_parents(handle); ++ if (err) ++ goto out; ++ ++ /* Zero blocks if necessary */ ++ if (!(right_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT) && ++ (flags & EXT2_FALLOCATE_ZERO_BLOCKS)) { ++ err = ext2fs_zero_blocks2(fs, pblk, ++ plen + cluster_fill, NULL, NULL); ++ if (err) ++ goto out; ++ } ++ } ++ ++try_anywhere: ++ /* Try implied cluster alloc on the left and right ends */ ++ if (range_len > 0 && (range_start & EXT2FS_CLUSTER_MASK(fs))) { ++ cluster_fill = EXT2FS_CLUSTER_RATIO(fs) - ++ (range_start & EXT2FS_CLUSTER_MASK(fs)); ++ cluster_fill &= EXT2FS_CLUSTER_MASK(fs); ++ if (cluster_fill > range_len) ++ cluster_fill = range_len; ++ newex.e_lblk = range_start; ++ err = ext2fs_map_cluster_block(fs, ino, inode, newex.e_lblk, ++ &pblk); ++ if (err) ++ goto out; ++ if (pblk == 0) ++ goto try_right_implied; ++ newex.e_pblk = pblk; ++ newex.e_len = cluster_fill; ++ newex.e_flags = (flags & EXT2_FALLOCATE_FORCE_INIT ? 0 : ++ EXT2_EXTENT_FLAGS_UNINIT); ++ dbg_print_extent("ext_falloc iclus left+", &newex); ++ ext2fs_extent_goto(handle, newex.e_lblk); ++ err = ext2fs_extent_get(handle, EXT2_EXTENT_CURRENT, ++ &ex); ++ if (err == EXT2_ET_NO_CURRENT_NODE) ++ ex.e_lblk = 0; ++ else if (err) ++ goto out; ++ ++ if (ex.e_lblk > newex.e_lblk) ++ op = 0; /* insert before */ ++ else ++ op = EXT2_EXTENT_INSERT_AFTER; ++ dbg_printf("%s: inserting %s lblk %llu newex=%llu\n", ++ __func__, op ? "after" : "before", ex.e_lblk, ++ newex.e_lblk); ++ err = ext2fs_extent_insert(handle, op, &newex); ++ if (err) ++ goto out; ++ err = ext2fs_extent_fix_parents(handle); ++ if (err) ++ goto out; ++ ++ if (!(newex.e_flags & EXT2_EXTENT_FLAGS_UNINIT) && ++ (flags & EXT2_FALLOCATE_ZERO_BLOCKS)) { ++ err = ext2fs_zero_blocks2(fs, newex.e_pblk, ++ newex.e_len, NULL, NULL); ++ if (err) ++ goto out; ++ } ++ ++ range_start += cluster_fill; ++ range_len -= cluster_fill; ++ } ++ ++try_right_implied: ++ y = range_start + range_len; ++ if (range_len > 0 && (y & EXT2FS_CLUSTER_MASK(fs))) { ++ cluster_fill = y & EXT2FS_CLUSTER_MASK(fs); ++ if (cluster_fill > range_len) ++ cluster_fill = range_len; ++ newex.e_lblk = y & ~EXT2FS_CLUSTER_MASK(fs); ++ err = ext2fs_map_cluster_block(fs, ino, inode, newex.e_lblk, ++ &pblk); ++ if (err) ++ goto out; ++ if (pblk == 0) ++ goto no_implied; ++ newex.e_pblk = pblk; ++ newex.e_len = cluster_fill; ++ newex.e_flags = (flags & EXT2_FALLOCATE_FORCE_INIT ? 0 : ++ EXT2_EXTENT_FLAGS_UNINIT); ++ dbg_print_extent("ext_falloc iclus right+", &newex); ++ ext2fs_extent_goto(handle, newex.e_lblk); ++ err = ext2fs_extent_get(handle, EXT2_EXTENT_CURRENT, ++ &ex); ++ if (err == EXT2_ET_NO_CURRENT_NODE) ++ ex.e_lblk = 0; ++ else if (err) ++ goto out; ++ ++ if (ex.e_lblk > newex.e_lblk) ++ op = 0; /* insert before */ ++ else ++ op = EXT2_EXTENT_INSERT_AFTER; ++ dbg_printf("%s: inserting %s lblk %llu newex=%llu\n", ++ __func__, op ? "after" : "before", ex.e_lblk, ++ newex.e_lblk); ++ err = ext2fs_extent_insert(handle, op, &newex); ++ if (err) ++ goto out; ++ err = ext2fs_extent_fix_parents(handle); ++ if (err) ++ goto out; ++ ++ if (!(newex.e_flags & EXT2_EXTENT_FLAGS_UNINIT) && ++ (flags & EXT2_FALLOCATE_ZERO_BLOCKS)) { ++ err = ext2fs_zero_blocks2(fs, newex.e_pblk, ++ newex.e_len, NULL, NULL); ++ if (err) ++ goto out; ++ } ++ ++ range_len -= cluster_fill; ++ } ++ ++no_implied: ++ if (range_len == 0) ++ return 0; ++ ++ newex.e_lblk = range_start; ++ if (flags & EXT2_FALLOCATE_FORCE_INIT) { ++ max_extent_len = max_init_len; ++ newex.e_flags = 0; ++ } else { ++ max_extent_len = max_uninit_len; ++ newex.e_flags = EXT2_EXTENT_FLAGS_UNINIT; ++ } ++ pblk = alloc_goal; ++ y = range_len; ++ for (x = 0; x < y;) { ++ cluster_fill = newex.e_lblk & EXT2FS_CLUSTER_MASK(fs); ++ fillable = min(range_len + cluster_fill, max_extent_len); ++ err = ext2fs_new_range(fs, 0, pblk & ~EXT2FS_CLUSTER_MASK(fs), ++ fillable, ++ NULL, &pblk, &plen); ++ if (err) ++ goto out; ++ err = claim_range(fs, inode, pblk, plen); ++ if (err) ++ goto out; ++ ++ /* Create extent */ ++ newex.e_pblk = pblk + cluster_fill; ++ newex.e_len = plen - cluster_fill; ++ dbg_print_extent("ext_falloc create", &newex); ++ ext2fs_extent_goto(handle, newex.e_lblk); ++ err = ext2fs_extent_get(handle, EXT2_EXTENT_CURRENT, ++ &ex); ++ if (err == EXT2_ET_NO_CURRENT_NODE) ++ ex.e_lblk = 0; ++ else if (err) ++ goto out; ++ ++ if (ex.e_lblk > newex.e_lblk) ++ op = 0; /* insert before */ ++ else ++ op = EXT2_EXTENT_INSERT_AFTER; ++ dbg_printf("%s: inserting %s lblk %llu newex=%llu\n", ++ __func__, op ? "after" : "before", ex.e_lblk, ++ newex.e_lblk); ++ err = ext2fs_extent_insert(handle, op, &newex); ++ if (err) ++ goto out; ++ err = ext2fs_extent_fix_parents(handle); ++ if (err) ++ goto out; ++ ++ if (!(newex.e_flags & EXT2_EXTENT_FLAGS_UNINIT) && ++ (flags & EXT2_FALLOCATE_ZERO_BLOCKS)) { ++ err = ext2fs_zero_blocks2(fs, pblk, plen, NULL, NULL); ++ if (err) ++ goto out; ++ } ++ ++ /* Update variables at end of loop */ ++ x += plen - cluster_fill; ++ range_len -= plen - cluster_fill; ++ newex.e_lblk += plen - cluster_fill; ++ pblk += plen - cluster_fill; ++ if (pblk >= ext2fs_blocks_count(fs->super)) ++ pblk = fs->super->s_first_data_block; ++ } ++ ++out: ++ return err; ++} ++ ++static errcode_t extent_fallocate(ext2_filsys fs, int flags, ext2_ino_t ino, ++ struct ext2_inode *inode, blk64_t goal, ++ blk64_t start, blk64_t len) ++{ ++ ext2_extent_handle_t handle; ++ struct ext2fs_extent left_extent, right_extent; ++ struct ext2fs_extent *left_adjacent, *right_adjacent; ++ errcode_t err; ++ blk64_t range_start, range_end = 0, end, next; ++ blk64_t count, goal_distance; ++ ++ end = start + len - 1; ++ err = ext2fs_extent_open2(fs, ino, inode, &handle); ++ if (err) ++ return err; ++ ++ /* ++ * Find the extent closest to the start of the alloc range. We don't ++ * check the return value because _goto() sets the current node to the ++ * next-lowest extent if 'start' is in a hole; or the next-highest ++ * extent if there aren't any lower ones; or doesn't set a current node ++ * if there was a real error reading the extent tree. In that case, ++ * _get() will error out. ++ */ ++start_again: ++ ext2fs_extent_goto(handle, start); ++ err = ext2fs_extent_get(handle, EXT2_EXTENT_CURRENT, &left_extent); ++ if (err == EXT2_ET_NO_CURRENT_NODE) { ++ blk64_t max_blocks = ext2fs_blocks_count(fs->super); ++ ++ if (goal == ~0ULL) ++ goal = ext2fs_find_inode_goal(fs, ino, inode, start); ++ err = ext2fs_find_first_zero_block_bitmap2(fs->block_map, ++ goal, max_blocks - 1, &goal); ++ goal += start; ++ err = ext_falloc_helper(fs, flags, ino, inode, handle, NULL, ++ NULL, start, len, goal); ++ goto errout; ++ } else if (err) ++ goto errout; ++ ++ dbg_print_extent("ext_falloc initial", &left_extent); ++ next = left_extent.e_lblk + left_extent.e_len; ++ if (left_extent.e_lblk > start) { ++ /* The nearest extent we found was beyond start??? */ ++ goal = left_extent.e_pblk - (left_extent.e_lblk - start); ++ err = ext_falloc_helper(fs, flags, ino, inode, handle, NULL, ++ &left_extent, start, ++ left_extent.e_lblk - start, goal); ++ if (err) ++ goto errout; ++ ++ goto start_again; ++ } else if (next >= start) { ++ range_start = next; ++ left_adjacent = &left_extent; ++ } else { ++ range_start = start; ++ left_adjacent = NULL; ++ } ++ goal = left_extent.e_pblk + (range_start - left_extent.e_lblk); ++ goal_distance = range_start - next; ++ ++ do { ++ err = ext2fs_extent_get(handle, EXT2_EXTENT_NEXT_LEAF, ++ &right_extent); ++ dbg_printf("%s: ino=%d get next =%d\n", __func__, ino, ++ (int)err); ++ dbg_print_extent("ext_falloc next", &right_extent); ++ /* Stop if we've seen this extent before */ ++ if (!err && right_extent.e_lblk <= left_extent.e_lblk) ++ err = EXT2_ET_EXTENT_NO_NEXT; ++ ++ if (err && err != EXT2_ET_EXTENT_NO_NEXT) ++ goto errout; ++ if (err == EXT2_ET_EXTENT_NO_NEXT || ++ right_extent.e_lblk > end + 1) { ++ range_end = end; ++ right_adjacent = NULL; ++ } else { ++ /* Handle right_extent.e_lblk <= end */ ++ range_end = right_extent.e_lblk - 1; ++ right_adjacent = &right_extent; ++ } ++ if (err != EXT2_ET_EXTENT_NO_NEXT && ++ goal_distance > (range_end - right_extent.e_lblk)) { ++ goal = right_extent.e_pblk - ++ (right_extent.e_lblk - range_start); ++ goal_distance = range_end - right_extent.e_lblk; ++ } ++ ++ dbg_printf("%s: ino=%d rstart=%llu rend=%llu\n", __func__, ino, ++ range_start, range_end); ++ err = 0; ++ if (range_start <= range_end) { ++ count = range_end - range_start + 1; ++ err = ext_falloc_helper(fs, flags, ino, inode, handle, ++ left_adjacent, right_adjacent, ++ range_start, count, goal); ++ if (err) ++ goto errout; ++ } ++ ++ if (range_end == end) ++ break; ++ ++ err = ext2fs_extent_goto(handle, right_extent.e_lblk); ++ if (err) ++ goto errout; ++ next = right_extent.e_lblk + right_extent.e_len; ++ left_extent = right_extent; ++ left_adjacent = &left_extent; ++ range_start = next; ++ goal = left_extent.e_pblk + (range_start - left_extent.e_lblk); ++ goal_distance = range_start - next; ++ } while (range_end < end); ++ ++errout: ++ ext2fs_extent_free(handle); ++ return err; ++} ++ ++/* ++ * Map physical blocks to a range of logical blocks within a file. The range ++ * of logical blocks are (start, start + len). If there are already extents, ++ * the mappings will try to extend the mappings; otherwise, it will try to map ++ * start as if logical block 0 points to goal. If goal is ~0ULL, then the goal ++ * is calculated based on the inode group. ++ * ++ * Flags: ++ * - EXT2_FALLOCATE_ZERO_BLOCKS: Zero the blocks that are allocated. ++ * - EXT2_FALLOCATE_FORCE_INIT: Create only initialized extents. ++ * - EXT2_FALLOCATE_FORCE_UNINIT: Create only uninitialized extents. ++ * - EXT2_FALLOCATE_INIT_BEYOND_EOF: Create extents beyond EOF. ++ * ++ * If neither FORCE_INIT nor FORCE_UNINIT are specified, this function will ++ * try to expand any extents it finds, zeroing blocks as necessary. ++ */ ++errcode_t ext2fs_fallocate(ext2_filsys fs, int flags, ext2_ino_t ino, ++ struct ext2_inode *inode, blk64_t goal, ++ blk64_t start, blk64_t len) ++{ ++ struct ext2_inode inode_buf; ++ blk64_t blk, x; ++ errcode_t err; ++ ++ if (((flags & EXT2_FALLOCATE_FORCE_INIT) && ++ (flags & EXT2_FALLOCATE_FORCE_UNINIT)) || ++ (flags & ~EXT2_FALLOCATE_ALL_FLAGS)) ++ return EXT2_ET_INVALID_ARGUMENT; ++ ++ if (len > ext2fs_blocks_count(fs->super)) ++ return EXT2_ET_BLOCK_ALLOC_FAIL; ++ else if (len == 0) ++ return 0; ++ ++ /* Read inode structure if necessary */ ++ if (!inode) { ++ err = ext2fs_read_inode(fs, ino, &inode_buf); ++ if (err) ++ return err; ++ inode = &inode_buf; ++ } ++ dbg_printf("%s: ino=%d start=%llu len=%llu goal=%llu\n", __func__, ino, ++ start, len, goal); ++ ++ if (inode->i_flags & EXT4_EXTENTS_FL) { ++ err = extent_fallocate(fs, flags, ino, inode, goal, start, len); ++ goto out; ++ } ++ ++ /* XXX: Allocate a bunch of blocks the slow way */ ++ for (blk = start; blk < start + len; blk++) { ++ err = ext2fs_bmap2(fs, ino, inode, NULL, 0, blk, 0, &x); ++ if (err) ++ return err; ++ if (x) ++ continue; ++ ++ err = ext2fs_bmap2(fs, ino, inode, NULL, ++ BMAP_ALLOC | BMAP_UNINIT | BMAP_ZERO, blk, ++ 0, &x); ++ if (err) ++ return err; ++ } ++ ++out: ++ if (inode == &inode_buf) ++ ext2fs_write_inode(fs, ino, inode); ++ return err; ++} +--- a/lib/ext2fs/fileio.c ++++ b/lib/ext2fs/fileio.c +@@ -123,6 +123,8 @@ + { + errcode_t retval; + ext2_filsys fs; ++ int ret_flags; ++ blk64_t dontcare; + + EXT2_CHECK_MAGIC(file, EXT2_ET_MAGIC_EXT2_FILE); + fs = file->fs; +@@ -131,6 +133,22 @@ + !(file->flags & EXT2_FILE_BUF_DIRTY)) + return 0; + ++ /* Is this an uninit block? */ ++ if (file->physblock && file->inode.i_flags & EXT4_EXTENTS_FL) { ++ retval = ext2fs_bmap2(fs, file->ino, &file->inode, BMAP_BUFFER, ++ 0, file->blockno, &ret_flags, &dontcare); ++ if (retval) ++ return retval; ++ if (ret_flags & BMAP_RET_UNINIT) { ++ retval = ext2fs_bmap2(fs, file->ino, &file->inode, ++ BMAP_BUFFER, BMAP_SET, ++ file->blockno, 0, ++ &file->physblock); ++ if (retval) ++ return retval; ++ } ++ } ++ + /* + * OK, the physical block hasn't been allocated yet. + * Allocate it. +@@ -185,15 +203,17 @@ + { + ext2_filsys fs = file->fs; + errcode_t retval; ++ int ret_flags; + + if (!(file->flags & EXT2_FILE_BUF_VALID)) { + retval = ext2fs_bmap2(fs, file->ino, &file->inode, +- BMAP_BUFFER, 0, file->blockno, 0, ++ BMAP_BUFFER, 0, file->blockno, &ret_flags, + &file->physblock); + if (retval) + return retval; + if (!dontfill) { +- if (file->physblock) { ++ if (file->physblock && ++ !(ret_flags & BMAP_RET_UNINIT)) { + retval = io_channel_read_blk64(fs->io, + file->physblock, + 1, file->buf); +@@ -224,6 +244,38 @@ + } + + ++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 = (char *) 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 +288,10 @@ + 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 +322,66 @@ + } + + ++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 +396,16 @@ + 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) +@@ -358,7 +484,7 @@ + errcode_t ext2fs_file_lseek(ext2_file_t file, ext2_off_t offset, + int whence, ext2_off_t *ret_pos) + { +- __u64 loffset, ret_loffset; ++ __u64 loffset, ret_loffset = 0; + errcode_t retval; + + loffset = offset; +--- a/lib/ext2fs/freefs.c ++++ b/lib/ext2fs/freefs.c +@@ -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)) +@@ -63,25 +61,11 @@ + + fs->magic = 0; + ++ ext2fs_zero_blocks2(NULL, 0, 0, NULL, NULL); + ext2fs_free_mem(&fs); + } + + /* +- * Free the inode cache structure +- */ +-static void ext2fs_free_inode_cache(struct ext2_inode_cache *icache) +-{ +- if (--icache->refcount) +- return; +- if (icache->buffer) +- ext2fs_free_mem(&icache->buffer); +- if (icache->cache) +- ext2fs_free_mem(&icache->cache); +- icache->buffer_blk = 0; +- ext2fs_free_mem(&icache); +-} +- +-/* + * This procedure frees a badblocks list. + */ + void ext2fs_u32_list_free(ext2_u32_list bb) +--- a/lib/ext2fs/gen_bitmap64.c ++++ b/lib/ext2fs/gen_bitmap64.c +@@ -80,7 +80,7 @@ + #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 @@ + 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 @@ + 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 @@ + 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 @@ + 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 @@ + 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 @@ + 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 @@ + 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 @@ + + 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 @@ + + 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++; +--- a/lib/ext2fs/gen_crc32ctable.c ++++ b/lib/ext2fs/gen_crc32ctable.c +@@ -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 @@ + 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 @@ + } + + /** +- * 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 \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; +--- /dev/null ++++ b/lib/ext2fs/get_num_dirs.c +@@ -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 ++#if HAVE_UNISTD_H ++#include ++#endif ++#include ++#include ++ ++#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; ++} ++ +--- a/lib/ext2fs/get_pathname.c ++++ b/lib/ext2fs/get_pathname.c +@@ -49,21 +49,20 @@ + { + 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; +--- a/lib/ext2fs/getsectsize.c ++++ b/lib/ext2fs/getsectsize.c +@@ -10,8 +10,12 @@ + * %End-Header% + */ + ++#ifndef _LARGEFILE_SOURCE + #define _LARGEFILE_SOURCE ++#endif ++#ifndef _LARGEFILE64_SOURCE + #define _LARGEFILE64_SOURCE ++#endif + + #include "config.h" + #include +--- a/lib/ext2fs/getsize.c ++++ b/lib/ext2fs/getsize.c +@@ -12,8 +12,12 @@ + * %End-Header% + */ + ++#ifndef _LARGEFILE_SOURCE + #define _LARGEFILE_SOURCE ++#endif ++#ifndef _LARGEFILE64_SOURCE + #define _LARGEFILE64_SOURCE ++#endif + + #include "config.h" + #include +--- a/lib/ext2fs/icount.c ++++ b/lib/ext2fs/icount.c +@@ -193,13 +193,14 @@ + 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 +--- a/lib/ext2fs/initialize.c ++++ b/lib/ext2fs/initialize.c +@@ -476,8 +476,7 @@ + * 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++) { + /* +--- a/lib/ext2fs/inline.c ++++ b/lib/ext2fs/inline.c +@@ -45,19 +45,16 @@ + errcode_t ext2fs_get_memalign(unsigned long size, + unsigned long align, void *ptr) + { +- errcode_t retval; ++ errcode_t retval = 0; + void **p = ptr; + + if (align < 8) + align = 8; + #ifdef HAVE_POSIX_MEMALIGN + retval = posix_memalign(p, align, size); +- if (retval) { +- if (retval == ENOMEM) +- return EXT2_ET_NO_MEMORY; +- return retval; +- } +-#else ++ if (retval == ENOMEM) ++ return EXT2_ET_NO_MEMORY; ++#else /* !HAVE_POSIX_MEMALIGN */ + #ifdef HAVE_MEMALIGN + *p = memalign(align, size); + if (*p == NULL) { +@@ -66,7 +63,7 @@ + else + return EXT2_ET_NO_MEMORY; + } +-#else ++#else /* !HAVE_MEMALIGN */ + #ifdef HAVE_VALLOC + if (align > sizeof(long long)) + *p = valloc(size); +@@ -79,9 +76,9 @@ + } + if (*p == 0) + return EXT2_ET_NO_MEMORY; +-#endif +-#endif +- return 0; ++#endif /* HAVE_MEMALIGN */ ++#endif /* HAVE_POSIX_MEMALIGN */ ++ return retval; + } + + #ifdef DEBUG +--- /dev/null ++++ b/lib/ext2fs/inline_data.c +@@ -0,0 +1,854 @@ ++/* ++ * inline_data.c --- data in inode ++ * ++ * Copyright (C) 2012 Zheng Liu ++ * ++ * %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 ++#include ++#include /* 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; ++ char empty[1] = { '\0' }; ++ ++ data.fs = fs; ++ data.ino = ino; ++ data.ea_size = 0; ++ data.ea_data = empty; ++ 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; ++ int offset; ++ unsigned int 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 */ ++ memset(inode->i_block, 0, sizeof(inode->i_block)); ++ if (EXT2_HAS_INCOMPAT_FEATURE(fs->super, ++ EXT3_FEATURE_INCOMPAT_EXTENTS)) { ++ ext2_extent_handle_t handle; ++ ++ inode->i_flags &= ~EXT4_EXTENTS_FL; ++ retval = ext2fs_extent_open2(fs, ino, inode, &handle); ++ if (retval) ++ return retval; ++ ext2fs_extent_free(handle); ++ } ++ 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((char *) 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 = (char *) 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; ++ ++ /* 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; ++ ++ /* setup */ ++ initialize_ext2_error_table(); ++ ++ memset(¶m, 0, sizeof(param)); ++ ext2fs_blocks_count_set(¶m, 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, ¶m, ++ 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) { ++ 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 +--- a/lib/ext2fs/inode.c ++++ b/lib/ext2fs/inode.c +@@ -30,6 +30,10 @@ + #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; +@@ -60,7 +64,7 @@ + */ + errcode_t ext2fs_flush_icache(ext2_filsys fs) + { +- int i; ++ unsigned i; + + if (!fs->icache) + return 0; +@@ -72,8 +76,28 @@ + 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) + { ++ unsigned 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) ++{ ++ unsigned i; + errcode_t retval; + + if (fs->icache) +@@ -84,24 +108,32 @@ + + 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, +@@ -143,13 +175,13 @@ + scan->bytes_left = 0; + scan->current_group = 0; + scan->groups_left = fs->group_desc_count - 1; +- scan->inode_buffer_blocks = buffer_blocks ? buffer_blocks : 8; ++ scan->inode_buffer_blocks = buffer_blocks ? buffer_blocks : ++ EXT2_INODE_SCAN_DEFAULT_BUFFER_BLOCKS; + scan->current_block = ext2fs_inode_table_loc(scan->fs, + 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)) { + __u32 unused = ext2fs_bg_itable_unused(fs, scan->current_group); + if (scan->inodes_left > unused) + scan->inodes_left -= unused; +@@ -169,16 +201,17 @@ + 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; +@@ -244,8 +277,7 @@ + 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)) { + __u32 unused = ext2fs_bg_itable_unused(fs, scan->current_group); + if (scan->inodes_left > unused) + scan->inodes_left -= unused; +@@ -329,6 +361,136 @@ + 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; ++ char *p; ++ struct ext2_inode_large *inode; ++ char *block_status; ++ unsigned int blk, bad_csum; ++ ++ 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 = (char *) 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); ++ ++ if (inodes_per_block < 2) ++ return; ++ ++#ifdef WORDS_BIGENDIAN ++ if (ext2fs_get_mem(EXT2_INODE_SIZE(scan->fs->super), &inode)) ++ return; ++#endif ++ ++ while (inodes_to_scan > 0) { ++ blk = (p - (char *)scan->inode_buffer) / scan->fs->blocksize; ++ bad_csum = ext2fs_inode_csum_verify(scan->fs, ino, ++ (struct ext2_inode_large *) p) == 0; ++ ++#ifdef WORDS_BIGENDIAN ++ ext2fs_swap_inode_full(scan->fs, ++ (struct ext2_inode_large *) inode, ++ (struct ext2_inode_large *) p, ++ 0, EXT2_INODE_SIZE(scan->fs->super)); ++#else ++ inode = (struct ext2_inode_large *) p; ++#endif ++ ++ /* Is this inode insane? */ ++ if (bad_csum) { ++ 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++; ++ }; ++ ++#ifdef WORDS_BIGENDIAN ++ ext2fs_free_mem(&inode); ++#endif ++} ++ + /* + * This function is called by ext2fs_get_next_inode when it needs to + * read in more blocks from the current blockgroup's inode table. +@@ -378,12 +540,15 @@ + 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; + } + +@@ -413,8 +578,14 @@ + { + 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? +@@ -475,44 +646,74 @@ + #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; + } + +@@ -533,8 +734,12 @@ + unsigned long group, block, offset; + char *ptr; + errcode_t retval; +- int clen, i, inodes_per_block, length; ++ unsigned i; ++ int clen, 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); + +@@ -550,18 +755,16 @@ + 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) { +@@ -586,11 +789,10 @@ + } + 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) +@@ -612,18 +814,26 @@ + 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; + } +@@ -641,9 +851,11 @@ + 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; ++ unsigned i; ++ int clen; ++ int length = EXT2_INODE_SIZE(fs->super); + + EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); + +@@ -654,48 +866,55 @@ + 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); +@@ -708,10 +927,6 @@ + + offset &= (EXT2_BLOCK_SIZE(fs->super) - 1); + +- length = EXT2_INODE_SIZE(fs->super); +- if (length > bufsize) +- length = bufsize; +- + ptr = (char *) w_inode; + + while (length) { +@@ -744,8 +959,7 @@ + + fs->flags |= EXT2_FLAG_CHANGED; + errout: +- if (w_inode && w_inode != &temp_inode) +- free(w_inode); ++ ext2fs_free_mem(&w_inode); + return retval; + } + +--- a/lib/ext2fs/io_manager.c ++++ b/lib/ext2fs/io_manager.c +@@ -112,6 +112,17 @@ + return EXT2_ET_UNIMPLEMENTED; + } + ++errcode_t io_channel_zeroout(io_channel channel, unsigned long long block, ++ unsigned long long count) ++{ ++ EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); ++ ++ if (channel->manager->zeroout) ++ return (channel->manager->zeroout)(channel, block, count); ++ ++ return EXT2_ET_UNIMPLEMENTED; ++} ++ + errcode_t io_channel_alloc_buf(io_channel io, int count, void *ptr) + { + size_t size; +@@ -128,3 +139,12 @@ + else + return ext2fs_get_mem(size, ptr); + } ++ ++errcode_t io_channel_cache_readahead(io_channel io, unsigned long long block, ++ unsigned long long count) ++{ ++ if (!io->manager->cache_readahead) ++ return EXT2_ET_OP_NOT_SUPPORTED; ++ ++ return io->manager->cache_readahead(io, block, count); ++} +--- a/lib/ext2fs/ismounted.c ++++ b/lib/ext2fs/ismounted.c +@@ -42,6 +42,7 @@ + #include "ext2_fs.h" + #include "ext2fs.h" + ++#ifdef HAVE_SETMNTENT + /* + * Check to see if a regular file is mounted. + * If /etc/mtab/ is a symlink of /proc/mounts, you will need the following check +@@ -72,7 +73,6 @@ + return 0; + } + +-#ifdef HAVE_SETMNTENT + /* + * Helper function which checks a file in /etc/mtab format to see if a + * filesystem is mounted. Returns an error if the file doesn't exist +--- a/lib/ext2fs/jfs_compat.h ++++ b/lib/ext2fs/jfs_compat.h +@@ -7,6 +7,7 @@ + #ifdef HAVE_NETINET_IN_H + #include + #endif ++#include + + #define printk printf + #define KERN_ERR "" +@@ -17,13 +18,45 @@ + + #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; ++typedef struct kdev_s *kdev_t; + + struct buffer_head; + struct inode; + ++#define GFP_KERNEL 0 ++#define JFS_TAG_SIZE32 JBD_TAG_SIZE32 ++#define JFS_BARRIER 0 ++typedef __u64 u64; ++#define JFS_CRC32_CHKSUM JBD2_CRC32_CHKSUM ++#define JFS_CRC32_CHKSUM_SIZE JBD2_CRC32_CHKSUM_SIZE ++#define put_bh(x) brelse(x) ++#define be64_to_cpu(x) ext2fs_be64_to_cpu(x) ++ ++static inline __u32 jbd2_chksum(journal_t *j EXT2FS_ATTR((unused)), ++ __u32 crc, const void *address, ++ unsigned int length) ++{ ++ return ext2fs_crc32c_le(crc, address, length); ++} ++#define crc32_be(x, y, z) ext2fs_crc32_be((x), (y), (z)) ++#define spin_lock_init(x) ++#define spin_lock(x) ++#define spin_unlock(x) ++#define yield() ++#define SLAB_HWCACHE_ALIGN 0 ++#define SLAB_TEMPORARY 0 ++#define KMEM_CACHE(__struct, __flags) kmem_cache_create(#__struct,\ ++ sizeof(struct __struct), __alignof__(struct __struct),\ ++ (__flags), NULL) ++ ++#define blkdev_issue_flush(kdev, a, b) sync_blockdev(kdev) ++#define is_power_of_2(x) ((x) != 0 && (((x) & ((x) - 1)) == 0)) ++ + struct journal_s + { + unsigned long j_flags; +@@ -44,8 +77,10 @@ + tid_t j_tail_sequence; + tid_t j_transaction_sequence; + __u8 j_uuid[16]; +- struct jbd_revoke_table_s *j_revoke; ++ struct jbd2_revoke_table_s *j_revoke; ++ struct jbd2_revoke_table_s *j_revoke_table[2]; + tid_t j_failed_commit; ++ __u32 j_csum_seed; + }; + + #define J_ASSERT(assert) \ +--- a/lib/ext2fs/jfs_user.h ++++ /dev/null +@@ -1,8 +0,0 @@ +-#ifndef _JFS_USER_H +-#define _JFS_USER_H +- +-typedef unsigned short kdev_t; +- +-#include "kernel-jbd.h" +- +-#endif /* _JFS_USER_H */ +--- a/lib/ext2fs/kernel-jbd.h ++++ b/lib/ext2fs/kernel-jbd.h +@@ -16,19 +16,9 @@ + #ifndef _LINUX_JBD_H + #define _LINUX_JBD_H + +-#if defined(CONFIG_JBD) || defined(CONFIG_JBD_MODULE) || !defined(__KERNEL__) +- +-/* Allow this file to be included directly into e2fsprogs */ +-#ifndef __KERNEL__ + #include "jfs_compat.h" + #define JFS_DEBUG + #define jfs_debug jbd_debug +-#else +- +-#include +-#include +-#include +-#endif + + #ifndef __GNUC__ + #define __FUNCTION__ "" +@@ -73,11 +63,6 @@ + + #define JFS_MIN_JOURNAL_BLOCKS 1024 + +-#ifdef __KERNEL__ +-typedef struct handle_s handle_t; /* Atomic operation type */ +-typedef struct journal_s journal_t; /* Journal control structure */ +-#endif +- + /* + * Internal structures used by the logging mechanism: + */ +@@ -114,12 +99,28 @@ + #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. ++ * ++ * If FEATURE_INCOMPAT_CSUM_V3 is set, the descriptor block uses ++ * journal_block_tag3_t to store a full 32-bit checksum. Everything else ++ * is the same as v2. ++ * ++ * Checksum v1, v2, and v3 are mutually exclusive features. + */ + struct commit_header { + __u32 h_magic; +@@ -136,15 +137,26 @@ + /* + * The block tag: used to describe a single buffer in the journal + */ +-typedef struct journal_block_tag_s ++typedef struct journal_block_tag3_s + { + __u32 t_blocknr; /* The on-disk block number */ + __u32 t_flags; /* See below */ + __u32 t_blocknr_high; /* most-significant high 32bits. */ ++ __u32 t_checksum; /* crc32c(uuid+seq+block) */ ++} journal_block_tag3_t; ++ ++typedef struct journal_block_tag_s ++{ ++ __u32 t_blocknr; /* The on-disk block number */ ++ __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 { ++ __be32 t_checksum; ++}; + + /* + * The revoke descriptor: used on disk to describe a series of blocks to +@@ -156,6 +168,10 @@ + int r_count; /* Count of bytes used in the block */ + } journal_revoke_header_t; + ++/* Tail of revoke block, for checksumming */ ++struct journal_revoke_tail { ++ __be32 r_checksum; ++}; + + /* Definitions for the journal tag flags word: */ + #define JFS_FLAG_ESCAPE 1 /* on-disk block is escaped */ +@@ -208,7 +224,10 @@ + __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,614 +247,71 @@ + + #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 ++#define JFS_FEATURE_INCOMPAT_CSUM_V3 0x00000010 + + /* 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) +- +-#ifdef __KERNEL__ +- +-#include +-#include +- +-#define JBD_ASSERTIONS +-#ifdef JBD_ASSERTIONS +-#define J_ASSERT(assert) \ +-do { \ +- if (!(assert)) { \ +- printk (KERN_EMERG \ +- "Assertion failure in %s() at %s:%d: \"%s\"\n", \ +- __FUNCTION__, __FILE__, __LINE__, # assert); \ +- BUG(); \ +- } \ +-} while (0) +- +-#if defined(CONFIG_BUFFER_DEBUG) +-void buffer_assertion_failure(struct buffer_head *bh); +-#define J_ASSERT_BH(bh, expr) \ +- do { \ +- if (!(expr)) \ +- buffer_assertion_failure(bh); \ +- J_ASSERT(expr); \ +- } while (0) +-#define J_ASSERT_JH(jh, expr) J_ASSERT_BH(jh2bh(jh), expr) ++ JFS_FEATURE_INCOMPAT_64BIT|\ ++ JFS_FEATURE_INCOMPAT_CSUM_V2|\ ++ JFS_FEATURE_INCOMPAT_CSUM_V3) ++ ++#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 J_ASSERT_BH(bh, expr) J_ASSERT(expr) +-#define J_ASSERT_JH(jh, expr) J_ASSERT(expr) ++#define _INLINE_ inline + #endif +- +-#else +-#define J_ASSERT(assert) +-#endif /* JBD_ASSERTIONS */ +- +-enum jbd_state_bits { +- BH_JWrite +- = BH_PrivateStart, /* 1 if being written to log (@@@ DEBUGGING) */ +- BH_Freed, /* 1 if buffer has been freed (truncated) */ +- BH_Revoked, /* 1 if buffer has been revoked from the log */ +- BH_RevokeValid, /* 1 if buffer revoked flag is valid */ +- BH_JBDDirty, /* 1 if buffer is dirty but journaled */ +-}; +- +-/* Return true if the buffer is one which JBD is managing */ +-static inline int buffer_jbd(struct buffer_head *bh) +-{ +- return __buffer_state(bh, JBD); +-} +- +-static inline struct buffer_head *jh2bh(struct journal_head *jh) +-{ +- return jh->b_bh; +-} +- +-static inline struct journal_head *bh2jh(struct buffer_head *bh) +-{ +- return bh->b_private; +-} +- +-struct jbd_revoke_table_s; +- +-/* The handle_t type represents a single atomic update being performed +- * by some process. All filesystem modifications made by the process go +- * through this handle. Recursive operations (such as quota operations) +- * are gathered into a single update. +- * +- * The buffer credits field is used to account for journaled buffers +- * being modified by the running process. To ensure that there is +- * enough log space for all outstanding operations, we need to limit the +- * number of outstanding buffers possible at any time. When the +- * operation completes, any buffer credits not used are credited back to +- * the transaction, so that at all times we know how many buffers the +- * outstanding updates on a transaction might possibly touch. */ +- +-struct handle_s +-{ +- /* Which compound transaction is this update a part of? */ +- transaction_t * h_transaction; +- +- /* Number of remaining buffers we are allowed to dirty: */ +- int h_buffer_credits; +- +- /* Reference count on this handle */ +- int h_ref; +- +- /* Field for caller's use to track errors through large fs +- operations */ +- int h_err; +- +- /* Flags */ +- unsigned int h_sync: 1; /* sync-on-close */ +- unsigned int h_jdata: 1; /* force data journaling */ +- unsigned int h_aborted: 1; /* fatal error on handle */ +-}; +- +- +-/* The transaction_t type is the guts of the journaling mechanism. It +- * tracks a compound transaction through its various states: +- * +- * RUNNING: accepting new updates +- * LOCKED: Updates still running but we don't accept new ones +- * RUNDOWN: Updates are tidying up but have finished requesting +- * new buffers to modify (state not used for now) +- * FLUSH: All updates complete, but we are still writing to disk +- * COMMIT: All data on disk, writing commit record +- * FINISHED: We still have to keep the transaction for checkpointing. +- * +- * The transaction keeps track of all of the buffers modified by a +- * running transaction, and all of the buffers committed but not yet +- * flushed to home for finished transactions. +- */ +- +-struct transaction_s +-{ +- /* Pointer to the journal for this transaction. */ +- journal_t * t_journal; +- +- /* Sequence number for this transaction */ +- tid_t t_tid; +- +- /* Transaction's current state */ +- enum { +- T_RUNNING, +- T_LOCKED, +- T_RUNDOWN, +- T_FLUSH, +- T_COMMIT, +- T_FINISHED +- } t_state; +- +- /* Where in the log does this transaction's commit start? */ +- unsigned long t_log_start; +- +- /* Doubly-linked circular list of all inodes owned by this +- transaction */ /* AKPM: unused */ +- struct inode * t_ilist; +- +- /* Number of buffers on the t_buffers list */ +- int t_nr_buffers; +- +- /* Doubly-linked circular list of all buffers reserved but not +- yet modified by this transaction */ +- struct journal_head * t_reserved_list; +- +- /* Doubly-linked circular list of all metadata buffers owned by this +- transaction */ +- struct journal_head * t_buffers; +- +- /* +- * Doubly-linked circular list of all data buffers still to be +- * flushed before this transaction can be committed. +- * Protected by journal_datalist_lock. +- */ +- struct journal_head * t_sync_datalist; +- +- /* +- * Doubly-linked circular list of all writepage data buffers +- * still to be written before this transaction can be committed. +- * Protected by journal_datalist_lock. +- */ +- struct journal_head * t_async_datalist; +- +- /* Doubly-linked circular list of all forget buffers (superceded +- buffers which we can un-checkpoint once this transaction +- commits) */ +- struct journal_head * t_forget; +- +- /* +- * Doubly-linked circular list of all buffers still to be +- * flushed before this transaction can be checkpointed. +- */ +- /* Protected by journal_datalist_lock */ +- struct journal_head * t_checkpoint_list; +- +- /* Doubly-linked circular list of temporary buffers currently +- undergoing IO in the log */ +- struct journal_head * t_iobuf_list; +- +- /* Doubly-linked circular list of metadata buffers being +- shadowed by log IO. The IO buffers on the iobuf list and the +- shadow buffers on this list match each other one for one at +- all times. */ +- struct journal_head * t_shadow_list; +- +- /* Doubly-linked circular list of control buffers being written +- to the log. */ +- struct journal_head * t_log_list; +- +- /* Number of outstanding updates running on this transaction */ +- int t_updates; +- +- /* Number of buffers reserved for use by all handles in this +- * transaction handle but not yet modified. */ +- int t_outstanding_credits; +- +- /* +- * Forward and backward links for the circular list of all +- * transactions awaiting checkpoint. +- */ +- /* Protected by journal_datalist_lock */ +- transaction_t *t_cpnext, *t_cpprev; +- +- /* When will the transaction expire (become due for commit), in +- * jiffies ? */ +- unsigned long t_expires; +- +- /* How many handles used this transaction? */ +- int t_handle_count; +-}; +- +- +-/* The journal_t maintains all of the journaling state information for a +- * single filesystem. It is linked to from the fs superblock structure. +- * +- * We use the journal_t to keep track of all outstanding transaction +- * activity on the filesystem, and to manage the state of the log +- * writing process. */ +- +-struct journal_s +-{ +- /* General journaling state flags */ +- unsigned long j_flags; +- +- /* Is there an outstanding uncleared error on the journal (from +- * a prior abort)? */ +- int j_errno; +- +- /* The superblock buffer */ +- struct buffer_head * j_sb_buffer; +- journal_superblock_t * j_superblock; +- +- /* Version of the superblock format */ +- int j_format_version; +- +- /* Number of processes waiting to create a barrier lock */ +- int j_barrier_count; +- +- /* The barrier lock itself */ +- struct semaphore j_barrier; +- +- /* Transactions: The current running transaction... */ +- transaction_t * j_running_transaction; +- +- /* ... the transaction we are pushing to disk ... */ +- transaction_t * j_committing_transaction; +- +- /* ... and a linked circular list of all transactions waiting +- * for checkpointing. */ +- /* Protected by journal_datalist_lock */ +- transaction_t * j_checkpoint_transactions; +- +- /* Wait queue for waiting for a locked transaction to start +- committing, or for a barrier lock to be released */ +- wait_queue_head_t j_wait_transaction_locked; +- +- /* Wait queue for waiting for checkpointing to complete */ +- wait_queue_head_t j_wait_logspace; +- +- /* Wait queue for waiting for commit to complete */ +- wait_queue_head_t j_wait_done_commit; +- +- /* Wait queue to trigger checkpointing */ +- wait_queue_head_t j_wait_checkpoint; +- +- /* Wait queue to trigger commit */ +- wait_queue_head_t j_wait_commit; +- +- /* Wait queue to wait for updates to complete */ +- wait_queue_head_t j_wait_updates; +- +- /* Semaphore for locking against concurrent checkpoints */ +- struct semaphore j_checkpoint_sem; +- +- /* The main journal lock, used by lock_journal() */ +- struct semaphore j_sem; +- +- /* Journal head: identifies the first unused block in the journal. */ +- unsigned long j_head; +- +- /* Journal tail: identifies the oldest still-used block in the +- * journal. */ +- unsigned long j_tail; +- +- /* Journal free: how many free blocks are there in the journal? */ +- unsigned long j_free; +- +- /* Journal start and end: the block numbers of the first usable +- * block and one beyond the last usable block in the journal. */ +- unsigned long j_first, j_last; +- +- /* Device, blocksize and starting block offset for the location +- * where we store the journal. */ +- kdev_t j_dev; +- int j_blocksize; +- unsigned int j_blk_offset; +- +- /* Device which holds the client fs. For internal journal this +- * will be equal to j_dev. */ +- kdev_t j_fs_dev; +- +- /* Total maximum capacity of the journal region on disk. */ +- unsigned int j_maxlen; +- +- /* Optional inode where we store the journal. If present, all +- * journal block numbers are mapped into this inode via +- * bmap(). */ +- struct inode * j_inode; +- +- /* Sequence number of the oldest transaction in the log */ +- tid_t j_tail_sequence; +- /* Sequence number of the next transaction to grant */ +- tid_t j_transaction_sequence; +- /* Sequence number of the most recently committed transaction */ +- tid_t j_commit_sequence; +- /* Sequence number of the most recent transaction wanting commit */ +- tid_t j_commit_request; +- +- /* Journal uuid: identifies the object (filesystem, LVM volume +- * etc) backed by this journal. This will eventually be +- * replaced by an array of uuids, allowing us to index multiple +- * devices within a single journal and to perform atomic updates +- * across them. */ +- +- __u8 j_uuid[16]; +- +- /* Pointer to the current commit thread for this journal */ +- struct task_struct * j_task; +- +- /* Maximum number of metadata buffers to allow in a single +- * compound commit transaction */ +- int j_max_transaction_buffers; +- +- /* What is the maximum transaction lifetime before we begin a +- * commit? */ +- unsigned long j_commit_interval; +- +- /* The timer used to wakeup the commit thread: */ +- struct timer_list * j_commit_timer; +- int j_commit_timer_active; +- +- /* Link all journals together - system-wide */ +- struct list_head j_all_journals; +- +- /* The revoke table: maintains the list of revoked blocks in the +- current transaction. */ +- struct jbd_revoke_table_s *j_revoke; +- +- /* Failed journal commit ID */ +- unsigned int j_failed_commit; +-}; +- +-/* +- * Journal flag definitions +- */ +-#define JFS_UNMOUNT 0x001 /* Journal thread is being destroyed */ +-#define JFS_ABORT 0x002 /* Journaling has been aborted for errors. */ +-#define JFS_ACK_ERR 0x004 /* The errno in the sb has been acked */ +-#define JFS_FLUSHED 0x008 /* The journal superblock has been flushed */ +-#define JFS_LOADED 0x010 /* The journal superblock has been loaded */ +- +-/* +- * Function declarations for the journaling transaction and buffer +- * management +- */ +- +-/* Filing buffers */ +-extern void __journal_unfile_buffer(struct journal_head *); +-extern void journal_unfile_buffer(struct journal_head *); +-extern void __journal_refile_buffer(struct journal_head *); +-extern void journal_refile_buffer(struct journal_head *); +-extern void __journal_file_buffer(struct journal_head *, transaction_t *, int); +-extern void __journal_free_buffer(struct journal_head *bh); +-extern void journal_file_buffer(struct journal_head *, transaction_t *, int); +-extern void __journal_clean_data_list(transaction_t *transaction); +- +-/* Log buffer allocation */ +-extern struct journal_head * journal_get_descriptor_buffer(journal_t *); +-extern unsigned long journal_next_log_block(journal_t *); +- +-/* Commit management */ +-extern void journal_commit_transaction(journal_t *); +- +-/* Checkpoint list management */ +-int __journal_clean_checkpoint_list(journal_t *journal); +-extern void journal_remove_checkpoint(struct journal_head *); +-extern void __journal_remove_checkpoint(struct journal_head *); +-extern void journal_insert_checkpoint(struct journal_head *, transaction_t *); +-extern void __journal_insert_checkpoint(struct journal_head *,transaction_t *); +- +-/* Buffer IO */ +-extern int +-journal_write_metadata_buffer(transaction_t *transaction, +- struct journal_head *jh_in, +- struct journal_head **jh_out, +- int blocknr); +- +-/* Transaction locking */ +-extern void __wait_on_journal (journal_t *); ++#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 */ + + /* +- * Journal locking. +- * +- * We need to lock the journal during transaction state changes so that +- * nobody ever tries to take a handle on the running transaction while +- * we are in the middle of moving it to the commit phase. +- * +- * Note that the locking is completely interrupt unsafe. We never touch +- * journal structures from interrupts. +- * +- * In 2.2, the BKL was required for lock_journal. This is no longer +- * the case. ++ * helper functions to deal with 32 or 64bit block numbers. + */ +- +-static inline void lock_journal(journal_t *journal) ++_INLINE_ size_t journal_tag_bytes(journal_t *journal) + { +- down(&journal->j_sem); +-} ++ size_t sz; + +-/* This returns zero if we acquired the semaphore */ +-static inline int try_lock_journal(journal_t * journal) +-{ +- return down_trylock(&journal->j_sem); +-} ++ if (JFS_HAS_INCOMPAT_FEATURE(journal, JFS_FEATURE_INCOMPAT_CSUM_V3)) ++ return sizeof(journal_block_tag3_t); + +-static inline void unlock_journal(journal_t * journal) +-{ +- up(&journal->j_sem); +-} ++ sz = sizeof(journal_block_tag_t); + ++ if (JFS_HAS_INCOMPAT_FEATURE(journal, JFS_FEATURE_INCOMPAT_CSUM_V2)) ++ sz += sizeof(__u16); + +-static inline handle_t *journal_current_handle(void) +-{ +- return current->journal_info; +-} +- +-/* The journaling code user interface: +- * +- * Create and destroy handles +- * Register buffer modifications against the current transaction. +- */ ++ if (JFS_HAS_INCOMPAT_FEATURE(journal, JFS_FEATURE_INCOMPAT_64BIT)) ++ return sz; + +-extern handle_t *journal_start(journal_t *, int nblocks); +-extern handle_t *journal_try_start(journal_t *, int nblocks); +-extern int journal_restart (handle_t *, int nblocks); +-extern int journal_extend (handle_t *, int nblocks); +-extern int journal_get_write_access (handle_t *, struct buffer_head *); +-extern int journal_get_create_access (handle_t *, struct buffer_head *); +-extern int journal_get_undo_access (handle_t *, struct buffer_head *); +-extern int journal_dirty_data (handle_t *, +- struct buffer_head *, int async); +-extern int journal_dirty_metadata (handle_t *, struct buffer_head *); +-extern void journal_release_buffer (handle_t *, struct buffer_head *); +-extern void journal_forget (handle_t *, struct buffer_head *); +-extern void journal_sync_buffer (struct buffer_head *); +-extern int journal_flushpage(journal_t *, struct page *, unsigned long); +-extern int journal_try_to_free_buffers(journal_t *, struct page *, int); +-extern int journal_stop(handle_t *); +-extern int journal_flush (journal_t *); +- +-extern void journal_lock_updates (journal_t *); +-extern void journal_unlock_updates (journal_t *); +- +-extern journal_t * journal_init_dev(kdev_t dev, kdev_t fs_dev, +- int start, int len, int bsize); +-extern journal_t * journal_init_inode (struct inode *); +-extern int journal_update_format (journal_t *); +-extern int journal_check_used_features +- (journal_t *, unsigned long, unsigned long, unsigned long); +-extern int journal_check_available_features +- (journal_t *, unsigned long, unsigned long, unsigned long); +-extern int journal_set_features +- (journal_t *, unsigned long, unsigned long, unsigned long); +-extern int journal_create (journal_t *); +-extern int journal_load (journal_t *journal); +-extern void journal_destroy (journal_t *); +-extern int journal_recover (journal_t *journal); +-extern int journal_wipe (journal_t *, int); +-extern int journal_skip_recovery (journal_t *); +-extern void journal_update_superblock (journal_t *, int); +-extern void __journal_abort (journal_t *); +-extern void journal_abort (journal_t *, int); +-extern int journal_errno (journal_t *); +-extern void journal_ack_err (journal_t *); +-extern int journal_clear_err (journal_t *); +-extern unsigned long journal_bmap(journal_t *journal, unsigned long blocknr); +-extern int journal_force_commit(journal_t *journal); +- +-/* +- * journal_head management +- */ +-extern struct journal_head +- *journal_add_journal_head(struct buffer_head *bh); +-extern void journal_remove_journal_head(struct buffer_head *bh); +-extern void __journal_remove_journal_head(struct buffer_head *bh); +-extern void journal_unlock_journal_head(struct journal_head *jh); +- +-/* Primary revoke support */ +-#define JOURNAL_REVOKE_DEFAULT_HASH 256 +-extern int journal_init_revoke(journal_t *, int); +-extern void journal_destroy_revoke_caches(void); +-extern int journal_init_revoke_caches(void); +- +-extern void journal_destroy_revoke(journal_t *); +-extern int journal_revoke (handle_t *, +- unsigned long, struct buffer_head *); +-extern int journal_cancel_revoke(handle_t *, struct journal_head *); +-extern void journal_write_revoke_records(journal_t *, transaction_t *); +- +-/* Recovery revoke support */ +-extern int journal_set_revoke(journal_t *, unsigned long, tid_t); +-extern int journal_test_revoke(journal_t *, unsigned long, tid_t); +-extern void journal_clear_revoke(journal_t *); +-extern void journal_brelse_array(struct buffer_head *b[], int n); +- +-/* The log thread user interface: +- * +- * Request space in the current transaction, and force transaction commit +- * transitions on demand. +- */ +- +-extern int log_space_left (journal_t *); /* Called with journal locked */ +-extern tid_t log_start_commit (journal_t *, transaction_t *); +-extern void log_wait_commit (journal_t *, tid_t); +-extern int log_do_checkpoint (journal_t *, int); +- +-extern void log_wait_for_space(journal_t *, int nblocks); +-extern void __journal_drop_transaction(journal_t *, transaction_t *); +-extern int cleanup_journal_tail(journal_t *); +- +-/* Reduce journal memory usage by flushing */ +-extern void shrink_journal_memory(void); +- +-/* Debugging code only: */ +- +-#define jbd_ENOSYS() \ +-do { \ +- printk (KERN_ERR "JBD unimplemented function " __FUNCTION__); \ +- current->state = TASK_UNINTERRUPTIBLE; \ +- schedule(); \ +-} while (1) +- +-/* +- * is_journal_abort +- * +- * Simple test wrapper function to test the JFS_ABORT state flag. This +- * bit, when set, indicates that we have had a fatal error somewhere, +- * either inside the journaling layer or indicated to us by the client +- * (eg. ext3), and that we and should not commit any further +- * transactions. +- */ +- +-static inline int is_journal_aborted(journal_t *journal) +-{ +- return journal->j_flags & JFS_ABORT; ++ return sz - sizeof(__u32); + } + +-static inline int is_handle_aborted(handle_t *handle) ++_INLINE_ int journal_has_csum_v2or3(journal_t *journal) + { +- if (handle->h_aborted) ++ if (JFS_HAS_INCOMPAT_FEATURE(journal, JFS_FEATURE_INCOMPAT_CSUM_V2) || ++ JFS_HAS_INCOMPAT_FEATURE(journal, JFS_FEATURE_INCOMPAT_CSUM_V3)) + return 1; +- return is_journal_aborted(handle->h_transaction->t_journal); +-} + +-static inline void journal_abort_handle(handle_t *handle) +-{ +- handle->h_aborted = 1; ++ return 0; + } +- +-/* Not all architectures define BUG() */ +-#ifndef BUG +-#define BUG() do { \ +- printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \ +- * ((char *) 0) = 0; \ +- } while (0) +-#endif /* BUG */ +- +-#else +- +-extern int journal_recover (journal_t *journal); +-extern int journal_skip_recovery (journal_t *); +- +-/* Primary revoke support */ +-extern int journal_init_revoke(journal_t *, int); +-extern void journal_destroy_revoke_caches(void); +-extern int journal_init_revoke_caches(void); +- +-/* Recovery revoke support */ +-extern int journal_set_revoke(journal_t *, unsigned long, tid_t); +-extern int journal_test_revoke(journal_t *, unsigned long, tid_t); +-extern void journal_clear_revoke(journal_t *); +-extern void journal_brelse_array(struct buffer_head *b[], int n); +- +-extern void journal_destroy_revoke(journal_t *); +-#endif /* __KERNEL__ */ ++#undef _INLINE_ ++#endif + + static inline int tid_gt(tid_t x, tid_t y) EXT2FS_ATTR((unused)); + static inline int tid_geq(tid_t x, tid_t y) EXT2FS_ATTR((unused)); +@@ -875,82 +351,4 @@ + + extern int jbd_blocks_per_page(struct inode *inode); + +-#ifdef __KERNEL__ +- +-extern spinlock_t jh_splice_lock; +-/* +- * Once `expr1' has been found true, take jh_splice_lock +- * and then reevaluate everything. +- */ +-#define SPLICE_LOCK(expr1, expr2) \ +- ({ \ +- int ret = (expr1); \ +- if (ret) { \ +- spin_lock(&jh_splice_lock); \ +- ret = (expr1) && (expr2); \ +- spin_unlock(&jh_splice_lock); \ +- } \ +- ret; \ +- }) +- +-/* +- * A number of buffer state predicates. They test for +- * buffer_jbd() because they are used in core kernel code. +- * +- * These will be racy on SMP unless we're *sure* that the +- * buffer won't be detached from the journalling system +- * in parallel. +- */ +- +-/* Return true if the buffer is on journal list `list' */ +-static inline int buffer_jlist_eq(struct buffer_head *bh, int list) +-{ +- return SPLICE_LOCK(buffer_jbd(bh), bh2jh(bh)->b_jlist == list); +-} +- +-/* Return true if this bufer is dirty wrt the journal */ +-static inline int buffer_jdirty(struct buffer_head *bh) +-{ +- return buffer_jbd(bh) && __buffer_state(bh, JBDDirty); +-} +- +-/* Return true if it's a data buffer which journalling is managing */ +-static inline int buffer_jbd_data(struct buffer_head *bh) +-{ +- return SPLICE_LOCK(buffer_jbd(bh), +- bh2jh(bh)->b_jlist == BJ_SyncData || +- bh2jh(bh)->b_jlist == BJ_AsyncData); +-} +- +-#ifdef CONFIG_SMP +-#define assert_spin_locked(lock) J_ASSERT(spin_is_locked(lock)) +-#else +-#define assert_spin_locked(lock) do {} while(0) +-#endif +- +-#define buffer_trace_init(bh) do {} while (0) +-#define print_buffer_fields(bh) do {} while (0) +-#define print_buffer_trace(bh) do {} while (0) +-#define BUFFER_TRACE(bh, info) do {} while (0) +-#define BUFFER_TRACE2(bh, bh2, info) do {} while (0) +-#define JBUFFER_TRACE(jh, info) do {} while (0) +- +-#endif /* __KERNEL__ */ +- +-#endif /* CONFIG_JBD || CONFIG_JBD_MODULE || !__KERNEL__ */ +- +-/* +- * Compatibility no-ops which allow the kernel to compile without CONFIG_JBD +- * go here. +- */ +- +-#if defined(__KERNEL__) && !(defined(CONFIG_JBD) || defined(CONFIG_JBD_MODULE)) +- +-#define J_ASSERT(expr) do {} while (0) +-#define J_ASSERT_BH(bh, expr) do {} while (0) +-#define buffer_jbd(bh) 0 +-#define buffer_jlist_eq(bh, val) 0 +-#define journal_buffer_journal_lru(bh) 0 +- +-#endif /* defined(__KERNEL__) && !defined(CONFIG_JBD) */ + #endif /* _LINUX_JBD_H */ +--- a/lib/ext2fs/link.c ++++ b/lib/ext2fs/link.c +@@ -41,6 +41,8 @@ + 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 @@ + 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 @@ + } + + /* ++ * 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 @@ + 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 @@ + 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 @@ + 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) +--- a/lib/ext2fs/llseek.c ++++ b/lib/ext2fs/llseek.c +@@ -9,8 +9,12 @@ + * %End-Header% + */ + ++#ifndef _LARGEFILE_SOURCE + #define _LARGEFILE_SOURCE ++#endif ++#ifndef _LARGEFILE64_SOURCE + #define _LARGEFILE64_SOURCE ++#endif + + #include "config.h" + #if HAVE_SYS_TYPES_H +--- a/lib/ext2fs/lookup.c ++++ b/lib/ext2fs/lookup.c +@@ -37,9 +37,9 @@ + { + 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++; +--- a/lib/ext2fs/Makefile.in ++++ b/lib/ext2fs/Makefile.in +@@ -4,7 +4,10 @@ + top_builddir = ../.. + my_dir = lib/ext2fs + INSTALL = @INSTALL@ +-DEPEND_CFLAGS = -I$(top_srcdir)/debugfs ++DEPEND_CFLAGS = -I$(top_srcdir)/debugfs -I$(srcdir)/../../e2fsck -DDEBUGFS ++# This nastyness is needed because of jfs_user.h hackery; when we finally ++# clean up this mess, we should be able to drop it ++DEBUGFS_CFLAGS = -I$(srcdir)/../../e2fsck $(ALL_CFLAGS) -DDEBUGFS + + @MCONFIG@ + +@@ -19,7 +22,8 @@ + 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 journal.o \ ++ revoke.o recovery.o do_journal.o + + DEBUG_SRCS= debug_cmds.c extent_cmds.c tst_cmds.c \ + $(top_srcdir)/debugfs/debugfs.c \ +@@ -37,7 +41,13 @@ + $(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 \ ++ $(top_srcdir)/debugfs/journal.c \ ++ $(top_srcdir)/e2fsck/revoke.c \ ++ $(top_srcdir)/e2fsck/recovery.c \ ++ $(top_srcdir)/debugfs/do_journal.c + + OBJS= $(DEBUGFS_LIB_OBJS) $(RESIZE_LIB_OBJS) $(E2IMAGE_LIB_OBJS) \ + $(TEST_IO_LIB_OBJS) \ +@@ -46,6 +56,7 @@ + alloc_sb.o \ + alloc_stats.o \ + alloc_tables.o \ ++ atexit.o \ + badblocks.o \ + bb_inode.o \ + bitmaps.o \ +@@ -68,12 +79,14 @@ + expanddir.o \ + ext_attr.o \ + extent.o \ ++ fallocate.o \ + fileio.o \ + finddev.o \ + flushb.o \ + freefs.o \ + gen_bitmap.o \ + gen_bitmap64.o \ ++ get_num_dirs.o \ + get_pathname.o \ + getsize.o \ + getsectsize.o \ +@@ -82,6 +95,7 @@ + ind_block.o \ + initialize.o \ + inline.o \ ++ inline_data.o \ + inode.o \ + io_manager.o \ + ismounted.o \ +@@ -102,6 +116,7 @@ + read_bb_file.o \ + res_gdt.o \ + rw_bitmaps.o \ ++ sha512.o \ + swapfs.o \ + symlink.o \ + tdb.o \ +@@ -117,6 +132,7 @@ + $(srcdir)/alloc_sb.c \ + $(srcdir)/alloc_stats.c \ + $(srcdir)/alloc_tables.c \ ++ $(srcdir)/atexit.c \ + $(srcdir)/badblocks.c \ + $(srcdir)/bb_compat.c \ + $(srcdir)/bb_inode.c \ +@@ -134,6 +150,7 @@ + $(srcdir)/csum.c \ + $(srcdir)/dblist.c \ + $(srcdir)/dblist_dir.c \ ++ $(srcdir)/digest_encode.c \ + $(srcdir)/dirblock.c \ + $(srcdir)/dirhash.c \ + $(srcdir)/dir_iterate.c \ +@@ -147,6 +164,7 @@ + $(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 +173,7 @@ + $(srcdir)/ind_block.c \ + $(srcdir)/initialize.c \ + $(srcdir)/inline.c \ ++ $(srcdir)/inline_data.c \ + $(srcdir)/inode.c \ + $(srcdir)/inode_io.c \ + $(srcdir)/imager.c \ +@@ -177,6 +196,8 @@ + $(srcdir)/read_bb_file.c \ + $(srcdir)/res_gdt.c \ + $(srcdir)/rw_bitmaps.c \ ++ $(srcdir)/sha256.c \ ++ $(srcdir)/sha512.c \ + $(srcdir)/swapfs.c \ + $(srcdir)/symlink.c \ + $(srcdir)/tdb.c \ +@@ -226,6 +247,7 @@ + $(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 $< +@@ -251,6 +273,11 @@ + $(Q) $(CC) -o tst_badblocks tst_badblocks.o $(ALL_LDFLAGS) \ + $(STATIC_LIBEXT2FS) $(STATIC_LIBCOM_ERR) $(SYSLIBS) + ++tst_digest_encode: $(srcdir)/digest_encode.c $(srcdir)/ext2_fs.h ++ $(E) " CC $@" ++ $(Q) $(CC) $(ALL_LDFLAGS) $(ALL_CFLAGS) -o tst_digest_encode \ ++ $(srcdir)/digest_encode.c -DUNITTEST $(SYSLIBS) ++ + tst_icount: $(srcdir)/icount.c $(STATIC_LIBEXT2FS) $(DEPSTATIC_LIBCOM_ERR) + $(E) " LD $@" + $(Q) $(CC) -o tst_icount $(srcdir)/icount.c -DDEBUG \ +@@ -313,6 +340,16 @@ + $(E) " LD $@" + $(Q) $(CC) -o tst_inode_size tst_inode_size.o $(ALL_LDFLAGS) $(SYSLIBS) + ++tst_sha256: $(srcdir)/sha256.c $(srcdir)/ext2_fs.h ++ $(E) " CC $@" ++ $(Q) $(CC) $(ALL_LDFLAGS) $(ALL_CFLAGS) -o tst_sha256 \ ++ $(srcdir)/sha256.c -DUNITTEST $(SYSLIBS) ++ ++tst_sha512: $(srcdir)/sha512.c $(srcdir)/ext2_fs.h ++ $(E) " CC $@" ++ $(Q) $(CC) $(ALL_LDFLAGS) $(ALL_CFLAGS) -o tst_sha512 \ ++ $(srcdir)/sha512.c -DUNITTEST $(SYSLIBS) ++ + ext2_tdbtool: tdbtool.o + $(E) " LD $@" + $(Q) $(CC) -o ext2_tdbtool tdbtool.o tdb.o $(ALL_LDFLAGS) $(SYSLIBS) +@@ -331,64 +368,88 @@ + + debugfs.o: $(top_srcdir)/debugfs/debugfs.c + $(E) " CC $<" +- $(Q) $(CC) $(ALL_CFLAGS) -c $< -o $@ ++ $(Q) $(CC) $(DEBUGFS_CFLAGS) -c $< -o $@ + + extent_inode.o: $(top_srcdir)/debugfs/extent_inode.c + $(E) " CC $<" +- $(Q) $(CC) $(ALL_CFLAGS) -c $< -o $@ ++ $(Q) $(CC) $(DEBUGFS_CFLAGS) -c $< -o $@ + + util.o: $(top_srcdir)/debugfs/util.c + $(E) " CC $<" +- $(Q) $(CC) $(ALL_CFLAGS) -c $< -o $@ ++ $(Q) $(CC) $(DEBUGFS_CFLAGS) -c $< -o $@ + + ncheck.o: $(top_srcdir)/debugfs/ncheck.c + $(E) " CC $<" +- $(Q) $(CC) $(ALL_CFLAGS) -c $< -o $@ ++ $(Q) $(CC) $(DEBUGFS_CFLAGS) -c $< -o $@ + + icheck.o: $(top_srcdir)/debugfs/icheck.c + $(E) " CC $<" +- $(Q) $(CC) $(ALL_CFLAGS) -c $< -o $@ ++ $(Q) $(CC) $(DEBUGFS_CFLAGS) -c $< -o $@ + + ls.o: $(top_srcdir)/debugfs/ls.c + $(E) " CC $<" +- $(Q) $(CC) $(ALL_CFLAGS) -c $< -o $@ ++ $(Q) $(CC) $(DEBUGFS_CFLAGS) -c $< -o $@ + + lsdel.o: $(top_srcdir)/debugfs/lsdel.c + $(E) " CC $<" +- $(Q) $(CC) $(ALL_CFLAGS) -c $< -o $@ ++ $(Q) $(CC) $(DEBUGFS_CFLAGS) -c $< -o $@ + + dump.o: $(top_srcdir)/debugfs/dump.c + $(E) " CC $<" +- $(Q) $(CC) $(ALL_CFLAGS) -c $< -o $@ ++ $(Q) $(CC) $(DEBUGFS_CFLAGS) -c $< -o $@ + + set_fields.o: $(top_srcdir)/debugfs/set_fields.c + $(E) " CC $<" +- $(Q) $(CC) $(ALL_CFLAGS) -c $< -o $@ ++ $(Q) $(CC) $(DEBUGFS_CFLAGS) -c $< -o $@ + + logdump.o: $(top_srcdir)/debugfs/logdump.c + $(E) " CC $<" +- $(Q) $(CC) $(ALL_CFLAGS) -c $< -o $@ ++ $(Q) $(CC) $(DEBUGFS_CFLAGS) -c $< -o $@ + + htree.o: $(top_srcdir)/debugfs/htree.c + $(E) " CC $<" +- $(Q) $(CC) $(ALL_CFLAGS) -c $< -o $@ ++ $(Q) $(CC) $(DEBUGFS_CFLAGS) -c $< -o $@ + + unused.o: $(top_srcdir)/debugfs/unused.c + $(E) " CC $<" +- $(Q) $(CC) $(ALL_CFLAGS) -c $< -o $@ ++ $(Q) $(CC) $(DEBUGFS_CFLAGS) -c $< -o $@ + + zap.o: $(top_srcdir)/debugfs/zap.c + $(E) " CC $<" +- $(Q) $(CC) $(ALL_CFLAGS) -c $< -o $@ ++ $(Q) $(CC) $(DEBUGFS_CFLAGS) -c $< -o $@ + + quota.o: $(top_srcdir)/debugfs/quota.c + $(E) " CC $<" +- $(Q) $(CC) $(ALL_CFLAGS) -c $< -o $@ ++ $(Q) $(CC) $(DEBUGFS_CFLAGS) -c $< -o $@ ++ ++journal.o: $(top_srcdir)/debugfs/journal.c ++ $(E) " CC $<" ++ $(Q) $(CC) $(DEBUGFS_CFLAGS) -c $< -o $@ ++ ++revoke.o: $(top_srcdir)/e2fsck/revoke.c ++ $(E) " CC $<" ++ $(Q) $(CC) $(DEBUGFS_CFLAGS) -c $< -o $@ ++ ++recovery.o: $(top_srcdir)/e2fsck/recovery.c ++ $(E) " CC $<" ++ $(Q) $(CC) $(DEBUGFS_CFLAGS) -c $< -o $@ ++ ++do_journal.o: $(top_srcdir)/debugfs/do_journal.c ++ $(E) " CC $<" ++ $(Q) $(CC) $(DEBUGFS_CFLAGS) -c $< -o $@ ++ ++xattrs.o: $(top_srcdir)/debugfs/xattrs.c ++ $(E) " CC $<" ++ $(Q) $(CC) $(DEBUGFS_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 $@ +@@ -411,21 +472,21 @@ + + tst_extents: $(srcdir)/extent.c $(DEBUG_OBJS) $(DEPSTATIC_LIBSS) libext2fs.a \ + $(STATIC_LIBE2P) $(DEPLIBUUID) $(DEPLIBBLKID) $(DEPSTATIC_LIBCOM_ERR) \ +- $(DEPLIBQUOTA) ++ $(DEPLIBSUPPORT) + $(E) " LD $@" + $(Q) $(CC) -o tst_extents $(srcdir)/extent.c \ + $(ALL_CFLAGS) $(ALL_LDFLAGS) -DDEBUG $(DEBUG_OBJS) \ +- $(STATIC_LIBSS) $(STATIC_LIBE2P) $(LIBQUOTA) \ ++ $(STATIC_LIBSS) $(STATIC_LIBE2P) $(LIBSUPPORT) \ + $(STATIC_LIBEXT2FS) $(LIBBLKID) $(LIBUUID) \ + $(STATIC_LIBCOM_ERR) $(SYSLIBS) -I $(top_srcdir)/debugfs + + tst_libext2fs: $(DEBUG_OBJS) \ + $(DEPSTATIC_LIBSS) $(STATIC_LIBE2P) $(DEPLIBUUID) libext2fs.a \ +- $(DEPLIBBLKID) $(DEPSTATIC_LIBCOM_ERR) $(DEPLIBQUOTA) ++ $(DEPLIBBLKID) $(DEPSTATIC_LIBCOM_ERR) $(DEPLIBSUPPORT) + $(E) " LD $@" + $(Q) $(CC) -o tst_libext2fs $(ALL_LDFLAGS) -DDEBUG $(DEBUG_OBJS) \ +- $(STATIC_LIBSS) $(STATIC_LIBE2P) $(LIBQUOTA) \ +- $(STATIC_LIBEXT2FS) $(LIBBLKID) $(LIBUUID) \ ++ $(STATIC_LIBSS) $(STATIC_LIBE2P) $(LIBSUPPORT) \ ++ $(STATIC_LIBEXT2FS) $(LIBBLKID) $(LIBUUID) $(LIBMAGIC) \ + $(STATIC_LIBCOM_ERR) $(SYSLIBS) -I $(top_srcdir)/debugfs + + tst_inline: $(srcdir)/inline.c $(STATIC_LIBEXT2FS) $(DEPSTATIC_LIBCOM_ERR) +@@ -434,6 +495,11 @@ + $(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) $(SYSLIBS) ++ + tst_csum: csum.c $(STATIC_LIBEXT2FS) $(DEPSTATIC_LIBCOM_ERR) $(STATIC_LIBE2P) \ + $(top_srcdir)/lib/e2p/e2p.h + $(E) " LD $@" +@@ -453,7 +519,8 @@ + + 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 tst_sha256 tst_sha512 \ ++ tst_digest_encode + $(TESTENV) ./tst_bitops + $(TESTENV) ./tst_badblocks + $(TESTENV) ./tst_iscan +@@ -463,7 +530,10 @@ + $(TESTENV) ./tst_inode_size + $(TESTENV) ./tst_csum + $(TESTENV) ./tst_inline ++ $(TESTENV) ./tst_inline_data + $(TESTENV) ./tst_crc32c ++ $(TESTENV) ./tst_sha256 ++ $(TESTENV) ./tst_sha512 + $(TESTENV) ./tst_bitmaps -f $(srcdir)/tst_bitmaps_cmds > tst_bitmaps_out + diff $(srcdir)/tst_bitmaps_exp tst_bitmaps_out + $(TESTENV) ./tst_bitmaps -t 2 -f $(srcdir)/tst_bitmaps_cmds > tst_bitmaps_out +@@ -472,6 +542,7 @@ + diff $(srcdir)/tst_bitmaps_exp tst_bitmaps_out + $(TESTENV) ./tst_bitmaps -l -f $(srcdir)/tst_bitmaps_cmds > tst_bitmaps_out + diff $(srcdir)/tst_bitmaps_exp tst_bitmaps_out ++ $(TESTENV) ./tst_digest_encode + + installdirs:: + $(E) " MKINSTALLDIRS $(libdir) $(includedir)/ext2fs" +@@ -506,6 +577,7 @@ + tst_bitops tst_types tst_icount tst_super_size tst_csum \ + tst_bitmaps tst_bitmaps_out tst_extents tst_inline \ + tst_inline_data tst_inode_size tst_bitmaps_cmd.c \ ++ tst_digest_encode tst_sha256 tst_sha512 \ + ext2_tdbtool mkjournal debug_cmds.c tst_cmds.c extent_cmds.c \ + ../libext2fs.a ../libext2fs_p.a ../libext2fs_chk.a \ + crc32c_table.h gen_crc32ctable tst_crc32c tst_libext2fs \ +@@ -565,6 +637,12 @@ + $(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 ++atexit.o: $(srcdir)/atexit.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)/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 + badblocks.o: $(srcdir)/badblocks.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 \ +@@ -667,6 +745,12 @@ + $(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 ++digest_encode.o: $(srcdir)/digest_encode.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 \ ++ $(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 + dirblock.o: $(srcdir)/dirblock.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 \ +@@ -698,7 +782,7 @@ + $(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 \ +@@ -752,6 +836,13 @@ + $(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 \ +@@ -800,6 +891,13 @@ + $(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 \ +@@ -851,15 +949,15 @@ + $(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 \ + $(srcdir)/ext2_fs.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 $(srcdir)/jfs_user.h $(srcdir)/kernel-jbd.h \ +- $(srcdir)/jfs_compat.h $(srcdir)/kernel-list.h ++ $(srcdir)/bitops.h $(srcdir)/kernel-jbd.h $(srcdir)/jfs_compat.h \ ++ $(srcdir)/kernel-list.h + mmp.o: $(srcdir)/mmp.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 \ +@@ -901,7 +999,7 @@ + $(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 \ +@@ -932,6 +1030,18 @@ + $(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)/e2image.h ++sha256.o: $(srcdir)/sha256.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 \ ++ $(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 ++sha512.o: $(srcdir)/sha512.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 \ ++ $(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 + swapfs.o: $(srcdir)/swapfs.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 \ +@@ -983,11 +1093,11 @@ + $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \ + $(srcdir)/ext2_ext_attr.h $(srcdir)/bitops.h + undo_io.o: $(srcdir)/undo_io.c $(top_builddir)/lib/config.h \ +- $(top_builddir)/lib/dirpaths.h $(srcdir)/tdb.h $(srcdir)/ext2_fs.h \ ++ $(top_builddir)/lib/dirpaths.h $(srcdir)/ext2_fs.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 + unix_io.o: $(srcdir)/unix_io.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 \ +@@ -1027,8 +1137,9 @@ + $(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)/lib/support/quotaio.h $(top_srcdir)/lib/support/dqblk_v2.h \ ++ $(top_srcdir)/lib/support/quotaio_tree.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 \ +@@ -1042,11 +1153,13 @@ + $(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 \ +- $(top_srcdir)/debugfs/../version.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)/lib/support/quotaio.h \ ++ $(top_srcdir)/lib/support/dqblk_v2.h \ ++ $(top_srcdir)/lib/support/quotaio_tree.h $(top_srcdir)/debugfs/../version.h \ ++ $(srcdir)/../../e2fsck/jfs_user.h $(srcdir)/kernel-jbd.h \ ++ $(srcdir)/jfs_compat.h $(srcdir)/kernel-list.h \ ++ $(top_srcdir)/lib/support/plausible.h + util.o: $(top_srcdir)/debugfs/util.c $(top_builddir)/lib/config.h \ + $(top_builddir)/lib/dirpaths.h $(top_srcdir)/lib/ss/ss.h \ + $(top_builddir)/lib/ss/ss_err.h $(top_srcdir)/lib/et/com_err.h \ +@@ -1054,9 +1167,10 @@ + $(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)/lib/support/quotaio.h \ ++ $(top_srcdir)/lib/support/dqblk_v2.h \ ++ $(top_srcdir)/lib/support/quotaio_tree.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 \ +@@ -1064,9 +1178,10 @@ + $(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)/lib/support/quotaio.h \ ++ $(top_srcdir)/lib/support/dqblk_v2.h \ ++ $(top_srcdir)/lib/support/quotaio_tree.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 \ +@@ -1074,9 +1189,10 @@ + $(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)/lib/support/quotaio.h \ ++ $(top_srcdir)/lib/support/dqblk_v2.h \ ++ $(top_srcdir)/lib/support/quotaio_tree.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 \ +@@ -1084,9 +1200,10 @@ + $(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)/lib/support/quotaio.h \ ++ $(top_srcdir)/lib/support/dqblk_v2.h \ ++ $(top_srcdir)/lib/support/quotaio_tree.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 \ +@@ -1094,9 +1211,10 @@ + $(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)/lib/support/quotaio.h \ ++ $(top_srcdir)/lib/support/dqblk_v2.h \ ++ $(top_srcdir)/lib/support/quotaio_tree.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 \ +@@ -1104,9 +1222,10 @@ + $(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)/lib/support/quotaio.h \ ++ $(top_srcdir)/lib/support/dqblk_v2.h \ ++ $(top_srcdir)/lib/support/quotaio_tree.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 \ +@@ -1114,9 +1233,10 @@ + $(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)/lib/support/quotaio.h \ ++ $(top_srcdir)/lib/support/dqblk_v2.h \ ++ $(top_srcdir)/lib/support/quotaio_tree.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 \ +@@ -1124,9 +1244,10 @@ + $(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)/bitops.h $(top_srcdir)/debugfs/../misc/create_inode.h \ ++ $(top_srcdir)/lib/e2p/e2p.h $(top_srcdir)/lib/support/quotaio.h \ ++ $(top_srcdir)/lib/support/dqblk_v2.h \ ++ $(top_srcdir)/lib/support/quotaio_tree.h $(srcdir)/../../e2fsck/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 \ +@@ -1135,9 +1256,10 @@ + $(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)/lib/support/quotaio.h \ ++ $(top_srcdir)/lib/support/dqblk_v2.h \ ++ $(top_srcdir)/lib/support/quotaio_tree.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 \ +@@ -1145,9 +1267,10 @@ + $(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)/lib/support/quotaio.h \ ++ $(top_srcdir)/lib/support/dqblk_v2.h \ ++ $(top_srcdir)/lib/support/quotaio_tree.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 \ +@@ -1155,9 +1278,10 @@ + $(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)/lib/support/quotaio.h \ ++ $(top_srcdir)/lib/support/dqblk_v2.h \ ++ $(top_srcdir)/lib/support/quotaio_tree.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 \ +@@ -1165,9 +1289,10 @@ + $(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)/lib/support/quotaio.h \ ++ $(top_srcdir)/lib/support/dqblk_v2.h \ ++ $(top_srcdir)/lib/support/quotaio_tree.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 \ +@@ -1175,9 +1300,10 @@ + $(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)/lib/support/quotaio.h \ ++ $(top_srcdir)/lib/support/dqblk_v2.h \ ++ $(top_srcdir)/lib/support/quotaio_tree.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 \ +@@ -1185,12 +1311,68 @@ + $(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)/lib/support/quotaio.h \ ++ $(top_srcdir)/lib/support/dqblk_v2.h \ ++ $(top_srcdir)/lib/support/quotaio_tree.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)/lib/support/quotaio.h \ ++ $(top_srcdir)/lib/support/dqblk_v2.h \ ++ $(top_srcdir)/lib/support/quotaio_tree.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 ++ $(srcdir)/bitops.h $(top_srcdir)/misc/e2freefrag.h \ ++ $(top_srcdir)/debugfs/debugfs.h $(top_srcdir)/lib/ss/ss.h \ ++ $(top_builddir)/lib/ss/ss_err.h $(top_srcdir)/debugfs/../misc/create_inode.h \ ++ $(top_srcdir)/lib/e2p/e2p.h $(top_srcdir)/lib/support/quotaio.h \ ++ $(top_srcdir)/lib/support/dqblk_v2.h \ ++ $(top_srcdir)/lib/support/quotaio_tree.h ++create_inode.o: $(top_srcdir)/misc/create_inode.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 $(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)/fiemap.h \ ++ $(top_srcdir)/misc/create_inode.h $(top_srcdir)/lib/e2p/e2p.h \ ++ $(top_srcdir)/lib/support/nls-enable.h ++journal.o: $(top_srcdir)/debugfs/journal.c $(top_builddir)/lib/config.h \ ++ $(top_builddir)/lib/dirpaths.h $(srcdir)/../../e2fsck/jfs_user.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 $(srcdir)/kernel-jbd.h \ ++ $(srcdir)/jfs_compat.h $(srcdir)/kernel-list.h ++revoke.o: $(top_srcdir)/e2fsck/revoke.c $(top_srcdir)/e2fsck/jfs_user.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 $(srcdir)/kernel-jbd.h \ ++ $(srcdir)/jfs_compat.h $(srcdir)/kernel-list.h ++recovery.o: $(top_srcdir)/e2fsck/recovery.c $(top_srcdir)/e2fsck/jfs_user.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 $(srcdir)/kernel-jbd.h \ ++ $(srcdir)/jfs_compat.h $(srcdir)/kernel-list.h ++do_journal.o: $(top_srcdir)/debugfs/do_journal.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)/lib/support/quotaio.h \ ++ $(top_srcdir)/lib/support/dqblk_v2.h \ ++ $(top_srcdir)/lib/support/quotaio_tree.h $(srcdir)/../../e2fsck/jfs_user.h \ ++ $(srcdir)/kernel-jbd.h $(srcdir)/jfs_compat.h $(srcdir)/kernel-list.h +--- /dev/null ++++ b/lib/ext2fs/Makefile.pq +@@ -0,0 +1,50 @@ ++TOPSRC=..\.. ++LIBNAME=EXT2.LIB ++OBJFILE=EXT2.LST ++ ++OBJS= alloc.obj \ ++ alloc_tables.obj \ ++ badblocks.obj \ ++ bb_compat.obj \ ++ bb_inode.obj \ ++ bitmaps.obj \ ++ bitops.obj \ ++ block.obj \ ++ bmap.obj \ ++ bmove.obj \ ++ check_desc.obj \ ++ closefs.obj \ ++ cmp_bitmaps.obj \ ++ dblist.obj \ ++ dblist_dir.obj \ ++ dirblock.obj \ ++ dir_iterate.obj \ ++ dupfs.obj \ ++ expanddir.obj \ ++ fileio.obj \ ++ freefs.obj \ ++ get_pathname.obj \ ++ icount.obj \ ++ initialize.obj \ ++ inline.obj \ ++ inline_data.obj \ ++ inode.obj \ ++ ismounted.obj \ ++ link.obj \ ++ lookup.obj \ ++ mkdir.obj \ ++ namei.obj \ ++ native.obj \ ++ newdir.obj \ ++ openfs.obj \ ++ read_bb.obj \ ++ read_bb_file.obj \ ++ rs_bitmap.obj \ ++ rw_bitmaps.obj \ ++ swapfs.obj \ ++ unlink.obj \ ++ valid_blk.obj \ ++ version.obj ++ ++!include $(TOPSRC)\powerquest\MCONFIG ++ +--- a/lib/ext2fs/mkdir.c ++++ b/lib/ext2fs/mkdir.c +@@ -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 @@ + 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,24 @@ + /* + * Allocate a data block for the directory + */ +- retval = ext2fs_new_block2(fs, 0, 0, &blk); +- if (retval) +- goto cleanup; ++ memset(&inode, 0, sizeof(struct ext2_inode)); ++ if (!inline_data) { ++ retval = ext2fs_new_block2(fs, ext2fs_find_inode_goal(fs, ino, ++ &inode, ++ 0), ++ NULL, &blk); ++ if (retval) ++ goto cleanup; ++ } + + /* + * Create a scratch template for the directory + */ +- retval = ext2fs_new_dir_block(fs, ino, parent, &block); ++ 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 +102,48 @@ + /* + * 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 +168,10 @@ + * 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 +181,8 @@ + /* + * 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: +--- a/lib/ext2fs/mkjournal.c ++++ b/lib/ext2fs/mkjournal.c +@@ -36,7 +36,8 @@ + #include "ext2_fs.h" + #include "e2p/e2p.h" + #include "ext2fs.h" +-#include "jfs_user.h" ++ ++#include "kernel-jbd.h" + + /* + * This function automatically sets up the journal superblock and +@@ -148,12 +149,13 @@ + * attempt to free the static zeroizing buffer. (This is to keep + * programs that check for memory leaks happy.) + */ +-#define STRIDE_LENGTH 8 ++#define MAX_STRIDE_LENGTH (4194304 / (int) fs->blocksize) + errcode_t ext2fs_zero_blocks2(ext2_filsys fs, blk64_t blk, int num, + blk64_t *ret_blk, int *ret_count) + { + int j, count; +- static char *buf; ++ static void *buf; ++ static int stride_length; + errcode_t retval; + + /* If fs is null, clean up the static buffer and return */ +@@ -164,24 +166,41 @@ + } + return 0; + } ++ ++ /* Deal with zeroing less than 1 block */ ++ if (num <= 0) ++ return 0; ++ ++ /* Try a zero out command, if supported */ ++ retval = io_channel_zeroout(fs->io, blk, num); ++ if (retval == 0) ++ return 0; ++ + /* Allocate the zeroizing buffer if necessary */ +- if (!buf) { +- buf = malloc(fs->blocksize * STRIDE_LENGTH); +- if (!buf) +- return ENOMEM; +- memset(buf, 0, fs->blocksize * STRIDE_LENGTH); ++ if (num > stride_length && stride_length < MAX_STRIDE_LENGTH) { ++ void *p; ++ int new_stride = num; ++ ++ if (new_stride > MAX_STRIDE_LENGTH) ++ new_stride = MAX_STRIDE_LENGTH; ++ p = realloc(buf, fs->blocksize * new_stride); ++ if (!p) ++ return EXT2_ET_NO_MEMORY; ++ buf = p; ++ stride_length = new_stride; ++ memset(buf, 0, fs->blocksize * stride_length); + } + /* OK, do the write loop */ + j=0; + while (j < num) { +- if (blk % STRIDE_LENGTH) { +- count = STRIDE_LENGTH - (blk % STRIDE_LENGTH); ++ if (blk % stride_length) { ++ count = stride_length - (blk % stride_length); + if (count > (num - j)) + count = num - j; + } else { + count = num - j; +- if (count > STRIDE_LENGTH) +- count = STRIDE_LENGTH; ++ if (count > stride_length) ++ count = stride_length; + } + retval = io_channel_write_blk64(fs->io, blk, count, buf); + if (retval) { +@@ -209,89 +228,6 @@ + } + + /* +- * Helper function for creating the journal using direct I/O routines +- */ +-struct mkjournal_struct { +- int num_blocks; +- int newblocks; +- blk64_t goal; +- blk64_t blk_to_zero; +- int zero_count; +- int flags; +- char *buf; +- errcode_t err; +-}; +- +-static int mkjournal_proc(ext2_filsys fs, +- blk64_t *blocknr, +- e2_blkcnt_t blockcnt, +- blk64_t ref_block EXT2FS_ATTR((unused)), +- int ref_offset EXT2FS_ATTR((unused)), +- void *priv_data) +-{ +- struct mkjournal_struct *es = (struct mkjournal_struct *) priv_data; +- blk64_t new_blk; +- errcode_t retval; +- +- if (*blocknr) { +- es->goal = *blocknr; +- return 0; +- } +- if (blockcnt && +- (EXT2FS_B2C(fs, es->goal) == EXT2FS_B2C(fs, es->goal+1))) +- new_blk = es->goal+1; +- else { +- es->goal &= ~EXT2FS_CLUSTER_MASK(fs); +- retval = ext2fs_new_block2(fs, es->goal, 0, &new_blk); +- if (retval) { +- es->err = retval; +- return BLOCK_ABORT; +- } +- ext2fs_block_alloc_stats2(fs, new_blk, +1); +- es->newblocks++; +- } +- if (blockcnt >= 0) +- es->num_blocks--; +- +- retval = 0; +- if (blockcnt <= 0) +- retval = io_channel_write_blk64(fs->io, new_blk, 1, es->buf); +- else if (!(es->flags & EXT2_MKJOURNAL_LAZYINIT)) { +- if (es->zero_count) { +- if ((es->blk_to_zero + es->zero_count == new_blk) && +- (es->zero_count < 1024)) +- es->zero_count++; +- else { +- retval = ext2fs_zero_blocks2(fs, +- es->blk_to_zero, +- es->zero_count, +- 0, 0); +- es->zero_count = 0; +- } +- } +- if (es->zero_count == 0) { +- es->blk_to_zero = new_blk; +- es->zero_count = 1; +- } +- } +- +- if (blockcnt == 0) +- memset(es->buf, 0, fs->blocksize); +- +- if (retval) { +- es->err = retval; +- return BLOCK_ABORT; +- } +- *blocknr = es->goal = new_blk; +- +- if (es->num_blocks == 0) +- return (BLOCK_CHANGED | BLOCK_ABORT); +- else +- return BLOCK_CHANGED; +- +-} +- +-/* + * Calculate the initial goal block to be roughly at the middle of the + * filesystem. Pick a group that has the largest number of free + * blocks. +@@ -332,7 +268,8 @@ + errcode_t retval; + struct ext2_inode inode; + unsigned long long inode_size; +- struct mkjournal_struct es; ++ int falloc_flags = EXT2_FALLOCATE_FORCE_INIT; ++ blk64_t zblk; + + if ((retval = ext2fs_create_journal_superblock(fs, num_blocks, flags, + &buf))) +@@ -349,48 +286,38 @@ + goto out2; + } + +- es.num_blocks = num_blocks; +- es.newblocks = 0; +- es.buf = buf; +- es.err = 0; +- es.flags = flags; +- es.zero_count = 0; +- es.goal = (goal != ~0ULL) ? goal : get_midpoint_journal_block(fs); ++ if (goal == ~0ULL) ++ goal = get_midpoint_journal_block(fs); + +- if (fs->super->s_feature_incompat & EXT3_FEATURE_INCOMPAT_EXTENTS) { ++ if (fs->super->s_feature_incompat & EXT3_FEATURE_INCOMPAT_EXTENTS) + inode.i_flags |= EXT4_EXTENTS_FL; +- if ((retval = ext2fs_write_inode(fs, journal_ino, &inode))) +- goto out2; +- } + +- retval = ext2fs_block_iterate3(fs, journal_ino, BLOCK_FLAG_APPEND, +- 0, mkjournal_proc, &es); +- if (es.err) { +- retval = es.err; +- goto errout; +- } +- if (es.zero_count) { +- retval = ext2fs_zero_blocks2(fs, es.blk_to_zero, +- es.zero_count, 0, 0); +- if (retval) +- goto errout; +- } +- +- if ((retval = ext2fs_read_inode(fs, journal_ino, &inode))) +- goto errout; ++ if (!(flags & EXT2_MKJOURNAL_LAZYINIT)) ++ falloc_flags |= EXT2_FALLOCATE_ZERO_BLOCKS; + + inode_size = (unsigned long long)fs->blocksize * num_blocks; +- ext2fs_iblk_add_blocks(fs, &inode, es.newblocks); + inode.i_mtime = inode.i_ctime = fs->now ? fs->now : time(0); + inode.i_links_count = 1; + inode.i_mode = LINUX_S_IFREG | 0600; + retval = ext2fs_inode_size_set(fs, &inode, inode_size); + if (retval) +- goto errout; ++ goto out2; ++ ++ retval = ext2fs_fallocate(fs, falloc_flags, journal_ino, ++ &inode, goal, 0, num_blocks); ++ if (retval) ++ goto out2; + + if ((retval = ext2fs_write_new_inode(fs, journal_ino, &inode))) +- goto errout; +- retval = 0; ++ goto out2; ++ ++ retval = ext2fs_bmap2(fs, journal_ino, &inode, NULL, 0, 0, NULL, &zblk); ++ if (retval) ++ goto out2; ++ ++ retval = io_channel_write_blk64(fs->io, zblk, 1, buf); ++ if (retval) ++ goto out2; + + memcpy(fs->super->s_jnl_blocks, inode.i_block, EXT2_N_BLOCKS*4); + fs->super->s_jnl_blocks[15] = inode.i_size_high; +@@ -398,8 +325,6 @@ + fs->super->s_jnl_backup_type = EXT3_JNL_BACKUP_BLOCKS; + ext2fs_mark_super_dirty(fs); + +-errout: +- ext2fs_zero_blocks2(0, 0, 0, 0, 0); + out2: + ext2fs_free_mem(&buf); + return retval; +@@ -488,6 +413,7 @@ + fs->super->s_journal_dev = st.st_rdev; + memcpy(fs->super->s_journal_uuid, jsb->s_uuid, + sizeof(fs->super->s_journal_uuid)); ++ memset(fs->super->s_jnl_blocks, 0, sizeof(fs->super->s_jnl_blocks)); + fs->super->s_feature_compat |= EXT3_FEATURE_COMPAT_HAS_JOURNAL; + ext2fs_mark_super_dirty(fs); + return 0; +--- a/lib/ext2fs/mmp.c ++++ b/lib/ext2fs/mmp.c +@@ -31,8 +31,14 @@ + #define O_DIRECT 0 + #endif + ++#pragma GCC diagnostic push ++#ifndef CONFIG_MMP ++#pragma GCC diagnostic ignored "-Wunused-parameter" ++#endif ++ + 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 +81,11 @@ + } + + 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 +100,14 @@ + + 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 +124,10 @@ + 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 +139,9 @@ + /* 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 +151,7 @@ + + unsigned ext2fs_mmp_new_seq(void) + { ++#ifdef CONFIG_MMP + unsigned new_seq; + struct timeval tv; + +@@ -145,8 +168,12 @@ + } while (new_seq > EXT4_MMP_SEQ_MAX); + + return new_seq; ++#else ++ return EXT2_ET_OP_NOT_SUPPORTED; ++#endif + } + ++#ifdef CONFIG_MMP + static errcode_t ext2fs_mmp_reset(ext2_filsys fs) + { + struct mmp_struct *mmp_s = NULL; +@@ -180,9 +207,16 @@ + out: + return retval; + } ++#endif ++ ++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 +225,14 @@ + 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 +261,9 @@ + + out: + return retval; ++#else ++ return EXT2_ET_OP_NOT_SUPPORTED; ++#endif + } + + /* +@@ -230,6 +271,7 @@ + */ + 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 +361,9 @@ + + mmp_error: + return retval; ++#else ++ return EXT2_ET_OP_NOT_SUPPORTED; ++#endif + } + + /* +@@ -329,6 +374,7 @@ + */ + errcode_t ext2fs_mmp_stop(ext2_filsys fs) + { ++#ifdef CONFIG_MMP + struct mmp_struct *mmp, *mmp_cmp; + errcode_t retval = 0; + +@@ -358,6 +404,13 @@ + } + + return retval; ++#else ++ if (!(fs->super->s_feature_incompat & EXT4_FEATURE_INCOMPAT_MMP) || ++ !(fs->flags & EXT2_FLAG_RW) || (fs->flags & EXT2_FLAG_SKIP_MMP)) ++ return 0; ++ ++ return EXT2_ET_OP_NOT_SUPPORTED; ++#endif + } + + #define EXT2_MIN_MMP_UPDATE_INTERVAL 60 +@@ -365,8 +418,9 @@ + /* + * 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 +430,8 @@ + 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 +450,12 @@ + + mmp_error: + return retval; ++#else ++ if (!(fs->super->s_feature_incompat & EXT4_FEATURE_INCOMPAT_MMP) || ++ !(fs->flags & EXT2_FLAG_RW) || (fs->flags & EXT2_FLAG_SKIP_MMP)) ++ return 0; ++ ++ return EXT2_ET_OP_NOT_SUPPORTED; ++#endif + } ++#pragma GCC diagnostic pop +--- a/lib/ext2fs/newdir.c ++++ b/lib/ext2fs/newdir.c +@@ -34,6 +34,8 @@ + 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 @@ + 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 @@ + 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,50 @@ + 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 EXT2FS_ATTR((unused)), ++ ext2_ino_t parent_ino, __u32 *iblock) ++{ ++ struct ext2_dir_entry *dir = NULL; ++ errcode_t retval; ++ int rec_len; ++ ++ 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; ++} +--- a/lib/ext2fs/openfs.c ++++ b/lib/ext2fs/openfs.c +@@ -215,6 +215,14 @@ + 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; ++ } ++ + #ifdef WORDS_BIGENDIAN + fs->flags |= EXT2_FLAG_SWAP_BYTES; + ext2fs_swap_super(fs->super); +@@ -225,10 +233,11 @@ + } + #endif + +- if (fs->super->s_magic != EXT2_SUPER_MAGIC) { ++ if (fs->super->s_magic != EXT2_SUPER_MAGIC) + retval = EXT2_ET_BAD_MAGIC; ++ if (retval) + goto cleanup; +- } ++ + if (fs->super->s_rev_level > EXT2_LIB_CURRENT_REV) { + retval = EXT2_ET_REV_TOO_HIGH; + goto cleanup; +@@ -295,6 +304,21 @@ + 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 +356,8 @@ + 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 +446,7 @@ + * 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++) { +--- a/lib/ext2fs/progress.c ++++ b/lib/ext2fs/progress.c +@@ -19,6 +19,12 @@ + 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; +--- a/lib/ext2fs/punch.c ++++ b/lib/ext2fs/punch.c +@@ -19,6 +19,7 @@ + + #include "ext2_fs.h" + #include "ext2fs.h" ++#include "ext2fsP.h" + + #undef PUNCH_DEBUG + +@@ -343,10 +344,16 @@ + 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 @@ + 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,31 @@ + 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 EXT2FS_ATTR((unused))) ++{ ++ 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 +481,9 @@ + 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; +--- a/lib/ext2fs/qcow2.c ++++ b/lib/ext2fs/qcow2.c +@@ -23,8 +23,12 @@ + * %End-Header% + */ + ++#ifndef _LARGEFILE_SOURCE + #define _LARGEFILE_SOURCE ++#endif ++#ifndef _LARGEFILE64_SOURCE + #define _LARGEFILE64_SOURCE ++#endif + + #include "config.h" + #include +--- a/lib/ext2fs/rw_bitmaps.c ++++ b/lib/ext2fs/rw_bitmaps.c +@@ -36,7 +36,7 @@ + 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 @@ + 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 @@ + 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 @@ + 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 @@ + 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 @@ + + 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 @@ + 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 @@ + 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; +--- /dev/null ++++ b/lib/ext2fs/sha256.c +@@ -0,0 +1,255 @@ ++/* ++ * sha256.c --- The sh256 algorithm ++ * ++ * Copyright (C) 2004 Sam Hocevar ++ * (copied from libtomcrypt and then relicensed under GPLv2) ++ * ++ * %Begin-Header% ++ * This file may be redistributed under the terms of the GNU Library ++ * General Public License, version 2. ++ * %End-Header% ++ */ ++ ++ ++#include "config.h" ++#if HAVE_SYS_TYPES_H ++#include ++#endif ++#include "ext2fs.h" ++ ++static const __u32 K[64] = { ++ 0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, 0x3956c25bUL, ++ 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, 0xd807aa98UL, 0x12835b01UL, ++ 0x243185beUL, 0x550c7dc3UL, 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, ++ 0xc19bf174UL, 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL, ++ 0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, 0x983e5152UL, ++ 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, 0xc6e00bf3UL, 0xd5a79147UL, ++ 0x06ca6351UL, 0x14292967UL, 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, ++ 0x53380d13UL, 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL, ++ 0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, 0xd192e819UL, ++ 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, 0x19a4c116UL, 0x1e376c08UL, ++ 0x2748774cUL, 0x34b0bcb5UL, 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL, ++ 0x682e6ff3UL, 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL, ++ 0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL ++}; ++ ++/* Various logical functions */ ++#define Ch(x,y,z) (z ^ (x & (y ^ z))) ++#define Maj(x,y,z) (((x | y) & z) | (x & y)) ++#define S(x, n) RORc((x),(n)) ++#define R(x, n) (((x)&0xFFFFFFFFUL)>>(n)) ++#define Sigma0(x) (S(x, 2) ^ S(x, 13) ^ S(x, 22)) ++#define Sigma1(x) (S(x, 6) ^ S(x, 11) ^ S(x, 25)) ++#define Gamma0(x) (S(x, 7) ^ S(x, 18) ^ R(x, 3)) ++#define Gamma1(x) (S(x, 17) ^ S(x, 19) ^ R(x, 10)) ++#define RORc(x, y) ( ((((__u32)(x)&0xFFFFFFFFUL)>>(__u32)((y)&31)) | ((__u32)(x)<<(__u32)(32-((y)&31)))) & 0xFFFFFFFFUL) ++ ++#define RND(a,b,c,d,e,f,g,h,i) \ ++ t0 = h + Sigma1(e) + Ch(e, f, g) + K[i] + W[i]; \ ++ t1 = Sigma0(a) + Maj(a, b, c); \ ++ d += t0; \ ++ h = t0 + t1; ++ ++#define STORE64H(x, y) \ ++ do { \ ++ (y)[0] = (unsigned char)(((x)>>56)&255);\ ++ (y)[1] = (unsigned char)(((x)>>48)&255);\ ++ (y)[2] = (unsigned char)(((x)>>40)&255);\ ++ (y)[3] = (unsigned char)(((x)>>32)&255);\ ++ (y)[4] = (unsigned char)(((x)>>24)&255);\ ++ (y)[5] = (unsigned char)(((x)>>16)&255);\ ++ (y)[6] = (unsigned char)(((x)>>8)&255);\ ++ (y)[7] = (unsigned char)((x)&255); } while(0) ++ ++#define STORE32H(x, y) \ ++ do { (y)[0] = (unsigned char)(((x)>>24)&255); (y)[1] = (unsigned char)(((x)>>16)&255); \ ++ (y)[2] = (unsigned char)(((x)>>8)&255); (y)[3] = (unsigned char)((x)&255); } while(0) ++ ++#define LOAD32H(x, y) \ ++ do { x = ((__u32)((y)[0] & 255)<<24) | \ ++ ((__u32)((y)[1] & 255)<<16) | \ ++ ((__u32)((y)[2] & 255)<<8) | \ ++ ((__u32)((y)[3] & 255)); } while(0) ++ ++struct sha256_state { ++ __u64 length; ++ __u32 state[8], curlen; ++ unsigned char buf[64]; ++}; ++ ++/* This is a highly simplified version from libtomcrypt */ ++struct hash_state { ++ struct sha256_state sha256; ++}; ++ ++static void sha256_compress(struct hash_state * md, const unsigned char *buf) ++{ ++ __u32 S[8], W[64], t0, t1; ++ __u32 t; ++ int i; ++ ++ /* copy state into S */ ++ for (i = 0; i < 8; i++) { ++ S[i] = md->sha256.state[i]; ++ } ++ ++ /* copy the state into 512-bits into W[0..15] */ ++ for (i = 0; i < 16; i++) { ++ LOAD32H(W[i], buf + (4*i)); ++ } ++ ++ /* fill W[16..63] */ ++ for (i = 16; i < 64; i++) { ++ W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) + W[i - 16]; ++ } ++ ++ /* Compress */ ++ for (i = 0; i < 64; ++i) { ++ RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],i); ++ t = S[7]; S[7] = S[6]; S[6] = S[5]; S[5] = S[4]; ++ S[4] = S[3]; S[3] = S[2]; S[2] = S[1]; S[1] = S[0]; S[0] = t; ++ } ++ ++ /* feedback */ ++ for (i = 0; i < 8; i++) { ++ md->sha256.state[i] = md->sha256.state[i] + S[i]; ++ } ++} ++ ++static void sha256_init(struct hash_state * md) ++{ ++ md->sha256.curlen = 0; ++ md->sha256.length = 0; ++ md->sha256.state[0] = 0x6A09E667UL; ++ md->sha256.state[1] = 0xBB67AE85UL; ++ md->sha256.state[2] = 0x3C6EF372UL; ++ md->sha256.state[3] = 0xA54FF53AUL; ++ md->sha256.state[4] = 0x510E527FUL; ++ md->sha256.state[5] = 0x9B05688CUL; ++ md->sha256.state[6] = 0x1F83D9ABUL; ++ md->sha256.state[7] = 0x5BE0CD19UL; ++} ++ ++#define MIN(x, y) ( ((x)<(y))?(x):(y) ) ++#define SHA256_BLOCKSIZE 64 ++static void sha256_process(struct hash_state * md, const unsigned char *in, unsigned long inlen) ++{ ++ unsigned long n; ++ ++ while (inlen > 0) { ++ if (md->sha256.curlen == 0 && inlen >= SHA256_BLOCKSIZE) { ++ sha256_compress(md, in); ++ md->sha256.length += SHA256_BLOCKSIZE * 8; ++ in += SHA256_BLOCKSIZE; ++ inlen -= SHA256_BLOCKSIZE; ++ } else { ++ n = MIN(inlen, (SHA256_BLOCKSIZE - md->sha256.curlen)); ++ memcpy(md->sha256.buf + md->sha256.curlen, in, (size_t)n); ++ md->sha256.curlen += n; ++ in += n; ++ inlen -= n; ++ if (md->sha256.curlen == SHA256_BLOCKSIZE) { ++ sha256_compress(md, md->sha256.buf); ++ md->sha256.length += 8*SHA256_BLOCKSIZE; ++ md->sha256.curlen = 0; ++ } ++ } ++ } ++} ++ ++ ++static void sha256_done(struct hash_state * md, unsigned char *out) ++{ ++ int i; ++ ++ /* increase the length of the message */ ++ md->sha256.length += md->sha256.curlen * 8; ++ ++ /* append the '1' bit */ ++ md->sha256.buf[md->sha256.curlen++] = (unsigned char)0x80; ++ ++ /* if the length is currently above 56 bytes we append zeros ++ * then compress. Then we can fall back to padding zeros and length ++ * encoding like normal. ++ */ ++ if (md->sha256.curlen > 56) { ++ while (md->sha256.curlen < 64) { ++ md->sha256.buf[md->sha256.curlen++] = (unsigned char)0; ++ } ++ sha256_compress(md, md->sha256.buf); ++ md->sha256.curlen = 0; ++ } ++ ++ /* pad upto 56 bytes of zeroes */ ++ while (md->sha256.curlen < 56) { ++ md->sha256.buf[md->sha256.curlen++] = (unsigned char)0; ++ } ++ ++ /* store length */ ++ STORE64H(md->sha256.length, md->sha256.buf+56); ++ sha256_compress(md, md->sha256.buf); ++ ++ /* copy output */ ++ for (i = 0; i < 8; i++) { ++ STORE32H(md->sha256.state[i], out+(4*i)); ++ } ++} ++ ++void ext2fs_sha256(const unsigned char *in, unsigned long in_size, ++ unsigned char out[EXT2FS_SHA256_LENGTH]) ++{ ++ struct hash_state md; ++ ++ sha256_init(&md); ++ sha256_process(&md, in, in_size); ++ sha256_done(&md, out); ++} ++ ++#ifdef UNITTEST ++static const struct { ++ char *msg; ++ unsigned char hash[32]; ++} tests[] = { ++ { "", ++ { 0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, ++ 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24, ++ 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, ++ 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55 } ++ }, ++ { "abc", ++ { 0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea, ++ 0x41, 0x41, 0x40, 0xde, 0x5d, 0xae, 0x22, 0x23, ++ 0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c, ++ 0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad } ++ }, ++ { "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", ++ { 0x24, 0x8d, 0x6a, 0x61, 0xd2, 0x06, 0x38, 0xb8, ++ 0xe5, 0xc0, 0x26, 0x93, 0x0c, 0x3e, 0x60, 0x39, ++ 0xa3, 0x3c, 0xe4, 0x59, 0x64, 0xff, 0x21, 0x67, ++ 0xf6, 0xec, 0xed, 0xd4, 0x19, 0xdb, 0x06, 0xc1 } ++ }, ++}; ++ ++int main(int argc, char **argv) ++{ ++ int i; ++ int errors = 0; ++ unsigned char tmp[32]; ++ struct hash_state md; ++ ++ for (i = 0; i < (int)(sizeof(tests) / sizeof(tests[0])); i++) { ++ unsigned char *msg = (unsigned char *) tests[i].msg; ++ int len = strlen(tests[i].msg); ++ ++ ext2fs_sha256(msg, len, tmp); ++ printf("SHA256 test message %d: ", i); ++ if (memcmp(tmp, tests[i].hash, 32) != 0) { ++ printf("FAILED\n"); ++ errors++; ++ } else ++ printf("OK\n"); ++ } ++ return errors; ++} ++ ++#endif /* UNITTEST */ +--- /dev/null ++++ b/lib/ext2fs/sha512.c +@@ -0,0 +1,303 @@ ++/* ++ * sha512.c --- The sha512 algorithm ++ * ++ * Copyright (C) 2004 Sam Hocevar ++ * (copied from libtomcrypt and then relicensed under GPLv2) ++ * ++ * %Begin-Header% ++ * This file may be redistributed under the terms of the GNU Library ++ * General Public License, version 2. ++ * %End-Header% ++ */ ++ ++ ++#include "config.h" ++#if HAVE_SYS_TYPES_H ++#include ++#endif ++#include "ext2fs.h" ++ ++/* the K array */ ++#define CONST64(n) n ++static const __u64 K[80] = { ++ CONST64(0x428a2f98d728ae22), CONST64(0x7137449123ef65cd), ++ CONST64(0xb5c0fbcfec4d3b2f), CONST64(0xe9b5dba58189dbbc), ++ CONST64(0x3956c25bf348b538), CONST64(0x59f111f1b605d019), ++ CONST64(0x923f82a4af194f9b), CONST64(0xab1c5ed5da6d8118), ++ CONST64(0xd807aa98a3030242), CONST64(0x12835b0145706fbe), ++ CONST64(0x243185be4ee4b28c), CONST64(0x550c7dc3d5ffb4e2), ++ CONST64(0x72be5d74f27b896f), CONST64(0x80deb1fe3b1696b1), ++ CONST64(0x9bdc06a725c71235), CONST64(0xc19bf174cf692694), ++ CONST64(0xe49b69c19ef14ad2), CONST64(0xefbe4786384f25e3), ++ CONST64(0x0fc19dc68b8cd5b5), CONST64(0x240ca1cc77ac9c65), ++ CONST64(0x2de92c6f592b0275), CONST64(0x4a7484aa6ea6e483), ++ CONST64(0x5cb0a9dcbd41fbd4), CONST64(0x76f988da831153b5), ++ CONST64(0x983e5152ee66dfab), CONST64(0xa831c66d2db43210), ++ CONST64(0xb00327c898fb213f), CONST64(0xbf597fc7beef0ee4), ++ CONST64(0xc6e00bf33da88fc2), CONST64(0xd5a79147930aa725), ++ CONST64(0x06ca6351e003826f), CONST64(0x142929670a0e6e70), ++ CONST64(0x27b70a8546d22ffc), CONST64(0x2e1b21385c26c926), ++ CONST64(0x4d2c6dfc5ac42aed), CONST64(0x53380d139d95b3df), ++ CONST64(0x650a73548baf63de), CONST64(0x766a0abb3c77b2a8), ++ CONST64(0x81c2c92e47edaee6), CONST64(0x92722c851482353b), ++ CONST64(0xa2bfe8a14cf10364), CONST64(0xa81a664bbc423001), ++ CONST64(0xc24b8b70d0f89791), CONST64(0xc76c51a30654be30), ++ CONST64(0xd192e819d6ef5218), CONST64(0xd69906245565a910), ++ CONST64(0xf40e35855771202a), CONST64(0x106aa07032bbd1b8), ++ CONST64(0x19a4c116b8d2d0c8), CONST64(0x1e376c085141ab53), ++ CONST64(0x2748774cdf8eeb99), CONST64(0x34b0bcb5e19b48a8), ++ CONST64(0x391c0cb3c5c95a63), CONST64(0x4ed8aa4ae3418acb), ++ CONST64(0x5b9cca4f7763e373), CONST64(0x682e6ff3d6b2b8a3), ++ CONST64(0x748f82ee5defb2fc), CONST64(0x78a5636f43172f60), ++ CONST64(0x84c87814a1f0ab72), CONST64(0x8cc702081a6439ec), ++ CONST64(0x90befffa23631e28), CONST64(0xa4506cebde82bde9), ++ CONST64(0xbef9a3f7b2c67915), CONST64(0xc67178f2e372532b), ++ CONST64(0xca273eceea26619c), CONST64(0xd186b8c721c0c207), ++ CONST64(0xeada7dd6cde0eb1e), CONST64(0xf57d4f7fee6ed178), ++ CONST64(0x06f067aa72176fba), CONST64(0x0a637dc5a2c898a6), ++ CONST64(0x113f9804bef90dae), CONST64(0x1b710b35131c471b), ++ CONST64(0x28db77f523047d84), CONST64(0x32caab7b40c72493), ++ CONST64(0x3c9ebe0a15c9bebc), CONST64(0x431d67c49c100d4c), ++ CONST64(0x4cc5d4becb3e42b6), CONST64(0x597f299cfc657e2a), ++ CONST64(0x5fcb6fab3ad6faec), CONST64(0x6c44198c4a475817) ++}; ++#define Ch(x,y,z) (z ^ (x & (y ^ z))) ++#define Maj(x,y,z) (((x | y) & z) | (x & y)) ++#define S(x, n) ROR64c(x, n) ++#define R(x, n) (((x)&CONST64(0xFFFFFFFFFFFFFFFF))>>((__u64)n)) ++#define Sigma0(x) (S(x, 28) ^ S(x, 34) ^ S(x, 39)) ++#define Sigma1(x) (S(x, 14) ^ S(x, 18) ^ S(x, 41)) ++#define Gamma0(x) (S(x, 1) ^ S(x, 8) ^ R(x, 7)) ++#define Gamma1(x) (S(x, 19) ^ S(x, 61) ^ R(x, 6)) ++#define RND(a,b,c,d,e,f,g,h,i)\ ++ t0 = h + Sigma1(e) + Ch(e, f, g) + K[i] + W[i];\ ++ t1 = Sigma0(a) + Maj(a, b, c);\ ++ d += t0;\ ++ h = t0 + t1; ++#define STORE64H(x, y) \ ++ do { \ ++ (y)[0] = (unsigned char)(((x)>>56)&255);\ ++ (y)[1] = (unsigned char)(((x)>>48)&255);\ ++ (y)[2] = (unsigned char)(((x)>>40)&255);\ ++ (y)[3] = (unsigned char)(((x)>>32)&255);\ ++ (y)[4] = (unsigned char)(((x)>>24)&255);\ ++ (y)[5] = (unsigned char)(((x)>>16)&255);\ ++ (y)[6] = (unsigned char)(((x)>>8)&255);\ ++ (y)[7] = (unsigned char)((x)&255); } while(0) ++ ++#define LOAD64H(x, y)\ ++ do {x = \ ++ (((__u64)((y)[0] & 255)) << 56) |\ ++ (((__u64)((y)[1] & 255)) << 48) |\ ++ (((__u64)((y)[2] & 255)) << 40) |\ ++ (((__u64)((y)[3] & 255)) << 32) |\ ++ (((__u64)((y)[4] & 255)) << 24) |\ ++ (((__u64)((y)[5] & 255)) << 16) |\ ++ (((__u64)((y)[6] & 255)) << 8) |\ ++ (((__u64)((y)[7] & 255)));\ ++ } while(0) ++ ++#define ROR64c(x, y) \ ++ ( ((((x)&CONST64(0xFFFFFFFFFFFFFFFF))>>((__u64)(y)&CONST64(63))) | \ ++ ((x)<<((__u64)(64-((y)&CONST64(63)))))) & CONST64(0xFFFFFFFFFFFFFFFF)) ++ ++struct sha512_state { ++ __u64 length, state[8]; ++ unsigned long curlen; ++ unsigned char buf[128]; ++}; ++ ++/* This is a highly simplified version from libtomcrypt */ ++struct hash_state { ++ struct sha512_state sha512; ++}; ++ ++static void sha512_compress(struct hash_state * md, const unsigned char *buf) ++{ ++ __u64 S[8], W[80], t0, t1; ++ int i; ++ ++ /* copy state into S */ ++ for (i = 0; i < 8; i++) { ++ S[i] = md->sha512.state[i]; ++ } ++ ++ /* copy the state into 1024-bits into W[0..15] */ ++ for (i = 0; i < 16; i++) { ++ LOAD64H(W[i], buf + (8*i)); ++ } ++ ++ /* fill W[16..79] */ ++ for (i = 16; i < 80; i++) { ++ W[i] = Gamma1(W[i - 2]) + W[i - 7] + ++ Gamma0(W[i - 15]) + W[i - 16]; ++ } ++ ++ for (i = 0; i < 80; i += 8) { ++ RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],i+0); ++ RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],i+1); ++ RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],i+2); ++ RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],i+3); ++ RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],i+4); ++ RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],i+5); ++ RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],i+6); ++ RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],i+7); ++ } ++ ++ /* feedback */ ++ for (i = 0; i < 8; i++) { ++ md->sha512.state[i] = md->sha512.state[i] + S[i]; ++ } ++} ++ ++static void sha512_init(struct hash_state * md) ++{ ++ md->sha512.curlen = 0; ++ md->sha512.length = 0; ++ md->sha512.state[0] = CONST64(0x6a09e667f3bcc908); ++ md->sha512.state[1] = CONST64(0xbb67ae8584caa73b); ++ md->sha512.state[2] = CONST64(0x3c6ef372fe94f82b); ++ md->sha512.state[3] = CONST64(0xa54ff53a5f1d36f1); ++ md->sha512.state[4] = CONST64(0x510e527fade682d1); ++ md->sha512.state[5] = CONST64(0x9b05688c2b3e6c1f); ++ md->sha512.state[6] = CONST64(0x1f83d9abfb41bd6b); ++ md->sha512.state[7] = CONST64(0x5be0cd19137e2179); ++} ++ ++static void sha512_done(struct hash_state * md, unsigned char *out) ++{ ++ int i; ++ ++ /* increase the length of the message */ ++ md->sha512.length += md->sha512.curlen * CONST64(8); ++ ++ /* append the '1' bit */ ++ md->sha512.buf[md->sha512.curlen++] = (unsigned char)0x80; ++ ++ /* if the length is currently above 112 bytes we append zeros then ++ * compress. Then we can fall back to padding zeros and length encoding ++ * like normal. */ ++ if (md->sha512.curlen > 112) { ++ while (md->sha512.curlen < 128) { ++ md->sha512.buf[md->sha512.curlen++] = (unsigned char)0; ++ } ++ sha512_compress(md, md->sha512.buf); ++ md->sha512.curlen = 0; ++ } ++ ++ /* pad upto 120 bytes of zeroes note: that from 112 to 120 is the 64 MSB ++ * of the length. We assume that you won't hash > 2^64 bits of data. */ ++ while (md->sha512.curlen < 120) { ++ md->sha512.buf[md->sha512.curlen++] = (unsigned char)0; ++ } ++ ++ /* store length */ ++ STORE64H(md->sha512.length, md->sha512.buf + 120); ++ sha512_compress(md, md->sha512.buf); ++ ++ /* copy output */ ++ for (i = 0; i < 8; i++) { ++ STORE64H(md->sha512.state[i], out+(8 * i)); ++ } ++} ++ ++#define MIN(x, y) ( ((x)<(y))?(x):(y) ) ++#define SHA512_BLOCKSIZE 128 ++static void sha512_process(struct hash_state * md, ++ const unsigned char *in, ++ unsigned long inlen) ++{ ++ unsigned long n; ++ ++ while (inlen > 0) { ++ if (md->sha512.curlen == 0 && inlen >= SHA512_BLOCKSIZE) { ++ sha512_compress(md, in); ++ md->sha512.length += SHA512_BLOCKSIZE * 8; ++ in += SHA512_BLOCKSIZE; ++ inlen -= SHA512_BLOCKSIZE; ++ } else { ++ n = MIN(inlen, (SHA512_BLOCKSIZE - md->sha512.curlen)); ++ memcpy(md->sha512.buf + md->sha512.curlen, ++ in, (size_t)n); ++ md->sha512.curlen += n; ++ in += n; ++ inlen -= n; ++ if (md->sha512.curlen == SHA512_BLOCKSIZE) { ++ sha512_compress(md, md->sha512.buf); ++ md->sha512.length += SHA512_BLOCKSIZE * 8; ++ md->sha512.curlen = 0; ++ } ++ } ++ } ++} ++ ++void ext2fs_sha512(const unsigned char *in, unsigned long in_size, ++ unsigned char out[EXT2FS_SHA512_LENGTH]) ++{ ++ struct hash_state md; ++ ++ sha512_init(&md); ++ sha512_process(&md, in, in_size); ++ sha512_done(&md, out); ++} ++ ++#ifdef UNITTEST ++static const struct { ++ char *msg; ++ unsigned char hash[64]; ++} tests[] = { ++ { "", ++ { 0xcf, 0x83, 0xe1, 0x35, 0x7e, 0xef, 0xb8, 0xbd, ++ 0xf1, 0x54, 0x28, 0x50, 0xd6, 0x6d, 0x80, 0x07, ++ 0xd6, 0x20, 0xe4, 0x05, 0x0b, 0x57, 0x15, 0xdc, ++ 0x83, 0xf4, 0xa9, 0x21, 0xd3, 0x6c, 0xe9, 0xce, ++ 0x47, 0xd0, 0xd1, 0x3c, 0x5d, 0x85, 0xf2, 0xb0, ++ 0xff, 0x83, 0x18, 0xd2, 0x87, 0x7e, 0xec, 0x2f, ++ 0x63, 0xb9, 0x31, 0xbd, 0x47, 0x41, 0x7a, 0x81, ++ 0xa5, 0x38, 0x32, 0x7a, 0xf9, 0x27, 0xda, 0x3e } ++ }, ++ { "abc", ++ { 0xdd, 0xaf, 0x35, 0xa1, 0x93, 0x61, 0x7a, 0xba, ++ 0xcc, 0x41, 0x73, 0x49, 0xae, 0x20, 0x41, 0x31, ++ 0x12, 0xe6, 0xfa, 0x4e, 0x89, 0xa9, 0x7e, 0xa2, ++ 0x0a, 0x9e, 0xee, 0xe6, 0x4b, 0x55, 0xd3, 0x9a, ++ 0x21, 0x92, 0x99, 0x2a, 0x27, 0x4f, 0xc1, 0xa8, ++ 0x36, 0xba, 0x3c, 0x23, 0xa3, 0xfe, 0xeb, 0xbd, ++ 0x45, 0x4d, 0x44, 0x23, 0x64, 0x3c, 0xe8, 0x0e, ++ 0x2a, 0x9a, 0xc9, 0x4f, 0xa5, 0x4c, 0xa4, 0x9f } ++ }, ++ { "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu", ++ { 0x8e, 0x95, 0x9b, 0x75, 0xda, 0xe3, 0x13, 0xda, ++ 0x8c, 0xf4, 0xf7, 0x28, 0x14, 0xfc, 0x14, 0x3f, ++ 0x8f, 0x77, 0x79, 0xc6, 0xeb, 0x9f, 0x7f, 0xa1, ++ 0x72, 0x99, 0xae, 0xad, 0xb6, 0x88, 0x90, 0x18, ++ 0x50, 0x1d, 0x28, 0x9e, 0x49, 0x00, 0xf7, 0xe4, ++ 0x33, 0x1b, 0x99, 0xde, 0xc4, 0xb5, 0x43, 0x3a, ++ 0xc7, 0xd3, 0x29, 0xee, 0xb6, 0xdd, 0x26, 0x54, ++ 0x5e, 0x96, 0xe5, 0x5b, 0x87, 0x4b, 0xe9, 0x09 } ++ }, ++}; ++ ++int main(int argc, char **argv) ++{ ++ int i; ++ int errors = 0; ++ unsigned char tmp[64]; ++ struct hash_state md; ++ ++ for (i = 0; i < (int)(sizeof(tests) / sizeof(tests[0])); i++) { ++ unsigned char *msg = (unsigned char *) tests[i].msg; ++ int len = strlen(tests[i].msg); ++ ++ ext2fs_sha512(msg, len, tmp); ++ printf("SHA512 test message %d: ", i); ++ if (memcmp(tmp, tests[i].hash, 64) != 0) { ++ printf("FAILED\n"); ++ errors++; ++ } else ++ printf("OK\n"); ++ } ++ return errors; ++} ++ ++#endif /* UNITTEST */ +--- a/lib/ext2fs/swapfs.c ++++ b/lib/ext2fs/swapfs.c +@@ -159,7 +159,8 @@ + 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 @@ + 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 @@ + { + 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 @@ + (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 && (t->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 @@ + 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 +--- a/lib/ext2fs/symlink.c ++++ b/lib/ext2fs/symlink.c +@@ -29,20 +29,20 @@ + #include "ext2fs.h" + + errcode_t ext2fs_symlink(ext2_filsys fs, ext2_ino_t parent, ext2_ino_t ino, +- const char *name, char *target) ++ const char *name, const char *target) + { + errcode_t retval; + struct ext2_inode inode; + ext2_ino_t scratch_ino; + blk64_t blk; +- int fastlink; ++ int fastlink, inlinelink; + unsigned int target_len; + char *block_buf = 0; + + EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); + + /* The Linux kernel doesn't allow for links longer than a block */ +- target_len = strlen(target); ++ target_len = strnlen(target, fs->blocksize + 1); + if (target_len > fs->blocksize) { + retval = EXT2_ET_INVALID_ARGUMENT; + goto cleanup; +@@ -51,12 +51,19 @@ + /* + * Allocate a data block for slow links + */ ++ retval = ext2fs_get_mem(fs->blocksize+1, &block_buf); ++ if (retval) ++ goto cleanup; ++ memset(block_buf, 0, fs->blocksize+1); ++ strncpy(block_buf, target, fs->blocksize); ++ ++ memset(&inode, 0, sizeof(struct ext2_inode)); + fastlink = (target_len < sizeof(inode.i_block)); + if (!fastlink) { +- retval = ext2fs_new_block2(fs, 0, 0, &blk); +- if (retval) +- goto cleanup; +- retval = ext2fs_get_mem(fs->blocksize, &block_buf); ++ retval = ext2fs_new_block2(fs, ext2fs_find_inode_goal(fs, ino, ++ &inode, ++ 0), ++ NULL, &blk); + if (retval) + goto cleanup; + } +@@ -74,21 +81,39 @@ + /* + * Create the inode structure.... + */ +- memset(&inode, 0, sizeof(struct ext2_inode)); + inode.i_mode = LINUX_S_IFLNK | 0777; + inode.i_uid = inode.i_gid = 0; +- ext2fs_iblk_set(fs, &inode, fastlink ? 0 : 1); + inode.i_links_count = 1; + ext2fs_inode_size_set(fs, &inode, target_len); + /* The time fields are set by ext2fs_write_new_inode() */ + ++ inlinelink = !fastlink && ++ (fs->super->s_feature_incompat & ++ EXT4_FEATURE_INCOMPAT_INLINE_DATA) && ++ (target_len < fs->blocksize); + if (fastlink) { + /* Fast symlinks, target stored in inode */ + strcpy((char *)&inode.i_block, target); ++ } else if (inlinelink) { ++ /* Try inserting an inline data symlink */ ++ inode.i_flags |= EXT4_INLINE_DATA_FL; ++ retval = ext2fs_write_new_inode(fs, ino, &inode); ++ if (retval) ++ goto cleanup; ++ retval = ext2fs_inline_data_set(fs, ino, &inode, block_buf, ++ target_len); ++ if (retval) { ++ inode.i_flags &= ~EXT4_INLINE_DATA_FL; ++ inlinelink = 0; ++ goto need_block; ++ } ++ retval = ext2fs_read_inode(fs, ino, &inode); ++ if (retval) ++ goto cleanup; + } else { ++need_block: + /* Slow symlinks, target stored in the first block */ +- memset(block_buf, 0, fs->blocksize); +- strncpy(block_buf, target, fs->blocksize); ++ ext2fs_iblk_set(fs, &inode, 1); + if (fs->super->s_feature_incompat & + EXT3_FEATURE_INCOMPAT_EXTENTS) { + /* +@@ -104,11 +129,14 @@ + * number is assigned by write_new_inode, which means that the + * operations using ino must come after it. + */ +- retval = ext2fs_write_new_inode(fs, ino, &inode); ++ if (inlinelink) ++ retval = ext2fs_write_inode(fs, ino, &inode); ++ else ++ retval = ext2fs_write_new_inode(fs, ino, &inode); + if (retval) + goto cleanup; + +- if (!fastlink) { ++ if (!fastlink && !inlinelink) { + retval = ext2fs_bmap2(fs, ino, &inode, NULL, BMAP_SET, 0, NULL, + &blk); + if (retval) +@@ -139,7 +167,7 @@ + /* + * Update accounting.... + */ +- if (!fastlink) ++ if (!fastlink && !inlinelink) + ext2fs_block_alloc_stats2(fs, blk, +1); + ext2fs_inode_alloc_stats2(fs, ino, +1, 0); + +--- a/lib/ext2fs/tdb.c ++++ b/lib/ext2fs/tdb.c +@@ -246,6 +246,7 @@ + int page_size; + int max_dead_records; + bool have_transaction_lock; ++ tdb_len_t real_map_size; /* how much space has been mapped */ + }; + + +@@ -970,9 +971,10 @@ + + #ifdef HAVE_MMAP + if (tdb->map_ptr) { +- int ret = munmap(tdb->map_ptr, tdb->map_size); ++ int ret = munmap(tdb->map_ptr, tdb->real_map_size); + if (ret != 0) + return ret; ++ tdb->real_map_size = 0; + } + #endif + tdb->map_ptr = NULL; +@@ -995,10 +997,12 @@ + */ + + if (tdb->map_ptr == MAP_FAILED) { ++ tdb->real_map_size = 0; + tdb->map_ptr = NULL; + TDB_LOG((tdb, TDB_DEBUG_WARNING, "tdb_mmap failed for size %d (%s)\n", + tdb->map_size, strerror(errno))); + } ++ tdb->real_map_size = tdb->map_size; + } else { + tdb->map_ptr = NULL; + } +@@ -4138,3 +4142,13 @@ + + return 0; + } ++ ++/** ++ * Flush a database file from the page cache. ++ **/ ++int tdb_flush(struct tdb_context *tdb) ++{ ++ if (tdb->fd != -1) ++ return fsync(tdb->fd); ++ return 0; ++} +--- a/lib/ext2fs/tdb.h ++++ b/lib/ext2fs/tdb.h +@@ -129,6 +129,7 @@ + #define tdb_lockall_nonblock ext2fs_tdb_lockall_nonblock + #define tdb_lockall_read_nonblock ext2fs_tdb_lockall_read_nonblock + #define tdb_lockall_unmark ext2fs_tdb_lockall_unmark ++#define tdb_flush ext2fs_tdb_flush + + /* this is the context structure that is returned from a db open */ + typedef struct tdb_context TDB_CONTEXT; +@@ -191,6 +192,7 @@ + int tdb_get_flags(struct tdb_context *tdb); + void tdb_enable_seqnum(struct tdb_context *tdb); + void tdb_increment_seqnum_nonblock(struct tdb_context *tdb); ++int tdb_flush(struct tdb_context *tdb); + + /* Low level locking functions: use with care */ + int tdb_chainlock(struct tdb_context *tdb, TDB_DATA key); +--- a/lib/ext2fs/test_io.c ++++ b/lib/ext2fs/test_io.c +@@ -85,6 +85,8 @@ + #define TEST_FLAG_DUMP 0x10 + #define TEST_FLAG_SET_OPTION 0x20 + #define TEST_FLAG_DISCARD 0x40 ++#define TEST_FLAG_READAHEAD 0x80 ++#define TEST_FLAG_ZEROOUT 0x100 + + static void test_dump_block(io_channel channel, + struct test_private_data *data, +@@ -486,6 +488,45 @@ + return retval; + } + ++static errcode_t test_cache_readahead(io_channel channel, ++ unsigned long long block, ++ unsigned long long count) ++{ ++ struct test_private_data *data; ++ errcode_t retval = 0; ++ ++ EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); ++ data = (struct test_private_data *) channel->private_data; ++ EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_TEST_IO_CHANNEL); ++ ++ if (data->real) ++ retval = io_channel_cache_readahead(data->real, block, count); ++ if (data->flags & TEST_FLAG_READAHEAD) ++ fprintf(data->outfile, ++ "Test_io: readahead(%llu, %llu) returned %s\n", ++ block, count, retval ? error_message(retval) : "OK"); ++ return retval; ++} ++ ++static errcode_t test_zeroout(io_channel channel, unsigned long long block, ++ unsigned long long count) ++{ ++ struct test_private_data *data; ++ errcode_t retval = 0; ++ ++ EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); ++ data = (struct test_private_data *) channel->private_data; ++ EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_TEST_IO_CHANNEL); ++ ++ if (data->real) ++ retval = io_channel_zeroout(data->real, block, count); ++ if (data->flags & TEST_FLAG_ZEROOUT) ++ fprintf(data->outfile, ++ "Test_io: zeroout(%llu, %llu) returned %s\n", ++ block, count, retval ? error_message(retval) : "OK"); ++ return retval; ++} ++ + static struct struct_io_manager struct_test_manager = { + .magic = EXT2_ET_MAGIC_IO_MANAGER, + .name = "Test I/O Manager", +@@ -501,6 +542,8 @@ + .read_blk64 = test_read_blk64, + .write_blk64 = test_write_blk64, + .discard = test_discard, ++ .cache_readahead = test_cache_readahead, ++ .zeroout = test_zeroout, + }; + + io_manager test_io_manager = &struct_test_manager; +--- a/lib/ext2fs/tst_super_size.c ++++ b/lib/ext2fs/tst_super_size.c +@@ -113,8 +113,9 @@ + 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_reserved_pad, 2); ++ check_field(s_checksum_type, 1); ++ check_field(s_encryption_level, 1); ++ check_field(s_reserved_pad, 1); + check_field(s_kbytes_written, 8); + check_field(s_snapshot_inum, 4); + check_field(s_snapshot_id, 4); +@@ -136,7 +137,10 @@ + check_field(s_grp_quota_inum, 4); + check_field(s_overhead_blocks, 4); + check_field(s_backup_bgs, 8); +- check_field(s_reserved, 106 * 4); ++ check_field(s_encrypt_algos, 4); ++ check_field(s_encrypt_pw_salt, 16); ++ check_field(s_lpf_ino, 4); ++ check_field(s_reserved, 100 * 4); + check_field(s_checksum, 4); + do_field("Superblock end", 0, 0, cur_offset, 1024); + #endif +--- a/lib/ext2fs/undo_io.c ++++ b/lib/ext2fs/undo_io.c +@@ -11,8 +11,12 @@ + * %End-Header% + */ + ++#ifndef _LARGEFILE_SOURCE + #define _LARGEFILE_SOURCE ++#endif ++#ifndef _LARGEFILE64_SOURCE + #define _LARGEFILE64_SOURCE ++#endif + + #include "config.h" + #include +@@ -37,11 +41,11 @@ + #if HAVE_SYS_RESOURCE_H + #include + #endif +- +-#include "tdb.h" ++#include + + #include "ext2_fs.h" + #include "ext2fs.h" ++#include "ext2fsP.h" + + #ifdef __GNUC__ + #define ATTR(x) __attribute__(x) +@@ -49,36 +53,102 @@ + #define ATTR(x) + #endif + ++#undef DEBUG ++ ++#ifdef DEBUG ++# define dbg_printf(f, a...) do {printf(f, ## a); fflush(stdout); } while (0) ++#else ++# define dbg_printf(f, a...) ++#endif ++ + /* + * For checking structure magic numbers... + */ + + #define EXT2_CHECK_MAGIC(struct, code) \ + if ((struct)->magic != (code)) return (code) ++/* ++ * Undo file format: The file is cut up into undo_header.block_size blocks. ++ * The first block contains the header. ++ * The second block contains the superblock. ++ * There is then a repeating series of blocks as follows: ++ * A key block, which contains undo_keys to map the following data blocks. ++ * Data blocks ++ * (Note that there are pointers to the first key block and the sb, so this ++ * order isn't strictly necessary.) ++ */ ++#define E2UNDO_MAGIC "E2UNDO02" ++#define KEYBLOCK_MAGIC 0xCADECADE ++ ++#define E2UNDO_STATE_FINISHED 0x1 /* undo file is complete */ ++ ++#define E2UNDO_MIN_BLOCK_SIZE 1024 /* undo blocks are no less than 1KB */ ++#define E2UNDO_MAX_BLOCK_SIZE 1048576 /* undo blocks are no more than 1MB */ ++ ++struct undo_header { ++ char magic[8]; /* "E2UNDO02" */ ++ __le64 num_keys; /* how many keys? */ ++ __le64 super_offset; /* where in the file is the superblock copy? */ ++ __le64 key_offset; /* where do the key/data block chunks start? */ ++ __le32 block_size; /* block size of the undo file */ ++ __le32 fs_block_size; /* block size of the target device */ ++ __le32 sb_crc; /* crc32c of the superblock */ ++ __le32 state; /* e2undo state flags */ ++ __le32 f_compat; /* compatible features (none so far) */ ++ __le32 f_incompat; /* incompatible features (none so far) */ ++ __le32 f_rocompat; /* ro compatible features (none so far) */ ++ __u8 padding[448]; /* padding */ ++ __le32 header_crc; /* crc32c of this header (but not this field) */ ++}; ++ ++#define E2UNDO_MAX_EXTENT_BLOCKS 512 /* max extent size, in blocks */ ++ ++struct undo_key { ++ __le64 fsblk; /* where in the fs does the block go */ ++ __le32 blk_crc; /* crc32c of the block */ ++ __le32 size; /* how many bytes in this block? */ ++}; ++ ++struct undo_key_block { ++ __le32 magic; /* KEYBLOCK_MAGIC number */ ++ __le32 crc; /* block checksum */ ++ __le64 reserved; /* zero */ ++ ++ struct undo_key keys[0]; /* keys, which come immediately after */ ++}; + + struct undo_private_data { + int magic; +- TDB_CONTEXT *tdb; +- char *tdb_file; ++ ++ /* the undo file io channel */ ++ io_channel undo_file; ++ blk64_t undo_blk_num; /* next free block */ ++ blk64_t key_blk_num; /* current key block location */ ++ blk64_t super_blk_num; /* superblock location */ ++ blk64_t first_key_blk; /* first key block location */ ++ struct undo_key_block *keyb; ++ size_t num_keys, keys_in_block; + + /* The backing io channel */ + io_channel real; + +- int tdb_data_size; ++ unsigned long long tdb_data_size; + int tdb_written; + + /* to support offset in unix I/O manager */ + ext2_loff_t offset; ++ ++ ext2fs_block_bitmap written_block_map; ++ struct struct_ext2_filsys fake_fs; ++ char *tdb_file; ++ struct undo_header hdr; + }; ++#define KEYS_PER_BLOCK(d) (((d)->tdb_data_size / sizeof(struct undo_key)) - 1) + + static io_manager undo_io_backing_manager; + static char *tdb_file; + static int actual_size; + +-static unsigned char mtime_key[] = "filesystem MTIME"; +-static unsigned char blksize_key[] = "filesystem BLKSIZE"; +-static unsigned char uuid_key[] = "filesystem UUID"; +- + errcode_t set_undo_io_backing_manager(io_manager manager) + { + /* +@@ -99,17 +169,38 @@ + return 0; + } + +-static errcode_t write_file_system_identity(io_channel undo_channel, +- TDB_CONTEXT *tdb) ++static errcode_t write_undo_indexes(struct undo_private_data *data, int flush) + { + errcode_t retval; + struct ext2_super_block super; +- TDB_DATA tdb_key, tdb_data; +- struct undo_private_data *data; + io_channel channel; +- int block_size ; ++ int block_size; ++ __u32 sb_crc, hdr_crc; + +- data = (struct undo_private_data *) undo_channel->private_data; ++ /* Spit out a key block, if there's any data */ ++ if (data->keys_in_block) { ++ data->keyb->magic = ext2fs_cpu_to_le32(KEYBLOCK_MAGIC); ++ data->keyb->crc = 0; ++ data->keyb->crc = ext2fs_cpu_to_le32( ++ ext2fs_crc32c_le(~0, ++ (unsigned char *)data->keyb, ++ data->tdb_data_size)); ++ dbg_printf("Writing keyblock to blk %llu\n", data->key_blk_num); ++ retval = io_channel_write_blk64(data->undo_file, ++ data->key_blk_num, ++ 1, data->keyb); ++ if (retval) ++ return retval; ++ /* Move on to the next key block if it's full. */ ++ if (data->keys_in_block == KEYS_PER_BLOCK(data)) { ++ memset(data->keyb, 0, data->tdb_data_size); ++ data->keys_in_block = 0; ++ data->key_blk_num = data->undo_blk_num; ++ data->undo_blk_num++; ++ } ++ } ++ ++ /* Prepare superblock for write */ + channel = data->real; + block_size = channel->block_size; + +@@ -117,50 +208,92 @@ + retval = io_channel_read_blk64(channel, 1, -SUPERBLOCK_SIZE, &super); + if (retval) + goto err_out; ++ sb_crc = ext2fs_crc32c_le(~0, (unsigned char *)&super, SUPERBLOCK_SIZE); ++ super.s_magic = ~super.s_magic; + +- /* Write to tdb file in the file system byte order */ +- tdb_key.dptr = mtime_key; +- tdb_key.dsize = sizeof(mtime_key); +- tdb_data.dptr = (unsigned char *) &(super.s_mtime); +- tdb_data.dsize = sizeof(super.s_mtime); +- +- retval = tdb_store(tdb, tdb_key, tdb_data, TDB_INSERT); +- if (retval == -1) { +- retval = EXT2_ET_TDB_SUCCESS + tdb_error(tdb); ++ /* Write the undo header to disk. */ ++ memcpy(data->hdr.magic, E2UNDO_MAGIC, sizeof(data->hdr.magic)); ++ data->hdr.num_keys = ext2fs_cpu_to_le64(data->num_keys); ++ data->hdr.super_offset = ext2fs_cpu_to_le64(data->super_blk_num); ++ data->hdr.key_offset = ext2fs_cpu_to_le64(data->first_key_blk); ++ data->hdr.fs_block_size = ext2fs_cpu_to_le32(block_size); ++ data->hdr.sb_crc = ext2fs_cpu_to_le32(sb_crc); ++ hdr_crc = ext2fs_crc32c_le(~0, (unsigned char *)&data->hdr, ++ sizeof(data->hdr) - ++ sizeof(data->hdr.header_crc)); ++ data->hdr.header_crc = ext2fs_cpu_to_le32(hdr_crc); ++ retval = io_channel_write_blk64(data->undo_file, 0, ++ -(int)sizeof(data->hdr), ++ &data->hdr); ++ if (retval) + goto err_out; +- } + +- tdb_key.dptr = uuid_key; +- tdb_key.dsize = sizeof(uuid_key); +- tdb_data.dptr = (unsigned char *)&(super.s_uuid); +- tdb_data.dsize = sizeof(super.s_uuid); +- +- retval = tdb_store(tdb, tdb_key, tdb_data, TDB_INSERT); +- if (retval == -1) { +- retval = EXT2_ET_TDB_SUCCESS + tdb_error(tdb); +- } ++ /* ++ * Record the entire superblock (in FS byte order) so that we can't ++ * apply e2undo files to the wrong FS or out of order. ++ */ ++ dbg_printf("Writing superblock to block %llu\n", data->super_blk_num); ++ retval = io_channel_write_blk64(data->undo_file, data->super_blk_num, ++ -SUPERBLOCK_SIZE, &super); ++ if (retval) ++ goto err_out; + ++ if (flush) ++ retval = io_channel_flush(data->undo_file); + err_out: + io_channel_set_blksize(channel, block_size); + return retval; + } + +-static errcode_t write_block_size(TDB_CONTEXT *tdb, int block_size) ++static errcode_t undo_setup_tdb(struct undo_private_data *data) + { ++ int i; + errcode_t retval; +- TDB_DATA tdb_key, tdb_data; + +- tdb_key.dptr = blksize_key; +- tdb_key.dsize = sizeof(blksize_key); +- tdb_data.dptr = (unsigned char *)&(block_size); +- tdb_data.dsize = sizeof(block_size); +- +- retval = tdb_store(tdb, tdb_key, tdb_data, TDB_INSERT); +- if (retval == -1) { +- retval = EXT2_ET_TDB_SUCCESS + tdb_error(tdb); +- } ++ if (data->tdb_written == 1) ++ return 0; + +- return retval; ++ data->tdb_written = 1; ++ ++ /* Make a bitmap to track what we've written */ ++ memset(&data->fake_fs, 0, sizeof(data->fake_fs)); ++ data->fake_fs.blocksize = data->tdb_data_size; ++ retval = ext2fs_alloc_generic_bmap(&data->fake_fs, ++ EXT2_ET_MAGIC_BLOCK_BITMAP64, ++ EXT2FS_BMAP64_RBTREE, ++ 0, ~1ULL, ~1ULL, ++ "undo block map", &data->written_block_map); ++ if (retval) ++ return retval; ++ ++ /* Allocate key block */ ++ retval = ext2fs_get_mem(data->tdb_data_size, &data->keyb); ++ if (retval) ++ return retval; ++ data->key_blk_num = data->first_key_blk; ++ ++ /* Record block size */ ++ dbg_printf("Undo block size %llu\n", data->tdb_data_size); ++ dbg_printf("Keys per block %llu\n", KEYS_PER_BLOCK(data)); ++ data->hdr.block_size = ext2fs_cpu_to_le32(data->tdb_data_size); ++ io_channel_set_blksize(data->undo_file, data->tdb_data_size); ++ ++ /* Ensure that we have space for header blocks */ ++ for (i = 0; i <= 2; i++) { ++ retval = io_channel_read_blk64(data->undo_file, i, 1, ++ data->keyb); ++ if (retval) ++ memset(data->keyb, 0, data->tdb_data_size); ++ retval = io_channel_write_blk64(data->undo_file, i, 1, ++ data->keyb); ++ if (retval) ++ return retval; ++ retval = io_channel_flush(data->undo_file); ++ if (retval) ++ return retval; ++ } ++ memset(data->keyb, 0, data->tdb_data_size); ++ return 0; + } + + static errcode_t undo_write_tdb(io_channel channel, +@@ -172,13 +305,16 @@ + errcode_t retval = 0; + ext2_loff_t offset; + struct undo_private_data *data; +- TDB_DATA tdb_key, tdb_data; + unsigned char *read_ptr; + unsigned long long end_block; ++ unsigned long long data_size; ++ void *data_ptr; ++ struct undo_key *key; ++ __u32 blk_crc; + + data = (struct undo_private_data *) channel->private_data; + +- if (data->tdb == NULL) { ++ if (data->undo_file == NULL) { + /* + * Transaction database not initialized + */ +@@ -193,6 +329,10 @@ + else + size = count * channel->block_size; + } ++ ++ retval = undo_setup_tdb(data); ++ if (retval) ++ return retval; + /* + * Data is stored in tdb database as blocks of tdb_data_size size + * This helps in efficient lookup further. +@@ -201,21 +341,22 @@ + */ + offset = (block * channel->block_size) + data->offset ; + block_num = offset / data->tdb_data_size; +- end_block = (offset + size) / data->tdb_data_size; ++ end_block = (offset + size - 1) / data->tdb_data_size; + +- tdb_transaction_start(data->tdb); +- while (block_num <= end_block ) { ++ while (block_num <= end_block) { ++ __u32 keysz; + +- tdb_key.dptr = (unsigned char *)&block_num; +- tdb_key.dsize = sizeof(block_num); + /* + * Check if we have the record already + */ +- if (tdb_exists(data->tdb, tdb_key)) { ++ if (ext2fs_test_block_bitmap2(data->written_block_map, ++ block_num)) { + /* Try the next block */ + block_num++; + continue; + } ++ ext2fs_mark_block_bitmap2(data->written_block_map, block_num); ++ + /* + * Read one block using the backing I/O manager + * The backing I/O manager block size may be +@@ -230,7 +371,6 @@ + ((offset - data->offset) % channel->block_size); + retval = ext2fs_get_mem(count, &read_ptr); + if (retval) { +- tdb_transaction_cancel(data->tdb); + return retval; + } + +@@ -245,53 +385,81 @@ + if (retval) { + if (retval != EXT2_ET_SHORT_READ) { + free(read_ptr); +- tdb_transaction_cancel(data->tdb); + return retval; + } + /* + * short read so update the record size + * accordingly + */ +- tdb_data.dsize = actual_size; ++ data_size = actual_size; + } else { +- tdb_data.dsize = data->tdb_data_size; ++ data_size = data->tdb_data_size; + } +- tdb_data.dptr = read_ptr + +- ((offset - data->offset) % channel->block_size); +-#ifdef DEBUG +- printf("Printing with key %lld data %x and size %d\n", +- block_num, +- tdb_data.dptr, +- tdb_data.dsize); +-#endif +- if (!data->tdb_written) { +- data->tdb_written = 1; +- /* Write the blocksize to tdb file */ +- retval = write_block_size(data->tdb, +- data->tdb_data_size); +- if (retval) { +- tdb_transaction_cancel(data->tdb); +- retval = EXT2_ET_TDB_ERR_IO; +- free(read_ptr); +- return retval; +- } ++ if (data_size == 0) { ++ free(read_ptr); ++ block_num++; ++ continue; + } +- retval = tdb_store(data->tdb, tdb_key, tdb_data, TDB_INSERT); +- if (retval == -1) { +- /* +- * TDB_ERR_EXISTS cannot happen because we +- * have already verified it doesn't exist +- */ +- tdb_transaction_cancel(data->tdb); +- retval = EXT2_ET_TDB_ERR_IO; ++ dbg_printf("Read %llu bytes from FS block %llu (blk=%llu cnt=%u)\n", ++ data_size, backing_blk_num, block, count); ++ if ((data_size % data->undo_file->block_size) == 0) ++ sz = data_size / data->undo_file->block_size; ++ else ++ sz = -actual_size; ++ data_ptr = read_ptr + ((offset - data->offset) % ++ data->undo_file->block_size); ++ /* extend this key? */ ++ if (data->keys_in_block) { ++ key = data->keyb->keys + data->keys_in_block - 1; ++ keysz = ext2fs_le32_to_cpu(key->size); ++ } else { ++ key = NULL; ++ keysz = 0; ++ } ++ if (key != NULL && ++ ext2fs_le64_to_cpu(key->fsblk) + ++ ((keysz + data->tdb_data_size - 1) / ++ data->tdb_data_size) == backing_blk_num && ++ E2UNDO_MAX_EXTENT_BLOCKS * data->tdb_data_size > ++ keysz + sz) { ++ blk_crc = ext2fs_le32_to_cpu(key->blk_crc); ++ blk_crc = ext2fs_crc32c_le(blk_crc, ++ (unsigned char *)data_ptr, ++ data_size); ++ key->blk_crc = ext2fs_cpu_to_le32(blk_crc); ++ key->size = ext2fs_cpu_to_le32(keysz + data_size); ++ } else { ++ data->num_keys++; ++ key = data->keyb->keys + data->keys_in_block; ++ data->keys_in_block++; ++ key->fsblk = ext2fs_cpu_to_le64(backing_blk_num); ++ blk_crc = ext2fs_crc32c_le(~0, ++ (unsigned char *)data_ptr, ++ data_size); ++ key->blk_crc = ext2fs_cpu_to_le32(blk_crc); ++ key->size = ext2fs_cpu_to_le32(data_size); ++ } ++ dbg_printf("Writing block %llu to offset %llu size %d key %zu\n", ++ block_num, ++ data->undo_blk_num, ++ sz, data->num_keys - 1); ++ retval = io_channel_write_blk64(data->undo_file, ++ data->undo_blk_num, sz, data_ptr); ++ if (retval) { + free(read_ptr); + return retval; + } ++ data->undo_blk_num++; + free(read_ptr); ++ ++ /* Write out the key block */ ++ retval = write_undo_indexes(data, 0); ++ if (retval) ++ return retval; ++ + /* Next block */ + block_num++; + } +- tdb_transaction_commit(data->tdb); + + return retval; + } +@@ -313,10 +481,203 @@ + channel->read_error = undo_io_read_error; + } + ++static int check_filesystem(struct undo_header *hdr, io_channel undo_file, ++ unsigned int blocksize, blk64_t super_block, ++ io_channel channel) ++{ ++ struct ext2_super_block super, *sb; ++ char *buf; ++ __u32 sb_crc; ++ errcode_t retval; ++ ++ io_channel_set_blksize(channel, SUPERBLOCK_OFFSET); ++ retval = io_channel_read_blk64(channel, 1, -SUPERBLOCK_SIZE, &super); ++ if (retval) ++ return retval; ++ ++ /* ++ * Compare the FS and the undo file superblock so that we don't ++ * append to something that doesn't match this FS. ++ */ ++ retval = ext2fs_get_mem(blocksize, &buf); ++ if (retval) ++ return retval; ++ retval = io_channel_read_blk64(undo_file, super_block, ++ -SUPERBLOCK_SIZE, buf); ++ if (retval) ++ goto out; ++ sb = (struct ext2_super_block *)buf; ++ sb->s_magic = ~sb->s_magic; ++ if (memcmp(&super, buf, sizeof(super))) { ++ retval = -1; ++ goto out; ++ } ++ sb_crc = ext2fs_crc32c_le(~0, (unsigned char *)buf, SUPERBLOCK_SIZE); ++ if (ext2fs_le32_to_cpu(hdr->sb_crc) != sb_crc) { ++ retval = -1; ++ goto out; ++ } ++ ++out: ++ ext2fs_free_mem(&buf); ++ return retval; ++} ++ ++/* ++ * Try to re-open the undo file, so that we can resume where we left off. ++ * That way, the user can pass the same undo file to various programs as ++ * part of an FS upgrade instead of having to create multiple files and ++ * then apply them in correct order. ++ */ ++static errcode_t try_reopen_undo_file(int undo_fd, ++ struct undo_private_data *data) ++{ ++ struct undo_header hdr; ++ struct undo_key *dkey; ++ ext2fs_struct_stat statbuf; ++ unsigned int blocksize, fs_blocksize; ++ blk64_t super_block, lblk; ++ size_t num_keys, keys_per_block, i; ++ __u32 hdr_crc, key_crc; ++ errcode_t retval; ++ ++ /* Zero size already? */ ++ retval = ext2fs_fstat(undo_fd, &statbuf); ++ if (retval) ++ goto bad_file; ++ if (statbuf.st_size == 0) ++ goto out; ++ ++ /* check the file header */ ++ retval = io_channel_read_blk64(data->undo_file, 0, -(int)sizeof(hdr), ++ &hdr); ++ if (retval) ++ goto bad_file; ++ ++ if (memcmp(hdr.magic, E2UNDO_MAGIC, ++ sizeof(hdr.magic))) ++ goto bad_file; ++ hdr_crc = ext2fs_crc32c_le(~0, (unsigned char *)&hdr, ++ sizeof(struct undo_header) - ++ sizeof(__u32)); ++ if (ext2fs_le32_to_cpu(hdr.header_crc) != hdr_crc) ++ goto bad_file; ++ blocksize = ext2fs_le32_to_cpu(hdr.block_size); ++ fs_blocksize = ext2fs_le32_to_cpu(hdr.fs_block_size); ++ if (blocksize > E2UNDO_MAX_BLOCK_SIZE || ++ blocksize < E2UNDO_MIN_BLOCK_SIZE || ++ !blocksize || !fs_blocksize) ++ goto bad_file; ++ super_block = ext2fs_le64_to_cpu(hdr.super_offset); ++ num_keys = ext2fs_le64_to_cpu(hdr.num_keys); ++ io_channel_set_blksize(data->undo_file, blocksize); ++ if (hdr.f_compat || hdr.f_incompat || hdr.f_rocompat) ++ goto bad_file; ++ ++ /* Superblock matches this FS? */ ++ if (check_filesystem(&hdr, data->undo_file, blocksize, super_block, ++ data->real) != 0) { ++ retval = EXT2_ET_UNDO_FILE_WRONG; ++ goto out; ++ } ++ ++ /* Try to set ourselves up */ ++ data->tdb_data_size = blocksize; ++ retval = undo_setup_tdb(data); ++ if (retval) ++ goto bad_file; ++ data->num_keys = num_keys; ++ data->super_blk_num = super_block; ++ data->first_key_blk = ext2fs_le64_to_cpu(hdr.key_offset); ++ ++ /* load the written block map */ ++ keys_per_block = KEYS_PER_BLOCK(data); ++ lblk = data->first_key_blk; ++ dbg_printf("nr_keys=%lu, kpb=%zu, blksz=%u\n", ++ num_keys, keys_per_block, blocksize); ++ for (i = 0; i < num_keys; i += keys_per_block) { ++ size_t j, max_j; ++ __le32 crc; ++ ++ data->key_blk_num = lblk; ++ retval = io_channel_read_blk64(data->undo_file, ++ lblk, 1, data->keyb); ++ if (retval) ++ goto bad_key_replay; ++ ++ /* check keys */ ++ if (ext2fs_le32_to_cpu(data->keyb->magic) != KEYBLOCK_MAGIC) { ++ retval = EXT2_ET_UNDO_FILE_CORRUPT; ++ goto bad_key_replay; ++ } ++ crc = data->keyb->crc; ++ data->keyb->crc = 0; ++ key_crc = ext2fs_crc32c_le(~0, (unsigned char *)data->keyb, ++ blocksize); ++ if (ext2fs_le32_to_cpu(crc) != key_crc) { ++ retval = EXT2_ET_UNDO_FILE_CORRUPT; ++ goto bad_key_replay; ++ } ++ ++ /* load keys from key block */ ++ lblk++; ++ max_j = data->num_keys - i; ++ if (max_j > keys_per_block) ++ max_j = keys_per_block; ++ for (j = 0, dkey = data->keyb->keys; ++ j < max_j; ++ j++, dkey++) { ++ blk64_t fsblk = ext2fs_le64_to_cpu(dkey->fsblk); ++ blk64_t undo_blk = fsblk * fs_blocksize / blocksize; ++ size_t size = ext2fs_le32_to_cpu(dkey->size); ++ ++ ext2fs_mark_block_bitmap_range2(data->written_block_map, ++ undo_blk, ++ (size + blocksize - 1) / blocksize); ++ lblk += (size + blocksize - 1) / blocksize; ++ data->undo_blk_num = lblk; ++ data->keys_in_block = j + 1; ++ } ++ } ++ dbg_printf("Reopen undo, keyblk=%llu undoblk=%llu nrkeys=%zu kib=%zu\n", ++ data->key_blk_num, data->undo_blk_num, data->num_keys, ++ data->keys_in_block); ++ ++ data->hdr.state = hdr.state & ~E2UNDO_STATE_FINISHED; ++ data->hdr.f_compat = hdr.f_compat; ++ data->hdr.f_incompat = hdr.f_incompat; ++ data->hdr.f_rocompat = hdr.f_rocompat; ++ return retval; ++ ++bad_key_replay: ++ data->key_blk_num = data->undo_blk_num = 0; ++ data->keys_in_block = 0; ++ ext2fs_free_mem(&data->keyb); ++ ext2fs_free_generic_bitmap(data->written_block_map); ++ data->tdb_written = 0; ++ goto out; ++bad_file: ++ retval = EXT2_ET_UNDO_FILE_CORRUPT; ++out: ++ return retval; ++} ++ ++static void undo_atexit(void *p) ++{ ++ struct undo_private_data *data = p; ++ errcode_t err; ++ ++ err = write_undo_indexes(data, 1); ++ io_channel_close(data->undo_file); ++ ++ com_err(data->tdb_file, err, "while force-closing undo file"); ++} ++ + static errcode_t undo_open(const char *name, int flags, io_channel *channel) + { + io_channel io = NULL; + struct undo_private_data *data = NULL; ++ int undo_fd = -1; + errcode_t retval; + + if (name == 0) +@@ -344,23 +705,37 @@ + + memset(data, 0, sizeof(struct undo_private_data)); + data->magic = EXT2_ET_MAGIC_UNIX_IO_CHANNEL; ++ data->super_blk_num = 1; ++ data->first_key_blk = 2; ++ data->undo_blk_num = 3; + + if (undo_io_backing_manager) { + retval = undo_io_backing_manager->open(name, flags, + &data->real); + if (retval) + goto cleanup; ++ ++ data->tdb_file = strdup(tdb_file); ++ if (data->tdb_file == NULL) ++ goto cleanup; ++ undo_fd = ext2fs_open_file(data->tdb_file, O_RDWR | O_CREAT, ++ 0600); ++ if (undo_fd < 0) ++ goto cleanup; ++ ++ retval = undo_io_backing_manager->open(data->tdb_file, ++ IO_FLAG_RW, ++ &data->undo_file); ++ if (retval) ++ goto cleanup; + } else { +- data->real = 0; ++ data->real = NULL; ++ data->undo_file = NULL; + } + +- /* setup the tdb file */ +- data->tdb = tdb_open(tdb_file, 0, TDB_CLEAR_IF_FIRST, +- O_RDWR | O_CREAT | O_TRUNC | O_EXCL, 0600); +- if (!data->tdb) { +- retval = errno; +- goto cleanup; +- } ++ if (data->real) ++ io->flags = (io->flags & ~CHANNEL_FLAGS_DISCARD_ZEROES) | ++ (data->real->flags & CHANNEL_FLAGS_DISCARD_ZEROES); + + /* + * setup err handler for read so that we know +@@ -369,10 +744,28 @@ + if (data->real) + undo_err_handler_init(data->real); + ++ if (data->undo_file) { ++ retval = try_reopen_undo_file(undo_fd, data); ++ if (retval) ++ goto cleanup; ++ } ++ retval = ext2fs_add_exit_fn(undo_atexit, data); ++ if (retval) ++ goto cleanup; ++ + *channel = io; +- return 0; ++ if (undo_fd >= 0) ++ close(undo_fd); ++ return retval; + + cleanup: ++ ext2fs_remove_exit_fn(undo_atexit, data); ++ if (undo_fd >= 0) ++ close(undo_fd); ++ if (data && data->undo_file) ++ io_channel_close(data->undo_file); ++ if (data && data->tdb_file) ++ free(data->tdb_file); + if (data && data->real) + io_channel_close(data->real); + if (data) +@@ -385,7 +778,7 @@ + static errcode_t undo_close(io_channel channel) + { + struct undo_private_data *data; +- errcode_t retval = 0; ++ errcode_t err, retval = 0; + + EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); + data = (struct undo_private_data *) channel->private_data; +@@ -394,18 +787,26 @@ + if (--channel->refcount > 0) + return 0; + /* Before closing write the file system identity */ +- retval = write_file_system_identity(channel, data->tdb); +- if (retval) +- return retval; ++ if (!getenv("UNDO_IO_SIMULATE_UNFINISHED")) ++ data->hdr.state = ext2fs_cpu_to_le32(E2UNDO_STATE_FINISHED); ++ err = write_undo_indexes(data, 1); ++ ext2fs_remove_exit_fn(undo_atexit, data); + if (data->real) + retval = io_channel_close(data->real); +- if (data->tdb) +- tdb_close(data->tdb); ++ if (data->tdb_file) ++ free(data->tdb_file); ++ if (data->undo_file) ++ io_channel_close(data->undo_file); ++ ext2fs_free_mem(&data->keyb); ++ if (data->written_block_map) ++ ext2fs_free_generic_bitmap(data->written_block_map); + ext2fs_free_mem(&channel->private_data); + if (channel->name) + ext2fs_free_mem(&channel->name); + ext2fs_free_mem(&channel); + ++ if (err) ++ return err; + return retval; + } + +@@ -418,14 +819,16 @@ + data = (struct undo_private_data *) channel->private_data; + EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL); + ++ if (blksize > E2UNDO_MAX_BLOCK_SIZE || blksize < E2UNDO_MIN_BLOCK_SIZE) ++ return EXT2_ET_INVALID_ARGUMENT; ++ + if (data->real) + retval = io_channel_set_blksize(data->real, blksize); + /* + * Set the block size used for tdb + */ +- if (!data->tdb_data_size) { ++ if (!data->tdb_data_size || !data->tdb_written) + data->tdb_data_size = blksize; +- } + channel->block_size = blksize; + return retval; + } +@@ -510,6 +913,77 @@ + return retval; + } + ++static errcode_t undo_discard(io_channel channel, unsigned long long block, ++ unsigned long long count) ++{ ++ struct undo_private_data *data; ++ errcode_t retval = 0; ++ int icount; ++ ++ EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); ++ data = (struct undo_private_data *) channel->private_data; ++ EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL); ++ ++ if (count > INT_MAX) ++ return EXT2_ET_UNIMPLEMENTED; ++ icount = count; ++ ++ /* ++ * First write the existing content into database ++ */ ++ retval = undo_write_tdb(channel, block, icount); ++ if (retval) ++ return retval; ++ if (data->real) ++ retval = io_channel_discard(data->real, block, count); ++ ++ return retval; ++} ++ ++static errcode_t undo_zeroout(io_channel channel, unsigned long long block, ++ unsigned long long count) ++{ ++ struct undo_private_data *data; ++ errcode_t retval = 0; ++ int icount; ++ ++ EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); ++ data = (struct undo_private_data *) channel->private_data; ++ EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL); ++ ++ if (count > INT_MAX) ++ return EXT2_ET_UNIMPLEMENTED; ++ icount = count; ++ ++ /* ++ * First write the existing content into database ++ */ ++ retval = undo_write_tdb(channel, block, icount); ++ if (retval) ++ return retval; ++ if (data->real) ++ retval = io_channel_zeroout(data->real, block, count); ++ ++ return retval; ++} ++ ++static errcode_t undo_cache_readahead(io_channel channel, ++ unsigned long long block, ++ unsigned long long count) ++{ ++ struct undo_private_data *data; ++ errcode_t retval = 0; ++ ++ EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); ++ data = (struct undo_private_data *) channel->private_data; ++ EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL); ++ ++ if (data->real) ++ retval = io_channel_cache_readahead(data->real, block, count); ++ ++ return retval; ++} ++ + /* + * Flush data buffers to disk. + */ +@@ -547,7 +1021,10 @@ + tmp = strtoul(arg, &end, 0); + if (*end) + return EXT2_ET_INVALID_ARGUMENT; ++ if (tmp > E2UNDO_MAX_BLOCK_SIZE || tmp < E2UNDO_MIN_BLOCK_SIZE) ++ return EXT2_ET_INVALID_ARGUMENT; + if (!data->tdb_data_size || !data->tdb_written) { ++ data->tdb_written = -1; + data->tdb_data_size = tmp; + } + return 0; +@@ -601,6 +1078,9 @@ + .get_stats = undo_get_stats, + .read_blk64 = undo_read_blk64, + .write_blk64 = undo_write_blk64, ++ .discard = undo_discard, ++ .zeroout = undo_zeroout, ++ .cache_readahead = undo_cache_readahead, + }; + + io_manager undo_io_manager = &struct_undo_manager; +--- a/lib/ext2fs/unix_io.c ++++ b/lib/ext2fs/unix_io.c +@@ -15,8 +15,15 @@ + * %End-Header% + */ + ++#define _XOPEN_SOURCE 600 ++#define _DARWIN_C_SOURCE ++#define _FILE_OFFSET_BITS 64 ++#ifndef _LARGEFILE_SOURCE + #define _LARGEFILE_SOURCE ++#endif ++#ifndef _LARGEFILE64_SOURCE + #define _LARGEFILE64_SOURCE ++#endif + #ifndef _GNU_SOURCE + #define _GNU_SOURCE + #endif +@@ -35,6 +42,9 @@ + #ifdef __linux__ + #include + #endif ++#if HAVE_SYS_TYPES_H ++#include ++#endif + #ifdef HAVE_SYS_IOCTL_H + #include + #endif +@@ -44,9 +54,6 @@ + #if HAVE_SYS_STAT_H + #include + #endif +-#if HAVE_SYS_TYPES_H +-#include +-#endif + #if HAVE_SYS_RESOURCE_H + #include + #endif +@@ -831,6 +838,23 @@ + #endif /* NO_IO_CACHE */ + } + ++static errcode_t unix_cache_readahead(io_channel channel, ++ unsigned long long block, ++ unsigned long long count) ++{ ++#ifdef POSIX_FADV_WILLNEED ++ struct unix_private_data *data; ++ ++ data = (struct unix_private_data *)channel->private_data; ++ return posix_fadvise(data->dev, ++ (ext2_loff_t)block * channel->block_size, ++ (ext2_loff_t)count * channel->block_size, ++ POSIX_FADV_WILLNEED); ++#else ++ return EXT2_ET_OP_NOT_SUPPORTED; ++#endif ++} ++ + static errcode_t unix_write_blk(io_channel channel, unsigned long block, + int count, const void *buf) + { +@@ -967,6 +991,76 @@ + return EXT2_ET_UNIMPLEMENTED; + } + ++/* parameters might not be used if OS doesn't support zeroout */ ++#pragma GCC diagnostic push ++#pragma GCC diagnostic ignored "-Wunused-parameter" ++static errcode_t unix_zeroout(io_channel channel, unsigned long long block, ++ unsigned long long count) ++{ ++ struct unix_private_data *data; ++ int ret; ++ ++ EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); ++ data = (struct unix_private_data *) channel->private_data; ++ EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL); ++ ++ if (getenv("UNIX_IO_NOZEROOUT")) ++ goto unimplemented; ++ ++ if (channel->flags & CHANNEL_FLAGS_BLOCK_DEVICE) { ++ /* Not implemented until the BLKZEROOUT mess is fixed */ ++ goto unimplemented; ++ } else { ++ /* Regular file, try to use truncate/punch/zero. */ ++ struct stat statbuf; ++ ++ if (count == 0) ++ return 0; ++ /* ++ * If we're trying to zero a range past the end of the file, ++ * extend the file size, then truncate everything. ++ */ ++ ret = fstat(data->dev, &statbuf); ++ if (ret) ++ goto err; ++ if (statbuf.st_size < (block + count) * channel->block_size) { ++ ret = ftruncate(data->dev, ++ (block + count) * channel->block_size); ++ if (ret) ++ goto err; ++ } ++#if defined(HAVE_FALLOCATE) && (defined(FALLOC_FL_ZERO_RANGE) || \ ++ (defined(FALLOC_FL_PUNCH_HOLE) && defined(FALLOC_FL_KEEP_SIZE))) ++#if defined(FALLOC_FL_PUNCH_HOLE) && defined(FALLOC_FL_KEEP_SIZE) ++ ret = fallocate(data->dev, ++ FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, ++ (off_t)(block) * channel->block_size, ++ (off_t)(count) * channel->block_size); ++ if (ret == 0) ++ goto err; ++#endif ++#ifdef FALLOC_FL_ZERO_RANGE ++ ret = fallocate(data->dev, ++ FALLOC_FL_ZERO_RANGE, ++ (off_t)(block) * channel->block_size, ++ (off_t)(count) * channel->block_size); ++#endif ++#else ++ goto unimplemented; ++#endif /* HAVE_FALLOCATE && (ZERO_RANGE || (PUNCH_HOLE && KEEP_SIZE)) */ ++ } ++err: ++ if (ret < 0) { ++ if (errno == EOPNOTSUPP) ++ goto unimplemented; ++ return errno; ++ } ++ return 0; ++unimplemented: ++ return EXT2_ET_UNIMPLEMENTED; ++} ++#pragma GCC diagnostic pop ++ + static struct struct_io_manager struct_unix_manager = { + .magic = EXT2_ET_MAGIC_IO_MANAGER, + .name = "Unix I/O Manager", +@@ -982,6 +1076,8 @@ + .read_blk64 = unix_read_blk64, + .write_blk64 = unix_write_blk64, + .discard = unix_discard, ++ .cache_readahead = unix_cache_readahead, ++ .zeroout = unix_zeroout, + }; + + io_manager unix_io_manager = &struct_unix_manager; +--- a/lib/ext2fs/unlink.c ++++ b/lib/ext2fs/unlink.c +@@ -44,9 +44,9 @@ + 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) { +--- a/lib/ext2fs/valid_blk.c ++++ b/lib/ext2fs/valid_blk.c +@@ -52,6 +52,13 @@ + 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; + } + +--- a/lib/quota/common.h ++++ /dev/null +@@ -1,36 +0,0 @@ +-/* +- * +- * Various things common for all utilities +- * +- */ +- +-#ifndef __QUOTA_COMMON_H__ +-#define __QUOTA_COMMON_H__ +- +-#if EXT2_FLAT_INCLUDES +-#include "e2_types.h" +-#else +-#include +-#endif /* EXT2_FLAT_INCLUDES */ +- +-/* #define DEBUG_QUOTA 1 */ +- +-#ifndef __attribute__ +-# if !defined __GNUC__ || __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 8) || __STRICT_ANSI__ +-# define __attribute__(x) +-# endif +-#endif +- +-#define log_err(format, arg ...) \ +- fprintf(stderr, "[ERROR] %s:%d:%s:: " format "\n", \ +- __FILE__, __LINE__, __func__, ## arg) +- +-#ifdef DEBUG_QUOTA +-# define log_debug(format, arg ...) \ +- fprintf(stderr, "[DEBUG] %s:%d:%s:: " format "\n", \ +- __FILE__, __LINE__, __func__, ## arg) +-#else +-# define log_debug(format, ...) +-#endif +- +-#endif /* __QUOTA_COMMON_H__ */ +--- a/lib/quota/dqblk_v2.h ++++ /dev/null +@@ -1,31 +0,0 @@ +-/* +- * Header file for disk format of new quotafile format +- * +- * Jan Kara - sponsored by SuSE CR +- */ +- +-#ifndef __QUOTA_DQBLK_V2_H__ +-#define __QUOTA_DQBLK_V2_H__ +- +-#include "quotaio_tree.h" +- +-/* Structure for format specific information */ +-struct v2_mem_dqinfo { +- struct qtree_mem_dqinfo dqi_qtree; +- unsigned int dqi_flags; /* Flags set in quotafile */ +- unsigned int dqi_used_entries; /* Number of entries in file - +- updated by scan_dquots */ +- unsigned int dqi_data_blocks; /* Number of data blocks in file - +- updated by scan_dquots */ +-}; +- +-struct v2_mem_dqblk { +- long long dqb_off; /* Offset of dquot in file */ +-}; +- +-struct quotafile_ops; /* Will be defined later in quotaio.h */ +- +-/* Operations above this format */ +-extern struct quotafile_ops quotafile_ops_2; +- +-#endif /* __QUOTA_DQBLK_V2_H__ */ +--- a/lib/quota/Makefile.in ++++ /dev/null +@@ -1,131 +0,0 @@ +-# Makefile for the QUOTA library +-# +- +-srcdir = @srcdir@ +-top_srcdir = @top_srcdir@ +-VPATH = @srcdir@ +-top_builddir = ../.. +-my_dir = lib/quota +-INSTALL = @INSTALL@ +- +-@MCONFIG@ +- +-all:: +- +-OBJS= mkquota.o quotaio.o quotaio_v2.o quotaio_tree.o dict.o +- +-SRCS= $(srcdir)/mkquota.c \ +- $(srcdir)/quotaio.c \ +- $(srcdir)/quotaio_tree.c \ +- $(srcdir)/quotaio_v2.c \ +- $(srcdir)/../../e2fsck/dict.c +- +-LIBRARY= libquota +-LIBDIR= quota +- +-#ELF_VERSION = 1.0 +-#ELF_SO_VERSION = 1 +-#ELF_IMAGE = libquota +-#ELF_MYDIR = quota +-#ELF_INSTALL_DIR = $(root_libdir) +-#ELF_OTHER_LIBS = -lext2fs +- +-#BSDLIB_VERSION = 1.0 +-#BSDLIB_IMAGE = libquota +-#BSDLIB_MYDIR = quota +-#BSDLIB_INSTALL_DIR = $(root_libdir) +- +-@MAKEFILE_LIBRARY@ +-#MAKEFILE_ELF# +-#MAKEFILE_BSDLIB# +-@MAKEFILE_PROFILE@ +- +-.c.o: +- $(E) " CC $<" +- $(Q) $(CC) $(ALL_CFLAGS) -c $< -o $@ +- $(Q) $(CHECK_CMD) $(ALL_CFLAGS) $< +-@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 $< +- +-dict.o: +- $(E) " CC $<" +- $(Q) $(CC) -c $(ALL_CFLAGS) $(top_srcdir)/e2fsck/dict.c -o $@ +-@PROFILE_CMT@ $(Q) $(CC) $(ALL_CFLAGS) -g -pg -o profiled/dict.o -c \ +-@PROFILE_CMT@ $(top_srcdir)/e2fsck/dict.c +-#ELF_CMT# $(Q) $(CC) $(ALL_CFLAGS) -fPIC -o elfshared/$*.o -c \ +-#ELF_CMT# $(top_srcdir)/e2fsck/dict.c +-#BSDLIB_CMT# $(Q) $(CC) $(ALL_CFLAGS) $(BSDLIB_PIC_FLAG) -o pic/$*.o -c \ +-#BSDLIB_CMT# $(top_srcdir)/e2fsck/dict.c +- +-installdirs:: +- +-install:: all +- +-uninstall:: +- +-clean:: +- $(RM) -f \#* *.s *.o *.a *~ *.bak core profiled/* +- $(RM) -f ../libquota.a ../libquota_p.a $(SMANPAGES) +- +-#check:: tst_uuid +-# LD_LIBRARY_PATH=$(LIB) DYLD_LIBRARY_PATH=$(LIB) ./tst_uuid +- +-mostlyclean:: clean +-distclean:: clean +- $(RM) -f .depend Makefile \ +- $(srcdir)/TAGS $(srcdir)/Makefile.in.old +- +-# +-# Hack to parallel makes recognize dependencies correctly. +-# +-../../lib/libquota.a: libquota.a +-../../lib/libquota.so: image +-../../lib/libquota.dylib: image +- +-$(OBJS): +- +-# +++ Dependency line eater +++ +-# +-# Makefile dependencies follow. This must be the last section in +-# the Makefile.in file +-# +-mkquota.o: $(srcdir)/mkquota.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 \ +- $(top_srcdir)/lib/e2p/e2p.h $(srcdir)/quotaio.h $(srcdir)/dqblk_v2.h \ +- $(srcdir)/quotaio_tree.h $(top_srcdir)/lib/../e2fsck/dict.h \ +- $(srcdir)/quotaio_v2.h $(srcdir)/common.h +-quotaio.o: $(srcdir)/quotaio.c $(top_builddir)/lib/config.h \ +- $(top_builddir)/lib/dirpaths.h $(srcdir)/common.h \ +- $(top_builddir)/lib/ext2fs/ext2_types.h $(srcdir)/quotaio.h \ +- $(top_srcdir)/lib/ext2fs/ext2_fs.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)/dqblk_v2.h $(srcdir)/quotaio_tree.h \ +- $(top_srcdir)/lib/../e2fsck/dict.h +-quotaio_tree.o: $(srcdir)/quotaio_tree.c $(top_builddir)/lib/config.h \ +- $(top_builddir)/lib/dirpaths.h $(srcdir)/common.h \ +- $(top_builddir)/lib/ext2fs/ext2_types.h $(srcdir)/quotaio_tree.h \ +- $(srcdir)/quotaio.h $(top_srcdir)/lib/ext2fs/ext2_fs.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)/dqblk_v2.h $(top_srcdir)/lib/../e2fsck/dict.h +-quotaio_v2.o: $(srcdir)/quotaio_v2.c $(top_builddir)/lib/config.h \ +- $(top_builddir)/lib/dirpaths.h $(srcdir)/common.h \ +- $(top_builddir)/lib/ext2fs/ext2_types.h $(srcdir)/quotaio_v2.h \ +- $(srcdir)/quotaio.h $(top_srcdir)/lib/ext2fs/ext2_fs.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)/dqblk_v2.h $(srcdir)/quotaio_tree.h \ +- $(top_srcdir)/lib/../e2fsck/dict.h +-dict.o: $(srcdir)/../../e2fsck/dict.c $(top_builddir)/lib/config.h \ +- $(top_builddir)/lib/dirpaths.h $(srcdir)/../../e2fsck/dict.h +--- a/lib/quota/mkquota.c ++++ /dev/null +@@ -1,630 +0,0 @@ +-/* +- * mkquota.c --- create quota files for a filesystem +- * +- * Aditya Kali +- */ +-#include "config.h" +-#include +-#include +-#include +-#include +-#include +-#include +- +-#include "ext2fs/ext2_fs.h" +-#include "ext2fs/ext2fs.h" +-#include "e2p/e2p.h" +- +-#include "quotaio.h" +-#include "quotaio_v2.h" +-#include "quotaio_tree.h" +-#include "common.h" +- +-/* Needed for architectures where sizeof(int) != sizeof(void *) */ +-#define UINT_TO_VOIDPTR(val) ((void *)(intptr_t)(val)) +-#define VOIDPTR_TO_UINT(ptr) ((unsigned int)(intptr_t)(ptr)) +- +-#if DEBUG_QUOTA +-static void print_inode(struct ext2_inode *inode) +-{ +- if (!inode) +- return; +- +- fprintf(stderr, " i_mode = %d\n", inode->i_mode); +- fprintf(stderr, " i_uid = %d\n", inode->i_uid); +- fprintf(stderr, " i_size = %d\n", inode->i_size); +- fprintf(stderr, " i_atime = %d\n", inode->i_atime); +- fprintf(stderr, " i_ctime = %d\n", inode->i_ctime); +- fprintf(stderr, " i_mtime = %d\n", inode->i_mtime); +- fprintf(stderr, " i_dtime = %d\n", inode->i_dtime); +- fprintf(stderr, " i_gid = %d\n", inode->i_gid); +- fprintf(stderr, " i_links_count = %d\n", inode->i_links_count); +- fprintf(stderr, " i_blocks = %d\n", inode->i_blocks); +- fprintf(stderr, " i_flags = %d\n", inode->i_flags); +- +- return; +-} +- +-static void print_dquot(const char *desc, struct dquot *dq) +-{ +- if (desc) +- fprintf(stderr, "%s: ", desc); +- fprintf(stderr, "%u %lld:%lld:%lld %lld:%lld:%lld\n", +- dq->dq_id, dq->dq_dqb.dqb_curspace, +- dq->dq_dqb.dqb_bsoftlimit, dq->dq_dqb.dqb_bhardlimit, +- dq->dq_dqb.dqb_curinodes, +- dq->dq_dqb.dqb_isoftlimit, dq->dq_dqb.dqb_ihardlimit); +-} +-#else +-static void print_dquot(const char *desc, struct dquot *dq) +-{ +-} +-#endif +- +-/* +- * Returns 0 if not able to find the quota file, otherwise returns its +- * inode number. +- */ +-int quota_file_exists(ext2_filsys fs, int qtype, int fmt) +-{ +- char qf_name[256]; +- errcode_t ret; +- ext2_ino_t ino; +- +- if (qtype >= MAXQUOTAS) +- return -EINVAL; +- +- quota_get_qf_name(qtype, QFMT_VFS_V1, qf_name); +- +- ret = ext2fs_lookup(fs, EXT2_ROOT_INO, qf_name, strlen(qf_name), 0, +- &ino); +- if (ret) +- return 0; +- +- return ino; +-} +- +-/* +- * Set the value for reserved quota inode number field in superblock. +- */ +-void quota_set_sb_inum(ext2_filsys fs, ext2_ino_t ino, int qtype) +-{ +- ext2_ino_t *inump; +- +- inump = (qtype == USRQUOTA) ? &fs->super->s_usr_quota_inum : +- &fs->super->s_grp_quota_inum; +- +- log_debug("setting quota ino in superblock: ino=%u, type=%d", ino, +- qtype); +- *inump = ino; +- ext2fs_mark_super_dirty(fs); +-} +- +-errcode_t quota_remove_inode(ext2_filsys fs, int qtype) +-{ +- ext2_ino_t qf_ino; +- errcode_t retval; +- +- retval = ext2fs_read_bitmaps(fs); +- if (retval) { +- log_err("Couldn't read bitmaps: %s", error_message(retval)); +- return retval; +- } +- qf_ino = (qtype == USRQUOTA) ? fs->super->s_usr_quota_inum : +- fs->super->s_grp_quota_inum; +- quota_set_sb_inum(fs, 0, qtype); +- /* Truncate the inode only if its a reserved one. */ +- if (qf_ino < EXT2_FIRST_INODE(fs->super)) +- quota_inode_truncate(fs, qf_ino); +- +- ext2fs_mark_super_dirty(fs); +- fs->flags &= ~EXT2_FLAG_SUPER_ONLY; +- retval = ext2fs_write_bitmaps(fs); +- if (retval) { +- log_err("Couldn't write bitmaps: %s", error_message(retval)); +- return retval; +- } +- return 0; +-} +- +-static void write_dquots(dict_t *dict, struct quota_handle *qh) +-{ +- dnode_t *n; +- struct dquot *dq; +- +- for (n = dict_first(dict); n; n = dict_next(dict, n)) { +- dq = dnode_get(n); +- if (dq) { +- print_dquot("write", dq); +- dq->dq_h = qh; +- update_grace_times(dq); +- qh->qh_ops->commit_dquot(dq); +- } +- } +-} +- +-errcode_t quota_write_inode(quota_ctx_t qctx, int qtype) +-{ +- int retval = 0, i; +- dict_t *dict; +- ext2_filsys fs; +- struct quota_handle *h = NULL; +- int fmt = QFMT_VFS_V1; +- +- if (!qctx) +- return 0; +- +- fs = qctx->fs; +- retval = ext2fs_get_mem(sizeof(struct quota_handle), &h); +- if (retval) { +- log_err("Unable to allocate quota handle: %s", +- error_message(retval)); +- goto out; +- } +- +- retval = ext2fs_read_bitmaps(fs); +- if (retval) { +- log_err("Couldn't read bitmaps: %s", error_message(retval)); +- goto out; +- } +- +- for (i = 0; i < MAXQUOTAS; i++) { +- if ((qtype != -1) && (i != qtype)) +- continue; +- +- dict = qctx->quota_dict[i]; +- if (!dict) +- continue; +- +- retval = quota_file_create(h, fs, i, fmt); +- if (retval < 0) { +- log_err("Cannot initialize io on quotafile"); +- continue; +- } +- +- write_dquots(dict, h); +- retval = quota_file_close(qctx, h); +- if (retval < 0) { +- log_err("Cannot finish IO on new quotafile: %s", +- strerror(errno)); +- if (h->qh_qf.e2_file) +- ext2fs_file_close(h->qh_qf.e2_file); +- quota_inode_truncate(fs, h->qh_qf.ino); +- continue; +- } +- +- /* Set quota inode numbers in superblock. */ +- quota_set_sb_inum(fs, h->qh_qf.ino, i); +- ext2fs_mark_super_dirty(fs); +- ext2fs_mark_bb_dirty(fs); +- fs->flags &= ~EXT2_FLAG_SUPER_ONLY; +- } +- +- retval = ext2fs_write_bitmaps(fs); +- if (retval) { +- log_err("Couldn't write bitmaps: %s", error_message(retval)); +- goto out; +- } +-out: +- if (h) +- ext2fs_free_mem(&h); +- return retval; +-} +- +-/******************************************************************/ +-/* Helper functions for computing quota in memory. */ +-/******************************************************************/ +- +-static int dict_uint_cmp(const void *a, const void *b) +-{ +- unsigned int c, d; +- +- c = VOIDPTR_TO_UINT(a); +- d = VOIDPTR_TO_UINT(b); +- +- if (c == d) +- return 0; +- else if (c > d) +- return 1; +- else +- return -1; +-} +- +-static inline qid_t get_qid(struct ext2_inode *inode, int qtype) +-{ +- if (qtype == USRQUOTA) +- return inode_uid(*inode); +- return inode_gid(*inode); +-} +- +-static void quota_dnode_free(dnode_t *node, +- void *context EXT2FS_ATTR((unused))) +-{ +- void *ptr = node ? dnode_get(node) : 0; +- +- ext2fs_free_mem(&ptr); +- free(node); +-} +- +-/* +- * Set up the quota tracking data structures. +- */ +-errcode_t quota_init_context(quota_ctx_t *qctx, ext2_filsys fs, int qtype) +-{ +- errcode_t err; +- dict_t *dict; +- quota_ctx_t ctx; +- int i; +- +- err = ext2fs_get_mem(sizeof(struct quota_ctx), &ctx); +- if (err) { +- log_err("Failed to allocate quota context"); +- return err; +- } +- +- memset(ctx, 0, sizeof(struct quota_ctx)); +- for (i = 0; i < MAXQUOTAS; i++) { +- ctx->quota_file[i] = NULL; +- if ((qtype != -1) && (i != qtype)) +- continue; +- err = ext2fs_get_mem(sizeof(dict_t), &dict); +- if (err) { +- log_err("Failed to allocate dictionary"); +- quota_release_context(&ctx); +- return err; +- } +- ctx->quota_dict[i] = dict; +- dict_init(dict, DICTCOUNT_T_MAX, dict_uint_cmp); +- dict_set_allocator(dict, NULL, quota_dnode_free, NULL); +- } +- +- ctx->fs = fs; +- *qctx = ctx; +- return 0; +-} +- +-void quota_release_context(quota_ctx_t *qctx) +-{ +- errcode_t err; +- dict_t *dict; +- int i; +- quota_ctx_t ctx; +- +- if (!qctx) +- return; +- +- ctx = *qctx; +- for (i = 0; i < MAXQUOTAS; i++) { +- dict = ctx->quota_dict[i]; +- ctx->quota_dict[i] = 0; +- if (dict) { +- dict_free_nodes(dict); +- free(dict); +- } +- if (ctx->quota_file[i]) { +- err = quota_file_close(ctx, ctx->quota_file[i]); +- if (err) { +- log_err("Cannot close quotafile: %s", +- strerror(errno)); +- ext2fs_free_mem(&ctx->quota_file[i]); +- } +- } +- } +- *qctx = NULL; +- free(ctx); +-} +- +-static struct dquot *get_dq(dict_t *dict, __u32 key) +-{ +- struct dquot *dq; +- dnode_t *n; +- +- n = dict_lookup(dict, UINT_TO_VOIDPTR(key)); +- if (n) +- dq = dnode_get(n); +- else { +- if (ext2fs_get_mem(sizeof(struct dquot), &dq)) { +- log_err("Unable to allocate dquot"); +- return NULL; +- } +- memset(dq, 0, sizeof(struct dquot)); +- dict_alloc_insert(dict, UINT_TO_VOIDPTR(key), dq); +- dq->dq_id = key; +- } +- return dq; +-} +- +- +-/* +- * Called to update the blocks used by a particular inode +- */ +-void quota_data_add(quota_ctx_t qctx, struct ext2_inode *inode, ext2_ino_t ino, +- qsize_t space) +-{ +- struct dquot *dq; +- dict_t *dict; +- int i; +- +- if (!qctx) +- return; +- +- log_debug("ADD_DATA: Inode: %u, UID/GID: %u/%u, space: %ld", ino, +- inode_uid(*inode), +- inode_gid(*inode), space); +- for (i = 0; i < MAXQUOTAS; i++) { +- dict = qctx->quota_dict[i]; +- if (dict) { +- dq = get_dq(dict, get_qid(inode, i)); +- if (dq) +- dq->dq_dqb.dqb_curspace += space; +- } +- } +-} +- +-/* +- * Called to remove some blocks used by a particular inode +- */ +-void quota_data_sub(quota_ctx_t qctx, struct ext2_inode *inode, ext2_ino_t ino, +- qsize_t space) +-{ +- struct dquot *dq; +- dict_t *dict; +- int i; +- +- if (!qctx) +- return; +- +- log_debug("SUB_DATA: Inode: %u, UID/GID: %u/%u, space: %ld", ino, +- inode_uid(*inode), +- inode_gid(*inode), space); +- for (i = 0; i < MAXQUOTAS; i++) { +- dict = qctx->quota_dict[i]; +- if (dict) { +- dq = get_dq(dict, get_qid(inode, i)); +- dq->dq_dqb.dqb_curspace -= space; +- } +- } +-} +- +-/* +- * Called to count the files used by an inode's user/group +- */ +-void quota_data_inodes(quota_ctx_t qctx, struct ext2_inode *inode, +- ext2_ino_t ino, int adjust) +-{ +- struct dquot *dq; +- dict_t *dict; +- int i; +- +- if (!qctx) +- return; +- +- log_debug("ADJ_INODE: Inode: %u, UID/GID: %u/%u, adjust: %d", ino, +- inode_uid(*inode), +- inode_gid(*inode), adjust); +- for (i = 0; i < MAXQUOTAS; i++) { +- dict = qctx->quota_dict[i]; +- if (dict) { +- dq = get_dq(dict, get_qid(inode, i)); +- dq->dq_dqb.dqb_curinodes += adjust; +- } +- } +-} +- +-errcode_t quota_compute_usage(quota_ctx_t qctx) +-{ +- ext2_filsys fs; +- ext2_ino_t ino; +- errcode_t ret; +- struct ext2_inode inode; +- qsize_t space; +- ext2_inode_scan scan; +- +- if (!qctx) +- return 0; +- +- fs = qctx->fs; +- ret = ext2fs_open_inode_scan(fs, 0, &scan); +- if (ret) { +- log_err("while opening inode scan. ret=%ld", ret); +- return ret; +- } +- +- while (1) { +- ret = ext2fs_get_next_inode(scan, &ino, &inode); +- if (ret) { +- log_err("while getting next inode. ret=%ld", ret); +- ext2fs_close_inode_scan(scan); +- return ret; +- } +- if (ino == 0) +- break; +- if (inode.i_links_count && +- (ino == EXT2_ROOT_INO || +- ino >= EXT2_FIRST_INODE(fs->super))) { +- space = ext2fs_inode_i_blocks(fs, &inode) << 9; +- quota_data_add(qctx, &inode, ino, space); +- quota_data_inodes(qctx, &inode, ino, +1); +- } +- } +- +- ext2fs_close_inode_scan(scan); +- +- return 0; +-} +- +-struct scan_dquots_data { +- dict_t *quota_dict; +- int update_limits; /* update limits from disk */ +- int update_usage; +- int usage_is_inconsistent; +-}; +- +-static int scan_dquots_callback(struct dquot *dquot, void *cb_data) +-{ +- struct scan_dquots_data *scan_data = cb_data; +- dict_t *quota_dict = scan_data->quota_dict; +- struct dquot *dq; +- +- dq = get_dq(quota_dict, dquot->dq_id); +- dq->dq_id = dquot->dq_id; +- dq->dq_flags |= DQF_SEEN; +- +- print_dquot("mem", dq); +- print_dquot("dsk", dquot); +- +- /* Check if there is inconsistancy. */ +- if (dq->dq_dqb.dqb_curspace != dquot->dq_dqb.dqb_curspace || +- dq->dq_dqb.dqb_curinodes != dquot->dq_dqb.dqb_curinodes) { +- scan_data->usage_is_inconsistent = 1; +- fprintf(stderr, "[QUOTA WARNING] Usage inconsistent for ID %d:" +- "actual (%llu, %llu) != expected (%llu, %llu)\n", +- dq->dq_id, (long long)dq->dq_dqb.dqb_curspace, +- (long long)dq->dq_dqb.dqb_curinodes, +- (long long)dquot->dq_dqb.dqb_curspace, +- (long long)dquot->dq_dqb.dqb_curinodes); +- } +- +- if (scan_data->update_limits) { +- dq->dq_dqb.dqb_ihardlimit = dquot->dq_dqb.dqb_ihardlimit; +- dq->dq_dqb.dqb_isoftlimit = dquot->dq_dqb.dqb_isoftlimit; +- dq->dq_dqb.dqb_bhardlimit = dquot->dq_dqb.dqb_bhardlimit; +- dq->dq_dqb.dqb_bsoftlimit = dquot->dq_dqb.dqb_bsoftlimit; +- } +- +- if (scan_data->update_usage) { +- dq->dq_dqb.dqb_curspace = dquot->dq_dqb.dqb_curspace; +- dq->dq_dqb.dqb_curinodes = dquot->dq_dqb.dqb_curinodes; +- } +- +- return 0; +-} +- +-/* +- * Read all dquots from quota file into memory +- */ +-static errcode_t quota_read_all_dquots(struct quota_handle *qh, +- quota_ctx_t qctx, int update_limits) +-{ +- struct scan_dquots_data scan_data; +- +- scan_data.quota_dict = qctx->quota_dict[qh->qh_type]; +- scan_data.update_limits = update_limits; +- scan_data.update_usage = 0; +- +- return qh->qh_ops->scan_dquots(qh, scan_dquots_callback, &scan_data); +-} +- +-/* +- * Write all memory dquots into quota file +- */ +-#if 0 /* currently unused, but may be useful in the future? */ +-static errcode_t quota_write_all_dquots(struct quota_handle *qh, +- quota_ctx_t qctx) +-{ +- errcode_t err; +- +- err = ext2fs_read_bitmaps(qctx->fs); +- if (err) +- return err; +- write_dquots(qctx->quota_dict[qh->qh_type], qh); +- ext2fs_mark_bb_dirty(qctx->fs); +- qctx->fs->flags &= ~EXT2_FLAG_SUPER_ONLY; +- ext2fs_write_bitmaps(qctx->fs); +- return 0; +-} +-#endif +- +-/* +- * Updates the in-memory quota limits from the given quota inode. +- */ +-errcode_t quota_update_limits(quota_ctx_t qctx, ext2_ino_t qf_ino, int type) +-{ +- struct quota_handle *qh; +- errcode_t err; +- +- if (!qctx) +- return 0; +- +- err = ext2fs_get_mem(sizeof(struct quota_handle), &qh); +- if (err) { +- log_err("Unable to allocate quota handle"); +- return err; +- } +- +- err = quota_file_open(qctx, qh, qf_ino, type, -1, 0); +- if (err) { +- log_err("Open quota file failed"); +- goto out; +- } +- +- quota_read_all_dquots(qh, qctx, 1); +- +- err = quota_file_close(qctx, qh); +- if (err) { +- log_err("Cannot finish IO on new quotafile: %s", +- strerror(errno)); +- if (qh->qh_qf.e2_file) +- ext2fs_file_close(qh->qh_qf.e2_file); +- } +-out: +- ext2fs_free_mem(&qh); +- return err; +-} +- +-/* +- * Compares the measured quota in qctx->quota_dict with that in the quota inode +- * on disk and updates the limits in qctx->quota_dict. 'usage_inconsistent' is +- * set to 1 if the supplied and on-disk quota usage values are not identical. +- */ +-errcode_t quota_compare_and_update(quota_ctx_t qctx, int qtype, +- int *usage_inconsistent) +-{ +- struct quota_handle qh; +- struct scan_dquots_data scan_data; +- struct dquot *dq; +- dnode_t *n; +- dict_t *dict = qctx->quota_dict[qtype]; +- errcode_t err = 0; +- +- if (!dict) +- goto out; +- +- err = quota_file_open(qctx, &qh, 0, qtype, -1, 0); +- if (err) { +- log_err("Open quota file failed"); +- goto out; +- } +- +- scan_data.quota_dict = qctx->quota_dict[qtype]; +- scan_data.update_limits = 1; +- scan_data.update_usage = 0; +- scan_data.usage_is_inconsistent = 0; +- err = qh.qh_ops->scan_dquots(&qh, scan_dquots_callback, &scan_data); +- if (err) { +- log_err("Error scanning dquots"); +- goto out_close_qh; +- } +- +- for (n = dict_first(dict); n; n = dict_next(dict, n)) { +- dq = dnode_get(n); +- if (!dq) +- continue; +- if ((dq->dq_flags & DQF_SEEN) == 0) { +- fprintf(stderr, "[QUOTA WARNING] " +- "Missing quota entry ID %d\n", dq->dq_id); +- scan_data.usage_is_inconsistent = 1; +- } +- } +- *usage_inconsistent = scan_data.usage_is_inconsistent; +- +-out_close_qh: +- err = quota_file_close(qctx, &qh); +- if (err) { +- log_err("Cannot close quotafile: %s", error_message(errno)); +- if (qh.qh_qf.e2_file) +- ext2fs_file_close(qh.qh_qf.e2_file); +- } +-out: +- return err; +-} +--- a/lib/quota/quotaio.c ++++ /dev/null +@@ -1,422 +0,0 @@ +-/** quotaio.c +- * +- * Generic IO operations on quotafiles +- * Jan Kara - sponsored by SuSE CR +- * Aditya Kali - Ported to e2fsprogs +- */ +- +-#include "config.h" +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +- +-#include "common.h" +-#include "quotaio.h" +- +-static const char * const extensions[MAXQUOTAS] = {"user", "group"}; +-static const char * const basenames[] = { +- "", /* undefined */ +- "quota", /* QFMT_VFS_OLD */ +- "aquota", /* QFMT_VFS_V0 */ +- "", /* QFMT_OCFS2 */ +- "aquota" /* QFMT_VFS_V1 */ +-}; +- +-/* Header in all newer quotafiles */ +-struct disk_dqheader { +- __u32 dqh_magic; +- __u32 dqh_version; +-} __attribute__ ((packed)); +- +-/** +- * Convert type of quota to written representation +- */ +-const char *type2name(int type) +-{ +- return extensions[type]; +-} +- +-/** +- * Creates a quota file name for given type and format. +- */ +-const char *quota_get_qf_name(int type, int fmt, char *buf) +-{ +- if (!buf) +- return NULL; +- snprintf(buf, QUOTA_NAME_LEN, "%s.%s", +- basenames[fmt], extensions[type]); +- +- return buf; +-} +- +-const char *quota_get_qf_path(const char *mntpt, int qtype, int fmt, +- char *path_buf, size_t path_buf_size) +-{ +- char qf_name[QUOTA_NAME_LEN]; +- +- if (!mntpt || !path_buf || !path_buf_size) +- return NULL; +- +- strncpy(path_buf, mntpt, path_buf_size); +- strncat(path_buf, "/", 1); +- strncat(path_buf, quota_get_qf_name(qtype, fmt, qf_name), +- path_buf_size - strlen(path_buf)); +- +- return path_buf; +-} +- +-/* +- * Set grace time if needed +- */ +-void update_grace_times(struct dquot *q) +-{ +- time_t now; +- +- time(&now); +- if (q->dq_dqb.dqb_bsoftlimit && toqb(q->dq_dqb.dqb_curspace) > +- q->dq_dqb.dqb_bsoftlimit) { +- if (!q->dq_dqb.dqb_btime) +- q->dq_dqb.dqb_btime = +- now + q->dq_h->qh_info.dqi_bgrace; +- } else { +- q->dq_dqb.dqb_btime = 0; +- } +- +- if (q->dq_dqb.dqb_isoftlimit && q->dq_dqb.dqb_curinodes > +- q->dq_dqb.dqb_isoftlimit) { +- if (!q->dq_dqb.dqb_itime) +- q->dq_dqb.dqb_itime = +- now + q->dq_h->qh_info.dqi_igrace; +- } else { +- q->dq_dqb.dqb_itime = 0; +- } +-} +- +-static int compute_num_blocks_proc(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 *private) +-{ +- blk64_t *num_blocks = private; +- +- *num_blocks += 1; +- return 0; +-} +- +-errcode_t quota_inode_truncate(ext2_filsys fs, ext2_ino_t ino) +-{ +- struct ext2_inode inode; +- errcode_t err; +- +- if ((err = ext2fs_read_inode(fs, ino, &inode))) +- return err; +- +- if ((ino == EXT4_USR_QUOTA_INO) || (ino == EXT4_GRP_QUOTA_INO)) { +- inode.i_dtime = fs->now ? fs->now : time(0); +- if (!ext2fs_inode_has_valid_blocks2(fs, &inode)) +- return 0; +- err = ext2fs_punch(fs, ino, &inode, NULL, 0, ~0ULL); +- if (err) +- return err; +- fs->flags &= ~EXT2_FLAG_SUPER_ONLY; +- memset(&inode, 0, sizeof(struct ext2_inode)); +- } else { +- inode.i_flags &= ~EXT2_IMMUTABLE_FL; +- } +- err = ext2fs_write_inode(fs, ino, &inode); +- return err; +-} +- +-static ext2_off64_t compute_inode_size(ext2_filsys fs, ext2_ino_t ino) +-{ +- blk64_t num_blocks = 0; +- +- ext2fs_block_iterate3(fs, ino, +- BLOCK_FLAG_READ_ONLY, +- NULL, +- compute_num_blocks_proc, +- &num_blocks); +- return num_blocks * fs->blocksize; +-} +- +-/* Functions to read/write quota file. */ +-static unsigned int quota_write_nomount(struct quota_file *qf, +- ext2_loff_t offset, +- void *buf, unsigned int size) +-{ +- ext2_file_t e2_file = qf->e2_file; +- unsigned int bytes_written = 0; +- errcode_t err; +- +- err = ext2fs_file_llseek(e2_file, offset, EXT2_SEEK_SET, NULL); +- if (err) { +- log_err("ext2fs_file_llseek failed: %ld", err); +- return 0; +- } +- +- err = ext2fs_file_write(e2_file, buf, size, &bytes_written); +- if (err) { +- log_err("ext2fs_file_write failed: %ld", err); +- return 0; +- } +- +- /* Correct inode.i_size is set in end_io. */ +- return bytes_written; +-} +- +-static unsigned int quota_read_nomount(struct quota_file *qf, +- ext2_loff_t offset, +- void *buf, unsigned int size) +-{ +- ext2_file_t e2_file = qf->e2_file; +- unsigned int bytes_read = 0; +- errcode_t err; +- +- err = ext2fs_file_llseek(e2_file, offset, EXT2_SEEK_SET, NULL); +- if (err) { +- log_err("ext2fs_file_llseek failed: %ld", err); +- return 0; +- } +- +- err = ext2fs_file_read(e2_file, buf, size, &bytes_read); +- if (err) { +- log_err("ext2fs_file_read failed: %ld", err); +- return 0; +- } +- +- return bytes_read; +-} +- +-/* +- * Detect quota format and initialize quota IO +- */ +-errcode_t quota_file_open(quota_ctx_t qctx, struct quota_handle *h, +- ext2_ino_t qf_ino, int type, int fmt, int flags) +-{ +- ext2_filsys fs = qctx->fs; +- ext2_file_t e2_file; +- errcode_t err; +- int allocated_handle = 0; +- +- if (type >= MAXQUOTAS) +- return EINVAL; +- +- if (fmt == -1) +- fmt = QFMT_VFS_V1; +- +- err = ext2fs_read_bitmaps(fs); +- if (err) +- return err; +- +- if (qf_ino == 0) { +- if (type == USRQUOTA) +- qf_ino = fs->super->s_usr_quota_inum; +- else +- qf_ino = fs->super->s_grp_quota_inum; +- } +- +- log_debug("Opening quota ino=%lu, type=%d", qf_ino, type); +- err = ext2fs_file_open(fs, qf_ino, flags, &e2_file); +- if (err) { +- log_err("ext2fs_file_open failed: %s", error_message(err)); +- return err; +- } +- +- if (!h) { +- if (qctx->quota_file[type]) { +- h = qctx->quota_file[type]; +- if (((flags & EXT2_FILE_WRITE) == 0) || +- (h->qh_file_flags & EXT2_FILE_WRITE)) +- return 0; +- (void) quota_file_close(qctx, h); +- } +- err = ext2fs_get_mem(sizeof(struct quota_handle), &h); +- if (err) { +- log_err("Unable to allocate quota handle"); +- return err; +- } +- allocated_handle = 1; +- } +- +- h->qh_qf.e2_file = e2_file; +- h->qh_qf.fs = fs; +- h->qh_qf.ino = qf_ino; +- h->e2fs_write = quota_write_nomount; +- h->e2fs_read = quota_read_nomount; +- h->qh_file_flags = flags; +- h->qh_io_flags = 0; +- h->qh_type = type; +- h->qh_fmt = fmt; +- memset(&h->qh_info, 0, sizeof(h->qh_info)); +- h->qh_ops = "afile_ops_2; +- +- if (h->qh_ops->check_file && +- (h->qh_ops->check_file(h, type, fmt) == 0)) { +- log_err("qh_ops->check_file failed"); +- goto errout; +- } +- +- if (h->qh_ops->init_io && (h->qh_ops->init_io(h) < 0)) { +- log_err("qh_ops->init_io failed"); +- goto errout; +- } +- if (allocated_handle) +- qctx->quota_file[type] = h; +- +- return 0; +-errout: +- ext2fs_file_close(e2_file); +- if (allocated_handle) +- ext2fs_free_mem(&h); +- return -1; +-} +- +-static errcode_t quota_inode_init_new(ext2_filsys fs, ext2_ino_t ino) +-{ +- struct ext2_inode inode; +- errcode_t err = 0; +- +- err = ext2fs_read_inode(fs, ino, &inode); +- if (err) { +- log_err("ex2fs_read_inode failed"); +- return err; +- } +- +- if (EXT2_I_SIZE(&inode)) +- quota_inode_truncate(fs, ino); +- +- memset(&inode, 0, sizeof(struct ext2_inode)); +- ext2fs_iblk_set(fs, &inode, 0); +- inode.i_atime = inode.i_mtime = +- inode.i_ctime = fs->now ? fs->now : time(0); +- inode.i_links_count = 1; +- inode.i_mode = LINUX_S_IFREG | 0600; +- inode.i_flags |= EXT2_IMMUTABLE_FL; +- if (fs->super->s_feature_incompat & +- EXT3_FEATURE_INCOMPAT_EXTENTS) +- inode.i_flags |= EXT4_EXTENTS_FL; +- +- err = ext2fs_write_new_inode(fs, ino, &inode); +- if (err) { +- log_err("ext2fs_write_new_inode failed: %ld", err); +- return err; +- } +- return err; +-} +- +-/* +- * Create new quotafile of specified format on given filesystem +- */ +-errcode_t quota_file_create(struct quota_handle *h, ext2_filsys fs, int type, int fmt) +-{ +- ext2_file_t e2_file; +- int err; +- unsigned long qf_inum; +- +- if (fmt == -1) +- fmt = QFMT_VFS_V1; +- +- h->qh_qf.fs = fs; +- if (type == USRQUOTA) +- qf_inum = EXT4_USR_QUOTA_INO; +- else if (type == GRPQUOTA) +- qf_inum = EXT4_GRP_QUOTA_INO; +- else +- return -1; +- +- err = ext2fs_read_bitmaps(fs); +- if (err) +- goto out_err; +- +- err = quota_inode_init_new(fs, qf_inum); +- if (err) { +- log_err("init_new_quota_inode failed"); +- goto out_err; +- } +- h->qh_qf.ino = qf_inum; +- h->qh_file_flags = EXT2_FILE_WRITE | EXT2_FILE_CREATE; +- h->e2fs_write = quota_write_nomount; +- h->e2fs_read = quota_read_nomount; +- +- log_debug("Creating quota ino=%lu, type=%d", qf_inum, type); +- err = ext2fs_file_open(fs, qf_inum, h->qh_file_flags, &e2_file); +- if (err) { +- log_err("ext2fs_file_open failed: %d", err); +- goto out_err; +- } +- h->qh_qf.e2_file = e2_file; +- +- h->qh_io_flags = 0; +- h->qh_type = type; +- h->qh_fmt = fmt; +- memset(&h->qh_info, 0, sizeof(h->qh_info)); +- h->qh_ops = "afile_ops_2; +- +- if (h->qh_ops->new_io && (h->qh_ops->new_io(h) < 0)) { +- log_err("qh_ops->new_io failed"); +- goto out_err1; +- } +- +- return 0; +- +-out_err1: +- ext2fs_file_close(e2_file); +-out_err: +- +- if (qf_inum) +- quota_inode_truncate(fs, qf_inum); +- +- return -1; +-} +- +-/* +- * Close quotafile and release handle +- */ +-errcode_t quota_file_close(quota_ctx_t qctx, struct quota_handle *h) +-{ +- if (h->qh_io_flags & IOFL_INFODIRTY) { +- if (h->qh_ops->write_info && h->qh_ops->write_info(h) < 0) +- return -1; +- h->qh_io_flags &= ~IOFL_INFODIRTY; +- } +- +- if (h->qh_ops->end_io && h->qh_ops->end_io(h) < 0) +- return -1; +- if (h->qh_qf.e2_file) { +- __u64 new_size, size; +- +- new_size = compute_inode_size(h->qh_qf.fs, h->qh_qf.ino); +- ext2fs_file_flush(h->qh_qf.e2_file); +- if (ext2fs_file_get_lsize(h->qh_qf.e2_file, &size)) +- new_size = 0; +- if (size != new_size) +- ext2fs_file_set_size2(h->qh_qf.e2_file, new_size); +- ext2fs_file_close(h->qh_qf.e2_file); +- } +- if (qctx->quota_file[h->qh_type] == h) +- ext2fs_free_mem(&qctx->quota_file[h->qh_type]); +- return 0; +-} +- +-/* +- * Create empty quota structure +- */ +-struct dquot *get_empty_dquot(void) +-{ +- struct dquot *dquot; +- +- if (ext2fs_get_memzero(sizeof(struct dquot), &dquot)) { +- log_err("Failed to allocate dquot"); +- return NULL; +- } +- +- dquot->dq_id = -1; +- return dquot; +-} +--- a/lib/quota/quotaio.h ++++ /dev/null +@@ -1,225 +0,0 @@ +-/** quotaio.h +- * +- * Interface to the quota library. +- * +- * The quota library provides interface for creating and updating the quota +- * files and the ext4 superblock fields. It supports the new VFS_V1 quota +- * format. The quota library also provides support for keeping track of quotas +- * in memory. +- * The typical way to use the quota library is as follows: +- * { +- * quota_ctx_t qctx; +- * +- * quota_init_context(&qctx, fs, -1); +- * { +- * quota_compute_usage(qctx, -1); +- * AND/OR +- * quota_data_add/quota_data_sub/quota_data_inodes(); +- * } +- * quota_write_inode(qctx, USRQUOTA); +- * quota_write_inode(qctx, GRPQUOTA); +- * quota_release_context(&qctx); +- * } +- * +- * This initial version does not support reading the quota files. This support +- * will be added in near future. +- * +- * Aditya Kali +- * Header of IO operations for quota utilities +- * +- * Jan Kara +- */ +- +-#ifndef GUARD_QUOTAIO_H +-#define GUARD_QUOTAIO_H +- +-#include +-#include +-#include +- +-#include "ext2fs/ext2_fs.h" +-#include "ext2fs/ext2fs.h" +-#include "dqblk_v2.h" +-#include "../e2fsck/dict.h" +- +-typedef int64_t qsize_t; /* Type in which we store size limitations */ +- +-#define MAXQUOTAS 2 +-#define USRQUOTA 0 +-#define GRPQUOTA 1 +- +-typedef struct quota_ctx *quota_ctx_t; +- +-struct quota_ctx { +- ext2_filsys fs; +- dict_t *quota_dict[MAXQUOTAS]; +- struct quota_handle *quota_file[MAXQUOTAS]; +-}; +- +-/* +- * Definitions of magics and versions of current quota files +- */ +-#define INITQMAGICS {\ +- 0xd9c01f11, /* USRQUOTA */\ +- 0xd9c01927 /* GRPQUOTA */\ +-} +- +-/* Size of blocks in which are counted size limits in generic utility parts */ +-#define QUOTABLOCK_BITS 10 +-#define QUOTABLOCK_SIZE (1 << QUOTABLOCK_BITS) +-#define toqb(x) (((x) + QUOTABLOCK_SIZE - 1) >> QUOTABLOCK_BITS) +- +-/* Quota format type IDs */ +-#define QFMT_VFS_OLD 1 +-#define QFMT_VFS_V0 2 +-#define QFMT_VFS_V1 4 +- +-/* +- * The following constants define the default amount of time given a user +- * before the soft limits are treated as hard limits (usually resulting +- * in an allocation failure). The timer is started when the user crosses +- * their soft limit, it is reset when they go below their soft limit. +- */ +-#define MAX_IQ_TIME 604800 /* (7*24*60*60) 1 week */ +-#define MAX_DQ_TIME 604800 /* (7*24*60*60) 1 week */ +- +-#define IOFL_INFODIRTY 0x01 /* Did info change? */ +- +-struct quotafile_ops; +- +-/* Generic information about quotafile */ +-struct util_dqinfo { +- time_t dqi_bgrace; /* Block grace time for given quotafile */ +- time_t dqi_igrace; /* Inode grace time for given quotafile */ +- union { +- struct v2_mem_dqinfo v2_mdqi; +- } u; /* Format specific info about quotafile */ +-}; +- +-struct quota_file { +- ext2_filsys fs; +- ext2_ino_t ino; +- ext2_file_t e2_file; +-}; +- +-/* Structure for one opened quota file */ +-struct quota_handle { +- int qh_type; /* Type of quotafile */ +- int qh_fmt; /* Quotafile format */ +- int qh_file_flags; +- int qh_io_flags; /* IO flags for file */ +- struct quota_file qh_qf; +- unsigned int (*e2fs_read)(struct quota_file *qf, ext2_loff_t offset, +- void *buf, unsigned int size); +- unsigned int (*e2fs_write)(struct quota_file *qf, ext2_loff_t offset, +- void *buf, unsigned int size); +- struct quotafile_ops *qh_ops; /* Operations on quotafile */ +- struct util_dqinfo qh_info; /* Generic quotafile info */ +-}; +- +-/* Utility quota block */ +-struct util_dqblk { +- qsize_t dqb_ihardlimit; +- qsize_t dqb_isoftlimit; +- qsize_t dqb_curinodes; +- qsize_t dqb_bhardlimit; +- qsize_t dqb_bsoftlimit; +- qsize_t dqb_curspace; +- time_t dqb_btime; +- time_t dqb_itime; +- union { +- struct v2_mem_dqblk v2_mdqb; +- } u; /* Format specific dquot information */ +-}; +- +-/* Structure for one loaded quota */ +-struct dquot { +- struct dquot *dq_next; /* Pointer to next dquot in the list */ +- qid_t dq_id; /* ID dquot belongs to */ +- int dq_flags; /* Some flags for utils */ +- struct quota_handle *dq_h; /* Handle of quotafile for this dquot */ +- struct util_dqblk dq_dqb; /* Parsed data of dquot */ +-}; +- +-#define DQF_SEEN 0x0001 +- +-/* Structure of quotafile operations */ +-struct quotafile_ops { +- /* Check whether quotafile is in our format */ +- int (*check_file) (struct quota_handle *h, int type, int fmt); +- /* Open quotafile */ +- int (*init_io) (struct quota_handle *h); +- /* Create new quotafile */ +- int (*new_io) (struct quota_handle *h); +- /* Write all changes and close quotafile */ +- int (*end_io) (struct quota_handle *h); +- /* Write info about quotafile */ +- int (*write_info) (struct quota_handle *h); +- /* Read dquot into memory */ +- struct dquot *(*read_dquot) (struct quota_handle *h, qid_t id); +- /* Write given dquot to disk */ +- int (*commit_dquot) (struct dquot *dquot); +- /* Scan quotafile and call callback on every structure */ +- int (*scan_dquots) (struct quota_handle *h, +- int (*process_dquot) (struct dquot *dquot, +- void *data), +- void *data); +- /* Function to print format specific file information */ +- int (*report) (struct quota_handle *h, int verbose); +-}; +- +-/* This might go into a special header file but that sounds a bit silly... */ +-extern struct quotafile_ops quotafile_ops_meta; +- +-/* Open existing quotafile of given type (and verify its format) on given +- * filesystem. */ +-errcode_t quota_file_open(quota_ctx_t qctx, struct quota_handle *h, +- ext2_ino_t qf_ino, int type, int fmt, int flags); +- +- +-/* Create new quotafile of specified format on given filesystem */ +-errcode_t quota_file_create(struct quota_handle *h, ext2_filsys fs, +- int type, int fmt); +- +-/* Close quotafile */ +-errcode_t quota_file_close(quota_ctx_t qctx, struct quota_handle *h); +- +-/* Get empty quota structure */ +-struct dquot *get_empty_dquot(void); +- +-errcode_t quota_inode_truncate(ext2_filsys fs, ext2_ino_t ino); +- +-const char *type2name(int type); +- +-void update_grace_times(struct dquot *q); +- +-/* size for the buffer returned by quota_get_qf_name(); must be greater +- than maxlen of extensions[] and fmtnames[] (plus 2) found in quotaio.c */ +-#define QUOTA_NAME_LEN 16 +- +-const char *quota_get_qf_name(int type, int fmt, char *buf); +-const char *quota_get_qf_path(const char *mntpt, int qtype, int fmt, +- char *path_buf, size_t path_buf_size); +- +-/* In mkquota.c */ +-errcode_t quota_init_context(quota_ctx_t *qctx, ext2_filsys fs, int qtype); +-void quota_data_inodes(quota_ctx_t qctx, struct ext2_inode *inode, ext2_ino_t ino, +- int adjust); +-void quota_data_add(quota_ctx_t qctx, struct ext2_inode *inode, ext2_ino_t ino, +- qsize_t space); +-void quota_data_sub(quota_ctx_t qctx, struct ext2_inode *inode, ext2_ino_t ino, +- qsize_t space); +-errcode_t quota_write_inode(quota_ctx_t qctx, int qtype); +-errcode_t quota_update_limits(quota_ctx_t qctx, ext2_ino_t qf_ino, int type); +-errcode_t quota_compute_usage(quota_ctx_t qctx); +-void quota_release_context(quota_ctx_t *qctx); +- +-errcode_t quota_remove_inode(ext2_filsys fs, int qtype); +-int quota_file_exists(ext2_filsys fs, int qtype, int fmt); +-void quota_set_sb_inum(ext2_filsys fs, ext2_ino_t ino, int qtype); +-errcode_t quota_compare_and_update(quota_ctx_t qctx, int qtype, +- int *usage_inconsistent); +- +- +- +-#endif /* GUARD_QUOTAIO_H */ +--- a/lib/quota/quotaio_tree.c ++++ /dev/null +@@ -1,662 +0,0 @@ +-/* +- * Implementation of new quotafile format +- * +- * Jan Kara - sponsored by SuSE CR +- */ +- +-#include "config.h" +-#include +-#include +-#include +-#include +-#include +-#include +- +-#include "common.h" +-#include "quotaio_tree.h" +-#include "quotaio.h" +- +-typedef char *dqbuf_t; +- +-#define freedqbuf(buf) ext2fs_free_mem(&buf) +- +-static inline dqbuf_t getdqbuf(void) +-{ +- dqbuf_t buf; +- if (ext2fs_get_memzero(QT_BLKSIZE, &buf)) { +- log_err("Failed to allocate dqbuf"); +- return NULL; +- } +- +- return buf; +-} +- +-/* Is given dquot empty? */ +-int qtree_entry_unused(struct qtree_mem_dqinfo *info, char *disk) +-{ +- int i; +- +- for (i = 0; i < info->dqi_entry_size; i++) +- if (disk[i]) +- return 0; +- return 1; +-} +- +-int qtree_dqstr_in_blk(struct qtree_mem_dqinfo *info) +-{ +- return (QT_BLKSIZE - sizeof(struct qt_disk_dqdbheader)) / +- info->dqi_entry_size; +-} +- +-static int get_index(qid_t id, int depth) +-{ +- return (id >> ((QT_TREEDEPTH - depth - 1) * 8)) & 0xff; +-} +- +-static inline void mark_quotafile_info_dirty(struct quota_handle *h) +-{ +- h->qh_io_flags |= IOFL_INFODIRTY; +-} +- +-/* Read given block */ +-static void read_blk(struct quota_handle *h, unsigned int blk, dqbuf_t buf) +-{ +- int err; +- +- err = h->e2fs_read(&h->qh_qf, blk << QT_BLKSIZE_BITS, buf, +- QT_BLKSIZE); +- if (err < 0) +- log_err("Cannot read block %u: %s", blk, strerror(errno)); +- else if (err != QT_BLKSIZE) +- memset(buf + err, 0, QT_BLKSIZE - err); +-} +- +-/* Write block */ +-static int write_blk(struct quota_handle *h, unsigned int blk, dqbuf_t buf) +-{ +- int err; +- +- err = h->e2fs_write(&h->qh_qf, blk << QT_BLKSIZE_BITS, buf, +- QT_BLKSIZE); +- if (err < 0 && errno != ENOSPC) +- log_err("Cannot write block (%u): %s", blk, strerror(errno)); +- if (err != QT_BLKSIZE) +- return -ENOSPC; +- return 0; +-} +- +-/* Get free block in file (either from free list or create new one) */ +-static int get_free_dqblk(struct quota_handle *h) +-{ +- dqbuf_t buf = getdqbuf(); +- struct qt_disk_dqdbheader *dh = (struct qt_disk_dqdbheader *)buf; +- struct qtree_mem_dqinfo *info = &h->qh_info.u.v2_mdqi.dqi_qtree; +- int blk; +- +- if (!buf) +- return -ENOMEM; +- +- if (info->dqi_free_blk) { +- blk = info->dqi_free_blk; +- read_blk(h, blk, buf); +- info->dqi_free_blk = ext2fs_le32_to_cpu(dh->dqdh_next_free); +- } else { +- memset(buf, 0, QT_BLKSIZE); +- /* Assure block allocation... */ +- if (write_blk(h, info->dqi_blocks, buf) < 0) { +- freedqbuf(buf); +- log_err("Cannot allocate new quota block " +- "(out of disk space)."); +- return -ENOSPC; +- } +- blk = info->dqi_blocks++; +- } +- mark_quotafile_info_dirty(h); +- freedqbuf(buf); +- return blk; +-} +- +-/* Put given block to free list */ +-static void put_free_dqblk(struct quota_handle *h, dqbuf_t buf, +- unsigned int blk) +-{ +- struct qt_disk_dqdbheader *dh = (struct qt_disk_dqdbheader *)buf; +- struct qtree_mem_dqinfo *info = &h->qh_info.u.v2_mdqi.dqi_qtree; +- +- dh->dqdh_next_free = ext2fs_cpu_to_le32(info->dqi_free_blk); +- dh->dqdh_prev_free = ext2fs_cpu_to_le32(0); +- dh->dqdh_entries = ext2fs_cpu_to_le16(0); +- info->dqi_free_blk = blk; +- mark_quotafile_info_dirty(h); +- write_blk(h, blk, buf); +-} +- +-/* Remove given block from the list of blocks with free entries */ +-static void remove_free_dqentry(struct quota_handle *h, dqbuf_t buf, +- unsigned int blk) +-{ +- dqbuf_t tmpbuf = getdqbuf(); +- struct qt_disk_dqdbheader *dh = (struct qt_disk_dqdbheader *)buf; +- unsigned int nextblk = ext2fs_le32_to_cpu(dh->dqdh_next_free), prevblk = +- +- ext2fs_le32_to_cpu(dh->dqdh_prev_free); +- +- if (!tmpbuf) +- return; +- +- if (nextblk) { +- read_blk(h, nextblk, tmpbuf); +- ((struct qt_disk_dqdbheader *)tmpbuf)->dqdh_prev_free = +- dh->dqdh_prev_free; +- write_blk(h, nextblk, tmpbuf); +- } +- if (prevblk) { +- read_blk(h, prevblk, tmpbuf); +- ((struct qt_disk_dqdbheader *)tmpbuf)->dqdh_next_free = +- dh->dqdh_next_free; +- write_blk(h, prevblk, tmpbuf); +- } else { +- h->qh_info.u.v2_mdqi.dqi_qtree.dqi_free_entry = nextblk; +- mark_quotafile_info_dirty(h); +- } +- freedqbuf(tmpbuf); +- dh->dqdh_next_free = dh->dqdh_prev_free = ext2fs_cpu_to_le32(0); +- write_blk(h, blk, buf); /* No matter whether write succeeds +- * block is out of list */ +-} +- +-/* Insert given block to the beginning of list with free entries */ +-static void insert_free_dqentry(struct quota_handle *h, dqbuf_t buf, +- unsigned int blk) +-{ +- dqbuf_t tmpbuf = getdqbuf(); +- struct qt_disk_dqdbheader *dh = (struct qt_disk_dqdbheader *)buf; +- struct qtree_mem_dqinfo *info = &h->qh_info.u.v2_mdqi.dqi_qtree; +- +- if (!tmpbuf) +- return; +- +- dh->dqdh_next_free = ext2fs_cpu_to_le32(info->dqi_free_entry); +- dh->dqdh_prev_free = ext2fs_cpu_to_le32(0); +- write_blk(h, blk, buf); +- if (info->dqi_free_entry) { +- read_blk(h, info->dqi_free_entry, tmpbuf); +- ((struct qt_disk_dqdbheader *)tmpbuf)->dqdh_prev_free = +- ext2fs_cpu_to_le32(blk); +- write_blk(h, info->dqi_free_entry, tmpbuf); +- } +- freedqbuf(tmpbuf); +- info->dqi_free_entry = blk; +- mark_quotafile_info_dirty(h); +-} +- +-/* Find space for dquot */ +-static unsigned int find_free_dqentry(struct quota_handle *h, +- struct dquot *dquot, int *err) +-{ +- int blk, i; +- struct qt_disk_dqdbheader *dh; +- struct qtree_mem_dqinfo *info = &h->qh_info.u.v2_mdqi.dqi_qtree; +- char *ddquot; +- dqbuf_t buf; +- +- *err = 0; +- buf = getdqbuf(); +- if (!buf) { +- *err = -ENOMEM; +- return 0; +- } +- +- dh = (struct qt_disk_dqdbheader *)buf; +- if (info->dqi_free_entry) { +- blk = info->dqi_free_entry; +- read_blk(h, blk, buf); +- } else { +- blk = get_free_dqblk(h); +- if (blk < 0) { +- freedqbuf(buf); +- *err = blk; +- return 0; +- } +- memset(buf, 0, QT_BLKSIZE); +- info->dqi_free_entry = blk; +- mark_quotafile_info_dirty(h); +- } +- +- /* Block will be full? */ +- if (ext2fs_le16_to_cpu(dh->dqdh_entries) + 1 >= +- qtree_dqstr_in_blk(info)) +- remove_free_dqentry(h, buf, blk); +- +- dh->dqdh_entries = +- ext2fs_cpu_to_le16(ext2fs_le16_to_cpu(dh->dqdh_entries) + 1); +- /* Find free structure in block */ +- ddquot = buf + sizeof(struct qt_disk_dqdbheader); +- for (i = 0; +- i < qtree_dqstr_in_blk(info) && !qtree_entry_unused(info, ddquot); +- i++) +- ddquot += info->dqi_entry_size; +- +- if (i == qtree_dqstr_in_blk(info)) +- log_err("find_free_dqentry(): Data block full unexpectedly."); +- +- write_blk(h, blk, buf); +- dquot->dq_dqb.u.v2_mdqb.dqb_off = +- (blk << QT_BLKSIZE_BITS) + sizeof(struct qt_disk_dqdbheader) + +- i * info->dqi_entry_size; +- freedqbuf(buf); +- return blk; +-} +- +-/* Insert reference to structure into the trie */ +-static int do_insert_tree(struct quota_handle *h, struct dquot *dquot, +- unsigned int * treeblk, int depth) +-{ +- dqbuf_t buf; +- int newson = 0, newact = 0; +- __u32 *ref; +- unsigned int newblk; +- int ret = 0; +- +- log_debug("inserting in tree: treeblk=%u, depth=%d", *treeblk, depth); +- buf = getdqbuf(); +- if (!buf) +- return -ENOMEM; +- +- if (!*treeblk) { +- ret = get_free_dqblk(h); +- if (ret < 0) +- goto out_buf; +- *treeblk = ret; +- memset(buf, 0, QT_BLKSIZE); +- newact = 1; +- } else { +- read_blk(h, *treeblk, buf); +- } +- +- ref = (__u32 *) buf; +- newblk = ext2fs_le32_to_cpu(ref[get_index(dquot->dq_id, depth)]); +- if (!newblk) +- newson = 1; +- if (depth == QT_TREEDEPTH - 1) { +- if (newblk) +- log_err("Inserting already present quota entry " +- "(block %u).", +- ref[get_index(dquot->dq_id, depth)]); +- newblk = find_free_dqentry(h, dquot, &ret); +- } else { +- ret = do_insert_tree(h, dquot, &newblk, depth + 1); +- } +- +- if (newson && ret >= 0) { +- ref[get_index(dquot->dq_id, depth)] = +- ext2fs_cpu_to_le32(newblk); +- write_blk(h, *treeblk, buf); +- } else if (newact && ret < 0) { +- put_free_dqblk(h, buf, *treeblk); +- } +- +-out_buf: +- freedqbuf(buf); +- return ret; +-} +- +-/* Wrapper for inserting quota structure into tree */ +-static void dq_insert_tree(struct quota_handle *h, struct dquot *dquot) +-{ +- unsigned int tmp = QT_TREEOFF; +- +- if (do_insert_tree(h, dquot, &tmp, 0) < 0) +- log_err("Cannot write quota (id %u): %s", +- (unsigned int) dquot->dq_id, strerror(errno)); +-} +- +-/* Write dquot to file */ +-void qtree_write_dquot(struct dquot *dquot) +-{ +- ssize_t ret; +- char *ddquot; +- struct quota_handle *h = dquot->dq_h; +- struct qtree_mem_dqinfo *info = +- &dquot->dq_h->qh_info.u.v2_mdqi.dqi_qtree; +- log_debug("writing ddquot 1: off=%llu, info->dqi_entry_size=%u", +- dquot->dq_dqb.u.v2_mdqb.dqb_off, +- info->dqi_entry_size); +- ret = ext2fs_get_mem(info->dqi_entry_size, &ddquot); +- if (ret) { +- errno = ENOMEM; +- log_err("Quota write failed (id %u): %s", +- (unsigned int)dquot->dq_id, strerror(errno)); +- return; +- } +- memset(ddquot, 0, info->dqi_entry_size); +- +- if (!dquot->dq_dqb.u.v2_mdqb.dqb_off) +- dq_insert_tree(dquot->dq_h, dquot); +- info->dqi_ops->mem2disk_dqblk(ddquot, dquot); +- log_debug("writing ddquot 2: off=%llu, info->dqi_entry_size=%u", +- dquot->dq_dqb.u.v2_mdqb.dqb_off, +- info->dqi_entry_size); +- ret = h->e2fs_write(&h->qh_qf, dquot->dq_dqb.u.v2_mdqb.dqb_off, ddquot, +- info->dqi_entry_size); +- +- if (ret != info->dqi_entry_size) { +- if (ret > 0) +- errno = ENOSPC; +- log_err("Quota write failed (id %u): %s", +- (unsigned int)dquot->dq_id, strerror(errno)); +- } +- ext2fs_free_mem(&ddquot); +-} +- +-/* Free dquot entry in data block */ +-static void free_dqentry(struct quota_handle *h, struct dquot *dquot, +- unsigned int blk) +-{ +- struct qt_disk_dqdbheader *dh; +- struct qtree_mem_dqinfo *info = &h->qh_info.u.v2_mdqi.dqi_qtree; +- dqbuf_t buf = getdqbuf(); +- +- if (!buf) +- return; +- +- if (dquot->dq_dqb.u.v2_mdqb.dqb_off >> QT_BLKSIZE_BITS != blk) +- log_err("Quota structure has offset to other block (%u) " +- "than it should (%u).", blk, +- (unsigned int) (dquot->dq_dqb.u.v2_mdqb.dqb_off >> +- QT_BLKSIZE_BITS)); +- +- read_blk(h, blk, buf); +- dh = (struct qt_disk_dqdbheader *)buf; +- dh->dqdh_entries = +- ext2fs_cpu_to_le16(ext2fs_le16_to_cpu(dh->dqdh_entries) - 1); +- +- if (!ext2fs_le16_to_cpu(dh->dqdh_entries)) { /* Block got free? */ +- remove_free_dqentry(h, buf, blk); +- put_free_dqblk(h, buf, blk); +- } else { +- memset(buf + (dquot->dq_dqb.u.v2_mdqb.dqb_off & +- ((1 << QT_BLKSIZE_BITS) - 1)), +- 0, info->dqi_entry_size); +- +- /* First free entry? */ +- if (ext2fs_le16_to_cpu(dh->dqdh_entries) == +- qtree_dqstr_in_blk(info) - 1) +- /* This will also write data block */ +- insert_free_dqentry(h, buf, blk); +- else +- write_blk(h, blk, buf); +- } +- dquot->dq_dqb.u.v2_mdqb.dqb_off = 0; +- freedqbuf(buf); +-} +- +-/* Remove reference to dquot from tree */ +-static void remove_tree(struct quota_handle *h, struct dquot *dquot, +- unsigned int * blk, int depth) +-{ +- dqbuf_t buf = getdqbuf(); +- unsigned int newblk; +- __u32 *ref = (__u32 *) buf; +- +- if (!buf) +- return; +- +- read_blk(h, *blk, buf); +- newblk = ext2fs_le32_to_cpu(ref[get_index(dquot->dq_id, depth)]); +- if (depth == QT_TREEDEPTH - 1) { +- free_dqentry(h, dquot, newblk); +- newblk = 0; +- } else { +- remove_tree(h, dquot, &newblk, depth + 1); +- } +- +- if (!newblk) { +- int i; +- +- ref[get_index(dquot->dq_id, depth)] = ext2fs_cpu_to_le32(0); +- +- /* Block got empty? */ +- for (i = 0; i < QT_BLKSIZE && !buf[i]; i++); +- +- /* Don't put the root block into the free block list */ +- if (i == QT_BLKSIZE && *blk != QT_TREEOFF) { +- put_free_dqblk(h, buf, *blk); +- *blk = 0; +- } else { +- write_blk(h, *blk, buf); +- } +- } +- freedqbuf(buf); +-} +- +-/* Delete dquot from tree */ +-void qtree_delete_dquot(struct dquot *dquot) +-{ +- unsigned int tmp = QT_TREEOFF; +- +- if (!dquot->dq_dqb.u.v2_mdqb.dqb_off) /* Even not allocated? */ +- return; +- remove_tree(dquot->dq_h, dquot, &tmp, 0); +-} +- +-/* Find entry in block */ +-static ext2_loff_t find_block_dqentry(struct quota_handle *h, +- struct dquot *dquot, unsigned int blk) +-{ +- struct qtree_mem_dqinfo *info = &h->qh_info.u.v2_mdqi.dqi_qtree; +- dqbuf_t buf = getdqbuf(); +- int i; +- char *ddquot = buf + sizeof(struct qt_disk_dqdbheader); +- +- if (!buf) +- return -ENOMEM; +- +- read_blk(h, blk, buf); +- for (i = 0; +- i < qtree_dqstr_in_blk(info) && !info->dqi_ops->is_id(ddquot, dquot); +- i++) +- ddquot += info->dqi_entry_size; +- +- if (i == qtree_dqstr_in_blk(info)) +- log_err("Quota for id %u referenced but not present.", +- dquot->dq_id); +- freedqbuf(buf); +- return (blk << QT_BLKSIZE_BITS) + sizeof(struct qt_disk_dqdbheader) + +- i * info->dqi_entry_size; +-} +- +-/* Find entry for given id in the tree */ +-static ext2_loff_t find_tree_dqentry(struct quota_handle *h, +- struct dquot *dquot, +- unsigned int blk, int depth) +-{ +- dqbuf_t buf = getdqbuf(); +- ext2_loff_t ret = 0; +- __u32 *ref = (__u32 *) buf; +- +- if (!buf) +- return -ENOMEM; +- +- read_blk(h, blk, buf); +- ret = 0; +- blk = ext2fs_le32_to_cpu(ref[get_index(dquot->dq_id, depth)]); +- if (!blk) /* No reference? */ +- goto out_buf; +- if (depth < QT_TREEDEPTH - 1) +- ret = find_tree_dqentry(h, dquot, blk, depth + 1); +- else +- ret = find_block_dqentry(h, dquot, blk); +-out_buf: +- freedqbuf(buf); +- return ret; +-} +- +-/* Find entry for given id in the tree - wrapper function */ +-static inline ext2_loff_t find_dqentry(struct quota_handle *h, +- struct dquot *dquot) +-{ +- return find_tree_dqentry(h, dquot, QT_TREEOFF, 0); +-} +- +-/* +- * Read dquot from disk. +- */ +-struct dquot *qtree_read_dquot(struct quota_handle *h, qid_t id) +-{ +- struct qtree_mem_dqinfo *info = &h->qh_info.u.v2_mdqi.dqi_qtree; +- ext2_loff_t offset; +- ssize_t ret; +- char *ddquot; +- struct dquot *dquot = get_empty_dquot(); +- +- if (!dquot) +- return NULL; +- if (ext2fs_get_mem(info->dqi_entry_size, &ddquot)) { +- ext2fs_free_mem(&dquot); +- return NULL; +- } +- +- dquot->dq_id = id; +- dquot->dq_h = h; +- dquot->dq_dqb.u.v2_mdqb.dqb_off = 0; +- memset(&dquot->dq_dqb, 0, sizeof(struct util_dqblk)); +- +- offset = find_dqentry(h, dquot); +- if (offset > 0) { +- dquot->dq_dqb.u.v2_mdqb.dqb_off = offset; +- ret = h->e2fs_read(&h->qh_qf, offset, ddquot, +- info->dqi_entry_size); +- if (ret != info->dqi_entry_size) { +- if (ret > 0) +- errno = EIO; +- log_err("Cannot read quota structure for id %u: %s", +- dquot->dq_id, strerror(errno)); +- } +- info->dqi_ops->disk2mem_dqblk(dquot, ddquot); +- } +- ext2fs_free_mem(&ddquot); +- return dquot; +-} +- +-/* +- * Scan all dquots in file and call callback on each +- */ +-#define set_bit(bmp, ind) ((bmp)[(ind) >> 3] |= (1 << ((ind) & 7))) +-#define get_bit(bmp, ind) ((bmp)[(ind) >> 3] & (1 << ((ind) & 7))) +- +-static int report_block(struct dquot *dquot, unsigned int blk, char *bitmap, +- int (*process_dquot) (struct dquot *, void *), +- void *data) +-{ +- struct qtree_mem_dqinfo *info = +- &dquot->dq_h->qh_info.u.v2_mdqi.dqi_qtree; +- dqbuf_t buf = getdqbuf(); +- struct qt_disk_dqdbheader *dh; +- char *ddata; +- int entries, i; +- +- if (!buf) +- return 0; +- +- set_bit(bitmap, blk); +- read_blk(dquot->dq_h, blk, buf); +- dh = (struct qt_disk_dqdbheader *)buf; +- ddata = buf + sizeof(struct qt_disk_dqdbheader); +- entries = ext2fs_le16_to_cpu(dh->dqdh_entries); +- for (i = 0; i < qtree_dqstr_in_blk(info); +- i++, ddata += info->dqi_entry_size) +- if (!qtree_entry_unused(info, ddata)) { +- dquot->dq_dqb.u.v2_mdqb.dqb_off = +- (blk << QT_BLKSIZE_BITS) + +- sizeof(struct qt_disk_dqdbheader) + +- i * info->dqi_entry_size; +- info->dqi_ops->disk2mem_dqblk(dquot, ddata); +- if (process_dquot(dquot, data) < 0) +- break; +- } +- freedqbuf(buf); +- return entries; +-} +- +-static void check_reference(struct quota_handle *h, unsigned int blk) +-{ +- if (blk >= h->qh_info.u.v2_mdqi.dqi_qtree.dqi_blocks) +- log_err("Illegal reference (%u >= %u) in %s quota file. " +- "Quota file is probably corrupted.\n" +- "Please run e2fsck (8) to fix it.", +- blk, +- h->qh_info.u.v2_mdqi.dqi_qtree.dqi_blocks, +- type2name(h->qh_type)); +-} +- +-static int report_tree(struct dquot *dquot, unsigned int blk, int depth, +- char *bitmap, +- int (*process_dquot) (struct dquot *, void *), +- void *data) +-{ +- int entries = 0, i; +- dqbuf_t buf = getdqbuf(); +- __u32 *ref = (__u32 *) buf; +- +- if (!buf) +- return 0; +- +- read_blk(dquot->dq_h, blk, buf); +- if (depth == QT_TREEDEPTH - 1) { +- for (i = 0; i < QT_BLKSIZE >> 2; i++) { +- blk = ext2fs_le32_to_cpu(ref[i]); +- check_reference(dquot->dq_h, blk); +- if (blk && !get_bit(bitmap, blk)) +- entries += report_block(dquot, blk, bitmap, +- process_dquot, data); +- } +- } else { +- for (i = 0; i < QT_BLKSIZE >> 2; i++) { +- blk = ext2fs_le32_to_cpu(ref[i]); +- if (blk) { +- check_reference(dquot->dq_h, blk); +- entries += report_tree(dquot, blk, depth + 1, +- bitmap, process_dquot, +- data); +- } +- } +- } +- freedqbuf(buf); +- return entries; +-} +- +-static unsigned int find_set_bits(char *bmp, int blocks) +-{ +- unsigned int i, used = 0; +- +- for (i = 0; i < blocks; i++) +- if (get_bit(bmp, i)) +- used++; +- return used; +-} +- +-int qtree_scan_dquots(struct quota_handle *h, +- int (*process_dquot) (struct dquot *, void *), +- void *data) +-{ +- char *bitmap; +- struct v2_mem_dqinfo *v2info = &h->qh_info.u.v2_mdqi; +- struct qtree_mem_dqinfo *info = &v2info->dqi_qtree; +- struct dquot *dquot = get_empty_dquot(); +- +- if (!dquot) +- return -1; +- +- dquot->dq_h = h; +- if (ext2fs_get_memzero((info->dqi_blocks + 7) >> 3, &bitmap)) { +- ext2fs_free_mem(&dquot); +- return -1; +- } +- v2info->dqi_used_entries = report_tree(dquot, QT_TREEOFF, 0, bitmap, +- process_dquot, data); +- v2info->dqi_data_blocks = find_set_bits(bitmap, info->dqi_blocks); +- ext2fs_free_mem(&bitmap); +- ext2fs_free_mem(&dquot); +- return 0; +-} +--- a/lib/quota/quotaio_tree.h ++++ /dev/null +@@ -1,64 +0,0 @@ +-/* +- * Definitions of structures for vfsv0 quota format +- */ +- +-#ifndef _LINUX_QUOTA_TREE_H +-#define _LINUX_QUOTA_TREE_H +- +-#include +- +-typedef __u32 qid_t; /* Type in which we store ids in memory */ +- +-#define QT_TREEOFF 1 /* Offset of tree in file in blocks */ +-#define QT_TREEDEPTH 4 /* Depth of quota tree */ +-#define QT_BLKSIZE_BITS 10 +-#define QT_BLKSIZE (1 << QT_BLKSIZE_BITS) /* Size of block with quota +- * structures */ +- +-/* +- * Structure of header of block with quota structures. It is padded to 16 bytes +- * so there will be space for exactly 21 quota-entries in a block +- */ +-struct qt_disk_dqdbheader { +- __u32 dqdh_next_free; /* Number of next block with free +- * entry */ +- __u32 dqdh_prev_free; /* Number of previous block with free +- * entry */ +- __u16 dqdh_entries; /* Number of valid entries in block */ +- __u16 dqdh_pad1; +- __u32 dqdh_pad2; +-} __attribute__ ((packed)); +- +-struct dquot; +-struct quota_handle; +- +-/* Operations */ +-struct qtree_fmt_operations { +- /* Convert given entry from in memory format to disk one */ +- void (*mem2disk_dqblk)(void *disk, struct dquot *dquot); +- /* Convert given entry from disk format to in memory one */ +- void (*disk2mem_dqblk)(struct dquot *dquot, void *disk); +- /* Is this structure for given id? */ +- int (*is_id)(void *disk, struct dquot *dquot); +-}; +- +-/* Inmemory copy of version specific information */ +-struct qtree_mem_dqinfo { +- unsigned int dqi_blocks; /* # of blocks in quota file */ +- unsigned int dqi_free_blk; /* First block in list of free blocks */ +- unsigned int dqi_free_entry; /* First block with free entry */ +- unsigned int dqi_entry_size; /* Size of quota entry in quota file */ +- struct qtree_fmt_operations *dqi_ops; /* Operations for entry +- * manipulation */ +-}; +- +-void qtree_write_dquot(struct dquot *dquot); +-struct dquot *qtree_read_dquot(struct quota_handle *h, qid_t id); +-void qtree_delete_dquot(struct dquot *dquot); +-int qtree_entry_unused(struct qtree_mem_dqinfo *info, char *disk); +-int qtree_scan_dquots(struct quota_handle *h, +- int (*process_dquot) (struct dquot *, void *), void *data); +- +-int qtree_dqstr_in_blk(struct qtree_mem_dqinfo *info); +- +-#endif /* _LINUX_QUOTAIO_TREE_H */ +--- a/lib/quota/quotaio_v2.c ++++ /dev/null +@@ -1,283 +0,0 @@ +-/* +- * Implementation of new quotafile format +- * +- * Jan Kara - sponsored by SuSE CR +- */ +- +-#include "config.h" +-#include +-#include +-#include +-#include +-#include +-#include +- +-#include "common.h" +-#include "quotaio_v2.h" +-#include "dqblk_v2.h" +-#include "quotaio.h" +-#include "quotaio_tree.h" +- +-static int v2_check_file(struct quota_handle *h, int type, int fmt); +-static int v2_init_io(struct quota_handle *h); +-static int v2_new_io(struct quota_handle *h); +-static int v2_write_info(struct quota_handle *h); +-static struct dquot *v2_read_dquot(struct quota_handle *h, qid_t id); +-static int v2_commit_dquot(struct dquot *dquot); +-static int v2_scan_dquots(struct quota_handle *h, +- int (*process_dquot) (struct dquot *dquot, +- void *data), +- void *data); +-static int v2_report(struct quota_handle *h, int verbose); +- +-struct quotafile_ops quotafile_ops_2 = { +- .check_file = v2_check_file, +- .init_io = v2_init_io, +- .new_io = v2_new_io, +- .write_info = v2_write_info, +- .read_dquot = v2_read_dquot, +- .commit_dquot = v2_commit_dquot, +- .scan_dquots = v2_scan_dquots, +- .report = v2_report, +-}; +- +-/* +- * Copy dquot from disk to memory +- */ +-static void v2r1_disk2memdqblk(struct dquot *dquot, void *dp) +-{ +- struct util_dqblk *m = &dquot->dq_dqb; +- struct v2r1_disk_dqblk *d = dp, empty; +- +- dquot->dq_id = ext2fs_le32_to_cpu(d->dqb_id); +- m->dqb_ihardlimit = ext2fs_le64_to_cpu(d->dqb_ihardlimit); +- m->dqb_isoftlimit = ext2fs_le64_to_cpu(d->dqb_isoftlimit); +- m->dqb_bhardlimit = ext2fs_le64_to_cpu(d->dqb_bhardlimit); +- m->dqb_bsoftlimit = ext2fs_le64_to_cpu(d->dqb_bsoftlimit); +- m->dqb_curinodes = ext2fs_le64_to_cpu(d->dqb_curinodes); +- m->dqb_curspace = ext2fs_le64_to_cpu(d->dqb_curspace); +- m->dqb_itime = ext2fs_le64_to_cpu(d->dqb_itime); +- m->dqb_btime = ext2fs_le64_to_cpu(d->dqb_btime); +- +- memset(&empty, 0, sizeof(struct v2r1_disk_dqblk)); +- empty.dqb_itime = ext2fs_cpu_to_le64(1); +- if (!memcmp(&empty, dp, sizeof(struct v2r1_disk_dqblk))) +- m->dqb_itime = 0; +-} +- +-/* +- * Copy dquot from memory to disk +- */ +-static void v2r1_mem2diskdqblk(void *dp, struct dquot *dquot) +-{ +- struct util_dqblk *m = &dquot->dq_dqb; +- struct v2r1_disk_dqblk *d = dp; +- +- d->dqb_ihardlimit = ext2fs_cpu_to_le64(m->dqb_ihardlimit); +- d->dqb_isoftlimit = ext2fs_cpu_to_le64(m->dqb_isoftlimit); +- d->dqb_bhardlimit = ext2fs_cpu_to_le64(m->dqb_bhardlimit); +- d->dqb_bsoftlimit = ext2fs_cpu_to_le64(m->dqb_bsoftlimit); +- d->dqb_curinodes = ext2fs_cpu_to_le64(m->dqb_curinodes); +- d->dqb_curspace = ext2fs_cpu_to_le64(m->dqb_curspace); +- d->dqb_itime = ext2fs_cpu_to_le64(m->dqb_itime); +- d->dqb_btime = ext2fs_cpu_to_le64(m->dqb_btime); +- d->dqb_id = ext2fs_cpu_to_le32(dquot->dq_id); +- if (qtree_entry_unused(&dquot->dq_h->qh_info.u.v2_mdqi.dqi_qtree, dp)) +- d->dqb_itime = ext2fs_cpu_to_le64(1); +-} +- +-static int v2r1_is_id(void *dp, struct dquot *dquot) +-{ +- struct v2r1_disk_dqblk *d = dp; +- struct qtree_mem_dqinfo *info = +- &dquot->dq_h->qh_info.u.v2_mdqi.dqi_qtree; +- +- if (qtree_entry_unused(info, dp)) +- return 0; +- return ext2fs_le32_to_cpu(d->dqb_id) == dquot->dq_id; +-} +- +-static struct qtree_fmt_operations v2r1_fmt_ops = { +- .mem2disk_dqblk = v2r1_mem2diskdqblk, +- .disk2mem_dqblk = v2r1_disk2memdqblk, +- .is_id = v2r1_is_id, +-}; +- +-/* +- * Copy dqinfo from disk to memory +- */ +-static inline void v2_disk2memdqinfo(struct util_dqinfo *m, +- struct v2_disk_dqinfo *d) +-{ +- m->dqi_bgrace = ext2fs_le32_to_cpu(d->dqi_bgrace); +- m->dqi_igrace = ext2fs_le32_to_cpu(d->dqi_igrace); +- m->u.v2_mdqi.dqi_flags = ext2fs_le32_to_cpu(d->dqi_flags) & V2_DQF_MASK; +- m->u.v2_mdqi.dqi_qtree.dqi_blocks = ext2fs_le32_to_cpu(d->dqi_blocks); +- m->u.v2_mdqi.dqi_qtree.dqi_free_blk = +- ext2fs_le32_to_cpu(d->dqi_free_blk); +- m->u.v2_mdqi.dqi_qtree.dqi_free_entry = +- ext2fs_le32_to_cpu(d->dqi_free_entry); +-} +- +-/* +- * Copy dqinfo from memory to disk +- */ +-static inline void v2_mem2diskdqinfo(struct v2_disk_dqinfo *d, +- struct util_dqinfo *m) +-{ +- d->dqi_bgrace = ext2fs_cpu_to_le32(m->dqi_bgrace); +- d->dqi_igrace = ext2fs_cpu_to_le32(m->dqi_igrace); +- d->dqi_flags = ext2fs_cpu_to_le32(m->u.v2_mdqi.dqi_flags & V2_DQF_MASK); +- d->dqi_blocks = ext2fs_cpu_to_le32(m->u.v2_mdqi.dqi_qtree.dqi_blocks); +- d->dqi_free_blk = +- ext2fs_cpu_to_le32(m->u.v2_mdqi.dqi_qtree.dqi_free_blk); +- d->dqi_free_entry = +- ext2fs_cpu_to_le32(m->u.v2_mdqi.dqi_qtree.dqi_free_entry); +-} +- +-static int v2_read_header(struct quota_handle *h, struct v2_disk_dqheader *dqh) +-{ +- if (h->e2fs_read(&h->qh_qf, 0, dqh, sizeof(struct v2_disk_dqheader)) != +- sizeof(struct v2_disk_dqheader)) +- return 0; +- +- return 1; +-} +- +-/* +- * Check whether given quota file is in our format +- */ +-static int v2_check_file(struct quota_handle *h, int type, int fmt) +-{ +- struct v2_disk_dqheader dqh; +- int file_magics[] = INITQMAGICS; +- +- if (fmt != QFMT_VFS_V1) +- return 0; +- +- if (!v2_read_header(h, &dqh)) +- return 0; +- +- if (ext2fs_le32_to_cpu(dqh.dqh_magic) != file_magics[type]) { +- if (ext2fs_be32_to_cpu(dqh.dqh_magic) == file_magics[type]) +- log_err("Your quota file is stored in wrong endianity"); +- return 0; +- } +- if (V2_VERSION != ext2fs_le32_to_cpu(dqh.dqh_version)) +- return 0; +- return 1; +-} +- +-/* +- * Open quotafile +- */ +-static int v2_init_io(struct quota_handle *h) +-{ +- struct v2_disk_dqinfo ddqinfo; +- +- h->qh_info.u.v2_mdqi.dqi_qtree.dqi_entry_size = +- sizeof(struct v2r1_disk_dqblk); +- h->qh_info.u.v2_mdqi.dqi_qtree.dqi_ops = &v2r1_fmt_ops; +- +- /* Read information about quotafile */ +- if (h->e2fs_read(&h->qh_qf, V2_DQINFOOFF, &ddqinfo, +- sizeof(ddqinfo)) != sizeof(ddqinfo)) +- return -1; +- v2_disk2memdqinfo(&h->qh_info, &ddqinfo); +- return 0; +-} +- +-/* +- * Initialize new quotafile +- */ +-static int v2_new_io(struct quota_handle *h) +-{ +- int file_magics[] = INITQMAGICS; +- struct v2_disk_dqheader ddqheader; +- struct v2_disk_dqinfo ddqinfo; +- +- if (h->qh_fmt != QFMT_VFS_V1) +- return -1; +- +- /* Write basic quota header */ +- ddqheader.dqh_magic = ext2fs_cpu_to_le32(file_magics[h->qh_type]); +- ddqheader.dqh_version = ext2fs_cpu_to_le32(V2_VERSION); +- if (h->e2fs_write(&h->qh_qf, 0, &ddqheader, sizeof(ddqheader)) != +- sizeof(ddqheader)) +- return -1; +- +- /* Write information about quotafile */ +- h->qh_info.dqi_bgrace = MAX_DQ_TIME; +- h->qh_info.dqi_igrace = MAX_IQ_TIME; +- h->qh_info.u.v2_mdqi.dqi_flags = 0; +- h->qh_info.u.v2_mdqi.dqi_qtree.dqi_blocks = QT_TREEOFF + 1; +- h->qh_info.u.v2_mdqi.dqi_qtree.dqi_free_blk = 0; +- h->qh_info.u.v2_mdqi.dqi_qtree.dqi_free_entry = 0; +- h->qh_info.u.v2_mdqi.dqi_qtree.dqi_entry_size = +- sizeof(struct v2r1_disk_dqblk); +- h->qh_info.u.v2_mdqi.dqi_qtree.dqi_ops = &v2r1_fmt_ops; +- v2_mem2diskdqinfo(&ddqinfo, &h->qh_info); +- if (h->e2fs_write(&h->qh_qf, V2_DQINFOOFF, &ddqinfo, +- sizeof(ddqinfo)) != +- sizeof(ddqinfo)) +- return -1; +- +- return 0; +-} +- +-/* +- * Write information (grace times to file) +- */ +-static int v2_write_info(struct quota_handle *h) +-{ +- struct v2_disk_dqinfo ddqinfo; +- +- v2_mem2diskdqinfo(&ddqinfo, &h->qh_info); +- if (h->e2fs_write(&h->qh_qf, V2_DQINFOOFF, &ddqinfo, sizeof(ddqinfo)) != +- sizeof(ddqinfo)) +- return -1; +- +- return 0; +-} +- +-/* +- * Read dquot from disk +- */ +-static struct dquot *v2_read_dquot(struct quota_handle *h, qid_t id) +-{ +- return qtree_read_dquot(h, id); +-} +- +-/* +- * Commit changes of dquot to disk - it might also mean deleting it when quota +- * became fake one and user has no blocks. +- * User can process use 'errno' to detect errstr. +- */ +-static int v2_commit_dquot(struct dquot *dquot) +-{ +- struct util_dqblk *b = &dquot->dq_dqb; +- +- if (!b->dqb_curspace && !b->dqb_curinodes && !b->dqb_bsoftlimit && +- !b->dqb_isoftlimit && !b->dqb_bhardlimit && !b->dqb_ihardlimit) +- qtree_delete_dquot(dquot); +- else +- qtree_write_dquot(dquot); +- return 0; +-} +- +-static int v2_scan_dquots(struct quota_handle *h, +- int (*process_dquot) (struct dquot *, void *), +- void *data) +-{ +- return qtree_scan_dquots(h, process_dquot, data); +-} +- +-/* Report information about quotafile. +- * TODO: Not used right now, but we should be able to use this when we add +- * support to debugfs to read quota files. +- */ +-static int v2_report(struct quota_handle *h, int verbose) +-{ +- log_err("Not Implemented."); +- return -1; +-} +--- a/lib/quota/quotaio_v2.h ++++ /dev/null +@@ -1,54 +0,0 @@ +-/* +- * +- * Header file for disk format of new quotafile format +- * +- */ +- +-#ifndef GUARD_QUOTAIO_V2_H +-#define GUARD_QUOTAIO_V2_H +- +-#include +-#include "quotaio.h" +- +-/* Offset of info header in file */ +-#define V2_DQINFOOFF sizeof(struct v2_disk_dqheader) +-/* Supported version of quota-tree format */ +-#define V2_VERSION 1 +- +-struct v2_disk_dqheader { +- __u32 dqh_magic; /* Magic number identifying file */ +- __u32 dqh_version; /* File version */ +-} __attribute__ ((packed)); +- +-/* Flags for version specific files */ +-#define V2_DQF_MASK 0x0000 /* Mask for all valid ondisk flags */ +- +-/* Header with type and version specific information */ +-struct v2_disk_dqinfo { +- __u32 dqi_bgrace; /* Time before block soft limit becomes +- * hard limit */ +- __u32 dqi_igrace; /* Time before inode soft limit becomes +- * hard limit */ +- __u32 dqi_flags; /* Flags for quotafile (DQF_*) */ +- __u32 dqi_blocks; /* Number of blocks in file */ +- __u32 dqi_free_blk; /* Number of first free block in the list */ +- __u32 dqi_free_entry; /* Number of block with at least one +- * free entry */ +-} __attribute__ ((packed)); +- +-struct v2r1_disk_dqblk { +- __u32 dqb_id; /* id this quota applies to */ +- __u32 dqb_pad; +- __u64 dqb_ihardlimit; /* absolute limit on allocated inodes */ +- __u64 dqb_isoftlimit; /* preferred inode limit */ +- __u64 dqb_curinodes; /* current # allocated inodes */ +- __u64 dqb_bhardlimit; /* absolute limit on disk space +- * (in QUOTABLOCK_SIZE) */ +- __u64 dqb_bsoftlimit; /* preferred limit on disk space +- * (in QUOTABLOCK_SIZE) */ +- __u64 dqb_curspace; /* current space occupied (in bytes) */ +- __u64 dqb_btime; /* time limit for excessive disk use */ +- __u64 dqb_itime; /* time limit for excessive inode use */ +-} __attribute__ ((packed)); +- +-#endif +--- /dev/null ++++ b/lib/ss/Android.mk +@@ -0,0 +1,49 @@ ++LOCAL_PATH := $(call my-dir) ++ ++libext2_ss_src_files := \ ++ ss_err.c \ ++ std_rqs.c \ ++ invocation.c help.c \ ++ execute_cmd.c \ ++ listen.c \ ++ parse.c \ ++ error.c \ ++ prompt.c \ ++ request_tbl.c \ ++ list_rqs.c \ ++ pager.c \ ++ requests.c \ ++ data.c \ ++ get_readline.c ++ ++libext2_ss_c_includes := external/e2fsprogs/lib ++ ++libext2_ss_cflags := -O2 -g -W -Wall ++ ++libext2_ss_shared_libraries := \ ++ libext2_com_err ++ ++libext2_ss_system_shared_libraries := libc ++ ++include $(CLEAR_VARS) ++ ++LOCAL_SRC_FILES := $(libext2_ss_src_files) ++LOCAL_C_INCLUDES := $(libext2_ss_c_includes) ++LOCAL_CFLAGS := $(libext2_ss_cflags) ++LOCAL_SHARED_LIBRARIES := $(libext2_ss_shared_libraries) ++LOCAL_SYSTEM_SHARED_LIBRARIES := $(libext2_ss_system_shared_libraries) ++LOCAL_MODULE := libext2_ss ++LOCAL_MODULE_TAGS := optional ++ ++include $(BUILD_SHARED_LIBRARY) ++ ++include $(CLEAR_VARS) ++ ++LOCAL_SRC_FILES := $(libext2_ss_src_files) ++LOCAL_SHARED_LIBRARIES := $(addsuffix _host, $(libext2_ss_shared_libraries)) ++LOCAL_C_INCLUDES := $(libext2_ss_c_includes) ++LOCAL_CFLAGS := $(libext2_ss_cflags) ++LOCAL_MODULE := libext2_ss_host ++LOCAL_MODULE_TAGS := optional ++ ++include $(BUILD_HOST_SHARED_LIBRARY) +--- a/lib/ss/data.c ++++ b/lib/ss/data.c +@@ -16,8 +16,5 @@ + #include + #include "ss_internal.h" + +-static const char copyright[] = +- "Copyright 1987, 1988, 1989 by the Massachusetts Institute of Technology"; +- + ss_data **_ss_table = (ss_data **)NULL; + char *_ss_pager_name = (char *)NULL; +--- a/lib/ss/get_readline.c ++++ b/lib/ss/get_readline.c +@@ -21,9 +21,9 @@ + #include + #endif + ++#ifdef HAVE_DLOPEN + static void ss_release_readline(ss_data *info) + { +-#ifdef HAVE_DLOPEN + if (!info->readline_handle) + return; + +@@ -33,15 +33,15 @@ + info->rl_completion_matches = 0; + dlclose(info->readline_handle); + info->readline_handle = 0; +-#endif + } ++#endif + + /* Libraries we will try to use for readline/editline functionality */ + #define DEFAULT_LIBPATH "libreadline.so.6:libreadline.so.5:libreadline.so.4:libreadline.so:libedit.so.2:libedit.so:libeditline.so.0:libeditline.so" + ++#ifdef HAVE_DLOPEN + void ss_get_readline(int sci_idx) + { +-#ifdef HAVE_DLOPEN + void *handle = NULL; + ss_data *info = ss_info(sci_idx); + const char **t, *libpath = 0; +@@ -92,7 +92,9 @@ + dlsym(handle, "rl_attempted_completion_function")) != NULL) + *completion_func = ss_rl_completion; + info->readline_shutdown = ss_release_readline; +-#endif + } +- +- ++#else ++void ss_get_readline(int sci_idx __SS_ATTR((unused))) ++{ ++} ++#endif +--- a/lib/ss/Makefile.in ++++ b/lib/ss/Makefile.in +@@ -35,6 +35,7 @@ + $(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 $< +@@ -171,7 +172,7 @@ + clean:: + $(RM) -f ../libss.a libss.a mk_cmds ss_err.h ss_err.c std_rqs.c \ + tst_cmds.c test_ss test_out test.diff *.o *~ \#* *.bak core \ +- test_cmd.c ++ test_cmd.c ss.pc + + mostlyclean:: clean + distclean:: clean +--- /dev/null ++++ b/lib/support/Android.mk +@@ -0,0 +1,57 @@ ++LOCAL_PATH := $(call my-dir) ++ ++libext2_quota_src_files := \ ++ dict.c \ ++ mkquota.c \ ++ plausible.c \ ++ profile.c \ ++ profile_helpers.c \ ++ prof_err.c \ ++ quotaio.c \ ++ quotaio_tree.c \ ++ quotaio_v2.c ++ ++libext2_quota_c_includes := external/e2fsprogs/lib ++ ++libext2_quota_cflags := -O2 -g -W -Wall ++ ++libext2_quota_shared_libraries := libext2fs libext2_com_err libext2_blkid ++ ++libext2_quota_system_shared_libraries := libc ++ ++include $(CLEAR_VARS) ++ ++LOCAL_SRC_FILES := $(libext2_quota_src_files) ++LOCAL_SYSTEM_SHARED_LIBRARIES := $(libext2_quota_system_shared_libraries) ++LOCAL_C_INCLUDES := $(libext2_quota_c_includes) ++LOCAL_CFLAGS := $(libext2_quota_cflags) ++LOCAL_SYSTEM_SHARED_LIBRARIES := libc $(libext2_quota_shared_libraries) ++LOCAL_MODULE := libext2_quota ++LOCAL_MODULE_TAGS := optional ++ ++include $(BUILD_SHARED_LIBRARY) ++ ++libext2_quota_static_libraries := libext2fs libext2_com_err ++ ++include $(CLEAR_VARS) ++ ++LOCAL_SRC_FILES := $(libext2_quota_src_files) ++LOCAL_C_INCLUDES := $(libext2_quota_c_includes) ++LOCAL_CFLAGS := $(libext2_quota_cflags) ++LOCAL_STATIC_LIBRARIES := libc $(libext2_quota_static_libraries) ++LOCAL_PRELINK_MODULE := false ++LOCAL_MODULE := libext2_quota ++LOCAL_MODULE_TAGS := optional ++ ++include $(BUILD_STATIC_LIBRARY) ++ ++include $(CLEAR_VARS) ++ ++LOCAL_SRC_FILES := $(libext2_quota_src_files) ++LOCAL_C_INCLUDES := $(libext2_quota_c_includes) ++LOCAL_CFLAGS := $(libext2_quota_cflags) ++LOCAL_MODULE := libext2_quota_host ++LOCAL_MODULE_TAGS := optional ++LOCAL_SHARED_LIBRARIES := $(addsuffix _host, $(libext2_quota_shared_libraries)) ++ ++include $(BUILD_HOST_SHARED_LIBRARY) +--- /dev/null ++++ b/lib/support/argv_parse.c +@@ -0,0 +1,166 @@ ++/* ++ * argv_parse.c --- utility function for parsing a string into a ++ * argc, argv array. ++ * ++ * This file defines a function argv_parse() which parsing a ++ * passed-in string, handling double quotes and backslashes, and ++ * creates an allocated argv vector which can be freed using the ++ * argv_free() function. ++ * ++ * See argv_parse.h for the formal definition of the functions. ++ * ++ * Copyright 1999 by Theodore Ts'o. ++ * ++ * Permission to use, copy, modify, and distribute this software for ++ * any purpose with or without fee is hereby granted, provided that ++ * the above copyright notice and this permission notice appear in all ++ * copies. THE SOFTWARE IS PROVIDED "AS IS" AND THEODORE TS'O (THE ++ * AUTHOR) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, ++ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. ++ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, ++ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ++ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION ++ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR ++ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. (Isn't ++ * it sick that the U.S. culture of lawsuit-happy lawyers requires ++ * this kind of disclaimer?) ++ * ++ * Version 1.1, modified 2/27/1999 ++ */ ++ ++#include "config.h" ++#ifdef HAVE_STDLIB_H ++#include ++#endif ++#include ++#include ++#include "argv_parse.h" ++ ++#define STATE_WHITESPACE 1 ++#define STATE_TOKEN 2 ++#define STATE_QUOTED 3 ++ ++/* ++ * Returns 0 on success, -1 on failure. ++ */ ++int argv_parse(char *in_buf, int *ret_argc, char ***ret_argv) ++{ ++ int argc = 0, max_argc = 0; ++ char **argv, **new_argv, *buf, ch; ++ char *cp = 0, *outcp = 0; ++ int state = STATE_WHITESPACE; ++ ++ buf = malloc(strlen(in_buf)+1); ++ if (!buf) ++ return -1; ++ ++ max_argc = 0; argc = 0; argv = 0; ++ outcp = buf; ++ for (cp = in_buf; (ch = *cp); cp++) { ++ if (state == STATE_WHITESPACE) { ++ if (isspace((int) ch)) ++ continue; ++ /* Not whitespace, so start a new token */ ++ state = STATE_TOKEN; ++ if (argc >= max_argc) { ++ max_argc += 3; ++ new_argv = realloc(argv, ++ (max_argc+1)*sizeof(char *)); ++ if (!new_argv) { ++ free(argv); ++ free(buf); ++ return -1; ++ } ++ argv = new_argv; ++ } ++ argv[argc++] = outcp; ++ } ++ if (state == STATE_QUOTED) { ++ if (ch == '"') ++ state = STATE_TOKEN; ++ else ++ *outcp++ = ch; ++ continue; ++ } ++ /* Must be processing characters in a word */ ++ if (isspace((int) ch)) { ++ /* ++ * Terminate the current word and start ++ * looking for the beginning of the next word. ++ */ ++ *outcp++ = 0; ++ state = STATE_WHITESPACE; ++ continue; ++ } ++ if (ch == '"') { ++ state = STATE_QUOTED; ++ continue; ++ } ++ if (ch == '\\') { ++ ch = *++cp; ++ switch (ch) { ++ case '\0': ++ ch = '\\'; cp--; break; ++ case 'n': ++ ch = '\n'; break; ++ case 't': ++ ch = '\t'; break; ++ case 'b': ++ ch = '\b'; break; ++ } ++ } ++ *outcp++ = ch; ++ } ++ if (state != STATE_WHITESPACE) ++ *outcp++ = '\0'; ++ if (argv == 0) { ++ argv = malloc(sizeof(char *)); ++ free(buf); ++ } ++ argv[argc] = 0; ++ if (ret_argc) ++ *ret_argc = argc; ++ if (ret_argv) ++ *ret_argv = argv; ++ return 0; ++} ++ ++void argv_free(char **argv) ++{ ++ free(*argv); ++ free(argv); ++} ++ ++#ifdef DEBUG ++/* ++ * For debugging ++ */ ++ ++#include ++ ++int main(int argc, char **argv) ++{ ++ int ac, ret; ++ char **av, **cpp; ++ char buf[256]; ++ ++ while (!feof(stdin)) { ++ if (fgets(buf, sizeof(buf), stdin) == NULL) ++ break; ++ ret = argv_parse(buf, &ac, &av); ++ if (ret != 0) { ++ printf("Argv_parse returned %d!\n", ret); ++ continue; ++ } ++ printf("Argv_parse returned %d arguments...\n", ac); ++ for (cpp = av; *cpp; cpp++) { ++ if (cpp != av) ++ printf(", "); ++ printf("'%s'", *cpp); ++ } ++ printf("\n"); ++ argv_free(av); ++ } ++ exit(0); ++} ++#endif /* DEBUG */ +--- /dev/null ++++ b/lib/support/argv_parse.h +@@ -0,0 +1,43 @@ ++/* ++ * argv_parse.h --- header file for the argv parser. ++ * ++ * This file defines the interface for the functions argv_parse() and ++ * argv_free(). ++ * ++ *********************************************************************** ++ * int argv_parse(char *in_buf, int *ret_argc, char ***ret_argv) ++ * ++ * This function takes as its first argument a string which it will ++ * parse into an argv argument vector, with each white-space separated ++ * word placed into its own slot in the argv. This function handles ++ * double quotes and backslashes so that the parsed words can contain ++ * special characters. The count of the number words found in the ++ * parsed string, as well as the argument vector, are returned into ++ * ret_argc and ret_argv, respectively. ++ *********************************************************************** ++ * extern void argv_free(char **argv); ++ * ++ * This function frees the argument vector created by argv_parse(). ++ *********************************************************************** ++ * ++ * Copyright 1999 by Theodore Ts'o. ++ * ++ * Permission to use, copy, modify, and distribute this software for ++ * any purpose with or without fee is hereby granted, provided that ++ * the above copyright notice and this permission notice appear in all ++ * copies. THE SOFTWARE IS PROVIDED "AS IS" AND THEODORE TS'O (THE ++ * AUTHOR) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, ++ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. ++ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, ++ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ++ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION ++ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR ++ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. (Isn't ++ * it sick that the U.S. culture of lawsuit-happy lawyers requires ++ * this kind of disclaimer?) ++ * ++ * Version 1.1, modified 2/27/1999 ++ */ ++ ++extern int argv_parse(char *in_buf, int *ret_argc, char ***ret_argv); ++extern void argv_free(char **argv); +--- /dev/null ++++ b/lib/support/common.h +@@ -0,0 +1,36 @@ ++/* ++ * ++ * Various things common for all utilities ++ * ++ */ ++ ++#ifndef __QUOTA_COMMON_H__ ++#define __QUOTA_COMMON_H__ ++ ++#if EXT2_FLAT_INCLUDES ++#include "e2_types.h" ++#else ++#include ++#endif /* EXT2_FLAT_INCLUDES */ ++ ++/* #define DEBUG_QUOTA 1 */ ++ ++#ifndef __attribute__ ++# if !defined __GNUC__ || __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 8) || __STRICT_ANSI__ ++# define __attribute__(x) ++# endif ++#endif ++ ++#define log_err(format, arg ...) \ ++ fprintf(stderr, "[ERROR] %s:%d:%s:: " format "\n", \ ++ __FILE__, __LINE__, __func__, ## arg) ++ ++#ifdef DEBUG_QUOTA ++# define log_debug(format, arg ...) \ ++ fprintf(stderr, "[DEBUG] %s:%d:%s:: " format "\n", \ ++ __FILE__, __LINE__, __func__, ## arg) ++#else ++# define log_debug(format, ...) ++#endif ++ ++#endif /* __QUOTA_COMMON_H__ */ +--- /dev/null ++++ b/lib/support/dict.c +@@ -0,0 +1,1531 @@ ++/* ++ * Dictionary Abstract Data Type ++ * Copyright (C) 1997 Kaz Kylheku ++ * ++ * Free Software License: ++ * ++ * All rights are reserved by the author, with the following exceptions: ++ * Permission is granted to freely reproduce and distribute this software, ++ * possibly in exchange for a fee, provided that this copyright notice appears ++ * intact. Permission is also granted to adapt this software to produce ++ * derivative works, as long as the modified versions carry this copyright ++ * notice and additional notices stating that the work has been modified. ++ * This source code may be translated into executable form and incorporated ++ * into proprietary software; there is no requirement for such software to ++ * contain a copyright notice related to this source. ++ * ++ * $Id: dict.c,v 1.40.2.7 2000/11/13 01:36:44 kaz Exp $ ++ * $Name: kazlib_1_20 $ ++ */ ++ ++#define DICT_NODEBUG ++ ++#ifdef __GNUC__ ++#define EXT2FS_ATTR(x) __attribute__(x) ++#else ++#define EXT2FS_ATTR(x) ++#endif ++ ++#include "config.h" ++#include ++#include ++#ifdef DICT_NODEBUG ++#define dict_assert(x) ++#else ++#include ++#define dict_assert(x) assert(x) ++#endif ++#define DICT_IMPLEMENTATION ++#include "dict.h" ++ ++#ifdef KAZLIB_RCSID ++static const char rcsid[] = "$Id: dict.c,v 1.40.2.7 2000/11/13 01:36:44 kaz Exp $"; ++#endif ++ ++/* ++ * These macros provide short convenient names for structure members, ++ * which are embellished with dict_ prefixes so that they are ++ * properly confined to the documented namespace. It's legal for a ++ * program which uses dict to define, for instance, a macro called ``parent''. ++ * Such a macro would interfere with the dnode_t struct definition. ++ * In general, highly portable and reusable C modules which expose their ++ * structures need to confine structure member names to well-defined spaces. ++ * The resulting identifiers aren't necessarily convenient to use, nor ++ * readable, in the implementation, however! ++ */ ++ ++#define left dict_left ++#define right dict_right ++#define parent dict_parent ++#define color dict_color ++#define key dict_key ++#define data dict_data ++ ++#define nilnode dict_nilnode ++#define nodecount dict_nodecount ++#define maxcount dict_maxcount ++#define compare dict_compare ++#define allocnode dict_allocnode ++#define freenode dict_freenode ++#define context dict_context ++#define dupes dict_dupes ++ ++#define dictptr dict_dictptr ++ ++#define dict_root(D) ((D)->nilnode.left) ++#define dict_nil(D) (&(D)->nilnode) ++#define DICT_DEPTH_MAX 64 ++ ++static dnode_t *dnode_alloc(void *context); ++static void dnode_free(dnode_t *node, void *context); ++ ++/* ++ * Perform a ``left rotation'' adjustment on the tree. The given node P and ++ * its right child C are rearranged so that the P instead becomes the left ++ * child of C. The left subtree of C is inherited as the new right subtree ++ * for P. The ordering of the keys within the tree is thus preserved. ++ */ ++ ++static void rotate_left(dnode_t *upper) ++{ ++ dnode_t *lower, *lowleft, *upparent; ++ ++ lower = upper->right; ++ upper->right = lowleft = lower->left; ++ lowleft->parent = upper; ++ ++ lower->parent = upparent = upper->parent; ++ ++ /* don't need to check for root node here because root->parent is ++ the sentinel nil node, and root->parent->left points back to root */ ++ ++ if (upper == upparent->left) { ++ upparent->left = lower; ++ } else { ++ dict_assert (upper == upparent->right); ++ upparent->right = lower; ++ } ++ ++ lower->left = upper; ++ upper->parent = lower; ++} ++ ++/* ++ * This operation is the ``mirror'' image of rotate_left. It is ++ * the same procedure, but with left and right interchanged. ++ */ ++ ++static void rotate_right(dnode_t *upper) ++{ ++ dnode_t *lower, *lowright, *upparent; ++ ++ lower = upper->left; ++ upper->left = lowright = lower->right; ++ lowright->parent = upper; ++ ++ lower->parent = upparent = upper->parent; ++ ++ if (upper == upparent->right) { ++ upparent->right = lower; ++ } else { ++ dict_assert (upper == upparent->left); ++ upparent->left = lower; ++ } ++ ++ lower->right = upper; ++ upper->parent = lower; ++} ++ ++/* ++ * Do a postorder traversal of the tree rooted at the specified ++ * node and free everything under it. Used by dict_free(). ++ */ ++ ++static void free_nodes(dict_t *dict, dnode_t *node, dnode_t *nil) ++{ ++ if (node == nil) ++ return; ++ free_nodes(dict, node->left, nil); ++ free_nodes(dict, node->right, nil); ++ dict->freenode(node, dict->context); ++} ++ ++/* ++ * This procedure performs a verification that the given subtree is a binary ++ * search tree. It performs an inorder traversal of the tree using the ++ * dict_next() successor function, verifying that the key of each node is ++ * strictly lower than that of its successor, if duplicates are not allowed, ++ * or lower or equal if duplicates are allowed. This function is used for ++ * debugging purposes. ++ */ ++#ifndef DICT_NODEBUG ++static int verify_bintree(dict_t *dict) ++{ ++ dnode_t *first, *next; ++ ++ first = dict_first(dict); ++ ++ if (dict->dupes) { ++ while (first && (next = dict_next(dict, first))) { ++ if (dict->compare(first->key, next->key) > 0) ++ return 0; ++ first = next; ++ } ++ } else { ++ while (first && (next = dict_next(dict, first))) { ++ if (dict->compare(first->key, next->key) >= 0) ++ return 0; ++ first = next; ++ } ++ } ++ return 1; ++} ++ ++/* ++ * This function recursively verifies that the given binary subtree satisfies ++ * three of the red black properties. It checks that every red node has only ++ * black children. It makes sure that each node is either red or black. And it ++ * checks that every path has the same count of black nodes from root to leaf. ++ * It returns the blackheight of the given subtree; this allows blackheights to ++ * be computed recursively and compared for left and right siblings for ++ * mismatches. It does not check for every nil node being black, because there ++ * is only one sentinel nil node. The return value of this function is the ++ * black height of the subtree rooted at the node ``root'', or zero if the ++ * subtree is not red-black. ++ */ ++ ++static unsigned int verify_redblack(dnode_t *nil, dnode_t *root) ++{ ++ unsigned height_left, height_right; ++ ++ if (root != nil) { ++ height_left = verify_redblack(nil, root->left); ++ height_right = verify_redblack(nil, root->right); ++ if (height_left == 0 || height_right == 0) ++ return 0; ++ if (height_left != height_right) ++ return 0; ++ if (root->color == dnode_red) { ++ if (root->left->color != dnode_black) ++ return 0; ++ if (root->right->color != dnode_black) ++ return 0; ++ return height_left; ++ } ++ if (root->color != dnode_black) ++ return 0; ++ return height_left + 1; ++ } ++ return 1; ++} ++ ++/* ++ * Compute the actual count of nodes by traversing the tree and ++ * return it. This could be compared against the stored count to ++ * detect a mismatch. ++ */ ++ ++static dictcount_t verify_node_count(dnode_t *nil, dnode_t *root) ++{ ++ if (root == nil) ++ return 0; ++ else ++ return 1 + verify_node_count(nil, root->left) ++ + verify_node_count(nil, root->right); ++} ++#endif ++ ++/* ++ * Verify that the tree contains the given node. This is done by ++ * traversing all of the nodes and comparing their pointers to the ++ * given pointer. Returns 1 if the node is found, otherwise ++ * returns zero. It is intended for debugging purposes. ++ */ ++ ++static int verify_dict_has_node(dnode_t *nil, dnode_t *root, dnode_t *node) ++{ ++ if (root != nil) { ++ return root == node ++ || verify_dict_has_node(nil, root->left, node) ++ || verify_dict_has_node(nil, root->right, node); ++ } ++ return 0; ++} ++ ++ ++#ifdef E2FSCK_NOTUSED ++/* ++ * Dynamically allocate and initialize a dictionary object. ++ */ ++ ++dict_t *dict_create(dictcount_t maxcount, dict_comp_t comp) ++{ ++ dict_t *new = malloc(sizeof *new); ++ ++ if (new) { ++ new->compare = comp; ++ new->allocnode = dnode_alloc; ++ new->freenode = dnode_free; ++ new->context = NULL; ++ new->nodecount = 0; ++ new->maxcount = maxcount; ++ new->nilnode.left = &new->nilnode; ++ new->nilnode.right = &new->nilnode; ++ new->nilnode.parent = &new->nilnode; ++ new->nilnode.color = dnode_black; ++ new->dupes = 0; ++ } ++ return new; ++} ++#endif /* E2FSCK_NOTUSED */ ++ ++/* ++ * Select a different set of node allocator routines. ++ */ ++ ++void dict_set_allocator(dict_t *dict, dnode_alloc_t al, ++ dnode_free_t fr, void *context) ++{ ++ dict_assert (dict_count(dict) == 0); ++ dict_assert ((al == NULL && fr == NULL) || (al != NULL && fr != NULL)); ++ ++ dict->allocnode = al ? al : dnode_alloc; ++ dict->freenode = fr ? fr : dnode_free; ++ dict->context = context; ++} ++ ++#ifdef E2FSCK_NOTUSED ++/* ++ * Free a dynamically allocated dictionary object. Removing the nodes ++ * from the tree before deleting it is required. ++ */ ++ ++void dict_destroy(dict_t *dict) ++{ ++ dict_assert (dict_isempty(dict)); ++ free(dict); ++} ++#endif ++ ++/* ++ * Free all the nodes in the dictionary by using the dictionary's ++ * installed free routine. The dictionary is emptied. ++ */ ++ ++void dict_free_nodes(dict_t *dict) ++{ ++ dnode_t *nil = dict_nil(dict), *root = dict_root(dict); ++ free_nodes(dict, root, nil); ++ dict->nodecount = 0; ++ dict->nilnode.left = &dict->nilnode; ++ dict->nilnode.right = &dict->nilnode; ++} ++ ++#ifdef E2FSCK_NOTUSED ++/* ++ * Obsolescent function, equivalent to dict_free_nodes ++ */ ++void dict_free(dict_t *dict) ++{ ++#ifdef KAZLIB_OBSOLESCENT_DEBUG ++ dict_assert ("call to obsolescent function dict_free()" && 0); ++#endif ++ dict_free_nodes(dict); ++} ++#endif ++ ++/* ++ * Initialize a user-supplied dictionary object. ++ */ ++ ++dict_t *dict_init(dict_t *dict, dictcount_t maxcount, dict_comp_t comp) ++{ ++ dict->compare = comp; ++ dict->allocnode = dnode_alloc; ++ dict->freenode = dnode_free; ++ dict->context = NULL; ++ dict->nodecount = 0; ++ dict->maxcount = maxcount; ++ dict->nilnode.left = &dict->nilnode; ++ dict->nilnode.right = &dict->nilnode; ++ dict->nilnode.parent = &dict->nilnode; ++ dict->nilnode.color = dnode_black; ++ dict->dupes = 0; ++ return dict; ++} ++ ++#ifdef E2FSCK_NOTUSED ++/* ++ * Initialize a dictionary in the likeness of another dictionary ++ */ ++ ++void dict_init_like(dict_t *dict, const dict_t *template) ++{ ++ dict->compare = template->compare; ++ dict->allocnode = template->allocnode; ++ dict->freenode = template->freenode; ++ dict->context = template->context; ++ dict->nodecount = 0; ++ dict->maxcount = template->maxcount; ++ dict->nilnode.left = &dict->nilnode; ++ dict->nilnode.right = &dict->nilnode; ++ dict->nilnode.parent = &dict->nilnode; ++ dict->nilnode.color = dnode_black; ++ dict->dupes = template->dupes; ++ ++ dict_assert (dict_similar(dict, template)); ++} ++ ++/* ++ * Remove all nodes from the dictionary (without freeing them in any way). ++ */ ++ ++static void dict_clear(dict_t *dict) ++{ ++ dict->nodecount = 0; ++ dict->nilnode.left = &dict->nilnode; ++ dict->nilnode.right = &dict->nilnode; ++ dict->nilnode.parent = &dict->nilnode; ++ dict_assert (dict->nilnode.color == dnode_black); ++} ++#endif /* E2FSCK_NOTUSED */ ++ ++ ++/* ++ * Verify the integrity of the dictionary structure. This is provided for ++ * debugging purposes, and should be placed in assert statements. Just because ++ * this function succeeds doesn't mean that the tree is not corrupt. Certain ++ * corruptions in the tree may simply cause undefined behavior. ++ */ ++#ifndef DICT_NODEBUG ++int dict_verify(dict_t *dict) ++{ ++ dnode_t *nil = dict_nil(dict), *root = dict_root(dict); ++ ++ /* check that the sentinel node and root node are black */ ++ if (root->color != dnode_black) ++ return 0; ++ if (nil->color != dnode_black) ++ return 0; ++ if (nil->right != nil) ++ return 0; ++ /* nil->left is the root node; check that its parent pointer is nil */ ++ if (nil->left->parent != nil) ++ return 0; ++ /* perform a weak test that the tree is a binary search tree */ ++ if (!verify_bintree(dict)) ++ return 0; ++ /* verify that the tree is a red-black tree */ ++ if (!verify_redblack(nil, root)) ++ return 0; ++ if (verify_node_count(nil, root) != dict_count(dict)) ++ return 0; ++ return 1; ++} ++#endif /* DICT_NODEBUG */ ++ ++#ifdef E2FSCK_NOTUSED ++/* ++ * Determine whether two dictionaries are similar: have the same comparison and ++ * allocator functions, and same status as to whether duplicates are allowed. ++ */ ++int dict_similar(const dict_t *left, const dict_t *right) ++{ ++ if (left->compare != right->compare) ++ return 0; ++ ++ if (left->allocnode != right->allocnode) ++ return 0; ++ ++ if (left->freenode != right->freenode) ++ return 0; ++ ++ if (left->context != right->context) ++ return 0; ++ ++ if (left->dupes != right->dupes) ++ return 0; ++ ++ return 1; ++} ++#endif /* E2FSCK_NOTUSED */ ++ ++/* ++ * Locate a node in the dictionary having the given key. ++ * If the node is not found, a null a pointer is returned (rather than ++ * a pointer that dictionary's nil sentinel node), otherwise a pointer to the ++ * located node is returned. ++ */ ++ ++dnode_t *dict_lookup(dict_t *dict, const void *key) ++{ ++ dnode_t *root = dict_root(dict); ++ dnode_t *nil = dict_nil(dict); ++ dnode_t *saved; ++ int result; ++ ++ /* simple binary search adapted for trees that contain duplicate keys */ ++ ++ while (root != nil) { ++ result = dict->compare(key, root->key); ++ if (result < 0) ++ root = root->left; ++ else if (result > 0) ++ root = root->right; ++ else { ++ if (!dict->dupes) { /* no duplicates, return match */ ++ return root; ++ } else { /* could be dupes, find leftmost one */ ++ do { ++ saved = root; ++ root = root->left; ++ while (root != nil && dict->compare(key, root->key)) ++ root = root->right; ++ } while (root != nil); ++ return saved; ++ } ++ } ++ } ++ ++ return NULL; ++} ++ ++#ifdef E2FSCK_NOTUSED ++/* ++ * Look for the node corresponding to the lowest key that is equal to or ++ * greater than the given key. If there is no such node, return null. ++ */ ++ ++dnode_t *dict_lower_bound(dict_t *dict, const void *key) ++{ ++ dnode_t *root = dict_root(dict); ++ dnode_t *nil = dict_nil(dict); ++ dnode_t *tentative = 0; ++ ++ while (root != nil) { ++ int result = dict->compare(key, root->key); ++ ++ if (result > 0) { ++ root = root->right; ++ } else if (result < 0) { ++ tentative = root; ++ root = root->left; ++ } else { ++ if (!dict->dupes) { ++ return root; ++ } else { ++ tentative = root; ++ root = root->left; ++ } ++ } ++ } ++ ++ return tentative; ++} ++ ++/* ++ * Look for the node corresponding to the greatest key that is equal to or ++ * lower than the given key. If there is no such node, return null. ++ */ ++ ++dnode_t *dict_upper_bound(dict_t *dict, const void *key) ++{ ++ dnode_t *root = dict_root(dict); ++ dnode_t *nil = dict_nil(dict); ++ dnode_t *tentative = 0; ++ ++ while (root != nil) { ++ int result = dict->compare(key, root->key); ++ ++ if (result < 0) { ++ root = root->left; ++ } else if (result > 0) { ++ tentative = root; ++ root = root->right; ++ } else { ++ if (!dict->dupes) { ++ return root; ++ } else { ++ tentative = root; ++ root = root->right; ++ } ++ } ++ } ++ ++ return tentative; ++} ++#endif ++ ++/* ++ * Insert a node into the dictionary. The node should have been ++ * initialized with a data field. All other fields are ignored. ++ * The behavior is undefined if the user attempts to insert into ++ * a dictionary that is already full (for which the dict_isfull() ++ * function returns true). ++ */ ++ ++void dict_insert(dict_t *dict, dnode_t *node, const void *key) ++{ ++ dnode_t *where = dict_root(dict), *nil = dict_nil(dict); ++ dnode_t *parent = nil, *uncle, *grandpa; ++ int result = -1; ++ ++ node->key = key; ++ ++ dict_assert (!dict_isfull(dict)); ++ dict_assert (!dict_contains(dict, node)); ++ dict_assert (!dnode_is_in_a_dict(node)); ++ ++ /* basic binary tree insert */ ++ ++ while (where != nil) { ++ parent = where; ++ result = dict->compare(key, where->key); ++ /* trap attempts at duplicate key insertion unless it's explicitly allowed */ ++ dict_assert (dict->dupes || result != 0); ++ if (result < 0) ++ where = where->left; ++ else ++ where = where->right; ++ } ++ ++ dict_assert (where == nil); ++ ++ if (result < 0) ++ parent->left = node; ++ else ++ parent->right = node; ++ ++ node->parent = parent; ++ node->left = nil; ++ node->right = nil; ++ ++ dict->nodecount++; ++ ++ /* red black adjustments */ ++ ++ node->color = dnode_red; ++ ++ while (parent->color == dnode_red) { ++ grandpa = parent->parent; ++ if (parent == grandpa->left) { ++ uncle = grandpa->right; ++ if (uncle->color == dnode_red) { /* red parent, red uncle */ ++ parent->color = dnode_black; ++ uncle->color = dnode_black; ++ grandpa->color = dnode_red; ++ node = grandpa; ++ parent = grandpa->parent; ++ } else { /* red parent, black uncle */ ++ if (node == parent->right) { ++ rotate_left(parent); ++ parent = node; ++ dict_assert (grandpa == parent->parent); ++ /* rotation between parent and child preserves grandpa */ ++ } ++ parent->color = dnode_black; ++ grandpa->color = dnode_red; ++ rotate_right(grandpa); ++ break; ++ } ++ } else { /* symmetric cases: parent == parent->parent->right */ ++ uncle = grandpa->left; ++ if (uncle->color == dnode_red) { ++ parent->color = dnode_black; ++ uncle->color = dnode_black; ++ grandpa->color = dnode_red; ++ node = grandpa; ++ parent = grandpa->parent; ++ } else { ++ if (node == parent->left) { ++ rotate_right(parent); ++ parent = node; ++ dict_assert (grandpa == parent->parent); ++ } ++ parent->color = dnode_black; ++ grandpa->color = dnode_red; ++ rotate_left(grandpa); ++ break; ++ } ++ } ++ } ++ ++ dict_root(dict)->color = dnode_black; ++ ++ dict_assert (dict_verify(dict)); ++} ++ ++#ifdef E2FSCK_NOTUSED ++/* ++ * Delete the given node from the dictionary. If the given node does not belong ++ * to the given dictionary, undefined behavior results. A pointer to the ++ * deleted node is returned. ++ */ ++ ++dnode_t *dict_delete(dict_t *dict, dnode_t *delete) ++{ ++ dnode_t *nil = dict_nil(dict), *child, *delparent = delete->parent; ++ ++ /* basic deletion */ ++ ++ dict_assert (!dict_isempty(dict)); ++ dict_assert (dict_contains(dict, delete)); ++ ++ /* ++ * If the node being deleted has two children, then we replace it with its ++ * successor (i.e. the leftmost node in the right subtree.) By doing this, ++ * we avoid the traditional algorithm under which the successor's key and ++ * value *only* move to the deleted node and the successor is spliced out ++ * from the tree. We cannot use this approach because the user may hold ++ * pointers to the successor, or nodes may be inextricably tied to some ++ * other structures by way of embedding, etc. So we must splice out the ++ * node we are given, not some other node, and must not move contents from ++ * one node to another behind the user's back. ++ */ ++ ++ if (delete->left != nil && delete->right != nil) { ++ dnode_t *next = dict_next(dict, delete); ++ dnode_t *nextparent = next->parent; ++ dnode_color_t nextcolor = next->color; ++ ++ dict_assert (next != nil); ++ dict_assert (next->parent != nil); ++ dict_assert (next->left == nil); ++ ++ /* ++ * First, splice out the successor from the tree completely, by ++ * moving up its right child into its place. ++ */ ++ ++ child = next->right; ++ child->parent = nextparent; ++ ++ if (nextparent->left == next) { ++ nextparent->left = child; ++ } else { ++ dict_assert (nextparent->right == next); ++ nextparent->right = child; ++ } ++ ++ /* ++ * Now that the successor has been extricated from the tree, install it ++ * in place of the node that we want deleted. ++ */ ++ ++ next->parent = delparent; ++ next->left = delete->left; ++ next->right = delete->right; ++ next->left->parent = next; ++ next->right->parent = next; ++ next->color = delete->color; ++ delete->color = nextcolor; ++ ++ if (delparent->left == delete) { ++ delparent->left = next; ++ } else { ++ dict_assert (delparent->right == delete); ++ delparent->right = next; ++ } ++ ++ } else { ++ dict_assert (delete != nil); ++ dict_assert (delete->left == nil || delete->right == nil); ++ ++ child = (delete->left != nil) ? delete->left : delete->right; ++ ++ child->parent = delparent = delete->parent; ++ ++ if (delete == delparent->left) { ++ delparent->left = child; ++ } else { ++ dict_assert (delete == delparent->right); ++ delparent->right = child; ++ } ++ } ++ ++ delete->parent = NULL; ++ delete->right = NULL; ++ delete->left = NULL; ++ ++ dict->nodecount--; ++ ++ dict_assert (verify_bintree(dict)); ++ ++ /* red-black adjustments */ ++ ++ if (delete->color == dnode_black) { ++ dnode_t *parent, *sister; ++ ++ dict_root(dict)->color = dnode_red; ++ ++ while (child->color == dnode_black) { ++ parent = child->parent; ++ if (child == parent->left) { ++ sister = parent->right; ++ dict_assert (sister != nil); ++ if (sister->color == dnode_red) { ++ sister->color = dnode_black; ++ parent->color = dnode_red; ++ rotate_left(parent); ++ sister = parent->right; ++ dict_assert (sister != nil); ++ } ++ if (sister->left->color == dnode_black ++ && sister->right->color == dnode_black) { ++ sister->color = dnode_red; ++ child = parent; ++ } else { ++ if (sister->right->color == dnode_black) { ++ dict_assert (sister->left->color == dnode_red); ++ sister->left->color = dnode_black; ++ sister->color = dnode_red; ++ rotate_right(sister); ++ sister = parent->right; ++ dict_assert (sister != nil); ++ } ++ sister->color = parent->color; ++ sister->right->color = dnode_black; ++ parent->color = dnode_black; ++ rotate_left(parent); ++ break; ++ } ++ } else { /* symmetric case: child == child->parent->right */ ++ dict_assert (child == parent->right); ++ sister = parent->left; ++ dict_assert (sister != nil); ++ if (sister->color == dnode_red) { ++ sister->color = dnode_black; ++ parent->color = dnode_red; ++ rotate_right(parent); ++ sister = parent->left; ++ dict_assert (sister != nil); ++ } ++ if (sister->right->color == dnode_black ++ && sister->left->color == dnode_black) { ++ sister->color = dnode_red; ++ child = parent; ++ } else { ++ if (sister->left->color == dnode_black) { ++ dict_assert (sister->right->color == dnode_red); ++ sister->right->color = dnode_black; ++ sister->color = dnode_red; ++ rotate_left(sister); ++ sister = parent->left; ++ dict_assert (sister != nil); ++ } ++ sister->color = parent->color; ++ sister->left->color = dnode_black; ++ parent->color = dnode_black; ++ rotate_right(parent); ++ break; ++ } ++ } ++ } ++ ++ child->color = dnode_black; ++ dict_root(dict)->color = dnode_black; ++ } ++ ++ dict_assert (dict_verify(dict)); ++ ++ return delete; ++} ++#endif /* E2FSCK_NOTUSED */ ++ ++/* ++ * Allocate a node using the dictionary's allocator routine, give it ++ * the data item. ++ */ ++ ++int dict_alloc_insert(dict_t *dict, const void *key, void *data) ++{ ++ dnode_t *node = dict->allocnode(dict->context); ++ ++ if (node) { ++ dnode_init(node, data); ++ dict_insert(dict, node, key); ++ return 1; ++ } ++ return 0; ++} ++ ++#ifdef E2FSCK_NOTUSED ++void dict_delete_free(dict_t *dict, dnode_t *node) ++{ ++ dict_delete(dict, node); ++ dict->freenode(node, dict->context); ++} ++#endif ++ ++/* ++ * Return the node with the lowest (leftmost) key. If the dictionary is empty ++ * (that is, dict_isempty(dict) returns 1) a null pointer is returned. ++ */ ++ ++dnode_t *dict_first(dict_t *dict) ++{ ++ dnode_t *nil = dict_nil(dict), *root = dict_root(dict), *left; ++ ++ if (root != nil) ++ while ((left = root->left) != nil) ++ root = left; ++ ++ return (root == nil) ? NULL : root; ++} ++ ++/* ++ * Return the node with the highest (rightmost) key. If the dictionary is empty ++ * (that is, dict_isempty(dict) returns 1) a null pointer is returned. ++ */ ++ ++dnode_t *dict_last(dict_t *dict) ++{ ++ dnode_t *nil = dict_nil(dict), *root = dict_root(dict), *right; ++ ++ if (root != nil) ++ while ((right = root->right) != nil) ++ root = right; ++ ++ return (root == nil) ? NULL : root; ++} ++ ++/* ++ * Return the given node's successor node---the node which has the ++ * next key in the the left to right ordering. If the node has ++ * no successor, a null pointer is returned rather than a pointer to ++ * the nil node. ++ */ ++ ++dnode_t *dict_next(dict_t *dict, dnode_t *curr) ++{ ++ dnode_t *nil = dict_nil(dict), *parent, *left; ++ ++ if (curr->right != nil) { ++ curr = curr->right; ++ while ((left = curr->left) != nil) ++ curr = left; ++ return curr; ++ } ++ ++ parent = curr->parent; ++ ++ while (parent != nil && curr == parent->right) { ++ curr = parent; ++ parent = curr->parent; ++ } ++ ++ return (parent == nil) ? NULL : parent; ++} ++ ++/* ++ * Return the given node's predecessor, in the key order. ++ * The nil sentinel node is returned if there is no predecessor. ++ */ ++ ++dnode_t *dict_prev(dict_t *dict, dnode_t *curr) ++{ ++ dnode_t *nil = dict_nil(dict), *parent, *right; ++ ++ if (curr->left != nil) { ++ curr = curr->left; ++ while ((right = curr->right) != nil) ++ curr = right; ++ return curr; ++ } ++ ++ parent = curr->parent; ++ ++ while (parent != nil && curr == parent->left) { ++ curr = parent; ++ parent = curr->parent; ++ } ++ ++ return (parent == nil) ? NULL : parent; ++} ++ ++void dict_allow_dupes(dict_t *dict) ++{ ++ dict->dupes = 1; ++} ++ ++#undef dict_count ++#undef dict_isempty ++#undef dict_isfull ++#undef dnode_get ++#undef dnode_put ++#undef dnode_getkey ++ ++dictcount_t dict_count(dict_t *dict) ++{ ++ return dict->nodecount; ++} ++ ++int dict_isempty(dict_t *dict) ++{ ++ return dict->nodecount == 0; ++} ++ ++int dict_isfull(dict_t *dict) ++{ ++ return dict->nodecount == dict->maxcount; ++} ++ ++int dict_contains(dict_t *dict, dnode_t *node) ++{ ++ return verify_dict_has_node(dict_nil(dict), dict_root(dict), node); ++} ++ ++static dnode_t *dnode_alloc(void *context EXT2FS_ATTR((unused))) ++{ ++ return malloc(sizeof *dnode_alloc(NULL)); ++} ++ ++static void dnode_free(dnode_t *node, void *context EXT2FS_ATTR((unused))) ++{ ++ free(node); ++} ++ ++dnode_t *dnode_create(void *data) ++{ ++ dnode_t *new = malloc(sizeof *new); ++ if (new) { ++ new->data = data; ++ new->parent = NULL; ++ new->left = NULL; ++ new->right = NULL; ++ } ++ return new; ++} ++ ++dnode_t *dnode_init(dnode_t *dnode, void *data) ++{ ++ dnode->data = data; ++ dnode->parent = NULL; ++ dnode->left = NULL; ++ dnode->right = NULL; ++ return dnode; ++} ++ ++void dnode_destroy(dnode_t *dnode) ++{ ++ dict_assert (!dnode_is_in_a_dict(dnode)); ++ free(dnode); ++} ++ ++void *dnode_get(dnode_t *dnode) ++{ ++ return dnode->data; ++} ++ ++const void *dnode_getkey(dnode_t *dnode) ++{ ++ return dnode->key; ++} ++ ++#ifdef E2FSCK_NOTUSED ++void dnode_put(dnode_t *dnode, void *data) ++{ ++ dnode->data = data; ++} ++#endif ++ ++#ifndef DICT_NODEBUG ++int dnode_is_in_a_dict(dnode_t *dnode) ++{ ++ return (dnode->parent && dnode->left && dnode->right); ++} ++#endif ++ ++#ifdef E2FSCK_NOTUSED ++void dict_process(dict_t *dict, void *context, dnode_process_t function) ++{ ++ dnode_t *node = dict_first(dict), *next; ++ ++ while (node != NULL) { ++ /* check for callback function deleting */ ++ /* the next node from under us */ ++ dict_assert (dict_contains(dict, node)); ++ next = dict_next(dict, node); ++ function(dict, node, context); ++ node = next; ++ } ++} ++ ++static void load_begin_internal(dict_load_t *load, dict_t *dict) ++{ ++ load->dictptr = dict; ++ load->nilnode.left = &load->nilnode; ++ load->nilnode.right = &load->nilnode; ++} ++ ++void dict_load_begin(dict_load_t *load, dict_t *dict) ++{ ++ dict_assert (dict_isempty(dict)); ++ load_begin_internal(load, dict); ++} ++ ++void dict_load_next(dict_load_t *load, dnode_t *newnode, const void *key) ++{ ++ dict_t *dict = load->dictptr; ++ dnode_t *nil = &load->nilnode; ++ ++ dict_assert (!dnode_is_in_a_dict(newnode)); ++ dict_assert (dict->nodecount < dict->maxcount); ++ ++#ifndef DICT_NODEBUG ++ if (dict->nodecount > 0) { ++ if (dict->dupes) ++ dict_assert (dict->compare(nil->left->key, key) <= 0); ++ else ++ dict_assert (dict->compare(nil->left->key, key) < 0); ++ } ++#endif ++ ++ newnode->key = key; ++ nil->right->left = newnode; ++ nil->right = newnode; ++ newnode->left = nil; ++ dict->nodecount++; ++} ++ ++void dict_load_end(dict_load_t *load) ++{ ++ dict_t *dict = load->dictptr; ++ dnode_t *tree[DICT_DEPTH_MAX] = { 0 }; ++ dnode_t *curr, *dictnil = dict_nil(dict), *loadnil = &load->nilnode, *next; ++ dnode_t *complete = 0; ++ dictcount_t fullcount = DICTCOUNT_T_MAX, nodecount = dict->nodecount; ++ dictcount_t botrowcount; ++ unsigned baselevel = 0, level = 0, i; ++ ++ dict_assert (dnode_red == 0 && dnode_black == 1); ++ ++ while (fullcount >= nodecount && fullcount) ++ fullcount >>= 1; ++ ++ botrowcount = nodecount - fullcount; ++ ++ for (curr = loadnil->left; curr != loadnil; curr = next) { ++ next = curr->left; ++ ++ if (complete == NULL && botrowcount-- == 0) { ++ dict_assert (baselevel == 0); ++ dict_assert (level == 0); ++ baselevel = level = 1; ++ complete = tree[0]; ++ ++ if (complete != 0) { ++ tree[0] = 0; ++ complete->right = dictnil; ++ while (tree[level] != 0) { ++ tree[level]->right = complete; ++ complete->parent = tree[level]; ++ complete = tree[level]; ++ tree[level++] = 0; ++ } ++ } ++ } ++ ++ if (complete == NULL) { ++ curr->left = dictnil; ++ curr->right = dictnil; ++ curr->color = level % 2; ++ complete = curr; ++ ++ dict_assert (level == baselevel); ++ while (tree[level] != 0) { ++ tree[level]->right = complete; ++ complete->parent = tree[level]; ++ complete = tree[level]; ++ tree[level++] = 0; ++ } ++ } else { ++ curr->left = complete; ++ curr->color = (level + 1) % 2; ++ complete->parent = curr; ++ tree[level] = curr; ++ complete = 0; ++ level = baselevel; ++ } ++ } ++ ++ if (complete == NULL) ++ complete = dictnil; ++ ++ for (i = 0; i < DICT_DEPTH_MAX; i++) { ++ if (tree[i] != 0) { ++ tree[i]->right = complete; ++ complete->parent = tree[i]; ++ complete = tree[i]; ++ } ++ } ++ ++ dictnil->color = dnode_black; ++ dictnil->right = dictnil; ++ complete->parent = dictnil; ++ complete->color = dnode_black; ++ dict_root(dict) = complete; ++ ++ dict_assert (dict_verify(dict)); ++} ++ ++void dict_merge(dict_t *dest, dict_t *source) ++{ ++ dict_load_t load; ++ dnode_t *leftnode = dict_first(dest), *rightnode = dict_first(source); ++ ++ dict_assert (dict_similar(dest, source)); ++ ++ if (source == dest) ++ return; ++ ++ dest->nodecount = 0; ++ load_begin_internal(&load, dest); ++ ++ for (;;) { ++ if (leftnode != NULL && rightnode != NULL) { ++ if (dest->compare(leftnode->key, rightnode->key) < 0) ++ goto copyleft; ++ else ++ goto copyright; ++ } else if (leftnode != NULL) { ++ goto copyleft; ++ } else if (rightnode != NULL) { ++ goto copyright; ++ } else { ++ dict_assert (leftnode == NULL && rightnode == NULL); ++ break; ++ } ++ ++ copyleft: ++ { ++ dnode_t *next = dict_next(dest, leftnode); ++#ifndef DICT_NODEBUG ++ leftnode->left = NULL; /* suppress assertion in dict_load_next */ ++#endif ++ dict_load_next(&load, leftnode, leftnode->key); ++ leftnode = next; ++ continue; ++ } ++ ++ copyright: ++ { ++ dnode_t *next = dict_next(source, rightnode); ++#ifndef DICT_NODEBUG ++ rightnode->left = NULL; ++#endif ++ dict_load_next(&load, rightnode, rightnode->key); ++ rightnode = next; ++ continue; ++ } ++ } ++ ++ dict_clear(source); ++ dict_load_end(&load); ++} ++#endif /* E2FSCK_NOTUSED */ ++ ++#ifdef KAZLIB_TEST_MAIN ++ ++#include ++#include ++#include ++#include ++ ++typedef char input_t[256]; ++ ++static int tokenize(char *string, ...) ++{ ++ char **tokptr; ++ va_list arglist; ++ int tokcount = 0; ++ ++ va_start(arglist, string); ++ tokptr = va_arg(arglist, char **); ++ while (tokptr) { ++ while (*string && isspace((unsigned char) *string)) ++ string++; ++ if (!*string) ++ break; ++ *tokptr = string; ++ while (*string && !isspace((unsigned char) *string)) ++ string++; ++ tokptr = va_arg(arglist, char **); ++ tokcount++; ++ if (!*string) ++ break; ++ *string++ = 0; ++ } ++ va_end(arglist); ++ ++ return tokcount; ++} ++ ++static int comparef(const void *key1, const void *key2) ++{ ++ return strcmp(key1, key2); ++} ++ ++static char *dupstring(char *str) ++{ ++ int sz = strlen(str) + 1; ++ char *new = malloc(sz); ++ if (new) ++ memcpy(new, str, sz); ++ return new; ++} ++ ++static dnode_t *new_node(void *c) ++{ ++ static dnode_t few[5]; ++ static int count; ++ ++ if (count < 5) ++ return few + count++; ++ ++ return NULL; ++} ++ ++static void del_node(dnode_t *n, void *c) ++{ ++} ++ ++static int prompt = 0; ++ ++static void construct(dict_t *d) ++{ ++ input_t in; ++ int done = 0; ++ dict_load_t dl; ++ dnode_t *dn; ++ char *tok1, *tok2, *val; ++ const char *key; ++ char *help = ++ "p turn prompt on\n" ++ "q finish construction\n" ++ "a add new entry\n"; ++ ++ if (!dict_isempty(d)) ++ puts("warning: dictionary not empty!"); ++ ++ dict_load_begin(&dl, d); ++ ++ while (!done) { ++ if (prompt) ++ putchar('>'); ++ fflush(stdout); ++ ++ if (!fgets(in, sizeof(input_t), stdin)) ++ break; ++ ++ switch (in[0]) { ++ case '?': ++ puts(help); ++ break; ++ case 'p': ++ prompt = 1; ++ break; ++ case 'q': ++ done = 1; ++ break; ++ case 'a': ++ if (tokenize(in+1, &tok1, &tok2, (char **) 0) != 2) { ++ puts("what?"); ++ break; ++ } ++ key = dupstring(tok1); ++ val = dupstring(tok2); ++ dn = dnode_create(val); ++ ++ if (!key || !val || !dn) { ++ puts("out of memory"); ++ free((void *) key); ++ free(val); ++ if (dn) ++ dnode_destroy(dn); ++ } ++ ++ dict_load_next(&dl, dn, key); ++ break; ++ default: ++ putchar('?'); ++ putchar('\n'); ++ break; ++ } ++ } ++ ++ dict_load_end(&dl); ++} ++ ++int main(void) ++{ ++ input_t in; ++ dict_t darray[10]; ++ dict_t *d = &darray[0]; ++ dnode_t *dn; ++ int i; ++ char *tok1, *tok2, *val; ++ const char *key; ++ ++ char *help = ++ "a add value to dictionary\n" ++ "d delete value from dictionary\n" ++ "l lookup value in dictionary\n" ++ "( lookup lower bound\n" ++ ") lookup upper bound\n" ++ "# switch to alternate dictionary (0-9)\n" ++ "j merge two dictionaries\n" ++ "f free the whole dictionary\n" ++ "k allow duplicate keys\n" ++ "c show number of entries\n" ++ "t dump whole dictionary in sort order\n" ++ "m make dictionary out of sorted items\n" ++ "p turn prompt on\n" ++ "s switch to non-functioning allocator\n" ++ "q quit"; ++ ++ for (i = 0; i < sizeof darray / sizeof *darray; i++) ++ dict_init(&darray[i], DICTCOUNT_T_MAX, comparef); ++ ++ for (;;) { ++ if (prompt) ++ putchar('>'); ++ fflush(stdout); ++ ++ if (!fgets(in, sizeof(input_t), stdin)) ++ break; ++ ++ switch(in[0]) { ++ case '?': ++ puts(help); ++ break; ++ case 'a': ++ if (tokenize(in+1, &tok1, &tok2, (char **) 0) != 2) { ++ puts("what?"); ++ break; ++ } ++ key = dupstring(tok1); ++ val = dupstring(tok2); ++ ++ if (!key || !val) { ++ puts("out of memory"); ++ free((void *) key); ++ free(val); ++ } ++ ++ if (!dict_alloc_insert(d, key, val)) { ++ puts("dict_alloc_insert failed"); ++ free((void *) key); ++ free(val); ++ break; ++ } ++ break; ++ case 'd': ++ if (tokenize(in+1, &tok1, (char **) 0) != 1) { ++ puts("what?"); ++ break; ++ } ++ dn = dict_lookup(d, tok1); ++ if (!dn) { ++ puts("dict_lookup failed"); ++ break; ++ } ++ val = dnode_get(dn); ++ key = dnode_getkey(dn); ++ dict_delete_free(d, dn); ++ ++ free(val); ++ free((void *) key); ++ break; ++ case 'f': ++ dict_free(d); ++ break; ++ case 'l': ++ case '(': ++ case ')': ++ if (tokenize(in+1, &tok1, (char **) 0) != 1) { ++ puts("what?"); ++ break; ++ } ++ dn = 0; ++ switch (in[0]) { ++ case 'l': ++ dn = dict_lookup(d, tok1); ++ break; ++ case '(': ++ dn = dict_lower_bound(d, tok1); ++ break; ++ case ')': ++ dn = dict_upper_bound(d, tok1); ++ break; ++ } ++ if (!dn) { ++ puts("lookup failed"); ++ break; ++ } ++ val = dnode_get(dn); ++ puts(val); ++ break; ++ case 'm': ++ construct(d); ++ break; ++ case 'k': ++ dict_allow_dupes(d); ++ break; ++ case 'c': ++ printf("%lu\n", (unsigned long) dict_count(d)); ++ break; ++ case 't': ++ for (dn = dict_first(d); dn; dn = dict_next(d, dn)) { ++ printf("%s\t%s\n", (char *) dnode_getkey(dn), ++ (char *) dnode_get(dn)); ++ } ++ break; ++ case 'q': ++ exit(0); ++ break; ++ case '\0': ++ break; ++ case 'p': ++ prompt = 1; ++ break; ++ case 's': ++ dict_set_allocator(d, new_node, del_node, NULL); ++ break; ++ case '#': ++ if (tokenize(in+1, &tok1, (char **) 0) != 1) { ++ puts("what?"); ++ break; ++ } else { ++ int dictnum = atoi(tok1); ++ if (dictnum < 0 || dictnum > 9) { ++ puts("invalid number"); ++ break; ++ } ++ d = &darray[dictnum]; ++ } ++ break; ++ case 'j': ++ if (tokenize(in+1, &tok1, &tok2, (char **) 0) != 2) { ++ puts("what?"); ++ break; ++ } else { ++ int dict1 = atoi(tok1), dict2 = atoi(tok2); ++ if (dict1 < 0 || dict1 > 9 || dict2 < 0 || dict2 > 9) { ++ puts("invalid number"); ++ break; ++ } ++ dict_merge(&darray[dict1], &darray[dict2]); ++ } ++ break; ++ default: ++ putchar('?'); ++ putchar('\n'); ++ break; ++ } ++ } ++ ++ return 0; ++} ++ ++#endif +--- /dev/null ++++ b/lib/support/dict.h +@@ -0,0 +1,144 @@ ++/* ++ * Dictionary Abstract Data Type ++ * Copyright (C) 1997 Kaz Kylheku ++ * ++ * Free Software License: ++ * ++ * All rights are reserved by the author, with the following exceptions: ++ * Permission is granted to freely reproduce and distribute this software, ++ * possibly in exchange for a fee, provided that this copyright notice appears ++ * intact. Permission is also granted to adapt this software to produce ++ * derivative works, as long as the modified versions carry this copyright ++ * notice and additional notices stating that the work has been modified. ++ * This source code may be translated into executable form and incorporated ++ * into proprietary software; there is no requirement for such software to ++ * contain a copyright notice related to this source. ++ * ++ * $Id: dict.h,v 1.22.2.6 2000/11/13 01:36:44 kaz Exp $ ++ * $Name: kazlib_1_20 $ ++ */ ++ ++#ifndef DICT_H ++#define DICT_H ++ ++#include ++#ifdef KAZLIB_SIDEEFFECT_DEBUG ++#include "sfx.h" ++#endif ++ ++/* ++ * Blurb for inclusion into C++ translation units ++ */ ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++typedef unsigned long dictcount_t; ++#define DICTCOUNT_T_MAX ULONG_MAX ++ ++/* ++ * The dictionary is implemented as a red-black tree ++ */ ++ ++typedef enum { dnode_red, dnode_black } dnode_color_t; ++ ++typedef struct dnode_t { ++#if defined(DICT_IMPLEMENTATION) || !defined(KAZLIB_OPAQUE_DEBUG) ++ struct dnode_t *dict_left; ++ struct dnode_t *dict_right; ++ struct dnode_t *dict_parent; ++ dnode_color_t dict_color; ++ const void *dict_key; ++ void *dict_data; ++#else ++ int dict_dummy; ++#endif ++} dnode_t; ++ ++typedef int (*dict_comp_t)(const void *, const void *); ++typedef dnode_t *(*dnode_alloc_t)(void *); ++typedef void (*dnode_free_t)(dnode_t *, void *); ++ ++typedef struct dict_t { ++#if defined(DICT_IMPLEMENTATION) || !defined(KAZLIB_OPAQUE_DEBUG) ++ dnode_t dict_nilnode; ++ dictcount_t dict_nodecount; ++ dictcount_t dict_maxcount; ++ dict_comp_t dict_compare; ++ dnode_alloc_t dict_allocnode; ++ dnode_free_t dict_freenode; ++ void *dict_context; ++ int dict_dupes; ++#else ++ int dict_dummmy; ++#endif ++} dict_t; ++ ++typedef void (*dnode_process_t)(dict_t *, dnode_t *, void *); ++ ++typedef struct dict_load_t { ++#if defined(DICT_IMPLEMENTATION) || !defined(KAZLIB_OPAQUE_DEBUG) ++ dict_t *dict_dictptr; ++ dnode_t dict_nilnode; ++#else ++ int dict_dummmy; ++#endif ++} dict_load_t; ++ ++extern dict_t *dict_create(dictcount_t, dict_comp_t); ++extern void dict_set_allocator(dict_t *, dnode_alloc_t, dnode_free_t, void *); ++extern void dict_destroy(dict_t *); ++extern void dict_free_nodes(dict_t *); ++extern void dict_free(dict_t *); ++extern dict_t *dict_init(dict_t *, dictcount_t, dict_comp_t); ++extern void dict_init_like(dict_t *, const dict_t *); ++extern int dict_verify(dict_t *); ++extern int dict_similar(const dict_t *, const dict_t *); ++extern dnode_t *dict_lookup(dict_t *, const void *); ++extern dnode_t *dict_lower_bound(dict_t *, const void *); ++extern dnode_t *dict_upper_bound(dict_t *, const void *); ++extern void dict_insert(dict_t *, dnode_t *, const void *); ++extern dnode_t *dict_delete(dict_t *, dnode_t *); ++extern int dict_alloc_insert(dict_t *, const void *, void *); ++extern void dict_delete_free(dict_t *, dnode_t *); ++extern dnode_t *dict_first(dict_t *); ++extern dnode_t *dict_last(dict_t *); ++extern dnode_t *dict_next(dict_t *, dnode_t *); ++extern dnode_t *dict_prev(dict_t *, dnode_t *); ++extern dictcount_t dict_count(dict_t *); ++extern int dict_isempty(dict_t *); ++extern int dict_isfull(dict_t *); ++extern int dict_contains(dict_t *, dnode_t *); ++extern void dict_allow_dupes(dict_t *); ++extern int dnode_is_in_a_dict(dnode_t *); ++extern dnode_t *dnode_create(void *); ++extern dnode_t *dnode_init(dnode_t *, void *); ++extern void dnode_destroy(dnode_t *); ++extern void *dnode_get(dnode_t *); ++extern const void *dnode_getkey(dnode_t *); ++extern void dnode_put(dnode_t *, void *); ++extern void dict_process(dict_t *, void *, dnode_process_t); ++extern void dict_load_begin(dict_load_t *, dict_t *); ++extern void dict_load_next(dict_load_t *, dnode_t *, const void *); ++extern void dict_load_end(dict_load_t *); ++extern void dict_merge(dict_t *, dict_t *); ++ ++#if defined(DICT_IMPLEMENTATION) || !defined(KAZLIB_OPAQUE_DEBUG) ++#ifdef KAZLIB_SIDEEFFECT_DEBUG ++#define dict_isfull(D) (SFX_CHECK(D)->dict_nodecount == (D)->dict_maxcount) ++#else ++#define dict_isfull(D) ((D)->dict_nodecount == (D)->dict_maxcount) ++#endif ++#define dict_count(D) ((D)->dict_nodecount) ++#define dict_isempty(D) ((D)->dict_nodecount == 0) ++#define dnode_get(N) ((N)->dict_data) ++#define dnode_getkey(N) ((N)->dict_key) ++#define dnode_put(N, X) ((N)->dict_data = (X)) ++#endif ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif +--- /dev/null ++++ b/lib/support/dqblk_v2.h +@@ -0,0 +1,31 @@ ++/* ++ * Header file for disk format of new quotafile format ++ * ++ * Jan Kara - sponsored by SuSE CR ++ */ ++ ++#ifndef __QUOTA_DQBLK_V2_H__ ++#define __QUOTA_DQBLK_V2_H__ ++ ++#include "quotaio_tree.h" ++ ++/* Structure for format specific information */ ++struct v2_mem_dqinfo { ++ struct qtree_mem_dqinfo dqi_qtree; ++ unsigned int dqi_flags; /* Flags set in quotafile */ ++ unsigned int dqi_used_entries; /* Number of entries in file - ++ updated by scan_dquots */ ++ unsigned int dqi_data_blocks; /* Number of data blocks in file - ++ updated by scan_dquots */ ++}; ++ ++struct v2_mem_dqblk { ++ long long dqb_off; /* Offset of dquot in file */ ++}; ++ ++struct quotafile_ops; /* Will be defined later in quotaio.h */ ++ ++/* Operations above this format */ ++extern struct quotafile_ops quotafile_ops_2; ++ ++#endif /* __QUOTA_DQBLK_V2_H__ */ +--- /dev/null ++++ b/lib/support/Makefile.in +@@ -0,0 +1,148 @@ ++# Makefile for e2fsprog's internal support ++# ++ ++srcdir = @srcdir@ ++top_srcdir = @top_srcdir@ ++VPATH = @srcdir@ ++top_builddir = ../.. ++my_dir = lib/support ++INSTALL = @INSTALL@ ++ ++@MCONFIG@ ++ ++all:: ++ ++OBJS= mkquota.o \ ++ plausible.o \ ++ profile.o \ ++ profile_helpers.o \ ++ prof_err.o \ ++ quotaio.o \ ++ quotaio_v2.o \ ++ quotaio_tree.o \ ++ dict.o ++ ++SRCS= $(srcdir)/argv_parse.c \ ++ $(srcdir)/mkquota.c \ ++ $(srcdir)/plausible.c \ ++ $(srcdir)/profile.c \ ++ $(srcdir)/profile_helpers.c \ ++ prof_err.c \ ++ $(srcdir)/quotaio.c \ ++ $(srcdir)/quotaio_tree.c \ ++ $(srcdir)/quotaio_v2.c \ ++ $(srcdir)/dict.c ++ ++LIBRARY= libsupport ++LIBDIR= support ++ ++@MAKEFILE_LIBRARY@ ++@MAKEFILE_PROFILE@ ++ ++COMPILE_ET=$(top_builddir)/lib/et/compile_et --build-tree ++ ++.c.o: ++ $(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 $< ++ ++installdirs:: ++ ++install:: all ++ ++uninstall:: ++ ++prof_err.c prof_err.h: prof_err.et ++ $(E) " COMPILE_ET prof_err.et" ++ $(Q) $(COMPILE_ET) $(srcdir)/prof_err.et ++ ++test_profile: $(srcdir)/profile.c profile_helpers.o argv_parse.o \ ++ prof_err.o profile.h $(DEPSTATIC_LIBCOM_ERR) ++ $(E) " LD $@" ++ $(Q) $(CC) -o test_profile -DDEBUG_PROGRAM $(srcdir)/profile.c prof_err.o \ ++ profile_helpers.o argv_parse.o $(STATIC_LIBCOM_ERR) \ ++ $(ALL_CFLAGS) ++ ++clean:: ++ $(RM) -f \#* *.s *.o *.a *~ *.bak core profiled/* \ ++ ../libsupport.a ../libsupport_p.a $(SMANPAGES) \ ++ prof_err.c prof_err.h test_profile ++ ++#check:: tst_uuid ++# LD_LIBRARY_PATH=$(LIB) DYLD_LIBRARY_PATH=$(LIB) ./tst_uuid ++ ++mostlyclean:: clean ++distclean:: clean ++ $(RM) -f .depend Makefile \ ++ $(srcdir)/TAGS $(srcdir)/Makefile.in.old ++ ++# ++# Hack to parallel makes recognize dependencies correctly. ++# ++../../lib/libsupport.a: libsupport.a ++../../lib/libsupport.so: image ++../../lib/libsupport.dylib: image ++ ++$(OBJS): ++ ++# +++ Dependency line eater +++ ++# ++# Makefile dependencies follow. This must be the last section in ++# the Makefile.in file ++# ++argv_parse.o: $(srcdir)/argv_parse.c $(top_builddir)/lib/config.h \ ++ $(top_builddir)/lib/dirpaths.h $(srcdir)/argv_parse.h ++mkquota.o: $(srcdir)/mkquota.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 \ ++ $(top_srcdir)/lib/e2p/e2p.h $(srcdir)/quotaio.h $(srcdir)/dqblk_v2.h \ ++ $(srcdir)/quotaio_tree.h $(srcdir)/quotaio_v2.h $(srcdir)/common.h \ ++ $(srcdir)/dict.h ++plausible.o: $(srcdir)/plausible.c $(top_builddir)/lib/config.h \ ++ $(top_builddir)/lib/dirpaths.h $(srcdir)/plausible.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 ++profile.o: $(srcdir)/profile.c $(top_builddir)/lib/config.h \ ++ $(top_builddir)/lib/dirpaths.h $(top_srcdir)/lib/et/com_err.h \ ++ $(srcdir)/profile.h prof_err.h ++profile_helpers.o: $(srcdir)/profile_helpers.c $(top_builddir)/lib/config.h \ ++ $(top_builddir)/lib/dirpaths.h $(top_srcdir)/lib/et/com_err.h \ ++ $(srcdir)/profile.h prof_err.h ++prof_err.o: prof_err.c ++quotaio.o: $(srcdir)/quotaio.c $(top_builddir)/lib/config.h \ ++ $(top_builddir)/lib/dirpaths.h $(srcdir)/common.h \ ++ $(top_builddir)/lib/ext2fs/ext2_types.h $(srcdir)/quotaio.h \ ++ $(top_srcdir)/lib/ext2fs/ext2_fs.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)/dqblk_v2.h $(srcdir)/quotaio_tree.h ++quotaio_tree.o: $(srcdir)/quotaio_tree.c $(top_builddir)/lib/config.h \ ++ $(top_builddir)/lib/dirpaths.h $(srcdir)/common.h \ ++ $(top_builddir)/lib/ext2fs/ext2_types.h $(srcdir)/quotaio_tree.h \ ++ $(srcdir)/quotaio.h $(top_srcdir)/lib/ext2fs/ext2_fs.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)/dqblk_v2.h ++quotaio_v2.o: $(srcdir)/quotaio_v2.c $(top_builddir)/lib/config.h \ ++ $(top_builddir)/lib/dirpaths.h $(srcdir)/common.h \ ++ $(top_builddir)/lib/ext2fs/ext2_types.h $(srcdir)/quotaio_v2.h \ ++ $(srcdir)/quotaio.h $(top_srcdir)/lib/ext2fs/ext2_fs.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)/dqblk_v2.h $(srcdir)/quotaio_tree.h ++dict.o: $(srcdir)/dict.c $(top_builddir)/lib/config.h \ ++ $(top_builddir)/lib/dirpaths.h $(srcdir)/dict.h +--- /dev/null ++++ b/lib/support/mkquota.c +@@ -0,0 +1,634 @@ ++/* ++ * mkquota.c --- create quota files for a filesystem ++ * ++ * Aditya Kali ++ */ ++#include "config.h" ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "ext2fs/ext2_fs.h" ++#include "ext2fs/ext2fs.h" ++#include "e2p/e2p.h" ++ ++#include "quotaio.h" ++#include "quotaio_v2.h" ++#include "quotaio_tree.h" ++#include "common.h" ++#include "dict.h" ++ ++/* Needed for architectures where sizeof(int) != sizeof(void *) */ ++#define UINT_TO_VOIDPTR(val) ((void *)(intptr_t)(val)) ++#define VOIDPTR_TO_UINT(ptr) ((unsigned int)(intptr_t)(ptr)) ++ ++#if DEBUG_QUOTA ++static void print_inode(struct ext2_inode *inode) ++{ ++ if (!inode) ++ return; ++ ++ fprintf(stderr, " i_mode = %d\n", inode->i_mode); ++ fprintf(stderr, " i_uid = %d\n", inode->i_uid); ++ fprintf(stderr, " i_size = %d\n", inode->i_size); ++ fprintf(stderr, " i_atime = %d\n", inode->i_atime); ++ fprintf(stderr, " i_ctime = %d\n", inode->i_ctime); ++ fprintf(stderr, " i_mtime = %d\n", inode->i_mtime); ++ fprintf(stderr, " i_dtime = %d\n", inode->i_dtime); ++ fprintf(stderr, " i_gid = %d\n", inode->i_gid); ++ fprintf(stderr, " i_links_count = %d\n", inode->i_links_count); ++ fprintf(stderr, " i_blocks = %d\n", inode->i_blocks); ++ fprintf(stderr, " i_flags = %d\n", inode->i_flags); ++ ++ return; ++} ++ ++static void print_dquot(const char *desc, struct dquot *dq) ++{ ++ if (desc) ++ fprintf(stderr, "%s: ", desc); ++ fprintf(stderr, "%u %lld:%lld:%lld %lld:%lld:%lld\n", ++ dq->dq_id, dq->dq_dqb.dqb_curspace, ++ dq->dq_dqb.dqb_bsoftlimit, dq->dq_dqb.dqb_bhardlimit, ++ dq->dq_dqb.dqb_curinodes, ++ dq->dq_dqb.dqb_isoftlimit, dq->dq_dqb.dqb_ihardlimit); ++} ++#else ++static void print_dquot(const char *desc EXT2FS_ATTR((unused)), ++ struct dquot *dq EXT2FS_ATTR((unused))) ++{ ++} ++#endif ++ ++/* ++ * Returns 0 if not able to find the quota file, otherwise returns its ++ * inode number. ++ */ ++int quota_file_exists(ext2_filsys fs, int qtype) ++{ ++ char qf_name[256]; ++ errcode_t ret; ++ ext2_ino_t ino; ++ ++ if (qtype >= MAXQUOTAS) ++ return -EINVAL; ++ ++ quota_get_qf_name(qtype, QFMT_VFS_V1, qf_name); ++ ++ ret = ext2fs_lookup(fs, EXT2_ROOT_INO, qf_name, strlen(qf_name), 0, ++ &ino); ++ if (ret) ++ return 0; ++ ++ return ino; ++} ++ ++/* ++ * Set the value for reserved quota inode number field in superblock. ++ */ ++void quota_set_sb_inum(ext2_filsys fs, ext2_ino_t ino, int qtype) ++{ ++ ext2_ino_t *inump; ++ ++ inump = (qtype == USRQUOTA) ? &fs->super->s_usr_quota_inum : ++ &fs->super->s_grp_quota_inum; ++ ++ log_debug("setting quota ino in superblock: ino=%u, type=%d", ino, ++ qtype); ++ *inump = ino; ++ ext2fs_mark_super_dirty(fs); ++} ++ ++errcode_t quota_remove_inode(ext2_filsys fs, int qtype) ++{ ++ ext2_ino_t qf_ino; ++ errcode_t retval; ++ ++ retval = ext2fs_read_bitmaps(fs); ++ if (retval) { ++ log_err("Couldn't read bitmaps: %s", error_message(retval)); ++ return retval; ++ } ++ qf_ino = (qtype == USRQUOTA) ? fs->super->s_usr_quota_inum : ++ fs->super->s_grp_quota_inum; ++ quota_set_sb_inum(fs, 0, qtype); ++ /* Truncate the inode only if its a reserved one. */ ++ if (qf_ino < EXT2_FIRST_INODE(fs->super)) ++ quota_inode_truncate(fs, qf_ino); ++ ++ ext2fs_mark_super_dirty(fs); ++ fs->flags &= ~EXT2_FLAG_SUPER_ONLY; ++ retval = ext2fs_write_bitmaps(fs); ++ if (retval) { ++ log_err("Couldn't write bitmaps: %s", error_message(retval)); ++ return retval; ++ } ++ return 0; ++} ++ ++static void write_dquots(dict_t *dict, struct quota_handle *qh) ++{ ++ dnode_t *n; ++ struct dquot *dq; ++ ++ for (n = dict_first(dict); n; n = dict_next(dict, n)) { ++ dq = dnode_get(n); ++ if (dq) { ++ print_dquot("write", dq); ++ dq->dq_h = qh; ++ update_grace_times(dq); ++ qh->qh_ops->commit_dquot(dq); ++ } ++ } ++} ++ ++errcode_t quota_write_inode(quota_ctx_t qctx, int qtype) ++{ ++ int retval = 0, i; ++ dict_t *dict; ++ ext2_filsys fs; ++ struct quota_handle *h = NULL; ++ int fmt = QFMT_VFS_V1; ++ ++ if (!qctx) ++ return 0; ++ ++ fs = qctx->fs; ++ retval = ext2fs_get_mem(sizeof(struct quota_handle), &h); ++ if (retval) { ++ log_err("Unable to allocate quota handle: %s", ++ error_message(retval)); ++ goto out; ++ } ++ ++ retval = ext2fs_read_bitmaps(fs); ++ if (retval) { ++ log_err("Couldn't read bitmaps: %s", error_message(retval)); ++ goto out; ++ } ++ ++ for (i = 0; i < MAXQUOTAS; i++) { ++ if ((qtype != -1) && (i != qtype)) ++ continue; ++ ++ dict = qctx->quota_dict[i]; ++ if (!dict) ++ continue; ++ ++ retval = quota_file_create(h, fs, i, fmt); ++ if (retval < 0) { ++ log_err("Cannot initialize io on quotafile"); ++ continue; ++ } ++ ++ write_dquots(dict, h); ++ retval = quota_file_close(qctx, h); ++ if (retval < 0) { ++ log_err("Cannot finish IO on new quotafile: %s", ++ strerror(errno)); ++ if (h->qh_qf.e2_file) ++ ext2fs_file_close(h->qh_qf.e2_file); ++ quota_inode_truncate(fs, h->qh_qf.ino); ++ continue; ++ } ++ ++ /* Set quota inode numbers in superblock. */ ++ quota_set_sb_inum(fs, h->qh_qf.ino, i); ++ ext2fs_mark_super_dirty(fs); ++ ext2fs_mark_bb_dirty(fs); ++ fs->flags &= ~EXT2_FLAG_SUPER_ONLY; ++ } ++ ++ retval = ext2fs_write_bitmaps(fs); ++ if (retval) { ++ log_err("Couldn't write bitmaps: %s", error_message(retval)); ++ goto out; ++ } ++out: ++ if (h) ++ ext2fs_free_mem(&h); ++ return retval; ++} ++ ++/******************************************************************/ ++/* Helper functions for computing quota in memory. */ ++/******************************************************************/ ++ ++static int dict_uint_cmp(const void *a, const void *b) ++{ ++ unsigned int c, d; ++ ++ c = VOIDPTR_TO_UINT(a); ++ d = VOIDPTR_TO_UINT(b); ++ ++ if (c == d) ++ return 0; ++ else if (c > d) ++ return 1; ++ else ++ return -1; ++} ++ ++static inline qid_t get_qid(struct ext2_inode *inode, int qtype) ++{ ++ if (qtype == USRQUOTA) ++ return inode_uid(*inode); ++ return inode_gid(*inode); ++} ++ ++static void quota_dnode_free(dnode_t *node, ++ void *context EXT2FS_ATTR((unused))) ++{ ++ void *ptr = node ? dnode_get(node) : 0; ++ ++ ext2fs_free_mem(&ptr); ++ free(node); ++} ++ ++/* ++ * Set up the quota tracking data structures. ++ */ ++errcode_t quota_init_context(quota_ctx_t *qctx, ext2_filsys fs, int qtype) ++{ ++ errcode_t err; ++ dict_t *dict; ++ quota_ctx_t ctx; ++ int i; ++ ++ err = ext2fs_get_mem(sizeof(struct quota_ctx), &ctx); ++ if (err) { ++ log_err("Failed to allocate quota context"); ++ return err; ++ } ++ ++ memset(ctx, 0, sizeof(struct quota_ctx)); ++ for (i = 0; i < MAXQUOTAS; i++) { ++ ctx->quota_file[i] = NULL; ++ if ((qtype != -1) && (i != qtype)) ++ continue; ++ err = ext2fs_get_mem(sizeof(dict_t), &dict); ++ if (err) { ++ log_err("Failed to allocate dictionary"); ++ quota_release_context(&ctx); ++ return err; ++ } ++ ctx->quota_dict[i] = dict; ++ dict_init(dict, DICTCOUNT_T_MAX, dict_uint_cmp); ++ dict_set_allocator(dict, NULL, quota_dnode_free, NULL); ++ } ++ ++ ctx->fs = fs; ++ *qctx = ctx; ++ return 0; ++} ++ ++void quota_release_context(quota_ctx_t *qctx) ++{ ++ errcode_t err; ++ dict_t *dict; ++ int i; ++ quota_ctx_t ctx; ++ ++ if (!qctx) ++ return; ++ ++ ctx = *qctx; ++ for (i = 0; i < MAXQUOTAS; i++) { ++ dict = ctx->quota_dict[i]; ++ ctx->quota_dict[i] = 0; ++ if (dict) { ++ dict_free_nodes(dict); ++ free(dict); ++ } ++ if (ctx->quota_file[i]) { ++ err = quota_file_close(ctx, ctx->quota_file[i]); ++ if (err) { ++ log_err("Cannot close quotafile: %s", ++ strerror(errno)); ++ ext2fs_free_mem(&ctx->quota_file[i]); ++ } ++ } ++ } ++ *qctx = NULL; ++ free(ctx); ++} ++ ++static struct dquot *get_dq(dict_t *dict, __u32 key) ++{ ++ struct dquot *dq; ++ dnode_t *n; ++ ++ n = dict_lookup(dict, UINT_TO_VOIDPTR(key)); ++ if (n) ++ dq = dnode_get(n); ++ else { ++ if (ext2fs_get_mem(sizeof(struct dquot), &dq)) { ++ log_err("Unable to allocate dquot"); ++ return NULL; ++ } ++ memset(dq, 0, sizeof(struct dquot)); ++ dict_alloc_insert(dict, UINT_TO_VOIDPTR(key), dq); ++ dq->dq_id = key; ++ } ++ return dq; ++} ++ ++ ++/* ++ * Called to update the blocks used by a particular inode ++ */ ++void quota_data_add(quota_ctx_t qctx, struct ext2_inode *inode, ++ ext2_ino_t ino EXT2FS_ATTR((unused)), ++ qsize_t space) ++{ ++ struct dquot *dq; ++ dict_t *dict; ++ int i; ++ ++ if (!qctx) ++ return; ++ ++ log_debug("ADD_DATA: Inode: %u, UID/GID: %u/%u, space: %ld", ino, ++ inode_uid(*inode), ++ inode_gid(*inode), space); ++ for (i = 0; i < MAXQUOTAS; i++) { ++ dict = qctx->quota_dict[i]; ++ if (dict) { ++ dq = get_dq(dict, get_qid(inode, i)); ++ if (dq) ++ dq->dq_dqb.dqb_curspace += space; ++ } ++ } ++} ++ ++/* ++ * Called to remove some blocks used by a particular inode ++ */ ++void quota_data_sub(quota_ctx_t qctx, struct ext2_inode *inode, ++ ext2_ino_t ino EXT2FS_ATTR((unused)), ++ qsize_t space) ++{ ++ struct dquot *dq; ++ dict_t *dict; ++ int i; ++ ++ if (!qctx) ++ return; ++ ++ log_debug("SUB_DATA: Inode: %u, UID/GID: %u/%u, space: %ld", ino, ++ inode_uid(*inode), ++ inode_gid(*inode), space); ++ for (i = 0; i < MAXQUOTAS; i++) { ++ dict = qctx->quota_dict[i]; ++ if (dict) { ++ dq = get_dq(dict, get_qid(inode, i)); ++ dq->dq_dqb.dqb_curspace -= space; ++ } ++ } ++} ++ ++/* ++ * Called to count the files used by an inode's user/group ++ */ ++void quota_data_inodes(quota_ctx_t qctx, struct ext2_inode *inode, ++ ext2_ino_t ino EXT2FS_ATTR((unused)), int adjust) ++{ ++ struct dquot *dq; ++ dict_t *dict; ++ int i; ++ ++ if (!qctx) ++ return; ++ ++ log_debug("ADJ_INODE: Inode: %u, UID/GID: %u/%u, adjust: %d", ino, ++ inode_uid(*inode), ++ inode_gid(*inode), adjust); ++ for (i = 0; i < MAXQUOTAS; i++) { ++ dict = qctx->quota_dict[i]; ++ if (dict) { ++ dq = get_dq(dict, get_qid(inode, i)); ++ dq->dq_dqb.dqb_curinodes += adjust; ++ } ++ } ++} ++ ++errcode_t quota_compute_usage(quota_ctx_t qctx) ++{ ++ ext2_filsys fs; ++ ext2_ino_t ino; ++ errcode_t ret; ++ struct ext2_inode inode; ++ qsize_t space; ++ ext2_inode_scan scan; ++ ++ if (!qctx) ++ return 0; ++ ++ fs = qctx->fs; ++ ret = ext2fs_open_inode_scan(fs, 0, &scan); ++ if (ret) { ++ log_err("while opening inode scan. ret=%ld", ret); ++ return ret; ++ } ++ ++ while (1) { ++ ret = ext2fs_get_next_inode(scan, &ino, &inode); ++ if (ret) { ++ log_err("while getting next inode. ret=%ld", ret); ++ ext2fs_close_inode_scan(scan); ++ return ret; ++ } ++ if (ino == 0) ++ break; ++ if (inode.i_links_count && ++ (ino == EXT2_ROOT_INO || ++ ino >= EXT2_FIRST_INODE(fs->super))) { ++ space = ext2fs_inode_i_blocks(fs, &inode) << 9; ++ quota_data_add(qctx, &inode, ino, space); ++ quota_data_inodes(qctx, &inode, ino, +1); ++ } ++ } ++ ++ ext2fs_close_inode_scan(scan); ++ ++ return 0; ++} ++ ++struct scan_dquots_data { ++ dict_t *quota_dict; ++ int update_limits; /* update limits from disk */ ++ int update_usage; ++ int usage_is_inconsistent; ++}; ++ ++static int scan_dquots_callback(struct dquot *dquot, void *cb_data) ++{ ++ struct scan_dquots_data *scan_data = cb_data; ++ dict_t *quota_dict = scan_data->quota_dict; ++ struct dquot *dq; ++ ++ dq = get_dq(quota_dict, dquot->dq_id); ++ dq->dq_id = dquot->dq_id; ++ dq->dq_flags |= DQF_SEEN; ++ ++ print_dquot("mem", dq); ++ print_dquot("dsk", dquot); ++ ++ /* Check if there is inconsistancy. */ ++ if (dq->dq_dqb.dqb_curspace != dquot->dq_dqb.dqb_curspace || ++ dq->dq_dqb.dqb_curinodes != dquot->dq_dqb.dqb_curinodes) { ++ scan_data->usage_is_inconsistent = 1; ++ fprintf(stderr, "[QUOTA WARNING] Usage inconsistent for ID %d:" ++ "actual (%llu, %llu) != expected (%llu, %llu)\n", ++ dq->dq_id, (long long)dq->dq_dqb.dqb_curspace, ++ (long long)dq->dq_dqb.dqb_curinodes, ++ (long long)dquot->dq_dqb.dqb_curspace, ++ (long long)dquot->dq_dqb.dqb_curinodes); ++ } ++ ++ if (scan_data->update_limits) { ++ dq->dq_dqb.dqb_ihardlimit = dquot->dq_dqb.dqb_ihardlimit; ++ dq->dq_dqb.dqb_isoftlimit = dquot->dq_dqb.dqb_isoftlimit; ++ dq->dq_dqb.dqb_bhardlimit = dquot->dq_dqb.dqb_bhardlimit; ++ dq->dq_dqb.dqb_bsoftlimit = dquot->dq_dqb.dqb_bsoftlimit; ++ } ++ ++ if (scan_data->update_usage) { ++ dq->dq_dqb.dqb_curspace = dquot->dq_dqb.dqb_curspace; ++ dq->dq_dqb.dqb_curinodes = dquot->dq_dqb.dqb_curinodes; ++ } ++ ++ return 0; ++} ++ ++/* ++ * Read all dquots from quota file into memory ++ */ ++static errcode_t quota_read_all_dquots(struct quota_handle *qh, ++ quota_ctx_t qctx, int update_limits) ++{ ++ struct scan_dquots_data scan_data; ++ ++ scan_data.quota_dict = qctx->quota_dict[qh->qh_type]; ++ scan_data.update_limits = update_limits; ++ scan_data.update_usage = 0; ++ ++ return qh->qh_ops->scan_dquots(qh, scan_dquots_callback, &scan_data); ++} ++ ++/* ++ * Write all memory dquots into quota file ++ */ ++#if 0 /* currently unused, but may be useful in the future? */ ++static errcode_t quota_write_all_dquots(struct quota_handle *qh, ++ quota_ctx_t qctx) ++{ ++ errcode_t err; ++ ++ err = ext2fs_read_bitmaps(qctx->fs); ++ if (err) ++ return err; ++ write_dquots(qctx->quota_dict[qh->qh_type], qh); ++ ext2fs_mark_bb_dirty(qctx->fs); ++ qctx->fs->flags &= ~EXT2_FLAG_SUPER_ONLY; ++ ext2fs_write_bitmaps(qctx->fs); ++ return 0; ++} ++#endif ++ ++/* ++ * Updates the in-memory quota limits from the given quota inode. ++ */ ++errcode_t quota_update_limits(quota_ctx_t qctx, ext2_ino_t qf_ino, int type) ++{ ++ struct quota_handle *qh; ++ errcode_t err; ++ ++ if (!qctx) ++ return 0; ++ ++ err = ext2fs_get_mem(sizeof(struct quota_handle), &qh); ++ if (err) { ++ log_err("Unable to allocate quota handle"); ++ return err; ++ } ++ ++ err = quota_file_open(qctx, qh, qf_ino, type, -1, 0); ++ if (err) { ++ log_err("Open quota file failed"); ++ goto out; ++ } ++ ++ quota_read_all_dquots(qh, qctx, 1); ++ ++ err = quota_file_close(qctx, qh); ++ if (err) { ++ log_err("Cannot finish IO on new quotafile: %s", ++ strerror(errno)); ++ if (qh->qh_qf.e2_file) ++ ext2fs_file_close(qh->qh_qf.e2_file); ++ } ++out: ++ ext2fs_free_mem(&qh); ++ return err; ++} ++ ++/* ++ * Compares the measured quota in qctx->quota_dict with that in the quota inode ++ * on disk and updates the limits in qctx->quota_dict. 'usage_inconsistent' is ++ * set to 1 if the supplied and on-disk quota usage values are not identical. ++ */ ++errcode_t quota_compare_and_update(quota_ctx_t qctx, int qtype, ++ int *usage_inconsistent) ++{ ++ struct quota_handle qh; ++ struct scan_dquots_data scan_data; ++ struct dquot *dq; ++ dnode_t *n; ++ dict_t *dict = qctx->quota_dict[qtype]; ++ errcode_t err = 0; ++ ++ if (!dict) ++ goto out; ++ ++ err = quota_file_open(qctx, &qh, 0, qtype, -1, 0); ++ if (err) { ++ log_err("Open quota file failed"); ++ goto out; ++ } ++ ++ scan_data.quota_dict = qctx->quota_dict[qtype]; ++ scan_data.update_limits = 1; ++ scan_data.update_usage = 0; ++ scan_data.usage_is_inconsistent = 0; ++ err = qh.qh_ops->scan_dquots(&qh, scan_dquots_callback, &scan_data); ++ if (err) { ++ log_err("Error scanning dquots"); ++ goto out_close_qh; ++ } ++ ++ for (n = dict_first(dict); n; n = dict_next(dict, n)) { ++ dq = dnode_get(n); ++ if (!dq) ++ continue; ++ if ((dq->dq_flags & DQF_SEEN) == 0) { ++ fprintf(stderr, "[QUOTA WARNING] " ++ "Missing quota entry ID %d\n", dq->dq_id); ++ scan_data.usage_is_inconsistent = 1; ++ } ++ } ++ *usage_inconsistent = scan_data.usage_is_inconsistent; ++ ++out_close_qh: ++ err = quota_file_close(qctx, &qh); ++ if (err) { ++ log_err("Cannot close quotafile: %s", error_message(errno)); ++ if (qh.qh_qf.e2_file) ++ ext2fs_file_close(qh.qh_qf.e2_file); ++ } ++out: ++ return err; ++} +--- /dev/null ++++ b/lib/support/nls-enable.h +@@ -0,0 +1,21 @@ ++#if defined(ENABLE_NLS) && !defined(DEBUGFS) ++#include ++#include ++#define _(a) (gettext (a)) ++#ifdef gettext_noop ++#define N_(a) gettext_noop (a) ++#else ++#define N_(a) (a) ++#endif ++#define P_(singular, plural, n) (ngettext (singular, plural, n)) ++#ifndef NLS_CAT_NAME ++#define NLS_CAT_NAME "e2fsprogs" ++#endif ++#ifndef LOCALEDIR ++#define LOCALEDIR "/usr/share/locale" ++#endif ++#else ++#define _(a) (a) ++#define N_(a) a ++#define P_(singular, plural, n) ((n) == 1 ? (singular) : (plural)) ++#endif +--- /dev/null ++++ b/lib/support/plausible.c +@@ -0,0 +1,274 @@ ++/* ++ * plausible.c --- Figure out if a pathname is ext* or something else. ++ * ++ * Copyright 2014, Oracle, Inc. ++ * ++ * Some parts are: ++ * Copyright 1995, 1996, 1997, 1998, 1999, 2000 by Theodore Ts'o. ++ * ++ * %Begin-Header% ++ * This file may be redistributed under the terms of the GNU Public ++ * License. ++ * %End-Header% ++ */ ++ ++#ifndef _LARGEFILE_SOURCE ++#define _LARGEFILE_SOURCE ++#endif ++#ifndef _LARGEFILE64_SOURCE ++#define _LARGEFILE64_SOURCE ++#endif ++ ++#include "config.h" ++#include ++#include ++#include ++#ifdef HAVE_SYS_STAT_H ++#include ++#endif ++#ifdef HAVE_UNISTD_H ++#include ++#endif ++#ifdef HAVE_MAGIC_H ++#include ++#endif ++#include "plausible.h" ++#include "ext2fs/ext2fs.h" ++#include "nls-enable.h" ++#include "blkid/blkid.h" ++ ++#ifdef HAVE_MAGIC_H ++static magic_t (*dl_magic_open)(int); ++static const char *(*dl_magic_file)(magic_t, const char *); ++static int (*dl_magic_load)(magic_t, const char *); ++static void (*dl_magic_close)(magic_t); ++ ++#ifdef HAVE_DLOPEN ++#include ++ ++static void *magic_handle; ++ ++static int magic_library_available(void) ++{ ++ if (!magic_handle) { ++ magic_handle = dlopen("libmagic.so.1", RTLD_NOW); ++ if (!magic_handle) ++ return 0; ++ ++ dl_magic_open = dlsym(magic_handle, "magic_open"); ++ dl_magic_file = dlsym(magic_handle, "magic_file"); ++ dl_magic_load = dlsym(magic_handle, "magic_load"); ++ dl_magic_close = dlsym(magic_handle, "magic_close"); ++ } ++ ++ if (!dl_magic_open || !dl_magic_file || ++ !dl_magic_load || !dl_magic_close) ++ return 0; ++ return 1; ++} ++#else ++static int magic_library_available(void) ++{ ++ dl_magic_open = magic_open; ++ dl_magic_file = magic_file; ++ dl_magic_load = magic_load; ++ dl_magic_close = magic_close; ++ ++ return 1; ++} ++#endif ++#endif ++ ++static void print_ext2_info(const char *device) ++ ++{ ++ struct ext2_super_block *sb; ++ ext2_filsys fs; ++ errcode_t retval; ++ time_t tm; ++ char buf[80]; ++ ++ retval = ext2fs_open2(device, 0, EXT2_FLAG_64BITS, 0, 0, ++ unix_io_manager, &fs); ++ if (retval) ++ return; ++ sb = fs->super; ++ ++ if (sb->s_mtime) { ++ tm = sb->s_mtime; ++ if (sb->s_last_mounted[0]) { ++ memset(buf, 0, sizeof(buf)); ++ strncpy(buf, sb->s_last_mounted, ++ sizeof(sb->s_last_mounted)); ++ printf(_("\tlast mounted on %s on %s"), buf, ++ ctime(&tm)); ++ } else ++ printf(_("\tlast mounted on %s"), ctime(&tm)); ++ } else if (sb->s_mkfs_time) { ++ tm = sb->s_mkfs_time; ++ printf(_("\tcreated on %s"), ctime(&tm)); ++ } else if (sb->s_wtime) { ++ tm = sb->s_wtime; ++ printf(_("\tlast modified on %s"), ctime(&tm)); ++ } ++ ext2fs_close_free(&fs); ++} ++ ++/* ++ * return 1 if there is no partition table, 0 if a partition table is ++ * detected, and -1 on an error. ++ */ ++#ifdef HAVE_BLKID_PROBE_ENABLE_PARTITIONS ++static int check_partition_table(const char *device) ++{ ++ blkid_probe pr; ++ const char *value; ++ int ret; ++ ++ pr = blkid_new_probe_from_filename(device); ++ if (!pr) ++ return -1; ++ ++ ret = blkid_probe_enable_partitions(pr, 1); ++ if (ret < 0) ++ goto errout; ++ ++ ret = blkid_probe_enable_superblocks(pr, 0); ++ if (ret < 0) ++ goto errout; ++ ++ ret = blkid_do_fullprobe(pr); ++ if (ret < 0) ++ goto errout; ++ ++ ret = blkid_probe_lookup_value(pr, "PTTYPE", &value, NULL); ++ if (ret == 0) ++ fprintf(stderr, _("Found a %s partition table in %s\n"), ++ value, device); ++ else ++ ret = 1; ++ ++errout: ++ blkid_free_probe(pr); ++ return ret; ++} ++#else ++static int check_partition_table(const char *device EXT2FS_ATTR((unused))) ++{ ++ return -1; ++} ++#endif ++ ++/* ++ * return 1 if the device looks plausible, creating the file if necessary ++ */ ++int check_plausibility(const char *device, int flags, int *ret_is_dev) ++{ ++ int fd, ret, is_dev = 0; ++ ext2fs_struct_stat s; ++ int fl = O_RDONLY; ++ blkid_cache cache = NULL; ++ char *fs_type = NULL; ++ char *fs_label = NULL; ++ ++ fd = ext2fs_open_file(device, fl, 0666); ++ if ((fd < 0) && (errno == ENOENT) && (flags & NO_SIZE)) { ++ fprintf(stderr, _("The file %s does not exist and no " ++ "size was specified.\n"), device); ++ exit(1); ++ } ++ if ((fd < 0) && (errno == ENOENT) && (flags & CREATE_FILE)) { ++ fl |= O_CREAT; ++ fd = ext2fs_open_file(device, fl, 0666); ++ if (fd >= 0 && (flags & VERBOSE_CREATE)) ++ printf(_("Creating regular file %s\n"), device); ++ } ++ if (fd < 0) { ++ fprintf(stderr, _("Could not open %s: %s\n"), ++ device, error_message(errno)); ++ if (errno == ENOENT) ++ fputs(_("\nThe device apparently does not exist; " ++ "did you specify it correctly?\n"), stderr); ++ exit(1); ++ } ++ ++ if (ext2fs_fstat(fd, &s) < 0) { ++ perror("stat"); ++ exit(1); ++ } ++ close(fd); ++ ++ if (S_ISBLK(s.st_mode)) ++ is_dev = 1; ++#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) ++ /* On FreeBSD, all disk devices are character specials */ ++ if (S_ISCHR(s.st_mode)) ++ is_dev = 1; ++#endif ++ if (ret_is_dev) ++ *ret_is_dev = is_dev; ++ ++ if ((flags & CHECK_BLOCK_DEV) && !is_dev) { ++ printf(_("%s is not a block special device.\n"), device); ++ return 0; ++ } ++ ++ /* ++ * Note: we use the older-style blkid API's here because we ++ * want as much functionality to be available when using the ++ * internal blkid library, when e2fsprogs is compiled for ++ * non-Linux systems that will probably not have the libraries ++ * from util-linux available. We only use the newer ++ * blkid-probe interfaces to access functionality not ++ * available in the original blkid library. ++ */ ++ if ((flags & CHECK_FS_EXIST) && blkid_get_cache(&cache, NULL) >= 0) { ++ fs_type = blkid_get_tag_value(cache, "TYPE", device); ++ if (fs_type) ++ fs_label = blkid_get_tag_value(cache, "LABEL", device); ++ blkid_put_cache(cache); ++ } ++ ++ if (fs_type) { ++ if (fs_label) ++ printf(_("%s contains a %s file system " ++ "labelled '%s'\n"), device, fs_type, fs_label); ++ else ++ printf(_("%s contains a %s file system\n"), device, ++ fs_type); ++ if (strncmp(fs_type, "ext", 3) == 0) ++ print_ext2_info(device); ++ free(fs_type); ++ free(fs_label); ++ return 0; ++ } ++ ++#ifdef HAVE_MAGIC_H ++ if ((flags & CHECK_FS_EXIST) && magic_library_available()) { ++ const char *msg; ++ magic_t mag; ++ int has_magic = 0; ++ ++ mag = dl_magic_open(MAGIC_RAW | MAGIC_SYMLINK | MAGIC_DEVICES | ++ MAGIC_ERROR | MAGIC_NO_CHECK_ELF | ++ MAGIC_NO_CHECK_COMPRESS); ++ dl_magic_load(mag, NULL); ++ ++ msg = dl_magic_file(mag, device); ++ if (msg && strcmp(msg, "data") && strcmp(msg, "empty")) { ++ printf(_("%s contains `%s' data\n"), device, msg); ++ has_magic = 1; ++ } ++ ++ dl_magic_close(mag); ++ return !has_magic; ++ } ++#endif ++ ++ ret = check_partition_table(device); ++ if (ret >= 0) ++ return ret; ++ ++ return 1; ++} ++ +--- /dev/null ++++ b/lib/support/plausible.h +@@ -0,0 +1,28 @@ ++/* ++ * plausible.h --- header file defining prototypes for helper functions ++ * used by tune2fs and mke2fs ++ * ++ * Copyright 2014 by Oracle, Inc. ++ * ++ * %Begin-Header% ++ * This file may be redistributed under the terms of the GNU Public ++ * License. ++ * %End-Header% ++ */ ++ ++#ifndef PLAUSIBLE_H_ ++#define PLAUSIBLE_H_ ++ ++/* ++ * Flags for check_plausibility() ++ */ ++#define CHECK_BLOCK_DEV 0x0001 ++#define CREATE_FILE 0x0002 ++#define CHECK_FS_EXIST 0x0004 ++#define VERBOSE_CREATE 0x0008 ++#define NO_SIZE 0x0010 ++ ++extern int check_plausibility(const char *device, int flags, ++ int *ret_is_dev); ++ ++#endif /* PLAUSIBLE_H_ */ +--- /dev/null ++++ b/lib/support/prof_err.et +@@ -0,0 +1,66 @@ ++error_table prof ++ ++error_code PROF_VERSION, "Profile version 0.0" ++ ++# ++# generated by prof_tree.c ++# ++error_code PROF_MAGIC_NODE, "Bad magic value in profile_node" ++error_code PROF_NO_SECTION, "Profile section not found" ++error_code PROF_NO_RELATION, "Profile relation not found" ++error_code PROF_ADD_NOT_SECTION, ++ "Attempt to add a relation to node which is not a section" ++error_code PROF_SECTION_WITH_VALUE, ++ "A profile section header has a non-zero value" ++error_code PROF_BAD_LINK_LIST, "Bad linked list in profile structures" ++error_code PROF_BAD_GROUP_LVL, "Bad group level in profile structures" ++error_code PROF_BAD_PARENT_PTR, ++ "Bad parent pointer in profile structures" ++error_code PROF_MAGIC_ITERATOR, "Bad magic value in profile iterator" ++error_code PROF_SET_SECTION_VALUE, "Can't set value on section node" ++error_code PROF_EINVAL, "Invalid argument passed to profile library" ++error_code PROF_READ_ONLY, "Attempt to modify read-only profile" ++ ++# ++# generated by prof_parse.c ++# ++ ++error_code PROF_SECTION_NOTOP, "Profile section header not at top level" ++error_code PROF_SECTION_SYNTAX, "Syntax error in profile section header" ++error_code PROF_RELATION_SYNTAX, "Syntax error in profile relation" ++error_code PROF_EXTRA_CBRACE, "Extra closing brace in profile" ++error_code PROF_MISSING_OBRACE, "Missing open brace in profile" ++ ++# ++# generated by prof_init.c ++# ++error_code PROF_MAGIC_PROFILE, "Bad magic value in profile_t" ++error_code PROF_MAGIC_SECTION, "Bad magic value in profile_section_t" ++error_code PROF_TOPSECTION_ITER_NOSUPP, ++ "Iteration through all top level section not supported" ++error_code PROF_INVALID_SECTION, "Invalid profile_section object" ++error_code PROF_END_OF_SECTIONS, "No more sections" ++error_code PROF_BAD_NAMESET, "Bad nameset passed to query routine" ++error_code PROF_NO_PROFILE, "No profile file open" ++ ++# ++# generated by prof_file.c ++# ++error_code PROF_MAGIC_FILE, "Bad magic value in profile_file_t" ++error_code PROF_FAIL_OPEN, "Couldn't open profile file" ++ ++# ++# generated by prof_set.c ++# ++error_code PROF_EXISTS, "Section already exists" ++ ++# ++# generated by prof_get.c ++# ++error_code PROF_BAD_BOOLEAN, "Invalid boolean value" ++error_code PROF_BAD_INTEGER, "Invalid integer value" ++ ++error_code PROF_MAGIC_FILE_DATA, "Bad magic value in profile_file_data_t" ++ ++ ++end +--- /dev/null ++++ b/lib/support/profile.c +@@ -0,0 +1,1905 @@ ++/* ++ * profile.c -- A simple configuration file parsing "library in a file" ++ * ++ * The profile library was originally written by Theodore Ts'o in 1995 ++ * for use in the MIT Kerberos v5 library. It has been ++ * modified/enhanced/bug-fixed over time by other members of the MIT ++ * Kerberos team. This version was originally taken from the Kerberos ++ * v5 distribution, version 1.4.2, and radically simplified for use in ++ * e2fsprogs. (Support for locking for multi-threaded operations, ++ * being able to modify and update the configuration file ++ * programmatically, and Mac/Windows portability have been removed. ++ * It has been folded into a single C source file to make it easier to ++ * fold into an application program.) ++ * ++ * Copyright (C) 2005, 2006 by Theodore Ts'o. ++ * ++ * %Begin-Header% ++ * This file may be redistributed under the terms of the GNU Public ++ * License. ++ * %End-Header% ++ * ++ * Copyright (C) 1985-2005 by the Massachusetts Institute of Technology. ++ * ++ * All rights reserved. ++ * ++ * Export of this software from the United States of America may require ++ * a specific license from the United States Government. It is the ++ * responsibility of any person or organization contemplating export to ++ * obtain such a license before exporting. ++ * ++ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and ++ * distribute this software and its documentation for any purpose and ++ * without fee is hereby granted, provided that the above copyright ++ * notice appear in all copies and that both that copyright notice and ++ * this permission notice appear in supporting documentation, and that ++ * the name of M.I.T. not be used in advertising or publicity pertaining ++ * to distribution of the software without specific, written prior ++ * permission. Furthermore if you modify this software you must label ++ * your software as modified software and not distribute it in such a ++ * fashion that it might be confused with the original MIT software. ++ * M.I.T. makes no representations about the suitability of this software ++ * for any purpose. It is provided "as is" without express or implied ++ * warranty. ++ * ++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR ++ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED ++ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. ++ * ++ */ ++ ++#include "config.h" ++#ifdef HAVE_UNISTD_H ++#include ++#endif ++#include ++#ifdef HAVE_STDLIB_H ++#include ++#endif ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#ifdef HAVE_PWD_H ++#include ++#endif ++ ++#include ++#include "profile.h" ++#include "prof_err.h" ++ ++#undef STAT_ONCE_PER_SECOND ++#undef HAVE_STAT ++ ++/* ++ * prof_int.h ++ */ ++ ++typedef long prf_magic_t; ++ ++/* ++ * This is the structure which stores the profile information for a ++ * particular configuration file. ++ */ ++struct _prf_file_t { ++ prf_magic_t magic; ++ char *filespec; ++#ifdef STAT_ONCE_PER_SECOND ++ time_t last_stat; ++#endif ++ time_t timestamp; /* time tree was last updated from file */ ++ int flags; /* r/w, dirty */ ++ int upd_serial; /* incremented when data changes */ ++ struct profile_node *root; ++ struct _prf_file_t *next; ++}; ++ ++typedef struct _prf_file_t *prf_file_t; ++ ++/* ++ * The profile flags ++ */ ++#define PROFILE_FILE_RW 0x0001 ++#define PROFILE_FILE_DIRTY 0x0002 ++#define PROFILE_FILE_NO_RELOAD 0x0004 ++ ++/* ++ * This structure defines the high-level, user visible profile_t ++ * object, which is used as a handle by users who need to query some ++ * configuration file(s) ++ */ ++struct _profile_t { ++ prf_magic_t magic; ++ prf_file_t first_file; ++}; ++ ++/* ++ * Used by the profile iterator in prof_get.c ++ */ ++#define PROFILE_ITER_LIST_SECTION 0x0001 ++#define PROFILE_ITER_SECTIONS_ONLY 0x0002 ++#define PROFILE_ITER_RELATIONS_ONLY 0x0004 ++ ++#define PROFILE_ITER_FINAL_SEEN 0x0100 ++ ++/* ++ * Check if a filespec is last in a list (NULL on UNIX, invalid FSSpec on MacOS ++ */ ++ ++#define PROFILE_LAST_FILESPEC(x) (((x) == NULL) || ((x)[0] == '\0')) ++ ++struct profile_node { ++ errcode_t magic; ++ char *name; ++ char *value; ++ int group_level; ++ unsigned int final:1; /* Indicate don't search next file */ ++ unsigned int deleted:1; ++ struct profile_node *first_child; ++ struct profile_node *parent; ++ struct profile_node *next, *prev; ++}; ++ ++#define CHECK_MAGIC(node) \ ++ if ((node)->magic != PROF_MAGIC_NODE) \ ++ return PROF_MAGIC_NODE; ++ ++/* profile parser declarations */ ++struct parse_state { ++ int state; ++ int group_level; ++ int line_num; ++ struct profile_node *root_section; ++ struct profile_node *current_section; ++}; ++ ++static const char *default_filename = ""; ++ ++static profile_syntax_err_cb_t syntax_err_cb; ++ ++static errcode_t parse_line(char *line, struct parse_state *state); ++ ++#ifdef DEBUG_PROGRAM ++static errcode_t profile_write_tree_file ++ (struct profile_node *root, FILE *dstfile); ++ ++static errcode_t profile_write_tree_to_buffer ++ (struct profile_node *root, char **buf); ++#endif ++ ++ ++static void profile_free_node ++ (struct profile_node *relation); ++ ++static errcode_t profile_create_node ++ (const char *name, const char *value, ++ struct profile_node **ret_node); ++ ++#ifdef DEBUG_PROGRAM ++static errcode_t profile_verify_node ++ (struct profile_node *node); ++#endif ++ ++static errcode_t profile_add_node ++ (struct profile_node *section, ++ const char *name, const char *value, ++ struct profile_node **ret_node); ++ ++static errcode_t profile_find_node ++ (struct profile_node *section, ++ const char *name, const char *value, ++ int section_flag, void **state, ++ struct profile_node **node); ++ ++static errcode_t profile_node_iterator ++ (void **iter_p, struct profile_node **ret_node, ++ char **ret_name, char **ret_value); ++ ++static errcode_t profile_open_file ++ (const char * file, prf_file_t *ret_prof); ++ ++static errcode_t profile_update_file ++ (prf_file_t prf); ++ ++static void profile_free_file ++ (prf_file_t profile); ++ ++static errcode_t profile_get_value(profile_t profile, const char *name, ++ const char *subname, const char *subsubname, ++ const char **ret_value); ++ ++ ++/* ++ * prof_init.c --- routines that manipulate the user-visible profile_t ++ * object. ++ */ ++ ++static int compstr(const void *m1, const void *m2) ++{ ++ const char *s1 = *((const char * const *) m1); ++ const char *s2 = *((const char * const *) m2); ++ ++ return strcmp(s1, s2); ++} ++ ++static void free_list(char **list) ++{ ++ char **cp; ++ ++ if (list == 0) ++ return; ++ ++ for (cp = list; *cp; cp++) ++ free(*cp); ++ free(list); ++} ++ ++static errcode_t get_dirlist(const char *dirname, char***ret_array) ++{ ++ DIR *dir; ++ struct dirent *de; ++ struct stat st; ++ errcode_t retval; ++ char *fn, *cp; ++ char **array = 0, **new_array; ++ int max = 0, num = 0; ++ ++ dir = opendir(dirname); ++ if (!dir) ++ return errno; ++ ++ while ((de = readdir(dir)) != NULL) { ++ for (cp = de->d_name; *cp; cp++) { ++ if (!isalnum(*cp) && ++ (*cp != '-') && ++ (*cp != '_')) ++ break; ++ } ++ if (*cp) ++ continue; ++ fn = malloc(strlen(dirname) + strlen(de->d_name) + 2); ++ if (!fn) { ++ retval = ENOMEM; ++ goto errout; ++ } ++ sprintf(fn, "%s/%s", dirname, de->d_name); ++ if ((stat(fn, &st) < 0) || !S_ISREG(st.st_mode)) { ++ free(fn); ++ continue; ++ } ++ if (num >= max) { ++ max += 10; ++ new_array = realloc(array, sizeof(char *) * (max+1)); ++ if (!new_array) { ++ retval = ENOMEM; ++ free(fn); ++ goto errout; ++ } ++ array = new_array; ++ } ++ array[num++] = fn; ++ } ++ if (array) { ++ qsort(array, num, sizeof(char *), compstr); ++ array[num++] = 0; ++ } ++ *ret_array = array; ++ closedir(dir); ++ return 0; ++errout: ++ if (array) ++ array[num] = 0; ++ closedir(dir); ++ free_list(array); ++ return retval; ++} ++ ++errcode_t ++profile_init(const char **files, profile_t *ret_profile) ++{ ++ const char **fs; ++ profile_t profile; ++ prf_file_t new_file, *last; ++ errcode_t retval = 0; ++ char **cpp, *cp, **array = 0; ++ ++ profile = malloc(sizeof(struct _profile_t)); ++ if (!profile) ++ return ENOMEM; ++ memset(profile, 0, sizeof(struct _profile_t)); ++ profile->magic = PROF_MAGIC_PROFILE; ++ last = &profile->first_file; ++ ++ /* if the filenames list is not specified return an empty profile */ ++ if ( files ) { ++ for (fs = files; !PROFILE_LAST_FILESPEC(*fs); fs++) { ++ if (array) ++ free_list(array); ++ array = NULL; ++ retval = get_dirlist(*fs, &array); ++ if (retval == 0) { ++ if (!array) ++ continue; ++ for (cpp = array; (cp = *cpp); cpp++) { ++ retval = profile_open_file(cp, &new_file); ++ if (retval == EACCES) ++ continue; ++ if (retval) ++ goto errout; ++ *last = new_file; ++ last = &new_file->next; ++ } ++ } else if ((retval != ENOTDIR) && ++ strcmp(*fs, default_filename)) ++ goto errout; ++ ++ retval = profile_open_file(*fs, &new_file); ++ /* if this file is missing, skip to the next */ ++ if (retval == ENOENT || retval == EACCES) { ++ continue; ++ } ++ if (retval) ++ goto errout; ++ *last = new_file; ++ last = &new_file->next; ++ } ++ /* ++ * If all the files were not found, return the appropriate error. ++ */ ++ if (!profile->first_file) { ++ retval = ENOENT; ++ goto errout; ++ } ++ } ++ ++ free_list(array); ++ *ret_profile = profile; ++ return 0; ++errout: ++ free_list(array); ++ profile_release(profile); ++ return retval; ++} ++ ++void ++profile_release(profile_t profile) ++{ ++ prf_file_t p, next; ++ ++ if (!profile || profile->magic != PROF_MAGIC_PROFILE) ++ return; ++ ++ for (p = profile->first_file; p; p = next) { ++ next = p->next; ++ profile_free_file(p); ++ } ++ profile->magic = 0; ++ free(profile); ++} ++ ++/* ++ * This function sets the value of the pseudo file "". If ++ * the file "" had previously been passed to profile_init(), ++ * then def_string parameter will be parsed and used as the profile ++ * information for the "" file. ++ */ ++errcode_t profile_set_default(profile_t profile, const char *def_string) ++{ ++ struct parse_state state; ++ prf_file_t prf; ++ errcode_t retval; ++ const char *in; ++ char *line, *p, *end; ++ int line_size, len; ++ ++ if (!def_string || !profile || profile->magic != PROF_MAGIC_PROFILE) ++ return PROF_MAGIC_PROFILE; ++ ++ for (prf = profile->first_file; prf; prf = prf->next) { ++ if (strcmp(prf->filespec, default_filename) == 0) ++ break; ++ } ++ if (!prf) ++ return 0; ++ ++ if (prf->root) { ++ profile_free_node(prf->root); ++ prf->root = 0; ++ } ++ ++ memset(&state, 0, sizeof(struct parse_state)); ++ retval = profile_create_node("(root)", 0, &state.root_section); ++ if (retval) ++ return retval; ++ ++ line = 0; ++ line_size = 0; ++ in = def_string; ++ while (*in) { ++ end = strchr(in, '\n'); ++ len = end ? (end - in) : (int) strlen(in); ++ if (len >= line_size) { ++ line_size = len+1; ++ p = realloc(line, line_size); ++ if (!p) { ++ retval = ENOMEM; ++ goto errout; ++ } ++ line = p; ++ } ++ memcpy(line, in, len); ++ line[len] = 0; ++ retval = parse_line(line, &state); ++ if (retval) { ++ errout: ++ if (syntax_err_cb) ++ (syntax_err_cb)(prf->filespec, retval, ++ state.line_num); ++ free(line); ++ if (prf->root) ++ profile_free_node(prf->root); ++ return retval; ++ } ++ if (!end) ++ break; ++ in = end+1; ++ } ++ prf->root = state.root_section; ++ free(line); ++ ++ return 0; ++} ++ ++/* ++ * prof_file.c ---- routines that manipulate an individual profile file. ++ */ ++ ++errcode_t profile_open_file(const char * filespec, ++ prf_file_t *ret_prof) ++{ ++ prf_file_t prf; ++ errcode_t retval; ++ char *home_env = 0; ++ unsigned int len; ++ char *expanded_filename; ++ ++ prf = malloc(sizeof(struct _prf_file_t)); ++ if (!prf) ++ return ENOMEM; ++ memset(prf, 0, sizeof(struct _prf_file_t)); ++ prf->magic = PROF_MAGIC_FILE; ++ ++ len = strlen(filespec)+1; ++ if (filespec[0] == '~' && filespec[1] == '/') { ++ home_env = getenv("HOME"); ++#ifdef HAVE_PWD_H ++ if (home_env == NULL) { ++#ifdef HAVE_GETWUID_R ++ struct passwd *pw, pwx; ++ uid_t uid; ++ char pwbuf[BUFSIZ]; ++ ++ uid = getuid(); ++ if (!getpwuid_r(uid, &pwx, pwbuf, sizeof(pwbuf), &pw) ++ && pw != NULL && pw->pw_dir[0] != 0) ++ home_env = pw->pw_dir; ++#else ++ struct passwd *pw; ++ ++ pw = getpwuid(getuid()); ++ home_env = pw->pw_dir; ++#endif ++ } ++#endif ++ if (home_env) ++ len += strlen(home_env); ++ } ++ expanded_filename = malloc(len); ++ if (expanded_filename == 0) { ++ profile_free_file(prf); ++ return errno; ++ } ++ if (home_env) { ++ strcpy(expanded_filename, home_env); ++ strcat(expanded_filename, filespec+1); ++ } else ++ memcpy(expanded_filename, filespec, len); ++ ++ prf->filespec = expanded_filename; ++ ++ if (strcmp(prf->filespec, default_filename) != 0) { ++ retval = profile_update_file(prf); ++ if (retval) { ++ profile_free_file(prf); ++ return retval; ++ } ++ } ++ ++ *ret_prof = prf; ++ return 0; ++} ++ ++errcode_t profile_update_file(prf_file_t prf) ++{ ++ errcode_t retval; ++#ifdef HAVE_STAT ++ struct stat st; ++#ifdef STAT_ONCE_PER_SECOND ++ time_t now; ++#endif ++#endif ++ FILE *f; ++ char buf[2048]; ++ struct parse_state state; ++ ++ if (prf->flags & PROFILE_FILE_NO_RELOAD) ++ return 0; ++ ++#ifdef HAVE_STAT ++#ifdef STAT_ONCE_PER_SECOND ++ now = time(0); ++ if (now == prf->last_stat && prf->root != NULL) { ++ return 0; ++ } ++#endif ++ if (stat(prf->filespec, &st)) { ++ retval = errno; ++ return retval; ++ } ++#ifdef STAT_ONCE_PER_SECOND ++ prf->last_stat = now; ++#endif ++ if (st.st_mtime == prf->timestamp && prf->root != NULL) { ++ return 0; ++ } ++ if (prf->root) { ++ profile_free_node(prf->root); ++ prf->root = 0; ++ } ++#else ++ /* ++ * If we don't have the stat() call, assume that our in-core ++ * memory image is correct. That is, we won't reread the ++ * profile file if it changes. ++ */ ++ if (prf->root) { ++ return 0; ++ } ++#endif ++ memset(&state, 0, sizeof(struct parse_state)); ++ retval = profile_create_node("(root)", 0, &state.root_section); ++ if (retval) ++ return retval; ++ errno = 0; ++ f = fopen(prf->filespec, "r"); ++ if (f == NULL) { ++ retval = errno; ++ if (retval == 0) ++ retval = ENOENT; ++ return retval; ++ } ++ prf->upd_serial++; ++ while (!feof(f)) { ++ if (fgets(buf, sizeof(buf), f) == NULL) ++ break; ++ retval = parse_line(buf, &state); ++ if (retval) { ++ if (syntax_err_cb) ++ (syntax_err_cb)(prf->filespec, retval, ++ state.line_num); ++ fclose(f); ++ return retval; ++ } ++ } ++ prf->root = state.root_section; ++ ++ fclose(f); ++ ++#ifdef HAVE_STAT ++ prf->timestamp = st.st_mtime; ++#endif ++ return 0; ++} ++ ++void profile_free_file(prf_file_t prf) ++{ ++ if (prf->root) ++ profile_free_node(prf->root); ++ free(prf->filespec); ++ free(prf); ++} ++ ++/* Begin the profile parser */ ++ ++profile_syntax_err_cb_t profile_set_syntax_err_cb(profile_syntax_err_cb_t hook) ++{ ++ profile_syntax_err_cb_t old; ++ ++ old = syntax_err_cb; ++ syntax_err_cb = hook; ++ return(old); ++} ++ ++#define STATE_INIT_COMMENT 0 ++#define STATE_STD_LINE 1 ++#define STATE_GET_OBRACE 2 ++ ++static char *skip_over_blanks(char *cp) ++{ ++ while (*cp && isspace((int) (*cp))) ++ cp++; ++ return cp; ++} ++ ++static int end_or_comment(char ch) ++{ ++ return (ch == 0 || ch == '#' || ch == ';'); ++} ++ ++static char *skip_over_nonblanks(char *cp) ++{ ++ while (!end_or_comment(*cp) && !isspace(*cp)) ++ cp++; ++ return cp; ++} ++ ++static void strip_line(char *line) ++{ ++ char *p = line + strlen(line); ++ while (p > line && (p[-1] == '\n' || p[-1] == '\r')) ++ *p-- = 0; ++} ++ ++static void parse_quoted_string(char *str) ++{ ++ char *to, *from; ++ ++ to = from = str; ++ ++ for (to = from = str; *from && *from != '"'; to++, from++) { ++ if (*from == '\\') { ++ from++; ++ switch (*from) { ++ case 'n': ++ *to = '\n'; ++ break; ++ case 't': ++ *to = '\t'; ++ break; ++ case 'b': ++ *to = '\b'; ++ break; ++ default: ++ *to = *from; ++ } ++ continue; ++ } ++ *to = *from; ++ } ++ *to = '\0'; ++} ++ ++static errcode_t parse_line(char *line, struct parse_state *state) ++{ ++ char *cp, ch, *tag, *value; ++ char *p; ++ errcode_t retval; ++ struct profile_node *node; ++ int do_subsection = 0; ++ void *iter = 0; ++ ++ state->line_num++; ++ if (state->state == STATE_GET_OBRACE) { ++ cp = skip_over_blanks(line); ++ if (*cp != '{') ++ return PROF_MISSING_OBRACE; ++ state->state = STATE_STD_LINE; ++ return 0; ++ } ++ if (state->state == STATE_INIT_COMMENT) { ++ if (line[0] != '[') ++ return 0; ++ state->state = STATE_STD_LINE; ++ } ++ ++ if (*line == 0) ++ return 0; ++ strip_line(line); ++ cp = skip_over_blanks(line); ++ ch = *cp; ++ if (end_or_comment(ch)) ++ return 0; ++ if (ch == '[') { ++ if (state->group_level > 0) ++ return PROF_SECTION_NOTOP; ++ cp++; ++ cp = skip_over_blanks(cp); ++ p = strchr(cp, ']'); ++ if (p == NULL) ++ return PROF_SECTION_SYNTAX; ++ if (*cp == '"') { ++ cp++; ++ parse_quoted_string(cp); ++ } else { ++ *p-- = '\0'; ++ while (isspace(*p) && (p > cp)) ++ *p-- = '\0'; ++ if (*cp == 0) ++ return PROF_SECTION_SYNTAX; ++ } ++ retval = profile_find_node(state->root_section, cp, 0, 1, ++ &iter, &state->current_section); ++ if (retval == PROF_NO_SECTION) { ++ retval = profile_add_node(state->root_section, ++ cp, 0, ++ &state->current_section); ++ if (retval) ++ return retval; ++ } else if (retval) ++ return retval; ++ ++ /* ++ * Finish off the rest of the line. ++ */ ++ cp = p+1; ++ if (*cp == '*') { ++ state->current_section->final = 1; ++ cp++; ++ } ++ /* ++ * Spaces or comments after ']' should not be fatal ++ */ ++ cp = skip_over_blanks(cp); ++ if (!end_or_comment(*cp)) ++ return PROF_SECTION_SYNTAX; ++ return 0; ++ } ++ if (ch == '}') { ++ if (state->group_level == 0) ++ return PROF_EXTRA_CBRACE; ++ if (*(cp+1) == '*') ++ state->current_section->final = 1; ++ state->current_section = state->current_section->parent; ++ state->group_level--; ++ return 0; ++ } ++ /* ++ * Parse the relations ++ */ ++ tag = cp; ++ cp = strchr(cp, '='); ++ if (!cp) ++ return PROF_RELATION_SYNTAX; ++ if (cp == tag) ++ return PROF_RELATION_SYNTAX; ++ *cp = '\0'; ++ if (*tag == '"') { ++ tag++; ++ parse_quoted_string(tag); ++ } else { ++ /* Look for whitespace on left-hand side. */ ++ p = skip_over_nonblanks(tag); ++ if (*p) ++ *p++ = 0; ++ p = skip_over_blanks(p); ++ /* If we have more non-whitespace, it's an error. */ ++ if (*p) ++ return PROF_RELATION_SYNTAX; ++ } ++ ++ cp = skip_over_blanks(cp+1); ++ value = cp; ++ ch = value[0]; ++ if (ch == '"') { ++ value++; ++ parse_quoted_string(value); ++ } else if (end_or_comment(ch)) { ++ do_subsection++; ++ state->state = STATE_GET_OBRACE; ++ } else if (value[0] == '{') { ++ cp = skip_over_blanks(value+1); ++ ch = *cp; ++ if (end_or_comment(ch)) ++ do_subsection++; ++ else ++ return PROF_RELATION_SYNTAX; ++ } else { ++ cp = skip_over_nonblanks(value); ++ p = skip_over_blanks(cp); ++ ch = *p; ++ *cp = 0; ++ if (!end_or_comment(ch)) ++ return PROF_RELATION_SYNTAX; ++ } ++ if (do_subsection) { ++ p = strchr(tag, '*'); ++ if (p) ++ *p = '\0'; ++ retval = profile_add_node(state->current_section, ++ tag, 0, &state->current_section); ++ if (retval) ++ return retval; ++ if (p) ++ state->current_section->final = 1; ++ state->group_level++; ++ return 0; ++ } ++ p = strchr(tag, '*'); ++ if (p) ++ *p = '\0'; ++ profile_add_node(state->current_section, tag, value, &node); ++ if (p) ++ node->final = 1; ++ return 0; ++} ++ ++#ifdef DEBUG_PROGRAM ++/* ++ * Return TRUE if the string begins or ends with whitespace ++ */ ++static int need_double_quotes(char *str) ++{ ++ if (!str || !*str) ++ return 0; ++ if (isspace((int) (*str)) ||isspace((int) (*(str + strlen(str) - 1)))) ++ return 1; ++ if (strchr(str, '\n') || strchr(str, '\t') || strchr(str, '\b') || ++ strchr(str, ' ') || strchr(str, '#') || strchr(str, ';')) ++ return 1; ++ return 0; ++} ++ ++/* ++ * Output a string with double quotes, doing appropriate backquoting ++ * of characters as necessary. ++ */ ++static void output_quoted_string(char *str, void (*cb)(const char *,void *), ++ void *data) ++{ ++ char ch; ++ char buf[2]; ++ ++ cb("\"", data); ++ if (!str) { ++ cb("\"", data); ++ return; ++ } ++ buf[1] = 0; ++ while ((ch = *str++)) { ++ switch (ch) { ++ case '\\': ++ cb("\\\\", data); ++ break; ++ case '\n': ++ cb("\\n", data); ++ break; ++ case '\t': ++ cb("\\t", data); ++ break; ++ case '\b': ++ cb("\\b", data); ++ break; ++ default: ++ /* This would be a lot faster if we scanned ++ forward for the next "interesting" ++ character. */ ++ buf[0] = ch; ++ cb(buf, data); ++ break; ++ } ++ } ++ cb("\"", data); ++} ++ ++#ifndef EOL ++#define EOL "\n" ++#endif ++ ++/* Errors should be returned, not ignored! */ ++static void dump_profile(struct profile_node *root, int level, ++ void (*cb)(const char *, void *), void *data) ++{ ++ int i; ++ struct profile_node *p; ++ void *iter; ++ long retval; ++ ++ iter = 0; ++ do { ++ retval = profile_find_node(root, 0, 0, 0, &iter, &p); ++ if (retval) ++ break; ++ for (i=0; i < level; i++) ++ cb("\t", data); ++ if (need_double_quotes(p->name)) ++ output_quoted_string(p->name, cb, data); ++ else ++ cb(p->name, data); ++ cb(" = ", data); ++ if (need_double_quotes(p->value)) ++ output_quoted_string(p->value, cb, data); ++ else ++ cb(p->value, data); ++ cb(EOL, data); ++ } while (iter != 0); ++ ++ iter = 0; ++ do { ++ retval = profile_find_node(root, 0, 0, 1, &iter, &p); ++ if (retval) ++ break; ++ if (level == 0) { /* [xxx] */ ++ cb("[", data); ++ if (need_double_quotes(p->name)) ++ output_quoted_string(p->name, cb, data); ++ else ++ cb(p->name, data); ++ cb("]", data); ++ cb(p->final ? "*" : "", data); ++ cb(EOL, data); ++ dump_profile(p, level+1, cb, data); ++ cb(EOL, data); ++ } else { /* xxx = { ... } */ ++ for (i=0; i < level; i++) ++ cb("\t", data); ++ if (need_double_quotes(p->name)) ++ output_quoted_string(p->name, cb, data); ++ else ++ cb(p->name, data); ++ cb(" = {", data); ++ cb(EOL, data); ++ dump_profile(p, level+1, cb, data); ++ for (i=0; i < level; i++) ++ cb("\t", data); ++ cb("}", data); ++ cb(p->final ? "*" : "", data); ++ cb(EOL, data); ++ } ++ } while (iter != 0); ++} ++ ++static void dump_profile_to_file_cb(const char *str, void *data) ++{ ++ fputs(str, data); ++} ++ ++errcode_t profile_write_tree_file(struct profile_node *root, FILE *dstfile) ++{ ++ dump_profile(root, 0, dump_profile_to_file_cb, dstfile); ++ return 0; ++} ++ ++struct prof_buf { ++ char *base; ++ size_t cur, max; ++ int err; ++}; ++ ++static void add_data_to_buffer(struct prof_buf *b, const void *d, size_t len) ++{ ++ if (b->err) ++ return; ++ if (b->max - b->cur < len) { ++ size_t newsize; ++ char *newptr; ++ ++ newsize = b->max + (b->max >> 1) + len + 1024; ++ newptr = realloc(b->base, newsize); ++ if (newptr == NULL) { ++ b->err = 1; ++ return; ++ } ++ b->base = newptr; ++ b->max = newsize; ++ } ++ memcpy(b->base + b->cur, d, len); ++ b->cur += len; /* ignore overflow */ ++} ++ ++static void dump_profile_to_buffer_cb(const char *str, void *data) ++{ ++ add_data_to_buffer((struct prof_buf *)data, str, strlen(str)); ++} ++ ++errcode_t profile_write_tree_to_buffer(struct profile_node *root, ++ char **buf) ++{ ++ struct prof_buf prof_buf = { 0, 0, 0, 0 }; ++ ++ dump_profile(root, 0, dump_profile_to_buffer_cb, &prof_buf); ++ if (prof_buf.err) { ++ *buf = NULL; ++ return ENOMEM; ++ } ++ add_data_to_buffer(&prof_buf, "", 1); /* append nul */ ++ if (prof_buf.max - prof_buf.cur > (prof_buf.max >> 3)) { ++ char *newptr = realloc(prof_buf.base, prof_buf.cur); ++ if (newptr) ++ prof_buf.base = newptr; ++ } ++ *buf = prof_buf.base; ++ return 0; ++} ++#endif ++ ++/* ++ * prof_tree.c --- these routines maintain the parse tree of the ++ * config file. ++ * ++ * All of the details of how the tree is stored is abstracted away in ++ * this file; all of the other profile routines build, access, and ++ * modify the tree via the accessor functions found in this file. ++ * ++ * Each node may represent either a relation or a section header. ++ * ++ * A section header must have its value field set to 0, and may a one ++ * or more child nodes, pointed to by first_child. ++ * ++ * A relation has as its value a pointer to allocated memory ++ * containing a string. Its first_child pointer must be null. ++ * ++ */ ++ ++/* ++ * Free a node, and any children ++ */ ++void profile_free_node(struct profile_node *node) ++{ ++ struct profile_node *child, *next; ++ ++ if (node->magic != PROF_MAGIC_NODE) ++ return; ++ ++ free(node->name); ++ free(node->value); ++ ++ for (child=node->first_child; child; child = next) { ++ next = child->next; ++ profile_free_node(child); ++ } ++ node->magic = 0; ++ ++ free(node); ++} ++ ++#ifndef HAVE_STRDUP ++#undef strdup ++#define strdup MYstrdup ++static char *MYstrdup (const char *s) ++{ ++ size_t sz = strlen(s) + 1; ++ char *p = malloc(sz); ++ if (p != 0) ++ memcpy(p, s, sz); ++ return p; ++} ++#endif ++ ++/* ++ * Create a node ++ */ ++errcode_t profile_create_node(const char *name, const char *value, ++ struct profile_node **ret_node) ++{ ++ struct profile_node *new; ++ ++ new = malloc(sizeof(struct profile_node)); ++ if (!new) ++ return ENOMEM; ++ memset(new, 0, sizeof(struct profile_node)); ++ new->name = strdup(name); ++ if (new->name == 0) { ++ profile_free_node(new); ++ return ENOMEM; ++ } ++ if (value) { ++ new->value = strdup(value); ++ if (new->value == 0) { ++ profile_free_node(new); ++ return ENOMEM; ++ } ++ } ++ new->magic = PROF_MAGIC_NODE; ++ ++ *ret_node = new; ++ return 0; ++} ++ ++/* ++ * This function verifies that all of the representation invarients of ++ * the profile are true. If not, we have a programming bug somewhere, ++ * probably in this file. ++ */ ++#ifdef DEBUG_PROGRAM ++errcode_t profile_verify_node(struct profile_node *node) ++{ ++ struct profile_node *p, *last; ++ errcode_t retval; ++ ++ CHECK_MAGIC(node); ++ ++ if (node->value && node->first_child) ++ return PROF_SECTION_WITH_VALUE; ++ ++ last = 0; ++ for (p = node->first_child; p; last = p, p = p->next) { ++ if (p->prev != last) ++ return PROF_BAD_LINK_LIST; ++ if (last && (last->next != p)) ++ return PROF_BAD_LINK_LIST; ++ if (node->group_level+1 != p->group_level) ++ return PROF_BAD_GROUP_LVL; ++ if (p->parent != node) ++ return PROF_BAD_PARENT_PTR; ++ retval = profile_verify_node(p); ++ if (retval) ++ return retval; ++ } ++ return 0; ++} ++#endif ++ ++/* ++ * Add a node to a particular section ++ */ ++errcode_t profile_add_node(struct profile_node *section, const char *name, ++ const char *value, struct profile_node **ret_node) ++{ ++ errcode_t retval; ++ struct profile_node *p, *last, *new; ++ ++ CHECK_MAGIC(section); ++ ++ if (section->value) ++ return PROF_ADD_NOT_SECTION; ++ ++ /* ++ * Find the place to insert the new node. We look for the ++ * place *after* the last match of the node name, since ++ * order matters. ++ */ ++ for (p=section->first_child, last = 0; p; last = p, p = p->next) { ++ int cmp; ++ cmp = strcmp(p->name, name); ++ if (cmp > 0) ++ break; ++ } ++ retval = profile_create_node(name, value, &new); ++ if (retval) ++ return retval; ++ new->group_level = section->group_level+1; ++ new->deleted = 0; ++ new->parent = section; ++ new->prev = last; ++ new->next = p; ++ if (p) ++ p->prev = new; ++ if (last) ++ last->next = new; ++ else ++ section->first_child = new; ++ if (ret_node) ++ *ret_node = new; ++ return 0; ++} ++ ++/* ++ * Iterate through the section, returning the nodes which match ++ * the given name. If name is NULL, then interate through all the ++ * nodes in the section. If section_flag is non-zero, only return the ++ * section which matches the name; don't return relations. If value ++ * is non-NULL, then only return relations which match the requested ++ * value. (The value argument is ignored if section_flag is non-zero.) ++ * ++ * The first time this routine is called, the state pointer must be ++ * null. When this profile_find_node_relation() returns, if the state ++ * pointer is non-NULL, then this routine should be called again. ++ * (This won't happen if section_flag is non-zero, obviously.) ++ * ++ */ ++errcode_t profile_find_node(struct profile_node *section, const char *name, ++ const char *value, int section_flag, void **state, ++ struct profile_node **node) ++{ ++ struct profile_node *p; ++ ++ CHECK_MAGIC(section); ++ p = *state; ++ if (p) { ++ CHECK_MAGIC(p); ++ } else ++ p = section->first_child; ++ ++ for (; p; p = p->next) { ++ if (name && (strcmp(p->name, name))) ++ continue; ++ if (section_flag) { ++ if (p->value) ++ continue; ++ } else { ++ if (!p->value) ++ continue; ++ if (value && (strcmp(p->value, value))) ++ continue; ++ } ++ if (p->deleted) ++ continue; ++ /* A match! */ ++ if (node) ++ *node = p; ++ break; ++ } ++ if (p == 0) { ++ *state = 0; ++ return section_flag ? PROF_NO_SECTION : PROF_NO_RELATION; ++ } ++ /* ++ * OK, we've found one match; now let's try to find another ++ * one. This way, if we return a non-zero state pointer, ++ * there's guaranteed to be another match that's returned. ++ */ ++ for (p = p->next; p; p = p->next) { ++ if (name && (strcmp(p->name, name))) ++ continue; ++ if (section_flag) { ++ if (p->value) ++ continue; ++ } else { ++ if (!p->value) ++ continue; ++ if (value && (strcmp(p->value, value))) ++ continue; ++ } ++ /* A match! */ ++ break; ++ } ++ *state = p; ++ return 0; ++} ++ ++/* ++ * This is a general-purpose iterator for returning all nodes that ++ * match the specified name array. ++ */ ++struct profile_iterator { ++ prf_magic_t magic; ++ profile_t profile; ++ int flags; ++ const char *const *names; ++ const char *name; ++ prf_file_t file; ++ int file_serial; ++ int done_idx; ++ struct profile_node *node; ++ int num; ++}; ++ ++errcode_t ++profile_iterator_create(profile_t profile, const char *const *names, int flags, ++ void **ret_iter) ++{ ++ struct profile_iterator *iter; ++ int done_idx = 0; ++ ++ if (profile == 0) ++ return PROF_NO_PROFILE; ++ if (profile->magic != PROF_MAGIC_PROFILE) ++ return PROF_MAGIC_PROFILE; ++ if (!names) ++ return PROF_BAD_NAMESET; ++ if (!(flags & PROFILE_ITER_LIST_SECTION)) { ++ if (!names[0]) ++ return PROF_BAD_NAMESET; ++ done_idx = 1; ++ } ++ ++ if ((iter = malloc(sizeof(struct profile_iterator))) == NULL) ++ return ENOMEM; ++ ++ iter->magic = PROF_MAGIC_ITERATOR; ++ iter->profile = profile; ++ iter->names = names; ++ iter->flags = flags; ++ iter->file = profile->first_file; ++ iter->done_idx = done_idx; ++ iter->node = 0; ++ iter->num = 0; ++ *ret_iter = iter; ++ return 0; ++} ++ ++void profile_iterator_free(void **iter_p) ++{ ++ struct profile_iterator *iter; ++ ++ if (!iter_p) ++ return; ++ iter = *iter_p; ++ if (!iter || iter->magic != PROF_MAGIC_ITERATOR) ++ return; ++ free(iter); ++ *iter_p = 0; ++} ++ ++/* ++ * Note: the returned character strings in ret_name and ret_value ++ * points to the stored character string in the parse string. Before ++ * this string value is returned to a calling application ++ * (profile_node_iterator is not an exported interface), it should be ++ * strdup()'ed. ++ */ ++errcode_t profile_node_iterator(void **iter_p, struct profile_node **ret_node, ++ char **ret_name, char **ret_value) ++{ ++ struct profile_iterator *iter = *iter_p; ++ struct profile_node *section, *p; ++ const char *const *cpp; ++ errcode_t retval; ++ int skip_num = 0; ++ ++ if (!iter || iter->magic != PROF_MAGIC_ITERATOR) ++ return PROF_MAGIC_ITERATOR; ++ if (iter->file && iter->file->magic != PROF_MAGIC_FILE) ++ return PROF_MAGIC_FILE; ++ /* ++ * If the file has changed, then the node pointer is invalid, ++ * so we'll have search the file again looking for it. ++ */ ++ if (iter->node && (iter->file && ++ iter->file->upd_serial != iter->file_serial)) { ++ iter->flags &= ~PROFILE_ITER_FINAL_SEEN; ++ skip_num = iter->num; ++ iter->node = 0; ++ } ++ if (iter->node && iter->node->magic != PROF_MAGIC_NODE) { ++ return PROF_MAGIC_NODE; ++ } ++get_new_file: ++ if (iter->node == 0) { ++ if (iter->file == 0 || ++ (iter->flags & PROFILE_ITER_FINAL_SEEN)) { ++ profile_iterator_free(iter_p); ++ if (ret_node) ++ *ret_node = 0; ++ if (ret_name) ++ *ret_name = 0; ++ if (ret_value) ++ *ret_value =0; ++ return 0; ++ } ++ if ((retval = profile_update_file(iter->file))) { ++ if (retval == ENOENT || retval == EACCES) { ++ /* XXX memory leak? */ ++ iter->file = iter->file->next; ++ skip_num = 0; ++ retval = 0; ++ goto get_new_file; ++ } else { ++ profile_iterator_free(iter_p); ++ return retval; ++ } ++ } ++ iter->file_serial = iter->file->upd_serial; ++ /* ++ * Find the section to list if we are a LIST_SECTION, ++ * or find the containing section if not. ++ */ ++ section = iter->file->root; ++ for (cpp = iter->names; cpp[iter->done_idx]; cpp++) { ++ for (p=section->first_child; p; p = p->next) { ++ if (!strcmp(p->name, *cpp) && !p->value) ++ break; ++ } ++ if (!p) { ++ section = 0; ++ break; ++ } ++ section = p; ++ if (p->final) ++ iter->flags |= PROFILE_ITER_FINAL_SEEN; ++ } ++ if (!section) { ++ iter->file = iter->file->next; ++ skip_num = 0; ++ goto get_new_file; ++ } ++ iter->name = *cpp; ++ iter->node = section->first_child; ++ } ++ /* ++ * OK, now we know iter->node is set up correctly. Let's do ++ * the search. ++ */ ++ for (p = iter->node; p; p = p->next) { ++ if (iter->name && strcmp(p->name, iter->name)) ++ continue; ++ if ((iter->flags & PROFILE_ITER_SECTIONS_ONLY) && ++ p->value) ++ continue; ++ if ((iter->flags & PROFILE_ITER_RELATIONS_ONLY) && ++ !p->value) ++ continue; ++ if (skip_num > 0) { ++ skip_num--; ++ continue; ++ } ++ if (p->deleted) ++ continue; ++ break; ++ } ++ iter->num++; ++ if (!p) { ++ iter->file = iter->file->next; ++ iter->node = 0; ++ skip_num = 0; ++ goto get_new_file; ++ } ++ if ((iter->node = p->next) == NULL) ++ iter->file = iter->file->next; ++ if (ret_node) ++ *ret_node = p; ++ if (ret_name) ++ *ret_name = p->name; ++ if (ret_value) ++ *ret_value = p->value; ++ return 0; ++} ++ ++ ++/* ++ * prof_get.c --- routines that expose the public interfaces for ++ * querying items from the profile. ++ * ++ */ ++ ++/* ++ * This function only gets the first value from the file; it is a ++ * helper function for profile_get_string, profile_get_integer, etc. ++ */ ++errcode_t profile_get_value(profile_t profile, const char *name, ++ const char *subname, const char *subsubname, ++ const char **ret_value) ++{ ++ errcode_t retval; ++ void *state; ++ char *value; ++ const char *names[4]; ++ ++ names[0] = name; ++ names[1] = subname; ++ names[2] = subsubname; ++ names[3] = 0; ++ ++ if ((retval = profile_iterator_create(profile, names, ++ PROFILE_ITER_RELATIONS_ONLY, ++ &state))) ++ return retval; ++ ++ if ((retval = profile_node_iterator(&state, 0, 0, &value))) ++ goto cleanup; ++ ++ if (value) ++ *ret_value = value; ++ else ++ retval = PROF_NO_RELATION; ++ ++cleanup: ++ profile_iterator_free(&state); ++ return retval; ++} ++ ++errcode_t ++profile_get_string(profile_t profile, const char *name, const char *subname, ++ const char *subsubname, const char *def_val, ++ char **ret_string) ++{ ++ const char *value; ++ errcode_t retval; ++ ++ if (profile) { ++ retval = profile_get_value(profile, name, subname, ++ subsubname, &value); ++ if (retval == PROF_NO_SECTION || retval == PROF_NO_RELATION) ++ value = def_val; ++ else if (retval) ++ return retval; ++ } else ++ value = def_val; ++ ++ if (value) { ++ *ret_string = malloc(strlen(value)+1); ++ if (*ret_string == 0) ++ return ENOMEM; ++ strcpy(*ret_string, value); ++ } else ++ *ret_string = 0; ++ return 0; ++} ++ ++errcode_t ++profile_get_integer(profile_t profile, const char *name, const char *subname, ++ const char *subsubname, int def_val, int *ret_int) ++{ ++ const char *value; ++ errcode_t retval; ++ char *end_value; ++ long ret_long; ++ ++ *ret_int = def_val; ++ if (profile == 0) ++ return 0; ++ ++ retval = profile_get_value(profile, name, subname, subsubname, &value); ++ if (retval == PROF_NO_SECTION || retval == PROF_NO_RELATION) { ++ *ret_int = def_val; ++ return 0; ++ } else if (retval) ++ return retval; ++ ++ if (value[0] == 0) ++ /* Empty string is no good. */ ++ return PROF_BAD_INTEGER; ++ errno = 0; ++ ret_long = strtol(value, &end_value, 0); ++ ++ /* Overflow or underflow. */ ++ if ((ret_long == LONG_MIN || ret_long == LONG_MAX) && errno != 0) ++ return PROF_BAD_INTEGER; ++ /* Value outside "int" range. */ ++ if ((long) (int) ret_long != ret_long) ++ return PROF_BAD_INTEGER; ++ /* Garbage in string. */ ++ if (end_value != value + strlen (value)) ++ return PROF_BAD_INTEGER; ++ ++ ++ *ret_int = ret_long; ++ return 0; ++} ++ ++errcode_t ++profile_get_uint(profile_t profile, const char *name, const char *subname, ++ const char *subsubname, unsigned int def_val, ++ unsigned int *ret_int) ++{ ++ const char *value; ++ errcode_t retval; ++ char *end_value; ++ unsigned long ret_long; ++ ++ *ret_int = def_val; ++ if (profile == 0) ++ return 0; ++ ++ retval = profile_get_value(profile, name, subname, subsubname, &value); ++ if (retval == PROF_NO_SECTION || retval == PROF_NO_RELATION) { ++ *ret_int = def_val; ++ return 0; ++ } else if (retval) ++ return retval; ++ ++ if (value[0] == 0) ++ /* Empty string is no good. */ ++ return PROF_BAD_INTEGER; ++ errno = 0; ++ ret_long = strtoul(value, &end_value, 0); ++ ++ /* Overflow or underflow. */ ++ if ((ret_long == ULONG_MAX) && errno != 0) ++ return PROF_BAD_INTEGER; ++ /* Value outside "int" range. */ ++ if ((unsigned long) (unsigned int) ret_long != ret_long) ++ return PROF_BAD_INTEGER; ++ /* Garbage in string. */ ++ if (end_value != value + strlen (value)) ++ return PROF_BAD_INTEGER; ++ ++ *ret_int = ret_long; ++ return 0; ++} ++ ++errcode_t ++profile_get_double(profile_t profile, const char *name, const char *subname, ++ const char *subsubname, double def_val, double *ret_double) ++{ ++ const char *value; ++ errcode_t retval; ++ char *end_value; ++ double double_val; ++ ++ *ret_double = def_val; ++ if (profile == 0) ++ return 0; ++ ++ retval = profile_get_value(profile, name, subname, subsubname, &value); ++ if (retval == PROF_NO_SECTION || retval == PROF_NO_RELATION) { ++ *ret_double = def_val; ++ return 0; ++ } else if (retval) ++ return retval; ++ ++ if (value[0] == 0) ++ /* Empty string is no good. */ ++ return PROF_BAD_INTEGER; ++ errno = 0; ++ double_val = strtod(value, &end_value); ++ ++ /* Overflow or underflow. */ ++ if (errno != 0) ++ return PROF_BAD_INTEGER; ++ /* Garbage in string. */ ++ if (end_value != value + strlen(value)) ++ return PROF_BAD_INTEGER; ++ ++ *ret_double = double_val; ++ return 0; ++} ++ ++static const char *const conf_yes[] = { ++ "y", "yes", "true", "t", "1", "on", ++ 0, ++}; ++ ++static const char *const conf_no[] = { ++ "n", "no", "false", "nil", "0", "off", ++ 0, ++}; ++ ++static errcode_t ++profile_parse_boolean(const char *s, int *ret_boolean) ++{ ++ const char *const *p; ++ ++ if (ret_boolean == NULL) ++ return PROF_EINVAL; ++ ++ for(p=conf_yes; *p; p++) { ++ if (!strcasecmp(*p,s)) { ++ *ret_boolean = 1; ++ return 0; ++ } ++ } ++ ++ for(p=conf_no; *p; p++) { ++ if (!strcasecmp(*p,s)) { ++ *ret_boolean = 0; ++ return 0; ++ } ++ } ++ ++ return PROF_BAD_BOOLEAN; ++} ++ ++errcode_t ++profile_get_boolean(profile_t profile, const char *name, const char *subname, ++ const char *subsubname, int def_val, int *ret_boolean) ++{ ++ const char *value; ++ errcode_t retval; ++ ++ if (profile == 0) { ++ *ret_boolean = def_val; ++ return 0; ++ } ++ ++ retval = profile_get_value(profile, name, subname, subsubname, &value); ++ if (retval == PROF_NO_SECTION || retval == PROF_NO_RELATION) { ++ *ret_boolean = def_val; ++ return 0; ++ } else if (retval) ++ return retval; ++ ++ return profile_parse_boolean (value, ret_boolean); ++} ++ ++errcode_t ++profile_iterator(void **iter_p, char **ret_name, char **ret_value) ++{ ++ char *name, *value; ++ errcode_t retval; ++ ++ retval = profile_node_iterator(iter_p, 0, &name, &value); ++ if (retval) ++ return retval; ++ ++ if (ret_name) { ++ if (name) { ++ *ret_name = malloc(strlen(name)+1); ++ if (!*ret_name) ++ return ENOMEM; ++ strcpy(*ret_name, name); ++ } else ++ *ret_name = 0; ++ } ++ if (ret_value) { ++ if (value) { ++ *ret_value = malloc(strlen(value)+1); ++ if (!*ret_value) { ++ if (ret_name) { ++ free(*ret_name); ++ *ret_name = 0; ++ } ++ return ENOMEM; ++ } ++ strcpy(*ret_value, value); ++ } else ++ *ret_value = 0; ++ } ++ return 0; ++} ++ ++#ifdef DEBUG_PROGRAM ++ ++/* ++ * test_profile.c --- testing program for the profile routine ++ */ ++ ++#include "argv_parse.h" ++#include "profile_helpers.h" ++ ++const char *program_name = "test_profile"; ++ ++#define PRINT_VALUE 1 ++#define PRINT_VALUES 2 ++ ++static void do_cmd(profile_t profile, char **argv) ++{ ++ errcode_t retval; ++ const char **names, *value; ++ char **values, **cpp; ++ char *cmd; ++ int print_status; ++ ++ cmd = *(argv); ++ names = (const char **) argv + 1; ++ print_status = 0; ++ retval = 0; ++ if (cmd == 0) ++ return; ++ if (!strcmp(cmd, "query")) { ++ retval = profile_get_values(profile, names, &values); ++ print_status = PRINT_VALUES; ++ } else if (!strcmp(cmd, "query1")) { ++ const char *name = 0; ++ const char *subname = 0; ++ const char *subsubname = 0; ++ ++ name = names[0]; ++ if (name) ++ subname = names[1]; ++ if (subname) ++ subsubname = names[2]; ++ if (subsubname && names[3]) { ++ fprintf(stderr, ++ "Only 3 levels are allowed with query1\n"); ++ retval = EINVAL; ++ } else ++ retval = profile_get_value(profile, name, subname, ++ subsubname, &value); ++ print_status = PRINT_VALUE; ++ } else if (!strcmp(cmd, "list_sections")) { ++ retval = profile_get_subsection_names(profile, names, ++ &values); ++ print_status = PRINT_VALUES; ++ } else if (!strcmp(cmd, "list_relations")) { ++ retval = profile_get_relation_names(profile, names, ++ &values); ++ print_status = PRINT_VALUES; ++ } else if (!strcmp(cmd, "dump")) { ++ retval = profile_write_tree_file ++ (profile->first_file->root, stdout); ++#if 0 ++ } else if (!strcmp(cmd, "clear")) { ++ retval = profile_clear_relation(profile, names); ++ } else if (!strcmp(cmd, "update")) { ++ retval = profile_update_relation(profile, names+2, ++ *names, *(names+1)); ++#endif ++ } else if (!strcmp(cmd, "verify")) { ++ retval = profile_verify_node ++ (profile->first_file->root); ++#if 0 ++ } else if (!strcmp(cmd, "rename_section")) { ++ retval = profile_rename_section(profile, names+1, *names); ++ } else if (!strcmp(cmd, "add")) { ++ value = *names; ++ if (strcmp(value, "NULL") == 0) ++ value = NULL; ++ retval = profile_add_relation(profile, names+1, value); ++ } else if (!strcmp(cmd, "flush")) { ++ retval = profile_flush(profile); ++#endif ++ } else { ++ printf("Invalid command.\n"); ++ } ++ if (retval) { ++ com_err(cmd, retval, ""); ++ print_status = 0; ++ } ++ switch (print_status) { ++ case PRINT_VALUE: ++ printf("%s\n", value); ++ break; ++ case PRINT_VALUES: ++ for (cpp = values; *cpp; cpp++) ++ printf("%s\n", *cpp); ++ profile_free_list(values); ++ break; ++ } ++} ++ ++static void do_batchmode(profile_t profile) ++{ ++ int argc, ret; ++ char **argv; ++ char buf[256]; ++ ++ while (!feof(stdin)) { ++ if (fgets(buf, sizeof(buf), stdin) == NULL) ++ break; ++ printf(">%s", buf); ++ ret = argv_parse(buf, &argc, &argv); ++ if (ret != 0) { ++ printf("Argv_parse returned %d!\n", ret); ++ continue; ++ } ++ do_cmd(profile, argv); ++ printf("\n"); ++ argv_free(argv); ++ } ++ profile_release(profile); ++ exit(0); ++ ++} ++ ++void syntax_err_report(const char *filename, long err, int line_num) ++{ ++ fprintf(stderr, "Syntax error in %s, line number %d: %s\n", ++ filename, line_num, error_message(err)); ++ exit(1); ++} ++ ++const char *default_str = "[foo]\n\tbar=quux\n\tsub = {\n\t\twin = true\n}\n"; ++ ++int main(int argc, char **argv) ++{ ++ profile_t profile; ++ long retval; ++ char *cmd; ++ ++ if (argc < 2) { ++ fprintf(stderr, "Usage: %s filename [cmd argset]\n", program_name); ++ exit(1); ++ } ++ ++ initialize_prof_error_table(); ++ ++ profile_set_syntax_err_cb(syntax_err_report); ++ ++ retval = profile_init_path(argv[1], &profile); ++ if (retval) { ++ com_err(program_name, retval, "while initializing profile"); ++ exit(1); ++ } ++ retval = profile_set_default(profile, default_str); ++ if (retval) { ++ com_err(program_name, retval, "while setting default"); ++ exit(1); ++ } ++ ++ cmd = *(argv+2); ++ if (!cmd || !strcmp(cmd, "batch")) ++ do_batchmode(profile); ++ else ++ do_cmd(profile, argv+2); ++ profile_release(profile); ++ ++ return 0; ++} ++ ++#endif +--- /dev/null ++++ b/lib/support/profile.h +@@ -0,0 +1,107 @@ ++/* ++ * profile.h ++ * ++ * Copyright (C) 2005 by Theodore Ts'o. ++ * ++ * %Begin-Header% ++ * This file may be redistributed under the terms of the GNU Public ++ * License. ++ * %End-Header% ++ * ++ * Copyright (C) 1985-2005 by the Massachusetts Institute of Technology. ++ * ++ * All rights reserved. ++ * ++ * Export of this software from the United States of America may require ++ * a specific license from the United States Government. It is the ++ * responsibility of any person or organization contemplating export to ++ * obtain such a license before exporting. ++ * ++ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and ++ * distribute this software and its documentation for any purpose and ++ * without fee is hereby granted, provided that the above copyright ++ * notice appear in all copies and that both that copyright notice and ++ * this permission notice appear in supporting documentation, and that ++ * the name of M.I.T. not be used in advertising or publicity pertaining ++ * to distribution of the software without specific, written prior ++ * permission. Furthermore if you modify this software you must label ++ * your software as modified software and not distribute it in such a ++ * fashion that it might be confused with the original MIT software. ++ * M.I.T. makes no representations about the suitability of this software ++ * for any purpose. It is provided "as is" without express or implied ++ * warranty. ++ * ++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR ++ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED ++ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. ++ */ ++ ++#ifndef _PROFILE_H ++#define _PROFILE_H ++ ++typedef struct _profile_t *profile_t; ++ ++typedef void (*profile_syntax_err_cb_t)(const char *file, long err, ++ int line_num); ++ ++/* ++ * Used by the profile iterator in prof_get.c ++ */ ++#define PROFILE_ITER_LIST_SECTION 0x0001 ++#define PROFILE_ITER_SECTIONS_ONLY 0x0002 ++#define PROFILE_ITER_RELATIONS_ONLY 0x0004 ++ ++#ifdef __cplusplus ++extern "C" { ++#endif /* __cplusplus */ ++ ++long profile_init ++ (const char * *files, profile_t *ret_profile); ++ ++void profile_release ++ (profile_t profile); ++ ++long profile_set_default ++ (profile_t profile, const char *def_string); ++ ++long profile_get_string ++ (profile_t profile, const char *name, const char *subname, ++ const char *subsubname, const char *def_val, ++ char **ret_string); ++long profile_get_integer ++ (profile_t profile, const char *name, const char *subname, ++ const char *subsubname, int def_val, ++ int *ret_default); ++ ++long profile_get_uint ++ (profile_t profile, const char *name, const char *subname, ++ const char *subsubname, unsigned int def_val, ++ unsigned int *ret_int); ++ ++long profile_get_double ++ (profile_t profile, const char *name, const char *subname, ++ const char *subsubname, double def_val, ++ double *ret_float); ++ ++long profile_get_boolean ++ (profile_t profile, const char *name, const char *subname, ++ const char *subsubname, int def_val, ++ int *ret_default); ++ ++long profile_iterator_create ++ (profile_t profile, const char *const *names, ++ int flags, void **ret_iter); ++ ++void profile_iterator_free ++ (void **iter_p); ++ ++long profile_iterator ++ (void **iter_p, char **ret_name, char **ret_value); ++ ++profile_syntax_err_cb_t profile_set_syntax_err_cb(profile_syntax_err_cb_t hook); ++ ++#ifdef __cplusplus ++} ++#endif /* __cplusplus */ ++ ++#endif /* _KRB5_H */ +--- /dev/null ++++ b/lib/support/profile_helpers.c +@@ -0,0 +1,310 @@ ++/* ++ * profile_helpers.c -- Helper functions for the profile library ++ * ++ * These functions are not part of the "core" profile library, and do ++ * not require access to the internal functions and data structures of ++ * the profile library. They are mainly convenience functions for ++ * programs that want to do something unusual such as obtaining the ++ * list of sections or relations, or accessing multiple values from a ++ * relation that is listed more than once. This functionality can all ++ * be done using the profile_iterator abstraction, but it is less ++ * convenient. ++ * ++ * Copyright (C) 2006 by Theodore Ts'o. ++ * ++ * %Begin-Header% ++ * This file may be redistributed under the terms of the GNU Public ++ * License. ++ * %End-Header% ++ */ ++ ++#include "config.h" ++#include ++#include ++#include ++ ++#include ++#include "profile.h" ++#include "prof_err.h" ++ ++/* ++ * These functions --- init_list(), end_list(), and add_to_list() are ++ * internal functions used to build up a null-terminated char ** list ++ * of strings to be returned by functions like profile_get_values. ++ * ++ * The profile_string_list structure is used for internal booking ++ * purposes to build up the list, which is returned in *ret_list by ++ * the end_list() function. ++ * ++ * The publicly exported interface for freeing char** list is ++ * profile_free_list(). ++ */ ++ ++struct profile_string_list { ++ char **list; ++ int num; ++ int max; ++}; ++ ++/* ++ * Initialize the string list abstraction. ++ */ ++static errcode_t init_list(struct profile_string_list *list) ++{ ++ list->num = 0; ++ list->max = 10; ++ list->list = malloc(list->max * sizeof(char *)); ++ if (list->list == 0) ++ return ENOMEM; ++ list->list[0] = 0; ++ return 0; ++} ++ ++/* ++ * Free any memory left over in the string abstraction, returning the ++ * built up list in *ret_list if it is non-null. ++ */ ++static void end_list(struct profile_string_list *list, char ***ret_list) ++{ ++ char **cp; ++ ++ if (list == 0) ++ return; ++ ++ if (ret_list) { ++ *ret_list = list->list; ++ return; ++ } else { ++ for (cp = list->list; *cp; cp++) ++ free(*cp); ++ free(list->list); ++ } ++ list->num = list->max = 0; ++ list->list = 0; ++} ++ ++/* ++ * Add a string to the list. ++ */ ++static errcode_t add_to_list(struct profile_string_list *list, char *str) ++{ ++ char **newlist; ++ int newmax; ++ ++ if (list->num+1 >= list->max) { ++ newmax = list->max + 10; ++ newlist = realloc(list->list, newmax * sizeof(char *)); ++ if (newlist == 0) ++ return ENOMEM; ++ list->max = newmax; ++ list->list = newlist; ++ } ++ ++ list->list[list->num++] = str; ++ list->list[list->num] = 0; ++ return 0; ++} ++ ++/* ++ * Return TRUE if the string is already a member of the list. ++ */ ++static int is_list_member(struct profile_string_list *list, const char *str) ++{ ++ char **cpp; ++ ++ if (!list->list) ++ return 0; ++ ++ for (cpp = list->list; *cpp; cpp++) { ++ if (!strcmp(*cpp, str)) ++ return 1; ++ } ++ return 0; ++} ++ ++/* ++ * This function frees a null-terminated list as returned by ++ * profile_get_values. ++ */ ++void profile_free_list(char **list) ++{ ++ char **cp; ++ ++ if (list == 0) ++ return; ++ ++ for (cp = list; *cp; cp++) ++ free(*cp); ++ free(list); ++} ++ ++errcode_t ++profile_get_values(profile_t profile, const char *const *names, ++ char ***ret_values) ++{ ++ errcode_t retval; ++ void *state; ++ char *value; ++ struct profile_string_list values; ++ ++ if ((retval = profile_iterator_create(profile, names, ++ PROFILE_ITER_RELATIONS_ONLY, ++ &state))) ++ return retval; ++ ++ if ((retval = init_list(&values))) ++ return retval; ++ ++ do { ++ if ((retval = profile_iterator(&state, 0, &value))) ++ goto cleanup; ++ if (value) ++ add_to_list(&values, value); ++ } while (state); ++ ++ if (values.num == 0) { ++ retval = PROF_NO_RELATION; ++ goto cleanup; ++ } ++ ++ end_list(&values, ret_values); ++ return 0; ++ ++cleanup: ++ end_list(&values, 0); ++ return retval; ++} ++ ++/* ++ * This function will return the list of the names of subections in the ++ * under the specified section name. ++ */ ++errcode_t ++profile_get_subsection_names(profile_t profile, const char **names, ++ char ***ret_names) ++{ ++ errcode_t retval; ++ void *state; ++ char *name; ++ struct profile_string_list values; ++ ++ if ((retval = profile_iterator_create(profile, names, ++ PROFILE_ITER_LIST_SECTION | PROFILE_ITER_SECTIONS_ONLY, ++ &state))) ++ return retval; ++ ++ if ((retval = init_list(&values))) ++ return retval; ++ ++ do { ++ if ((retval = profile_iterator(&state, &name, 0))) ++ goto cleanup; ++ if (name) ++ add_to_list(&values, name); ++ } while (state); ++ ++ end_list(&values, ret_names); ++ return 0; ++ ++cleanup: ++ end_list(&values, 0); ++ return retval; ++} ++ ++/* ++ * This function will return the list of the names of relations in the ++ * under the specified section name. ++ */ ++errcode_t ++profile_get_relation_names(profile_t profile, const char **names, ++ char ***ret_names) ++{ ++ errcode_t retval; ++ void *state; ++ char *name; ++ struct profile_string_list values; ++ ++ if ((retval = profile_iterator_create(profile, names, ++ PROFILE_ITER_LIST_SECTION | PROFILE_ITER_RELATIONS_ONLY, ++ &state))) ++ return retval; ++ ++ if ((retval = init_list(&values))) ++ return retval; ++ ++ do { ++ if ((retval = profile_iterator(&state, &name, 0))) ++ goto cleanup; ++ if (name) { ++ if (is_list_member(&values, name)) ++ free(name); ++ else ++ add_to_list(&values, name); ++ } ++ } while (state); ++ ++ end_list(&values, ret_names); ++ return 0; ++ ++cleanup: ++ end_list(&values, 0); ++ return retval; ++} ++ ++ ++void ++profile_release_string(char *str) ++{ ++ free(str); ++} ++ ++errcode_t ++profile_init_path(const char * filepath, ++ profile_t *ret_profile) ++{ ++ int n_entries, i; ++ unsigned int ent_len; ++ const char *s, *t; ++ char **filenames; ++ errcode_t retval; ++ ++ /* count the distinct filename components */ ++ for(s = filepath, n_entries = 1; *s; s++) { ++ if (*s == ':') ++ n_entries++; ++ } ++ ++ /* the array is NULL terminated */ ++ filenames = (char **) malloc((n_entries+1) * sizeof(char*)); ++ if (filenames == 0) ++ return ENOMEM; ++ ++ /* measure, copy, and skip each one */ ++ for(s = filepath, i=0; (t = strchr(s, ':')) || (t=s+strlen(s)); s=t+1, i++) { ++ ent_len = t-s; ++ filenames[i] = (char*) malloc(ent_len + 1); ++ if (filenames[i] == 0) { ++ /* if malloc fails, free the ones that worked */ ++ while(--i >= 0) free(filenames[i]); ++ free(filenames); ++ return ENOMEM; ++ } ++ strncpy(filenames[i], s, ent_len); ++ filenames[i][ent_len] = 0; ++ if (*t == 0) { ++ i++; ++ break; ++ } ++ } ++ /* cap the array */ ++ filenames[i] = 0; ++ ++ retval = profile_init((const char **) filenames, ++ ret_profile); ++ ++ /* count back down and free the entries */ ++ while(--i >= 0) free(filenames[i]); ++ free(filenames); ++ ++ return retval; ++} +--- /dev/null ++++ b/lib/support/profile_helpers.h +@@ -0,0 +1,28 @@ ++/* ++ * profile_helpers.h -- Function prototypes for profile helper functions ++ * ++ * Copyright (C) 2006 by Theodore Ts'o. ++ * ++ * %Begin-Header% ++ * This file may be redistributed under the terms of the GNU Public ++ * License. ++ * %End-Header% ++ */ ++ ++long profile_get_values ++ (profile_t profile, const char *const *names, char ***ret_values); ++ ++void profile_free_list ++ (char **list); ++ ++long profile_get_relation_names ++ (profile_t profile, const char **names, char ***ret_names); ++ ++long profile_get_subsection_names ++ (profile_t profile, const char **names, char ***ret_names); ++ ++void profile_release_string (char *str); ++ ++long profile_init_path ++ (const char * filelist, profile_t *ret_profile); ++ +--- /dev/null ++++ b/lib/support/quotaio.c +@@ -0,0 +1,407 @@ ++/** quotaio.c ++ * ++ * Generic IO operations on quotafiles ++ * Jan Kara - sponsored by SuSE CR ++ * Aditya Kali - Ported to e2fsprogs ++ */ ++ ++#include "config.h" ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "common.h" ++#include "quotaio.h" ++ ++static const char * const extensions[MAXQUOTAS] = {"user", "group"}; ++static const char * const basenames[] = { ++ "", /* undefined */ ++ "quota", /* QFMT_VFS_OLD */ ++ "aquota", /* QFMT_VFS_V0 */ ++ "", /* QFMT_OCFS2 */ ++ "aquota" /* QFMT_VFS_V1 */ ++}; ++ ++/* Header in all newer quotafiles */ ++struct disk_dqheader { ++ __le32 dqh_magic; ++ __le32 dqh_version; ++} __attribute__ ((packed)); ++ ++/** ++ * Convert type of quota to written representation ++ */ ++const char *type2name(int type) ++{ ++ return extensions[type]; ++} ++ ++/** ++ * Creates a quota file name for given type and format. ++ */ ++const char *quota_get_qf_name(int type, int fmt, char *buf) ++{ ++ if (!buf) ++ return NULL; ++ snprintf(buf, QUOTA_NAME_LEN, "%s.%s", ++ basenames[fmt], extensions[type]); ++ ++ return buf; ++} ++ ++/* ++ * Set grace time if needed ++ */ ++void update_grace_times(struct dquot *q) ++{ ++ time_t now; ++ ++ time(&now); ++ if (q->dq_dqb.dqb_bsoftlimit && toqb(q->dq_dqb.dqb_curspace) > ++ q->dq_dqb.dqb_bsoftlimit) { ++ if (!q->dq_dqb.dqb_btime) ++ q->dq_dqb.dqb_btime = ++ now + q->dq_h->qh_info.dqi_bgrace; ++ } else { ++ q->dq_dqb.dqb_btime = 0; ++ } ++ ++ if (q->dq_dqb.dqb_isoftlimit && q->dq_dqb.dqb_curinodes > ++ q->dq_dqb.dqb_isoftlimit) { ++ if (!q->dq_dqb.dqb_itime) ++ q->dq_dqb.dqb_itime = ++ now + q->dq_h->qh_info.dqi_igrace; ++ } else { ++ q->dq_dqb.dqb_itime = 0; ++ } ++} ++ ++static int compute_num_blocks_proc(ext2_filsys fs EXT2FS_ATTR((unused)), ++ blk64_t *blocknr EXT2FS_ATTR((unused)), ++ e2_blkcnt_t blockcnt EXT2FS_ATTR((unused)), ++ blk64_t ref_block EXT2FS_ATTR((unused)), ++ int ref_offset EXT2FS_ATTR((unused)), ++ void *private) ++{ ++ blk64_t *num_blocks = private; ++ ++ *num_blocks += 1; ++ return 0; ++} ++ ++errcode_t quota_inode_truncate(ext2_filsys fs, ext2_ino_t ino) ++{ ++ struct ext2_inode inode; ++ errcode_t err; ++ ++ if ((err = ext2fs_read_inode(fs, ino, &inode))) ++ return err; ++ ++ if ((ino == EXT4_USR_QUOTA_INO) || (ino == EXT4_GRP_QUOTA_INO)) { ++ inode.i_dtime = fs->now ? fs->now : time(0); ++ if (!ext2fs_inode_has_valid_blocks2(fs, &inode)) ++ return 0; ++ err = ext2fs_punch(fs, ino, &inode, NULL, 0, ~0ULL); ++ if (err) ++ return err; ++ fs->flags &= ~EXT2_FLAG_SUPER_ONLY; ++ memset(&inode, 0, sizeof(struct ext2_inode)); ++ } else { ++ inode.i_flags &= ~EXT2_IMMUTABLE_FL; ++ } ++ err = ext2fs_write_inode(fs, ino, &inode); ++ return err; ++} ++ ++static ext2_off64_t compute_inode_size(ext2_filsys fs, ext2_ino_t ino) ++{ ++ blk64_t num_blocks = 0; ++ ++ ext2fs_block_iterate3(fs, ino, ++ BLOCK_FLAG_READ_ONLY, ++ NULL, ++ compute_num_blocks_proc, ++ &num_blocks); ++ return num_blocks * fs->blocksize; ++} ++ ++/* Functions to read/write quota file. */ ++static unsigned int quota_write_nomount(struct quota_file *qf, ++ ext2_loff_t offset, ++ void *buf, unsigned int size) ++{ ++ ext2_file_t e2_file = qf->e2_file; ++ unsigned int bytes_written = 0; ++ errcode_t err; ++ ++ err = ext2fs_file_llseek(e2_file, offset, EXT2_SEEK_SET, NULL); ++ if (err) { ++ log_err("ext2fs_file_llseek failed: %ld", err); ++ return 0; ++ } ++ ++ err = ext2fs_file_write(e2_file, buf, size, &bytes_written); ++ if (err) { ++ log_err("ext2fs_file_write failed: %ld", err); ++ return 0; ++ } ++ ++ /* Correct inode.i_size is set in end_io. */ ++ return bytes_written; ++} ++ ++static unsigned int quota_read_nomount(struct quota_file *qf, ++ ext2_loff_t offset, ++ void *buf, unsigned int size) ++{ ++ ext2_file_t e2_file = qf->e2_file; ++ unsigned int bytes_read = 0; ++ errcode_t err; ++ ++ err = ext2fs_file_llseek(e2_file, offset, EXT2_SEEK_SET, NULL); ++ if (err) { ++ log_err("ext2fs_file_llseek failed: %ld", err); ++ return 0; ++ } ++ ++ err = ext2fs_file_read(e2_file, buf, size, &bytes_read); ++ if (err) { ++ log_err("ext2fs_file_read failed: %ld", err); ++ return 0; ++ } ++ ++ return bytes_read; ++} ++ ++/* ++ * Detect quota format and initialize quota IO ++ */ ++errcode_t quota_file_open(quota_ctx_t qctx, struct quota_handle *h, ++ ext2_ino_t qf_ino, int type, int fmt, int flags) ++{ ++ ext2_filsys fs = qctx->fs; ++ ext2_file_t e2_file; ++ errcode_t err; ++ int allocated_handle = 0; ++ ++ if (type >= MAXQUOTAS) ++ return EINVAL; ++ ++ if (fmt == -1) ++ fmt = QFMT_VFS_V1; ++ ++ err = ext2fs_read_bitmaps(fs); ++ if (err) ++ return err; ++ ++ if (qf_ino == 0) { ++ if (type == USRQUOTA) ++ qf_ino = fs->super->s_usr_quota_inum; ++ else ++ qf_ino = fs->super->s_grp_quota_inum; ++ } ++ ++ log_debug("Opening quota ino=%lu, type=%d", qf_ino, type); ++ err = ext2fs_file_open(fs, qf_ino, flags, &e2_file); ++ if (err) { ++ log_err("ext2fs_file_open failed: %s", error_message(err)); ++ return err; ++ } ++ ++ if (!h) { ++ if (qctx->quota_file[type]) { ++ h = qctx->quota_file[type]; ++ if (((flags & EXT2_FILE_WRITE) == 0) || ++ (h->qh_file_flags & EXT2_FILE_WRITE)) ++ return 0; ++ (void) quota_file_close(qctx, h); ++ } ++ err = ext2fs_get_mem(sizeof(struct quota_handle), &h); ++ if (err) { ++ log_err("Unable to allocate quota handle"); ++ return err; ++ } ++ allocated_handle = 1; ++ } ++ ++ h->qh_qf.e2_file = e2_file; ++ h->qh_qf.fs = fs; ++ h->qh_qf.ino = qf_ino; ++ h->e2fs_write = quota_write_nomount; ++ h->e2fs_read = quota_read_nomount; ++ h->qh_file_flags = flags; ++ h->qh_io_flags = 0; ++ h->qh_type = type; ++ h->qh_fmt = fmt; ++ memset(&h->qh_info, 0, sizeof(h->qh_info)); ++ h->qh_ops = "afile_ops_2; ++ ++ if (h->qh_ops->check_file && ++ (h->qh_ops->check_file(h, type, fmt) == 0)) { ++ log_err("qh_ops->check_file failed"); ++ goto errout; ++ } ++ ++ if (h->qh_ops->init_io && (h->qh_ops->init_io(h) < 0)) { ++ log_err("qh_ops->init_io failed"); ++ goto errout; ++ } ++ if (allocated_handle) ++ qctx->quota_file[type] = h; ++ ++ return 0; ++errout: ++ ext2fs_file_close(e2_file); ++ if (allocated_handle) ++ ext2fs_free_mem(&h); ++ return -1; ++} ++ ++static errcode_t quota_inode_init_new(ext2_filsys fs, ext2_ino_t ino) ++{ ++ struct ext2_inode inode; ++ errcode_t err = 0; ++ ++ err = ext2fs_read_inode(fs, ino, &inode); ++ if (err) { ++ log_err("ex2fs_read_inode failed"); ++ return err; ++ } ++ ++ if (EXT2_I_SIZE(&inode)) ++ quota_inode_truncate(fs, ino); ++ ++ memset(&inode, 0, sizeof(struct ext2_inode)); ++ ext2fs_iblk_set(fs, &inode, 0); ++ inode.i_atime = inode.i_mtime = ++ inode.i_ctime = fs->now ? fs->now : time(0); ++ inode.i_links_count = 1; ++ inode.i_mode = LINUX_S_IFREG | 0600; ++ inode.i_flags |= EXT2_IMMUTABLE_FL; ++ if (fs->super->s_feature_incompat & ++ EXT3_FEATURE_INCOMPAT_EXTENTS) ++ inode.i_flags |= EXT4_EXTENTS_FL; ++ ++ err = ext2fs_write_new_inode(fs, ino, &inode); ++ if (err) { ++ log_err("ext2fs_write_new_inode failed: %ld", err); ++ return err; ++ } ++ return err; ++} ++ ++/* ++ * Create new quotafile of specified format on given filesystem ++ */ ++errcode_t quota_file_create(struct quota_handle *h, ext2_filsys fs, int type, int fmt) ++{ ++ ext2_file_t e2_file; ++ int err; ++ unsigned long qf_inum; ++ ++ if (fmt == -1) ++ fmt = QFMT_VFS_V1; ++ ++ h->qh_qf.fs = fs; ++ if (type == USRQUOTA) ++ qf_inum = EXT4_USR_QUOTA_INO; ++ else if (type == GRPQUOTA) ++ qf_inum = EXT4_GRP_QUOTA_INO; ++ else ++ return -1; ++ ++ err = ext2fs_read_bitmaps(fs); ++ if (err) ++ goto out_err; ++ ++ err = quota_inode_init_new(fs, qf_inum); ++ if (err) { ++ log_err("init_new_quota_inode failed"); ++ goto out_err; ++ } ++ h->qh_qf.ino = qf_inum; ++ h->qh_file_flags = EXT2_FILE_WRITE | EXT2_FILE_CREATE; ++ h->e2fs_write = quota_write_nomount; ++ h->e2fs_read = quota_read_nomount; ++ ++ log_debug("Creating quota ino=%lu, type=%d", qf_inum, type); ++ err = ext2fs_file_open(fs, qf_inum, h->qh_file_flags, &e2_file); ++ if (err) { ++ log_err("ext2fs_file_open failed: %d", err); ++ goto out_err; ++ } ++ h->qh_qf.e2_file = e2_file; ++ ++ h->qh_io_flags = 0; ++ h->qh_type = type; ++ h->qh_fmt = fmt; ++ memset(&h->qh_info, 0, sizeof(h->qh_info)); ++ h->qh_ops = "afile_ops_2; ++ ++ if (h->qh_ops->new_io && (h->qh_ops->new_io(h) < 0)) { ++ log_err("qh_ops->new_io failed"); ++ goto out_err1; ++ } ++ ++ return 0; ++ ++out_err1: ++ ext2fs_file_close(e2_file); ++out_err: ++ ++ if (qf_inum) ++ quota_inode_truncate(fs, qf_inum); ++ ++ return -1; ++} ++ ++/* ++ * Close quotafile and release handle ++ */ ++errcode_t quota_file_close(quota_ctx_t qctx, struct quota_handle *h) ++{ ++ if (h->qh_io_flags & IOFL_INFODIRTY) { ++ if (h->qh_ops->write_info && h->qh_ops->write_info(h) < 0) ++ return -1; ++ h->qh_io_flags &= ~IOFL_INFODIRTY; ++ } ++ ++ if (h->qh_ops->end_io && h->qh_ops->end_io(h) < 0) ++ return -1; ++ if (h->qh_qf.e2_file) { ++ __u64 new_size, size; ++ ++ new_size = compute_inode_size(h->qh_qf.fs, h->qh_qf.ino); ++ ext2fs_file_flush(h->qh_qf.e2_file); ++ if (ext2fs_file_get_lsize(h->qh_qf.e2_file, &size)) ++ new_size = 0; ++ if (size != new_size) ++ ext2fs_file_set_size2(h->qh_qf.e2_file, new_size); ++ ext2fs_file_close(h->qh_qf.e2_file); ++ } ++ if (qctx->quota_file[h->qh_type] == h) ++ ext2fs_free_mem(&qctx->quota_file[h->qh_type]); ++ return 0; ++} ++ ++/* ++ * Create empty quota structure ++ */ ++struct dquot *get_empty_dquot(void) ++{ ++ struct dquot *dquot; ++ ++ if (ext2fs_get_memzero(sizeof(struct dquot), &dquot)) { ++ log_err("Failed to allocate dquot"); ++ return NULL; ++ } ++ ++ dquot->dq_id = -1; ++ return dquot; ++} +--- /dev/null ++++ b/lib/support/quotaio.h +@@ -0,0 +1,223 @@ ++/** quotaio.h ++ * ++ * Interface to the quota library. ++ * ++ * The quota library provides interface for creating and updating the quota ++ * files and the ext4 superblock fields. It supports the new VFS_V1 quota ++ * format. The quota library also provides support for keeping track of quotas ++ * in memory. ++ * The typical way to use the quota library is as follows: ++ * { ++ * quota_ctx_t qctx; ++ * ++ * quota_init_context(&qctx, fs, -1); ++ * { ++ * quota_compute_usage(qctx, -1); ++ * AND/OR ++ * quota_data_add/quota_data_sub/quota_data_inodes(); ++ * } ++ * quota_write_inode(qctx, USRQUOTA); ++ * quota_write_inode(qctx, GRPQUOTA); ++ * quota_release_context(&qctx); ++ * } ++ * ++ * This initial version does not support reading the quota files. This support ++ * will be added in near future. ++ * ++ * Aditya Kali ++ * Header of IO operations for quota utilities ++ * ++ * Jan Kara ++ */ ++ ++#ifndef GUARD_QUOTAIO_H ++#define GUARD_QUOTAIO_H ++ ++#include ++#include ++#include ++ ++#include "ext2fs/ext2_fs.h" ++#include "ext2fs/ext2fs.h" ++#include "dqblk_v2.h" ++ ++typedef int64_t qsize_t; /* Type in which we store size limitations */ ++ ++#define MAXQUOTAS 2 ++#define USRQUOTA 0 ++#define GRPQUOTA 1 ++ ++typedef struct quota_ctx *quota_ctx_t; ++struct dict_t; ++ ++struct quota_ctx { ++ ext2_filsys fs; ++ struct dict_t *quota_dict[MAXQUOTAS]; ++ struct quota_handle *quota_file[MAXQUOTAS]; ++}; ++ ++/* ++ * Definitions of magics and versions of current quota files ++ */ ++#define INITQMAGICS {\ ++ 0xd9c01f11, /* USRQUOTA */\ ++ 0xd9c01927 /* GRPQUOTA */\ ++} ++ ++/* Size of blocks in which are counted size limits in generic utility parts */ ++#define QUOTABLOCK_BITS 10 ++#define QUOTABLOCK_SIZE (1 << QUOTABLOCK_BITS) ++#define toqb(x) (((x) + QUOTABLOCK_SIZE - 1) >> QUOTABLOCK_BITS) ++ ++/* Quota format type IDs */ ++#define QFMT_VFS_OLD 1 ++#define QFMT_VFS_V0 2 ++#define QFMT_VFS_V1 4 ++ ++/* ++ * The following constants define the default amount of time given a user ++ * before the soft limits are treated as hard limits (usually resulting ++ * in an allocation failure). The timer is started when the user crosses ++ * their soft limit, it is reset when they go below their soft limit. ++ */ ++#define MAX_IQ_TIME 604800 /* (7*24*60*60) 1 week */ ++#define MAX_DQ_TIME 604800 /* (7*24*60*60) 1 week */ ++ ++#define IOFL_INFODIRTY 0x01 /* Did info change? */ ++ ++struct quotafile_ops; ++ ++/* Generic information about quotafile */ ++struct util_dqinfo { ++ time_t dqi_bgrace; /* Block grace time for given quotafile */ ++ time_t dqi_igrace; /* Inode grace time for given quotafile */ ++ union { ++ struct v2_mem_dqinfo v2_mdqi; ++ } u; /* Format specific info about quotafile */ ++}; ++ ++struct quota_file { ++ ext2_filsys fs; ++ ext2_ino_t ino; ++ ext2_file_t e2_file; ++}; ++ ++/* Structure for one opened quota file */ ++struct quota_handle { ++ int qh_type; /* Type of quotafile */ ++ int qh_fmt; /* Quotafile format */ ++ int qh_file_flags; ++ int qh_io_flags; /* IO flags for file */ ++ struct quota_file qh_qf; ++ unsigned int (*e2fs_read)(struct quota_file *qf, ext2_loff_t offset, ++ void *buf, unsigned int size); ++ unsigned int (*e2fs_write)(struct quota_file *qf, ext2_loff_t offset, ++ void *buf, unsigned int size); ++ struct quotafile_ops *qh_ops; /* Operations on quotafile */ ++ struct util_dqinfo qh_info; /* Generic quotafile info */ ++}; ++ ++/* Utility quota block */ ++struct util_dqblk { ++ qsize_t dqb_ihardlimit; ++ qsize_t dqb_isoftlimit; ++ qsize_t dqb_curinodes; ++ qsize_t dqb_bhardlimit; ++ qsize_t dqb_bsoftlimit; ++ qsize_t dqb_curspace; ++ time_t dqb_btime; ++ time_t dqb_itime; ++ union { ++ struct v2_mem_dqblk v2_mdqb; ++ } u; /* Format specific dquot information */ ++}; ++ ++/* Structure for one loaded quota */ ++struct dquot { ++ struct dquot *dq_next; /* Pointer to next dquot in the list */ ++ qid_t dq_id; /* ID dquot belongs to */ ++ int dq_flags; /* Some flags for utils */ ++ struct quota_handle *dq_h; /* Handle of quotafile for this dquot */ ++ struct util_dqblk dq_dqb; /* Parsed data of dquot */ ++}; ++ ++#define DQF_SEEN 0x0001 ++ ++/* Structure of quotafile operations */ ++struct quotafile_ops { ++ /* Check whether quotafile is in our format */ ++ int (*check_file) (struct quota_handle *h, int type, int fmt); ++ /* Open quotafile */ ++ int (*init_io) (struct quota_handle *h); ++ /* Create new quotafile */ ++ int (*new_io) (struct quota_handle *h); ++ /* Write all changes and close quotafile */ ++ int (*end_io) (struct quota_handle *h); ++ /* Write info about quotafile */ ++ int (*write_info) (struct quota_handle *h); ++ /* Read dquot into memory */ ++ struct dquot *(*read_dquot) (struct quota_handle *h, qid_t id); ++ /* Write given dquot to disk */ ++ int (*commit_dquot) (struct dquot *dquot); ++ /* Scan quotafile and call callback on every structure */ ++ int (*scan_dquots) (struct quota_handle *h, ++ int (*process_dquot) (struct dquot *dquot, ++ void *data), ++ void *data); ++ /* Function to print format specific file information */ ++ int (*report) (struct quota_handle *h, int verbose); ++}; ++ ++/* This might go into a special header file but that sounds a bit silly... */ ++extern struct quotafile_ops quotafile_ops_meta; ++ ++/* Open existing quotafile of given type (and verify its format) on given ++ * filesystem. */ ++errcode_t quota_file_open(quota_ctx_t qctx, struct quota_handle *h, ++ ext2_ino_t qf_ino, int type, int fmt, int flags); ++ ++ ++/* Create new quotafile of specified format on given filesystem */ ++errcode_t quota_file_create(struct quota_handle *h, ext2_filsys fs, ++ int type, int fmt); ++ ++/* Close quotafile */ ++errcode_t quota_file_close(quota_ctx_t qctx, struct quota_handle *h); ++ ++/* Get empty quota structure */ ++struct dquot *get_empty_dquot(void); ++ ++errcode_t quota_inode_truncate(ext2_filsys fs, ext2_ino_t ino); ++ ++const char *type2name(int type); ++ ++void update_grace_times(struct dquot *q); ++ ++/* size for the buffer returned by quota_get_qf_name(); must be greater ++ than maxlen of extensions[] and fmtnames[] (plus 2) found in quotaio.c */ ++#define QUOTA_NAME_LEN 16 ++ ++const char *quota_get_qf_name(int type, int fmt, char *buf); ++ ++/* In mkquota.c */ ++errcode_t quota_init_context(quota_ctx_t *qctx, ext2_filsys fs, int qtype); ++void quota_data_inodes(quota_ctx_t qctx, struct ext2_inode *inode, ext2_ino_t ino, ++ int adjust); ++void quota_data_add(quota_ctx_t qctx, struct ext2_inode *inode, ext2_ino_t ino, ++ qsize_t space); ++void quota_data_sub(quota_ctx_t qctx, struct ext2_inode *inode, ext2_ino_t ino, ++ qsize_t space); ++errcode_t quota_write_inode(quota_ctx_t qctx, int qtype); ++errcode_t quota_update_limits(quota_ctx_t qctx, ext2_ino_t qf_ino, int type); ++errcode_t quota_compute_usage(quota_ctx_t qctx); ++void quota_release_context(quota_ctx_t *qctx); ++ ++errcode_t quota_remove_inode(ext2_filsys fs, int qtype); ++int quota_file_exists(ext2_filsys fs, int qtype); ++void quota_set_sb_inum(ext2_filsys fs, ext2_ino_t ino, int qtype); ++errcode_t quota_compare_and_update(quota_ctx_t qctx, int qtype, ++ int *usage_inconsistent); ++ ++ ++ ++#endif /* GUARD_QUOTAIO_H */ +--- /dev/null ++++ b/lib/support/quotaio_tree.c +@@ -0,0 +1,662 @@ ++/* ++ * Implementation of new quotafile format ++ * ++ * Jan Kara - sponsored by SuSE CR ++ */ ++ ++#include "config.h" ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "common.h" ++#include "quotaio_tree.h" ++#include "quotaio.h" ++ ++typedef char *dqbuf_t; ++ ++#define freedqbuf(buf) ext2fs_free_mem(&buf) ++ ++static inline dqbuf_t getdqbuf(void) ++{ ++ dqbuf_t buf; ++ if (ext2fs_get_memzero(QT_BLKSIZE, &buf)) { ++ log_err("Failed to allocate dqbuf"); ++ return NULL; ++ } ++ ++ return buf; ++} ++ ++/* Is given dquot empty? */ ++int qtree_entry_unused(struct qtree_mem_dqinfo *info, char *disk) ++{ ++ int i; ++ ++ for (i = 0; i < info->dqi_entry_size; i++) ++ if (disk[i]) ++ return 0; ++ return 1; ++} ++ ++int qtree_dqstr_in_blk(struct qtree_mem_dqinfo *info) ++{ ++ return (QT_BLKSIZE - sizeof(struct qt_disk_dqdbheader)) / ++ info->dqi_entry_size; ++} ++ ++static int get_index(qid_t id, int depth) ++{ ++ return (id >> ((QT_TREEDEPTH - depth - 1) * 8)) & 0xff; ++} ++ ++static inline void mark_quotafile_info_dirty(struct quota_handle *h) ++{ ++ h->qh_io_flags |= IOFL_INFODIRTY; ++} ++ ++/* Read given block */ ++static void read_blk(struct quota_handle *h, unsigned int blk, dqbuf_t buf) ++{ ++ int err; ++ ++ err = h->e2fs_read(&h->qh_qf, blk << QT_BLKSIZE_BITS, buf, ++ QT_BLKSIZE); ++ if (err < 0) ++ log_err("Cannot read block %u: %s", blk, strerror(errno)); ++ else if (err != QT_BLKSIZE) ++ memset(buf + err, 0, QT_BLKSIZE - err); ++} ++ ++/* Write block */ ++static int write_blk(struct quota_handle *h, unsigned int blk, dqbuf_t buf) ++{ ++ int err; ++ ++ err = h->e2fs_write(&h->qh_qf, blk << QT_BLKSIZE_BITS, buf, ++ QT_BLKSIZE); ++ if (err < 0 && errno != ENOSPC) ++ log_err("Cannot write block (%u): %s", blk, strerror(errno)); ++ if (err != QT_BLKSIZE) ++ return -ENOSPC; ++ return 0; ++} ++ ++/* Get free block in file (either from free list or create new one) */ ++static int get_free_dqblk(struct quota_handle *h) ++{ ++ dqbuf_t buf = getdqbuf(); ++ struct qt_disk_dqdbheader *dh = (struct qt_disk_dqdbheader *)buf; ++ struct qtree_mem_dqinfo *info = &h->qh_info.u.v2_mdqi.dqi_qtree; ++ int blk; ++ ++ if (!buf) ++ return -ENOMEM; ++ ++ if (info->dqi_free_blk) { ++ blk = info->dqi_free_blk; ++ read_blk(h, blk, buf); ++ info->dqi_free_blk = ext2fs_le32_to_cpu(dh->dqdh_next_free); ++ } else { ++ memset(buf, 0, QT_BLKSIZE); ++ /* Assure block allocation... */ ++ if (write_blk(h, info->dqi_blocks, buf) < 0) { ++ freedqbuf(buf); ++ log_err("Cannot allocate new quota block " ++ "(out of disk space)."); ++ return -ENOSPC; ++ } ++ blk = info->dqi_blocks++; ++ } ++ mark_quotafile_info_dirty(h); ++ freedqbuf(buf); ++ return blk; ++} ++ ++/* Put given block to free list */ ++static void put_free_dqblk(struct quota_handle *h, dqbuf_t buf, ++ unsigned int blk) ++{ ++ struct qt_disk_dqdbheader *dh = (struct qt_disk_dqdbheader *)buf; ++ struct qtree_mem_dqinfo *info = &h->qh_info.u.v2_mdqi.dqi_qtree; ++ ++ dh->dqdh_next_free = ext2fs_cpu_to_le32(info->dqi_free_blk); ++ dh->dqdh_prev_free = ext2fs_cpu_to_le32(0); ++ dh->dqdh_entries = ext2fs_cpu_to_le16(0); ++ info->dqi_free_blk = blk; ++ mark_quotafile_info_dirty(h); ++ write_blk(h, blk, buf); ++} ++ ++/* Remove given block from the list of blocks with free entries */ ++static void remove_free_dqentry(struct quota_handle *h, dqbuf_t buf, ++ unsigned int blk) ++{ ++ dqbuf_t tmpbuf = getdqbuf(); ++ struct qt_disk_dqdbheader *dh = (struct qt_disk_dqdbheader *)buf; ++ unsigned int nextblk = ext2fs_le32_to_cpu(dh->dqdh_next_free), prevblk = ++ ++ ext2fs_le32_to_cpu(dh->dqdh_prev_free); ++ ++ if (!tmpbuf) ++ return; ++ ++ if (nextblk) { ++ read_blk(h, nextblk, tmpbuf); ++ ((struct qt_disk_dqdbheader *)tmpbuf)->dqdh_prev_free = ++ dh->dqdh_prev_free; ++ write_blk(h, nextblk, tmpbuf); ++ } ++ if (prevblk) { ++ read_blk(h, prevblk, tmpbuf); ++ ((struct qt_disk_dqdbheader *)tmpbuf)->dqdh_next_free = ++ dh->dqdh_next_free; ++ write_blk(h, prevblk, tmpbuf); ++ } else { ++ h->qh_info.u.v2_mdqi.dqi_qtree.dqi_free_entry = nextblk; ++ mark_quotafile_info_dirty(h); ++ } ++ freedqbuf(tmpbuf); ++ dh->dqdh_next_free = dh->dqdh_prev_free = ext2fs_cpu_to_le32(0); ++ write_blk(h, blk, buf); /* No matter whether write succeeds ++ * block is out of list */ ++} ++ ++/* Insert given block to the beginning of list with free entries */ ++static void insert_free_dqentry(struct quota_handle *h, dqbuf_t buf, ++ unsigned int blk) ++{ ++ dqbuf_t tmpbuf = getdqbuf(); ++ struct qt_disk_dqdbheader *dh = (struct qt_disk_dqdbheader *)buf; ++ struct qtree_mem_dqinfo *info = &h->qh_info.u.v2_mdqi.dqi_qtree; ++ ++ if (!tmpbuf) ++ return; ++ ++ dh->dqdh_next_free = ext2fs_cpu_to_le32(info->dqi_free_entry); ++ dh->dqdh_prev_free = ext2fs_cpu_to_le32(0); ++ write_blk(h, blk, buf); ++ if (info->dqi_free_entry) { ++ read_blk(h, info->dqi_free_entry, tmpbuf); ++ ((struct qt_disk_dqdbheader *)tmpbuf)->dqdh_prev_free = ++ ext2fs_cpu_to_le32(blk); ++ write_blk(h, info->dqi_free_entry, tmpbuf); ++ } ++ freedqbuf(tmpbuf); ++ info->dqi_free_entry = blk; ++ mark_quotafile_info_dirty(h); ++} ++ ++/* Find space for dquot */ ++static unsigned int find_free_dqentry(struct quota_handle *h, ++ struct dquot *dquot, int *err) ++{ ++ int blk, i; ++ struct qt_disk_dqdbheader *dh; ++ struct qtree_mem_dqinfo *info = &h->qh_info.u.v2_mdqi.dqi_qtree; ++ char *ddquot; ++ dqbuf_t buf; ++ ++ *err = 0; ++ buf = getdqbuf(); ++ if (!buf) { ++ *err = -ENOMEM; ++ return 0; ++ } ++ ++ dh = (struct qt_disk_dqdbheader *)buf; ++ if (info->dqi_free_entry) { ++ blk = info->dqi_free_entry; ++ read_blk(h, blk, buf); ++ } else { ++ blk = get_free_dqblk(h); ++ if (blk < 0) { ++ freedqbuf(buf); ++ *err = blk; ++ return 0; ++ } ++ memset(buf, 0, QT_BLKSIZE); ++ info->dqi_free_entry = blk; ++ mark_quotafile_info_dirty(h); ++ } ++ ++ /* Block will be full? */ ++ if (ext2fs_le16_to_cpu(dh->dqdh_entries) + 1 >= ++ qtree_dqstr_in_blk(info)) ++ remove_free_dqentry(h, buf, blk); ++ ++ dh->dqdh_entries = ++ ext2fs_cpu_to_le16(ext2fs_le16_to_cpu(dh->dqdh_entries) + 1); ++ /* Find free structure in block */ ++ ddquot = buf + sizeof(struct qt_disk_dqdbheader); ++ for (i = 0; ++ i < qtree_dqstr_in_blk(info) && !qtree_entry_unused(info, ddquot); ++ i++) ++ ddquot += info->dqi_entry_size; ++ ++ if (i == qtree_dqstr_in_blk(info)) ++ log_err("find_free_dqentry(): Data block full unexpectedly."); ++ ++ write_blk(h, blk, buf); ++ dquot->dq_dqb.u.v2_mdqb.dqb_off = ++ (blk << QT_BLKSIZE_BITS) + sizeof(struct qt_disk_dqdbheader) + ++ i * info->dqi_entry_size; ++ freedqbuf(buf); ++ return blk; ++} ++ ++/* Insert reference to structure into the trie */ ++static int do_insert_tree(struct quota_handle *h, struct dquot *dquot, ++ unsigned int * treeblk, int depth) ++{ ++ dqbuf_t buf; ++ int newson = 0, newact = 0; ++ __le32 *ref; ++ unsigned int newblk; ++ int ret = 0; ++ ++ log_debug("inserting in tree: treeblk=%u, depth=%d", *treeblk, depth); ++ buf = getdqbuf(); ++ if (!buf) ++ return -ENOMEM; ++ ++ if (!*treeblk) { ++ ret = get_free_dqblk(h); ++ if (ret < 0) ++ goto out_buf; ++ *treeblk = ret; ++ memset(buf, 0, QT_BLKSIZE); ++ newact = 1; ++ } else { ++ read_blk(h, *treeblk, buf); ++ } ++ ++ ref = (__le32 *) buf; ++ newblk = ext2fs_le32_to_cpu(ref[get_index(dquot->dq_id, depth)]); ++ if (!newblk) ++ newson = 1; ++ if (depth == QT_TREEDEPTH - 1) { ++ if (newblk) ++ log_err("Inserting already present quota entry " ++ "(block %u).", ++ ref[get_index(dquot->dq_id, depth)]); ++ newblk = find_free_dqentry(h, dquot, &ret); ++ } else { ++ ret = do_insert_tree(h, dquot, &newblk, depth + 1); ++ } ++ ++ if (newson && ret >= 0) { ++ ref[get_index(dquot->dq_id, depth)] = ++ ext2fs_cpu_to_le32(newblk); ++ write_blk(h, *treeblk, buf); ++ } else if (newact && ret < 0) { ++ put_free_dqblk(h, buf, *treeblk); ++ } ++ ++out_buf: ++ freedqbuf(buf); ++ return ret; ++} ++ ++/* Wrapper for inserting quota structure into tree */ ++static void dq_insert_tree(struct quota_handle *h, struct dquot *dquot) ++{ ++ unsigned int tmp = QT_TREEOFF; ++ ++ if (do_insert_tree(h, dquot, &tmp, 0) < 0) ++ log_err("Cannot write quota (id %u): %s", ++ (unsigned int) dquot->dq_id, strerror(errno)); ++} ++ ++/* Write dquot to file */ ++void qtree_write_dquot(struct dquot *dquot) ++{ ++ ssize_t ret; ++ char *ddquot; ++ struct quota_handle *h = dquot->dq_h; ++ struct qtree_mem_dqinfo *info = ++ &dquot->dq_h->qh_info.u.v2_mdqi.dqi_qtree; ++ log_debug("writing ddquot 1: off=%llu, info->dqi_entry_size=%u", ++ dquot->dq_dqb.u.v2_mdqb.dqb_off, ++ info->dqi_entry_size); ++ ret = ext2fs_get_mem(info->dqi_entry_size, &ddquot); ++ if (ret) { ++ errno = ENOMEM; ++ log_err("Quota write failed (id %u): %s", ++ (unsigned int)dquot->dq_id, strerror(errno)); ++ return; ++ } ++ memset(ddquot, 0, info->dqi_entry_size); ++ ++ if (!dquot->dq_dqb.u.v2_mdqb.dqb_off) ++ dq_insert_tree(dquot->dq_h, dquot); ++ info->dqi_ops->mem2disk_dqblk(ddquot, dquot); ++ log_debug("writing ddquot 2: off=%llu, info->dqi_entry_size=%u", ++ dquot->dq_dqb.u.v2_mdqb.dqb_off, ++ info->dqi_entry_size); ++ ret = h->e2fs_write(&h->qh_qf, dquot->dq_dqb.u.v2_mdqb.dqb_off, ddquot, ++ info->dqi_entry_size); ++ ++ if (ret != info->dqi_entry_size) { ++ if (ret > 0) ++ errno = ENOSPC; ++ log_err("Quota write failed (id %u): %s", ++ (unsigned int)dquot->dq_id, strerror(errno)); ++ } ++ ext2fs_free_mem(&ddquot); ++} ++ ++/* Free dquot entry in data block */ ++static void free_dqentry(struct quota_handle *h, struct dquot *dquot, ++ unsigned int blk) ++{ ++ struct qt_disk_dqdbheader *dh; ++ struct qtree_mem_dqinfo *info = &h->qh_info.u.v2_mdqi.dqi_qtree; ++ dqbuf_t buf = getdqbuf(); ++ ++ if (!buf) ++ return; ++ ++ if (dquot->dq_dqb.u.v2_mdqb.dqb_off >> QT_BLKSIZE_BITS != blk) ++ log_err("Quota structure has offset to other block (%u) " ++ "than it should (%u).", blk, ++ (unsigned int) (dquot->dq_dqb.u.v2_mdqb.dqb_off >> ++ QT_BLKSIZE_BITS)); ++ ++ read_blk(h, blk, buf); ++ dh = (struct qt_disk_dqdbheader *)buf; ++ dh->dqdh_entries = ++ ext2fs_cpu_to_le16(ext2fs_le16_to_cpu(dh->dqdh_entries) - 1); ++ ++ if (!ext2fs_le16_to_cpu(dh->dqdh_entries)) { /* Block got free? */ ++ remove_free_dqentry(h, buf, blk); ++ put_free_dqblk(h, buf, blk); ++ } else { ++ memset(buf + (dquot->dq_dqb.u.v2_mdqb.dqb_off & ++ ((1 << QT_BLKSIZE_BITS) - 1)), ++ 0, info->dqi_entry_size); ++ ++ /* First free entry? */ ++ if (ext2fs_le16_to_cpu(dh->dqdh_entries) == ++ qtree_dqstr_in_blk(info) - 1) ++ /* This will also write data block */ ++ insert_free_dqentry(h, buf, blk); ++ else ++ write_blk(h, blk, buf); ++ } ++ dquot->dq_dqb.u.v2_mdqb.dqb_off = 0; ++ freedqbuf(buf); ++} ++ ++/* Remove reference to dquot from tree */ ++static void remove_tree(struct quota_handle *h, struct dquot *dquot, ++ unsigned int * blk, int depth) ++{ ++ dqbuf_t buf = getdqbuf(); ++ unsigned int newblk; ++ __le32 *ref = (__le32 *) buf; ++ ++ if (!buf) ++ return; ++ ++ read_blk(h, *blk, buf); ++ newblk = ext2fs_le32_to_cpu(ref[get_index(dquot->dq_id, depth)]); ++ if (depth == QT_TREEDEPTH - 1) { ++ free_dqentry(h, dquot, newblk); ++ newblk = 0; ++ } else { ++ remove_tree(h, dquot, &newblk, depth + 1); ++ } ++ ++ if (!newblk) { ++ int i; ++ ++ ref[get_index(dquot->dq_id, depth)] = ext2fs_cpu_to_le32(0); ++ ++ /* Block got empty? */ ++ for (i = 0; i < QT_BLKSIZE && !buf[i]; i++); ++ ++ /* Don't put the root block into the free block list */ ++ if (i == QT_BLKSIZE && *blk != QT_TREEOFF) { ++ put_free_dqblk(h, buf, *blk); ++ *blk = 0; ++ } else { ++ write_blk(h, *blk, buf); ++ } ++ } ++ freedqbuf(buf); ++} ++ ++/* Delete dquot from tree */ ++void qtree_delete_dquot(struct dquot *dquot) ++{ ++ unsigned int tmp = QT_TREEOFF; ++ ++ if (!dquot->dq_dqb.u.v2_mdqb.dqb_off) /* Even not allocated? */ ++ return; ++ remove_tree(dquot->dq_h, dquot, &tmp, 0); ++} ++ ++/* Find entry in block */ ++static ext2_loff_t find_block_dqentry(struct quota_handle *h, ++ struct dquot *dquot, unsigned int blk) ++{ ++ struct qtree_mem_dqinfo *info = &h->qh_info.u.v2_mdqi.dqi_qtree; ++ dqbuf_t buf = getdqbuf(); ++ int i; ++ char *ddquot = buf + sizeof(struct qt_disk_dqdbheader); ++ ++ if (!buf) ++ return -ENOMEM; ++ ++ read_blk(h, blk, buf); ++ for (i = 0; ++ i < qtree_dqstr_in_blk(info) && !info->dqi_ops->is_id(ddquot, dquot); ++ i++) ++ ddquot += info->dqi_entry_size; ++ ++ if (i == qtree_dqstr_in_blk(info)) ++ log_err("Quota for id %u referenced but not present.", ++ dquot->dq_id); ++ freedqbuf(buf); ++ return (blk << QT_BLKSIZE_BITS) + sizeof(struct qt_disk_dqdbheader) + ++ i * info->dqi_entry_size; ++} ++ ++/* Find entry for given id in the tree */ ++static ext2_loff_t find_tree_dqentry(struct quota_handle *h, ++ struct dquot *dquot, ++ unsigned int blk, int depth) ++{ ++ dqbuf_t buf = getdqbuf(); ++ ext2_loff_t ret = 0; ++ __le32 *ref = (__le32 *) buf; ++ ++ if (!buf) ++ return -ENOMEM; ++ ++ read_blk(h, blk, buf); ++ ret = 0; ++ blk = ext2fs_le32_to_cpu(ref[get_index(dquot->dq_id, depth)]); ++ if (!blk) /* No reference? */ ++ goto out_buf; ++ if (depth < QT_TREEDEPTH - 1) ++ ret = find_tree_dqentry(h, dquot, blk, depth + 1); ++ else ++ ret = find_block_dqentry(h, dquot, blk); ++out_buf: ++ freedqbuf(buf); ++ return ret; ++} ++ ++/* Find entry for given id in the tree - wrapper function */ ++static inline ext2_loff_t find_dqentry(struct quota_handle *h, ++ struct dquot *dquot) ++{ ++ return find_tree_dqentry(h, dquot, QT_TREEOFF, 0); ++} ++ ++/* ++ * Read dquot from disk. ++ */ ++struct dquot *qtree_read_dquot(struct quota_handle *h, qid_t id) ++{ ++ struct qtree_mem_dqinfo *info = &h->qh_info.u.v2_mdqi.dqi_qtree; ++ ext2_loff_t offset; ++ ssize_t ret; ++ char *ddquot; ++ struct dquot *dquot = get_empty_dquot(); ++ ++ if (!dquot) ++ return NULL; ++ if (ext2fs_get_mem(info->dqi_entry_size, &ddquot)) { ++ ext2fs_free_mem(&dquot); ++ return NULL; ++ } ++ ++ dquot->dq_id = id; ++ dquot->dq_h = h; ++ dquot->dq_dqb.u.v2_mdqb.dqb_off = 0; ++ memset(&dquot->dq_dqb, 0, sizeof(struct util_dqblk)); ++ ++ offset = find_dqentry(h, dquot); ++ if (offset > 0) { ++ dquot->dq_dqb.u.v2_mdqb.dqb_off = offset; ++ ret = h->e2fs_read(&h->qh_qf, offset, ddquot, ++ info->dqi_entry_size); ++ if (ret != info->dqi_entry_size) { ++ if (ret > 0) ++ errno = EIO; ++ log_err("Cannot read quota structure for id %u: %s", ++ dquot->dq_id, strerror(errno)); ++ } ++ info->dqi_ops->disk2mem_dqblk(dquot, ddquot); ++ } ++ ext2fs_free_mem(&ddquot); ++ return dquot; ++} ++ ++/* ++ * Scan all dquots in file and call callback on each ++ */ ++#define set_bit(bmp, ind) ((bmp)[(ind) >> 3] |= (1 << ((ind) & 7))) ++#define get_bit(bmp, ind) ((bmp)[(ind) >> 3] & (1 << ((ind) & 7))) ++ ++static int report_block(struct dquot *dquot, unsigned int blk, char *bitmap, ++ int (*process_dquot) (struct dquot *, void *), ++ void *data) ++{ ++ struct qtree_mem_dqinfo *info = ++ &dquot->dq_h->qh_info.u.v2_mdqi.dqi_qtree; ++ dqbuf_t buf = getdqbuf(); ++ struct qt_disk_dqdbheader *dh; ++ char *ddata; ++ int entries, i; ++ ++ if (!buf) ++ return 0; ++ ++ set_bit(bitmap, blk); ++ read_blk(dquot->dq_h, blk, buf); ++ dh = (struct qt_disk_dqdbheader *)buf; ++ ddata = buf + sizeof(struct qt_disk_dqdbheader); ++ entries = ext2fs_le16_to_cpu(dh->dqdh_entries); ++ for (i = 0; i < qtree_dqstr_in_blk(info); ++ i++, ddata += info->dqi_entry_size) ++ if (!qtree_entry_unused(info, ddata)) { ++ dquot->dq_dqb.u.v2_mdqb.dqb_off = ++ (blk << QT_BLKSIZE_BITS) + ++ sizeof(struct qt_disk_dqdbheader) + ++ i * info->dqi_entry_size; ++ info->dqi_ops->disk2mem_dqblk(dquot, ddata); ++ if (process_dquot(dquot, data) < 0) ++ break; ++ } ++ freedqbuf(buf); ++ return entries; ++} ++ ++static void check_reference(struct quota_handle *h, unsigned int blk) ++{ ++ if (blk >= h->qh_info.u.v2_mdqi.dqi_qtree.dqi_blocks) ++ log_err("Illegal reference (%u >= %u) in %s quota file. " ++ "Quota file is probably corrupted.\n" ++ "Please run e2fsck (8) to fix it.", ++ blk, ++ h->qh_info.u.v2_mdqi.dqi_qtree.dqi_blocks, ++ type2name(h->qh_type)); ++} ++ ++static int report_tree(struct dquot *dquot, unsigned int blk, int depth, ++ char *bitmap, ++ int (*process_dquot) (struct dquot *, void *), ++ void *data) ++{ ++ int entries = 0, i; ++ dqbuf_t buf = getdqbuf(); ++ __le32 *ref = (__le32 *) buf; ++ ++ if (!buf) ++ return 0; ++ ++ read_blk(dquot->dq_h, blk, buf); ++ if (depth == QT_TREEDEPTH - 1) { ++ for (i = 0; i < QT_BLKSIZE >> 2; i++) { ++ blk = ext2fs_le32_to_cpu(ref[i]); ++ check_reference(dquot->dq_h, blk); ++ if (blk && !get_bit(bitmap, blk)) ++ entries += report_block(dquot, blk, bitmap, ++ process_dquot, data); ++ } ++ } else { ++ for (i = 0; i < QT_BLKSIZE >> 2; i++) { ++ blk = ext2fs_le32_to_cpu(ref[i]); ++ if (blk) { ++ check_reference(dquot->dq_h, blk); ++ entries += report_tree(dquot, blk, depth + 1, ++ bitmap, process_dquot, ++ data); ++ } ++ } ++ } ++ freedqbuf(buf); ++ return entries; ++} ++ ++static unsigned int find_set_bits(char *bmp, int blocks) ++{ ++ unsigned int i, used = 0; ++ ++ for (i = 0; i < blocks; i++) ++ if (get_bit(bmp, i)) ++ used++; ++ return used; ++} ++ ++int qtree_scan_dquots(struct quota_handle *h, ++ int (*process_dquot) (struct dquot *, void *), ++ void *data) ++{ ++ char *bitmap; ++ struct v2_mem_dqinfo *v2info = &h->qh_info.u.v2_mdqi; ++ struct qtree_mem_dqinfo *info = &v2info->dqi_qtree; ++ struct dquot *dquot = get_empty_dquot(); ++ ++ if (!dquot) ++ return -1; ++ ++ dquot->dq_h = h; ++ if (ext2fs_get_memzero((info->dqi_blocks + 7) >> 3, &bitmap)) { ++ ext2fs_free_mem(&dquot); ++ return -1; ++ } ++ v2info->dqi_used_entries = report_tree(dquot, QT_TREEOFF, 0, bitmap, ++ process_dquot, data); ++ v2info->dqi_data_blocks = find_set_bits(bitmap, info->dqi_blocks); ++ ext2fs_free_mem(&bitmap); ++ ext2fs_free_mem(&dquot); ++ return 0; ++} +--- /dev/null ++++ b/lib/support/quotaio_tree.h +@@ -0,0 +1,64 @@ ++/* ++ * Definitions of structures for vfsv0 quota format ++ */ ++ ++#ifndef _LINUX_QUOTA_TREE_H ++#define _LINUX_QUOTA_TREE_H ++ ++#include ++ ++typedef __u32 qid_t; /* Type in which we store ids in memory */ ++ ++#define QT_TREEOFF 1 /* Offset of tree in file in blocks */ ++#define QT_TREEDEPTH 4 /* Depth of quota tree */ ++#define QT_BLKSIZE_BITS 10 ++#define QT_BLKSIZE (1 << QT_BLKSIZE_BITS) /* Size of block with quota ++ * structures */ ++ ++/* ++ * Structure of header of block with quota structures. It is padded to 16 bytes ++ * so there will be space for exactly 21 quota-entries in a block ++ */ ++struct qt_disk_dqdbheader { ++ __le32 dqdh_next_free; /* Number of next block with free ++ * entry */ ++ __le32 dqdh_prev_free; /* Number of previous block with free ++ * entry */ ++ __le16 dqdh_entries; /* Number of valid entries in block */ ++ __le16 dqdh_pad1; ++ __le32 dqdh_pad2; ++} __attribute__ ((packed)); ++ ++struct dquot; ++struct quota_handle; ++ ++/* Operations */ ++struct qtree_fmt_operations { ++ /* Convert given entry from in memory format to disk one */ ++ void (*mem2disk_dqblk)(void *disk, struct dquot *dquot); ++ /* Convert given entry from disk format to in memory one */ ++ void (*disk2mem_dqblk)(struct dquot *dquot, void *disk); ++ /* Is this structure for given id? */ ++ int (*is_id)(void *disk, struct dquot *dquot); ++}; ++ ++/* Inmemory copy of version specific information */ ++struct qtree_mem_dqinfo { ++ unsigned int dqi_blocks; /* # of blocks in quota file */ ++ unsigned int dqi_free_blk; /* First block in list of free blocks */ ++ unsigned int dqi_free_entry; /* First block with free entry */ ++ unsigned int dqi_entry_size; /* Size of quota entry in quota file */ ++ struct qtree_fmt_operations *dqi_ops; /* Operations for entry ++ * manipulation */ ++}; ++ ++void qtree_write_dquot(struct dquot *dquot); ++struct dquot *qtree_read_dquot(struct quota_handle *h, qid_t id); ++void qtree_delete_dquot(struct dquot *dquot); ++int qtree_entry_unused(struct qtree_mem_dqinfo *info, char *disk); ++int qtree_scan_dquots(struct quota_handle *h, ++ int (*process_dquot) (struct dquot *, void *), void *data); ++ ++int qtree_dqstr_in_blk(struct qtree_mem_dqinfo *info); ++ ++#endif /* _LINUX_QUOTAIO_TREE_H */ +--- /dev/null ++++ b/lib/support/quotaio_v2.c +@@ -0,0 +1,285 @@ ++/* ++ * Implementation of new quotafile format ++ * ++ * Jan Kara - sponsored by SuSE CR ++ */ ++ ++#include "config.h" ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "common.h" ++#include "quotaio_v2.h" ++#include "dqblk_v2.h" ++#include "quotaio.h" ++#include "quotaio_tree.h" ++ ++static int v2_check_file(struct quota_handle *h, int type, int fmt); ++static int v2_init_io(struct quota_handle *h); ++static int v2_new_io(struct quota_handle *h); ++static int v2_write_info(struct quota_handle *h); ++static struct dquot *v2_read_dquot(struct quota_handle *h, qid_t id); ++static int v2_commit_dquot(struct dquot *dquot); ++static int v2_scan_dquots(struct quota_handle *h, ++ int (*process_dquot) (struct dquot *dquot, ++ void *data), ++ void *data); ++static int v2_report(struct quota_handle *h, int verbose); ++ ++struct quotafile_ops quotafile_ops_2 = { ++ .check_file = v2_check_file, ++ .init_io = v2_init_io, ++ .new_io = v2_new_io, ++ .write_info = v2_write_info, ++ .read_dquot = v2_read_dquot, ++ .commit_dquot = v2_commit_dquot, ++ .scan_dquots = v2_scan_dquots, ++ .report = v2_report, ++}; ++ ++/* ++ * Copy dquot from disk to memory ++ */ ++static void v2r1_disk2memdqblk(struct dquot *dquot, void *dp) ++{ ++ struct util_dqblk *m = &dquot->dq_dqb; ++ struct v2r1_disk_dqblk *d = dp, empty; ++ ++ dquot->dq_id = ext2fs_le32_to_cpu(d->dqb_id); ++ m->dqb_ihardlimit = ext2fs_le64_to_cpu(d->dqb_ihardlimit); ++ m->dqb_isoftlimit = ext2fs_le64_to_cpu(d->dqb_isoftlimit); ++ m->dqb_bhardlimit = ext2fs_le64_to_cpu(d->dqb_bhardlimit); ++ m->dqb_bsoftlimit = ext2fs_le64_to_cpu(d->dqb_bsoftlimit); ++ m->dqb_curinodes = ext2fs_le64_to_cpu(d->dqb_curinodes); ++ m->dqb_curspace = ext2fs_le64_to_cpu(d->dqb_curspace); ++ m->dqb_itime = ext2fs_le64_to_cpu(d->dqb_itime); ++ m->dqb_btime = ext2fs_le64_to_cpu(d->dqb_btime); ++ ++ memset(&empty, 0, sizeof(struct v2r1_disk_dqblk)); ++ empty.dqb_itime = ext2fs_cpu_to_le64(1); ++ if (!memcmp(&empty, dp, sizeof(struct v2r1_disk_dqblk))) ++ m->dqb_itime = 0; ++} ++ ++/* ++ * Copy dquot from memory to disk ++ */ ++static void v2r1_mem2diskdqblk(void *dp, struct dquot *dquot) ++{ ++ struct util_dqblk *m = &dquot->dq_dqb; ++ struct v2r1_disk_dqblk *d = dp; ++ ++ d->dqb_ihardlimit = ext2fs_cpu_to_le64(m->dqb_ihardlimit); ++ d->dqb_isoftlimit = ext2fs_cpu_to_le64(m->dqb_isoftlimit); ++ d->dqb_bhardlimit = ext2fs_cpu_to_le64(m->dqb_bhardlimit); ++ d->dqb_bsoftlimit = ext2fs_cpu_to_le64(m->dqb_bsoftlimit); ++ d->dqb_curinodes = ext2fs_cpu_to_le64(m->dqb_curinodes); ++ d->dqb_curspace = ext2fs_cpu_to_le64(m->dqb_curspace); ++ d->dqb_itime = ext2fs_cpu_to_le64(m->dqb_itime); ++ d->dqb_btime = ext2fs_cpu_to_le64(m->dqb_btime); ++ d->dqb_id = ext2fs_cpu_to_le32(dquot->dq_id); ++ if (qtree_entry_unused(&dquot->dq_h->qh_info.u.v2_mdqi.dqi_qtree, dp)) ++ d->dqb_itime = ext2fs_cpu_to_le64(1); ++} ++ ++static int v2r1_is_id(void *dp, struct dquot *dquot) ++{ ++ struct v2r1_disk_dqblk *d = dp; ++ struct qtree_mem_dqinfo *info = ++ &dquot->dq_h->qh_info.u.v2_mdqi.dqi_qtree; ++ ++ if (qtree_entry_unused(info, dp)) ++ return 0; ++ return ext2fs_le32_to_cpu(d->dqb_id) == dquot->dq_id; ++} ++ ++static struct qtree_fmt_operations v2r1_fmt_ops = { ++ .mem2disk_dqblk = v2r1_mem2diskdqblk, ++ .disk2mem_dqblk = v2r1_disk2memdqblk, ++ .is_id = v2r1_is_id, ++}; ++ ++/* ++ * Copy dqinfo from disk to memory ++ */ ++static inline void v2_disk2memdqinfo(struct util_dqinfo *m, ++ struct v2_disk_dqinfo *d) ++{ ++ m->dqi_bgrace = ext2fs_le32_to_cpu(d->dqi_bgrace); ++ m->dqi_igrace = ext2fs_le32_to_cpu(d->dqi_igrace); ++ m->u.v2_mdqi.dqi_flags = ext2fs_le32_to_cpu(d->dqi_flags) & V2_DQF_MASK; ++ m->u.v2_mdqi.dqi_qtree.dqi_blocks = ext2fs_le32_to_cpu(d->dqi_blocks); ++ m->u.v2_mdqi.dqi_qtree.dqi_free_blk = ++ ext2fs_le32_to_cpu(d->dqi_free_blk); ++ m->u.v2_mdqi.dqi_qtree.dqi_free_entry = ++ ext2fs_le32_to_cpu(d->dqi_free_entry); ++} ++ ++/* ++ * Copy dqinfo from memory to disk ++ */ ++static inline void v2_mem2diskdqinfo(struct v2_disk_dqinfo *d, ++ struct util_dqinfo *m) ++{ ++ d->dqi_bgrace = ext2fs_cpu_to_le32(m->dqi_bgrace); ++ d->dqi_igrace = ext2fs_cpu_to_le32(m->dqi_igrace); ++ d->dqi_flags = ext2fs_cpu_to_le32(m->u.v2_mdqi.dqi_flags & V2_DQF_MASK); ++ d->dqi_blocks = ext2fs_cpu_to_le32(m->u.v2_mdqi.dqi_qtree.dqi_blocks); ++ d->dqi_free_blk = ++ ext2fs_cpu_to_le32(m->u.v2_mdqi.dqi_qtree.dqi_free_blk); ++ d->dqi_free_entry = ++ ext2fs_cpu_to_le32(m->u.v2_mdqi.dqi_qtree.dqi_free_entry); ++} ++ ++static int v2_read_header(struct quota_handle *h, struct v2_disk_dqheader *dqh) ++{ ++ if (h->e2fs_read(&h->qh_qf, 0, dqh, sizeof(struct v2_disk_dqheader)) != ++ sizeof(struct v2_disk_dqheader)) ++ return 0; ++ ++ return 1; ++} ++ ++/* ++ * Check whether given quota file is in our format ++ */ ++static int v2_check_file(struct quota_handle *h, int type, int fmt) ++{ ++ struct v2_disk_dqheader dqh; ++ int file_magics[] = INITQMAGICS; ++ int be_magic; ++ ++ if (fmt != QFMT_VFS_V1) ++ return 0; ++ ++ if (!v2_read_header(h, &dqh)) ++ return 0; ++ ++ be_magic = ext2fs_be32_to_cpu((__force __be32)dqh.dqh_magic); ++ if (be_magic == file_magics[type]) { ++ log_err("Your quota file is stored in wrong endianity"); ++ return 0; ++ } ++ if (V2_VERSION != ext2fs_le32_to_cpu(dqh.dqh_version)) ++ return 0; ++ return 1; ++} ++ ++/* ++ * Open quotafile ++ */ ++static int v2_init_io(struct quota_handle *h) ++{ ++ struct v2_disk_dqinfo ddqinfo; ++ ++ h->qh_info.u.v2_mdqi.dqi_qtree.dqi_entry_size = ++ sizeof(struct v2r1_disk_dqblk); ++ h->qh_info.u.v2_mdqi.dqi_qtree.dqi_ops = &v2r1_fmt_ops; ++ ++ /* Read information about quotafile */ ++ if (h->e2fs_read(&h->qh_qf, V2_DQINFOOFF, &ddqinfo, ++ sizeof(ddqinfo)) != sizeof(ddqinfo)) ++ return -1; ++ v2_disk2memdqinfo(&h->qh_info, &ddqinfo); ++ return 0; ++} ++ ++/* ++ * Initialize new quotafile ++ */ ++static int v2_new_io(struct quota_handle *h) ++{ ++ int file_magics[] = INITQMAGICS; ++ struct v2_disk_dqheader ddqheader; ++ struct v2_disk_dqinfo ddqinfo; ++ ++ if (h->qh_fmt != QFMT_VFS_V1) ++ return -1; ++ ++ /* Write basic quota header */ ++ ddqheader.dqh_magic = ext2fs_cpu_to_le32(file_magics[h->qh_type]); ++ ddqheader.dqh_version = ext2fs_cpu_to_le32(V2_VERSION); ++ if (h->e2fs_write(&h->qh_qf, 0, &ddqheader, sizeof(ddqheader)) != ++ sizeof(ddqheader)) ++ return -1; ++ ++ /* Write information about quotafile */ ++ h->qh_info.dqi_bgrace = MAX_DQ_TIME; ++ h->qh_info.dqi_igrace = MAX_IQ_TIME; ++ h->qh_info.u.v2_mdqi.dqi_flags = 0; ++ h->qh_info.u.v2_mdqi.dqi_qtree.dqi_blocks = QT_TREEOFF + 1; ++ h->qh_info.u.v2_mdqi.dqi_qtree.dqi_free_blk = 0; ++ h->qh_info.u.v2_mdqi.dqi_qtree.dqi_free_entry = 0; ++ h->qh_info.u.v2_mdqi.dqi_qtree.dqi_entry_size = ++ sizeof(struct v2r1_disk_dqblk); ++ h->qh_info.u.v2_mdqi.dqi_qtree.dqi_ops = &v2r1_fmt_ops; ++ v2_mem2diskdqinfo(&ddqinfo, &h->qh_info); ++ if (h->e2fs_write(&h->qh_qf, V2_DQINFOOFF, &ddqinfo, ++ sizeof(ddqinfo)) != ++ sizeof(ddqinfo)) ++ return -1; ++ ++ return 0; ++} ++ ++/* ++ * Write information (grace times to file) ++ */ ++static int v2_write_info(struct quota_handle *h) ++{ ++ struct v2_disk_dqinfo ddqinfo; ++ ++ v2_mem2diskdqinfo(&ddqinfo, &h->qh_info); ++ if (h->e2fs_write(&h->qh_qf, V2_DQINFOOFF, &ddqinfo, sizeof(ddqinfo)) != ++ sizeof(ddqinfo)) ++ return -1; ++ ++ return 0; ++} ++ ++/* ++ * Read dquot from disk ++ */ ++static struct dquot *v2_read_dquot(struct quota_handle *h, qid_t id) ++{ ++ return qtree_read_dquot(h, id); ++} ++ ++/* ++ * Commit changes of dquot to disk - it might also mean deleting it when quota ++ * became fake one and user has no blocks. ++ * User can process use 'errno' to detect errstr. ++ */ ++static int v2_commit_dquot(struct dquot *dquot) ++{ ++ struct util_dqblk *b = &dquot->dq_dqb; ++ ++ if (!b->dqb_curspace && !b->dqb_curinodes && !b->dqb_bsoftlimit && ++ !b->dqb_isoftlimit && !b->dqb_bhardlimit && !b->dqb_ihardlimit) ++ qtree_delete_dquot(dquot); ++ else ++ qtree_write_dquot(dquot); ++ return 0; ++} ++ ++static int v2_scan_dquots(struct quota_handle *h, ++ int (*process_dquot) (struct dquot *, void *), ++ void *data) ++{ ++ return qtree_scan_dquots(h, process_dquot, data); ++} ++ ++/* Report information about quotafile. ++ * TODO: Not used right now, but we should be able to use this when we add ++ * support to debugfs to read quota files. ++ */ ++static int v2_report(struct quota_handle *h EXT2FS_ATTR((unused)), ++ int verbose EXT2FS_ATTR((unused))) ++{ ++ log_err("Not Implemented."); ++ return -1; ++} +--- /dev/null ++++ b/lib/support/quotaio_v2.h +@@ -0,0 +1,54 @@ ++/* ++ * ++ * Header file for disk format of new quotafile format ++ * ++ */ ++ ++#ifndef GUARD_QUOTAIO_V2_H ++#define GUARD_QUOTAIO_V2_H ++ ++#include ++#include "quotaio.h" ++ ++/* Offset of info header in file */ ++#define V2_DQINFOOFF sizeof(struct v2_disk_dqheader) ++/* Supported version of quota-tree format */ ++#define V2_VERSION 1 ++ ++struct v2_disk_dqheader { ++ __le32 dqh_magic; /* Magic number identifying file */ ++ __le32 dqh_version; /* File version */ ++} __attribute__ ((packed)); ++ ++/* Flags for version specific files */ ++#define V2_DQF_MASK 0x0000 /* Mask for all valid ondisk flags */ ++ ++/* Header with type and version specific information */ ++struct v2_disk_dqinfo { ++ __le32 dqi_bgrace; /* Time before block soft limit becomes ++ * hard limit */ ++ __le32 dqi_igrace; /* Time before inode soft limit becomes ++ * hard limit */ ++ __le32 dqi_flags; /* Flags for quotafile (DQF_*) */ ++ __le32 dqi_blocks; /* Number of blocks in file */ ++ __le32 dqi_free_blk; /* Number of first free block in the list */ ++ __le32 dqi_free_entry; /* Number of block with at least one ++ * free entry */ ++} __attribute__ ((packed)); ++ ++struct v2r1_disk_dqblk { ++ __le32 dqb_id; /* id this quota applies to */ ++ __le32 dqb_pad; ++ __le64 dqb_ihardlimit; /* absolute limit on allocated inodes */ ++ __le64 dqb_isoftlimit; /* preferred inode limit */ ++ __le64 dqb_curinodes; /* current # allocated inodes */ ++ __le64 dqb_bhardlimit; /* absolute limit on disk space ++ * (in QUOTABLOCK_SIZE) */ ++ __le64 dqb_bsoftlimit; /* preferred limit on disk space ++ * (in QUOTABLOCK_SIZE) */ ++ __le64 dqb_curspace; /* current space occupied (in bytes) */ ++ __le64 dqb_btime; /* time limit for excessive disk use */ ++ __le64 dqb_itime; /* time limit for excessive inode use */ ++} __attribute__ ((packed)); ++ ++#endif +--- /dev/null ++++ b/lib/uuid/Android.mk +@@ -0,0 +1,68 @@ ++LOCAL_PATH := $(call my-dir) ++ ++libext2_uuid_src_files := \ ++ clear.c \ ++ compare.c \ ++ copy.c \ ++ gen_uuid.c \ ++ isnull.c \ ++ pack.c \ ++ parse.c \ ++ unpack.c \ ++ unparse.c \ ++ uuid_time.c ++ ++ ++libext2_uuid_c_includes := external/e2fsprogs/lib ++ ++libext2_uuid_cflags := -O2 -g -W -Wall ++ ++libext2_uuid_system_shared_libraries := libc ++ ++include $(CLEAR_VARS) ++ ++LOCAL_SRC_FILES := $(libext2_uuid_src_files) ++LOCAL_C_INCLUDES := $(libext2_uuid_c_includes) ++LOCAL_CFLAGS := $(libext2_uuid_cflags) ++LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH) ++LOCAL_SYSTEM_SHARED_LIBRARIES := $(libext2_uuid_system_shared_libraries) ++LOCAL_MODULE := libext2_uuid ++LOCAL_MODULE_TAGS := optional ++ ++include $(BUILD_SHARED_LIBRARY) ++ ++include $(CLEAR_VARS) ++ ++LOCAL_SRC_FILES := $(libext2_uuid_src_files) ++LOCAL_C_INCLUDES := $(libext2_uuid_c_includes) ++LOCAL_CFLAGS := $(libext2_uuid_cflags) ++LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH) ++LOCAL_MODULE := libext2_uuid_host ++LOCAL_MODULE_TAGS := optional ++ ++include $(BUILD_HOST_SHARED_LIBRARY) ++ ++ ++include $(CLEAR_VARS) ++ ++LOCAL_SRC_FILES := $(libext2_uuid_src_files) ++LOCAL_C_INCLUDES := $(libext2_uuid_c_includes) ++LOCAL_CFLAGS := $(libext2_uuid_cflags) ++LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH) ++LOCAL_STATIC_LIBRARIES := libc ++LOCAL_MODULE := libext2_uuid_static ++LOCAL_MODULE_TAGS := optional ++ ++include $(BUILD_STATIC_LIBRARY) ++ ++ ++include $(CLEAR_VARS) ++ ++LOCAL_SRC_FILES := $(libext2_uuid_src_files) ++LOCAL_C_INCLUDES := $(libext2_uuid_c_includes) ++LOCAL_CFLAGS := $(libext2_uuid_cflags) ++LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH) ++LOCAL_MODULE := libext2_uuid_host ++LOCAL_MODULE_TAGS := optional ++ ++include $(BUILD_HOST_STATIC_LIBRARY) +--- a/lib/uuid/gen_uuid.c ++++ b/lib/uuid/gen_uuid.c +@@ -425,6 +425,7 @@ + return 0; + } + ++#if defined(USE_UUIDD) && defined(HAVE_SYS_UN_H) + static ssize_t read_all(int fd, char *buf, size_t count) + { + ssize_t ret; +@@ -475,8 +476,12 @@ + open("/dev/null", O_RDWR); + } + } ++#endif /* defined(USE_UUIDD) && defined(HAVE_SYS_UN_H) */ + +- ++#pragma GCC diagnostic push ++#if !defined(USE_UUIDD) || !defined(HAVE_SYS_UN_H) ++#pragma GCC diagnostic ignored "-Wunused-parameter" ++#endif + /* + * Try using the uuidd daemon to generate the UUID + * +@@ -559,6 +564,7 @@ + #endif + return -1; + } ++#pragma GCC diagnostic pop + + void uuid__generate_time(uuid_t out, int *num) + { +--- a/lib/uuid/Makefile.in ++++ b/lib/uuid/Makefile.in +@@ -62,6 +62,7 @@ + $(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 $< +@@ -166,8 +167,9 @@ + $(RM) -f $(DESTDIR)$(man3dir)/uuid_generate_random.3 $(DESTDIR)$(man3dir)/uuid_generate_time.3 + + clean:: +- $(RM) -f \#* *.s *.o *.a *~ *.bak core profiled/* uuid.h +- $(RM) -f ../libuuid.a ../libuuid_p.a tst_uuid uuid_time $(SMANPAGES) ++ $(RM) -f \#* *.s *.o *.a *~ *.bak core profiled/* uuid.h \ ++ ../libuuid.a ../libuuid_p.a tst_uuid uuid_time \ ++ uuid.pc uuid_types.h $(SMANPAGES) + + check:: tst_uuid + LD_LIBRARY_PATH=$(LIB) DYLD_LIBRARY_PATH=$(LIB) ./tst_uuid +--- a/Makefile.in ++++ b/Makefile.in +@@ -13,9 +13,9 @@ + @DEBUGFS_CMT@DEBUGFS_DIR= debugfs + @UUID_CMT@UUID_LIB_SUBDIR= lib/uuid + @BLKID_CMT@BLKID_LIB_SUBDIR= lib/blkid +-QUOTA_LIB_SUBDIR= lib/quota ++SUPPORT_LIB_SUBDIR= lib/support + +-LIB_SUBDIRS=lib/et lib/ss lib/e2p $(UUID_LIB_SUBDIR) $(BLKID_LIB_SUBDIR) $(QUOTA_LIB_SUBDIR) lib/ext2fs intl ++LIB_SUBDIRS=lib/et lib/ss lib/e2p $(UUID_LIB_SUBDIR) $(BLKID_LIB_SUBDIR) $(SUPPORT_LIB_SUBDIR) lib/ext2fs intl + PROG_SUBDIRS=e2fsck $(DEBUGFS_DIR) misc $(RESIZE_DIR) tests/progs po + SUBDIRS=util $(LIB_SUBDIRS) $(PROG_SUBDIRS) tests + +@@ -115,7 +115,8 @@ + $(RM) -f $(SUBS) + + distclean: distclean-doc distclean-recursive +- $(RM) -rf autom4te.cache e2fsprogs.spec ext2ed/Makefile po/stamp-po ++ $(RM) -rf autom4te.cache e2fsprogs.spec ext2ed/Makefile po/stamp-po \ ++ asm_types.h config.log public_config.h parse-types.log + $(MAKE) distclean-local + + realclean: realclean-recursive realclean-local +--- a/MCONFIG.in ++++ b/MCONFIG.in +@@ -53,23 +53,29 @@ + + @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@ +-CFLAGS = @CFLAGS@ @DEFS@ ++CFLAGS = @CFLAGS@ + CPPFLAGS = @INCLUDES@ +-ALL_CFLAGS = $(CPPFLAGS) $(CFLAGS) ++ALL_CFLAGS = $(CPPFLAGS) $(CFLAGS) @DEFS@ $(LOCAL_CFLAGS) + LDFLAGS = @LDFLAGS@ + ALL_LDFLAGS = $(LDFLAGS) @LDFLAG_DYNAMIC@ + LDFLAGS_STATIC = $(LDFLAGS) @LDFLAG_STATIC@ +@@ -108,14 +114,16 @@ + LIBE2P = $(LIB)/libe2p@LIB_EXT@ + LIBEXT2FS = $(LIB)/libext2fs@LIB_EXT@ + LIBUUID = @LIBUUID@ @SOCKET_LIB@ +-LIBQUOTA = @STATIC_LIBQUOTA@ ++LIBMAGIC = @MAGIC_LIB@ ++LIBFUSE = @FUSE_LIB@ ++LIBSUPPORT = $(LIB)/libsupport@STATIC_LIB_EXT@ + LIBBLKID = @LIBBLKID@ @PRIVATE_LIBS_CMT@ $(LIBUUID) + LIBINTL = @LIBINTL@ + SYSLIBS = @LIBS@ + DEPLIBSS = $(LIB)/libss@LIB_EXT@ + DEPLIBCOM_ERR = $(LIB)/libcom_err@LIB_EXT@ + DEPLIBUUID = @DEPLIBUUID@ +-DEPLIBQUOTA = @DEPSTATIC_LIBQUOTA@ ++DEPLIBSUPPORT = $(LIBSUPPORT) + DEPLIBBLKID = @DEPLIBBLKID@ @PRIVATE_LIBS_CMT@ $(DEPLIBUUID) + TESTENV = LD_LIBRARY_PATH="$(LIB):$${LD_LIBRARY_PATH}" DYLD_LIBRARY_PATH="$(LIB):$${DYLD_LIBRARY_PATH}" + +@@ -124,12 +132,12 @@ + STATIC_LIBE2P = $(LIB)/libe2p@STATIC_LIB_EXT@ + STATIC_LIBEXT2FS = $(LIB)/libext2fs@STATIC_LIB_EXT@ + STATIC_LIBUUID = @STATIC_LIBUUID@ @SOCKET_LIB@ +-STATIC_LIBQUOTA = @STATIC_LIBQUOTA@ ++STATIC_LIBSUPPORT = $(LIBSUPPORT) + STATIC_LIBBLKID = @STATIC_LIBBLKID@ $(STATIC_LIBUUID) + DEPSTATIC_LIBSS = $(LIB)/libss@STATIC_LIB_EXT@ + DEPSTATIC_LIBCOM_ERR = $(LIB)/libcom_err@STATIC_LIB_EXT@ + DEPSTATIC_LIBUUID = @DEPSTATIC_LIBUUID@ +-DEPSTATIC_LIBQUOTA = @DEPSTATIC_LIBQUOTA@ ++DEPSTATIC_LIBSUPPORT = $(DEPLIBSUPPORT) + DEPSTATIC_LIBBLKID = @DEPSTATIC_LIBBLKID@ $(DEPSTATIC_LIBUUID) + + PROFILED_LIBSS = $(LIB)/libss@PROFILED_LIB_EXT@ @DLOPEN_LIB@ +@@ -137,12 +145,12 @@ + PROFILED_LIBE2P = $(LIB)/libe2p@PROFILED_LIB_EXT@ + PROFILED_LIBEXT2FS = $(LIB)/libext2fs@PROFILED_LIB_EXT@ + PROFILED_LIBUUID = @PROFILED_LIBUUID@ @SOCKET_LIB@ +-PROFILED_LIBQUOTA = @PROFILED_LIBQUOTA@ ++PROFILED_LIBSUPPORT = $(LIB)/libsupport@PROFILED_LIB_EXT@ + PROFILED_LIBBLKID = @PROFILED_LIBBLKID@ $(PROFILED_LIBUUID) + DEPPROFILED_LIBSS = $(LIB)/libss@PROFILED_LIB_EXT@ + DEPPROFILED_LIBCOM_ERR = $(LIB)/libcom_err@PROFILED_LIB_EXT@ + DEPPROFILED_LIBUUID = @PROFILED_LIBUUID@ +-DEPPROFILED_LIBQUOTA = @PROFILED_LIBQUOTA@ ++DEPPROFILED_LIBSUPPORT = $(PROFILED_LIBSUPPORT) + DEPPROFILED_LIBBLKID = @PROFILED_LIBBLKID@ $(DEPPROFILED_LIBUUID) + + # +@@ -179,7 +187,7 @@ + # 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 \ +@@ -190,11 +198,18 @@ + -UENABLE_NLS + + gcc-wall-new: +- (make CFLAGS="@CFLAGS@ $(WFLAGS)" > /dev/null) 2>&1 | sed -f $(top_srcdir)/util/gcc-wall-cleanup ++ ($(MAKE) CFLAGS="$(ALL_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="$(ALL_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 +@@ -249,7 +264,7 @@ + $(DEP_MAKEFILE) $(top_builddir)/config.status + cd $(top_builddir); CONFIG_FILES=$(my_dir)/Makefile ./config.status + +-@MAINTAINER_CMT@$(top_srcdir)/configure: $(top_srcdir)/configure.in ++@MAINTAINER_CMT@$(top_srcdir)/configure: $(top_srcdir)/configure.ac + @MAINTAINER_CMT@ cd $(top_srcdir) && autoheader && autoconf + + coverage.txt: Makefile $(SRCS) +--- /dev/null ++++ b/misc/Android.mk +@@ -0,0 +1,375 @@ ++LOCAL_PATH := $(call my-dir) ++ ++######################################################################### ++# Build mke2fs ++mke2fs_src_files := \ ++ mke2fs.c \ ++ util.c \ ++ mk_hugefiles.c \ ++ default_profile.c \ ++ create_inode.c ++ ++mke2fs_c_includes := \ ++ external/e2fsprogs/lib \ ++ external/e2fsprogs/e2fsck ++ ++mke2fs_cflags := -O2 -g -W -Wall ++ ++mke2fs_shared_libraries := \ ++ libext2fs \ ++ libext2_blkid \ ++ libext2_uuid \ ++ libext2_quota \ ++ libext2_com_err \ ++ libext2_e2p ++ ++mke2fs_system_shared_libraries := libc ++ ++include $(CLEAR_VARS) ++ ++LOCAL_SRC_FILES := $(mke2fs_src_files) ++LOCAL_C_INCLUDES := $(mke2fs_c_includes) ++LOCAL_CFLAGS := $(mke2fs_cflags) ++LOCAL_SYSTEM_SHARED_LIBRARIES := $(mke2fs_system_shared_libraries) ++LOCAL_SHARED_LIBRARIES := $(mke2fs_shared_libraries) ++LOCAL_MODULE := mke2fs ++LOCAL_MODULE_TAGS := optional ++include $(BUILD_EXECUTABLE) ++ ++include $(CLEAR_VARS) ++ ++LOCAL_SRC_FILES := $(mke2fs_src_files) ++LOCAL_C_INCLUDES := $(mke2fs_c_includes) ++LOCAL_CFLAGS := $(mke2fs_cflags) ++LOCAL_SHARED_LIBRARIES := $(addsuffix _host, $(mke2fs_shared_libraries)) ++LOCAL_MODULE := mke2fs_host ++LOCAL_MODULE_STEM := mke2fs ++LOCAL_MODULE_TAGS := optional ++ ++include $(BUILD_HOST_EXECUTABLE) ++ ++########################################################################### ++# Build tune2fs ++# ++tune2fs_src_files := \ ++ tune2fs.c \ ++ util.c ++ ++tune2fs_c_includes := \ ++ external/e2fsprogs/lib \ ++ external/e2fsprogs/e2fsck ++ ++tune2fs_cflags := -O2 -g -W -Wall ++ ++tune2fs_shared_libraries := \ ++ libext2fs \ ++ libext2_com_err \ ++ libext2_blkid \ ++ libext2_quota \ ++ libext2_uuid \ ++ libext2_e2p ++ ++tune2fs_system_shared_libraries := libc ++ ++ ++tune2fs_static_libraries := \ ++ libext2_com_err \ ++ libext2_blkid \ ++ libext2_quota \ ++ libext2_uuid_static \ ++ libext2_e2p \ ++ libext2fs ++ ++tune2fs_system_static_libraries := libc ++ ++include $(CLEAR_VARS) ++ ++LOCAL_SRC_FILES := $(tune2fs_src_files) ++LOCAL_C_INCLUDES := $(tune2fs_c_includes) ++LOCAL_CFLAGS := $(tune2fs_cflags) ++LOCAL_SHARED_LIBRARIES := $(tune2fs_shared_libraries) ++LOCAL_SYSTEM_SHARED_LIBRARIES := $(tune2fs_system_shared_libraries) ++LOCAL_MODULE := tune2fs ++LOCAL_MODULE_TAGS := optional ++ ++include $(BUILD_EXECUTABLE) ++ ++include $(CLEAR_VARS) ++ ++LOCAL_SRC_FILES := $(tune2fs_src_files) ++LOCAL_C_INCLUDES := $(tune2fs_c_includes) ++LOCAL_CFLAGS := $(tune2fs_cflags) ++LOCAL_STATIC_LIBRARIES := $(tune2fs_static_libraries) $(tune2fs_system_static_libraries) ++LOCAL_FORCE_STATIC_EXECUTABLE := true ++LOCAL_MODULE := tune2fs_static ++LOCAL_MODULE_TAGS := optional ++ ++include $(BUILD_EXECUTABLE) ++ ++include $(CLEAR_VARS) ++ ++LOCAL_SRC_FILES := $(tune2fs_src_files) ++LOCAL_C_INCLUDES := $(tune2fs_c_includes) ++LOCAL_CFLAGS := $(tune2fs_cflags) -DBUILD_AS_LIB ++LOCAL_STATIC_LIBRARIES := $(tune2fs_static_libraries) $(tune2fs_system_static_libraries) ++LOCAL_MODULE := libtune2fs ++LOCAL_MODULE_TAGS := optional ++ ++include $(BUILD_STATIC_LIBRARY) ++ ++include $(CLEAR_VARS) ++ ++LOCAL_SRC_FILES := $(tune2fs_src_files) ++LOCAL_C_INCLUDES := $(tune2fs_c_includes) ++LOCAL_CFLAGS := $(tune2fs_cflags) ++LOCAL_SHARED_LIBRARIES := $(addsuffix _host, $(tune2fs_shared_libraries)) ++LOCAL_MODULE := tune2fs_host ++LOCAL_MODULE_STEM := tune2fs ++LOCAL_MODULE_TAGS := optional ++ ++include $(BUILD_HOST_EXECUTABLE) ++ ++######################################################################### ++# Build badblocks ++# ++include $(CLEAR_VARS) ++ ++badblocks_src_files := \ ++ badblocks.c ++ ++badblocks_c_includes := \ ++ external/e2fsprogs/lib ++ ++badblocks_cflags := -O2 -g -W -Wall ++ ++badblocks_shared_libraries := \ ++ libext2fs \ ++ libext2_com_err \ ++ libext2_uuid \ ++ libext2_blkid \ ++ libext2_e2p ++ ++badblocks_system_shared_libraries := libc ++ ++include $(CLEAR_VARS) ++ ++LOCAL_SRC_FILES := $(badblocks_src_files) ++LOCAL_C_INCLUDES := $(badblocks_c_includes) ++LOCAL_CFLAGS := $(badblocks_cflags) ++LOCAL_SHARED_LIBRARIES := $(badblocks_shared_libraries) ++LOCAL_SYSTEM_SHARED_LIBRARIES := $(badblocks_system_shared_libraries) ++LOCAL_MODULE := badblocks ++LOCAL_MODULE_TAGS := optional ++ ++include $(BUILD_EXECUTABLE) ++ ++include $(CLEAR_VARS) ++ ++LOCAL_SRC_FILES := $(badblocks_src_files) ++LOCAL_C_INCLUDES := $(badblocks_c_includes) ++LOCAL_CFLAGS := $(badblocks_cflags) ++LOCAL_SHARED_LIBRARIES := $(addsuffix _host, $(badblocks_shared_libraries)) ++LOCAL_MODULE := badblocks_host ++LOCAL_MODULE_STEM := badblocks ++LOCAL_MODULE_TAGS := optional ++ ++include $(BUILD_HOST_EXECUTABLE) ++ ++######################################################################### ++# Build chattr ++# ++include $(CLEAR_VARS) ++ ++chattr_src_files := \ ++ chattr.c ++ ++chattr_c_includes := \ ++ external/e2fsprogs/lib ++ ++chattr_cflags := -O2 -g -W -Wall ++ ++chattr_shared_libraries := \ ++ libext2_com_err \ ++ libext2_e2p ++ ++chattr_system_shared_libraries := libc ++ ++include $(CLEAR_VARS) ++ ++LOCAL_SRC_FILES := $(chattr_src_files) ++LOCAL_C_INCLUDES := $(chattr_c_includes) ++LOCAL_CFLAGS := $(chattr_cflags) ++LOCAL_SHARED_LIBRARIES := $(chattr_shared_libraries) ++LOCAL_SYSTEM_SHARED_LIBRARIES := $(chattr_system_shared_libraries) ++LOCAL_MODULE := chattr ++LOCAL_MODULE_TAGS := optional ++ ++include $(BUILD_EXECUTABLE) ++ ++include $(CLEAR_VARS) ++ ++LOCAL_SRC_FILES := $(chattr_src_files) ++LOCAL_C_INCLUDES := $(chattr_c_includes) ++LOCAL_CFLAGS := $(chattr_cflags) ++LOCAL_SHARED_LIBRARIES := $(addsuffix _host, $(chattr_shared_libraries)) ++LOCAL_MODULE := chattr_host ++LOCAL_MODULE_STEM := chattr ++LOCAL_MODULE_TAGS := optional ++ ++include $(BUILD_HOST_EXECUTABLE) ++ ++######################################################################### ++# Build lsattr ++# ++include $(CLEAR_VARS) ++ ++lsattr_src_files := \ ++ lsattr.c ++ ++lsattr_c_includes := \ ++ external/e2fsprogs/lib ++ ++lsattr_cflags := -O2 -g -W -Wall ++ ++lsattr_shared_libraries := \ ++ libext2_com_err \ ++ libext2_e2p ++ ++lsattr_system_shared_libraries := libc ++ ++include $(CLEAR_VARS) ++ ++LOCAL_SRC_FILES := $(lsattr_src_files) ++LOCAL_C_INCLUDES := $(lsattr_c_includes) ++LOCAL_CFLAGS := $(lsattr_cflags) ++LOCAL_SHARED_LIBRARIES := $(lsattr_shared_libraries) ++LOCAL_SYSTEM_SHARED_LIBRARIES := $(lsattr_system_shared_libraries) ++LOCAL_MODULE := lsattr ++LOCAL_MODULE_TAGS := optional ++ ++include $(BUILD_EXECUTABLE) ++ ++include $(CLEAR_VARS) ++ ++LOCAL_SRC_FILES := $(lsattr_src_files) ++LOCAL_C_INCLUDES := $(lsattr_c_includes) ++LOCAL_CFLAGS := $(lsattr_cflags) ++LOCAL_SHARED_LIBRARIES := $(addsuffix _host, $(lsattr_shared_libraries)) ++LOCAL_MODULE := lsattr_host ++LOCAL_MODULE_STEM := lsattr ++LOCAL_MODULE_TAGS := optional ++ ++include $(BUILD_HOST_EXECUTABLE) ++ ++######################################################################### ++# Build blkid ++# ++include $(CLEAR_VARS) ++ ++blkid_src_files := \ ++ blkid.c ++ ++blkid_c_includes := \ ++ external/e2fsprogs/lib ++ ++blkid_cflags := -O2 -g -W -Wall ++ ++blkid_shared_libraries := \ ++ libext2fs \ ++ libext2_blkid \ ++ libext2_com_err \ ++ libext2_e2p ++ ++blkid_system_shared_libraries := libc ++ ++include $(CLEAR_VARS) ++ ++LOCAL_SRC_FILES := $(blkid_src_files) ++LOCAL_C_INCLUDES := $(blkid_c_includes) ++LOCAL_CFLAGS := $(blkid_cflags) ++LOCAL_SHARED_LIBRARIES := $(blkid_shared_libraries) ++LOCAL_SYSTEM_SHARED_LIBRARIES := $(blkid_system_shared_libraries) ++LOCAL_MODULE := blkid ++LOCAL_MODULE_TAGS := optional ++ ++include $(BUILD_EXECUTABLE) ++ ++######################################################################### ++# Build e4crypt ++e4crypt_src_files := e4crypt.c ++ ++e4crypt_c_includes := \ ++ external/e2fsprogs/lib ++ ++e4crypt_cflags := -O2 -g -W -Wall ++ ++e4crypt_shared_libraries := libext2fs libext2_uuid ++ ++e4crypt_system_shared_libraries := libc ++ ++include $(CLEAR_VARS) ++ ++LOCAL_SRC_FILES := $(e4crypt_src_files) ++LOCAL_C_INCLUDES := $(e4crypt_c_includes) ++LOCAL_CFLAGS := $(e4crypt_cflags) ++LOCAL_SYSTEM_SHARED_LIBRARIES := $(e4crypt_system_shared_libraries) ++LOCAL_SHARED_LIBRARIES := $(e4crypt_shared_libraries) ++LOCAL_MODULE := e4crypt ++LOCAL_MODULE_TAGS := optional ++include $(BUILD_EXECUTABLE) ++ ++include $(CLEAR_VARS) ++ ++LOCAL_SRC_FILES := $(e4crypt_src_files) ++LOCAL_C_INCLUDES := $(e4crypt_c_includes) ++LOCAL_CFLAGS := $(e4crypt_cflags) ++LOCAL_SHARED_LIBRARIES := $(addsuffix _host, $(e4crypt_shared_libraries)) ++LOCAL_MODULE := e4crypt_host ++LOCAL_MODULE_STEM := e4crypt ++LOCAL_MODULE_TAGS := optional ++ ++include $(BUILD_HOST_EXECUTABLE) ++ ++########################################################################### ++# Build e2image ++# ++e2image_src_files := \ ++ e2image.c ++ ++e2image_c_includes := \ ++ external/e2fsprogs/lib ++ ++e2image_cflags := -O2 -g -W -Wall ++ ++e2image_shared_libraries := \ ++ libext2fs \ ++ libext2_blkid \ ++ libext2_com_err \ ++ libext2_quota ++ ++e2image_system_shared_libraries := libc ++ ++include $(CLEAR_VARS) ++ ++LOCAL_SRC_FILES := $(e2image_src_files) ++LOCAL_C_INCLUDES := $(e2image_c_includes) ++mke2fs_c_includesLOCAL_CFLAGS := $(e2image_cflags) ++LOCAL_SHARED_LIBRARIES := $(e2image_shared_libraries) ++LOCAL_SYSTEM_SHARED_LIBRARIES := $(e2image_system_shared_libraries) ++LOCAL_MODULE := e2image ++LOCAL_MODULE_TAGS := optional ++ ++include $(BUILD_EXECUTABLE) ++ ++include $(CLEAR_VARS) ++ ++LOCAL_SRC_FILES := $(e2image_src_files) ++LOCAL_C_INCLUDES := $(e2image_c_includes) ++LOCAL_CFLAGS := $(e2image_cflags) ++LOCAL_SHARED_LIBRARIES := $(addsuffix _host, $(e2image_shared_libraries)) ++LOCAL_MODULE := e2image_host ++LOCAL_MODULE_STEM := e2image ++LOCAL_MODULE_TAGS := optional ++ ++include $(BUILD_HOST_EXECUTABLE) ++ +--- a/misc/badblocks.c ++++ b/misc/badblocks.c +@@ -59,7 +59,7 @@ + #include "ext2fs/ext2_io.h" + #include "ext2fs/ext2_fs.h" + #include "ext2fs/ext2fs.h" +-#include "nls-enable.h" ++#include "support/nls-enable.h" + + #ifndef O_LARGEFILE + #define O_LARGEFILE 0 +--- a/misc/chattr.1.in ++++ b/misc/chattr.1.in +@@ -107,8 +107,8 @@ + the blocks on disk. It may not be removed using + .BR chattr (1). + .PP +-The 'E' attribute is used by the experimental compression patches to +-indicate that a compressed file has a compression error. It may not be ++The 'E' attribute is used by the experimental encryption patches to ++indicate that the file has been encrypted. It may not be + set or reset using + .BR chattr (1), + although it can be displayed by +--- a/misc/chattr.c ++++ b/misc/chattr.c +@@ -51,9 +51,9 @@ + + #include "et/com_err.h" + #include "e2p/e2p.h" ++#include "support/nls-enable.h" + + #include "../version.h" +-#include "nls-enable.h" + + static const char * program_name = "chattr"; + +--- /dev/null ++++ b/misc/create_inode.c +@@ -0,0 +1,899 @@ ++/* ++ * create_inode.c --- create an inode ++ * ++ * Copyright (C) 2014 Robert Yang ++ * ++ * %Begin-Header% ++ * This file may be redistributed under the terms of the GNU library ++ * General Public License, version 2. ++ * %End-Header% ++ */ ++ ++#define _FILE_OFFSET_BITS 64 ++#define _LARGEFILE64_SOURCE 1 ++#define _GNU_SOURCE 1 ++ ++#include "config.h" ++#include ++#include ++#include ++#include /* for PATH_MAX */ ++#ifdef HAVE_ATTR_XATTR_H ++#include ++#endif ++#include ++#include ++#include ++#include ++ ++#include "create_inode.h" ++#include "support/nls-enable.h" ++ ++/* 64KiB is the minimium blksize to best minimize system call overhead. */ ++#define COPY_FILE_BUFLEN 65536 ++ ++static int ext2_file_type(unsigned int mode) ++{ ++ if (LINUX_S_ISREG(mode)) ++ return EXT2_FT_REG_FILE; ++ ++ if (LINUX_S_ISDIR(mode)) ++ return EXT2_FT_DIR; ++ ++ if (LINUX_S_ISCHR(mode)) ++ return EXT2_FT_CHRDEV; ++ ++ if (LINUX_S_ISBLK(mode)) ++ return EXT2_FT_BLKDEV; ++ ++ if (LINUX_S_ISLNK(mode)) ++ return EXT2_FT_SYMLINK; ++ ++ if (LINUX_S_ISFIFO(mode)) ++ return EXT2_FT_FIFO; ++ ++ if (LINUX_S_ISSOCK(mode)) ++ return EXT2_FT_SOCK; ++ ++ return 0; ++} ++ ++/* 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, ++ ext2_file_type(inode.i_mode)); ++ 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, ++ ext2_file_type(inode.i_mode)); ++ } ++ 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; ++} ++ ++/* Set the uid, gid, mode and time for the inode */ ++static errcode_t set_inode_extra(ext2_filsys fs, 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; ++ } ++ ++ 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; ++ ++ retval = ext2fs_write_inode(fs, ino, &inode); ++ if (retval) ++ com_err(__func__, retval, _("while writing inode %u"), ino); ++ return retval; ++} ++ ++#ifdef HAVE_LLISTXATTR ++static errcode_t set_inode_xattr(ext2_filsys fs, ext2_ino_t ino, ++ const char *filename) ++{ ++ errcode_t retval, close_retval; ++ struct ext2_xattr_handle *handle; ++ ssize_t size, value_size; ++ char *list = NULL; ++ int i; ++ ++ size = llistxattr(filename, NULL, 0); ++ if (size == -1) { ++ retval = errno; ++ com_err(__func__, retval, _("while listing attributes of \"%s\""), ++ filename); ++ return retval; ++ } 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, _("while allocating memory")); ++ goto out; ++ } ++ ++ size = llistxattr(filename, list, size); ++ if (size == -1) { ++ retval = errno; ++ com_err(__func__, retval, _("while listing attributes of \"%s\""), ++ filename); ++ goto out; ++ } ++ ++ for (i = 0; i < size; i += strlen(&list[i]) + 1) { ++ const char *name = &list[i]; ++ char *value; ++ ++ value_size = lgetxattr(filename, name, NULL, 0); ++ if (value_size == -1) { ++ retval = errno; ++ com_err(__func__, retval, ++ _("while reading attribute \"%s\" of \"%s\""), ++ name, filename); ++ break; ++ } ++ ++ retval = ext2fs_get_mem(value_size, &value); ++ if (retval) { ++ com_err(__func__, retval, _("while allocating memory")); ++ break; ++ } ++ ++ value_size = lgetxattr(filename, name, value, value_size); ++ if (value_size == -1) { ++ ext2fs_free_mem(&value); ++ retval = errno; ++ com_err(__func__, retval, ++ _("while reading attribute \"%s\" of \"%s\""), ++ name, filename); ++ break; ++ } ++ ++ retval = ext2fs_xattr_set(handle, name, value, value_size); ++ ext2fs_free_mem(&value); ++ if (retval) { ++ com_err(__func__, retval, ++ _("while writing attribute \"%s\" to inode %u"), ++ name, 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; ++ return 0; ++} ++#else /* HAVE_LLISTXATTR */ ++static errcode_t set_inode_xattr(ext2_filsys fs EXT2FS_ATTR((unused)), ++ ext2_ino_t ino EXT2FS_ATTR((unused)), ++ const char *filename EXT2FS_ATTR((unused))) ++{ ++ 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; ++ } ++ ++ retval = ext2fs_new_inode(fs, cwd, 010755, 0, &ino); ++ if (retval) { ++ com_err(__func__, retval, _("while allocating inode \"%s\""), ++ name); ++ 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, _("while creating inode \"%s\""), name); ++ 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 writing 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; ++ ++ 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; ++ ++ 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; ++ } ++ retval = ext2fs_symlink(fs, parent_ino, 0, name, target); ++ } ++ if (retval) ++ com_err("ext2fs_symlink", retval, ++ _("while creating symlink \"%s\""), name); ++ return retval; ++} ++ ++/* Make a directory in the fs */ ++errcode_t do_mkdir_internal(ext2_filsys fs, ext2_ino_t cwd, const char *name, ++ ext2_ino_t root) ++{ ++ char *cp; ++ ext2_ino_t parent_ino; ++ errcode_t retval; ++ ++ ++ cp = strrchr(name, '/'); ++ if (cp) { ++ *cp = 0; ++ retval = ext2fs_namei(fs, root, cwd, name, &parent_ino); ++ if (retval) { ++ com_err(name, retval, _("while looking up \"%s\""), ++ name); ++ return retval; ++ } ++ name = cp+1; ++ } else ++ parent_ino = cwd; ++ ++ 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; ++ } ++ retval = ext2fs_mkdir(fs, parent_ino, 0, name); ++ } ++ if (retval) ++ com_err("ext2fs_mkdir", retval, ++ _("while creating directory \"%s\""), name); ++ return retval; ++} ++ ++#if !defined HAVE_PREAD64 && !defined HAVE_PREAD ++static ssize_t my_pread(int fd, void *buf, size_t count, off_t offset) ++{ ++ if (lseek(fd, offset, SEEK_SET) < 0) ++ return 0; ++ ++ return read(fd, buf, count); ++} ++#endif /* !defined HAVE_PREAD64 && !defined HAVE_PREAD */ ++ ++static errcode_t copy_file_range(ext2_filsys fs, int fd, ext2_file_t e2_file, ++ off_t start, off_t end, char *buf, ++ char *zerobuf) ++{ ++ off_t off, bpos; ++ ssize_t got, blen; ++ unsigned int written; ++ char *ptr; ++ errcode_t err = 0; ++ ++ for (off = start; off < end; off += COPY_FILE_BUFLEN) { ++#ifdef HAVE_PREAD64 ++ got = pread64(fd, buf, COPY_FILE_BUFLEN, off); ++#elif HAVE_PREAD ++ got = pread(fd, buf, COPY_FILE_BUFLEN, off); ++#else ++ got = my_pread(fd, buf, COPY_FILE_BUFLEN, off); ++#endif ++ if (got < 0) { ++ err = errno; ++ goto fail; ++ } ++ for (bpos = 0, ptr = buf; bpos < got; bpos += fs->blocksize) { ++ blen = fs->blocksize; ++ if (blen > got - bpos) ++ blen = got - bpos; ++ if (memcmp(ptr, zerobuf, blen) == 0) { ++ ptr += blen; ++ continue; ++ } ++ err = ext2fs_file_lseek(e2_file, off + bpos, ++ EXT2_SEEK_SET, NULL); ++ if (err) ++ goto fail; ++ while (blen > 0) { ++ err = ext2fs_file_write(e2_file, ptr, blen, ++ &written); ++ if (err) ++ goto fail; ++ if (written == 0) { ++ err = EIO; ++ goto fail; ++ } ++ blen -= written; ++ ptr += written; ++ } ++ } ++ } ++fail: ++ return err; ++} ++ ++static errcode_t try_lseek_copy(ext2_filsys fs, int fd, struct stat *statbuf, ++ ext2_file_t e2_file, char *buf, char *zerobuf) ++{ ++#if defined(SEEK_DATA) && defined(SEEK_HOLE) ++ off_t data = 0, hole; ++ off_t data_blk, hole_blk; ++ errcode_t err; ++ ++ /* Try to use SEEK_DATA and SEEK_HOLE */ ++ while (data < statbuf->st_size) { ++ data = lseek(fd, data, SEEK_DATA); ++ if (data < 0) { ++ if (errno == ENXIO) ++ break; ++ return EXT2_ET_UNIMPLEMENTED; ++ } ++ hole = lseek(fd, data, SEEK_HOLE); ++ if (hole < 0) ++ return EXT2_ET_UNIMPLEMENTED; ++ ++ data_blk = data & ~(fs->blocksize - 1); ++ hole_blk = (hole + (fs->blocksize - 1)) & ~(fs->blocksize - 1); ++ err = copy_file_range(fs, fd, e2_file, data_blk, hole_blk, buf, ++ zerobuf); ++ if (err) ++ return err; ++ ++ data = hole; ++ } ++ ++ return err; ++#else ++ return EXT2_ET_UNIMPLEMENTED; ++#endif /* SEEK_DATA and SEEK_HOLE */ ++} ++ ++static errcode_t try_fiemap_copy(ext2_filsys fs, int fd, ext2_file_t e2_file, ++ char *buf, char *zerobuf) ++{ ++#if defined(FS_IOC_FIEMAP) ++#define EXTENT_MAX_COUNT 512 ++ struct fiemap *fiemap_buf; ++ struct fiemap_extent *ext_buf, *ext; ++ int ext_buf_size, fie_buf_size; ++ off_t pos = 0; ++ unsigned int i; ++ errcode_t err; ++ ++ ext_buf_size = EXTENT_MAX_COUNT * sizeof(struct fiemap_extent); ++ fie_buf_size = sizeof(struct fiemap) + ext_buf_size; ++ ++ err = ext2fs_get_memzero(fie_buf_size, &fiemap_buf); ++ if (err) ++ return err; ++ ++ ext_buf = fiemap_buf->fm_extents; ++ memset(fiemap_buf, 0, fie_buf_size); ++ fiemap_buf->fm_length = FIEMAP_MAX_OFFSET; ++ fiemap_buf->fm_flags |= FIEMAP_FLAG_SYNC; ++ fiemap_buf->fm_extent_count = EXTENT_MAX_COUNT; ++ ++ do { ++ fiemap_buf->fm_start = pos; ++ memset(ext_buf, 0, ext_buf_size); ++ err = ioctl(fd, FS_IOC_FIEMAP, fiemap_buf); ++ if (err < 0 && (errno == EOPNOTSUPP || errno == ENOTTY)) { ++ err = EXT2_ET_UNIMPLEMENTED; ++ goto out; ++ } else if (err < 0 || fiemap_buf->fm_mapped_extents == 0) { ++ err = errno; ++ goto out; ++ } ++ for (i = 0, ext = ext_buf; i < fiemap_buf->fm_mapped_extents; ++ i++, ext++) { ++ err = copy_file_range(fs, fd, e2_file, ext->fe_logical, ++ ext->fe_logical + ext->fe_length, ++ buf, zerobuf); ++ if (err) ++ goto out; ++ } ++ ++ ext--; ++ /* Record file's logical offset this time */ ++ pos = ext->fe_logical + ext->fe_length; ++ /* ++ * If fm_extents array has been filled and ++ * there are extents left, continue to cycle. ++ */ ++ } while (fiemap_buf->fm_mapped_extents == EXTENT_MAX_COUNT && ++ !(ext->fe_flags & FIEMAP_EXTENT_LAST)); ++out: ++ ext2fs_free_mem(&fiemap_buf); ++ return err; ++#else ++ return EXT2_ET_UNIMPLEMENTED; ++#endif /* FS_IOC_FIEMAP */ ++} ++ ++static errcode_t copy_file(ext2_filsys fs, int fd, struct stat *statbuf, ++ ext2_ino_t ino) ++{ ++ ext2_file_t e2_file; ++ char *buf = NULL, *zerobuf = NULL; ++ errcode_t err, close_err; ++ ++ err = ext2fs_file_open(fs, ino, EXT2_FILE_WRITE, &e2_file); ++ if (err) ++ return err; ++ ++ err = ext2fs_get_mem(COPY_FILE_BUFLEN, &buf); ++ if (err) ++ goto out; ++ ++ err = ext2fs_get_memzero(fs->blocksize, &zerobuf); ++ if (err) ++ goto out; ++ ++ err = try_lseek_copy(fs, fd, statbuf, e2_file, buf, zerobuf); ++ if (err != EXT2_ET_UNIMPLEMENTED) ++ goto out; ++ ++ err = try_fiemap_copy(fs, fd, e2_file, buf, zerobuf); ++ if (err != EXT2_ET_UNIMPLEMENTED) ++ goto out; ++ ++ err = copy_file_range(fs, fd, e2_file, 0, statbuf->st_size, buf, ++ zerobuf); ++out: ++ ext2fs_free_mem(&zerobuf); ++ ext2fs_free_mem(&buf); ++ close_err = ext2fs_file_close(e2_file); ++ if (err == 0) ++ err = close_err; ++ return err; ++} ++ ++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; ++ ++ fd = ext2fs_open_file(src, O_RDONLY, 0); ++ if (fd < 0) { ++ retval = errno; ++ com_err(__func__, retval, _("while opening \"%s\" to copy"), ++ src); ++ return retval; ++ } ++ if (fstat(fd, &statbuf) < 0) { ++ retval = errno; ++ goto out; ++ } ++ ++ retval = ext2fs_namei(fs, root, cwd, dest, &newfile); ++ if (retval == 0) { ++ retval = EXT2_ET_FILE_EXISTS; ++ goto out; ++ } ++ ++ retval = ext2fs_new_inode(fs, cwd, 010755, 0, &newfile); ++ if (retval) ++ goto out; ++#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) ++ goto out; ++ retval = ext2fs_link(fs, cwd, dest, newfile, ++ EXT2_FT_REG_FILE); ++ } ++ if (retval) ++ goto out; ++ 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) ++ goto out; ++ 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) { ++ ext2_extent_handle_t handle; ++ ++ inode.i_flags &= ~EXT4_EXTENTS_FL; ++ retval = ext2fs_extent_open2(fs, newfile, &inode, &handle); ++ if (retval) ++ goto out; ++ ext2fs_extent_free(handle); ++ } ++ ++ retval = ext2fs_write_new_inode(fs, newfile, &inode); ++ if (retval) ++ goto out; ++ if (inode.i_flags & EXT4_INLINE_DATA_FL) { ++ retval = ext2fs_inline_data_init(fs, newfile); ++ if (retval) ++ goto out; ++ } ++ if (LINUX_S_ISREG(inode.i_mode)) { ++ retval = copy_file(fs, fd, &statbuf, newfile); ++ if (retval) ++ goto out; ++ } ++out: ++ 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) { ++ retval = errno; ++ com_err(__func__, retval, ++ _("while changing working directory to \"%s\""), ++ source_dir); ++ return retval; ++ } ++ ++ if (!(dh = opendir("."))) { ++ retval = errno; ++ com_err(__func__, retval, ++ _("while opening directory \"%s\""), source_dir); ++ return retval; ++ } ++ ++ while ((dent = readdir(dh))) { ++ if ((!strcmp(dent->d_name, ".")) || ++ (!strcmp(dent->d_name, ".."))) ++ continue; ++ if (lstat(dent->d_name, &st)) { ++ retval = errno; ++ com_err(__func__, retval, _("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) { ++ retval = errno; ++ com_err(__func__, retval, ++ _("while trying to read link \"%s\""), ++ name); ++ 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: ++ /* Don't choke on /lost+found */ ++ if (parent_ino == EXT2_ROOT_INO && ++ strcmp(name, "lost+found") == 0) ++ goto find_lnf; ++ retval = do_mkdir_internal(fs, parent_ino, name, ++ root); ++ if (retval) { ++ com_err(__func__, retval, ++ _("while making dir \"%s\""), name); ++ goto out; ++ } ++find_lnf: ++ 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) ++ goto out; ++ if (chdir("..")) { ++ retval = errno; ++ com_err(__func__, retval, ++ _("while changing directory")); ++ 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, _("while looking up \"%s\""), ++ name); ++ goto out; ++ } ++ ++ retval = set_inode_extra(fs, 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) { ++ retval = EXT2_ET_NO_MEMORY; ++ com_err(name, retval, ++ _("while saving inode data")); ++ 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; ++ ++ if (!(fs->flags & EXT2_FLAG_RW)) { ++ com_err(__func__, 0, "Filesystem opened readonly"); ++ return EROFS; ++ } ++ ++ hdlinks.count = 0; ++ hdlinks.size = HDLINK_CNT; ++ hdlinks.hdl = realloc(NULL, hdlinks.size * sizeof(struct hdlink_s)); ++ if (hdlinks.hdl == NULL) { ++ retval = errno; ++ com_err(__func__, retval, _("while allocating memory")); ++ return retval; ++ } ++ ++ retval = __populate_fs(fs, parent_ino, source_dir, root, &hdlinks); ++ ++ free(hdlinks.hdl); ++ return retval; ++} +--- /dev/null ++++ b/misc/create_inode.h +@@ -0,0 +1,41 @@ ++#ifndef _CREATE_INODE_H ++#define _CREATE_INODE_H ++ ++#include ++#include ++#include ++#include "et/com_err.h" ++#include "e2p/e2p.h" ++#include "ext2fs/ext2fs.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, 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 */ +--- a/misc/dumpe2fs.8.in ++++ b/misc/dumpe2fs.8.in +@@ -8,7 +8,7 @@ + .SH SYNOPSIS + .B dumpe2fs + [ +-.B \-bfhixV ++.B \-bfghixV + ] + [ + .B \-o superblock=\fIsuperblock +@@ -49,6 +49,14 @@ + force dumpe2fs to display a filesystem even though it may have some + filesystem feature flags which dumpe2fs may not understand (and which + can cause some of dumpe2fs's display to be suspect). ++.TP ++.B \-g ++display the group descriptor information in a machine readable colon-separated ++value format. The fields displayed are the group number; the number of the ++first block in the group; the superblock location (or -1 if not present); the ++range of blocks used by the group descriptors (or -1 if not present); the block ++bitmap location; the inode bitmap location; and the range of blocks used by the ++inode table. + .TP + .B \-h + only display the superblock information and not any of the block +--- a/misc/dumpe2fs.c ++++ b/misc/dumpe2fs.c +@@ -37,11 +37,12 @@ + + #include "ext2fs/ext2fs.h" + #include "e2p/e2p.h" +-#include "jfs_user.h" ++#include "ext2fs/kernel-jbd.h" + #include + ++#include "support/nls-enable.h" ++#include "support/plausible.h" + #include "../version.h" +-#include "nls-enable.h" + + #define in_use(m, x) (ext2fs_test_bit ((x), (m))) + +@@ -52,9 +53,9 @@ + + static void usage(void) + { +- fprintf (stderr, _("Usage: %s [-bfhixV] [-o superblock=] " ++ fprintf(stderr, _("Usage: %s [-bfghixV] [-o superblock=] " + "[-o blocksize=] device\n"), program_name); +- exit (1); ++ exit(1); + } + + static void print_number(unsigned long long num) +@@ -121,7 +122,7 @@ + { + 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", +@@ -150,7 +151,7 @@ + } + } + +-static void list_desc (ext2_filsys fs) ++static void list_desc(ext2_filsys fs, int grp_only) + { + unsigned long i; + blk64_t first_block, last_block; +@@ -187,6 +188,8 @@ + old_desc_blocks = fs->super->s_first_meta_bg; + else + old_desc_blocks = fs->desc_blocks; ++ if (grp_only) ++ printf("group:block:super:gdt:bbitmap:ibitmap:itable\n"); + for (i = 0; i < fs->group_desc_count; i++) { + first_block = ext2fs_group_first_block2(fs, i); + last_block = ext2fs_group_last_block2(fs, i); +@@ -194,20 +197,39 @@ + ext2fs_super_and_bgd_loc2(fs, i, &super_blk, + &old_desc_blk, &new_desc_blk, 0); + +- printf (_("Group %lu: (Blocks "), i); ++ if (grp_only) { ++ printf("%lu:%llu:", i, first_block); ++ if (i == 0 || super_blk) ++ printf("%llu:", super_blk); ++ else ++ printf("-1:"); ++ if (old_desc_blk) { ++ print_range(old_desc_blk, ++ old_desc_blk + old_desc_blocks - 1); ++ printf(":"); ++ } else if (new_desc_blk) ++ printf("%llu:", new_desc_blk); ++ else ++ printf("-1:"); ++ printf("%llu:%llu:%llu\n", ++ ext2fs_block_bitmap_loc(fs, i), ++ ext2fs_inode_bitmap_loc(fs, i), ++ ext2fs_inode_table_loc(fs, i)); ++ continue; ++ } ++ ++ printf(_("Group %lu: (Blocks "), i); + 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); + +- printf(_(" Checksum 0x%04x"), csum); ++ printf(_(" csum 0x%04x"), csum); + if (csum != exp_csum) + printf(_(" (EXPECTED 0x%04x)"), exp_csum); +- printf(_(", unused inodes %u\n"), +- ext2fs_bg_itable_unused(fs, i)); + } ++ print_bg_opts(fs, i); + has_super = ((i==0) || super_blk); + if (has_super) { + printf (_(" %s superblock at "), +@@ -236,10 +258,22 @@ + print_number(ext2fs_block_bitmap_loc(fs, i)); + print_bg_rel_offset(fs, ext2fs_block_bitmap_loc(fs, i), 0, + first_block, last_block); +- fputs(_(", Inode bitmap at "), stdout); ++ if (fs->super->s_feature_ro_compat & ++ EXT4_FEATURE_RO_COMPAT_METADATA_CSUM) ++ printf(_(", csum 0x%08x"), ++ ext2fs_block_bitmap_checksum(fs, i)); ++ if (getenv("DUMPE2FS_IGNORE_80COL")) ++ fputs(_(","), stdout); ++ else ++ fputs(_("\n "), stdout); ++ 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 +360,16 @@ + 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 +438,17 @@ + (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_V3)) || ++ (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)); +@@ -404,8 +459,9 @@ + errcode_t retval; + char buf[1024]; + char str[80]; +- unsigned int i; ++ unsigned int i, j, printed = 0; + journal_superblock_t *jsb; ++ __u32 *mask_ptr, mask, m; + + /* Get the journal superblock */ + if ((retval = io_channel_read_blk64(fs->io, +@@ -424,6 +480,29 @@ + 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_V3)) || ++ (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("%s", _("Journal features: ")); ++ for (i = 0, mask_ptr = &jsb->s_feature_compat; i < 3; i++, mask_ptr++) { ++ mask = be32_to_cpu(*mask_ptr); ++ for (j = 0, m = 1; j < 32; j++, m <<= 1) { ++ if (mask & m) { ++ printf(" %s", e2p_jrnl_feature2string(i, m)); ++ printed++; ++ } ++ } ++ } ++ + printf(_("\nJournal block size: %u\n" + "Journal length: %u\n" + "Journal first block: %u\n" +@@ -531,6 +610,7 @@ + int flags; + int header_only = 0; + int c; ++ int grp_only = 0; + + #ifdef ENABLE_NLS + setlocale(LC_MESSAGES, ""); +@@ -545,7 +625,7 @@ + if (argc && *argv) + program_name = *argv; + +- while ((c = getopt (argc, argv, "bfhixVo:")) != EOF) { ++ while ((c = getopt(argc, argv, "bfghixVo:")) != EOF) { + switch (c) { + case 'b': + print_badblocks++; +@@ -553,6 +633,9 @@ + case 'f': + force++; + break; ++ case 'g': ++ grp_only++; ++ break; + case 'h': + header_only++; + break; +@@ -585,7 +668,7 @@ + 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; +@@ -600,10 +683,19 @@ + } 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); + printf("%s", _("Couldn't find valid filesystem superblock.\n")); ++ if (retval == EXT2_ET_BAD_MAGIC) ++ check_plausibility(device_name, CHECK_FS_EXIST, NULL); + exit (1); + } + fs->default_bitmap_type = EXT2FS_BMAP64_RBTREE; +@@ -612,6 +704,8 @@ + if (print_badblocks) { + list_bad_blocks(fs, 1); + } else { ++ if (grp_only) ++ goto just_descriptors; + list_super (fs->super); + if (fs->super->s_feature_incompat & + EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) { +@@ -628,8 +722,17 @@ + ext2fs_close_free(&fs); + exit (0); + } ++ fs->flags &= ~EXT2_FLAG_IGNORE_CSUM_ERRORS; ++try_bitmaps_again: + retval = ext2fs_read_bitmaps (fs); +- list_desc (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")); ++just_descriptors: ++ list_desc(fs, grp_only); + if (retval) { + printf(_("\n%s: %s: error reading bitmaps: %s\n"), + program_name, device_name, +--- /dev/null ++++ b/misc/e2fuzz.c +@@ -0,0 +1,370 @@ ++/* ++ * 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 ++#include ++#include ++#include ++#include ++#ifdef HAVE_GETOPT_H ++#include ++#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; ++ ++#if !defined HAVE_PWRITE64 && !defined HAVE_PWRITE ++static ssize_t my_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 /* !defined HAVE_PWRITE64 && !defined HAVE_PWRITE */ ++ ++static int getseed(void) ++{ ++ int r; ++ int fd; ++ ++ fd = open("/dev/urandom", O_RDONLY); ++ if (fd < 0) { ++ perror("open"); ++ exit(0); ++ } ++ if (read(fd, &r, sizeof(r)) != sizeof(r)) ++ printf("Unable to read random seed!\n"); ++ close(fd); ++ return r; ++} ++ ++struct find_block { ++ ext2_ino_t ino; ++ ext2fs_block_bitmap bmap; ++ struct ext2_inode *inode; ++ blk64_t corrupt_blocks; ++}; ++ ++static int find_block_helper(ext2_filsys fs EXT2FS_ATTR((unused)), ++ blk64_t *blocknr, e2_blkcnt_t blockcnt, ++ blk64_t ref_blk EXT2FS_ATTR((unused)), ++ int ref_offset EXT2FS_ATTR((unused)), ++ 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; ++} ++ ++static 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; ++} ++ ++static uint64_t rand_num(uint64_t min, uint64_t max) ++{ ++ uint64_t x; ++ unsigned 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))); ++} ++ ++static 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; ++ off_t 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 %zu in block %zu to 0x%x\n", ++ off % fs->blocksize, off / fs->blocksize, c); ++ if (dryrun) ++ continue; ++#ifdef HAVE_PWRITE64 ++ if (pwrite64(fd, &c, sizeof(c), off) != sizeof(c)) { ++ perror(fsname); ++ goto fail3; ++ } ++#elif HAVE_PWRITE ++ if (pwrite(fd, &c, sizeof(c), off) != sizeof(c)) { ++ perror(fsname); ++ goto fail3; ++ } ++#else ++ if (my_pwrite(fd, &c, sizeof(c), off) != sizeof(c)) { ++ perror(fsname); ++ goto fail3; ++ } ++#endif ++ } ++ 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; ++} ++ ++static 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; ++} +--- /dev/null ++++ b/misc/e2fuzz.sh +@@ -0,0 +1,327 @@ ++#!/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 e2fsck 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 * 4 / 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}/" -type f 2> /dev/null | head -n 50000 | while read f; do ++ attr -l "$f" > /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 ++ mv "$f" "$f.longer" > /dev/null 2>> "${OPS_LOG}" ++ 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}" ++ pass_img_sz="$(stat -c '%s' "${PASS_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 ++ ++ fsck_img_sz="$(stat -c '%s' "${FSCK_IMG}")" ++ if [ "${fsck_img_sz}" -ne "${pass_img_sz}" ]; then ++ echo "++ fsck image size changed" ++ exit 3 ++ fi ++ done ++ fsck_loop_ret=$? ++ if [ "${fsck_loop_ret}" -gt 0 ]; then ++ break; ++ fi ++ fi ++ ++ echo "+++ check fs for round 2" ++ FSCK_LOG="${TESTDIR}/e2fuzz-${pass}-round2.log" ++ e2fsck -fn "${FSCK_IMG}" ${EXTENDED_FSCK_OPTS} >> "${FSCK_LOG}" 2>&1 ++ res=$? ++ if [ "${res}" -ne 0 ]; then ++ echo "++++ fsck failed." ++ exit 1 ++ fi ++ ++ echo "++ mount image (2)" ++ mount "${FSCK_IMG}" "${TESTMNT}" -o loop ++ res=$? ++ ++ if [ "${res}" -eq 0 ]; then ++ echo "+++ ls -laR (2)" ++ ls -laR "${TESTMNT}/test.1/" > /dev/null 2> "${OPS_LOG}" ++ ++ echo "+++ cat files (2)" ++ find "${TESTMNT}/test.1/" -type f -size -1048576k -print0 | xargs -0 cat > /dev/null 2>> "${OPS_LOG}" ++ ++ echo "+++ expand (2)" ++ find "${TESTMNT}/" -type f 2> /dev/null | head -n 50000 | while read f; do ++ attr -l "$f" > /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 ++ mv "$f" "$f.longer" > /dev/null 2>> "${OPS_LOG}" ++ done ++ sync ++ ++ echo "+++ create files (2)" ++ cp -pRdu "${SRCDIR}" "${TESTMNT}/test.moo" 2>> "${OPS_LOG}" ++ sync ++ ++ echo "+++ remove files (2)" ++ 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 ++ ++ echo "+++ check fs (2)" ++ e2fsck -fn "${FSCK_IMG}" >> "${FSCK_LOG}" 2>&1 ++ res=$? ++ if [ "${res}" -ne 0 ]; then ++ echo "++ fsck failed." ++ exit 1 ++ fi ++ else ++ echo "++ mount(2) failed with ${res}" ++ exit 1 ++ fi ++ rm -rf "${FSCK_IMG}" "${PASS_IMG}" "${FUZZ_LOG}" "${TESTDIR}"/e2fuzz*.log ++done ++ ++exit $ret +--- a/misc/e2image.c ++++ b/misc/e2image.c +@@ -10,8 +10,12 @@ + * %End-Header% + */ + ++#ifndef _LARGEFILE_SOURCE + #define _LARGEFILE_SOURCE ++#endif ++#ifndef _LARGEFILE64_SOURCE + #define _LARGEFILE64_SOURCE ++#endif + + #include "config.h" + #include +@@ -45,8 +49,9 @@ + #include "ext2fs/e2image.h" + #include "ext2fs/qcow2.h" + ++#include "support/nls-enable.h" ++#include "support/plausible.h" + #include "../version.h" +-#include "nls-enable.h" + + #define QCOW_OFLAG_COPIED (1LL << 63) + #define NO_BLK ((blk64_t) -1) +@@ -419,9 +424,7 @@ + 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); +@@ -1580,6 +1583,8 @@ + com_err (program_name, retval, _("while trying to open %s"), + device_name); + fputs(_("Couldn't find valid filesystem superblock.\n"), stdout); ++ if (retval == EXT2_ET_BAD_MAGIC) ++ check_plausibility(device_name, CHECK_FS_EXIST, NULL); + exit(1); + } + +--- a/misc/e2initrd_helper.c ++++ b/misc/e2initrd_helper.c +@@ -35,9 +35,9 @@ + #include "ext2fs/ext2_fs.h" + #include "ext2fs/ext2fs.h" + #include "blkid/blkid.h" ++#include "support/nls-enable.h" + + #include "../version.h" +-#include "nls-enable.h" + + static const char * program_name = "e2initrd_helper"; + static char * device_name; +--- a/misc/e2label.c ++++ b/misc/e2label.c +@@ -33,7 +33,7 @@ + #ifdef HAVE_ERRNO_H + #include + #endif +-#include "nls-enable.h" ++#include "support/nls-enable.h" + + #define EXT2_SUPER_MAGIC 0xEF53 + +--- a/misc/e2undo.8.in ++++ b/misc/e2undo.8.in +@@ -10,6 +10,12 @@ + [ + .B \-f + ] ++[ ++.B \-n ++] ++[ ++.B \-v ++] + .I undo_log device + .SH DESCRIPTION + .B e2undo +@@ -24,13 +30,18 @@ + .B \-f + Normally, + .B e2undo +-will check the filesystem UUID and last modified time to make sure the +-undo log matches with the filesystem on the device. If they do not +-match, ++will check the filesystem superblock to make sure the undo log matches ++with the filesystem on the device. If they do not match, + .B e2undo + will refuse to apply the undo log as a safety mechanism. The + .B \-f + option disables this safety mechanism. ++.TP ++.B \-n ++Dry-run; do not actually write blocks back to the filesystem. ++.TP ++.B \-v ++Report which block we're currently replaying. + .SH AUTHOR + .B e2undo + was written by Aneesh Kumar K.V. (aneesh.kumar@linux.vnet.ibm.com) +--- a/misc/e2undo.c ++++ b/misc/e2undo.c +@@ -20,115 +20,278 @@ + #if HAVE_ERRNO_H + #include + #endif +-#include "ext2fs/tdb.h" ++#include + #include "ext2fs/ext2fs.h" +-#include "nls-enable.h" ++#include "support/nls-enable.h" + +-static unsigned char mtime_key[] = "filesystem MTIME"; +-static unsigned char uuid_key[] = "filesystem UUID"; +-static unsigned char blksize_key[] = "filesystem BLKSIZE"; ++#undef DEBUG ++ ++#ifdef DEBUG ++# define dbg_printf(f, a...) do {printf(f, ## a); fflush(stdout); } while (0) ++#else ++# define dbg_printf(f, a...) ++#endif ++ ++/* ++ * Undo file format: The file is cut up into undo_header.block_size blocks. ++ * The first block contains the header. ++ * The second block contains the superblock. ++ * There is then a repeating series of blocks as follows: ++ * A key block, which contains undo_keys to map the following data blocks. ++ * Data blocks ++ * (Note that there are pointers to the first key block and the sb, so this ++ * order isn't strictly necessary.) ++ */ ++#define E2UNDO_MAGIC "E2UNDO02" ++#define KEYBLOCK_MAGIC 0xCADECADE ++ ++#define E2UNDO_STATE_FINISHED 0x1 /* undo file is complete */ ++ ++#define E2UNDO_MIN_BLOCK_SIZE 1024 /* undo blocks are no less than 1KB */ ++#define E2UNDO_MAX_BLOCK_SIZE 1048576 /* undo blocks are no more than 1MB */ ++ ++struct undo_header { ++ char magic[8]; /* "E2UNDO02" */ ++ __le64 num_keys; /* how many keys? */ ++ __le64 super_offset; /* where in the file is the superblock copy? */ ++ __le64 key_offset; /* where do the key/data block chunks start? */ ++ __le32 block_size; /* block size of the undo file */ ++ __le32 fs_block_size; /* block size of the target device */ ++ __le32 sb_crc; /* crc32c of the superblock */ ++ __le32 state; /* e2undo state flags */ ++ __le32 f_compat; /* compatible features (none so far) */ ++ __le32 f_incompat; /* incompatible features (none so far) */ ++ __le32 f_rocompat; /* ro compatible features (none so far) */ ++ __u8 padding[448]; /* padding */ ++ __le32 header_crc; /* crc32c of the header (but not this field) */ ++}; ++ ++#define E2UNDO_MAX_EXTENT_BLOCKS 512 /* max extent size, in blocks */ ++ ++struct undo_key { ++ __le64 fsblk; /* where in the fs does the block go */ ++ __le32 blk_crc; /* crc32c of the block */ ++ __le32 size; /* how many bytes in this block? */ ++}; ++ ++struct undo_key_block { ++ __le32 magic; /* KEYBLOCK_MAGIC number */ ++ __le32 crc; /* block checksum */ ++ __le64 reserved; /* zero */ ++ ++ struct undo_key keys[0]; /* keys, which come immediately after */ ++}; ++ ++struct undo_key_info { ++ blk64_t fsblk; ++ blk64_t fileblk; ++ __u32 blk_crc; ++ unsigned int size; ++}; ++ ++struct undo_context { ++ struct undo_header hdr; ++ io_channel undo_file; ++ unsigned int blocksize, fs_blocksize; ++ blk64_t super_block; ++ size_t num_keys; ++ struct undo_key_info *keys; ++}; ++#define KEYS_PER_BLOCK(d) (((d)->blocksize / sizeof(struct undo_key)) - 1) + + static char *prg_name; ++static char *undo_file; + + static void usage(void) + { + fprintf(stderr, +- _("Usage: %s \n"), prg_name); ++ _("Usage: %s [-f] [-h] [-n] [-v] \n"), prg_name); + exit(1); + } + +-static int check_filesystem(TDB_CONTEXT *tdb, io_channel channel) ++static void dump_header(struct undo_header *hdr) + { +- __u32 s_mtime; +- __u8 s_uuid[16]; ++ printf("nr keys:\t%llu\n", ext2fs_le64_to_cpu(hdr->num_keys)); ++ printf("super block:\t%llu\n", ext2fs_le64_to_cpu(hdr->super_offset)); ++ printf("key block:\t%llu\n", ext2fs_le64_to_cpu(hdr->key_offset)); ++ printf("block size:\t%u\n", ext2fs_le32_to_cpu(hdr->block_size)); ++ printf("fs block size:\t%u\n", ext2fs_le32_to_cpu(hdr->fs_block_size)); ++ printf("super crc:\t0x%x\n", ext2fs_le32_to_cpu(hdr->sb_crc)); ++ printf("state:\t\t0x%x\n", ext2fs_le32_to_cpu(hdr->state)); ++ printf("compat:\t\t0x%x\n", ext2fs_le32_to_cpu(hdr->f_compat)); ++ printf("incompat:\t0x%x\n", ext2fs_le32_to_cpu(hdr->f_incompat)); ++ printf("rocompat:\t0x%x\n", ext2fs_le32_to_cpu(hdr->f_rocompat)); ++ printf("header crc:\t0x%x\n", ext2fs_le32_to_cpu(hdr->header_crc)); ++} ++ ++static void print_undo_mismatch(struct ext2_super_block *fs_super, ++ struct ext2_super_block *undo_super) ++{ ++ printf("%s", ++ _("The file system superblock doesn't match the undo file.\n")); ++ if (memcmp(fs_super->s_uuid, undo_super->s_uuid, ++ sizeof(fs_super->s_uuid))) ++ printf("%s", _("UUID does not match.\n")); ++ if (fs_super->s_mtime != undo_super->s_mtime) ++ printf("%s", _("Last mount time does not match.\n")); ++ if (fs_super->s_wtime != undo_super->s_wtime) ++ printf("%s", _("Last write time does not match.\n")); ++ if (fs_super->s_kbytes_written != undo_super->s_kbytes_written) ++ printf("%s", _("Lifetime write counter does not match.\n")); ++} ++ ++static int check_filesystem(struct undo_context *ctx, io_channel channel) ++{ ++ struct ext2_super_block super, *sb; ++ char *buf; ++ __u32 sb_crc; + errcode_t retval; +- TDB_DATA tdb_key, tdb_data; +- struct ext2_super_block super; + + io_channel_set_blksize(channel, SUPERBLOCK_OFFSET); + retval = io_channel_read_blk64(channel, 1, -SUPERBLOCK_SIZE, &super); + if (retval) { + com_err(prg_name, retval, +- "%s", _("Failed to read the file system data \n")); ++ "%s", _("while reading filesystem superblock.")); + return retval; + } + +- tdb_key.dptr = mtime_key; +- tdb_key.dsize = sizeof(mtime_key); +- tdb_data = tdb_fetch(tdb, tdb_key); +- if (!tdb_data.dptr) { +- retval = EXT2_ET_TDB_SUCCESS + tdb_error(tdb); +- com_err(prg_name, retval, +- _("Failed tdb_fetch %s\n"), tdb_errorstr(tdb)); ++ /* ++ * Compare the FS and the undo file superblock so that we can't apply ++ * e2undo "patches" out of order. ++ */ ++ retval = ext2fs_get_mem(ctx->blocksize, &buf); ++ if (retval) { ++ com_err(prg_name, retval, "%s", _("while allocating memory")); + return retval; + } +- +- s_mtime = *(__u32 *)tdb_data.dptr; +- if (super.s_mtime != s_mtime) { +- +- com_err(prg_name, 0, +- _("The file system Mount time didn't match %u\n"), +- s_mtime); +- +- return -1; ++ retval = io_channel_read_blk64(ctx->undo_file, ctx->super_block, ++ -SUPERBLOCK_SIZE, buf); ++ if (retval) { ++ com_err(prg_name, retval, "%s", _("while fetching superblock")); ++ goto out; + } ++ sb = (struct ext2_super_block *)buf; ++ sb->s_magic = ~sb->s_magic; ++ if (memcmp(&super, buf, sizeof(super))) { ++ print_undo_mismatch(&super, (struct ext2_super_block *)buf); ++ retval = -1; ++ goto out; ++ } ++ sb_crc = ext2fs_crc32c_le(~0, (unsigned char *)buf, SUPERBLOCK_SIZE); ++ if (ext2fs_le32_to_cpu(ctx->hdr.sb_crc) != sb_crc) { ++ fprintf(stderr, ++ _("Undo file superblock checksum doesn't match.\n")); ++ retval = -1; ++ goto out; ++ } ++ ++out: ++ ext2fs_free_mem(&buf); ++ return retval; ++} + ++static int key_compare(const void *a, const void *b) ++{ ++ const struct undo_key_info *ka, *kb; + +- tdb_key.dptr = uuid_key; +- tdb_key.dsize = sizeof(uuid_key); +- tdb_data = tdb_fetch(tdb, tdb_key); +- if (!tdb_data.dptr) { +- retval = EXT2_ET_TDB_SUCCESS + tdb_error(tdb); +- com_err(prg_name, retval, +- _("Failed tdb_fetch %s\n"), tdb_errorstr(tdb)); +- return retval; +- } +- memcpy(s_uuid, tdb_data.dptr, sizeof(s_uuid)); +- if (memcmp(s_uuid, super.s_uuid, sizeof(s_uuid))) { +- com_err(prg_name, 0, "%s", +- _("The file system UUID didn't match \n")); +- return -1; +- } +- +- return 0; ++ ka = a; ++ kb = b; ++ return ext2fs_le64_to_cpu(ka->fsblk) - ++ ext2fs_le64_to_cpu(kb->fsblk); + } + +-static int set_blk_size(TDB_CONTEXT *tdb, io_channel channel) ++static int e2undo_setup_tdb(const char *name, io_manager *io_ptr) + { +- int block_size; +- errcode_t retval; +- TDB_DATA tdb_key, tdb_data; ++ errcode_t retval = 0; ++ const char *tdb_dir; ++ char *tdb_file = NULL; ++ char *dev_name, *tmp_name; ++ ++ /* (re)open a specific undo file */ ++ if (undo_file && undo_file[0] != 0) { ++ retval = set_undo_io_backing_manager(*io_ptr); ++ if (retval) ++ goto err; ++ *io_ptr = undo_io_manager; ++ retval = set_undo_io_backup_file(undo_file); ++ if (retval) ++ goto err; ++ printf(_("Overwriting existing filesystem; this can be undone " ++ "using the command:\n" ++ " e2undo %s %s\n\n"), ++ undo_file, name); ++ return retval; ++ } + +- tdb_key.dptr = blksize_key; +- tdb_key.dsize = sizeof(blksize_key); +- tdb_data = tdb_fetch(tdb, tdb_key); +- if (!tdb_data.dptr) { +- retval = EXT2_ET_TDB_SUCCESS + tdb_error(tdb); ++ /* ++ * Configuration via a conf file would be ++ * nice ++ */ ++ tdb_dir = getenv("E2FSPROGS_UNDO_DIR"); ++ if (!tdb_dir) ++ tdb_dir = "/var/lib/e2fsprogs"; ++ ++ if (!strcmp(tdb_dir, "none") || (tdb_dir[0] == 0) || ++ access(tdb_dir, W_OK)) ++ return 0; ++ ++ tmp_name = strdup(name); ++ if (!tmp_name) ++ goto errout; ++ dev_name = basename(tmp_name); ++ tdb_file = malloc(strlen(tdb_dir) + 8 + strlen(dev_name) + 7 + 1); ++ if (!tdb_file) { ++ free(tmp_name); ++ goto errout; ++ } ++ sprintf(tdb_file, "%s/e2undo-%s.e2undo", tdb_dir, dev_name); ++ free(tmp_name); ++ ++ if ((unlink(tdb_file) < 0) && (errno != ENOENT)) { ++ retval = errno; + com_err(prg_name, retval, +- _("Failed tdb_fetch %s\n"), tdb_errorstr(tdb)); +- return retval; ++ _("while trying to delete %s"), tdb_file); ++ goto errout; + } + +- block_size = *(int *)tdb_data.dptr; +-#ifdef DEBUG +- printf("Block size %d\n", block_size); +-#endif +- io_channel_set_blksize(channel, block_size); ++ retval = set_undo_io_backing_manager(*io_ptr); ++ if (retval) ++ goto errout; ++ *io_ptr = undo_io_manager; ++ retval = set_undo_io_backup_file(tdb_file); ++ if (retval) ++ goto errout; ++ printf(_("Overwriting existing filesystem; this can be undone " ++ "using the command:\n" ++ " e2undo %s %s\n\n"), ++ tdb_file, name); + ++ free(tdb_file); + return 0; ++errout: ++ free(tdb_file); ++err: ++ com_err(prg_name, retval, "while trying to setup undo file\n"); ++ return retval; + } + + int main(int argc, char *argv[]) + { +- int c,force = 0; +- TDB_CONTEXT *tdb; +- TDB_DATA key, data; ++ int c, force = 0, dry_run = 0, verbose = 0, dump = 0; + io_channel channel; + errcode_t retval; +- int mount_flags; +- blk64_t blk_num; ++ int mount_flags, csum_error = 0, io_error = 0; ++ size_t i, keys_per_block; + char *device_name, *tdb_file; + io_manager manager = unix_io_manager; ++ struct undo_context undo_ctx; ++ char *buf; ++ struct undo_key_block *keyb; ++ struct undo_key *dkey; ++ struct undo_key_info *ikey; ++ __u32 key_crc, blk_crc, hdr_crc; ++ blk64_t lblk; ++ ext2_filsys fs; + + #ifdef ENABLE_NLS + setlocale(LC_MESSAGES, ""); +@@ -140,13 +303,25 @@ + add_error_table(&et_ext2_error_table); + + prg_name = argv[0]; +- while((c = getopt(argc, argv, "f")) != EOF) { ++ while ((c = getopt(argc, argv, "fhnvz:")) != EOF) { + switch (c) { +- case 'f': +- force = 1; +- break; +- default: +- usage(); ++ case 'f': ++ force = 1; ++ break; ++ case 'h': ++ dump = 1; ++ break; ++ case 'n': ++ dry_run = 1; ++ break; ++ case 'v': ++ verbose = 1; ++ break; ++ case 'z': ++ undo_file = optarg; ++ break; ++ default: ++ usage(); + } + } + +@@ -156,70 +331,274 @@ + tdb_file = argv[optind]; + device_name = argv[optind+1]; + +- tdb = tdb_open(tdb_file, 0, 0, O_RDONLY, 0600); ++ if (undo_file && strcmp(tdb_file, undo_file) == 0) { ++ printf(_("Will not write to an undo file while replaying it.\n")); ++ exit(1); ++ } + +- if (!tdb) { ++ /* Interpret the undo file */ ++ retval = manager->open(tdb_file, IO_FLAG_EXCLUSIVE, ++ &undo_ctx.undo_file); ++ if (retval) { + com_err(prg_name, errno, +- _("Failed tdb_open %s\n"), tdb_file); ++ _("while opening undo file `%s'\n"), tdb_file); ++ exit(1); ++ } ++ retval = io_channel_read_blk64(undo_ctx.undo_file, 0, ++ -(int)sizeof(undo_ctx.hdr), ++ &undo_ctx.hdr); ++ if (retval) { ++ com_err(prg_name, retval, _("while reading undo file")); ++ exit(1); ++ } ++ if (memcmp(undo_ctx.hdr.magic, E2UNDO_MAGIC, ++ sizeof(undo_ctx.hdr.magic))) { ++ fprintf(stderr, _("%s: Not an undo file.\n"), tdb_file); ++ exit(1); ++ } ++ if (dump) { ++ dump_header(&undo_ctx.hdr); ++ exit(1); ++ } ++ hdr_crc = ext2fs_crc32c_le(~0, (unsigned char *)&undo_ctx.hdr, ++ sizeof(struct undo_header) - ++ sizeof(__u32)); ++ if (!force && ext2fs_le32_to_cpu(undo_ctx.hdr.header_crc) != hdr_crc) { ++ fprintf(stderr, _("%s: Header checksum doesn't match.\n"), ++ tdb_file); ++ exit(1); ++ } ++ undo_ctx.blocksize = ext2fs_le32_to_cpu(undo_ctx.hdr.block_size); ++ undo_ctx.fs_blocksize = ext2fs_le32_to_cpu(undo_ctx.hdr.fs_block_size); ++ if (undo_ctx.blocksize == 0 || undo_ctx.fs_blocksize == 0) { ++ fprintf(stderr, _("%s: Corrupt undo file header.\n"), tdb_file); ++ exit(1); ++ } ++ if (!force && undo_ctx.blocksize > E2UNDO_MAX_BLOCK_SIZE) { ++ fprintf(stderr, _("%s: Undo block size too large.\n"), ++ tdb_file); ++ exit(1); ++ } ++ if (!force && undo_ctx.blocksize < E2UNDO_MIN_BLOCK_SIZE) { ++ fprintf(stderr, _("%s: Undo block size too small.\n"), ++ tdb_file); ++ exit(1); ++ } ++ undo_ctx.super_block = ext2fs_le64_to_cpu(undo_ctx.hdr.super_offset); ++ undo_ctx.num_keys = ext2fs_le64_to_cpu(undo_ctx.hdr.num_keys); ++ io_channel_set_blksize(undo_ctx.undo_file, undo_ctx.blocksize); ++ if (!force && (undo_ctx.hdr.f_compat || undo_ctx.hdr.f_incompat || ++ undo_ctx.hdr.f_rocompat)) { ++ fprintf(stderr, _("%s: Unknown undo file feature set.\n"), ++ tdb_file); + exit(1); + } + ++ /* open the fs */ + retval = ext2fs_check_if_mounted(device_name, &mount_flags); + if (retval) { + com_err(prg_name, retval, _("Error while determining whether " +- "%s is mounted.\n"), device_name); ++ "%s is mounted."), device_name); + exit(1); + } + + if (mount_flags & EXT2_MF_MOUNTED) { + com_err(prg_name, retval, "%s", _("e2undo should only be run " +- "on unmounted file system\n")); ++ "on unmounted filesystems")); + exit(1); + } + ++ if (undo_file) { ++ retval = e2undo_setup_tdb(device_name, &manager); ++ if (retval) ++ exit(1); ++ } ++ + retval = manager->open(device_name, +- IO_FLAG_EXCLUSIVE | IO_FLAG_RW, &channel); ++ IO_FLAG_EXCLUSIVE | (dry_run ? 0 : IO_FLAG_RW), ++ &channel); + if (retval) { + com_err(prg_name, retval, +- _("Failed to open %s\n"), device_name); ++ _("while opening `%s'"), device_name); + exit(1); + } + +- if (!force && check_filesystem(tdb, channel)) { ++ if (!force && check_filesystem(&undo_ctx, channel)) + exit(1); +- } + +- if (set_blk_size(tdb, channel)) { ++ /* prepare to read keys */ ++ retval = ext2fs_get_mem(sizeof(struct undo_key_info) * undo_ctx.num_keys, ++ &undo_ctx.keys); ++ if (retval) { ++ com_err(prg_name, retval, "%s", _("while allocating memory")); ++ exit(1); ++ } ++ ikey = undo_ctx.keys; ++ retval = ext2fs_get_mem(undo_ctx.blocksize, &keyb); ++ if (retval) { ++ com_err(prg_name, retval, "%s", _("while allocating memory")); ++ exit(1); ++ } ++ retval = ext2fs_get_mem(E2UNDO_MAX_EXTENT_BLOCKS * undo_ctx.blocksize, ++ &buf); ++ if (retval) { ++ com_err(prg_name, retval, "%s", _("while allocating memory")); + exit(1); + } + +- for (key = tdb_firstkey(tdb); key.dptr; key = tdb_nextkey(tdb, key)) { +- if (!strcmp((char *) key.dptr, (char *) mtime_key) || +- !strcmp((char *) key.dptr, (char *) uuid_key) || +- !strcmp((char *) key.dptr, (char *) blksize_key)) { +- continue; ++ /* load keys */ ++ keys_per_block = KEYS_PER_BLOCK(&undo_ctx); ++ lblk = ext2fs_le64_to_cpu(undo_ctx.hdr.key_offset); ++ dbg_printf("nr_keys=%lu, kpb=%zu, blksz=%u\n", ++ undo_ctx.num_keys, keys_per_block, undo_ctx.blocksize); ++ for (i = 0; i < undo_ctx.num_keys; i += keys_per_block) { ++ size_t j, max_j; ++ __le32 crc; ++ ++ retval = io_channel_read_blk64(undo_ctx.undo_file, ++ lblk, 1, keyb); ++ if (retval) { ++ com_err(prg_name, retval, "%s", _("while reading keys")); ++ if (force) { ++ io_error = 1; ++ undo_ctx.num_keys = i - 1; ++ break; ++ } ++ exit(1); + } + +- data = tdb_fetch(tdb, key); +- if (!data.dptr) { +- com_err(prg_name, 0, +- _("Failed tdb_fetch %s\n"), tdb_errorstr(tdb)); ++ /* check keys */ ++ if (!force && ++ ext2fs_le32_to_cpu(keyb->magic) != KEYBLOCK_MAGIC) { ++ fprintf(stderr, _("%s: wrong key magic at %llu\n"), ++ tdb_file, lblk); + exit(1); + } +- blk_num = *(blk64_t *)key.dptr; +- printf(_("Replayed transaction of size %zd at location %llu\n"), +- data.dsize, blk_num); +- retval = io_channel_write_blk64(channel, blk_num, +- -data.dsize, data.dptr); +- if (retval == -1) { +- com_err(prg_name, retval, +- _("Failed write %s\n"), +- strerror(errno)); ++ crc = keyb->crc; ++ keyb->crc = 0; ++ key_crc = ext2fs_crc32c_le(~0, (unsigned char *)keyb, ++ undo_ctx.blocksize); ++ if (!force && ext2fs_le32_to_cpu(crc) != key_crc) { ++ fprintf(stderr, ++ _("%s: key block checksum error at %llu.\n"), ++ tdb_file, lblk); + exit(1); + } ++ ++ /* load keys from key block */ ++ lblk++; ++ max_j = undo_ctx.num_keys - i; ++ if (max_j > keys_per_block) ++ max_j = keys_per_block; ++ for (j = 0, dkey = keyb->keys; ++ j < max_j; ++ j++, ikey++, dkey++) { ++ ikey->fsblk = ext2fs_le64_to_cpu(dkey->fsblk); ++ ikey->fileblk = lblk; ++ ikey->blk_crc = ext2fs_le32_to_cpu(dkey->blk_crc); ++ ikey->size = ext2fs_le32_to_cpu(dkey->size); ++ lblk += (ikey->size + undo_ctx.blocksize - 1) / ++ undo_ctx.blocksize; ++ ++ if (E2UNDO_MAX_EXTENT_BLOCKS * undo_ctx.blocksize < ++ ikey->size) { ++ com_err(prg_name, retval, ++ _("%s: block %llu is too long."), ++ tdb_file, ikey->fsblk); ++ exit(1); ++ } ++ ++ /* check each block's crc */ ++ retval = io_channel_read_blk64(undo_ctx.undo_file, ++ ikey->fileblk, ++ -(int)ikey->size, ++ buf); ++ if (retval) { ++ com_err(prg_name, retval, ++ _("while fetching block %llu."), ++ ikey->fileblk); ++ if (!force) ++ exit(1); ++ io_error = 1; ++ continue; ++ } ++ ++ blk_crc = ext2fs_crc32c_le(~0, (unsigned char *)buf, ++ ikey->size); ++ if (blk_crc != ikey->blk_crc) { ++ fprintf(stderr, ++ _("checksum error in filesystem block " ++ "%llu (undo blk %llu)\n"), ++ ikey->fsblk, ikey->fileblk); ++ if (!force) ++ exit(1); ++ csum_error = 1; ++ } ++ } + } ++ ext2fs_free_mem(&keyb); ++ ++ /* sort keys in fs block order */ ++ qsort(undo_ctx.keys, undo_ctx.num_keys, sizeof(struct undo_key_info), ++ key_compare); ++ ++ /* replay */ ++ io_channel_set_blksize(channel, undo_ctx.fs_blocksize); ++ for (i = 0, ikey = undo_ctx.keys; i < undo_ctx.num_keys; i++, ikey++) { ++ retval = io_channel_read_blk64(undo_ctx.undo_file, ++ ikey->fileblk, ++ -(int)ikey->size, ++ buf); ++ if (retval) { ++ com_err(prg_name, retval, ++ _("while fetching block %llu."), ++ ikey->fileblk); ++ io_error = 1; ++ continue; ++ } ++ ++ if (verbose) ++ printf("Replayed block of size %u from %llu to %llu\n", ++ ikey->size, ikey->fileblk, ikey->fsblk); ++ if (dry_run) ++ continue; ++ retval = io_channel_write_blk64(channel, ikey->fsblk, ++ -(int)ikey->size, buf); ++ if (retval) { ++ com_err(prg_name, retval, ++ _("while writing block %llu."), ikey->fsblk); ++ io_error = 1; ++ } ++ } ++ ++ if (csum_error) ++ fprintf(stderr, _("Undo file corruption; run e2fsck NOW!\n")); ++ if (io_error) ++ fprintf(stderr, _("IO error during replay; run e2fsck NOW!\n")); ++ if (!(ext2fs_le32_to_cpu(undo_ctx.hdr.state) & E2UNDO_STATE_FINISHED)) { ++ force = 1; ++ fprintf(stderr, _("Incomplete undo record; run e2fsck.\n")); ++ } ++ ext2fs_free_mem(&buf); ++ ext2fs_free_mem(&undo_ctx.keys); + io_channel_close(channel); +- tdb_close(tdb); + +- return 0; ++ /* If there were problems, try to force a fsck */ ++ if (!dry_run && (force || csum_error || io_error)) { ++ retval = ext2fs_open2(device_name, NULL, ++ EXT2_FLAG_RW | EXT2_FLAG_64BITS, 0, 0, ++ manager, &fs); ++ if (retval) ++ goto out; ++ fs->super->s_state &= ~EXT2_VALID_FS; ++ if (csum_error || io_error) ++ fs->super->s_state |= EXT2_ERROR_FS; ++ ext2fs_mark_super_dirty(fs); ++ ext2fs_close_free(&fs); ++ } ++ ++out: ++ io_channel_close(undo_ctx.undo_file); ++ ++ return csum_error; + } +--- /dev/null ++++ b/misc/e4crypt.8.in +@@ -0,0 +1,48 @@ ++.TH E4CRYPT 8 "@E2FSPROGS_MONTH@ @E2FSPROGS_YEAR@" "E2fsprogs version @E2FSPROGS_VERSION@" ++.SH NAME ++e4crypt \- ext4 filesystem encryption utility ++.SH SYNOPSIS ++.B e4crypt \-a \-S ++.I salt ++[ ++.B \-k ++.I keyring ++] ++[ ++.I path\fR ... ++] ++.br ++.B e4crypt \-s ++.I policy ++.I path\fR ... ++.SH DESCRIPTION ++.B e4crypt ++performs encryption management for ext4 file systems. ++.SH COMMANDS ++.TP ++.B e4crypt add_key -S \fR[\fB -k \fIkeyring\fR ] [\fB-v\fR] [\fB-q\fR] [ \fI path\fR ... ] ++Prompts the user for a passphrase and inserts it into the specified ++keyring. If no keyring is specified, e4crypt will use the session ++keyring if it exists or the user session keyring if it does not. ++.IP ++If one or more directory paths are specified, e4crypt will try to ++set the policy of those directories to use the key just entered by ++the user. ++.TP ++.B e4crypt new_session ++Give the invoking process (typically a shell) a new session keyring, ++discarding its old session keyring. ++.TP ++.B set_policy -s \fIpolicy path\fR ... ++Sets the policy for the directories specified on the command line. ++All directories must be empty to set the policy; if the directory ++already has a policy established, e4crypt will validate that it the ++policy matches what was specified. A policy is an encryption key ++identifier consisting of 16 hexadecimal characters. ++.SH AUTHOR ++Written by Michael Halcrow , Ildar Muslukhov ++, and Theodore Ts'o ++.SH SEE ALSO ++.BR keyctl (1), ++.BR mke2fs (8), ++.BR mount (8). +--- /dev/null ++++ b/misc/e4crypt.c +@@ -0,0 +1,881 @@ ++/* ++ * e4crypt.c - ext4 encryption management utility ++ * ++ * Copyright (c) 2014 Google, Inc. ++ * SHA512 implementation from libtomcrypt. ++ * ++ * Authors: Michael Halcrow , ++ * Ildar Muslukhov ++ */ ++ ++#ifndef _LARGEFILE_SOURCE ++#define _LARGEFILE_SOURCE ++#endif ++ ++#ifndef _LARGEFILE64_SOURCE ++#define _LARGEFILE64_SOURCE ++#endif ++ ++#ifndef _GNU_SOURCE ++#define _GNU_SOURCE ++#endif ++ ++#include "config.h" ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#if !defined(HAVE_ADD_KEY) || !defined(HAVE_KEYCTL) ++#include ++#endif ++#ifdef HAVE_SYS_KEY_H ++#include ++#endif ++ ++#include "ext2fs/ext2_fs.h" ++#include "ext2fs/ext2fs.h" ++#include "uuid/uuid.h" ++ ++/* special process keyring shortcut IDs */ ++#define KEY_SPEC_THREAD_KEYRING -1 ++#define KEY_SPEC_PROCESS_KEYRING -2 ++#define KEY_SPEC_SESSION_KEYRING -3 ++#define KEY_SPEC_USER_KEYRING -4 ++#define KEY_SPEC_USER_SESSION_KEYRING -5 ++#define KEY_SPEC_GROUP_KEYRING -6 ++ ++#define KEYCTL_GET_KEYRING_ID 0 ++#define KEYCTL_JOIN_SESSION_KEYRING 1 ++#define KEYCTL_DESCRIBE 6 ++#define KEYCTL_SEARCH 10 ++#define KEYCTL_SESSION_TO_PARENT 18 ++ ++typedef __s32 key_serial_t; ++ ++#define EXT4_KEY_REF_STR_BUF_SIZE ((EXT4_KEY_DESCRIPTOR_SIZE * 2) + 1) ++ ++#ifndef EXT4_IOC_GET_ENCRYPTION_PWSALT ++#define EXT4_IOC_GET_ENCRYPTION_PWSALT _IOW('f', 20, __u8[16]) ++#endif ++ ++#define OPT_VERBOSE 0x0001 ++#define OPT_QUIET 0x0002 ++ ++int options; ++ ++#ifndef HAVE_KEYCTL ++static long keyctl(int cmd, ...) ++{ ++ va_list va; ++ unsigned long arg2, arg3, arg4, arg5; ++ ++ va_start(va, cmd); ++ arg2 = va_arg(va, unsigned long); ++ arg3 = va_arg(va, unsigned long); ++ arg4 = va_arg(va, unsigned long); ++ arg5 = va_arg(va, unsigned long); ++ va_end(va); ++ return syscall(__NR_keyctl, cmd, arg2, arg3, arg4, arg5); ++} ++#endif ++ ++#ifndef HAVE_ADD_KEY ++static key_serial_t add_key(const char *type, const char *description, ++ const void *payload, size_t plen, ++ key_serial_t keyring) ++{ ++ return syscall(__NR_add_key, type, description, payload, ++ plen, keyring); ++} ++#endif ++ ++static const unsigned char *hexchars = (const unsigned char *) "0123456789abcdef"; ++static const size_t hexchars_size = 16; ++ ++#define SHA512_LENGTH 64 ++#define EXT2FS_KEY_TYPE_LOGON "logon" ++#define EXT2FS_KEY_DESC_PREFIX "ext4:" ++#define EXT2FS_KEY_DESC_PREFIX_SIZE 5 ++ ++#define EXT4_IOC_SET_ENCRYPTION_POLICY _IOR('f', 19, struct ext4_encryption_policy) ++#define EXT4_IOC_GET_ENCRYPTION_POLICY _IOW('f', 21, struct ext4_encryption_policy) ++ ++static int int_log2(int arg) ++{ ++ int l = 0; ++ ++ arg >>= 1; ++ while (arg) { ++ l++; ++ arg >>= 1; ++ } ++ return l; ++} ++ ++static void validate_paths(int argc, char *argv[], int path_start_index) ++{ ++ int x; ++ int valid = 1; ++ struct stat st; ++ ++ for (x = path_start_index; x < argc; x++) { ++ int ret = access(argv[x], W_OK); ++ if (ret) { ++ invalid: ++ perror(argv[x]); ++ valid = 0; ++ continue; ++ } ++ ret = stat(argv[x], &st); ++ if (ret < 0) ++ goto invalid; ++ if (!S_ISDIR(st.st_mode)) { ++ fprintf(stderr, "%s is not a directory\n", argv[x]); ++ goto invalid; ++ } ++ } ++ if (!valid) ++ exit(1); ++} ++ ++static int hex2byte(const char *hex, size_t hex_size, unsigned char *bytes, ++ size_t bytes_size) ++{ ++ size_t x; ++ unsigned char *h, *l; ++ ++ if (hex_size % 2) ++ return -EINVAL; ++ for (x = 0; x < hex_size; x += 2) { ++ h = memchr(hexchars, hex[x], hexchars_size); ++ if (!h) ++ return -EINVAL; ++ l = memchr(hexchars, hex[x + 1], hexchars_size); ++ if (!l) ++ return -EINVAL; ++ if ((x >> 1) >= bytes_size) ++ return -EINVAL; ++ bytes[x >> 1] = (((unsigned char)(h - hexchars) << 4) + ++ (unsigned char)(l - hexchars)); ++ } ++ return 0; ++} ++ ++/* ++ * Salt handling ++ */ ++struct salt { ++ unsigned char *salt; ++ char key_ref_str[EXT4_KEY_REF_STR_BUF_SIZE]; ++ unsigned char key_desc[EXT4_KEY_DESCRIPTOR_SIZE]; ++ unsigned char key[EXT4_MAX_KEY_SIZE]; ++ size_t salt_len; ++}; ++struct salt *salt_list; ++unsigned num_salt; ++unsigned max_salt; ++char in_passphrase[EXT4_MAX_PASSPHRASE_SIZE]; ++ ++static struct salt *find_by_salt(unsigned char *salt, size_t salt_len) ++{ ++ unsigned int i; ++ struct salt *p; ++ ++ for (i = 0, p = salt_list; i < num_salt; i++, p++) ++ if ((p->salt_len == salt_len) && ++ !memcmp(p->salt, salt, salt_len)) ++ return p; ++ return NULL; ++} ++ ++static void add_salt(unsigned char *salt, size_t salt_len) ++{ ++ if (find_by_salt(salt, salt_len)) ++ return; ++ if (num_salt >= max_salt) { ++ max_salt = num_salt + 10; ++ salt_list = realloc(salt_list, max_salt * sizeof(struct salt)); ++ if (!salt_list) { ++ fprintf(stderr, "Couldn't allocate salt list\n"); ++ exit(1); ++ } ++ } ++ salt_list[num_salt].salt = salt; ++ salt_list[num_salt].salt_len = salt_len; ++ num_salt++; ++} ++ ++static void clear_secrets(void) ++{ ++ if (salt_list) { ++ memset(salt_list, 0, sizeof(struct salt) * max_salt); ++ free(salt_list); ++ salt_list = NULL; ++ } ++ memset(in_passphrase, 0, sizeof(in_passphrase)); ++} ++ ++static void die_signal_handler(int signum EXT2FS_ATTR((unused)), ++ siginfo_t *siginfo EXT2FS_ATTR((unused)), ++ void *context EXT2FS_ATTR((unused))) ++{ ++ clear_secrets(); ++ exit(-1); ++} ++ ++static void sigcatcher_setup(void) ++{ ++ struct sigaction sa; ++ ++ memset(&sa, 0, sizeof(struct sigaction)); ++ sa.sa_sigaction = die_signal_handler; ++ sa.sa_flags = SA_SIGINFO; ++ ++ sigaction(SIGHUP, &sa, 0); ++ sigaction(SIGINT, &sa, 0); ++ sigaction(SIGQUIT, &sa, 0); ++ sigaction(SIGFPE, &sa, 0); ++ sigaction(SIGILL, &sa, 0); ++ sigaction(SIGBUS, &sa, 0); ++ sigaction(SIGSEGV, &sa, 0); ++ sigaction(SIGABRT, &sa, 0); ++ sigaction(SIGPIPE, &sa, 0); ++ sigaction(SIGALRM, &sa, 0); ++ sigaction(SIGTERM, &sa, 0); ++ sigaction(SIGUSR1, &sa, 0); ++ sigaction(SIGUSR2, &sa, 0); ++ sigaction(SIGPOLL, &sa, 0); ++ sigaction(SIGPROF, &sa, 0); ++ sigaction(SIGSYS, &sa, 0); ++ sigaction(SIGTRAP, &sa, 0); ++ sigaction(SIGVTALRM, &sa, 0); ++ sigaction(SIGXCPU, &sa, 0); ++ sigaction(SIGXFSZ, &sa, 0); ++} ++ ++ ++#define PARSE_FLAGS_NOTSUPP_OK 0x0001 ++#define PARSE_FLAGS_FORCE_FN 0x0002 ++ ++static void parse_salt(char *salt_str, int flags) ++{ ++ unsigned char buf[EXT4_MAX_SALT_SIZE]; ++ char *cp = salt_str; ++ unsigned char *salt_buf; ++ int fd, ret, salt_len = 0; ++ ++ if (flags & PARSE_FLAGS_FORCE_FN) ++ goto salt_from_filename; ++ if (strncmp(cp, "s:", 2) == 0) { ++ cp += 2; ++ salt_len = strlen(cp); ++ if (salt_len >= EXT4_MAX_SALT_SIZE) ++ goto invalid_salt; ++ strncpy((char *) buf, cp, sizeof(buf)); ++ } else if (cp[0] == '/') { ++ salt_from_filename: ++ fd = open(cp, O_RDONLY | O_DIRECTORY); ++ if (fd == -1 && errno == ENOTDIR) ++ fd = open(cp, O_RDONLY); ++ if (fd == -1) { ++ perror(cp); ++ exit(1); ++ } ++ ret = ioctl(fd, EXT4_IOC_GET_ENCRYPTION_PWSALT, &buf); ++ close(fd); ++ if (ret < 0) { ++ if (flags & PARSE_FLAGS_NOTSUPP_OK) ++ return; ++ perror("EXT4_IOC_GET_ENCRYPTION_PWSALT"); ++ exit(1); ++ } ++ if (options & OPT_VERBOSE) { ++ char tmp[80]; ++ uuid_unparse(buf, tmp); ++ printf("%s has pw salt %s\n", cp, tmp); ++ } ++ salt_len = 16; ++ } else if (strncmp(cp, "f:", 2) == 0) { ++ cp += 2; ++ goto salt_from_filename; ++ } else if (strncmp(cp, "0x", 2) == 0) { ++ unsigned char *h, *l; ++ ++ cp += 2; ++ if (strlen(cp) & 1) ++ goto invalid_salt; ++ while (*cp) { ++ if (salt_len >= EXT4_MAX_SALT_SIZE) ++ goto invalid_salt; ++ h = memchr(hexchars, *cp++, hexchars_size); ++ l = memchr(hexchars, *cp++, hexchars_size); ++ if (!h || !l) ++ goto invalid_salt; ++ buf[salt_len++] = ++ (((unsigned char)(h - hexchars) << 4) + ++ (unsigned char)(l - hexchars)); ++ } ++ } else if (uuid_parse(cp, buf) == 0) { ++ salt_len = 16; ++ } else { ++ invalid_salt: ++ fprintf(stderr, "Invalid salt: %s\n", salt_str); ++ exit(1); ++ } ++ salt_buf = malloc(salt_len); ++ if (!salt_buf) { ++ fprintf(stderr, "Couldn't allocate salt\n"); ++ exit(1); ++ } ++ memcpy(salt_buf, buf, salt_len); ++ add_salt(salt_buf, salt_len); ++} ++ ++static void set_policy(struct salt *set_salt, int pad, ++ int argc, char *argv[], int path_start_index) ++{ ++ struct salt *salt; ++ struct ext4_encryption_policy policy; ++ uuid_t uu; ++ int fd; ++ int x; ++ int rc; ++ ++ if ((pad != 4) && (pad != 8) && ++ (pad != 16) && (pad != 32)) { ++ fprintf(stderr, "Invalid padding %d\n", pad); ++ exit(1); ++ } ++ ++ for (x = path_start_index; x < argc; x++) { ++ fd = open(argv[x], O_DIRECTORY); ++ if (fd == -1) { ++ perror(argv[x]); ++ exit(1); ++ } ++ if (set_salt) ++ salt = set_salt; ++ else { ++ if (ioctl(fd, EXT4_IOC_GET_ENCRYPTION_PWSALT, ++ &uu) < 0) { ++ perror("EXT4_IOC_GET_ENCRYPTION_PWSALT"); ++ exit(1); ++ } ++ salt = find_by_salt(uu, sizeof(uu)); ++ if (!salt) { ++ fprintf(stderr, "Couldn't find salt!?!\n"); ++ exit(1); ++ } ++ } ++ policy.version = 0; ++ policy.contents_encryption_mode = ++ EXT4_ENCRYPTION_MODE_AES_256_XTS; ++ policy.filenames_encryption_mode = ++ EXT4_ENCRYPTION_MODE_AES_256_CTS; ++ policy.flags = int_log2(pad >> 2); ++ memcpy(policy.master_key_descriptor, salt->key_desc, ++ EXT4_KEY_DESCRIPTOR_SIZE); ++ rc = ioctl(fd, EXT4_IOC_SET_ENCRYPTION_POLICY, &policy); ++ close(fd); ++ if (rc) { ++ printf("Error [%s] setting policy.\nThe key descriptor " ++ "[%s] may not match the existing encryption " ++ "context for directory [%s].\n", ++ strerror(errno), salt->key_ref_str, argv[x]); ++ continue; ++ } ++ printf("Key with descriptor [%s] applied to %s.\n", ++ salt->key_ref_str, argv[x]); ++ } ++} ++ ++static void pbkdf2_sha512(const char *passphrase, struct salt *salt, ++ unsigned int count, ++ unsigned char derived_key[EXT4_MAX_KEY_SIZE]) ++{ ++ size_t passphrase_size = strlen(passphrase); ++ unsigned char buf[SHA512_LENGTH + EXT4_MAX_PASSPHRASE_SIZE] = {0}; ++ unsigned char tempbuf[SHA512_LENGTH] = {0}; ++ char final[SHA512_LENGTH] = {0}; ++ unsigned char saltbuf[EXT4_MAX_SALT_SIZE + EXT4_MAX_PASSPHRASE_SIZE] = {0}; ++ int actual_buf_len = SHA512_LENGTH + passphrase_size; ++ int actual_saltbuf_len = EXT4_MAX_SALT_SIZE + passphrase_size; ++ unsigned int x, y; ++ __u32 *final_u32 = (__u32 *)final; ++ __u32 *temp_u32 = (__u32 *)tempbuf; ++ ++ if (passphrase_size > EXT4_MAX_PASSPHRASE_SIZE) { ++ printf("Passphrase size is %zd; max is %d.\n", passphrase_size, ++ EXT4_MAX_PASSPHRASE_SIZE); ++ exit(1); ++ } ++ if (salt->salt_len > EXT4_MAX_SALT_SIZE) { ++ printf("Salt size is %zd; max is %d.\n", salt->salt_len, ++ EXT4_MAX_SALT_SIZE); ++ exit(1); ++ } ++ assert(EXT4_MAX_KEY_SIZE <= SHA512_LENGTH); ++ ++ memcpy(saltbuf, salt->salt, salt->salt_len); ++ memcpy(&saltbuf[EXT4_MAX_SALT_SIZE], passphrase, passphrase_size); ++ ++ memcpy(&buf[SHA512_LENGTH], passphrase, passphrase_size); ++ ++ for (x = 0; x < count; ++x) { ++ if (x == 0) { ++ ext2fs_sha512(saltbuf, actual_saltbuf_len, tempbuf); ++ } else { ++ /* ++ * buf: [previous hash || passphrase] ++ */ ++ memcpy(buf, tempbuf, SHA512_LENGTH); ++ ext2fs_sha512(buf, actual_buf_len, tempbuf); ++ } ++ for (y = 0; y < (sizeof(final) / sizeof(*final_u32)); ++y) ++ final_u32[y] = final_u32[y] ^ temp_u32[y]; ++ } ++ memcpy(derived_key, final, EXT4_MAX_KEY_SIZE); ++} ++ ++static int disable_echo(struct termios *saved_settings) ++{ ++ struct termios current_settings; ++ int rc = 0; ++ ++ rc = tcgetattr(0, ¤t_settings); ++ if (rc) ++ return rc; ++ *saved_settings = current_settings; ++ current_settings.c_lflag &= ~ECHO; ++ rc = tcsetattr(0, TCSANOW, ¤t_settings); ++ ++ return rc; ++} ++ ++static void get_passphrase(char *passphrase, int len) ++{ ++ char *p; ++ struct termios current_settings; ++ ++ assert(len > 0); ++ disable_echo(¤t_settings); ++ p = fgets(passphrase, len, stdin); ++ tcsetattr(0, TCSANOW, ¤t_settings); ++ printf("\n"); ++ if (!p) { ++ printf("Aborting.\n"); ++ exit(1); ++ } ++ p = strrchr(passphrase, '\n'); ++ if (!p) ++ p = passphrase + len - 1; ++ *p = '\0'; ++} ++ ++struct keyring_map { ++ char name[4]; ++ size_t name_len; ++ int code; ++}; ++ ++static const struct keyring_map keyrings[] = { ++ {"@us", 3, KEY_SPEC_USER_SESSION_KEYRING}, ++ {"@u", 2, KEY_SPEC_USER_KEYRING}, ++ {"@s", 2, KEY_SPEC_SESSION_KEYRING}, ++ {"@g", 2, KEY_SPEC_GROUP_KEYRING}, ++ {"@p", 2, KEY_SPEC_PROCESS_KEYRING}, ++ {"@t", 2, KEY_SPEC_THREAD_KEYRING}, ++}; ++ ++static int get_keyring_id(const char *keyring) ++{ ++ unsigned int x; ++ char *end; ++ ++ /* ++ * If no keyring is specified, by default use either the user ++ * session key ring or the session keyring. Fetching the ++ * session keyring will return the user session keyring if no ++ * session keyring has been set. ++ * ++ * We need to do this instead of simply adding the key to ++ * KEY_SPEC_SESSION_KEYRING since trying to add a key to a ++ * session keyring that does not yet exist will cause the ++ * kernel to create a session keyring --- which wil then get ++ * garbage collected as soon as e4crypt exits. ++ * ++ * The fact that the keyctl system call and the add_key system ++ * call treats KEY_SPEC_SESSION_KEYRING differently when a ++ * session keyring does not exist is very unfortunate and ++ * confusing, but so it goes... ++ */ ++ if (keyring == NULL) ++ return keyctl(KEYCTL_GET_KEYRING_ID, ++ KEY_SPEC_SESSION_KEYRING, 0); ++ for (x = 0; x < (sizeof(keyrings) / sizeof(keyrings[0])); ++x) { ++ if (strcmp(keyring, keyrings[x].name) == 0) { ++ return keyrings[x].code; ++ } ++ } ++ x = strtoul(keyring, &end, 10); ++ if (*end == '\0') { ++ if (keyctl(KEYCTL_DESCRIBE, x, NULL, 0) < 0) ++ return 0; ++ return x; ++ } ++ return 0; ++} ++ ++static void generate_key_ref_str(struct salt *salt) ++{ ++ unsigned char key_ref1[SHA512_LENGTH]; ++ unsigned char key_ref2[SHA512_LENGTH]; ++ int x; ++ ++ ext2fs_sha512(salt->key, EXT4_MAX_KEY_SIZE, key_ref1); ++ ext2fs_sha512(key_ref1, SHA512_LENGTH, key_ref2); ++ memcpy(salt->key_desc, key_ref2, EXT4_KEY_DESCRIPTOR_SIZE); ++ for (x = 0; x < EXT4_KEY_DESCRIPTOR_SIZE; ++x) { ++ sprintf(&salt->key_ref_str[x * 2], "%02x", ++ salt->key_desc[x]); ++ } ++ salt->key_ref_str[EXT4_KEY_REF_STR_BUF_SIZE - 1] = '\0'; ++} ++ ++static void insert_key_into_keyring(const char *keyring, struct salt *salt) ++{ ++ int keyring_id = get_keyring_id(keyring); ++ struct ext4_encryption_key key; ++ char key_ref_full[EXT2FS_KEY_DESC_PREFIX_SIZE + ++ EXT4_KEY_REF_STR_BUF_SIZE]; ++ int rc; ++ ++ if (keyring_id == 0) { ++ printf("Invalid keyring [%s].\n", keyring); ++ exit(1); ++ } ++ sprintf(key_ref_full, "%s%s", EXT2FS_KEY_DESC_PREFIX, ++ salt->key_ref_str); ++ rc = keyctl(KEYCTL_SEARCH, keyring_id, EXT2FS_KEY_TYPE_LOGON, ++ key_ref_full, 0); ++ if (rc != -1) { ++ if ((options & OPT_QUIET) == 0) ++ printf("Key with descriptor [%s] already exists\n", ++ salt->key_ref_str); ++ return; ++ } else if ((rc == -1) && (errno != ENOKEY)) { ++ printf("keyctl_search failed: %s\n", strerror(errno)); ++ if (errno == -EINVAL) ++ printf("Keyring [%s] is not available.\n", keyring); ++ exit(1); ++ } ++ key.mode = EXT4_ENCRYPTION_MODE_AES_256_XTS; ++ memcpy(key.raw, salt->key, EXT4_MAX_KEY_SIZE); ++ key.size = EXT4_MAX_KEY_SIZE; ++ rc = add_key(EXT2FS_KEY_TYPE_LOGON, key_ref_full, (void *)&key, ++ sizeof(key), keyring_id); ++ if (rc == -1) { ++ if (errno == EDQUOT) { ++ printf("Error adding key to keyring; quota exceeded\n"); ++ } else { ++ printf("Error adding key with key descriptor [%s]: " ++ "%s\n", salt->key_ref_str, strerror(errno)); ++ } ++ exit(1); ++ } else { ++ if ((options & OPT_QUIET) == 0) ++ printf("Added key with descriptor [%s]\n", ++ salt->key_ref_str); ++ } ++} ++ ++static void get_default_salts(void) ++{ ++ FILE *f = setmntent("/etc/mtab", "r"); ++ struct mntent *mnt; ++ ++ while (f && ((mnt = getmntent(f)) != NULL)) { ++ if (strcmp(mnt->mnt_type, "ext4") || ++ access(mnt->mnt_dir, R_OK)) ++ continue; ++ parse_salt(mnt->mnt_dir, PARSE_FLAGS_NOTSUPP_OK); ++ } ++ endmntent(f); ++} ++ ++/* Functions which implement user commands */ ++ ++struct cmd_desc { ++ const char *cmd_name; ++ void (*cmd_func)(int, char **, const struct cmd_desc *); ++ const char *cmd_desc; ++ const char *cmd_help; ++ int cmd_flags; ++}; ++ ++#define CMD_HIDDEN 0x0001 ++ ++static void do_help(int argc, char **argv, const struct cmd_desc *cmd); ++ ++#define add_key_desc "adds a key to the user's keyring" ++#define add_key_help \ ++"e4crypt add_key -S salt [ -k keyring ] [-v] [-q] [ path ... ]\n\n" \ ++"Prompts the user for a passphrase and inserts it into the specified\n" \ ++"keyring. If no keyring is specified, e4crypt will use the session\n" \ ++"keyring if it exists or the user session keyring if it does not.\n\n" \ ++"If one or more directory paths are specified, e4crypt will try to\n" \ ++"set the policy of those directories to use the key just entered by\n" \ ++"the user.\n" ++ ++static void do_add_key(int argc, char **argv, const struct cmd_desc *cmd) ++{ ++ struct salt *salt; ++ char *keyring = NULL; ++ int i, opt, pad = 4; ++ unsigned j; ++ ++ while ((opt = getopt(argc, argv, "k:S:p:vq")) != -1) { ++ switch (opt) { ++ case 'k': ++ /* Specify a keyring. */ ++ keyring = optarg; ++ break; ++ case 'p': ++ pad = atoi(optarg); ++ break; ++ case 'S': ++ /* Salt value for passphrase. */ ++ parse_salt(optarg, 0); ++ break; ++ case 'v': ++ options |= OPT_VERBOSE; ++ break; ++ case 'q': ++ options |= OPT_QUIET; ++ break; ++ default: ++ fprintf(stderr, "Unrecognized option: %c\n", opt); ++ case '?': ++ fputs("USAGE:\n ", stderr); ++ fputs(cmd->cmd_help, stderr); ++ exit(1); ++ } ++ } ++ if (num_salt == 0) ++ get_default_salts(); ++ if (num_salt == 0) { ++ fprintf(stderr, "No salt values available\n"); ++ exit(1); ++ } ++ validate_paths(argc, argv, optind); ++ for (i = optind; i < argc; i++) ++ parse_salt(argv[i], PARSE_FLAGS_FORCE_FN); ++ printf("Enter passphrase (echo disabled): "); ++ get_passphrase(in_passphrase, sizeof(in_passphrase)); ++ for (j = 0, salt = salt_list; j < num_salt; j++, salt++) { ++ pbkdf2_sha512(in_passphrase, salt, ++ EXT4_PBKDF2_ITERATIONS, salt->key); ++ generate_key_ref_str(salt); ++ insert_key_into_keyring(keyring, salt); ++ } ++ if (optind != argc) ++ set_policy(NULL, pad, argc, argv, optind); ++ clear_secrets(); ++ exit(0); ++} ++ ++#define set_policy_desc "sets a policy for directories" ++#define set_policy_help \ ++"e4crypt set_policy policy path ... \n\n" \ ++"Sets the policy for the directories specified on the command line.\n" \ ++"All directories must be empty to set the policy; if the directory\n" \ ++"already has a policy established, e4crypt will validate that it the\n" \ ++"policy matches what was specified. A policy is an encryption key\n" \ ++"identifier consisting of 16 hexadecimal characters.\n" ++ ++static void do_set_policy(int argc, char **argv, const struct cmd_desc *cmd) ++{ ++ struct salt saltbuf; ++ int c, pad = 4; ++ ++ while ((c = getopt (argc, argv, "p:")) != EOF) { ++ switch (c) { ++ case 'p': ++ pad = atoi(optarg); ++ break; ++ } ++ } ++ ++ if (argc < optind + 2) { ++ fprintf(stderr, "Missing required argument(s).\n\n"); ++ fputs("USAGE:\n ", stderr); ++ fputs(cmd->cmd_help, stderr); ++ exit(1); ++ } ++ ++ printf("arg %s\n", argv[optind]); ++ exit(0); ++ ++ strcpy(saltbuf.key_ref_str, argv[optind]); ++ if ((strlen(argv[optind]) != (EXT4_KEY_DESCRIPTOR_SIZE * 2)) || ++ hex2byte(argv[optind], (EXT4_KEY_DESCRIPTOR_SIZE * 2), ++ saltbuf.key_desc, EXT4_KEY_DESCRIPTOR_SIZE)) { ++ printf("Invalid key descriptor [%s]. Valid characters " ++ "are 0-9 and a-f, lower case. " ++ "Length must be %d.\n", ++ argv[optind], (EXT4_KEY_DESCRIPTOR_SIZE * 2)); ++ exit(1); ++ } ++ validate_paths(argc, argv, optind+1); ++ set_policy(&saltbuf, pad, argc, argv, optind+1); ++ exit(0); ++} ++ ++#define get_policy_desc "get the encryption for directories" ++#define get_policy_help \ ++"e4crypt get_policy path ... \n\n" \ ++"Gets the policy for the directories specified on the command line.\n" ++ ++static void do_get_policy(int argc, char **argv, const struct cmd_desc *cmd) ++{ ++ struct ext4_encryption_policy policy; ++ struct stat st; ++ int i, j, fd, rc; ++ ++ if (argc < 2) { ++ fprintf(stderr, "Missing required argument(s).\n\n"); ++ fputs("USAGE:\n ", stderr); ++ fputs(cmd->cmd_help, stderr); ++ exit(1); ++ } ++ ++ for (i = 1; i < argc; i++) { ++ if (stat(argv[i], &st) < 0) { ++ perror(argv[i]); ++ continue; ++ } ++ fd = open(argv[i], ++ S_ISDIR(st.st_mode) ? O_DIRECTORY : O_RDONLY); ++ if (fd == -1) { ++ perror(argv[i]); ++ exit(1); ++ } ++ rc = ioctl(fd, EXT4_IOC_GET_ENCRYPTION_POLICY, &policy); ++ close(fd); ++ if (rc) { ++ printf("Error getting policy for %s: %s\n", ++ argv[i], strerror(errno)); ++ continue; ++ } ++ printf("%s: ", argv[i]); ++ for (j = 0; j < EXT4_KEY_DESCRIPTOR_SIZE; j++) { ++ printf("%02x", (unsigned char) policy.master_key_descriptor[j]); ++ } ++ fputc('\n', stdout); ++ } ++ exit(0); ++} ++ ++#define new_session_desc "given the invoking process a new session keyring" ++#define new_session_help \ ++"e4crypt new_sessoin\n\n" \ ++"Give the invoking process (typically a shell) a new session keyring,\n" \ ++"discarding its old session keyring.\n" ++ ++static void do_new_session(int argc, char **argv EXT2FS_ATTR((unused)), ++ const struct cmd_desc *cmd) ++{ ++ long keyid, ret; ++ ++ if (argc > 1) { ++ fputs("Excess arguments\n\n", stderr); ++ fputs(cmd->cmd_help, stderr); ++ exit(1); ++ } ++ keyid = keyctl(KEYCTL_JOIN_SESSION_KEYRING, NULL); ++ if (keyid < 0) { ++ perror("KEYCTL_JOIN_SESSION_KEYRING"); ++ exit(1); ++ } ++ ret = keyctl(KEYCTL_SESSION_TO_PARENT, NULL); ++ if (ret < 0) { ++ perror("KEYCTL_SESSION_TO_PARENT"); ++ exit(1); ++ } ++ printf("Switched invoking process to new session keyring %ld\n", keyid); ++ exit(0); ++} ++ ++#define CMD(name) { #name, do_##name, name##_desc, name##_help, 0 } ++#define _CMD(name) { #name, do_##name, NULL, NULL, CMD_HIDDEN } ++ ++const struct cmd_desc cmd_list[] = { ++ _CMD(help), ++ CMD(add_key), ++ CMD(get_policy), ++ CMD(new_session), ++ CMD(set_policy), ++ { NULL, NULL, NULL, NULL, 0 } ++}; ++ ++static void do_help(int argc, char **argv, ++ const struct cmd_desc *cmd EXT2FS_ATTR((unused))) ++{ ++ const struct cmd_desc *p; ++ ++ if (argc > 1) { ++ for (p = cmd_list; p->cmd_name; p++) { ++ if (p->cmd_flags & CMD_HIDDEN) ++ continue; ++ if (strcmp(p->cmd_name, argv[1]) == 0) { ++ putc('\n', stdout); ++ fputs("USAGE:\n ", stdout); ++ fputs(p->cmd_help, stdout); ++ exit(0); ++ } ++ } ++ printf("Unknown command: %s\n\n", argv[1]); ++ } ++ ++ fputs("Available commands:\n", stdout); ++ for (p = cmd_list; p->cmd_name; p++) { ++ if (p->cmd_flags & CMD_HIDDEN) ++ continue; ++ printf(" %-20s %s\n", p->cmd_name, p->cmd_desc); ++ } ++ printf("\nTo get more information on a commnd, " ++ "type 'e4crypt help cmd'\n"); ++ exit(0); ++} ++ ++int main(int argc, char *argv[]) ++{ ++ const struct cmd_desc *cmd; ++ ++ if (argc < 2) ++ do_help(argc, argv, cmd_list); ++ ++ sigcatcher_setup(); ++ for (cmd = cmd_list; cmd->cmd_name; cmd++) { ++ if (strcmp(cmd->cmd_name, argv[1]) == 0) { ++ cmd->cmd_func(argc-1, argv+1, cmd); ++ exit(0); ++ } ++ } ++ printf("Unknown command: %s\n\n", argv[1]); ++ do_help(1, argv, cmd_list); ++ return 0; ++} +--- a/misc/e4defrag.c ++++ b/misc/e4defrag.c +@@ -387,8 +387,10 @@ + *page_num = 0; + *page_num = (length + pagesize - 1) / pagesize; + *vec = (unsigned char *)calloc(*page_num, 1); +- if (*vec == NULL) ++ if (*vec == NULL) { ++ munmap(page, length); + return -1; ++ } + + /* Get information on whether pages are in core */ + if (mincore(page, (size_t)length, *vec) == -1 || +--- a/misc/ext4.5.in ++++ b/misc/ext4.5.in +@@ -149,6 +149,9 @@ + 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 +@@ -199,17 +202,17 @@ + This ext4 feature provides multiple mount protection (MMP). MMP helps to + protect the filesystem from being multiply mounted and is useful in + shared storage environments. +-@QUOTA_MAN_COMMENT@.TP +-@QUOTA_MAN_COMMENT@.B quota +-@QUOTA_MAN_COMMENT@.br +-@QUOTA_MAN_COMMENT@Create quota inodes (inode #3 for userquota and inode +-@QUOTA_MAN_COMMENT@#4 for group quota) and set them in the superblock. +-@QUOTA_MAN_COMMENT@With this feature, the quotas will be enabled +-@QUOTA_MAN_COMMENT@automatically when the filesystem is mounted. +-@QUOTA_MAN_COMMENT@.IP +-@QUOTA_MAN_COMMENT@Causes the quota files (i.e., user.quota and +-@QUOTA_MAN_COMMENT@group.quota which existed +-@QUOTA_MAN_COMMENT@in the older quota design) to be hidden inodes. ++.TP ++.B quota ++.br ++Create quota inodes (inode #3 for userquota and inode ++#4 for group quota) and set them in the superblock. ++With this feature, the quotas will be enabled ++automatically when the filesystem is mounted. ++.IP ++Causes the quota files (i.e., user.quota and ++group.quota which existed ++in the older quota design) to be hidden inodes. + .TP + .B resize_inode + .br +--- a/misc/filefrag.c ++++ b/misc/filefrag.c +@@ -20,7 +20,13 @@ + exit(EXIT_FAILURE); + } + #else ++#ifndef _LARGEFILE_SOURCE ++#define _LARGEFILE_SOURCE ++#endif ++#ifndef _LARGEFILE64_SOURCE + #define _LARGEFILE64_SOURCE ++#endif ++ + + #include + #include +@@ -181,7 +187,8 @@ + print_flag(&fe_flags, mask, flags, hex); + } + +- if (fm_extent->fe_logical + fm_extent->fe_length >= st->st_size) ++ if (fm_extent->fe_logical + fm_extent->fe_length >= ++ (unsigned long long) st->st_size) + strcat(flags, "eof,"); + + /* Remove trailing comma, if any */ +@@ -198,7 +205,7 @@ + static int filefrag_fiemap(int fd, int blk_shift, int *num_extents, + ext2fs_struct_stat *st) + { +- char buf[16384]; ++ __u64 buf[2048]; /* __u64 for proper field alignment */ + struct fiemap *fiemap = (struct fiemap *)buf; + struct fiemap_extent *fm_ext = &fiemap->fm_extents[0]; + int count = (sizeof(buf) - sizeof(*fiemap)) / +@@ -287,8 +294,8 @@ + const long bpib = st->st_blksize / 4; + int count; + ++ memset(&fm_ext, 0, sizeof(fm_ext)); + if (force_extent) { +- memset(&fm_ext, 0, sizeof(fm_ext)); + fm_ext.fe_flags = FIEMAP_EXTENT_MERGED; + } + +@@ -331,15 +338,17 @@ + blk_shift, st); + fm_ext.fe_length = 0; + (*num_extents)++; ++ fm_ext.fe_logical = logical; ++ fm_ext.fe_physical = block * st->st_blksize; + } else if (last_block && (block != last_block + 1)) { + if (verbose) + printf("Discontinuity: Block %ld is at %lu (was " + "%lu)\n", i, block, last_block + 1); + fm_ext.fe_length = 0; + (*num_extents)++; ++ fm_ext.fe_logical = logical; ++ fm_ext.fe_physical = block * st->st_blksize; + } +- fm_ext.fe_logical = logical; +- fm_ext.fe_physical = block * st->st_blksize; + fm_ext.fe_length += st->st_blksize; + last_block = block; + } +--- a/misc/findsuper.c ++++ b/misc/findsuper.c +@@ -94,7 +94,7 @@ + + #include "ext2fs/ext2_fs.h" + #include "ext2fs/ext2fs.h" +-#include "nls-enable.h" ++#include "support/nls-enable.h" + + #undef DEBUG + +--- a/misc/fsck.c ++++ b/misc/fsck.c +@@ -59,7 +59,7 @@ + #endif + + #include "../version.h" +-#include "nls-enable.h" ++#include "support/nls-enable.h" + #include "fsck.h" + #include "blkid/blkid.h" + +--- /dev/null ++++ b/misc/fuse2fs.c +@@ -0,0 +1,3919 @@ ++/* ++ * fuse2fs.c - FUSE server for e2fsprogs. ++ * ++ * Copyright (C) 2014 Oracle. ++ * ++ * %Begin-Header% ++ * This file may be redistributed under the terms of the GNU Public ++ * License. ++ * %End-Header% ++ */ ++#define _FILE_OFFSET_BITS 64 ++#define FUSE_USE_VERSION 29 ++#ifndef _GNU_SOURCE ++#define _GNU_SOURCE ++#endif ++#include "config.h" ++#include ++#ifdef __linux__ ++# include ++# include ++# include ++# define FUSE_PLATFORM_OPTS ",nonempty,big_writes" ++# ifdef HAVE_SYS_ACL_H ++# define TRANSLATE_LINUX_ACLS ++# endif ++#else ++# define FUSE_PLATFORM_OPTS "" ++#endif ++#ifdef TRANSLATE_LINUX_ACLS ++# include ++#endif ++#include ++#include ++#include ++#include ++#include "ext2fs/ext2fs.h" ++#include "ext2fs/ext2_fs.h" ++ ++#ifdef ENABLE_NLS ++#include ++#include ++#define _(a) (gettext(a)) ++#ifdef gettext_noop ++#define N_(a) gettext_noop(a) ++#else ++#define N_(a) (a) ++#endif ++#define P_(singular, plural, n) (ngettext(singular, plural, n)) ++#ifndef NLS_CAT_NAME ++#define NLS_CAT_NAME "e2fsprogs" ++#endif ++#ifndef LOCALEDIR ++#define LOCALEDIR "/usr/share/locale" ++#endif ++#else ++#define _(a) (a) ++#define N_(a) a ++#define P_(singular, plural, n) ((n) == 1 ? (singular) : (plural)) ++#endif ++ ++static ext2_filsys global_fs; /* Try not to use this directly */ ++ ++#undef DEBUG ++ ++#ifdef DEBUG ++# define dbg_printf(f, a...) do {printf("FUSE2FS-" f, ## a); \ ++ fflush(stdout); \ ++} while (0) ++#else ++# define dbg_printf(f, a...) ++#endif ++ ++#if FUSE_VERSION >= FUSE_MAKE_VERSION(2, 8) ++# ifdef _IOR ++# ifdef _IOW ++# define SUPPORT_I_FLAGS ++# endif ++# endif ++#endif ++ ++#ifdef FALLOC_FL_KEEP_SIZE ++# define FL_KEEP_SIZE_FLAG FALLOC_FL_KEEP_SIZE ++# define SUPPORT_FALLOCATE ++#else ++# define FL_KEEP_SIZE_FLAG (0) ++#endif ++ ++#ifdef FALLOC_FL_PUNCH_HOLE ++# define FL_PUNCH_HOLE_FLAG FALLOC_FL_PUNCH_HOLE ++#else ++# define FL_PUNCH_HOLE_FLAG (0) ++#endif ++ ++errcode_t ext2fs_run_ext3_journal(ext2_filsys *fs); ++ ++/* ACL translation stuff */ ++#ifdef TRANSLATE_LINUX_ACLS ++/* ++ * Copied from acl_ea.h in libacl source; ACLs have to be sent to and from fuse ++ * in this format... at least on Linux. ++ */ ++#define ACL_EA_ACCESS "system.posix_acl_access" ++#define ACL_EA_DEFAULT "system.posix_acl_default" ++ ++#define ACL_EA_VERSION 0x0002 ++ ++typedef struct { ++ u_int16_t e_tag; ++ u_int16_t e_perm; ++ u_int32_t e_id; ++} acl_ea_entry; ++ ++typedef struct { ++ u_int32_t a_version; ++ acl_ea_entry a_entries[0]; ++} acl_ea_header; ++ ++static inline size_t acl_ea_size(int count) ++{ ++ return sizeof(acl_ea_header) + count * sizeof(acl_ea_entry); ++} ++ ++static inline int acl_ea_count(size_t size) ++{ ++ if (size < sizeof(acl_ea_header)) ++ return -1; ++ size -= sizeof(acl_ea_header); ++ if (size % sizeof(acl_ea_entry)) ++ return -1; ++ return size / sizeof(acl_ea_entry); ++} ++ ++/* ++ * ext4 ACL structures, copied from fs/ext4/acl.h. ++ */ ++#define EXT4_ACL_VERSION 0x0001 ++ ++typedef struct { ++ __u16 e_tag; ++ __u16 e_perm; ++ __u32 e_id; ++} ext4_acl_entry; ++ ++typedef struct { ++ __u16 e_tag; ++ __u16 e_perm; ++} ext4_acl_entry_short; ++ ++typedef struct { ++ __u32 a_version; ++} ext4_acl_header; ++ ++static inline size_t ext4_acl_size(int count) ++{ ++ if (count <= 4) { ++ return sizeof(ext4_acl_header) + ++ count * sizeof(ext4_acl_entry_short); ++ } else { ++ return sizeof(ext4_acl_header) + ++ 4 * sizeof(ext4_acl_entry_short) + ++ (count - 4) * sizeof(ext4_acl_entry); ++ } ++} ++ ++static inline int ext4_acl_count(size_t size) ++{ ++ ssize_t s; ++ ++ size -= sizeof(ext4_acl_header); ++ s = size - 4 * sizeof(ext4_acl_entry_short); ++ if (s < 0) { ++ if (size % sizeof(ext4_acl_entry_short)) ++ return -1; ++ return size / sizeof(ext4_acl_entry_short); ++ } ++ if (s % sizeof(ext4_acl_entry)) ++ return -1; ++ return s / sizeof(ext4_acl_entry) + 4; ++} ++ ++static errcode_t fuse_to_ext4_acl(acl_ea_header *facl, size_t facl_sz, ++ ext4_acl_header **eacl, size_t *eacl_sz) ++{ ++ int i, facl_count; ++ ext4_acl_header *h; ++ size_t h_sz; ++ ext4_acl_entry *e; ++ acl_ea_entry *a; ++ unsigned char *hptr; ++ errcode_t err; ++ ++ facl_count = acl_ea_count(facl_sz); ++ h_sz = ext4_acl_size(facl_count); ++ if (facl_count < 0 || facl->a_version != ACL_EA_VERSION) ++ return EXT2_ET_INVALID_ARGUMENT; ++ ++ err = ext2fs_get_mem(h_sz, &h); ++ if (err) ++ return err; ++ ++ h->a_version = ext2fs_cpu_to_le32(EXT4_ACL_VERSION); ++ hptr = (unsigned char *) (h + 1); ++ for (i = 0, a = facl->a_entries; i < facl_count; i++, a++) { ++ e = (ext4_acl_entry *) hptr; ++ e->e_tag = ext2fs_cpu_to_le16(a->e_tag); ++ e->e_perm = ext2fs_cpu_to_le16(a->e_perm); ++ ++ switch (a->e_tag) { ++ case ACL_USER: ++ case ACL_GROUP: ++ e->e_id = ext2fs_cpu_to_le32(a->e_id); ++ hptr += sizeof(ext4_acl_entry); ++ break; ++ case ACL_USER_OBJ: ++ case ACL_GROUP_OBJ: ++ case ACL_MASK: ++ case ACL_OTHER: ++ hptr += sizeof(ext4_acl_entry_short); ++ break; ++ default: ++ err = EXT2_ET_INVALID_ARGUMENT; ++ goto out; ++ } ++ } ++ ++ *eacl = h; ++ *eacl_sz = h_sz; ++ return err; ++out: ++ ext2fs_free_mem(&h); ++ return err; ++} ++ ++static errcode_t ext4_to_fuse_acl(acl_ea_header **facl, size_t *facl_sz, ++ ext4_acl_header *eacl, size_t eacl_sz) ++{ ++ int i, eacl_count; ++ acl_ea_header *f; ++ ext4_acl_entry *e; ++ acl_ea_entry *a; ++ size_t f_sz; ++ unsigned char *hptr; ++ errcode_t err; ++ ++ eacl_count = ext4_acl_count(eacl_sz); ++ f_sz = acl_ea_size(eacl_count); ++ if (eacl_count < 0 || ++ eacl->a_version != ext2fs_cpu_to_le32(EXT4_ACL_VERSION)) ++ return EXT2_ET_INVALID_ARGUMENT; ++ ++ err = ext2fs_get_mem(f_sz, &f); ++ if (err) ++ return err; ++ ++ f->a_version = ACL_EA_VERSION; ++ hptr = (unsigned char *) (eacl + 1); ++ for (i = 0, a = f->a_entries; i < eacl_count; i++, a++) { ++ e = (ext4_acl_entry *) hptr; ++ a->e_tag = ext2fs_le16_to_cpu(e->e_tag); ++ a->e_perm = ext2fs_le16_to_cpu(e->e_perm); ++ ++ switch (a->e_tag) { ++ case ACL_USER: ++ case ACL_GROUP: ++ a->e_id = ext2fs_le32_to_cpu(e->e_id); ++ hptr += sizeof(ext4_acl_entry); ++ break; ++ case ACL_USER_OBJ: ++ case ACL_GROUP_OBJ: ++ case ACL_MASK: ++ case ACL_OTHER: ++ hptr += sizeof(ext4_acl_entry_short); ++ break; ++ default: ++ err = EXT2_ET_INVALID_ARGUMENT; ++ goto out; ++ } ++ } ++ ++ *facl = f; ++ *facl_sz = f_sz; ++ return err; ++out: ++ ext2fs_free_mem(&f); ++ return err; ++} ++#endif /* TRANSLATE_LINUX_ACLS */ ++ ++/* ++ * ext2_file_t contains a struct inode, so we can't leave files open. ++ * Use this as a proxy instead. ++ */ ++#define FUSE2FS_FILE_MAGIC (0xEF53DEAFUL) ++struct fuse2fs_file_handle { ++ unsigned long magic; ++ ext2_ino_t ino; ++ int open_flags; ++}; ++ ++/* Main program context */ ++#define FUSE2FS_MAGIC (0xEF53DEADUL) ++struct fuse2fs { ++ unsigned long magic; ++ ext2_filsys fs; ++ pthread_mutex_t bfl; ++ int panic_on_error; ++ int minixdf; ++ int alloc_all_blocks; ++ FILE *err_fp; ++ unsigned int next_generation; ++}; ++ ++#define FUSE2FS_CHECK_MAGIC(fs, ptr, num) do {if ((ptr)->magic != (num)) \ ++ return translate_error((fs), 0, EXT2_ET_MAGIC_EXT2_FILE); \ ++} while (0) ++ ++#define FUSE2FS_CHECK_CONTEXT(ptr) do {if ((ptr)->magic != FUSE2FS_MAGIC) \ ++ return translate_error(global_fs, 0, EXT2_ET_BAD_MAGIC); \ ++} while (0) ++ ++static int __translate_error(ext2_filsys fs, errcode_t err, ext2_ino_t ino, ++ const char *file, int line); ++#define translate_error(fs, ino, err) __translate_error((fs), (err), (ino), \ ++ __FILE__, __LINE__) ++ ++/* for macosx */ ++#ifndef W_OK ++# define W_OK 2 ++#endif ++ ++#ifndef R_OK ++# define R_OK 4 ++#endif ++ ++#define EXT4_EPOCH_BITS 2 ++#define EXT4_EPOCH_MASK ((1 << EXT4_EPOCH_BITS) - 1) ++#define EXT4_NSEC_MASK (~0UL << EXT4_EPOCH_BITS) ++ ++/* ++ * Extended fields will fit into an inode if the filesystem was formatted ++ * with large inodes (-I 256 or larger) and there are not currently any EAs ++ * consuming all of the available space. For new inodes we always reserve ++ * enough space for the kernel's known extended fields, but for inodes ++ * created with an old kernel this might not have been the case. None of ++ * the extended inode fields is critical for correct filesystem operation. ++ * This macro checks if a certain field fits in the inode. Note that ++ * inode-size = GOOD_OLD_INODE_SIZE + i_extra_isize ++ */ ++#define EXT4_FITS_IN_INODE(ext4_inode, field) \ ++ ((offsetof(typeof(*ext4_inode), field) + \ ++ sizeof((ext4_inode)->field)) \ ++ <= ((size_t) EXT2_GOOD_OLD_INODE_SIZE + \ ++ (ext4_inode)->i_extra_isize)) \ ++ ++static inline __u32 ext4_encode_extra_time(const struct timespec *time) ++{ ++ __u32 extra = sizeof(time->tv_sec) > 4 ? ++ ((time->tv_sec - (__s32)time->tv_sec) >> 32) & ++ EXT4_EPOCH_MASK : 0; ++ return extra | (time->tv_nsec << EXT4_EPOCH_BITS); ++} ++ ++static inline void ext4_decode_extra_time(struct timespec *time, __u32 extra) ++{ ++ if (sizeof(time->tv_sec) > 4 && (extra & EXT4_EPOCH_MASK)) { ++ __u64 extra_bits = extra & EXT4_EPOCH_MASK; ++ /* ++ * Prior to kernel 3.14?, we had a broken decode function, ++ * wherein we effectively did this: ++ * if (extra_bits == 3) ++ * extra_bits = 0; ++ */ ++ time->tv_sec += extra_bits << 32; ++ } ++ time->tv_nsec = ((extra) & EXT4_NSEC_MASK) >> EXT4_EPOCH_BITS; ++} ++ ++#define EXT4_INODE_SET_XTIME(xtime, timespec, raw_inode) \ ++do { \ ++ (raw_inode)->xtime = (timespec)->tv_sec; \ ++ if (EXT4_FITS_IN_INODE(raw_inode, xtime ## _extra)) \ ++ (raw_inode)->xtime ## _extra = \ ++ ext4_encode_extra_time(timespec); \ ++} while (0) ++ ++#define EXT4_EINODE_SET_XTIME(xtime, timespec, raw_inode) \ ++do { \ ++ if (EXT4_FITS_IN_INODE(raw_inode, xtime)) \ ++ (raw_inode)->xtime = (timespec)->tv_sec; \ ++ if (EXT4_FITS_IN_INODE(raw_inode, xtime ## _extra)) \ ++ (raw_inode)->xtime ## _extra = \ ++ ext4_encode_extra_time(timespec); \ ++} while (0) ++ ++#define EXT4_INODE_GET_XTIME(xtime, timespec, raw_inode) \ ++do { \ ++ (timespec)->tv_sec = (signed)((raw_inode)->xtime); \ ++ if (EXT4_FITS_IN_INODE(raw_inode, xtime ## _extra)) \ ++ ext4_decode_extra_time((timespec), \ ++ (raw_inode)->xtime ## _extra); \ ++ else \ ++ (timespec)->tv_nsec = 0; \ ++} while (0) ++ ++#define EXT4_EINODE_GET_XTIME(xtime, timespec, raw_inode) \ ++do { \ ++ if (EXT4_FITS_IN_INODE(raw_inode, xtime)) \ ++ (timespec)->tv_sec = \ ++ (signed)((raw_inode)->xtime); \ ++ if (EXT4_FITS_IN_INODE(raw_inode, xtime ## _extra)) \ ++ ext4_decode_extra_time((timespec), \ ++ raw_inode->xtime ## _extra); \ ++ else \ ++ (timespec)->tv_nsec = 0; \ ++} while (0) ++ ++static void get_now(struct timespec *now) ++{ ++#ifdef CLOCK_REALTIME ++ if (!clock_gettime(CLOCK_REALTIME, now)) ++ return; ++#endif ++ ++ now->tv_sec = time(NULL); ++ now->tv_nsec = 0; ++} ++ ++static void increment_version(struct ext2_inode_large *inode) ++{ ++ __u64 ver; ++ ++ ver = inode->osd1.linux1.l_i_version; ++ if (EXT4_FITS_IN_INODE(inode, i_version_hi)) ++ ver |= (__u64)inode->i_version_hi << 32; ++ ver++; ++ inode->osd1.linux1.l_i_version = ver; ++ if (EXT4_FITS_IN_INODE(inode, i_version_hi)) ++ inode->i_version_hi = ver >> 32; ++} ++ ++static void init_times(struct ext2_inode_large *inode) ++{ ++ struct timespec now; ++ ++ get_now(&now); ++ EXT4_INODE_SET_XTIME(i_atime, &now, inode); ++ EXT4_INODE_SET_XTIME(i_ctime, &now, inode); ++ EXT4_INODE_SET_XTIME(i_mtime, &now, inode); ++ EXT4_EINODE_SET_XTIME(i_crtime, &now, inode); ++ increment_version(inode); ++} ++ ++static int update_ctime(ext2_filsys fs, ext2_ino_t ino, ++ struct ext2_inode_large *pinode) ++{ ++ errcode_t err; ++ struct timespec now; ++ struct ext2_inode_large inode; ++ ++ get_now(&now); ++ ++ /* If user already has a inode buffer, just update that */ ++ if (pinode) { ++ increment_version(pinode); ++ EXT4_INODE_SET_XTIME(i_ctime, &now, pinode); ++ return 0; ++ } ++ ++ /* Otherwise we have to read-modify-write the inode */ ++ memset(&inode, 0, sizeof(inode)); ++ err = ext2fs_read_inode_full(fs, ino, (struct ext2_inode *)&inode, ++ sizeof(inode)); ++ if (err) ++ return translate_error(fs, ino, err); ++ ++ increment_version(&inode); ++ EXT4_INODE_SET_XTIME(i_ctime, &now, &inode); ++ ++ err = ext2fs_write_inode_full(fs, ino, (struct ext2_inode *)&inode, ++ sizeof(inode)); ++ if (err) ++ return translate_error(fs, ino, err); ++ ++ return 0; ++} ++ ++static int update_atime(ext2_filsys fs, ext2_ino_t ino) ++{ ++ errcode_t err; ++ struct ext2_inode_large inode, *pinode; ++ struct timespec atime, mtime, now; ++ ++ if (!(fs->flags & EXT2_FLAG_RW)) ++ return 0; ++ memset(&inode, 0, sizeof(inode)); ++ err = ext2fs_read_inode_full(fs, ino, (struct ext2_inode *)&inode, ++ sizeof(inode)); ++ if (err) ++ return translate_error(fs, ino, err); ++ ++ pinode = &inode; ++ EXT4_INODE_GET_XTIME(i_atime, &atime, pinode); ++ EXT4_INODE_GET_XTIME(i_mtime, &mtime, pinode); ++ get_now(&now); ++ /* ++ * If atime is newer than mtime and atime hasn't been updated in thirty ++ * seconds, skip the atime update. Same idea as Linux "relatime". ++ */ ++ if (atime.tv_sec >= mtime.tv_sec && atime.tv_sec >= now.tv_sec - 30) ++ return 0; ++ EXT4_INODE_SET_XTIME(i_atime, &now, &inode); ++ ++ err = ext2fs_write_inode_full(fs, ino, (struct ext2_inode *)&inode, ++ sizeof(inode)); ++ if (err) ++ return translate_error(fs, ino, err); ++ ++ return 0; ++} ++ ++static int update_mtime(ext2_filsys fs, ext2_ino_t ino, ++ struct ext2_inode_large *pinode) ++{ ++ errcode_t err; ++ struct ext2_inode_large inode; ++ struct timespec now; ++ ++ if (pinode) { ++ get_now(&now); ++ EXT4_INODE_SET_XTIME(i_mtime, &now, pinode); ++ EXT4_INODE_SET_XTIME(i_ctime, &now, pinode); ++ increment_version(pinode); ++ return 0; ++ } ++ ++ memset(&inode, 0, sizeof(inode)); ++ err = ext2fs_read_inode_full(fs, ino, (struct ext2_inode *)&inode, ++ sizeof(inode)); ++ if (err) ++ return translate_error(fs, ino, err); ++ ++ get_now(&now); ++ EXT4_INODE_SET_XTIME(i_mtime, &now, &inode); ++ EXT4_INODE_SET_XTIME(i_ctime, &now, &inode); ++ increment_version(&inode); ++ ++ err = ext2fs_write_inode_full(fs, ino, (struct ext2_inode *)&inode, ++ sizeof(inode)); ++ if (err) ++ return translate_error(fs, ino, err); ++ ++ return 0; ++} ++ ++static int ext2_file_type(unsigned int mode) ++{ ++ if (LINUX_S_ISREG(mode)) ++ return EXT2_FT_REG_FILE; ++ ++ if (LINUX_S_ISDIR(mode)) ++ return EXT2_FT_DIR; ++ ++ if (LINUX_S_ISCHR(mode)) ++ return EXT2_FT_CHRDEV; ++ ++ if (LINUX_S_ISBLK(mode)) ++ return EXT2_FT_BLKDEV; ++ ++ if (LINUX_S_ISLNK(mode)) ++ return EXT2_FT_SYMLINK; ++ ++ if (LINUX_S_ISFIFO(mode)) ++ return EXT2_FT_FIFO; ++ ++ if (LINUX_S_ISSOCK(mode)) ++ return EXT2_FT_SOCK; ++ ++ return 0; ++} ++ ++static int fs_can_allocate(struct fuse2fs *ff, blk64_t num) ++{ ++ ext2_filsys fs = ff->fs; ++ blk64_t reserved; ++ ++ dbg_printf("%s: Asking for %llu; alloc_all=%d total=%llu free=%llu " ++ "rsvd=%llu\n", __func__, num, ff->alloc_all_blocks, ++ ext2fs_blocks_count(fs->super), ++ ext2fs_free_blocks_count(fs->super), ++ ext2fs_r_blocks_count(fs->super)); ++ if (num > ext2fs_blocks_count(fs->super)) ++ return 0; ++ ++ if (ff->alloc_all_blocks) ++ return 1; ++ ++ /* ++ * Different meaning for r_blocks -- libext2fs has bugs where the FS ++ * can get corrupted if it totally runs out of blocks. Avoid this ++ * by refusing to allocate any of the reserve blocks to anybody. ++ */ ++ reserved = ext2fs_r_blocks_count(fs->super); ++ if (reserved == 0) ++ reserved = ext2fs_blocks_count(fs->super) / 10; ++ return ext2fs_free_blocks_count(fs->super) > reserved + num; ++} ++ ++static int fs_writeable(ext2_filsys fs) ++{ ++ return (fs->flags & EXT2_FLAG_RW) && (fs->super->s_error_count == 0); ++} ++ ++static int check_inum_access(ext2_filsys fs, ext2_ino_t ino, mode_t mask) ++{ ++ struct fuse_context *ctxt = fuse_get_context(); ++ struct ext2_inode inode; ++ mode_t perms; ++ errcode_t err; ++ ++ /* no writing to read-only or broken fs */ ++ if ((mask & W_OK) && !fs_writeable(fs)) ++ return -EROFS; ++ ++ err = ext2fs_read_inode(fs, ino, &inode); ++ if (err) ++ return translate_error(fs, ino, err); ++ perms = inode.i_mode & 0777; ++ ++ dbg_printf("access ino=%d mask=e%s%s%s perms=0%o fuid=%d fgid=%d " ++ "uid=%d gid=%d\n", ino, ++ (mask & R_OK ? "r" : ""), (mask & W_OK ? "w" : ""), ++ (mask & X_OK ? "x" : ""), perms, inode.i_uid, inode.i_gid, ++ ctxt->uid, ctxt->gid); ++ ++ /* existence check */ ++ if (mask == 0) ++ return 0; ++ ++ /* is immutable? */ ++ if ((mask & W_OK) && ++ (inode.i_flags & EXT2_IMMUTABLE_FL)) ++ return -EACCES; ++ ++ /* Figure out what root's allowed to do */ ++ if (ctxt->uid == 0) { ++ /* Non-file access always ok */ ++ if (!LINUX_S_ISREG(inode.i_mode)) ++ return 0; ++ ++ /* R/W access to a file always ok */ ++ if (!(mask & X_OK)) ++ return 0; ++ ++ /* X access to a file ok if a user/group/other can X */ ++ if (perms & 0111) ++ return 0; ++ ++ /* Trying to execute a file that's not executable. BZZT! */ ++ return -EACCES; ++ } ++ ++ /* allow owner, if perms match */ ++ if (inode.i_uid == ctxt->uid) { ++ if ((mask & (perms >> 6)) == mask) ++ return 0; ++ return -EACCES; ++ } ++ ++ /* allow group, if perms match */ ++ if (inode.i_gid == ctxt->gid) { ++ if ((mask & (perms >> 3)) == mask) ++ return 0; ++ return -EACCES; ++ } ++ ++ /* otherwise check other */ ++ if ((mask & perms) == mask) ++ return 0; ++ return -EACCES; ++} ++ ++static void op_destroy(void *p EXT2FS_ATTR((unused))) ++{ ++ struct fuse_context *ctxt = fuse_get_context(); ++ struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data; ++ ext2_filsys fs; ++ errcode_t err; ++ ++ if (ff->magic != FUSE2FS_MAGIC) { ++ translate_error(global_fs, 0, EXT2_ET_BAD_MAGIC); ++ return; ++ } ++ fs = ff->fs; ++ dbg_printf("%s: dev=%s\n", __func__, fs->device_name); ++ if (fs->flags & EXT2_FLAG_RW) { ++ fs->super->s_state |= EXT2_VALID_FS; ++ if (fs->super->s_error_count) ++ fs->super->s_state |= EXT2_ERROR_FS; ++ ext2fs_mark_super_dirty(fs); ++ err = ext2fs_set_gdt_csum(fs); ++ if (err) ++ translate_error(fs, 0, err); ++ ++ err = ext2fs_flush2(fs, 0); ++ if (err) ++ translate_error(fs, 0, err); ++ } ++} ++ ++static void *op_init(struct fuse_conn_info *conn) ++{ ++ struct fuse_context *ctxt = fuse_get_context(); ++ struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data; ++ ext2_filsys fs; ++ errcode_t err; ++ ++ if (ff->magic != FUSE2FS_MAGIC) { ++ translate_error(global_fs, 0, EXT2_ET_BAD_MAGIC); ++ return NULL; ++ } ++ fs = ff->fs; ++ dbg_printf("%s: dev=%s\n", __func__, fs->device_name); ++#ifdef FUSE_CAP_IOCTL_DIR ++ conn->want |= FUSE_CAP_IOCTL_DIR; ++#endif ++ if (fs->flags & EXT2_FLAG_RW) { ++ fs->super->s_mnt_count++; ++ fs->super->s_mtime = time(NULL); ++ fs->super->s_state &= ~EXT2_VALID_FS; ++ ext2fs_mark_super_dirty(fs); ++ err = ext2fs_flush2(fs, 0); ++ if (err) ++ translate_error(fs, 0, err); ++ } ++ return ff; ++} ++ ++static blkcnt_t blocks_from_inode(ext2_filsys fs, ++ struct ext2_inode_large *inode) ++{ ++ blkcnt_t b; ++ ++ b = inode->i_blocks; ++ if (fs->super->s_feature_ro_compat & EXT4_FEATURE_RO_COMPAT_HUGE_FILE) ++ b += ((long long) inode->osd2.linux2.l_i_blocks_hi) << 32; ++ ++ if (!(fs->super->s_feature_ro_compat & ++ EXT4_FEATURE_RO_COMPAT_HUGE_FILE) || ++ !(inode->i_flags & EXT4_HUGE_FILE_FL)) ++ b *= fs->blocksize / 512; ++ b *= EXT2FS_CLUSTER_RATIO(fs); ++ ++ return b; ++} ++ ++static int stat_inode(ext2_filsys fs, ext2_ino_t ino, struct stat *statbuf) ++{ ++ struct ext2_inode_large inode; ++ dev_t fakedev = 0; ++ errcode_t err; ++ int ret = 0; ++ struct timespec tv; ++ ++ memset(&inode, 0, sizeof(inode)); ++ err = ext2fs_read_inode_full(fs, ino, (struct ext2_inode *)&inode, ++ sizeof(inode)); ++ if (err) ++ return translate_error(fs, ino, err); ++ ++ memcpy(&fakedev, fs->super->s_uuid, sizeof(fakedev)); ++ statbuf->st_dev = fakedev; ++ statbuf->st_ino = ino; ++ statbuf->st_mode = inode.i_mode; ++ statbuf->st_nlink = inode.i_links_count; ++ statbuf->st_uid = inode.i_uid; ++ statbuf->st_gid = inode.i_gid; ++ statbuf->st_size = EXT2_I_SIZE(&inode); ++ statbuf->st_blksize = fs->blocksize; ++ statbuf->st_blocks = blocks_from_inode(fs, &inode); ++ EXT4_INODE_GET_XTIME(i_atime, &tv, &inode); ++ statbuf->st_atime = tv.tv_sec; ++ EXT4_INODE_GET_XTIME(i_mtime, &tv, &inode); ++ statbuf->st_mtime = tv.tv_sec; ++ EXT4_INODE_GET_XTIME(i_ctime, &tv, &inode); ++ statbuf->st_ctime = tv.tv_sec; ++ if (LINUX_S_ISCHR(inode.i_mode) || ++ LINUX_S_ISBLK(inode.i_mode)) { ++ if (inode.i_block[0]) ++ statbuf->st_rdev = inode.i_block[0]; ++ else ++ statbuf->st_rdev = inode.i_block[1]; ++ } ++ ++ return ret; ++} ++ ++static int op_getattr(const char *path, struct stat *statbuf) ++{ ++ struct fuse_context *ctxt = fuse_get_context(); ++ struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data; ++ ext2_filsys fs; ++ ext2_ino_t ino; ++ errcode_t err; ++ int ret = 0; ++ ++ FUSE2FS_CHECK_CONTEXT(ff); ++ fs = ff->fs; ++ dbg_printf("%s: path=%s\n", __func__, path); ++ pthread_mutex_lock(&ff->bfl); ++ err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, path, &ino); ++ if (err) { ++ ret = translate_error(fs, 0, err); ++ goto out; ++ } ++ ret = stat_inode(fs, ino, statbuf); ++out: ++ pthread_mutex_unlock(&ff->bfl); ++ return ret; ++} ++ ++static int op_readlink(const char *path, char *buf, size_t len) ++{ ++ struct fuse_context *ctxt = fuse_get_context(); ++ struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data; ++ ext2_filsys fs; ++ errcode_t err; ++ ext2_ino_t ino; ++ struct ext2_inode inode; ++ unsigned int got; ++ ext2_file_t file; ++ int ret = 0; ++ ++ FUSE2FS_CHECK_CONTEXT(ff); ++ fs = ff->fs; ++ dbg_printf("%s: path=%s\n", __func__, path); ++ pthread_mutex_lock(&ff->bfl); ++ err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, path, &ino); ++ if (err || ino == 0) { ++ ret = translate_error(fs, 0, err); ++ goto out; ++ } ++ ++ err = ext2fs_read_inode(fs, ino, &inode); ++ if (err) { ++ ret = translate_error(fs, ino, err); ++ goto out; ++ } ++ ++ if (!LINUX_S_ISLNK(inode.i_mode)) { ++ ret = -EINVAL; ++ goto out; ++ } ++ ++ len--; ++ if (inode.i_size < len) ++ len = inode.i_size; ++ if (ext2fs_inode_data_blocks2(fs, &inode) || ++ (inode.i_flags & EXT4_INLINE_DATA_FL)) { ++ /* big/inline symlink */ ++ ++ err = ext2fs_file_open(fs, ino, 0, &file); ++ if (err) { ++ ret = translate_error(fs, ino, err); ++ goto out; ++ } ++ ++ err = ext2fs_file_read(file, buf, len, &got); ++ if (err || got != len) { ++ ext2fs_file_close(file); ++ ret = translate_error(fs, ino, err); ++ goto out2; ++ } ++ ++out2: ++ err = ext2fs_file_close(file); ++ if (ret) ++ goto out; ++ if (err) { ++ ret = translate_error(fs, ino, err); ++ goto out; ++ } ++ } else ++ /* inline symlink */ ++ memcpy(buf, (char *)inode.i_block, len); ++ buf[len] = 0; ++ ++ if (fs_writeable(fs)) { ++ ret = update_atime(fs, ino); ++ if (ret) ++ goto out; ++ } ++ ++out: ++ pthread_mutex_unlock(&ff->bfl); ++ return ret; ++} ++ ++static int op_mknod(const char *path, mode_t mode, dev_t dev) ++{ ++ struct fuse_context *ctxt = fuse_get_context(); ++ struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data; ++ ext2_filsys fs; ++ ext2_ino_t parent, child; ++ char *temp_path = strdup(path); ++ errcode_t err; ++ char *node_name, a; ++ int filetype; ++ struct ext2_inode_large inode; ++ int ret = 0; ++ ++ FUSE2FS_CHECK_CONTEXT(ff); ++ fs = ff->fs; ++ dbg_printf("%s: path=%s mode=0%o dev=0x%x\n", __func__, path, mode, ++ (unsigned int)dev); ++ if (!temp_path) { ++ ret = -ENOMEM; ++ goto out; ++ } ++ node_name = strrchr(temp_path, '/'); ++ if (!node_name) { ++ ret = -ENOMEM; ++ goto out; ++ } ++ node_name++; ++ a = *node_name; ++ *node_name = 0; ++ ++ pthread_mutex_lock(&ff->bfl); ++ if (!fs_can_allocate(ff, 2)) { ++ ret = -ENOSPC; ++ goto out2; ++ } ++ ++ err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, temp_path, ++ &parent); ++ if (err) { ++ ret = translate_error(fs, 0, err); ++ goto out2; ++ } ++ ++ ret = check_inum_access(fs, parent, W_OK); ++ if (ret) ++ goto out2; ++ ++ *node_name = a; ++ ++ if (LINUX_S_ISCHR(mode)) ++ filetype = EXT2_FT_CHRDEV; ++ else if (LINUX_S_ISBLK(mode)) ++ filetype = EXT2_FT_BLKDEV; ++ else if (LINUX_S_ISFIFO(mode)) ++ filetype = EXT2_FT_FIFO; ++ else if (LINUX_S_ISSOCK(mode)) ++ filetype = EXT2_FT_SOCK; ++ else { ++ ret = -EINVAL; ++ goto out2; ++ } ++ ++ err = ext2fs_new_inode(fs, parent, mode, 0, &child); ++ if (err) { ++ ret = translate_error(fs, 0, err); ++ goto out2; ++ } ++ ++ dbg_printf("%s: create ino=%d/name=%s in dir=%d\n", __func__, child, ++ node_name, parent); ++ err = ext2fs_link(fs, parent, node_name, child, filetype); ++ if (err == EXT2_ET_DIR_NO_SPACE) { ++ err = ext2fs_expand_dir(fs, parent); ++ if (err) { ++ ret = translate_error(fs, parent, err); ++ goto out2; ++ } ++ ++ err = ext2fs_link(fs, parent, node_name, child, ++ filetype); ++ } ++ if (err) { ++ ret = translate_error(fs, parent, err); ++ goto out2; ++ } ++ ++ ret = update_mtime(fs, parent, NULL); ++ if (ret) ++ goto out2; ++ ++ memset(&inode, 0, sizeof(inode)); ++ inode.i_mode = mode; ++ ++ if (dev & ~0xFFFF) ++ inode.i_block[1] = dev; ++ else ++ inode.i_block[0] = dev; ++ inode.i_links_count = 1; ++ inode.i_extra_isize = sizeof(struct ext2_inode_large) - ++ EXT2_GOOD_OLD_INODE_SIZE; ++ ++ err = ext2fs_write_new_inode(fs, child, (struct ext2_inode *)&inode); ++ if (err) { ++ ret = translate_error(fs, child, err); ++ goto out2; ++ } ++ ++ inode.i_generation = ff->next_generation++; ++ init_times(&inode); ++ err = ext2fs_write_inode_full(fs, child, (struct ext2_inode *)&inode, ++ sizeof(inode)); ++ if (err) { ++ ret = translate_error(fs, child, err); ++ goto out2; ++ } ++ ++ ext2fs_inode_alloc_stats2(fs, child, 1, 0); ++ ++out2: ++ pthread_mutex_unlock(&ff->bfl); ++out: ++ free(temp_path); ++ return ret; ++} ++ ++static int op_mkdir(const char *path, mode_t mode) ++{ ++ struct fuse_context *ctxt = fuse_get_context(); ++ struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data; ++ ext2_filsys fs; ++ ext2_ino_t parent, child; ++ char *temp_path = strdup(path); ++ errcode_t err; ++ char *node_name, a; ++ struct ext2_inode_large inode; ++ char *block; ++ blk64_t blk; ++ int ret = 0; ++ mode_t parent_sgid; ++ ++ FUSE2FS_CHECK_CONTEXT(ff); ++ fs = ff->fs; ++ dbg_printf("%s: path=%s mode=0%o\n", __func__, path, mode); ++ if (!temp_path) { ++ ret = -ENOMEM; ++ goto out; ++ } ++ node_name = strrchr(temp_path, '/'); ++ if (!node_name) { ++ ret = -ENOMEM; ++ goto out; ++ } ++ node_name++; ++ a = *node_name; ++ *node_name = 0; ++ ++ pthread_mutex_lock(&ff->bfl); ++ if (!fs_can_allocate(ff, 1)) { ++ ret = -ENOSPC; ++ goto out2; ++ } ++ ++ err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, temp_path, ++ &parent); ++ if (err) { ++ ret = translate_error(fs, 0, err); ++ goto out2; ++ } ++ ++ ret = check_inum_access(fs, parent, W_OK); ++ if (ret) ++ goto out2; ++ ++ /* Is the parent dir sgid? */ ++ err = ext2fs_read_inode_full(fs, parent, (struct ext2_inode *)&inode, ++ sizeof(inode)); ++ if (err) { ++ ret = translate_error(fs, parent, err); ++ goto out2; ++ } ++ parent_sgid = inode.i_mode & S_ISGID; ++ ++ *node_name = a; ++ ++ err = ext2fs_mkdir(fs, parent, 0, node_name); ++ if (err == EXT2_ET_DIR_NO_SPACE) { ++ err = ext2fs_expand_dir(fs, parent); ++ if (err) { ++ ret = translate_error(fs, parent, err); ++ goto out2; ++ } ++ ++ err = ext2fs_mkdir(fs, parent, 0, node_name); ++ } ++ if (err) { ++ ret = translate_error(fs, parent, err); ++ goto out2; ++ } ++ ++ ret = update_mtime(fs, parent, NULL); ++ if (ret) ++ goto out2; ++ ++ /* Still have to update the uid/gid of the dir */ ++ err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, temp_path, ++ &child); ++ if (err) { ++ ret = translate_error(fs, 0, err); ++ goto out2; ++ } ++ dbg_printf("%s: created ino=%d/path=%s in dir=%d\n", __func__, child, ++ node_name, parent); ++ ++ memset(&inode, 0, sizeof(inode)); ++ err = ext2fs_read_inode_full(fs, child, (struct ext2_inode *)&inode, ++ sizeof(inode)); ++ if (err) { ++ ret = translate_error(fs, child, err); ++ goto out2; ++ } ++ ++ inode.i_uid = ctxt->uid; ++ inode.i_gid = ctxt->gid; ++ inode.i_mode = LINUX_S_IFDIR | (mode & ~(S_ISUID | fs->umask)) | ++ parent_sgid; ++ inode.i_generation = ff->next_generation++; ++ ++ err = ext2fs_write_inode_full(fs, child, (struct ext2_inode *)&inode, ++ sizeof(inode)); ++ if (err) { ++ ret = translate_error(fs, child, err); ++ goto out2; ++ } ++ ++ /* Rewrite the directory block checksum, having set i_generation */ ++ if ((inode.i_flags & EXT4_INLINE_DATA_FL) || ++ !EXT2_HAS_RO_COMPAT_FEATURE(fs->super, ++ EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) ++ goto out2; ++ err = ext2fs_new_dir_block(fs, child, parent, &block); ++ if (err) { ++ ret = translate_error(fs, child, err); ++ goto out2; ++ } ++ err = ext2fs_bmap2(fs, child, (struct ext2_inode *)&inode, NULL, 0, 0, ++ NULL, &blk); ++ if (err) { ++ ret = translate_error(fs, child, err); ++ goto out3; ++ } ++ err = ext2fs_write_dir_block4(fs, blk, block, 0, child); ++ if (err) { ++ ret = translate_error(fs, child, err); ++ goto out3; ++ } ++ ++out3: ++ ext2fs_free_mem(&block); ++out2: ++ pthread_mutex_unlock(&ff->bfl); ++out: ++ free(temp_path); ++ return ret; ++} ++ ++static int unlink_file_by_name(ext2_filsys fs, const char *path) ++{ ++ errcode_t err; ++ ext2_ino_t dir; ++ char *filename = strdup(path); ++ char *base_name; ++ int ret; ++ ++ base_name = strrchr(filename, '/'); ++ if (base_name) { ++ *base_name++ = '\0'; ++ err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, filename, ++ &dir); ++ if (err) { ++ free(filename); ++ return translate_error(fs, 0, err); ++ } ++ } else { ++ dir = EXT2_ROOT_INO; ++ base_name = filename; ++ } ++ ++ ret = check_inum_access(fs, dir, W_OK); ++ if (ret) { ++ free(filename); ++ return ret; ++ } ++ ++ dbg_printf("%s: unlinking name=%s from dir=%d\n", __func__, ++ base_name, dir); ++ err = ext2fs_unlink(fs, dir, base_name, 0, 0); ++ free(filename); ++ if (err) ++ return translate_error(fs, dir, err); ++ ++ return update_mtime(fs, dir, NULL); ++} ++ ++static int remove_inode(struct fuse2fs *ff, ext2_ino_t ino) ++{ ++ ext2_filsys fs = ff->fs; ++ errcode_t err; ++ struct ext2_inode_large inode; ++ int ret = 0; ++ ++ memset(&inode, 0, sizeof(inode)); ++ err = ext2fs_read_inode_full(fs, ino, (struct ext2_inode *)&inode, ++ sizeof(inode)); ++ if (err) { ++ ret = translate_error(fs, ino, err); ++ goto out; ++ } ++ dbg_printf("%s: put ino=%d links=%d\n", __func__, ino, ++ inode.i_links_count); ++ ++ switch (inode.i_links_count) { ++ case 0: ++ return 0; /* XXX: already done? */ ++ case 1: ++ inode.i_links_count--; ++ inode.i_dtime = fs->now ? fs->now : time(0); ++ break; ++ default: ++ inode.i_links_count--; ++ } ++ ++ ret = update_ctime(fs, ino, &inode); ++ if (ret) ++ goto out; ++ ++ if (inode.i_links_count) ++ goto write_out; ++ ++ /* Nobody holds this file; free its blocks! */ ++ err = ext2fs_free_ext_attr(fs, ino, &inode); ++ if (err) ++ goto write_out; ++ ++ if (ext2fs_inode_has_valid_blocks2(fs, (struct ext2_inode *)&inode)) { ++ err = ext2fs_punch(fs, ino, (struct ext2_inode *)&inode, NULL, ++ 0, ~0ULL); ++ if (err) { ++ ret = translate_error(fs, ino, err); ++ goto write_out; ++ } ++ } ++ ++ ext2fs_inode_alloc_stats2(fs, ino, -1, ++ LINUX_S_ISDIR(inode.i_mode)); ++ ++write_out: ++ err = ext2fs_write_inode_full(fs, ino, (struct ext2_inode *)&inode, ++ sizeof(inode)); ++ if (err) { ++ ret = translate_error(fs, ino, err); ++ goto out; ++ } ++out: ++ return ret; ++} ++ ++static int __op_unlink(struct fuse2fs *ff, const char *path) ++{ ++ ext2_filsys fs = ff->fs; ++ ext2_ino_t ino; ++ errcode_t err; ++ int ret = 0; ++ ++ err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, path, &ino); ++ if (err) { ++ ret = translate_error(fs, 0, err); ++ goto out; ++ } ++ ++ ret = unlink_file_by_name(fs, path); ++ if (ret) ++ goto out; ++ ++ ret = remove_inode(ff, ino); ++ if (ret) ++ goto out; ++out: ++ return ret; ++} ++ ++static int op_unlink(const char *path) ++{ ++ struct fuse_context *ctxt = fuse_get_context(); ++ struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data; ++ int ret; ++ ++ FUSE2FS_CHECK_CONTEXT(ff); ++ pthread_mutex_lock(&ff->bfl); ++ ret = __op_unlink(ff, path); ++ pthread_mutex_unlock(&ff->bfl); ++ return ret; ++} ++ ++struct rd_struct { ++ ext2_ino_t parent; ++ int empty; ++}; ++ ++static int rmdir_proc(ext2_ino_t dir EXT2FS_ATTR((unused)), ++ int entry EXT2FS_ATTR((unused)), ++ struct ext2_dir_entry *dirent, ++ int offset EXT2FS_ATTR((unused)), ++ int blocksize EXT2FS_ATTR((unused)), ++ char *buf EXT2FS_ATTR((unused)), ++ void *private) ++{ ++ struct rd_struct *rds = (struct rd_struct *) private; ++ ++ if (dirent->inode == 0) ++ return 0; ++ if (((dirent->name_len & 0xFF) == 1) && (dirent->name[0] == '.')) ++ return 0; ++ if (((dirent->name_len & 0xFF) == 2) && (dirent->name[0] == '.') && ++ (dirent->name[1] == '.')) { ++ rds->parent = dirent->inode; ++ return 0; ++ } ++ rds->empty = 0; ++ return 0; ++} ++ ++static int __op_rmdir(struct fuse2fs *ff, const char *path) ++{ ++ ext2_filsys fs = ff->fs; ++ ext2_ino_t child; ++ errcode_t err; ++ struct ext2_inode_large inode; ++ struct rd_struct rds; ++ int ret = 0; ++ ++ err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, path, &child); ++ if (err) { ++ ret = translate_error(fs, 0, err); ++ goto out; ++ } ++ dbg_printf("%s: rmdir path=%s ino=%d\n", __func__, path, child); ++ ++ rds.parent = 0; ++ rds.empty = 1; ++ ++ err = ext2fs_dir_iterate2(fs, child, 0, 0, rmdir_proc, &rds); ++ if (err) { ++ ret = translate_error(fs, child, err); ++ goto out; ++ } ++ ++ if (rds.empty == 0) { ++ ret = -ENOTEMPTY; ++ goto out; ++ } ++ ++ ret = unlink_file_by_name(fs, path); ++ if (ret) ++ goto out; ++ /* Directories have to be "removed" twice. */ ++ ret = remove_inode(ff, child); ++ if (ret) ++ goto out; ++ ret = remove_inode(ff, child); ++ if (ret) ++ goto out; ++ ++ if (rds.parent) { ++ dbg_printf("%s: decr dir=%d link count\n", __func__, ++ rds.parent); ++ err = ext2fs_read_inode_full(fs, rds.parent, ++ (struct ext2_inode *)&inode, ++ sizeof(inode)); ++ if (err) { ++ ret = translate_error(fs, rds.parent, err); ++ goto out; ++ } ++ if (inode.i_links_count > 1) ++ inode.i_links_count--; ++ ret = update_mtime(fs, rds.parent, &inode); ++ if (ret) ++ goto out; ++ err = ext2fs_write_inode_full(fs, rds.parent, ++ (struct ext2_inode *)&inode, ++ sizeof(inode)); ++ if (err) { ++ ret = translate_error(fs, rds.parent, err); ++ goto out; ++ } ++ } ++ ++out: ++ return ret; ++} ++ ++static int op_rmdir(const char *path) ++{ ++ struct fuse_context *ctxt = fuse_get_context(); ++ struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data; ++ int ret; ++ ++ FUSE2FS_CHECK_CONTEXT(ff); ++ pthread_mutex_lock(&ff->bfl); ++ ret = __op_rmdir(ff, path); ++ pthread_mutex_unlock(&ff->bfl); ++ return ret; ++} ++ ++static int op_symlink(const char *src, const char *dest) ++{ ++ struct fuse_context *ctxt = fuse_get_context(); ++ struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data; ++ ext2_filsys fs; ++ ext2_ino_t parent, child; ++ char *temp_path = strdup(dest); ++ errcode_t err; ++ char *node_name, a; ++ struct ext2_inode_large inode; ++ int ret = 0; ++ ++ FUSE2FS_CHECK_CONTEXT(ff); ++ fs = ff->fs; ++ dbg_printf("%s: symlink %s to %s\n", __func__, src, dest); ++ if (!temp_path) { ++ ret = -ENOMEM; ++ goto out; ++ } ++ node_name = strrchr(temp_path, '/'); ++ if (!node_name) { ++ ret = -ENOMEM; ++ goto out; ++ } ++ node_name++; ++ a = *node_name; ++ *node_name = 0; ++ ++ pthread_mutex_lock(&ff->bfl); ++ err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, temp_path, ++ &parent); ++ *node_name = a; ++ if (err) { ++ ret = translate_error(fs, 0, err); ++ goto out2; ++ } ++ ++ ret = check_inum_access(fs, parent, W_OK); ++ if (ret) ++ goto out2; ++ ++ ++ /* Create symlink */ ++ err = ext2fs_symlink(fs, parent, 0, node_name, src); ++ if (err == EXT2_ET_DIR_NO_SPACE) { ++ err = ext2fs_expand_dir(fs, parent); ++ if (err) { ++ ret = translate_error(fs, parent, err); ++ goto out2; ++ } ++ ++ err = ext2fs_symlink(fs, parent, 0, node_name, src); ++ } ++ if (err) { ++ ret = translate_error(fs, parent, err); ++ goto out2; ++ } ++ ++ /* Update parent dir's mtime */ ++ ret = update_mtime(fs, parent, NULL); ++ if (ret) ++ goto out2; ++ ++ /* Still have to update the uid/gid of the symlink */ ++ err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, temp_path, ++ &child); ++ if (err) { ++ ret = translate_error(fs, 0, err); ++ goto out2; ++ } ++ dbg_printf("%s: symlinking ino=%d/name=%s to dir=%d\n", __func__, ++ child, node_name, parent); ++ ++ memset(&inode, 0, sizeof(inode)); ++ err = ext2fs_read_inode_full(fs, child, (struct ext2_inode *)&inode, ++ sizeof(inode)); ++ if (err) { ++ ret = translate_error(fs, child, err); ++ goto out2; ++ } ++ ++ inode.i_uid = ctxt->uid; ++ inode.i_gid = ctxt->gid; ++ inode.i_generation = ff->next_generation++; ++ ++ err = ext2fs_write_inode_full(fs, child, (struct ext2_inode *)&inode, ++ sizeof(inode)); ++ if (err) { ++ ret = translate_error(fs, child, err); ++ goto out2; ++ } ++out2: ++ pthread_mutex_unlock(&ff->bfl); ++out: ++ free(temp_path); ++ return ret; ++} ++ ++struct update_dotdot { ++ ext2_ino_t new_dotdot; ++}; ++ ++static int update_dotdot_helper(ext2_ino_t dir EXT2FS_ATTR((unused)), ++ int entry EXT2FS_ATTR((unused)), ++ struct ext2_dir_entry *dirent, ++ int offset EXT2FS_ATTR((unused)), ++ int blocksize EXT2FS_ATTR((unused)), ++ char *buf EXT2FS_ATTR((unused)), ++ void *priv_data) ++{ ++ struct update_dotdot *ud = priv_data; ++ ++ if (ext2fs_dirent_name_len(dirent) == 2 && ++ dirent->name[0] == '.' && dirent->name[1] == '.') { ++ dirent->inode = ud->new_dotdot; ++ return DIRENT_CHANGED | DIRENT_ABORT; ++ } ++ ++ return 0; ++} ++ ++static int op_rename(const char *from, const char *to) ++{ ++ struct fuse_context *ctxt = fuse_get_context(); ++ struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data; ++ ext2_filsys fs; ++ errcode_t err; ++ ext2_ino_t from_ino, to_ino, to_dir_ino, from_dir_ino; ++ char *temp_to = NULL, *temp_from = NULL; ++ char *cp, a; ++ struct ext2_inode inode; ++ struct update_dotdot ud; ++ int ret = 0; ++ ++ FUSE2FS_CHECK_CONTEXT(ff); ++ fs = ff->fs; ++ dbg_printf("%s: renaming %s to %s\n", __func__, from, to); ++ pthread_mutex_lock(&ff->bfl); ++ if (!fs_can_allocate(ff, 5)) { ++ ret = -ENOSPC; ++ goto out; ++ } ++ ++ err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, from, &from_ino); ++ if (err || from_ino == 0) { ++ ret = translate_error(fs, 0, err); ++ goto out; ++ } ++ ++ err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, to, &to_ino); ++ if (err && err != EXT2_ET_FILE_NOT_FOUND) { ++ ret = translate_error(fs, 0, err); ++ goto out; ++ } ++ ++ if (err == EXT2_ET_FILE_NOT_FOUND) ++ to_ino = 0; ++ ++ /* Already the same file? */ ++ if (to_ino != 0 && to_ino == from_ino) { ++ ret = 0; ++ goto out; ++ } ++ ++ temp_to = strdup(to); ++ if (!temp_to) { ++ ret = -ENOMEM; ++ goto out; ++ } ++ ++ temp_from = strdup(from); ++ if (!temp_from) { ++ ret = -ENOMEM; ++ goto out2; ++ } ++ ++ /* Find parent dir of the source and check write access */ ++ cp = strrchr(temp_from, '/'); ++ if (!cp) { ++ ret = -EINVAL; ++ goto out2; ++ } ++ ++ a = *(cp + 1); ++ *(cp + 1) = 0; ++ err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, temp_from, ++ &from_dir_ino); ++ *(cp + 1) = a; ++ if (err) { ++ ret = translate_error(fs, 0, err); ++ goto out2; ++ } ++ if (from_dir_ino == 0) { ++ ret = -ENOENT; ++ goto out2; ++ } ++ ++ ret = check_inum_access(fs, from_dir_ino, W_OK); ++ if (ret) ++ goto out2; ++ ++ /* Find parent dir of the destination and check write access */ ++ cp = strrchr(temp_to, '/'); ++ if (!cp) { ++ ret = -EINVAL; ++ goto out2; ++ } ++ ++ a = *(cp + 1); ++ *(cp + 1) = 0; ++ err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, temp_to, ++ &to_dir_ino); ++ *(cp + 1) = a; ++ if (err) { ++ ret = translate_error(fs, 0, err); ++ goto out2; ++ } ++ if (to_dir_ino == 0) { ++ ret = -ENOENT; ++ goto out2; ++ } ++ ++ ret = check_inum_access(fs, to_dir_ino, W_OK); ++ if (ret) ++ goto out2; ++ ++ /* If the target exists, unlink it first */ ++ if (to_ino != 0) { ++ err = ext2fs_read_inode(fs, to_ino, &inode); ++ if (err) { ++ ret = translate_error(fs, to_ino, err); ++ goto out2; ++ } ++ ++ dbg_printf("%s: unlinking %s ino=%d\n", __func__, ++ LINUX_S_ISDIR(inode.i_mode) ? "dir" : "file", ++ to_ino); ++ if (LINUX_S_ISDIR(inode.i_mode)) ++ ret = __op_rmdir(ff, to); ++ else ++ ret = __op_unlink(ff, to); ++ if (ret) ++ goto out2; ++ } ++ ++ /* Get ready to do the move */ ++ err = ext2fs_read_inode(fs, from_ino, &inode); ++ if (err) { ++ ret = translate_error(fs, from_ino, err); ++ goto out2; ++ } ++ ++ /* Link in the new file */ ++ dbg_printf("%s: linking ino=%d/path=%s to dir=%d\n", __func__, ++ from_ino, cp + 1, to_dir_ino); ++ err = ext2fs_link(fs, to_dir_ino, cp + 1, from_ino, ++ ext2_file_type(inode.i_mode)); ++ if (err == EXT2_ET_DIR_NO_SPACE) { ++ err = ext2fs_expand_dir(fs, to_dir_ino); ++ if (err) { ++ ret = translate_error(fs, to_dir_ino, err); ++ goto out2; ++ } ++ ++ err = ext2fs_link(fs, to_dir_ino, cp + 1, from_ino, ++ ext2_file_type(inode.i_mode)); ++ } ++ if (err) { ++ ret = translate_error(fs, to_dir_ino, err); ++ goto out2; ++ } ++ ++ /* Update '..' pointer if dir */ ++ err = ext2fs_read_inode(fs, from_ino, &inode); ++ if (err) { ++ ret = translate_error(fs, from_ino, err); ++ goto out2; ++ } ++ ++ if (LINUX_S_ISDIR(inode.i_mode)) { ++ ud.new_dotdot = to_dir_ino; ++ dbg_printf("%s: updating .. entry for dir=%d\n", __func__, ++ to_dir_ino); ++ err = ext2fs_dir_iterate2(fs, from_ino, 0, NULL, ++ update_dotdot_helper, &ud); ++ if (err) { ++ ret = translate_error(fs, from_ino, err); ++ goto out2; ++ } ++ ++ /* Decrease from_dir_ino's links_count */ ++ dbg_printf("%s: moving linkcount from dir=%d to dir=%d\n", ++ __func__, from_dir_ino, to_dir_ino); ++ err = ext2fs_read_inode(fs, from_dir_ino, &inode); ++ if (err) { ++ ret = translate_error(fs, from_dir_ino, err); ++ goto out2; ++ } ++ inode.i_links_count--; ++ err = ext2fs_write_inode(fs, from_dir_ino, &inode); ++ if (err) { ++ ret = translate_error(fs, from_dir_ino, err); ++ goto out2; ++ } ++ ++ /* Increase to_dir_ino's links_count */ ++ err = ext2fs_read_inode(fs, to_dir_ino, &inode); ++ if (err) { ++ ret = translate_error(fs, to_dir_ino, err); ++ goto out2; ++ } ++ inode.i_links_count++; ++ err = ext2fs_write_inode(fs, to_dir_ino, &inode); ++ if (err) { ++ ret = translate_error(fs, to_dir_ino, err); ++ goto out2; ++ } ++ } ++ ++ /* Update timestamps */ ++ ret = update_ctime(fs, from_ino, NULL); ++ if (ret) ++ goto out2; ++ ++ ret = update_mtime(fs, to_dir_ino, NULL); ++ if (ret) ++ goto out2; ++ ++ /* Remove the old file */ ++ ret = unlink_file_by_name(fs, from); ++ if (ret) ++ goto out2; ++ ++ /* Flush the whole mess out */ ++ err = ext2fs_flush2(fs, 0); ++ if (err) ++ ret = translate_error(fs, 0, err); ++ ++out2: ++ free(temp_from); ++ free(temp_to); ++out: ++ pthread_mutex_unlock(&ff->bfl); ++ return ret; ++} ++ ++static int op_link(const char *src, const char *dest) ++{ ++ struct fuse_context *ctxt = fuse_get_context(); ++ struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data; ++ ext2_filsys fs; ++ char *temp_path = strdup(dest); ++ errcode_t err; ++ char *node_name, a; ++ ext2_ino_t parent, ino; ++ struct ext2_inode_large inode; ++ int ret = 0; ++ ++ FUSE2FS_CHECK_CONTEXT(ff); ++ fs = ff->fs; ++ dbg_printf("%s: src=%s dest=%s\n", __func__, src, dest); ++ if (!temp_path) { ++ ret = -ENOMEM; ++ goto out; ++ } ++ node_name = strrchr(temp_path, '/'); ++ if (!node_name) { ++ ret = -ENOMEM; ++ goto out; ++ } ++ node_name++; ++ a = *node_name; ++ *node_name = 0; ++ ++ pthread_mutex_lock(&ff->bfl); ++ if (!fs_can_allocate(ff, 2)) { ++ ret = -ENOSPC; ++ goto out2; ++ } ++ ++ err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, temp_path, ++ &parent); ++ *node_name = a; ++ if (err) { ++ err = -ENOENT; ++ goto out2; ++ } ++ ++ ret = check_inum_access(fs, parent, W_OK); ++ if (ret) ++ goto out2; ++ ++ ++ err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, src, &ino); ++ if (err || ino == 0) { ++ ret = translate_error(fs, 0, err); ++ goto out2; ++ } ++ ++ memset(&inode, 0, sizeof(inode)); ++ err = ext2fs_read_inode_full(fs, ino, (struct ext2_inode *)&inode, ++ sizeof(inode)); ++ if (err) { ++ ret = translate_error(fs, ino, err); ++ goto out2; ++ } ++ ++ inode.i_links_count++; ++ ret = update_ctime(fs, ino, &inode); ++ if (ret) ++ goto out2; ++ ++ err = ext2fs_write_inode_full(fs, ino, (struct ext2_inode *)&inode, ++ sizeof(inode)); ++ if (err) { ++ ret = translate_error(fs, ino, err); ++ goto out2; ++ } ++ ++ dbg_printf("%s: linking ino=%d/name=%s to dir=%d\n", __func__, ino, ++ node_name, parent); ++ err = ext2fs_link(fs, parent, node_name, ino, ++ ext2_file_type(inode.i_mode)); ++ if (err == EXT2_ET_DIR_NO_SPACE) { ++ err = ext2fs_expand_dir(fs, parent); ++ if (err) { ++ ret = translate_error(fs, parent, err); ++ goto out2; ++ } ++ ++ err = ext2fs_link(fs, parent, node_name, ino, ++ ext2_file_type(inode.i_mode)); ++ } ++ if (err) { ++ ret = translate_error(fs, parent, err); ++ goto out2; ++ } ++ ++ ret = update_mtime(fs, parent, NULL); ++ if (ret) ++ goto out2; ++ ++out2: ++ pthread_mutex_unlock(&ff->bfl); ++out: ++ free(temp_path); ++ return ret; ++} ++ ++static int op_chmod(const char *path, mode_t mode) ++{ ++ struct fuse_context *ctxt = fuse_get_context(); ++ struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data; ++ ext2_filsys fs; ++ errcode_t err; ++ ext2_ino_t ino; ++ struct ext2_inode_large inode; ++ int ret = 0; ++ ++ FUSE2FS_CHECK_CONTEXT(ff); ++ fs = ff->fs; ++ pthread_mutex_lock(&ff->bfl); ++ err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, path, &ino); ++ if (err) { ++ ret = translate_error(fs, 0, err); ++ goto out; ++ } ++ dbg_printf("%s: path=%s mode=0%o ino=%d\n", __func__, path, mode, ino); ++ ++ memset(&inode, 0, sizeof(inode)); ++ err = ext2fs_read_inode_full(fs, ino, (struct ext2_inode *)&inode, ++ sizeof(inode)); ++ if (err) { ++ ret = translate_error(fs, ino, err); ++ goto out; ++ } ++ ++ if (ctxt->uid != 0 && ctxt->uid != inode.i_uid) { ++ ret = -EPERM; ++ goto out; ++ } ++ ++ /* ++ * XXX: We should really check that the inode gid is not in /any/ ++ * of the user's groups, but FUSE only tells us about the primary ++ * group. ++ */ ++ if (ctxt->uid != 0 && ctxt->gid != inode.i_gid) ++ mode &= ~S_ISGID; ++ ++ inode.i_mode &= ~0xFFF; ++ inode.i_mode |= mode & 0xFFF; ++ ret = update_ctime(fs, ino, &inode); ++ if (ret) ++ goto out; ++ ++ err = ext2fs_write_inode_full(fs, ino, (struct ext2_inode *)&inode, ++ sizeof(inode)); ++ if (err) { ++ ret = translate_error(fs, ino, err); ++ goto out; ++ } ++ ++out: ++ pthread_mutex_unlock(&ff->bfl); ++ return ret; ++} ++ ++static int op_chown(const char *path, uid_t owner, gid_t group) ++{ ++ struct fuse_context *ctxt = fuse_get_context(); ++ struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data; ++ ext2_filsys fs; ++ errcode_t err; ++ ext2_ino_t ino; ++ struct ext2_inode_large inode; ++ int ret = 0; ++ ++ FUSE2FS_CHECK_CONTEXT(ff); ++ fs = ff->fs; ++ pthread_mutex_lock(&ff->bfl); ++ err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, path, &ino); ++ if (err) { ++ ret = translate_error(fs, 0, err); ++ goto out; ++ } ++ dbg_printf("%s: path=%s owner=%d group=%d ino=%d\n", __func__, ++ path, owner, group, ino); ++ ++ memset(&inode, 0, sizeof(inode)); ++ err = ext2fs_read_inode_full(fs, ino, (struct ext2_inode *)&inode, ++ sizeof(inode)); ++ if (err) { ++ ret = translate_error(fs, ino, err); ++ goto out; ++ } ++ ++ /* FUSE seems to feed us ~0 to mean "don't change" */ ++ if (owner != (uid_t) ~0) { ++ /* Only root gets to change UID. */ ++ if (ctxt->uid != 0 && ++ !(inode.i_uid == ctxt->uid && owner == ctxt->uid)) { ++ ret = -EPERM; ++ goto out; ++ } ++ inode.i_uid = owner; ++ } ++ ++ if (group != (gid_t) ~0) { ++ /* Only root or the owner get to change GID. */ ++ if (ctxt->uid != 0 && inode.i_uid != ctxt->uid) { ++ ret = -EPERM; ++ goto out; ++ } ++ ++ /* XXX: We /should/ check group membership but FUSE */ ++ inode.i_gid = group; ++ } ++ ++ ret = update_ctime(fs, ino, &inode); ++ if (ret) ++ goto out; ++ ++ err = ext2fs_write_inode_full(fs, ino, (struct ext2_inode *)&inode, ++ sizeof(inode)); ++ if (err) { ++ ret = translate_error(fs, ino, err); ++ goto out; ++ } ++ ++out: ++ pthread_mutex_unlock(&ff->bfl); ++ return ret; ++} ++ ++static int op_truncate(const char *path, off_t len) ++{ ++ struct fuse_context *ctxt = fuse_get_context(); ++ struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data; ++ ext2_filsys fs; ++ errcode_t err; ++ ext2_ino_t ino; ++ ext2_file_t file; ++ int ret = 0; ++ ++ FUSE2FS_CHECK_CONTEXT(ff); ++ fs = ff->fs; ++ pthread_mutex_lock(&ff->bfl); ++ err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, path, &ino); ++ if (err || ino == 0) { ++ ret = translate_error(fs, 0, err); ++ goto out; ++ } ++ dbg_printf("%s: ino=%d len=%jd\n", __func__, ino, len); ++ ++ ret = check_inum_access(fs, ino, W_OK); ++ if (ret) ++ goto out; ++ ++ err = ext2fs_file_open(fs, ino, EXT2_FILE_WRITE, &file); ++ if (err) { ++ ret = translate_error(fs, ino, err); ++ goto out; ++ } ++ ++ err = ext2fs_file_set_size2(file, len); ++ if (err) { ++ ret = translate_error(fs, ino, err); ++ goto out2; ++ } ++ ++out2: ++ err = ext2fs_file_close(file); ++ if (ret) ++ goto out; ++ if (err) { ++ ret = translate_error(fs, ino, err); ++ goto out; ++ } ++ ++ ret = update_mtime(fs, ino, NULL); ++ ++out: ++ pthread_mutex_unlock(&ff->bfl); ++ return err; ++} ++ ++#ifdef __linux__ ++static void detect_linux_executable_open(int kernel_flags, int *access_check, ++ int *e2fs_open_flags) ++{ ++ /* ++ * On Linux, execve will bleed __FMODE_EXEC into the file mode flags, ++ * and FUSE is more than happy to let that slip through. ++ */ ++ if (kernel_flags & 0x20) { ++ *access_check = X_OK; ++ *e2fs_open_flags &= ~EXT2_FILE_WRITE; ++ } ++} ++#else ++static void detect_linux_executable_open(int kernel_flags, int *access_check, ++ int *e2fs_open_flags) ++{ ++ /* empty */ ++} ++#endif /* __linux__ */ ++ ++static int __op_open(struct fuse2fs *ff, const char *path, ++ struct fuse_file_info *fp) ++{ ++ ext2_filsys fs = ff->fs; ++ errcode_t err; ++ struct fuse2fs_file_handle *file; ++ int check = 0, ret = 0; ++ ++ dbg_printf("%s: path=%s\n", __func__, path); ++ err = ext2fs_get_mem(sizeof(*file), &file); ++ if (err) ++ return translate_error(fs, 0, err); ++ file->magic = FUSE2FS_FILE_MAGIC; ++ ++ file->open_flags = 0; ++ switch (fp->flags & O_ACCMODE) { ++ case O_RDONLY: ++ check = R_OK; ++ break; ++ case O_WRONLY: ++ check = W_OK; ++ file->open_flags |= EXT2_FILE_WRITE; ++ break; ++ case O_RDWR: ++ check = R_OK | W_OK; ++ file->open_flags |= EXT2_FILE_WRITE; ++ break; ++ } ++ ++ detect_linux_executable_open(fp->flags, &check, &file->open_flags); ++ ++ if (fp->flags & O_CREAT) ++ file->open_flags |= EXT2_FILE_CREATE; ++ ++ err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, path, &file->ino); ++ if (err || file->ino == 0) { ++ ret = translate_error(fs, 0, err); ++ goto out; ++ } ++ dbg_printf("%s: ino=%d\n", __func__, file->ino); ++ ++ ret = check_inum_access(fs, file->ino, check); ++ if (ret) { ++ /* ++ * In a regular (Linux) fs driver, the kernel will open ++ * binaries for reading if the user has --x privileges (i.e. ++ * execute without read). Since the kernel doesn't have any ++ * way to tell us if it's opening a file via execve, we'll ++ * just assume that allowing access is ok if asking for ro mode ++ * fails but asking for x mode succeeds. Of course we can ++ * also employ undocumented hacks (see above). ++ */ ++ if (check == R_OK) { ++ ret = check_inum_access(fs, file->ino, X_OK); ++ if (ret) ++ goto out; ++ } else ++ goto out; ++ } ++ fp->fh = (uint64_t)file; ++ ++out: ++ if (ret) ++ ext2fs_free_mem(&file); ++ return ret; ++} ++ ++static int op_open(const char *path, struct fuse_file_info *fp) ++{ ++ struct fuse_context *ctxt = fuse_get_context(); ++ struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data; ++ int ret; ++ ++ FUSE2FS_CHECK_CONTEXT(ff); ++ pthread_mutex_lock(&ff->bfl); ++ ret = __op_open(ff, path, fp); ++ pthread_mutex_unlock(&ff->bfl); ++ return ret; ++} ++ ++static int op_read(const char *path EXT2FS_ATTR((unused)), char *buf, ++ size_t len, off_t offset, ++ struct fuse_file_info *fp) ++{ ++ struct fuse_context *ctxt = fuse_get_context(); ++ struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data; ++ struct fuse2fs_file_handle *fh = (struct fuse2fs_file_handle *)fp->fh; ++ ext2_filsys fs; ++ ext2_file_t efp; ++ errcode_t err; ++ unsigned int got = 0; ++ int ret = 0; ++ ++ FUSE2FS_CHECK_CONTEXT(ff); ++ fs = ff->fs; ++ FUSE2FS_CHECK_MAGIC(fs, fh, FUSE2FS_FILE_MAGIC); ++ dbg_printf("%s: ino=%d off=%jd len=%jd\n", __func__, fh->ino, offset, ++ len); ++ pthread_mutex_lock(&ff->bfl); ++ err = ext2fs_file_open(fs, fh->ino, fh->open_flags, &efp); ++ if (err) { ++ ret = translate_error(fs, fh->ino, err); ++ goto out; ++ } ++ ++ err = ext2fs_file_llseek(efp, offset, SEEK_SET, NULL); ++ if (err) { ++ ret = translate_error(fs, fh->ino, err); ++ goto out2; ++ } ++ ++ err = ext2fs_file_read(efp, buf, len, &got); ++ if (err) { ++ ret = translate_error(fs, fh->ino, err); ++ goto out2; ++ } ++ ++out2: ++ err = ext2fs_file_close(efp); ++ if (ret) ++ goto out; ++ if (err) { ++ ret = translate_error(fs, fh->ino, err); ++ goto out; ++ } ++ ++ if (fs_writeable(fs)) { ++ ret = update_atime(fs, fh->ino); ++ if (ret) ++ goto out; ++ } ++out: ++ pthread_mutex_unlock(&ff->bfl); ++ return got ? (int) got : ret; ++} ++ ++static int op_write(const char *path EXT2FS_ATTR((unused)), ++ const char *buf, size_t len, off_t offset, ++ struct fuse_file_info *fp) ++{ ++ struct fuse_context *ctxt = fuse_get_context(); ++ struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data; ++ struct fuse2fs_file_handle *fh = (struct fuse2fs_file_handle *)fp->fh; ++ ext2_filsys fs; ++ ext2_file_t efp; ++ errcode_t err; ++ unsigned int got = 0; ++ int ret = 0; ++ ++ FUSE2FS_CHECK_CONTEXT(ff); ++ fs = ff->fs; ++ FUSE2FS_CHECK_MAGIC(fs, fh, FUSE2FS_FILE_MAGIC); ++ dbg_printf("%s: ino=%d off=%jd len=%jd\n", __func__, fh->ino, offset, ++ len); ++ pthread_mutex_lock(&ff->bfl); ++ if (!fs_writeable(fs)) { ++ ret = -EROFS; ++ goto out; ++ } ++ ++ if (!fs_can_allocate(ff, len / fs->blocksize)) { ++ ret = -ENOSPC; ++ goto out; ++ } ++ ++ err = ext2fs_file_open(fs, fh->ino, fh->open_flags, &efp); ++ if (err) { ++ ret = translate_error(fs, fh->ino, err); ++ goto out; ++ } ++ ++ err = ext2fs_file_llseek(efp, offset, SEEK_SET, NULL); ++ if (err) { ++ ret = translate_error(fs, fh->ino, err); ++ goto out2; ++ } ++ ++ err = ext2fs_file_write(efp, buf, len, &got); ++ if (err) { ++ ret = translate_error(fs, fh->ino, err); ++ goto out2; ++ } ++ ++ err = ext2fs_file_flush(efp); ++ if (err) { ++ got = 0; ++ ret = translate_error(fs, fh->ino, err); ++ goto out2; ++ } ++ ++out2: ++ err = ext2fs_file_close(efp); ++ if (ret) ++ goto out; ++ if (err) { ++ ret = translate_error(fs, fh->ino, err); ++ goto out; ++ } ++ ++ ret = update_mtime(fs, fh->ino, NULL); ++ if (ret) ++ goto out; ++ ++out: ++ pthread_mutex_unlock(&ff->bfl); ++ return got ? (int) got : ret; ++} ++ ++static int op_release(const char *path EXT2FS_ATTR((unused)), ++ struct fuse_file_info *fp) ++{ ++ struct fuse_context *ctxt = fuse_get_context(); ++ struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data; ++ struct fuse2fs_file_handle *fh = (struct fuse2fs_file_handle *)fp->fh; ++ ext2_filsys fs; ++ errcode_t err; ++ int ret = 0; ++ ++ FUSE2FS_CHECK_CONTEXT(ff); ++ fs = ff->fs; ++ FUSE2FS_CHECK_MAGIC(fs, fh, FUSE2FS_FILE_MAGIC); ++ dbg_printf("%s: ino=%d\n", __func__, fh->ino); ++ pthread_mutex_lock(&ff->bfl); ++ if (fs_writeable(fs) && fh->open_flags & EXT2_FILE_WRITE) { ++ err = ext2fs_flush2(fs, EXT2_FLAG_FLUSH_NO_SYNC); ++ if (err) ++ ret = translate_error(fs, fh->ino, err); ++ } ++ fp->fh = 0; ++ pthread_mutex_unlock(&ff->bfl); ++ ++ ext2fs_free_mem(&fh); ++ ++ return ret; ++} ++ ++static int op_fsync(const char *path EXT2FS_ATTR((unused)), ++ int datasync EXT2FS_ATTR((unused)), ++ struct fuse_file_info *fp) ++{ ++ struct fuse_context *ctxt = fuse_get_context(); ++ struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data; ++ struct fuse2fs_file_handle *fh = (struct fuse2fs_file_handle *)fp->fh; ++ ext2_filsys fs; ++ errcode_t err; ++ int ret = 0; ++ ++ FUSE2FS_CHECK_CONTEXT(ff); ++ fs = ff->fs; ++ FUSE2FS_CHECK_MAGIC(fs, fh, FUSE2FS_FILE_MAGIC); ++ dbg_printf("%s: ino=%d\n", __func__, fh->ino); ++ /* For now, flush everything, even if it's slow */ ++ pthread_mutex_lock(&ff->bfl); ++ if (fs_writeable(fs) && fh->open_flags & EXT2_FILE_WRITE) { ++ err = ext2fs_flush2(fs, 0); ++ if (err) ++ ret = translate_error(fs, fh->ino, err); ++ } ++ pthread_mutex_unlock(&ff->bfl); ++ ++ return ret; ++} ++ ++static int op_statfs(const char *path EXT2FS_ATTR((unused)), ++ struct statvfs *buf) ++{ ++ struct fuse_context *ctxt = fuse_get_context(); ++ struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data; ++ ext2_filsys fs; ++ uint64_t fsid, *f; ++ blk64_t overhead, reserved, free; ++ ++ FUSE2FS_CHECK_CONTEXT(ff); ++ fs = ff->fs; ++ dbg_printf("%s: path=%s\n", __func__, path); ++ buf->f_bsize = fs->blocksize; ++ buf->f_frsize = 0; ++ ++ if (ff->minixdf) ++ overhead = 0; ++ else ++ overhead = fs->desc_blocks + ++ fs->group_desc_count * ++ (fs->inode_blocks_per_group + 2); ++ reserved = ext2fs_r_blocks_count(fs->super); ++ if (!reserved) ++ reserved = ext2fs_blocks_count(fs->super) / 10; ++ free = ext2fs_free_blocks_count(fs->super); ++ ++ buf->f_blocks = ext2fs_blocks_count(fs->super) - overhead; ++ buf->f_bfree = free; ++ if (free < reserved) ++ buf->f_bavail = 0; ++ else ++ buf->f_bavail = free - reserved; ++ buf->f_files = fs->super->s_inodes_count; ++ buf->f_ffree = fs->super->s_free_inodes_count; ++ buf->f_favail = fs->super->s_free_inodes_count; ++ f = (uint64_t *)fs->super->s_uuid; ++ fsid = *f; ++ f++; ++ fsid ^= *f; ++ buf->f_fsid = fsid; ++ buf->f_flag = 0; ++ if (fs->flags & EXT2_FLAG_RW) ++ buf->f_flag |= ST_RDONLY; ++ buf->f_namemax = EXT2_NAME_LEN; ++ ++ return 0; ++} ++ ++typedef errcode_t (*xattr_xlate_get)(void **cooked_buf, size_t *cooked_sz, ++ const void *raw_buf, size_t raw_sz); ++typedef errcode_t (*xattr_xlate_set)(const void *cooked_buf, size_t cooked_sz, ++ const void **raw_buf, size_t *raw_sz); ++struct xattr_translate { ++ const char *prefix; ++ xattr_xlate_get get; ++ xattr_xlate_set set; ++}; ++ ++#define XATTR_TRANSLATOR(p, g, s) \ ++ {.prefix = (p), \ ++ .get = (xattr_xlate_get)(g), \ ++ .set = (xattr_xlate_set)(s)} ++ ++static struct xattr_translate xattr_translators[] = { ++#ifdef TRANSLATE_LINUX_ACLS ++ XATTR_TRANSLATOR(ACL_EA_ACCESS, ext4_to_fuse_acl, fuse_to_ext4_acl), ++ XATTR_TRANSLATOR(ACL_EA_DEFAULT, ext4_to_fuse_acl, fuse_to_ext4_acl), ++#endif ++ XATTR_TRANSLATOR(NULL, NULL, NULL), ++}; ++#undef XATTR_TRANSLATOR ++ ++static int op_getxattr(const char *path, const char *key, char *value, ++ size_t len) ++{ ++ struct fuse_context *ctxt = fuse_get_context(); ++ struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data; ++ ext2_filsys fs; ++ struct ext2_xattr_handle *h; ++ struct xattr_translate *xt; ++ void *ptr, *cptr; ++ size_t plen, clen; ++ ext2_ino_t ino; ++ errcode_t err; ++ int ret = 0; ++ ++ FUSE2FS_CHECK_CONTEXT(ff); ++ fs = ff->fs; ++ pthread_mutex_lock(&ff->bfl); ++ if (!EXT2_HAS_COMPAT_FEATURE(fs->super, ++ EXT2_FEATURE_COMPAT_EXT_ATTR)) { ++ ret = -ENOTSUP; ++ goto out; ++ } ++ ++ err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, path, &ino); ++ if (err || ino == 0) { ++ ret = translate_error(fs, 0, err); ++ goto out; ++ } ++ dbg_printf("%s: ino=%d\n", __func__, ino); ++ ++ ret = check_inum_access(fs, ino, R_OK); ++ if (ret) ++ goto out; ++ ++ err = ext2fs_xattrs_open(fs, ino, &h); ++ if (err) { ++ ret = translate_error(fs, ino, err); ++ goto out; ++ } ++ ++ err = ext2fs_xattrs_read(h); ++ if (err) { ++ ret = translate_error(fs, ino, err); ++ goto out2; ++ } ++ ++ err = ext2fs_xattr_get(h, key, &ptr, &plen); ++ if (err) { ++ ret = translate_error(fs, ino, err); ++ goto out2; ++ } ++ ++ for (xt = xattr_translators; xt->prefix != NULL; xt++) { ++ if (strncmp(key, xt->prefix, strlen(xt->prefix)) == 0) { ++ err = xt->get(&cptr, &clen, ptr, plen); ++ if (err) ++ goto out3; ++ ext2fs_free_mem(&ptr); ++ ptr = cptr; ++ plen = clen; ++ } ++ } ++ ++ if (!len) { ++ ret = plen; ++ } else if (len < plen) { ++ ret = -ERANGE; ++ } else { ++ memcpy(value, ptr, plen); ++ ret = plen; ++ } ++ ++out3: ++ ext2fs_free_mem(&ptr); ++out2: ++ err = ext2fs_xattrs_close(&h); ++ if (err) ++ ret = translate_error(fs, ino, err); ++out: ++ pthread_mutex_unlock(&ff->bfl); ++ ++ return ret; ++} ++ ++static int count_buffer_space(char *name, char *value EXT2FS_ATTR((unused)), ++ size_t value_len EXT2FS_ATTR((unused)), ++ void *data) ++{ ++ unsigned int *x = data; ++ ++ *x = *x + strlen(name) + 1; ++ return 0; ++} ++ ++static int copy_names(char *name, char *value EXT2FS_ATTR((unused)), ++ size_t value_len EXT2FS_ATTR((unused)), void *data) ++{ ++ char **b = data; ++ ++ strncpy(*b, name, strlen(name)); ++ *b = *b + strlen(name) + 1; ++ ++ return 0; ++} ++ ++static int op_listxattr(const char *path, char *names, size_t len) ++{ ++ struct fuse_context *ctxt = fuse_get_context(); ++ struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data; ++ ext2_filsys fs; ++ struct ext2_xattr_handle *h; ++ unsigned int bufsz; ++ ext2_ino_t ino; ++ errcode_t err; ++ int ret = 0; ++ ++ FUSE2FS_CHECK_CONTEXT(ff); ++ fs = ff->fs; ++ pthread_mutex_lock(&ff->bfl); ++ if (!EXT2_HAS_COMPAT_FEATURE(fs->super, ++ EXT2_FEATURE_COMPAT_EXT_ATTR)) { ++ ret = -ENOTSUP; ++ goto out; ++ } ++ ++ err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, path, &ino); ++ if (err || ino == 0) { ++ ret = translate_error(fs, ino, err); ++ goto out; ++ } ++ dbg_printf("%s: ino=%d\n", __func__, ino); ++ ++ ret = check_inum_access(fs, ino, R_OK); ++ if (ret) ++ goto out2; ++ ++ err = ext2fs_xattrs_open(fs, ino, &h); ++ if (err) { ++ ret = translate_error(fs, ino, err); ++ goto out; ++ } ++ ++ err = ext2fs_xattrs_read(h); ++ if (err) { ++ ret = translate_error(fs, ino, err); ++ goto out2; ++ } ++ ++ /* Count buffer space needed for names */ ++ bufsz = 0; ++ err = ext2fs_xattrs_iterate(h, count_buffer_space, &bufsz); ++ if (err) { ++ ret = translate_error(fs, ino, err); ++ goto out2; ++ } ++ ++ if (len == 0) { ++ ret = bufsz; ++ goto out2; ++ } else if (len < bufsz) { ++ ret = -ERANGE; ++ goto out2; ++ } ++ ++ /* Copy names out */ ++ memset(names, 0, len); ++ err = ext2fs_xattrs_iterate(h, copy_names, &names); ++ if (err) { ++ ret = translate_error(fs, ino, err); ++ goto out2; ++ } ++ ret = bufsz; ++out2: ++ err = ext2fs_xattrs_close(&h); ++ if (err) ++ ret = translate_error(fs, ino, err); ++out: ++ pthread_mutex_unlock(&ff->bfl); ++ ++ return ret; ++} ++ ++static int op_setxattr(const char *path EXT2FS_ATTR((unused)), ++ const char *key, const char *value, ++ size_t len, int flags EXT2FS_ATTR((unused))) ++{ ++ struct fuse_context *ctxt = fuse_get_context(); ++ struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data; ++ ext2_filsys fs; ++ struct ext2_xattr_handle *h; ++ struct xattr_translate *xt; ++ const void *cvalue; ++ size_t clen; ++ ext2_ino_t ino; ++ errcode_t err; ++ int ret = 0; ++ ++ FUSE2FS_CHECK_CONTEXT(ff); ++ fs = ff->fs; ++ pthread_mutex_lock(&ff->bfl); ++ if (!EXT2_HAS_COMPAT_FEATURE(fs->super, ++ EXT2_FEATURE_COMPAT_EXT_ATTR)) { ++ ret = -ENOTSUP; ++ goto out; ++ } ++ ++ err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, path, &ino); ++ if (err || ino == 0) { ++ ret = translate_error(fs, 0, err); ++ goto out; ++ } ++ dbg_printf("%s: ino=%d\n", __func__, ino); ++ ++ ret = check_inum_access(fs, ino, W_OK); ++ if (ret == -EACCES) { ++ ret = -EPERM; ++ goto out; ++ } else if (ret) ++ goto out; ++ ++ err = ext2fs_xattrs_open(fs, ino, &h); ++ if (err) { ++ ret = translate_error(fs, ino, err); ++ goto out; ++ } ++ ++ err = ext2fs_xattrs_read(h); ++ if (err) { ++ ret = translate_error(fs, ino, err); ++ goto out2; ++ } ++ ++ cvalue = value; ++ clen = len; ++ for (xt = xattr_translators; xt->prefix != NULL; xt++) { ++ if (strncmp(key, xt->prefix, strlen(xt->prefix)) == 0) { ++ err = xt->set(value, len, &cvalue, &clen); ++ if (err) ++ goto out3; ++ } ++ } ++ ++ err = ext2fs_xattr_set(h, key, cvalue, clen); ++ if (err) { ++ ret = translate_error(fs, ino, err); ++ goto out3; ++ } ++ ++ err = ext2fs_xattrs_write(h); ++ if (err) { ++ ret = translate_error(fs, ino, err); ++ goto out3; ++ } ++ ++ ret = update_ctime(fs, ino, NULL); ++out3: ++ if (cvalue != value) ++ ext2fs_free_mem(&cvalue); ++out2: ++ err = ext2fs_xattrs_close(&h); ++ if (!ret && err) ++ ret = translate_error(fs, ino, err); ++out: ++ pthread_mutex_unlock(&ff->bfl); ++ ++ return ret; ++} ++ ++static int op_removexattr(const char *path, const char *key) ++{ ++ struct fuse_context *ctxt = fuse_get_context(); ++ struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data; ++ ext2_filsys fs; ++ struct ext2_xattr_handle *h; ++ ext2_ino_t ino; ++ errcode_t err; ++ int ret = 0; ++ ++ FUSE2FS_CHECK_CONTEXT(ff); ++ fs = ff->fs; ++ pthread_mutex_lock(&ff->bfl); ++ if (!EXT2_HAS_COMPAT_FEATURE(fs->super, ++ EXT2_FEATURE_COMPAT_EXT_ATTR)) { ++ ret = -ENOTSUP; ++ goto out; ++ } ++ ++ if (!fs_can_allocate(ff, 1)) { ++ ret = -ENOSPC; ++ goto out; ++ } ++ ++ err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, path, &ino); ++ if (err || ino == 0) { ++ ret = translate_error(fs, 0, err); ++ goto out; ++ } ++ dbg_printf("%s: ino=%d\n", __func__, ino); ++ ++ ret = check_inum_access(fs, ino, W_OK); ++ if (ret) ++ goto out; ++ ++ err = ext2fs_xattrs_open(fs, ino, &h); ++ if (err) { ++ ret = translate_error(fs, ino, err); ++ goto out; ++ } ++ ++ err = ext2fs_xattrs_read(h); ++ if (err) { ++ ret = translate_error(fs, ino, err); ++ goto out2; ++ } ++ ++ err = ext2fs_xattr_remove(h, key); ++ if (err) { ++ ret = translate_error(fs, ino, err); ++ goto out2; ++ } ++ ++ err = ext2fs_xattrs_write(h); ++ if (err) { ++ ret = translate_error(fs, ino, err); ++ goto out2; ++ } ++ ++ ret = update_ctime(fs, ino, NULL); ++out2: ++ err = ext2fs_xattrs_close(&h); ++ if (err) ++ ret = translate_error(fs, ino, err); ++out: ++ pthread_mutex_unlock(&ff->bfl); ++ ++ return ret; ++} ++ ++struct readdir_iter { ++ void *buf; ++ fuse_fill_dir_t func; ++}; ++ ++static int op_readdir_iter(ext2_ino_t dir EXT2FS_ATTR((unused)), ++ int entry EXT2FS_ATTR((unused)), ++ struct ext2_dir_entry *dirent, ++ int offset EXT2FS_ATTR((unused)), ++ int blocksize EXT2FS_ATTR((unused)), ++ char *buf EXT2FS_ATTR((unused)), void *data) ++{ ++ struct readdir_iter *i = data; ++ char namebuf[EXT2_NAME_LEN + 1]; ++ int ret; ++ ++ memcpy(namebuf, dirent->name, dirent->name_len & 0xFF); ++ namebuf[dirent->name_len & 0xFF] = 0; ++ ret = i->func(i->buf, namebuf, NULL, 0); ++ if (ret) ++ return DIRENT_ABORT; ++ ++ return 0; ++} ++ ++static int op_readdir(const char *path EXT2FS_ATTR((unused)), ++ void *buf, fuse_fill_dir_t fill_func, ++ off_t offset EXT2FS_ATTR((unused)), ++ struct fuse_file_info *fp) ++{ ++ struct fuse_context *ctxt = fuse_get_context(); ++ struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data; ++ struct fuse2fs_file_handle *fh = (struct fuse2fs_file_handle *)fp->fh; ++ ext2_filsys fs; ++ errcode_t err; ++ struct readdir_iter i; ++ int ret = 0; ++ ++ FUSE2FS_CHECK_CONTEXT(ff); ++ fs = ff->fs; ++ FUSE2FS_CHECK_MAGIC(fs, fh, FUSE2FS_FILE_MAGIC); ++ dbg_printf("%s: ino=%d\n", __func__, fh->ino); ++ pthread_mutex_lock(&ff->bfl); ++ i.buf = buf; ++ i.func = fill_func; ++ err = ext2fs_dir_iterate2(fs, fh->ino, 0, NULL, op_readdir_iter, &i); ++ if (err) { ++ ret = translate_error(fs, fh->ino, err); ++ goto out; ++ } ++ ++ if (fs_writeable(fs)) { ++ ret = update_atime(fs, fh->ino); ++ if (ret) ++ goto out; ++ } ++out: ++ pthread_mutex_unlock(&ff->bfl); ++ return ret; ++} ++ ++static int op_access(const char *path, int mask) ++{ ++ struct fuse_context *ctxt = fuse_get_context(); ++ struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data; ++ ext2_filsys fs; ++ errcode_t err; ++ ext2_ino_t ino; ++ int ret = 0; ++ ++ FUSE2FS_CHECK_CONTEXT(ff); ++ fs = ff->fs; ++ dbg_printf("%s: path=%s mask=0x%x\n", __func__, path, mask); ++ pthread_mutex_lock(&ff->bfl); ++ err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, path, &ino); ++ if (err || ino == 0) { ++ ret = translate_error(fs, 0, err); ++ goto out; ++ } ++ ++ ret = check_inum_access(fs, ino, mask); ++ if (ret) ++ goto out; ++ ++out: ++ pthread_mutex_unlock(&ff->bfl); ++ return ret; ++} ++ ++static int op_create(const char *path, mode_t mode, struct fuse_file_info *fp) ++{ ++ struct fuse_context *ctxt = fuse_get_context(); ++ struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data; ++ ext2_filsys fs; ++ ext2_ino_t parent, child; ++ char *temp_path = strdup(path); ++ errcode_t err; ++ char *node_name, a; ++ int filetype; ++ struct ext2_inode_large inode; ++ int ret = 0; ++ ++ FUSE2FS_CHECK_CONTEXT(ff); ++ fs = ff->fs; ++ dbg_printf("%s: path=%s mode=0%o\n", __func__, path, mode); ++ if (!temp_path) { ++ ret = -ENOMEM; ++ goto out; ++ } ++ node_name = strrchr(temp_path, '/'); ++ if (!node_name) { ++ ret = -ENOMEM; ++ goto out; ++ } ++ node_name++; ++ a = *node_name; ++ *node_name = 0; ++ ++ pthread_mutex_lock(&ff->bfl); ++ if (!fs_can_allocate(ff, 1)) { ++ ret = -ENOSPC; ++ goto out2; ++ } ++ ++ err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, temp_path, ++ &parent); ++ if (err) { ++ ret = translate_error(fs, 0, err); ++ goto out2; ++ } ++ ++ ret = check_inum_access(fs, parent, W_OK); ++ if (ret) ++ goto out2; ++ ++ *node_name = a; ++ ++ filetype = ext2_file_type(mode); ++ ++ err = ext2fs_new_inode(fs, parent, mode, 0, &child); ++ if (err) { ++ ret = translate_error(fs, parent, err); ++ goto out2; ++ } ++ ++ dbg_printf("%s: creating ino=%d/name=%s in dir=%d\n", __func__, child, ++ node_name, parent); ++ err = ext2fs_link(fs, parent, node_name, child, filetype); ++ if (err == EXT2_ET_DIR_NO_SPACE) { ++ err = ext2fs_expand_dir(fs, parent); ++ if (err) { ++ ret = translate_error(fs, parent, err); ++ goto out2; ++ } ++ ++ err = ext2fs_link(fs, parent, node_name, child, ++ filetype); ++ } ++ if (err) { ++ ret = translate_error(fs, parent, err); ++ goto out2; ++ } ++ ++ ret = update_mtime(fs, parent, NULL); ++ if (ret) ++ goto out2; ++ ++ memset(&inode, 0, sizeof(inode)); ++ inode.i_mode = mode; ++ inode.i_links_count = 1; ++ inode.i_extra_isize = sizeof(struct ext2_inode_large) - ++ EXT2_GOOD_OLD_INODE_SIZE; ++ if (fs->super->s_feature_incompat & EXT3_FEATURE_INCOMPAT_EXTENTS) { ++ ext2_extent_handle_t handle; ++ ++ inode.i_flags &= ~EXT4_EXTENTS_FL; ++ ret = ext2fs_extent_open2(fs, child, ++ (struct ext2_inode *)&inode, &handle); ++ if (ret) ++ return ret; ++ ext2fs_extent_free(handle); ++ } ++ ++ err = ext2fs_write_new_inode(fs, child, (struct ext2_inode *)&inode); ++ if (err) { ++ ret = translate_error(fs, child, err); ++ goto out2; ++ } ++ ++ inode.i_generation = ff->next_generation++; ++ init_times(&inode); ++ err = ext2fs_write_inode_full(fs, child, (struct ext2_inode *)&inode, ++ sizeof(inode)); ++ if (err) { ++ ret = translate_error(fs, child, err); ++ goto out2; ++ } ++ ++ ext2fs_inode_alloc_stats2(fs, child, 1, 0); ++ ++ ret = __op_open(ff, path, fp); ++ if (ret) ++ goto out2; ++out2: ++ pthread_mutex_unlock(&ff->bfl); ++out: ++ free(temp_path); ++ return ret; ++} ++ ++static int op_ftruncate(const char *path EXT2FS_ATTR((unused)), ++ off_t len, struct fuse_file_info *fp) ++{ ++ struct fuse_context *ctxt = fuse_get_context(); ++ struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data; ++ struct fuse2fs_file_handle *fh = (struct fuse2fs_file_handle *)fp->fh; ++ ext2_filsys fs; ++ ext2_file_t efp; ++ errcode_t err; ++ int ret = 0; ++ ++ FUSE2FS_CHECK_CONTEXT(ff); ++ fs = ff->fs; ++ FUSE2FS_CHECK_MAGIC(fs, fh, FUSE2FS_FILE_MAGIC); ++ dbg_printf("%s: ino=%d len=%jd\n", __func__, fh->ino, len); ++ pthread_mutex_lock(&ff->bfl); ++ if (!fs_writeable(fs)) { ++ ret = -EROFS; ++ goto out; ++ } ++ ++ err = ext2fs_file_open(fs, fh->ino, fh->open_flags, &efp); ++ if (err) { ++ ret = translate_error(fs, fh->ino, err); ++ goto out; ++ } ++ ++ err = ext2fs_file_set_size2(efp, len); ++ if (err) { ++ ret = translate_error(fs, fh->ino, err); ++ goto out2; ++ } ++ ++out2: ++ err = ext2fs_file_close(efp); ++ if (ret) ++ goto out; ++ if (err) { ++ ret = translate_error(fs, fh->ino, err); ++ goto out; ++ } ++ ++ ret = update_mtime(fs, fh->ino, NULL); ++ if (ret) ++ goto out; ++ ++out: ++ pthread_mutex_unlock(&ff->bfl); ++ return 0; ++} ++ ++static int op_fgetattr(const char *path EXT2FS_ATTR((unused)), ++ struct stat *statbuf, ++ struct fuse_file_info *fp) ++{ ++ struct fuse_context *ctxt = fuse_get_context(); ++ struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data; ++ ext2_filsys fs; ++ struct fuse2fs_file_handle *fh = (struct fuse2fs_file_handle *)fp->fh; ++ int ret = 0; ++ ++ FUSE2FS_CHECK_CONTEXT(ff); ++ fs = ff->fs; ++ FUSE2FS_CHECK_MAGIC(fs, fh, FUSE2FS_FILE_MAGIC); ++ dbg_printf("%s: ino=%d\n", __func__, fh->ino); ++ pthread_mutex_lock(&ff->bfl); ++ ret = stat_inode(fs, fh->ino, statbuf); ++ pthread_mutex_unlock(&ff->bfl); ++ ++ return ret; ++} ++ ++static int op_utimens(const char *path, const struct timespec ctv[2]) ++{ ++ struct fuse_context *ctxt = fuse_get_context(); ++ struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data; ++ struct timespec tv[2]; ++ ext2_filsys fs; ++ errcode_t err; ++ ext2_ino_t ino; ++ struct ext2_inode_large inode; ++ int ret = 0; ++ ++ FUSE2FS_CHECK_CONTEXT(ff); ++ fs = ff->fs; ++ pthread_mutex_lock(&ff->bfl); ++ err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, path, &ino); ++ if (err) { ++ ret = translate_error(fs, 0, err); ++ goto out; ++ } ++ dbg_printf("%s: ino=%d\n", __func__, ino); ++ ++ ret = check_inum_access(fs, ino, W_OK); ++ if (ret) ++ goto out; ++ ++ memset(&inode, 0, sizeof(inode)); ++ err = ext2fs_read_inode_full(fs, ino, (struct ext2_inode *)&inode, ++ sizeof(inode)); ++ if (err) { ++ ret = translate_error(fs, ino, err); ++ goto out; ++ } ++ ++ tv[0] = ctv[0]; ++ tv[1] = ctv[1]; ++#ifdef UTIME_NOW ++ if (tv[0].tv_nsec == UTIME_NOW) ++ get_now(tv); ++ if (tv[1].tv_nsec == UTIME_NOW) ++ get_now(tv + 1); ++#endif /* UTIME_NOW */ ++#ifdef UTIME_OMIT ++ if (tv[0].tv_nsec != UTIME_OMIT) ++ EXT4_INODE_SET_XTIME(i_atime, tv, &inode); ++ if (tv[1].tv_nsec != UTIME_OMIT) ++ EXT4_INODE_SET_XTIME(i_mtime, tv + 1, &inode); ++#endif /* UTIME_OMIT */ ++ ret = update_ctime(fs, ino, &inode); ++ if (ret) ++ goto out; ++ ++ err = ext2fs_write_inode_full(fs, ino, (struct ext2_inode *)&inode, ++ sizeof(inode)); ++ if (err) { ++ ret = translate_error(fs, ino, err); ++ goto out; ++ } ++ ++out: ++ pthread_mutex_unlock(&ff->bfl); ++ return ret; ++} ++ ++#ifdef SUPPORT_I_FLAGS ++static int ioctl_getflags(ext2_filsys fs, struct fuse2fs_file_handle *fh, ++ void *data) ++{ ++ errcode_t err; ++ struct ext2_inode_large inode; ++ ++ FUSE2FS_CHECK_MAGIC(fs, fh, FUSE2FS_FILE_MAGIC); ++ dbg_printf("%s: ino=%d\n", __func__, fh->ino); ++ memset(&inode, 0, sizeof(inode)); ++ err = ext2fs_read_inode_full(fs, fh->ino, (struct ext2_inode *)&inode, ++ sizeof(inode)); ++ if (err) ++ return translate_error(fs, fh->ino, err); ++ ++ *(__u32 *)data = inode.i_flags & EXT2_FL_USER_VISIBLE; ++ return 0; ++} ++ ++#define FUSE2FS_MODIFIABLE_IFLAGS \ ++ (EXT2_IMMUTABLE_FL | EXT2_APPEND_FL | EXT2_NODUMP_FL | \ ++ EXT2_NOATIME_FL | EXT3_JOURNAL_DATA_FL | EXT2_DIRSYNC_FL | \ ++ EXT2_TOPDIR_FL) ++ ++static int ioctl_setflags(ext2_filsys fs, struct fuse2fs_file_handle *fh, ++ void *data) ++{ ++ errcode_t err; ++ struct ext2_inode_large inode; ++ int ret; ++ __u32 flags = *(__u32 *)data; ++ struct fuse_context *ctxt = fuse_get_context(); ++ ++ FUSE2FS_CHECK_MAGIC(fs, fh, FUSE2FS_FILE_MAGIC); ++ dbg_printf("%s: ino=%d\n", __func__, fh->ino); ++ memset(&inode, 0, sizeof(inode)); ++ err = ext2fs_read_inode_full(fs, fh->ino, (struct ext2_inode *)&inode, ++ sizeof(inode)); ++ if (err) ++ return translate_error(fs, fh->ino, err); ++ ++ if (ctxt->uid != 0 && inode.i_uid != ctxt->uid) ++ return -EPERM; ++ ++ if ((inode.i_flags ^ flags) & ~FUSE2FS_MODIFIABLE_IFLAGS) ++ return -EINVAL; ++ ++ inode.i_flags = (inode.i_flags & ~FUSE2FS_MODIFIABLE_IFLAGS) | ++ (flags & FUSE2FS_MODIFIABLE_IFLAGS); ++ ++ ret = update_ctime(fs, fh->ino, &inode); ++ if (ret) ++ return ret; ++ ++ err = ext2fs_write_inode_full(fs, fh->ino, (struct ext2_inode *)&inode, ++ sizeof(inode)); ++ if (err) ++ return translate_error(fs, fh->ino, err); ++ ++ return 0; ++} ++ ++static int ioctl_getversion(ext2_filsys fs, struct fuse2fs_file_handle *fh, ++ void *data) ++{ ++ errcode_t err; ++ struct ext2_inode_large inode; ++ ++ FUSE2FS_CHECK_MAGIC(fs, fh, FUSE2FS_FILE_MAGIC); ++ dbg_printf("%s: ino=%d\n", __func__, fh->ino); ++ memset(&inode, 0, sizeof(inode)); ++ err = ext2fs_read_inode_full(fs, fh->ino, (struct ext2_inode *)&inode, ++ sizeof(inode)); ++ if (err) ++ return translate_error(fs, fh->ino, err); ++ ++ *(__u32 *)data = inode.i_generation; ++ return 0; ++} ++ ++static int ioctl_setversion(ext2_filsys fs, struct fuse2fs_file_handle *fh, ++ void *data) ++{ ++ errcode_t err; ++ struct ext2_inode_large inode; ++ int ret; ++ __u32 generation = *(__u32 *)data; ++ struct fuse_context *ctxt = fuse_get_context(); ++ ++ FUSE2FS_CHECK_MAGIC(fs, fh, FUSE2FS_FILE_MAGIC); ++ dbg_printf("%s: ino=%d\n", __func__, fh->ino); ++ memset(&inode, 0, sizeof(inode)); ++ err = ext2fs_read_inode_full(fs, fh->ino, (struct ext2_inode *)&inode, ++ sizeof(inode)); ++ if (err) ++ return translate_error(fs, fh->ino, err); ++ ++ if (ctxt->uid != 0 && inode.i_uid != ctxt->uid) ++ return -EPERM; ++ ++ inode.i_generation = generation; ++ ++ ret = update_ctime(fs, fh->ino, &inode); ++ if (ret) ++ return ret; ++ ++ err = ext2fs_write_inode_full(fs, fh->ino, (struct ext2_inode *)&inode, ++ sizeof(inode)); ++ if (err) ++ return translate_error(fs, fh->ino, err); ++ ++ return 0; ++} ++#endif /* SUPPORT_I_FLAGS */ ++ ++#ifdef FITRIM ++static int ioctl_fitrim(ext2_filsys fs, struct fuse2fs_file_handle *fh, ++ void *data) ++{ ++ struct fstrim_range *fr = data; ++ blk64_t start, end, max_blocks, b, cleared; ++ errcode_t err = 0; ++ ++ start = fr->start / fs->blocksize; ++ end = (fr->start + fr->len - 1) / fs->blocksize; ++ dbg_printf("%s: start=%llu end=%llu\n", __func__, start, end); ++ ++ if (start < fs->super->s_first_data_block) ++ start = fs->super->s_first_data_block; ++ if (start >= ext2fs_blocks_count(fs->super)) ++ start = ext2fs_blocks_count(fs->super) - 1; ++ ++ if (end < fs->super->s_first_data_block) ++ end = fs->super->s_first_data_block; ++ if (end >= ext2fs_blocks_count(fs->super)) ++ end = ext2fs_blocks_count(fs->super) - 1; ++ ++ cleared = 0; ++ max_blocks = 2048ULL * 1024 * 1024 / fs->blocksize; ++ ++ fr->len = 0; ++ while (start <= end) { ++ err = ext2fs_find_first_zero_block_bitmap2(fs->block_map, ++ start, end, &start); ++ if (err == ENOENT) ++ return 0; ++ else if (err) ++ return translate_error(fs, fh->ino, err); ++ ++ b = start + max_blocks < end ? start + max_blocks : end; ++ err = ext2fs_find_first_set_block_bitmap2(fs->block_map, ++ start, b, &b); ++ if (err && err != ENOENT) ++ return translate_error(fs, fh->ino, err); ++ if (b - start >= fr->minlen) { ++ err = io_channel_discard(fs->io, start, b - start); ++ if (err) ++ return translate_error(fs, fh->ino, err); ++ cleared += b - start; ++ fr->len = cleared * fs->blocksize; ++ } ++ start = b + 1; ++ } ++ ++ return err; ++} ++#endif /* FITRIM */ ++ ++#if FUSE_VERSION >= FUSE_MAKE_VERSION(2, 8) ++static int op_ioctl(const char *path EXT2FS_ATTR((unused)), int cmd, ++ void *arg EXT2FS_ATTR((unused)), ++ struct fuse_file_info *fp, ++ unsigned int flags EXT2FS_ATTR((unused)), void *data) ++{ ++ struct fuse_context *ctxt = fuse_get_context(); ++ struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data; ++ struct fuse2fs_file_handle *fh = (struct fuse2fs_file_handle *)fp->fh; ++ ext2_filsys fs; ++ int ret = 0; ++ ++ FUSE2FS_CHECK_CONTEXT(ff); ++ fs = ff->fs; ++ pthread_mutex_lock(&ff->bfl); ++ switch ((unsigned long) cmd) { ++#ifdef SUPPORT_I_FLAGS ++ case EXT2_IOC_GETFLAGS: ++ ret = ioctl_getflags(fs, fh, data); ++ break; ++ case EXT2_IOC_SETFLAGS: ++ ret = ioctl_setflags(fs, fh, data); ++ break; ++ case EXT2_IOC_GETVERSION: ++ ret = ioctl_getversion(fs, fh, data); ++ break; ++ case EXT2_IOC_SETVERSION: ++ ret = ioctl_setversion(fs, fh, data); ++ break; ++#endif ++#ifdef FITRIM ++ case FITRIM: ++ ret = ioctl_fitrim(fs, fh, data); ++ break; ++#endif ++ default: ++ dbg_printf("%s: Unknown ioctl %d\n", __func__, cmd); ++ ret = -ENOTTY; ++ } ++ pthread_mutex_unlock(&ff->bfl); ++ ++ return ret; ++} ++#endif /* FUSE 28 */ ++ ++static int op_bmap(const char *path, size_t blocksize EXT2FS_ATTR((unused)), ++ uint64_t *idx) ++{ ++ struct fuse_context *ctxt = fuse_get_context(); ++ struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data; ++ ext2_filsys fs; ++ ext2_ino_t ino; ++ errcode_t err; ++ int ret = 0; ++ ++ FUSE2FS_CHECK_CONTEXT(ff); ++ fs = ff->fs; ++ pthread_mutex_lock(&ff->bfl); ++ err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, path, &ino); ++ if (err) { ++ ret = translate_error(fs, 0, err); ++ goto out; ++ } ++ dbg_printf("%s: ino=%d blk=%"PRIu64"\n", __func__, ino, *idx); ++ ++ err = ext2fs_bmap2(fs, ino, NULL, NULL, 0, *idx, 0, (blk64_t *)idx); ++ if (err) { ++ ret = translate_error(fs, ino, err); ++ goto out; ++ } ++ ++out: ++ pthread_mutex_unlock(&ff->bfl); ++ return ret; ++} ++ ++#if FUSE_VERSION >= FUSE_MAKE_VERSION(2, 9) ++# ifdef SUPPORT_FALLOCATE ++static int fallocate_helper(struct fuse_file_info *fp, int mode, off_t offset, ++ off_t len) ++{ ++ struct fuse_context *ctxt = fuse_get_context(); ++ struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data; ++ struct fuse2fs_file_handle *fh = (struct fuse2fs_file_handle *)fp->fh; ++ ext2_filsys fs; ++ struct ext2_inode_large inode; ++ blk64_t start, end; ++ __u64 fsize; ++ errcode_t err; ++ int flags; ++ ++ FUSE2FS_CHECK_CONTEXT(ff); ++ fs = ff->fs; ++ FUSE2FS_CHECK_MAGIC(fs, fh, FUSE2FS_FILE_MAGIC); ++ start = offset / fs->blocksize; ++ end = (offset + len - 1) / fs->blocksize; ++ dbg_printf("%s: ino=%d mode=0x%x start=%jd end=%llu\n", __func__, ++ fh->ino, mode, offset / fs->blocksize, end); ++ if (!fs_can_allocate(ff, len / fs->blocksize)) ++ return -ENOSPC; ++ ++ memset(&inode, 0, sizeof(inode)); ++ err = ext2fs_read_inode_full(fs, fh->ino, (struct ext2_inode *)&inode, ++ sizeof(inode)); ++ if (err) ++ return err; ++ fsize = EXT2_I_SIZE(&inode); ++ ++ /* Allocate a bunch of blocks */ ++ flags = (mode & FL_KEEP_SIZE_FLAG ? 0 : ++ EXT2_FALLOCATE_INIT_BEYOND_EOF); ++ err = ext2fs_fallocate(fs, flags, fh->ino, ++ (struct ext2_inode *)&inode, ++ ~0ULL, start, end - start + 1); ++ if (err && err != EXT2_ET_BLOCK_ALLOC_FAIL) ++ return translate_error(fs, fh->ino, err); ++ ++ /* Update i_size */ ++ if (!(mode & FL_KEEP_SIZE_FLAG)) { ++ if ((__u64) offset + len > fsize) { ++ err = ext2fs_inode_size_set(fs, ++ (struct ext2_inode *)&inode, ++ offset + len); ++ if (err) ++ return translate_error(fs, fh->ino, err); ++ } ++ } ++ ++ err = update_mtime(fs, fh->ino, &inode); ++ if (err) ++ return err; ++ ++ err = ext2fs_write_inode_full(fs, fh->ino, (struct ext2_inode *)&inode, ++ sizeof(inode)); ++ if (err) ++ return translate_error(fs, fh->ino, err); ++ ++ return err; ++} ++ ++static errcode_t clean_block_middle(ext2_filsys fs, ext2_ino_t ino, ++ struct ext2_inode_large *inode, off_t offset, ++ off_t len, char **buf) ++{ ++ blk64_t blk; ++ off_t residue; ++ int retflags; ++ errcode_t err; ++ ++ residue = offset % fs->blocksize; ++ if (residue == 0) ++ return 0; ++ ++ if (!*buf) { ++ err = ext2fs_get_mem(fs->blocksize, buf); ++ if (err) ++ return err; ++ } ++ ++ err = ext2fs_bmap2(fs, ino, (struct ext2_inode *)inode, *buf, 0, ++ offset / fs->blocksize, &retflags, &blk); ++ if (err) ++ return err; ++ if (!blk || (retflags & BMAP_RET_UNINIT)) ++ return 0; ++ ++ err = io_channel_read_blk(fs->io, blk, 1, *buf); ++ if (err) ++ return err; ++ ++ memset(*buf + residue, 0, len); ++ ++ return io_channel_write_blk(fs->io, blk, 1, *buf); ++} ++ ++static errcode_t clean_block_edge(ext2_filsys fs, ext2_ino_t ino, ++ struct ext2_inode_large *inode, off_t offset, ++ int clean_before, char **buf) ++{ ++ blk64_t blk; ++ int retflags; ++ off_t residue; ++ errcode_t err; ++ ++ residue = offset % fs->blocksize; ++ if (residue == 0) ++ return 0; ++ ++ if (!*buf) { ++ err = ext2fs_get_mem(fs->blocksize, buf); ++ if (err) ++ return err; ++ } ++ ++ err = ext2fs_bmap2(fs, ino, (struct ext2_inode *)inode, *buf, 0, ++ offset / fs->blocksize, &retflags, &blk); ++ if (err) ++ return err; ++ ++ err = io_channel_read_blk(fs->io, blk, 1, *buf); ++ if (err) ++ return err; ++ if (!blk || (retflags & BMAP_RET_UNINIT)) ++ return 0; ++ ++ if (clean_before) ++ memset(*buf, 0, residue); ++ else ++ memset(*buf + residue, 0, fs->blocksize - residue); ++ ++ return io_channel_write_blk(fs->io, blk, 1, *buf); ++} ++ ++static int punch_helper(struct fuse_file_info *fp, int mode, off_t offset, ++ off_t len) ++{ ++ struct fuse_context *ctxt = fuse_get_context(); ++ struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data; ++ struct fuse2fs_file_handle *fh = (struct fuse2fs_file_handle *)fp->fh; ++ ext2_filsys fs; ++ struct ext2_inode_large inode; ++ blk64_t start, end; ++ errcode_t err; ++ char *buf = NULL; ++ ++ FUSE2FS_CHECK_CONTEXT(ff); ++ fs = ff->fs; ++ FUSE2FS_CHECK_MAGIC(fs, fh, FUSE2FS_FILE_MAGIC); ++ dbg_printf("%s: offset=%jd len=%jd\n", __func__, offset, len); ++ ++ /* kernel ext4 punch requires this flag to be set */ ++ if (!(mode & FL_KEEP_SIZE_FLAG)) ++ return -EINVAL; ++ ++ /* Punch out a bunch of blocks */ ++ start = (offset + fs->blocksize - 1) / fs->blocksize; ++ end = (offset + len - fs->blocksize) / fs->blocksize; ++ dbg_printf("%s: ino=%d mode=0x%x start=%llu end=%llu\n", __func__, ++ fh->ino, mode, start, end); ++ ++ memset(&inode, 0, sizeof(inode)); ++ err = ext2fs_read_inode_full(fs, fh->ino, (struct ext2_inode *)&inode, ++ sizeof(inode)); ++ if (err) ++ return translate_error(fs, fh->ino, err); ++ ++ /* Zero everything before the first block and after the last block */ ++ if ((offset / fs->blocksize) == ((offset + len) / fs->blocksize)) ++ err = clean_block_middle(fs, fh->ino, &inode, offset, ++ len, &buf); ++ else { ++ err = clean_block_edge(fs, fh->ino, &inode, offset, 0, &buf); ++ if (!err) ++ err = clean_block_edge(fs, fh->ino, &inode, ++ offset + len, 1, &buf); ++ } ++ if (buf) ++ ext2fs_free_mem(&buf); ++ if (err) ++ return translate_error(fs, fh->ino, err); ++ ++ /* Unmap full blocks in the middle */ ++ if (start <= end) { ++ err = ext2fs_punch(fs, fh->ino, (struct ext2_inode *)&inode, ++ NULL, start, end); ++ if (err) ++ return translate_error(fs, fh->ino, err); ++ } ++ ++ err = update_mtime(fs, fh->ino, &inode); ++ if (err) ++ return err; ++ ++ err = ext2fs_write_inode_full(fs, fh->ino, (struct ext2_inode *)&inode, ++ sizeof(inode)); ++ if (err) ++ return translate_error(fs, fh->ino, err); ++ ++ return 0; ++} ++ ++static int op_fallocate(const char *path EXT2FS_ATTR((unused)), int mode, ++ off_t offset, off_t len, ++ struct fuse_file_info *fp) ++{ ++ struct fuse_context *ctxt = fuse_get_context(); ++ struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data; ++ ext2_filsys fs = ff->fs; ++ int ret; ++ ++ /* Catch unknown flags */ ++ if (mode & ~(FL_PUNCH_HOLE_FLAG | FL_KEEP_SIZE_FLAG)) ++ return -EINVAL; ++ ++ pthread_mutex_lock(&ff->bfl); ++ if (!fs_writeable(fs)) { ++ ret = -EROFS; ++ goto out; ++ } ++ if (mode & FL_PUNCH_HOLE_FLAG) ++ ret = punch_helper(fp, mode, offset, len); ++ else ++ ret = fallocate_helper(fp, mode, offset, len); ++out: ++ pthread_mutex_unlock(&ff->bfl); ++ ++ return ret; ++} ++# endif /* SUPPORT_FALLOCATE */ ++#endif /* FUSE 29 */ ++ ++static struct fuse_operations fs_ops = { ++ .init = op_init, ++ .destroy = op_destroy, ++ .getattr = op_getattr, ++ .readlink = op_readlink, ++ .mknod = op_mknod, ++ .mkdir = op_mkdir, ++ .unlink = op_unlink, ++ .rmdir = op_rmdir, ++ .symlink = op_symlink, ++ .rename = op_rename, ++ .link = op_link, ++ .chmod = op_chmod, ++ .chown = op_chown, ++ .truncate = op_truncate, ++ .open = op_open, ++ .read = op_read, ++ .write = op_write, ++ .statfs = op_statfs, ++ .release = op_release, ++ .fsync = op_fsync, ++ .setxattr = op_setxattr, ++ .getxattr = op_getxattr, ++ .listxattr = op_listxattr, ++ .removexattr = op_removexattr, ++ .opendir = op_open, ++ .readdir = op_readdir, ++ .releasedir = op_release, ++ .fsyncdir = op_fsync, ++ .access = op_access, ++ .create = op_create, ++ .ftruncate = op_ftruncate, ++ .fgetattr = op_fgetattr, ++ .utimens = op_utimens, ++#if FUSE_VERSION >= FUSE_MAKE_VERSION(2, 9) ++# if defined(UTIME_NOW) || defined(UTIME_OMIT) ++ .flag_utime_omit_ok = 1, ++# endif ++#endif ++ .bmap = op_bmap, ++#ifdef SUPERFLUOUS ++ .lock = op_lock, ++ .poll = op_poll, ++#endif ++#if FUSE_VERSION >= FUSE_MAKE_VERSION(2, 8) ++ .ioctl = op_ioctl, ++ .flag_nullpath_ok = 1, ++#endif ++#if FUSE_VERSION >= FUSE_MAKE_VERSION(2, 9) ++ .flag_nopath = 1, ++# ifdef SUPPORT_FALLOCATE ++ .fallocate = op_fallocate, ++# endif ++#endif ++}; ++ ++static int get_random_bytes(void *p, size_t sz) ++{ ++ int fd; ++ ssize_t r; ++ ++ fd = open("/dev/urandom", O_RDONLY); ++ if (fd < 0) { ++ perror("/dev/urandom"); ++ return 0; ++ } ++ ++ r = read(fd, p, sz); ++ ++ close(fd); ++ return (size_t) r == sz; ++} ++ ++static void print_help(const char *progname) ++{ ++ printf(_("Usage: %s dev mntpt [-o options] [fuse_args]\n"), progname); ++} ++ ++int main(int argc, char *argv[]) ++{ ++ errcode_t err; ++ char *tok, *arg, *logfile; ++ int i; ++ int readwrite = 1, panic_on_error = 0, minixdf = 0; ++ struct fuse2fs *ff; ++ char extra_args[BUFSIZ]; ++ int ret = 0, flags = EXT2_FLAG_64BITS | EXT2_FLAG_EXCLUSIVE; ++ ++ if (argc < 2) { ++ print_help(argv[0]); ++ return 1; ++ } ++ ++ for (i = 1; i < argc; i++) { ++ if (strcmp(argv[i], "--help") == 0) { ++ print_help(argv[0]); ++ return 1; ++ } ++ } ++ ++ for (i = 1; i < argc - 1; i++) { ++ if (strcmp(argv[i], "-o")) ++ continue; ++ arg = argv[i + 1]; ++ while ((tok = strtok(arg, ","))) { ++ arg = NULL; ++ if (!strcmp(tok, "ro")) ++ readwrite = 0; ++ else if (!strcmp(tok, "errors=panic")) ++ panic_on_error = 1; ++ else if (!strcmp(tok, "minixdf")) ++ minixdf = 1; ++ } ++ } ++ ++ if (!readwrite) ++ printf("%s", _("Mounting read-only.\n")); ++ ++#ifdef ENABLE_NLS ++ setlocale(LC_MESSAGES, ""); ++ setlocale(LC_CTYPE, ""); ++ bindtextdomain(NLS_CAT_NAME, LOCALEDIR); ++ textdomain(NLS_CAT_NAME); ++ set_com_err_gettext(gettext); ++#endif ++ add_error_table(&et_ext2_error_table); ++ ++ ff = calloc(1, sizeof(*ff)); ++ if (!ff) { ++ perror("init"); ++ return 1; ++ } ++ ff->magic = FUSE2FS_MAGIC; ++ ff->panic_on_error = panic_on_error; ++ ff->minixdf = minixdf; ++ ++ /* Set up error logging */ ++ logfile = getenv("FUSE2FS_LOGFILE"); ++ if (logfile) { ++ ff->err_fp = fopen(logfile, "a"); ++ if (!ff->err_fp) { ++ perror(logfile); ++ goto out_nofs; ++ } ++ } else ++ ff->err_fp = stderr; ++ ++ /* Will we allow users to allocate every last block? */ ++ if (getenv("FUSE2FS_ALLOC_ALL_BLOCKS")) { ++ printf(_("%s: Allowing users to allocate all blocks. " ++ "This is dangerous!\n"), argv[1]); ++ ff->alloc_all_blocks = 1; ++ } ++ ++ /* Start up the fs (while we still can use stdout) */ ++ ret = 2; ++ if (readwrite) ++ flags |= EXT2_FLAG_RW; ++ err = ext2fs_open2(argv[1], NULL, flags, 0, 0, unix_io_manager, ++ &global_fs); ++ if (err) { ++ printf(_("%s: %s.\n"), argv[1], error_message(err)); ++ printf(_("Please run e2fsck -fy %s.\n"), argv[1]); ++ goto out_nofs; ++ } ++ ff->fs = global_fs; ++ global_fs->priv_data = ff; ++ ++ ret = 3; ++ if (EXT2_HAS_INCOMPAT_FEATURE(global_fs->super, ++ EXT3_FEATURE_INCOMPAT_RECOVER)) { ++ if (readwrite) { ++ printf(_("%s: recovering journal\n"), argv[1]); ++ err = ext2fs_run_ext3_journal(&global_fs); ++ if (err) { ++ printf(_("%s: %s.\n"), argv[1], ++ error_message(err)); ++ printf(_("Please run e2fsck -fy %s.\n"), ++ argv[1]); ++ goto out; ++ } ++ global_fs->super->s_feature_incompat &= ++ ~EXT3_FEATURE_INCOMPAT_RECOVER; ++ ext2fs_mark_super_dirty(global_fs); ++ } else { ++ printf("%s", _("Journal needs recovery; running " ++ "`e2fsck -E journal_only' is required.\n")); ++ goto out; ++ } ++ } ++ ++ if (readwrite) { ++ if (EXT2_HAS_COMPAT_FEATURE(global_fs->super, ++ EXT3_FEATURE_COMPAT_HAS_JOURNAL)) ++ printf(_("%s: Writing to the journal is not supported.\n"), ++ argv[1]); ++ err = ext2fs_read_inode_bitmap(global_fs); ++ if (err) { ++ translate_error(global_fs, 0, err); ++ goto out; ++ } ++ err = ext2fs_read_block_bitmap(global_fs); ++ if (err) { ++ translate_error(global_fs, 0, err); ++ goto out; ++ } ++ } ++ ++ if (!(global_fs->super->s_state & EXT2_VALID_FS)) ++ printf("%s", _("Warning: Mounting unchecked fs, running e2fsck " ++ "is recommended.\n")); ++ if (global_fs->super->s_max_mnt_count > 0 && ++ global_fs->super->s_mnt_count >= global_fs->super->s_max_mnt_count) ++ printf("%s", _("Warning: Maximal mount count reached, running " ++ "e2fsck is recommended.\n")); ++ if (global_fs->super->s_checkinterval > 0 && ++ global_fs->super->s_lastcheck + ++ global_fs->super->s_checkinterval <= time(0)) ++ printf("%s", _("Warning: Check time reached; running e2fsck " ++ "is recommended.\n")); ++ if (global_fs->super->s_last_orphan) ++ printf("%s", ++ _("Orphans detected; running e2fsck is recommended.\n")); ++ ++ if (global_fs->super->s_state & EXT2_ERROR_FS) { ++ printf("%s", ++ _("Errors detected; running e2fsck is required.\n")); ++ goto out; ++ } ++ ++ /* Initialize generation counter */ ++ get_random_bytes(&ff->next_generation, sizeof(unsigned int)); ++ ++ /* Stuff in some fuse parameters of our own */ ++ snprintf(extra_args, BUFSIZ, "-okernel_cache,subtype=ext4,use_ino," ++ "fsname=%s,attr_timeout=0,allow_other" FUSE_PLATFORM_OPTS, ++ argv[1]); ++ argv[0] = argv[1]; ++ argv[1] = argv[2]; ++ argv[2] = extra_args; ++ ++ pthread_mutex_init(&ff->bfl, NULL); ++ fuse_main(argc, argv, &fs_ops, ff); ++ pthread_mutex_destroy(&ff->bfl); ++ ++ ret = 0; ++out: ++ err = ext2fs_close(global_fs); ++ if (err) ++ com_err(argv[0], err, "while closing fs"); ++ global_fs = NULL; ++out_nofs: ++ free(ff); ++ ++ return ret; ++} ++ ++static int __translate_error(ext2_filsys fs, errcode_t err, ext2_ino_t ino, ++ const char *file, int line) ++{ ++ struct timespec now; ++ int ret = err; ++ struct fuse2fs *ff = fs->priv_data; ++ int is_err = 0; ++ ++ /* Translate ext2 error to unix error code */ ++ if (err < EXT2_ET_BASE) ++ goto no_translation; ++ switch (err) { ++ case EXT2_ET_NO_MEMORY: ++ case EXT2_ET_TDB_ERR_OOM: ++ ret = -ENOMEM; ++ break; ++ case EXT2_ET_INVALID_ARGUMENT: ++ case EXT2_ET_LLSEEK_FAILED: ++ ret = -EINVAL; ++ break; ++ case EXT2_ET_NO_DIRECTORY: ++ ret = -ENOTDIR; ++ break; ++ case EXT2_ET_FILE_NOT_FOUND: ++ ret = -ENOENT; ++ break; ++ case EXT2_ET_DIR_NO_SPACE: ++ is_err = 1; ++ case EXT2_ET_TOOSMALL: ++ case EXT2_ET_BLOCK_ALLOC_FAIL: ++ case EXT2_ET_INODE_ALLOC_FAIL: ++ case EXT2_ET_EA_NO_SPACE: ++ ret = -ENOSPC; ++ break; ++ case EXT2_ET_SYMLINK_LOOP: ++ ret = -EMLINK; ++ break; ++ case EXT2_ET_FILE_TOO_BIG: ++ ret = -EFBIG; ++ break; ++ case EXT2_ET_TDB_ERR_EXISTS: ++ case EXT2_ET_FILE_EXISTS: ++ ret = -EEXIST; ++ break; ++ case EXT2_ET_MMP_FAILED: ++ case EXT2_ET_MMP_FSCK_ON: ++ ret = -EBUSY; ++ break; ++ case EXT2_ET_EA_KEY_NOT_FOUND: ++#ifdef ENODATA ++ ret = -ENODATA; ++#else ++ ret = -ENOENT; ++#endif ++ break; ++ /* Sometimes fuse returns a garbage file handle pointer to us... */ ++ case EXT2_ET_MAGIC_EXT2_FILE: ++ ret = -EFAULT; ++ break; ++ case EXT2_ET_UNIMPLEMENTED: ++ ret = -EOPNOTSUPP; ++ break; ++ default: ++ is_err = 1; ++ ret = -EIO; ++ break; ++ } ++ ++no_translation: ++ if (!is_err) ++ return ret; ++ ++ if (ino) ++ fprintf(ff->err_fp, "FUSE2FS (%s): %s (inode #%d) at %s:%d.\n", ++ fs && fs->device_name ? fs->device_name : "???", ++ error_message(err), ino, file, line); ++ else ++ fprintf(ff->err_fp, "FUSE2FS (%s): %s at %s:%d.\n", ++ fs && fs->device_name ? fs->device_name : "???", ++ error_message(err), file, line); ++ fflush(ff->err_fp); ++ ++ /* Make a note in the error log */ ++ get_now(&now); ++ fs->super->s_last_error_time = now.tv_sec; ++ fs->super->s_last_error_ino = ino; ++ fs->super->s_last_error_line = line; ++ fs->super->s_last_error_block = err; /* Yeah... */ ++ strncpy((char *)fs->super->s_last_error_func, file, ++ sizeof(fs->super->s_last_error_func)); ++ if (fs->super->s_first_error_time == 0) { ++ fs->super->s_first_error_time = now.tv_sec; ++ fs->super->s_first_error_ino = ino; ++ fs->super->s_first_error_line = line; ++ fs->super->s_first_error_block = err; ++ strncpy((char *)fs->super->s_first_error_func, file, ++ sizeof(fs->super->s_first_error_func)); ++ } ++ ++ fs->super->s_error_count++; ++ ext2fs_mark_super_dirty(fs); ++ ext2fs_flush(fs); ++ if (ff->panic_on_error) ++ abort(); ++ ++ return ret; ++} +--- a/misc/jfs_user.h ++++ /dev/null +@@ -1,8 +0,0 @@ +-#ifndef _JFS_USER_H +-#define _JFS_USER_H +- +-typedef unsigned short kdev_t; +- +-#include +- +-#endif /* _JFS_USER_H */ +--- a/misc/logsave.c ++++ b/misc/logsave.c +@@ -219,7 +219,7 @@ + sprintf(buffer, "died with signal %d\n", + WTERMSIG(status)); + send_output(buffer, 0, SEND_BOTH); +- rc = 1; ++ return 1; + } + rc = 0; + } +--- a/misc/lsattr.c ++++ b/misc/lsattr.c +@@ -43,8 +43,8 @@ + #include "et/com_err.h" + #include "e2p/e2p.h" + ++#include "support/nls-enable.h" + #include "../version.h" +-#include "nls-enable.h" + + #ifdef __GNUC__ + #define EXT2FS_ATTR(x) __attribute__(x) +--- a/misc/Makefile.in ++++ b/misc/Makefile.in +@@ -14,6 +14,9 @@ + @DEFRAG_CMT@@LINUX_CMT@E4DEFRAG_PROG= e4defrag + @DEFRAG_CMT@@LINUX_CMT@E4DEFRAG_MAN= e4defrag.8 + ++@LINUX_CMT@E4CRYPT_PROG = e4crypt ++@LINUX_CMT@E4CRYPT_MAN= e4crypt.8 ++ + @IMAGER_CMT@E2IMAGE_PROG= e2image + @IMAGER_CMT@E2IMAGE_MAN= e2image.8 + +@@ -27,13 +30,16 @@ + @BLKID_CMT@FINDFS_LINK= findfs + @BLKID_CMT@FINDFS_MAN= findfs.8 + ++@FUSE_CMT@FUSE_PROG= fuse2fs ++ + SPROGS= mke2fs badblocks tune2fs dumpe2fs $(BLKID_PROG) logsave \ + $(E2IMAGE_PROG) @FSCK_PROG@ e2undo +-USPROGS= mklost+found filefrag e2freefrag $(UUIDD_PROG) $(E4DEFRAG_PROG) ++USPROGS= mklost+found filefrag e2freefrag $(UUIDD_PROG) \ ++ $(E4DEFRAG_PROG) $(E4CRYPT_PROG) $(FUSE_PROG) + SMANPAGES= tune2fs.8 mklost+found.8 mke2fs.8 dumpe2fs.8 badblocks.8 \ + e2label.8 $(FINDFS_MAN) $(BLKID_MAN) $(E2IMAGE_MAN) \ + logsave.8 filefrag.8 e2freefrag.8 e2undo.8 \ +- $(UUIDD_MAN) $(E4DEFRAG_MAN) @FSCK_MAN@ ++ $(UUIDD_MAN) $(E4DEFRAG_MAN) $(E4CRYPT_MAN) @FSCK_MAN@ + FMANPAGES= mke2fs.conf.5 ext4.5 + + UPROGS= chattr lsattr @UUID_CMT@ uuidgen +@@ -43,8 +49,8 @@ + + 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 ++MKE2FS_OBJS= mke2fs.o util.o default_profile.o mk_hugefiles.o \ ++ create_inode.o + CHATTR_OBJS= chattr.o + LSATTR_OBJS= lsattr.o + UUIDGEN_OBJS= uuidgen.o +@@ -57,13 +63,17 @@ + FILEFRAG_OBJS= filefrag.o + E2UNDO_OBJS= e2undo.o + E4DEFRAG_OBJS= e4defrag.o ++E4CRYPT_OBJS= e4crypt.o + E2FREEFRAG_OBJS= e2freefrag.o ++E2FUZZ_OBJS= e2fuzz.o ++FUSE2FS_OBJS= fuse2fs.o journal.o recovery.o revoke.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 +@@ -78,54 +88,59 @@ + PROFILED_E2FREEFRAG_OBJS= profiled/e2freefrag.o + PROFILED_E2UNDO_OBJS= profiled/e2undo.o + PROFILED_E4DEFRAG_OBJS= profiled/e4defrag.o ++PROFILED_E4CRYPT_OBJS= profiled/e4crypt.o ++PROFILED_FUSE2FS_OJBS= profiled/fuse2fs.o profiled/journal.o \ ++ profiled/recovery.o profiled/revoke.o + + SRCS= $(srcdir)/tune2fs.c $(srcdir)/mklost+found.c $(srcdir)/mke2fs.c $(srcdir)/mk_hugefiles.c \ + $(srcdir)/chattr.c $(srcdir)/lsattr.c $(srcdir)/dumpe2fs.c \ + $(srcdir)/badblocks.c $(srcdir)/fsck.c $(srcdir)/util.c \ + $(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 +- +-LIBS= $(LIBEXT2FS) $(LIBCOM_ERR) +-DEPLIBS= $(LIBEXT2FS) $(DEPLIBCOM_ERR) +-PROFILED_LIBS= $(PROFILED_LIBEXT2FS) $(PROFILED_LIBCOM_ERR) +-PROFILED_DEPLIBS= $(PROFILED_LIBEXT2FS) $(DEPPROFILED_LIBCOM_ERR) ++ $(srcdir)/ismounted.c $(srcdir)/e2undo.c \ ++ $(srcdir)/e2freefrag.c $(srcdir)/create_inode.c \ ++ $(srcdir)/fuse2fs.c \ ++ $(srcdir)/../debugfs/journal.c $(srcdir)/../e2fsck/revoke.c \ ++ $(srcdir)/../e2fsck/recovery.c ++ ++LIBS= $(LIBEXT2FS) $(LIBCOM_ERR) $(LIBSUPPORT) ++DEPLIBS= $(LIBEXT2FS) $(DEPLIBCOM_ERR) $(DEPLIBSUPPORT) ++PROFILED_LIBS= $(PROFILED_LIBEXT2FS) $(PROFILED_LIBCOM_ERR) $(LIBSUPPORT) ++PROFILED_DEPLIBS= $(PROFILED_LIBEXT2FS) $(DEPPROFILED_LIBCOM_ERR) $(DEPLIBSUPPORT) + +-STATIC_LIBS= $(STATIC_LIBEXT2FS) $(STATIC_LIBCOM_ERR) +-STATIC_DEPLIBS= $(STATIC_LIBEXT2FS) $(DEPSTATIC_LIBCOM_ERR) ++STATIC_LIBS= $(STATIC_LIBEXT2FS) $(STATIC_LIBCOM_ERR) $(LIBSUPPORT) ++STATIC_DEPLIBS= $(STATIC_LIBEXT2FS) $(DEPSTATIC_LIBCOM_ERR) $(DEPLIBSUPPORT) + +-LIBS_E2P= $(LIBE2P) $(LIBCOM_ERR) +-DEPLIBS_E2P= $(LIBE2P) $(DEPLIBCOM_ERR) ++LIBS_E2P= $(LIBE2P) $(LIBCOM_ERR) ++DEPLIBS_E2P= $(LIBE2P) $(DEPLIBCOM_ERR) + + COMPILE_ET=$(top_builddir)/lib/et/compile_et --build-tree + ++# This nastyness is needed because of jfs_user.h hackery; when we finally ++# clean up this mess, we should be able to drop it ++JOURNAL_CFLAGS = -I$(srcdir)/../e2fsck $(ALL_CFLAGS) -DDEBUGFS ++DEPEND_CFLAGS = -I$(top_srcdir)/e2fsck ++ + .c.o: + $(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) $(E4CRYPT_PROGS) e2fuzz + + @PROFILE_CMT@all:: tune2fs.profiled blkid.profiled e2image.profiled \ + e2undo.profiled mke2fs.profiled dumpe2fs.profiled fsck.profiled \ + logsave.profiled filefrag.profiled uuidgen.profiled $(UUIDD_PROFILED) \ +- e2image.profiled e4defrag.profiled e2freefrag.profiled ++ e2image.profiled e4defrag.profiled e4crypt.profiled \ ++ e2freefrag.profiled + + profiled: + @PROFILE_CMT@ $(E) " MKDIR $@" + @PROFILE_CMT@ $(Q) mkdir profiled + +-prof_err.c prof_err.h: $(srcdir)/../e2fsck/prof_err.et +- $(E) " COMPILE_ET prof_err.et" +- $(Q) $(COMPILE_ET) $(srcdir)/../e2fsck/prof_err.et +- +-profile.h: $(top_srcdir)/e2fsck/profile.h +- $(E) " CP $<" +- $(Q) cp $< $@ +- + mke2fs.conf: $(srcdir)/mke2fs.conf.in + if test -f $(srcdir)/mke2fs.conf.custom.in ; then \ + cp $(srcdir)/mke2fs.conf.custom.in mke2fs.conf; \ +@@ -137,12 +152,6 @@ + $(E) " PROFILE_TO_C mke2fs.conf" + $(Q) $(AWK) -f $(srcdir)/profile-to-c.awk < mke2fs.conf \ + > default_profile.c +-profile.o: +- $(E) " CC $<" +- $(Q) $(CC) -c $(ALL_CFLAGS) $(srcdir)/../e2fsck/profile.c -o $@ +-@PROFILE_CMT@ $(Q) $(CC) $(ALL_CFLAGS) -g -pg -o profiled/profile.o -c \ +-@PROFILE_CMT@ $(srcdir)/../e2fsck/profile.c +- + findsuper: findsuper.o + $(E) " LD $@" + $(Q) $(CC) $(ALL_LDFLAGS) -o findsuper findsuper.o $(LIBS) $(SYSLIBS) +@@ -157,26 +166,27 @@ + $(LIBBLKID) $(LIBEXT2FS) $(LIBINTL) $(SYSLIBS) + + tune2fs: $(TUNE2FS_OBJS) $(DEPLIBS) $(DEPLIBS_E2P) $(DEPLIBBLKID) \ +- $(DEPLIBUUID) $(DEPLIBQUOTA) $(LIBEXT2FS) ++ $(DEPLIBUUID) $(LIBEXT2FS) + $(E) " LD $@" + $(Q) $(CC) $(ALL_LDFLAGS) -o tune2fs $(TUNE2FS_OBJS) $(LIBS) \ +- $(LIBBLKID) $(LIBUUID) $(LIBQUOTA) $(LIBEXT2FS) $(LIBS_E2P) \ +- $(LIBINTL) $(SYSLIBS) ++ $(LIBBLKID) $(LIBUUID) $(LIBEXT2FS) $(LIBS_E2P) \ ++ $(LIBINTL) $(SYSLIBS) $(LIBBLKID) $(LIBMAGIC) + + tune2fs.static: $(TUNE2FS_OBJS) $(STATIC_DEPLIBS) $(STATIC_LIBE2P) $(DEPSTATIC_LIBBLKID) + $(E) " LD $@" + $(Q) $(CC) $(LDFLAGS_STATIC) -o tune2fs.static $(TUNE2FS_OBJS) \ + $(STATIC_LIBS) $(STATIC_LIBBLKID) $(STATIC_LIBUUID) \ +- $(STATIC_LIBQUOTA) $(STATIC_LIBE2P) $(LIBINTL) $(SYSLIBS) ++ $(STATIC_LIBE2P) $(LIBINTL) $(SYSLIBS) \ ++ $(STATIC_LIBBLKID) $(LIBMAGIC) + + tune2fs.profiled: $(TUNE2FS_OBJS) $(PROFILED_DEPLIBS) \ +- $(PROFILED_E2P) $(DEPPROFILED_LIBBLKID) $(DEPPROFILED_LIBUUID) \ +- $(DEPPROFILED_LIBQUOTA) ++ $(PROFILED_E2P) $(DEPPROFILED_LIBBLKID) $(DEPPROFILED_LIBUUID) + $(E) " LD $@" + $(Q) $(CC) $(ALL_LDFLAGS) -g -pg -o tune2fs.profiled \ + $(PROFILED_TUNE2FS_OBJS) $(PROFILED_LIBBLKID) \ +- $(PROFILED_LIBUUID) $(PROFILED_LIBQUOTA) $(PROFILED_LIBE2P) \ +- $(LIBINTL) $(PROFILED_LIBS) $(SYSLIBS) ++ $(PROFILED_LIBUUID) $(PROFILED_LIBE2P) \ ++ $(LIBINTL) $(PROFILED_LIBS) $(SYSLIBS) $(PROFILED_LIBBLKID) \ ++ $(LIBMAGIC) + + blkid: $(BLKID_OBJS) $(DEPLIBBLKID) $(LIBEXT2FS) + $(E) " LD $@" +@@ -194,15 +204,16 @@ + $(Q) $(CC) $(ALL_LDFLAGS) -g -pg -o blkid.profiled $(PROFILED_BLKID_OBJS) \ + $(PROFILED_LIBBLKID) $(LIBINTL) $(PROFILED_LIBEXT2FS) $(SYSLIBS) + +-e2image: $(E2IMAGE_OBJS) $(DEPLIBS) ++e2image: $(E2IMAGE_OBJS) $(DEPLIBS) $(DEPLIBBLKID) + $(E) " LD $@" + $(Q) $(CC) $(ALL_LDFLAGS) -o e2image $(E2IMAGE_OBJS) $(LIBS) \ +- $(LIBINTL) $(SYSLIBS) ++ $(LIBINTL) $(SYSLIBS) $(LIBBLKID) $(LIBMAGIC) + +-e2image.profiled: $(E2IMAGE_OBJS) $(PROFILED_DEPLIBS) ++e2image.profiled: $(E2IMAGE_OBJS) $(PROFILED_DEPLIBS) $(DEPLIBBLKID) + $(E) " LD $@" + $(Q) $(CC) $(ALL_LDFLAGS) -g -pg -o e2image.profiled \ +- $(PROFILED_E2IMAGE_OBJS) $(PROFILED_LIBS) $(LIBINTL) $(SYSLIBS) ++ $(PROFILED_E2IMAGE_OBJS) $(PROFILED_LIBS) $(LIBINTL) $(SYSLIBS) \ ++ $(LIBBLKID) $(LIBMAGIC) + + e2undo: $(E2UNDO_OBJS) $(DEPLIBS) + $(E) " LD $@" +@@ -219,11 +230,22 @@ + $(Q) $(CC) $(ALL_LDFLAGS) -o e4defrag $(E4DEFRAG_OBJS) $(LIBS) \ + $(SYSLIBS) + ++e4crypt: $(E4CRYPT_OBJS) $(DEPLIBS) $(DEPSTATIC_LIBUUID) ++ $(E) " LD $@" ++ $(Q) $(CC) $(ALL_LDFLAGS) -o e4crypt $(E4CRYPT_OBJS) \ ++ $(STATIC_LIBUUID) $(STATIC_LIBS) ++ + e4defrag.profiled: $(E4DEFRAG_OBJS) $(PROFILED_DEPLIBS) + $(E) " LD $@" + $(Q) $(CC) $(ALL_LDFLAGS) -g -pg -o e4defrag.profiled \ + $(PROFILED_E4DEFRAG_OBJS) $(PROFILED_LIBS) $(SYSLIBS) + ++e4crypt.profiled: $(E4CRYPT_OBJS) $(DEPPROFILED_LIBUUID) $(PROFILED_DEPLIBS) ++ $(E) " LD $@" ++ $(Q) $(CC) $(ALL_LDFLAGS) -g -pg -o e4crypt.profiled \ ++ $(PROFILED_E4CRYPT_OBJS) $(PROFILED_LIBUUID) $(PROFILED_LIBS) \ ++ $(SYSLIBS) ++ + base_device: base_device.c + $(E) " LD $@" + $(Q) $(CC) $(ALL_CFLAGS) $(ALL_LDFLAGS) $(srcdir)/base_device.c \ +@@ -239,27 +261,27 @@ + $(LIBINTL) $(SYSLIBS) + + mke2fs: $(MKE2FS_OBJS) $(DEPLIBS) $(LIBE2P) $(DEPLIBBLKID) $(DEPLIBUUID) \ +- $(DEPLIBQUOTA) $(LIBEXT2FS) ++ $(LIBEXT2FS) + $(E) " LD $@" + $(Q) $(CC) $(ALL_LDFLAGS) -o mke2fs $(MKE2FS_OBJS) $(LIBS) $(LIBBLKID) \ +- $(LIBUUID) $(LIBQUOTA) $(LIBEXT2FS) $(LIBE2P) $(LIBINTL) \ +- $(SYSLIBS) ++ $(LIBUUID) $(LIBEXT2FS) $(LIBE2P) $(LIBINTL) \ ++ $(SYSLIBS) $(LIBMAGIC) + + mke2fs.static: $(MKE2FS_OBJS) $(STATIC_DEPLIBS) $(STATIC_LIBE2P) $(DEPSTATIC_LIBUUID) \ +- $(DEPSTATIC_LIBQUOTA) $(DEPSTATIC_LIBBLKID) ++ $(DEPSTATIC_LIBBLKID) + $(E) " LD $@" + $(Q) $(CC) $(ALL_LDFLAGS) -static -o mke2fs.static $(MKE2FS_OBJS) \ +- $(STATIC_LIBQUOTA) $(STATIC_LIBS) $(STATIC_LIBE2P) \ +- $(STATIC_LIBBLKID) $(STATIC_LIBUUID) $(LIBINTL) $(SYSLIBS) ++ $(STATIC_LIBS) $(STATIC_LIBE2P) \ ++ $(STATIC_LIBBLKID) $(STATIC_LIBUUID) $(LIBINTL) $(SYSLIBS) \ ++ $(LIBMAGIC) + + mke2fs.profiled: $(MKE2FS_OBJS) $(PROFILED_DEPLIBS) \ +- $(PROFILED_LIBE2P) $(PROFILED_DEPLIBBLKID) $(PROFILED_DEPLIBUUID) \ +- $(PROFILED_LIBQUOTA) ++ $(PROFILED_LIBE2P) $(PROFILED_DEPLIBBLKID) $(PROFILED_DEPLIBUUID) + $(E) " LD $@" + $(Q) $(CC) $(ALL_LDFLAGS) -g -pg -o mke2fs.profiled \ + $(PROFILED_MKE2FS_OBJS) $(PROFILED_LIBBLKID) \ +- $(PROFILED_LIBUUID) $(PROFILED_LIBQUOTA) $(PROFILED_LIBE2P) \ +- $(LIBINTL) $(PROFILED_LIBS) $(SYSLIBS) ++ $(PROFILED_LIBUUID) $(PROFILED_LIBE2P) \ ++ $(LIBINTL) $(PROFILED_LIBS) $(SYSLIBS) $(LIBMAGIC) + + chattr: $(CHATTR_OBJS) $(DEPLIBS_E2P) + $(E) " LD $@" +@@ -292,17 +314,19 @@ + $(Q) $(CC) $(ALL_LDFLAGS) -g -pg -o uuidd.profiled $(PROFILED_UUIDD_OBJS) \ + $(PROFILED_LIBUUID) $(LIBINTL) $(SYSLIBS) + +-dumpe2fs: $(DUMPE2FS_OBJS) $(DEPLIBS) $(DEPLIBS_E2P) $(DEPLIBUUID) ++dumpe2fs: $(DUMPE2FS_OBJS) $(DEPLIBS) $(DEPLIBS_E2P) $(DEPLIBUUID) $(DEPLIBBLKID) + $(E) " LD $@" + $(Q) $(CC) $(ALL_LDFLAGS) -o dumpe2fs $(DUMPE2FS_OBJS) $(LIBS) \ +- $(LIBS_E2P) $(LIBUUID) $(LIBINTL) $(SYSLIBS) ++ $(LIBS_E2P) $(LIBUUID) $(LIBINTL) $(SYSLIBS) $(LIBBLKID) \ ++ $(LIBMAGIC) + + dumpe2fs.profiled: $(DUMPE2FS_OBJS) $(PROFILED_DEPLIBS) \ +- $(PROFILED_LIBE2P) $(PROFILED_DEPLIBUUID) ++ $(PROFILED_LIBE2P) $(PROFILED_DEPLIBUUID) $(PROFILED_DEPLIBBLKID) + $(E) " LD $@" + $(Q) $(CC) $(ALL_LDFLAGS) -g -pg -o dumpe2fs.profiled \ + $(PROFILED_DUMPE2FS_OBJS) $(PROFILED_LIBS) \ +- $(PROFILED_LIBE2P) $(PROFILED_LIBUUID) $(LIBINTL) $(SYSLIBS) ++ $(PROFILED_LIBE2P) $(PROFILED_LIBUUID) $(LIBINTL) $(SYSLIBS) \ ++ $(PROFILED_LIBBLKID) $(LIBMAGIC) + + fsck: $(FSCK_OBJS) $(DEPLIBBLKID) + $(E) " LD $@" +@@ -344,6 +368,12 @@ + $(Q) $(CC) $(ALL_LDFLAGS) -g -pg -o e2freefrag.profiled \ + $(PROFILED_E2FREEFRAG_OBJS) $(PROFILED_LIBS) $(SYSLIBS) + ++e2fuzz: $(E2FUZZ_OBJS) $(DEPLIBS) $(DEPLIBBLKID) $(DEPLIBUUID) \ ++ $(LIBEXT2FS) ++ $(E) " LD $@" ++ $(Q) $(CC) $(ALL_LDFLAGS) -o e2fuzz $(E2FUZZ_OBJS) $(LIBS) \ ++ $(LIBBLKID) $(LIBUUID) $(LIBEXT2FS) $(SYSLIBS) ++ + filefrag: $(FILEFRAG_OBJS) + $(E) " LD $@" + $(Q) $(CC) $(ALL_LDFLAGS) -o filefrag $(FILEFRAG_OBJS) $(SYSLIBS) +@@ -353,6 +383,27 @@ + $(Q) $(CC) $(ALL_LDFLAGS) -g -pg -o filefrag.profiled \ + $(PROFILED_FILEFRAG_OBJS) + ++fuse2fs: $(FUSE2FS_OBJS) $(DEPLIBS) $(DEPLIBBLKID) $(DEPLIBUUID) \ ++ $(LIBEXT2FS) ++ $(E) " LD $@" ++ $(Q) $(CC) $(ALL_LDFLAGS) -o fuse2fs $(FUSE2FS_OBJS) $(LIBS) \ ++ $(LIBFUSE) $(LIBBLKID) $(LIBUUID) $(LIBEXT2FS) $(LIBINTL) ++ ++journal.o: $(srcdir)/../debugfs/journal.c ++ $(E) " CC $@" ++ $(Q) $(CC) -c $(JOURNAL_CFLAGS) -I$(srcdir) \ ++ $(srcdir)/../debugfs/journal.c -o $@ ++ ++recovery.o: $(srcdir)/../e2fsck/recovery.c ++ $(E) " CC $@" ++ $(Q) $(CC) -c $(JOURNAL_CFLAGS) -I$(srcdir) \ ++ $(srcdir)/../e2fsck/recovery.c -o $@ ++ ++revoke.o: $(srcdir)/../e2fsck/revoke.c ++ $(E) " CC $@" ++ $(Q) $(CC) -c $(JOURNAL_CFLAGS) -I$(srcdir) \ ++ $(srcdir)/../e2fsck/revoke.c -o $@ ++ + tst_ismounted: $(srcdir)/ismounted.c $(STATIC_LIBEXT2FS) $(DEPLIBCOM_ERR) + $(E) " LD $@" + $(CC) -o tst_ismounted $(srcdir)/ismounted.c -DDEBUG $(ALL_CFLAGS) \ +@@ -398,6 +449,10 @@ + $(E) " SUBST $@" + $(Q) $(SUBSTITUTE_UPTIME) $(srcdir)/e4defrag.8.in e4defrag.8 + ++e4crypt.8: $(DEP_SUBSTITUTE) $(srcdir)/e4crypt.8.in ++ $(E) " SUBST $@" ++ $(Q) $(SUBSTITUTE_UPTIME) $(srcdir)/e4crypt.8.in e4crypt.8 ++ + dumpe2fs.8: $(DEP_SUBSTITUTE) $(srcdir)/dumpe2fs.8.in + $(E) " SUBST $@" + $(Q) $(SUBSTITUTE_UPTIME) $(srcdir)/dumpe2fs.8.in dumpe2fs.8 +@@ -610,7 +665,7 @@ + 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 +@@ -628,16 +683,16 @@ + $(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 \ +- $(top_srcdir)/lib/e2p/e2p.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 $(srcdir)/util.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)/version.h $(srcdir)/nls-enable.h ++ $(top_srcdir)/lib/ext2fs/kernel-list.h $(top_srcdir)/lib/support/plausible.h \ ++ $(top_srcdir)/lib/support/quotaio.h $(top_srcdir)/lib/support/dqblk_v2.h \ ++ $(top_srcdir)/lib/support/quotaio_tree.h $(top_srcdir)/lib/e2p/e2p.h \ ++ $(srcdir)/util.h $(top_srcdir)/version.h \ ++ $(top_srcdir)/lib/support/nls-enable.h + mklost+found.o: $(srcdir)/mklost+found.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)/version.h \ +- $(srcdir)/nls-enable.h ++ $(top_srcdir)/lib/support/nls-enable.h + mke2fs.o: $(srcdir)/mke2fs.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 \ +@@ -645,11 +700,13 @@ + $(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 ++ $(srcdir)/util.h $(top_srcdir)/lib/support/nls-enable.h \ ++ $(top_srcdir)/lib/support/plausible.h $(top_srcdir)/lib/support/profile.h \ ++ $(top_builddir)/lib/support/prof_err.h $(top_srcdir)/version.h \ ++ $(top_srcdir)/lib/support/quotaio.h $(top_srcdir)/lib/ext2fs/ext2fs.h \ ++ $(top_srcdir)/lib/support/dqblk_v2.h \ ++ $(top_srcdir)/lib/support/quotaio_tree.h $(srcdir)/mke2fs.h \ ++ $(srcdir)/create_inode.h $(top_srcdir)/lib/e2p/e2p.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 \ +@@ -658,26 +715,29 @@ + $(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 $(srcdir)/nls-enable.h \ +- $(srcdir)/mke2fs.h ++ $(srcdir)/util.h $(top_srcdir)/lib/support/profile.h \ ++ $(top_builddir)/lib/support/prof_err.h \ ++ $(top_srcdir)/lib/support/nls-enable.h $(srcdir)/mke2fs.h + chattr.o: $(srcdir)/chattr.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/et/com_err.h \ +- $(top_srcdir)/lib/e2p/e2p.h $(top_srcdir)/version.h $(srcdir)/nls-enable.h ++ $(top_srcdir)/lib/e2p/e2p.h $(top_srcdir)/lib/support/nls-enable.h \ ++ $(top_srcdir)/version.h + lsattr.o: $(srcdir)/lsattr.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/et/com_err.h \ +- $(top_srcdir)/lib/e2p/e2p.h $(top_srcdir)/version.h $(srcdir)/nls-enable.h ++ $(top_srcdir)/lib/e2p/e2p.h $(top_srcdir)/lib/support/nls-enable.h \ ++ $(top_srcdir)/version.h + dumpe2fs.o: $(srcdir)/dumpe2fs.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 \ +- $(top_srcdir)/lib/e2p/e2p.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)/version.h \ +- $(srcdir)/nls-enable.h ++ $(top_srcdir)/lib/e2p/e2p.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/support/nls-enable.h $(top_srcdir)/lib/support/plausible.h \ ++ $(top_srcdir)/version.h + badblocks.o: $(srcdir)/badblocks.c $(top_builddir)/lib/config.h \ + $(top_builddir)/lib/dirpaths.h $(top_srcdir)/lib/et/com_err.h \ + $(top_srcdir)/lib/ext2fs/ext2_io.h $(top_srcdir)/lib/ext2fs/ext2_fs.h \ +@@ -685,10 +745,10 @@ + $(top_srcdir)/lib/ext2fs/ext3_extents.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 ++ $(top_srcdir)/lib/support/nls-enable.h + fsck.o: $(srcdir)/fsck.c $(top_builddir)/lib/config.h \ + $(top_builddir)/lib/dirpaths.h $(top_srcdir)/version.h \ +- $(srcdir)/nls-enable.h $(srcdir)/fsck.h ++ $(top_srcdir)/lib/support/nls-enable.h $(srcdir)/fsck.h + util.o: $(srcdir)/util.c $(top_builddir)/lib/config.h \ + $(top_builddir)/lib/dirpaths.h $(top_srcdir)/lib/et/com_err.h \ + $(top_srcdir)/lib/e2p/e2p.h $(top_srcdir)/lib/ext2fs/ext2_fs.h \ +@@ -696,9 +756,9 @@ + $(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 $(srcdir)/util.h ++ $(top_srcdir)/lib/support/nls-enable.h $(srcdir)/util.h + uuidgen.o: $(srcdir)/uuidgen.c $(top_builddir)/lib/config.h \ +- $(top_builddir)/lib/dirpaths.h $(srcdir)/nls-enable.h ++ $(top_builddir)/lib/dirpaths.h $(top_srcdir)/lib/support/nls-enable.h + blkid.o: $(srcdir)/blkid.c $(top_builddir)/lib/config.h \ + $(top_builddir)/lib/dirpaths.h $(top_srcdir)/lib/ext2fs/ext2fs.h \ + $(top_builddir)/lib/ext2fs/ext2_types.h $(top_srcdir)/lib/ext2fs/ext2_fs.h \ +@@ -719,17 +779,13 @@ + ismounted.o: $(srcdir)/ismounted.c $(top_builddir)/lib/config.h \ + $(top_builddir)/lib/dirpaths.h $(srcdir)/fsck.h \ + $(top_srcdir)/lib/et/com_err.h +-profile.o: $(srcdir)/../e2fsck/profile.c $(top_builddir)/lib/config.h \ +- $(top_builddir)/lib/dirpaths.h $(top_srcdir)/lib/et/com_err.h \ +- $(srcdir)/../e2fsck/profile.h prof_err.h + e2undo.o: $(srcdir)/e2undo.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_builddir)/lib/dirpaths.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 ++ $(top_srcdir)/lib/support/nls-enable.h + e2freefrag.o: $(srcdir)/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 \ +@@ -737,3 +793,51 @@ + $(top_srcdir)/lib/ext2fs/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \ + $(top_srcdir)/lib/ext2fs/ext2_ext_attr.h $(top_srcdir)/lib/ext2fs/bitops.h \ + $(srcdir)/e2freefrag.h ++create_inode.o: $(srcdir)/create_inode.c $(top_builddir)/lib/config.h \ ++ $(top_builddir)/lib/dirpaths.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 \ ++ $(top_srcdir)/lib/ext2fs/fiemap.h $(srcdir)/create_inode.h \ ++ $(top_srcdir)/lib/e2p/e2p.h $(top_srcdir)/lib/support/nls-enable.h ++fuse2fs.o: $(srcdir)/fuse2fs.c $(top_builddir)/lib/config.h \ ++ $(top_builddir)/lib/dirpaths.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 ++journal.o: $(srcdir)/../debugfs/journal.c $(top_builddir)/lib/config.h \ ++ $(top_builddir)/lib/dirpaths.h $(top_srcdir)/e2fsck/jfs_user.h \ ++ $(top_srcdir)/e2fsck/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 \ ++ $(top_srcdir)/lib/support/profile.h $(top_builddir)/lib/support/prof_err.h \ ++ $(top_srcdir)/lib/support/quotaio.h $(top_srcdir)/lib/support/dqblk_v2.h \ ++ $(top_srcdir)/lib/support/quotaio_tree.h \ ++ $(top_srcdir)/lib/ext2fs/kernel-jbd.h $(top_srcdir)/lib/ext2fs/jfs_compat.h \ ++ $(top_srcdir)/lib/ext2fs/kernel-list.h ++revoke.o: $(srcdir)/../e2fsck/revoke.c $(srcdir)/../e2fsck/jfs_user.h \ ++ $(srcdir)/../e2fsck/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 \ ++ $(top_srcdir)/lib/support/profile.h $(top_builddir)/lib/support/prof_err.h \ ++ $(top_srcdir)/lib/support/quotaio.h $(top_srcdir)/lib/support/dqblk_v2.h \ ++ $(top_srcdir)/lib/support/quotaio_tree.h \ ++ $(top_srcdir)/lib/ext2fs/kernel-jbd.h $(top_srcdir)/lib/ext2fs/jfs_compat.h \ ++ $(top_srcdir)/lib/ext2fs/kernel-list.h ++recovery.o: $(srcdir)/../e2fsck/recovery.c $(srcdir)/../e2fsck/jfs_user.h \ ++ $(srcdir)/../e2fsck/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 \ ++ $(top_srcdir)/lib/support/profile.h $(top_builddir)/lib/support/prof_err.h \ ++ $(top_srcdir)/lib/support/quotaio.h $(top_srcdir)/lib/support/dqblk_v2.h \ ++ $(top_srcdir)/lib/support/quotaio_tree.h \ ++ $(top_srcdir)/lib/ext2fs/kernel-jbd.h $(top_srcdir)/lib/ext2fs/jfs_compat.h \ ++ $(top_srcdir)/lib/ext2fs/kernel-list.h +--- a/misc/mke2fs.8.in ++++ b/misc/mke2fs.8.in +@@ -18,6 +18,10 @@ + .I block-size + ] + [ ++.B \-d ++.I root-directory ++] ++[ + .B \-D + ] + [ +@@ -109,6 +113,14 @@ + [ + .B \-V + ] ++[ ++.B \-e ++.I errors-behavior ++] ++[ ++.B \-z ++.I undo_file ++] + .I device + [ + .I fs-size +@@ -225,12 +237,35 @@ + man page for more details about bigalloc.) The default cluster size if + bigalloc is enabled is 16 times the block size. + .TP ++.BI \-d " root-directory" ++Copy the contents of the given directory into the root directory of the ++filesystem. ++.TP + .B \-D + Use direct I/O when writing to the disk. This avoids mke2fs dirtying a + 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 +@@ -342,13 +377,13 @@ + .TP + .BI nodiscard + Do not attempt to discard blocks at mkfs time. +-@QUOTA_MAN_COMMENT@.TP +-@QUOTA_MAN_COMMENT@.BI quotatype +-@QUOTA_MAN_COMMENT@Specify which quota type ('usr' or 'grp') is to be +-@QUOTA_MAN_COMMENT@initialized. This option has effect only if the +-@QUOTA_MAN_COMMENT@.B quota +-@QUOTA_MAN_COMMENT@feature is set. Without this extended option, the default +-@QUOTA_MAN_COMMENT@behavior is to initialize both user and group quotas. ++.TP ++.BI quotatype ++Specify which quota type ('usr' or 'grp') is to be ++initialized. This option has effect only if the ++.B quota ++feature is set. Without this extended option, the default ++behavior is to initialize both user and group quotas. + .RE + .TP + .BI \-f " fragment-size" +@@ -619,18 +654,26 @@ + create revision 1 filesystems. + .TP + .B \-S +-Write superblock and group descriptors only. This is useful if all of ++Write superblock and group descriptors only. This is an extreme ++measure to be taken only in the very unlikely case that all of + the superblock and backup superblocks are corrupted, and a last-ditch +-recovery method is desired. It causes ++recovery method is desired by experienced users. It causes + .B mke2fs +-to reinitialize the +-superblock and group descriptors, while not touching the inode table +-and the block and inode bitmaps. The ++to reinitialize the superblock and group descriptors, while not ++touching the inode table and the block and inode bitmaps. The + .B e2fsck + program should be run immediately after this option is used, and there +-is no guarantee that any data will be salvageable. It is critical to +-specify the correct filesystem blocksize when using this option, +-or there is no chance of recovery. ++is no guarantee that any data will be salvageable. Due to the wide ++variety of possible options to ++.BR mke2fs ++that affect the on-disk layout, is critical to specify exactly the same ++the same format options, such as blocksize, fs-type, feature flags, and ++other tunables when using this option, or the filesystem will be further ++corrupted. In some cases, such as filesystems that have been resized, ++or have had features enabled after format time, it is impossible to ++overwrite all of the superblocks corretly, and at least some filesystem ++corruption will occur. It is best to run this on a full copy of the ++filesystem so other options can be tried if this doesn't work. + .\" .TP + .\" .BI \-t " test" + .\" Check the device for bad blocks before creating the file system +@@ -708,6 +751,17 @@ + Print the version number of + .B mke2fs + and exit. ++.TP ++.BI \-z " undo_file" ++Before overwriting a file system block, write the old contents of the block to ++an undo file. This undo file can be used with e2undo(8) to restore the old ++contents of the file system should something go wrong. If the empty string is ++passed as the undo_file argument, the undo file will be written to a file named ++mke2fs-\fIdevice\fR.e2undo in the directory specified via the ++\fIE2FSPROGS_UNDO_DIR\fR environment variable or the \fIundo_dir\fR directive ++in the configuration file. ++ ++WARNING: The undo file cannot be used to recover from a power or system crash. + .SH ENVIRONMENT + .TP + .BI MKE2FS_SYNC +--- a/misc/mke2fs.c ++++ b/misc/mke2fs.c +@@ -16,13 +16,12 @@ + * 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 + #include + #include +-#include + #include + #include + #ifdef __linux__ +@@ -45,25 +44,22 @@ + #include + #endif + #include +-#include +-#include + #include + #include + #include + + #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 "support/nls-enable.h" ++#include "support/plausible.h" ++#include "support/profile.h" ++#include "support/prof_err.h" + #include "../version.h" +-#include "nls-enable.h" +-#include "quota/quotaio.h" ++#include "support/quotaio.h" + #include "mke2fs.h" ++#include "create_inode.h" + + #define STRIDE_LENGTH 8 + +@@ -113,23 +109,29 @@ + 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 char *undo_file; + + 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] " +- "[-jnqvDFKSV] device [blocks-count]\n"), ++ "\t[-t fs-type] [-T usage-type ] [-U UUID] [-e errors_behavior]" ++ "[-z undo_file]\n" ++ "\t[-jnqvDFKSV] device [blocks-count]\n"), + program_name); + exit(1); + } +@@ -193,7 +195,7 @@ + if (linux_version_code == 0) + return 0; + +- return linux_version_code < KERNEL_VERSION(major, minor, rev); ++ return linux_version_code < (int) KERNEL_VERSION(major, minor, rev); + } + #else + static int is_before_linux_ver(unsigned int major, unsigned int minor, +@@ -339,6 +341,25 @@ + 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; +@@ -402,12 +423,14 @@ + ext2fs_bg_flags_set(fs, i, EXT2_BG_INODE_ZEROED); + ext2fs_group_desc_csum_set(fs, i); + } +- retval = ext2fs_zero_blocks2(fs, blk, num, &blk, &num); +- if (retval) { +- fprintf(stderr, _("\nCould not write %d " +- "blocks in inode table starting at %llu: %s\n"), +- num, blk, error_message(retval)); +- exit(1); ++ if (!itable_zeroed) { ++ retval = ext2fs_zero_blocks2(fs, blk, num, &blk, &num); ++ if (retval) { ++ fprintf(stderr, _("\nCould not write %d " ++ "blocks in inode table starting at %llu: %s\n"), ++ num, blk, error_message(retval)); ++ exit(1); ++ } + } + if (sync_kludge) { + if (sync_kludge == 1) +@@ -416,9 +439,14 @@ + sync(); + } + } +- 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) +@@ -599,7 +627,6 @@ + count -= c; + ext2fs_numeric_progress_update(fs, &progress, blk); + } +- ext2fs_zero_blocks2(0, 0, 0, 0, 0); + + ext2fs_numeric_progress_close(fs, &progress, NULL); + write_superblock: +@@ -707,6 +734,23 @@ + } + + /* ++ * 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 +1077,9 @@ + 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| ++ EXT4_FEATURE_INCOMPAT_ENCRYPT, + /* R/O compat */ + EXT2_FEATURE_RO_COMPAT_LARGE_FILE| + EXT4_FEATURE_RO_COMPAT_HUGE_FILE| +@@ -1042,10 +1088,8 @@ + EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER| + EXT4_FEATURE_RO_COMPAT_GDT_CSUM| + EXT4_FEATURE_RO_COMPAT_BIGALLOC| +-#ifdef CONFIG_QUOTA + EXT4_FEATURE_RO_COMPAT_QUOTA| +-#endif +- 0 ++ EXT4_FEATURE_RO_COMPAT_METADATA_CSUM + }; + + +@@ -1174,15 +1218,11 @@ + 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) +@@ -1354,11 +1394,11 @@ + * device's alignment offset, if any, or a negative error. + */ + static int get_device_geometry(const char *file, +- struct ext2_super_block *fs_param, +- int psector_size) ++ struct ext2_super_block *param, ++ unsigned int psector_size) + { + int rc = -1; +- int blocksize; ++ unsigned int blocksize; + blkid_probe pr; + blkid_topology tp; + unsigned long min_io; +@@ -1379,7 +1419,7 @@ + + min_io = blkid_topology_get_minimum_io_size(tp); + opt_io = blkid_topology_get_optimal_io_size(tp); +- blocksize = EXT2_BLOCK_SIZE(fs_param); ++ blocksize = EXT2_BLOCK_SIZE(param); + if ((min_io == 0) && (psector_size > blocksize)) + min_io = psector_size; + if ((opt_io == 0) && min_io) +@@ -1389,9 +1429,9 @@ + + /* setting stripe/stride to blocksize is pointless */ + if (min_io > blocksize) +- fs_param->s_raid_stride = min_io / blocksize; ++ param->s_raid_stride = min_io / blocksize; + if (opt_io > blocksize) +- fs_param->s_raid_stripe_width = opt_io / blocksize; ++ param->s_raid_stripe_width = opt_io / blocksize; + + rc = blkid_topology_get_alignment_offset(tp); + out: +@@ -1512,7 +1552,7 @@ + } + + 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:Vz:")) != EOF) { + switch (c) { + case 'b': + blocksize = parse_num_blocks2(optarg, -1); +@@ -1555,6 +1595,20 @@ + 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 +1765,9 @@ + case 'U': + fs_uuid = optarg; + break; ++ case 'd': ++ root_dir = optarg; ++ break; + case 'v': + verbose = 1; + break; +@@ -1718,6 +1775,9 @@ + /* Print version number and exit */ + show_version_only++; + break; ++ case 'z': ++ undo_file = optarg; ++ break; + default: + usage(); + } +@@ -1896,10 +1956,40 @@ + 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); +@@ -2040,7 +2130,8 @@ + reserved_ratio = 0; + fs_param.s_feature_incompat = EXT3_FEATURE_INCOMPAT_JOURNAL_DEV; + fs_param.s_feature_compat = 0; +- fs_param.s_feature_ro_compat = 0; ++ fs_param.s_feature_ro_compat &= ++ EXT4_FEATURE_RO_COMPAT_METADATA_CSUM; + } + + /* Check the user's mkfs options for 64bit */ +@@ -2088,7 +2179,8 @@ + } + + #ifdef HAVE_BLKID_PROBE_GET_TOPOLOGY +- retval = get_device_geometry(device_name, &fs_param, psector_size); ++ retval = get_device_geometry(device_name, &fs_param, ++ (unsigned int) psector_size); + if (retval < 0) { + fprintf(stderr, + _("warning: Unable to get device geometry for %s\n"), +@@ -2126,6 +2218,14 @@ + blocksize, sys_page_size); + } + ++ /* Metadata checksumming wasn't totally stable before 3.18. */ ++ if (is_before_linux_ver(3, 18, 0) && ++ (fs_param.s_feature_ro_compat & ++ EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) ++ fprintf(stderr, _("Suggestion: Use Linux kernel >= 3.18 for " ++ "improved stability of the metadata and journal " ++ "checksum features.\n")); ++ + /* + * On newer kernels we do have lazy_itable_init support. So pick the + * right default in case ext4 module is not loaded. +@@ -2173,6 +2273,13 @@ + 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)) { +@@ -2198,7 +2305,8 @@ + "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) && +@@ -2257,6 +2365,20 @@ + 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, ++ _("%d byte inodes are too small for inline data; " ++ "specify larger size"), ++ 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; +@@ -2326,7 +2448,8 @@ + 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; +@@ -2374,6 +2497,21 @@ + char *dev_name, *tmp_name; + int free_tdb_dir = 0; + ++ /* (re)open a specific undo file */ ++ if (undo_file && undo_file[0] != 0) { ++ retval = set_undo_io_backing_manager(*io_ptr); ++ if (retval) ++ goto err; ++ *io_ptr = undo_io_manager; ++ retval = set_undo_io_backup_file(undo_file); ++ if (retval) ++ goto err; ++ printf(_("Overwriting existing filesystem; this can be undone " ++ "using the command:\n" ++ " e2undo %s %s\n\n"), undo_file, name); ++ return retval; ++ } ++ + /* + * Configuration via a conf file would be + * nice +@@ -2407,10 +2545,14 @@ + + if ((unlink(tdb_file) < 0) && (errno != ENOENT)) { + retval = errno; ++ com_err(program_name, retval, ++ _("while trying to delete %s"), tdb_file); + goto errout; + } + +- set_undo_io_backing_manager(*io_ptr); ++ retval = set_undo_io_backing_manager(*io_ptr); ++ if (retval) ++ goto errout; + *io_ptr = undo_io_manager; + retval = set_undo_io_backup_file(tdb_file); + if (retval) +@@ -2428,6 +2570,7 @@ + if (free_tdb_dir) + free(tdb_dir); + free(tdb_file); ++err: + com_err(program_name, retval, "%s", + _("while trying to setup undo file\n")); + return retval; +@@ -2534,6 +2677,38 @@ + 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; +@@ -2567,7 +2742,7 @@ + #endif + io_ptr = unix_io_manager; + +- if (should_do_undo(device_name)) { ++ if (undo_file != NULL || should_do_undo(device_name)) { + retval = mke2fs_setup_tdb(device_name, &io_ptr); + if (retval) + exit(1); +@@ -2596,6 +2771,35 @@ + _("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_INCOMPAT_FEATURE(fs->super, ++ EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) && ++ 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) || +@@ -2633,6 +2837,7 @@ + (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; + +@@ -2653,6 +2858,7 @@ + } + } else + uuid_generate(fs->super->s_uuid); ++ ext2fs_init_csum_seed(fs); + + /* + * Initialize the directory index variables +@@ -2729,6 +2935,19 @@ + sizeof(fs->super->s_last_mounted)); + } + ++ /* Set current default encryption algorithms for data and ++ * filename encryption */ ++ if (fs->super->s_feature_incompat & EXT4_FEATURE_INCOMPAT_ENCRYPT) { ++ fs->super->s_encrypt_algos[0] = ++ EXT4_ENCRYPTION_MODE_AES_256_XTS; ++ fs->super->s_encrypt_algos[1] = ++ EXT4_ENCRYPTION_MODE_AES_256_CTS; ++ } ++ ++ 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); + +@@ -2738,6 +2957,7 @@ + if (fs->super->s_feature_incompat & + EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) { + create_journal_dev(fs); ++ printf("\n"); + exit(ext2fs_close_free(&fs) ? 1 : 0); + } + +@@ -2771,16 +2991,20 @@ + } + + if (super_only) { ++ check_plausibility(device_name, CHECK_FS_EXIST, NULL); ++ printf(_("%s may be further corrupted by superblock rewrite\n"), ++ device_name); ++ if (!force) ++ proceed_question(proceed_delay); + fs->super->s_state |= EXT2_ERROR_FS; + fs->flags &= ~(EXT2_FLAG_IB_DIRTY|EXT2_FLAG_BB_DIRTY); +- /* ++ /* + * The command "mke2fs -S" is used to recover + * corrupted file systems, so do not mark any of the + * 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); + } +@@ -2918,6 +3142,20 @@ + 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", ++ _("while populating file system")); ++ exit(1); ++ } else if (!quiet) ++ printf("%s", _("done\n")); ++ } + + if (!quiet) + printf("%s", _("Writing superblocks and " +--- a/misc/mke2fs.conf.5.in ++++ b/misc/mke2fs.conf.5.in +@@ -317,6 +317,25 @@ + 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 +--- a/misc/mke2fs.conf.in ++++ b/misc/mke2fs.conf.in +@@ -11,12 +11,11 @@ + features = has_journal + } + ext4 = { +- features = has_journal,extent,huge_file,flex_bg,uninit_bg,dir_nlink,extra_isize +- auto_64-bit_support = 1 ++ features = has_journal,extent,huge_file,flex_bg,metadata_csum,64bit,dir_nlink,extra_isize + 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 + } +--- a/misc/mk_hugefiles.c ++++ b/misc/mk_hugefiles.c +@@ -45,9 +45,9 @@ + #include "e2p/e2p.h" + #include "ext2fs/ext2fs.h" + #include "util.h" +-#include "profile.h" +-#include "prof_err.h" +-#include "nls-enable.h" ++#include "support/profile.h" ++#include "support/prof_err.h" ++#include "support/nls-enable.h" + #include "mke2fs.h" + + static int uid; +@@ -258,12 +258,7 @@ + + { + errcode_t retval; +- blk64_t lblk, bend = 0; +- __u64 size; +- blk64_t left; +- blk64_t count = 0; + struct ext2_inode inode; +- ext2_extent_handle_t handle; + + retval = ext2fs_new_inode(fs, 0, LINUX_S_IFREG, NULL, ino); + if (retval) +@@ -283,85 +278,20 @@ + + ext2fs_inode_alloc_stats2(fs, *ino, +1, 0); + +- retval = ext2fs_extent_open2(fs, *ino, &inode, &handle); ++ if (EXT2_HAS_INCOMPAT_FEATURE(fs->super, ++ EXT3_FEATURE_INCOMPAT_EXTENTS)) ++ inode.i_flags |= EXT4_EXTENTS_FL; ++ retval = ext2fs_fallocate(fs, ++ EXT2_FALLOCATE_FORCE_INIT | ++ EXT2_FALLOCATE_ZERO_BLOCKS, ++ *ino, &inode, goal, 0, num); + if (retval) + return retval; +- +- lblk = 0; +- left = num ? num : 1; +- while (left) { +- blk64_t pblk, end; +- blk64_t n = left; +- +- retval = ext2fs_find_first_zero_block_bitmap2(fs->block_map, +- goal, ext2fs_blocks_count(fs->super) - 1, &end); +- if (retval) +- goto errout; +- goal = end; +- +- retval = ext2fs_find_first_set_block_bitmap2(fs->block_map, goal, +- ext2fs_blocks_count(fs->super) - 1, &bend); +- if (retval == ENOENT) { +- bend = ext2fs_blocks_count(fs->super); +- if (num == 0) +- left = 0; +- } +- if (!num || bend - goal < left) +- n = bend - goal; +- pblk = goal; +- if (num) +- left -= n; +- goal += n; +- count += n; +- ext2fs_block_alloc_stats_range(fs, pblk, n, +1); +- +- if (zero_hugefile) { +- blk64_t ret_blk; +- retval = ext2fs_zero_blocks2(fs, pblk, n, +- &ret_blk, NULL); +- +- if (retval) +- com_err(program_name, retval, +- _("while zeroing block %llu " +- "for hugefile"), ret_blk); +- } +- +- while (n) { +- blk64_t l = n; +- struct ext2fs_extent newextent; +- +- if (l > EXT_INIT_MAX_LEN) +- l = EXT_INIT_MAX_LEN; +- +- newextent.e_len = l; +- newextent.e_pblk = pblk; +- newextent.e_lblk = lblk; +- newextent.e_flags = 0; +- +- retval = ext2fs_extent_insert(handle, +- EXT2_EXTENT_INSERT_AFTER, &newextent); +- if (retval) +- return retval; +- pblk += l; +- lblk += l; +- n -= l; +- } +- } +- +- retval = ext2fs_read_inode(fs, *ino, &inode); ++ retval = ext2fs_inode_size_set(fs, &inode, num * fs->blocksize); + if (retval) +- goto errout; +- +- retval = ext2fs_iblk_add_blocks(fs, &inode, +- count / EXT2FS_CLUSTER_RATIO(fs)); +- if (retval) +- goto errout; +- size = (__u64) count * fs->blocksize; +- retval = ext2fs_inode_size_set(fs, &inode, size); +- if (retval) +- goto errout; ++ return retval; + +- retval = ext2fs_write_new_inode(fs, *ino, &inode); ++ retval = ext2fs_write_inode(fs, *ino, &inode); + if (retval) + goto errout; + +@@ -379,13 +309,7 @@ + goto retry; + } + +- if (retval) +- goto errout; +- + errout: +- if (handle) +- ext2fs_extent_free(handle); +- + return retval; + } + +@@ -476,6 +400,10 @@ + if (!get_bool_from_profile(fs_types, "make_hugefiles", 0)) + return 0; + ++ if (!EXT2_HAS_INCOMPAT_FEATURE(fs->super, ++ EXT3_FEATURE_INCOMPAT_EXTENTS)) ++ return EXT2_ET_EXTENT_NOT_SUPPORTED; ++ + uid = get_int_from_profile(fs_types, "hugefiles_uid", 0); + gid = get_int_from_profile(fs_types, "hugefiles_gid", 0); + fs->umask = get_int_from_profile(fs_types, "hugefiles_umask", 077); +@@ -529,10 +457,10 @@ + + fs_blocks = ext2fs_free_blocks_count(fs->super); + if (fs_blocks < num_slack + align) +- return ENOMEM; ++ return ENOSPC; + fs_blocks -= num_slack + align; + if (num_blocks && num_blocks > fs_blocks) +- return ENOMEM; ++ return ENOSPC; + if (num_blocks == 0 && num_files == 0) + num_files = 1; + +@@ -568,6 +496,8 @@ + printf(_("with %llu blocks each"), num_blocks); + fputs(": ", stdout); + } ++ if (num_blocks == 0) ++ num_blocks = ext2fs_blocks_count(fs->super) - goal; + for (i=0; i < num_files; i++) { + ext2_ino_t ino; + +--- a/misc/mklost+found.c ++++ b/misc/mklost+found.c +@@ -25,7 +25,7 @@ + + #include "ext2fs/ext2_fs.h" + #include "../version.h" +-#include "nls-enable.h" ++#include "support/nls-enable.h" + + #define LPF "lost+found" + +--- a/misc/nls-enable.h ++++ /dev/null +@@ -1,21 +0,0 @@ +-#ifdef ENABLE_NLS +-#include +-#include +-#define _(a) (gettext (a)) +-#ifdef gettext_noop +-#define N_(a) gettext_noop (a) +-#else +-#define N_(a) (a) +-#endif +-#define P_(singular, plural, n) (ngettext (singular, plural, n)) +-#ifndef NLS_CAT_NAME +-#define NLS_CAT_NAME "e2fsprogs" +-#endif +-#ifndef LOCALEDIR +-#define LOCALEDIR "/usr/share/locale" +-#endif +-#else +-#define _(a) (a) +-#define N_(a) a +-#define P_(singular, plural, n) ((n) == 1 ? (singular) : (plural)) +-#endif +--- a/misc/partinfo.c ++++ b/misc/partinfo.c +@@ -18,7 +18,7 @@ + #include + #include + #include +-#include "nls-enable.h" ++#include "support/nls-enable.h" + + #if defined(__linux__) && defined(_IO) && !defined(BLKGETSIZE) + #define BLKGETSIZE _IO(0x12,96) /* return device size */ +--- a/misc/tune2fs.8.in ++++ b/misc/tune2fs.8.in +@@ -88,6 +88,10 @@ + .B \-U + .I UUID + ] ++[ ++.B \-z ++.I undo_file ++] + device + .SH DESCRIPTION + .BI tune2fs +@@ -333,7 +337,7 @@ + .I journal-size + megabytes. The size of the journal must be at least 1024 filesystem blocks + (i.e., 1MB if using 1k blocks, 4MB if using 4k blocks, etc.) +-and may be no more than 102,400 filesystem blocks. ++and may be no more than 10,240,000 filesystem blocks. + There must be enough free space in the filesystem to create a journal of + that size. + .TP +@@ -563,9 +567,12 @@ + .TP + .B mmp + Enable or disable multiple mount protection (MMP) feature. +-@QUOTA_MAN_COMMENT@.TP +-@QUOTA_MAN_COMMENT@.B quota +-@QUOTA_MAN_COMMENT@Enable internal file system quota inodes. ++.TP ++.B quota ++Enable internal file system quota inodes. ++.TP ++.B read-only ++Force the kernel to mount the file system read-only. + .TP + .B sparse_super + Limit the number of backup superblocks to save space on large filesystems. +@@ -684,6 +691,16 @@ + .IR /dev/urandom , + .B tune2fs + will automatically use a time-based UUID instead of a randomly-generated UUID. ++.TP ++.BI \-z " undo_file" ++Before overwriting a file system block, write the old contents of the block to ++an undo file. This undo file can be used with e2undo(8) to restore the old ++contents of the file system should something go wrong. If the empty string is ++passed as the undo_file argument, the undo file will be written to a file named ++tune2fs-\fIdevice\fR.e2undo in the directory specified via the ++\fIE2FSPROGS_UNDO_DIR\fR environment variable. ++ ++WARNING: The undo file cannot be used to recover from a power or system crash. + .SH BUGS + We haven't found any bugs yet. That doesn't mean there aren't any... + .SH AUTHOR +--- a/misc/tune2fs.c ++++ b/misc/tune2fs.c +@@ -54,16 +54,17 @@ + + #include "ext2fs/ext2_fs.h" + #include "ext2fs/ext2fs.h" ++#include "ext2fs/kernel-jbd.h" + #include "et/com_err.h" ++#include "support/plausible.h" ++#include "support/quotaio.h" + #include "uuid/uuid.h" + #include "e2p/e2p.h" +-#include "jfs_user.h" + #include "util.h" + #include "blkid/blkid.h" +-#include "quota/quotaio.h" + + #include "../version.h" +-#include "nls-enable.h" ++#include "support/nls-enable.h" + + #define QOPT_ENABLE (1) + #define QOPT_DISABLE (-1) +@@ -95,6 +96,10 @@ + static unsigned long new_inode_size; + static char *ext_mount_opts; + static int usrquota, grpquota; ++static int rewrite_checksums; ++static int feature_64bit; ++static int fsck_requested; ++static char *undo_file; + + int journal_size, journal_flags; + char *journal_device; +@@ -110,6 +115,8 @@ + + + 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); +@@ -121,16 +128,14 @@ + _("Usage: %s [-c max_mounts_count] [-e errors_behavior] " + "[-g group]\n" + "\t[-i interval[d|m|w]] [-j] [-J journal_options] [-l]\n" +- "\t[-m reserved_blocks_percent] " +- "[-o [^]mount_options[,...]] [-p mmp_update_interval]\n" +- "\t[-r reserved_blocks_count] [-u user] [-C mount_count] " +- "[-L volume_label]\n" +- "\t[-M last_mounted_dir] [-O [^]feature[,...]]\n" +-#ifdef CONFIG_QUOTA +- "\t[-Q quota_options]\n" +-#endif ++ "\t[-m reserved_blocks_percent] [-o [^]mount_options[,...]]\n" ++ "\t[-p mmp_update_interval] [-r reserved_blocks_count] " ++ "[-u user]\n" ++ "\t[-C mount_count] [-L volume_label] [-M last_mounted_dir]\n" ++ "\t[-O [^]feature[,...]] [-Q quota_options]\n" + "\t[-E extended-option[,...]] [-T last_check_time] " +- "[-U UUID]\n\t[ -I new_inode_size ] device\n"), program_name); ++ "[-U UUID]\n\t[-I new_inode_size] [-z undo_file] device\n"), ++ program_name); + exit(1); + } + +@@ -142,17 +147,19 @@ + EXT2_FEATURE_INCOMPAT_FILETYPE | + EXT3_FEATURE_INCOMPAT_EXTENTS | + EXT4_FEATURE_INCOMPAT_FLEX_BG | +- EXT4_FEATURE_INCOMPAT_MMP, ++ EXT4_FEATURE_INCOMPAT_MMP | ++ EXT4_FEATURE_INCOMPAT_64BIT | ++ EXT4_FEATURE_INCOMPAT_ENCRYPT, + /* R/O compat */ + EXT2_FEATURE_RO_COMPAT_LARGE_FILE | + 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 ++ EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER | + EXT4_FEATURE_RO_COMPAT_QUOTA | +-#endif +- EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER ++ EXT4_FEATURE_RO_COMPAT_METADATA_CSUM | ++ EXT4_FEATURE_RO_COMPAT_READONLY + }; + + static __u32 clear_ok_features[3] = { +@@ -163,16 +170,17 @@ + /* Incompat */ + EXT2_FEATURE_INCOMPAT_FILETYPE | + EXT4_FEATURE_INCOMPAT_FLEX_BG | +- EXT4_FEATURE_INCOMPAT_MMP, ++ EXT4_FEATURE_INCOMPAT_MMP | ++ EXT4_FEATURE_INCOMPAT_64BIT, + /* R/O compat */ + EXT2_FEATURE_RO_COMPAT_LARGE_FILE | + EXT4_FEATURE_RO_COMPAT_HUGE_FILE| + EXT4_FEATURE_RO_COMPAT_DIR_NLINK| + EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE| +-#ifdef CONFIG_QUOTA ++ EXT4_FEATURE_RO_COMPAT_GDT_CSUM | + EXT4_FEATURE_RO_COMPAT_QUOTA | +-#endif +- EXT4_FEATURE_RO_COMPAT_GDT_CSUM ++ EXT4_FEATURE_RO_COMPAT_METADATA_CSUM | ++ EXT4_FEATURE_RO_COMPAT_READONLY + }; + + /** +@@ -181,7 +189,6 @@ + static int get_journal_sb(ext2_filsys jfs, char buf[SUPERBLOCK_SIZE]) + { + int retval; +- int start; + journal_superblock_t *jsb; + + if (!(jfs->super->s_feature_incompat & +@@ -226,7 +233,7 @@ + { + char *journal_path; + ext2_filsys jfs; +- char buf[SUPERBLOCK_SIZE]; ++ char buf[SUPERBLOCK_SIZE] __attribute__ ((aligned(8))); + journal_superblock_t *jsb; + int i, nr_users; + errcode_t retval; +@@ -374,6 +381,7 @@ + return retval; + } + fs->super->s_journal_inum = 0; ++ memset(fs->super->s_jnl_blocks, 0, sizeof(fs->super->s_jnl_blocks)); + ext2fs_mark_super_dirty(fs); + + return 0; +@@ -406,29 +414,555 @@ + return 1; + } + ++static void request_dir_fsck_afterwards(ext2_filsys fs) ++{ ++ static int requested; ++ ++ if (requested++) ++ return; ++ fsck_requested++; ++ 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; + + if (requested++) + return; ++ fsck_requested++; + fs->super->s_state &= ~EXT2_VALID_FS; + printf("\n%s\n", _(please_fsck)); + if (mount_flags & EXT2_MF_READONLY) + printf("%s", _("(and reboot afterwards!)\n")); + } + ++static void convert_64bit(ext2_filsys fs, int direction) ++{ ++ if (!direction) ++ return; ++ ++ /* ++ * Is resize2fs going to demand a fsck run? Might as well tell the ++ * user now. ++ */ ++ if (!fsck_requested && ++ ((fs->super->s_state & EXT2_ERROR_FS) || ++ !(fs->super->s_state & EXT2_VALID_FS) || ++ fs->super->s_lastcheck < fs->super->s_mtime)) ++ request_fsck_afterwards(fs); ++ if (fsck_requested) ++ fprintf(stderr, _("After running e2fsck, please run `resize2fs %s %s"), ++ direction > 0 ? "-b" : "-s", fs->device_name); ++ else ++ fprintf(stderr, _("Please run `resize2fs %s %s"), ++ direction > 0 ? "-b" : "-s", fs->device_name); ++ ++ if (undo_file) ++ fprintf(stderr, _(" -z \"%s\""), undo_file); ++ if (direction > 0) ++ fprintf(stderr, _("' to enable 64-bit mode.\n")); ++ else ++ fprintf(stderr, _("' to disable 64-bit mode.\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; ++ errcode_t errcode; ++ struct ext2_extent_info info; ++ ++ if (!(inode->i_flags & EXT4_EXTENTS_FL) || ++ !EXT2_HAS_RO_COMPAT_FEATURE(fs->super, ++ EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) ++ return 0; ++ ++ errcode = ext2fs_extent_open(fs, ino, &handle); ++ if (errcode) ++ return errcode; ++ ++ errcode = ext2fs_extent_get(handle, EXT2_EXTENT_ROOT, &extent); ++ if (errcode) ++ goto out; ++ ++ do { ++ errcode = ext2fs_extent_get_info(handle, &info); ++ if (errcode) ++ break; ++ ++ /* ++ * If this is the first extent in an extent block that we ++ * haven't visited, rewrite the extent to force the ETB ++ * checksum to be rewritten. ++ */ ++ if (info.curr_entry == 1 && info.curr_level != 0 && ++ !(extent.e_flags & EXT2_EXTENT_FLAGS_SECOND_VISIT)) { ++ errcode = ext2fs_extent_replace(handle, 0, &extent); ++ if (errcode) ++ break; ++ } ++ ++ /* Skip to the end of a block of leaf nodes */ ++ if (extent.e_flags & EXT2_EXTENT_FLAGS_LEAF) { ++ errcode = ext2fs_extent_get(handle, ++ EXT2_EXTENT_LAST_SIB, ++ &extent); ++ if (errcode) ++ break; ++ } ++ ++ errcode = ext2fs_extent_get(handle, EXT2_EXTENT_NEXT, &extent); ++ } while (errcode == 0); ++ ++out: ++ /* Ok if we run off the end */ ++ if (errcode == EXT2_ET_EXTENT_NO_NEXT) ++ errcode = 0; ++ ext2fs_extent_free(handle); ++ 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 = NULL; ++ 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 errcode_t 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; ++ ++ /* 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); ++ fs->super->s_feature_ro_compat &= ~csum_feature_flag; ++ if (retval) { ++ com_err("disable_uninit_bg", retval, ++ "while reading bitmaps"); ++ request_fsck_afterwards(fs); ++ return retval; ++ } ++ ext2fs_mark_ib_dirty(fs); ++ ext2fs_mark_bb_dirty(fs); ++ ++ /* 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); ++ return retval; ++ } ++ } ++ ++ /* 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); ++ ++ return 0; ++} ++ + /* + * 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; ++ errcode_t err; + + #define FEATURE_ON(type, mask) (!(old_features[(type)] & (mask)) && \ + ((&sb->s_feature_compat)[(type)] & (mask))) +@@ -606,33 +1140,135 @@ + } + + 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); ++ EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) { ++ if (check_fsck_needed(fs)) ++ exit(1); ++ if (mount_flags & EXT2_MF_MOUNTED) { ++ fputs(_("Cannot enable metadata_csum on a mounted " ++ "filesystem!\n"), stderr); ++ exit(1); + } +- fs->flags &= ~EXT2_FLAG_SUPER_ONLY; ++ 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. " ++ "Re-run with -O extent 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. " ++ "Run resize2fs -b to rectify.\n")); ++ 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_METADATA_CSUM)) { ++ __u32 test_features[3]; ++ ++ if (check_fsck_needed(fs)) ++ exit(1); ++ if (mount_flags & EXT2_MF_MOUNTED) { ++ fputs(_("Cannot disable metadata_csum on a mounted " ++ "filesystem!\n"), stderr); ++ exit(1); ++ } ++ rewrite_checksums = 1; ++ ++ /* Enable uninit_bg unless the user expressly turned it off */ ++ memcpy(test_features, old_features, sizeof(test_features)); ++ test_features[E2P_FEATURE_RO_INCOMPAT] |= ++ EXT4_FEATURE_RO_COMPAT_GDT_CSUM; ++ e2p_edit_feature2(features, test_features, ok_features, ++ clear_ok_features, NULL, NULL); ++ if (test_features[E2P_FEATURE_RO_INCOMPAT] & ++ EXT4_FEATURE_RO_COMPAT_GDT_CSUM) ++ fs->super->s_feature_ro_compat |= ++ EXT4_FEATURE_RO_COMPAT_GDT_CSUM; ++ ++ /* ++ * 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)) { ++ err = disable_uninit_bg(fs, ++ EXT4_FEATURE_RO_COMPAT_METADATA_CSUM); ++ if (err) ++ return 1; ++ } 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)) { +- 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; ++ err = disable_uninit_bg(fs, ++ EXT4_FEATURE_RO_COMPAT_GDT_CSUM); ++ if (err) ++ return 1; ++ } ++ ++ /* ++ * We don't actually toggle 64bit; resize2fs does that. But this ++ * must come after the metadata_csum feature_on so that it won't ++ * complain about the lack of 64bit. ++ */ ++ if (FEATURE_ON(E2P_FEATURE_INCOMPAT, ++ EXT4_FEATURE_INCOMPAT_64BIT)) { ++ if (mount_flags & EXT2_MF_MOUNTED) { ++ fprintf(stderr, _("Cannot enable 64-bit mode " ++ "while mounted!\n")); ++ exit(1); + } +- fs->flags &= ~EXT2_FLAG_SUPER_ONLY; ++ sb->s_feature_incompat &= ~EXT4_FEATURE_INCOMPAT_64BIT; ++ feature_64bit = 1; ++ } ++ if (FEATURE_OFF(E2P_FEATURE_INCOMPAT, ++ EXT4_FEATURE_INCOMPAT_64BIT)) { ++ if (mount_flags & EXT2_MF_MOUNTED) { ++ fprintf(stderr, _("Cannot disable 64-bit mode " ++ "while mounted!\n")); ++ exit(1); ++ } ++ sb->s_feature_incompat |= EXT4_FEATURE_INCOMPAT_64BIT; ++ feature_64bit = -1; + } + + if (FEATURE_ON(E2P_FEATURE_RO_INCOMPAT, +@@ -665,6 +1301,13 @@ + grpquota = QOPT_DISABLE; + } + ++ if (FEATURE_ON(E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_ENCRYPT)) { ++ fs->super->s_encrypt_algos[0] = ++ EXT4_ENCRYPTION_MODE_AES_256_XTS; ++ fs->super->s_encrypt_algos[1] = ++ EXT4_ENCRYPTION_MODE_AES_256_CTS; ++ } ++ + if (sb->s_rev_level == EXT2_GOOD_OLD_REV && + (sb->s_feature_compat || sb->s_feature_ro_compat || + sb->s_feature_incompat)) +@@ -789,8 +1432,7 @@ + quota_compute_usage(qctx); + + if (usrquota == QOPT_ENABLE && !fs->super->s_usr_quota_inum) { +- if ((qf_ino = quota_file_exists(fs, USRQUOTA, +- QFMT_VFS_V1)) > 0) ++ if ((qf_ino = quota_file_exists(fs, USRQUOTA)) > 0) + quota_update_limits(qctx, qf_ino, USRQUOTA); + quota_write_inode(qctx, USRQUOTA); + } else if (usrquota == QOPT_DISABLE) { +@@ -798,8 +1440,7 @@ + } + + if (grpquota == QOPT_ENABLE && !fs->super->s_grp_quota_inum) { +- if ((qf_ino = quota_file_exists(fs, GRPQUOTA, +- QFMT_VFS_V1)) > 0) ++ if ((qf_ino = quota_file_exists(fs, GRPQUOTA)) > 0) + quota_update_limits(qctx, qf_ino, GRPQUOTA); + quota_write_inode(qctx, GRPQUOTA); + } else if (grpquota == QOPT_DISABLE) { +@@ -820,7 +1461,6 @@ + return; + } + +-#ifdef CONFIG_QUOTA + static void parse_quota_opts(const char *opts) + { + char *buf, *token, *next, *p; +@@ -863,7 +1503,6 @@ + } + free(buf); + } +-#endif + + static void parse_e2label_options(int argc, char ** argv) + { +@@ -925,13 +1564,9 @@ + char *tmp; + struct group *gr; + struct passwd *pw; +- char optstring[100] = "c:e:fg:i:jlm:o:r:s:u:C:E:I:J:L:M:O:T:U:"; ++ char optstring[100] = "c:e:fg:i:jlm:o:r:s:u:C:E:I:J:L:M:O:T:U:z:Q:"; + +-#ifdef CONFIG_QUOTA +- strcat(optstring, "Q:"); +-#endif + open_flag = 0; +- + printf("tune2fs %s (%s)\n", E2FSPROGS_VERSION, E2FSPROGS_DATE); + while ((c = getopt(argc, argv, optstring)) != EOF) + switch (c) { +@@ -1087,13 +1722,11 @@ + features_cmd = optarg; + open_flag = EXT2_FLAG_RW; + break; +-#ifdef CONFIG_QUOTA + case 'Q': + Q_flag = 1; + parse_quota_opts(optarg); + open_flag = EXT2_FLAG_RW; + break; +-#endif + case 'r': + reserved_blocks = strtoul(optarg, &tmp, 0); + if (*tmp) { +@@ -1159,6 +1792,9 @@ + open_flag = EXT2_FLAG_RW; + I_flag = 1; + break; ++ case 'z': ++ undo_file = optarg; ++ break; + default: + usage(); + } +@@ -1700,6 +2336,8 @@ + + /* Update the meta data */ + fs->inode_blocks_per_group = new_ino_blks_per_grp; ++ ext2fs_free_inode_cache(fs->icache); ++ fs->icache = 0; + fs->super->s_inode_size = new_ino_size; + + err_out: +@@ -1874,27 +2512,29 @@ + { + errcode_t retval = 0; + const char *tdb_dir; +- char *tdb_file; ++ char *tdb_file = NULL; + char *dev_name, *tmp_name; + +-#if 0 /* FIXME!! */ ++ /* (re)open a specific undo file */ ++ if (undo_file && undo_file[0] != 0) { ++ retval = set_undo_io_backing_manager(*io_ptr); ++ if (retval) ++ goto err; ++ *io_ptr = undo_io_manager; ++ retval = set_undo_io_backup_file(undo_file); ++ if (retval) ++ goto err; ++ printf(_("Overwriting existing filesystem; this can be undone " ++ "using the command:\n" ++ " e2undo %s %s\n\n"), ++ undo_file, name); ++ return retval; ++ } ++ + /* + * Configuration via a conf file would be + * nice + */ +- profile_get_string(profile, "scratch_files", +- "directory", 0, 0, +- &tdb_dir); +-#endif +- tmp_name = strdup(name); +- if (!tmp_name) { +- alloc_fn_fail: +- com_err(program_name, ENOMEM, "%s", +- _("Couldn't allocate memory for tdb filename\n")); +- return ENOMEM; +- } +- dev_name = basename(tmp_name); +- + tdb_dir = getenv("E2FSPROGS_UNDO_DIR"); + if (!tdb_dir) + tdb_dir = "/var/lib/e2fsprogs"; +@@ -1903,31 +2543,47 @@ + access(tdb_dir, W_OK)) + return 0; + ++ tmp_name = strdup(name); ++ if (!tmp_name) ++ goto errout; ++ dev_name = basename(tmp_name); + tdb_file = malloc(strlen(tdb_dir) + 9 + strlen(dev_name) + 7 + 1); +- if (!tdb_file) +- goto alloc_fn_fail; ++ if (!tdb_file) { ++ free(tmp_name); ++ goto errout; ++ } + sprintf(tdb_file, "%s/tune2fs-%s.e2undo", tdb_dir, dev_name); ++ free(tmp_name); + + if ((unlink(tdb_file) < 0) && (errno != ENOENT)) { + retval = errno; + com_err(program_name, retval, + _("while trying to delete %s"), tdb_file); +- free(tdb_file); +- return retval; ++ goto errout; + } + +- set_undo_io_backing_manager(*io_ptr); ++ retval = set_undo_io_backing_manager(*io_ptr); ++ if (retval) ++ goto errout; + *io_ptr = undo_io_manager; +- set_undo_io_backup_file(tdb_file); +- printf(_("To undo the tune2fs operation please run " +- "the command\n e2undo %s %s\n\n"), ++ retval = set_undo_io_backup_file(tdb_file); ++ if (retval) ++ goto errout; ++ printf(_("Overwriting existing filesystem; this can be undone " ++ "using the command:\n" ++ " e2undo %s %s\n\n"), + tdb_file, name); ++ + free(tdb_file); +- free(tmp_name); ++ return 0; ++errout: ++ free(tdb_file); ++err: ++ com_err("tune2fs", retval, "while trying to setup undo file\n"); + return retval; + } + +-int ++static int + fs_update_journal_user(struct ext2_super_block *sb, __u8 old_uuid[UUID_SIZE]) + { + int retval, nr_users, start; +@@ -1936,7 +2592,7 @@ + __u8 *j_uuid; + char *journal_path; + char uuid[UUID_STR_SIZE]; +- char buf[SUPERBLOCK_SIZE]; ++ char buf[SUPERBLOCK_SIZE] __attribute__ ((aligned(8))); + + if (!(sb->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL) || + uuid_is_null(sb->s_journal_uuid)) +@@ -1992,13 +2648,18 @@ + return 0; + } + ++#ifndef BUILD_AS_LIB + int main(int argc, char **argv) ++#else ++int tune2fs_main(int argc, char **argv) ++#endif /* BUILD_AS_LIB */ + { + errcode_t retval; + ext2_filsys fs; + struct ext2_super_block *sb; + io_manager io_ptr, io_ptr_orig = NULL; + int rc = 0; ++ char default_undo_file[1] = { 0 }; + + #ifdef ENABLE_NLS + setlocale(LC_MESSAGES, ""); +@@ -2032,7 +2693,7 @@ + if ((open_flag & EXT2_FLAG_RW) == 0 || f_flag) + open_flag |= EXT2_FLAG_SKIP_MMP; + +- open_flag |= EXT2_FLAG_64BITS; ++ open_flag |= EXT2_FLAG_64BITS | EXT2_FLAG_JOURNAL_DEV_OK; + + /* keep the filesystem struct around to dump MMP data */ + open_flag |= EXT2_FLAG_NOFREE_ON_ERROR; +@@ -2055,6 +2716,8 @@ + fprintf(stderr, + _("MMP block magic is bad. Try to fix it by " + "running:\n'e2fsck -f %s'\n"), device_name); ++ else if (retval == EXT2_ET_BAD_MAGIC) ++ check_plausibility(device_name, CHECK_FS_EXIST, NULL); + else if (retval != EXT2_ET_MMP_FAILED) + fprintf(stderr, "%s", + _("Couldn't find valid filesystem superblock.\n")); +@@ -2062,9 +2725,15 @@ + ext2fs_free(fs); + exit(1); + } ++ if (EXT2_HAS_INCOMPAT_FEATURE(fs->super, ++ EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)) { ++ fprintf(stderr, "%s", _("Cannot modify a journal device.\n")); ++ ext2fs_free(fs); ++ exit(1); ++ } + fs->default_bitmap_type = EXT2FS_BMAP64_RBTREE; + +- if (I_flag && !io_ptr_orig) { ++ if (I_flag) { + /* + * Check the inode size is right so we can issue an + * error message and bail before setting up the tdb +@@ -2088,11 +2757,15 @@ + rc = 1; + goto closefs; + } +- + /* + * If inode resize is requested use the + * Undo I/O manager + */ ++ undo_file = default_undo_file; ++ } ++ ++ /* Set up an undo file */ ++ if (undo_file && io_ptr_orig == NULL) { + io_ptr_orig = io_ptr; + retval = tune2fs_setup_tdb(device_name, &io_ptr); + if (retval) { +@@ -2279,11 +2952,10 @@ + if (U_flag) { + int set_csum = 0; + dgrp_t i; +- char buf[SUPERBLOCK_SIZE]; ++ char buf[SUPERBLOCK_SIZE] __attribute__ ((aligned(8))); + __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. +@@ -2323,6 +2995,7 @@ + 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); +@@ -2352,7 +3025,11 @@ + } + + ext2fs_mark_super_dirty(fs); ++ if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super, ++ EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) ++ rewrite_checksums = 1; + } ++ + if (I_flag) { + if (mount_flags & EXT2_MF_MOUNTED) { + fputs(_("The inode size may only be " +@@ -2374,10 +3051,16 @@ + * We want to update group descriptor also + * with the new free inode count + */ ++ if (rewrite_checksums) ++ fs->flags |= EXT2_FLAG_IGNORE_CSUM_ERRORS; + fs->flags &= ~EXT2_FLAG_SUPER_ONLY; +- if (resize_inode(fs, new_inode_size) == 0) { ++ retval = resize_inode(fs, new_inode_size); ++ if (rewrite_checksums) ++ fs->flags &= ~EXT2_FLAG_IGNORE_CSUM_ERRORS; ++ if (retval == 0) { + printf(_("Setting inode size %lu\n"), + new_inode_size); ++ rewrite_checksums = 1; + } else { + printf("%s", _("Failed to change inode size\n")); + rc = 1; +@@ -2385,6 +3068,9 @@ + } + } + ++ if (rewrite_checksums) ++ rewrite_metadata_checksums(fs); ++ + if (l_flag) + list_super(sb); + if (stride_set) { +@@ -2412,8 +3098,11 @@ + closefs: + if (rc) { + ext2fs_mmp_stop(fs); ++#ifndef BUILD_AS_LIB + exit(1); ++#endif + } + ++ convert_64bit(fs, feature_64bit); + return (ext2fs_close_free(&fs) ? 1 : 0); + } +--- /dev/null ++++ b/misc/tune2fs.h +@@ -0,0 +1,13 @@ ++/* ++ * tune2fs.h - Change the file system parameters on an ext2 file system ++ * ++ * %Begin-Header% ++ * This file may be redistributed under the terms of the GNU Public ++ * License. ++ * %End-Header% ++ */ ++ ++/* Takes exactly the same args as the tune2fs exectuable. ++ * Is the entrypoint for libtune2fs. ++ */ ++int tune2fs_main(int argc, char **argv); +--- a/misc/util.c ++++ b/misc/util.c +@@ -9,8 +9,12 @@ + * %End-Header% + */ + ++#ifndef _LARGEFILE_SOURCE + #define _LARGEFILE_SOURCE ++#endif ++#ifndef _LARGEFILE64_SOURCE + #define _LARGEFILE64_SOURCE ++#endif + + #include "config.h" + #include +@@ -37,7 +41,7 @@ + #include "e2p/e2p.h" + #include "ext2fs/ext2_fs.h" + #include "ext2fs/ext2fs.h" +-#include "nls-enable.h" ++#include "support/nls-enable.h" + #include "blkid/blkid.h" + #include "util.h" + +@@ -75,7 +79,7 @@ + + static jmp_buf alarm_env; + +-static void alarm_signal(int signal) ++static void alarm_signal(int signal EXT2FS_ATTR((unused))) + { + longjmp(alarm_env, 1); + } +@@ -108,203 +112,6 @@ + signal(SIGALRM, SIG_IGN); + } + +-static void print_ext2_info(const char *device) +- +-{ +- struct ext2_super_block *sb; +- ext2_filsys fs; +- errcode_t retval; +- time_t tm; +- char buf[80]; +- +- retval = ext2fs_open2(device, 0, EXT2_FLAG_64BITS, 0, 0, +- unix_io_manager, &fs); +- if (retval) +- return; +- sb = fs->super; +- +- if (sb->s_mtime) { +- tm = sb->s_mtime; +- if (sb->s_last_mounted[0]) { +- memset(buf, 0, sizeof(buf)); +- strncpy(buf, sb->s_last_mounted, +- sizeof(sb->s_last_mounted)); +- printf(_("\tlast mounted on %s on %s"), buf, +- ctime(&tm)); +- } else +- printf(_("\tlast mounted on %s"), ctime(&tm)); +- } else if (sb->s_mkfs_time) { +- tm = sb->s_mkfs_time; +- printf(_("\tcreated on %s"), ctime(&tm)); +- } else if (sb->s_wtime) { +- tm = sb->s_wtime; +- printf(_("\tlast modified on %s"), ctime(&tm)); +- } +- ext2fs_close_free(&fs); +-} +- +-/* +- * return 1 if there is no partition table, 0 if a partition table is +- * detected, and -1 on an error. +- */ +-static int check_partition_table(const char *device) +-{ +-#ifdef HAVE_BLKID_PROBE_ENABLE_PARTITIONS +- blkid_probe pr; +- const char *value; +- int ret; +- +- pr = blkid_new_probe_from_filename(device); +- if (!pr) +- return -1; +- +- ret = blkid_probe_enable_partitions(pr, 1); +- if (ret < 0) +- goto errout; +- +- ret = blkid_probe_enable_superblocks(pr, 0); +- if (ret < 0) +- goto errout; +- +- ret = blkid_do_fullprobe(pr); +- if (ret < 0) +- goto errout; +- +- ret = blkid_probe_lookup_value(pr, "PTTYPE", &value, NULL); +- if (ret == 0) +- fprintf(stderr, _("Found a %s partition table in %s\n"), +- value, device); +- else +- ret = 1; +- +-errout: +- blkid_free_probe(pr); +- return ret; +-#else +- return -1; +-#endif +-} +- +-/* +- * return 1 if the device looks plausible, creating the file if necessary +- */ +-int check_plausibility(const char *device, int flags, int *ret_is_dev) +-{ +- int fd, ret, is_dev = 0; +- ext2fs_struct_stat s; +- int fl = O_RDONLY; +- blkid_cache cache = NULL; +- char *fs_type = NULL; +- char *fs_label = NULL; +- +- fd = ext2fs_open_file(device, fl, 0666); +- if ((fd < 0) && (errno == ENOENT) && (flags & NO_SIZE)) { +- fprintf(stderr, _("The file %s does not exist and no " +- "size was specified.\n"), device); +- exit(1); +- } +- if ((fd < 0) && (errno == ENOENT) && (flags & CREATE_FILE)) { +- fl |= O_CREAT; +- fd = ext2fs_open_file(device, fl, 0666); +- if (fd >= 0 && (flags & VERBOSE_CREATE)) +- printf(_("Creating regular file %s\n"), device); +- } +- if (fd < 0) { +- fprintf(stderr, _("Could not open %s: %s\n"), +- device, error_message(errno)); +- if (errno == ENOENT) +- fputs(_("\nThe device apparently does not exist; " +- "did you specify it correctly?\n"), stderr); +- exit(1); +- } +- +- if (ext2fs_fstat(fd, &s) < 0) { +- perror("stat"); +- exit(1); +- } +- close(fd); +- +- if (S_ISBLK(s.st_mode)) +- is_dev = 1; +-#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) +- /* On FreeBSD, all disk devices are character specials */ +- if (S_ISCHR(s.st_mode)) +- is_dev = 1; +-#endif +- if (ret_is_dev) +- *ret_is_dev = is_dev; +- +- if ((flags & CHECK_BLOCK_DEV) && !is_dev) { +- printf(_("%s is not a block special device.\n"), device); +- return 0; +- } +- +- /* +- * Note: we use the older-style blkid API's here because we +- * want as much functionality to be available when using the +- * internal blkid library, when e2fsprogs is compiled for +- * non-Linux systems that will probably not have the libraries +- * from util-linux available. We only use the newer +- * blkid-probe interfaces to access functionality not +- * available in the original blkid library. +- */ +- if ((flags & CHECK_FS_EXIST) && blkid_get_cache(&cache, NULL) >= 0) { +- fs_type = blkid_get_tag_value(cache, "TYPE", device); +- if (fs_type) +- fs_label = blkid_get_tag_value(cache, "LABEL", device); +- blkid_put_cache(cache); +- } +- +- if (fs_type) { +- if (fs_label) +- printf(_("%s contains a %s file system " +- "labelled '%s'\n"), device, fs_type, fs_label); +- else +- printf(_("%s contains a %s file system\n"), device, +- fs_type); +- if (strncmp(fs_type, "ext", 3) == 0) +- print_ext2_info(device); +- free(fs_type); +- free(fs_label); +- return 0; +- } +- +- ret = check_partition_table(device); +- if (ret >= 0) +- return ret; +- +-#ifdef HAVE_LINUX_MAJOR_H +-#ifndef MAJOR +-#define MAJOR(dev) ((dev)>>8) +-#define MINOR(dev) ((dev) & 0xff) +-#endif +-#ifndef SCSI_BLK_MAJOR +-#ifdef SCSI_DISK0_MAJOR +-#ifdef SCSI_DISK8_MAJOR +-#define SCSI_DISK_MAJOR(M) ((M) == SCSI_DISK0_MAJOR || \ +- ((M) >= SCSI_DISK1_MAJOR && (M) <= SCSI_DISK7_MAJOR) || \ +- ((M) >= SCSI_DISK8_MAJOR && (M) <= SCSI_DISK15_MAJOR)) +-#else +-#define SCSI_DISK_MAJOR(M) ((M) == SCSI_DISK0_MAJOR || \ +- ((M) >= SCSI_DISK1_MAJOR && (M) <= SCSI_DISK7_MAJOR)) +-#endif /* defined(SCSI_DISK8_MAJOR) */ +-#define SCSI_BLK_MAJOR(M) (SCSI_DISK_MAJOR((M)) || (M) == SCSI_CDROM_MAJOR) +-#else +-#define SCSI_BLK_MAJOR(M) ((M) == SCSI_DISK_MAJOR || (M) == SCSI_CDROM_MAJOR) +-#endif /* defined(SCSI_DISK0_MAJOR) */ +-#endif /* defined(SCSI_BLK_MAJOR) */ +- if (((MAJOR(s.st_rdev) == HD_MAJOR && +- MINOR(s.st_rdev)%64 == 0) || +- (SCSI_BLK_MAJOR(MAJOR(s.st_rdev)) && +- MINOR(s.st_rdev)%16 == 0))) { +- printf(_("%s is entire device, not just one partition!\n"), +- device); +- return 0; +- } +-#endif +- return 1; +-} +- + void check_mount(const char *device, int force, const char *type) + { + errcode_t retval; +--- a/misc/util.h ++++ b/misc/util.h +@@ -15,22 +15,11 @@ + extern char *journal_device; + extern char *journal_location_string; + +-/* +- * Flags for check_plausibility() +- */ +-#define CHECK_BLOCK_DEV 0x0001 +-#define CREATE_FILE 0x0002 +-#define CHECK_FS_EXIST 0x0004 +-#define VERBOSE_CREATE 0x0008 +-#define NO_SIZE 0x0010 +- + #ifndef HAVE_STRCASECMP + extern int strcasecmp (char *s1, char *s2); + #endif + extern char *get_progname(char *argv_zero); + extern void proceed_question(int delay); +-extern int check_plausibility(const char *device, int flags, +- int *ret_is_dev); + extern void parse_journal_opts(const char *opts); + extern void check_mount(const char *device, int force, const char *type); + extern unsigned int figure_journal_size(int size, ext2_filsys fs); +--- a/misc/uuidd.c ++++ b/misc/uuidd.c +@@ -35,7 +35,7 @@ + #endif + #include "uuid/uuid.h" + #include "uuid/uuidd.h" +-#include "nls-enable.h" ++#include "support/nls-enable.h" + #include "ext2fs/ext2fs.h" + + #ifdef __GNUC__ +--- a/misc/uuidgen.c ++++ b/misc/uuidgen.c +@@ -22,7 +22,7 @@ + extern int optind; + #endif + #include "uuid/uuid.h" +-#include "nls-enable.h" ++#include "support/nls-enable.h" + + #define DO_TYPE_TIME 1 + #define DO_TYPE_RANDOM 2 +--- /dev/null ++++ b/README.subset +@@ -0,0 +1,15 @@ ++This distribution contains a subset of the e2fsprogs package; it ++contains the base libraries (ss, et, uuid, blkid) which may be used by ++other non-ext2-related applications. ++ ++This may be useful for non-Linux operating systems that need these ++libraries for GNOME, but who do not need the ext2/ext3 filesystem ++utilities. ++ ++The full e2fsprogs distributions can be found at the e2fsprogs web ++page, which is: ++ ++ http://e2fsprogs.sourceforge.net ++ ++In case of bugs in these libraries, please contact Ted Ts'o at ++tytso@mit.edu or tytso@alum.mit.edu. +--- a/RELEASE-NOTES ++++ b/RELEASE-NOTES +@@ -1,3 +1,171 @@ ++E2fsprogs 1.43-WIP (May 18, 2015) -- cd27af3ecb83 ++================================================= ++ ++Add support for the ext4 metadata checksum, inline data, encryption, ++and read-only features. ++ ++Mke2fs will now create file systems with the metadata_csum and 64bit ++features enabled by default. ++ ++Support for the very old, experimental, and never-added-to-mainline ++compression feature has been removed. ++ ++Debugfs can now modify extended attributes and journal transactions. ++ ++The resize2fs command can now convert file systems between 64-bit and ++32-bit mode. ++ ++We now use a new e2undo file format which is much more efficient and ++faster than the old tdb-based scheme. Since it so much faster, ++e2fsck, tune2fs, debugfs, and resize2fs now also can support using ++creating an undo file. ++ ++The mke2fs command can now set the error behavior when initializing ++the file system (so the administrator doesn't have to issue a separate ++tune2fs -e command). ++ ++E2fsck is now much more paranoid about not freeing or corrupting ++critical metadata blocks, such as inode table blocks, even if ++corrupted indirect blocks or extent trees point at these blocks. ++ ++E2fsck now prints block ranges in pass1b instead of listing all of the ++blocks exhaustively. ++ ++E2fsck will try to expand the root directory if the lost+found can't ++be linked to the root directory. Also, offer to use the root ++directory if lost+found can't be created. ++ ++E2fsck is now more paranoid handling corrupted extent trees as well as ++corrupted journals. ++ ++E2fsck can now rebuild extent trees, either (a) to optimize them, (b) ++to recover from a corrupted extent tree, or (c) to convert ++block-mapped inodes to use extents. ++ ++E2fsck now has a readahead mechanism which can significantly speed its ++performance, especially on RAID arrays. ++ ++E2fsck now has a "yes to all" option which the user can give if she is ++tired of answering 'y' to a very large number of questions. ++ ++E2fsck will now ignore the badblocks inode if the contents of the ++badblocks inode indicate that the portion inode table containing the ++badblocks inode is bad. (We must go deeper...) ++ ++E2fsck can now correctly fix directory with holes on bigalloc file ++systems. ++ ++Fixed a bug in e2fsck to avoid overrunning a buffer containing jbd2 ++revoke records if the journal is corrupted. ++ ++Fixed a bug in e2fsck which could cause it loop forever if a special ++inode has too many invalid block mappings. ++ ++Fixed a bug in e2fsck which could cause pass1b/c/d processing to get ++confused if an attempt to allocate a block can't find any free space ++in the file system. ++ ++E2fsck will no longer try to force rewrite blocks located beyond the ++file system. ++ ++Fixed a bug in resize2fs which could lead to resize2fs crashing or a ++corrupted file system if the file system is almost completely full ++when trying grow a file system and we need to allocate blocks to grow ++the block group descriptors. ++ ++Fixed a bug in resize2fs which could cause it to get fooled trying to ++determinthe the RAID array's stride when flex_bg is enabled. ++ ++The dumpe2fs output has been improved so it is cleaner and always fits ++within 80 columns. Also added a more easily machine-parsable output ++of dumpe2fs. ++ ++The mke2fs program can now pre-populate a file system from a directory ++hierarchy using the -d option. ++ ++The mke2fs program now skips zeroing inode table blocks if they were ++already zeroed using the discard 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. ++ ++Added a new e2fuzz command that will fuzz an ext4 image for testing ++purposes. ++ ++The debugfs logdump command can now deal with 64-bit revoke tables ++correctly. Also, "logdump -O" will print the old log contents (before ++the journal was replayed). ++ ++The debugfs bmap command can now be used to set or allocate a physical ++block. ++ ++Fixed a bug so "filefrag -B -e -v" does not return a separate entry ++for each block. ++ ++The file I/O functions now correctly handle inodes containing ++uninitialized blocks. ++ ++Fix a bug in tune2fs so that removing uninit_bg feature on a bigalloc ++file system won't result in corrupted block bitmaps. ++ ++Programmer's Notes ++------------------ ++ ++Fixed coverity, sparce gcc -Wall, and clang warnings/nits. ++ ++Added Android build files so that e2fsprogs can be built in the ++Android source tree. ++ ++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. ++ ++Developers can now overide the debugging and optimization flags by ++redefining the CFLAGS makefile macro. ++ ++The mke2fs command will now ask the user for confirmation if block ++device or image file contains an existing file system image, and ++stdout and stdin are connected to a tty. ++ ++The libext2fs library now picks a more intelligent goal block when ++doing block allocations. ++ ++The libext2fs library will now automatically set the BLOCK_UNINT flag ++if all of the blocks in a block group are free, to speed up future ++e2fsck and dumpe2fs operations on the file system. ++ ++Add two new functions ext2fs_new_range() and ext2fs_alloc_range() to ++libext2fs. ++ ++The ext2fs_zero_blocks() command will use FALLOC_FL_ZERO_RANGE for ++file-based images. ++ ++The ext2fs_bmap() function supports new flags BMAP_UNINIT and ++BMAP_ZERO. ++ ++The ext2fs_new_block2() function will now call the alloc_block hook ++before checking fs->block_map. ++ ++Support for the MMP feature can now be disabled at compile time. ++ ++Added support to manipulate extended attributes to libext2fs. ++ ++Added a lot of new regression tests. ++ ++Added endian annotations so it's possible to scan e2fsprogs for endian ++problems using a static code analyzer. ++ ++Fixed memory leaks in libext2fs. ++ ++The e2fsck jbd2 handling code has been resynced with the 3.16 kernel. ++There is now a script in the contrib directory which automates most of ++the resync process. ++ ++The build system will now run cppcheck (a static code analysis tool) ++via "make C=1" ++ ++ + E2fsprogs 1.42.13 (May 17, 2015) + ================================ + +--- /dev/null ++++ b/resize/Android.mk +@@ -0,0 +1,45 @@ ++LOCAL_PATH := $(call my-dir) ++ ++resize2fs_src_files := \ ++ extent.c \ ++ resize2fs.c \ ++ main.c \ ++ online.c \ ++ sim_progress.c \ ++ resource_track.c ++ ++resize2fs_c_includes := external/e2fsprogs/lib ++ ++resize2fs_cflags := -O2 -g -W -Wall ++ ++resize2fs_shared_libraries := \ ++ libext2fs \ ++ libext2_com_err \ ++ libext2_e2p \ ++ libext2_uuid \ ++ libext2_blkid ++ ++resize2fs_system_shared_libraries := libc ++ ++include $(CLEAR_VARS) ++ ++LOCAL_SRC_FILES := $(resize2fs_src_files) ++LOCAL_C_INCLUDES := $(resize2fs_c_includes) ++LOCAL_CFLAGS := $(resize2fs_cflags) ++LOCAL_SHARED_LIBRARIES := $(resize2fs_shared_libraries) ++LOCAL_SYSTEM_SHARED_LIBRARIES := $(resize2fs_system_shared_libraries) ++LOCAL_MODULE := resize2fs ++LOCAL_MODULE_TAGS := optional ++include $(BUILD_EXECUTABLE) ++ ++include $(CLEAR_VARS) ++ ++LOCAL_SRC_FILES := $(resize2fs_src_files) ++LOCAL_C_INCLUDES := $(resize2fs_c_includes) ++LOCAL_CFLAGS := $(resize2fs_cflags) ++LOCAL_SHARED_LIBRARIES := $(addsuffix _host, $(resize2fs_shared_libraries)) ++LOCAL_MODULE := resize2fs_host ++LOCAL_MODULE_STEM := resize2fs ++LOCAL_MODULE_TAGS := optional ++ ++include $(BUILD_HOST_EXECUTABLE) +--- a/resize/main.c ++++ b/resize/main.c +@@ -12,8 +12,12 @@ + * %End-Header% + */ + ++#ifndef _LARGEFILE_SOURCE + #define _LARGEFILE_SOURCE ++#endif ++#ifndef _LARGEFILE64_SOURCE + #define _LARGEFILE64_SOURCE ++#endif + + #include "config.h" + #ifdef HAVE_GETOPT_H +@@ -29,6 +33,7 @@ + #include + #include + #include ++#include + + #include "e2p/e2p.h" + +@@ -42,7 +47,8 @@ + static void usage (char *prog) + { + fprintf (stderr, _("Usage: %s [-d debug_flags] [-f] [-F] [-M] [-P] " +- "[-p] device [new_size]\n\n"), prog); ++ "[-p] device [-b|-s|new_size] [-z undo_file]\n\n"), ++ prog); + + exit (1); + } +@@ -105,6 +111,7 @@ + unsigned long long sum; + unsigned int has_sb, prev_has_sb = 0, num; + int i_stride, b_stride; ++ int flexbg_size = 1 << fs->super->s_log_groups_per_flex; + + if (fs->stride) + return; +@@ -120,7 +127,8 @@ + ext2fs_inode_bitmap_loc(fs, group - 1) - + fs->super->s_blocks_per_group; + if (b_stride != i_stride || +- b_stride < 0) ++ b_stride < 0 || ++ (flexbg_size > 1 && (group % flexbg_size == 0))) + goto next; + + /* printf("group %d has stride %d\n", group, b_stride); */ +@@ -160,6 +168,81 @@ + } + } + ++static int resize2fs_setup_tdb(const char *device_name, char *undo_file, ++ io_manager *io_ptr) ++{ ++ errcode_t retval = ENOMEM; ++ char *tdb_dir = NULL, *tdb_file = NULL; ++ char *dev_name, *tmp_name; ++ ++ /* (re)open a specific undo file */ ++ if (undo_file && undo_file[0] != 0) { ++ retval = set_undo_io_backing_manager(*io_ptr); ++ if (retval) ++ goto err; ++ *io_ptr = undo_io_manager; ++ retval = set_undo_io_backup_file(undo_file); ++ if (retval) ++ goto err; ++ printf(_("Overwriting existing filesystem; this can be undone " ++ "using the command:\n" ++ " e2undo %s %s\n\n"), ++ undo_file, device_name); ++ return retval; ++ } ++ ++ /* ++ * Configuration via a conf file would be ++ * nice ++ */ ++ tdb_dir = getenv("E2FSPROGS_UNDO_DIR"); ++ if (!tdb_dir) ++ tdb_dir = "/var/lib/e2fsprogs"; ++ ++ if (!strcmp(tdb_dir, "none") || (tdb_dir[0] == 0) || ++ access(tdb_dir, W_OK)) ++ return 0; ++ ++ tmp_name = strdup(device_name); ++ if (!tmp_name) ++ goto errout; ++ dev_name = basename(tmp_name); ++ tdb_file = malloc(strlen(tdb_dir) + 11 + strlen(dev_name) + 7 + 1); ++ if (!tdb_file) { ++ free(tmp_name); ++ goto errout; ++ } ++ sprintf(tdb_file, "%s/resize2fs-%s.e2undo", tdb_dir, dev_name); ++ free(tmp_name); ++ ++ if ((unlink(tdb_file) < 0) && (errno != ENOENT)) { ++ retval = errno; ++ com_err(program_name, retval, ++ _("while trying to delete %s"), tdb_file); ++ goto errout; ++ } ++ ++ retval = set_undo_io_backing_manager(*io_ptr); ++ if (retval) ++ goto errout; ++ *io_ptr = undo_io_manager; ++ retval = set_undo_io_backup_file(tdb_file); ++ if (retval) ++ goto errout; ++ printf(_("Overwriting existing filesystem; this can be undone " ++ "using the command:\n" ++ " e2undo %s %s\n\n"), tdb_file, device_name); ++ ++ free(tdb_file); ++ return 0; ++errout: ++ free(tdb_file); ++err: ++ com_err(program_name, retval, "%s", ++ _("while trying to setup undo file\n")); ++ return retval; ++} ++ + int main (int argc, char ** argv) + { + errcode_t retval; +@@ -184,7 +267,7 @@ + unsigned int blocksize; + long sysval; + int len, mount_flags; +- char *mtpt; ++ char *mtpt, *undo_file = NULL; + + #ifdef ENABLE_NLS + setlocale(LC_MESSAGES, ""); +@@ -201,7 +284,7 @@ + if (argc && *argv) + program_name = *argv; + +- while ((c = getopt (argc, argv, "d:fFhMPpS:")) != EOF) { ++ while ((c = getopt(argc, argv, "d:fFhMPpS:bsz:")) != EOF) { + switch (c) { + case 'h': + usage(program_name); +@@ -227,6 +310,15 @@ + case 'S': + use_stride = atoi(optarg); + break; ++ case 'b': ++ flags |= RESIZE_ENABLE_64BIT; ++ break; ++ case 's': ++ flags |= RESIZE_DISABLE_64BIT; ++ break; ++ case 'z': ++ undo_file = optarg; ++ break; + default: + usage(program_name); + } +@@ -310,7 +402,11 @@ + io_flags = EXT2_FLAG_RW | EXT2_FLAG_EXCLUSIVE; + + io_flags |= EXT2_FLAG_64BITS; +- ++ if (undo_file) { ++ retval = resize2fs_setup_tdb(device_name, undo_file, &io_ptr); ++ if (retval) ++ exit(1); ++ } + retval = ext2fs_open2(device_name, io_options, io_flags, + 0, 0, io_ptr, &fs); + if (retval) { +@@ -411,6 +507,10 @@ + if (sys_page_size > blocksize) + new_size &= ~((sys_page_size / blocksize)-1); + } ++ /* If changing 64bit, don't change the filesystem size. */ ++ if (flags & (RESIZE_DISABLE_64BIT | RESIZE_ENABLE_64BIT)) { ++ new_size = ext2fs_blocks_count(fs->super); ++ } + if (!EXT2_HAS_INCOMPAT_FEATURE(fs->super, + EXT4_FEATURE_INCOMPAT_64BIT)) { + /* Take 16T down to 2^32-1 blocks */ +@@ -462,20 +562,58 @@ + blocksize / 1024, new_size); + exit(1); + } +- if (new_size == ext2fs_blocks_count(fs->super)) { ++ if ((flags & RESIZE_DISABLE_64BIT) && (flags & RESIZE_ENABLE_64BIT)) { ++ fprintf(stderr, _("Cannot set and unset 64bit feature.\n")); ++ exit(1); ++ } else if (flags & (RESIZE_DISABLE_64BIT | RESIZE_ENABLE_64BIT)) { ++ if (new_size >= (1ULL << 32)) { ++ fprintf(stderr, _("Cannot change the 64bit feature " ++ "on a filesystem that is larger than " ++ "2^32 blocks.\n")); ++ exit(1); ++ } ++ if (mount_flags & EXT2_MF_MOUNTED) { ++ fprintf(stderr, _("Cannot change the 64bit feature " ++ "while the filesystem is mounted.\n")); ++ exit(1); ++ } ++ if (flags & RESIZE_ENABLE_64BIT && ++ !EXT2_HAS_INCOMPAT_FEATURE(fs->super, ++ EXT3_FEATURE_INCOMPAT_EXTENTS)) { ++ fprintf(stderr, _("Please enable the extents feature " ++ "with tune2fs before enabling the 64bit " ++ "feature.\n")); ++ exit(1); ++ } ++ } else if (new_size == ext2fs_blocks_count(fs->super)) { + fprintf(stderr, _("The filesystem is already %llu (%dk) " + "blocks long. Nothing to do!\n\n"), new_size, + blocksize / 1024); + exit(0); + } ++ if ((flags & RESIZE_ENABLE_64BIT) && ++ EXT2_HAS_INCOMPAT_FEATURE(fs->super, EXT4_FEATURE_INCOMPAT_64BIT)) { ++ fprintf(stderr, _("The filesystem is already 64-bit.\n")); ++ exit(0); ++ } ++ if ((flags & RESIZE_DISABLE_64BIT) && ++ !EXT2_HAS_INCOMPAT_FEATURE(fs->super, EXT4_FEATURE_INCOMPAT_64BIT)) { ++ fprintf(stderr, _("The filesystem is already 32-bit.\n")); ++ exit(0); ++ } + if (mount_flags & EXT2_MF_MOUNTED) { + bigalloc_check(fs, force); + retval = online_resize_fs(fs, mtpt, &new_size, flags); + } else { + bigalloc_check(fs, force); +- printf(_("Resizing the filesystem on " +- "%s to %llu (%dk) blocks.\n"), +- device_name, new_size, blocksize / 1024); ++ if (flags & RESIZE_ENABLE_64BIT) ++ printf(_("Converting the filesystem to 64-bit.\n")); ++ else if (flags & RESIZE_DISABLE_64BIT) ++ printf(_("Converting the filesystem to 32-bit.\n")); ++ else ++ printf(_("Resizing the filesystem on " ++ "%s to %llu (%dk) blocks.\n"), ++ device_name, new_size, blocksize / 1024); + retval = resize_fs(fs, &new_size, flags, + ((flags & RESIZE_PERCENT_COMPLETE) ? + resize_progress_func : 0)); +--- a/resize/Makefile.in ++++ b/resize/Makefile.in +@@ -39,6 +39,7 @@ + $(E) " CC $<" + $(Q) $(CC) -c $(ALL_CFLAGS) $< -o $@ + $(Q) $(CHECK_CMD) $(ALL_CFLAGS) $< ++ $(Q) $(CPPCHECK_CMD) $(CPPFLAGS) $< + + all:: $(PROGS) $(TEST_PROGS) $(MANPAGES) + +--- /dev/null ++++ b/resize/Makefile.pq +@@ -0,0 +1,11 @@ ++TOPSRC=.. ++LIBNAME=RESIZE.LIB ++OBJFILE=RESIZE.LST ++ ++OBJS= extent.obj \ ++ ext2_block_move.obj \ ++ ext2_inode_move.obj \ ++ resize2fs.obj ++ ++!include $(TOPSRC)\powerquest\MCONFIG ++ +--- a/resize/resize2fs.8.in ++++ b/resize/resize2fs.8.in +@@ -8,7 +8,7 @@ + .SH SYNOPSIS + .B resize2fs + [ +-.B \-fFpPM ++.B \-fFpPMbs + ] + [ + .B \-d +@@ -18,6 +18,10 @@ + .B \-S + .I RAID-stride + ] ++[ ++.B \-z ++.I undo_file ++] + .I device + [ + .I size +@@ -86,8 +90,21 @@ + to shrink the size of the partition. When shrinking the size of + the partition, make sure you do not make it smaller than the new size + of the ext2 filesystem! ++.PP ++The ++.B \-b ++and ++.B \-s ++options enable and disable the 64bit feature, respectively. The resize2fs ++program will, of course, take care of resizing the block group descriptors ++and moving other data blocks out of the way, as needed. It is not possible ++to resize the filesystem concurrent with changing the 64bit status. + .SH OPTIONS + .TP ++.B \-b ++Turns on the 64bit feature, resizes the group descriptors as necessary, and ++moves other metadata out of the way. ++.TP + .B \-d \fIdebug-flags + Turns on various resize2fs debugging features, if they have been compiled + into the binary. +@@ -127,12 +144,25 @@ + .B \-P + Print the minimum size of the filesystem and exit. + .TP ++.B \-s ++Turns off the 64bit feature and frees blocks that are no longer in use. ++.TP + .B \-S \fIRAID-stride + The + .B resize2fs + program will heuristically determine the RAID stride that was specified + when the filesystem was created. This option allows the user to + explicitly specify a RAID stride setting to be used by resize2fs instead. ++.TP ++.BI \-z " undo_file" ++Before overwriting a file system block, write the old contents of the block to ++an undo file. This undo file can be used with e2undo(8) to restore the old ++contents of the file system should something go wrong. If the empty string is ++passed as the undo_file argument, the undo file will be written to a file named ++resize2fs-\fIdevice\fR.e2undo in the directory specified via the ++\fIE2FSPROGS_UNDO_DIR\fR environment variable. ++ ++WARNING: The undo file cannot be used to recover from a power or system crash. + .SH KNOWN BUGS + The minimum size of the filesystem as estimated by resize2fs may be + incorrect, especially for filesystems with 1k and 2k blocksizes. +--- a/resize/resize2fs.c ++++ b/resize/resize2fs.c +@@ -56,6 +56,9 @@ + static errcode_t clear_sparse_super2_last_group(ext2_resize_t rfs); + static errcode_t reserve_sparse_super2_last_group(ext2_resize_t rfs, + ext2fs_block_bitmap meta_bmap); ++static errcode_t resize_group_descriptors(ext2_resize_t rfs, blk64_t new_size); ++static errcode_t move_bg_metadata(ext2_resize_t rfs); ++static errcode_t zero_high_bits_in_inodes(ext2_resize_t rfs); + + /* + * Some helper CPP macros +@@ -122,13 +125,30 @@ + if (retval) + goto errout; + ++ init_resource_track(&rtrack, "resize_group_descriptors", fs->io); ++ retval = resize_group_descriptors(rfs, *new_size); ++ if (retval) ++ goto errout; ++ print_resource_track(rfs, &rtrack, fs->io); ++ ++ init_resource_track(&rtrack, "move_bg_metadata", fs->io); ++ retval = move_bg_metadata(rfs); ++ if (retval) ++ goto errout; ++ print_resource_track(rfs, &rtrack, fs->io); ++ ++ init_resource_track(&rtrack, "zero_high_bits_in_metadata", fs->io); ++ retval = zero_high_bits_in_inodes(rfs); ++ if (retval) ++ goto errout; ++ print_resource_track(rfs, &rtrack, fs->io); ++ + init_resource_track(&rtrack, "adjust_superblock", fs->io); + retval = adjust_superblock(rfs, *new_size); + if (retval) + goto errout; + print_resource_track(rfs, &rtrack, fs->io); + +- + init_resource_track(&rtrack, "fix_uninit_block_bitmaps 2", fs->io); + fix_uninit_block_bitmaps(rfs->new_fs); + print_resource_track(rfs, &rtrack, fs->io); +@@ -198,6 +218,10 @@ + if (retval) + goto errout; + ++ retval = ext2fs_set_gdt_csum(rfs->new_fs); ++ if (retval) ++ goto errout; ++ + rfs->new_fs->super->s_state &= ~EXT2_ERROR_FS; + rfs->new_fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY; + +@@ -231,6 +255,322 @@ + return retval; + } + ++/* Keep the size of the group descriptor region constant */ ++static void adjust_reserved_gdt_blocks(ext2_filsys old_fs, ext2_filsys fs) ++{ ++ if ((fs->super->s_feature_compat & ++ EXT2_FEATURE_COMPAT_RESIZE_INODE) && ++ (old_fs->desc_blocks != fs->desc_blocks)) { ++ int new; ++ ++ new = ((int) fs->super->s_reserved_gdt_blocks) + ++ (old_fs->desc_blocks - fs->desc_blocks); ++ if (new < 0) ++ new = 0; ++ if (new > (int) fs->blocksize/4) ++ new = fs->blocksize/4; ++ fs->super->s_reserved_gdt_blocks = new; ++ } ++} ++ ++/* Toggle 64bit mode */ ++static errcode_t resize_group_descriptors(ext2_resize_t rfs, blk64_t new_size) ++{ ++ void *o, *n, *new_group_desc; ++ dgrp_t i; ++ int copy_size; ++ errcode_t retval; ++ ++ if (!(rfs->flags & (RESIZE_DISABLE_64BIT | RESIZE_ENABLE_64BIT))) ++ return 0; ++ ++ if (new_size != ext2fs_blocks_count(rfs->new_fs->super) || ++ ext2fs_blocks_count(rfs->new_fs->super) >= (1ULL << 32) || ++ (rfs->flags & RESIZE_DISABLE_64BIT && ++ rfs->flags & RESIZE_ENABLE_64BIT)) ++ return EXT2_ET_INVALID_ARGUMENT; ++ ++ if (rfs->flags & RESIZE_DISABLE_64BIT) { ++ rfs->new_fs->super->s_feature_incompat &= ++ ~EXT4_FEATURE_INCOMPAT_64BIT; ++ rfs->new_fs->super->s_desc_size = EXT2_MIN_DESC_SIZE; ++ } else if (rfs->flags & RESIZE_ENABLE_64BIT) { ++ rfs->new_fs->super->s_feature_incompat |= ++ EXT4_FEATURE_INCOMPAT_64BIT; ++ rfs->new_fs->super->s_desc_size = EXT2_MIN_DESC_SIZE_64BIT; ++ } ++ ++ if (EXT2_DESC_SIZE(rfs->old_fs->super) == ++ EXT2_DESC_SIZE(rfs->new_fs->super)) ++ return 0; ++ ++ o = rfs->new_fs->group_desc; ++ rfs->new_fs->desc_blocks = ext2fs_div_ceil( ++ rfs->old_fs->group_desc_count, ++ EXT2_DESC_PER_BLOCK(rfs->new_fs->super)); ++ retval = ext2fs_get_arrayzero(rfs->new_fs->desc_blocks, ++ rfs->old_fs->blocksize, &new_group_desc); ++ if (retval) ++ return retval; ++ ++ n = new_group_desc; ++ ++ if (EXT2_DESC_SIZE(rfs->old_fs->super) <= ++ EXT2_DESC_SIZE(rfs->new_fs->super)) ++ copy_size = EXT2_DESC_SIZE(rfs->old_fs->super); ++ else ++ copy_size = EXT2_DESC_SIZE(rfs->new_fs->super); ++ for (i = 0; i < rfs->old_fs->group_desc_count; i++) { ++ memcpy(n, o, copy_size); ++ n += EXT2_DESC_SIZE(rfs->new_fs->super); ++ o += EXT2_DESC_SIZE(rfs->old_fs->super); ++ } ++ ++ ext2fs_free_mem(&rfs->new_fs->group_desc); ++ rfs->new_fs->group_desc = new_group_desc; ++ ++ for (i = 0; i < rfs->old_fs->group_desc_count; i++) ++ ext2fs_group_desc_csum_set(rfs->new_fs, i); ++ ++ adjust_reserved_gdt_blocks(rfs->old_fs, rfs->new_fs); ++ ++ return 0; ++} ++ ++/* Move bitmaps/inode tables out of the way. */ ++static errcode_t move_bg_metadata(ext2_resize_t rfs) ++{ ++ dgrp_t i; ++ blk64_t b, c, d, old_desc_blocks, new_desc_blocks, j; ++ ext2fs_block_bitmap old_map, new_map; ++ int old, new; ++ errcode_t retval; ++ int cluster_ratio; ++ ++ if (!(rfs->flags & (RESIZE_DISABLE_64BIT | RESIZE_ENABLE_64BIT))) ++ return 0; ++ ++ retval = ext2fs_allocate_block_bitmap(rfs->old_fs, "oldfs", &old_map); ++ if (retval) ++ return retval; ++ ++ retval = ext2fs_allocate_block_bitmap(rfs->new_fs, "newfs", &new_map); ++ if (retval) ++ goto out; ++ ++ if (EXT2_HAS_INCOMPAT_FEATURE(rfs->old_fs->super, ++ EXT2_FEATURE_INCOMPAT_META_BG)) { ++ old_desc_blocks = rfs->old_fs->super->s_first_meta_bg; ++ new_desc_blocks = rfs->new_fs->super->s_first_meta_bg; ++ } else { ++ old_desc_blocks = rfs->old_fs->desc_blocks + ++ rfs->old_fs->super->s_reserved_gdt_blocks; ++ new_desc_blocks = rfs->new_fs->desc_blocks + ++ rfs->new_fs->super->s_reserved_gdt_blocks; ++ } ++ ++ /* Construct bitmaps of super/descriptor blocks in old and new fs */ ++ for (i = 0; i < rfs->old_fs->group_desc_count; i++) { ++ retval = ext2fs_super_and_bgd_loc2(rfs->old_fs, i, &b, &c, &d, ++ NULL); ++ if (retval) ++ goto out; ++ if (b) ++ ext2fs_mark_block_bitmap2(old_map, b); ++ for (j = 0; c != 0 && j < old_desc_blocks; j++) ++ ext2fs_mark_block_bitmap2(old_map, c + j); ++ if (d) ++ ext2fs_mark_block_bitmap2(old_map, d); ++ ++ retval = ext2fs_super_and_bgd_loc2(rfs->new_fs, i, &b, &c, &d, ++ NULL); ++ if (retval) ++ goto out; ++ if (b) ++ ext2fs_mark_block_bitmap2(new_map, b); ++ for (j = 0; c != 0 && j < new_desc_blocks; j++) ++ ext2fs_mark_block_bitmap2(new_map, c + j); ++ if (d) ++ ext2fs_mark_block_bitmap2(new_map, d); ++ } ++ ++ cluster_ratio = EXT2FS_CLUSTER_RATIO(rfs->new_fs); ++ ++ /* Find changes in block allocations for bg metadata */ ++ for (b = EXT2FS_B2C(rfs->old_fs, ++ rfs->old_fs->super->s_first_data_block); ++ b < ext2fs_blocks_count(rfs->new_fs->super); ++ b += cluster_ratio) { ++ old = ext2fs_test_block_bitmap2(old_map, b); ++ new = ext2fs_test_block_bitmap2(new_map, b); ++ ++ if (old && !new) { ++ /* mark old_map, unmark new_map */ ++ if (cluster_ratio == 1) ++ ext2fs_unmark_block_bitmap2( ++ rfs->new_fs->block_map, b); ++ } else if (!old && new) ++ ; /* unmark old_map, mark new_map */ ++ else { ++ ext2fs_unmark_block_bitmap2(old_map, b); ++ ext2fs_unmark_block_bitmap2(new_map, b); ++ } ++ } ++ ++ /* ++ * new_map now shows blocks that have been newly allocated. ++ * old_map now shows blocks that have been newly freed. ++ */ ++ ++ /* ++ * Move any conflicting bitmaps and inode tables. Ensure that we ++ * don't try to free clusters associated with bitmaps or tables. ++ */ ++ for (i = 0; i < rfs->old_fs->group_desc_count; i++) { ++ b = ext2fs_block_bitmap_loc(rfs->new_fs, i); ++ if (ext2fs_test_block_bitmap2(new_map, b)) ++ ext2fs_block_bitmap_loc_set(rfs->new_fs, i, 0); ++ else if (ext2fs_test_block_bitmap2(old_map, b)) ++ ext2fs_unmark_block_bitmap2(old_map, b); ++ ++ b = ext2fs_inode_bitmap_loc(rfs->new_fs, i); ++ if (ext2fs_test_block_bitmap2(new_map, b)) ++ ext2fs_inode_bitmap_loc_set(rfs->new_fs, i, 0); ++ else if (ext2fs_test_block_bitmap2(old_map, b)) ++ ext2fs_unmark_block_bitmap2(old_map, b); ++ ++ c = ext2fs_inode_table_loc(rfs->new_fs, i); ++ for (b = 0; ++ b < rfs->new_fs->inode_blocks_per_group; ++ b++) { ++ if (ext2fs_test_block_bitmap2(new_map, b + c)) ++ ext2fs_inode_table_loc_set(rfs->new_fs, i, 0); ++ else if (ext2fs_test_block_bitmap2(old_map, b + c)) ++ ext2fs_unmark_block_bitmap2(old_map, b + c); ++ } ++ } ++ ++ /* Free unused clusters */ ++ for (b = 0; ++ cluster_ratio > 1 && b < ext2fs_blocks_count(rfs->new_fs->super); ++ b += cluster_ratio) ++ if (ext2fs_test_block_bitmap2(old_map, b)) ++ ext2fs_unmark_block_bitmap2(rfs->new_fs->block_map, b); ++out: ++ if (old_map) ++ ext2fs_free_block_bitmap(old_map); ++ if (new_map) ++ ext2fs_free_block_bitmap(new_map); ++ return retval; ++} ++ ++/* Zero out the high bits of extent fields */ ++static errcode_t zero_high_bits_in_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; ++ ++ op = EXT2_EXTENT_NEXT_SIB; ++ ++ if (extent.e_pblk > (1ULL << 32)) { ++ extent.e_pblk &= (1ULL << 32) - 1; ++ 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; ++ ext2fs_extent_free(handle); ++ return errcode; ++} ++ ++/* Zero out the high bits of inodes. */ ++static errcode_t zero_high_bits_in_inodes(ext2_resize_t rfs) ++{ ++ ext2_filsys fs = rfs->old_fs; ++ int length = EXT2_INODE_SIZE(fs->super); ++ struct ext2_inode *inode = NULL; ++ ext2_inode_scan scan = NULL; ++ errcode_t retval; ++ ext2_ino_t ino; ++ ++ if (!(rfs->flags & (RESIZE_DISABLE_64BIT | RESIZE_ENABLE_64BIT))) ++ return 0; ++ ++ if (fs->super->s_creator_os != EXT2_OS_LINUX) ++ return 0; ++ ++ retval = ext2fs_open_inode_scan(fs, 0, &scan); ++ if (retval) ++ return retval; ++ ++ 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)) ++ continue; ++ ++ /* ++ * Here's how we deal with high block number fields: ++ * ++ * - i_size_high has been been written out with i_size_lo ++ * since the ext2 days, so no conversion is needed. ++ * ++ * - i_blocks_hi is guarded by both the huge_file feature and ++ * inode flags and has always been written out with ++ * i_blocks_lo if the feature is set. The field is only ++ * ever read if both feature and inode flag are set, so ++ * we don't need to zero it now. ++ * ++ * - i_file_acl_high can be uninitialized, so zero it if ++ * it isn't already. ++ */ ++ if (inode->osd2.linux2.l_i_file_acl_high) { ++ inode->osd2.linux2.l_i_file_acl_high = 0; ++ retval = ext2fs_write_inode_full(fs, ino, inode, ++ length); ++ if (retval) ++ goto out; ++ } ++ ++ retval = zero_high_bits_in_extents(fs, ino, inode); ++ if (retval) ++ goto out; ++ } while (ino); ++ ++out: ++ if (inode) ++ ext2fs_free_mem(&inode); ++ if (scan) ++ ext2fs_close_inode_scan(scan); ++ return retval; ++} ++ + /* + * Clean up the bitmaps for unitialized bitmaps + */ +@@ -240,8 +580,7 @@ + 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++) { +@@ -455,7 +794,8 @@ + /* + * Reallocate the group descriptors as necessary. + */ +- if (old_fs->desc_blocks != fs->desc_blocks) { ++ if (EXT2_DESC_SIZE(old_fs->super) == EXT2_DESC_SIZE(fs->super) && ++ old_fs->desc_blocks != fs->desc_blocks) { + retval = ext2fs_resize_mem(old_fs->desc_blocks * + fs->blocksize, + fs->desc_blocks * fs->blocksize, +@@ -474,20 +814,11 @@ + * number of descriptor blocks, then adjust + * s_reserved_gdt_blocks if possible to avoid needing to move + * the inode table either now or in the future. ++ * ++ * Note: If we're converting to 64bit mode, we did this earlier. + */ +- if ((fs->super->s_feature_compat & +- EXT2_FEATURE_COMPAT_RESIZE_INODE) && +- (old_fs->desc_blocks != fs->desc_blocks)) { +- int new; +- +- new = ((int) fs->super->s_reserved_gdt_blocks) + +- (old_fs->desc_blocks - fs->desc_blocks); +- if (new < 0) +- new = 0; +- if (new > (int) fs->blocksize/4) +- new = fs->blocksize/4; +- fs->super->s_reserved_gdt_blocks = new; +- } ++ if (EXT2_DESC_SIZE(old_fs->super) == EXT2_DESC_SIZE(fs->super)) ++ adjust_reserved_gdt_blocks(old_fs, fs); + + if ((fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_META_BG) && + (fs->super->s_first_meta_bg > fs->desc_blocks)) { +@@ -572,9 +903,9 @@ + */ + 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); +- if (access("/sys/fs/ext4/features/lazy_itable_init", F_OK) == 0) ++ csum_flag = ext2fs_has_group_desc_csum(fs); ++ if (!getenv("RESIZE2FS_FORCE_ITABLE_INIT") && ++ 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) + old_desc_blocks = fs->super->s_first_meta_bg; +@@ -731,9 +1062,7 @@ + * 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; + } +@@ -762,11 +1091,11 @@ + /* + * Write out the new inode table + */ +- retval = io_channel_write_blk64(fs->io, +- ext2fs_inode_table_loc(fs, i), +- fs->inode_blocks_per_group, +- rfs->itable_buf); +- if (retval) goto errout; ++ retval = ext2fs_zero_blocks2(fs, ext2fs_inode_table_loc(fs, i), ++ fs->inode_blocks_per_group, NULL, ++ NULL); ++ if (retval) ++ goto errout; + + io_channel_flush(fs->io); + if (rfs->progress) { +@@ -889,9 +1218,9 @@ + } + } + } +- 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 +1316,7 @@ + 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 +@@ -1019,7 +1347,9 @@ + if (retval) + goto errout; + +- if (old_blocks == new_blocks) { ++ if (EXT2_DESC_SIZE(rfs->old_fs->super) == ++ EXT2_DESC_SIZE(rfs->new_fs->super) && ++ old_blocks == new_blocks) { + retval = 0; + goto errout; + } +@@ -1047,7 +1377,7 @@ + } + + for (i = 0; i < max_groups; i++) { +- if (!ext2fs_bg_has_super(fs, i)) { ++ if (!ext2fs_bg_has_super(old_fs, i)) { + group_blk += fs->super->s_blocks_per_group; + continue; + } +@@ -1284,7 +1614,8 @@ + } + } + +-static errcode_t resize2fs_get_alloc_block(ext2_filsys fs, blk64_t goal, ++static errcode_t resize2fs_get_alloc_block(ext2_filsys fs, ++ blk64_t goal EXT2FS_ATTR((unused)), + blk64_t *ret) + { + ext2_resize_t rfs = (ext2_resize_t) fs->priv_data; +@@ -1461,10 +1792,12 @@ + 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 +1821,13 @@ + #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 (pb->is_dir) { + retval = ext2fs_add_dir_block2(fs->dblist, pb->ino, + block, (int) blockcnt); +@@ -1532,6 +1867,106 @@ + return 0; + } + ++static errcode_t migrate_ea_block(ext2_resize_t rfs, ext2_ino_t ino, ++ struct ext2_inode *inode, int *changed) ++{ ++ char *buf = NULL; ++ 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; ++} ++ ++/* Rewrite extents */ ++static errcode_t rewrite_extents(ext2_filsys fs, ext2_ino_t ino) ++{ ++ ext2_extent_handle_t handle; ++ struct ext2fs_extent extent; ++ errcode_t errcode; ++ struct ext2_extent_info info; ++ ++ errcode = ext2fs_extent_open(fs, ino, &handle); ++ if (errcode) ++ return errcode; ++ ++ errcode = ext2fs_extent_get(handle, EXT2_EXTENT_ROOT, &extent); ++ if (errcode) ++ goto out; ++ ++ do { ++ errcode = ext2fs_extent_get_info(handle, &info); ++ if (errcode) ++ break; ++ ++ /* ++ * If this is the first extent in an extent block that we ++ * haven't visited, rewrite the extent to force the ETB ++ * checksum to be rewritten. ++ */ ++ if (info.curr_entry == 1 && info.curr_level != 0 && ++ !(extent.e_flags & EXT2_EXTENT_FLAGS_SECOND_VISIT)) { ++ errcode = ext2fs_extent_replace(handle, 0, &extent); ++ if (errcode) ++ break; ++ } ++ ++ /* Skip to the end of a block of leaf nodes */ ++ if (extent.e_flags & EXT2_EXTENT_FLAGS_LEAF) { ++ errcode = ext2fs_extent_get(handle, ++ EXT2_EXTENT_LAST_SIB, ++ &extent); ++ if (errcode) ++ break; ++ } ++ ++ errcode = ext2fs_extent_get(handle, EXT2_EXTENT_NEXT, &extent); ++ } while (errcode == 0); ++ ++out: ++ /* Ok if we run off the end */ ++ if (errcode == EXT2_ET_EXTENT_NO_NEXT) ++ errcode = 0; ++ ext2fs_extent_free(handle); ++ return errcode; ++} ++ ++static void quiet_com_err_proc(const char *whoami EXT2FS_ATTR((unused)), ++ errcode_t code EXT2FS_ATTR((unused)), ++ const char *fmt EXT2FS_ATTR((unused)), ++ va_list args EXT2FS_ATTR((unused))) ++{ ++} ++ + static errcode_t inode_scan_and_fix(ext2_resize_t rfs) + { + struct process_block_struct pb; +@@ -1541,8 +1976,6 @@ + errcode_t retval; + 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 <= +@@ -1550,16 +1983,7 @@ + !rfs->bmap) + return 0; + +- /* +- * Save the original size of the old filesystem, and +- * temporarily set the size to be the new size if the new size +- * is larger. We need to do this to avoid catching an error +- * by the block iterator routines +- */ +- orig_size = ext2fs_blocks_count(rfs->old_fs->super); +- if (orig_size < ext2fs_blocks_count(rfs->new_fs->super)) +- ext2fs_blocks_count_set(rfs->old_fs->super, +- ext2fs_blocks_count(rfs->new_fs->super)); ++ set_com_err_hook(quiet_com_err_proc); + + retval = ext2fs_open_inode_scan(rfs->old_fs, 0, &scan); + if (retval) goto errout; +@@ -1605,37 +2029,19 @@ + 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 +2049,12 @@ + + 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,11 +2066,60 @@ + 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; ++ ++ /* Rewrite extent block checksums with new inode number */ ++ if (EXT2_HAS_RO_COMPAT_FEATURE(rfs->old_fs->super, ++ EXT4_FEATURE_RO_COMPAT_METADATA_CSUM) && ++ (inode->i_flags & EXT4_EXTENTS_FL)) { ++ rfs->old_fs->flags |= EXT2_FLAG_IGNORE_CSUM_ERRORS; ++ retval = rewrite_extents(rfs->old_fs, new_inode); ++ rfs->old_fs->flags &= ~EXT2_FLAG_IGNORE_CSUM_ERRORS; ++ 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); + + errout: +- ext2fs_blocks_count_set(rfs->old_fs->super, orig_size); ++ reset_com_err_hook(); + if (rfs->bmap) { + ext2fs_free_extent_table(rfs->bmap); + rfs->bmap = 0; +@@ -1706,6 +2157,7 @@ + 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 +2168,26 @@ + 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 +2199,10 @@ + 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 +2229,11 @@ + 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) { +@@ -2052,7 +2515,7 @@ + if (retval) + return retval; + +- if (!sb) { ++ if (last_bg && !sb) { + fputs(_("Should never happen! No sb in last super_sparse bg?\n"), + stderr); + exit(1); +@@ -2112,15 +2575,11 @@ + { + struct ext2_inode inode; + errcode_t retval; +- char *block_buf = NULL; + + if (!(fs->super->s_feature_compat & + EXT2_FEATURE_COMPAT_RESIZE_INODE)) + return 0; + +- retval = ext2fs_get_mem(fs->blocksize, &block_buf); +- if (retval) goto errout; +- + retval = ext2fs_read_inode(fs, EXT2_RESIZE_INO, &inode); + if (retval) goto errout; + +@@ -2140,19 +2599,16 @@ + exit(1); + } + +- memset(block_buf, 0, fs->blocksize); +- +- retval = io_channel_write_blk64(fs->io, inode.i_block[EXT2_DIND_BLOCK], +- 1, block_buf); +- if (retval) goto errout; ++ retval = ext2fs_zero_blocks2(fs, inode.i_block[EXT2_DIND_BLOCK], 1, ++ NULL, NULL); ++ if (retval) ++ goto errout; + + retval = ext2fs_create_resize_inode(fs); + if (retval) + goto errout; + + errout: +- if (block_buf) +- ext2fs_free_mem(&block_buf); + return retval; + } + +--- a/resize/resize2fs.h ++++ b/resize/resize2fs.h +@@ -82,6 +82,9 @@ + #define RESIZE_PERCENT_COMPLETE 0x0100 + #define RESIZE_VERBOSE 0x0200 + ++#define RESIZE_ENABLE_64BIT 0x0400 ++#define RESIZE_DISABLE_64BIT 0x0800 ++ + /* + * This structure is used for keeping track of how much resources have + * been used for a particular resize2fs pass. +--- /dev/null ++++ b/tests/d_dumpe2fs_group_only/expect +@@ -0,0 +1,51 @@ ++Creating filesystem with 1048576 4k blocks and 262144 inodes ++Superblock backups stored on blocks: ++ 32768, 98304, 163840, 229376, 294912, 819200, 884736 ++ ++Allocating group tables: done ++Writing inode tables: done ++Creating journal (32768 blocks): done ++Writing superblocks and filesystem accounting information: done ++ ++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/262144 files (0.0% non-contiguous), 51278/1048576 blocks ++Exit status is 0 ++dumpe2fs output ++ ++group:block:super:gdt:bbitmap:ibitmap:itable ++0:0:0:1-1:257:273:289 ++1:32768:32768:32769-32769:258:274:801 ++2:65536:-1:-1:259:275:1313 ++3:98304:98304:98305-98305:260:276:1825 ++4:131072:-1:-1:261:277:2337 ++5:163840:163840:163841-163841:262:278:2849 ++6:196608:-1:-1:263:279:3361 ++7:229376:229376:229377-229377:264:280:3873 ++8:262144:-1:-1:265:281:4385 ++9:294912:294912:294913-294913:266:282:4897 ++10:327680:-1:-1:267:283:5409 ++11:360448:-1:-1:268:284:5921 ++12:393216:-1:-1:269:285:6433 ++13:425984:-1:-1:270:286:6945 ++14:458752:-1:-1:271:287:7457 ++15:491520:-1:-1:272:288:7969 ++16:524288:-1:-1:524288:524304:524320 ++17:557056:-1:-1:524289:524305:524832 ++18:589824:-1:-1:524290:524306:525344 ++19:622592:-1:-1:524291:524307:525856 ++20:655360:-1:-1:524292:524308:526368 ++21:688128:-1:-1:524293:524309:526880 ++22:720896:-1:-1:524294:524310:527392 ++23:753664:-1:-1:524295:524311:527904 ++24:786432:-1:-1:524296:524312:528416 ++25:819200:819200:819201-819201:524297:524313:528928 ++26:851968:-1:-1:524298:524314:529440 ++27:884736:884736:884737-884737:524299:524315:529952 ++28:917504:-1:-1:524300:524316:530464 ++29:950272:-1:-1:524301:524317:530976 ++30:983040:-1:-1:524302:524318:531488 ++31:1015808:-1:-1:524303:524319:532000 +--- /dev/null ++++ b/tests/d_dumpe2fs_group_only/name +@@ -0,0 +1 @@ ++dumpe2fs group only mode +--- /dev/null ++++ b/tests/d_dumpe2fs_group_only/script +@@ -0,0 +1,49 @@ ++if [ $(uname -s) = "Darwin" ]; then ++ # creates a 4GB filesystem ++ echo "$test_name: $DESCRIPTION: skipped for HFS+ (no sparse files)" ++ return 0 ++fi ++ ++if test -x $DEBUGFS_EXE; then ++ ++FSCK_OPT=-fy ++OUT=$test_name.log ++if [ -f $test_dir/expect.gz ]; then ++ EXP=$test_name.tmp ++ gunzip < $test_dir/expect.gz > $EXP1 ++else ++ EXP=$test_dir/expect ++fi ++ ++cp /dev/null $OUT ++ ++$MKE2FS -F -o Linux -b 4096 -O has_journal -T ext4 $TMPFILE 1048576 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT 2>&1 ++ ++$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 ++status=$? ++echo Exit status is $status >> $OUT.new ++sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT ++rm -f $OUT.new ++ ++echo "dumpe2fs output" >> $OUT ++$DUMPE2FS -g $TMPFILE 2>&1 | sed -f $cmd_dir/filter.sed >> $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 IMAGE FSCK_OPT OUT EXP ++ ++else #if test -x $DEBUGFS_EXE; then ++ echo "$test_name: $test_description: skipped" ++fi +--- /dev/null ++++ b/tests/defaults/j_script +@@ -0,0 +1 @@ ++. $cmd_dir/run_e2fsck +--- /dev/null ++++ b/tests/d_fallocate/name +@@ -0,0 +1 @@ ++fallocate sparse files and big files +--- /dev/null ++++ b/tests/d_fallocate/script +@@ -0,0 +1,175 @@ ++if test -x $DEBUGFS_EXE; then ++ ++FSCK_OPT=-fy ++OUT=$test_name.log ++if [ -f $test_dir/expect.gz ]; then ++ EXP=$test_name.tmp ++ gunzip < $test_dir/expect.gz > $EXP ++else ++ EXP=$test_dir/expect ++fi ++ ++cp /dev/null $OUT ++ ++cat > $TMPFILE.conf << ENDL ++[fs_types] ++ext4 = { ++ base_features = sparse_super,filetype,resize_inode,dir_index,ext_attr,^has_journal,extent,huge_file,flex_bg,uninit_bg,dir_nlink,extra_isize,64bit ++ blocksize = 1024 ++ inode_size = 256 ++ inode_ratio = 16384 ++} ++ENDL ++MKE2FS_CONFIG=$TMPFILE.conf $MKE2FS -F -o Linux -b 1024 -O ^bigalloc -T ext4 $TMPFILE 65536 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT 2>&1 ++rm -rf $TMPFILE.conf ++ ++$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 ++status=$? ++echo Exit status is $status >> $OUT.new ++sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT ++rm -f $OUT.new ++ ++echo "debugfs write files" >> $OUT ++make_file() { ++ name="$1" ++ start="$2" ++ flag="$3" ++ ++ cat << ENDL ++write /dev/null $name ++sif /$name size 40960 ++eo /$name ++set_bmap $flag 10 $((start + 10)) ++set_bmap $flag 13 $((start + 13)) ++set_bmap $flag 26 $((start + 26)) ++set_bmap $flag 29 $((start + 29)) ++ec ++sif /$name blocks 8 ++setb $((start + 10)) ++setb $((start + 13)) ++setb $((start + 26)) ++setb $((start + 29)) ++ENDL ++} ++ ++#Files we create: ++# a: fallocate a 40k file ++# b*: falloc sparse file starting at b* ++# c*: falloc spare file ending at c* ++# d: midcluster to midcluster, surrounding sparse ++# e: partial middle cluster alloc ++# f: one big file ++# g*: falloc sparse init file starting at g* ++# h*: falloc sparse init file ending at h* ++# i: midcluster to midcluster, surrounding sparse init ++# j: partial middle cluster alloc ++# k: one big init file ++base=5000 ++cat > $TMPFILE.cmd << ENDL ++write /dev/null a ++sif /a size 40960 ++fallocate /a 0 39 ++ENDL ++echo "ex /a" >> $TMPFILE.cmd2 ++ ++make_file sample $base --uninit >> $TMPFILE.cmd ++echo "ex /sample" >> $TMPFILE.cmd2 ++base=10000 ++ ++for i in 8 9 10 11 12 13 14 15; do ++ make_file b$i $(($base + (40 * ($i - 8)))) --uninit >> $TMPFILE.cmd ++ echo "fallocate /b$i $i 39" >> $TMPFILE.cmd ++ echo "ex /b$i" >> $TMPFILE.cmd2 ++done ++ ++for i in 24 25 26 27 28 29 30 31; do ++ make_file c$i $(($base + 320 + (40 * ($i - 24)))) --uninit >> $TMPFILE.cmd ++ echo "fallocate /c$i 0 $i" >> $TMPFILE.cmd ++ echo "ex /c$i" >> $TMPFILE.cmd2 ++done ++ ++make_file d $(($base + 640)) --uninit >> $TMPFILE.cmd ++echo "fallocate /d 4 35" >> $TMPFILE.cmd ++echo "ex /d" >> $TMPFILE.cmd2 ++ ++make_file e $(($base + 680)) --uninit >> $TMPFILE.cmd ++echo "fallocate /e 19 20" >> $TMPFILE.cmd ++echo "ex /e" >> $TMPFILE.cmd2 ++ ++cat >> $TMPFILE.cmd << ENDL ++write /dev/null f ++sif /f size 1024 ++eo /f ++set_bmap --uninit 0 9000 ++ec ++sif /f blocks 2 ++setb 9000 ++fallocate /f 0 8999 ++ENDL ++echo "ex /f" >> $TMPFILE.cmd2 ++ ++# Now do it again, but with initialized blocks ++base=20000 ++for i in 8 9 10 11 12 13 14 15; do ++ make_file g$i $(($base + (40 * ($i - 8)))) >> $TMPFILE.cmd ++ echo "fallocate /g$i $i 39" >> $TMPFILE.cmd ++ echo "ex /g$i" >> $TMPFILE.cmd2 ++done ++ ++for i in 24 25 26 27 28 29 30 31; do ++ make_file h$i $(($base + 320 + (40 * ($i - 24)))) >> $TMPFILE.cmd ++ echo "fallocate /h$i 0 $i" >> $TMPFILE.cmd ++ echo "ex /h$i" >> $TMPFILE.cmd2 ++done ++ ++make_file i $(($base + 640)) >> $TMPFILE.cmd ++echo "fallocate /i 4 35" >> $TMPFILE.cmd ++echo "ex /i" >> $TMPFILE.cmd2 ++ ++make_file j $(($base + 680)) >> $TMPFILE.cmd ++echo "fallocate /j 19 20" >> $TMPFILE.cmd ++echo "ex /j" >> $TMPFILE.cmd2 ++ ++cat >> $TMPFILE.cmd << ENDL ++write /dev/null k ++sif /k size 1024 ++eo /k ++set_bmap 0 19000 ++ec ++sif /k blocks 2 ++setb 19000 ++fallocate /k 0 8999 ++sif /k size 9216000 ++ENDL ++echo "ex /k" >> $TMPFILE.cmd2 ++ ++$DEBUGFS_EXE -w -f $TMPFILE.cmd $TMPFILE > /dev/null 2>&1 ++$DEBUGFS_EXE -f $TMPFILE.cmd2 $TMPFILE >> $OUT.new 2>&1 ++sed -f $cmd_dir/filter.sed < $OUT.new >> $OUT ++rm -rf $OUT.new $TMPFILE.cmd $TMPFILE.cmd2 ++ ++$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 ++status=$? ++echo Exit status is $status >> $OUT.new ++sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT ++rm -f $OUT.new ++ ++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 IMAGE FSCK_OPT OUT EXP ++ ++else #if test -x $DEBUGFS_EXE; then ++ echo "$test_name: $test_description: skipped" ++fi +--- /dev/null ++++ b/tests/d_fallocate_bigalloc/name +@@ -0,0 +1 @@ ++fallocate sparse files and big files with bigalloc +--- /dev/null ++++ b/tests/d_fallocate_bigalloc/script +@@ -0,0 +1,176 @@ ++if test -x $DEBUGFS_EXE; then ++ ++FSCK_OPT=-fy ++OUT=$test_name.log ++if [ -f $test_dir/expect.gz ]; then ++ EXP=$test_name.tmp ++ gunzip < $test_dir/expect.gz > $EXP ++else ++ EXP=$test_dir/expect ++fi ++ ++cp /dev/null $OUT ++ ++cat > $TMPFILE.conf << ENDL ++[fs_types] ++ext4 = { ++ cluster_size = 8192 ++ base_features = sparse_super,filetype,resize_inode,dir_index,ext_attr,^has_journal,extent,huge_file,flex_bg,uninit_bg,dir_nlink,extra_isize,64bit ++ blocksize = 1024 ++ inode_size = 256 ++ inode_ratio = 16384 ++} ++ENDL ++MKE2FS_CONFIG=$TMPFILE.conf $MKE2FS -F -o Linux -b 1024 -O bigalloc -T ext4 $TMPFILE 65536 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT 2>&1 ++rm -rf $TMPFILE.conf ++ ++$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 ++status=$? ++echo Exit status is $status >> $OUT.new ++sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT ++rm -f $OUT.new ++ ++echo "debugfs write files" >> $OUT ++make_file() { ++ name="$1" ++ start="$2" ++ flag="$3" ++ ++ cat << ENDL ++write /dev/null $name ++sif /$name size 40960 ++eo /$name ++set_bmap $flag 10 $((start + 10)) ++set_bmap $flag 13 $((start + 13)) ++set_bmap $flag 26 $((start + 26)) ++set_bmap $flag 29 $((start + 29)) ++ec ++sif /$name blocks 32 ++setb $((start + 10)) ++setb $((start + 13)) ++setb $((start + 26)) ++setb $((start + 29)) ++ENDL ++} ++ ++#Files we create: ++# a: fallocate a 40k file ++# b*: falloc sparse file starting at b* ++# c*: falloc spare file ending at c* ++# d: midcluster to midcluster, surrounding sparse ++# e: partial middle cluster alloc ++# f: one big file ++# g*: falloc sparse init file starting at g* ++# h*: falloc sparse init file ending at h* ++# i: midcluster to midcluster, surrounding sparse init ++# j: partial middle cluster alloc ++# k: one big init file ++base=5000 ++cat > $TMPFILE.cmd << ENDL ++write /dev/null a ++sif /a size 40960 ++fallocate /a 0 39 ++ENDL ++echo "ex /a" >> $TMPFILE.cmd2 ++ ++make_file sample $base --uninit >> $TMPFILE.cmd ++echo "ex /sample" >> $TMPFILE.cmd2 ++base=10000 ++ ++for i in 8 9 10 11 12 13 14 15; do ++ make_file b$i $(($base + (40 * ($i - 8)))) --uninit >> $TMPFILE.cmd ++ echo "fallocate /b$i $i 39" >> $TMPFILE.cmd ++ echo "ex /b$i" >> $TMPFILE.cmd2 ++done ++ ++for i in 24 25 26 27 28 29 30 31; do ++ make_file c$i $(($base + 320 + (40 * ($i - 24)))) --uninit >> $TMPFILE.cmd ++ echo "fallocate /c$i 0 $i" >> $TMPFILE.cmd ++ echo "ex /c$i" >> $TMPFILE.cmd2 ++done ++ ++make_file d $(($base + 640)) --uninit >> $TMPFILE.cmd ++echo "fallocate /d 4 35" >> $TMPFILE.cmd ++echo "ex /d" >> $TMPFILE.cmd2 ++ ++make_file e $(($base + 680)) --uninit >> $TMPFILE.cmd ++echo "fallocate /e 19 20" >> $TMPFILE.cmd ++echo "ex /e" >> $TMPFILE.cmd2 ++ ++cat >> $TMPFILE.cmd << ENDL ++write /dev/null f ++sif /f size 1024 ++eo /f ++set_bmap --uninit 0 9000 ++ec ++sif /f blocks 16 ++setb 9000 ++fallocate /f 0 8999 ++ENDL ++echo "ex /f" >> $TMPFILE.cmd2 ++ ++# Now do it again, but with initialized blocks ++base=20000 ++for i in 8 9 10 11 12 13 14 15; do ++ make_file g$i $(($base + (40 * ($i - 8)))) >> $TMPFILE.cmd ++ echo "fallocate /g$i $i 39" >> $TMPFILE.cmd ++ echo "ex /g$i" >> $TMPFILE.cmd2 ++done ++ ++for i in 24 25 26 27 28 29 30 31; do ++ make_file h$i $(($base + 320 + (40 * ($i - 24)))) >> $TMPFILE.cmd ++ echo "fallocate /h$i 0 $i" >> $TMPFILE.cmd ++ echo "ex /h$i" >> $TMPFILE.cmd2 ++done ++ ++make_file i $(($base + 640)) >> $TMPFILE.cmd ++echo "fallocate /i 4 35" >> $TMPFILE.cmd ++echo "ex /i" >> $TMPFILE.cmd2 ++ ++make_file j $(($base + 680)) >> $TMPFILE.cmd ++echo "fallocate /j 19 20" >> $TMPFILE.cmd ++echo "ex /j" >> $TMPFILE.cmd2 ++ ++cat >> $TMPFILE.cmd << ENDL ++write /dev/null k ++sif /k size 1024 ++eo /k ++set_bmap 0 19000 ++ec ++sif /k blocks 16 ++setb 19000 ++fallocate /k 0 8999 ++sif /k size 9216000 ++ENDL ++echo "ex /k" >> $TMPFILE.cmd2 ++ ++$DEBUGFS_EXE -w -f $TMPFILE.cmd $TMPFILE > /dev/null 2>&1 ++$DEBUGFS_EXE -f $TMPFILE.cmd2 $TMPFILE >> $OUT.new 2>&1 ++sed -f $cmd_dir/filter.sed < $OUT.new >> $OUT ++rm -rf $OUT.new $TMPFILE.cmd $TMPFILE.cmd2 ++ ++$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 ++status=$? ++echo Exit status is $status >> $OUT.new ++sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT ++rm -f $OUT.new ++ ++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 IMAGE FSCK_OPT OUT EXP ++ ++else #if test -x $DEBUGFS_EXE; then ++ echo "$test_name: $test_description: skipped" ++fi +--- /dev/null ++++ b/tests/d_fallocate_blkmap/expect +@@ -0,0 +1,58 @@ ++Creating filesystem with 65536 1k blocks and 4096 inodes ++Superblock backups stored on blocks: ++ 8193, 24577, 40961, 57345 ++ ++Allocating group tables: done ++Writing inode tables: done ++Writing superblocks and filesystem accounting information: done ++ ++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/4096 files (0.0% non-contiguous), 2340/65536 blocks ++Exit status is 0 ++debugfs write files ++debugfs: stat /a ++Inode: 12 Type: regular Mode: 0666 Flags: 0x0 ++Generation: 0 Version: 0x00000000:00000000 ++User: 0 Group: 0 Size: 40960 ++File ACL: 0 Directory ACL: 0 ++Links: 1 Blockcount: 82 ++Fragment: Address: 0 Number: 0 Size: 0 ++Size of extra inode fields: 28 ++BLOCKS: ++(0-1):1312-1313, (2-11):8000-8009, (IND):8010, (12-39):8011-8038 ++TOTAL: 41 ++ ++debugfs: stat /b ++Inode: 13 Type: regular Mode: 0666 Flags: 0x0 ++Generation: 0 Version: 0x00000000:00000000 ++User: 0 Group: 0 Size: 10240000 ++File ACL: 0 Directory ACL: 0 ++Links: 1 Blockcount: 20082 ++Fragment: Address: 0 Number: 0 Size: 0 ++Size of extra inode fields: 28 ++BLOCKS: ++(0-11):10000-10011, (IND):10012, (12-267):10013-10268, (DIND):10269, (IND):10270, (268-523):10271-10526, (IND):10527, (524-779):10528-10783, (IND):10784, (780-1035):10785-11040, (IND):11041, (1036-1291):11042-11297, (IND):11298, (1292-1547):11299-11554, (IND):11555, (1548-1803):11556-11811, (IND):11812, (1804-2059):11813-12068, (IND):12069, (2060-2315):12070-12325, (IND):12326, (2316-2571):12327-12582, (IND):12583, (2572-2827):12584-12839, (IND):12840, (2828-3083):12841-13096, (IND):13097, (3084-3339):13098-13353, (IND):13354, (3340-3595):13355-13610, (IND):13611, (3596-3851):13612-13867, (IND):13868, (3852-4107):13869-14124, (IND):14125, (4108-4363):14126-14381, (IND):14382, (4364-4619):14383-14638, (IND):14639, (4620-4875):14640-14895, (IND):14896, (4876-5131):14897-15152, (IND):15153, (5132-5387):15154-15409, (IND):15410, (5388-5643):15411-15666, (IND):15667, (5644-5899):15668-15923, (IND):15924, (5900-6155):15925-16180, (IND):16181, (6156-6411):16182-16437, (IND):16438, (6412-6667):16439-16694, (IND):16695, (6668-6923):16696-16951, (IND):16952, (6924-7179):16953-17208, (IND):17209, (7180-7435):17210-17465, (IND):17466, (7436-7691):17467-17722, (IND):17723, (7692-7947):17724-17979, (IND):17980, (7948-8203):17981-18236, (IND):18237, (8204-8459):18238-18493, (IND):18494, (8460-8715):18495-18750, (IND):18751, (8716-8971):18752-19007, (IND):19008, (8972-9227):19009-19264, (IND):19265, (9228-9483):19266-19521, (IND):19522, (9484-9739):19523-19778, (IND):19779, (9740-9995):19780-20035, (IND):20036, (9996-9999):20037-20040 ++TOTAL: 10041 ++ ++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 ++Free blocks count wrong for group #0 (6841, counted=6840). ++Fix? yes ++ ++Free blocks count wrong for group #1 (1551, counted=1550). ++Fix? yes ++ ++Free blocks count wrong (53116, counted=53114). ++Fix? yes ++ ++ ++test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** ++test_filesys: 13/4096 files (7.7% non-contiguous), 12422/65536 blocks ++Exit status is 1 +--- /dev/null ++++ b/tests/d_fallocate_blkmap/name +@@ -0,0 +1 @@ ++fallocate sparse files and big files on a blockmap fs +--- /dev/null ++++ b/tests/d_fallocate_blkmap/script +@@ -0,0 +1,85 @@ ++if test -x $DEBUGFS_EXE; then ++ ++FSCK_OPT=-fy ++OUT=$test_name.log ++if [ -f $test_dir/expect.gz ]; then ++ EXP=$test_name.tmp ++ gunzip < $test_dir/expect.gz > $EXP1 ++else ++ EXP=$test_dir/expect ++fi ++ ++cp /dev/null $OUT ++ ++cat > $TMPFILE.conf << ENDL ++[fs_types] ++ext4 = { ++ base_features = sparse_super,filetype,resize_inode,dir_index,ext_attr,^has_journal,^extent,huge_file,flex_bg,uninit_bg,dir_nlink,extra_isize,^64bit ++ blocksize = 1024 ++ inode_size = 256 ++ inode_ratio = 16384 ++} ++ENDL ++MKE2FS_CONFIG=$TMPFILE.conf $MKE2FS -F -o Linux -b 1024 -O ^bigalloc -T ext4 $TMPFILE 65536 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT 2>&1 ++rm -rf $TMPFILE.conf ++ ++$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 ++status=$? ++echo Exit status is $status >> $OUT.new ++sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT ++rm -f $OUT.new ++ ++echo "debugfs write files" >> $OUT ++ ++#Files we create: ++# a: fallocate a 40k file ++# k: one big file ++base=5000 ++cat > $TMPFILE.cmd << ENDL ++write /dev/null a ++sif /a bmap[2] 8000 ++sif /a size 40960 ++sif /a i_blocks 2 ++setb 8000 ++fallocate /a 0 39 ++ ++write /dev/null b ++sif /b size 10240000 ++sif /b bmap[0] 10000 ++sif /b i_blocks 2 ++setb 10000 ++fallocate /b 0 9999 ++ENDL ++echo "stat /a" >> $TMPFILE.cmd2 ++echo "stat /b" >> $TMPFILE.cmd2 ++ ++$DEBUGFS_EXE -w -f $TMPFILE.cmd $TMPFILE > /dev/null 2>&1 ++$DEBUGFS_EXE -f $TMPFILE.cmd2 $TMPFILE >> $OUT.new 2>&1 ++sed -f $cmd_dir/filter.sed -e '/^.*time:.*$/d' < $OUT.new >> $OUT ++rm -rf $OUT.new $TMPFILE.cmd $TMPFILE.cmd2 ++ ++$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 ++status=$? ++echo Exit status is $status >> $OUT.new ++sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT ++rm -f $OUT.new ++ ++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 IMAGE FSCK_OPT OUT EXP ++ ++else #if test -x $DEBUGFS_EXE; then ++ echo "$test_name: $test_description: skipped" ++fi +--- /dev/null ++++ b/tests/d_inline_dump/expect +@@ -0,0 +1,95 @@ ++*** long file ++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 ++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 ++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 ++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 ++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 ++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 +--- /dev/null ++++ b/tests/d_inline_dump/name +@@ -0,0 +1 @@ ++debugfs dump inline data test +--- /dev/null ++++ b/tests/d_inline_dump/script +@@ -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 2>&1 | $CLEAN_OUTPUT >> $OUT 2>&1 ++echo "*** short file" >> $OUT ++$DEBUGFS -R 'stat /shortfile' $TMPFILE 2>&1 | $CLEAN_OUTPUT >> $OUT 2>&1 ++echo >> $OUT ++ ++echo "*** long dir" >> $OUT ++$DEBUGFS -R 'stat /dir' $TMPFILE 2>&1 | $CLEAN_OUTPUT >> $OUT 2>&1 ++echo "*** short dir" >> $OUT ++$DEBUGFS -R 'stat /shortdir' $TMPFILE 2>&1 | $CLEAN_OUTPUT >> $OUT 2>&1 ++echo >> $OUT ++ ++echo "*** long link" >> $OUT ++$DEBUGFS -R 'stat /link' $TMPFILE 2>&1 | $CLEAN_OUTPUT >> $OUT 2>&1 ++echo "*** short link" >> $OUT ++$DEBUGFS -R 'stat /shortlink' $TMPFILE 2>&1 | $CLEAN_OUTPUT >> $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 +--- /dev/null ++++ b/tests/d_punch/expect +@@ -0,0 +1,176 @@ ++Creating filesystem with 65536 1k blocks and 4096 inodes ++Superblock backups stored on blocks: ++ 8193, 24577, 40961, 57345 ++ ++Allocating group tables: done ++Writing inode tables: done ++Writing superblocks and filesystem accounting information: done ++ ++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/4096 files (0.0% non-contiguous), 2345/65536 blocks ++Exit status is 0 ++debugfs write files ++debugfs: ex /a ++Level Entries Logical Physical Length Flags ++debugfs: ex /sample ++Level Entries Logical Physical Length Flags ++ 0/ 1 1/ 1 0 - 4294967295 1323 0 ++ 1/ 1 1/ 5 0 - 9 1313 - 1322 10 Uninit ++ 1/ 1 2/ 5 11 - 12 1324 - 1325 2 Uninit ++ 1/ 1 3/ 5 14 - 25 1327 - 1338 12 Uninit ++ 1/ 1 4/ 5 27 - 28 1340 - 1341 2 Uninit ++ 1/ 1 5/ 5 30 - 39 1343 - 1352 10 Uninit ++debugfs: ex /b8 ++Level Entries Logical Physical Length Flags ++ 0/ 1 1/ 1 0 - 4294967295 1390 0 ++ 1/ 1 1/ 4 0 - 0 1326 - 1326 1 Uninit ++ 1/ 1 2/ 4 1 - 1 1339 - 1339 1 Uninit ++ 1/ 1 3/ 4 2 - 2 1342 - 1342 1 Uninit ++ 1/ 1 4/ 4 3 - 7 1353 - 1357 5 Uninit ++debugfs: ex /b9 ++Level Entries Logical Physical Length Flags ++ 0/ 1 1/ 1 0 - 4294967295 1368 0 ++ 1/ 1 1/ 1 0 - 8 1358 - 1366 9 Uninit ++debugfs: ex /b10 ++Level Entries Logical Physical Length Flags ++ 0/ 1 1/ 1 0 - 4294967295 1378 0 ++ 1/ 1 1/ 2 0 - 0 1367 - 1367 1 Uninit ++ 1/ 1 2/ 2 1 - 9 1369 - 1377 9 Uninit ++debugfs: ex /b11 ++Level Entries Logical Physical Length Flags ++ 0/ 1 1/ 1 0 - 4294967295 1389 0 ++ 1/ 1 1/ 1 0 - 9 1379 - 1388 10 Uninit ++debugfs: ex /b12 ++Level Entries Logical Physical Length Flags ++ 0/ 1 1/ 1 0 - 4294967295 1401 0 ++ 1/ 1 1/ 2 0 - 9 1391 - 1400 10 Uninit ++ 1/ 1 2/ 2 11 - 11 1402 - 1402 1 Uninit ++debugfs: ex /b13 ++Level Entries Logical Physical Length Flags ++ 0/ 1 1/ 1 0 - 4294967295 1413 0 ++ 1/ 1 1/ 2 0 - 9 1403 - 1412 10 Uninit ++ 1/ 1 2/ 2 11 - 12 1414 - 1415 2 Uninit ++debugfs: ex /b14 ++Level Entries Logical Physical Length Flags ++ 0/ 1 1/ 1 0 - 4294967295 1426 0 ++ 1/ 1 1/ 2 0 - 9 1416 - 1425 10 Uninit ++ 1/ 1 2/ 2 11 - 12 1427 - 1428 2 Uninit ++debugfs: ex /b15 ++Level Entries Logical Physical Length Flags ++ 0/ 1 1/ 1 0 - 4294967295 1439 0 ++ 1/ 1 1/ 3 0 - 9 1429 - 1438 10 Uninit ++ 1/ 1 2/ 3 11 - 12 1440 - 1441 2 Uninit ++ 1/ 1 3/ 3 14 - 14 1443 - 1443 1 Uninit ++debugfs: ex /c24 ++Level Entries Logical Physical Length Flags ++ 0/ 1 1/ 1 25 - 4294967295 1453 4294967271 ++ 1/ 1 1/ 3 25 - 25 1468 - 1468 1 Uninit ++ 1/ 1 2/ 3 27 - 28 1470 - 1471 2 Uninit ++ 1/ 1 3/ 3 30 - 39 1473 - 1482 10 Uninit ++debugfs: ex /c25 ++Level Entries Logical Physical Length Flags ++ 0/ 1 1/ 1 27 - 4294967295 1483 4294967269 ++ 1/ 1 1/ 2 27 - 28 1485 - 1486 2 Uninit ++ 1/ 1 2/ 2 30 - 39 1488 - 1497 10 Uninit ++debugfs: ex /c26 ++Level Entries Logical Physical Length Flags ++ 0/ 1 1/ 1 27 - 4294967295 1484 4294967269 ++ 1/ 1 1/ 2 27 - 28 1498 - 1499 2 Uninit ++ 1/ 1 2/ 2 30 - 39 1501 - 1510 10 Uninit ++debugfs: ex /c27 ++Level Entries Logical Physical Length Flags ++ 0/ 1 1/ 1 28 - 4294967295 1487 4294967268 ++ 1/ 1 1/ 2 28 - 28 1512 - 1512 1 Uninit ++ 1/ 1 2/ 2 30 - 39 1514 - 1523 10 Uninit ++debugfs: ex /c28 ++Level Entries Logical Physical Length Flags ++ 0/ 1 1/ 1 30 - 4294967295 1500 4294967266 ++ 1/ 1 1/ 1 30 - 39 1526 - 1535 10 Uninit ++debugfs: ex /c29 ++Level Entries Logical Physical Length Flags ++ 0/ 1 1/ 1 30 - 4294967295 1511 4294967266 ++ 1/ 1 1/ 1 30 - 39 1537 - 1546 10 Uninit ++debugfs: ex /c30 ++Level Entries Logical Physical Length Flags ++ 0/ 1 1/ 1 31 - 4294967295 1513 4294967265 ++ 1/ 1 1/ 1 31 - 39 1549 - 1557 9 Uninit ++debugfs: ex /c31 ++Level Entries Logical Physical Length Flags ++ 0/ 1 1/ 1 32 - 4294967295 1524 4294967264 ++ 1/ 1 1/ 1 32 - 39 1560 - 1567 8 Uninit ++debugfs: ex /d ++Level Entries Logical Physical Length Flags ++ 0/ 1 1/ 1 0 - 4294967295 1525 0 ++ 1/ 1 1/ 3 0 - 0 1442 - 1442 1 Uninit ++ 1/ 1 2/ 3 1 - 3 1444 - 1446 3 Uninit ++ 1/ 1 3/ 3 36 - 39 1573 - 1576 4 Uninit ++debugfs: ex /e ++Level Entries Logical Physical Length Flags ++ 0/ 1 1/ 1 0 - 4294967295 1547 0 ++ 1/ 1 1/ 11 0 - 5 1447 - 1452 6 Uninit ++ 1/ 1 2/ 11 6 - 9 1454 - 1457 4 Uninit ++ 1/ 1 3/ 11 11 - 12 1459 - 1460 2 Uninit ++ 1/ 1 4/ 11 14 - 18 1462 - 1466 5 Uninit ++ 1/ 1 5/ 11 21 - 21 1472 - 1472 1 Uninit ++ 1/ 1 6/ 11 22 - 22 1536 - 1536 1 Uninit ++ 1/ 1 7/ 11 23 - 23 1548 - 1548 1 Uninit ++ 1/ 1 8/ 11 24 - 25 1558 - 1559 2 Uninit ++ 1/ 1 9/ 11 27 - 28 1569 - 1570 2 Uninit ++ 1/ 1 10/ 11 30 - 30 1572 - 1572 1 Uninit ++ 1/ 1 11/ 11 31 - 39 1577 - 1585 9 Uninit ++debugfs: ex /f ++Level Entries Logical Physical Length Flags ++ 0/ 0 1/ 2 0 - 0 9000 - 9000 1 Uninit ++ 0/ 0 2/ 2 8999 - 8999 17999 - 17999 1 Uninit ++Pass 1: Checking inodes, blocks, and sizes ++Inode 15 extent tree (at level 1) could be shorter. Fix? yes ++ ++Inode 16 extent tree (at level 1) could be shorter. Fix? yes ++ ++Inode 17 extent tree (at level 1) could be shorter. Fix? yes ++ ++Inode 18 extent tree (at level 1) could be shorter. Fix? yes ++ ++Inode 19 extent tree (at level 1) could be shorter. Fix? yes ++ ++Inode 20 extent tree (at level 1) could be shorter. Fix? yes ++ ++Inode 21 extent tree (at level 1) could be shorter. Fix? yes ++ ++Inode 22 extent tree (at level 1) could be shorter. Fix? yes ++ ++Inode 23 extent tree (at level 1) could be shorter. Fix? yes ++ ++Inode 24 extent tree (at level 1) could be shorter. Fix? yes ++ ++Inode 25 extent tree (at level 1) could be shorter. Fix? yes ++ ++Inode 26 extent tree (at level 1) could be shorter. Fix? yes ++ ++Inode 27 extent tree (at level 1) could be shorter. Fix? yes ++ ++Inode 28 extent tree (at level 1) could be shorter. Fix? yes ++ ++Inode 29 extent tree (at level 1) could be shorter. Fix? yes ++ ++Inode 30 extent tree (at level 1) could be shorter. Fix? yes ++ ++Pass 1E: Optimizing extent trees ++Pass 2: Checking directory structure ++Pass 3: Checking directory connectivity ++Pass 4: Checking reference counts ++Pass 5: Checking group summary information ++Free blocks count wrong for group #1 (7934, counted=7933). ++Fix? yes ++ ++Free blocks count wrong (62939, counted=62938). ++Fix? yes ++ ++ ++test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** ++test_filesys: 32/4096 files (43.8% non-contiguous), 2598/65536 blocks ++Exit status is 1 +--- /dev/null ++++ b/tests/d_punch/name +@@ -0,0 +1 @@ ++punch sparse files and big files +--- /dev/null ++++ b/tests/d_punch/script +@@ -0,0 +1,129 @@ ++if test -x $DEBUGFS_EXE; then ++ ++FSCK_OPT=-fy ++OUT=$test_name.log ++if [ -f $test_dir/expect.gz ]; then ++ EXP=$test_name.tmp ++ gunzip < $test_dir/expect.gz > $EXP1 ++else ++ EXP=$test_dir/expect ++fi ++ ++cp /dev/null $OUT ++ ++cat > $TMPFILE.conf << ENDL ++[fs_types] ++ext4 = { ++ base_features = sparse_super,filetype,resize_inode,dir_index,ext_attr,^has_journal,extent,huge_file,flex_bg,uninit_bg,dir_nlink,extra_isize,64bit ++ blocksize = 1024 ++ inode_size = 256 ++ inode_ratio = 16384 ++} ++ENDL ++MKE2FS_CONFIG=$TMPFILE.conf $MKE2FS -F -o Linux -b 1024 -O ^bigalloc -T ext4 $TMPFILE 65536 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT 2>&1 ++rm -rf $TMPFILE.conf ++ ++$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 ++status=$? ++echo Exit status is $status >> $OUT.new ++sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT ++rm -f $OUT.new ++ ++echo "debugfs write files" >> $OUT ++make_file() { ++ name="$1" ++ start="$2" ++ flag="$3" ++ ++ cat << ENDL ++write /dev/null $name ++fallocate /$name 0 39 ++punch /$name 10 10 ++punch /$name 13 13 ++punch /$name 26 26 ++punch /$name 29 29 ++ENDL ++} ++ ++#Files we create: ++# a: punch a 40k file ++# b*: punch sparse file starting at b* ++# c*: punch spare file ending at c* ++# d: midcluster to midcluster, surrounding sparse ++# e: partial middle cluster alloc ++# f: one big file ++base=5000 ++cat > $TMPFILE.cmd << ENDL ++write /dev/null a ++fallocate /a 0 39 ++punch /a 0 39 ++ENDL ++echo "ex /a" >> $TMPFILE.cmd2 ++ ++make_file sample $base --uninit >> $TMPFILE.cmd ++echo "ex /sample" >> $TMPFILE.cmd2 ++base=10000 ++ ++for i in 8 9 10 11 12 13 14 15; do ++ make_file b$i $(($base + (40 * ($i - 8)))) --uninit >> $TMPFILE.cmd ++ echo "punch /b$i $i 39" >> $TMPFILE.cmd ++ echo "ex /b$i" >> $TMPFILE.cmd2 ++done ++ ++for i in 24 25 26 27 28 29 30 31; do ++ make_file c$i $(($base + 320 + (40 * ($i - 24)))) --uninit >> $TMPFILE.cmd ++ echo "punch /c$i 0 $i" >> $TMPFILE.cmd ++ echo "ex /c$i" >> $TMPFILE.cmd2 ++done ++ ++make_file d $(($base + 640)) --uninit >> $TMPFILE.cmd ++echo "punch /d 4 35" >> $TMPFILE.cmd ++echo "ex /d" >> $TMPFILE.cmd2 ++ ++make_file e $(($base + 680)) --uninit >> $TMPFILE.cmd ++echo "punch /e 19 20" >> $TMPFILE.cmd ++echo "ex /e" >> $TMPFILE.cmd2 ++ ++cat >> $TMPFILE.cmd << ENDL ++write /dev/null f ++sif /f size 1024 ++eo /f ++set_bmap --uninit 0 9000 ++ec ++sif /f blocks 2 ++setb 9000 ++fallocate /f 0 8999 ++punch /f 1 8998 ++ENDL ++echo "ex /f" >> $TMPFILE.cmd2 ++ ++$DEBUGFS_EXE -w -f $TMPFILE.cmd $TMPFILE > /dev/null 2>&1 ++$DEBUGFS_EXE -f $TMPFILE.cmd2 $TMPFILE >> $OUT.new 2>&1 ++sed -f $cmd_dir/filter.sed < $OUT.new >> $OUT ++rm -rf $OUT.new $TMPFILE.cmd $TMPFILE.cmd2 ++ ++$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 ++status=$? ++echo Exit status is $status >> $OUT.new ++sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT ++rm -f $OUT.new ++ ++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 IMAGE FSCK_OPT OUT EXP ++ ++else #if test -x $DEBUGFS_EXE; then ++ echo "$test_name: $test_description: skipped" ++fi +--- /dev/null ++++ b/tests/d_punch_bigalloc/expect +@@ -0,0 +1,175 @@ ++ ++Warning: the bigalloc feature is still under development ++See https://ext4.wiki.kernel.org/index.php/Bigalloc for more information ++ ++Creating filesystem with 65536 1k blocks and 4096 inodes ++ ++Allocating group tables: done ++Writing inode tables: done ++Writing superblocks and filesystem accounting information: done ++ ++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/4096 files (9.1% non-contiguous), 1144/65536 blocks ++Exit status is 0 ++debugfs write files ++debugfs: ex /a ++Level Entries Logical Physical Length Flags ++debugfs: ex /sample ++Level Entries Logical Physical Length Flags ++ 0/ 1 1/ 1 0 - 4294967295 1184 0 ++ 1/ 1 1/ 5 0 - 9 1144 - 1153 10 Uninit ++ 1/ 1 2/ 5 11 - 12 1155 - 1156 2 Uninit ++ 1/ 1 3/ 5 14 - 25 1158 - 1169 12 Uninit ++ 1/ 1 4/ 5 27 - 28 1171 - 1172 2 Uninit ++ 1/ 1 5/ 5 30 - 39 1174 - 1183 10 Uninit ++debugfs: ex /b8 ++Level Entries Logical Physical Length Flags ++ 0/ 1 1/ 1 0 - 4294967295 1232 0 ++ 1/ 1 1/ 1 0 - 7 1192 - 1199 8 Uninit ++debugfs: ex /b9 ++Level Entries Logical Physical Length Flags ++ 0/ 1 1/ 1 0 - 4294967295 1248 0 ++ 1/ 1 1/ 1 0 - 8 1200 - 1208 9 Uninit ++debugfs: ex /b10 ++Level Entries Logical Physical Length Flags ++ 0/ 1 1/ 1 0 - 4294967295 1272 0 ++ 1/ 1 1/ 1 0 - 9 1216 - 1225 10 Uninit ++debugfs: ex /b11 ++Level Entries Logical Physical Length Flags ++ 0/ 1 1/ 1 0 - 4294967295 1296 0 ++ 1/ 1 1/ 2 0 - 7 1240 - 1247 8 Uninit ++ 1/ 1 2/ 2 8 - 9 1256 - 1257 2 Uninit ++debugfs: ex /b12 ++Level Entries Logical Physical Length Flags ++ 0/ 1 1/ 1 0 - 4294967295 1320 0 ++ 1/ 1 1/ 3 0 - 7 1264 - 1271 8 Uninit ++ 1/ 1 2/ 3 8 - 9 1280 - 1281 2 Uninit ++ 1/ 1 3/ 3 11 - 11 1283 - 1283 1 Uninit ++debugfs: ex /b13 ++Level Entries Logical Physical Length Flags ++ 0/ 1 1/ 1 0 - 4294967295 1344 0 ++ 1/ 1 1/ 3 0 - 7 1288 - 1295 8 Uninit ++ 1/ 1 2/ 3 8 - 9 1304 - 1305 2 Uninit ++ 1/ 1 3/ 3 11 - 12 1307 - 1308 2 Uninit ++debugfs: ex /b14 ++Level Entries Logical Physical Length Flags ++ 0/ 1 1/ 1 0 - 4294967295 1368 0 ++ 1/ 1 1/ 3 0 - 7 1312 - 1319 8 Uninit ++ 1/ 1 2/ 3 8 - 9 1328 - 1329 2 Uninit ++ 1/ 1 3/ 3 11 - 12 1331 - 1332 2 Uninit ++debugfs: ex /b15 ++Level Entries Logical Physical Length Flags ++ 0/ 1 1/ 1 0 - 4294967295 1392 0 ++ 1/ 1 1/ 4 0 - 7 1336 - 1343 8 Uninit ++ 1/ 1 2/ 4 8 - 9 1352 - 1353 2 Uninit ++ 1/ 1 3/ 4 11 - 12 1355 - 1356 2 Uninit ++ 1/ 1 4/ 4 14 - 14 1358 - 1358 1 Uninit ++debugfs: ex /c24 ++Level Entries Logical Physical Length Flags ++ 0/ 1 1/ 1 25 - 4294967295 1416 4294967271 ++ 1/ 1 1/ 3 25 - 25 1401 - 1401 1 Uninit ++ 1/ 1 2/ 3 27 - 28 1403 - 1404 2 Uninit ++ 1/ 1 3/ 3 30 - 39 1406 - 1415 10 Uninit ++debugfs: ex /c25 ++Level Entries Logical Physical Length Flags ++ 0/ 1 1/ 1 27 - 4294967295 1440 4294967269 ++ 1/ 1 1/ 2 27 - 28 1427 - 1428 2 Uninit ++ 1/ 1 2/ 2 30 - 39 1430 - 1439 10 Uninit ++debugfs: ex /c26 ++Level Entries Logical Physical Length Flags ++ 0/ 1 1/ 1 27 - 4294967295 1464 4294967269 ++ 1/ 1 1/ 2 27 - 28 1451 - 1452 2 Uninit ++ 1/ 1 2/ 2 30 - 39 1454 - 1463 10 Uninit ++debugfs: ex /c27 ++Level Entries Logical Physical Length Flags ++ 0/ 1 1/ 1 28 - 4294967295 1488 4294967268 ++ 1/ 1 1/ 2 28 - 28 1476 - 1476 1 Uninit ++ 1/ 1 2/ 2 30 - 39 1478 - 1487 10 Uninit ++debugfs: ex /c28 ++Level Entries Logical Physical Length Flags ++ 0/ 1 1/ 1 30 - 4294967295 1512 4294967266 ++ 1/ 1 1/ 1 30 - 39 1502 - 1511 10 Uninit ++debugfs: ex /c29 ++Level Entries Logical Physical Length Flags ++ 0/ 1 1/ 1 30 - 4294967295 1536 4294967266 ++ 1/ 1 1/ 1 30 - 39 1526 - 1535 10 Uninit ++debugfs: ex /c30 ++Level Entries Logical Physical Length Flags ++ 0/ 1 1/ 1 31 - 4294967295 1560 4294967265 ++ 1/ 1 1/ 1 31 - 39 1551 - 1559 9 Uninit ++debugfs: ex /c31 ++Level Entries Logical Physical Length Flags ++ 0/ 1 1/ 1 32 - 4294967295 1584 4294967264 ++ 1/ 1 1/ 1 32 - 39 1576 - 1583 8 Uninit ++debugfs: ex /d ++Level Entries Logical Physical Length Flags ++ 0/ 1 1/ 1 0 - 4294967295 1600 0 ++ 1/ 1 1/ 2 0 - 3 1360 - 1363 4 Uninit ++ 1/ 1 2/ 2 36 - 39 1596 - 1599 4 Uninit ++debugfs: ex /e ++Level Entries Logical Physical Length Flags ++ 0/ 1 1/ 1 0 - 4294967295 1624 0 ++ 1/ 1 1/ 8 0 - 9 1376 - 1385 10 Uninit ++ 1/ 1 2/ 8 11 - 12 1387 - 1388 2 Uninit ++ 1/ 1 3/ 8 14 - 15 1390 - 1391 2 Uninit ++ 1/ 1 4/ 8 16 - 18 1568 - 1570 3 Uninit ++ 1/ 1 5/ 8 21 - 23 1573 - 1575 3 Uninit ++ 1/ 1 6/ 8 24 - 25 1608 - 1609 2 Uninit ++ 1/ 1 7/ 8 27 - 28 1611 - 1612 2 Uninit ++ 1/ 1 8/ 8 30 - 39 1614 - 1623 10 Uninit ++debugfs: ex /f ++Level Entries Logical Physical Length Flags ++ 0/ 0 1/ 2 0 - 0 9000 - 9000 1 Uninit ++ 0/ 0 2/ 2 8999 - 8999 17999 - 17999 1 Uninit ++Pass 1: Checking inodes, blocks, and sizes ++Inode 14 extent tree (at level 1) could be shorter. Fix? yes ++ ++Inode 15 extent tree (at level 1) could be shorter. Fix? yes ++ ++Inode 16 extent tree (at level 1) could be shorter. Fix? yes ++ ++Inode 17 extent tree (at level 1) could be shorter. Fix? yes ++ ++Inode 18 extent tree (at level 1) could be shorter. Fix? yes ++ ++Inode 19 extent tree (at level 1) could be shorter. Fix? yes ++ ++Inode 20 extent tree (at level 1) could be shorter. Fix? yes ++ ++Inode 22 extent tree (at level 1) could be shorter. Fix? yes ++ ++Inode 23 extent tree (at level 1) could be shorter. Fix? yes ++ ++Inode 24 extent tree (at level 1) could be shorter. Fix? yes ++ ++Inode 25 extent tree (at level 1) could be shorter. Fix? yes ++ ++Inode 26 extent tree (at level 1) could be shorter. Fix? yes ++ ++Inode 27 extent tree (at level 1) could be shorter. Fix? yes ++ ++Inode 28 extent tree (at level 1) could be shorter. Fix? yes ++ ++Inode 29 extent tree (at level 1) could be shorter. Fix? yes ++ ++Inode 30 extent tree (at level 1) could be shorter. Fix? yes ++ ++Pass 1E: Optimizing extent trees ++Pass 2: Checking directory structure ++Pass 3: Checking directory connectivity ++Pass 4: Checking reference counts ++Pass 5: Checking group summary information ++Free blocks count wrong for group #0 (8003, counted=8002). ++Fix? yes ++ ++Free blocks count wrong (64024, counted=64016). ++Fix? yes ++ ++ ++test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** ++test_filesys: 32/4096 files (43.8% non-contiguous), 1520/65536 blocks ++Exit status is 1 +--- /dev/null ++++ b/tests/d_punch_bigalloc/name +@@ -0,0 +1 @@ ++punch sparse files and big files with bigalloc +--- /dev/null ++++ b/tests/d_punch_bigalloc/script +@@ -0,0 +1,130 @@ ++if test -x $DEBUGFS_EXE; then ++ ++FSCK_OPT=-fy ++OUT=$test_name.log ++if [ -f $test_dir/expect.gz ]; then ++ EXP=$test_name.tmp ++ gunzip < $test_dir/expect.gz > $EXP1 ++else ++ EXP=$test_dir/expect ++fi ++ ++cp /dev/null $OUT ++ ++cat > $TMPFILE.conf << ENDL ++[fs_types] ++ext4 = { ++ cluster_size = 8192 ++ base_features = sparse_super,filetype,resize_inode,dir_index,ext_attr,^has_journal,extent,huge_file,flex_bg,uninit_bg,dir_nlink,extra_isize,64bit ++ blocksize = 1024 ++ inode_size = 256 ++ inode_ratio = 16384 ++} ++ENDL ++MKE2FS_CONFIG=$TMPFILE.conf $MKE2FS -F -o Linux -b 1024 -O bigalloc -T ext4 $TMPFILE 65536 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT 2>&1 ++rm -rf $TMPFILE.conf ++ ++$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 ++status=$? ++echo Exit status is $status >> $OUT.new ++sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT ++rm -f $OUT.new ++ ++echo "debugfs write files" >> $OUT ++make_file() { ++ name="$1" ++ start="$2" ++ flag="$3" ++ ++ cat << ENDL ++write /dev/null $name ++fallocate /$name 0 39 ++punch /$name 10 10 ++punch /$name 13 13 ++punch /$name 26 26 ++punch /$name 29 29 ++ENDL ++} ++ ++#Files we create: ++# a: punch a 40k file ++# b*: punch sparse file starting at b* ++# c*: punch spare file ending at c* ++# d: midcluster to midcluster, surrounding sparse ++# e: partial middle cluster alloc ++# f: one big file ++base=5000 ++cat > $TMPFILE.cmd << ENDL ++write /dev/null a ++fallocate /a 0 39 ++punch /a 0 39 ++ENDL ++echo "ex /a" >> $TMPFILE.cmd2 ++ ++make_file sample $base --uninit >> $TMPFILE.cmd ++echo "ex /sample" >> $TMPFILE.cmd2 ++base=10000 ++ ++for i in 8 9 10 11 12 13 14 15; do ++ make_file b$i $(($base + (40 * ($i - 8)))) --uninit >> $TMPFILE.cmd ++ echo "punch /b$i $i 39" >> $TMPFILE.cmd ++ echo "ex /b$i" >> $TMPFILE.cmd2 ++done ++ ++for i in 24 25 26 27 28 29 30 31; do ++ make_file c$i $(($base + 320 + (40 * ($i - 24)))) --uninit >> $TMPFILE.cmd ++ echo "punch /c$i 0 $i" >> $TMPFILE.cmd ++ echo "ex /c$i" >> $TMPFILE.cmd2 ++done ++ ++make_file d $(($base + 640)) --uninit >> $TMPFILE.cmd ++echo "punch /d 4 35" >> $TMPFILE.cmd ++echo "ex /d" >> $TMPFILE.cmd2 ++ ++make_file e $(($base + 680)) --uninit >> $TMPFILE.cmd ++echo "punch /e 19 20" >> $TMPFILE.cmd ++echo "ex /e" >> $TMPFILE.cmd2 ++ ++cat >> $TMPFILE.cmd << ENDL ++write /dev/null f ++sif /f size 1024 ++eo /f ++set_bmap --uninit 0 9000 ++ec ++sif /f blocks 16 ++setb 9000 ++fallocate /f 0 8999 ++punch /f 1 8998 ++ENDL ++echo "ex /f" >> $TMPFILE.cmd2 ++ ++$DEBUGFS_EXE -w -f $TMPFILE.cmd $TMPFILE > /dev/null 2>&1 ++$DEBUGFS_EXE -f $TMPFILE.cmd2 $TMPFILE >> $OUT.new 2>&1 ++sed -f $cmd_dir/filter.sed < $OUT.new >> $OUT ++rm -rf $OUT.new $TMPFILE.cmd $TMPFILE.cmd2 ++ ++$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 ++status=$? ++echo Exit status is $status >> $OUT.new ++sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT ++rm -f $OUT.new ++ ++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 IMAGE FSCK_OPT OUT EXP ++ ++else #if test -x $DEBUGFS_EXE; then ++ echo "$test_name: $test_description: skipped" ++fi +--- a/tests/d_special_files/expect ++++ b/tests/d_special_files/expect +@@ -11,7 +11,7 @@ + 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 +--- /dev/null ++++ b/tests/d_xattr_edits/expect +@@ -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 -f d_xattr_edits.tmp / user.file_based_xattr ++Exit status is 0 ++ea_list / ++Extended attributes: ++ user.file_based_xattr = "12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567\012" (108) ++Exit status is 0 ++ea_get -f d_xattr_edits.ver.tmp / user.file_based_xattr ++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 +--- /dev/null ++++ b/tests/d_xattr_edits/name +@@ -0,0 +1 @@ ++edit extended attributes in debugfs +--- /dev/null ++++ b/tests/d_xattr_edits/script +@@ -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 -R "ea_set / user.joe smith" $TMPFILE >> $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 -R "ea_set / user.moo FEE_FIE_FOE_FUMMMMMM" $TMPFILE >> $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 -R "ea_list /" $TMPFILE >> $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 -R "ea_get / user.moo" $TMPFILE >> $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 -R "ea_get / nosuchea" $TMPFILE >> $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 -R "ea_rm / user.moo" $TMPFILE >> $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 -R "ea_rm / nosuchea" $TMPFILE >> $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 -R "ea_list /" $TMPFILE >> $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 -R "ea_get / user.moo" $TMPFILE >> $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 -R "ea_rm / user.joe" $TMPFILE >> $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 -R "ea_list /" $TMPFILE >> $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 -f $TEST_DATA / user.file_based_xattr" > $OUT.new ++$DEBUGFS -w -R "ea_set -f $TEST_DATA / user.file_based_xattr" $TMPFILE >> $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 -R "ea_list /" $TMPFILE >> $OUT.new 2>&1 ++status=$? ++echo Exit status is $status >> $OUT.new ++sed -f $cmd_dir/filter.sed $OUT.new >> $OUT ++ ++echo "ea_get -f $VERIFY_DATA / user.file_based_xattr" > $OUT.new ++$DEBUGFS -w -R "ea_get -f $VERIFY_DATA / user.file_based_xattr" $TMPFILE >> $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 +--- /dev/null ++++ b/tests/f_bad_bbitmap/expect.1 +@@ -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 +--- /dev/null ++++ b/tests/f_bad_bbitmap/expect.2 +@@ -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 +--- /dev/null ++++ b/tests/f_bad_bbitmap/name +@@ -0,0 +1 @@ ++corrupt block bitmap (metadata_csum) +--- /dev/null ++++ b/tests/f_bad_bmap_csum/expect.1 +@@ -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 +--- /dev/null ++++ b/tests/f_bad_bmap_csum/expect.2 +@@ -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 +--- /dev/null ++++ b/tests/f_bad_bmap_csum/name +@@ -0,0 +1 @@ ++bad block/inode bitmap csum (metadata_csum) +--- a/tests/f_badcluster/expect ++++ b/tests/f_badcluster/expect +@@ -19,12 +19,14 @@ + Will fix in pass 1B. + Inode 18, i_blocks is 32, should be 64. Fix? yes + ++Inode 15 on bigalloc filesystem cannot be block mapped. 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 +@@ -65,19 +67,20 @@ + has 1 multiply-claimed block(s), shared with 0 file(s): + Clone multiply-claimed blocks? yes + ++Pass 1E: Optimizing extent trees + Pass 2: Checking directory structure + Pass 3: Checking directory connectivity + Pass 4: Checking reference counts + Pass 5: Checking group summary information +-Free blocks count wrong for group #0 (50, counted=47). ++Free blocks count wrong for group #0 (51, counted=48). + Fix? yes + +-Free blocks count wrong (800, counted=752). ++Free blocks count wrong (816, counted=768). + Fix? yes + + + test_fs: ***** FILE SYSTEM WAS MODIFIED ***** +-test_fs: 18/128 files (22.2% non-contiguous), 1296/2048 blocks ++test_fs: 18/128 files (22.2% non-contiguous), 1280/2048 blocks + Pass 1: Checking inodes, blocks, and sizes + Inode 12, i_blocks is 64, should be 32. Fix? yes + +@@ -94,21 +97,21 @@ + Block bitmap differences: -(1168--1200) + Fix? yes + +-Free blocks count wrong for group #0 (47, counted=50). ++Free blocks count wrong for group #0 (48, counted=51). + Fix? yes + +-Free blocks count wrong (752, counted=800). ++Free blocks count wrong (768, counted=816). + Fix? yes + + + test_fs: ***** FILE SYSTEM WAS MODIFIED ***** +-test_fs: 18/128 files (5.6% non-contiguous), 1248/2048 blocks ++test_fs: 18/128 files (5.6% non-contiguous), 1232/2048 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 +-test_fs: 18/128 files (5.6% non-contiguous), 1248/2048 blocks ++test_fs: 18/128 files (5.6% non-contiguous), 1232/2048 blocks + debugfs: stat /a + Inode: 12 Type: regular Mode: 0644 Flags: 0x80000 + Generation: 1117152157 Version: 0x00000001 +@@ -146,19 +149,16 @@ + EXTENTS: + (0-1):1216-1217, (2):1218 + debugfs: stat /d +-Inode: 15 Type: regular Mode: 0644 Flags: 0x0 ++Inode: 15 Type: regular Mode: 0644 Flags: 0x80000 + Generation: 1117152160 Version: 0x00000001 + User: 0 Group: 0 Size: 3072 + File ACL: 0 Directory ACL: 0 +-Links: 1 Blockcount: 32 ++Links: 1 Blockcount: 0 + Fragment: Address: 0 Number: 0 Size: 0 + ctime: 0x539ff5b2 -- Tue Jun 17 08:00:50 2014 + atime: 0x539ff5b2 -- Tue Jun 17 08:00:50 2014 + mtime: 0x539ff5b2 -- Tue Jun 17 08:00:50 2014 +-BLOCKS: +-(TIND):1650 +-TOTAL: 1 +- ++EXTENTS: + debugfs: stat /e + Inode: 16 Type: regular Mode: 0644 Flags: 0x80000 + Generation: 1117152161 Version: 0x00000001 +--- a/tests/f_badcluster/script ++++ b/tests/f_badcluster/script +@@ -8,7 +8,7 @@ + $FSCK -fy $TMPFILE 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT + for i in a b c d e f g; do echo "stat /$i"; done > $TMPFILE.tmp + echo "quit" >> $TMPFILE.tmp +- $DEBUGFS_EXE -f $TMPFILE.tmp $TMPFILE >> $OUT ++ $DEBUGFS_EXE -f $TMPFILE.tmp $TMPFILE 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT + rm -f $TMPFILE.tmp + + cmp -s $OUT $EXP +--- a/tests/f_bad_disconnected_inode/expect.1 ++++ b/tests/f_bad_disconnected_inode/expect.1 +@@ -2,10 +2,13 @@ + Inode 1 has EXTENTS_FL flag set on filesystem without extents support. + Clear? yes + +-Inode 15 has EXTENTS_FL flag set on filesystem without extents support. ++Inode 14 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. ++Inode 15 has INLINE_DATA_FL flag on filesystem without inline data support. ++Clear? yes ++ ++Inode 16 has INLINE_DATA_FL flag on filesystem without inline data support. + Clear? yes + + Pass 2: Checking directory structure +@@ -21,12 +24,6 @@ + Inode 13 (...) has invalid mode (0117003). + Clear? yes + +-i_file_acl for inode 14 (...) is 2892851642, should be zero. +-Clear? yes +- +-Inode 14 (...) has invalid mode (0154247). +-Clear? yes +- + Pass 5: Checking group summary information + Block bitmap differences: -(9--19) + Fix? yes +@@ -37,15 +34,9 @@ + Free blocks count wrong (79, counted=91). + Fix? yes + +-Free inodes count wrong for group #0 (6, counted=5). +-Fix? yes +- + Directories count wrong for group #0 (3, counted=2). + Fix? yes + +-Free inodes count wrong (6, counted=5). +-Fix? yes +- + + test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** + test_filesys: 11/16 files (0.0% non-contiguous), 9/100 blocks +--- /dev/null ++++ b/tests/f_bad_gdt_csum/expect.1 +@@ -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 +--- /dev/null ++++ b/tests/f_bad_gdt_csum/expect.2 +@@ -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 +--- /dev/null ++++ b/tests/f_bad_gdt_csum/name +@@ -0,0 +1 @@ ++bad group descriptor csum (metadata_csum) +--- /dev/null ++++ b/tests/f_bad_ibitmap/expect.1 +@@ -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 +--- /dev/null ++++ b/tests/f_bad_ibitmap/expect.2 +@@ -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 +--- /dev/null ++++ b/tests/f_bad_ibitmap/name +@@ -0,0 +1 @@ ++corrupt inode bitmap (metadata_csum) +--- /dev/null ++++ b/tests/f_bad_inode_csum/expect.1 +@@ -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 +--- /dev/null ++++ b/tests/f_bad_inode_csum/expect.2 +@@ -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 +--- /dev/null ++++ b/tests/f_bad_inode_csum/name +@@ -0,0 +1 @@ ++inode table corruption (metadata_csum) +--- a/tests/f_badjourblks/expect.1 ++++ b/tests/f_badjourblks/expect.1 +@@ -1,7 +1,7 @@ + Superblock has an invalid journal (inode 8). + Clear? yes + +-*** ext3 journal has been deleted - filesystem is now ext2 only *** ++*** journal has been deleted *** + + Pass 1: Checking inodes, blocks, and sizes + Journal inode is not in use, but contains data. Clear? yes +@@ -23,7 +23,7 @@ + + Creating journal (1024 blocks): Done. + +-*** journal has been re-created - filesystem is now ext3 again *** ++*** journal has been regenerated *** + + test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** + test_filesys: 11/256 files (0.0% non-contiguous), 1079/8192 blocks +--- a/tests/f_badjour_indblks/expect.1 ++++ b/tests/f_badjour_indblks/expect.1 +@@ -1,7 +1,7 @@ + Superblock has an invalid journal (inode 8). + Clear? yes + +-*** ext3 journal has been deleted - filesystem is now ext2 only *** ++*** journal has been deleted *** + + Adding dirhash hint to filesystem. + +@@ -25,7 +25,7 @@ + + Creating journal (1024 blocks): Done. + +-*** journal has been re-created - filesystem is now ext3 again *** ++*** journal has been regenerated *** + + test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** + test_filesys: 11/256 files (0.0% non-contiguous), 1111/8192 blocks +--- a/tests/f_bbfile/expect.1 ++++ b/tests/f_bbfile/expect.1 +@@ -8,8 +8,8 @@ + 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.) +--- /dev/null ++++ b/tests/f_bb_in_bb/expect.1 +@@ -0,0 +1,17 @@ ++Pass 1: Checking inodes, blocks, and sizes ++Bad block list says the bad block list inode is bad. Clear inode? yes ++ ++Pass 2: Checking directory structure ++Pass 3: Checking directory connectivity ++Pass 4: Checking reference counts ++Pass 5: Checking group summary information ++Free blocks count wrong for group #0 (493, counted=494). ++Fix? yes ++ ++Free blocks count wrong (493, counted=494). ++Fix? yes ++ ++ ++test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** ++test_filesys: 11/128 files (0.0% non-contiguous), 18/512 blocks ++Exit status is 1 +--- /dev/null ++++ b/tests/f_bb_in_bb/expect.2 +@@ -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 +--- /dev/null ++++ b/tests/f_bb_in_bb/name +@@ -0,0 +1 @@ ++bad block inode table block in bad block list +--- /dev/null ++++ b/tests/f_cloneblock_alloc_error/expect.1 +@@ -0,0 +1,36 @@ ++Pass 1: Checking inodes, blocks, and sizes ++Inode 12, i_size is 0, should be 2015232. 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 13: 8 ++Multiply-claimed block(s) in inode 14: 8 ++Pass 1C: Scanning directories for inodes with multiply-claimed blocks ++Pass 1D: Reconciling multiply-claimed blocks ++(There are 2 inodes containing multiply-claimed blocks.) ++ ++File /b (inode #13, mod time Wed Jan 21 03:41:55 2015) ++ has 1 multiply-claimed block(s), shared with 1 file(s): ++ /c (inode #14, mod time Wed Jan 21 03:42:37 2015) ++Clone multiply-claimed blocks? yes ++ ++clone_file: Could not allocate block in ext2 filesystem returned from clone_file_block ++Couldn't clone file: Could not allocate block in ext2 filesystem ++Delete file? yes ++ ++File /c (inode #14, mod time Wed Jan 21 03:42:37 2015) ++ has 1 multiply-claimed block(s), shared with 1 file(s): ++ /b (inode #13, mod time Wed Jan 21 03:41:55 2015) ++Multiply-claimed blocks already reassigned or cloned. ++ ++Pass 2: Checking directory structure ++Entry 'b' in / (2) has deleted/unused inode 13. Clear? yes ++ ++Pass 3: Checking directory connectivity ++Pass 4: Checking reference counts ++Pass 5: Checking group summary information ++ ++test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** ++test_filesys: 13/128 files (7.7% non-contiguous), 512/512 blocks ++Exit status is 1 +--- /dev/null ++++ b/tests/f_cloneblock_alloc_error/expect.2 +@@ -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: 13/128 files (7.7% non-contiguous), 512/512 blocks ++Exit status is 0 +--- /dev/null ++++ b/tests/f_cloneblock_alloc_error/name +@@ -0,0 +1 @@ ++decrement badcount after remapping duplicate block +--- /dev/null ++++ b/tests/f_collapse_extent_tree/expect.1 +@@ -0,0 +1,16 @@ ++debugfs: ex /a ++Level Entries Logical Physical Length Flags ++ 0/ 1 1/ 1 0 - 0 9 1 ++ 1/ 1 1/ 1 0 - 0 10 - 10 1 ++Pass 1: Checking inodes, blocks, and sizes ++Inode 12 extent tree (at level 1) could be shorter. Fix? yes ++ ++Pass 1E: Optimizing extent trees ++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 +--- /dev/null ++++ b/tests/f_collapse_extent_tree/expect.2 +@@ -0,0 +1,10 @@ ++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 ++debugfs: ex /a ++Level Entries Logical Physical Length Flags ++ 0/ 0 1/ 1 0 - 0 10 - 10 1 +--- /dev/null ++++ b/tests/f_collapse_extent_tree/name +@@ -0,0 +1 @@ ++extent tree can be collapsed one level +--- /dev/null ++++ b/tests/f_collapse_extent_tree/script +@@ -0,0 +1,118 @@ ++if [ "$DESCRIPTION"x != x ]; then ++ test_description="$DESCRIPTION" ++fi ++if [ "$IMAGE"x = x ]; then ++ IMAGE=$test_dir/image.gz ++fi ++ ++if [ "$FSCK_OPT"x = x ]; then ++ FSCK_OPT=-yf ++fi ++ ++if [ "$SECOND_FSCK_OPT"x = x ]; then ++ SECOND_FSCK_OPT=-yf ++fi ++ ++if [ "$OUT1"x = x ]; then ++ OUT1=$test_name.1.log ++fi ++ ++if [ "$OUT2"x = x ]; then ++ OUT2=$test_name.2.log ++fi ++ ++if [ "$EXP1"x = x ]; then ++ if [ -f $test_dir/expect.1.gz ]; then ++ EXP1=$test_name.1.tmp ++ gunzip < $test_dir/expect.1.gz > $EXP1 ++ else ++ EXP1=$test_dir/expect.1 ++ fi ++fi ++ ++if [ "$EXP2"x = x ]; then ++ if [ -f $test_dir/expect.2.gz ]; then ++ EXP2=$test_name.2.tmp ++ gunzip < $test_dir/expect.2.gz > $EXP2 ++ else ++ EXP2=$test_dir/expect.2 ++ fi ++fi ++ ++if [ "$SKIP_GUNZIP" != "true" ] ; then ++ gunzip < $IMAGE > $TMPFILE ++fi ++ ++cp /dev/null $OUT1 ++ ++eval $PREP_CMD ++ ++echo 'ex /a' > $TMPFILE.cmd ++$DEBUGFS -f $TMPFILE.cmd $TMPFILE > $OUT1.new 2>&1 ++rm -rf $TMPFILE.cmd ++$FSCK $FSCK_OPT -N test_filesys $TMPFILE >> $OUT1.new 2>&1 ++status=$? ++echo Exit status is $status >> $OUT1.new ++sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT1.new >> $OUT1 ++rm -f $OUT1.new ++ ++if [ "$ONE_PASS_ONLY" != "true" ]; then ++ $FSCK $SECOND_FSCK_OPT -N test_filesys $TMPFILE > $OUT2.new 2>&1 ++ status=$? ++ echo Exit status is $status >> $OUT2.new ++ echo 'ex /a' > $TMPFILE.cmd ++ $DEBUGFS -f $TMPFILE.cmd $TMPFILE >> $OUT2.new 2>&1 ++ rm -rf $TMPFILE.cmd ++ sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT2.new > $OUT2 ++ rm -f $OUT2.new ++fi ++ ++eval $AFTER_CMD ++ ++if [ "$SKIP_VERIFY" != "true" ] ; then ++ rm -f $test_name.ok $test_name.failed ++ cmp -s $OUT1 $EXP1 ++ status1=$? ++ if [ "$ONE_PASS_ONLY" != "true" ]; then ++ cmp -s $OUT2 $EXP2 ++ status2=$? ++ else ++ status2=0 ++ fi ++ if [ "$PASS_ZERO" = "true" ]; then ++ cmp -s $test_name.0.log $test_dir/expect.0 ++ status3=$? ++ else ++ status3=0 ++ fi ++ ++ if [ -z "$test_description" ] ; then ++ description="$test_name" ++ else ++ description="$test_name: $test_description" ++ fi ++ ++ if [ "$status1" -eq 0 -a "$status2" -eq 0 -a "$status3" -eq 0 ] ; then ++ echo "$description: ok" ++ touch $test_name.ok ++ else ++ echo "$description: failed" ++ rm -f $test_name.failed ++ if [ "$PASS_ZERO" = "true" ]; then ++ diff $DIFF_OPTS $test_dir/expect.0 \ ++ $test_name.0.log >> $test_name.failed ++ fi ++ diff $DIFF_OPTS $EXP1 $OUT1 >> $test_name.failed ++ if [ "$ONE_PASS_ONLY" != "true" ]; then ++ diff $DIFF_OPTS $EXP2 $OUT2 >> $test_name.failed ++ fi ++ fi ++ rm -f tmp_expect ++fi ++ ++if [ "$SKIP_CLEANUP" != "true" ] ; then ++ unset IMAGE FSCK_OPT SECOND_FSCK_OPT OUT1 OUT2 EXP1 EXP2 ++ unset SKIP_VERIFY SKIP_CLEANUP SKIP_GUNZIP ONE_PASS_ONLY PREP_CMD ++ unset DESCRIPTION SKIP_UNLINK AFTER_CMD PASS_ZERO ++fi ++ +--- /dev/null ++++ b/tests/f_compress_extent_tree_level/expect.1 +@@ -0,0 +1,23 @@ ++debugfs: ex /a ++Level Entries Logical Physical Length Flags ++ 0/ 1 1/ 2 0 - 16 9 17 ++ 1/ 1 1/ 4 0 - 0 10 - 10 1 ++ 1/ 1 2/ 4 11 - 11 100 - 100 1 ++ 1/ 1 3/ 4 13 - 13 101 - 101 1 ++ 1/ 1 4/ 4 15 - 15 102 - 102 1 ++ 0/ 1 2/ 2 17 - 21 12 5 ++ 1/ 1 1/ 3 17 - 17 103 - 103 1 ++ 1/ 1 2/ 3 19 - 19 104 - 104 1 ++ 1/ 1 3/ 3 21 - 21 105 - 105 1 ++Pass 1: Checking inodes, blocks, and sizes ++Inode 12 extent tree (at (level 1) could be narrower. Fix? yes ++ ++Pass 1E: Optimizing extent trees ++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 (8.3% non-contiguous), 26/512 blocks ++Exit status is 1 +--- /dev/null ++++ b/tests/f_compress_extent_tree_level/expect.2 +@@ -0,0 +1,17 @@ ++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), 26/512 blocks ++Exit status is 0 ++debugfs: ex /a ++Level Entries Logical Physical Length Flags ++ 0/ 1 1/ 1 0 - 21 9 22 ++ 1/ 1 1/ 7 0 - 0 10 - 10 1 ++ 1/ 1 2/ 7 11 - 11 100 - 100 1 ++ 1/ 1 3/ 7 13 - 13 101 - 101 1 ++ 1/ 1 4/ 7 15 - 15 102 - 102 1 ++ 1/ 1 5/ 7 17 - 17 103 - 103 1 ++ 1/ 1 6/ 7 19 - 19 104 - 104 1 ++ 1/ 1 7/ 7 21 - 21 105 - 105 1 +--- /dev/null ++++ b/tests/f_compress_extent_tree_level/name +@@ -0,0 +1 @@ ++compress an extent tree level +--- /dev/null ++++ b/tests/f_compress_extent_tree_level/script +@@ -0,0 +1,118 @@ ++if [ "$DESCRIPTION"x != x ]; then ++ test_description="$DESCRIPTION" ++fi ++if [ "$IMAGE"x = x ]; then ++ IMAGE=$test_dir/image.gz ++fi ++ ++if [ "$FSCK_OPT"x = x ]; then ++ FSCK_OPT=-yf ++fi ++ ++if [ "$SECOND_FSCK_OPT"x = x ]; then ++ SECOND_FSCK_OPT=-yf ++fi ++ ++if [ "$OUT1"x = x ]; then ++ OUT1=$test_name.1.log ++fi ++ ++if [ "$OUT2"x = x ]; then ++ OUT2=$test_name.2.log ++fi ++ ++if [ "$EXP1"x = x ]; then ++ if [ -f $test_dir/expect.1.gz ]; then ++ EXP1=$test_name.1.tmp ++ gunzip < $test_dir/expect.1.gz > $EXP1 ++ else ++ EXP1=$test_dir/expect.1 ++ fi ++fi ++ ++if [ "$EXP2"x = x ]; then ++ if [ -f $test_dir/expect.2.gz ]; then ++ EXP2=$test_name.2.tmp ++ gunzip < $test_dir/expect.2.gz > $EXP2 ++ else ++ EXP2=$test_dir/expect.2 ++ fi ++fi ++ ++if [ "$SKIP_GUNZIP" != "true" ] ; then ++ gunzip < $IMAGE > $TMPFILE ++fi ++ ++cp /dev/null $OUT1 ++ ++eval $PREP_CMD ++ ++echo 'ex /a' > $TMPFILE.cmd ++$DEBUGFS -f $TMPFILE.cmd $TMPFILE > $OUT1.new 2>&1 ++rm -rf $TMPFILE.cmd ++$FSCK $FSCK_OPT -N test_filesys $TMPFILE >> $OUT1.new 2>&1 ++status=$? ++echo Exit status is $status >> $OUT1.new ++sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT1.new >> $OUT1 ++rm -f $OUT1.new ++ ++if [ "$ONE_PASS_ONLY" != "true" ]; then ++ $FSCK $SECOND_FSCK_OPT -N test_filesys $TMPFILE > $OUT2.new 2>&1 ++ status=$? ++ echo Exit status is $status >> $OUT2.new ++ echo 'ex /a' > $TMPFILE.cmd ++ $DEBUGFS -f $TMPFILE.cmd $TMPFILE >> $OUT2.new 2>&1 ++ rm -rf $TMPFILE.cmd ++ sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT2.new > $OUT2 ++ rm -f $OUT2.new ++fi ++ ++eval $AFTER_CMD ++ ++if [ "$SKIP_VERIFY" != "true" ] ; then ++ rm -f $test_name.ok $test_name.failed ++ cmp -s $OUT1 $EXP1 ++ status1=$? ++ if [ "$ONE_PASS_ONLY" != "true" ]; then ++ cmp -s $OUT2 $EXP2 ++ status2=$? ++ else ++ status2=0 ++ fi ++ if [ "$PASS_ZERO" = "true" ]; then ++ cmp -s $test_name.0.log $test_dir/expect.0 ++ status3=$? ++ else ++ status3=0 ++ fi ++ ++ if [ -z "$test_description" ] ; then ++ description="$test_name" ++ else ++ description="$test_name: $test_description" ++ fi ++ ++ if [ "$status1" -eq 0 -a "$status2" -eq 0 -a "$status3" -eq 0 ] ; then ++ echo "$description: ok" ++ touch $test_name.ok ++ else ++ echo "$description: failed" ++ rm -f $test_name.failed ++ if [ "$PASS_ZERO" = "true" ]; then ++ diff $DIFF_OPTS $test_dir/expect.0 \ ++ $test_name.0.log >> $test_name.failed ++ fi ++ diff $DIFF_OPTS $EXP1 $OUT1 >> $test_name.failed ++ if [ "$ONE_PASS_ONLY" != "true" ]; then ++ diff $DIFF_OPTS $EXP2 $OUT2 >> $test_name.failed ++ fi ++ fi ++ rm -f tmp_expect ++fi ++ ++if [ "$SKIP_CLEANUP" != "true" ] ; then ++ unset IMAGE FSCK_OPT SECOND_FSCK_OPT OUT1 OUT2 EXP1 EXP2 ++ unset SKIP_VERIFY SKIP_CLEANUP SKIP_GUNZIP ONE_PASS_ONLY PREP_CMD ++ unset DESCRIPTION SKIP_UNLINK AFTER_CMD PASS_ZERO ++fi ++ +--- /dev/null ++++ b/tests/f_convert_bmap/expect.1 +@@ -0,0 +1,26 @@ ++debugfs: stat /a ++Inode: 12 Type: regular Mode: 0644 Flags: 0x0 ++Generation: 1573716129 Version: 0x00000000:00000001 ++User: 0 Group: 0 Size: 524288 ++File ACL: 0 Directory ACL: 0 ++Links: 1 Blockcount: 1030 ++Fragment: Address: 0 Number: 0 Size: 0 ++ ctime: 0x5457f87a:62ae2980 -- Mon Nov 3 21:49:46 2014 ++ atime: 0x5457f87a:61ba0598 -- Mon Nov 3 21:49:46 2014 ++ mtime: 0x5457f87a:62ae2980 -- Mon Nov 3 21:49:46 2014 ++crtime: 0x5457f87a:61ba0598 -- Mon Nov 3 21:49:46 2014 ++Size of extra inode fields: 28 ++BLOCKS: ++(0-11):1025-1036, (IND):24, (12-267):1037-1292, (DIND):25, (IND):41, (268-511):1293-1536 ++TOTAL: 515 ++ ++Pass 1: Checking inodes, blocks, and sizes ++Pass 1E: Optimizing extent trees ++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 (8.3% non-contiguous), 570/2048 blocks ++Exit status is 1 +--- /dev/null ++++ b/tests/f_convert_bmap/expect.2 +@@ -0,0 +1,10 @@ ++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), 570/2048 blocks ++Exit status is 0 ++debugfs: ex /a ++Level Entries Logical Physical Length Flags ++ 0/ 0 1/ 1 0 - 511 1025 - 1536 512 +--- /dev/null ++++ b/tests/f_convert_bmap/name +@@ -0,0 +1 @@ ++convert blockmap file to extents file +--- /dev/null ++++ b/tests/f_convert_bmap/script +@@ -0,0 +1,117 @@ ++if [ "$DESCRIPTION"x != x ]; then ++ test_description="$DESCRIPTION" ++fi ++if [ "$IMAGE"x = x ]; then ++ IMAGE=$test_dir/image.gz ++fi ++ ++if [ "$FSCK_OPT"x = x ]; then ++ FSCK_OPT=-yf ++fi ++ ++if [ "$SECOND_FSCK_OPT"x = x ]; then ++ SECOND_FSCK_OPT=-yf ++fi ++ ++if [ "$OUT1"x = x ]; then ++ OUT1=$test_name.1.log ++fi ++ ++if [ "$OUT2"x = x ]; then ++ OUT2=$test_name.2.log ++fi ++ ++if [ "$EXP1"x = x ]; then ++ if [ -f $test_dir/expect.1.gz ]; then ++ EXP1=$test_name.1.tmp ++ gunzip < $test_dir/expect.1.gz > $EXP1 ++ else ++ EXP1=$test_dir/expect.1 ++ fi ++fi ++ ++if [ "$EXP2"x = x ]; then ++ if [ -f $test_dir/expect.2.gz ]; then ++ EXP2=$test_name.2.tmp ++ gunzip < $test_dir/expect.2.gz > $EXP2 ++ else ++ EXP2=$test_dir/expect.2 ++ fi ++fi ++ ++if [ "$SKIP_GUNZIP" != "true" ] ; then ++ gunzip < $IMAGE > $TMPFILE ++fi ++ ++cp /dev/null $OUT1 ++ ++eval $PREP_CMD ++ ++echo 'stat /a' > $TMPFILE.cmd ++$DEBUGFS -f $TMPFILE.cmd $TMPFILE > $OUT1.new 2>&1 ++rm -rf $TMPFILE.cmd ++$TUNE2FS -O extent $TMPFILE >> $OUT1.new 2>&1 ++$FSCK $FSCK_OPT -E bmap2extent -N test_filesys $TMPFILE >> $OUT1.new 2>&1 ++status=$? ++echo Exit status is $status >> $OUT1.new ++sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT1.new >> $OUT1 ++rm -f $OUT1.new ++ ++$FSCK $SECOND_FSCK_OPT -N test_filesys $TMPFILE > $OUT2.new 2>&1 ++status=$? ++echo Exit status is $status >> $OUT2.new ++echo 'ex /a' > $TMPFILE.cmd ++$DEBUGFS -f $TMPFILE.cmd $TMPFILE >> $OUT2.new 2>&1 ++rm -rf $TMPFILE.cmd ++sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT2.new > $OUT2 ++rm -f $OUT2.new ++ ++eval $AFTER_CMD ++ ++if [ "$SKIP_VERIFY" != "true" ] ; then ++ rm -f $test_name.ok $test_name.failed ++ cmp -s $OUT1 $EXP1 ++ status1=$? ++ if [ "$ONE_PASS_ONLY" != "true" ]; then ++ cmp -s $OUT2 $EXP2 ++ status2=$? ++ else ++ status2=0 ++ fi ++ if [ "$PASS_ZERO" = "true" ]; then ++ cmp -s $test_name.0.log $test_dir/expect.0 ++ status3=$? ++ else ++ status3=0 ++ fi ++ ++ if [ -z "$test_description" ] ; then ++ description="$test_name" ++ else ++ description="$test_name: $test_description" ++ fi ++ ++ if [ "$status1" -eq 0 -a "$status2" -eq 0 -a "$status3" -eq 0 ] ; then ++ echo "$description: ok" ++ touch $test_name.ok ++ else ++ echo "$description: failed" ++ rm -f $test_name.failed ++ if [ "$PASS_ZERO" = "true" ]; then ++ diff $DIFF_OPTS $test_dir/expect.0 \ ++ $test_name.0.log >> $test_name.failed ++ fi ++ diff $DIFF_OPTS $EXP1 $OUT1 >> $test_name.failed ++ if [ "$ONE_PASS_ONLY" != "true" ]; then ++ diff $DIFF_OPTS $EXP2 $OUT2 >> $test_name.failed ++ fi ++ fi ++ rm -f tmp_expect ++fi ++ ++if [ "$SKIP_CLEANUP" != "true" ] ; then ++ unset IMAGE FSCK_OPT SECOND_FSCK_OPT OUT1 OUT2 EXP1 EXP2 ++ unset SKIP_VERIFY SKIP_CLEANUP SKIP_GUNZIP ONE_PASS_ONLY PREP_CMD ++ unset DESCRIPTION SKIP_UNLINK AFTER_CMD PASS_ZERO ++fi ++ +--- /dev/null ++++ b/tests/f_convert_bmap_and_extent/expect.1 +@@ -0,0 +1,33 @@ ++debugfs: stat /a ++Inode: 12 Type: regular Mode: 0644 Flags: 0x0 ++Generation: 1573716129 Version: 0x00000000:00000001 ++User: 0 Group: 0 Size: 524288 ++File ACL: 0 Directory ACL: 0 ++Links: 1 Blockcount: 1030 ++Fragment: Address: 0 Number: 0 Size: 0 ++ ctime: 0x5457f87a:62ae2980 -- Mon Nov 3 21:49:46 2014 ++ atime: 0x5457f87a:61ba0598 -- Mon Nov 3 21:49:46 2014 ++ mtime: 0x5457f87a:62ae2980 -- Mon Nov 3 21:49:46 2014 ++crtime: 0x5457f87a:61ba0598 -- Mon Nov 3 21:49:46 2014 ++Size of extra inode fields: 28 ++BLOCKS: ++(0-11):1025-1036, (IND):24, (12-267):1037-1292, (DIND):25, (IND):41, (268-511):1293-1536 ++TOTAL: 515 ++ ++debugfs: ex /zero ++Level Entries Logical Physical Length Flags ++ 0/ 1 1/ 1 0 - 8 28 9 ++ 1/ 1 1/ 4 0 - 0 27 - 27 1 ++ 1/ 1 2/ 4 2 - 2 29 - 29 1 ++ 1/ 1 3/ 4 4 - 4 31 - 31 1 ++ 1/ 1 4/ 4 6 - 6 33 - 33 1 ++Pass 1: Checking inodes, blocks, and sizes ++Pass 1E: Optimizing extent trees ++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: 13/128 files (15.4% non-contiguous), 574/2048 blocks ++Exit status is 1 +--- /dev/null ++++ b/tests/f_convert_bmap_and_extent/expect.2 +@@ -0,0 +1,16 @@ ++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: 13/128 files (7.7% non-contiguous), 574/2048 blocks ++Exit status is 0 ++debugfs: ex /a ++Level Entries Logical Physical Length Flags ++ 0/ 0 1/ 1 0 - 511 1025 - 1536 512 ++debugfs: ex /zero ++Level Entries Logical Physical Length Flags ++ 0/ 0 1/ 4 0 - 0 27 - 27 1 ++ 0/ 0 2/ 4 2 - 2 29 - 29 1 ++ 0/ 0 3/ 4 4 - 4 31 - 31 1 ++ 0/ 0 4/ 4 6 - 6 33 - 33 1 +--- /dev/null ++++ b/tests/f_convert_bmap_and_extent/name +@@ -0,0 +1 @@ ++convert blockmap and extents files to extents files +--- /dev/null ++++ b/tests/f_convert_bmap_and_extent/script +@@ -0,0 +1,119 @@ ++if [ "$DESCRIPTION"x != x ]; then ++ test_description="$DESCRIPTION" ++fi ++if [ "$IMAGE"x = x ]; then ++ IMAGE=$test_dir/image.gz ++fi ++ ++if [ "$FSCK_OPT"x = x ]; then ++ FSCK_OPT=-yf ++fi ++ ++if [ "$SECOND_FSCK_OPT"x = x ]; then ++ SECOND_FSCK_OPT=-yf ++fi ++ ++if [ "$OUT1"x = x ]; then ++ OUT1=$test_name.1.log ++fi ++ ++if [ "$OUT2"x = x ]; then ++ OUT2=$test_name.2.log ++fi ++ ++if [ "$EXP1"x = x ]; then ++ if [ -f $test_dir/expect.1.gz ]; then ++ EXP1=$test_name.1.tmp ++ gunzip < $test_dir/expect.1.gz > $EXP1 ++ else ++ EXP1=$test_dir/expect.1 ++ fi ++fi ++ ++if [ "$EXP2"x = x ]; then ++ if [ -f $test_dir/expect.2.gz ]; then ++ EXP2=$test_name.2.tmp ++ gunzip < $test_dir/expect.2.gz > $EXP2 ++ else ++ EXP2=$test_dir/expect.2 ++ fi ++fi ++ ++if [ "$SKIP_GUNZIP" != "true" ] ; then ++ gunzip < $IMAGE > $TMPFILE ++fi ++ ++cp /dev/null $OUT1 ++ ++eval $PREP_CMD ++ ++echo 'stat /a' > $TMPFILE.cmd ++echo 'ex /zero' >> $TMPFILE.cmd ++$DEBUGFS -f $TMPFILE.cmd $TMPFILE > $OUT1.new 2>&1 ++rm -rf $TMPFILE.cmd ++$TUNE2FS -O extent $TMPFILE >> $OUT1.new 2>&1 ++$FSCK $FSCK_OPT -E bmap2extent -N test_filesys $TMPFILE >> $OUT1.new 2>&1 ++status=$? ++echo Exit status is $status >> $OUT1.new ++sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT1.new >> $OUT1 ++rm -f $OUT1.new ++ ++$FSCK $SECOND_FSCK_OPT -N test_filesys $TMPFILE > $OUT2.new 2>&1 ++status=$? ++echo Exit status is $status >> $OUT2.new ++echo 'ex /a' > $TMPFILE.cmd ++echo 'ex /zero' >> $TMPFILE.cmd ++$DEBUGFS -f $TMPFILE.cmd $TMPFILE >> $OUT2.new 2>&1 ++rm -rf $TMPFILE.cmd ++sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT2.new > $OUT2 ++rm -f $OUT2.new ++ ++eval $AFTER_CMD ++ ++if [ "$SKIP_VERIFY" != "true" ] ; then ++ rm -f $test_name.ok $test_name.failed ++ cmp -s $OUT1 $EXP1 ++ status1=$? ++ if [ "$ONE_PASS_ONLY" != "true" ]; then ++ cmp -s $OUT2 $EXP2 ++ status2=$? ++ else ++ status2=0 ++ fi ++ if [ "$PASS_ZERO" = "true" ]; then ++ cmp -s $test_name.0.log $test_dir/expect.0 ++ status3=$? ++ else ++ status3=0 ++ fi ++ ++ if [ -z "$test_description" ] ; then ++ description="$test_name" ++ else ++ description="$test_name: $test_description" ++ fi ++ ++ if [ "$status1" -eq 0 -a "$status2" -eq 0 -a "$status3" -eq 0 ] ; then ++ echo "$description: ok" ++ touch $test_name.ok ++ else ++ echo "$description: failed" ++ rm -f $test_name.failed ++ if [ "$PASS_ZERO" = "true" ]; then ++ diff $DIFF_OPTS $test_dir/expect.0 \ ++ $test_name.0.log >> $test_name.failed ++ fi ++ diff $DIFF_OPTS $EXP1 $OUT1 >> $test_name.failed ++ if [ "$ONE_PASS_ONLY" != "true" ]; then ++ diff $DIFF_OPTS $EXP2 $OUT2 >> $test_name.failed ++ fi ++ fi ++ rm -f tmp_expect ++fi ++ ++if [ "$SKIP_CLEANUP" != "true" ] ; then ++ unset IMAGE FSCK_OPT SECOND_FSCK_OPT OUT1 OUT2 EXP1 EXP2 ++ unset SKIP_VERIFY SKIP_CLEANUP SKIP_GUNZIP ONE_PASS_ONLY PREP_CMD ++ unset DESCRIPTION SKIP_UNLINK AFTER_CMD PASS_ZERO ++fi ++ +--- /dev/null ++++ b/tests/f_corrupt_dirent_tail/expect.1 +@@ -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 +--- /dev/null ++++ b/tests/f_corrupt_dirent_tail/expect.2 +@@ -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 +--- /dev/null ++++ b/tests/f_corrupt_dirent_tail/name +@@ -0,0 +1 @@ ++rebuild a directory with corrupt dirent tail +--- /dev/null ++++ b/tests/f_create_symlinks/expect +@@ -0,0 +1,69 @@ ++mke2fs -q -F -o Linux -b 1024 -g 256 -O inline_data,extents -I 256 test.img 1024 ++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), 441/1024 blocks ++Exit status is 0 ++debugfs -R "symlink /l_30 /xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" test.img ++debugfs -R "symlink /l_70 /xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" test.img ++debugfs -R "symlink /l_500 /xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" test.img ++debugfs -R "symlink /l_1023 /xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" test.img ++debugfs -R "symlink /l_1024 /xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" test.img ++ext2fs_symlink: Invalid argument passed to ext2 library while creating symlink "l_1024" ++symlink: Invalid argument passed to ext2 library ++debugfs -R "symlink /l_1500 /xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" test.img ++ext2fs_symlink: Invalid argument passed to ext2 library while creating symlink "l_1500" ++symlink: Invalid argument passed to ext2 library ++debugfs -R "stat /l_30" test.img ++Inode: 12 Type: symlink Mode: 0777 Flags: 0x0 ++Generation: 0 Version: 0x00000000:00000000 ++User: 0 Group: 0 Size: 31 ++File ACL: 0 Directory ACL: 0 ++Links: 1 Blockcount: 0 ++Fragment: Address: 0 Number: 0 Size: 0 ++Size of extra inode fields: 28 ++Fast link dest: "/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" ++debugfs -R "stat /l_70" test.img ++Inode: 13 Type: symlink Mode: 0777 Flags: 0x10000000 ++Generation: 0 Version: 0x00000000:00000000 ++User: 0 Group: 0 Size: 71 ++File ACL: 0 Directory ACL: 0 ++Links: 1 Blockcount: 0 ++Fragment: Address: 0 Number: 0 Size: 0 ++Size of extra inode fields: 28 ++Extended attributes: ++ system.data (11) ++Fast link dest: "/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" ++debugfs -R "stat /l_500" test.img ++Inode: 14 Type: symlink Mode: 0777 Flags: 0x80000 ++Generation: 0 Version: 0x00000000:00000000 ++User: 0 Group: 0 Size: 501 ++File ACL: 0 Directory ACL: 0 ++Links: 1 Blockcount: 2 ++Fragment: Address: 0 Number: 0 Size: 0 ++Size of extra inode fields: 28 ++EXTENTS: ++(0):153 ++debugfs -R "stat /l_1023" test.img ++Inode: 15 Type: symlink Mode: 0777 Flags: 0x80000 ++Generation: 0 Version: 0x00000000:00000000 ++User: 0 Group: 0 Size: 1024 ++File ACL: 0 Directory ACL: 0 ++Links: 1 Blockcount: 2 ++Fragment: Address: 0 Number: 0 Size: 0 ++Size of extra inode fields: 28 ++EXTENTS: ++(0):154 ++debugfs -R "stat /l_1024" test.img ++/l_1024: File not found by ext2_lookup ++debugfs -R "stat /l_1500" test.img ++/l_1500: File not found by ext2_lookup ++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 (0.0% non-contiguous), 443/1024 blocks ++Exit status is 0 +--- /dev/null ++++ b/tests/f_create_symlinks/name +@@ -0,0 +1 @@ ++create fast, inlinedata, and regular symlinks +--- /dev/null ++++ b/tests/f_create_symlinks/script +@@ -0,0 +1,64 @@ ++if test -x $DEBUGFS_EXE; then ++ ++FSCK_OPT=-yf ++OUT=$test_name.log ++if [ -f $test_dir/expect.gz ]; then ++ EXP=$test_name.tmp ++ gunzip < $test_dir/expect.gz > $EXP1 ++else ++ EXP=$test_dir/expect ++fi ++ ++cp /dev/null $OUT ++ ++dd if=/dev/zero of=$TMPFILE bs=1k count=512 > /dev/null 2>&1 ++ ++echo mke2fs -q -F -o Linux -b 1024 -g 256 -O inline_data,extents -I 256 test.img 1024 >> $OUT ++$MKE2FS -q -F -o Linux -b 1024 -g 256 -O inline_data,extents -I 256 $TMPFILE 1024 2>&1 | ++ sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" >> $OUT ++ ++$FSCK $FSCK_OPT -N test_filesys $TMPFILE > $OUT.new 2>&1 ++status=$? ++echo Exit status is $status >> $OUT.new ++sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT ++rm -f $OUT.new ++ ++for i in 30 70 500 1023 1024 1500; do ++ echo "debugfs -R \"symlink /l_$i /$(perl -e "print 'x' x $i;")\" test.img" >> $OUT ++ $DEBUGFS -w -R "symlink /l_$i /$(perl -e "print 'x' x $i;")" $TMPFILE \ ++ 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT ++done ++ ++for i in 30 70 500 1023 1024 1500; do ++ echo "debugfs -R \"stat /l_$i\" test.img" >> $OUT ++ $DEBUGFS -R "stat /l_$i" $TMPFILE 2>&1 | \ ++ sed -f $cmd_dir/filter.sed | grep -v "time: " >> $OUT ++done ++ ++/bin/cp $TMPFILE /tmp/foo.img ++ ++$FSCK $FSCK_OPT -N test_filesys $TMPFILE > $OUT.new 2>&1 ++status=$? ++echo Exit status is $status >> $OUT.new ++sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT ++rm -f $OUT.new ++ ++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 IMAGE FSCK_OPT OUT EXP ++ ++else #if test -a -x $DEBUGFS_EXE; then ++ echo "$test_name: $test_description: skipped" ++fi +--- /dev/null ++++ b/tests/f_deleted_inode_bad_csum/expect.1 +@@ -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 +--- /dev/null ++++ b/tests/f_deleted_inode_bad_csum/expect.2 +@@ -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 +--- /dev/null ++++ b/tests/f_deleted_inode_bad_csum/name +@@ -0,0 +1 @@ ++deleted inode with a bad csum that wasn't getting fixed (metadata_csum) +--- /dev/null ++++ b/tests/f_detect_junk/expect +@@ -0,0 +1,25 @@ ++*** e2fsck ++ext2fs_open2: Bad magic number in super-block ++../e2fsck/e2fsck: Superblock invalid, trying backup blocks... ++../e2fsck/e2fsck: Bad magic number in super-block while trying to open test.img ++ ++The superblock could not be read or does not describe a valid ext2/ext3/ext4 ++filesystem. If the device is valid and it really contains an ext2/ext3/ext4 ++filesystem (and not swap or ufs or something else), then the superblock ++is corrupt, and you might try running e2fsck with an alternate superblock: ++ e2fsck -b 8193 ++ or ++ e2fsck -b 32768 ++ ++test.img contains `PNG image data, 148 x 31, 8-bit/color RGBA, non-interlaced' data ++*** debugfs ++test.img: Bad magic number in super-block while opening filesystem ++test.img contains `PNG image data, 148 x 31, 8-bit/color RGBA, non-interlaced' data ++*** tune2fs ++../misc/tune2fs: Bad magic number in super-block while trying to open test.img ++test.img contains `PNG image data, 148 x 31, 8-bit/color RGBA, non-interlaced' data ++*** mke2fs ++Creating filesystem with 16384 1k blocks and 4096 inodes ++Superblock backups stored on blocks: ++ 8193 ++ +--- /dev/null ++++ b/tests/f_detect_junk/expect.nodebugfs +@@ -0,0 +1,23 @@ ++*** e2fsck ++ext2fs_open2: Bad magic number in super-block ++../e2fsck/e2fsck: Superblock invalid, trying backup blocks... ++../e2fsck/e2fsck: Bad magic number in super-block while trying to open test.img ++ ++The superblock could not be read or does not describe a valid ext2/ext3/ext4 ++filesystem. If the device is valid and it really contains an ext2/ext3/ext4 ++filesystem (and not swap or ufs or something else), then the superblock ++is corrupt, and you might try running e2fsck with an alternate superblock: ++ e2fsck -b 8193 ++ or ++ e2fsck -b 32768 ++ ++test.img contains `PNG image data, 148 x 31, 8-bit/color RGBA, non-interlaced' data ++*** debugfs ++*** tune2fs ++../misc/tune2fs: Bad magic number in super-block while trying to open test.img ++test.img contains `PNG image data, 148 x 31, 8-bit/color RGBA, non-interlaced' data ++*** mke2fs ++Creating filesystem with 16384 1k blocks and 4096 inodes ++Superblock backups stored on blocks: ++ 8193 ++ +--- /dev/null ++++ b/tests/f_detect_junk/name +@@ -0,0 +1 @@ ++detect non-fs file data +--- /dev/null ++++ b/tests/f_detect_junk/script +@@ -0,0 +1,44 @@ ++#!/bin/bash ++ ++if [ "$(grep -c 'define HAVE_MAGIC_H' ../lib/config.h)" -gt 0 ]; then ++ ++FSCK_OPT=-fn ++IMAGE=$test_dir/image.bz2 ++ ++bzip2 -d < $IMAGE > $TMPFILE ++dd if=/dev/zero of=$TMPFILE conv=notrunc oflag=append bs=1024k count=16 > /dev/null 2>&1 ++ ++# Run fsck to fix things? ++if [ -x $DEBUGFS_EXE ]; then ++ EXP=$test_dir/expect ++else ++ EXP=$test_dir/expect.nodebugfs ++fi ++OUT=$test_name.log ++rm -rf $test_name.failed $test_name.ok ++ ++echo "*** e2fsck" > $OUT ++$FSCK $FSCK_OPT $TMPFILE >> $OUT 2>&1 ++echo "*** debugfs" >> $OUT ++test -x $DEBUGFS_EXE && $DEBUGFS_EXE -R 'quit' $TMPFILE >> $OUT 2>&1 ++echo "*** tune2fs" >> $OUT ++$TUNE2FS -i 0 $TMPFILE >> $OUT 2>&1 ++echo "*** mke2fs" >> $OUT ++$MKE2FS -n $TMPFILE >> $OUT 2>&1 ++ ++sed -f $cmd_dir/filter.sed -e "s|$TMPFILE|test.img|g" < $OUT > $OUT.new ++mv $OUT.new $OUT ++ ++# Figure out what happened ++if cmp -s $EXP $OUT; then ++ echo "$test_name: $test_description: ok" ++ touch $test_name.ok ++else ++ echo "$test_name: $test_description: failed" ++ diff -u $EXP $OUT >> $test_name.failed ++fi ++unset EXP OUT FSCK_OPT IMAGE ++ ++else #if HAVE_MAGIC_H ++ echo "$test_name: $test_description: skipped" ++fi +--- /dev/null ++++ b/tests/f_detect_xfs/expect +@@ -0,0 +1,25 @@ ++*** e2fsck ++ext2fs_open2: Bad magic number in super-block ++../e2fsck/e2fsck: Superblock invalid, trying backup blocks... ++../e2fsck/e2fsck: Bad magic number in super-block while trying to open test.img ++ ++The superblock could not be read or does not describe a valid ext2/ext3/ext4 ++filesystem. If the device is valid and it really contains an ext2/ext3/ext4 ++filesystem (and not swap or ufs or something else), then the superblock ++is corrupt, and you might try running e2fsck with an alternate superblock: ++ e2fsck -b 8193 ++ or ++ e2fsck -b 32768 ++ ++test.img contains a xfs file system labelled 'test_filsys' ++*** debugfs ++test.img: Bad magic number in super-block while opening filesystem ++test.img contains a xfs file system labelled 'test_filsys' ++*** tune2fs ++../misc/tune2fs: Bad magic number in super-block while trying to open test.img ++test.img contains a xfs file system labelled 'test_filsys' ++*** mke2fs ++Creating filesystem with 16384 1k blocks and 4096 inodes ++Superblock backups stored on blocks: ++ 8193 ++ +--- /dev/null ++++ b/tests/f_detect_xfs/expect.nodebugfs +@@ -0,0 +1,23 @@ ++*** e2fsck ++ext2fs_open2: Bad magic number in super-block ++../e2fsck/e2fsck: Superblock invalid, trying backup blocks... ++../e2fsck/e2fsck: Bad magic number in super-block while trying to open test.img ++ ++The superblock could not be read or does not describe a valid ext2/ext3/ext4 ++filesystem. If the device is valid and it really contains an ext2/ext3/ext4 ++filesystem (and not swap or ufs or something else), then the superblock ++is corrupt, and you might try running e2fsck with an alternate superblock: ++ e2fsck -b 8193 ++ or ++ e2fsck -b 32768 ++ ++test.img contains a xfs file system labelled 'test_filsys' ++*** debugfs ++*** tune2fs ++../misc/tune2fs: Bad magic number in super-block while trying to open test.img ++test.img contains a xfs file system labelled 'test_filsys' ++*** mke2fs ++Creating filesystem with 16384 1k blocks and 4096 inodes ++Superblock backups stored on blocks: ++ 8193 ++ +--- /dev/null ++++ b/tests/f_detect_xfs/name +@@ -0,0 +1 @@ ++detect xfs filesystem +--- /dev/null ++++ b/tests/f_detect_xfs/script +@@ -0,0 +1,37 @@ ++#!/bin/bash ++ ++FSCK_OPT=-fn ++IMAGE=$test_dir/image.bz2 ++ ++bzip2 -d < $IMAGE > $TMPFILE ++ ++# Run fsck to fix things? ++if [ -x $DEBUGFS_EXE ]; then ++ EXP=$test_dir/expect ++else ++ EXP=$test_dir/expect.nodebugfs ++fi ++OUT=$test_name.log ++rm -rf $test_name.failed $test_name.ok ++ ++echo "*** e2fsck" > $OUT ++$FSCK $FSCK_OPT $TMPFILE >> $OUT 2>&1 ++echo "*** debugfs" >> $OUT ++test -x $DEBUGFS_EXE && $DEBUGFS_EXE -R 'quit' $TMPFILE >> $OUT 2>&1 ++echo "*** tune2fs" >> $OUT ++$TUNE2FS -i 0 $TMPFILE >> $OUT 2>&1 ++echo "*** mke2fs" >> $OUT ++$MKE2FS -n $TMPFILE >> $OUT 2>&1 ++ ++sed -f $cmd_dir/filter.sed -e "s|$TMPFILE|test.img|g" < $OUT > $OUT.new ++mv $OUT.new $OUT ++ ++# Figure out what happened ++if cmp -s $EXP $OUT; then ++ echo "$test_name: $test_description: ok" ++ touch $test_name.ok ++else ++ echo "$test_name: $test_description: failed" ++ diff -u $EXP $OUT >> $test_name.failed ++fi ++unset EXP OUT FSCK_OPT IMAGE +--- /dev/null ++++ b/tests/f_dir_bad_csum/expect.1 +@@ -0,0 +1,56 @@ ++Pass 1: Checking inodes, blocks, and sizes ++Pass 2: Checking directory structure ++Directory inode 12, block #0: directory passes checks but fails checksum. ++Fix? yes ++ ++Directory inode 13, block #0, offset 0: directory has no checksum. ++Fix? yes ++ ++Directory inode 14, block #0, offset 0: directory has no 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 (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 +--- /dev/null ++++ b/tests/f_dir_bad_csum/expect.2 +@@ -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 +--- /dev/null ++++ b/tests/f_dir_bad_csum/name +@@ -0,0 +1 @@ ++dir block w/ missing/bad csum, no tail, or dir block corruption (metadata_csum) +--- a/tests/f_dup/expect.1 ++++ b/tests/f_dup/expect.1 +@@ -4,8 +4,8 @@ + + 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.) +--- a/tests/f_dup2/expect.1 ++++ b/tests/f_dup2/expect.1 +@@ -4,9 +4,9 @@ + + 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.) +--- a/tests/f_dup_ba/expect.1 ++++ b/tests/f_dup_ba/expect.1 +@@ -6,12 +6,12 @@ + + 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.) +--- a/tests/f_dupfsblks/expect.1 ++++ b/tests/f_dupfsblks/expect.1 +@@ -8,8 +8,8 @@ + + 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 +--- a/tests/f_dup_resize/expect.1 ++++ b/tests/f_dup_resize/expect.1 +@@ -4,8 +4,8 @@ + + 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.) +--- a/tests/f_dupsuper/expect.1 ++++ b/tests/f_dupsuper/expect.1 +@@ -4,7 +4,7 @@ + + 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.) +--- /dev/null ++++ b/tests/f_ea_bad_csum/expect.1 +@@ -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 +--- /dev/null ++++ b/tests/f_ea_bad_csum/expect.2 +@@ -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 +--- /dev/null ++++ b/tests/f_ea_bad_csum/name +@@ -0,0 +1 @@ ++EA block with bad checksum (metadata_csum) +--- /dev/null ++++ b/tests/f_ea_value_crash/expect.1 +@@ -0,0 +1,15 @@ ++Pass 1: Checking inodes, blocks, and sizes ++Inode 12 has INLINE_DATA_FL flag but extended attribute not found. Truncate? yes ++ ++Inode 12 extended attribute is corrupt (allocation collision). Clear? yes ++ ++Inode 13 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: 13/128 files (0.0% non-contiguous), 17/512 blocks ++Exit status is 1 +--- /dev/null ++++ b/tests/f_ea_value_crash/expect.2 +@@ -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: 13/128 files (0.0% non-contiguous), 17/512 blocks ++Exit status is 0 +--- /dev/null ++++ b/tests/f_ea_value_crash/name +@@ -0,0 +1 @@ ++extended attribute value conflicts with key +--- /dev/null ++++ b/tests/f_encrypted_lpf/expect.1 +@@ -0,0 +1,27 @@ ++Pass 1: Checking inodes, blocks, and sizes ++Pass 2: Checking directory structure ++Pass 3: Checking directory connectivity ++Unconnected directory inode 12 (/???) ++Connect to /lost+found? yes ++ ++/lost+found is encrypted ++Clear? yes ++ ++/lost+found not found. Create? yes ++ ++Restarting e2fsck from the beginning... ++Pass 1: Checking inodes, blocks, and sizes ++Pass 2: Checking directory structure ++Pass 3: Checking directory connectivity ++Unconnected directory inode 11 (/???) ++Connect to /lost+found? yes ++ ++Pass 3A: Optimizing directories ++Pass 4: Checking reference counts ++Inode 12 ref count is 3, should be 2. Fix? yes ++ ++Pass 5: Checking group summary information ++ ++test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** ++test_filesys: 13/64 files (0.0% non-contiguous), 13/100 blocks ++Exit status is 1 +--- /dev/null ++++ b/tests/f_encrypted_lpf/expect.2 +@@ -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: 13/64 files (0.0% non-contiguous), 13/100 blocks ++Exit status is 0 +--- /dev/null ++++ b/tests/f_encrypted_lpf/name +@@ -0,0 +1 @@ ++encrypted lost+found directory +--- /dev/null ++++ b/tests/f_expandroot_create_lnf/expect.1 +@@ -0,0 +1,12 @@ ++Pass 1: Checking inodes, blocks, and sizes ++Pass 2: Checking directory structure ++Pass 3: Checking directory connectivity ++/lost+found not found. Create? yes ++ ++Pass 3A: Optimizing directories ++Pass 4: Checking reference counts ++Pass 5: Checking group summary information ++ ++test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** ++test_filesys: 16/64 files (0.0% non-contiguous), 33/1024 blocks ++Exit status is 1 +--- /dev/null ++++ b/tests/f_expandroot_create_lnf/expect.2 +@@ -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: 16/64 files (6.3% non-contiguous), 33/1024 blocks ++Exit status is 0 +--- /dev/null ++++ b/tests/f_expandroot_create_lnf/name +@@ -0,0 +1 @@ ++no space in root to create lost+found entry +--- a/tests/f_extent_bad_node/expect.1 ++++ b/tests/f_extent_bad_node/expect.1 +@@ -2,8 +2,11 @@ + Inode 12 has an invalid extent node (blk 22, lblk 0) + Clear? yes + ++Inode 12 extent tree (at level 1) could be shorter. Fix? yes ++ + Inode 12, i_blocks is 16, should be 8. Fix? yes + ++Pass 1E: Optimizing extent trees + Pass 2: Checking directory structure + Pass 3: Checking directory connectivity + Pass 4: Checking reference counts +@@ -11,13 +14,13 @@ + Block bitmap differences: -(21--23) -25 + Fix? yes + +-Free blocks count wrong for group #0 (71, counted=75). ++Free blocks count wrong for group #0 (73, counted=77). + Fix? yes + +-Free blocks count wrong (71, counted=75). ++Free blocks count wrong (73, counted=77). + Fix? yes + + + test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** +-test_filesys: 12/16 files (0.0% non-contiguous), 25/100 blocks ++test_filesys: 12/16 files (0.0% non-contiguous), 23/100 blocks + Exit status is 1 +--- a/tests/f_extent_bad_node/expect.2 ++++ b/tests/f_extent_bad_node/expect.2 +@@ -3,5 +3,5 @@ + Pass 3: Checking directory connectivity + Pass 4: Checking reference counts + Pass 5: Checking group summary information +-test_filesys: 12/16 files (0.0% non-contiguous), 25/100 blocks ++test_filesys: 12/16 files (0.0% non-contiguous), 23/100 blocks + Exit status is 0 +--- a/tests/f_extent_bad_node/name ++++ b/tests/f_extent_bad_node/name +@@ -1 +1 @@ +-bad interior node in extent tree ++bad interior node in extent tree (metadata_csum) +--- /dev/null ++++ b/tests/f_extent_int_bad_csum/expect.1 +@@ -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, 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 +--- /dev/null ++++ b/tests/f_extent_int_bad_csum/expect.2 +@@ -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 +--- /dev/null ++++ b/tests/f_extent_int_bad_csum/name +@@ -0,0 +1 @@ ++bad csum in internal extent (metadata_csum) +--- /dev/null ++++ b/tests/f_extent_int_bad_extent/expect.1 +@@ -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 +--- /dev/null ++++ b/tests/f_extent_int_bad_extent/expect.2 +@@ -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 +--- /dev/null ++++ b/tests/f_extent_int_bad_extent/name +@@ -0,0 +1 @@ ++bad extent in internal extent (metadata_csum) +--- /dev/null ++++ b/tests/f_extent_int_bad_magic/expect.1 +@@ -0,0 +1,26 @@ ++Pass 1: Checking inodes, blocks, and sizes ++Inode 12 has an invalid extent node (blk 1295, lblk 0) ++Clear? yes ++ ++Inode 12 extent tree (at level 1) could be shorter. Fix? yes ++ ++Inode 12, i_blocks is 712, should be 0. Fix? yes ++ ++Pass 1E: Optimizing extent trees ++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 +--- /dev/null ++++ b/tests/f_extent_int_bad_magic/expect.2 +@@ -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 +--- /dev/null ++++ b/tests/f_extent_int_bad_magic/name +@@ -0,0 +1 @@ ++bad magic number in internal extent (metadata_csum) +--- /dev/null ++++ b/tests/f_extent_leaf_bad_csum/expect.1 +@@ -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, 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 +--- /dev/null ++++ b/tests/f_extent_leaf_bad_csum/expect.2 +@@ -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 +--- /dev/null ++++ b/tests/f_extent_leaf_bad_csum/name +@@ -0,0 +1 @@ ++bad csum in leaf extent (metadata_csum) +--- /dev/null ++++ b/tests/f_extent_leaf_bad_extent/expect.1 +@@ -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 +--- /dev/null ++++ b/tests/f_extent_leaf_bad_extent/expect.2 +@@ -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 +--- /dev/null ++++ b/tests/f_extent_leaf_bad_extent/name +@@ -0,0 +1 @@ ++bad extent in leaf extent (metadata_csum) +--- /dev/null ++++ b/tests/f_extent_leaf_bad_magic/expect.1 +@@ -0,0 +1,26 @@ ++Pass 1: Checking inodes, blocks, and sizes ++Inode 12 has an invalid extent node (blk 1604, lblk 0) ++Clear? yes ++ ++Inode 12 extent tree (at level 1) could be shorter. Fix? yes ++ ++Inode 12, i_blocks is 18, should be 0. Fix? yes ++ ++Pass 1E: Optimizing extent trees ++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 +--- /dev/null ++++ b/tests/f_extent_leaf_bad_magic/expect.2 +@@ -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 +--- /dev/null ++++ b/tests/f_extent_leaf_bad_magic/name +@@ -0,0 +1 @@ ++bad magic number in leaf extent (metadata_csum) +--- a/tests/f_extent_oobounds/expect.1 ++++ b/tests/f_extent_oobounds/expect.1 +@@ -3,8 +3,11 @@ + (logical block 15, physical block 200, len 30) + Clear? yes + ++Inode 12 extent tree (at (level 1) could be narrower. Fix? yes ++ + Inode 12, i_blocks is 154, should be 94. Fix? yes + ++Pass 1E: Optimizing extent trees + Pass 2: Checking directory structure + Pass 3: Checking directory connectivity + Pass 4: Checking reference counts +@@ -12,13 +15,13 @@ + Block bitmap differences: -(200--229) + Fix? yes + +-Free blocks count wrong for group #0 (156, counted=186). ++Free blocks count wrong for group #0 (158, counted=188). + Fix? yes + +-Free blocks count wrong (156, counted=186). ++Free blocks count wrong (158, counted=188). + Fix? yes + + + test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** +-test_filesys: 12/32 files (8.3% non-contiguous), 70/256 blocks ++test_filesys: 12/32 files (8.3% non-contiguous), 68/256 blocks + Exit status is 1 +--- a/tests/f_extent_oobounds/expect.2 ++++ b/tests/f_extent_oobounds/expect.2 +@@ -3,5 +3,5 @@ + Pass 3: Checking directory connectivity + Pass 4: Checking reference counts + Pass 5: Checking group summary information +-test_filesys: 12/32 files (8.3% non-contiguous), 70/256 blocks ++test_filesys: 12/32 files (8.3% non-contiguous), 68/256 blocks + Exit status is 0 +--- a/tests/f_extent_oobounds/script ++++ b/tests/f_extent_oobounds/script +@@ -7,6 +7,9 @@ + $MKE2FS -Ft ext4 $TMPFILE > /dev/null 2>&1 + $DEBUGFS -w $TMPFILE << EOF > /dev/null 2>&1 + write /dev/null testfile ++setb 100 15 ++setb 130 30 ++setb 200 30 + extent_open testfile + insert_node 0 15 100 + insert_node --after 15 15 115 +@@ -22,9 +25,6 @@ + extent_close + set_inode_field testfile i_size 61400 + set_inode_field testfile i_blocks 154 +-setb 100 15 +-setb 130 30 +-setb 200 30 + set_bg 0 free_blocks_count 156 + set_bg 0 bg_checksum calc + set_super_value free_blocks_count 156 +--- a/tests/f_extents/expect.1 ++++ b/tests/f_extents/expect.1 +@@ -6,15 +6,25 @@ + (logical block 0, invalid physical block 21994527527949, len 17) + Clear? yes + ++Inode 12 extent tree (at level 1) could be shorter. Fix? yes ++ + Inode 12, i_blocks is 34, should be 0. Fix? yes + + Inode 13 missing EXTENT_FL, but is in extents format + Fix? yes + ++Inode 16 has a duplicate extent mapping ++ (logical block 3, invalid physical block 4613, len 2) ++Clear? yes ++ ++Inode 16, i_blocks is 16, should be 12. Fix? yes ++ + Inode 17 has an invalid extent + (logical block 0, invalid physical block 22011707397135, len 15) + Clear? yes + ++Inode 17 extent tree (at level 1) could be shorter. Fix? yes ++ + Inode 17, i_blocks is 32, should be 0. Fix? yes + + Error while reading over extent tree in inode 18: Corrupt extent header +@@ -22,19 +32,23 @@ + + 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 1E: Optimizing extent trees + Pass 2: Checking directory structure + Entry 'fbad-flag' in / (2) has deleted/unused inode 18. Clear? yes + + Pass 3: Checking directory connectivity + Pass 4: Checking reference counts + Pass 5: Checking group summary information +-Block bitmap differences: -1081 +4611 -(5121--5142) ++Block bitmap differences: -1081 +4611 -(4613--4614) -(5121--5142) + Fix? yes + +-Free blocks count wrong for group #0 (7081, counted=7098). ++Free blocks count wrong for group #0 (7081, counted=7100). + Fix? yes + +-Free blocks count wrong (7081, counted=7098). ++Free blocks count wrong (7081, counted=7100). + Fix? yes + + Inode bitmap differences: -18 +@@ -48,5 +62,5 @@ + + + test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** +-test_filesys: 18/256 files (0.0% non-contiguous), 1094/8192 blocks ++test_filesys: 18/256 files (5.6% non-contiguous), 1092/8192 blocks + Exit status is 1 +--- a/tests/f_extents/expect.2 ++++ b/tests/f_extents/expect.2 +@@ -3,5 +3,5 @@ + Pass 3: Checking directory connectivity + Pass 4: Checking reference counts + Pass 5: Checking group summary information +-test_filesys: 18/256 files (0.0% non-contiguous), 1094/8192 blocks ++test_filesys: 18/256 files (5.6% non-contiguous), 1092/8192 blocks + Exit status is 0 +--- a/tests/f_extents2/expect.1 ++++ b/tests/f_extents2/expect.1 +@@ -55,7 +55,7 @@ + Pass 3: Checking directory connectivity + Pass 4: Checking reference counts + Pass 5: Checking group summary information +-Block bitmap differences: -(26--34) -(154--199) ++Block bitmap differences: -(25--33) -(154--199) + Fix? yes + + Free blocks count wrong for group #0 (65535, counted=55). +--- /dev/null ++++ b/tests/f_extent_too_deep/expect.1 +@@ -0,0 +1,23 @@ ++debugfs: ex /a ++Level Entries Logical Physical Length Flags ++ 0/ 7 1/ 1 0 - 0 12 1 ++ 1/ 7 1/ 1 0 - 0 13 1 ++ 2/ 7 1/ 1 0 - 0 14 1 ++ 3/ 7 1/ 1 0 - 0 15 1 ++ 4/ 7 1/ 1 0 - 0 16 1 ++ 5/ 7 1/ 1 0 - 0 17 1 ++ 6/ 7 1/ 1 0 - 0 9 1 ++ 7/ 7 1/ 1 0 - 0 10 - 10 1 ++Pass 1: Checking inodes, blocks, and sizes ++Inode 12 extent tree could be more shallow (7; could be <= 4) ++Fix? yes ++ ++Pass 1E: Optimizing extent trees ++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 +--- /dev/null ++++ b/tests/f_extent_too_deep/expect.2 +@@ -0,0 +1,10 @@ ++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 ++debugfs: ex /a ++Level Entries Logical Physical Length Flags ++ 0/ 0 1/ 1 0 - 0 10 - 10 1 +--- /dev/null ++++ b/tests/f_extent_too_deep/name +@@ -0,0 +1 @@ ++extent tree is deeper than it needs to be +--- /dev/null ++++ b/tests/f_extent_too_deep/script +@@ -0,0 +1,118 @@ ++if [ "$DESCRIPTION"x != x ]; then ++ test_description="$DESCRIPTION" ++fi ++if [ "$IMAGE"x = x ]; then ++ IMAGE=$test_dir/image.gz ++fi ++ ++if [ "$FSCK_OPT"x = x ]; then ++ FSCK_OPT=-yf ++fi ++ ++if [ "$SECOND_FSCK_OPT"x = x ]; then ++ SECOND_FSCK_OPT=-yf ++fi ++ ++if [ "$OUT1"x = x ]; then ++ OUT1=$test_name.1.log ++fi ++ ++if [ "$OUT2"x = x ]; then ++ OUT2=$test_name.2.log ++fi ++ ++if [ "$EXP1"x = x ]; then ++ if [ -f $test_dir/expect.1.gz ]; then ++ EXP1=$test_name.1.tmp ++ gunzip < $test_dir/expect.1.gz > $EXP1 ++ else ++ EXP1=$test_dir/expect.1 ++ fi ++fi ++ ++if [ "$EXP2"x = x ]; then ++ if [ -f $test_dir/expect.2.gz ]; then ++ EXP2=$test_name.2.tmp ++ gunzip < $test_dir/expect.2.gz > $EXP2 ++ else ++ EXP2=$test_dir/expect.2 ++ fi ++fi ++ ++if [ "$SKIP_GUNZIP" != "true" ] ; then ++ gunzip < $IMAGE > $TMPFILE ++fi ++ ++cp /dev/null $OUT1 ++ ++eval $PREP_CMD ++ ++echo 'ex /a' > $TMPFILE.cmd ++$DEBUGFS -f $TMPFILE.cmd $TMPFILE > $OUT1.new 2>&1 ++rm -rf $TMPFILE.cmd ++$FSCK $FSCK_OPT -N test_filesys $TMPFILE >> $OUT1.new 2>&1 ++status=$? ++echo Exit status is $status >> $OUT1.new ++sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT1.new >> $OUT1 ++rm -f $OUT1.new ++ ++if [ "$ONE_PASS_ONLY" != "true" ]; then ++ $FSCK $SECOND_FSCK_OPT -N test_filesys $TMPFILE > $OUT2.new 2>&1 ++ status=$? ++ echo Exit status is $status >> $OUT2.new ++ echo 'ex /a' > $TMPFILE.cmd ++ $DEBUGFS -f $TMPFILE.cmd $TMPFILE >> $OUT2.new 2>&1 ++ rm -rf $TMPFILE.cmd ++ sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT2.new > $OUT2 ++ rm -f $OUT2.new ++fi ++ ++eval $AFTER_CMD ++ ++if [ "$SKIP_VERIFY" != "true" ] ; then ++ rm -f $test_name.ok $test_name.failed ++ cmp -s $OUT1 $EXP1 ++ status1=$? ++ if [ "$ONE_PASS_ONLY" != "true" ]; then ++ cmp -s $OUT2 $EXP2 ++ status2=$? ++ else ++ status2=0 ++ fi ++ if [ "$PASS_ZERO" = "true" ]; then ++ cmp -s $test_name.0.log $test_dir/expect.0 ++ status3=$? ++ else ++ status3=0 ++ fi ++ ++ if [ -z "$test_description" ] ; then ++ description="$test_name" ++ else ++ description="$test_name: $test_description" ++ fi ++ ++ if [ "$status1" -eq 0 -a "$status2" -eq 0 -a "$status3" -eq 0 ] ; then ++ echo "$description: ok" ++ touch $test_name.ok ++ else ++ echo "$description: failed" ++ rm -f $test_name.failed ++ if [ "$PASS_ZERO" = "true" ]; then ++ diff $DIFF_OPTS $test_dir/expect.0 \ ++ $test_name.0.log >> $test_name.failed ++ fi ++ diff $DIFF_OPTS $EXP1 $OUT1 >> $test_name.failed ++ if [ "$ONE_PASS_ONLY" != "true" ]; then ++ diff $DIFF_OPTS $EXP2 $OUT2 >> $test_name.failed ++ fi ++ fi ++ rm -f tmp_expect ++fi ++ ++if [ "$SKIP_CLEANUP" != "true" ] ; then ++ unset IMAGE FSCK_OPT SECOND_FSCK_OPT OUT1 OUT2 EXP1 EXP2 ++ unset SKIP_VERIFY SKIP_CLEANUP SKIP_GUNZIP ONE_PASS_ONLY PREP_CMD ++ unset DESCRIPTION SKIP_UNLINK AFTER_CMD PASS_ZERO ++fi ++ +--- /dev/null ++++ b/tests/f_holedir4/expect.1 +@@ -0,0 +1,68 @@ ++Pass 1: Checking inodes, blocks, and sizes ++Directory inode 12 block 211 should be at block 25. Fix? yes ++ ++Inode 12, i_size is 4096, should be 110592. Fix? yes ++ ++Inode 12, i_blocks is 128, should be 256. Fix? yes ++ ++Pass 2: Checking directory structure ++Directory inode 12 has an unallocated block #2. Allocate? yes ++ ++Directory inode 12 has an unallocated block #3. Allocate? yes ++ ++Directory inode 12 has an unallocated block #4. Allocate? yes ++ ++Directory inode 12 has an unallocated block #5. Allocate? yes ++ ++Directory inode 12 has an unallocated block #6. Allocate? yes ++ ++Directory inode 12 has an unallocated block #7. Allocate? yes ++ ++Directory inode 12 has an unallocated block #8. Allocate? yes ++ ++Directory inode 12 has an unallocated block #9. Allocate? yes ++ ++Directory inode 12 has an unallocated block #10. Allocate? yes ++ ++Directory inode 12 has an unallocated block #11. Allocate? yes ++ ++Directory inode 12 has an unallocated block #12. Allocate? yes ++ ++Directory inode 12 has an unallocated block #13. Allocate? yes ++ ++Directory inode 12 has an unallocated block #14. Allocate? yes ++ ++Directory inode 12 has an unallocated block #15. Allocate? yes ++ ++Directory inode 12 has an unallocated block #16. Allocate? yes ++ ++Directory inode 12 has an unallocated block #17. Allocate? yes ++ ++Directory inode 12 has an unallocated block #18. Allocate? yes ++ ++Directory inode 12 has an unallocated block #19. Allocate? yes ++ ++Directory inode 12 has an unallocated block #20. Allocate? yes ++ ++Directory inode 12 has an unallocated block #21. Allocate? yes ++ ++Directory inode 12 has an unallocated block #22. Allocate? yes ++ ++Directory inode 12 has an unallocated block #23. Allocate? yes ++ ++Directory inode 12 has an unallocated block #24. Allocate? yes ++ ++Pass 3: Checking directory connectivity ++Pass 3A: Optimizing directories ++Pass 4: Checking reference counts ++Pass 5: Checking group summary information ++Free blocks count wrong for group #0 (26, counted=25). ++Fix? yes ++ ++Free blocks count wrong (416, counted=400). ++Fix? yes ++ ++ ++test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** ++test_filesys: 13/32 files (7.7% non-contiguous), 112/512 blocks ++Exit status is 1 +--- /dev/null ++++ b/tests/f_holedir4/expect.2 +@@ -0,0 +1,11 @@ ++Pass 1: Checking inodes, blocks, and sizes ++Inode 12, i_blocks is 3072, should be 128. 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: 13/32 files (0.0% non-contiguous), 112/512 blocks ++Exit status is 1 +--- /dev/null ++++ b/tests/f_holedir4/name +@@ -0,0 +1 @@ ++bigalloc directory with hole and misaligned extent after hole +--- /dev/null ++++ b/tests/f_htree_bad_csum/expect.1 +@@ -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 +--- /dev/null ++++ b/tests/f_htree_bad_csum/expect.2 +@@ -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 +--- /dev/null ++++ b/tests/f_htree_bad_csum/name +@@ -0,0 +1 @@ ++htree block w/ missing/bad csum, bad protective dirent, or htree index corruption (metadata_csum) +--- /dev/null ++++ b/tests/f_htree_leaf_csum/expect.1 +@@ -0,0 +1,12 @@ ++Pass 1: Checking inodes, blocks, and sizes ++Pass 2: Checking directory structure ++Directory inode 12, block #1: directory passes checks but fails checksum. ++Fix? yes ++ ++Pass 3: Checking directory connectivity ++Pass 4: Checking reference counts ++Pass 5: Checking group summary information ++ ++test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** ++test_filesys: 430/512 files (0.2% non-contiguous), 45/512 blocks ++Exit status is 1 +--- /dev/null ++++ b/tests/f_htree_leaf_csum/expect.2 +@@ -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: 430/512 files (0.2% non-contiguous), 45/512 blocks ++Exit status is 0 +--- /dev/null ++++ b/tests/f_htree_leaf_csum/name +@@ -0,0 +1 @@ ++bad csum in htree leaf block +--- /dev/null ++++ b/tests/f_idata_and_extents/expect.1 +@@ -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 +--- /dev/null ++++ b/tests/f_idata_and_extents/expect.2 +@@ -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 +--- /dev/null ++++ b/tests/f_idata_and_extents/name +@@ -0,0 +1 @@ ++conflicting extents and inline_data inode flags +--- a/tests/filter.sed ++++ b/tests/filter.sed +@@ -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 +@@ -13,7 +18,11 @@ + /^Lifetime writes:/d + /^Maximum mount count:/d + /^Next check after:/d ++/^Suggestion:/d + /Reserved blocks uid:/s/ (user .*)// + /Reserved blocks gid:/s/ (group .*)// + /whichever comes first/d + /^ Checksum /d ++s/, csum 0x\([0-9a-f]*\)//g ++s/ csum 0x\([0-9a-f]*\)//g ++/^Checksum:/d +--- /dev/null ++++ b/tests/f_ind_inode_collision/expect.1 +@@ -0,0 +1,147 @@ ++Pass 1: Checking inodes, blocks, and sizes ++Inode 12 block 41 conflicts with critical metadata, skipping block checks. ++Inode 12 block 40 conflicts with critical metadata, skipping block checks. ++Inode 12 block 34 conflicts with critical metadata, skipping block checks. ++Illegal block number passed to ext2fs_test_block_bitmap #16777215 for metadata block map ++Inode 12 block 1 conflicts with critical metadata, skipping block checks. ++Inode 12, i_size is 33, should be 25227264. Fix? yes ++ ++Inode 12, i_blocks is 999, should be 184. 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 2: 3 ++Multiply-claimed block(s) in inode 7: 11 ++Multiply-claimed block(s) in inode 11: 4--7 ++Multiply-claimed block(s) in inode 12: 41 40Illegal block number passed to ext2fs_test_block_bitmap #1421529376 for multiply claimed block map ++Illegal block number passed to ext2fs_test_block_bitmap #1421529376 for multiply claimed block map ++Illegal block number passed to ext2fs_test_block_bitmap #1421529376 for multiply claimed block map ++Illegal block number passed to ext2fs_test_block_bitmap #16877 for multiply claimed block map ++Illegal block number passed to ext2fs_test_block_bitmap #4096 for multiply claimed block map ++Illegal block number passed to ext2fs_test_block_bitmap #1421529376 for multiply claimed block map ++Illegal block number passed to ext2fs_test_block_bitmap #1421529376 for multiply claimed block map ++Illegal block number passed to ext2fs_test_block_bitmap #1421529376 for multiply claimed block map ++Illegal block number passed to ext2fs_test_block_bitmap #196608 for multiply claimed block map ++ 34 8 3Illegal block number passed to ext2fs_test_block_bitmap #1421529376 for multiply claimed block map ++Illegal block number passed to ext2fs_test_block_bitmap #33152 for multiply claimed block map ++Illegal block number passed to ext2fs_test_block_bitmap #4243456 for multiply claimed block map ++Illegal block number passed to ext2fs_test_block_bitmap #1421529376 for multiply claimed block map ++Illegal block number passed to ext2fs_test_block_bitmap #1421529376 for multiply claimed block map ++Illegal block number passed to ext2fs_test_block_bitmap #1421529376 for multiply claimed block map ++Illegal block number passed to ext2fs_test_block_bitmap #65536 for multiply claimed block map ++ 28 8 11 1Illegal block number passed to ext2fs_test_block_bitmap #1421529376 for multiply claimed block map ++Illegal block number passed to ext2fs_test_block_bitmap #16832 for multiply claimed block map ++Illegal block number passed to ext2fs_test_block_bitmap #16384 for multiply claimed block map ++Illegal block number passed to ext2fs_test_block_bitmap #1421529376 for multiply claimed block map ++Illegal block number passed to ext2fs_test_block_bitmap #1421529376 for multiply claimed block map ++Illegal block number passed to ext2fs_test_block_bitmap #1421529376 for multiply claimed block map ++Illegal block number passed to ext2fs_test_block_bitmap #131072 for multiply claimed block map ++ 28 4--7Illegal block number passed to ext2fs_test_block_bitmap #1421529376 for multiply claimed block map ++Illegal block number passed to ext2fs_test_block_bitmap #33206 for multiply claimed block map ++Illegal block number passed to ext2fs_test_block_bitmap #25227264 for multiply claimed block map ++Illegal block number passed to ext2fs_test_block_bitmap #1421529397 for multiply claimed block map ++Illegal block number passed to ext2fs_test_block_bitmap #1421529397 for multiply claimed block map ++Illegal block number passed to ext2fs_test_block_bitmap #1421529397 for multiply claimed block map ++Illegal block number passed to ext2fs_test_block_bitmap #65536 for multiply claimed block map ++ 28 41Illegal block number passed to ext2fs_test_block_bitmap #1421529397 for multiply claimed block map ++Illegal block number passed to ext2fs_test_block_bitmap #16777215 for multiply claimed block map ++ 28 ++Error while iterating over blocks in inode 12 (pass1b): Illegal indirect block found ++Pass 1C: Scanning directories for inodes with multiply-claimed blocks ++Pass 1D: Reconciling multiply-claimed blocks ++(There are 3 inodes containing multiply-claimed blocks.) ++ ++File / (inode #2, mod time Sat Jan 17 21:16:16 2015) ++ has 1 multiply-claimed block(s), shared with 1 file(s): ++ /a (inode #12, mod time Sat Jan 17 21:16:37 2015) ++Clone multiply-claimed blocks? yes ++ ++File /lost+found (inode #11, mod time Sat Jan 17 21:16:16 2015) ++ has 4 multiply-claimed block(s), shared with 1 file(s): ++ /a (inode #12, mod time Sat Jan 17 21:16:37 2015) ++Clone multiply-claimed blocks? yes ++ ++File /a (inode #12, mod time Sat Jan 17 21:16:37 2015) ++ has 17 multiply-claimed block(s), shared with 4 file(s): ++ ++ /lost+found (inode #11, mod time Sat Jan 17 21:16:16 2015) ++ (inode #7, mod time Sat Jan 17 21:16:16 2015) ++ / (inode #2, mod time Sat Jan 17 21:16:16 2015) ++Clone multiply-claimed blocks? yes ++ ++Illegal block number passed to ext2fs_test_block_bitmap #1421529376 for multiply claimed block map ++Illegal block number passed to ext2fs_test_block_bitmap #1421529376 for multiply claimed block map ++Illegal block number passed to ext2fs_test_block_bitmap #1421529376 for multiply claimed block map ++Illegal block number passed to ext2fs_test_block_bitmap #16877 for multiply claimed block map ++Illegal block number passed to ext2fs_test_block_bitmap #4096 for multiply claimed block map ++Illegal block number passed to ext2fs_test_block_bitmap #1421529376 for multiply claimed block map ++Illegal block number passed to ext2fs_test_block_bitmap #1421529376 for multiply claimed block map ++Illegal block number passed to ext2fs_test_block_bitmap #1421529376 for multiply claimed block map ++Illegal block number passed to ext2fs_test_block_bitmap #196608 for multiply claimed block map ++Illegal block number passed to ext2fs_test_block_bitmap #1421529376 for multiply claimed block map ++Illegal block number passed to ext2fs_test_block_bitmap #33152 for multiply claimed block map ++Illegal block number passed to ext2fs_test_block_bitmap #4243456 for multiply claimed block map ++Illegal block number passed to ext2fs_test_block_bitmap #1421529376 for multiply claimed block map ++Illegal block number passed to ext2fs_test_block_bitmap #1421529376 for multiply claimed block map ++Illegal block number passed to ext2fs_test_block_bitmap #1421529376 for multiply claimed block map ++Illegal block number passed to ext2fs_test_block_bitmap #65536 for multiply claimed block map ++Illegal block number passed to ext2fs_test_block_bitmap #1421529376 for multiply claimed block map ++Illegal block number passed to ext2fs_test_block_bitmap #16832 for multiply claimed block map ++Illegal block number passed to ext2fs_test_block_bitmap #16384 for multiply claimed block map ++Illegal block number passed to ext2fs_test_block_bitmap #1421529376 for multiply claimed block map ++Illegal block number passed to ext2fs_test_block_bitmap #1421529376 for multiply claimed block map ++Illegal block number passed to ext2fs_test_block_bitmap #1421529376 for multiply claimed block map ++Illegal block number passed to ext2fs_test_block_bitmap #131072 for multiply claimed block map ++Illegal block number passed to ext2fs_test_block_bitmap #1421529376 for multiply claimed block map ++Illegal block number passed to ext2fs_test_block_bitmap #33206 for multiply claimed block map ++Illegal block number passed to ext2fs_test_block_bitmap #25227264 for multiply claimed block map ++Illegal block number passed to ext2fs_test_block_bitmap #1421529397 for multiply claimed block map ++Illegal block number passed to ext2fs_test_block_bitmap #1421529397 for multiply claimed block map ++Illegal block number passed to ext2fs_test_block_bitmap #1421529397 for multiply claimed block map ++Illegal block number passed to ext2fs_test_block_bitmap #65536 for multiply claimed block map ++Illegal block number passed to ext2fs_test_block_bitmap #1421529397 for multiply claimed block map ++Illegal block number passed to ext2fs_test_block_bitmap #16777215 for multiply claimed block map ++Pass 2: Checking directory structure ++Restarting e2fsck from the beginning... ++Pass 1: Checking inodes, blocks, and sizes ++Inode 12 has illegal block(s). Clear? yes ++ ++Illegal block #1038 (1421529376) in inode 12. CLEARED. ++Illegal block #1039 (1421529376) in inode 12. CLEARED. ++Illegal block #1040 (1421529376) in inode 12. CLEARED. ++Illegal block #1100 (16877) in inode 12. CLEARED. ++Illegal block #1101 (4096) in inode 12. CLEARED. ++Illegal block #1102 (1421529376) in inode 12. CLEARED. ++Illegal block #1103 (1421529376) in inode 12. CLEARED. ++Illegal block #1104 (1421529376) in inode 12. CLEARED. ++Illegal block #1106 (196608) in inode 12. CLEARED. ++Illegal block #1136 (1421529376) in inode 12. CLEARED. ++Illegal block #1420 (33152) in inode 12. CLEARED. ++Too many illegal blocks in inode 12. ++Clear inode? yes ++ ++Restarting e2fsck from the beginning... ++Pass 1: Checking inodes, blocks, and sizes ++Pass 2: Checking directory structure ++Entry 'a' in / (2) has deleted/unused inode 12. Clear? yes ++ ++Pass 3: Checking directory connectivity ++Pass 4: Checking reference counts ++Pass 5: Checking group summary information ++Block bitmap differences: -(3--7) -(15--17) -(19--24) ++Fix? yes ++ ++Inode bitmap differences: -12 ++Fix? yes ++ ++Free inodes count wrong for group #0 (116, counted=117). ++Fix? yes ++ ++Free inodes count wrong (116, counted=117). ++Fix? yes ++ ++ ++test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** ++test_filesys: 11/128 files (9.1% non-contiguous), 18/512 blocks ++Exit status is 1 +--- /dev/null ++++ b/tests/f_ind_inode_collision/expect.2 +@@ -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), 18/512 blocks ++Exit status is 0 +--- /dev/null ++++ b/tests/f_ind_inode_collision/name +@@ -0,0 +1 @@ ++multiple *ind collisions with critical metadata +--- /dev/null ++++ b/tests/f_inlinedata_dirblocks/expect.1 +@@ -0,0 +1,25 @@ ++Pass 1: Checking inodes, blocks, and sizes ++Pass 2: Checking directory structure ++Entry '..' in ??? (12) has invalid inode #: 1752440867. ++Clear? yes ++ ++Directory inode 12, block #0, offset 4: directory corrupted ++Salvage? yes ++ ++Directory inode 12, block #1, offset 0: directory corrupted ++Salvage? yes ++ ++Pass 3: Checking directory connectivity ++'..' in /aoo (12) is ??? (1752440867), should be / (2). ++Fix? yes ++ ++Error while adjusting inode count on inode 0 ++Pass 4: Checking reference counts ++Pass 5: Checking group summary information ++Directories count wrong for group #0 (2, counted=3). ++Fix? yes ++ ++ ++test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** ++test_filesys: 12/128 files (0.0% non-contiguous), 17/512 blocks ++Exit status is 1 +--- /dev/null ++++ b/tests/f_inlinedata_dirblocks/expect.2 +@@ -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), 17/512 blocks ++Exit status is 0 +--- /dev/null ++++ b/tests/f_inlinedata_dirblocks/name +@@ -0,0 +1 @@ ++check inline dir as two dirent blocks +--- /dev/null ++++ b/tests/f_inlinedata_repair/expect.1 +@@ -0,0 +1,58 @@ ++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 ++ ++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 ++ ++Symlink /1 (inode #12) is invalid. ++Clear? yes ++ ++Symlink /3 (inode #14) is invalid. ++Clear? yes ++ ++Inode 38 (/B) has invalid mode (00). ++Clear? yes ++ ++Inode 36 (/A) has invalid mode (00). ++Clear? yes ++ ++Pass 3: Checking directory connectivity ++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 ++ ++Pass 5: Checking group summary information ++ ++test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** ++test_filesys: 26/128 files (0.0% non-contiguous), 18/512 blocks ++Exit status is 1 +--- /dev/null ++++ b/tests/f_inlinedata_repair/expect.2 +@@ -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: 26/128 files (0.0% non-contiguous), 18/512 blocks ++Exit status is 0 +--- /dev/null ++++ b/tests/f_inlinedata_repair/name +@@ -0,0 +1 @@ ++repair corrupt inline data files +--- /dev/null ++++ b/tests/f_inlinedir_detector/expect.1 +@@ -0,0 +1,20 @@ ++Pass 1: Checking inodes, blocks, and sizes ++Special (device/socket/fifo) file (inode 12) has extents ++or inline-data flag set. Clear? yes ++ ++Special (device/socket/fifo) inode 12 has non-zero size. Fix? yes ++ ++Inode 13 is a named pipe but it looks like it is really a directory. ++Fix? yes ++ ++Pass 2: Checking directory structure ++Entry 'moo' in / (2) has an incorrect filetype (was 1, should be 5). ++Fix? yes ++ ++Pass 3: Checking directory connectivity ++Pass 4: Checking reference counts ++Pass 5: Checking group summary information ++ ++test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** ++test_filesys: 13/128 files (0.0% non-contiguous), 17/512 blocks ++Exit status is 1 +--- /dev/null ++++ b/tests/f_inlinedir_detector/expect.2 +@@ -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: 13/128 files (0.0% non-contiguous), 17/512 blocks ++Exit status is 0 +--- /dev/null ++++ b/tests/f_inlinedir_detector/name +@@ -0,0 +1 @@ ++detect inline dirs correctly +--- /dev/null ++++ b/tests/f_inode_ea_collision/expect.1 +@@ -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 +--- /dev/null ++++ b/tests/f_inode_ea_collision/expect.2 +@@ -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 +--- /dev/null ++++ b/tests/f_inode_ea_collision/name +@@ -0,0 +1 @@ ++collisions in the inode ea area +--- /dev/null ++++ b/tests/f_itable_collision/expect.1 +@@ -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): ++ ++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 +--- /dev/null ++++ b/tests/f_itable_collision/expect.2 +@@ -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 +--- /dev/null ++++ b/tests/f_itable_collision/name +@@ -0,0 +1 @@ ++collision between IND/extent tree blocks and inode table +--- /dev/null ++++ b/tests/f_itable_collision/script +@@ -0,0 +1,37 @@ ++#!/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 ++ ++# 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 -N test_filesys $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 -N test_filesys $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 +--- a/tests/f_jnl_64bit/expect.0 ++++ b/tests/f_jnl_64bit/expect.0 +@@ -1,189 +1,97 @@ + 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 @@ + 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: +--- a/tests/f_jnl_errno/expect.0 ++++ b/tests/f_jnl_errno/expect.0 +@@ -40,7 +40,8 @@ + Group 0: (Blocks 1-8191) [ITABLE_ZEROED] + Primary superblock at 1, Group descriptors at 2-2 + Reserved GDT blocks at 3-33 +- Block bitmap at 34 (+33), Inode bitmap at 50 (+49) ++ Block bitmap at 34 (+33) ++ Inode bitmap at 50 (+49) + Inode table at 66-321 (+65) + 6862 free blocks, 2037 free inodes, 2 directories, 2037 unused inodes + Free blocks: 1330-8191 +--- /dev/null ++++ b/tests/f_jnl_etb_alloc_fail/expect.1 +@@ -0,0 +1,31 @@ ++Superblock has an invalid journal (inode 8). ++Clear? yes ++ ++*** journal has been deleted *** ++ ++Superblock has_journal flag is clear, but a journal is present. ++Clear? yes ++ ++Pass 1: Checking inodes, blocks, and sizes ++Journal inode is not in use, but contains data. Clear? 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: -(32--33) -(35--49) -(83--511) -(513--1087) -1089 ++Fix? yes ++ ++Free blocks count wrong for group #0 (0, counted=1022). ++Fix? yes ++ ++Free blocks count wrong (0, counted=1022). ++Fix? yes ++ ++Recreate journal? yes ++ ++Creating journal (1024 blocks): Could not allocate block in ext2 filesystem: while trying to create journal ++ ++test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** ++test_filesys: 12/128 files (8.3% non-contiguous), 2048/2048 blocks ++Exit status is 1 +--- /dev/null ++++ b/tests/f_jnl_etb_alloc_fail/expect.2 +@@ -0,0 +1,20 @@ ++Pass 1: Checking inodes, blocks, and sizes ++Journal inode is not in use, but contains data. Clear? 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: -(32--33) -(35--49) -(83--511) -(513--1087) -1089 ++Fix? yes ++ ++Free blocks count wrong for group #0 (0, counted=1022). ++Fix? yes ++ ++Free blocks count wrong (0, counted=1022). ++Fix? yes ++ ++ ++test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** ++test_filesys: 12/128 files (8.3% non-contiguous), 1026/2048 blocks ++Exit status is 1 +--- /dev/null ++++ b/tests/f_jnl_etb_alloc_fail/name +@@ -0,0 +1 @@ ++can't allocate extent tree block while recreating journal +--- a/tests/f_miss_journal/expect.1 ++++ b/tests/f_miss_journal/expect.1 +@@ -1,7 +1,7 @@ + Superblock has an invalid journal (inode 8). + Clear? yes + +-*** ext3 journal has been deleted - filesystem is now ext2 only *** ++*** journal has been deleted *** + + Pass 1: Checking inodes, blocks, and sizes + Pass 2: Checking directory structure +@@ -21,7 +21,7 @@ + + Creating journal (1024 blocks): Done. + +-*** journal has been re-created - filesystem is now ext3 again *** ++*** journal has been regenerated *** + + test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** + test_filesys: 11/256 files (0.0% non-contiguous), 1079/2048 blocks +--- /dev/null ++++ b/tests/f_no/expect +@@ -0,0 +1,48 @@ ++Pass 1: Checking inodes, blocks, and sizes ++Inode 12 has an invalid extent ++ (logical block 0, invalid physical block 999999999, len 1) ++Clear? no ++Inode 12 has an invalid extent ++ (logical block 1, invalid physical block 9999999999, len 1) ++Clear? no ++Inode 13 is in use, but has dtime set. Fix? no ++Inode 13 has an invalid extent ++ (logical block 1, invalid physical block 8888888888888, len 1) ++Clear? no ++Inode 13 has an invalid extent ++ (logical block 0, invalid physical block 888888888888, len 1) ++Clear? no ++Inode 14 is in use, but has dtime set. Fix? no ++Inode 14 has an invalid extent ++ (logical block 300, invalid physical block 777777777777, len 300) ++Clear? no ++Inode 14 has an invalid extent ++ (logical block 0, invalid physical block 7777777777, len 1) ++Clear? no ++Inode 14, i_blocks is 52574694748113, should be 0. Fix? no ++Pass 2: Checking directory structure ++Extended attribute block for inode 12 (/a) is invalid (999999). ++Clear? no ++Extended attribute block for inode 13 (/b) is invalid (298954296). ++Clear? no ++Extended attribute block for inode 14 (/c) is invalid (388697201). ++Clear? no ++Pass 3: Checking directory connectivity ++Pass 4: Checking reference counts ++Inode 12 ref count is 34463, should be 1. Fix? no ++Inode 13 ref count is 9999, should be 1. Fix? no ++Inode 14 ref count is 12241, should be 1. Fix? no ++Pass 5: Checking group summary information ++Block bitmap differences: -202 -381 -457 ++Fix? no ++Free blocks count wrong for group #0 (0, counted=491). ++Fix? no ++Free blocks count wrong (494, counted=491). ++Fix? no ++Free inodes count wrong for group #0 (4294967293, counted=114). ++Fix? no ++ ++test_filesys: ********** WARNING: Filesystem still has errors ********** ++ ++test_filesys: 14/128 files (0.0% non-contiguous), 18/512 blocks ++Exit status is 4 +--- /dev/null ++++ b/tests/f_no/script +@@ -0,0 +1,27 @@ ++test_description="e2fsck with repeated no" ++FSCK_OPT=-f ++OUT=$test_name.log ++EXP=$test_dir/expect ++ ++gunzip < $test_dir/../f_yesall/image.gz > $TMPFILE ++ ++rm -rf $OUT ++echo "nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn" | E2FSCK_FORCE_INTERACTIVE=y $FSCK $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 ++rm -f $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 ++ rm -f tmp_expect ++fi ++ ++unset IMAGE FSCK_OPT OUT EXP +--- /dev/null ++++ b/tests/f_no_cache_corrupt_inode/expect.1 +@@ -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 +--- /dev/null ++++ b/tests/f_no_cache_corrupt_inode/expect.2 +@@ -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 +--- /dev/null ++++ b/tests/f_no_cache_corrupt_inode/name +@@ -0,0 +1 @@ ++don't cache inodes that fail checksum verification +--- /dev/null ++++ b/tests/f_nospc_create_lnf/expect.1 +@@ -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 +--- /dev/null ++++ b/tests/f_nospc_create_lnf/expect.2 +@@ -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 +--- /dev/null ++++ b/tests/f_nospc_create_lnf/name +@@ -0,0 +1 @@ ++no space to create lost+found +--- /dev/null ++++ b/tests/f_opt_extent/expect +@@ -0,0 +1,55 @@ ++tune2fs metadata_csum test ++Creating filesystem with 524288 1k blocks and 65536 inodes ++Superblock backups stored on blocks: ++ 8193, 24577, 40961, 57345, 73729, 204801, 221185, 401409 ++ ++Allocating group tables: done ++Writing inode tables: done ++Creating journal (16384 blocks): done ++Creating 477 huge file(s) with 1024 blocks each: done ++Writing superblocks and filesystem accounting information: done ++ ++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 ++ ++Exit status is 0 ++Pass 1: Checking inodes, blocks, and sizes ++Pass 2: Checking directory structure ++Pass 3: Checking directory connectivity ++Pass 3A: Optimizing directories ++Pass 4: Checking reference counts ++Pass 5: Checking group summary information ++ ++ ++ ++Change in FS metadata: ++@@ -10,7 +10,7 @@ ++ Inode count: 65536 ++ Block count: 524288 ++ Reserved block count: 26214 ++-Free blocks: 570 +++Free blocks: 567 ++ Free inodes: 65047 ++ First block: 1 ++ Block size: 1024 ++@@ -47,8 +47,8 @@ ++ Block bitmap at 262 (+261) ++ Inode bitmap at 278 (+277) ++ Inode table at 294-549 (+293) ++- 21 free blocks, 535 free inodes, 3 directories, 535 unused inodes ++- Free blocks: 4414-4434 +++ 18 free blocks, 535 free inodes, 3 directories, 535 unused inodes +++ Free blocks: 4417-4434 ++ Free inodes: 490-1024 ++ Group 1: (Blocks 8193-16384) [INODE_UNINIT] ++ Backup superblock at 8193, Group descriptors at 8194-8197 ++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 ++ ++Exit status is 0 +--- /dev/null ++++ b/tests/f_opt_extent/name +@@ -0,0 +1 @@ ++optimize extent tree +--- /dev/null ++++ b/tests/f_opt_extent/script +@@ -0,0 +1,64 @@ ++FSCK_OPT=-fn ++OUT=$test_name.log ++EXP=$test_dir/expect ++CONF=$TMPFILE.conf ++ ++cat > $CONF << ENDL ++[fs_types] ++ ext4h = { ++ features = has_journal,extent,huge_file,flex_bg,uninit_bg,dir_nlink,extra_isize,sparse_super,filetype,dir_index,ext_attr,resize_inode,64bit,metadata_csum ++ blocksize = 1024 ++ inode_size = 256 ++ make_hugefiles = true ++ hugefiles_dir = /xyz ++ hugefiles_slack = 0 ++ hugefiles_name = aaaaa ++ hugefiles_digits = 4 ++ hugefiles_size = 1M ++ zero_hugefiles = false ++ } ++ENDL ++ ++echo "tune2fs metadata_csum test" > $OUT ++ ++MKE2FS_CONFIG=$CONF $MKE2FS -F -T ext4h $TMPFILE 524288 >> $OUT 2>&1 ++rm -rf $CONF ++ ++# dump and check ++$DUMPE2FS $TMPFILE 2> /dev/null | grep '^Group 0:' -B99 -A20 | sed -f $cmd_dir/filter.sed > $OUT.before ++$FSCK $FSCK_OPT -N test_filesys $TMPFILE >> $OUT 2>&1 ++status=$? ++echo Exit status is $status >> $OUT ++ ++# check ++$FSCK -fyD -N test_filesys $TMPFILE >> $OUT 2>&1 ++ ++# dump and check ++$DUMPE2FS $TMPFILE 2> /dev/null | grep '^Group 0:' -B99 -A20 | sed -f $cmd_dir/filter.sed > $OUT.after ++echo "Change in FS metadata:" >> $OUT ++diff -u $OUT.before $OUT.after | tail -n +3 >> $OUT ++$FSCK $FSCK_OPT -N test_filesys $TMPFILE >> $OUT 2>&1 ++status=$? ++echo Exit status is $status >> $OUT ++ ++rm $TMPFILE $OUT.before $OUT.after ++ ++# ++# Do the verification ++# ++ ++sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" -e 's/test_filesys:.*//g' < $OUT > $OUT.new ++mv $OUT.new $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 IMAGE FSCK_OPT OUT EXP CONF +--- /dev/null ++++ b/tests/f_opt_extent_ext3/expect +@@ -0,0 +1,44 @@ ++rebuild extent metadata_csum test ++Creating filesystem with 524288 1k blocks and 65536 inodes ++Superblock backups stored on blocks: ++ 8193, 24577, 40961, 57345, 73729, 204801, 221185, 401409 ++ ++Allocating group tables: done ++Writing inode tables: done ++Creating journal (16384 blocks): done ++mke2fs: Operation not supported for inodes containing extents while creating huge files ++Writing superblocks and filesystem accounting information: done ++ ++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 ++ ++Exit status is 0 ++Pass 1: Checking inodes, blocks, and sizes ++Pass 2: Checking directory structure ++Pass 3: Checking directory connectivity ++Pass 3A: Optimizing directories ++Pass 4: Checking reference counts ++Pass 5: Checking group summary information ++ ++ ++ ++Change in FS metadata: ++@@ -2,7 +2,7 @@ ++ Last mounted on: ++ Filesystem magic number: 0xEF53 ++ Filesystem revision #: 1 (dynamic) ++-Filesystem features: has_journal ext_attr resize_inode dir_index filetype sparse_super large_file huge_file dir_nlink +++Filesystem features: has_journal ext_attr resize_inode dir_index filetype extent sparse_super large_file huge_file dir_nlink ++ Default mount options: user_xattr acl ++ Filesystem state: clean ++ Errors behavior: Continue ++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 ++ ++Exit status is 0 +--- /dev/null ++++ b/tests/f_opt_extent_ext3/name +@@ -0,0 +1 @@ ++convert ext3 to extent tree +--- /dev/null ++++ b/tests/f_opt_extent_ext3/script +@@ -0,0 +1,65 @@ ++FSCK_OPT=-fn ++OUT=$test_name.log ++EXP=$test_dir/expect ++CONF=$TMPFILE.conf ++ ++cat > $CONF << ENDL ++[fs_types] ++ ext4h = { ++ features = has_journal,^extent,huge_file,^flex_bg,^uninit_bg,dir_nlink,^extra_isize,sparse_super,filetype,dir_index,ext_attr,resize_inode,^64bit,^metadata_csum ++ blocksize = 1024 ++ inode_size = 256 ++ make_hugefiles = true ++ hugefiles_dir = / ++ num_hugefiles = 100 ++ hugefiles_slack = 0 ++ hugefiles_name = aaaaa ++ hugefiles_digits = 4 ++ hugefiles_size = 1M ++ zero_hugefiles = false ++ } ++ENDL ++ ++echo "rebuild extent metadata_csum test" > $OUT ++ ++MKE2FS_CONFIG=$CONF $MKE2FS -F -T ext4h $TMPFILE 524288 >> $OUT 2>&1 ++rm -rf $CONF ++ ++# dump and check ++$DUMPE2FS $TMPFILE 2> /dev/null | grep '^Group 0:' -B99 -A20 | sed -f $cmd_dir/filter.sed > $OUT.before ++$FSCK $FSCK_OPT -N test_filesys $TMPFILE >> $OUT 2>&1 ++status=$? ++echo Exit status is $status >> $OUT ++ ++# check ++$FSCK -fyD -N test_filesys -E bmap2extent $TMPFILE >> $OUT 2>&1 ++ ++# dump and check ++$DUMPE2FS $TMPFILE 2> /dev/null | grep '^Group 0:' -B99 -A20 | sed -f $cmd_dir/filter.sed > $OUT.after ++echo "Change in FS metadata:" >> $OUT ++diff -u $OUT.before $OUT.after | tail -n +3 >> $OUT ++$FSCK $FSCK_OPT -N test_filesys $TMPFILE >> $OUT 2>&1 ++status=$? ++echo Exit status is $status >> $OUT ++ ++rm $TMPFILE $OUT.before $OUT.after ++ ++# ++# Do the verification ++# ++ ++sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" -e 's/test_filesys:.*//g' < $OUT > $OUT.new ++mv $OUT.new $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 IMAGE FSCK_OPT OUT EXP CONF +--- /dev/null ++++ b/tests/f_rebuild_csum_rootdir/expect.1 +@@ -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 (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 +--- /dev/null ++++ b/tests/f_rebuild_csum_rootdir/expect.2 +@@ -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 +--- /dev/null ++++ b/tests/f_rebuild_csum_rootdir/name +@@ -0,0 +1 @@ ++force fsck to rebuild a corrupted rootdir w/ metadata_csum +--- /dev/null ++++ b/tests/f_short_encrypted_dirent/expect.1 +@@ -0,0 +1,17 @@ ++Pass 1: Checking inodes, blocks, and sizes ++Pass 2: Checking directory structure ++Encrypted entry 'motd' in /get_shorty (12) is too short. ++Clear? yes ++ ++Pass 3: Checking directory connectivity ++Pass 4: Checking reference counts ++Unattached inode 13 ++Connect to /lost+found? yes ++ ++Inode 13 ref count is 2, should be 1. Fix? yes ++ ++Pass 5: Checking group summary information ++ ++test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** ++test_filesys: 13/16 files (0.0% non-contiguous), 23/100 blocks ++Exit status is 1 +--- /dev/null ++++ b/tests/f_short_encrypted_dirent/expect.2 +@@ -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: 13/16 files (0.0% non-contiguous), 23/100 blocks ++Exit status is 0 +--- /dev/null ++++ b/tests/f_short_encrypted_dirent/name +@@ -0,0 +1 @@ ++short encrypted directory entry +--- /dev/null ++++ b/tests/f_super_bad_csum/expect.1 +@@ -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 +--- /dev/null ++++ b/tests/f_super_bad_csum/expect.2 +@@ -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 +--- /dev/null ++++ b/tests/f_super_bad_csum/name +@@ -0,0 +1 @@ ++bad csum in superblock (metadata_csum) +--- /dev/null ++++ b/tests/f_super_bad_csum/script +@@ -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 +--- /dev/null ++++ b/tests/f_trunc_dirent_header/expect.1 +@@ -0,0 +1,15 @@ ++Pass 1: Checking inodes, blocks, and sizes ++Pass 2: Checking directory structure ++Directory inode 15, block #0, offset 4092: directory corrupted ++Salvage? yes ++ ++Directory inode 13, block #1, offset 28: directory corrupted ++Salvage? yes ++ ++Pass 3: Checking directory connectivity ++Pass 4: Checking reference counts ++Pass 5: Checking group summary information ++ ++test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** ++test_filesys: 32/128 files (0.0% non-contiguous), 18/512 blocks ++Exit status is 1 +--- /dev/null ++++ b/tests/f_trunc_dirent_header/expect.2 +@@ -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: 32/128 files (0.0% non-contiguous), 18/512 blocks ++Exit status is 0 +--- /dev/null ++++ b/tests/f_trunc_dirent_header/name +@@ -0,0 +1 @@ ++no space for dirent header at end of buf +--- /dev/null ++++ b/tests/f_uninit_cat/name +@@ -0,0 +1 @@ ++cat a file with uninit blocks +--- /dev/null ++++ b/tests/f_uninit_cat/script +@@ -0,0 +1,37 @@ ++#!/bin/bash ++ ++if test -x $DEBUGFS_EXE; then ++FSCK_OPT=-fy ++IMAGE=$test_dir/image.gz ++ ++gzip -d < $IMAGE > $TMPFILE ++#e2label $TMPFILE test_filesys ++ ++# Run fsck to fix things? ++EXP=$test_dir/expect ++OUT=$test_name.log ++rm -rf $test_name.failed $test_name.ok ++ ++$FSCK $FSCK_OPT -N test_filesys $TMPFILE 2>&1 | sed -f $cmd_dir/filter.sed > $OUT ++echo "Exit status is $?" >> $OUT ++ ++echo "debugfs cat uninit file" >> $OUT ++echo "ex /a" > $TMPFILE.cmd ++echo "cat /a" >> $TMPFILE.cmd ++$DEBUGFS_EXE -w -f $TMPFILE.cmd $TMPFILE >> $OUT.new 2>&1 ++echo >> $OUT.new ++sed -f $cmd_dir/filter.sed < $OUT.new >> $OUT ++rm -rf $OUT.new $TMPFILE ++ ++# Figure out what happened ++if cmp -s $EXP $OUT; then ++ echo "$test_name: $test_description: ok" ++ touch $test_name.ok ++else ++ echo "$test_name: $test_description: failed" ++ diff -u $EXP $OUT >> $test_name.failed ++fi ++unset EXP OUT FSCK_OPT IMAGE ++else #if test -a -x $DEBUGFS_EXE; then ++ echo "$test_name: $test_description: skipped" ++fi +--- /dev/null ++++ b/tests/f_write_ea_no_extra_isize/expect.1 +@@ -0,0 +1,12 @@ ++Pass 1: Checking inodes, blocks, and sizes ++Pass 2: Checking directory structure ++Directory inode 12, block #0, offset 4: directory corrupted ++Salvage? yes ++ ++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), 17/512 blocks ++Exit status is 1 +--- /dev/null ++++ b/tests/f_write_ea_no_extra_isize/expect.2 +@@ -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), 17/512 blocks ++Exit status is 0 +--- /dev/null ++++ b/tests/f_write_ea_no_extra_isize/name +@@ -0,0 +1 @@ ++write EA when i_extra_size is zero +--- /dev/null ++++ b/tests/f_write_ea_toobig_extra_isize/expect.1 +@@ -0,0 +1,12 @@ ++Pass 1: Checking inodes, blocks, and sizes ++Pass 2: Checking directory structure ++Directory inode 12, block #0, offset 4: directory corrupted ++Salvage? yes ++ ++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), 17/512 blocks ++Exit status is 1 +--- /dev/null ++++ b/tests/f_write_ea_toobig_extra_isize/expect.2 +@@ -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), 17/512 blocks ++Exit status is 0 +--- /dev/null ++++ b/tests/f_write_ea_toobig_extra_isize/name +@@ -0,0 +1 @@ ++write EA when i_extra_size is too big for EA +--- /dev/null ++++ b/tests/f_write_ea_toosmall_extra_isize/expect.1 +@@ -0,0 +1,15 @@ ++Pass 1: Checking inodes, blocks, and sizes ++Inode 12 has a extra size (1) which is invalid ++Fix? yes ++ ++Pass 2: Checking directory structure ++Directory inode 12, block #0, offset 4: directory corrupted ++Salvage? yes ++ ++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), 17/512 blocks ++Exit status is 1 +--- /dev/null ++++ b/tests/f_write_ea_toosmall_extra_isize/expect.2 +@@ -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), 17/512 blocks ++Exit status is 0 +--- /dev/null ++++ b/tests/f_write_ea_toosmall_extra_isize/name +@@ -0,0 +1 @@ ++write EA when i_extra_size is too small to make sense +--- /dev/null ++++ b/tests/f_yes/expect +@@ -0,0 +1,45 @@ ++Pass 1: Checking inodes, blocks, and sizes ++Inode 12 has an invalid extent ++ (logical block 0, invalid physical block 999999999, len 1) ++Clear? yes ++Inode 12 has an invalid extent ++ (logical block 1, invalid physical block 9999999999, len 1) ++Clear? yes ++Inode 13 is in use, but has dtime set. Fix? yes ++Inode 13 has an invalid extent ++ (logical block 1, invalid physical block 8888888888888, len 1) ++Clear? yes ++Inode 13 has an invalid extent ++ (logical block 0, invalid physical block 888888888888, len 1) ++Clear? yes ++Inode 14 is in use, but has dtime set. Fix? yes ++Inode 14 has an invalid extent ++ (logical block 300, invalid physical block 777777777777, len 300) ++Clear? yes ++Inode 14 has an invalid extent ++ (logical block 0, invalid physical block 7777777777, len 1) ++Clear? yes ++Inode 14, i_blocks is 52574694748113, should be 0. Fix? yes ++Pass 2: Checking directory structure ++Extended attribute block for inode 12 (/a) is invalid (999999). ++Clear ('a' enables 'yes' to all) ? yes ++Extended attribute block for inode 13 (/b) is invalid (298954296). ++Clear ('a' enables 'yes' to all) ? yes ++Extended attribute block for inode 14 (/c) is invalid (388697201). ++Clear ('a' enables 'yes' to all) ? yes ++Pass 3: Checking directory connectivity ++Pass 4: Checking reference counts ++Inode 12 ref count is 34463, should be 1. Fix ('a' enables 'yes' to all) ? yes ++Inode 13 ref count is 9999, should be 1. Fix? yes ++Inode 14 ref count is 12241, should be 1. Fix? yes ++Pass 5: Checking group summary information ++Block bitmap differences: -202 -381 -457 ++Fix? yes ++Free blocks count wrong for group #0 (0, counted=494). ++Fix? yes ++Free inodes count wrong for group #0 (4294967293, counted=114). ++Fix? yes ++ ++test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** ++test_filesys: 14/128 files (0.0% non-contiguous), 18/512 blocks ++Exit status is 1 +--- /dev/null ++++ b/tests/f_yes/script +@@ -0,0 +1,27 @@ ++test_description="e2fsck with repeated yes" ++FSCK_OPT=-f ++OUT=$test_name.log ++EXP=$test_dir/expect ++ ++gunzip < $test_dir/../f_yesall/image.gz > $TMPFILE ++ ++rm -rf $OUT ++echo "yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy" | E2FSCK_FORCE_INTERACTIVE=y $FSCK $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 ++rm -f $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 ++ rm -f tmp_expect ++fi ++ ++unset IMAGE FSCK_OPT OUT EXP +--- /dev/null ++++ b/tests/f_yesall/expect +@@ -0,0 +1,62 @@ ++Pass 1: Checking inodes, blocks, and sizes ++Inode 12 has an invalid extent ++ (logical block 0, invalid physical block 999999999, len 1) ++Clear? yes to all ++Inode 12 has an invalid extent ++ (logical block 1, invalid physical block 9999999999, len 1) ++Clear? yes ++ ++Inode 13 is in use, but has dtime set. Fix? yes ++ ++Inode 13 has an invalid extent ++ (logical block 1, invalid physical block 8888888888888, len 1) ++Clear? yes ++ ++Inode 13 has an invalid extent ++ (logical block 0, invalid physical block 888888888888, len 1) ++Clear? yes ++ ++Inode 14 is in use, but has dtime set. Fix? yes ++ ++Inode 14 has an invalid extent ++ (logical block 300, invalid physical block 777777777777, len 300) ++Clear? yes ++ ++Inode 14 has an invalid extent ++ (logical block 0, invalid physical block 7777777777, len 1) ++Clear? yes ++ ++Inode 14, i_blocks is 52574694748113, should be 0. Fix? yes ++ ++Pass 2: Checking directory structure ++Extended attribute block for inode 12 (/a) is invalid (999999). ++Clear? yes ++ ++Extended attribute block for inode 13 (/b) is invalid (298954296). ++Clear? yes ++ ++Extended attribute block for inode 14 (/c) is invalid (388697201). ++Clear? yes ++ ++Pass 3: Checking directory connectivity ++Pass 4: Checking reference counts ++Inode 12 ref count is 34463, should be 1. Fix? yes ++ ++Inode 13 ref count is 9999, should be 1. Fix? yes ++ ++Inode 14 ref count is 12241, should be 1. Fix? yes ++ ++Pass 5: Checking group summary information ++Block bitmap differences: -202 -381 -457 ++Fix? yes ++ ++Free blocks count wrong for group #0 (0, counted=494). ++Fix? yes ++ ++Free inodes count wrong for group #0 (4294967293, counted=114). ++Fix? yes ++ ++ ++test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** ++test_filesys: 14/128 files (0.0% non-contiguous), 18/512 blocks ++Exit status is 1 +--- /dev/null ++++ b/tests/f_yesall/script +@@ -0,0 +1,27 @@ ++test_description="e2fsck with yes-to-all" ++FSCK_OPT=-f ++OUT=$test_name.log ++EXP=$test_dir/expect ++ ++gunzip < $test_dir/image.gz > $TMPFILE ++ ++rm -rf $OUT ++echo "annnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn" | E2FSCK_FORCE_INTERACTIVE=y $FSCK $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 ++rm -f $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 ++ rm -f tmp_expect ++fi ++ ++unset IMAGE FSCK_OPT OUT EXP +--- /dev/null ++++ b/tests/f_yesthenall/expect +@@ -0,0 +1,52 @@ ++Pass 1: Checking inodes, blocks, and sizes ++Inode 12 has an invalid extent ++ (logical block 0, invalid physical block 999999999, len 1) ++Clear? yes ++Inode 12 has an invalid extent ++ (logical block 1, invalid physical block 9999999999, len 1) ++Clear? yes ++Inode 13 is in use, but has dtime set. Fix? yes ++Inode 13 has an invalid extent ++ (logical block 1, invalid physical block 8888888888888, len 1) ++Clear? yes ++Inode 13 has an invalid extent ++ (logical block 0, invalid physical block 888888888888, len 1) ++Clear? yes ++Inode 14 is in use, but has dtime set. Fix? yes ++Inode 14 has an invalid extent ++ (logical block 300, invalid physical block 777777777777, len 300) ++Clear? yes ++Inode 14 has an invalid extent ++ (logical block 0, invalid physical block 7777777777, len 1) ++Clear? yes ++Inode 14, i_blocks is 52574694748113, should be 0. Fix? yes ++Pass 2: Checking directory structure ++Extended attribute block for inode 12 (/a) is invalid (999999). ++Clear ('a' enables 'yes' to all) ? yes ++Extended attribute block for inode 13 (/b) is invalid (298954296). ++Clear ('a' enables 'yes' to all) ? yes to all ++Extended attribute block for inode 14 (/c) is invalid (388697201). ++Clear? yes ++ ++Pass 3: Checking directory connectivity ++Pass 4: Checking reference counts ++Inode 12 ref count is 34463, should be 1. Fix? yes ++ ++Inode 13 ref count is 9999, should be 1. Fix? yes ++ ++Inode 14 ref count is 12241, should be 1. Fix? yes ++ ++Pass 5: Checking group summary information ++Block bitmap differences: -202 -381 -457 ++Fix? yes ++ ++Free blocks count wrong for group #0 (0, counted=494). ++Fix? yes ++ ++Free inodes count wrong for group #0 (4294967293, counted=114). ++Fix? yes ++ ++ ++test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** ++test_filesys: 14/128 files (0.0% non-contiguous), 18/512 blocks ++Exit status is 1 +--- /dev/null ++++ b/tests/f_yesthenall/script +@@ -0,0 +1,27 @@ ++test_description="e2fsck with yes then yes-to-all" ++FSCK_OPT=-f ++OUT=$test_name.log ++EXP=$test_dir/expect ++ ++gunzip < $test_dir/../f_yesall/image.gz > $TMPFILE ++ ++rm -rf $OUT ++echo "yyyyyyyyyyannnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn" | E2FSCK_FORCE_INTERACTIVE=y $FSCK $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 ++rm -f $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 ++ rm -f tmp_expect ++fi ++ ++unset IMAGE FSCK_OPT OUT EXP +--- /dev/null ++++ b/tests/f_yesthenno/expect +@@ -0,0 +1,50 @@ ++Pass 1: Checking inodes, blocks, and sizes ++Inode 12 has an invalid extent ++ (logical block 0, invalid physical block 999999999, len 1) ++Clear? yes ++Inode 12 has an invalid extent ++ (logical block 1, invalid physical block 9999999999, len 1) ++Clear? yes ++Inode 13 is in use, but has dtime set. Fix? yes ++Inode 13 has an invalid extent ++ (logical block 1, invalid physical block 8888888888888, len 1) ++Clear? yes ++Inode 13 has an invalid extent ++ (logical block 0, invalid physical block 888888888888, len 1) ++Clear? yes ++Inode 14 is in use, but has dtime set. Fix? yes ++Inode 14 has an invalid extent ++ (logical block 300, invalid physical block 777777777777, len 300) ++Clear? yes ++Inode 14 has an invalid extent ++ (logical block 0, invalid physical block 7777777777, len 1) ++Clear? yes ++Inode 14, i_blocks is 52574694748113, should be 0. Fix? yes ++Pass 2: Checking directory structure ++Extended attribute block for inode 12 (/a) is invalid (999999). ++Clear ('a' enables 'yes' to all) ? yes ++Extended attribute block for inode 13 (/b) is invalid (298954296). ++Clear ('a' enables 'yes' to all) ? no ++Extended attribute block for inode 14 (/c) is invalid (388697201). ++Clear? no ++Pass 3: Checking directory connectivity ++Pass 4: Checking reference counts ++Inode 12 ref count is 34463, should be 1. Fix? no ++Inode 13 ref count is 9999, should be 1. Fix? no ++Inode 14 ref count is 12241, should be 1. Fix? no ++Pass 5: Checking group summary information ++Block bitmap differences: -202 -381 -457 ++Fix? no ++Free blocks count wrong for group #0 (0, counted=491). ++Fix? no ++Free blocks count wrong (494, counted=491). ++Fix? no ++Free inodes count wrong for group #0 (4294967293, counted=114). ++Fix? no ++ ++test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** ++ ++test_filesys: ********** WARNING: Filesystem still has errors ********** ++ ++test_filesys: 14/128 files (0.0% non-contiguous), 18/512 blocks ++Exit status is 4 +--- /dev/null ++++ b/tests/f_yesthenno/script +@@ -0,0 +1,27 @@ ++test_description="e2fsck with yes then no" ++FSCK_OPT=-f ++OUT=$test_name.log ++EXP=$test_dir/expect ++ ++gunzip < $test_dir/../f_yesall/image.gz > $TMPFILE ++ ++rm -rf $OUT ++echo "yyyyyyyyyynnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn" | E2FSCK_FORCE_INTERACTIVE=y $FSCK $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 ++rm -f $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 ++ rm -f tmp_expect ++fi ++ ++unset IMAGE FSCK_OPT OUT EXP +--- /dev/null ++++ b/tests/j_corrupt_commit_csum/expect +@@ -0,0 +1,18 @@ ++test_filesys: recovering journal ++Journal transaction 3 was corrupt, replay was aborted. ++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), 1092/2048 blocks ++Exit status is 0 ++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), 1092/2048 blocks ++Exit status is 0 ++debugfs: cat /a ++aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadebugfs: +--- /dev/null ++++ b/tests/j_corrupt_commit_csum/name +@@ -0,0 +1 @@ ++corrupt commit csum (csum v3) +--- /dev/null ++++ b/tests/j_corrupt_commit_csum/script +@@ -0,0 +1,52 @@ ++if test -x $DEBUGFS_EXE; then ++ ++IMAGE=$test_dir/image.gz ++FSCK_OPT=-fy ++OUT=$test_name.log ++if [ -f $test_dir/expect.gz ]; then ++ EXP=$test_name.tmp ++ gunzip < $test_dir/expect.gz > $EXP1 ++else ++ EXP=$test_dir/expect ++fi ++ ++cp /dev/null $OUT ++ ++gzip -d < $IMAGE > $TMPFILE ++ ++$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 ++status=$? ++echo Exit status is $status >> $OUT.new ++sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT ++rm -f $OUT.new ++ ++$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 ++status=$? ++echo Exit status is $status >> $OUT.new ++sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT ++rm -f $OUT.new ++ ++echo "cat /a" > $TMPFILE.cmd ++echo >> $TMPFILE.cmd ++$DEBUGFS_EXE -f $TMPFILE.cmd $TMPFILE 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT ++rm -f $TMPFILE.cmd ++ ++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 IMAGE FSCK_OPT OUT EXP ++ ++else #if test -x $DEBUGFS_EXE; then ++ echo "$test_name: $test_description: skipped" ++fi +--- /dev/null ++++ b/tests/j_corrupt_commit_tid/expect +@@ -0,0 +1,17 @@ ++test_filesys: recovering journal ++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), 1092/2048 blocks ++Exit status is 0 ++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), 1092/2048 blocks ++Exit status is 0 ++debugfs: cat /a ++aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadebugfs: +--- /dev/null ++++ b/tests/j_corrupt_commit_tid/name +@@ -0,0 +1 @@ ++corrupt commit tid (csum v3) +--- /dev/null ++++ b/tests/j_corrupt_commit_tid/script +@@ -0,0 +1,52 @@ ++if test -x $DEBUGFS_EXE; then ++ ++IMAGE=$test_dir/image.gz ++FSCK_OPT=-fy ++OUT=$test_name.log ++if [ -f $test_dir/expect.gz ]; then ++ EXP=$test_name.tmp ++ gunzip < $test_dir/expect.gz > $EXP1 ++else ++ EXP=$test_dir/expect ++fi ++ ++cp /dev/null $OUT ++ ++gzip -d < $IMAGE > $TMPFILE ++ ++$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 ++status=$? ++echo Exit status is $status >> $OUT.new ++sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT ++rm -f $OUT.new ++ ++$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 ++status=$? ++echo Exit status is $status >> $OUT.new ++sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT ++rm -f $OUT.new ++ ++echo "cat /a" > $TMPFILE.cmd ++echo >> $TMPFILE.cmd ++$DEBUGFS_EXE -f $TMPFILE.cmd $TMPFILE 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT ++rm -f $TMPFILE.cmd ++ ++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 IMAGE FSCK_OPT OUT EXP ++ ++else #if test -x $DEBUGFS_EXE; then ++ echo "$test_name: $test_description: skipped" ++fi +--- /dev/null ++++ b/tests/j_corrupt_descr_csum/expect +@@ -0,0 +1,18 @@ ++test_filesys: recovering journal ++../e2fsck/e2fsck: Input/output error while recovering ext3 journal of test_filesys ++ ++test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** ++ ++test_filesys: ********** WARNING: Filesystem still has errors ********** ++ ++Exit status is 12 ++test_filesys: recovering journal ++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), 1093/2048 blocks ++Exit status is 0 ++debugfs: cat /a ++aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadebugfs: +--- /dev/null ++++ b/tests/j_corrupt_descr_csum/name +@@ -0,0 +1 @@ ++corrupt descr csum (csum v3) +--- /dev/null ++++ b/tests/j_corrupt_descr_csum/script +@@ -0,0 +1,52 @@ ++if test -x $DEBUGFS_EXE; then ++ ++IMAGE=$test_dir/image.gz ++FSCK_OPT=-fy ++OUT=$test_name.log ++if [ -f $test_dir/expect.gz ]; then ++ EXP=$test_name.tmp ++ gunzip < $test_dir/expect.gz > $EXP1 ++else ++ EXP=$test_dir/expect ++fi ++ ++cp /dev/null $OUT ++ ++gzip -d < $IMAGE > $TMPFILE ++ ++$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 ++status=$? ++echo Exit status is $status >> $OUT.new ++sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT ++rm -f $OUT.new ++ ++$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 ++status=$? ++echo Exit status is $status >> $OUT.new ++sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT ++rm -f $OUT.new ++ ++echo "cat /a" > $TMPFILE.cmd ++echo >> $TMPFILE.cmd ++$DEBUGFS_EXE -f $TMPFILE.cmd $TMPFILE 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT ++rm -f $TMPFILE.cmd ++ ++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 IMAGE FSCK_OPT OUT EXP ++ ++else #if test -x $DEBUGFS_EXE; then ++ echo "$test_name: $test_description: skipped" ++fi +--- /dev/null ++++ b/tests/j_corrupt_descr_tid/expect +@@ -0,0 +1,17 @@ ++test_filesys: recovering journal ++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), 1093/2048 blocks ++Exit status is 0 ++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), 1093/2048 blocks ++Exit status is 0 ++debugfs: cat /a ++aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadebugfs: +--- /dev/null ++++ b/tests/j_corrupt_descr_tid/name +@@ -0,0 +1 @@ ++corrupt descr tid (csum v3) +--- /dev/null ++++ b/tests/j_corrupt_descr_tid/script +@@ -0,0 +1,52 @@ ++if test -x $DEBUGFS_EXE; then ++ ++IMAGE=$test_dir/image.gz ++FSCK_OPT=-fy ++OUT=$test_name.log ++if [ -f $test_dir/expect.gz ]; then ++ EXP=$test_name.tmp ++ gunzip < $test_dir/expect.gz > $EXP1 ++else ++ EXP=$test_dir/expect ++fi ++ ++cp /dev/null $OUT ++ ++gzip -d < $IMAGE > $TMPFILE ++ ++$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 ++status=$? ++echo Exit status is $status >> $OUT.new ++sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT ++rm -f $OUT.new ++ ++$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 ++status=$? ++echo Exit status is $status >> $OUT.new ++sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT ++rm -f $OUT.new ++ ++echo "cat /a" > $TMPFILE.cmd ++echo >> $TMPFILE.cmd ++$DEBUGFS_EXE -f $TMPFILE.cmd $TMPFILE 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT ++rm -f $TMPFILE.cmd ++ ++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 IMAGE FSCK_OPT OUT EXP ++ ++else #if test -x $DEBUGFS_EXE; then ++ echo "$test_name: $test_description: skipped" ++fi +--- /dev/null ++++ b/tests/j_corrupt_ext_jnl_sb_block/expect +@@ -0,0 +1,5 @@ ++External journal does not support this filesystem ++ ++test_filesys: ********** WARNING: Filesystem still has errors ********** ++ ++Exit status is 12 +--- /dev/null ++++ b/tests/j_corrupt_ext_jnl_sb_block/name +@@ -0,0 +1 @@ ++corrupt external journal fs superblock block (metadata_csum) +--- /dev/null ++++ b/tests/j_corrupt_ext_jnl_sb_block/script +@@ -0,0 +1,36 @@ ++FSCK_OPT=-fy ++OUT=$test_name.log ++if [ -f $test_dir/expect.gz ]; then ++ EXP=$test_name.tmp ++ gunzip < $test_dir/expect.gz > $EXP1 ++else ++ EXP=$test_dir/expect ++fi ++ ++cp /dev/null $OUT ++ ++bzip2 -dc < $test_dir/image.tar.bz2 | tar x ++test -d "$JOURNAL_DUMP_DIR" -a -w "$JOURNAL_DUMP_DIR" && cp $test_name.img "$JOURNAL_DUMP_DIR/$test_name.img" ++test -d "$JOURNAL_DUMP_DIR" -a -w "$JOURNAL_DUMP_DIR" && cp $test_name.img.jnl "$JOURNAL_DUMP_DIR/$test_name.img.jnl" ++ ++$FSCK $FSCK_OPT -N test_filesys -j $test_name.img.jnl $test_name.img > $OUT.new 2>&1 ++status=$? ++echo Exit status is $status >> $OUT.new ++sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT ++rm -f $OUT.new ++ ++rm -f $TMPFILE $test_name.img $test_name.img.jnl ++ ++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 IMAGE FSCK_OPT OUT EXP +--- /dev/null ++++ b/tests/j_corrupt_ext_jnl_sb_csum/expect +@@ -0,0 +1,25 @@ ++External journal superblock checksum does not match superblock. Fix? yes ++ ++test_filesys: recovering journal ++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: +(1--31) +34 +(50--82) ++Fix? yes ++ ++Inode bitmap differences: +(1--11) ++Fix? yes ++ ++ ++test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** ++test_filesys: 11/128 files (0.0% non-contiguous), 66/2048 blocks ++Exit status is 1 ++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), 66/2048 blocks ++Exit status is 0 +--- /dev/null ++++ b/tests/j_corrupt_ext_jnl_sb_csum/name +@@ -0,0 +1 @@ ++corrupt external journal fs superblock csum (metadata_csum) +--- /dev/null ++++ b/tests/j_corrupt_ext_jnl_sb_csum/script +@@ -0,0 +1,42 @@ ++FSCK_OPT=-fy ++OUT=$test_name.log ++if [ -f $test_dir/expect.gz ]; then ++ EXP=$test_name.tmp ++ gunzip < $test_dir/expect.gz > $EXP1 ++else ++ EXP=$test_dir/expect ++fi ++ ++cp /dev/null $OUT ++ ++bzip2 -dc < $test_dir/image.tar.bz2 | tar x ++test -d "$JOURNAL_DUMP_DIR" -a -w "$JOURNAL_DUMP_DIR" && cp $test_name.img "$JOURNAL_DUMP_DIR/$test_name.img" ++test -d "$JOURNAL_DUMP_DIR" -a -w "$JOURNAL_DUMP_DIR" && cp $test_name.img.jnl "$JOURNAL_DUMP_DIR/$test_name.img.jnl" ++ ++$FSCK $FSCK_OPT -N test_filesys -j $test_name.img.jnl $test_name.img > $OUT.new 2>&1 ++status=$? ++echo Exit status is $status >> $OUT.new ++sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT ++rm -f $OUT.new ++ ++$FSCK $FSCK_OPT -N test_filesys -j $test_name.img.jnl $test_name.img > $OUT.new 2>&1 ++status=$? ++echo Exit status is $status >> $OUT.new ++sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT ++rm -f $OUT.new ++ ++rm -f $TMPFILE $test_name.img $test_name.img.jnl ++ ++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 IMAGE FSCK_OPT OUT EXP +--- /dev/null ++++ b/tests/j_corrupt_journal_block/expect +@@ -0,0 +1,20 @@ ++test_filesys: recovering journal ++JBD2: Invalid checksum recovering block 1090 in log ++../e2fsck/e2fsck: Input/output error while recovering ext3 journal of test_filesys ++ ++test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** ++ ++test_filesys: ********** WARNING: Filesystem still has errors ********** ++ ++Exit status is 12 ++test_filesys: recovering journal ++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), 1093/2048 blocks ++Exit status is 0 ++debugfs: cat /a ++bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccdddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddebugfs: ++ +--- /dev/null ++++ b/tests/j_corrupt_journal_block/name +@@ -0,0 +1 @@ ++corrupt journal block (csum v3) +--- /dev/null ++++ b/tests/j_corrupt_journal_block/script +@@ -0,0 +1,53 @@ ++if test -x $DEBUGFS_EXE; then ++ ++IMAGE=$test_dir/image.gz ++FSCK_OPT=-fy ++OUT=$test_name.log ++if [ -f $test_dir/expect.gz ]; then ++ EXP=$test_name.tmp ++ gunzip < $test_dir/expect.gz > $EXP1 ++else ++ EXP=$test_dir/expect ++fi ++ ++cp /dev/null $OUT ++ ++gzip -d < $IMAGE > $TMPFILE ++ ++$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 ++status=$? ++echo Exit status is $status >> $OUT.new ++sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT ++rm -f $OUT.new ++ ++$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 ++status=$? ++echo Exit status is $status >> $OUT.new ++sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT ++rm -f $OUT.new ++ ++echo "cat /a" > $TMPFILE.cmd ++echo >> $TMPFILE.cmd ++$DEBUGFS_EXE -f $TMPFILE.cmd $TMPFILE 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT ++echo >> $OUT ++rm -f $TMPFILE.cmd ++ ++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 IMAGE FSCK_OPT OUT EXP ++ ++else #if test -x $DEBUGFS_EXE; then ++ echo "$test_name: $test_description: skipped" ++fi +--- /dev/null ++++ b/tests/j_corrupt_revoke_block/expect +@@ -0,0 +1,17 @@ ++test_filesys: recovering journal ++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), 1092/2048 blocks ++Exit status is 0 ++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), 1092/2048 blocks ++Exit status is 0 ++debugfs: cat /a ++bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbdebugfs: +--- /dev/null ++++ b/tests/j_corrupt_revoke_block/name +@@ -0,0 +1 @@ ++corrupt revoke block (csum v3) +--- /dev/null ++++ b/tests/j_corrupt_revoke_block/script +@@ -0,0 +1,52 @@ ++if test -x $DEBUGFS_EXE; then ++ ++IMAGE=$test_dir/image.gz ++FSCK_OPT=-fy ++OUT=$test_name.log ++if [ -f $test_dir/expect.gz ]; then ++ EXP=$test_name.tmp ++ gunzip < $test_dir/expect.gz > $EXP1 ++else ++ EXP=$test_dir/expect ++fi ++ ++cp /dev/null $OUT ++ ++gzip -d < $IMAGE > $TMPFILE ++ ++$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 ++status=$? ++echo Exit status is $status >> $OUT.new ++sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT ++rm -f $OUT.new ++ ++$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 ++status=$? ++echo Exit status is $status >> $OUT.new ++sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT ++rm -f $OUT.new ++ ++echo "cat /a" > $TMPFILE.cmd ++echo >> $TMPFILE.cmd ++$DEBUGFS_EXE -f $TMPFILE.cmd $TMPFILE 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT ++rm -f $TMPFILE.cmd ++ ++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 IMAGE FSCK_OPT OUT EXP ++ ++else #if test -x $DEBUGFS_EXE; then ++ echo "$test_name: $test_description: skipped" ++fi +--- /dev/null ++++ b/tests/j_corrupt_revoke_csum/expect +@@ -0,0 +1,17 @@ ++test_filesys: recovering journal ++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), 1092/2048 blocks ++Exit status is 0 ++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), 1092/2048 blocks ++Exit status is 0 ++debugfs: cat /a ++bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbdebugfs: +--- /dev/null ++++ b/tests/j_corrupt_revoke_csum/name +@@ -0,0 +1 @@ ++corrupt revoke csum (csum v3) +--- /dev/null ++++ b/tests/j_corrupt_revoke_csum/script +@@ -0,0 +1,52 @@ ++if test -x $DEBUGFS_EXE; then ++ ++IMAGE=$test_dir/image.gz ++FSCK_OPT=-fy ++OUT=$test_name.log ++if [ -f $test_dir/expect.gz ]; then ++ EXP=$test_name.tmp ++ gunzip < $test_dir/expect.gz > $EXP1 ++else ++ EXP=$test_dir/expect ++fi ++ ++cp /dev/null $OUT ++ ++gzip -d < $IMAGE > $TMPFILE ++ ++$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 ++status=$? ++echo Exit status is $status >> $OUT.new ++sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT ++rm -f $OUT.new ++ ++$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 ++status=$? ++echo Exit status is $status >> $OUT.new ++sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT ++rm -f $OUT.new ++ ++echo "cat /a" > $TMPFILE.cmd ++echo >> $TMPFILE.cmd ++$DEBUGFS_EXE -f $TMPFILE.cmd $TMPFILE 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT ++rm -f $TMPFILE.cmd ++ ++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 IMAGE FSCK_OPT OUT EXP ++ ++else #if test -x $DEBUGFS_EXE; then ++ echo "$test_name: $test_description: skipped" ++fi +--- /dev/null ++++ b/tests/j_corrupt_revoke_rcount/expect.1 +@@ -0,0 +1,8 @@ ++test_filesys: recovering journal ++../e2fsck/e2fsck: Invalid argument while recovering ext3 journal of test_filesys ++ ++test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** ++ ++test_filesys: ********** WARNING: Filesystem still has errors ********** ++ ++Exit status is 12 +--- /dev/null ++++ b/tests/j_corrupt_revoke_rcount/expect.2 +@@ -0,0 +1,8 @@ ++test_filesys: recovering journal ++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/512 files (9.1% non-contiguous), 1066/2048 blocks ++Exit status is 0 +--- /dev/null ++++ b/tests/j_corrupt_revoke_rcount/name +@@ -0,0 +1 @@ ++corrupt revoke r_count buffer overflow +--- /dev/null ++++ b/tests/j_corrupt_sb_csum/expect +@@ -0,0 +1,21 @@ ++Journal superblock is corrupt. ++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: ***** FILE SYSTEM WAS MODIFIED ***** ++test_filesys: 12/128 files (8.3% non-contiguous), 1092/2048 blocks ++Exit status is 1 ++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), 1092/2048 blocks ++Exit status is 0 ++debugfs: cat /a ++aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadebugfs: +--- /dev/null ++++ b/tests/j_corrupt_sb_csum/name +@@ -0,0 +1 @@ ++corrupt sb csum (csum v3) +--- /dev/null ++++ b/tests/j_corrupt_sb_csum/script +@@ -0,0 +1,52 @@ ++if test -x $DEBUGFS_EXE; then ++ ++IMAGE=$test_dir/image.gz ++FSCK_OPT=-fy ++OUT=$test_name.log ++if [ -f $test_dir/expect.gz ]; then ++ EXP=$test_name.tmp ++ gunzip < $test_dir/expect.gz > $EXP1 ++else ++ EXP=$test_dir/expect ++fi ++ ++cp /dev/null $OUT ++ ++gzip -d < $IMAGE > $TMPFILE ++ ++$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 ++status=$? ++echo Exit status is $status >> $OUT.new ++sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT ++rm -f $OUT.new ++ ++$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 ++status=$? ++echo Exit status is $status >> $OUT.new ++sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT ++rm -f $OUT.new ++ ++echo "cat /a" > $TMPFILE.cmd ++echo >> $TMPFILE.cmd ++$DEBUGFS_EXE -f $TMPFILE.cmd $TMPFILE 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT ++rm -f $TMPFILE.cmd ++ ++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 IMAGE FSCK_OPT OUT EXP ++ ++else #if test -x $DEBUGFS_EXE; then ++ echo "$test_name: $test_description: skipped" ++fi +--- /dev/null ++++ b/tests/j_corrupt_sb_magic/expect +@@ -0,0 +1,42 @@ ++Superblock has an invalid journal (inode 8). ++Clear? yes ++ ++*** journal has been deleted *** ++ ++Superblock has_journal flag is clear, but a journal is present. ++Clear? yes ++ ++Pass 1: Checking inodes, blocks, and sizes ++Journal inode is not in use, but contains data. Clear? 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: -(32--33) -(35--49) -(83--1089) ++Fix? yes ++ ++Free blocks count wrong for group #0 (956, counted=1980). ++Fix? yes ++ ++Free blocks count wrong (956, counted=1980). ++Fix? yes ++ ++Recreate journal? yes ++ ++Creating journal (1024 blocks): Done. ++ ++*** journal has been regenerated *** ++ ++test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** ++test_filesys: 12/128 files (0.0% non-contiguous), 1092/2048 blocks ++Exit status is 1 ++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), 1092/2048 blocks ++Exit status is 0 ++debugfs: cat /a ++aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadebugfs: +--- /dev/null ++++ b/tests/j_corrupt_sb_magic/name +@@ -0,0 +1 @@ ++corrupt sb magic (csum v3) +--- /dev/null ++++ b/tests/j_corrupt_sb_magic/script +@@ -0,0 +1,52 @@ ++if test -x $DEBUGFS_EXE; then ++ ++IMAGE=$test_dir/image.gz ++FSCK_OPT=-fy ++OUT=$test_name.log ++if [ -f $test_dir/expect.gz ]; then ++ EXP=$test_name.tmp ++ gunzip < $test_dir/expect.gz > $EXP1 ++else ++ EXP=$test_dir/expect ++fi ++ ++cp /dev/null $OUT ++ ++gzip -d < $IMAGE > $TMPFILE ++ ++$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 ++status=$? ++echo Exit status is $status >> $OUT.new ++sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT ++rm -f $OUT.new ++ ++$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 ++status=$? ++echo Exit status is $status >> $OUT.new ++sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT ++rm -f $OUT.new ++ ++echo "cat /a" > $TMPFILE.cmd ++echo >> $TMPFILE.cmd ++$DEBUGFS_EXE -f $TMPFILE.cmd $TMPFILE 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT ++rm -f $TMPFILE.cmd ++ ++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 IMAGE FSCK_OPT OUT EXP ++ ++else #if test -x $DEBUGFS_EXE; then ++ echo "$test_name: $test_description: skipped" ++fi +--- /dev/null ++++ b/tests/j_ext_dumpe2fs/expect +@@ -0,0 +1,54 @@ ++e2fsck external journal ++../e2fsck/e2fsck: Filesystem has unsupported feature(s) while trying to open test.img ++ ++The superblock could not be read or does not describe a valid ext2/ext3/ext4 ++filesystem. If the device is valid and it really contains an ext2/ext3/ext4 ++filesystem (and not swap or ufs or something else), then the superblock ++is corrupt, and you might try running e2fsck with an alternate superblock: ++ e2fsck -b 8193 ++ or ++ e2fsck -b 32768 ++ ++Exit status is 8 ++dumpe2fs external journal ++Filesystem volume name: ++Last mounted on: ++Filesystem magic number: 0xEF53 ++Filesystem revision #: 1 (dynamic) ++Filesystem features: journal_dev metadata_csum ++Default mount options: user_xattr acl block_validity ++Filesystem state: clean ++Errors behavior: Continue ++Filesystem OS type: Linux ++Inode count: 0 ++Block count: 2048 ++Reserved block count: 0 ++Free blocks: 0 ++Free inodes: 0 ++First block: 1 ++Block size: 1024 ++Fragment size: 1024 ++Blocks per group: 8192 ++Fragments per group: 8192 ++Inodes per group: 0 ++Inode blocks per group: 0 ++Mount count: 0 ++Check interval: 0 () ++Reserved blocks uid: 0 ++Reserved blocks gid: 0 ++First inode: 11 ++Inode size: 256 ++Required extra isize: 28 ++Desired extra isize: 28 ++Default directory hash: half_md4 ++Checksum type: crc32c ++Journal checksum type: crc32c ++Journal checksum: 0x661e816f ++Journal features: journal_64bit journal_checksum_v3 ++Journal block size: 1024 ++Journal length: 2048 ++Journal first block: 3 ++Journal sequence: 0x00000003 ++Journal start: 0 ++Journal number of users: 1 ++Journal users: 117f752e-f27d-4f6f-a652-072586a29b82 +--- /dev/null ++++ b/tests/j_ext_dumpe2fs/name +@@ -0,0 +1 @@ ++dumpe2fs of external journal device +--- /dev/null ++++ b/tests/j_ext_dumpe2fs/script +@@ -0,0 +1,40 @@ ++FSCK_OPT=-fy ++OUT=$test_name.log ++if [ -f $test_dir/expect.gz ]; then ++ EXP=$test_name.tmp ++ gunzip < $test_dir/expect.gz > $EXP1 ++else ++ EXP=$test_dir/expect ++fi ++ ++cp /dev/null $OUT ++ ++gunzip < $test_dir/image.gz > $TMPFILE ++ ++echo "e2fsck external journal" >> $OUT ++$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 ++status=$? ++echo Exit status is $status >> $OUT.new ++sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT ++rm -f $OUT.new ++ ++echo "dumpe2fs external journal" >> $OUT ++$DUMPE2FS $TMPFILE > $OUT.new 2>&1 ++sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT ++rm -f $OUT.new ++ ++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 IMAGE FSCK_OPT OUT EXP +--- /dev/null ++++ b/tests/j_ext_long_revoke_trans/expect +@@ -0,0 +1,91 @@ ++Creating filesystem with 262144 1k blocks and 0 inodes ++Superblock backups stored on blocks: ++ ++Zeroing journal device:  ++Creating filesystem with 262144 1k blocks and 16384 inodes ++Superblock backups stored on blocks: ++ 8193, 24577, 40961, 57345, 73729, 204801, 221185 ++ ++Allocating group tables: done ++Writing inode tables: done ++Writing superblocks and filesystem accounting information: done ++ ++debugfs add journal device/UUID ++debugfs: feature has_journal ++Filesystem features: has_journal ext_attr resize_inode dir_index filetype extent flex_bg sparse_super huge_file uninit_bg dir_nlink extra_isize ++debugfs: ssv journal_dev 0x9999 ++debugfs: ssv journal_uuid 1db3f677-6832-4adb-bafc-8e4059c30a34 ++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/16384 files (0.0% non-contiguous), 6239/262144 blocks ++Exit status is 0 ++debugfs write journal ++debugfs: logdump -c ++Ext2 superblock header found. ++Journal starts at block 3, transaction 1 ++Found expected sequence 1, type 1 (descriptor block) at block 3 ++Found expected sequence 1, type 1 (descriptor block) at block 128 ++Found expected sequence 1, type 1 (descriptor block) at block 253 ++Found expected sequence 1, type 1 (descriptor block) at block 378 ++Found expected sequence 1, type 1 (descriptor block) at block 503 ++Found expected sequence 1, type 1 (descriptor block) at block 628 ++Found expected sequence 1, type 1 (descriptor block) at block 753 ++Found expected sequence 1, type 1 (descriptor block) at block 878 ++Found expected sequence 1, type 1 (descriptor block) at block 1003 ++Found expected sequence 1, type 1 (descriptor block) at block 1128 ++Found expected sequence 1, type 1 (descriptor block) at block 1253 ++Found expected sequence 1, type 1 (descriptor block) at block 1378 ++Found expected sequence 1, type 1 (descriptor block) at block 1503 ++Found expected sequence 1, type 1 (descriptor block) at block 1628 ++Found expected sequence 1, type 1 (descriptor block) at block 1753 ++Found expected sequence 1, type 1 (descriptor block) at block 1878 ++Found expected sequence 1, type 1 (descriptor block) at block 2003 ++Found expected sequence 1, type 1 (descriptor block) at block 2128 ++Found expected sequence 1, type 1 (descriptor block) at block 2253 ++Found expected sequence 1, type 1 (descriptor block) at block 2378 ++Found expected sequence 1, type 1 (descriptor block) at block 2503 ++Found expected sequence 1, type 1 (descriptor block) at block 2628 ++Found expected sequence 1, type 1 (descriptor block) at block 2753 ++Found expected sequence 1, type 1 (descriptor block) at block 2878 ++Found expected sequence 1, type 1 (descriptor block) at block 3003 ++Found expected sequence 1, type 1 (descriptor block) at block 3128 ++Found expected sequence 1, type 1 (descriptor block) at block 3253 ++Found expected sequence 1, type 1 (descriptor block) at block 3378 ++Found expected sequence 1, type 1 (descriptor block) at block 3503 ++Found expected sequence 1, type 1 (descriptor block) at block 3628 ++Found expected sequence 1, type 1 (descriptor block) at block 3753 ++Found expected sequence 1, type 1 (descriptor block) at block 3878 ++Found expected sequence 1, type 1 (descriptor block) at block 4003 ++Found expected sequence 1, type 1 (descriptor block) at block 4128 ++Found expected sequence 1, type 2 (commit block) at block 4135 ++Found expected sequence 2, type 5 (revoke table) at block 4136 ++Found expected sequence 2, type 5 (revoke table) at block 4137 ++Found expected sequence 2, type 5 (revoke table) at block 4138 ++Found expected sequence 2, type 5 (revoke table) at block 4139 ++Found expected sequence 2, type 5 (revoke table) at block 4140 ++Found expected sequence 2, type 5 (revoke table) at block 4141 ++Found expected sequence 2, type 5 (revoke table) at block 4142 ++Found expected sequence 2, type 5 (revoke table) at block 4143 ++Found expected sequence 2, type 5 (revoke table) at block 4144 ++Found expected sequence 2, type 5 (revoke table) at block 4145 ++Found expected sequence 2, type 5 (revoke table) at block 4146 ++Found expected sequence 2, type 5 (revoke table) at block 4147 ++Found expected sequence 2, type 5 (revoke table) at block 4148 ++Found expected sequence 2, type 5 (revoke table) at block 4149 ++Found expected sequence 2, type 5 (revoke table) at block 4150 ++Found expected sequence 2, type 5 (revoke table) at block 4151 ++Found expected sequence 2, type 5 (revoke table) at block 4152 ++Found expected sequence 2, type 2 (commit block) at block 4153 ++No magic number at block 4154: end of journal. ++debugfs fsck ++test_filesys: recovering journal ++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/16384 files (0.0% non-contiguous), 6239/262144 blocks ++Exit status is 0 +--- /dev/null ++++ b/tests/j_ext_long_revoke_trans/name +@@ -0,0 +1 @@ ++revoked transaction nuking free space w/ ext. journal +--- /dev/null ++++ b/tests/j_ext_long_revoke_trans/script +@@ -0,0 +1,77 @@ ++if test -x $DEBUGFS_EXE; then ++ ++FSCK_OPT=-fy ++OUT=$test_name.log ++if [ -f $test_dir/expect.gz ]; then ++ EXP=$test_name.tmp ++ gunzip < $test_dir/expect.gz > $EXP1 ++else ++ EXP=$test_dir/expect ++fi ++ ++cp /dev/null $OUT ++ ++JNLFILE=$TMPFILE.jnl ++ ++touch $JNLFILE ++$MKE2FS -F -o Linux -b 1024 -O journal_dev -T ext4 -U 1db3f677-6832-4adb-bafc-8e4059c30a34 $JNLFILE 262144 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT 2>&1 ++$MKE2FS -F -o Linux -b 1024 -O ^has_journal -T ext4 $TMPFILE 262144 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT 2>&1 ++ ++echo "debugfs add journal device/UUID" >> $OUT ++$DEBUGFS -w -f - $TMPFILE <<-EOF >> $OUT.new 2>&1 ++ feature has_journal ++ ssv journal_dev 0x9999 ++ ssv journal_uuid 1db3f677-6832-4adb-bafc-8e4059c30a34 ++EOF ++sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT ++rm -f $OUT.new ++ ++$FSCK -fy -N test_filesys -j $JNLFILE $TMPFILE > $OUT.new 2>&1 ++status=$? ++echo Exit status is $status >> $OUT.new ++sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT ++rm -f $OUT.new ++ ++echo "debugfs write journal" >> $OUT ++echo "jo -f $JNLFILE" > $TMPFILE.cmd ++echo "jw -b 259-4356 /dev/zero" >> $TMPFILE.cmd ++echo "jc" >> $TMPFILE.cmd ++echo "jo -f $JNLFILE" >> $TMPFILE.cmd ++echo "jw -r 259-4356 /dev/zero" >> $TMPFILE.cmd ++echo "jc" >> $TMPFILE.cmd ++$DEBUGFS_EXE -w -f $TMPFILE.cmd $TMPFILE 2>> $OUT.new > /dev/null ++sed -f $cmd_dir/filter.sed < $OUT.new >> $OUT ++rm -rf $OUT.new ++ ++test -d "$JOURNAL_DUMP_DIR" -a -w "$JOURNAL_DUMP_DIR" && cp "$TMPFILE" "$JOURNAL_DUMP_DIR/$test_name.img" ++test -d "$JOURNAL_DUMP_DIR" -a -w "$JOURNAL_DUMP_DIR" && cp "$JNLFILE" "$JOURNAL_DUMP_DIR/$test_name.img.jnl" ++echo "logdump -c -f $JNLFILE" > $TMPFILE.cmd ++$DEBUGFS_EXE -f $TMPFILE.cmd $TMPFILE 2>&1 | sed -f $cmd_dir/filter.sed -e 's/logdump -c -f.*/logdump -c/g' >> $OUT ++rm -rf $TMPFILE.cmd ++ ++echo "debugfs fsck" >> $OUT ++$FSCK -fy -N test_filesys -j $JNLFILE $TMPFILE > $OUT.new 2>&1 ++status=$? ++echo Exit status is $status >> $OUT.new ++sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT ++rm -f $OUT.new ++ ++rm -f $TMPFILE $JNLFILE ++ ++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 IMAGE FSCK_OPT OUT EXP JNLFILE ++ ++else #if test -x $DEBUGFS_EXE; then ++ echo "$test_name: $test_description: skipped" ++fi +--- /dev/null ++++ b/tests/j_ext_long_trans/expect +@@ -0,0 +1,104 @@ ++Creating filesystem with 262144 1k blocks and 0 inodes ++Superblock backups stored on blocks: ++ ++Zeroing journal device:  ++Creating filesystem with 262144 1k blocks and 16384 inodes ++Superblock backups stored on blocks: ++ 8193, 24577, 40961, 57345, 73729, 204801, 221185 ++ ++Allocating group tables: done ++Writing inode tables: done ++Writing superblocks and filesystem accounting information: done ++ ++debugfs add journal device/UUID ++debugfs: feature has_journal ++Filesystem features: has_journal ext_attr resize_inode dir_index filetype extent flex_bg sparse_super huge_file uninit_bg dir_nlink extra_isize ++debugfs: ssv journal_dev 0x9999 ++debugfs: ssv journal_uuid 1db3f677-6832-4adb-bafc-8e4059c30a34 ++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/16384 files (0.0% non-contiguous), 6239/262144 blocks ++Exit status is 0 ++debugfs write journal ++debugfs: logdump -c ++Ext2 superblock header found. ++Journal starts at block 3, transaction 1 ++Found expected sequence 1, type 1 (descriptor block) at block 3 ++Found expected sequence 1, type 1 (descriptor block) at block 128 ++Found expected sequence 1, type 1 (descriptor block) at block 253 ++Found expected sequence 1, type 1 (descriptor block) at block 378 ++Found expected sequence 1, type 1 (descriptor block) at block 503 ++Found expected sequence 1, type 1 (descriptor block) at block 628 ++Found expected sequence 1, type 1 (descriptor block) at block 753 ++Found expected sequence 1, type 1 (descriptor block) at block 878 ++Found expected sequence 1, type 1 (descriptor block) at block 1003 ++Found expected sequence 1, type 1 (descriptor block) at block 1128 ++Found expected sequence 1, type 1 (descriptor block) at block 1253 ++Found expected sequence 1, type 1 (descriptor block) at block 1378 ++Found expected sequence 1, type 1 (descriptor block) at block 1503 ++Found expected sequence 1, type 1 (descriptor block) at block 1628 ++Found expected sequence 1, type 1 (descriptor block) at block 1753 ++Found expected sequence 1, type 1 (descriptor block) at block 1878 ++Found expected sequence 1, type 1 (descriptor block) at block 2003 ++Found expected sequence 1, type 1 (descriptor block) at block 2128 ++Found expected sequence 1, type 1 (descriptor block) at block 2253 ++Found expected sequence 1, type 1 (descriptor block) at block 2378 ++Found expected sequence 1, type 1 (descriptor block) at block 2503 ++Found expected sequence 1, type 1 (descriptor block) at block 2628 ++Found expected sequence 1, type 1 (descriptor block) at block 2753 ++Found expected sequence 1, type 1 (descriptor block) at block 2878 ++Found expected sequence 1, type 1 (descriptor block) at block 3003 ++Found expected sequence 1, type 1 (descriptor block) at block 3128 ++Found expected sequence 1, type 1 (descriptor block) at block 3253 ++Found expected sequence 1, type 1 (descriptor block) at block 3378 ++Found expected sequence 1, type 1 (descriptor block) at block 3503 ++Found expected sequence 1, type 1 (descriptor block) at block 3628 ++Found expected sequence 1, type 1 (descriptor block) at block 3753 ++Found expected sequence 1, type 1 (descriptor block) at block 3878 ++Found expected sequence 1, type 1 (descriptor block) at block 4003 ++Found expected sequence 1, type 1 (descriptor block) at block 4128 ++Found expected sequence 1, type 2 (commit block) at block 4135 ++No magic number at block 4136: end of journal. ++debugfs fsck ++test_filesys: recovering journal ++Resize inode not valid. Recreate? yes ++ ++Pass 1: Checking inodes, blocks, and sizes ++Root inode is not a directory. Clear? yes ++ ++Pass 2: Checking directory structure ++Pass 3: Checking directory connectivity ++Root inode not allocated. Allocate? yes ++ ++/lost+found not found. Create? yes ++ ++Pass 4: Checking reference counts ++Pass 5: Checking group summary information ++Block bitmap differences: +(1--259) +275 +(291--418) +2341 ++Fix? yes ++ ++Free blocks count wrong for group #0 (5838, counted=5851). ++Fix? yes ++ ++Free blocks count wrong (255903, counted=255916). ++Fix? yes ++ ++Inode bitmap differences: +1 +(3--10) ++Fix? yes ++ ++Free inodes count wrong for group #0 (500, counted=501). ++Fix? yes ++ ++Directories count wrong for group #0 (3, counted=2). ++Fix? yes ++ ++Free inodes count wrong (16372, counted=16373). ++Fix? yes ++ ++ ++test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** ++test_filesys: 11/16384 files (0.0% non-contiguous), 6228/262144 blocks ++Exit status is 1 +--- /dev/null ++++ b/tests/j_ext_long_trans/name +@@ -0,0 +1 @@ ++transaction nuking free space w/ ext. journal +--- /dev/null ++++ b/tests/j_ext_long_trans/script +@@ -0,0 +1,74 @@ ++if test -x $DEBUGFS_EXE; then ++ ++FSCK_OPT=-fy ++OUT=$test_name.log ++if [ -f $test_dir/expect.gz ]; then ++ EXP=$test_name.tmp ++ gunzip < $test_dir/expect.gz > $EXP1 ++else ++ EXP=$test_dir/expect ++fi ++ ++cp /dev/null $OUT ++ ++JNLFILE=$TMPFILE.jnl ++ ++touch $JNLFILE ++$MKE2FS -F -o Linux -b 1024 -O journal_dev -T ext4 -U 1db3f677-6832-4adb-bafc-8e4059c30a34 $JNLFILE 262144 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT 2>&1 ++$MKE2FS -F -o Linux -b 1024 -O ^has_journal -T ext4 $TMPFILE 262144 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT 2>&1 ++ ++echo "debugfs add journal device/UUID" >> $OUT ++$DEBUGFS -w -f - $TMPFILE <<- EOF >> $OUT.new 2>&1 ++ feature has_journal ++ ssv journal_dev 0x9999 ++ ssv journal_uuid 1db3f677-6832-4adb-bafc-8e4059c30a34 ++EOF ++sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT ++rm -f $OUT.new ++ ++$FSCK -fy -N test_filesys -j $JNLFILE $TMPFILE > $OUT.new 2>&1 ++status=$? ++echo Exit status is $status >> $OUT.new ++sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT ++rm -f $OUT.new ++ ++echo "debugfs write journal" >> $OUT ++echo "jo -f $JNLFILE" > $TMPFILE.cmd ++echo "jw -b 259-4356 /dev/zero" >> $TMPFILE.cmd ++echo "jc" >> $TMPFILE.cmd ++$DEBUGFS_EXE -w -f $TMPFILE.cmd $TMPFILE 2>> $OUT.new > /dev/null ++sed -f $cmd_dir/filter.sed < $OUT.new >> $OUT ++rm -rf $OUT.new ++ ++test -d "$JOURNAL_DUMP_DIR" -a -w "$JOURNAL_DUMP_DIR" && cp "$TMPFILE" "$JOURNAL_DUMP_DIR/$test_name.img" ++test -d "$JOURNAL_DUMP_DIR" -a -w "$JOURNAL_DUMP_DIR" && cp "$JNLFILE" "$JOURNAL_DUMP_DIR/$test_name.img.jnl" ++echo "logdump -c -f $JNLFILE" > $TMPFILE.cmd ++$DEBUGFS_EXE -f $TMPFILE.cmd $TMPFILE 2>&1 | sed -f $cmd_dir/filter.sed -e 's/logdump -c -f.*/logdump -c/g' >> $OUT ++rm -rf $TMPFILE.cmd ++ ++echo "debugfs fsck" >> $OUT ++$FSCK -fy -N test_filesys -j $JNLFILE $TMPFILE > $OUT.new 2>&1 ++status=$? ++echo Exit status is $status >> $OUT.new ++sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT ++rm -f $OUT.new ++ ++rm -f $TMPFILE $JNLFILE ++ ++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 IMAGE FSCK_OPT OUT EXP JNLFILE ++ ++else #if test -x $DEBUGFS_EXE; then ++ echo "$test_name: $test_description: skipped" ++fi +--- /dev/null ++++ b/tests/j_long_revoke_trans/expect +@@ -0,0 +1,81 @@ ++Creating filesystem with 262144 1k blocks and 16384 inodes ++Superblock backups stored on blocks: ++ 8193, 24577, 40961, 57345, 73729, 204801, 221185 ++ ++Allocating group tables: done ++Writing inode tables: done ++Creating journal (8192 blocks): done ++Writing superblocks and filesystem accounting information: done ++ ++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/16384 files (0.0% non-contiguous), 14431/262144 blocks ++Exit status is 0 ++debugfs write journal ++debugfs: logdump -c ++Journal starts at block 1, transaction 1 ++Found expected sequence 1, type 1 (descriptor block) at block 1 ++Found expected sequence 1, type 1 (descriptor block) at block 126 ++Found expected sequence 1, type 1 (descriptor block) at block 251 ++Found expected sequence 1, type 1 (descriptor block) at block 376 ++Found expected sequence 1, type 1 (descriptor block) at block 501 ++Found expected sequence 1, type 1 (descriptor block) at block 626 ++Found expected sequence 1, type 1 (descriptor block) at block 751 ++Found expected sequence 1, type 1 (descriptor block) at block 876 ++Found expected sequence 1, type 1 (descriptor block) at block 1001 ++Found expected sequence 1, type 1 (descriptor block) at block 1126 ++Found expected sequence 1, type 1 (descriptor block) at block 1251 ++Found expected sequence 1, type 1 (descriptor block) at block 1376 ++Found expected sequence 1, type 1 (descriptor block) at block 1501 ++Found expected sequence 1, type 1 (descriptor block) at block 1626 ++Found expected sequence 1, type 1 (descriptor block) at block 1751 ++Found expected sequence 1, type 1 (descriptor block) at block 1876 ++Found expected sequence 1, type 1 (descriptor block) at block 2001 ++Found expected sequence 1, type 1 (descriptor block) at block 2126 ++Found expected sequence 1, type 1 (descriptor block) at block 2251 ++Found expected sequence 1, type 1 (descriptor block) at block 2376 ++Found expected sequence 1, type 1 (descriptor block) at block 2501 ++Found expected sequence 1, type 1 (descriptor block) at block 2626 ++Found expected sequence 1, type 1 (descriptor block) at block 2751 ++Found expected sequence 1, type 1 (descriptor block) at block 2876 ++Found expected sequence 1, type 1 (descriptor block) at block 3001 ++Found expected sequence 1, type 1 (descriptor block) at block 3126 ++Found expected sequence 1, type 1 (descriptor block) at block 3251 ++Found expected sequence 1, type 1 (descriptor block) at block 3376 ++Found expected sequence 1, type 1 (descriptor block) at block 3501 ++Found expected sequence 1, type 1 (descriptor block) at block 3626 ++Found expected sequence 1, type 1 (descriptor block) at block 3751 ++Found expected sequence 1, type 1 (descriptor block) at block 3876 ++Found expected sequence 1, type 1 (descriptor block) at block 4001 ++Found expected sequence 1, type 1 (descriptor block) at block 4126 ++Found expected sequence 1, type 2 (commit block) at block 4133 ++Found expected sequence 2, type 5 (revoke table) at block 4134 ++Found expected sequence 2, type 5 (revoke table) at block 4135 ++Found expected sequence 2, type 5 (revoke table) at block 4136 ++Found expected sequence 2, type 5 (revoke table) at block 4137 ++Found expected sequence 2, type 5 (revoke table) at block 4138 ++Found expected sequence 2, type 5 (revoke table) at block 4139 ++Found expected sequence 2, type 5 (revoke table) at block 4140 ++Found expected sequence 2, type 5 (revoke table) at block 4141 ++Found expected sequence 2, type 5 (revoke table) at block 4142 ++Found expected sequence 2, type 5 (revoke table) at block 4143 ++Found expected sequence 2, type 5 (revoke table) at block 4144 ++Found expected sequence 2, type 5 (revoke table) at block 4145 ++Found expected sequence 2, type 5 (revoke table) at block 4146 ++Found expected sequence 2, type 5 (revoke table) at block 4147 ++Found expected sequence 2, type 5 (revoke table) at block 4148 ++Found expected sequence 2, type 5 (revoke table) at block 4149 ++Found expected sequence 2, type 5 (revoke table) at block 4150 ++Found expected sequence 2, type 2 (commit block) at block 4151 ++No magic number at block 4152: end of journal. ++test_filesys: recovering journal ++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/16384 files (0.0% non-contiguous), 14431/262144 blocks ++Exit status is 0 +--- /dev/null ++++ b/tests/j_long_revoke_trans/name +@@ -0,0 +1 @@ ++revoked transaction nuking free space +--- /dev/null ++++ b/tests/j_long_revoke_trans/script +@@ -0,0 +1,62 @@ ++if test -x $DEBUGFS_EXE; then ++ ++FSCK_OPT=-fy ++OUT=$test_name.log ++if [ -f $test_dir/expect.gz ]; then ++ EXP=$test_name.tmp ++ gunzip < $test_dir/expect.gz > $EXP1 ++else ++ EXP=$test_dir/expect ++fi ++ ++cp /dev/null $OUT ++ ++$MKE2FS -F -o Linux -b 1024 -O has_journal -T ext4 $TMPFILE 262144 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT 2>&1 ++ ++$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 ++status=$? ++echo Exit status is $status >> $OUT.new ++sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT ++rm -f $OUT.new ++ ++echo "debugfs write journal" >> $OUT ++echo "jo" > $TMPFILE.cmd ++echo "jw -b 259-4356 /dev/zero" >> $TMPFILE.cmd ++echo "jc" >> $TMPFILE.cmd ++echo "jo" >> $TMPFILE.cmd ++echo "jw -r 259-4356" >> $TMPFILE.cmd ++echo "jc" >> $TMPFILE.cmd ++$DEBUGFS_EXE -w -f $TMPFILE.cmd $TMPFILE 2>> $OUT.new > /dev/null ++sed -f $cmd_dir/filter.sed < $OUT.new >> $OUT ++rm -rf $OUT.new ++ ++test -d "$JOURNAL_DUMP_DIR" -a -w "$JOURNAL_DUMP_DIR" && cp "$TMPFILE" "$JOURNAL_DUMP_DIR/$test_name.img" ++echo "logdump -c" > $TMPFILE.cmd ++$DEBUGFS_EXE -f $TMPFILE.cmd $TMPFILE 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT ++rm -rf $TMPFILE.cmd ++ ++$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 ++status=$? ++echo Exit status is $status >> $OUT.new ++sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT ++rm -f $OUT.new ++ ++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 IMAGE FSCK_OPT OUT EXP ++ ++else #if test -x $DEBUGFS_EXE; then ++ echo "$test_name: $test_description: skipped" ++fi +--- /dev/null ++++ b/tests/j_long_revoke_trans_mcsum_32bit/expect +@@ -0,0 +1,117 @@ ++64-bit filesystem support is not enabled. The larger fields afforded by this feature enable full-strength checksumming. Pass -O 64bit to rectify. ++Creating filesystem with 524288 1k blocks and 32768 inodes ++Superblock backups stored on blocks: ++ 8193, 24577, 40961, 57345, 73729, 204801, 221185, 401409 ++ ++Allocating group tables: done ++Writing inode tables: done ++Creating journal (16384 blocks): done ++Writing superblocks and filesystem accounting information: done ++ ++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/32768 files (0.0% non-contiguous), 27050/524288 blocks ++Exit status is 0 ++Journal features: (none) ++debugfs write journal ++Journal features: journal_incompat_revoke journal_checksum_v3 ++debugfs: logdump -c ++Journal starts at block 1, transaction 1 ++Found expected sequence 1, type 1 (descriptor block) at block 1 ++Found expected sequence 1, type 1 (descriptor block) at block 64 ++Found expected sequence 1, type 1 (descriptor block) at block 127 ++Found expected sequence 1, type 1 (descriptor block) at block 190 ++Found expected sequence 1, type 1 (descriptor block) at block 253 ++Found expected sequence 1, type 1 (descriptor block) at block 316 ++Found expected sequence 1, type 1 (descriptor block) at block 379 ++Found expected sequence 1, type 1 (descriptor block) at block 442 ++Found expected sequence 1, type 1 (descriptor block) at block 505 ++Found expected sequence 1, type 1 (descriptor block) at block 568 ++Found expected sequence 1, type 1 (descriptor block) at block 631 ++Found expected sequence 1, type 1 (descriptor block) at block 694 ++Found expected sequence 1, type 1 (descriptor block) at block 757 ++Found expected sequence 1, type 1 (descriptor block) at block 820 ++Found expected sequence 1, type 1 (descriptor block) at block 883 ++Found expected sequence 1, type 1 (descriptor block) at block 946 ++Found expected sequence 1, type 1 (descriptor block) at block 1009 ++Found expected sequence 1, type 1 (descriptor block) at block 1072 ++Found expected sequence 1, type 1 (descriptor block) at block 1135 ++Found expected sequence 1, type 1 (descriptor block) at block 1198 ++Found expected sequence 1, type 1 (descriptor block) at block 1261 ++Found expected sequence 1, type 1 (descriptor block) at block 1324 ++Found expected sequence 1, type 1 (descriptor block) at block 1387 ++Found expected sequence 1, type 1 (descriptor block) at block 1450 ++Found expected sequence 1, type 1 (descriptor block) at block 1513 ++Found expected sequence 1, type 1 (descriptor block) at block 1576 ++Found expected sequence 1, type 1 (descriptor block) at block 1639 ++Found expected sequence 1, type 1 (descriptor block) at block 1702 ++Found expected sequence 1, type 1 (descriptor block) at block 1765 ++Found expected sequence 1, type 1 (descriptor block) at block 1828 ++Found expected sequence 1, type 1 (descriptor block) at block 1891 ++Found expected sequence 1, type 1 (descriptor block) at block 1954 ++Found expected sequence 1, type 1 (descriptor block) at block 2017 ++Found expected sequence 1, type 1 (descriptor block) at block 2080 ++Found expected sequence 1, type 1 (descriptor block) at block 2143 ++Found expected sequence 1, type 1 (descriptor block) at block 2206 ++Found expected sequence 1, type 1 (descriptor block) at block 2269 ++Found expected sequence 1, type 1 (descriptor block) at block 2332 ++Found expected sequence 1, type 1 (descriptor block) at block 2395 ++Found expected sequence 1, type 1 (descriptor block) at block 2458 ++Found expected sequence 1, type 1 (descriptor block) at block 2521 ++Found expected sequence 1, type 1 (descriptor block) at block 2584 ++Found expected sequence 1, type 1 (descriptor block) at block 2647 ++Found expected sequence 1, type 1 (descriptor block) at block 2710 ++Found expected sequence 1, type 1 (descriptor block) at block 2773 ++Found expected sequence 1, type 1 (descriptor block) at block 2836 ++Found expected sequence 1, type 1 (descriptor block) at block 2899 ++Found expected sequence 1, type 1 (descriptor block) at block 2962 ++Found expected sequence 1, type 1 (descriptor block) at block 3025 ++Found expected sequence 1, type 1 (descriptor block) at block 3088 ++Found expected sequence 1, type 1 (descriptor block) at block 3151 ++Found expected sequence 1, type 1 (descriptor block) at block 3214 ++Found expected sequence 1, type 1 (descriptor block) at block 3277 ++Found expected sequence 1, type 1 (descriptor block) at block 3340 ++Found expected sequence 1, type 1 (descriptor block) at block 3403 ++Found expected sequence 1, type 1 (descriptor block) at block 3466 ++Found expected sequence 1, type 1 (descriptor block) at block 3529 ++Found expected sequence 1, type 1 (descriptor block) at block 3592 ++Found expected sequence 1, type 1 (descriptor block) at block 3655 ++Found expected sequence 1, type 1 (descriptor block) at block 3718 ++Found expected sequence 1, type 1 (descriptor block) at block 3781 ++Found expected sequence 1, type 1 (descriptor block) at block 3844 ++Found expected sequence 1, type 1 (descriptor block) at block 3907 ++Found expected sequence 1, type 1 (descriptor block) at block 3970 ++Found expected sequence 1, type 1 (descriptor block) at block 4033 ++Found expected sequence 1, type 1 (descriptor block) at block 4096 ++Found expected sequence 1, type 1 (descriptor block) at block 4159 ++Found expected sequence 1, type 2 (commit block) at block 4165 ++Found expected sequence 2, type 5 (revoke table) at block 4166 ++Found expected sequence 2, type 5 (revoke table) at block 4167 ++Found expected sequence 2, type 5 (revoke table) at block 4168 ++Found expected sequence 2, type 5 (revoke table) at block 4169 ++Found expected sequence 2, type 5 (revoke table) at block 4170 ++Found expected sequence 2, type 5 (revoke table) at block 4171 ++Found expected sequence 2, type 5 (revoke table) at block 4172 ++Found expected sequence 2, type 5 (revoke table) at block 4173 ++Found expected sequence 2, type 5 (revoke table) at block 4174 ++Found expected sequence 2, type 5 (revoke table) at block 4175 ++Found expected sequence 2, type 5 (revoke table) at block 4176 ++Found expected sequence 2, type 5 (revoke table) at block 4177 ++Found expected sequence 2, type 5 (revoke table) at block 4178 ++Found expected sequence 2, type 5 (revoke table) at block 4179 ++Found expected sequence 2, type 5 (revoke table) at block 4180 ++Found expected sequence 2, type 5 (revoke table) at block 4181 ++Found expected sequence 2, type 5 (revoke table) at block 4182 ++Found expected sequence 2, type 2 (commit block) at block 4183 ++No magic number at block 4184: end of journal. ++test_filesys: recovering journal ++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/32768 files (0.0% non-contiguous), 27050/524288 blocks ++Exit status is 0 +--- /dev/null ++++ b/tests/j_long_revoke_trans_mcsum_32bit/name +@@ -0,0 +1 @@ ++revoked transaction nuking free space on 32bit,metadata_csum +--- /dev/null ++++ b/tests/j_long_revoke_trans_mcsum_32bit/script +@@ -0,0 +1,67 @@ ++if test -x $DEBUGFS_EXE; then ++ ++FSCK_OPT=-fy ++OUT=$test_name.log ++if [ -f $test_dir/expect.gz ]; then ++ EXP=$test_name.tmp ++ gunzip < $test_dir/expect.gz > $EXP1 ++else ++ EXP=$test_dir/expect ++fi ++ ++cp /dev/null $OUT ++ ++$MKE2FS -F -o Linux -b 1024 -O ^64bit,has_journal,metadata_csum -T ext4 $TMPFILE 524288 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT 2>&1 ++ ++$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 ++status=$? ++echo Exit status is $status >> $OUT.new ++sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT ++rm -f $OUT.new ++ ++$DUMPE2FS $TMPFILE 2>&1 | grep '^Journal features:' >> $OUT ++ ++echo "debugfs write journal" >> $OUT ++echo "jo -c" > $TMPFILE.cmd ++echo "jw -b 260-4356 /dev/zero" >> $TMPFILE.cmd ++echo "jc" >> $TMPFILE.cmd ++echo "jo" >> $TMPFILE.cmd ++echo "jw -r 260-4356" >> $TMPFILE.cmd ++echo "jc" >> $TMPFILE.cmd ++#$DEBUGFS_EXE -w $TMPFILE -f $TMPFILE.cmd >> $OUT 2>&1 ++$DEBUGFS_EXE -w -f $TMPFILE.cmd $TMPFILE 2>> $OUT.new > /dev/null ++sed -f $cmd_dir/filter.sed < $OUT.new >> $OUT ++rm -rf $OUT.new ++ ++$DUMPE2FS $TMPFILE 2>&1 | grep '^Journal features:' >> $OUT ++ ++test -d "$JOURNAL_DUMP_DIR" -a -w "$JOURNAL_DUMP_DIR" && cp "$TMPFILE" "$JOURNAL_DUMP_DIR/$test_name.img" ++echo "logdump -c" > $TMPFILE.cmd ++$DEBUGFS_EXE -f $TMPFILE.cmd $TMPFILE 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT ++rm -rf $TMPFILE.cmd ++ ++$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 ++status=$? ++echo Exit status is $status >> $OUT.new ++sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT ++rm -f $OUT.new ++ ++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 IMAGE FSCK_OPT OUT EXP ++ ++else #if test -x $DEBUGFS_EXE; then ++ echo "$test_name: $test_description: skipped" ++fi +--- /dev/null ++++ b/tests/j_long_revoke_trans_mcsum_64bit/expect +@@ -0,0 +1,132 @@ ++Creating filesystem with 524288 1k blocks and 32768 inodes ++Superblock backups stored on blocks: ++ 8193, 24577, 40961, 57345, 73729, 204801, 221185, 401409 ++ ++Allocating group tables: done ++Writing inode tables: done ++Creating journal (16384 blocks): done ++Writing superblocks and filesystem accounting information: done ++ ++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/32768 files (0.0% non-contiguous), 27068/524288 blocks ++Exit status is 0 ++Journal features: (none) ++debugfs write journal ++Journal features: journal_incompat_revoke journal_64bit journal_checksum_v3 ++debugfs: logdump -c ++Journal starts at block 1, transaction 1 ++Found expected sequence 1, type 1 (descriptor block) at block 1 ++Found expected sequence 1, type 1 (descriptor block) at block 64 ++Found expected sequence 1, type 1 (descriptor block) at block 127 ++Found expected sequence 1, type 1 (descriptor block) at block 190 ++Found expected sequence 1, type 1 (descriptor block) at block 253 ++Found expected sequence 1, type 1 (descriptor block) at block 316 ++Found expected sequence 1, type 1 (descriptor block) at block 379 ++Found expected sequence 1, type 1 (descriptor block) at block 442 ++Found expected sequence 1, type 1 (descriptor block) at block 505 ++Found expected sequence 1, type 1 (descriptor block) at block 568 ++Found expected sequence 1, type 1 (descriptor block) at block 631 ++Found expected sequence 1, type 1 (descriptor block) at block 694 ++Found expected sequence 1, type 1 (descriptor block) at block 757 ++Found expected sequence 1, type 1 (descriptor block) at block 820 ++Found expected sequence 1, type 1 (descriptor block) at block 883 ++Found expected sequence 1, type 1 (descriptor block) at block 946 ++Found expected sequence 1, type 1 (descriptor block) at block 1009 ++Found expected sequence 1, type 1 (descriptor block) at block 1072 ++Found expected sequence 1, type 1 (descriptor block) at block 1135 ++Found expected sequence 1, type 1 (descriptor block) at block 1198 ++Found expected sequence 1, type 1 (descriptor block) at block 1261 ++Found expected sequence 1, type 1 (descriptor block) at block 1324 ++Found expected sequence 1, type 1 (descriptor block) at block 1387 ++Found expected sequence 1, type 1 (descriptor block) at block 1450 ++Found expected sequence 1, type 1 (descriptor block) at block 1513 ++Found expected sequence 1, type 1 (descriptor block) at block 1576 ++Found expected sequence 1, type 1 (descriptor block) at block 1639 ++Found expected sequence 1, type 1 (descriptor block) at block 1702 ++Found expected sequence 1, type 1 (descriptor block) at block 1765 ++Found expected sequence 1, type 1 (descriptor block) at block 1828 ++Found expected sequence 1, type 1 (descriptor block) at block 1891 ++Found expected sequence 1, type 1 (descriptor block) at block 1954 ++Found expected sequence 1, type 1 (descriptor block) at block 2017 ++Found expected sequence 1, type 1 (descriptor block) at block 2080 ++Found expected sequence 1, type 1 (descriptor block) at block 2143 ++Found expected sequence 1, type 1 (descriptor block) at block 2206 ++Found expected sequence 1, type 1 (descriptor block) at block 2269 ++Found expected sequence 1, type 1 (descriptor block) at block 2332 ++Found expected sequence 1, type 1 (descriptor block) at block 2395 ++Found expected sequence 1, type 1 (descriptor block) at block 2458 ++Found expected sequence 1, type 1 (descriptor block) at block 2521 ++Found expected sequence 1, type 1 (descriptor block) at block 2584 ++Found expected sequence 1, type 1 (descriptor block) at block 2647 ++Found expected sequence 1, type 1 (descriptor block) at block 2710 ++Found expected sequence 1, type 1 (descriptor block) at block 2773 ++Found expected sequence 1, type 1 (descriptor block) at block 2836 ++Found expected sequence 1, type 1 (descriptor block) at block 2899 ++Found expected sequence 1, type 1 (descriptor block) at block 2962 ++Found expected sequence 1, type 1 (descriptor block) at block 3025 ++Found expected sequence 1, type 1 (descriptor block) at block 3088 ++Found expected sequence 1, type 1 (descriptor block) at block 3151 ++Found expected sequence 1, type 1 (descriptor block) at block 3214 ++Found expected sequence 1, type 1 (descriptor block) at block 3277 ++Found expected sequence 1, type 1 (descriptor block) at block 3340 ++Found expected sequence 1, type 1 (descriptor block) at block 3403 ++Found expected sequence 1, type 1 (descriptor block) at block 3466 ++Found expected sequence 1, type 1 (descriptor block) at block 3529 ++Found expected sequence 1, type 1 (descriptor block) at block 3592 ++Found expected sequence 1, type 1 (descriptor block) at block 3655 ++Found expected sequence 1, type 1 (descriptor block) at block 3718 ++Found expected sequence 1, type 1 (descriptor block) at block 3781 ++Found expected sequence 1, type 1 (descriptor block) at block 3844 ++Found expected sequence 1, type 1 (descriptor block) at block 3907 ++Found expected sequence 1, type 1 (descriptor block) at block 3970 ++Found expected sequence 1, type 1 (descriptor block) at block 4033 ++Found expected sequence 1, type 1 (descriptor block) at block 4096 ++Found expected sequence 1, type 1 (descriptor block) at block 4159 ++Found expected sequence 1, type 2 (commit block) at block 4165 ++Found expected sequence 2, type 5 (revoke table) at block 4166 ++Found expected sequence 2, type 5 (revoke table) at block 4167 ++Found expected sequence 2, type 5 (revoke table) at block 4168 ++Found expected sequence 2, type 5 (revoke table) at block 4169 ++Found expected sequence 2, type 5 (revoke table) at block 4170 ++Found expected sequence 2, type 5 (revoke table) at block 4171 ++Found expected sequence 2, type 5 (revoke table) at block 4172 ++Found expected sequence 2, type 5 (revoke table) at block 4173 ++Found expected sequence 2, type 5 (revoke table) at block 4174 ++Found expected sequence 2, type 5 (revoke table) at block 4175 ++Found expected sequence 2, type 5 (revoke table) at block 4176 ++Found expected sequence 2, type 5 (revoke table) at block 4177 ++Found expected sequence 2, type 5 (revoke table) at block 4178 ++Found expected sequence 2, type 5 (revoke table) at block 4179 ++Found expected sequence 2, type 5 (revoke table) at block 4180 ++Found expected sequence 2, type 5 (revoke table) at block 4181 ++Found expected sequence 2, type 5 (revoke table) at block 4182 ++Found expected sequence 2, type 5 (revoke table) at block 4183 ++Found expected sequence 2, type 5 (revoke table) at block 4184 ++Found expected sequence 2, type 5 (revoke table) at block 4185 ++Found expected sequence 2, type 5 (revoke table) at block 4186 ++Found expected sequence 2, type 5 (revoke table) at block 4187 ++Found expected sequence 2, type 5 (revoke table) at block 4188 ++Found expected sequence 2, type 5 (revoke table) at block 4189 ++Found expected sequence 2, type 5 (revoke table) at block 4190 ++Found expected sequence 2, type 5 (revoke table) at block 4191 ++Found expected sequence 2, type 5 (revoke table) at block 4192 ++Found expected sequence 2, type 5 (revoke table) at block 4193 ++Found expected sequence 2, type 5 (revoke table) at block 4194 ++Found expected sequence 2, type 5 (revoke table) at block 4195 ++Found expected sequence 2, type 5 (revoke table) at block 4196 ++Found expected sequence 2, type 5 (revoke table) at block 4197 ++Found expected sequence 2, type 5 (revoke table) at block 4198 ++Found expected sequence 2, type 2 (commit block) at block 4199 ++No magic number at block 4200: end of journal. ++test_filesys: recovering journal ++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/32768 files (0.0% non-contiguous), 27068/524288 blocks ++Exit status is 0 +--- /dev/null ++++ b/tests/j_long_revoke_trans_mcsum_64bit/name +@@ -0,0 +1 @@ ++revoked transaction nuking free space on 64bit,metadata_csum +--- /dev/null ++++ b/tests/j_long_revoke_trans_mcsum_64bit/script +@@ -0,0 +1,67 @@ ++if test -x $DEBUGFS_EXE; then ++ ++FSCK_OPT=-fy ++OUT=$test_name.log ++if [ -f $test_dir/expect.gz ]; then ++ EXP=$test_name.tmp ++ gunzip < $test_dir/expect.gz > $EXP1 ++else ++ EXP=$test_dir/expect ++fi ++ ++cp /dev/null $OUT ++ ++$MKE2FS -F -o Linux -b 1024 -O 64bit,has_journal,metadata_csum -T ext4 $TMPFILE 524288 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT 2>&1 ++ ++$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 ++status=$? ++echo Exit status is $status >> $OUT.new ++sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT ++rm -f $OUT.new ++ ++$DUMPE2FS $TMPFILE 2>&1 | grep '^Journal features:' >> $OUT ++ ++echo "debugfs write journal" >> $OUT ++echo "jo -c" > $TMPFILE.cmd ++echo "jw -b 262-4358 /dev/zero" >> $TMPFILE.cmd ++echo "jc" >> $TMPFILE.cmd ++echo "jo" >> $TMPFILE.cmd ++echo "jw -r 262-4358" >> $TMPFILE.cmd ++echo "jc" >> $TMPFILE.cmd ++#$DEBUGFS_EXE -w $TMPFILE -f $TMPFILE.cmd >> $OUT 2>&1 ++$DEBUGFS_EXE -w -f $TMPFILE.cmd $TMPFILE 2>> $OUT.new > /dev/null ++sed -f $cmd_dir/filter.sed < $OUT.new >> $OUT ++rm -rf $OUT.new ++ ++$DUMPE2FS $TMPFILE 2>&1 | grep '^Journal features:' >> $OUT ++ ++test -d "$JOURNAL_DUMP_DIR" -a -w "$JOURNAL_DUMP_DIR" && cp "$TMPFILE" "$JOURNAL_DUMP_DIR/$test_name.img" ++echo "logdump -c" > $TMPFILE.cmd ++$DEBUGFS_EXE -f $TMPFILE.cmd $TMPFILE 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT ++rm -rf $TMPFILE.cmd ++ ++$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 ++status=$? ++echo Exit status is $status >> $OUT.new ++sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT ++rm -f $OUT.new ++ ++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 IMAGE FSCK_OPT OUT EXP ++ ++else #if test -x $DEBUGFS_EXE; then ++ echo "$test_name: $test_description: skipped" ++fi +--- /dev/null ++++ b/tests/j_long_trans/expect +@@ -0,0 +1,107 @@ ++Creating filesystem with 262144 1k blocks and 16384 inodes ++Superblock backups stored on blocks: ++ 8193, 24577, 40961, 57345, 73729, 204801, 221185 ++ ++Allocating group tables: done ++Writing inode tables: done ++Creating journal (8192 blocks): done ++Writing superblocks and filesystem accounting information: done ++ ++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/16384 files (0.0% non-contiguous), 14431/262144 blocks ++Exit status is 0 ++debugfs write journal ++debugfs: logdump -c ++Journal starts at block 1, transaction 1 ++Found expected sequence 1, type 1 (descriptor block) at block 1 ++Found expected sequence 1, type 1 (descriptor block) at block 126 ++Found expected sequence 1, type 1 (descriptor block) at block 251 ++Found expected sequence 1, type 1 (descriptor block) at block 376 ++Found expected sequence 1, type 1 (descriptor block) at block 501 ++Found expected sequence 1, type 1 (descriptor block) at block 626 ++Found expected sequence 1, type 1 (descriptor block) at block 751 ++Found expected sequence 1, type 1 (descriptor block) at block 876 ++Found expected sequence 1, type 1 (descriptor block) at block 1001 ++Found expected sequence 1, type 1 (descriptor block) at block 1126 ++Found expected sequence 1, type 1 (descriptor block) at block 1251 ++Found expected sequence 1, type 1 (descriptor block) at block 1376 ++Found expected sequence 1, type 1 (descriptor block) at block 1501 ++Found expected sequence 1, type 1 (descriptor block) at block 1626 ++Found expected sequence 1, type 1 (descriptor block) at block 1751 ++Found expected sequence 1, type 1 (descriptor block) at block 1876 ++Found expected sequence 1, type 1 (descriptor block) at block 2001 ++Found expected sequence 1, type 1 (descriptor block) at block 2126 ++Found expected sequence 1, type 1 (descriptor block) at block 2251 ++Found expected sequence 1, type 1 (descriptor block) at block 2376 ++Found expected sequence 1, type 1 (descriptor block) at block 2501 ++Found expected sequence 1, type 1 (descriptor block) at block 2626 ++Found expected sequence 1, type 1 (descriptor block) at block 2751 ++Found expected sequence 1, type 1 (descriptor block) at block 2876 ++Found expected sequence 1, type 1 (descriptor block) at block 3001 ++Found expected sequence 1, type 1 (descriptor block) at block 3126 ++Found expected sequence 1, type 1 (descriptor block) at block 3251 ++Found expected sequence 1, type 1 (descriptor block) at block 3376 ++Found expected sequence 1, type 1 (descriptor block) at block 3501 ++Found expected sequence 1, type 1 (descriptor block) at block 3626 ++Found expected sequence 1, type 1 (descriptor block) at block 3751 ++Found expected sequence 1, type 1 (descriptor block) at block 3876 ++Found expected sequence 1, type 1 (descriptor block) at block 4001 ++Found expected sequence 1, type 1 (descriptor block) at block 4126 ++Found expected sequence 1, type 2 (commit block) at block 4133 ++No magic number at block 4134: end of journal. ++test_filesys: recovering journal ++Superblock has an invalid journal (inode 8). ++Clear? yes ++ ++*** journal has been deleted *** ++ ++Resize inode not valid. Recreate? yes ++ ++Pass 1: Checking inodes, blocks, and sizes ++Root inode is not a directory. Clear? yes ++ ++Pass 2: Checking directory structure ++Pass 3: Checking directory connectivity ++Root inode not allocated. Allocate? yes ++ ++/lost+found not found. Create? yes ++ ++Pass 4: Checking reference counts ++Pass 5: Checking group summary information ++Block bitmap differences: +(1--259) +273 +275 +289 +(291--418) +(2083--2210) +2341 ++Fix? yes ++ ++Free blocks count wrong for group #0 (5838, counted=5851). ++Fix? yes ++ ++Free blocks count wrong for group #14 (0, counted=8192). ++Fix? yes ++ ++Free blocks count wrong (247711, counted=255916). ++Fix? yes ++ ++Inode bitmap differences: +1 +(3--10) ++Fix? yes ++ ++Free inodes count wrong for group #0 (500, counted=501). ++Fix? yes ++ ++Directories count wrong for group #0 (3, counted=2). ++Fix? yes ++ ++Free inodes count wrong (16372, counted=16373). ++Fix? yes ++ ++Recreate journal? yes ++ ++Creating journal (8192 blocks): Done. ++ ++*** journal has been regenerated *** ++ ++test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** ++test_filesys: 11/16384 files (0.0% non-contiguous), 14420/262144 blocks ++Exit status is 1 +--- /dev/null ++++ b/tests/j_long_trans/name +@@ -0,0 +1 @@ ++transaction nuking free space +--- /dev/null ++++ b/tests/j_long_trans/script +@@ -0,0 +1,59 @@ ++if test -x $DEBUGFS_EXE; then ++ ++FSCK_OPT=-fy ++OUT=$test_name.log ++if [ -f $test_dir/expect.gz ]; then ++ EXP=$test_name.tmp ++ gunzip < $test_dir/expect.gz > $EXP1 ++else ++ EXP=$test_dir/expect ++fi ++ ++cp /dev/null $OUT ++ ++$MKE2FS -F -o Linux -b 1024 -O has_journal -T ext4 $TMPFILE 262144 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT 2>&1 ++ ++$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 ++status=$? ++echo Exit status is $status >> $OUT.new ++sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT ++rm -f $OUT.new ++ ++echo "debugfs write journal" >> $OUT ++echo "jo" > $TMPFILE.cmd ++echo "jw -b 259-4356 /dev/zero" >> $TMPFILE.cmd ++echo "jc" >> $TMPFILE.cmd ++$DEBUGFS_EXE -w -f $TMPFILE.cmd $TMPFILE 2>> $OUT.new > /dev/null ++sed -f $cmd_dir/filter.sed < $OUT.new >> $OUT ++rm -rf $OUT.new ++ ++test -d "$JOURNAL_DUMP_DIR" -a -w "$JOURNAL_DUMP_DIR" && cp "$TMPFILE" "$JOURNAL_DUMP_DIR/$test_name.img" ++echo "logdump -c" > $TMPFILE.cmd ++$DEBUGFS_EXE -f $TMPFILE.cmd $TMPFILE 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT ++rm -rf $TMPFILE.cmd ++ ++$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 ++status=$? ++echo Exit status is $status >> $OUT.new ++sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT ++rm -f $OUT.new ++ ++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 IMAGE FSCK_OPT OUT EXP ++ ++else #if test -x $DEBUGFS_EXE; then ++ echo "$test_name: $test_description: skipped" ++fi +--- /dev/null ++++ b/tests/j_long_trans_mcsum_32bit/expect +@@ -0,0 +1,146 @@ ++64-bit filesystem support is not enabled. The larger fields afforded by this feature enable full-strength checksumming. Pass -O 64bit to rectify. ++Creating filesystem with 524288 1k blocks and 32768 inodes ++Superblock backups stored on blocks: ++ 8193, 24577, 40961, 57345, 73729, 204801, 221185, 401409 ++ ++Allocating group tables: done ++Writing inode tables: done ++Creating journal (16384 blocks): done ++Writing superblocks and filesystem accounting information: done ++ ++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/32768 files (0.0% non-contiguous), 27050/524288 blocks ++Exit status is 0 ++Journal features: (none) ++debugfs write journal ++Journal features: journal_checksum_v3 ++debugfs: logdump -c ++Journal starts at block 1, transaction 1 ++Found expected sequence 1, type 1 (descriptor block) at block 1 ++Found expected sequence 1, type 1 (descriptor block) at block 64 ++Found expected sequence 1, type 1 (descriptor block) at block 127 ++Found expected sequence 1, type 1 (descriptor block) at block 190 ++Found expected sequence 1, type 1 (descriptor block) at block 253 ++Found expected sequence 1, type 1 (descriptor block) at block 316 ++Found expected sequence 1, type 1 (descriptor block) at block 379 ++Found expected sequence 1, type 1 (descriptor block) at block 442 ++Found expected sequence 1, type 1 (descriptor block) at block 505 ++Found expected sequence 1, type 1 (descriptor block) at block 568 ++Found expected sequence 1, type 1 (descriptor block) at block 631 ++Found expected sequence 1, type 1 (descriptor block) at block 694 ++Found expected sequence 1, type 1 (descriptor block) at block 757 ++Found expected sequence 1, type 1 (descriptor block) at block 820 ++Found expected sequence 1, type 1 (descriptor block) at block 883 ++Found expected sequence 1, type 1 (descriptor block) at block 946 ++Found expected sequence 1, type 1 (descriptor block) at block 1009 ++Found expected sequence 1, type 1 (descriptor block) at block 1072 ++Found expected sequence 1, type 1 (descriptor block) at block 1135 ++Found expected sequence 1, type 1 (descriptor block) at block 1198 ++Found expected sequence 1, type 1 (descriptor block) at block 1261 ++Found expected sequence 1, type 1 (descriptor block) at block 1324 ++Found expected sequence 1, type 1 (descriptor block) at block 1387 ++Found expected sequence 1, type 1 (descriptor block) at block 1450 ++Found expected sequence 1, type 1 (descriptor block) at block 1513 ++Found expected sequence 1, type 1 (descriptor block) at block 1576 ++Found expected sequence 1, type 1 (descriptor block) at block 1639 ++Found expected sequence 1, type 1 (descriptor block) at block 1702 ++Found expected sequence 1, type 1 (descriptor block) at block 1765 ++Found expected sequence 1, type 1 (descriptor block) at block 1828 ++Found expected sequence 1, type 1 (descriptor block) at block 1891 ++Found expected sequence 1, type 1 (descriptor block) at block 1954 ++Found expected sequence 1, type 1 (descriptor block) at block 2017 ++Found expected sequence 1, type 1 (descriptor block) at block 2080 ++Found expected sequence 1, type 1 (descriptor block) at block 2143 ++Found expected sequence 1, type 1 (descriptor block) at block 2206 ++Found expected sequence 1, type 1 (descriptor block) at block 2269 ++Found expected sequence 1, type 1 (descriptor block) at block 2332 ++Found expected sequence 1, type 1 (descriptor block) at block 2395 ++Found expected sequence 1, type 1 (descriptor block) at block 2458 ++Found expected sequence 1, type 1 (descriptor block) at block 2521 ++Found expected sequence 1, type 1 (descriptor block) at block 2584 ++Found expected sequence 1, type 1 (descriptor block) at block 2647 ++Found expected sequence 1, type 1 (descriptor block) at block 2710 ++Found expected sequence 1, type 1 (descriptor block) at block 2773 ++Found expected sequence 1, type 1 (descriptor block) at block 2836 ++Found expected sequence 1, type 1 (descriptor block) at block 2899 ++Found expected sequence 1, type 1 (descriptor block) at block 2962 ++Found expected sequence 1, type 1 (descriptor block) at block 3025 ++Found expected sequence 1, type 1 (descriptor block) at block 3088 ++Found expected sequence 1, type 1 (descriptor block) at block 3151 ++Found expected sequence 1, type 1 (descriptor block) at block 3214 ++Found expected sequence 1, type 1 (descriptor block) at block 3277 ++Found expected sequence 1, type 1 (descriptor block) at block 3340 ++Found expected sequence 1, type 1 (descriptor block) at block 3403 ++Found expected sequence 1, type 1 (descriptor block) at block 3466 ++Found expected sequence 1, type 1 (descriptor block) at block 3529 ++Found expected sequence 1, type 1 (descriptor block) at block 3592 ++Found expected sequence 1, type 1 (descriptor block) at block 3655 ++Found expected sequence 1, type 1 (descriptor block) at block 3718 ++Found expected sequence 1, type 1 (descriptor block) at block 3781 ++Found expected sequence 1, type 1 (descriptor block) at block 3844 ++Found expected sequence 1, type 1 (descriptor block) at block 3907 ++Found expected sequence 1, type 1 (descriptor block) at block 3970 ++Found expected sequence 1, type 1 (descriptor block) at block 4033 ++Found expected sequence 1, type 1 (descriptor block) at block 4096 ++Found expected sequence 1, type 1 (descriptor block) at block 4159 ++Found expected sequence 1, type 2 (commit block) at block 4165 ++No magic number at block 4166: end of journal. ++test_filesys: recovering journal ++Superblock has an invalid journal (inode 8). ++Clear? yes ++ ++*** journal has been deleted *** ++ ++Resize inode not valid. Recreate? yes ++ ++Pass 1: Checking inodes, blocks, and sizes ++Root inode is not a directory. Clear? yes ++ ++Pass 2: Checking directory structure ++Pass 3: Checking directory connectivity ++Root inode not allocated. Allocate? yes ++ ++/lost+found not found. Create? yes ++ ++Pass 4: Checking reference counts ++Pass 5: Checking group summary information ++Block bitmap differences: +(1--260) +276 +(292--419) +2342 -(139265--155648) ++Fix? yes ++ ++Free blocks count wrong for group #0 (5837, counted=5850). ++Fix? yes ++ ++Free blocks count wrong for group #17 (0, counted=8192). ++Fix? yes ++ ++Free blocks count wrong for group #18 (0, counted=8192). ++Fix? yes ++ ++Free blocks count wrong (497236, counted=513633). ++Fix? yes ++ ++Inode bitmap differences: +1 +(3--10) ++Fix? yes ++ ++Free inodes count wrong for group #0 (500, counted=501). ++Fix? yes ++ ++Directories count wrong for group #0 (3, counted=2). ++Fix? yes ++ ++Free inodes count wrong (32756, counted=32757). ++Fix? yes ++ ++Recreate journal? yes ++ ++Creating journal (16384 blocks): Done. ++ ++*** journal has been regenerated *** ++ ++test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** ++test_filesys: 11/32768 files (0.0% non-contiguous), 27039/524288 blocks ++Exit status is 1 +--- /dev/null ++++ b/tests/j_long_trans_mcsum_32bit/name +@@ -0,0 +1 @@ ++transaction nuking free space on 32bit,metadata_csum +--- /dev/null ++++ b/tests/j_long_trans_mcsum_32bit/script +@@ -0,0 +1,63 @@ ++if test -x $DEBUGFS_EXE; then ++ ++FSCK_OPT=-fy ++OUT=$test_name.log ++if [ -f $test_dir/expect.gz ]; then ++ EXP=$test_name.tmp ++ gunzip < $test_dir/expect.gz > $EXP1 ++else ++ EXP=$test_dir/expect ++fi ++ ++cp /dev/null $OUT ++ ++$MKE2FS -F -o Linux -b 1024 -O ^64bit,has_journal,metadata_csum -T ext4 $TMPFILE 524288 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT 2>&1 ++ ++$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 ++status=$? ++echo Exit status is $status >> $OUT.new ++sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT ++rm -f $OUT.new ++ ++$DUMPE2FS $TMPFILE 2>&1 | grep '^Journal features:' >> $OUT ++ ++echo "debugfs write journal" >> $OUT ++echo "jo -c" > $TMPFILE.cmd ++echo "jw -b 260-4356 /dev/zero" >> $TMPFILE.cmd ++echo "jc" >> $TMPFILE.cmd ++$DEBUGFS_EXE -w -f $TMPFILE.cmd $TMPFILE 2>> $OUT.new > /dev/null ++sed -f $cmd_dir/filter.sed < $OUT.new >> $OUT ++rm -rf $OUT.new ++ ++$DUMPE2FS $TMPFILE 2>&1 | grep '^Journal features:' >> $OUT ++ ++test -d "$JOURNAL_DUMP_DIR" -a -w "$JOURNAL_DUMP_DIR" && cp "$TMPFILE" "$JOURNAL_DUMP_DIR/$test_name.img" ++echo "logdump -c" > $TMPFILE.cmd ++$DEBUGFS_EXE -f $TMPFILE.cmd $TMPFILE 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT ++rm -rf $TMPFILE.cmd ++ ++$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 ++status=$? ++echo Exit status is $status >> $OUT.new ++sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT ++rm -f $OUT.new ++ ++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 IMAGE FSCK_OPT OUT EXP ++ ++else #if test -x $DEBUGFS_EXE; then ++ echo "$test_name: $test_description: skipped" ++fi +--- /dev/null ++++ b/tests/j_long_trans_mcsum_64bit/expect +@@ -0,0 +1,145 @@ ++Creating filesystem with 524288 1k blocks and 32768 inodes ++Superblock backups stored on blocks: ++ 8193, 24577, 40961, 57345, 73729, 204801, 221185, 401409 ++ ++Allocating group tables: done ++Writing inode tables: done ++Creating journal (16384 blocks): done ++Writing superblocks and filesystem accounting information: done ++ ++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/32768 files (0.0% non-contiguous), 27068/524288 blocks ++Exit status is 0 ++Journal features: (none) ++debugfs write journal ++Journal features: journal_64bit journal_checksum_v3 ++debugfs: logdump -c ++Journal starts at block 1, transaction 1 ++Found expected sequence 1, type 1 (descriptor block) at block 1 ++Found expected sequence 1, type 1 (descriptor block) at block 64 ++Found expected sequence 1, type 1 (descriptor block) at block 127 ++Found expected sequence 1, type 1 (descriptor block) at block 190 ++Found expected sequence 1, type 1 (descriptor block) at block 253 ++Found expected sequence 1, type 1 (descriptor block) at block 316 ++Found expected sequence 1, type 1 (descriptor block) at block 379 ++Found expected sequence 1, type 1 (descriptor block) at block 442 ++Found expected sequence 1, type 1 (descriptor block) at block 505 ++Found expected sequence 1, type 1 (descriptor block) at block 568 ++Found expected sequence 1, type 1 (descriptor block) at block 631 ++Found expected sequence 1, type 1 (descriptor block) at block 694 ++Found expected sequence 1, type 1 (descriptor block) at block 757 ++Found expected sequence 1, type 1 (descriptor block) at block 820 ++Found expected sequence 1, type 1 (descriptor block) at block 883 ++Found expected sequence 1, type 1 (descriptor block) at block 946 ++Found expected sequence 1, type 1 (descriptor block) at block 1009 ++Found expected sequence 1, type 1 (descriptor block) at block 1072 ++Found expected sequence 1, type 1 (descriptor block) at block 1135 ++Found expected sequence 1, type 1 (descriptor block) at block 1198 ++Found expected sequence 1, type 1 (descriptor block) at block 1261 ++Found expected sequence 1, type 1 (descriptor block) at block 1324 ++Found expected sequence 1, type 1 (descriptor block) at block 1387 ++Found expected sequence 1, type 1 (descriptor block) at block 1450 ++Found expected sequence 1, type 1 (descriptor block) at block 1513 ++Found expected sequence 1, type 1 (descriptor block) at block 1576 ++Found expected sequence 1, type 1 (descriptor block) at block 1639 ++Found expected sequence 1, type 1 (descriptor block) at block 1702 ++Found expected sequence 1, type 1 (descriptor block) at block 1765 ++Found expected sequence 1, type 1 (descriptor block) at block 1828 ++Found expected sequence 1, type 1 (descriptor block) at block 1891 ++Found expected sequence 1, type 1 (descriptor block) at block 1954 ++Found expected sequence 1, type 1 (descriptor block) at block 2017 ++Found expected sequence 1, type 1 (descriptor block) at block 2080 ++Found expected sequence 1, type 1 (descriptor block) at block 2143 ++Found expected sequence 1, type 1 (descriptor block) at block 2206 ++Found expected sequence 1, type 1 (descriptor block) at block 2269 ++Found expected sequence 1, type 1 (descriptor block) at block 2332 ++Found expected sequence 1, type 1 (descriptor block) at block 2395 ++Found expected sequence 1, type 1 (descriptor block) at block 2458 ++Found expected sequence 1, type 1 (descriptor block) at block 2521 ++Found expected sequence 1, type 1 (descriptor block) at block 2584 ++Found expected sequence 1, type 1 (descriptor block) at block 2647 ++Found expected sequence 1, type 1 (descriptor block) at block 2710 ++Found expected sequence 1, type 1 (descriptor block) at block 2773 ++Found expected sequence 1, type 1 (descriptor block) at block 2836 ++Found expected sequence 1, type 1 (descriptor block) at block 2899 ++Found expected sequence 1, type 1 (descriptor block) at block 2962 ++Found expected sequence 1, type 1 (descriptor block) at block 3025 ++Found expected sequence 1, type 1 (descriptor block) at block 3088 ++Found expected sequence 1, type 1 (descriptor block) at block 3151 ++Found expected sequence 1, type 1 (descriptor block) at block 3214 ++Found expected sequence 1, type 1 (descriptor block) at block 3277 ++Found expected sequence 1, type 1 (descriptor block) at block 3340 ++Found expected sequence 1, type 1 (descriptor block) at block 3403 ++Found expected sequence 1, type 1 (descriptor block) at block 3466 ++Found expected sequence 1, type 1 (descriptor block) at block 3529 ++Found expected sequence 1, type 1 (descriptor block) at block 3592 ++Found expected sequence 1, type 1 (descriptor block) at block 3655 ++Found expected sequence 1, type 1 (descriptor block) at block 3718 ++Found expected sequence 1, type 1 (descriptor block) at block 3781 ++Found expected sequence 1, type 1 (descriptor block) at block 3844 ++Found expected sequence 1, type 1 (descriptor block) at block 3907 ++Found expected sequence 1, type 1 (descriptor block) at block 3970 ++Found expected sequence 1, type 1 (descriptor block) at block 4033 ++Found expected sequence 1, type 1 (descriptor block) at block 4096 ++Found expected sequence 1, type 1 (descriptor block) at block 4159 ++Found expected sequence 1, type 2 (commit block) at block 4165 ++No magic number at block 4166: end of journal. ++test_filesys: recovering journal ++Superblock has an invalid journal (inode 8). ++Clear? yes ++ ++*** journal has been deleted *** ++ ++Resize inode not valid. Recreate? yes ++ ++Pass 1: Checking inodes, blocks, and sizes ++Root inode is not a directory. Clear? yes ++ ++Pass 2: Checking directory structure ++Pass 3: Checking directory connectivity ++Root inode not allocated. Allocate? yes ++ ++/lost+found not found. Create? yes ++ ++Pass 4: Checking reference counts ++Pass 5: Checking group summary information ++Block bitmap differences: +(1--262) +278 +(294--421) +2344 -(139265--155648) ++Fix? yes ++ ++Free blocks count wrong for group #0 (5835, counted=5848). ++Fix? yes ++ ++Free blocks count wrong for group #17 (0, counted=8192). ++Fix? yes ++ ++Free blocks count wrong for group #18 (0, counted=8192). ++Fix? yes ++ ++Free blocks count wrong (497218, counted=513615). ++Fix? yes ++ ++Inode bitmap differences: +1 +(3--10) ++Fix? yes ++ ++Free inodes count wrong for group #0 (500, counted=501). ++Fix? yes ++ ++Directories count wrong for group #0 (3, counted=2). ++Fix? yes ++ ++Free inodes count wrong (32756, counted=32757). ++Fix? yes ++ ++Recreate journal? yes ++ ++Creating journal (16384 blocks): Done. ++ ++*** journal has been regenerated *** ++ ++test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** ++test_filesys: 11/32768 files (0.0% non-contiguous), 27057/524288 blocks ++Exit status is 1 +--- /dev/null ++++ b/tests/j_long_trans_mcsum_64bit/name +@@ -0,0 +1 @@ ++transaction nuking free space on 64bit,metadata_csum +--- /dev/null ++++ b/tests/j_long_trans_mcsum_64bit/script +@@ -0,0 +1,63 @@ ++if test -x $DEBUGFS_EXE; then ++ ++FSCK_OPT=-fy ++OUT=$test_name.log ++if [ -f $test_dir/expect.gz ]; then ++ EXP=$test_name.tmp ++ gunzip < $test_dir/expect.gz > $EXP1 ++else ++ EXP=$test_dir/expect ++fi ++ ++cp /dev/null $OUT ++ ++$MKE2FS -F -o Linux -b 1024 -O 64bit,has_journal,metadata_csum -T ext4 $TMPFILE 524288 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT 2>&1 ++ ++$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 ++status=$? ++echo Exit status is $status >> $OUT.new ++sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT ++rm -f $OUT.new ++ ++$DUMPE2FS $TMPFILE 2>&1 | grep '^Journal features:' >> $OUT ++ ++echo "debugfs write journal" >> $OUT ++echo "jo -c" > $TMPFILE.cmd ++echo "jw -b 262-4358 /dev/zero" >> $TMPFILE.cmd ++echo "jc" >> $TMPFILE.cmd ++$DEBUGFS_EXE -w -f $TMPFILE.cmd $TMPFILE 2>> $OUT.new > /dev/null ++sed -f $cmd_dir/filter.sed < $OUT.new >> $OUT ++rm -rf $OUT.new ++ ++$DUMPE2FS $TMPFILE 2>&1 | grep '^Journal features:' >> $OUT ++ ++test -d "$JOURNAL_DUMP_DIR" -a -w "$JOURNAL_DUMP_DIR" && cp "$TMPFILE" "$JOURNAL_DUMP_DIR/$test_name.img" ++echo "logdump -c" > $TMPFILE.cmd ++$DEBUGFS_EXE -f $TMPFILE.cmd $TMPFILE 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT ++rm -rf $TMPFILE.cmd ++ ++$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 ++status=$? ++echo Exit status is $status >> $OUT.new ++sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT ++rm -f $OUT.new ++ ++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 IMAGE FSCK_OPT OUT EXP ++ ++else #if test -x $DEBUGFS_EXE; then ++ echo "$test_name: $test_description: skipped" ++fi +--- /dev/null ++++ b/tests/j_recover_csum2_32bit/expect.1 +@@ -0,0 +1,16 @@ ++test_filesys: recovering journal ++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: +(1--259) +265 +(274--275) +281 +(290--418) +(1059--1186) +(2211--2352) ++Fix? yes ++ ++Inode bitmap differences: +(1--11) ++Fix? yes ++ ++ ++test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** ++test_filesys: 11/8192 files (0.0% non-contiguous), 7739/131072 blocks ++Exit status is 0 +--- /dev/null ++++ b/tests/j_recover_csum2_32bit/expect.2 +@@ -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/8192 files (0.0% non-contiguous), 7739/131072 blocks ++Exit status is 0 +--- /dev/null ++++ b/tests/j_recover_csum2_32bit/name +@@ -0,0 +1 @@ ++recover 32-bit journal checksum v2 +--- /dev/null ++++ b/tests/j_recover_csum2_32bit/script +@@ -0,0 +1,31 @@ ++#!/bin/bash ++ ++FSCK_OPT=-fy ++IMAGE=$test_dir/image.bz2 ++ ++bzip2 -d < $IMAGE > $TMPFILE ++ ++# 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 -N test_filesys $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 -N test_filesys $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 +--- /dev/null ++++ b/tests/j_recover_csum2_64bit/expect.1 +@@ -0,0 +1,16 @@ ++test_filesys: recovering journal ++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: +(1--259) +265 +(274--275) +281 +(290--418) +(1059--1186) +(2211--2352) ++Fix? yes ++ ++Inode bitmap differences: +(1--11) ++Fix? yes ++ ++ ++test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** ++test_filesys: 11/8192 files (0.0% non-contiguous), 7739/131072 blocks ++Exit status is 0 +--- /dev/null ++++ b/tests/j_recover_csum2_64bit/expect.2 +@@ -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/8192 files (0.0% non-contiguous), 7739/131072 blocks ++Exit status is 0 +--- /dev/null ++++ b/tests/j_recover_csum2_64bit/name +@@ -0,0 +1 @@ ++recover 64-bit journal checksum v2 +--- /dev/null ++++ b/tests/j_recover_csum2_64bit/script +@@ -0,0 +1,31 @@ ++#!/bin/bash ++ ++FSCK_OPT=-fy ++IMAGE=$test_dir/image.bz2 ++ ++bzip2 -d < $IMAGE > $TMPFILE ++ ++# 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 -N test_filesys $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 -N test_filesys $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 +--- /dev/null ++++ b/tests/j_short_revoke_trans/expect +@@ -0,0 +1,32 @@ ++Creating filesystem with 65536 4k blocks and 16384 inodes ++Superblock backups stored on blocks: ++ 32768 ++ ++Allocating group tables: done ++Writing inode tables: done ++Creating journal (4096 blocks): done ++Writing superblocks and filesystem accounting information: done ++ ++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/16384 files (0.0% non-contiguous), 5164/65536 blocks ++Exit status is 0 ++debugfs write journal ++debugfs: logdump -c ++Journal starts at block 1, transaction 1 ++Found expected sequence 1, type 1 (descriptor block) at block 1 ++Found expected sequence 1, type 2 (commit block) at block 6 ++Found expected sequence 2, type 5 (revoke table) at block 7 ++Found expected sequence 2, type 2 (commit block) at block 8 ++No magic number at block 9: end of journal. ++test_filesys: recovering journal ++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/16384 files (0.0% non-contiguous), 5164/65536 blocks ++Exit status is 0 +--- /dev/null ++++ b/tests/j_short_revoke_trans/name +@@ -0,0 +1 @@ ++revoke blocks of transaction nuking bitmaps +--- /dev/null ++++ b/tests/j_short_revoke_trans/script +@@ -0,0 +1,64 @@ ++if test -x $DEBUGFS_EXE; then ++ ++FSCK_OPT=-fy ++OUT=$test_name.log ++if [ -f $test_dir/expect.gz ]; then ++ EXP=$test_name.tmp ++ gunzip < $test_dir/expect.gz > $EXP1 ++else ++ EXP=$test_dir/expect ++fi ++ ++cp /dev/null $OUT ++ ++$MKE2FS -F -o Linux -b 4096 -O has_journal -T ext4 $TMPFILE 65536 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT 2>&1 ++ ++$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 ++status=$? ++echo Exit status is $status >> $OUT.new ++sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT ++rm -f $OUT.new ++ ++bitmaps="$($DUMPE2FS $TMPFILE 2>&1 | grep 'bitmap at' | sed -e 's/^.*bitmap at \([0-9]*\).*$/\1/g' | tr '\n' ',')" ++ ++echo "debugfs write journal" >> $OUT ++echo "jo" > $TMPFILE.cmd ++echo "jw -b $bitmaps /dev/zero" >> $TMPFILE.cmd ++echo "jc" >> $TMPFILE.cmd ++echo "jo" >> $TMPFILE.cmd ++echo "jw -r $bitmaps" >> $TMPFILE.cmd ++echo "jc" >> $TMPFILE.cmd ++$DEBUGFS_EXE -w -f $TMPFILE.cmd $TMPFILE 2>> $OUT.new > /dev/null ++sed -f $cmd_dir/filter.sed < $OUT.new >> $OUT ++rm -rf $OUT.new ++ ++test -d "$JOURNAL_DUMP_DIR" -a -w "$JOURNAL_DUMP_DIR" && cp "$TMPFILE" "$JOURNAL_DUMP_DIR/$test_name.img" ++echo "logdump -c" > $TMPFILE.cmd ++$DEBUGFS_EXE -f $TMPFILE.cmd $TMPFILE 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT ++rm -rf $TMPFILE.cmd ++ ++$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 ++status=$? ++echo Exit status is $status >> $OUT.new ++sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT ++rm -f $OUT.new ++ ++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 IMAGE FSCK_OPT OUT EXP ++ ++else #if test -x $DEBUGFS_EXE; then ++ echo "$test_name: $test_description: skipped" ++fi +--- /dev/null ++++ b/tests/j_short_revoke_trans_mcsum_64bit/expect +@@ -0,0 +1,34 @@ ++Creating filesystem with 131072 4k blocks and 32768 inodes ++Superblock backups stored on blocks: ++ 32768, 98304 ++ ++Allocating group tables: done ++Writing inode tables: done ++Creating journal (4096 blocks): done ++Writing superblocks and filesystem accounting information: done ++ ++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/32768 files (0.0% non-contiguous), 6353/131072 blocks ++Exit status is 0 ++Journal features: (none) ++debugfs write journal ++Journal features: journal_incompat_revoke journal_64bit journal_checksum_v3 ++debugfs: logdump -c ++Journal starts at block 1, transaction 1 ++Found expected sequence 1, type 1 (descriptor block) at block 1 ++Found expected sequence 1, type 2 (commit block) at block 10 ++Found expected sequence 2, type 5 (revoke table) at block 11 ++Found expected sequence 2, type 2 (commit block) at block 12 ++No magic number at block 13: end of journal. ++test_filesys: recovering journal ++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/32768 files (0.0% non-contiguous), 6353/131072 blocks ++Exit status is 0 +--- /dev/null ++++ b/tests/j_short_revoke_trans_mcsum_64bit/name +@@ -0,0 +1 @@ ++revoke blocks of transaction nuking the bitmaps on 64bit,metadata_csum +--- /dev/null ++++ b/tests/j_short_revoke_trans_mcsum_64bit/script +@@ -0,0 +1,68 @@ ++if test -x $DEBUGFS_EXE; then ++ ++FSCK_OPT=-fy ++OUT=$test_name.log ++if [ -f $test_dir/expect.gz ]; then ++ EXP=$test_name.tmp ++ gunzip < $test_dir/expect.gz > $EXP1 ++else ++ EXP=$test_dir/expect ++fi ++ ++cp /dev/null $OUT ++ ++$MKE2FS -F -o Linux -b 4096 -O 64bit,has_journal,metadata_csum -T ext4 $TMPFILE 131072 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT 2>&1 ++ ++$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 ++status=$? ++echo Exit status is $status >> $OUT.new ++sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT ++rm -f $OUT.new ++ ++bitmaps="$($DUMPE2FS $TMPFILE 2>&1 | grep 'bitmap at' | sed -e 's/^.*bitmap at \([0-9]*\).*$/\1/g' | tr '\n' ',')" ++ ++$DUMPE2FS $TMPFILE 2>&1 | grep '^Journal features:' >> $OUT ++ ++echo "debugfs write journal" >> $OUT ++echo "jo -c" > $TMPFILE.cmd ++echo "jw -b $bitmaps /dev/zero" >> $TMPFILE.cmd ++echo "jc" >> $TMPFILE.cmd ++echo "jo" >> $TMPFILE.cmd ++echo "jw -r $bitmaps" >> $TMPFILE.cmd ++echo "jc" >> $TMPFILE.cmd ++$DEBUGFS_EXE -w -f $TMPFILE.cmd $TMPFILE 2>> $OUT.new > /dev/null ++sed -f $cmd_dir/filter.sed < $OUT.new >> $OUT ++rm -rf $OUT.new ++ ++$DUMPE2FS $TMPFILE 2>&1 | grep '^Journal features:' >> $OUT ++ ++test -d "$JOURNAL_DUMP_DIR" -a -w "$JOURNAL_DUMP_DIR" && cp "$TMPFILE" "$JOURNAL_DUMP_DIR/$test_name.img" ++echo "logdump -c" > $TMPFILE.cmd ++$DEBUGFS_EXE -f $TMPFILE.cmd $TMPFILE 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT ++rm -rf $TMPFILE.cmd ++ ++$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 ++status=$? ++echo Exit status is $status >> $OUT.new ++sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT ++rm -f $OUT.new ++ ++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 IMAGE FSCK_OPT OUT EXP ++ ++else #if test -x $DEBUGFS_EXE; then ++ echo "$test_name: $test_description: skipped" ++fi +--- /dev/null ++++ b/tests/j_short_trans/expect +@@ -0,0 +1,38 @@ ++Creating filesystem with 65536 4k blocks and 16384 inodes ++Superblock backups stored on blocks: ++ 32768 ++ ++Allocating group tables: done ++Writing inode tables: done ++Creating journal (4096 blocks): done ++Writing superblocks and filesystem accounting information: done ++ ++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/16384 files (0.0% non-contiguous), 5164/65536 blocks ++Exit status is 0 ++debugfs write journal ++debugfs: logdump -c ++Journal starts at block 1, transaction 1 ++Found expected sequence 1, type 1 (descriptor block) at block 1 ++Found expected sequence 1, type 2 (commit block) at block 6 ++No magic number at block 7: end of journal. ++test_filesys: recovering journal ++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: +(0--1050) +(32768--36880) ++Fix? yes ++ ++Inode bitmap differences: +(1--11) ++Fix? yes ++ ++ ++test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** ++test_filesys: 11/16384 files (0.0% non-contiguous), 5164/65536 blocks ++Exit status is 1 +--- /dev/null ++++ b/tests/j_short_trans/name +@@ -0,0 +1 @@ ++transaction nuking the bitmaps +--- /dev/null ++++ b/tests/j_short_trans/script +@@ -0,0 +1,61 @@ ++if test -x $DEBUGFS_EXE; then ++ ++FSCK_OPT=-fy ++OUT=$test_name.log ++if [ -f $test_dir/expect.gz ]; then ++ EXP=$test_name.tmp ++ gunzip < $test_dir/expect.gz > $EXP1 ++else ++ EXP=$test_dir/expect ++fi ++ ++cp /dev/null $OUT ++ ++$MKE2FS -F -o Linux -b 4096 -O has_journal -T ext4 $TMPFILE 65536 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT 2>&1 ++ ++$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 ++status=$? ++echo Exit status is $status >> $OUT.new ++sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT ++rm -f $OUT.new ++ ++bitmaps="$($DUMPE2FS $TMPFILE 2>&1 | grep 'bitmap at' | sed -e 's/^.*bitmap at \([0-9]*\).*$/\1/g' | tr '\n' ',')" ++ ++echo "debugfs write journal" >> $OUT ++echo "jo" > $TMPFILE.cmd ++echo "jw -b $bitmaps /dev/zero" >> $TMPFILE.cmd ++echo "jc" >> $TMPFILE.cmd ++$DEBUGFS_EXE -w -f $TMPFILE.cmd $TMPFILE 2>> $OUT.new > /dev/null ++sed -f $cmd_dir/filter.sed < $OUT.new >> $OUT ++rm -rf $OUT.new ++ ++test -d "$JOURNAL_DUMP_DIR" -a -w "$JOURNAL_DUMP_DIR" && cp "$TMPFILE" "$JOURNAL_DUMP_DIR/$test_name.img" ++echo "logdump -c" > $TMPFILE.cmd ++$DEBUGFS_EXE -f $TMPFILE.cmd $TMPFILE 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT ++rm -rf $TMPFILE.cmd ++ ++$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 ++status=$? ++echo Exit status is $status >> $OUT.new ++sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT ++rm -f $OUT.new ++ ++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 IMAGE FSCK_OPT OUT EXP ++ ++else #if test -x $DEBUGFS_EXE; then ++ echo "$test_name: $test_description: skipped" ++fi +--- /dev/null ++++ b/tests/j_short_trans_64bit/expect +@@ -0,0 +1,40 @@ ++Creating filesystem with 65536 4k blocks and 16384 inodes ++Superblock backups stored on blocks: ++ 32768 ++ ++Allocating group tables: done ++Writing inode tables: done ++Creating journal (4096 blocks): done ++Writing superblocks and filesystem accounting information: done ++ ++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/16384 files (0.0% non-contiguous), 5196/65536 blocks ++Exit status is 0 ++Journal features: (none) ++debugfs write journal ++Journal features: journal_64bit ++debugfs: logdump -c ++Journal starts at block 1, transaction 1 ++Found expected sequence 1, type 1 (descriptor block) at block 1 ++Found expected sequence 1, type 2 (commit block) at block 6 ++No magic number at block 7: end of journal. ++test_filesys: recovering journal ++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: +(0--1066) +(32768--36896) ++Fix? yes ++ ++Inode bitmap differences: +(1--11) ++Fix? yes ++ ++ ++test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** ++test_filesys: 11/16384 files (0.0% non-contiguous), 5196/65536 blocks ++Exit status is 1 +--- /dev/null ++++ b/tests/j_short_trans_64bit/name +@@ -0,0 +1 @@ ++transaction nuking the bitmaps on 64bit +--- /dev/null ++++ b/tests/j_short_trans_64bit/script +@@ -0,0 +1,65 @@ ++if test -x $DEBUGFS_EXE; then ++ ++FSCK_OPT=-fy ++OUT=$test_name.log ++if [ -f $test_dir/expect.gz ]; then ++ EXP=$test_name.tmp ++ gunzip < $test_dir/expect.gz > $EXP1 ++else ++ EXP=$test_dir/expect ++fi ++ ++cp /dev/null $OUT ++ ++$MKE2FS -F -o Linux -b 4096 -O 64bit,has_journal -T ext4 $TMPFILE 65536 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT 2>&1 ++ ++$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 ++status=$? ++echo Exit status is $status >> $OUT.new ++sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT ++rm -f $OUT.new ++ ++bitmaps="$($DUMPE2FS $TMPFILE 2>&1 | grep 'bitmap at' | sed -e 's/^.*bitmap at \([0-9]*\).*$/\1/g' | tr '\n' ',')" ++ ++$DUMPE2FS $TMPFILE 2>&1 | grep '^Journal features:' >> $OUT ++ ++echo "debugfs write journal" >> $OUT ++echo "jo" > $TMPFILE.cmd ++echo "jw -b $bitmaps /dev/zero" >> $TMPFILE.cmd ++echo "jc" >> $TMPFILE.cmd ++$DEBUGFS_EXE -w -f $TMPFILE.cmd $TMPFILE 2>> $OUT.new > /dev/null ++sed -f $cmd_dir/filter.sed < $OUT.new >> $OUT ++rm -rf $OUT.new ++ ++$DUMPE2FS $TMPFILE 2>&1 | grep '^Journal features:' >> $OUT ++ ++test -d "$JOURNAL_DUMP_DIR" -a -w "$JOURNAL_DUMP_DIR" && cp "$TMPFILE" "$JOURNAL_DUMP_DIR/$test_name.img" ++echo "logdump -c" > $TMPFILE.cmd ++$DEBUGFS_EXE -f $TMPFILE.cmd $TMPFILE 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT ++rm -rf $TMPFILE.cmd ++ ++$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 ++status=$? ++echo Exit status is $status >> $OUT.new ++sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT ++rm -f $OUT.new ++ ++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 IMAGE FSCK_OPT OUT EXP ++ ++else #if test -x $DEBUGFS_EXE; then ++ echo "$test_name: $test_description: skipped" ++fi +--- /dev/null ++++ b/tests/j_short_trans_mcsum_64bit/expect +@@ -0,0 +1,40 @@ ++Creating filesystem with 131072 4k blocks and 32768 inodes ++Superblock backups stored on blocks: ++ 32768, 98304 ++ ++Allocating group tables: done ++Writing inode tables: done ++Creating journal (4096 blocks): done ++Writing superblocks and filesystem accounting information: done ++ ++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/32768 files (0.0% non-contiguous), 6353/131072 blocks ++Exit status is 0 ++Journal features: (none) ++debugfs write journal ++Journal features: journal_64bit journal_checksum_v3 ++debugfs: logdump -c ++Journal starts at block 1, transaction 1 ++Found expected sequence 1, type 1 (descriptor block) at block 1 ++Found expected sequence 1, type 2 (commit block) at block 10 ++No magic number at block 11: end of journal. ++test_filesys: recovering journal ++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: +(0--65) +(67--69) +(71--584) +(1097--2126) +(65536--69631) +(98304--98368) ++Fix? yes ++ ++Inode bitmap differences: +(1--11) ++Fix? yes ++ ++ ++test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** ++test_filesys: 11/32768 files (0.0% non-contiguous), 6353/131072 blocks ++Exit status is 1 +--- /dev/null ++++ b/tests/j_short_trans_mcsum_64bit/name +@@ -0,0 +1 @@ ++transaction nuking the bitmaps on 64bit,metadata_csum +--- /dev/null ++++ b/tests/j_short_trans_mcsum_64bit/script +@@ -0,0 +1,65 @@ ++if test -x $DEBUGFS_EXE; then ++ ++FSCK_OPT=-fy ++OUT=$test_name.log ++if [ -f $test_dir/expect.gz ]; then ++ EXP=$test_name.tmp ++ gunzip < $test_dir/expect.gz > $EXP1 ++else ++ EXP=$test_dir/expect ++fi ++ ++cp /dev/null $OUT ++ ++$MKE2FS -F -o Linux -b 4096 -O 64bit,has_journal,metadata_csum -T ext4 $TMPFILE 131072 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT 2>&1 ++ ++$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 ++status=$? ++echo Exit status is $status >> $OUT.new ++sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT ++rm -f $OUT.new ++ ++bitmaps="$($DUMPE2FS $TMPFILE 2>&1 | grep 'bitmap at' | sed -e 's/^.*bitmap at \([0-9]*\).*$/\1/g' | tr '\n' ',')" ++ ++$DUMPE2FS $TMPFILE 2>&1 | grep '^Journal features:' >> $OUT ++ ++echo "debugfs write journal" >> $OUT ++echo "jo -c" > $TMPFILE.cmd ++echo "jw -b $bitmaps /dev/zero" >> $TMPFILE.cmd ++echo "jc" >> $TMPFILE.cmd ++$DEBUGFS_EXE -w -f $TMPFILE.cmd $TMPFILE 2>> $OUT.new > /dev/null ++sed -f $cmd_dir/filter.sed < $OUT.new >> $OUT ++rm -rf $OUT.new ++ ++$DUMPE2FS $TMPFILE 2>&1 | grep '^Journal features:' >> $OUT ++ ++test -d "$JOURNAL_DUMP_DIR" -a -w "$JOURNAL_DUMP_DIR" && cp "$TMPFILE" "$JOURNAL_DUMP_DIR/$test_name.img" ++echo "logdump -c" > $TMPFILE.cmd ++$DEBUGFS_EXE -f $TMPFILE.cmd $TMPFILE 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT ++rm -rf $TMPFILE.cmd ++ ++$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 ++status=$? ++echo Exit status is $status >> $OUT.new ++sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT ++rm -f $OUT.new ++ ++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 IMAGE FSCK_OPT OUT EXP ++ ++else #if test -x $DEBUGFS_EXE; then ++ echo "$test_name: $test_description: skipped" ++fi +--- /dev/null ++++ b/tests/j_short_trans_old_csum/expect +@@ -0,0 +1,40 @@ ++Creating filesystem with 65536 4k blocks and 16384 inodes ++Superblock backups stored on blocks: ++ 32768 ++ ++Allocating group tables: done ++Writing inode tables: done ++Creating journal (4096 blocks): done ++Writing superblocks and filesystem accounting information: done ++ ++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/16384 files (0.0% non-contiguous), 5164/65536 blocks ++Exit status is 0 ++Journal features: (none) ++debugfs write journal ++Journal features: journal_checksum ++debugfs: logdump -c ++Journal starts at block 1, transaction 1 ++Found expected sequence 1, type 1 (descriptor block) at block 1 ++Found expected sequence 1, type 2 (commit block) at block 6 ++No magic number at block 7: end of journal. ++test_filesys: recovering journal ++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: +(0--1050) +(32768--36880) ++Fix? yes ++ ++Inode bitmap differences: +(1--11) ++Fix? yes ++ ++ ++test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** ++test_filesys: 11/16384 files (0.0% non-contiguous), 5164/65536 blocks ++Exit status is 1 +--- /dev/null ++++ b/tests/j_short_trans_old_csum/name +@@ -0,0 +1 @@ ++transaction nuking the bitmaps with old journal checksum (v1) +--- /dev/null ++++ b/tests/j_short_trans_old_csum/script +@@ -0,0 +1,65 @@ ++if test -x $DEBUGFS_EXE; then ++ ++FSCK_OPT=-fy ++OUT=$test_name.log ++if [ -f $test_dir/expect.gz ]; then ++ EXP=$test_name.tmp ++ gunzip < $test_dir/expect.gz > $EXP1 ++else ++ EXP=$test_dir/expect ++fi ++ ++cp /dev/null $OUT ++ ++$MKE2FS -F -o Linux -b 4096 -O has_journal -T ext4 $TMPFILE 65536 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT 2>&1 ++ ++$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 ++status=$? ++echo Exit status is $status >> $OUT.new ++sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT ++rm -f $OUT.new ++ ++bitmaps="$($DUMPE2FS $TMPFILE 2>&1 | grep 'bitmap at' | sed -e 's/^.*bitmap at \([0-9]*\).*$/\1/g' | tr '\n' ',')" ++ ++$DUMPE2FS $TMPFILE 2>&1 | grep '^Journal features:' >> $OUT ++ ++echo "debugfs write journal" >> $OUT ++echo "jo -c" > $TMPFILE.cmd ++echo "jw -b $bitmaps /dev/zero" >> $TMPFILE.cmd ++echo "jc" >> $TMPFILE.cmd ++$DEBUGFS_EXE -w -f $TMPFILE.cmd $TMPFILE 2>> $OUT.new > /dev/null ++sed -f $cmd_dir/filter.sed < $OUT.new >> $OUT ++rm -rf $OUT.new ++ ++$DUMPE2FS $TMPFILE 2>&1 | grep '^Journal features:' >> $OUT ++ ++test -d "$JOURNAL_DUMP_DIR" -a -w "$JOURNAL_DUMP_DIR" && cp "$TMPFILE" "$JOURNAL_DUMP_DIR/$test_name.img" ++echo "logdump -c" > $TMPFILE.cmd ++$DEBUGFS_EXE -f $TMPFILE.cmd $TMPFILE 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT ++rm -rf $TMPFILE.cmd ++ ++$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 ++status=$? ++echo Exit status is $status >> $OUT.new ++sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT ++rm -f $OUT.new ++ ++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 IMAGE FSCK_OPT OUT EXP ++ ++else #if test -x $DEBUGFS_EXE; then ++ echo "$test_name: $test_description: skipped" ++fi +--- /dev/null ++++ b/tests/j_short_trans_open_recover/expect +@@ -0,0 +1,43 @@ ++Creating filesystem with 65536 4k blocks and 16384 inodes ++Superblock backups stored on blocks: ++ 32768 ++ ++Allocating group tables: done ++Writing inode tables: done ++Creating journal (4096 blocks): done ++Writing superblocks and filesystem accounting information: done ++ ++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/16384 files (0.0% non-contiguous), 5164/65536 blocks ++Exit status is 0 ++debugfs write journal ++debugfs: logdump -c ++Journal starts at block 1, transaction 1 ++Found expected sequence 1, type 1 (descriptor block) at block 1 ++Found expected sequence 1, type 2 (commit block) at block 6 ++No magic number at block 7: end of journal. ++debugfs can't recover open journal ++debugfs: jo ++debugfs: jr ++Please close the journal before recovering it. ++debugfs: jc ++test_filesys: recovering journal ++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: +(0--1050) +(32768--36880) ++Fix? yes ++ ++Inode bitmap differences: +(1--11) ++Fix? yes ++ ++ ++test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** ++test_filesys: 11/16384 files (0.0% non-contiguous), 5164/65536 blocks ++Exit status is 1 +--- /dev/null ++++ b/tests/j_short_trans_open_recover/name +@@ -0,0 +1 @@ ++ensure we can't recover the journal with journal open +--- /dev/null ++++ b/tests/j_short_trans_open_recover/script +@@ -0,0 +1,69 @@ ++if test -x $DEBUGFS_EXE; then ++ ++FSCK_OPT=-fy ++OUT=$test_name.log ++if [ -f $test_dir/expect.gz ]; then ++ EXP=$test_name.tmp ++ gunzip < $test_dir/expect.gz > $EXP1 ++else ++ EXP=$test_dir/expect ++fi ++ ++cp /dev/null $OUT ++ ++$MKE2FS -F -o Linux -b 4096 -O has_journal -T ext4 $TMPFILE 65536 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT 2>&1 ++ ++$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 ++status=$? ++echo Exit status is $status >> $OUT.new ++sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT ++rm -f $OUT.new ++ ++bitmaps="$($DUMPE2FS $TMPFILE 2>&1 | grep 'bitmap at' | sed -e 's/^.*bitmap at \([0-9]*\).*$/\1/g' | tr '\n' ',')" ++ ++echo "debugfs write journal" >> $OUT ++echo "jo" > $TMPFILE.cmd ++echo "jw -b $bitmaps /dev/zero" >> $TMPFILE.cmd ++echo "jc" >> $TMPFILE.cmd ++$DEBUGFS_EXE -w -f $TMPFILE.cmd $TMPFILE 2>> $OUT.new > /dev/null ++sed -f $cmd_dir/filter.sed < $OUT.new >> $OUT ++rm -rf $OUT.new ++ ++test -d "$JOURNAL_DUMP_DIR" -a -w "$JOURNAL_DUMP_DIR" && cp "$TMPFILE" "$JOURNAL_DUMP_DIR/$test_name.img" ++echo "logdump -c" > $TMPFILE.cmd ++$DEBUGFS_EXE -f $TMPFILE.cmd $TMPFILE 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT ++rm -rf $TMPFILE.cmd ++ ++echo "debugfs can't recover open journal" >> $OUT ++echo "jo" > $TMPFILE.cmd ++echo "jr" >> $TMPFILE.cmd ++echo "jc" >> $TMPFILE.cmd ++$DEBUGFS_EXE -w -f $TMPFILE.cmd $TMPFILE > $OUT.new 2>&1 ++sed -f $cmd_dir/filter.sed < $OUT.new >> $OUT ++rm -rf $OUT.new ++ ++$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 ++status=$? ++echo Exit status is $status >> $OUT.new ++sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT ++rm -f $OUT.new ++ ++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 IMAGE FSCK_OPT OUT EXP ++ ++else #if test -x $DEBUGFS_EXE; then ++ echo "$test_name: $test_description: skipped" ++fi +--- /dev/null ++++ b/tests/j_short_trans_recover/expect +@@ -0,0 +1,40 @@ ++Creating filesystem with 65536 4k blocks and 16384 inodes ++Superblock backups stored on blocks: ++ 32768 ++ ++Allocating group tables: done ++Writing inode tables: done ++Creating journal (4096 blocks): done ++Writing superblocks and filesystem accounting information: done ++ ++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/16384 files (0.0% non-contiguous), 5164/65536 blocks ++Exit status is 0 ++debugfs write journal ++debugfs: logdump -c ++Journal starts at block 1, transaction 1 ++Found expected sequence 1, type 1 (descriptor block) at block 1 ++Found expected sequence 1, type 2 (commit block) at block 7 ++Found expected sequence 2, type 5 (revoke table) at block 8 ++Found expected sequence 2, type 2 (commit block) at block 9 ++No magic number at block 10: end of journal. ++debugfs recover journal ++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: +(0--1050) +(32768--36880) ++Fix? yes ++ ++Inode bitmap differences: +(1--11) ++Fix? yes ++ ++ ++test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** ++test_filesys: 11/16384 files (0.0% non-contiguous), 5164/65536 blocks ++Exit status is 1 +--- /dev/null ++++ b/tests/j_short_trans_recover/name +@@ -0,0 +1 @@ ++transaction nuking the bitmaps (debugfs recovery) +--- /dev/null ++++ b/tests/j_short_trans_recover/script +@@ -0,0 +1,70 @@ ++if test -x $DEBUGFS_EXE; then ++ ++FSCK_OPT=-fy ++OUT=$test_name.log ++if [ -f $test_dir/expect.gz ]; then ++ EXP=$test_name.tmp ++ gunzip < $test_dir/expect.gz > $EXP1 ++else ++ EXP=$test_dir/expect ++fi ++ ++cp /dev/null $OUT ++ ++$MKE2FS -F -o Linux -b 4096 -O has_journal -T ext4 $TMPFILE 65536 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT 2>&1 ++ ++$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 ++status=$? ++echo Exit status is $status >> $OUT.new ++sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT ++rm -f $OUT.new ++ ++bitmaps="$($DUMPE2FS $TMPFILE 2>&1 | grep 'bitmap at' | sed -e 's/^.*bitmap at \([0-9]*\).*$/\1/g' | tr '\n' ',')" ++ ++echo "debugfs write journal" >> $OUT ++echo "jo" > $TMPFILE.cmd ++echo "jw -b 333,$bitmaps /dev/zero" >> $TMPFILE.cmd ++echo "jc" >> $TMPFILE.cmd ++echo "jo" >> $TMPFILE.cmd ++echo "jw -r 333" >> $TMPFILE.cmd ++echo "jc" >> $TMPFILE.cmd ++$DEBUGFS_EXE -w -f $TMPFILE.cmd $TMPFILE 2>> $OUT.new > /dev/null ++sed -f $cmd_dir/filter.sed < $OUT.new >> $OUT ++rm -rf $OUT.new ++ ++test -d "$JOURNAL_DUMP_DIR" -a -w "$JOURNAL_DUMP_DIR" && cp "$TMPFILE" "$JOURNAL_DUMP_DIR/$test_name.img" ++echo "logdump -c" > $TMPFILE.cmd ++$DEBUGFS_EXE -f $TMPFILE.cmd $TMPFILE 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT ++rm -rf $TMPFILE.cmd ++ ++echo "debugfs recover journal" >> $OUT ++echo "jr" > $TMPFILE.cmd ++$DEBUGFS_EXE -w -f $TMPFILE.cmd $TMPFILE 2>> $OUT.new > /dev/null ++sed -f $cmd_dir/filter.sed < $OUT.new >> $OUT ++rm -rf $OUT.new ++ ++$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 ++status=$? ++echo Exit status is $status >> $OUT.new ++sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT ++rm -f $OUT.new ++ ++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 IMAGE FSCK_OPT OUT EXP ++ ++else #if test -x $DEBUGFS_EXE; then ++ echo "$test_name: $test_description: skipped" ++fi +--- /dev/null ++++ b/tests/j_short_trans_recover_mcsum_64bit/expect +@@ -0,0 +1,42 @@ ++Creating filesystem with 131072 4k blocks and 32768 inodes ++Superblock backups stored on blocks: ++ 32768, 98304 ++ ++Allocating group tables: done ++Writing inode tables: done ++Creating journal (4096 blocks): done ++Writing superblocks and filesystem accounting information: done ++ ++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/32768 files (0.0% non-contiguous), 6353/131072 blocks ++Exit status is 0 ++Journal features: (none) ++debugfs write journal ++Journal features: journal_incompat_revoke journal_64bit journal_checksum_v3 ++debugfs: logdump -c ++Journal starts at block 1, transaction 1 ++Found expected sequence 1, type 1 (descriptor block) at block 1 ++Found expected sequence 1, type 2 (commit block) at block 11 ++Found expected sequence 2, type 5 (revoke table) at block 12 ++Found expected sequence 2, type 2 (commit block) at block 13 ++No magic number at block 14: end of journal. ++debugfs recover journal ++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: +(0--65) +(67--69) +(71--584) +(1097--2126) +(65536--69631) +(98304--98368) ++Fix? yes ++ ++Inode bitmap differences: +(1--11) ++Fix? yes ++ ++ ++test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** ++test_filesys: 11/32768 files (0.0% non-contiguous), 6353/131072 blocks ++Exit status is 1 +--- /dev/null ++++ b/tests/j_short_trans_recover_mcsum_64bit/name +@@ -0,0 +1 @@ ++uncommitted transaction nuking the bitmaps on 64bit,metadata_csum (debugfs recover) +--- /dev/null ++++ b/tests/j_short_trans_recover_mcsum_64bit/script +@@ -0,0 +1,74 @@ ++if test -x $DEBUGFS_EXE; then ++ ++FSCK_OPT=-fy ++OUT=$test_name.log ++if [ -f $test_dir/expect.gz ]; then ++ EXP=$test_name.tmp ++ gunzip < $test_dir/expect.gz > $EXP1 ++else ++ EXP=$test_dir/expect ++fi ++ ++cp /dev/null $OUT ++ ++$MKE2FS -F -o Linux -b 4096 -O 64bit,has_journal,metadata_csum -T ext4 $TMPFILE 131072 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT 2>&1 ++ ++$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 ++status=$? ++echo Exit status is $status >> $OUT.new ++sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT ++rm -f $OUT.new ++ ++bitmaps="$($DUMPE2FS $TMPFILE 2>&1 | grep 'bitmap at' | sed -e 's/^.*bitmap at \([0-9]*\).*$/\1/g' | tr '\n' ',')" ++ ++$DUMPE2FS $TMPFILE 2>&1 | grep '^Journal features:' >> $OUT ++ ++echo "debugfs write journal" >> $OUT ++echo "jo -c" > $TMPFILE.cmd ++echo "jw -b 333,$bitmaps /dev/zero" >> $TMPFILE.cmd ++echo "jc" >> $TMPFILE.cmd ++echo "jo" >> $TMPFILE.cmd ++echo "jw -r 333" >> $TMPFILE.cmd ++echo "jc" >> $TMPFILE.cmd ++$DEBUGFS_EXE -w -f $TMPFILE.cmd $TMPFILE 2>> $OUT.new > /dev/null ++sed -f $cmd_dir/filter.sed < $OUT.new >> $OUT ++rm -rf $OUT.new ++ ++$DUMPE2FS $TMPFILE 2>&1 | grep '^Journal features:' >> $OUT ++ ++test -d "$JOURNAL_DUMP_DIR" -a -w "$JOURNAL_DUMP_DIR" && cp "$TMPFILE" "$JOURNAL_DUMP_DIR/$test_name.img" ++echo "logdump -c" > $TMPFILE.cmd ++$DEBUGFS_EXE -f $TMPFILE.cmd $TMPFILE 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT ++rm -rf $TMPFILE.cmd ++ ++echo "debugfs recover journal" >> $OUT ++echo "jr" > $TMPFILE.cmd ++$DEBUGFS_EXE -w -f $TMPFILE.cmd $TMPFILE 2>> $OUT.new > /dev/null ++sed -f $cmd_dir/filter.sed < $OUT.new >> $OUT ++rm -rf $OUT.new ++ ++$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 ++status=$? ++echo Exit status is $status >> $OUT.new ++sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT ++rm -f $OUT.new ++ ++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 IMAGE FSCK_OPT OUT EXP ++ ++else #if test -x $DEBUGFS_EXE; then ++ echo "$test_name: $test_description: skipped" ++fi +--- /dev/null ++++ b/tests/j_short_uncommitted_trans/expect +@@ -0,0 +1,26 @@ ++Creating filesystem with 65536 4k blocks and 16384 inodes ++Superblock backups stored on blocks: ++ 32768 ++ ++Allocating group tables: done ++Writing inode tables: done ++Creating journal (4096 blocks): done ++Writing superblocks and filesystem accounting information: done ++ ++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/16384 files (0.0% non-contiguous), 5164/65536 blocks ++Exit status is 0 ++debugfs write journal ++debugfs: logdump -c ++Journal starts at block 0, transaction 1 ++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/16384 files (0.0% non-contiguous), 5164/65536 blocks ++Exit status is 0 +--- /dev/null ++++ b/tests/j_short_uncommitted_trans/name +@@ -0,0 +1 @@ ++uncommitted transaction nuking bitmaps +--- /dev/null ++++ b/tests/j_short_uncommitted_trans/script +@@ -0,0 +1,61 @@ ++if test -x $DEBUGFS_EXE; then ++ ++FSCK_OPT=-fy ++OUT=$test_name.log ++if [ -f $test_dir/expect.gz ]; then ++ EXP=$test_name.tmp ++ gunzip < $test_dir/expect.gz > $EXP1 ++else ++ EXP=$test_dir/expect ++fi ++ ++cp /dev/null $OUT ++ ++$MKE2FS -F -o Linux -b 4096 -O has_journal -T ext4 $TMPFILE 65536 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT 2>&1 ++ ++$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 ++status=$? ++echo Exit status is $status >> $OUT.new ++sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT ++rm -f $OUT.new ++ ++bitmaps="$($DUMPE2FS $TMPFILE 2>&1 | grep 'bitmap at' | sed -e 's/^.*bitmap at \([0-9]*\).*$/\1/g' | tr '\n' ',')" ++ ++echo "debugfs write journal" >> $OUT ++echo "jo" > $TMPFILE.cmd ++echo "jw -b $bitmaps -c /dev/zero" >> $TMPFILE.cmd ++echo "jc" >> $TMPFILE.cmd ++$DEBUGFS_EXE -w -f $TMPFILE.cmd $TMPFILE 2>> $OUT.new > /dev/null ++sed -f $cmd_dir/filter.sed < $OUT.new >> $OUT ++rm -rf $OUT.new ++ ++test -d "$JOURNAL_DUMP_DIR" -a -w "$JOURNAL_DUMP_DIR" && cp "$TMPFILE" "$JOURNAL_DUMP_DIR/$test_name.img" ++echo "logdump -c" > $TMPFILE.cmd ++$DEBUGFS_EXE -f $TMPFILE.cmd $TMPFILE 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT ++rm -rf $TMPFILE.cmd ++ ++$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 ++status=$? ++echo Exit status is $status >> $OUT.new ++sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT ++rm -f $OUT.new ++ ++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 IMAGE FSCK_OPT OUT EXP ++ ++else #if test -x $DEBUGFS_EXE; then ++ echo "$test_name: $test_description: skipped" ++fi +--- /dev/null ++++ b/tests/j_short_uncommitted_trans_mcsum_64bit/expect +@@ -0,0 +1,28 @@ ++Creating filesystem with 131072 4k blocks and 32768 inodes ++Superblock backups stored on blocks: ++ 32768, 98304 ++ ++Allocating group tables: done ++Writing inode tables: done ++Creating journal (4096 blocks): done ++Writing superblocks and filesystem accounting information: done ++ ++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/32768 files (0.0% non-contiguous), 6353/131072 blocks ++Exit status is 0 ++Journal features: (none) ++debugfs write journal ++Journal features: journal_64bit journal_checksum_v3 ++debugfs: logdump -c ++Journal starts at block 0, transaction 1 ++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/32768 files (0.0% non-contiguous), 6353/131072 blocks ++Exit status is 0 +--- /dev/null ++++ b/tests/j_short_uncommitted_trans_mcsum_64bit/name +@@ -0,0 +1 @@ ++uncommitted transaction nuking the bitmaps on 64bit,metadata_csum +--- /dev/null ++++ b/tests/j_short_uncommitted_trans_mcsum_64bit/script +@@ -0,0 +1,65 @@ ++if test -x $DEBUGFS_EXE; then ++ ++FSCK_OPT=-fy ++OUT=$test_name.log ++if [ -f $test_dir/expect.gz ]; then ++ EXP=$test_name.tmp ++ gunzip < $test_dir/expect.gz > $EXP1 ++else ++ EXP=$test_dir/expect ++fi ++ ++cp /dev/null $OUT ++ ++$MKE2FS -F -o Linux -b 4096 -O 64bit,has_journal,metadata_csum -T ext4 $TMPFILE 131072 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT 2>&1 ++ ++$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 ++status=$? ++echo Exit status is $status >> $OUT.new ++sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT ++rm -f $OUT.new ++ ++bitmaps="$($DUMPE2FS $TMPFILE 2>&1 | grep 'bitmap at' | sed -e 's/^.*bitmap at \([0-9]*\).*$/\1/g' | tr '\n' ',')" ++ ++$DUMPE2FS $TMPFILE 2>&1 | grep '^Journal features:' >> $OUT ++ ++echo "debugfs write journal" >> $OUT ++echo "jo -c" > $TMPFILE.cmd ++echo "jw -b $bitmaps /dev/zero -c" >> $TMPFILE.cmd ++echo "jc" >> $TMPFILE.cmd ++$DEBUGFS_EXE -w -f $TMPFILE.cmd $TMPFILE 2>> $OUT.new > /dev/null ++sed -f $cmd_dir/filter.sed < $OUT.new >> $OUT ++rm -rf $OUT.new ++ ++$DUMPE2FS $TMPFILE 2>&1 | grep '^Journal features:' >> $OUT ++ ++test -d "$JOURNAL_DUMP_DIR" -a -w "$JOURNAL_DUMP_DIR" && cp "$TMPFILE" "$JOURNAL_DUMP_DIR/$test_name.img" ++echo "logdump -c" > $TMPFILE.cmd ++$DEBUGFS_EXE -f $TMPFILE.cmd $TMPFILE 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT ++rm -rf $TMPFILE.cmd ++ ++$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 ++status=$? ++echo Exit status is $status >> $OUT.new ++sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT ++rm -f $OUT.new ++ ++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 IMAGE FSCK_OPT OUT EXP ++ ++else #if test -x $DEBUGFS_EXE; then ++ echo "$test_name: $test_description: skipped" ++fi +--- a/tests/m_64bit_flexbg/expect.1 ++++ b/tests/m_64bit_flexbg/expect.1 +@@ -48,7 +48,8 @@ + Group 0: (Blocks 1-1023) + Primary superblock at 1, Group descriptors at 2-2 + Reserved GDT blocks at 3-9 +- Block bitmap at 10 (+9), Inode bitmap at 26 (+25) ++ Block bitmap at 10 (+9) ++ Inode bitmap at 26 (+25) + Inode table at 42-57 (+41) + 982 free blocks, 117 free inodes, 2 directories + Free blocks: 24-25, 28-41, 58-1023 +--- a/tests/Makefile.in ++++ b/tests/Makefile.in +@@ -16,8 +16,8 @@ + test_one: $(srcdir)/test_one.in Makefile mke2fs.conf + @echo "Creating test_one script..." + @echo "#!/bin/sh" > test_one +-@HTREE_CMT@ @echo "HTREE=y" >> test_one +-@QUOTA_CMT@ @echo "QUOTA=y" >> test_one ++ @echo "HTREE=y" >> test_one ++ @echo "QUOTA=y" >> test_one + @echo "SRCDIR=@srcdir@" >> test_one + @echo "DIFF_OPTS=@UNI_DIFF_OPTS@" >> test_one + @cat $(srcdir)/test_one.in >> test_one +--- a/tests/m_bigjournal/expect.1 ++++ b/tests/m_bigjournal/expect.1 +@@ -52,8 +52,8 @@ + Reserved GDT blocks at 2-672 + Block bitmap at 673 (+673), Inode bitmap at 757 (+757) + Inode table at 841-841 (+841) +- 31836 free blocks, 5 free inodes, 2 directories, 5 unused inodes +- Free blocks: 932-32767 ++ 31837 free blocks, 5 free inodes, 2 directories, 5 unused inodes ++ Free blocks: 931-32767 + Free inodes: 12-16 + Group 1: (Blocks 32768-65535) [INODE_UNINIT, BLOCK_UNINIT] + Backup superblock at 32768, Group descriptors at 32769-32769 +@@ -297,11 +297,11 @@ + 32768 free blocks, 16 free inodes, 0 directories, 16 unused inodes + Free blocks: 1245184-1277951 + Free inodes: 609-624 +-Group 39: (Blocks 1277952-1310719) [INODE_UNINIT, BLOCK_UNINIT] ++Group 39: (Blocks 1277952-1310719) [INODE_UNINIT] + Block bitmap at 712 (bg #0 + 712), Inode bitmap at 796 (bg #0 + 796) + Inode table at 880-880 (bg #0 + 880) +- 32768 free blocks, 16 free inodes, 0 directories, 16 unused inodes +- Free blocks: 1277952-1310719 ++ 32767 free blocks, 16 free inodes, 0 directories, 16 unused inodes ++ Free blocks: 1277952-1310718 + Free inodes: 625-640 + Group 40: (Blocks 1310720-1343487) [INODE_UNINIT] + Block bitmap at 713 (bg #0 + 713), Inode bitmap at 797 (bg #0 + 797) +--- a/tests/m_bigjournal/script ++++ b/tests/m_bigjournal/script +@@ -1,8 +1,12 @@ + DESCRIPTION="journal over 4GB in size" + FS_SIZE=11000000 ++DUMPE2FS_IGNORE_80COL=1 ++export DUMPE2FS_IGNORE_80COL + MKE2FS_OPTS="-t ext4 -G 512 -N 1280 -J size=5000 -q -E lazy_journal_init,lazy_itable_init,nodiscard" + if [ $(uname -s) = "Darwin" ]; then ++ # creates a 44GB filesystem + echo "$test_name: $DESCRIPTION: skipped for HFS+ (no sparse files)" + return 0 + fi + . $cmd_dir/run_mke2fs ++unset DUMPE2FS_IGNORE_80COL +--- a/tests/m_dasd_bs/expect.1 ++++ b/tests/m_dasd_bs/expect.1 +@@ -48,7 +48,8 @@ + Group 0: (Blocks 0-16383) + Primary superblock at 0, Group descriptors at 1-1 + Reserved GDT blocks at 2-32 +- Block bitmap at 33 (+33), Inode bitmap at 34 (+34) ++ Block bitmap at 33 (+33) ++ Inode bitmap at 34 (+34) + Inode table at 35-546 (+35) + 15827 free blocks, 8181 free inodes, 2 directories + Free blocks: 557-16383 +@@ -56,7 +57,8 @@ + Group 1: (Blocks 16384-32767) + Backup superblock at 16384, Group descriptors at 16385-16385 + Reserved GDT blocks at 16386-16416 +- Block bitmap at 16417 (+33), Inode bitmap at 16418 (+34) ++ Block bitmap at 16417 (+33) ++ Inode bitmap at 16418 (+34) + Inode table at 16419-16930 (+35) + 15837 free blocks, 8192 free inodes, 0 directories + Free blocks: 16931-32767 +--- a/tests/m_desc_size_128/script ++++ b/tests/m_desc_size_128/script +@@ -1,4 +1,7 @@ + DESCRIPTION="enable 128-byte group descriptor on mkfs" + FS_SIZE=131072 ++DUMPE2FS_IGNORE_80COL=1 ++export DUMPE2FS_IGNORE_80COL + MKE2FS_OPTS="-b 1024 -O 64bit,extents -g 1024 -N 8192 -E desc_size=128" + . $cmd_dir/run_mke2fs ++unset DUMPE2FS_IGNORE_80COL +--- /dev/null ++++ b/tests/m_devdir/script +@@ -0,0 +1,33 @@ ++if test -x $DEBUGFS_EXE; then ++ ++test_description="create fs image from /dev" ++MKFS_DIR=/dev ++OUT=$test_name.log ++ ++$MKE2FS -q -F -o Linux -T ext4 -O metadata_csum,64bit -E lazy_itable_init=1 -b 1024 -d $MKFS_DIR $TMPFILE 16384 > $OUT 2>&1 ++mkfs_status=$? ++ ++$DUMPE2FS $TMPFILE >> $OUT 2>&1 ++$DEBUGFS -R 'ls /' $TMPFILE >> $OUT 2>&1 ++ ++$FSCK -f -n $TMPFILE >> $OUT 2>&1 ++fsck_status=$? ++ ++sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" < $OUT > $OUT.tmp ++mv $OUT.tmp $OUT ++ ++if [ $mkfs_status -ne 0 ]; then ++ echo "$test_name: $test_description: skipped" ++elif [ $mkfs_status -eq 0 ] && [ $fsck_status -eq 0 ]; then ++ echo "$test_name: $test_description: ok" ++ touch $test_name.ok ++else ++ echo "$test_name: $test_description: failed" ++fi ++ ++rm -rf $TMPFILE.cmd $OUT.sed ++unset MKFS_DIR OUT EXP ++ ++else #if test -x $DEBUGFS_EXE; then ++ echo "$test_name: $test_description: skipped" ++fi +--- a/tests/m_extent_journal/script ++++ b/tests/m_extent_journal/script +@@ -1,4 +1,7 @@ + DESCRIPTION="extent-mapped journal" + FS_SIZE=65536 ++DUMPE2FS_IGNORE_80COL=1 ++export DUMPE2FS_IGNORE_80COL + MKE2FS_OPTS="-O extents -j" + . $cmd_dir/run_mke2fs ++unset DUMPE2FS_IGNORE_80COL +--- /dev/null ++++ b/tests/m_hugefile/expect +@@ -0,0 +1,36 @@ ++mke2fs -F -T hugefile test.img 4T ++Creating filesystem with 1073741824 4k blocks and 1048576 inodes ++Superblock backups stored on blocks: ++ ++Allocating group tables: done ++Writing inode tables: done ++Creating 1 huge file(s) : done ++Writing superblocks and filesystem accounting information: done ++ ++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 ++ ++Exit status is 0 ++debugfs -R "extents /store/big-data" test.img | head ++Level Entries Logical Physical Length Flags ++ 0/ 2 1/ 1 0 - 1073610751 131070 1073610752 ++ 1/ 2 1/ 97 0 - 11108351 131071 11108352 ++ 2/ 2 1/339 0 - 32767 131072 - 163839 32768 ++ 2/ 2 2/339 32768 - 65535 163840 - 196607 32768 ++ 2/ 2 3/339 65536 - 98303 196608 - 229375 32768 ++ 2/ 2 4/339 98304 - 131071 229376 - 262143 32768 ++ 2/ 2 5/339 131072 - 163839 262144 - 294911 32768 ++ 2/ 2 6/339 163840 - 196607 294912 - 327679 32768 ++ 2/ 2 7/339 196608 - 229375 327680 - 360447 32768 ++ 2/ 2 8/339 229376 - 262143 360448 - 393215 32768 ++ 2/ 2 9/339 262144 - 294911 393216 - 425983 32768 ++ 2/ 2 10/339 294912 - 327679 425984 - 458751 32768 ++ 2/ 2 11/339 327680 - 360447 458752 - 491519 32768 ++ 2/ 2 12/339 360448 - 393215 491520 - 524287 32768 ++ 2/ 2 13/339 393216 - 425983 524288 - 557055 32768 ++ 2/ 2 14/339 425984 - 458751 557056 - 589823 32768 ++ 2/ 2 15/339 458752 - 491519 589824 - 622591 32768 ++ 2/ 2 16/339 491520 - 524287 622592 - 655359 32768 +--- /dev/null ++++ b/tests/m_hugefile/name +@@ -0,0 +1 @@ ++create a hugefile fs with a single huge file +--- /dev/null ++++ b/tests/m_hugefile/script +@@ -0,0 +1,67 @@ ++FSCK_OPT=-fn ++OUT=$test_name.log ++EXP=$test_dir/expect ++CONF=$TMPFILE.conf ++ ++if [ $(uname -s) = "Darwin" ]; then ++ # creates a 4TB filesystem ++ echo "$test_name: $DESCRIPTION: skipped for HFS+ (no sparse files)" ++ return 0 ++fi ++ ++#gzip -d < $EXP.gz > $EXP ++ ++cat > $CONF << ENDL ++[fs_types] ++ hugefile = { ++ features = extent,huge_file,flex_bg,uninit_bg,dir_nlink,extra_isize,^resize_inode,sparse_super2 ++ hash_alg = half_md4 ++ num_backup_sb = 0 ++ packed_meta_blocks = 1 ++ make_hugefiles = 1 ++ inode_ratio = 4194304 ++ hugefiles_dir = /store ++ hugefiles_name = big-data ++ hugefiles_digits = 0 ++ hugefiles_size = 0 ++ hugefiles_align = 256M ++ num_hugefiles = 1 ++ zero_hugefiles = false ++ flex_bg_size = 262144 ++ } ++ENDL ++ ++echo "mke2fs -F -T hugefile test.img 4T" > $OUT ++MKE2FS_CONFIG=$CONF $MKE2FS -F -T hugefile $TMPFILE 4T >> $OUT 2>&1 ++rm -rf $CONF ++ ++# check the file system if we get this far, we succeeded... ++$FSCK $FSCK_OPT -N test_filesys $TMPFILE >> $OUT 2>&1 ++status=$? ++echo Exit status is $status >> $OUT ++ ++echo 'debugfs -R "extents /store/big-data" test.img | head' >> $OUT ++ ++$DEBUGFS -R "extents /store/big-data" $TMPFILE 2>&1 | head -n 20 >> $OUT 2>&1 ++ ++rm $TMPFILE ++ ++# ++# Do the verification ++# ++ ++sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" -e 's/test_filesys:.*//g' < $OUT > $OUT.new ++mv $OUT.new $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 IMAGE FSCK_OPT OUT EXP CONF +--- a/tests/m_hugefile_slack/expect ++++ b/tests/m_hugefile_slack/expect +@@ -1,4 +1,4 @@ +-tune2fs test ++mke2fs -F -T ext4h -I 128 test.img 786432 + Creating filesystem with 786432 1k blocks and 98304 inodes + Superblock backups stored on blocks: + 8193, 24577, 40961, 57345, 73729, 204801, 221185, 401409, 663553 +--- a/tests/m_hugefile_slack/script ++++ b/tests/m_hugefile_slack/script +@@ -1,5 +1,3 @@ +-if test -x $RESIZE2FS_EXE -a -x $DEBUGFS_EXE; then +- + FSCK_OPT=-fn + OUT=$test_name.log + EXP=$test_dir/expect +@@ -23,8 +21,7 @@ + } + ENDL + +-echo "tune2fs test" > $OUT +- ++echo "mke2fs -F -T ext4h -I 128 test.img 786432" > $OUT + MKE2FS_CONFIG=$CONF $MKE2FS -F -T ext4h -I 128 $TMPFILE 786432 >> $OUT 2>&1 + rm -rf $CONF + +@@ -54,8 +51,3 @@ + fi + + unset IMAGE FSCK_OPT OUT EXP CONF +- +-else #if test -x $RESIZE2FS_EXE -a -x $DEBUGFS_EXE; then +- echo "$test_name: $test_description: skipped" +-fi +- +--- a/tests/m_large_file/expect.1 ++++ b/tests/m_large_file/expect.1 +@@ -48,7 +48,8 @@ + Group 0: (Blocks 0-16383) + Primary superblock at 0, Group descriptors at 1-1 + Reserved GDT blocks at 2-4 +- Block bitmap at 5 (+5), Inode bitmap at 6 (+6) ++ Block bitmap at 5 (+5) ++ Inode bitmap at 6 (+6) + Inode table at 7-10 (+7) + 16367 free blocks, 53 free inodes, 2 directories + Free blocks: 17-16383 +--- /dev/null ++++ b/tests/m_mcsum_extjournal/expect +@@ -0,0 +1,5 @@ ++Creating filesystem with 4096 1k blocks and 0 inodes ++Superblock backups stored on blocks: ++ ++Zeroing journal device:  ++Filesystem features: journal_dev metadata_csum +--- /dev/null ++++ b/tests/m_mcsum_extjournal/name +@@ -0,0 +1 @@ ++create external journal with sb checksum (metadata_csum) +--- /dev/null ++++ b/tests/m_mcsum_extjournal/script +@@ -0,0 +1,29 @@ ++FSCK_OPT=-fy ++OUT=$test_name.log ++if [ -f $test_dir/expect.gz ]; then ++ EXP=$test_name.tmp ++ gunzip < $test_dir/expect.gz > $EXP1 ++else ++ EXP=$test_dir/expect ++fi ++ ++cp /dev/null $OUT ++ ++$MKE2FS -F -o Linux -b 1024 -O journal_dev,metadata_csum -T ext4 $TMPFILE 4096 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT 2>&1 ++$DUMPE2FS -h $TMPFILE 2>&1 | grep 'Filesystem features:' >> $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 IMAGE FSCK_OPT OUT EXP +--- a/tests/m_meta_bg/script ++++ b/tests/m_meta_bg/script +@@ -1,4 +1,7 @@ + DESCRIPTION="meta blockgroup feature" + FS_SIZE=131072 ++DUMPE2FS_IGNORE_80COL=1 ++export DUMPE2FS_IGNORE_80COL + MKE2FS_OPTS="-O meta_bg,sparse_super,^resize_inode -g 1024" + . $cmd_dir/run_mke2fs ++unset DUMPE2FS_IGNORE_80COL +--- /dev/null ++++ b/tests/m_minrootdir/expect +@@ -0,0 +1,216 @@ ++create fs ++Filesystem volume name: ++Last mounted on: ++Filesystem magic number: 0xEF53 ++Filesystem revision #: 1 (dynamic) ++Filesystem features: ext_attr dir_index filetype extent 64bit flex_bg sparse_super huge_file dir_nlink extra_isize metadata_csum ++Default mount options: (none) ++Filesystem state: clean ++Errors behavior: Continue ++Filesystem OS type: Linux ++Inode count: 1024 ++Block count: 16384 ++Reserved block count: 819 ++Free blocks: 16065 ++Free inodes: 1006 ++First block: 1 ++Block size: 1024 ++Fragment size: 1024 ++Group descriptor size: 64 ++Blocks per group: 8192 ++Fragments per group: 8192 ++Inodes per group: 512 ++Inode blocks per group: 128 ++Flex block group size: 16 ++Mount count: 0 ++Check interval: 15552000 (6 months) ++Reserved blocks uid: 0 ++Reserved blocks gid: 0 ++First inode: 11 ++Inode size: 256 ++Required extra isize: 28 ++Desired extra isize: 28 ++Default directory hash: half_md4 ++Checksum type: crc32c ++ ++ ++Group 0: (Blocks 1-8192) ++ Primary superblock at 1, Group descriptors at 2-2 ++ Block bitmap at 3 (+2) ++ Inode bitmap at 5 (+4) ++ Inode table at 7-134 (+6) ++ 7876 free blocks, 494 free inodes, 4 directories, 494 unused inodes ++ Free blocks: 317-8192 ++ Free inodes: 19-512 ++Group 1: (Blocks 8193-16383) [INODE_UNINIT] ++ Backup superblock at 8193, Group descriptors at 8194-8194 ++ Block bitmap at 4 (bg #0 + 3) ++ Inode bitmap at 6 (bg #0 + 5) ++ Inode table at 135-262 (bg #0 + 134) ++ 8189 free blocks, 512 free inodes, 0 directories, 512 unused inodes ++ Free blocks: 8195-16383 ++ Free inodes: 513-1024 ++debugfs: stat /emptyfile ++Inode: III Type: regular ++Size: 0 ++Fragment: Address: 0 Number: 0 Size: 0 ++debugfs: stat /bigfile ++Inode: III Type: regular ++Size: 32768 ++Fragment: Address: 0 Number: 0 Size: 0 ++debugfs: stat /sparsefile ++Inode: III Type: regular ++Size: 1073741825 ++Fragment: Address: 0 Number: 0 Size: 0 ++debugfs: stat /bigzerofile ++Inode: III Type: regular ++Size: 1073741825 ++Fragment: Address: 0 Number: 0 Size: 0 ++debugfs: stat /fifo ++debugfs: stat /emptydir ++Inode: III Type: directory ++Size: 1024 ++Fragment: Address: 0 Number: 0 Size: 0 ++debugfs: stat /dir ++Inode: III Type: directory ++Size: 1024 ++Fragment: Address: 0 Number: 0 Size: 0 ++debugfs: stat /dir/file ++Inode: III Type: regular ++Size: 8 ++Fragment: Address: 0 Number: 0 Size: 0 ++debugfs: ex /emptyfile ++Level Entries Logical Physical Length Flags ++debugfs: ex /bigfile ++Level Entries Logical Physical Length Flags ++X 0/0 1/1 0-31 AAA-BBB 32 ++debugfs: ex /sparsefile ++Level Entries Logical Physical Length Flags ++Y 0/1 1/1 1-1048576 AAA 1048576 ++X 1/1 1/5 1-1 AAA-BBB 1 ++X 1/1 2/5 512-512 AAA-BBB 1 ++X 1/1 3/5 1024-1024 AAA-BBB 1 ++X 1/1 4/5 524288-524288 AAA-BBB 1 ++X 1/1 5/5 1048576-1048576 AAA-BBB 1 ++debugfs: ex /bigzerofile ++Level Entries Logical Physical Length Flags ++debugfs: ex /dir ++Level Entries Logical Physical Length Flags ++X 0/0 1/1 0-0 AAA-BBB 1 ++debugfs: ex /dir/file ++Level Entries Logical Physical Length Flags ++X 0/0 1/1 0-0 AAA-BBB 1 ++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.img: 18/1024 files (0.0% non-contiguous), 319/16384 blocks ++minify fs ++Setting reserved blocks percentage to 0% (0 blocks) ++Resizing the filesystem on test.img to 338 (1k) blocks. ++The filesystem on test.img is now 338 (1k) blocks long. ++ ++Filesystem volume name: ++Last mounted on: ++Filesystem magic number: 0xEF53 ++Filesystem revision #: 1 (dynamic) ++Filesystem features: ext_attr dir_index filetype extent 64bit flex_bg sparse_super huge_file dir_nlink extra_isize metadata_csum ++Default mount options: (none) ++Filesystem state: clean ++Errors behavior: Continue ++Filesystem OS type: Linux ++Inode count: 512 ++Block count: 338 ++Reserved block count: 0 ++Free blocks: 151 ++Free inodes: 494 ++First block: 1 ++Block size: 1024 ++Fragment size: 1024 ++Group descriptor size: 64 ++Blocks per group: 8192 ++Fragments per group: 8192 ++Inodes per group: 512 ++Inode blocks per group: 128 ++Flex block group size: 16 ++Mount count: 0 ++Check interval: 15552000 (6 months) ++Reserved blocks uid: 0 ++Reserved blocks gid: 0 ++First inode: 11 ++Inode size: 256 ++Required extra isize: 28 ++Desired extra isize: 28 ++Default directory hash: half_md4 ++Checksum type: crc32c ++ ++ ++Group 0: (Blocks 1-337) ++ Primary superblock at 1, Group descriptors at 2-2 ++ Block bitmap at 3 (+2) ++ Inode bitmap at 5 (+4) ++ Inode table at 7-134 (+6) ++ 151 free blocks, 494 free inodes, 4 directories, 494 unused inodes ++ Free blocks: 4, 6, 135-262, 317-337 ++ Free inodes: 19-512 ++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.img: 18/512 files (0.0% non-contiguous), 187/338 blocks ++minify fs (2) ++Setting reserved blocks percentage to 0% (0 blocks) ++Resizing the filesystem on test.img to 188 (1k) blocks. ++The filesystem on test.img is now 188 (1k) blocks long. ++ ++Filesystem volume name: ++Last mounted on: ++Filesystem magic number: 0xEF53 ++Filesystem revision #: 1 (dynamic) ++Filesystem features: ext_attr dir_index filetype extent 64bit flex_bg sparse_super huge_file dir_nlink extra_isize metadata_csum ++Default mount options: (none) ++Filesystem state: clean ++Errors behavior: Continue ++Filesystem OS type: Linux ++Inode count: 512 ++Block count: 188 ++Reserved block count: 0 ++Free blocks: 1 ++Free inodes: 494 ++First block: 1 ++Block size: 1024 ++Fragment size: 1024 ++Group descriptor size: 64 ++Blocks per group: 8192 ++Fragments per group: 8192 ++Inodes per group: 512 ++Inode blocks per group: 128 ++Flex block group size: 16 ++Mount count: 0 ++Check interval: 15552000 (6 months) ++Reserved blocks uid: 0 ++Reserved blocks gid: 0 ++First inode: 11 ++Inode size: 256 ++Required extra isize: 28 ++Desired extra isize: 28 ++Default directory hash: half_md4 ++Checksum type: crc32c ++ ++ ++Group 0: (Blocks 1-187) ++ Primary superblock at 1, Group descriptors at 2-2 ++ Block bitmap at 3 (+2) ++ Inode bitmap at 5 (+4) ++ Inode table at 7-134 (+6) ++ 1 free blocks, 494 free inodes, 4 directories, 494 unused inodes ++ Free blocks: 187 ++ Free inodes: 19-512 ++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.img: 18/512 files (5.6% non-contiguous), 187/188 blocks +--- /dev/null ++++ b/tests/m_minrootdir/output.sed +@@ -0,0 +1,5 @@ ++s/^[[:space:]]*\([0-9]*\)\/[[:space:]]*\([0-9]*\)[[:space:]]*\([0-9]*\)\/[[:space:]]*\([0-9]*\)[[:space:]]*\([0-9]*\)[[:space:]]*-[[:space:]]*\([0-9]*\)[[:space:]]*[0-9]*[[:space:]]*-[[:space:]]*[0-9]*[[:space:]]*\([0-9]*\)/X \1\/\2 \3\/\4 \5-\6 AAA-BBB \7/g ++s/^[[:space:]]*\([0-9]*\)\/[[:space:]]*\([0-9]*\)[[:space:]]*\([0-9]*\)\/[[:space:]]*\([0-9]*\)[[:space:]]*\([0-9]*\)[[:space:]]*-[[:space:]]*\([0-9]*\)[[:space:]]*[0-9]*[[:space:]]*\([0-9]*\)/Y \1\/\2 \3\/\4 \5-\6 AAA \7/g ++s/Mode:.*$//g ++s/User:.*Size:/Size:/g ++s/^Inode: [0-9]*/Inode: III/g +--- /dev/null ++++ b/tests/m_minrootdir/script +@@ -0,0 +1,81 @@ ++if test -x $DEBUGFS_EXE -a -x $RESIZE2FS_EXE; then ++ ++test_description="create fs image from dir, then minimize it" ++MKFS_DIR=$TMPFILE.dir ++OUT=$test_name.log ++EXP=$test_dir/expect ++ ++rm -rf $MKFS_DIR ++mkdir -p $MKFS_DIR ++mkdir $MKFS_DIR/dir ++mkdir $MKFS_DIR/emptydir ++dd if=/dev/zero of=$MKFS_DIR/bigzerofile bs=1 count=1 seek=1073741824 2> /dev/null ++echo "M" | dd of=$MKFS_DIR/sparsefile bs=1 count=1 seek=1024 2> /dev/null ++echo "M" | dd of=$MKFS_DIR/sparsefile bs=1 count=1 seek=524288 conv=notrunc 2> /dev/null ++echo "M" | dd of=$MKFS_DIR/sparsefile bs=1 count=1 seek=1048576 conv=notrunc 2> /dev/null ++echo "M" | dd of=$MKFS_DIR/sparsefile bs=1 count=1 seek=536870912 conv=notrunc 2> /dev/null ++echo "M" | dd of=$MKFS_DIR/sparsefile bs=1 count=1 seek=1073741824 conv=notrunc 2> /dev/null ++dd if=/dev/zero bs=1024 count=32 2> /dev/null | tr '\0' 'a' > $MKFS_DIR/bigfile ++touch $MKFS_DIR/emptyfile ++echo "Test me" > $MKFS_DIR/dir/file ++ ++echo "create fs" > $OUT ++$MKE2FS -q -F -o Linux -T ext4 -O ^has_journal,metadata_csum,64bit,^resize_inode -E lazy_itable_init=1 -b 1024 -d $MKFS_DIR $TMPFILE 16384 >> $OUT 2>&1 ++ ++$DUMPE2FS $TMPFILE >> $OUT 2>&1 ++cat > $TMPFILE.cmd << ENDL ++stat /emptyfile ++stat /bigfile ++stat /sparsefile ++stat /bigzerofile ++stat /fifo ++stat /emptydir ++stat /dir ++stat /dir/file ++ENDL ++$DEBUGFS -f $TMPFILE.cmd $TMPFILE 2>&1 | egrep "(stat|Size:|Type:)" | sed -f $test_dir/output.sed >> $OUT ++ ++cat > $TMPFILE.cmd << ENDL ++ex /emptyfile ++ex /bigfile ++ex /sparsefile ++ex /bigzerofile ++ex /dir ++ex /dir/file ++ENDL ++$DEBUGFS -f $TMPFILE.cmd $TMPFILE 2>&1 | sed -f $test_dir/output.sed >> $OUT ++$FSCK -f -n $TMPFILE >> $OUT 2>&1 ++ ++echo "minify fs" >> $OUT ++$TUNE2FS -m 0 $TMPFILE >> $OUT 2>&1 ++$RESIZE2FS -M $TMPFILE >> $OUT 2>&1 ++$DUMPE2FS $TMPFILE >> $OUT 2>&1 ++$FSCK -f -n $TMPFILE >> $OUT 2>&1 ++ ++echo "minify fs (2)" >> $OUT ++$TUNE2FS -m 0 $TMPFILE >> $OUT 2>&1 ++$RESIZE2FS -M $TMPFILE >> $OUT 2>&1 ++$DUMPE2FS $TMPFILE >> $OUT 2>&1 ++$FSCK -f -n $TMPFILE >> $OUT 2>&1 ++ ++sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" < $OUT > $OUT.tmp ++mv $OUT.tmp $OUT ++ ++# 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 ++ ++rm -rf $TMPFILE.cmd $MKFS_DIR $OUT.sed ++unset MKFS_DIR OUT EXP ++ ++else #if test -x $DEBUGFS_EXE -a -x RESIZE2FS_EXE; then ++ echo "$test_name: $test_description: skipped" ++fi +--- a/tests/m_mmp/expect.1 ++++ b/tests/m_mmp/expect.1 +@@ -51,7 +51,8 @@ + Group 0: (Blocks 0-32767) + Primary superblock at 0, Group descriptors at 1-1 + Reserved GDT blocks at 2-16 +- Block bitmap at 17 (+17), Inode bitmap at 18 (+18) ++ Block bitmap at 17 (+17) ++ Inode bitmap at 18 (+18) + Inode table at 19-1042 (+19) + 31718 free blocks, 32757 free inodes, 2 directories + Free blocks: 1050-32767 +@@ -59,7 +60,8 @@ + Group 1: (Blocks 32768-65535) + Backup superblock at 32768, Group descriptors at 32769-32769 + Reserved GDT blocks at 32770-32784 +- Block bitmap at 32785 (+17), Inode bitmap at 32786 (+18) ++ Block bitmap at 32785 (+17) ++ Inode bitmap at 32786 (+18) + Inode table at 32787-33810 (+19) + 31725 free blocks, 32768 free inodes, 0 directories + Free blocks: 33811-65535 +--- /dev/null ++++ b/tests/m_mmp_bad_csum/expect +@@ -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 +--- /dev/null ++++ b/tests/m_mmp_bad_csum/name +@@ -0,0 +1 @@ ++mmp with bad csum (metadata_csum) +--- /dev/null ++++ b/tests/m_mmp_bad_csum/script +@@ -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_name.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 +--- /dev/null ++++ b/tests/m_mmp_bad_magic/expect +@@ -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 +--- /dev/null ++++ b/tests/m_mmp_bad_magic/.log +@@ -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 +--- /dev/null ++++ b/tests/m_mmp_bad_magic/name +@@ -0,0 +1 @@ ++mmp with bad magic (metadata_csum) +--- /dev/null ++++ b/tests/m_mmp_bad_magic/script +@@ -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_name.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 +--- a/tests/m_no_opt/script ++++ b/tests/m_no_opt/script +@@ -1,4 +1,7 @@ + DESCRIPTION="no filesystem extensions" + FS_SIZE=65536 ++DUMPE2FS_IGNORE_80COL=1 ++export DUMPE2FS_IGNORE_80COL + MKE2FS_OPTS="-O ^sparse_super,^filetype,^resize_inode,^dir_index,^ext_attr" + . $cmd_dir/run_mke2fs ++unset DUMPE2FS_IGNORE_80COL +--- a/tests/m_quota/script ++++ b/tests/m_quota/script +@@ -5,4 +5,7 @@ + echo "$test_name: $DESCRIPTION: skipped" + return 0 + fi ++DUMPE2FS_IGNORE_80COL=1 ++export DUMPE2FS_IGNORE_80COL + . $cmd_dir/run_mke2fs ++unset DUMPE2FS_IGNORE_80COL +--- a/tests/m_raid_opt/script ++++ b/tests/m_raid_opt/script +@@ -1,4 +1,7 @@ + DESCRIPTION="raid options" + FS_SIZE=131072 + MKE2FS_OPTS="-E stride=13 -O sparse_super -g 1024" ++DUMPE2FS_IGNORE_80COL=1 ++export DUMPE2FS_IGNORE_80COL + . $cmd_dir/run_mke2fs ++unset DUMPE2FS_IGNORE_80COL +--- /dev/null ++++ b/tests/m_rootdir/expect +@@ -0,0 +1,117 @@ ++Filesystem volume name: ++Last mounted on: ++Filesystem magic number: 0xEF53 ++Filesystem revision #: 1 (dynamic) ++Filesystem features: has_journal ext_attr resize_inode dir_index filetype extent 64bit flex_bg sparse_super huge_file dir_nlink extra_isize metadata_csum ++Default mount options: (none) ++Filesystem state: clean ++Errors behavior: Continue ++Filesystem OS type: Linux ++Inode count: 1024 ++Block count: 16384 ++Reserved block count: 819 ++Free blocks: 14786 ++Free inodes: 1005 ++First block: 1 ++Block size: 1024 ++Fragment size: 1024 ++Group descriptor size: 64 ++Reserved GDT blocks: 127 ++Blocks per group: 8192 ++Fragments per group: 8192 ++Inodes per group: 512 ++Inode blocks per group: 128 ++Flex block group size: 16 ++Mount count: 0 ++Check interval: 15552000 (6 months) ++Reserved blocks uid: 0 ++Reserved blocks gid: 0 ++First inode: 11 ++Inode size: 256 ++Required extra isize: 28 ++Desired extra isize: 28 ++Journal inode: 8 ++Default directory hash: half_md4 ++Journal backup: inode blocks ++Checksum type: crc32c ++Journal features: (none) ++Journal size: 1024k ++Journal length: 1024 ++Journal sequence: 0x00000001 ++Journal start: 0 ++ ++ ++Group 0: (Blocks 1-8192) ++ Primary superblock at 1, Group descriptors at 2-2 ++ Reserved GDT blocks at 3-129 ++ Block bitmap at 130 (+129) ++ Inode bitmap at 132 (+131) ++ Inode table at 134-261 (+133) ++ 7748 free blocks, 493 free inodes, 4 directories, 493 unused inodes ++ Free blocks: 445-8192 ++ Free inodes: 20-512 ++Group 1: (Blocks 8193-16383) [INODE_UNINIT] ++ Backup superblock at 8193, Group descriptors at 8194-8194 ++ Reserved GDT blocks at 8195-8321 ++ Block bitmap at 131 (bg #0 + 130) ++ Inode bitmap at 133 (bg #0 + 132) ++ Inode table at 262-389 (bg #0 + 261) ++ 7038 free blocks, 512 free inodes, 0 directories, 512 unused inodes ++ Free blocks: 9346-16383 ++ Free inodes: 513-1024 ++debugfs: stat /emptyfile ++Inode: III Type: regular ++Size: 0 ++Fragment: Address: 0 Number: 0 Size: 0 ++debugfs: stat /bigfile ++Inode: III Type: regular ++Size: 32768 ++Fragment: Address: 0 Number: 0 Size: 0 ++debugfs: stat /sparsefile ++Inode: III Type: regular ++Size: 1073741825 ++Fragment: Address: 0 Number: 0 Size: 0 ++debugfs: stat /bigzerofile ++Inode: III Type: regular ++Size: 1073741825 ++Fragment: Address: 0 Number: 0 Size: 0 ++debugfs: stat /fifo ++debugfs: stat /emptydir ++Inode: III Type: directory ++Size: 1024 ++Fragment: Address: 0 Number: 0 Size: 0 ++debugfs: stat /dir ++Inode: III Type: directory ++Size: 1024 ++Fragment: Address: 0 Number: 0 Size: 0 ++debugfs: stat /dir/file ++Inode: III Type: regular ++Size: 8 ++Fragment: Address: 0 Number: 0 Size: 0 ++debugfs: ex /emptyfile ++Level Entries Logical Physical Length Flags ++debugfs: ex /bigfile ++Level Entries Logical Physical Length Flags ++X 0/0 1/1 0-31 AAA-BBB 32 ++debugfs: ex /sparsefile ++Level Entries Logical Physical Length Flags ++Y 0/1 1/1 1-1048576 AAA 1048576 ++X 1/1 1/5 1-1 AAA-BBB 1 ++X 1/1 2/5 512-512 AAA-BBB 1 ++X 1/1 3/5 1024-1024 AAA-BBB 1 ++X 1/1 4/5 524288-524288 AAA-BBB 1 ++X 1/1 5/5 1048576-1048576 AAA-BBB 1 ++debugfs: ex /bigzerofile ++Level Entries Logical Physical Length Flags ++debugfs: ex /dir ++Level Entries Logical Physical Length Flags ++X 0/0 1/1 0-0 AAA-BBB 1 ++debugfs: ex /dir/file ++Level Entries Logical Physical Length Flags ++X 0/0 1/1 0-0 AAA-BBB 1 ++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.img: 19/1024 files (0.0% non-contiguous), 1598/16384 blocks +--- /dev/null ++++ b/tests/m_rootdir/output.sed +@@ -0,0 +1,5 @@ ++s/^[[:space:]]*\([0-9]*\)\/[[:space:]]*\([0-9]*\)[[:space:]]*\([0-9]*\)\/[[:space:]]*\([0-9]*\)[[:space:]]*\([0-9]*\)[[:space:]]*-[[:space:]]*\([0-9]*\)[[:space:]]*[0-9]*[[:space:]]*-[[:space:]]*[0-9]*[[:space:]]*\([0-9]*\)/X \1\/\2 \3\/\4 \5-\6 AAA-BBB \7/g ++s/^[[:space:]]*\([0-9]*\)\/[[:space:]]*\([0-9]*\)[[:space:]]*\([0-9]*\)\/[[:space:]]*\([0-9]*\)[[:space:]]*\([0-9]*\)[[:space:]]*-[[:space:]]*\([0-9]*\)[[:space:]]*[0-9]*[[:space:]]*\([0-9]*\)/Y \1\/\2 \3\/\4 \5-\6 AAA \7/g ++s/Mode:.*$//g ++s/User:.*Size:/Size:/g ++s/^Inode: [0-9]*/Inode: III/g +--- /dev/null ++++ b/tests/m_rootdir/script +@@ -0,0 +1,71 @@ ++if test -x $DEBUGFS_EXE; then ++ ++test_description="create fs image from dir" ++MKFS_DIR=$TMPFILE.dir ++OUT=$test_name.log ++EXP=$test_dir/expect ++ ++rm -rf $MKFS_DIR ++mkdir -p $MKFS_DIR ++touch $MKFS_DIR/emptyfile ++dd if=/dev/zero bs=1024 count=32 2> /dev/null | tr '\0' 'a' > $MKFS_DIR/bigfile ++echo "M" | dd of=$MKFS_DIR/sparsefile bs=1 count=1 seek=1024 2> /dev/null ++echo "M" | dd of=$MKFS_DIR/sparsefile bs=1 count=1 seek=524288 conv=notrunc 2> /dev/null ++echo "M" | dd of=$MKFS_DIR/sparsefile bs=1 count=1 seek=1048576 conv=notrunc 2> /dev/null ++echo "M" | dd of=$MKFS_DIR/sparsefile bs=1 count=1 seek=536870912 conv=notrunc 2> /dev/null ++echo "M" | dd of=$MKFS_DIR/sparsefile bs=1 count=1 seek=1073741824 conv=notrunc 2> /dev/null ++dd if=/dev/zero of=$MKFS_DIR/bigzerofile bs=1 count=1 seek=1073741824 2> /dev/null ++ln $MKFS_DIR/bigzerofile $MKFS_DIR/bigzerofile_hardlink ++ln -s /silly_bs_link $MKFS_DIR/silly_bs_link ++mkdir $MKFS_DIR/emptydir ++mkdir $MKFS_DIR/dir ++echo "Test me" > $MKFS_DIR/dir/file ++ ++$MKE2FS -q -F -o Linux -T ext4 -O metadata_csum,64bit -E lazy_itable_init=1 -b 1024 -d $MKFS_DIR $TMPFILE 16384 > $OUT 2>&1 ++ ++$DUMPE2FS $TMPFILE >> $OUT 2>&1 ++cat > $TMPFILE.cmd << ENDL ++stat /emptyfile ++stat /bigfile ++stat /sparsefile ++stat /bigzerofile ++stat /fifo ++stat /emptydir ++stat /dir ++stat /dir/file ++ENDL ++$DEBUGFS -f $TMPFILE.cmd $TMPFILE 2>&1 | egrep "(stat|Size:|Type:)" | sed -f $test_dir/output.sed >> $OUT ++ ++cat > $TMPFILE.cmd << ENDL ++ex /emptyfile ++ex /bigfile ++ex /sparsefile ++ex /bigzerofile ++ex /dir ++ex /dir/file ++ENDL ++$DEBUGFS -f $TMPFILE.cmd $TMPFILE 2>&1 | sed -f $test_dir/output.sed >> $OUT 2>&1 ++ ++$FSCK -f -n $TMPFILE >> $OUT 2>&1 ++ ++sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" < $OUT > $OUT.tmp ++mv $OUT.tmp $OUT ++ ++# 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 ++ ++rm -rf $TMPFILE.cmd $MKFS_DIR $OUT.sed ++unset MKFS_DIR OUT EXP ++ ++else #if test -x $DEBUGFS_EXE; then ++ echo "$test_name: $test_description: skipped" ++fi +--- a/tests/m_root_owner/expect.1 ++++ b/tests/m_root_owner/expect.1 +@@ -46,7 +46,8 @@ + Group 0: (Blocks 1-1023) + Primary superblock at 1, Group descriptors at 2-2 + Reserved GDT blocks at 3-5 +- Block bitmap at 6 (+5), Inode bitmap at 7 (+6) ++ Block bitmap at 6 (+5) ++ Inode bitmap at 7 (+6) + Inode table at 8-23 (+7) + 986 free blocks, 117 free inodes, 2 directories + Free blocks: 38-1023 +--- a/tests/m_std/script ++++ b/tests/m_std/script +@@ -1,3 +1,6 @@ + DESCRIPTION="standard filesystem options" ++DUMPE2FS_IGNORE_80COL=1 ++export DUMPE2FS_IGNORE_80COL + FS_SIZE=65536 + . $cmd_dir/run_mke2fs ++unset DUMPE2FS_IGNORE_80COL +--- a/tests/m_uninit/script ++++ b/tests/m_uninit/script +@@ -1,4 +1,7 @@ + DESCRIPTION="uninitialized group feature" ++DUMPE2FS_IGNORE_80COL=1 ++export DUMPE2FS_IGNORE_80COL + FS_SIZE=131072 + MKE2FS_OPTS="-O uninit_bg" + . $cmd_dir/run_mke2fs ++unset DUMPE2FS_IGNORE_80COL +--- a/tests/progs/Makefile.in ++++ b/tests/progs/Makefile.in +@@ -28,6 +28,7 @@ + $(E) " CC $<" + $(Q) $(CC) -c $(ALL_CFLAGS) $< -o $@ + $(Q) $(CHECK_CMD) $(ALL_CFLAGS) $< ++ $(Q) $(CPPCHECK_CMD) $(CPPFLAGS) $< + + all:: $(PROGS) + +--- /dev/null ++++ b/tests/r_32to64bit/expect +@@ -0,0 +1,94 @@ ++resize2fs test ++Creating filesystem with 524288 1k blocks and 65536 inodes ++Superblock backups stored on blocks: ++ 8193, 24577, 40961, 57345, 73729, 204801, 221185, 401409 ++ ++Allocating group tables: done ++Writing inode tables: done ++Creating journal (16384 blocks): done ++Creating 477 huge file(s) with 1024 blocks each: done ++Writing superblocks and filesystem accounting information: done ++ ++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 ++ ++Exit status is 0 ++resize2fs test.img -b ++Converting the filesystem to 64-bit. ++The filesystem on test.img is now 524288 (1k) blocks long. ++ ++Exit status is 0 ++Change in FS metadata: ++@@ -2,7 +2,7 @@ ++ Last mounted on: ++ Filesystem magic number: 0xEF53 ++ Filesystem revision #: 1 (dynamic) ++-Filesystem features: has_journal ext_attr resize_inode dir_index filetype extent flex_bg sparse_super large_file huge_file uninit_bg dir_nlink extra_isize +++Filesystem features: has_journal ext_attr resize_inode dir_index filetype extent 64bit flex_bg sparse_super large_file huge_file uninit_bg dir_nlink extra_isize ++ Default mount options: user_xattr acl ++ Filesystem state: clean ++ Errors behavior: Continue ++@@ -15,7 +15,8 @@ ++ First block: 1 ++ Block size: 1024 ++ Fragment size: 1024 ++-Reserved GDT blocks: 256 +++Group descriptor size: 64 +++Reserved GDT blocks: 254 ++ Blocks per group: 8192 ++ Fragments per group: 8192 ++ Inodes per group: 1024 ++@@ -40,16 +41,16 @@ ++ ++ ++ group:block:super:gdt:bbitmap:ibitmap:itable ++-0:1:1:2-3:260:276:292 ++-1:8193:8193:8194-8195:261:277:548 +++0:1:1:2-5:260:276:292 +++1:8193:8193:8194-8197:261:277:548 ++ 2:16385:-1:-1:262:278:804 ++-3:24577:24577:24578-24579:263:279:1060 +++3:24577:24577:24578-24581:263:279:1060 ++ 4:32769:-1:-1:264:280:1316 ++-5:40961:40961:40962-40963:265:281:1572 +++5:40961:40961:40962-40965:265:281:1572 ++ 6:49153:-1:-1:266:282:1828 ++-7:57345:57345:57346-57347:267:283:2084 +++7:57345:57345:57346-57349:267:283:2084 ++ 8:65537:-1:-1:268:284:2340 ++-9:73729:73729:73730-73731:269:285:2596 +++9:73729:73729:73730-73733:269:285:2596 ++ 10:81921:-1:-1:270:286:2852 ++ 11:90113:-1:-1:271:287:3108 ++ 12:98305:-1:-1:272:288:3364 ++@@ -65,9 +66,9 @@ ++ 22:180225:-1:-1:131079:131095:132641 ++ 23:188417:-1:-1:131080:131096:132897 ++ 24:196609:-1:-1:131081:131097:133153 ++-25:204801:204801:204802-204803:131082:131098:133409 +++25:204801:204801:204802-204805:131082:131098:133409 ++ 26:212993:-1:-1:131083:131099:133665 ++-27:221185:221185:221186-221187:131084:131100:133921 +++27:221185:221185:221186-221189:131084:131100:133921 ++ 28:229377:-1:-1:131085:131101:134177 ++ 29:237569:-1:-1:131086:131102:134433 ++ 30:245761:-1:-1:131087:131103:134689 ++@@ -89,7 +90,7 @@ ++ 46:376833:-1:-1:262159:262175:265761 ++ 47:385025:-1:-1:262160:262176:266017 ++ 48:393217:-1:-1:393217:393233:393249 ++-49:401409:401409:401410-401411:393218:393234:393505 +++49:401409:401409:401410-401413:393218:393234:393505 ++ 50:409601:-1:-1:393219:393235:393761 ++ 51:417793:-1:-1:393220:393236:394017 ++ 52:425985:-1:-1:393221:393237:394273 ++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 ++ ++Exit status is 0 +--- /dev/null ++++ b/tests/r_32to64bit/name +@@ -0,0 +1 @@ ++convert flex_bg 32bit fs to 64bit fs +--- /dev/null ++++ b/tests/r_32to64bit/script +@@ -0,0 +1,74 @@ ++if test -x $RESIZE2FS_EXE -a -x $DEBUGFS_EXE; then ++ ++FSCK_OPT=-fn ++OUT=$test_name.log ++EXP=$test_dir/expect ++CONF=$TMPFILE.conf ++ ++cat > $CONF << ENDL ++[fs_types] ++ ext4h = { ++ features = has_journal,extent,huge_file,flex_bg,uninit_bg,dir_nlink,extra_isize,sparse_super,filetype,dir_index,ext_attr,resize_inode ++ blocksize = 1024 ++ inode_size = 256 ++ make_hugefiles = true ++ hugefiles_dir = / ++ hugefiles_slack = 0 ++ hugefiles_name = aaaaa ++ hugefiles_digits = 4 ++ hugefiles_size = 1M ++ zero_hugefiles = false ++ } ++ENDL ++ ++echo "resize2fs test" > $OUT ++ ++MKE2FS_CONFIG=$CONF $MKE2FS -F -T ext4h $TMPFILE 524288 >> $OUT 2>&1 ++rm -rf $CONF ++ ++# dump and check ++($DUMPE2FS -h $TMPFILE; $DUMPE2FS -g $TMPFILE) 2> /dev/null | sed -f $cmd_dir/filter.sed > $OUT.before ++$FSCK $FSCK_OPT -N test_filesys $TMPFILE >> $OUT 2>&1 ++status=$? ++echo Exit status is $status >> $OUT ++ ++# resize it ++echo "resize2fs test.img -b" >> $OUT ++$RESIZE2FS -b -f $TMPFILE 2>&1 >> $OUT 2>&1 ++status=$? ++echo Exit status is $status >> $OUT ++ ++# dump and check ++($DUMPE2FS -h $TMPFILE; $DUMPE2FS -g $TMPFILE) 2> /dev/null | sed -f $cmd_dir/filter.sed > $OUT.after ++echo "Change in FS metadata:" >> $OUT ++diff -u $OUT.before $OUT.after | tail -n +3 >> $OUT ++$FSCK $FSCK_OPT -N test_filesys $TMPFILE >> $OUT 2>&1 ++status=$? ++echo Exit status is $status >> $OUT ++ ++rm $TMPFILE $OUT.before $OUT.after ++ ++# ++# Do the verification ++# ++ ++sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" -e 's/test_filesys:.*//g' < $OUT > $OUT.new ++mv $OUT.new $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 IMAGE FSCK_OPT OUT EXP CONF ++ ++else #if test -x $RESIZE2FS_EXE -a -x $DEBUGFS_EXE; then ++ echo "$test_name: $test_description: skipped" ++fi ++ +--- /dev/null ++++ b/tests/r_32to64bit_expand_full/expect +@@ -0,0 +1,139 @@ ++resize2fs test ++Creating filesystem with 786432 1k blocks and 98304 inodes ++Superblock backups stored on blocks: ++ 8193, 24577, 40961, 57345, 73729, 204801, 221185, 401409, 663553 ++ ++Allocating group tables: done ++Writing inode tables: done ++Creating journal (16384 blocks): done ++Creating 727 huge file(s) with 1024 blocks each: done ++Writing superblocks and filesystem accounting information: done ++ ++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 ++ ++Exit status is 0 ++resize2fs -b test.img ++Converting the filesystem to 64-bit. ++The filesystem on test.img is now 786432 (1k) blocks long. ++ ++resize2fs test.img ++Resizing the filesystem on test.img to 1179648 (1k) blocks. ++The filesystem on test.img is now 1179648 (1k) blocks long. ++ ++Exit status is 0 ++Change in FS metadata: ++@@ -1,15 +1,15 @@ ++ ++ group:block:super:gdt:bbitmap:ibitmap:itable ++-0:1:1:2-7:8:9:10 ++-1:8193:8193:8194-8199:8200:8201:8202 +++0:1:1:2-10:266:267:268 +++1:8193:8193:8194-8202:8458:8459:8460 ++ 2:16385:-1:-1:16385:16386:16387 ++-3:24577:24577:24578-24583:24584:24585:24586 +++3:24577:24577:24578-24586:24842:24843:24844 ++ 4:32769:-1:-1:32769:32770:32771 ++-5:40961:40961:40962-40967:40968:40969:40970 +++5:40961:40961:40962-40970:41226:41227:41228 ++ 6:49153:-1:-1:49153:49154:49155 ++-7:57345:57345:57346-57351:57352:57353:57354 +++7:57345:57345:57346-57354:57610:57611:57612 ++ 8:65537:-1:-1:65537:65538:65539 ++-9:73729:73729:73730-73735:73736:73737:73738 +++9:73729:73729:73730-73738:73994:73995:73996 ++ 10:81921:-1:-1:81921:81922:81923 ++ 11:90113:-1:-1:90113:90114:90115 ++ 12:98305:-1:-1:98305:98306:98307 ++@@ -25,9 +25,9 @@ ++ 22:180225:-1:-1:180225:180226:180227 ++ 23:188417:-1:-1:188417:188418:188419 ++ 24:196609:-1:-1:196609:196610:196611 ++-25:204801:204801:204802-204807:204808:204809:204810 +++25:204801:204801:204802-204810:205066:205067:205068 ++ 26:212993:-1:-1:212993:212994:212995 ++-27:221185:221185:221186-221191:221192:221193:221194 +++27:221185:221185:221186-221194:221450:221451:221452 ++ 28:229377:-1:-1:229377:229378:229379 ++ 29:237569:-1:-1:237569:237570:237571 ++ 30:245761:-1:-1:245761:245762:245763 ++@@ -49,7 +49,7 @@ ++ 46:376833:-1:-1:376833:376834:376835 ++ 47:385025:-1:-1:385025:385026:385027 ++ 48:393217:-1:-1:393217:393218:393219 ++-49:401409:401409:401410-401415:401416:401417:401418 +++49:401409:401409:401410-401418:401674:401675:401676 ++ 50:409601:-1:-1:409601:409602:409603 ++ 51:417793:-1:-1:417793:417794:417795 ++ 52:425985:-1:-1:425985:425986:425987 ++@@ -81,7 +81,7 @@ ++ 78:638977:-1:-1:638977:638978:638979 ++ 79:647169:-1:-1:647169:647170:647171 ++ 80:655361:-1:-1:655361:655362:655363 ++-81:663553:663553:663554-663559:663560:663561:663562 +++81:663553:663553:663554-663562:663818:663819:663820 ++ 82:671745:-1:-1:671745:671746:671747 ++ 83:679937:-1:-1:679937:679938:679939 ++ 84:688129:-1:-1:688129:688130:688131 ++@@ -96,3 +96,51 @@ ++ 93:761857:-1:-1:761857:761858:761859 ++ 94:770049:-1:-1:770049:770050:770051 ++ 95:778241:-1:-1:778241:778242:778243 +++96:786433:-1:-1:786433:786434:786435 +++97:794625:-1:-1:794625:794626:794627 +++98:802817:-1:-1:802817:802818:802819 +++99:811009:-1:-1:811009:811010:811011 +++100:819201:-1:-1:819201:819202:819203 +++101:827393:-1:-1:827393:827394:827395 +++102:835585:-1:-1:835585:835586:835587 +++103:843777:-1:-1:843777:843778:843779 +++104:851969:-1:-1:851969:851970:851971 +++105:860161:-1:-1:860161:860162:860163 +++106:868353:-1:-1:868353:868354:868355 +++107:876545:-1:-1:876545:876546:876547 +++108:884737:-1:-1:884737:884738:884739 +++109:892929:-1:-1:892929:892930:892931 +++110:901121:-1:-1:901121:901122:901123 +++111:909313:-1:-1:909313:909314:909315 +++112:917505:-1:-1:917505:917506:917507 +++113:925697:-1:-1:925697:925698:925699 +++114:933889:-1:-1:933889:933890:933891 +++115:942081:-1:-1:942081:942082:942083 +++116:950273:-1:-1:950273:950274:950275 +++117:958465:-1:-1:958465:958466:958467 +++118:966657:-1:-1:966657:966658:966659 +++119:974849:-1:-1:974849:974850:974851 +++120:983041:-1:-1:983041:983042:983043 +++121:991233:-1:-1:991233:991234:991235 +++122:999425:-1:-1:999425:999426:999427 +++123:1007617:-1:-1:1007617:1007618:1007619 +++124:1015809:-1:-1:1015809:1015810:1015811 +++125:1024001:1024001:1024002-1024010:1024011:1024012:1024013 +++126:1032193:-1:-1:1032193:1032194:1032195 +++127:1040385:-1:-1:1040385:1040386:1040387 +++128:1048577:-1:-1:1048577:1048578:1048579 +++129:1056769:-1:-1:1056769:1056770:1056771 +++130:1064961:-1:-1:1064961:1064962:1064963 +++131:1073153:-1:-1:1073153:1073154:1073155 +++132:1081345:-1:-1:1081345:1081346:1081347 +++133:1089537:-1:-1:1089537:1089538:1089539 +++134:1097729:-1:-1:1097729:1097730:1097731 +++135:1105921:-1:-1:1105921:1105922:1105923 +++136:1114113:-1:-1:1114113:1114114:1114115 +++137:1122305:-1:-1:1122305:1122306:1122307 +++138:1130497:-1:-1:1130497:1130498:1130499 +++139:1138689:-1:-1:1138689:1138690:1138691 +++140:1146881:-1:-1:1146881:1146882:1146883 +++141:1155073:-1:-1:1155073:1155074:1155075 +++142:1163265:-1:-1:1163265:1163266:1163267 +++143:1171457:-1:-1:1171457:1171458:1171459 ++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 ++ ++Exit status is 0 +--- /dev/null ++++ b/tests/r_32to64bit_expand_full/name +@@ -0,0 +1 @@ ++convert a totally full filesystem to 64bit, then expand +--- /dev/null ++++ b/tests/r_32to64bit_expand_full/script +@@ -0,0 +1,83 @@ ++if test -x $RESIZE2FS_EXE -a -x $DEBUGFS_EXE; then ++ ++FSCK_OPT=-fn ++OUT=$test_name.log ++EXP=$test_dir/expect ++CONF=$TMPFILE.conf ++ ++#gzip -d < $EXP.gz > $EXP ++ ++cat > $CONF << ENDL ++[fs_types] ++ ext4h = { ++ features = has_journal,extent,huge_file,uninit_bg,dir_nlink,extra_isize,sparse_super,filetype,dir_index,ext_attr,^resize_inode,^meta_bg,^flex_bg ++ blocksize = 1024 ++ inode_size = 256 ++ make_hugefiles = true ++ hugefiles_dir = / ++ hugefiles_slack = 0 ++ hugefiles_name = aaaaa ++ hugefiles_digits = 4 ++ hugefiles_size = 1M ++ zero_hugefiles = false ++ } ++ENDL ++ ++echo "resize2fs test" > $OUT ++ ++MKE2FS_CONFIG=$CONF $MKE2FS -F -T ext4h $TMPFILE 786432 >> $OUT 2>&1 ++rm -rf $CONF ++ ++# check ++$FSCK $FSCK_OPT -N test_filesys $TMPFILE >> $OUT 2>&1 ++status=$? ++echo Exit status is $status >> $OUT ++ ++# convert it ++echo "resize2fs -b test.img" >> $OUT ++$RESIZE2FS -b -f $TMPFILE 2>&1 >> $OUT 2>&1 ++$DUMPE2FS -g $TMPFILE 2>&1 >> $OUT.before 2> /dev/null ++ ++# grow it ++echo "resize2fs test.img" >> $OUT ++dd if=/dev/zero of=$TMPFILE conv=notrunc bs=1 count=1 seek=1207959552 2> /dev/null ++$RESIZE2FS -f $TMPFILE 2>&1 >> $OUT 2>&1 ++status=$? ++echo Exit status is $status >> $OUT ++ ++# dump and check ++$DUMPE2FS -g $TMPFILE 2>&1 >> $OUT.after 2> /dev/null ++echo "Change in FS metadata:" >> $OUT ++diff -u $OUT.before $OUT.after | tail -n +3 >> $OUT ++$FSCK $FSCK_OPT -N test_filesys $TMPFILE >> $OUT 2>&1 ++status=$? ++echo Exit status is $status >> $OUT ++ ++rm $TMPFILE ++ ++# ++# Do the verification ++# ++ ++sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" -e 's/test_filesys:.*//g' < $OUT > $OUT.new ++mv $OUT.new $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 ++ ++rm $OUT.before $OUT.after ++ ++unset IMAGE FSCK_OPT OUT EXP CONF ++ ++else #if test -x $RESIZE2FS_EXE -a -x $DEBUGFS_EXE; then ++ echo "$test_name: $test_description: skipped" ++fi ++ +--- /dev/null ++++ b/tests/r_32to64bit_meta/expect +@@ -0,0 +1,80 @@ ++resize2fs test ++Creating filesystem with 524288 1k blocks and 65536 inodes ++Superblock backups stored on blocks: ++ 8193, 24577, 40961, 57345, 73729, 204801, 221185, 401409 ++ ++Allocating group tables: done ++Writing inode tables: done ++Creating journal (16384 blocks): done ++Creating 479 huge file(s) with 1024 blocks each: done ++Writing superblocks and filesystem accounting information: done ++ ++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 ++ ++Exit status is 0 ++resize2fs test.img -b ++Converting the filesystem to 64-bit. ++The filesystem on test.img is now 524288 (1k) blocks long. ++ ++Exit status is 0 ++Change in FS metadata: ++@@ -2,7 +2,7 @@ ++ Last mounted on: ++ Filesystem magic number: 0xEF53 ++ Filesystem revision #: 1 (dynamic) ++-Filesystem features: has_journal ext_attr dir_index filetype meta_bg extent flex_bg sparse_super large_file huge_file uninit_bg dir_nlink extra_isize +++Filesystem features: has_journal ext_attr dir_index filetype meta_bg extent 64bit flex_bg sparse_super large_file huge_file uninit_bg dir_nlink extra_isize ++ Default mount options: user_xattr acl ++ Filesystem state: clean ++ Errors behavior: Continue ++@@ -10,11 +10,12 @@ ++ Inode count: 65536 ++ Block count: 524288 ++ Reserved block count: 26214 ++-Free blocks: 858 +++Free blocks: 852 ++ Free inodes: 65046 ++ First block: 1 ++ Block size: 1024 ++ Fragment size: 1024 +++Group descriptor size: 64 ++ Blocks per group: 8192 ++ Fragments per group: 8192 ++ Inodes per group: 1024 ++@@ -54,9 +55,9 @@ ++ 12:98305:-1:-1:15:31:3107 ++ 13:106497:-1:-1:16:32:3363 ++ 14:114689:-1:-1:17:33:3619 ++-15:122881:-1:-1:18:34:3875 ++-16:131073:-1:-1:131073:131089:131105 ++-17:139265:-1:-1:131074:131090:131361 +++15:122881:-1:122881:18:34:3875 +++16:131073:-1:131073:135201:131089:131105 +++17:139265:-1:139265:131074:131090:131361 ++ 18:147457:-1:-1:131075:131091:131617 ++ 19:155649:-1:-1:131076:131092:131873 ++ 20:163841:-1:-1:131077:131093:132129 ++@@ -86,9 +87,9 @@ ++ 44:360449:-1:-1:262158:262174:265250 ++ 45:368641:-1:-1:262159:262175:265506 ++ 46:376833:-1:-1:262160:262176:265762 ++-47:385025:-1:-1:262161:262177:266018 ++-48:393217:-1:-1:393217:393233:393249 ++-49:401409:401409:-1:393218:393234:393505 +++47:385025:-1:385025:262161:262177:266018 +++48:393217:-1:393217:397345:393233:393249 +++49:401409:401409:401410:393218:393234:393505 ++ 50:409601:-1:-1:393219:393235:393761 ++ 51:417793:-1:-1:393220:393236:394017 ++ 52:425985:-1:-1:393221:393237:394273 ++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 ++ ++Exit status is 0 +--- /dev/null ++++ b/tests/r_32to64bit_meta/name +@@ -0,0 +1 @@ ++convert meta_bg 32bit fs to 64bit fs +--- /dev/null ++++ b/tests/r_32to64bit_meta/script +@@ -0,0 +1,74 @@ ++if test -x $RESIZE2FS_EXE -a -x $DEBUGFS_EXE; then ++ ++FSCK_OPT=-fn ++OUT=$test_name.log ++EXP=$test_dir/expect ++CONF=$TMPFILE.conf ++ ++cat > $CONF << ENDL ++[fs_types] ++ ext4h = { ++ features = has_journal,extent,huge_file,flex_bg,uninit_bg,dir_nlink,extra_isize,sparse_super,filetype,dir_index,ext_attr,meta_bg,^resize_inode ++ blocksize = 1024 ++ inode_size = 256 ++ make_hugefiles = true ++ hugefiles_dir = / ++ hugefiles_slack = 0 ++ hugefiles_name = aaaaa ++ hugefiles_digits = 4 ++ hugefiles_size = 1M ++ zero_hugefiles = false ++ } ++ENDL ++ ++echo "resize2fs test" > $OUT ++ ++MKE2FS_CONFIG=$CONF $MKE2FS -F -T ext4h $TMPFILE 524288 >> $OUT 2>&1 ++rm -rf $CONF ++ ++# dump and check ++($DUMPE2FS -h $TMPFILE; $DUMPE2FS -g $TMPFILE) 2> /dev/null | sed -f $cmd_dir/filter.sed > $OUT.before ++$FSCK $FSCK_OPT -N test_filesys $TMPFILE >> $OUT 2>&1 ++status=$? ++echo Exit status is $status >> $OUT ++ ++# resize it ++echo "resize2fs test.img -b" >> $OUT ++$RESIZE2FS -b -f $TMPFILE 2>&1 >> $OUT 2>&1 ++status=$? ++echo Exit status is $status >> $OUT ++ ++# dump and check ++($DUMPE2FS -h $TMPFILE; $DUMPE2FS -g $TMPFILE) 2> /dev/null | sed -f $cmd_dir/filter.sed > $OUT.after ++echo "Change in FS metadata:" >> $OUT ++diff -u $OUT.before $OUT.after | tail -n +3 >> $OUT ++$FSCK $FSCK_OPT -N test_filesys $TMPFILE >> $OUT 2>&1 ++status=$? ++echo Exit status is $status >> $OUT ++ ++rm $TMPFILE $OUT.before $OUT.after ++ ++# ++# Do the verification ++# ++ ++sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" -e 's/test_filesys:.*//g' < $OUT > $OUT.new ++mv $OUT.new $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 IMAGE FSCK_OPT OUT EXP CONF ++ ++else #if test -x $RESIZE2FS_EXE -a -x $DEBUGFS_EXE; then ++ echo "$test_name: $test_description: skipped" ++fi ++ +--- /dev/null ++++ b/tests/r_32to64bit_move_itable/expect +@@ -0,0 +1,107 @@ ++resize2fs test ++Creating filesystem with 786432 1k blocks and 98304 inodes ++Superblock backups stored on blocks: ++ 8193, 24577, 40961, 57345, 73729, 204801, 221185, 401409, 663553 ++ ++Allocating group tables: done ++Writing inode tables: done ++Creating journal (16384 blocks): done ++Creating 727 huge file(s) with 1024 blocks each: done ++Writing superblocks and filesystem accounting information: done ++ ++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 ++ ++Exit status is 0 ++resize2fs test.img -b ++Converting the filesystem to 64-bit. ++The filesystem on test.img is now 786432 (1k) blocks long. ++ ++Exit status is 0 ++Change in FS metadata: ++@@ -2,7 +2,7 @@ ++ Last mounted on: ++ Filesystem magic number: 0xEF53 ++ Filesystem revision #: 1 (dynamic) ++-Filesystem features: has_journal ext_attr dir_index filetype extent sparse_super large_file huge_file uninit_bg dir_nlink extra_isize +++Filesystem features: has_journal ext_attr dir_index filetype extent 64bit sparse_super large_file huge_file uninit_bg dir_nlink extra_isize ++ Default mount options: user_xattr acl ++ Filesystem state: clean ++ Errors behavior: Continue ++@@ -10,11 +10,12 @@ ++ Inode count: 98304 ++ Block count: 786432 ++ Reserved block count: 39321 ++-Free blocks: 764 +++Free blocks: 734 ++ Free inodes: 97566 ++ First block: 1 ++ Block size: 1024 ++ Fragment size: 1024 +++Group descriptor size: 64 ++ Blocks per group: 8192 ++ Fragments per group: 8192 ++ Inodes per group: 1024 ++@@ -38,16 +39,16 @@ ++ ++ ++ group:block:super:gdt:bbitmap:ibitmap:itable ++-0:1:1:2-4:5:6:7 ++-1:8193:8193:8194-8196:8197:8198:8199 +++0:1:1:2-7:8:9:10 +++1:8193:8193:8194-8199:8200:8201:8202 ++ 2:16385:-1:-1:16385:16386:16387 ++-3:24577:24577:24578-24580:24581:24582:24583 +++3:24577:24577:24578-24583:24584:24585:24586 ++ 4:32769:-1:-1:32769:32770:32771 ++-5:40961:40961:40962-40964:40965:40966:40967 +++5:40961:40961:40962-40967:40968:40969:40970 ++ 6:49153:-1:-1:49153:49154:49155 ++-7:57345:57345:57346-57348:57349:57350:57351 +++7:57345:57345:57346-57351:57352:57353:57354 ++ 8:65537:-1:-1:65537:65538:65539 ++-9:73729:73729:73730-73732:73733:73734:73735 +++9:73729:73729:73730-73735:73736:73737:73738 ++ 10:81921:-1:-1:81921:81922:81923 ++ 11:90113:-1:-1:90113:90114:90115 ++ 12:98305:-1:-1:98305:98306:98307 ++@@ -63,9 +64,9 @@ ++ 22:180225:-1:-1:180225:180226:180227 ++ 23:188417:-1:-1:188417:188418:188419 ++ 24:196609:-1:-1:196609:196610:196611 ++-25:204801:204801:204802-204804:204805:204806:204807 +++25:204801:204801:204802-204807:204808:204809:204810 ++ 26:212993:-1:-1:212993:212994:212995 ++-27:221185:221185:221186-221188:221189:221190:221191 +++27:221185:221185:221186-221191:221192:221193:221194 ++ 28:229377:-1:-1:229377:229378:229379 ++ 29:237569:-1:-1:237569:237570:237571 ++ 30:245761:-1:-1:245761:245762:245763 ++@@ -87,7 +88,7 @@ ++ 46:376833:-1:-1:376833:376834:376835 ++ 47:385025:-1:-1:385025:385026:385027 ++ 48:393217:-1:-1:393217:393218:393219 ++-49:401409:401409:401410-401412:401413:401414:401415 +++49:401409:401409:401410-401415:401416:401417:401418 ++ 50:409601:-1:-1:409601:409602:409603 ++ 51:417793:-1:-1:417793:417794:417795 ++ 52:425985:-1:-1:425985:425986:425987 ++@@ -119,7 +120,7 @@ ++ 78:638977:-1:-1:638977:638978:638979 ++ 79:647169:-1:-1:647169:647170:647171 ++ 80:655361:-1:-1:655361:655362:655363 ++-81:663553:663553:663554-663556:663557:663558:663559 +++81:663553:663553:663554-663559:663560:663561:663562 ++ 82:671745:-1:-1:671745:671746:671747 ++ 83:679937:-1:-1:679937:679938:679939 ++ 84:688129:-1:-1:688129:688130:688131 ++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 ++ ++Exit status is 0 +--- /dev/null ++++ b/tests/r_32to64bit_move_itable/name +@@ -0,0 +1 @@ ++convert 32bit fs to 64bit fs, forcing inode table move +--- /dev/null ++++ b/tests/r_32to64bit_move_itable/script +@@ -0,0 +1,74 @@ ++if test -x $RESIZE2FS_EXE -a -x $DEBUGFS_EXE; then ++ ++FSCK_OPT=-fn ++OUT=$test_name.log ++EXP=$test_dir/expect ++CONF=$TMPFILE.conf ++ ++cat > $CONF << ENDL ++[fs_types] ++ ext4h = { ++ features = has_journal,extent,huge_file,uninit_bg,dir_nlink,extra_isize,sparse_super,filetype,dir_index,ext_attr,^resize_inode,^meta_bg,^flex_bg ++ blocksize = 1024 ++ inode_size = 256 ++ make_hugefiles = true ++ hugefiles_dir = / ++ hugefiles_slack = 0 ++ hugefiles_name = aaaaa ++ hugefiles_digits = 4 ++ hugefiles_size = 1M ++ zero_hugefiles = false ++ } ++ENDL ++ ++echo "resize2fs test" > $OUT ++ ++MKE2FS_CONFIG=$CONF $MKE2FS -F -T ext4h $TMPFILE 786432 >> $OUT 2>&1 ++rm -rf $CONF ++ ++# dump and check ++($DUMPE2FS -h $TMPFILE; $DUMPE2FS -g $TMPFILE) 2> /dev/null | sed -f $cmd_dir/filter.sed > $OUT.before ++$FSCK $FSCK_OPT -N test_filesys $TMPFILE >> $OUT 2>&1 ++status=$? ++echo Exit status is $status >> $OUT ++ ++# convert it ++echo "resize2fs test.img -b" >> $OUT ++$RESIZE2FS -b -f $TMPFILE 2>&1 >> $OUT 2>&1 ++status=$? ++echo Exit status is $status >> $OUT ++ ++# dump and check ++($DUMPE2FS -h $TMPFILE; $DUMPE2FS -g $TMPFILE) 2> /dev/null | sed -f $cmd_dir/filter.sed > $OUT.after ++echo "Change in FS metadata:" >> $OUT ++diff -u $OUT.before $OUT.after | tail -n +3 >> $OUT ++$FSCK $FSCK_OPT -N test_filesys $TMPFILE >> $OUT 2>&1 ++status=$? ++echo Exit status is $status >> $OUT ++ ++rm $TMPFILE $OUT.before $OUT.after ++ ++# ++# Do the verification ++# ++ ++sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" -e 's/test_filesys:.*//g' < $OUT > $OUT.new ++mv $OUT.new $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 IMAGE FSCK_OPT OUT EXP CONF ++ ++else #if test -x $RESIZE2FS_EXE -a -x $DEBUGFS_EXE; then ++ echo "$test_name: $test_description: skipped" ++fi ++ +--- /dev/null ++++ b/tests/r_64to32bit/expect +@@ -0,0 +1,98 @@ ++resize2fs test ++Creating filesystem with 524288 1k blocks and 65536 inodes ++Superblock backups stored on blocks: ++ 8193, 24577, 40961, 57345, 73729, 204801, 221185, 401409 ++ ++Allocating group tables: done ++Writing inode tables: done ++Creating journal (16384 blocks): done ++Creating 477 huge file(s) with 1024 blocks each: done ++Writing superblocks and filesystem accounting information: done ++ ++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 ++ ++Exit status is 0 ++resize2fs test.img -s ++Converting the filesystem to 32-bit. ++The filesystem on test.img is now 524288 (1k) blocks long. ++ ++Exit status is 0 ++Change in FS metadata: ++@@ -2,7 +2,7 @@ ++ Last mounted on: ++ Filesystem magic number: 0xEF53 ++ Filesystem revision #: 1 (dynamic) ++-Filesystem features: has_journal ext_attr resize_inode dir_index filetype extent 64bit flex_bg sparse_super large_file huge_file uninit_bg dir_nlink extra_isize +++Filesystem features: has_journal ext_attr resize_inode dir_index filetype extent flex_bg sparse_super large_file huge_file uninit_bg dir_nlink extra_isize ++ Default mount options: user_xattr acl ++ Filesystem state: clean ++ Errors behavior: Continue ++@@ -10,12 +10,11 @@ ++ Inode count: 65536 ++ Block count: 524288 ++ Reserved block count: 26214 ++-Free blocks: 571 +++Free blocks: 589 ++ Free inodes: 65048 ++ First block: 1 ++ Block size: 1024 ++ Fragment size: 1024 ++-Group descriptor size: 64 ++ Reserved GDT blocks: 256 ++ Blocks per group: 8192 ++ Fragments per group: 8192 ++@@ -41,16 +40,16 @@ ++ ++ ++ group:block:super:gdt:bbitmap:ibitmap:itable ++-0:1:1:2-5:262:278:294 ++-1:8193:8193:8194-8197:263:279:550 +++0:1:1:2-3:262:278:294 +++1:8193:8193:8194-8195:263:279:550 ++ 2:16385:-1:-1:264:280:806 ++-3:24577:24577:24578-24581:265:281:1062 +++3:24577:24577:24578-24579:265:281:1062 ++ 4:32769:-1:-1:266:282:1318 ++-5:40961:40961:40962-40965:267:283:1574 +++5:40961:40961:40962-40963:267:283:1574 ++ 6:49153:-1:-1:268:284:1830 ++-7:57345:57345:57346-57349:269:285:2086 +++7:57345:57345:57346-57347:269:285:2086 ++ 8:65537:-1:-1:270:286:2342 ++-9:73729:73729:73730-73733:271:287:2598 +++9:73729:73729:73730-73731:271:287:2598 ++ 10:81921:-1:-1:272:288:2854 ++ 11:90113:-1:-1:273:289:3110 ++ 12:98305:-1:-1:274:290:3366 ++@@ -66,9 +65,9 @@ ++ 22:180225:-1:-1:131079:131095:132641 ++ 23:188417:-1:-1:131080:131096:132897 ++ 24:196609:-1:-1:131081:131097:133153 ++-25:204801:204801:204802-204805:131082:131098:133409 +++25:204801:204801:204802-204803:131082:131098:133409 ++ 26:212993:-1:-1:131083:131099:133665 ++-27:221185:221185:221186-221189:131084:131100:133921 +++27:221185:221185:221186-221187:131084:131100:133921 ++ 28:229377:-1:-1:131085:131101:134177 ++ 29:237569:-1:-1:131086:131102:134433 ++ 30:245761:-1:-1:131087:131103:134689 ++@@ -90,7 +89,7 @@ ++ 46:376833:-1:-1:262159:262175:265761 ++ 47:385025:-1:-1:262160:262176:266017 ++ 48:393217:-1:-1:393217:393233:393249 ++-49:401409:401409:401410-401413:393218:393234:393505 +++49:401409:401409:401410-401411:393218:393234:393505 ++ 50:409601:-1:-1:393219:393235:393761 ++ 51:417793:-1:-1:393220:393236:394017 ++ 52:425985:-1:-1:393221:393237:394273 ++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 ++ ++Exit status is 0 +--- /dev/null ++++ b/tests/r_64to32bit/name +@@ -0,0 +1 @@ ++convert flex_bg 64bit fs to 32bit fs +--- /dev/null ++++ b/tests/r_64to32bit/script +@@ -0,0 +1,76 @@ ++if test -x $RESIZE2FS_EXE -a -x $DEBUGFS_EXE; then ++ ++FSCK_OPT=-fn ++OUT=$test_name.log ++EXP=$test_dir/expect ++CONF=$TMPFILE.conf ++ ++cat > $CONF << ENDL ++[fs_types] ++ ext4h = { ++ features = has_journal,extent,huge_file,flex_bg,uninit_bg,dir_nlink,extra_isize,sparse_super,filetype,dir_index,ext_attr,resize_inode,64bit ++ blocksize = 1024 ++ inode_size = 256 ++ make_hugefiles = true ++ hugefiles_dir = / ++ hugefiles_slack = 0 ++ hugefiles_name = aaaaa ++ hugefiles_digits = 4 ++ hugefiles_size = 1M ++ zero_hugefiles = false ++ } ++ENDL ++ ++echo "resize2fs test" > $OUT ++ ++MKE2FS_CONFIG=$CONF $MKE2FS -F -T ext4h $TMPFILE 524288 >> $OUT 2>&1 ++rm -rf $CONF ++ ++# dump and check ++($DUMPE2FS -h $TMPFILE; $DUMPE2FS -g $TMPFILE) 2> /dev/null | sed -f $cmd_dir/filter.sed > $OUT.before ++$FSCK $FSCK_OPT -N test_filesys $TMPFILE >> $OUT 2>&1 ++status=$? ++echo Exit status is $status >> $OUT ++ ++# resize it ++echo "resize2fs test.img -s" >> $OUT ++$RESIZE2FS -s -f $TMPFILE 2>&1 >> $OUT 2>&1 ++status=$? ++echo Exit status is $status >> $OUT ++ ++# dump and check ++($DUMPE2FS -h $TMPFILE; $DUMPE2FS -g $TMPFILE) 2> /dev/null | sed -f $cmd_dir/filter.sed > $OUT.after ++echo "Change in FS metadata:" >> $OUT ++diff -u $OUT.before $OUT.after | tail -n +3 >> $OUT ++$FSCK $FSCK_OPT -N test_filesys $TMPFILE >> $OUT 2>&1 ++status=$? ++echo Exit status is $status >> $OUT ++ ++rm $TMPFILE ++ ++# ++# Do the verification ++# ++ ++sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" -e 's/test_filesys:.*//g' < $OUT > $OUT.new ++mv $OUT.new $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 ++ ++rm $OUT.before $OUT.after ++ ++unset IMAGE FSCK_OPT OUT EXP CONF ++ ++else #if test -x $RESIZE2FS_EXE -a -x $DEBUGFS_EXE; then ++ echo "$test_name: $test_description: skipped" ++fi ++ +--- /dev/null ++++ b/tests/r_64to32bit_meta/expect +@@ -0,0 +1,80 @@ ++resize2fs test ++Creating filesystem with 524288 1k blocks and 65536 inodes ++Superblock backups stored on blocks: ++ 8193, 24577, 40961, 57345, 73729, 204801, 221185, 401409 ++ ++Allocating group tables: done ++Writing inode tables: done ++Creating journal (16384 blocks): done ++Creating 479 huge file(s) with 1024 blocks each: done ++Writing superblocks and filesystem accounting information: done ++ ++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 ++ ++Exit status is 0 ++resize2fs test.img -s ++Converting the filesystem to 32-bit. ++The filesystem on test.img is now 524288 (1k) blocks long. ++ ++Exit status is 0 ++Change in FS metadata: ++@@ -2,7 +2,7 @@ ++ Last mounted on: ++ Filesystem magic number: 0xEF53 ++ Filesystem revision #: 1 (dynamic) ++-Filesystem features: has_journal ext_attr dir_index filetype meta_bg extent 64bit flex_bg sparse_super large_file huge_file uninit_bg dir_nlink extra_isize +++Filesystem features: has_journal ext_attr dir_index filetype meta_bg extent flex_bg sparse_super large_file huge_file uninit_bg dir_nlink extra_isize ++ Default mount options: user_xattr acl ++ Filesystem state: clean ++ Errors behavior: Continue ++@@ -10,12 +10,11 @@ ++ Inode count: 65536 ++ Block count: 524288 ++ Reserved block count: 26214 ++-Free blocks: 852 +++Free blocks: 858 ++ Free inodes: 65046 ++ First block: 1 ++ Block size: 1024 ++ Fragment size: 1024 ++-Group descriptor size: 64 ++ Blocks per group: 8192 ++ Fragments per group: 8192 ++ Inodes per group: 1024 ++@@ -55,9 +54,9 @@ ++ 12:98305:-1:-1:15:31:3107 ++ 13:106497:-1:-1:16:32:3363 ++ 14:114689:-1:-1:17:33:3619 ++-15:122881:-1:122881:18:34:3875 ++-16:131073:-1:131073:131074:131090:131106 ++-17:139265:-1:139265:131075:131091:131362 +++15:122881:-1:-1:18:34:3875 +++16:131073:-1:-1:131074:131090:131106 +++17:139265:-1:-1:131075:131091:131362 ++ 18:147457:-1:-1:131076:131092:131618 ++ 19:155649:-1:-1:131077:131093:131874 ++ 20:163841:-1:-1:131078:131094:132130 ++@@ -87,9 +86,9 @@ ++ 44:360449:-1:-1:262158:262174:265250 ++ 45:368641:-1:-1:262159:262175:265506 ++ 46:376833:-1:-1:262160:262176:265762 ++-47:385025:-1:385025:262161:262177:266018 ++-48:393217:-1:393217:393218:393234:393250 ++-49:401409:401409:401410:393219:393235:393506 +++47:385025:-1:-1:262161:262177:266018 +++48:393217:-1:-1:393218:393234:393250 +++49:401409:401409:-1:393219:393235:393506 ++ 50:409601:-1:-1:393220:393236:393762 ++ 51:417793:-1:-1:393221:393237:394018 ++ 52:425985:-1:-1:393222:393238:394274 ++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 ++ ++Exit status is 0 +--- /dev/null ++++ b/tests/r_64to32bit_meta/name +@@ -0,0 +1 @@ ++convert meta_bg 64bit fs to 32bit fs +--- /dev/null ++++ b/tests/r_64to32bit_meta/script +@@ -0,0 +1,76 @@ ++if test -x $RESIZE2FS_EXE -a -x $DEBUGFS_EXE; then ++ ++FSCK_OPT=-fn ++OUT=$test_name.log ++EXP=$test_dir/expect ++CONF=$TMPFILE.conf ++ ++cat > $CONF << ENDL ++[fs_types] ++ ext4h = { ++ features = has_journal,extent,huge_file,flex_bg,uninit_bg,dir_nlink,extra_isize,sparse_super,filetype,dir_index,ext_attr,meta_bg,^resize_inode,64bit ++ blocksize = 1024 ++ inode_size = 256 ++ make_hugefiles = true ++ hugefiles_dir = / ++ hugefiles_slack = 0 ++ hugefiles_name = aaaaa ++ hugefiles_digits = 4 ++ hugefiles_size = 1M ++ zero_hugefiles = false ++ } ++ENDL ++ ++echo "resize2fs test" > $OUT ++ ++MKE2FS_CONFIG=$CONF $MKE2FS -F -T ext4h $TMPFILE 524288 >> $OUT 2>&1 ++rm -rf $CONF ++ ++# dump and check ++($DUMPE2FS -h $TMPFILE; $DUMPE2FS -g $TMPFILE) 2> /dev/null | sed -f $cmd_dir/filter.sed > $OUT.before ++$FSCK $FSCK_OPT -N test_filesys $TMPFILE >> $OUT 2>&1 ++status=$? ++echo Exit status is $status >> $OUT ++ ++# resize it ++echo "resize2fs test.img -s" >> $OUT ++$RESIZE2FS -s -f $TMPFILE 2>&1 >> $OUT 2>&1 ++status=$? ++echo Exit status is $status >> $OUT ++ ++# dump and check ++($DUMPE2FS -h $TMPFILE; $DUMPE2FS -g $TMPFILE) 2> /dev/null | sed -f $cmd_dir/filter.sed > $OUT.after ++echo "Change in FS metadata:" >> $OUT ++diff -u $OUT.before $OUT.after | tail -n +3 >> $OUT ++$FSCK $FSCK_OPT -N test_filesys $TMPFILE >> $OUT 2>&1 ++status=$? ++echo Exit status is $status >> $OUT ++ ++rm $TMPFILE ++ ++# ++# Do the verification ++# ++ ++sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" -e 's/test_filesys:.*//g' < $OUT > $OUT.new ++mv $OUT.new $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 ++ ++rm $OUT.before $OUT.after ++ ++unset IMAGE FSCK_OPT OUT EXP CONF ++ ++else #if test -x $RESIZE2FS_EXE -a -x $DEBUGFS_EXE; then ++ echo "$test_name: $test_description: skipped" ++fi ++ +--- /dev/null ++++ b/tests/r_expand_full/expect +@@ -0,0 +1,375 @@ ++resize2fs test ++Creating filesystem with 786432 1k blocks and 98304 inodes ++Superblock backups stored on blocks: ++ 8193, 24577, 40961, 57345, 73729, 204801, 221185, 401409, 663553 ++ ++Allocating group tables: done ++Writing inode tables: done ++Creating journal (16384 blocks): done ++Creating 727 huge file(s) with 1024 blocks each: done ++Writing superblocks and filesystem accounting information: done ++ ++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 ++ ++Exit status is 0 ++resize2fs test.img ++Resizing the filesystem on test.img to 3145728 (1k) blocks. ++The filesystem on test.img is now 3145728 (1k) blocks long. ++ ++Exit status is 0 ++Change in FS metadata: ++@@ -1,15 +1,15 @@ ++ ++ group:block:super:gdt:bbitmap:ibitmap:itable ++-0:1:1:2-4:5:6:7 ++-1:8193:8193:8194-8196:8197:8198:8199 +++0:1:1:2-13:263:264:265 +++1:8193:8193:8194-8205:8455:8456:8457 ++ 2:16385:-1:-1:16385:16386:16387 ++-3:24577:24577:24578-24580:24581:24582:24583 +++3:24577:24577:24578-24589:24839:24840:24841 ++ 4:32769:-1:-1:32769:32770:32771 ++-5:40961:40961:40962-40964:40965:40966:40967 +++5:40961:40961:40962-40973:41223:41224:41225 ++ 6:49153:-1:-1:49153:49154:49155 ++-7:57345:57345:57346-57348:57349:57350:57351 +++7:57345:57345:57346-57357:57607:57608:57609 ++ 8:65537:-1:-1:65537:65538:65539 ++-9:73729:73729:73730-73732:73733:73734:73735 +++9:73729:73729:73730-73741:73991:73992:73993 ++ 10:81921:-1:-1:81921:81922:81923 ++ 11:90113:-1:-1:90113:90114:90115 ++ 12:98305:-1:-1:98305:98306:98307 ++@@ -25,9 +25,9 @@ ++ 22:180225:-1:-1:180225:180226:180227 ++ 23:188417:-1:-1:188417:188418:188419 ++ 24:196609:-1:-1:196609:196610:196611 ++-25:204801:204801:204802-204804:204805:204806:204807 +++25:204801:204801:204802-204813:205063:205064:205065 ++ 26:212993:-1:-1:212993:212994:212995 ++-27:221185:221185:221186-221188:221189:221190:221191 +++27:221185:221185:221186-221197:221447:221448:221449 ++ 28:229377:-1:-1:229377:229378:229379 ++ 29:237569:-1:-1:237569:237570:237571 ++ 30:245761:-1:-1:245761:245762:245763 ++@@ -49,7 +49,7 @@ ++ 46:376833:-1:-1:376833:376834:376835 ++ 47:385025:-1:-1:385025:385026:385027 ++ 48:393217:-1:-1:393217:393218:393219 ++-49:401409:401409:401410-401412:401413:401414:401415 +++49:401409:401409:401410-401421:401671:401672:401673 ++ 50:409601:-1:-1:409601:409602:409603 ++ 51:417793:-1:-1:417793:417794:417795 ++ 52:425985:-1:-1:425985:425986:425987 ++@@ -81,7 +81,7 @@ ++ 78:638977:-1:-1:638977:638978:638979 ++ 79:647169:-1:-1:647169:647170:647171 ++ 80:655361:-1:-1:655361:655362:655363 ++-81:663553:663553:663554-663556:663557:663558:663559 +++81:663553:663553:663554-663565:663815:663816:663817 ++ 82:671745:-1:-1:671745:671746:671747 ++ 83:679937:-1:-1:679937:679938:679939 ++ 84:688129:-1:-1:688129:688130:688131 ++@@ -96,3 +96,291 @@ ++ 93:761857:-1:-1:761857:761858:761859 ++ 94:770049:-1:-1:770049:770050:770051 ++ 95:778241:-1:-1:778241:778242:778243 +++96:786433:-1:-1:786433:786434:786435 +++97:794625:-1:-1:794625:794626:794627 +++98:802817:-1:-1:802817:802818:802819 +++99:811009:-1:-1:811009:811010:811011 +++100:819201:-1:-1:819201:819202:819203 +++101:827393:-1:-1:827393:827394:827395 +++102:835585:-1:-1:835585:835586:835587 +++103:843777:-1:-1:843777:843778:843779 +++104:851969:-1:-1:851969:851970:851971 +++105:860161:-1:-1:860161:860162:860163 +++106:868353:-1:-1:868353:868354:868355 +++107:876545:-1:-1:876545:876546:876547 +++108:884737:-1:-1:884737:884738:884739 +++109:892929:-1:-1:892929:892930:892931 +++110:901121:-1:-1:901121:901122:901123 +++111:909313:-1:-1:909313:909314:909315 +++112:917505:-1:-1:917505:917506:917507 +++113:925697:-1:-1:925697:925698:925699 +++114:933889:-1:-1:933889:933890:933891 +++115:942081:-1:-1:942081:942082:942083 +++116:950273:-1:-1:950273:950274:950275 +++117:958465:-1:-1:958465:958466:958467 +++118:966657:-1:-1:966657:966658:966659 +++119:974849:-1:-1:974849:974850:974851 +++120:983041:-1:-1:983041:983042:983043 +++121:991233:-1:-1:991233:991234:991235 +++122:999425:-1:-1:999425:999426:999427 +++123:1007617:-1:-1:1007617:1007618:1007619 +++124:1015809:-1:-1:1015809:1015810:1015811 +++125:1024001:1024001:1024002-1024013:1024014:1024015:1024016 +++126:1032193:-1:-1:1032193:1032194:1032195 +++127:1040385:-1:-1:1040385:1040386:1040387 +++128:1048577:-1:-1:1048577:1048578:1048579 +++129:1056769:-1:-1:1056769:1056770:1056771 +++130:1064961:-1:-1:1064961:1064962:1064963 +++131:1073153:-1:-1:1073153:1073154:1073155 +++132:1081345:-1:-1:1081345:1081346:1081347 +++133:1089537:-1:-1:1089537:1089538:1089539 +++134:1097729:-1:-1:1097729:1097730:1097731 +++135:1105921:-1:-1:1105921:1105922:1105923 +++136:1114113:-1:-1:1114113:1114114:1114115 +++137:1122305:-1:-1:1122305:1122306:1122307 +++138:1130497:-1:-1:1130497:1130498:1130499 +++139:1138689:-1:-1:1138689:1138690:1138691 +++140:1146881:-1:-1:1146881:1146882:1146883 +++141:1155073:-1:-1:1155073:1155074:1155075 +++142:1163265:-1:-1:1163265:1163266:1163267 +++143:1171457:-1:-1:1171457:1171458:1171459 +++144:1179649:-1:-1:1179649:1179650:1179651 +++145:1187841:-1:-1:1187841:1187842:1187843 +++146:1196033:-1:-1:1196033:1196034:1196035 +++147:1204225:-1:-1:1204225:1204226:1204227 +++148:1212417:-1:-1:1212417:1212418:1212419 +++149:1220609:-1:-1:1220609:1220610:1220611 +++150:1228801:-1:-1:1228801:1228802:1228803 +++151:1236993:-1:-1:1236993:1236994:1236995 +++152:1245185:-1:-1:1245185:1245186:1245187 +++153:1253377:-1:-1:1253377:1253378:1253379 +++154:1261569:-1:-1:1261569:1261570:1261571 +++155:1269761:-1:-1:1269761:1269762:1269763 +++156:1277953:-1:-1:1277953:1277954:1277955 +++157:1286145:-1:-1:1286145:1286146:1286147 +++158:1294337:-1:-1:1294337:1294338:1294339 +++159:1302529:-1:-1:1302529:1302530:1302531 +++160:1310721:-1:-1:1310721:1310722:1310723 +++161:1318913:-1:-1:1318913:1318914:1318915 +++162:1327105:-1:-1:1327105:1327106:1327107 +++163:1335297:-1:-1:1335297:1335298:1335299 +++164:1343489:-1:-1:1343489:1343490:1343491 +++165:1351681:-1:-1:1351681:1351682:1351683 +++166:1359873:-1:-1:1359873:1359874:1359875 +++167:1368065:-1:-1:1368065:1368066:1368067 +++168:1376257:-1:-1:1376257:1376258:1376259 +++169:1384449:-1:-1:1384449:1384450:1384451 +++170:1392641:-1:-1:1392641:1392642:1392643 +++171:1400833:-1:-1:1400833:1400834:1400835 +++172:1409025:-1:-1:1409025:1409026:1409027 +++173:1417217:-1:-1:1417217:1417218:1417219 +++174:1425409:-1:-1:1425409:1425410:1425411 +++175:1433601:-1:-1:1433601:1433602:1433603 +++176:1441793:-1:-1:1441793:1441794:1441795 +++177:1449985:-1:-1:1449985:1449986:1449987 +++178:1458177:-1:-1:1458177:1458178:1458179 +++179:1466369:-1:-1:1466369:1466370:1466371 +++180:1474561:-1:-1:1474561:1474562:1474563 +++181:1482753:-1:-1:1482753:1482754:1482755 +++182:1490945:-1:-1:1490945:1490946:1490947 +++183:1499137:-1:-1:1499137:1499138:1499139 +++184:1507329:-1:-1:1507329:1507330:1507331 +++185:1515521:-1:-1:1515521:1515522:1515523 +++186:1523713:-1:-1:1523713:1523714:1523715 +++187:1531905:-1:-1:1531905:1531906:1531907 +++188:1540097:-1:-1:1540097:1540098:1540099 +++189:1548289:-1:-1:1548289:1548290:1548291 +++190:1556481:-1:-1:1556481:1556482:1556483 +++191:1564673:-1:-1:1564673:1564674:1564675 +++192:1572865:-1:-1:1572865:1572866:1572867 +++193:1581057:-1:-1:1581057:1581058:1581059 +++194:1589249:-1:-1:1589249:1589250:1589251 +++195:1597441:-1:-1:1597441:1597442:1597443 +++196:1605633:-1:-1:1605633:1605634:1605635 +++197:1613825:-1:-1:1613825:1613826:1613827 +++198:1622017:-1:-1:1622017:1622018:1622019 +++199:1630209:-1:-1:1630209:1630210:1630211 +++200:1638401:-1:-1:1638401:1638402:1638403 +++201:1646593:-1:-1:1646593:1646594:1646595 +++202:1654785:-1:-1:1654785:1654786:1654787 +++203:1662977:-1:-1:1662977:1662978:1662979 +++204:1671169:-1:-1:1671169:1671170:1671171 +++205:1679361:-1:-1:1679361:1679362:1679363 +++206:1687553:-1:-1:1687553:1687554:1687555 +++207:1695745:-1:-1:1695745:1695746:1695747 +++208:1703937:-1:-1:1703937:1703938:1703939 +++209:1712129:-1:-1:1712129:1712130:1712131 +++210:1720321:-1:-1:1720321:1720322:1720323 +++211:1728513:-1:-1:1728513:1728514:1728515 +++212:1736705:-1:-1:1736705:1736706:1736707 +++213:1744897:-1:-1:1744897:1744898:1744899 +++214:1753089:-1:-1:1753089:1753090:1753091 +++215:1761281:-1:-1:1761281:1761282:1761283 +++216:1769473:-1:-1:1769473:1769474:1769475 +++217:1777665:-1:-1:1777665:1777666:1777667 +++218:1785857:-1:-1:1785857:1785858:1785859 +++219:1794049:-1:-1:1794049:1794050:1794051 +++220:1802241:-1:-1:1802241:1802242:1802243 +++221:1810433:-1:-1:1810433:1810434:1810435 +++222:1818625:-1:-1:1818625:1818626:1818627 +++223:1826817:-1:-1:1826817:1826818:1826819 +++224:1835009:-1:-1:1835009:1835010:1835011 +++225:1843201:-1:-1:1843201:1843202:1843203 +++226:1851393:-1:-1:1851393:1851394:1851395 +++227:1859585:-1:-1:1859585:1859586:1859587 +++228:1867777:-1:-1:1867777:1867778:1867779 +++229:1875969:-1:-1:1875969:1875970:1875971 +++230:1884161:-1:-1:1884161:1884162:1884163 +++231:1892353:-1:-1:1892353:1892354:1892355 +++232:1900545:-1:-1:1900545:1900546:1900547 +++233:1908737:-1:-1:1908737:1908738:1908739 +++234:1916929:-1:-1:1916929:1916930:1916931 +++235:1925121:-1:-1:1925121:1925122:1925123 +++236:1933313:-1:-1:1933313:1933314:1933315 +++237:1941505:-1:-1:1941505:1941506:1941507 +++238:1949697:-1:-1:1949697:1949698:1949699 +++239:1957889:-1:-1:1957889:1957890:1957891 +++240:1966081:-1:-1:1966081:1966082:1966083 +++241:1974273:-1:-1:1974273:1974274:1974275 +++242:1982465:-1:-1:1982465:1982466:1982467 +++243:1990657:1990657:1990658-1990669:1990670:1990671:1990672 +++244:1998849:-1:-1:1998849:1998850:1998851 +++245:2007041:-1:-1:2007041:2007042:2007043 +++246:2015233:-1:-1:2015233:2015234:2015235 +++247:2023425:-1:-1:2023425:2023426:2023427 +++248:2031617:-1:-1:2031617:2031618:2031619 +++249:2039809:-1:-1:2039809:2039810:2039811 +++250:2048001:-1:-1:2048001:2048002:2048003 +++251:2056193:-1:-1:2056193:2056194:2056195 +++252:2064385:-1:-1:2064385:2064386:2064387 +++253:2072577:-1:-1:2072577:2072578:2072579 +++254:2080769:-1:-1:2080769:2080770:2080771 +++255:2088961:-1:-1:2088961:2088962:2088963 +++256:2097153:-1:-1:2097153:2097154:2097155 +++257:2105345:-1:-1:2105345:2105346:2105347 +++258:2113537:-1:-1:2113537:2113538:2113539 +++259:2121729:-1:-1:2121729:2121730:2121731 +++260:2129921:-1:-1:2129921:2129922:2129923 +++261:2138113:-1:-1:2138113:2138114:2138115 +++262:2146305:-1:-1:2146305:2146306:2146307 +++263:2154497:-1:-1:2154497:2154498:2154499 +++264:2162689:-1:-1:2162689:2162690:2162691 +++265:2170881:-1:-1:2170881:2170882:2170883 +++266:2179073:-1:-1:2179073:2179074:2179075 +++267:2187265:-1:-1:2187265:2187266:2187267 +++268:2195457:-1:-1:2195457:2195458:2195459 +++269:2203649:-1:-1:2203649:2203650:2203651 +++270:2211841:-1:-1:2211841:2211842:2211843 +++271:2220033:-1:-1:2220033:2220034:2220035 +++272:2228225:-1:-1:2228225:2228226:2228227 +++273:2236417:-1:-1:2236417:2236418:2236419 +++274:2244609:-1:-1:2244609:2244610:2244611 +++275:2252801:-1:-1:2252801:2252802:2252803 +++276:2260993:-1:-1:2260993:2260994:2260995 +++277:2269185:-1:-1:2269185:2269186:2269187 +++278:2277377:-1:-1:2277377:2277378:2277379 +++279:2285569:-1:-1:2285569:2285570:2285571 +++280:2293761:-1:-1:2293761:2293762:2293763 +++281:2301953:-1:-1:2301953:2301954:2301955 +++282:2310145:-1:-1:2310145:2310146:2310147 +++283:2318337:-1:-1:2318337:2318338:2318339 +++284:2326529:-1:-1:2326529:2326530:2326531 +++285:2334721:-1:-1:2334721:2334722:2334723 +++286:2342913:-1:-1:2342913:2342914:2342915 +++287:2351105:-1:-1:2351105:2351106:2351107 +++288:2359297:-1:-1:2359297:2359298:2359299 +++289:2367489:-1:-1:2367489:2367490:2367491 +++290:2375681:-1:-1:2375681:2375682:2375683 +++291:2383873:-1:-1:2383873:2383874:2383875 +++292:2392065:-1:-1:2392065:2392066:2392067 +++293:2400257:-1:-1:2400257:2400258:2400259 +++294:2408449:-1:-1:2408449:2408450:2408451 +++295:2416641:-1:-1:2416641:2416642:2416643 +++296:2424833:-1:-1:2424833:2424834:2424835 +++297:2433025:-1:-1:2433025:2433026:2433027 +++298:2441217:-1:-1:2441217:2441218:2441219 +++299:2449409:-1:-1:2449409:2449410:2449411 +++300:2457601:-1:-1:2457601:2457602:2457603 +++301:2465793:-1:-1:2465793:2465794:2465795 +++302:2473985:-1:-1:2473985:2473986:2473987 +++303:2482177:-1:-1:2482177:2482178:2482179 +++304:2490369:-1:-1:2490369:2490370:2490371 +++305:2498561:-1:-1:2498561:2498562:2498563 +++306:2506753:-1:-1:2506753:2506754:2506755 +++307:2514945:-1:-1:2514945:2514946:2514947 +++308:2523137:-1:-1:2523137:2523138:2523139 +++309:2531329:-1:-1:2531329:2531330:2531331 +++310:2539521:-1:-1:2539521:2539522:2539523 +++311:2547713:-1:-1:2547713:2547714:2547715 +++312:2555905:-1:-1:2555905:2555906:2555907 +++313:2564097:-1:-1:2564097:2564098:2564099 +++314:2572289:-1:-1:2572289:2572290:2572291 +++315:2580481:-1:-1:2580481:2580482:2580483 +++316:2588673:-1:-1:2588673:2588674:2588675 +++317:2596865:-1:-1:2596865:2596866:2596867 +++318:2605057:-1:-1:2605057:2605058:2605059 +++319:2613249:-1:-1:2613249:2613250:2613251 +++320:2621441:-1:-1:2621441:2621442:2621443 +++321:2629633:-1:-1:2629633:2629634:2629635 +++322:2637825:-1:-1:2637825:2637826:2637827 +++323:2646017:-1:-1:2646017:2646018:2646019 +++324:2654209:-1:-1:2654209:2654210:2654211 +++325:2662401:-1:-1:2662401:2662402:2662403 +++326:2670593:-1:-1:2670593:2670594:2670595 +++327:2678785:-1:-1:2678785:2678786:2678787 +++328:2686977:-1:-1:2686977:2686978:2686979 +++329:2695169:-1:-1:2695169:2695170:2695171 +++330:2703361:-1:-1:2703361:2703362:2703363 +++331:2711553:-1:-1:2711553:2711554:2711555 +++332:2719745:-1:-1:2719745:2719746:2719747 +++333:2727937:-1:-1:2727937:2727938:2727939 +++334:2736129:-1:-1:2736129:2736130:2736131 +++335:2744321:-1:-1:2744321:2744322:2744323 +++336:2752513:-1:-1:2752513:2752514:2752515 +++337:2760705:-1:-1:2760705:2760706:2760707 +++338:2768897:-1:-1:2768897:2768898:2768899 +++339:2777089:-1:-1:2777089:2777090:2777091 +++340:2785281:-1:-1:2785281:2785282:2785283 +++341:2793473:-1:-1:2793473:2793474:2793475 +++342:2801665:-1:-1:2801665:2801666:2801667 +++343:2809857:2809857:2809858-2809869:2809870:2809871:2809872 +++344:2818049:-1:-1:2818049:2818050:2818051 +++345:2826241:-1:-1:2826241:2826242:2826243 +++346:2834433:-1:-1:2834433:2834434:2834435 +++347:2842625:-1:-1:2842625:2842626:2842627 +++348:2850817:-1:-1:2850817:2850818:2850819 +++349:2859009:-1:-1:2859009:2859010:2859011 +++350:2867201:-1:-1:2867201:2867202:2867203 +++351:2875393:-1:-1:2875393:2875394:2875395 +++352:2883585:-1:-1:2883585:2883586:2883587 +++353:2891777:-1:-1:2891777:2891778:2891779 +++354:2899969:-1:-1:2899969:2899970:2899971 +++355:2908161:-1:-1:2908161:2908162:2908163 +++356:2916353:-1:-1:2916353:2916354:2916355 +++357:2924545:-1:-1:2924545:2924546:2924547 +++358:2932737:-1:-1:2932737:2932738:2932739 +++359:2940929:-1:-1:2940929:2940930:2940931 +++360:2949121:-1:-1:2949121:2949122:2949123 +++361:2957313:-1:-1:2957313:2957314:2957315 +++362:2965505:-1:-1:2965505:2965506:2965507 +++363:2973697:-1:-1:2973697:2973698:2973699 +++364:2981889:-1:-1:2981889:2981890:2981891 +++365:2990081:-1:-1:2990081:2990082:2990083 +++366:2998273:-1:-1:2998273:2998274:2998275 +++367:3006465:-1:-1:3006465:3006466:3006467 +++368:3014657:-1:-1:3014657:3014658:3014659 +++369:3022849:-1:-1:3022849:3022850:3022851 +++370:3031041:-1:-1:3031041:3031042:3031043 +++371:3039233:-1:-1:3039233:3039234:3039235 +++372:3047425:-1:-1:3047425:3047426:3047427 +++373:3055617:-1:-1:3055617:3055618:3055619 +++374:3063809:-1:-1:3063809:3063810:3063811 +++375:3072001:-1:-1:3072001:3072002:3072003 +++376:3080193:-1:-1:3080193:3080194:3080195 +++377:3088385:-1:-1:3088385:3088386:3088387 +++378:3096577:-1:-1:3096577:3096578:3096579 +++379:3104769:-1:-1:3104769:3104770:3104771 +++380:3112961:-1:-1:3112961:3112962:3112963 +++381:3121153:-1:-1:3121153:3121154:3121155 +++382:3129345:-1:-1:3129345:3129346:3129347 +++383:3137537:-1:-1:3137537:3137538:3137539 ++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 ++ ++Exit status is 0 +--- /dev/null ++++ b/tests/r_expand_full/name +@@ -0,0 +1 @@ ++expand a totally full filesystem +--- /dev/null ++++ b/tests/r_expand_full/script +@@ -0,0 +1,79 @@ ++if test -x $RESIZE2FS_EXE -a -x $DEBUGFS_EXE; then ++ ++FSCK_OPT=-fn ++OUT=$test_name.log ++EXP=$test_dir/expect ++CONF=$TMPFILE.conf ++ ++#gzip -d < $EXP.gz > $EXP ++ ++cat > $CONF << ENDL ++[fs_types] ++ ext4h = { ++ features = has_journal,extent,huge_file,uninit_bg,dir_nlink,extra_isize,sparse_super,filetype,dir_index,ext_attr,^resize_inode,^meta_bg,^flex_bg ++ blocksize = 1024 ++ inode_size = 256 ++ make_hugefiles = true ++ hugefiles_dir = / ++ hugefiles_slack = 0 ++ hugefiles_name = aaaaa ++ hugefiles_digits = 4 ++ hugefiles_size = 1M ++ zero_hugefiles = false ++ } ++ENDL ++ ++echo "resize2fs test" > $OUT ++ ++MKE2FS_CONFIG=$CONF $MKE2FS -F -T ext4h $TMPFILE 786432 >> $OUT 2>&1 ++rm -rf $CONF ++ ++# dump and check ++$DUMPE2FS -g $TMPFILE 2>&1 >> $OUT.before 2> /dev/null ++$FSCK $FSCK_OPT -N test_filesys $TMPFILE >> $OUT 2>&1 ++status=$? ++echo Exit status is $status >> $OUT ++ ++# convert it ++echo "resize2fs test.img" >> $OUT ++dd if=/dev/zero of=$TMPFILE conv=notrunc bs=1 count=1 seek=3221225471 2> /dev/null ++$RESIZE2FS -f $TMPFILE 2>&1 >> $OUT 2>&1 ++status=$? ++echo Exit status is $status >> $OUT ++ ++# dump and check ++$DUMPE2FS -g $TMPFILE 2>&1 >> $OUT.after 2> /dev/null ++echo "Change in FS metadata:" >> $OUT ++diff -u $OUT.before $OUT.after | tail -n +3 >> $OUT ++$FSCK $FSCK_OPT -N test_filesys $TMPFILE >> $OUT 2>&1 ++status=$? ++echo Exit status is $status >> $OUT ++ ++rm $TMPFILE ++ ++# ++# Do the verification ++# ++ ++sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" -e 's/test_filesys:.*//g' < $OUT > $OUT.new ++mv $OUT.new $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 ++ ++rm $OUT.before $OUT.after ++ ++unset IMAGE FSCK_OPT OUT EXP CONF ++ ++else #if test -x $RESIZE2FS_EXE -a -x $DEBUGFS_EXE; then ++ echo "$test_name: $test_description: skipped" ++fi ++ +--- /dev/null ++++ b/tests/r_fixup_lastbg/expect +@@ -0,0 +1,39 @@ ++Creating filesystem with 20000 1k blocks and 1248 inodes ++Superblock backups stored on blocks: ++ 8193 ++ ++Allocating group tables: done ++Writing inode tables: done ++Creating journal (1024 blocks): done ++Writing superblocks and filesystem accounting information: done ++ ++Group 2: (Blocks 16385-19999) [INODE_UNINIT, ITABLE_ZEROED] ++ Block bitmap at 83 (bg #0 + 82) ++ Inode bitmap at 86 (bg #0 + 85) ++ Inode table at 295-398 (bg #0 + 294) ++ 3615 free blocks, 416 free inodes, 0 directories, 416 unused inodes ++ Free blocks: 16385-19999 ++ Free inodes: 833-1248 ++Group 2: (Blocks 16385-19999) ++ Block bitmap at 83 (bg #0 + 82) ++ Inode bitmap at 86 (bg #0 + 85) ++ Inode table at 295-398 (bg #0 + 294) ++ 3615 free blocks, 416 free inodes, 0 directories ++ Free blocks: 16385-19999 ++ Free inodes: 833-1248 ++Resizing the filesystem on test.img to 20004 (1k) blocks. ++The filesystem on test.img is now 20004 (1k) blocks long. ++ ++Group 2: (Blocks 16385-20003) [INODE_UNINIT] ++ Block bitmap at 83 (bg #0 + 82) ++ Inode bitmap at 86 (bg #0 + 85) ++ Inode table at 295-398 (bg #0 + 294) ++ 3619 free blocks, 416 free inodes, 0 directories, 416 unused inodes ++ Free blocks: 16385-20003 ++ Free inodes: 833-1248 ++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.img: 11/1248 files (0.0% non-contiguous), 1517/20004 blocks +--- /dev/null ++++ b/tests/r_fixup_lastbg/script +@@ -0,0 +1,37 @@ ++if test -x $RESIZE2FS_EXE -a -x $DEBUGFS_EXE; then ++test_description="fix up last bg when expanding within the last bg" ++ ++EXP=$test_dir/expect ++OUT=$test_name.out ++LOG=$test_name.log ++E2FSCK=../e2fsck/e2fsck ++ ++$MKE2FS -T ext4 -b 1024 -F -U 56d3ee50-8532-4f29-8181-d7c6ea4a94a6 $TMPFILE 20000 > $OUT 2>&1 ++$DUMPE2FS $TMPFILE 2>&1 | grep -A10 '^Group 2:' >> $OUT ++$DEBUGFS -R "set_bg 2 itable_unused 0" -w $TMPFILE > /dev/null 2>&1 ++$DEBUGFS -R "set_bg 2 flags 0" -w $TMPFILE > /dev/null 2>&1 ++$DEBUGFS -R "set_bg 2 checksum 0xd318" -w $TMPFILE > /dev/null 2>&1 ++$DUMPE2FS $TMPFILE 2>&1 | grep -A10 '^Group 2:' >> $OUT ++#dd if=/dev/zero of=$TMPFILE bs=1 count=1 seek=$((1024 * 20004)) conv=notrunc >> $OUT 2> /dev/null ++$RESIZE2FS_EXE -f -p $TMPFILE 20004 >> $OUT 2>&1 ++$DUMPE2FS $TMPFILE 2>&1 | grep -A10 '^Group 2:' >> $OUT ++$E2FSCK -fy $TMPFILE >> $OUT 2>&1 ++ ++sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" < $OUT > $LOG ++rm -rf $OUT ++ ++cmp -s $LOG $EXP ++RC=$? ++if [ $RC -eq 0 ]; then ++ echo "$test_name: $test_description: ok" ++ touch $test_name.ok ++else ++ echo "$test_name: $test_description: failed" ++ diff -u $EXP $LOG > $test_name.failed ++fi ++ ++unset EXP LOG OUT E2FSCK ++ ++else #if test -x $RESIZE2FS_EXE -a -x $DEBUGFS_EXE; then ++ echo "$test_name: $test_description: skipped" ++fi +--- /dev/null ++++ b/tests/r_fixup_lastbg_big/expect +@@ -0,0 +1,45 @@ ++Creating filesystem with 20000 1k blocks and 1248 inodes ++Superblock backups stored on blocks: ++ 8193 ++ ++Allocating group tables: done ++Writing inode tables: done ++Creating journal (1024 blocks): done ++Writing superblocks and filesystem accounting information: done ++ ++Group 2: (Blocks 16385-19999) [INODE_UNINIT, ITABLE_ZEROED] ++ Block bitmap at 83 (bg #0 + 82) ++ Inode bitmap at 86 (bg #0 + 85) ++ Inode table at 295-398 (bg #0 + 294) ++ 3615 free blocks, 416 free inodes, 0 directories, 416 unused inodes ++ Free blocks: 16385-19999 ++ Free inodes: 833-1248 ++Group 2: (Blocks 16385-19999) ++ Block bitmap at 83 (bg #0 + 82) ++ Inode bitmap at 86 (bg #0 + 85) ++ Inode table at 295-398 (bg #0 + 294) ++ 3615 free blocks, 416 free inodes, 0 directories ++ Free blocks: 16385-19999 ++ Free inodes: 833-1248 ++Resizing the filesystem on test.img to 40000 (1k) blocks. ++Begin pass 1 (max = 2) ++Extending the inode table ----------------------------------------XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX ++The filesystem on test.img is now 40000 (1k) blocks long. ++ ++Group 2: (Blocks 16385-24576) [INODE_UNINIT, BLOCK_UNINIT] ++ Block bitmap at 83 (bg #0 + 82) ++ Inode bitmap at 86 (bg #0 + 85) ++ Inode table at 295-398 (bg #0 + 294) ++ 8192 free blocks, 416 free inodes, 0 directories, 416 unused inodes ++ Free blocks: 16385-24576 ++ Free inodes: 833-1248 ++Group 3: (Blocks 24577-32768) [INODE_UNINIT, ITABLE_ZEROED] ++ Backup superblock at 24577, Group descriptors at 24578-24578 ++ Reserved GDT blocks at 24579-24656 ++ Block bitmap at 413 (bg #0 + 412) ++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.img: 11/2080 files (0.0% non-contiguous), 1809/40000 blocks +--- /dev/null ++++ b/tests/r_fixup_lastbg_big/script +@@ -0,0 +1,37 @@ ++if test -x $RESIZE2FS_EXE -a -x $DEBUGFS_EXE; then ++test_description="fix up last bg when expanding beyond the last bg" ++ ++EXP=$test_dir/expect ++OUT=$test_name.out ++LOG=$test_name.log ++E2FSCK=../e2fsck/e2fsck ++ ++$MKE2FS -T ext4 -b 1024 -F -U 56d3ee50-8532-4f29-8181-d7c6ea4a94a6 $TMPFILE 20000 > $OUT 2>&1 ++$DUMPE2FS $TMPFILE 2>&1 | grep -A10 '^Group 2:' >> $OUT ++$DEBUGFS -R "set_bg 2 itable_unused 0" -w $TMPFILE > /dev/null 2>&1 ++$DEBUGFS -R "set_bg 2 flags 0" -w $TMPFILE > /dev/null 2>&1 ++$DEBUGFS -R "set_bg 2 checksum 0xd318" -w $TMPFILE > /dev/null 2>&1 ++$DUMPE2FS $TMPFILE 2>&1 | grep -A10 '^Group 2:' >> $OUT ++dd if=/dev/zero of=$TMPFILE bs=1 count=1 seek=$((1024 * 40000)) conv=notrunc >> $OUT 2> /dev/null ++RESIZE2FS_FORCE_ITABLE_INIT=1 $RESIZE2FS_EXE -f -p $TMPFILE >> $OUT 2>&1 ++$DUMPE2FS $TMPFILE 2>&1 | grep -A10 '^Group 2:' >> $OUT ++$E2FSCK -fy $TMPFILE >> $OUT 2>&1 ++ ++sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" < $OUT > $LOG ++rm -rf $OUT ++ ++cmp -s $LOG $EXP ++RC=$? ++if [ $RC -eq 0 ]; then ++ echo "$test_name: $test_description: ok" ++ touch $test_name.ok ++else ++ echo "$test_name: $test_description: failed" ++ diff -u $EXP $LOG > $test_name.failed ++fi ++ ++unset EXP LOG OUT E2FSCK ++ ++else #if test -x $RESIZE2FS_EXE -a -x $DEBUGFS_EXE; then ++ echo "$test_name: $test_description: skipped" ++fi +--- a/tests/r_inline_xattr/expect ++++ b/tests/r_inline_xattr/expect +@@ -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 @@ + 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 +--- a/tests/r_move_itable/script ++++ b/tests/r_move_itable/script +@@ -33,7 +33,7 @@ + $TUNE2FS -c 20 -U clear $TMPFILE >/dev/null 2>&1 + + echo dumpe2fs test.img >> $OUT +-$DUMPE2FS $TMPFILE 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT ++$DUMPE2FS $TMPFILE 2>&1 | sed -f $cmd_dir/filter.sed -e '/Block bitmap.*$/N;s/\n Inode bitmap/, Inode bitmap/g' >> $OUT + + echo "--------------------------------" >> $OUT + +@@ -53,7 +53,7 @@ + $TUNE2FS -c 20 -U clear $TMPFILE >/dev/null 2>&1 + + echo dumpe2fs test.img >> $OUT +-$DUMPE2FS $TMPFILE 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT ++$DUMPE2FS $TMPFILE 2>&1 | sed -f $cmd_dir/filter.sed -e '/Block bitmap.*$/N;s/\n Inode bitmap/, Inode bitmap/g' >> $OUT + + echo "--------------------------------" >> $OUT + +@@ -73,7 +73,7 @@ + $TUNE2FS -c 20 -U clear $TMPFILE >/dev/null 2>&1 + + echo dumpe2fs test.img >> $OUT +-$DUMPE2FS $TMPFILE 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT ++$DUMPE2FS $TMPFILE 2>&1 | sed -f $cmd_dir/filter.sed -e '/Block bitmap.*$/N;s/\n Inode bitmap/, Inode bitmap/g' >> $OUT + + echo "--------------------------------" >> $OUT + +@@ -93,7 +93,7 @@ + $TUNE2FS -c 20 -U clear $TMPFILE >/dev/null 2>&1 + + echo dumpe2fs test.img >> $OUT +-$DUMPE2FS $TMPFILE 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT ++$DUMPE2FS $TMPFILE 2>&1 | sed -f $cmd_dir/filter.sed -e '/Block bitmap.*$/N;s/\n Inode bitmap/, Inode bitmap/g' >> $OUT + + rm -f $TMPFILE + +--- a/tests/r_resize_inode/script ++++ b/tests/r_resize_inode/script +@@ -33,7 +33,7 @@ + $TUNE2FS -c 20 -U clear $TMPFILE >/dev/null 2>&1 + + echo dumpe2fs test.img >> $OUT +-$DUMPE2FS $TMPFILE 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT ++$DUMPE2FS $TMPFILE 2>&1 | sed -f $cmd_dir/filter.sed -e '/Block bitmap.*$/N;s/\n Inode bitmap/, Inode bitmap/g' >> $OUT + + echo "--------------------------------" >> $OUT + +@@ -59,7 +59,7 @@ + $TUNE2FS -c 20 -U clear $TMPFILE >/dev/null 2>&1 + + echo dumpe2fs test.img >> $OUT +-$DUMPE2FS $TMPFILE 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT ++$DUMPE2FS $TMPFILE 2>&1 | sed -f $cmd_dir/filter.sed -e '/Block bitmap.*$/N;s/\n Inode bitmap/, Inode bitmap/g' >> $OUT + + echo "--------------------------------" >> $OUT + +@@ -79,7 +79,7 @@ + $TUNE2FS -c 20 -U clear $TMPFILE >/dev/null 2>&1 + + echo dumpe2fs test.img >> $OUT +-$DUMPE2FS $TMPFILE 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT ++$DUMPE2FS $TMPFILE 2>&1 | sed -f $cmd_dir/filter.sed -e '/Block bitmap.*$/N;s/\n Inode bitmap/, Inode bitmap/g' >> $OUT + + rm -f $TMPFILE + cmp -s $OUT $EXP +--- a/tests/scripts/resize_test ++++ b/tests/scripts/resize_test +@@ -67,7 +67,7 @@ + echo $FSCK -fy $TMPFILE >> $LOG 2>&1 + if ! $FSCK -fy $TMPFILE >> $LOG 2>&1 + then +- dumpe2fs $TMPFILE >> $LOG ++ $DUMPE2FS $TMPFILE >> $LOG + return 1 + fi + +@@ -97,7 +97,7 @@ + echo $FSCK -fy $TMPFILE >> $LOG 2>&1 + if ! $FSCK -fy $TMPFILE >> $LOG 2>&1 + then +- dumpe2fs $TMPFILE >> $LOG ++ $DUMPE2FS $TMPFILE >> $LOG + return 1 + fi + +@@ -122,7 +122,7 @@ + echo $FSCK -fy $TMPFILE >> $LOG 2>&1 + if ! $FSCK -fy $TMPFILE >> $LOG 2>&1 + then +- dumpe2fs $TMPFILE >> $LOG ++ $DUMPE2FS $TMPFILE >> $LOG + return 1 + fi + +@@ -147,7 +147,7 @@ + echo $FSCK -fy $TMPFILE >> $LOG 2>&1 + if ! $FSCK -fy $TMPFILE >> $LOG 2>&1 + then +- dumpe2fs $TMPFILE >> $LOG ++ $DUMPE2FS $TMPFILE >> $LOG + return 1 + fi + +--- /dev/null ++++ b/tests/t_disable_mcsum/expect +@@ -0,0 +1,45 @@ ++tune2fs ^metadata_csum test ++Creating filesystem with 524288 1k blocks and 65536 inodes ++Superblock backups stored on blocks: ++ 8193, 24577, 40961, 57345, 73729, 204801, 221185, 401409 ++ ++Allocating group tables: done ++Writing inode tables: done ++Creating journal (16384 blocks): done ++Creating 477 huge file(s) with 1024 blocks each: done ++Writing superblocks and filesystem accounting information: done ++ ++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 ++ ++Exit status is 0 ++tune2fs -O ^metadata_csum test.img ++Exit status is 0 ++Change in FS metadata: ++@@ -2,7 +2,7 @@ ++ Last mounted on: ++ Filesystem magic number: 0xEF53 ++ Filesystem revision #: 1 (dynamic) ++-Filesystem features: has_journal ext_attr resize_inode dir_index filetype extent 64bit flex_bg sparse_super large_file huge_file dir_nlink extra_isize metadata_csum +++Filesystem features: has_journal ext_attr resize_inode dir_index filetype extent 64bit flex_bg sparse_super large_file huge_file uninit_bg dir_nlink extra_isize ++ Default mount options: user_xattr acl ++ Filesystem state: clean ++ Errors behavior: Continue ++@@ -33,7 +33,6 @@ ++ Journal inode: 8 ++ Default directory hash: half_md4 ++ Journal backup: inode blocks ++-Checksum type: crc32c ++ Journal features: (none) ++ Journal size: 16M ++ Journal length: 16384 ++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 ++ ++Exit status is 0 +--- /dev/null ++++ b/tests/t_disable_mcsum/name +@@ -0,0 +1 @@ ++disable metadata_csum +--- /dev/null ++++ b/tests/t_disable_mcsum/script +@@ -0,0 +1,67 @@ ++FSCK_OPT=-fn ++OUT=$test_name.log ++EXP=$test_dir/expect ++CONF=$TMPFILE.conf ++ ++cat > $CONF << ENDL ++[fs_types] ++ ext4h = { ++ features = has_journal,extent,huge_file,flex_bg,uninit_bg,dir_nlink,extra_isize,sparse_super,filetype,dir_index,ext_attr,resize_inode,64bit,metadata_csum ++ blocksize = 1024 ++ inode_size = 256 ++ make_hugefiles = true ++ hugefiles_dir = / ++ hugefiles_slack = 0 ++ hugefiles_name = aaaaa ++ hugefiles_digits = 4 ++ hugefiles_size = 1M ++ zero_hugefiles = false ++ } ++ENDL ++ ++echo "tune2fs ^metadata_csum test" > $OUT ++ ++MKE2FS_CONFIG=$CONF $MKE2FS -F -T ext4h $TMPFILE 524288 >> $OUT 2>&1 ++rm -rf $CONF ++ ++# dump and check ++$DUMPE2FS $TMPFILE 2> /dev/null | grep '^Group 0:' -B99 -A20 | sed -f $cmd_dir/filter.sed > $OUT.before ++$FSCK $FSCK_OPT -N test_filesys $TMPFILE >> $OUT 2>&1 ++status=$? ++echo Exit status is $status >> $OUT ++ ++# remove mcsum ++echo "tune2fs -O ^metadata_csum test.img" >> $OUT ++$TUNE2FS -O ^metadata_csum $TMPFILE >> $OUT 2>&1 ++status=$? ++echo Exit status is $status >> $OUT ++ ++# dump and check ++$DUMPE2FS $TMPFILE 2> /dev/null | grep '^Group 0:' -B99 -A20 | sed -f $cmd_dir/filter.sed > $OUT.after ++echo "Change in FS metadata:" >> $OUT ++diff -u $OUT.before $OUT.after | tail -n +3 >> $OUT ++$FSCK $FSCK_OPT -N test_filesys $TMPFILE >> $OUT 2>&1 ++status=$? ++echo Exit status is $status >> $OUT ++ ++rm $TMPFILE $OUT.before $OUT.after ++ ++# ++# Do the verification ++# ++ ++sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" -e 's/test_filesys:.*//g' < $OUT > $OUT.new ++mv $OUT.new $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 IMAGE FSCK_OPT OUT EXP CONF +--- /dev/null ++++ b/tests/t_disable_mcsum_noinitbg/expect +@@ -0,0 +1,68 @@ ++tune2fs ^metadata_csum test ++Creating filesystem with 524288 1k blocks and 65536 inodes ++Superblock backups stored on blocks: ++ 8193, 24577, 40961, 57345, 73729, 204801, 221185, 401409 ++ ++Allocating group tables: done ++Writing inode tables: done ++Creating journal (16384 blocks): done ++Creating 477 huge file(s) with 1024 blocks each: done ++Writing superblocks and filesystem accounting information: done ++ ++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 ++ ++Exit status is 0 ++tune2fs -O ^metadata_csum,^uninit_bg test.img ++Exit status is 0 ++Change in FS metadata: ++@@ -2,7 +2,7 @@ ++ Last mounted on: ++ Filesystem magic number: 0xEF53 ++ Filesystem revision #: 1 (dynamic) ++-Filesystem features: has_journal ext_attr resize_inode dir_index filetype extent 64bit flex_bg sparse_super large_file huge_file dir_nlink extra_isize metadata_csum +++Filesystem features: has_journal ext_attr resize_inode dir_index filetype extent 64bit flex_bg sparse_super large_file huge_file dir_nlink extra_isize ++ Default mount options: user_xattr acl ++ Filesystem state: clean ++ Errors behavior: Continue ++@@ -33,7 +33,6 @@ ++ Journal inode: 8 ++ Default directory hash: half_md4 ++ Journal backup: inode blocks ++-Checksum type: crc32c ++ Journal features: (none) ++ Journal size: 16M ++ Journal length: 16384 ++@@ -47,18 +46,18 @@ ++ Block bitmap at 262 (+261) ++ Inode bitmap at 278 (+277) ++ Inode table at 294-549 (+293) ++- 21 free blocks, 536 free inodes, 2 directories, 536 unused inodes +++ 21 free blocks, 536 free inodes, 2 directories ++ Free blocks: 4413-4433 ++ Free inodes: 489-1024 ++-Group 1: (Blocks 8193-16384) [INODE_UNINIT] +++Group 1: (Blocks 8193-16384) ++ Backup superblock at 8193, Group descriptors at 8194-8197 ++ Reserved GDT blocks at 8198-8453 ++ Block bitmap at 263 (bg #0 + 262) ++ Inode bitmap at 279 (bg #0 + 278) ++ Inode table at 550-805 (bg #0 + 549) ++- 0 free blocks, 1024 free inodes, 0 directories, 1024 unused inodes +++ 0 free blocks, 1024 free inodes, 0 directories ++ Free blocks: ++ Free inodes: 1025-2048 ++-Group 2: (Blocks 16385-24576) [INODE_UNINIT] +++Group 2: (Blocks 16385-24576) ++ Block bitmap at 264 (bg #0 + 263) ++ Inode bitmap at 280 (bg #0 + 279) ++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 ++ ++Exit status is 0 +--- /dev/null ++++ b/tests/t_disable_mcsum_noinitbg/name +@@ -0,0 +1 @@ ++disable metadata_csum and uninit_bg +--- /dev/null ++++ b/tests/t_disable_mcsum_noinitbg/script +@@ -0,0 +1,67 @@ ++FSCK_OPT=-fn ++OUT=$test_name.log ++EXP=$test_dir/expect ++CONF=$TMPFILE.conf ++ ++cat > $CONF << ENDL ++[fs_types] ++ ext4h = { ++ features = has_journal,extent,huge_file,flex_bg,uninit_bg,dir_nlink,extra_isize,sparse_super,filetype,dir_index,ext_attr,resize_inode,64bit,metadata_csum ++ blocksize = 1024 ++ inode_size = 256 ++ make_hugefiles = true ++ hugefiles_dir = / ++ hugefiles_slack = 0 ++ hugefiles_name = aaaaa ++ hugefiles_digits = 4 ++ hugefiles_size = 1M ++ zero_hugefiles = false ++ } ++ENDL ++ ++echo "tune2fs ^metadata_csum test" > $OUT ++ ++MKE2FS_CONFIG=$CONF $MKE2FS -F -T ext4h $TMPFILE 524288 >> $OUT 2>&1 ++rm -rf $CONF ++ ++# dump and check ++$DUMPE2FS $TMPFILE 2> /dev/null | grep '^Group 0:' -B99 -A20 | sed -f $cmd_dir/filter.sed > $OUT.before ++$FSCK $FSCK_OPT -N test_filesys $TMPFILE >> $OUT 2>&1 ++status=$? ++echo Exit status is $status >> $OUT ++ ++# remove mcsum ++echo "tune2fs -O ^metadata_csum,^uninit_bg test.img" >> $OUT ++$TUNE2FS -O ^metadata_csum,^uninit_bg $TMPFILE >> $OUT 2>&1 ++status=$? ++echo Exit status is $status >> $OUT ++ ++# dump and check ++$DUMPE2FS $TMPFILE 2> /dev/null | grep '^Group 0:' -B99 -A20 | sed -f $cmd_dir/filter.sed > $OUT.after ++echo "Change in FS metadata:" >> $OUT ++diff -u $OUT.before $OUT.after | tail -n +3 >> $OUT ++$FSCK $FSCK_OPT -N test_filesys $TMPFILE >> $OUT 2>&1 ++status=$? ++echo Exit status is $status >> $OUT ++ ++rm $TMPFILE $OUT.before $OUT.after ++ ++# ++# Do the verification ++# ++ ++sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" -e 's/test_filesys:.*//g' < $OUT > $OUT.new ++mv $OUT.new $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 IMAGE FSCK_OPT OUT EXP CONF +--- /dev/null ++++ b/tests/t_disable_mcsum_yesinitbg/expect +@@ -0,0 +1,45 @@ ++tune2fs ^metadata_csum test ++Creating filesystem with 524288 1k blocks and 65536 inodes ++Superblock backups stored on blocks: ++ 8193, 24577, 40961, 57345, 73729, 204801, 221185, 401409 ++ ++Allocating group tables: done ++Writing inode tables: done ++Creating journal (16384 blocks): done ++Creating 477 huge file(s) with 1024 blocks each: done ++Writing superblocks and filesystem accounting information: done ++ ++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 ++ ++Exit status is 0 ++tune2fs -O ^metadata_csum,uninit_bg test.img ++Exit status is 0 ++Change in FS metadata: ++@@ -2,7 +2,7 @@ ++ Last mounted on: ++ Filesystem magic number: 0xEF53 ++ Filesystem revision #: 1 (dynamic) ++-Filesystem features: has_journal ext_attr resize_inode dir_index filetype extent 64bit flex_bg sparse_super large_file huge_file dir_nlink extra_isize metadata_csum +++Filesystem features: has_journal ext_attr resize_inode dir_index filetype extent 64bit flex_bg sparse_super large_file huge_file uninit_bg dir_nlink extra_isize ++ Default mount options: user_xattr acl ++ Filesystem state: clean ++ Errors behavior: Continue ++@@ -33,7 +33,6 @@ ++ Journal inode: 8 ++ Default directory hash: half_md4 ++ Journal backup: inode blocks ++-Checksum type: crc32c ++ Journal features: (none) ++ Journal size: 16M ++ Journal length: 16384 ++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 ++ ++Exit status is 0 +--- /dev/null ++++ b/tests/t_disable_mcsum_yesinitbg/name +@@ -0,0 +1 @@ ++disable metadata_csum and enable uninit_bg +--- /dev/null ++++ b/tests/t_disable_mcsum_yesinitbg/script +@@ -0,0 +1,67 @@ ++FSCK_OPT=-fn ++OUT=$test_name.log ++EXP=$test_dir/expect ++CONF=$TMPFILE.conf ++ ++cat > $CONF << ENDL ++[fs_types] ++ ext4h = { ++ features = has_journal,extent,huge_file,flex_bg,uninit_bg,dir_nlink,extra_isize,sparse_super,filetype,dir_index,ext_attr,resize_inode,64bit,metadata_csum ++ blocksize = 1024 ++ inode_size = 256 ++ make_hugefiles = true ++ hugefiles_dir = / ++ hugefiles_slack = 0 ++ hugefiles_name = aaaaa ++ hugefiles_digits = 4 ++ hugefiles_size = 1M ++ zero_hugefiles = false ++ } ++ENDL ++ ++echo "tune2fs ^metadata_csum test" > $OUT ++ ++MKE2FS_CONFIG=$CONF $MKE2FS -F -T ext4h $TMPFILE 524288 >> $OUT 2>&1 ++rm -rf $CONF ++ ++# dump and check ++$DUMPE2FS $TMPFILE 2> /dev/null | grep '^Group 0:' -B99 -A20 | sed -f $cmd_dir/filter.sed > $OUT.before ++$FSCK $FSCK_OPT -N test_filesys $TMPFILE >> $OUT 2>&1 ++status=$? ++echo Exit status is $status >> $OUT ++ ++# remove mcsum ++echo "tune2fs -O ^metadata_csum,uninit_bg test.img" >> $OUT ++$TUNE2FS -O ^metadata_csum,uninit_bg $TMPFILE >> $OUT 2>&1 ++status=$? ++echo Exit status is $status >> $OUT ++ ++# dump and check ++$DUMPE2FS $TMPFILE 2> /dev/null | grep '^Group 0:' -B99 -A20 | sed -f $cmd_dir/filter.sed > $OUT.after ++echo "Change in FS metadata:" >> $OUT ++diff -u $OUT.before $OUT.after | tail -n +3 >> $OUT ++$FSCK $FSCK_OPT -N test_filesys $TMPFILE >> $OUT 2>&1 ++status=$? ++echo Exit status is $status >> $OUT ++ ++rm $TMPFILE $OUT.before $OUT.after ++ ++# ++# Do the verification ++# ++ ++sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" -e 's/test_filesys:.*//g' < $OUT > $OUT.new ++mv $OUT.new $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 IMAGE FSCK_OPT OUT EXP CONF +--- /dev/null ++++ b/tests/t_enable_mcsum/expect +@@ -0,0 +1,78 @@ ++tune2fs metadata_csum test ++Creating filesystem with 524288 1k blocks and 65536 inodes ++Superblock backups stored on blocks: ++ 8193, 24577, 40961, 57345, 73729, 204801, 221185, 401409 ++ ++Allocating group tables: done ++Writing inode tables: done ++Creating journal (16384 blocks): done ++Creating 477 huge file(s) with 1024 blocks each: done ++Writing superblocks and filesystem accounting information: done ++ ++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 ++ ++Exit status is 0 ++tune2fs -O metadata_csum test.img ++ ++Please run e2fsck -D on the filesystem. ++ ++Exit status is 0 ++test_filesys was not cleanly unmounted, check forced. ++Pass 1: Checking inodes, blocks, and sizes ++Pass 2: Checking directory structure ++Pass 3: Checking directory connectivity ++Pass 3A: Optimizing directories ++Pass 4: Checking reference counts ++Pass 5: Checking group summary information ++ ++ ++ ++Change in FS metadata: ++@@ -2,7 +2,7 @@ ++ Last mounted on: ++ Filesystem magic number: 0xEF53 ++ Filesystem revision #: 1 (dynamic) ++-Filesystem features: has_journal ext_attr resize_inode dir_index filetype extent 64bit flex_bg sparse_super large_file huge_file uninit_bg dir_nlink extra_isize +++Filesystem features: has_journal ext_attr resize_inode dir_index filetype extent 64bit flex_bg sparse_super large_file huge_file dir_nlink extra_isize metadata_csum ++ Default mount options: user_xattr acl ++ Filesystem state: clean ++ Errors behavior: Continue ++@@ -10,7 +10,7 @@ ++ Inode count: 65536 ++ Block count: 524288 ++ Reserved block count: 26214 ++-Free blocks: 571 +++Free blocks: 568 ++ Free inodes: 65048 ++ First block: 1 ++ Block size: 1024 ++@@ -33,6 +33,7 @@ ++ Journal inode: 8 ++ Default directory hash: half_md4 ++ Journal backup: inode blocks +++Checksum type: crc32c ++ Journal features: (none) ++ Journal size: 16M ++ Journal length: 16384 ++@@ -46,8 +47,8 @@ ++ Block bitmap at 262 (+261) ++ Inode bitmap at 278 (+277) ++ Inode table at 294-549 (+293) ++- 21 free blocks, 536 free inodes, 2 directories, 536 unused inodes ++- Free blocks: 4413-4433 +++ 18 free blocks, 536 free inodes, 2 directories, 536 unused inodes +++ Free blocks: 4413, 4417-4433 ++ Free inodes: 489-1024 ++ Group 1: (Blocks 8193-16384) [INODE_UNINIT] ++ Backup superblock at 8193, Group descriptors at 8194-8197 ++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 ++ ++Exit status is 0 +--- /dev/null ++++ b/tests/t_enable_mcsum/name +@@ -0,0 +1 @@ ++enable metadata_csum +--- /dev/null ++++ b/tests/t_enable_mcsum/script +@@ -0,0 +1,70 @@ ++FSCK_OPT=-fn ++OUT=$test_name.log ++EXP=$test_dir/expect ++CONF=$TMPFILE.conf ++ ++cat > $CONF << ENDL ++[fs_types] ++ ext4h = { ++ features = has_journal,extent,huge_file,flex_bg,uninit_bg,dir_nlink,extra_isize,sparse_super,filetype,dir_index,ext_attr,resize_inode,64bit ++ blocksize = 1024 ++ inode_size = 256 ++ make_hugefiles = true ++ hugefiles_dir = / ++ hugefiles_slack = 0 ++ hugefiles_name = aaaaa ++ hugefiles_digits = 4 ++ hugefiles_size = 1M ++ zero_hugefiles = false ++ } ++ENDL ++ ++echo "tune2fs metadata_csum test" > $OUT ++ ++MKE2FS_CONFIG=$CONF $MKE2FS -F -T ext4h $TMPFILE 524288 >> $OUT 2>&1 ++rm -rf $CONF ++ ++# dump and check ++$DUMPE2FS $TMPFILE 2> /dev/null | grep '^Group 0:' -B99 -A20 | sed -f $cmd_dir/filter.sed > $OUT.before ++$FSCK $FSCK_OPT -N test_filesys $TMPFILE >> $OUT 2>&1 ++status=$? ++echo Exit status is $status >> $OUT ++ ++# add mcsum ++echo "tune2fs -O metadata_csum test.img" >> $OUT ++$TUNE2FS -O metadata_csum $TMPFILE >> $OUT 2>&1 ++status=$? ++echo Exit status is $status >> $OUT ++ ++# check ++$FSCK -yD -N test_filesys $TMPFILE >> $OUT 2>&1 ++ ++# dump and check ++$DUMPE2FS $TMPFILE 2> /dev/null | grep '^Group 0:' -B99 -A20 | sed -f $cmd_dir/filter.sed > $OUT.after ++echo "Change in FS metadata:" >> $OUT ++diff -u $OUT.before $OUT.after | tail -n +3 >> $OUT ++$FSCK $FSCK_OPT -N test_filesys $TMPFILE >> $OUT 2>&1 ++status=$? ++echo Exit status is $status >> $OUT ++ ++rm $TMPFILE $OUT.before $OUT.after ++ ++# ++# Do the verification ++# ++ ++sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" -e 's/test_filesys:.*//g' < $OUT > $OUT.new ++mv $OUT.new $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 IMAGE FSCK_OPT OUT EXP CONF +--- /dev/null ++++ b/tests/t_enable_mcsum_ext3/expect +@@ -0,0 +1,74 @@ ++tune2fs metadata_csum test ++Creating filesystem with 524288 1k blocks and 65536 inodes ++Superblock backups stored on blocks: ++ 8193, 24577, 40961, 57345, 73729, 204801, 221185, 401409 ++ ++Allocating group tables: done ++Writing inode tables: done ++Creating journal (16384 blocks): done ++mke2fs: Operation not supported for inodes containing extents while creating huge files ++Writing superblocks and filesystem accounting information: done ++ ++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 ++ ++Exit status is 0 ++tune2fs -O metadata_csum test.img ++Extents are not enabled. The file extent tree can be checksummed, whereas block maps cannot. Not enabling extents reduces the coverage of metadata checksumming. Re-run with -O extent to rectify. ++64-bit filesystem support is not enabled. The larger fields afforded by this feature enable full-strength checksumming. Run resize2fs -b to rectify. ++Exit status is 0 ++ ++Change in FS metadata: ++@@ -2,7 +2,7 @@ ++ Last mounted on: ++ Filesystem magic number: 0xEF53 ++ Filesystem revision #: 1 (dynamic) ++-Filesystem features: has_journal ext_attr resize_inode dir_index filetype sparse_super large_file +++Filesystem features: has_journal ext_attr resize_inode dir_index filetype sparse_super large_file metadata_csum ++ Default mount options: user_xattr acl ++ Filesystem state: clean ++ Errors behavior: Continue ++@@ -29,6 +29,7 @@ ++ Journal inode: 8 ++ Default directory hash: half_md4 ++ Journal backup: inode blocks +++Checksum type: crc32c ++ Journal features: (none) ++ Journal size: 16M ++ Journal length: 16384 ++@@ -36,7 +37,7 @@ ++ Journal start: 0 ++ ++ ++-Group 0: (Blocks 1-8192) +++Group 0: (Blocks 1-8192) [ITABLE_ZEROED] ++ Primary superblock at 1, Group descriptors at 2-3 ++ Reserved GDT blocks at 4-259 ++ Block bitmap at 260 (+259) ++@@ -45,7 +46,7 @@ ++ 0 free blocks, 1013 free inodes, 2 directories ++ Free blocks: ++ Free inodes: 12-1024 ++-Group 1: (Blocks 8193-16384) +++Group 1: (Blocks 8193-16384) [ITABLE_ZEROED] ++ Backup superblock at 8193, Group descriptors at 8194-8195 ++ Reserved GDT blocks at 8196-8451 ++ Block bitmap at 8452 (+259) ++@@ -54,6 +55,6 @@ ++ 0 free blocks, 1024 free inodes, 0 directories ++ Free blocks: ++ Free inodes: 1025-2048 ++-Group 2: (Blocks 16385-24576) +++Group 2: (Blocks 16385-24576) [ITABLE_ZEROED] ++ Block bitmap at 16385 (+0) ++ Inode bitmap at 16386 (+1) ++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 ++ ++Exit status is 0 +--- /dev/null ++++ b/tests/t_enable_mcsum_ext3/name +@@ -0,0 +1 @@ ++enable metadata_csum on ext3 fs +--- /dev/null ++++ b/tests/t_enable_mcsum_ext3/script +@@ -0,0 +1,70 @@ ++FSCK_OPT=-fn ++OUT=$test_name.log ++EXP=$test_dir/expect ++CONF=$TMPFILE.conf ++ ++cat > $CONF << ENDL ++[fs_types] ++ ext4h = { ++ features = has_journal,^extent,^huge_file,^flex_bg,^uninit_bg,^dir_nlink,^extra_isize,sparse_super,filetype,dir_index,ext_attr,resize_inode,^64bit ++ blocksize = 1024 ++ inode_size = 128 ++ make_hugefiles = true ++ hugefiles_dir = / ++ num_hugefiles = 10 ++ hugefiles_name = aaaaa ++ hugefiles_digits = 4 ++ hugefiles_size = 1M ++ zero_hugefiles = false ++ } ++ENDL ++ ++echo "tune2fs metadata_csum test" > $OUT ++ ++MKE2FS_CONFIG=$CONF $MKE2FS -F -T ext4h $TMPFILE 524288 >> $OUT 2>&1 ++rm -rf $CONF ++ ++# dump and check ++$DUMPE2FS $TMPFILE 2> /dev/null | grep '^Group 0:' -B99 -A20 | sed -f $cmd_dir/filter.sed > $OUT.before ++$FSCK $FSCK_OPT -N test_filesys $TMPFILE >> $OUT 2>&1 ++status=$? ++echo Exit status is $status >> $OUT ++ ++# add mcsum ++echo "tune2fs -O metadata_csum test.img" >> $OUT ++$TUNE2FS -O metadata_csum $TMPFILE >> $OUT 2>&1 ++status=$? ++echo Exit status is $status >> $OUT ++ ++# check ++$FSCK -yD -N test_filesys $TMPFILE >> $OUT 2>&1 ++ ++# dump and check ++$DUMPE2FS $TMPFILE 2> /dev/null | grep '^Group 0:' -B99 -A20 | sed -f $cmd_dir/filter.sed > $OUT.after ++echo "Change in FS metadata:" >> $OUT ++diff -u $OUT.before $OUT.after | tail -n +3 >> $OUT ++$FSCK $FSCK_OPT -N test_filesys $TMPFILE >> $OUT 2>&1 ++status=$? ++echo Exit status is $status >> $OUT ++ ++rm $TMPFILE $OUT.before $OUT.after ++ ++# ++# Do the verification ++# ++ ++sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" -e 's/test_filesys:.*//g' < $OUT > $OUT.new ++mv $OUT.new $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 IMAGE FSCK_OPT OUT EXP CONF +--- /dev/null ++++ b/tests/t_enable_mcsum_initbg/expect +@@ -0,0 +1,98 @@ ++tune2fs metadata_csum test ++Creating filesystem with 524288 1k blocks and 65536 inodes ++Superblock backups stored on blocks: ++ 8193, 24577, 40961, 57345, 73729, 204801, 221185, 401409 ++ ++Allocating group tables: done ++Writing inode tables: done ++Creating journal (16384 blocks): done ++Creating 477 huge file(s) with 1024 blocks each: done ++Writing superblocks and filesystem accounting information: done ++ ++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 ++ ++Exit status is 0 ++tune2fs -O metadata_csum test.img ++ ++Please run e2fsck -D on the filesystem. ++ ++Exit status is 0 ++test_filesys was not cleanly unmounted, check forced. ++Pass 1: Checking inodes, blocks, and sizes ++Pass 2: Checking directory structure ++Pass 3: Checking directory connectivity ++Pass 3A: Optimizing directories ++Pass 4: Checking reference counts ++Pass 5: Checking group summary information ++ ++ ++ ++Change in FS metadata: ++@@ -2,7 +2,7 @@ ++ Last mounted on: ++ Filesystem magic number: 0xEF53 ++ Filesystem revision #: 1 (dynamic) ++-Filesystem features: has_journal ext_attr resize_inode dir_index filetype extent 64bit flex_bg sparse_super large_file huge_file dir_nlink extra_isize +++Filesystem features: has_journal ext_attr resize_inode dir_index filetype extent 64bit flex_bg sparse_super large_file huge_file dir_nlink extra_isize metadata_csum ++ Default mount options: user_xattr acl ++ Filesystem state: clean ++ Errors behavior: Continue ++@@ -10,7 +10,7 @@ ++ Inode count: 65536 ++ Block count: 524288 ++ Reserved block count: 26214 ++-Free blocks: 571 +++Free blocks: 568 ++ Free inodes: 65048 ++ First block: 1 ++ Block size: 1024 ++@@ -33,6 +33,7 @@ ++ Journal inode: 8 ++ Default directory hash: half_md4 ++ Journal backup: inode blocks +++Checksum type: crc32c ++ Journal features: (none) ++ Journal size: 16M ++ Journal length: 16384 ++@@ -40,24 +41,24 @@ ++ Journal start: 0 ++ ++ ++-Group 0: (Blocks 1-8192) +++Group 0: (Blocks 1-8192) [ITABLE_ZEROED] ++ Primary superblock at 1, Group descriptors at 2-5 ++ Reserved GDT blocks at 6-261 ++ Block bitmap at 262 (+261) ++ Inode bitmap at 278 (+277) ++ Inode table at 294-549 (+293) ++- 21 free blocks, 536 free inodes, 2 directories ++- Free blocks: 4413-4433 +++ 18 free blocks, 536 free inodes, 2 directories, 536 unused inodes +++ Free blocks: 4413, 4417-4433 ++ Free inodes: 489-1024 ++-Group 1: (Blocks 8193-16384) +++Group 1: (Blocks 8193-16384) [INODE_UNINIT, ITABLE_ZEROED] ++ Backup superblock at 8193, Group descriptors at 8194-8197 ++ Reserved GDT blocks at 8198-8453 ++ Block bitmap at 263 (bg #0 + 262) ++ Inode bitmap at 279 (bg #0 + 278) ++ Inode table at 550-805 (bg #0 + 549) ++- 0 free blocks, 1024 free inodes, 0 directories +++ 0 free blocks, 1024 free inodes, 0 directories, 1024 unused inodes ++ Free blocks: ++ Free inodes: 1025-2048 ++-Group 2: (Blocks 16385-24576) +++Group 2: (Blocks 16385-24576) [INODE_UNINIT, ITABLE_ZEROED] ++ Block bitmap at 264 (bg #0 + 263) ++ Inode bitmap at 280 (bg #0 + 279) ++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 ++ ++Exit status is 0 +--- /dev/null ++++ b/tests/t_enable_mcsum_initbg/name +@@ -0,0 +1 @@ ++enable metadata_csum when ^uninit_bg +--- /dev/null ++++ b/tests/t_enable_mcsum_initbg/script +@@ -0,0 +1,70 @@ ++FSCK_OPT=-fn ++OUT=$test_name.log ++EXP=$test_dir/expect ++CONF=$TMPFILE.conf ++ ++cat > $CONF << ENDL ++[fs_types] ++ ext4h = { ++ features = has_journal,extent,huge_file,flex_bg,^uninit_bg,dir_nlink,extra_isize,sparse_super,filetype,dir_index,ext_attr,resize_inode,64bit ++ blocksize = 1024 ++ inode_size = 256 ++ make_hugefiles = true ++ hugefiles_dir = / ++ hugefiles_slack = 0 ++ hugefiles_name = aaaaa ++ hugefiles_digits = 4 ++ hugefiles_size = 1M ++ zero_hugefiles = false ++ } ++ENDL ++ ++echo "tune2fs metadata_csum test" > $OUT ++ ++MKE2FS_CONFIG=$CONF $MKE2FS -F -T ext4h $TMPFILE 524288 >> $OUT 2>&1 ++rm -rf $CONF ++ ++# dump and check ++$DUMPE2FS $TMPFILE 2> /dev/null | grep '^Group 0:' -B99 -A20 | sed -f $cmd_dir/filter.sed > $OUT.before ++$FSCK $FSCK_OPT -N test_filesys $TMPFILE >> $OUT 2>&1 ++status=$? ++echo Exit status is $status >> $OUT ++ ++# add mcsum ++echo "tune2fs -O metadata_csum test.img" >> $OUT ++$TUNE2FS -O metadata_csum $TMPFILE >> $OUT 2>&1 ++status=$? ++echo Exit status is $status >> $OUT ++ ++# check ++$FSCK -yD -N test_filesys $TMPFILE >> $OUT 2>&1 ++ ++# dump and check ++$DUMPE2FS $TMPFILE 2> /dev/null | grep '^Group 0:' -B99 -A20 | sed -f $cmd_dir/filter.sed > $OUT.after ++echo "Change in FS metadata:" >> $OUT ++diff -u $OUT.before $OUT.after | tail -n +3 >> $OUT ++$FSCK $FSCK_OPT -N test_filesys $TMPFILE >> $OUT 2>&1 ++status=$? ++echo Exit status is $status >> $OUT ++ ++rm $TMPFILE $OUT.before $OUT.after ++ ++# ++# Do the verification ++# ++ ++sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" -e 's/test_filesys:.*//g' < $OUT > $OUT.new ++mv $OUT.new $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 IMAGE FSCK_OPT OUT EXP CONF +--- a/tests/test_config ++++ b/tests/test_config +@@ -17,9 +17,11 @@ + RESIZE2FS_EXE="../resize/resize2fs" + RESIZE2FS="$USE_VALGRIND $RESIZE2FS_EXE" + E2UNDO_EXE="../misc/e2undo" ++E2UNDO="$USE_VALGRIND $E2UNDO_EXE" + TEST_REL=../tests/progs/test_rel + TEST_ICOUNT=../tests/progs/test_icount + CRCSUM=../tests/progs/crcsum ++CLEAN_OUTPUT="sed -f $cmd_dir/filter.sed" + LD_LIBRARY_PATH=../lib:../lib/ext2fs:../lib/e2p:../lib/et:../lib/ss:${LD_LIBRARY_PATH} + DYLD_LIBRARY_PATH=../lib:../lib/ext2fs:../lib/e2p:../lib/et:../lib/ss:${DYLD_LIBRARY_PATH} + export LD_LIBRARY_PATH +--- /dev/null ++++ b/tests/t_ext_jnl_fail/expect +@@ -0,0 +1,6 @@ ++Creating filesystem with 4096 1k blocks and 0 inodes ++Superblock backups stored on blocks: ++ ++Zeroing journal device:  ++tune2fs external journal ++Cannot modify a journal device. +--- /dev/null ++++ b/tests/t_ext_jnl_fail/name +@@ -0,0 +1 @@ ++tune2fs fail external journal +--- /dev/null ++++ b/tests/t_ext_jnl_fail/script +@@ -0,0 +1,30 @@ ++FSCK_OPT=-fy ++OUT=$test_name.log ++if [ -f $test_dir/expect.gz ]; then ++ EXP=$test_name.tmp ++ gunzip < $test_dir/expect.gz > $EXP1 ++else ++ EXP=$test_dir/expect ++fi ++ ++cp /dev/null $OUT ++ ++$MKE2FS -F -o Linux -b 1024 -O journal_dev,metadata_csum -T ext4 $TMPFILE 4096 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT 2>&1 ++echo "tune2fs external journal" >> $OUT ++$TUNE2FS -i 0 $TMPFILE 2>&1 | sed -f $cmd_dir/filter.sed >> $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 IMAGE FSCK_OPT OUT EXP +--- /dev/null ++++ b/tests/t_iexpand_full/expect +@@ -0,0 +1,38 @@ ++tune2fs test ++Creating filesystem with 786432 1k blocks and 98304 inodes ++Superblock backups stored on blocks: ++ 8193, 24577, 40961, 57345, 73729, 204801, 221185, 401409, 663553 ++ ++Allocating group tables: done ++Writing inode tables: done ++Creating journal (16384 blocks): done ++Creating 6368 huge file(s) with 117 blocks each: done ++Writing superblocks and filesystem accounting information: done ++ ++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 ++ ++Exit status is 0 ++tune2fs -I 256 test.img ++Setting inode size 256 ++Exit status is 0 ++Change in FS metadata: ++@@ -13 +13 @@ ++-Free blocks: 12301 +++Free blocks: 12 ++@@ -22 +22 @@ ++-Inode blocks per group: 128 +++Inode blocks per group: 256 ++@@ -28 +28 @@ ++-Inode size: 128 +++Inode size: 256 ++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 ++ ++Exit status is 0 +--- /dev/null ++++ b/tests/t_iexpand_full/name +@@ -0,0 +1 @@ ++expand inodes on a totally full filesystem +--- /dev/null ++++ b/tests/t_iexpand_full/script +@@ -0,0 +1,85 @@ ++if test -x $RESIZE2FS_EXE -a -x $DEBUGFS_EXE; then ++ ++if [ $(uname -s) = "Darwin" ]; then ++ # creates a 3GB filesystem ++ echo "$test_name: $DESCRIPTION: skipped for HFS+ (no sparse files)" ++ return 0 ++fi ++ ++FSCK_OPT=-fn ++OUT=$test_name.log ++EXP=$test_dir/expect ++CONF=$TMPFILE.conf ++ ++#gzip -d < $EXP.gz > $EXP ++ ++cat > $CONF << ENDL ++[fs_types] ++ ext4h = { ++ features = has_journal,extent,huge_file,uninit_bg,dir_nlink,extra_isize,sparse_super,filetype,dir_index,ext_attr,^resize_inode,^meta_bg,^flex_bg,metadata_csum,64bit ++ blocksize = 1024 ++ inode_size = 256 ++ make_hugefiles = true ++ hugefiles_dir = / ++ hugefiles_slack = 12000K ++ hugefiles_name = aaaaa ++ hugefiles_digits = 4 ++ hugefiles_size = 117K ++ zero_hugefiles = false ++ } ++ENDL ++ ++echo "tune2fs test" > $OUT ++ ++MKE2FS_CONFIG=$CONF $MKE2FS -F -T ext4h -I 128 $TMPFILE 786432 >> $OUT 2>&1 ++rm -rf $CONF ++ ++# dump and check ++($DUMPE2FS -h $TMPFILE; $DUMPE2FS -g $TMPFILE) 2>&1 | sed -f $cmd_dir/filter.sed -e '/^Checksum:.*/d' >> $OUT.before 2> /dev/null ++$FSCK $FSCK_OPT -N test_filesys $TMPFILE >> $OUT 2>&1 ++status=$? ++echo Exit status is $status >> $OUT ++ ++# convert it ++echo "tune2fs -I 256 test.img" >> $OUT ++dd if=/dev/zero of=$TMPFILE conv=notrunc bs=1 count=1 seek=3221225471 2> /dev/null ++$TUNE2FS -I 256 $TMPFILE >> $OUT 2>&1 ++status=$? ++echo Exit status is $status >> $OUT ++ ++# dump and check ++($DUMPE2FS -h $TMPFILE; $DUMPE2FS -g $TMPFILE) 2>&1 | sed -f $cmd_dir/filter.sed -e '/^Checksum:.*/d' >> $OUT.after 2> /dev/null ++echo "Change in FS metadata:" >> $OUT ++diff -U 0 $OUT.before $OUT.after | sed -e '/^---.*/d' -e '/^+++.*/d' >> $OUT ++$FSCK $FSCK_OPT -N test_filesys $TMPFILE >> $OUT 2>&1 ++status=$? ++echo Exit status is $status >> $OUT ++ ++rm $TMPFILE ++ ++# ++# Do the verification ++# ++ ++sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" -e 's/test_filesys:.*//g' < $OUT > $OUT.new ++mv $OUT.new $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 ++ ++rm $OUT.before $OUT.after ++ ++unset IMAGE FSCK_OPT OUT EXP CONF ++ ++else #if test -x $RESIZE2FS_EXE -a -x $DEBUGFS_EXE; then ++ echo "$test_name: $test_description: skipped" ++fi ++ +--- /dev/null ++++ b/tests/t_iexpand_mcsum/expect +@@ -0,0 +1,54 @@ ++tune2fs test ++Creating filesystem with 786432 1k blocks and 98304 inodes ++Superblock backups stored on blocks: ++ 8193, 24577, 40961, 57345, 73729, 204801, 221185, 401409, 663553 ++ ++Allocating group tables: done ++Writing inode tables: done ++Creating journal (16384 blocks): done ++Creating 6334 huge file(s) with 117 blocks each: done ++Writing superblocks and filesystem accounting information: done ++ ++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 ++ ++Exit status is 0 ++tune2fs -I 256 -O metadata_csum test.img ++Setting inode size 256 ++ ++Please run e2fsck -D on the filesystem. ++ ++Exit status is 0 ++Backing up journal inode block information. ++ ++Pass 1: Checking inodes, blocks, and sizes ++Pass 2: Checking directory structure ++Pass 3: Checking directory connectivity ++Pass 3A: Optimizing directories ++Pass 4: Checking reference counts ++Pass 5: Checking group summary information ++ ++ ++ ++Change in FS metadata: ++@@ -5 +5 @@ ++-Filesystem features: has_journal ext_attr dir_index filetype extent 64bit sparse_super large_file huge_file uninit_bg dir_nlink extra_isize +++Filesystem features: has_journal ext_attr dir_index filetype extent 64bit sparse_super large_file huge_file dir_nlink extra_isize metadata_csum ++@@ -21 +21 @@ ++-Inode blocks per group: 128 +++Inode blocks per group: 256 ++@@ -27 +27 @@ ++-Inode size: 128 +++Inode size: 256 ++@@ -30,0 +31 @@ +++Checksum type: crc32c ++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 ++ ++Exit status is 0 +--- /dev/null ++++ b/tests/t_iexpand_mcsum/name +@@ -0,0 +1 @@ ++expand inodes and turn on metadata_csum +--- /dev/null ++++ b/tests/t_iexpand_mcsum/script +@@ -0,0 +1,85 @@ ++if test -x $RESIZE2FS_EXE -a -x $DEBUGFS_EXE; then ++if [ $(uname -s) = "Darwin" ]; then ++ # creates a 3GB filesystem ++ echo "$test_name: $DESCRIPTION: skipped for HFS+ (no sparse files)" ++ return 0 ++fi ++ ++FSCK_OPT=-fn ++OUT=$test_name.log ++EXP=$test_dir/expect ++CONF=$TMPFILE.conf ++ ++#gzip -d < $EXP.gz > $EXP ++ ++cat > $CONF << ENDL ++[fs_types] ++ ext4h = { ++ features = has_journal,extent,huge_file,uninit_bg,dir_nlink,extra_isize,sparse_super,filetype,dir_index,ext_attr,^resize_inode,^meta_bg,^flex_bg,^metadata_csum,64bit ++ blocksize = 1024 ++ inode_size = 256 ++ make_hugefiles = true ++ hugefiles_dir = / ++ hugefiles_slack = 16000K ++ hugefiles_name = aaaaa ++ hugefiles_digits = 4 ++ hugefiles_size = 117K ++ zero_hugefiles = false ++ } ++ENDL ++ ++echo "tune2fs test" > $OUT ++ ++MKE2FS_CONFIG=$CONF $MKE2FS -F -T ext4h -I 128 $TMPFILE 786432 >> $OUT 2>&1 ++rm -rf $CONF ++ ++# dump and check ++($DUMPE2FS -h $TMPFILE | grep -v '^Free blocks:'; $DUMPE2FS -g $TMPFILE) 2>&1 | sed -f $cmd_dir/filter.sed -e '/^Checksum:.*/d' >> $OUT.before 2> /dev/null ++$FSCK $FSCK_OPT -N test_filesys $TMPFILE >> $OUT 2>&1 ++status=$? ++echo Exit status is $status >> $OUT ++ ++# convert it ++echo "tune2fs -I 256 -O metadata_csum test.img" >> $OUT ++dd if=/dev/zero of=$TMPFILE conv=notrunc bs=1 count=1 seek=3221225471 2> /dev/null ++$TUNE2FS -I 256 -O metadata_csum $TMPFILE >> $OUT 2>&1 ++status=$? ++echo Exit status is $status >> $OUT ++$FSCK -N test_filesys -y -f -D $TMPFILE >> $OUT 2>&1 ++ ++# dump and check ++($DUMPE2FS -h $TMPFILE | grep -v '^Free blocks:'; $DUMPE2FS -g $TMPFILE) 2>&1 | sed -f $cmd_dir/filter.sed -e '/^Checksum:.*/d' >> $OUT.after 2> /dev/null ++echo "Change in FS metadata:" >> $OUT ++diff -U 0 $OUT.before $OUT.after | sed -e '/^---.*/d' -e '/^+++.*/d' >> $OUT ++$FSCK $FSCK_OPT -N test_filesys $TMPFILE >> $OUT 2>&1 ++status=$? ++echo Exit status is $status >> $OUT ++ ++rm $TMPFILE ++ ++# ++# Do the verification ++# ++ ++sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" -e 's/test_filesys:.*//g' < $OUT > $OUT.new ++mv $OUT.new $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 ++ ++rm $OUT.before $OUT.after ++ ++unset IMAGE FSCK_OPT OUT EXP CONF ++ ++else #if test -x $RESIZE2FS_EXE -a -x $DEBUGFS_EXE; then ++ echo "$test_name: $test_description: skipped" ++fi ++ +--- /dev/null ++++ b/tests/t_mke2fs_errors/expect +@@ -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 +--- /dev/null ++++ b/tests/t_mke2fs_errors/script +@@ -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 -T test_suite -F $TMPFILE > /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 -T test_suite -F $TMPFILE > /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 -T test_suite -F $TMPFILE > /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 -T test_suite -e panic -F $TMPFILE > /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 ++ +--- /dev/null ++++ b/tests/t_uninit_bg_rm/expect +@@ -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 +--- /dev/null ++++ b/tests/t_uninit_bg_rm/script +@@ -0,0 +1,56 @@ ++test_description="remove uninit_bg" ++OUT=$test_name.log ++FSCK_OPT=-yf ++EXP=$test_dir/expect ++ ++if [ $(uname -s) = "Darwin" ]; then ++ # creates a 10GB filesystem ++ echo "$test_name: $DESCRIPTION: skipped for HFS+ (no sparse files)" ++ return 0 ++fi ++ ++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 +--- /dev/null ++++ b/tests/u_compound_bad_rollback/script +@@ -0,0 +1,62 @@ ++test_description="e2undo with mke2fs/tune2fs/resize2fs/e2fsck -z" ++if test -x $RESIZE2FS_EXE -a -x $E2UNDO_EXE; then ++ ++TDB_FILE=${TMPDIR:-/tmp}/resize2fs-$(basename $TMPFILE).e2undo ++OUT=$test_name.log ++rm -f $TDB_FILE >/dev/null 2>&1 ++ ++echo compound e2undo rollback test > $OUT ++ ++dd if=/dev/zero of=$TMPFILE bs=1k count=512 > /dev/null 2>&1 ++crc0=`$CRCSUM $TMPFILE` ++echo $CRCSUM before mke2fs $crc0 >> $OUT ++ ++echo mke2fs -q -F -o Linux -T ext4 -O ^metadata_csum,64bit -E lazy_itable_init=1 -b 1024 -z $TDB_FILE.0 $TMPFILE 256 >> $OUT ++$MKE2FS -q -F -o Linux -T ext4 -O ^metadata_csum,64bit -E lazy_itable_init=1 -b 1024 -z $TDB_FILE.0 $TMPFILE 256 >> $OUT 2>&1 ++crc1=`$CRCSUM $TMPFILE` ++echo $CRCSUM after mke2fs $crc1 >> $OUT ++ ++echo using tune2fs to test e2undo >> $OUT ++$TUNE2FS -O metadata_csum -z $TDB_FILE.1 $TMPFILE >> $OUT 2>&1 ++crc2=`$CRCSUM $TMPFILE` ++echo $CRCSUM after tune2fs $crc2 >> $OUT ++ ++echo using resize2fs to test e2undo >> $OUT ++$RESIZE2FS -z $TDB_FILE.2 $TMPFILE 512 >> $OUT 2>&1 ++crc3=`$CRCSUM $TMPFILE` ++echo $CRCSUM after resize2fs $crc3 >> $OUT ++ ++echo using e2fsck to test e2undo >> $OUT ++$FSCK -f -y -D -z $TDB_FILE.3 $TMPFILE >> $OUT 2>&1 ++crc4=`$CRCSUM $TMPFILE` ++echo $CRCSUM after e2fsck $crc4 >> $OUT ++ ++echo roll back mke2fs >> $OUT ++$E2UNDO $TDB_FILE.0 $TMPFILE >> $OUT 2>&1 ++crc0_2=`$CRCSUM $TMPFILE` ++echo $CRCSUM after e2undo mke2fs $crc0_2 >> $OUT ++ ++echo roll back tune2fs >> $OUT ++$E2UNDO $TDB_FILE.1 $TMPFILE >> $OUT 2>&1 ++crc1_2=`$CRCSUM $TMPFILE` ++echo $CRCSUM after e2undo tune2fs $crc1_2 >> $OUT ++ ++echo roll back resize2fs >> $OUT ++$E2UNDO $TDB_FILE.2 $TMPFILE >> $OUT 2>&1 ++crc2_2=`$CRCSUM $TMPFILE` ++echo $CRCSUM after e2undo resize2fs $crc2_2 >> $OUT ++ ++echo roll back e2fsck >> $OUT ++$E2UNDO $TDB_FILE.3 $TMPFILE >> $OUT 2>&1 ++crc3_2=`$CRCSUM $TMPFILE` ++echo $CRCSUM after e2undo e2fsck $crc3_2 >> $OUT ++ ++if [ $crc4 = $crc0_2 ] && [ $crc4 = $crc1_2 ] && [ $crc4 = $crc2_2 ] && [ $crc3 = $crc3_2 ]; then ++ echo "$test_name: $test_description: ok" ++ touch $test_name.ok ++else ++ ln -f $test_name.log $test_name.failed ++ echo "$test_name: $test_description: failed" ++fi ++rm -f $TDB_FILE.0 $TDB_FILE.1 $TDB_FILE.2 $TDB_FILE.3 $TMPFILE ++fi +--- /dev/null ++++ b/tests/u_compound_rollback/script +@@ -0,0 +1,62 @@ ++test_description="e2undo with mke2fs/tune2fs/resize2fs/e2fsck -z" ++if test -x $RESIZE2FS_EXE -a -x $E2UNDO_EXE; then ++ ++TDB_FILE=${TMPDIR:-/tmp}/resize2fs-$(basename $TMPFILE).e2undo ++OUT=$test_name.log ++rm -f $TDB_FILE >/dev/null 2>&1 ++ ++echo compound e2undo rollback test > $OUT ++ ++dd if=/dev/zero of=$TMPFILE bs=1k count=512 > /dev/null 2>&1 ++crc0=`$CRCSUM $TMPFILE` ++echo $CRCSUM before mke2fs $crc0 >> $OUT ++ ++echo mke2fs -q -F -o Linux -T ext4 -O ^metadata_csum,64bit -E lazy_itable_init=1 -b 1024 -z $TDB_FILE.0 $TMPFILE 256 >> $OUT ++$MKE2FS -q -F -o Linux -T ext4 -O ^metadata_csum,64bit -E lazy_itable_init=1 -b 1024 -z $TDB_FILE.0 $TMPFILE 256 >> $OUT 2>&1 ++crc1=`$CRCSUM $TMPFILE` ++echo $CRCSUM after mke2fs $crc1 >> $OUT ++ ++echo using tune2fs to test e2undo >> $OUT ++$TUNE2FS -O metadata_csum -z $TDB_FILE.1 $TMPFILE >> $OUT 2>&1 ++crc2=`$CRCSUM $TMPFILE` ++echo $CRCSUM after tune2fs $crc2 >> $OUT ++ ++echo using resize2fs to test e2undo >> $OUT ++$RESIZE2FS -z $TDB_FILE.2 $TMPFILE 512 >> $OUT 2>&1 ++crc3=`$CRCSUM $TMPFILE` ++echo $CRCSUM after resize2fs $crc3 >> $OUT ++ ++echo using e2fsck to test e2undo >> $OUT ++$FSCK -f -y -D -z $TDB_FILE.3 $TMPFILE >> $OUT 2>&1 ++crc4=`$CRCSUM $TMPFILE` ++echo $CRCSUM after e2fsck $crc4 >> $OUT ++ ++echo roll back e2fsck >> $OUT ++$E2UNDO $TDB_FILE.3 $TMPFILE >> $OUT 2>&1 ++crc3_2=`$CRCSUM $TMPFILE` ++echo $CRCSUM after e2undo e2fsck $crc3_2 >> $OUT ++ ++echo roll back resize2fs >> $OUT ++$E2UNDO $TDB_FILE.2 $TMPFILE >> $OUT 2>&1 ++crc2_2=`$CRCSUM $TMPFILE` ++echo $CRCSUM after e2undo resize2fs $crc2_2 >> $OUT ++ ++echo roll back tune2fs >> $OUT ++$E2UNDO $TDB_FILE.1 $TMPFILE >> $OUT 2>&1 ++crc1_2=`$CRCSUM $TMPFILE` ++echo $CRCSUM after e2undo tune2fs $crc1_2 >> $OUT ++ ++echo roll back mke2fs >> $OUT ++$E2UNDO $TDB_FILE.0 $TMPFILE >> $OUT 2>&1 ++crc0_2=`$CRCSUM $TMPFILE` ++echo $CRCSUM after e2undo mke2fs $crc0_2 >> $OUT ++ ++if [ $crc0 = $crc0_2 ] && [ $crc1 = $crc1_2 ] && [ $crc2 = $crc2_2 ] && [ $crc3 = $crc3_2 ]; then ++ echo "$test_name: $test_description: ok" ++ touch $test_name.ok ++else ++ ln -f $test_name.log $test_name.failed ++ echo "$test_name: $test_description: failed" ++fi ++rm -f $TDB_FILE.0 $TDB_FILE.1 $TDB_FILE.2 $TDB_FILE.3 $TMPFILE ++fi +--- /dev/null ++++ b/tests/u_corrupt_blk_csum/script +@@ -0,0 +1,38 @@ ++test_description="corrupt e2undo block data" ++if test -x $E2UNDO_EXE; then ++ ++E2FSPROGS_UNDO_DIR=${TMPDIR:-/tmp} ++export E2FSPROGS_UNDO_DIR ++TDB_FILE=$E2FSPROGS_UNDO_DIR/tune2fs-$(basename $TMPFILE).e2undo ++OUT=$test_name.log ++rm -f $TDB_FILE >/dev/null 2>&1 ++ ++dd if=/dev/zero of=$TMPFILE bs=1k count=512 > /dev/null 2>&1 ++ ++echo mke2fs -q -F -o Linux -b 1024 $TMPFILE > $OUT ++$MKE2FS -q -F -o Linux -I 128 -b 1024 $TMPFILE >> $OUT 2>&1 ++crc0=`$CRCSUM $TMPFILE` ++echo $CRCSUM before tune2fs $crc0 >> $OUT ++ ++echo using tune2fs to test e2undo >> $OUT ++$TUNE2FS -I 256 $TMPFILE >> $OUT 2>&1 ++crc1=`$CRCSUM $TMPFILE` ++echo $CRCSUM after tune2fs $crc1 >> $OUT ++ ++undo_blks=$(( $(stat -c '%s' $TDB_FILE 2>/dev/null || stat -f '%z' $TDB_FILE 2>/dev/null) / 1024 )) ++dd if=/dev/zero of=$TDB_FILE bs=1024 count=1 seek=$((undo_blks - 2)) conv=notrunc > /dev/null 2>&1 ++ ++$E2UNDO $TDB_FILE $TMPFILE >> $OUT 2>&1 ++res=$? ++crc2=`$CRCSUM $TMPFILE` ++echo $CRCSUM after e2undo $crc2 >> $OUT ++ ++if [ $res -ne 0 ] && [ $crc2 = $crc1 ] && [ $crc2 != $crc0 ]; then ++ echo "$test_name: $test_description: ok" ++ touch $test_name.ok ++else ++ ln -f $test_name.log $test_name.failed ++ echo "$test_name: $test_description: failed" ++fi ++rm -f $TDB_FILE $TMPFILE ++fi +--- /dev/null ++++ b/tests/u_corrupt_blk_csum_force/script +@@ -0,0 +1,38 @@ ++test_description="force replay of corrupt e2undo block data" ++if test -x $E2UNDO_EXE; then ++ ++E2FSPROGS_UNDO_DIR=${TMPDIR:-/tmp} ++export E2FSPROGS_UNDO_DIR ++TDB_FILE=$E2FSPROGS_UNDO_DIR/tune2fs-$(basename $TMPFILE).e2undo ++OUT=$test_name.log ++rm -f $TDB_FILE >/dev/null 2>&1 ++ ++dd if=/dev/zero of=$TMPFILE bs=1k count=512 > /dev/null 2>&1 ++ ++echo mke2fs -q -F -o Linux -b 1024 $TMPFILE > $OUT ++$MKE2FS -q -F -o Linux -I 128 -b 1024 $TMPFILE >> $OUT 2>&1 ++crc0=`$CRCSUM $TMPFILE` ++echo $CRCSUM before tune2fs $crc0 >> $OUT ++ ++echo using tune2fs to test e2undo >> $OUT ++$TUNE2FS -I 256 $TMPFILE >> $OUT 2>&1 ++crc1=`$CRCSUM $TMPFILE` ++echo $CRCSUM after tune2fs $crc1 >> $OUT ++ ++undo_blks=$(( $(stat -c '%s' $TDB_FILE 2>/dev/null || stat -f '%z' $TDB_FILE 2>/dev/null) / 1024 )) ++dd if=/dev/zero of=$TDB_FILE bs=1024 count=1 seek=$((undo_blks - 2)) conv=notrunc > /dev/null 2>&1 ++ ++$E2UNDO -f $TDB_FILE $TMPFILE >> $OUT 2>&1 ++res=$? ++crc2=`$CRCSUM $TMPFILE` ++echo $CRCSUM after e2undo $crc2 >> $OUT ++ ++if [ $crc2 != $crc1 ] && [ $crc2 != $crc0 ]; then ++ echo "$test_name: $test_description: ok" ++ touch $test_name.ok ++else ++ ln -f $test_name.log $test_name.failed ++ echo "$test_name: $test_description: failed" ++fi ++rm -f $TDB_FILE $TMPFILE ++fi +--- /dev/null ++++ b/tests/u_corrupt_hdr_csum/script +@@ -0,0 +1,37 @@ ++test_description="corrupt e2undo header" ++if test -x $E2UNDO_EXE; then ++ ++E2FSPROGS_UNDO_DIR=${TMPDIR:-/tmp} ++export E2FSPROGS_UNDO_DIR ++TDB_FILE=$E2FSPROGS_UNDO_DIR/tune2fs-$(basename $TMPFILE).e2undo ++OUT=$test_name.log ++rm -f $TDB_FILE >/dev/null 2>&1 ++ ++dd if=/dev/zero of=$TMPFILE bs=1k count=512 > /dev/null 2>&1 ++ ++echo mke2fs -q -F -o Linux -b 1024 $TMPFILE > $OUT ++$MKE2FS -q -F -o Linux -I 128 -b 1024 $TMPFILE >> $OUT 2>&1 ++crc0=`$CRCSUM $TMPFILE` ++echo $CRCSUM before tune2fs $crc0 >> $OUT ++ ++echo using tune2fs to test e2undo >> $OUT ++$TUNE2FS -I 256 $TMPFILE >> $OUT 2>&1 ++crc1=`$CRCSUM $TMPFILE` ++echo $CRCSUM after tune2fs $crc1 >> $OUT ++ ++dd if=/dev/zero of=$TDB_FILE bs=256 count=1 seek=1 conv=notrunc > /dev/null 2>&1 ++ ++$E2UNDO $TDB_FILE $TMPFILE >> $OUT 2>&1 ++res=$? ++crc2=`$CRCSUM $TMPFILE` ++echo $CRCSUM after e2undo $crc2 >> $OUT ++ ++if [ $res -ne 0 ]; then ++ echo "$test_name: $test_description: ok" ++ touch $test_name.ok ++else ++ ln -f $test_name.log $test_name.failed ++ echo "$test_name: $test_description: failed" ++fi ++rm -f $TDB_FILE $TMPFILE ++fi +--- /dev/null ++++ b/tests/u_corrupt_key_csum/script +@@ -0,0 +1,37 @@ ++test_description="corrupt e2undo key data" ++if test -x $E2UNDO_EXE; then ++ ++E2FSPROGS_UNDO_DIR=${TMPDIR:-/tmp} ++export E2FSPROGS_UNDO_DIR ++TDB_FILE=$E2FSPROGS_UNDO_DIR/tune2fs-$(basename $TMPFILE).e2undo ++OUT=$test_name.log ++rm -f $TDB_FILE >/dev/null 2>&1 ++ ++dd if=/dev/zero of=$TMPFILE bs=1k count=512 > /dev/null 2>&1 ++ ++echo mke2fs -q -F -o Linux -b 1024 $TMPFILE > $OUT ++$MKE2FS -q -F -o Linux -I 128 -b 1024 $TMPFILE >> $OUT 2>&1 ++crc0=`$CRCSUM $TMPFILE` ++echo $CRCSUM before tune2fs $crc0 >> $OUT ++ ++echo using tune2fs to test e2undo >> $OUT ++$TUNE2FS -I 256 $TMPFILE >> $OUT 2>&1 ++crc1=`$CRCSUM $TMPFILE` ++echo $CRCSUM after tune2fs $crc1 >> $OUT ++ ++undo_blks=$(( $(stat -c '%s' $TDB_FILE 2>/dev/null || stat -f '%z' $TDB_FILE 2>/dev/null) / 1024 )) ++dd if=/dev/zero of=$TDB_FILE bs=1024 count=1 seek=$((undo_blks - 1)) conv=notrunc > /dev/null 2>&1 ++ ++$E2UNDO $TDB_FILE $TMPFILE >> $OUT 2>&1 ++crc2=`$CRCSUM $TMPFILE` ++echo $CRCSUM after e2undo $crc2 >> $OUT ++ ++if [ $crc0 != $crc1 ] && [ $crc1 = $crc2 ]; then ++ echo "$test_name: $test_description: ok" ++ touch $test_name.ok ++else ++ ln -f $test_name.log $test_name.failed ++ echo "$test_name: $test_description: failed" ++fi ++rm -f $TDB_FILE $TMPFILE ++fi +--- /dev/null ++++ b/tests/u_debugfs_opt/script +@@ -0,0 +1,32 @@ ++test_description="e2undo with debugfs -z" ++if test -x $E2UNDO_EXE -a -x $DEBUGFS_EXE; then ++ ++TDB_FILE=${TMPDIR:-/tmp}/tune2fs-$(basename $TMPFILE).e2undo ++OUT=$test_name.log ++rm -f $TDB_FILE >/dev/null 2>&1 ++ ++dd if=/dev/zero of=$TMPFILE bs=1k count=512 > /dev/null 2>&1 ++ ++echo mke2fs -q -F -o Linux -T ext4 -O ^metadata_csum,64bit -E lazy_itable_init=1 -b 1024 $TMPFILE > $OUT ++$MKE2FS -q -F -o Linux -T ext4 -O ^metadata_csum,64bit -E lazy_itable_init=1 -b 1024 $TMPFILE >> $OUT 2>&1 ++crc0=`$CRCSUM $TMPFILE` ++echo $CRCSUM before debugfs $crc0 >> $OUT ++ ++echo using debugfs to test e2undo >> $OUT ++$DEBUGFS -w -z $TDB_FILE -R 'zap -p 0x55 0' $TMPFILE >> $OUT 2>&1 ++crc1=`$CRCSUM $TMPFILE` ++echo $CRCSUM after debugfs $crc1 >> $OUT ++ ++$E2UNDO $TDB_FILE $TMPFILE >> $OUT 2>&1 ++crc2=`$CRCSUM $TMPFILE` ++echo $CRCSUM after e2undo $crc2 >> $OUT ++ ++if [ $crc0 = $crc2 ] && [ $crc1 != $crc2 ]; then ++ echo "$test_name: $test_description: ok" ++ touch $test_name.ok ++else ++ ln -f $test_name.log $test_name.failed ++ echo "$test_name: $test_description: failed" ++fi ++rm -f $TDB_FILE $TMPFILE ++fi +--- /dev/null ++++ b/tests/u_dryrun/script +@@ -0,0 +1,32 @@ ++test_description="e2undo dry run" ++if test -x $E2UNDO_EXE; then ++ ++TDB_FILE=${TMPDIR:-/tmp}/tune2fs-$(basename $TMPFILE).e2undo ++OUT=$test_name.log ++rm -f $TDB_FILE >/dev/null 2>&1 ++ ++dd if=/dev/zero of=$TMPFILE bs=1k count=512 > /dev/null 2>&1 ++ ++echo mke2fs -q -F -o Linux -T ext4 -O ^metadata_csum,64bit -E lazy_itable_init=1 -b 1024 $TMPFILE > $OUT ++$MKE2FS -q -F -o Linux -T ext4 -O ^metadata_csum,64bit -E lazy_itable_init=1 -b 1024 $TMPFILE >> $OUT 2>&1 ++crc0=`$CRCSUM $TMPFILE` ++echo $CRCSUM before tune2fs $crc0 >> $OUT ++ ++echo using tune2fs to test e2undo >> $OUT ++$TUNE2FS -O metadata_csum -z $TDB_FILE $TMPFILE >> $OUT 2>&1 ++crc1=`$CRCSUM $TMPFILE` ++echo $CRCSUM after tune2fs $crc1 >> $OUT ++ ++$E2UNDO -n $TDB_FILE $TMPFILE >> $OUT 2>&1 ++crc2=`$CRCSUM $TMPFILE` ++echo $CRCSUM after e2undo $crc2 >> $OUT ++ ++if [ $crc1 = $crc2 ] && [ $crc1 != $crc0 ]; then ++ echo "$test_name: $test_description: ok" ++ touch $test_name.ok ++else ++ ln -f $test_name.log $test_name.failed ++ echo "$test_name: $test_description: failed" ++fi ++rm -f $TDB_FILE $TMPFILE ++fi +--- /dev/null ++++ b/tests/u_e2fsck_opt/script +@@ -0,0 +1,32 @@ ++test_description="e2undo with e2fsck -z" ++if test -x $E2UNDO_EXE; then ++ ++TDB_FILE=${TMPDIR:-/tmp}/e2fsck-$(basename $TMPFILE).e2undo ++OUT=$test_name.log ++rm -f $TDB_FILE >/dev/null 2>&1 ++ ++dd if=/dev/zero of=$TMPFILE bs=1k count=512 > /dev/null 2>&1 ++ ++echo mke2fs -q -F -o Linux -T ext4 -O ^metadata_csum,64bit -E lazy_itable_init=1 -b 1024 $TMPFILE > $OUT ++$MKE2FS -q -F -o Linux -T ext4 -O ^metadata_csum,64bit -E lazy_itable_init=1 -b 1024 $TMPFILE >> $OUT 2>&1 ++crc0=`$CRCSUM $TMPFILE` ++echo $CRCSUM before e2fsck $crc0 >> $OUT ++ ++echo using e2fsck to test e2undo >> $OUT ++$FSCK -f -y -z $TDB_FILE $TMPFILE >> $OUT 2>&1 ++crc1=`$CRCSUM $TMPFILE` ++echo $CRCSUM after e2fsck $crc1 >> $OUT ++ ++$E2UNDO $TDB_FILE $TMPFILE >> $OUT 2>&1 ++crc2=`$CRCSUM $TMPFILE` ++echo $CRCSUM after e2undo $crc2 >> $OUT ++ ++if [ $crc0 = $crc2 ] && [ $crc1 != $crc2 ]; then ++ echo "$test_name: $test_description: ok" ++ touch $test_name.ok ++else ++ ln -f $test_name.log $test_name.failed ++ echo "$test_name: $test_description: failed" ++fi ++rm -f $TDB_FILE $TMPFILE ++fi +--- /dev/null ++++ b/tests/u_errorout/script +@@ -0,0 +1,49 @@ ++test_description="e2undo a failed command" ++if test -x $RESIZE2FS_EXE -a -x $E2UNDO_EXE; then ++ ++TDB_FILE=${TMPDIR:-/tmp}/resize2fs-$(basename $TMPFILE).e2undo ++OUT=$test_name.log ++rm -f $TDB_FILE >/dev/null 2>&1 ++ ++echo check that we cant append a bad undo file > $OUT ++ ++dd if=/dev/zero of=$TMPFILE bs=1k count=512 > /dev/null 2>&1 ++crc0=`$CRCSUM $TMPFILE` ++echo $CRCSUM before mke2fs $crc0 >> $OUT ++ ++CONF=$TMPFILE.conf ++cat > $CONF << ENDL ++[fs_types] ++ ext4h = { ++ features = ^has_journal,extent,huge_file,flex_bg,uninit_bg,dir_nlink,extra_isize,sparse_super,filetype,dir_index,ext_attr,resize_inode ++ blocksize = 4096 ++ inode_size = 256 ++ make_hugefiles = true ++ hugefiles_dir = / ++ hugefiles_slack = 0 ++ hugefiles_name = aaaaa ++ hugefiles_digits = 4 ++ hugefiles_size = 1K ++ zero_hugefiles = false ++ } ++ENDL ++ ++echo mke2fs -q -F -o Linux -T ext4h -O ^metadata_csum,^64bit -E lazy_itable_init=1 -b 1024 -z $TDB_FILE.0 $TMPFILE 524288 >> $OUT ++MKE2FS_CONFIG=$CONF $MKE2FS -q -F -o Linux -T ext4h -O ^metadata_csum,^64bit -E lazy_itable_init=1 -b 1024 -z $TDB_FILE.0 -d /etc/ $TMPFILE >> $OUT 2>&1 ++crc1=`$CRCSUM $TMPFILE` ++echo $CRCSUM after mke2fs $crc1 >> $OUT ++ ++echo roll back mke2fs >> $OUT ++$E2UNDO $TDB_FILE.0 $TMPFILE >> $OUT 2>&1 ++crc2=`$CRCSUM $TMPFILE` ++echo $CRCSUM after e2undo mke2fs $crc2 >> $OUT ++ ++if [ $crc0 != $crc1 ] && [ $crc1 != $crc2 ] && [ $crc0 = $crc2 ]; then ++ echo "$test_name: $test_description: ok" ++ touch $test_name.ok ++else ++ ln -f $test_name.log $test_name.failed ++ echo "$test_name: $test_description: failed" ++fi ++rm -f $TDB_FILE.0 $TMPFILE $CONF ++fi +--- /dev/null ++++ b/tests/u_force/script +@@ -0,0 +1,40 @@ ++test_description="e2undo force" ++if test -x $E2UNDO_EXE; then ++ ++TDB_FILE=${TMPDIR:-/tmp}/tune2fs-$(basename $TMPFILE).e2undo ++OUT=$test_name.log ++rm -f $TDB_FILE >/dev/null 2>&1 ++ ++dd if=/dev/zero of=$TMPFILE bs=1k count=512 > /dev/null 2>&1 ++ ++echo mke2fs -q -F -o Linux -T ext4 -O ^metadata_csum,64bit -E lazy_itable_init=1 -b 1024 $TMPFILE > $OUT ++$MKE2FS -q -F -o Linux -T ext4 -O ^metadata_csum,64bit -E lazy_itable_init=1 -b 1024 $TMPFILE >> $OUT 2>&1 ++crc0=`$CRCSUM $TMPFILE` ++echo $CRCSUM before tune2fs $crc0 >> $OUT ++ ++echo using tune2fs to test e2undo >> $OUT ++$TUNE2FS -O metadata_csum -z $TDB_FILE $TMPFILE >> $OUT 2>&1 ++crc1=`$CRCSUM $TMPFILE` ++echo $CRCSUM after tune2fs $crc1 >> $OUT ++ ++dd if=/dev/zero of=$TDB_FILE bs=4 count=1 seek=127 conv=notrunc 2> /dev/null ++ ++$E2UNDO $TDB_FILE $TMPFILE >> $OUT 2>&1 ++crc2=`$CRCSUM $TMPFILE` ++echo $CRCSUM after e2undo $crc2 >> $OUT ++ ++$E2UNDO -f $TDB_FILE $TMPFILE >> $OUT 2>&1 ++crc3=`$CRCSUM $TMPFILE` ++echo $CRCSUM after e2undo -f $crc3 >> $OUT ++ ++MUST_FSCK=$($DUMPE2FS $TMPFILE 2> /dev/null | grep 'Filesystem state:.*not clean' -c ) ++ ++if [ $MUST_FSCK -eq 1 ] && [ $crc0 != $crc3 ] && [ $crc1 = $crc2 ] && [ $crc2 != $crc0 ]; then ++ echo "$test_name: $test_description: ok" ++ touch $test_name.ok ++else ++ ln -f $test_name.log $test_name.failed ++ echo "$test_name: $test_description: failed" ++fi ++rm -f $TDB_FILE $TMPFILE ++fi +--- /dev/null ++++ b/tests/u_force_dryrun/script +@@ -0,0 +1,38 @@ ++test_description="force dry-run replay of corrupt e2undo block data" ++if test -x $E2UNDO_EXE; then ++ ++E2FSPROGS_UNDO_DIR=${TMPDIR:-/tmp} ++export E2FSPROGS_UNDO_DIR ++TDB_FILE=$E2FSPROGS_UNDO_DIR/tune2fs-$(basename $TMPFILE).e2undo ++OUT=$test_name.log ++rm -f $TDB_FILE >/dev/null 2>&1 ++ ++dd if=/dev/zero of=$TMPFILE bs=1k count=512 > /dev/null 2>&1 ++ ++echo mke2fs -q -F -o Linux -b 1024 $TMPFILE > $OUT ++$MKE2FS -q -F -o Linux -I 128 -b 1024 $TMPFILE >> $OUT 2>&1 ++crc0=`$CRCSUM $TMPFILE` ++echo $CRCSUM before tune2fs $crc0 >> $OUT ++ ++echo using tune2fs to test e2undo >> $OUT ++$TUNE2FS -I 256 $TMPFILE >> $OUT 2>&1 ++crc1=`$CRCSUM $TMPFILE` ++echo $CRCSUM after tune2fs $crc1 >> $OUT ++ ++undo_blks=$(( $(stat -c '%s' $TDB_FILE 2>/dev/null || stat -f '%z' $TDB_FILE 2>/dev/null) / 1024 )) ++dd if=/dev/zero of=$TDB_FILE bs=1024 count=1 seek=$((undo_blks - 2)) conv=notrunc > /dev/null 2>&1 ++ ++$E2UNDO -f -n $TDB_FILE $TMPFILE >> $OUT 2>&1 ++res=$? ++crc2=`$CRCSUM $TMPFILE` ++echo $CRCSUM after e2undo $crc2 >> $OUT ++ ++if [ $crc2 = $crc1 ] && [ $crc2 != $crc0 ]; then ++ echo "$test_name: $test_description: ok" ++ touch $test_name.ok ++else ++ ln -f $test_name.log $test_name.failed ++ echo "$test_name: $test_description: failed" ++fi ++rm -f $TDB_FILE $TMPFILE ++fi +--- /dev/null ++++ b/tests/u_incomplete/script +@@ -0,0 +1,38 @@ ++test_description="e2undo with incomplete undo file" ++if test -x $E2UNDO_EXE; then ++ ++TDB_FILE=${TMPDIR:-/tmp}/tune2fs-$(basename $TMPFILE).e2undo ++OUT=$test_name.log ++rm -f $TDB_FILE >/dev/null 2>&1 ++ ++dd if=/dev/zero of=$TMPFILE bs=1k count=512 > /dev/null 2>&1 ++ ++echo mke2fs -q -F -o Linux -T ext4 -O ^metadata_csum,64bit -E lazy_itable_init=1 -b 1024 $TMPFILE > $OUT ++$MKE2FS -q -F -o Linux -T ext4 -O ^metadata_csum,64bit -E lazy_itable_init=1 -b 1024 $TMPFILE >> $OUT 2>&1 ++crc0=`$CRCSUM $TMPFILE` ++echo $CRCSUM before tune2fs $crc0 >> $OUT ++ ++echo using tune2fs to test e2undo >> $OUT ++UNDO_IO_SIMULATE_UNFINISHED=1 $TUNE2FS -O metadata_csum -z $TDB_FILE $TMPFILE >> $OUT 2>&1 ++crc1=`$CRCSUM $TMPFILE` ++echo $CRCSUM after tune2fs $crc1 >> $OUT ++ ++$E2UNDO $TDB_FILE $TMPFILE >> $OUT 2>&1 ++crc2=`$CRCSUM $TMPFILE` ++echo $CRCSUM after e2undo $crc2 >> $OUT ++ ++$FSCK -y $TMPFILE >> $OUT 2>&1 ++fsck_res=$? ++crc3=`$CRCSUM $TMPFILE` ++echo $CRCSUM after fsck $crc3 >> $OUT ++echo fsck result $fsck_res >> $OUT ++ ++if [ $crc0 != $crc2 ] && [ $crc1 != $crc2 ] && [ $crc0 != $crc1 ] && [ $fsck_res -eq 1 ]; then ++ echo "$test_name: $test_description: ok" ++ touch $test_name.ok ++else ++ ln -f $test_name.log $test_name.failed ++ echo "$test_name: $test_description: failed" ++fi ++rm -f $TDB_FILE $TMPFILE ++fi +--- a/tests/u_mke2fs/script ++++ b/tests/u_mke2fs/script +@@ -1,7 +1,7 @@ + test_description="e2undo with mke2fs" + if test -x $E2UNDO_EXE; then + +-E2FSPROGS_UNDO_DIR=/tmp ++E2FSPROGS_UNDO_DIR=${TMPDIR:-/tmp} + export E2FSPROGS_UNDO_DIR + TDB_FILE=$E2FSPROGS_UNDO_DIR/mke2fs-$(basename $TMPFILE).e2undo + OUT=$test_name.log +@@ -19,7 +19,7 @@ + new_crc=`$CRCSUM $TMPFILE` + echo $CRCSUM after mke2fs $new_crc >> $OUT + +-$E2UNDO_EXE $TDB_FILE $TMPFILE >> $OUT 2>&1 ++$E2UNDO $TDB_FILE $TMPFILE >> $OUT 2>&1 + new_crc=`$CRCSUM $TMPFILE` + echo $CRCSUM after e2undo $new_crc >> $OUT + +--- /dev/null ++++ b/tests/u_mke2fs_opt/script +@@ -0,0 +1,32 @@ ++test_description="e2undo with mke2fs -z" ++if test -x $E2UNDO_EXE; then ++ ++TDB_FILE=${TMPDIR:-/tmp}/mke2fs-$(basename $TMPFILE).e2undo ++OUT=$test_name.log ++rm -f $TDB_FILE >/dev/null 2>&1 ++ ++dd if=/dev/zero of=$TMPFILE bs=1k count=512 > /dev/null 2>&1 ++ ++echo mke2fs -F -o Linux -I 128 -b 1024 test.img > $OUT ++$MKE2FS -F -o Linux -I 128 -b 1024 $TMPFILE >> $OUT 2>&1 ++crc0=`$CRCSUM $TMPFILE` ++echo $CRCSUM before mke2fs $crc0 >> $OUT ++ ++echo using mke2fs to test e2undo >> $OUT ++$MKE2FS -q -F -o Linux -T ext4 -E lazy_itable_init=1 -b 1024 -z $TDB_FILE $TMPFILE >> $OUT 2>&1 ++crc1=`$CRCSUM $TMPFILE` ++echo $CRCSUM after mke2fs $crc1 >> $OUT ++ ++$E2UNDO $TDB_FILE $TMPFILE >> $OUT 2>&1 ++crc2=`$CRCSUM $TMPFILE` ++echo $CRCSUM after e2undo $crc2 >> $OUT ++ ++if [ $crc0 = $crc2 ] && [ $crc1 != $crc2 ]; then ++ echo "$test_name: $test_description: ok" ++ touch $test_name.ok ++else ++ ln -f $test_name.log $test_name.failed ++ echo "$test_name: $test_description: failed" ++fi ++rm -f $TDB_FILE $TMPFILE ++fi +--- /dev/null ++++ b/tests/u_mke2fs_opt_oddsize/script +@@ -0,0 +1,31 @@ ++test_description="e2undo with mke2fs -z and non-32k-aligned bdev size" ++if test -x $E2UNDO_EXE; then ++ ++TDB_FILE=${TMPDIR:-/tmp}/mke2fs-$(basename $TMPFILE).e2undo ++OUT=$test_name.log ++rm -f $TDB_FILE >/dev/null 2>&1 ++ ++dd if=/dev/zero of=$TMPFILE bs=1k count=512 > /dev/null 2>&1 ++yes "abc123abc123abc" | dd bs=1k count=8 >> $TMPFILE 2> /dev/null ++ ++crc0=`$CRCSUM $TMPFILE` ++echo $CRCSUM before mke2fs $crc0 > $OUT ++ ++echo using mke2fs to test e2undo >> $OUT ++$MKE2FS -q -F -o Linux -T ext4 -E lazy_itable_init=1 -b 1024 -z $TDB_FILE $TMPFILE >> $OUT 2>&1 ++crc1=`$CRCSUM $TMPFILE` ++echo $CRCSUM after mke2fs $crc1 >> $OUT ++ ++$E2UNDO $TDB_FILE $TMPFILE >> $OUT 2>&1 ++crc2=`$CRCSUM $TMPFILE` ++echo $CRCSUM after e2undo $crc2 >> $OUT ++ ++if [ $crc0 = $crc2 ] && [ $crc1 != $crc2 ]; then ++ echo "$test_name: $test_description: ok" ++ touch $test_name.ok ++else ++ ln -f $test_name.log $test_name.failed ++ echo "$test_name: $test_description: failed" ++fi ++rm -f $TDB_FILE $TMPFILE ++fi +--- /dev/null ++++ b/tests/u_not_undo/script +@@ -0,0 +1,28 @@ ++test_description="e2undo a non-undo file" ++if test -x $E2UNDO_EXE; then ++ ++TDB_FILE=${TMPDIR:-/tmp}/tune2fs-$(basename $TMPFILE).e2undo ++OUT=$test_name.log ++rm -f $TDB_FILE >/dev/null 2>&1 ++ ++dd if=/dev/zero of=$TMPFILE bs=1k count=512 > /dev/null 2>&1 ++dd if=/dev/zero of=$TDB_FILE bs=1k count=512 > /dev/null 2>&1 ++ ++crc0=`$CRCSUM $TMPFILE` ++echo $CRCSUM before e2undo $crc0 > $OUT ++ ++od -tx1 -Ad -c < $TDB_FILE >> $OUT ++ ++$E2UNDO $TDB_FILE $TMPFILE >> $OUT 2>&1 ++crc3=`$CRCSUM $TMPFILE` ++echo $CRCSUM after e2undo $crc3 >> $OUT ++ ++if [ $crc3 = $crc0 ]; then ++ echo "$test_name: $test_description: ok" ++ touch $test_name.ok ++else ++ ln -f $test_name.log $test_name.failed ++ echo "$test_name: $test_description: failed" ++fi ++rm -f $TDB_FILE $TMPFILE ++fi +--- /dev/null ++++ b/tests/u_onefile_bad/script +@@ -0,0 +1,115 @@ ++test_description="check that we cant append a bad undo file" ++if test -x $RESIZE2FS_EXE -a -x $E2UNDO_EXE; then ++ ++TDB_FILE=${TMPDIR:-/tmp}/resize2fs-$(basename $TMPFILE).e2undo ++OUT=$test_name.log ++rm -f $TDB_FILE >/dev/null 2>&1 ++fail=0 ++ ++echo check that we cant append a bad undo file > $OUT ++ ++dd if=/dev/zero of=$TMPFILE bs=1k count=512 > /dev/null 2>&1 ++crc0=`$CRCSUM $TMPFILE` ++echo $CRCSUM before mke2fs $crc0 >> $OUT ++ ++CONF=$TMPFILE.conf ++cat > $CONF << ENDL ++[fs_types] ++ ext4h = { ++ features = has_journal,extent,huge_file,flex_bg,uninit_bg,dir_nlink,extra_isize,sparse_super,filetype,dir_index,ext_attr,resize_inode ++ blocksize = 4096 ++ inode_size = 256 ++ make_hugefiles = true ++ hugefiles_dir = / ++ hugefiles_slack = 0 ++ hugefiles_name = aaaaa ++ hugefiles_digits = 4 ++ hugefiles_size = 1M ++ zero_hugefiles = false ++ } ++ENDL ++ ++echo mke2fs -q -F -o Linux -T ext4h -O ^metadata_csum,^64bit -E lazy_itable_init=1 -b 4096 -z $TDB_FILE.0 $TMPFILE 524288 >> $OUT ++MKE2FS_CONFIG=$CONF $MKE2FS -q -F -o Linux -T ext4h -O ^metadata_csum,^64bit -E lazy_itable_init=1 -b 4096 -z $TDB_FILE.0 $TMPFILE >> $OUT 2>&1 ++crc1=`$CRCSUM $TMPFILE` ++echo $CRCSUM after mke2fs $crc1 >> $OUT ++features="$($DUMPE2FS -h $TMPFILE 2> /dev/null | grep 'Filesystem features:')" ++if [ "$(echo "${features}" | grep "metadata_csum" -c)" -gt 0 ] || [ "$(echo "${features}" | grep 64bit -c)" -gt 0 ]; then ++ echo "FS features: ${features}" >> $OUT ++ echo "Should not have 64bit or metadata_csum set" >> $OUT ++ fail=1 ++fi ++$FSCK -f -n $TMPFILE >> $OUT 2>&1 || fail=1 ++ ++echo using resize2fs to test e2undo >> $OUT ++$RESIZE2FS -z $TDB_FILE.1 -b $TMPFILE >> $OUT 2>&1 ++crc2=`$CRCSUM $TMPFILE` ++echo $CRCSUM after resize2fs $crc2 >> $OUT ++features="$($DUMPE2FS -h $TMPFILE 2> /dev/null | grep 'Filesystem features:')" ++if [ "$(echo "${features}" | grep "metadata_csum" -c)" -gt 0 ] || [ "$(echo "${features}" | grep 64bit -c)" -lt 1 ]; then ++ echo "FS features: ${features}" >> $OUT ++ echo "Should have 64bit but not metadata_csum set" >> $OUT ++ fail=1 ++fi ++$FSCK -f -n $TMPFILE >> $OUT 2>&1 || fail=1 ++ ++echo corrupt $TDB_FILE.1 >> $OUT ++dd if=/dev/zero of=$TDB_FILE.1 bs=4096 count=1 skip=1 2> /dev/null ++ ++echo using tune2fs to test e2undo >> $OUT ++$TUNE2FS -O metadata_csum -z $TDB_FILE.1 $TMPFILE >> $OUT 2>&1 ++crc3=`$CRCSUM $TMPFILE` ++echo $CRCSUM after tune2fs $crc3 >> $OUT ++features="$($DUMPE2FS -h $TMPFILE 2> /dev/null | grep 'Filesystem features:')" ++if [ "$(echo "${features}" | grep "metadata_csum" -c)" -gt 0 ] || [ "$(echo "${features}" | grep 64bit -c)" -lt 1 ]; then ++ echo "FS features: ${features}" >> $OUT ++ echo "Should have 64bit but not metadata_csum set" >> $OUT ++ fail=1 ++fi ++$FSCK -f -n $TMPFILE >> $OUT 2>&1 || fail=1 ++ ++echo using e2fsck to test e2undo >> $OUT ++$FSCK -f -y -D -z $TDB_FILE.1 $TMPFILE >> $OUT 2>&1 ++crc4=`$CRCSUM $TMPFILE` ++echo $CRCSUM after e2fsck $crc4 >> $OUT ++features="$($DUMPE2FS -h $TMPFILE 2> /dev/null | grep 'Filesystem features:')" ++if [ "$(echo "${features}" | grep "metadata_csum" -c)" -gt 0 ] || [ "$(echo "${features}" | grep 64bit -c)" -lt 1 ]; then ++ echo "FS features: ${features}" >> $OUT ++ echo "Should have 64bit but not metadata_csum set" >> $OUT ++ fail=1 ++fi ++$FSCK -f -n $TMPFILE >> $OUT 2>&1 || fail=1 ++ ++echo roll back e2fsck/tune2fs/resize2fs >> $OUT ++$E2UNDO $TDB_FILE.1 $TMPFILE >> $OUT 2>&1 ++crc1_2=`$CRCSUM $TMPFILE` ++echo $CRCSUM after e2undo e2fsck/tune2fs/resize2fs $crc1_2 >> $OUT ++features="$($DUMPE2FS -h $TMPFILE 2> /dev/null | grep 'Filesystem features:')" ++if [ "$(echo "${features}" | grep "metadata_csum" -c)" -gt 0 ] || [ "$(echo "${features}" | grep 64bit -c)" -lt 1 ]; then ++ echo "FS features: ${features}" >> $OUT ++ echo "Should have 64bit but not metadata_csum set" >> $OUT ++ fail=1 ++fi ++$FSCK -f -n $TMPFILE >> $OUT 2>&1 || fail=1 ++ ++echo roll back mke2fs >> $OUT ++$E2UNDO $TDB_FILE.0 $TMPFILE >> $OUT 2>&1 ++crc0_2=`$CRCSUM $TMPFILE` ++echo $CRCSUM after e2undo mke2fs $crc0_2 >> $OUT ++features="$($DUMPE2FS -h $TMPFILE 2> /dev/null | grep 'Filesystem features:')" ++if [ "$(echo "${features}" | grep "metadata_csum" -c)" -gt 0 ] || [ "$(echo "${features}" | grep 64bit -c)" -lt 1 ]; then ++ echo "FS features: ${features}" >> $OUT ++ echo "Should have 64bit but not metadata_csum set" >> $OUT ++ fail=1 ++fi ++$FSCK -f -n $TMPFILE >> $OUT 2>&1 || fail=1 ++ ++if [ $fail -eq 0 ] && [ $crc0 != $crc1 ] && [ $crc1 != $crc2 ] && [ $crc2 = $crc3 ] && [ $crc3 = $crc4 ] && [ $crc1_2 = $crc2 ] && [ $crc0_2 = $crc2 ]; then ++ echo "$test_name: $test_description: ok" ++ touch $test_name.ok ++else ++ ln -f $test_name.log $test_name.failed ++ echo "$test_name: $test_description: failed" ++fi ++rm -f $TDB_FILE.0 $TDB_FILE.1 $TMPFILE $CONF ++fi +--- /dev/null ++++ b/tests/u_resize2fs_opt/script +@@ -0,0 +1,32 @@ ++test_description="e2undo with resize2fs -z" ++if test -x $RESIZE2FS_EXE -a -x $E2UNDO_EXE; then ++ ++TDB_FILE=${TMPDIR:-/tmp}/resize2fs-$(basename $TMPFILE).e2undo ++OUT=$test_name.log ++rm -f $TDB_FILE >/dev/null 2>&1 ++ ++dd if=/dev/zero of=$TMPFILE bs=1k count=512 > /dev/null 2>&1 ++ ++echo mke2fs -q -F -o Linux -T ext4 -O ^metadata_csum,64bit -E lazy_itable_init=1 -b 1024 $TMPFILE 256 > $OUT ++$MKE2FS -q -F -o Linux -T ext4 -O ^metadata_csum,64bit -E lazy_itable_init=1 -b 1024 $TMPFILE 256 >> $OUT 2>&1 ++crc0=`$CRCSUM $TMPFILE` ++echo $CRCSUM before resize2fs $crc0 >> $OUT ++ ++echo using resize2fs to test e2undo >> $OUT ++$RESIZE2FS -z $TDB_FILE $TMPFILE 512 >> $OUT 2>&1 ++crc1=`$CRCSUM $TMPFILE` ++echo $CRCSUM after resize2fs $crc1 >> $OUT ++ ++$E2UNDO $TDB_FILE $TMPFILE >> $OUT 2>&1 ++crc2=`$CRCSUM $TMPFILE` ++echo $CRCSUM after e2undo $crc2 >> $OUT ++ ++if [ $crc0 = $crc2 ] && [ $crc1 != $crc2 ]; then ++ echo "$test_name: $test_description: ok" ++ touch $test_name.ok ++else ++ ln -f $test_name.log $test_name.failed ++ echo "$test_name: $test_description: failed" ++fi ++rm -f $TDB_FILE $TMPFILE ++fi +--- /dev/null ++++ b/tests/u_revert_64bitmcsum_onefile/script +@@ -0,0 +1,112 @@ ++test_description="convert fs to 64bit,metadata_csum and revert as one undo file" ++if test -x $RESIZE2FS_EXE -a -x $E2UNDO_EXE; then ++ ++TDB_FILE=${TMPDIR:-/tmp}/resize2fs-$(basename $TMPFILE).e2undo ++OUT=$test_name.log ++rm -f $TDB_FILE >/dev/null 2>&1 ++fail=0 ++ ++echo convert fs to 64bit,metadata_csum and revert both changes as one undo file > $OUT ++ ++dd if=/dev/zero of=$TMPFILE bs=1k count=512 > /dev/null 2>&1 ++crc0=`$CRCSUM $TMPFILE` ++echo $CRCSUM before mke2fs $crc0 >> $OUT ++ ++CONF=$TMPFILE.conf ++cat > $CONF << ENDL ++[fs_types] ++ ext4h = { ++ features = has_journal,extent,huge_file,flex_bg,uninit_bg,dir_nlink,extra_isize,sparse_super,filetype,dir_index,ext_attr,resize_inode ++ blocksize = 4096 ++ inode_size = 256 ++ make_hugefiles = true ++ hugefiles_dir = / ++ hugefiles_slack = 0 ++ hugefiles_name = aaaaa ++ hugefiles_digits = 4 ++ hugefiles_size = 1M ++ zero_hugefiles = false ++ } ++ENDL ++ ++echo mke2fs -q -F -o Linux -T ext4h -O ^metadata_csum,^64bit -E lazy_itable_init=1 -b 4096 -z $TDB_FILE.0 $TMPFILE 524288 >> $OUT ++MKE2FS_CONFIG=$CONF $MKE2FS -q -F -o Linux -T ext4h -O ^metadata_csum,^64bit -E lazy_itable_init=1 -b 4096 -z $TDB_FILE.0 $TMPFILE >> $OUT 2>&1 ++crc1=`$CRCSUM $TMPFILE` ++echo $CRCSUM after mke2fs $crc1 >> $OUT ++features="$($DUMPE2FS -h $TMPFILE 2> /dev/null | grep 'Filesystem features:')" ++if [ "$(echo "${features}" | grep "metadata_csum" -c)" -gt 0 ] || [ "$(echo "${features}" | grep 64bit -c)" -gt 0 ]; then ++ echo "FS features: ${features}" >> $OUT ++ echo "Should not have 64bit or metadata_csum set" >> $OUT ++ fail=1 ++fi ++$FSCK -f -n $TMPFILE >> $OUT 2>&1 || fail=1 ++ ++echo using resize2fs to test e2undo >> $OUT ++$RESIZE2FS -z $TDB_FILE.1 -b $TMPFILE >> $OUT 2>&1 ++crc2=`$CRCSUM $TMPFILE` ++echo $CRCSUM after resize2fs $crc2 >> $OUT ++features="$($DUMPE2FS -h $TMPFILE 2> /dev/null | grep 'Filesystem features:')" ++if [ "$(echo "${features}" | grep "metadata_csum" -c)" -gt 0 ] || [ "$(echo "${features}" | grep 64bit -c)" -lt 1 ]; then ++ echo "FS features: ${features}" >> $OUT ++ echo "Should have 64bit but not metadata_csum set" >> $OUT ++ fail=1 ++fi ++$FSCK -f -n $TMPFILE >> $OUT 2>&1 || fail=1 ++ ++echo using tune2fs to test e2undo >> $OUT ++$TUNE2FS -O metadata_csum -z $TDB_FILE.1 $TMPFILE >> $OUT 2>&1 ++crc3=`$CRCSUM $TMPFILE` ++echo $CRCSUM after tune2fs $crc3 >> $OUT ++features="$($DUMPE2FS -h $TMPFILE 2> /dev/null | grep 'Filesystem features:')" ++if [ "$(echo "${features}" | grep "metadata_csum" -c)" -lt 1 ] || [ "$(echo "${features}" | grep 64bit -c)" -lt 1 ]; then ++ echo "FS features: ${features}" >> $OUT ++ echo "Should have 64bit and metadata_csum set" >> $OUT ++ fail=1 ++fi ++$FSCK -f -n $TMPFILE >> $OUT 2>&1 || fail=1 ++ ++echo using e2fsck to test e2undo >> $OUT ++$FSCK -f -y -D -z $TDB_FILE.1 $TMPFILE >> $OUT 2>&1 ++crc4=`$CRCSUM $TMPFILE` ++echo $CRCSUM after e2fsck $crc4 >> $OUT ++features="$($DUMPE2FS -h $TMPFILE 2> /dev/null | grep 'Filesystem features:')" ++if [ "$(echo "${features}" | grep "metadata_csum" -c)" -lt 1 ] || [ "$(echo "${features}" | grep 64bit -c)" -lt 1 ]; then ++ echo "FS features: ${features}" >> $OUT ++ echo "Should have 64bit and metadata_csum set" >> $OUT ++ fail=1 ++fi ++$FSCK -f -n $TMPFILE >> $OUT 2>&1 || fail=1 ++ ++echo roll back e2fsck/tune2fs/resize2fs >> $OUT ++$E2UNDO $TDB_FILE.1 $TMPFILE >> $OUT 2>&1 ++crc1_2=`$CRCSUM $TMPFILE` ++echo $CRCSUM after e2undo e2fsck/tune2fs/resize2fs $crc1_2 >> $OUT ++features="$($DUMPE2FS -h $TMPFILE 2> /dev/null | grep 'Filesystem features:')" ++if [ "$(echo "${features}" | grep "metadata_csum" -c)" -gt 0 ] || [ "$(echo "${features}" | grep 64bit -c)" -gt 0 ]; then ++ echo "FS features: ${features}" >> $OUT ++ echo "Should not have 64bit or metadata_csum set" >> $OUT ++ fail=1 ++fi ++$FSCK -f -n $TMPFILE >> $OUT 2>&1 || fail=1 ++ ++echo roll back mke2fs >> $OUT ++$E2UNDO $TDB_FILE.0 $TMPFILE >> $OUT 2>&1 ++crc0_2=`$CRCSUM $TMPFILE` ++echo $CRCSUM after e2undo mke2fs $crc0_2 >> $OUT ++features="$($DUMPE2FS -h $TMPFILE 2> /dev/null | grep 'Filesystem features:')" ++if [ -n "${features}" ]; then ++ echo "FS features: ${features}" >> $OUT ++ echo "Should not have any features set" >> $OUT ++ fail=1 ++fi ++$FSCK -f -n $TMPFILE >> $OUT 2>&1 && fail=1 ++ ++if [ $fail -eq 0 ] && [ $crc0 = $crc0_2 ] && [ $crc1 = $crc1_2 ]; then ++ echo "$test_name: $test_description: ok" ++ touch $test_name.ok ++else ++ ln -f $test_name.log $test_name.failed ++ echo "$test_name: $test_description: failed" ++fi ++rm -f $TDB_FILE.0 $TDB_FILE.1 $TMPFILE $CONF ++fi +--- /dev/null ++++ b/tests/u_revert_all_onefile/script +@@ -0,0 +1,100 @@ ++test_description="convert fs to 64bit,metadata_csum and revert as one undo file" ++if test -x $RESIZE2FS_EXE -a -x $E2UNDO_EXE; then ++ ++TDB_FILE=${TMPDIR:-/tmp}/resize2fs-$(basename $TMPFILE).e2undo ++OUT=$test_name.log ++rm -f $TDB_FILE >/dev/null 2>&1 ++fail=0 ++ ++echo convert fs to 64bit,metadata_csum and revert both changes as one undo file > $OUT ++ ++dd if=/dev/zero of=$TMPFILE bs=1k count=512 > /dev/null 2>&1 ++crc0=`$CRCSUM $TMPFILE` ++echo $CRCSUM before mke2fs $crc0 >> $OUT ++ ++CONF=$TMPFILE.conf ++cat > $CONF << ENDL ++[fs_types] ++ ext4h = { ++ features = has_journal,extent,huge_file,flex_bg,uninit_bg,dir_nlink,extra_isize,sparse_super,filetype,dir_index,ext_attr,resize_inode ++ blocksize = 4096 ++ inode_size = 256 ++ make_hugefiles = true ++ hugefiles_dir = / ++ hugefiles_slack = 0 ++ hugefiles_name = aaaaa ++ hugefiles_digits = 4 ++ hugefiles_size = 1M ++ zero_hugefiles = false ++ } ++ENDL ++ ++echo mke2fs -q -F -o Linux -T ext4h -O ^metadata_csum,^64bit -E lazy_itable_init=1 -b 4096 -z $TDB_FILE.0 $TMPFILE 524288 >> $OUT ++MKE2FS_CONFIG=$CONF $MKE2FS -q -F -o Linux -T ext4h -O ^metadata_csum,^64bit -E lazy_itable_init=1 -b 4096 -z $TDB_FILE.0 $TMPFILE >> $OUT 2>&1 ++crc1=`$CRCSUM $TMPFILE` ++echo $CRCSUM after mke2fs $crc1 >> $OUT ++features="$($DUMPE2FS -h $TMPFILE 2> /dev/null | grep 'Filesystem features:')" ++if [ "$(echo "${features}" | grep "metadata_csum" -c)" -gt 0 ] || [ "$(echo "${features}" | grep 64bit -c)" -gt 0 ]; then ++ echo "FS features: ${features}" >> $OUT ++ echo "Should not have 64bit or metadata_csum set" >> $OUT ++ fail=1 ++fi ++$FSCK -f -n $TMPFILE >> $OUT 2>&1 || fail=1 ++ ++echo using resize2fs to test e2undo >> $OUT ++$RESIZE2FS -z $TDB_FILE.0 -b $TMPFILE >> $OUT 2>&1 ++crc2=`$CRCSUM $TMPFILE` ++echo $CRCSUM after resize2fs $crc2 >> $OUT ++features="$($DUMPE2FS -h $TMPFILE 2> /dev/null | grep 'Filesystem features:')" ++if [ "$(echo "${features}" | grep "metadata_csum" -c)" -gt 0 ] || [ "$(echo "${features}" | grep 64bit -c)" -lt 1 ]; then ++ echo "FS features: ${features}" >> $OUT ++ echo "Should have 64bit but not metadata_csum set" >> $OUT ++ fail=1 ++fi ++$FSCK -f -n $TMPFILE >> $OUT 2>&1 || fail=1 ++ ++echo using tune2fs to test e2undo >> $OUT ++$TUNE2FS -O metadata_csum -z $TDB_FILE.0 $TMPFILE >> $OUT 2>&1 ++crc3=`$CRCSUM $TMPFILE` ++echo $CRCSUM after tune2fs $crc3 >> $OUT ++features="$($DUMPE2FS -h $TMPFILE 2> /dev/null | grep 'Filesystem features:')" ++if [ "$(echo "${features}" | grep "metadata_csum" -c)" -lt 1 ] || [ "$(echo "${features}" | grep 64bit -c)" -lt 1 ]; then ++ echo "FS features: ${features}" >> $OUT ++ echo "Should have 64bit and metadata_csum set" >> $OUT ++ fail=1 ++fi ++$FSCK -f -n $TMPFILE >> $OUT 2>&1 || fail=1 ++ ++echo using e2fsck to test e2undo >> $OUT ++$FSCK -f -y -D -z $TDB_FILE.0 $TMPFILE >> $OUT 2>&1 ++crc4=`$CRCSUM $TMPFILE` ++echo $CRCSUM after e2fsck $crc4 >> $OUT ++features="$($DUMPE2FS -h $TMPFILE 2> /dev/null | grep 'Filesystem features:')" ++if [ "$(echo "${features}" | grep "metadata_csum" -c)" -lt 1 ] || [ "$(echo "${features}" | grep 64bit -c)" -lt 1 ]; then ++ echo "FS features: ${features}" >> $OUT ++ echo "Should have 64bit and metadata_csum set" >> $OUT ++ fail=1 ++fi ++$FSCK -f -n $TMPFILE >> $OUT 2>&1 || fail=1 ++ ++echo roll back e2fsck/tune2fs/resize2fs/mke2fs >> $OUT ++$E2UNDO $TDB_FILE.0 $TMPFILE >> $OUT 2>&1 ++crc0_2=`$CRCSUM $TMPFILE` ++echo $CRCSUM after e2undo e2fsck/tune2fs/resize2fs/mke2fs $crc1_2 >> $OUT ++features="$($DUMPE2FS -h $TMPFILE 2> /dev/null | grep 'Filesystem features:')" ++if [ -n "${features}" ]; then ++ echo "FS features: ${features}" >> $OUT ++ echo "Should not have any features set" >> $OUT ++ fail=1 ++fi ++$FSCK -f -n $TMPFILE >> $OUT 2>&1 && fail=1 ++ ++if [ $fail -eq 0 ] && [ $crc0 = $crc0_2 ]; then ++ echo "$test_name: $test_description: ok" ++ touch $test_name.ok ++else ++ ln -f $test_name.log $test_name.failed ++ echo "$test_name: $test_description: failed" ++fi ++rm -f $TDB_FILE.0 $TDB_FILE.1 $TMPFILE $CONF ++fi +--- /dev/null ++++ b/tests/u_revert_upgrade_to_64bitmcsum/script +@@ -0,0 +1,136 @@ ++test_description="convert fs to 64bit,metadata_csum and revert both changes" ++if test -x $RESIZE2FS_EXE -a -x $E2UNDO_EXE; then ++ ++TDB_FILE=${TMPDIR:-/tmp}/resize2fs-$(basename $TMPFILE).e2undo ++OUT=$test_name.log ++rm -f $TDB_FILE >/dev/null 2>&1 ++fail=0 ++ ++echo convert fs to 64bit,metadata_csum and revert both changes > $OUT ++ ++dd if=/dev/zero of=$TMPFILE bs=1k count=512 > /dev/null 2>&1 ++crc0=`$CRCSUM $TMPFILE` ++echo $CRCSUM before mke2fs $crc0 >> $OUT ++ ++CONF=$TMPFILE.conf ++cat > $CONF << ENDL ++[fs_types] ++ ext4h = { ++ features = has_journal,extent,huge_file,flex_bg,uninit_bg,dir_nlink,extra_isize,sparse_super,filetype,dir_index,ext_attr,resize_inode ++ blocksize = 4096 ++ inode_size = 256 ++ make_hugefiles = true ++ hugefiles_dir = / ++ hugefiles_slack = 0 ++ hugefiles_name = aaaaa ++ hugefiles_digits = 4 ++ hugefiles_size = 1M ++ zero_hugefiles = false ++ } ++ENDL ++ ++echo mke2fs -q -F -o Linux -T ext4h -O ^metadata_csum,^64bit -E lazy_itable_init=1 -b 4096 -z $TDB_FILE.0 $TMPFILE 524288 >> $OUT ++MKE2FS_CONFIG=$CONF $MKE2FS -q -F -o Linux -T ext4h -O ^metadata_csum,^64bit -E lazy_itable_init=1 -b 4096 -z $TDB_FILE.0 $TMPFILE >> $OUT 2>&1 ++crc1=`$CRCSUM $TMPFILE` ++echo $CRCSUM after mke2fs $crc1 >> $OUT ++features="$($DUMPE2FS -h $TMPFILE 2> /dev/null | grep 'Filesystem features:')" ++if [ "$(echo "${features}" | grep "metadata_csum" -c)" -gt 0 ] || [ "$(echo "${features}" | grep 64bit -c)" -gt 0 ]; then ++ echo "FS features: ${features}" >> $OUT ++ echo "Should not have 64bit or metadata_csum set" >> $OUT ++ fail=1 ++fi ++$FSCK -f -n $TMPFILE >> $OUT 2>&1 || fail=1 ++ ++echo using resize2fs to test e2undo >> $OUT ++$RESIZE2FS -z $TDB_FILE.1 -b $TMPFILE >> $OUT 2>&1 ++crc2=`$CRCSUM $TMPFILE` ++echo $CRCSUM after resize2fs $crc2 >> $OUT ++features="$($DUMPE2FS -h $TMPFILE 2> /dev/null | grep 'Filesystem features:')" ++if [ "$(echo "${features}" | grep "metadata_csum" -c)" -gt 0 ] || [ "$(echo "${features}" | grep 64bit -c)" -lt 1 ]; then ++ echo "FS features: ${features}" >> $OUT ++ echo "Should have 64bit but not metadata_csum set" >> $OUT ++ fail=1 ++fi ++$FSCK -f -n $TMPFILE >> $OUT 2>&1 || fail=1 ++ ++echo using tune2fs to test e2undo >> $OUT ++$TUNE2FS -O metadata_csum -z $TDB_FILE.2 $TMPFILE >> $OUT 2>&1 ++crc3=`$CRCSUM $TMPFILE` ++echo $CRCSUM after tune2fs $crc3 >> $OUT ++features="$($DUMPE2FS -h $TMPFILE 2> /dev/null | grep 'Filesystem features:')" ++if [ "$(echo "${features}" | grep "metadata_csum" -c)" -lt 1 ] || [ "$(echo "${features}" | grep 64bit -c)" -lt 1 ]; then ++ echo "FS features: ${features}" >> $OUT ++ echo "Should have 64bit and metadata_csum set" >> $OUT ++ fail=1 ++fi ++$FSCK -f -n $TMPFILE >> $OUT 2>&1 || fail=1 ++ ++echo using e2fsck to test e2undo >> $OUT ++$FSCK -f -y -D -z $TDB_FILE.3 $TMPFILE >> $OUT 2>&1 ++crc4=`$CRCSUM $TMPFILE` ++echo $CRCSUM after e2fsck $crc4 >> $OUT ++features="$($DUMPE2FS -h $TMPFILE 2> /dev/null | grep 'Filesystem features:')" ++if [ "$(echo "${features}" | grep "metadata_csum" -c)" -lt 1 ] || [ "$(echo "${features}" | grep 64bit -c)" -lt 1 ]; then ++ echo "FS features: ${features}" >> $OUT ++ echo "Should have 64bit and metadata_csum set" >> $OUT ++ fail=1 ++fi ++$FSCK -f -n $TMPFILE >> $OUT 2>&1 || fail=1 ++ ++echo roll back e2fsck >> $OUT ++$E2UNDO $TDB_FILE.3 $TMPFILE >> $OUT 2>&1 ++crc3_2=`$CRCSUM $TMPFILE` ++echo $CRCSUM after e2undo e2fsck $crc3_2 >> $OUT ++features="$($DUMPE2FS -h $TMPFILE 2> /dev/null | grep 'Filesystem features:')" ++if [ "$(echo "${features}" | grep "metadata_csum" -c)" -lt 1 ] || [ "$(echo "${features}" | grep 64bit -c)" -lt 1 ]; then ++ echo "FS features: ${features}" >> $OUT ++ echo "Should have 64bit and metadata_csum set" >> $OUT ++ fail=1 ++fi ++$FSCK -f -n $TMPFILE >> $OUT 2>&1 || fail=1 ++ ++echo roll back tune2fs >> $OUT ++$E2UNDO $TDB_FILE.2 $TMPFILE >> $OUT 2>&1 ++crc2_2=`$CRCSUM $TMPFILE` ++echo $CRCSUM after e2undo tune2fs $crc2_2 >> $OUT ++features="$($DUMPE2FS -h $TMPFILE 2> /dev/null | grep 'Filesystem features:')" ++if [ "$(echo "${features}" | grep "metadata_csum" -c)" -gt 0 ] || [ "$(echo "${features}" | grep 64bit -c)" -lt 1 ]; then ++ echo "FS features: ${features}" >> $OUT ++ echo "Should have 64bit but not metadata_csum set" >> $OUT ++ fail=1 ++fi ++$FSCK -f -n $TMPFILE >> $OUT 2>&1 || fail=1 ++ ++echo roll back resize2fs >> $OUT ++$E2UNDO $TDB_FILE.1 $TMPFILE >> $OUT 2>&1 ++crc1_2=`$CRCSUM $TMPFILE` ++echo $CRCSUM after e2undo resize2fs $crc1_2 >> $OUT ++features="$($DUMPE2FS -h $TMPFILE 2> /dev/null | grep 'Filesystem features:')" ++if [ "$(echo "${features}" | grep "metadata_csum" -c)" -gt 0 ] || [ "$(echo "${features}" | grep 64bit -c)" -gt 0 ]; then ++ echo "FS features: ${features}" >> $OUT ++ echo "Should not have 64bit or metadata_csum set" >> $OUT ++ fail=1 ++fi ++$FSCK -f -n $TMPFILE >> $OUT 2>&1 || fail=1 ++ ++echo roll back mke2fs >> $OUT ++$E2UNDO $TDB_FILE.0 $TMPFILE >> $OUT 2>&1 ++crc0_2=`$CRCSUM $TMPFILE` ++echo $CRCSUM after e2undo mke2fs $crc0_2 >> $OUT ++features="$($DUMPE2FS -h $TMPFILE 2> /dev/null | grep 'Filesystem features:')" ++if [ -n "${features}" ]; then ++ echo "FS features: ${features}" >> $OUT ++ echo "Should not have any features set" >> $OUT ++ fail=1 ++fi ++$FSCK -f -n $TMPFILE >> $OUT 2>&1 && fail=1 ++ ++if [ $fail -eq 0 ] && [ $crc0 = $crc0_2 ] && [ $crc1 = $crc1_2 ] && [ $crc2 = $crc2_2 ] && [ $crc3 = $crc3_2 ]; then ++ echo "$test_name: $test_description: ok" ++ touch $test_name.ok ++else ++ ln -f $test_name.log $test_name.failed ++ echo "$test_name: $test_description: failed" ++fi ++rm -f $TDB_FILE.0 $TDB_FILE.1 $TDB_FILE.2 $TDB_FILE.3 $TMPFILE $CONF ++fi +--- a/tests/u_tune2fs/script ++++ b/tests/u_tune2fs/script +@@ -1,7 +1,7 @@ + test_description="e2undo with tune2fs" + if test -x $E2UNDO_EXE; then + +-E2FSPROGS_UNDO_DIR=/tmp ++E2FSPROGS_UNDO_DIR=${TMPDIR:-/tmp} + export E2FSPROGS_UNDO_DIR + TDB_FILE=$E2FSPROGS_UNDO_DIR/tune2fs-$(basename $TMPFILE).e2undo + OUT=$test_name.log +@@ -19,7 +19,7 @@ + new_crc=`$CRCSUM $TMPFILE` + echo $CRCSUM after tune2fs $new_crc >> $OUT + +-$E2UNDO_EXE $TDB_FILE $TMPFILE >> $OUT 2>&1 ++$E2UNDO $TDB_FILE $TMPFILE >> $OUT 2>&1 + new_crc=`$CRCSUM $TMPFILE` + echo $CRCSUM after e2undo $new_crc >> $OUT + +--- /dev/null ++++ b/tests/u_tune2fs_opt/script +@@ -0,0 +1,32 @@ ++test_description="e2undo with tune2fs -z" ++if test -x $E2UNDO_EXE; then ++ ++TDB_FILE=${TMPDIR:-/tmp}/tune2fs-$(basename $TMPFILE).e2undo ++OUT=$test_name.log ++rm -f $TDB_FILE >/dev/null 2>&1 ++ ++dd if=/dev/zero of=$TMPFILE bs=1k count=512 > /dev/null 2>&1 ++ ++echo mke2fs -q -F -o Linux -T ext4 -O ^metadata_csum,64bit -E lazy_itable_init=1 -b 1024 $TMPFILE > $OUT ++$MKE2FS -q -F -o Linux -T ext4 -O ^metadata_csum,64bit -E lazy_itable_init=1 -b 1024 $TMPFILE >> $OUT 2>&1 ++crc0=`$CRCSUM $TMPFILE` ++echo $CRCSUM before tune2fs $crc0 >> $OUT ++ ++echo using tune2fs to test e2undo >> $OUT ++$TUNE2FS -O metadata_csum -z $TDB_FILE $TMPFILE >> $OUT 2>&1 ++crc1=`$CRCSUM $TMPFILE` ++echo $CRCSUM after tune2fs $crc1 >> $OUT ++ ++$E2UNDO $TDB_FILE $TMPFILE >> $OUT 2>&1 ++crc2=`$CRCSUM $TMPFILE` ++echo $CRCSUM after e2undo $crc2 >> $OUT ++ ++if [ $crc0 = $crc2 ] && [ $crc1 != $crc2 ]; then ++ echo "$test_name: $test_description: ok" ++ touch $test_name.ok ++else ++ ln -f $test_name.log $test_name.failed ++ echo "$test_name: $test_description: failed" ++fi ++rm -f $TDB_FILE $TMPFILE ++fi +--- /dev/null ++++ b/tests/u_undo_undo/script +@@ -0,0 +1,54 @@ ++test_description="undo e2undo" ++if test -x $E2UNDO_EXE; then ++ ++TDB_FILE=${TMPDIR:-/tmp}/e2fsck-$(basename $TMPFILE).e2undo ++TDB_FILE2=${TMPDIR:-/tmp}/e2undo-$(basename $TMPFILE).e2undo ++OUT=$test_name.log ++rm -f $TDB_FILE $TDB_FILE2 >/dev/null 2>&1 ++ ++dd if=/dev/zero of=$TMPFILE bs=1k count=512 > /dev/null 2>&1 ++ ++echo mke2fs -q -F -o Linux -T ext4 -O ^metadata_csum,64bit -E lazy_itable_init=1 -b 1024 $TMPFILE > $OUT ++$MKE2FS -q -F -o Linux -T ext4 -O ^metadata_csum,64bit -E lazy_itable_init=1 -b 1024 $TMPFILE >> $OUT 2>&1 ++crc0=`$CRCSUM $TMPFILE` ++echo $CRCSUM before e2fsck $crc0 >> $OUT ++ ++echo using e2fsck to test e2undo >> $OUT ++$FSCK -f -y -D -z $TDB_FILE $TMPFILE >> $OUT 2>&1 ++crc1=`$CRCSUM $TMPFILE` ++echo $CRCSUM after e2fsck $crc1 >> $OUT ++ ++echo e2undo the e2fsck >> $OUT ++$E2UNDO -z $TDB_FILE2 $TDB_FILE $TMPFILE >> $OUT 2>&1 ++crc2=`$CRCSUM $TMPFILE` ++echo $CRCSUM after e2undo $crc2 >> $OUT ++ ++echo e2undo the e2undo >> $OUT ++$E2UNDO $TDB_FILE2 $TMPFILE >> $OUT 2>&1 ++crc3=`$CRCSUM $TMPFILE` ++echo $CRCSUM after e2undo $crc3 >> $OUT ++ ++echo e2undo the e2undo the e2undo >> $OUT ++$E2UNDO $TDB_FILE $TMPFILE >> $OUT 2>&1 ++crc4=`$CRCSUM $TMPFILE` ++echo $CRCSUM after e2undo $crc4 >> $OUT ++ ++$E2UNDO -h $TDB_FILE $TMPFILE >> $OUT 2>&1 ++$E2UNDO -h $TDB_FILE2 $TMPFILE >> $OUT 2>&1 ++ ++$E2UNDO -z $TDB_FILE2 $TDB_FILE2 $TMPFILE >> $OUT 2>&1 ++ ++crc5=`$CRCSUM $TMPFILE` ++echo $CRCSUM after failed e2undo $crc5 >> $OUT ++ ++echo $crc0 $crc1 $crc2 $crc3 $crc4 $crc5 >> $OUT ++ ++if [ $crc0 = $crc2 ] && [ $crc2 = $crc4 ] && [ $crc5 = $crc4 ] && [ $crc1 = $crc3 ] && [ $crc1 != $crc2 ]; then ++ echo "$test_name: $test_description: ok" ++ touch $test_name.ok ++else ++ ln -f $test_name.log $test_name.failed ++ echo "$test_name: $test_description: failed" ++fi ++rm -f $TDB_FILE $TDB_FILE2 $TMPFILE ++fi +--- /dev/null ++++ b/tests/u_wrong_fs/script +@@ -0,0 +1,36 @@ ++test_description="e2undo on the wrong fs" ++if test -x $E2UNDO_EXE; then ++ ++TDB_FILE=${TMPDIR:-/tmp}/tune2fs-$(basename $TMPFILE).e2undo ++OUT=$test_name.log ++rm -f $TDB_FILE >/dev/null 2>&1 ++ ++dd if=/dev/zero of=$TMPFILE bs=1k count=512 > /dev/null 2>&1 ++ ++echo mke2fs -q -F -o Linux -T ext4 -O ^metadata_csum,64bit -E lazy_itable_init=1 -b 1024 $TMPFILE > $OUT ++$MKE2FS -q -F -o Linux -T ext4 -O ^metadata_csum,64bit -E lazy_itable_init=1 -b 1024 $TMPFILE >> $OUT 2>&1 ++crc0=`$CRCSUM $TMPFILE` ++echo $CRCSUM before tune2fs $crc0 >> $OUT ++ ++echo using tune2fs to test e2undo >> $OUT ++$TUNE2FS -O metadata_csum -z $TDB_FILE $TMPFILE >> $OUT 2>&1 ++crc1=`$CRCSUM $TMPFILE` ++echo $CRCSUM after tune2fs $crc1 >> $OUT ++ ++$MKE2FS -q -F -o Linux -T ext4 -O ^metadata_csum,64bit -E lazy_itable_init=1 -b 1024 $TMPFILE >> $OUT 2>&1 ++crc2=`$CRCSUM $TMPFILE` ++echo $CRCSUM after re-mke2fs $crc2 >> $OUT ++ ++$E2UNDO $TDB_FILE $TMPFILE >> $OUT 2>&1 ++crc3=`$CRCSUM $TMPFILE` ++echo $CRCSUM after e2undo $crc3 >> $OUT ++ ++if [ $crc3 = $crc2 ] && [ $crc2 != $crc1 ]; then ++ echo "$test_name: $test_description: ok" ++ touch $test_name.ok ++else ++ ln -f $test_name.log $test_name.failed ++ echo "$test_name: $test_description: failed" ++fi ++rm -f $TDB_FILE $TMPFILE ++fi +--- /dev/null ++++ b/TODO +@@ -0,0 +1,277 @@ ++Need to process the bad block inode *before* doing the inode scan. ++ ++Also check to see if the first block of the inode table is not on the ++bad block scan, and fix that. We need to check for an inaccurate ++blocks, and fix them before we start doing anything else with the ++filesystem! ++ ++--------------------------------------------------- ++User request: ++ ++BTW: Could you please add some sort of deleted and possibly corrupted file ++ and inode list to e2fsck report. There should be filenames deleted ++ from directory inodes, files with duplicate blocks e.t.c. ++ It's pretty annoying to filter this information from e2fsck output ++ by hand :- ++ ++------------------------------------------ ++ ++Add a "answer Yes always to this class of question" response. ++ ++---------------------------------- ++ ++ext2fs_flush() should return a different error message for primary ++versus backup superblock flushing, so that mke2fs can print an ++appropriate error message. ++ ++--------------------------------- ++Date: Mon, 08 Mar 1999 21:46:14 +0100 ++From: Sergio Polini ++ ++ ++I'm reading the sorce code of e2fsck 1.14. ++In pass2.c, lines 352-357, I read: ++ ++if ((dirent->name_len & 0xFF) > EXT2_NAME_LEN) { ++ if (fix_problem(ctx, PR_2_FILENAME_LONG, &cd->pctx)) { ++ dirent->name_len = EXT2_NAME_LEN; ++ dir_modified++; ++ } ++} ++ ++I think that I'll never see any messages about too long filenames, ++because "whatever & 0xFF" can never be "> 0xFF". ++Am I wrong? ++-------------------------------------- ++ ++Add chmod command to debugfs. ++ ++------------------------------------------ ++ ++Date: Tue, 18 Jan 2000 17:54:53 -0800 (PST) ++From: Alan Blanchard ++To: tytso@MIT.EDU ++Subject: DEBUGFS - thanks and a feature idea ++Content-Type: TEXT/PLAIN; charset=US-ASCII ++ ++Theodore: ++ ++First, let me thank you for writing debugfs. Recently, my Linux box ++(RH 6.0, 400 MHz PIII, on a DSL line) was hacked into. The intruder did ++an "rm -Rf" on a 34 GB drive with about 5GB of data on it. I was able to ++restore essentially the entire thing with debugfs and a bit of C code and Perl. ++Actually, I could have done the entire thing with debugfs and Perl, but I ++thought it would be too slow. ++ ++During this exercise, I noticed that one small feature was lacking that would ++have made my job a bit easier. The length of a deleted directory is ++reported as 0, hence debugfs won't dump the contents of the directory to a ++file using the "dump" command. The only thing that saved me was that the ++list of disk blocks is not zeroed out. I was able to dump the contents of the ++directories by using debugfs to get the relevant block numbers, then ++using dd to get the actual data. ++ ++If debugfs had a feature where it ignored the size of a directory reported by ++the inode and instead just dumped all the blocks, it would have facilited ++things a bit. This seems like a very easy feature to add. ++ ++Again, thanks for writing debugfs (and all the other Linux stuff you've written!). ++ ++Cheers, ++Alan Blanchard ++alan@abraxas.to ++ ++ ++------------------------------------------------------------------- ++ ++Date: Fri, 21 Jan 2000 14:07:12 -0800 ++From: "H. Peter Anvin" ++Subject: mkfs -cc and fsck -c ++ ++b) An option to mkfs to zero the partition. Yes, it can be done with ++dd, but it would be a nicer way of doing it. ++ ++------------------------------------------------------------------ ++ ++Add support for in ext2fs_block_iterate() for a returning the ++compressed flag blocks to block_iterate. Change default to not return ++EXT2_COMPRESSED_BLKADDR. Change e2fsck to pass this flag in. ++ ++(The old compression patches did this by default all the time, which ++is bad, since it meant e2fsck never saw the EXT2_COMPRESSED_BLKADDR ++flagword. ++ ++------------------------------------------------------------ ++ ++E2fsck should offer to clear all the blocks in an indirect block, not ++the entire inode, so there's better recovery for when an indirect ++block gets trashed. ++ ++ ++------------------------------------------------------------- ++ ++From: Yann Dirson - LOGATIQUE ++Date: Thu, 2 Mar 2000 13:52:13 +0100 (MET) ++ ++During my experiments on the broken system, I noticed the following in ++the badblocks program (which I'm aware is not designed for IDE drives) ++- I'd probably have already fixed them if my home system was up :( ++ ++* the syntax summary documents 2nd arg as blocks_count, which should ++probably read something like end_count. ++ ++* testing past end of device is not detected, and lists those blocks ++as bad, whereas they simply do not exist. ++ ++ ++I think I'll probably add a "max count" option to findsuper(8), so ++that I do not have to wait for the whole disk to be scanned when the ++system had to be launched with "init=/bin/sh", in which case Ctrl-[CZ] ++and friends appear to be absolutely ignored. ++ ++ ++Somewhat unrelated, I just noticed the ++http://web.mit.edu/tytso/www/linux/ext2.html could be updated: ++ ++- could mention SGI xfs (http://oss.sgi.com/projects/xfs/ - they just ++ release 0.03 snapshot) ++ ++---------------------------------------------------------------- ++ ++Return-Path: ++Date: Thu, 10 Feb 2000 13:20:14 -0500 ++From: "Theodore Y. Ts'o" ++To: R.E.Wolff@BitWizard.nl ++In-Reply-To: Rogier Wolff's message of Thu, 10 Feb 2000 08:46:30 +0100 (MET), ++ <200002100746.IAA24573@cave.bitwizard.nl> ++Subject: Re: e2fsck request for enhancement. ++Phone: (781) 391-3464 ++ ++ Date: Thu, 10 Feb 2000 08:46:30 +0100 (MET) ++ From: R.E.Wolff@BitWizard.nl (Rogier Wolff) ++ ++ Lately, while trying to recover a broken disk, my system froze (twice, ++ until I tried something else) while copying the disk. ++ ++ So I had a file of about 50Mb that was growing frantically at the ++ moment of the crash. ++ ++ e2fsck, then finds an indirect block that is completely bogus. It ++ starts by asking me if it's ok to clear a few of the referenced ++ blocks. I say yes. Then it comes to the conclusion: ++ ++ too many invalid blocks. Clear inode? ++ ++ and then I get the option to delete the whole file. Not to truncate ++ the file to a "working" size. ++ ++ ++ I'd MUCH rather have e2fsck say something like: ++ ++ inode 1234 references an invalid block 134345454. Hmm. ++ inode 1234 references 567 out of 50176 invalid blocks, ++ all near the end. Truncate file to 49152 blocks? ++ ++ Here you can see that of the 1024 blocks near the end of the file, ++ only 567 were detected as invalid. However now 48Mb of the file will ++ be recovered, instead of thrown away. ++ ++That's a good point. Actually, the right thing is for e2fsck to offer ++to clear all of the bad blocks in a particular indirect block. I don't ++know how hard it would be to do that, but I'll put it on my e2fsprogs ++TODO list. ++ ++ - Ted ++ ++--------------------------------------------------------------- ++From e2fsprogs Debian TODO file as of 1.10-13. ++ ++* Maybe make -dbg packages. Look at how others do it. ++ ++--------------------------------------------------------------- ++ ++Add --lba option to debian icheck command, and have ways of making it ++easier to translate LBA to filesystem block numbers. ++ ++------------------------------------------------------- ++ ++ ++ ++List of projects for e2fsprogs: ++ ++ ++1) Make debugfs's "ncheck " command list all of the pathnames ++to an inode, not just only the first link to the inode which is found. ++(A good "intro to libext2fs programming interfaces project) ++ ++ Difficulty: Low Priority: Low ++ ++2) Use a code coverage tool such as Rational's PureCoverage to see ++what kind of code coverage we have for e2fsck, and try to add test ++cases to increase the code coverage for e2fsck. ++ ++ Difficulty: Medium Priorty: Low ++ ++3) Use a code coverage tool such as Rational's PureCoverage to see ++what kind of code coverage we have for resize2fs, and try to add test ++cases to increase the code coverage for resize2fs. ++ ++ Difficulty: Medium Priorty: Medium ++ ++4) Create a new I/O manager (i.e., test_io.c, unix_io.c, et.al.) which ++layers on top of an existing I/O manager which provides copy-on-write ++functionality. This COW I/O manager takes will take two open I/O ++managers, call them "base" and "changed". The "base" I/O manager is ++opened read/only, so any changes are written instead to the "changed" ++I/O manager, in a compact, non-sparse format containing the intended ++modification to the "base" filesystem. ++ ++This will allow resize2fs to figure out what changes need to made to ++extend a filesystem, or expand the size of inodes in the inode table, ++and the changes can be pushed the filesystem in one fell swoop. (If ++the system crashes; the program which runs the "changed" file can be ++re-run, much like a journal replay. My assumption is that the COW ++file will contain the filesystem UUID in a the COW superblock, and the ++COW file will be stored in some place such as /var/state/e2fsprogs, ++with an init.d file to automate the replay so we can recover cleanly ++from a crash during the resize2fs process.) ++ ++ Difficulty: Medium Priority: Medium ++ ++5) Create a new I/O manager (i.e., test_io.c, unix_io.c, et.al.) which ++layers on top of an existing I/O manager which provides an "undo" ++functionality. This undo I/O manager takes will take two open I/O ++managers, call them "base" and "undo". The "base" I/O manager is be ++opened read/write, and when any writes are sent to the I/O manager, ++the I/O manager will check the "undo" I/O manager, using a file format ++identical to the one found in (5) above. ++ ++This is useful for allowing e2fsck to create an "undo" file, which ++would make things like "e2fsck -y" much safer. ++ ++ Difficulty: Low (once 5 is done) Priority: Low ++ ++6) Modify resize2fs so that it can relocate and reorganize the ++filesystem in the following ways: (1) increase the inode size, so that ++an existing filesystem can use the EA-in-inode kernel patch, (2) ++reserve blocks in the resize inode to allow for on-line resizing. Use ++the COW I/O manager described in (5) in order to provide robustness in ++case of a crash during the resize/reorganization operation. ++ ++ Difficulty: High Priority: Medium ++ ++7) Review the EA-in-inode patches to e2fsck for correctness/code ++cleanliness. (I will probably have to do this myself -- Ted) ++ ++ Difficulty: High Priorty: Medium ++ ++8) Add support for extent maps to e2fsprogs. I need to review the ++extent maps first/in parallel. ++ ++ Difficulty: High Priority: Medium ++ ++---------------------------------- ++ ++Need to deal with the case where the resize inode overlaps with the ++bad blocks inode. ++ +--- /dev/null ++++ b/util/android_config.h +@@ -0,0 +1,51 @@ ++/* work around bug in AndroidConfig.h */ ++#ifdef HAVE_MALLOC_H ++#undef HAVE_MALLOC_H ++#define HAVE_MALLOC_H 1 ++#endif ++ ++#define ROOT_SYSCONFDIR "/etc" ++ ++#define DISABLE_BACKTRACE 1 ++#define HAVE_DIRENT_H 1 ++#define HAVE_ERRNO_H 1 ++#define HAVE_EXT2_IOCTLS 1 ++#define HAVE_FALLOCATE 1 ++#define HAVE_GETOPT_H 1 ++#define HAVE_GETPAGESIZE 1 ++#define HAVE_GETPWUID_R 1 ++#define HAVE_INTPTR_T 1 ++#define HAVE_INTTYPES_H 1 ++#define HAVE_LINUX_FD_H 1 ++#define HAVE_LSEEK64 1 ++#define HAVE_LSEEK64_PROTOTYPE 1 ++#define HAVE_MMAP 1 ++#define HAVE_NETINET_IN_H 1 ++#define HAVE_NET_IF_H 1 ++#define HAVE_POSIX_MEMALIGN 1 ++#define HAVE_PREAD 1 ++#define HAVE_PREAD64 1 ++#define HAVE_PWRITE 1 ++#define HAVE_PWRITE64 1 ++#define HAVE_SETJMP_H 1 ++#define HAVE_SNPRINTF 1 ++#define HAVE_STDLIB_H 1 ++#define HAVE_STRCASECMP 1 ++#define HAVE_STRDUP 1 ++#define HAVE_STRINGS_H 1 ++#define HAVE_STRPTIME 1 ++#define HAVE_SYSCONF 1 ++#define HAVE_SYS_IOCTL_H 1 ++#define HAVE_SYS_MMAN_H 1 ++#define HAVE_SYS_MOUNT_H 1 ++#define HAVE_SYS_PARAM_H 1 ++#define HAVE_SYS_PRCTL_H 1 ++#define HAVE_SYS_RESOURCE_H 1 ++#define HAVE_SYS_SELECT_H 1 ++#define HAVE_SYS_STAT_H 1 ++#define HAVE_SYS_TIME_H 1 ++#define HAVE_SYS_TYPES_H 1 ++#define HAVE_SYS_WAIT_H 1 ++#define HAVE_TYPE_SSIZE_T 1 ++#define HAVE_UNISTD_H 1 ++#define HAVE_UTIME_H 1 +--- /dev/null ++++ b/util/android_types.h +@@ -0,0 +1,39 @@ ++/* ++ * If linux/types.h is already been included, assume it has defined ++ * everything we need. (cross fingers) Other header files may have ++ * also defined the types that we need. ++ */ ++#if (!defined(_LINUX_TYPES_H) && !defined(_BLKID_TYPES_H) && \ ++ !defined(_EXT2_TYPES_H)) ++#define _EXT2_TYPES_H ++ ++typedef unsigned char __u8; ++typedef __signed__ char __s8; ++typedef unsigned short __u16; ++typedef __signed__ short __s16; ++typedef unsigned int __u32; ++typedef __signed__ int __s32; ++typedef unsigned long long __u64; ++typedef __signed__ long long __s64; ++#endif ++ ++/* endian checking stuff */ ++#ifndef EXT2_ENDIAN_H_ ++#define EXT2_ENDIAN_H_ ++ ++#ifdef __CHECKER__ ++#define __bitwise __attribute__((bitwise)) ++#define __force __attribute__((force)) ++#else ++#define __bitwise ++#define __force ++#endif ++ ++typedef __u16 __bitwise __le16; ++typedef __u32 __bitwise __le32; ++typedef __u64 __bitwise __le64; ++typedef __u16 __bitwise __be16; ++typedef __u32 __bitwise __be32; ++typedef __u64 __bitwise __be64; ++ ++#endif /* EXT2_ENDIAN_H_ */ +--- /dev/null ++++ b/util/gen-android-files +@@ -0,0 +1,61 @@ ++#!/bin/sh ++ ++ANDROID_GENERATED_FILES="lib/ext2fs/ext2_err.c lib/ext2fs/ext2_err.h \ ++ lib/ss/ss_err.c lib/ss/ss_err.h lib/support/prof_err.c \ ++ lib/support/prof_err.h \ ++ lib/blkid/blkid_types.h lib/uuid/uuid_types.h \ ++ lib/ext2fs/ext2_types.h lib/config.h lib/blkid/blkid.h \ ++ lib/uuid/uuid.h lib/ext2fs/crc32c_table.h misc/default_profile.c \ ++ lib/ss/std_rqs.c debugfs/debug_cmds.c debugfs/ro_debug_cmds.c \ ++ debugfs/extent_cmds.c debugfs/e2freefrag.c debugfs/create_inode.c \ ++ debugfs/recovery.c debugfs/revoke.c \ ++ MODULE_LICENSE_GPL" ++ ++SS_DIR=$(pwd)/lib/ss ++MK_CMDS=/tmp/mk_cmds$$.sh ++ ++sed -e "s;@SS_DIR@;$SS_DIR;" < $SS_DIR/mk_cmds.sh.in \ ++ | sed -e "s/@AWK@/awk/" | sed -e "s/@SED@/sed/" > $MK_CMDS ++ ++sed -e "s/@E2FSPROGS_VERSION@/$(git describe)/" < lib/ext2fs/ext2_err.et.in > lib/ext2fs/ext2_err.et ++ ++for i in lib/ss/ss_err lib/support/prof_err lib/ext2fs/ext2_err ++do ++ rm -f $i.c $i.h ++ awk -f lib/et/et_c.awk outfile=$i.c outfn=$(basename $i.c) $i.et ++ awk -f lib/et/et_h.awk outfile=$i.h outfn=$(basename $i.h) $i.et ++done ++ ++for i in lib/ss/std_rqs debugfs/debug_cmds debugfs/ro_debug_cmds \ ++ debugfs/extent_cmds ++do ++ /bin/sh $MK_CMDS $i.ct ++ mv -f $(basename $i).c $i.c ++done ++ ++rm -f $MK_CMDS ++ ++cp lib/blkid/blkid.h.in lib/blkid/blkid.h ++cp lib/uuid/uuid.h.in lib/uuid/uuid.h ++cp util/android_types.h lib/ext2fs/ext2_types.h ++cp util/android_types.h lib/blkid/blkid_types.h ++cp util/android_types.h lib/uuid/uuid_types.h ++cp util/android_config.h lib/config.h ++cp misc/e2freefrag.c misc/create_inode.c debugfs/ ++cp e2fsck/recovery.c e2fsck/revoke.c debugfs/ ++ ++gcc -o gen_crc32ctable lib/ext2fs/gen_crc32ctable.c ++./gen_crc32ctable > lib/ext2fs/crc32c_table.h ++ ++awk -f misc/profile-to-c.awk < misc/mke2fs.conf.in > misc/default_profile.c ++ ++rm -f ./gen_crc32table ./gen_crc32ctable lib/ext2fs/ext2_err.et ++ ++touch MODULE_LICENSE_GPL ++ ++git add -f $ANDROID_GENERATED_FILES ++if test -f COPYING ++then ++ git mv COPYING NOTICE ++fi ++git commit -m "Update generated files for Android" +--- a/util/Makefile.in ++++ b/util/Makefile.in +@@ -17,6 +17,7 @@ + $(E) " CC $<" + $(Q) $(BUILD_CC) -c $(BUILD_CFLAGS) $< -o $@ + $(Q) $(CHECK_CMD) $(ALL_CFLAGS) $< ++ $(Q) $(CPPCHECK_CMD) $(CPPFLAGS) $< + + PROGS= subst symlinks + +@@ -52,7 +53,7 @@ + + clean:: + $(RM) -f $(PROGS) \#* *.s *.o *.a *~ core *.tar.gz gen-tarball \ +- copy-sparse dirpaths.h ++ copy-sparse dirpaths.h install-symlink + + mostlyclean: clean + +--- /dev/null ++++ b/util/Makefile.pq +@@ -0,0 +1,10 @@ ++TOPSRC=.. ++ ++!include $(TOPSRC)\powerquest\MCONFIG ++ ++ALL:: libecho.exe ++ ++libecho.exe: libecho.c ++ ++clean:: ++ $(RM) libecho.exe +--- /dev/null ++++ b/util/static-analysis-cleanup +@@ -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 +--- a/util/subst.c ++++ b/util/subst.c +@@ -24,6 +24,9 @@ + #include + #include + #include ++#ifdef HAVE_SYS_TIME_H ++#include ++#endif + + #ifdef HAVE_GETOPT_H + #include +@@ -444,6 +447,8 @@ + } + if (old) + fclose(old); ++ if (newfn) ++ free(newfn); + return (0); + } + +--- a/util/subst.conf.in ++++ b/util/subst.conf.in +@@ -18,5 +18,3 @@ + # Enable the documentation for the journal device mke2fs, tune2fs, and + # e2fsck's man page + JDEV +-# Enable documentation for quota feature in mke2fs +-QUOTA_MAN_COMMENT @QUOTA_MAN_COMMENT@ +--- a/util/symlinks.c ++++ b/util/symlinks.c +@@ -1,6 +1,10 @@ + #define _FILE_OFFSET_BITS 64 ++#ifndef _LARGEFILE_SOURCE + #define _LARGEFILE_SOURCE ++#endif ++#ifndef _LARGEFILE64_SOURCE + #define _LARGEFILE64_SOURCE ++#endif + + #include + #ifndef _POSIX_SOURCE +@@ -166,7 +170,7 @@ + struct stat stbuf, lstbuf; + int c, fix_abs = 0, fix_messy = 0, fix_long = 0; + +- if ((c = readlink(path, lpath, sizeof(lpath))) == -1) { ++ if ((c = readlink(path, lpath, sizeof(lpath) - 1)) == -1) { + perror(path); + return; + } +--- 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.13" +-#define E2FSPROGS_DATE "17-May-2015" ++#define E2FSPROGS_VERSION "1.43-WIP" ++#define E2FSPROGS_DATE "18-May-2015" diff -Nru e2fsprogs-1.42.13/debian/patches/02-enable-e4encrypt.patch e2fsprogs-1.42.13/debian/patches/02-enable-e4encrypt.patch --- e2fsprogs-1.42.13/debian/patches/02-enable-e4encrypt.patch 1970-01-01 00:00:00.000000000 +0000 +++ e2fsprogs-1.42.13/debian/patches/02-enable-e4encrypt.patch 2015-11-29 18:47:34.000000000 +0000 @@ -0,0 +1,14 @@ +diff --git a/misc/e4crypt.c b/misc/e4crypt.c +index ad95bd2..8a5654a 100644 +--- a/misc/e4crypt.c ++++ b/misc/e4crypt.c +@@ -726,9 +726,6 @@ static void do_set_policy(int argc, char **argv, const struct cmd_desc *cmd) + exit(1); + } + +- printf("arg %s\n", argv[optind]); +- exit(0); +- + strcpy(saltbuf.key_ref_str, argv[optind]); + if ((strlen(argv[optind]) != (EXT4_KEY_DESCRIPTOR_SIZE * 2)) || + hex2byte(argv[optind], (EXT4_KEY_DESCRIPTOR_SIZE * 2), diff -Nru e2fsprogs-1.42.13/debian/patches/20151129.patch e2fsprogs-1.42.13/debian/patches/20151129.patch --- e2fsprogs-1.42.13/debian/patches/20151129.patch 2015-11-29 18:41:51.000000000 +0000 +++ e2fsprogs-1.42.13/debian/patches/20151129.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,83316 +0,0 @@ -diff --git a/.gitignore b/.gitignore -index ac0fd2b..baf9b1a 100644 ---- a/.gitignore -+++ b/.gitignore -@@ -154,6 +154,7 @@ misc/dumpe2fs - misc/dumpe2fs.8 - misc/e2freefrag - misc/e2freefrag.8 -+misc/e2fuzz - misc/e2image - misc/e2image.8 - misc/e2initrd_helper -diff --git a/Android.mk b/Android.mk -new file mode 100644 -index 0000000..5053e7d ---- /dev/null -+++ b/Android.mk -@@ -0,0 +1 @@ -+include $(call all-subdir-makefiles) -diff --git a/CleanSpec.mk b/CleanSpec.mk -new file mode 100644 -index 0000000..ded4ceb ---- /dev/null -+++ b/CleanSpec.mk -@@ -0,0 +1,51 @@ -+# Copyright (C) 2007 The Android Open Source Project -+# -+# Licensed under the Apache License, Version 2.0 (the "License"); -+# you may not use this file except in compliance with the License. -+# You may obtain a copy of the License at -+# -+# http://www.apache.org/licenses/LICENSE-2.0 -+# -+# Unless required by applicable law or agreed to in writing, software -+# distributed under the License is distributed on an "AS IS" BASIS, -+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -+# See the License for the specific language governing permissions and -+# limitations under the License. -+# -+ -+# If you don't need to do a full clean build but would like to touch -+# a file or delete some intermediate files, add a clean step to the end -+# of the list. These steps will only be run once, if they haven't been -+# run before. -+# -+# E.g.: -+# $(call add-clean-step, touch -c external/sqlite/sqlite3.h) -+# $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libz_intermediates) -+# -+# Always use "touch -c" and "rm -f" or "rm -rf" to gracefully deal with -+# files that are missing or have been moved. -+# -+# Use $(PRODUCT_OUT) to get to the "out/target/product/blah/" directory. -+# Use $(OUT_DIR) to refer to the "out" directory. -+# -+# If you need to re-do something that's already mentioned, just copy -+# the command and add it to the bottom of the list. E.g., if a change -+# that you made last week required touching a file and a change you -+# made today requires touching the same file, just copy the old -+# touch step and add it to the end of the list. -+# -+# ************************************************ -+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST -+# ************************************************ -+ -+# For example: -+#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/AndroidTests_intermediates) -+#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/core_intermediates) -+#$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f) -+#$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*) -+ -+# ************************************************ -+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST -+# ************************************************ -+ -+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libext2_uuid_intermediates) -diff --git a/MCONFIG.in b/MCONFIG.in -index f1003cf..25835d4 100644 ---- a/MCONFIG.in -+++ b/MCONFIG.in -@@ -53,23 +53,29 @@ 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@ --CFLAGS = @CFLAGS@ @DEFS@ -+CFLAGS = @CFLAGS@ - CPPFLAGS = @INCLUDES@ --ALL_CFLAGS = $(CPPFLAGS) $(CFLAGS) -+ALL_CFLAGS = $(CPPFLAGS) $(CFLAGS) @DEFS@ $(LOCAL_CFLAGS) - LDFLAGS = @LDFLAGS@ - ALL_LDFLAGS = $(LDFLAGS) @LDFLAG_DYNAMIC@ - LDFLAGS_STATIC = $(LDFLAGS) @LDFLAG_STATIC@ -@@ -108,14 +114,16 @@ LIBCOM_ERR = $(LIB)/libcom_err@LIB_EXT@ @PRIVATE_LIBS_CMT@ @SEM_INIT_LIB@ - LIBE2P = $(LIB)/libe2p@LIB_EXT@ - LIBEXT2FS = $(LIB)/libext2fs@LIB_EXT@ - LIBUUID = @LIBUUID@ @SOCKET_LIB@ --LIBQUOTA = @STATIC_LIBQUOTA@ -+LIBMAGIC = @MAGIC_LIB@ -+LIBFUSE = @FUSE_LIB@ -+LIBSUPPORT = $(LIB)/libsupport@STATIC_LIB_EXT@ - LIBBLKID = @LIBBLKID@ @PRIVATE_LIBS_CMT@ $(LIBUUID) - LIBINTL = @LIBINTL@ - SYSLIBS = @LIBS@ - DEPLIBSS = $(LIB)/libss@LIB_EXT@ - DEPLIBCOM_ERR = $(LIB)/libcom_err@LIB_EXT@ - DEPLIBUUID = @DEPLIBUUID@ --DEPLIBQUOTA = @DEPSTATIC_LIBQUOTA@ -+DEPLIBSUPPORT = $(LIBSUPPORT) - DEPLIBBLKID = @DEPLIBBLKID@ @PRIVATE_LIBS_CMT@ $(DEPLIBUUID) - TESTENV = LD_LIBRARY_PATH="$(LIB):$${LD_LIBRARY_PATH}" DYLD_LIBRARY_PATH="$(LIB):$${DYLD_LIBRARY_PATH}" - -@@ -124,12 +132,12 @@ STATIC_LIBCOM_ERR = $(LIB)/libcom_err@STATIC_LIB_EXT@ @SEM_INIT_LIB@ - STATIC_LIBE2P = $(LIB)/libe2p@STATIC_LIB_EXT@ - STATIC_LIBEXT2FS = $(LIB)/libext2fs@STATIC_LIB_EXT@ - STATIC_LIBUUID = @STATIC_LIBUUID@ @SOCKET_LIB@ --STATIC_LIBQUOTA = @STATIC_LIBQUOTA@ -+STATIC_LIBSUPPORT = $(LIBSUPPORT) - STATIC_LIBBLKID = @STATIC_LIBBLKID@ $(STATIC_LIBUUID) - DEPSTATIC_LIBSS = $(LIB)/libss@STATIC_LIB_EXT@ - DEPSTATIC_LIBCOM_ERR = $(LIB)/libcom_err@STATIC_LIB_EXT@ - DEPSTATIC_LIBUUID = @DEPSTATIC_LIBUUID@ --DEPSTATIC_LIBQUOTA = @DEPSTATIC_LIBQUOTA@ -+DEPSTATIC_LIBSUPPORT = $(DEPLIBSUPPORT) - DEPSTATIC_LIBBLKID = @DEPSTATIC_LIBBLKID@ $(DEPSTATIC_LIBUUID) - - PROFILED_LIBSS = $(LIB)/libss@PROFILED_LIB_EXT@ @DLOPEN_LIB@ -@@ -137,12 +145,12 @@ PROFILED_LIBCOM_ERR = $(LIB)/libcom_err@PROFILED_LIB_EXT@ @SEM_INIT_LIB@ - PROFILED_LIBE2P = $(LIB)/libe2p@PROFILED_LIB_EXT@ - PROFILED_LIBEXT2FS = $(LIB)/libext2fs@PROFILED_LIB_EXT@ - PROFILED_LIBUUID = @PROFILED_LIBUUID@ @SOCKET_LIB@ --PROFILED_LIBQUOTA = @PROFILED_LIBQUOTA@ -+PROFILED_LIBSUPPORT = $(LIB)/libsupport@PROFILED_LIB_EXT@ - PROFILED_LIBBLKID = @PROFILED_LIBBLKID@ $(PROFILED_LIBUUID) - DEPPROFILED_LIBSS = $(LIB)/libss@PROFILED_LIB_EXT@ - DEPPROFILED_LIBCOM_ERR = $(LIB)/libcom_err@PROFILED_LIB_EXT@ - DEPPROFILED_LIBUUID = @PROFILED_LIBUUID@ --DEPPROFILED_LIBQUOTA = @PROFILED_LIBQUOTA@ -+DEPPROFILED_LIBSUPPORT = $(PROFILED_LIBSUPPORT) - DEPPROFILED_LIBBLKID = @PROFILED_LIBBLKID@ $(DEPPROFILED_LIBUUID) - - # -@@ -179,7 +187,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 \ -@@ -190,11 +198,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="$(ALL_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="$(ALL_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 -@@ -249,7 +264,7 @@ Makefile: $(srcdir)/Makefile.in $(top_builddir)/MCONFIG \ - $(DEP_MAKEFILE) $(top_builddir)/config.status - cd $(top_builddir); CONFIG_FILES=$(my_dir)/Makefile ./config.status - --@MAINTAINER_CMT@$(top_srcdir)/configure: $(top_srcdir)/configure.in -+@MAINTAINER_CMT@$(top_srcdir)/configure: $(top_srcdir)/configure.ac - @MAINTAINER_CMT@ cd $(top_srcdir) && autoheader && autoconf - - coverage.txt: Makefile $(SRCS) -diff --git a/Makefile.in b/Makefile.in -index f5727a8..a2e1756 100644 ---- a/Makefile.in -+++ b/Makefile.in -@@ -13,9 +13,9 @@ INSTALL = @INSTALL@ - @DEBUGFS_CMT@DEBUGFS_DIR= debugfs - @UUID_CMT@UUID_LIB_SUBDIR= lib/uuid - @BLKID_CMT@BLKID_LIB_SUBDIR= lib/blkid --QUOTA_LIB_SUBDIR= lib/quota -+SUPPORT_LIB_SUBDIR= lib/support - --LIB_SUBDIRS=lib/et lib/ss lib/e2p $(UUID_LIB_SUBDIR) $(BLKID_LIB_SUBDIR) $(QUOTA_LIB_SUBDIR) lib/ext2fs intl -+LIB_SUBDIRS=lib/et lib/ss lib/e2p $(UUID_LIB_SUBDIR) $(BLKID_LIB_SUBDIR) $(SUPPORT_LIB_SUBDIR) lib/ext2fs intl - PROG_SUBDIRS=e2fsck $(DEBUGFS_DIR) misc $(RESIZE_DIR) tests/progs po - SUBDIRS=util $(LIB_SUBDIRS) $(PROG_SUBDIRS) tests - -@@ -115,7 +115,8 @@ clean:: clean-recursive clean-local clean-doc - $(RM) -f $(SUBS) - - distclean: distclean-doc distclean-recursive -- $(RM) -rf autom4te.cache e2fsprogs.spec ext2ed/Makefile po/stamp-po -+ $(RM) -rf autom4te.cache e2fsprogs.spec ext2ed/Makefile po/stamp-po \ -+ asm_types.h config.log public_config.h parse-types.log - $(MAKE) distclean-local - - realclean: realclean-recursive realclean-local -diff --git a/RELEASE-NOTES b/RELEASE-NOTES -index 557e950..f4c4bfc 100644 ---- a/RELEASE-NOTES -+++ b/RELEASE-NOTES -@@ -1,3 +1,171 @@ -+E2fsprogs 1.43-WIP (May 18, 2015) -- cd27af3ecb83 -+================================================= -+ -+Add support for the ext4 metadata checksum, inline data, encryption, -+and read-only features. -+ -+Mke2fs will now create file systems with the metadata_csum and 64bit -+features enabled by default. -+ -+Support for the very old, experimental, and never-added-to-mainline -+compression feature has been removed. -+ -+Debugfs can now modify extended attributes and journal transactions. -+ -+The resize2fs command can now convert file systems between 64-bit and -+32-bit mode. -+ -+We now use a new e2undo file format which is much more efficient and -+faster than the old tdb-based scheme. Since it so much faster, -+e2fsck, tune2fs, debugfs, and resize2fs now also can support using -+creating an undo file. -+ -+The mke2fs command can now set the error behavior when initializing -+the file system (so the administrator doesn't have to issue a separate -+tune2fs -e command). -+ -+E2fsck is now much more paranoid about not freeing or corrupting -+critical metadata blocks, such as inode table blocks, even if -+corrupted indirect blocks or extent trees point at these blocks. -+ -+E2fsck now prints block ranges in pass1b instead of listing all of the -+blocks exhaustively. -+ -+E2fsck will try to expand the root directory if the lost+found can't -+be linked to the root directory. Also, offer to use the root -+directory if lost+found can't be created. -+ -+E2fsck is now more paranoid handling corrupted extent trees as well as -+corrupted journals. -+ -+E2fsck can now rebuild extent trees, either (a) to optimize them, (b) -+to recover from a corrupted extent tree, or (c) to convert -+block-mapped inodes to use extents. -+ -+E2fsck now has a readahead mechanism which can significantly speed its -+performance, especially on RAID arrays. -+ -+E2fsck now has a "yes to all" option which the user can give if she is -+tired of answering 'y' to a very large number of questions. -+ -+E2fsck will now ignore the badblocks inode if the contents of the -+badblocks inode indicate that the portion inode table containing the -+badblocks inode is bad. (We must go deeper...) -+ -+E2fsck can now correctly fix directory with holes on bigalloc file -+systems. -+ -+Fixed a bug in e2fsck to avoid overrunning a buffer containing jbd2 -+revoke records if the journal is corrupted. -+ -+Fixed a bug in e2fsck which could cause it loop forever if a special -+inode has too many invalid block mappings. -+ -+Fixed a bug in e2fsck which could cause pass1b/c/d processing to get -+confused if an attempt to allocate a block can't find any free space -+in the file system. -+ -+E2fsck will no longer try to force rewrite blocks located beyond the -+file system. -+ -+Fixed a bug in resize2fs which could lead to resize2fs crashing or a -+corrupted file system if the file system is almost completely full -+when trying grow a file system and we need to allocate blocks to grow -+the block group descriptors. -+ -+Fixed a bug in resize2fs which could cause it to get fooled trying to -+determinthe the RAID array's stride when flex_bg is enabled. -+ -+The dumpe2fs output has been improved so it is cleaner and always fits -+within 80 columns. Also added a more easily machine-parsable output -+of dumpe2fs. -+ -+The mke2fs program can now pre-populate a file system from a directory -+hierarchy using the -d option. -+ -+The mke2fs program now skips zeroing inode table blocks if they were -+already zeroed using the discard 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. -+ -+Added a new e2fuzz command that will fuzz an ext4 image for testing -+purposes. -+ -+The debugfs logdump command can now deal with 64-bit revoke tables -+correctly. Also, "logdump -O" will print the old log contents (before -+the journal was replayed). -+ -+The debugfs bmap command can now be used to set or allocate a physical -+block. -+ -+Fixed a bug so "filefrag -B -e -v" does not return a separate entry -+for each block. -+ -+The file I/O functions now correctly handle inodes containing -+uninitialized blocks. -+ -+Fix a bug in tune2fs so that removing uninit_bg feature on a bigalloc -+file system won't result in corrupted block bitmaps. -+ -+Programmer's Notes -+------------------ -+ -+Fixed coverity, sparce gcc -Wall, and clang warnings/nits. -+ -+Added Android build files so that e2fsprogs can be built in the -+Android source tree. -+ -+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. -+ -+Developers can now overide the debugging and optimization flags by -+redefining the CFLAGS makefile macro. -+ -+The mke2fs command will now ask the user for confirmation if block -+device or image file contains an existing file system image, and -+stdout and stdin are connected to a tty. -+ -+The libext2fs library now picks a more intelligent goal block when -+doing block allocations. -+ -+The libext2fs library will now automatically set the BLOCK_UNINT flag -+if all of the blocks in a block group are free, to speed up future -+e2fsck and dumpe2fs operations on the file system. -+ -+Add two new functions ext2fs_new_range() and ext2fs_alloc_range() to -+libext2fs. -+ -+The ext2fs_zero_blocks() command will use FALLOC_FL_ZERO_RANGE for -+file-based images. -+ -+The ext2fs_bmap() function supports new flags BMAP_UNINIT and -+BMAP_ZERO. -+ -+The ext2fs_new_block2() function will now call the alloc_block hook -+before checking fs->block_map. -+ -+Support for the MMP feature can now be disabled at compile time. -+ -+Added support to manipulate extended attributes to libext2fs. -+ -+Added a lot of new regression tests. -+ -+Added endian annotations so it's possible to scan e2fsprogs for endian -+problems using a static code analyzer. -+ -+Fixed memory leaks in libext2fs. -+ -+The e2fsck jbd2 handling code has been resynced with the 3.16 kernel. -+There is now a script in the contrib directory which automates most of -+the resync process. -+ -+The build system will now run cppcheck (a static code analysis tool) -+via "make C=1" -+ -+ - E2fsprogs 1.42.13 (May 17, 2015) - ================================ - -diff --git a/config/config.guess b/config/config.guess -old mode 100644 -new mode 100755 -index 1f5c50c..f7eb141 ---- a/config/config.guess -+++ b/config/config.guess -@@ -1,8 +1,8 @@ - #! /bin/sh - # Attempt to guess a canonical system name. --# Copyright 1992-2014 Free Software Foundation, Inc. -+# Copyright 1992-2015 Free Software Foundation, Inc. - --timestamp='2014-03-23' -+timestamp='2015-03-04' - - # This file is free software; you can redistribute it and/or modify it - # under the terms of the GNU General Public License as published by -@@ -24,12 +24,12 @@ timestamp='2014-03-23' - # program. This Exception is an additional permission under section 7 - # of the GNU General Public License, version 3 ("GPLv3"). - # --# Originally written by Per Bothner. -+# Originally written by Per Bothner; maintained since 2000 by Ben Elliston. - # - # You can get the latest version of this script from: - # http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD - # --# Please send patches with a ChangeLog entry to config-patches@gnu.org. -+# Please send patches to . - - - me=`echo "$0" | sed -e 's,.*/,,'` -@@ -50,7 +50,7 @@ version="\ - GNU config.guess ($timestamp) - - Originally written by Per Bothner. --Copyright 1992-2014 Free Software Foundation, Inc. -+Copyright 1992-2015 Free Software Foundation, Inc. - - This is free software; see the source for copying conditions. There is NO - warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." -@@ -168,20 +168,27 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in - # Note: NetBSD doesn't particularly care about the vendor - # portion of the name. We always set it to "unknown". - sysctl="sysctl -n hw.machine_arch" -- UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ -- /usr/sbin/$sysctl 2>/dev/null || echo unknown)` -+ UNAME_MACHINE_ARCH=`(uname -p 2>/dev/null || \ -+ /sbin/$sysctl 2>/dev/null || \ -+ /usr/sbin/$sysctl 2>/dev/null || \ -+ echo unknown)` - case "${UNAME_MACHINE_ARCH}" in - armeb) machine=armeb-unknown ;; - arm*) machine=arm-unknown ;; - sh3el) machine=shl-unknown ;; - sh3eb) machine=sh-unknown ;; - sh5el) machine=sh5le-unknown ;; -+ earmv*) -+ arch=`echo ${UNAME_MACHINE_ARCH} | sed -e 's,^e\(armv[0-9]\).*$,\1,'` -+ endian=`echo ${UNAME_MACHINE_ARCH} | sed -ne 's,^.*\(eb\)$,\1,p'` -+ machine=${arch}${endian}-unknown -+ ;; - *) machine=${UNAME_MACHINE_ARCH}-unknown ;; - esac - # The Operating System including object format, if it has switched - # to ELF recently, or will in the future. - case "${UNAME_MACHINE_ARCH}" in -- arm*|i386|m68k|ns32k|sh3*|sparc|vax) -+ arm*|earm*|i386|m68k|ns32k|sh3*|sparc|vax) - eval $set_cc_for_build - if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ - | grep -q __ELF__ -@@ -197,6 +204,13 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in - os=netbsd - ;; - esac -+ # Determine ABI tags. -+ case "${UNAME_MACHINE_ARCH}" in -+ earm*) -+ expr='s/^earmv[0-9]/-eabi/;s/eb$//' -+ abi=`echo ${UNAME_MACHINE_ARCH} | sed -e "$expr"` -+ ;; -+ esac - # The OS release - # Debian GNU/NetBSD machines have a different userland, and - # thus, need a distinct triplet. However, they do not need -@@ -213,7 +227,7 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in - # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: - # contains redundant information, the shorter form: - # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. -- echo "${machine}-${os}${release}" -+ echo "${machine}-${os}${release}${abi}" - exit ;; - *:Bitrig:*:*) - UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'` -@@ -579,8 +593,9 @@ EOF - else - IBM_ARCH=powerpc - fi -- if [ -x /usr/bin/oslevel ] ; then -- IBM_REV=`/usr/bin/oslevel` -+ if [ -x /usr/bin/lslpp ] ; then -+ IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc | -+ awk -F: '{ print $3 }' | sed s/[0-9]*$/0/` - else - IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} - fi -@@ -932,6 +947,9 @@ EOF - crisv32:Linux:*:*) - echo ${UNAME_MACHINE}-axis-linux-${LIBC} - exit ;; -+ e2k:Linux:*:*) -+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC} -+ exit ;; - frv:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} - exit ;; -diff --git a/config/config.rpath b/config/config.rpath -index c38b914..b625621 100755 ---- a/config/config.rpath -+++ b/config/config.rpath -@@ -2,7 +2,7 @@ - # Output a system dependent set of variables, describing how to set the - # run time search path of shared libraries in an executable. - # --# Copyright 1996-2013 Free Software Foundation, Inc. -+# Copyright 1996-2014 Free Software Foundation, Inc. - # Taken from GNU libtool, 2001 - # Originally by Gordon Matzigkeit , 1996 - # -@@ -367,11 +367,7 @@ else - dgux*) - hardcode_libdir_flag_spec='-L$libdir' - ;; -- freebsd2.2*) -- hardcode_libdir_flag_spec='-R$libdir' -- hardcode_direct=yes -- ;; -- freebsd2*) -+ freebsd2.[01]*) - hardcode_direct=yes - hardcode_minus_L=yes - ;; -@@ -548,13 +544,11 @@ case "$host_os" in - dgux*) - library_names_spec='$libname$shrext' - ;; -+ freebsd[23].*) -+ library_names_spec='$libname$shrext$versuffix' -+ ;; - freebsd* | dragonfly*) -- case "$host_os" in -- freebsd[123]*) -- library_names_spec='$libname$shrext$versuffix' ;; -- *) -- library_names_spec='$libname$shrext' ;; -- esac -+ library_names_spec='$libname$shrext' - ;; - gnu*) - library_names_spec='$libname$shrext' -diff --git a/config/config.sub b/config/config.sub -old mode 100644 -new mode 100755 -index d654d03..8f1229c ---- a/config/config.sub -+++ b/config/config.sub -@@ -1,8 +1,8 @@ - #! /bin/sh - # Configuration validation subroutine script. --# Copyright 1992-2014 Free Software Foundation, Inc. -+# Copyright 1992-2015 Free Software Foundation, Inc. - --timestamp='2014-05-01' -+timestamp='2015-03-08' - - # This file is free software; you can redistribute it and/or modify it - # under the terms of the GNU General Public License as published by -@@ -25,7 +25,7 @@ timestamp='2014-05-01' - # of the GNU General Public License, version 3 ("GPLv3"). - - --# Please send patches with a ChangeLog entry to config-patches@gnu.org. -+# Please send patches to . - # - # Configuration subroutine to validate and canonicalize a configuration type. - # Supply the specified configuration type as an argument. -@@ -68,7 +68,7 @@ Report bugs and patches to ." - version="\ - GNU config.sub ($timestamp) - --Copyright 1992-2014 Free Software Foundation, Inc. -+Copyright 1992-2015 Free Software Foundation, Inc. - - This is free software; see the source for copying conditions. There is NO - warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." -@@ -117,7 +117,7 @@ maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` - case $maybe_os in - nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \ - linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \ -- knetbsd*-gnu* | netbsd*-gnu* | \ -+ knetbsd*-gnu* | netbsd*-gnu* | netbsd*-eabi* | \ - kopensolaris*-gnu* | \ - storm-chaos* | os2-emx* | rtmk-nova*) - os=-$maybe_os -@@ -259,8 +259,8 @@ case $basic_machine in - | bfin \ - | c4x | c8051 | clipper \ - | d10v | d30v | dlx | dsp16xx \ -- | epiphany \ -- | fido | fr30 | frv \ -+ | e2k | epiphany \ -+ | fido | fr30 | frv | ft32 \ - | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ - | hexagon \ - | i370 | i860 | i960 | ia64 \ -@@ -302,6 +302,7 @@ case $basic_machine in - | pdp10 | pdp11 | pj | pjl \ - | powerpc | powerpc64 | powerpc64le | powerpcle \ - | pyramid \ -+ | riscv32 | riscv64 \ - | rl78 | rx \ - | score \ - | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ -@@ -312,6 +313,7 @@ case $basic_machine in - | tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \ - | ubicom32 \ - | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \ -+ | visium \ - | we32k \ - | x86 | xc16x | xstormy16 | xtensa \ - | z8k | z80) -@@ -326,6 +328,9 @@ case $basic_machine in - c6x) - basic_machine=tic6x-unknown - ;; -+ leon|leon[3-9]) -+ basic_machine=sparc-$basic_machine -+ ;; - m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | nvptx | picochip) - basic_machine=$basic_machine-unknown - os=-none -@@ -376,7 +381,7 @@ case $basic_machine in - | c[123]* | c30-* | [cjt]90-* | c4x-* \ - | c8051-* | clipper-* | craynv-* | cydra-* \ - | d10v-* | d30v-* | dlx-* \ -- | elxsi-* \ -+ | e2k-* | elxsi-* \ - | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ - | h8300-* | h8500-* \ - | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ -@@ -436,6 +441,7 @@ case $basic_machine in - | ubicom32-* \ - | v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \ - | vax-* \ -+ | visium-* \ - | we32k-* \ - | x86-* | x86_64-* | xc16x-* | xps100-* \ - | xstormy16-* | xtensa*-* \ -@@ -512,6 +518,9 @@ case $basic_machine in - basic_machine=i386-pc - os=-aros - ;; -+ asmjs) -+ basic_machine=asmjs-unknown -+ ;; - aux) - basic_machine=m68k-apple - os=-aux -@@ -773,6 +782,9 @@ case $basic_machine in - basic_machine=m68k-isi - os=-sysv - ;; -+ leon-*|leon[3-9]-*) -+ basic_machine=sparc-`echo $basic_machine | sed 's/-.*//'` -+ ;; - m68knommu) - basic_machine=m68k-unknown - os=-linux -@@ -828,6 +840,10 @@ case $basic_machine in - basic_machine=powerpc-unknown - os=-morphos - ;; -+ moxiebox) -+ basic_machine=moxie-unknown -+ os=-moxiebox -+ ;; - msdos) - basic_machine=i386-pc - os=-msdos -@@ -1360,7 +1376,7 @@ case $os in - | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \ - | -sym* | -kopensolaris* | -plan9* \ - | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ -- | -aos* | -aros* \ -+ | -aos* | -aros* | -cloudabi* \ - | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ - | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ - | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ -@@ -1373,7 +1389,7 @@ case $os in - | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ - | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \ - | -linux-newlib* | -linux-musl* | -linux-uclibc* \ -- | -uxpv* | -beos* | -mpeix* | -udk* \ -+ | -uxpv* | -beos* | -mpeix* | -udk* | -moxiebox* \ - | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ - | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ - | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ -diff --git a/configure b/configure -index f9de3f6..30b0949 100755 ---- a/configure -+++ b/configure -@@ -643,6 +643,9 @@ CYGWIN_CMT - LINUX_CMT - UNI_DIFF_OPTS - SEM_INIT_LIB -+FUSE_CMT -+FUSE_LIB -+MAGIC_LIB - SOCKET_LIB - SIZEOF_OFF_T - SIZEOF_LONG_LONG -@@ -733,14 +736,6 @@ DEFRAG_CMT - RESIZER_CMT - IMAGER_CMT - DEBUGFS_CMT --QUOTA_CMT --DEPPROFILED_LIBQUOTA --PROFILED_LIBQUOTA --DEPSTATIC_LIBQUOTA --STATIC_LIBQUOTA --DEPLIBQUOTA --LIBQUOTA --QUOTA_MAN_COMMENT - BLKID_CMT - DEPPROFILED_LIBBLKID - PROFILED_LIBBLKID -@@ -767,7 +762,6 @@ LIB_EXT - PROFILE_CMT - BSDLIB_CMT - ELF_CMT --HTREE_CMT - Q - ES - E -@@ -858,8 +852,6 @@ enable_relative_symlinks - enable_symlink_relative_symlinks - enable_symlink_build - enable_verbose_makecmds --enable_compression --enable_htree - enable_elf_shlibs - enable_bsd_shlibs - enable_profile -@@ -869,7 +861,6 @@ enable_blkid_debug - enable_testio_debug - enable_libuuid - enable_libblkid --enable_quota - enable_backtrace - enable_debugfs - enable_imager -@@ -879,6 +870,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 -@@ -887,6 +881,7 @@ with_libpth_prefix - with_libiconv_prefix - with_included_gettext - with_libintl_prefix -+enable_fuse2fs - with_multiarch - ' - ac_precious_vars='build_alias -@@ -1518,8 +1513,6 @@ Optional Features: - - --enable-symlink-build use symlinks while building instead of hard links - --enable-verbose-makecmds enable verbose make command output -- --enable-compression enable EXPERIMENTAL compression support -- --enable-htree enable EXPERIMENTAL htree directory support - --enable-elf-shlibs select ELF shared libraries - --enable-bsd-shlibs select BSD shared libraries - --enable-profile build profiling libraries -@@ -1527,9 +1520,8 @@ Optional Features: - --enable-jbd-debug enable journal debugging - --enable-blkid-debug enable blkid debugging - --disable-testio-debug disable the use of the test I/O manager for debugging -- --disable-libuuid do not build private uuid library -- --disable-libblkid do not build private blkid library -- --enable-quota enable quota support -+ --enable-libuuid build and use private uuid library -+ --enable-libblkid build and use private blkid library - --disable-backtrace disable use backtrace - --disable-debugfs disable support of debugfs program - --disable-imager disable support of e2image program -@@ -1539,11 +1531,15 @@ 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 - --disable-threads build without multithread safety - --disable-rpath do not hardcode runtime library paths -+ --disable-fuse2fs do not build fuse2fs - - Optional Packages: - --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] -@@ -4895,54 +4891,6 @@ fi - - - --# Check whether --enable-compression was given. --if test "${enable_compression+set}" = set; then : -- enableval=$enable_compression; if test "$enableval" = "no" --then -- { $as_echo "$as_me:${as_lineno-$LINENO}: result: Disabling compression support" >&5 --$as_echo "Disabling compression support" >&6; } --else -- --$as_echo "#define ENABLE_COMPRESSION 1" >>confdefs.h -- -- { $as_echo "$as_me:${as_lineno-$LINENO}: result: Enabling compression support" >&5 --$as_echo "Enabling compression support" >&6; } -- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Compression support is experimental" >&5 --$as_echo "$as_me: WARNING: Compression support is experimental" >&2;} --fi -- --else -- { $as_echo "$as_me:${as_lineno-$LINENO}: result: Disabling compression support by default" >&5 --$as_echo "Disabling compression support by default" >&6; } -- --fi -- -- --# Check whether --enable-htree was given. --if test "${enable_htree+set}" = set; then : -- enableval=$enable_htree; if test "$enableval" = "no" --then -- HTREE_CMT=# -- { $as_echo "$as_me:${as_lineno-$LINENO}: result: Disabling htree directory support" >&5 --$as_echo "Disabling htree directory support" >&6; } --else -- HTREE_CMT= -- $as_echo "#define ENABLE_HTREE 1" >>confdefs.h -- -- { $as_echo "$as_me:${as_lineno-$LINENO}: result: Enabling htree directory support" >&5 --$as_echo "Enabling htree directory support" >&6; } --fi -- --else -- HTREE_CMT= --$as_echo "#define ENABLE_HTREE 1" >>confdefs.h -- --{ $as_echo "$as_me:${as_lineno-$LINENO}: result: Enabling htree directory support by default" >&5 --$as_echo "Enabling htree directory support by default" >&6; } -- --fi -- -- - E2_PKG_CONFIG_STATIC=--static - LDFLAG_DYNAMIC= - PRIVATE_LIBS_CMT= -@@ -5318,14 +5266,64 @@ $as_echo "Enabling private uuid library" >&6; } - fi - - else -- LIBUUID='$(LIB)/libuuid'$LIB_EXT --DEPLIBUUID=$LIBUUID --STATIC_LIBUUID='$(LIB)/libuuid'$STATIC_LIB_EXT --DEPSTATIC_LIBUUID=$STATIC_LIBUUID --PROFILED_LIBUUID='$(LIB)/libuuid'$PROFILED_LIB_EXT --DEPPROFILED_LIBUUID=$PROFILED_LIBUUID --{ $as_echo "$as_me:${as_lineno-$LINENO}: result: Enabling private uuid library by default" >&5 -+ if test -n "$PKG_CONFIG"; then -+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for uuid_generate in -luuid" >&5 -+$as_echo_n "checking for uuid_generate in -luuid... " >&6; } -+if ${ac_cv_lib_uuid_uuid_generate+:} false; then : -+ $as_echo_n "(cached) " >&6 -+else -+ ac_check_lib_save_LIBS=$LIBS -+LIBS="-luuid $LIBS" -+cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+/* end confdefs.h. */ -+ -+/* Override any GCC internal prototype to avoid an error. -+ Use char because int might match the return type of a GCC -+ builtin and then its argument prototype would still apply. */ -+#ifdef __cplusplus -+extern "C" -+#endif -+char uuid_generate (); -+int -+main () -+{ -+return uuid_generate (); -+ ; -+ return 0; -+} -+_ACEOF -+if ac_fn_c_try_link "$LINENO"; then : -+ ac_cv_lib_uuid_uuid_generate=yes -+else -+ ac_cv_lib_uuid_uuid_generate=no -+fi -+rm -f core conftest.err conftest.$ac_objext \ -+ conftest$ac_exeext conftest.$ac_ext -+LIBS=$ac_check_lib_save_LIBS -+fi -+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_uuid_uuid_generate" >&5 -+$as_echo "$ac_cv_lib_uuid_uuid_generate" >&6; } -+if test "x$ac_cv_lib_uuid_uuid_generate" = xyes; then : -+ LIBUUID=`$PKG_CONFIG --libs uuid`; -+ STATIC_LIBUUID=`$PKG_CONFIG --static --libs uuid` -+fi -+ -+fi -+if test -n "$LIBUUID"; then -+ PROFILED_LIBUUID=$LIBUUID -+ UUID_CMT=# -+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: Using system uuid by default" >&5 -+$as_echo "Using system uuid by default" >&6; } -+else -+ LIBUUID='$(LIB)/libuuid'$LIB_EXT -+ DEPLIBUUID=$LIBUUID -+ STATIC_LIBUUID='$(LIB)/libuuid'$STATIC_LIB_EXT -+ DEPSTATIC_LIBUUID=$STATIC_LIBUUID -+ PROFILED_LIBUUID='$(LIB)/libuuid'$PROFILED_LIB_EXT -+ DEPPROFILED_LIBUUID=$PROFILED_LIBUUID -+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: Enabling private uuid library by default" >&5 - $as_echo "Enabling private uuid library by default" >&6; } -+fi - - fi - -@@ -5533,180 +5531,69 @@ $as_echo "Enabling private blkid library" >&6; } - fi - - else -- LIBBLKID='$(LIB)/libblkid'$LIB_EXT --DEPLIBBLKID=$LIBBLKID --STATIC_LIBBLKID='$(LIB)/libblkid'$STATIC_LIB_EXT --DEPSTATIC_LIBBLKID=$STATIC_LIBBLKID --PROFILED_LIBBLKID='$(LIB)/libblkid'$PROFILED_LIB_EXT --DEPPROFILED_LIBBLKID=$PROFILED_LIBBLKID --$as_echo "#define CONFIG_BUILD_FINDFS 1" >>confdefs.h -- --{ $as_echo "$as_me:${as_lineno-$LINENO}: result: Enabling private blkid library by default" >&5 --$as_echo "Enabling private blkid library by default" >&6; } -- --fi -- -- -- -- -- -- -- -- --QUOTA_MAN_COMMENT='.\"' --QUOTA_CMT= -- -- -- -- -- -- -- -- --if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then -- if test -n "$ac_tool_prefix"; then -- # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args. --set dummy ${ac_tool_prefix}pkg-config; ac_word=$2 --{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 --$as_echo_n "checking for $ac_word... " >&6; } --if ${ac_cv_path_PKG_CONFIG+:} false; then : -+ if test -n "$PKG_CONFIG"; then -+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for blkid_get_cache in -lblkid" >&5 -+$as_echo_n "checking for blkid_get_cache in -lblkid... " >&6; } -+if ${ac_cv_lib_blkid_blkid_get_cache+:} false; then : - $as_echo_n "(cached) " >&6 - else -- case $PKG_CONFIG in -- [\\/]* | ?:[\\/]*) -- ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path. -- ;; -- *) -- as_save_IFS=$IFS; IFS=$PATH_SEPARATOR --for as_dir in $PATH --do -- IFS=$as_save_IFS -- test -z "$as_dir" && as_dir=. -- for ac_exec_ext in '' $ac_executable_extensions; do -- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then -- ac_cv_path_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext" -- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 -- break 2 -- fi --done -- done --IFS=$as_save_IFS -- -- ;; --esac --fi --PKG_CONFIG=$ac_cv_path_PKG_CONFIG --if test -n "$PKG_CONFIG"; then -- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5 --$as_echo "$PKG_CONFIG" >&6; } --else -- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 --$as_echo "no" >&6; } --fi -- -+ ac_check_lib_save_LIBS=$LIBS -+LIBS="-lblkid $LIBS" -+cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+/* end confdefs.h. */ - --fi --if test -z "$ac_cv_path_PKG_CONFIG"; then -- ac_pt_PKG_CONFIG=$PKG_CONFIG -- # Extract the first word of "pkg-config", so it can be a program name with args. --set dummy pkg-config; ac_word=$2 --{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 --$as_echo_n "checking for $ac_word... " >&6; } --if ${ac_cv_path_ac_pt_PKG_CONFIG+:} false; then : -- $as_echo_n "(cached) " >&6 -+/* Override any GCC internal prototype to avoid an error. -+ Use char because int might match the return type of a GCC -+ builtin and then its argument prototype would still apply. */ -+#ifdef __cplusplus -+extern "C" -+#endif -+char blkid_get_cache (); -+int -+main () -+{ -+return blkid_get_cache (); -+ ; -+ return 0; -+} -+_ACEOF -+if ac_fn_c_try_link "$LINENO"; then : -+ ac_cv_lib_blkid_blkid_get_cache=yes - else -- case $ac_pt_PKG_CONFIG in -- [\\/]* | ?:[\\/]*) -- ac_cv_path_ac_pt_PKG_CONFIG="$ac_pt_PKG_CONFIG" # Let the user override the test with a path. -- ;; -- *) -- as_save_IFS=$IFS; IFS=$PATH_SEPARATOR --for as_dir in $PATH --do -- IFS=$as_save_IFS -- test -z "$as_dir" && as_dir=. -- for ac_exec_ext in '' $ac_executable_extensions; do -- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then -- ac_cv_path_ac_pt_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext" -- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 -- break 2 -- fi --done -- done --IFS=$as_save_IFS -- -- ;; --esac -+ ac_cv_lib_blkid_blkid_get_cache=no - fi --ac_pt_PKG_CONFIG=$ac_cv_path_ac_pt_PKG_CONFIG --if test -n "$ac_pt_PKG_CONFIG"; then -- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKG_CONFIG" >&5 --$as_echo "$ac_pt_PKG_CONFIG" >&6; } --else -- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 --$as_echo "no" >&6; } -+rm -f core conftest.err conftest.$ac_objext \ -+ conftest$ac_exeext conftest.$ac_ext -+LIBS=$ac_check_lib_save_LIBS - fi -- -- if test "x$ac_pt_PKG_CONFIG" = x; then -- PKG_CONFIG="" -- else -- case $cross_compiling:$ac_tool_warned in --yes:) --{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 --$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} --ac_tool_warned=yes ;; --esac -- PKG_CONFIG=$ac_pt_PKG_CONFIG -- fi --else -- PKG_CONFIG="$ac_cv_path_PKG_CONFIG" -+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_blkid_blkid_get_cache" >&5 -+$as_echo "$ac_cv_lib_blkid_blkid_get_cache" >&6; } -+if test "x$ac_cv_lib_blkid_blkid_get_cache" = xyes; then : -+ LIBBLKID=`$PKG_CONFIG --libs blkid`; -+ STATIC_LIBBLKID=`$PKG_CONFIG --static --libs blkid` - fi - - fi --if test -n "$PKG_CONFIG"; then -- _pkg_min_version=0.9.0 -- { $as_echo "$as_me:${as_lineno-$LINENO}: checking pkg-config is at least version $_pkg_min_version" >&5 --$as_echo_n "checking pkg-config is at least version $_pkg_min_version... " >&6; } -- if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then -- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 --$as_echo "yes" >&6; } -- else -- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 --$as_echo "no" >&6; } -- PKG_CONFIG="" -- fi --fi -- --# Check whether --enable-quota was given. --if test "${enable_quota+set}" = set; then : -- enableval=$enable_quota; if test "$enableval" = "no" --then -- QUOTA_CMT=# -- { $as_echo "$as_me:${as_lineno-$LINENO}: result: Disabling quota support" >&5 --$as_echo "Disabling quota support" >&6; } -+if test -n "$LIBBLKID"; then -+ BLKID_CMT=# -+ PROFILED_LIBBLKID=$LIBBLKID -+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: Using system blkid library by default" >&5 -+$as_echo "Using system blkid library by default" >&6; } - else -- QUOTA_CMT= -- $as_echo "#define CONFIG_QUOTA 1" >>confdefs.h -- -- { $as_echo "$as_me:${as_lineno-$LINENO}: result: Enabling quota support" >&5 --$as_echo "Enabling quota support" >&6; } -- QUOTA_MAN_COMMENT="" -+ LIBBLKID='$(LIB)/libblkid'$LIB_EXT -+ DEPLIBBLKID=$LIBBLKID -+ STATIC_LIBBLKID='$(LIB)/libblkid'$STATIC_LIB_EXT -+ DEPSTATIC_LIBBLKID=$STATIC_LIBBLKID -+ PROFILED_LIBBLKID='$(LIB)/libblkid'$PROFILED_LIB_EXT -+ DEPPROFILED_LIBBLKID=$PROFILED_LIBBLKID -+ $as_echo "#define CONFIG_BUILD_FINDFS 1" >>confdefs.h - -+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: Enabling private blkid library by default" >&5 -+$as_echo "Enabling private blkid library by default" >&6; } - fi - --else -- QUOTA_CMT=# --{ $as_echo "$as_me:${as_lineno-$LINENO}: result: Disabling quota support by default" >&5 --$as_echo "Disabling quota support by default" >&6; } -- - fi - --LIBQUOTA='$(LIB)/libquota'$LIB_EXT --DEPLIBQUOTA=$LIBQUOTA --STATIC_LIBQUOTA='$(LIB)/libquota'$STATIC_LIB_EXT --DEPSTATIC_LIBQUOTA=$STATIC_LIBQUOTA --PROFILED_LIBQUOTA='$(LIB)/libquota'$PROFILED_LIB_EXT --DEPPROFILED_LIBQUOTA=$PROFILED_LIBQUOTA - - - -@@ -5991,6 +5878,77 @@ fi - 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 -@@ -12336,7 +12294,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/acl.h sys/disklabel.h sys/disk.h sys/file.h sys/ioctl.h sys/key.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/sysctl.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" -@@ -13003,7 +12961,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 utimes valloc -+for ac_func in __secure_getenv add_key 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 keyctl 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 utimes 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" -@@ -13057,6 +13015,329 @@ if test "x$ac_cv_lib_socket_socket" = xyes; then : - fi - - -+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for magic_file in -lmagic" >&5 -+$as_echo_n "checking for magic_file in -lmagic... " >&6; } -+if ${ac_cv_lib_magic_magic_file+:} false; then : -+ $as_echo_n "(cached) " >&6 -+else -+ ac_check_lib_save_LIBS=$LIBS -+LIBS="-lmagic $LIBS" -+cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+/* end confdefs.h. */ -+ -+/* Override any GCC internal prototype to avoid an error. -+ Use char because int might match the return type of a GCC -+ builtin and then its argument prototype would still apply. */ -+#ifdef __cplusplus -+extern "C" -+#endif -+char magic_file (); -+int -+main () -+{ -+return magic_file (); -+ ; -+ return 0; -+} -+_ACEOF -+if ac_fn_c_try_link "$LINENO"; then : -+ ac_cv_lib_magic_magic_file=yes -+else -+ ac_cv_lib_magic_magic_file=no -+fi -+rm -f core conftest.err conftest.$ac_objext \ -+ conftest$ac_exeext conftest.$ac_ext -+LIBS=$ac_check_lib_save_LIBS -+fi -+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_magic_magic_file" >&5 -+$as_echo "$ac_cv_lib_magic_magic_file" >&6; } -+if test "x$ac_cv_lib_magic_magic_file" = xyes; then : -+ MAGIC_LIB=-lmagic -+for ac_header in magic.h -+do : -+ ac_fn_c_check_header_mongrel "$LINENO" "magic.h" "ac_cv_header_magic_h" "$ac_includes_default" -+if test "x$ac_cv_header_magic_h" = xyes; then : -+ cat >>confdefs.h <<_ACEOF -+#define HAVE_MAGIC_H 1 -+_ACEOF -+ -+fi -+ -+done -+ -+fi -+ -+if test "$ac_cv_lib_dl_dlopen" = yes ; then -+ MAGIC_LIB=$DLOPEN_LIB -+fi -+ -+FUSE_CMT= -+FUSE_LIB= -+# Check whether --enable-fuse2fs was given. -+if test "${enable_fuse2fs+set}" = set; then : -+ enableval=$enable_fuse2fs; if test "$enableval" = "no" -+then -+ FUSE_CMT="#" -+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: Disabling fuse2fs" >&5 -+$as_echo "Disabling fuse2fs" >&6; } -+else -+ for ac_header in pthread.h fuse.h -+do : -+ as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` -+ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "#define _FILE_OFFSET_BITS 64 -+#define FUSE_USE_VERSION 29 -+" -+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : -+ cat >>confdefs.h <<_ACEOF -+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 -+_ACEOF -+ -+else -+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -+as_fn_error $? "Cannot find fuse2fs headers. -+See \`config.log' for more details" "$LINENO" 5; } -+fi -+ -+done -+ -+ -+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+/* end confdefs.h. */ -+#define FUSE_USE_VERSION 29 -+#ifdef __linux__ -+#include -+#include -+#include -+#endif -+ -+int -+main () -+{ -+ -+ ; -+ return 0; -+} -+_ACEOF -+if ac_fn_c_try_cpp "$LINENO"; then : -+ -+else -+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -+as_fn_error $? "Cannot find fuse2fs Linux headers. -+See \`config.log' for more details" "$LINENO" 5; } -+fi -+rm -f conftest.err conftest.i conftest.$ac_ext -+ -+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for fuse_main in -losxfuse" >&5 -+$as_echo_n "checking for fuse_main in -losxfuse... " >&6; } -+if ${ac_cv_lib_osxfuse_fuse_main+:} false; then : -+ $as_echo_n "(cached) " >&6 -+else -+ ac_check_lib_save_LIBS=$LIBS -+LIBS="-losxfuse $LIBS" -+cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+/* end confdefs.h. */ -+ -+/* Override any GCC internal prototype to avoid an error. -+ Use char because int might match the return type of a GCC -+ builtin and then its argument prototype would still apply. */ -+#ifdef __cplusplus -+extern "C" -+#endif -+char fuse_main (); -+int -+main () -+{ -+return fuse_main (); -+ ; -+ return 0; -+} -+_ACEOF -+if ac_fn_c_try_link "$LINENO"; then : -+ ac_cv_lib_osxfuse_fuse_main=yes -+else -+ ac_cv_lib_osxfuse_fuse_main=no -+fi -+rm -f core conftest.err conftest.$ac_objext \ -+ conftest$ac_exeext conftest.$ac_ext -+LIBS=$ac_check_lib_save_LIBS -+fi -+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_osxfuse_fuse_main" >&5 -+$as_echo "$ac_cv_lib_osxfuse_fuse_main" >&6; } -+if test "x$ac_cv_lib_osxfuse_fuse_main" = xyes; then : -+ FUSE_LIB=-losxfuse -+else -+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for fuse_main in -lfuse" >&5 -+$as_echo_n "checking for fuse_main in -lfuse... " >&6; } -+if ${ac_cv_lib_fuse_fuse_main+:} false; then : -+ $as_echo_n "(cached) " >&6 -+else -+ ac_check_lib_save_LIBS=$LIBS -+LIBS="-lfuse $LIBS" -+cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+/* end confdefs.h. */ -+ -+/* Override any GCC internal prototype to avoid an error. -+ Use char because int might match the return type of a GCC -+ builtin and then its argument prototype would still apply. */ -+#ifdef __cplusplus -+extern "C" -+#endif -+char fuse_main (); -+int -+main () -+{ -+return fuse_main (); -+ ; -+ return 0; -+} -+_ACEOF -+if ac_fn_c_try_link "$LINENO"; then : -+ ac_cv_lib_fuse_fuse_main=yes -+else -+ ac_cv_lib_fuse_fuse_main=no -+fi -+rm -f core conftest.err conftest.$ac_objext \ -+ conftest$ac_exeext conftest.$ac_ext -+LIBS=$ac_check_lib_save_LIBS -+fi -+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_fuse_fuse_main" >&5 -+$as_echo "$ac_cv_lib_fuse_fuse_main" >&6; } -+if test "x$ac_cv_lib_fuse_fuse_main" = xyes; then : -+ FUSE_LIB=-lfuse -+else -+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -+as_fn_error $? "Cannot find fuse library. -+See \`config.log' for more details" "$LINENO" 5; } -+fi -+ -+fi -+ -+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: Enabling fuse2fs" >&5 -+$as_echo "Enabling fuse2fs" >&6; } -+fi -+ -+else -+ for ac_header in pthread.h fuse.h -+do : -+ as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` -+ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "#define _FILE_OFFSET_BITS 64 -+#define FUSE_USE_VERSION 29 -+#ifdef __linux__ -+# include -+# include -+# include -+#endif -+" -+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : -+ cat >>confdefs.h <<_ACEOF -+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 -+_ACEOF -+ -+else -+ FUSE_CMT="#" -+fi -+ -+done -+ -+if test -z "$FUSE_CMT" -+then -+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for fuse_main in -losxfuse" >&5 -+$as_echo_n "checking for fuse_main in -losxfuse... " >&6; } -+if ${ac_cv_lib_osxfuse_fuse_main+:} false; then : -+ $as_echo_n "(cached) " >&6 -+else -+ ac_check_lib_save_LIBS=$LIBS -+LIBS="-losxfuse $LIBS" -+cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+/* end confdefs.h. */ -+ -+/* Override any GCC internal prototype to avoid an error. -+ Use char because int might match the return type of a GCC -+ builtin and then its argument prototype would still apply. */ -+#ifdef __cplusplus -+extern "C" -+#endif -+char fuse_main (); -+int -+main () -+{ -+return fuse_main (); -+ ; -+ return 0; -+} -+_ACEOF -+if ac_fn_c_try_link "$LINENO"; then : -+ ac_cv_lib_osxfuse_fuse_main=yes -+else -+ ac_cv_lib_osxfuse_fuse_main=no -+fi -+rm -f core conftest.err conftest.$ac_objext \ -+ conftest$ac_exeext conftest.$ac_ext -+LIBS=$ac_check_lib_save_LIBS -+fi -+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_osxfuse_fuse_main" >&5 -+$as_echo "$ac_cv_lib_osxfuse_fuse_main" >&6; } -+if test "x$ac_cv_lib_osxfuse_fuse_main" = xyes; then : -+ FUSE_LIB=-losxfuse -+else -+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for fuse_main in -lfuse" >&5 -+$as_echo_n "checking for fuse_main in -lfuse... " >&6; } -+if ${ac_cv_lib_fuse_fuse_main+:} false; then : -+ $as_echo_n "(cached) " >&6 -+else -+ ac_check_lib_save_LIBS=$LIBS -+LIBS="-lfuse $LIBS" -+cat confdefs.h - <<_ACEOF >conftest.$ac_ext -+/* end confdefs.h. */ -+ -+/* Override any GCC internal prototype to avoid an error. -+ Use char because int might match the return type of a GCC -+ builtin and then its argument prototype would still apply. */ -+#ifdef __cplusplus -+extern "C" -+#endif -+char fuse_main (); -+int -+main () -+{ -+return fuse_main (); -+ ; -+ return 0; -+} -+_ACEOF -+if ac_fn_c_try_link "$LINENO"; then : -+ ac_cv_lib_fuse_fuse_main=yes -+else -+ ac_cv_lib_fuse_fuse_main=no -+fi -+rm -f core conftest.err conftest.$ac_objext \ -+ conftest$ac_exeext conftest.$ac_ext -+LIBS=$ac_check_lib_save_LIBS -+fi -+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_fuse_fuse_main" >&5 -+$as_echo "$ac_cv_lib_fuse_fuse_main" >&6; } -+if test "x$ac_cv_lib_fuse_fuse_main" = xyes; then : -+ FUSE_LIB=-lfuse -+else -+ FUSE_CMT="#" -+fi -+ -+fi -+ -+fi -+if test -z "$FUSE_CMT" -+then -+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: Enabling fuse2fs by default." >&5 -+$as_echo "Enabling fuse2fs by default." >&6; } -+fi -+ -+fi -+ -+ -+ - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for optreset" >&5 - $as_echo_n "checking for optreset... " >&6; } - if ${ac_cv_have_optreset+:} false; then : -@@ -13419,14 +13700,20 @@ test -d lib || mkdir lib - test -d include || mkdir include - test -d include/linux || mkdir include/linux - test -d include/asm || mkdir include/asm -+if test -z "$UUID_CMT" ; then -+ uuid_out_list="lib/uuid/Makefile lib/uuid/uuid.pc \ -+ lib/uuid/uuid_types.h" -+fi -+if test -z "$BLKID_CMT" ; then -+ blkid_out_list="lib/blkid/Makefile lib/blkid/blkid.pc \ -+ lib/blkid/blkid_types.h" -+fi - for i in MCONFIG Makefile e2fsprogs.spec \ - util/Makefile util/subst.conf util/gen-tarball util/install-symlink \ - lib/et/Makefile lib/ss/Makefile lib/e2p/Makefile \ - lib/ext2fs/Makefile lib/ext2fs/ext2_types.h \ -- lib/uuid/Makefile lib/uuid/uuid_types.h \ -- lib/blkid/Makefile lib/blkid/blkid_types.h lib/quota/Makefile \ -- lib/ss/ss.pc lib/uuid/uuid.pc lib/et/com_err.pc \ -- lib/e2p/e2p.pc lib/blkid/blkid.pc lib/ext2fs/ext2fs.pc \ -+ $uuid_out_list $blkid_out_list lib/support/Makefile \ -+ lib/ss/ss.pc lib/et/com_err.pc lib/e2p/e2p.pc lib/ext2fs/ext2fs.pc \ - misc/Makefile ext2ed/Makefile e2fsck/Makefile \ - debugfs/Makefile tests/Makefile tests/progs/Makefile \ - resize/Makefile doc/Makefile intl/Makefile \ -diff --git a/configure.ac b/configure.ac -new file mode 100644 -index 0000000..c1fe224 ---- /dev/null -+++ b/configure.ac -@@ -0,0 +1,1418 @@ -+AC_INIT(version.h) -+AC_PREREQ(2.54) -+AC_CONFIG_AUX_DIR(config) -+AC_CONFIG_HEADERS([lib/config.h]) -+AH_BOTTOM([#include ]) -+MCONFIG=./MCONFIG -+AC_SUBST_FILE(MCONFIG) -+BINARY_TYPE=bin -+dnl -+dnl This is to figure out the version number and the date.... -+dnl -+E2FSPROGS_VERSION=`grep E2FSPROGS_VERSION ${srcdir}/version.h \ -+ | awk '{print $3}' | tr \" " " | awk '{print $1}'` -+DATE=`grep E2FSPROGS_DATE ${srcdir}/version.h | awk '{print $3}' \ -+ | tr \" " "` -+E2FSPROGS_DAY=`echo $DATE | awk -F- '{print $1}'` -+MONTH=`echo $DATE | awk -F- '{print $2}'` -+YEAR=`echo $DATE | awk -F- '{print $3}'` -+ -+if expr $YEAR ">" 1900 > /dev/null ; then -+ E2FSPROGS_YEAR=$YEAR -+elif expr $YEAR ">" 90 >/dev/null ; then -+ E2FSPROGS_YEAR=19$YEAR -+else -+ E2FSPROGS_YEAR=20$YEAR -+fi -+ -+case $MONTH in -+Jan) MONTH_NUM=01; E2FSPROGS_MONTH="January" ;; -+Feb) MONTH_NUM=02; E2FSPROGS_MONTH="February" ;; -+Mar) MONTH_NUM=03; E2FSPROGS_MONTH="March" ;; -+Apr) MONTH_NUM=04; E2FSPROGS_MONTH="April" ;; -+May) MONTH_NUM=05; E2FSPROGS_MONTH="May" ;; -+Jun) MONTH_NUM=06; E2FSPROGS_MONTH="June" ;; -+Jul) MONTH_NUM=07; E2FSPROGS_MONTH="July" ;; -+Aug) MONTH_NUM=08; E2FSPROGS_MONTH="August" ;; -+Sep) MONTH_NUM=09; E2FSPROGS_MONTH="September" ;; -+Oct) MONTH_NUM=10; E2FSPROGS_MONTH="October" ;; -+Nov) MONTH_NUM=11; E2FSPROGS_MONTH="November" ;; -+Dec) MONTH_NUM=12; E2FSPROGS_MONTH="December" ;; -+*) AC_MSG_WARN([Unknown month $MONTH??]) ;; -+esac -+ -+base_ver=`echo $E2FSPROGS_VERSION | \ -+ sed -e 's/-WIP//' -e 's/pre-//' -e 's/-PLUS//'` -+ -+date_spec=${E2FSPROGS_YEAR}.${MONTH_NUM}.${E2FSPROGS_DAY} -+ -+case $E2FSPROGS_VERSION in -+*-WIP|pre-*) -+ E2FSPROGS_PKGVER="$base_ver~WIP-$E2FSPROGS_YEAR-$MONTH_NUM-$E2FSPROGS_DAY" -+ ;; -+*) -+ E2FSPROGS_PKGVER="$base_ver" -+ ;; -+esac -+ -+unset DATE MONTH YEAR base_ver pre_vers date_spec -+AC_MSG_RESULT([Generating configuration file for e2fsprogs version $E2FSPROGS_VERSION]) -+AC_MSG_RESULT([Release date is ${E2FSPROGS_MONTH}, ${E2FSPROGS_YEAR}]) -+AC_SUBST(E2FSPROGS_YEAR) -+AC_SUBST(E2FSPROGS_MONTH) -+AC_SUBST(E2FSPROGS_DAY) -+AC_SUBST(E2FSPROGS_VERSION) -+AC_SUBST(E2FSPROGS_PKGVER) -+dnl -+dnl Use diet libc -+dnl -+WITH_DIET_LIBC= -+AC_ARG_WITH([diet-libc], -+[ --with-diet-libc use diet libc], -+CC="diet cc -nostdinc" -+WITH_DIET_LIBC=yes -+if test -z "$LIBS" -+then -+ LIBS="-lcompat" -+else -+ LIBS="$LIBS -lcompat" -+fi -+AC_MSG_RESULT(CC=$CC))dnl -+dnl -+AC_CANONICAL_HOST -+dnl -+dnl Check to see if libdl exists for the sake of dlopen -+dnl -+DLOPEN_LIB='' -+AC_CHECK_LIB(dl, dlopen, -+[DLOPEN_LIB=-ldl -+AC_DEFINE(HAVE_DLOPEN, 1, [Define to 1 if dlopen/libdl exists])]) -+AC_SUBST(DLOPEN_LIB) -+dnl -+AC_ARG_WITH([cc], -+AC_HELP_STRING([--with-cc],[no longer supported, use CC= instead]), -+AC_MSG_ERROR([--with-cc no longer supported; use CC= instead])) -+dnl -+AC_ARG_WITH([ccopts], -+AC_HELP_STRING([--with-ccopts],[no longer supported, use CFLAGS= instead]), -+AC_MSG_ERROR([--with-ccopts no longer supported; use CFLAGS= instead])) -+dnl -+AC_ARG_WITH([ldopts], -+AC_HELP_STRING([--with-ldopts],[no longer supported, use LDFLAGS= instead]), -+AC_MSG_ERROR([--with-ldopts no longer supported; use LDFLAGS= instead])) -+dnl -+AC_PROG_CC -+if test "$GCC" = yes; then -+ RDYNAMIC="-rdynamic" -+ AC_SUBST(RDYNAMIC) -+fi -+AC_PROG_CPP -+dnl -+dnl Alpha computers use fast and imprecise floating point code that may -+dnl miss exceptions by default. Force sane options if we're using GCC. -+AC_MSG_CHECKING(for additional special compiler flags) -+if test "$GCC" = yes -+then -+ case "$host_cpu" in -+ alpha) addcflags="-mieee" ;; -+ esac -+fi -+if test "x$addcflags" != x -+then -+ AC_MSG_RESULT($addcflags) -+ CFLAGS="$addcflags $CFLAGS" -+else -+ AC_MSG_RESULT([[(none)]]) -+fi -+AC_USE_SYSTEM_EXTENSIONS -+dnl -+dnl Set default values for library extentions. Will be dealt with after -+dnl parsing configuration opions, which may modify these -+dnl -+LIB_EXT=.a -+STATIC_LIB_EXT=.a -+PROFILED_LIB_EXT=.a -+dnl -+dnl Allow separate `root_prefix' to be specified -+dnl -+AC_ARG_WITH([root-prefix], -+[ --with-root-prefix=PREFIX override prefix variable for files to be placed in the root], -+root_prefix=$withval, -+root_prefix=NONE)dnl -+dnl -+dnl handle --enable-maintainer-mode -+dnl -+AC_ARG_ENABLE([maintainer-mode], -+[ --enable-maintainer-mode enable makefile rules useful for maintainers], -+if test "$enableval" = "no" -+then -+ MAINTAINER_CMT=# -+ AC_MSG_RESULT([Disabling maintainer mode]) -+else -+ MAINTAINER_CMT= -+ AC_MSG_RESULT([Enabling maintainer mode]) -+fi -+, -+MAINTAINER_CMT=# -+AC_MSG_RESULT([Disabling maintainer mode by default]) -+) -+AC_SUBST(MAINTAINER_CMT) -+dnl -+dnl handle --enable-symlink-install -+dnl -+AC_ARG_ENABLE([symlink-install], -+[ --enable-symlink-install use symlinks when installing instead of hard links], -+if test "$enableval" = "no" -+then -+ LINK_INSTALL_FLAGS=-f -+ AC_MSG_RESULT([Disabling symlinks for install]) -+else -+ LINK_INSTALL_FLAGS=-sf -+ AC_MSG_RESULT([Enabling symlinks for install]) -+fi -+, -+LINK_INSTALL_FLAGS=-f -+AC_MSG_RESULT([Disabling symlinks for install by default]) -+) -+AC_SUBST(LINK_INSTALL_FLAGS) -+dnl -+dnl handle --enable-relative-symlinks -+dnl -+relative_symlink_defined= -+AC_ARG_ENABLE([relative-symlinks], -+[ --enable-relative-symlinks use relative symlinks when installing], -+if test "$enableval" = "no" -+then -+ SYMLINK_RELATIVE= -+ relative_symlink_defined=yes -+ AC_MSG_RESULT([Disabling relative symlinks for install]) -+else -+ SYMLINK_RELATIVE=--relative -+ relative_symlink_defined=yes -+ AC_MSG_RESULT([Enabling relative symlinks for install]) -+fi) -+AC_ARG_ENABLE([symlink-relative-symlinks],, -+if test "$enableval" = "no" -+then -+ SYMLINK_RELATIVE=yes -+ AC_MSG_RESULT([Disabling relative symlinks for install]) -+else -+ SYMLINK_RELATIVE=--relative -+ AC_MSG_RESULT([Enabling relative symlinks for install]) -+fi -+, -+if test -z "$relative_symlink_defined" -+then -+ SYMLINK_RELATIVE= -+AC_MSG_RESULT([Disabling relative symlinks for install by default]) -+fi -+) -+AC_SUBST(SYMLINK_RELATIVE) -+dnl -+dnl handle --enable-symlink-build -+dnl -+AC_ARG_ENABLE([symlink-build], -+[ --enable-symlink-build use symlinks while building instead of hard links], -+if test "$enableval" = "no" -+then -+ LINK_BUILD_FLAGS= -+ AC_MSG_RESULT([Disabling symlinks for build]) -+else -+ LINK_BUILD_FLAGS=-s -+ AC_MSG_RESULT([Enabling symlinks for build]) -+fi -+, -+LINK_BUILD_FLAGS= -+AC_MSG_RESULT([Disabling symlinks for build by default]) -+) -+AC_SUBST(LINK_BUILD_FLAGS) -+dnl -+dnl handle --enable-verbose-makecmds -+dnl -+AC_ARG_ENABLE([verbose-makecmds], -+[ --enable-verbose-makecmds enable verbose make command output], -+if test "$enableval" = "no" -+then -+ AC_MSG_RESULT([Disabling verbose make commands]) -+ E=@echo -+ ES=echo -+ Q=@ -+else -+ AC_MSG_RESULT([Enabling verbose make commands]) -+ E=@\\# -+ ES=\\# -+ Q= -+fi -+, -+AC_MSG_RESULT([Disabling verbose make commands]) -+E=@echo -+ES=echo -+Q=@ -+) -+AC_SUBST(E) -+AC_SUBST(ES) -+AC_SUBST(Q) -+dnl -+dnl This needs to be before all of the --enable-*-shlibs options -+dnl -+E2_PKG_CONFIG_STATIC=--static -+LDFLAG_DYNAMIC= -+PRIVATE_LIBS_CMT= -+dnl -+dnl handle --enable-elf-shlibs -+dnl -+AC_ARG_ENABLE([elf-shlibs], -+[ --enable-elf-shlibs select ELF shared libraries], -+if test "$enableval" = "no" -+then -+ ELF_CMT=# -+ MAKEFILE_ELF=/dev/null -+ AC_MSG_RESULT([Disabling ELF shared libraries]) -+else -+ E2_PKG_CONFIG_STATIC= -+ ELF_CMT= -+ MAKEFILE_ELF=$srcdir/lib/Makefile.elf-lib -+ [case "$host_os" in -+ solaris2.*) -+ MAKEFILE_ELF=$srcdir/lib/Makefile.solaris-lib -+ ;; -+ esac] -+ BINARY_TYPE=elfbin -+ LIB_EXT=.so -+ PRIVATE_LIBS_CMT=# -+ LDFLAG_DYNAMIC=['-Wl,-rpath-link,$(top_builddir)/lib'] -+ AC_MSG_RESULT([Enabling ELF shared libraries]) -+fi -+, -+MAKEFILE_ELF=/dev/null -+ELF_CMT=# -+AC_MSG_RESULT([Disabling ELF shared libraries by default]) -+) -+AC_SUBST(ELF_CMT) -+AC_SUBST_FILE(MAKEFILE_ELF) -+dnl -+dnl handle --enable-bsd-shlibs -+dnl -+AC_ARG_ENABLE([bsd-shlibs], -+[ --enable-bsd-shlibs select BSD shared libraries], -+if test "$enableval" = "no" -+then -+ BSDLIB_CMT=# -+ MAKEFILE_BSDLIB=/dev/null -+ AC_MSG_RESULT([Disabling BSD shared libraries]) -+else -+ E2_PKG_CONFIG_STATIC= -+ BSDLIB_CMT= -+ MAKEFILE_BSDLIB=$srcdir/lib/Makefile.bsd-lib -+ LIB_EXT=.so -+ [case "$host_os" in -+ darwin*) -+ MAKEFILE_BSDLIB=$srcdir/lib/Makefile.darwin-lib -+ LIB_EXT=.dylib -+ ;; -+ esac] -+ AC_MSG_RESULT([Enabling BSD shared libraries]) -+fi -+, -+MAKEFILE_BSDLIB=/dev/null -+BSDLIB_CMT=# -+AC_MSG_RESULT([Disabling BSD shared libraries by default]) -+) -+AC_SUBST(BSDLIB_CMT) -+AC_SUBST_FILE(MAKEFILE_BSDLIB) -+dnl -+dnl handle --enable-profile -+dnl -+AC_ARG_ENABLE([profile], -+[ --enable-profile build profiling libraries], -+if test "$enableval" = "no" -+then -+ PROFILE_CMT=# -+ MAKEFILE_PROFILE=/dev/null -+ AC_MSG_RESULT([Disabling profiling libraries]) -+else -+ PROFILE_CMT= -+ MAKEFILE_PROFILE=$srcdir/lib/Makefile.profile -+ PROFILED_LIB_EXT=_p.a -+ AC_MSG_RESULT([Building profiling libraries]) -+fi -+, -+PROFILE_CMT=# -+MAKEFILE_PROFILE=/dev/null -+AC_MSG_RESULT([Disabling profiling libraries by default]) -+) -+AC_SUBST(PROFILE_CMT) -+AC_SUBST_FILE(MAKEFILE_PROFILE) -+dnl -+dnl handle --enable-gcov -+dnl -+AC_ARG_ENABLE([gcov], -+[ --enable-gcov build for coverage testing using gcov], -+if test "$enableval" = "yes" -+then -+ CFLAGS="-g -fprofile-arcs -ftest-coverage" -+ LDFLAGS="-fprofile-arcs -ftest-coverage" -+ AC_MSG_RESULT([Enabling gcov support]) -+fi -+) -+ -+dnl -+dnl Substitute library extensions -+dnl -+AC_SUBST(LIB_EXT) -+AC_SUBST(STATIC_LIB_EXT) -+AC_SUBST(PROFILED_LIB_EXT) -+AC_SUBST(LDFLAG_DYNAMIC) -+AC_SUBST(PRIVATE_LIBS_CMT) -+dnl -+dnl handle --enable-jbd-debug -+dnl -+AC_ARG_ENABLE([jbd-debug], -+[ --enable-jbd-debug enable journal debugging], -+if test "$enableval" = "no" -+then -+ AC_MSG_RESULT([Disabling journal debugging]) -+else -+ AC_DEFINE(CONFIG_JBD_DEBUG, 1, -+ [Define to 1 if debugging ext3/4 journal code]) -+ AC_MSG_RESULT([Enabling journal debugging]) -+fi -+, -+AC_MSG_RESULT([Disabling journal debugging by default]) -+) -+dnl -+dnl handle --enable-blkid-debug -+dnl -+AC_ARG_ENABLE([blkid-debug], -+[ --enable-blkid-debug enable blkid debugging], -+if test "$enableval" = "no" -+then -+ AC_MSG_RESULT([Disabling blkid debugging]) -+else -+ AC_DEFINE(CONFIG_BLKID_DEBUG, 1, -+ [Define to 1 if debugging the blkid library]) -+ AC_MSG_RESULT([Enabling blkid debugging]) -+fi -+, -+AC_MSG_RESULT([Disabling blkid debugging by default]) -+) -+dnl -+dnl handle --enable-testio-debug -+dnl -+AC_ARG_ENABLE([testio-debug], -+[ --disable-testio-debug disable the use of the test I/O manager for debugging], -+AH_TEMPLATE([CONFIG_TESTIO_DEBUG], -+ [Define to 1 if the testio I/O manager should be enabled]) -+if test "$enableval" = "no" -+then -+ AC_MSG_RESULT([Disabling testio debugging]) -+ TEST_IO_CMT="#" -+else -+ TEST_IO_CMT= -+ AC_DEFINE(CONFIG_TESTIO_DEBUG, 1) -+ AC_MSG_RESULT([Enabling testio debugging]) -+fi -+, -+AC_MSG_RESULT([Enabling testio debugging by default]) -+AC_DEFINE(CONFIG_TESTIO_DEBUG, 1) -+TEST_IO_CMT= -+) -+AC_SUBST(TEST_IO_CMT) -+dnl -+dnl handle --disable-libuuid -+dnl -+PKG_PROG_PKG_CONFIG -+LIBUUID= -+DEPLIBUUID= -+STATIC_LIBUUID= -+DEPSTATIC_LIBUUID= -+PROFILED_LIBUUID= -+DEPPROFILED_LIBUUID= -+UUID_CMT= -+AC_ARG_ENABLE([libuuid], -+[ --enable-libuuid build and use private uuid library], -+if test "$enableval" = "no" -+then -+ if test -z "$PKG_CONFIG"; then -+ AC_MSG_ERROR([pkg-config not installed; please install it.]) -+ fi -+ -+ AC_CHECK_LIB(uuid, uuid_generate, -+ [LIBUUID=`$PKG_CONFIG --libs uuid`; -+ STATIC_LIBUUID=`$PKG_CONFIG --static --libs uuid`], -+ [AC_MSG_ERROR([external uuid library not found])]) -+ PROFILED_LIBUUID=$LIBUUID -+ UUID_CMT=# -+ AC_MSG_RESULT([Disabling private uuid library]) -+else -+ LIBUUID='$(LIB)/libuuid'$LIB_EXT -+ DEPLIBUUID=$LIBUUID -+ STATIC_LIBUUID='$(LIB)/libuuid'$STATIC_LIB_EXT -+ DEPSTATIC_LIBUUID=$STATIC_LIBUUID -+ PROFILED_LIBUUID='$(LIB)/libuuid'$PROFILED_LIB_EXT -+ DEPPROFILED_LIBUUID=$PROFILED_LIBUUID -+ AC_MSG_RESULT([Enabling private uuid library]) -+fi -+, -+if test -n "$PKG_CONFIG"; then -+ AC_CHECK_LIB(uuid, uuid_generate, -+ [LIBUUID=`$PKG_CONFIG --libs uuid`; -+ STATIC_LIBUUID=`$PKG_CONFIG --static --libs uuid`]) -+fi -+if test -n "$LIBUUID"; then -+ PROFILED_LIBUUID=$LIBUUID -+ UUID_CMT=# -+ AC_MSG_RESULT([Using system uuid by default]) -+else -+ LIBUUID='$(LIB)/libuuid'$LIB_EXT -+ DEPLIBUUID=$LIBUUID -+ STATIC_LIBUUID='$(LIB)/libuuid'$STATIC_LIB_EXT -+ DEPSTATIC_LIBUUID=$STATIC_LIBUUID -+ PROFILED_LIBUUID='$(LIB)/libuuid'$PROFILED_LIB_EXT -+ DEPPROFILED_LIBUUID=$PROFILED_LIBUUID -+ AC_MSG_RESULT([Enabling private uuid library by default]) -+fi -+) -+AC_SUBST(LIBUUID) -+AC_SUBST(DEPLIBUUID) -+AC_SUBST(STATIC_LIBUUID) -+AC_SUBST(DEPSTATIC_LIBUUID) -+AC_SUBST(PROFILED_LIBUUID) -+AC_SUBST(DEPPROFILED_LIBUUID) -+AC_SUBST(UUID_CMT) -+dnl -+dnl handle --disable-libblkid -+dnl -+PKG_PROG_PKG_CONFIG -+LIBBLKID= -+DEPLIBBLKID= -+STATIC_LIBBLKID= -+DEPSTATIC_LIBBLKID= -+PROFILED_LIBBLKID= -+DEPPROFILED_LIBBLKID= -+BLKID_CMT= -+AH_TEMPLATE([CONFIG_BUILD_FINDFS], [Define to 1 to compile findfs]) -+AC_ARG_ENABLE([libblkid], -+[ --enable-libblkid build and use private blkid library], -+if test "$enableval" = "no" -+then -+ if test -z "$PKG_CONFIG"; then -+ AC_MSG_ERROR([pkg-config not installed; please install it.]) -+ fi -+ -+ AC_CHECK_LIB(blkid, blkid_get_cache, -+ [LIBBLKID=`$PKG_CONFIG --libs blkid`; -+ STATIC_LIBBLKID=`$PKG_CONFIG --static --libs blkid`], -+ [AC_MSG_ERROR([external blkid library not found])], -luuid) -+ BLKID_CMT=# -+ PROFILED_LIBBLKID=$LIBBLKID -+ AC_MSG_RESULT([Disabling private blkid library]) -+else -+ LIBBLKID='$(LIB)/libblkid'$LIB_EXT -+ DEPLIBBLKID=$LIBBLKID -+ STATIC_LIBBLKID='$(LIB)/libblkid'$STATIC_LIB_EXT -+ DEPSTATIC_LIBBLKID=$STATIC_LIBBLKID -+ PROFILED_LIBBLKID='$(LIB)/libblkid'$PROFILED_LIB_EXT -+ DEPPROFILED_LIBBLKID=$PROFILED_LIBBLKID -+ AC_DEFINE(CONFIG_BUILD_FINDFS, 1) -+ AC_MSG_RESULT([Enabling private blkid library]) -+fi -+, -+if test -n "$PKG_CONFIG"; then -+ AC_CHECK_LIB(blkid, blkid_get_cache, -+ [LIBBLKID=`$PKG_CONFIG --libs blkid`; -+ STATIC_LIBBLKID=`$PKG_CONFIG --static --libs blkid`]) -+fi -+if test -n "$LIBBLKID"; then -+ BLKID_CMT=# -+ PROFILED_LIBBLKID=$LIBBLKID -+ AC_MSG_RESULT([Using system blkid library by default]) -+else -+ LIBBLKID='$(LIB)/libblkid'$LIB_EXT -+ DEPLIBBLKID=$LIBBLKID -+ STATIC_LIBBLKID='$(LIB)/libblkid'$STATIC_LIB_EXT -+ DEPSTATIC_LIBBLKID=$STATIC_LIBBLKID -+ PROFILED_LIBBLKID='$(LIB)/libblkid'$PROFILED_LIB_EXT -+ DEPPROFILED_LIBBLKID=$PROFILED_LIBBLKID -+ AC_DEFINE(CONFIG_BUILD_FINDFS, 1) -+ AC_MSG_RESULT([Enabling private blkid library by default]) -+fi -+) -+AC_SUBST(LIBBLKID) -+AC_SUBST(DEPLIBBLKID) -+AC_SUBST(STATIC_LIBBLKID) -+AC_SUBST(DEPSTATIC_LIBBLKID) -+AC_SUBST(PROFILED_LIBBLKID) -+AC_SUBST(DEPPROFILED_LIBBLKID) -+AC_SUBST(BLKID_CMT) -+dnl -+dnl handle --disable-backtrace -+dnl -+AH_TEMPLATE([DISABLE_BACKTRACE], [Define to 1 to disable use of backtrace]) -+AC_ARG_ENABLE([backtrace], -+[ --disable-backtrace disable use backtrace], -+if test "$enableval" = "no" -+then -+ AC_MSG_RESULT([Disabling use of backtrace]) -+ AC_DEFINE(DISABLE_BACKTRACE, 1) -+else -+ AC_MSG_RESULT([Enabling use of backtrace]) -+fi -+, -+AC_MSG_RESULT([Enabling use of backtrace by default]) -+) -+dnl -+dnl handle --enable-debugfs -+dnl -+AC_ARG_ENABLE([debugfs], -+[ --disable-debugfs disable support of debugfs program], -+if test "$enableval" = "no" -+then -+ AC_MSG_RESULT([Disabling debugfs support]) -+ DEBUGFS_CMT="#" -+else -+ DEBUGFS_CMT= -+ AC_MSG_RESULT([Enabling debugfs support]) -+fi -+, -+AC_MSG_RESULT([Enabling debugfs support by default]) -+DEBUGFS_CMT= -+) -+AC_SUBST(DEBUGFS_CMT) -+dnl -+dnl handle --enable-imager -+dnl -+AC_ARG_ENABLE([imager], -+[ --disable-imager disable support of e2image program], -+if test "$enableval" = "no" -+then -+ AC_MSG_RESULT([Disabling e2image support]) -+ IMAGER_CMT="#" -+else -+ IMAGER_CMT= -+ AC_MSG_RESULT([Enabling e2image support]) -+fi -+, -+AC_MSG_RESULT([Enabling e2image support by default]) -+IMAGER_CMT= -+) -+AC_SUBST(IMAGER_CMT) -+dnl -+dnl handle --enable-resizer -+dnl -+AC_ARG_ENABLE([resizer], -+[ --disable-resizer disable support of e2resize program], -+if test "$enableval" = "no" -+then -+ AC_MSG_RESULT([Disabling e2resize support]) -+ RESIZER_CMT="#" -+else -+ RESIZER_CMT= -+ AC_MSG_RESULT([Enabling e2resize support]) -+fi -+, -+AC_MSG_RESULT([Enabling e2resize support by default]) -+RESIZER_CMT= -+) -+AC_SUBST(RESIZER_CMT) -+dnl -+dnl handle --enable-defrag -+dnl -+AC_ARG_ENABLE([defrag], -+[ --disable-defrag disable support of e4defrag program], -+if test "$enableval" = "no" -+then -+ AC_MSG_RESULT([Disabling e4defrag support]) -+ DEFRAG_CMT="#" -+else -+ DEFRAG_CMT= -+ AC_MSG_RESULT([Enabling e4defrag support]) -+fi -+, -+if test -z "$WITH_DIET_LIBC" -+then -+ AC_MSG_RESULT([Enabling e4defrag support by default]) -+ DEFRAG_CMT= -+else -+ AC_MSG_RESULT([Disabling e4defrag support by default]) -+ DEFRAG_CMT="#" -+fi -+) -+AC_SUBST(DEFRAG_CMT) -+dnl -+dnl See whether to install the `fsck' wrapper program (that calls e2fsck) -+dnl -+AC_ARG_ENABLE([fsck], -+[ --enable-fsck build fsck wrapper program], -+[if test "$enableval" = "no" -+then -+ FSCK_PROG='' FSCK_MAN='' -+ AC_MSG_RESULT([Not building fsck wrapper]) -+else -+ FSCK_PROG=fsck FSCK_MAN=fsck.8 -+ AC_MSG_RESULT([Building fsck wrapper]) -+fi] -+, -+[case "$host_os" in -+ gnu*) -+ FSCK_PROG='' FSCK_MAN='' -+ AC_MSG_RESULT([Not building fsck wrapper by default]) -+ ;; -+ *) -+ FSCK_PROG=fsck FSCK_MAN=fsck.8 -+ AC_MSG_RESULT([Building fsck wrapper by default]) -+esac] -+) -+AC_SUBST(FSCK_PROG) -+AC_SUBST(FSCK_MAN) -+dnl -+dnl See whether to install the `e2initrd-helper' program -+dnl -+AC_ARG_ENABLE([e2initrd-helper], -+[ --enable-e2initrd-helper build e2initrd-helper program], -+[if test "$enableval" = "no" -+then -+ E2INITRD_PROG='' E2INITRD_MAN='' -+ AC_MSG_RESULT([Not building e2initrd helper]) -+else -+ E2INITRD_PROG=e2initrd_helper E2INITRD_MAN=e2initrd_helper.8 -+ AC_MSG_RESULT([Building e2initrd helper]) -+fi] -+, -+E2INITRD_PROG=e2initrd_helper E2INITRD_MAN=e2initrd_helper.8 -+AC_MSG_RESULT([Building e2initrd helper by default]) -+) -+AC_SUBST(E2INITRD_PROG) -+AC_SUBST(E2INITRD_MAN) -+dnl -+dnl -+dnl -+AC_ARG_ENABLE([tls], -+[ --disable-tls disable use of thread local support], -+[if test "$enableval" = "no" -+then -+ try_tls="" -+ AC_MSG_RESULT([Disabling thread local support]) -+else -+ try_tls="yes" -+ AC_MSG_RESULT([Enabling thread local support]) -+fi] -+, -+if test -n "$WITH_DIET_LIBC" -+then -+ try_tls="" -+ AC_MSG_RESULT([Diet libc does not support thread local support]) -+else -+ try_tls="yes" -+ AC_MSG_RESULT([Try using thread local support by default]) -+fi -+) -+if test "$try_tls" = "yes" -+then -+AX_TLS -+fi -+dnl -+dnl -+dnl -+AH_TEMPLATE([USE_UUIDD], [Define to 1 to build uuidd]) -+AC_ARG_ENABLE([uuidd], -+[ --disable-uuidd disable building the uuid daemon], -+[if test "$enableval" = "no" -+then -+ AC_MSG_RESULT([Not building uuidd]) -+ UUIDD_CMT="#" -+else -+ AC_DEFINE(USE_UUIDD, 1) -+ UUIDD_CMT="" -+ AC_MSG_RESULT([Building uuidd]) -+fi] -+, -+AC_DEFINE(USE_UUIDD, 1) -+if test -z "$UUID_CMT" -+then -+ UUIDD_CMT="" -+ AC_MSG_RESULT([Building uuidd by default]) -+else -+ UUIDD_CMT="#" -+ AC_MSG_RESULT([Disabling uuidd by default]) -+fi -+) -+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 -+AC_SUBST_FILE(MAKEFILE_LIBRARY) -+dnl -+dnl Add internationalization support, using gettext. -+dnl -+GETTEXT_PACKAGE=e2fsprogs -+PACKAGE=e2fsprogs -+VERSION="$E2FSPROGS_VERSION" -+VERSION=0.14.1 -+AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [package name for gettext]) -+AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [version for gettext]) -+AC_SUBST(GETTEXT_PACKAGE) -+AC_SUBST(PACKAGE) -+AC_SUBST(VERSION) -+ -+AM_GNU_GETTEXT -+dnl -+dnl End of configuration options -+dnl -+AC_SUBST(BINARY_TYPE) -+AC_PROG_MAKE_SET -+CHECK_GNU_MAKE -+AC_PATH_PROG(LN, ln, ln) -+AC_PROG_LN_S -+AC_PATH_PROG(MV, mv, mv) -+AC_PATH_PROG(CP, cp, cp) -+AC_PATH_PROG(RM, rm, rm) -+AC_PATH_PROG(CHMOD, chmod, :) -+AC_PROG_AWK -+AC_PROG_EGREP -+AC_PATH_PROG(SED, sed, sed) -+AC_PATH_PROG(PERL, perl, perl) -+AC_PATH_PROG(LDCONFIG, ldconfig, :) -+AC_CHECK_TOOL(AR, ar, ar) -+AC_CHECK_TOOL(RANLIB, ranlib, :) -+AC_CHECK_TOOL(STRIP, strip, :) -+AC_CHECK_PROG(MAKEINFO, makeinfo, makeinfo, ) -+if test "_$MAKEINFO" = "_"; then -+ MAKEINFO="@echo Makeinfo is missing. Info documentation will not be built.;true" -+else -+ case "$MAKEINFO" in -+ */missing.*) -+ AC_MSG_WARN([ -+*** Makeinfo is missing. Info documentation will not be built.]) -+ ;; -+ *) -+ ;; -+ esac -+fi -+AC_SUBST(MAKEINFO) -+AC_PROG_INSTALL -+# See if we need a separate native compiler. -+if test $cross_compiling = no; then -+ BUILD_CC="$CC" -+ AC_SUBST(BUILD_CC) -+else -+ AC_CHECK_PROGS(BUILD_CC, gcc cc) -+fi -+AC_CHECK_HEADERS(m4_flatten([ -+ 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/acl.h -+ sys/disklabel.h -+ sys/disk.h -+ sys/file.h -+ sys/ioctl.h -+ sys/key.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/sysctl.h -+ sys/sysmacros.h -+ sys/time.h -+ sys/types.h -+ sys/un.h -+ sys/wait.h -+])) -+AC_CHECK_HEADERS(net/if.h,,, -+[[ -+#if HAVE_SYS_TYPES_H -+#include -+#endif -+#if HAVE_SYS_SOCKET -+#include -+#endif -+]]) -+AC_FUNC_VPRINTF -+dnl Check to see if dirent has member d_reclen. On cygwin those d_reclen -+dnl is not decleared. -+AC_CHECK_MEMBER(struct dirent.d_reclen,[AC_DEFINE(HAVE_RECLEN_DIRENT, 1, -+ [Define to 1 if dirent has d_reclen])],, -+ [#include ]) -+AC_CHECK_MEMBERS([struct stat.st_atim]) -+dnl Check to see if ssize_t was declared -+AC_CHECK_TYPE(ssize_t,[AC_DEFINE(HAVE_TYPE_SSIZE_T, 1, -+ [Define to 1 if ssize_t declared])],, -+ [#include ]) -+dnl -+dnl Check to see if llseek() is declared in unistd.h. On some libc's -+dnl it is, and on others it isn't..... Thank you glibc developers.... -+dnl -+AC_CHECK_DECL(llseek,[AC_DEFINE(HAVE_LLSEEK_PROTOTYPE, 1, -+ [Define to 1 if llseek declared in unistd.h])],, -+ [#include ]) -+dnl -+dnl Check to see if lseek64() is declared in unistd.h. Glibc's header files -+dnl are so convoluted that I can't tell whether it will always be defined, -+dnl and if it isn't defined while lseek64 is defined in the library, -+dnl disaster will strike. -+dnl -+dnl Warning! Use of --enable-gcc-wall may throw off this test. -+dnl -+dnl -+AC_CHECK_DECL(lseek64,[AC_DEFINE(HAVE_LSEEK64_PROTOTYPE, 1, -+ [Define to 1 if lseek64 declared in unistd.h])],, -+ [#define _LARGEFILE_SOURCE -+ #define _LARGEFILE64_SOURCE -+ #include ]) -+dnl -+dnl Word sizes... -+dnl -+AC_CHECK_SIZEOF(short) -+AC_CHECK_SIZEOF(int) -+AC_CHECK_SIZEOF(long) -+AC_CHECK_SIZEOF(long long) -+AC_CHECK_SIZEOF(off_t) -+SIZEOF_SHORT=$ac_cv_sizeof_short -+SIZEOF_INT=$ac_cv_sizeof_int -+SIZEOF_LONG=$ac_cv_sizeof_long -+SIZEOF_LONG_LONG=$ac_cv_sizeof_long_long -+SIZEOF_OFF_T=$ac_cv_sizeof_off_t -+AC_SUBST(SIZEOF_SHORT) -+AC_SUBST(SIZEOF_INT) -+AC_SUBST(SIZEOF_LONG) -+AC_SUBST(SIZEOF_LONG_LONG) -+AC_SUBST(SIZEOF_OFF_T) -+AC_C_BIGENDIAN -+if test $cross_compiling = no; then -+ BUILD_CC="$BUILD_CC" CPP="$CPP" /bin/sh $ac_aux_dir/parse-types.sh -+else -+ CROSS_COMPILE="1" BUILD_CC="$BUILD_CC" CPP="$CPP" /bin/sh $ac_aux_dir/parse-types.sh -+fi -+ASM_TYPES_HEADER=./asm_types.h -+AC_SUBST_FILE(ASM_TYPES_HEADER) -+dnl -+dnl Save the configuration #defines needed for the public ext2fs.h -+dnl header file -+dnl -+echo "/* These defines are needed for the public ext2fs.h header file */" \ -+ > public_config.h -+if grep HAVE_SYS_TYPES_H confdefs.h > tmp_config.$$; then -+ uniq tmp_config.$$ >> public_config.h -+else -+ echo "#undef HAVE_SYS_TYPES_H" >> public_config.h -+fi -+if grep WORDS_BIGENDIAN confdefs.h > tmp_config.$$; then -+ uniq tmp_config.$$ >> public_config.h -+else -+ echo "#undef WORDS_BIGENDIAN" >> public_config.h -+fi -+rm -f tmp_config.$$ -+PUBLIC_CONFIG_HEADER=./public_config.h -+AC_SUBST_FILE(PUBLIC_CONFIG_HEADER) -+dnl -+dnl See if we have inttypes.h and if intptr_t is defined -+dnl -+AC_CHECK_HEADERS([inttypes.h]) -+AC_CHECK_TYPES(intptr_t) -+dnl -+dnl See if struct stat has a st_flags field, in which case we can get file -+dnl flags somewhat portably. Also check for the analogous setter, chflags(). -+dnl -+AC_MSG_CHECKING(whether struct stat has a st_flags field) -+AC_CACHE_VAL(e2fsprogs_cv_struct_st_flags, -+ AC_TRY_COMPILE([#include ], -+ [struct stat stat; stat.st_flags = 0;], -+ [e2fsprogs_cv_struct_st_flags=yes], -+ [e2fsprogs_cv_struct_st_flags=no])) -+AC_MSG_RESULT($e2fsprogs_cv_struct_st_flags) -+if test "$e2fsprogs_cv_struct_st_flags" = yes; then -+ AC_MSG_CHECKING(whether st_flags field is useful) -+ AC_CACHE_VAL(e2fsprogs_cv_struct_st_flags_immut, -+ AC_TRY_COMPILE([#include ], -+ [struct stat stat; stat.st_flags |= UF_IMMUTABLE;], -+ [e2fsprogs_cv_struct_st_flags_immut=yes], -+ [e2fsprogs_cv_struct_st_flags_immut=no])) -+ AC_MSG_RESULT($e2fsprogs_cv_struct_st_flags_immut) -+ if test "$e2fsprogs_cv_struct_st_flags_immut" = yes; then -+ AC_DEFINE(HAVE_STAT_FLAGS, 1, -+ [Define to 1 if struct stat has st_flags]) -+ fi -+fi -+dnl -+dnl Check for the presence of SA_LEN -+dnl -+AC_CHECK_MEMBER(struct sockaddr.sa_len, -+ AC_DEFINE_UNQUOTED(HAVE_SA_LEN,1, -+ [Define to 1 if if struct sockaddr contains sa_len]),, -+ [#include -+ #include ]) -+dnl -+dnl This will add -lblkid to the AC_CHECK_FUNCS search if we are using -+dnl the system-provided blkid library -+dnl -+if test -n "$BLKID_CMT"; then -+ AC_SEARCH_LIBS([blkid_probe_all], [blkid]) -+fi -+dnl -+AC_CHECK_FUNCS(m4_flatten([ -+ __secure_getenv -+ add_key -+ 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 -+ keyctl -+ 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 -+ utimes -+ valloc -+])) -+dnl -+dnl Check to see if -lsocket is required (solaris) to make something -+dnl that uses socket() to compile; this is needed for the UUID library -+dnl -+SOCKET_LIB='' -+AC_CHECK_LIB(socket, socket, [SOCKET_LIB=-lsocket]) -+AC_SUBST(SOCKET_LIB) -+dnl -+dnl See if libmagic exists -+dnl -+AC_CHECK_LIB(magic, magic_file, [MAGIC_LIB=-lmagic -+AC_CHECK_HEADERS([magic.h])]) -+if test "$ac_cv_lib_dl_dlopen" = yes ; then -+ MAGIC_LIB=$DLOPEN_LIB -+fi -+AC_SUBST(MAGIC_LIB) -+dnl -+dnl Check to see if the FUSE library is -lfuse or -losxfuse -+dnl -+FUSE_CMT= -+FUSE_LIB= -+dnl osxfuse.dylib supersedes fuselib.dylib -+AC_ARG_ENABLE([fuse2fs], -+[ --disable-fuse2fs do not build fuse2fs], -+if test "$enableval" = "no" -+then -+ FUSE_CMT="#" -+ AC_MSG_RESULT([Disabling fuse2fs]) -+else -+ AC_CHECK_HEADERS([pthread.h fuse.h], [], -+[AC_MSG_FAILURE([Cannot find fuse2fs headers.])], -+[#define _FILE_OFFSET_BITS 64 -+#define FUSE_USE_VERSION 29]) -+ -+ AC_PREPROC_IFELSE( -+[AC_LANG_PROGRAM([[#define FUSE_USE_VERSION 29 -+#ifdef __linux__ -+#include -+#include -+#include -+#endif -+]], [])], [], [AC_MSG_FAILURE([Cannot find fuse2fs Linux headers.])]) -+ -+ AC_CHECK_LIB(osxfuse, fuse_main, [FUSE_LIB=-losxfuse], -+ [AC_CHECK_LIB(fuse, fuse_main, [FUSE_LIB=-lfuse], -+ [AC_MSG_FAILURE([Cannot find fuse library.])])]) -+ AC_MSG_RESULT([Enabling fuse2fs]) -+fi -+, -+AC_CHECK_HEADERS([pthread.h fuse.h], [], [FUSE_CMT="#"], -+[#define _FILE_OFFSET_BITS 64 -+#define FUSE_USE_VERSION 29 -+#ifdef __linux__ -+# include -+# include -+# include -+#endif]) -+if test -z "$FUSE_CMT" -+then -+ AC_CHECK_LIB(osxfuse, fuse_main, [FUSE_LIB=-losxfuse], -+[AC_CHECK_LIB(fuse, fuse_main, [FUSE_LIB=-lfuse], [FUSE_CMT="#"])]) -+fi -+if test -z "$FUSE_CMT" -+then -+ AC_MSG_RESULT([Enabling fuse2fs by default.]) -+fi -+) -+AC_SUBST(FUSE_LIB) -+AC_SUBST(FUSE_CMT) -+dnl -+dnl See if optreset exists -+dnl -+AC_MSG_CHECKING(for optreset) -+AC_CACHE_VAL(ac_cv_have_optreset, -+[AC_EGREP_HEADER(optreset, unistd.h, -+ ac_cv_have_optreset=yes, ac_cv_have_optreset=no)])dnl -+AC_MSG_RESULT($ac_cv_have_optreset) -+if test $ac_cv_have_optreset = yes; then -+ AC_DEFINE(HAVE_OPTRESET, 1, [Define to 1 if optreset for getopt is present]) -+fi -+dnl -+dnl Test for sem_init, and which library it might require: -+dnl -+AH_TEMPLATE([HAVE_SEM_INIT], [Define to 1 if sem_init() exists]) -+SEM_INIT_LIB='' -+AC_CHECK_FUNC(sem_init, , -+ AC_CHECK_LIB(pthread, sem_init, -+ AC_DEFINE(HAVE_SEM_INIT, 1) -+ SEM_INIT_LIB=-lpthread, -+ AC_CHECK_LIB(rt, sem_init, -+ AC_DEFINE(HAVE_SEM_INIT, 1) -+ SEM_INIT_LIB=-lrt, -+ AC_CHECK_LIB(posix4, sem_init, -+ AC_DEFINE(HAVE_SEM_INIT, 1) -+ SEM_INIT_LIB=-lposix4))))dnl -+AC_SUBST(SEM_INIT_LIB) -+dnl -+dnl Check for unified diff -+dnl -+AC_MSG_CHECKING(for unified diff option) -+if diff -u $0 $0 > /dev/null 2>&1 ; then -+ UNI_DIFF_OPTS=-u -+else -+ UNI_DIFF_OPTS=-c -+fi -+AC_MSG_RESULT($UNI_DIFF_OPTS) -+AC_SUBST(UNI_DIFF_OPTS) -+dnl -+dnl We use the EXT2 ioctls only under Linux -+dnl -+case "$host_os" in -+linux*) -+ AC_DEFINE(HAVE_EXT2_IOCTLS, 1, [Define to 1 if Ext2 ioctls present]) -+ ;; -+esac -+dnl -+dnl OS-specific uncomment control -+dnl -+LINUX_CMT="#" -+CYGWIN_CMT="#" -+UNIX_CMT= -+case "$host_os" in -+linux*) -+ LINUX_CMT= -+ ;; -+cygwin) -+ CYGWIN_CMT= -+ UNIX_CMT="#" -+ ;; -+esac -+AC_SUBST(LINUX_CMT) -+AC_SUBST(CYGWIN_CMT) -+AC_SUBST(UNIX_CMT) -+dnl -+dnl Linux and Hurd places root files in the / by default -+dnl -+case "$host_os" in -+linux* | gnu* | k*bsd*-gnu) -+ if test "$prefix" = NONE -a "$root_prefix" = NONE ; then -+ root_prefix=""; -+ AC_MSG_RESULT([On $host_os systems, root_prefix defaults to '']) -+ fi -+ ;; -+esac -+dnl -+dnl On Linux/hurd, force the prefix to be /usr -+dnl -+case "$host_os" in -+linux* | gnu* | k*bsd*-gnu) -+ if test "$prefix" = NONE ; then -+ prefix="/usr"; -+ AC_MSG_RESULT([On $host_os systems, prefix defaults to /usr]) -+ if test "$mandir" = '${prefix}/man' ; then -+ AC_MSG_RESULT([...and mandir defaults to /usr/share/man]) -+ mandir=/usr/share/man -+ fi -+ fi -+;; -+esac -+if test "$root_prefix" = NONE ; then -+ if test "$prefix" = NONE ; then -+ root_prefix="$ac_default_prefix" -+ else -+ root_prefix="$prefix" -+ fi -+ root_bindir=$bindir -+ root_sbindir=$sbindir -+ root_libdir=$libdir -+ root_sysconfdir=$sysconfdir -+else -+ root_bindir='${root_prefix}/bin' -+ root_sbindir='${root_prefix}/sbin' -+ root_libdir='${root_prefix}/lib' -+ root_sysconfdir='${root_prefix}/etc' -+fi -+if test "$bindir" != '${exec_prefix}/bin'; then -+ root_bindir=$bindir -+ AC_MSG_RESULT([Setting root_bindir to $root_bindir]) -+fi -+if test "$sbindir" != '${exec_prefix}/sbin'; then -+ root_sbindir=$sbindir -+ AC_MSG_RESULT([Setting root_sbindir to $root_sbindir]) -+fi -+if test "$libdir" != '${exec_prefix}/lib'; then -+ root_libdir=$libdir -+ AC_MSG_RESULT([Setting root_libdir to $root_libdir]) -+fi -+if test "$sysconfdir" != '${prefix}/etc'; then -+ root_sysconfdir=$sysconfdir -+ AC_MSG_RESULT([Setting root_sysconfdir to $root_sysconfdir]) -+fi -+AC_SUBST(root_prefix) -+AC_SUBST(root_bindir) -+AC_SUBST(root_sbindir) -+AC_SUBST(root_libdir) -+AC_SUBST(root_sysconfdir) -+dnl -+dnl Allow specification of the multiarch arch -+dnl -+AC_ARG_WITH([multiarch], -+[ --with-multiarch=ARCH specify the multiarch triplet], -+if test "$withval" = "lib64"; then -+ libdir=/usr/lib64 -+ root_libdir=/lib64 -+else -+ libdir=$libdir/$withval -+ root_libdir=$root_libdir/$withval -+fi -+)dnl -+dnl -+dnl See if -static works. This could fail if the linker does not -+dnl support -static, or if required external libraries are not available -+dnl in static form. -+dnl -+AC_MSG_CHECKING([whether we can link with -static]) -+AC_CACHE_VAL(ac_cv_e2fsprogs_use_static, -+[SAVE_LDFLAGS=$LDFLAGS; LDFLAGS="$LDFLAGS -static" -+AC_TRY_LINK([#include ],[fflush(stdout);], -+ ac_cv_e2fsprogs_use_static=yes, ac_cv_e2fsprogs_use_static=no) -+LDFLAGS=$SAVE_LDFLAGS]) -+dnl -+dnl Regardless of how the test turns out, Solaris doesn't handle -static -+dnl This is caused by the socket library requiring the nsl library, which -+dnl requires the -dl library, which only works for dynamically linked -+dnl programs. It basically means you can't have statically linked programs -+dnl which use the network under Solaris. -+dnl -+case "$host_os" in -+solaris2.*) -+ ac_cv_e2fsprogs_use_static=no -+;; -+esac -+AC_MSG_RESULT($ac_cv_e2fsprogs_use_static) -+LDFLAG_STATIC= -+if test $ac_cv_e2fsprogs_use_static = yes; then -+ LDFLAG_STATIC=-static -+fi -+AC_SUBST(LDFLAG_STATIC) -+dnl -+dnl Work around mysterious Darwin / GNU libintl problem -+dnl (__asm__ redirection doesn't work for some mysterious reason. Looks like -+dnl Apple hacked gcc somehow?) -+dnl -+case "$host_os" in -+darwin*) -+ AC_MSG_RESULT([Using Apple Darwin / GNU libintl workaround]) -+ AC_DEFINE(_INTL_REDIRECT_MACROS, 1, -+ [Define to 1 if Apple Darwin libintl workaround is needed]) -+ ;; -+esac -+dnl -+dnl Make the ss and et directories work correctly. -+dnl -+SS_DIR=`cd ${srcdir}/lib/ss; pwd` -+ET_DIR=`cd ${srcdir}/lib/et; pwd` -+AC_SUBST(SS_DIR) -+AC_SUBST(ET_DIR) -+dnl -+dnl Only try to run the test suite if we're not cross compiling. -+dnl -+if test "$cross_compiling" = yes ; then -+ DO_TEST_SUITE= -+else -+ DO_TEST_SUITE=check -+fi -+AC_SUBST(DO_TEST_SUITE) -+dnl -+dnl Only include the intl include files if we're building with them -+dnl -+INCLUDES='-I. -I$(top_builddir)/lib -I$(top_srcdir)/lib' -+if test -n "$CPPFLAGS" ; then -+ INCLUDES="$INCLUDES $CPPFLAGS" -+fi -+if test "$USE_INCLUDED_LIBINTL" = "yes" ; then -+ INCLUDES=$INCLUDES' -I$(top_builddir)/intl -I$(top_srcdir)/intl' -+fi -+if test -n "$WITH_DIET_LIBC" ; then -+ INCLUDES="$INCLUDES -D_REENTRANT" -+fi -+AC_SUBST(INCLUDES) -+AM_MKINSTALLDIRS -+dnl -+dnl Build CFLAGS -+dnl -+if test $cross_compiling = no; then -+ BUILD_CFLAGS="$CFLAGS $CPPFLAGS $INCLUDES -DHAVE_CONFIG_H" -+ BUILD_LDFLAGS="$LDFLAGS" -+fi -+AC_SUBST(BUILD_CFLAGS) -+AC_SUBST(BUILD_LDFLAGS) -+dnl -+dnl Make our output files, being sure that we create the some miscellaneous -+dnl directories -+dnl -+test -d lib || mkdir lib -+test -d include || mkdir include -+test -d include/linux || mkdir include/linux -+test -d include/asm || mkdir include/asm -+if test -z "$UUID_CMT" ; then -+ uuid_out_list="lib/uuid/Makefile lib/uuid/uuid.pc \ -+ lib/uuid/uuid_types.h" -+fi -+if test -z "$BLKID_CMT" ; then -+ blkid_out_list="lib/blkid/Makefile lib/blkid/blkid.pc \ -+ lib/blkid/blkid_types.h" -+fi -+for i in MCONFIG Makefile e2fsprogs.spec \ -+ util/Makefile util/subst.conf util/gen-tarball util/install-symlink \ -+ lib/et/Makefile lib/ss/Makefile lib/e2p/Makefile \ -+ lib/ext2fs/Makefile lib/ext2fs/ext2_types.h \ -+ $uuid_out_list $blkid_out_list lib/support/Makefile \ -+ lib/ss/ss.pc lib/et/com_err.pc lib/e2p/e2p.pc lib/ext2fs/ext2fs.pc \ -+ misc/Makefile ext2ed/Makefile e2fsck/Makefile \ -+ debugfs/Makefile tests/Makefile tests/progs/Makefile \ -+ resize/Makefile doc/Makefile intl/Makefile \ -+ intl/libgnuintl.h po/Makefile.in ; do -+ if test -d `dirname ${srcdir}/$i` ; then -+ outlist="$outlist $i" -+ fi -+done -+AC_OUTPUT($outlist) -+if test -f util/gen-tarball; then chmod +x util/gen-tarball; fi -diff --git a/configure.in b/configure.in -deleted file mode 100644 -index 0146bfe..0000000 ---- a/configure.in -+++ /dev/null -@@ -1,1346 +0,0 @@ --AC_INIT(version.h) --AC_PREREQ(2.54) --AC_CONFIG_AUX_DIR(config) --AC_CONFIG_HEADERS([lib/config.h]) --AH_BOTTOM([#include ]) --MCONFIG=./MCONFIG --AC_SUBST_FILE(MCONFIG) --BINARY_TYPE=bin --dnl --dnl This is to figure out the version number and the date.... --dnl --E2FSPROGS_VERSION=`grep E2FSPROGS_VERSION ${srcdir}/version.h \ -- | awk '{print $3}' | tr \" " " | awk '{print $1}'` --DATE=`grep E2FSPROGS_DATE ${srcdir}/version.h | awk '{print $3}' \ -- | tr \" " "` --E2FSPROGS_DAY=`echo $DATE | awk -F- '{print $1}'` --MONTH=`echo $DATE | awk -F- '{print $2}'` --YEAR=`echo $DATE | awk -F- '{print $3}'` -- --if expr $YEAR ">" 1900 > /dev/null ; then -- E2FSPROGS_YEAR=$YEAR --elif expr $YEAR ">" 90 >/dev/null ; then -- E2FSPROGS_YEAR=19$YEAR --else -- E2FSPROGS_YEAR=20$YEAR --fi -- --case $MONTH in --Jan) MONTH_NUM=01; E2FSPROGS_MONTH="January" ;; --Feb) MONTH_NUM=02; E2FSPROGS_MONTH="February" ;; --Mar) MONTH_NUM=03; E2FSPROGS_MONTH="March" ;; --Apr) MONTH_NUM=04; E2FSPROGS_MONTH="April" ;; --May) MONTH_NUM=05; E2FSPROGS_MONTH="May" ;; --Jun) MONTH_NUM=06; E2FSPROGS_MONTH="June" ;; --Jul) MONTH_NUM=07; E2FSPROGS_MONTH="July" ;; --Aug) MONTH_NUM=08; E2FSPROGS_MONTH="August" ;; --Sep) MONTH_NUM=09; E2FSPROGS_MONTH="September" ;; --Oct) MONTH_NUM=10; E2FSPROGS_MONTH="October" ;; --Nov) MONTH_NUM=11; E2FSPROGS_MONTH="November" ;; --Dec) MONTH_NUM=12; E2FSPROGS_MONTH="December" ;; --*) AC_MSG_WARN([Unknown month $MONTH??]) ;; --esac -- --base_ver=`echo $E2FSPROGS_VERSION | \ -- sed -e 's/-WIP//' -e 's/pre-//' -e 's/-PLUS//'` -- --date_spec=${E2FSPROGS_YEAR}.${MONTH_NUM}.${E2FSPROGS_DAY} -- --case $E2FSPROGS_VERSION in --*-WIP|pre-*) -- E2FSPROGS_PKGVER="$base_ver~WIP-$E2FSPROGS_YEAR-$MONTH_NUM-$E2FSPROGS_DAY" -- ;; --*) -- E2FSPROGS_PKGVER="$base_ver" -- ;; --esac -- --unset DATE MONTH YEAR base_ver pre_vers date_spec --AC_MSG_RESULT([Generating configuration file for e2fsprogs version $E2FSPROGS_VERSION]) --AC_MSG_RESULT([Release date is ${E2FSPROGS_MONTH}, ${E2FSPROGS_YEAR}]) --AC_SUBST(E2FSPROGS_YEAR) --AC_SUBST(E2FSPROGS_MONTH) --AC_SUBST(E2FSPROGS_DAY) --AC_SUBST(E2FSPROGS_VERSION) --AC_SUBST(E2FSPROGS_PKGVER) --dnl --dnl Use diet libc --dnl --WITH_DIET_LIBC= --AC_ARG_WITH([diet-libc], --[ --with-diet-libc use diet libc], --CC="diet cc -nostdinc" --WITH_DIET_LIBC=yes --if test -z "$LIBS" --then -- LIBS="-lcompat" --else -- LIBS="$LIBS -lcompat" --fi --AC_MSG_RESULT(CC=$CC))dnl --dnl --AC_CANONICAL_HOST --dnl --dnl Check to see if libdl exists for the sake of dlopen --dnl --DLOPEN_LIB='' --AC_CHECK_LIB(dl, dlopen, --[DLOPEN_LIB=-ldl --AC_DEFINE(HAVE_DLOPEN, 1, [Define to 1 if dlopen/libdl exists])]) --AC_SUBST(DLOPEN_LIB) --dnl --AC_ARG_WITH([cc], --AC_HELP_STRING([--with-cc],[no longer supported, use CC= instead]), --AC_MSG_ERROR([--with-cc no longer supported; use CC= instead])) --dnl --AC_ARG_WITH([ccopts], --AC_HELP_STRING([--with-ccopts],[no longer supported, use CFLAGS= instead]), --AC_MSG_ERROR([--with-ccopts no longer supported; use CFLAGS= instead])) --dnl --AC_ARG_WITH([ldopts], --AC_HELP_STRING([--with-ldopts],[no longer supported, use LDFLAGS= instead]), --AC_MSG_ERROR([--with-ldopts no longer supported; use LDFLAGS= instead])) --dnl --AC_PROG_CC --if test "$GCC" = yes; then -- RDYNAMIC="-rdynamic" -- AC_SUBST(RDYNAMIC) --fi --AC_PROG_CPP --dnl --dnl Alpha computers use fast and imprecise floating point code that may --dnl miss exceptions by default. Force sane options if we're using GCC. --AC_MSG_CHECKING(for additional special compiler flags) --if test "$GCC" = yes --then -- case "$host_cpu" in -- alpha) addcflags="-mieee" ;; -- esac --fi --if test "x$addcflags" != x --then -- AC_MSG_RESULT($addcflags) -- CFLAGS="$addcflags $CFLAGS" --else -- AC_MSG_RESULT([[(none)]]) --fi --AC_USE_SYSTEM_EXTENSIONS --dnl --dnl Set default values for library extentions. Will be dealt with after --dnl parsing configuration opions, which may modify these --dnl --LIB_EXT=.a --STATIC_LIB_EXT=.a --PROFILED_LIB_EXT=.a --dnl --dnl Allow separate `root_prefix' to be specified --dnl --AC_ARG_WITH([root-prefix], --[ --with-root-prefix=PREFIX override prefix variable for files to be placed in the root], --root_prefix=$withval, --root_prefix=NONE)dnl --dnl --dnl handle --enable-maintainer-mode --dnl --AC_ARG_ENABLE([maintainer-mode], --[ --enable-maintainer-mode enable makefile rules useful for maintainers], --if test "$enableval" = "no" --then -- MAINTAINER_CMT=# -- AC_MSG_RESULT([Disabling maintainer mode]) --else -- MAINTAINER_CMT= -- AC_MSG_RESULT([Enabling maintainer mode]) --fi --, --MAINTAINER_CMT=# --AC_MSG_RESULT([Disabling maintainer mode by default]) --) --AC_SUBST(MAINTAINER_CMT) --dnl --dnl handle --enable-symlink-install --dnl --AC_ARG_ENABLE([symlink-install], --[ --enable-symlink-install use symlinks when installing instead of hard links], --if test "$enableval" = "no" --then -- LINK_INSTALL_FLAGS=-f -- AC_MSG_RESULT([Disabling symlinks for install]) --else -- LINK_INSTALL_FLAGS=-sf -- AC_MSG_RESULT([Enabling symlinks for install]) --fi --, --LINK_INSTALL_FLAGS=-f --AC_MSG_RESULT([Disabling symlinks for install by default]) --) --AC_SUBST(LINK_INSTALL_FLAGS) --dnl --dnl handle --enable-relative-symlinks --dnl --relative_symlink_defined= --AC_ARG_ENABLE([relative-symlinks], --[ --enable-relative-symlinks use relative symlinks when installing], --if test "$enableval" = "no" --then -- SYMLINK_RELATIVE= -- relative_symlink_defined=yes -- AC_MSG_RESULT([Disabling relative symlinks for install]) --else -- SYMLINK_RELATIVE=--relative -- relative_symlink_defined=yes -- AC_MSG_RESULT([Enabling relative symlinks for install]) --fi) --AC_ARG_ENABLE([symlink-relative-symlinks],, --if test "$enableval" = "no" --then -- SYMLINK_RELATIVE=yes -- AC_MSG_RESULT([Disabling relative symlinks for install]) --else -- SYMLINK_RELATIVE=--relative -- AC_MSG_RESULT([Enabling relative symlinks for install]) --fi --, --if test -z "$relative_symlink_defined" --then -- SYMLINK_RELATIVE= --AC_MSG_RESULT([Disabling relative symlinks for install by default]) --fi --) --AC_SUBST(SYMLINK_RELATIVE) --dnl --dnl handle --enable-symlink-build --dnl --AC_ARG_ENABLE([symlink-build], --[ --enable-symlink-build use symlinks while building instead of hard links], --if test "$enableval" = "no" --then -- LINK_BUILD_FLAGS= -- AC_MSG_RESULT([Disabling symlinks for build]) --else -- LINK_BUILD_FLAGS=-s -- AC_MSG_RESULT([Enabling symlinks for build]) --fi --, --LINK_BUILD_FLAGS= --AC_MSG_RESULT([Disabling symlinks for build by default]) --) --AC_SUBST(LINK_BUILD_FLAGS) --dnl --dnl handle --enable-verbose-makecmds --dnl --AC_ARG_ENABLE([verbose-makecmds], --[ --enable-verbose-makecmds enable verbose make command output], --if test "$enableval" = "no" --then -- AC_MSG_RESULT([Disabling verbose make commands]) -- E=@echo -- ES=echo -- Q=@ --else -- AC_MSG_RESULT([Enabling verbose make commands]) -- E=@\\# -- ES=\\# -- Q= --fi --, --AC_MSG_RESULT([Disabling verbose make commands]) --E=@echo --ES=echo --Q=@ --) --AC_SUBST(E) --AC_SUBST(ES) --AC_SUBST(Q) --dnl --dnl handle --enable-compression --dnl --AC_ARG_ENABLE([compression], --[ --enable-compression enable EXPERIMENTAL compression support], --if test "$enableval" = "no" --then -- AC_MSG_RESULT([Disabling compression support]) --else -- AC_DEFINE(ENABLE_COMPRESSION, 1, -- [Define to 1 if ext2 compression enabled]) -- AC_MSG_RESULT([Enabling compression support]) -- AC_MSG_WARN([Compression support is experimental]) --fi --, --AC_MSG_RESULT([Disabling compression support by default]) --) --dnl --dnl handle --enable-htree --dnl --AH_TEMPLATE([ENABLE_HTREE], [Define to 1 if ext3/4 htree support enabled]) --AC_ARG_ENABLE([htree], --[ --enable-htree enable EXPERIMENTAL htree directory support], --if test "$enableval" = "no" --then -- HTREE_CMT=# -- AC_MSG_RESULT([Disabling htree directory support]) --else -- HTREE_CMT= -- AC_DEFINE(ENABLE_HTREE, 1) -- AC_MSG_RESULT([Enabling htree directory support]) --fi --, --HTREE_CMT= --AC_DEFINE(ENABLE_HTREE, 1) --AC_MSG_RESULT([Enabling htree directory support by default]) --) --AC_SUBST(HTREE_CMT) --dnl --dnl This needs to be before all of the --enable-*-shlibs options --dnl --E2_PKG_CONFIG_STATIC=--static --LDFLAG_DYNAMIC= --PRIVATE_LIBS_CMT= --dnl --dnl handle --enable-elf-shlibs --dnl --AC_ARG_ENABLE([elf-shlibs], --[ --enable-elf-shlibs select ELF shared libraries], --if test "$enableval" = "no" --then -- ELF_CMT=# -- MAKEFILE_ELF=/dev/null -- AC_MSG_RESULT([Disabling ELF shared libraries]) --else -- E2_PKG_CONFIG_STATIC= -- ELF_CMT= -- MAKEFILE_ELF=$srcdir/lib/Makefile.elf-lib -- [case "$host_os" in -- solaris2.*) -- MAKEFILE_ELF=$srcdir/lib/Makefile.solaris-lib -- ;; -- esac] -- BINARY_TYPE=elfbin -- LIB_EXT=.so -- PRIVATE_LIBS_CMT=# -- LDFLAG_DYNAMIC=['-Wl,-rpath-link,$(top_builddir)/lib'] -- AC_MSG_RESULT([Enabling ELF shared libraries]) --fi --, --MAKEFILE_ELF=/dev/null --ELF_CMT=# --AC_MSG_RESULT([Disabling ELF shared libraries by default]) --) --AC_SUBST(ELF_CMT) --AC_SUBST_FILE(MAKEFILE_ELF) --dnl --dnl handle --enable-bsd-shlibs --dnl --AC_ARG_ENABLE([bsd-shlibs], --[ --enable-bsd-shlibs select BSD shared libraries], --if test "$enableval" = "no" --then -- BSDLIB_CMT=# -- MAKEFILE_BSDLIB=/dev/null -- AC_MSG_RESULT([Disabling BSD shared libraries]) --else -- E2_PKG_CONFIG_STATIC= -- BSDLIB_CMT= -- MAKEFILE_BSDLIB=$srcdir/lib/Makefile.bsd-lib -- LIB_EXT=.so -- [case "$host_os" in -- darwin*) -- MAKEFILE_BSDLIB=$srcdir/lib/Makefile.darwin-lib -- LIB_EXT=.dylib -- ;; -- esac] -- AC_MSG_RESULT([Enabling BSD shared libraries]) --fi --, --MAKEFILE_BSDLIB=/dev/null --BSDLIB_CMT=# --AC_MSG_RESULT([Disabling BSD shared libraries by default]) --) --AC_SUBST(BSDLIB_CMT) --AC_SUBST_FILE(MAKEFILE_BSDLIB) --dnl --dnl handle --enable-profile --dnl --AC_ARG_ENABLE([profile], --[ --enable-profile build profiling libraries], --if test "$enableval" = "no" --then -- PROFILE_CMT=# -- MAKEFILE_PROFILE=/dev/null -- AC_MSG_RESULT([Disabling profiling libraries]) --else -- PROFILE_CMT= -- MAKEFILE_PROFILE=$srcdir/lib/Makefile.profile -- PROFILED_LIB_EXT=_p.a -- AC_MSG_RESULT([Building profiling libraries]) --fi --, --PROFILE_CMT=# --MAKEFILE_PROFILE=/dev/null --AC_MSG_RESULT([Disabling profiling libraries by default]) --) --AC_SUBST(PROFILE_CMT) --AC_SUBST_FILE(MAKEFILE_PROFILE) --dnl --dnl handle --enable-gcov --dnl --AC_ARG_ENABLE([gcov], --[ --enable-gcov build for coverage testing using gcov], --if test "$enableval" = "yes" --then -- CFLAGS="-g -fprofile-arcs -ftest-coverage" -- LDFLAGS="-fprofile-arcs -ftest-coverage" -- AC_MSG_RESULT([Enabling gcov support]) --fi --) -- --dnl --dnl Substitute library extensions --dnl --AC_SUBST(LIB_EXT) --AC_SUBST(STATIC_LIB_EXT) --AC_SUBST(PROFILED_LIB_EXT) --AC_SUBST(LDFLAG_DYNAMIC) --AC_SUBST(PRIVATE_LIBS_CMT) --dnl --dnl handle --enable-jbd-debug --dnl --AC_ARG_ENABLE([jbd-debug], --[ --enable-jbd-debug enable journal debugging], --if test "$enableval" = "no" --then -- AC_MSG_RESULT([Disabling journal debugging]) --else -- AC_DEFINE(CONFIG_JBD_DEBUG, 1, -- [Define to 1 if debugging ext3/4 journal code]) -- AC_MSG_RESULT([Enabling journal debugging]) --fi --, --AC_MSG_RESULT([Disabling journal debugging by default]) --) --dnl --dnl handle --enable-blkid-debug --dnl --AC_ARG_ENABLE([blkid-debug], --[ --enable-blkid-debug enable blkid debugging], --if test "$enableval" = "no" --then -- AC_MSG_RESULT([Disabling blkid debugging]) --else -- AC_DEFINE(CONFIG_BLKID_DEBUG, 1, -- [Define to 1 if debugging the blkid library]) -- AC_MSG_RESULT([Enabling blkid debugging]) --fi --, --AC_MSG_RESULT([Disabling blkid debugging by default]) --) --dnl --dnl handle --enable-testio-debug --dnl --AC_ARG_ENABLE([testio-debug], --[ --disable-testio-debug disable the use of the test I/O manager for debugging], --AH_TEMPLATE([CONFIG_TESTIO_DEBUG], -- [Define to 1 if the testio I/O manager should be enabled]) --if test "$enableval" = "no" --then -- AC_MSG_RESULT([Disabling testio debugging]) -- TEST_IO_CMT="#" --else -- TEST_IO_CMT= -- AC_DEFINE(CONFIG_TESTIO_DEBUG, 1) -- AC_MSG_RESULT([Enabling testio debugging]) --fi --, --AC_MSG_RESULT([Enabling testio debugging by default]) --AC_DEFINE(CONFIG_TESTIO_DEBUG, 1) --TEST_IO_CMT= --) --AC_SUBST(TEST_IO_CMT) --dnl --dnl handle --disable-libuuid --dnl --PKG_PROG_PKG_CONFIG --LIBUUID= --DEPLIBUUID= --STATIC_LIBUUID= --DEPSTATIC_LIBUUID= --PROFILED_LIBUUID= --DEPPROFILED_LIBUUID= --UUID_CMT= --AC_ARG_ENABLE([libuuid], --[ --disable-libuuid do not build private uuid library], --if test "$enableval" = "no" --then -- if test -z "$PKG_CONFIG"; then -- AC_MSG_ERROR([pkg-config not installed; please install it.]) -- fi -- -- AC_CHECK_LIB(uuid, uuid_generate, -- [LIBUUID=`$PKG_CONFIG --libs uuid`; -- STATIC_LIBUUID=`$PKG_CONFIG --static --libs uuid`], -- [AC_MSG_ERROR([external uuid library not found])]) -- PROFILED_LIBUUID=$LIBUUID -- UUID_CMT=# -- AC_MSG_RESULT([Disabling private uuid library]) --else -- LIBUUID='$(LIB)/libuuid'$LIB_EXT -- DEPLIBUUID=$LIBUUID -- STATIC_LIBUUID='$(LIB)/libuuid'$STATIC_LIB_EXT -- DEPSTATIC_LIBUUID=$STATIC_LIBUUID -- PROFILED_LIBUUID='$(LIB)/libuuid'$PROFILED_LIB_EXT -- DEPPROFILED_LIBUUID=$PROFILED_LIBUUID -- AC_MSG_RESULT([Enabling private uuid library]) --fi --, --LIBUUID='$(LIB)/libuuid'$LIB_EXT --DEPLIBUUID=$LIBUUID --STATIC_LIBUUID='$(LIB)/libuuid'$STATIC_LIB_EXT --DEPSTATIC_LIBUUID=$STATIC_LIBUUID --PROFILED_LIBUUID='$(LIB)/libuuid'$PROFILED_LIB_EXT --DEPPROFILED_LIBUUID=$PROFILED_LIBUUID --AC_MSG_RESULT([Enabling private uuid library by default]) --) --AC_SUBST(LIBUUID) --AC_SUBST(DEPLIBUUID) --AC_SUBST(STATIC_LIBUUID) --AC_SUBST(DEPSTATIC_LIBUUID) --AC_SUBST(PROFILED_LIBUUID) --AC_SUBST(DEPPROFILED_LIBUUID) --AC_SUBST(UUID_CMT) --dnl --dnl handle --disable-libblkid --dnl --PKG_PROG_PKG_CONFIG --LIBBLKID= --DEPLIBBLKID= --STATIC_LIBBLKID= --DEPSTATIC_LIBBLKID= --PROFILED_LIBBLKID= --DEPPROFILED_LIBBLKID= --BLKID_CMT= --AH_TEMPLATE([CONFIG_BUILD_FINDFS], [Define to 1 to compile findfs]) --AC_ARG_ENABLE([libblkid], --[ --disable-libblkid do not build private blkid library], --if test "$enableval" = "no" --then -- if test -z "$PKG_CONFIG"; then -- AC_MSG_ERROR([pkg-config not installed; please install it.]) -- fi -- -- AC_CHECK_LIB(blkid, blkid_get_cache, -- [LIBBLKID=`$PKG_CONFIG --libs blkid`; -- STATIC_LIBBLKID=`$PKG_CONFIG --static --libs blkid`], -- [AC_MSG_ERROR([external blkid library not found])], -luuid) -- BLKID_CMT=# -- PROFILED_LIBBLKID=$LIBBLKID -- AC_MSG_RESULT([Disabling private blkid library]) --else -- LIBBLKID='$(LIB)/libblkid'$LIB_EXT -- DEPLIBBLKID=$LIBBLKID -- STATIC_LIBBLKID='$(LIB)/libblkid'$STATIC_LIB_EXT -- DEPSTATIC_LIBBLKID=$STATIC_LIBBLKID -- PROFILED_LIBBLKID='$(LIB)/libblkid'$PROFILED_LIB_EXT -- DEPPROFILED_LIBBLKID=$PROFILED_LIBBLKID -- AC_DEFINE(CONFIG_BUILD_FINDFS, 1) -- AC_MSG_RESULT([Enabling private blkid library]) --fi --, --LIBBLKID='$(LIB)/libblkid'$LIB_EXT --DEPLIBBLKID=$LIBBLKID --STATIC_LIBBLKID='$(LIB)/libblkid'$STATIC_LIB_EXT --DEPSTATIC_LIBBLKID=$STATIC_LIBBLKID --PROFILED_LIBBLKID='$(LIB)/libblkid'$PROFILED_LIB_EXT --DEPPROFILED_LIBBLKID=$PROFILED_LIBBLKID --AC_DEFINE(CONFIG_BUILD_FINDFS, 1) --AC_MSG_RESULT([Enabling private blkid library by default]) --) --AC_SUBST(LIBBLKID) --AC_SUBST(DEPLIBBLKID) --AC_SUBST(STATIC_LIBBLKID) --AC_SUBST(DEPSTATIC_LIBBLKID) --AC_SUBST(PROFILED_LIBBLKID) --AC_SUBST(DEPPROFILED_LIBBLKID) --AC_SUBST(BLKID_CMT) --dnl --dnl handle --enable-quota --dnl --QUOTA_MAN_COMMENT='.\"' --QUOTA_CMT= --AC_SUBST(QUOTA_MAN_COMMENT) --PKG_PROG_PKG_CONFIG --AH_TEMPLATE([CONFIG_QUOTA], [Define to 1 to enable quota support]) --AC_ARG_ENABLE([quota], --[ --enable-quota enable quota support], --if test "$enableval" = "no" --then -- QUOTA_CMT=# -- AC_MSG_RESULT([Disabling quota support]) --else -- QUOTA_CMT= -- AC_DEFINE(CONFIG_QUOTA, 1) -- AC_MSG_RESULT([Enabling quota support]) -- QUOTA_MAN_COMMENT="" -- AC_SUBST(QUOTA_MAN_COMMENT) --fi --, --QUOTA_CMT=# --AC_MSG_RESULT([Disabling quota support by default]) --) --dnl --dnl Define stuff expected for quota library --dnl --LIBQUOTA='$(LIB)/libquota'$LIB_EXT --DEPLIBQUOTA=$LIBQUOTA --STATIC_LIBQUOTA='$(LIB)/libquota'$STATIC_LIB_EXT --DEPSTATIC_LIBQUOTA=$STATIC_LIBQUOTA --PROFILED_LIBQUOTA='$(LIB)/libquota'$PROFILED_LIB_EXT --DEPPROFILED_LIBQUOTA=$PROFILED_LIBQUOTA --AC_SUBST(LIBQUOTA) --AC_SUBST(DEPLIBQUOTA) --AC_SUBST(STATIC_LIBQUOTA) --AC_SUBST(DEPSTATIC_LIBQUOTA) --AC_SUBST(PROFILED_LIBQUOTA) --AC_SUBST(DEPPROFILED_LIBQUOTA) --AC_SUBST(QUOTA_CMT) --dnl --dnl handle --disable-backtrace --dnl --AH_TEMPLATE([DISABLE_BACKTRACE], [Define to 1 to disable use of backtrace]) --AC_ARG_ENABLE([backtrace], --[ --disable-backtrace disable use backtrace], --if test "$enableval" = "no" --then -- AC_MSG_RESULT([Disabling use of backtrace]) -- AC_DEFINE(DISABLE_BACKTRACE, 1) --else -- AC_MSG_RESULT([Enabling use of backtrace]) --fi --, --AC_MSG_RESULT([Enabling use of backtrace by default]) --) --dnl --dnl handle --enable-debugfs --dnl --AC_ARG_ENABLE([debugfs], --[ --disable-debugfs disable support of debugfs program], --if test "$enableval" = "no" --then -- AC_MSG_RESULT([Disabling debugfs support]) -- DEBUGFS_CMT="#" --else -- DEBUGFS_CMT= -- AC_MSG_RESULT([Enabling debugfs support]) --fi --, --AC_MSG_RESULT([Enabling debugfs support by default]) --DEBUGFS_CMT= --) --AC_SUBST(DEBUGFS_CMT) --dnl --dnl handle --enable-imager --dnl --AC_ARG_ENABLE([imager], --[ --disable-imager disable support of e2image program], --if test "$enableval" = "no" --then -- AC_MSG_RESULT([Disabling e2image support]) -- IMAGER_CMT="#" --else -- IMAGER_CMT= -- AC_MSG_RESULT([Enabling e2image support]) --fi --, --AC_MSG_RESULT([Enabling e2image support by default]) --IMAGER_CMT= --) --AC_SUBST(IMAGER_CMT) --dnl --dnl handle --enable-resizer --dnl --AC_ARG_ENABLE([resizer], --[ --disable-resizer disable support of e2resize program], --if test "$enableval" = "no" --then -- AC_MSG_RESULT([Disabling e2resize support]) -- RESIZER_CMT="#" --else -- RESIZER_CMT= -- AC_MSG_RESULT([Enabling e2resize support]) --fi --, --AC_MSG_RESULT([Enabling e2resize support by default]) --RESIZER_CMT= --) --AC_SUBST(RESIZER_CMT) --dnl --dnl handle --enable-defrag --dnl --AC_ARG_ENABLE([defrag], --[ --disable-defrag disable support of e4defrag program], --if test "$enableval" = "no" --then -- AC_MSG_RESULT([Disabling e4defrag support]) -- DEFRAG_CMT="#" --else -- DEFRAG_CMT= -- AC_MSG_RESULT([Enabling e4defrag support]) --fi --, --if test -z "$WITH_DIET_LIBC" --then -- AC_MSG_RESULT([Enabling e4defrag support by default]) -- DEFRAG_CMT= --else -- AC_MSG_RESULT([Disabling e4defrag support by default]) -- DEFRAG_CMT="#" --fi --) --AC_SUBST(DEFRAG_CMT) --dnl --dnl See whether to install the `fsck' wrapper program (that calls e2fsck) --dnl --AC_ARG_ENABLE([fsck], --[ --enable-fsck build fsck wrapper program], --[if test "$enableval" = "no" --then -- FSCK_PROG='' FSCK_MAN='' -- AC_MSG_RESULT([Not building fsck wrapper]) --else -- FSCK_PROG=fsck FSCK_MAN=fsck.8 -- AC_MSG_RESULT([Building fsck wrapper]) --fi] --, --[case "$host_os" in -- gnu*) -- FSCK_PROG='' FSCK_MAN='' -- AC_MSG_RESULT([Not building fsck wrapper by default]) -- ;; -- *) -- FSCK_PROG=fsck FSCK_MAN=fsck.8 -- AC_MSG_RESULT([Building fsck wrapper by default]) --esac] --) --AC_SUBST(FSCK_PROG) --AC_SUBST(FSCK_MAN) --dnl --dnl See whether to install the `e2initrd-helper' program --dnl --AC_ARG_ENABLE([e2initrd-helper], --[ --enable-e2initrd-helper build e2initrd-helper program], --[if test "$enableval" = "no" --then -- E2INITRD_PROG='' E2INITRD_MAN='' -- AC_MSG_RESULT([Not building e2initrd helper]) --else -- E2INITRD_PROG=e2initrd_helper E2INITRD_MAN=e2initrd_helper.8 -- AC_MSG_RESULT([Building e2initrd helper]) --fi] --, --E2INITRD_PROG=e2initrd_helper E2INITRD_MAN=e2initrd_helper.8 --AC_MSG_RESULT([Building e2initrd helper by default]) --) --AC_SUBST(E2INITRD_PROG) --AC_SUBST(E2INITRD_MAN) --dnl --dnl --dnl --AC_ARG_ENABLE([tls], --[ --disable-tls disable use of thread local support], --[if test "$enableval" = "no" --then -- try_tls="" -- AC_MSG_RESULT([Disabling thread local support]) --else -- try_tls="yes" -- AC_MSG_RESULT([Enabling thread local support]) --fi] --, --if test -n "$WITH_DIET_LIBC" --then -- try_tls="" -- AC_MSG_RESULT([Diet libc does not support thread local support]) --else -- try_tls="yes" -- AC_MSG_RESULT([Try using thread local support by default]) --fi --) --if test "$try_tls" = "yes" --then --AX_TLS --fi --dnl --dnl --dnl --AH_TEMPLATE([USE_UUIDD], [Define to 1 to build uuidd]) --AC_ARG_ENABLE([uuidd], --[ --disable-uuidd disable building the uuid daemon], --[if test "$enableval" = "no" --then -- AC_MSG_RESULT([Not building uuidd]) -- UUIDD_CMT="#" --else -- AC_DEFINE(USE_UUIDD, 1) -- UUIDD_CMT="" -- AC_MSG_RESULT([Building uuidd]) --fi] --, --AC_DEFINE(USE_UUIDD, 1) --if test -z "$UUID_CMT" --then -- UUIDD_CMT="" -- AC_MSG_RESULT([Building uuidd by default]) --else -- UUIDD_CMT="#" -- AC_MSG_RESULT([Disabling uuidd by default]) --fi --) --AC_SUBST(UUIDD_CMT) --dnl --dnl --dnl --MAKEFILE_LIBRARY=$srcdir/lib/Makefile.library --AC_SUBST_FILE(MAKEFILE_LIBRARY) --dnl --dnl Add internationalization support, using gettext. --dnl --GETTEXT_PACKAGE=e2fsprogs --PACKAGE=e2fsprogs --VERSION="$E2FSPROGS_VERSION" --VERSION=0.14.1 --AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [package name for gettext]) --AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [version for gettext]) --AC_SUBST(GETTEXT_PACKAGE) --AC_SUBST(PACKAGE) --AC_SUBST(VERSION) -- --AM_GNU_GETTEXT --dnl --dnl End of configuration options --dnl --AC_SUBST(BINARY_TYPE) --AC_PROG_MAKE_SET --CHECK_GNU_MAKE --AC_PATH_PROG(LN, ln, ln) --AC_PROG_LN_S --AC_PATH_PROG(MV, mv, mv) --AC_PATH_PROG(CP, cp, cp) --AC_PATH_PROG(RM, rm, rm) --AC_PATH_PROG(CHMOD, chmod, :) --AC_PROG_AWK --AC_PROG_EGREP --AC_PATH_PROG(SED, sed, sed) --AC_PATH_PROG(PERL, perl, perl) --AC_PATH_PROG(LDCONFIG, ldconfig, :) --AC_CHECK_TOOL(AR, ar, ar) --AC_CHECK_TOOL(RANLIB, ranlib, :) --AC_CHECK_TOOL(STRIP, strip, :) --AC_CHECK_PROG(MAKEINFO, makeinfo, makeinfo, ) --if test "_$MAKEINFO" = "_"; then -- MAKEINFO="@echo Makeinfo is missing. Info documentation will not be built.;true" --else -- case "$MAKEINFO" in -- */missing.*) -- AC_MSG_WARN([ --*** Makeinfo is missing. Info documentation will not be built.]) -- ;; -- *) -- ;; -- esac --fi --AC_SUBST(MAKEINFO) --AC_PROG_INSTALL --# See if we need a separate native compiler. --if test $cross_compiling = no; then -- BUILD_CC="$CC" -- AC_SUBST(BUILD_CC) --else -- AC_CHECK_PROGS(BUILD_CC, gcc cc) --fi --AC_CHECK_HEADERS(m4_flatten([ -- 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 --])) --AC_CHECK_HEADERS(net/if.h,,, --[[ --#if HAVE_SYS_TYPES_H --#include --#endif --#if HAVE_SYS_SOCKET --#include --#endif --]]) --AC_FUNC_VPRINTF --dnl Check to see if dirent has member d_reclen. On cygwin those d_reclen --dnl is not decleared. --AC_CHECK_MEMBER(struct dirent.d_reclen,[AC_DEFINE(HAVE_RECLEN_DIRENT, 1, -- [Define to 1 if dirent has d_reclen])],, -- [#include ]) --AC_CHECK_MEMBERS([struct stat.st_atim]) --dnl Check to see if ssize_t was declared --AC_CHECK_TYPE(ssize_t,[AC_DEFINE(HAVE_TYPE_SSIZE_T, 1, -- [Define to 1 if ssize_t declared])],, -- [#include ]) --dnl --dnl Check to see if llseek() is declared in unistd.h. On some libc's --dnl it is, and on others it isn't..... Thank you glibc developers.... --dnl --AC_CHECK_DECL(llseek,[AC_DEFINE(HAVE_LLSEEK_PROTOTYPE, 1, -- [Define to 1 if llseek declared in unistd.h])],, -- [#include ]) --dnl --dnl Check to see if lseek64() is declared in unistd.h. Glibc's header files --dnl are so convoluted that I can't tell whether it will always be defined, --dnl and if it isn't defined while lseek64 is defined in the library, --dnl disaster will strike. --dnl --dnl Warning! Use of --enable-gcc-wall may throw off this test. --dnl --dnl --AC_CHECK_DECL(lseek64,[AC_DEFINE(HAVE_LSEEK64_PROTOTYPE, 1, -- [Define to 1 if lseek64 declared in unistd.h])],, -- [#define _LARGEFILE_SOURCE -- #define _LARGEFILE64_SOURCE -- #include ]) --dnl --dnl Word sizes... --dnl --AC_CHECK_SIZEOF(short) --AC_CHECK_SIZEOF(int) --AC_CHECK_SIZEOF(long) --AC_CHECK_SIZEOF(long long) --AC_CHECK_SIZEOF(off_t) --SIZEOF_SHORT=$ac_cv_sizeof_short --SIZEOF_INT=$ac_cv_sizeof_int --SIZEOF_LONG=$ac_cv_sizeof_long --SIZEOF_LONG_LONG=$ac_cv_sizeof_long_long --SIZEOF_OFF_T=$ac_cv_sizeof_off_t --AC_SUBST(SIZEOF_SHORT) --AC_SUBST(SIZEOF_INT) --AC_SUBST(SIZEOF_LONG) --AC_SUBST(SIZEOF_LONG_LONG) --AC_SUBST(SIZEOF_OFF_T) --AC_C_BIGENDIAN --if test $cross_compiling = no; then -- BUILD_CC="$BUILD_CC" CPP="$CPP" /bin/sh $ac_aux_dir/parse-types.sh --else -- CROSS_COMPILE="1" BUILD_CC="$BUILD_CC" CPP="$CPP" /bin/sh $ac_aux_dir/parse-types.sh --fi --ASM_TYPES_HEADER=./asm_types.h --AC_SUBST_FILE(ASM_TYPES_HEADER) --dnl --dnl Save the configuration #defines needed for the public ext2fs.h --dnl header file --dnl --echo "/* These defines are needed for the public ext2fs.h header file */" \ -- > public_config.h --if grep HAVE_SYS_TYPES_H confdefs.h > tmp_config.$$; then -- uniq tmp_config.$$ >> public_config.h --else -- echo "#undef HAVE_SYS_TYPES_H" >> public_config.h --fi --if grep WORDS_BIGENDIAN confdefs.h > tmp_config.$$; then -- uniq tmp_config.$$ >> public_config.h --else -- echo "#undef WORDS_BIGENDIAN" >> public_config.h --fi --rm -f tmp_config.$$ --PUBLIC_CONFIG_HEADER=./public_config.h --AC_SUBST_FILE(PUBLIC_CONFIG_HEADER) --dnl --dnl See if we have inttypes.h and if intptr_t is defined --dnl --AC_CHECK_HEADERS([inttypes.h]) --AC_CHECK_TYPES(intptr_t) --dnl --dnl See if struct stat has a st_flags field, in which case we can get file --dnl flags somewhat portably. Also check for the analogous setter, chflags(). --dnl --AC_MSG_CHECKING(whether struct stat has a st_flags field) --AC_CACHE_VAL(e2fsprogs_cv_struct_st_flags, -- AC_TRY_COMPILE([#include ], -- [struct stat stat; stat.st_flags = 0;], -- [e2fsprogs_cv_struct_st_flags=yes], -- [e2fsprogs_cv_struct_st_flags=no])) --AC_MSG_RESULT($e2fsprogs_cv_struct_st_flags) --if test "$e2fsprogs_cv_struct_st_flags" = yes; then -- AC_MSG_CHECKING(whether st_flags field is useful) -- AC_CACHE_VAL(e2fsprogs_cv_struct_st_flags_immut, -- AC_TRY_COMPILE([#include ], -- [struct stat stat; stat.st_flags |= UF_IMMUTABLE;], -- [e2fsprogs_cv_struct_st_flags_immut=yes], -- [e2fsprogs_cv_struct_st_flags_immut=no])) -- AC_MSG_RESULT($e2fsprogs_cv_struct_st_flags_immut) -- if test "$e2fsprogs_cv_struct_st_flags_immut" = yes; then -- AC_DEFINE(HAVE_STAT_FLAGS, 1, -- [Define to 1 if struct stat has st_flags]) -- fi --fi --dnl --dnl Check for the presence of SA_LEN --dnl --AC_CHECK_MEMBER(struct sockaddr.sa_len, -- AC_DEFINE_UNQUOTED(HAVE_SA_LEN,1, -- [Define to 1 if if struct sockaddr contains sa_len]),, -- [#include -- #include ]) --dnl --dnl This will add -lblkid to the AC_CHECK_FUNCS search if we are using --dnl the system-provided blkid library --dnl --if test -n "$BLKID_CMT"; then -- AC_SEARCH_LIBS([blkid_probe_all], [blkid]) --fi --dnl --AC_CHECK_FUNCS(m4_flatten([ -- __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 -- utimes -- valloc --])) --dnl --dnl Check to see if -lsocket is required (solaris) to make something --dnl that uses socket() to compile; this is needed for the UUID library --dnl --SOCKET_LIB='' --AC_CHECK_LIB(socket, socket, [SOCKET_LIB=-lsocket]) --AC_SUBST(SOCKET_LIB) --dnl --dnl See if optreset exists --dnl --AC_MSG_CHECKING(for optreset) --AC_CACHE_VAL(ac_cv_have_optreset, --[AC_EGREP_HEADER(optreset, unistd.h, -- ac_cv_have_optreset=yes, ac_cv_have_optreset=no)])dnl --AC_MSG_RESULT($ac_cv_have_optreset) --if test $ac_cv_have_optreset = yes; then -- AC_DEFINE(HAVE_OPTRESET, 1, [Define to 1 if optreset for getopt is present]) --fi --dnl --dnl Test for sem_init, and which library it might require: --dnl --AH_TEMPLATE([HAVE_SEM_INIT], [Define to 1 if sem_init() exists]) --SEM_INIT_LIB='' --AC_CHECK_FUNC(sem_init, , -- AC_CHECK_LIB(pthread, sem_init, -- AC_DEFINE(HAVE_SEM_INIT, 1) -- SEM_INIT_LIB=-lpthread, -- AC_CHECK_LIB(rt, sem_init, -- AC_DEFINE(HAVE_SEM_INIT, 1) -- SEM_INIT_LIB=-lrt, -- AC_CHECK_LIB(posix4, sem_init, -- AC_DEFINE(HAVE_SEM_INIT, 1) -- SEM_INIT_LIB=-lposix4))))dnl --AC_SUBST(SEM_INIT_LIB) --dnl --dnl Check for unified diff --dnl --AC_MSG_CHECKING(for unified diff option) --if diff -u $0 $0 > /dev/null 2>&1 ; then -- UNI_DIFF_OPTS=-u --else -- UNI_DIFF_OPTS=-c --fi --AC_MSG_RESULT($UNI_DIFF_OPTS) --AC_SUBST(UNI_DIFF_OPTS) --dnl --dnl We use the EXT2 ioctls only under Linux --dnl --case "$host_os" in --linux*) -- AC_DEFINE(HAVE_EXT2_IOCTLS, 1, [Define to 1 if Ext2 ioctls present]) -- ;; --esac --dnl --dnl OS-specific uncomment control --dnl --LINUX_CMT="#" --CYGWIN_CMT="#" --UNIX_CMT= --case "$host_os" in --linux*) -- LINUX_CMT= -- ;; --cygwin) -- CYGWIN_CMT= -- UNIX_CMT="#" -- ;; --esac --AC_SUBST(LINUX_CMT) --AC_SUBST(CYGWIN_CMT) --AC_SUBST(UNIX_CMT) --dnl --dnl Linux and Hurd places root files in the / by default --dnl --case "$host_os" in --linux* | gnu* | k*bsd*-gnu) -- if test "$prefix" = NONE -a "$root_prefix" = NONE ; then -- root_prefix=""; -- AC_MSG_RESULT([On $host_os systems, root_prefix defaults to '']) -- fi -- ;; --esac --dnl --dnl On Linux/hurd, force the prefix to be /usr --dnl --case "$host_os" in --linux* | gnu* | k*bsd*-gnu) -- if test "$prefix" = NONE ; then -- prefix="/usr"; -- AC_MSG_RESULT([On $host_os systems, prefix defaults to /usr]) -- if test "$mandir" = '${prefix}/man' ; then -- AC_MSG_RESULT([...and mandir defaults to /usr/share/man]) -- mandir=/usr/share/man -- fi -- fi --;; --esac --if test "$root_prefix" = NONE ; then -- if test "$prefix" = NONE ; then -- root_prefix="$ac_default_prefix" -- else -- root_prefix="$prefix" -- fi -- root_bindir=$bindir -- root_sbindir=$sbindir -- root_libdir=$libdir -- root_sysconfdir=$sysconfdir --else -- root_bindir='${root_prefix}/bin' -- root_sbindir='${root_prefix}/sbin' -- root_libdir='${root_prefix}/lib' -- root_sysconfdir='${root_prefix}/etc' --fi --if test "$bindir" != '${exec_prefix}/bin'; then -- root_bindir=$bindir -- AC_MSG_RESULT([Setting root_bindir to $root_bindir]) --fi --if test "$sbindir" != '${exec_prefix}/sbin'; then -- root_sbindir=$sbindir -- AC_MSG_RESULT([Setting root_sbindir to $root_sbindir]) --fi --if test "$libdir" != '${exec_prefix}/lib'; then -- root_libdir=$libdir -- AC_MSG_RESULT([Setting root_libdir to $root_libdir]) --fi --if test "$sysconfdir" != '${prefix}/etc'; then -- root_sysconfdir=$sysconfdir -- AC_MSG_RESULT([Setting root_sysconfdir to $root_sysconfdir]) --fi --AC_SUBST(root_prefix) --AC_SUBST(root_bindir) --AC_SUBST(root_sbindir) --AC_SUBST(root_libdir) --AC_SUBST(root_sysconfdir) --dnl --dnl Allow specification of the multiarch arch --dnl --AC_ARG_WITH([multiarch], --[ --with-multiarch=ARCH specify the multiarch triplet], --if test "$withval" = "lib64"; then -- libdir=/usr/lib64 -- root_libdir=/lib64 --else -- libdir=$libdir/$withval -- root_libdir=$root_libdir/$withval --fi --)dnl --dnl --dnl See if -static works. This could fail if the linker does not --dnl support -static, or if required external libraries are not available --dnl in static form. --dnl --AC_MSG_CHECKING([whether we can link with -static]) --AC_CACHE_VAL(ac_cv_e2fsprogs_use_static, --[SAVE_LDFLAGS=$LDFLAGS; LDFLAGS="$LDFLAGS -static" --AC_TRY_LINK([#include ],[fflush(stdout);], -- ac_cv_e2fsprogs_use_static=yes, ac_cv_e2fsprogs_use_static=no) --LDFLAGS=$SAVE_LDFLAGS]) --dnl --dnl Regardless of how the test turns out, Solaris doesn't handle -static --dnl This is caused by the socket library requiring the nsl library, which --dnl requires the -dl library, which only works for dynamically linked --dnl programs. It basically means you can't have statically linked programs --dnl which use the network under Solaris. --dnl --case "$host_os" in --solaris2.*) -- ac_cv_e2fsprogs_use_static=no --;; --esac --AC_MSG_RESULT($ac_cv_e2fsprogs_use_static) --LDFLAG_STATIC= --if test $ac_cv_e2fsprogs_use_static = yes; then -- LDFLAG_STATIC=-static --fi --AC_SUBST(LDFLAG_STATIC) --dnl --dnl Work around mysterious Darwin / GNU libintl problem --dnl (__asm__ redirection doesn't work for some mysterious reason. Looks like --dnl Apple hacked gcc somehow?) --dnl --case "$host_os" in --darwin*) -- AC_MSG_RESULT([Using Apple Darwin / GNU libintl workaround]) -- AC_DEFINE(_INTL_REDIRECT_MACROS, 1, -- [Define to 1 if Apple Darwin libintl workaround is needed]) -- ;; --esac --dnl --dnl Make the ss and et directories work correctly. --dnl --SS_DIR=`cd ${srcdir}/lib/ss; pwd` --ET_DIR=`cd ${srcdir}/lib/et; pwd` --AC_SUBST(SS_DIR) --AC_SUBST(ET_DIR) --dnl --dnl Only try to run the test suite if we're not cross compiling. --dnl --if test "$cross_compiling" = yes ; then -- DO_TEST_SUITE= --else -- DO_TEST_SUITE=check --fi --AC_SUBST(DO_TEST_SUITE) --dnl --dnl Only include the intl include files if we're building with them --dnl --INCLUDES='-I. -I$(top_builddir)/lib -I$(top_srcdir)/lib' --if test -n "$CPPFLAGS" ; then -- INCLUDES="$INCLUDES $CPPFLAGS" --fi --if test "$USE_INCLUDED_LIBINTL" = "yes" ; then -- INCLUDES=$INCLUDES' -I$(top_builddir)/intl -I$(top_srcdir)/intl' --fi --if test -n "$WITH_DIET_LIBC" ; then -- INCLUDES="$INCLUDES -D_REENTRANT" --fi --AC_SUBST(INCLUDES) --AM_MKINSTALLDIRS --dnl --dnl Build CFLAGS --dnl --if test $cross_compiling = no; then -- BUILD_CFLAGS="$CFLAGS $CPPFLAGS $INCLUDES -DHAVE_CONFIG_H" -- BUILD_LDFLAGS="$LDFLAGS" --fi --AC_SUBST(BUILD_CFLAGS) --AC_SUBST(BUILD_LDFLAGS) --dnl --dnl Make our output files, being sure that we create the some miscellaneous --dnl directories --dnl --test -d lib || mkdir lib --test -d include || mkdir include --test -d include/linux || mkdir include/linux --test -d include/asm || mkdir include/asm --for i in MCONFIG Makefile e2fsprogs.spec \ -- util/Makefile util/subst.conf util/gen-tarball util/install-symlink \ -- lib/et/Makefile lib/ss/Makefile lib/e2p/Makefile \ -- lib/ext2fs/Makefile lib/ext2fs/ext2_types.h \ -- lib/uuid/Makefile lib/uuid/uuid_types.h \ -- lib/blkid/Makefile lib/blkid/blkid_types.h lib/quota/Makefile \ -- lib/ss/ss.pc lib/uuid/uuid.pc lib/et/com_err.pc \ -- lib/e2p/e2p.pc lib/blkid/blkid.pc lib/ext2fs/ext2fs.pc \ -- misc/Makefile ext2ed/Makefile e2fsck/Makefile \ -- debugfs/Makefile tests/Makefile tests/progs/Makefile \ -- resize/Makefile doc/Makefile intl/Makefile \ -- intl/libgnuintl.h po/Makefile.in ; do -- if test -d `dirname ${srcdir}/$i` ; then -- outlist="$outlist $i" -- fi --done --AC_OUTPUT($outlist) --if test -f util/gen-tarball; then chmod +x util/gen-tarball; fi -diff --git a/contrib/Android.mk b/contrib/Android.mk -new file mode 100644 -index 0000000..6628145 ---- /dev/null -+++ b/contrib/Android.mk -@@ -0,0 +1,79 @@ -+LOCAL_PATH := $(call my-dir) -+ -+########################################################################### -+# Build fsstress -+# -+fsstress_src_files := \ -+ fsstress.c -+ -+fsstress_c_includes := -+ -+fsstress_cflags := -O2 -g -W -Wall -+ -+fsstress_shared_libraries := -+ -+fsstress_system_shared_libraries := libc -+ -+include $(CLEAR_VARS) -+ -+LOCAL_SRC_FILES := $(fsstress_src_files) -+mke2fs_c_includesLOCAL_CFLAGS := $(fsstress_cflags) -+LOCAL_SYSTEM_SHARED_LIBRARIES := $(fsstress_system_shared_libraries) -+LOCAL_MODULE := fsstress -+LOCAL_MODULE_TAGS := optional -+ -+include $(BUILD_EXECUTABLE) -+ -+include $(CLEAR_VARS) -+ -+LOCAL_SRC_FILES := $(fsstress_src_files) -+LOCAL_CFLAGS := $(fsstress_cflags) -+LOCAL_MODULE := fsstress_host -+LOCAL_MODULE_STEM := fsstress -+LOCAL_MODULE_TAGS := optional -+ -+include $(BUILD_HOST_EXECUTABLE) -+ -+######################################################################### -+# Build add_ext4_encrypt -+# -+include $(CLEAR_VARS) -+ -+add_ext4_encrypt_src_files := \ -+ add_ext4_encrypt.c -+ -+add_ext4_encrypt_c_includes := \ -+ external/e2fsprogs/lib -+ -+add_ext4_encrypt_cflags := -O2 -g -W -Wall -+ -+add_ext4_encrypt_shared_libraries := \ -+ libext2fs \ -+ libext2_com_err -+ -+add_ext4_encrypt_system_shared_libraries := libc -+ -+include $(CLEAR_VARS) -+ -+LOCAL_SRC_FILES := $(add_ext4_encrypt_src_files) -+LOCAL_C_INCLUDES := $(add_ext4_encrypt_c_includes) -+LOCAL_CFLAGS := $(add_ext4_encrypt_cflags) -+LOCAL_SHARED_LIBRARIES := $(add_ext4_encrypt_shared_libraries) -+LOCAL_SYSTEM_SHARED_LIBRARIES := $(add_ext4_encrypt_system_shared_libraries) -+LOCAL_MODULE := add_ext4_encrypt -+LOCAL_MODULE_TAGS := optional -+ -+include $(BUILD_EXECUTABLE) -+ -+include $(CLEAR_VARS) -+ -+LOCAL_SRC_FILES := $(add_ext4_encrypt_src_files) -+LOCAL_C_INCLUDES := $(add_ext4_encrypt_c_includes) -+LOCAL_CFLAGS := $(add_ext4_encrypt_cflags) -+LOCAL_SHARED_LIBRARIES := $(addsuffix _host, $(add_ext4_encrypt_shared_libraries)) -+LOCAL_MODULE := add_ext4_encrypt_host -+LOCAL_MODULE_STEM := add_ext4_encrypt -+LOCAL_MODULE_TAGS := optional -+ -+include $(BUILD_HOST_EXECUTABLE) -+ -diff --git a/contrib/add_ext4_encrypt.c b/contrib/add_ext4_encrypt.c -new file mode 100644 -index 0000000..73008dc ---- /dev/null -+++ b/contrib/add_ext4_encrypt.c -@@ -0,0 +1,65 @@ -+/* -+ * Basic progam to add ext4 encryption to a file system -+ * -+ * Copyright 2015, Google, Inc. -+ * -+ * %Begin-Header% -+ * This file may be redistributed under the terms of the GNU Public -+ * License. -+ * %End-Header% -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+int main (int argc, char *argv[]) -+{ -+ errcode_t retval = 0; -+ ext2_filsys fs; -+ -+ setbuf(stdout, NULL); -+ setbuf(stderr, NULL); -+ initialize_ext2_error_table(); -+ -+ if (argc != 2) { -+ fprintf(stderr, "%s: Usage \n", argv[0]); -+ exit(1); -+ } -+ -+ retval = ext2fs_open(argv[1], EXT2_FLAG_RW, 0, 0, -+ unix_io_manager, &fs); -+ -+ if (retval) { -+ com_err(argv[0], retval, "while trying to open '%s'", -+ argv[1]); -+ exit(1); -+ } -+ if (!EXT2_HAS_INCOMPAT_FEATURE(fs->super, -+ EXT4_FEATURE_INCOMPAT_ENCRYPT)) { -+ fs->super->s_feature_incompat |= EXT4_FEATURE_INCOMPAT_ENCRYPT; -+ fs->super->s_encrypt_algos[0] = -+ EXT4_ENCRYPTION_MODE_AES_256_XTS; -+ fs->super->s_encrypt_algos[1] = -+ EXT4_ENCRYPTION_MODE_AES_256_CTS; -+ ext2fs_mark_super_dirty(fs); -+ printf("Ext4 encryption enabled on %s\n", argv[1]); -+ } else -+ printf("Ext4 encryption already enabled on %s\n", argv[1]); -+ -+ retval = ext2fs_close(fs); -+ if (retval) { -+ com_err(argv[0], retval, "while trying to close '%s'", -+ argv[1]); -+ exit(1); -+ } -+ return (0); -+} -+ -diff --git a/contrib/dir2fs b/contrib/dir2fs -new file mode 100755 -index 0000000..abcecb3 ---- /dev/null -+++ b/contrib/dir2fs -@@ -0,0 +1,66 @@ -+#!/bin/sh -+ -+dir="$1" -+dev="$2" -+ -+if [ "$1" = "--help" ] || [ ! -d "${dir}" ]; then -+ echo "Usage: $0 dir [mke2fs args] dev" -+ exit 1 -+fi -+ -+shift -+ -+# Goal: Put all the files at the beginning (which mke2fs does) and minimize -+# the number of free inodes given the minimum number of blocks required. -+# Hence all this math to get the inode ratio just right. -+ -+bytes="$(du -ks "${dir}" | awk '{print $1}')" -+bytes="$((bytes * 1024))" -+inodes="$(find "${dir}" -print0 | xargs -0 stat -c '%i' | sort -g | uniq | wc -l)" -+block_sz=4096 -+inode_sz=256 -+sb_overhead=4096 -+blocks_per_group="$((block_sz * 8))" -+bytes_per_group="$((blocks_per_group * block_sz))" -+inode_bytes="$((inodes * inode_sz))" -+ -+# Estimate overhead with the minimum number of groups... -+nr_groups="$(( (bytes + inode_bytes + bytes_per_group - 1) / bytes_per_group))" -+inode_bytes_per_group="$((inode_bytes / nr_groups))" -+inode_blocks_per_group="$(( (inode_bytes_per_group + (block_sz - 1)) / block_sz ))" -+per_grp_overhead="$(( ((3 + inode_blocks_per_group) * block_sz) + 64 ))" -+overhead="$(( sb_overhead + (per_grp_overhead * nr_groups) ))" -+used_bytes="$((bytes + overhead))" -+ -+# Then do it again with the real number of groups. -+nr_groups="$(( (used_bytes + (bytes_per_group - 1)) / bytes_per_group))" -+tot_blocks="$((nr_groups * blocks_per_group))" -+tot_bytes="$((tot_blocks * block_sz))" -+ -+ratio="$((bytes / inodes))" -+mkfs_blocks="$((tot_blocks * 4 / 3))" -+ -+mke2fs -i "${ratio}" -T ext4 -d "${dir}" -O ^resize_inode,sparse_super2,metadata_csum,64bit,^has_journal -E packed_meta_blocks=1,num_backup_sb=0 -b "${block_sz}" -I "${inodesz}" -F "${dev}" "${mkfs_blocks}" || exit -+ -+e2fsck -fyD "${dev}" -+ -+blocks="$(dumpe2fs -h "${dev}" 2>&1 | grep 'Block count:' | awk '{print $3}')" -+while resize2fs -f -M "${dev}"; do -+ new_blocks="$(dumpe2fs -h "${dev}" 2>&1 | grep 'Block count:' | awk '{print $3}')" -+ if [ "${new_blocks}" -eq "${blocks}" ]; then -+ break; -+ fi -+ blocks="${new_blocks}" -+done -+ -+if [ ! -b "${dev}" ]; then -+ truncate -s "$((blocks * block_sz))" "${dev}" || (e2image -ar "${dev}" "${dev}.min"; mv "${dev}.min" "${dev}") -+fi -+ -+e2fsck -fy "${dev}" -+ -+dir_blocks="$((bytes / block_sz))" -+overhead="$((blocks - dir_blocks))" -+echo "Minimized image overhead: $((100 * overhead / dir_blocks))%" -+ -+exit 0 -diff --git a/contrib/fallocate.c b/contrib/fallocate.c -index 1f9b59a..a05b8f2 100644 ---- a/contrib/fallocate.c -+++ b/contrib/fallocate.c -@@ -21,8 +21,12 @@ - * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -+#ifndef _LARGEFILE_SOURCE - #define _LARGEFILE_SOURCE -+#endif -+#ifndef _LARGEFILE64_SOURCE - #define _LARGEFILE64_SOURCE -+#endif - - #include - #include -@@ -36,6 +40,8 @@ - // #include - #define FALLOC_FL_KEEP_SIZE 0x01 - #define FALLOC_FL_PUNCH_HOLE 0x02 /* de-allocates range */ -+#define FALLOC_FL_COLLAPSE_RANGE 0x08 -+#define FALLOC_FL_ZERO_RANGE 0x10 - - void usage(void) - { -@@ -95,7 +101,7 @@ int main(int argc, char **argv) - int error; - int tflag = 0; - -- while ((opt = getopt(argc, argv, "npl:o:t")) != -1) { -+ while ((opt = getopt(argc, argv, "npl:o:tzc")) != -1) { - switch(opt) { - case 'n': - /* do not change filesize */ -@@ -106,6 +112,16 @@ int main(int argc, char **argv) - falloc_mode = (FALLOC_FL_PUNCH_HOLE | - FALLOC_FL_KEEP_SIZE); - break; -+ case 'c': -+ /* collapse range mode */ -+ falloc_mode = (FALLOC_FL_COLLAPSE_RANGE | -+ FALLOC_FL_KEEP_SIZE); -+ break; -+ case 'z': -+ /* zero range mode */ -+ falloc_mode = (FALLOC_FL_ZERO_RANGE | -+ FALLOC_FL_KEEP_SIZE); -+ break; - case 'l': - length = cvtnum(optarg); - break; -diff --git a/contrib/fsstress.c b/contrib/fsstress.c -new file mode 100644 -index 0000000..2a98348 ---- /dev/null -+++ b/contrib/fsstress.c -@@ -0,0 +1,2701 @@ -+/* -+ * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of version 2 of the GNU General Public License as -+ * published by the Free Software Foundation. -+ * -+ * This program is distributed in the hope that it would be useful, but -+ * WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -+ * -+ * Further, this software is distributed without any warranty that it is -+ * free of the rightful claim of any third person regarding infringement -+ * or the like. Any license provided herein, whether implied or -+ * otherwise, applies only to this software file. Patent licenses, if -+ * any, provided herein do not apply to combinations of this program with -+ * other software, or any other product whatsoever. -+ * -+ * You should have received a copy of the GNU General Public License along -+ * with this program; if not, write the Free Software Foundation, Inc., -+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -+ * -+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, -+ * Mountain View, CA 94043, or: -+ * -+ * http://www.sgi.com -+ * -+ * For further information regarding this notice, see: -+ * -+ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ -+ */ -+ -+#define NO_XFS -+#define HAVE_SYS_PRCTL_H -+#define _LARGEFILE64_SOURCE -+ -+#define MAXNAMELEN 1024 -+struct dioattr { -+ int d_miniosz, d_maxiosz, d_mem; -+}; -+ -+#define MIN(a,b) ((a)<(b) ? (a):(b)) -+#define MAX(a,b) ((a)>(b) ? (a):(b)) -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#ifndef O_DIRECT -+#define O_DIRECT 040000 -+#endif -+ -+#ifdef HAVE_SYS_PRCTL_H -+# include -+#endif -+ -+#define XFS_ERRTAG_MAX 17 -+ -+typedef enum { -+#ifndef NO_XFS -+ OP_ALLOCSP, -+ OP_ATTR_REMOVE, -+ OP_ATTR_SET, -+ OP_BULKSTAT, -+ OP_BULKSTAT1, -+#endif -+ OP_CHOWN, -+ OP_CREAT, -+ OP_DREAD, -+ OP_DWRITE, -+ OP_FDATASYNC, -+#ifndef NO_XFS -+ OP_FREESP, -+#endif -+ OP_FSYNC, -+ OP_GETDENTS, -+ OP_LINK, -+ OP_MKDIR, -+ OP_MKNOD, -+ OP_READ, -+ OP_READLINK, -+ OP_RENAME, -+#ifndef NO_XFS -+ OP_RESVSP, -+#endif -+ OP_RMDIR, -+ OP_STAT, -+ OP_SYMLINK, -+ OP_SYNC, -+ OP_TRUNCATE, -+ OP_UNLINK, -+#ifndef NO_XFS -+ OP_UNRESVSP, -+#endif -+ OP_WRITE, -+ OP_LAST -+} opty_t; -+ -+typedef void (*opfnc_t) (int, long); -+ -+typedef struct opdesc { -+ opty_t op; -+ char *name; -+ opfnc_t func; -+ int freq; -+ int iswrite; -+ int isxfs; -+} opdesc_t; -+ -+typedef struct fent { -+ int id; -+ int parent; -+} fent_t; -+ -+typedef struct flist { -+ int nfiles; -+ int nslots; -+ int tag; -+ fent_t *fents; -+} flist_t; -+ -+typedef struct pathname { -+ int len; -+ char *path; -+} pathname_t; -+ -+#define FT_DIR 0 -+#define FT_DIRm (1 << FT_DIR) -+#define FT_REG 1 -+#define FT_REGm (1 << FT_REG) -+#define FT_SYM 2 -+#define FT_SYMm (1 << FT_SYM) -+#define FT_DEV 3 -+#define FT_DEVm (1 << FT_DEV) -+#define FT_RTF 4 -+#define FT_RTFm (1 << FT_RTF) -+#define FT_nft 5 -+#define FT_ANYm ((1 << FT_nft) - 1) -+#define FT_REGFILE (FT_REGm | FT_RTFm) -+#define FT_NOTDIR (FT_ANYm & ~FT_DIRm) -+ -+#define FLIST_SLOT_INCR 16 -+#define NDCACHE 64 -+ -+#define MAXFSIZE ((1ULL << 63) - 1ULL) -+#define MAXFSIZE32 ((1ULL << 40) - 1ULL) -+ -+void allocsp_f(int, long); -+void attr_remove_f(int, long); -+void attr_set_f(int, long); -+void bulkstat_f(int, long); -+void bulkstat1_f(int, long); -+void chown_f(int, long); -+void creat_f(int, long); -+void dread_f(int, long); -+void dwrite_f(int, long); -+void fdatasync_f(int, long); -+void freesp_f(int, long); -+void fsync_f(int, long); -+void getdents_f(int, long); -+void link_f(int, long); -+void mkdir_f(int, long); -+void mknod_f(int, long); -+void read_f(int, long); -+void readlink_f(int, long); -+void rename_f(int, long); -+void resvsp_f(int, long); -+void rmdir_f(int, long); -+void stat_f(int, long); -+void symlink_f(int, long); -+void sync_f(int, long); -+void truncate_f(int, long); -+void unlink_f(int, long); -+void unresvsp_f(int, long); -+void write_f(int, long); -+ -+opdesc_t ops[] = { -+#ifndef NO_XFS -+ {OP_ALLOCSP, "allocsp", allocsp_f, 1, 1, 1}, -+ {OP_ATTR_REMOVE, "attr_remove", attr_remove_f, /* 1 */ 0, 1, 1}, -+ {OP_ATTR_SET, "attr_set", attr_set_f, /* 2 */ 0, 1, 1}, -+ {OP_BULKSTAT, "bulkstat", bulkstat_f, 1, 0, 1}, -+ {OP_BULKSTAT1, "bulkstat1", bulkstat1_f, 1, 0, 1}, -+#endif -+ {OP_CHOWN, "chown", chown_f, 3, 1, 0}, -+ {OP_CREAT, "creat", creat_f, 4, 1, 0}, -+ {OP_DREAD, "dread", dread_f, 4, 0, 0}, -+ {OP_DWRITE, "dwrite", dwrite_f, 4, 1, 0}, -+ {OP_FDATASYNC, "fdatasync", fdatasync_f, 1, 1, 0}, -+#ifndef NO_XFS -+ {OP_FREESP, "freesp", freesp_f, 1, 1, 1}, -+#endif -+ {OP_FSYNC, "fsync", fsync_f, 1, 1, 0}, -+ {OP_GETDENTS, "getdents", getdents_f, 1, 0, 0}, -+ {OP_LINK, "link", link_f, 1, 1, 0}, -+ {OP_MKDIR, "mkdir", mkdir_f, 2, 1, 0}, -+ {OP_MKNOD, "mknod", mknod_f, 2, 1, 0}, -+ {OP_READ, "read", read_f, 1, 0, 0}, -+ {OP_READLINK, "readlink", readlink_f, 1, 0, 0}, -+ {OP_RENAME, "rename", rename_f, 2, 1, 0}, -+#ifndef NO_XFS -+ {OP_RESVSP, "resvsp", resvsp_f, 1, 1, 1}, -+#endif -+ {OP_RMDIR, "rmdir", rmdir_f, 1, 1, 0}, -+ {OP_STAT, "stat", stat_f, 1, 0, 0}, -+ {OP_SYMLINK, "symlink", symlink_f, 2, 1, 0}, -+ {OP_SYNC, "sync", sync_f, 1, 0, 0}, -+ {OP_TRUNCATE, "truncate", truncate_f, 2, 1, 0}, -+ {OP_UNLINK, "unlink", unlink_f, 1, 1, 0}, -+#ifndef NO_XFS -+ {OP_UNRESVSP, "unresvsp", unresvsp_f, 1, 1, 1}, -+#endif -+ {OP_WRITE, "write", write_f, 4, 1, 0}, -+}, *ops_end; -+ -+flist_t flist[FT_nft] = { -+ {0, 0, 'd', NULL}, -+ {0, 0, 'f', NULL}, -+ {0, 0, 'l', NULL}, -+ {0, 0, 'c', NULL}, -+ {0, 0, 'r', NULL}, -+}; -+ -+int dcache[NDCACHE]; -+int errrange; -+int errtag; -+opty_t *freq_table; -+int freq_table_size; -+#ifndef NO_XFS -+xfs_fsop_geom_t geom; -+#endif -+char *homedir; -+int *ilist; -+int ilistlen; -+off64_t maxfsize; -+char *myprog; -+int namerand; -+int nameseq; -+int nops; -+int nproc = 1; -+int operations = 1; -+int procid; -+int rtpct; -+unsigned long seed = 0; -+ino_t top_ino; -+int verbose = 0; -+#ifndef NO_XFS -+int no_xfs = 0; -+#else -+int no_xfs = 1; -+#endif -+sig_atomic_t should_stop = 0; -+ -+void add_to_flist(int, int, int); -+void append_pathname(pathname_t *, char *); -+#ifndef NO_XFS -+int attr_list_path(pathname_t *, char *, const int, int, attrlist_cursor_t *); -+int attr_remove_path(pathname_t *, const char *, int); -+int attr_set_path(pathname_t *, const char *, const char *, const int, int); -+#endif -+void check_cwd(void); -+int creat_path(pathname_t *, mode_t); -+void dcache_enter(int, int); -+void dcache_init(void); -+fent_t *dcache_lookup(int); -+void dcache_purge(int); -+void del_from_flist(int, int); -+int dirid_to_name(char *, int); -+void doproc(void); -+void fent_to_name(pathname_t *, flist_t *, fent_t *); -+void fix_parent(int, int); -+void free_pathname(pathname_t *); -+int generate_fname(fent_t *, int, pathname_t *, int *, int *); -+int get_fname(int, long, pathname_t *, flist_t **, fent_t **, int *); -+void init_pathname(pathname_t *); -+int lchown_path(pathname_t *, uid_t, gid_t); -+int link_path(pathname_t *, pathname_t *); -+int lstat64_path(pathname_t *, struct stat64 *); -+void make_freq_table(void); -+int mkdir_path(pathname_t *, mode_t); -+int mknod_path(pathname_t *, mode_t, dev_t); -+void namerandpad(int, char *, int); -+int open_path(pathname_t *, int); -+DIR *opendir_path(pathname_t *); -+void process_freq(char *); -+int readlink_path(pathname_t *, char *, size_t); -+int rename_path(pathname_t *, pathname_t *); -+int rmdir_path(pathname_t *); -+void separate_pathname(pathname_t *, char *, pathname_t *); -+void show_ops(int, char *); -+int stat64_path(pathname_t *, struct stat64 *); -+int symlink_path(const char *, pathname_t *); -+int truncate64_path(pathname_t *, off64_t); -+int unlink_path(pathname_t *); -+void usage(void); -+void write_freq(void); -+void zero_freq(void); -+ -+void sg_handler(int signum) -+{ -+ should_stop = 1; -+} -+ -+int main(int argc, char **argv) -+{ -+ char buf[10]; -+ int c; -+ char *dirname = NULL; -+ int fd; -+ int i; -+ int cleanup = 0; -+ int loops = 1; -+ int loopcntr = 1; -+ char cmd[256]; -+#ifndef NO_XFS -+ int j; -+#endif -+ char *p; -+ int stat; -+ struct timeval t; -+#ifndef NO_XFS -+ ptrdiff_t srval; -+#endif -+ int nousage = 0; -+#ifndef NO_XFS -+ xfs_error_injection_t err_inj; -+#endif -+ struct sigaction action; -+ -+ errrange = errtag = 0; -+ umask(0); -+ nops = sizeof(ops) / sizeof(ops[0]); -+ ops_end = &ops[nops]; -+ myprog = argv[0]; -+ while ((c = getopt(argc, argv, "cd:e:f:i:l:n:p:rs:vwzHSX")) != -1) { -+ switch (c) { -+ case 'c': -+ /*Don't cleanup */ -+ cleanup = 1; -+ break; -+ case 'd': -+ dirname = optarg; -+ break; -+ case 'e': -+ sscanf(optarg, "%d", &errtag); -+ if (errtag < 0) { -+ errtag = -errtag; -+ errrange = 1; -+ } else if (errtag == 0) -+ errtag = -1; -+ if (errtag >= XFS_ERRTAG_MAX) { -+ fprintf(stderr, -+ "error tag %d too large (max %d)\n", -+ errtag, XFS_ERRTAG_MAX - 1); -+ exit(1); -+ } -+ break; -+ case 'f': -+ process_freq(optarg); -+ break; -+ case 'i': -+ ilist = realloc(ilist, ++ilistlen * sizeof(*ilist)); -+ ilist[ilistlen - 1] = strtol(optarg, &p, 16); -+ break; -+ case 'l': -+ loops = atoi(optarg); -+ break; -+ case 'n': -+ operations = atoi(optarg); -+ break; -+ case 'p': -+ nproc = atoi(optarg); -+ break; -+ case 'r': -+ namerand = 1; -+ break; -+ case 's': -+ seed = strtoul(optarg, NULL, 0); -+ break; -+ case 'v': -+ verbose = 1; -+ break; -+ case 'w': -+ write_freq(); -+ break; -+ case 'z': -+ zero_freq(); -+ break; -+ case 'S': -+ show_ops(0, NULL); -+ printf("\n"); -+ nousage = 1; -+ break; -+ case '?': -+ fprintf(stderr, "%s - invalid parameters\n", myprog); -+ /* fall through */ -+ case 'H': -+ usage(); -+ exit(1); -+ case 'X': -+ no_xfs = 1; -+ break; -+ } -+ } -+ -+ if (no_xfs && errtag) { -+ fprintf(stderr, "error injection only works on XFS\n"); -+ exit(1); -+ } -+ -+ if (no_xfs) { -+ int i; -+ for (i = 0; ops + i < ops_end; ++i) { -+ if (ops[i].isxfs) -+ ops[i].freq = 0; -+ } -+ } -+ -+ make_freq_table(); -+ -+ while (((loopcntr <= loops) || (loops == 0)) && !should_stop) { -+ if (!dirname) { -+ /* no directory specified */ -+ if (!nousage) -+ usage(); -+ exit(1); -+ } -+ -+ (void)mkdir(dirname, 0777); -+ if (chdir(dirname) < 0) { -+ perror(dirname); -+ exit(1); -+ } -+ sprintf(buf, "fss%x", getpid()); -+ fd = creat(buf, 0666); -+ if (lseek64(fd, (off64_t) (MAXFSIZE32 + 1ULL), SEEK_SET) < 0) -+ maxfsize = (off64_t) MAXFSIZE32; -+ else -+ maxfsize = (off64_t) MAXFSIZE; -+ dcache_init(); -+ setlinebuf(stdout); -+ if (!seed) { -+ gettimeofday(&t, NULL); -+ seed = (int)t.tv_sec ^ (int)t.tv_usec; -+ printf("seed = %ld\n", seed); -+ } -+#ifndef NO_XFS -+ if (!no_xfs) { -+ memset(&geom, 0, sizeof(geom)); -+ i = ioctl(fd, XFS_IOC_FSGEOMETRY, &geom); -+ if (i >= 0 && geom.rtblocks) -+ rtpct = MIN(MAX(geom.rtblocks * 100 / -+ (geom.rtblocks + -+ geom.datablocks), 1), 99); -+ else -+ rtpct = 0; -+ } -+ if (errtag != 0) { -+ if (errrange == 0) { -+ if (errtag <= 0) { -+ srandom(seed); -+ j = random() % 100; -+ -+ for (i = 0; i < j; i++) -+ (void)random(); -+ -+ errtag = -+ (random() % (XFS_ERRTAG_MAX - 1)) + -+ 1; -+ } -+ } else { -+ srandom(seed); -+ j = random() % 100; -+ -+ for (i = 0; i < j; i++) -+ (void)random(); -+ -+ errtag += -+ (random() % (XFS_ERRTAG_MAX - errtag)); -+ } -+ printf("Injecting failure on tag #%d\n", errtag); -+ memset(&err_inj, 0, sizeof(err_inj)); -+ err_inj.errtag = errtag; -+ err_inj.fd = fd; -+ srval = ioctl(fd, XFS_IOC_ERROR_INJECTION, &err_inj); -+ if (srval < -1) { -+ perror -+ ("fsstress - XFS_SYSSGI error injection call"); -+ close(fd); -+ unlink(buf); -+ exit(1); -+ } -+ } else -+#endif -+ close(fd); -+ unlink(buf); -+ -+ -+ if (nproc == 1) { -+ procid = 0; -+ doproc(); -+ } else { -+ setpgid(0, 0); -+ action.sa_handler = sg_handler; -+ sigemptyset(&action.sa_mask); -+ action.sa_flags = 0; -+ if (sigaction(SIGTERM, &action, 0)) { -+ perror("sigaction failed"); -+ exit(1); -+ } -+ -+ for (i = 0; i < nproc; i++) { -+ if (fork() == 0) { -+ -+ action.sa_handler = SIG_DFL; -+ sigemptyset(&action.sa_mask); -+ if (sigaction(SIGTERM, &action, 0)) -+ return 1; -+#ifdef HAVE_SYS_PRCTL_H -+ prctl(PR_SET_PDEATHSIG, SIGKILL); -+ if (getppid() == 1) /* parent died already? */ -+ return 0; -+#endif -+ procid = i; -+ doproc(); -+ return 0; -+ } -+ } -+ while (wait(&stat) > 0 && !should_stop) { -+ continue; -+ } -+ if (should_stop) { -+ action.sa_flags = SA_RESTART; -+ sigaction(SIGTERM, &action, 0); -+ kill(-getpid(), SIGTERM); -+ while (wait(&stat) > 0) -+ continue; -+ } -+ } -+#ifndef NO_XFS -+ if (errtag != 0) { -+ memset(&err_inj, 0, sizeof(err_inj)); -+ err_inj.errtag = 0; -+ err_inj.fd = fd; -+ if ((srval = -+ ioctl(fd, XFS_IOC_ERROR_CLEARALL, -+ &err_inj)) != 0) { -+ fprintf(stderr, "Bad ej clear on %d (%d).\n", -+ fd, errno); -+ perror -+ ("fsstress - XFS_SYSSGI clear error injection call"); -+ close(fd); -+ exit(1); -+ } -+ close(fd); -+ } -+#endif -+ if (cleanup == 0) { -+ sprintf(cmd, "rm -rf %s/*", dirname); -+ system(cmd); -+ for (i = 0; i < FT_nft; i++) { -+ flist[i].nslots = 0; -+ flist[i].nfiles = 0; -+ free(flist[i].fents); -+ flist[i].fents = NULL; -+ } -+ } -+ loopcntr++; -+ } -+ return 0; -+} -+ -+void add_to_flist(int ft, int id, int parent) -+{ -+ fent_t *fep; -+ flist_t *ftp; -+ -+ ftp = &flist[ft]; -+ if (ftp->nfiles == ftp->nslots) { -+ ftp->nslots += FLIST_SLOT_INCR; -+ ftp->fents = realloc(ftp->fents, ftp->nslots * sizeof(fent_t)); -+ } -+ fep = &ftp->fents[ftp->nfiles++]; -+ fep->id = id; -+ fep->parent = parent; -+} -+ -+void append_pathname(pathname_t * name, char *str) -+{ -+ int len; -+ -+ len = strlen(str); -+#ifdef DEBUG -+ if (len && *str == '/' && name->len == 0) { -+ fprintf(stderr, "fsstress: append_pathname failure\n"); -+ chdir(homedir); -+ abort(); -+ -+ } -+#endif -+ name->path = realloc(name->path, name->len + 1 + len); -+ strcpy(&name->path[name->len], str); -+ name->len += len; -+} -+ -+#ifndef NO_XFS -+int -+attr_list_path(pathname_t * name, char *buffer, const int buffersize, int flags, -+ attrlist_cursor_t * cursor) -+{ -+ char buf[MAXNAMELEN]; -+ pathname_t newname; -+ int rval; -+ -+ rval = attr_list(name->path, buffer, buffersize, flags, cursor); -+ if (rval >= 0 || errno != ENAMETOOLONG) -+ return rval; -+ separate_pathname(name, buf, &newname); -+ if (chdir(buf) == 0) { -+ rval = attr_list_path(&newname, buffer, buffersize, flags, -+ cursor); -+ chdir(".."); -+ } -+ free_pathname(&newname); -+ return rval; -+} -+ -+int attr_remove_path(pathname_t * name, const char *attrname, int flags) -+{ -+ char buf[MAXNAMELEN]; -+ pathname_t newname; -+ int rval; -+ -+ rval = attr_remove(name->path, attrname, flags); -+ if (rval >= 0 || errno != ENAMETOOLONG) -+ return rval; -+ separate_pathname(name, buf, &newname); -+ if (chdir(buf) == 0) { -+ rval = attr_remove_path(&newname, attrname, flags); -+ chdir(".."); -+ } -+ free_pathname(&newname); -+ return rval; -+} -+ -+int -+attr_set_path(pathname_t * name, const char *attrname, const char *attrvalue, -+ const int valuelength, int flags) -+{ -+ char buf[MAXNAMELEN]; -+ pathname_t newname; -+ int rval; -+ -+ rval = attr_set(name->path, attrname, attrvalue, valuelength, flags); -+ if (rval >= 0 || errno != ENAMETOOLONG) -+ return rval; -+ separate_pathname(name, buf, &newname); -+ if (chdir(buf) == 0) { -+ rval = attr_set_path(&newname, attrname, attrvalue, valuelength, -+ flags); -+ chdir(".."); -+ } -+ free_pathname(&newname); -+ return rval; -+} -+#endif -+ -+void check_cwd(void) -+{ -+#ifdef DEBUG -+ struct stat64 statbuf; -+ -+ if (stat64(".", &statbuf) == 0 && statbuf.st_ino == top_ino) -+ return; -+ chdir(homedir); -+ fprintf(stderr, "fsstress: check_cwd failure\n"); -+ abort(); -+ -+#endif -+} -+ -+int creat_path(pathname_t * name, mode_t mode) -+{ -+ char buf[MAXNAMELEN]; -+ pathname_t newname; -+ int rval; -+ -+ rval = creat(name->path, mode); -+ if (rval >= 0 || errno != ENAMETOOLONG) -+ return rval; -+ separate_pathname(name, buf, &newname); -+ if (chdir(buf) == 0) { -+ rval = creat_path(&newname, mode); -+ chdir(".."); -+ } -+ free_pathname(&newname); -+ return rval; -+} -+ -+void dcache_enter(int dirid, int slot) -+{ -+ dcache[dirid % NDCACHE] = slot; -+} -+ -+void dcache_init(void) -+{ -+ int i; -+ -+ for (i = 0; i < NDCACHE; i++) -+ dcache[i] = -1; -+} -+ -+fent_t *dcache_lookup(int dirid) -+{ -+ fent_t *fep; -+ int i; -+ -+ i = dcache[dirid % NDCACHE]; -+ if (i >= 0 && (fep = &flist[FT_DIR].fents[i])->id == dirid) -+ return fep; -+ return NULL; -+} -+ -+void dcache_purge(int dirid) -+{ -+ int *dcp; -+ -+ dcp = &dcache[dirid % NDCACHE]; -+ if (*dcp >= 0 && flist[FT_DIR].fents[*dcp].id == dirid) -+ *dcp = -1; -+} -+ -+void del_from_flist(int ft, int slot) -+{ -+ flist_t *ftp; -+ -+ ftp = &flist[ft]; -+ if (ft == FT_DIR) -+ dcache_purge(ftp->fents[slot].id); -+ if (slot != ftp->nfiles - 1) { -+ if (ft == FT_DIR) -+ dcache_purge(ftp->fents[ftp->nfiles - 1].id); -+ ftp->fents[slot] = ftp->fents[--ftp->nfiles]; -+ } else -+ ftp->nfiles--; -+} -+ -+fent_t *dirid_to_fent(int dirid) -+{ -+ fent_t *efep; -+ fent_t *fep; -+ flist_t *flp; -+ -+ if ((fep = dcache_lookup(dirid))) -+ return fep; -+ flp = &flist[FT_DIR]; -+ for (fep = flp->fents, efep = &fep[flp->nfiles]; fep < efep; fep++) { -+ if (fep->id == dirid) { -+ dcache_enter(dirid, fep - flp->fents); -+ return fep; -+ } -+ } -+ return NULL; -+} -+ -+void doproc(void) -+{ -+ struct stat64 statbuf; -+ char buf[10]; -+ int opno; -+ int rval; -+ opdesc_t *p; -+ -+ sprintf(buf, "p%x", procid); -+ (void)mkdir(buf, 0777); -+ if (chdir(buf) < 0 || stat64(".", &statbuf) < 0) { -+ perror(buf); -+ _exit(1); -+ } -+ top_ino = statbuf.st_ino; -+ homedir = getcwd(NULL, -1); -+ seed += procid; -+ srandom(seed); -+ if (namerand) -+ namerand = random(); -+ for (opno = 0; opno < operations; opno++) { -+ p = &ops[freq_table[random() % freq_table_size]]; -+ if ((unsigned long)p->func < 4096) -+ abort(); -+ -+ p->func(opno, random()); -+ /* -+ * test for forced shutdown by stat'ing the test -+ * directory. If this stat returns EIO, assume -+ * the forced shutdown happened. -+ */ -+ if (errtag != 0 && opno % 100 == 0) { -+ rval = stat64(".", &statbuf); -+ if (rval == EIO) { -+ fprintf(stderr, "Detected EIO\n"); -+ return; -+ } -+ } -+ } -+} -+ -+void fent_to_name(pathname_t * name, flist_t * flp, fent_t * fep) -+{ -+ char buf[MAXNAMELEN]; -+ int i; -+ fent_t *pfep; -+ -+ if (fep == NULL) -+ return; -+ if (fep->parent != -1) { -+ pfep = dirid_to_fent(fep->parent); -+ fent_to_name(name, &flist[FT_DIR], pfep); -+ append_pathname(name, "/"); -+ } -+ i = sprintf(buf, "%c%x", flp->tag, fep->id); -+ namerandpad(fep->id, buf, i); -+ append_pathname(name, buf); -+} -+ -+void fix_parent(int oldid, int newid) -+{ -+ fent_t *fep; -+ flist_t *flp; -+ int i; -+ int j; -+ -+ for (i = 0, flp = flist; i < FT_nft; i++, flp++) { -+ for (j = 0, fep = flp->fents; j < flp->nfiles; j++, fep++) { -+ if (fep->parent == oldid) -+ fep->parent = newid; -+ } -+ } -+} -+ -+void free_pathname(pathname_t * name) -+{ -+ if (name->path) { -+ free(name->path); -+ name->path = NULL; -+ name->len = 0; -+ } -+} -+ -+int generate_fname(fent_t * fep, int ft, pathname_t * name, int *idp, int *v) -+{ -+ char buf[MAXNAMELEN]; -+ flist_t *flp; -+ int id; -+ int j; -+ int len; -+ -+ flp = &flist[ft]; -+ len = sprintf(buf, "%c%x", flp->tag, id = nameseq++); -+ namerandpad(id, buf, len); -+ if (fep) { -+ fent_to_name(name, &flist[FT_DIR], fep); -+ append_pathname(name, "/"); -+ } -+ append_pathname(name, buf); -+ *idp = id; -+ *v = verbose; -+ for (j = 0; !*v && j < ilistlen; j++) { -+ if (ilist[j] == id) { -+ *v = 1; -+ break; -+ } -+ } -+ return 1; -+} -+ -+int -+get_fname(int which, long r, pathname_t * name, flist_t ** flpp, fent_t ** fepp, -+ int *v) -+{ -+ int c; -+ fent_t *fep; -+ flist_t *flp; -+ int i; -+ int j; -+ int x; -+ -+ for (i = 0, c = 0, flp = flist; i < FT_nft; i++, flp++) { -+ if (which & (1 << i)) -+ c += flp->nfiles; -+ } -+ if (c == 0) { -+ if (flpp) -+ *flpp = NULL; -+ if (fepp) -+ *fepp = NULL; -+ *v = verbose; -+ return 0; -+ } -+ x = (int)(r % c); -+ for (i = 0, c = 0, flp = flist; i < FT_nft; i++, flp++) { -+ if (which & (1 << i)) { -+ if (x < c + flp->nfiles) { -+ fep = &flp->fents[x - c]; -+ if (name) -+ fent_to_name(name, flp, fep); -+ if (flpp) -+ *flpp = flp; -+ if (fepp) -+ *fepp = fep; -+ *v = verbose; -+ for (j = 0; !*v && j < ilistlen; j++) { -+ if (ilist[j] == fep->id) { -+ *v = 1; -+ break; -+ } -+ } -+ return 1; -+ } -+ c += flp->nfiles; -+ } -+ } -+#ifdef DEBUG -+ fprintf(stderr, "fsstress: get_fname failure\n"); -+ abort(); -+#endif -+ return -1; -+ -+} -+ -+void init_pathname(pathname_t * name) -+{ -+ name->len = 0; -+ name->path = NULL; -+} -+ -+int lchown_path(pathname_t * name, uid_t owner, gid_t group) -+{ -+ char buf[MAXNAMELEN]; -+ pathname_t newname; -+ int rval; -+ -+ rval = lchown(name->path, owner, group); -+ if (rval >= 0 || errno != ENAMETOOLONG) -+ return rval; -+ separate_pathname(name, buf, &newname); -+ if (chdir(buf) == 0) { -+ rval = lchown_path(&newname, owner, group); -+ chdir(".."); -+ } -+ free_pathname(&newname); -+ return rval; -+} -+ -+int link_path(pathname_t * name1, pathname_t * name2) -+{ -+ char buf1[MAXNAMELEN]; -+ char buf2[MAXNAMELEN]; -+ int down1; -+ pathname_t newname1; -+ pathname_t newname2; -+ int rval; -+ -+ rval = link(name1->path, name2->path); -+ if (rval >= 0 || errno != ENAMETOOLONG) -+ return rval; -+ separate_pathname(name1, buf1, &newname1); -+ separate_pathname(name2, buf2, &newname2); -+ if (strcmp(buf1, buf2) == 0) { -+ if (chdir(buf1) == 0) { -+ rval = link_path(&newname1, &newname2); -+ chdir(".."); -+ } -+ } else { -+ if (strcmp(buf1, "..") == 0) -+ down1 = 0; -+ else if (strcmp(buf2, "..") == 0) -+ down1 = 1; -+ else if (strlen(buf1) == 0) -+ down1 = 0; -+ else if (strlen(buf2) == 0) -+ down1 = 1; -+ else -+ down1 = MAX(newname1.len, 3 + name2->len) <= -+ MAX(3 + name1->len, newname2.len); -+ if (down1) { -+ free_pathname(&newname2); -+ append_pathname(&newname2, "../"); -+ append_pathname(&newname2, name2->path); -+ if (chdir(buf1) == 0) { -+ rval = link_path(&newname1, &newname2); -+ chdir(".."); -+ } -+ } else { -+ free_pathname(&newname1); -+ append_pathname(&newname1, "../"); -+ append_pathname(&newname1, name1->path); -+ if (chdir(buf2) == 0) { -+ rval = link_path(&newname1, &newname2); -+ chdir(".."); -+ } -+ } -+ } -+ free_pathname(&newname1); -+ free_pathname(&newname2); -+ return rval; -+} -+ -+int lstat64_path(pathname_t * name, struct stat64 *sbuf) -+{ -+ char buf[MAXNAMELEN]; -+ pathname_t newname; -+ int rval; -+ -+ rval = lstat64(name->path, sbuf); -+ if (rval >= 0 || errno != ENAMETOOLONG) -+ return rval; -+ separate_pathname(name, buf, &newname); -+ if (chdir(buf) == 0) { -+ rval = lstat64_path(&newname, sbuf); -+ chdir(".."); -+ } -+ free_pathname(&newname); -+ return rval; -+} -+ -+void make_freq_table(void) -+{ -+ int f; -+ int i; -+ opdesc_t *p; -+ -+ for (p = ops, f = 0; p < ops_end; p++) -+ f += p->freq; -+ freq_table = malloc(f * sizeof(*freq_table)); -+ freq_table_size = f; -+ for (p = ops, i = 0; p < ops_end; p++) { -+ for (f = 0; f < p->freq; f++, i++) -+ freq_table[i] = p->op; -+ } -+} -+ -+int mkdir_path(pathname_t * name, mode_t mode) -+{ -+ char buf[MAXNAMELEN]; -+ pathname_t newname; -+ int rval; -+ -+ rval = mkdir(name->path, mode); -+ if (rval >= 0 || errno != ENAMETOOLONG) -+ return rval; -+ separate_pathname(name, buf, &newname); -+ if (chdir(buf) == 0) { -+ rval = mkdir_path(&newname, mode); -+ chdir(".."); -+ } -+ free_pathname(&newname); -+ return rval; -+} -+ -+int mknod_path(pathname_t * name, mode_t mode, dev_t dev) -+{ -+ char buf[MAXNAMELEN]; -+ pathname_t newname; -+ int rval; -+ -+ rval = mknod(name->path, mode, dev); -+ if (rval >= 0 || errno != ENAMETOOLONG) -+ return rval; -+ separate_pathname(name, buf, &newname); -+ if (chdir(buf) == 0) { -+ rval = mknod_path(&newname, mode, dev); -+ chdir(".."); -+ } -+ free_pathname(&newname); -+ return rval; -+} -+ -+void namerandpad(int id, char *buf, int i) -+{ -+ int bucket; -+ static int buckets[] = { 2, 4, 8, 16, 32, 64, 128, MAXNAMELEN - 1 }; -+ int padlen; -+ int padmod; -+ -+ if (namerand == 0) -+ return; -+ bucket = (id ^ namerand) % (sizeof(buckets) / sizeof(buckets[0])); -+ padmod = buckets[bucket] + 1 - i; -+ if (padmod <= 0) -+ return; -+ padlen = (id ^ namerand) % padmod; -+ if (padlen) { -+ memset(&buf[i], 'X', padlen); -+ buf[i + padlen] = '\0'; -+ } -+} -+ -+int open_path(pathname_t * name, int oflag) -+{ -+ char buf[MAXNAMELEN]; -+ pathname_t newname; -+ int rval; -+ -+ rval = open(name->path, oflag); -+ if (rval >= 0 || errno != ENAMETOOLONG) -+ return rval; -+ separate_pathname(name, buf, &newname); -+ if (chdir(buf) == 0) { -+ rval = open_path(&newname, oflag); -+ chdir(".."); -+ } -+ free_pathname(&newname); -+ return rval; -+} -+ -+DIR *opendir_path(pathname_t * name) -+{ -+ char buf[MAXNAMELEN]; -+ pathname_t newname; -+ DIR *rval; -+ -+ rval = opendir(name->path); -+ if (rval || errno != ENAMETOOLONG) -+ return rval; -+ separate_pathname(name, buf, &newname); -+ if (chdir(buf) == 0) { -+ rval = opendir_path(&newname); -+ chdir(".."); -+ } -+ free_pathname(&newname); -+ return rval; -+} -+ -+void process_freq(char *arg) -+{ -+ opdesc_t *p; -+ char *s; -+ -+ s = strchr(arg, '='); -+ if (s == NULL) { -+ fprintf(stderr, "bad argument '%s'\n", arg); -+ exit(1); -+ } -+ *s++ = '\0'; -+ for (p = ops; p < ops_end; p++) { -+ if (strcmp(arg, p->name) == 0) { -+ p->freq = atoi(s); -+ return; -+ } -+ } -+ fprintf(stderr, "can't find op type %s for -f\n", arg); -+ exit(1); -+} -+ -+int readlink_path(pathname_t * name, char *lbuf, size_t lbufsiz) -+{ -+ char buf[MAXNAMELEN]; -+ pathname_t newname; -+ int rval; -+ -+ rval = readlink(name->path, lbuf, lbufsiz); -+ if (rval >= 0 || errno != ENAMETOOLONG) -+ return rval; -+ separate_pathname(name, buf, &newname); -+ if (chdir(buf) == 0) { -+ rval = readlink_path(&newname, lbuf, lbufsiz); -+ chdir(".."); -+ } -+ free_pathname(&newname); -+ return rval; -+} -+ -+int rename_path(pathname_t * name1, pathname_t * name2) -+{ -+ char buf1[MAXNAMELEN]; -+ char buf2[MAXNAMELEN]; -+ int down1; -+ pathname_t newname1; -+ pathname_t newname2; -+ int rval; -+ -+ rval = rename(name1->path, name2->path); -+ if (rval >= 0 || errno != ENAMETOOLONG) -+ return rval; -+ separate_pathname(name1, buf1, &newname1); -+ separate_pathname(name2, buf2, &newname2); -+ if (strcmp(buf1, buf2) == 0) { -+ if (chdir(buf1) == 0) { -+ rval = rename_path(&newname1, &newname2); -+ chdir(".."); -+ } -+ } else { -+ if (strcmp(buf1, "..") == 0) -+ down1 = 0; -+ else if (strcmp(buf2, "..") == 0) -+ down1 = 1; -+ else if (strlen(buf1) == 0) -+ down1 = 0; -+ else if (strlen(buf2) == 0) -+ down1 = 1; -+ else -+ down1 = MAX(newname1.len, 3 + name2->len) <= -+ MAX(3 + name1->len, newname2.len); -+ if (down1) { -+ free_pathname(&newname2); -+ append_pathname(&newname2, "../"); -+ append_pathname(&newname2, name2->path); -+ if (chdir(buf1) == 0) { -+ rval = rename_path(&newname1, &newname2); -+ chdir(".."); -+ } -+ } else { -+ free_pathname(&newname1); -+ append_pathname(&newname1, "../"); -+ append_pathname(&newname1, name1->path); -+ if (chdir(buf2) == 0) { -+ rval = rename_path(&newname1, &newname2); -+ chdir(".."); -+ } -+ } -+ } -+ free_pathname(&newname1); -+ free_pathname(&newname2); -+ return rval; -+} -+ -+int rmdir_path(pathname_t * name) -+{ -+ char buf[MAXNAMELEN]; -+ pathname_t newname; -+ int rval; -+ -+ rval = rmdir(name->path); -+ if (rval >= 0 || errno != ENAMETOOLONG) -+ return rval; -+ separate_pathname(name, buf, &newname); -+ if (chdir(buf) == 0) { -+ rval = rmdir_path(&newname); -+ chdir(".."); -+ } -+ free_pathname(&newname); -+ return rval; -+} -+ -+void separate_pathname(pathname_t * name, char *buf, pathname_t * newname) -+{ -+ char *slash; -+ -+ init_pathname(newname); -+ slash = strchr(name->path, '/'); -+ if (slash == NULL) { -+ buf[0] = '\0'; -+ return; -+ } -+ *slash = '\0'; -+ strcpy(buf, name->path); -+ *slash = '/'; -+ append_pathname(newname, slash + 1); -+} -+ -+#define WIDTH 80 -+ -+void show_ops(int flag, char *lead_str) -+{ -+ opdesc_t *p; -+ -+ if (flag < 0) { -+ /* print in list form */ -+ int x = WIDTH; -+ -+ for (p = ops; p < ops_end; p++) { -+ if (lead_str != NULL -+ && x + strlen(p->name) >= WIDTH - 5) -+ x = printf("%s%s", (p == ops) ? "" : "\n", -+ lead_str); -+ x += printf("%s ", p->name); -+ } -+ printf("\n"); -+ } else { -+ int f; -+ for (f = 0, p = ops; p < ops_end; p++) -+ f += p->freq; -+ -+ if (f == 0) -+ flag = 1; -+ -+ for (p = ops; p < ops_end; p++) { -+ if (flag != 0 || p->freq > 0) { -+ if (lead_str != NULL) -+ printf("%s", lead_str); -+ printf("%20s %d/%d %s\n", -+ p->name, p->freq, f, -+ (p->iswrite == 0) ? " " : "write op"); -+ } -+ } -+ } -+} -+ -+int stat64_path(pathname_t * name, struct stat64 *sbuf) -+{ -+ char buf[MAXNAMELEN]; -+ pathname_t newname; -+ int rval; -+ -+ rval = stat64(name->path, sbuf); -+ if (rval >= 0 || errno != ENAMETOOLONG) -+ return rval; -+ separate_pathname(name, buf, &newname); -+ if (chdir(buf) == 0) { -+ rval = stat64_path(&newname, sbuf); -+ chdir(".."); -+ } -+ free_pathname(&newname); -+ return rval; -+} -+ -+int symlink_path(const char *name1, pathname_t * name) -+{ -+ char buf[MAXNAMELEN]; -+ pathname_t newname; -+ int rval; -+ -+ if (!strcmp(name1, name->path)) { -+ printf("yikes! %s %s\n", name1, name->path); -+ return 0; -+ } -+ -+ rval = symlink(name1, name->path); -+ if (rval >= 0 || errno != ENAMETOOLONG) -+ return rval; -+ separate_pathname(name, buf, &newname); -+ if (chdir(buf) == 0) { -+ rval = symlink_path(name1, &newname); -+ chdir(".."); -+ } -+ free_pathname(&newname); -+ return rval; -+} -+ -+int truncate64_path(pathname_t * name, off64_t length) -+{ -+ char buf[MAXNAMELEN]; -+ pathname_t newname; -+ int rval; -+ -+ rval = truncate64(name->path, length); -+ if (rval >= 0 || errno != ENAMETOOLONG) -+ return rval; -+ separate_pathname(name, buf, &newname); -+ if (chdir(buf) == 0) { -+ rval = truncate64_path(&newname, length); -+ chdir(".."); -+ } -+ free_pathname(&newname); -+ return rval; -+} -+ -+int unlink_path(pathname_t * name) -+{ -+ char buf[MAXNAMELEN]; -+ pathname_t newname; -+ int rval; -+ -+ rval = unlink(name->path); -+ if (rval >= 0 || errno != ENAMETOOLONG) -+ return rval; -+ separate_pathname(name, buf, &newname); -+ if (chdir(buf) == 0) { -+ rval = unlink_path(&newname); -+ chdir(".."); -+ } -+ free_pathname(&newname); -+ return rval; -+} -+ -+void usage(void) -+{ -+ printf("Usage: %s -H or\n", myprog); -+ printf -+ (" %s [-c][-d dir][-e errtg][-f op_name=freq][-l loops][-n nops]\n", -+ myprog); -+ printf(" [-p nproc][-r len][-s seed][-v][-w][-z][-S]\n"); -+ printf("where\n"); -+ printf -+ (" -c specifies not to remove files(cleanup) after execution\n"); -+ printf -+ (" -d dir specifies the base directory for operations\n"); -+ printf(" -e errtg specifies error injection stuff\n"); -+ printf -+ (" -f op_name=freq changes the frequency of option name to freq\n"); -+ printf(" the valid operation names are:\n"); -+ show_ops(-1, " "); -+ printf -+ (" -l loops specifies the no. of times the testrun should loop.\n"); -+ printf(" *use 0 for infinite (default 1)\n"); -+ printf -+ (" -n nops specifies the no. of operations per process (default 1)\n"); -+ printf -+ (" -p nproc specifies the no. of processes (default 1)\n"); -+ printf(" -r specifies random name padding\n"); -+ printf -+ (" -s seed specifies the seed for the random generator (default random)\n"); -+ printf(" -v specifies verbose mode\n"); -+ printf -+ (" -w zeros frequencies of non-write operations\n"); -+ printf(" -z zeros frequencies of all operations\n"); -+ printf -+ (" -S prints the table of operations (omitting zero frequency)\n"); -+ printf(" -H prints usage and exits\n"); -+ printf -+ (" -X don't do anything XFS specific (default with -DNO_XFS)\n"); -+} -+ -+void write_freq(void) -+{ -+ opdesc_t *p; -+ -+ for (p = ops; p < ops_end; p++) { -+ if (!p->iswrite) -+ p->freq = 0; -+ } -+} -+ -+void zero_freq(void) -+{ -+ opdesc_t *p; -+ -+ for (p = ops; p < ops_end; p++) -+ p->freq = 0; -+} -+ -+#ifndef NO_XFS -+ -+void allocsp_f(int opno, long r) -+{ -+ int e; -+ pathname_t f; -+ int fd; -+ struct xfs_flock64 fl; -+ __s64 lr; -+ __s64 off; -+ struct stat64 stb; -+ int v; -+ -+ init_pathname(&f); -+ if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) { -+ if (v) -+ printf("%d/%d: allocsp - no filename\n", procid, opno); -+ free_pathname(&f); -+ return; -+ } -+ fd = open_path(&f, O_RDWR); -+ e = fd < 0 ? errno : 0; -+ check_cwd(); -+ if (fd < 0) { -+ if (v) -+ printf("%d/%d: allocsp - open %s failed %d\n", -+ procid, opno, f.path, e); -+ free_pathname(&f); -+ return; -+ } -+ if (fstat64(fd, &stb) < 0) { -+ if (v) -+ printf("%d/%d: allocsp - fstat64 %s failed %d\n", -+ procid, opno, f.path, errno); -+ free_pathname(&f); -+ close(fd); -+ return; -+ } -+ lr = ((__s64) random() << 32) + random(); -+ off = lr % MIN(stb.st_size + (1024 * 1024), MAXFSIZE); -+ off %= maxfsize; -+ memset(&fl, 0, sizeof(fl)); -+ fl.l_whence = SEEK_SET; -+ fl.l_start = off; -+ fl.l_len = 0; -+ e = ioctl(fd, XFS_IOC_ALLOCSP64, &fl) < 0 ? errno : 0; -+ if (v) -+ printf("%d/%d: ioctl(XFS_IOC_ALLOCSP64) %s %lld 0 %d\n", -+ procid, opno, f.path, (long long)off, e); -+ free_pathname(&f); -+ close(fd); -+} -+ -+void attr_remove_f(int opno, long r) -+{ -+ attrlist_ent_t *aep; -+ attrlist_t *alist; -+ char *aname; -+ char buf[4096]; -+ attrlist_cursor_t cursor; -+ int e; -+ int ent; -+ pathname_t f; -+ int total; -+ int v; -+ int which; -+ -+ init_pathname(&f); -+ if (!get_fname(FT_ANYm, r, &f, NULL, NULL, &v)) -+ append_pathname(&f, "."); -+ total = 0; -+ memset(&cursor, 0x00, sizeof(cursor)); -+ do { -+ e = attr_list_path(&f, buf, sizeof(buf), ATTR_DONTFOLLOW, -+ &cursor); -+ check_cwd(); -+ if (e) -+ break; -+ alist = (attrlist_t *) buf; -+ total += alist->al_count; -+ } while (alist->al_more); -+ if (total == 0) { -+ if (v) -+ printf("%d/%d: attr_remove - no attrs for %s\n", -+ procid, opno, f.path); -+ free_pathname(&f); -+ return; -+ } -+ which = (int)(random() % total); -+ memset(&cursor, 0x00, sizeof(cursor)); -+ ent = 0; -+ aname = NULL; -+ do { -+ e = attr_list_path(&f, buf, sizeof(buf), ATTR_DONTFOLLOW, -+ &cursor); -+ check_cwd(); -+ if (e) -+ break; -+ alist = (attrlist_t *) buf; -+ if (which < ent + alist->al_count) { -+ aep = (attrlist_ent_t *) -+ & buf[alist->al_offset[which - ent]]; -+ aname = aep->a_name; -+ break; -+ } -+ ent += alist->al_count; -+ } while (alist->al_more); -+ if (aname == NULL) { -+ if (v) -+ printf("%d/%d: attr_remove - name %d not found at %s\n", -+ procid, opno, which, f.path); -+ free_pathname(&f); -+ return; -+ } -+ e = attr_remove_path(&f, aname, ATTR_DONTFOLLOW) < 0 ? errno : 0; -+ check_cwd(); -+ if (v) -+ printf("%d/%d: attr_remove %s %s %d\n", -+ procid, opno, f.path, aname, e); -+ free_pathname(&f); -+} -+ -+void attr_set_f(int opno, long r) -+{ -+ char aname[10]; -+ char *aval; -+ int e; -+ pathname_t f; -+ int len; -+ static int lengths[] = { 10, 100, 1000, 10000 }; -+ int li; -+ int v; -+ -+ init_pathname(&f); -+ if (!get_fname(FT_ANYm, r, &f, NULL, NULL, &v)) -+ append_pathname(&f, "."); -+ sprintf(aname, "a%x", nameseq++); -+ li = (int)(random() % (sizeof(lengths) / sizeof(lengths[0]))); -+ len = (int)(random() % lengths[li]); -+ if (len == 0) -+ len = 1; -+ aval = malloc(len); -+ memset(aval, nameseq & 0xff, len); -+ e = attr_set_path(&f, aname, aval, len, ATTR_DONTFOLLOW) < 0 ? -+ errno : 0; -+ check_cwd(); -+ free(aval); -+ if (v) -+ printf("%d/%d: attr_set %s %s %d\n", procid, opno, f.path, -+ aname, e); -+ free_pathname(&f); -+} -+ -+void bulkstat_f(int opno, long r) -+{ -+ __s32 count; -+ int fd; -+ __u64 last; -+ __s32 nent; -+ xfs_bstat_t *t; -+ __int64_t total; -+ xfs_fsop_bulkreq_t bsr; -+ -+ last = 0; -+ nent = (r % 999) + 2; -+ t = malloc(nent * sizeof(*t)); -+ fd = open(".", O_RDONLY); -+ total = 0; -+ -+ memset(&bsr, 0, sizeof(bsr)); -+ bsr.lastip = &last; -+ bsr.icount = nent; -+ bsr.ubuffer = t; -+ bsr.ocount = &count; -+ -+ while (ioctl(fd, XFS_IOC_FSBULKSTAT, &bsr) == 0 && count > 0) -+ total += count; -+ free(t); -+ if (verbose) -+ printf("%d/%d: bulkstat nent %d total %lld\n", -+ procid, opno, (int)nent, (long long)total); -+ close(fd); -+} -+ -+void bulkstat1_f(int opno, long r) -+{ -+ int e; -+ pathname_t f; -+ int fd; -+ int good; -+ __u64 ino; -+ struct stat64 s; -+ xfs_bstat_t t; -+ int v; -+ xfs_fsop_bulkreq_t bsr; -+ -+ good = random() & 1; -+ if (good) { -+ /* use an inode we know exists */ -+ init_pathname(&f); -+ if (!get_fname(FT_ANYm, r, &f, NULL, NULL, &v)) -+ append_pathname(&f, "."); -+ ino = stat64_path(&f, &s) < 0 ? (ino64_t) r : s.st_ino; -+ check_cwd(); -+ free_pathname(&f); -+ } else { -+ /* -+ * pick a random inode -+ * -+ * note this can generate kernel warning messages -+ * since bulkstat_one will read the disk block that -+ * would contain a given inode even if that disk -+ * block doesn't contain inodes. -+ * -+ * this is detected later, but not until after the -+ * warning is displayed. -+ * -+ * "XFS: device 0x825- bad inode magic/vsn daddr 0x0 #0" -+ * -+ */ -+ ino = (ino64_t) r; -+ v = verbose; -+ } -+ fd = open(".", O_RDONLY); -+ -+ memset(&bsr, 0, sizeof(bsr)); -+ bsr.lastip = &ino; -+ bsr.icount = 1; -+ bsr.ubuffer = &t; -+ bsr.ocount = NULL; -+ -+ e = ioctl(fd, XFS_IOC_FSBULKSTAT_SINGLE, &bsr) < 0 ? errno : 0; -+ if (v) -+ printf("%d/%d: bulkstat1 %s ino %lld %d\n", -+ procid, opno, good ? "real" : "random", -+ (long long)ino, e); -+ close(fd); -+} -+ -+#endif -+ -+void chown_f(int opno, long r) -+{ -+ int e; -+ pathname_t f; -+ int nbits; -+ uid_t u; -+ int v; -+ -+ init_pathname(&f); -+ if (!get_fname(FT_ANYm, r, &f, NULL, NULL, &v)) -+ append_pathname(&f, "."); -+ u = (uid_t) random(); -+ nbits = (int)(random() % 32); -+ u &= (1 << nbits) - 1; -+ e = lchown_path(&f, u, -1) < 0 ? errno : 0; -+ check_cwd(); -+ if (v) -+ printf("%d/%d: chown %s %d %d\n", procid, opno, f.path, u, e); -+ free_pathname(&f); -+} -+ -+void creat_f(int opno, long r) -+{ -+ int e; -+ int e1; -+ int extsize; -+ pathname_t f; -+ int fd; -+ fent_t *fep; -+ int id; -+ int parid; -+ int type; -+ int v; -+ int v1; -+ int esz = 0; -+ -+ if (!get_fname(FT_DIRm, r, NULL, NULL, &fep, &v1)) -+ parid = -1; -+ else -+ parid = fep->id; -+ init_pathname(&f); -+ type = rtpct ? ((random() % 100) > rtpct ? FT_REG : FT_RTF) : FT_REG; -+ if (type == FT_RTF) -+ extsize = (random() % 10) + 1; -+ else -+ extsize = 0; -+ e = generate_fname(fep, type, &f, &id, &v); -+ v |= v1; -+ if (!e) { -+ if (v) { -+ fent_to_name(&f, &flist[FT_DIR], fep); -+ printf("%d/%d: creat - no filename from %s\n", -+ procid, opno, f.path); -+ } -+ free_pathname(&f); -+ return; -+ } -+ fd = creat_path(&f, 0666); -+ e = fd < 0 ? errno : 0; -+ e1 = 0; -+ check_cwd(); -+ esz = 0; -+ if (fd >= 0) { -+#ifndef NO_XFS -+ struct fsxattr a; -+ memset(&a, 0, sizeof(a)); -+ if (extsize && ioctl(fd, XFS_IOC_FSGETXATTR, &a) >= 0) { -+ a.fsx_xflags |= XFS_XFLAG_REALTIME; -+ a.fsx_extsize = -+ geom.rtextsize * geom.blocksize * extsize; -+ if (ioctl(fd, XFS_IOC_FSSETXATTR, &a) < 0) -+ e1 = errno; -+ esz = a.fsx_extsize; -+ -+ } -+#endif -+ add_to_flist(type, id, parid); -+ close(fd); -+ } -+ if (v) -+ printf("%d/%d: creat %s x:%d %d %d\n", procid, opno, f.path, -+ esz, e, e1); -+ free_pathname(&f); -+} -+ -+int setdirect(int fd) -+{ -+ static int no_direct; -+ int flags; -+ -+ if (no_direct) -+ return 0; -+ -+ flags = fcntl(fd, F_GETFL, 0); -+ if (flags < 0) -+ return 0; -+ -+ if (fcntl(fd, F_SETFL, flags | O_DIRECT) < 0) { -+ if (no_xfs) { -+ no_direct = 1; -+ return 0; -+ } -+ printf("cannot set O_DIRECT: %s\n", strerror(errno)); -+ return 0; -+ } -+ -+ return 1; -+} -+ -+void dread_f(int opno, long r) -+{ -+ __int64_t align; -+ char *buf = NULL; -+ struct dioattr diob; -+ int e; -+ pathname_t f; -+ int fd; -+ size_t len; -+ __int64_t lr; -+ off64_t off; -+ struct stat64 stb; -+ int v; -+ -+ init_pathname(&f); -+ if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) { -+ if (v) -+ printf("%d/%d: dread - no filename\n", procid, opno); -+ free_pathname(&f); -+ return; -+ } -+ fd = open_path(&f, O_RDONLY); -+ -+ e = fd < 0 ? errno : 0; -+ check_cwd(); -+ if (fd < 0) { -+ if (v) -+ printf("%d/%d: dread - open %s failed %d\n", -+ procid, opno, f.path, e); -+ free_pathname(&f); -+ return; -+ } -+ -+ if (!setdirect(fd)) { -+ close(fd); -+ free_pathname(&f); -+ return; -+ } -+ -+ if (fstat64(fd, &stb) < 0) { -+ if (v) -+ printf("%d/%d: dread - fstat64 %s failed %d\n", -+ procid, opno, f.path, errno); -+ free_pathname(&f); -+ close(fd); -+ return; -+ } -+ if (stb.st_size == 0) { -+ if (v) -+ printf("%d/%d: dread - %s zero size\n", procid, opno, -+ f.path); -+ free_pathname(&f); -+ close(fd); -+ return; -+ } -+ -+ memset(&diob, 0, sizeof(diob)); -+ if (no_xfs) { -+ diob.d_miniosz = stb.st_blksize; -+ diob.d_maxiosz = stb.st_blksize * 256; /* good number ? */ -+ diob.d_mem = stb.st_blksize; -+ } -+#ifndef NO_XFS -+ else if (ioctl(fd, XFS_IOC_DIOINFO, &diob) < 0) { -+ if (v) -+ printf -+ ("%d/%d: dread - ioctl(fd, XFS_IOC_DIOINFO) %s failed %d\n", -+ procid, opno, f.path, errno); -+ free_pathname(&f); -+ close(fd); -+ return; -+ } -+#endif -+ align = (__int64_t) diob.d_miniosz; -+ lr = ((__int64_t) random() << 32) + random(); -+ off = (off64_t) (lr % stb.st_size); -+ off -= (off % align); -+ lseek64(fd, off, SEEK_SET); -+ len = (random() % (getpagesize() * 32)) + 1; -+ len -= (len % align); -+ if (len <= 0) -+ len = align; -+ else if (len > diob.d_maxiosz) -+ len = diob.d_maxiosz; -+ if ((e = posix_memalign((void **)&buf, diob.d_mem, len)) != 0) { -+ fprintf(stderr, "posix_memalign: %s\n", strerror(e)); -+ exit(1); -+ } -+ if (buf == NULL) { -+ fprintf(stderr, "posix_memalign: buf is NULL\n"); -+ exit(1); -+ } -+ e = read(fd, buf, len) < 0 ? errno : 0; -+ free(buf); -+ if (v) -+ printf("%d/%d: dread %s [%lld,%ld] %d\n", -+ procid, opno, f.path, (long long int)off, (long)len, e); -+ free_pathname(&f); -+ close(fd); -+} -+ -+void dwrite_f(int opno, long r) -+{ -+ __int64_t align; -+ char *buf = NULL; -+ struct dioattr diob; -+ int e; -+ pathname_t f; -+ int fd; -+ size_t len; -+ __int64_t lr; -+ off64_t off; -+ struct stat64 stb; -+ int v; -+ -+ init_pathname(&f); -+ if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) { -+ if (v) -+ printf("%d/%d: dwrite - no filename\n", procid, opno); -+ free_pathname(&f); -+ return; -+ } -+ fd = open_path(&f, O_WRONLY); -+ e = fd < 0 ? errno : 0; -+ check_cwd(); -+ if (fd < 0) { -+ if (v) -+ printf("%d/%d: dwrite - open %s failed %d\n", -+ procid, opno, f.path, e); -+ free_pathname(&f); -+ return; -+ } -+ -+ if (!setdirect(fd)) { -+ close(fd); -+ free_pathname(&f); -+ return; -+ } -+ if (fstat64(fd, &stb) < 0) { -+ if (v) -+ printf("%d/%d: dwrite - fstat64 %s failed %d\n", -+ procid, opno, f.path, errno); -+ free_pathname(&f); -+ close(fd); -+ return; -+ } -+ memset(&diob, 0, sizeof(diob)); -+ if (no_xfs) { -+ diob.d_miniosz = stb.st_blksize; -+ diob.d_maxiosz = stb.st_blksize * 256; /* good number ? */ -+ diob.d_mem = stb.st_blksize; -+ } -+#ifndef NO_XFS -+ else if (ioctl(fd, XFS_IOC_DIOINFO, &diob) < 0) { -+ if (v) -+ printf -+ ("%d/%d: dwrite - ioctl(fd, XFS_IOC_DIOINFO) %s failed %d\n", -+ procid, opno, f.path, errno); -+ free_pathname(&f); -+ close(fd); -+ return; -+ } -+#endif -+ align = (__int64_t) diob.d_miniosz; -+ lr = ((__int64_t) random() << 32) + random(); -+ off = (off64_t) (lr % MIN(stb.st_size + (1024 * 1024), MAXFSIZE)); -+ off -= (off % align); -+ lseek64(fd, off, SEEK_SET); -+ len = (random() % (getpagesize() * 32)) + 1; -+ len -= (len % align); -+ if (len <= 0) -+ len = align; -+ else if (len > diob.d_maxiosz) -+ len = diob.d_maxiosz; -+ if ((e = posix_memalign((void **)&buf, diob.d_mem, len)) != 0) { -+ fprintf(stderr, "posix_memalign: %s\n", strerror(e)); -+ exit(1); -+ } -+ if (buf == NULL) { -+ fprintf(stderr, "posix_memalign: buf is NULL\n"); -+ exit(1); -+ } -+ off %= maxfsize; -+ lseek64(fd, off, SEEK_SET); -+ memset(buf, nameseq & 0xff, len); -+ e = write(fd, buf, len) < 0 ? errno : 0; -+ free(buf); -+ if (v) -+ printf("%d/%d: dwrite %s [%lld,%ld] %d\n", -+ procid, opno, f.path, (long long)off, (long int)len, e); -+ free_pathname(&f); -+ close(fd); -+} -+ -+void fdatasync_f(int opno, long r) -+{ -+ int e; -+ pathname_t f; -+ int fd; -+ int v; -+ -+ init_pathname(&f); -+ if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) { -+ if (v) -+ printf("%d/%d: fdatasync - no filename\n", -+ procid, opno); -+ free_pathname(&f); -+ return; -+ } -+ fd = open_path(&f, O_WRONLY); -+ e = fd < 0 ? errno : 0; -+ check_cwd(); -+ if (fd < 0) { -+ if (v) -+ printf("%d/%d: fdatasync - open %s failed %d\n", -+ procid, opno, f.path, e); -+ free_pathname(&f); -+ return; -+ } -+ e = fdatasync(fd) < 0 ? errno : 0; -+ if (v) -+ printf("%d/%d: fdatasync %s %d\n", procid, opno, f.path, e); -+ free_pathname(&f); -+ close(fd); -+} -+ -+#ifndef NO_XFS -+void freesp_f(int opno, long r) -+{ -+ int e; -+ pathname_t f; -+ int fd; -+ struct xfs_flock64 fl; -+ __s64 lr; -+ __s64 off; -+ struct stat64 stb; -+ int v; -+ -+ init_pathname(&f); -+ if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) { -+ if (v) -+ printf("%d/%d: freesp - no filename\n", procid, opno); -+ free_pathname(&f); -+ return; -+ } -+ fd = open_path(&f, O_RDWR); -+ e = fd < 0 ? errno : 0; -+ check_cwd(); -+ if (fd < 0) { -+ if (v) -+ printf("%d/%d: freesp - open %s failed %d\n", -+ procid, opno, f.path, e); -+ free_pathname(&f); -+ return; -+ } -+ if (fstat64(fd, &stb) < 0) { -+ if (v) -+ printf("%d/%d: freesp - fstat64 %s failed %d\n", -+ procid, opno, f.path, errno); -+ free_pathname(&f); -+ close(fd); -+ return; -+ } -+ lr = ((__s64) random() << 32) + random(); -+ off = lr % MIN(stb.st_size + (1024 * 1024), MAXFSIZE); -+ off %= maxfsize; -+ memset(&fl, 0, sizeof(fl)); -+ fl.l_whence = SEEK_SET; -+ fl.l_start = off; -+ fl.l_len = 0; -+ e = ioctl(fd, XFS_IOC_FREESP64, &fl) < 0 ? errno : 0; -+ if (v) -+ printf("%d/%d: ioctl(XFS_IOC_FREESP64) %s %lld 0 %d\n", -+ procid, opno, f.path, (long long)off, e); -+ free_pathname(&f); -+ close(fd); -+} -+ -+#endif -+ -+void fsync_f(int opno, long r) -+{ -+ int e; -+ pathname_t f; -+ int fd; -+ int v; -+ -+ init_pathname(&f); -+ if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) { -+ if (v) -+ printf("%d/%d: fsync - no filename\n", procid, opno); -+ free_pathname(&f); -+ return; -+ } -+ fd = open_path(&f, O_WRONLY); -+ e = fd < 0 ? errno : 0; -+ check_cwd(); -+ if (fd < 0) { -+ if (v) -+ printf("%d/%d: fsync - open %s failed %d\n", -+ procid, opno, f.path, e); -+ free_pathname(&f); -+ return; -+ } -+ e = fsync(fd) < 0 ? errno : 0; -+ if (v) -+ printf("%d/%d: fsync %s %d\n", procid, opno, f.path, e); -+ free_pathname(&f); -+ close(fd); -+} -+ -+void getdents_f(int opno, long r) -+{ -+ DIR *dir; -+ pathname_t f; -+ int v; -+ -+ init_pathname(&f); -+ if (!get_fname(FT_DIRm, r, &f, NULL, NULL, &v)) -+ append_pathname(&f, "."); -+ dir = opendir_path(&f); -+ check_cwd(); -+ if (dir == NULL) { -+ if (v) -+ printf("%d/%d: getdents - can't open %s\n", -+ procid, opno, f.path); -+ free_pathname(&f); -+ return; -+ } -+ while (readdir64(dir) != NULL) -+ continue; -+ if (v) -+ printf("%d/%d: getdents %s 0\n", procid, opno, f.path); -+ free_pathname(&f); -+ closedir(dir); -+} -+ -+void link_f(int opno, long r) -+{ -+ int e; -+ pathname_t f; -+ fent_t *fep; -+ flist_t *flp; -+ int id; -+ pathname_t l; -+ int parid; -+ int v; -+ int v1; -+ -+ init_pathname(&f); -+ if (!get_fname(FT_NOTDIR, r, &f, &flp, NULL, &v1)) { -+ if (v1) -+ printf("%d/%d: link - no file\n", procid, opno); -+ free_pathname(&f); -+ return; -+ } -+ if (!get_fname(FT_DIRm, random(), NULL, NULL, &fep, &v)) -+ parid = -1; -+ else -+ parid = fep->id; -+ v |= v1; -+ init_pathname(&l); -+ e = generate_fname(fep, flp - flist, &l, &id, &v1); -+ v |= v1; -+ if (!e) { -+ if (v) { -+ fent_to_name(&l, &flist[FT_DIR], fep); -+ printf("%d/%d: link - no filename from %s\n", -+ procid, opno, l.path); -+ } -+ free_pathname(&l); -+ free_pathname(&f); -+ return; -+ } -+ e = link_path(&f, &l) < 0 ? errno : 0; -+ check_cwd(); -+ if (e == 0) -+ add_to_flist(flp - flist, id, parid); -+ if (v) -+ printf("%d/%d: link %s %s %d\n", procid, opno, f.path, l.path, -+ e); -+ free_pathname(&l); -+ free_pathname(&f); -+} -+ -+void mkdir_f(int opno, long r) -+{ -+ int e; -+ pathname_t f; -+ fent_t *fep; -+ int id; -+ int parid; -+ int v; -+ int v1; -+ -+ if (!get_fname(FT_DIRm, r, NULL, NULL, &fep, &v)) -+ parid = -1; -+ else -+ parid = fep->id; -+ init_pathname(&f); -+ e = generate_fname(fep, FT_DIR, &f, &id, &v1); -+ v |= v1; -+ if (!e) { -+ if (v) { -+ fent_to_name(&f, &flist[FT_DIR], fep); -+ printf("%d/%d: mkdir - no filename from %s\n", -+ procid, opno, f.path); -+ } -+ free_pathname(&f); -+ return; -+ } -+ e = mkdir_path(&f, 0777) < 0 ? errno : 0; -+ check_cwd(); -+ if (e == 0) -+ add_to_flist(FT_DIR, id, parid); -+ if (v) -+ printf("%d/%d: mkdir %s %d\n", procid, opno, f.path, e); -+ free_pathname(&f); -+} -+ -+void mknod_f(int opno, long r) -+{ -+ int e; -+ pathname_t f; -+ fent_t *fep; -+ int id; -+ int parid; -+ int v; -+ int v1; -+ -+ if (!get_fname(FT_DIRm, r, NULL, NULL, &fep, &v)) -+ parid = -1; -+ else -+ parid = fep->id; -+ init_pathname(&f); -+ e = generate_fname(fep, FT_DEV, &f, &id, &v1); -+ v |= v1; -+ if (!e) { -+ if (v) { -+ fent_to_name(&f, &flist[FT_DIR], fep); -+ printf("%d/%d: mknod - no filename from %s\n", -+ procid, opno, f.path); -+ } -+ free_pathname(&f); -+ return; -+ } -+ e = mknod_path(&f, S_IFCHR | 0444, 0) < 0 ? errno : 0; -+ check_cwd(); -+ if (e == 0) -+ add_to_flist(FT_DEV, id, parid); -+ if (v) -+ printf("%d/%d: mknod %s %d\n", procid, opno, f.path, e); -+ free_pathname(&f); -+} -+ -+void read_f(int opno, long r) -+{ -+ char *buf; -+ int e; -+ pathname_t f; -+ int fd; -+ size_t len; -+ __int64_t lr; -+ off64_t off; -+ struct stat64 stb; -+ int v; -+ -+ init_pathname(&f); -+ if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) { -+ if (v) -+ printf("%d/%d: read - no filename\n", procid, opno); -+ free_pathname(&f); -+ return; -+ } -+ fd = open_path(&f, O_RDONLY); -+ e = fd < 0 ? errno : 0; -+ check_cwd(); -+ if (fd < 0) { -+ if (v) -+ printf("%d/%d: read - open %s failed %d\n", -+ procid, opno, f.path, e); -+ free_pathname(&f); -+ return; -+ } -+ if (fstat64(fd, &stb) < 0) { -+ if (v) -+ printf("%d/%d: read - fstat64 %s failed %d\n", -+ procid, opno, f.path, errno); -+ free_pathname(&f); -+ close(fd); -+ return; -+ } -+ if (stb.st_size == 0) { -+ if (v) -+ printf("%d/%d: read - %s zero size\n", procid, opno, -+ f.path); -+ free_pathname(&f); -+ close(fd); -+ return; -+ } -+ lr = ((__int64_t) random() << 32) + random(); -+ off = (off64_t) (lr % stb.st_size); -+ lseek64(fd, off, SEEK_SET); -+ len = (random() % (getpagesize() * 32)) + 1; -+ buf = malloc(len); -+ e = read(fd, buf, len) < 0 ? errno : 0; -+ free(buf); -+ if (v) -+ printf("%d/%d: read %s [%lld,%ld] %d\n", -+ procid, opno, f.path, (long long)off, (long int)len, e); -+ free_pathname(&f); -+ close(fd); -+} -+ -+void readlink_f(int opno, long r) -+{ -+ char buf[PATH_MAX]; -+ int e; -+ pathname_t f; -+ int v; -+ -+ init_pathname(&f); -+ if (!get_fname(FT_SYMm, r, &f, NULL, NULL, &v)) { -+ if (v) -+ printf("%d/%d: readlink - no filename\n", procid, opno); -+ free_pathname(&f); -+ return; -+ } -+ e = readlink_path(&f, buf, PATH_MAX) < 0 ? errno : 0; -+ check_cwd(); -+ if (v) -+ printf("%d/%d: readlink %s %d\n", procid, opno, f.path, e); -+ free_pathname(&f); -+} -+ -+void rename_f(int opno, long r) -+{ -+ fent_t *dfep; -+ int e; -+ pathname_t f; -+ fent_t *fep; -+ flist_t *flp; -+ int id; -+ pathname_t newf; -+ int oldid; -+ int parid; -+ int v; -+ int v1; -+ -+ init_pathname(&f); -+ if (!get_fname(FT_ANYm, r, &f, &flp, &fep, &v1)) { -+ if (v1) -+ printf("%d/%d: rename - no filename\n", procid, opno); -+ free_pathname(&f); -+ return; -+ } -+ if (!get_fname(FT_DIRm, random(), NULL, NULL, &dfep, &v)) -+ parid = -1; -+ else -+ parid = dfep->id; -+ v |= v1; -+ init_pathname(&newf); -+ e = generate_fname(dfep, flp - flist, &newf, &id, &v1); -+ v |= v1; -+ if (!e) { -+ if (v) { -+ fent_to_name(&f, &flist[FT_DIR], dfep); -+ printf("%d/%d: rename - no filename from %s\n", -+ procid, opno, f.path); -+ } -+ free_pathname(&newf); -+ free_pathname(&f); -+ return; -+ } -+ e = rename_path(&f, &newf) < 0 ? errno : 0; -+ check_cwd(); -+ if (e == 0) { -+ if (flp - flist == FT_DIR) { -+ oldid = fep->id; -+ fix_parent(oldid, id); -+ } -+ del_from_flist(flp - flist, fep - flp->fents); -+ add_to_flist(flp - flist, id, parid); -+ } -+ if (v) -+ printf("%d/%d: rename %s to %s %d\n", procid, opno, f.path, -+ newf.path, e); -+ free_pathname(&newf); -+ free_pathname(&f); -+} -+ -+#ifndef NO_XFS -+void resvsp_f(int opno, long r) -+{ -+ int e; -+ pathname_t f; -+ int fd; -+ struct xfs_flock64 fl; -+ __s64 lr; -+ __s64 off; -+ struct stat64 stb; -+ int v; -+ -+ init_pathname(&f); -+ if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) { -+ if (v) -+ printf("%d/%d: resvsp - no filename\n", procid, opno); -+ free_pathname(&f); -+ return; -+ } -+ fd = open_path(&f, O_RDWR); -+ e = fd < 0 ? errno : 0; -+ check_cwd(); -+ if (fd < 0) { -+ if (v) -+ printf("%d/%d: resvsp - open %s failed %d\n", -+ procid, opno, f.path, e); -+ free_pathname(&f); -+ return; -+ } -+ if (fstat64(fd, &stb) < 0) { -+ if (v) -+ printf("%d/%d: resvsp - fstat64 %s failed %d\n", -+ procid, opno, f.path, errno); -+ free_pathname(&f); -+ close(fd); -+ return; -+ } -+ lr = ((__s64) random() << 32) + random(); -+ off = lr % MIN(stb.st_size + (1024 * 1024), MAXFSIZE); -+ off %= maxfsize; -+ memset(&fl, 0, sizeof(fl)); -+ fl.l_whence = SEEK_SET; -+ fl.l_start = off; -+ fl.l_len = (__s64) (random() % (1024 * 1024)); -+ e = ioctl(fd, XFS_IOC_RESVSP64, &fl) < 0 ? errno : 0; -+ if (v) -+ printf("%d/%d: ioctl(XFS_IOC_RESVSP64) %s %lld %lld %d\n", -+ procid, opno, f.path, (long long)off, -+ (long long)fl.l_len, e); -+ free_pathname(&f); -+ close(fd); -+} -+#endif -+ -+void rmdir_f(int opno, long r) -+{ -+ int e; -+ pathname_t f; -+ fent_t *fep; -+ int v; -+ -+ init_pathname(&f); -+ if (!get_fname(FT_DIRm, r, &f, NULL, &fep, &v)) { -+ if (v) -+ printf("%d/%d: rmdir - no directory\n", procid, opno); -+ free_pathname(&f); -+ return; -+ } -+ e = rmdir_path(&f) < 0 ? errno : 0; -+ check_cwd(); -+ if (e == 0) -+ del_from_flist(FT_DIR, fep - flist[FT_DIR].fents); -+ if (v) -+ printf("%d/%d: rmdir %s %d\n", procid, opno, f.path, e); -+ free_pathname(&f); -+} -+ -+void stat_f(int opno, long r) -+{ -+ int e; -+ pathname_t f; -+ struct stat64 stb; -+ int v; -+ -+ init_pathname(&f); -+ if (!get_fname(FT_ANYm, r, &f, NULL, NULL, &v)) { -+ if (v) -+ printf("%d/%d: stat - no entries\n", procid, opno); -+ free_pathname(&f); -+ return; -+ } -+ e = lstat64_path(&f, &stb) < 0 ? errno : 0; -+ check_cwd(); -+ if (v) -+ printf("%d/%d: stat %s %d\n", procid, opno, f.path, e); -+ free_pathname(&f); -+} -+ -+void symlink_f(int opno, long r) -+{ -+ int e; -+ pathname_t f; -+ fent_t *fep; -+ int i; -+ int id; -+ int len; -+ int parid; -+ int v; -+ int v1; -+ char *val; -+ -+ if (!get_fname(FT_DIRm, r, NULL, NULL, &fep, &v)) -+ parid = -1; -+ else -+ parid = fep->id; -+ init_pathname(&f); -+ e = generate_fname(fep, FT_SYM, &f, &id, &v1); -+ v |= v1; -+ if (!e) { -+ if (v) { -+ fent_to_name(&f, &flist[FT_DIR], fep); -+ printf("%d/%d: symlink - no filename from %s\n", -+ procid, opno, f.path); -+ } -+ free_pathname(&f); -+ return; -+ } -+ len = (int)(random() % PATH_MAX); -+ val = malloc(len + 1); -+ if (len) -+ memset(val, 'x', len); -+ val[len] = '\0'; -+ for (i = 10; i < len - 1; i += 10) -+ val[i] = '/'; -+ e = symlink_path(val, &f) < 0 ? errno : 0; -+ check_cwd(); -+ if (e == 0) -+ add_to_flist(FT_SYM, id, parid); -+ free(val); -+ if (v) -+ printf("%d/%d: symlink %s %d\n", procid, opno, f.path, e); -+ free_pathname(&f); -+} -+ -+/* ARGSUSED */ -+void sync_f(int opno, long r) -+{ -+ sync(); -+ if (verbose) -+ printf("%d/%d: sync\n", procid, opno); -+} -+ -+void truncate_f(int opno, long r) -+{ -+ int e; -+ pathname_t f; -+ __int64_t lr; -+ off64_t off; -+ struct stat64 stb; -+ int v; -+ -+ init_pathname(&f); -+ if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) { -+ if (v) -+ printf("%d/%d: truncate - no filename\n", procid, opno); -+ free_pathname(&f); -+ return; -+ } -+ e = stat64_path(&f, &stb) < 0 ? errno : 0; -+ check_cwd(); -+ if (e > 0) { -+ if (v) -+ printf("%d/%d: truncate - stat64 %s failed %d\n", -+ procid, opno, f.path, e); -+ free_pathname(&f); -+ return; -+ } -+ lr = ((__int64_t) random() << 32) + random(); -+ off = lr % MIN(stb.st_size + (1024 * 1024), MAXFSIZE); -+ off %= maxfsize; -+ e = truncate64_path(&f, off) < 0 ? errno : 0; -+ check_cwd(); -+ if (v) -+ printf("%d/%d: truncate %s %lld %d\n", procid, opno, f.path, -+ (long long)off, e); -+ free_pathname(&f); -+} -+ -+void unlink_f(int opno, long r) -+{ -+ int e; -+ pathname_t f; -+ fent_t *fep; -+ flist_t *flp; -+ int v; -+ -+ init_pathname(&f); -+ if (!get_fname(FT_NOTDIR, r, &f, &flp, &fep, &v)) { -+ if (v) -+ printf("%d/%d: unlink - no file\n", procid, opno); -+ free_pathname(&f); -+ return; -+ } -+ e = unlink_path(&f) < 0 ? errno : 0; -+ check_cwd(); -+ if (e == 0) -+ del_from_flist(flp - flist, fep - flp->fents); -+ if (v) -+ printf("%d/%d: unlink %s %d\n", procid, opno, f.path, e); -+ free_pathname(&f); -+} -+ -+#ifndef NO_XFS -+void unresvsp_f(int opno, long r) -+{ -+ int e; -+ pathname_t f; -+ int fd; -+ struct xfs_flock64 fl; -+ __s64 lr; -+ __s64 off; -+ struct stat64 stb; -+ int v; -+ -+ init_pathname(&f); -+ if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) { -+ if (v) -+ printf("%d/%d: unresvsp - no filename\n", procid, opno); -+ free_pathname(&f); -+ return; -+ } -+ fd = open_path(&f, O_RDWR); -+ e = fd < 0 ? errno : 0; -+ check_cwd(); -+ if (fd < 0) { -+ if (v) -+ printf("%d/%d: unresvsp - open %s failed %d\n", -+ procid, opno, f.path, e); -+ free_pathname(&f); -+ return; -+ } -+ if (fstat64(fd, &stb) < 0) { -+ if (v) -+ printf("%d/%d: unresvsp - fstat64 %s failed %d\n", -+ procid, opno, f.path, errno); -+ free_pathname(&f); -+ close(fd); -+ return; -+ } -+ lr = ((__s64) random() << 32) + random(); -+ off = lr % MIN(stb.st_size + (1024 * 1024), MAXFSIZE); -+ off %= maxfsize; -+ memset(&fl, 0, sizeof(fl)); -+ fl.l_whence = SEEK_SET; -+ fl.l_start = off; -+ fl.l_len = (__s64) (random() % (1 << 20)); -+ e = ioctl(fd, XFS_IOC_UNRESVSP64, &fl) < 0 ? errno : 0; -+ if (v) -+ printf("%d/%d: ioctl(XFS_IOC_UNRESVSP64) %s %lld %lld %d\n", -+ procid, opno, f.path, (long long)off, -+ (long long)fl.l_len, e); -+ free_pathname(&f); -+ close(fd); -+} -+#endif -+ -+void write_f(int opno, long r) -+{ -+ char *buf; -+ int e; -+ pathname_t f; -+ int fd; -+ size_t len; -+ __int64_t lr; -+ off64_t off; -+ struct stat64 stb; -+ int v; -+ -+ init_pathname(&f); -+ if (!get_fname(FT_REGm, r, &f, NULL, NULL, &v)) { -+ if (v) -+ printf("%d/%d: write - no filename\n", procid, opno); -+ free_pathname(&f); -+ return; -+ } -+ fd = open_path(&f, O_WRONLY); -+ e = fd < 0 ? errno : 0; -+ check_cwd(); -+ if (fd < 0) { -+ if (v) -+ printf("%d/%d: write - open %s failed %d\n", -+ procid, opno, f.path, e); -+ free_pathname(&f); -+ return; -+ } -+ if (fstat64(fd, &stb) < 0) { -+ if (v) -+ printf("%d/%d: write - fstat64 %s failed %d\n", -+ procid, opno, f.path, errno); -+ free_pathname(&f); -+ close(fd); -+ return; -+ } -+ lr = ((__int64_t) random() << 32) + random(); -+ off = (off64_t) (lr % MIN(stb.st_size + (1024 * 1024), MAXFSIZE)); -+ off %= maxfsize; -+ lseek64(fd, off, SEEK_SET); -+ len = (random() % (getpagesize() * 32)) + 1; -+ buf = malloc(len); -+ memset(buf, nameseq & 0xff, len); -+ e = write(fd, buf, len) < 0 ? errno : 0; -+ free(buf); -+ if (v) -+ printf("%d/%d: write %s [%lld,%ld] %d\n", -+ procid, opno, f.path, (long long)off, (long int)len, e); -+ free_pathname(&f); -+ close(fd); -+} -diff --git a/contrib/jbd2-resync.sh b/contrib/jbd2-resync.sh -new file mode 100755 -index 0000000..4133b63 ---- /dev/null -+++ b/contrib/jbd2-resync.sh -@@ -0,0 +1,19 @@ -+#!/bin/bash -+ -+if [ -z "$1" -o -z "$2" ]; then -+ echo "Usage: $0 kernel-file e2fsprogs-file" -+ exit 0 -+fi -+ -+# Transform a few things to fit the compatibility things defined in jfs_user.h. -+# Use the ext2fs_ endian conversion functions because they truncate oversized -+# inputs (e.g. passing a u32 to cpu_to_be16()) like the kernel versions and -+# unlike the libc6 versions. -+exec sed -e 's/JBD_/JFS_/g' \ -+ -e 's/JBD2_/JFS_/g' \ -+ -e 's/jbd2_journal_/journal_/g' \ -+ -e 's/__be/__u/g' \ -+ -e 's/struct kmem_cache/lkmem_cache_t/g' \ -+ -e 's/cpu_to_be/ext2fs_cpu_to_be/g' \ -+ -e 's/be\([0-9][0-9]\)_to_cpu/ext2fs_be\1_to_cpu/g' \ -+ < "$1" > "$2" -diff --git a/contrib/make-sparse.c b/contrib/make-sparse.c -index 1b3d550..98b86b0 100644 ---- a/contrib/make-sparse.c -+++ b/contrib/make-sparse.c -@@ -9,8 +9,12 @@ - * %End-Header% - */ - -+#ifndef _LARGEFILE_SOURCE - #define _LARGEFILE_SOURCE -+#endif -+#ifndef _LARGEFILE64_SOURCE - #define _LARGEFILE64_SOURCE -+#endif - - #include - #include -diff --git a/debian/changelog b/debian/changelog -index 9506939..054b150 100644 ---- a/debian/changelog -+++ b/debian/changelog -@@ -1,3 +1,18 @@ -+e2fsprogs (1.43~WIP-2015-05-18-1) unstable; urgency=low -+ -+ * Merge in updates from the maint branch (changes from 1.42.13) -+ * Add support for file encryption feature -+ * Mke2fs will now create file systems with metadata_csum and 64bit -+ enabled by default. -+ * The resize2fs command can now convert file systems between 64-bit -+ and 32-bit mode. -+ * The new undo file format is much faster/efficent than before -+ * E2fsck now has readahead support to speed up its behavior on RAID -+ arrays. -+ * E2fsck can now rebuild/optimize inode extent trees -+ -+ -- Theodore Y. Ts'o Mon, 18 May 2015 01:47:43 -0400 -+ - e2fsprogs (1.42.13-1) unstable; urgency=low - - * New upstream version -@@ -31,6 +46,16 @@ e2fsprogs (1.42.13-1) unstable; urgency=low - - -- Theodore Y. Ts'o Sun, 17 May 2015 20:38:27 -0400 - -+e2fsprogs (1.43~WIP-2015-03-29-1) unstable; urgency=low -+ -+ * Merge in updates from the maint branch (changes from 1.42.12-1) -+ * Add support for inline directories -+ * Add support for the jbd2 checksum v3 format -+ * New dumpe2fs format -+ * Add support for file encryption feature -+ -+ -- Theodore Y. Ts'o Sun, 14 Dec 2014 22:49:03 -0500 -+ - e2fsprogs (1.42.12-1.1) unstable; urgency=high - - * Non-maintainer upload by the Security Team. -@@ -138,6 +163,12 @@ e2fsprogs (1.42.10-1.1) unstable; urgency=medium - - -- Hilko Bengen Sat, 21 Jun 2014 12:57:25 +0200 - -+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 Wed, 04 Feb 2014 23:31:56 -0500 -+ - e2fsprogs (1.42.10-1) unstable; urgency=medium - - * New upstream version -@@ -360,6 +391,12 @@ e2fsprogs (1.42.7-1) unstable; urgency=low - - -- Theodore Y. Ts'o 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 Sat, 22 Sep 2012 21:50:20 -0400 -+ - e2fsprogs (1.42.6-1) unstable; urgency=low - - * New upstream version -diff --git a/debian/control.in b/debian/control.in -index 7624029..05929ac 100644 ---- a/debian/control.in -+++ b/debian/control.in -@@ -66,7 +66,7 @@ Description: command-line interface parsing library - libss provides a simple command-line interface parser which will - accept input from the user, parse the command into an argv argument - vector, and then dispatch it to a handler function. -- . -+ . - It was originally inspired by the Multics SubSystem library. - - Package: ss-dev -@@ -78,7 +78,7 @@ Description: command-line interface parsing library - headers and static librari - This package includes a tool that parses a command table to generate - a simple command-line interface parser, the include files needed to - compile and use it, and the static libs. -- . -+ . - It was originally inspired by the Multics SubSystem library. - . - This package contains the development environment for the ss library. -diff --git a/debian/e2fslibs.symbols b/debian/e2fslibs.symbols -index c8a5fb6..646b813 100644 ---- a/debian/e2fslibs.symbols -+++ b/debian/e2fslibs.symbols -@@ -2,6 +2,7 @@ libe2p.so.2 e2fslibs #MINVER# - e2p_edit_feature2@Base 1.40.7 - e2p_edit_feature@Base 1.37 - e2p_edit_mntopts@Base 1.37 -+ e2p_encmode2string@Base 1.43~WIP-2015-05-18 - e2p_feature2string@Base 1.37 - e2p_hash2string@Base 1.37 - e2p_is_null_uuid@Base 1.37 -@@ -10,6 +11,7 @@ libe2p.so.2 e2fslibs #MINVER# - e2p_mntopt2string@Base 1.37 - e2p_os2string@Base 1.37 - e2p_percent@Base 1.40 -+ e2p_string2encmode@Base 1.43~WIP-2015-05-18 - e2p_string2feature@Base 1.37 - e2p_string2hash@Base 1.37 - e2p_string2mntopt@Base 1.37 -@@ -43,14 +45,17 @@ libext2fs.so.2 e2fslibs #MINVER# - et_ext2_error_table@Base 1.37 - ext2fs_add_dir_block2@Base 1.42 - ext2fs_add_dir_block@Base 1.37 -+ ext2fs_add_exit_fn@Base 1.43~WIP-2015-05-18 - ext2fs_add_journal_device@Base 1.37 - 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 - ext2fs_alloc_generic_bmap@Base 1.42 -+ ext2fs_alloc_range@Base 1.43~WIP-2015-05-18 - ext2fs_allocate_block_bitmap@Base 1.37 - ext2fs_allocate_generic_bitmap@Base 1.37 - ext2fs_allocate_group_table@Base 1.37 -@@ -89,6 +94,9 @@ libext2fs.so.2 e2fslibs #MINVER# - ext2fs_block_alloc_stats2@Base 1.42 - ext2fs_block_alloc_stats@Base 1.37 - ext2fs_block_alloc_stats_range@Base 1.42.9-3~ -+ ext2fs_block_bitmap_checksum@Base 1.43~WIP-2012-08-01 -+ ext2fs_block_bitmap_csum_set@Base 1.43~WIP-2012-08-01 -+ ext2fs_block_bitmap_csum_verify@Base 1.43~WIP-2012-08-01 - ext2fs_block_bitmap_loc@Base 1.42 - ext2fs_block_bitmap_loc_set@Base 1.42 - ext2fs_block_iterate2@Base 1.37 -@@ -123,11 +131,12 @@ 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 - ext2fs_crc32c_le@Base 1.42 - ext2fs_create_icount2@Base 1.37 - ext2fs_create_icount@Base 1.37 - ext2fs_create_icount_tdb@Base 1.40 -+ ext2fs_create_inode_cache@Base 1.43~WIP-2015-05-18 - ext2fs_create_journal_superblock@Base 1.37 - ext2fs_create_resize_inode@Base 1.37 - ext2fs_dblist_count2@Base 1.42 -@@ -137,20 +146,33 @@ libext2fs.so.2 e2fslibs #MINVER# - ext2fs_dblist_get_last2@Base 1.42 - ext2fs_dblist_get_last@Base 1.40.8 - ext2fs_dblist_iterate2@Base 1.42 -+ ext2fs_dblist_iterate3@Base 1.43~WIP-2015-05-18 - ext2fs_dblist_iterate@Base 1.37 - ext2fs_dblist_sort2@Base 1.42 - ext2fs_dblist_sort@Base 1.37 - 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_file_type@Base 1.43~WIP-2015-05-18 -+ ext2fs_dirent_has_tail@Base 1.43~WIP-2012-08-01 -+ ext2fs_dirent_name_len@Base 1.43~WIP-2015-05-18 -+ ext2fs_dirent_set_file_type@Base 1.43~WIP-2015-05-18 -+ ext2fs_dirent_set_name_len@Base 1.43~WIP-2015-05-18 - 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 -@@ -214,6 +236,7 @@ libext2fs.so.2 e2fslibs #MINVER# - ext2fs_find_first_zero_generic_bitmap@Base 1.42.3 - ext2fs_find_first_zero_generic_bmap@Base 1.42.2 - ext2fs_find_first_zero_inode_bitmap2@Base 1.42.2 -+ ext2fs_find_inode_goal@Base 1.43~WIP-2015-05-18 - ext2fs_flush2@Base 1.42 - ext2fs_flush@Base 1.37 - ext2fs_flush_icache@Base 1.37 -@@ -224,10 +247,12 @@ libext2fs.so.2 e2fslibs #MINVER# - ext2fs_free_blocks_count_add@Base 1.42 - ext2fs_free_blocks_count_set@Base 1.42 - ext2fs_free_dblist@Base 1.37 -+ ext2fs_free_ext_attr@Base 1.43~WIP-2015-05-18 - ext2fs_free_generic_bitmap@Base 1.37 - ext2fs_free_generic_bmap@Base 1.42 - ext2fs_free_icount@Base 1.37 - ext2fs_free_inode_bitmap@Base 1.37 -+ ext2fs_free_inode_cache@Base 1.43~WIP-2015-05-18 - ext2fs_free_mem@Base 1.37 - ext2fs_fstat@Base 1.42 - ext2fs_fudge_block_bitmap_end2@Base 1.42 -@@ -251,6 +276,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 +327,26 @@ 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_inline_data_dir_iterate@Base 1.43~WIP-2015-05-18 -+ ext2fs_inline_data_ea_remove@Base 1.43~WIP-2015-05-18 -+ ext2fs_inline_data_expand@Base 1.43~WIP-2015-05-18 -+ ext2fs_inline_data_get@Base 1.43~WIP-2015-05-18 -+ ext2fs_inline_data_init@Base 1.43~WIP-2015-05-18 -+ ext2fs_inline_data_set@Base 1.43~WIP-2015-05-18 -+ ext2fs_inline_data_size@Base 1.43~WIP-2015-05-18 - ext2fs_inode_alloc_stats2@Base 1.37 - ext2fs_inode_alloc_stats@Base 1.37 -+ ext2fs_inode_bitmap_checksum@Base 1.43~WIP-2012-08-01 -+ ext2fs_inode_bitmap_csum_set@Base 1.43~WIP-2012-08-01 -+ ext2fs_inode_bitmap_csum_verify@Base 1.43~WIP-2012-08-01 - ext2fs_inode_bitmap_loc@Base 1.42 - ext2fs_inode_bitmap_loc_set@Base 1.42 -+ ext2fs_inode_csum_set@Base 1.43~WIP-2012-08-01 -+ ext2fs_inode_csum_verify@Base 1.43~WIP-2012-08-01 - ext2fs_inode_data_blocks2@Base 1.42 - ext2fs_inode_data_blocks@Base 1.37 - ext2fs_inode_has_valid_blocks2@Base 1.42 -@@ -338,14 +378,18 @@ libext2fs.so.2 e2fslibs #MINVER# - ext2fs_mark_inode_bitmap@Base 1.37 - ext2fs_mark_super_dirty@Base 1.37 - ext2fs_mark_valid@Base 1.37 -+ ext2fs_max_extent_depth@Base 1.43~WIP-2015-05-18 - ext2fs_mem_is_zero@Base 1.42 - ext2fs_mkdir@Base 1.37 - ext2fs_mmp_clear@Base 1.42 -+ ext2fs_mmp_csum_set@Base 1.43~WIP-2012-08-01 -+ ext2fs_mmp_csum_verify@Base 1.43~WIP-2012-08-01 - ext2fs_mmp_init@Base 1.42 - ext2fs_mmp_new_seq@Base 1.42 - ext2fs_mmp_read@Base 1.42 - ext2fs_mmp_start@Base 1.42 - ext2fs_mmp_stop@Base 1.42 -+ ext2fs_mmp_update2@Base 1.43~WIP-2012-08-01 - ext2fs_mmp_update@Base 1.42 - ext2fs_mmp_write@Base 1.42 - ext2fs_namei@Base 1.37 -@@ -354,9 +398,12 @@ libext2fs.so.2 e2fslibs #MINVER# - ext2fs_new_block2@Base 1.42 - ext2fs_new_block@Base 1.37 - ext2fs_new_dir_block@Base 1.37 -+ ext2fs_new_dir_inline_data@Base 1.43~WIP-2015-05-18 - ext2fs_new_inode@Base 1.37 -+ ext2fs_new_range@Base 1.43~WIP-2015-05-18 - 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 -@@ -385,13 +432,16 @@ 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 - ext2fs_read_inode_bitmap@Base 1.37 - ext2fs_read_inode_full@Base 1.37 -+ ext2fs_remove_exit_fn@Base 1.43~WIP-2015-05-18 - ext2fs_reserve_super_and_bgd@Base 1.37 - ext2fs_resize_block_bitmap2@Base 1.42 - ext2fs_resize_block_bitmap@Base 1.37 -@@ -420,9 +470,12 @@ libext2fs.so.2 e2fslibs #MINVER# - ext2fs_set_inode_bitmap_range@Base 1.41.0 - ext2fs_set_inode_callback@Base 1.37 - ext2fs_set_rec_len@Base 1.41.7 -+ ext2fs_sha512@Base 1.43~WIP-2015-05-18 - 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 -@@ -446,6 +499,7 @@ libext2fs.so.2 e2fslibs #MINVER# - ext2fs_tdb_fd@Base 1.40 - ext2fs_tdb_fetch@Base 1.40 - ext2fs_tdb_firstkey@Base 1.40 -+ ext2fs_tdb_flush@Base 1.43~WIP-2015-05-18 - ext2fs_tdb_get_flags@Base 1.40 - ext2fs_tdb_get_logging_private@Base 1.40 - ext2fs_tdb_get_seqnum@Base 1.40 -@@ -519,6 +573,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 -@@ -527,25 +582,39 @@ 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 - ext2fs_write_inode_bitmap@Base 1.37 - ext2fs_write_inode_full@Base 1.37 - ext2fs_write_new_inode@Base 1.37 -+ ext2fs_xattr_get@Base 1.43~WIP-2015-05-18 -+ ext2fs_xattr_inode_max_size@Base 1.43~WIP-2015-05-18 -+ ext2fs_xattr_remove@Base 1.43~WIP-2015-05-18 -+ ext2fs_xattr_set@Base 1.43~WIP-2015-05-18 -+ ext2fs_xattrs_close@Base 1.43~WIP-2015-05-18 -+ ext2fs_xattrs_count@Base 1.43~WIP-2015-05-18 -+ ext2fs_xattrs_iterate@Base 1.43~WIP-2015-05-18 -+ ext2fs_xattrs_open@Base 1.43~WIP-2015-05-18 -+ ext2fs_xattrs_read@Base 1.43~WIP-2015-05-18 -+ ext2fs_xattrs_write@Base 1.43~WIP-2015-05-18 - ext2fs_zero_blocks2@Base 1.42 - ext2fs_zero_blocks@Base 1.41.0 - initialize_ext2_error_table@Base 1.37 - initialize_ext2_error_table_r@Base 1.37 - inode_io_manager@Base 1.37 - io_channel_alloc_buf@Base 1.42.3 -+ io_channel_cache_readahead@Base 1.43~WIP-2015-05-18 - io_channel_discard@Base 1.42 - io_channel_read_blk64@Base 1.41.1 - io_channel_set_options@Base 1.37 - io_channel_write_blk64@Base 1.41.1 - io_channel_write_byte@Base 1.37 -+ io_channel_zeroout@Base 1.43~WIP-2015-05-18 - qcow2_read_header@Base 1.42 - qcow2_write_raw_image@Base 1.42 - set_undo_io_backing_manager@Base 1.41.0 -diff --git a/debugfs/Android.mk b/debugfs/Android.mk -new file mode 100644 -index 0000000..80b5ec3 ---- /dev/null -+++ b/debugfs/Android.mk -@@ -0,0 +1,71 @@ -+LOCAL_PATH := $(call my-dir) -+ -+######################### -+# Build the debugfs binary -+ -+debugfs_src_files := \ -+ debug_cmds.c \ -+ debugfs.c \ -+ util.c \ -+ ncheck.c\ -+ icheck.c \ -+ ls.c \ -+ lsdel.c \ -+ dump.c \ -+ set_fields.c \ -+ logdump.c \ -+ htree.c \ -+ unused.c \ -+ e2freefrag.c \ -+ filefrag.c \ -+ extent_cmds.c \ -+ extent_inode.c \ -+ zap.c \ -+ create_inode.c \ -+ quota.c \ -+ xattrs.c \ -+ journal.c \ -+ revoke.c \ -+ recovery.c \ -+ do_journal.c -+ -+debugfs_shared_libraries := \ -+ libext2fs \ -+ libext2_blkid \ -+ libext2_uuid \ -+ libext2_ss \ -+ libext2_quota \ -+ libext2_com_err \ -+ libext2_e2p -+ -+debugfs_system_shared_libraries := libc -+ -+debugfs_c_includes := \ -+ external/e2fsprogs/e2fsck \ -+ external/e2fsprogs/misc \ -+ external/e2fsprogs/lib -+ -+debugfs_cflags := -O2 -g -W -Wall -fno-strict-aliasing -DDEBUGFS -+ -+include $(CLEAR_VARS) -+ -+LOCAL_SRC_FILES := $(debugfs_src_files) -+LOCAL_C_INCLUDES := $(debugfs_c_includes) -+LOCAL_CFLAGS := $(debugfs_cflags) -+LOCAL_SYSTEM_SHARED_LIBRARIES := $(debugfs_system_shared_libraries) -+LOCAL_SHARED_LIBRARIES := $(debugfs_shared_libraries) -+LOCAL_MODULE := debugfs -+LOCAL_MODULE_TAGS := optional -+include $(BUILD_EXECUTABLE) -+ -+include $(CLEAR_VARS) -+ -+LOCAL_SRC_FILES := $(debugfs_src_files) -+LOCAL_C_INCLUDES := $(debugfs_c_includes) -+LOCAL_CFLAGS := $(debugfs_cflags) -+LOCAL_SHARED_LIBRARIES := $(addsuffix _host, $(debugfs_shared_libraries)) -+LOCAL_MODULE := debugfs_host -+LOCAL_MODULE_STEM := debugfs -+LOCAL_MODULE_TAGS := optional -+ -+include $(BUILD_HOST_EXECUTABLE) -diff --git a/debugfs/Makefile.in b/debugfs/Makefile.in -index 3dd06f0..c22b8c0 100644 ---- a/debugfs/Makefile.in -+++ b/debugfs/Makefile.in -@@ -18,35 +18,44 @@ 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 journal.o revoke.o recovery.o do_journal.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 \ -+ $(srcdir)/journal.c $(srcdir)/../e2fsck/revoke.c \ -+ $(srcdir)/../e2fsck/recovery.c $(srcdir)/do_journal.c - --LIBS= $(LIBQUOTA) $(LIBEXT2FS) $(LIBE2P) $(LIBSS) $(LIBCOM_ERR) $(LIBBLKID) \ -- $(LIBUUID) $(SYSLIBS) --DEPLIBS= $(DEPLIBQUOTA) $(LIBEXT2FS) $(LIBE2P) $(DEPLIBSS) $(DEPLIBCOM_ERR) \ -+LIBS= $(LIBSUPPORT) $(LIBEXT2FS) $(LIBE2P) $(LIBSS) $(LIBCOM_ERR) $(LIBBLKID) \ -+ $(LIBUUID) $(LIBMAGIC) $(SYSLIBS) -+DEPLIBS= $(DEPLIBSUPPORT) $(LIBEXT2FS) $(LIBE2P) $(DEPLIBSS) $(DEPLIBCOM_ERR) \ - $(DEPLIBBLKID) $(DEPLIBUUID) - --STATIC_LIBS= $(STATIC_LIBQUOTA) $(STATIC_LIBEXT2FS) $(STATIC_LIBSS) \ -+STATIC_LIBS= $(STATIC_LIBSUPPORT) $(STATIC_LIBEXT2FS) $(STATIC_LIBSS) \ - $(STATIC_LIBCOM_ERR) $(STATIC_LIBBLKID) $(STATIC_LIBUUID) \ -- $(STATIC_LIBE2P) $(SYSLIBS) -+ $(STATIC_LIBE2P) $(LIBMAGIC) $(SYSLIBS) - STATIC_DEPLIBS= $(STATIC_LIBEXT2FS) $(DEPSTATIC_LIBSS) \ - $(DEPSTATIC_LIBCOM_ERR) $(DEPSTATIC_LIBUUID) \ - $(DEPSTATIC_LIBE2P) - -+# This nastyness is needed because of jfs_user.h hackery; when we finally -+# clean up this mess, we should be able to drop it -+LOCAL_CFLAGS = -I$(srcdir)/../e2fsck -DDEBUGFS -+DEPEND_CFLAGS = -I$(srcdir) -+ - .c.o: - $(E) " CC $<" - $(Q) $(CC) -c $(ALL_CFLAGS) $< -o $@ - $(Q) $(CHECK_CMD) $(ALL_CFLAGS) $< -+ $(Q) $(CPPCHECK_CMD) $(CPPFLAGS) $< - - all:: $(PROGS) $(MANPAGES) - -@@ -81,7 +90,22 @@ ro_debugfs.o: debugfs.c - - e2freefrag.o: $(srcdir)/../misc/e2freefrag.c - $(E) " CC $@" -- $(Q) $(CC) -c $(ALL_CFLAGS) -I$(srcdir) $< -DDEBUGFS -o $@ -+ $(Q) $(CC) -c $(ALL_CFLAGS) -I$(srcdir) $< -o $@ -+ -+recovery.o: $(srcdir)/../e2fsck/recovery.c -+ $(E) " CC $@" -+ $(Q) $(CC) -c $(ALL_CFLAGS) -I$(srcdir) \ -+ $(srcdir)/../e2fsck/recovery.c -o $@ -+ -+revoke.o: $(srcdir)/../e2fsck/revoke.c -+ $(E) " CC $@" -+ $(Q) $(CC) -c $(ALL_CFLAGS) -I$(srcdir) \ -+ $(srcdir)/../e2fsck/revoke.c -o $@ -+ -+create_inode.o: $(srcdir)/../misc/create_inode.c -+ $(E) " CC $@" -+ $(Q) $(CC) -c $(ALL_CFLAGS) -I$(srcdir) \ -+ $(srcdir)/../misc/create_inode.c -o $@ - - debugfs.8: $(DEP_SUBSTITUTE) $(srcdir)/debugfs.8.in - $(E) " SUBST $@" -@@ -121,12 +145,22 @@ uninstall: - - clean:: - $(RM) -f $(PROGS) debugfs.8 \#* *.s *.o *.a *~ debug_cmds.c \ -- extent_cmds.c ro_debug_cmds.c core rdebugfs debugfs.static -+ extent_cmds.c ro_debug_cmds.c core rdebugfs debugfs.static \ -+ tst_set_fields - - mostlyclean: clean - distclean: clean - $(RM) -f debug_cmds.c .depend Makefile $(srcdir)/TAGS \ -- $(srcdir)/Makefile.in.old -+ $(srcdir)/Makefile.in.old $(srcdir)/recovery.c \ -+ $(srcdir)/revoke.c -+ -+tst_set_fields: set_fields.c util.c -+ $(E) " LD $@" -+ $(Q) $(CC) $(ALL_CFLAGS) $(ALL_LDFLAGS) $(SYSLIBS) -DUNITTEST \ -+ -o tst_set_fields $(srcdir)/set_fields.c $(srcdir)/util.c $(LIBS) -+ -+check:: tst_set_fields -+ $(TESTENV) ./tst_set_fields - - # +++ Dependency line eater +++ - # -@@ -142,11 +176,12 @@ 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 \ -- $(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 \ -- $(top_srcdir)/lib/ext2fs/kernel-jbd.h $(top_srcdir)/lib/ext2fs/jfs_compat.h \ -- $(top_srcdir)/lib/ext2fs/kernel-list.h -+ $(srcdir)/../misc/create_inode.h $(top_srcdir)/lib/e2p/e2p.h \ -+ $(top_srcdir)/lib/support/quotaio.h $(top_srcdir)/lib/support/dqblk_v2.h \ -+ $(top_srcdir)/lib/support/quotaio_tree.h $(top_srcdir)/version.h \ -+ $(srcdir)/../e2fsck/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/support/plausible.h - util.o: $(srcdir)/util.c $(top_builddir)/lib/config.h \ - $(top_builddir)/lib/dirpaths.h $(top_srcdir)/lib/ss/ss.h \ - $(top_builddir)/lib/ss/ss_err.h $(top_srcdir)/lib/et/com_err.h \ -@@ -155,8 +190,9 @@ 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 \ -- $(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)/../misc/create_inode.h $(top_srcdir)/lib/e2p/e2p.h \ -+ $(top_srcdir)/lib/support/quotaio.h $(top_srcdir)/lib/support/dqblk_v2.h \ -+ $(top_srcdir)/lib/support/quotaio_tree.h - ls.o: $(srcdir)/ls.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 \ -@@ -164,8 +200,9 @@ 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 \ -- $(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)/../misc/create_inode.h $(top_srcdir)/lib/e2p/e2p.h \ -+ $(top_srcdir)/lib/support/quotaio.h $(top_srcdir)/lib/support/dqblk_v2.h \ -+ $(top_srcdir)/lib/support/quotaio_tree.h - ncheck.o: $(srcdir)/ncheck.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 \ -@@ -173,8 +210,9 @@ 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 \ -- $(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)/../misc/create_inode.h $(top_srcdir)/lib/e2p/e2p.h \ -+ $(top_srcdir)/lib/support/quotaio.h $(top_srcdir)/lib/support/dqblk_v2.h \ -+ $(top_srcdir)/lib/support/quotaio_tree.h - icheck.o: $(srcdir)/icheck.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 \ -@@ -182,8 +220,9 @@ 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 \ -- $(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)/../misc/create_inode.h $(top_srcdir)/lib/e2p/e2p.h \ -+ $(top_srcdir)/lib/support/quotaio.h $(top_srcdir)/lib/support/dqblk_v2.h \ -+ $(top_srcdir)/lib/support/quotaio_tree.h - lsdel.o: $(srcdir)/lsdel.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 \ -@@ -191,8 +230,9 @@ 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 \ -- $(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)/../misc/create_inode.h $(top_srcdir)/lib/e2p/e2p.h \ -+ $(top_srcdir)/lib/support/quotaio.h $(top_srcdir)/lib/support/dqblk_v2.h \ -+ $(top_srcdir)/lib/support/quotaio_tree.h - dump.o: $(srcdir)/dump.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 \ -@@ -200,8 +240,9 @@ 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 \ -- $(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)/../misc/create_inode.h $(top_srcdir)/lib/e2p/e2p.h \ -+ $(top_srcdir)/lib/support/quotaio.h $(top_srcdir)/lib/support/dqblk_v2.h \ -+ $(top_srcdir)/lib/support/quotaio_tree.h - set_fields.o: $(srcdir)/set_fields.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 \ -@@ -209,9 +250,9 @@ 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 \ -- $(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)/../misc/create_inode.h $(top_srcdir)/lib/e2p/e2p.h \ -+ $(top_srcdir)/lib/support/quotaio.h $(top_srcdir)/lib/support/dqblk_v2.h \ -+ $(top_srcdir)/lib/support/quotaio_tree.h - logdump.o: $(srcdir)/logdump.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 \ -@@ -219,10 +260,11 @@ 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 \ -- $(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 \ -- $(top_srcdir)/lib/ext2fs/jfs_compat.h $(top_srcdir)/lib/ext2fs/kernel-list.h -+ $(srcdir)/../misc/create_inode.h $(top_srcdir)/lib/e2p/e2p.h \ -+ $(top_srcdir)/lib/support/quotaio.h $(top_srcdir)/lib/support/dqblk_v2.h \ -+ $(top_srcdir)/lib/support/quotaio_tree.h $(srcdir)/../e2fsck/jfs_user.h \ -+ $(top_srcdir)/lib/ext2fs/kernel-jbd.h $(top_srcdir)/lib/ext2fs/jfs_compat.h \ -+ $(top_srcdir)/lib/ext2fs/kernel-list.h - htree.o: $(srcdir)/htree.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 \ -@@ -230,9 +272,9 @@ 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 \ -- $(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)/../misc/create_inode.h $(top_srcdir)/lib/e2p/e2p.h \ -+ $(top_srcdir)/lib/support/quotaio.h $(top_srcdir)/lib/support/dqblk_v2.h \ -+ $(top_srcdir)/lib/support/quotaio_tree.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 \ -@@ -240,15 +282,20 @@ unused.o: $(srcdir)/unused.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 \ -- $(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)/../misc/create_inode.h $(top_srcdir)/lib/e2p/e2p.h \ -+ $(top_srcdir)/lib/support/quotaio.h $(top_srcdir)/lib/support/dqblk_v2.h \ -+ $(top_srcdir)/lib/support/quotaio_tree.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 -+ $(srcdir)/../misc/e2freefrag.h $(srcdir)/debugfs.h $(top_srcdir)/lib/ss/ss.h \ -+ $(top_builddir)/lib/ss/ss_err.h $(srcdir)/../misc/create_inode.h \ -+ $(top_srcdir)/lib/e2p/e2p.h $(top_srcdir)/lib/support/quotaio.h \ -+ $(top_srcdir)/lib/support/dqblk_v2.h \ -+ $(top_srcdir)/lib/support/quotaio_tree.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 \ -@@ -256,8 +303,9 @@ filefrag.o: $(srcdir)/filefrag.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 \ -- $(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)/../misc/create_inode.h $(top_srcdir)/lib/e2p/e2p.h \ -+ $(top_srcdir)/lib/support/quotaio.h $(top_srcdir)/lib/support/dqblk_v2.h \ -+ $(top_srcdir)/lib/support/quotaio_tree.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 \ -@@ -265,8 +313,9 @@ extent_inode.o: $(srcdir)/extent_inode.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 \ -- $(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)/../misc/create_inode.h $(top_srcdir)/lib/e2p/e2p.h \ -+ $(top_srcdir)/lib/support/quotaio.h $(top_srcdir)/lib/support/dqblk_v2.h \ -+ $(top_srcdir)/lib/support/quotaio_tree.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 \ -@@ -274,8 +323,27 @@ zap.o: $(srcdir)/zap.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 \ -- $(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)/../misc/create_inode.h $(top_srcdir)/lib/e2p/e2p.h \ -+ $(top_srcdir)/lib/support/quotaio.h $(top_srcdir)/lib/support/dqblk_v2.h \ -+ $(top_srcdir)/lib/support/quotaio_tree.h -+create_inode.o: $(srcdir)/../misc/create_inode.c $(top_builddir)/lib/config.h \ -+ $(top_builddir)/lib/dirpaths.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 \ -+ $(top_srcdir)/lib/ext2fs/fiemap.h $(srcdir)/../misc/create_inode.h \ -+ $(top_srcdir)/lib/e2p/e2p.h $(top_srcdir)/lib/support/nls-enable.h -+xattrs.o: $(srcdir)/xattrs.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 \ -+ $(top_srcdir)/lib/support/quotaio.h $(top_srcdir)/lib/support/dqblk_v2.h \ -+ $(top_srcdir)/lib/support/quotaio_tree.h - quota.o: $(srcdir)/quota.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 \ -@@ -283,5 +351,43 @@ quota.o: $(srcdir)/quota.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 \ -- $(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)/../misc/create_inode.h $(top_srcdir)/lib/e2p/e2p.h \ -+ $(top_srcdir)/lib/support/quotaio.h $(top_srcdir)/lib/support/dqblk_v2.h \ -+ $(top_srcdir)/lib/support/quotaio_tree.h -+journal.o: $(srcdir)/journal.c $(top_builddir)/lib/config.h \ -+ $(top_builddir)/lib/dirpaths.h $(srcdir)/../e2fsck/jfs_user.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 \ -+ $(top_srcdir)/lib/ext2fs/kernel-jbd.h $(top_srcdir)/lib/ext2fs/jfs_compat.h \ -+ $(top_srcdir)/lib/ext2fs/kernel-list.h -+revoke.o: $(srcdir)/../e2fsck/revoke.c $(srcdir)/../e2fsck/jfs_user.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 \ -+ $(top_srcdir)/lib/ext2fs/kernel-jbd.h $(top_srcdir)/lib/ext2fs/jfs_compat.h \ -+ $(top_srcdir)/lib/ext2fs/kernel-list.h -+recovery.o: $(srcdir)/../e2fsck/recovery.c $(srcdir)/../e2fsck/jfs_user.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 \ -+ $(top_srcdir)/lib/ext2fs/kernel-jbd.h $(top_srcdir)/lib/ext2fs/jfs_compat.h \ -+ $(top_srcdir)/lib/ext2fs/kernel-list.h -+do_journal.o: $(srcdir)/do_journal.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 \ -+ $(top_srcdir)/lib/support/quotaio.h $(top_srcdir)/lib/support/dqblk_v2.h \ -+ $(top_srcdir)/lib/support/quotaio_tree.h $(srcdir)/../e2fsck/jfs_user.h \ -+ $(top_srcdir)/lib/ext2fs/kernel-jbd.h $(top_srcdir)/lib/ext2fs/jfs_compat.h \ -+ $(top_srcdir)/lib/ext2fs/kernel-list.h -diff --git a/debugfs/debug_cmds.ct b/debugfs/debug_cmds.ct -index ed3728f..34dad9e 100644 ---- a/debugfs/debug_cmds.ct -+++ b/debugfs/debug_cmds.ct -@@ -157,6 +157,9 @@ request do_dirsearch, "Search a directory for a particular filename", - request do_bmap, "Calculate the logical->physical block mapping for an inode", - bmap; - -+request do_fallocate, "Allocate uninitialized blocks to an inode", -+ fallocate; -+ - request do_punch, "Punch (or truncate) blocks from an inode by deallocating them", - punch, truncate; - -@@ -190,6 +193,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; - -@@ -199,6 +214,17 @@ request do_get_quota, "Get quota", - request do_idump, "Dump the inode structure in hex", - inode_dump, idump, id; - -+request do_journal_open, "Open the journal", -+ journal_open, jo; -+ -+request do_journal_close, "Close the journal", -+ journal_close, jc; -+ -+request do_journal_write, "Write a transaction to the journal", -+ journal_write, jw; -+ -+request do_journal_run, "Recover the journal", -+ journal_run, jr; - - end; - -diff --git a/debugfs/debugfs.8.in b/debugfs/debugfs.8.in -index bae14db..a463c73 100644 ---- a/debugfs/debugfs.8.in -+++ b/debugfs/debugfs.8.in -@@ -8,7 +8,7 @@ debugfs \- ext2/ext3/ext4 file system debugger - .SH SYNOPSIS - .B debugfs - [ --.B \-DVwci -+.B \-DVwcin - ] - [ - .B \-b -@@ -31,6 +31,10 @@ request - data_source_device - ] - [ -+.B \-z -+.I undo_file -+] -+[ - device - ] - .SH DESCRIPTION -@@ -48,6 +52,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 -@@ -125,6 +134,16 @@ and then exit. - print the version number of - .B debugfs - and exit. -+.TP -+.BI \-z " undo_file" -+Before overwriting a file system block, write the old contents of the block to -+an undo file. This undo file can be used with e2undo(8) to restore the old -+contents of the file system should something go wrong. If the empty string is -+passed as the undo_file argument, the undo file will be written to a file named -+resize2fs-\fIdevice\fR.e2undo in the directory specified via the -+\fIE2FSPROGS_UNDO_DIR\fR environment variable. -+ -+WARNING: The undo file cannot be used to recover from a power or system crash. - .SH SPECIFYING FILES - Many - .B debugfs -@@ -162,11 +181,14 @@ Print the blocks used by the inode - .I filespec - to stdout. - .TP --.BI bmap " filespec logical_block" --Print the physical block number corresponding to the logical block number -+.BI bmap " [ -a ] filespec logical_block [physical_block]" -+Print or set the physical block number corresponding to the logical block number - .I logical_block - in the inode - .IR filespec . -+If the -+.I -a -+flag is specified, try to allocate a block if necessary. - .TP - .BI block_dump " [-f filespec] block_num" - Dump the filesystem block given by -@@ -254,10 +276,43 @@ not stored in filesystem data structures. Hence, the values displayed - may not necessarily by accurate and does not indicate a problem or - corruption in the file system.) - .TP -+.BI ea_get " [-f outfile] filespec attr_name" -+Retrieve the value of the extended attribute -+.I attr_name -+in the file -+.I filespec -+and write it either to stdout or to \fIoutfile\fR. -+.TP -+.BI ea_list " filespec -+List the extended attributes associated with the file -+.I filespec -+to standard output. -+.TP -+.BI ea_set " [-f infile] filespec attr_name attr_value -+Set the value of the extended attribute -+.I attr_name -+in the file -+.I filespec -+to the string value -+.I attr_value -+or read it from \fIinfile\fR. -+.TP -+.BI ea_rm " filespec attr_names... -+Remove the extended attribute -+.I attr_name -+from the file \fIfilespec\fR. -+.TP - .BI expand_dir " filespec" - Expand the directory - .IR filespec . - .TP -+.BI fallocate " filespec start_block [end_block] -+Allocate and map uninitialized blocks into \fIfilespec\fR between -+logical block \fIstart_block\fR and \fIend_block\fR, inclusive. If -+\fIend_block\fR is not supplied, this function maps until it runs out -+of free disk blocks or the maximum file size is reached. Existing -+mappings are left alone. -+.TP - .BI feature " [fs_feature] [-fs_feature] ..." - Set or clear various filesystem features in the superblock. After setting - or clearing any filesystem features that were requested, print the current -@@ -365,6 +420,26 @@ to do this, use the - program. This is just a call to the low-level library, which sets up - the superblock and block descriptors. - .TP -+.BI journal_close -+Close the open journal. -+.TP -+.BI journal_open " [-c] [-v ver] [-j ext_jnl] -+Opens the journal for reading and writing. Journal checksumming can -+be enabled by supplying \fI-c\fR; checksum formats 2 and 3 can be -+selected with the \fI-v\fR option. An external journal can be loaded -+from \fIext_jnl\fR. -+.TP -+.BI journal_run -+Replay all transactions in the open journal. -+.TP -+.BI journal_write " [-b blocks] [-r revoke] [-c] file -+Write a transaction to the open journal. The list of blocks to write -+should be supplied as a comma-separated list in \fIblocks\fR; the -+blocks themselves should be readable from \fIfile\fR. A list of -+blocks to revoke can be supplied as a comma-separated list in -+\fIrevoke\fR. By default, a commit record is written at the end; the -+\fI-c\fR switch writes an uncommitted transaction. -+.TP - .BI kill_file " filespec" - Deallocate the inode - .I filespec -@@ -387,7 +462,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 +493,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] [-r] 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 -@@ -433,6 +517,9 @@ The - flag will list the files in a format which is more easily parsable by - scripts, as well as making it more clear when there are spaces or other - non-printing characters at the end of filenames. -+The -+.I \-r -+flag will force the printing of the filename, even if it is encrypted. - .TP - .BI list_deleted_inodes " [limit]" - List deleted inodes, optionally limited to those deleted within -@@ -469,7 +556,7 @@ to those inodes. The - flag will enable checking the file type information in the directory - entry to make sure it matches the inode's type. - .TP --.BI open " [-weficD] [-b blocksize] [-s superblock] device" -+.BI open " [-weficD] [-b blocksize] [-s superblock] [-z undo_file] device" - Open a filesystem for editing. The - .I -f - flag forces the filesystem to be opened even if there are some unknown -@@ -650,7 +737,6 @@ into a newly-created file in the filesystem named - .IR out_file . - .TP - .BI zap_block " [-f filespec] [-o offset] [-l length] [-p pattern] block_num" --.TP - Overwrite the block specified by - .I block_num - with zero (NUL) bytes, or if -diff --git a/debugfs/debugfs.c b/debugfs/debugfs.c -index 5423634..583cf8b 100644 ---- a/debugfs/debugfs.c -+++ b/debugfs/debugfs.c -@@ -15,6 +15,7 @@ - #include - #include - #include -+#include - #ifdef HAVE_GETOPT_H - #include - #else -@@ -25,8 +26,6 @@ extern char *optarg; - #include - #endif - #include --#include --#include - - #include "debugfs.h" - #include "uuid/uuid.h" -@@ -36,35 +35,101 @@ extern char *optarg; - - #include "../version.h" - #include "jfs_user.h" -+#include "support/plausible.h" - - #ifndef BUFSIZ - #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; - -+static int debugfs_setup_tdb(const char *device_name, char *undo_file, -+ io_manager *io_ptr) -+{ -+ errcode_t retval = ENOMEM; -+ char *tdb_dir = NULL, *tdb_file = NULL; -+ char *dev_name, *tmp_name; -+ -+ /* (re)open a specific undo file */ -+ if (undo_file && undo_file[0] != 0) { -+ retval = set_undo_io_backing_manager(*io_ptr); -+ if (retval) -+ goto err; -+ *io_ptr = undo_io_manager; -+ retval = set_undo_io_backup_file(undo_file); -+ if (retval) -+ goto err; -+ printf("Overwriting existing filesystem; this can be undone " -+ "using the command:\n" -+ " e2undo %s %s\n\n", -+ undo_file, device_name); -+ return retval; -+ } -+ -+ /* -+ * Configuration via a conf file would be -+ * nice -+ */ -+ tdb_dir = getenv("E2FSPROGS_UNDO_DIR"); -+ if (!tdb_dir) -+ tdb_dir = "/var/lib/e2fsprogs"; -+ -+ if (!strcmp(tdb_dir, "none") || (tdb_dir[0] == 0) || -+ access(tdb_dir, W_OK)) -+ return 0; -+ -+ tmp_name = strdup(device_name); -+ if (!tmp_name) -+ goto errout; -+ dev_name = basename(tmp_name); -+ tdb_file = malloc(strlen(tdb_dir) + 9 + strlen(dev_name) + 7 + 1); -+ if (!tdb_file) { -+ free(tmp_name); -+ goto errout; -+ } -+ sprintf(tdb_file, "%s/debugfs-%s.e2undo", tdb_dir, dev_name); -+ free(tmp_name); -+ -+ if ((unlink(tdb_file) < 0) && (errno != ENOENT)) { -+ retval = errno; -+ com_err("debugfs", retval, -+ "while trying to delete %s", tdb_file); -+ goto errout; -+ } -+ -+ retval = set_undo_io_backing_manager(*io_ptr); -+ if (retval) -+ goto errout; -+ *io_ptr = undo_io_manager; -+ retval = set_undo_io_backup_file(tdb_file); -+ if (retval) -+ goto errout; -+ printf("Overwriting existing filesystem; this can be undone " -+ "using the command:\n" -+ " e2undo %s %s\n\n", tdb_file, device_name); -+ -+ free(tdb_file); -+ return 0; -+errout: -+ free(tdb_file); -+err: -+ com_err("debugfs", retval, "while trying to setup undo file\n"); -+ return retval; -+} -+ - static void open_filesystem(char *device, int open_flags, blk64_t superblock, - blk64_t blocksize, int catastrophic, -- char *data_filename) -+ char *data_filename, char *undo_file) - { - int retval; - io_channel data_io = 0; -+ io_manager io_ptr = unix_io_manager; - - if (superblock != 0 && blocksize == 0) { - com_err(device, 0, "if you specify the superblock, you must also specify the block size"); -@@ -95,10 +160,18 @@ static void open_filesystem(char *device, int open_flags, blk64_t superblock, - if (catastrophic) - open_flags |= EXT2_FLAG_SKIP_MMP; - -+ if (undo_file) { -+ retval = debugfs_setup_tdb(device, undo_file, &io_ptr); -+ if (retval) -+ exit(1); -+ } -+ - retval = ext2fs_open(device, open_flags, superblock, blocksize, -- unix_io_manager, ¤t_fs); -+ io_ptr, ¤t_fs); - if (retval) { - com_err(device, retval, "while opening filesystem"); -+ if (retval == EXT2_ET_BAD_MAGIC) -+ check_plausibility(device, CHECK_FS_EXIST, NULL); - current_fs = NULL; - return; - } -@@ -145,9 +218,10 @@ void do_open_filesys(int argc, char **argv) - blk64_t blocksize = 0; - int open_flags = EXT2_FLAG_SOFTSUPP_FEATURES | EXT2_FLAG_64BITS; - char *data_filename = 0; -+ char *undo_file = NULL; - - reset_getopt(); -- while ((c = getopt (argc, argv, "iwfecb:s:d:D")) != EOF) { -+ while ((c = getopt(argc, argv, "iwfecb:s:d:Dz:")) != EOF) { - switch (c) { - case 'i': - open_flags |= EXT2_FLAG_IMAGE_FILE; -@@ -186,6 +260,9 @@ void do_open_filesys(int argc, char **argv) - if (err) - return; - break; -+ case 'z': -+ undo_file = optarg; -+ break; - default: - goto print_usage; - } -@@ -197,7 +274,7 @@ void do_open_filesys(int argc, char **argv) - return; - open_filesystem(argv[optind], open_flags, - superblock, blocksize, catastrophic, -- data_filename); -+ data_filename, undo_file); - return; - - print_usage: -@@ -373,8 +450,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,36 +582,11 @@ 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)), - struct ext2_inode_large *inode) - { -- struct ext2_ext_attr_entry *entry; -- __u32 *magic; -- char *start, *end; -- - fprintf(out, "Size of extra inode fields: %u\n", inode->i_extra_isize); - if (inode->i_extra_isize > EXT2_INODE_SIZE(current_fs->super) - - EXT2_GOOD_OLD_INODE_SIZE) { -@@ -543,33 +594,6 @@ static void internal_dump_inode_extra(FILE *out, - inode->i_extra_isize); - return; - } -- 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); -- char *name = EXT2_EXT_ATTR_NAME(entry); -- char *value = start + entry->e_value_offs; -- -- if (name + entry->e_name_len >= end || -- value + entry->e_value_size >= end || -- (char *) next >= end) { -- fprintf(out, "invalid EA entry in inode\n"); -- return; -- } -- fprintf(out, " "); -- dump_xattr_string(out, name, entry->e_name_len); -- fprintf(out, " = \""); -- dump_xattr_string(out, value, 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) -@@ -718,6 +742,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 { -+ size_t sz = EXT2_I_SIZE(inode); -+ -+ if (sz > sizeof(inode->i_block)) -+ sz = sizeof(inode->i_block); -+ fprintf(out, "%sFast link dest: \"%.*s\"\n", prefix, (int) 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, -@@ -817,9 +891,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; -@@ -840,6 +928,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); - } -@@ -1574,195 +1664,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", - " ", 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; -+ unsigned long major, minor; - errcode_t retval; -- struct ext2_inode inode; -- int filetype, nr; -+ int nr; -+ struct stat st; - - if (check_fs_open(argv[0])) - return; -@@ -1771,115 +1691,52 @@ void do_mknod(int argc, char *argv[]) - com_err(argv[0], 0, "Usage: mknod [p| [c|b] ]"); - return; - } -- mode = minor = major = 0; -+ -+ 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", - "", 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], root); -+ if (retval) -+ com_err(argv[0], retval, 0); - - } - -@@ -1905,11 +1762,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)); -@@ -1976,9 +1832,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; -@@ -2093,28 +1949,64 @@ void do_features(int argc, char *argv[]) - void do_bmap(int argc, char *argv[]) - { - ext2_ino_t ino; -- blk64_t blk, pblk; -- int err; -+ blk64_t blk, pblk = 0; -+ int c, err, flags = 0, ret_flags = 0; - errcode_t errcode; - -- if (common_args_process(argc, argv, 3, 3, argv[0], -- " logical_blk", 0)) -+ if (check_fs_open(argv[0])) - return; - -- ino = string_to_inode(argv[1]); -+ reset_getopt(); -+ while ((c = getopt (argc, argv, "a")) != EOF) { -+ switch (c) { -+ case 'a': -+ flags |= BMAP_ALLOC; -+ break; -+ default: -+ goto print_usage; -+ } -+ } -+ -+ if (argc <= optind+1) { -+ print_usage: -+ com_err(0, 0, -+ "Usage: bmap [-a] logical_blk [physical_blk]"); -+ return; -+ } -+ -+ ino = string_to_inode(argv[optind++]); - if (!ino) - return; -- err = strtoblk(argv[0], argv[2], "logical block", &blk); -+ err = strtoblk(argv[0], argv[optind++], "logical block", &blk); - if (err) - return; - -- errcode = ext2fs_bmap2(current_fs, ino, 0, 0, 0, blk, 0, &pblk); -+ if (argc > optind+1) -+ goto print_usage; -+ -+ if (argc == optind+1) { -+ err = strtoblk(argv[0], argv[optind++], -+ "physical block", &pblk); -+ if (err) -+ return; -+ if (flags & BMAP_ALLOC) { -+ com_err(0, 0, "Can't set and allocate a block"); -+ return; -+ } -+ flags |= BMAP_SET; -+ } -+ -+ errcode = ext2fs_bmap2(current_fs, ino, 0, 0, flags, blk, -+ &ret_flags, &pblk); - if (errcode) { - com_err(argv[0], errcode, - "while mapping logical block %llu\n", blk); - return; - } -- printf("%llu\n", pblk); -+ printf("%llu", pblk); -+ if (ret_flags & BMAP_RET_UNINIT) -+ fputs(" (uninit)", stdout); -+ fputc('\n', stdout); - } - - void do_imap(int argc, char *argv[]) -@@ -2303,51 +2195,59 @@ void do_punch(int argc, char *argv[]) - return; - } - } -+ -+void do_fallocate(int argc, char *argv[]) -+{ -+ ext2_ino_t ino; -+ blk64_t start, end; -+ int err; -+ errcode_t errcode; -+ -+ if (common_args_process(argc, argv, 3, 4, argv[0], -+ " start_blk [end_blk]", -+ CHECK_FS_RW | CHECK_FS_BITMAPS)) -+ return; -+ -+ ino = string_to_inode(argv[1]); -+ if (!ino) -+ return; -+ err = strtoblk(argv[0], argv[2], "logical block", &start); -+ if (err) -+ return; -+ if (argc == 4) { -+ err = strtoblk(argv[0], argv[3], "logical block", &end); -+ if (err) -+ return; -+ } else -+ end = ~0; -+ -+ errcode = ext2fs_fallocate(current_fs, EXT2_FALLOCATE_INIT_BEYOND_EOF, -+ ino, NULL, ~0ULL, start, end - start + 1); -+ -+ if (errcode) { -+ com_err(argv[0], errcode, -+ "while fallocating inode %u from %llu to %llu\n", ino, -+ (unsigned long long) start, (unsigned long long) end); -+ return; -+ } -+} - #endif /* READ_ONLY */ - - 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", - " ", 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); - - } - -+#if CONFIG_MMP - void do_dump_mmp(int argc EXT2FS_ATTR((unused)), char *argv[]) - { - struct mmp_struct *mmp_s; -@@ -2385,7 +2285,18 @@ 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); -+ fprintf(stdout, "MMP is unsupported, please recompile with " -+ "--enable-mmp\n"); - } -+#else -+void do_dump_mmp(int argc EXT2FS_ATTR((unused)), -+ char *argv[] EXT2FS_ATTR((unused))) -+{ -+ fprintf(stdout, "MMP is unsupported, please recompile with " -+ "--enable-mmp\n"); -+} -+#endif - - static int source_file(const char *cmd_file, int ss_idx) - { -@@ -2436,7 +2347,7 @@ int main(int argc, char **argv) - "Usage: %s [-b blocksize] [-s superblock] [-f cmd_file] " - "[-R request] [-V] [" - #ifndef READ_ONLY -- "[-w] " -+ "[-w] [-z undo_file] " - #endif - "[-c] device]"; - int c; -@@ -2449,9 +2360,10 @@ 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:Dz:"; -+ char *undo_file = NULL; - #endif - - if (debug_prog_name == 0) -@@ -2478,6 +2390,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; -@@ -2505,6 +2420,9 @@ int main(int argc, char **argv) - fprintf(stderr, "\tUsing %s\n", - error_message(EXT2_ET_BASE)); - exit(0); -+ case 'z': -+ undo_file = optarg; -+ break; - default: - com_err(argv[0], 0, usage, debug_prog_name); - return 1; -@@ -2513,7 +2431,7 @@ int main(int argc, char **argv) - if (optind < argc) - open_filesystem(argv[optind], open_flags, - superblock, blocksize, catastrophic, -- data_filename); -+ data_filename, undo_file); - - sci_idx = ss_create_invocation(debug_prog_name, "0.0", (char *) NULL, - &debug_cmds, &retval); -diff --git a/debugfs/debugfs.h b/debugfs/debugfs.h -index 0e75cee..fa2aacb 100644 ---- a/debugfs/debugfs.h -+++ b/debugfs/debugfs.h -@@ -5,7 +5,8 @@ - #include "ss/ss.h" - #include "ext2fs/ext2_fs.h" - #include "ext2fs/ext2fs.h" --#include "quota/quotaio.h" -+#include "../misc/create_inode.h" -+#include "support/quotaio.h" - - #ifdef __STDC__ - #define NOARGS void -@@ -162,9 +163,11 @@ extern void do_expand_dir(int argc, char **argv); - extern void do_features(int argc, char **argv); - extern void do_bmap(int argc, char **argv); - extern void do_imap(int argc, char **argv); -+extern void do_idump(int argc, char *argv[]); - extern void do_set_current_time(int argc, char **argv); - extern void do_supported_features(int argc, char **argv); - extern void do_punch(int argc, char **argv); -+extern void do_fallocate(int argc, char **argv); - extern void do_symlink(int argc, char **argv); - - extern void do_dump_mmp(int argc, char **argv); -@@ -173,12 +176,27 @@ extern void do_set_mmp_value(int argc, char **argv); - extern void do_freefrag(int argc, char **argv); - extern void do_filefrag(int argc, char *argv[]); - -+/* do_journal.c */ -+ -+extern void do_journal_write(int argc, char *argv[]); -+extern void do_journal_open(int argc, char *argv[]); -+extern void do_journal_close(int argc, char *argv[]); -+extern void do_journal_run(int argc, char *argv[]); -+ - /* quota.c */ - extern void do_list_quota(int argc, char *argv[]); - extern void do_get_quota(int argc, char *argv[]); - - /* util.c */ - extern time_t string_to_time(const char *arg); -+errcode_t read_list(char *str, blk64_t **list, size_t *len); -+ -+/* 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); -diff --git a/debugfs/do_journal.c b/debugfs/do_journal.c -new file mode 100644 -index 0000000..5c2c2a2 ---- /dev/null -+++ b/debugfs/do_journal.c -@@ -0,0 +1,985 @@ -+/* -+ * do_journal.c --- Scribble onto the journal! -+ * -+ * Copyright (C) 2014 Oracle. This file may be redistributed -+ * under the terms of the GNU Public License. -+ */ -+ -+#include "config.h" -+#include -+#ifdef HAVE_GETOPT_H -+#include -+#else -+extern int optind; -+extern char *optarg; -+#endif -+#include -+#include -+#ifdef HAVE_SYS_TIME_H -+#include -+#endif -+ -+#include "debugfs.h" -+#include "ext2fs/kernel-jbd.h" -+#include "journal.h" -+ -+#undef DEBUG -+ -+#ifdef DEBUG -+# define dbg_printf(f, a...) do {printf("JFS DEBUG: " f, ## a); \ -+ fflush(stdout); \ -+} while (0) -+#else -+# define dbg_printf(f, a...) -+#endif -+ -+#define JOURNAL_CHECK_TRANS_MAGIC(x) \ -+ do { \ -+ if ((x)->magic != J_TRANS_MAGIC) \ -+ return EXT2_ET_INVALID_ARGUMENT; \ -+ } while (0) -+ -+#define J_TRANS_MAGIC 0xD15EA5ED -+#define J_TRANS_OPEN 1 -+#define J_TRANS_COMMITTED 2 -+struct journal_transaction_s { -+ unsigned int magic; -+ ext2_filsys fs; -+ journal_t *journal; -+ blk64_t block; -+ blk64_t start, end; -+ tid_t tid; -+ int flags; -+}; -+ -+typedef struct journal_transaction_s journal_transaction_t; -+ -+static journal_t *current_journal = NULL; -+ -+static void journal_dump_trans(journal_transaction_t *trans EXT2FS_ATTR((unused)), -+ const char *tag EXT2FS_ATTR((unused))) -+{ -+ dbg_printf("TRANS %p(%s): tid=%d start=%llu block=%llu end=%llu " -+ "flags=0x%x\n", trans, tag, trans->tid, trans->start, -+ trans->block, trans->end, trans->flags); -+} -+ -+static errcode_t journal_commit_trans(journal_transaction_t *trans) -+{ -+ struct buffer_head *bh, *cbh = NULL; -+ struct commit_header *commit; -+#ifdef HAVE_SYS_TIME_H -+ struct timeval tv; -+#endif -+ errcode_t err; -+ -+ JOURNAL_CHECK_TRANS_MAGIC(trans); -+ -+ if ((trans->flags & J_TRANS_COMMITTED) || -+ !(trans->flags & J_TRANS_OPEN)) -+ return EXT2_ET_INVALID_ARGUMENT; -+ -+ bh = getblk(trans->journal->j_dev, 0, trans->journal->j_blocksize); -+ if (bh == NULL) -+ return ENOMEM; -+ -+ /* write the descriptor block header */ -+ commit = (struct commit_header *)bh->b_data; -+ commit->h_magic = ext2fs_cpu_to_be32(JFS_MAGIC_NUMBER); -+ commit->h_blocktype = ext2fs_cpu_to_be32(JFS_COMMIT_BLOCK); -+ commit->h_sequence = ext2fs_cpu_to_be32(trans->tid); -+ if (JFS_HAS_COMPAT_FEATURE(trans->journal, -+ JFS_FEATURE_COMPAT_CHECKSUM)) { -+ __u32 csum_v1 = ~0; -+ blk64_t cblk; -+ -+ cbh = getblk(trans->journal->j_dev, 0, -+ trans->journal->j_blocksize); -+ if (cbh == NULL) { -+ err = ENOMEM; -+ goto error; -+ } -+ -+ for (cblk = trans->start; cblk < trans->block; cblk++) { -+ err = journal_bmap(trans->journal, cblk, -+ &cbh->b_blocknr); -+ if (err) -+ goto error; -+ mark_buffer_uptodate(cbh, 0); -+ ll_rw_block(READ, 1, &cbh); -+ err = cbh->b_err; -+ if (err) -+ goto error; -+ csum_v1 = ext2fs_crc32_be(csum_v1, -+ (unsigned char const *)cbh->b_data, -+ cbh->b_size); -+ } -+ -+ commit->h_chksum_type = JFS_CRC32_CHKSUM; -+ commit->h_chksum_size = JFS_CRC32_CHKSUM_SIZE; -+ commit->h_chksum[0] = ext2fs_cpu_to_be32(csum_v1); -+ } else { -+ commit->h_chksum_type = 0; -+ commit->h_chksum_size = 0; -+ commit->h_chksum[0] = 0; -+ } -+#ifdef HAVE_SYS_TIME_H -+ gettimeofday(&tv, NULL); -+ commit->h_commit_sec = ext2fs_cpu_to_be32(tv.tv_sec); -+ commit->h_commit_nsec = ext2fs_cpu_to_be32(tv.tv_usec * 1000); -+#else -+ commit->h_commit_sec = 0; -+ commit->h_commit_nsec = 0; -+#endif -+ -+ /* Write block */ -+ jbd2_commit_block_csum_set(trans->journal, bh); -+ err = journal_bmap(trans->journal, trans->block, &bh->b_blocknr); -+ if (err) -+ goto error; -+ -+ dbg_printf("Writing commit block at %llu:%llu\n", trans->block, -+ bh->b_blocknr); -+ mark_buffer_dirty(bh); -+ ll_rw_block(WRITE, 1, &bh); -+ err = bh->b_err; -+ if (err) -+ goto error; -+ trans->flags |= J_TRANS_COMMITTED; -+ trans->flags &= ~J_TRANS_OPEN; -+ trans->block++; -+ -+ trans->fs->super->s_feature_incompat |= EXT3_FEATURE_INCOMPAT_RECOVER; -+ ext2fs_mark_super_dirty(trans->fs); -+error: -+ if (cbh) -+ brelse(cbh); -+ brelse(bh); -+ return err; -+} -+ -+static errcode_t journal_add_revoke_to_trans(journal_transaction_t *trans, -+ blk64_t *revoke_list, -+ size_t revoke_len) -+{ -+ journal_revoke_header_t *jrb; -+ void *buf; -+ size_t i, offset; -+ blk64_t curr_blk; -+ int sz, csum_size = 0; -+ struct buffer_head *bh; -+ errcode_t err; -+ -+ JOURNAL_CHECK_TRANS_MAGIC(trans); -+ -+ if ((trans->flags & J_TRANS_COMMITTED) || -+ !(trans->flags & J_TRANS_OPEN)) -+ return EXT2_ET_INVALID_ARGUMENT; -+ -+ if (revoke_len == 0) -+ return 0; -+ -+ /* Do we need to leave space at the end for a checksum? */ -+ if (journal_has_csum_v2or3(trans->journal)) -+ csum_size = sizeof(struct journal_revoke_tail); -+ -+ curr_blk = trans->block; -+ -+ bh = getblk(trans->journal->j_dev, curr_blk, -+ trans->journal->j_blocksize); -+ if (bh == NULL) -+ return ENOMEM; -+ jrb = buf = bh->b_data; -+ jrb->r_header.h_magic = ext2fs_cpu_to_be32(JFS_MAGIC_NUMBER); -+ jrb->r_header.h_blocktype = ext2fs_cpu_to_be32(JFS_REVOKE_BLOCK); -+ jrb->r_header.h_sequence = ext2fs_cpu_to_be32(trans->tid); -+ offset = sizeof(*jrb); -+ -+ if (JFS_HAS_INCOMPAT_FEATURE(trans->journal, -+ JFS_FEATURE_INCOMPAT_64BIT)) -+ sz = 8; -+ else -+ sz = 4; -+ -+ for (i = 0; i < revoke_len; i++) { -+ /* Block full, write to journal */ -+ if (offset + sz > trans->journal->j_blocksize - csum_size) { -+ jrb->r_count = ext2fs_cpu_to_be32(offset); -+ jbd2_revoke_csum_set(trans->journal, bh); -+ -+ err = journal_bmap(trans->journal, curr_blk, -+ &bh->b_blocknr); -+ if (err) -+ goto error; -+ dbg_printf("Writing revoke block at %llu:%llu\n", -+ curr_blk, bh->b_blocknr); -+ mark_buffer_dirty(bh); -+ ll_rw_block(WRITE, 1, &bh); -+ err = bh->b_err; -+ if (err) -+ goto error; -+ -+ offset = sizeof(*jrb); -+ curr_blk++; -+ } -+ -+ if (revoke_list[i] >= -+ ext2fs_blocks_count(trans->journal->j_fs_dev->k_fs->super)) { -+ err = EXT2_ET_BAD_BLOCK_NUM; -+ goto error; -+ } -+ -+ if (JFS_HAS_INCOMPAT_FEATURE(trans->journal, -+ JFS_FEATURE_INCOMPAT_64BIT)) -+ *((__u64 *)(&((char *)buf)[offset])) = -+ ext2fs_cpu_to_be64(revoke_list[i]); -+ else -+ *((__u32 *)(&((char *)buf)[offset])) = -+ ext2fs_cpu_to_be32(revoke_list[i]); -+ offset += sz; -+ } -+ -+ if (offset > 0) { -+ jrb->r_count = ext2fs_cpu_to_be32(offset); -+ jbd2_revoke_csum_set(trans->journal, bh); -+ -+ err = journal_bmap(trans->journal, curr_blk, &bh->b_blocknr); -+ if (err) -+ goto error; -+ dbg_printf("Writing revoke block at %llu:%llu\n", -+ curr_blk, bh->b_blocknr); -+ mark_buffer_dirty(bh); -+ ll_rw_block(WRITE, 1, &bh); -+ err = bh->b_err; -+ if (err) -+ goto error; -+ curr_blk++; -+ } -+ -+error: -+ trans->block = curr_blk; -+ brelse(bh); -+ return err; -+} -+ -+static errcode_t journal_add_blocks_to_trans(journal_transaction_t *trans, -+ blk64_t *block_list, size_t block_len, -+ FILE *fp) -+{ -+ blk64_t curr_blk, jdb_blk; -+ size_t i, j; -+ int csum_size = 0; -+ journal_header_t *jdb; -+ journal_block_tag_t *jdbt; -+ int tag_bytes; -+ void *buf = NULL, *jdb_buf = NULL; -+ struct buffer_head *bh = NULL, *data_bh; -+ errcode_t err; -+ -+ JOURNAL_CHECK_TRANS_MAGIC(trans); -+ -+ if ((trans->flags & J_TRANS_COMMITTED) || -+ !(trans->flags & J_TRANS_OPEN)) -+ return EXT2_ET_INVALID_ARGUMENT; -+ -+ if (block_len == 0) -+ return 0; -+ -+ /* Do we need to leave space at the end for a checksum? */ -+ if (journal_has_csum_v2or3(trans->journal)) -+ csum_size = sizeof(struct journal_block_tail); -+ -+ curr_blk = jdb_blk = trans->block; -+ -+ data_bh = getblk(trans->journal->j_dev, curr_blk, -+ trans->journal->j_blocksize); -+ if (data_bh == NULL) -+ return ENOMEM; -+ buf = data_bh->b_data; -+ -+ /* write the descriptor block header */ -+ bh = getblk(trans->journal->j_dev, curr_blk, -+ trans->journal->j_blocksize); -+ if (bh == NULL) { -+ err = ENOMEM; -+ goto error; -+ } -+ jdb = jdb_buf = bh->b_data; -+ jdb->h_magic = ext2fs_cpu_to_be32(JFS_MAGIC_NUMBER); -+ jdb->h_blocktype = ext2fs_cpu_to_be32(JFS_DESCRIPTOR_BLOCK); -+ jdb->h_sequence = ext2fs_cpu_to_be32(trans->tid); -+ jdbt = (journal_block_tag_t *)(jdb + 1); -+ -+ curr_blk++; -+ for (i = 0; i < block_len; i++) { -+ j = fread(data_bh->b_data, trans->journal->j_blocksize, 1, fp); -+ if (j != 1) { -+ err = errno; -+ goto error; -+ } -+ -+ tag_bytes = journal_tag_bytes(trans->journal); -+ -+ /* No space left in descriptor block, write it out */ -+ if ((char *)jdbt + tag_bytes > -+ (char *)jdb_buf + trans->journal->j_blocksize - csum_size) { -+ jbd2_descr_block_csum_set(trans->journal, bh); -+ err = journal_bmap(trans->journal, jdb_blk, -+ &bh->b_blocknr); -+ if (err) -+ goto error; -+ dbg_printf("Writing descriptor block at %llu:%llu\n", -+ jdb_blk, bh->b_blocknr); -+ mark_buffer_dirty(bh); -+ ll_rw_block(WRITE, 1, &bh); -+ err = bh->b_err; -+ if (err) -+ goto error; -+ -+ jdbt = (journal_block_tag_t *)(jdb + 1); -+ jdb_blk = curr_blk; -+ curr_blk++; -+ } -+ -+ if (block_list[i] >= -+ ext2fs_blocks_count(trans->journal->j_fs_dev->k_fs->super)) { -+ err = EXT2_ET_BAD_BLOCK_NUM; -+ goto error; -+ } -+ -+ /* Fill out the block tag */ -+ jdbt->t_blocknr = ext2fs_cpu_to_be32(block_list[i] & 0xFFFFFFFF); -+ jdbt->t_flags = 0; -+ if (jdbt != (journal_block_tag_t *)(jdb + 1)) -+ jdbt->t_flags |= ext2fs_cpu_to_be16(JFS_FLAG_SAME_UUID); -+ else { -+ memcpy(jdbt + tag_bytes, -+ trans->journal->j_superblock->s_uuid, -+ sizeof(trans->journal->j_superblock->s_uuid)); -+ tag_bytes += 16; -+ } -+ if (i == block_len - 1) -+ jdbt->t_flags |= ext2fs_cpu_to_be16(JFS_FLAG_LAST_TAG); -+ if (*((__u32 *)buf) == ext2fs_cpu_to_be32(JFS_MAGIC_NUMBER)) { -+ *((__u32 *)buf) = 0; -+ jdbt->t_flags |= ext2fs_cpu_to_be16(JFS_FLAG_ESCAPE); -+ } -+ if (JFS_HAS_INCOMPAT_FEATURE(trans->journal, -+ JFS_FEATURE_INCOMPAT_64BIT)) -+ jdbt->t_blocknr_high = ext2fs_cpu_to_be32(block_list[i] >> 32); -+ jbd2_block_tag_csum_set(trans->journal, jdbt, data_bh, -+ trans->tid); -+ -+ /* Write the data block */ -+ err = journal_bmap(trans->journal, curr_blk, -+ &data_bh->b_blocknr); -+ if (err) -+ goto error; -+ dbg_printf("Writing data block %llu at %llu:%llu tag %d\n", -+ block_list[i], curr_blk, data_bh->b_blocknr, -+ tag_bytes); -+ mark_buffer_dirty(data_bh); -+ ll_rw_block(WRITE, 1, &data_bh); -+ err = data_bh->b_err; -+ if (err) -+ goto error; -+ -+ curr_blk++; -+ jdbt = (journal_block_tag_t *)(((char *)jdbt) + tag_bytes); -+ } -+ -+ /* Write out the last descriptor block */ -+ if (jdbt != (journal_block_tag_t *)(jdb + 1)) { -+ jbd2_descr_block_csum_set(trans->journal, bh); -+ err = journal_bmap(trans->journal, jdb_blk, &bh->b_blocknr); -+ if (err) -+ goto error; -+ dbg_printf("Writing descriptor block at %llu:%llu\n", -+ jdb_blk, bh->b_blocknr); -+ mark_buffer_dirty(bh); -+ ll_rw_block(WRITE, 1, &bh); -+ err = bh->b_err; -+ if (err) -+ goto error; -+ } -+ -+error: -+ trans->block = curr_blk; -+ if (bh) -+ brelse(bh); -+ brelse(data_bh); -+ return err; -+} -+ -+static blk64_t journal_guess_blocks(journal_t *journal, blk64_t data_blocks, -+ blk64_t revoke_blocks) -+{ -+ blk64_t ret = 1; -+ unsigned int bs, sz; -+ -+ /* Estimate # of revoke blocks */ -+ bs = journal->j_blocksize; -+ if (journal_has_csum_v2or3(journal)) -+ bs -= sizeof(struct journal_revoke_tail); -+ sz = JFS_HAS_INCOMPAT_FEATURE(journal, JFS_FEATURE_INCOMPAT_64BIT) ? -+ sizeof(__u64) : sizeof(__u32); -+ ret += revoke_blocks * sz / bs; -+ -+ /* Estimate # of data blocks */ -+ bs = journal->j_blocksize - 16; -+ if (journal_has_csum_v2or3(journal)) -+ bs -= sizeof(struct journal_block_tail); -+ sz = journal_tag_bytes(journal); -+ ret += data_blocks * sz / bs; -+ -+ ret += data_blocks; -+ -+ return ret; -+} -+ -+static errcode_t journal_open_trans(journal_t *journal, -+ journal_transaction_t *trans, -+ blk64_t blocks) -+{ -+ trans->fs = journal->j_fs_dev->k_fs; -+ trans->journal = journal; -+ trans->flags = J_TRANS_OPEN; -+ -+ if (journal->j_tail == 0) { -+ /* Clean journal, start at the tail */ -+ trans->tid = journal->j_tail_sequence; -+ trans->start = journal->j_first; -+ } else { -+ /* Put new transaction at the head of the list */ -+ trans->tid = journal->j_transaction_sequence; -+ trans->start = journal->j_head; -+ } -+ -+ trans->block = trans->start; -+ if (trans->start + blocks > journal->j_last) -+ return ENOSPC; -+ trans->end = trans->block + blocks; -+ journal_dump_trans(trans, "new transaction"); -+ -+ trans->magic = J_TRANS_MAGIC; -+ return 0; -+} -+ -+static errcode_t journal_close_trans(journal_transaction_t *trans) -+{ -+ journal_t *journal; -+ -+ JOURNAL_CHECK_TRANS_MAGIC(trans); -+ -+ if (!(trans->flags & J_TRANS_COMMITTED)) -+ return 0; -+ -+ journal = trans->journal; -+ if (journal->j_tail == 0) { -+ /* Update the tail */ -+ journal->j_tail_sequence = trans->tid; -+ journal->j_tail = trans->start; -+ journal->j_superblock->s_start = ext2fs_cpu_to_be32(trans->start); -+ } -+ -+ /* Update the head */ -+ journal->j_head = trans->end + 1; -+ journal->j_transaction_sequence = trans->tid + 1; -+ -+ trans->magic = 0; -+ -+ /* Mark ourselves as needing recovery */ -+ if (!(EXT2_HAS_INCOMPAT_FEATURE(trans->fs->super, -+ EXT3_FEATURE_INCOMPAT_RECOVER))) { -+ trans->fs->super->s_feature_incompat |= -+ EXT3_FEATURE_INCOMPAT_RECOVER; -+ ext2fs_mark_super_dirty(trans->fs); -+ } -+ -+ return 0; -+} -+ -+#define JOURNAL_WRITE_NO_COMMIT 1 -+static errcode_t journal_write(journal_t *journal, -+ int flags, blk64_t *block_list, -+ size_t block_len, blk64_t *revoke_list, -+ size_t revoke_len, FILE *fp) -+{ -+ blk64_t blocks; -+ journal_transaction_t trans; -+ errcode_t err; -+ -+ if (revoke_len > 0) { -+ journal->j_superblock->s_feature_incompat |= -+ ext2fs_cpu_to_be32(JFS_FEATURE_INCOMPAT_REVOKE); -+ mark_buffer_dirty(journal->j_sb_buffer); -+ } -+ -+ blocks = journal_guess_blocks(journal, block_len, revoke_len); -+ err = journal_open_trans(journal, &trans, blocks); -+ if (err) -+ goto error; -+ -+ err = journal_add_blocks_to_trans(&trans, block_list, block_len, fp); -+ if (err) -+ goto error; -+ -+ err = journal_add_revoke_to_trans(&trans, revoke_list, revoke_len); -+ if (err) -+ goto error; -+ -+ if (!(flags & JOURNAL_WRITE_NO_COMMIT)) { -+ err = journal_commit_trans(&trans); -+ if (err) -+ goto error; -+ } -+ -+ err = journal_close_trans(&trans); -+ if (err) -+ goto error; -+error: -+ return err; -+} -+ -+void do_journal_write(int argc, char *argv[]) -+{ -+ blk64_t *blist = NULL, *rlist = NULL; -+ size_t bn = 0, rn = 0; -+ FILE *fp = NULL; -+ int opt; -+ int flags = 0; -+ errcode_t err; -+ -+ if (current_journal == NULL) { -+ printf("Journal not open.\n"); -+ return; -+ } -+ -+ reset_getopt(); -+ while ((opt = getopt(argc, argv, "b:r:c")) != -1) { -+ switch (opt) { -+ case 'b': -+ err = read_list(optarg, &blist, &bn); -+ if (err) -+ com_err(argv[0], err, -+ "while reading block list"); -+ break; -+ case 'r': -+ err = read_list(optarg, &rlist, &rn); -+ if (err) -+ com_err(argv[0], err, -+ "while reading revoke list"); -+ break; -+ case 'c': -+ flags |= JOURNAL_WRITE_NO_COMMIT; -+ break; -+ default: -+ printf("%s [-b blocks] [-r revoke] [-c] file\n", -+ argv[0]); -+ printf("-b: Write these blocks into transaction.\n"); -+ printf("-c: Do not commit transaction.\n"); -+ printf("-r: Revoke these blocks from transaction.\n"); -+ -+ goto out; -+ } -+ } -+ -+ if (bn > 0 && optind != argc - 1) { -+ printf("Need a file to read blocks from.\n"); -+ return; -+ } -+ -+ if (bn > 0) { -+ fp = fopen(argv[optind], "r"); -+ if (fp == NULL) { -+ com_err(argv[0], errno, -+ "while opening journal data file"); -+ goto out; -+ } -+ } -+ -+ err = journal_write(current_journal, flags, blist, bn, -+ rlist, rn, fp); -+ if (err) -+ com_err("journal_write", err, "while writing journal"); -+ -+ if (fp) -+ fclose(fp); -+out: -+ if (blist) -+ free(blist); -+ if (rlist) -+ free(rlist); -+} -+ -+/* Make sure we wrap around the log correctly! */ -+#define wrap(journal, var) \ -+do { \ -+ if (var >= (journal)->j_last) \ -+ var -= ((journal)->j_last - (journal)->j_first); \ -+} while (0) -+ -+/* -+ * Count the number of in-use tags in a journal descriptor block. -+ */ -+ -+static int count_tags(journal_t *journal, char *buf) -+{ -+ char *tagp; -+ journal_block_tag_t *tag; -+ int nr = 0, size = journal->j_blocksize; -+ int tag_bytes = journal_tag_bytes(journal); -+ -+ if (journal_has_csum_v2or3(journal)) -+ size -= sizeof(struct journal_block_tail); -+ -+ tagp = buf + sizeof(journal_header_t); -+ -+ while ((tagp - buf + tag_bytes) <= size) { -+ tag = (journal_block_tag_t *) tagp; -+ -+ nr++; -+ tagp += tag_bytes; -+ if (!(tag->t_flags & ext2fs_cpu_to_be16(JFS_FLAG_SAME_UUID))) -+ tagp += 16; -+ -+ if (tag->t_flags & ext2fs_cpu_to_be16(JFS_FLAG_LAST_TAG)) -+ break; -+ } -+ -+ return nr; -+} -+ -+static errcode_t journal_find_head(journal_t *journal) -+{ -+ unsigned int next_commit_ID; -+ blk64_t next_log_block, head_block; -+ int err; -+ journal_superblock_t *sb; -+ journal_header_t *tmp; -+ struct buffer_head *bh; -+ unsigned int sequence; -+ int blocktype; -+ -+ /* -+ * First thing is to establish what we expect to find in the log -+ * (in terms of transaction IDs), and where (in terms of log -+ * block offsets): query the superblock. -+ */ -+ -+ sb = journal->j_superblock; -+ next_commit_ID = ext2fs_be32_to_cpu(sb->s_sequence); -+ next_log_block = ext2fs_be32_to_cpu(sb->s_start); -+ head_block = next_log_block; -+ -+ if (next_log_block == 0) -+ return 0; -+ -+ bh = getblk(journal->j_dev, 0, journal->j_blocksize); -+ if (bh == NULL) -+ return ENOMEM; -+ -+ /* -+ * Now we walk through the log, transaction by transaction, -+ * making sure that each transaction has a commit block in the -+ * expected place. Each complete transaction gets replayed back -+ * into the main filesystem. -+ */ -+ while (1) { -+ dbg_printf("Scanning for sequence ID %u at %lu/%lu\n", -+ next_commit_ID, (unsigned long)next_log_block, -+ journal->j_last); -+ -+ /* Skip over each chunk of the transaction looking -+ * either the next descriptor block or the final commit -+ * record. */ -+ err = journal_bmap(journal, next_log_block, &bh->b_blocknr); -+ if (err) -+ goto err; -+ mark_buffer_uptodate(bh, 0); -+ ll_rw_block(READ, 1, &bh); -+ err = bh->b_err; -+ if (err) -+ goto err; -+ -+ next_log_block++; -+ wrap(journal, next_log_block); -+ -+ /* What kind of buffer is it? -+ * -+ * If it is a descriptor block, check that it has the -+ * expected sequence number. Otherwise, we're all done -+ * here. */ -+ -+ tmp = (journal_header_t *)bh->b_data; -+ -+ if (tmp->h_magic != ext2fs_cpu_to_be32(JFS_MAGIC_NUMBER)) { -+ dbg_printf("JBD2: wrong magic 0x%x\n", tmp->h_magic); -+ goto err; -+ } -+ -+ blocktype = ext2fs_be32_to_cpu(tmp->h_blocktype); -+ sequence = ext2fs_be32_to_cpu(tmp->h_sequence); -+ dbg_printf("Found magic %d, sequence %d\n", -+ blocktype, sequence); -+ -+ if (sequence != next_commit_ID) { -+ dbg_printf("JBD2: Wrong sequence %d (wanted %d)\n", -+ sequence, next_commit_ID); -+ goto err; -+ } -+ -+ /* OK, we have a valid descriptor block which matches -+ * all of the sequence number checks. What are we going -+ * to do with it? That depends on the pass... */ -+ -+ switch (blocktype) { -+ case JFS_DESCRIPTOR_BLOCK: -+ next_log_block += count_tags(journal, bh->b_data); -+ wrap(journal, next_log_block); -+ continue; -+ -+ case JFS_COMMIT_BLOCK: -+ head_block = next_log_block; -+ next_commit_ID++; -+ continue; -+ -+ case JFS_REVOKE_BLOCK: -+ continue; -+ -+ default: -+ dbg_printf("Unrecognised magic %d, end of scan.\n", -+ blocktype); -+ err = -EINVAL; -+ goto err; -+ } -+ } -+ -+err: -+ if (err == 0) { -+ dbg_printf("head seq=%d blk=%llu\n", next_commit_ID, -+ head_block); -+ journal->j_transaction_sequence = next_commit_ID; -+ journal->j_head = head_block; -+ } -+ brelse(bh); -+ return err; -+} -+ -+static void update_journal_csum(journal_t *journal, int ver) -+{ -+ journal_superblock_t *jsb; -+ -+ if (journal->j_format_version < 2) -+ return; -+ -+ if (journal->j_tail != 0 || -+ EXT2_HAS_INCOMPAT_FEATURE(journal->j_fs_dev->k_fs->super, -+ EXT3_FEATURE_INCOMPAT_RECOVER)) { -+ printf("Journal needs recovery, will not add csums.\n"); -+ return; -+ } -+ -+ /* metadata_csum implies journal csum v3 */ -+ jsb = journal->j_superblock; -+ if (EXT2_HAS_RO_COMPAT_FEATURE(journal->j_fs_dev->k_fs->super, -+ EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) { -+ printf("Setting csum v%d\n", ver); -+ switch (ver) { -+ case 2: -+ journal->j_superblock->s_feature_incompat &= -+ ext2fs_cpu_to_be32(~JFS_FEATURE_INCOMPAT_CSUM_V3); -+ journal->j_superblock->s_feature_incompat |= -+ ext2fs_cpu_to_be32(JFS_FEATURE_INCOMPAT_CSUM_V2); -+ journal->j_superblock->s_feature_compat &= -+ ext2fs_cpu_to_be32(~JFS_FEATURE_COMPAT_CHECKSUM); -+ break; -+ case 3: -+ journal->j_superblock->s_feature_incompat &= -+ ext2fs_cpu_to_be32(~JFS_FEATURE_INCOMPAT_CSUM_V2); -+ journal->j_superblock->s_feature_incompat |= -+ ext2fs_cpu_to_be32(JFS_FEATURE_INCOMPAT_CSUM_V3); -+ journal->j_superblock->s_feature_compat &= -+ ext2fs_cpu_to_be32(~JFS_FEATURE_COMPAT_CHECKSUM); -+ break; -+ default: -+ printf("Unknown checksum v%d\n", ver); -+ break; -+ } -+ journal->j_superblock->s_checksum_type = JBD2_CRC32C_CHKSUM; -+ journal->j_csum_seed = jbd2_chksum(journal, ~0, jsb->s_uuid, -+ sizeof(jsb->s_uuid)); -+ } else { -+ journal->j_superblock->s_feature_compat |= -+ ext2fs_cpu_to_be32(JFS_FEATURE_COMPAT_CHECKSUM); -+ journal->j_superblock->s_feature_incompat &= -+ ext2fs_cpu_to_be32(~(JFS_FEATURE_INCOMPAT_CSUM_V2 | -+ JFS_FEATURE_INCOMPAT_CSUM_V3)); -+ } -+} -+ -+static void update_uuid(journal_t *journal) -+{ -+ size_t z; -+ ext2_filsys fs; -+ -+ if (journal->j_format_version < 2) -+ return; -+ -+ for (z = 0; z < sizeof(journal->j_superblock->s_uuid); z++) -+ if (journal->j_superblock->s_uuid[z]) -+ break; -+ if (z == 0) -+ return; -+ -+ fs = journal->j_fs_dev->k_fs; -+ if (!EXT2_HAS_INCOMPAT_FEATURE(fs->super, -+ EXT4_FEATURE_INCOMPAT_64BIT)) -+ return; -+ -+ if (JFS_HAS_INCOMPAT_FEATURE(journal, JFS_FEATURE_INCOMPAT_64BIT) && -+ EXT2_HAS_INCOMPAT_FEATURE(fs->super, -+ EXT4_FEATURE_INCOMPAT_64BIT)) -+ return; -+ -+ if (journal->j_tail != 0 || -+ EXT2_HAS_INCOMPAT_FEATURE(fs->super, -+ EXT3_FEATURE_INCOMPAT_RECOVER)) { -+ printf("Journal needs recovery, will not set 64bit.\n"); -+ return; -+ } -+ -+ memcpy(journal->j_superblock->s_uuid, fs->super->s_uuid, -+ sizeof(fs->super->s_uuid)); -+} -+ -+static void update_64bit_flag(journal_t *journal) -+{ -+ if (journal->j_format_version < 2) -+ return; -+ -+ if (!EXT2_HAS_INCOMPAT_FEATURE(journal->j_fs_dev->k_fs->super, -+ EXT4_FEATURE_INCOMPAT_64BIT)) -+ return; -+ -+ if (JFS_HAS_INCOMPAT_FEATURE(journal, JFS_FEATURE_INCOMPAT_64BIT) && -+ EXT2_HAS_INCOMPAT_FEATURE(journal->j_fs_dev->k_fs->super, -+ EXT4_FEATURE_INCOMPAT_64BIT)) -+ return; -+ -+ if (journal->j_tail != 0 || -+ EXT2_HAS_INCOMPAT_FEATURE(journal->j_fs_dev->k_fs->super, -+ EXT3_FEATURE_INCOMPAT_RECOVER)) { -+ printf("Journal needs recovery, will not set 64bit.\n"); -+ return; -+ } -+ -+ journal->j_superblock->s_feature_incompat |= -+ ext2fs_cpu_to_be32(JFS_FEATURE_INCOMPAT_64BIT); -+} -+ -+void do_journal_open(int argc, char *argv[]) -+{ -+ int opt, enable_csum = 0, csum_ver = 3; -+ journal_t *journal; -+ errcode_t err; -+ -+ if (check_fs_open(argv[0])) -+ return; -+ if (check_fs_read_write(argv[0])) -+ return; -+ if (check_fs_bitmaps(argv[0])) -+ return; -+ if (current_journal) { -+ printf("Journal is already open.\n"); -+ return; -+ } -+ if (!EXT2_HAS_COMPAT_FEATURE(current_fs->super, -+ EXT3_FEATURE_COMPAT_HAS_JOURNAL)) { -+ printf("Journalling is not enabled on this filesystem.\n"); -+ return; -+ } -+ -+ reset_getopt(); -+ while ((opt = getopt(argc, argv, "cv:f:")) != -1) { -+ switch (opt) { -+ case 'c': -+ enable_csum = 1; -+ break; -+ case 'f': -+ if (current_fs->journal_name) -+ free(current_fs->journal_name); -+ current_fs->journal_name = strdup(optarg); -+ break; -+ case 'v': -+ csum_ver = atoi(optarg); -+ if (csum_ver != 2 && csum_ver != 3) { -+ printf("Unknown journal csum v%d\n", csum_ver); -+ csum_ver = 3; -+ } -+ break; -+ default: -+ printf("%s: [-c] [-v ver] [-f ext_jnl]\n", argv[0]); -+ printf("-c: Enable journal checksumming.\n"); -+ printf("-v: Use this version checksum format.\n"); -+ printf("-j: Load this external journal.\n"); -+ } -+ } -+ -+ err = ext2fs_open_journal(current_fs, ¤t_journal); -+ if (err) { -+ com_err(argv[0], err, "while opening journal"); -+ return; -+ } -+ journal = current_journal; -+ -+ dbg_printf("JOURNAL: seq=%d tailseq=%d start=%lu first=%lu " -+ "maxlen=%lu\n", journal->j_tail_sequence, -+ journal->j_transaction_sequence, journal->j_tail, -+ journal->j_first, journal->j_last); -+ -+ update_uuid(journal); -+ update_64bit_flag(journal); -+ if (enable_csum) -+ update_journal_csum(journal, csum_ver); -+ -+ err = journal_find_head(journal); -+ if (err) -+ com_err(argv[0], err, "while examining journal"); -+} -+ -+void do_journal_close(int argc EXT2FS_ATTR((unused)), -+ char *argv[] EXT2FS_ATTR((unused))) -+{ -+ if (current_journal == NULL) { -+ printf("Journal not open.\n"); -+ return; -+ } -+ -+ ext2fs_close_journal(current_fs, ¤t_journal); -+} -+ -+void do_journal_run(int argc EXT2FS_ATTR((unused)), char *argv[]) -+{ -+ errcode_t err; -+ -+ if (check_fs_open(argv[0])) -+ return; -+ if (check_fs_read_write(argv[0])) -+ return; -+ if (check_fs_bitmaps(argv[0])) -+ return; -+ if (current_journal) { -+ printf("Please close the journal before recovering it.\n"); -+ return; -+ } -+ -+ err = ext2fs_run_ext3_journal(¤t_fs); -+ if (err) -+ com_err("journal_run", err, "while recovering journal"); -+ else { -+ current_fs->super->s_feature_incompat &= -+ ~EXT3_FEATURE_INCOMPAT_RECOVER; -+ ext2fs_mark_super_dirty(current_fs); -+ } -+} -diff --git a/debugfs/dump.c b/debugfs/dump.c -index 8d97886..1dc6154 100644 ---- a/debugfs/dump.c -+++ b/debugfs/dump.c -@@ -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; - -diff --git a/debugfs/extent_inode.c b/debugfs/extent_inode.c -index 8b22f5e..c7a92a7 100644 ---- a/debugfs/extent_inode.c -+++ b/debugfs/extent_inode.c -@@ -97,6 +97,11 @@ void do_extent_open(int argc, char *argv[]) - - orig_prompt = ss_get_prompt(sci_idx); - extent_prompt = malloc(strlen(orig_prompt) + 32); -+ if (extent_prompt == NULL) { -+ com_err(argv[1], retval, "out of memory"); -+ return; -+ } -+ - strcpy(extent_prompt, orig_prompt); - cp = strchr(extent_prompt, ':'); - if (cp) -diff --git a/debugfs/filefrag.c b/debugfs/filefrag.c -index 0adea40..49345ad 100644 ---- a/debugfs/filefrag.c -+++ b/debugfs/filefrag.c -@@ -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; -diff --git a/debugfs/htree.c b/debugfs/htree.c -index 24f8250..83f558c 100644 ---- a/debugfs/htree.c -+++ b/debugfs/htree.c -@@ -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)) { -+ ((unsigned) 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"); -@@ -118,19 +138,33 @@ static void htree_dump_int_node(ext2_filsys fs, ext2_ino_t ino, - struct ext2_dx_entry *ent, - char *buf, int level) - { -- struct ext2_dx_countlimit limit; -- struct ext2_dx_entry e; -+ struct ext2_dx_countlimit dx_countlimit; -+ struct ext2_dx_tail *tail; - int hash, i; -+ int limit, count; -+ int remainder; -+ -+ dx_countlimit = *((struct ext2_dx_countlimit *) ent); -+ count = ext2fs_le16_to_cpu(dx_countlimit.count); -+ limit = ext2fs_le16_to_cpu(dx_countlimit.limit); -+ -+ fprintf(pager, "Number of entries (count): %d\n", count); -+ fprintf(pager, "Number of entries (limit): %d\n", limit); -+ -+ remainder = fs->blocksize - (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); -+ fprintf(pager, "Checksum: 0x%08x\n", -+ ext2fs_le32_to_cpu(tail->dt_checksum)); -+ } - -- -- limit = *((struct ext2_dx_countlimit *) ent); -- limit.count = ext2fs_le16_to_cpu(limit.count); -- limit.limit = ext2fs_le16_to_cpu(limit.limit); -- -- fprintf(pager, "Number of entries (count): %d\n", limit.count); -- fprintf(pager, "Number of entries (limit): %d\n", limit.limit); -- -- for (i=0; i < limit.count; i++) { -+ for (i=0; i < count; i++) { - hash = i ? ext2fs_le32_to_cpu(ent[i].hash) : 0; - fprintf(pager, "Entry #%d: Hash 0x%08x%s, block %u\n", i, - hash, (hash & 1) ? " (**)" : "", -@@ -139,17 +173,19 @@ static void htree_dump_int_node(ext2_filsys fs, ext2_ino_t ino, - - fprintf(pager, "\n"); - -- for (i=0; i < limit.count; i++) { -- e.hash = ext2fs_le32_to_cpu(ent[i].hash); -- e.block = ext2fs_le32_to_cpu(ent[i].block); -+ for (i=0; i < count; i++) { -+ unsigned int hashval, block; -+ -+ hashval = ext2fs_le32_to_cpu(ent[i].hash); -+ block = ext2fs_le32_to_cpu(ent[i].block); - fprintf(pager, "Entry #%d: Hash 0x%08x, block %u\n", i, -- i ? e.hash : 0, e.block); -+ i ? hashval : 0, block); - if (level) - htree_dump_int_block(fs, ino, inode, rootnode, -- e.block, buf, level-1); -+ block, buf, level-1); - else - htree_dump_leaf_node(fs, ino, inode, rootnode, -- e.block, buf); -+ block, buf); - } - - fprintf(pager, "---------------------\n"); -@@ -393,7 +429,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, " -diff --git a/debugfs/jfs_user.h b/debugfs/jfs_user.h -deleted file mode 100644 -index 3070cd5..0000000 ---- a/debugfs/jfs_user.h -+++ /dev/null -@@ -1,8 +0,0 @@ --#ifndef _JFS_USER_H --#define _JFS_USER_H -- --typedef unsigned short kdev_t; -- --#include -- --#endif /* _JFS_USER_H */ -diff --git a/debugfs/journal.c b/debugfs/journal.c -new file mode 100644 -index 0000000..9f0d7fc ---- /dev/null -+++ b/debugfs/journal.c -@@ -0,0 +1,937 @@ -+/* -+ * journal.c --- code for handling the "ext3" journal -+ * -+ * Copyright (C) 2000 Andreas Dilger -+ * Copyright (C) 2000 Theodore Ts'o -+ * -+ * Parts of the code are based on fs/jfs/journal.c by Stephen C. Tweedie -+ * Copyright (C) 1999 Red Hat Software -+ * -+ * This file may be redistributed under the terms of the -+ * GNU General Public License version 2 or at your discretion -+ * any later version. -+ */ -+ -+#include "config.h" -+#ifdef HAVE_SYS_MOUNT_H -+#include -+#include -+#define MNT_FL (MS_MGC_VAL | MS_RDONLY) -+#endif -+#ifdef HAVE_SYS_STAT_H -+#include -+#endif -+ -+#define E2FSCK_INCLUDE_INLINE_FUNCS -+#include "uuid/uuid.h" -+#include "journal.h" -+ -+#ifdef CONFIG_JBD_DEBUG /* Enabled by configure --enable-jfs-debug */ -+static int bh_count = 0; -+#endif -+ -+#if EXT2_FLAT_INCLUDES -+#include "blkid.h" -+#else -+#include "blkid/blkid.h" -+#endif -+ -+/* -+ * Define USE_INODE_IO to use the inode_io.c / fileio.c codepaths. -+ * This creates a larger static binary, and a smaller binary using -+ * shared libraries. It's also probably slightly less CPU-efficient, -+ * which is why it's not on by default. But, it's a good way of -+ * testing the functions in inode_io.c and fileio.c. -+ */ -+#undef USE_INODE_IO -+ -+/* Checksumming functions */ -+static int ext2fs_journal_verify_csum_type(journal_t *j, -+ journal_superblock_t *jsb) -+{ -+ if (!journal_has_csum_v2or3(j)) -+ return 1; -+ -+ return jsb->s_checksum_type == JBD2_CRC32C_CHKSUM; -+} -+ -+static __u32 ext2fs_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 ext2fs_journal_sb_csum_verify(journal_t *j, -+ journal_superblock_t *jsb) -+{ -+ __u32 provided, calculated; -+ -+ if (!journal_has_csum_v2or3(j)) -+ return 1; -+ -+ provided = ext2fs_be32_to_cpu(jsb->s_checksum); -+ calculated = ext2fs_journal_sb_csum(jsb); -+ -+ return provided == calculated; -+} -+ -+static errcode_t ext2fs_journal_sb_csum_set(journal_t *j, -+ journal_superblock_t *jsb) -+{ -+ __u32 crc; -+ -+ if (!journal_has_csum_v2or3(j)) -+ return 0; -+ -+ crc = ext2fs_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. -+ */ -+int journal_bmap(journal_t *journal, blk64_t block, unsigned long long *phys) -+{ -+#ifdef USE_INODE_IO -+ *phys = block; -+ return 0; -+#else -+ struct inode *inode = journal->j_inode; -+ errcode_t retval; -+ blk64_t pblk; -+ -+ if (!inode) { -+ *phys = block; -+ return 0; -+ } -+ -+ retval = ext2fs_bmap2(inode->i_fs, inode->i_ino, -+ &inode->i_ext2, NULL, 0, block, 0, &pblk); -+ *phys = pblk; -+ return (int) retval; -+#endif -+} -+ -+struct buffer_head *getblk(kdev_t kdev, blk64_t blocknr, int blocksize) -+{ -+ struct buffer_head *bh; -+ int bufsize = sizeof(*bh) + kdev->k_fs->blocksize - -+ sizeof(bh->b_data); -+ errcode_t retval; -+ -+ retval = ext2fs_get_memzero(bufsize, &bh); -+ if (retval) -+ return NULL; -+ -+#ifdef CONFIG_JBD_DEBUG -+ if (journal_enable_debug >= 3) -+ bh_count++; -+#endif -+ jfs_debug(4, "getblk for block %llu (%d bytes)(total %d)\n", -+ (unsigned long long) blocknr, blocksize, bh_count); -+ -+ bh->b_fs = kdev->k_fs; -+ if (kdev->k_dev == K_DEV_FS) -+ bh->b_io = kdev->k_fs->io; -+ else -+ bh->b_io = kdev->k_fs->journal_io; -+ bh->b_size = blocksize; -+ bh->b_blocknr = blocknr; -+ -+ return bh; -+} -+ -+int sync_blockdev(kdev_t kdev) -+{ -+ io_channel io; -+ -+ if (kdev->k_dev == K_DEV_FS) -+ io = kdev->k_fs->io; -+ else -+ io = kdev->k_fs->journal_io; -+ -+ return io_channel_flush(io) ? EIO : 0; -+} -+ -+void ll_rw_block(int rw, int nr, struct buffer_head *bhp[]) -+{ -+ errcode_t retval; -+ struct buffer_head *bh; -+ -+ for (; nr > 0; --nr) { -+ bh = *bhp++; -+ if (rw == READ && !bh->b_uptodate) { -+ jfs_debug(3, "reading block %llu/%p\n", -+ bh->b_blocknr, (void *) bh); -+ retval = io_channel_read_blk64(bh->b_io, -+ bh->b_blocknr, -+ 1, bh->b_data); -+ if (retval) { -+ com_err(bh->b_fs->device_name, retval, -+ "while reading block %llu\n", -+ bh->b_blocknr); -+ bh->b_err = (int) retval; -+ continue; -+ } -+ bh->b_uptodate = 1; -+ } else if (rw == WRITE && bh->b_dirty) { -+ jfs_debug(3, "writing block %llu/%p\n", -+ bh->b_blocknr, -+ (void *) bh); -+ retval = io_channel_write_blk64(bh->b_io, -+ bh->b_blocknr, -+ 1, bh->b_data); -+ if (retval) { -+ com_err(bh->b_fs->device_name, retval, -+ "while writing block %llu\n", -+ bh->b_blocknr); -+ bh->b_err = (int) retval; -+ continue; -+ } -+ bh->b_dirty = 0; -+ bh->b_uptodate = 1; -+ } else { -+ jfs_debug(3, "no-op %s for block %llu\n", -+ rw == READ ? "read" : "write", -+ bh->b_blocknr); -+ } -+ } -+} -+ -+void mark_buffer_dirty(struct buffer_head *bh) -+{ -+ bh->b_dirty = 1; -+} -+ -+static void mark_buffer_clean(struct buffer_head *bh) -+{ -+ bh->b_dirty = 0; -+} -+ -+void brelse(struct buffer_head *bh) -+{ -+ if (bh->b_dirty) -+ ll_rw_block(WRITE, 1, &bh); -+ jfs_debug(3, "freeing block %llu/%p (total %d)\n", -+ bh->b_blocknr, (void *) bh, --bh_count); -+ ext2fs_free_mem(&bh); -+} -+ -+int buffer_uptodate(struct buffer_head *bh) -+{ -+ return bh->b_uptodate; -+} -+ -+void mark_buffer_uptodate(struct buffer_head *bh, int val) -+{ -+ bh->b_uptodate = val; -+} -+ -+void wait_on_buffer(struct buffer_head *bh) -+{ -+ if (!bh->b_uptodate) -+ ll_rw_block(READ, 1, &bh); -+} -+ -+ -+static void ext2fs_clear_recover(ext2_filsys fs, int error) -+{ -+ fs->super->s_feature_incompat &= ~EXT3_FEATURE_INCOMPAT_RECOVER; -+ -+ /* if we had an error doing journal recovery, we need a full fsck */ -+ if (error) -+ fs->super->s_state &= ~EXT2_VALID_FS; -+ ext2fs_mark_super_dirty(fs); -+} -+ -+/* -+ * This is a helper function to check the validity of the journal. -+ */ -+struct process_block_struct { -+ e2_blkcnt_t last_block; -+}; -+ -+static int process_journal_block(ext2_filsys fs, -+ blk64_t *block_nr, -+ e2_blkcnt_t blockcnt, -+ blk64_t ref_block EXT2FS_ATTR((unused)), -+ int ref_offset EXT2FS_ATTR((unused)), -+ void *priv_data) -+{ -+ struct process_block_struct *p; -+ blk64_t blk = *block_nr; -+ -+ p = (struct process_block_struct *) priv_data; -+ -+ if (!blk || blk < fs->super->s_first_data_block || -+ blk >= ext2fs_blocks_count(fs->super)) -+ return BLOCK_ABORT; -+ -+ if (blockcnt >= 0) -+ p->last_block = blockcnt; -+ return 0; -+} -+ -+static errcode_t ext2fs_get_journal(ext2_filsys fs, journal_t **ret_journal) -+{ -+ struct process_block_struct pb; -+ struct ext2_super_block *sb = fs->super; -+ struct ext2_super_block jsuper; -+ struct buffer_head *bh; -+ struct inode *j_inode = NULL; -+ struct kdev_s *dev_fs = NULL, *dev_journal; -+ const char *journal_name = 0; -+ journal_t *journal = NULL; -+ errcode_t retval = 0; -+ io_manager io_ptr = 0; -+ unsigned long long start = 0; -+ int ext_journal = 0; -+ int tried_backup_jnl = 0; -+ -+ retval = ext2fs_get_memzero(sizeof(journal_t), &journal); -+ if (retval) -+ return retval; -+ -+ retval = ext2fs_get_memzero(2 * sizeof(struct kdev_s), &dev_fs); -+ if (retval) -+ goto errout; -+ dev_journal = dev_fs+1; -+ -+ dev_fs->k_fs = dev_journal->k_fs = fs; -+ dev_fs->k_dev = K_DEV_FS; -+ dev_journal->k_dev = K_DEV_JOURNAL; -+ -+ journal->j_dev = dev_journal; -+ journal->j_fs_dev = dev_fs; -+ journal->j_inode = NULL; -+ journal->j_blocksize = fs->blocksize; -+ -+ if (uuid_is_null(sb->s_journal_uuid)) { -+ if (!sb->s_journal_inum) { -+ retval = EXT2_ET_BAD_INODE_NUM; -+ goto errout; -+ } -+ retval = ext2fs_get_memzero(sizeof(*j_inode), &j_inode); -+ if (retval) -+ goto errout; -+ -+ j_inode->i_fs = fs; -+ j_inode->i_ino = sb->s_journal_inum; -+ -+ retval = ext2fs_read_inode(fs, sb->s_journal_inum, -+ &j_inode->i_ext2); -+ if (retval) { -+try_backup_journal: -+ if (sb->s_jnl_backup_type != EXT3_JNL_BACKUP_BLOCKS || -+ tried_backup_jnl) -+ goto errout; -+ memset(&j_inode->i_ext2, 0, sizeof(struct ext2_inode)); -+ memcpy(&j_inode->i_ext2.i_block[0], sb->s_jnl_blocks, -+ EXT2_N_BLOCKS*4); -+ j_inode->i_ext2.i_size_high = sb->s_jnl_blocks[15]; -+ j_inode->i_ext2.i_size = sb->s_jnl_blocks[16]; -+ j_inode->i_ext2.i_links_count = 1; -+ j_inode->i_ext2.i_mode = LINUX_S_IFREG | 0600; -+ tried_backup_jnl++; -+ } -+ if (!j_inode->i_ext2.i_links_count || -+ !LINUX_S_ISREG(j_inode->i_ext2.i_mode)) { -+ retval = EXT2_ET_NO_JOURNAL; -+ goto try_backup_journal; -+ } -+ if (EXT2_I_SIZE(&j_inode->i_ext2) / journal->j_blocksize < -+ JFS_MIN_JOURNAL_BLOCKS) { -+ retval = EXT2_ET_JOURNAL_TOO_SMALL; -+ goto try_backup_journal; -+ } -+ pb.last_block = -1; -+ retval = ext2fs_block_iterate3(fs, j_inode->i_ino, -+ BLOCK_FLAG_HOLE, 0, -+ process_journal_block, &pb); -+ if ((pb.last_block + 1) * fs->blocksize < -+ (int) EXT2_I_SIZE(&j_inode->i_ext2)) { -+ retval = EXT2_ET_JOURNAL_TOO_SMALL; -+ goto try_backup_journal; -+ } -+ if (tried_backup_jnl && (fs->flags & EXT2_FLAG_RW)) { -+ retval = ext2fs_write_inode(fs, sb->s_journal_inum, -+ &j_inode->i_ext2); -+ if (retval) -+ goto errout; -+ } -+ -+ journal->j_maxlen = EXT2_I_SIZE(&j_inode->i_ext2) / -+ journal->j_blocksize; -+ -+#ifdef USE_INODE_IO -+ retval = ext2fs_inode_io_intern2(fs, sb->s_journal_inum, -+ &j_inode->i_ext2, -+ &journal_name); -+ if (retval) -+ goto errout; -+ -+ io_ptr = inode_io_manager; -+#else -+ journal->j_inode = j_inode; -+ fs->journal_io = fs->io; -+ retval = (errcode_t)journal_bmap(journal, 0, &start); -+ if (retval) -+ goto errout; -+#endif -+ } else { -+ ext_journal = 1; -+ if (!fs->journal_name) { -+ char uuid[37]; -+ blkid_cache blkid; -+ -+ blkid_get_cache(&blkid, NULL); -+ uuid_unparse(sb->s_journal_uuid, uuid); -+ fs->journal_name = blkid_get_devname(blkid, -+ "UUID", uuid); -+ if (!fs->journal_name) -+ fs->journal_name = blkid_devno_to_devname(sb->s_journal_dev); -+ blkid_put_cache(blkid); -+ } -+ journal_name = fs->journal_name; -+ -+ if (!journal_name) { -+ retval = EXT2_ET_LOAD_EXT_JOURNAL; -+ goto errout; -+ } -+ -+ jfs_debug(1, "Using journal file %s\n", journal_name); -+ io_ptr = unix_io_manager; -+ } -+ -+#if 0 -+ test_io_backing_manager = io_ptr; -+ io_ptr = test_io_manager; -+#endif -+#ifndef USE_INODE_IO -+ if (ext_journal) -+#endif -+ { -+ retval = io_ptr->open(journal_name, fs->flags & EXT2_FLAG_RW, -+ &fs->journal_io); -+ } -+ if (retval) -+ goto errout; -+ -+ io_channel_set_blksize(fs->journal_io, fs->blocksize); -+ -+ if (ext_journal) { -+ blk64_t maxlen; -+ -+ start = ext2fs_journal_sb_start(fs->blocksize) - 1; -+ bh = getblk(dev_journal, start, fs->blocksize); -+ if (!bh) { -+ retval = EXT2_ET_NO_MEMORY; -+ goto errout; -+ } -+ ll_rw_block(READ, 1, &bh); -+ retval = bh->b_err; -+ if (retval) { -+ brelse(bh); -+ goto errout; -+ } -+ memcpy(&jsuper, start ? bh->b_data : -+ bh->b_data + SUPERBLOCK_OFFSET, -+ sizeof(jsuper)); -+#ifdef WORDS_BIGENDIAN -+ if (jsuper.s_magic == ext2fs_swab16(EXT2_SUPER_MAGIC)) -+ ext2fs_swap_super(&jsuper); -+#endif -+ if (jsuper.s_magic != EXT2_SUPER_MAGIC || -+ !(jsuper.s_feature_incompat & -+ EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)) { -+ retval = EXT2_ET_LOAD_EXT_JOURNAL; -+ brelse(bh); -+ goto errout; -+ } -+ /* Make sure the journal UUID is correct */ -+ if (memcmp(jsuper.s_uuid, fs->super->s_journal_uuid, -+ sizeof(jsuper.s_uuid))) { -+ retval = EXT2_ET_LOAD_EXT_JOURNAL; -+ brelse(bh); -+ goto errout; -+ } -+ -+ /* Check the superblock checksum */ -+ if (jsuper.s_feature_ro_compat & -+ EXT4_FEATURE_RO_COMPAT_METADATA_CSUM) { -+ struct struct_ext2_filsys fsx; -+ struct ext2_super_block superx; -+ void *p; -+ -+ p = start ? bh->b_data : bh->b_data + SUPERBLOCK_OFFSET; -+ memcpy(&fsx, fs, sizeof(fsx)); -+ memcpy(&superx, fs->super, sizeof(superx)); -+ fsx.super = &superx; -+ fsx.super->s_feature_ro_compat |= -+ EXT4_FEATURE_RO_COMPAT_METADATA_CSUM; -+ if (!ext2fs_superblock_csum_verify(&fsx, p)) { -+ retval = EXT2_ET_LOAD_EXT_JOURNAL; -+ brelse(bh); -+ goto errout; -+ } -+ } -+ brelse(bh); -+ -+ maxlen = ext2fs_blocks_count(&jsuper); -+ journal->j_maxlen = (maxlen < 1ULL << 32) ? maxlen : -+ (1ULL << 32) - 1; -+ start++; -+ } -+ -+ bh = getblk(dev_journal, start, journal->j_blocksize); -+ if (!bh) { -+ retval = EXT2_ET_NO_MEMORY; -+ goto errout; -+ } -+ -+ journal->j_sb_buffer = bh; -+ journal->j_superblock = (journal_superblock_t *)bh->b_data; -+ -+#ifdef USE_INODE_IO -+ if (j_inode) -+ ext2fs_free_mem(&j_inode); -+#endif -+ -+ *ret_journal = journal; -+ return 0; -+ -+errout: -+ if (dev_fs) -+ ext2fs_free_mem(&dev_fs); -+ if (j_inode) -+ ext2fs_free_mem(&j_inode); -+ if (journal) -+ ext2fs_free_mem(&journal); -+ return retval; -+} -+ -+static errcode_t ext2fs_journal_fix_bad_inode(ext2_filsys fs) -+{ -+ struct ext2_super_block *sb = fs->super; -+ int recover = fs->super->s_feature_incompat & -+ EXT3_FEATURE_INCOMPAT_RECOVER; -+ int has_journal = fs->super->s_feature_compat & -+ EXT3_FEATURE_COMPAT_HAS_JOURNAL; -+ -+ if (has_journal || sb->s_journal_inum) { -+ /* The journal inode is bogus, remove and force full fsck */ -+ return EXT2_ET_BAD_INODE_NUM; -+ } else if (recover) { -+ return EXT2_ET_UNSUPP_FEATURE; -+ } -+ return 0; -+} -+ -+#define V1_SB_SIZE 0x0024 -+static void clear_v2_journal_fields(journal_t *journal) -+{ -+ ext2_filsys fs = journal->j_dev->k_fs; -+ -+ memset(((char *) journal->j_superblock) + V1_SB_SIZE, 0, -+ fs->blocksize-V1_SB_SIZE); -+ mark_buffer_dirty(journal->j_sb_buffer); -+} -+ -+ -+static errcode_t ext2fs_journal_load(journal_t *journal) -+{ -+ ext2_filsys fs = journal->j_dev->k_fs; -+ journal_superblock_t *jsb; -+ struct buffer_head *jbh = journal->j_sb_buffer; -+ -+ ll_rw_block(READ, 1, &jbh); -+ if (jbh->b_err) -+ return jbh->b_err; -+ -+ jsb = journal->j_superblock; -+ /* If we don't even have JFS_MAGIC, we probably have a wrong inode */ -+ if (jsb->s_header.h_magic != htonl(JFS_MAGIC_NUMBER)) -+ return ext2fs_journal_fix_bad_inode(fs); -+ -+ switch (ntohl(jsb->s_header.h_blocktype)) { -+ case JFS_SUPERBLOCK_V1: -+ journal->j_format_version = 1; -+ if (jsb->s_feature_compat || -+ jsb->s_feature_incompat || -+ jsb->s_feature_ro_compat || -+ jsb->s_nr_users) -+ clear_v2_journal_fields(journal); -+ break; -+ -+ case JFS_SUPERBLOCK_V2: -+ journal->j_format_version = 2; -+ if (ntohl(jsb->s_nr_users) > 1 && -+ uuid_is_null(fs->super->s_journal_uuid)) -+ clear_v2_journal_fields(journal); -+ if (ntohl(jsb->s_nr_users) > 1) -+ return EXT2_ET_JOURNAL_UNSUPP_VERSION; -+ break; -+ -+ /* -+ * These should never appear in a journal super block, so if -+ * they do, the journal is badly corrupted. -+ */ -+ case JFS_DESCRIPTOR_BLOCK: -+ case JFS_COMMIT_BLOCK: -+ case JFS_REVOKE_BLOCK: -+ return EXT2_ET_CORRUPT_SUPERBLOCK; -+ -+ /* If we don't understand the superblock major type, but there -+ * is a magic number, then it is likely to be a new format we -+ * just don't understand, so leave it alone. */ -+ default: -+ return EXT2_ET_JOURNAL_UNSUPP_VERSION; -+ } -+ -+ if (JFS_HAS_INCOMPAT_FEATURE(journal, ~JFS_KNOWN_INCOMPAT_FEATURES)) -+ return EXT2_ET_UNSUPP_FEATURE; -+ -+ if (JFS_HAS_RO_COMPAT_FEATURE(journal, ~JFS_KNOWN_ROCOMPAT_FEATURES)) -+ return EXT2_ET_RO_UNSUPP_FEATURE; -+ -+ /* Checksum v1-3 are mutually exclusive features. */ -+ if (JFS_HAS_INCOMPAT_FEATURE(journal, JFS_FEATURE_INCOMPAT_CSUM_V2) && -+ JFS_HAS_INCOMPAT_FEATURE(journal, JFS_FEATURE_INCOMPAT_CSUM_V3)) -+ return EXT2_ET_CORRUPT_SUPERBLOCK; -+ -+ if (journal_has_csum_v2or3(journal) && -+ JFS_HAS_COMPAT_FEATURE(journal, JFS_FEATURE_COMPAT_CHECKSUM)) -+ return EXT2_ET_CORRUPT_SUPERBLOCK; -+ -+ if (!ext2fs_journal_verify_csum_type(journal, jsb) || -+ !ext2fs_journal_sb_csum_verify(journal, jsb)) -+ return EXT2_ET_CORRUPT_SUPERBLOCK; -+ -+ if (journal_has_csum_v2or3(journal)) -+ journal->j_csum_seed = jbd2_chksum(journal, ~0, jsb->s_uuid, -+ sizeof(jsb->s_uuid)); -+ -+ /* 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. */ -+ if (jsb->s_blocksize != htonl(journal->j_blocksize)) -+ return EXT2_ET_CORRUPT_SUPERBLOCK; -+ -+ if (ntohl(jsb->s_maxlen) < journal->j_maxlen) -+ journal->j_maxlen = ntohl(jsb->s_maxlen); -+ else if (ntohl(jsb->s_maxlen) > journal->j_maxlen) -+ return EXT2_ET_CORRUPT_SUPERBLOCK; -+ -+ journal->j_tail_sequence = ntohl(jsb->s_sequence); -+ journal->j_transaction_sequence = journal->j_tail_sequence; -+ journal->j_tail = ntohl(jsb->s_start); -+ journal->j_first = ntohl(jsb->s_first); -+ journal->j_last = ntohl(jsb->s_maxlen); -+ -+ return 0; -+} -+ -+static void ext2fs_journal_release(ext2_filsys fs, journal_t *journal, -+ int reset, int drop) -+{ -+ journal_superblock_t *jsb; -+ -+ if (drop) -+ mark_buffer_clean(journal->j_sb_buffer); -+ else if (fs->flags & EXT2_FLAG_RW) { -+ jsb = journal->j_superblock; -+ jsb->s_sequence = htonl(journal->j_tail_sequence); -+ if (reset) -+ jsb->s_start = 0; /* this marks the journal as empty */ -+ ext2fs_journal_sb_csum_set(journal, jsb); -+ mark_buffer_dirty(journal->j_sb_buffer); -+ } -+ brelse(journal->j_sb_buffer); -+ -+ if (fs && fs->journal_io) { -+ if (fs->io != fs->journal_io) -+ io_channel_close(fs->journal_io); -+ fs->journal_io = NULL; -+ } -+ -+#ifndef USE_INODE_IO -+ if (journal->j_inode) -+ ext2fs_free_mem(&journal->j_inode); -+#endif -+ if (journal->j_fs_dev) -+ ext2fs_free_mem(&journal->j_fs_dev); -+ ext2fs_free_mem(&journal); -+} -+ -+/* -+ * This function makes sure that the superblock fields regarding the -+ * journal are consistent. -+ */ -+static errcode_t ext2fs_check_ext3_journal(ext2_filsys fs) -+{ -+ struct ext2_super_block *sb = fs->super; -+ journal_t *journal; -+ int recover = fs->super->s_feature_incompat & -+ EXT3_FEATURE_INCOMPAT_RECOVER; -+ errcode_t retval; -+ -+ /* If we don't have any journal features, don't do anything more */ -+ if (!(sb->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL) && -+ !recover && sb->s_journal_inum == 0 && sb->s_journal_dev == 0 && -+ uuid_is_null(sb->s_journal_uuid)) -+ return 0; -+ -+ retval = ext2fs_get_journal(fs, &journal); -+ if (retval) -+ return retval; -+ -+ retval = ext2fs_journal_load(journal); -+ if (retval) -+ goto err; -+ -+ /* -+ * We want to make the flags consistent here. We will not leave with -+ * needs_recovery set but has_journal clear. We can't get in a loop -+ * with -y, -n, or -p, only if a user isn't making up their mind. -+ */ -+ if (!(sb->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL)) { -+ retval = EXT2_ET_JOURNAL_FLAGS_WRONG; -+ goto err; -+ } -+ -+ if (sb->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL && -+ !(sb->s_feature_incompat & EXT3_FEATURE_INCOMPAT_RECOVER) && -+ journal->j_superblock->s_start != 0) { -+ retval = EXT2_ET_JOURNAL_FLAGS_WRONG; -+ goto err; -+ } -+ -+ /* -+ * If we don't need to do replay the journal, check to see if -+ * the journal's errno is set; if so, we need to mark the file -+ * system as being corrupt and clear the journal's s_errno. -+ */ -+ if (!(sb->s_feature_incompat & EXT3_FEATURE_INCOMPAT_RECOVER) && -+ journal->j_superblock->s_errno) { -+ fs->super->s_state |= EXT2_ERROR_FS; -+ ext2fs_mark_super_dirty(fs); -+ journal->j_superblock->s_errno = 0; -+ ext2fs_journal_sb_csum_set(journal, journal->j_superblock); -+ mark_buffer_dirty(journal->j_sb_buffer); -+ } -+ -+err: -+ ext2fs_journal_release(fs, journal, 0, retval ? 1 : 0); -+ return retval; -+} -+ -+static errcode_t recover_ext3_journal(ext2_filsys fs) -+{ -+ journal_t *journal; -+ errcode_t retval; -+ -+ journal_init_revoke_caches(); -+ retval = ext2fs_get_journal(fs, &journal); -+ if (retval) -+ return retval; -+ -+ retval = ext2fs_journal_load(journal); -+ if (retval) -+ goto errout; -+ -+ retval = journal_init_revoke(journal, 1024); -+ if (retval) -+ goto errout; -+ -+ retval = -journal_recover(journal); -+ if (retval) -+ goto errout; -+ -+ if (journal->j_failed_commit) { -+ journal->j_superblock->s_errno = -EINVAL; -+ mark_buffer_dirty(journal->j_sb_buffer); -+ } -+ -+errout: -+ journal_destroy_revoke(journal); -+ journal_destroy_revoke_caches(); -+ ext2fs_journal_release(fs, journal, 1, 0); -+ return retval; -+} -+ -+errcode_t ext2fs_run_ext3_journal(ext2_filsys *fsp) -+{ -+ ext2_filsys fs = *fsp; -+ io_manager io_ptr = fs->io->manager; -+ errcode_t retval, recover_retval; -+ io_stats stats = 0; -+ unsigned long long kbytes_written = 0; -+ char *fsname; -+ int fsflags; -+ int fsblocksize; -+ -+ if (!(fs->flags & EXT2_FLAG_RW)) -+ return EXT2_ET_FILE_RO; -+ -+ if (fs->flags & EXT2_FLAG_DIRTY) -+ ext2fs_flush(fs); /* Force out any modifications */ -+ -+ recover_retval = recover_ext3_journal(fs); -+ -+ /* -+ * Reload the filesystem context to get up-to-date data from disk -+ * because journal recovery will change the filesystem under us. -+ */ -+ if (fs->super->s_kbytes_written && -+ fs->io->manager->get_stats) -+ fs->io->manager->get_stats(fs->io, &stats); -+ if (stats && stats->bytes_written) -+ kbytes_written = stats->bytes_written >> 10; -+ -+ ext2fs_mmp_stop(fs); -+ fsname = strdup(fs->device_name); -+ fsflags = fs->flags; -+ fsblocksize = fs->blocksize; -+ ext2fs_free(fs); -+ retval = ext2fs_open(fsname, fsflags, -+ 0, fsblocksize, io_ptr, -+ fsp); -+ free(fsname); -+ if (retval) -+ return retval; -+ -+ fs = *fsp; -+ fs->flags |= EXT2_FLAG_MASTER_SB_ONLY; -+ fs->super->s_kbytes_written += kbytes_written; -+ -+ /* Set the superblock flags */ -+ ext2fs_clear_recover(fs, recover_retval != 0); -+ -+ /* -+ * Do one last sanity check, and propagate journal->s_errno to -+ * the EXT2_ERROR_FS flag in the fs superblock if needed. -+ */ -+ retval = ext2fs_check_ext3_journal(fs); -+ return retval ? retval : recover_retval; -+} -+ -+errcode_t ext2fs_open_journal(ext2_filsys fs, journal_t **j) -+{ -+ journal_t *journal; -+ errcode_t retval; -+ -+ journal_init_revoke_caches(); -+ retval = ext2fs_get_journal(fs, &journal); -+ if (retval) -+ return retval; -+ -+ retval = ext2fs_journal_load(journal); -+ if (retval) -+ goto errout; -+ -+ retval = journal_init_revoke(journal, 1024); -+ if (retval) -+ goto errout; -+ -+ if (journal->j_failed_commit) { -+ journal->j_superblock->s_errno = -EINVAL; -+ mark_buffer_dirty(journal->j_sb_buffer); -+ } -+ -+ *j = journal; -+ return 0; -+ -+errout: -+ journal_destroy_revoke(journal); -+ journal_destroy_revoke_caches(); -+ ext2fs_journal_release(fs, journal, 1, 0); -+ return retval; -+} -+ -+errcode_t ext2fs_close_journal(ext2_filsys fs, journal_t **j) -+{ -+ journal_t *journal = *j; -+ -+ journal_destroy_revoke(journal); -+ journal_destroy_revoke_caches(); -+ ext2fs_journal_release(fs, journal, 0, 0); -+ *j = NULL; -+ -+ return 0; -+} -+ -+void jbd2_commit_block_csum_set(journal_t *j, struct buffer_head *bh) -+{ -+ struct commit_header *h; -+ __u32 csum; -+ -+ if (!journal_has_csum_v2or3(j)) -+ return; -+ -+ h = (struct commit_header *)(bh->b_data); -+ h->h_chksum_type = 0; -+ h->h_chksum_size = 0; -+ h->h_chksum[0] = 0; -+ csum = jbd2_chksum(j, j->j_csum_seed, bh->b_data, j->j_blocksize); -+ h->h_chksum[0] = ext2fs_cpu_to_be32(csum); -+} -+ -+void jbd2_revoke_csum_set(journal_t *j, struct buffer_head *bh) -+{ -+ struct journal_revoke_tail *tail; -+ __u32 csum; -+ -+ if (!journal_has_csum_v2or3(j)) -+ return; -+ -+ tail = (struct journal_revoke_tail *)(bh->b_data + j->j_blocksize - -+ sizeof(struct journal_revoke_tail)); -+ tail->r_checksum = 0; -+ csum = jbd2_chksum(j, j->j_csum_seed, bh->b_data, j->j_blocksize); -+ tail->r_checksum = ext2fs_cpu_to_be32(csum); -+} -+ -+void jbd2_descr_block_csum_set(journal_t *j, struct buffer_head *bh) -+{ -+ struct journal_block_tail *tail; -+ __u32 csum; -+ -+ if (!journal_has_csum_v2or3(j)) -+ return; -+ -+ tail = (struct journal_block_tail *)(bh->b_data + j->j_blocksize - -+ sizeof(struct journal_block_tail)); -+ tail->t_checksum = 0; -+ csum = jbd2_chksum(j, j->j_csum_seed, bh->b_data, j->j_blocksize); -+ tail->t_checksum = ext2fs_cpu_to_be32(csum); -+} -+ -+void jbd2_block_tag_csum_set(journal_t *j, journal_block_tag_t *tag, -+ struct buffer_head *bh, __u32 sequence) -+{ -+ journal_block_tag3_t *tag3 = (journal_block_tag3_t *)tag; -+ __u32 csum32; -+ __be32 seq; -+ -+ if (!journal_has_csum_v2or3(j)) -+ return; -+ -+ seq = ext2fs_cpu_to_be32(sequence); -+ csum32 = jbd2_chksum(j, j->j_csum_seed, (__u8 *)&seq, sizeof(seq)); -+ csum32 = jbd2_chksum(j, csum32, bh->b_data, bh->b_size); -+ -+ if (JFS_HAS_INCOMPAT_FEATURE(j, JFS_FEATURE_INCOMPAT_CSUM_V3)) -+ tag3->t_checksum = ext2fs_cpu_to_be32(csum32); -+ else -+ tag->t_checksum = ext2fs_cpu_to_be16(csum32); -+} -+ -diff --git a/debugfs/journal.h b/debugfs/journal.h -new file mode 100644 -index 0000000..10b638e ---- /dev/null -+++ b/debugfs/journal.h -@@ -0,0 +1,25 @@ -+/* -+ * journal.h -+ * -+ * Copyright (C) 2000 Andreas Dilger -+ * Copyright (C) 2000 Theodore Ts'o -+ * -+ * Parts of the code are based on fs/jfs/journal.c by Stephen C. Tweedie -+ * Copyright (C) 1999 Red Hat Software -+ * -+ * This file may be redistributed under the terms of the -+ * GNU General Public License version 2 or at your discretion -+ * any later version. -+ */ -+ -+#include "jfs_user.h" -+ -+/* journal.c */ -+errcode_t ext2fs_open_journal(ext2_filsys fs, journal_t **j); -+errcode_t ext2fs_close_journal(ext2_filsys fs, journal_t **j); -+errcode_t ext2fs_run_ext3_journal(ext2_filsys *fs); -+void jbd2_commit_block_csum_set(journal_t *j, struct buffer_head *bh); -+void jbd2_revoke_csum_set(journal_t *j, struct buffer_head *bh); -+void jbd2_descr_block_csum_set(journal_t *j, struct buffer_head *bh); -+void jbd2_block_tag_csum_set(journal_t *j, journal_block_tag_t *tag, -+ struct buffer_head *bh, __u32 sequence); -diff --git a/debugfs/logdump.c b/debugfs/logdump.c -index d2c3b30..885e590 100644 ---- a/debugfs/logdump.c -+++ b/debugfs/logdump.c -@@ -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] [-i]\n\t" -+ fprintf(stderr, "%s: Usage: logdump [-acsO] [-b] [-i]\n\t" - "[-f] [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) { -@@ -459,6 +468,23 @@ static void dump_journal(char *cmdname, FILE *out_file, - } - } - -+static inline size_t journal_super_tag_bytes(journal_superblock_t *jsb) -+{ -+ size_t sz; -+ -+ if (JSB_HAS_INCOMPAT_FEATURE(jsb, JFS_FEATURE_INCOMPAT_CSUM_V3)) -+ return sizeof(journal_block_tag3_t); -+ -+ sz = sizeof(journal_block_tag_t); -+ -+ if (JSB_HAS_INCOMPAT_FEATURE(jsb, JFS_FEATURE_INCOMPAT_CSUM_V2)) -+ sz += sizeof(__u16); -+ -+ if (JSB_HAS_INCOMPAT_FEATURE(jsb, JFS_FEATURE_INCOMPAT_64BIT)) -+ return sz; -+ -+ return sz - sizeof(__u32); -+} - - static void dump_descriptor_block(FILE *out_file, - struct journal_source *source, -@@ -467,19 +493,21 @@ static void dump_descriptor_block(FILE *out_file, - unsigned int *blockp, int blocksize, - tid_t transaction) - { -- int offset, tag_size = JBD_TAG_SIZE32; -+ int offset, tag_size, csum_size = 0; - char *tagp; - journal_block_tag_t *tag; - unsigned int blocknr; - __u32 tag_block; - __u32 tag_flags; - -- if (be32_to_cpu(jsb->s_feature_incompat) & JFS_FEATURE_INCOMPAT_64BIT) -- tag_size = JBD_TAG_SIZE64; -- -+ tag_size = journal_super_tag_bytes(jsb); - offset = sizeof(journal_header_t); - blocknr = *blockp; - -+ if (JSB_HAS_INCOMPAT_FEATURE(jsb, JFS_FEATURE_INCOMPAT_CSUM_V3) || -+ JSB_HAS_INCOMPAT_FEATURE(jsb, JFS_FEATURE_INCOMPAT_CSUM_V2)) -+ csum_size = sizeof(struct journal_block_tail); -+ - if (dump_all) - fprintf(out_file, "Dumping descriptor block, sequence %u, at " - "block %u:\n", transaction, blocknr); -@@ -496,11 +524,11 @@ static void dump_descriptor_block(FILE *out_file, - - /* ... and if we have gone too far, then we've reached the - end of this block. */ -- if (offset > blocksize) -+ if (offset > blocksize - csum_size) - 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 +554,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; - } - } - -diff --git a/debugfs/ls.c b/debugfs/ls.c -index b4036de..057e3f6 100644 ---- a/debugfs/ls.c -+++ b/debugfs/ls.c -@@ -30,18 +30,57 @@ extern char *optarg; - */ - - #define LONG_OPT 0x0001 --#define DELETED_OPT 0x0002 --#define PARSE_OPT 0x0004 -+#define PARSE_OPT 0x0002 -+#define RAW_OPT 0x0004 -+#define ENCRYPT_OPT 0x8000 - - struct list_dir_struct { - FILE *f; - int col; - int options; -+ int state; - }; - - static const char *monstr[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", - "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; - -+static int print_filename(FILE *f, struct ext2_dir_entry *dirent, int options) -+{ -+ unsigned char ch; -+ const char *cp = dirent->name; -+ int len = ext2fs_dirent_name_len(dirent); -+ int retlen = 0; -+ -+ if ((options & ENCRYPT_OPT) && !(options & RAW_OPT)) { -+ if (f) -+ return fprintf(f, "", len); -+ else { -+ char tmp[1]; -+ return snprintf(tmp, sizeof(tmp), -+ "", len); -+ } -+ } -+ while (len--) { -+ ch = *cp++; -+ if (ch > 128) { -+ if (f) -+ fputs("M-", f); -+ ch -= 128; -+ retlen += 2; -+ } -+ if ((ch < 32) || (ch == 0x7f)) { -+ if (f) -+ fputc('^', f); -+ ch ^= 0x40; /* ^@, ^A, ^B; ^? for DEL */ -+ retlen++; -+ } -+ if (f) -+ fputc(ch, f); -+ retlen++; -+ } -+ return retlen; -+} -+ - static int list_dir_proc(ext2_ino_t dir EXT2FS_ATTR((unused)), - int entry, - struct ext2_dir_entry *dirent, -@@ -54,17 +93,21 @@ static int list_dir_proc(ext2_ino_t dir EXT2FS_ATTR((unused)), - ext2_ino_t ino; - struct tm *tm_p; - time_t modtime; -- char name[EXT2_NAME_LEN + 1]; - char tmp[EXT2_NAME_LEN + 16]; - char datestr[80]; - char lbr, rbr; - int thislen; -+ int options; - 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; -- strncpy(name, dirent->name, thislen); -- name[thislen] = '\0'; -+ thislen = ext2fs_dirent_name_len(dirent); - ino = dirent->inode; -+ options = ls->options; -+ if (ls->state < 2) { -+ ls->state++; -+ options |= RAW_OPT; -+ } - - if (entry == DIRENT_DELETED_FILE) { - lbr = '<'; -@@ -73,21 +116,22 @@ static int list_dir_proc(ext2_ino_t dir EXT2FS_ATTR((unused)), - } else { - lbr = rbr = ' '; - } -- if (ls->options & PARSE_OPT) { -+ if (options & PARSE_OPT) { - if (ino) { -- if (debugfs_read_inode(ino, &inode, name)) -+ if (debugfs_read_inode(ino, &inode, "ls")) - return 0; - } else - memset(&inode, 0, sizeof(struct ext2_inode)); -- fprintf(ls->f,"/%u/%06o/%d/%d/%s/",ino,inode.i_mode,inode.i_uid, inode.i_gid,name); -+ fprintf(ls->f,"/%u/%06o/%d/%d/%*s/", ino, inode.i_mode, -+ inode.i_uid, inode.i_gid, thislen, dirent->name); - if (LINUX_S_ISDIR(inode.i_mode)) - fprintf(ls->f, "/"); - else - fprintf(ls->f, "%lld/", EXT2_I_SIZE(&inode)); - fprintf(ls->f, "\n"); -- } else if (ls->options & LONG_OPT) { -+ } else if (options & LONG_OPT) { - if (ino) { -- if (debugfs_read_inode(ino, &inode, name)) -+ if (debugfs_read_inode(ino, &inode, "ls")) - return 0; - modtime = inode.i_mtime; - tm_p = localtime(&modtime); -@@ -99,24 +143,48 @@ 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); - else - fprintf(ls->f, "%5llu", EXT2_I_SIZE(&inode)); -- fprintf (ls->f, " %s %s\n", datestr, name); -+ fputs(datestr, ls->f); -+ fputc(' ', ls->f); -+ print_filename(ls->f, dirent, options); -+ fputc('\n', ls->f); - } else { -- sprintf(tmp, "%c%u%c (%d) %s ", lbr, dirent->inode, rbr, -- dirent->rec_len, name); -- thislen = strlen(tmp); -+ if (entry == DIRENT_CHECKSUM) { -+ sprintf(tmp, "%c%u%c (dirblock checksum: 0x%08x) ", -+ lbr, dirent->inode, rbr, t->det_checksum); -+ thislen = strlen(tmp); -+ if (ls->col + thislen > 80) { -+ fputc('\n', ls->f); -+ ls->col = 0; -+ } -+ fprintf(ls->f, "%s", tmp); -+ ls->col += thislen; -+ return 0; -+ } -+ sprintf(tmp, "%c%u%c (%d) ", lbr, dirent->inode, rbr, -+ dirent->rec_len); -+ thislen = strlen(tmp) + 3; -+ thislen += print_filename(NULL, dirent, options); - - if (ls->col + thislen > 80) { -- fprintf(ls->f, "\n"); -+ fputc('\n', ls->f); - ls->col = 0; - } - fprintf(ls->f, "%s", tmp); -+ print_filename(ls->f, dirent, options); -+ fputs(" ", ls->f); - ls->col += thislen; - } - return 0; -@@ -124,28 +192,36 @@ static int list_dir_proc(ext2_ino_t dir EXT2FS_ATTR((unused)), - - void do_list_dir(int argc, char *argv[]) - { -- ext2_ino_t inode; -+ struct ext2_inode inode; -+ ext2_ino_t ino; - int retval; - int c; -- int flags; -+ int flags = DIRENT_FLAG_INCLUDE_EMPTY; - struct list_dir_struct ls; - - ls.options = 0; -+ ls.state = 0; - if (check_fs_open(argv[0])) - return; - - reset_getopt(); -- while ((c = getopt (argc, argv, "dlp")) != EOF) { -+ while ((c = getopt (argc, argv, "cdlpr")) != 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; - break; -+ case 'r': -+ ls.options |= RAW_OPT; -+ break; - default: - goto print_usage; - } -@@ -158,19 +234,22 @@ void do_list_dir(int argc, char *argv[]) - } - - if (argc == optind) -- inode = cwd; -+ ino = cwd; - else -- inode = string_to_inode(argv[optind]); -- if (!inode) -+ ino = string_to_inode(argv[optind]); -+ if (!ino) - return; - - 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, -+ if (debugfs_read_inode(ino, &inode, argv[0])) -+ return; -+ -+ if (inode.i_flags & EXT4_ENCRYPT_FL) -+ ls.options |= ENCRYPT_OPT; -+ -+ retval = ext2fs_dir_iterate2(current_fs, ino, flags, - 0, list_dir_proc, &ls); - fprintf(ls.f, "\n"); - close_pager(ls.f); -diff --git a/debugfs/lsdel.c b/debugfs/lsdel.c -index e5b2d20..a7c30b3 100644 ---- a/debugfs/lsdel.c -+++ b/debugfs/lsdel.c -@@ -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, -diff --git a/debugfs/ncheck.c b/debugfs/ncheck.c -index 58f3a50..5d9b5d2 100644 ---- a/debugfs/ncheck.c -+++ b/debugfs/ncheck.c -@@ -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") && -diff --git a/debugfs/quota.c b/debugfs/quota.c -index 9612f64..7aa0f3b 100644 ---- a/debugfs/quota.c -+++ b/debugfs/quota.c -@@ -90,7 +90,8 @@ static int parse_quota_type(const char *cmdname, const char *str) - } - - --static int list_quota_callback(struct dquot *dq, void *cb_data) -+static int list_quota_callback(struct dquot *dq, -+ void *cb_data EXT2FS_ATTR((unused))) - { - printf("%8u %8lld %8lld %8lld %8lld %8lld %8lld\n", - dq->dq_id, (long long)dq->dq_dqb.dqb_curspace, -diff --git a/debugfs/set_fields.c b/debugfs/set_fields.c -index 6104b2b..b14fec9 100644 ---- a/debugfs/set_fields.c -+++ b/debugfs/set_fields.c -@@ -30,6 +30,7 @@ - #ifdef HAVE_ERRNO_H - #include - #endif -+#include - #if HAVE_STRINGS_H - #include - #endif -@@ -50,6 +51,7 @@ static ext2_ino_t set_ino; - static int array_idx; - - #define FLAG_ARRAY 0x0001 -+#define FLAG_ALIAS 0x0002 /* Data intersects with other field */ - - struct field_set_info { - const char *name; -@@ -72,6 +74,9 @@ static errcode_t parse_gd_csum(struct field_set_info *info, char *field, char *a - static errcode_t parse_mmp_clear(struct field_set_info *info, char *field, - char *arg); - -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wmissing-field-initializers" -+ - static struct field_set_info super_fields[] = { - { "inodes_count", &set_sb.s_inodes_count, NULL, 4, parse_uint }, - { "blocks_count", &set_sb.s_blocks_count, &set_sb.s_blocks_count_hi, -@@ -110,7 +115,6 @@ static struct field_set_info super_fields[] = { - { "uuid", &set_sb.s_uuid, NULL, 16, parse_uuid }, - { "volume_name", &set_sb.s_volume_name, NULL, 16, parse_string }, - { "last_mounted", &set_sb.s_last_mounted, NULL, 64, parse_string }, -- { "lastcheck", &set_sb.s_lastcheck, NULL, 4, parse_uint }, - { "algorithm_usage_bitmap", &set_sb.s_algorithm_usage_bitmap, NULL, - 4, parse_uint }, - { "prealloc_blocks", &set_sb.s_prealloc_blocks, NULL, 1, parse_uint }, -@@ -135,7 +139,6 @@ static struct field_set_info super_fields[] = { - { "want_extra_isize", &set_sb.s_want_extra_isize, NULL, 2, parse_uint }, - { "flags", &set_sb.s_flags, NULL, 4, parse_uint }, - { "raid_stride", &set_sb.s_raid_stride, NULL, 2, parse_uint }, -- { "min_extra_isize", &set_sb.s_min_extra_isize, NULL, 4, parse_uint }, - { "mmp_interval", &set_sb.s_mmp_update_interval, NULL, 2, parse_uint }, - { "mmp_block", &set_sb.s_mmp_block, NULL, 8, parse_uint }, - { "raid_stripe_width", &set_sb.s_raid_stripe_width, NULL, 4, parse_uint }, -@@ -153,22 +156,27 @@ 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 }, -+ { "encryption_level", &set_sb.s_encryption_level, 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 }, - { "first_error_block", &set_sb.s_first_error_block, NULL, 8, parse_uint }, - { "first_error_func", &set_sb.s_first_error_func, NULL, 32, parse_string }, -- { "first_error_line", &set_sb.s_first_error_ino, NULL, 4, parse_uint }, -+ { "first_error_line", &set_sb.s_first_error_line, NULL, 4, parse_uint }, - { "last_error_time", &set_sb.s_last_error_time, NULL, 4, parse_time }, - { "last_error_ino", &set_sb.s_last_error_ino, NULL, 4, parse_uint }, - { "last_error_block", &set_sb.s_last_error_block, NULL, 8, parse_uint }, - { "last_error_func", &set_sb.s_last_error_func, NULL, 32, parse_string }, -- { "last_error_line", &set_sb.s_last_error_ino, NULL, 4, parse_uint }, -+ { "last_error_line", &set_sb.s_last_error_line, NULL, 4, parse_uint }, -+ { "encrypt_algos", &set_sb.s_encrypt_algos, NULL, 1, parse_uint, -+ FLAG_ARRAY, 4 }, -+ { "encrypt_pw_salt", &set_sb.s_encrypt_pw_salt, NULL, 16, parse_uuid }, -+ { "lpf_ino", &set_sb.s_lpf_ino, NULL, 4, parse_uint }, - { 0, 0, 0, 0 } - }; - - static struct field_set_info inode_fields[] = { -- { "inodes_count", &set_sb.s_inodes_count, NULL, 4, parse_uint }, - { "mode", &set_inode.i_mode, NULL, 2, parse_uint }, - { "uid", &set_inode.i_uid, &set_inode.osd2.linux2.l_i_uid_high, - 2, parse_uint }, -@@ -186,7 +194,8 @@ static struct field_set_info inode_fields[] = { - { "flags", &set_inode.i_flags, NULL, 4, parse_uint }, - { "version", &set_inode.osd1.linux1.l_i_version, - &set_inode.i_version_hi, 4, parse_uint }, -- { "translator", &set_inode.osd1.hurd1.h_i_translator, NULL, 4, parse_uint }, -+ { "translator", &set_inode.osd1.hurd1.h_i_translator, NULL, -+ 4, parse_uint, FLAG_ALIAS }, - { "block", &set_inode.i_block[0], NULL, 4, parse_uint, FLAG_ARRAY, - EXT2_NDIR_BLOCKS }, - { "block[IND]", &set_inode.i_block[EXT2_IND_BLOCK], NULL, 4, parse_uint }, -@@ -196,14 +205,14 @@ static struct field_set_info inode_fields[] = { - /* Special case: i_file_acl_high is 2 bytes */ - { "file_acl", &set_inode.i_file_acl, - &set_inode.osd2.linux2.l_i_file_acl_high, 6, parse_uint }, -- { "dir_acl", &set_inode.i_dir_acl, NULL, 4, parse_uint }, -+ { "dir_acl", &set_inode.i_dir_acl, NULL, 4, parse_uint, FLAG_ALIAS }, - { "faddr", &set_inode.i_faddr, NULL, 4, parse_uint }, -- { "frag", &set_inode.osd2.hurd2.h_i_frag, NULL, 1, parse_uint }, -+ { "frag", &set_inode.osd2.hurd2.h_i_frag, NULL, 1, parse_uint, FLAG_ALIAS }, - { "fsize", &set_inode.osd2.hurd2.h_i_fsize, NULL, 1, parse_uint }, - { "checksum", &set_inode.osd2.linux2.l_i_checksum_lo, - &set_inode.i_checksum_hi, 2, parse_uint }, - { "author", &set_inode.osd2.hurd2.h_i_author, NULL, -- 4, parse_uint }, -+ 4, parse_uint, FLAG_ALIAS }, - { "extra_isize", &set_inode.i_extra_isize, NULL, - 2, parse_uint }, - { "ctime_extra", &set_inode.i_ctime_extra, NULL, -@@ -259,7 +268,8 @@ static struct field_set_info ext4_bg_fields[] = { - }; - - static struct field_set_info mmp_fields[] = { -- { "clear", &set_mmp.mmp_magic, NULL, sizeof(set_mmp), parse_mmp_clear }, -+ { "clear", &set_mmp.mmp_magic, NULL, sizeof(set_mmp), -+ parse_mmp_clear, FLAG_ALIAS }, - { "magic", &set_mmp.mmp_magic, NULL, 4, parse_uint }, - { "seq", &set_mmp.mmp_seq, NULL, 4, parse_uint }, - { "time", &set_mmp.mmp_time, NULL, 8, parse_uint }, -@@ -268,7 +278,62 @@ 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 }, -+ { 0, 0, 0, 0 } - }; -+#pragma GCC diagnostic pop -+ -+#ifdef UNITTEST -+ -+ -+static void do_verify_field_set_info(struct field_set_info *fields, -+ const void *data, size_t size) -+{ -+ struct field_set_info *ss, *ss2; -+ const char *begin = (char *)data; -+ const char *end = begin + size; -+ -+ for (ss = fields ; ss->name ; ss++) { -+ const char *ptr; -+ -+ /* Check pointers */ -+ ptr = ss->ptr; -+ assert(!ptr || (ptr >= begin && ptr < end)); -+ ptr = ss->ptr2; -+ assert(!ptr || (ptr >= begin && ptr < end)); -+ -+ /* Check function */ -+ assert(ss->func); -+ -+ for (ss2 = fields ; ss2 != ss ; ss2++) { -+ /* Check duplicate names */ -+ assert(strcmp(ss->name, ss2->name)); -+ -+ if (ss->flags & FLAG_ALIAS || ss2->flags & FLAG_ALIAS) -+ continue; -+ /* Check false aliases, might be copy-n-paste error */ -+ assert(!ss->ptr || (ss->ptr != ss2->ptr && -+ ss->ptr != ss2->ptr2)); -+ assert(!ss->ptr2 || (ss->ptr2 != ss2->ptr && -+ ss->ptr2 != ss2->ptr2)); -+ } -+ } -+} -+ -+int main(int argc, char **argv) -+{ -+ do_verify_field_set_info(super_fields, &set_sb, sizeof(set_sb)); -+ do_verify_field_set_info(inode_fields, &set_inode, sizeof(set_inode)); -+ do_verify_field_set_info(ext2_bg_fields, &set_gd, sizeof(set_gd)); -+ do_verify_field_set_info(ext4_bg_fields, &set_gd4, sizeof(set_gd4)); -+ do_verify_field_set_info(mmp_fields, &set_mmp, sizeof(set_mmp)); -+ return 0; -+} -+ -+ext2_filsys current_fs; -+ext2_ino_t root, cwd; -+ -+#endif /* UNITTEST */ - - static int check_suffix(const char *field) - { -@@ -784,6 +849,7 @@ static errcode_t parse_mmp_clear(struct field_set_info *info, - return 1; /* we don't need the MMP block written again */ - } - -+#ifdef CONFIG_MMP - void do_set_mmp_value(int argc, char *argv[]) - { - const char *usage = " \n" -@@ -841,4 +907,12 @@ void do_set_mmp_value(int argc, char *argv[]) - *mmp_s = set_mmp; - } - } -+#else -+void do_set_mmp_value(int argc EXT2FS_ATTR((unused)), -+ char *argv[] EXT2FS_ATTR((unused))) -+{ -+ fprintf(stdout, "MMP is unsupported, please recompile with " -+ "--enable-mmp\n"); -+} -+#endif - -diff --git a/debugfs/util.c b/debugfs/util.c -index 20c6c61..56ea695 100644 ---- a/debugfs/util.c -+++ b/debugfs/util.c -@@ -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)); -@@ -390,7 +390,7 @@ int common_block_args_process(int argc, char *argv[], - return 1; - if (*block == 0) { - com_err(argv[0], 0, "Invalid block number 0"); -- err = 1; -+ return 1; - } - - if (argc > 2) { -@@ -497,3 +497,50 @@ int ext2_file_type(unsigned int mode) - - return 0; - } -+ -+errcode_t read_list(char *str, blk64_t **list, size_t *len) -+{ -+ blk64_t *lst = *list; -+ size_t ln = *len; -+ char *tok, *p = str; -+ errcode_t retval; -+ -+ while ((tok = strtok(p, ","))) { -+ blk64_t *l; -+ blk64_t x, y; -+ char *e; -+ -+ errno = 0; -+ y = x = strtoull(tok, &e, 0); -+ if (errno) -+ return errno; -+ if (*e == '-') { -+ y = strtoull(e + 1, NULL, 0); -+ if (errno) -+ return errno; -+ } else if (*e != 0) { -+ retval = EINVAL; -+ goto err; -+ } -+ if (y < x) { -+ retval = EINVAL; -+ goto err; -+ } -+ l = realloc(lst, sizeof(blk64_t) * (ln + y - x + 1)); -+ if (l == NULL) { -+ retval = ENOMEM; -+ goto err; -+ } -+ lst = l; -+ for (; x <= y; x++) -+ lst[ln++] = x; -+ p = NULL; -+ } -+ -+ *list = lst; -+ *len = ln; -+ return 0; -+err: -+ free(lst); -+ return retval; -+} -diff --git a/debugfs/xattrs.c b/debugfs/xattrs.c -new file mode 100644 -index 0000000..e71bc15 ---- /dev/null -+++ b/debugfs/xattrs.c -@@ -0,0 +1,303 @@ -+/* -+ * 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 -+#ifdef HAVE_GETOPT_H -+#include -+#else -+extern int optind; -+extern char *optarg; -+#endif -+#include -+ -+#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 \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 [-f outfile]\n", -+ argv[0], argv[0]); -+ goto out2; -+ } -+ } -+ -+ if (optind != argc - 2) { -+ printf("%s: Usage: %s [-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 [-f infile | " -+ "value]\n", argv[0], argv[0]); -+ goto out2; -+ } -+ } -+ -+ if (!(fp && optind == argc - 2) && !(!fp && optind == argc - 3)) { -+ printf("%s: Usage: %s [-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 ...\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++) { -+ 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"); -+} -diff --git a/debugfs/zap.c b/debugfs/zap.c -index 917bddf..0a1ae9b 100644 ---- a/debugfs/zap.c -+++ b/debugfs/zap.c -@@ -174,7 +174,6 @@ void do_block_dump(int argc, char *argv[]) - errcode_t errcode; - blk64_t block; - char *file = NULL; -- unsigned int i, j; - int c, err; - - if (check_fs_open(argv[0])) -diff --git a/e2fsck/Android.mk b/e2fsck/Android.mk -new file mode 100644 -index 0000000..9726589 ---- /dev/null -+++ b/e2fsck/Android.mk -@@ -0,0 +1,69 @@ -+LOCAL_PATH := $(call my-dir) -+ -+######################### -+# Build the e2fsck binary -+ -+e2fsck_src_files := \ -+ e2fsck.c \ -+ super.c \ -+ pass1.c \ -+ pass1b.c \ -+ pass2.c \ -+ pass3.c \ -+ pass4.c \ -+ pass5.c \ -+ logfile.c \ -+ journal.c \ -+ recovery.c \ -+ revoke.c \ -+ badblocks.c \ -+ util.c \ -+ unix.c \ -+ dirinfo.c \ -+ dx_dirinfo.c \ -+ ehandler.c \ -+ problem.c \ -+ message.c \ -+ ea_refcount.c \ -+ quota.c \ -+ rehash.c \ -+ region.c \ -+ sigcatcher.c \ -+ readahead.c \ -+ extents.c -+ -+e2fsck_shared_libraries := \ -+ libext2fs \ -+ libext2_blkid \ -+ libext2_uuid \ -+ libext2_quota \ -+ libext2_com_err \ -+ libext2_e2p -+e2fsck_system_shared_libraries := libc -+ -+e2fsck_c_includes := external/e2fsprogs/lib -+ -+e2fsck_cflags := -O2 -g -W -Wall -fno-strict-aliasing -+ -+include $(CLEAR_VARS) -+ -+LOCAL_SRC_FILES := $(e2fsck_src_files) -+LOCAL_C_INCLUDES := $(e2fsck_c_includes) -+LOCAL_CFLAGS := $(e2fsck_cflags) -+LOCAL_SYSTEM_SHARED_LIBRARIES := $(e2fsck_system_shared_libraries) -+LOCAL_SHARED_LIBRARIES := $(e2fsck_shared_libraries) -+LOCAL_MODULE := e2fsck -+LOCAL_MODULE_TAGS := optional -+include $(BUILD_EXECUTABLE) -+ -+include $(CLEAR_VARS) -+ -+LOCAL_SRC_FILES := $(e2fsck_src_files) -+LOCAL_C_INCLUDES := $(e2fsck_c_includes) -+LOCAL_CFLAGS := $(e2fsck_cflags) -+LOCAL_SHARED_LIBRARIES := $(addsuffix _host, $(e2fsck_shared_libraries)) -+LOCAL_MODULE := e2fsck_host -+LOCAL_MODULE_STEM := e2fsck -+LOCAL_MODULE_TAGS := optional -+ -+include $(BUILD_HOST_EXECUTABLE) -diff --git a/e2fsck/Makefile.in b/e2fsck/Makefile.in -index b1ce222..06d9f55 100644 ---- a/e2fsck/Makefile.in -+++ b/e2fsck/Makefile.in -@@ -15,22 +15,22 @@ PROGS= e2fsck - MANPAGES= e2fsck.8 - FMANPAGES= e2fsck.conf.5 - --LIBS= $(LIBQUOTA) $(LIBEXT2FS) $(LIBCOM_ERR) $(LIBBLKID) $(LIBUUID) \ -- $(LIBINTL) $(LIBE2P) $(SYSLIBS) --DEPLIBS= $(DEPLIBQUOTA) $(LIBEXT2FS) $(DEPLIBCOM_ERR) $(DEPLIBBLKID) \ -+LIBS= $(LIBSUPPORT) $(LIBEXT2FS) $(LIBCOM_ERR) $(LIBBLKID) $(LIBUUID) \ -+ $(LIBINTL) $(LIBE2P) $(LIBMAGIC) $(SYSLIBS) -+DEPLIBS= $(DEPLIBSUPPORT) $(LIBEXT2FS) $(DEPLIBCOM_ERR) $(DEPLIBBLKID) \ - $(DEPLIBUUID) $(DEPLIBE2P) - --STATIC_LIBS= $(STATIC_LIBQUOTA) $(STATIC_LIBEXT2FS) $(STATIC_LIBCOM_ERR) \ -+STATIC_LIBS= $(STATIC_LIBSUPPORT) $(STATIC_LIBEXT2FS) $(STATIC_LIBCOM_ERR) \ - $(STATIC_LIBBLKID) $(STATIC_LIBUUID) $(LIBINTL) $(STATIC_LIBE2P) \ -- $(SYSLIBS) --STATIC_DEPLIBS= $(DEPSTATIC_LIBQUOTA) $(STATIC_LIBEXT2FS) \ -+ $(LIBMAGIC) $(SYSLIBS) -+STATIC_DEPLIBS= $(DEPSTATIC_LIBSUPPORT) $(STATIC_LIBEXT2FS) \ - $(DEPSTATIC_LIBCOM_ERR) $(DEPSTATIC_LIBBLKID) \ - $(DEPSTATIC_LIBUUID) $(DEPSTATIC_LIBE2P) - --PROFILED_LIBS= $(PROFILED_LIBQUOTA) $(PROFILED_LIBEXT2FS) \ -+PROFILED_LIBS= $(PROFILED_LIBSUPPORT) $(PROFILED_LIBEXT2FS) \ - $(PROFILED_LIBCOM_ERR) $(PROFILED_LIBBLKID) $(PROFILED_LIBUUID) \ -- $(PROFILED_LIBE2P) $(LIBINTL) $(SYSLIBS) --PROFILED_DEPLIBS= $(DEPPROFILED_LIBQUOTA) $(PROFILED_LIBEXT2FS) \ -+ $(PROFILED_LIBE2P) $(LIBINTL) $(LIBMAGIC) $(SYSLIBS) -+PROFILED_DEPLIBS= $(DEPPROFILED_LIBSUPPORT) $(PROFILED_LIBEXT2FS) \ - $(DEPPROFILED_LIBCOM_ERR) $(DEPPROFILED_LIBBLKID) \ - $(DEPPROFILED_LIBUUID) $(DEPPROFILED_LIBE2P) - -@@ -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,27 +58,25 @@ 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= 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 \ -- logfile.o sigcatcher.o $(MTRACE_OBJ) -+ region.o revoke.o ea_refcount.o rehash.o \ -+ logfile.o sigcatcher.o $(MTRACE_OBJ) readahead.o \ -+ extents.o - --PROFILED_OBJS= profiled/dict.o profiled/unix.o profiled/e2fsck.o \ -+PROFILED_OBJS= profiled/unix.o profiled/e2fsck.o \ - profiled/super.o profiled/pass1.o profiled/pass1b.o \ - profiled/pass2.o profiled/pass3.o profiled/pass4.o profiled/pass5.o \ - profiled/journal.o profiled/badblocks.o profiled/util.o \ - profiled/dirinfo.o profiled/dx_dirinfo.o profiled/ehandler.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/sigcatcher.o -+ profiled/ea_refcount.o profiled/rehash.o \ -+ profiled/logfile.o profiled/sigcatcher.o \ -+ profiled/readahead.o profiled/extents.o - - SRCS= $(srcdir)/e2fsck.c \ -- $(srcdir)/crc32.c \ -- $(srcdir)/gen_crc32table.c \ -- $(srcdir)/dict.c \ - $(srcdir)/super.c \ - $(srcdir)/pass1.c \ - $(srcdir)/pass1b.c \ -@@ -98,22 +97,18 @@ SRCS= $(srcdir)/e2fsck.c \ - $(srcdir)/message.c \ - $(srcdir)/ea_refcount.c \ - $(srcdir)/rehash.c \ -+ $(srcdir)/readahead.c \ - $(srcdir)/region.c \ -- $(srcdir)/profile.c \ - $(srcdir)/sigcatcher.c \ - $(srcdir)/logfile.c \ -- prof_err.c \ - $(srcdir)/quota.c \ -+ $(srcdir)/extents.c \ - $(MTRACE_SRC) - - all:: profiled $(PROGS) e2fsck $(MANPAGES) $(FMANPAGES) - - @PROFILE_CMT@all:: e2fsck.profiled - --prof_err.c prof_err.h: prof_err.et -- $(E) " COMPILE_ET prof_err.et" -- $(Q) $(COMPILE_ET) $(srcdir)/prof_err.et -- - e2fsck: $(OBJS) $(DEPLIBS) - $(E) " LD $@" - $(Q) $(LD) $(ALL_LDFLAGS) $(RDYNAMIC) -o e2fsck $(OBJS) $(LIBS) -@@ -127,15 +122,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) $(ALL_CFLAGS) $(ALL_LDFLAGS) $(RDYNAMIC) \ -@@ -147,10 +133,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) $(ALL_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 \ -@@ -168,10 +150,9 @@ tst_region: region.c $(DEPLIBCOM_ERR) - $(ALL_CFLAGS) $(ALL_LDFLAGS) -DTEST_PROGRAM \ - $(LIBCOM_ERR) $(SYSLIBS) - --check:: tst_refcount tst_region tst_crc32 tst_problem -+check:: tst_refcount tst_region tst_problem - $(TESTENV) ./tst_refcount - $(TESTENV) ./tst_region -- $(TESTENV) ./tst_crc32 - $(TESTENV) ./tst_problem - - extend: extend.o -@@ -268,9 +249,9 @@ 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 tst_crc32 \ -+ gen_crc32table e2fsck.conf.5 \ -+ prof_err.c prof_err.h test_profile - $(RM) -rf profiled - - mostlyclean: clean -@@ -289,22 +270,9 @@ 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 --dict.o: $(srcdir)/dict.c $(top_builddir)/lib/config.h \ -- $(top_builddir)/lib/dirpaths.h $(srcdir)/dict.h -+ $(top_srcdir)/lib/support/profile.h $(top_builddir)/lib/support/prof_err.h \ -+ $(top_srcdir)/lib/support/quotaio.h $(top_srcdir)/lib/support/dqblk_v2.h \ -+ $(top_srcdir)/lib/support/quotaio_tree.h $(srcdir)/problem.h - super.o: $(srcdir)/super.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 \ -@@ -312,9 +280,9 @@ super.o: $(srcdir)/super.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 -+ $(top_srcdir)/lib/support/profile.h $(top_builddir)/lib/support/prof_err.h \ -+ $(top_srcdir)/lib/support/quotaio.h $(top_srcdir)/lib/support/dqblk_v2.h \ -+ $(top_srcdir)/lib/support/quotaio_tree.h $(srcdir)/problem.h - pass1.o: $(srcdir)/pass1.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 \ -@@ -322,9 +290,9 @@ pass1.o: $(srcdir)/pass1.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 -+ $(top_srcdir)/lib/support/profile.h $(top_builddir)/lib/support/prof_err.h \ -+ $(top_srcdir)/lib/support/quotaio.h $(top_srcdir)/lib/support/dqblk_v2.h \ -+ $(top_srcdir)/lib/support/quotaio_tree.h $(srcdir)/problem.h - pass1b.o: $(srcdir)/pass1b.c $(top_builddir)/lib/config.h \ - $(top_builddir)/lib/dirpaths.h $(top_srcdir)/lib/et/com_err.h \ - $(srcdir)/e2fsck.h $(top_srcdir)/lib/ext2fs/ext2_fs.h \ -@@ -332,9 +300,10 @@ pass1b.o: $(srcdir)/pass1b.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)/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 $(srcdir)/dict.h -+ $(top_srcdir)/lib/support/profile.h $(top_builddir)/lib/support/prof_err.h \ -+ $(top_srcdir)/lib/support/quotaio.h $(top_srcdir)/lib/support/dqblk_v2.h \ -+ $(top_srcdir)/lib/support/quotaio_tree.h $(srcdir)/problem.h \ -+ $(top_srcdir)/lib/support/dict.h - pass2.o: $(srcdir)/pass2.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 \ -@@ -342,9 +311,10 @@ pass2.o: $(srcdir)/pass2.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 $(srcdir)/dict.h -+ $(top_srcdir)/lib/support/profile.h $(top_builddir)/lib/support/prof_err.h \ -+ $(top_srcdir)/lib/support/quotaio.h $(top_srcdir)/lib/support/dqblk_v2.h \ -+ $(top_srcdir)/lib/support/quotaio_tree.h $(srcdir)/problem.h \ -+ $(top_srcdir)/lib/support/dict.h - pass3.o: $(srcdir)/pass3.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 \ -@@ -352,9 +322,9 @@ pass3.o: $(srcdir)/pass3.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 -+ $(top_srcdir)/lib/support/profile.h $(top_builddir)/lib/support/prof_err.h \ -+ $(top_srcdir)/lib/support/quotaio.h $(top_srcdir)/lib/support/dqblk_v2.h \ -+ $(top_srcdir)/lib/support/quotaio_tree.h $(srcdir)/problem.h - pass4.o: $(srcdir)/pass4.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 \ -@@ -362,9 +332,9 @@ pass4.o: $(srcdir)/pass4.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 -+ $(top_srcdir)/lib/support/profile.h $(top_builddir)/lib/support/prof_err.h \ -+ $(top_srcdir)/lib/support/quotaio.h $(top_srcdir)/lib/support/dqblk_v2.h \ -+ $(top_srcdir)/lib/support/quotaio_tree.h $(srcdir)/problem.h - pass5.o: $(srcdir)/pass5.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 \ -@@ -372,9 +342,9 @@ pass5.o: $(srcdir)/pass5.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 -+ $(top_srcdir)/lib/support/profile.h $(top_builddir)/lib/support/prof_err.h \ -+ $(top_srcdir)/lib/support/quotaio.h $(top_srcdir)/lib/support/dqblk_v2.h \ -+ $(top_srcdir)/lib/support/quotaio_tree.h $(srcdir)/problem.h - journal.o: $(srcdir)/journal.c $(top_builddir)/lib/config.h \ - $(top_builddir)/lib/dirpaths.h $(srcdir)/jfs_user.h $(srcdir)/e2fsck.h \ - $(top_srcdir)/lib/ext2fs/ext2_fs.h $(top_builddir)/lib/ext2fs/ext2_types.h \ -@@ -382,33 +352,33 @@ journal.o: $(srcdir)/journal.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 $(top_srcdir)/lib/ext2fs/kernel-jbd.h \ -- $(top_srcdir)/lib/ext2fs/jfs_compat.h $(top_srcdir)/lib/ext2fs/kernel-list.h \ -- $(srcdir)/problem.h --recovery.o: $(srcdir)/recovery.c $(top_builddir)/lib/config.h \ -- $(top_builddir)/lib/dirpaths.h $(srcdir)/jfs_user.h $(srcdir)/e2fsck.h \ -+ $(top_srcdir)/lib/support/profile.h $(top_builddir)/lib/support/prof_err.h \ -+ $(top_srcdir)/lib/support/quotaio.h $(top_srcdir)/lib/support/dqblk_v2.h \ -+ $(top_srcdir)/lib/support/quotaio_tree.h \ -+ $(top_srcdir)/lib/ext2fs/kernel-jbd.h $(top_srcdir)/lib/ext2fs/jfs_compat.h \ -+ $(top_srcdir)/lib/ext2fs/kernel-list.h $(srcdir)/problem.h -+recovery.o: $(srcdir)/recovery.c $(srcdir)/jfs_user.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 $(top_srcdir)/lib/ext2fs/kernel-jbd.h \ -- $(top_srcdir)/lib/ext2fs/jfs_compat.h $(top_srcdir)/lib/ext2fs/kernel-list.h --revoke.o: $(srcdir)/revoke.c $(top_builddir)/lib/config.h \ -- $(top_builddir)/lib/dirpaths.h $(srcdir)/jfs_user.h $(srcdir)/e2fsck.h \ -+ $(top_srcdir)/lib/support/profile.h $(top_builddir)/lib/support/prof_err.h \ -+ $(top_srcdir)/lib/support/quotaio.h $(top_srcdir)/lib/support/dqblk_v2.h \ -+ $(top_srcdir)/lib/support/quotaio_tree.h \ -+ $(top_srcdir)/lib/ext2fs/kernel-jbd.h $(top_srcdir)/lib/ext2fs/jfs_compat.h \ -+ $(top_srcdir)/lib/ext2fs/kernel-list.h -+revoke.o: $(srcdir)/revoke.c $(srcdir)/jfs_user.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 $(top_srcdir)/lib/ext2fs/kernel-jbd.h \ -- $(top_srcdir)/lib/ext2fs/jfs_compat.h $(top_srcdir)/lib/ext2fs/kernel-list.h -+ $(top_srcdir)/lib/support/profile.h $(top_builddir)/lib/support/prof_err.h \ -+ $(top_srcdir)/lib/support/quotaio.h $(top_srcdir)/lib/support/dqblk_v2.h \ -+ $(top_srcdir)/lib/support/quotaio_tree.h \ -+ $(top_srcdir)/lib/ext2fs/kernel-jbd.h $(top_srcdir)/lib/ext2fs/jfs_compat.h \ -+ $(top_srcdir)/lib/ext2fs/kernel-list.h - badblocks.o: $(srcdir)/badblocks.c $(top_builddir)/lib/config.h \ - $(top_builddir)/lib/dirpaths.h $(top_srcdir)/lib/et/com_err.h \ - $(srcdir)/e2fsck.h $(top_srcdir)/lib/ext2fs/ext2_fs.h \ -@@ -416,9 +386,9 @@ badblocks.o: $(srcdir)/badblocks.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)/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 -+ $(top_srcdir)/lib/support/profile.h $(top_builddir)/lib/support/prof_err.h \ -+ $(top_srcdir)/lib/support/quotaio.h $(top_srcdir)/lib/support/dqblk_v2.h \ -+ $(top_srcdir)/lib/support/quotaio_tree.h - util.o: $(srcdir)/util.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 \ -@@ -426,19 +396,20 @@ util.o: $(srcdir)/util.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 -+ $(top_srcdir)/lib/support/profile.h $(top_builddir)/lib/support/prof_err.h \ -+ $(top_srcdir)/lib/support/quotaio.h $(top_srcdir)/lib/support/dqblk_v2.h \ -+ $(top_srcdir)/lib/support/quotaio_tree.h - unix.o: $(srcdir)/unix.c $(top_builddir)/lib/config.h \ - $(top_builddir)/lib/dirpaths.h $(top_srcdir)/lib/e2p/e2p.h \ - $(top_srcdir)/lib/ext2fs/ext2_fs.h $(top_builddir)/lib/ext2fs/ext2_types.h \ -- $(top_srcdir)/lib/et/com_err.h $(srcdir)/e2fsck.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/et/com_err.h $(top_srcdir)/lib/support/plausible.h \ -+ $(srcdir)/e2fsck.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)/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 \ -+ $(top_srcdir)/lib/support/profile.h $(top_builddir)/lib/support/prof_err.h \ -+ $(top_srcdir)/lib/support/quotaio.h $(top_srcdir)/lib/support/dqblk_v2.h \ -+ $(top_srcdir)/lib/support/quotaio_tree.h $(srcdir)/problem.h \ - $(top_srcdir)/version.h - dirinfo.o: $(srcdir)/dirinfo.c $(top_builddir)/lib/config.h \ - $(top_builddir)/lib/dirpaths.h $(srcdir)/e2fsck.h \ -@@ -447,9 +418,9 @@ dirinfo.o: $(srcdir)/dirinfo.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 $(top_srcdir)/lib/ext2fs/tdb.h -+ $(top_srcdir)/lib/support/profile.h $(top_builddir)/lib/support/prof_err.h \ -+ $(top_srcdir)/lib/support/quotaio.h $(top_srcdir)/lib/support/dqblk_v2.h \ -+ $(top_srcdir)/lib/support/quotaio_tree.h $(top_srcdir)/lib/ext2fs/tdb.h - dx_dirinfo.o: $(srcdir)/dx_dirinfo.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 \ -@@ -457,9 +428,9 @@ dx_dirinfo.o: $(srcdir)/dx_dirinfo.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 -+ $(top_srcdir)/lib/support/profile.h $(top_builddir)/lib/support/prof_err.h \ -+ $(top_srcdir)/lib/support/quotaio.h $(top_srcdir)/lib/support/dqblk_v2.h \ -+ $(top_srcdir)/lib/support/quotaio_tree.h - ehandler.o: $(srcdir)/ehandler.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 \ -@@ -467,9 +438,9 @@ ehandler.o: $(srcdir)/ehandler.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 -+ $(top_srcdir)/lib/support/profile.h $(top_builddir)/lib/support/prof_err.h \ -+ $(top_srcdir)/lib/support/quotaio.h $(top_srcdir)/lib/support/dqblk_v2.h \ -+ $(top_srcdir)/lib/support/quotaio_tree.h - problem.o: $(srcdir)/problem.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 \ -@@ -477,9 +448,10 @@ problem.o: $(srcdir)/problem.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 $(srcdir)/problemP.h -+ $(top_srcdir)/lib/support/profile.h $(top_builddir)/lib/support/prof_err.h \ -+ $(top_srcdir)/lib/support/quotaio.h $(top_srcdir)/lib/support/dqblk_v2.h \ -+ $(top_srcdir)/lib/support/quotaio_tree.h $(srcdir)/problem.h \ -+ $(srcdir)/problemP.h - message.o: $(srcdir)/message.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 \ -@@ -487,9 +459,9 @@ message.o: $(srcdir)/message.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 -+ $(top_srcdir)/lib/support/profile.h $(top_builddir)/lib/support/prof_err.h \ -+ $(top_srcdir)/lib/support/quotaio.h $(top_srcdir)/lib/support/dqblk_v2.h \ -+ $(top_srcdir)/lib/support/quotaio_tree.h $(srcdir)/problem.h - ea_refcount.o: $(srcdir)/ea_refcount.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 \ -@@ -497,9 +469,9 @@ ea_refcount.o: $(srcdir)/ea_refcount.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 -+ $(top_srcdir)/lib/support/profile.h $(top_builddir)/lib/support/prof_err.h \ -+ $(top_srcdir)/lib/support/quotaio.h $(top_srcdir)/lib/support/dqblk_v2.h \ -+ $(top_srcdir)/lib/support/quotaio_tree.h - rehash.o: $(srcdir)/rehash.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 \ -@@ -507,9 +479,19 @@ rehash.o: $(srcdir)/rehash.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 -+ $(top_srcdir)/lib/support/profile.h $(top_builddir)/lib/support/prof_err.h \ -+ $(top_srcdir)/lib/support/quotaio.h $(top_srcdir)/lib/support/dqblk_v2.h \ -+ $(top_srcdir)/lib/support/quotaio_tree.h $(srcdir)/problem.h -+readahead.o: $(srcdir)/readahead.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 \ -+ $(top_srcdir)/lib/support/profile.h $(top_builddir)/lib/support/prof_err.h \ -+ $(top_srcdir)/lib/support/quotaio.h $(top_srcdir)/lib/support/dqblk_v2.h \ -+ $(top_srcdir)/lib/support/quotaio_tree.h - region.o: $(srcdir)/region.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 \ -@@ -517,12 +499,9 @@ region.o: $(srcdir)/region.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 --profile.o: $(srcdir)/profile.c $(top_builddir)/lib/config.h \ -- $(top_builddir)/lib/dirpaths.h $(top_srcdir)/lib/et/com_err.h \ -- $(srcdir)/profile.h prof_err.h -+ $(top_srcdir)/lib/support/profile.h $(top_builddir)/lib/support/prof_err.h \ -+ $(top_srcdir)/lib/support/quotaio.h $(top_srcdir)/lib/support/dqblk_v2.h \ -+ $(top_srcdir)/lib/support/quotaio_tree.h - sigcatcher.o: $(srcdir)/sigcatcher.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 \ -@@ -530,9 +509,9 @@ sigcatcher.o: $(srcdir)/sigcatcher.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 -+ $(top_srcdir)/lib/support/profile.h $(top_builddir)/lib/support/prof_err.h \ -+ $(top_srcdir)/lib/support/quotaio.h $(top_srcdir)/lib/support/dqblk_v2.h \ -+ $(top_srcdir)/lib/support/quotaio_tree.h - logfile.o: $(srcdir)/logfile.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 \ -@@ -540,10 +519,9 @@ logfile.o: $(srcdir)/logfile.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 --prof_err.o: prof_err.c -+ $(top_srcdir)/lib/support/profile.h $(top_builddir)/lib/support/prof_err.h \ -+ $(top_srcdir)/lib/support/quotaio.h $(top_srcdir)/lib/support/dqblk_v2.h \ -+ $(top_srcdir)/lib/support/quotaio_tree.h - quota.o: $(srcdir)/quota.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 \ -@@ -551,6 +529,16 @@ quota.o: $(srcdir)/quota.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 -+ $(top_srcdir)/lib/support/profile.h $(top_builddir)/lib/support/prof_err.h \ -+ $(top_srcdir)/lib/support/quotaio.h $(top_srcdir)/lib/support/dqblk_v2.h \ -+ $(top_srcdir)/lib/support/quotaio_tree.h $(srcdir)/problem.h -+extents.o: $(srcdir)/extents.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 \ -+ $(top_srcdir)/lib/support/profile.h $(top_builddir)/lib/support/prof_err.h \ -+ $(top_srcdir)/lib/support/quotaio.h $(top_srcdir)/lib/support/dqblk_v2.h \ -+ $(top_srcdir)/lib/support/quotaio_tree.h $(srcdir)/problem.h -diff --git a/e2fsck/argv_parse.c b/e2fsck/argv_parse.c -deleted file mode 100644 -index d22f634..0000000 ---- a/e2fsck/argv_parse.c -+++ /dev/null -@@ -1,166 +0,0 @@ --/* -- * argv_parse.c --- utility function for parsing a string into a -- * argc, argv array. -- * -- * This file defines a function argv_parse() which parsing a -- * passed-in string, handling double quotes and backslashes, and -- * creates an allocated argv vector which can be freed using the -- * argv_free() function. -- * -- * See argv_parse.h for the formal definition of the functions. -- * -- * Copyright 1999 by Theodore Ts'o. -- * -- * Permission to use, copy, modify, and distribute this software for -- * any purpose with or without fee is hereby granted, provided that -- * the above copyright notice and this permission notice appear in all -- * copies. THE SOFTWARE IS PROVIDED "AS IS" AND THEODORE TS'O (THE -- * AUTHOR) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -- * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. -- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, -- * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER -- * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION -- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR -- * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. (Isn't -- * it sick that the U.S. culture of lawsuit-happy lawyers requires -- * this kind of disclaimer?) -- * -- * Version 1.1, modified 2/27/1999 -- */ -- --#include "config.h" --#ifdef HAVE_STDLIB_H --#include --#endif --#include --#include --#include "argv_parse.h" -- --#define STATE_WHITESPACE 1 --#define STATE_TOKEN 2 --#define STATE_QUOTED 3 -- --/* -- * Returns 0 on success, -1 on failure. -- */ --int argv_parse(char *in_buf, int *ret_argc, char ***ret_argv) --{ -- int argc = 0, max_argc = 0; -- char **argv, **new_argv, *buf, ch; -- char *cp = 0, *outcp = 0; -- int state = STATE_WHITESPACE; -- -- buf = malloc(strlen(in_buf)+1); -- if (!buf) -- return -1; -- -- max_argc = 0; argc = 0; argv = 0; -- outcp = buf; -- for (cp = in_buf; (ch = *cp); cp++) { -- if (state == STATE_WHITESPACE) { -- if (isspace((int) ch)) -- continue; -- /* Not whitespace, so start a new token */ -- state = STATE_TOKEN; -- if (argc >= max_argc) { -- max_argc += 3; -- new_argv = realloc(argv, -- (max_argc+1)*sizeof(char *)); -- if (!new_argv) { -- free(argv); -- free(buf); -- return -1; -- } -- argv = new_argv; -- } -- argv[argc++] = outcp; -- } -- if (state == STATE_QUOTED) { -- if (ch == '"') -- state = STATE_TOKEN; -- else -- *outcp++ = ch; -- continue; -- } -- /* Must be processing characters in a word */ -- if (isspace((int) ch)) { -- /* -- * Terminate the current word and start -- * looking for the beginning of the next word. -- */ -- *outcp++ = 0; -- state = STATE_WHITESPACE; -- continue; -- } -- if (ch == '"') { -- state = STATE_QUOTED; -- continue; -- } -- if (ch == '\\') { -- ch = *++cp; -- switch (ch) { -- case '\0': -- ch = '\\'; cp--; break; -- case 'n': -- ch = '\n'; break; -- case 't': -- ch = '\t'; break; -- case 'b': -- ch = '\b'; break; -- } -- } -- *outcp++ = ch; -- } -- if (state != STATE_WHITESPACE) -- *outcp++ = '\0'; -- if (argv == 0) { -- argv = malloc(sizeof(char *)); -- free(buf); -- } -- argv[argc] = 0; -- if (ret_argc) -- *ret_argc = argc; -- if (ret_argv) -- *ret_argv = argv; -- return 0; --} -- --void argv_free(char **argv) --{ -- free(*argv); -- free(argv); --} -- --#ifdef DEBUG --/* -- * For debugging -- */ -- --#include -- --int main(int argc, char **argv) --{ -- int ac, ret; -- char **av, **cpp; -- char buf[256]; -- -- while (!feof(stdin)) { -- if (fgets(buf, sizeof(buf), stdin) == NULL) -- break; -- ret = argv_parse(buf, &ac, &av); -- if (ret != 0) { -- printf("Argv_parse returned %d!\n", ret); -- continue; -- } -- printf("Argv_parse returned %d arguments...\n", ac); -- for (cpp = av; *cpp; cpp++) { -- if (cpp != av) -- printf(", "); -- printf("'%s'", *cpp); -- } -- printf("\n"); -- argv_free(av); -- } -- exit(0); --} --#endif /* DEBUG */ -diff --git a/e2fsck/argv_parse.h b/e2fsck/argv_parse.h -deleted file mode 100644 -index 86f4564..0000000 ---- a/e2fsck/argv_parse.h -+++ /dev/null -@@ -1,43 +0,0 @@ --/* -- * argv_parse.h --- header file for the argv parser. -- * -- * This file defines the interface for the functions argv_parse() and -- * argv_free(). -- * -- *********************************************************************** -- * int argv_parse(char *in_buf, int *ret_argc, char ***ret_argv) -- * -- * This function takes as its first argument a string which it will -- * parse into an argv argument vector, with each white-space separated -- * word placed into its own slot in the argv. This function handles -- * double quotes and backslashes so that the parsed words can contain -- * special characters. The count of the number words found in the -- * parsed string, as well as the argument vector, are returned into -- * ret_argc and ret_argv, respectively. -- *********************************************************************** -- * extern void argv_free(char **argv); -- * -- * This function frees the argument vector created by argv_parse(). -- *********************************************************************** -- * -- * Copyright 1999 by Theodore Ts'o. -- * -- * Permission to use, copy, modify, and distribute this software for -- * any purpose with or without fee is hereby granted, provided that -- * the above copyright notice and this permission notice appear in all -- * copies. THE SOFTWARE IS PROVIDED "AS IS" AND THEODORE TS'O (THE -- * AUTHOR) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -- * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. -- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, -- * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER -- * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION -- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR -- * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. (Isn't -- * it sick that the U.S. culture of lawsuit-happy lawyers requires -- * this kind of disclaimer?) -- * -- * Version 1.1, modified 2/27/1999 -- */ -- --extern int argv_parse(char *in_buf, int *ret_argc, char ***ret_argv); --extern void argv_free(char **argv); -diff --git a/e2fsck/crc32.c b/e2fsck/crc32.c -deleted file mode 100644 -index 0497a38..0000000 ---- a/e2fsck/crc32.c -+++ /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 -- * 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 -- * 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 --#include --#include --#include -- --#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 --#include -- --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 -index 27414d2..0000000 ---- a/e2fsck/crc32defs.h -+++ /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< 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 -diff --git a/e2fsck/dict.c b/e2fsck/dict.c -deleted file mode 100644 -index 90c4d84..0000000 ---- a/e2fsck/dict.c -+++ /dev/null -@@ -1,1522 +0,0 @@ --/* -- * Dictionary Abstract Data Type -- * Copyright (C) 1997 Kaz Kylheku -- * -- * Free Software License: -- * -- * All rights are reserved by the author, with the following exceptions: -- * Permission is granted to freely reproduce and distribute this software, -- * possibly in exchange for a fee, provided that this copyright notice appears -- * intact. Permission is also granted to adapt this software to produce -- * derivative works, as long as the modified versions carry this copyright -- * notice and additional notices stating that the work has been modified. -- * This source code may be translated into executable form and incorporated -- * into proprietary software; there is no requirement for such software to -- * contain a copyright notice related to this source. -- * -- * $Id: dict.c,v 1.40.2.7 2000/11/13 01:36:44 kaz Exp $ -- * $Name: kazlib_1_20 $ -- */ -- --#define NDEBUG -- --#ifdef __GNUC__ --#define EXT2FS_ATTR(x) __attribute__(x) --#else --#define EXT2FS_ATTR(x) --#endif -- --#include "config.h" --#include --#include --#include --#define DICT_IMPLEMENTATION --#include "dict.h" -- --#ifdef KAZLIB_RCSID --static const char rcsid[] = "$Id: dict.c,v 1.40.2.7 2000/11/13 01:36:44 kaz Exp $"; --#endif -- --/* -- * These macros provide short convenient names for structure members, -- * which are embellished with dict_ prefixes so that they are -- * properly confined to the documented namespace. It's legal for a -- * program which uses dict to define, for instance, a macro called ``parent''. -- * Such a macro would interfere with the dnode_t struct definition. -- * In general, highly portable and reusable C modules which expose their -- * structures need to confine structure member names to well-defined spaces. -- * The resulting identifiers aren't necessarily convenient to use, nor -- * readable, in the implementation, however! -- */ -- --#define left dict_left --#define right dict_right --#define parent dict_parent --#define color dict_color --#define key dict_key --#define data dict_data -- --#define nilnode dict_nilnode --#define nodecount dict_nodecount --#define maxcount dict_maxcount --#define compare dict_compare --#define allocnode dict_allocnode --#define freenode dict_freenode --#define context dict_context --#define dupes dict_dupes -- --#define dictptr dict_dictptr -- --#define dict_root(D) ((D)->nilnode.left) --#define dict_nil(D) (&(D)->nilnode) --#define DICT_DEPTH_MAX 64 -- --static dnode_t *dnode_alloc(void *context); --static void dnode_free(dnode_t *node, void *context); -- --/* -- * Perform a ``left rotation'' adjustment on the tree. The given node P and -- * its right child C are rearranged so that the P instead becomes the left -- * child of C. The left subtree of C is inherited as the new right subtree -- * for P. The ordering of the keys within the tree is thus preserved. -- */ -- --static void rotate_left(dnode_t *upper) --{ -- dnode_t *lower, *lowleft, *upparent; -- -- lower = upper->right; -- upper->right = lowleft = lower->left; -- lowleft->parent = upper; -- -- lower->parent = upparent = upper->parent; -- -- /* don't need to check for root node here because root->parent is -- the sentinel nil node, and root->parent->left points back to root */ -- -- if (upper == upparent->left) { -- upparent->left = lower; -- } else { -- assert (upper == upparent->right); -- upparent->right = lower; -- } -- -- lower->left = upper; -- upper->parent = lower; --} -- --/* -- * This operation is the ``mirror'' image of rotate_left. It is -- * the same procedure, but with left and right interchanged. -- */ -- --static void rotate_right(dnode_t *upper) --{ -- dnode_t *lower, *lowright, *upparent; -- -- lower = upper->left; -- upper->left = lowright = lower->right; -- lowright->parent = upper; -- -- lower->parent = upparent = upper->parent; -- -- if (upper == upparent->right) { -- upparent->right = lower; -- } else { -- assert (upper == upparent->left); -- upparent->left = lower; -- } -- -- lower->right = upper; -- upper->parent = lower; --} -- --/* -- * Do a postorder traversal of the tree rooted at the specified -- * node and free everything under it. Used by dict_free(). -- */ -- --static void free_nodes(dict_t *dict, dnode_t *node, dnode_t *nil) --{ -- if (node == nil) -- return; -- free_nodes(dict, node->left, nil); -- free_nodes(dict, node->right, nil); -- dict->freenode(node, dict->context); --} -- --/* -- * This procedure performs a verification that the given subtree is a binary -- * search tree. It performs an inorder traversal of the tree using the -- * dict_next() successor function, verifying that the key of each node is -- * strictly lower than that of its successor, if duplicates are not allowed, -- * or lower or equal if duplicates are allowed. This function is used for -- * debugging purposes. -- */ --#ifndef NDEBUG --static int verify_bintree(dict_t *dict) --{ -- dnode_t *first, *next; -- -- first = dict_first(dict); -- -- if (dict->dupes) { -- while (first && (next = dict_next(dict, first))) { -- if (dict->compare(first->key, next->key) > 0) -- return 0; -- first = next; -- } -- } else { -- while (first && (next = dict_next(dict, first))) { -- if (dict->compare(first->key, next->key) >= 0) -- return 0; -- first = next; -- } -- } -- return 1; --} -- --/* -- * This function recursively verifies that the given binary subtree satisfies -- * three of the red black properties. It checks that every red node has only -- * black children. It makes sure that each node is either red or black. And it -- * checks that every path has the same count of black nodes from root to leaf. -- * It returns the blackheight of the given subtree; this allows blackheights to -- * be computed recursively and compared for left and right siblings for -- * mismatches. It does not check for every nil node being black, because there -- * is only one sentinel nil node. The return value of this function is the -- * black height of the subtree rooted at the node ``root'', or zero if the -- * subtree is not red-black. -- */ -- --static unsigned int verify_redblack(dnode_t *nil, dnode_t *root) --{ -- unsigned height_left, height_right; -- -- if (root != nil) { -- height_left = verify_redblack(nil, root->left); -- height_right = verify_redblack(nil, root->right); -- if (height_left == 0 || height_right == 0) -- return 0; -- if (height_left != height_right) -- return 0; -- if (root->color == dnode_red) { -- if (root->left->color != dnode_black) -- return 0; -- if (root->right->color != dnode_black) -- return 0; -- return height_left; -- } -- if (root->color != dnode_black) -- return 0; -- return height_left + 1; -- } -- return 1; --} -- --/* -- * Compute the actual count of nodes by traversing the tree and -- * return it. This could be compared against the stored count to -- * detect a mismatch. -- */ -- --static dictcount_t verify_node_count(dnode_t *nil, dnode_t *root) --{ -- if (root == nil) -- return 0; -- else -- return 1 + verify_node_count(nil, root->left) -- + verify_node_count(nil, root->right); --} --#endif -- --/* -- * Verify that the tree contains the given node. This is done by -- * traversing all of the nodes and comparing their pointers to the -- * given pointer. Returns 1 if the node is found, otherwise -- * returns zero. It is intended for debugging purposes. -- */ -- --static int verify_dict_has_node(dnode_t *nil, dnode_t *root, dnode_t *node) --{ -- if (root != nil) { -- return root == node -- || verify_dict_has_node(nil, root->left, node) -- || verify_dict_has_node(nil, root->right, node); -- } -- return 0; --} -- -- --#ifdef E2FSCK_NOTUSED --/* -- * Dynamically allocate and initialize a dictionary object. -- */ -- --dict_t *dict_create(dictcount_t maxcount, dict_comp_t comp) --{ -- dict_t *new = malloc(sizeof *new); -- -- if (new) { -- new->compare = comp; -- new->allocnode = dnode_alloc; -- new->freenode = dnode_free; -- new->context = NULL; -- new->nodecount = 0; -- new->maxcount = maxcount; -- new->nilnode.left = &new->nilnode; -- new->nilnode.right = &new->nilnode; -- new->nilnode.parent = &new->nilnode; -- new->nilnode.color = dnode_black; -- new->dupes = 0; -- } -- return new; --} --#endif /* E2FSCK_NOTUSED */ -- --/* -- * Select a different set of node allocator routines. -- */ -- --void dict_set_allocator(dict_t *dict, dnode_alloc_t al, -- dnode_free_t fr, void *context) --{ -- assert (dict_count(dict) == 0); -- assert ((al == NULL && fr == NULL) || (al != NULL && fr != NULL)); -- -- dict->allocnode = al ? al : dnode_alloc; -- dict->freenode = fr ? fr : dnode_free; -- dict->context = context; --} -- --#ifdef E2FSCK_NOTUSED --/* -- * Free a dynamically allocated dictionary object. Removing the nodes -- * from the tree before deleting it is required. -- */ -- --void dict_destroy(dict_t *dict) --{ -- assert (dict_isempty(dict)); -- free(dict); --} --#endif -- --/* -- * Free all the nodes in the dictionary by using the dictionary's -- * installed free routine. The dictionary is emptied. -- */ -- --void dict_free_nodes(dict_t *dict) --{ -- dnode_t *nil = dict_nil(dict), *root = dict_root(dict); -- free_nodes(dict, root, nil); -- dict->nodecount = 0; -- dict->nilnode.left = &dict->nilnode; -- dict->nilnode.right = &dict->nilnode; --} -- --#ifdef E2FSCK_NOTUSED --/* -- * Obsolescent function, equivalent to dict_free_nodes -- */ --void dict_free(dict_t *dict) --{ --#ifdef KAZLIB_OBSOLESCENT_DEBUG -- assert ("call to obsolescent function dict_free()" && 0); --#endif -- dict_free_nodes(dict); --} --#endif -- --/* -- * Initialize a user-supplied dictionary object. -- */ -- --dict_t *dict_init(dict_t *dict, dictcount_t maxcount, dict_comp_t comp) --{ -- dict->compare = comp; -- dict->allocnode = dnode_alloc; -- dict->freenode = dnode_free; -- dict->context = NULL; -- dict->nodecount = 0; -- dict->maxcount = maxcount; -- dict->nilnode.left = &dict->nilnode; -- dict->nilnode.right = &dict->nilnode; -- dict->nilnode.parent = &dict->nilnode; -- dict->nilnode.color = dnode_black; -- dict->dupes = 0; -- return dict; --} -- --#ifdef E2FSCK_NOTUSED --/* -- * Initialize a dictionary in the likeness of another dictionary -- */ -- --void dict_init_like(dict_t *dict, const dict_t *template) --{ -- dict->compare = template->compare; -- dict->allocnode = template->allocnode; -- dict->freenode = template->freenode; -- dict->context = template->context; -- dict->nodecount = 0; -- dict->maxcount = template->maxcount; -- dict->nilnode.left = &dict->nilnode; -- dict->nilnode.right = &dict->nilnode; -- dict->nilnode.parent = &dict->nilnode; -- dict->nilnode.color = dnode_black; -- dict->dupes = template->dupes; -- -- assert (dict_similar(dict, template)); --} -- --/* -- * Remove all nodes from the dictionary (without freeing them in any way). -- */ -- --static void dict_clear(dict_t *dict) --{ -- dict->nodecount = 0; -- dict->nilnode.left = &dict->nilnode; -- dict->nilnode.right = &dict->nilnode; -- dict->nilnode.parent = &dict->nilnode; -- assert (dict->nilnode.color == dnode_black); --} -- -- --/* -- * Verify the integrity of the dictionary structure. This is provided for -- * debugging purposes, and should be placed in assert statements. Just because -- * this function succeeds doesn't mean that the tree is not corrupt. Certain -- * corruptions in the tree may simply cause undefined behavior. -- */ -- --int dict_verify(dict_t *dict) --{ --#ifndef NDEBUG -- dnode_t *nil = dict_nil(dict), *root = dict_root(dict); -- -- /* check that the sentinel node and root node are black */ -- if (root->color != dnode_black) -- return 0; -- if (nil->color != dnode_black) -- return 0; -- if (nil->right != nil) -- return 0; -- /* nil->left is the root node; check that its parent pointer is nil */ -- if (nil->left->parent != nil) -- return 0; -- /* perform a weak test that the tree is a binary search tree */ -- if (!verify_bintree(dict)) -- return 0; -- /* verify that the tree is a red-black tree */ -- if (!verify_redblack(nil, root)) -- return 0; -- if (verify_node_count(nil, root) != dict_count(dict)) -- return 0; --#endif -- return 1; --} -- --/* -- * Determine whether two dictionaries are similar: have the same comparison and -- * allocator functions, and same status as to whether duplicates are allowed. -- */ -- --int dict_similar(const dict_t *left, const dict_t *right) --{ -- if (left->compare != right->compare) -- return 0; -- -- if (left->allocnode != right->allocnode) -- return 0; -- -- if (left->freenode != right->freenode) -- return 0; -- -- if (left->context != right->context) -- return 0; -- -- if (left->dupes != right->dupes) -- return 0; -- -- return 1; --} --#endif /* E2FSCK_NOTUSED */ -- --/* -- * Locate a node in the dictionary having the given key. -- * If the node is not found, a null a pointer is returned (rather than -- * a pointer that dictionary's nil sentinel node), otherwise a pointer to the -- * located node is returned. -- */ -- --dnode_t *dict_lookup(dict_t *dict, const void *key) --{ -- dnode_t *root = dict_root(dict); -- dnode_t *nil = dict_nil(dict); -- dnode_t *saved; -- int result; -- -- /* simple binary search adapted for trees that contain duplicate keys */ -- -- while (root != nil) { -- result = dict->compare(key, root->key); -- if (result < 0) -- root = root->left; -- else if (result > 0) -- root = root->right; -- else { -- if (!dict->dupes) { /* no duplicates, return match */ -- return root; -- } else { /* could be dupes, find leftmost one */ -- do { -- saved = root; -- root = root->left; -- while (root != nil && dict->compare(key, root->key)) -- root = root->right; -- } while (root != nil); -- return saved; -- } -- } -- } -- -- return NULL; --} -- --#ifdef E2FSCK_NOTUSED --/* -- * Look for the node corresponding to the lowest key that is equal to or -- * greater than the given key. If there is no such node, return null. -- */ -- --dnode_t *dict_lower_bound(dict_t *dict, const void *key) --{ -- dnode_t *root = dict_root(dict); -- dnode_t *nil = dict_nil(dict); -- dnode_t *tentative = 0; -- -- while (root != nil) { -- int result = dict->compare(key, root->key); -- -- if (result > 0) { -- root = root->right; -- } else if (result < 0) { -- tentative = root; -- root = root->left; -- } else { -- if (!dict->dupes) { -- return root; -- } else { -- tentative = root; -- root = root->left; -- } -- } -- } -- -- return tentative; --} -- --/* -- * Look for the node corresponding to the greatest key that is equal to or -- * lower than the given key. If there is no such node, return null. -- */ -- --dnode_t *dict_upper_bound(dict_t *dict, const void *key) --{ -- dnode_t *root = dict_root(dict); -- dnode_t *nil = dict_nil(dict); -- dnode_t *tentative = 0; -- -- while (root != nil) { -- int result = dict->compare(key, root->key); -- -- if (result < 0) { -- root = root->left; -- } else if (result > 0) { -- tentative = root; -- root = root->right; -- } else { -- if (!dict->dupes) { -- return root; -- } else { -- tentative = root; -- root = root->right; -- } -- } -- } -- -- return tentative; --} --#endif -- --/* -- * Insert a node into the dictionary. The node should have been -- * initialized with a data field. All other fields are ignored. -- * The behavior is undefined if the user attempts to insert into -- * a dictionary that is already full (for which the dict_isfull() -- * function returns true). -- */ -- --void dict_insert(dict_t *dict, dnode_t *node, const void *key) --{ -- dnode_t *where = dict_root(dict), *nil = dict_nil(dict); -- dnode_t *parent = nil, *uncle, *grandpa; -- int result = -1; -- -- node->key = key; -- -- assert (!dict_isfull(dict)); -- assert (!dict_contains(dict, node)); -- assert (!dnode_is_in_a_dict(node)); -- -- /* basic binary tree insert */ -- -- while (where != nil) { -- parent = where; -- result = dict->compare(key, where->key); -- /* trap attempts at duplicate key insertion unless it's explicitly allowed */ -- assert (dict->dupes || result != 0); -- if (result < 0) -- where = where->left; -- else -- where = where->right; -- } -- -- assert (where == nil); -- -- if (result < 0) -- parent->left = node; -- else -- parent->right = node; -- -- node->parent = parent; -- node->left = nil; -- node->right = nil; -- -- dict->nodecount++; -- -- /* red black adjustments */ -- -- node->color = dnode_red; -- -- while (parent->color == dnode_red) { -- grandpa = parent->parent; -- if (parent == grandpa->left) { -- uncle = grandpa->right; -- if (uncle->color == dnode_red) { /* red parent, red uncle */ -- parent->color = dnode_black; -- uncle->color = dnode_black; -- grandpa->color = dnode_red; -- node = grandpa; -- parent = grandpa->parent; -- } else { /* red parent, black uncle */ -- if (node == parent->right) { -- rotate_left(parent); -- parent = node; -- assert (grandpa == parent->parent); -- /* rotation between parent and child preserves grandpa */ -- } -- parent->color = dnode_black; -- grandpa->color = dnode_red; -- rotate_right(grandpa); -- break; -- } -- } else { /* symmetric cases: parent == parent->parent->right */ -- uncle = grandpa->left; -- if (uncle->color == dnode_red) { -- parent->color = dnode_black; -- uncle->color = dnode_black; -- grandpa->color = dnode_red; -- node = grandpa; -- parent = grandpa->parent; -- } else { -- if (node == parent->left) { -- rotate_right(parent); -- parent = node; -- assert (grandpa == parent->parent); -- } -- parent->color = dnode_black; -- grandpa->color = dnode_red; -- rotate_left(grandpa); -- break; -- } -- } -- } -- -- dict_root(dict)->color = dnode_black; -- -- assert (dict_verify(dict)); --} -- --#ifdef E2FSCK_NOTUSED --/* -- * Delete the given node from the dictionary. If the given node does not belong -- * to the given dictionary, undefined behavior results. A pointer to the -- * deleted node is returned. -- */ -- --dnode_t *dict_delete(dict_t *dict, dnode_t *delete) --{ -- dnode_t *nil = dict_nil(dict), *child, *delparent = delete->parent; -- -- /* basic deletion */ -- -- assert (!dict_isempty(dict)); -- assert (dict_contains(dict, delete)); -- -- /* -- * If the node being deleted has two children, then we replace it with its -- * successor (i.e. the leftmost node in the right subtree.) By doing this, -- * we avoid the traditional algorithm under which the successor's key and -- * value *only* move to the deleted node and the successor is spliced out -- * from the tree. We cannot use this approach because the user may hold -- * pointers to the successor, or nodes may be inextricably tied to some -- * other structures by way of embedding, etc. So we must splice out the -- * node we are given, not some other node, and must not move contents from -- * one node to another behind the user's back. -- */ -- -- if (delete->left != nil && delete->right != nil) { -- dnode_t *next = dict_next(dict, delete); -- dnode_t *nextparent = next->parent; -- dnode_color_t nextcolor = next->color; -- -- assert (next != nil); -- assert (next->parent != nil); -- assert (next->left == nil); -- -- /* -- * First, splice out the successor from the tree completely, by -- * moving up its right child into its place. -- */ -- -- child = next->right; -- child->parent = nextparent; -- -- if (nextparent->left == next) { -- nextparent->left = child; -- } else { -- assert (nextparent->right == next); -- nextparent->right = child; -- } -- -- /* -- * Now that the successor has been extricated from the tree, install it -- * in place of the node that we want deleted. -- */ -- -- next->parent = delparent; -- next->left = delete->left; -- next->right = delete->right; -- next->left->parent = next; -- next->right->parent = next; -- next->color = delete->color; -- delete->color = nextcolor; -- -- if (delparent->left == delete) { -- delparent->left = next; -- } else { -- assert (delparent->right == delete); -- delparent->right = next; -- } -- -- } else { -- assert (delete != nil); -- assert (delete->left == nil || delete->right == nil); -- -- child = (delete->left != nil) ? delete->left : delete->right; -- -- child->parent = delparent = delete->parent; -- -- if (delete == delparent->left) { -- delparent->left = child; -- } else { -- assert (delete == delparent->right); -- delparent->right = child; -- } -- } -- -- delete->parent = NULL; -- delete->right = NULL; -- delete->left = NULL; -- -- dict->nodecount--; -- -- assert (verify_bintree(dict)); -- -- /* red-black adjustments */ -- -- if (delete->color == dnode_black) { -- dnode_t *parent, *sister; -- -- dict_root(dict)->color = dnode_red; -- -- while (child->color == dnode_black) { -- parent = child->parent; -- if (child == parent->left) { -- sister = parent->right; -- assert (sister != nil); -- if (sister->color == dnode_red) { -- sister->color = dnode_black; -- parent->color = dnode_red; -- rotate_left(parent); -- sister = parent->right; -- assert (sister != nil); -- } -- if (sister->left->color == dnode_black -- && sister->right->color == dnode_black) { -- sister->color = dnode_red; -- child = parent; -- } else { -- if (sister->right->color == dnode_black) { -- assert (sister->left->color == dnode_red); -- sister->left->color = dnode_black; -- sister->color = dnode_red; -- rotate_right(sister); -- sister = parent->right; -- assert (sister != nil); -- } -- sister->color = parent->color; -- sister->right->color = dnode_black; -- parent->color = dnode_black; -- rotate_left(parent); -- break; -- } -- } else { /* symmetric case: child == child->parent->right */ -- assert (child == parent->right); -- sister = parent->left; -- assert (sister != nil); -- if (sister->color == dnode_red) { -- sister->color = dnode_black; -- parent->color = dnode_red; -- rotate_right(parent); -- sister = parent->left; -- assert (sister != nil); -- } -- if (sister->right->color == dnode_black -- && sister->left->color == dnode_black) { -- sister->color = dnode_red; -- child = parent; -- } else { -- if (sister->left->color == dnode_black) { -- assert (sister->right->color == dnode_red); -- sister->right->color = dnode_black; -- sister->color = dnode_red; -- rotate_left(sister); -- sister = parent->left; -- assert (sister != nil); -- } -- sister->color = parent->color; -- sister->left->color = dnode_black; -- parent->color = dnode_black; -- rotate_right(parent); -- break; -- } -- } -- } -- -- child->color = dnode_black; -- dict_root(dict)->color = dnode_black; -- } -- -- assert (dict_verify(dict)); -- -- return delete; --} --#endif /* E2FSCK_NOTUSED */ -- --/* -- * Allocate a node using the dictionary's allocator routine, give it -- * the data item. -- */ -- --int dict_alloc_insert(dict_t *dict, const void *key, void *data) --{ -- dnode_t *node = dict->allocnode(dict->context); -- -- if (node) { -- dnode_init(node, data); -- dict_insert(dict, node, key); -- return 1; -- } -- return 0; --} -- --#ifdef E2FSCK_NOTUSED --void dict_delete_free(dict_t *dict, dnode_t *node) --{ -- dict_delete(dict, node); -- dict->freenode(node, dict->context); --} --#endif -- --/* -- * Return the node with the lowest (leftmost) key. If the dictionary is empty -- * (that is, dict_isempty(dict) returns 1) a null pointer is returned. -- */ -- --dnode_t *dict_first(dict_t *dict) --{ -- dnode_t *nil = dict_nil(dict), *root = dict_root(dict), *left; -- -- if (root != nil) -- while ((left = root->left) != nil) -- root = left; -- -- return (root == nil) ? NULL : root; --} -- --/* -- * Return the node with the highest (rightmost) key. If the dictionary is empty -- * (that is, dict_isempty(dict) returns 1) a null pointer is returned. -- */ -- --dnode_t *dict_last(dict_t *dict) --{ -- dnode_t *nil = dict_nil(dict), *root = dict_root(dict), *right; -- -- if (root != nil) -- while ((right = root->right) != nil) -- root = right; -- -- return (root == nil) ? NULL : root; --} -- --/* -- * Return the given node's successor node---the node which has the -- * next key in the the left to right ordering. If the node has -- * no successor, a null pointer is returned rather than a pointer to -- * the nil node. -- */ -- --dnode_t *dict_next(dict_t *dict, dnode_t *curr) --{ -- dnode_t *nil = dict_nil(dict), *parent, *left; -- -- if (curr->right != nil) { -- curr = curr->right; -- while ((left = curr->left) != nil) -- curr = left; -- return curr; -- } -- -- parent = curr->parent; -- -- while (parent != nil && curr == parent->right) { -- curr = parent; -- parent = curr->parent; -- } -- -- return (parent == nil) ? NULL : parent; --} -- --/* -- * Return the given node's predecessor, in the key order. -- * The nil sentinel node is returned if there is no predecessor. -- */ -- --dnode_t *dict_prev(dict_t *dict, dnode_t *curr) --{ -- dnode_t *nil = dict_nil(dict), *parent, *right; -- -- if (curr->left != nil) { -- curr = curr->left; -- while ((right = curr->right) != nil) -- curr = right; -- return curr; -- } -- -- parent = curr->parent; -- -- while (parent != nil && curr == parent->left) { -- curr = parent; -- parent = curr->parent; -- } -- -- return (parent == nil) ? NULL : parent; --} -- --void dict_allow_dupes(dict_t *dict) --{ -- dict->dupes = 1; --} -- --#undef dict_count --#undef dict_isempty --#undef dict_isfull --#undef dnode_get --#undef dnode_put --#undef dnode_getkey -- --dictcount_t dict_count(dict_t *dict) --{ -- return dict->nodecount; --} -- --int dict_isempty(dict_t *dict) --{ -- return dict->nodecount == 0; --} -- --int dict_isfull(dict_t *dict) --{ -- return dict->nodecount == dict->maxcount; --} -- --int dict_contains(dict_t *dict, dnode_t *node) --{ -- return verify_dict_has_node(dict_nil(dict), dict_root(dict), node); --} -- --static dnode_t *dnode_alloc(void *context EXT2FS_ATTR((unused))) --{ -- return malloc(sizeof *dnode_alloc(NULL)); --} -- --static void dnode_free(dnode_t *node, void *context EXT2FS_ATTR((unused))) --{ -- free(node); --} -- --dnode_t *dnode_create(void *data) --{ -- dnode_t *new = malloc(sizeof *new); -- if (new) { -- new->data = data; -- new->parent = NULL; -- new->left = NULL; -- new->right = NULL; -- } -- return new; --} -- --dnode_t *dnode_init(dnode_t *dnode, void *data) --{ -- dnode->data = data; -- dnode->parent = NULL; -- dnode->left = NULL; -- dnode->right = NULL; -- return dnode; --} -- --void dnode_destroy(dnode_t *dnode) --{ -- assert (!dnode_is_in_a_dict(dnode)); -- free(dnode); --} -- --void *dnode_get(dnode_t *dnode) --{ -- return dnode->data; --} -- --const void *dnode_getkey(dnode_t *dnode) --{ -- return dnode->key; --} -- --#ifdef E2FSCK_NOTUSED --void dnode_put(dnode_t *dnode, void *data) --{ -- dnode->data = data; --} -- --int dnode_is_in_a_dict(dnode_t *dnode) --{ -- return (dnode->parent && dnode->left && dnode->right); --} -- --void dict_process(dict_t *dict, void *context, dnode_process_t function) --{ -- dnode_t *node = dict_first(dict), *next; -- -- while (node != NULL) { -- /* check for callback function deleting */ -- /* the next node from under us */ -- assert (dict_contains(dict, node)); -- next = dict_next(dict, node); -- function(dict, node, context); -- node = next; -- } --} -- --static void load_begin_internal(dict_load_t *load, dict_t *dict) --{ -- load->dictptr = dict; -- load->nilnode.left = &load->nilnode; -- load->nilnode.right = &load->nilnode; --} -- --void dict_load_begin(dict_load_t *load, dict_t *dict) --{ -- assert (dict_isempty(dict)); -- load_begin_internal(load, dict); --} -- --void dict_load_next(dict_load_t *load, dnode_t *newnode, const void *key) --{ -- dict_t *dict = load->dictptr; -- dnode_t *nil = &load->nilnode; -- -- assert (!dnode_is_in_a_dict(newnode)); -- assert (dict->nodecount < dict->maxcount); -- --#ifndef NDEBUG -- if (dict->nodecount > 0) { -- if (dict->dupes) -- assert (dict->compare(nil->left->key, key) <= 0); -- else -- assert (dict->compare(nil->left->key, key) < 0); -- } --#endif -- -- newnode->key = key; -- nil->right->left = newnode; -- nil->right = newnode; -- newnode->left = nil; -- dict->nodecount++; --} -- --void dict_load_end(dict_load_t *load) --{ -- dict_t *dict = load->dictptr; -- dnode_t *tree[DICT_DEPTH_MAX] = { 0 }; -- dnode_t *curr, *dictnil = dict_nil(dict), *loadnil = &load->nilnode, *next; -- dnode_t *complete = 0; -- dictcount_t fullcount = DICTCOUNT_T_MAX, nodecount = dict->nodecount; -- dictcount_t botrowcount; -- unsigned baselevel = 0, level = 0, i; -- -- assert (dnode_red == 0 && dnode_black == 1); -- -- while (fullcount >= nodecount && fullcount) -- fullcount >>= 1; -- -- botrowcount = nodecount - fullcount; -- -- for (curr = loadnil->left; curr != loadnil; curr = next) { -- next = curr->left; -- -- if (complete == NULL && botrowcount-- == 0) { -- assert (baselevel == 0); -- assert (level == 0); -- baselevel = level = 1; -- complete = tree[0]; -- -- if (complete != 0) { -- tree[0] = 0; -- complete->right = dictnil; -- while (tree[level] != 0) { -- tree[level]->right = complete; -- complete->parent = tree[level]; -- complete = tree[level]; -- tree[level++] = 0; -- } -- } -- } -- -- if (complete == NULL) { -- curr->left = dictnil; -- curr->right = dictnil; -- curr->color = level % 2; -- complete = curr; -- -- assert (level == baselevel); -- while (tree[level] != 0) { -- tree[level]->right = complete; -- complete->parent = tree[level]; -- complete = tree[level]; -- tree[level++] = 0; -- } -- } else { -- curr->left = complete; -- curr->color = (level + 1) % 2; -- complete->parent = curr; -- tree[level] = curr; -- complete = 0; -- level = baselevel; -- } -- } -- -- if (complete == NULL) -- complete = dictnil; -- -- for (i = 0; i < DICT_DEPTH_MAX; i++) { -- if (tree[i] != 0) { -- tree[i]->right = complete; -- complete->parent = tree[i]; -- complete = tree[i]; -- } -- } -- -- dictnil->color = dnode_black; -- dictnil->right = dictnil; -- complete->parent = dictnil; -- complete->color = dnode_black; -- dict_root(dict) = complete; -- -- assert (dict_verify(dict)); --} -- --void dict_merge(dict_t *dest, dict_t *source) --{ -- dict_load_t load; -- dnode_t *leftnode = dict_first(dest), *rightnode = dict_first(source); -- -- assert (dict_similar(dest, source)); -- -- if (source == dest) -- return; -- -- dest->nodecount = 0; -- load_begin_internal(&load, dest); -- -- for (;;) { -- if (leftnode != NULL && rightnode != NULL) { -- if (dest->compare(leftnode->key, rightnode->key) < 0) -- goto copyleft; -- else -- goto copyright; -- } else if (leftnode != NULL) { -- goto copyleft; -- } else if (rightnode != NULL) { -- goto copyright; -- } else { -- assert (leftnode == NULL && rightnode == NULL); -- break; -- } -- -- copyleft: -- { -- dnode_t *next = dict_next(dest, leftnode); --#ifndef NDEBUG -- leftnode->left = NULL; /* suppress assertion in dict_load_next */ --#endif -- dict_load_next(&load, leftnode, leftnode->key); -- leftnode = next; -- continue; -- } -- -- copyright: -- { -- dnode_t *next = dict_next(source, rightnode); --#ifndef NDEBUG -- rightnode->left = NULL; --#endif -- dict_load_next(&load, rightnode, rightnode->key); -- rightnode = next; -- continue; -- } -- } -- -- dict_clear(source); -- dict_load_end(&load); --} --#endif /* E2FSCK_NOTUSED */ -- --#ifdef KAZLIB_TEST_MAIN -- --#include --#include --#include --#include -- --typedef char input_t[256]; -- --static int tokenize(char *string, ...) --{ -- char **tokptr; -- va_list arglist; -- int tokcount = 0; -- -- va_start(arglist, string); -- tokptr = va_arg(arglist, char **); -- while (tokptr) { -- while (*string && isspace((unsigned char) *string)) -- string++; -- if (!*string) -- break; -- *tokptr = string; -- while (*string && !isspace((unsigned char) *string)) -- string++; -- tokptr = va_arg(arglist, char **); -- tokcount++; -- if (!*string) -- break; -- *string++ = 0; -- } -- va_end(arglist); -- -- return tokcount; --} -- --static int comparef(const void *key1, const void *key2) --{ -- return strcmp(key1, key2); --} -- --static char *dupstring(char *str) --{ -- int sz = strlen(str) + 1; -- char *new = malloc(sz); -- if (new) -- memcpy(new, str, sz); -- return new; --} -- --static dnode_t *new_node(void *c) --{ -- static dnode_t few[5]; -- static int count; -- -- if (count < 5) -- return few + count++; -- -- return NULL; --} -- --static void del_node(dnode_t *n, void *c) --{ --} -- --static int prompt = 0; -- --static void construct(dict_t *d) --{ -- input_t in; -- int done = 0; -- dict_load_t dl; -- dnode_t *dn; -- char *tok1, *tok2, *val; -- const char *key; -- char *help = -- "p turn prompt on\n" -- "q finish construction\n" -- "a add new entry\n"; -- -- if (!dict_isempty(d)) -- puts("warning: dictionary not empty!"); -- -- dict_load_begin(&dl, d); -- -- while (!done) { -- if (prompt) -- putchar('>'); -- fflush(stdout); -- -- if (!fgets(in, sizeof(input_t), stdin)) -- break; -- -- switch (in[0]) { -- case '?': -- puts(help); -- break; -- case 'p': -- prompt = 1; -- break; -- case 'q': -- done = 1; -- break; -- case 'a': -- if (tokenize(in+1, &tok1, &tok2, (char **) 0) != 2) { -- puts("what?"); -- break; -- } -- key = dupstring(tok1); -- val = dupstring(tok2); -- dn = dnode_create(val); -- -- if (!key || !val || !dn) { -- puts("out of memory"); -- free((void *) key); -- free(val); -- if (dn) -- dnode_destroy(dn); -- } -- -- dict_load_next(&dl, dn, key); -- break; -- default: -- putchar('?'); -- putchar('\n'); -- break; -- } -- } -- -- dict_load_end(&dl); --} -- --int main(void) --{ -- input_t in; -- dict_t darray[10]; -- dict_t *d = &darray[0]; -- dnode_t *dn; -- int i; -- char *tok1, *tok2, *val; -- const char *key; -- -- char *help = -- "a add value to dictionary\n" -- "d delete value from dictionary\n" -- "l lookup value in dictionary\n" -- "( lookup lower bound\n" -- ") lookup upper bound\n" -- "# switch to alternate dictionary (0-9)\n" -- "j merge two dictionaries\n" -- "f free the whole dictionary\n" -- "k allow duplicate keys\n" -- "c show number of entries\n" -- "t dump whole dictionary in sort order\n" -- "m make dictionary out of sorted items\n" -- "p turn prompt on\n" -- "s switch to non-functioning allocator\n" -- "q quit"; -- -- for (i = 0; i < sizeof darray / sizeof *darray; i++) -- dict_init(&darray[i], DICTCOUNT_T_MAX, comparef); -- -- for (;;) { -- if (prompt) -- putchar('>'); -- fflush(stdout); -- -- if (!fgets(in, sizeof(input_t), stdin)) -- break; -- -- switch(in[0]) { -- case '?': -- puts(help); -- break; -- case 'a': -- if (tokenize(in+1, &tok1, &tok2, (char **) 0) != 2) { -- puts("what?"); -- break; -- } -- key = dupstring(tok1); -- val = dupstring(tok2); -- -- if (!key || !val) { -- puts("out of memory"); -- free((void *) key); -- free(val); -- } -- -- if (!dict_alloc_insert(d, key, val)) { -- puts("dict_alloc_insert failed"); -- free((void *) key); -- free(val); -- break; -- } -- break; -- case 'd': -- if (tokenize(in+1, &tok1, (char **) 0) != 1) { -- puts("what?"); -- break; -- } -- dn = dict_lookup(d, tok1); -- if (!dn) { -- puts("dict_lookup failed"); -- break; -- } -- val = dnode_get(dn); -- key = dnode_getkey(dn); -- dict_delete_free(d, dn); -- -- free(val); -- free((void *) key); -- break; -- case 'f': -- dict_free(d); -- break; -- case 'l': -- case '(': -- case ')': -- if (tokenize(in+1, &tok1, (char **) 0) != 1) { -- puts("what?"); -- break; -- } -- dn = 0; -- switch (in[0]) { -- case 'l': -- dn = dict_lookup(d, tok1); -- break; -- case '(': -- dn = dict_lower_bound(d, tok1); -- break; -- case ')': -- dn = dict_upper_bound(d, tok1); -- break; -- } -- if (!dn) { -- puts("lookup failed"); -- break; -- } -- val = dnode_get(dn); -- puts(val); -- break; -- case 'm': -- construct(d); -- break; -- case 'k': -- dict_allow_dupes(d); -- break; -- case 'c': -- printf("%lu\n", (unsigned long) dict_count(d)); -- break; -- case 't': -- for (dn = dict_first(d); dn; dn = dict_next(d, dn)) { -- printf("%s\t%s\n", (char *) dnode_getkey(dn), -- (char *) dnode_get(dn)); -- } -- break; -- case 'q': -- exit(0); -- break; -- case '\0': -- break; -- case 'p': -- prompt = 1; -- break; -- case 's': -- dict_set_allocator(d, new_node, del_node, NULL); -- break; -- case '#': -- if (tokenize(in+1, &tok1, (char **) 0) != 1) { -- puts("what?"); -- break; -- } else { -- int dictnum = atoi(tok1); -- if (dictnum < 0 || dictnum > 9) { -- puts("invalid number"); -- break; -- } -- d = &darray[dictnum]; -- } -- break; -- case 'j': -- if (tokenize(in+1, &tok1, &tok2, (char **) 0) != 2) { -- puts("what?"); -- break; -- } else { -- int dict1 = atoi(tok1), dict2 = atoi(tok2); -- if (dict1 < 0 || dict1 > 9 || dict2 < 0 || dict2 > 9) { -- puts("invalid number"); -- break; -- } -- dict_merge(&darray[dict1], &darray[dict2]); -- } -- break; -- default: -- putchar('?'); -- putchar('\n'); -- break; -- } -- } -- -- return 0; --} -- --#endif -diff --git a/e2fsck/dict.h b/e2fsck/dict.h -deleted file mode 100644 -index 838079d..0000000 ---- a/e2fsck/dict.h -+++ /dev/null -@@ -1,144 +0,0 @@ --/* -- * Dictionary Abstract Data Type -- * Copyright (C) 1997 Kaz Kylheku -- * -- * Free Software License: -- * -- * All rights are reserved by the author, with the following exceptions: -- * Permission is granted to freely reproduce and distribute this software, -- * possibly in exchange for a fee, provided that this copyright notice appears -- * intact. Permission is also granted to adapt this software to produce -- * derivative works, as long as the modified versions carry this copyright -- * notice and additional notices stating that the work has been modified. -- * This source code may be translated into executable form and incorporated -- * into proprietary software; there is no requirement for such software to -- * contain a copyright notice related to this source. -- * -- * $Id: dict.h,v 1.22.2.6 2000/11/13 01:36:44 kaz Exp $ -- * $Name: kazlib_1_20 $ -- */ -- --#ifndef DICT_H --#define DICT_H -- --#include --#ifdef KAZLIB_SIDEEFFECT_DEBUG --#include "sfx.h" --#endif -- --/* -- * Blurb for inclusion into C++ translation units -- */ -- --#ifdef __cplusplus --extern "C" { --#endif -- --typedef unsigned long dictcount_t; --#define DICTCOUNT_T_MAX ULONG_MAX -- --/* -- * The dictionary is implemented as a red-black tree -- */ -- --typedef enum { dnode_red, dnode_black } dnode_color_t; -- --typedef struct dnode_t { --#if defined(DICT_IMPLEMENTATION) || !defined(KAZLIB_OPAQUE_DEBUG) -- struct dnode_t *dict_left; -- struct dnode_t *dict_right; -- struct dnode_t *dict_parent; -- dnode_color_t dict_color; -- const void *dict_key; -- void *dict_data; --#else -- int dict_dummy; --#endif --} dnode_t; -- --typedef int (*dict_comp_t)(const void *, const void *); --typedef dnode_t *(*dnode_alloc_t)(void *); --typedef void (*dnode_free_t)(dnode_t *, void *); -- --typedef struct dict_t { --#if defined(DICT_IMPLEMENTATION) || !defined(KAZLIB_OPAQUE_DEBUG) -- dnode_t dict_nilnode; -- dictcount_t dict_nodecount; -- dictcount_t dict_maxcount; -- dict_comp_t dict_compare; -- dnode_alloc_t dict_allocnode; -- dnode_free_t dict_freenode; -- void *dict_context; -- int dict_dupes; --#else -- int dict_dummmy; --#endif --} dict_t; -- --typedef void (*dnode_process_t)(dict_t *, dnode_t *, void *); -- --typedef struct dict_load_t { --#if defined(DICT_IMPLEMENTATION) || !defined(KAZLIB_OPAQUE_DEBUG) -- dict_t *dict_dictptr; -- dnode_t dict_nilnode; --#else -- int dict_dummmy; --#endif --} dict_load_t; -- --extern dict_t *dict_create(dictcount_t, dict_comp_t); --extern void dict_set_allocator(dict_t *, dnode_alloc_t, dnode_free_t, void *); --extern void dict_destroy(dict_t *); --extern void dict_free_nodes(dict_t *); --extern void dict_free(dict_t *); --extern dict_t *dict_init(dict_t *, dictcount_t, dict_comp_t); --extern void dict_init_like(dict_t *, const dict_t *); --extern int dict_verify(dict_t *); --extern int dict_similar(const dict_t *, const dict_t *); --extern dnode_t *dict_lookup(dict_t *, const void *); --extern dnode_t *dict_lower_bound(dict_t *, const void *); --extern dnode_t *dict_upper_bound(dict_t *, const void *); --extern void dict_insert(dict_t *, dnode_t *, const void *); --extern dnode_t *dict_delete(dict_t *, dnode_t *); --extern int dict_alloc_insert(dict_t *, const void *, void *); --extern void dict_delete_free(dict_t *, dnode_t *); --extern dnode_t *dict_first(dict_t *); --extern dnode_t *dict_last(dict_t *); --extern dnode_t *dict_next(dict_t *, dnode_t *); --extern dnode_t *dict_prev(dict_t *, dnode_t *); --extern dictcount_t dict_count(dict_t *); --extern int dict_isempty(dict_t *); --extern int dict_isfull(dict_t *); --extern int dict_contains(dict_t *, dnode_t *); --extern void dict_allow_dupes(dict_t *); --extern int dnode_is_in_a_dict(dnode_t *); --extern dnode_t *dnode_create(void *); --extern dnode_t *dnode_init(dnode_t *, void *); --extern void dnode_destroy(dnode_t *); --extern void *dnode_get(dnode_t *); --extern const void *dnode_getkey(dnode_t *); --extern void dnode_put(dnode_t *, void *); --extern void dict_process(dict_t *, void *, dnode_process_t); --extern void dict_load_begin(dict_load_t *, dict_t *); --extern void dict_load_next(dict_load_t *, dnode_t *, const void *); --extern void dict_load_end(dict_load_t *); --extern void dict_merge(dict_t *, dict_t *); -- --#if defined(DICT_IMPLEMENTATION) || !defined(KAZLIB_OPAQUE_DEBUG) --#ifdef KAZLIB_SIDEEFFECT_DEBUG --#define dict_isfull(D) (SFX_CHECK(D)->dict_nodecount == (D)->dict_maxcount) --#else --#define dict_isfull(D) ((D)->dict_nodecount == (D)->dict_maxcount) --#endif --#define dict_count(D) ((D)->dict_nodecount) --#define dict_isempty(D) ((D)->dict_nodecount == 0) --#define dnode_get(N) ((N)->dict_data) --#define dnode_getkey(N) ((N)->dict_key) --#define dnode_put(N, X) ((N)->dict_data = (X)) --#endif -- --#ifdef __cplusplus --} --#endif -- --#endif -diff --git a/e2fsck/dirinfo.c b/e2fsck/dirinfo.c -index dab5a13..9b36ddc 100644 ---- a/e2fsck/dirinfo.c -+++ b/e2fsck/dirinfo.c -@@ -13,6 +13,7 @@ - #include - #include "uuid/uuid.h" - -+#include "ext2fs/ext2fs.h" - #include - - struct dir_info_db { -diff --git a/e2fsck/dx_dirinfo.c b/e2fsck/dx_dirinfo.c -index be53fff..c7b6056 100644 ---- a/e2fsck/dx_dirinfo.c -+++ b/e2fsck/dx_dirinfo.c -@@ -7,7 +7,6 @@ - - #include "config.h" - #include "e2fsck.h" --#ifdef ENABLE_HTREE - - /* - * This subroutine is called during pass1 to create a directory info -@@ -151,5 +150,3 @@ struct dx_dir_info *e2fsck_dx_dir_info_iter(e2fsck_t ctx, int *control) - - return(ctx->dx_dir_info + (*control)++); - } -- --#endif /* ENABLE_HTREE */ -diff --git a/e2fsck/e2fsck.8.in b/e2fsck/e2fsck.8.in -index f5ed758..f6d8436 100644 ---- a/e2fsck/e2fsck.8.in -+++ b/e2fsck/e2fsck.8.in -@@ -68,6 +68,19 @@ are not valid if the filesystem is mounted. If - asks whether or not you should check a filesystem which is mounted, - the only correct answer is ``no''. Only experts who really know what - they are doing should consider answering this question in any other way. -+.PP -+If -+.B e2fsck -+is run in interactive mode (meaning that none of -+.BR \-y , -+.BR \-n , -+or -+.BR \-p -+are specified), the program will ask the user to fix each problem found in the -+filesystem. A response of 'y' will fix the error; 'n' will leave the error -+unfixed; and 'a' will fix the problem and all subsequent problems; pressing -+Enter will proceed with the default response, which is printed before the -+question mark. Pressing Control-C terminates e2fsck immediately. - .SH OPTIONS - .TP - .B \-a -@@ -207,6 +220,21 @@ option may prevent you from further manual data recovery. - .BI nodiscard - Do not attempt to discard free blocks and unused inode blocks. This option is - exactly the opposite of discard option. This is set as default. -+.TP -+.BI readahead_kb -+Use this many KiB of memory to pre-fetch metadata in the hopes of reducing -+e2fsck runtime. By default, this is set to the size of two block groups' inode -+tables (typically 4MiB on a regular ext4 filesystem); if this amount is more -+than 1/50th of total physical memory, readahead is disabled. Set this to zero -+to disable readahead entirely. -+.TP -+.BI bmap2extent -+Convert block-mapped files to extent-mapped files. -+.TP -+.BI fixes_only -+Only fix damaged metadata; do not optimize htree directories or compress -+extent trees. This option is incompatible with the -D and -E bmap2extent -+options. - .RE - .TP - .B \-f -@@ -311,6 +339,16 @@ may not be specified at the same time as the - or - .B \-p - options. -+.TP -+.BI \-z " undo_file" -+Before overwriting a file system block, write the old contents of the block to -+an undo file. This undo file can be used with e2undo(8) to restore the old -+contents of the file system should something go wrong. If the empty string is -+passed as the undo_file argument, the undo file will be written to a file named -+e2fsck-\fIdevice\fR.e2undo in the directory specified via the -+\fIE2FSPROGS_UNDO_DIR\fR environment variable. -+ -+WARNING: The undo file cannot be used to recover from a power or system crash. - .SH EXIT CODE - The exit code returned by - .B e2fsck -diff --git a/e2fsck/e2fsck.c b/e2fsck/e2fsck.c -index 0ec1540..dd8150b 100644 ---- a/e2fsck/e2fsck.c -+++ b/e2fsck/e2fsck.c -@@ -89,9 +89,7 @@ errcode_t e2fsck_reset_context(e2fsck_t ctx) - ctx->fs->dblist = 0; - } - e2fsck_free_dir_info(ctx); --#ifdef ENABLE_HTREE - e2fsck_free_dx_dir_info(ctx); --#endif - if (ctx->refcount) { - ea_refcount_free(ctx->refcount); - ctx->refcount = 0; -@@ -108,6 +106,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; -@@ -140,6 +142,10 @@ errcode_t e2fsck_reset_context(e2fsck_t ctx) - ext2fs_free_mem(&ctx->invalid_inode_table_flag); - ctx->invalid_inode_table_flag = 0; - } -+ if (ctx->encrypted_dirs) { -+ ext2fs_u32_list_free(ctx->encrypted_dirs); -+ ctx->encrypted_dirs = 0; -+ } - - /* Clear statistic counters */ - ctx->fs_directory_count = 0; -@@ -200,8 +206,8 @@ void e2fsck_free_context(e2fsck_t ctx) - typedef void (*pass_t)(e2fsck_t ctx); - - static pass_t e2fsck_passes[] = { -- e2fsck_pass1, e2fsck_pass2, e2fsck_pass3, e2fsck_pass4, -- e2fsck_pass5, 0 }; -+ e2fsck_pass1, e2fsck_pass1e, e2fsck_pass2, e2fsck_pass3, -+ e2fsck_pass4, e2fsck_pass5, 0 }; - - #define E2F_FLAG_RUN_RETURN (E2F_FLAG_SIGNAL_MASK|E2F_FLAG_RESTART) - -diff --git a/e2fsck/e2fsck.conf.5.in b/e2fsck/e2fsck.conf.5.in -index 9ebfbbf..ab83180 100644 ---- a/e2fsck/e2fsck.conf.5.in -+++ b/e2fsck/e2fsck.conf.5.in -@@ -205,6 +205,21 @@ of that type are squelched. This can be useful if the console is slow - (i.e., connected to a serial port) and so a large amount of output could - end up delaying the boot process for a long time (potentially hours). - .TP -+.I readahead_mem_pct -+Use this percentage of memory to try to read in metadata blocks ahead of the -+main e2fsck thread. This should reduce run times, depending on the speed of -+the underlying storage and the amount of free memory. There is no default, but -+see -+.B readahead_mem_pct -+for more details. -+.TP -+.I readahead_kb -+Use this amount of memory to read in metadata blocks ahead of the main checking -+thread. Setting this value to zero disables readahead entirely. By default, -+this is set the size of two block groups' inode tables (typically 4MiB on a -+regular ext4 filesystem); if this amount is more than 1/50th of total physical -+memory, readahead is disabled. -+.TP - .I report_features - If this boolean relation is true, e2fsck will print the file system - features as part of its verbose reporting (i.e., if the -diff --git a/e2fsck/e2fsck.h b/e2fsck/e2fsck.h -index f904026..48d4a29 100644 ---- a/e2fsck/e2fsck.h -+++ b/e2fsck/e2fsck.h -@@ -36,8 +36,8 @@ - #include "blkid/blkid.h" - #endif - --#include "profile.h" --#include "prof_err.h" -+#include "support/profile.h" -+#include "support/prof_err.h" - - #ifdef ENABLE_NLS - #include -@@ -67,7 +67,7 @@ - #define E2FSCK_ATTR(x) - #endif - --#include "quota/quotaio.h" -+#include "support/quotaio.h" - - /* - * Exit codes used by fsck-type programs -@@ -167,6 +167,8 @@ struct resource_track { - #define E2F_OPT_FRAGCHECK 0x0800 - #define E2F_OPT_JOURNAL_ONLY 0x1000 /* only replay the journal */ - #define E2F_OPT_DISCARD 0x2000 -+#define E2F_OPT_CONVERT_BMAP 0x4000 /* convert blockmap to extent */ -+#define E2F_OPT_FIXES_ONLY 0x8000 /* skip all optimizations */ - - /* - * E2fsck flags -@@ -190,6 +192,7 @@ struct resource_track { - #define E2F_FLAG_EXITING 0x1000 /* E2fsck exiting due to errors */ - #define E2F_FLAG_TIME_INSANE 0x2000 /* Time is insane */ - #define E2F_FLAG_PROBLEMS_FIXED 0x4000 /* At least one problem was fixed */ -+#define E2F_FLAG_ALLOC_OK 0x8000 /* Can we allocate blocks? */ - - #define E2F_RESET_FLAGS (E2F_FLAG_TIME_INSANE | E2F_FLAG_PROBLEMS_FIXED) - -@@ -368,6 +371,7 @@ struct e2fsck_struct { - int ext_attr_ver; - profile_t profile; - int blocks_per_page; -+ ext2_u32_list encrypted_dirs; - - /* Reserve blocks for root and l+f re-creation */ - blk64_t root_repair_block, lnf_repair_block; -@@ -377,10 +381,34 @@ struct e2fsck_struct { - * e2fsck functions themselves. - */ - void *priv_data; -+ ext2fs_block_bitmap block_metadata_map; /* Metadata blocks */ -+ -+ /* How much are we allowed to readahead? */ -+ unsigned long long readahead_kb; -+ -+ /* -+ * Inodes to rebuild extent trees -+ */ -+ ext2fs_inode_bitmap inodes_to_rebuild; -+ -+ /* Undo file */ -+ char *undo_file; -+}; -+ -+/* Data structures to evaluate whether an extent tree needs rebuilding. */ -+struct extent_tree_level { -+ unsigned int num_extents; -+ unsigned int max_extents; -+}; -+ -+struct extent_tree_info { -+ ext2_ino_t ino; -+ int force_rebuild; -+ struct extent_tree_level ext_info[MAX_EXTENT_DEPTH_COUNT]; - }; - - /* Used by the region allocation code */ --typedef __u32 region_addr_t; -+typedef __u64 region_addr_t; - typedef struct region_struct *region_t; - - #ifndef HAVE_STRNLEN -@@ -410,9 +438,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); -@@ -455,6 +480,19 @@ extern blk64_t ea_refcount_intr_next(ext2_refcount_t refcount, int *ret); - extern const char *ehandler_operation(const char *op); - extern void ehandler_init(io_channel channel); - -+/* extents.c */ -+struct problem_context; -+errcode_t e2fsck_rebuild_extents_later(e2fsck_t ctx, ext2_ino_t ino); -+int e2fsck_ino_will_be_rebuilt(e2fsck_t ctx, ext2_ino_t ino); -+void e2fsck_pass1e(e2fsck_t ctx); -+errcode_t e2fsck_check_rebuild_extents(e2fsck_t ctx, ext2_ino_t ino, -+ struct ext2_inode *inode, -+ struct problem_context *pctx); -+errcode_t e2fsck_should_rebuild_extents(e2fsck_t ctx, -+ struct problem_context *pctx, -+ struct extent_tree_info *eti, -+ struct ext2_extent_info *info); -+ - /* journal.c */ - extern errcode_t e2fsck_check_ext3_journal(e2fsck_t ctx); - extern errcode_t e2fsck_run_ext3_journal(e2fsck_t ctx); -@@ -483,6 +521,10 @@ extern void e2fsck_intercept_block_allocations(e2fsck_t ctx); - /* pass2.c */ - extern int e2fsck_process_bad_inode(e2fsck_t ctx, ext2_ino_t dir, - ext2_ino_t ino, char *buf); -+extern int get_filename_hash(ext2_filsys fs, int encrypted, int version, -+ const char *name, int len, -+ ext2_dirhash_t *ret_hash, -+ ext2_dirhash_t *ret_minor_hash); - - /* pass3.c */ - extern int e2fsck_reconnect_file(e2fsck_t ctx, ext2_ino_t inode); -@@ -492,6 +534,23 @@ extern ext2_ino_t e2fsck_get_lost_and_found(e2fsck_t ctx, int fix); - extern errcode_t e2fsck_adjust_inode_count(e2fsck_t ctx, ext2_ino_t ino, - int adj); - -+/* readahead.c */ -+#define E2FSCK_READA_SUPER (0x01) -+#define E2FSCK_READA_GDT (0x02) -+#define E2FSCK_READA_BBITMAP (0x04) -+#define E2FSCK_READA_IBITMAP (0x08) -+#define E2FSCK_READA_ITABLE (0x10) -+#define E2FSCK_READA_ALL_FLAGS (0x1F) -+errcode_t e2fsck_readahead(ext2_filsys fs, int flags, dgrp_t start, -+ dgrp_t ngroups); -+#define E2FSCK_RA_DBLIST_IGNORE_BLOCKCNT (0x01) -+#define E2FSCK_RA_DBLIST_ALL_FLAGS (0x01) -+errcode_t e2fsck_readahead_dblist(ext2_filsys fs, int flags, -+ ext2_dblist dblist, -+ unsigned long long start, -+ unsigned long long count); -+int e2fsck_can_readahead(ext2_filsys fs); -+unsigned long long e2fsck_guess_readahead(ext2_filsys fs); - - /* region.c */ - extern region_t region_create(region_addr_t min, region_addr_t max); -@@ -499,7 +558,10 @@ extern void region_free(region_t region); - extern int region_allocate(region_t region, region_addr_t start, int n); - - /* rehash.c */ --errcode_t e2fsck_rehash_dir(e2fsck_t ctx, ext2_ino_t ino); -+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, -+ struct problem_context *pctx); - void e2fsck_rehash_directories(e2fsck_t ctx); - - /* sigcatcher.c */ -@@ -524,8 +586,6 @@ extern void e2fsck_read_bitmaps(e2fsck_t ctx); - extern void e2fsck_write_bitmaps(e2fsck_t ctx); - extern void preenhalt(e2fsck_t ctx); - extern char *string_copy(e2fsck_t ctx, const char *str, int len); --extern errcode_t e2fsck_zero_blocks(ext2_filsys fs, blk_t blk, int num, -- blk_t *ret_blk, int *ret_count); - extern int fs_proc_check(const char *fs_name); - extern int check_for_modules(const char *fs_name); - #ifdef RESOURCE_TRACK -@@ -579,6 +639,7 @@ extern errcode_t e2fsck_allocate_subcluster_bitmap(ext2_filsys fs, - int default_type, - const char *profile_name, - ext2fs_block_bitmap *ret); -+unsigned long long get_memory_size(void); - - /* unix.c */ - extern void e2fsck_clear_progbar(e2fsck_t ctx); -diff --git a/e2fsck/ehandler.c b/e2fsck/ehandler.c -index 6dddf9c..71ca301 100644 ---- a/e2fsck/ehandler.c -+++ b/e2fsck/ehandler.c -@@ -58,6 +58,11 @@ static errcode_t e2fsck_handle_read_error(io_channel channel, - printf(_("Error reading block %lu (%s). "), block, - error_message(error)); - preenhalt(ctx); -+ -+ /* Don't rewrite a block past the end of the FS. */ -+ if (block >= ext2fs_blocks_count(fs->super)) -+ return 0; -+ - if (ask(ctx, _("Ignore error"), 1)) { - if (ask(ctx, _("Force rewrite"), 1)) - io_channel_write_blk64(channel, block, count, data); -diff --git a/e2fsck/extents.c b/e2fsck/extents.c -new file mode 100644 -index 0000000..407dafb ---- /dev/null -+++ b/e2fsck/extents.c -@@ -0,0 +1,543 @@ -+/* -+ * extents.c --- rebuild extent tree -+ * -+ * Copyright (C) 2014 Oracle. -+ * -+ * %Begin-Header% -+ * This file may be redistributed under the terms of the GNU Public -+ * License, version 2. -+ * %End-Header% -+ */ -+ -+#include "config.h" -+#include -+#include -+#include -+#include "e2fsck.h" -+#include "problem.h" -+ -+#undef DEBUG -+#undef DEBUG_SUMMARY -+#undef DEBUG_FREE -+ -+#define NUM_EXTENTS 341 /* about one ETB' worth of extents */ -+ -+static errcode_t e2fsck_rebuild_extents(e2fsck_t ctx, ext2_ino_t ino); -+ -+/* Schedule an inode to have its extent tree rebuilt during pass 1E. */ -+errcode_t e2fsck_rebuild_extents_later(e2fsck_t ctx, ext2_ino_t ino) -+{ -+ errcode_t retval = 0; -+ -+ if (!EXT2_HAS_INCOMPAT_FEATURE(ctx->fs->super, -+ EXT3_FEATURE_INCOMPAT_EXTENTS) || -+ (ctx->options & E2F_OPT_NO) || -+ (ino != EXT2_ROOT_INO && ino < ctx->fs->super->s_first_ino)) -+ return 0; -+ -+ if (ctx->flags & E2F_FLAG_ALLOC_OK) -+ return e2fsck_rebuild_extents(ctx, ino); -+ -+ if (!ctx->inodes_to_rebuild) -+ retval = e2fsck_allocate_inode_bitmap(ctx->fs, -+ _("extent rebuild inode map"), -+ EXT2FS_BMAP64_RBTREE, -+ "inodes_to_rebuild", -+ &ctx->inodes_to_rebuild); -+ if (retval) -+ return retval; -+ -+ ext2fs_mark_inode_bitmap2(ctx->inodes_to_rebuild, ino); -+ return 0; -+} -+ -+/* Ask if an inode will have its extents rebuilt during pass 1E. */ -+int e2fsck_ino_will_be_rebuilt(e2fsck_t ctx, ext2_ino_t ino) -+{ -+ if (!ctx->inodes_to_rebuild) -+ return 0; -+ return ext2fs_test_inode_bitmap2(ctx->inodes_to_rebuild, ino); -+} -+ -+struct extent_list { -+ blk64_t blocks_freed; -+ struct ext2fs_extent *extents; -+ unsigned int count; -+ unsigned int size; -+ unsigned int ext_read; -+ errcode_t retval; -+ ext2_ino_t ino; -+}; -+ -+static errcode_t load_extents(e2fsck_t ctx, struct extent_list *list) -+{ -+ ext2_filsys fs = ctx->fs; -+ ext2_extent_handle_t handle; -+ struct ext2fs_extent extent; -+ errcode_t retval; -+ -+ retval = ext2fs_extent_open(fs, list->ino, &handle); -+ if (retval) -+ return retval; -+ -+ retval = ext2fs_extent_get(handle, EXT2_EXTENT_ROOT, &extent); -+ if (retval) -+ goto out; -+ -+ do { -+ if (extent.e_flags & EXT2_EXTENT_FLAGS_SECOND_VISIT) -+ goto next; -+ -+ /* Internal node; free it and we'll re-allocate it later */ -+ if (!(extent.e_flags & EXT2_EXTENT_FLAGS_LEAF)) { -+#if defined(DEBUG) || defined(DEBUG_FREE) -+ printf("ino=%d free=%llu bf=%llu\n", list->ino, -+ extent.e_pblk, list->blocks_freed + 1); -+#endif -+ list->blocks_freed++; -+ ext2fs_block_alloc_stats2(fs, extent.e_pblk, -1); -+ goto next; -+ } -+ -+ list->ext_read++; -+ /* Can we attach it to the previous extent? */ -+ if (list->count) { -+ struct ext2fs_extent *last = list->extents + -+ list->count - 1; -+ blk64_t end = last->e_len + extent.e_len; -+ -+ if (last->e_pblk + last->e_len == extent.e_pblk && -+ last->e_lblk + last->e_len == extent.e_lblk && -+ (last->e_flags & EXT2_EXTENT_FLAGS_UNINIT) == -+ (extent.e_flags & EXT2_EXTENT_FLAGS_UNINIT) && -+ end < (1ULL << 32)) { -+ last->e_len += extent.e_len; -+#ifdef DEBUG -+ printf("R: ino=%d len=%u\n", list->ino, -+ last->e_len); -+#endif -+ goto next; -+ } -+ } -+ -+ /* Do we need to expand? */ -+ if (list->count == list->size) { -+ unsigned int new_size = (list->size + NUM_EXTENTS) * -+ sizeof(struct ext2fs_extent); -+ retval = ext2fs_resize_mem(0, new_size, &list->extents); -+ if (retval) -+ goto out; -+ list->size += NUM_EXTENTS; -+ } -+ -+ /* Add a new extent */ -+ memcpy(list->extents + list->count, &extent, sizeof(extent)); -+#ifdef DEBUG -+ printf("R: ino=%d pblk=%llu lblk=%llu len=%u\n", list->ino, -+ extent.e_pblk, extent.e_lblk, extent.e_len); -+#endif -+ list->count++; -+next: -+ retval = ext2fs_extent_get(handle, EXT2_EXTENT_NEXT, &extent); -+ } while (retval == 0); -+ -+out: -+ /* Ok if we run off the end */ -+ if (retval == EXT2_ET_EXTENT_NO_NEXT) -+ retval = 0; -+ ext2fs_extent_free(handle); -+ return retval; -+} -+ -+static int find_blocks(ext2_filsys fs, blk64_t *blocknr, e2_blkcnt_t blockcnt, -+ blk64_t ref_blk EXT2FS_ATTR((unused)), -+ int ref_offset EXT2FS_ATTR((unused)), void *priv_data) -+{ -+ struct extent_list *list = priv_data; -+ -+ /* Internal node? */ -+ if (blockcnt < 0) { -+#if defined(DEBUG) || defined(DEBUG_FREE) -+ printf("ino=%d free=%llu bf=%llu\n", list->ino, *blocknr, -+ list->blocks_freed + 1); -+#endif -+ list->blocks_freed++; -+ ext2fs_block_alloc_stats2(fs, *blocknr, -1); -+ return 0; -+ } -+ -+ /* Can we attach it to the previous extent? */ -+ if (list->count) { -+ struct ext2fs_extent *last = list->extents + -+ list->count - 1; -+ blk64_t end = last->e_len + 1; -+ -+ if (last->e_pblk + last->e_len == *blocknr && -+ end < (1ULL << 32)) { -+ last->e_len++; -+#ifdef DEBUG -+ printf("R: ino=%d len=%u\n", list->ino, last->e_len); -+#endif -+ return 0; -+ } -+ } -+ -+ /* Do we need to expand? */ -+ if (list->count == list->size) { -+ unsigned int new_size = (list->size + NUM_EXTENTS) * -+ sizeof(struct ext2fs_extent); -+ list->retval = ext2fs_resize_mem(0, new_size, &list->extents); -+ if (list->retval) -+ return BLOCK_ABORT; -+ list->size += NUM_EXTENTS; -+ } -+ -+ /* Add a new extent */ -+ list->extents[list->count].e_pblk = *blocknr; -+ list->extents[list->count].e_lblk = blockcnt; -+ list->extents[list->count].e_len = 1; -+ list->extents[list->count].e_flags = 0; -+#ifdef DEBUG -+ printf("R: ino=%d pblk=%llu lblk=%llu len=%u\n", list->ino, *blocknr, -+ blockcnt, 1); -+#endif -+ list->count++; -+ -+ return 0; -+} -+ -+static errcode_t rebuild_extent_tree(e2fsck_t ctx, struct extent_list *list, -+ ext2_ino_t ino) -+{ -+ struct ext2_inode inode; -+ errcode_t retval; -+ ext2_extent_handle_t handle; -+ unsigned int i, ext_written; -+ struct ext2fs_extent *ex, extent; -+ -+ list->count = 0; -+ list->blocks_freed = 0; -+ list->ino = ino; -+ list->ext_read = 0; -+ e2fsck_read_inode(ctx, ino, &inode, "rebuild_extents"); -+ -+ /* Skip deleted inodes and inline data files */ -+ if (inode.i_links_count == 0 || -+ inode.i_flags & EXT4_INLINE_DATA_FL) -+ return 0; -+ -+ /* Collect lblk->pblk mappings */ -+ if (inode.i_flags & EXT4_EXTENTS_FL) { -+ retval = load_extents(ctx, list); -+ if (retval) -+ goto err; -+ goto extents_loaded; -+ } -+ -+ retval = ext2fs_block_iterate3(ctx->fs, ino, BLOCK_FLAG_READ_ONLY, 0, -+ find_blocks, list); -+ if (retval) -+ goto err; -+ if (list->retval) { -+ retval = list->retval; -+ goto err; -+ } -+ -+extents_loaded: -+ /* Reset extent tree */ -+ inode.i_flags &= ~EXT4_EXTENTS_FL; -+ memset(inode.i_block, 0, sizeof(inode.i_block)); -+ -+ /* Make a note of freed blocks */ -+ retval = ext2fs_iblk_sub_blocks(ctx->fs, &inode, list->blocks_freed); -+ if (retval) -+ goto err; -+ -+ /* Now stuff extents into the file */ -+ retval = ext2fs_extent_open2(ctx->fs, ino, &inode, &handle); -+ if (retval) -+ goto err; -+ -+ ext_written = 0; -+ for (i = 0, ex = list->extents; i < list->count; i++, ex++) { -+ memcpy(&extent, ex, sizeof(struct ext2fs_extent)); -+ extent.e_flags &= EXT2_EXTENT_FLAGS_UNINIT; -+ if (extent.e_flags & EXT2_EXTENT_FLAGS_UNINIT) { -+ if (extent.e_len > EXT_UNINIT_MAX_LEN) { -+ extent.e_len = EXT_UNINIT_MAX_LEN; -+ ex->e_pblk += EXT_UNINIT_MAX_LEN; -+ ex->e_lblk += EXT_UNINIT_MAX_LEN; -+ ex->e_len -= EXT_UNINIT_MAX_LEN; -+ ex--; -+ i--; -+ } -+ } else { -+ if (extent.e_len > EXT_INIT_MAX_LEN) { -+ extent.e_len = EXT_INIT_MAX_LEN; -+ ex->e_pblk += EXT_INIT_MAX_LEN; -+ ex->e_lblk += EXT_INIT_MAX_LEN; -+ ex->e_len -= EXT_INIT_MAX_LEN; -+ ex--; -+ i--; -+ } -+ } -+ -+#ifdef DEBUG -+ printf("W: ino=%d pblk=%llu lblk=%llu len=%u\n", ino, -+ extent.e_pblk, extent.e_lblk, extent.e_len); -+#endif -+ retval = ext2fs_extent_insert(handle, EXT2_EXTENT_INSERT_AFTER, -+ &extent); -+ if (retval) -+ goto err2; -+ retval = ext2fs_extent_fix_parents(handle); -+ if (retval) -+ goto err2; -+ ext_written++; -+ } -+ -+#if defined(DEBUG) || defined(DEBUG_SUMMARY) -+ printf("rebuild: ino=%d extents=%d->%d\n", ino, list->ext_read, -+ ext_written); -+#endif -+ e2fsck_write_inode(ctx, ino, &inode, "rebuild_extents"); -+ -+err2: -+ ext2fs_extent_free(handle); -+err: -+ return retval; -+} -+ -+/* Rebuild the extents immediately */ -+static errcode_t e2fsck_rebuild_extents(e2fsck_t ctx, ext2_ino_t ino) -+{ -+ struct extent_list list; -+ errcode_t err; -+ -+ if (!EXT2_HAS_INCOMPAT_FEATURE(ctx->fs->super, -+ EXT3_FEATURE_INCOMPAT_EXTENTS) || -+ (ctx->options & E2F_OPT_NO) || -+ (ino != EXT2_ROOT_INO && ino < ctx->fs->super->s_first_ino)) -+ return 0; -+ -+ e2fsck_read_bitmaps(ctx); -+ memset(&list, 0, sizeof(list)); -+ err = ext2fs_get_mem(sizeof(struct ext2fs_extent) * NUM_EXTENTS, -+ &list.extents); -+ if (err) -+ return err; -+ list.size = NUM_EXTENTS; -+ err = rebuild_extent_tree(ctx, &list, ino); -+ ext2fs_free_mem(&list.extents); -+ -+ return err; -+} -+ -+static void rebuild_extents(e2fsck_t ctx, const char *pass_name, int pr_header) -+{ -+ struct problem_context pctx; -+#ifdef RESOURCE_TRACK -+ struct resource_track rtrack; -+#endif -+ struct extent_list list; -+ int first = 1; -+ ext2_ino_t ino = 0; -+ errcode_t retval; -+ -+ if (!EXT2_HAS_INCOMPAT_FEATURE(ctx->fs->super, -+ EXT3_FEATURE_INCOMPAT_EXTENTS) || -+ !ext2fs_test_valid(ctx->fs) || -+ ctx->invalid_bitmaps) { -+ if (ctx->inodes_to_rebuild) -+ ext2fs_free_inode_bitmap(ctx->inodes_to_rebuild); -+ ctx->inodes_to_rebuild = NULL; -+ } -+ -+ if (ctx->inodes_to_rebuild == NULL) -+ return; -+ -+ init_resource_track(&rtrack, ctx->fs->io); -+ clear_problem_context(&pctx); -+ e2fsck_read_bitmaps(ctx); -+ -+ memset(&list, 0, sizeof(list)); -+ retval = ext2fs_get_mem(sizeof(struct ext2fs_extent) * NUM_EXTENTS, -+ &list.extents); -+ list.size = NUM_EXTENTS; -+ while (1) { -+ retval = ext2fs_find_first_set_inode_bitmap2( -+ ctx->inodes_to_rebuild, ino + 1, -+ ctx->fs->super->s_inodes_count, &ino); -+ if (retval) -+ break; -+ pctx.ino = ino; -+ if (first) { -+ fix_problem(ctx, pr_header, &pctx); -+ first = 0; -+ } -+ pctx.errcode = rebuild_extent_tree(ctx, &list, ino); -+ if (pctx.errcode) { -+ end_problem_latch(ctx, PR_LATCH_OPTIMIZE_EXT); -+ fix_problem(ctx, PR_1E_OPTIMIZE_EXT_ERR, &pctx); -+ } -+ if (ctx->progress && !ctx->progress_fd) -+ e2fsck_simple_progress(ctx, "Rebuilding extents", -+ 100.0 * (float) ino / -+ (float) ctx->fs->super->s_inodes_count, -+ ino); -+ } -+ end_problem_latch(ctx, PR_LATCH_OPTIMIZE_EXT); -+ -+ ext2fs_free_inode_bitmap(ctx->inodes_to_rebuild); -+ ctx->inodes_to_rebuild = NULL; -+ ext2fs_free_mem(&list.extents); -+ -+ print_resource_track(ctx, pass_name, &rtrack, ctx->fs->io); -+} -+ -+/* Scan a file to see if we should rebuild its extent tree */ -+errcode_t e2fsck_check_rebuild_extents(e2fsck_t ctx, ext2_ino_t ino, -+ struct ext2_inode *inode, -+ struct problem_context *pctx) -+{ -+ struct extent_tree_info eti; -+ struct ext2_extent_info info, top_info; -+ struct ext2fs_extent extent; -+ ext2_extent_handle_t ehandle; -+ ext2_filsys fs = ctx->fs; -+ errcode_t retval; -+ -+ /* block map file and we want extent conversion */ -+ if (!(inode->i_flags & EXT4_EXTENTS_FL) && -+ !(inode->i_flags & EXT4_INLINE_DATA_FL) && -+ (ctx->options & E2F_OPT_CONVERT_BMAP)) { -+ return e2fsck_rebuild_extents_later(ctx, ino); -+ } -+ -+ if (!(inode->i_flags & EXT4_EXTENTS_FL)) -+ return 0; -+ memset(&eti, 0, sizeof(eti)); -+ eti.ino = ino; -+ -+ /* Otherwise, go scan the extent tree... */ -+ retval = ext2fs_extent_open2(fs, ino, inode, &ehandle); -+ if (retval) -+ return 0; -+ -+ retval = ext2fs_extent_get_info(ehandle, &top_info); -+ if (retval) -+ goto out; -+ -+ /* Check maximum extent depth */ -+ pctx->ino = ino; -+ pctx->blk = top_info.max_depth; -+ pctx->blk2 = ext2fs_max_extent_depth(ehandle); -+ if (pctx->blk2 < pctx->blk && -+ fix_problem(ctx, PR_1_EXTENT_BAD_MAX_DEPTH, pctx)) -+ eti.force_rebuild = 1; -+ -+ /* Can we collect extent tree level stats? */ -+ pctx->blk = MAX_EXTENT_DEPTH_COUNT; -+ if (pctx->blk2 > pctx->blk) -+ fix_problem(ctx, PR_1E_MAX_EXTENT_TREE_DEPTH, pctx); -+ -+ /* We need to fix tree depth problems, but the scan isn't a fix. */ -+ if (ctx->options & E2F_OPT_FIXES_ONLY) -+ goto out; -+ -+ retval = ext2fs_extent_get(ehandle, EXT2_EXTENT_ROOT, &extent); -+ if (retval) -+ goto out; -+ -+ do { -+ retval = ext2fs_extent_get_info(ehandle, &info); -+ if (retval) -+ break; -+ -+ /* -+ * If this is the first extent in an extent block that we -+ * haven't visited, collect stats on the block. -+ */ -+ if (info.curr_entry == 1 && -+ !(extent.e_flags & EXT2_EXTENT_FLAGS_SECOND_VISIT) && -+ !eti.force_rebuild) { -+ struct extent_tree_level *etl; -+ -+ etl = eti.ext_info + info.curr_level; -+ etl->num_extents += info.num_entries; -+ etl->max_extents += info.max_entries; -+ /* -+ * Implementation wart: Splitting extent blocks when -+ * appending will leave the old block with one free -+ * entry. Therefore unless the node is totally full, -+ * pretend that a non-root extent block can hold one -+ * fewer entry than it actually does, so that we don't -+ * repeatedly rebuild the extent tree. -+ */ -+ if (info.curr_level && -+ info.num_entries < info.max_entries) -+ etl->max_extents--; -+ } -+ -+ /* Skip to the end of a block of leaf nodes */ -+ if (extent.e_flags & EXT2_EXTENT_FLAGS_LEAF) { -+ retval = ext2fs_extent_get(ehandle, -+ EXT2_EXTENT_LAST_SIB, -+ &extent); -+ if (retval) -+ break; -+ } -+ -+ retval = ext2fs_extent_get(ehandle, EXT2_EXTENT_NEXT, &extent); -+ } while (retval == 0); -+out: -+ ext2fs_extent_free(ehandle); -+ return e2fsck_should_rebuild_extents(ctx, pctx, &eti, &top_info); -+} -+ -+/* Having scanned a file's extent tree, decide if we should rebuild it */ -+errcode_t e2fsck_should_rebuild_extents(e2fsck_t ctx, -+ struct problem_context *pctx, -+ struct extent_tree_info *eti, -+ struct ext2_extent_info *info) -+{ -+ struct extent_tree_level *ei; -+ int i, j, op; -+ unsigned int extents_per_block; -+ -+ if (eti->force_rebuild) -+ goto rebuild; -+ -+ extents_per_block = (ctx->fs->blocksize - -+ sizeof(struct ext3_extent_header)) / -+ sizeof(struct ext3_extent); -+ /* -+ * If we can consolidate a level or shorten the tree, schedule the -+ * extent tree to be rebuilt. -+ */ -+ for (i = 0, ei = eti->ext_info; i < info->max_depth + 1; i++, ei++) { -+ if (ei->max_extents - ei->num_extents > extents_per_block) { -+ pctx->blk = i; -+ op = PR_1E_CAN_NARROW_EXTENT_TREE; -+ goto rebuild; -+ } -+ for (j = 0; j < i; j++) { -+ if (ei->num_extents < eti->ext_info[j].max_extents) { -+ pctx->blk = i; -+ op = PR_1E_CAN_COLLAPSE_EXTENT_TREE; -+ goto rebuild; -+ } -+ } -+ } -+ return 0; -+ -+rebuild: -+ if (eti->force_rebuild || fix_problem(ctx, op, pctx)) -+ return e2fsck_rebuild_extents_later(ctx, eti->ino); -+ return 0; -+} -+ -+void e2fsck_pass1e(e2fsck_t ctx) -+{ -+ rebuild_extents(ctx, "Pass 1E", PR_1E_PASS_HEADER); -+} -diff --git a/e2fsck/gen_crc32table.c b/e2fsck/gen_crc32table.c -deleted file mode 100644 -index 2c1aa8e..0000000 ---- a/e2fsck/gen_crc32table.c -+++ /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 --#include "crc32defs.h" --#include -- --#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; --} -diff --git a/e2fsck/jfs_user.h b/e2fsck/jfs_user.h -index bfc1bcd..be81f43 100644 ---- a/e2fsck/jfs_user.h -+++ b/e2fsck/jfs_user.h -@@ -8,62 +8,83 @@ - * GNU General Public License version 2 or at your discretion - * any later version. - */ -- -+#ifndef _JFS_USER_H -+#define _JFS_USER_H -+ -+#ifdef DEBUGFS -+#include -+#include -+#if EXT2_FLAT_INCLUDES -+#include "ext2_fs.h" -+#include "ext2fs.h" -+#include "blkid.h" -+#else -+#include "ext2fs/ext2_fs.h" -+#include "ext2fs/ext2fs.h" -+#include "blkid/blkid.h" -+#endif -+#else - /* - * Pull in the definition of the e2fsck context structure - */ - #include "e2fsck.h" -+#endif - - struct buffer_head { -+#ifdef DEBUGFS -+ ext2_filsys b_fs; -+#else - e2fsck_t b_ctx; -- io_channel b_io; -- int b_size; -+#endif -+ io_channel b_io; -+ int b_size; - unsigned long long b_blocknr; -- int b_dirty; -- int b_uptodate; -- int b_err; -+ int b_dirty; -+ int b_uptodate; -+ int b_err; - char b_data[1024]; - }; - - struct inode { -+#ifdef DEBUGFS -+ ext2_filsys i_fs; -+#else - e2fsck_t i_ctx; -+#endif - ext2_ino_t i_ino; - struct ext2_inode i_ext2; - }; - - struct kdev_s { -+#ifdef DEBUGFS -+ ext2_filsys k_fs; -+#else - e2fsck_t k_ctx; -+#endif - int k_dev; - }; - - #define K_DEV_FS 1 - #define K_DEV_JOURNAL 2 - --typedef struct kdev_s *kdev_t; -- --#define lock_buffer(bh) do {} while(0) --#define unlock_buffer(bh) do {} while(0) -+#define lock_buffer(bh) do {} while (0) -+#define unlock_buffer(bh) do {} while (0) - #define buffer_req(bh) 1 --#define do_readahead(journal, start) do {} while(0) -- --extern e2fsck_t e2fsck_global_ctx; /* Try your very best not to use this! */ -+#define do_readahead(journal, start) do {} while (0) - - typedef struct { - int object_length; - } lkmem_cache_t; - --#define kmem_cache_alloc(cache,flags) malloc((cache)->object_length) --#define kmem_cache_free(cache,obj) free(obj) --#define kmem_cache_create(name,len,a,b,c,d) do_cache_create(len) -+#define kmem_cache_alloc(cache, flags) malloc((cache)->object_length) -+#define kmem_cache_free(cache, obj) free(obj) -+#define kmem_cache_create(name, len, a, b, c) do_cache_create(len) - #define kmem_cache_destroy(cache) do_cache_destroy(cache) --#define kmalloc(len,flags) malloc(len) -+#define kmalloc(len, flags) malloc(len) - #define kfree(p) free(p) - - #define cond_resched() do { } while (0) - --typedef unsigned int __be32; --typedef __u64 __be64; -- - #define __init - - /* -@@ -76,7 +97,7 @@ typedef __u64 __be64; - * functions. - */ - #ifdef NO_INLINE_FUNCS --extern lkmem_cache_t * do_cache_create(int len); -+extern lkmem_cache_t *do_cache_create(int len); - extern void do_cache_destroy(lkmem_cache_t *cache); - extern size_t journal_tag_bytes(journal_t *journal); - #endif -@@ -101,9 +122,10 @@ extern size_t journal_tag_bytes(journal_t *journal); - #endif /* E2FSCK_INCLUDE_INLINE_FUNCS */ - - --_INLINE_ lkmem_cache_t * do_cache_create(int len) -+_INLINE_ lkmem_cache_t *do_cache_create(int len) - { - lkmem_cache_t *new_cache; -+ - new_cache = malloc(sizeof(*new_cache)); - if (new_cache) - new_cache->object_length = len; -@@ -115,17 +137,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 - -@@ -134,7 +145,7 @@ _INLINE_ size_t journal_tag_bytes(journal_t *journal) - */ - int journal_bmap(journal_t *journal, blk64_t block, unsigned long long *phys); - struct buffer_head *getblk(kdev_t ctx, blk64_t blocknr, int blocksize); --void sync_blockdev(kdev_t kdev); -+int sync_blockdev(kdev_t kdev); - void ll_rw_block(int rw, int dummy, struct buffer_head *bh[]); - void mark_buffer_dirty(struct buffer_head *bh); - void mark_buffer_uptodate(struct buffer_head *bh, int val); -@@ -147,3 +158,41 @@ void wait_on_buffer(struct buffer_head *bh); - */ - #define __getblk(dev, blocknr, blocksize) getblk(dev, blocknr, blocksize) - #define set_buffer_uptodate(bh) mark_buffer_uptodate(bh, 1) -+ -+#ifdef DEBUGFS -+#include -+#undef J_ASSERT -+#define J_ASSERT(x) assert(x) -+ -+#define JSB_HAS_INCOMPAT_FEATURE(jsb, mask) \ -+ ((jsb)->s_header.h_blocktype == ext2fs_cpu_to_be32(JFS_SUPERBLOCK_V2) && \ -+ ((jsb)->s_feature_incompat & ext2fs_cpu_to_be32((mask)))) -+#else /* !DEBUGFS */ -+ -+extern e2fsck_t e2fsck_global_ctx; /* Try your very best not to use this! */ -+ -+#define J_ASSERT(assert) \ -+ do { if (!(assert)) { \ -+ printf ("Assertion failure in %s() at %s line %d: " \ -+ "\"%s\"\n", \ -+ __FUNCTION__, __FILE__, __LINE__, # assert); \ -+ fatal_error(e2fsck_global_ctx, 0); \ -+ } } while (0) -+ -+#endif /* DEBUGFS */ -+ -+/* recovery.c */ -+extern int journal_recover (journal_t *journal); -+extern int journal_skip_recovery (journal_t *); -+ -+/* revoke.c */ -+extern int journal_init_revoke(journal_t *, int); -+extern void journal_destroy_revoke(journal_t *); -+extern void journal_destroy_revoke_caches(void); -+extern int journal_init_revoke_caches(void); -+ -+extern int journal_set_revoke(journal_t *, unsigned long long, tid_t); -+extern int journal_test_revoke(journal_t *, unsigned long long, tid_t); -+extern void journal_clear_revoke(journal_t *); -+ -+#endif /* _JFS_USER_H */ -diff --git a/e2fsck/journal.c b/e2fsck/journal.c -index 3b40e00..9f32095 100644 ---- a/e2fsck/journal.c -+++ b/e2fsck/journal.c -@@ -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 (!journal_has_csum_v2or3(j)) -+ 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 (!journal_has_csum_v2or3(j)) -+ 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 (!journal_has_csum_v2or3(j)) -+ 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. -@@ -94,7 +144,7 @@ struct buffer_head *getblk(kdev_t kdev, blk64_t blocknr, int blocksize) - return bh; - } - --void sync_blockdev(kdev_t kdev) -+int sync_blockdev(kdev_t kdev) - { - io_channel io; - -@@ -103,7 +153,7 @@ void sync_blockdev(kdev_t kdev) - else - io = kdev->k_ctx->journal_io; - -- io_channel_flush(io); -+ return io_channel_flush(io) ? EIO : 0; - } - - void ll_rw_block(int rw, int nr, struct buffer_head *bhp[]) -@@ -406,7 +456,6 @@ static errcode_t e2fsck_get_journal(e2fsck_t ctx, journal_t **ret_journal) - } - memcpy(&jsuper, start ? bh->b_data : bh->b_data + SUPERBLOCK_OFFSET, - sizeof(jsuper)); -- brelse(bh); - #ifdef WORDS_BIGENDIAN - if (jsuper.s_magic == ext2fs_swab16(EXT2_SUPER_MAGIC)) - ext2fs_swap_super(&jsuper); -@@ -415,6 +464,7 @@ static errcode_t e2fsck_get_journal(e2fsck_t ctx, journal_t **ret_journal) - !(jsuper.s_feature_incompat & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)) { - fix_problem(ctx, PR_0_EXT_JOURNAL_BAD_SUPER, &pctx); - retval = EXT2_ET_LOAD_EXT_JOURNAL; -+ brelse(bh); - goto errout; - } - /* Make sure the journal UUID is correct */ -@@ -422,9 +472,32 @@ static errcode_t e2fsck_get_journal(e2fsck_t ctx, journal_t **ret_journal) - sizeof(jsuper.s_uuid))) { - fix_problem(ctx, PR_0_JOURNAL_BAD_UUID, &pctx); - retval = EXT2_ET_LOAD_EXT_JOURNAL; -+ brelse(bh); - goto errout; - } - -+ /* Check the superblock checksum */ -+ if (jsuper.s_feature_ro_compat & -+ EXT4_FEATURE_RO_COMPAT_METADATA_CSUM) { -+ struct struct_ext2_filsys fsx; -+ struct ext2_super_block superx; -+ void *p; -+ -+ p = start ? bh->b_data : bh->b_data + SUPERBLOCK_OFFSET; -+ memcpy(&fsx, ctx->fs, sizeof(fsx)); -+ memcpy(&superx, ctx->fs->super, sizeof(superx)); -+ fsx.super = &superx; -+ fsx.super->s_feature_ro_compat |= -+ EXT4_FEATURE_RO_COMPAT_METADATA_CSUM; -+ if (!ext2fs_superblock_csum_verify(&fsx, p) && -+ fix_problem(ctx, PR_0_EXT_JOURNAL_SUPER_CSUM_INVALID, -+ &pctx)) { -+ ext2fs_superblock_csum_set(&fsx, p); -+ mark_buffer_dirty(bh); -+ } -+ } -+ brelse(bh); -+ - maxlen = ext2fs_blocks_count(&jsuper); - journal->j_maxlen = (maxlen < 1ULL << 32) ? maxlen : (1ULL << 32) - 1; - start++; -@@ -472,10 +545,10 @@ static errcode_t e2fsck_journal_fix_bad_inode(e2fsck_t ctx, - pctx->ino = sb->s_journal_inum; - if (fix_problem(ctx, PR_0_JOURNAL_BAD_INODE, pctx)) { - if (has_journal && sb->s_journal_inum) -- printf("*** ext3 journal has been deleted - " -- "filesystem is now ext2 only ***\n\n"); -+ printf("*** journal has been deleted ***\n\n"); - sb->s_feature_compat &= ~EXT3_FEATURE_COMPAT_HAS_JOURNAL; - sb->s_journal_inum = 0; -+ memset(sb->s_jnl_blocks, 0, sizeof(sb->s_jnl_blocks)); - ctx->flags |= E2F_FLAG_JOURNAL_INODE; - ctx->fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY; - e2fsck_clear_recover(ctx, 1); -@@ -573,6 +646,23 @@ 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-3 are mutually exclusive features. */ -+ if (JFS_HAS_INCOMPAT_FEATURE(journal, JFS_FEATURE_INCOMPAT_CSUM_V2) && -+ JFS_HAS_INCOMPAT_FEATURE(journal, JFS_FEATURE_INCOMPAT_CSUM_V3)) -+ return EXT2_ET_CORRUPT_SUPERBLOCK; -+ -+ if (journal_has_csum_v2or3(journal) && -+ 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; -+ -+ if (journal_has_csum_v2or3(journal)) -+ journal->j_csum_seed = jbd2_chksum(journal, ~0, jsb->s_uuid, -+ sizeof(jsb->s_uuid)); -+ - /* 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 +730,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); -@@ -677,9 +768,10 @@ static void e2fsck_journal_release(e2fsck_t ctx, journal_t *journal, - mark_buffer_clean(journal->j_sb_buffer); - else if (!(ctx->options & E2F_OPT_READONLY)) { - jsb = journal->j_superblock; -- jsb->s_sequence = htonl(journal->j_transaction_sequence); -+ jsb->s_sequence = htonl(journal->j_tail_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 +916,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); - } - -diff --git a/e2fsck/message.c b/e2fsck/message.c -index 97f53fa..9c1433f 100644 ---- a/e2fsck/message.c -+++ b/e2fsck/message.c -@@ -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: -diff --git a/e2fsck/pass1.c b/e2fsck/pass1.c -index 3bf481f..61ae2d9 100644 ---- a/e2fsck/pass1.c -+++ b/e2fsck/pass1.c -@@ -56,6 +56,8 @@ - #define _INLINE_ inline - #endif - -+#undef DEBUG -+ - static int process_block(ext2_filsys fs, blk64_t *blocknr, - e2_blkcnt_t blockcnt, blk64_t ref_blk, - int ref_offset, void *priv_data); -@@ -68,6 +70,7 @@ static void mark_table_blocks(e2fsck_t ctx); - static void alloc_bb_map(e2fsck_t ctx); - static void alloc_imagic_map(e2fsck_t ctx); - static void mark_inode_bad(e2fsck_t ctx, ino_t ino); -+static void add_encrypted_dir(e2fsck_t ctx, ino_t ino); - static void handle_fs_bad_blocks(e2fsck_t ctx); - static void process_inodes(e2fsck_t ctx, char *block_buf); - static EXT2_QSORT_TYPE process_inode_cmp(const void *a, const void *b); -@@ -93,6 +96,8 @@ struct process_block_struct { - struct problem_context *pctx; - ext2fs_block_bitmap fs_meta_blocks; - e2fsck_t ctx; -+ region_t region; -+ struct extent_tree_info eti; - }; - - struct process_inode_block { -@@ -182,6 +187,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 +210,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) || -@@ -218,9 +238,34 @@ int e2fsck_pass1_check_symlink(ext2_filsys fs, ext2_ino_t ino, - if (io_channel_read_blk64(fs->io, inode->i_block[0], 1, buf)) - return 0; - -- len = strnlen(buf, fs->blocksize); -+ if (inode->i_flags & EXT4_ENCRYPT_FL) { -+ len = ext2fs_le32_to_cpu(*((__u32 *)buf)) + 4; -+ } else { -+ 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; -@@ -230,11 +275,30 @@ int e2fsck_pass1_check_symlink(ext2_filsys fs, ext2_ino_t ino, - return 0; - } - if (len != inode->i_size) -- return 0; -+ if ((inode->i_flags & EXT4_ENCRYPT_FL) == 0) -+ return 0; - return 1; - } - - /* -+ * 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 +338,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 +356,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 +405,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 +426,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 +443,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 +507,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 +535,52 @@ 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; -+ __u32 dotdot; -+ unsigned int rec_len; -+ struct ext2_dir_entry de; -+ -+ 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; -+ /* -+ * If the first 10 bytes don't look like a directory entry, -+ * it's probably not a directory. -+ */ -+ memcpy(&dotdot, inode->i_block, sizeof(dotdot)); -+ memcpy(&de, ((char *)inode->i_block) + EXT4_INLINE_DATA_DOTDOT_SIZE, -+ EXT2_DIR_REC_LEN(0)); -+ dotdot = ext2fs_le32_to_cpu(dotdot); -+ de.inode = ext2fs_le32_to_cpu(de.inode); -+ de.rec_len = ext2fs_le16_to_cpu(de.rec_len); -+ ext2fs_get_rec_len(ctx->fs, &de, &rec_len); -+ if (dotdot >= ctx->fs->super->s_inodes_count || -+ (dotdot < EXT2_FIRST_INO(ctx->fs->super) && -+ dotdot != EXT2_ROOT_INO) || -+ de.inode >= ctx->fs->super->s_inodes_count || -+ (de.inode < EXT2_FIRST_INO(ctx->fs->super) && -+ de.inode != 0) || -+ rec_len > EXT4_MIN_INLINE_DATA_SIZE - -+ EXT4_INLINE_DATA_DOTDOT_SIZE) -+ return; -+ /* device files never have a "system.data" entry */ -+ goto isdir; -+ } else if (extent_fs && (inode->i_flags & EXT4_EXTENTS_FL)) { - /* extent mapped */ - if (ext2fs_bmap2(ctx->fs, pctx->ino, inode, 0, 0, 0, 0, - &blk)) -@@ -473,7 +615,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 +624,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 +636,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 +683,38 @@ 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. -+ */ -+ ctx->stashed_ino = 0; -+ 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 +751,209 @@ 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 (inode_size > EXT2_GOOD_OLD_INODE_SIZE) -+ max_inline_ea_size = inode_size - -+ (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; -+} -+ -+static void pass1_readahead(e2fsck_t ctx, dgrp_t *group, ext2_ino_t *next_ino) -+{ -+ ext2_ino_t inodes_in_group = 0, inodes_per_block, inodes_per_buffer; -+ dgrp_t start = *group, grp; -+ blk64_t blocks_to_read = 0; -+ errcode_t err = EXT2_ET_INVALID_ARGUMENT; -+ -+ if (ctx->readahead_kb == 0) -+ goto out; -+ -+ /* Keep iterating groups until we have enough to readahead */ -+ inodes_per_block = EXT2_INODES_PER_BLOCK(ctx->fs->super); -+ for (grp = start; grp < ctx->fs->group_desc_count; grp++) { -+ if (ext2fs_bg_flags_test(ctx->fs, grp, EXT2_BG_INODE_UNINIT)) -+ continue; -+ inodes_in_group = ctx->fs->super->s_inodes_per_group - -+ ext2fs_bg_itable_unused(ctx->fs, grp); -+ blocks_to_read += (inodes_in_group + inodes_per_block - 1) / -+ inodes_per_block; -+ if (blocks_to_read * ctx->fs->blocksize > -+ ctx->readahead_kb * 1024) -+ break; -+ } -+ -+ err = e2fsck_readahead(ctx->fs, E2FSCK_READA_ITABLE, start, -+ grp - start + 1); -+ if (err == EAGAIN) { -+ ctx->readahead_kb /= 2; -+ err = 0; -+ } -+ -+out: -+ if (err) { -+ /* Error; disable itable readahead */ -+ *group = ctx->fs->group_desc_count; -+ *next_ino = ctx->fs->super->s_inodes_count; -+ } else { -+ /* -+ * Don't do more readahead until we've reached the first inode -+ * of the last inode scan buffer block for the last group. -+ */ -+ *group = grp + 1; -+ inodes_per_buffer = (ctx->inode_buffer_blocks ? -+ ctx->inode_buffer_blocks : -+ EXT2_INODE_SCAN_DEFAULT_BUFFER_BLOCKS) * -+ ctx->fs->blocksize / -+ EXT2_INODE_SIZE(ctx->fs->super); -+ inodes_in_group--; -+ *next_ino = inodes_in_group - -+ (inodes_in_group % inodes_per_buffer) + 1 + -+ (grp * ctx->fs->super->s_inodes_per_group); -+ } -+} -+ - void e2fsck_pass1(e2fsck_t ctx) - { - int i; -@@ -594,13 +972,23 @@ 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 inode_size = EXT2_INODE_SIZE(fs->super); -+ int failed_csum = 0; -+ ext2_ino_t ino_threshold = 0; -+ dgrp_t ra_group = 0; - - init_resource_track(&rtrack, ctx->fs->io); - clear_problem_context(&pctx); - -+ /* If we can do readahead, figure out how many groups to pull in. */ -+ if (!e2fsck_can_readahead(ctx->fs)) -+ ctx->readahead_kb = 0; -+ else if (ctx->readahead_kb == ~0ULL) -+ ctx->readahead_kb = e2fsck_guess_readahead(ctx->fs); -+ pass1_readahead(ctx, &ra_group, &ino_threshold); -+ - if (!(ctx->options & E2F_OPT_PREEN)) - fix_problem(ctx, PR_1_PASS_HEADER, &pctx); - -@@ -627,6 +1015,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 +1059,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, -@@ -683,7 +1082,6 @@ void e2fsck_pass1(e2fsck_t ctx) - ctx->flags |= E2F_FLAG_ABORT; - return; - } -- inode_size = EXT2_INODE_SIZE(fs->super); - inode = (struct ext2_inode *) - e2fsck_allocate_memory(ctx, inode_size, "scratch inode"); - -@@ -725,7 +1123,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 +1135,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 +1156,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)) -@@ -764,17 +1167,52 @@ void e2fsck_pass1(e2fsck_t ctx) - old_op = ehandler_operation(_("getting next inode from scan")); - pctx.errcode = ext2fs_get_next_inode_full(scan, &ino, - inode, inode_size); -+ if (ino > ino_threshold) -+ pass1_readahead(ctx, &ra_group, &ino_threshold); - ehandler_operation(old_op); - if (ctx->flags & E2F_FLAG_SIGNAL_MASK) - return; - if (pctx.errcode == EXT2_ET_BAD_BLOCK_IN_INODE_TABLE) { -+ /* -+ * If badblocks says badblocks is bad, offer to clear -+ * the list, update the in-core bb list, and restart -+ * the inode scan. -+ */ -+ if (ino == EXT2_BAD_INO && -+ fix_problem(ctx, PR_1_BADBLOCKS_IN_BADBLOCKS, -+ &pctx)) { -+ errcode_t err; -+ -+ e2fsck_clear_inode(ctx, ino, inode, 0, "pass1"); -+ ext2fs_badblocks_list_free(ctx->fs->badblocks); -+ ctx->fs->badblocks = NULL; -+ err = ext2fs_read_bb_inode(ctx->fs, -+ &ctx->fs->badblocks); -+ if (err) { -+ fix_problem(ctx, PR_1_ISCAN_ERROR, -+ &pctx); -+ ctx->flags |= E2F_FLAG_ABORT; -+ goto endit; -+ } -+ err = ext2fs_inode_scan_goto_blockgroup(scan, -+ 0); -+ if (err) { -+ fix_problem(ctx, PR_1_ISCAN_ERROR, -+ &pctx); -+ ctx->flags |= E2F_FLAG_ABORT; -+ goto endit; -+ } -+ continue; -+ } - if (!ctx->inode_bb_map) - alloc_bb_map(ctx); - ext2fs_mark_inode_bitmap2(ctx->inode_bb_map, ino); - 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 +1222,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 +1243,95 @@ 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; -+ } -+ if (LINUX_S_ISLNK(inode->i_mode)) -+ inode->i_flags &= ~EXT4_INLINE_DATA_FL; -+ 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 +1362,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 +1399,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 +1449,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 +1475,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 +1487,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 +1502,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 +1517,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 +1532,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 +1554,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 +1586,7 @@ void e2fsck_pass1(e2fsck_t ctx) - 0 : ctx->now; - e2fsck_write_inode(ctx, ino, inode, - "pass1"); -+ failed_csum = 0; - } - } - -@@ -1048,8 +1601,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 +1621,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; - } - } - -@@ -1103,6 +1659,7 @@ void e2fsck_pass1(e2fsck_t ctx) - inode->i_flags &= ~EXT2_IMAGIC_FL; - e2fsck_write_inode(ctx, ino, - inode, "pass1"); -+ failed_csum = 0; - } - } - } -@@ -1120,22 +1677,27 @@ 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)) { - ext2fs_mark_inode_bitmap2(ctx->inode_dir_map, ino); - e2fsck_add_dir_info(ctx, ino, 0); - ctx->fs_directory_count++; -+ if (inode->i_flags & EXT4_ENCRYPT_FL) -+ add_encrypted_dir(ctx, ino); - } else if (LINUX_S_ISREG (inode->i_mode)) { - ext2fs_mark_inode_bitmap2(ctx->inode_reg_map, ino); - 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++; -@@ -1144,25 +1706,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]) -@@ -1171,6 +1740,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] || -@@ -1181,6 +1751,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; - -@@ -1264,6 +1836,7 @@ void e2fsck_pass1(e2fsck_t ctx) - } - e2fsck_pass1_dupblocks(ctx, block_buf); - } -+ ctx->flags |= E2F_FLAG_ALLOC_OK; - ext2fs_free_mem(&inodes_to_process); - endit: - e2fsck_use_inode_shortcuts(ctx, 0); -@@ -1275,9 +1848,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 -@@ -1396,6 +1976,23 @@ static void mark_inode_bad(e2fsck_t ctx, ino_t ino) - ext2fs_mark_inode_bitmap2(ctx->inode_bad_map, ino); - } - -+static void add_encrypted_dir(e2fsck_t ctx, ino_t ino) -+{ -+ struct problem_context pctx; -+ -+ if (!ctx->encrypted_dirs) { -+ pctx.errcode = ext2fs_u32_list_create(&ctx->encrypted_dirs, 0); -+ if (pctx.errcode) -+ goto error; -+ } -+ pctx.errcode = ext2fs_u32_list_add(ctx->encrypted_dirs, ino); -+ if (pctx.errcode == 0) -+ return; -+error: -+ fix_problem(ctx, PR_1_ALLOCATE_ENCRYPTED_DIRLIST, &pctx); -+ /* Should never get here */ -+ ctx->flags |= E2F_FLAG_ABORT; -+} - - /* - * This procedure will allocate the inode "bb" (badblock) map table -@@ -1505,7 +2102,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; -@@ -1516,8 +2114,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); -@@ -1542,6 +2141,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) -@@ -1615,9 +2215,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) && -@@ -1633,6 +2242,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); -@@ -1697,6 +2309,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); -@@ -1779,6 +2403,16 @@ void e2fsck_clear_inode(e2fsck_t ctx, ext2_ino_t ino, - ext2fs_icount_store(ctx->inode_link_info, ino, 0); - inode->i_dtime = ctx->now; - -+ /* -+ * If a special inode has such rotten block mappings that we -+ * want to clear the whole inode, be sure to actually zap -+ * the block maps because i_links_count isn't checked for -+ * special inodes, and we'll end up right back here the next -+ * time we run fsck. -+ */ -+ if (ino < EXT2_FIRST_INODE(ctx->fs->super)) -+ memset(inode->i_block, 0, sizeof(inode->i_block)); -+ - ext2fs_unmark_inode_bitmap2(ctx->inode_dir_map, ino); - ext2fs_unmark_inode_bitmap2(ctx->inode_used_map, ino); - if (ctx->inode_reg_map) -@@ -1836,7 +2470,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; -@@ -1845,19 +2480,47 @@ 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) - return; -+ if (!(ctx->options & E2F_OPT_FIXES_ONLY) && -+ !pb->eti.force_rebuild) { -+ struct extent_tree_level *etl; -+ -+ etl = pb->eti.ext_info + info.curr_level; -+ etl->num_extents += info.num_entries; -+ etl->max_extents += info.max_entries; -+ /* -+ * Implementation wart: Splitting extent blocks when appending -+ * will leave the old block with one free entry. Therefore -+ * unless the node is totally full, pretend that a non-root -+ * extent block can hold one fewer entry than it actually does, -+ * so that we don't repeatedly rebuild the extent tree. -+ */ -+ if (info.curr_level && info.num_entries < info.max_entries) -+ etl->max_extents--; -+ } - - 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)) -@@ -1879,11 +2542,15 @@ static void scan_extent_node(e2fsck_t ctx, struct problem_context *pctx, - (1 << (21 - ctx->fs->super->s_log_block_size)))) - problem = PR_1_TOOBIG_DIR; - -+ if (is_leaf && problem == 0 && extent.e_len > 0 && -+ region_allocate(pb->region, extent.e_lblk, extent.e_len)) -+ problem = PR_1_EXTENT_COLLISION; -+ - /* - * 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; -@@ -1892,14 +2559,11 @@ 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)) { - if (ctx->invalid_bitmaps) { - /* -@@ -1942,6 +2606,7 @@ report_problem: - pctx->errcode = 0; - break; - } -+ failed_csum = 0; - continue; - } - goto next; -@@ -1949,13 +2614,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; -@@ -1980,7 +2665,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, -@@ -2021,16 +2707,16 @@ 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; - - new_lblk = pb->last_block + 1; - if (EXT2FS_CLUSTER_RATIO(ctx->fs) > 1) - new_lblk = ((new_lblk + -- EXT2FS_CLUSTER_RATIO(ctx->fs)) & -- EXT2FS_CLUSTER_MASK(ctx->fs)) | -- (extent.e_lblk & -+ EXT2FS_CLUSTER_RATIO(ctx->fs) - 1) & -+ ~EXT2FS_CLUSTER_MASK(ctx->fs)) | -+ (extent.e_pblk & - EXT2FS_CLUSTER_MASK(ctx->fs)); - pctx->blk = extent.e_lblk; - pctx->blk2 = new_lblk; -@@ -2051,6 +2737,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: -@@ -2118,6 +2805,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; - } -@@ -2144,14 +2841,38 @@ static void check_blocks_extents(e2fsck_t ctx, struct problem_context *pctx, - - retval = ext2fs_extent_get_info(ehandle, &info); - if (retval == 0) { -- if (info.max_depth >= MAX_EXTENT_DEPTH_COUNT) -- info.max_depth = MAX_EXTENT_DEPTH_COUNT-1; -- ctx->extent_depth_count[info.max_depth]++; -+ int max_depth = info.max_depth; -+ -+ if (max_depth >= MAX_EXTENT_DEPTH_COUNT) -+ max_depth = MAX_EXTENT_DEPTH_COUNT-1; -+ ctx->extent_depth_count[max_depth]++; -+ } -+ -+ /* Check maximum extent depth */ -+ pctx->blk = info.max_depth; -+ pctx->blk2 = ext2fs_max_extent_depth(ehandle); -+ if (pctx->blk2 < pctx->blk && -+ fix_problem(ctx, PR_1_EXTENT_BAD_MAX_DEPTH, pctx)) -+ pb->eti.force_rebuild = 1; -+ -+ /* Can we collect extent tree level stats? */ -+ pctx->blk = MAX_EXTENT_DEPTH_COUNT; -+ if (pctx->blk2 > pctx->blk) -+ fix_problem(ctx, PR_1E_MAX_EXTENT_TREE_DEPTH, pctx); -+ memset(pb->eti.ext_info, 0, sizeof(pb->eti.ext_info)); -+ pb->eti.ino = pb->ino; -+ -+ pb->region = region_create(0, info.max_lblk); -+ if (!pb->region) { -+ ext2fs_extent_free(ehandle); -+ fix_problem(ctx, PR_1_EXTENT_ALLOC_REGION_ABORT, pctx); -+ ctx->flags |= E2F_FLAG_ABORT; -+ return; - } - - 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; -@@ -2160,7 +2881,67 @@ static void check_blocks_extents(e2fsck_t ctx, struct problem_context *pctx, - "check_blocks_extents"); - pctx->errcode = 0; - } -+ region_free(pb->region); -+ pb->region = NULL; - ext2fs_extent_free(ehandle); -+ -+ /* Rebuild unless it's a dir and we're rehashing it */ -+ if (LINUX_S_ISDIR(inode->i_mode) && -+ e2fsck_dir_will_be_rehashed(ctx, ino)) -+ return; -+ -+ if (ctx->options & E2F_OPT_CONVERT_BMAP) -+ e2fsck_rebuild_extents_later(ctx, ino); -+ else -+ e2fsck_should_rebuild_extents(ctx, pctx, &pb->eti, &info); -+} -+ -+/* -+ * 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) -+{ -+ int flags; -+ size_t inline_data_size = 0; -+ -+ if (!pb->is_dir) { -+ pctx->errcode = 0; -+ return; -+ } -+ -+ /* Process the dirents in i_block[] as the "first" block. */ -+ pctx->errcode = ext2fs_add_dir_block2(ctx->fs->dblist, pb->ino, 0, 0); -+ if (pctx->errcode) -+ goto err; -+ -+ /* Process the dirents in the EA as a "second" block. */ -+ flags = ctx->fs->flags; -+ ctx->fs->flags |= EXT2_FLAG_IGNORE_CSUM_ERRORS; -+ pctx->errcode = ext2fs_inline_data_size(ctx->fs, pb->ino, -+ &inline_data_size); -+ ctx->fs->flags = (flags & EXT2_FLAG_IGNORE_CSUM_ERRORS) | -+ (ctx->fs->flags & ~EXT2_FLAG_IGNORE_CSUM_ERRORS); -+ if (pctx->errcode) { -+ pctx->errcode = 0; -+ return; -+ } -+ -+ if (inline_data_size <= EXT4_MIN_INLINE_DATA_SIZE) -+ return; -+ -+ pctx->errcode = ext2fs_add_dir_block2(ctx->fs->dblist, pb->ino, 0, 1); -+ if (pctx->errcode) -+ goto err; -+ -+ return; -+err: -+ pctx->blk = 0; -+ pctx->num = 0; -+ fix_problem(ctx, PR_1_ADD_DBLOCK, pctx); -+ ctx->flags |= E2F_FLAG_ABORT; - } - - /* -@@ -2177,6 +2958,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; -@@ -2196,35 +2978,28 @@ static void check_blocks(e2fsck_t ctx, struct problem_context *pctx, - pb.pctx = pctx; - pb.ctx = ctx; - pb.inode_modified = 0; -+ pb.eti.force_rebuild = 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 & -- EXT2_FEATURE_INCOMPAT_COMPRESSION) -- pb.compressed = 1; -- else { -- if (fix_problem(ctx, PR_1_COMPR_SET, pctx)) { -- inode->i_flags &= ~EXT2_COMPRBLK_FL; -- dirty_inode++; -- } -- } -- } -- -- 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. -@@ -2234,6 +3009,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); -@@ -2251,6 +3028,17 @@ 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); -+ -+ if (ctx->options & E2F_OPT_CONVERT_BMAP) { -+#ifdef DEBUG -+ printf("bmap rebuild ino=%d\n", ino); -+#endif -+ if (!LINUX_S_ISDIR(inode->i_mode) || -+ !e2fsck_dir_will_be_rehashed(ctx, ino)) -+ e2fsck_rebuild_extents_later(ctx, ino); -+ } - } - } - end_problem_latch(ctx, PR_LATCH_BLOCK); -@@ -2278,13 +3066,12 @@ static void check_blocks(e2fsck_t ctx, struct problem_context *pctx, - inode->i_flags &= ~EXT2_INDEX_FL; - dirty_inode++; - } else { --#ifdef ENABLE_HTREE - e2fsck_add_dx_dir(ctx, ino, pb.last_block+1); --#endif - } - } - -- 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--; -@@ -2310,7 +3097,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; -@@ -2342,12 +3147,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; -@@ -2370,10 +3183,28 @@ static void check_blocks(e2fsck_t ctx, struct problem_context *pctx, - pctx->num = 0; - } - -+ /* -+ * The kernel gets mad if we ask it to allocate bigalloc clusters to -+ * a block mapped file, so rebuild it as an extent file. We can skip -+ * symlinks because they're never rewritten. -+ */ -+ if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super, -+ EXT4_FEATURE_RO_COMPAT_BIGALLOC) && -+ (LINUX_S_ISREG(inode->i_mode) || LINUX_S_ISDIR(inode->i_mode)) && -+ ext2fs_inode_data_blocks2(fs, inode) > 0 && -+ (ino == EXT2_ROOT_INO || ino >= EXT2_FIRST_INO(fs->super)) && -+ !(inode->i_flags & (EXT4_EXTENTS_FL | EXT4_INLINE_DATA_FL)) && -+ fix_problem(ctx, PR_1_NO_BIGALLOC_BLOCKMAP_FILES, pctx)) { -+ pctx->errcode = e2fsck_rebuild_extents_later(ctx, ino); -+ if (pctx->errcode) -+ goto out; -+ } -+ - 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) -@@ -2453,28 +3284,6 @@ static int process_block(ext2_filsys fs, - pctx = p->pctx; - ctx = p->ctx; - -- if (p->compressed && (blk == EXT2FS_COMPRESSED_BLKADDR)) { -- /* todo: Check that the comprblk_fl is high, that the -- blkaddr pattern looks right (all non-holes up to -- first EXT2FS_COMPRESSED_BLKADDR, then all -- EXT2FS_COMPRESSED_BLKADDR up to end of cluster), -- that the feature_incompat bit is high, and that the -- inode is a regular file. If we're doing a "full -- check" (a concept introduced to e2fsck by e2compr, -- meaning that we look at data blocks as well as -- metadata) then call some library routine that -- checks the compressed data. I'll have to think -- about this, because one particularly important -- problem to be able to fix is to recalculate the -- cluster size if necessary. I think that perhaps -- we'd better do most/all e2compr-specific checks -- separately, after the non-e2compr checks. If not -- doing a full check, it may be useful to test that -- the personality is linux; e.g. if it isn't then -- perhaps this really is just an illegal block. */ -- return 0; -- } -- - /* - * For a directory, add logical block zero for processing even if it's - * not mapped or we'll be perennially stuck with broken "." and ".." -@@ -2503,7 +3312,7 @@ static int process_block(ext2_filsys fs, - * file be contiguous. (Which can never be true for really - * big files that are greater than a block group.) - */ -- if (!HOLE_BLKADDR(p->previous_block) && p->ino != EXT2_RESIZE_INO) { -+ if (p->previous_block && p->ino != EXT2_RESIZE_INO) { - if (p->previous_block+1 != blk) { - if (ctx->options & E2F_OPT_FRAGCHECK) { - char type = '?'; -@@ -2535,8 +3344,44 @@ 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)) { -+ 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 the IND/DIND/TIND block could have 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. -+ * -+ * Even if we previously determined that an *IND block -+ * conflicts with critical metadata, we must still try to -+ * iterate the *IND block as if it is an *IND block to find and -+ * mark the blocks it points to. Better to be overly cautious -+ * with the used_blocks map so that we don't move the *IND -+ * block to a block that's really in use! -+ */ -+ if (p->ino != EXT2_RESIZE_INO && -+ ref_block != 0 && -+ ext2fs_test_block_bitmap2(ctx->block_metadata_map, -+ ref_block)) { -+ *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; -@@ -2641,11 +3486,6 @@ static int process_bad_block(ext2_filsys fs, - struct problem_context *pctx; - e2fsck_t ctx; - -- /* -- * Note: This function processes blocks for the bad blocks -- * inode, which is never compressed. So we don't use HOLE_BLKADDR(). -- */ -- - if (!blk) - return 0; - -@@ -2864,12 +3704,15 @@ static void new_table_block(e2fsck_t ctx, blk64_t first_block, dgrp_t group, - old_block + i, 1, buf); - if (pctx.errcode) - fix_problem(ctx, PR_1_RELOC_READ_ERR, &pctx); -- } else -- memset(buf, 0, fs->blocksize); -+ pctx.blk = (*new_block) + i; -+ pctx.errcode = io_channel_write_blk64(fs->io, pctx.blk, -+ 1, buf); -+ } else { -+ pctx.blk = (*new_block) + i; -+ pctx.errcode = ext2fs_zero_blocks2(fs, pctx.blk, 1, -+ NULL, NULL); -+ } - -- pctx.blk = (*new_block) + i; -- pctx.errcode = io_channel_write_blk64(fs->io, pctx.blk, -- 1, buf); - if (pctx.errcode) - fix_problem(ctx, PR_1_RELOC_WRITE_ERR, &pctx); - } -@@ -2935,6 +3778,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 -@@ -2953,8 +3797,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); - } - } - } -@@ -2973,8 +3819,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 -@@ -2988,6 +3835,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)); - } -@@ -3072,7 +3921,7 @@ static errcode_t e2fsck_get_alloc_block(ext2_filsys fs, blk64_t goal, - return retval; - } - -- retval = ext2fs_new_block2(fs, goal, 0, &new_block); -+ retval = ext2fs_new_block2(fs, goal, fs->block_map, &new_block); - if (retval) - return retval; - } -@@ -3081,10 +3930,37 @@ static errcode_t e2fsck_get_alloc_block(ext2_filsys fs, blk64_t goal, - return (0); - } - -+static errcode_t e2fsck_new_range(ext2_filsys fs, int flags, blk64_t goal, -+ blk64_t len, blk64_t *pblk, blk64_t *plen) -+{ -+ e2fsck_t ctx = (e2fsck_t) fs->priv_data; -+ errcode_t retval; -+ -+ if (ctx->block_found_map) -+ return ext2fs_new_range(fs, flags, goal, len, -+ ctx->block_found_map, pblk, plen); -+ -+ if (!fs->block_map) { -+ retval = ext2fs_read_block_bitmap(fs); -+ if (retval) -+ return retval; -+ } -+ -+ return ext2fs_new_range(fs, flags, goal, len, fs->block_map, -+ pblk, plen); -+} -+ - 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); -@@ -3093,6 +3969,28 @@ static void e2fsck_block_alloc_stats(ext2_filsys fs, blk64_t blk, int inuse) - } - } - -+static void e2fsck_block_alloc_stats_range(ext2_filsys fs, blk64_t blk, -+ blk_t num, 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_bitmap_range2(ctx->block_metadata_map, blk, num)) -+ return; -+ -+ if (ctx->block_found_map) { -+ if (inuse > 0) -+ ext2fs_mark_block_bitmap_range2(ctx->block_found_map, -+ blk, num); -+ else -+ ext2fs_unmark_block_bitmap_range2(ctx->block_found_map, -+ blk, num); -+ } -+} -+ - void e2fsck_use_inode_shortcuts(e2fsck_t ctx, int use_shortcuts) - { - ext2_filsys fs = ctx->fs; -@@ -3116,4 +4014,7 @@ void e2fsck_intercept_block_allocations(e2fsck_t ctx) - ext2fs_set_alloc_block_callback(ctx->fs, e2fsck_get_alloc_block, 0); - ext2fs_set_block_alloc_stats_callback(ctx->fs, - e2fsck_block_alloc_stats, 0); -+ ext2fs_set_new_range_callback(ctx->fs, e2fsck_new_range, NULL); -+ ext2fs_set_block_alloc_stats_range_callback(ctx->fs, -+ e2fsck_block_alloc_stats_range, NULL); - } -diff --git a/e2fsck/pass1b.c b/e2fsck/pass1b.c -index bb81d5e..e0f34e0 100644 ---- a/e2fsck/pass1b.c -+++ b/e2fsck/pass1b.c -@@ -49,7 +49,7 @@ typedef long intptr_t; - #include "e2fsck.h" - - #include "problem.h" --#include "dict.h" -+#include "support/dict.h" - - /* Define an extension to the ext2 library's block count information */ - #define BLOCK_COUNT_EXTATTR (-5) -@@ -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,8 +362,9 @@ 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)) -+ if (*block_nr == 0) - return 0; - p = (struct process_block_struct *) priv_data; - ctx = p->ctx; -@@ -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); -@@ -609,7 +628,7 @@ static int delete_file_block(ext2_filsys fs, - pb = (struct process_block_struct *) priv_data; - ctx = pb->ctx; - -- if (HOLE_BLKADDR(*block_nr)) -+ if (*block_nr == 0) - return 0; - - c = EXT2FS_B2C(fs, *block_nr); -@@ -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; -@@ -706,8 +725,30 @@ struct clone_struct { - char *buf; - e2fsck_t ctx; - struct ext2_inode *inode; -+ -+ struct dup_cluster *save_dup_cluster; -+ blk64_t save_blocknr; - }; - -+/* -+ * Decrement the bad count *after* we've shown that (a) we can allocate a -+ * replacement block and (b) remap the file blocks. Unfortunately, there's no -+ * way to find out if the remap succeeded until either the next -+ * clone_file_block() call (an error when remapping the block after returning -+ * BLOCK_CHANGED will halt the iteration) or after block_iterate() returns. -+ * Otherwise, it's possible that we decrease the badcount once in preparation -+ * to remap, then the remap fails (either we can't find a replacement block or -+ * we have to split the extent tree and can't find a new extent block), so we -+ * delete the file, which decreases the badcount again. -+ */ -+static void deferred_dec_badcount(struct clone_struct *cs) -+{ -+ if (!cs->save_dup_cluster) -+ return; -+ decrement_badcount(cs->ctx, cs->save_blocknr, cs->save_dup_cluster); -+ cs->save_dup_cluster = NULL; -+} -+ - static int clone_file_block(ext2_filsys fs, - blk64_t *block_nr, - e2_blkcnt_t blockcnt, -@@ -715,7 +756,7 @@ static int clone_file_block(ext2_filsys fs, - int ref_offset EXT2FS_ATTR((unused)), - void *priv_data) - { -- struct dup_cluster *p; -+ struct dup_cluster *p = NULL; - blk64_t new_block; - errcode_t retval; - struct clone_struct *cs = (struct clone_struct *) priv_data; -@@ -725,8 +766,9 @@ static int clone_file_block(ext2_filsys fs, - int is_meta = 0; - - ctx = cs->ctx; -+ deferred_dec_badcount(cs); - -- if (HOLE_BLKADDR(*block_nr)) -+ if (*block_nr == 0) - return 0; - - c = EXT2FS_B2C(fs, blockcnt); -@@ -749,8 +791,6 @@ static int clone_file_block(ext2_filsys fs, - } - - p = (struct dup_cluster *) dnode_get(n); -- if (!is_meta) -- decrement_badcount(ctx, *block_nr, p); - - cs->dup_cluster = c; - /* -@@ -800,6 +840,8 @@ cluster_alloc_ok: - cs->errcode = retval; - return BLOCK_ABORT; - } -+ cs->save_dup_cluster = (is_meta ? NULL : p); -+ cs->save_blocknr = *block_nr; - *block_nr = new_block; - ext2fs_mark_block_bitmap2(ctx->block_found_map, new_block); - ext2fs_mark_block_bitmap2(fs->block_map, new_block); -@@ -829,6 +871,8 @@ static errcode_t clone_file(e2fsck_t ctx, ext2_ino_t ino, - cs.ctx = ctx; - cs.ino = ino; - cs.inode = &dp->inode; -+ cs.save_dup_cluster = NULL; -+ cs.save_blocknr = 0; - retval = ext2fs_get_mem(fs->blocksize, &cs.buf); - if (retval) - return retval; -@@ -841,6 +885,7 @@ static errcode_t clone_file(e2fsck_t ctx, ext2_ino_t ino, - if (ext2fs_inode_has_valid_blocks2(fs, &dp->inode)) - pctx.errcode = ext2fs_block_iterate3(fs, ino, 0, block_buf, - clone_file_block, &cs); -+ deferred_dec_badcount(&cs); - ext2fs_mark_bb_dirty(fs); - if (pctx.errcode) { - fix_problem(ctx, PR_1B_BLOCK_ITERATE, &pctx); -diff --git a/e2fsck/pass2.c b/e2fsck/pass2.c -index 4acddae..4b81575 100644 ---- a/e2fsck/pass2.c -+++ b/e2fsck/pass2.c -@@ -47,7 +47,7 @@ - - #include "e2fsck.h" - #include "problem.h" --#include "dict.h" -+#include "support/dict.h" - - #ifdef NO_INLINE_FUNCS - #define _INLINE_ -@@ -61,6 +61,9 @@ - * Keeps track of how many times an inode is referenced. - */ - static void deallocate_inode(e2fsck_t ctx, ext2_ino_t ino, char* block_buf); -+static int check_dir_block2(ext2_filsys fs, -+ struct ext2_db_entry2 *dir_blocks_info, -+ void *priv_data); - static int check_dir_block(ext2_filsys fs, - struct ext2_db_entry2 *dir_blocks_info, - void *priv_data); -@@ -77,6 +80,9 @@ struct check_dir_struct { - struct problem_context pctx; - int count, max; - e2fsck_t ctx; -+ unsigned long long list_offset; -+ unsigned long long ra_entries; -+ unsigned long long next_ra_off; - }; - - void e2fsck_pass2(e2fsck_t ctx) -@@ -96,6 +102,9 @@ void e2fsck_pass2(e2fsck_t ctx) - int i, depth; - problem_t code; - int bad_dir; -+ int (*check_dir_func)(ext2_filsys fs, -+ struct ext2_db_entry2 *dir_blocks_info, -+ void *priv_data); - - init_resource_track(&rtrack, ctx->fs->io); - clear_problem_context(&cd.pctx); -@@ -139,6 +148,9 @@ void e2fsck_pass2(e2fsck_t ctx) - cd.ctx = ctx; - cd.count = 1; - cd.max = ext2fs_dblist_count2(fs->dblist); -+ cd.list_offset = 0; -+ cd.ra_entries = ctx->readahead_kb * 1024 / ctx->fs->blocksize; -+ cd.next_ra_off = 0; - - if (ctx->progress) - (void) (ctx->progress)(ctx, 2, 0, cd.max); -@@ -146,7 +158,8 @@ void e2fsck_pass2(e2fsck_t ctx) - if (fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX) - ext2fs_dblist_sort2(fs->dblist, special_dir_block_cmp); - -- cd.pctx.errcode = ext2fs_dblist_iterate2(fs->dblist, check_dir_block, -+ check_dir_func = cd.ra_entries ? check_dir_block2 : check_dir_block; -+ cd.pctx.errcode = ext2fs_dblist_iterate2(fs->dblist, check_dir_func, - &cd); - if (ctx->flags & E2F_FLAG_SIGNAL_MASK || ctx->flags & E2F_FLAG_RESTART) - return; -@@ -162,11 +175,11 @@ void e2fsck_pass2(e2fsck_t ctx) - return; - } - --#ifdef ENABLE_HTREE - for (i=0; (dx_dir = e2fsck_dx_dir_info_iter(ctx, &i)) != 0;) { - if (ctx->flags & E2F_FLAG_SIGNAL_MASK) - return; -- if (dx_dir->numblocks == 0) -+ if (e2fsck_dir_will_be_rehashed(ctx, dx_dir->ino) || -+ dx_dir->numblocks == 0) - continue; - clear_problem_context(&pctx); - bad_dir = 0; -@@ -250,7 +263,7 @@ void e2fsck_pass2(e2fsck_t ctx) - } - } - e2fsck_free_dx_dir_info(ctx); --#endif -+ - ext2fs_free_mem(&buf); - ext2fs_free_dblist(fs->dblist); - -@@ -262,6 +275,10 @@ void e2fsck_pass2(e2fsck_t ctx) - ext2fs_free_inode_bitmap(ctx->inode_reg_map); - ctx->inode_reg_map = 0; - } -+ if (ctx->encrypted_dirs) { -+ ext2fs_u32_list_free(ctx->encrypted_dirs); -+ ctx->encrypted_dirs = 0; -+ } - - clear_problem_context(&pctx); - if (ctx->large_files) { -@@ -302,14 +319,14 @@ 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); - -- return strncmp(de_a->name, de_b->name, a_len); -+ return memcmp(de_a->name, de_b->name, a_len); - } - - /* -@@ -357,7 +374,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 +386,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 +411,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 +435,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 +453,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'; -@@ -454,27 +475,39 @@ static int check_dotdot(e2fsck_t ctx, - */ - static int check_name(e2fsck_t ctx, - struct ext2_dir_entry *dirent, -- ext2_ino_t dir_ino EXT2FS_ATTR((unused)), - struct problem_context *pctx) - { - int i; - int fixup = -1; - int ret = 0; - -- for ( i = 0; i < (dirent->name_len & 0xFF); i++) { -- if (dirent->name[i] == '/' || dirent->name[i] == '\0') { -- if (fixup < 0) { -- fixup = fix_problem(ctx, PR_2_BAD_NAME, pctx); -- } -- if (fixup) { -- dirent->name[i] = '.'; -- ret = 1; -- } -- } -+ for ( i = 0; i < ext2fs_dirent_name_len(dirent); i++) { -+ if (dirent->name[i] != '/' && dirent->name[i] != '\0') -+ continue; -+ if (fixup < 0) -+ fixup = fix_problem(ctx, PR_2_BAD_NAME, pctx); -+ if (fixup == 0) -+ return 0; -+ dirent->name[i] = '.'; -+ ret = 1; - } - return ret; - } - -+static int encrypted_check_name(e2fsck_t ctx, -+ struct ext2_dir_entry *dirent, -+ struct problem_context *pctx) -+{ -+ if (ext2fs_dirent_name_len(dirent) < EXT4_CRYPTO_BLOCK_SIZE) { -+ if (fix_problem(ctx, PR_2_BAD_ENCRYPTED_NAME, pctx)) { -+ dirent->inode = 0; -+ return 1; -+ } -+ ext2fs_unmark_valid(ctx->fs); -+ } -+ return 0; -+} -+ - /* - * Check the directory filetype (if present) - */ -@@ -483,7 +516,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 +525,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,16 +551,15 @@ 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; - } - --#ifdef ENABLE_HTREE - 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 +570,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 +585,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 +611,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,8 +682,8 @@ 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 */ - - /* - * Given a busted directory, try to salvage it somehow. -@@ -642,23 +692,35 @@ 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; - -- (void) ext2fs_get_rec_len(fs, dirent, &rec_len); -- left = fs->blocksize - *offset - rec_len; -+ /* -+ * If the space left for the entry is too small to be an entry, -+ * we can't access dirent's fields, so plumb in the values needed -+ * so that the previous entry absorbs this one. -+ */ -+ if (block_len - *offset < EXT2_DIR_ENTRY_HEADER_LEN) { -+ name_len = 0; -+ rec_len = block_len - *offset; -+ } else { -+ name_len = ext2fs_dirent_name_len(dirent); -+ (void) ext2fs_get_rec_len(fs, dirent, &rec_len); -+ } -+ left = block_len - *offset - rec_len; - - /* - * Special case of directory entry of size 8: copy what's left - * of the directory block up to cover up the invalid hole. - */ -- if ((left >= 12) && (rec_len == 8)) { -- memmove(cp, cp+8, left); -- memset(cp + left, 0, 8); -+ if ((left >= 12) && (rec_len == EXT2_DIR_ENTRY_HEADER_LEN)) { -+ memmove(cp, cp+EXT2_DIR_ENTRY_HEADER_LEN, left); -+ memset(cp + left, 0, EXT2_DIR_ENTRY_HEADER_LEN); - return; - } - /* -@@ -667,8 +729,8 @@ static void salvage_directory(ext2_filsys fs, - * record length. - */ - if ((left < 0) && -- ((int) rec_len + left > 8) && -- ((int) name_len + 8 <= (int) rec_len + left) && -+ ((int) rec_len + left > EXT2_DIR_ENTRY_HEADER_LEN) && -+ ((int) name_len + EXT2_DIR_ENTRY_HEADER_LEN <= (int) rec_len + left) && - dirent->inode <= fs->super->s_inodes_count && - strnlen(dirent->name, name_len) == name_len) { - (void) ext2fs_set_rec_len(fs, (int) rec_len + left, dirent); -@@ -680,7 +742,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,26 +757,144 @@ 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; - } - } - -+#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; -+ -+ 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; -+ /* -+ * If there's not enough bytes to start the "second" dir block -+ * (in the EA space) then truncate everything to the first block. -+ */ -+ if (old_size > EXT4_MIN_INLINE_DATA_SIZE && -+ old_size < EXT4_MIN_INLINE_DATA_SIZE + -+ EXT2_DIR_REC_LEN(1)) { -+ old_size = EXT4_MIN_INLINE_DATA_SIZE; -+ new_size = old_size; -+ } else -+ /* Increase to the next four-byte boundary for salvaging */ -+ 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) { -+ /* Or we can't, so truncate. */ -+ 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_block2(ext2_filsys fs, -+ struct ext2_db_entry2 *db, -+ void *priv_data) -+{ -+ int err; -+ struct check_dir_struct *cd = priv_data; -+ -+ if (cd->ra_entries && cd->list_offset >= cd->next_ra_off) { -+ err = e2fsck_readahead_dblist(fs, -+ E2FSCK_RA_DBLIST_IGNORE_BLOCKCNT, -+ fs->dblist, -+ cd->list_offset + cd->ra_entries / 8, -+ cd->ra_entries); -+ if (err) -+ cd->ra_entries = 0; -+ cd->next_ra_off = cd->list_offset + (cd->ra_entries * 7 / 8); -+ } -+ -+ err = check_dir_block(fs, db, priv_data); -+ cd->list_offset++; -+ return err; -+} -+ - static int check_dir_block(ext2_filsys fs, - struct ext2_db_entry2 *db, - void *priv_data) - { - struct dx_dir_info *dx_dir; --#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; -@@ -725,7 +905,7 @@ static int check_dir_block(ext2_filsys fs, - ext2_ino_t subdir_parent; - __u16 links; - struct check_dir_struct *cd; -- char *buf; -+ char *buf, *ibuf; - e2fsck_t ctx; - problem_t problem; - struct ext2_dx_root_info *root; -@@ -734,9 +914,16 @@ 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; -+ int encrypted = 0; -+ size_t max_block_size; - - cd = (struct check_dir_struct *) priv_data; -- buf = cd->buf; -+ ibuf = buf = cd->buf; - ctx = cd->ctx; - - if (ctx->flags & E2F_FLAG_SIGNAL_MASK || ctx->flags & E2F_FLAG_RESTART) -@@ -745,6 +932,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 +956,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,18 +986,66 @@ 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) { -+ memset(buf, 0, fs->blocksize - 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 -+ if (db->blockcnt) -+ goto skip_first_read_swab; -+ *((__u32 *)buf) = ext2fs_le32_to_cpu(*((__u32 *)buf)); -+ cd->pctx.errcode = ext2fs_dirent_swab_in2(fs, -+ buf + EXT4_INLINE_DATA_DOTDOT_SIZE, -+ EXT4_MIN_INLINE_DATA_SIZE - EXT4_INLINE_DATA_DOTDOT_SIZE, -+ 0); -+ if (cd->pctx.errcode) -+ goto inline_read_fail; -+skip_first_read_swab: -+ if (inline_data_size <= EXT4_MIN_INLINE_DATA_SIZE || -+ !db->blockcnt) -+ goto inline_read_fail; -+ cd->pctx.errcode = ext2fs_dirent_swab_in2(fs, -+ buf + EXT4_MIN_INLINE_DATA_SIZE, -+ inline_data_size - EXT4_MIN_INLINE_DATA_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) || -+ (inline_data_size > EXT4_MIN_INLINE_DATA_SIZE && -+ inline_data_size < EXT4_MIN_INLINE_DATA_SIZE + -+ EXT2_DIR_REC_LEN(1))) && -+ 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); - if (dx_dir && dx_dir->numblocks) { - if (db->blockcnt >= dx_dir->numblocks) { -@@ -833,36 +1087,145 @@ 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 = (dx_db->type == DX_DIRBLOCK_LEAF); - } - 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)) { -+ failed_csum = 0; -+ goto skip_checksum; -+ } -+ if (!fix_problem(cd->ctx, PR_2_LEAF_NODE_MISSING_CSUM, -+ &cd->pctx)) -+ goto skip_checksum; -+ e2fsck_rehash_dir_later(ctx, ino); -+ failed_csum = 0; -+ goto skip_checksum; -+ } -+ /* htree nodes don't use fake dirents to store checksums */ -+ if (!is_leaf) -+ de_csum_size = 0; -+ -+skip_checksum: -+ if (inline_data_size) { -+ if (db->blockcnt) { -+ buf += EXT4_MIN_INLINE_DATA_SIZE; -+ max_block_size = inline_data_size - EXT4_MIN_INLINE_DATA_SIZE; -+ /* Zero-length second block, just exit */ -+ if (max_block_size == 0) -+ return 0; -+ } else { -+ max_block_size = EXT4_MIN_INLINE_DATA_SIZE; -+ } -+ } else -+ max_block_size = fs->blocksize - de_csum_size; -+ -+ if (ctx->encrypted_dirs) -+ encrypted = ext2fs_u32_list_test(ctx->encrypted_dirs, ino); - - dict_init(&de_dict, DICTCOUNT_T_MAX, dict_de_cmp); - prev = 0; - do { - dgrp_t group; - ext2_ino_t first_unused_inode; -+ unsigned int name_len; - - problem = 0; -- dirent = (struct ext2_dir_entry *) (buf + offset); -- (void) ext2fs_get_rec_len(fs, dirent, &rec_len); -- cd->pctx.dirent = dirent; -- cd->pctx.num = offset; -- if (((offset + rec_len) > fs->blocksize) || -- (rec_len < 12) || -- ((rec_len % 4) != 0) || -- (((dirent->name_len & (unsigned) 0xFF)+8) > rec_len)) { -- if (fix_problem(ctx, PR_2_DIR_CORRUPTED, &cd->pctx)) { -- salvage_directory(fs, dirent, prev, &offset); -- dir_modified++; -- continue; -- } else -- goto abort_free_dict; -+ if (!inline_data_size || dot_state > 1) { -+ dirent = (struct ext2_dir_entry *) (buf + offset); -+ /* -+ * If there's not even space for the entry header, -+ * force salvaging this dir. -+ */ -+ if (max_block_size - offset < EXT2_DIR_ENTRY_HEADER_LEN) -+ rec_len = EXT2_DIR_REC_LEN(1); -+ else -+ (void) ext2fs_get_rec_len(fs, dirent, &rec_len); -+ cd->pctx.dirent = dirent; -+ cd->pctx.num = offset; -+ if ((offset + rec_len > max_block_size) || -+ (rec_len < 12) || -+ ((rec_len % 4) != 0) || -+ ((ext2fs_dirent_name_len(dirent) + EXT2_DIR_ENTRY_HEADER_LEN) > rec_len)) { -+ if (fix_problem(ctx, PR_2_DIR_CORRUPTED, -+ &cd->pctx)) { -+#ifdef WORDS_BIGENDIAN -+ /* -+ * On big-endian systems, if the dirent -+ * swap routine finds a rec_len that it -+ * doesn't like, it continues -+ * processing the block as if rec_len -+ * == EXT2_DIR_ENTRY_HEADER_LEN. This means that the name -+ * field gets byte swapped, which means -+ * that salvage will not detect the -+ * correct name length (unless the name -+ * has a length that's an exact -+ * multiple of four bytes), and it'll -+ * discard the entry (unnecessarily) -+ * and the rest of the dirent block. -+ * Therefore, swap the rest of the -+ * block back to disk order, run -+ * salvage, and re-swap anything after -+ * the salvaged dirent. -+ */ -+ int need_reswab = 0; -+ if (rec_len < EXT2_DIR_ENTRY_HEADER_LEN || rec_len % 4) { -+ need_reswab = 1; -+ ext2fs_dirent_swab_in2(fs, -+ ((char *)dirent) + EXT2_DIR_ENTRY_HEADER_LEN, -+ max_block_size - offset - EXT2_DIR_ENTRY_HEADER_LEN, -+ 0); -+ } -+#endif -+ salvage_directory(fs, dirent, prev, -+ &offset, -+ max_block_size); -+#ifdef WORDS_BIGENDIAN -+ if (need_reswab) { -+ (void) ext2fs_get_rec_len(fs, -+ dirent, &rec_len); -+ ext2fs_dirent_swab_in2(fs, -+ ((char *)dirent) + offset + rec_len, -+ max_block_size - offset - rec_len, -+ 0); -+ } -+#endif -+ dir_modified++; -+ continue; -+ } else -+ goto abort_free_dict; -+ } -+ } else { -+ if (dot_state == 0) { -+ memset(&dot, 0, sizeof(dot)); -+ dirent = ˙ -+ 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) { -@@ -888,6 +1251,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)) { -@@ -900,8 +1264,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 -@@ -909,8 +1272,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] == '.')) { - /* -@@ -928,8 +1290,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. - */ -@@ -1033,23 +1394,27 @@ out_htree: - } - } - -- if (check_name(ctx, dirent, ino, &cd->pctx)) -+ if (!encrypted && check_name(ctx, dirent, &cd->pctx)) - dir_modified++; - -+ if (encrypted && (dot_state) > 1 && -+ encrypted_check_name(ctx, dirent, &cd->pctx)) { -+ dir_modified++; -+ goto next; -+ } -+ - if (check_filetype(ctx, dirent, ino, &cd->pctx)) - dir_modified++; - --#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; - if (hash > dx_db->max_hash) - dx_db->max_hash = hash; - } --#endif - - /* - * If this is a directory, then mark its parent in its -@@ -1089,10 +1454,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); -@@ -1106,13 +1468,28 @@ 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 (offset < max_block_size); - #if 0 - printf("\n"); - #endif --#ifdef ENABLE_HTREE - if (dx_db) { - #ifdef DX_DEBUG - printf("db_block %d, type %d, min_hash 0x%0x, max_hash 0x%0x\n", -@@ -1122,24 +1499,87 @@ out_htree: - cd->pctx.dir = cd->pctx.ino; - if ((dx_db->type == DX_DIRBLOCK_ROOT) || - (dx_db->type == DX_DIRBLOCK_NODE)) -- parse_int_node(fs, db, cd, dx_dir, buf); -+ parse_int_node(fs, db, cd, dx_dir, buf, failed_csum); - } --#endif /* ENABLE_HTREE */ -- if (offset != fs->blocksize) { -- cd->pctx.num = rec_len - fs->blocksize + offset; -+ -+ if (offset != max_block_size) { -+ cd->pctx.num = rec_len + offset - max_block_size; - 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) { -+ buf = ibuf; -+#ifdef WORDS_BIGENDIAN -+ if (db->blockcnt) -+ goto skip_first_write_swab; -+ *((__u32 *)buf) = ext2fs_le32_to_cpu(*((__u32 *)buf)); -+ cd->pctx.errcode = ext2fs_dirent_swab_out2(fs, -+ buf + EXT4_INLINE_DATA_DOTDOT_SIZE, -+ EXT4_MIN_INLINE_DATA_SIZE - -+ EXT4_INLINE_DATA_DOTDOT_SIZE, -+ 0); -+ if (cd->pctx.errcode) -+ goto skip_second_write_swab; -+skip_first_write_swab: -+ if (inline_data_size <= EXT4_MIN_INLINE_DATA_SIZE || -+ !db->blockcnt) -+ goto skip_second_write_swab; -+ cd->pctx.errcode = ext2fs_dirent_swab_out2(fs, -+ buf + EXT4_MIN_INLINE_DATA_SIZE, -+ inline_data_size - -+ EXT4_MIN_INLINE_DATA_SIZE, -+ 0); -+skip_second_write_swab: -+ 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; -@@ -1167,7 +1607,7 @@ static int deallocate_inode_block(ext2_filsys fs, - { - struct del_block *p = priv_data; - -- if (HOLE_BLKADDR(*block_nr)) -+ if (*block_nr == 0) - return 0; - if ((*block_nr < fs->super->s_first_data_block) || - (*block_nr >= ext2fs_blocks_count(fs->super))) -@@ -1201,9 +1641,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; -@@ -1224,6 +1664,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--; -@@ -1402,7 +1846,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 -@@ -1435,7 +1878,8 @@ static int allocate_dir_block(e2fsck_t ctx, - pctx->errcode = ext2fs_map_cluster_block(fs, db->ino, &inode, - db->blockcnt, &blk); - if (pctx->errcode || blk == 0) { -- pctx->errcode = ext2fs_new_block2(fs, 0, -+ blk = ext2fs_find_inode_goal(fs, db->ino, &inode, db->blockcnt); -+ pctx->errcode = ext2fs_new_block2(fs, blk, - ctx->block_found_map, &blk); - if (pctx->errcode) { - pctx->str = "ext2fs_new_block"; -@@ -1462,7 +1906,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"; -diff --git a/e2fsck/pass3.c b/e2fsck/pass3.c -index 0274213..d7b8802 100644 ---- a/e2fsck/pass3.c -+++ b/e2fsck/pass3.c -@@ -100,7 +100,8 @@ void e2fsck_pass3(e2fsck_t ctx) - - iter = e2fsck_dir_info_iter_begin(ctx); - while ((dir = e2fsck_dir_info_iter(ctx, iter)) != 0) { -- if (ctx->flags & E2F_FLAG_SIGNAL_MASK) -+ if (ctx->flags & E2F_FLAG_SIGNAL_MASK || -+ ctx->flags & E2F_FLAG_RESTART) - goto abort_exit; - if (ctx->progress && (ctx->progress)(ctx, 3, count++, maxdirs)) - goto abort_exit; -@@ -205,27 +206,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 +228,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); -@@ -381,18 +385,44 @@ ext2_ino_t e2fsck_get_lost_and_found(e2fsck_t ctx, int fix) - char * block; - static const char name[] = "lost+found"; - struct problem_context pctx; -+ int will_rehash, flags; - - if (ctx->lost_and_found) - return ctx->lost_and_found; - - clear_problem_context(&pctx); - -+ will_rehash = e2fsck_dir_will_be_rehashed(ctx, EXT2_ROOT_INO); -+ if (will_rehash) { -+ flags = ctx->fs->flags; -+ ctx->fs->flags |= EXT2_FLAG_IGNORE_CSUM_ERRORS; -+ } - retval = ext2fs_lookup(fs, EXT2_ROOT_INO, name, - sizeof(name)-1, 0, &ino); -+ if (will_rehash) -+ ctx->fs->flags = (flags & EXT2_FLAG_IGNORE_CSUM_ERRORS) | -+ (ctx->fs->flags & ~EXT2_FLAG_IGNORE_CSUM_ERRORS); - 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 (fix && (inode.i_flags & EXT4_ENCRYPT_FL)) { -+ if (!fix_problem(ctx, PR_3_LPF_ENCRYPTED, &pctx)) -+ return 0; -+ goto unlink; -+ } -+ -+ if (ext2fs_check_directory(fs, ino) == 0) { - ctx->lost_and_found = ino; - return ino; - } -@@ -404,6 +434,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) { -@@ -413,6 +444,15 @@ ext2_ino_t e2fsck_get_lost_and_found(e2fsck_t ctx, int fix) - } - (void) e2fsck_dir_info_set_parent(ctx, ino, 0); - e2fsck_adjust_inode_count(ctx, ino, -1); -+ /* -+ * If the old lost+found was a directory, we've just -+ * disconnected it from the directory tree, which -+ * means we need to restart the directory tree scan. -+ * The simplest way to do this is restart the whole -+ * e2fsck operation. -+ */ -+ if (LINUX_S_ISDIR(inode.i_mode)) -+ ctx->flags |= E2F_FLAG_RESTART; - } else if (retval != EXT2_ET_FILE_NOT_FOUND) { - pctx.errcode = retval; - fix_problem(ctx, PR_3_ERR_FIND_LPF, &pctx); -@@ -435,6 +475,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 +495,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 +511,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,11 +530,40 @@ 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 - */ - pctx.errcode = ext2fs_link(fs, EXT2_ROOT_INO, name, ino, EXT2_FT_DIR); -+ if (pctx.errcode == EXT2_ET_DIR_NO_SPACE) { -+ pctx.errcode = ext2fs_expand_dir(fs, EXT2_ROOT_INO); -+ if (pctx.errcode) -+ goto link_error; -+ pctx.errcode = ext2fs_link(fs, EXT2_ROOT_INO, name, ino, -+ EXT2_FT_DIR); -+ } - if (pctx.errcode) { -+link_error: - pctx.str = "ext2fs_link"; - fix_problem(ctx, PR_3_CREATE_LPF_ERROR, &pctx); - return 0; -@@ -635,7 +698,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 +718,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 +732,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 +745,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 +780,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,21 +832,15 @@ static int expand_dir_proc(ext2_filsys fs, - return BLOCK_ABORT; - } - es->num--; -- retval = ext2fs_write_dir_block3(fs, new_blk, block, 0); -- } else { -- retval = ext2fs_get_mem(fs->blocksize, &block); -- if (retval) { -- es->err = retval; -- return BLOCK_ABORT; -- } -- memset(block, 0, fs->blocksize); -- retval = io_channel_write_blk64(fs->io, new_blk, 1, block); -- } -+ retval = ext2fs_write_dir_block4(fs, new_blk, block, 0, -+ es->dir); -+ ext2fs_free_mem(&block); -+ } else -+ retval = ext2fs_zero_blocks2(fs, new_blk, 1, NULL, NULL); - if (retval) { - es->err = retval; - return BLOCK_ABORT; - } -- ext2fs_free_mem(&block); - *blocknr = new_blk; - ext2fs_mark_block_bitmap2(ctx->block_found_map, new_blk); - -@@ -791,7 +857,7 @@ errcode_t e2fsck_expand_directory(e2fsck_t ctx, ext2_ino_t dir, - errcode_t retval; - struct expand_dir_struct es; - struct ext2_inode inode; -- blk64_t sz, before, after; -+ blk64_t sz; - - if (!(fs->flags & EXT2_FLAG_RW)) - return EXT2_ET_RO_FILSYS; -@@ -812,6 +878,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); -diff --git a/e2fsck/pass4.c b/e2fsck/pass4.c -index 21d93f0..bc9a2c4 100644 ---- a/e2fsck/pass4.c -+++ b/e2fsck/pass4.c -@@ -106,6 +106,15 @@ void e2fsck_pass4(e2fsck_t ctx) - #ifdef MTRACE - mtrace_print("Pass 4"); - #endif -+ /* -+ * Since pass4 is mostly CPU bound, start readahead of bitmaps -+ * ahead of pass 5 if we haven't already loaded them. -+ */ -+ if (ctx->readahead_kb && -+ (fs->block_map == NULL || fs->inode_map == NULL)) -+ e2fsck_readahead(fs, E2FSCK_READA_BBITMAP | -+ E2FSCK_READA_IBITMAP, -+ 0, fs->group_desc_count); - - clear_problem_context(&pctx); - -diff --git a/e2fsck/pass5.c b/e2fsck/pass5.c -index bc9a32a..64fb7fe 100644 ---- a/e2fsck/pass5.c -+++ b/e2fsck/pass5.c -@@ -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,133 @@ 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 = NULL; -+ 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_mem(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 = NULL; -+ 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_mem(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) - { -@@ -206,11 +325,7 @@ static void check_block_bitmaps(e2fsck_t ctx) - problem_t problem, save_problem; - int fixit, had_problem; - errcode_t retval; -- int old_desc_blocks = 0; -- int count = 0; -- int cmp_block = 0; - int redo_flag = 0; -- blk64_t super_blk, old_desc_blk, new_desc_blk; - char *actual_buf, *bitmap_buf; - - actual_buf = (char *) e2fsck_allocate_memory(ctx, fs->blocksize, -@@ -502,8 +617,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; -diff --git a/e2fsck/problem.c b/e2fsck/problem.c -index f442a33..f761ec9 100644 ---- a/e2fsck/problem.c -+++ b/e2fsck/problem.c -@@ -99,6 +99,9 @@ static const char *preen_msg[] = { - "", /* 20 */ - }; - -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wmissing-field-initializers" -+ - static struct e2fsck_problem problem_table[] = { - - /* Pre-Pass 1 errors */ -@@ -126,7 +129,7 @@ static struct e2fsck_problem problem_table[] = { - " e2fsck -b 8193 <@v>\n" - " or\n" - " e2fsck -b 32768 <@v>\n\n"), -- PROMPT_NONE, PR_FATAL }, -+ PROMPT_NONE, 0 }, - - /* Filesystem size is wrong */ - { PR_0_FS_SIZE_WRONG, -@@ -435,6 +438,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. "), -@@ -445,6 +462,11 @@ static struct e2fsck_problem problem_table[] = { - N_("First_meta_bg is too big. (%N, max value %g). "), - PROMPT_CLEAR, 0 }, - -+ /* External journal has corrupt superblock */ -+ { PR_0_EXT_JOURNAL_SUPER_CSUM_INVALID, -+ N_("External @j @S checksum does not match @S. "), -+ PROMPT_FIX, PR_PREEN_OK }, -+ - /* Pass 1 errors */ - - /* Pass 1: Checking inodes, blocks, and sizes */ -@@ -692,11 +714,6 @@ static struct e2fsck_problem problem_table[] = { - "or append-only flag set. "), - PROMPT_CLEAR, PR_PREEN_OK | PR_PREEN_NO | PR_NO_OK }, - -- /* Compression flag set on an inode when filesystem doesn't support it */ -- { PR_1_COMPR_SET, -- N_("@i %i has @cion flag set on @f without @cion support. "), -- PROMPT_CLEAR, 0 }, -- - /* Non-zero size for device, fifo or socket inode */ - { PR_1_SET_NONZSIZE, - N_("Special (@v/socket/fifo) @i %i has non-zero size. "), -@@ -765,7 +782,7 @@ static struct e2fsck_problem problem_table[] = { - - /* Error allocating EA region allocation structure */ - { PR_1_EA_ALLOC_REGION_ABORT, -- N_("@A @a @b %b. "), -+ N_("@A @a region allocation structure. "), - PROMPT_NONE, PR_FATAL}, - - /* Error EA allocation collision */ -@@ -958,6 +975,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, 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 +1020,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 should be at block */ - { PR_1_COLLAPSE_DBLOCK, -@@ -987,6 +1053,67 @@ 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 }, -+ -+ /* Bad block list says the bad block list inode is bad */ -+ { PR_1_BADBLOCKS_IN_BADBLOCKS, -+ N_("Bad block list says the bad block list @i is bad. "), -+ PROMPT_CLEAR_INODE, 0 }, -+ -+ /* Error allocating extent region allocation structure */ -+ { PR_1_EXTENT_ALLOC_REGION_ABORT, -+ N_("@A @x region allocation structure. "), -+ PROMPT_NONE, PR_FATAL}, -+ -+ /* Inode has a duplicate extent mapping */ -+ { PR_1_EXTENT_COLLISION, -+ N_("@i %i has a duplicate @x mapping\n\t(logical @b %c, @n physical @b %b, len %N)\n"), -+ PROMPT_CLEAR, 0 }, -+ -+ /* Error allocating memory for encrypted directory list */ -+ { PR_1_ALLOCATE_ENCRYPTED_DIRLIST, -+ N_("@A memory for encrypted @d list\n"), -+ PROMPT_NONE, PR_FATAL }, -+ -+ /* Inode extent tree could be more shallow */ -+ { PR_1_EXTENT_BAD_MAX_DEPTH, -+ N_("@i %i @x tree could be more shallow (%b; could be <= %c)\n"), -+ PROMPT_FIX, PR_NO_OK | PR_PREEN_NO | PR_PREEN_OK }, -+ -+ /* Inode extent tree could be more shallow */ -+ { PR_1_NO_BIGALLOC_BLOCKMAP_FILES, -+ N_("@i %i on bigalloc @f cannot be @b mapped. "), -+ PROMPT_FIX, 0 }, -+ - /* Pass 1b errors */ - - /* Pass 1B: Rescan for duplicate/bad blocks */ -@@ -1030,6 +1157,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"), -@@ -1079,6 +1211,48 @@ static struct e2fsck_problem problem_table[] = { - { PR_1D_CLONE_ERROR, - N_("Couldn't clone file: %m\n"), PROMPT_NONE, 0 }, - -+ /* Pass 1E Extent tree optimization */ -+ -+ /* Pass 1E: Optimizing extent trees */ -+ { PR_1E_PASS_HEADER, -+ N_("Pass 1E: Optimizing @x trees\n"), -+ PROMPT_NONE, PR_PREEN_NOMSG }, -+ -+ /* Failed to optimize extent tree */ -+ { PR_1E_OPTIMIZE_EXT_ERR, -+ N_("Failed to optimize @x tree %p (%i): %m\n"), -+ PROMPT_NONE, 0 }, -+ -+ /* Optimizing extent trees */ -+ { PR_1E_OPTIMIZE_EXT_HEADER, -+ N_("Optimizing @x trees: "), -+ PROMPT_NONE, PR_MSG_ONLY }, -+ -+ /* Rebuilding extent tree %d */ -+ { PR_1E_OPTIMIZE_EXT, -+ " %i", -+ PROMPT_NONE, PR_LATCH_OPTIMIZE_EXT | PR_PREEN_NOHDR}, -+ -+ /* Rebuilding extent tree end */ -+ { PR_1E_OPTIMIZE_EXT_END, -+ "\n", -+ PROMPT_NONE, PR_PREEN_NOHDR }, -+ -+ /* Internal error: extent tree depth too large */ -+ { PR_1E_MAX_EXTENT_TREE_DEPTH, -+ N_("Internal error: max extent tree depth too large (%b; expected=%c).\n"), -+ PROMPT_NONE, PR_FATAL }, -+ -+ /* Inode extent tree could be shorter */ -+ { PR_1E_CAN_COLLAPSE_EXTENT_TREE, -+ N_("@i %i @x tree (at level %b) could be shorter. "), -+ PROMPT_FIX, PR_NO_OK | PR_PREEN_NO | PR_PREEN_OK }, -+ -+ /* Inode extent tree could be narrower */ -+ { PR_1E_CAN_NARROW_EXTENT_TREE, -+ N_("@i %i @x tree (at (level %b) could be narrower. "), -+ PROMPT_FIX, PR_NO_OK | PR_PREEN_NO | PR_PREEN_OK }, -+ - /* Pass 2 errors */ - - /* Pass 2: Checking directory structure */ -@@ -1409,6 +1583,41 @@ 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: @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 }, -+ -+ /* Encrypted directory entry is too short */ -+ { PR_2_BAD_ENCRYPTED_NAME, -+ N_("Encrypted @E is too short.\n"), -+ PROMPT_CLEAR, 0 }, -+ - /* Pass 3 errors */ - - /* Pass 3: Checking directory connectivity */ -@@ -1531,6 +1740,26 @@ 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 }, -+ -+ /* Lost+found is encrypted */ -+ { PR_3_LPF_ENCRYPTED, -+ N_("/@l is encrypted\n"), -+ PROMPT_CLEAR, 0 }, -+ - /* Pass 3A Directory Optimization */ - - /* Pass 3A: Optimizing directories */ -@@ -1725,6 +1954,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 */ -@@ -1772,8 +2011,10 @@ static struct latch_descr pr_latch_info[] = { - { PR_LATCH_TOOBIG, PR_1_INODE_TOOBIG, 0 }, - { PR_LATCH_OPTIMIZE_DIR, PR_3A_OPTIMIZE_DIR_HEADER, PR_3A_OPTIMIZE_DIR_END }, - { PR_LATCH_BG_CHECKSUM, PR_0_GDT_CSUM_LATCH, 0 }, -+ { PR_LATCH_OPTIMIZE_EXT, PR_1E_OPTIMIZE_EXT_HEADER, PR_1E_OPTIMIZE_EXT_END }, - { -1, 0, 0 }, - }; -+#pragma GCC diagnostic pop - - static struct e2fsck_problem *find_problem(problem_t code) - { -diff --git a/e2fsck/problem.h b/e2fsck/problem.h -index 212ed35..2ff0f5e 100644 ---- a/e2fsck/problem.h -+++ b/e2fsck/problem.h -@@ -40,6 +40,7 @@ struct problem_context { - #define PR_LATCH_TOOBIG 0x0080 /* Latch for file to big errors */ - #define PR_LATCH_OPTIMIZE_DIR 0x0090 /* Latch for optimize directories */ - #define PR_LATCH_BG_CHECKSUM 0x00A0 /* Latch for block group checksums */ -+#define PR_LATCH_OPTIMIZE_EXT 0x00B0 /* Latch for rebuild extents */ - - #define PR_LATCH(x) ((((x) & PR_LATCH_MASK) >> 4) - 1) - -@@ -249,12 +250,24 @@ 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 - - /* The first_meta_bg is too big */ - #define PR_0_FIRST_META_BG_TOO_BIG 0x000049 - -+/* External journal has corrupt superblock */ -+#define PR_0_EXT_JOURNAL_SUPER_CSUM_INVALID 0x00004A -+ - /* - * Pass 1 errors - */ -@@ -403,8 +416,8 @@ struct problem_context { - /* Immutable flag set on a device or socket inode */ - #define PR_1_SET_IMMUTABLE 0x010030 - --/* Compression flag set on a non-compressed filesystem */ --#define PR_1_COMPR_SET 0x010031 -+/* Compression flag set on a non-compressed filesystem -- no longer used*/ -+/* #define PR_1_COMPR_SET 0x010031 */ - - /* Non-zero size on on device, fifo or socket inode */ - #define PR_1_SET_NONZSIZE 0x010032 -@@ -564,6 +577,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 +615,42 @@ 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 -+ -+/* badblocks is in badblocks */ -+#define PR_1_BADBLOCKS_IN_BADBLOCKS 0x01007B -+ -+/* can't allocate extent region */ -+#define PR_1_EXTENT_ALLOC_REGION_ABORT 0x01007C -+ -+/* leaf extent collision */ -+#define PR_1_EXTENT_COLLISION 0x01007D -+ -+/* Error allocating memory for encrypted directory list */ -+#define PR_1_ALLOCATE_ENCRYPTED_DIRLIST 0x01007E -+ -+/* extent tree max depth too big */ -+#define PR_1_EXTENT_BAD_MAX_DEPTH 0x01007F -+ -+/* bigalloc fs cannot have blockmap files */ -+#define PR_1_NO_BIGALLOC_BLOCKMAP_FILES 0x010080 -+ - /* - * Pass 1b errors - */ -@@ -615,6 +679,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 - -@@ -647,6 +714,33 @@ struct problem_context { - #define PR_1D_CLONE_ERROR 0x013008 - - /* -+ * Pass 1e --- rebuilding extent trees -+ */ -+/* Pass 1e: Rebuilding extent trees */ -+#define PR_1E_PASS_HEADER 0x014000 -+ -+/* Error rehash directory */ -+#define PR_1E_OPTIMIZE_EXT_ERR 0x014001 -+ -+/* Rebuilding extent trees */ -+#define PR_1E_OPTIMIZE_EXT_HEADER 0x014002 -+ -+/* Rebuilding extent %d */ -+#define PR_1E_OPTIMIZE_EXT 0x014003 -+ -+/* Rebuilding extent tree end */ -+#define PR_1E_OPTIMIZE_EXT_END 0x014004 -+ -+/* Internal error: extent tree depth too large */ -+#define PR_1E_MAX_EXTENT_TREE_DEPTH 0x014005 -+ -+/* Inode extent tree could be shorter */ -+#define PR_1E_CAN_COLLAPSE_EXTENT_TREE 0x014006 -+ -+/* Inode extent tree could be narrower */ -+#define PR_1E_CAN_NARROW_EXTENT_TREE 0x014007 -+ -+/* - * Pass 2 errors - */ - -@@ -851,6 +945,27 @@ 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 -+ -+/* Encrypted directory entry is too short */ -+#define PR_2_BAD_ENCRYPTED_NAME 0x020050 -+ - /* - * Pass 3 errors - */ -@@ -927,6 +1042,18 @@ 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 -+ -+/* Lost+found is encrypted */ -+#define PR_3_LPF_ENCRYPTED 0x03001B -+ - /* - * Pass 3a --- rehashing diretories - */ -@@ -948,6 +1075,8 @@ struct problem_context { - /* Rehashing dir end */ - #define PR_3A_OPTIMIZE_DIR_END 0x031005 - -+/* Pass 3B is really just 1E */ -+ - /* - * Pass 4 errors - */ -@@ -1049,6 +1178,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 - */ -diff --git a/e2fsck/prof_err.et b/e2fsck/prof_err.et -deleted file mode 100644 -index c9316c7..0000000 ---- a/e2fsck/prof_err.et -+++ /dev/null -@@ -1,66 +0,0 @@ --error_table prof -- --error_code PROF_VERSION, "Profile version 0.0" -- --# --# generated by prof_tree.c --# --error_code PROF_MAGIC_NODE, "Bad magic value in profile_node" --error_code PROF_NO_SECTION, "Profile section not found" --error_code PROF_NO_RELATION, "Profile relation not found" --error_code PROF_ADD_NOT_SECTION, -- "Attempt to add a relation to node which is not a section" --error_code PROF_SECTION_WITH_VALUE, -- "A profile section header has a non-zero value" --error_code PROF_BAD_LINK_LIST, "Bad linked list in profile structures" --error_code PROF_BAD_GROUP_LVL, "Bad group level in profile structures" --error_code PROF_BAD_PARENT_PTR, -- "Bad parent pointer in profile structures" --error_code PROF_MAGIC_ITERATOR, "Bad magic value in profile iterator" --error_code PROF_SET_SECTION_VALUE, "Can't set value on section node" --error_code PROF_EINVAL, "Invalid argument passed to profile library" --error_code PROF_READ_ONLY, "Attempt to modify read-only profile" -- --# --# generated by prof_parse.c --# -- --error_code PROF_SECTION_NOTOP, "Profile section header not at top level" --error_code PROF_SECTION_SYNTAX, "Syntax error in profile section header" --error_code PROF_RELATION_SYNTAX, "Syntax error in profile relation" --error_code PROF_EXTRA_CBRACE, "Extra closing brace in profile" --error_code PROF_MISSING_OBRACE, "Missing open brace in profile" -- --# --# generated by prof_init.c --# --error_code PROF_MAGIC_PROFILE, "Bad magic value in profile_t" --error_code PROF_MAGIC_SECTION, "Bad magic value in profile_section_t" --error_code PROF_TOPSECTION_ITER_NOSUPP, -- "Iteration through all top level section not supported" --error_code PROF_INVALID_SECTION, "Invalid profile_section object" --error_code PROF_END_OF_SECTIONS, "No more sections" --error_code PROF_BAD_NAMESET, "Bad nameset passed to query routine" --error_code PROF_NO_PROFILE, "No profile file open" -- --# --# generated by prof_file.c --# --error_code PROF_MAGIC_FILE, "Bad magic value in profile_file_t" --error_code PROF_FAIL_OPEN, "Couldn't open profile file" -- --# --# generated by prof_set.c --# --error_code PROF_EXISTS, "Section already exists" -- --# --# generated by prof_get.c --# --error_code PROF_BAD_BOOLEAN, "Invalid boolean value" --error_code PROF_BAD_INTEGER, "Invalid integer value" -- --error_code PROF_MAGIC_FILE_DATA, "Bad magic value in profile_file_data_t" -- -- --end -diff --git a/e2fsck/profile.c b/e2fsck/profile.c -deleted file mode 100644 -index c4528c8..0000000 ---- a/e2fsck/profile.c -+++ /dev/null -@@ -1,1905 +0,0 @@ --/* -- * profile.c -- A simple configuration file parsing "library in a file" -- * -- * The profile library was originally written by Theodore Ts'o in 1995 -- * for use in the MIT Kerberos v5 library. It has been -- * modified/enhanced/bug-fixed over time by other members of the MIT -- * Kerberos team. This version was originally taken from the Kerberos -- * v5 distribution, version 1.4.2, and radically simplified for use in -- * e2fsprogs. (Support for locking for multi-threaded operations, -- * being able to modify and update the configuration file -- * programmatically, and Mac/Windows portability have been removed. -- * It has been folded into a single C source file to make it easier to -- * fold into an application program.) -- * -- * Copyright (C) 2005, 2006 by Theodore Ts'o. -- * -- * %Begin-Header% -- * This file may be redistributed under the terms of the GNU Public -- * License. -- * %End-Header% -- * -- * Copyright (C) 1985-2005 by the Massachusetts Institute of Technology. -- * -- * All rights reserved. -- * -- * Export of this software from the United States of America may require -- * a specific license from the United States Government. It is the -- * responsibility of any person or organization contemplating export to -- * obtain such a license before exporting. -- * -- * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and -- * distribute this software and its documentation for any purpose and -- * without fee is hereby granted, provided that the above copyright -- * notice appear in all copies and that both that copyright notice and -- * this permission notice appear in supporting documentation, and that -- * the name of M.I.T. not be used in advertising or publicity pertaining -- * to distribution of the software without specific, written prior -- * permission. Furthermore if you modify this software you must label -- * your software as modified software and not distribute it in such a -- * fashion that it might be confused with the original MIT software. -- * M.I.T. makes no representations about the suitability of this software -- * for any purpose. It is provided "as is" without express or implied -- * warranty. -- * -- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR -- * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED -- * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. -- * -- */ -- --#include "config.h" --#ifdef HAVE_UNISTD_H --#include --#endif --#include --#ifdef HAVE_STDLIB_H --#include --#endif --#include --#include --#include --#include --#include --#include --#include --#include --#include --#ifdef HAVE_PWD_H --#include --#endif -- --#include --#include "profile.h" --#include "prof_err.h" -- --#undef STAT_ONCE_PER_SECOND --#undef HAVE_STAT -- --/* -- * prof_int.h -- */ -- --typedef long prf_magic_t; -- --/* -- * This is the structure which stores the profile information for a -- * particular configuration file. -- */ --struct _prf_file_t { -- prf_magic_t magic; -- char *filespec; --#ifdef STAT_ONCE_PER_SECOND -- time_t last_stat; --#endif -- time_t timestamp; /* time tree was last updated from file */ -- int flags; /* r/w, dirty */ -- int upd_serial; /* incremented when data changes */ -- struct profile_node *root; -- struct _prf_file_t *next; --}; -- --typedef struct _prf_file_t *prf_file_t; -- --/* -- * The profile flags -- */ --#define PROFILE_FILE_RW 0x0001 --#define PROFILE_FILE_DIRTY 0x0002 --#define PROFILE_FILE_NO_RELOAD 0x0004 -- --/* -- * This structure defines the high-level, user visible profile_t -- * object, which is used as a handle by users who need to query some -- * configuration file(s) -- */ --struct _profile_t { -- prf_magic_t magic; -- prf_file_t first_file; --}; -- --/* -- * Used by the profile iterator in prof_get.c -- */ --#define PROFILE_ITER_LIST_SECTION 0x0001 --#define PROFILE_ITER_SECTIONS_ONLY 0x0002 --#define PROFILE_ITER_RELATIONS_ONLY 0x0004 -- --#define PROFILE_ITER_FINAL_SEEN 0x0100 -- --/* -- * Check if a filespec is last in a list (NULL on UNIX, invalid FSSpec on MacOS -- */ -- --#define PROFILE_LAST_FILESPEC(x) (((x) == NULL) || ((x)[0] == '\0')) -- --struct profile_node { -- errcode_t magic; -- char *name; -- char *value; -- int group_level; -- unsigned int final:1; /* Indicate don't search next file */ -- unsigned int deleted:1; -- struct profile_node *first_child; -- struct profile_node *parent; -- struct profile_node *next, *prev; --}; -- --#define CHECK_MAGIC(node) \ -- if ((node)->magic != PROF_MAGIC_NODE) \ -- return PROF_MAGIC_NODE; -- --/* profile parser declarations */ --struct parse_state { -- int state; -- int group_level; -- int line_num; -- struct profile_node *root_section; -- struct profile_node *current_section; --}; -- --static const char *default_filename = ""; -- --static profile_syntax_err_cb_t syntax_err_cb; -- --static errcode_t parse_line(char *line, struct parse_state *state); -- --#ifdef DEBUG_PROGRAM --static errcode_t profile_write_tree_file -- (struct profile_node *root, FILE *dstfile); -- --static errcode_t profile_write_tree_to_buffer -- (struct profile_node *root, char **buf); --#endif -- -- --static void profile_free_node -- (struct profile_node *relation); -- --static errcode_t profile_create_node -- (const char *name, const char *value, -- struct profile_node **ret_node); -- --#ifdef DEBUG_PROGRAM --static errcode_t profile_verify_node -- (struct profile_node *node); --#endif -- --static errcode_t profile_add_node -- (struct profile_node *section, -- const char *name, const char *value, -- struct profile_node **ret_node); -- --static errcode_t profile_find_node -- (struct profile_node *section, -- const char *name, const char *value, -- int section_flag, void **state, -- struct profile_node **node); -- --static errcode_t profile_node_iterator -- (void **iter_p, struct profile_node **ret_node, -- char **ret_name, char **ret_value); -- --static errcode_t profile_open_file -- (const char * file, prf_file_t *ret_prof); -- --static errcode_t profile_update_file -- (prf_file_t prf); -- --static void profile_free_file -- (prf_file_t profile); -- --static errcode_t profile_get_value(profile_t profile, const char *name, -- const char *subname, const char *subsubname, -- const char **ret_value); -- -- --/* -- * prof_init.c --- routines that manipulate the user-visible profile_t -- * object. -- */ -- --static int compstr(const void *m1, const void *m2) --{ -- const char *s1 = *((const char * const *) m1); -- const char *s2 = *((const char * const *) m2); -- -- return strcmp(s1, s2); --} -- --static void free_list(char **list) --{ -- char **cp; -- -- if (list == 0) -- return; -- -- for (cp = list; *cp; cp++) -- free(*cp); -- free(list); --} -- --static errcode_t get_dirlist(const char *dirname, char***ret_array) --{ -- DIR *dir; -- struct dirent *de; -- struct stat st; -- errcode_t retval; -- char *fn, *cp; -- char **array = 0, **new_array; -- int max = 0, num = 0; -- -- dir = opendir(dirname); -- if (!dir) -- return errno; -- -- while ((de = readdir(dir)) != NULL) { -- for (cp = de->d_name; *cp; cp++) { -- if (!isalnum(*cp) && -- (*cp != '-') && -- (*cp != '_')) -- break; -- } -- if (*cp) -- continue; -- fn = malloc(strlen(dirname) + strlen(de->d_name) + 2); -- if (!fn) { -- retval = ENOMEM; -- goto errout; -- } -- sprintf(fn, "%s/%s", dirname, de->d_name); -- if ((stat(fn, &st) < 0) || !S_ISREG(st.st_mode)) { -- free(fn); -- continue; -- } -- if (num >= max) { -- max += 10; -- new_array = realloc(array, sizeof(char *) * (max+1)); -- if (!new_array) { -- retval = ENOMEM; -- free(fn); -- goto errout; -- } -- array = new_array; -- } -- array[num++] = fn; -- } -- if (array) { -- qsort(array, num, sizeof(char *), compstr); -- array[num++] = 0; -- } -- *ret_array = array; -- closedir(dir); -- return 0; --errout: -- if (array) -- array[num] = 0; -- closedir(dir); -- free_list(array); -- return retval; --} -- --errcode_t --profile_init(const char **files, profile_t *ret_profile) --{ -- const char **fs; -- profile_t profile; -- prf_file_t new_file, *last; -- errcode_t retval = 0; -- char **cpp, *cp, **array = 0; -- -- profile = malloc(sizeof(struct _profile_t)); -- if (!profile) -- return ENOMEM; -- memset(profile, 0, sizeof(struct _profile_t)); -- profile->magic = PROF_MAGIC_PROFILE; -- last = &profile->first_file; -- -- /* if the filenames list is not specified return an empty profile */ -- if ( files ) { -- for (fs = files; !PROFILE_LAST_FILESPEC(*fs); fs++) { -- if (array) -- free_list(array); -- array = NULL; -- retval = get_dirlist(*fs, &array); -- if (retval == 0) { -- if (!array) -- continue; -- for (cpp = array; (cp = *cpp); cpp++) { -- retval = profile_open_file(cp, &new_file); -- if (retval == EACCES) -- continue; -- if (retval) -- goto errout; -- *last = new_file; -- last = &new_file->next; -- } -- } else if ((retval != ENOTDIR) && -- strcmp(*fs, default_filename)) -- goto errout; -- -- retval = profile_open_file(*fs, &new_file); -- /* if this file is missing, skip to the next */ -- if (retval == ENOENT || retval == EACCES) { -- continue; -- } -- if (retval) -- goto errout; -- *last = new_file; -- last = &new_file->next; -- } -- /* -- * If all the files were not found, return the appropriate error. -- */ -- if (!profile->first_file) { -- retval = ENOENT; -- goto errout; -- } -- } -- -- free_list(array); -- *ret_profile = profile; -- return 0; --errout: -- free_list(array); -- profile_release(profile); -- return retval; --} -- --void --profile_release(profile_t profile) --{ -- prf_file_t p, next; -- -- if (!profile || profile->magic != PROF_MAGIC_PROFILE) -- return; -- -- for (p = profile->first_file; p; p = next) { -- next = p->next; -- profile_free_file(p); -- } -- profile->magic = 0; -- free(profile); --} -- --/* -- * This function sets the value of the pseudo file "". If -- * the file "" had previously been passed to profile_init(), -- * then def_string parameter will be parsed and used as the profile -- * information for the "" file. -- */ --errcode_t profile_set_default(profile_t profile, const char *def_string) --{ -- struct parse_state state; -- prf_file_t prf; -- errcode_t retval; -- const char *in; -- char *line, *p, *end; -- int line_size, len; -- -- if (!def_string || !profile || profile->magic != PROF_MAGIC_PROFILE) -- return PROF_MAGIC_PROFILE; -- -- for (prf = profile->first_file; prf; prf = prf->next) { -- if (strcmp(prf->filespec, default_filename) == 0) -- break; -- } -- if (!prf) -- return 0; -- -- if (prf->root) { -- profile_free_node(prf->root); -- prf->root = 0; -- } -- -- memset(&state, 0, sizeof(struct parse_state)); -- retval = profile_create_node("(root)", 0, &state.root_section); -- if (retval) -- return retval; -- -- line = 0; -- line_size = 0; -- in = def_string; -- while (*in) { -- end = strchr(in, '\n'); -- len = end ? (end - in) : (int) strlen(in); -- if (len >= line_size) { -- line_size = len+1; -- p = realloc(line, line_size); -- if (!p) { -- retval = ENOMEM; -- goto errout; -- } -- line = p; -- } -- memcpy(line, in, len); -- line[len] = 0; -- retval = parse_line(line, &state); -- if (retval) { -- errout: -- if (syntax_err_cb) -- (syntax_err_cb)(prf->filespec, retval, -- state.line_num); -- free(line); -- if (prf->root) -- profile_free_node(prf->root); -- return retval; -- } -- if (!end) -- break; -- in = end+1; -- } -- prf->root = state.root_section; -- free(line); -- -- return 0; --} -- --/* -- * prof_file.c ---- routines that manipulate an individual profile file. -- */ -- --errcode_t profile_open_file(const char * filespec, -- prf_file_t *ret_prof) --{ -- prf_file_t prf; -- errcode_t retval; -- char *home_env = 0; -- unsigned int len; -- char *expanded_filename; -- -- prf = malloc(sizeof(struct _prf_file_t)); -- if (!prf) -- return ENOMEM; -- memset(prf, 0, sizeof(struct _prf_file_t)); -- prf->magic = PROF_MAGIC_FILE; -- -- len = strlen(filespec)+1; -- if (filespec[0] == '~' && filespec[1] == '/') { -- home_env = getenv("HOME"); --#ifdef HAVE_PWD_H -- if (home_env == NULL) { --#ifdef HAVE_GETWUID_R -- struct passwd *pw, pwx; -- uid_t uid; -- char pwbuf[BUFSIZ]; -- -- uid = getuid(); -- if (!getpwuid_r(uid, &pwx, pwbuf, sizeof(pwbuf), &pw) -- && pw != NULL && pw->pw_dir[0] != 0) -- home_env = pw->pw_dir; --#else -- struct passwd *pw; -- -- pw = getpwuid(getuid()); -- home_env = pw->pw_dir; --#endif -- } --#endif -- if (home_env) -- len += strlen(home_env); -- } -- expanded_filename = malloc(len); -- if (expanded_filename == 0) { -- profile_free_file(prf); -- return errno; -- } -- if (home_env) { -- strcpy(expanded_filename, home_env); -- strcat(expanded_filename, filespec+1); -- } else -- memcpy(expanded_filename, filespec, len); -- -- prf->filespec = expanded_filename; -- -- if (strcmp(prf->filespec, default_filename) != 0) { -- retval = profile_update_file(prf); -- if (retval) { -- profile_free_file(prf); -- return retval; -- } -- } -- -- *ret_prof = prf; -- return 0; --} -- --errcode_t profile_update_file(prf_file_t prf) --{ -- errcode_t retval; --#ifdef HAVE_STAT -- struct stat st; --#ifdef STAT_ONCE_PER_SECOND -- time_t now; --#endif --#endif -- FILE *f; -- char buf[2048]; -- struct parse_state state; -- -- if (prf->flags & PROFILE_FILE_NO_RELOAD) -- return 0; -- --#ifdef HAVE_STAT --#ifdef STAT_ONCE_PER_SECOND -- now = time(0); -- if (now == prf->last_stat && prf->root != NULL) { -- return 0; -- } --#endif -- if (stat(prf->filespec, &st)) { -- retval = errno; -- return retval; -- } --#ifdef STAT_ONCE_PER_SECOND -- prf->last_stat = now; --#endif -- if (st.st_mtime == prf->timestamp && prf->root != NULL) { -- return 0; -- } -- if (prf->root) { -- profile_free_node(prf->root); -- prf->root = 0; -- } --#else -- /* -- * If we don't have the stat() call, assume that our in-core -- * memory image is correct. That is, we won't reread the -- * profile file if it changes. -- */ -- if (prf->root) { -- return 0; -- } --#endif -- memset(&state, 0, sizeof(struct parse_state)); -- retval = profile_create_node("(root)", 0, &state.root_section); -- if (retval) -- return retval; -- errno = 0; -- f = fopen(prf->filespec, "r"); -- if (f == NULL) { -- retval = errno; -- if (retval == 0) -- retval = ENOENT; -- return retval; -- } -- prf->upd_serial++; -- while (!feof(f)) { -- if (fgets(buf, sizeof(buf), f) == NULL) -- break; -- retval = parse_line(buf, &state); -- if (retval) { -- if (syntax_err_cb) -- (syntax_err_cb)(prf->filespec, retval, -- state.line_num); -- fclose(f); -- return retval; -- } -- } -- prf->root = state.root_section; -- -- fclose(f); -- --#ifdef HAVE_STAT -- prf->timestamp = st.st_mtime; --#endif -- return 0; --} -- --void profile_free_file(prf_file_t prf) --{ -- if (prf->root) -- profile_free_node(prf->root); -- free(prf->filespec); -- free(prf); --} -- --/* Begin the profile parser */ -- --profile_syntax_err_cb_t profile_set_syntax_err_cb(profile_syntax_err_cb_t hook) --{ -- profile_syntax_err_cb_t old; -- -- old = syntax_err_cb; -- syntax_err_cb = hook; -- return(old); --} -- --#define STATE_INIT_COMMENT 0 --#define STATE_STD_LINE 1 --#define STATE_GET_OBRACE 2 -- --static char *skip_over_blanks(char *cp) --{ -- while (*cp && isspace((int) (*cp))) -- cp++; -- return cp; --} -- --static int end_or_comment(char ch) --{ -- return (ch == 0 || ch == '#' || ch == ';'); --} -- --static char *skip_over_nonblanks(char *cp) --{ -- while (!end_or_comment(*cp) && !isspace(*cp)) -- cp++; -- return cp; --} -- --static void strip_line(char *line) --{ -- char *p = line + strlen(line); -- while (p > line && (p[-1] == '\n' || p[-1] == '\r')) -- *p-- = 0; --} -- --static void parse_quoted_string(char *str) --{ -- char *to, *from; -- -- to = from = str; -- -- for (to = from = str; *from && *from != '"'; to++, from++) { -- if (*from == '\\') { -- from++; -- switch (*from) { -- case 'n': -- *to = '\n'; -- break; -- case 't': -- *to = '\t'; -- break; -- case 'b': -- *to = '\b'; -- break; -- default: -- *to = *from; -- } -- continue; -- } -- *to = *from; -- } -- *to = '\0'; --} -- --static errcode_t parse_line(char *line, struct parse_state *state) --{ -- char *cp, ch, *tag, *value; -- char *p; -- errcode_t retval; -- struct profile_node *node; -- int do_subsection = 0; -- void *iter = 0; -- -- state->line_num++; -- if (state->state == STATE_GET_OBRACE) { -- cp = skip_over_blanks(line); -- if (*cp != '{') -- return PROF_MISSING_OBRACE; -- state->state = STATE_STD_LINE; -- return 0; -- } -- if (state->state == STATE_INIT_COMMENT) { -- if (line[0] != '[') -- return 0; -- state->state = STATE_STD_LINE; -- } -- -- if (*line == 0) -- return 0; -- strip_line(line); -- cp = skip_over_blanks(line); -- ch = *cp; -- if (end_or_comment(ch)) -- return 0; -- if (ch == '[') { -- if (state->group_level > 0) -- return PROF_SECTION_NOTOP; -- cp++; -- cp = skip_over_blanks(cp); -- p = strchr(cp, ']'); -- if (p == NULL) -- return PROF_SECTION_SYNTAX; -- if (*cp == '"') { -- cp++; -- parse_quoted_string(cp); -- } else { -- *p-- = '\0'; -- while (isspace(*p) && (p > cp)) -- *p-- = '\0'; -- if (*cp == 0) -- return PROF_SECTION_SYNTAX; -- } -- retval = profile_find_node(state->root_section, cp, 0, 1, -- &iter, &state->current_section); -- if (retval == PROF_NO_SECTION) { -- retval = profile_add_node(state->root_section, -- cp, 0, -- &state->current_section); -- if (retval) -- return retval; -- } else if (retval) -- return retval; -- -- /* -- * Finish off the rest of the line. -- */ -- cp = p+1; -- if (*cp == '*') { -- state->current_section->final = 1; -- cp++; -- } -- /* -- * Spaces or comments after ']' should not be fatal -- */ -- cp = skip_over_blanks(cp); -- if (!end_or_comment(*cp)) -- return PROF_SECTION_SYNTAX; -- return 0; -- } -- if (ch == '}') { -- if (state->group_level == 0) -- return PROF_EXTRA_CBRACE; -- if (*(cp+1) == '*') -- state->current_section->final = 1; -- state->current_section = state->current_section->parent; -- state->group_level--; -- return 0; -- } -- /* -- * Parse the relations -- */ -- tag = cp; -- cp = strchr(cp, '='); -- if (!cp) -- return PROF_RELATION_SYNTAX; -- if (cp == tag) -- return PROF_RELATION_SYNTAX; -- *cp = '\0'; -- if (*tag == '"') { -- tag++; -- parse_quoted_string(tag); -- } else { -- /* Look for whitespace on left-hand side. */ -- p = skip_over_nonblanks(tag); -- if (*p) -- *p++ = 0; -- p = skip_over_blanks(p); -- /* If we have more non-whitespace, it's an error. */ -- if (*p) -- return PROF_RELATION_SYNTAX; -- } -- -- cp = skip_over_blanks(cp+1); -- value = cp; -- ch = value[0]; -- if (ch == '"') { -- value++; -- parse_quoted_string(value); -- } else if (end_or_comment(ch)) { -- do_subsection++; -- state->state = STATE_GET_OBRACE; -- } else if (value[0] == '{') { -- cp = skip_over_blanks(value+1); -- ch = *cp; -- if (end_or_comment(ch)) -- do_subsection++; -- else -- return PROF_RELATION_SYNTAX; -- } else { -- cp = skip_over_nonblanks(value); -- p = skip_over_blanks(cp); -- ch = *p; -- *cp = 0; -- if (!end_or_comment(ch)) -- return PROF_RELATION_SYNTAX; -- } -- if (do_subsection) { -- p = strchr(tag, '*'); -- if (p) -- *p = '\0'; -- retval = profile_add_node(state->current_section, -- tag, 0, &state->current_section); -- if (retval) -- return retval; -- if (p) -- state->current_section->final = 1; -- state->group_level++; -- return 0; -- } -- p = strchr(tag, '*'); -- if (p) -- *p = '\0'; -- profile_add_node(state->current_section, tag, value, &node); -- if (p) -- node->final = 1; -- return 0; --} -- --#ifdef DEBUG_PROGRAM --/* -- * Return TRUE if the string begins or ends with whitespace -- */ --static int need_double_quotes(char *str) --{ -- if (!str || !*str) -- return 0; -- if (isspace((int) (*str)) ||isspace((int) (*(str + strlen(str) - 1)))) -- return 1; -- if (strchr(str, '\n') || strchr(str, '\t') || strchr(str, '\b') || -- strchr(str, ' ') || strchr(str, '#') || strchr(str, ';')) -- return 1; -- return 0; --} -- --/* -- * Output a string with double quotes, doing appropriate backquoting -- * of characters as necessary. -- */ --static void output_quoted_string(char *str, void (*cb)(const char *,void *), -- void *data) --{ -- char ch; -- char buf[2]; -- -- cb("\"", data); -- if (!str) { -- cb("\"", data); -- return; -- } -- buf[1] = 0; -- while ((ch = *str++)) { -- switch (ch) { -- case '\\': -- cb("\\\\", data); -- break; -- case '\n': -- cb("\\n", data); -- break; -- case '\t': -- cb("\\t", data); -- break; -- case '\b': -- cb("\\b", data); -- break; -- default: -- /* This would be a lot faster if we scanned -- forward for the next "interesting" -- character. */ -- buf[0] = ch; -- cb(buf, data); -- break; -- } -- } -- cb("\"", data); --} -- --#ifndef EOL --#define EOL "\n" --#endif -- --/* Errors should be returned, not ignored! */ --static void dump_profile(struct profile_node *root, int level, -- void (*cb)(const char *, void *), void *data) --{ -- int i; -- struct profile_node *p; -- void *iter; -- long retval; -- -- iter = 0; -- do { -- retval = profile_find_node(root, 0, 0, 0, &iter, &p); -- if (retval) -- break; -- for (i=0; i < level; i++) -- cb("\t", data); -- if (need_double_quotes(p->name)) -- output_quoted_string(p->name, cb, data); -- else -- cb(p->name, data); -- cb(" = ", data); -- if (need_double_quotes(p->value)) -- output_quoted_string(p->value, cb, data); -- else -- cb(p->value, data); -- cb(EOL, data); -- } while (iter != 0); -- -- iter = 0; -- do { -- retval = profile_find_node(root, 0, 0, 1, &iter, &p); -- if (retval) -- break; -- if (level == 0) { /* [xxx] */ -- cb("[", data); -- if (need_double_quotes(p->name)) -- output_quoted_string(p->name, cb, data); -- else -- cb(p->name, data); -- cb("]", data); -- cb(p->final ? "*" : "", data); -- cb(EOL, data); -- dump_profile(p, level+1, cb, data); -- cb(EOL, data); -- } else { /* xxx = { ... } */ -- for (i=0; i < level; i++) -- cb("\t", data); -- if (need_double_quotes(p->name)) -- output_quoted_string(p->name, cb, data); -- else -- cb(p->name, data); -- cb(" = {", data); -- cb(EOL, data); -- dump_profile(p, level+1, cb, data); -- for (i=0; i < level; i++) -- cb("\t", data); -- cb("}", data); -- cb(p->final ? "*" : "", data); -- cb(EOL, data); -- } -- } while (iter != 0); --} -- --static void dump_profile_to_file_cb(const char *str, void *data) --{ -- fputs(str, data); --} -- --errcode_t profile_write_tree_file(struct profile_node *root, FILE *dstfile) --{ -- dump_profile(root, 0, dump_profile_to_file_cb, dstfile); -- return 0; --} -- --struct prof_buf { -- char *base; -- size_t cur, max; -- int err; --}; -- --static void add_data_to_buffer(struct prof_buf *b, const void *d, size_t len) --{ -- if (b->err) -- return; -- if (b->max - b->cur < len) { -- size_t newsize; -- char *newptr; -- -- newsize = b->max + (b->max >> 1) + len + 1024; -- newptr = realloc(b->base, newsize); -- if (newptr == NULL) { -- b->err = 1; -- return; -- } -- b->base = newptr; -- b->max = newsize; -- } -- memcpy(b->base + b->cur, d, len); -- b->cur += len; /* ignore overflow */ --} -- --static void dump_profile_to_buffer_cb(const char *str, void *data) --{ -- add_data_to_buffer((struct prof_buf *)data, str, strlen(str)); --} -- --errcode_t profile_write_tree_to_buffer(struct profile_node *root, -- char **buf) --{ -- struct prof_buf prof_buf = { 0, 0, 0, 0 }; -- -- dump_profile(root, 0, dump_profile_to_buffer_cb, &prof_buf); -- if (prof_buf.err) { -- *buf = NULL; -- return ENOMEM; -- } -- add_data_to_buffer(&prof_buf, "", 1); /* append nul */ -- if (prof_buf.max - prof_buf.cur > (prof_buf.max >> 3)) { -- char *newptr = realloc(prof_buf.base, prof_buf.cur); -- if (newptr) -- prof_buf.base = newptr; -- } -- *buf = prof_buf.base; -- return 0; --} --#endif -- --/* -- * prof_tree.c --- these routines maintain the parse tree of the -- * config file. -- * -- * All of the details of how the tree is stored is abstracted away in -- * this file; all of the other profile routines build, access, and -- * modify the tree via the accessor functions found in this file. -- * -- * Each node may represent either a relation or a section header. -- * -- * A section header must have its value field set to 0, and may a one -- * or more child nodes, pointed to by first_child. -- * -- * A relation has as its value a pointer to allocated memory -- * containing a string. Its first_child pointer must be null. -- * -- */ -- --/* -- * Free a node, and any children -- */ --void profile_free_node(struct profile_node *node) --{ -- struct profile_node *child, *next; -- -- if (node->magic != PROF_MAGIC_NODE) -- return; -- -- free(node->name); -- free(node->value); -- -- for (child=node->first_child; child; child = next) { -- next = child->next; -- profile_free_node(child); -- } -- node->magic = 0; -- -- free(node); --} -- --#ifndef HAVE_STRDUP --#undef strdup --#define strdup MYstrdup --static char *MYstrdup (const char *s) --{ -- size_t sz = strlen(s) + 1; -- char *p = malloc(sz); -- if (p != 0) -- memcpy(p, s, sz); -- return p; --} --#endif -- --/* -- * Create a node -- */ --errcode_t profile_create_node(const char *name, const char *value, -- struct profile_node **ret_node) --{ -- struct profile_node *new; -- -- new = malloc(sizeof(struct profile_node)); -- if (!new) -- return ENOMEM; -- memset(new, 0, sizeof(struct profile_node)); -- new->name = strdup(name); -- if (new->name == 0) { -- profile_free_node(new); -- return ENOMEM; -- } -- if (value) { -- new->value = strdup(value); -- if (new->value == 0) { -- profile_free_node(new); -- return ENOMEM; -- } -- } -- new->magic = PROF_MAGIC_NODE; -- -- *ret_node = new; -- return 0; --} -- --/* -- * This function verifies that all of the representation invarients of -- * the profile are true. If not, we have a programming bug somewhere, -- * probably in this file. -- */ --#ifdef DEBUG_PROGRAM --errcode_t profile_verify_node(struct profile_node *node) --{ -- struct profile_node *p, *last; -- errcode_t retval; -- -- CHECK_MAGIC(node); -- -- if (node->value && node->first_child) -- return PROF_SECTION_WITH_VALUE; -- -- last = 0; -- for (p = node->first_child; p; last = p, p = p->next) { -- if (p->prev != last) -- return PROF_BAD_LINK_LIST; -- if (last && (last->next != p)) -- return PROF_BAD_LINK_LIST; -- if (node->group_level+1 != p->group_level) -- return PROF_BAD_GROUP_LVL; -- if (p->parent != node) -- return PROF_BAD_PARENT_PTR; -- retval = profile_verify_node(p); -- if (retval) -- return retval; -- } -- return 0; --} --#endif -- --/* -- * Add a node to a particular section -- */ --errcode_t profile_add_node(struct profile_node *section, const char *name, -- const char *value, struct profile_node **ret_node) --{ -- errcode_t retval; -- struct profile_node *p, *last, *new; -- -- CHECK_MAGIC(section); -- -- if (section->value) -- return PROF_ADD_NOT_SECTION; -- -- /* -- * Find the place to insert the new node. We look for the -- * place *after* the last match of the node name, since -- * order matters. -- */ -- for (p=section->first_child, last = 0; p; last = p, p = p->next) { -- int cmp; -- cmp = strcmp(p->name, name); -- if (cmp > 0) -- break; -- } -- retval = profile_create_node(name, value, &new); -- if (retval) -- return retval; -- new->group_level = section->group_level+1; -- new->deleted = 0; -- new->parent = section; -- new->prev = last; -- new->next = p; -- if (p) -- p->prev = new; -- if (last) -- last->next = new; -- else -- section->first_child = new; -- if (ret_node) -- *ret_node = new; -- return 0; --} -- --/* -- * Iterate through the section, returning the nodes which match -- * the given name. If name is NULL, then interate through all the -- * nodes in the section. If section_flag is non-zero, only return the -- * section which matches the name; don't return relations. If value -- * is non-NULL, then only return relations which match the requested -- * value. (The value argument is ignored if section_flag is non-zero.) -- * -- * The first time this routine is called, the state pointer must be -- * null. When this profile_find_node_relation() returns, if the state -- * pointer is non-NULL, then this routine should be called again. -- * (This won't happen if section_flag is non-zero, obviously.) -- * -- */ --errcode_t profile_find_node(struct profile_node *section, const char *name, -- const char *value, int section_flag, void **state, -- struct profile_node **node) --{ -- struct profile_node *p; -- -- CHECK_MAGIC(section); -- p = *state; -- if (p) { -- CHECK_MAGIC(p); -- } else -- p = section->first_child; -- -- for (; p; p = p->next) { -- if (name && (strcmp(p->name, name))) -- continue; -- if (section_flag) { -- if (p->value) -- continue; -- } else { -- if (!p->value) -- continue; -- if (value && (strcmp(p->value, value))) -- continue; -- } -- if (p->deleted) -- continue; -- /* A match! */ -- if (node) -- *node = p; -- break; -- } -- if (p == 0) { -- *state = 0; -- return section_flag ? PROF_NO_SECTION : PROF_NO_RELATION; -- } -- /* -- * OK, we've found one match; now let's try to find another -- * one. This way, if we return a non-zero state pointer, -- * there's guaranteed to be another match that's returned. -- */ -- for (p = p->next; p; p = p->next) { -- if (name && (strcmp(p->name, name))) -- continue; -- if (section_flag) { -- if (p->value) -- continue; -- } else { -- if (!p->value) -- continue; -- if (value && (strcmp(p->value, value))) -- continue; -- } -- /* A match! */ -- break; -- } -- *state = p; -- return 0; --} -- --/* -- * This is a general-purpose iterator for returning all nodes that -- * match the specified name array. -- */ --struct profile_iterator { -- prf_magic_t magic; -- profile_t profile; -- int flags; -- const char *const *names; -- const char *name; -- prf_file_t file; -- int file_serial; -- int done_idx; -- struct profile_node *node; -- int num; --}; -- --errcode_t --profile_iterator_create(profile_t profile, const char *const *names, int flags, -- void **ret_iter) --{ -- struct profile_iterator *iter; -- int done_idx = 0; -- -- if (profile == 0) -- return PROF_NO_PROFILE; -- if (profile->magic != PROF_MAGIC_PROFILE) -- return PROF_MAGIC_PROFILE; -- if (!names) -- return PROF_BAD_NAMESET; -- if (!(flags & PROFILE_ITER_LIST_SECTION)) { -- if (!names[0]) -- return PROF_BAD_NAMESET; -- done_idx = 1; -- } -- -- if ((iter = malloc(sizeof(struct profile_iterator))) == NULL) -- return ENOMEM; -- -- iter->magic = PROF_MAGIC_ITERATOR; -- iter->profile = profile; -- iter->names = names; -- iter->flags = flags; -- iter->file = profile->first_file; -- iter->done_idx = done_idx; -- iter->node = 0; -- iter->num = 0; -- *ret_iter = iter; -- return 0; --} -- --void profile_iterator_free(void **iter_p) --{ -- struct profile_iterator *iter; -- -- if (!iter_p) -- return; -- iter = *iter_p; -- if (!iter || iter->magic != PROF_MAGIC_ITERATOR) -- return; -- free(iter); -- *iter_p = 0; --} -- --/* -- * Note: the returned character strings in ret_name and ret_value -- * points to the stored character string in the parse string. Before -- * this string value is returned to a calling application -- * (profile_node_iterator is not an exported interface), it should be -- * strdup()'ed. -- */ --errcode_t profile_node_iterator(void **iter_p, struct profile_node **ret_node, -- char **ret_name, char **ret_value) --{ -- struct profile_iterator *iter = *iter_p; -- struct profile_node *section, *p; -- const char *const *cpp; -- errcode_t retval; -- int skip_num = 0; -- -- if (!iter || iter->magic != PROF_MAGIC_ITERATOR) -- return PROF_MAGIC_ITERATOR; -- if (iter->file && iter->file->magic != PROF_MAGIC_FILE) -- return PROF_MAGIC_FILE; -- /* -- * If the file has changed, then the node pointer is invalid, -- * so we'll have search the file again looking for it. -- */ -- if (iter->node && (iter->file && -- iter->file->upd_serial != iter->file_serial)) { -- iter->flags &= ~PROFILE_ITER_FINAL_SEEN; -- skip_num = iter->num; -- iter->node = 0; -- } -- if (iter->node && iter->node->magic != PROF_MAGIC_NODE) { -- return PROF_MAGIC_NODE; -- } --get_new_file: -- if (iter->node == 0) { -- if (iter->file == 0 || -- (iter->flags & PROFILE_ITER_FINAL_SEEN)) { -- profile_iterator_free(iter_p); -- if (ret_node) -- *ret_node = 0; -- if (ret_name) -- *ret_name = 0; -- if (ret_value) -- *ret_value =0; -- return 0; -- } -- if ((retval = profile_update_file(iter->file))) { -- if (retval == ENOENT || retval == EACCES) { -- /* XXX memory leak? */ -- iter->file = iter->file->next; -- skip_num = 0; -- retval = 0; -- goto get_new_file; -- } else { -- profile_iterator_free(iter_p); -- return retval; -- } -- } -- iter->file_serial = iter->file->upd_serial; -- /* -- * Find the section to list if we are a LIST_SECTION, -- * or find the containing section if not. -- */ -- section = iter->file->root; -- for (cpp = iter->names; cpp[iter->done_idx]; cpp++) { -- for (p=section->first_child; p; p = p->next) { -- if (!strcmp(p->name, *cpp) && !p->value) -- break; -- } -- if (!p) { -- section = 0; -- break; -- } -- section = p; -- if (p->final) -- iter->flags |= PROFILE_ITER_FINAL_SEEN; -- } -- if (!section) { -- iter->file = iter->file->next; -- skip_num = 0; -- goto get_new_file; -- } -- iter->name = *cpp; -- iter->node = section->first_child; -- } -- /* -- * OK, now we know iter->node is set up correctly. Let's do -- * the search. -- */ -- for (p = iter->node; p; p = p->next) { -- if (iter->name && strcmp(p->name, iter->name)) -- continue; -- if ((iter->flags & PROFILE_ITER_SECTIONS_ONLY) && -- p->value) -- continue; -- if ((iter->flags & PROFILE_ITER_RELATIONS_ONLY) && -- !p->value) -- continue; -- if (skip_num > 0) { -- skip_num--; -- continue; -- } -- if (p->deleted) -- continue; -- break; -- } -- iter->num++; -- if (!p) { -- iter->file = iter->file->next; -- iter->node = 0; -- skip_num = 0; -- goto get_new_file; -- } -- if ((iter->node = p->next) == NULL) -- iter->file = iter->file->next; -- if (ret_node) -- *ret_node = p; -- if (ret_name) -- *ret_name = p->name; -- if (ret_value) -- *ret_value = p->value; -- return 0; --} -- -- --/* -- * prof_get.c --- routines that expose the public interfaces for -- * querying items from the profile. -- * -- */ -- --/* -- * This function only gets the first value from the file; it is a -- * helper function for profile_get_string, profile_get_integer, etc. -- */ --errcode_t profile_get_value(profile_t profile, const char *name, -- const char *subname, const char *subsubname, -- const char **ret_value) --{ -- errcode_t retval; -- void *state; -- char *value; -- const char *names[4]; -- -- names[0] = name; -- names[1] = subname; -- names[2] = subsubname; -- names[3] = 0; -- -- if ((retval = profile_iterator_create(profile, names, -- PROFILE_ITER_RELATIONS_ONLY, -- &state))) -- return retval; -- -- if ((retval = profile_node_iterator(&state, 0, 0, &value))) -- goto cleanup; -- -- if (value) -- *ret_value = value; -- else -- retval = PROF_NO_RELATION; -- --cleanup: -- profile_iterator_free(&state); -- return retval; --} -- --errcode_t --profile_get_string(profile_t profile, const char *name, const char *subname, -- const char *subsubname, const char *def_val, -- char **ret_string) --{ -- const char *value; -- errcode_t retval; -- -- if (profile) { -- retval = profile_get_value(profile, name, subname, -- subsubname, &value); -- if (retval == PROF_NO_SECTION || retval == PROF_NO_RELATION) -- value = def_val; -- else if (retval) -- return retval; -- } else -- value = def_val; -- -- if (value) { -- *ret_string = malloc(strlen(value)+1); -- if (*ret_string == 0) -- return ENOMEM; -- strcpy(*ret_string, value); -- } else -- *ret_string = 0; -- return 0; --} -- --errcode_t --profile_get_integer(profile_t profile, const char *name, const char *subname, -- const char *subsubname, int def_val, int *ret_int) --{ -- const char *value; -- errcode_t retval; -- char *end_value; -- long ret_long; -- -- *ret_int = def_val; -- if (profile == 0) -- return 0; -- -- retval = profile_get_value(profile, name, subname, subsubname, &value); -- if (retval == PROF_NO_SECTION || retval == PROF_NO_RELATION) { -- *ret_int = def_val; -- return 0; -- } else if (retval) -- return retval; -- -- if (value[0] == 0) -- /* Empty string is no good. */ -- return PROF_BAD_INTEGER; -- errno = 0; -- ret_long = strtol(value, &end_value, 0); -- -- /* Overflow or underflow. */ -- if ((ret_long == LONG_MIN || ret_long == LONG_MAX) && errno != 0) -- return PROF_BAD_INTEGER; -- /* Value outside "int" range. */ -- if ((long) (int) ret_long != ret_long) -- return PROF_BAD_INTEGER; -- /* Garbage in string. */ -- if (end_value != value + strlen (value)) -- return PROF_BAD_INTEGER; -- -- -- *ret_int = ret_long; -- return 0; --} -- --errcode_t --profile_get_uint(profile_t profile, const char *name, const char *subname, -- const char *subsubname, unsigned int def_val, -- unsigned int *ret_int) --{ -- const char *value; -- errcode_t retval; -- char *end_value; -- unsigned long ret_long; -- -- *ret_int = def_val; -- if (profile == 0) -- return 0; -- -- retval = profile_get_value(profile, name, subname, subsubname, &value); -- if (retval == PROF_NO_SECTION || retval == PROF_NO_RELATION) { -- *ret_int = def_val; -- return 0; -- } else if (retval) -- return retval; -- -- if (value[0] == 0) -- /* Empty string is no good. */ -- return PROF_BAD_INTEGER; -- errno = 0; -- ret_long = strtoul(value, &end_value, 0); -- -- /* Overflow or underflow. */ -- if ((ret_long == ULONG_MAX) && errno != 0) -- return PROF_BAD_INTEGER; -- /* Value outside "int" range. */ -- if ((unsigned long) (unsigned int) ret_long != ret_long) -- return PROF_BAD_INTEGER; -- /* Garbage in string. */ -- if (end_value != value + strlen (value)) -- return PROF_BAD_INTEGER; -- -- *ret_int = ret_long; -- return 0; --} -- --errcode_t --profile_get_double(profile_t profile, const char *name, const char *subname, -- const char *subsubname, double def_val, double *ret_double) --{ -- const char *value; -- errcode_t retval; -- char *end_value; -- double double_val; -- -- *ret_double = def_val; -- if (profile == 0) -- return 0; -- -- retval = profile_get_value(profile, name, subname, subsubname, &value); -- if (retval == PROF_NO_SECTION || retval == PROF_NO_RELATION) { -- *ret_double = def_val; -- return 0; -- } else if (retval) -- return retval; -- -- if (value[0] == 0) -- /* Empty string is no good. */ -- return PROF_BAD_INTEGER; -- errno = 0; -- double_val = strtod(value, &end_value); -- -- /* Overflow or underflow. */ -- if (errno != 0) -- return PROF_BAD_INTEGER; -- /* Garbage in string. */ -- if (end_value != value + strlen(value)) -- return PROF_BAD_INTEGER; -- -- *ret_double = double_val; -- return 0; --} -- --static const char *const conf_yes[] = { -- "y", "yes", "true", "t", "1", "on", -- 0, --}; -- --static const char *const conf_no[] = { -- "n", "no", "false", "nil", "0", "off", -- 0, --}; -- --static errcode_t --profile_parse_boolean(const char *s, int *ret_boolean) --{ -- const char *const *p; -- -- if (ret_boolean == NULL) -- return PROF_EINVAL; -- -- for(p=conf_yes; *p; p++) { -- if (!strcasecmp(*p,s)) { -- *ret_boolean = 1; -- return 0; -- } -- } -- -- for(p=conf_no; *p; p++) { -- if (!strcasecmp(*p,s)) { -- *ret_boolean = 0; -- return 0; -- } -- } -- -- return PROF_BAD_BOOLEAN; --} -- --errcode_t --profile_get_boolean(profile_t profile, const char *name, const char *subname, -- const char *subsubname, int def_val, int *ret_boolean) --{ -- const char *value; -- errcode_t retval; -- -- if (profile == 0) { -- *ret_boolean = def_val; -- return 0; -- } -- -- retval = profile_get_value(profile, name, subname, subsubname, &value); -- if (retval == PROF_NO_SECTION || retval == PROF_NO_RELATION) { -- *ret_boolean = def_val; -- return 0; -- } else if (retval) -- return retval; -- -- return profile_parse_boolean (value, ret_boolean); --} -- --errcode_t --profile_iterator(void **iter_p, char **ret_name, char **ret_value) --{ -- char *name, *value; -- errcode_t retval; -- -- retval = profile_node_iterator(iter_p, 0, &name, &value); -- if (retval) -- return retval; -- -- if (ret_name) { -- if (name) { -- *ret_name = malloc(strlen(name)+1); -- if (!*ret_name) -- return ENOMEM; -- strcpy(*ret_name, name); -- } else -- *ret_name = 0; -- } -- if (ret_value) { -- if (value) { -- *ret_value = malloc(strlen(value)+1); -- if (!*ret_value) { -- if (ret_name) { -- free(*ret_name); -- *ret_name = 0; -- } -- return ENOMEM; -- } -- strcpy(*ret_value, value); -- } else -- *ret_value = 0; -- } -- return 0; --} -- --#ifdef DEBUG_PROGRAM -- --/* -- * test_profile.c --- testing program for the profile routine -- */ -- --#include "argv_parse.h" --#include "profile_helpers.h" -- --const char *program_name = "test_profile"; -- --#define PRINT_VALUE 1 --#define PRINT_VALUES 2 -- --static void do_cmd(profile_t profile, char **argv) --{ -- errcode_t retval; -- const char **names, *value; -- char **values, **cpp; -- char *cmd; -- int print_status; -- -- cmd = *(argv); -- names = (const char **) argv + 1; -- print_status = 0; -- retval = 0; -- if (cmd == 0) -- return; -- if (!strcmp(cmd, "query")) { -- retval = profile_get_values(profile, names, &values); -- print_status = PRINT_VALUES; -- } else if (!strcmp(cmd, "query1")) { -- const char *name = 0; -- const char *subname = 0; -- const char *subsubname = 0; -- -- name = names[0]; -- if (name) -- subname = names[1]; -- if (subname) -- subsubname = names[2]; -- if (subsubname && names[3]) { -- fprintf(stderr, -- "Only 3 levels are allowed with query1\n"); -- retval = EINVAL; -- } else -- retval = profile_get_value(profile, name, subname, -- subsubname, &value); -- print_status = PRINT_VALUE; -- } else if (!strcmp(cmd, "list_sections")) { -- retval = profile_get_subsection_names(profile, names, -- &values); -- print_status = PRINT_VALUES; -- } else if (!strcmp(cmd, "list_relations")) { -- retval = profile_get_relation_names(profile, names, -- &values); -- print_status = PRINT_VALUES; -- } else if (!strcmp(cmd, "dump")) { -- retval = profile_write_tree_file -- (profile->first_file->root, stdout); --#if 0 -- } else if (!strcmp(cmd, "clear")) { -- retval = profile_clear_relation(profile, names); -- } else if (!strcmp(cmd, "update")) { -- retval = profile_update_relation(profile, names+2, -- *names, *(names+1)); --#endif -- } else if (!strcmp(cmd, "verify")) { -- retval = profile_verify_node -- (profile->first_file->root); --#if 0 -- } else if (!strcmp(cmd, "rename_section")) { -- retval = profile_rename_section(profile, names+1, *names); -- } else if (!strcmp(cmd, "add")) { -- value = *names; -- if (strcmp(value, "NULL") == 0) -- value = NULL; -- retval = profile_add_relation(profile, names+1, value); -- } else if (!strcmp(cmd, "flush")) { -- retval = profile_flush(profile); --#endif -- } else { -- printf("Invalid command.\n"); -- } -- if (retval) { -- com_err(cmd, retval, ""); -- print_status = 0; -- } -- switch (print_status) { -- case PRINT_VALUE: -- printf("%s\n", value); -- break; -- case PRINT_VALUES: -- for (cpp = values; *cpp; cpp++) -- printf("%s\n", *cpp); -- profile_free_list(values); -- break; -- } --} -- --static void do_batchmode(profile_t profile) --{ -- int argc, ret; -- char **argv; -- char buf[256]; -- -- while (!feof(stdin)) { -- if (fgets(buf, sizeof(buf), stdin) == NULL) -- break; -- printf(">%s", buf); -- ret = argv_parse(buf, &argc, &argv); -- if (ret != 0) { -- printf("Argv_parse returned %d!\n", ret); -- continue; -- } -- do_cmd(profile, argv); -- printf("\n"); -- argv_free(argv); -- } -- profile_release(profile); -- exit(0); -- --} -- --void syntax_err_report(const char *filename, long err, int line_num) --{ -- fprintf(stderr, "Syntax error in %s, line number %d: %s\n", -- filename, line_num, error_message(err)); -- exit(1); --} -- --const char *default_str = "[foo]\n\tbar=quux\n\tsub = {\n\t\twin = true\n}\n"; -- --int main(int argc, char **argv) --{ -- profile_t profile; -- long retval; -- char *cmd; -- -- if (argc < 2) { -- fprintf(stderr, "Usage: %s filename [cmd argset]\n", program_name); -- exit(1); -- } -- -- initialize_prof_error_table(); -- -- profile_set_syntax_err_cb(syntax_err_report); -- -- retval = profile_init_path(argv[1], &profile); -- if (retval) { -- com_err(program_name, retval, "while initializing profile"); -- exit(1); -- } -- retval = profile_set_default(profile, default_str); -- if (retval) { -- com_err(program_name, retval, "while setting default"); -- exit(1); -- } -- -- cmd = *(argv+2); -- if (!cmd || !strcmp(cmd, "batch")) -- do_batchmode(profile); -- else -- do_cmd(profile, argv+2); -- profile_release(profile); -- -- return 0; --} -- --#endif -diff --git a/e2fsck/profile.h b/e2fsck/profile.h -deleted file mode 100644 -index 4cc10eb..0000000 ---- a/e2fsck/profile.h -+++ /dev/null -@@ -1,107 +0,0 @@ --/* -- * profile.h -- * -- * Copyright (C) 2005 by Theodore Ts'o. -- * -- * %Begin-Header% -- * This file may be redistributed under the terms of the GNU Public -- * License. -- * %End-Header% -- * -- * Copyright (C) 1985-2005 by the Massachusetts Institute of Technology. -- * -- * All rights reserved. -- * -- * Export of this software from the United States of America may require -- * a specific license from the United States Government. It is the -- * responsibility of any person or organization contemplating export to -- * obtain such a license before exporting. -- * -- * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and -- * distribute this software and its documentation for any purpose and -- * without fee is hereby granted, provided that the above copyright -- * notice appear in all copies and that both that copyright notice and -- * this permission notice appear in supporting documentation, and that -- * the name of M.I.T. not be used in advertising or publicity pertaining -- * to distribution of the software without specific, written prior -- * permission. Furthermore if you modify this software you must label -- * your software as modified software and not distribute it in such a -- * fashion that it might be confused with the original MIT software. -- * M.I.T. makes no representations about the suitability of this software -- * for any purpose. It is provided "as is" without express or implied -- * warranty. -- * -- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR -- * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED -- * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. -- */ -- --#ifndef _PROFILE_H --#define _PROFILE_H -- --typedef struct _profile_t *profile_t; -- --typedef void (*profile_syntax_err_cb_t)(const char *file, long err, -- int line_num); -- --/* -- * Used by the profile iterator in prof_get.c -- */ --#define PROFILE_ITER_LIST_SECTION 0x0001 --#define PROFILE_ITER_SECTIONS_ONLY 0x0002 --#define PROFILE_ITER_RELATIONS_ONLY 0x0004 -- --#ifdef __cplusplus --extern "C" { --#endif /* __cplusplus */ -- --long profile_init -- (const char * *files, profile_t *ret_profile); -- --void profile_release -- (profile_t profile); -- --long profile_set_default -- (profile_t profile, const char *def_string); -- --long profile_get_string -- (profile_t profile, const char *name, const char *subname, -- const char *subsubname, const char *def_val, -- char **ret_string); --long profile_get_integer -- (profile_t profile, const char *name, const char *subname, -- const char *subsubname, int def_val, -- int *ret_default); -- --long profile_get_uint -- (profile_t profile, const char *name, const char *subname, -- const char *subsubname, unsigned int def_val, -- unsigned int *ret_int); -- --long profile_get_double -- (profile_t profile, const char *name, const char *subname, -- const char *subsubname, double def_val, -- double *ret_float); -- --long profile_get_boolean -- (profile_t profile, const char *name, const char *subname, -- const char *subsubname, int def_val, -- int *ret_default); -- --long profile_iterator_create -- (profile_t profile, const char *const *names, -- int flags, void **ret_iter); -- --void profile_iterator_free -- (void **iter_p); -- --long profile_iterator -- (void **iter_p, char **ret_name, char **ret_value); -- --profile_syntax_err_cb_t profile_set_syntax_err_cb(profile_syntax_err_cb_t hook); -- --#ifdef __cplusplus --} --#endif /* __cplusplus */ -- --#endif /* _KRB5_H */ -diff --git a/e2fsck/profile_helpers.c b/e2fsck/profile_helpers.c -deleted file mode 100644 -index 9c9080a..0000000 ---- a/e2fsck/profile_helpers.c -+++ /dev/null -@@ -1,310 +0,0 @@ --/* -- * profile_helpers.c -- Helper functions for the profile library -- * -- * These functions are not part of the "core" profile library, and do -- * not require access to the internal functions and data structures of -- * the profile library. They are mainly convenience functions for -- * programs that want to do something unusual such as obtaining the -- * list of sections or relations, or accessing multiple values from a -- * relation that is listed more than once. This functionality can all -- * be done using the profile_iterator abstraction, but it is less -- * convenient. -- * -- * Copyright (C) 2006 by Theodore Ts'o. -- * -- * %Begin-Header% -- * This file may be redistributed under the terms of the GNU Public -- * License. -- * %End-Header% -- */ -- --#include "config.h" --#include --#include --#include -- --#include --#include "profile.h" --#include "prof_err.h" -- --/* -- * These functions --- init_list(), end_list(), and add_to_list() are -- * internal functions used to build up a null-terminated char ** list -- * of strings to be returned by functions like profile_get_values. -- * -- * The profile_string_list structure is used for internal booking -- * purposes to build up the list, which is returned in *ret_list by -- * the end_list() function. -- * -- * The publicly exported interface for freeing char** list is -- * profile_free_list(). -- */ -- --struct profile_string_list { -- char **list; -- int num; -- int max; --}; -- --/* -- * Initialize the string list abstraction. -- */ --static errcode_t init_list(struct profile_string_list *list) --{ -- list->num = 0; -- list->max = 10; -- list->list = malloc(list->max * sizeof(char *)); -- if (list->list == 0) -- return ENOMEM; -- list->list[0] = 0; -- return 0; --} -- --/* -- * Free any memory left over in the string abstraction, returning the -- * built up list in *ret_list if it is non-null. -- */ --static void end_list(struct profile_string_list *list, char ***ret_list) --{ -- char **cp; -- -- if (list == 0) -- return; -- -- if (ret_list) { -- *ret_list = list->list; -- return; -- } else { -- for (cp = list->list; *cp; cp++) -- free(*cp); -- free(list->list); -- } -- list->num = list->max = 0; -- list->list = 0; --} -- --/* -- * Add a string to the list. -- */ --static errcode_t add_to_list(struct profile_string_list *list, char *str) --{ -- char **newlist; -- int newmax; -- -- if (list->num+1 >= list->max) { -- newmax = list->max + 10; -- newlist = realloc(list->list, newmax * sizeof(char *)); -- if (newlist == 0) -- return ENOMEM; -- list->max = newmax; -- list->list = newlist; -- } -- -- list->list[list->num++] = str; -- list->list[list->num] = 0; -- return 0; --} -- --/* -- * Return TRUE if the string is already a member of the list. -- */ --static int is_list_member(struct profile_string_list *list, const char *str) --{ -- char **cpp; -- -- if (!list->list) -- return 0; -- -- for (cpp = list->list; *cpp; cpp++) { -- if (!strcmp(*cpp, str)) -- return 1; -- } -- return 0; --} -- --/* -- * This function frees a null-terminated list as returned by -- * profile_get_values. -- */ --void profile_free_list(char **list) --{ -- char **cp; -- -- if (list == 0) -- return; -- -- for (cp = list; *cp; cp++) -- free(*cp); -- free(list); --} -- --errcode_t --profile_get_values(profile_t profile, const char *const *names, -- char ***ret_values) --{ -- errcode_t retval; -- void *state; -- char *value; -- struct profile_string_list values; -- -- if ((retval = profile_iterator_create(profile, names, -- PROFILE_ITER_RELATIONS_ONLY, -- &state))) -- return retval; -- -- if ((retval = init_list(&values))) -- return retval; -- -- do { -- if ((retval = profile_iterator(&state, 0, &value))) -- goto cleanup; -- if (value) -- add_to_list(&values, value); -- } while (state); -- -- if (values.num == 0) { -- retval = PROF_NO_RELATION; -- goto cleanup; -- } -- -- end_list(&values, ret_values); -- return 0; -- --cleanup: -- end_list(&values, 0); -- return retval; --} -- --/* -- * This function will return the list of the names of subections in the -- * under the specified section name. -- */ --errcode_t --profile_get_subsection_names(profile_t profile, const char **names, -- char ***ret_names) --{ -- errcode_t retval; -- void *state; -- char *name; -- struct profile_string_list values; -- -- if ((retval = profile_iterator_create(profile, names, -- PROFILE_ITER_LIST_SECTION | PROFILE_ITER_SECTIONS_ONLY, -- &state))) -- return retval; -- -- if ((retval = init_list(&values))) -- return retval; -- -- do { -- if ((retval = profile_iterator(&state, &name, 0))) -- goto cleanup; -- if (name) -- add_to_list(&values, name); -- } while (state); -- -- end_list(&values, ret_names); -- return 0; -- --cleanup: -- end_list(&values, 0); -- return retval; --} -- --/* -- * This function will return the list of the names of relations in the -- * under the specified section name. -- */ --errcode_t --profile_get_relation_names(profile_t profile, const char **names, -- char ***ret_names) --{ -- errcode_t retval; -- void *state; -- char *name; -- struct profile_string_list values; -- -- if ((retval = profile_iterator_create(profile, names, -- PROFILE_ITER_LIST_SECTION | PROFILE_ITER_RELATIONS_ONLY, -- &state))) -- return retval; -- -- if ((retval = init_list(&values))) -- return retval; -- -- do { -- if ((retval = profile_iterator(&state, &name, 0))) -- goto cleanup; -- if (name) { -- if (is_list_member(&values, name)) -- free(name); -- else -- add_to_list(&values, name); -- } -- } while (state); -- -- end_list(&values, ret_names); -- return 0; -- --cleanup: -- end_list(&values, 0); -- return retval; --} -- -- --void --profile_release_string(char *str) --{ -- free(str); --} -- --errcode_t --profile_init_path(const char * filepath, -- profile_t *ret_profile) --{ -- int n_entries, i; -- unsigned int ent_len; -- const char *s, *t; -- char **filenames; -- errcode_t retval; -- -- /* count the distinct filename components */ -- for(s = filepath, n_entries = 1; *s; s++) { -- if (*s == ':') -- n_entries++; -- } -- -- /* the array is NULL terminated */ -- filenames = (char **) malloc((n_entries+1) * sizeof(char*)); -- if (filenames == 0) -- return ENOMEM; -- -- /* measure, copy, and skip each one */ -- for(s = filepath, i=0; (t = strchr(s, ':')) || (t=s+strlen(s)); s=t+1, i++) { -- ent_len = t-s; -- filenames[i] = (char*) malloc(ent_len + 1); -- if (filenames[i] == 0) { -- /* if malloc fails, free the ones that worked */ -- while(--i >= 0) free(filenames[i]); -- free(filenames); -- return ENOMEM; -- } -- strncpy(filenames[i], s, ent_len); -- filenames[i][ent_len] = 0; -- if (*t == 0) { -- i++; -- break; -- } -- } -- /* cap the array */ -- filenames[i] = 0; -- -- retval = profile_init((const char **) filenames, -- ret_profile); -- -- /* count back down and free the entries */ -- while(--i >= 0) free(filenames[i]); -- free(filenames); -- -- return retval; --} -diff --git a/e2fsck/profile_helpers.h b/e2fsck/profile_helpers.h -deleted file mode 100644 -index af63ca5..0000000 ---- a/e2fsck/profile_helpers.h -+++ /dev/null -@@ -1,28 +0,0 @@ --/* -- * profile_helpers.h -- Function prototypes for profile helper functions -- * -- * Copyright (C) 2006 by Theodore Ts'o. -- * -- * %Begin-Header% -- * This file may be redistributed under the terms of the GNU Public -- * License. -- * %End-Header% -- */ -- --long profile_get_values -- (profile_t profile, const char *const *names, char ***ret_values); -- --void profile_free_list -- (char **list); -- --long profile_get_relation_names -- (profile_t profile, const char **names, char ***ret_names); -- --long profile_get_subsection_names -- (profile_t profile, const char **names, char ***ret_names); -- --void profile_release_string (char *str); -- --long profile_init_path -- (const char * filelist, profile_t *ret_profile); -- -diff --git a/e2fsck/quota.c b/e2fsck/quota.c -index c6bbb9a..2293aad 100644 ---- a/e2fsck/quota.c -+++ b/e2fsck/quota.c -@@ -15,7 +15,6 @@ - - #include "e2fsck.h" - #include "problem.h" --#include "quota/quotaio.h" - - static void move_quota_inode(ext2_filsys fs, ext2_ino_t from_ino, - ext2_ino_t to_ino, int qtype) -diff --git a/e2fsck/readahead.c b/e2fsck/readahead.c -new file mode 100644 -index 0000000..a860f2b ---- /dev/null -+++ b/e2fsck/readahead.c -@@ -0,0 +1,252 @@ -+/* -+ * readahead.c -- Prefetch filesystem metadata to speed up fsck. -+ * -+ * 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% -+ */ -+ -+#include "config.h" -+#include -+ -+#include "e2fsck.h" -+ -+#undef DEBUG -+ -+#ifdef DEBUG -+# define dbg_printf(f, a...) do {printf(f, ## a); fflush(stdout); } while (0) -+#else -+# define dbg_printf(f, a...) -+#endif -+ -+struct read_dblist { -+ errcode_t err; -+ blk64_t run_start; -+ blk64_t run_len; -+ int flags; -+}; -+ -+static int readahead_dir_block(ext2_filsys fs, struct ext2_db_entry2 *db, -+ void *priv_data) -+{ -+ struct read_dblist *pr = priv_data; -+ e2_blkcnt_t count = (pr->flags & E2FSCK_RA_DBLIST_IGNORE_BLOCKCNT ? -+ 1 : db->blockcnt); -+ -+ if (!pr->run_len || db->blk != pr->run_start + pr->run_len) { -+ if (pr->run_len) { -+ pr->err = io_channel_cache_readahead(fs->io, -+ pr->run_start, -+ pr->run_len); -+ dbg_printf("readahead start=%llu len=%llu err=%d\n", -+ pr->run_start, pr->run_len, -+ (int)pr->err); -+ } -+ pr->run_start = db->blk; -+ pr->run_len = 0; -+ } -+ pr->run_len += count; -+ -+ return pr->err ? DBLIST_ABORT : 0; -+} -+ -+errcode_t e2fsck_readahead_dblist(ext2_filsys fs, int flags, -+ ext2_dblist dblist, -+ unsigned long long start, -+ unsigned long long count) -+{ -+ errcode_t err; -+ struct read_dblist pr; -+ -+ dbg_printf("%s: flags=0x%x\n", __func__, flags); -+ if (flags & ~E2FSCK_RA_DBLIST_ALL_FLAGS) -+ return EXT2_ET_INVALID_ARGUMENT; -+ -+ memset(&pr, 0, sizeof(pr)); -+ pr.flags = flags; -+ err = ext2fs_dblist_iterate3(dblist, readahead_dir_block, start, -+ count, &pr); -+ if (pr.err) -+ return pr.err; -+ if (err) -+ return err; -+ -+ if (pr.run_len) -+ err = io_channel_cache_readahead(fs->io, pr.run_start, -+ pr.run_len); -+ -+ return err; -+} -+ -+static errcode_t e2fsck_readahead_bitmap(ext2_filsys fs, -+ ext2fs_block_bitmap ra_map) -+{ -+ blk64_t start, end, out; -+ errcode_t err; -+ -+ start = 1; -+ end = ext2fs_blocks_count(fs->super) - 1; -+ -+ err = ext2fs_find_first_set_block_bitmap2(ra_map, start, end, &out); -+ while (err == 0) { -+ start = out; -+ err = ext2fs_find_first_zero_block_bitmap2(ra_map, start, end, -+ &out); -+ if (err == ENOENT) { -+ out = end; -+ err = 0; -+ } else if (err) -+ break; -+ -+ err = io_channel_cache_readahead(fs->io, start, out - start); -+ if (err) -+ break; -+ start = out; -+ err = ext2fs_find_first_set_block_bitmap2(ra_map, start, end, -+ &out); -+ } -+ -+ if (err == ENOENT) -+ err = 0; -+ -+ return err; -+} -+ -+/* Try not to spew bitmap range errors for readahead */ -+static errcode_t mark_bmap_range(ext2fs_block_bitmap map, -+ blk64_t blk, unsigned int num) -+{ -+ if (blk >= ext2fs_get_generic_bmap_start(map) && -+ blk + num <= ext2fs_get_generic_bmap_end(map)) -+ ext2fs_mark_block_bitmap_range2(map, blk, num); -+ else -+ return EXT2_ET_INVALID_ARGUMENT; -+ return 0; -+} -+ -+static errcode_t mark_bmap(ext2fs_block_bitmap map, blk64_t blk) -+{ -+ if (blk >= ext2fs_get_generic_bmap_start(map) && -+ blk <= ext2fs_get_generic_bmap_end(map)) -+ ext2fs_mark_block_bitmap2(map, blk); -+ else -+ return EXT2_ET_INVALID_ARGUMENT; -+ return 0; -+} -+ -+errcode_t e2fsck_readahead(ext2_filsys fs, int flags, dgrp_t start, -+ dgrp_t ngroups) -+{ -+ blk64_t super, old_gdt, new_gdt; -+ blk_t blocks; -+ dgrp_t i; -+ ext2fs_block_bitmap ra_map = NULL; -+ dgrp_t end = start + ngroups; -+ errcode_t err = 0; -+ -+ dbg_printf("%s: flags=0x%x start=%d groups=%d\n", __func__, flags, -+ start, ngroups); -+ if (flags & ~E2FSCK_READA_ALL_FLAGS) -+ return EXT2_ET_INVALID_ARGUMENT; -+ -+ if (end > fs->group_desc_count) -+ end = fs->group_desc_count; -+ -+ if (flags == 0) -+ return 0; -+ -+ err = ext2fs_allocate_block_bitmap(fs, "readahead bitmap", -+ &ra_map); -+ if (err) -+ return err; -+ -+ for (i = start; i < end; i++) { -+ err = ext2fs_super_and_bgd_loc2(fs, i, &super, &old_gdt, -+ &new_gdt, &blocks); -+ if (err) -+ break; -+ -+ if (flags & E2FSCK_READA_SUPER) { -+ err = mark_bmap(ra_map, super); -+ if (err) -+ break; -+ } -+ -+ if (flags & E2FSCK_READA_GDT) { -+ err = mark_bmap_range(ra_map, -+ old_gdt ? old_gdt : new_gdt, -+ blocks); -+ if (err) -+ break; -+ } -+ -+ if ((flags & E2FSCK_READA_BBITMAP) && -+ !ext2fs_bg_flags_test(fs, i, EXT2_BG_BLOCK_UNINIT) && -+ ext2fs_bg_free_blocks_count(fs, i) < -+ fs->super->s_blocks_per_group) { -+ super = ext2fs_block_bitmap_loc(fs, i); -+ err = mark_bmap(ra_map, super); -+ if (err) -+ break; -+ } -+ -+ if ((flags & E2FSCK_READA_IBITMAP) && -+ !ext2fs_bg_flags_test(fs, i, EXT2_BG_INODE_UNINIT) && -+ ext2fs_bg_free_inodes_count(fs, i) < -+ fs->super->s_inodes_per_group) { -+ super = ext2fs_inode_bitmap_loc(fs, i); -+ err = mark_bmap(ra_map, super); -+ if (err) -+ break; -+ } -+ -+ if ((flags & E2FSCK_READA_ITABLE) && -+ ext2fs_bg_free_inodes_count(fs, i) < -+ fs->super->s_inodes_per_group) { -+ super = ext2fs_inode_table_loc(fs, i); -+ blocks = fs->inode_blocks_per_group - -+ (ext2fs_bg_itable_unused(fs, i) * -+ EXT2_INODE_SIZE(fs->super) / fs->blocksize); -+ err = mark_bmap_range(ra_map, super, blocks); -+ if (err) -+ break; -+ } -+ } -+ -+ if (!err) -+ err = e2fsck_readahead_bitmap(fs, ra_map); -+ -+ ext2fs_free_block_bitmap(ra_map); -+ return err; -+} -+ -+int e2fsck_can_readahead(ext2_filsys fs) -+{ -+ errcode_t err; -+ -+ err = io_channel_cache_readahead(fs->io, 0, 1); -+ dbg_printf("%s: supp=%d\n", __func__, err != EXT2_ET_OP_NOT_SUPPORTED); -+ return err != EXT2_ET_OP_NOT_SUPPORTED; -+} -+ -+unsigned long long e2fsck_guess_readahead(ext2_filsys fs) -+{ -+ unsigned long long guess; -+ -+ /* -+ * The optimal readahead sizes were experimentally determined by -+ * djwong in August 2014. Setting the RA size to two block groups' -+ * worth of inode table blocks seems to yield the largest reductions -+ * in e2fsck runtime. -+ */ -+ guess = 2ULL * fs->blocksize * fs->inode_blocks_per_group; -+ -+ /* Disable RA if it'd use more 1/50th of RAM. */ -+ if (get_memory_size() > (guess * 50)) -+ return guess / 1024; -+ -+ return 0; -+} -diff --git a/e2fsck/recovery.c b/e2fsck/recovery.c -index e4e5ae1..d5244be 100644 ---- a/e2fsck/recovery.c -+++ b/e2fsck/recovery.c -@@ -1,5 +1,5 @@ - /* -- * linux/fs/jbd/recovery.c -+ * linux/fs/jbd2/recovery.c - * - * Written by Stephen C. Tweedie , 1999 - * -@@ -14,14 +14,14 @@ - */ - - #ifndef __KERNEL__ --#include "config.h" - #include "jfs_user.h" - #else - #include - #include --#include -+#include - #include --#include -+#include -+#include - #endif - - /* -@@ -90,7 +90,7 @@ static int do_readahead(journal_t *journal, unsigned int start) - err = journal_bmap(journal, next, &blocknr); - - if (err) { -- printk (KERN_ERR "JBD: bad block at offset %u\n", -+ printk(KERN_ERR "JBD2: bad block at offset %u\n", - next); - goto failed; - } -@@ -139,14 +139,14 @@ static int jread(struct buffer_head **bhp, journal_t *journal, - *bhp = NULL; - - if (offset >= journal->j_maxlen) { -- printk(KERN_ERR "JBD: corrupted journal superblock\n"); -+ printk(KERN_ERR "JBD2: corrupted journal superblock\n"); - return -EIO; - } - - err = journal_bmap(journal, offset, &blocknr); - - if (err) { -- printk (KERN_ERR "JBD: bad block at offset %u\n", -+ printk(KERN_ERR "JBD2: bad block at offset %u\n", - offset); - return err; - } -@@ -164,7 +164,7 @@ static int jread(struct buffer_head **bhp, journal_t *journal, - } - - if (!buffer_uptodate(bh)) { -- printk (KERN_ERR "JBD: Failed to read block at offset %u\n", -+ printk(KERN_ERR "JBD2: Failed to read block at offset %u\n", - offset); - brelse(bh); - return -EIO; -@@ -174,6 +174,25 @@ 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; -+ __u32 calculated; -+ -+ if (!journal_has_csum_v2or3(j)) -+ return 1; -+ -+ tail = (struct journal_block_tail *)(buf + j->j_blocksize - -+ sizeof(struct journal_block_tail)); -+ provided = tail->t_checksum; -+ tail->t_checksum = 0; -+ calculated = jbd2_chksum(j, j->j_csum_seed, buf, j->j_blocksize); -+ tail->t_checksum = provided; -+ -+ return provided == ext2fs_cpu_to_be32(calculated); -+} - - /* - * Count the number of in-use tags in a journal descriptor block. -@@ -186,6 +205,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 (journal_has_csum_v2or3(journal)) -+ size -= sizeof(struct journal_block_tail); -+ - tagp = &bh->b_data[sizeof(journal_header_t)]; - - while ((tagp - bh->b_data + tag_bytes) <= size) { -@@ -193,10 +215,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 & ext2fs_cpu_to_be16(JFS_FLAG_SAME_UUID))) - tagp += 16; - -- if (tag->t_flags & cpu_to_be32(JFS_FLAG_LAST_TAG)) -+ if (tag->t_flags & ext2fs_cpu_to_be16(JFS_FLAG_LAST_TAG)) - break; - } - -@@ -225,7 +247,7 @@ do { \ - */ - int journal_recover(journal_t *journal) - { -- int err; -+ int err, err2; - journal_superblock_t * sb; - - struct recovery_info info; -@@ -241,8 +263,8 @@ int journal_recover(journal_t *journal) - - if (!sb->s_start) { - jbd_debug(1, "No recovery required, last transaction %d\n", -- be32_to_cpu(sb->s_sequence)); -- journal->j_transaction_sequence = be32_to_cpu(sb->s_sequence) + 1; -+ ext2fs_be32_to_cpu(sb->s_sequence)); -+ journal->j_transaction_sequence = ext2fs_be32_to_cpu(sb->s_sequence) + 1; - return 0; - } - -@@ -252,10 +274,10 @@ int journal_recover(journal_t *journal) - if (!err) - err = do_one_pass(journal, &info, PASS_REPLAY); - -- jbd_debug(1, "JBD: recovery, exit status %d, " -+ jbd_debug(1, "JBD2: recovery, exit status %d, " - "recovered transactions %u to %u\n", - err, info.start_transaction, info.end_transaction); -- jbd_debug(1, "JBD: Replayed %d and revoked %d/%d blocks\n", -+ jbd_debug(1, "JBD2: Replayed %d and revoked %d/%d blocks\n", - info.nr_replays, info.nr_revoke_hits, info.nr_revokes); - - /* Restart the log at the next transaction ID, thus invalidating -@@ -263,7 +285,15 @@ int journal_recover(journal_t *journal) - journal->j_transaction_sequence = ++info.end_transaction; - - journal_clear_revoke(journal); -- sync_blockdev(journal->j_fs_dev); -+ err2 = sync_blockdev(journal->j_fs_dev); -+ if (!err) -+ err = err2; -+ /* Make sure all replayed data is on permanent storage */ -+ if (journal->j_flags & JFS_BARRIER) { -+ err2 = blkdev_issue_flush(journal->j_fs_dev, GFP_KERNEL, NULL); -+ if (!err) -+ err = err2; -+ } - return err; - } - -@@ -283,6 +313,7 @@ int journal_recover(journal_t *journal) - int journal_skip_recovery(journal_t *journal) - { - int err; -+ - struct recovery_info info; - - memset (&info, 0, sizeof(info)); -@@ -290,17 +321,16 @@ int journal_skip_recovery(journal_t *journal) - err = do_one_pass(journal, &info, PASS_SCAN); - - if (err) { -- printk(KERN_ERR "JBD: error %d scanning journal\n", err); -+ printk(KERN_ERR "JBD2: error %d scanning journal\n", err); - ++journal->j_transaction_sequence; - } else { --#ifdef CONFIG_JBD_DEBUG -- journal_superblock_t *sb = journal->j_superblock; -- -- int dropped = info.end_transaction - be32_to_cpu(sb->s_sequence); --#endif -+#ifdef CONFIG_JFS_DEBUG -+ int dropped = info.end_transaction - -+ ext2fs_be32_to_cpu(journal->j_superblock->s_sequence); - jbd_debug(1, -- "JBD: ignoring %d transaction%s from the journal.\n", -+ "JBD2: ignoring %d transaction%s from the journal.\n", - dropped, (dropped == 1) ? "" : "s"); -+#endif - journal->j_transaction_sequence = ++info.end_transaction; - } - -@@ -308,11 +338,12 @@ int journal_skip_recovery(journal_t *journal) - return err; - } - --static inline unsigned long long read_tag_block(int tag_bytes, journal_block_tag_t *tag) -+static inline unsigned long long read_tag_block(journal_t *journal, -+ journal_block_tag_t *tag) - { -- unsigned long long block = be32_to_cpu(tag->t_blocknr); -- if (tag_bytes > JBD_TAG_SIZE32) -- block |= (__u64)be32_to_cpu(tag->t_blocknr_high) << 32; -+ unsigned long long block = ext2fs_be32_to_cpu(tag->t_blocknr); -+ if (JFS_HAS_INCOMPAT_FEATURE(journal, JFS_FEATURE_INCOMPAT_64BIT)) -+ block |= (u64)ext2fs_be32_to_cpu(tag->t_blocknr_high) << 32; - return block; - } - -@@ -321,10 +352,10 @@ static inline unsigned long long read_tag_block(int tag_bytes, journal_block_tag - * descriptor block. - */ - static int calc_chksums(journal_t *journal, struct buffer_head *bh, -- unsigned long long *next_log_block, __u32 *crc32_sum) -+ unsigned long *next_log_block, __u32 *crc32_sum) - { - int i, num_blks, err; -- unsigned long long io_block; -+ unsigned long io_block; - struct buffer_head *obh; - - num_blks = count_tags(journal, bh); -@@ -336,23 +367,61 @@ static int calc_chksums(journal_t *journal, struct buffer_head *bh, - wrap(journal, *next_log_block); - err = jread(&obh, journal, io_block); - if (err) { -- printk(KERN_ERR "JBD: IO error %d recovering block " -- "%llu in log\n", err, io_block); -+ printk(KERN_ERR "JBD2: IO error %d recovering block " -+ "%lu in log\n", err, io_block); - return 1; - } else { - *crc32_sum = crc32_be(*crc32_sum, (void *)obh->b_data, - obh->b_size); - } -- brelse(obh); -+ put_bh(obh); - } - return 0; - } - -+static int jbd2_commit_block_csum_verify(journal_t *j, void *buf) -+{ -+ struct commit_header *h; -+ __u32 provided; -+ __u32 calculated; -+ -+ if (!journal_has_csum_v2or3(j)) -+ return 1; -+ -+ h = buf; -+ provided = h->h_chksum[0]; -+ h->h_chksum[0] = 0; -+ calculated = jbd2_chksum(j, j->j_csum_seed, buf, j->j_blocksize); -+ h->h_chksum[0] = provided; -+ -+ return provided == ext2fs_cpu_to_be32(calculated); -+} -+ -+static int jbd2_block_tag_csum_verify(journal_t *j, journal_block_tag_t *tag, -+ void *buf, __u32 sequence) -+{ -+ journal_block_tag3_t *tag3 = (journal_block_tag3_t *)tag; -+ __u32 csum32; -+ __u32 seq; -+ -+ if (!journal_has_csum_v2or3(j)) -+ return 1; -+ -+ seq = ext2fs_cpu_to_be32(sequence); -+ csum32 = jbd2_chksum(j, j->j_csum_seed, (__u8 *)&seq, sizeof(seq)); -+ csum32 = jbd2_chksum(j, csum32, buf, j->j_blocksize); -+ -+ if (JFS_HAS_INCOMPAT_FEATURE(j, JFS_FEATURE_INCOMPAT_CSUM_V3)) -+ return tag3->t_checksum == ext2fs_cpu_to_be32(csum32); -+ -+ return tag->t_checksum == ext2fs_cpu_to_be16(csum32); -+} -+ - static int do_one_pass(journal_t *journal, - struct recovery_info *info, enum passtype pass) - { - unsigned int first_commit_ID, next_commit_ID; -- unsigned long long next_log_block; -+ unsigned long next_log_block; - int err, success = 0; - journal_superblock_t * sb; - journal_header_t * tmp; -@@ -361,6 +430,8 @@ 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; -+ int block_error = 0; - - /* - * First thing is to establish what we expect to find in the log -@@ -369,8 +440,8 @@ static int do_one_pass(journal_t *journal, - */ - - sb = journal->j_superblock; -- next_commit_ID = be32_to_cpu(sb->s_sequence); -- next_log_block = be32_to_cpu(sb->s_start); -+ next_commit_ID = ext2fs_be32_to_cpu(sb->s_sequence); -+ next_log_block = ext2fs_be32_to_cpu(sb->s_start); - - first_commit_ID = next_commit_ID; - if (pass == PASS_SCAN) -@@ -402,14 +473,14 @@ static int do_one_pass(journal_t *journal, - if (tid_geq(next_commit_ID, info->end_transaction)) - break; - -- jbd_debug(2, "Scanning for sequence ID %u at %llu/%lu\n", -+ jbd_debug(2, "Scanning for sequence ID %u at %lu/%lu\n", - next_commit_ID, next_log_block, journal->j_last); - - /* Skip over each chunk of the transaction looking - * either the next descriptor block or the final commit - * record. */ - -- jbd_debug(3, "JBD: checking block %llu\n", next_log_block); -+ jbd_debug(3, "JBD2: checking block %ld\n", next_log_block); - err = jread(&bh, journal, next_log_block); - if (err) - goto failed; -@@ -425,13 +496,13 @@ static int do_one_pass(journal_t *journal, - - tmp = (journal_header_t *)bh->b_data; - -- if (tmp->h_magic != cpu_to_be32(JFS_MAGIC_NUMBER)) { -+ if (tmp->h_magic != ext2fs_cpu_to_be32(JFS_MAGIC_NUMBER)) { - brelse(bh); - break; - } - -- blocktype = be32_to_cpu(tmp->h_blocktype); -- sequence = be32_to_cpu(tmp->h_sequence); -+ blocktype = ext2fs_be32_to_cpu(tmp->h_blocktype); -+ sequence = ext2fs_be32_to_cpu(tmp->h_sequence); - jbd_debug(3, "Found magic %d, sequence %d\n", - blocktype, sequence); - -@@ -446,6 +517,18 @@ static int do_one_pass(journal_t *journal, - - switch(blocktype) { - case JFS_DESCRIPTOR_BLOCK: -+ /* Verify checksum first */ -+ if (journal_has_csum_v2or3(journal)) -+ 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, -@@ -458,15 +541,15 @@ static int do_one_pass(journal_t *journal, - if (calc_chksums(journal, bh, - &next_log_block, - &crc32_sum)) { -- brelse(bh); -+ put_bh(bh); - break; - } -- brelse(bh); -+ put_bh(bh); - continue; - } - next_log_block += count_tags(journal, bh); - wrap(journal, next_log_block); -- brelse(bh); -+ put_bh(bh); - continue; - } - -@@ -476,11 +559,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) { -- unsigned long long io_block; -+ <= journal->j_blocksize - descr_csum_size) { -+ unsigned long io_block; - - tag = (journal_block_tag_t *) tagp; -- flags = be32_to_cpu(tag->t_flags); -+ flags = ext2fs_be16_to_cpu(tag->t_flags); - - io_block = next_log_block++; - wrap(journal, next_log_block); -@@ -489,15 +572,15 @@ static int do_one_pass(journal_t *journal, - /* Recover what we can, but - * report failure at the end. */ - success = err; -- printk (KERN_ERR -- "JBD: IO error %d recovering " -- "block %llu in log\n", -+ printk(KERN_ERR -+ "JBD2: IO error %d recovering " -+ "block %ld in log\n", - err, io_block); - } else { - unsigned long long blocknr; - - J_ASSERT(obh != NULL); -- blocknr = read_tag_block(tag_bytes, -+ blocknr = read_tag_block(journal, - tag); - - /* If the block has been -@@ -511,6 +594,20 @@ 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, -+ ext2fs_be32_to_cpu(tmp->h_sequence))) { -+ brelse(obh); -+ success = -EIO; -+ printk(KERN_ERR "JBD2: Invalid " -+ "checksum recovering " -+ "block %llu in log\n", -+ blocknr); -+ block_error = 1; -+ goto skip_write; -+ } -+ - /* Find a buffer for the new - * data being restored */ - nbh = __getblk(journal->j_fs_dev, -@@ -518,7 +615,7 @@ static int do_one_pass(journal_t *journal, - journal->j_blocksize); - if (nbh == NULL) { - printk(KERN_ERR -- "JBD: Out of memory " -+ "JBD2: Out of memory " - "during recovery.\n"); - err = -ENOMEM; - brelse(bh); -@@ -530,10 +627,8 @@ static int do_one_pass(journal_t *journal, - memcpy(nbh->b_data, obh->b_data, - journal->j_blocksize); - if (flags & JFS_FLAG_ESCAPE) { -- journal_header_t *header; -- -- header = (journal_header_t *) &nbh->b_data[0]; -- header->h_magic = cpu_to_be32(JFS_MAGIC_NUMBER); -+ *((__u32 *)nbh->b_data) = -+ ext2fs_cpu_to_be32(JFS_MAGIC_NUMBER); - } - - BUFFER_TRACE(nbh, "marking dirty"); -@@ -560,8 +655,6 @@ static int do_one_pass(journal_t *journal, - continue; - - case JFS_COMMIT_BLOCK: -- jbd_debug(3, "Commit block for #%u found\n", -- next_commit_ID); - /* How to differentiate between interrupted commit - * and journal corruption ? - * -@@ -604,12 +697,10 @@ static int do_one_pass(journal_t *journal, - struct commit_header *cbh = - (struct commit_header *)bh->b_data; - unsigned found_chksum = -- be32_to_cpu(cbh->h_chksum[0]); -+ ext2fs_be32_to_cpu(cbh->h_chksum[0]); - - chksum_err = chksum_seen = 0; - -- jbd_debug(3, "Checksums %x %x\n", -- crc32_sum, found_chksum); - if (info->end_transaction) { - journal->j_failed_commit = - info->end_transaction; -@@ -618,9 +709,9 @@ static int do_one_pass(journal_t *journal, - } - - if (crc32_sum == found_chksum && -- cbh->h_chksum_type == JBD2_CRC32_CHKSUM && -+ cbh->h_chksum_type == JFS_CRC32_CHKSUM && - cbh->h_chksum_size == -- JBD2_CRC32_CHKSUM_SIZE) -+ JFS_CRC32_CHKSUM_SIZE) - chksum_seen = 1; - else if (!(cbh->h_chksum_type == 0 && - cbh->h_chksum_size == 0 && -@@ -640,8 +731,7 @@ static int do_one_pass(journal_t *journal, - - if (chksum_err) { - info->end_transaction = next_commit_ID; -- jbd_debug(1, "Checksum_err %x %x\n", -- crc32_sum, found_chksum); -+ - if (!JFS_HAS_INCOMPAT_FEATURE(journal, - JFS_FEATURE_INCOMPAT_ASYNC_COMMIT)){ - journal->j_failed_commit = -@@ -652,6 +742,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; -@@ -694,20 +797,40 @@ static int do_one_pass(journal_t *journal, - /* It's really bad news if different passes end up at - * different places (but possible due to IO errors). */ - if (info->end_transaction != next_commit_ID) { -- printk (KERN_ERR "JBD: recovery pass %d ended at " -+ printk(KERN_ERR "JBD2: recovery pass %d ended at " - "transaction %u, expected %u\n", - pass, next_commit_ID, info->end_transaction); - if (!success) - success = -EIO; - } - } -- -+ if (block_error && success == 0) -+ success = -EIO; - return success; - - failed: - return err; - } - -+static int jbd2_revoke_block_csum_verify(journal_t *j, -+ void *buf) -+{ -+ struct journal_revoke_tail *tail; -+ __u32 provided; -+ __u32 calculated; -+ -+ if (!journal_has_csum_v2or3(j)) -+ return 1; -+ -+ tail = (struct journal_revoke_tail *)(buf + j->j_blocksize - -+ sizeof(struct journal_revoke_tail)); -+ provided = tail->r_checksum; -+ tail->r_checksum = 0; -+ calculated = jbd2_chksum(j, j->j_csum_seed, buf, j->j_blocksize); -+ tail->r_checksum = provided; -+ -+ return provided == ext2fs_cpu_to_be32(calculated); -+} - - /* Scan a revoke record, marking all blocks mentioned as revoked. */ - -@@ -716,29 +839,34 @@ static int scan_revoke_records(journal_t *journal, struct buffer_head *bh, - { - journal_revoke_header_t *header; - int offset, max; -+ int csum_size = 0; -+ __u32 rcount; - int record_len = 4; - - header = (journal_revoke_header_t *) bh->b_data; - offset = sizeof(journal_revoke_header_t); -- max = be32_to_cpu(header->r_count); -+ rcount = ext2fs_be32_to_cpu(header->r_count); -+ -+ if (!jbd2_revoke_block_csum_verify(journal, header)) -+ return -EINVAL; -+ -+ if (journal_has_csum_v2or3(journal)) -+ csum_size = sizeof(struct journal_revoke_tail); -+ if (rcount > journal->j_blocksize - csum_size) -+ return -EINVAL; -+ max = rcount; - - if (JFS_HAS_INCOMPAT_FEATURE(journal, JFS_FEATURE_INCOMPAT_64BIT)) - record_len = 8; - -- while (offset < max) { -+ while (offset + record_len <= max) { - unsigned long long blocknr; - int err; - -- if (record_len == 4) { -- __be32 b; -- memcpy(&b, bh->b_data + offset, sizeof(__be32)); -- blocknr = ext2fs_be32_to_cpu(b); -- } else { -- __be64 b; -- memcpy(&b, bh->b_data + offset, sizeof(__be64)); -- blocknr = ext2fs_be64_to_cpu(b); -- } -- -+ if (record_len == 4) -+ blocknr = ext2fs_be32_to_cpu(* ((__u32 *) (bh->b_data+offset))); -+ else -+ blocknr = ext2fs_be64_to_cpu(* ((__u64 *) (bh->b_data+offset))); - offset += record_len; - err = journal_set_revoke(journal, blocknr, sequence); - if (err) -diff --git a/e2fsck/region.c b/e2fsck/region.c -index 4b669f0..e32f89d 100644 ---- a/e2fsck/region.c -+++ b/e2fsck/region.c -@@ -159,10 +159,10 @@ void region_print(region_t region, FILE *f) - struct region_el *r; - int i = 0; - -- fprintf(f, "Printing region (min=%d. max=%d)\n\t", region->min, -+ fprintf(f, "Printing region (min=%llu. max=%llu)\n\t", region->min, - region->max); - for (r = region->allocated; r; r = r->next) { -- fprintf(f, "(%d, %d) ", r->start, r->end); -+ fprintf(f, "(%llu, %llu) ", r->start, r->end); - if (++i >= 8) - fprintf(f, "\n\t"); - } -@@ -183,7 +183,7 @@ int main(int argc, char **argv) - case BCODE_CREATE: - start = bcode_program[pc++]; - end = bcode_program[pc++]; -- printf("Creating region with args(%d, %d)\n", -+ printf("Creating region with args(%llu, %llu)\n", - start, end); - r = region_create(start, end); - if (!r) { -@@ -195,7 +195,7 @@ int main(int argc, char **argv) - start = bcode_program[pc++]; - end = bcode_program[pc++]; - ret = region_allocate(r, start, end); -- printf("Region_allocate(%d, %d) returns %d\n", -+ printf("Region_allocate(%llu, %llu) returns %d\n", - start, end, ret); - break; - case BCODE_PRINT: -@@ -203,6 +203,8 @@ int main(int argc, char **argv) - break; - } - } -+ if (r) -+ region_free(r); - } - - #endif /* TEST_PROGRAM */ -diff --git a/e2fsck/rehash.c b/e2fsck/rehash.c -index 8ff4883..bddbe19 100644 ---- a/e2fsck/rehash.c -+++ b/e2fsck/rehash.c -@@ -52,9 +52,29 @@ - #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; -+ ext2_ino_t ino; - errcode_t err; - e2fsck_t ctx; - struct hash_entry *harray; -@@ -62,6 +82,7 @@ struct fill_dir_struct { - unsigned int dir_size; - int compress; - ino_t parent; -+ ext2_ino_t dir; - }; - - struct hash_entry { -@@ -89,7 +110,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) -@@ -100,13 +121,19 @@ static int fill_dir_block(ext2_filsys fs, - fd->err = EXT2_ET_DIR_CORRUPTED; - return BLOCK_ABORT; - } -+ - dir = (fd->buf+offset); -- if (HOLE_BLKADDR(*block_nr)) { -+ if (*block_nr == 0) { - memset(dir, 0, fs->blocksize); - 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 +146,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 +177,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 +208,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 +305,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 +325,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 +368,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 +383,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 +396,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, new_name, new_len, - fs->super->s_hash_seed, - &ent->hash, &ent->minor_hash); - fixed++; -@@ -407,6 +436,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 +448,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 +466,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 +483,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 +502,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 +526,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 +542,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 +569,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 +586,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 +689,7 @@ struct write_dir_struct { - errcode_t err; - e2fsck_t ctx; - blk64_t cleared; -+ ext2_ino_t dir; - }; - - /* -@@ -641,11 +704,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 +735,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; -@@ -672,11 +747,11 @@ static int write_dir_block(ext2_filsys fs, - - static errcode_t write_directory(e2fsck_t ctx, ext2_filsys fs, - struct out_dir *outdir, -- ext2_ino_t ino, int compress) -+ ext2_ino_t ino, struct ext2_inode *inode, -+ int compress) - { - struct write_dir_struct wd; - errcode_t retval; -- struct ext2_inode inode; - - retval = e2fsck_expand_directory(ctx, ino, -1, outdir->num); - if (retval) -@@ -686,6 +761,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); -@@ -694,22 +770,23 @@ static errcode_t write_directory(e2fsck_t ctx, ext2_filsys fs, - if (wd.err) - return wd.err; - -- e2fsck_read_inode(ctx, ino, &inode, "rehash_dir"); -+ e2fsck_read_inode(ctx, ino, inode, "rehash_dir"); - if (compress) -- inode.i_flags &= ~EXT2_INDEX_FL; -+ inode->i_flags &= ~EXT2_INDEX_FL; - else -- inode.i_flags |= EXT2_INDEX_FL; -- retval = ext2fs_inode_size_set(fs, &inode, -+ inode->i_flags |= EXT2_INDEX_FL; -+ retval = ext2fs_inode_size_set(fs, inode, - outdir->num * fs->blocksize); - if (retval) - return retval; -- ext2fs_iblk_sub_blocks(fs, &inode, wd.cleared); -- e2fsck_write_inode(ctx, ino, &inode, "rehash_dir"); -+ ext2fs_iblk_sub_blocks(fs, inode, wd.cleared); -+ e2fsck_write_inode(ctx, ino, inode, "rehash_dir"); - - return 0; - } - --errcode_t e2fsck_rehash_dir(e2fsck_t ctx, ext2_ino_t ino) -+errcode_t e2fsck_rehash_dir(e2fsck_t ctx, ext2_ino_t ino, -+ struct problem_context *pctx) - { - ext2_filsys fs = ctx->fs; - errcode_t retval; -@@ -723,6 +800,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); -@@ -738,9 +820,11 @@ errcode_t e2fsck_rehash_dir(e2fsck_t ctx, ext2_ino_t ino) - fd.ctx = ctx; - fd.buf = dir_buf; - fd.inode = &inode; -+ fd.ino = 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; -@@ -813,10 +897,14 @@ resort: - goto errout; - } - -- retval = write_directory(ctx, fs, &outdir, ino, fd.compress); -+ retval = write_directory(ctx, fs, &outdir, ino, &inode, fd.compress); - if (retval) - goto errout; - -+ if (ctx->options & E2F_OPT_CONVERT_BMAP) -+ retval = e2fsck_rebuild_extents_later(ctx, ino); -+ else -+ retval = e2fsck_check_rebuild_extents(ctx, ino, &inode, pctx); - errout: - free(dir_buf); - free(fd.harray); -@@ -844,7 +932,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 +960,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); -@@ -882,7 +969,7 @@ void e2fsck_rehash_directories(e2fsck_t ctx) - #if 0 - fix_problem(ctx, PR_3A_OPTIMIZE_DIR, &pctx); - #endif -- pctx.errcode = e2fsck_rehash_dir(ctx, ino); -+ pctx.errcode = e2fsck_rehash_dir(ctx, ino, &pctx); - if (pctx.errcode) { - end_problem_latch(ctx, PR_LATCH_OPTIMIZE_DIR); - fix_problem(ctx, PR_3A_OPTIMIZE_DIR_ERR, &pctx); -diff --git a/e2fsck/revoke.c b/e2fsck/revoke.c -index 38c265e..0543099 100644 ---- a/e2fsck/revoke.c -+++ b/e2fsck/revoke.c -@@ -1,5 +1,5 @@ - /* -- * linux/fs/revoke.c -+ * linux/fs/jbd2/revoke.c - * - * Written by Stephen C. Tweedie , 2000 - * -@@ -47,6 +47,10 @@ - * overwriting the new data. We don't even need to clear the revoke - * bit here. - * -+ * We cache revoke status of a buffer in the current transaction in b_states -+ * bits. As the name says, revokevalid flag indicates that the cached revoke -+ * status of a buffer is valid and we can rely on the cached status. -+ * - * Revoke information on buffers is a tri-state value: - * - * RevokeValid clear: no cached revoke status, need to look it up -@@ -55,40 +59,58 @@ - * need do nothing. - * RevokeValid set, Revoked set: - * buffer has been revoked. -+ * -+ * Locking rules: -+ * We keep two hash tables of revoke records. One hashtable belongs to the -+ * running transaction (is pointed to by journal->j_revoke), the other one -+ * belongs to the committing transaction. Accesses to the second hash table -+ * happen only from the kjournald and no other thread touches this table. Also -+ * journal_switch_revoke_table() which switches which hashtable belongs to the -+ * running and which to the committing transaction is called only from -+ * kjournald. Therefore we need no locks when accessing the hashtable belonging -+ * to the committing transaction. -+ * -+ * All users operating on the hash table belonging to the running transaction -+ * have a handle to the transaction. Therefore they are safe from kjournald -+ * switching hash tables under them. For operations on the lists of entries in -+ * the hash table j_revoke_lock is used. -+ * -+ * Finally, also replay code uses the hash tables but at this moment no one else -+ * can touch them (filesystem isn't mounted yet) and hence no locking is -+ * needed. - */ - - #ifndef __KERNEL__ --#include "config.h" - #include "jfs_user.h" - #else --#include -+#include - #include --#include -+#include - #include - #include --#include - #include --#include - #include -+#include -+#include - #endif - --static lkmem_cache_t *revoke_record_cache; --static lkmem_cache_t *revoke_table_cache; -+static lkmem_cache_t *jbd2_revoke_record_cache; -+static lkmem_cache_t *jbd2_revoke_table_cache; - - /* Each revoke record represents one single revoked block. During - journal replay, this involves recording the transaction ID of the - last transaction to revoke this block. */ - --struct jbd_revoke_record_s -+struct jbd2_revoke_record_s - { - struct list_head hash; - tid_t sequence; /* Used for recovery only */ -- unsigned long blocknr; -+ unsigned long long blocknr; - }; - - - /* The revoke table is just a simple hash table of revoke records. */ --struct jbd_revoke_table_s -+struct jbd2_revoke_table_s - { - /* It is conceivable that we might want a larger hash table - * for recovery. Must be a power of two. */ -@@ -100,159 +122,187 @@ struct jbd_revoke_table_s - - #ifdef __KERNEL__ - static void write_one_revoke_record(journal_t *, transaction_t *, -- struct journal_head **, int *, -- struct jbd_revoke_record_s *); --static void flush_descriptor(journal_t *, struct journal_head *, int); -+ struct list_head *, -+ struct buffer_head **, int *, -+ struct jbd2_revoke_record_s *, int); -+static void flush_descriptor(journal_t *, struct buffer_head *, int, int); - #endif - - /* Utility functions to maintain the revoke table */ - - /* Borrowed from buffer.c: this is a tried and tested block hash function */ --static inline int hash(journal_t *journal, unsigned long block) -+static inline int hash(journal_t *journal, unsigned long long block) - { -- struct jbd_revoke_table_s *table = journal->j_revoke; -+ struct jbd2_revoke_table_s *table = journal->j_revoke; - int hash_shift = table->hash_shift; -+ int hash = (int)block ^ (int)((block >> 31) >> 1); - -- return ((block << (hash_shift - 6)) ^ -- (block >> 13) ^ -- (block << (hash_shift - 12))) & (table->hash_size - 1); -+ return ((hash << (hash_shift - 6)) ^ -+ (hash >> 13) ^ -+ (hash << (hash_shift - 12))) & (table->hash_size - 1); - } - --static int insert_revoke_hash(journal_t *journal, unsigned long blocknr, -+static int insert_revoke_hash(journal_t *journal, unsigned long long blocknr, - tid_t seq) - { - struct list_head *hash_list; -- struct jbd_revoke_record_s *record; -+ struct jbd2_revoke_record_s *record; - --#ifdef __KERNEL__ - repeat: --#endif -- record = kmem_cache_alloc(revoke_record_cache, GFP_NOFS); -+ record = kmem_cache_alloc(jbd2_revoke_record_cache, GFP_NOFS); - if (!record) - goto oom; - - record->sequence = seq; - record->blocknr = blocknr; - hash_list = &journal->j_revoke->hash_table[hash(journal, blocknr)]; -+ spin_lock(&journal->j_revoke_lock); - list_add(&record->hash, hash_list); -+ spin_unlock(&journal->j_revoke_lock); - return 0; - - oom: --#ifdef __KERNEL__ - if (!journal_oom_retry) - return -ENOMEM; -- jbd_debug(1, "ENOMEM in " __FUNCTION__ ", retrying.\n"); -- current->policy |= SCHED_YIELD; -- schedule(); -+ jbd_debug(1, "ENOMEM in %s, retrying\n", __func__); -+ yield(); - goto repeat; --#else -- return -ENOMEM; --#endif - } - - /* Find a revoke record in the journal's hash table. */ - --static struct jbd_revoke_record_s *find_revoke_record(journal_t *journal, -- unsigned long blocknr) -+static struct jbd2_revoke_record_s *find_revoke_record(journal_t *journal, -+ unsigned long long blocknr) - { - struct list_head *hash_list; -- struct jbd_revoke_record_s *record; -+ struct jbd2_revoke_record_s *record; - - hash_list = &journal->j_revoke->hash_table[hash(journal, blocknr)]; - -- record = (struct jbd_revoke_record_s *) hash_list->next; -+ spin_lock(&journal->j_revoke_lock); -+ record = (struct jbd2_revoke_record_s *) hash_list->next; - while (&(record->hash) != hash_list) { -- if (record->blocknr == blocknr) -+ if (record->blocknr == blocknr) { -+ spin_unlock(&journal->j_revoke_lock); - return record; -- record = (struct jbd_revoke_record_s *) record->hash.next; -+ } -+ record = (struct jbd2_revoke_record_s *) record->hash.next; - } -+ spin_unlock(&journal->j_revoke_lock); - return NULL; - } - --int __init journal_init_revoke_caches(void) -+void journal_destroy_revoke_caches(void) - { -- revoke_record_cache = kmem_cache_create("revoke_record", -- sizeof(struct jbd_revoke_record_s), -- 0, SLAB_HWCACHE_ALIGN, NULL, NULL); -- if (revoke_record_cache == 0) -- return -ENOMEM; -- -- revoke_table_cache = kmem_cache_create("revoke_table", -- sizeof(struct jbd_revoke_table_s), -- 0, 0, NULL, NULL); -- if (revoke_table_cache == 0) { -- kmem_cache_destroy(revoke_record_cache); -- revoke_record_cache = NULL; -- return -ENOMEM; -+ if (jbd2_revoke_record_cache) { -+ kmem_cache_destroy(jbd2_revoke_record_cache); -+ jbd2_revoke_record_cache = NULL; -+ } -+ if (jbd2_revoke_table_cache) { -+ kmem_cache_destroy(jbd2_revoke_table_cache); -+ jbd2_revoke_table_cache = NULL; - } -- return 0; - } - --void journal_destroy_revoke_caches(void) -+int __init journal_init_revoke_caches(void) - { -- kmem_cache_destroy(revoke_record_cache); -- revoke_record_cache = 0; -- kmem_cache_destroy(revoke_table_cache); -- revoke_table_cache = 0; -+ J_ASSERT(!jbd2_revoke_record_cache); -+ J_ASSERT(!jbd2_revoke_table_cache); -+ -+ jbd2_revoke_record_cache = KMEM_CACHE(jbd2_revoke_record_s, -+ SLAB_HWCACHE_ALIGN|SLAB_TEMPORARY); -+ if (!jbd2_revoke_record_cache) -+ goto record_cache_failure; -+ -+ jbd2_revoke_table_cache = KMEM_CACHE(jbd2_revoke_table_s, -+ SLAB_TEMPORARY); -+ if (!jbd2_revoke_table_cache) -+ goto table_cache_failure; -+ return 0; -+table_cache_failure: -+ journal_destroy_revoke_caches(); -+record_cache_failure: -+ return -ENOMEM; - } - --/* Initialise the revoke table for a given journal to a given size. */ -- --int journal_init_revoke(journal_t *journal, int hash_size) -+static struct jbd2_revoke_table_s *journal_init_revoke_table(int hash_size) - { -- int shift, tmp; -- -- J_ASSERT (journal->j_revoke == NULL); -- -- journal->j_revoke = kmem_cache_alloc(revoke_table_cache, GFP_KERNEL); -- if (!journal->j_revoke) -- return -ENOMEM; -- -- /* Check that the hash_size is a power of two */ -- J_ASSERT ((hash_size & (hash_size-1)) == 0); -+ int shift = 0; -+ int tmp = hash_size; -+ struct jbd2_revoke_table_s *table; - -- journal->j_revoke->hash_size = hash_size; -+ table = kmem_cache_alloc(jbd2_revoke_table_cache, GFP_KERNEL); -+ if (!table) -+ goto out; - -- shift = 0; -- tmp = hash_size; - while((tmp >>= 1UL) != 0UL) - shift++; -- journal->j_revoke->hash_shift = shift; - -- journal->j_revoke->hash_table = -+ table->hash_size = hash_size; -+ table->hash_shift = shift; -+ table->hash_table = - kmalloc(hash_size * sizeof(struct list_head), GFP_KERNEL); -- if (!journal->j_revoke->hash_table) { -- kmem_cache_free(revoke_table_cache, journal->j_revoke); -- journal->j_revoke = NULL; -- return -ENOMEM; -+ if (!table->hash_table) { -+ kmem_cache_free(jbd2_revoke_table_cache, table); -+ table = NULL; -+ goto out; - } - - for (tmp = 0; tmp < hash_size; tmp++) -- INIT_LIST_HEAD(&journal->j_revoke->hash_table[tmp]); -+ INIT_LIST_HEAD(&table->hash_table[tmp]); - -- return 0; -+out: -+ return table; - } - --/* Destoy a journal's revoke table. The table must already be empty! */ -- --void journal_destroy_revoke(journal_t *journal) -+static void journal_destroy_revoke_table(struct jbd2_revoke_table_s *table) - { -- struct jbd_revoke_table_s *table; -- struct list_head *hash_list; - int i; -+ struct list_head *hash_list; - -- table = journal->j_revoke; -- if (!table) -- return; -- -- for (i=0; ihash_size; i++) { -+ for (i = 0; i < table->hash_size; i++) { - hash_list = &table->hash_table[i]; -- J_ASSERT (list_empty(hash_list)); -+ J_ASSERT(list_empty(hash_list)); - } - - kfree(table->hash_table); -- kmem_cache_free(revoke_table_cache, table); -+ kmem_cache_free(jbd2_revoke_table_cache, table); -+} -+ -+/* Initialise the revoke table for a given journal to a given size. */ -+int journal_init_revoke(journal_t *journal, int hash_size) -+{ -+ J_ASSERT(journal->j_revoke_table[0] == NULL); -+ J_ASSERT(is_power_of_2(hash_size)); -+ -+ journal->j_revoke_table[0] = journal_init_revoke_table(hash_size); -+ if (!journal->j_revoke_table[0]) -+ goto fail0; -+ -+ journal->j_revoke_table[1] = journal_init_revoke_table(hash_size); -+ if (!journal->j_revoke_table[1]) -+ goto fail1; -+ -+ journal->j_revoke = journal->j_revoke_table[1]; -+ -+ spin_lock_init(&journal->j_revoke_lock); -+ -+ return 0; -+ -+fail1: -+ journal_destroy_revoke_table(journal->j_revoke_table[0]); -+fail0: -+ return -ENOMEM; -+} -+ -+/* Destroy a journal's revoke table. The table must already be empty! */ -+void journal_destroy_revoke(journal_t *journal) -+{ - journal->j_revoke = NULL; -+ if (journal->j_revoke_table[0]) -+ journal_destroy_revoke_table(journal->j_revoke_table[0]); -+ if (journal->j_revoke_table[1]) -+ journal_destroy_revoke_table(journal->j_revoke_table[1]); - } - - -@@ -282,14 +332,15 @@ void journal_destroy_revoke(journal_t *journal) - * by one. - */ - --int journal_revoke(handle_t *handle, unsigned long blocknr, -+int journal_revoke(handle_t *handle, unsigned long long blocknr, - struct buffer_head *bh_in) - { - struct buffer_head *bh = NULL; - journal_t *journal; -- kdev_t dev; -+ struct block_device *bdev; - int err; - -+ might_sleep(); - if (bh_in) - BUFFER_TRACE(bh_in, "enter"); - -@@ -299,34 +350,32 @@ int journal_revoke(handle_t *handle, unsigned long blocknr, - return -EINVAL; - } - -- dev = journal->j_fs_dev; -+ bdev = journal->j_fs_dev; - bh = bh_in; - - if (!bh) { -- bh = get_hash_table(dev, blocknr, journal->j_blocksize); -+ bh = __find_get_block(bdev, blocknr, journal->j_blocksize); - if (bh) - BUFFER_TRACE(bh, "found on hash"); - } --#ifdef JBD_EXPENSIVE_CHECKING -+#ifdef JFS_EXPENSIVE_CHECKING - else { - struct buffer_head *bh2; - - /* If there is a different buffer_head lying around in - * memory anywhere... */ -- bh2 = get_hash_table(dev, blocknr, journal->j_blocksize); -+ bh2 = __find_get_block(bdev, blocknr, journal->j_blocksize); - if (bh2) { - /* ... and it has RevokeValid status... */ -- if ((bh2 != bh) && -- test_bit(BH_RevokeValid, &bh2->b_state)) -+ if (bh2 != bh && buffer_revokevalid(bh2)) - /* ...then it better be revoked too, - * since it's illegal to create a revoke - * record against a buffer_head which is - * not marked revoked --- that would - * risk missing a subsequent revoke - * cancel. */ -- J_ASSERT_BH(bh2, test_bit(BH_Revoked, & -- bh2->b_state)); -- __brelse(bh2); -+ J_ASSERT_BH(bh2, buffer_revoked(bh2)); -+ put_bh(bh2); - } - } - #endif -@@ -335,9 +384,14 @@ int journal_revoke(handle_t *handle, unsigned long blocknr, - first having the revoke cancelled: it's illegal to free a - block twice without allocating it in between! */ - if (bh) { -- J_ASSERT_BH(bh, !test_bit(BH_Revoked, &bh->b_state)); -- set_bit(BH_Revoked, &bh->b_state); -- set_bit(BH_RevokeValid, &bh->b_state); -+ if (!J_EXPECT_BH(bh, !buffer_revoked(bh), -+ "inconsistent data on disk")) { -+ if (!bh_in) -+ brelse(bh); -+ return -EIO; -+ } -+ set_buffer_revoked(bh); -+ set_buffer_revokevalid(bh); - if (bh_in) { - BUFFER_TRACE(bh_in, "call journal_forget"); - journal_forget(handle, bh_in); -@@ -347,11 +401,9 @@ int journal_revoke(handle_t *handle, unsigned long blocknr, - } - } - -- lock_journal(journal); -- jbd_debug(2, "insert revoke for block %lu, bh_in=%p\n", blocknr, bh_in); -+ jbd_debug(2, "insert revoke for block %llu, bh_in=%p\n",blocknr, bh_in); - err = insert_revoke_hash(journal, blocknr, - handle->h_transaction->t_tid); -- unlock_journal(journal); - BUFFER_TRACE(bh_in, "exit"); - return err; - } -@@ -360,7 +412,7 @@ int journal_revoke(handle_t *handle, unsigned long blocknr, - * Cancel an outstanding revoke. For use only internally by the - * journaling code (called from journal_get_write_access). - * -- * We trust the BH_Revoked bit on the buffer if the buffer is already -+ * We trust buffer_revoked() on the buffer if the buffer is already - * being journaled: if there is no revoke pending on the buffer, then we - * don't do anything here. - * -@@ -370,12 +422,10 @@ int journal_revoke(handle_t *handle, unsigned long blocknr, - * the second time we would still have a pending revoke to cancel. So, - * do not trust the Revoked bit on buffers unless RevokeValid is also - * set. -- * -- * The caller must have the journal locked. - */ - int journal_cancel_revoke(handle_t *handle, struct journal_head *jh) - { -- struct jbd_revoke_record_s *record; -+ struct jbd2_revoke_record_s *record; - journal_t *journal = handle->h_transaction->t_journal; - int need_cancel; - int did_revoke = 0; /* akpm: debug */ -@@ -387,25 +437,27 @@ int journal_cancel_revoke(handle_t *handle, struct journal_head *jh) - * only perform the full cancel if the revoke bit is set. If - * not, we can't trust the revoke bit, and we need to do the - * full search for a revoke record. */ -- if (test_and_set_bit(BH_RevokeValid, &bh->b_state)) -- need_cancel = (test_and_clear_bit(BH_Revoked, &bh->b_state)); -- else { -+ if (test_set_buffer_revokevalid(bh)) { -+ need_cancel = test_clear_buffer_revoked(bh); -+ } else { - need_cancel = 1; -- clear_bit(BH_Revoked, &bh->b_state); -+ clear_buffer_revoked(bh); - } - - if (need_cancel) { - record = find_revoke_record(journal, bh->b_blocknr); - if (record) { - jbd_debug(4, "cancelled existing revoke on " -- "blocknr %lu\n", bh->b_blocknr); -+ "blocknr %llu\n", (unsigned long long)bh->b_blocknr); -+ spin_lock(&journal->j_revoke_lock); - list_del(&record->hash); -- kmem_cache_free(revoke_record_cache, record); -+ spin_unlock(&journal->j_revoke_lock); -+ kmem_cache_free(jbd2_revoke_record_cache, record); - did_revoke = 1; - } - } - --#ifdef JBD_EXPENSIVE_CHECKING -+#ifdef JFS_EXPENSIVE_CHECKING - /* There better not be one left behind by now! */ - record = find_revoke_record(journal, bh->b_blocknr); - J_ASSERT_JH(jh, record == NULL); -@@ -415,56 +467,104 @@ int journal_cancel_revoke(handle_t *handle, struct journal_head *jh) - * buffer_head? If so, we'd better make sure we clear the - * revoked status on any hashed alias too, otherwise the revoke - * state machine will get very upset later on. */ -- if (need_cancel && !bh->b_pprev) { -+ if (need_cancel) { - struct buffer_head *bh2; -- bh2 = get_hash_table(bh->b_dev, bh->b_blocknr, bh->b_size); -+ bh2 = __find_get_block(bh->b_bdev, bh->b_blocknr, bh->b_size); - if (bh2) { -- clear_bit(BH_Revoked, &bh2->b_state); -+ if (bh2 != bh) -+ clear_buffer_revoked(bh2); - __brelse(bh2); - } - } -- - return did_revoke; - } - -+/* -+ * journal_clear_revoked_flag clears revoked flag of buffers in -+ * revoke table to reflect there is no revoked buffers in the next -+ * transaction which is going to be started. -+ */ -+void jbd2_clear_buffer_revoked_flags(journal_t *journal) -+{ -+ struct jbd2_revoke_table_s *revoke = journal->j_revoke; -+ int i = 0; -+ -+ for (i = 0; i < revoke->hash_size; i++) { -+ struct list_head *hash_list; -+ struct list_head *list_entry; -+ hash_list = &revoke->hash_table[i]; -+ -+ list_for_each(list_entry, hash_list) { -+ struct jbd2_revoke_record_s *record; -+ struct buffer_head *bh; -+ record = (struct jbd2_revoke_record_s *)list_entry; -+ bh = __find_get_block(journal->j_fs_dev, -+ record->blocknr, -+ journal->j_blocksize); -+ if (bh) { -+ clear_buffer_revoked(bh); -+ __brelse(bh); -+ } -+ } -+ } -+} -+ -+/* journal_switch_revoke table select j_revoke for next transaction -+ * we do not want to suspend any processing until all revokes are -+ * written -bzzz -+ */ -+void journal_switch_revoke_table(journal_t *journal) -+{ -+ int i; -+ -+ if (journal->j_revoke == journal->j_revoke_table[0]) -+ journal->j_revoke = journal->j_revoke_table[1]; -+ else -+ journal->j_revoke = journal->j_revoke_table[0]; -+ -+ for (i = 0; i < journal->j_revoke->hash_size; i++) -+ INIT_LIST_HEAD(&journal->j_revoke->hash_table[i]); -+} - - /* - * Write revoke records to the journal for all entries in the current - * revoke hash, deleting the entries as we go. -- * -- * Called with the journal lock held. - */ -- - void journal_write_revoke_records(journal_t *journal, -- transaction_t *transaction) -+ transaction_t *transaction, -+ struct list_head *log_bufs, -+ int write_op) - { -- struct journal_head *descriptor; -- struct jbd_revoke_record_s *record; -- struct jbd_revoke_table_s *revoke; -+ struct buffer_head *descriptor; -+ struct jbd2_revoke_record_s *record; -+ struct jbd2_revoke_table_s *revoke; - struct list_head *hash_list; - int i, offset, count; - - descriptor = NULL; - offset = 0; - count = 0; -- revoke = journal->j_revoke; -+ -+ /* select revoke table for committing transaction */ -+ revoke = journal->j_revoke == journal->j_revoke_table[0] ? -+ journal->j_revoke_table[1] : journal->j_revoke_table[0]; - - for (i = 0; i < revoke->hash_size; i++) { - hash_list = &revoke->hash_table[i]; - - while (!list_empty(hash_list)) { -- record = (struct jbd_revoke_record_s *) -+ record = (struct jbd2_revoke_record_s *) - hash_list->next; -- write_one_revoke_record(journal, transaction, -+ write_one_revoke_record(journal, transaction, log_bufs, - &descriptor, &offset, -- record); -+ record, write_op); - count++; - list_del(&record->hash); -- kmem_cache_free(revoke_record_cache, record); -+ kmem_cache_free(jbd2_revoke_record_cache, record); - } - } - if (descriptor) -- flush_descriptor(journal, descriptor, offset); -+ flush_descriptor(journal, descriptor, offset, write_op); - jbd_debug(1, "Wrote %d revoke records\n", count); - } - -@@ -475,12 +575,15 @@ void journal_write_revoke_records(journal_t *journal, - - static void write_one_revoke_record(journal_t *journal, - transaction_t *transaction, -- struct journal_head **descriptorp, -+ struct list_head *log_bufs, -+ struct buffer_head **descriptorp, - int *offsetp, -- struct jbd_revoke_record_s *record) -+ struct jbd2_revoke_record_s *record, -+ int write_op) - { -- struct journal_head *descriptor; -- int offset; -+ int csum_size = 0; -+ struct buffer_head *descriptor; -+ int sz, offset; - journal_header_t *header; - - /* If we are already aborting, this all becomes a noop. We -@@ -493,10 +596,19 @@ static void write_one_revoke_record(journal_t *journal, - descriptor = *descriptorp; - offset = *offsetp; - -+ /* Do we need to leave space at the end for a checksum? */ -+ if (journal_has_csum_v2or3(journal)) -+ csum_size = sizeof(struct journal_revoke_tail); -+ -+ if (JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_64BIT)) -+ sz = 8; -+ else -+ sz = 4; -+ - /* Make sure we have a descriptor with space left for the record */ - if (descriptor) { -- if (offset == journal->j_blocksize) { -- flush_descriptor(journal, descriptor, offset); -+ if (offset + sz > journal->j_blocksize - csum_size) { -+ flush_descriptor(journal, descriptor, offset, write_op); - descriptor = NULL; - } - } -@@ -505,25 +617,45 @@ static void write_one_revoke_record(journal_t *journal, - descriptor = journal_get_descriptor_buffer(journal); - if (!descriptor) - return; -- header = (journal_header_t *) &jh2bh(descriptor)->b_data[0]; -- header->h_magic = htonl(JFS_MAGIC_NUMBER); -- header->h_blocktype = htonl(JFS_REVOKE_BLOCK); -- header->h_sequence = htonl(transaction->t_tid); -+ header = (journal_header_t *)descriptor->b_data; -+ header->h_magic = ext2fs_cpu_to_be32(JFS_MAGIC_NUMBER); -+ header->h_blocktype = ext2fs_cpu_to_be32(JFS_REVOKE_BLOCK); -+ header->h_sequence = ext2fs_cpu_to_be32(transaction->t_tid); - - /* Record it so that we can wait for IO completion later */ -- JBUFFER_TRACE(descriptor, "file as BJ_LogCtl"); -- journal_file_buffer(descriptor, transaction, BJ_LogCtl); -+ BUFFER_TRACE(descriptor, "file in log_bufs"); -+ jbd2_file_log_bh(log_bufs, descriptor); - - offset = sizeof(journal_revoke_header_t); - *descriptorp = descriptor; - } - -- * ((unsigned int *)(&jh2bh(descriptor)->b_data[offset])) = -- htonl(record->blocknr); -- offset += 4; -+ if (JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_64BIT)) { -+ * ((__be64 *)(&descriptor->b_data[offset])) = -+ cpu_to_be64(record->blocknr); -+ else -+ * ((__be32 *)(&descriptor->b_data[offset])) = -+ cpu_to_be32(record->blocknr); -+ offset += sz; -+ - *offsetp = offset; - } - -+static void jbd2_revoke_csum_set(journal_t *j, struct buffer_head *bh) -+{ -+ struct journal_revoke_tail *tail; -+ __u32 csum; -+ -+ if (!journal_has_csum_v2or3(j)) -+ return; -+ -+ tail = (struct journal_revoke_tail *)(bh->b_data + j->j_blocksize - -+ sizeof(struct journal_revoke_tail)); -+ tail->r_checksum = 0; -+ csum = jbd2_chksum(j, j->j_csum_seed, bh->b_data, j->j_blocksize); -+ tail->r_checksum = ext2fs_cpu_to_be32(csum); -+} -+ - /* - * Flush a revoke descriptor out to the journal. If we are aborting, - * this is a noop; otherwise we are generating a buffer which needs to -@@ -532,27 +664,25 @@ static void write_one_revoke_record(journal_t *journal, - */ - - static void flush_descriptor(journal_t *journal, -- struct journal_head *descriptor, -- int offset) -+ struct buffer_head *descriptor, -+ int offset, int write_op) - { - journal_revoke_header_t *header; - - if (is_journal_aborted(journal)) { -- JBUFFER_TRACE(descriptor, "brelse"); -- __brelse(jh2bh(descriptor)); -+ put_bh(descriptor); - return; - } - -- header = (journal_revoke_header_t *) jh2bh(descriptor)->b_data; -- header->r_count = htonl(offset); -- set_bit(BH_JWrite, &jh2bh(descriptor)->b_state); -- { -- struct buffer_head *bh = jh2bh(descriptor); -- BUFFER_TRACE(bh, "write"); -- ll_rw_block (WRITE, 1, &bh); -- } --} -+ header = (journal_revoke_header_t *)descriptor->b_data; -+ header->r_count = ext2fs_cpu_to_be32(offset); -+ jbd2_revoke_csum_set(journal, descriptor); - -+ set_buffer_jwrite(descriptor); -+ BUFFER_TRACE(descriptor, "write"); -+ set_buffer_dirty(descriptor); -+ write_dirty_buffer(descriptor, write_op); -+} - #endif - - /* -@@ -578,14 +708,14 @@ static void flush_descriptor(journal_t *journal, - */ - - int journal_set_revoke(journal_t *journal, -- unsigned long blocknr, -+ unsigned long long blocknr, - tid_t sequence) - { -- struct jbd_revoke_record_s *record; -+ struct jbd2_revoke_record_s *record; - - record = find_revoke_record(journal, blocknr); - if (record) { -- /* If we have multiple occurences, only record the -+ /* If we have multiple occurrences, only record the - * latest sequence number in the hashed record */ - if (tid_gt(sequence, record->sequence)) - record->sequence = sequence; -@@ -602,10 +732,10 @@ int journal_set_revoke(journal_t *journal, - */ - - int journal_test_revoke(journal_t *journal, -- unsigned long blocknr, -+ unsigned long long blocknr, - tid_t sequence) - { -- struct jbd_revoke_record_s *record; -+ struct jbd2_revoke_record_s *record; - - record = find_revoke_record(journal, blocknr); - if (!record) -@@ -624,18 +754,17 @@ void journal_clear_revoke(journal_t *journal) - { - int i; - struct list_head *hash_list; -- struct jbd_revoke_record_s *record; -- struct jbd_revoke_table_s *revoke; -+ struct jbd2_revoke_record_s *record; -+ struct jbd2_revoke_table_s *revoke; - - revoke = journal->j_revoke; - - for (i = 0; i < revoke->hash_size; i++) { - hash_list = &revoke->hash_table[i]; - while (!list_empty(hash_list)) { -- record = (struct jbd_revoke_record_s*) hash_list->next; -+ record = (struct jbd2_revoke_record_s*) hash_list->next; - list_del(&record->hash); -- kmem_cache_free(revoke_record_cache, record); -+ kmem_cache_free(jbd2_revoke_record_cache, record); - } - } - } -- -diff --git a/e2fsck/sigcatcher.c b/e2fsck/sigcatcher.c -index e4d60ce..a9d3b7f 100644 ---- a/e2fsck/sigcatcher.c -+++ b/e2fsck/sigcatcher.c -@@ -334,8 +334,6 @@ static const char *lookup_table_fallback(int num, struct str_table *table) - static void die_signal_handler(int signum, siginfo_t *siginfo, - void *context EXT2FS_ATTR((unused))) - { -- void *stack_syms[32]; -- int frames; - const char *cp; - - fprintf(stderr, "Signal (%d) %s ", signum, -@@ -374,8 +372,13 @@ static void die_signal_handler(int signum, siginfo_t *siginfo, - fprintf(stderr, "\n"); - - #if defined(HAVE_BACKTRACE) && !defined(DISABLE_BACKTRACE) -- frames = backtrace(stack_syms, 32); -- backtrace_symbols_fd(stack_syms, frames, 2); -+ { -+ void *stack_syms[32]; -+ int frames; -+ -+ frames = backtrace(stack_syms, 32); -+ backtrace_symbols_fd(stack_syms, frames, 2); -+ } - #endif - exit(FSCK_ERROR); - } -@@ -392,6 +395,7 @@ void sigcatcher_setup(void) - sigaction(SIGILL, &sa, 0); - sigaction(SIGBUS, &sa, 0); - sigaction(SIGSEGV, &sa, 0); -+ sigaction(SIGABRT, &sa, 0); - } - - -diff --git a/e2fsck/super.c b/e2fsck/super.c -index 768316a..397ad0f 100644 ---- a/e2fsck/super.c -+++ b/e2fsck/super.c -@@ -76,7 +76,7 @@ static int release_inode_block(ext2_filsys fs, - pctx->blk = blk; - pctx->blkcount = blockcnt; - -- if (HOLE_BLKADDR(blk)) -+ if (blk == 0) - return 0; - - if ((blk < fs->super->s_first_data_block) || -@@ -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) && -@@ -591,6 +606,13 @@ void check_super_block(e2fsck_t ctx) - ext2fs_mark_super_dirty(fs); - } - -+ /* Did user ask us to convert files to extents? */ -+ if (ctx->options & E2F_OPT_CONVERT_BMAP) { -+ fs->super->s_feature_incompat |= -+ EXT3_FEATURE_INCOMPAT_EXTENTS; -+ ext2fs_mark_super_dirty(fs); -+ } -+ - if ((fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_META_BG) && - (fs->super->s_first_meta_bg > fs->desc_blocks)) { - pctx.group = fs->desc_blocks; -@@ -609,8 +631,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 +762,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; - } -diff --git a/e2fsck/unix.c b/e2fsck/unix.c -index 10036e7..9d49a0e 100644 ---- a/e2fsck/unix.c -+++ b/e2fsck/unix.c -@@ -45,10 +45,12 @@ extern int optind; - #ifdef HAVE_DIRENT_H - #include - #endif -+#include - - #include "e2p/e2p.h" - #include "et/com_err.h" - #include "e2p/e2p.h" -+#include "support/plausible.h" - #include "e2fsck.h" - #include "problem.h" - #include "../version.h" -@@ -74,7 +76,7 @@ static void usage(e2fsck_t ctx) - _("Usage: %s [-panyrcdfvtDFV] [-b superblock] [-B blocksize]\n" - "\t\t[-I inode_buffer_blocks] [-P process_inode_size]\n" - "\t\t[-l|-L bad_blocks_file] [-C fd] [-j external_journal]\n" -- "\t\t[-E extended-options] device\n"), -+ "\t\t[-E extended-options] [-z undo_file] device\n"), - ctx->program_name); - - fprintf(stderr, "%s", _("\nEmergency help:\n" -@@ -90,6 +92,7 @@ static void usage(e2fsck_t ctx) - " -j external_journal Set location of the external journal\n" - " -l bad_blocks_file Add to badblocks list\n" - " -L bad_blocks_file Set badblocks list\n" -+ " -z undo_file Create an undo file\n" - )); - - exit(FSCK_USAGE); -@@ -649,6 +652,7 @@ static void parse_extended_opts(e2fsck_t ctx, const char *opts) - char *buf, *token, *next, *p, *arg; - int ea_ver; - int extended_usage = 0; -+ unsigned long long reada_kb; - - buf = string_copy(ctx, opts, 0); - for (token = buf; token && *token; token = next) { -@@ -677,6 +681,19 @@ static void parse_extended_opts(e2fsck_t ctx, const char *opts) - continue; - } - ctx->ext_attr_ver = ea_ver; -+ } else if (strcmp(token, "readahead_kb") == 0) { -+ if (!arg) { -+ extended_usage++; -+ continue; -+ } -+ reada_kb = strtoull(arg, &p, 0); -+ if (*p) { -+ fprintf(stderr, "%s", -+ _("Invalid readahead buffer size.\n")); -+ extended_usage++; -+ continue; -+ } -+ ctx->readahead_kb = reada_kb; - } else if (strcmp(token, "fragcheck") == 0) { - ctx->options |= E2F_OPT_FRAGCHECK; - continue; -@@ -698,6 +715,12 @@ static void parse_extended_opts(e2fsck_t ctx, const char *opts) - else - ctx->log_fn = string_copy(ctx, arg, 0); - continue; -+ } else if (strcmp(token, "bmap2extent") == 0) { -+ ctx->options |= E2F_OPT_CONVERT_BMAP; -+ continue; -+ } else if (strcmp(token, "fixes_only") == 0) { -+ ctx->options |= E2F_OPT_FIXES_ONLY; -+ continue; - } else { - fprintf(stderr, _("Unknown extended option: %s\n"), - token); -@@ -716,6 +739,8 @@ static void parse_extended_opts(e2fsck_t ctx, const char *opts) - fputs(("\tjournal_only\n"), stderr); - fputs(("\tdiscard\n"), stderr); - fputs(("\tnodiscard\n"), stderr); -+ fputs(("\treadahead_kb=\n"), stderr); -+ fputs(("\tbmap2extent\n"), stderr); - fputc('\n', stderr); - exit(1); - } -@@ -749,6 +774,7 @@ static errcode_t PRS(int argc, char *argv[], e2fsck_t *ret_ctx) - #ifdef CONFIG_JBD_DEBUG - char *jbd_debug; - #endif -+ unsigned long long phys_mem_kb; - - retval = e2fsck_allocate_context(&ctx); - if (retval) -@@ -759,7 +785,7 @@ static errcode_t PRS(int argc, char *argv[], e2fsck_t *ret_ctx) - - setvbuf(stdout, NULL, _IONBF, BUFSIZ); - setvbuf(stderr, NULL, _IONBF, BUFSIZ); -- if (isatty(0) && isatty(1)) { -+ if (getenv("E2FSCK_FORCE_INTERACTIVE") || (isatty(0) && isatty(1))) { - ctx->interactive = 1; - } else { - ctx->start_meta[0] = '\001'; -@@ -776,7 +802,9 @@ static errcode_t PRS(int argc, char *argv[], e2fsck_t *ret_ctx) - else - ctx->program_name = "e2fsck"; - -- while ((c = getopt (argc, argv, "panyrcC:B:dE:fvtFVM:b:I:j:P:l:L:N:SsDk")) != EOF) -+ phys_mem_kb = get_memory_size() / 1024; -+ ctx->readahead_kb = ~0ULL; -+ while ((c = getopt(argc, argv, "panyrcC:B:dE:fvtFVM:b:I:j:P:l:L:N:SsDkz:")) != EOF) - switch (c) { - case 'C': - ctx->progress = e2fsck_update_progress; -@@ -908,6 +936,9 @@ static errcode_t PRS(int argc, char *argv[], e2fsck_t *ret_ctx) - case 'k': - keep_bad_blocks++; - break; -+ case 'z': -+ ctx->undo_file = optarg; -+ break; - default: - usage(ctx); - } -@@ -946,6 +977,22 @@ static errcode_t PRS(int argc, char *argv[], e2fsck_t *ret_ctx) - if (extended_opts) - parse_extended_opts(ctx, extended_opts); - -+ /* Complain about mutually exclusive rebuilding activities */ -+ if (getenv("E2FSCK_FIXES_ONLY")) -+ ctx->options |= E2F_OPT_FIXES_ONLY; -+ if ((ctx->options & E2F_OPT_COMPRESS_DIRS) && -+ (ctx->options & E2F_OPT_FIXES_ONLY)) { -+ com_err(ctx->program_name, 0, "%s", -+ _("The -D and -E fixes_only options are incompatible.")); -+ fatal_error(ctx, 0); -+ } -+ if ((ctx->options & E2F_OPT_CONVERT_BMAP) && -+ (ctx->options & E2F_OPT_FIXES_ONLY)) { -+ com_err(ctx->program_name, 0, "%s", -+ _("The -E bmap2extent and fixes_only options are incompatible.")); -+ fatal_error(ctx, 0); -+ } -+ - if ((cp = getenv("E2FSCK_CONFIG")) != NULL) - config_fn[0] = cp; - profile_set_syntax_err_cb(syntax_err_report); -@@ -960,6 +1007,20 @@ static errcode_t PRS(int argc, char *argv[], e2fsck_t *ret_ctx) - if (c) - verbose = 1; - -+ if (ctx->readahead_kb == ~0ULL) { -+ profile_get_integer(ctx->profile, "options", -+ "readahead_mem_pct", 0, -1, &c); -+ if (c >= 0 && c <= 100) -+ ctx->readahead_kb = phys_mem_kb * c / 100; -+ profile_get_integer(ctx->profile, "options", -+ "readahead_kb", 0, -1, &c); -+ if (c >= 0) -+ ctx->readahead_kb = c; -+ if (ctx->readahead_kb != ~0ULL && -+ ctx->readahead_kb > phys_mem_kb) -+ ctx->readahead_kb = phys_mem_kb; -+ } -+ - /* Turn off discard in read-only mode */ - if ((ctx->options & E2F_OPT_NO) && - (ctx->options & E2F_OPT_DISCARD)) -@@ -1161,7 +1222,101 @@ 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; -+} -+ -+static int e2fsck_setup_tdb(e2fsck_t ctx, io_manager *io_ptr) -+{ -+ errcode_t retval = ENOMEM; -+ char *tdb_dir = NULL, *tdb_file = NULL; -+ char *dev_name, *tmp_name; -+ int free_tdb_dir = 0; -+ -+ /* (re)open a specific undo file */ -+ if (ctx->undo_file && ctx->undo_file[0] != 0) { -+ retval = set_undo_io_backing_manager(*io_ptr); -+ if (retval) -+ goto err; -+ *io_ptr = undo_io_manager; -+ retval = set_undo_io_backup_file(ctx->undo_file); -+ if (retval) -+ goto err; -+ printf(_("Overwriting existing filesystem; this can be undone " -+ "using the command:\n" -+ " e2undo %s %s\n\n"), -+ ctx->undo_file, ctx->filesystem_name); -+ return retval; - } -+ -+ /* -+ * Configuration via a conf file would be -+ * nice -+ */ -+ tdb_dir = getenv("E2FSPROGS_UNDO_DIR"); -+ if (!tdb_dir) { -+ profile_get_string(ctx->profile, "defaults", -+ "undo_dir", 0, "/var/lib/e2fsprogs", -+ &tdb_dir); -+ free_tdb_dir = 1; -+ } -+ -+ if (!strcmp(tdb_dir, "none") || (tdb_dir[0] == 0) || -+ access(tdb_dir, W_OK)) { -+ if (free_tdb_dir) -+ free(tdb_dir); -+ return 0; -+ } -+ -+ tmp_name = strdup(ctx->filesystem_name); -+ if (!tmp_name) -+ goto errout; -+ dev_name = basename(tmp_name); -+ tdb_file = malloc(strlen(tdb_dir) + 8 + strlen(dev_name) + 7 + 1); -+ if (!tdb_file) { -+ free(tmp_name); -+ goto errout; -+ } -+ sprintf(tdb_file, "%s/e2fsck-%s.e2undo", tdb_dir, dev_name); -+ free(tmp_name); -+ -+ if ((unlink(tdb_file) < 0) && (errno != ENOENT)) { -+ retval = errno; -+ com_err(ctx->program_name, retval, -+ _("while trying to delete %s"), tdb_file); -+ goto errout; -+ } -+ -+ retval = set_undo_io_backing_manager(*io_ptr); -+ if (retval) -+ goto errout; -+ *io_ptr = undo_io_manager; -+ retval = set_undo_io_backup_file(tdb_file); -+ if (retval) -+ goto errout; -+ printf(_("Overwriting existing filesystem; this can be undone " -+ "using the command:\n" -+ " e2undo %s %s\n\n"), tdb_file, ctx->filesystem_name); -+ -+ if (free_tdb_dir) -+ free(tdb_dir); -+ free(tdb_file); -+ return 0; -+ -+errout: -+ if (free_tdb_dir) -+ free(tdb_dir); -+ free(tdb_file); -+err: -+ com_err(ctx->program_name, retval, "%s", -+ _("while trying to setup undo file\n")); - return retval; - } - -@@ -1274,12 +1429,19 @@ restart: - flags &= ~EXT2_FLAG_EXCLUSIVE; - } - -+ if (ctx->undo_file) { -+ retval = e2fsck_setup_tdb(ctx, &io_ptr); -+ if (retval) -+ exit(FSCK_ERROR); -+ } -+ - ctx->openfs_flags = flags; - retval = try_open_fs(ctx, flags, io_ptr, &fs); - - 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) { -@@ -1374,8 +1536,12 @@ failure: - "-n option to do a read-only\n" - "check of the device.\n")); - #endif -- else -+ else { - fix_problem(ctx, PR_0_SB_CORRUPT, &pctx); -+ if (retval == EXT2_ET_BAD_MAGIC) -+ check_plausibility(ctx->filesystem_name, -+ CHECK_FS_EXIST, NULL); -+ } - fatal_error(ctx, 0); - } - /* -@@ -1474,12 +1640,14 @@ failure: - /* - * Make sure the ext3 superblock fields are consistent. - */ -- retval = e2fsck_check_ext3_journal(ctx); -- if (retval) { -- com_err(ctx->program_name, retval, -- _("while checking ext3 journal for %s"), -- ctx->device_name); -- fatal_error(ctx, 0); -+ if ((ctx->mount_flags & (EXT2_MF_MOUNTED | EXT2_MF_BUSY)) == 0) { -+ retval = e2fsck_check_ext3_journal(ctx); -+ if (retval) { -+ com_err(ctx->program_name, retval, -+ _("while checking ext3 journal for %s"), -+ ctx->device_name); -+ fatal_error(ctx, 0); -+ } - } - - /* -@@ -1544,20 +1712,6 @@ print_unsupp_features: - log_err(ctx, "\n"); - goto get_newer; - } --#ifdef ENABLE_COMPRESSION -- if (sb->s_feature_incompat & EXT2_FEATURE_INCOMPAT_COMPRESSION) -- log_err(ctx, _("%s: warning: compression support " -- "is experimental.\n"), -- ctx->program_name); --#endif --#ifndef ENABLE_HTREE -- if (sb->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX) { -- log_err(ctx, _("%s: e2fsck not compiled with HTREE support,\n\t" -- "but filesystem %s has HTREE directories.\n"), -- ctx->program_name, ctx->device_name); -- goto get_newer; -- } --#endif - - /* - * If the user specified a specific superblock, presumably the -@@ -1661,8 +1815,7 @@ print_unsupp_features: - } - log_out(ctx, "%s", _(" Done.\n")); - log_out(ctx, "%s", -- _("\n*** journal has been re-created - " -- "filesystem is now ext3 again ***\n")); -+ _("\n*** journal has been regenerated ***\n")); - } - } - no_journal: -diff --git a/e2fsck/util.c b/e2fsck/util.c -index fa529b4..9e217e6 100644 ---- a/e2fsck/util.c -+++ b/e2fsck/util.c -@@ -37,6 +37,10 @@ - #include - #endif - -+#ifdef HAVE_SYS_SYSCTL_H -+#include -+#endif -+ - #include "e2fsck.h" - - extern e2fsck_t e2fsck_global_ctx; /* Try your very best not to use this! */ -@@ -189,6 +193,10 @@ int ask_yn(e2fsck_t ctx, const char * string, int def) - const char *defstr; - const char *short_yes = _("yY"); - const char *short_no = _("nN"); -+ const char *short_yesall = _("aA"); -+ const char *yesall_prompt = _(" ('a' enables 'yes' to all) "); -+ const char *extra_prompt = ""; -+ static int yes_answers; - - #ifdef HAVE_TERMIOS_H - struct termios termios, tmp; -@@ -207,7 +215,16 @@ int ask_yn(e2fsck_t ctx, const char * string, int def) - defstr = _(_("")); - else - defstr = _(" (y/n)"); -- log_out(ctx, "%s%s? ", string, defstr); -+ /* -+ * If the user presses 'y' more than 8 (but less than 12) times in -+ * succession without pressing anything else, display a hint about -+ * yes-to-all mode. -+ */ -+ if (yes_answers > 12) -+ yes_answers = -1; -+ else if (yes_answers > 8) -+ extra_prompt = yesall_prompt; -+ log_out(ctx, "%s%s%s? ", string, extra_prompt, defstr); - while (1) { - fflush (stdout); - if ((c = read_a_char()) == EOF) -@@ -221,20 +238,31 @@ int ask_yn(e2fsck_t ctx, const char * string, int def) - longjmp(e2fsck_global_ctx->abort_loc, 1); - } - log_out(ctx, "%s", _("cancelled!\n")); -+ yes_answers = 0; - return 0; - } - if (strchr(short_yes, (char) c)) { - def = 1; -+ if (yes_answers >= 0) -+ yes_answers++; - break; -- } -- else if (strchr(short_no, (char) c)) { -+ } else if (strchr(short_no, (char) c)) { - def = 0; -+ yes_answers = -1; - break; -- } -- else if ((c == 27 || c == ' ' || c == '\n') && (def != -1)) -+ } else if (strchr(short_yesall, (char)c)) { -+ def = 2; -+ yes_answers = -1; -+ ctx->options |= E2F_OPT_YES; - break; -+ } else if ((c == 27 || c == ' ' || c == '\n') && (def != -1)) { -+ yes_answers = -1; -+ break; -+ } - } -- if (def) -+ if (def == 2) -+ log_out(ctx, "%s", _("yes to all\n")); -+ else if (def) - log_out(ctx, "%s", _("yes\n")); - else - log_out(ctx, "%s", _("no\n")); -@@ -267,6 +295,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 +307,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) { -@@ -603,59 +636,6 @@ int ext2_file_type(unsigned int mode) - return 0; - } - --#define STRIDE_LENGTH 8 --/* -- * Helper function which zeros out _num_ blocks starting at _blk_. In -- * case of an error, the details of the error is returned via _ret_blk_ -- * and _ret_count_ if they are non-NULL pointers. Returns 0 on -- * success, and an error code on an error. -- * -- * As a special case, if the first argument is NULL, then it will -- * attempt to free the static zeroizing buffer. (This is to keep -- * programs that check for memory leaks happy.) -- */ --errcode_t e2fsck_zero_blocks(ext2_filsys fs, blk_t blk, int num, -- blk_t *ret_blk, int *ret_count) --{ -- int j, count; -- static char *buf; -- errcode_t retval; -- -- /* If fs is null, clean up the static buffer and return */ -- if (!fs) { -- if (buf) { -- free(buf); -- buf = 0; -- } -- return 0; -- } -- /* Allocate the zeroizing buffer if necessary */ -- if (!buf) { -- buf = malloc(fs->blocksize * STRIDE_LENGTH); -- if (!buf) { -- com_err("malloc", ENOMEM, "%s", -- _("while allocating zeroizing buffer")); -- exit(1); -- } -- memset(buf, 0, fs->blocksize * STRIDE_LENGTH); -- } -- /* OK, do the write loop */ -- for (j = 0; j < num; j += STRIDE_LENGTH, blk += STRIDE_LENGTH) { -- count = num - j; -- if (count > STRIDE_LENGTH) -- count = STRIDE_LENGTH; -- retval = io_channel_write_blk64(fs->io, blk, count, buf); -- if (retval) { -- if (ret_count) -- *ret_count = count; -- if (ret_blk) -- *ret_blk = blk; -- return retval; -- } -- } -- return 0; --} -- - /* - * Check to see if a filesystem is in /proc/filesystems. - * Returns 1 if found, 0 if not -@@ -843,3 +823,50 @@ errcode_t e2fsck_allocate_subcluster_bitmap(ext2_filsys fs, const char *descr, - fs->default_bitmap_type = save_type; - return retval; - } -+ -+/* Return memory size in bytes */ -+unsigned long long get_memory_size(void) -+{ -+#if defined(_SC_PHYS_PAGES) -+# if defined(_SC_PAGESIZE) -+ return (unsigned long long)sysconf(_SC_PHYS_PAGES) * -+ (unsigned long long)sysconf(_SC_PAGESIZE); -+# elif defined(_SC_PAGE_SIZE) -+ return (unsigned long long)sysconf(_SC_PHYS_PAGES) * -+ (unsigned long long)sysconf(_SC_PAGE_SIZE); -+# endif -+#elif defined(CTL_HW) -+# if (defined(HW_MEMSIZE) || defined(HW_PHYSMEM64)) -+# define CTL_HW_INT64 -+# elif (defined(HW_PHYSMEM) || defined(HW_REALMEM)) -+# define CTL_HW_UINT -+# endif -+ int mib[2]; -+ -+ mib[0] = CTL_HW; -+# if defined(HW_MEMSIZE) -+ mib[1] = HW_MEMSIZE; -+# elif defined(HW_PHYSMEM64) -+ mib[1] = HW_PHYSMEM64; -+# elif defined(HW_REALMEM) -+ mib[1] = HW_REALMEM; -+# elif defined(HW_PYSMEM) -+ mib[1] = HW_PHYSMEM; -+# endif -+# if defined(CTL_HW_INT64) -+ unsigned long long size = 0; -+# elif defined(CTL_HW_UINT) -+ unsigned int size = 0; -+# endif -+# if defined(CTL_HW_INT64) || defined(CTL_HW_UINT) -+ size_t len = sizeof(size); -+ -+ if (sysctl(mib, 2, &size, &len, NULL, 0) == 0) -+ return (unsigned long long)size; -+# endif -+ return 0; -+#else -+# warning "Don't know how to detect memory on your platform?" -+ return 0; -+#endif -+} -diff --git a/ext2ed/Makefile.in b/ext2ed/Makefile.in -index 5f4cc69..0697431 100644 ---- a/ext2ed/Makefile.in -+++ b/ext2ed/Makefile.in -@@ -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 - -diff --git a/intl/Makefile.in b/intl/Makefile.in -index 87d081f..db6d7d7 100644 ---- a/intl/Makefile.in -+++ b/intl/Makefile.in -@@ -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 $@ $< -diff --git a/lib/Android.mk b/lib/Android.mk -new file mode 100644 -index 0000000..5053e7d ---- /dev/null -+++ b/lib/Android.mk -@@ -0,0 +1 @@ -+include $(call all-subdir-makefiles) -diff --git a/lib/blkid/Android.mk b/lib/blkid/Android.mk -new file mode 100644 -index 0000000..8a7bdd2 ---- /dev/null -+++ b/lib/blkid/Android.mk -@@ -0,0 +1,63 @@ -+LOCAL_PATH := $(call my-dir) -+ -+libext2_blkid_src_files := \ -+ cache.c \ -+ dev.c \ -+ devname.c \ -+ devno.c \ -+ getsize.c \ -+ llseek.c \ -+ probe.c \ -+ read.c \ -+ resolve.c \ -+ save.c \ -+ tag.c \ -+ version.c \ -+ -+ -+libext2_blkid_shared_libraries := libext2_uuid -+ -+libext2_blkid_system_shared_libraries := libc -+ -+libext2_blkid_static_libraries := libext2_uuid_static -+ -+libext2_blkid_system_static_libraries := libc -+ -+libext2_blkid_c_includes := external/e2fsprogs/lib -+ -+libext2_blkid_cflags := -O2 -g -W -Wall -fno-strict-aliasing -+ -+include $(CLEAR_VARS) -+ -+LOCAL_SRC_FILES := $(libext2_blkid_src_files) -+LOCAL_SYSTEM_SHARED_LIBRARIES := $(libext2_blkid_system_shared_libraries) -+LOCAL_SHARED_LIBRARIES := $(libext2_blkid_shared_libraries) -+LOCAL_C_INCLUDES := $(libext2_blkid_c_includes) -+LOCAL_CFLAGS := $(libext2_blkid_cflags) -+LOCAL_MODULE := libext2_blkid -+LOCAL_MODULE_TAGS := optional -+ -+include $(BUILD_SHARED_LIBRARY) -+ -+include $(CLEAR_VARS) -+ -+LOCAL_SRC_FILES := $(libext2_blkid_src_files) -+LOCAL_STATIC_LIBRARIES := $(libext2_blkid_static_libraries) $(libext2_blkid_system_static_libraries) -+LOCAL_C_INCLUDES := $(libext2_blkid_c_includes) -+LOCAL_CFLAGS := $(libext2_blkid_cflags) $(libext2_blkid_cflags_linux) -fno-strict-aliasing -+LOCAL_PRELINK_MODULE := false -+LOCAL_MODULE := libext2_blkid -+LOCAL_MODULE_TAGS := optional -+ -+include $(BUILD_STATIC_LIBRARY) -+ -+include $(CLEAR_VARS) -+ -+LOCAL_SRC_FILES := $(libext2_blkid_src_files) -+LOCAL_SHARED_LIBRARIES := $(addsuffix _host, $(libext2_blkid_shared_libraries)) -+LOCAL_C_INCLUDES := $(libext2_blkid_c_includes) -+LOCAL_CFLAGS := $(libext2_blkid_cflags) -+LOCAL_MODULE := libext2_blkid_host -+LOCAL_MODULE_TAGS := optional -+ -+include $(BUILD_HOST_SHARED_LIBRARY) -diff --git a/lib/blkid/Makefile.in b/lib/blkid/Makefile.in -index 6cabd36..275ba84 100644 ---- a/lib/blkid/Makefile.in -+++ b/lib/blkid/Makefile.in -@@ -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 $< -@@ -178,7 +179,7 @@ clean:: - tst_tag tst_types tests/*.out tests/*.ok \ - tests/*.img results test_probe core profiled/* \ - blkid.h blkid_types.h ../libblkid.a ../libblkid_p.a \ -- $(SMANPAGES) blkid -+ $(SMANPAGES) blkid blkid.pc - @echo rmdir tests/tmp tests - @(rmdir tests/tmp tests 2> /dev/null ; exit 0) - -diff --git a/lib/blkid/getsize.c b/lib/blkid/getsize.c -index a5c40aa..50293b8 100644 ---- a/lib/blkid/getsize.c -+++ b/lib/blkid/getsize.c -@@ -9,8 +9,12 @@ - * %End-Header% - */ - -+#ifndef _LARGEFILE_SOURCE - #define _LARGEFILE_SOURCE -+#endif -+#ifndef _LARGEFILE64_SOURCE - #define _LARGEFILE64_SOURCE -+#endif - - #include "config.h" - #include "blkidP.h" -diff --git a/lib/blkid/llseek.c b/lib/blkid/llseek.c -index 1cee34b..5929864 100644 ---- a/lib/blkid/llseek.c -+++ b/lib/blkid/llseek.c -@@ -9,8 +9,12 @@ - * %End-Header% - */ - -+#ifndef _LARGEFILE_SOURCE - #define _LARGEFILE_SOURCE -+#endif -+#ifndef _LARGEFILE64_SOURCE - #define _LARGEFILE64_SOURCE -+#endif - - #include "config.h" - #if HAVE_SYS_TYPES_H -diff --git a/lib/blkid/probe.c b/lib/blkid/probe.c -index 4b797ab..b260862 100644 ---- a/lib/blkid/probe.c -+++ b/lib/blkid/probe.c -@@ -874,8 +874,9 @@ static int probe_jfs(struct blkid_probe *probe, - return 0; - } - --static int probe_zfs(struct blkid_probe *probe, struct blkid_magic *id, -- unsigned char *buf) -+static int probe_zfs(struct blkid_probe *probe __BLKID_ATTR((unused)), -+ struct blkid_magic *id __BLKID_ATTR((unused)), -+ unsigned char *buf __BLKID_ATTR((unused))) - { - #if 0 - char *vdev_label; -@@ -1376,7 +1377,7 @@ static int probe_lvm2(struct blkid_probe *probe, - } - - static int probe_btrfs(struct blkid_probe *probe, -- struct blkid_magic *id, -+ struct blkid_magic *id __BLKID_ATTR((unused)), - unsigned char *buf) - { - struct btrfs_super_block *bs; -diff --git a/lib/blkid/probe.h b/lib/blkid/probe.h -index 37e80ef..d6809e1 100644 ---- a/lib/blkid/probe.h -+++ b/lib/blkid/probe.h -@@ -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 -diff --git a/lib/config.h.in b/lib/config.h.in -index aa5898a..c17a3fe 100644 ---- a/lib/config.h.in -+++ b/lib/config.h.in -@@ -1,4 +1,4 @@ --/* lib/config.h.in. Generated from configure.in by autoheader. */ -+/* lib/config.h.in. Generated from configure.ac by autoheader. */ - - /* Define if building universal (internal helper macro) */ - #undef AC_APPLE_UNIVERSAL_BUILD -@@ -12,8 +12,8 @@ - /* Define to 1 if debugging ext3/4 journal code */ - #undef CONFIG_JBD_DEBUG - --/* Define to 1 to enable quota support */ --#undef CONFIG_QUOTA -+/* Define to 1 to enable mmp support */ -+#undef CONFIG_MMP - - /* Define to 1 if the testio I/O manager should be enabled */ - #undef CONFIG_TESTIO_DEBUG -@@ -29,16 +29,19 @@ - /* Define to 1 to disable use of backtrace */ - #undef DISABLE_BACKTRACE - --/* Define to 1 if ext2 compression enabled */ --#undef ENABLE_COMPRESSION -+/* Define to 1 to enable bitmap stats. */ -+#undef ENABLE_BMAP_STATS - --/* Define to 1 if ext3/4 htree support enabled */ --#undef ENABLE_HTREE -+/* Define to 1 to enable bitmap stats. */ -+#undef ENABLE_BMAP_STATS_OPS - - /* Define to 1 if translation of program messages to the user's native - language is requested. */ - #undef ENABLE_NLS - -+/* Define to 1 if you have the `add_key' function. */ -+#undef HAVE_ADD_KEY -+ - /* Define to 1 if you have `alloca', as a function or macro. */ - #undef HAVE_ALLOCA - -@@ -61,6 +64,9 @@ - /* Define to 1 if you have the `asprintf' function. */ - #undef HAVE_ASPRINTF - -+/* Define to 1 if you have the header file. */ -+#undef HAVE_ATTR_XATTR_H -+ - /* Define to 1 if you have the `backtrace' function. */ - #undef HAVE_BACKTRACE - -@@ -150,6 +156,9 @@ - /* Define to 1 if you have the `ftruncate64' function. */ - #undef HAVE_FTRUNCATE64 - -+/* Define to 1 if you have the header file. */ -+#undef HAVE_FUSE_H -+ - /* Define to 1 if you have the `futimes' function. */ - #undef HAVE_FUTIMES - -@@ -214,6 +223,9 @@ - /* Define to 1 if you have the `jrand48' function. */ - #undef HAVE_JRAND48 - -+/* Define to 1 if you have the `keyctl' function. */ -+#undef HAVE_KEYCTL -+ - /* Define if you have and nl_langinfo(CODESET). */ - #undef HAVE_LANGINFO_CODESET - -@@ -235,6 +247,9 @@ - /* Define to 1 if you have the 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 - -@@ -250,6 +265,9 @@ - /* Define to 1 if lseek64 declared in unistd.h */ - #undef HAVE_LSEEK64_PROTOTYPE - -+/* Define to 1 if you have the header file. */ -+#undef HAVE_MAGIC_H -+ - /* Define to 1 if you have the `mallinfo' function. */ - #undef HAVE_MALLINFO - -@@ -331,6 +349,9 @@ - /* Define to 1 if you have the `pread64' function. */ - #undef HAVE_PREAD64 - -+/* Define to 1 if you have the header file. */ -+#undef HAVE_PTHREAD_H -+ - /* Define if the defines PTHREAD_MUTEX_RECURSIVE. */ - #undef HAVE_PTHREAD_MUTEX_RECURSIVE - -@@ -446,6 +467,9 @@ - /* Define to 1 if you have the `sysconf' function. */ - #undef HAVE_SYSCONF - -+/* Define to 1 if you have the header file. */ -+#undef HAVE_SYS_ACL_H -+ - /* Define to 1 if you have the header file. */ - #undef HAVE_SYS_DISKLABEL_H - -@@ -458,6 +482,9 @@ - /* Define to 1 if you have the header file. */ - #undef HAVE_SYS_IOCTL_H - -+/* Define to 1 if you have the header file. */ -+#undef HAVE_SYS_KEY_H -+ - /* Define to 1 if you have the header file. */ - #undef HAVE_SYS_MKDEV_H - -@@ -491,6 +518,9 @@ - /* Define to 1 if you have the header file. */ - #undef HAVE_SYS_SYSCALL_H - -+/* Define to 1 if you have the header file. */ -+#undef HAVE_SYS_SYSCTL_H -+ - /* Define to 1 if you have the header file. */ - #undef HAVE_SYS_SYSMACROS_H - -diff --git a/lib/e2p/Android.mk b/lib/e2p/Android.mk -new file mode 100644 -index 0000000..3d7aad5 ---- /dev/null -+++ b/lib/e2p/Android.mk -@@ -0,0 +1,64 @@ -+LOCAL_PATH := $(call my-dir) -+ -+libext2_e2p_src_files := \ -+ feature.c \ -+ fgetflags.c \ -+ fsetflags.c \ -+ fgetversion.c \ -+ fsetversion.c \ -+ getflags.c \ -+ getversion.c \ -+ hashstr.c \ -+ iod.c \ -+ ls.c \ -+ mntopts.c \ -+ parse_num.c \ -+ pe.c \ -+ pf.c \ -+ ps.c \ -+ setflags.c \ -+ setversion.c \ -+ uuid.c \ -+ ostype.c \ -+ percent.c -+ -+libext2_e2p_c_includes := external/e2fsprogs/lib -+ -+libext2_e2p_cflags := -O2 -g -W -Wall -+ -+libext2_e2p_system_shared_libraries := libc -+ -+libext2_e2p_system_static_libraries := libc -+ -+include $(CLEAR_VARS) -+ -+LOCAL_SRC_FILES := $(libext2_e2p_src_files) -+LOCAL_C_INCLUDES := $(libext2_e2p_c_includes) -+LOCAL_CFLAGS := $(libext2_e2p_cflags) -+LOCAL_SYSTEM_SHARED_LIBRARIES := $(libext2_e2p_system_shared_libraries) -+LOCAL_MODULE := libext2_e2p -+LOCAL_MODULE_TAGS := optional -+ -+include $(BUILD_SHARED_LIBRARY) -+ -+include $(CLEAR_VARS) -+ -+LOCAL_SRC_FILES := $(libext2_e2p_src_files) -+LOCAL_C_INCLUDES := $(libext2_e2p_c_includes) -+LOCAL_CFLAGS := $(libext2_e2p_cflags) -+LOCAL_STATIC_LIBRARIES := $(libext2_e2p_system_static_libraries) -+LOCAL_PRELINK_MODULE := false -+LOCAL_MODULE := libext2_e2p -+LOCAL_MODULE_TAGS := optional -+ -+include $(BUILD_STATIC_LIBRARY) -+ -+include $(CLEAR_VARS) -+ -+LOCAL_SRC_FILES := $(libext2_e2p_src_files) -+LOCAL_C_INCLUDES := $(libext2_e2p_c_includes) -+LOCAL_CFLAGS := $(libext2_e2p_cflags) -+LOCAL_MODULE := libext2_e2p_host -+LOCAL_MODULE_TAGS := optional -+ -+include $(BUILD_HOST_SHARED_LIBRARY) -diff --git a/lib/e2p/Makefile.in b/lib/e2p/Makefile.in -index 1c71c1c..ab036a6 100644 ---- a/lib/e2p/Makefile.in -+++ b/lib/e2p/Makefile.in -@@ -19,7 +19,7 @@ all:: e2p.pc - OBJS= feature.o fgetflags.o fsetflags.o fgetversion.o fsetversion.o \ - getflags.o getversion.o hashstr.o iod.o ls.o mntopts.o \ - parse_num.o pe.o pf.o ps.o setflags.o setversion.o uuid.o \ -- ostype.o percent.o -+ ostype.o percent.o crypto_mode.o - - SRCS= $(srcdir)/feature.c $(srcdir)/fgetflags.c \ - $(srcdir)/fsetflags.c $(srcdir)/fgetversion.c \ -@@ -28,7 +28,7 @@ SRCS= $(srcdir)/feature.c $(srcdir)/fgetflags.c \ - $(srcdir)/ls.c $(srcdir)/mntopts.c $(srcdir)/parse_num.c \ - $(srcdir)/pe.c $(srcdir)/pf.c $(srcdir)/ps.c \ - $(srcdir)/setflags.c $(srcdir)/setversion.c $(srcdir)/uuid.c \ -- $(srcdir)/ostype.c $(srcdir)/percent.c -+ $(srcdir)/ostype.c $(srcdir)/percent.c $(srcdir)/crypto_mode.c - HFILES= e2p.h - - LIBRARY= libe2p -@@ -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 $< -@@ -101,7 +102,7 @@ uninstall:: - - clean:: - $(RM) -f \#* *.s *.o *.a *~ *.bak core profiled/* -- $(RM) -f ../libe2p.a ../libe2p_p.a tst_ostype tst_feature -+ $(RM) -f ../libe2p.a ../libe2p_p.a tst_ostype tst_feature e2p.pc - - mostlyclean:: clean - distclean:: clean -@@ -122,8 +123,8 @@ feature.o: $(srcdir)/feature.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/ext2fs/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/kernel-jbd.h $(top_srcdir)/lib/ext2fs/jfs_compat.h \ -+ $(top_srcdir)/lib/ext2fs/kernel-list.h - fgetflags.o: $(srcdir)/fgetflags.c $(top_builddir)/lib/config.h \ - $(top_builddir)/lib/dirpaths.h $(srcdir)/e2p.h \ - $(top_srcdir)/lib/ext2fs/ext2_fs.h $(top_builddir)/lib/ext2fs/ext2_types.h -@@ -181,3 +182,6 @@ ostype.o: $(srcdir)/ostype.c $(top_builddir)/lib/config.h \ - percent.o: $(srcdir)/percent.c $(top_builddir)/lib/config.h \ - $(top_builddir)/lib/dirpaths.h $(srcdir)/e2p.h \ - $(top_srcdir)/lib/ext2fs/ext2_fs.h $(top_builddir)/lib/ext2fs/ext2_types.h -+crypto_mode.o: $(srcdir)/crypto_mode.c $(top_builddir)/lib/config.h \ -+ $(top_builddir)/lib/dirpaths.h $(srcdir)/e2p.h \ -+ $(top_srcdir)/lib/ext2fs/ext2_fs.h $(top_builddir)/lib/ext2fs/ext2_types.h -diff --git a/lib/e2p/crypto_mode.c b/lib/e2p/crypto_mode.c -new file mode 100644 -index 0000000..6146224 ---- /dev/null -+++ b/lib/e2p/crypto_mode.c -@@ -0,0 +1,73 @@ -+/* -+ * crypto_mode.c --- convert between encryption modes and strings -+ * -+ * Copyright (C) 1999 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 -+#include -+#include -+#include -+#include -+ -+#include "e2p.h" -+ -+struct mode { -+ unsigned int num; -+ const char *string; -+}; -+ -+static struct mode mode_list[] = { -+ { EXT4_ENCRYPTION_MODE_INVALID, "Invalid"}, -+ { EXT4_ENCRYPTION_MODE_AES_256_XTS, "AES-256-XTS"}, -+ { EXT4_ENCRYPTION_MODE_AES_256_GCM, "AES-256-GCM"}, -+ { EXT4_ENCRYPTION_MODE_AES_256_CBC, "AES-256-CBC"}, -+ { 0, 0 }, -+}; -+ -+const char *e2p_encmode2string(int num) -+{ -+ struct mode *p; -+ static char buf[20]; -+ -+ for (p = mode_list; p->string; p++) { -+ if (num == p->num) -+ return p->string; -+ } -+ sprintf(buf, "ENC_MODE_%d", num); -+ return buf; -+} -+ -+/* -+ * Returns the hash algorithm, or -1 on error -+ */ -+int e2p_string2encmode(char *string) -+{ -+ struct mode *p; -+ char *eptr; -+ int num; -+ -+ for (p = mode_list; p->string; p++) { -+ if (!strcasecmp(string, p->string)) { -+ return p->num; -+ } -+ } -+ if (strncasecmp(string, "ENC_MODE_", 9)) -+ return -1; -+ -+ if (string[9] == 0) -+ return -1; -+ num = strtol(string+9, &eptr, 10); -+ if (num > 255 || num < 0) -+ return -1; -+ if (*eptr) -+ return -1; -+ return num; -+} -+ -diff --git a/lib/e2p/feature.c b/lib/e2p/feature.c -index 1d3e689..737b0b9 100644 ---- a/lib/e2p/feature.c -+++ b/lib/e2p/feature.c -@@ -18,7 +18,7 @@ - - #include "e2p.h" - #include --#include -+#include - - struct feature { - int compat; -@@ -68,6 +68,8 @@ static struct feature feature_list[] = { - "metadata_csum"}, - { E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_REPLICA, - "replica" }, -+ { E2P_FEATURE_RO_INCOMPAT, EXT4_FEATURE_RO_COMPAT_READONLY, -+ "read-only" }, - - { E2P_FEATURE_INCOMPAT, EXT2_FEATURE_INCOMPAT_COMPRESSION, - "compression" }, -@@ -95,8 +97,10 @@ 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"}, -+ { E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_ENCRYPT, -+ "encrypt"}, - { 0, 0, 0 }, - }; - -@@ -110,6 +114,10 @@ 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" }, -+ { E2P_FEATURE_INCOMPAT, JFS_FEATURE_INCOMPAT_CSUM_V3, -+ "journal_checksum_v3" }, - { 0, 0, 0 }, - }; - -@@ -179,7 +187,7 @@ int e2p_string2feature(char *string, int *compat_type, unsigned int *mask) - if (string[9] == 0) - return 1; - num = strtol(string+9, &eptr, 10); -- if (num > 32 || num < 0) -+ if (num > 31 || num < 0) - return 1; - if (*eptr) - return 1; -@@ -253,7 +261,7 @@ int e2p_jrnl_string2feature(char *string, int *compat_type, unsigned int *mask) - if (string[9] == 0) - return 1; - num = strtol(string+9, &eptr, 10); -- if (num > 32 || num < 0) -+ if (num > 31 || num < 0) - return 1; - if (*eptr) - return 1; -diff --git a/lib/e2p/fgetflags.c b/lib/e2p/fgetflags.c -index 2af8462..7b93cba 100644 ---- a/lib/e2p/fgetflags.c -+++ b/lib/e2p/fgetflags.c -@@ -16,8 +16,12 @@ - * 93/10/30 - Creation - */ - -+#ifndef _LARGEFILE_SOURCE - #define _LARGEFILE_SOURCE -+#endif -+#ifndef _LARGEFILE64_SOURCE - #define _LARGEFILE64_SOURCE -+#endif - - #include "config.h" - #if HAVE_ERRNO_H -diff --git a/lib/e2p/fgetversion.c b/lib/e2p/fgetversion.c -index e6cee8b..d957024 100644 ---- a/lib/e2p/fgetversion.c -+++ b/lib/e2p/fgetversion.c -@@ -16,8 +16,12 @@ - * 93/10/30 - Creation - */ - -+#ifndef _LARGEFILE_SOURCE - #define _LARGEFILE_SOURCE -+#endif -+#ifndef _LARGEFILE64_SOURCE - #define _LARGEFILE64_SOURCE -+#endif - - #include "config.h" - #if HAVE_ERRNO_H -diff --git a/lib/e2p/fsetflags.c b/lib/e2p/fsetflags.c -index 167d16e..027834b 100644 ---- a/lib/e2p/fsetflags.c -+++ b/lib/e2p/fsetflags.c -@@ -16,8 +16,12 @@ - * 93/10/30 - Creation - */ - -+#ifndef _LARGEFILE_SOURCE - #define _LARGEFILE_SOURCE -+#endif -+#ifndef _LARGEFILE64_SOURCE - #define _LARGEFILE64_SOURCE -+#endif - - #include "config.h" - #if HAVE_ERRNO_H -diff --git a/lib/e2p/fsetversion.c b/lib/e2p/fsetversion.c -index d41d59f..dcbff5b 100644 ---- a/lib/e2p/fsetversion.c -+++ b/lib/e2p/fsetversion.c -@@ -16,8 +16,12 @@ - * 93/10/30 - Creation - */ - -+#ifndef _LARGEFILE_SOURCE - #define _LARGEFILE_SOURCE -+#endif -+#ifndef _LARGEFILE64_SOURCE - #define _LARGEFILE64_SOURCE -+#endif - - #include "config.h" - #if HAVE_ERRNO_H -diff --git a/lib/e2p/ls.c b/lib/e2p/ls.c -index 6f741c0..2e98c14 100644 ---- a/lib/e2p/ls.c -+++ b/lib/e2p/ls.c -@@ -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,15 @@ 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); -+ } -+ if (!e2p_is_null_uuid(sb->s_encrypt_pw_salt)) -+ fprintf(f, "Encryption PW Salt: %s\n", -+ e2p_uuid2str(sb->s_encrypt_pw_salt)); - } - - void list_super (struct ext2_super_block * s) -diff --git a/lib/e2p/mntopts.c b/lib/e2p/mntopts.c -index d56cc52..ff2e5de 100644 ---- a/lib/e2p/mntopts.c -+++ b/lib/e2p/mntopts.c -@@ -72,7 +72,7 @@ int e2p_string2mntopt(char *string, unsigned int *mask) - if (string[8] == 0) - return 1; - num = strtol(string+8, &eptr, 10); -- if (num > 32 || num < 0) -+ if (num > 31 || num < 0) - return 1; - if (*eptr) - return 1; -diff --git a/lib/e2p/pf.c b/lib/e2p/pf.c -index e2f8ce5..8961727 100644 ---- a/lib/e2p/pf.c -+++ b/lib/e2p/pf.c -@@ -37,12 +37,7 @@ static struct flags_name flags_array[] = { - { EXT2_NODUMP_FL, "d", "No_Dump" }, - { EXT2_NOATIME_FL, "A", "No_Atime" }, - { EXT2_COMPR_FL, "c", "Compression_Requested" }, --#ifdef ENABLE_COMPRESSION -- { EXT2_COMPRBLK_FL, "B", "Compressed_File" }, -- { EXT2_DIRTY_FL, "Z", "Compressed_Dirty_File" }, -- { EXT2_NOCOMPR_FL, "X", "Compression_Raw_Access" }, -- { EXT2_ECOMPR_FL, "E", "Compression_Error" }, --#endif -+ { EXT4_ENCRYPT_FL, "E", "Encrypted" }, - { EXT3_JOURNAL_DATA_FL, "j", "Journaled_Data" }, - { EXT2_INDEX_FL, "I", "Indexed_directory" }, - { EXT2_NOTAIL_FL, "t", "No_Tailmerging" }, -@@ -50,6 +45,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 } - }; - -diff --git a/lib/et/Android.mk b/lib/et/Android.mk -new file mode 100644 -index 0000000..5b6c969 ---- /dev/null -+++ b/lib/et/Android.mk -@@ -0,0 +1,47 @@ -+LOCAL_PATH := $(call my-dir) -+ -+libext2_com_err_src_files := \ -+ error_message.c \ -+ et_name.c \ -+ init_et.c \ -+ com_err.c \ -+ com_right.c -+ -+libext2_com_err_c_includes := external/e2fsprogs/lib -+ -+libext2_com_err_cflags := -O2 -g -W -Wall -+ -+libext2_com_err_system_shared_libraries := libc -+ -+include $(CLEAR_VARS) -+ -+LOCAL_SRC_FILES := $(libext2_com_err_src_files) -+LOCAL_C_INCLUDES := $(libext2_com_err_c_includes) -+LOCAL_CFLAGS := $(libext2_com_err_cflags) -+LOCAL_SYSTEM_SHARED_LIBRARIES := libc -+LOCAL_MODULE := libext2_com_err -+LOCAL_MODULE_TAGS := optional -+ -+include $(BUILD_SHARED_LIBRARY) -+ -+include $(CLEAR_VARS) -+ -+LOCAL_SRC_FILES := $(libext2_com_err_src_files) -+LOCAL_C_INCLUDES := $(libext2_com_err_c_includes) -+LOCAL_CFLAGS := $(libext2_com_err_cflags) -+LOCAL_STATIC_LIBRARIES := libc -+LOCAL_MODULE := libext2_com_err -+LOCAL_MODULE_TAGS := optional -+LOCAL_PRELINK_MODULE := false -+ -+include $(BUILD_STATIC_LIBRARY) -+ -+include $(CLEAR_VARS) -+ -+LOCAL_SRC_FILES := $(libext2_com_err_src_files) -+LOCAL_C_INCLUDES := $(libext2_com_err_c_includes) -+LOCAL_CFLAGS := $(libext2_com_err_cflags) -+LOCAL_MODULE := libext2_com_err_host -+LOCAL_MODULE_TAGS := optional -+ -+include $(BUILD_HOST_SHARED_LIBRARY) -diff --git a/lib/et/Makefile.in b/lib/et/Makefile.in -index 68c3baf..dbf7c1a 100644 ---- a/lib/et/Makefile.in -+++ b/lib/et/Makefile.in -@@ -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 $< -diff --git a/lib/ext2fs/Android.mk b/lib/ext2fs/Android.mk -new file mode 100644 -index 0000000..cbfbe65 ---- /dev/null -+++ b/lib/ext2fs/Android.mk -@@ -0,0 +1,140 @@ -+LOCAL_PATH := $(call my-dir) -+ -+libext2fs_src_files := \ -+ ext2_err.c \ -+ alloc.c \ -+ alloc_sb.c \ -+ alloc_stats.c \ -+ alloc_tables.c \ -+ atexit.c \ -+ badblocks.c \ -+ bb_inode.c \ -+ bitmaps.c \ -+ bitops.c \ -+ blkmap64_ba.c \ -+ blkmap64_rb.c \ -+ blknum.c \ -+ block.c \ -+ bmap.c \ -+ check_desc.c \ -+ crc16.c \ -+ crc32c.c \ -+ csum.c \ -+ closefs.c \ -+ dblist.c \ -+ dblist_dir.c \ -+ digest_encode.c \ -+ dirblock.c \ -+ dirhash.c \ -+ dir_iterate.c \ -+ dupfs.c \ -+ expanddir.c \ -+ ext_attr.c \ -+ extent.c \ -+ fallocate.c \ -+ fileio.c \ -+ finddev.c \ -+ flushb.c \ -+ freefs.c \ -+ gen_bitmap.c \ -+ gen_bitmap64.c \ -+ get_num_dirs.c \ -+ get_pathname.c \ -+ getsize.c \ -+ getsectsize.c \ -+ i_block.c \ -+ icount.c \ -+ imager.c \ -+ ind_block.c \ -+ initialize.c \ -+ inline.c \ -+ inline_data.c \ -+ inode.c \ -+ io_manager.c \ -+ ismounted.c \ -+ link.c \ -+ llseek.c \ -+ lookup.c \ -+ mmp.c \ -+ mkdir.c \ -+ mkjournal.c \ -+ namei.c \ -+ native.c \ -+ newdir.c \ -+ openfs.c \ -+ progress.c \ -+ punch.c \ -+ qcow2.c \ -+ rbtree.c \ -+ read_bb.c \ -+ read_bb_file.c \ -+ res_gdt.c \ -+ rw_bitmaps.c \ -+ sha256.c \ -+ sha512.c \ -+ swapfs.c \ -+ symlink.c \ -+ tdb.c \ -+ undo_io.c \ -+ unix_io.c \ -+ unlink.c \ -+ valid_blk.c \ -+ version.c -+ -+# get rid of this?! -+libext2fs_src_files += test_io.c -+ -+libext2fs_shared_libraries := \ -+ libext2_com_err \ -+ libext2_uuid \ -+ libext2_blkid \ -+ libext2_e2p -+ -+libext2fs_system_shared_libraries := libc -+ -+libext2fs_static_libraries := \ -+ libext2_com_err \ -+ libext2_uuid_static \ -+ libext2_blkid \ -+ libext2_e2p -+ -+libext2fs_system_static_libraries := libc -+ -+libext2fs_c_includes := external/e2fsprogs/lib -+ -+libext2fs_cflags := -O2 -g -W -Wall -+ -+include $(CLEAR_VARS) -+ -+LOCAL_SRC_FILES := $(libext2fs_src_files) -+LOCAL_SYSTEM_SHARED_LIBRARIES := $(libext2fs_system_shared_libraries) -+LOCAL_SHARED_LIBRARIES := $(libext2fs_shared_libraries) -+LOCAL_C_INCLUDES := $(libext2fs_c_includes) -+LOCAL_CFLAGS := $(libext2fs_cflags) -+LOCAL_MODULE := libext2fs -+LOCAL_MODULE_TAGS := optional -+ -+include $(BUILD_SHARED_LIBRARY) -+ -+include $(CLEAR_VARS) -+ -+LOCAL_SRC_FILES := $(libext2fs_src_files) -+LOCAL_STATIC_LIBRARIES := $(libext2fs_static_libraries) $(libext2fs_system_static_libraries) -+LOCAL_C_INCLUDES := $(libext2fs_c_includes) -+LOCAL_CFLAGS := $(libext2fs_cflags) $(libext2fs_cflags_linux) -+LOCAL_PRELINK_MODULE := false -+LOCAL_MODULE := libext2fs -+LOCAL_MODULE_TAGS := optional -+ -+include $(BUILD_STATIC_LIBRARY) -+ -+include $(CLEAR_VARS) -+ -+LOCAL_SRC_FILES := $(libext2fs_src_files) -+LOCAL_SHARED_LIBRARIES := $(addsuffix _host, $(libext2fs_shared_libraries)) -+LOCAL_C_INCLUDES := $(libext2fs_c_includes) -+LOCAL_CFLAGS := $(libext2fs_cflags) -+LOCAL_MODULE := libext2fs_host -+LOCAL_MODULE_TAGS := optional -+ -+include $(BUILD_HOST_SHARED_LIBRARY) -diff --git a/lib/ext2fs/Makefile.in b/lib/ext2fs/Makefile.in -index 847c26b..d5e71e5 100644 ---- a/lib/ext2fs/Makefile.in -+++ b/lib/ext2fs/Makefile.in -@@ -4,7 +4,10 @@ VPATH = @srcdir@ - top_builddir = ../.. - my_dir = lib/ext2fs - INSTALL = @INSTALL@ --DEPEND_CFLAGS = -I$(top_srcdir)/debugfs -+DEPEND_CFLAGS = -I$(top_srcdir)/debugfs -I$(srcdir)/../../e2fsck -DDEBUGFS -+# This nastyness is needed because of jfs_user.h hackery; when we finally -+# clean up this mess, we should be able to drop it -+DEBUGFS_CFLAGS = -I$(srcdir)/../../e2fsck $(ALL_CFLAGS) -DDEBUGFS - - @MCONFIG@ - -@@ -19,7 +22,8 @@ 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 journal.o \ -+ revoke.o recovery.o do_journal.o - - DEBUG_SRCS= debug_cmds.c extent_cmds.c tst_cmds.c \ - $(top_srcdir)/debugfs/debugfs.c \ -@@ -37,7 +41,13 @@ 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 \ -+ $(top_srcdir)/debugfs/journal.c \ -+ $(top_srcdir)/e2fsck/revoke.c \ -+ $(top_srcdir)/e2fsck/recovery.c \ -+ $(top_srcdir)/debugfs/do_journal.c - - OBJS= $(DEBUGFS_LIB_OBJS) $(RESIZE_LIB_OBJS) $(E2IMAGE_LIB_OBJS) \ - $(TEST_IO_LIB_OBJS) \ -@@ -46,6 +56,7 @@ OBJS= $(DEBUGFS_LIB_OBJS) $(RESIZE_LIB_OBJS) $(E2IMAGE_LIB_OBJS) \ - alloc_sb.o \ - alloc_stats.o \ - alloc_tables.o \ -+ atexit.o \ - badblocks.o \ - bb_inode.o \ - bitmaps.o \ -@@ -68,12 +79,14 @@ OBJS= $(DEBUGFS_LIB_OBJS) $(RESIZE_LIB_OBJS) $(E2IMAGE_LIB_OBJS) \ - expanddir.o \ - ext_attr.o \ - extent.o \ -+ fallocate.o \ - fileio.o \ - finddev.o \ - flushb.o \ - freefs.o \ - gen_bitmap.o \ - gen_bitmap64.o \ -+ get_num_dirs.o \ - get_pathname.o \ - getsize.o \ - getsectsize.o \ -@@ -82,6 +95,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 \ -@@ -102,6 +116,7 @@ OBJS= $(DEBUGFS_LIB_OBJS) $(RESIZE_LIB_OBJS) $(E2IMAGE_LIB_OBJS) \ - read_bb_file.o \ - res_gdt.o \ - rw_bitmaps.o \ -+ sha512.o \ - swapfs.o \ - symlink.o \ - tdb.o \ -@@ -117,6 +132,7 @@ SRCS= ext2_err.c \ - $(srcdir)/alloc_sb.c \ - $(srcdir)/alloc_stats.c \ - $(srcdir)/alloc_tables.c \ -+ $(srcdir)/atexit.c \ - $(srcdir)/badblocks.c \ - $(srcdir)/bb_compat.c \ - $(srcdir)/bb_inode.c \ -@@ -134,6 +150,7 @@ SRCS= ext2_err.c \ - $(srcdir)/csum.c \ - $(srcdir)/dblist.c \ - $(srcdir)/dblist_dir.c \ -+ $(srcdir)/digest_encode.c \ - $(srcdir)/dirblock.c \ - $(srcdir)/dirhash.c \ - $(srcdir)/dir_iterate.c \ -@@ -147,6 +164,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 +173,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 \ -@@ -177,6 +196,8 @@ SRCS= ext2_err.c \ - $(srcdir)/read_bb_file.c \ - $(srcdir)/res_gdt.c \ - $(srcdir)/rw_bitmaps.c \ -+ $(srcdir)/sha256.c \ -+ $(srcdir)/sha512.c \ - $(srcdir)/swapfs.c \ - $(srcdir)/symlink.c \ - $(srcdir)/tdb.c \ -@@ -226,6 +247,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 $< -@@ -251,6 +273,11 @@ tst_badblocks: tst_badblocks.o $(STATIC_LIBEXT2FS) $(DEPSTATIC_LIBCOM_ERR) - $(Q) $(CC) -o tst_badblocks tst_badblocks.o $(ALL_LDFLAGS) \ - $(STATIC_LIBEXT2FS) $(STATIC_LIBCOM_ERR) $(SYSLIBS) - -+tst_digest_encode: $(srcdir)/digest_encode.c $(srcdir)/ext2_fs.h -+ $(E) " CC $@" -+ $(Q) $(CC) $(ALL_LDFLAGS) $(ALL_CFLAGS) -o tst_digest_encode \ -+ $(srcdir)/digest_encode.c -DUNITTEST $(SYSLIBS) -+ - tst_icount: $(srcdir)/icount.c $(STATIC_LIBEXT2FS) $(DEPSTATIC_LIBCOM_ERR) - $(E) " LD $@" - $(Q) $(CC) -o tst_icount $(srcdir)/icount.c -DDEBUG \ -@@ -313,6 +340,16 @@ tst_inode_size: tst_inode_size.o - $(E) " LD $@" - $(Q) $(CC) -o tst_inode_size tst_inode_size.o $(ALL_LDFLAGS) $(SYSLIBS) - -+tst_sha256: $(srcdir)/sha256.c $(srcdir)/ext2_fs.h -+ $(E) " CC $@" -+ $(Q) $(CC) $(ALL_LDFLAGS) $(ALL_CFLAGS) -o tst_sha256 \ -+ $(srcdir)/sha256.c -DUNITTEST $(SYSLIBS) -+ -+tst_sha512: $(srcdir)/sha512.c $(srcdir)/ext2_fs.h -+ $(E) " CC $@" -+ $(Q) $(CC) $(ALL_LDFLAGS) $(ALL_CFLAGS) -o tst_sha512 \ -+ $(srcdir)/sha512.c -DUNITTEST $(SYSLIBS) -+ - ext2_tdbtool: tdbtool.o - $(E) " LD $@" - $(Q) $(CC) -o ext2_tdbtool tdbtool.o tdb.o $(ALL_LDFLAGS) $(SYSLIBS) -@@ -331,64 +368,88 @@ extent_cmds.c extent_cmds.h: $(top_srcdir)/debugfs/extent_cmds.ct - - debugfs.o: $(top_srcdir)/debugfs/debugfs.c - $(E) " CC $<" -- $(Q) $(CC) $(ALL_CFLAGS) -c $< -o $@ -+ $(Q) $(CC) $(DEBUGFS_CFLAGS) -c $< -o $@ - - extent_inode.o: $(top_srcdir)/debugfs/extent_inode.c - $(E) " CC $<" -- $(Q) $(CC) $(ALL_CFLAGS) -c $< -o $@ -+ $(Q) $(CC) $(DEBUGFS_CFLAGS) -c $< -o $@ - - util.o: $(top_srcdir)/debugfs/util.c - $(E) " CC $<" -- $(Q) $(CC) $(ALL_CFLAGS) -c $< -o $@ -+ $(Q) $(CC) $(DEBUGFS_CFLAGS) -c $< -o $@ - - ncheck.o: $(top_srcdir)/debugfs/ncheck.c - $(E) " CC $<" -- $(Q) $(CC) $(ALL_CFLAGS) -c $< -o $@ -+ $(Q) $(CC) $(DEBUGFS_CFLAGS) -c $< -o $@ - - icheck.o: $(top_srcdir)/debugfs/icheck.c - $(E) " CC $<" -- $(Q) $(CC) $(ALL_CFLAGS) -c $< -o $@ -+ $(Q) $(CC) $(DEBUGFS_CFLAGS) -c $< -o $@ - - ls.o: $(top_srcdir)/debugfs/ls.c - $(E) " CC $<" -- $(Q) $(CC) $(ALL_CFLAGS) -c $< -o $@ -+ $(Q) $(CC) $(DEBUGFS_CFLAGS) -c $< -o $@ - - lsdel.o: $(top_srcdir)/debugfs/lsdel.c - $(E) " CC $<" -- $(Q) $(CC) $(ALL_CFLAGS) -c $< -o $@ -+ $(Q) $(CC) $(DEBUGFS_CFLAGS) -c $< -o $@ - - dump.o: $(top_srcdir)/debugfs/dump.c - $(E) " CC $<" -- $(Q) $(CC) $(ALL_CFLAGS) -c $< -o $@ -+ $(Q) $(CC) $(DEBUGFS_CFLAGS) -c $< -o $@ - - set_fields.o: $(top_srcdir)/debugfs/set_fields.c - $(E) " CC $<" -- $(Q) $(CC) $(ALL_CFLAGS) -c $< -o $@ -+ $(Q) $(CC) $(DEBUGFS_CFLAGS) -c $< -o $@ - - logdump.o: $(top_srcdir)/debugfs/logdump.c - $(E) " CC $<" -- $(Q) $(CC) $(ALL_CFLAGS) -c $< -o $@ -+ $(Q) $(CC) $(DEBUGFS_CFLAGS) -c $< -o $@ - - htree.o: $(top_srcdir)/debugfs/htree.c - $(E) " CC $<" -- $(Q) $(CC) $(ALL_CFLAGS) -c $< -o $@ -+ $(Q) $(CC) $(DEBUGFS_CFLAGS) -c $< -o $@ - - unused.o: $(top_srcdir)/debugfs/unused.c - $(E) " CC $<" -- $(Q) $(CC) $(ALL_CFLAGS) -c $< -o $@ -+ $(Q) $(CC) $(DEBUGFS_CFLAGS) -c $< -o $@ - - zap.o: $(top_srcdir)/debugfs/zap.c - $(E) " CC $<" -- $(Q) $(CC) $(ALL_CFLAGS) -c $< -o $@ -+ $(Q) $(CC) $(DEBUGFS_CFLAGS) -c $< -o $@ - - quota.o: $(top_srcdir)/debugfs/quota.c - $(E) " CC $<" -- $(Q) $(CC) $(ALL_CFLAGS) -c $< -o $@ -+ $(Q) $(CC) $(DEBUGFS_CFLAGS) -c $< -o $@ -+ -+journal.o: $(top_srcdir)/debugfs/journal.c -+ $(E) " CC $<" -+ $(Q) $(CC) $(DEBUGFS_CFLAGS) -c $< -o $@ -+ -+revoke.o: $(top_srcdir)/e2fsck/revoke.c -+ $(E) " CC $<" -+ $(Q) $(CC) $(DEBUGFS_CFLAGS) -c $< -o $@ -+ -+recovery.o: $(top_srcdir)/e2fsck/recovery.c -+ $(E) " CC $<" -+ $(Q) $(CC) $(DEBUGFS_CFLAGS) -c $< -o $@ -+ -+do_journal.o: $(top_srcdir)/debugfs/do_journal.c -+ $(E) " CC $<" -+ $(Q) $(CC) $(DEBUGFS_CFLAGS) -c $< -o $@ -+ -+xattrs.o: $(top_srcdir)/debugfs/xattrs.c -+ $(E) " CC $<" -+ $(Q) $(CC) $(DEBUGFS_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 $@ -@@ -411,21 +472,21 @@ tst_bitmaps: tst_bitmaps.o tst_bitmaps_cmd.o $(srcdir)/blkmap64_rb.c \ - - tst_extents: $(srcdir)/extent.c $(DEBUG_OBJS) $(DEPSTATIC_LIBSS) libext2fs.a \ - $(STATIC_LIBE2P) $(DEPLIBUUID) $(DEPLIBBLKID) $(DEPSTATIC_LIBCOM_ERR) \ -- $(DEPLIBQUOTA) -+ $(DEPLIBSUPPORT) - $(E) " LD $@" - $(Q) $(CC) -o tst_extents $(srcdir)/extent.c \ - $(ALL_CFLAGS) $(ALL_LDFLAGS) -DDEBUG $(DEBUG_OBJS) \ -- $(STATIC_LIBSS) $(STATIC_LIBE2P) $(LIBQUOTA) \ -+ $(STATIC_LIBSS) $(STATIC_LIBE2P) $(LIBSUPPORT) \ - $(STATIC_LIBEXT2FS) $(LIBBLKID) $(LIBUUID) \ - $(STATIC_LIBCOM_ERR) $(SYSLIBS) -I $(top_srcdir)/debugfs - - tst_libext2fs: $(DEBUG_OBJS) \ - $(DEPSTATIC_LIBSS) $(STATIC_LIBE2P) $(DEPLIBUUID) libext2fs.a \ -- $(DEPLIBBLKID) $(DEPSTATIC_LIBCOM_ERR) $(DEPLIBQUOTA) -+ $(DEPLIBBLKID) $(DEPSTATIC_LIBCOM_ERR) $(DEPLIBSUPPORT) - $(E) " LD $@" - $(Q) $(CC) -o tst_libext2fs $(ALL_LDFLAGS) -DDEBUG $(DEBUG_OBJS) \ -- $(STATIC_LIBSS) $(STATIC_LIBE2P) $(LIBQUOTA) \ -- $(STATIC_LIBEXT2FS) $(LIBBLKID) $(LIBUUID) \ -+ $(STATIC_LIBSS) $(STATIC_LIBE2P) $(LIBSUPPORT) \ -+ $(STATIC_LIBEXT2FS) $(LIBBLKID) $(LIBUUID) $(LIBMAGIC) \ - $(STATIC_LIBCOM_ERR) $(SYSLIBS) -I $(top_srcdir)/debugfs - - tst_inline: $(srcdir)/inline.c $(STATIC_LIBEXT2FS) $(DEPSTATIC_LIBCOM_ERR) -@@ -434,6 +495,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) $(SYSLIBS) -+ - tst_csum: csum.c $(STATIC_LIBEXT2FS) $(DEPSTATIC_LIBCOM_ERR) $(STATIC_LIBE2P) \ - $(top_srcdir)/lib/e2p/e2p.h - $(E) " LD $@" -@@ -453,7 +519,8 @@ 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 tst_sha256 tst_sha512 \ -+ tst_digest_encode - $(TESTENV) ./tst_bitops - $(TESTENV) ./tst_badblocks - $(TESTENV) ./tst_iscan -@@ -463,7 +530,10 @@ check:: tst_bitops tst_badblocks tst_iscan tst_types tst_icount \ - $(TESTENV) ./tst_inode_size - $(TESTENV) ./tst_csum - $(TESTENV) ./tst_inline -+ $(TESTENV) ./tst_inline_data - $(TESTENV) ./tst_crc32c -+ $(TESTENV) ./tst_sha256 -+ $(TESTENV) ./tst_sha512 - $(TESTENV) ./tst_bitmaps -f $(srcdir)/tst_bitmaps_cmds > tst_bitmaps_out - diff $(srcdir)/tst_bitmaps_exp tst_bitmaps_out - $(TESTENV) ./tst_bitmaps -t 2 -f $(srcdir)/tst_bitmaps_cmds > tst_bitmaps_out -@@ -472,6 +542,7 @@ check:: tst_bitops tst_badblocks tst_iscan tst_types tst_icount \ - diff $(srcdir)/tst_bitmaps_exp tst_bitmaps_out - $(TESTENV) ./tst_bitmaps -l -f $(srcdir)/tst_bitmaps_cmds > tst_bitmaps_out - diff $(srcdir)/tst_bitmaps_exp tst_bitmaps_out -+ $(TESTENV) ./tst_digest_encode - - installdirs:: - $(E) " MKINSTALLDIRS $(libdir) $(includedir)/ext2fs" -@@ -506,6 +577,7 @@ clean:: - tst_bitops tst_types tst_icount tst_super_size tst_csum \ - tst_bitmaps tst_bitmaps_out tst_extents tst_inline \ - tst_inline_data tst_inode_size tst_bitmaps_cmd.c \ -+ tst_digest_encode tst_sha256 tst_sha512 \ - ext2_tdbtool mkjournal debug_cmds.c tst_cmds.c extent_cmds.c \ - ../libext2fs.a ../libext2fs_p.a ../libext2fs_chk.a \ - crc32c_table.h gen_crc32ctable tst_crc32c tst_libext2fs \ -@@ -565,6 +637,12 @@ alloc_tables.o: $(srcdir)/alloc_tables.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 $(srcdir)/ext2fsP.h -+atexit.o: $(srcdir)/atexit.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)/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 - badblocks.o: $(srcdir)/badblocks.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 \ -@@ -667,6 +745,12 @@ dblist_dir.o: $(srcdir)/dblist_dir.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 -+digest_encode.o: $(srcdir)/digest_encode.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 \ -+ $(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 - dirblock.o: $(srcdir)/dirblock.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 \ -@@ -698,7 +782,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 \ -@@ -752,6 +836,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 \ -@@ -800,6 +891,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 \ -@@ -851,15 +949,15 @@ 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 \ - $(srcdir)/ext2_fs.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 $(srcdir)/jfs_user.h $(srcdir)/kernel-jbd.h \ -- $(srcdir)/jfs_compat.h $(srcdir)/kernel-list.h -+ $(srcdir)/bitops.h $(srcdir)/kernel-jbd.h $(srcdir)/jfs_compat.h \ -+ $(srcdir)/kernel-list.h - mmp.o: $(srcdir)/mmp.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 \ -@@ -901,7 +999,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 \ -@@ -932,6 +1030,18 @@ rw_bitmaps.o: $(srcdir)/rw_bitmaps.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 $(srcdir)/e2image.h -+sha256.o: $(srcdir)/sha256.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 \ -+ $(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 -+sha512.o: $(srcdir)/sha512.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 \ -+ $(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 - swapfs.o: $(srcdir)/swapfs.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 \ -@@ -983,11 +1093,11 @@ tst_iscan.o: $(srcdir)/tst_iscan.c $(top_builddir)/lib/config.h \ - $(srcdir)/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \ - $(srcdir)/ext2_ext_attr.h $(srcdir)/bitops.h - undo_io.o: $(srcdir)/undo_io.c $(top_builddir)/lib/config.h \ -- $(top_builddir)/lib/dirpaths.h $(srcdir)/tdb.h $(srcdir)/ext2_fs.h \ -+ $(top_builddir)/lib/dirpaths.h $(srcdir)/ext2_fs.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 - unix_io.o: $(srcdir)/unix_io.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 \ -@@ -1027,8 +1137,9 @@ 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)/lib/support/quotaio.h $(top_srcdir)/lib/support/dqblk_v2.h \ -+ $(top_srcdir)/lib/support/quotaio_tree.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 \ -@@ -1042,11 +1153,13 @@ 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 \ -- $(top_srcdir)/debugfs/../version.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)/lib/support/quotaio.h \ -+ $(top_srcdir)/lib/support/dqblk_v2.h \ -+ $(top_srcdir)/lib/support/quotaio_tree.h $(top_srcdir)/debugfs/../version.h \ -+ $(srcdir)/../../e2fsck/jfs_user.h $(srcdir)/kernel-jbd.h \ -+ $(srcdir)/jfs_compat.h $(srcdir)/kernel-list.h \ -+ $(top_srcdir)/lib/support/plausible.h - util.o: $(top_srcdir)/debugfs/util.c $(top_builddir)/lib/config.h \ - $(top_builddir)/lib/dirpaths.h $(top_srcdir)/lib/ss/ss.h \ - $(top_builddir)/lib/ss/ss_err.h $(top_srcdir)/lib/et/com_err.h \ -@@ -1054,9 +1167,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)/lib/support/quotaio.h \ -+ $(top_srcdir)/lib/support/dqblk_v2.h \ -+ $(top_srcdir)/lib/support/quotaio_tree.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 \ -@@ -1064,9 +1178,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)/lib/support/quotaio.h \ -+ $(top_srcdir)/lib/support/dqblk_v2.h \ -+ $(top_srcdir)/lib/support/quotaio_tree.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 \ -@@ -1074,9 +1189,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)/lib/support/quotaio.h \ -+ $(top_srcdir)/lib/support/dqblk_v2.h \ -+ $(top_srcdir)/lib/support/quotaio_tree.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 \ -@@ -1084,9 +1200,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)/lib/support/quotaio.h \ -+ $(top_srcdir)/lib/support/dqblk_v2.h \ -+ $(top_srcdir)/lib/support/quotaio_tree.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 \ -@@ -1094,9 +1211,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)/lib/support/quotaio.h \ -+ $(top_srcdir)/lib/support/dqblk_v2.h \ -+ $(top_srcdir)/lib/support/quotaio_tree.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 \ -@@ -1104,9 +1222,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)/lib/support/quotaio.h \ -+ $(top_srcdir)/lib/support/dqblk_v2.h \ -+ $(top_srcdir)/lib/support/quotaio_tree.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 \ -@@ -1114,9 +1233,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)/lib/support/quotaio.h \ -+ $(top_srcdir)/lib/support/dqblk_v2.h \ -+ $(top_srcdir)/lib/support/quotaio_tree.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 \ -@@ -1124,9 +1244,10 @@ 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)/bitops.h $(top_srcdir)/debugfs/../misc/create_inode.h \ -+ $(top_srcdir)/lib/e2p/e2p.h $(top_srcdir)/lib/support/quotaio.h \ -+ $(top_srcdir)/lib/support/dqblk_v2.h \ -+ $(top_srcdir)/lib/support/quotaio_tree.h $(srcdir)/../../e2fsck/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 \ -@@ -1135,9 +1256,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)/lib/support/quotaio.h \ -+ $(top_srcdir)/lib/support/dqblk_v2.h \ -+ $(top_srcdir)/lib/support/quotaio_tree.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 \ -@@ -1145,9 +1267,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)/lib/support/quotaio.h \ -+ $(top_srcdir)/lib/support/dqblk_v2.h \ -+ $(top_srcdir)/lib/support/quotaio_tree.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 \ -@@ -1155,9 +1278,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)/lib/support/quotaio.h \ -+ $(top_srcdir)/lib/support/dqblk_v2.h \ -+ $(top_srcdir)/lib/support/quotaio_tree.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 \ -@@ -1165,9 +1289,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)/lib/support/quotaio.h \ -+ $(top_srcdir)/lib/support/dqblk_v2.h \ -+ $(top_srcdir)/lib/support/quotaio_tree.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 \ -@@ -1175,9 +1300,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)/lib/support/quotaio.h \ -+ $(top_srcdir)/lib/support/dqblk_v2.h \ -+ $(top_srcdir)/lib/support/quotaio_tree.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 \ -@@ -1185,12 +1311,68 @@ 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)/lib/support/quotaio.h \ -+ $(top_srcdir)/lib/support/dqblk_v2.h \ -+ $(top_srcdir)/lib/support/quotaio_tree.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)/lib/support/quotaio.h \ -+ $(top_srcdir)/lib/support/dqblk_v2.h \ -+ $(top_srcdir)/lib/support/quotaio_tree.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 -+ $(srcdir)/bitops.h $(top_srcdir)/misc/e2freefrag.h \ -+ $(top_srcdir)/debugfs/debugfs.h $(top_srcdir)/lib/ss/ss.h \ -+ $(top_builddir)/lib/ss/ss_err.h $(top_srcdir)/debugfs/../misc/create_inode.h \ -+ $(top_srcdir)/lib/e2p/e2p.h $(top_srcdir)/lib/support/quotaio.h \ -+ $(top_srcdir)/lib/support/dqblk_v2.h \ -+ $(top_srcdir)/lib/support/quotaio_tree.h -+create_inode.o: $(top_srcdir)/misc/create_inode.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 $(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)/fiemap.h \ -+ $(top_srcdir)/misc/create_inode.h $(top_srcdir)/lib/e2p/e2p.h \ -+ $(top_srcdir)/lib/support/nls-enable.h -+journal.o: $(top_srcdir)/debugfs/journal.c $(top_builddir)/lib/config.h \ -+ $(top_builddir)/lib/dirpaths.h $(srcdir)/../../e2fsck/jfs_user.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 $(srcdir)/kernel-jbd.h \ -+ $(srcdir)/jfs_compat.h $(srcdir)/kernel-list.h -+revoke.o: $(top_srcdir)/e2fsck/revoke.c $(top_srcdir)/e2fsck/jfs_user.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 $(srcdir)/kernel-jbd.h \ -+ $(srcdir)/jfs_compat.h $(srcdir)/kernel-list.h -+recovery.o: $(top_srcdir)/e2fsck/recovery.c $(top_srcdir)/e2fsck/jfs_user.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 $(srcdir)/kernel-jbd.h \ -+ $(srcdir)/jfs_compat.h $(srcdir)/kernel-list.h -+do_journal.o: $(top_srcdir)/debugfs/do_journal.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)/lib/support/quotaio.h \ -+ $(top_srcdir)/lib/support/dqblk_v2.h \ -+ $(top_srcdir)/lib/support/quotaio_tree.h $(srcdir)/../../e2fsck/jfs_user.h \ -+ $(srcdir)/kernel-jbd.h $(srcdir)/jfs_compat.h $(srcdir)/kernel-list.h -diff --git a/lib/ext2fs/Makefile.pq b/lib/ext2fs/Makefile.pq -index 2f7b654..89082a7 100644 ---- a/lib/ext2fs/Makefile.pq -+++ b/lib/ext2fs/Makefile.pq -@@ -27,6 +27,7 @@ OBJS= alloc.obj \ - icount.obj \ - initialize.obj \ - inline.obj \ -+ inline_data.obj \ - inode.obj \ - ismounted.obj \ - link.obj \ -diff --git a/lib/ext2fs/alloc.c b/lib/ext2fs/alloc.c -index 2061b9d..86e7f99 100644 ---- a/lib/ext2fs/alloc.c -+++ b/lib/ext2fs/alloc.c -@@ -26,13 +26,22 @@ - #include "ext2_fs.h" - #include "ext2fs.h" - -+#define min(a, b) ((a) < (b) ? (a) : (b)) -+ -+#undef DEBUG -+ -+#ifdef DEBUG -+# define dbg_printf(f, a...) do {printf(f, ## a); fflush(stdout); } while (0) -+#else -+# define dbg_printf(f, a...) -+#endif -+ - /* - * Clear the uninit block bitmap flag if necessary - */ - 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 +61,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; - -@@ -139,9 +147,23 @@ errcode_t ext2fs_new_block2(ext2_filsys fs, blk64_t goal, - { - errcode_t retval; - blk64_t b = 0; -+ errcode_t (*gab)(ext2_filsys fs, blk64_t goal, blk64_t *ret); - - EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); - -+ if (!map && fs->get_alloc_block) { -+ /* -+ * In case there are clients out there whose get_alloc_block -+ * handlers call ext2fs_new_block2 with a NULL block map, -+ * temporarily swap out the function pointer so that we don't -+ * end up in an infinite loop. -+ */ -+ gab = fs->get_alloc_block; -+ fs->get_alloc_block = NULL; -+ retval = gab(fs, goal, &b); -+ fs->get_alloc_block = gab; -+ goto allocated; -+ } - if (!map) - map = fs->block_map; - if (!map) -@@ -155,6 +177,7 @@ errcode_t ext2fs_new_block2(ext2_filsys fs, blk64_t goal, - if ((retval == ENOENT) && (goal != fs->super->s_first_data_block)) - retval = ext2fs_find_first_zero_block_bitmap2(map, - fs->super->s_first_data_block, goal - 1, &b); -+allocated: - if (retval == ENOENT) - return EXT2_ET_BLOCK_ALLOC_FAIL; - if (retval) -@@ -185,15 +208,6 @@ errcode_t ext2fs_alloc_block2(ext2_filsys fs, blk64_t goal, - { - errcode_t retval; - blk64_t block; -- char *buf = 0; -- -- if (!block_buf) { -- retval = ext2fs_get_mem(fs->blocksize, &buf); -- if (retval) -- return retval; -- block_buf = buf; -- } -- memset(block_buf, 0, fs->blocksize); - - if (fs->get_alloc_block) { - retval = (fs->get_alloc_block)(fs, goal, &block); -@@ -211,7 +225,11 @@ errcode_t ext2fs_alloc_block2(ext2_filsys fs, blk64_t goal, - goto fail; - } - -- retval = io_channel_write_blk64(fs->io, block, 1, block_buf); -+ if (block_buf) { -+ memset(block_buf, 0, fs->blocksize); -+ retval = io_channel_write_blk64(fs->io, block, 1, block_buf); -+ } else -+ retval = ext2fs_zero_blocks2(fs, block, 1, NULL, NULL); - if (retval) - goto fail; - -@@ -219,8 +237,6 @@ errcode_t ext2fs_alloc_block2(ext2_filsys fs, blk64_t goal, - *ret = block; - - fail: -- if (buf) -- ext2fs_free_mem(&buf); - return retval; - } - -@@ -298,3 +314,211 @@ void ext2fs_set_alloc_block_callback(ext2_filsys fs, - - fs->get_alloc_block = func; - } -+ -+blk64_t ext2fs_find_inode_goal(ext2_filsys fs, ext2_ino_t ino, -+ struct ext2_inode *inode, blk64_t lblk) -+{ -+ dgrp_t group; -+ __u8 log_flex; -+ struct ext2fs_extent extent; -+ ext2_extent_handle_t handle = NULL; -+ errcode_t err; -+ -+ if (inode == NULL || ext2fs_inode_data_blocks2(fs, inode) == 0) -+ goto no_blocks; -+ -+ if (inode->i_flags & EXT4_INLINE_DATA_FL) -+ goto no_blocks; -+ -+ if (inode->i_flags & EXT4_EXTENTS_FL) { -+ err = ext2fs_extent_open2(fs, ino, inode, &handle); -+ if (err) -+ goto no_blocks; -+ err = ext2fs_extent_goto2(handle, 0, lblk); -+ if (err) -+ goto no_blocks; -+ err = ext2fs_extent_get(handle, EXT2_EXTENT_CURRENT, &extent); -+ if (err) -+ goto no_blocks; -+ ext2fs_extent_free(handle); -+ return extent.e_pblk + (lblk - extent.e_lblk); -+ } -+ -+ /* block mapped file; see if block zero is mapped? */ -+ if (inode->i_block[0]) -+ return inode->i_block[0]; -+ -+no_blocks: -+ ext2fs_extent_free(handle); -+ log_flex = fs->super->s_log_groups_per_flex; -+ group = ext2fs_group_of_ino(fs, ino); -+ if (log_flex) -+ group = group & ~((1 << (log_flex)) - 1); -+ return ext2fs_group_first_block2(fs, group); -+} -+ -+/* -+ * Starting at _goal_, scan around the filesystem to find a run of free blocks -+ * that's at least _len_ blocks long. Possible flags: -+ * - EXT2_NEWRANGE_EXACT_GOAL: The range of blocks must start at _goal_. -+ * - EXT2_NEWRANGE_MIN_LENGTH: do not return a allocation shorter than _len_. -+ * - EXT2_NEWRANGE_ZERO_BLOCKS: Zero blocks pblk to pblk+plen before returning. -+ * -+ * The starting block is returned in _pblk_ and the length is returned via -+ * _plen_. The blocks are not marked in the bitmap; the caller must mark -+ * however much of the returned run they actually use, hopefully via -+ * ext2fs_block_alloc_stats_range(). -+ * -+ * This function can return a range that is longer than what was requested. -+ */ -+errcode_t ext2fs_new_range(ext2_filsys fs, int flags, blk64_t goal, -+ blk64_t len, ext2fs_block_bitmap map, blk64_t *pblk, -+ blk64_t *plen) -+{ -+ errcode_t retval; -+ blk64_t start, end, b; -+ int looped = 0; -+ blk64_t max_blocks = ext2fs_blocks_count(fs->super); -+ errcode_t (*nrf)(ext2_filsys fs, int flags, blk64_t goal, -+ blk64_t len, blk64_t *pblk, blk64_t *plen); -+ -+ dbg_printf("%s: flags=0x%x goal=%llu len=%llu\n", __func__, flags, -+ goal, len); -+ EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); -+ if (len == 0 || (flags & ~EXT2_NEWRANGE_ALL_FLAGS)) -+ return EXT2_ET_INVALID_ARGUMENT; -+ -+ if (!map && fs->new_range) { -+ /* -+ * In case there are clients out there whose new_range -+ * handlers call ext2fs_new_range with a NULL block map, -+ * temporarily swap out the function pointer so that we don't -+ * end up in an infinite loop. -+ */ -+ nrf = fs->new_range; -+ fs->new_range = NULL; -+ retval = nrf(fs, flags, goal, len, pblk, plen); -+ fs->new_range = nrf; -+ if (retval) -+ return retval; -+ start = *pblk; -+ end = *pblk + *plen; -+ goto allocated; -+ } -+ if (!map) -+ map = fs->block_map; -+ if (!map) -+ return EXT2_ET_NO_BLOCK_BITMAP; -+ if (!goal || goal >= ext2fs_blocks_count(fs->super)) -+ goal = fs->super->s_first_data_block; -+ -+ start = goal; -+ while (!looped || start <= goal) { -+ retval = ext2fs_find_first_zero_block_bitmap2(map, start, -+ max_blocks - 1, -+ &start); -+ if (retval == ENOENT) { -+ /* -+ * If there are no free blocks beyond the starting -+ * point, try scanning the whole filesystem, unless the -+ * user told us only to allocate from _goal_, or if -+ * we're already scanning the whole filesystem. -+ */ -+ if (flags & EXT2_NEWRANGE_FIXED_GOAL || -+ start == fs->super->s_first_data_block) -+ goto fail; -+ start = fs->super->s_first_data_block; -+ continue; -+ } else if (retval) -+ goto errout; -+ -+ if (flags & EXT2_NEWRANGE_FIXED_GOAL && start != goal) -+ goto fail; -+ -+ b = min(start + len - 1, max_blocks - 1); -+ retval = ext2fs_find_first_set_block_bitmap2(map, start, b, -+ &end); -+ if (retval == ENOENT) -+ end = b + 1; -+ else if (retval) -+ goto errout; -+ -+ if (!(flags & EXT2_NEWRANGE_MIN_LENGTH) || -+ (end - start) >= len) { -+ /* Success! */ -+ *pblk = start; -+ *plen = end - start; -+ dbg_printf("%s: new_range goal=%llu--%llu " -+ "blk=%llu--%llu %llu\n", -+ __func__, goal, goal + len - 1, -+ *pblk, *pblk + *plen - 1, *plen); -+allocated: -+ for (b = start; b < end; -+ b += fs->super->s_blocks_per_group) -+ clear_block_uninit(fs, -+ ext2fs_group_of_blk2(fs, b)); -+ return 0; -+ } -+ -+ if (flags & EXT2_NEWRANGE_FIXED_GOAL) -+ goto fail; -+ start = end; -+ if (start >= max_blocks) { -+ if (looped) -+ goto fail; -+ looped = 1; -+ start = fs->super->s_first_data_block; -+ } -+ } -+ -+fail: -+ retval = EXT2_ET_BLOCK_ALLOC_FAIL; -+errout: -+ return retval; -+} -+ -+void ext2fs_set_new_range_callback(ext2_filsys fs, -+ errcode_t (*func)(ext2_filsys fs, int flags, blk64_t goal, -+ blk64_t len, blk64_t *pblk, blk64_t *plen), -+ errcode_t (**old)(ext2_filsys fs, int flags, blk64_t goal, -+ blk64_t len, blk64_t *pblk, blk64_t *plen)) -+{ -+ if (!fs || fs->magic != EXT2_ET_MAGIC_EXT2FS_FILSYS) -+ return; -+ -+ if (old) -+ *old = fs->new_range; -+ -+ fs->new_range = func; -+} -+ -+errcode_t ext2fs_alloc_range(ext2_filsys fs, int flags, blk64_t goal, -+ blk_t len, blk64_t *ret) -+{ -+ int newr_flags = EXT2_NEWRANGE_MIN_LENGTH; -+ errcode_t retval; -+ blk64_t plen; -+ -+ EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); -+ if (len == 0 || (flags & ~EXT2_ALLOCRANGE_ALL_FLAGS)) -+ return EXT2_ET_INVALID_ARGUMENT; -+ -+ if (flags & EXT2_ALLOCRANGE_FIXED_GOAL) -+ newr_flags |= EXT2_NEWRANGE_FIXED_GOAL; -+ -+ retval = ext2fs_new_range(fs, newr_flags, goal, len, NULL, ret, &plen); -+ if (retval) -+ return retval; -+ -+ if (plen < len) -+ return EXT2_ET_BLOCK_ALLOC_FAIL; -+ -+ if (flags & EXT2_ALLOCRANGE_ZERO_BLOCKS) { -+ retval = ext2fs_zero_blocks2(fs, *ret, len, NULL, NULL); -+ if (retval) -+ return retval; -+ } -+ -+ ext2fs_block_alloc_stats_range(fs, *ret, len, +1); -+ return retval; -+} -diff --git a/lib/ext2fs/alloc_stats.c b/lib/ext2fs/alloc_stats.c -index 53d990a..3949f61 100644 ---- a/lib/ext2fs/alloc_stats.c -+++ b/lib/ext2fs/alloc_stats.c -@@ -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; -@@ -146,4 +145,20 @@ void ext2fs_block_alloc_stats_range(ext2_filsys fs, blk64_t blk, - } - ext2fs_mark_super_dirty(fs); - ext2fs_mark_bb_dirty(fs); -+ if (fs->block_alloc_stats_range) -+ (fs->block_alloc_stats_range)(fs, blk, num, inuse); -+} -+ -+void ext2fs_set_block_alloc_stats_range_callback(ext2_filsys fs, -+ void (*func)(ext2_filsys fs, blk64_t blk, -+ blk_t num, int inuse), -+ void (**old)(ext2_filsys fs, blk64_t blk, -+ blk_t num, int inuse)) -+{ -+ if (!fs || fs->magic != EXT2_ET_MAGIC_EXT2FS_FILSYS) -+ return; -+ if (old) -+ *old = fs->block_alloc_stats_range; -+ -+ fs->block_alloc_stats_range = func; - } -diff --git a/lib/ext2fs/alloc_tables.c b/lib/ext2fs/alloc_tables.c -index 3760d61..3e1952f 100644 ---- a/lib/ext2fs/alloc_tables.c -+++ b/lib/ext2fs/alloc_tables.c -@@ -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; - } - -diff --git a/lib/ext2fs/atexit.c b/lib/ext2fs/atexit.c -new file mode 100644 -index 0000000..b3be1d5 ---- /dev/null -+++ b/lib/ext2fs/atexit.c -@@ -0,0 +1,116 @@ -+/* -+ * atexit.c --- Clean things up when we exit normally. -+ * -+ * Copyright Oracle, 2014 -+ * Author Darrick J. Wong -+ * -+ * %Begin-Header% -+ * This file may be redistributed under the terms of the GNU Library -+ * General Public License, version 2. -+ * %End-Header% -+ */ -+ -+#ifndef _LARGEFILE_SOURCE -+#define _LARGEFILE_SOURCE -+#endif -+#ifndef _LARGEFILE64_SOURCE -+#define _LARGEFILE64_SOURCE -+#endif -+ -+#include "config.h" -+#include -+ -+#include "ext2_fs.h" -+#include "ext2fs.h" -+#include "ext2fsP.h" -+ -+struct exit_data { -+ ext2_exit_fn func; -+ void *data; -+}; -+ -+static struct exit_data *items; -+static size_t nr_items; -+ -+static void handle_exit(void) -+{ -+ struct exit_data *ed; -+ -+ for (ed = items + nr_items - 1; ed >= items; ed--) { -+ if (ed->func == NULL) -+ continue; -+ ed->func(ed->data); -+ } -+ -+ ext2fs_free_mem(&items); -+ nr_items = 0; -+} -+ -+/* -+ * Schedule a function to be called at (normal) program termination. -+ * If you want this to be called during a signal exit, you must capture -+ * the signal and call exit() yourself! -+ */ -+errcode_t ext2fs_add_exit_fn(ext2_exit_fn func, void *data) -+{ -+ struct exit_data *ed, *free_ed = NULL; -+ size_t x; -+ errcode_t ret; -+ -+ if (func == NULL) -+ return EXT2_ET_INVALID_ARGUMENT; -+ -+ for (x = 0, ed = items; x < nr_items; x++, ed++) { -+ if (ed->func == func && ed->data == data) -+ return EXT2_ET_FILE_EXISTS; -+ if (ed->func == NULL) -+ free_ed = ed; -+ } -+ -+ if (free_ed) { -+ free_ed->func = func; -+ free_ed->data = data; -+ return 0; -+ } -+ -+ if (nr_items == 0) { -+ ret = atexit(handle_exit); -+ if (ret) -+ return ret; -+ } -+ -+ ret = ext2fs_resize_mem(0, (nr_items + 1) * sizeof(struct exit_data), -+ &items); -+ if (ret) -+ return ret; -+ -+ items[nr_items].func = func; -+ items[nr_items].data = data; -+ nr_items++; -+ -+ return 0; -+} -+ -+/* Remove a function from the exit cleanup list. */ -+errcode_t ext2fs_remove_exit_fn(ext2_exit_fn func, void *data) -+{ -+ struct exit_data *ed; -+ size_t x; -+ -+ if (func == NULL) -+ return EXT2_ET_INVALID_ARGUMENT; -+ -+ for (x = 0, ed = items; x < nr_items; x++, ed++) { -+ if (ed->func == NULL) -+ return 0; -+ if (ed->func == func && ed->data == data) { -+ size_t sz = (nr_items - (x + 1)) * -+ sizeof(struct exit_data); -+ memmove(ed, ed + 1, sz); -+ memset(items + nr_items - 1, 0, -+ sizeof(struct exit_data)); -+ } -+ } -+ -+ return 0; -+} -diff --git a/lib/ext2fs/bitops.h b/lib/ext2fs/bitops.h -index 4fb7dc6..bc59608 100644 ---- a/lib/ext2fs/bitops.h -+++ b/lib/ext2fs/bitops.h -@@ -11,31 +11,33 @@ - */ - - #ifdef WORDS_BIGENDIAN --#define ext2fs_cpu_to_le64(x) ext2fs_swab64((x)) --#define ext2fs_le64_to_cpu(x) ext2fs_swab64((x)) --#define ext2fs_cpu_to_le32(x) ext2fs_swab32((x)) --#define ext2fs_le32_to_cpu(x) ext2fs_swab32((x)) --#define ext2fs_cpu_to_le16(x) ext2fs_swab16((x)) --#define ext2fs_le16_to_cpu(x) ext2fs_swab16((x)) --#define ext2fs_cpu_to_be64(x) ((__u64)(x)) --#define ext2fs_be64_to_cpu(x) ((__u64)(x)) --#define ext2fs_cpu_to_be32(x) ((__u32)(x)) --#define ext2fs_be32_to_cpu(x) ((__u32)(x)) --#define ext2fs_cpu_to_be16(x) ((__u16)(x)) --#define ext2fs_be16_to_cpu(x) ((__u16)(x)) -+#define ext2fs_cpu_to_le64(x) ((__force __le64)ext2fs_swab64((__u64)(x))) -+#define ext2fs_le64_to_cpu(x) ext2fs_swab64((__force __u64)(__le64)(x)) -+#define ext2fs_cpu_to_le32(x) ((__force __le32)ext2fs_swab32((__u32)(x))) -+#define ext2fs_le32_to_cpu(x) ext2fs_swab32((__force __u32)(__le32)(x)) -+#define ext2fs_cpu_to_le16(x) ((__force __le16)ext2fs_swab16((__u16)(x))) -+#define ext2fs_le16_to_cpu(x) ext2fs_swab16((__force __u16)(__le16)(x)) -+ -+#define ext2fs_cpu_to_be64(x) ((__force __be64)(__u64)(x)) -+#define ext2fs_be64_to_cpu(x) ((__force __u64)(__be64)(x)) -+#define ext2fs_cpu_to_be32(x) ((__force __be32)(__u32)(x)) -+#define ext2fs_be32_to_cpu(x) ((__force __u32)(__be32)(x)) -+#define ext2fs_cpu_to_be16(x) ((__force __be16)(__u16)(x)) -+#define ext2fs_be16_to_cpu(x) ((__force __u16)(__be16)(x)) - #else --#define ext2fs_cpu_to_le64(x) ((__u64)(x)) --#define ext2fs_le64_to_cpu(x) ((__u64)(x)) --#define ext2fs_cpu_to_le32(x) ((__u32)(x)) --#define ext2fs_le32_to_cpu(x) ((__u32)(x)) --#define ext2fs_cpu_to_le16(x) ((__u16)(x)) --#define ext2fs_le16_to_cpu(x) ((__u16)(x)) --#define ext2fs_cpu_to_be64(x) ext2fs_swab64((x)) --#define ext2fs_be64_to_cpu(x) ext2fs_swab64((x)) --#define ext2fs_cpu_to_be32(x) ext2fs_swab32((x)) --#define ext2fs_be32_to_cpu(x) ext2fs_swab32((x)) --#define ext2fs_cpu_to_be16(x) ext2fs_swab16((x)) --#define ext2fs_be16_to_cpu(x) ext2fs_swab16((x)) -+#define ext2fs_cpu_to_le64(x) ((__force __le64)(__u64)(x)) -+#define ext2fs_le64_to_cpu(x) ((__force __u64)(__le64)(x)) -+#define ext2fs_cpu_to_le32(x) ((__force __le32)(__u32)(x)) -+#define ext2fs_le32_to_cpu(x) ((__force __u32)(__le32)(x)) -+#define ext2fs_cpu_to_le16(x) ((__force __le16)(__u16)(x)) -+#define ext2fs_le16_to_cpu(x) ((__force __u16)(__le16)(x)) -+ -+#define ext2fs_cpu_to_be64(x) ((__force __be64)ext2fs_swab64((__u64)(x))) -+#define ext2fs_be64_to_cpu(x) ext2fs_swab64((__force __u64)(__be64)(x)) -+#define ext2fs_cpu_to_be32(x) ((__force __be32)ext2fs_swab32((__u32)(x))) -+#define ext2fs_be32_to_cpu(x) ext2fs_swab32((__force __u32)(__be32)(x)) -+#define ext2fs_cpu_to_be16(x) ((__force __be16)ext2fs_swab16((__u16)(x))) -+#define ext2fs_be16_to_cpu(x) ext2fs_swab16((__force __u16)(__be16)(x)) - #endif - - /* -diff --git a/lib/ext2fs/blkmap64_ba.c b/lib/ext2fs/blkmap64_ba.c -index 894293a..4671c50 100644 ---- a/lib/ext2fs/blkmap64_ba.c -+++ b/lib/ext2fs/blkmap64_ba.c -@@ -310,12 +310,18 @@ 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 EXT2FS_ATTR((unused))) -+{ -+} -+#endif - - /* Find the first zero bit between start and end, inclusive. */ - static errcode_t ba_find_first_zero(ext2fs_generic_bitmap bitmap, -diff --git a/lib/ext2fs/blkmap64_rb.c b/lib/ext2fs/blkmap64_rb.c -index fdbd330..7964fdb 100644 ---- a/lib/ext2fs/blkmap64_rb.c -+++ b/lib/ext2fs/blkmap64_rb.c -@@ -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; -@@ -735,8 +733,7 @@ static errcode_t rb_get_bmap_range(ext2fs_generic_bitmap bitmap, - struct rb_node *parent = NULL, *next, **n; - struct ext2fs_rb_private *bp; - struct bmap_rb_extent *ext; -- int count; -- __u64 pos; -+ __u64 count, pos; - - bp = (struct ext2fs_rb_private *) bitmap->private; - n = &bp->root.rb_node; -@@ -767,9 +764,9 @@ static errcode_t rb_get_bmap_range(ext2fs_generic_bitmap bitmap, - if (pos >= start + num) - break; - if (pos < start) { -- count -= start - pos; -- if (count < 0) -+ if (pos + count < start) - continue; -+ count -= start - pos; - pos = start; - } - if (pos + count > start + num) -@@ -891,7 +888,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 +899,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 +923,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 +950,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 = { -diff --git a/lib/ext2fs/blknum.c b/lib/ext2fs/blknum.c -index 3367335..93b64ce 100644 ---- a/lib/ext2fs/blknum.c -+++ b/lib/ext2fs/blknum.c -@@ -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) -diff --git a/lib/ext2fs/block.c b/lib/ext2fs/block.c -index b8c6879..601129d 100644 ---- a/lib/ext2fs/block.c -+++ b/lib/ext2fs/block.c -@@ -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) { -diff --git a/lib/ext2fs/bmap.c b/lib/ext2fs/bmap.c -index a8bb00d..c18f742 100644 ---- a/lib/ext2fs/bmap.c -+++ b/lib/ext2fs/bmap.c -@@ -214,10 +214,13 @@ static errcode_t extent_bmap(ext2_filsys fs, ext2_ino_t ino, - errcode_t retval = 0; - blk64_t blk64 = 0; - int alloc = 0; -+ int set_flags; -+ -+ set_flags = bmap_flags & BMAP_UNINIT ? EXT2_EXTENT_SET_BMAP_UNINIT : 0; - - if (bmap_flags & BMAP_SET) { - retval = ext2fs_extent_set_bmap(handle, block, -- *phys_blk, 0); -+ *phys_blk, set_flags); - return retval; - } - retval = ext2fs_extent_goto(handle, block); -@@ -244,7 +247,7 @@ got_block: - retval = extent_bmap(fs, ino, inode, handle, block_buf, - 0, block-1, 0, blocks_alloc, &blk64); - if (retval) -- blk64 = 0; -+ blk64 = ext2fs_find_inode_goal(fs, ino, inode, block); - retval = ext2fs_alloc_block2(fs, blk64, block_buf, - &blk64); - if (retval) -@@ -254,7 +257,7 @@ got_block: - alloc++; - set_extent: - retval = ext2fs_extent_set_bmap(handle, block, -- blk64, 0); -+ blk64, set_flags); - if (retval) { - ext2fs_block_alloc_stats2(fs, blk64, -1); - return retval; -@@ -321,6 +324,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) -@@ -347,7 +357,8 @@ errcode_t ext2fs_bmap2(ext2_filsys fs, ext2_ino_t ino, struct ext2_inode *inode, - } - - *phys_blk = inode_bmap(inode, block); -- b = block ? inode_bmap(inode, block-1) : 0; -+ b = block ? inode_bmap(inode, block - 1) : -+ ext2fs_find_inode_goal(fs, ino, inode, block); - - if ((*phys_blk == 0) && (bmap_flags & BMAP_ALLOC)) { - retval = ext2fs_alloc_block(fs, b, block_buf, &b); -@@ -433,6 +444,8 @@ errcode_t ext2fs_bmap2(ext2_filsys fs, ext2_ino_t ino, struct ext2_inode *inode, - if (retval == 0) - *phys_blk = blk32; - done: -+ if (*phys_blk && retval == 0 && (bmap_flags & BMAP_ZERO)) -+ retval = ext2fs_zero_blocks2(fs, *phys_blk, 1, NULL, NULL); - if (buf) - ext2fs_free_mem(&buf); - if (handle) -diff --git a/lib/ext2fs/bmap64.h b/lib/ext2fs/bmap64.h -index 9deba46..d8c7a3c 100644 ---- a/lib/ext2fs/bmap64.h -+++ b/lib/ext2fs/bmap64.h -@@ -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 - }; -diff --git a/lib/ext2fs/closefs.c b/lib/ext2fs/closefs.c -index ab5b2fb..3c7c7dc 100644 ---- a/lib/ext2fs/closefs.c -+++ b/lib/ext2fs/closefs.c -@@ -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); -diff --git a/lib/ext2fs/crc32c.c b/lib/ext2fs/crc32c.c -index 2512528..624ad77 100644 ---- a/lib/ext2fs/crc32c.c -+++ b/lib/ext2fs/crc32c.c -@@ -32,7 +32,6 @@ - #include - #include - #include --#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) -@@ -58,400 +57,189 @@ - #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++; -diff --git a/lib/ext2fs/crc32c_defs.h b/lib/ext2fs/crc32c_defs.h -index 023f2c0..3f9a09e 100644 ---- a/lib/ext2fs/crc32c_defs.h -+++ b/lib/ext2fs/crc32c_defs.h -@@ -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 */ -diff --git a/lib/ext2fs/csum.c b/lib/ext2fs/csum.c -index 669f806..6dcefb9 100644 ---- a/lib/ext2fs/csum.c -+++ b/lib/ext2fs/csum.c -@@ -30,62 +30,779 @@ - #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); -+} -+ -+/* NOTE: The input to this function MUST be in LE order */ -+int ext2fs_superblock_csum_verify(ext2_filsys fs, struct ext2_super_block *sb) -+{ -+ __u32 flag, calculated; -+ -+ if (fs->flags & EXT2_FLAG_SWAP_BYTES) -+ flag = EXT4_FEATURE_RO_COMPAT_METADATA_CSUM; -+ else -+ flag = ext2fs_cpu_to_le32(EXT4_FEATURE_RO_COMPAT_METADATA_CSUM); -+ -+ if (!EXT2_HAS_RO_COMPAT_FEATURE(fs->super, flag)) -+ return 1; -+ -+ calculated = ext2fs_superblock_csum(fs, sb); -+ -+ return ext2fs_le32_to_cpu(sb->s_checksum) == calculated; -+} -+ -+/* NOTE: The input to this function MUST be in LE order */ -+errcode_t ext2fs_superblock_csum_set(ext2_filsys fs, -+ struct ext2_super_block *sb) -+{ -+ __u32 flag, crc; -+ -+ if (fs->flags & EXT2_FLAG_SWAP_BYTES) -+ flag = EXT4_FEATURE_RO_COMPAT_METADATA_CSUM; -+ else -+ flag = ext2fs_cpu_to_le32(EXT4_FEATURE_RO_COMPAT_METADATA_CSUM); -+ -+ if (!EXT2_HAS_RO_COMPAT_FEATURE(fs->super, flag)) -+ 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, -- (char *)save_desc + ext4_bg_size, -- save_size - ext4_bg_size); -+ crc32 = ext2fs_crc32c_le(crc32, -+ (unsigned 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 +812,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 +846,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++) { -@@ -139,6 +854,11 @@ errcode_t ext2fs_set_gdt_csum(ext2_filsys fs) - __u32 old_unused = ext2fs_bg_itable_unused(fs, i); - __u32 old_flags = ext2fs_bg_flags(fs, i); - __u32 old_free_inodes_count = ext2fs_bg_free_inodes_count(fs, i); -+ __u32 old_free_blocks_count = ext2fs_bg_free_blocks_count(fs, i); -+ -+ if (old_free_blocks_count == sb->s_blocks_per_group && -+ i != fs->group_desc_count - 1) -+ ext2fs_bg_flags_set(fs, i, EXT2_BG_BLOCK_UNINIT); - - if (old_free_inodes_count == sb->s_inodes_per_group) { - ext2fs_bg_flags_set(fs, i, EXT2_BG_INODE_UNINIT); -diff --git a/lib/ext2fs/dblist.c b/lib/ext2fs/dblist.c -index 3f6ea50..bbdb221 100644 ---- a/lib/ext2fs/dblist.c -+++ b/lib/ext2fs/dblist.c -@@ -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). - */ -@@ -222,20 +194,25 @@ void ext2fs_dblist_sort2(ext2_dblist dblist, - /* - * This function iterates over the directory block list - */ --errcode_t ext2fs_dblist_iterate2(ext2_dblist dblist, -+errcode_t ext2fs_dblist_iterate3(ext2_dblist dblist, - int (*func)(ext2_filsys fs, - struct ext2_db_entry2 *db_info, - void *priv_data), -+ unsigned long long start, -+ unsigned long long count, - void *priv_data) - { -- unsigned long long i; -+ unsigned long long i, end; - int ret; - - EXT2_CHECK_MAGIC(dblist, EXT2_ET_MAGIC_DBLIST); - -+ end = start + count; - if (!dblist->sorted) - ext2fs_dblist_sort2(dblist, 0); -- for (i=0; i < dblist->count; i++) { -+ if (end > dblist->count) -+ end = dblist->count; -+ for (i = start; i < end; i++) { - ret = (*func)(dblist->fs, &dblist->list[i], priv_data); - if (ret & DBLIST_ABORT) - return 0; -@@ -243,6 +220,16 @@ errcode_t ext2fs_dblist_iterate2(ext2_dblist dblist, - return 0; - } - -+errcode_t ext2fs_dblist_iterate2(ext2_dblist dblist, -+ int (*func)(ext2_filsys fs, -+ struct ext2_db_entry2 *db_info, -+ void *priv_data), -+ void *priv_data) -+{ -+ return ext2fs_dblist_iterate3(dblist, func, 0, dblist->count, -+ priv_data); -+} -+ - static EXT2_QSORT_TYPE dir_block_cmp2(const void *a, const void *b) - { - const struct ext2_db_entry2 *db_a = -diff --git a/lib/ext2fs/dblist_dir.c b/lib/ext2fs/dblist_dir.c -index d4d5111..864a3ca 100644 ---- a/lib/ext2fs/dblist_dir.c -+++ b/lib/ext2fs/dblist_dir.c -@@ -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; -diff --git a/lib/ext2fs/digest_encode.c b/lib/ext2fs/digest_encode.c -new file mode 100644 -index 0000000..d90b300 ---- /dev/null -+++ b/lib/ext2fs/digest_encode.c -@@ -0,0 +1,186 @@ -+/* -+ * lib/ext2fs/digest_encode.c -+ * -+ * A function to encode a digest using 64 characters that are valid in a -+ * filename per ext2fs rules. -+ * -+ * Written by Uday Savagaonkar, 2014. -+ * -+ * Copyright 2014 Google Inc. All Rights Reserved. -+ * -+ * %Begin-Header% -+ * This file may be redistributed under the terms of the GNU Library -+ * General Public License, version 2. -+ * %End-Header% -+ */ -+ -+#include "config.h" -+#if HAVE_SYS_TYPES_H -+#include -+#endif -+#include "ext2fs.h" -+ -+static const char *lookup_table = -+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+,"; -+ -+/** -+ * ext2fs_digest_encode() - -+ * -+ * Encodes the input digest using characters from the set [a-zA-Z0-9_+]. -+ * The encoded string is roughly 4/3 times the size of the input string. -+ */ -+int ext2fs_digest_encode(const char *src, int len, char *dst) -+{ -+ int i = 0, bits = 0, ac = 0; -+ char *cp = dst; -+ -+ while (i < len) { -+ ac += (((unsigned char) src[i]) << bits); -+ bits += 8; -+ do { -+ *cp++ = lookup_table[ac & 0x3f]; -+ ac >>= 6; -+ bits -= 6; -+ } while (bits >= 6); -+ i++; -+ } -+ if (bits) -+ *cp++ = lookup_table[ac & 0x3f]; -+ return cp - dst; -+} -+ -+int ext2fs_digest_decode(const char *src, int len, char *dst) -+{ -+ int i = 0, bits = 0, ac = 0; -+ const char *p; -+ char *cp = dst; -+ -+ while (i < len) { -+ p = strchr(lookup_table, src[i]); -+ if (p == NULL || src[i] == 0) -+ return -1; -+ ac += (p - lookup_table) << bits; -+ bits += 6; -+ if (bits >= 8) { -+ *cp++ = ac & 0xff; -+ ac >>= 8; -+ bits -= 8; -+ } -+ i++; -+ } -+ if (ac) -+ return -1; -+ return cp - dst; -+} -+ -+ -+#ifdef UNITTEST -+static const struct { -+ unsigned char d[32]; -+ unsigned int len; -+ const unsigned char *ed; -+} tests[] = { -+ { { 0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, -+ 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24, -+ 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, -+ 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55 }, 32, -+ "jDLxChJ,cQhm7TPyZ+WukcirBROZbOJTkWZmbgnU4WF" -+ }, -+ { { 0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea, -+ 0x41, 0x41, 0x40, 0xde, 0x5d, 0xae, 0x22, 0x23, -+ 0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c, -+ 0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad }, 32, -+ "6inF,+YAPreQBBk3d5qIjA7AhNqlXoHn0Cx,hJPAV0K" -+ }, -+ { { 0x24, 0x8d, 0x6a, 0x61, 0xd2, 0x06, 0x38, 0xb8, -+ 0xe5, 0xc0, 0x26, 0x93, 0x0c, 0x3e, 0x60, 0x39, -+ 0xa3, 0x3c, 0xe4, 0x59, 0x64, 0xff, 0x21, 0x67, -+ 0xf6, 0xec, 0xed, 0xd4, 0x19, 0xdb, 0x06, 0xc1 }, 32, -+ "k0oahJtB4gb5AbykM4DY5MKPknFZ,HyZ2ze7Unx2GEM" -+ }, -+ { { 0x00, }, 1, -+ "AA" -+ }, -+ { { 0x01, }, 1, -+ "BA" -+ }, -+ { { 0x01, 0x02 }, 2, -+ "BIA" -+ }, -+ { { 0x01, 0x02, 0x03 }, 3, -+ "BIwA" -+ }, -+ { { 0x01, 0x02, 0x03, 0x04 }, 4, -+ "BIwAEA" -+ }, -+ { { 0x01, 0x02, 0x03, 0x04, 0xff }, 5, -+ "BIwAE8P" -+ }, -+ { { 0x01, 0x02, 0x03, 0x04, 0xff, 0xfe }, 6, -+ "BIwAE8v," -+ }, -+ { { 0x01, 0x02, 0x03, 0x04, 0xff, 0xfe, 0xfd }, 7, -+ "BIwAE8v,9D" -+ }, -+}; -+ -+int main(int argc, char **argv) -+{ -+ int i, ret, len, len2; -+ int errors = 0; -+ unsigned char tmp[1024], tmp2[1024]; -+ -+ if (argc == 3 && !strcmp(argv[1], "encode")) { -+ memset(tmp, 0, sizeof(tmp)); -+ ext2fs_digest_encode(argv[2], strlen(argv[2]), tmp); -+ puts(tmp); -+ exit(0); -+ } -+ if (argc == 3 && !strcmp(argv[1], "decode")) { -+ memset(tmp, 0, sizeof(tmp)); -+ ret = ext2fs_digest_decode(argv[2], strlen(argv[2]), tmp); -+ puts(tmp); -+ fprintf(stderr, "returned %d\n", ret); -+ exit(0); -+ } -+ for (i = 0; i < (int)(sizeof(tests) / sizeof(tests[0])); i++) { -+ memset(tmp, 0, sizeof(tmp)); -+ ret = ext2fs_digest_encode(tests[i].d, tests[i].len, tmp); -+ len = strlen(tmp); -+ printf("Test Digest %d (returned %d): ", i, ret); -+ if (ret != len) { -+ printf("FAILED returned %d, string length was %d\n", -+ ret, len); -+ errors++; -+ continue; -+ } else if (strcmp(tmp, tests[i].ed) != 0) { -+ printf("FAILED: got %s, expected %s\n", tmp, -+ tests[i].ed); -+ errors++; -+ continue; -+ } -+ ret = ext2fs_digest_decode(tmp, len, tmp2); -+ if (ret != tests[i].len) { -+ printf("FAILED decode returned %d, expected %d\n", -+ ret, tests[i].len); -+ errors++; -+ continue; -+ } -+ if (memcmp(tmp2, tests[i].d, ret) != 0) { -+ puts("FAILED: decode mismatched"); -+ errors++; -+ continue; -+ } -+ printf("OK\n"); -+ } -+ for (i = 1; i < argc; i++) { -+ memset(tmp, 0, sizeof(tmp)); -+ ret = ext2fs_digest_encode(argv[i], strlen(argv[i]), tmp); -+ len = strlen(tmp); -+ printf("Digest of '%s' is '%s' (returned %d, length %d)\n", -+ argv[i], tmp, ret, len); -+ } -+ return errors; -+} -+ -+#endif /* UNITTEST */ -diff --git a/lib/ext2fs/dir_iterate.c b/lib/ext2fs/dir_iterate.c -index 0744ee8..390573a 100644 ---- a/lib/ext2fs/dir_iterate.c -+++ b/lib/ext2fs/dir_iterate.c -@@ -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) > (int) 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 - 8) { -+ while (offset < buflen - 8) { - 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) > (int) 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; - } -- -diff --git a/lib/ext2fs/dirblock.c b/lib/ext2fs/dirblock.c -index cb3a104..54b2777 100644 ---- a/lib/ext2fs/dirblock.c -+++ b/lib/ext2fs/dirblock.c -@@ -20,45 +20,36 @@ - #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, -diff --git a/lib/ext2fs/expanddir.c b/lib/ext2fs/expanddir.c -index 153b838..9f02312 100644 ---- a/lib/ext2fs/expanddir.c -+++ b/lib/ext2fs/expanddir.c -@@ -18,12 +18,14 @@ - - #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,23 +65,17 @@ static int expand_dir_proc(ext2_filsys fs, - return BLOCK_ABORT; - } - es->done = 1; -- retval = ext2fs_write_dir_block(fs, new_blk, block); -- } else { -- retval = ext2fs_get_mem(fs->blocksize, &block); -- if (retval) { -- es->err = retval; -- return BLOCK_ABORT; -- } -- memset(block, 0, fs->blocksize); -- retval = io_channel_write_blk64(fs->io, new_blk, 1, block); -- } -+ retval = ext2fs_write_dir_block4(fs, new_blk, block, 0, -+ es->dir); -+ ext2fs_free_mem(&block); -+ } else -+ retval = ext2fs_zero_blocks2(fs, new_blk, 1, NULL, NULL); - if (blockcnt >= 0) - es->goal = new_blk; - if (retval) { - es->err = retval; - return BLOCK_ABORT; - } -- ext2fs_free_mem(&block); - *blocknr = new_blk; - - if (es->done) -@@ -106,13 +102,20 @@ errcode_t ext2fs_expand_dir(ext2_filsys fs, ext2_ino_t dir) - if (retval) - return retval; - -+ retval = ext2fs_read_inode(fs, dir, &inode); -+ if (retval) -+ return retval; -+ - es.done = 0; - es.err = 0; -- es.goal = 0; -+ es.goal = ext2fs_find_inode_goal(fs, dir, &inode, 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; -diff --git a/lib/ext2fs/ext2_err.et.in b/lib/ext2fs/ext2_err.et.in -index 87812ab..894789e 100644 ---- a/lib/ext2fs/ext2_err.et.in -+++ b/lib/ext2fs/ext2_err.et.in -@@ -476,4 +476,58 @@ 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" -+ -+ec EXT2_ET_JOURNAL_FLAGS_WRONG, -+ "Journal flags inconsistent" -+ -+ec EXT2_ET_UNDO_FILE_CORRUPT, -+ "Undo file corrupt" -+ -+ec EXT2_ET_UNDO_FILE_WRONG, -+ "Wrong undo file for this filesystem" -+ - end -diff --git a/lib/ext2fs/ext2_ext_attr.h b/lib/ext2fs/ext2_ext_attr.h -index ed548d1..bbb0aaa 100644 ---- a/lib/ext2fs/ext2_ext_attr.h -+++ b/lib/ext2fs/ext2_ext_attr.h -@@ -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 { -diff --git a/lib/ext2fs/ext2_fs.h b/lib/ext2fs/ext2_fs.h -index 6c3620c..cfeaa05 100644 ---- a/lib/ext2fs/ext2_fs.h -+++ b/lib/ext2fs/ext2_fs.h -@@ -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 */ -@@ -226,15 +233,22 @@ struct ext2_dx_root_info { - #define EXT2_HASH_FLAG_INCOMPAT 0x1 - - struct ext2_dx_entry { -- __u32 hash; -- __u32 block; -+ __le32 hash; -+ __le32 block; - }; - - struct ext2_dx_countlimit { -- __u16 limit; -- __u16 count; -+ __le16 limit; -+ __le16 count; - }; - -+/* -+ * This goes at the end of each htree block. -+ */ -+struct ext2_dx_tail { -+ __le32 dt_reserved; -+ __le32 dt_checksum; /* crc32c(uuid+inum+dxblock) */ -+}; - - /* - * Macro-instructions used to manage group descriptors -@@ -293,7 +307,8 @@ struct ext2_dx_countlimit { - #define EXT2_DIRTY_FL 0x00000100 - #define EXT2_COMPRBLK_FL 0x00000200 /* One or more compressed clusters */ - #define EXT2_NOCOMPR_FL 0x00000400 /* Access raw compressed data */ --#define EXT2_ECOMPR_FL 0x00000800 /* Compression error */ -+ /* nb: was previously EXT2_ECOMPR_FL */ -+#define EXT4_ENCRYPT_FL 0x00000800 /* encrypted inode */ - /* End compression flags --- maybe not all used */ - #define EXT2_BTREE_FL 0x00001000 /* btree format dir */ - #define EXT2_INDEX_FL 0x00001000 /* hash-indexed directory */ -@@ -310,6 +325,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 +475,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 +562,48 @@ struct ext2_inode_large { - #define ext4_offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) - #endif - -+/* Metadata checksum algorithms */ -+#define EXT2_CRC32C_CHKSUM 1 -+ -+/* Encryption algorithms, key size and key reference len */ -+#define EXT4_ENCRYPTION_MODE_INVALID 0 -+#define EXT4_ENCRYPTION_MODE_AES_256_XTS 1 -+#define EXT4_ENCRYPTION_MODE_AES_256_GCM 2 -+#define EXT4_ENCRYPTION_MODE_AES_256_CBC 3 -+#define EXT4_ENCRYPTION_MODE_AES_256_CTS 4 -+ -+#define EXT4_AES_256_XTS_KEY_SIZE 64 -+#define EXT4_AES_256_GCM_KEY_SIZE 32 -+#define EXT4_AES_256_CBC_KEY_SIZE 32 -+#define EXT4_AES_256_CTS_KEY_SIZE 32 -+#define EXT4_MAX_KEY_SIZE 64 -+ -+#define EXT4_KEY_DESCRIPTOR_SIZE 8 -+#define EXT4_CRYPTO_BLOCK_SIZE 16 -+ -+/* Password derivation constants */ -+#define EXT4_MAX_PASSPHRASE_SIZE 1024 -+#define EXT4_MAX_SALT_SIZE 256 -+#define EXT4_PBKDF2_ITERATIONS 0xFFFF -+ -+/* -+ * Policy provided via an ioctl on the topmost directory. This -+ * structure is also in the kernel. -+ */ -+struct ext4_encryption_policy { -+ char version; -+ char contents_encryption_mode; -+ char filenames_encryption_mode; -+ char flags; -+ char master_key_descriptor[EXT4_KEY_DESCRIPTOR_SIZE]; -+} __attribute__((__packed__)); -+ -+struct ext4_encryption_key { -+ __u32 mode; -+ char raw[EXT4_MAX_KEY_SIZE]; -+ __u32 size; -+} __attribute__((__packed__)); -+ - /* - * Structure of the super block - */ -@@ -625,8 +689,9 @@ 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; -- __u16 s_reserved_pad; /* Padding to next 32bits */ -+ __u8 s_checksum_type; /* metadata checksum algorithm */ -+ __u8 s_encryption_level; /* versioning level for encryption */ -+ __u8 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 */ - __u32 s_snapshot_id; /* sequential ID of active snapshot */ -@@ -651,7 +716,10 @@ struct ext2_super_block { - __u32 s_grp_quota_inum; /* inode number of group quota file */ - __u32 s_overhead_blocks; /* overhead blocks/clusters in fs */ - __u32 s_backup_bgs[2]; /* If sparse_super2 enabled */ -- __u32 s_reserved[106]; /* Padding to the end of the block */ -+ __u8 s_encrypt_algos[4]; /* Encryption algorithms in use */ -+ __u8 s_encrypt_pw_salt[16]; /* Salt used for string2key algorithm */ -+ __le32 s_lpf_ino; /* Location of the lost+found inode */ -+ __le32 s_reserved[100]; /* Padding to the end of the block */ - __u32 s_checksum; /* crc32c(superblock) */ - }; - -@@ -715,8 +783,15 @@ 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 -+#define EXT4_FEATURE_RO_COMPAT_READONLY 0x1000 -+ - - #define EXT2_FEATURE_INCOMPAT_COMPRESSION 0x0001 - #define EXT2_FEATURE_INCOMPAT_FILETYPE 0x0002 -@@ -731,7 +806,8 @@ 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 EXT4_FEATURE_INCOMPAT_ENCRYPT 0x10000 - - #define EXT2_FEATURE_COMPAT_SUPP 0 - #define EXT2_FEATURE_INCOMPAT_SUPP (EXT2_FEATURE_INCOMPAT_FILETYPE| \ -@@ -781,6 +857,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 +875,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,13 +901,24 @@ 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 - */ -+#define EXT2_DIR_ENTRY_HEADER_LEN 8 - #define EXT2_DIR_PAD 4 - #define EXT2_DIR_ROUND (EXT2_DIR_PAD - 1) --#define EXT2_DIR_REC_LEN(name_len) (((name_len) + 8 + EXT2_DIR_ROUND) & \ -+#define EXT2_DIR_REC_LEN(name_len) (((name_len) + \ -+ EXT2_DIR_ENTRY_HEADER_LEN + \ -+ EXT2_DIR_ROUND) & \ - ~EXT2_DIR_ROUND) - - /* -@@ -838,6 +944,7 @@ struct ext2_dir_entry_2 { - #define EXT4_MMP_SEQ_FSCK 0xE24D4D50U /* mmp_seq value when being fscked */ - #define EXT4_MMP_SEQ_MAX 0xE24D4D4FU /* maximum valid mmp_seq value */ - -+/* Not endian-annotated; it's swapped at read/write time */ - struct mmp_struct { - __u32 mmp_magic; /* Magic number for MMP */ - __u32 mmp_seq; /* Sequence no. updated periodically */ -@@ -846,7 +953,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 +972,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 */ -diff --git a/lib/ext2fs/ext2_io.h b/lib/ext2fs/ext2_io.h -index 1894fb8..1faa720 100644 ---- a/lib/ext2fs/ext2_io.h -+++ b/lib/ext2fs/ext2_io.h -@@ -90,7 +90,12 @@ struct struct_io_manager { - int count, const void *data); - errcode_t (*discard)(io_channel channel, unsigned long long block, - unsigned long long count); -- long reserved[16]; -+ errcode_t (*cache_readahead)(io_channel channel, -+ unsigned long long block, -+ unsigned long long count); -+ errcode_t (*zeroout)(io_channel channel, unsigned long long block, -+ unsigned long long count); -+ long reserved[14]; - }; - - #define IO_FLAG_RW 0x0001 -@@ -122,8 +127,14 @@ extern errcode_t io_channel_write_blk64(io_channel channel, - extern errcode_t io_channel_discard(io_channel channel, - unsigned long long block, - unsigned long long count); -+extern errcode_t io_channel_zeroout(io_channel channel, -+ unsigned long long block, -+ unsigned long long count); - extern errcode_t io_channel_alloc_buf(io_channel channel, - int count, void *ptr); -+extern errcode_t io_channel_cache_readahead(io_channel io, -+ unsigned long long block, -+ unsigned long long count); - - /* unix_io.c */ - extern io_manager unix_io_manager; -diff --git a/lib/ext2fs/ext2_types.h.in b/lib/ext2fs/ext2_types.h.in -index 1320431..fd57231 100644 ---- a/lib/ext2fs/ext2_types.h.in -+++ b/lib/ext2fs/ext2_types.h.in -@@ -166,4 +166,25 @@ typedef long __s64; - - #endif /* _*_TYPES_H */ - -+/* endian checking stuff */ -+#ifndef EXT2_ENDIAN_H_ -+#define EXT2_ENDIAN_H_ -+ -+#ifdef __CHECKER__ -+#define __bitwise __attribute__((bitwise)) -+#define __force __attribute__((force)) -+#else -+#define __bitwise -+#define __force -+#endif -+ -+typedef __u16 __bitwise __le16; -+typedef __u32 __bitwise __le32; -+typedef __u64 __bitwise __le64; -+typedef __u16 __bitwise __be16; -+typedef __u32 __bitwise __be32; -+typedef __u64 __bitwise __be64; -+ -+#endif /* EXT2_ENDIAN_H_ */ -+ - @PUBLIC_CONFIG_HEADER@ -diff --git a/lib/ext2fs/ext2fs.h b/lib/ext2fs/ext2fs.h -index d3a34d5..86d860f 100644 ---- a/lib/ext2fs/ext2fs.h -+++ b/lib/ext2fs/ext2fs.h -@@ -66,12 +66,6 @@ extern "C" { - #include - #endif /* EXT2_FLAT_INCLUDES */ - --#ifdef __CHECK_ENDIAN__ --#define __bitwise __attribute__((bitwise)) --#else --#define __bitwise --#endif -- - typedef __u32 __bitwise ext2_ino_t; - typedef __u32 __bitwise blk_t; - typedef __u64 __bitwise blk64_t; -@@ -193,6 +187,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 +270,21 @@ 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; -+ -+ io_channel journal_io; -+ char *journal_name; -+ -+ /* New block range allocation hooks */ -+ errcode_t (*new_range)(ext2_filsys fs, int flags, blk64_t goal, -+ blk64_t len, blk64_t *pblk, blk64_t *plen); -+ void (*block_alloc_stats_range)(ext2_filsys fs, blk64_t blk, blk_t num, -+ int inuse); - }; - - #if EXT2_FLAT_INCLUDES -@@ -293,9 +303,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 +443,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 +465,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 -@@ -518,6 +533,8 @@ typedef struct ext2_icount *ext2_icount_t; - */ - #define BMAP_ALLOC 0x0001 - #define BMAP_SET 0x0002 -+#define BMAP_UNINIT 0x0004 -+#define BMAP_ZERO 0x0008 - - /* - * Returned flags from ext2fs_bmap -@@ -537,13 +554,6 @@ typedef struct ext2_icount *ext2_icount_t; - #define EXT2_CHECK_MAGIC(struct, code) \ - if ((struct)->magic != (code)) return (code) - -- --/* -- * For ext2 compression support -- */ --#define EXT2FS_COMPRESSED_BLKADDR ((blk_t) -1) --#define HOLE_BLKADDR(_b) ((_b) == 0 || (_b) == EXT2FS_COMPRESSED_BLKADDR) -- - /* - * Features supported by this version of the library - */ -@@ -555,34 +565,23 @@ typedef struct ext2_icount *ext2_icount_t; - EXT2_FEATURE_COMPAT_EXT_ATTR|\ - EXT4_FEATURE_COMPAT_SPARSE_SUPER2) - --/* This #ifdef is temporary until compression is fully supported */ --#ifdef ENABLE_COMPRESSION --#ifndef I_KNOW_THAT_COMPRESSION_IS_EXPERIMENTAL --/* If the below warning bugs you, then have -- `CPPFLAGS=-DI_KNOW_THAT_COMPRESSION_IS_EXPERIMENTAL' in your -- 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) -+#ifdef CONFIG_MMP -+#define EXT4_LIB_INCOMPAT_MMP EXT4_FEATURE_INCOMPAT_MMP - #else -+#define EXT4_LIB_INCOMPAT_MMP (0) -+#endif -+ - #define EXT2_LIB_FEATURE_INCOMPAT_SUPP (EXT2_FEATURE_INCOMPAT_FILETYPE|\ - 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|\ -+ EXT4_FEATURE_INCOMPAT_ENCRYPT) -+ - #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,16 +589,9 @@ 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_FEATURE_RO_COMPAT_QUOTA|\ -+ EXT4_FEATURE_RO_COMPAT_METADATA_CSUM|\ -+ EXT4_FEATURE_RO_COMPAT_READONLY) - - /* - * These features are only allowed if EXT2_FLAG_SOFTSUPP_FEATURES is passed -@@ -632,8 +624,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) -@@ -667,6 +672,29 @@ extern void ext2fs_set_alloc_block_callback(ext2_filsys fs, - errcode_t (**old)(ext2_filsys fs, - blk64_t goal, - blk64_t *ret)); -+blk64_t ext2fs_find_inode_goal(ext2_filsys fs, ext2_ino_t ino, -+ struct ext2_inode *inode, blk64_t lblk); -+extern void ext2fs_set_new_range_callback(ext2_filsys fs, -+ errcode_t (*func)(ext2_filsys fs, int flags, blk64_t goal, -+ blk64_t len, blk64_t *pblk, blk64_t *plen), -+ errcode_t (**old)(ext2_filsys fs, int flags, blk64_t goal, -+ blk64_t len, blk64_t *pblk, blk64_t *plen)); -+extern void ext2fs_set_block_alloc_stats_range_callback(ext2_filsys fs, -+ void (*func)(ext2_filsys fs, blk64_t blk, -+ blk_t num, int inuse), -+ void (**old)(ext2_filsys fs, blk64_t blk, -+ blk_t num, int inuse)); -+#define EXT2_NEWRANGE_FIXED_GOAL (0x1) -+#define EXT2_NEWRANGE_MIN_LENGTH (0x2) -+#define EXT2_NEWRANGE_ALL_FLAGS (0x3) -+errcode_t ext2fs_new_range(ext2_filsys fs, int flags, blk64_t goal, -+ blk64_t len, ext2fs_block_bitmap map, blk64_t *pblk, -+ blk64_t *plen); -+#define EXT2_ALLOCRANGE_FIXED_GOAL (0x1) -+#define EXT2_ALLOCRANGE_ZERO_BLOCKS (0x2) -+#define EXT2_ALLOCRANGE_ALL_FLAGS (0x3) -+errcode_t ext2fs_alloc_range(ext2_filsys fs, int flags, blk64_t goal, -+ blk_t len, blk64_t *ret); - - /* alloc_sb.c */ - extern int ext2fs_reserve_super_and_bgd(ext2_filsys fs, -@@ -809,6 +837,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 +866,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 +982,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); -@@ -976,11 +1055,17 @@ extern void ext2fs_dblist_sort2(ext2_dblist dblist, - extern errcode_t ext2fs_dblist_iterate(ext2_dblist dblist, - int (*func)(ext2_filsys fs, struct ext2_db_entry *db_info, - void *priv_data), -- void *priv_data); -+ void *priv_data); - extern errcode_t ext2fs_dblist_iterate2(ext2_dblist dblist, - int (*func)(ext2_filsys fs, struct ext2_db_entry2 *db_info, - void *priv_data), -- void *priv_data); -+ void *priv_data); -+extern errcode_t ext2fs_dblist_iterate3(ext2_dblist dblist, -+ int (*func)(ext2_filsys fs, struct ext2_db_entry2 *db_info, -+ void *priv_data), -+ unsigned long long start, -+ unsigned long long count, -+ void *priv_data); - extern errcode_t ext2fs_set_dir_block(ext2_dblist dblist, ext2_ino_t ino, - blk_t blk, int blockcnt); - extern errcode_t ext2fs_set_dir_block2(ext2_dblist dblist, ext2_ino_t ino, -@@ -1009,6 +1094,13 @@ extern errcode_t - void *priv_data), - void *priv_data); - -+#if 0 -+/* digest_encode.c */ -+#define EXT2FS_DIGEST_SIZE EXT2FS_SHA256_LENGTH -+extern int ext2fs_digest_encode(const char *src, int len, char *dst); -+extern int ext2fs_digest_decode(const char *src, int len, char *dst); -+#endif -+ - /* dirblock.c */ - extern errcode_t ext2fs_read_dir_block(ext2_filsys fs, blk_t block, - void *buf); -@@ -1016,12 +1108,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 +1168,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); -@@ -1109,6 +1235,17 @@ extern errcode_t ext2fs_extent_goto(ext2_extent_handle_t handle, - extern errcode_t ext2fs_extent_goto2(ext2_extent_handle_t handle, - int leaf_level, blk64_t blk); - extern errcode_t ext2fs_extent_fix_parents(ext2_extent_handle_t handle); -+size_t ext2fs_max_extent_depth(ext2_extent_handle_t handle); -+ -+/* fallocate.c */ -+#define EXT2_FALLOCATE_ZERO_BLOCKS (0x1) -+#define EXT2_FALLOCATE_FORCE_INIT (0x2) -+#define EXT2_FALLOCATE_FORCE_UNINIT (0x4) -+#define EXT2_FALLOCATE_INIT_BEYOND_EOF (0x8) -+#define EXT2_FALLOCATE_ALL_FLAGS (0xF) -+errcode_t ext2fs_fallocate(ext2_filsys fs, int flags, ext2_ino_t ino, -+ struct ext2_inode *inode, blk64_t goal, -+ blk64_t start, blk64_t len); - - /* fileio.c */ - extern errcode_t ext2fs_file_open2(ext2_filsys fs, ext2_ino_t ino, -@@ -1190,10 +1327,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 +1355,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,12 +1419,27 @@ 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, - struct ext2_inode *inode, - int bufsize); -+#define EXT2_INODE_SCAN_DEFAULT_BUFFER_BLOCKS 8 - extern errcode_t ext2fs_open_inode_scan(ext2_filsys fs, int buffer_blocks, - ext2_inode_scan *ret_scan); - extern void ext2fs_close_inode_scan(ext2_inode_scan scan); -@@ -1359,6 +1510,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, -@@ -1414,7 +1567,7 @@ errcode_t ext2fs_unlink(ext2_filsys fs, ext2_ino_t dir, const char *name, - - /* symlink.c */ - errcode_t ext2fs_symlink(ext2_filsys fs, ext2_ino_t parent, ext2_ino_t ino, -- const char *name, char *target); -+ const char *name, const char *target); - - /* mmp.c */ - errcode_t ext2fs_mmp_read(ext2_filsys fs, blk64_t mmp_blk, void *buf); -@@ -1423,6 +1576,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); - -@@ -1446,7 +1600,25 @@ extern errcode_t ext2fs_read_bb_FILE(ext2_filsys fs, FILE *f, - /* res_gdt.c */ - extern errcode_t ext2fs_create_resize_inode(ext2_filsys fs); - -+/*sha256.c */ -+#define EXT2FS_SHA256_LENGTH 32 -+#if 0 -+extern void ext2fs_sha256(const unsigned char *in, unsigned long in_size, -+ unsigned char out[EXT2FS_SHA256_LENGTH]); -+#endif -+ -+/* sha512.c */ -+#define EXT2FS_SHA512_LENGTH 64 -+extern void ext2fs_sha512(const unsigned char *in, unsigned long in_size, -+ unsigned char out[EXT2FS_SHA512_LENGTH]); -+ - /* 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 +1658,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, -@@ -1513,6 +1686,11 @@ extern blk_t ext2fs_inode_data_blocks(ext2_filsys fs, - struct ext2_inode *inode); - extern unsigned int ext2fs_div_ceil(unsigned int a, unsigned int b); - extern __u64 ext2fs_div64_ceil(__u64 a, __u64 b); -+extern int ext2fs_dirent_name_len(const struct ext2_dir_entry *entry); -+extern void ext2fs_dirent_set_name_len(struct ext2_dir_entry *entry, int len); -+extern int ext2fs_dirent_file_type(const struct ext2_dir_entry *entry); -+extern void ext2fs_dirent_set_file_type(struct ext2_dir_entry *entry, int type); -+ - #endif - - /* -@@ -1536,6 +1714,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 - /* -@@ -1566,7 +1754,7 @@ _INLINE_ errcode_t ext2fs_get_memzero(unsigned long size, void *ptr) - - _INLINE_ errcode_t ext2fs_get_array(unsigned long count, unsigned long size, void *ptr) - { -- if (count && (-1UL)/countname_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 - -diff --git a/lib/ext2fs/ext2fsP.h b/lib/ext2fs/ext2fsP.h -index a88db93..8de9d33 100644 ---- a/lib/ext2fs/ext2fsP.h -+++ b/lib/ext2fs/ext2fsP.h -@@ -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); -@@ -145,3 +169,8 @@ extern int ext2fs_mem_is_zero(const char *mem, size_t len); - extern int ext2fs_file_block_offset_too_big(ext2_filsys fs, - struct ext2_inode *inode, - blk64_t offset); -+ -+/* atexit support */ -+typedef void (*ext2_exit_fn)(void *); -+errcode_t ext2fs_add_exit_fn(ext2_exit_fn fn, void *data); -+errcode_t ext2fs_remove_exit_fn(ext2_exit_fn fn, void *data); -diff --git a/lib/ext2fs/ext3_extents.h b/lib/ext2fs/ext3_extents.h -index fcf4d86..f73a332 100644 ---- a/lib/ext2fs/ext3_extents.h -+++ b/lib/ext2fs/ext3_extents.h -@@ -19,14 +19,25 @@ - */ - - /* -+ * 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 { -+ __le32 et_checksum; /* crc32c(uuid+inum+extent_block) */ -+}; -+ -+/* - * this is extent on-disk structure - * it's used at the bottom of the tree - */ - struct ext3_extent { -- __u32 ee_block; /* first logical block extent covers */ -- __u16 ee_len; /* number of blocks covered by extent */ -- __u16 ee_start_hi; /* high 16 bits of physical block */ -- __u32 ee_start; /* low 32 bigs of physical block */ -+ __le32 ee_block; /* first logical block extent covers */ -+ __le16 ee_len; /* number of blocks covered by extent */ -+ __le16 ee_start_hi; /* high 16 bits of physical block */ -+ __le32 ee_start; /* low 32 bigs of physical block */ - }; - - /* -@@ -34,22 +45,22 @@ struct ext3_extent { - * it's used at all the levels, but the bottom - */ - struct ext3_extent_idx { -- __u32 ei_block; /* index covers logical blocks from 'block' */ -- __u32 ei_leaf; /* pointer to the physical block of the next * -+ __le32 ei_block; /* index covers logical blocks from 'block' */ -+ __le32 ei_leaf; /* pointer to the physical block of the next * - * level. leaf or next index could bet here */ -- __u16 ei_leaf_hi; /* high 16 bits of physical block */ -- __u16 ei_unused; -+ __le16 ei_leaf_hi; /* high 16 bits of physical block */ -+ __le16 ei_unused; - }; - - /* - * each block (leaves and indexes), even inode-stored has header - */ - struct ext3_extent_header { -- __u16 eh_magic; /* probably will support different formats */ -- __u16 eh_entries; /* number of valid entries */ -- __u16 eh_max; /* capacity of store in entries */ -- __u16 eh_depth; /* has tree real underlaying blocks? */ -- __u32 eh_generation; /* generation of the tree */ -+ __le16 eh_magic; /* probably will support different formats */ -+ __le16 eh_entries; /* number of valid entries */ -+ __le16 eh_max; /* capacity of store in entries */ -+ __le16 eh_depth; /* has tree real underlaying blocks? */ -+ __le32 eh_generation; /* generation of the tree */ - }; - - #define EXT3_EXT_MAGIC 0xf30a -@@ -87,6 +98,8 @@ struct ext3_ext_path { - */ - #define EXT_INIT_MAX_LEN (1UL << 15) - #define EXT_UNINIT_MAX_LEN (EXT_INIT_MAX_LEN - 1) -+#define EXT_MAX_EXTENT_LBLK (((__u64) 1 << 32) - 1) -+#define EXT_MAX_EXTENT_PBLK (((__u64) 1 << 48) - 1) - - #define EXT_FIRST_EXTENT(__hdr__) \ - ((struct ext3_extent *) (((char *) (__hdr__)) + \ -diff --git a/lib/ext2fs/ext_attr.c b/lib/ext2fs/ext_attr.c -index 1889824..bb950aa 100644 ---- a/lib/ext2fs/ext_attr.c -+++ b/lib/ext2fs/ext_attr.c -@@ -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,926 @@ 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}, -+}; -+ -+/* Push empty attributes to the end and inlinedata to the front. */ -+static int attr_compare(const void *a, const void *b) -+{ -+ const struct ext2_xattr *xa = a, *xb = b; -+ -+ if (xa->name == NULL) -+ return +1; -+ else if (xb->name == NULL) -+ return -1; -+ else if (!strcmp(xa->name, "system.data")) -+ return -1; -+ else if (!strcmp(xb->name, "system.data")) -+ return +1; -+ return 0; -+} -+ -+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(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; -+ blk64_t blk; -+ 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; -+ 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 */ -+ goal = ext2fs_find_inode_goal(fs, ino, (struct ext2_inode *)inode, 0); -+ 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, -+ int write_hash) -+{ -+ struct ext2_xattr *x = *pos; -+ struct ext2_ext_attr_entry *e = entries_start; -+ char *end = (char *) 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 ((char *)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 - (char *)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((char *)e + sizeof(*e), shortname, e->e_name_len); -+ memcpy(end, x->value, e->e_value_size); -+ -+ if (write_hash) -+ e->e_hash = ext2fs_ext_attr_hash_entry(e, end); -+ else -+ e->e_hash = 0; -+ -+ 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; -+ char *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; -+ -+ /* If extra_isize isn't set, we need to set it now */ -+ if (inode->i_extra_isize == 0 && -+ EXT2_INODE_SIZE(handle->fs->super) > EXT2_GOOD_OLD_INODE_SIZE) { -+ char *p = (char *)inode; -+ size_t extra = handle->fs->super->s_want_extra_isize; -+ -+ if (extra == 0) -+ extra = sizeof(__u32); -+ memset(p + EXT2_GOOD_OLD_INODE_SIZE, 0, extra); -+ inode->i_extra_isize = extra; -+ } -+ -+ /* -+ * Force the inlinedata attr to the front and the empty entries -+ * to the end. -+ */ -+ x = handle->attrs; -+ qsort(x, handle->length, sizeof(struct ext2_xattr), attr_compare); -+ -+ /* Does the inode have space for EA? */ -+ if (inode->i_extra_isize < sizeof(inode->i_extra_isize) || -+ 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, 0); -+ if (err) -+ goto out; -+ -+write_ea_block: -+ /* Are we done? */ -+ if (x >= handle->attrs + handle->count) -+ goto skip_ea_block; -+ -+ /* Write the EA block */ -+ err = ext2fs_get_memzero(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, -+ start - block_buf, 1); -+ 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 = (struct ext2_ext_attr_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, -+ char *value_start, -+ size_t *nr_read) -+{ -+ struct ext2_xattr *x; -+ struct ext2_ext_attr_entry *entry, *end; -+ const char *prefix; -+ unsigned int remain, prefix_len; -+ errcode_t err; -+ unsigned int values_size = storage_size + -+ ((char *)entries - value_start); -+ -+ x = handle->attrs; -+ while (x->name) -+ x++; -+ -+ /* find the end */ -+ end = entries; -+ remain = storage_size; -+ while (remain >= sizeof(struct ext2_ext_attr_entry) && -+ !EXT2_EXT_IS_LAST_ENTRY(end)) { -+ -+ /* header eats this space */ -+ remain -= sizeof(struct ext2_ext_attr_entry); -+ -+ /* is attribute name valid? */ -+ if (EXT2_EXT_ATTR_SIZE(end->e_name_len) > remain) -+ return EXT2_ET_EA_BAD_NAME_LEN; -+ -+ /* attribute len eats this space */ -+ remain -= EXT2_EXT_ATTR_SIZE(end->e_name_len); -+ end = EXT2_EXT_ATTR_NEXT(end); -+ } -+ -+ 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); -+ -+ /* 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; -+ -+ if (entry->e_value_size > 0 && -+ value_start + entry->e_value_offs < -+ (char *)end + sizeof(__u32)) -+ 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, -+ (char *)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_inode_large *inode; -+ struct ext2_ext_attr_header *header; -+ __u32 ea_inode_magic; -+ unsigned int storage_size; -+ char *start, *block_buf = NULL; -+ blk64_t blk; -+ size_t 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 space for EA? */ -+ if (inode->i_extra_isize < sizeof(inode->i_extra_isize) || -+ 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, -+ (struct ext2_ext_attr_entry *) 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, -+ (struct ext2_ext_attr_entry *) 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; -+ 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; -+ char *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_entry *entry; -+ struct ext2_inode_large *inode; -+ __u32 ea_inode_magic; -+ unsigned int minoff; -+ char *start; -+ size_t 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 */ -+ start= ((char *) inode) + EXT2_GOOD_OLD_INODE_SIZE + -+ inode->i_extra_isize + sizeof(__u32); -+ entry = (struct ext2_ext_attr_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; -+ -+ 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; - } -diff --git a/lib/ext2fs/extent.c b/lib/ext2fs/extent.c -index c12bc93..a9cdae7 100644 ---- a/lib/ext2fs/extent.c -+++ b/lib/ext2fs/extent.c -@@ -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) - { -@@ -909,6 +934,25 @@ static errcode_t extent_node_split(ext2_extent_handle_t handle, - orig_height = info.max_depth - info.curr_level; - orig_lblk = extent.e_lblk; - -+ /* Try to put the index block before the first extent */ -+ path = handle->path + handle->level; -+ eh = (struct ext3_extent_header *) path->buf; -+ if (handle->level == handle->max_depth) { -+ struct ext3_extent *ex; -+ -+ ex = EXT_FIRST_EXTENT(eh); -+ goal_blk = ext2fs_le32_to_cpu(ex->ee_start) + -+ ((__u64) ext2fs_le16_to_cpu(ex->ee_start_hi) << 32); -+ } else { -+ struct ext3_extent_idx *ix; -+ -+ ix = EXT_FIRST_INDEX(eh); -+ goal_blk = ext2fs_le32_to_cpu(ix->ei_leaf) + -+ ((__u64) ext2fs_le16_to_cpu(ix->ei_leaf_hi) << 32); -+ } -+ goal_blk -= EXT2FS_CLUSTER_RATIO(handle->fs); -+ goal_blk &= ~EXT2FS_CLUSTER_MASK(handle->fs); -+ - /* Is there room in the parent for a new entry? */ - if (handle->level && - (handle->path[handle->level - 1].entries >= -@@ -922,7 +966,6 @@ static errcode_t extent_node_split(ext2_extent_handle_t handle, - retval = ext2fs_extent_get(handle, EXT2_EXTENT_UP, &extent); - if (retval) - goto done; -- goal_blk = extent.e_pblk; - - retval = extent_node_split(handle, expand_allowed); - if (retval) -@@ -954,13 +997,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; -@@ -989,14 +1030,9 @@ static errcode_t extent_node_split(ext2_extent_handle_t handle, - goto done; - } - -- if (!goal_blk) { -- dgrp_t group = ext2fs_group_of_ino(handle->fs, handle->ino); -- __u8 log_flex = handle->fs->super->s_log_groups_per_flex; -- -- if (log_flex) -- group = group & ~((1 << (log_flex)) - 1); -- goal_blk = ext2fs_group_first_block2(handle->fs, group); -- } -+ if (!goal_blk) -+ goal_blk = ext2fs_find_inode_goal(handle->fs, handle->ino, -+ handle->inode, 0); - retval = ext2fs_alloc_block2(handle->fs, goal_blk, block_buf, - &new_node_pblk); - if (retval) -@@ -1024,6 +1060,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 +1077,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 +1466,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 +1517,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); -@@ -1483,18 +1536,18 @@ errcode_t ext2fs_extent_set_bmap(ext2_extent_handle_t handle, - if (retval) - goto done; - } else { -- __u32 orig_length; -- blk64_t orig_lblk; -- struct ext2fs_extent orig_extent; -+ __u32 save_length; -+ blk64_t save_lblk; -+ struct ext2fs_extent save_extent; - errcode_t r2; - - #ifdef DEBUG - printf("(re/un)mapping in middle of extent\n"); - #endif - /* need to split this extent; later */ -- orig_lblk = extent.e_lblk; -- orig_length = extent.e_len; -- orig_extent = extent; -+ save_lblk = extent.e_lblk; -+ save_length = extent.e_len; -+ save_extent = extent; - - /* shorten pre-split extent */ - extent.e_len = (logical - extent.e_lblk); -@@ -1507,17 +1560,17 @@ errcode_t ext2fs_extent_set_bmap(ext2_extent_handle_t handle, - retval = ext2fs_extent_insert(handle, - EXT2_EXTENT_INSERT_AFTER, &newextent); - if (retval) { -- r2 = ext2fs_extent_goto(handle, orig_lblk); -+ r2 = ext2fs_extent_goto(handle, save_lblk); - if (r2 == 0) -- ext2fs_extent_replace(handle, 0, -- &orig_extent); -+ (void)ext2fs_extent_replace(handle, 0, -+ &save_extent); - goto done; - } - } - /* add post-split extent */ - extent.e_pblk += extent.e_len + 1; - extent.e_lblk += extent.e_len + 1; -- extent.e_len = orig_length - extent.e_len - 1; -+ extent.e_len = save_length - extent.e_len - 1; - retval = ext2fs_extent_insert(handle, - EXT2_EXTENT_INSERT_AFTER, &extent); - if (retval) { -@@ -1525,11 +1578,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); -+ r2 = ext2fs_extent_goto(handle, save_lblk); - if (r2 == 0) -- ext2fs_extent_replace(handle, 0, &orig_extent); -+ (void)ext2fs_extent_replace(handle, 0, -+ &save_extent); - goto done; - } - } -@@ -1610,8 +1664,10 @@ errcode_t ext2fs_extent_delete(ext2_extent_handle_t handle, int flags) - } else { - eh = (struct ext3_extent_header *) path->buf; - eh->eh_entries = ext2fs_cpu_to_le16(path->entries); -- if ((path->entries == 0) && (handle->level == 0)) -- eh->eh_depth = handle->max_depth = 0; -+ if ((path->entries == 0) && (handle->level == 0)) { -+ eh->eh_depth = 0; -+ handle->max_depth = 0; -+ } - retval = update_path(handle); - } - return retval; -@@ -1641,14 +1697,46 @@ errcode_t ext2fs_extent_get_info(ext2_extent_handle_t handle, - - info->curr_level = handle->level; - info->max_depth = handle->max_depth; -- info->max_lblk = ((__u64) 1 << 32) - 1; -- info->max_pblk = ((__u64) 1 << 48) - 1; -- info->max_len = (1UL << 15); -- info->max_uninit_len = (1UL << 15) - 1; -+ info->max_lblk = EXT_MAX_EXTENT_LBLK; -+ info->max_pblk = EXT_MAX_EXTENT_PBLK; -+ info->max_len = EXT_INIT_MAX_LEN; -+ info->max_uninit_len = EXT_UNINIT_MAX_LEN; - - return 0; - } - -+static int ul_log2(unsigned long arg) -+{ -+ int l = 0; -+ -+ arg >>= 1; -+ while (arg) { -+ l++; -+ arg >>= 1; -+ } -+ return l; -+} -+ -+size_t ext2fs_max_extent_depth(ext2_extent_handle_t handle) -+{ -+ size_t iblock_sz = sizeof(((struct ext2_inode *)NULL)->i_block); -+ size_t iblock_extents = (iblock_sz - sizeof(struct ext3_extent_header)) / -+ sizeof(struct ext3_extent); -+ size_t extents_per_block = (handle->fs->blocksize - -+ sizeof(struct ext3_extent_header)) / -+ sizeof(struct ext3_extent); -+ static unsigned int last_blocksize = 0; -+ static size_t last_result = 0; -+ -+ if (last_blocksize && last_blocksize == handle->fs->blocksize) -+ return last_result; -+ -+ last_result = 1 + ((ul_log2(EXT_MAX_EXTENT_LBLK) - ul_log2(iblock_extents)) / -+ ul_log2(extents_per_block)); -+ last_blocksize = handle->fs->blocksize; -+ return last_result; -+} -+ - #ifdef DEBUG - /* - * Override debugfs's prompt -diff --git a/lib/ext2fs/fallocate.c b/lib/ext2fs/fallocate.c -new file mode 100644 -index 0000000..01c709a ---- /dev/null -+++ b/lib/ext2fs/fallocate.c -@@ -0,0 +1,858 @@ -+/* -+ * fallocate.c -- Allocate large chunks of file. -+ * -+ * 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% -+ */ -+ -+#include "config.h" -+ -+#if HAVE_SYS_TYPES_H -+#include -+#endif -+ -+#include "ext2_fs.h" -+#include "ext2fs.h" -+#define min(a, b) ((a) < (b) ? (a) : (b)) -+ -+#undef DEBUG -+ -+#ifdef DEBUG -+# define dbg_printf(f, a...) do {printf(f, ## a); fflush(stdout); } while (0) -+#else -+# define dbg_printf(f, a...) -+#endif -+ -+/* -+ * Extent-based fallocate code. -+ * -+ * Find runs of unmapped logical blocks by starting at start and walking the -+ * extents until we reach the end of the range we want. -+ * -+ * For each run of unmapped blocks, try to find the extents on either side of -+ * the range. If there's a left extent that can grow by at least a cluster and -+ * there are lblocks between start and the next lcluster after start, see if -+ * there's an implied cluster allocation; if so, zero the blocks (if the left -+ * extent is initialized) and adjust the extent. Ditto for the blocks between -+ * the end of the last full lcluster and end, if there's a right extent. -+ * -+ * Try to attach as much as we can to the left extent, then try to attach as -+ * much as we can to the right extent. For the remainder, try to allocate the -+ * whole range; map in whatever we get; and repeat until we're done. -+ * -+ * To attach to a left extent, figure out the maximum amount we can add to the -+ * extent and try to allocate that much, and append if successful. To attach -+ * to a right extent, figure out the max we can add to the extent, try to -+ * allocate that much, and prepend if successful. -+ * -+ * We need an alloc_range function that tells us how much we can allocate given -+ * a maximum length and one of a suggested start, a fixed start, or a fixed end -+ * point. -+ * -+ * Every time we modify the extent tree we also need to update the block stats. -+ * -+ * At the end, update i_blocks and i_size appropriately. -+ */ -+ -+static void dbg_print_extent(const char *desc EXT2FS_ATTR((unused)), -+ const struct ext2fs_extent *extent EXT2FS_ATTR((unused))) -+{ -+#ifdef DEBUG -+ if (desc) -+ printf("%s: ", desc); -+ printf("extent: lblk %llu--%llu, len %u, pblk %llu, flags: ", -+ extent->e_lblk, extent->e_lblk + extent->e_len - 1, -+ extent->e_len, extent->e_pblk); -+ if (extent->e_flags & EXT2_EXTENT_FLAGS_LEAF) -+ fputs("LEAF ", stdout); -+ if (extent->e_flags & EXT2_EXTENT_FLAGS_UNINIT) -+ fputs("UNINIT ", stdout); -+ if (extent->e_flags & EXT2_EXTENT_FLAGS_SECOND_VISIT) -+ fputs("2ND_VISIT ", stdout); -+ if (!extent->e_flags) -+ fputs("(none)", stdout); -+ fputc('\n', stdout); -+ fflush(stdout); -+#endif -+} -+ -+static errcode_t claim_range(ext2_filsys fs, struct ext2_inode *inode, -+ blk64_t blk, blk64_t len) -+{ -+ blk64_t clusters; -+ -+ clusters = (len + EXT2FS_CLUSTER_RATIO(fs) - 1) / -+ EXT2FS_CLUSTER_RATIO(fs); -+ ext2fs_block_alloc_stats_range(fs, blk, -+ clusters * EXT2FS_CLUSTER_RATIO(fs), +1); -+ return ext2fs_iblk_add_blocks(fs, inode, clusters); -+} -+ -+static errcode_t ext_falloc_helper(ext2_filsys fs, -+ int flags, -+ ext2_ino_t ino, -+ struct ext2_inode *inode, -+ ext2_extent_handle_t handle, -+ struct ext2fs_extent *left_ext, -+ struct ext2fs_extent *right_ext, -+ blk64_t range_start, blk64_t range_len, -+ blk64_t alloc_goal) -+{ -+ struct ext2fs_extent newex, ex; -+ int op; -+ blk64_t fillable, pblk, plen, x, y; -+ blk64_t eof_blk = 0, cluster_fill = 0; -+ errcode_t err; -+ blk_t max_extent_len, max_uninit_len, max_init_len; -+ -+#ifdef DEBUG -+ printf("%s: ", __func__); -+ if (left_ext) -+ printf("left_ext=%llu--%llu, ", left_ext->e_lblk, -+ left_ext->e_lblk + left_ext->e_len - 1); -+ if (right_ext) -+ printf("right_ext=%llu--%llu, ", right_ext->e_lblk, -+ right_ext->e_lblk + right_ext->e_len - 1); -+ printf("start=%llu len=%llu, goal=%llu\n", range_start, range_len, -+ alloc_goal); -+ fflush(stdout); -+#endif -+ /* Can't create initialized extents past EOF? */ -+ if (!(flags & EXT2_FALLOCATE_INIT_BEYOND_EOF)) -+ eof_blk = EXT2_I_SIZE(inode) / fs->blocksize; -+ -+ /* The allocation goal must be as far into a cluster as range_start. */ -+ alloc_goal = (alloc_goal & ~EXT2FS_CLUSTER_MASK(fs)) | -+ (range_start & EXT2FS_CLUSTER_MASK(fs)); -+ -+ max_uninit_len = EXT_UNINIT_MAX_LEN & ~EXT2FS_CLUSTER_MASK(fs); -+ max_init_len = EXT_INIT_MAX_LEN & ~EXT2FS_CLUSTER_MASK(fs); -+ -+ /* We must lengthen the left extent to the end of the cluster */ -+ if (left_ext && EXT2FS_CLUSTER_RATIO(fs) > 1) { -+ /* How many more blocks can be attached to left_ext? */ -+ if (left_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT) -+ fillable = max_uninit_len - left_ext->e_len; -+ else -+ fillable = max_init_len - left_ext->e_len; -+ -+ if (fillable > range_len) -+ fillable = range_len; -+ if (fillable == 0) -+ goto expand_right; -+ -+ /* -+ * If range_start isn't on a cluster boundary, try an -+ * implied cluster allocation for left_ext. -+ */ -+ cluster_fill = EXT2FS_CLUSTER_RATIO(fs) - -+ (range_start & EXT2FS_CLUSTER_MASK(fs)); -+ cluster_fill &= EXT2FS_CLUSTER_MASK(fs); -+ if (cluster_fill == 0) -+ goto expand_right; -+ -+ if (cluster_fill > fillable) -+ cluster_fill = fillable; -+ -+ /* Don't expand an initialized left_ext beyond EOF */ -+ if (!(flags & EXT2_FALLOCATE_INIT_BEYOND_EOF)) { -+ x = left_ext->e_lblk + left_ext->e_len - 1; -+ dbg_printf("%s: lend=%llu newlend=%llu eofblk=%llu\n", -+ __func__, x, x + cluster_fill, eof_blk); -+ if (eof_blk >= x && eof_blk <= x + cluster_fill) -+ cluster_fill = eof_blk - x; -+ if (cluster_fill == 0) -+ goto expand_right; -+ } -+ -+ err = ext2fs_extent_goto(handle, left_ext->e_lblk); -+ if (err) -+ goto expand_right; -+ left_ext->e_len += cluster_fill; -+ range_start += cluster_fill; -+ range_len -= cluster_fill; -+ alloc_goal += cluster_fill; -+ -+ dbg_print_extent("ext_falloc clus left+", left_ext); -+ err = ext2fs_extent_replace(handle, 0, left_ext); -+ if (err) -+ goto out; -+ err = ext2fs_extent_fix_parents(handle); -+ if (err) -+ goto out; -+ -+ /* Zero blocks */ -+ if (!(left_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT)) { -+ err = ext2fs_zero_blocks2(fs, left_ext->e_pblk + -+ left_ext->e_len - -+ cluster_fill, cluster_fill, -+ NULL, NULL); -+ if (err) -+ goto out; -+ } -+ } -+ -+expand_right: -+ /* We must lengthen the right extent to the beginning of the cluster */ -+ if (right_ext && EXT2FS_CLUSTER_RATIO(fs) > 1) { -+ /* How much can we attach to right_ext? */ -+ if (right_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT) -+ fillable = max_uninit_len - right_ext->e_len; -+ else -+ fillable = max_init_len - right_ext->e_len; -+ -+ if (fillable > range_len) -+ fillable = range_len; -+ if (fillable == 0) -+ goto try_merge; -+ -+ /* -+ * If range_end isn't on a cluster boundary, try an implied -+ * cluster allocation for right_ext. -+ */ -+ cluster_fill = right_ext->e_lblk & EXT2FS_CLUSTER_MASK(fs); -+ if (cluster_fill == 0) -+ goto try_merge; -+ -+ err = ext2fs_extent_goto(handle, right_ext->e_lblk); -+ if (err) -+ goto out; -+ -+ if (cluster_fill > fillable) -+ cluster_fill = fillable; -+ right_ext->e_lblk -= cluster_fill; -+ right_ext->e_pblk -= cluster_fill; -+ right_ext->e_len += cluster_fill; -+ range_len -= cluster_fill; -+ -+ dbg_print_extent("ext_falloc clus right+", right_ext); -+ err = ext2fs_extent_replace(handle, 0, right_ext); -+ if (err) -+ goto out; -+ err = ext2fs_extent_fix_parents(handle); -+ if (err) -+ goto out; -+ -+ /* Zero blocks if necessary */ -+ if (!(right_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT)) { -+ err = ext2fs_zero_blocks2(fs, right_ext->e_pblk, -+ cluster_fill, NULL, NULL); -+ if (err) -+ goto out; -+ } -+ } -+ -+try_merge: -+ /* Merge both extents together, perhaps? */ -+ if (left_ext && right_ext) { -+ /* Are the two extents mergeable? */ -+ if ((left_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT) != -+ (right_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT)) -+ goto try_left; -+ -+ /* User requires init/uninit but extent is uninit/init. */ -+ if (((flags & EXT2_FALLOCATE_FORCE_INIT) && -+ (left_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT)) || -+ ((flags & EXT2_FALLOCATE_FORCE_UNINIT) && -+ !(left_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT))) -+ goto try_left; -+ -+ /* -+ * Skip initialized extent unless user wants to zero blocks -+ * or requires init extent. -+ */ -+ if (!(left_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT) && -+ (!(flags & EXT2_FALLOCATE_ZERO_BLOCKS) || -+ !(flags & EXT2_FALLOCATE_FORCE_INIT))) -+ goto try_left; -+ -+ /* Will it even fit? */ -+ x = left_ext->e_len + range_len + right_ext->e_len; -+ if (x > (left_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT ? -+ max_uninit_len : max_init_len)) -+ goto try_left; -+ -+ err = ext2fs_extent_goto(handle, left_ext->e_lblk); -+ if (err) -+ goto try_left; -+ -+ /* Allocate blocks */ -+ y = left_ext->e_pblk + left_ext->e_len; -+ err = ext2fs_new_range(fs, EXT2_NEWRANGE_FIXED_GOAL | -+ EXT2_NEWRANGE_MIN_LENGTH, y, -+ right_ext->e_pblk - y + 1, NULL, -+ &pblk, &plen); -+ if (err) -+ goto try_left; -+ if (pblk + plen != right_ext->e_pblk) -+ goto try_left; -+ err = claim_range(fs, inode, pblk, plen); -+ if (err) -+ goto out; -+ -+ /* Modify extents */ -+ left_ext->e_len = x; -+ dbg_print_extent("ext_falloc merge", left_ext); -+ err = ext2fs_extent_replace(handle, 0, left_ext); -+ if (err) -+ goto out; -+ err = ext2fs_extent_fix_parents(handle); -+ if (err) -+ goto out; -+ err = ext2fs_extent_get(handle, EXT2_EXTENT_NEXT_LEAF, &newex); -+ if (err) -+ goto out; -+ err = ext2fs_extent_delete(handle, 0); -+ if (err) -+ goto out; -+ err = ext2fs_extent_fix_parents(handle); -+ if (err) -+ goto out; -+ *right_ext = *left_ext; -+ -+ /* Zero blocks */ -+ if (!(left_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT) && -+ (flags & EXT2_FALLOCATE_ZERO_BLOCKS)) { -+ err = ext2fs_zero_blocks2(fs, range_start, range_len, -+ NULL, NULL); -+ if (err) -+ goto out; -+ } -+ -+ return 0; -+ } -+ -+try_left: -+ /* Extend the left extent */ -+ if (left_ext) { -+ /* How many more blocks can be attached to left_ext? */ -+ if (left_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT) -+ fillable = max_uninit_len - left_ext->e_len; -+ else if (flags & EXT2_FALLOCATE_ZERO_BLOCKS) -+ fillable = max_init_len - left_ext->e_len; -+ else -+ fillable = 0; -+ -+ /* User requires init/uninit but extent is uninit/init. */ -+ if (((flags & EXT2_FALLOCATE_FORCE_INIT) && -+ (left_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT)) || -+ ((flags & EXT2_FALLOCATE_FORCE_UNINIT) && -+ !(left_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT))) -+ goto try_right; -+ -+ if (fillable > range_len) -+ fillable = range_len; -+ -+ /* Don't expand an initialized left_ext beyond EOF */ -+ x = left_ext->e_lblk + left_ext->e_len - 1; -+ if (!(flags & EXT2_FALLOCATE_INIT_BEYOND_EOF)) { -+ dbg_printf("%s: lend=%llu newlend=%llu eofblk=%llu\n", -+ __func__, x, x + fillable, eof_blk); -+ if (eof_blk >= x && eof_blk <= x + fillable) -+ fillable = eof_blk - x; -+ } -+ -+ if (fillable == 0) -+ goto try_right; -+ -+ /* Test if the right edge of the range is already mapped? */ -+ if (EXT2FS_CLUSTER_RATIO(fs) > 1) { -+ err = ext2fs_map_cluster_block(fs, ino, inode, -+ x + fillable, &pblk); -+ if (err) -+ goto out; -+ if (pblk) -+ fillable -= 1 + ((x + fillable) -+ & EXT2FS_CLUSTER_MASK(fs)); -+ if (fillable == 0) -+ goto try_right; -+ } -+ -+ /* Allocate range of blocks */ -+ x = left_ext->e_pblk + left_ext->e_len; -+ err = ext2fs_new_range(fs, EXT2_NEWRANGE_FIXED_GOAL | -+ EXT2_NEWRANGE_MIN_LENGTH, -+ x, fillable, NULL, &pblk, &plen); -+ if (err) -+ goto try_right; -+ err = claim_range(fs, inode, pblk, plen); -+ if (err) -+ goto out; -+ -+ /* Modify left_ext */ -+ err = ext2fs_extent_goto(handle, left_ext->e_lblk); -+ if (err) -+ goto out; -+ range_start += plen; -+ range_len -= plen; -+ left_ext->e_len += plen; -+ dbg_print_extent("ext_falloc left+", left_ext); -+ err = ext2fs_extent_replace(handle, 0, left_ext); -+ if (err) -+ goto out; -+ err = ext2fs_extent_fix_parents(handle); -+ if (err) -+ goto out; -+ -+ /* Zero blocks if necessary */ -+ if (!(left_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT) && -+ (flags & EXT2_FALLOCATE_ZERO_BLOCKS)) { -+ err = ext2fs_zero_blocks2(fs, pblk, plen, NULL, NULL); -+ if (err) -+ goto out; -+ } -+ } -+ -+try_right: -+ /* Extend the right extent */ -+ if (right_ext) { -+ /* How much can we attach to right_ext? */ -+ if (right_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT) -+ fillable = max_uninit_len - right_ext->e_len; -+ else if (flags & EXT2_FALLOCATE_ZERO_BLOCKS) -+ fillable = max_init_len - right_ext->e_len; -+ else -+ fillable = 0; -+ -+ /* User requires init/uninit but extent is uninit/init. */ -+ if (((flags & EXT2_FALLOCATE_FORCE_INIT) && -+ (right_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT)) || -+ ((flags & EXT2_FALLOCATE_FORCE_UNINIT) && -+ !(right_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT))) -+ goto try_anywhere; -+ -+ if (fillable > range_len) -+ fillable = range_len; -+ if (fillable == 0) -+ goto try_anywhere; -+ -+ /* Test if the left edge of the range is already mapped? */ -+ if (EXT2FS_CLUSTER_RATIO(fs) > 1) { -+ err = ext2fs_map_cluster_block(fs, ino, inode, -+ right_ext->e_lblk - fillable, &pblk); -+ if (err) -+ goto out; -+ if (pblk) -+ fillable -= EXT2FS_CLUSTER_RATIO(fs) - -+ ((right_ext->e_lblk - fillable) -+ & EXT2FS_CLUSTER_MASK(fs)); -+ if (fillable == 0) -+ goto try_anywhere; -+ } -+ -+ /* -+ * FIXME: It would be nice if we could handle allocating a -+ * variable range from a fixed end point instead of just -+ * skipping to the general allocator if the whole range is -+ * unavailable. -+ */ -+ err = ext2fs_new_range(fs, EXT2_NEWRANGE_FIXED_GOAL | -+ EXT2_NEWRANGE_MIN_LENGTH, -+ right_ext->e_pblk - fillable, -+ fillable, NULL, &pblk, &plen); -+ if (err) -+ goto try_anywhere; -+ err = claim_range(fs, inode, -+ pblk & ~EXT2FS_CLUSTER_MASK(fs), -+ plen + (pblk & EXT2FS_CLUSTER_MASK(fs))); -+ if (err) -+ goto out; -+ -+ /* Modify right_ext */ -+ err = ext2fs_extent_goto(handle, right_ext->e_lblk); -+ if (err) -+ goto out; -+ range_len -= plen; -+ right_ext->e_lblk -= plen; -+ right_ext->e_pblk -= plen; -+ right_ext->e_len += plen; -+ dbg_print_extent("ext_falloc right+", right_ext); -+ err = ext2fs_extent_replace(handle, 0, right_ext); -+ if (err) -+ goto out; -+ err = ext2fs_extent_fix_parents(handle); -+ if (err) -+ goto out; -+ -+ /* Zero blocks if necessary */ -+ if (!(right_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT) && -+ (flags & EXT2_FALLOCATE_ZERO_BLOCKS)) { -+ err = ext2fs_zero_blocks2(fs, pblk, -+ plen + cluster_fill, NULL, NULL); -+ if (err) -+ goto out; -+ } -+ } -+ -+try_anywhere: -+ /* Try implied cluster alloc on the left and right ends */ -+ if (range_len > 0 && (range_start & EXT2FS_CLUSTER_MASK(fs))) { -+ cluster_fill = EXT2FS_CLUSTER_RATIO(fs) - -+ (range_start & EXT2FS_CLUSTER_MASK(fs)); -+ cluster_fill &= EXT2FS_CLUSTER_MASK(fs); -+ if (cluster_fill > range_len) -+ cluster_fill = range_len; -+ newex.e_lblk = range_start; -+ err = ext2fs_map_cluster_block(fs, ino, inode, newex.e_lblk, -+ &pblk); -+ if (err) -+ goto out; -+ if (pblk == 0) -+ goto try_right_implied; -+ newex.e_pblk = pblk; -+ newex.e_len = cluster_fill; -+ newex.e_flags = (flags & EXT2_FALLOCATE_FORCE_INIT ? 0 : -+ EXT2_EXTENT_FLAGS_UNINIT); -+ dbg_print_extent("ext_falloc iclus left+", &newex); -+ ext2fs_extent_goto(handle, newex.e_lblk); -+ err = ext2fs_extent_get(handle, EXT2_EXTENT_CURRENT, -+ &ex); -+ if (err == EXT2_ET_NO_CURRENT_NODE) -+ ex.e_lblk = 0; -+ else if (err) -+ goto out; -+ -+ if (ex.e_lblk > newex.e_lblk) -+ op = 0; /* insert before */ -+ else -+ op = EXT2_EXTENT_INSERT_AFTER; -+ dbg_printf("%s: inserting %s lblk %llu newex=%llu\n", -+ __func__, op ? "after" : "before", ex.e_lblk, -+ newex.e_lblk); -+ err = ext2fs_extent_insert(handle, op, &newex); -+ if (err) -+ goto out; -+ err = ext2fs_extent_fix_parents(handle); -+ if (err) -+ goto out; -+ -+ if (!(newex.e_flags & EXT2_EXTENT_FLAGS_UNINIT) && -+ (flags & EXT2_FALLOCATE_ZERO_BLOCKS)) { -+ err = ext2fs_zero_blocks2(fs, newex.e_pblk, -+ newex.e_len, NULL, NULL); -+ if (err) -+ goto out; -+ } -+ -+ range_start += cluster_fill; -+ range_len -= cluster_fill; -+ } -+ -+try_right_implied: -+ y = range_start + range_len; -+ if (range_len > 0 && (y & EXT2FS_CLUSTER_MASK(fs))) { -+ cluster_fill = y & EXT2FS_CLUSTER_MASK(fs); -+ if (cluster_fill > range_len) -+ cluster_fill = range_len; -+ newex.e_lblk = y & ~EXT2FS_CLUSTER_MASK(fs); -+ err = ext2fs_map_cluster_block(fs, ino, inode, newex.e_lblk, -+ &pblk); -+ if (err) -+ goto out; -+ if (pblk == 0) -+ goto no_implied; -+ newex.e_pblk = pblk; -+ newex.e_len = cluster_fill; -+ newex.e_flags = (flags & EXT2_FALLOCATE_FORCE_INIT ? 0 : -+ EXT2_EXTENT_FLAGS_UNINIT); -+ dbg_print_extent("ext_falloc iclus right+", &newex); -+ ext2fs_extent_goto(handle, newex.e_lblk); -+ err = ext2fs_extent_get(handle, EXT2_EXTENT_CURRENT, -+ &ex); -+ if (err == EXT2_ET_NO_CURRENT_NODE) -+ ex.e_lblk = 0; -+ else if (err) -+ goto out; -+ -+ if (ex.e_lblk > newex.e_lblk) -+ op = 0; /* insert before */ -+ else -+ op = EXT2_EXTENT_INSERT_AFTER; -+ dbg_printf("%s: inserting %s lblk %llu newex=%llu\n", -+ __func__, op ? "after" : "before", ex.e_lblk, -+ newex.e_lblk); -+ err = ext2fs_extent_insert(handle, op, &newex); -+ if (err) -+ goto out; -+ err = ext2fs_extent_fix_parents(handle); -+ if (err) -+ goto out; -+ -+ if (!(newex.e_flags & EXT2_EXTENT_FLAGS_UNINIT) && -+ (flags & EXT2_FALLOCATE_ZERO_BLOCKS)) { -+ err = ext2fs_zero_blocks2(fs, newex.e_pblk, -+ newex.e_len, NULL, NULL); -+ if (err) -+ goto out; -+ } -+ -+ range_len -= cluster_fill; -+ } -+ -+no_implied: -+ if (range_len == 0) -+ return 0; -+ -+ newex.e_lblk = range_start; -+ if (flags & EXT2_FALLOCATE_FORCE_INIT) { -+ max_extent_len = max_init_len; -+ newex.e_flags = 0; -+ } else { -+ max_extent_len = max_uninit_len; -+ newex.e_flags = EXT2_EXTENT_FLAGS_UNINIT; -+ } -+ pblk = alloc_goal; -+ y = range_len; -+ for (x = 0; x < y;) { -+ cluster_fill = newex.e_lblk & EXT2FS_CLUSTER_MASK(fs); -+ fillable = min(range_len + cluster_fill, max_extent_len); -+ err = ext2fs_new_range(fs, 0, pblk & ~EXT2FS_CLUSTER_MASK(fs), -+ fillable, -+ NULL, &pblk, &plen); -+ if (err) -+ goto out; -+ err = claim_range(fs, inode, pblk, plen); -+ if (err) -+ goto out; -+ -+ /* Create extent */ -+ newex.e_pblk = pblk + cluster_fill; -+ newex.e_len = plen - cluster_fill; -+ dbg_print_extent("ext_falloc create", &newex); -+ ext2fs_extent_goto(handle, newex.e_lblk); -+ err = ext2fs_extent_get(handle, EXT2_EXTENT_CURRENT, -+ &ex); -+ if (err == EXT2_ET_NO_CURRENT_NODE) -+ ex.e_lblk = 0; -+ else if (err) -+ goto out; -+ -+ if (ex.e_lblk > newex.e_lblk) -+ op = 0; /* insert before */ -+ else -+ op = EXT2_EXTENT_INSERT_AFTER; -+ dbg_printf("%s: inserting %s lblk %llu newex=%llu\n", -+ __func__, op ? "after" : "before", ex.e_lblk, -+ newex.e_lblk); -+ err = ext2fs_extent_insert(handle, op, &newex); -+ if (err) -+ goto out; -+ err = ext2fs_extent_fix_parents(handle); -+ if (err) -+ goto out; -+ -+ if (!(newex.e_flags & EXT2_EXTENT_FLAGS_UNINIT) && -+ (flags & EXT2_FALLOCATE_ZERO_BLOCKS)) { -+ err = ext2fs_zero_blocks2(fs, pblk, plen, NULL, NULL); -+ if (err) -+ goto out; -+ } -+ -+ /* Update variables at end of loop */ -+ x += plen - cluster_fill; -+ range_len -= plen - cluster_fill; -+ newex.e_lblk += plen - cluster_fill; -+ pblk += plen - cluster_fill; -+ if (pblk >= ext2fs_blocks_count(fs->super)) -+ pblk = fs->super->s_first_data_block; -+ } -+ -+out: -+ return err; -+} -+ -+static errcode_t extent_fallocate(ext2_filsys fs, int flags, ext2_ino_t ino, -+ struct ext2_inode *inode, blk64_t goal, -+ blk64_t start, blk64_t len) -+{ -+ ext2_extent_handle_t handle; -+ struct ext2fs_extent left_extent, right_extent; -+ struct ext2fs_extent *left_adjacent, *right_adjacent; -+ errcode_t err; -+ blk64_t range_start, range_end = 0, end, next; -+ blk64_t count, goal_distance; -+ -+ end = start + len - 1; -+ err = ext2fs_extent_open2(fs, ino, inode, &handle); -+ if (err) -+ return err; -+ -+ /* -+ * Find the extent closest to the start of the alloc range. We don't -+ * check the return value because _goto() sets the current node to the -+ * next-lowest extent if 'start' is in a hole; or the next-highest -+ * extent if there aren't any lower ones; or doesn't set a current node -+ * if there was a real error reading the extent tree. In that case, -+ * _get() will error out. -+ */ -+start_again: -+ ext2fs_extent_goto(handle, start); -+ err = ext2fs_extent_get(handle, EXT2_EXTENT_CURRENT, &left_extent); -+ if (err == EXT2_ET_NO_CURRENT_NODE) { -+ blk64_t max_blocks = ext2fs_blocks_count(fs->super); -+ -+ if (goal == ~0ULL) -+ goal = ext2fs_find_inode_goal(fs, ino, inode, start); -+ err = ext2fs_find_first_zero_block_bitmap2(fs->block_map, -+ goal, max_blocks - 1, &goal); -+ goal += start; -+ err = ext_falloc_helper(fs, flags, ino, inode, handle, NULL, -+ NULL, start, len, goal); -+ goto errout; -+ } else if (err) -+ goto errout; -+ -+ dbg_print_extent("ext_falloc initial", &left_extent); -+ next = left_extent.e_lblk + left_extent.e_len; -+ if (left_extent.e_lblk > start) { -+ /* The nearest extent we found was beyond start??? */ -+ goal = left_extent.e_pblk - (left_extent.e_lblk - start); -+ err = ext_falloc_helper(fs, flags, ino, inode, handle, NULL, -+ &left_extent, start, -+ left_extent.e_lblk - start, goal); -+ if (err) -+ goto errout; -+ -+ goto start_again; -+ } else if (next >= start) { -+ range_start = next; -+ left_adjacent = &left_extent; -+ } else { -+ range_start = start; -+ left_adjacent = NULL; -+ } -+ goal = left_extent.e_pblk + (range_start - left_extent.e_lblk); -+ goal_distance = range_start - next; -+ -+ do { -+ err = ext2fs_extent_get(handle, EXT2_EXTENT_NEXT_LEAF, -+ &right_extent); -+ dbg_printf("%s: ino=%d get next =%d\n", __func__, ino, -+ (int)err); -+ dbg_print_extent("ext_falloc next", &right_extent); -+ /* Stop if we've seen this extent before */ -+ if (!err && right_extent.e_lblk <= left_extent.e_lblk) -+ err = EXT2_ET_EXTENT_NO_NEXT; -+ -+ if (err && err != EXT2_ET_EXTENT_NO_NEXT) -+ goto errout; -+ if (err == EXT2_ET_EXTENT_NO_NEXT || -+ right_extent.e_lblk > end + 1) { -+ range_end = end; -+ right_adjacent = NULL; -+ } else { -+ /* Handle right_extent.e_lblk <= end */ -+ range_end = right_extent.e_lblk - 1; -+ right_adjacent = &right_extent; -+ } -+ if (err != EXT2_ET_EXTENT_NO_NEXT && -+ goal_distance > (range_end - right_extent.e_lblk)) { -+ goal = right_extent.e_pblk - -+ (right_extent.e_lblk - range_start); -+ goal_distance = range_end - right_extent.e_lblk; -+ } -+ -+ dbg_printf("%s: ino=%d rstart=%llu rend=%llu\n", __func__, ino, -+ range_start, range_end); -+ err = 0; -+ if (range_start <= range_end) { -+ count = range_end - range_start + 1; -+ err = ext_falloc_helper(fs, flags, ino, inode, handle, -+ left_adjacent, right_adjacent, -+ range_start, count, goal); -+ if (err) -+ goto errout; -+ } -+ -+ if (range_end == end) -+ break; -+ -+ err = ext2fs_extent_goto(handle, right_extent.e_lblk); -+ if (err) -+ goto errout; -+ next = right_extent.e_lblk + right_extent.e_len; -+ left_extent = right_extent; -+ left_adjacent = &left_extent; -+ range_start = next; -+ goal = left_extent.e_pblk + (range_start - left_extent.e_lblk); -+ goal_distance = range_start - next; -+ } while (range_end < end); -+ -+errout: -+ ext2fs_extent_free(handle); -+ return err; -+} -+ -+/* -+ * Map physical blocks to a range of logical blocks within a file. The range -+ * of logical blocks are (start, start + len). If there are already extents, -+ * the mappings will try to extend the mappings; otherwise, it will try to map -+ * start as if logical block 0 points to goal. If goal is ~0ULL, then the goal -+ * is calculated based on the inode group. -+ * -+ * Flags: -+ * - EXT2_FALLOCATE_ZERO_BLOCKS: Zero the blocks that are allocated. -+ * - EXT2_FALLOCATE_FORCE_INIT: Create only initialized extents. -+ * - EXT2_FALLOCATE_FORCE_UNINIT: Create only uninitialized extents. -+ * - EXT2_FALLOCATE_INIT_BEYOND_EOF: Create extents beyond EOF. -+ * -+ * If neither FORCE_INIT nor FORCE_UNINIT are specified, this function will -+ * try to expand any extents it finds, zeroing blocks as necessary. -+ */ -+errcode_t ext2fs_fallocate(ext2_filsys fs, int flags, ext2_ino_t ino, -+ struct ext2_inode *inode, blk64_t goal, -+ blk64_t start, blk64_t len) -+{ -+ struct ext2_inode inode_buf; -+ blk64_t blk, x; -+ errcode_t err; -+ -+ if (((flags & EXT2_FALLOCATE_FORCE_INIT) && -+ (flags & EXT2_FALLOCATE_FORCE_UNINIT)) || -+ (flags & ~EXT2_FALLOCATE_ALL_FLAGS)) -+ return EXT2_ET_INVALID_ARGUMENT; -+ -+ if (len > ext2fs_blocks_count(fs->super)) -+ return EXT2_ET_BLOCK_ALLOC_FAIL; -+ else if (len == 0) -+ return 0; -+ -+ /* Read inode structure if necessary */ -+ if (!inode) { -+ err = ext2fs_read_inode(fs, ino, &inode_buf); -+ if (err) -+ return err; -+ inode = &inode_buf; -+ } -+ dbg_printf("%s: ino=%d start=%llu len=%llu goal=%llu\n", __func__, ino, -+ start, len, goal); -+ -+ if (inode->i_flags & EXT4_EXTENTS_FL) { -+ err = extent_fallocate(fs, flags, ino, inode, goal, start, len); -+ goto out; -+ } -+ -+ /* XXX: Allocate a bunch of blocks the slow way */ -+ for (blk = start; blk < start + len; blk++) { -+ err = ext2fs_bmap2(fs, ino, inode, NULL, 0, blk, 0, &x); -+ if (err) -+ return err; -+ if (x) -+ continue; -+ -+ err = ext2fs_bmap2(fs, ino, inode, NULL, -+ BMAP_ALLOC | BMAP_UNINIT | BMAP_ZERO, blk, -+ 0, &x); -+ if (err) -+ return err; -+ } -+ -+out: -+ if (inode == &inode_buf) -+ ext2fs_write_inode(fs, ino, inode); -+ return err; -+} -diff --git a/lib/ext2fs/fileio.c b/lib/ext2fs/fileio.c -index 0ddb245..810a7fd 100644 ---- a/lib/ext2fs/fileio.c -+++ b/lib/ext2fs/fileio.c -@@ -123,6 +123,8 @@ errcode_t ext2fs_file_flush(ext2_file_t file) - { - errcode_t retval; - ext2_filsys fs; -+ int ret_flags; -+ blk64_t dontcare; - - EXT2_CHECK_MAGIC(file, EXT2_ET_MAGIC_EXT2_FILE); - fs = file->fs; -@@ -131,6 +133,22 @@ errcode_t ext2fs_file_flush(ext2_file_t file) - !(file->flags & EXT2_FILE_BUF_DIRTY)) - return 0; - -+ /* Is this an uninit block? */ -+ if (file->physblock && file->inode.i_flags & EXT4_EXTENTS_FL) { -+ retval = ext2fs_bmap2(fs, file->ino, &file->inode, BMAP_BUFFER, -+ 0, file->blockno, &ret_flags, &dontcare); -+ if (retval) -+ return retval; -+ if (ret_flags & BMAP_RET_UNINIT) { -+ retval = ext2fs_bmap2(fs, file->ino, &file->inode, -+ BMAP_BUFFER, BMAP_SET, -+ file->blockno, 0, -+ &file->physblock); -+ if (retval) -+ return retval; -+ } -+ } -+ - /* - * OK, the physical block hasn't been allocated yet. - * Allocate it. -@@ -185,15 +203,17 @@ static errcode_t load_buffer(ext2_file_t file, int dontfill) - { - ext2_filsys fs = file->fs; - errcode_t retval; -+ int ret_flags; - - if (!(file->flags & EXT2_FILE_BUF_VALID)) { - retval = ext2fs_bmap2(fs, file->ino, &file->inode, -- BMAP_BUFFER, 0, file->blockno, 0, -+ BMAP_BUFFER, 0, file->blockno, &ret_flags, - &file->physblock); - if (retval) - return retval; - if (!dontfill) { -- if (file->physblock) { -+ if (file->physblock && -+ !(ret_flags & BMAP_RET_UNINIT)) { - retval = io_channel_read_blk64(fs->io, - file->physblock, - 1, file->buf); -@@ -224,6 +244,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 = (char *) 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 +288,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 +322,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 +396,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) -@@ -358,7 +484,7 @@ errcode_t ext2fs_file_llseek(ext2_file_t file, __u64 offset, - errcode_t ext2fs_file_lseek(ext2_file_t file, ext2_off_t offset, - int whence, ext2_off_t *ret_pos) - { -- __u64 loffset, ret_loffset; -+ __u64 loffset, ret_loffset = 0; - errcode_t retval; - - loffset = offset; -diff --git a/lib/ext2fs/freefs.c b/lib/ext2fs/freefs.c -index 1ad2d91..ea9742e 100644 ---- a/lib/ext2fs/freefs.c -+++ b/lib/ext2fs/freefs.c -@@ -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)) -@@ -63,25 +61,11 @@ void ext2fs_free(ext2_filsys fs) - - fs->magic = 0; - -+ ext2fs_zero_blocks2(NULL, 0, 0, NULL, NULL); - ext2fs_free_mem(&fs); - } - - /* -- * Free the inode cache structure -- */ --static void ext2fs_free_inode_cache(struct ext2_inode_cache *icache) --{ -- if (--icache->refcount) -- return; -- if (icache->buffer) -- ext2fs_free_mem(&icache->buffer); -- if (icache->cache) -- ext2fs_free_mem(&icache->cache); -- icache->buffer_blk = 0; -- ext2fs_free_mem(&icache); --} -- --/* - * This procedure frees a badblocks list. - */ - void ext2fs_u32_list_free(ext2_u32_list bb) -diff --git a/lib/ext2fs/gen_bitmap64.c b/lib/ext2fs/gen_bitmap64.c -index af55097..3fc7349 100644 ---- a/lib/ext2fs/gen_bitmap64.c -+++ b/lib/ext2fs/gen_bitmap64.c -@@ -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++; -diff --git a/lib/ext2fs/gen_crc32ctable.c b/lib/ext2fs/gen_crc32ctable.c -index 9996e9d..a0742ee 100644 ---- a/lib/ext2fs/gen_crc32ctable.c -+++ b/lib/ext2fs/gen_crc32ctable.c -@@ -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 \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 -index 0000000..f5644f8 ---- /dev/null -+++ b/lib/ext2fs/get_num_dirs.c -@@ -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 -+#if HAVE_UNISTD_H -+#include -+#endif -+#include -+#include -+ -+#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; -+} -+ -diff --git a/lib/ext2fs/get_pathname.c b/lib/ext2fs/get_pathname.c -index 52aea62..4c9c765 100644 ---- a/lib/ext2fs/get_pathname.c -+++ b/lib/ext2fs/get_pathname.c -@@ -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; -diff --git a/lib/ext2fs/getsectsize.c b/lib/ext2fs/getsectsize.c -index 9c3f4a2..b57bf56 100644 ---- a/lib/ext2fs/getsectsize.c -+++ b/lib/ext2fs/getsectsize.c -@@ -10,8 +10,12 @@ - * %End-Header% - */ - -+#ifndef _LARGEFILE_SOURCE - #define _LARGEFILE_SOURCE -+#endif -+#ifndef _LARGEFILE64_SOURCE - #define _LARGEFILE64_SOURCE -+#endif - - #include "config.h" - #include -diff --git a/lib/ext2fs/getsize.c b/lib/ext2fs/getsize.c -index a227155..89c33d4 100644 ---- a/lib/ext2fs/getsize.c -+++ b/lib/ext2fs/getsize.c -@@ -12,8 +12,12 @@ - * %End-Header% - */ - -+#ifndef _LARGEFILE_SOURCE - #define _LARGEFILE_SOURCE -+#endif -+#ifndef _LARGEFILE64_SOURCE - #define _LARGEFILE64_SOURCE -+#endif - - #include "config.h" - #include -diff --git a/lib/ext2fs/icount.c b/lib/ext2fs/icount.c -index a3b20f0..5e1f5c6 100644 ---- a/lib/ext2fs/icount.c -+++ b/lib/ext2fs/icount.c -@@ -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 -diff --git a/lib/ext2fs/initialize.c b/lib/ext2fs/initialize.c -index 36c94a9..75fbf8e 100644 ---- a/lib/ext2fs/initialize.c -+++ b/lib/ext2fs/initialize.c -@@ -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.c b/lib/ext2fs/inline.c -index 05da1f7..8f40394 100644 ---- a/lib/ext2fs/inline.c -+++ b/lib/ext2fs/inline.c -@@ -45,19 +45,16 @@ - errcode_t ext2fs_get_memalign(unsigned long size, - unsigned long align, void *ptr) - { -- errcode_t retval; -+ errcode_t retval = 0; - void **p = ptr; - - if (align < 8) - align = 8; - #ifdef HAVE_POSIX_MEMALIGN - retval = posix_memalign(p, align, size); -- if (retval) { -- if (retval == ENOMEM) -- return EXT2_ET_NO_MEMORY; -- return retval; -- } --#else -+ if (retval == ENOMEM) -+ return EXT2_ET_NO_MEMORY; -+#else /* !HAVE_POSIX_MEMALIGN */ - #ifdef HAVE_MEMALIGN - *p = memalign(align, size); - if (*p == NULL) { -@@ -66,7 +63,7 @@ errcode_t ext2fs_get_memalign(unsigned long size, - else - return EXT2_ET_NO_MEMORY; - } --#else -+#else /* !HAVE_MEMALIGN */ - #ifdef HAVE_VALLOC - if (align > sizeof(long long)) - *p = valloc(size); -@@ -79,9 +76,9 @@ errcode_t ext2fs_get_memalign(unsigned long size, - } - if (*p == 0) - return EXT2_ET_NO_MEMORY; --#endif --#endif -- return 0; -+#endif /* HAVE_MEMALIGN */ -+#endif /* HAVE_POSIX_MEMALIGN */ -+ return retval; - } - - #ifdef DEBUG -diff --git a/lib/ext2fs/inline_data.c b/lib/ext2fs/inline_data.c -new file mode 100644 -index 0000000..3a81eb0 ---- /dev/null -+++ b/lib/ext2fs/inline_data.c -@@ -0,0 +1,854 @@ -+/* -+ * inline_data.c --- data in inode -+ * -+ * Copyright (C) 2012 Zheng Liu -+ * -+ * %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 -+#include -+#include /* 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; -+ char empty[1] = { '\0' }; -+ -+ data.fs = fs; -+ data.ino = ino; -+ data.ea_size = 0; -+ data.ea_data = empty; -+ 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; -+ int offset; -+ unsigned int 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 */ -+ memset(inode->i_block, 0, sizeof(inode->i_block)); -+ if (EXT2_HAS_INCOMPAT_FEATURE(fs->super, -+ EXT3_FEATURE_INCOMPAT_EXTENTS)) { -+ ext2_extent_handle_t handle; -+ -+ inode->i_flags &= ~EXT4_EXTENTS_FL; -+ retval = ext2fs_extent_open2(fs, ino, inode, &handle); -+ if (retval) -+ return retval; -+ ext2fs_extent_free(handle); -+ } -+ 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((char *) 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 = (char *) 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; -+ -+ /* 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; -+ -+ /* setup */ -+ initialize_ext2_error_table(); -+ -+ memset(¶m, 0, sizeof(param)); -+ ext2fs_blocks_count_set(¶m, 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, ¶m, -+ 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) { -+ 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 -diff --git a/lib/ext2fs/inode.c b/lib/ext2fs/inode.c -index a2f2ecd..ba7ad2c 100644 ---- a/lib/ext2fs/inode.c -+++ b/lib/ext2fs/inode.c -@@ -30,6 +30,10 @@ - #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; -@@ -60,7 +64,7 @@ struct ext2_struct_inode_scan { - */ - errcode_t ext2fs_flush_icache(ext2_filsys fs) - { -- int i; -+ unsigned i; - - if (!fs->icache) - return 0; -@@ -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) - { -+ unsigned 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) -+{ -+ unsigned 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, -@@ -143,13 +175,13 @@ errcode_t ext2fs_open_inode_scan(ext2_filsys fs, int buffer_blocks, - scan->bytes_left = 0; - scan->current_group = 0; - scan->groups_left = fs->group_desc_count - 1; -- scan->inode_buffer_blocks = buffer_blocks ? buffer_blocks : 8; -+ scan->inode_buffer_blocks = buffer_blocks ? buffer_blocks : -+ EXT2_INODE_SCAN_DEFAULT_BUFFER_BLOCKS; - scan->current_block = ext2fs_inode_table_loc(scan->fs, - 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)) { - __u32 unused = ext2fs_bg_itable_unused(fs, scan->current_group); - if (scan->inodes_left > unused) - scan->inodes_left -= unused; -@@ -169,16 +201,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; -@@ -244,8 +277,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)) { - __u32 unused = ext2fs_bg_itable_unused(fs, scan->current_group); - if (scan->inodes_left > unused) - scan->inodes_left -= unused; -@@ -329,6 +361,136 @@ 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; -+ char *p; -+ struct ext2_inode_large *inode; -+ char *block_status; -+ unsigned int blk, bad_csum; -+ -+ 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 = (char *) 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); -+ -+ if (inodes_per_block < 2) -+ return; -+ -+#ifdef WORDS_BIGENDIAN -+ if (ext2fs_get_mem(EXT2_INODE_SIZE(scan->fs->super), &inode)) -+ return; -+#endif -+ -+ while (inodes_to_scan > 0) { -+ blk = (p - (char *)scan->inode_buffer) / scan->fs->blocksize; -+ bad_csum = ext2fs_inode_csum_verify(scan->fs, ino, -+ (struct ext2_inode_large *) p) == 0; -+ -+#ifdef WORDS_BIGENDIAN -+ ext2fs_swap_inode_full(scan->fs, -+ (struct ext2_inode_large *) inode, -+ (struct ext2_inode_large *) p, -+ 0, EXT2_INODE_SIZE(scan->fs->super)); -+#else -+ inode = (struct ext2_inode_large *) p; -+#endif -+ -+ /* Is this inode insane? */ -+ if (bad_csum) { -+ 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++; -+ }; -+ -+#ifdef WORDS_BIGENDIAN -+ ext2fs_free_mem(&inode); -+#endif -+} -+ - /* - * This function is called by ext2fs_get_next_inode when it needs to - * read in more blocks from the current blockgroup's inode table. -@@ -378,12 +540,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; - } - -@@ -413,8 +578,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? -@@ -475,44 +646,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; - } - -@@ -533,8 +734,12 @@ 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; -+ unsigned i; -+ int clen, 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); - -@@ -550,18 +755,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) { -@@ -586,11 +789,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) -@@ -612,18 +814,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; - } -@@ -641,9 +851,11 @@ 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; -+ unsigned i; -+ int clen; -+ int length = EXT2_INODE_SIZE(fs->super); - - EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); - -@@ -654,48 +866,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); -@@ -708,10 +927,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) { -@@ -744,8 +959,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; - } - -diff --git a/lib/ext2fs/io_manager.c b/lib/ext2fs/io_manager.c -index 34e4859..c395d61 100644 ---- a/lib/ext2fs/io_manager.c -+++ b/lib/ext2fs/io_manager.c -@@ -112,6 +112,17 @@ errcode_t io_channel_discard(io_channel channel, unsigned long long block, - return EXT2_ET_UNIMPLEMENTED; - } - -+errcode_t io_channel_zeroout(io_channel channel, unsigned long long block, -+ unsigned long long count) -+{ -+ EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); -+ -+ if (channel->manager->zeroout) -+ return (channel->manager->zeroout)(channel, block, count); -+ -+ return EXT2_ET_UNIMPLEMENTED; -+} -+ - errcode_t io_channel_alloc_buf(io_channel io, int count, void *ptr) - { - size_t size; -@@ -128,3 +139,12 @@ errcode_t io_channel_alloc_buf(io_channel io, int count, void *ptr) - else - return ext2fs_get_mem(size, ptr); - } -+ -+errcode_t io_channel_cache_readahead(io_channel io, unsigned long long block, -+ unsigned long long count) -+{ -+ if (!io->manager->cache_readahead) -+ return EXT2_ET_OP_NOT_SUPPORTED; -+ -+ return io->manager->cache_readahead(io, block, count); -+} -diff --git a/lib/ext2fs/ismounted.c b/lib/ext2fs/ismounted.c -index 6c6ecff..b1eff85 100644 ---- a/lib/ext2fs/ismounted.c -+++ b/lib/ext2fs/ismounted.c -@@ -42,6 +42,7 @@ - #include "ext2_fs.h" - #include "ext2fs.h" - -+#ifdef HAVE_SETMNTENT - /* - * Check to see if a regular file is mounted. - * If /etc/mtab/ is a symlink of /proc/mounts, you will need the following check -@@ -72,7 +73,6 @@ static int check_loop_mounted(const char *mnt_fsname, dev_t mnt_rdev, - return 0; - } - --#ifdef HAVE_SETMNTENT - /* - * Helper function which checks a file in /etc/mtab format to see if a - * filesystem is mounted. Returns an error if the file doesn't exist -diff --git a/lib/ext2fs/jfs_compat.h b/lib/ext2fs/jfs_compat.h -index 7b8aafd..75a0596 100644 ---- a/lib/ext2fs/jfs_compat.h -+++ b/lib/ext2fs/jfs_compat.h -@@ -7,6 +7,7 @@ - #ifdef HAVE_NETINET_IN_H - #include - #endif -+#include - - #define printk printf - #define KERN_ERR "" -@@ -17,13 +18,45 @@ - - #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; -+typedef struct kdev_s *kdev_t; - - struct buffer_head; - struct inode; - -+#define GFP_KERNEL 0 -+#define JFS_TAG_SIZE32 JBD_TAG_SIZE32 -+#define JFS_BARRIER 0 -+typedef __u64 u64; -+#define JFS_CRC32_CHKSUM JBD2_CRC32_CHKSUM -+#define JFS_CRC32_CHKSUM_SIZE JBD2_CRC32_CHKSUM_SIZE -+#define put_bh(x) brelse(x) -+#define be64_to_cpu(x) ext2fs_be64_to_cpu(x) -+ -+static inline __u32 jbd2_chksum(journal_t *j EXT2FS_ATTR((unused)), -+ __u32 crc, const void *address, -+ unsigned int length) -+{ -+ return ext2fs_crc32c_le(crc, address, length); -+} -+#define crc32_be(x, y, z) ext2fs_crc32_be((x), (y), (z)) -+#define spin_lock_init(x) -+#define spin_lock(x) -+#define spin_unlock(x) -+#define yield() -+#define SLAB_HWCACHE_ALIGN 0 -+#define SLAB_TEMPORARY 0 -+#define KMEM_CACHE(__struct, __flags) kmem_cache_create(#__struct,\ -+ sizeof(struct __struct), __alignof__(struct __struct),\ -+ (__flags), NULL) -+ -+#define blkdev_issue_flush(kdev, a, b) sync_blockdev(kdev) -+#define is_power_of_2(x) ((x) != 0 && (((x) & ((x) - 1)) == 0)) -+ - struct journal_s - { - unsigned long j_flags; -@@ -44,8 +77,10 @@ struct journal_s - tid_t j_tail_sequence; - tid_t j_transaction_sequence; - __u8 j_uuid[16]; -- struct jbd_revoke_table_s *j_revoke; -+ struct jbd2_revoke_table_s *j_revoke; -+ struct jbd2_revoke_table_s *j_revoke_table[2]; - tid_t j_failed_commit; -+ __u32 j_csum_seed; - }; - - #define J_ASSERT(assert) \ -diff --git a/lib/ext2fs/jfs_user.h b/lib/ext2fs/jfs_user.h -deleted file mode 100644 -index 3a52123..0000000 ---- a/lib/ext2fs/jfs_user.h -+++ /dev/null -@@ -1,8 +0,0 @@ --#ifndef _JFS_USER_H --#define _JFS_USER_H -- --typedef unsigned short kdev_t; -- --#include "kernel-jbd.h" -- --#endif /* _JFS_USER_H */ -diff --git a/lib/ext2fs/kernel-jbd.h b/lib/ext2fs/kernel-jbd.h -index 2baae73..4653560 100644 ---- a/lib/ext2fs/kernel-jbd.h -+++ b/lib/ext2fs/kernel-jbd.h -@@ -16,19 +16,9 @@ - #ifndef _LINUX_JBD_H - #define _LINUX_JBD_H - --#if defined(CONFIG_JBD) || defined(CONFIG_JBD_MODULE) || !defined(__KERNEL__) -- --/* Allow this file to be included directly into e2fsprogs */ --#ifndef __KERNEL__ - #include "jfs_compat.h" - #define JFS_DEBUG - #define jfs_debug jbd_debug --#else -- --#include --#include --#include --#endif - - #ifndef __GNUC__ - #define __FUNCTION__ "" -@@ -73,11 +63,6 @@ extern void * __jbd_kmalloc (char *where, size_t size, int flags, int retry); - - #define JFS_MIN_JOURNAL_BLOCKS 1024 - --#ifdef __KERNEL__ --typedef struct handle_s handle_t; /* Atomic operation type */ --typedef struct journal_s journal_t; /* Journal control structure */ --#endif -- - /* - * Internal structures used by the logging mechanism: - */ -@@ -114,12 +99,28 @@ 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. -+ * -+ * If FEATURE_INCOMPAT_CSUM_V3 is set, the descriptor block uses -+ * journal_block_tag3_t to store a full 32-bit checksum. Everything else -+ * is the same as v2. -+ * -+ * Checksum v1, v2, and v3 are mutually exclusive features. - */ - struct commit_header { - __u32 h_magic; -@@ -136,15 +137,26 @@ struct commit_header { - /* - * The block tag: used to describe a single buffer in the journal - */ --typedef struct journal_block_tag_s -+typedef struct journal_block_tag3_s - { - __u32 t_blocknr; /* The on-disk block number */ - __u32 t_flags; /* See below */ - __u32 t_blocknr_high; /* most-significant high 32bits. */ -+ __u32 t_checksum; /* crc32c(uuid+seq+block) */ -+} journal_block_tag3_t; -+ -+typedef struct journal_block_tag_s -+{ -+ __u32 t_blocknr; /* The on-disk block number */ -+ __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 { -+ __be32 t_checksum; -+}; - - /* - * The revoke descriptor: used on disk to describe a series of blocks to -@@ -156,6 +168,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 { -+ __be32 r_checksum; -+}; - - /* Definitions for the journal tag flags word: */ - #define JFS_FLAG_ESCAPE 1 /* on-disk block is escaped */ -@@ -208,7 +224,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,614 +247,71 @@ 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 -+#define JFS_FEATURE_INCOMPAT_CSUM_V3 0x00000010 - - /* 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) -- --#ifdef __KERNEL__ -- --#include --#include -- --#define JBD_ASSERTIONS --#ifdef JBD_ASSERTIONS --#define J_ASSERT(assert) \ --do { \ -- if (!(assert)) { \ -- printk (KERN_EMERG \ -- "Assertion failure in %s() at %s:%d: \"%s\"\n", \ -- __FUNCTION__, __FILE__, __LINE__, # assert); \ -- BUG(); \ -- } \ --} while (0) -- --#if defined(CONFIG_BUFFER_DEBUG) --void buffer_assertion_failure(struct buffer_head *bh); --#define J_ASSERT_BH(bh, expr) \ -- do { \ -- if (!(expr)) \ -- buffer_assertion_failure(bh); \ -- J_ASSERT(expr); \ -- } while (0) --#define J_ASSERT_JH(jh, expr) J_ASSERT_BH(jh2bh(jh), expr) -+ JFS_FEATURE_INCOMPAT_64BIT|\ -+ JFS_FEATURE_INCOMPAT_CSUM_V2|\ -+ JFS_FEATURE_INCOMPAT_CSUM_V3) -+ -+#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 J_ASSERT_BH(bh, expr) J_ASSERT(expr) --#define J_ASSERT_JH(jh, expr) J_ASSERT(expr) -+#define _INLINE_ inline - #endif -- --#else --#define J_ASSERT(assert) --#endif /* JBD_ASSERTIONS */ -- --enum jbd_state_bits { -- BH_JWrite -- = BH_PrivateStart, /* 1 if being written to log (@@@ DEBUGGING) */ -- BH_Freed, /* 1 if buffer has been freed (truncated) */ -- BH_Revoked, /* 1 if buffer has been revoked from the log */ -- BH_RevokeValid, /* 1 if buffer revoked flag is valid */ -- BH_JBDDirty, /* 1 if buffer is dirty but journaled */ --}; -- --/* Return true if the buffer is one which JBD is managing */ --static inline int buffer_jbd(struct buffer_head *bh) --{ -- return __buffer_state(bh, JBD); --} -- --static inline struct buffer_head *jh2bh(struct journal_head *jh) --{ -- return jh->b_bh; --} -- --static inline struct journal_head *bh2jh(struct buffer_head *bh) --{ -- return bh->b_private; --} -- --struct jbd_revoke_table_s; -- --/* The handle_t type represents a single atomic update being performed -- * by some process. All filesystem modifications made by the process go -- * through this handle. Recursive operations (such as quota operations) -- * are gathered into a single update. -- * -- * The buffer credits field is used to account for journaled buffers -- * being modified by the running process. To ensure that there is -- * enough log space for all outstanding operations, we need to limit the -- * number of outstanding buffers possible at any time. When the -- * operation completes, any buffer credits not used are credited back to -- * the transaction, so that at all times we know how many buffers the -- * outstanding updates on a transaction might possibly touch. */ -- --struct handle_s --{ -- /* Which compound transaction is this update a part of? */ -- transaction_t * h_transaction; -- -- /* Number of remaining buffers we are allowed to dirty: */ -- int h_buffer_credits; -- -- /* Reference count on this handle */ -- int h_ref; -- -- /* Field for caller's use to track errors through large fs -- operations */ -- int h_err; -- -- /* Flags */ -- unsigned int h_sync: 1; /* sync-on-close */ -- unsigned int h_jdata: 1; /* force data journaling */ -- unsigned int h_aborted: 1; /* fatal error on handle */ --}; -- -- --/* The transaction_t type is the guts of the journaling mechanism. It -- * tracks a compound transaction through its various states: -- * -- * RUNNING: accepting new updates -- * LOCKED: Updates still running but we don't accept new ones -- * RUNDOWN: Updates are tidying up but have finished requesting -- * new buffers to modify (state not used for now) -- * FLUSH: All updates complete, but we are still writing to disk -- * COMMIT: All data on disk, writing commit record -- * FINISHED: We still have to keep the transaction for checkpointing. -- * -- * The transaction keeps track of all of the buffers modified by a -- * running transaction, and all of the buffers committed but not yet -- * flushed to home for finished transactions. -- */ -- --struct transaction_s --{ -- /* Pointer to the journal for this transaction. */ -- journal_t * t_journal; -- -- /* Sequence number for this transaction */ -- tid_t t_tid; -- -- /* Transaction's current state */ -- enum { -- T_RUNNING, -- T_LOCKED, -- T_RUNDOWN, -- T_FLUSH, -- T_COMMIT, -- T_FINISHED -- } t_state; -- -- /* Where in the log does this transaction's commit start? */ -- unsigned long t_log_start; -- -- /* Doubly-linked circular list of all inodes owned by this -- transaction */ /* AKPM: unused */ -- struct inode * t_ilist; -- -- /* Number of buffers on the t_buffers list */ -- int t_nr_buffers; -- -- /* Doubly-linked circular list of all buffers reserved but not -- yet modified by this transaction */ -- struct journal_head * t_reserved_list; -- -- /* Doubly-linked circular list of all metadata buffers owned by this -- transaction */ -- struct journal_head * t_buffers; -- -- /* -- * Doubly-linked circular list of all data buffers still to be -- * flushed before this transaction can be committed. -- * Protected by journal_datalist_lock. -- */ -- struct journal_head * t_sync_datalist; -- -- /* -- * Doubly-linked circular list of all writepage data buffers -- * still to be written before this transaction can be committed. -- * Protected by journal_datalist_lock. -- */ -- struct journal_head * t_async_datalist; -- -- /* Doubly-linked circular list of all forget buffers (superceded -- buffers which we can un-checkpoint once this transaction -- commits) */ -- struct journal_head * t_forget; -- -- /* -- * Doubly-linked circular list of all buffers still to be -- * flushed before this transaction can be checkpointed. -- */ -- /* Protected by journal_datalist_lock */ -- struct journal_head * t_checkpoint_list; -- -- /* Doubly-linked circular list of temporary buffers currently -- undergoing IO in the log */ -- struct journal_head * t_iobuf_list; -- -- /* Doubly-linked circular list of metadata buffers being -- shadowed by log IO. The IO buffers on the iobuf list and the -- shadow buffers on this list match each other one for one at -- all times. */ -- struct journal_head * t_shadow_list; -- -- /* Doubly-linked circular list of control buffers being written -- to the log. */ -- struct journal_head * t_log_list; -- -- /* Number of outstanding updates running on this transaction */ -- int t_updates; -- -- /* Number of buffers reserved for use by all handles in this -- * transaction handle but not yet modified. */ -- int t_outstanding_credits; -- -- /* -- * Forward and backward links for the circular list of all -- * transactions awaiting checkpoint. -- */ -- /* Protected by journal_datalist_lock */ -- transaction_t *t_cpnext, *t_cpprev; -- -- /* When will the transaction expire (become due for commit), in -- * jiffies ? */ -- unsigned long t_expires; -- -- /* How many handles used this transaction? */ -- int t_handle_count; --}; -- -- --/* The journal_t maintains all of the journaling state information for a -- * single filesystem. It is linked to from the fs superblock structure. -- * -- * We use the journal_t to keep track of all outstanding transaction -- * activity on the filesystem, and to manage the state of the log -- * writing process. */ -- --struct journal_s --{ -- /* General journaling state flags */ -- unsigned long j_flags; -- -- /* Is there an outstanding uncleared error on the journal (from -- * a prior abort)? */ -- int j_errno; -- -- /* The superblock buffer */ -- struct buffer_head * j_sb_buffer; -- journal_superblock_t * j_superblock; -- -- /* Version of the superblock format */ -- int j_format_version; -- -- /* Number of processes waiting to create a barrier lock */ -- int j_barrier_count; -- -- /* The barrier lock itself */ -- struct semaphore j_barrier; -- -- /* Transactions: The current running transaction... */ -- transaction_t * j_running_transaction; -- -- /* ... the transaction we are pushing to disk ... */ -- transaction_t * j_committing_transaction; -- -- /* ... and a linked circular list of all transactions waiting -- * for checkpointing. */ -- /* Protected by journal_datalist_lock */ -- transaction_t * j_checkpoint_transactions; -- -- /* Wait queue for waiting for a locked transaction to start -- committing, or for a barrier lock to be released */ -- wait_queue_head_t j_wait_transaction_locked; -- -- /* Wait queue for waiting for checkpointing to complete */ -- wait_queue_head_t j_wait_logspace; -- -- /* Wait queue for waiting for commit to complete */ -- wait_queue_head_t j_wait_done_commit; -- -- /* Wait queue to trigger checkpointing */ -- wait_queue_head_t j_wait_checkpoint; -- -- /* Wait queue to trigger commit */ -- wait_queue_head_t j_wait_commit; -- -- /* Wait queue to wait for updates to complete */ -- wait_queue_head_t j_wait_updates; -- -- /* Semaphore for locking against concurrent checkpoints */ -- struct semaphore j_checkpoint_sem; -- -- /* The main journal lock, used by lock_journal() */ -- struct semaphore j_sem; -- -- /* Journal head: identifies the first unused block in the journal. */ -- unsigned long j_head; -- -- /* Journal tail: identifies the oldest still-used block in the -- * journal. */ -- unsigned long j_tail; -- -- /* Journal free: how many free blocks are there in the journal? */ -- unsigned long j_free; -- -- /* Journal start and end: the block numbers of the first usable -- * block and one beyond the last usable block in the journal. */ -- unsigned long j_first, j_last; -- -- /* Device, blocksize and starting block offset for the location -- * where we store the journal. */ -- kdev_t j_dev; -- int j_blocksize; -- unsigned int j_blk_offset; -- -- /* Device which holds the client fs. For internal journal this -- * will be equal to j_dev. */ -- kdev_t j_fs_dev; -- -- /* Total maximum capacity of the journal region on disk. */ -- unsigned int j_maxlen; -- -- /* Optional inode where we store the journal. If present, all -- * journal block numbers are mapped into this inode via -- * bmap(). */ -- struct inode * j_inode; -- -- /* Sequence number of the oldest transaction in the log */ -- tid_t j_tail_sequence; -- /* Sequence number of the next transaction to grant */ -- tid_t j_transaction_sequence; -- /* Sequence number of the most recently committed transaction */ -- tid_t j_commit_sequence; -- /* Sequence number of the most recent transaction wanting commit */ -- tid_t j_commit_request; -- -- /* Journal uuid: identifies the object (filesystem, LVM volume -- * etc) backed by this journal. This will eventually be -- * replaced by an array of uuids, allowing us to index multiple -- * devices within a single journal and to perform atomic updates -- * across them. */ -- -- __u8 j_uuid[16]; -- -- /* Pointer to the current commit thread for this journal */ -- struct task_struct * j_task; -- -- /* Maximum number of metadata buffers to allow in a single -- * compound commit transaction */ -- int j_max_transaction_buffers; -- -- /* What is the maximum transaction lifetime before we begin a -- * commit? */ -- unsigned long j_commit_interval; -- -- /* The timer used to wakeup the commit thread: */ -- struct timer_list * j_commit_timer; -- int j_commit_timer_active; -- -- /* Link all journals together - system-wide */ -- struct list_head j_all_journals; -- -- /* The revoke table: maintains the list of revoked blocks in the -- current transaction. */ -- struct jbd_revoke_table_s *j_revoke; -- -- /* Failed journal commit ID */ -- unsigned int j_failed_commit; --}; -- --/* -- * Journal flag definitions -- */ --#define JFS_UNMOUNT 0x001 /* Journal thread is being destroyed */ --#define JFS_ABORT 0x002 /* Journaling has been aborted for errors. */ --#define JFS_ACK_ERR 0x004 /* The errno in the sb has been acked */ --#define JFS_FLUSHED 0x008 /* The journal superblock has been flushed */ --#define JFS_LOADED 0x010 /* The journal superblock has been loaded */ -- --/* -- * Function declarations for the journaling transaction and buffer -- * management -- */ -- --/* Filing buffers */ --extern void __journal_unfile_buffer(struct journal_head *); --extern void journal_unfile_buffer(struct journal_head *); --extern void __journal_refile_buffer(struct journal_head *); --extern void journal_refile_buffer(struct journal_head *); --extern void __journal_file_buffer(struct journal_head *, transaction_t *, int); --extern void __journal_free_buffer(struct journal_head *bh); --extern void journal_file_buffer(struct journal_head *, transaction_t *, int); --extern void __journal_clean_data_list(transaction_t *transaction); -- --/* Log buffer allocation */ --extern struct journal_head * journal_get_descriptor_buffer(journal_t *); --extern unsigned long journal_next_log_block(journal_t *); -- --/* Commit management */ --extern void journal_commit_transaction(journal_t *); -- --/* Checkpoint list management */ --int __journal_clean_checkpoint_list(journal_t *journal); --extern void journal_remove_checkpoint(struct journal_head *); --extern void __journal_remove_checkpoint(struct journal_head *); --extern void journal_insert_checkpoint(struct journal_head *, transaction_t *); --extern void __journal_insert_checkpoint(struct journal_head *,transaction_t *); -- --/* Buffer IO */ --extern int --journal_write_metadata_buffer(transaction_t *transaction, -- struct journal_head *jh_in, -- struct journal_head **jh_out, -- int blocknr); -- --/* Transaction locking */ --extern void __wait_on_journal (journal_t *); -+#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 */ - - /* -- * Journal locking. -- * -- * We need to lock the journal during transaction state changes so that -- * nobody ever tries to take a handle on the running transaction while -- * we are in the middle of moving it to the commit phase. -- * -- * Note that the locking is completely interrupt unsafe. We never touch -- * journal structures from interrupts. -- * -- * In 2.2, the BKL was required for lock_journal. This is no longer -- * the case. -+ * helper functions to deal with 32 or 64bit block numbers. - */ -- --static inline void lock_journal(journal_t *journal) --{ -- down(&journal->j_sem); --} -- --/* This returns zero if we acquired the semaphore */ --static inline int try_lock_journal(journal_t * journal) -+_INLINE_ size_t journal_tag_bytes(journal_t *journal) - { -- return down_trylock(&journal->j_sem); --} -+ size_t sz; - --static inline void unlock_journal(journal_t * journal) --{ -- up(&journal->j_sem); --} -+ if (JFS_HAS_INCOMPAT_FEATURE(journal, JFS_FEATURE_INCOMPAT_CSUM_V3)) -+ return sizeof(journal_block_tag3_t); - -+ sz = sizeof(journal_block_tag_t); - --static inline handle_t *journal_current_handle(void) --{ -- return current->journal_info; --} -+ if (JFS_HAS_INCOMPAT_FEATURE(journal, JFS_FEATURE_INCOMPAT_CSUM_V2)) -+ sz += sizeof(__u16); - --/* The journaling code user interface: -- * -- * Create and destroy handles -- * Register buffer modifications against the current transaction. -- */ -- --extern handle_t *journal_start(journal_t *, int nblocks); --extern handle_t *journal_try_start(journal_t *, int nblocks); --extern int journal_restart (handle_t *, int nblocks); --extern int journal_extend (handle_t *, int nblocks); --extern int journal_get_write_access (handle_t *, struct buffer_head *); --extern int journal_get_create_access (handle_t *, struct buffer_head *); --extern int journal_get_undo_access (handle_t *, struct buffer_head *); --extern int journal_dirty_data (handle_t *, -- struct buffer_head *, int async); --extern int journal_dirty_metadata (handle_t *, struct buffer_head *); --extern void journal_release_buffer (handle_t *, struct buffer_head *); --extern void journal_forget (handle_t *, struct buffer_head *); --extern void journal_sync_buffer (struct buffer_head *); --extern int journal_flushpage(journal_t *, struct page *, unsigned long); --extern int journal_try_to_free_buffers(journal_t *, struct page *, int); --extern int journal_stop(handle_t *); --extern int journal_flush (journal_t *); -- --extern void journal_lock_updates (journal_t *); --extern void journal_unlock_updates (journal_t *); -- --extern journal_t * journal_init_dev(kdev_t dev, kdev_t fs_dev, -- int start, int len, int bsize); --extern journal_t * journal_init_inode (struct inode *); --extern int journal_update_format (journal_t *); --extern int journal_check_used_features -- (journal_t *, unsigned long, unsigned long, unsigned long); --extern int journal_check_available_features -- (journal_t *, unsigned long, unsigned long, unsigned long); --extern int journal_set_features -- (journal_t *, unsigned long, unsigned long, unsigned long); --extern int journal_create (journal_t *); --extern int journal_load (journal_t *journal); --extern void journal_destroy (journal_t *); --extern int journal_recover (journal_t *journal); --extern int journal_wipe (journal_t *, int); --extern int journal_skip_recovery (journal_t *); --extern void journal_update_superblock (journal_t *, int); --extern void __journal_abort (journal_t *); --extern void journal_abort (journal_t *, int); --extern int journal_errno (journal_t *); --extern void journal_ack_err (journal_t *); --extern int journal_clear_err (journal_t *); --extern unsigned long journal_bmap(journal_t *journal, unsigned long blocknr); --extern int journal_force_commit(journal_t *journal); -+ if (JFS_HAS_INCOMPAT_FEATURE(journal, JFS_FEATURE_INCOMPAT_64BIT)) -+ return sz; - --/* -- * journal_head management -- */ --extern struct journal_head -- *journal_add_journal_head(struct buffer_head *bh); --extern void journal_remove_journal_head(struct buffer_head *bh); --extern void __journal_remove_journal_head(struct buffer_head *bh); --extern void journal_unlock_journal_head(struct journal_head *jh); -- --/* Primary revoke support */ --#define JOURNAL_REVOKE_DEFAULT_HASH 256 --extern int journal_init_revoke(journal_t *, int); --extern void journal_destroy_revoke_caches(void); --extern int journal_init_revoke_caches(void); -- --extern void journal_destroy_revoke(journal_t *); --extern int journal_revoke (handle_t *, -- unsigned long, struct buffer_head *); --extern int journal_cancel_revoke(handle_t *, struct journal_head *); --extern void journal_write_revoke_records(journal_t *, transaction_t *); -- --/* Recovery revoke support */ --extern int journal_set_revoke(journal_t *, unsigned long, tid_t); --extern int journal_test_revoke(journal_t *, unsigned long, tid_t); --extern void journal_clear_revoke(journal_t *); --extern void journal_brelse_array(struct buffer_head *b[], int n); -- --/* The log thread user interface: -- * -- * Request space in the current transaction, and force transaction commit -- * transitions on demand. -- */ -- --extern int log_space_left (journal_t *); /* Called with journal locked */ --extern tid_t log_start_commit (journal_t *, transaction_t *); --extern void log_wait_commit (journal_t *, tid_t); --extern int log_do_checkpoint (journal_t *, int); -- --extern void log_wait_for_space(journal_t *, int nblocks); --extern void __journal_drop_transaction(journal_t *, transaction_t *); --extern int cleanup_journal_tail(journal_t *); -- --/* Reduce journal memory usage by flushing */ --extern void shrink_journal_memory(void); -- --/* Debugging code only: */ -- --#define jbd_ENOSYS() \ --do { \ -- printk (KERN_ERR "JBD unimplemented function " __FUNCTION__); \ -- current->state = TASK_UNINTERRUPTIBLE; \ -- schedule(); \ --} while (1) -- --/* -- * is_journal_abort -- * -- * Simple test wrapper function to test the JFS_ABORT state flag. This -- * bit, when set, indicates that we have had a fatal error somewhere, -- * either inside the journaling layer or indicated to us by the client -- * (eg. ext3), and that we and should not commit any further -- * transactions. -- */ -- --static inline int is_journal_aborted(journal_t *journal) --{ -- return journal->j_flags & JFS_ABORT; -+ return sz - sizeof(__u32); - } - --static inline int is_handle_aborted(handle_t *handle) -+_INLINE_ int journal_has_csum_v2or3(journal_t *journal) - { -- if (handle->h_aborted) -+ if (JFS_HAS_INCOMPAT_FEATURE(journal, JFS_FEATURE_INCOMPAT_CSUM_V2) || -+ JFS_HAS_INCOMPAT_FEATURE(journal, JFS_FEATURE_INCOMPAT_CSUM_V3)) - return 1; -- return is_journal_aborted(handle->h_transaction->t_journal); --} - --static inline void journal_abort_handle(handle_t *handle) --{ -- handle->h_aborted = 1; -+ return 0; - } -- --/* Not all architectures define BUG() */ --#ifndef BUG --#define BUG() do { \ -- printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \ -- * ((char *) 0) = 0; \ -- } while (0) --#endif /* BUG */ -- --#else -- --extern int journal_recover (journal_t *journal); --extern int journal_skip_recovery (journal_t *); -- --/* Primary revoke support */ --extern int journal_init_revoke(journal_t *, int); --extern void journal_destroy_revoke_caches(void); --extern int journal_init_revoke_caches(void); -- --/* Recovery revoke support */ --extern int journal_set_revoke(journal_t *, unsigned long, tid_t); --extern int journal_test_revoke(journal_t *, unsigned long, tid_t); --extern void journal_clear_revoke(journal_t *); --extern void journal_brelse_array(struct buffer_head *b[], int n); -- --extern void journal_destroy_revoke(journal_t *); --#endif /* __KERNEL__ */ -+#undef _INLINE_ -+#endif - - static inline int tid_gt(tid_t x, tid_t y) EXT2FS_ATTR((unused)); - static inline int tid_geq(tid_t x, tid_t y) EXT2FS_ATTR((unused)); -@@ -875,82 +351,4 @@ extern int journal_blocks_per_page(struct inode *inode); - - extern int jbd_blocks_per_page(struct inode *inode); - --#ifdef __KERNEL__ -- --extern spinlock_t jh_splice_lock; --/* -- * Once `expr1' has been found true, take jh_splice_lock -- * and then reevaluate everything. -- */ --#define SPLICE_LOCK(expr1, expr2) \ -- ({ \ -- int ret = (expr1); \ -- if (ret) { \ -- spin_lock(&jh_splice_lock); \ -- ret = (expr1) && (expr2); \ -- spin_unlock(&jh_splice_lock); \ -- } \ -- ret; \ -- }) -- --/* -- * A number of buffer state predicates. They test for -- * buffer_jbd() because they are used in core kernel code. -- * -- * These will be racy on SMP unless we're *sure* that the -- * buffer won't be detached from the journalling system -- * in parallel. -- */ -- --/* Return true if the buffer is on journal list `list' */ --static inline int buffer_jlist_eq(struct buffer_head *bh, int list) --{ -- return SPLICE_LOCK(buffer_jbd(bh), bh2jh(bh)->b_jlist == list); --} -- --/* Return true if this bufer is dirty wrt the journal */ --static inline int buffer_jdirty(struct buffer_head *bh) --{ -- return buffer_jbd(bh) && __buffer_state(bh, JBDDirty); --} -- --/* Return true if it's a data buffer which journalling is managing */ --static inline int buffer_jbd_data(struct buffer_head *bh) --{ -- return SPLICE_LOCK(buffer_jbd(bh), -- bh2jh(bh)->b_jlist == BJ_SyncData || -- bh2jh(bh)->b_jlist == BJ_AsyncData); --} -- --#ifdef CONFIG_SMP --#define assert_spin_locked(lock) J_ASSERT(spin_is_locked(lock)) --#else --#define assert_spin_locked(lock) do {} while(0) --#endif -- --#define buffer_trace_init(bh) do {} while (0) --#define print_buffer_fields(bh) do {} while (0) --#define print_buffer_trace(bh) do {} while (0) --#define BUFFER_TRACE(bh, info) do {} while (0) --#define BUFFER_TRACE2(bh, bh2, info) do {} while (0) --#define JBUFFER_TRACE(jh, info) do {} while (0) -- --#endif /* __KERNEL__ */ -- --#endif /* CONFIG_JBD || CONFIG_JBD_MODULE || !__KERNEL__ */ -- --/* -- * Compatibility no-ops which allow the kernel to compile without CONFIG_JBD -- * go here. -- */ -- --#if defined(__KERNEL__) && !(defined(CONFIG_JBD) || defined(CONFIG_JBD_MODULE)) -- --#define J_ASSERT(expr) do {} while (0) --#define J_ASSERT_BH(bh, expr) do {} while (0) --#define buffer_jbd(bh) 0 --#define buffer_jlist_eq(bh, val) 0 --#define journal_buffer_journal_lru(bh) 0 -- --#endif /* defined(__KERNEL__) && !defined(CONFIG_JBD) */ - #endif /* _LINUX_JBD_H */ -diff --git a/lib/ext2fs/link.c b/lib/ext2fs/link.c -index bf3c859..09e6cb4 100644 ---- a/lib/ext2fs/link.c -+++ b/lib/ext2fs/link.c -@@ -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) -diff --git a/lib/ext2fs/llseek.c b/lib/ext2fs/llseek.c -index 2730f20..0466b59 100644 ---- a/lib/ext2fs/llseek.c -+++ b/lib/ext2fs/llseek.c -@@ -9,8 +9,12 @@ - * %End-Header% - */ - -+#ifndef _LARGEFILE_SOURCE - #define _LARGEFILE_SOURCE -+#endif -+#ifndef _LARGEFILE64_SOURCE - #define _LARGEFILE64_SOURCE -+#endif - - #include "config.h" - #if HAVE_SYS_TYPES_H -diff --git a/lib/ext2fs/lookup.c b/lib/ext2fs/lookup.c -index 0e66e71..c1d802c 100644 ---- a/lib/ext2fs/lookup.c -+++ b/lib/ext2fs/lookup.c -@@ -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++; -diff --git a/lib/ext2fs/mkdir.c b/lib/ext2fs/mkdir.c -index b12bf2d..433f3b4 100644 ---- a/lib/ext2fs/mkdir.c -+++ b/lib/ext2fs/mkdir.c -@@ -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,24 @@ 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; -+ memset(&inode, 0, sizeof(struct ext2_inode)); -+ if (!inline_data) { -+ retval = ext2fs_new_block2(fs, ext2fs_find_inode_goal(fs, ino, -+ &inode, -+ 0), -+ NULL, &blk); -+ if (retval) -+ goto cleanup; -+ } - - /* - * Create a scratch template for the directory - */ -- retval = ext2fs_new_dir_block(fs, ino, parent, &block); -+ 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 +102,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 +168,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 +181,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: -diff --git a/lib/ext2fs/mkjournal.c b/lib/ext2fs/mkjournal.c -index e6d04c4..80a1021 100644 ---- a/lib/ext2fs/mkjournal.c -+++ b/lib/ext2fs/mkjournal.c -@@ -36,7 +36,8 @@ - #include "ext2_fs.h" - #include "e2p/e2p.h" - #include "ext2fs.h" --#include "jfs_user.h" -+ -+#include "kernel-jbd.h" - - /* - * This function automatically sets up the journal superblock and -@@ -148,12 +149,13 @@ errfree: - * attempt to free the static zeroizing buffer. (This is to keep - * programs that check for memory leaks happy.) - */ --#define STRIDE_LENGTH 8 -+#define MAX_STRIDE_LENGTH (4194304 / (int) fs->blocksize) - errcode_t ext2fs_zero_blocks2(ext2_filsys fs, blk64_t blk, int num, - blk64_t *ret_blk, int *ret_count) - { - int j, count; -- static char *buf; -+ static void *buf; -+ static int stride_length; - errcode_t retval; - - /* If fs is null, clean up the static buffer and return */ -@@ -164,24 +166,41 @@ errcode_t ext2fs_zero_blocks2(ext2_filsys fs, blk64_t blk, int num, - } - return 0; - } -+ -+ /* Deal with zeroing less than 1 block */ -+ if (num <= 0) -+ return 0; -+ -+ /* Try a zero out command, if supported */ -+ retval = io_channel_zeroout(fs->io, blk, num); -+ if (retval == 0) -+ return 0; -+ - /* Allocate the zeroizing buffer if necessary */ -- if (!buf) { -- buf = malloc(fs->blocksize * STRIDE_LENGTH); -- if (!buf) -- return ENOMEM; -- memset(buf, 0, fs->blocksize * STRIDE_LENGTH); -+ if (num > stride_length && stride_length < MAX_STRIDE_LENGTH) { -+ void *p; -+ int new_stride = num; -+ -+ if (new_stride > MAX_STRIDE_LENGTH) -+ new_stride = MAX_STRIDE_LENGTH; -+ p = realloc(buf, fs->blocksize * new_stride); -+ if (!p) -+ return EXT2_ET_NO_MEMORY; -+ buf = p; -+ stride_length = new_stride; -+ memset(buf, 0, fs->blocksize * stride_length); - } - /* OK, do the write loop */ - j=0; - while (j < num) { -- if (blk % STRIDE_LENGTH) { -- count = STRIDE_LENGTH - (blk % STRIDE_LENGTH); -+ if (blk % stride_length) { -+ count = stride_length - (blk % stride_length); - if (count > (num - j)) - count = num - j; - } else { - count = num - j; -- if (count > STRIDE_LENGTH) -- count = STRIDE_LENGTH; -+ if (count > stride_length) -+ count = stride_length; - } - retval = io_channel_write_blk64(fs->io, blk, count, buf); - if (retval) { -@@ -209,89 +228,6 @@ errcode_t ext2fs_zero_blocks(ext2_filsys fs, blk_t blk, int num, - } - - /* -- * Helper function for creating the journal using direct I/O routines -- */ --struct mkjournal_struct { -- int num_blocks; -- int newblocks; -- blk64_t goal; -- blk64_t blk_to_zero; -- int zero_count; -- int flags; -- char *buf; -- errcode_t err; --}; -- --static int mkjournal_proc(ext2_filsys fs, -- blk64_t *blocknr, -- e2_blkcnt_t blockcnt, -- blk64_t ref_block EXT2FS_ATTR((unused)), -- int ref_offset EXT2FS_ATTR((unused)), -- void *priv_data) --{ -- struct mkjournal_struct *es = (struct mkjournal_struct *) priv_data; -- blk64_t new_blk; -- errcode_t retval; -- -- if (*blocknr) { -- es->goal = *blocknr; -- return 0; -- } -- if (blockcnt && -- (EXT2FS_B2C(fs, es->goal) == EXT2FS_B2C(fs, es->goal+1))) -- new_blk = es->goal+1; -- else { -- es->goal &= ~EXT2FS_CLUSTER_MASK(fs); -- retval = ext2fs_new_block2(fs, es->goal, 0, &new_blk); -- if (retval) { -- es->err = retval; -- return BLOCK_ABORT; -- } -- ext2fs_block_alloc_stats2(fs, new_blk, +1); -- es->newblocks++; -- } -- if (blockcnt >= 0) -- es->num_blocks--; -- -- retval = 0; -- if (blockcnt <= 0) -- retval = io_channel_write_blk64(fs->io, new_blk, 1, es->buf); -- else if (!(es->flags & EXT2_MKJOURNAL_LAZYINIT)) { -- if (es->zero_count) { -- if ((es->blk_to_zero + es->zero_count == new_blk) && -- (es->zero_count < 1024)) -- es->zero_count++; -- else { -- retval = ext2fs_zero_blocks2(fs, -- es->blk_to_zero, -- es->zero_count, -- 0, 0); -- es->zero_count = 0; -- } -- } -- if (es->zero_count == 0) { -- es->blk_to_zero = new_blk; -- es->zero_count = 1; -- } -- } -- -- if (blockcnt == 0) -- memset(es->buf, 0, fs->blocksize); -- -- if (retval) { -- es->err = retval; -- return BLOCK_ABORT; -- } -- *blocknr = es->goal = new_blk; -- -- if (es->num_blocks == 0) -- return (BLOCK_CHANGED | BLOCK_ABORT); -- else -- return BLOCK_CHANGED; -- --} -- --/* - * Calculate the initial goal block to be roughly at the middle of the - * filesystem. Pick a group that has the largest number of free - * blocks. -@@ -332,7 +268,8 @@ static errcode_t write_journal_inode(ext2_filsys fs, ext2_ino_t journal_ino, - errcode_t retval; - struct ext2_inode inode; - unsigned long long inode_size; -- struct mkjournal_struct es; -+ int falloc_flags = EXT2_FALLOCATE_FORCE_INIT; -+ blk64_t zblk; - - if ((retval = ext2fs_create_journal_superblock(fs, num_blocks, flags, - &buf))) -@@ -349,48 +286,38 @@ static errcode_t write_journal_inode(ext2_filsys fs, ext2_ino_t journal_ino, - goto out2; - } - -- es.num_blocks = num_blocks; -- es.newblocks = 0; -- es.buf = buf; -- es.err = 0; -- es.flags = flags; -- es.zero_count = 0; -- es.goal = (goal != ~0ULL) ? goal : get_midpoint_journal_block(fs); -+ if (goal == ~0ULL) -+ goal = get_midpoint_journal_block(fs); - -- if (fs->super->s_feature_incompat & EXT3_FEATURE_INCOMPAT_EXTENTS) { -+ if (fs->super->s_feature_incompat & EXT3_FEATURE_INCOMPAT_EXTENTS) - inode.i_flags |= EXT4_EXTENTS_FL; -- if ((retval = ext2fs_write_inode(fs, journal_ino, &inode))) -- goto out2; -- } - -- retval = ext2fs_block_iterate3(fs, journal_ino, BLOCK_FLAG_APPEND, -- 0, mkjournal_proc, &es); -- if (es.err) { -- retval = es.err; -- goto errout; -- } -- if (es.zero_count) { -- retval = ext2fs_zero_blocks2(fs, es.blk_to_zero, -- es.zero_count, 0, 0); -- if (retval) -- goto errout; -- } -- -- if ((retval = ext2fs_read_inode(fs, journal_ino, &inode))) -- goto errout; -+ if (!(flags & EXT2_MKJOURNAL_LAZYINIT)) -+ falloc_flags |= EXT2_FALLOCATE_ZERO_BLOCKS; - - inode_size = (unsigned long long)fs->blocksize * num_blocks; -- ext2fs_iblk_add_blocks(fs, &inode, es.newblocks); - inode.i_mtime = inode.i_ctime = fs->now ? fs->now : time(0); - inode.i_links_count = 1; - inode.i_mode = LINUX_S_IFREG | 0600; - retval = ext2fs_inode_size_set(fs, &inode, inode_size); - if (retval) -- goto errout; -+ goto out2; -+ -+ retval = ext2fs_fallocate(fs, falloc_flags, journal_ino, -+ &inode, goal, 0, num_blocks); -+ if (retval) -+ goto out2; - - if ((retval = ext2fs_write_new_inode(fs, journal_ino, &inode))) -- goto errout; -- retval = 0; -+ goto out2; -+ -+ retval = ext2fs_bmap2(fs, journal_ino, &inode, NULL, 0, 0, NULL, &zblk); -+ if (retval) -+ goto out2; -+ -+ retval = io_channel_write_blk64(fs->io, zblk, 1, buf); -+ if (retval) -+ goto out2; - - memcpy(fs->super->s_jnl_blocks, inode.i_block, EXT2_N_BLOCKS*4); - fs->super->s_jnl_blocks[15] = inode.i_size_high; -@@ -398,8 +325,6 @@ static errcode_t write_journal_inode(ext2_filsys fs, ext2_ino_t journal_ino, - fs->super->s_jnl_backup_type = EXT3_JNL_BACKUP_BLOCKS; - ext2fs_mark_super_dirty(fs); - --errout: -- ext2fs_zero_blocks2(0, 0, 0, 0, 0); - out2: - ext2fs_free_mem(&buf); - return retval; -@@ -488,6 +413,7 @@ errcode_t ext2fs_add_journal_device(ext2_filsys fs, ext2_filsys journal_dev) - fs->super->s_journal_dev = st.st_rdev; - memcpy(fs->super->s_journal_uuid, jsb->s_uuid, - sizeof(fs->super->s_journal_uuid)); -+ memset(fs->super->s_jnl_blocks, 0, sizeof(fs->super->s_jnl_blocks)); - fs->super->s_feature_compat |= EXT3_FEATURE_COMPAT_HAS_JOURNAL; - ext2fs_mark_super_dirty(fs); - return 0; -diff --git a/lib/ext2fs/mmp.c b/lib/ext2fs/mmp.c -index e4c7dcc..ac27837 100644 ---- a/lib/ext2fs/mmp.c -+++ b/lib/ext2fs/mmp.c -@@ -31,8 +31,14 @@ - #define O_DIRECT 0 - #endif - -+#pragma GCC diagnostic push -+#ifndef CONFIG_MMP -+#pragma GCC diagnostic ignored "-Wunused-parameter" -+#endif -+ - 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 +81,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 +100,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 +124,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 +139,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 +151,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,8 +168,12 @@ unsigned ext2fs_mmp_new_seq(void) - } while (new_seq > EXT4_MMP_SEQ_MAX); - - return new_seq; -+#else -+ return EXT2_ET_OP_NOT_SUPPORTED; -+#endif - } - -+#ifdef CONFIG_MMP - static errcode_t ext2fs_mmp_reset(ext2_filsys fs) - { - struct mmp_struct *mmp_s = NULL; -@@ -180,9 +207,16 @@ static errcode_t ext2fs_mmp_reset(ext2_filsys fs) - out: - return retval; - } -+#endif -+ -+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 +225,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 +261,9 @@ errcode_t ext2fs_mmp_init(ext2_filsys fs) - - out: - return retval; -+#else -+ return EXT2_ET_OP_NOT_SUPPORTED; -+#endif - } - - /* -@@ -230,6 +271,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 +361,9 @@ clean_seq: - - mmp_error: - return retval; -+#else -+ return EXT2_ET_OP_NOT_SUPPORTED; -+#endif - } - - /* -@@ -329,6 +374,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 +404,13 @@ mmp_error: - } - - return retval; -+#else -+ if (!(fs->super->s_feature_incompat & EXT4_FEATURE_INCOMPAT_MMP) || -+ !(fs->flags & EXT2_FLAG_RW) || (fs->flags & EXT2_FLAG_SKIP_MMP)) -+ return 0; -+ -+ return EXT2_ET_OP_NOT_SUPPORTED; -+#endif - } - - #define EXT2_MIN_MMP_UPDATE_INTERVAL 60 -@@ -365,8 +418,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 +430,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 +450,12 @@ errcode_t ext2fs_mmp_update(ext2_filsys fs) - - mmp_error: - return retval; -+#else -+ if (!(fs->super->s_feature_incompat & EXT4_FEATURE_INCOMPAT_MMP) || -+ !(fs->flags & EXT2_FLAG_RW) || (fs->flags & EXT2_FLAG_SKIP_MMP)) -+ return 0; -+ -+ return EXT2_ET_OP_NOT_SUPPORTED; -+#endif - } -+#pragma GCC diagnostic pop -diff --git a/lib/ext2fs/newdir.c b/lib/ext2fs/newdir.c -index 3e2c0db..ed250c7 100644 ---- a/lib/ext2fs/newdir.c -+++ b/lib/ext2fs/newdir.c -@@ -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,50 @@ 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 EXT2FS_ATTR((unused)), -+ ext2_ino_t parent_ino, __u32 *iblock) -+{ -+ struct ext2_dir_entry *dir = NULL; -+ errcode_t retval; -+ int rec_len; -+ -+ 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; -+} -diff --git a/lib/ext2fs/openfs.c b/lib/ext2fs/openfs.c -index ba501e6..1d6f147 100644 ---- a/lib/ext2fs/openfs.c -+++ b/lib/ext2fs/openfs.c -@@ -215,6 +215,14 @@ 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; -+ } -+ - #ifdef WORDS_BIGENDIAN - fs->flags |= EXT2_FLAG_SWAP_BYTES; - ext2fs_swap_super(fs->super); -@@ -225,10 +233,11 @@ errcode_t ext2fs_open2(const char *name, const char *io_options, - } - #endif - -- if (fs->super->s_magic != EXT2_SUPER_MAGIC) { -+ if (fs->super->s_magic != EXT2_SUPER_MAGIC) - retval = EXT2_ET_BAD_MAGIC; -+ if (retval) - goto cleanup; -- } -+ - if (fs->super->s_rev_level > EXT2_LIB_CURRENT_REV) { - retval = EXT2_ET_REV_TOO_HIGH; - goto cleanup; -@@ -295,6 +304,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 +356,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 +446,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++) { -diff --git a/lib/ext2fs/progress.c b/lib/ext2fs/progress.c -index 8c9a6f1..83556b1 100644 ---- a/lib/ext2fs/progress.c -+++ b/lib/ext2fs/progress.c -@@ -19,6 +19,12 @@ - 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; -diff --git a/lib/ext2fs/punch.c b/lib/ext2fs/punch.c -index a3d020e..db4aa19 100644 ---- a/lib/ext2fs/punch.c -+++ b/lib/ext2fs/punch.c -@@ -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,31 @@ 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 EXT2FS_ATTR((unused))) -+{ -+ 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 +481,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; -diff --git a/lib/ext2fs/qcow2.c b/lib/ext2fs/qcow2.c -index c7cdbee..4037f93 100644 ---- a/lib/ext2fs/qcow2.c -+++ b/lib/ext2fs/qcow2.c -@@ -23,8 +23,12 @@ - * %End-Header% - */ - -+#ifndef _LARGEFILE_SOURCE - #define _LARGEFILE_SOURCE -+#endif -+#ifndef _LARGEFILE64_SOURCE - #define _LARGEFILE64_SOURCE -+#endif - - #include "config.h" - #include -diff --git a/lib/ext2fs/rw_bitmaps.c b/lib/ext2fs/rw_bitmaps.c -index a07ecd5..ae593d4 100644 ---- a/lib/ext2fs/rw_bitmaps.c -+++ b/lib/ext2fs/rw_bitmaps.c -@@ -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; -diff --git a/lib/ext2fs/sha256.c b/lib/ext2fs/sha256.c -new file mode 100644 -index 0000000..103c338 ---- /dev/null -+++ b/lib/ext2fs/sha256.c -@@ -0,0 +1,255 @@ -+/* -+ * sha256.c --- The sh256 algorithm -+ * -+ * Copyright (C) 2004 Sam Hocevar -+ * (copied from libtomcrypt and then relicensed under GPLv2) -+ * -+ * %Begin-Header% -+ * This file may be redistributed under the terms of the GNU Library -+ * General Public License, version 2. -+ * %End-Header% -+ */ -+ -+ -+#include "config.h" -+#if HAVE_SYS_TYPES_H -+#include -+#endif -+#include "ext2fs.h" -+ -+static const __u32 K[64] = { -+ 0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, 0x3956c25bUL, -+ 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, 0xd807aa98UL, 0x12835b01UL, -+ 0x243185beUL, 0x550c7dc3UL, 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, -+ 0xc19bf174UL, 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL, -+ 0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, 0x983e5152UL, -+ 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, 0xc6e00bf3UL, 0xd5a79147UL, -+ 0x06ca6351UL, 0x14292967UL, 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, -+ 0x53380d13UL, 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL, -+ 0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, 0xd192e819UL, -+ 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, 0x19a4c116UL, 0x1e376c08UL, -+ 0x2748774cUL, 0x34b0bcb5UL, 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL, -+ 0x682e6ff3UL, 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL, -+ 0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL -+}; -+ -+/* Various logical functions */ -+#define Ch(x,y,z) (z ^ (x & (y ^ z))) -+#define Maj(x,y,z) (((x | y) & z) | (x & y)) -+#define S(x, n) RORc((x),(n)) -+#define R(x, n) (((x)&0xFFFFFFFFUL)>>(n)) -+#define Sigma0(x) (S(x, 2) ^ S(x, 13) ^ S(x, 22)) -+#define Sigma1(x) (S(x, 6) ^ S(x, 11) ^ S(x, 25)) -+#define Gamma0(x) (S(x, 7) ^ S(x, 18) ^ R(x, 3)) -+#define Gamma1(x) (S(x, 17) ^ S(x, 19) ^ R(x, 10)) -+#define RORc(x, y) ( ((((__u32)(x)&0xFFFFFFFFUL)>>(__u32)((y)&31)) | ((__u32)(x)<<(__u32)(32-((y)&31)))) & 0xFFFFFFFFUL) -+ -+#define RND(a,b,c,d,e,f,g,h,i) \ -+ t0 = h + Sigma1(e) + Ch(e, f, g) + K[i] + W[i]; \ -+ t1 = Sigma0(a) + Maj(a, b, c); \ -+ d += t0; \ -+ h = t0 + t1; -+ -+#define STORE64H(x, y) \ -+ do { \ -+ (y)[0] = (unsigned char)(((x)>>56)&255);\ -+ (y)[1] = (unsigned char)(((x)>>48)&255);\ -+ (y)[2] = (unsigned char)(((x)>>40)&255);\ -+ (y)[3] = (unsigned char)(((x)>>32)&255);\ -+ (y)[4] = (unsigned char)(((x)>>24)&255);\ -+ (y)[5] = (unsigned char)(((x)>>16)&255);\ -+ (y)[6] = (unsigned char)(((x)>>8)&255);\ -+ (y)[7] = (unsigned char)((x)&255); } while(0) -+ -+#define STORE32H(x, y) \ -+ do { (y)[0] = (unsigned char)(((x)>>24)&255); (y)[1] = (unsigned char)(((x)>>16)&255); \ -+ (y)[2] = (unsigned char)(((x)>>8)&255); (y)[3] = (unsigned char)((x)&255); } while(0) -+ -+#define LOAD32H(x, y) \ -+ do { x = ((__u32)((y)[0] & 255)<<24) | \ -+ ((__u32)((y)[1] & 255)<<16) | \ -+ ((__u32)((y)[2] & 255)<<8) | \ -+ ((__u32)((y)[3] & 255)); } while(0) -+ -+struct sha256_state { -+ __u64 length; -+ __u32 state[8], curlen; -+ unsigned char buf[64]; -+}; -+ -+/* This is a highly simplified version from libtomcrypt */ -+struct hash_state { -+ struct sha256_state sha256; -+}; -+ -+static void sha256_compress(struct hash_state * md, const unsigned char *buf) -+{ -+ __u32 S[8], W[64], t0, t1; -+ __u32 t; -+ int i; -+ -+ /* copy state into S */ -+ for (i = 0; i < 8; i++) { -+ S[i] = md->sha256.state[i]; -+ } -+ -+ /* copy the state into 512-bits into W[0..15] */ -+ for (i = 0; i < 16; i++) { -+ LOAD32H(W[i], buf + (4*i)); -+ } -+ -+ /* fill W[16..63] */ -+ for (i = 16; i < 64; i++) { -+ W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) + W[i - 16]; -+ } -+ -+ /* Compress */ -+ for (i = 0; i < 64; ++i) { -+ RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],i); -+ t = S[7]; S[7] = S[6]; S[6] = S[5]; S[5] = S[4]; -+ S[4] = S[3]; S[3] = S[2]; S[2] = S[1]; S[1] = S[0]; S[0] = t; -+ } -+ -+ /* feedback */ -+ for (i = 0; i < 8; i++) { -+ md->sha256.state[i] = md->sha256.state[i] + S[i]; -+ } -+} -+ -+static void sha256_init(struct hash_state * md) -+{ -+ md->sha256.curlen = 0; -+ md->sha256.length = 0; -+ md->sha256.state[0] = 0x6A09E667UL; -+ md->sha256.state[1] = 0xBB67AE85UL; -+ md->sha256.state[2] = 0x3C6EF372UL; -+ md->sha256.state[3] = 0xA54FF53AUL; -+ md->sha256.state[4] = 0x510E527FUL; -+ md->sha256.state[5] = 0x9B05688CUL; -+ md->sha256.state[6] = 0x1F83D9ABUL; -+ md->sha256.state[7] = 0x5BE0CD19UL; -+} -+ -+#define MIN(x, y) ( ((x)<(y))?(x):(y) ) -+#define SHA256_BLOCKSIZE 64 -+static void sha256_process(struct hash_state * md, const unsigned char *in, unsigned long inlen) -+{ -+ unsigned long n; -+ -+ while (inlen > 0) { -+ if (md->sha256.curlen == 0 && inlen >= SHA256_BLOCKSIZE) { -+ sha256_compress(md, in); -+ md->sha256.length += SHA256_BLOCKSIZE * 8; -+ in += SHA256_BLOCKSIZE; -+ inlen -= SHA256_BLOCKSIZE; -+ } else { -+ n = MIN(inlen, (SHA256_BLOCKSIZE - md->sha256.curlen)); -+ memcpy(md->sha256.buf + md->sha256.curlen, in, (size_t)n); -+ md->sha256.curlen += n; -+ in += n; -+ inlen -= n; -+ if (md->sha256.curlen == SHA256_BLOCKSIZE) { -+ sha256_compress(md, md->sha256.buf); -+ md->sha256.length += 8*SHA256_BLOCKSIZE; -+ md->sha256.curlen = 0; -+ } -+ } -+ } -+} -+ -+ -+static void sha256_done(struct hash_state * md, unsigned char *out) -+{ -+ int i; -+ -+ /* increase the length of the message */ -+ md->sha256.length += md->sha256.curlen * 8; -+ -+ /* append the '1' bit */ -+ md->sha256.buf[md->sha256.curlen++] = (unsigned char)0x80; -+ -+ /* if the length is currently above 56 bytes we append zeros -+ * then compress. Then we can fall back to padding zeros and length -+ * encoding like normal. -+ */ -+ if (md->sha256.curlen > 56) { -+ while (md->sha256.curlen < 64) { -+ md->sha256.buf[md->sha256.curlen++] = (unsigned char)0; -+ } -+ sha256_compress(md, md->sha256.buf); -+ md->sha256.curlen = 0; -+ } -+ -+ /* pad upto 56 bytes of zeroes */ -+ while (md->sha256.curlen < 56) { -+ md->sha256.buf[md->sha256.curlen++] = (unsigned char)0; -+ } -+ -+ /* store length */ -+ STORE64H(md->sha256.length, md->sha256.buf+56); -+ sha256_compress(md, md->sha256.buf); -+ -+ /* copy output */ -+ for (i = 0; i < 8; i++) { -+ STORE32H(md->sha256.state[i], out+(4*i)); -+ } -+} -+ -+void ext2fs_sha256(const unsigned char *in, unsigned long in_size, -+ unsigned char out[EXT2FS_SHA256_LENGTH]) -+{ -+ struct hash_state md; -+ -+ sha256_init(&md); -+ sha256_process(&md, in, in_size); -+ sha256_done(&md, out); -+} -+ -+#ifdef UNITTEST -+static const struct { -+ char *msg; -+ unsigned char hash[32]; -+} tests[] = { -+ { "", -+ { 0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, -+ 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24, -+ 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, -+ 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55 } -+ }, -+ { "abc", -+ { 0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea, -+ 0x41, 0x41, 0x40, 0xde, 0x5d, 0xae, 0x22, 0x23, -+ 0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c, -+ 0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad } -+ }, -+ { "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", -+ { 0x24, 0x8d, 0x6a, 0x61, 0xd2, 0x06, 0x38, 0xb8, -+ 0xe5, 0xc0, 0x26, 0x93, 0x0c, 0x3e, 0x60, 0x39, -+ 0xa3, 0x3c, 0xe4, 0x59, 0x64, 0xff, 0x21, 0x67, -+ 0xf6, 0xec, 0xed, 0xd4, 0x19, 0xdb, 0x06, 0xc1 } -+ }, -+}; -+ -+int main(int argc, char **argv) -+{ -+ int i; -+ int errors = 0; -+ unsigned char tmp[32]; -+ struct hash_state md; -+ -+ for (i = 0; i < (int)(sizeof(tests) / sizeof(tests[0])); i++) { -+ unsigned char *msg = (unsigned char *) tests[i].msg; -+ int len = strlen(tests[i].msg); -+ -+ ext2fs_sha256(msg, len, tmp); -+ printf("SHA256 test message %d: ", i); -+ if (memcmp(tmp, tests[i].hash, 32) != 0) { -+ printf("FAILED\n"); -+ errors++; -+ } else -+ printf("OK\n"); -+ } -+ return errors; -+} -+ -+#endif /* UNITTEST */ -diff --git a/lib/ext2fs/sha512.c b/lib/ext2fs/sha512.c -new file mode 100644 -index 0000000..f113053 ---- /dev/null -+++ b/lib/ext2fs/sha512.c -@@ -0,0 +1,303 @@ -+/* -+ * sha512.c --- The sha512 algorithm -+ * -+ * Copyright (C) 2004 Sam Hocevar -+ * (copied from libtomcrypt and then relicensed under GPLv2) -+ * -+ * %Begin-Header% -+ * This file may be redistributed under the terms of the GNU Library -+ * General Public License, version 2. -+ * %End-Header% -+ */ -+ -+ -+#include "config.h" -+#if HAVE_SYS_TYPES_H -+#include -+#endif -+#include "ext2fs.h" -+ -+/* the K array */ -+#define CONST64(n) n -+static const __u64 K[80] = { -+ CONST64(0x428a2f98d728ae22), CONST64(0x7137449123ef65cd), -+ CONST64(0xb5c0fbcfec4d3b2f), CONST64(0xe9b5dba58189dbbc), -+ CONST64(0x3956c25bf348b538), CONST64(0x59f111f1b605d019), -+ CONST64(0x923f82a4af194f9b), CONST64(0xab1c5ed5da6d8118), -+ CONST64(0xd807aa98a3030242), CONST64(0x12835b0145706fbe), -+ CONST64(0x243185be4ee4b28c), CONST64(0x550c7dc3d5ffb4e2), -+ CONST64(0x72be5d74f27b896f), CONST64(0x80deb1fe3b1696b1), -+ CONST64(0x9bdc06a725c71235), CONST64(0xc19bf174cf692694), -+ CONST64(0xe49b69c19ef14ad2), CONST64(0xefbe4786384f25e3), -+ CONST64(0x0fc19dc68b8cd5b5), CONST64(0x240ca1cc77ac9c65), -+ CONST64(0x2de92c6f592b0275), CONST64(0x4a7484aa6ea6e483), -+ CONST64(0x5cb0a9dcbd41fbd4), CONST64(0x76f988da831153b5), -+ CONST64(0x983e5152ee66dfab), CONST64(0xa831c66d2db43210), -+ CONST64(0xb00327c898fb213f), CONST64(0xbf597fc7beef0ee4), -+ CONST64(0xc6e00bf33da88fc2), CONST64(0xd5a79147930aa725), -+ CONST64(0x06ca6351e003826f), CONST64(0x142929670a0e6e70), -+ CONST64(0x27b70a8546d22ffc), CONST64(0x2e1b21385c26c926), -+ CONST64(0x4d2c6dfc5ac42aed), CONST64(0x53380d139d95b3df), -+ CONST64(0x650a73548baf63de), CONST64(0x766a0abb3c77b2a8), -+ CONST64(0x81c2c92e47edaee6), CONST64(0x92722c851482353b), -+ CONST64(0xa2bfe8a14cf10364), CONST64(0xa81a664bbc423001), -+ CONST64(0xc24b8b70d0f89791), CONST64(0xc76c51a30654be30), -+ CONST64(0xd192e819d6ef5218), CONST64(0xd69906245565a910), -+ CONST64(0xf40e35855771202a), CONST64(0x106aa07032bbd1b8), -+ CONST64(0x19a4c116b8d2d0c8), CONST64(0x1e376c085141ab53), -+ CONST64(0x2748774cdf8eeb99), CONST64(0x34b0bcb5e19b48a8), -+ CONST64(0x391c0cb3c5c95a63), CONST64(0x4ed8aa4ae3418acb), -+ CONST64(0x5b9cca4f7763e373), CONST64(0x682e6ff3d6b2b8a3), -+ CONST64(0x748f82ee5defb2fc), CONST64(0x78a5636f43172f60), -+ CONST64(0x84c87814a1f0ab72), CONST64(0x8cc702081a6439ec), -+ CONST64(0x90befffa23631e28), CONST64(0xa4506cebde82bde9), -+ CONST64(0xbef9a3f7b2c67915), CONST64(0xc67178f2e372532b), -+ CONST64(0xca273eceea26619c), CONST64(0xd186b8c721c0c207), -+ CONST64(0xeada7dd6cde0eb1e), CONST64(0xf57d4f7fee6ed178), -+ CONST64(0x06f067aa72176fba), CONST64(0x0a637dc5a2c898a6), -+ CONST64(0x113f9804bef90dae), CONST64(0x1b710b35131c471b), -+ CONST64(0x28db77f523047d84), CONST64(0x32caab7b40c72493), -+ CONST64(0x3c9ebe0a15c9bebc), CONST64(0x431d67c49c100d4c), -+ CONST64(0x4cc5d4becb3e42b6), CONST64(0x597f299cfc657e2a), -+ CONST64(0x5fcb6fab3ad6faec), CONST64(0x6c44198c4a475817) -+}; -+#define Ch(x,y,z) (z ^ (x & (y ^ z))) -+#define Maj(x,y,z) (((x | y) & z) | (x & y)) -+#define S(x, n) ROR64c(x, n) -+#define R(x, n) (((x)&CONST64(0xFFFFFFFFFFFFFFFF))>>((__u64)n)) -+#define Sigma0(x) (S(x, 28) ^ S(x, 34) ^ S(x, 39)) -+#define Sigma1(x) (S(x, 14) ^ S(x, 18) ^ S(x, 41)) -+#define Gamma0(x) (S(x, 1) ^ S(x, 8) ^ R(x, 7)) -+#define Gamma1(x) (S(x, 19) ^ S(x, 61) ^ R(x, 6)) -+#define RND(a,b,c,d,e,f,g,h,i)\ -+ t0 = h + Sigma1(e) + Ch(e, f, g) + K[i] + W[i];\ -+ t1 = Sigma0(a) + Maj(a, b, c);\ -+ d += t0;\ -+ h = t0 + t1; -+#define STORE64H(x, y) \ -+ do { \ -+ (y)[0] = (unsigned char)(((x)>>56)&255);\ -+ (y)[1] = (unsigned char)(((x)>>48)&255);\ -+ (y)[2] = (unsigned char)(((x)>>40)&255);\ -+ (y)[3] = (unsigned char)(((x)>>32)&255);\ -+ (y)[4] = (unsigned char)(((x)>>24)&255);\ -+ (y)[5] = (unsigned char)(((x)>>16)&255);\ -+ (y)[6] = (unsigned char)(((x)>>8)&255);\ -+ (y)[7] = (unsigned char)((x)&255); } while(0) -+ -+#define LOAD64H(x, y)\ -+ do {x = \ -+ (((__u64)((y)[0] & 255)) << 56) |\ -+ (((__u64)((y)[1] & 255)) << 48) |\ -+ (((__u64)((y)[2] & 255)) << 40) |\ -+ (((__u64)((y)[3] & 255)) << 32) |\ -+ (((__u64)((y)[4] & 255)) << 24) |\ -+ (((__u64)((y)[5] & 255)) << 16) |\ -+ (((__u64)((y)[6] & 255)) << 8) |\ -+ (((__u64)((y)[7] & 255)));\ -+ } while(0) -+ -+#define ROR64c(x, y) \ -+ ( ((((x)&CONST64(0xFFFFFFFFFFFFFFFF))>>((__u64)(y)&CONST64(63))) | \ -+ ((x)<<((__u64)(64-((y)&CONST64(63)))))) & CONST64(0xFFFFFFFFFFFFFFFF)) -+ -+struct sha512_state { -+ __u64 length, state[8]; -+ unsigned long curlen; -+ unsigned char buf[128]; -+}; -+ -+/* This is a highly simplified version from libtomcrypt */ -+struct hash_state { -+ struct sha512_state sha512; -+}; -+ -+static void sha512_compress(struct hash_state * md, const unsigned char *buf) -+{ -+ __u64 S[8], W[80], t0, t1; -+ int i; -+ -+ /* copy state into S */ -+ for (i = 0; i < 8; i++) { -+ S[i] = md->sha512.state[i]; -+ } -+ -+ /* copy the state into 1024-bits into W[0..15] */ -+ for (i = 0; i < 16; i++) { -+ LOAD64H(W[i], buf + (8*i)); -+ } -+ -+ /* fill W[16..79] */ -+ for (i = 16; i < 80; i++) { -+ W[i] = Gamma1(W[i - 2]) + W[i - 7] + -+ Gamma0(W[i - 15]) + W[i - 16]; -+ } -+ -+ for (i = 0; i < 80; i += 8) { -+ RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],i+0); -+ RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],i+1); -+ RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],i+2); -+ RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],i+3); -+ RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],i+4); -+ RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],i+5); -+ RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],i+6); -+ RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],i+7); -+ } -+ -+ /* feedback */ -+ for (i = 0; i < 8; i++) { -+ md->sha512.state[i] = md->sha512.state[i] + S[i]; -+ } -+} -+ -+static void sha512_init(struct hash_state * md) -+{ -+ md->sha512.curlen = 0; -+ md->sha512.length = 0; -+ md->sha512.state[0] = CONST64(0x6a09e667f3bcc908); -+ md->sha512.state[1] = CONST64(0xbb67ae8584caa73b); -+ md->sha512.state[2] = CONST64(0x3c6ef372fe94f82b); -+ md->sha512.state[3] = CONST64(0xa54ff53a5f1d36f1); -+ md->sha512.state[4] = CONST64(0x510e527fade682d1); -+ md->sha512.state[5] = CONST64(0x9b05688c2b3e6c1f); -+ md->sha512.state[6] = CONST64(0x1f83d9abfb41bd6b); -+ md->sha512.state[7] = CONST64(0x5be0cd19137e2179); -+} -+ -+static void sha512_done(struct hash_state * md, unsigned char *out) -+{ -+ int i; -+ -+ /* increase the length of the message */ -+ md->sha512.length += md->sha512.curlen * CONST64(8); -+ -+ /* append the '1' bit */ -+ md->sha512.buf[md->sha512.curlen++] = (unsigned char)0x80; -+ -+ /* if the length is currently above 112 bytes we append zeros then -+ * compress. Then we can fall back to padding zeros and length encoding -+ * like normal. */ -+ if (md->sha512.curlen > 112) { -+ while (md->sha512.curlen < 128) { -+ md->sha512.buf[md->sha512.curlen++] = (unsigned char)0; -+ } -+ sha512_compress(md, md->sha512.buf); -+ md->sha512.curlen = 0; -+ } -+ -+ /* pad upto 120 bytes of zeroes note: that from 112 to 120 is the 64 MSB -+ * of the length. We assume that you won't hash > 2^64 bits of data. */ -+ while (md->sha512.curlen < 120) { -+ md->sha512.buf[md->sha512.curlen++] = (unsigned char)0; -+ } -+ -+ /* store length */ -+ STORE64H(md->sha512.length, md->sha512.buf + 120); -+ sha512_compress(md, md->sha512.buf); -+ -+ /* copy output */ -+ for (i = 0; i < 8; i++) { -+ STORE64H(md->sha512.state[i], out+(8 * i)); -+ } -+} -+ -+#define MIN(x, y) ( ((x)<(y))?(x):(y) ) -+#define SHA512_BLOCKSIZE 128 -+static void sha512_process(struct hash_state * md, -+ const unsigned char *in, -+ unsigned long inlen) -+{ -+ unsigned long n; -+ -+ while (inlen > 0) { -+ if (md->sha512.curlen == 0 && inlen >= SHA512_BLOCKSIZE) { -+ sha512_compress(md, in); -+ md->sha512.length += SHA512_BLOCKSIZE * 8; -+ in += SHA512_BLOCKSIZE; -+ inlen -= SHA512_BLOCKSIZE; -+ } else { -+ n = MIN(inlen, (SHA512_BLOCKSIZE - md->sha512.curlen)); -+ memcpy(md->sha512.buf + md->sha512.curlen, -+ in, (size_t)n); -+ md->sha512.curlen += n; -+ in += n; -+ inlen -= n; -+ if (md->sha512.curlen == SHA512_BLOCKSIZE) { -+ sha512_compress(md, md->sha512.buf); -+ md->sha512.length += SHA512_BLOCKSIZE * 8; -+ md->sha512.curlen = 0; -+ } -+ } -+ } -+} -+ -+void ext2fs_sha512(const unsigned char *in, unsigned long in_size, -+ unsigned char out[EXT2FS_SHA512_LENGTH]) -+{ -+ struct hash_state md; -+ -+ sha512_init(&md); -+ sha512_process(&md, in, in_size); -+ sha512_done(&md, out); -+} -+ -+#ifdef UNITTEST -+static const struct { -+ char *msg; -+ unsigned char hash[64]; -+} tests[] = { -+ { "", -+ { 0xcf, 0x83, 0xe1, 0x35, 0x7e, 0xef, 0xb8, 0xbd, -+ 0xf1, 0x54, 0x28, 0x50, 0xd6, 0x6d, 0x80, 0x07, -+ 0xd6, 0x20, 0xe4, 0x05, 0x0b, 0x57, 0x15, 0xdc, -+ 0x83, 0xf4, 0xa9, 0x21, 0xd3, 0x6c, 0xe9, 0xce, -+ 0x47, 0xd0, 0xd1, 0x3c, 0x5d, 0x85, 0xf2, 0xb0, -+ 0xff, 0x83, 0x18, 0xd2, 0x87, 0x7e, 0xec, 0x2f, -+ 0x63, 0xb9, 0x31, 0xbd, 0x47, 0x41, 0x7a, 0x81, -+ 0xa5, 0x38, 0x32, 0x7a, 0xf9, 0x27, 0xda, 0x3e } -+ }, -+ { "abc", -+ { 0xdd, 0xaf, 0x35, 0xa1, 0x93, 0x61, 0x7a, 0xba, -+ 0xcc, 0x41, 0x73, 0x49, 0xae, 0x20, 0x41, 0x31, -+ 0x12, 0xe6, 0xfa, 0x4e, 0x89, 0xa9, 0x7e, 0xa2, -+ 0x0a, 0x9e, 0xee, 0xe6, 0x4b, 0x55, 0xd3, 0x9a, -+ 0x21, 0x92, 0x99, 0x2a, 0x27, 0x4f, 0xc1, 0xa8, -+ 0x36, 0xba, 0x3c, 0x23, 0xa3, 0xfe, 0xeb, 0xbd, -+ 0x45, 0x4d, 0x44, 0x23, 0x64, 0x3c, 0xe8, 0x0e, -+ 0x2a, 0x9a, 0xc9, 0x4f, 0xa5, 0x4c, 0xa4, 0x9f } -+ }, -+ { "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu", -+ { 0x8e, 0x95, 0x9b, 0x75, 0xda, 0xe3, 0x13, 0xda, -+ 0x8c, 0xf4, 0xf7, 0x28, 0x14, 0xfc, 0x14, 0x3f, -+ 0x8f, 0x77, 0x79, 0xc6, 0xeb, 0x9f, 0x7f, 0xa1, -+ 0x72, 0x99, 0xae, 0xad, 0xb6, 0x88, 0x90, 0x18, -+ 0x50, 0x1d, 0x28, 0x9e, 0x49, 0x00, 0xf7, 0xe4, -+ 0x33, 0x1b, 0x99, 0xde, 0xc4, 0xb5, 0x43, 0x3a, -+ 0xc7, 0xd3, 0x29, 0xee, 0xb6, 0xdd, 0x26, 0x54, -+ 0x5e, 0x96, 0xe5, 0x5b, 0x87, 0x4b, 0xe9, 0x09 } -+ }, -+}; -+ -+int main(int argc, char **argv) -+{ -+ int i; -+ int errors = 0; -+ unsigned char tmp[64]; -+ struct hash_state md; -+ -+ for (i = 0; i < (int)(sizeof(tests) / sizeof(tests[0])); i++) { -+ unsigned char *msg = (unsigned char *) tests[i].msg; -+ int len = strlen(tests[i].msg); -+ -+ ext2fs_sha512(msg, len, tmp); -+ printf("SHA512 test message %d: ", i); -+ if (memcmp(tmp, tests[i].hash, 64) != 0) { -+ printf("FAILED\n"); -+ errors++; -+ } else -+ printf("OK\n"); -+ } -+ return errors; -+} -+ -+#endif /* UNITTEST */ -diff --git a/lib/ext2fs/swapfs.c b/lib/ext2fs/swapfs.c -index 2a7b768..ee7a455 100644 ---- a/lib/ext2fs/swapfs.c -+++ b/lib/ext2fs/swapfs.c -@@ -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 && (t->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 -diff --git a/lib/ext2fs/symlink.c b/lib/ext2fs/symlink.c -index 7c485a5..6e988ad 100644 ---- a/lib/ext2fs/symlink.c -+++ b/lib/ext2fs/symlink.c -@@ -29,20 +29,20 @@ - #include "ext2fs.h" - - errcode_t ext2fs_symlink(ext2_filsys fs, ext2_ino_t parent, ext2_ino_t ino, -- const char *name, char *target) -+ const char *name, const char *target) - { - errcode_t retval; - struct ext2_inode inode; - ext2_ino_t scratch_ino; - blk64_t blk; -- int fastlink; -+ int fastlink, inlinelink; - unsigned int target_len; - char *block_buf = 0; - - EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); - - /* The Linux kernel doesn't allow for links longer than a block */ -- target_len = strlen(target); -+ target_len = strnlen(target, fs->blocksize + 1); - if (target_len > fs->blocksize) { - retval = EXT2_ET_INVALID_ARGUMENT; - goto cleanup; -@@ -51,12 +51,19 @@ errcode_t ext2fs_symlink(ext2_filsys fs, ext2_ino_t parent, ext2_ino_t ino, - /* - * Allocate a data block for slow links - */ -+ retval = ext2fs_get_mem(fs->blocksize+1, &block_buf); -+ if (retval) -+ goto cleanup; -+ memset(block_buf, 0, fs->blocksize+1); -+ strncpy(block_buf, target, fs->blocksize); -+ -+ memset(&inode, 0, sizeof(struct ext2_inode)); - fastlink = (target_len < sizeof(inode.i_block)); - if (!fastlink) { -- retval = ext2fs_new_block2(fs, 0, 0, &blk); -- if (retval) -- goto cleanup; -- retval = ext2fs_get_mem(fs->blocksize, &block_buf); -+ retval = ext2fs_new_block2(fs, ext2fs_find_inode_goal(fs, ino, -+ &inode, -+ 0), -+ NULL, &blk); - if (retval) - goto cleanup; - } -@@ -74,21 +81,39 @@ errcode_t ext2fs_symlink(ext2_filsys fs, ext2_ino_t parent, ext2_ino_t ino, - /* - * Create the inode structure.... - */ -- memset(&inode, 0, sizeof(struct ext2_inode)); - inode.i_mode = LINUX_S_IFLNK | 0777; - inode.i_uid = inode.i_gid = 0; -- ext2fs_iblk_set(fs, &inode, fastlink ? 0 : 1); - inode.i_links_count = 1; - ext2fs_inode_size_set(fs, &inode, target_len); - /* The time fields are set by ext2fs_write_new_inode() */ - -+ inlinelink = !fastlink && -+ (fs->super->s_feature_incompat & -+ EXT4_FEATURE_INCOMPAT_INLINE_DATA) && -+ (target_len < fs->blocksize); - if (fastlink) { - /* Fast symlinks, target stored in inode */ - strcpy((char *)&inode.i_block, target); -+ } else if (inlinelink) { -+ /* Try inserting an inline data symlink */ -+ inode.i_flags |= EXT4_INLINE_DATA_FL; -+ retval = ext2fs_write_new_inode(fs, ino, &inode); -+ if (retval) -+ goto cleanup; -+ retval = ext2fs_inline_data_set(fs, ino, &inode, block_buf, -+ target_len); -+ if (retval) { -+ inode.i_flags &= ~EXT4_INLINE_DATA_FL; -+ inlinelink = 0; -+ goto need_block; -+ } -+ retval = ext2fs_read_inode(fs, ino, &inode); -+ if (retval) -+ goto cleanup; - } else { -+need_block: - /* Slow symlinks, target stored in the first block */ -- memset(block_buf, 0, fs->blocksize); -- strncpy(block_buf, target, fs->blocksize); -+ ext2fs_iblk_set(fs, &inode, 1); - if (fs->super->s_feature_incompat & - EXT3_FEATURE_INCOMPAT_EXTENTS) { - /* -@@ -104,11 +129,14 @@ errcode_t ext2fs_symlink(ext2_filsys fs, ext2_ino_t parent, ext2_ino_t ino, - * number is assigned by write_new_inode, which means that the - * operations using ino must come after it. - */ -- retval = ext2fs_write_new_inode(fs, ino, &inode); -+ if (inlinelink) -+ retval = ext2fs_write_inode(fs, ino, &inode); -+ else -+ retval = ext2fs_write_new_inode(fs, ino, &inode); - if (retval) - goto cleanup; - -- if (!fastlink) { -+ if (!fastlink && !inlinelink) { - retval = ext2fs_bmap2(fs, ino, &inode, NULL, BMAP_SET, 0, NULL, - &blk); - if (retval) -@@ -139,7 +167,7 @@ errcode_t ext2fs_symlink(ext2_filsys fs, ext2_ino_t parent, ext2_ino_t ino, - /* - * Update accounting.... - */ -- if (!fastlink) -+ if (!fastlink && !inlinelink) - ext2fs_block_alloc_stats2(fs, blk, +1); - ext2fs_inode_alloc_stats2(fs, ino, +1, 0); - -diff --git a/lib/ext2fs/tdb.c b/lib/ext2fs/tdb.c -index 61e30ed..7317288 100644 ---- a/lib/ext2fs/tdb.c -+++ b/lib/ext2fs/tdb.c -@@ -246,6 +246,7 @@ struct tdb_context { - int page_size; - int max_dead_records; - bool have_transaction_lock; -+ tdb_len_t real_map_size; /* how much space has been mapped */ - }; - - -@@ -970,9 +971,10 @@ int tdb_munmap(struct tdb_context *tdb) - - #ifdef HAVE_MMAP - if (tdb->map_ptr) { -- int ret = munmap(tdb->map_ptr, tdb->map_size); -+ int ret = munmap(tdb->map_ptr, tdb->real_map_size); - if (ret != 0) - return ret; -+ tdb->real_map_size = 0; - } - #endif - tdb->map_ptr = NULL; -@@ -995,10 +997,12 @@ void tdb_mmap(struct tdb_context *tdb) - */ - - if (tdb->map_ptr == MAP_FAILED) { -+ tdb->real_map_size = 0; - tdb->map_ptr = NULL; - TDB_LOG((tdb, TDB_DEBUG_WARNING, "tdb_mmap failed for size %d (%s)\n", - tdb->map_size, strerror(errno))); - } -+ tdb->real_map_size = tdb->map_size; - } else { - tdb->map_ptr = NULL; - } -@@ -4138,3 +4142,13 @@ int tdb_reopen_all(int parent_longlived) - - return 0; - } -+ -+/** -+ * Flush a database file from the page cache. -+ **/ -+int tdb_flush(struct tdb_context *tdb) -+{ -+ if (tdb->fd != -1) -+ return fsync(tdb->fd); -+ return 0; -+} -diff --git a/lib/ext2fs/tdb.h b/lib/ext2fs/tdb.h -index 732ef0e..6a4086c 100644 ---- a/lib/ext2fs/tdb.h -+++ b/lib/ext2fs/tdb.h -@@ -129,6 +129,7 @@ typedef struct TDB_DATA { - #define tdb_lockall_nonblock ext2fs_tdb_lockall_nonblock - #define tdb_lockall_read_nonblock ext2fs_tdb_lockall_read_nonblock - #define tdb_lockall_unmark ext2fs_tdb_lockall_unmark -+#define tdb_flush ext2fs_tdb_flush - - /* this is the context structure that is returned from a db open */ - typedef struct tdb_context TDB_CONTEXT; -@@ -191,6 +192,7 @@ size_t tdb_map_size(struct tdb_context *tdb); - int tdb_get_flags(struct tdb_context *tdb); - void tdb_enable_seqnum(struct tdb_context *tdb); - void tdb_increment_seqnum_nonblock(struct tdb_context *tdb); -+int tdb_flush(struct tdb_context *tdb); - - /* Low level locking functions: use with care */ - int tdb_chainlock(struct tdb_context *tdb, TDB_DATA key); -diff --git a/lib/ext2fs/test_io.c b/lib/ext2fs/test_io.c -index 6f0d035..f7c50d1 100644 ---- a/lib/ext2fs/test_io.c -+++ b/lib/ext2fs/test_io.c -@@ -85,6 +85,8 @@ void (*test_io_cb_write_byte) - #define TEST_FLAG_DUMP 0x10 - #define TEST_FLAG_SET_OPTION 0x20 - #define TEST_FLAG_DISCARD 0x40 -+#define TEST_FLAG_READAHEAD 0x80 -+#define TEST_FLAG_ZEROOUT 0x100 - - static void test_dump_block(io_channel channel, - struct test_private_data *data, -@@ -486,6 +488,45 @@ static errcode_t test_discard(io_channel channel, unsigned long long block, - return retval; - } - -+static errcode_t test_cache_readahead(io_channel channel, -+ unsigned long long block, -+ unsigned long long count) -+{ -+ struct test_private_data *data; -+ errcode_t retval = 0; -+ -+ EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); -+ data = (struct test_private_data *) channel->private_data; -+ EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_TEST_IO_CHANNEL); -+ -+ if (data->real) -+ retval = io_channel_cache_readahead(data->real, block, count); -+ if (data->flags & TEST_FLAG_READAHEAD) -+ fprintf(data->outfile, -+ "Test_io: readahead(%llu, %llu) returned %s\n", -+ block, count, retval ? error_message(retval) : "OK"); -+ return retval; -+} -+ -+static errcode_t test_zeroout(io_channel channel, unsigned long long block, -+ unsigned long long count) -+{ -+ struct test_private_data *data; -+ errcode_t retval = 0; -+ -+ EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); -+ data = (struct test_private_data *) channel->private_data; -+ EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_TEST_IO_CHANNEL); -+ -+ if (data->real) -+ retval = io_channel_zeroout(data->real, block, count); -+ if (data->flags & TEST_FLAG_ZEROOUT) -+ fprintf(data->outfile, -+ "Test_io: zeroout(%llu, %llu) returned %s\n", -+ block, count, retval ? error_message(retval) : "OK"); -+ return retval; -+} -+ - static struct struct_io_manager struct_test_manager = { - .magic = EXT2_ET_MAGIC_IO_MANAGER, - .name = "Test I/O Manager", -@@ -501,6 +542,8 @@ static struct struct_io_manager struct_test_manager = { - .read_blk64 = test_read_blk64, - .write_blk64 = test_write_blk64, - .discard = test_discard, -+ .cache_readahead = test_cache_readahead, -+ .zeroout = test_zeroout, - }; - - io_manager test_io_manager = &struct_test_manager; -diff --git a/lib/ext2fs/tst_super_size.c b/lib/ext2fs/tst_super_size.c -index f9cec8a..8e3c21f 100644 ---- a/lib/ext2fs/tst_super_size.c -+++ b/lib/ext2fs/tst_super_size.c -@@ -113,8 +113,9 @@ 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_reserved_pad, 2); -+ check_field(s_checksum_type, 1); -+ check_field(s_encryption_level, 1); -+ check_field(s_reserved_pad, 1); - check_field(s_kbytes_written, 8); - check_field(s_snapshot_inum, 4); - check_field(s_snapshot_id, 4); -@@ -136,7 +137,10 @@ int main(int argc, char **argv) - check_field(s_grp_quota_inum, 4); - check_field(s_overhead_blocks, 4); - check_field(s_backup_bgs, 8); -- check_field(s_reserved, 106 * 4); -+ check_field(s_encrypt_algos, 4); -+ check_field(s_encrypt_pw_salt, 16); -+ check_field(s_lpf_ino, 4); -+ check_field(s_reserved, 100 * 4); - check_field(s_checksum, 4); - do_field("Superblock end", 0, 0, cur_offset, 1024); - #endif -diff --git a/lib/ext2fs/undo_io.c b/lib/ext2fs/undo_io.c -index d6beb02..4213320 100644 ---- a/lib/ext2fs/undo_io.c -+++ b/lib/ext2fs/undo_io.c -@@ -11,8 +11,12 @@ - * %End-Header% - */ - -+#ifndef _LARGEFILE_SOURCE - #define _LARGEFILE_SOURCE -+#endif -+#ifndef _LARGEFILE64_SOURCE - #define _LARGEFILE64_SOURCE -+#endif - - #include "config.h" - #include -@@ -37,11 +41,11 @@ - #if HAVE_SYS_RESOURCE_H - #include - #endif -- --#include "tdb.h" -+#include - - #include "ext2_fs.h" - #include "ext2fs.h" -+#include "ext2fsP.h" - - #ifdef __GNUC__ - #define ATTR(x) __attribute__(x) -@@ -49,36 +53,102 @@ - #define ATTR(x) - #endif - -+#undef DEBUG -+ -+#ifdef DEBUG -+# define dbg_printf(f, a...) do {printf(f, ## a); fflush(stdout); } while (0) -+#else -+# define dbg_printf(f, a...) -+#endif -+ - /* - * For checking structure magic numbers... - */ - - #define EXT2_CHECK_MAGIC(struct, code) \ - if ((struct)->magic != (code)) return (code) -+/* -+ * Undo file format: The file is cut up into undo_header.block_size blocks. -+ * The first block contains the header. -+ * The second block contains the superblock. -+ * There is then a repeating series of blocks as follows: -+ * A key block, which contains undo_keys to map the following data blocks. -+ * Data blocks -+ * (Note that there are pointers to the first key block and the sb, so this -+ * order isn't strictly necessary.) -+ */ -+#define E2UNDO_MAGIC "E2UNDO02" -+#define KEYBLOCK_MAGIC 0xCADECADE -+ -+#define E2UNDO_STATE_FINISHED 0x1 /* undo file is complete */ -+ -+#define E2UNDO_MIN_BLOCK_SIZE 1024 /* undo blocks are no less than 1KB */ -+#define E2UNDO_MAX_BLOCK_SIZE 1048576 /* undo blocks are no more than 1MB */ -+ -+struct undo_header { -+ char magic[8]; /* "E2UNDO02" */ -+ __le64 num_keys; /* how many keys? */ -+ __le64 super_offset; /* where in the file is the superblock copy? */ -+ __le64 key_offset; /* where do the key/data block chunks start? */ -+ __le32 block_size; /* block size of the undo file */ -+ __le32 fs_block_size; /* block size of the target device */ -+ __le32 sb_crc; /* crc32c of the superblock */ -+ __le32 state; /* e2undo state flags */ -+ __le32 f_compat; /* compatible features (none so far) */ -+ __le32 f_incompat; /* incompatible features (none so far) */ -+ __le32 f_rocompat; /* ro compatible features (none so far) */ -+ __u8 padding[448]; /* padding */ -+ __le32 header_crc; /* crc32c of this header (but not this field) */ -+}; -+ -+#define E2UNDO_MAX_EXTENT_BLOCKS 512 /* max extent size, in blocks */ -+ -+struct undo_key { -+ __le64 fsblk; /* where in the fs does the block go */ -+ __le32 blk_crc; /* crc32c of the block */ -+ __le32 size; /* how many bytes in this block? */ -+}; -+ -+struct undo_key_block { -+ __le32 magic; /* KEYBLOCK_MAGIC number */ -+ __le32 crc; /* block checksum */ -+ __le64 reserved; /* zero */ -+ -+ struct undo_key keys[0]; /* keys, which come immediately after */ -+}; - - struct undo_private_data { - int magic; -- TDB_CONTEXT *tdb; -- char *tdb_file; -+ -+ /* the undo file io channel */ -+ io_channel undo_file; -+ blk64_t undo_blk_num; /* next free block */ -+ blk64_t key_blk_num; /* current key block location */ -+ blk64_t super_blk_num; /* superblock location */ -+ blk64_t first_key_blk; /* first key block location */ -+ struct undo_key_block *keyb; -+ size_t num_keys, keys_in_block; - - /* The backing io channel */ - io_channel real; - -- int tdb_data_size; -+ unsigned long long tdb_data_size; - int tdb_written; - - /* to support offset in unix I/O manager */ - ext2_loff_t offset; -+ -+ ext2fs_block_bitmap written_block_map; -+ struct struct_ext2_filsys fake_fs; -+ char *tdb_file; -+ struct undo_header hdr; - }; -+#define KEYS_PER_BLOCK(d) (((d)->tdb_data_size / sizeof(struct undo_key)) - 1) - - static io_manager undo_io_backing_manager; - static char *tdb_file; - static int actual_size; - --static unsigned char mtime_key[] = "filesystem MTIME"; --static unsigned char blksize_key[] = "filesystem BLKSIZE"; --static unsigned char uuid_key[] = "filesystem UUID"; -- - errcode_t set_undo_io_backing_manager(io_manager manager) - { - /* -@@ -99,17 +169,38 @@ errcode_t set_undo_io_backup_file(char *file_name) - return 0; - } - --static errcode_t write_file_system_identity(io_channel undo_channel, -- TDB_CONTEXT *tdb) -+static errcode_t write_undo_indexes(struct undo_private_data *data, int flush) - { - errcode_t retval; - struct ext2_super_block super; -- TDB_DATA tdb_key, tdb_data; -- struct undo_private_data *data; - io_channel channel; -- int block_size ; -+ int block_size; -+ __u32 sb_crc, hdr_crc; -+ -+ /* Spit out a key block, if there's any data */ -+ if (data->keys_in_block) { -+ data->keyb->magic = ext2fs_cpu_to_le32(KEYBLOCK_MAGIC); -+ data->keyb->crc = 0; -+ data->keyb->crc = ext2fs_cpu_to_le32( -+ ext2fs_crc32c_le(~0, -+ (unsigned char *)data->keyb, -+ data->tdb_data_size)); -+ dbg_printf("Writing keyblock to blk %llu\n", data->key_blk_num); -+ retval = io_channel_write_blk64(data->undo_file, -+ data->key_blk_num, -+ 1, data->keyb); -+ if (retval) -+ return retval; -+ /* Move on to the next key block if it's full. */ -+ if (data->keys_in_block == KEYS_PER_BLOCK(data)) { -+ memset(data->keyb, 0, data->tdb_data_size); -+ data->keys_in_block = 0; -+ data->key_blk_num = data->undo_blk_num; -+ data->undo_blk_num++; -+ } -+ } - -- data = (struct undo_private_data *) undo_channel->private_data; -+ /* Prepare superblock for write */ - channel = data->real; - block_size = channel->block_size; - -@@ -117,50 +208,92 @@ static errcode_t write_file_system_identity(io_channel undo_channel, - retval = io_channel_read_blk64(channel, 1, -SUPERBLOCK_SIZE, &super); - if (retval) - goto err_out; -- -- /* Write to tdb file in the file system byte order */ -- tdb_key.dptr = mtime_key; -- tdb_key.dsize = sizeof(mtime_key); -- tdb_data.dptr = (unsigned char *) &(super.s_mtime); -- tdb_data.dsize = sizeof(super.s_mtime); -- -- retval = tdb_store(tdb, tdb_key, tdb_data, TDB_INSERT); -- if (retval == -1) { -- retval = EXT2_ET_TDB_SUCCESS + tdb_error(tdb); -+ sb_crc = ext2fs_crc32c_le(~0, (unsigned char *)&super, SUPERBLOCK_SIZE); -+ super.s_magic = ~super.s_magic; -+ -+ /* Write the undo header to disk. */ -+ memcpy(data->hdr.magic, E2UNDO_MAGIC, sizeof(data->hdr.magic)); -+ data->hdr.num_keys = ext2fs_cpu_to_le64(data->num_keys); -+ data->hdr.super_offset = ext2fs_cpu_to_le64(data->super_blk_num); -+ data->hdr.key_offset = ext2fs_cpu_to_le64(data->first_key_blk); -+ data->hdr.fs_block_size = ext2fs_cpu_to_le32(block_size); -+ data->hdr.sb_crc = ext2fs_cpu_to_le32(sb_crc); -+ hdr_crc = ext2fs_crc32c_le(~0, (unsigned char *)&data->hdr, -+ sizeof(data->hdr) - -+ sizeof(data->hdr.header_crc)); -+ data->hdr.header_crc = ext2fs_cpu_to_le32(hdr_crc); -+ retval = io_channel_write_blk64(data->undo_file, 0, -+ -(int)sizeof(data->hdr), -+ &data->hdr); -+ if (retval) - goto err_out; -- } -- -- tdb_key.dptr = uuid_key; -- tdb_key.dsize = sizeof(uuid_key); -- tdb_data.dptr = (unsigned char *)&(super.s_uuid); -- tdb_data.dsize = sizeof(super.s_uuid); - -- retval = tdb_store(tdb, tdb_key, tdb_data, TDB_INSERT); -- if (retval == -1) { -- retval = EXT2_ET_TDB_SUCCESS + tdb_error(tdb); -- } -+ /* -+ * Record the entire superblock (in FS byte order) so that we can't -+ * apply e2undo files to the wrong FS or out of order. -+ */ -+ dbg_printf("Writing superblock to block %llu\n", data->super_blk_num); -+ retval = io_channel_write_blk64(data->undo_file, data->super_blk_num, -+ -SUPERBLOCK_SIZE, &super); -+ if (retval) -+ goto err_out; - -+ if (flush) -+ retval = io_channel_flush(data->undo_file); - err_out: - io_channel_set_blksize(channel, block_size); - return retval; - } - --static errcode_t write_block_size(TDB_CONTEXT *tdb, int block_size) -+static errcode_t undo_setup_tdb(struct undo_private_data *data) - { -+ int i; - errcode_t retval; -- TDB_DATA tdb_key, tdb_data; - -- tdb_key.dptr = blksize_key; -- tdb_key.dsize = sizeof(blksize_key); -- tdb_data.dptr = (unsigned char *)&(block_size); -- tdb_data.dsize = sizeof(block_size); -+ if (data->tdb_written == 1) -+ return 0; - -- retval = tdb_store(tdb, tdb_key, tdb_data, TDB_INSERT); -- if (retval == -1) { -- retval = EXT2_ET_TDB_SUCCESS + tdb_error(tdb); -- } -+ data->tdb_written = 1; - -- return retval; -+ /* Make a bitmap to track what we've written */ -+ memset(&data->fake_fs, 0, sizeof(data->fake_fs)); -+ data->fake_fs.blocksize = data->tdb_data_size; -+ retval = ext2fs_alloc_generic_bmap(&data->fake_fs, -+ EXT2_ET_MAGIC_BLOCK_BITMAP64, -+ EXT2FS_BMAP64_RBTREE, -+ 0, ~1ULL, ~1ULL, -+ "undo block map", &data->written_block_map); -+ if (retval) -+ return retval; -+ -+ /* Allocate key block */ -+ retval = ext2fs_get_mem(data->tdb_data_size, &data->keyb); -+ if (retval) -+ return retval; -+ data->key_blk_num = data->first_key_blk; -+ -+ /* Record block size */ -+ dbg_printf("Undo block size %llu\n", data->tdb_data_size); -+ dbg_printf("Keys per block %llu\n", KEYS_PER_BLOCK(data)); -+ data->hdr.block_size = ext2fs_cpu_to_le32(data->tdb_data_size); -+ io_channel_set_blksize(data->undo_file, data->tdb_data_size); -+ -+ /* Ensure that we have space for header blocks */ -+ for (i = 0; i <= 2; i++) { -+ retval = io_channel_read_blk64(data->undo_file, i, 1, -+ data->keyb); -+ if (retval) -+ memset(data->keyb, 0, data->tdb_data_size); -+ retval = io_channel_write_blk64(data->undo_file, i, 1, -+ data->keyb); -+ if (retval) -+ return retval; -+ retval = io_channel_flush(data->undo_file); -+ if (retval) -+ return retval; -+ } -+ memset(data->keyb, 0, data->tdb_data_size); -+ return 0; - } - - static errcode_t undo_write_tdb(io_channel channel, -@@ -172,13 +305,16 @@ static errcode_t undo_write_tdb(io_channel channel, - errcode_t retval = 0; - ext2_loff_t offset; - struct undo_private_data *data; -- TDB_DATA tdb_key, tdb_data; - unsigned char *read_ptr; - unsigned long long end_block; -+ unsigned long long data_size; -+ void *data_ptr; -+ struct undo_key *key; -+ __u32 blk_crc; - - data = (struct undo_private_data *) channel->private_data; - -- if (data->tdb == NULL) { -+ if (data->undo_file == NULL) { - /* - * Transaction database not initialized - */ -@@ -193,6 +329,10 @@ static errcode_t undo_write_tdb(io_channel channel, - else - size = count * channel->block_size; - } -+ -+ retval = undo_setup_tdb(data); -+ if (retval) -+ return retval; - /* - * Data is stored in tdb database as blocks of tdb_data_size size - * This helps in efficient lookup further. -@@ -201,21 +341,22 @@ static errcode_t undo_write_tdb(io_channel channel, - */ - offset = (block * channel->block_size) + data->offset ; - block_num = offset / data->tdb_data_size; -- end_block = (offset + size) / data->tdb_data_size; -+ end_block = (offset + size - 1) / data->tdb_data_size; - -- tdb_transaction_start(data->tdb); -- while (block_num <= end_block ) { -+ while (block_num <= end_block) { -+ __u32 keysz; - -- tdb_key.dptr = (unsigned char *)&block_num; -- tdb_key.dsize = sizeof(block_num); - /* - * Check if we have the record already - */ -- if (tdb_exists(data->tdb, tdb_key)) { -+ if (ext2fs_test_block_bitmap2(data->written_block_map, -+ block_num)) { - /* Try the next block */ - block_num++; - continue; - } -+ ext2fs_mark_block_bitmap2(data->written_block_map, block_num); -+ - /* - * Read one block using the backing I/O manager - * The backing I/O manager block size may be -@@ -230,7 +371,6 @@ static errcode_t undo_write_tdb(io_channel channel, - ((offset - data->offset) % channel->block_size); - retval = ext2fs_get_mem(count, &read_ptr); - if (retval) { -- tdb_transaction_cancel(data->tdb); - return retval; - } - -@@ -245,53 +385,81 @@ static errcode_t undo_write_tdb(io_channel channel, - if (retval) { - if (retval != EXT2_ET_SHORT_READ) { - free(read_ptr); -- tdb_transaction_cancel(data->tdb); - return retval; - } - /* - * short read so update the record size - * accordingly - */ -- tdb_data.dsize = actual_size; -+ data_size = actual_size; - } else { -- tdb_data.dsize = data->tdb_data_size; -+ data_size = data->tdb_data_size; - } -- tdb_data.dptr = read_ptr + -- ((offset - data->offset) % channel->block_size); --#ifdef DEBUG -- printf("Printing with key %lld data %x and size %d\n", -- block_num, -- tdb_data.dptr, -- tdb_data.dsize); --#endif -- if (!data->tdb_written) { -- data->tdb_written = 1; -- /* Write the blocksize to tdb file */ -- retval = write_block_size(data->tdb, -- data->tdb_data_size); -- if (retval) { -- tdb_transaction_cancel(data->tdb); -- retval = EXT2_ET_TDB_ERR_IO; -- free(read_ptr); -- return retval; -- } -+ if (data_size == 0) { -+ free(read_ptr); -+ block_num++; -+ continue; - } -- retval = tdb_store(data->tdb, tdb_key, tdb_data, TDB_INSERT); -- if (retval == -1) { -- /* -- * TDB_ERR_EXISTS cannot happen because we -- * have already verified it doesn't exist -- */ -- tdb_transaction_cancel(data->tdb); -- retval = EXT2_ET_TDB_ERR_IO; -+ dbg_printf("Read %llu bytes from FS block %llu (blk=%llu cnt=%u)\n", -+ data_size, backing_blk_num, block, count); -+ if ((data_size % data->undo_file->block_size) == 0) -+ sz = data_size / data->undo_file->block_size; -+ else -+ sz = -actual_size; -+ data_ptr = read_ptr + ((offset - data->offset) % -+ data->undo_file->block_size); -+ /* extend this key? */ -+ if (data->keys_in_block) { -+ key = data->keyb->keys + data->keys_in_block - 1; -+ keysz = ext2fs_le32_to_cpu(key->size); -+ } else { -+ key = NULL; -+ keysz = 0; -+ } -+ if (key != NULL && -+ ext2fs_le64_to_cpu(key->fsblk) + -+ ((keysz + data->tdb_data_size - 1) / -+ data->tdb_data_size) == backing_blk_num && -+ E2UNDO_MAX_EXTENT_BLOCKS * data->tdb_data_size > -+ keysz + sz) { -+ blk_crc = ext2fs_le32_to_cpu(key->blk_crc); -+ blk_crc = ext2fs_crc32c_le(blk_crc, -+ (unsigned char *)data_ptr, -+ data_size); -+ key->blk_crc = ext2fs_cpu_to_le32(blk_crc); -+ key->size = ext2fs_cpu_to_le32(keysz + data_size); -+ } else { -+ data->num_keys++; -+ key = data->keyb->keys + data->keys_in_block; -+ data->keys_in_block++; -+ key->fsblk = ext2fs_cpu_to_le64(backing_blk_num); -+ blk_crc = ext2fs_crc32c_le(~0, -+ (unsigned char *)data_ptr, -+ data_size); -+ key->blk_crc = ext2fs_cpu_to_le32(blk_crc); -+ key->size = ext2fs_cpu_to_le32(data_size); -+ } -+ dbg_printf("Writing block %llu to offset %llu size %d key %zu\n", -+ block_num, -+ data->undo_blk_num, -+ sz, data->num_keys - 1); -+ retval = io_channel_write_blk64(data->undo_file, -+ data->undo_blk_num, sz, data_ptr); -+ if (retval) { - free(read_ptr); - return retval; - } -+ data->undo_blk_num++; - free(read_ptr); -+ -+ /* Write out the key block */ -+ retval = write_undo_indexes(data, 0); -+ if (retval) -+ return retval; -+ - /* Next block */ - block_num++; - } -- tdb_transaction_commit(data->tdb); - - return retval; - } -@@ -313,10 +481,203 @@ static void undo_err_handler_init(io_channel channel) - channel->read_error = undo_io_read_error; - } - -+static int check_filesystem(struct undo_header *hdr, io_channel undo_file, -+ unsigned int blocksize, blk64_t super_block, -+ io_channel channel) -+{ -+ struct ext2_super_block super, *sb; -+ char *buf; -+ __u32 sb_crc; -+ errcode_t retval; -+ -+ io_channel_set_blksize(channel, SUPERBLOCK_OFFSET); -+ retval = io_channel_read_blk64(channel, 1, -SUPERBLOCK_SIZE, &super); -+ if (retval) -+ return retval; -+ -+ /* -+ * Compare the FS and the undo file superblock so that we don't -+ * append to something that doesn't match this FS. -+ */ -+ retval = ext2fs_get_mem(blocksize, &buf); -+ if (retval) -+ return retval; -+ retval = io_channel_read_blk64(undo_file, super_block, -+ -SUPERBLOCK_SIZE, buf); -+ if (retval) -+ goto out; -+ sb = (struct ext2_super_block *)buf; -+ sb->s_magic = ~sb->s_magic; -+ if (memcmp(&super, buf, sizeof(super))) { -+ retval = -1; -+ goto out; -+ } -+ sb_crc = ext2fs_crc32c_le(~0, (unsigned char *)buf, SUPERBLOCK_SIZE); -+ if (ext2fs_le32_to_cpu(hdr->sb_crc) != sb_crc) { -+ retval = -1; -+ goto out; -+ } -+ -+out: -+ ext2fs_free_mem(&buf); -+ return retval; -+} -+ -+/* -+ * Try to re-open the undo file, so that we can resume where we left off. -+ * That way, the user can pass the same undo file to various programs as -+ * part of an FS upgrade instead of having to create multiple files and -+ * then apply them in correct order. -+ */ -+static errcode_t try_reopen_undo_file(int undo_fd, -+ struct undo_private_data *data) -+{ -+ struct undo_header hdr; -+ struct undo_key *dkey; -+ ext2fs_struct_stat statbuf; -+ unsigned int blocksize, fs_blocksize; -+ blk64_t super_block, lblk; -+ size_t num_keys, keys_per_block, i; -+ __u32 hdr_crc, key_crc; -+ errcode_t retval; -+ -+ /* Zero size already? */ -+ retval = ext2fs_fstat(undo_fd, &statbuf); -+ if (retval) -+ goto bad_file; -+ if (statbuf.st_size == 0) -+ goto out; -+ -+ /* check the file header */ -+ retval = io_channel_read_blk64(data->undo_file, 0, -(int)sizeof(hdr), -+ &hdr); -+ if (retval) -+ goto bad_file; -+ -+ if (memcmp(hdr.magic, E2UNDO_MAGIC, -+ sizeof(hdr.magic))) -+ goto bad_file; -+ hdr_crc = ext2fs_crc32c_le(~0, (unsigned char *)&hdr, -+ sizeof(struct undo_header) - -+ sizeof(__u32)); -+ if (ext2fs_le32_to_cpu(hdr.header_crc) != hdr_crc) -+ goto bad_file; -+ blocksize = ext2fs_le32_to_cpu(hdr.block_size); -+ fs_blocksize = ext2fs_le32_to_cpu(hdr.fs_block_size); -+ if (blocksize > E2UNDO_MAX_BLOCK_SIZE || -+ blocksize < E2UNDO_MIN_BLOCK_SIZE || -+ !blocksize || !fs_blocksize) -+ goto bad_file; -+ super_block = ext2fs_le64_to_cpu(hdr.super_offset); -+ num_keys = ext2fs_le64_to_cpu(hdr.num_keys); -+ io_channel_set_blksize(data->undo_file, blocksize); -+ if (hdr.f_compat || hdr.f_incompat || hdr.f_rocompat) -+ goto bad_file; -+ -+ /* Superblock matches this FS? */ -+ if (check_filesystem(&hdr, data->undo_file, blocksize, super_block, -+ data->real) != 0) { -+ retval = EXT2_ET_UNDO_FILE_WRONG; -+ goto out; -+ } -+ -+ /* Try to set ourselves up */ -+ data->tdb_data_size = blocksize; -+ retval = undo_setup_tdb(data); -+ if (retval) -+ goto bad_file; -+ data->num_keys = num_keys; -+ data->super_blk_num = super_block; -+ data->first_key_blk = ext2fs_le64_to_cpu(hdr.key_offset); -+ -+ /* load the written block map */ -+ keys_per_block = KEYS_PER_BLOCK(data); -+ lblk = data->first_key_blk; -+ dbg_printf("nr_keys=%lu, kpb=%zu, blksz=%u\n", -+ num_keys, keys_per_block, blocksize); -+ for (i = 0; i < num_keys; i += keys_per_block) { -+ size_t j, max_j; -+ __le32 crc; -+ -+ data->key_blk_num = lblk; -+ retval = io_channel_read_blk64(data->undo_file, -+ lblk, 1, data->keyb); -+ if (retval) -+ goto bad_key_replay; -+ -+ /* check keys */ -+ if (ext2fs_le32_to_cpu(data->keyb->magic) != KEYBLOCK_MAGIC) { -+ retval = EXT2_ET_UNDO_FILE_CORRUPT; -+ goto bad_key_replay; -+ } -+ crc = data->keyb->crc; -+ data->keyb->crc = 0; -+ key_crc = ext2fs_crc32c_le(~0, (unsigned char *)data->keyb, -+ blocksize); -+ if (ext2fs_le32_to_cpu(crc) != key_crc) { -+ retval = EXT2_ET_UNDO_FILE_CORRUPT; -+ goto bad_key_replay; -+ } -+ -+ /* load keys from key block */ -+ lblk++; -+ max_j = data->num_keys - i; -+ if (max_j > keys_per_block) -+ max_j = keys_per_block; -+ for (j = 0, dkey = data->keyb->keys; -+ j < max_j; -+ j++, dkey++) { -+ blk64_t fsblk = ext2fs_le64_to_cpu(dkey->fsblk); -+ blk64_t undo_blk = fsblk * fs_blocksize / blocksize; -+ size_t size = ext2fs_le32_to_cpu(dkey->size); -+ -+ ext2fs_mark_block_bitmap_range2(data->written_block_map, -+ undo_blk, -+ (size + blocksize - 1) / blocksize); -+ lblk += (size + blocksize - 1) / blocksize; -+ data->undo_blk_num = lblk; -+ data->keys_in_block = j + 1; -+ } -+ } -+ dbg_printf("Reopen undo, keyblk=%llu undoblk=%llu nrkeys=%zu kib=%zu\n", -+ data->key_blk_num, data->undo_blk_num, data->num_keys, -+ data->keys_in_block); -+ -+ data->hdr.state = hdr.state & ~E2UNDO_STATE_FINISHED; -+ data->hdr.f_compat = hdr.f_compat; -+ data->hdr.f_incompat = hdr.f_incompat; -+ data->hdr.f_rocompat = hdr.f_rocompat; -+ return retval; -+ -+bad_key_replay: -+ data->key_blk_num = data->undo_blk_num = 0; -+ data->keys_in_block = 0; -+ ext2fs_free_mem(&data->keyb); -+ ext2fs_free_generic_bitmap(data->written_block_map); -+ data->tdb_written = 0; -+ goto out; -+bad_file: -+ retval = EXT2_ET_UNDO_FILE_CORRUPT; -+out: -+ return retval; -+} -+ -+static void undo_atexit(void *p) -+{ -+ struct undo_private_data *data = p; -+ errcode_t err; -+ -+ err = write_undo_indexes(data, 1); -+ io_channel_close(data->undo_file); -+ -+ com_err(data->tdb_file, err, "while force-closing undo file"); -+} -+ - static errcode_t undo_open(const char *name, int flags, io_channel *channel) - { - io_channel io = NULL; - struct undo_private_data *data = NULL; -+ int undo_fd = -1; - errcode_t retval; - - if (name == 0) -@@ -344,23 +705,37 @@ static errcode_t undo_open(const char *name, int flags, io_channel *channel) - - memset(data, 0, sizeof(struct undo_private_data)); - data->magic = EXT2_ET_MAGIC_UNIX_IO_CHANNEL; -+ data->super_blk_num = 1; -+ data->first_key_blk = 2; -+ data->undo_blk_num = 3; - - if (undo_io_backing_manager) { - retval = undo_io_backing_manager->open(name, flags, - &data->real); - if (retval) - goto cleanup; -+ -+ data->tdb_file = strdup(tdb_file); -+ if (data->tdb_file == NULL) -+ goto cleanup; -+ undo_fd = ext2fs_open_file(data->tdb_file, O_RDWR | O_CREAT, -+ 0600); -+ if (undo_fd < 0) -+ goto cleanup; -+ -+ retval = undo_io_backing_manager->open(data->tdb_file, -+ IO_FLAG_RW, -+ &data->undo_file); -+ if (retval) -+ goto cleanup; - } else { -- data->real = 0; -+ data->real = NULL; -+ data->undo_file = NULL; - } - -- /* setup the tdb file */ -- data->tdb = tdb_open(tdb_file, 0, TDB_CLEAR_IF_FIRST, -- O_RDWR | O_CREAT | O_TRUNC | O_EXCL, 0600); -- if (!data->tdb) { -- retval = errno; -- goto cleanup; -- } -+ if (data->real) -+ io->flags = (io->flags & ~CHANNEL_FLAGS_DISCARD_ZEROES) | -+ (data->real->flags & CHANNEL_FLAGS_DISCARD_ZEROES); - - /* - * setup err handler for read so that we know -@@ -369,10 +744,28 @@ static errcode_t undo_open(const char *name, int flags, io_channel *channel) - if (data->real) - undo_err_handler_init(data->real); - -+ if (data->undo_file) { -+ retval = try_reopen_undo_file(undo_fd, data); -+ if (retval) -+ goto cleanup; -+ } -+ retval = ext2fs_add_exit_fn(undo_atexit, data); -+ if (retval) -+ goto cleanup; -+ - *channel = io; -- return 0; -+ if (undo_fd >= 0) -+ close(undo_fd); -+ return retval; - - cleanup: -+ ext2fs_remove_exit_fn(undo_atexit, data); -+ if (undo_fd >= 0) -+ close(undo_fd); -+ if (data && data->undo_file) -+ io_channel_close(data->undo_file); -+ if (data && data->tdb_file) -+ free(data->tdb_file); - if (data && data->real) - io_channel_close(data->real); - if (data) -@@ -385,7 +778,7 @@ cleanup: - static errcode_t undo_close(io_channel channel) - { - struct undo_private_data *data; -- errcode_t retval = 0; -+ errcode_t err, retval = 0; - - EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); - data = (struct undo_private_data *) channel->private_data; -@@ -394,18 +787,26 @@ static errcode_t undo_close(io_channel channel) - if (--channel->refcount > 0) - return 0; - /* Before closing write the file system identity */ -- retval = write_file_system_identity(channel, data->tdb); -- if (retval) -- return retval; -+ if (!getenv("UNDO_IO_SIMULATE_UNFINISHED")) -+ data->hdr.state = ext2fs_cpu_to_le32(E2UNDO_STATE_FINISHED); -+ err = write_undo_indexes(data, 1); -+ ext2fs_remove_exit_fn(undo_atexit, data); - if (data->real) - retval = io_channel_close(data->real); -- if (data->tdb) -- tdb_close(data->tdb); -+ if (data->tdb_file) -+ free(data->tdb_file); -+ if (data->undo_file) -+ io_channel_close(data->undo_file); -+ ext2fs_free_mem(&data->keyb); -+ if (data->written_block_map) -+ ext2fs_free_generic_bitmap(data->written_block_map); - ext2fs_free_mem(&channel->private_data); - if (channel->name) - ext2fs_free_mem(&channel->name); - ext2fs_free_mem(&channel); - -+ if (err) -+ return err; - return retval; - } - -@@ -418,14 +819,16 @@ static errcode_t undo_set_blksize(io_channel channel, int blksize) - data = (struct undo_private_data *) channel->private_data; - EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL); - -+ if (blksize > E2UNDO_MAX_BLOCK_SIZE || blksize < E2UNDO_MIN_BLOCK_SIZE) -+ return EXT2_ET_INVALID_ARGUMENT; -+ - if (data->real) - retval = io_channel_set_blksize(data->real, blksize); - /* - * Set the block size used for tdb - */ -- if (!data->tdb_data_size) { -+ if (!data->tdb_data_size || !data->tdb_written) - data->tdb_data_size = blksize; -- } - channel->block_size = blksize; - return retval; - } -@@ -510,6 +913,77 @@ static errcode_t undo_write_byte(io_channel channel, unsigned long offset, - return retval; - } - -+static errcode_t undo_discard(io_channel channel, unsigned long long block, -+ unsigned long long count) -+{ -+ struct undo_private_data *data; -+ errcode_t retval = 0; -+ int icount; -+ -+ EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); -+ data = (struct undo_private_data *) channel->private_data; -+ EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL); -+ -+ if (count > INT_MAX) -+ return EXT2_ET_UNIMPLEMENTED; -+ icount = count; -+ -+ /* -+ * First write the existing content into database -+ */ -+ retval = undo_write_tdb(channel, block, icount); -+ if (retval) -+ return retval; -+ if (data->real) -+ retval = io_channel_discard(data->real, block, count); -+ -+ return retval; -+} -+ -+static errcode_t undo_zeroout(io_channel channel, unsigned long long block, -+ unsigned long long count) -+{ -+ struct undo_private_data *data; -+ errcode_t retval = 0; -+ int icount; -+ -+ EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); -+ data = (struct undo_private_data *) channel->private_data; -+ EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL); -+ -+ if (count > INT_MAX) -+ return EXT2_ET_UNIMPLEMENTED; -+ icount = count; -+ -+ /* -+ * First write the existing content into database -+ */ -+ retval = undo_write_tdb(channel, block, icount); -+ if (retval) -+ return retval; -+ if (data->real) -+ retval = io_channel_zeroout(data->real, block, count); -+ -+ return retval; -+} -+ -+static errcode_t undo_cache_readahead(io_channel channel, -+ unsigned long long block, -+ unsigned long long count) -+{ -+ struct undo_private_data *data; -+ errcode_t retval = 0; -+ -+ EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); -+ data = (struct undo_private_data *) channel->private_data; -+ EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL); -+ -+ if (data->real) -+ retval = io_channel_cache_readahead(data->real, block, count); -+ -+ return retval; -+} -+ - /* - * Flush data buffers to disk. - */ -@@ -547,7 +1021,10 @@ static errcode_t undo_set_option(io_channel channel, const char *option, - tmp = strtoul(arg, &end, 0); - if (*end) - return EXT2_ET_INVALID_ARGUMENT; -+ if (tmp > E2UNDO_MAX_BLOCK_SIZE || tmp < E2UNDO_MIN_BLOCK_SIZE) -+ return EXT2_ET_INVALID_ARGUMENT; - if (!data->tdb_data_size || !data->tdb_written) { -+ data->tdb_written = -1; - data->tdb_data_size = tmp; - } - return 0; -@@ -601,6 +1078,9 @@ static struct struct_io_manager struct_undo_manager = { - .get_stats = undo_get_stats, - .read_blk64 = undo_read_blk64, - .write_blk64 = undo_write_blk64, -+ .discard = undo_discard, -+ .zeroout = undo_zeroout, -+ .cache_readahead = undo_cache_readahead, - }; - - io_manager undo_io_manager = &struct_undo_manager; -diff --git a/lib/ext2fs/unix_io.c b/lib/ext2fs/unix_io.c -index 23f22e3..1e71438 100644 ---- a/lib/ext2fs/unix_io.c -+++ b/lib/ext2fs/unix_io.c -@@ -15,8 +15,15 @@ - * %End-Header% - */ - -+#define _XOPEN_SOURCE 600 -+#define _DARWIN_C_SOURCE -+#define _FILE_OFFSET_BITS 64 -+#ifndef _LARGEFILE_SOURCE - #define _LARGEFILE_SOURCE -+#endif -+#ifndef _LARGEFILE64_SOURCE - #define _LARGEFILE64_SOURCE -+#endif - #ifndef _GNU_SOURCE - #define _GNU_SOURCE - #endif -@@ -35,6 +42,9 @@ - #ifdef __linux__ - #include - #endif -+#if HAVE_SYS_TYPES_H -+#include -+#endif - #ifdef HAVE_SYS_IOCTL_H - #include - #endif -@@ -44,9 +54,6 @@ - #if HAVE_SYS_STAT_H - #include - #endif --#if HAVE_SYS_TYPES_H --#include --#endif - #if HAVE_SYS_RESOURCE_H - #include - #endif -@@ -831,6 +838,23 @@ static errcode_t unix_write_blk64(io_channel channel, unsigned long long block, - #endif /* NO_IO_CACHE */ - } - -+static errcode_t unix_cache_readahead(io_channel channel, -+ unsigned long long block, -+ unsigned long long count) -+{ -+#ifdef POSIX_FADV_WILLNEED -+ struct unix_private_data *data; -+ -+ data = (struct unix_private_data *)channel->private_data; -+ return posix_fadvise(data->dev, -+ (ext2_loff_t)block * channel->block_size, -+ (ext2_loff_t)count * channel->block_size, -+ POSIX_FADV_WILLNEED); -+#else -+ return EXT2_ET_OP_NOT_SUPPORTED; -+#endif -+} -+ - static errcode_t unix_write_blk(io_channel channel, unsigned long block, - int count, const void *buf) - { -@@ -967,6 +991,76 @@ unimplemented: - return EXT2_ET_UNIMPLEMENTED; - } - -+/* parameters might not be used if OS doesn't support zeroout */ -+#pragma GCC diagnostic push -+#pragma GCC diagnostic ignored "-Wunused-parameter" -+static errcode_t unix_zeroout(io_channel channel, unsigned long long block, -+ unsigned long long count) -+{ -+ struct unix_private_data *data; -+ int ret; -+ -+ EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); -+ data = (struct unix_private_data *) channel->private_data; -+ EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL); -+ -+ if (getenv("UNIX_IO_NOZEROOUT")) -+ goto unimplemented; -+ -+ if (channel->flags & CHANNEL_FLAGS_BLOCK_DEVICE) { -+ /* Not implemented until the BLKZEROOUT mess is fixed */ -+ goto unimplemented; -+ } else { -+ /* Regular file, try to use truncate/punch/zero. */ -+ struct stat statbuf; -+ -+ if (count == 0) -+ return 0; -+ /* -+ * If we're trying to zero a range past the end of the file, -+ * extend the file size, then truncate everything. -+ */ -+ ret = fstat(data->dev, &statbuf); -+ if (ret) -+ goto err; -+ if (statbuf.st_size < (block + count) * channel->block_size) { -+ ret = ftruncate(data->dev, -+ (block + count) * channel->block_size); -+ if (ret) -+ goto err; -+ } -+#if defined(HAVE_FALLOCATE) && (defined(FALLOC_FL_ZERO_RANGE) || \ -+ (defined(FALLOC_FL_PUNCH_HOLE) && defined(FALLOC_FL_KEEP_SIZE))) -+#if defined(FALLOC_FL_PUNCH_HOLE) && defined(FALLOC_FL_KEEP_SIZE) -+ ret = fallocate(data->dev, -+ FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, -+ (off_t)(block) * channel->block_size, -+ (off_t)(count) * channel->block_size); -+ if (ret == 0) -+ goto err; -+#endif -+#ifdef FALLOC_FL_ZERO_RANGE -+ ret = fallocate(data->dev, -+ FALLOC_FL_ZERO_RANGE, -+ (off_t)(block) * channel->block_size, -+ (off_t)(count) * channel->block_size); -+#endif -+#else -+ goto unimplemented; -+#endif /* HAVE_FALLOCATE && (ZERO_RANGE || (PUNCH_HOLE && KEEP_SIZE)) */ -+ } -+err: -+ if (ret < 0) { -+ if (errno == EOPNOTSUPP) -+ goto unimplemented; -+ return errno; -+ } -+ return 0; -+unimplemented: -+ return EXT2_ET_UNIMPLEMENTED; -+} -+#pragma GCC diagnostic pop -+ - static struct struct_io_manager struct_unix_manager = { - .magic = EXT2_ET_MAGIC_IO_MANAGER, - .name = "Unix I/O Manager", -@@ -982,6 +1076,8 @@ static struct struct_io_manager struct_unix_manager = { - .read_blk64 = unix_read_blk64, - .write_blk64 = unix_write_blk64, - .discard = unix_discard, -+ .cache_readahead = unix_cache_readahead, -+ .zeroout = unix_zeroout, - }; - - io_manager unix_io_manager = &struct_unix_manager; -diff --git a/lib/ext2fs/unlink.c b/lib/ext2fs/unlink.c -index d2d31cc..8ab27ee 100644 ---- a/lib/ext2fs/unlink.c -+++ b/lib/ext2fs/unlink.c -@@ -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) { -diff --git a/lib/ext2fs/valid_blk.c b/lib/ext2fs/valid_blk.c -index 895e36e..db5d90a 100644 ---- a/lib/ext2fs/valid_blk.c -+++ b/lib/ext2fs/valid_blk.c -@@ -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; - } - -diff --git a/lib/quota/Makefile.in b/lib/quota/Makefile.in -deleted file mode 100644 -index 4dd42ed..0000000 ---- a/lib/quota/Makefile.in -+++ /dev/null -@@ -1,131 +0,0 @@ --# Makefile for the QUOTA library --# -- --srcdir = @srcdir@ --top_srcdir = @top_srcdir@ --VPATH = @srcdir@ --top_builddir = ../.. --my_dir = lib/quota --INSTALL = @INSTALL@ -- --@MCONFIG@ -- --all:: -- --OBJS= mkquota.o quotaio.o quotaio_v2.o quotaio_tree.o dict.o -- --SRCS= $(srcdir)/mkquota.c \ -- $(srcdir)/quotaio.c \ -- $(srcdir)/quotaio_tree.c \ -- $(srcdir)/quotaio_v2.c \ -- $(srcdir)/../../e2fsck/dict.c -- --LIBRARY= libquota --LIBDIR= quota -- --#ELF_VERSION = 1.0 --#ELF_SO_VERSION = 1 --#ELF_IMAGE = libquota --#ELF_MYDIR = quota --#ELF_INSTALL_DIR = $(root_libdir) --#ELF_OTHER_LIBS = -lext2fs -- --#BSDLIB_VERSION = 1.0 --#BSDLIB_IMAGE = libquota --#BSDLIB_MYDIR = quota --#BSDLIB_INSTALL_DIR = $(root_libdir) -- --@MAKEFILE_LIBRARY@ --#MAKEFILE_ELF# --#MAKEFILE_BSDLIB# --@MAKEFILE_PROFILE@ -- --.c.o: -- $(E) " CC $<" -- $(Q) $(CC) $(ALL_CFLAGS) -c $< -o $@ -- $(Q) $(CHECK_CMD) $(ALL_CFLAGS) $< --@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 $< -- --dict.o: -- $(E) " CC $<" -- $(Q) $(CC) -c $(ALL_CFLAGS) $(top_srcdir)/e2fsck/dict.c -o $@ --@PROFILE_CMT@ $(Q) $(CC) $(ALL_CFLAGS) -g -pg -o profiled/dict.o -c \ --@PROFILE_CMT@ $(top_srcdir)/e2fsck/dict.c --#ELF_CMT# $(Q) $(CC) $(ALL_CFLAGS) -fPIC -o elfshared/$*.o -c \ --#ELF_CMT# $(top_srcdir)/e2fsck/dict.c --#BSDLIB_CMT# $(Q) $(CC) $(ALL_CFLAGS) $(BSDLIB_PIC_FLAG) -o pic/$*.o -c \ --#BSDLIB_CMT# $(top_srcdir)/e2fsck/dict.c -- --installdirs:: -- --install:: all -- --uninstall:: -- --clean:: -- $(RM) -f \#* *.s *.o *.a *~ *.bak core profiled/* -- $(RM) -f ../libquota.a ../libquota_p.a $(SMANPAGES) -- --#check:: tst_uuid --# LD_LIBRARY_PATH=$(LIB) DYLD_LIBRARY_PATH=$(LIB) ./tst_uuid -- --mostlyclean:: clean --distclean:: clean -- $(RM) -f .depend Makefile \ -- $(srcdir)/TAGS $(srcdir)/Makefile.in.old -- --# --# Hack to parallel makes recognize dependencies correctly. --# --../../lib/libquota.a: libquota.a --../../lib/libquota.so: image --../../lib/libquota.dylib: image -- --$(OBJS): -- --# +++ Dependency line eater +++ --# --# Makefile dependencies follow. This must be the last section in --# the Makefile.in file --# --mkquota.o: $(srcdir)/mkquota.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 \ -- $(top_srcdir)/lib/e2p/e2p.h $(srcdir)/quotaio.h $(srcdir)/dqblk_v2.h \ -- $(srcdir)/quotaio_tree.h $(top_srcdir)/lib/../e2fsck/dict.h \ -- $(srcdir)/quotaio_v2.h $(srcdir)/common.h --quotaio.o: $(srcdir)/quotaio.c $(top_builddir)/lib/config.h \ -- $(top_builddir)/lib/dirpaths.h $(srcdir)/common.h \ -- $(top_builddir)/lib/ext2fs/ext2_types.h $(srcdir)/quotaio.h \ -- $(top_srcdir)/lib/ext2fs/ext2_fs.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)/dqblk_v2.h $(srcdir)/quotaio_tree.h \ -- $(top_srcdir)/lib/../e2fsck/dict.h --quotaio_tree.o: $(srcdir)/quotaio_tree.c $(top_builddir)/lib/config.h \ -- $(top_builddir)/lib/dirpaths.h $(srcdir)/common.h \ -- $(top_builddir)/lib/ext2fs/ext2_types.h $(srcdir)/quotaio_tree.h \ -- $(srcdir)/quotaio.h $(top_srcdir)/lib/ext2fs/ext2_fs.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)/dqblk_v2.h $(top_srcdir)/lib/../e2fsck/dict.h --quotaio_v2.o: $(srcdir)/quotaio_v2.c $(top_builddir)/lib/config.h \ -- $(top_builddir)/lib/dirpaths.h $(srcdir)/common.h \ -- $(top_builddir)/lib/ext2fs/ext2_types.h $(srcdir)/quotaio_v2.h \ -- $(srcdir)/quotaio.h $(top_srcdir)/lib/ext2fs/ext2_fs.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)/dqblk_v2.h $(srcdir)/quotaio_tree.h \ -- $(top_srcdir)/lib/../e2fsck/dict.h --dict.o: $(srcdir)/../../e2fsck/dict.c $(top_builddir)/lib/config.h \ -- $(top_builddir)/lib/dirpaths.h $(srcdir)/../../e2fsck/dict.h -diff --git a/lib/quota/common.h b/lib/quota/common.h -deleted file mode 100644 -index f1ad79f..0000000 ---- a/lib/quota/common.h -+++ /dev/null -@@ -1,36 +0,0 @@ --/* -- * -- * Various things common for all utilities -- * -- */ -- --#ifndef __QUOTA_COMMON_H__ --#define __QUOTA_COMMON_H__ -- --#if EXT2_FLAT_INCLUDES --#include "e2_types.h" --#else --#include --#endif /* EXT2_FLAT_INCLUDES */ -- --/* #define DEBUG_QUOTA 1 */ -- --#ifndef __attribute__ --# if !defined __GNUC__ || __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 8) || __STRICT_ANSI__ --# define __attribute__(x) --# endif --#endif -- --#define log_err(format, arg ...) \ -- fprintf(stderr, "[ERROR] %s:%d:%s:: " format "\n", \ -- __FILE__, __LINE__, __func__, ## arg) -- --#ifdef DEBUG_QUOTA --# define log_debug(format, arg ...) \ -- fprintf(stderr, "[DEBUG] %s:%d:%s:: " format "\n", \ -- __FILE__, __LINE__, __func__, ## arg) --#else --# define log_debug(format, ...) --#endif -- --#endif /* __QUOTA_COMMON_H__ */ -diff --git a/lib/quota/dqblk_v2.h b/lib/quota/dqblk_v2.h -deleted file mode 100644 -index d12512a..0000000 ---- a/lib/quota/dqblk_v2.h -+++ /dev/null -@@ -1,31 +0,0 @@ --/* -- * Header file for disk format of new quotafile format -- * -- * Jan Kara - sponsored by SuSE CR -- */ -- --#ifndef __QUOTA_DQBLK_V2_H__ --#define __QUOTA_DQBLK_V2_H__ -- --#include "quotaio_tree.h" -- --/* Structure for format specific information */ --struct v2_mem_dqinfo { -- struct qtree_mem_dqinfo dqi_qtree; -- unsigned int dqi_flags; /* Flags set in quotafile */ -- unsigned int dqi_used_entries; /* Number of entries in file - -- updated by scan_dquots */ -- unsigned int dqi_data_blocks; /* Number of data blocks in file - -- updated by scan_dquots */ --}; -- --struct v2_mem_dqblk { -- long long dqb_off; /* Offset of dquot in file */ --}; -- --struct quotafile_ops; /* Will be defined later in quotaio.h */ -- --/* Operations above this format */ --extern struct quotafile_ops quotafile_ops_2; -- --#endif /* __QUOTA_DQBLK_V2_H__ */ -diff --git a/lib/quota/mkquota.c b/lib/quota/mkquota.c -deleted file mode 100644 -index 0ece088..0000000 ---- a/lib/quota/mkquota.c -+++ /dev/null -@@ -1,630 +0,0 @@ --/* -- * mkquota.c --- create quota files for a filesystem -- * -- * Aditya Kali -- */ --#include "config.h" --#include --#include --#include --#include --#include --#include -- --#include "ext2fs/ext2_fs.h" --#include "ext2fs/ext2fs.h" --#include "e2p/e2p.h" -- --#include "quotaio.h" --#include "quotaio_v2.h" --#include "quotaio_tree.h" --#include "common.h" -- --/* Needed for architectures where sizeof(int) != sizeof(void *) */ --#define UINT_TO_VOIDPTR(val) ((void *)(intptr_t)(val)) --#define VOIDPTR_TO_UINT(ptr) ((unsigned int)(intptr_t)(ptr)) -- --#if DEBUG_QUOTA --static void print_inode(struct ext2_inode *inode) --{ -- if (!inode) -- return; -- -- fprintf(stderr, " i_mode = %d\n", inode->i_mode); -- fprintf(stderr, " i_uid = %d\n", inode->i_uid); -- fprintf(stderr, " i_size = %d\n", inode->i_size); -- fprintf(stderr, " i_atime = %d\n", inode->i_atime); -- fprintf(stderr, " i_ctime = %d\n", inode->i_ctime); -- fprintf(stderr, " i_mtime = %d\n", inode->i_mtime); -- fprintf(stderr, " i_dtime = %d\n", inode->i_dtime); -- fprintf(stderr, " i_gid = %d\n", inode->i_gid); -- fprintf(stderr, " i_links_count = %d\n", inode->i_links_count); -- fprintf(stderr, " i_blocks = %d\n", inode->i_blocks); -- fprintf(stderr, " i_flags = %d\n", inode->i_flags); -- -- return; --} -- --static void print_dquot(const char *desc, struct dquot *dq) --{ -- if (desc) -- fprintf(stderr, "%s: ", desc); -- fprintf(stderr, "%u %lld:%lld:%lld %lld:%lld:%lld\n", -- dq->dq_id, dq->dq_dqb.dqb_curspace, -- dq->dq_dqb.dqb_bsoftlimit, dq->dq_dqb.dqb_bhardlimit, -- dq->dq_dqb.dqb_curinodes, -- dq->dq_dqb.dqb_isoftlimit, dq->dq_dqb.dqb_ihardlimit); --} --#else --static void print_dquot(const char *desc, struct dquot *dq) --{ --} --#endif -- --/* -- * Returns 0 if not able to find the quota file, otherwise returns its -- * inode number. -- */ --int quota_file_exists(ext2_filsys fs, int qtype, int fmt) --{ -- char qf_name[256]; -- errcode_t ret; -- ext2_ino_t ino; -- -- if (qtype >= MAXQUOTAS) -- return -EINVAL; -- -- quota_get_qf_name(qtype, QFMT_VFS_V1, qf_name); -- -- ret = ext2fs_lookup(fs, EXT2_ROOT_INO, qf_name, strlen(qf_name), 0, -- &ino); -- if (ret) -- return 0; -- -- return ino; --} -- --/* -- * Set the value for reserved quota inode number field in superblock. -- */ --void quota_set_sb_inum(ext2_filsys fs, ext2_ino_t ino, int qtype) --{ -- ext2_ino_t *inump; -- -- inump = (qtype == USRQUOTA) ? &fs->super->s_usr_quota_inum : -- &fs->super->s_grp_quota_inum; -- -- log_debug("setting quota ino in superblock: ino=%u, type=%d", ino, -- qtype); -- *inump = ino; -- ext2fs_mark_super_dirty(fs); --} -- --errcode_t quota_remove_inode(ext2_filsys fs, int qtype) --{ -- ext2_ino_t qf_ino; -- errcode_t retval; -- -- retval = ext2fs_read_bitmaps(fs); -- if (retval) { -- log_err("Couldn't read bitmaps: %s", error_message(retval)); -- return retval; -- } -- qf_ino = (qtype == USRQUOTA) ? fs->super->s_usr_quota_inum : -- fs->super->s_grp_quota_inum; -- quota_set_sb_inum(fs, 0, qtype); -- /* Truncate the inode only if its a reserved one. */ -- if (qf_ino < EXT2_FIRST_INODE(fs->super)) -- quota_inode_truncate(fs, qf_ino); -- -- ext2fs_mark_super_dirty(fs); -- fs->flags &= ~EXT2_FLAG_SUPER_ONLY; -- retval = ext2fs_write_bitmaps(fs); -- if (retval) { -- log_err("Couldn't write bitmaps: %s", error_message(retval)); -- return retval; -- } -- return 0; --} -- --static void write_dquots(dict_t *dict, struct quota_handle *qh) --{ -- dnode_t *n; -- struct dquot *dq; -- -- for (n = dict_first(dict); n; n = dict_next(dict, n)) { -- dq = dnode_get(n); -- if (dq) { -- print_dquot("write", dq); -- dq->dq_h = qh; -- update_grace_times(dq); -- qh->qh_ops->commit_dquot(dq); -- } -- } --} -- --errcode_t quota_write_inode(quota_ctx_t qctx, int qtype) --{ -- int retval = 0, i; -- dict_t *dict; -- ext2_filsys fs; -- struct quota_handle *h = NULL; -- int fmt = QFMT_VFS_V1; -- -- if (!qctx) -- return 0; -- -- fs = qctx->fs; -- retval = ext2fs_get_mem(sizeof(struct quota_handle), &h); -- if (retval) { -- log_err("Unable to allocate quota handle: %s", -- error_message(retval)); -- goto out; -- } -- -- retval = ext2fs_read_bitmaps(fs); -- if (retval) { -- log_err("Couldn't read bitmaps: %s", error_message(retval)); -- goto out; -- } -- -- for (i = 0; i < MAXQUOTAS; i++) { -- if ((qtype != -1) && (i != qtype)) -- continue; -- -- dict = qctx->quota_dict[i]; -- if (!dict) -- continue; -- -- retval = quota_file_create(h, fs, i, fmt); -- if (retval < 0) { -- log_err("Cannot initialize io on quotafile"); -- continue; -- } -- -- write_dquots(dict, h); -- retval = quota_file_close(qctx, h); -- if (retval < 0) { -- log_err("Cannot finish IO on new quotafile: %s", -- strerror(errno)); -- if (h->qh_qf.e2_file) -- ext2fs_file_close(h->qh_qf.e2_file); -- quota_inode_truncate(fs, h->qh_qf.ino); -- continue; -- } -- -- /* Set quota inode numbers in superblock. */ -- quota_set_sb_inum(fs, h->qh_qf.ino, i); -- ext2fs_mark_super_dirty(fs); -- ext2fs_mark_bb_dirty(fs); -- fs->flags &= ~EXT2_FLAG_SUPER_ONLY; -- } -- -- retval = ext2fs_write_bitmaps(fs); -- if (retval) { -- log_err("Couldn't write bitmaps: %s", error_message(retval)); -- goto out; -- } --out: -- if (h) -- ext2fs_free_mem(&h); -- return retval; --} -- --/******************************************************************/ --/* Helper functions for computing quota in memory. */ --/******************************************************************/ -- --static int dict_uint_cmp(const void *a, const void *b) --{ -- unsigned int c, d; -- -- c = VOIDPTR_TO_UINT(a); -- d = VOIDPTR_TO_UINT(b); -- -- if (c == d) -- return 0; -- else if (c > d) -- return 1; -- else -- return -1; --} -- --static inline qid_t get_qid(struct ext2_inode *inode, int qtype) --{ -- if (qtype == USRQUOTA) -- return inode_uid(*inode); -- return inode_gid(*inode); --} -- --static void quota_dnode_free(dnode_t *node, -- void *context EXT2FS_ATTR((unused))) --{ -- void *ptr = node ? dnode_get(node) : 0; -- -- ext2fs_free_mem(&ptr); -- free(node); --} -- --/* -- * Set up the quota tracking data structures. -- */ --errcode_t quota_init_context(quota_ctx_t *qctx, ext2_filsys fs, int qtype) --{ -- errcode_t err; -- dict_t *dict; -- quota_ctx_t ctx; -- int i; -- -- err = ext2fs_get_mem(sizeof(struct quota_ctx), &ctx); -- if (err) { -- log_err("Failed to allocate quota context"); -- return err; -- } -- -- memset(ctx, 0, sizeof(struct quota_ctx)); -- for (i = 0; i < MAXQUOTAS; i++) { -- ctx->quota_file[i] = NULL; -- if ((qtype != -1) && (i != qtype)) -- continue; -- err = ext2fs_get_mem(sizeof(dict_t), &dict); -- if (err) { -- log_err("Failed to allocate dictionary"); -- quota_release_context(&ctx); -- return err; -- } -- ctx->quota_dict[i] = dict; -- dict_init(dict, DICTCOUNT_T_MAX, dict_uint_cmp); -- dict_set_allocator(dict, NULL, quota_dnode_free, NULL); -- } -- -- ctx->fs = fs; -- *qctx = ctx; -- return 0; --} -- --void quota_release_context(quota_ctx_t *qctx) --{ -- errcode_t err; -- dict_t *dict; -- int i; -- quota_ctx_t ctx; -- -- if (!qctx) -- return; -- -- ctx = *qctx; -- for (i = 0; i < MAXQUOTAS; i++) { -- dict = ctx->quota_dict[i]; -- ctx->quota_dict[i] = 0; -- if (dict) { -- dict_free_nodes(dict); -- free(dict); -- } -- if (ctx->quota_file[i]) { -- err = quota_file_close(ctx, ctx->quota_file[i]); -- if (err) { -- log_err("Cannot close quotafile: %s", -- strerror(errno)); -- ext2fs_free_mem(&ctx->quota_file[i]); -- } -- } -- } -- *qctx = NULL; -- free(ctx); --} -- --static struct dquot *get_dq(dict_t *dict, __u32 key) --{ -- struct dquot *dq; -- dnode_t *n; -- -- n = dict_lookup(dict, UINT_TO_VOIDPTR(key)); -- if (n) -- dq = dnode_get(n); -- else { -- if (ext2fs_get_mem(sizeof(struct dquot), &dq)) { -- log_err("Unable to allocate dquot"); -- return NULL; -- } -- memset(dq, 0, sizeof(struct dquot)); -- dict_alloc_insert(dict, UINT_TO_VOIDPTR(key), dq); -- dq->dq_id = key; -- } -- return dq; --} -- -- --/* -- * Called to update the blocks used by a particular inode -- */ --void quota_data_add(quota_ctx_t qctx, struct ext2_inode *inode, ext2_ino_t ino, -- qsize_t space) --{ -- struct dquot *dq; -- dict_t *dict; -- int i; -- -- if (!qctx) -- return; -- -- log_debug("ADD_DATA: Inode: %u, UID/GID: %u/%u, space: %ld", ino, -- inode_uid(*inode), -- inode_gid(*inode), space); -- for (i = 0; i < MAXQUOTAS; i++) { -- dict = qctx->quota_dict[i]; -- if (dict) { -- dq = get_dq(dict, get_qid(inode, i)); -- if (dq) -- dq->dq_dqb.dqb_curspace += space; -- } -- } --} -- --/* -- * Called to remove some blocks used by a particular inode -- */ --void quota_data_sub(quota_ctx_t qctx, struct ext2_inode *inode, ext2_ino_t ino, -- qsize_t space) --{ -- struct dquot *dq; -- dict_t *dict; -- int i; -- -- if (!qctx) -- return; -- -- log_debug("SUB_DATA: Inode: %u, UID/GID: %u/%u, space: %ld", ino, -- inode_uid(*inode), -- inode_gid(*inode), space); -- for (i = 0; i < MAXQUOTAS; i++) { -- dict = qctx->quota_dict[i]; -- if (dict) { -- dq = get_dq(dict, get_qid(inode, i)); -- dq->dq_dqb.dqb_curspace -= space; -- } -- } --} -- --/* -- * Called to count the files used by an inode's user/group -- */ --void quota_data_inodes(quota_ctx_t qctx, struct ext2_inode *inode, -- ext2_ino_t ino, int adjust) --{ -- struct dquot *dq; -- dict_t *dict; -- int i; -- -- if (!qctx) -- return; -- -- log_debug("ADJ_INODE: Inode: %u, UID/GID: %u/%u, adjust: %d", ino, -- inode_uid(*inode), -- inode_gid(*inode), adjust); -- for (i = 0; i < MAXQUOTAS; i++) { -- dict = qctx->quota_dict[i]; -- if (dict) { -- dq = get_dq(dict, get_qid(inode, i)); -- dq->dq_dqb.dqb_curinodes += adjust; -- } -- } --} -- --errcode_t quota_compute_usage(quota_ctx_t qctx) --{ -- ext2_filsys fs; -- ext2_ino_t ino; -- errcode_t ret; -- struct ext2_inode inode; -- qsize_t space; -- ext2_inode_scan scan; -- -- if (!qctx) -- return 0; -- -- fs = qctx->fs; -- ret = ext2fs_open_inode_scan(fs, 0, &scan); -- if (ret) { -- log_err("while opening inode scan. ret=%ld", ret); -- return ret; -- } -- -- while (1) { -- ret = ext2fs_get_next_inode(scan, &ino, &inode); -- if (ret) { -- log_err("while getting next inode. ret=%ld", ret); -- ext2fs_close_inode_scan(scan); -- return ret; -- } -- if (ino == 0) -- break; -- if (inode.i_links_count && -- (ino == EXT2_ROOT_INO || -- ino >= EXT2_FIRST_INODE(fs->super))) { -- space = ext2fs_inode_i_blocks(fs, &inode) << 9; -- quota_data_add(qctx, &inode, ino, space); -- quota_data_inodes(qctx, &inode, ino, +1); -- } -- } -- -- ext2fs_close_inode_scan(scan); -- -- return 0; --} -- --struct scan_dquots_data { -- dict_t *quota_dict; -- int update_limits; /* update limits from disk */ -- int update_usage; -- int usage_is_inconsistent; --}; -- --static int scan_dquots_callback(struct dquot *dquot, void *cb_data) --{ -- struct scan_dquots_data *scan_data = cb_data; -- dict_t *quota_dict = scan_data->quota_dict; -- struct dquot *dq; -- -- dq = get_dq(quota_dict, dquot->dq_id); -- dq->dq_id = dquot->dq_id; -- dq->dq_flags |= DQF_SEEN; -- -- print_dquot("mem", dq); -- print_dquot("dsk", dquot); -- -- /* Check if there is inconsistancy. */ -- if (dq->dq_dqb.dqb_curspace != dquot->dq_dqb.dqb_curspace || -- dq->dq_dqb.dqb_curinodes != dquot->dq_dqb.dqb_curinodes) { -- scan_data->usage_is_inconsistent = 1; -- fprintf(stderr, "[QUOTA WARNING] Usage inconsistent for ID %d:" -- "actual (%llu, %llu) != expected (%llu, %llu)\n", -- dq->dq_id, (long long)dq->dq_dqb.dqb_curspace, -- (long long)dq->dq_dqb.dqb_curinodes, -- (long long)dquot->dq_dqb.dqb_curspace, -- (long long)dquot->dq_dqb.dqb_curinodes); -- } -- -- if (scan_data->update_limits) { -- dq->dq_dqb.dqb_ihardlimit = dquot->dq_dqb.dqb_ihardlimit; -- dq->dq_dqb.dqb_isoftlimit = dquot->dq_dqb.dqb_isoftlimit; -- dq->dq_dqb.dqb_bhardlimit = dquot->dq_dqb.dqb_bhardlimit; -- dq->dq_dqb.dqb_bsoftlimit = dquot->dq_dqb.dqb_bsoftlimit; -- } -- -- if (scan_data->update_usage) { -- dq->dq_dqb.dqb_curspace = dquot->dq_dqb.dqb_curspace; -- dq->dq_dqb.dqb_curinodes = dquot->dq_dqb.dqb_curinodes; -- } -- -- return 0; --} -- --/* -- * Read all dquots from quota file into memory -- */ --static errcode_t quota_read_all_dquots(struct quota_handle *qh, -- quota_ctx_t qctx, int update_limits) --{ -- struct scan_dquots_data scan_data; -- -- scan_data.quota_dict = qctx->quota_dict[qh->qh_type]; -- scan_data.update_limits = update_limits; -- scan_data.update_usage = 0; -- -- return qh->qh_ops->scan_dquots(qh, scan_dquots_callback, &scan_data); --} -- --/* -- * Write all memory dquots into quota file -- */ --#if 0 /* currently unused, but may be useful in the future? */ --static errcode_t quota_write_all_dquots(struct quota_handle *qh, -- quota_ctx_t qctx) --{ -- errcode_t err; -- -- err = ext2fs_read_bitmaps(qctx->fs); -- if (err) -- return err; -- write_dquots(qctx->quota_dict[qh->qh_type], qh); -- ext2fs_mark_bb_dirty(qctx->fs); -- qctx->fs->flags &= ~EXT2_FLAG_SUPER_ONLY; -- ext2fs_write_bitmaps(qctx->fs); -- return 0; --} --#endif -- --/* -- * Updates the in-memory quota limits from the given quota inode. -- */ --errcode_t quota_update_limits(quota_ctx_t qctx, ext2_ino_t qf_ino, int type) --{ -- struct quota_handle *qh; -- errcode_t err; -- -- if (!qctx) -- return 0; -- -- err = ext2fs_get_mem(sizeof(struct quota_handle), &qh); -- if (err) { -- log_err("Unable to allocate quota handle"); -- return err; -- } -- -- err = quota_file_open(qctx, qh, qf_ino, type, -1, 0); -- if (err) { -- log_err("Open quota file failed"); -- goto out; -- } -- -- quota_read_all_dquots(qh, qctx, 1); -- -- err = quota_file_close(qctx, qh); -- if (err) { -- log_err("Cannot finish IO on new quotafile: %s", -- strerror(errno)); -- if (qh->qh_qf.e2_file) -- ext2fs_file_close(qh->qh_qf.e2_file); -- } --out: -- ext2fs_free_mem(&qh); -- return err; --} -- --/* -- * Compares the measured quota in qctx->quota_dict with that in the quota inode -- * on disk and updates the limits in qctx->quota_dict. 'usage_inconsistent' is -- * set to 1 if the supplied and on-disk quota usage values are not identical. -- */ --errcode_t quota_compare_and_update(quota_ctx_t qctx, int qtype, -- int *usage_inconsistent) --{ -- struct quota_handle qh; -- struct scan_dquots_data scan_data; -- struct dquot *dq; -- dnode_t *n; -- dict_t *dict = qctx->quota_dict[qtype]; -- errcode_t err = 0; -- -- if (!dict) -- goto out; -- -- err = quota_file_open(qctx, &qh, 0, qtype, -1, 0); -- if (err) { -- log_err("Open quota file failed"); -- goto out; -- } -- -- scan_data.quota_dict = qctx->quota_dict[qtype]; -- scan_data.update_limits = 1; -- scan_data.update_usage = 0; -- scan_data.usage_is_inconsistent = 0; -- err = qh.qh_ops->scan_dquots(&qh, scan_dquots_callback, &scan_data); -- if (err) { -- log_err("Error scanning dquots"); -- goto out_close_qh; -- } -- -- for (n = dict_first(dict); n; n = dict_next(dict, n)) { -- dq = dnode_get(n); -- if (!dq) -- continue; -- if ((dq->dq_flags & DQF_SEEN) == 0) { -- fprintf(stderr, "[QUOTA WARNING] " -- "Missing quota entry ID %d\n", dq->dq_id); -- scan_data.usage_is_inconsistent = 1; -- } -- } -- *usage_inconsistent = scan_data.usage_is_inconsistent; -- --out_close_qh: -- err = quota_file_close(qctx, &qh); -- if (err) { -- log_err("Cannot close quotafile: %s", error_message(errno)); -- if (qh.qh_qf.e2_file) -- ext2fs_file_close(qh.qh_qf.e2_file); -- } --out: -- return err; --} -diff --git a/lib/quota/quotaio.c b/lib/quota/quotaio.c -deleted file mode 100644 -index 65fccaa..0000000 ---- a/lib/quota/quotaio.c -+++ /dev/null -@@ -1,422 +0,0 @@ --/** quotaio.c -- * -- * Generic IO operations on quotafiles -- * Jan Kara - sponsored by SuSE CR -- * Aditya Kali - Ported to e2fsprogs -- */ -- --#include "config.h" --#include --#include --#include --#include --#include --#include --#include --#include --#include -- --#include "common.h" --#include "quotaio.h" -- --static const char * const extensions[MAXQUOTAS] = {"user", "group"}; --static const char * const basenames[] = { -- "", /* undefined */ -- "quota", /* QFMT_VFS_OLD */ -- "aquota", /* QFMT_VFS_V0 */ -- "", /* QFMT_OCFS2 */ -- "aquota" /* QFMT_VFS_V1 */ --}; -- --/* Header in all newer quotafiles */ --struct disk_dqheader { -- __u32 dqh_magic; -- __u32 dqh_version; --} __attribute__ ((packed)); -- --/** -- * Convert type of quota to written representation -- */ --const char *type2name(int type) --{ -- return extensions[type]; --} -- --/** -- * Creates a quota file name for given type and format. -- */ --const char *quota_get_qf_name(int type, int fmt, char *buf) --{ -- if (!buf) -- return NULL; -- snprintf(buf, QUOTA_NAME_LEN, "%s.%s", -- basenames[fmt], extensions[type]); -- -- return buf; --} -- --const char *quota_get_qf_path(const char *mntpt, int qtype, int fmt, -- char *path_buf, size_t path_buf_size) --{ -- char qf_name[QUOTA_NAME_LEN]; -- -- if (!mntpt || !path_buf || !path_buf_size) -- return NULL; -- -- strncpy(path_buf, mntpt, path_buf_size); -- strncat(path_buf, "/", 1); -- strncat(path_buf, quota_get_qf_name(qtype, fmt, qf_name), -- path_buf_size - strlen(path_buf)); -- -- return path_buf; --} -- --/* -- * Set grace time if needed -- */ --void update_grace_times(struct dquot *q) --{ -- time_t now; -- -- time(&now); -- if (q->dq_dqb.dqb_bsoftlimit && toqb(q->dq_dqb.dqb_curspace) > -- q->dq_dqb.dqb_bsoftlimit) { -- if (!q->dq_dqb.dqb_btime) -- q->dq_dqb.dqb_btime = -- now + q->dq_h->qh_info.dqi_bgrace; -- } else { -- q->dq_dqb.dqb_btime = 0; -- } -- -- if (q->dq_dqb.dqb_isoftlimit && q->dq_dqb.dqb_curinodes > -- q->dq_dqb.dqb_isoftlimit) { -- if (!q->dq_dqb.dqb_itime) -- q->dq_dqb.dqb_itime = -- now + q->dq_h->qh_info.dqi_igrace; -- } else { -- q->dq_dqb.dqb_itime = 0; -- } --} -- --static int compute_num_blocks_proc(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 *private) --{ -- blk64_t *num_blocks = private; -- -- *num_blocks += 1; -- return 0; --} -- --errcode_t quota_inode_truncate(ext2_filsys fs, ext2_ino_t ino) --{ -- struct ext2_inode inode; -- errcode_t err; -- -- if ((err = ext2fs_read_inode(fs, ino, &inode))) -- return err; -- -- if ((ino == EXT4_USR_QUOTA_INO) || (ino == EXT4_GRP_QUOTA_INO)) { -- inode.i_dtime = fs->now ? fs->now : time(0); -- if (!ext2fs_inode_has_valid_blocks2(fs, &inode)) -- return 0; -- err = ext2fs_punch(fs, ino, &inode, NULL, 0, ~0ULL); -- if (err) -- return err; -- fs->flags &= ~EXT2_FLAG_SUPER_ONLY; -- memset(&inode, 0, sizeof(struct ext2_inode)); -- } else { -- inode.i_flags &= ~EXT2_IMMUTABLE_FL; -- } -- err = ext2fs_write_inode(fs, ino, &inode); -- return err; --} -- --static ext2_off64_t compute_inode_size(ext2_filsys fs, ext2_ino_t ino) --{ -- blk64_t num_blocks = 0; -- -- ext2fs_block_iterate3(fs, ino, -- BLOCK_FLAG_READ_ONLY, -- NULL, -- compute_num_blocks_proc, -- &num_blocks); -- return num_blocks * fs->blocksize; --} -- --/* Functions to read/write quota file. */ --static unsigned int quota_write_nomount(struct quota_file *qf, -- ext2_loff_t offset, -- void *buf, unsigned int size) --{ -- ext2_file_t e2_file = qf->e2_file; -- unsigned int bytes_written = 0; -- errcode_t err; -- -- err = ext2fs_file_llseek(e2_file, offset, EXT2_SEEK_SET, NULL); -- if (err) { -- log_err("ext2fs_file_llseek failed: %ld", err); -- return 0; -- } -- -- err = ext2fs_file_write(e2_file, buf, size, &bytes_written); -- if (err) { -- log_err("ext2fs_file_write failed: %ld", err); -- return 0; -- } -- -- /* Correct inode.i_size is set in end_io. */ -- return bytes_written; --} -- --static unsigned int quota_read_nomount(struct quota_file *qf, -- ext2_loff_t offset, -- void *buf, unsigned int size) --{ -- ext2_file_t e2_file = qf->e2_file; -- unsigned int bytes_read = 0; -- errcode_t err; -- -- err = ext2fs_file_llseek(e2_file, offset, EXT2_SEEK_SET, NULL); -- if (err) { -- log_err("ext2fs_file_llseek failed: %ld", err); -- return 0; -- } -- -- err = ext2fs_file_read(e2_file, buf, size, &bytes_read); -- if (err) { -- log_err("ext2fs_file_read failed: %ld", err); -- return 0; -- } -- -- return bytes_read; --} -- --/* -- * Detect quota format and initialize quota IO -- */ --errcode_t quota_file_open(quota_ctx_t qctx, struct quota_handle *h, -- ext2_ino_t qf_ino, int type, int fmt, int flags) --{ -- ext2_filsys fs = qctx->fs; -- ext2_file_t e2_file; -- errcode_t err; -- int allocated_handle = 0; -- -- if (type >= MAXQUOTAS) -- return EINVAL; -- -- if (fmt == -1) -- fmt = QFMT_VFS_V1; -- -- err = ext2fs_read_bitmaps(fs); -- if (err) -- return err; -- -- if (qf_ino == 0) { -- if (type == USRQUOTA) -- qf_ino = fs->super->s_usr_quota_inum; -- else -- qf_ino = fs->super->s_grp_quota_inum; -- } -- -- log_debug("Opening quota ino=%lu, type=%d", qf_ino, type); -- err = ext2fs_file_open(fs, qf_ino, flags, &e2_file); -- if (err) { -- log_err("ext2fs_file_open failed: %s", error_message(err)); -- return err; -- } -- -- if (!h) { -- if (qctx->quota_file[type]) { -- h = qctx->quota_file[type]; -- if (((flags & EXT2_FILE_WRITE) == 0) || -- (h->qh_file_flags & EXT2_FILE_WRITE)) -- return 0; -- (void) quota_file_close(qctx, h); -- } -- err = ext2fs_get_mem(sizeof(struct quota_handle), &h); -- if (err) { -- log_err("Unable to allocate quota handle"); -- return err; -- } -- allocated_handle = 1; -- } -- -- h->qh_qf.e2_file = e2_file; -- h->qh_qf.fs = fs; -- h->qh_qf.ino = qf_ino; -- h->e2fs_write = quota_write_nomount; -- h->e2fs_read = quota_read_nomount; -- h->qh_file_flags = flags; -- h->qh_io_flags = 0; -- h->qh_type = type; -- h->qh_fmt = fmt; -- memset(&h->qh_info, 0, sizeof(h->qh_info)); -- h->qh_ops = "afile_ops_2; -- -- if (h->qh_ops->check_file && -- (h->qh_ops->check_file(h, type, fmt) == 0)) { -- log_err("qh_ops->check_file failed"); -- goto errout; -- } -- -- if (h->qh_ops->init_io && (h->qh_ops->init_io(h) < 0)) { -- log_err("qh_ops->init_io failed"); -- goto errout; -- } -- if (allocated_handle) -- qctx->quota_file[type] = h; -- -- return 0; --errout: -- ext2fs_file_close(e2_file); -- if (allocated_handle) -- ext2fs_free_mem(&h); -- return -1; --} -- --static errcode_t quota_inode_init_new(ext2_filsys fs, ext2_ino_t ino) --{ -- struct ext2_inode inode; -- errcode_t err = 0; -- -- err = ext2fs_read_inode(fs, ino, &inode); -- if (err) { -- log_err("ex2fs_read_inode failed"); -- return err; -- } -- -- if (EXT2_I_SIZE(&inode)) -- quota_inode_truncate(fs, ino); -- -- memset(&inode, 0, sizeof(struct ext2_inode)); -- ext2fs_iblk_set(fs, &inode, 0); -- inode.i_atime = inode.i_mtime = -- inode.i_ctime = fs->now ? fs->now : time(0); -- inode.i_links_count = 1; -- inode.i_mode = LINUX_S_IFREG | 0600; -- inode.i_flags |= EXT2_IMMUTABLE_FL; -- if (fs->super->s_feature_incompat & -- EXT3_FEATURE_INCOMPAT_EXTENTS) -- inode.i_flags |= EXT4_EXTENTS_FL; -- -- err = ext2fs_write_new_inode(fs, ino, &inode); -- if (err) { -- log_err("ext2fs_write_new_inode failed: %ld", err); -- return err; -- } -- return err; --} -- --/* -- * Create new quotafile of specified format on given filesystem -- */ --errcode_t quota_file_create(struct quota_handle *h, ext2_filsys fs, int type, int fmt) --{ -- ext2_file_t e2_file; -- int err; -- unsigned long qf_inum; -- -- if (fmt == -1) -- fmt = QFMT_VFS_V1; -- -- h->qh_qf.fs = fs; -- if (type == USRQUOTA) -- qf_inum = EXT4_USR_QUOTA_INO; -- else if (type == GRPQUOTA) -- qf_inum = EXT4_GRP_QUOTA_INO; -- else -- return -1; -- -- err = ext2fs_read_bitmaps(fs); -- if (err) -- goto out_err; -- -- err = quota_inode_init_new(fs, qf_inum); -- if (err) { -- log_err("init_new_quota_inode failed"); -- goto out_err; -- } -- h->qh_qf.ino = qf_inum; -- h->qh_file_flags = EXT2_FILE_WRITE | EXT2_FILE_CREATE; -- h->e2fs_write = quota_write_nomount; -- h->e2fs_read = quota_read_nomount; -- -- log_debug("Creating quota ino=%lu, type=%d", qf_inum, type); -- err = ext2fs_file_open(fs, qf_inum, h->qh_file_flags, &e2_file); -- if (err) { -- log_err("ext2fs_file_open failed: %d", err); -- goto out_err; -- } -- h->qh_qf.e2_file = e2_file; -- -- h->qh_io_flags = 0; -- h->qh_type = type; -- h->qh_fmt = fmt; -- memset(&h->qh_info, 0, sizeof(h->qh_info)); -- h->qh_ops = "afile_ops_2; -- -- if (h->qh_ops->new_io && (h->qh_ops->new_io(h) < 0)) { -- log_err("qh_ops->new_io failed"); -- goto out_err1; -- } -- -- return 0; -- --out_err1: -- ext2fs_file_close(e2_file); --out_err: -- -- if (qf_inum) -- quota_inode_truncate(fs, qf_inum); -- -- return -1; --} -- --/* -- * Close quotafile and release handle -- */ --errcode_t quota_file_close(quota_ctx_t qctx, struct quota_handle *h) --{ -- if (h->qh_io_flags & IOFL_INFODIRTY) { -- if (h->qh_ops->write_info && h->qh_ops->write_info(h) < 0) -- return -1; -- h->qh_io_flags &= ~IOFL_INFODIRTY; -- } -- -- if (h->qh_ops->end_io && h->qh_ops->end_io(h) < 0) -- return -1; -- if (h->qh_qf.e2_file) { -- __u64 new_size, size; -- -- new_size = compute_inode_size(h->qh_qf.fs, h->qh_qf.ino); -- ext2fs_file_flush(h->qh_qf.e2_file); -- if (ext2fs_file_get_lsize(h->qh_qf.e2_file, &size)) -- new_size = 0; -- if (size != new_size) -- ext2fs_file_set_size2(h->qh_qf.e2_file, new_size); -- ext2fs_file_close(h->qh_qf.e2_file); -- } -- if (qctx->quota_file[h->qh_type] == h) -- ext2fs_free_mem(&qctx->quota_file[h->qh_type]); -- return 0; --} -- --/* -- * Create empty quota structure -- */ --struct dquot *get_empty_dquot(void) --{ -- struct dquot *dquot; -- -- if (ext2fs_get_memzero(sizeof(struct dquot), &dquot)) { -- log_err("Failed to allocate dquot"); -- return NULL; -- } -- -- dquot->dq_id = -1; -- return dquot; --} -diff --git a/lib/quota/quotaio.h b/lib/quota/quotaio.h -deleted file mode 100644 -index 7ca7830..0000000 ---- a/lib/quota/quotaio.h -+++ /dev/null -@@ -1,225 +0,0 @@ --/** quotaio.h -- * -- * Interface to the quota library. -- * -- * The quota library provides interface for creating and updating the quota -- * files and the ext4 superblock fields. It supports the new VFS_V1 quota -- * format. The quota library also provides support for keeping track of quotas -- * in memory. -- * The typical way to use the quota library is as follows: -- * { -- * quota_ctx_t qctx; -- * -- * quota_init_context(&qctx, fs, -1); -- * { -- * quota_compute_usage(qctx, -1); -- * AND/OR -- * quota_data_add/quota_data_sub/quota_data_inodes(); -- * } -- * quota_write_inode(qctx, USRQUOTA); -- * quota_write_inode(qctx, GRPQUOTA); -- * quota_release_context(&qctx); -- * } -- * -- * This initial version does not support reading the quota files. This support -- * will be added in near future. -- * -- * Aditya Kali -- * Header of IO operations for quota utilities -- * -- * Jan Kara -- */ -- --#ifndef GUARD_QUOTAIO_H --#define GUARD_QUOTAIO_H -- --#include --#include --#include -- --#include "ext2fs/ext2_fs.h" --#include "ext2fs/ext2fs.h" --#include "dqblk_v2.h" --#include "../e2fsck/dict.h" -- --typedef int64_t qsize_t; /* Type in which we store size limitations */ -- --#define MAXQUOTAS 2 --#define USRQUOTA 0 --#define GRPQUOTA 1 -- --typedef struct quota_ctx *quota_ctx_t; -- --struct quota_ctx { -- ext2_filsys fs; -- dict_t *quota_dict[MAXQUOTAS]; -- struct quota_handle *quota_file[MAXQUOTAS]; --}; -- --/* -- * Definitions of magics and versions of current quota files -- */ --#define INITQMAGICS {\ -- 0xd9c01f11, /* USRQUOTA */\ -- 0xd9c01927 /* GRPQUOTA */\ --} -- --/* Size of blocks in which are counted size limits in generic utility parts */ --#define QUOTABLOCK_BITS 10 --#define QUOTABLOCK_SIZE (1 << QUOTABLOCK_BITS) --#define toqb(x) (((x) + QUOTABLOCK_SIZE - 1) >> QUOTABLOCK_BITS) -- --/* Quota format type IDs */ --#define QFMT_VFS_OLD 1 --#define QFMT_VFS_V0 2 --#define QFMT_VFS_V1 4 -- --/* -- * The following constants define the default amount of time given a user -- * before the soft limits are treated as hard limits (usually resulting -- * in an allocation failure). The timer is started when the user crosses -- * their soft limit, it is reset when they go below their soft limit. -- */ --#define MAX_IQ_TIME 604800 /* (7*24*60*60) 1 week */ --#define MAX_DQ_TIME 604800 /* (7*24*60*60) 1 week */ -- --#define IOFL_INFODIRTY 0x01 /* Did info change? */ -- --struct quotafile_ops; -- --/* Generic information about quotafile */ --struct util_dqinfo { -- time_t dqi_bgrace; /* Block grace time for given quotafile */ -- time_t dqi_igrace; /* Inode grace time for given quotafile */ -- union { -- struct v2_mem_dqinfo v2_mdqi; -- } u; /* Format specific info about quotafile */ --}; -- --struct quota_file { -- ext2_filsys fs; -- ext2_ino_t ino; -- ext2_file_t e2_file; --}; -- --/* Structure for one opened quota file */ --struct quota_handle { -- int qh_type; /* Type of quotafile */ -- int qh_fmt; /* Quotafile format */ -- int qh_file_flags; -- int qh_io_flags; /* IO flags for file */ -- struct quota_file qh_qf; -- unsigned int (*e2fs_read)(struct quota_file *qf, ext2_loff_t offset, -- void *buf, unsigned int size); -- unsigned int (*e2fs_write)(struct quota_file *qf, ext2_loff_t offset, -- void *buf, unsigned int size); -- struct quotafile_ops *qh_ops; /* Operations on quotafile */ -- struct util_dqinfo qh_info; /* Generic quotafile info */ --}; -- --/* Utility quota block */ --struct util_dqblk { -- qsize_t dqb_ihardlimit; -- qsize_t dqb_isoftlimit; -- qsize_t dqb_curinodes; -- qsize_t dqb_bhardlimit; -- qsize_t dqb_bsoftlimit; -- qsize_t dqb_curspace; -- time_t dqb_btime; -- time_t dqb_itime; -- union { -- struct v2_mem_dqblk v2_mdqb; -- } u; /* Format specific dquot information */ --}; -- --/* Structure for one loaded quota */ --struct dquot { -- struct dquot *dq_next; /* Pointer to next dquot in the list */ -- qid_t dq_id; /* ID dquot belongs to */ -- int dq_flags; /* Some flags for utils */ -- struct quota_handle *dq_h; /* Handle of quotafile for this dquot */ -- struct util_dqblk dq_dqb; /* Parsed data of dquot */ --}; -- --#define DQF_SEEN 0x0001 -- --/* Structure of quotafile operations */ --struct quotafile_ops { -- /* Check whether quotafile is in our format */ -- int (*check_file) (struct quota_handle *h, int type, int fmt); -- /* Open quotafile */ -- int (*init_io) (struct quota_handle *h); -- /* Create new quotafile */ -- int (*new_io) (struct quota_handle *h); -- /* Write all changes and close quotafile */ -- int (*end_io) (struct quota_handle *h); -- /* Write info about quotafile */ -- int (*write_info) (struct quota_handle *h); -- /* Read dquot into memory */ -- struct dquot *(*read_dquot) (struct quota_handle *h, qid_t id); -- /* Write given dquot to disk */ -- int (*commit_dquot) (struct dquot *dquot); -- /* Scan quotafile and call callback on every structure */ -- int (*scan_dquots) (struct quota_handle *h, -- int (*process_dquot) (struct dquot *dquot, -- void *data), -- void *data); -- /* Function to print format specific file information */ -- int (*report) (struct quota_handle *h, int verbose); --}; -- --/* This might go into a special header file but that sounds a bit silly... */ --extern struct quotafile_ops quotafile_ops_meta; -- --/* Open existing quotafile of given type (and verify its format) on given -- * filesystem. */ --errcode_t quota_file_open(quota_ctx_t qctx, struct quota_handle *h, -- ext2_ino_t qf_ino, int type, int fmt, int flags); -- -- --/* Create new quotafile of specified format on given filesystem */ --errcode_t quota_file_create(struct quota_handle *h, ext2_filsys fs, -- int type, int fmt); -- --/* Close quotafile */ --errcode_t quota_file_close(quota_ctx_t qctx, struct quota_handle *h); -- --/* Get empty quota structure */ --struct dquot *get_empty_dquot(void); -- --errcode_t quota_inode_truncate(ext2_filsys fs, ext2_ino_t ino); -- --const char *type2name(int type); -- --void update_grace_times(struct dquot *q); -- --/* size for the buffer returned by quota_get_qf_name(); must be greater -- than maxlen of extensions[] and fmtnames[] (plus 2) found in quotaio.c */ --#define QUOTA_NAME_LEN 16 -- --const char *quota_get_qf_name(int type, int fmt, char *buf); --const char *quota_get_qf_path(const char *mntpt, int qtype, int fmt, -- char *path_buf, size_t path_buf_size); -- --/* In mkquota.c */ --errcode_t quota_init_context(quota_ctx_t *qctx, ext2_filsys fs, int qtype); --void quota_data_inodes(quota_ctx_t qctx, struct ext2_inode *inode, ext2_ino_t ino, -- int adjust); --void quota_data_add(quota_ctx_t qctx, struct ext2_inode *inode, ext2_ino_t ino, -- qsize_t space); --void quota_data_sub(quota_ctx_t qctx, struct ext2_inode *inode, ext2_ino_t ino, -- qsize_t space); --errcode_t quota_write_inode(quota_ctx_t qctx, int qtype); --errcode_t quota_update_limits(quota_ctx_t qctx, ext2_ino_t qf_ino, int type); --errcode_t quota_compute_usage(quota_ctx_t qctx); --void quota_release_context(quota_ctx_t *qctx); -- --errcode_t quota_remove_inode(ext2_filsys fs, int qtype); --int quota_file_exists(ext2_filsys fs, int qtype, int fmt); --void quota_set_sb_inum(ext2_filsys fs, ext2_ino_t ino, int qtype); --errcode_t quota_compare_and_update(quota_ctx_t qctx, int qtype, -- int *usage_inconsistent); -- -- -- --#endif /* GUARD_QUOTAIO_H */ -diff --git a/lib/quota/quotaio_tree.c b/lib/quota/quotaio_tree.c -deleted file mode 100644 -index 4d7a9ab..0000000 ---- a/lib/quota/quotaio_tree.c -+++ /dev/null -@@ -1,662 +0,0 @@ --/* -- * Implementation of new quotafile format -- * -- * Jan Kara - sponsored by SuSE CR -- */ -- --#include "config.h" --#include --#include --#include --#include --#include --#include -- --#include "common.h" --#include "quotaio_tree.h" --#include "quotaio.h" -- --typedef char *dqbuf_t; -- --#define freedqbuf(buf) ext2fs_free_mem(&buf) -- --static inline dqbuf_t getdqbuf(void) --{ -- dqbuf_t buf; -- if (ext2fs_get_memzero(QT_BLKSIZE, &buf)) { -- log_err("Failed to allocate dqbuf"); -- return NULL; -- } -- -- return buf; --} -- --/* Is given dquot empty? */ --int qtree_entry_unused(struct qtree_mem_dqinfo *info, char *disk) --{ -- int i; -- -- for (i = 0; i < info->dqi_entry_size; i++) -- if (disk[i]) -- return 0; -- return 1; --} -- --int qtree_dqstr_in_blk(struct qtree_mem_dqinfo *info) --{ -- return (QT_BLKSIZE - sizeof(struct qt_disk_dqdbheader)) / -- info->dqi_entry_size; --} -- --static int get_index(qid_t id, int depth) --{ -- return (id >> ((QT_TREEDEPTH - depth - 1) * 8)) & 0xff; --} -- --static inline void mark_quotafile_info_dirty(struct quota_handle *h) --{ -- h->qh_io_flags |= IOFL_INFODIRTY; --} -- --/* Read given block */ --static void read_blk(struct quota_handle *h, unsigned int blk, dqbuf_t buf) --{ -- int err; -- -- err = h->e2fs_read(&h->qh_qf, blk << QT_BLKSIZE_BITS, buf, -- QT_BLKSIZE); -- if (err < 0) -- log_err("Cannot read block %u: %s", blk, strerror(errno)); -- else if (err != QT_BLKSIZE) -- memset(buf + err, 0, QT_BLKSIZE - err); --} -- --/* Write block */ --static int write_blk(struct quota_handle *h, unsigned int blk, dqbuf_t buf) --{ -- int err; -- -- err = h->e2fs_write(&h->qh_qf, blk << QT_BLKSIZE_BITS, buf, -- QT_BLKSIZE); -- if (err < 0 && errno != ENOSPC) -- log_err("Cannot write block (%u): %s", blk, strerror(errno)); -- if (err != QT_BLKSIZE) -- return -ENOSPC; -- return 0; --} -- --/* Get free block in file (either from free list or create new one) */ --static int get_free_dqblk(struct quota_handle *h) --{ -- dqbuf_t buf = getdqbuf(); -- struct qt_disk_dqdbheader *dh = (struct qt_disk_dqdbheader *)buf; -- struct qtree_mem_dqinfo *info = &h->qh_info.u.v2_mdqi.dqi_qtree; -- int blk; -- -- if (!buf) -- return -ENOMEM; -- -- if (info->dqi_free_blk) { -- blk = info->dqi_free_blk; -- read_blk(h, blk, buf); -- info->dqi_free_blk = ext2fs_le32_to_cpu(dh->dqdh_next_free); -- } else { -- memset(buf, 0, QT_BLKSIZE); -- /* Assure block allocation... */ -- if (write_blk(h, info->dqi_blocks, buf) < 0) { -- freedqbuf(buf); -- log_err("Cannot allocate new quota block " -- "(out of disk space)."); -- return -ENOSPC; -- } -- blk = info->dqi_blocks++; -- } -- mark_quotafile_info_dirty(h); -- freedqbuf(buf); -- return blk; --} -- --/* Put given block to free list */ --static void put_free_dqblk(struct quota_handle *h, dqbuf_t buf, -- unsigned int blk) --{ -- struct qt_disk_dqdbheader *dh = (struct qt_disk_dqdbheader *)buf; -- struct qtree_mem_dqinfo *info = &h->qh_info.u.v2_mdqi.dqi_qtree; -- -- dh->dqdh_next_free = ext2fs_cpu_to_le32(info->dqi_free_blk); -- dh->dqdh_prev_free = ext2fs_cpu_to_le32(0); -- dh->dqdh_entries = ext2fs_cpu_to_le16(0); -- info->dqi_free_blk = blk; -- mark_quotafile_info_dirty(h); -- write_blk(h, blk, buf); --} -- --/* Remove given block from the list of blocks with free entries */ --static void remove_free_dqentry(struct quota_handle *h, dqbuf_t buf, -- unsigned int blk) --{ -- dqbuf_t tmpbuf = getdqbuf(); -- struct qt_disk_dqdbheader *dh = (struct qt_disk_dqdbheader *)buf; -- unsigned int nextblk = ext2fs_le32_to_cpu(dh->dqdh_next_free), prevblk = -- -- ext2fs_le32_to_cpu(dh->dqdh_prev_free); -- -- if (!tmpbuf) -- return; -- -- if (nextblk) { -- read_blk(h, nextblk, tmpbuf); -- ((struct qt_disk_dqdbheader *)tmpbuf)->dqdh_prev_free = -- dh->dqdh_prev_free; -- write_blk(h, nextblk, tmpbuf); -- } -- if (prevblk) { -- read_blk(h, prevblk, tmpbuf); -- ((struct qt_disk_dqdbheader *)tmpbuf)->dqdh_next_free = -- dh->dqdh_next_free; -- write_blk(h, prevblk, tmpbuf); -- } else { -- h->qh_info.u.v2_mdqi.dqi_qtree.dqi_free_entry = nextblk; -- mark_quotafile_info_dirty(h); -- } -- freedqbuf(tmpbuf); -- dh->dqdh_next_free = dh->dqdh_prev_free = ext2fs_cpu_to_le32(0); -- write_blk(h, blk, buf); /* No matter whether write succeeds -- * block is out of list */ --} -- --/* Insert given block to the beginning of list with free entries */ --static void insert_free_dqentry(struct quota_handle *h, dqbuf_t buf, -- unsigned int blk) --{ -- dqbuf_t tmpbuf = getdqbuf(); -- struct qt_disk_dqdbheader *dh = (struct qt_disk_dqdbheader *)buf; -- struct qtree_mem_dqinfo *info = &h->qh_info.u.v2_mdqi.dqi_qtree; -- -- if (!tmpbuf) -- return; -- -- dh->dqdh_next_free = ext2fs_cpu_to_le32(info->dqi_free_entry); -- dh->dqdh_prev_free = ext2fs_cpu_to_le32(0); -- write_blk(h, blk, buf); -- if (info->dqi_free_entry) { -- read_blk(h, info->dqi_free_entry, tmpbuf); -- ((struct qt_disk_dqdbheader *)tmpbuf)->dqdh_prev_free = -- ext2fs_cpu_to_le32(blk); -- write_blk(h, info->dqi_free_entry, tmpbuf); -- } -- freedqbuf(tmpbuf); -- info->dqi_free_entry = blk; -- mark_quotafile_info_dirty(h); --} -- --/* Find space for dquot */ --static unsigned int find_free_dqentry(struct quota_handle *h, -- struct dquot *dquot, int *err) --{ -- int blk, i; -- struct qt_disk_dqdbheader *dh; -- struct qtree_mem_dqinfo *info = &h->qh_info.u.v2_mdqi.dqi_qtree; -- char *ddquot; -- dqbuf_t buf; -- -- *err = 0; -- buf = getdqbuf(); -- if (!buf) { -- *err = -ENOMEM; -- return 0; -- } -- -- dh = (struct qt_disk_dqdbheader *)buf; -- if (info->dqi_free_entry) { -- blk = info->dqi_free_entry; -- read_blk(h, blk, buf); -- } else { -- blk = get_free_dqblk(h); -- if (blk < 0) { -- freedqbuf(buf); -- *err = blk; -- return 0; -- } -- memset(buf, 0, QT_BLKSIZE); -- info->dqi_free_entry = blk; -- mark_quotafile_info_dirty(h); -- } -- -- /* Block will be full? */ -- if (ext2fs_le16_to_cpu(dh->dqdh_entries) + 1 >= -- qtree_dqstr_in_blk(info)) -- remove_free_dqentry(h, buf, blk); -- -- dh->dqdh_entries = -- ext2fs_cpu_to_le16(ext2fs_le16_to_cpu(dh->dqdh_entries) + 1); -- /* Find free structure in block */ -- ddquot = buf + sizeof(struct qt_disk_dqdbheader); -- for (i = 0; -- i < qtree_dqstr_in_blk(info) && !qtree_entry_unused(info, ddquot); -- i++) -- ddquot += info->dqi_entry_size; -- -- if (i == qtree_dqstr_in_blk(info)) -- log_err("find_free_dqentry(): Data block full unexpectedly."); -- -- write_blk(h, blk, buf); -- dquot->dq_dqb.u.v2_mdqb.dqb_off = -- (blk << QT_BLKSIZE_BITS) + sizeof(struct qt_disk_dqdbheader) + -- i * info->dqi_entry_size; -- freedqbuf(buf); -- return blk; --} -- --/* Insert reference to structure into the trie */ --static int do_insert_tree(struct quota_handle *h, struct dquot *dquot, -- unsigned int * treeblk, int depth) --{ -- dqbuf_t buf; -- int newson = 0, newact = 0; -- __u32 *ref; -- unsigned int newblk; -- int ret = 0; -- -- log_debug("inserting in tree: treeblk=%u, depth=%d", *treeblk, depth); -- buf = getdqbuf(); -- if (!buf) -- return -ENOMEM; -- -- if (!*treeblk) { -- ret = get_free_dqblk(h); -- if (ret < 0) -- goto out_buf; -- *treeblk = ret; -- memset(buf, 0, QT_BLKSIZE); -- newact = 1; -- } else { -- read_blk(h, *treeblk, buf); -- } -- -- ref = (__u32 *) buf; -- newblk = ext2fs_le32_to_cpu(ref[get_index(dquot->dq_id, depth)]); -- if (!newblk) -- newson = 1; -- if (depth == QT_TREEDEPTH - 1) { -- if (newblk) -- log_err("Inserting already present quota entry " -- "(block %u).", -- ref[get_index(dquot->dq_id, depth)]); -- newblk = find_free_dqentry(h, dquot, &ret); -- } else { -- ret = do_insert_tree(h, dquot, &newblk, depth + 1); -- } -- -- if (newson && ret >= 0) { -- ref[get_index(dquot->dq_id, depth)] = -- ext2fs_cpu_to_le32(newblk); -- write_blk(h, *treeblk, buf); -- } else if (newact && ret < 0) { -- put_free_dqblk(h, buf, *treeblk); -- } -- --out_buf: -- freedqbuf(buf); -- return ret; --} -- --/* Wrapper for inserting quota structure into tree */ --static void dq_insert_tree(struct quota_handle *h, struct dquot *dquot) --{ -- unsigned int tmp = QT_TREEOFF; -- -- if (do_insert_tree(h, dquot, &tmp, 0) < 0) -- log_err("Cannot write quota (id %u): %s", -- (unsigned int) dquot->dq_id, strerror(errno)); --} -- --/* Write dquot to file */ --void qtree_write_dquot(struct dquot *dquot) --{ -- ssize_t ret; -- char *ddquot; -- struct quota_handle *h = dquot->dq_h; -- struct qtree_mem_dqinfo *info = -- &dquot->dq_h->qh_info.u.v2_mdqi.dqi_qtree; -- log_debug("writing ddquot 1: off=%llu, info->dqi_entry_size=%u", -- dquot->dq_dqb.u.v2_mdqb.dqb_off, -- info->dqi_entry_size); -- ret = ext2fs_get_mem(info->dqi_entry_size, &ddquot); -- if (ret) { -- errno = ENOMEM; -- log_err("Quota write failed (id %u): %s", -- (unsigned int)dquot->dq_id, strerror(errno)); -- return; -- } -- memset(ddquot, 0, info->dqi_entry_size); -- -- if (!dquot->dq_dqb.u.v2_mdqb.dqb_off) -- dq_insert_tree(dquot->dq_h, dquot); -- info->dqi_ops->mem2disk_dqblk(ddquot, dquot); -- log_debug("writing ddquot 2: off=%llu, info->dqi_entry_size=%u", -- dquot->dq_dqb.u.v2_mdqb.dqb_off, -- info->dqi_entry_size); -- ret = h->e2fs_write(&h->qh_qf, dquot->dq_dqb.u.v2_mdqb.dqb_off, ddquot, -- info->dqi_entry_size); -- -- if (ret != info->dqi_entry_size) { -- if (ret > 0) -- errno = ENOSPC; -- log_err("Quota write failed (id %u): %s", -- (unsigned int)dquot->dq_id, strerror(errno)); -- } -- ext2fs_free_mem(&ddquot); --} -- --/* Free dquot entry in data block */ --static void free_dqentry(struct quota_handle *h, struct dquot *dquot, -- unsigned int blk) --{ -- struct qt_disk_dqdbheader *dh; -- struct qtree_mem_dqinfo *info = &h->qh_info.u.v2_mdqi.dqi_qtree; -- dqbuf_t buf = getdqbuf(); -- -- if (!buf) -- return; -- -- if (dquot->dq_dqb.u.v2_mdqb.dqb_off >> QT_BLKSIZE_BITS != blk) -- log_err("Quota structure has offset to other block (%u) " -- "than it should (%u).", blk, -- (unsigned int) (dquot->dq_dqb.u.v2_mdqb.dqb_off >> -- QT_BLKSIZE_BITS)); -- -- read_blk(h, blk, buf); -- dh = (struct qt_disk_dqdbheader *)buf; -- dh->dqdh_entries = -- ext2fs_cpu_to_le16(ext2fs_le16_to_cpu(dh->dqdh_entries) - 1); -- -- if (!ext2fs_le16_to_cpu(dh->dqdh_entries)) { /* Block got free? */ -- remove_free_dqentry(h, buf, blk); -- put_free_dqblk(h, buf, blk); -- } else { -- memset(buf + (dquot->dq_dqb.u.v2_mdqb.dqb_off & -- ((1 << QT_BLKSIZE_BITS) - 1)), -- 0, info->dqi_entry_size); -- -- /* First free entry? */ -- if (ext2fs_le16_to_cpu(dh->dqdh_entries) == -- qtree_dqstr_in_blk(info) - 1) -- /* This will also write data block */ -- insert_free_dqentry(h, buf, blk); -- else -- write_blk(h, blk, buf); -- } -- dquot->dq_dqb.u.v2_mdqb.dqb_off = 0; -- freedqbuf(buf); --} -- --/* Remove reference to dquot from tree */ --static void remove_tree(struct quota_handle *h, struct dquot *dquot, -- unsigned int * blk, int depth) --{ -- dqbuf_t buf = getdqbuf(); -- unsigned int newblk; -- __u32 *ref = (__u32 *) buf; -- -- if (!buf) -- return; -- -- read_blk(h, *blk, buf); -- newblk = ext2fs_le32_to_cpu(ref[get_index(dquot->dq_id, depth)]); -- if (depth == QT_TREEDEPTH - 1) { -- free_dqentry(h, dquot, newblk); -- newblk = 0; -- } else { -- remove_tree(h, dquot, &newblk, depth + 1); -- } -- -- if (!newblk) { -- int i; -- -- ref[get_index(dquot->dq_id, depth)] = ext2fs_cpu_to_le32(0); -- -- /* Block got empty? */ -- for (i = 0; i < QT_BLKSIZE && !buf[i]; i++); -- -- /* Don't put the root block into the free block list */ -- if (i == QT_BLKSIZE && *blk != QT_TREEOFF) { -- put_free_dqblk(h, buf, *blk); -- *blk = 0; -- } else { -- write_blk(h, *blk, buf); -- } -- } -- freedqbuf(buf); --} -- --/* Delete dquot from tree */ --void qtree_delete_dquot(struct dquot *dquot) --{ -- unsigned int tmp = QT_TREEOFF; -- -- if (!dquot->dq_dqb.u.v2_mdqb.dqb_off) /* Even not allocated? */ -- return; -- remove_tree(dquot->dq_h, dquot, &tmp, 0); --} -- --/* Find entry in block */ --static ext2_loff_t find_block_dqentry(struct quota_handle *h, -- struct dquot *dquot, unsigned int blk) --{ -- struct qtree_mem_dqinfo *info = &h->qh_info.u.v2_mdqi.dqi_qtree; -- dqbuf_t buf = getdqbuf(); -- int i; -- char *ddquot = buf + sizeof(struct qt_disk_dqdbheader); -- -- if (!buf) -- return -ENOMEM; -- -- read_blk(h, blk, buf); -- for (i = 0; -- i < qtree_dqstr_in_blk(info) && !info->dqi_ops->is_id(ddquot, dquot); -- i++) -- ddquot += info->dqi_entry_size; -- -- if (i == qtree_dqstr_in_blk(info)) -- log_err("Quota for id %u referenced but not present.", -- dquot->dq_id); -- freedqbuf(buf); -- return (blk << QT_BLKSIZE_BITS) + sizeof(struct qt_disk_dqdbheader) + -- i * info->dqi_entry_size; --} -- --/* Find entry for given id in the tree */ --static ext2_loff_t find_tree_dqentry(struct quota_handle *h, -- struct dquot *dquot, -- unsigned int blk, int depth) --{ -- dqbuf_t buf = getdqbuf(); -- ext2_loff_t ret = 0; -- __u32 *ref = (__u32 *) buf; -- -- if (!buf) -- return -ENOMEM; -- -- read_blk(h, blk, buf); -- ret = 0; -- blk = ext2fs_le32_to_cpu(ref[get_index(dquot->dq_id, depth)]); -- if (!blk) /* No reference? */ -- goto out_buf; -- if (depth < QT_TREEDEPTH - 1) -- ret = find_tree_dqentry(h, dquot, blk, depth + 1); -- else -- ret = find_block_dqentry(h, dquot, blk); --out_buf: -- freedqbuf(buf); -- return ret; --} -- --/* Find entry for given id in the tree - wrapper function */ --static inline ext2_loff_t find_dqentry(struct quota_handle *h, -- struct dquot *dquot) --{ -- return find_tree_dqentry(h, dquot, QT_TREEOFF, 0); --} -- --/* -- * Read dquot from disk. -- */ --struct dquot *qtree_read_dquot(struct quota_handle *h, qid_t id) --{ -- struct qtree_mem_dqinfo *info = &h->qh_info.u.v2_mdqi.dqi_qtree; -- ext2_loff_t offset; -- ssize_t ret; -- char *ddquot; -- struct dquot *dquot = get_empty_dquot(); -- -- if (!dquot) -- return NULL; -- if (ext2fs_get_mem(info->dqi_entry_size, &ddquot)) { -- ext2fs_free_mem(&dquot); -- return NULL; -- } -- -- dquot->dq_id = id; -- dquot->dq_h = h; -- dquot->dq_dqb.u.v2_mdqb.dqb_off = 0; -- memset(&dquot->dq_dqb, 0, sizeof(struct util_dqblk)); -- -- offset = find_dqentry(h, dquot); -- if (offset > 0) { -- dquot->dq_dqb.u.v2_mdqb.dqb_off = offset; -- ret = h->e2fs_read(&h->qh_qf, offset, ddquot, -- info->dqi_entry_size); -- if (ret != info->dqi_entry_size) { -- if (ret > 0) -- errno = EIO; -- log_err("Cannot read quota structure for id %u: %s", -- dquot->dq_id, strerror(errno)); -- } -- info->dqi_ops->disk2mem_dqblk(dquot, ddquot); -- } -- ext2fs_free_mem(&ddquot); -- return dquot; --} -- --/* -- * Scan all dquots in file and call callback on each -- */ --#define set_bit(bmp, ind) ((bmp)[(ind) >> 3] |= (1 << ((ind) & 7))) --#define get_bit(bmp, ind) ((bmp)[(ind) >> 3] & (1 << ((ind) & 7))) -- --static int report_block(struct dquot *dquot, unsigned int blk, char *bitmap, -- int (*process_dquot) (struct dquot *, void *), -- void *data) --{ -- struct qtree_mem_dqinfo *info = -- &dquot->dq_h->qh_info.u.v2_mdqi.dqi_qtree; -- dqbuf_t buf = getdqbuf(); -- struct qt_disk_dqdbheader *dh; -- char *ddata; -- int entries, i; -- -- if (!buf) -- return 0; -- -- set_bit(bitmap, blk); -- read_blk(dquot->dq_h, blk, buf); -- dh = (struct qt_disk_dqdbheader *)buf; -- ddata = buf + sizeof(struct qt_disk_dqdbheader); -- entries = ext2fs_le16_to_cpu(dh->dqdh_entries); -- for (i = 0; i < qtree_dqstr_in_blk(info); -- i++, ddata += info->dqi_entry_size) -- if (!qtree_entry_unused(info, ddata)) { -- dquot->dq_dqb.u.v2_mdqb.dqb_off = -- (blk << QT_BLKSIZE_BITS) + -- sizeof(struct qt_disk_dqdbheader) + -- i * info->dqi_entry_size; -- info->dqi_ops->disk2mem_dqblk(dquot, ddata); -- if (process_dquot(dquot, data) < 0) -- break; -- } -- freedqbuf(buf); -- return entries; --} -- --static void check_reference(struct quota_handle *h, unsigned int blk) --{ -- if (blk >= h->qh_info.u.v2_mdqi.dqi_qtree.dqi_blocks) -- log_err("Illegal reference (%u >= %u) in %s quota file. " -- "Quota file is probably corrupted.\n" -- "Please run e2fsck (8) to fix it.", -- blk, -- h->qh_info.u.v2_mdqi.dqi_qtree.dqi_blocks, -- type2name(h->qh_type)); --} -- --static int report_tree(struct dquot *dquot, unsigned int blk, int depth, -- char *bitmap, -- int (*process_dquot) (struct dquot *, void *), -- void *data) --{ -- int entries = 0, i; -- dqbuf_t buf = getdqbuf(); -- __u32 *ref = (__u32 *) buf; -- -- if (!buf) -- return 0; -- -- read_blk(dquot->dq_h, blk, buf); -- if (depth == QT_TREEDEPTH - 1) { -- for (i = 0; i < QT_BLKSIZE >> 2; i++) { -- blk = ext2fs_le32_to_cpu(ref[i]); -- check_reference(dquot->dq_h, blk); -- if (blk && !get_bit(bitmap, blk)) -- entries += report_block(dquot, blk, bitmap, -- process_dquot, data); -- } -- } else { -- for (i = 0; i < QT_BLKSIZE >> 2; i++) { -- blk = ext2fs_le32_to_cpu(ref[i]); -- if (blk) { -- check_reference(dquot->dq_h, blk); -- entries += report_tree(dquot, blk, depth + 1, -- bitmap, process_dquot, -- data); -- } -- } -- } -- freedqbuf(buf); -- return entries; --} -- --static unsigned int find_set_bits(char *bmp, int blocks) --{ -- unsigned int i, used = 0; -- -- for (i = 0; i < blocks; i++) -- if (get_bit(bmp, i)) -- used++; -- return used; --} -- --int qtree_scan_dquots(struct quota_handle *h, -- int (*process_dquot) (struct dquot *, void *), -- void *data) --{ -- char *bitmap; -- struct v2_mem_dqinfo *v2info = &h->qh_info.u.v2_mdqi; -- struct qtree_mem_dqinfo *info = &v2info->dqi_qtree; -- struct dquot *dquot = get_empty_dquot(); -- -- if (!dquot) -- return -1; -- -- dquot->dq_h = h; -- if (ext2fs_get_memzero((info->dqi_blocks + 7) >> 3, &bitmap)) { -- ext2fs_free_mem(&dquot); -- return -1; -- } -- v2info->dqi_used_entries = report_tree(dquot, QT_TREEOFF, 0, bitmap, -- process_dquot, data); -- v2info->dqi_data_blocks = find_set_bits(bitmap, info->dqi_blocks); -- ext2fs_free_mem(&bitmap); -- ext2fs_free_mem(&dquot); -- return 0; --} -diff --git a/lib/quota/quotaio_tree.h b/lib/quota/quotaio_tree.h -deleted file mode 100644 -index be34edb..0000000 ---- a/lib/quota/quotaio_tree.h -+++ /dev/null -@@ -1,64 +0,0 @@ --/* -- * Definitions of structures for vfsv0 quota format -- */ -- --#ifndef _LINUX_QUOTA_TREE_H --#define _LINUX_QUOTA_TREE_H -- --#include -- --typedef __u32 qid_t; /* Type in which we store ids in memory */ -- --#define QT_TREEOFF 1 /* Offset of tree in file in blocks */ --#define QT_TREEDEPTH 4 /* Depth of quota tree */ --#define QT_BLKSIZE_BITS 10 --#define QT_BLKSIZE (1 << QT_BLKSIZE_BITS) /* Size of block with quota -- * structures */ -- --/* -- * Structure of header of block with quota structures. It is padded to 16 bytes -- * so there will be space for exactly 21 quota-entries in a block -- */ --struct qt_disk_dqdbheader { -- __u32 dqdh_next_free; /* Number of next block with free -- * entry */ -- __u32 dqdh_prev_free; /* Number of previous block with free -- * entry */ -- __u16 dqdh_entries; /* Number of valid entries in block */ -- __u16 dqdh_pad1; -- __u32 dqdh_pad2; --} __attribute__ ((packed)); -- --struct dquot; --struct quota_handle; -- --/* Operations */ --struct qtree_fmt_operations { -- /* Convert given entry from in memory format to disk one */ -- void (*mem2disk_dqblk)(void *disk, struct dquot *dquot); -- /* Convert given entry from disk format to in memory one */ -- void (*disk2mem_dqblk)(struct dquot *dquot, void *disk); -- /* Is this structure for given id? */ -- int (*is_id)(void *disk, struct dquot *dquot); --}; -- --/* Inmemory copy of version specific information */ --struct qtree_mem_dqinfo { -- unsigned int dqi_blocks; /* # of blocks in quota file */ -- unsigned int dqi_free_blk; /* First block in list of free blocks */ -- unsigned int dqi_free_entry; /* First block with free entry */ -- unsigned int dqi_entry_size; /* Size of quota entry in quota file */ -- struct qtree_fmt_operations *dqi_ops; /* Operations for entry -- * manipulation */ --}; -- --void qtree_write_dquot(struct dquot *dquot); --struct dquot *qtree_read_dquot(struct quota_handle *h, qid_t id); --void qtree_delete_dquot(struct dquot *dquot); --int qtree_entry_unused(struct qtree_mem_dqinfo *info, char *disk); --int qtree_scan_dquots(struct quota_handle *h, -- int (*process_dquot) (struct dquot *, void *), void *data); -- --int qtree_dqstr_in_blk(struct qtree_mem_dqinfo *info); -- --#endif /* _LINUX_QUOTAIO_TREE_H */ -diff --git a/lib/quota/quotaio_v2.c b/lib/quota/quotaio_v2.c -deleted file mode 100644 -index e7bf29c..0000000 ---- a/lib/quota/quotaio_v2.c -+++ /dev/null -@@ -1,283 +0,0 @@ --/* -- * Implementation of new quotafile format -- * -- * Jan Kara - sponsored by SuSE CR -- */ -- --#include "config.h" --#include --#include --#include --#include --#include --#include -- --#include "common.h" --#include "quotaio_v2.h" --#include "dqblk_v2.h" --#include "quotaio.h" --#include "quotaio_tree.h" -- --static int v2_check_file(struct quota_handle *h, int type, int fmt); --static int v2_init_io(struct quota_handle *h); --static int v2_new_io(struct quota_handle *h); --static int v2_write_info(struct quota_handle *h); --static struct dquot *v2_read_dquot(struct quota_handle *h, qid_t id); --static int v2_commit_dquot(struct dquot *dquot); --static int v2_scan_dquots(struct quota_handle *h, -- int (*process_dquot) (struct dquot *dquot, -- void *data), -- void *data); --static int v2_report(struct quota_handle *h, int verbose); -- --struct quotafile_ops quotafile_ops_2 = { -- .check_file = v2_check_file, -- .init_io = v2_init_io, -- .new_io = v2_new_io, -- .write_info = v2_write_info, -- .read_dquot = v2_read_dquot, -- .commit_dquot = v2_commit_dquot, -- .scan_dquots = v2_scan_dquots, -- .report = v2_report, --}; -- --/* -- * Copy dquot from disk to memory -- */ --static void v2r1_disk2memdqblk(struct dquot *dquot, void *dp) --{ -- struct util_dqblk *m = &dquot->dq_dqb; -- struct v2r1_disk_dqblk *d = dp, empty; -- -- dquot->dq_id = ext2fs_le32_to_cpu(d->dqb_id); -- m->dqb_ihardlimit = ext2fs_le64_to_cpu(d->dqb_ihardlimit); -- m->dqb_isoftlimit = ext2fs_le64_to_cpu(d->dqb_isoftlimit); -- m->dqb_bhardlimit = ext2fs_le64_to_cpu(d->dqb_bhardlimit); -- m->dqb_bsoftlimit = ext2fs_le64_to_cpu(d->dqb_bsoftlimit); -- m->dqb_curinodes = ext2fs_le64_to_cpu(d->dqb_curinodes); -- m->dqb_curspace = ext2fs_le64_to_cpu(d->dqb_curspace); -- m->dqb_itime = ext2fs_le64_to_cpu(d->dqb_itime); -- m->dqb_btime = ext2fs_le64_to_cpu(d->dqb_btime); -- -- memset(&empty, 0, sizeof(struct v2r1_disk_dqblk)); -- empty.dqb_itime = ext2fs_cpu_to_le64(1); -- if (!memcmp(&empty, dp, sizeof(struct v2r1_disk_dqblk))) -- m->dqb_itime = 0; --} -- --/* -- * Copy dquot from memory to disk -- */ --static void v2r1_mem2diskdqblk(void *dp, struct dquot *dquot) --{ -- struct util_dqblk *m = &dquot->dq_dqb; -- struct v2r1_disk_dqblk *d = dp; -- -- d->dqb_ihardlimit = ext2fs_cpu_to_le64(m->dqb_ihardlimit); -- d->dqb_isoftlimit = ext2fs_cpu_to_le64(m->dqb_isoftlimit); -- d->dqb_bhardlimit = ext2fs_cpu_to_le64(m->dqb_bhardlimit); -- d->dqb_bsoftlimit = ext2fs_cpu_to_le64(m->dqb_bsoftlimit); -- d->dqb_curinodes = ext2fs_cpu_to_le64(m->dqb_curinodes); -- d->dqb_curspace = ext2fs_cpu_to_le64(m->dqb_curspace); -- d->dqb_itime = ext2fs_cpu_to_le64(m->dqb_itime); -- d->dqb_btime = ext2fs_cpu_to_le64(m->dqb_btime); -- d->dqb_id = ext2fs_cpu_to_le32(dquot->dq_id); -- if (qtree_entry_unused(&dquot->dq_h->qh_info.u.v2_mdqi.dqi_qtree, dp)) -- d->dqb_itime = ext2fs_cpu_to_le64(1); --} -- --static int v2r1_is_id(void *dp, struct dquot *dquot) --{ -- struct v2r1_disk_dqblk *d = dp; -- struct qtree_mem_dqinfo *info = -- &dquot->dq_h->qh_info.u.v2_mdqi.dqi_qtree; -- -- if (qtree_entry_unused(info, dp)) -- return 0; -- return ext2fs_le32_to_cpu(d->dqb_id) == dquot->dq_id; --} -- --static struct qtree_fmt_operations v2r1_fmt_ops = { -- .mem2disk_dqblk = v2r1_mem2diskdqblk, -- .disk2mem_dqblk = v2r1_disk2memdqblk, -- .is_id = v2r1_is_id, --}; -- --/* -- * Copy dqinfo from disk to memory -- */ --static inline void v2_disk2memdqinfo(struct util_dqinfo *m, -- struct v2_disk_dqinfo *d) --{ -- m->dqi_bgrace = ext2fs_le32_to_cpu(d->dqi_bgrace); -- m->dqi_igrace = ext2fs_le32_to_cpu(d->dqi_igrace); -- m->u.v2_mdqi.dqi_flags = ext2fs_le32_to_cpu(d->dqi_flags) & V2_DQF_MASK; -- m->u.v2_mdqi.dqi_qtree.dqi_blocks = ext2fs_le32_to_cpu(d->dqi_blocks); -- m->u.v2_mdqi.dqi_qtree.dqi_free_blk = -- ext2fs_le32_to_cpu(d->dqi_free_blk); -- m->u.v2_mdqi.dqi_qtree.dqi_free_entry = -- ext2fs_le32_to_cpu(d->dqi_free_entry); --} -- --/* -- * Copy dqinfo from memory to disk -- */ --static inline void v2_mem2diskdqinfo(struct v2_disk_dqinfo *d, -- struct util_dqinfo *m) --{ -- d->dqi_bgrace = ext2fs_cpu_to_le32(m->dqi_bgrace); -- d->dqi_igrace = ext2fs_cpu_to_le32(m->dqi_igrace); -- d->dqi_flags = ext2fs_cpu_to_le32(m->u.v2_mdqi.dqi_flags & V2_DQF_MASK); -- d->dqi_blocks = ext2fs_cpu_to_le32(m->u.v2_mdqi.dqi_qtree.dqi_blocks); -- d->dqi_free_blk = -- ext2fs_cpu_to_le32(m->u.v2_mdqi.dqi_qtree.dqi_free_blk); -- d->dqi_free_entry = -- ext2fs_cpu_to_le32(m->u.v2_mdqi.dqi_qtree.dqi_free_entry); --} -- --static int v2_read_header(struct quota_handle *h, struct v2_disk_dqheader *dqh) --{ -- if (h->e2fs_read(&h->qh_qf, 0, dqh, sizeof(struct v2_disk_dqheader)) != -- sizeof(struct v2_disk_dqheader)) -- return 0; -- -- return 1; --} -- --/* -- * Check whether given quota file is in our format -- */ --static int v2_check_file(struct quota_handle *h, int type, int fmt) --{ -- struct v2_disk_dqheader dqh; -- int file_magics[] = INITQMAGICS; -- -- if (fmt != QFMT_VFS_V1) -- return 0; -- -- if (!v2_read_header(h, &dqh)) -- return 0; -- -- if (ext2fs_le32_to_cpu(dqh.dqh_magic) != file_magics[type]) { -- if (ext2fs_be32_to_cpu(dqh.dqh_magic) == file_magics[type]) -- log_err("Your quota file is stored in wrong endianity"); -- return 0; -- } -- if (V2_VERSION != ext2fs_le32_to_cpu(dqh.dqh_version)) -- return 0; -- return 1; --} -- --/* -- * Open quotafile -- */ --static int v2_init_io(struct quota_handle *h) --{ -- struct v2_disk_dqinfo ddqinfo; -- -- h->qh_info.u.v2_mdqi.dqi_qtree.dqi_entry_size = -- sizeof(struct v2r1_disk_dqblk); -- h->qh_info.u.v2_mdqi.dqi_qtree.dqi_ops = &v2r1_fmt_ops; -- -- /* Read information about quotafile */ -- if (h->e2fs_read(&h->qh_qf, V2_DQINFOOFF, &ddqinfo, -- sizeof(ddqinfo)) != sizeof(ddqinfo)) -- return -1; -- v2_disk2memdqinfo(&h->qh_info, &ddqinfo); -- return 0; --} -- --/* -- * Initialize new quotafile -- */ --static int v2_new_io(struct quota_handle *h) --{ -- int file_magics[] = INITQMAGICS; -- struct v2_disk_dqheader ddqheader; -- struct v2_disk_dqinfo ddqinfo; -- -- if (h->qh_fmt != QFMT_VFS_V1) -- return -1; -- -- /* Write basic quota header */ -- ddqheader.dqh_magic = ext2fs_cpu_to_le32(file_magics[h->qh_type]); -- ddqheader.dqh_version = ext2fs_cpu_to_le32(V2_VERSION); -- if (h->e2fs_write(&h->qh_qf, 0, &ddqheader, sizeof(ddqheader)) != -- sizeof(ddqheader)) -- return -1; -- -- /* Write information about quotafile */ -- h->qh_info.dqi_bgrace = MAX_DQ_TIME; -- h->qh_info.dqi_igrace = MAX_IQ_TIME; -- h->qh_info.u.v2_mdqi.dqi_flags = 0; -- h->qh_info.u.v2_mdqi.dqi_qtree.dqi_blocks = QT_TREEOFF + 1; -- h->qh_info.u.v2_mdqi.dqi_qtree.dqi_free_blk = 0; -- h->qh_info.u.v2_mdqi.dqi_qtree.dqi_free_entry = 0; -- h->qh_info.u.v2_mdqi.dqi_qtree.dqi_entry_size = -- sizeof(struct v2r1_disk_dqblk); -- h->qh_info.u.v2_mdqi.dqi_qtree.dqi_ops = &v2r1_fmt_ops; -- v2_mem2diskdqinfo(&ddqinfo, &h->qh_info); -- if (h->e2fs_write(&h->qh_qf, V2_DQINFOOFF, &ddqinfo, -- sizeof(ddqinfo)) != -- sizeof(ddqinfo)) -- return -1; -- -- return 0; --} -- --/* -- * Write information (grace times to file) -- */ --static int v2_write_info(struct quota_handle *h) --{ -- struct v2_disk_dqinfo ddqinfo; -- -- v2_mem2diskdqinfo(&ddqinfo, &h->qh_info); -- if (h->e2fs_write(&h->qh_qf, V2_DQINFOOFF, &ddqinfo, sizeof(ddqinfo)) != -- sizeof(ddqinfo)) -- return -1; -- -- return 0; --} -- --/* -- * Read dquot from disk -- */ --static struct dquot *v2_read_dquot(struct quota_handle *h, qid_t id) --{ -- return qtree_read_dquot(h, id); --} -- --/* -- * Commit changes of dquot to disk - it might also mean deleting it when quota -- * became fake one and user has no blocks. -- * User can process use 'errno' to detect errstr. -- */ --static int v2_commit_dquot(struct dquot *dquot) --{ -- struct util_dqblk *b = &dquot->dq_dqb; -- -- if (!b->dqb_curspace && !b->dqb_curinodes && !b->dqb_bsoftlimit && -- !b->dqb_isoftlimit && !b->dqb_bhardlimit && !b->dqb_ihardlimit) -- qtree_delete_dquot(dquot); -- else -- qtree_write_dquot(dquot); -- return 0; --} -- --static int v2_scan_dquots(struct quota_handle *h, -- int (*process_dquot) (struct dquot *, void *), -- void *data) --{ -- return qtree_scan_dquots(h, process_dquot, data); --} -- --/* Report information about quotafile. -- * TODO: Not used right now, but we should be able to use this when we add -- * support to debugfs to read quota files. -- */ --static int v2_report(struct quota_handle *h, int verbose) --{ -- log_err("Not Implemented."); -- return -1; --} -diff --git a/lib/quota/quotaio_v2.h b/lib/quota/quotaio_v2.h -deleted file mode 100644 -index 646c698..0000000 ---- a/lib/quota/quotaio_v2.h -+++ /dev/null -@@ -1,54 +0,0 @@ --/* -- * -- * Header file for disk format of new quotafile format -- * -- */ -- --#ifndef GUARD_QUOTAIO_V2_H --#define GUARD_QUOTAIO_V2_H -- --#include --#include "quotaio.h" -- --/* Offset of info header in file */ --#define V2_DQINFOOFF sizeof(struct v2_disk_dqheader) --/* Supported version of quota-tree format */ --#define V2_VERSION 1 -- --struct v2_disk_dqheader { -- __u32 dqh_magic; /* Magic number identifying file */ -- __u32 dqh_version; /* File version */ --} __attribute__ ((packed)); -- --/* Flags for version specific files */ --#define V2_DQF_MASK 0x0000 /* Mask for all valid ondisk flags */ -- --/* Header with type and version specific information */ --struct v2_disk_dqinfo { -- __u32 dqi_bgrace; /* Time before block soft limit becomes -- * hard limit */ -- __u32 dqi_igrace; /* Time before inode soft limit becomes -- * hard limit */ -- __u32 dqi_flags; /* Flags for quotafile (DQF_*) */ -- __u32 dqi_blocks; /* Number of blocks in file */ -- __u32 dqi_free_blk; /* Number of first free block in the list */ -- __u32 dqi_free_entry; /* Number of block with at least one -- * free entry */ --} __attribute__ ((packed)); -- --struct v2r1_disk_dqblk { -- __u32 dqb_id; /* id this quota applies to */ -- __u32 dqb_pad; -- __u64 dqb_ihardlimit; /* absolute limit on allocated inodes */ -- __u64 dqb_isoftlimit; /* preferred inode limit */ -- __u64 dqb_curinodes; /* current # allocated inodes */ -- __u64 dqb_bhardlimit; /* absolute limit on disk space -- * (in QUOTABLOCK_SIZE) */ -- __u64 dqb_bsoftlimit; /* preferred limit on disk space -- * (in QUOTABLOCK_SIZE) */ -- __u64 dqb_curspace; /* current space occupied (in bytes) */ -- __u64 dqb_btime; /* time limit for excessive disk use */ -- __u64 dqb_itime; /* time limit for excessive inode use */ --} __attribute__ ((packed)); -- --#endif -diff --git a/lib/ss/Android.mk b/lib/ss/Android.mk -new file mode 100644 -index 0000000..9231793 ---- /dev/null -+++ b/lib/ss/Android.mk -@@ -0,0 +1,49 @@ -+LOCAL_PATH := $(call my-dir) -+ -+libext2_ss_src_files := \ -+ ss_err.c \ -+ std_rqs.c \ -+ invocation.c help.c \ -+ execute_cmd.c \ -+ listen.c \ -+ parse.c \ -+ error.c \ -+ prompt.c \ -+ request_tbl.c \ -+ list_rqs.c \ -+ pager.c \ -+ requests.c \ -+ data.c \ -+ get_readline.c -+ -+libext2_ss_c_includes := external/e2fsprogs/lib -+ -+libext2_ss_cflags := -O2 -g -W -Wall -+ -+libext2_ss_shared_libraries := \ -+ libext2_com_err -+ -+libext2_ss_system_shared_libraries := libc -+ -+include $(CLEAR_VARS) -+ -+LOCAL_SRC_FILES := $(libext2_ss_src_files) -+LOCAL_C_INCLUDES := $(libext2_ss_c_includes) -+LOCAL_CFLAGS := $(libext2_ss_cflags) -+LOCAL_SHARED_LIBRARIES := $(libext2_ss_shared_libraries) -+LOCAL_SYSTEM_SHARED_LIBRARIES := $(libext2_ss_system_shared_libraries) -+LOCAL_MODULE := libext2_ss -+LOCAL_MODULE_TAGS := optional -+ -+include $(BUILD_SHARED_LIBRARY) -+ -+include $(CLEAR_VARS) -+ -+LOCAL_SRC_FILES := $(libext2_ss_src_files) -+LOCAL_SHARED_LIBRARIES := $(addsuffix _host, $(libext2_ss_shared_libraries)) -+LOCAL_C_INCLUDES := $(libext2_ss_c_includes) -+LOCAL_CFLAGS := $(libext2_ss_cflags) -+LOCAL_MODULE := libext2_ss_host -+LOCAL_MODULE_TAGS := optional -+ -+include $(BUILD_HOST_SHARED_LIBRARY) -diff --git a/lib/ss/Makefile.in b/lib/ss/Makefile.in -index 0120e56..cfe0f38 100644 ---- a/lib/ss/Makefile.in -+++ b/lib/ss/Makefile.in -@@ -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 $< -@@ -171,7 +172,7 @@ check:: all test_ss - clean:: - $(RM) -f ../libss.a libss.a mk_cmds ss_err.h ss_err.c std_rqs.c \ - tst_cmds.c test_ss test_out test.diff *.o *~ \#* *.bak core \ -- test_cmd.c -+ test_cmd.c ss.pc - - mostlyclean:: clean - distclean:: clean -diff --git a/lib/ss/data.c b/lib/ss/data.c -index 80d1b29..e8245bd 100644 ---- a/lib/ss/data.c -+++ b/lib/ss/data.c -@@ -16,8 +16,5 @@ - #include - #include "ss_internal.h" - --static const char copyright[] = -- "Copyright 1987, 1988, 1989 by the Massachusetts Institute of Technology"; -- - ss_data **_ss_table = (ss_data **)NULL; - char *_ss_pager_name = (char *)NULL; -diff --git a/lib/ss/get_readline.c b/lib/ss/get_readline.c -index 8da85f1..9365be0 100644 ---- a/lib/ss/get_readline.c -+++ b/lib/ss/get_readline.c -@@ -21,9 +21,9 @@ - #include - #endif - -+#ifdef HAVE_DLOPEN - static void ss_release_readline(ss_data *info) - { --#ifdef HAVE_DLOPEN - if (!info->readline_handle) - return; - -@@ -33,15 +33,15 @@ static void ss_release_readline(ss_data *info) - info->rl_completion_matches = 0; - dlclose(info->readline_handle); - info->readline_handle = 0; --#endif - } -+#endif - - /* Libraries we will try to use for readline/editline functionality */ - #define DEFAULT_LIBPATH "libreadline.so.6:libreadline.so.5:libreadline.so.4:libreadline.so:libedit.so.2:libedit.so:libeditline.so.0:libeditline.so" - -+#ifdef HAVE_DLOPEN - void ss_get_readline(int sci_idx) - { --#ifdef HAVE_DLOPEN - void *handle = NULL; - ss_data *info = ss_info(sci_idx); - const char **t, *libpath = 0; -@@ -92,7 +92,9 @@ void ss_get_readline(int sci_idx) - dlsym(handle, "rl_attempted_completion_function")) != NULL) - *completion_func = ss_rl_completion; - info->readline_shutdown = ss_release_readline; --#endif - } -- -- -+#else -+void ss_get_readline(int sci_idx __SS_ATTR((unused))) -+{ -+} -+#endif -diff --git a/lib/support/Android.mk b/lib/support/Android.mk -new file mode 100644 -index 0000000..59094fd ---- /dev/null -+++ b/lib/support/Android.mk -@@ -0,0 +1,57 @@ -+LOCAL_PATH := $(call my-dir) -+ -+libext2_quota_src_files := \ -+ dict.c \ -+ mkquota.c \ -+ plausible.c \ -+ profile.c \ -+ profile_helpers.c \ -+ prof_err.c \ -+ quotaio.c \ -+ quotaio_tree.c \ -+ quotaio_v2.c -+ -+libext2_quota_c_includes := external/e2fsprogs/lib -+ -+libext2_quota_cflags := -O2 -g -W -Wall -+ -+libext2_quota_shared_libraries := libext2fs libext2_com_err libext2_blkid -+ -+libext2_quota_system_shared_libraries := libc -+ -+include $(CLEAR_VARS) -+ -+LOCAL_SRC_FILES := $(libext2_quota_src_files) -+LOCAL_SYSTEM_SHARED_LIBRARIES := $(libext2_quota_system_shared_libraries) -+LOCAL_C_INCLUDES := $(libext2_quota_c_includes) -+LOCAL_CFLAGS := $(libext2_quota_cflags) -+LOCAL_SYSTEM_SHARED_LIBRARIES := libc $(libext2_quota_shared_libraries) -+LOCAL_MODULE := libext2_quota -+LOCAL_MODULE_TAGS := optional -+ -+include $(BUILD_SHARED_LIBRARY) -+ -+libext2_quota_static_libraries := libext2fs libext2_com_err -+ -+include $(CLEAR_VARS) -+ -+LOCAL_SRC_FILES := $(libext2_quota_src_files) -+LOCAL_C_INCLUDES := $(libext2_quota_c_includes) -+LOCAL_CFLAGS := $(libext2_quota_cflags) -+LOCAL_STATIC_LIBRARIES := libc $(libext2_quota_static_libraries) -+LOCAL_PRELINK_MODULE := false -+LOCAL_MODULE := libext2_quota -+LOCAL_MODULE_TAGS := optional -+ -+include $(BUILD_STATIC_LIBRARY) -+ -+include $(CLEAR_VARS) -+ -+LOCAL_SRC_FILES := $(libext2_quota_src_files) -+LOCAL_C_INCLUDES := $(libext2_quota_c_includes) -+LOCAL_CFLAGS := $(libext2_quota_cflags) -+LOCAL_MODULE := libext2_quota_host -+LOCAL_MODULE_TAGS := optional -+LOCAL_SHARED_LIBRARIES := $(addsuffix _host, $(libext2_quota_shared_libraries)) -+ -+include $(BUILD_HOST_SHARED_LIBRARY) -diff --git a/lib/support/Makefile.in b/lib/support/Makefile.in -new file mode 100644 -index 0000000..4b57bbb ---- /dev/null -+++ b/lib/support/Makefile.in -@@ -0,0 +1,148 @@ -+# Makefile for e2fsprog's internal support -+# -+ -+srcdir = @srcdir@ -+top_srcdir = @top_srcdir@ -+VPATH = @srcdir@ -+top_builddir = ../.. -+my_dir = lib/support -+INSTALL = @INSTALL@ -+ -+@MCONFIG@ -+ -+all:: -+ -+OBJS= mkquota.o \ -+ plausible.o \ -+ profile.o \ -+ profile_helpers.o \ -+ prof_err.o \ -+ quotaio.o \ -+ quotaio_v2.o \ -+ quotaio_tree.o \ -+ dict.o -+ -+SRCS= $(srcdir)/argv_parse.c \ -+ $(srcdir)/mkquota.c \ -+ $(srcdir)/plausible.c \ -+ $(srcdir)/profile.c \ -+ $(srcdir)/profile_helpers.c \ -+ prof_err.c \ -+ $(srcdir)/quotaio.c \ -+ $(srcdir)/quotaio_tree.c \ -+ $(srcdir)/quotaio_v2.c \ -+ $(srcdir)/dict.c -+ -+LIBRARY= libsupport -+LIBDIR= support -+ -+@MAKEFILE_LIBRARY@ -+@MAKEFILE_PROFILE@ -+ -+COMPILE_ET=$(top_builddir)/lib/et/compile_et --build-tree -+ -+.c.o: -+ $(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 $< -+ -+installdirs:: -+ -+install:: all -+ -+uninstall:: -+ -+prof_err.c prof_err.h: prof_err.et -+ $(E) " COMPILE_ET prof_err.et" -+ $(Q) $(COMPILE_ET) $(srcdir)/prof_err.et -+ -+test_profile: $(srcdir)/profile.c profile_helpers.o argv_parse.o \ -+ prof_err.o profile.h $(DEPSTATIC_LIBCOM_ERR) -+ $(E) " LD $@" -+ $(Q) $(CC) -o test_profile -DDEBUG_PROGRAM $(srcdir)/profile.c prof_err.o \ -+ profile_helpers.o argv_parse.o $(STATIC_LIBCOM_ERR) \ -+ $(ALL_CFLAGS) -+ -+clean:: -+ $(RM) -f \#* *.s *.o *.a *~ *.bak core profiled/* \ -+ ../libsupport.a ../libsupport_p.a $(SMANPAGES) \ -+ prof_err.c prof_err.h test_profile -+ -+#check:: tst_uuid -+# LD_LIBRARY_PATH=$(LIB) DYLD_LIBRARY_PATH=$(LIB) ./tst_uuid -+ -+mostlyclean:: clean -+distclean:: clean -+ $(RM) -f .depend Makefile \ -+ $(srcdir)/TAGS $(srcdir)/Makefile.in.old -+ -+# -+# Hack to parallel makes recognize dependencies correctly. -+# -+../../lib/libsupport.a: libsupport.a -+../../lib/libsupport.so: image -+../../lib/libsupport.dylib: image -+ -+$(OBJS): -+ -+# +++ Dependency line eater +++ -+# -+# Makefile dependencies follow. This must be the last section in -+# the Makefile.in file -+# -+argv_parse.o: $(srcdir)/argv_parse.c $(top_builddir)/lib/config.h \ -+ $(top_builddir)/lib/dirpaths.h $(srcdir)/argv_parse.h -+mkquota.o: $(srcdir)/mkquota.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 \ -+ $(top_srcdir)/lib/e2p/e2p.h $(srcdir)/quotaio.h $(srcdir)/dqblk_v2.h \ -+ $(srcdir)/quotaio_tree.h $(srcdir)/quotaio_v2.h $(srcdir)/common.h \ -+ $(srcdir)/dict.h -+plausible.o: $(srcdir)/plausible.c $(top_builddir)/lib/config.h \ -+ $(top_builddir)/lib/dirpaths.h $(srcdir)/plausible.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 -+profile.o: $(srcdir)/profile.c $(top_builddir)/lib/config.h \ -+ $(top_builddir)/lib/dirpaths.h $(top_srcdir)/lib/et/com_err.h \ -+ $(srcdir)/profile.h prof_err.h -+profile_helpers.o: $(srcdir)/profile_helpers.c $(top_builddir)/lib/config.h \ -+ $(top_builddir)/lib/dirpaths.h $(top_srcdir)/lib/et/com_err.h \ -+ $(srcdir)/profile.h prof_err.h -+prof_err.o: prof_err.c -+quotaio.o: $(srcdir)/quotaio.c $(top_builddir)/lib/config.h \ -+ $(top_builddir)/lib/dirpaths.h $(srcdir)/common.h \ -+ $(top_builddir)/lib/ext2fs/ext2_types.h $(srcdir)/quotaio.h \ -+ $(top_srcdir)/lib/ext2fs/ext2_fs.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)/dqblk_v2.h $(srcdir)/quotaio_tree.h -+quotaio_tree.o: $(srcdir)/quotaio_tree.c $(top_builddir)/lib/config.h \ -+ $(top_builddir)/lib/dirpaths.h $(srcdir)/common.h \ -+ $(top_builddir)/lib/ext2fs/ext2_types.h $(srcdir)/quotaio_tree.h \ -+ $(srcdir)/quotaio.h $(top_srcdir)/lib/ext2fs/ext2_fs.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)/dqblk_v2.h -+quotaio_v2.o: $(srcdir)/quotaio_v2.c $(top_builddir)/lib/config.h \ -+ $(top_builddir)/lib/dirpaths.h $(srcdir)/common.h \ -+ $(top_builddir)/lib/ext2fs/ext2_types.h $(srcdir)/quotaio_v2.h \ -+ $(srcdir)/quotaio.h $(top_srcdir)/lib/ext2fs/ext2_fs.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)/dqblk_v2.h $(srcdir)/quotaio_tree.h -+dict.o: $(srcdir)/dict.c $(top_builddir)/lib/config.h \ -+ $(top_builddir)/lib/dirpaths.h $(srcdir)/dict.h -diff --git a/lib/support/argv_parse.c b/lib/support/argv_parse.c -new file mode 100644 -index 0000000..d22f634 ---- /dev/null -+++ b/lib/support/argv_parse.c -@@ -0,0 +1,166 @@ -+/* -+ * argv_parse.c --- utility function for parsing a string into a -+ * argc, argv array. -+ * -+ * This file defines a function argv_parse() which parsing a -+ * passed-in string, handling double quotes and backslashes, and -+ * creates an allocated argv vector which can be freed using the -+ * argv_free() function. -+ * -+ * See argv_parse.h for the formal definition of the functions. -+ * -+ * Copyright 1999 by Theodore Ts'o. -+ * -+ * Permission to use, copy, modify, and distribute this software for -+ * any purpose with or without fee is hereby granted, provided that -+ * the above copyright notice and this permission notice appear in all -+ * copies. THE SOFTWARE IS PROVIDED "AS IS" AND THEODORE TS'O (THE -+ * AUTHOR) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. -+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, -+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER -+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION -+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR -+ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. (Isn't -+ * it sick that the U.S. culture of lawsuit-happy lawyers requires -+ * this kind of disclaimer?) -+ * -+ * Version 1.1, modified 2/27/1999 -+ */ -+ -+#include "config.h" -+#ifdef HAVE_STDLIB_H -+#include -+#endif -+#include -+#include -+#include "argv_parse.h" -+ -+#define STATE_WHITESPACE 1 -+#define STATE_TOKEN 2 -+#define STATE_QUOTED 3 -+ -+/* -+ * Returns 0 on success, -1 on failure. -+ */ -+int argv_parse(char *in_buf, int *ret_argc, char ***ret_argv) -+{ -+ int argc = 0, max_argc = 0; -+ char **argv, **new_argv, *buf, ch; -+ char *cp = 0, *outcp = 0; -+ int state = STATE_WHITESPACE; -+ -+ buf = malloc(strlen(in_buf)+1); -+ if (!buf) -+ return -1; -+ -+ max_argc = 0; argc = 0; argv = 0; -+ outcp = buf; -+ for (cp = in_buf; (ch = *cp); cp++) { -+ if (state == STATE_WHITESPACE) { -+ if (isspace((int) ch)) -+ continue; -+ /* Not whitespace, so start a new token */ -+ state = STATE_TOKEN; -+ if (argc >= max_argc) { -+ max_argc += 3; -+ new_argv = realloc(argv, -+ (max_argc+1)*sizeof(char *)); -+ if (!new_argv) { -+ free(argv); -+ free(buf); -+ return -1; -+ } -+ argv = new_argv; -+ } -+ argv[argc++] = outcp; -+ } -+ if (state == STATE_QUOTED) { -+ if (ch == '"') -+ state = STATE_TOKEN; -+ else -+ *outcp++ = ch; -+ continue; -+ } -+ /* Must be processing characters in a word */ -+ if (isspace((int) ch)) { -+ /* -+ * Terminate the current word and start -+ * looking for the beginning of the next word. -+ */ -+ *outcp++ = 0; -+ state = STATE_WHITESPACE; -+ continue; -+ } -+ if (ch == '"') { -+ state = STATE_QUOTED; -+ continue; -+ } -+ if (ch == '\\') { -+ ch = *++cp; -+ switch (ch) { -+ case '\0': -+ ch = '\\'; cp--; break; -+ case 'n': -+ ch = '\n'; break; -+ case 't': -+ ch = '\t'; break; -+ case 'b': -+ ch = '\b'; break; -+ } -+ } -+ *outcp++ = ch; -+ } -+ if (state != STATE_WHITESPACE) -+ *outcp++ = '\0'; -+ if (argv == 0) { -+ argv = malloc(sizeof(char *)); -+ free(buf); -+ } -+ argv[argc] = 0; -+ if (ret_argc) -+ *ret_argc = argc; -+ if (ret_argv) -+ *ret_argv = argv; -+ return 0; -+} -+ -+void argv_free(char **argv) -+{ -+ free(*argv); -+ free(argv); -+} -+ -+#ifdef DEBUG -+/* -+ * For debugging -+ */ -+ -+#include -+ -+int main(int argc, char **argv) -+{ -+ int ac, ret; -+ char **av, **cpp; -+ char buf[256]; -+ -+ while (!feof(stdin)) { -+ if (fgets(buf, sizeof(buf), stdin) == NULL) -+ break; -+ ret = argv_parse(buf, &ac, &av); -+ if (ret != 0) { -+ printf("Argv_parse returned %d!\n", ret); -+ continue; -+ } -+ printf("Argv_parse returned %d arguments...\n", ac); -+ for (cpp = av; *cpp; cpp++) { -+ if (cpp != av) -+ printf(", "); -+ printf("'%s'", *cpp); -+ } -+ printf("\n"); -+ argv_free(av); -+ } -+ exit(0); -+} -+#endif /* DEBUG */ -diff --git a/lib/support/argv_parse.h b/lib/support/argv_parse.h -new file mode 100644 -index 0000000..86f4564 ---- /dev/null -+++ b/lib/support/argv_parse.h -@@ -0,0 +1,43 @@ -+/* -+ * argv_parse.h --- header file for the argv parser. -+ * -+ * This file defines the interface for the functions argv_parse() and -+ * argv_free(). -+ * -+ *********************************************************************** -+ * int argv_parse(char *in_buf, int *ret_argc, char ***ret_argv) -+ * -+ * This function takes as its first argument a string which it will -+ * parse into an argv argument vector, with each white-space separated -+ * word placed into its own slot in the argv. This function handles -+ * double quotes and backslashes so that the parsed words can contain -+ * special characters. The count of the number words found in the -+ * parsed string, as well as the argument vector, are returned into -+ * ret_argc and ret_argv, respectively. -+ *********************************************************************** -+ * extern void argv_free(char **argv); -+ * -+ * This function frees the argument vector created by argv_parse(). -+ *********************************************************************** -+ * -+ * Copyright 1999 by Theodore Ts'o. -+ * -+ * Permission to use, copy, modify, and distribute this software for -+ * any purpose with or without fee is hereby granted, provided that -+ * the above copyright notice and this permission notice appear in all -+ * copies. THE SOFTWARE IS PROVIDED "AS IS" AND THEODORE TS'O (THE -+ * AUTHOR) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. -+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, -+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER -+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION -+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR -+ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. (Isn't -+ * it sick that the U.S. culture of lawsuit-happy lawyers requires -+ * this kind of disclaimer?) -+ * -+ * Version 1.1, modified 2/27/1999 -+ */ -+ -+extern int argv_parse(char *in_buf, int *ret_argc, char ***ret_argv); -+extern void argv_free(char **argv); -diff --git a/lib/support/common.h b/lib/support/common.h -new file mode 100644 -index 0000000..f1ad79f ---- /dev/null -+++ b/lib/support/common.h -@@ -0,0 +1,36 @@ -+/* -+ * -+ * Various things common for all utilities -+ * -+ */ -+ -+#ifndef __QUOTA_COMMON_H__ -+#define __QUOTA_COMMON_H__ -+ -+#if EXT2_FLAT_INCLUDES -+#include "e2_types.h" -+#else -+#include -+#endif /* EXT2_FLAT_INCLUDES */ -+ -+/* #define DEBUG_QUOTA 1 */ -+ -+#ifndef __attribute__ -+# if !defined __GNUC__ || __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 8) || __STRICT_ANSI__ -+# define __attribute__(x) -+# endif -+#endif -+ -+#define log_err(format, arg ...) \ -+ fprintf(stderr, "[ERROR] %s:%d:%s:: " format "\n", \ -+ __FILE__, __LINE__, __func__, ## arg) -+ -+#ifdef DEBUG_QUOTA -+# define log_debug(format, arg ...) \ -+ fprintf(stderr, "[DEBUG] %s:%d:%s:: " format "\n", \ -+ __FILE__, __LINE__, __func__, ## arg) -+#else -+# define log_debug(format, ...) -+#endif -+ -+#endif /* __QUOTA_COMMON_H__ */ -diff --git a/lib/support/dict.c b/lib/support/dict.c -new file mode 100644 -index 0000000..6a5c15c ---- /dev/null -+++ b/lib/support/dict.c -@@ -0,0 +1,1531 @@ -+/* -+ * Dictionary Abstract Data Type -+ * Copyright (C) 1997 Kaz Kylheku -+ * -+ * Free Software License: -+ * -+ * All rights are reserved by the author, with the following exceptions: -+ * Permission is granted to freely reproduce and distribute this software, -+ * possibly in exchange for a fee, provided that this copyright notice appears -+ * intact. Permission is also granted to adapt this software to produce -+ * derivative works, as long as the modified versions carry this copyright -+ * notice and additional notices stating that the work has been modified. -+ * This source code may be translated into executable form and incorporated -+ * into proprietary software; there is no requirement for such software to -+ * contain a copyright notice related to this source. -+ * -+ * $Id: dict.c,v 1.40.2.7 2000/11/13 01:36:44 kaz Exp $ -+ * $Name: kazlib_1_20 $ -+ */ -+ -+#define DICT_NODEBUG -+ -+#ifdef __GNUC__ -+#define EXT2FS_ATTR(x) __attribute__(x) -+#else -+#define EXT2FS_ATTR(x) -+#endif -+ -+#include "config.h" -+#include -+#include -+#ifdef DICT_NODEBUG -+#define dict_assert(x) -+#else -+#include -+#define dict_assert(x) assert(x) -+#endif -+#define DICT_IMPLEMENTATION -+#include "dict.h" -+ -+#ifdef KAZLIB_RCSID -+static const char rcsid[] = "$Id: dict.c,v 1.40.2.7 2000/11/13 01:36:44 kaz Exp $"; -+#endif -+ -+/* -+ * These macros provide short convenient names for structure members, -+ * which are embellished with dict_ prefixes so that they are -+ * properly confined to the documented namespace. It's legal for a -+ * program which uses dict to define, for instance, a macro called ``parent''. -+ * Such a macro would interfere with the dnode_t struct definition. -+ * In general, highly portable and reusable C modules which expose their -+ * structures need to confine structure member names to well-defined spaces. -+ * The resulting identifiers aren't necessarily convenient to use, nor -+ * readable, in the implementation, however! -+ */ -+ -+#define left dict_left -+#define right dict_right -+#define parent dict_parent -+#define color dict_color -+#define key dict_key -+#define data dict_data -+ -+#define nilnode dict_nilnode -+#define nodecount dict_nodecount -+#define maxcount dict_maxcount -+#define compare dict_compare -+#define allocnode dict_allocnode -+#define freenode dict_freenode -+#define context dict_context -+#define dupes dict_dupes -+ -+#define dictptr dict_dictptr -+ -+#define dict_root(D) ((D)->nilnode.left) -+#define dict_nil(D) (&(D)->nilnode) -+#define DICT_DEPTH_MAX 64 -+ -+static dnode_t *dnode_alloc(void *context); -+static void dnode_free(dnode_t *node, void *context); -+ -+/* -+ * Perform a ``left rotation'' adjustment on the tree. The given node P and -+ * its right child C are rearranged so that the P instead becomes the left -+ * child of C. The left subtree of C is inherited as the new right subtree -+ * for P. The ordering of the keys within the tree is thus preserved. -+ */ -+ -+static void rotate_left(dnode_t *upper) -+{ -+ dnode_t *lower, *lowleft, *upparent; -+ -+ lower = upper->right; -+ upper->right = lowleft = lower->left; -+ lowleft->parent = upper; -+ -+ lower->parent = upparent = upper->parent; -+ -+ /* don't need to check for root node here because root->parent is -+ the sentinel nil node, and root->parent->left points back to root */ -+ -+ if (upper == upparent->left) { -+ upparent->left = lower; -+ } else { -+ dict_assert (upper == upparent->right); -+ upparent->right = lower; -+ } -+ -+ lower->left = upper; -+ upper->parent = lower; -+} -+ -+/* -+ * This operation is the ``mirror'' image of rotate_left. It is -+ * the same procedure, but with left and right interchanged. -+ */ -+ -+static void rotate_right(dnode_t *upper) -+{ -+ dnode_t *lower, *lowright, *upparent; -+ -+ lower = upper->left; -+ upper->left = lowright = lower->right; -+ lowright->parent = upper; -+ -+ lower->parent = upparent = upper->parent; -+ -+ if (upper == upparent->right) { -+ upparent->right = lower; -+ } else { -+ dict_assert (upper == upparent->left); -+ upparent->left = lower; -+ } -+ -+ lower->right = upper; -+ upper->parent = lower; -+} -+ -+/* -+ * Do a postorder traversal of the tree rooted at the specified -+ * node and free everything under it. Used by dict_free(). -+ */ -+ -+static void free_nodes(dict_t *dict, dnode_t *node, dnode_t *nil) -+{ -+ if (node == nil) -+ return; -+ free_nodes(dict, node->left, nil); -+ free_nodes(dict, node->right, nil); -+ dict->freenode(node, dict->context); -+} -+ -+/* -+ * This procedure performs a verification that the given subtree is a binary -+ * search tree. It performs an inorder traversal of the tree using the -+ * dict_next() successor function, verifying that the key of each node is -+ * strictly lower than that of its successor, if duplicates are not allowed, -+ * or lower or equal if duplicates are allowed. This function is used for -+ * debugging purposes. -+ */ -+#ifndef DICT_NODEBUG -+static int verify_bintree(dict_t *dict) -+{ -+ dnode_t *first, *next; -+ -+ first = dict_first(dict); -+ -+ if (dict->dupes) { -+ while (first && (next = dict_next(dict, first))) { -+ if (dict->compare(first->key, next->key) > 0) -+ return 0; -+ first = next; -+ } -+ } else { -+ while (first && (next = dict_next(dict, first))) { -+ if (dict->compare(first->key, next->key) >= 0) -+ return 0; -+ first = next; -+ } -+ } -+ return 1; -+} -+ -+/* -+ * This function recursively verifies that the given binary subtree satisfies -+ * three of the red black properties. It checks that every red node has only -+ * black children. It makes sure that each node is either red or black. And it -+ * checks that every path has the same count of black nodes from root to leaf. -+ * It returns the blackheight of the given subtree; this allows blackheights to -+ * be computed recursively and compared for left and right siblings for -+ * mismatches. It does not check for every nil node being black, because there -+ * is only one sentinel nil node. The return value of this function is the -+ * black height of the subtree rooted at the node ``root'', or zero if the -+ * subtree is not red-black. -+ */ -+ -+static unsigned int verify_redblack(dnode_t *nil, dnode_t *root) -+{ -+ unsigned height_left, height_right; -+ -+ if (root != nil) { -+ height_left = verify_redblack(nil, root->left); -+ height_right = verify_redblack(nil, root->right); -+ if (height_left == 0 || height_right == 0) -+ return 0; -+ if (height_left != height_right) -+ return 0; -+ if (root->color == dnode_red) { -+ if (root->left->color != dnode_black) -+ return 0; -+ if (root->right->color != dnode_black) -+ return 0; -+ return height_left; -+ } -+ if (root->color != dnode_black) -+ return 0; -+ return height_left + 1; -+ } -+ return 1; -+} -+ -+/* -+ * Compute the actual count of nodes by traversing the tree and -+ * return it. This could be compared against the stored count to -+ * detect a mismatch. -+ */ -+ -+static dictcount_t verify_node_count(dnode_t *nil, dnode_t *root) -+{ -+ if (root == nil) -+ return 0; -+ else -+ return 1 + verify_node_count(nil, root->left) -+ + verify_node_count(nil, root->right); -+} -+#endif -+ -+/* -+ * Verify that the tree contains the given node. This is done by -+ * traversing all of the nodes and comparing their pointers to the -+ * given pointer. Returns 1 if the node is found, otherwise -+ * returns zero. It is intended for debugging purposes. -+ */ -+ -+static int verify_dict_has_node(dnode_t *nil, dnode_t *root, dnode_t *node) -+{ -+ if (root != nil) { -+ return root == node -+ || verify_dict_has_node(nil, root->left, node) -+ || verify_dict_has_node(nil, root->right, node); -+ } -+ return 0; -+} -+ -+ -+#ifdef E2FSCK_NOTUSED -+/* -+ * Dynamically allocate and initialize a dictionary object. -+ */ -+ -+dict_t *dict_create(dictcount_t maxcount, dict_comp_t comp) -+{ -+ dict_t *new = malloc(sizeof *new); -+ -+ if (new) { -+ new->compare = comp; -+ new->allocnode = dnode_alloc; -+ new->freenode = dnode_free; -+ new->context = NULL; -+ new->nodecount = 0; -+ new->maxcount = maxcount; -+ new->nilnode.left = &new->nilnode; -+ new->nilnode.right = &new->nilnode; -+ new->nilnode.parent = &new->nilnode; -+ new->nilnode.color = dnode_black; -+ new->dupes = 0; -+ } -+ return new; -+} -+#endif /* E2FSCK_NOTUSED */ -+ -+/* -+ * Select a different set of node allocator routines. -+ */ -+ -+void dict_set_allocator(dict_t *dict, dnode_alloc_t al, -+ dnode_free_t fr, void *context) -+{ -+ dict_assert (dict_count(dict) == 0); -+ dict_assert ((al == NULL && fr == NULL) || (al != NULL && fr != NULL)); -+ -+ dict->allocnode = al ? al : dnode_alloc; -+ dict->freenode = fr ? fr : dnode_free; -+ dict->context = context; -+} -+ -+#ifdef E2FSCK_NOTUSED -+/* -+ * Free a dynamically allocated dictionary object. Removing the nodes -+ * from the tree before deleting it is required. -+ */ -+ -+void dict_destroy(dict_t *dict) -+{ -+ dict_assert (dict_isempty(dict)); -+ free(dict); -+} -+#endif -+ -+/* -+ * Free all the nodes in the dictionary by using the dictionary's -+ * installed free routine. The dictionary is emptied. -+ */ -+ -+void dict_free_nodes(dict_t *dict) -+{ -+ dnode_t *nil = dict_nil(dict), *root = dict_root(dict); -+ free_nodes(dict, root, nil); -+ dict->nodecount = 0; -+ dict->nilnode.left = &dict->nilnode; -+ dict->nilnode.right = &dict->nilnode; -+} -+ -+#ifdef E2FSCK_NOTUSED -+/* -+ * Obsolescent function, equivalent to dict_free_nodes -+ */ -+void dict_free(dict_t *dict) -+{ -+#ifdef KAZLIB_OBSOLESCENT_DEBUG -+ dict_assert ("call to obsolescent function dict_free()" && 0); -+#endif -+ dict_free_nodes(dict); -+} -+#endif -+ -+/* -+ * Initialize a user-supplied dictionary object. -+ */ -+ -+dict_t *dict_init(dict_t *dict, dictcount_t maxcount, dict_comp_t comp) -+{ -+ dict->compare = comp; -+ dict->allocnode = dnode_alloc; -+ dict->freenode = dnode_free; -+ dict->context = NULL; -+ dict->nodecount = 0; -+ dict->maxcount = maxcount; -+ dict->nilnode.left = &dict->nilnode; -+ dict->nilnode.right = &dict->nilnode; -+ dict->nilnode.parent = &dict->nilnode; -+ dict->nilnode.color = dnode_black; -+ dict->dupes = 0; -+ return dict; -+} -+ -+#ifdef E2FSCK_NOTUSED -+/* -+ * Initialize a dictionary in the likeness of another dictionary -+ */ -+ -+void dict_init_like(dict_t *dict, const dict_t *template) -+{ -+ dict->compare = template->compare; -+ dict->allocnode = template->allocnode; -+ dict->freenode = template->freenode; -+ dict->context = template->context; -+ dict->nodecount = 0; -+ dict->maxcount = template->maxcount; -+ dict->nilnode.left = &dict->nilnode; -+ dict->nilnode.right = &dict->nilnode; -+ dict->nilnode.parent = &dict->nilnode; -+ dict->nilnode.color = dnode_black; -+ dict->dupes = template->dupes; -+ -+ dict_assert (dict_similar(dict, template)); -+} -+ -+/* -+ * Remove all nodes from the dictionary (without freeing them in any way). -+ */ -+ -+static void dict_clear(dict_t *dict) -+{ -+ dict->nodecount = 0; -+ dict->nilnode.left = &dict->nilnode; -+ dict->nilnode.right = &dict->nilnode; -+ dict->nilnode.parent = &dict->nilnode; -+ dict_assert (dict->nilnode.color == dnode_black); -+} -+#endif /* E2FSCK_NOTUSED */ -+ -+ -+/* -+ * Verify the integrity of the dictionary structure. This is provided for -+ * debugging purposes, and should be placed in assert statements. Just because -+ * this function succeeds doesn't mean that the tree is not corrupt. Certain -+ * corruptions in the tree may simply cause undefined behavior. -+ */ -+#ifndef DICT_NODEBUG -+int dict_verify(dict_t *dict) -+{ -+ dnode_t *nil = dict_nil(dict), *root = dict_root(dict); -+ -+ /* check that the sentinel node and root node are black */ -+ if (root->color != dnode_black) -+ return 0; -+ if (nil->color != dnode_black) -+ return 0; -+ if (nil->right != nil) -+ return 0; -+ /* nil->left is the root node; check that its parent pointer is nil */ -+ if (nil->left->parent != nil) -+ return 0; -+ /* perform a weak test that the tree is a binary search tree */ -+ if (!verify_bintree(dict)) -+ return 0; -+ /* verify that the tree is a red-black tree */ -+ if (!verify_redblack(nil, root)) -+ return 0; -+ if (verify_node_count(nil, root) != dict_count(dict)) -+ return 0; -+ return 1; -+} -+#endif /* DICT_NODEBUG */ -+ -+#ifdef E2FSCK_NOTUSED -+/* -+ * Determine whether two dictionaries are similar: have the same comparison and -+ * allocator functions, and same status as to whether duplicates are allowed. -+ */ -+int dict_similar(const dict_t *left, const dict_t *right) -+{ -+ if (left->compare != right->compare) -+ return 0; -+ -+ if (left->allocnode != right->allocnode) -+ return 0; -+ -+ if (left->freenode != right->freenode) -+ return 0; -+ -+ if (left->context != right->context) -+ return 0; -+ -+ if (left->dupes != right->dupes) -+ return 0; -+ -+ return 1; -+} -+#endif /* E2FSCK_NOTUSED */ -+ -+/* -+ * Locate a node in the dictionary having the given key. -+ * If the node is not found, a null a pointer is returned (rather than -+ * a pointer that dictionary's nil sentinel node), otherwise a pointer to the -+ * located node is returned. -+ */ -+ -+dnode_t *dict_lookup(dict_t *dict, const void *key) -+{ -+ dnode_t *root = dict_root(dict); -+ dnode_t *nil = dict_nil(dict); -+ dnode_t *saved; -+ int result; -+ -+ /* simple binary search adapted for trees that contain duplicate keys */ -+ -+ while (root != nil) { -+ result = dict->compare(key, root->key); -+ if (result < 0) -+ root = root->left; -+ else if (result > 0) -+ root = root->right; -+ else { -+ if (!dict->dupes) { /* no duplicates, return match */ -+ return root; -+ } else { /* could be dupes, find leftmost one */ -+ do { -+ saved = root; -+ root = root->left; -+ while (root != nil && dict->compare(key, root->key)) -+ root = root->right; -+ } while (root != nil); -+ return saved; -+ } -+ } -+ } -+ -+ return NULL; -+} -+ -+#ifdef E2FSCK_NOTUSED -+/* -+ * Look for the node corresponding to the lowest key that is equal to or -+ * greater than the given key. If there is no such node, return null. -+ */ -+ -+dnode_t *dict_lower_bound(dict_t *dict, const void *key) -+{ -+ dnode_t *root = dict_root(dict); -+ dnode_t *nil = dict_nil(dict); -+ dnode_t *tentative = 0; -+ -+ while (root != nil) { -+ int result = dict->compare(key, root->key); -+ -+ if (result > 0) { -+ root = root->right; -+ } else if (result < 0) { -+ tentative = root; -+ root = root->left; -+ } else { -+ if (!dict->dupes) { -+ return root; -+ } else { -+ tentative = root; -+ root = root->left; -+ } -+ } -+ } -+ -+ return tentative; -+} -+ -+/* -+ * Look for the node corresponding to the greatest key that is equal to or -+ * lower than the given key. If there is no such node, return null. -+ */ -+ -+dnode_t *dict_upper_bound(dict_t *dict, const void *key) -+{ -+ dnode_t *root = dict_root(dict); -+ dnode_t *nil = dict_nil(dict); -+ dnode_t *tentative = 0; -+ -+ while (root != nil) { -+ int result = dict->compare(key, root->key); -+ -+ if (result < 0) { -+ root = root->left; -+ } else if (result > 0) { -+ tentative = root; -+ root = root->right; -+ } else { -+ if (!dict->dupes) { -+ return root; -+ } else { -+ tentative = root; -+ root = root->right; -+ } -+ } -+ } -+ -+ return tentative; -+} -+#endif -+ -+/* -+ * Insert a node into the dictionary. The node should have been -+ * initialized with a data field. All other fields are ignored. -+ * The behavior is undefined if the user attempts to insert into -+ * a dictionary that is already full (for which the dict_isfull() -+ * function returns true). -+ */ -+ -+void dict_insert(dict_t *dict, dnode_t *node, const void *key) -+{ -+ dnode_t *where = dict_root(dict), *nil = dict_nil(dict); -+ dnode_t *parent = nil, *uncle, *grandpa; -+ int result = -1; -+ -+ node->key = key; -+ -+ dict_assert (!dict_isfull(dict)); -+ dict_assert (!dict_contains(dict, node)); -+ dict_assert (!dnode_is_in_a_dict(node)); -+ -+ /* basic binary tree insert */ -+ -+ while (where != nil) { -+ parent = where; -+ result = dict->compare(key, where->key); -+ /* trap attempts at duplicate key insertion unless it's explicitly allowed */ -+ dict_assert (dict->dupes || result != 0); -+ if (result < 0) -+ where = where->left; -+ else -+ where = where->right; -+ } -+ -+ dict_assert (where == nil); -+ -+ if (result < 0) -+ parent->left = node; -+ else -+ parent->right = node; -+ -+ node->parent = parent; -+ node->left = nil; -+ node->right = nil; -+ -+ dict->nodecount++; -+ -+ /* red black adjustments */ -+ -+ node->color = dnode_red; -+ -+ while (parent->color == dnode_red) { -+ grandpa = parent->parent; -+ if (parent == grandpa->left) { -+ uncle = grandpa->right; -+ if (uncle->color == dnode_red) { /* red parent, red uncle */ -+ parent->color = dnode_black; -+ uncle->color = dnode_black; -+ grandpa->color = dnode_red; -+ node = grandpa; -+ parent = grandpa->parent; -+ } else { /* red parent, black uncle */ -+ if (node == parent->right) { -+ rotate_left(parent); -+ parent = node; -+ dict_assert (grandpa == parent->parent); -+ /* rotation between parent and child preserves grandpa */ -+ } -+ parent->color = dnode_black; -+ grandpa->color = dnode_red; -+ rotate_right(grandpa); -+ break; -+ } -+ } else { /* symmetric cases: parent == parent->parent->right */ -+ uncle = grandpa->left; -+ if (uncle->color == dnode_red) { -+ parent->color = dnode_black; -+ uncle->color = dnode_black; -+ grandpa->color = dnode_red; -+ node = grandpa; -+ parent = grandpa->parent; -+ } else { -+ if (node == parent->left) { -+ rotate_right(parent); -+ parent = node; -+ dict_assert (grandpa == parent->parent); -+ } -+ parent->color = dnode_black; -+ grandpa->color = dnode_red; -+ rotate_left(grandpa); -+ break; -+ } -+ } -+ } -+ -+ dict_root(dict)->color = dnode_black; -+ -+ dict_assert (dict_verify(dict)); -+} -+ -+#ifdef E2FSCK_NOTUSED -+/* -+ * Delete the given node from the dictionary. If the given node does not belong -+ * to the given dictionary, undefined behavior results. A pointer to the -+ * deleted node is returned. -+ */ -+ -+dnode_t *dict_delete(dict_t *dict, dnode_t *delete) -+{ -+ dnode_t *nil = dict_nil(dict), *child, *delparent = delete->parent; -+ -+ /* basic deletion */ -+ -+ dict_assert (!dict_isempty(dict)); -+ dict_assert (dict_contains(dict, delete)); -+ -+ /* -+ * If the node being deleted has two children, then we replace it with its -+ * successor (i.e. the leftmost node in the right subtree.) By doing this, -+ * we avoid the traditional algorithm under which the successor's key and -+ * value *only* move to the deleted node and the successor is spliced out -+ * from the tree. We cannot use this approach because the user may hold -+ * pointers to the successor, or nodes may be inextricably tied to some -+ * other structures by way of embedding, etc. So we must splice out the -+ * node we are given, not some other node, and must not move contents from -+ * one node to another behind the user's back. -+ */ -+ -+ if (delete->left != nil && delete->right != nil) { -+ dnode_t *next = dict_next(dict, delete); -+ dnode_t *nextparent = next->parent; -+ dnode_color_t nextcolor = next->color; -+ -+ dict_assert (next != nil); -+ dict_assert (next->parent != nil); -+ dict_assert (next->left == nil); -+ -+ /* -+ * First, splice out the successor from the tree completely, by -+ * moving up its right child into its place. -+ */ -+ -+ child = next->right; -+ child->parent = nextparent; -+ -+ if (nextparent->left == next) { -+ nextparent->left = child; -+ } else { -+ dict_assert (nextparent->right == next); -+ nextparent->right = child; -+ } -+ -+ /* -+ * Now that the successor has been extricated from the tree, install it -+ * in place of the node that we want deleted. -+ */ -+ -+ next->parent = delparent; -+ next->left = delete->left; -+ next->right = delete->right; -+ next->left->parent = next; -+ next->right->parent = next; -+ next->color = delete->color; -+ delete->color = nextcolor; -+ -+ if (delparent->left == delete) { -+ delparent->left = next; -+ } else { -+ dict_assert (delparent->right == delete); -+ delparent->right = next; -+ } -+ -+ } else { -+ dict_assert (delete != nil); -+ dict_assert (delete->left == nil || delete->right == nil); -+ -+ child = (delete->left != nil) ? delete->left : delete->right; -+ -+ child->parent = delparent = delete->parent; -+ -+ if (delete == delparent->left) { -+ delparent->left = child; -+ } else { -+ dict_assert (delete == delparent->right); -+ delparent->right = child; -+ } -+ } -+ -+ delete->parent = NULL; -+ delete->right = NULL; -+ delete->left = NULL; -+ -+ dict->nodecount--; -+ -+ dict_assert (verify_bintree(dict)); -+ -+ /* red-black adjustments */ -+ -+ if (delete->color == dnode_black) { -+ dnode_t *parent, *sister; -+ -+ dict_root(dict)->color = dnode_red; -+ -+ while (child->color == dnode_black) { -+ parent = child->parent; -+ if (child == parent->left) { -+ sister = parent->right; -+ dict_assert (sister != nil); -+ if (sister->color == dnode_red) { -+ sister->color = dnode_black; -+ parent->color = dnode_red; -+ rotate_left(parent); -+ sister = parent->right; -+ dict_assert (sister != nil); -+ } -+ if (sister->left->color == dnode_black -+ && sister->right->color == dnode_black) { -+ sister->color = dnode_red; -+ child = parent; -+ } else { -+ if (sister->right->color == dnode_black) { -+ dict_assert (sister->left->color == dnode_red); -+ sister->left->color = dnode_black; -+ sister->color = dnode_red; -+ rotate_right(sister); -+ sister = parent->right; -+ dict_assert (sister != nil); -+ } -+ sister->color = parent->color; -+ sister->right->color = dnode_black; -+ parent->color = dnode_black; -+ rotate_left(parent); -+ break; -+ } -+ } else { /* symmetric case: child == child->parent->right */ -+ dict_assert (child == parent->right); -+ sister = parent->left; -+ dict_assert (sister != nil); -+ if (sister->color == dnode_red) { -+ sister->color = dnode_black; -+ parent->color = dnode_red; -+ rotate_right(parent); -+ sister = parent->left; -+ dict_assert (sister != nil); -+ } -+ if (sister->right->color == dnode_black -+ && sister->left->color == dnode_black) { -+ sister->color = dnode_red; -+ child = parent; -+ } else { -+ if (sister->left->color == dnode_black) { -+ dict_assert (sister->right->color == dnode_red); -+ sister->right->color = dnode_black; -+ sister->color = dnode_red; -+ rotate_left(sister); -+ sister = parent->left; -+ dict_assert (sister != nil); -+ } -+ sister->color = parent->color; -+ sister->left->color = dnode_black; -+ parent->color = dnode_black; -+ rotate_right(parent); -+ break; -+ } -+ } -+ } -+ -+ child->color = dnode_black; -+ dict_root(dict)->color = dnode_black; -+ } -+ -+ dict_assert (dict_verify(dict)); -+ -+ return delete; -+} -+#endif /* E2FSCK_NOTUSED */ -+ -+/* -+ * Allocate a node using the dictionary's allocator routine, give it -+ * the data item. -+ */ -+ -+int dict_alloc_insert(dict_t *dict, const void *key, void *data) -+{ -+ dnode_t *node = dict->allocnode(dict->context); -+ -+ if (node) { -+ dnode_init(node, data); -+ dict_insert(dict, node, key); -+ return 1; -+ } -+ return 0; -+} -+ -+#ifdef E2FSCK_NOTUSED -+void dict_delete_free(dict_t *dict, dnode_t *node) -+{ -+ dict_delete(dict, node); -+ dict->freenode(node, dict->context); -+} -+#endif -+ -+/* -+ * Return the node with the lowest (leftmost) key. If the dictionary is empty -+ * (that is, dict_isempty(dict) returns 1) a null pointer is returned. -+ */ -+ -+dnode_t *dict_first(dict_t *dict) -+{ -+ dnode_t *nil = dict_nil(dict), *root = dict_root(dict), *left; -+ -+ if (root != nil) -+ while ((left = root->left) != nil) -+ root = left; -+ -+ return (root == nil) ? NULL : root; -+} -+ -+/* -+ * Return the node with the highest (rightmost) key. If the dictionary is empty -+ * (that is, dict_isempty(dict) returns 1) a null pointer is returned. -+ */ -+ -+dnode_t *dict_last(dict_t *dict) -+{ -+ dnode_t *nil = dict_nil(dict), *root = dict_root(dict), *right; -+ -+ if (root != nil) -+ while ((right = root->right) != nil) -+ root = right; -+ -+ return (root == nil) ? NULL : root; -+} -+ -+/* -+ * Return the given node's successor node---the node which has the -+ * next key in the the left to right ordering. If the node has -+ * no successor, a null pointer is returned rather than a pointer to -+ * the nil node. -+ */ -+ -+dnode_t *dict_next(dict_t *dict, dnode_t *curr) -+{ -+ dnode_t *nil = dict_nil(dict), *parent, *left; -+ -+ if (curr->right != nil) { -+ curr = curr->right; -+ while ((left = curr->left) != nil) -+ curr = left; -+ return curr; -+ } -+ -+ parent = curr->parent; -+ -+ while (parent != nil && curr == parent->right) { -+ curr = parent; -+ parent = curr->parent; -+ } -+ -+ return (parent == nil) ? NULL : parent; -+} -+ -+/* -+ * Return the given node's predecessor, in the key order. -+ * The nil sentinel node is returned if there is no predecessor. -+ */ -+ -+dnode_t *dict_prev(dict_t *dict, dnode_t *curr) -+{ -+ dnode_t *nil = dict_nil(dict), *parent, *right; -+ -+ if (curr->left != nil) { -+ curr = curr->left; -+ while ((right = curr->right) != nil) -+ curr = right; -+ return curr; -+ } -+ -+ parent = curr->parent; -+ -+ while (parent != nil && curr == parent->left) { -+ curr = parent; -+ parent = curr->parent; -+ } -+ -+ return (parent == nil) ? NULL : parent; -+} -+ -+void dict_allow_dupes(dict_t *dict) -+{ -+ dict->dupes = 1; -+} -+ -+#undef dict_count -+#undef dict_isempty -+#undef dict_isfull -+#undef dnode_get -+#undef dnode_put -+#undef dnode_getkey -+ -+dictcount_t dict_count(dict_t *dict) -+{ -+ return dict->nodecount; -+} -+ -+int dict_isempty(dict_t *dict) -+{ -+ return dict->nodecount == 0; -+} -+ -+int dict_isfull(dict_t *dict) -+{ -+ return dict->nodecount == dict->maxcount; -+} -+ -+int dict_contains(dict_t *dict, dnode_t *node) -+{ -+ return verify_dict_has_node(dict_nil(dict), dict_root(dict), node); -+} -+ -+static dnode_t *dnode_alloc(void *context EXT2FS_ATTR((unused))) -+{ -+ return malloc(sizeof *dnode_alloc(NULL)); -+} -+ -+static void dnode_free(dnode_t *node, void *context EXT2FS_ATTR((unused))) -+{ -+ free(node); -+} -+ -+dnode_t *dnode_create(void *data) -+{ -+ dnode_t *new = malloc(sizeof *new); -+ if (new) { -+ new->data = data; -+ new->parent = NULL; -+ new->left = NULL; -+ new->right = NULL; -+ } -+ return new; -+} -+ -+dnode_t *dnode_init(dnode_t *dnode, void *data) -+{ -+ dnode->data = data; -+ dnode->parent = NULL; -+ dnode->left = NULL; -+ dnode->right = NULL; -+ return dnode; -+} -+ -+void dnode_destroy(dnode_t *dnode) -+{ -+ dict_assert (!dnode_is_in_a_dict(dnode)); -+ free(dnode); -+} -+ -+void *dnode_get(dnode_t *dnode) -+{ -+ return dnode->data; -+} -+ -+const void *dnode_getkey(dnode_t *dnode) -+{ -+ return dnode->key; -+} -+ -+#ifdef E2FSCK_NOTUSED -+void dnode_put(dnode_t *dnode, void *data) -+{ -+ dnode->data = data; -+} -+#endif -+ -+#ifndef DICT_NODEBUG -+int dnode_is_in_a_dict(dnode_t *dnode) -+{ -+ return (dnode->parent && dnode->left && dnode->right); -+} -+#endif -+ -+#ifdef E2FSCK_NOTUSED -+void dict_process(dict_t *dict, void *context, dnode_process_t function) -+{ -+ dnode_t *node = dict_first(dict), *next; -+ -+ while (node != NULL) { -+ /* check for callback function deleting */ -+ /* the next node from under us */ -+ dict_assert (dict_contains(dict, node)); -+ next = dict_next(dict, node); -+ function(dict, node, context); -+ node = next; -+ } -+} -+ -+static void load_begin_internal(dict_load_t *load, dict_t *dict) -+{ -+ load->dictptr = dict; -+ load->nilnode.left = &load->nilnode; -+ load->nilnode.right = &load->nilnode; -+} -+ -+void dict_load_begin(dict_load_t *load, dict_t *dict) -+{ -+ dict_assert (dict_isempty(dict)); -+ load_begin_internal(load, dict); -+} -+ -+void dict_load_next(dict_load_t *load, dnode_t *newnode, const void *key) -+{ -+ dict_t *dict = load->dictptr; -+ dnode_t *nil = &load->nilnode; -+ -+ dict_assert (!dnode_is_in_a_dict(newnode)); -+ dict_assert (dict->nodecount < dict->maxcount); -+ -+#ifndef DICT_NODEBUG -+ if (dict->nodecount > 0) { -+ if (dict->dupes) -+ dict_assert (dict->compare(nil->left->key, key) <= 0); -+ else -+ dict_assert (dict->compare(nil->left->key, key) < 0); -+ } -+#endif -+ -+ newnode->key = key; -+ nil->right->left = newnode; -+ nil->right = newnode; -+ newnode->left = nil; -+ dict->nodecount++; -+} -+ -+void dict_load_end(dict_load_t *load) -+{ -+ dict_t *dict = load->dictptr; -+ dnode_t *tree[DICT_DEPTH_MAX] = { 0 }; -+ dnode_t *curr, *dictnil = dict_nil(dict), *loadnil = &load->nilnode, *next; -+ dnode_t *complete = 0; -+ dictcount_t fullcount = DICTCOUNT_T_MAX, nodecount = dict->nodecount; -+ dictcount_t botrowcount; -+ unsigned baselevel = 0, level = 0, i; -+ -+ dict_assert (dnode_red == 0 && dnode_black == 1); -+ -+ while (fullcount >= nodecount && fullcount) -+ fullcount >>= 1; -+ -+ botrowcount = nodecount - fullcount; -+ -+ for (curr = loadnil->left; curr != loadnil; curr = next) { -+ next = curr->left; -+ -+ if (complete == NULL && botrowcount-- == 0) { -+ dict_assert (baselevel == 0); -+ dict_assert (level == 0); -+ baselevel = level = 1; -+ complete = tree[0]; -+ -+ if (complete != 0) { -+ tree[0] = 0; -+ complete->right = dictnil; -+ while (tree[level] != 0) { -+ tree[level]->right = complete; -+ complete->parent = tree[level]; -+ complete = tree[level]; -+ tree[level++] = 0; -+ } -+ } -+ } -+ -+ if (complete == NULL) { -+ curr->left = dictnil; -+ curr->right = dictnil; -+ curr->color = level % 2; -+ complete = curr; -+ -+ dict_assert (level == baselevel); -+ while (tree[level] != 0) { -+ tree[level]->right = complete; -+ complete->parent = tree[level]; -+ complete = tree[level]; -+ tree[level++] = 0; -+ } -+ } else { -+ curr->left = complete; -+ curr->color = (level + 1) % 2; -+ complete->parent = curr; -+ tree[level] = curr; -+ complete = 0; -+ level = baselevel; -+ } -+ } -+ -+ if (complete == NULL) -+ complete = dictnil; -+ -+ for (i = 0; i < DICT_DEPTH_MAX; i++) { -+ if (tree[i] != 0) { -+ tree[i]->right = complete; -+ complete->parent = tree[i]; -+ complete = tree[i]; -+ } -+ } -+ -+ dictnil->color = dnode_black; -+ dictnil->right = dictnil; -+ complete->parent = dictnil; -+ complete->color = dnode_black; -+ dict_root(dict) = complete; -+ -+ dict_assert (dict_verify(dict)); -+} -+ -+void dict_merge(dict_t *dest, dict_t *source) -+{ -+ dict_load_t load; -+ dnode_t *leftnode = dict_first(dest), *rightnode = dict_first(source); -+ -+ dict_assert (dict_similar(dest, source)); -+ -+ if (source == dest) -+ return; -+ -+ dest->nodecount = 0; -+ load_begin_internal(&load, dest); -+ -+ for (;;) { -+ if (leftnode != NULL && rightnode != NULL) { -+ if (dest->compare(leftnode->key, rightnode->key) < 0) -+ goto copyleft; -+ else -+ goto copyright; -+ } else if (leftnode != NULL) { -+ goto copyleft; -+ } else if (rightnode != NULL) { -+ goto copyright; -+ } else { -+ dict_assert (leftnode == NULL && rightnode == NULL); -+ break; -+ } -+ -+ copyleft: -+ { -+ dnode_t *next = dict_next(dest, leftnode); -+#ifndef DICT_NODEBUG -+ leftnode->left = NULL; /* suppress assertion in dict_load_next */ -+#endif -+ dict_load_next(&load, leftnode, leftnode->key); -+ leftnode = next; -+ continue; -+ } -+ -+ copyright: -+ { -+ dnode_t *next = dict_next(source, rightnode); -+#ifndef DICT_NODEBUG -+ rightnode->left = NULL; -+#endif -+ dict_load_next(&load, rightnode, rightnode->key); -+ rightnode = next; -+ continue; -+ } -+ } -+ -+ dict_clear(source); -+ dict_load_end(&load); -+} -+#endif /* E2FSCK_NOTUSED */ -+ -+#ifdef KAZLIB_TEST_MAIN -+ -+#include -+#include -+#include -+#include -+ -+typedef char input_t[256]; -+ -+static int tokenize(char *string, ...) -+{ -+ char **tokptr; -+ va_list arglist; -+ int tokcount = 0; -+ -+ va_start(arglist, string); -+ tokptr = va_arg(arglist, char **); -+ while (tokptr) { -+ while (*string && isspace((unsigned char) *string)) -+ string++; -+ if (!*string) -+ break; -+ *tokptr = string; -+ while (*string && !isspace((unsigned char) *string)) -+ string++; -+ tokptr = va_arg(arglist, char **); -+ tokcount++; -+ if (!*string) -+ break; -+ *string++ = 0; -+ } -+ va_end(arglist); -+ -+ return tokcount; -+} -+ -+static int comparef(const void *key1, const void *key2) -+{ -+ return strcmp(key1, key2); -+} -+ -+static char *dupstring(char *str) -+{ -+ int sz = strlen(str) + 1; -+ char *new = malloc(sz); -+ if (new) -+ memcpy(new, str, sz); -+ return new; -+} -+ -+static dnode_t *new_node(void *c) -+{ -+ static dnode_t few[5]; -+ static int count; -+ -+ if (count < 5) -+ return few + count++; -+ -+ return NULL; -+} -+ -+static void del_node(dnode_t *n, void *c) -+{ -+} -+ -+static int prompt = 0; -+ -+static void construct(dict_t *d) -+{ -+ input_t in; -+ int done = 0; -+ dict_load_t dl; -+ dnode_t *dn; -+ char *tok1, *tok2, *val; -+ const char *key; -+ char *help = -+ "p turn prompt on\n" -+ "q finish construction\n" -+ "a add new entry\n"; -+ -+ if (!dict_isempty(d)) -+ puts("warning: dictionary not empty!"); -+ -+ dict_load_begin(&dl, d); -+ -+ while (!done) { -+ if (prompt) -+ putchar('>'); -+ fflush(stdout); -+ -+ if (!fgets(in, sizeof(input_t), stdin)) -+ break; -+ -+ switch (in[0]) { -+ case '?': -+ puts(help); -+ break; -+ case 'p': -+ prompt = 1; -+ break; -+ case 'q': -+ done = 1; -+ break; -+ case 'a': -+ if (tokenize(in+1, &tok1, &tok2, (char **) 0) != 2) { -+ puts("what?"); -+ break; -+ } -+ key = dupstring(tok1); -+ val = dupstring(tok2); -+ dn = dnode_create(val); -+ -+ if (!key || !val || !dn) { -+ puts("out of memory"); -+ free((void *) key); -+ free(val); -+ if (dn) -+ dnode_destroy(dn); -+ } -+ -+ dict_load_next(&dl, dn, key); -+ break; -+ default: -+ putchar('?'); -+ putchar('\n'); -+ break; -+ } -+ } -+ -+ dict_load_end(&dl); -+} -+ -+int main(void) -+{ -+ input_t in; -+ dict_t darray[10]; -+ dict_t *d = &darray[0]; -+ dnode_t *dn; -+ int i; -+ char *tok1, *tok2, *val; -+ const char *key; -+ -+ char *help = -+ "a add value to dictionary\n" -+ "d delete value from dictionary\n" -+ "l lookup value in dictionary\n" -+ "( lookup lower bound\n" -+ ") lookup upper bound\n" -+ "# switch to alternate dictionary (0-9)\n" -+ "j merge two dictionaries\n" -+ "f free the whole dictionary\n" -+ "k allow duplicate keys\n" -+ "c show number of entries\n" -+ "t dump whole dictionary in sort order\n" -+ "m make dictionary out of sorted items\n" -+ "p turn prompt on\n" -+ "s switch to non-functioning allocator\n" -+ "q quit"; -+ -+ for (i = 0; i < sizeof darray / sizeof *darray; i++) -+ dict_init(&darray[i], DICTCOUNT_T_MAX, comparef); -+ -+ for (;;) { -+ if (prompt) -+ putchar('>'); -+ fflush(stdout); -+ -+ if (!fgets(in, sizeof(input_t), stdin)) -+ break; -+ -+ switch(in[0]) { -+ case '?': -+ puts(help); -+ break; -+ case 'a': -+ if (tokenize(in+1, &tok1, &tok2, (char **) 0) != 2) { -+ puts("what?"); -+ break; -+ } -+ key = dupstring(tok1); -+ val = dupstring(tok2); -+ -+ if (!key || !val) { -+ puts("out of memory"); -+ free((void *) key); -+ free(val); -+ } -+ -+ if (!dict_alloc_insert(d, key, val)) { -+ puts("dict_alloc_insert failed"); -+ free((void *) key); -+ free(val); -+ break; -+ } -+ break; -+ case 'd': -+ if (tokenize(in+1, &tok1, (char **) 0) != 1) { -+ puts("what?"); -+ break; -+ } -+ dn = dict_lookup(d, tok1); -+ if (!dn) { -+ puts("dict_lookup failed"); -+ break; -+ } -+ val = dnode_get(dn); -+ key = dnode_getkey(dn); -+ dict_delete_free(d, dn); -+ -+ free(val); -+ free((void *) key); -+ break; -+ case 'f': -+ dict_free(d); -+ break; -+ case 'l': -+ case '(': -+ case ')': -+ if (tokenize(in+1, &tok1, (char **) 0) != 1) { -+ puts("what?"); -+ break; -+ } -+ dn = 0; -+ switch (in[0]) { -+ case 'l': -+ dn = dict_lookup(d, tok1); -+ break; -+ case '(': -+ dn = dict_lower_bound(d, tok1); -+ break; -+ case ')': -+ dn = dict_upper_bound(d, tok1); -+ break; -+ } -+ if (!dn) { -+ puts("lookup failed"); -+ break; -+ } -+ val = dnode_get(dn); -+ puts(val); -+ break; -+ case 'm': -+ construct(d); -+ break; -+ case 'k': -+ dict_allow_dupes(d); -+ break; -+ case 'c': -+ printf("%lu\n", (unsigned long) dict_count(d)); -+ break; -+ case 't': -+ for (dn = dict_first(d); dn; dn = dict_next(d, dn)) { -+ printf("%s\t%s\n", (char *) dnode_getkey(dn), -+ (char *) dnode_get(dn)); -+ } -+ break; -+ case 'q': -+ exit(0); -+ break; -+ case '\0': -+ break; -+ case 'p': -+ prompt = 1; -+ break; -+ case 's': -+ dict_set_allocator(d, new_node, del_node, NULL); -+ break; -+ case '#': -+ if (tokenize(in+1, &tok1, (char **) 0) != 1) { -+ puts("what?"); -+ break; -+ } else { -+ int dictnum = atoi(tok1); -+ if (dictnum < 0 || dictnum > 9) { -+ puts("invalid number"); -+ break; -+ } -+ d = &darray[dictnum]; -+ } -+ break; -+ case 'j': -+ if (tokenize(in+1, &tok1, &tok2, (char **) 0) != 2) { -+ puts("what?"); -+ break; -+ } else { -+ int dict1 = atoi(tok1), dict2 = atoi(tok2); -+ if (dict1 < 0 || dict1 > 9 || dict2 < 0 || dict2 > 9) { -+ puts("invalid number"); -+ break; -+ } -+ dict_merge(&darray[dict1], &darray[dict2]); -+ } -+ break; -+ default: -+ putchar('?'); -+ putchar('\n'); -+ break; -+ } -+ } -+ -+ return 0; -+} -+ -+#endif -diff --git a/lib/support/dict.h b/lib/support/dict.h -new file mode 100644 -index 0000000..838079d ---- /dev/null -+++ b/lib/support/dict.h -@@ -0,0 +1,144 @@ -+/* -+ * Dictionary Abstract Data Type -+ * Copyright (C) 1997 Kaz Kylheku -+ * -+ * Free Software License: -+ * -+ * All rights are reserved by the author, with the following exceptions: -+ * Permission is granted to freely reproduce and distribute this software, -+ * possibly in exchange for a fee, provided that this copyright notice appears -+ * intact. Permission is also granted to adapt this software to produce -+ * derivative works, as long as the modified versions carry this copyright -+ * notice and additional notices stating that the work has been modified. -+ * This source code may be translated into executable form and incorporated -+ * into proprietary software; there is no requirement for such software to -+ * contain a copyright notice related to this source. -+ * -+ * $Id: dict.h,v 1.22.2.6 2000/11/13 01:36:44 kaz Exp $ -+ * $Name: kazlib_1_20 $ -+ */ -+ -+#ifndef DICT_H -+#define DICT_H -+ -+#include -+#ifdef KAZLIB_SIDEEFFECT_DEBUG -+#include "sfx.h" -+#endif -+ -+/* -+ * Blurb for inclusion into C++ translation units -+ */ -+ -+#ifdef __cplusplus -+extern "C" { -+#endif -+ -+typedef unsigned long dictcount_t; -+#define DICTCOUNT_T_MAX ULONG_MAX -+ -+/* -+ * The dictionary is implemented as a red-black tree -+ */ -+ -+typedef enum { dnode_red, dnode_black } dnode_color_t; -+ -+typedef struct dnode_t { -+#if defined(DICT_IMPLEMENTATION) || !defined(KAZLIB_OPAQUE_DEBUG) -+ struct dnode_t *dict_left; -+ struct dnode_t *dict_right; -+ struct dnode_t *dict_parent; -+ dnode_color_t dict_color; -+ const void *dict_key; -+ void *dict_data; -+#else -+ int dict_dummy; -+#endif -+} dnode_t; -+ -+typedef int (*dict_comp_t)(const void *, const void *); -+typedef dnode_t *(*dnode_alloc_t)(void *); -+typedef void (*dnode_free_t)(dnode_t *, void *); -+ -+typedef struct dict_t { -+#if defined(DICT_IMPLEMENTATION) || !defined(KAZLIB_OPAQUE_DEBUG) -+ dnode_t dict_nilnode; -+ dictcount_t dict_nodecount; -+ dictcount_t dict_maxcount; -+ dict_comp_t dict_compare; -+ dnode_alloc_t dict_allocnode; -+ dnode_free_t dict_freenode; -+ void *dict_context; -+ int dict_dupes; -+#else -+ int dict_dummmy; -+#endif -+} dict_t; -+ -+typedef void (*dnode_process_t)(dict_t *, dnode_t *, void *); -+ -+typedef struct dict_load_t { -+#if defined(DICT_IMPLEMENTATION) || !defined(KAZLIB_OPAQUE_DEBUG) -+ dict_t *dict_dictptr; -+ dnode_t dict_nilnode; -+#else -+ int dict_dummmy; -+#endif -+} dict_load_t; -+ -+extern dict_t *dict_create(dictcount_t, dict_comp_t); -+extern void dict_set_allocator(dict_t *, dnode_alloc_t, dnode_free_t, void *); -+extern void dict_destroy(dict_t *); -+extern void dict_free_nodes(dict_t *); -+extern void dict_free(dict_t *); -+extern dict_t *dict_init(dict_t *, dictcount_t, dict_comp_t); -+extern void dict_init_like(dict_t *, const dict_t *); -+extern int dict_verify(dict_t *); -+extern int dict_similar(const dict_t *, const dict_t *); -+extern dnode_t *dict_lookup(dict_t *, const void *); -+extern dnode_t *dict_lower_bound(dict_t *, const void *); -+extern dnode_t *dict_upper_bound(dict_t *, const void *); -+extern void dict_insert(dict_t *, dnode_t *, const void *); -+extern dnode_t *dict_delete(dict_t *, dnode_t *); -+extern int dict_alloc_insert(dict_t *, const void *, void *); -+extern void dict_delete_free(dict_t *, dnode_t *); -+extern dnode_t *dict_first(dict_t *); -+extern dnode_t *dict_last(dict_t *); -+extern dnode_t *dict_next(dict_t *, dnode_t *); -+extern dnode_t *dict_prev(dict_t *, dnode_t *); -+extern dictcount_t dict_count(dict_t *); -+extern int dict_isempty(dict_t *); -+extern int dict_isfull(dict_t *); -+extern int dict_contains(dict_t *, dnode_t *); -+extern void dict_allow_dupes(dict_t *); -+extern int dnode_is_in_a_dict(dnode_t *); -+extern dnode_t *dnode_create(void *); -+extern dnode_t *dnode_init(dnode_t *, void *); -+extern void dnode_destroy(dnode_t *); -+extern void *dnode_get(dnode_t *); -+extern const void *dnode_getkey(dnode_t *); -+extern void dnode_put(dnode_t *, void *); -+extern void dict_process(dict_t *, void *, dnode_process_t); -+extern void dict_load_begin(dict_load_t *, dict_t *); -+extern void dict_load_next(dict_load_t *, dnode_t *, const void *); -+extern void dict_load_end(dict_load_t *); -+extern void dict_merge(dict_t *, dict_t *); -+ -+#if defined(DICT_IMPLEMENTATION) || !defined(KAZLIB_OPAQUE_DEBUG) -+#ifdef KAZLIB_SIDEEFFECT_DEBUG -+#define dict_isfull(D) (SFX_CHECK(D)->dict_nodecount == (D)->dict_maxcount) -+#else -+#define dict_isfull(D) ((D)->dict_nodecount == (D)->dict_maxcount) -+#endif -+#define dict_count(D) ((D)->dict_nodecount) -+#define dict_isempty(D) ((D)->dict_nodecount == 0) -+#define dnode_get(N) ((N)->dict_data) -+#define dnode_getkey(N) ((N)->dict_key) -+#define dnode_put(N, X) ((N)->dict_data = (X)) -+#endif -+ -+#ifdef __cplusplus -+} -+#endif -+ -+#endif -diff --git a/lib/support/dqblk_v2.h b/lib/support/dqblk_v2.h -new file mode 100644 -index 0000000..d12512a ---- /dev/null -+++ b/lib/support/dqblk_v2.h -@@ -0,0 +1,31 @@ -+/* -+ * Header file for disk format of new quotafile format -+ * -+ * Jan Kara - sponsored by SuSE CR -+ */ -+ -+#ifndef __QUOTA_DQBLK_V2_H__ -+#define __QUOTA_DQBLK_V2_H__ -+ -+#include "quotaio_tree.h" -+ -+/* Structure for format specific information */ -+struct v2_mem_dqinfo { -+ struct qtree_mem_dqinfo dqi_qtree; -+ unsigned int dqi_flags; /* Flags set in quotafile */ -+ unsigned int dqi_used_entries; /* Number of entries in file - -+ updated by scan_dquots */ -+ unsigned int dqi_data_blocks; /* Number of data blocks in file - -+ updated by scan_dquots */ -+}; -+ -+struct v2_mem_dqblk { -+ long long dqb_off; /* Offset of dquot in file */ -+}; -+ -+struct quotafile_ops; /* Will be defined later in quotaio.h */ -+ -+/* Operations above this format */ -+extern struct quotafile_ops quotafile_ops_2; -+ -+#endif /* __QUOTA_DQBLK_V2_H__ */ -diff --git a/lib/support/mkquota.c b/lib/support/mkquota.c -new file mode 100644 -index 0000000..00e96f8 ---- /dev/null -+++ b/lib/support/mkquota.c -@@ -0,0 +1,634 @@ -+/* -+ * mkquota.c --- create quota files for a filesystem -+ * -+ * Aditya Kali -+ */ -+#include "config.h" -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "ext2fs/ext2_fs.h" -+#include "ext2fs/ext2fs.h" -+#include "e2p/e2p.h" -+ -+#include "quotaio.h" -+#include "quotaio_v2.h" -+#include "quotaio_tree.h" -+#include "common.h" -+#include "dict.h" -+ -+/* Needed for architectures where sizeof(int) != sizeof(void *) */ -+#define UINT_TO_VOIDPTR(val) ((void *)(intptr_t)(val)) -+#define VOIDPTR_TO_UINT(ptr) ((unsigned int)(intptr_t)(ptr)) -+ -+#if DEBUG_QUOTA -+static void print_inode(struct ext2_inode *inode) -+{ -+ if (!inode) -+ return; -+ -+ fprintf(stderr, " i_mode = %d\n", inode->i_mode); -+ fprintf(stderr, " i_uid = %d\n", inode->i_uid); -+ fprintf(stderr, " i_size = %d\n", inode->i_size); -+ fprintf(stderr, " i_atime = %d\n", inode->i_atime); -+ fprintf(stderr, " i_ctime = %d\n", inode->i_ctime); -+ fprintf(stderr, " i_mtime = %d\n", inode->i_mtime); -+ fprintf(stderr, " i_dtime = %d\n", inode->i_dtime); -+ fprintf(stderr, " i_gid = %d\n", inode->i_gid); -+ fprintf(stderr, " i_links_count = %d\n", inode->i_links_count); -+ fprintf(stderr, " i_blocks = %d\n", inode->i_blocks); -+ fprintf(stderr, " i_flags = %d\n", inode->i_flags); -+ -+ return; -+} -+ -+static void print_dquot(const char *desc, struct dquot *dq) -+{ -+ if (desc) -+ fprintf(stderr, "%s: ", desc); -+ fprintf(stderr, "%u %lld:%lld:%lld %lld:%lld:%lld\n", -+ dq->dq_id, dq->dq_dqb.dqb_curspace, -+ dq->dq_dqb.dqb_bsoftlimit, dq->dq_dqb.dqb_bhardlimit, -+ dq->dq_dqb.dqb_curinodes, -+ dq->dq_dqb.dqb_isoftlimit, dq->dq_dqb.dqb_ihardlimit); -+} -+#else -+static void print_dquot(const char *desc EXT2FS_ATTR((unused)), -+ struct dquot *dq EXT2FS_ATTR((unused))) -+{ -+} -+#endif -+ -+/* -+ * Returns 0 if not able to find the quota file, otherwise returns its -+ * inode number. -+ */ -+int quota_file_exists(ext2_filsys fs, int qtype) -+{ -+ char qf_name[256]; -+ errcode_t ret; -+ ext2_ino_t ino; -+ -+ if (qtype >= MAXQUOTAS) -+ return -EINVAL; -+ -+ quota_get_qf_name(qtype, QFMT_VFS_V1, qf_name); -+ -+ ret = ext2fs_lookup(fs, EXT2_ROOT_INO, qf_name, strlen(qf_name), 0, -+ &ino); -+ if (ret) -+ return 0; -+ -+ return ino; -+} -+ -+/* -+ * Set the value for reserved quota inode number field in superblock. -+ */ -+void quota_set_sb_inum(ext2_filsys fs, ext2_ino_t ino, int qtype) -+{ -+ ext2_ino_t *inump; -+ -+ inump = (qtype == USRQUOTA) ? &fs->super->s_usr_quota_inum : -+ &fs->super->s_grp_quota_inum; -+ -+ log_debug("setting quota ino in superblock: ino=%u, type=%d", ino, -+ qtype); -+ *inump = ino; -+ ext2fs_mark_super_dirty(fs); -+} -+ -+errcode_t quota_remove_inode(ext2_filsys fs, int qtype) -+{ -+ ext2_ino_t qf_ino; -+ errcode_t retval; -+ -+ retval = ext2fs_read_bitmaps(fs); -+ if (retval) { -+ log_err("Couldn't read bitmaps: %s", error_message(retval)); -+ return retval; -+ } -+ qf_ino = (qtype == USRQUOTA) ? fs->super->s_usr_quota_inum : -+ fs->super->s_grp_quota_inum; -+ quota_set_sb_inum(fs, 0, qtype); -+ /* Truncate the inode only if its a reserved one. */ -+ if (qf_ino < EXT2_FIRST_INODE(fs->super)) -+ quota_inode_truncate(fs, qf_ino); -+ -+ ext2fs_mark_super_dirty(fs); -+ fs->flags &= ~EXT2_FLAG_SUPER_ONLY; -+ retval = ext2fs_write_bitmaps(fs); -+ if (retval) { -+ log_err("Couldn't write bitmaps: %s", error_message(retval)); -+ return retval; -+ } -+ return 0; -+} -+ -+static void write_dquots(dict_t *dict, struct quota_handle *qh) -+{ -+ dnode_t *n; -+ struct dquot *dq; -+ -+ for (n = dict_first(dict); n; n = dict_next(dict, n)) { -+ dq = dnode_get(n); -+ if (dq) { -+ print_dquot("write", dq); -+ dq->dq_h = qh; -+ update_grace_times(dq); -+ qh->qh_ops->commit_dquot(dq); -+ } -+ } -+} -+ -+errcode_t quota_write_inode(quota_ctx_t qctx, int qtype) -+{ -+ int retval = 0, i; -+ dict_t *dict; -+ ext2_filsys fs; -+ struct quota_handle *h = NULL; -+ int fmt = QFMT_VFS_V1; -+ -+ if (!qctx) -+ return 0; -+ -+ fs = qctx->fs; -+ retval = ext2fs_get_mem(sizeof(struct quota_handle), &h); -+ if (retval) { -+ log_err("Unable to allocate quota handle: %s", -+ error_message(retval)); -+ goto out; -+ } -+ -+ retval = ext2fs_read_bitmaps(fs); -+ if (retval) { -+ log_err("Couldn't read bitmaps: %s", error_message(retval)); -+ goto out; -+ } -+ -+ for (i = 0; i < MAXQUOTAS; i++) { -+ if ((qtype != -1) && (i != qtype)) -+ continue; -+ -+ dict = qctx->quota_dict[i]; -+ if (!dict) -+ continue; -+ -+ retval = quota_file_create(h, fs, i, fmt); -+ if (retval < 0) { -+ log_err("Cannot initialize io on quotafile"); -+ continue; -+ } -+ -+ write_dquots(dict, h); -+ retval = quota_file_close(qctx, h); -+ if (retval < 0) { -+ log_err("Cannot finish IO on new quotafile: %s", -+ strerror(errno)); -+ if (h->qh_qf.e2_file) -+ ext2fs_file_close(h->qh_qf.e2_file); -+ quota_inode_truncate(fs, h->qh_qf.ino); -+ continue; -+ } -+ -+ /* Set quota inode numbers in superblock. */ -+ quota_set_sb_inum(fs, h->qh_qf.ino, i); -+ ext2fs_mark_super_dirty(fs); -+ ext2fs_mark_bb_dirty(fs); -+ fs->flags &= ~EXT2_FLAG_SUPER_ONLY; -+ } -+ -+ retval = ext2fs_write_bitmaps(fs); -+ if (retval) { -+ log_err("Couldn't write bitmaps: %s", error_message(retval)); -+ goto out; -+ } -+out: -+ if (h) -+ ext2fs_free_mem(&h); -+ return retval; -+} -+ -+/******************************************************************/ -+/* Helper functions for computing quota in memory. */ -+/******************************************************************/ -+ -+static int dict_uint_cmp(const void *a, const void *b) -+{ -+ unsigned int c, d; -+ -+ c = VOIDPTR_TO_UINT(a); -+ d = VOIDPTR_TO_UINT(b); -+ -+ if (c == d) -+ return 0; -+ else if (c > d) -+ return 1; -+ else -+ return -1; -+} -+ -+static inline qid_t get_qid(struct ext2_inode *inode, int qtype) -+{ -+ if (qtype == USRQUOTA) -+ return inode_uid(*inode); -+ return inode_gid(*inode); -+} -+ -+static void quota_dnode_free(dnode_t *node, -+ void *context EXT2FS_ATTR((unused))) -+{ -+ void *ptr = node ? dnode_get(node) : 0; -+ -+ ext2fs_free_mem(&ptr); -+ free(node); -+} -+ -+/* -+ * Set up the quota tracking data structures. -+ */ -+errcode_t quota_init_context(quota_ctx_t *qctx, ext2_filsys fs, int qtype) -+{ -+ errcode_t err; -+ dict_t *dict; -+ quota_ctx_t ctx; -+ int i; -+ -+ err = ext2fs_get_mem(sizeof(struct quota_ctx), &ctx); -+ if (err) { -+ log_err("Failed to allocate quota context"); -+ return err; -+ } -+ -+ memset(ctx, 0, sizeof(struct quota_ctx)); -+ for (i = 0; i < MAXQUOTAS; i++) { -+ ctx->quota_file[i] = NULL; -+ if ((qtype != -1) && (i != qtype)) -+ continue; -+ err = ext2fs_get_mem(sizeof(dict_t), &dict); -+ if (err) { -+ log_err("Failed to allocate dictionary"); -+ quota_release_context(&ctx); -+ return err; -+ } -+ ctx->quota_dict[i] = dict; -+ dict_init(dict, DICTCOUNT_T_MAX, dict_uint_cmp); -+ dict_set_allocator(dict, NULL, quota_dnode_free, NULL); -+ } -+ -+ ctx->fs = fs; -+ *qctx = ctx; -+ return 0; -+} -+ -+void quota_release_context(quota_ctx_t *qctx) -+{ -+ errcode_t err; -+ dict_t *dict; -+ int i; -+ quota_ctx_t ctx; -+ -+ if (!qctx) -+ return; -+ -+ ctx = *qctx; -+ for (i = 0; i < MAXQUOTAS; i++) { -+ dict = ctx->quota_dict[i]; -+ ctx->quota_dict[i] = 0; -+ if (dict) { -+ dict_free_nodes(dict); -+ free(dict); -+ } -+ if (ctx->quota_file[i]) { -+ err = quota_file_close(ctx, ctx->quota_file[i]); -+ if (err) { -+ log_err("Cannot close quotafile: %s", -+ strerror(errno)); -+ ext2fs_free_mem(&ctx->quota_file[i]); -+ } -+ } -+ } -+ *qctx = NULL; -+ free(ctx); -+} -+ -+static struct dquot *get_dq(dict_t *dict, __u32 key) -+{ -+ struct dquot *dq; -+ dnode_t *n; -+ -+ n = dict_lookup(dict, UINT_TO_VOIDPTR(key)); -+ if (n) -+ dq = dnode_get(n); -+ else { -+ if (ext2fs_get_mem(sizeof(struct dquot), &dq)) { -+ log_err("Unable to allocate dquot"); -+ return NULL; -+ } -+ memset(dq, 0, sizeof(struct dquot)); -+ dict_alloc_insert(dict, UINT_TO_VOIDPTR(key), dq); -+ dq->dq_id = key; -+ } -+ return dq; -+} -+ -+ -+/* -+ * Called to update the blocks used by a particular inode -+ */ -+void quota_data_add(quota_ctx_t qctx, struct ext2_inode *inode, -+ ext2_ino_t ino EXT2FS_ATTR((unused)), -+ qsize_t space) -+{ -+ struct dquot *dq; -+ dict_t *dict; -+ int i; -+ -+ if (!qctx) -+ return; -+ -+ log_debug("ADD_DATA: Inode: %u, UID/GID: %u/%u, space: %ld", ino, -+ inode_uid(*inode), -+ inode_gid(*inode), space); -+ for (i = 0; i < MAXQUOTAS; i++) { -+ dict = qctx->quota_dict[i]; -+ if (dict) { -+ dq = get_dq(dict, get_qid(inode, i)); -+ if (dq) -+ dq->dq_dqb.dqb_curspace += space; -+ } -+ } -+} -+ -+/* -+ * Called to remove some blocks used by a particular inode -+ */ -+void quota_data_sub(quota_ctx_t qctx, struct ext2_inode *inode, -+ ext2_ino_t ino EXT2FS_ATTR((unused)), -+ qsize_t space) -+{ -+ struct dquot *dq; -+ dict_t *dict; -+ int i; -+ -+ if (!qctx) -+ return; -+ -+ log_debug("SUB_DATA: Inode: %u, UID/GID: %u/%u, space: %ld", ino, -+ inode_uid(*inode), -+ inode_gid(*inode), space); -+ for (i = 0; i < MAXQUOTAS; i++) { -+ dict = qctx->quota_dict[i]; -+ if (dict) { -+ dq = get_dq(dict, get_qid(inode, i)); -+ dq->dq_dqb.dqb_curspace -= space; -+ } -+ } -+} -+ -+/* -+ * Called to count the files used by an inode's user/group -+ */ -+void quota_data_inodes(quota_ctx_t qctx, struct ext2_inode *inode, -+ ext2_ino_t ino EXT2FS_ATTR((unused)), int adjust) -+{ -+ struct dquot *dq; -+ dict_t *dict; -+ int i; -+ -+ if (!qctx) -+ return; -+ -+ log_debug("ADJ_INODE: Inode: %u, UID/GID: %u/%u, adjust: %d", ino, -+ inode_uid(*inode), -+ inode_gid(*inode), adjust); -+ for (i = 0; i < MAXQUOTAS; i++) { -+ dict = qctx->quota_dict[i]; -+ if (dict) { -+ dq = get_dq(dict, get_qid(inode, i)); -+ dq->dq_dqb.dqb_curinodes += adjust; -+ } -+ } -+} -+ -+errcode_t quota_compute_usage(quota_ctx_t qctx) -+{ -+ ext2_filsys fs; -+ ext2_ino_t ino; -+ errcode_t ret; -+ struct ext2_inode inode; -+ qsize_t space; -+ ext2_inode_scan scan; -+ -+ if (!qctx) -+ return 0; -+ -+ fs = qctx->fs; -+ ret = ext2fs_open_inode_scan(fs, 0, &scan); -+ if (ret) { -+ log_err("while opening inode scan. ret=%ld", ret); -+ return ret; -+ } -+ -+ while (1) { -+ ret = ext2fs_get_next_inode(scan, &ino, &inode); -+ if (ret) { -+ log_err("while getting next inode. ret=%ld", ret); -+ ext2fs_close_inode_scan(scan); -+ return ret; -+ } -+ if (ino == 0) -+ break; -+ if (inode.i_links_count && -+ (ino == EXT2_ROOT_INO || -+ ino >= EXT2_FIRST_INODE(fs->super))) { -+ space = ext2fs_inode_i_blocks(fs, &inode) << 9; -+ quota_data_add(qctx, &inode, ino, space); -+ quota_data_inodes(qctx, &inode, ino, +1); -+ } -+ } -+ -+ ext2fs_close_inode_scan(scan); -+ -+ return 0; -+} -+ -+struct scan_dquots_data { -+ dict_t *quota_dict; -+ int update_limits; /* update limits from disk */ -+ int update_usage; -+ int usage_is_inconsistent; -+}; -+ -+static int scan_dquots_callback(struct dquot *dquot, void *cb_data) -+{ -+ struct scan_dquots_data *scan_data = cb_data; -+ dict_t *quota_dict = scan_data->quota_dict; -+ struct dquot *dq; -+ -+ dq = get_dq(quota_dict, dquot->dq_id); -+ dq->dq_id = dquot->dq_id; -+ dq->dq_flags |= DQF_SEEN; -+ -+ print_dquot("mem", dq); -+ print_dquot("dsk", dquot); -+ -+ /* Check if there is inconsistancy. */ -+ if (dq->dq_dqb.dqb_curspace != dquot->dq_dqb.dqb_curspace || -+ dq->dq_dqb.dqb_curinodes != dquot->dq_dqb.dqb_curinodes) { -+ scan_data->usage_is_inconsistent = 1; -+ fprintf(stderr, "[QUOTA WARNING] Usage inconsistent for ID %d:" -+ "actual (%llu, %llu) != expected (%llu, %llu)\n", -+ dq->dq_id, (long long)dq->dq_dqb.dqb_curspace, -+ (long long)dq->dq_dqb.dqb_curinodes, -+ (long long)dquot->dq_dqb.dqb_curspace, -+ (long long)dquot->dq_dqb.dqb_curinodes); -+ } -+ -+ if (scan_data->update_limits) { -+ dq->dq_dqb.dqb_ihardlimit = dquot->dq_dqb.dqb_ihardlimit; -+ dq->dq_dqb.dqb_isoftlimit = dquot->dq_dqb.dqb_isoftlimit; -+ dq->dq_dqb.dqb_bhardlimit = dquot->dq_dqb.dqb_bhardlimit; -+ dq->dq_dqb.dqb_bsoftlimit = dquot->dq_dqb.dqb_bsoftlimit; -+ } -+ -+ if (scan_data->update_usage) { -+ dq->dq_dqb.dqb_curspace = dquot->dq_dqb.dqb_curspace; -+ dq->dq_dqb.dqb_curinodes = dquot->dq_dqb.dqb_curinodes; -+ } -+ -+ return 0; -+} -+ -+/* -+ * Read all dquots from quota file into memory -+ */ -+static errcode_t quota_read_all_dquots(struct quota_handle *qh, -+ quota_ctx_t qctx, int update_limits) -+{ -+ struct scan_dquots_data scan_data; -+ -+ scan_data.quota_dict = qctx->quota_dict[qh->qh_type]; -+ scan_data.update_limits = update_limits; -+ scan_data.update_usage = 0; -+ -+ return qh->qh_ops->scan_dquots(qh, scan_dquots_callback, &scan_data); -+} -+ -+/* -+ * Write all memory dquots into quota file -+ */ -+#if 0 /* currently unused, but may be useful in the future? */ -+static errcode_t quota_write_all_dquots(struct quota_handle *qh, -+ quota_ctx_t qctx) -+{ -+ errcode_t err; -+ -+ err = ext2fs_read_bitmaps(qctx->fs); -+ if (err) -+ return err; -+ write_dquots(qctx->quota_dict[qh->qh_type], qh); -+ ext2fs_mark_bb_dirty(qctx->fs); -+ qctx->fs->flags &= ~EXT2_FLAG_SUPER_ONLY; -+ ext2fs_write_bitmaps(qctx->fs); -+ return 0; -+} -+#endif -+ -+/* -+ * Updates the in-memory quota limits from the given quota inode. -+ */ -+errcode_t quota_update_limits(quota_ctx_t qctx, ext2_ino_t qf_ino, int type) -+{ -+ struct quota_handle *qh; -+ errcode_t err; -+ -+ if (!qctx) -+ return 0; -+ -+ err = ext2fs_get_mem(sizeof(struct quota_handle), &qh); -+ if (err) { -+ log_err("Unable to allocate quota handle"); -+ return err; -+ } -+ -+ err = quota_file_open(qctx, qh, qf_ino, type, -1, 0); -+ if (err) { -+ log_err("Open quota file failed"); -+ goto out; -+ } -+ -+ quota_read_all_dquots(qh, qctx, 1); -+ -+ err = quota_file_close(qctx, qh); -+ if (err) { -+ log_err("Cannot finish IO on new quotafile: %s", -+ strerror(errno)); -+ if (qh->qh_qf.e2_file) -+ ext2fs_file_close(qh->qh_qf.e2_file); -+ } -+out: -+ ext2fs_free_mem(&qh); -+ return err; -+} -+ -+/* -+ * Compares the measured quota in qctx->quota_dict with that in the quota inode -+ * on disk and updates the limits in qctx->quota_dict. 'usage_inconsistent' is -+ * set to 1 if the supplied and on-disk quota usage values are not identical. -+ */ -+errcode_t quota_compare_and_update(quota_ctx_t qctx, int qtype, -+ int *usage_inconsistent) -+{ -+ struct quota_handle qh; -+ struct scan_dquots_data scan_data; -+ struct dquot *dq; -+ dnode_t *n; -+ dict_t *dict = qctx->quota_dict[qtype]; -+ errcode_t err = 0; -+ -+ if (!dict) -+ goto out; -+ -+ err = quota_file_open(qctx, &qh, 0, qtype, -1, 0); -+ if (err) { -+ log_err("Open quota file failed"); -+ goto out; -+ } -+ -+ scan_data.quota_dict = qctx->quota_dict[qtype]; -+ scan_data.update_limits = 1; -+ scan_data.update_usage = 0; -+ scan_data.usage_is_inconsistent = 0; -+ err = qh.qh_ops->scan_dquots(&qh, scan_dquots_callback, &scan_data); -+ if (err) { -+ log_err("Error scanning dquots"); -+ goto out_close_qh; -+ } -+ -+ for (n = dict_first(dict); n; n = dict_next(dict, n)) { -+ dq = dnode_get(n); -+ if (!dq) -+ continue; -+ if ((dq->dq_flags & DQF_SEEN) == 0) { -+ fprintf(stderr, "[QUOTA WARNING] " -+ "Missing quota entry ID %d\n", dq->dq_id); -+ scan_data.usage_is_inconsistent = 1; -+ } -+ } -+ *usage_inconsistent = scan_data.usage_is_inconsistent; -+ -+out_close_qh: -+ err = quota_file_close(qctx, &qh); -+ if (err) { -+ log_err("Cannot close quotafile: %s", error_message(errno)); -+ if (qh.qh_qf.e2_file) -+ ext2fs_file_close(qh.qh_qf.e2_file); -+ } -+out: -+ return err; -+} -diff --git a/lib/support/nls-enable.h b/lib/support/nls-enable.h -new file mode 100644 -index 0000000..2f62c01 ---- /dev/null -+++ b/lib/support/nls-enable.h -@@ -0,0 +1,21 @@ -+#if defined(ENABLE_NLS) && !defined(DEBUGFS) -+#include -+#include -+#define _(a) (gettext (a)) -+#ifdef gettext_noop -+#define N_(a) gettext_noop (a) -+#else -+#define N_(a) (a) -+#endif -+#define P_(singular, plural, n) (ngettext (singular, plural, n)) -+#ifndef NLS_CAT_NAME -+#define NLS_CAT_NAME "e2fsprogs" -+#endif -+#ifndef LOCALEDIR -+#define LOCALEDIR "/usr/share/locale" -+#endif -+#else -+#define _(a) (a) -+#define N_(a) a -+#define P_(singular, plural, n) ((n) == 1 ? (singular) : (plural)) -+#endif -diff --git a/lib/support/plausible.c b/lib/support/plausible.c -new file mode 100644 -index 0000000..0a029e2 ---- /dev/null -+++ b/lib/support/plausible.c -@@ -0,0 +1,274 @@ -+/* -+ * plausible.c --- Figure out if a pathname is ext* or something else. -+ * -+ * Copyright 2014, Oracle, Inc. -+ * -+ * Some parts are: -+ * Copyright 1995, 1996, 1997, 1998, 1999, 2000 by Theodore Ts'o. -+ * -+ * %Begin-Header% -+ * This file may be redistributed under the terms of the GNU Public -+ * License. -+ * %End-Header% -+ */ -+ -+#ifndef _LARGEFILE_SOURCE -+#define _LARGEFILE_SOURCE -+#endif -+#ifndef _LARGEFILE64_SOURCE -+#define _LARGEFILE64_SOURCE -+#endif -+ -+#include "config.h" -+#include -+#include -+#include -+#ifdef HAVE_SYS_STAT_H -+#include -+#endif -+#ifdef HAVE_UNISTD_H -+#include -+#endif -+#ifdef HAVE_MAGIC_H -+#include -+#endif -+#include "plausible.h" -+#include "ext2fs/ext2fs.h" -+#include "nls-enable.h" -+#include "blkid/blkid.h" -+ -+#ifdef HAVE_MAGIC_H -+static magic_t (*dl_magic_open)(int); -+static const char *(*dl_magic_file)(magic_t, const char *); -+static int (*dl_magic_load)(magic_t, const char *); -+static void (*dl_magic_close)(magic_t); -+ -+#ifdef HAVE_DLOPEN -+#include -+ -+static void *magic_handle; -+ -+static int magic_library_available(void) -+{ -+ if (!magic_handle) { -+ magic_handle = dlopen("libmagic.so.1", RTLD_NOW); -+ if (!magic_handle) -+ return 0; -+ -+ dl_magic_open = dlsym(magic_handle, "magic_open"); -+ dl_magic_file = dlsym(magic_handle, "magic_file"); -+ dl_magic_load = dlsym(magic_handle, "magic_load"); -+ dl_magic_close = dlsym(magic_handle, "magic_close"); -+ } -+ -+ if (!dl_magic_open || !dl_magic_file || -+ !dl_magic_load || !dl_magic_close) -+ return 0; -+ return 1; -+} -+#else -+static int magic_library_available(void) -+{ -+ dl_magic_open = magic_open; -+ dl_magic_file = magic_file; -+ dl_magic_load = magic_load; -+ dl_magic_close = magic_close; -+ -+ return 1; -+} -+#endif -+#endif -+ -+static void print_ext2_info(const char *device) -+ -+{ -+ struct ext2_super_block *sb; -+ ext2_filsys fs; -+ errcode_t retval; -+ time_t tm; -+ char buf[80]; -+ -+ retval = ext2fs_open2(device, 0, EXT2_FLAG_64BITS, 0, 0, -+ unix_io_manager, &fs); -+ if (retval) -+ return; -+ sb = fs->super; -+ -+ if (sb->s_mtime) { -+ tm = sb->s_mtime; -+ if (sb->s_last_mounted[0]) { -+ memset(buf, 0, sizeof(buf)); -+ strncpy(buf, sb->s_last_mounted, -+ sizeof(sb->s_last_mounted)); -+ printf(_("\tlast mounted on %s on %s"), buf, -+ ctime(&tm)); -+ } else -+ printf(_("\tlast mounted on %s"), ctime(&tm)); -+ } else if (sb->s_mkfs_time) { -+ tm = sb->s_mkfs_time; -+ printf(_("\tcreated on %s"), ctime(&tm)); -+ } else if (sb->s_wtime) { -+ tm = sb->s_wtime; -+ printf(_("\tlast modified on %s"), ctime(&tm)); -+ } -+ ext2fs_close_free(&fs); -+} -+ -+/* -+ * return 1 if there is no partition table, 0 if a partition table is -+ * detected, and -1 on an error. -+ */ -+#ifdef HAVE_BLKID_PROBE_ENABLE_PARTITIONS -+static int check_partition_table(const char *device) -+{ -+ blkid_probe pr; -+ const char *value; -+ int ret; -+ -+ pr = blkid_new_probe_from_filename(device); -+ if (!pr) -+ return -1; -+ -+ ret = blkid_probe_enable_partitions(pr, 1); -+ if (ret < 0) -+ goto errout; -+ -+ ret = blkid_probe_enable_superblocks(pr, 0); -+ if (ret < 0) -+ goto errout; -+ -+ ret = blkid_do_fullprobe(pr); -+ if (ret < 0) -+ goto errout; -+ -+ ret = blkid_probe_lookup_value(pr, "PTTYPE", &value, NULL); -+ if (ret == 0) -+ fprintf(stderr, _("Found a %s partition table in %s\n"), -+ value, device); -+ else -+ ret = 1; -+ -+errout: -+ blkid_free_probe(pr); -+ return ret; -+} -+#else -+static int check_partition_table(const char *device EXT2FS_ATTR((unused))) -+{ -+ return -1; -+} -+#endif -+ -+/* -+ * return 1 if the device looks plausible, creating the file if necessary -+ */ -+int check_plausibility(const char *device, int flags, int *ret_is_dev) -+{ -+ int fd, ret, is_dev = 0; -+ ext2fs_struct_stat s; -+ int fl = O_RDONLY; -+ blkid_cache cache = NULL; -+ char *fs_type = NULL; -+ char *fs_label = NULL; -+ -+ fd = ext2fs_open_file(device, fl, 0666); -+ if ((fd < 0) && (errno == ENOENT) && (flags & NO_SIZE)) { -+ fprintf(stderr, _("The file %s does not exist and no " -+ "size was specified.\n"), device); -+ exit(1); -+ } -+ if ((fd < 0) && (errno == ENOENT) && (flags & CREATE_FILE)) { -+ fl |= O_CREAT; -+ fd = ext2fs_open_file(device, fl, 0666); -+ if (fd >= 0 && (flags & VERBOSE_CREATE)) -+ printf(_("Creating regular file %s\n"), device); -+ } -+ if (fd < 0) { -+ fprintf(stderr, _("Could not open %s: %s\n"), -+ device, error_message(errno)); -+ if (errno == ENOENT) -+ fputs(_("\nThe device apparently does not exist; " -+ "did you specify it correctly?\n"), stderr); -+ exit(1); -+ } -+ -+ if (ext2fs_fstat(fd, &s) < 0) { -+ perror("stat"); -+ exit(1); -+ } -+ close(fd); -+ -+ if (S_ISBLK(s.st_mode)) -+ is_dev = 1; -+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) -+ /* On FreeBSD, all disk devices are character specials */ -+ if (S_ISCHR(s.st_mode)) -+ is_dev = 1; -+#endif -+ if (ret_is_dev) -+ *ret_is_dev = is_dev; -+ -+ if ((flags & CHECK_BLOCK_DEV) && !is_dev) { -+ printf(_("%s is not a block special device.\n"), device); -+ return 0; -+ } -+ -+ /* -+ * Note: we use the older-style blkid API's here because we -+ * want as much functionality to be available when using the -+ * internal blkid library, when e2fsprogs is compiled for -+ * non-Linux systems that will probably not have the libraries -+ * from util-linux available. We only use the newer -+ * blkid-probe interfaces to access functionality not -+ * available in the original blkid library. -+ */ -+ if ((flags & CHECK_FS_EXIST) && blkid_get_cache(&cache, NULL) >= 0) { -+ fs_type = blkid_get_tag_value(cache, "TYPE", device); -+ if (fs_type) -+ fs_label = blkid_get_tag_value(cache, "LABEL", device); -+ blkid_put_cache(cache); -+ } -+ -+ if (fs_type) { -+ if (fs_label) -+ printf(_("%s contains a %s file system " -+ "labelled '%s'\n"), device, fs_type, fs_label); -+ else -+ printf(_("%s contains a %s file system\n"), device, -+ fs_type); -+ if (strncmp(fs_type, "ext", 3) == 0) -+ print_ext2_info(device); -+ free(fs_type); -+ free(fs_label); -+ return 0; -+ } -+ -+#ifdef HAVE_MAGIC_H -+ if ((flags & CHECK_FS_EXIST) && magic_library_available()) { -+ const char *msg; -+ magic_t mag; -+ int has_magic = 0; -+ -+ mag = dl_magic_open(MAGIC_RAW | MAGIC_SYMLINK | MAGIC_DEVICES | -+ MAGIC_ERROR | MAGIC_NO_CHECK_ELF | -+ MAGIC_NO_CHECK_COMPRESS); -+ dl_magic_load(mag, NULL); -+ -+ msg = dl_magic_file(mag, device); -+ if (msg && strcmp(msg, "data") && strcmp(msg, "empty")) { -+ printf(_("%s contains `%s' data\n"), device, msg); -+ has_magic = 1; -+ } -+ -+ dl_magic_close(mag); -+ return !has_magic; -+ } -+#endif -+ -+ ret = check_partition_table(device); -+ if (ret >= 0) -+ return ret; -+ -+ return 1; -+} -+ -diff --git a/lib/support/plausible.h b/lib/support/plausible.h -new file mode 100644 -index 0000000..594e4b1 ---- /dev/null -+++ b/lib/support/plausible.h -@@ -0,0 +1,28 @@ -+/* -+ * plausible.h --- header file defining prototypes for helper functions -+ * used by tune2fs and mke2fs -+ * -+ * Copyright 2014 by Oracle, Inc. -+ * -+ * %Begin-Header% -+ * This file may be redistributed under the terms of the GNU Public -+ * License. -+ * %End-Header% -+ */ -+ -+#ifndef PLAUSIBLE_H_ -+#define PLAUSIBLE_H_ -+ -+/* -+ * Flags for check_plausibility() -+ */ -+#define CHECK_BLOCK_DEV 0x0001 -+#define CREATE_FILE 0x0002 -+#define CHECK_FS_EXIST 0x0004 -+#define VERBOSE_CREATE 0x0008 -+#define NO_SIZE 0x0010 -+ -+extern int check_plausibility(const char *device, int flags, -+ int *ret_is_dev); -+ -+#endif /* PLAUSIBLE_H_ */ -diff --git a/lib/support/prof_err.et b/lib/support/prof_err.et -new file mode 100644 -index 0000000..c9316c7 ---- /dev/null -+++ b/lib/support/prof_err.et -@@ -0,0 +1,66 @@ -+error_table prof -+ -+error_code PROF_VERSION, "Profile version 0.0" -+ -+# -+# generated by prof_tree.c -+# -+error_code PROF_MAGIC_NODE, "Bad magic value in profile_node" -+error_code PROF_NO_SECTION, "Profile section not found" -+error_code PROF_NO_RELATION, "Profile relation not found" -+error_code PROF_ADD_NOT_SECTION, -+ "Attempt to add a relation to node which is not a section" -+error_code PROF_SECTION_WITH_VALUE, -+ "A profile section header has a non-zero value" -+error_code PROF_BAD_LINK_LIST, "Bad linked list in profile structures" -+error_code PROF_BAD_GROUP_LVL, "Bad group level in profile structures" -+error_code PROF_BAD_PARENT_PTR, -+ "Bad parent pointer in profile structures" -+error_code PROF_MAGIC_ITERATOR, "Bad magic value in profile iterator" -+error_code PROF_SET_SECTION_VALUE, "Can't set value on section node" -+error_code PROF_EINVAL, "Invalid argument passed to profile library" -+error_code PROF_READ_ONLY, "Attempt to modify read-only profile" -+ -+# -+# generated by prof_parse.c -+# -+ -+error_code PROF_SECTION_NOTOP, "Profile section header not at top level" -+error_code PROF_SECTION_SYNTAX, "Syntax error in profile section header" -+error_code PROF_RELATION_SYNTAX, "Syntax error in profile relation" -+error_code PROF_EXTRA_CBRACE, "Extra closing brace in profile" -+error_code PROF_MISSING_OBRACE, "Missing open brace in profile" -+ -+# -+# generated by prof_init.c -+# -+error_code PROF_MAGIC_PROFILE, "Bad magic value in profile_t" -+error_code PROF_MAGIC_SECTION, "Bad magic value in profile_section_t" -+error_code PROF_TOPSECTION_ITER_NOSUPP, -+ "Iteration through all top level section not supported" -+error_code PROF_INVALID_SECTION, "Invalid profile_section object" -+error_code PROF_END_OF_SECTIONS, "No more sections" -+error_code PROF_BAD_NAMESET, "Bad nameset passed to query routine" -+error_code PROF_NO_PROFILE, "No profile file open" -+ -+# -+# generated by prof_file.c -+# -+error_code PROF_MAGIC_FILE, "Bad magic value in profile_file_t" -+error_code PROF_FAIL_OPEN, "Couldn't open profile file" -+ -+# -+# generated by prof_set.c -+# -+error_code PROF_EXISTS, "Section already exists" -+ -+# -+# generated by prof_get.c -+# -+error_code PROF_BAD_BOOLEAN, "Invalid boolean value" -+error_code PROF_BAD_INTEGER, "Invalid integer value" -+ -+error_code PROF_MAGIC_FILE_DATA, "Bad magic value in profile_file_data_t" -+ -+ -+end -diff --git a/lib/support/profile.c b/lib/support/profile.c -new file mode 100644 -index 0000000..c4528c8 ---- /dev/null -+++ b/lib/support/profile.c -@@ -0,0 +1,1905 @@ -+/* -+ * profile.c -- A simple configuration file parsing "library in a file" -+ * -+ * The profile library was originally written by Theodore Ts'o in 1995 -+ * for use in the MIT Kerberos v5 library. It has been -+ * modified/enhanced/bug-fixed over time by other members of the MIT -+ * Kerberos team. This version was originally taken from the Kerberos -+ * v5 distribution, version 1.4.2, and radically simplified for use in -+ * e2fsprogs. (Support for locking for multi-threaded operations, -+ * being able to modify and update the configuration file -+ * programmatically, and Mac/Windows portability have been removed. -+ * It has been folded into a single C source file to make it easier to -+ * fold into an application program.) -+ * -+ * Copyright (C) 2005, 2006 by Theodore Ts'o. -+ * -+ * %Begin-Header% -+ * This file may be redistributed under the terms of the GNU Public -+ * License. -+ * %End-Header% -+ * -+ * Copyright (C) 1985-2005 by the Massachusetts Institute of Technology. -+ * -+ * All rights reserved. -+ * -+ * Export of this software from the United States of America may require -+ * a specific license from the United States Government. It is the -+ * responsibility of any person or organization contemplating export to -+ * obtain such a license before exporting. -+ * -+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and -+ * distribute this software and its documentation for any purpose and -+ * without fee is hereby granted, provided that the above copyright -+ * notice appear in all copies and that both that copyright notice and -+ * this permission notice appear in supporting documentation, and that -+ * the name of M.I.T. not be used in advertising or publicity pertaining -+ * to distribution of the software without specific, written prior -+ * permission. Furthermore if you modify this software you must label -+ * your software as modified software and not distribute it in such a -+ * fashion that it might be confused with the original MIT software. -+ * M.I.T. makes no representations about the suitability of this software -+ * for any purpose. It is provided "as is" without express or implied -+ * warranty. -+ * -+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR -+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED -+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. -+ * -+ */ -+ -+#include "config.h" -+#ifdef HAVE_UNISTD_H -+#include -+#endif -+#include -+#ifdef HAVE_STDLIB_H -+#include -+#endif -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#ifdef HAVE_PWD_H -+#include -+#endif -+ -+#include -+#include "profile.h" -+#include "prof_err.h" -+ -+#undef STAT_ONCE_PER_SECOND -+#undef HAVE_STAT -+ -+/* -+ * prof_int.h -+ */ -+ -+typedef long prf_magic_t; -+ -+/* -+ * This is the structure which stores the profile information for a -+ * particular configuration file. -+ */ -+struct _prf_file_t { -+ prf_magic_t magic; -+ char *filespec; -+#ifdef STAT_ONCE_PER_SECOND -+ time_t last_stat; -+#endif -+ time_t timestamp; /* time tree was last updated from file */ -+ int flags; /* r/w, dirty */ -+ int upd_serial; /* incremented when data changes */ -+ struct profile_node *root; -+ struct _prf_file_t *next; -+}; -+ -+typedef struct _prf_file_t *prf_file_t; -+ -+/* -+ * The profile flags -+ */ -+#define PROFILE_FILE_RW 0x0001 -+#define PROFILE_FILE_DIRTY 0x0002 -+#define PROFILE_FILE_NO_RELOAD 0x0004 -+ -+/* -+ * This structure defines the high-level, user visible profile_t -+ * object, which is used as a handle by users who need to query some -+ * configuration file(s) -+ */ -+struct _profile_t { -+ prf_magic_t magic; -+ prf_file_t first_file; -+}; -+ -+/* -+ * Used by the profile iterator in prof_get.c -+ */ -+#define PROFILE_ITER_LIST_SECTION 0x0001 -+#define PROFILE_ITER_SECTIONS_ONLY 0x0002 -+#define PROFILE_ITER_RELATIONS_ONLY 0x0004 -+ -+#define PROFILE_ITER_FINAL_SEEN 0x0100 -+ -+/* -+ * Check if a filespec is last in a list (NULL on UNIX, invalid FSSpec on MacOS -+ */ -+ -+#define PROFILE_LAST_FILESPEC(x) (((x) == NULL) || ((x)[0] == '\0')) -+ -+struct profile_node { -+ errcode_t magic; -+ char *name; -+ char *value; -+ int group_level; -+ unsigned int final:1; /* Indicate don't search next file */ -+ unsigned int deleted:1; -+ struct profile_node *first_child; -+ struct profile_node *parent; -+ struct profile_node *next, *prev; -+}; -+ -+#define CHECK_MAGIC(node) \ -+ if ((node)->magic != PROF_MAGIC_NODE) \ -+ return PROF_MAGIC_NODE; -+ -+/* profile parser declarations */ -+struct parse_state { -+ int state; -+ int group_level; -+ int line_num; -+ struct profile_node *root_section; -+ struct profile_node *current_section; -+}; -+ -+static const char *default_filename = ""; -+ -+static profile_syntax_err_cb_t syntax_err_cb; -+ -+static errcode_t parse_line(char *line, struct parse_state *state); -+ -+#ifdef DEBUG_PROGRAM -+static errcode_t profile_write_tree_file -+ (struct profile_node *root, FILE *dstfile); -+ -+static errcode_t profile_write_tree_to_buffer -+ (struct profile_node *root, char **buf); -+#endif -+ -+ -+static void profile_free_node -+ (struct profile_node *relation); -+ -+static errcode_t profile_create_node -+ (const char *name, const char *value, -+ struct profile_node **ret_node); -+ -+#ifdef DEBUG_PROGRAM -+static errcode_t profile_verify_node -+ (struct profile_node *node); -+#endif -+ -+static errcode_t profile_add_node -+ (struct profile_node *section, -+ const char *name, const char *value, -+ struct profile_node **ret_node); -+ -+static errcode_t profile_find_node -+ (struct profile_node *section, -+ const char *name, const char *value, -+ int section_flag, void **state, -+ struct profile_node **node); -+ -+static errcode_t profile_node_iterator -+ (void **iter_p, struct profile_node **ret_node, -+ char **ret_name, char **ret_value); -+ -+static errcode_t profile_open_file -+ (const char * file, prf_file_t *ret_prof); -+ -+static errcode_t profile_update_file -+ (prf_file_t prf); -+ -+static void profile_free_file -+ (prf_file_t profile); -+ -+static errcode_t profile_get_value(profile_t profile, const char *name, -+ const char *subname, const char *subsubname, -+ const char **ret_value); -+ -+ -+/* -+ * prof_init.c --- routines that manipulate the user-visible profile_t -+ * object. -+ */ -+ -+static int compstr(const void *m1, const void *m2) -+{ -+ const char *s1 = *((const char * const *) m1); -+ const char *s2 = *((const char * const *) m2); -+ -+ return strcmp(s1, s2); -+} -+ -+static void free_list(char **list) -+{ -+ char **cp; -+ -+ if (list == 0) -+ return; -+ -+ for (cp = list; *cp; cp++) -+ free(*cp); -+ free(list); -+} -+ -+static errcode_t get_dirlist(const char *dirname, char***ret_array) -+{ -+ DIR *dir; -+ struct dirent *de; -+ struct stat st; -+ errcode_t retval; -+ char *fn, *cp; -+ char **array = 0, **new_array; -+ int max = 0, num = 0; -+ -+ dir = opendir(dirname); -+ if (!dir) -+ return errno; -+ -+ while ((de = readdir(dir)) != NULL) { -+ for (cp = de->d_name; *cp; cp++) { -+ if (!isalnum(*cp) && -+ (*cp != '-') && -+ (*cp != '_')) -+ break; -+ } -+ if (*cp) -+ continue; -+ fn = malloc(strlen(dirname) + strlen(de->d_name) + 2); -+ if (!fn) { -+ retval = ENOMEM; -+ goto errout; -+ } -+ sprintf(fn, "%s/%s", dirname, de->d_name); -+ if ((stat(fn, &st) < 0) || !S_ISREG(st.st_mode)) { -+ free(fn); -+ continue; -+ } -+ if (num >= max) { -+ max += 10; -+ new_array = realloc(array, sizeof(char *) * (max+1)); -+ if (!new_array) { -+ retval = ENOMEM; -+ free(fn); -+ goto errout; -+ } -+ array = new_array; -+ } -+ array[num++] = fn; -+ } -+ if (array) { -+ qsort(array, num, sizeof(char *), compstr); -+ array[num++] = 0; -+ } -+ *ret_array = array; -+ closedir(dir); -+ return 0; -+errout: -+ if (array) -+ array[num] = 0; -+ closedir(dir); -+ free_list(array); -+ return retval; -+} -+ -+errcode_t -+profile_init(const char **files, profile_t *ret_profile) -+{ -+ const char **fs; -+ profile_t profile; -+ prf_file_t new_file, *last; -+ errcode_t retval = 0; -+ char **cpp, *cp, **array = 0; -+ -+ profile = malloc(sizeof(struct _profile_t)); -+ if (!profile) -+ return ENOMEM; -+ memset(profile, 0, sizeof(struct _profile_t)); -+ profile->magic = PROF_MAGIC_PROFILE; -+ last = &profile->first_file; -+ -+ /* if the filenames list is not specified return an empty profile */ -+ if ( files ) { -+ for (fs = files; !PROFILE_LAST_FILESPEC(*fs); fs++) { -+ if (array) -+ free_list(array); -+ array = NULL; -+ retval = get_dirlist(*fs, &array); -+ if (retval == 0) { -+ if (!array) -+ continue; -+ for (cpp = array; (cp = *cpp); cpp++) { -+ retval = profile_open_file(cp, &new_file); -+ if (retval == EACCES) -+ continue; -+ if (retval) -+ goto errout; -+ *last = new_file; -+ last = &new_file->next; -+ } -+ } else if ((retval != ENOTDIR) && -+ strcmp(*fs, default_filename)) -+ goto errout; -+ -+ retval = profile_open_file(*fs, &new_file); -+ /* if this file is missing, skip to the next */ -+ if (retval == ENOENT || retval == EACCES) { -+ continue; -+ } -+ if (retval) -+ goto errout; -+ *last = new_file; -+ last = &new_file->next; -+ } -+ /* -+ * If all the files were not found, return the appropriate error. -+ */ -+ if (!profile->first_file) { -+ retval = ENOENT; -+ goto errout; -+ } -+ } -+ -+ free_list(array); -+ *ret_profile = profile; -+ return 0; -+errout: -+ free_list(array); -+ profile_release(profile); -+ return retval; -+} -+ -+void -+profile_release(profile_t profile) -+{ -+ prf_file_t p, next; -+ -+ if (!profile || profile->magic != PROF_MAGIC_PROFILE) -+ return; -+ -+ for (p = profile->first_file; p; p = next) { -+ next = p->next; -+ profile_free_file(p); -+ } -+ profile->magic = 0; -+ free(profile); -+} -+ -+/* -+ * This function sets the value of the pseudo file "". If -+ * the file "" had previously been passed to profile_init(), -+ * then def_string parameter will be parsed and used as the profile -+ * information for the "" file. -+ */ -+errcode_t profile_set_default(profile_t profile, const char *def_string) -+{ -+ struct parse_state state; -+ prf_file_t prf; -+ errcode_t retval; -+ const char *in; -+ char *line, *p, *end; -+ int line_size, len; -+ -+ if (!def_string || !profile || profile->magic != PROF_MAGIC_PROFILE) -+ return PROF_MAGIC_PROFILE; -+ -+ for (prf = profile->first_file; prf; prf = prf->next) { -+ if (strcmp(prf->filespec, default_filename) == 0) -+ break; -+ } -+ if (!prf) -+ return 0; -+ -+ if (prf->root) { -+ profile_free_node(prf->root); -+ prf->root = 0; -+ } -+ -+ memset(&state, 0, sizeof(struct parse_state)); -+ retval = profile_create_node("(root)", 0, &state.root_section); -+ if (retval) -+ return retval; -+ -+ line = 0; -+ line_size = 0; -+ in = def_string; -+ while (*in) { -+ end = strchr(in, '\n'); -+ len = end ? (end - in) : (int) strlen(in); -+ if (len >= line_size) { -+ line_size = len+1; -+ p = realloc(line, line_size); -+ if (!p) { -+ retval = ENOMEM; -+ goto errout; -+ } -+ line = p; -+ } -+ memcpy(line, in, len); -+ line[len] = 0; -+ retval = parse_line(line, &state); -+ if (retval) { -+ errout: -+ if (syntax_err_cb) -+ (syntax_err_cb)(prf->filespec, retval, -+ state.line_num); -+ free(line); -+ if (prf->root) -+ profile_free_node(prf->root); -+ return retval; -+ } -+ if (!end) -+ break; -+ in = end+1; -+ } -+ prf->root = state.root_section; -+ free(line); -+ -+ return 0; -+} -+ -+/* -+ * prof_file.c ---- routines that manipulate an individual profile file. -+ */ -+ -+errcode_t profile_open_file(const char * filespec, -+ prf_file_t *ret_prof) -+{ -+ prf_file_t prf; -+ errcode_t retval; -+ char *home_env = 0; -+ unsigned int len; -+ char *expanded_filename; -+ -+ prf = malloc(sizeof(struct _prf_file_t)); -+ if (!prf) -+ return ENOMEM; -+ memset(prf, 0, sizeof(struct _prf_file_t)); -+ prf->magic = PROF_MAGIC_FILE; -+ -+ len = strlen(filespec)+1; -+ if (filespec[0] == '~' && filespec[1] == '/') { -+ home_env = getenv("HOME"); -+#ifdef HAVE_PWD_H -+ if (home_env == NULL) { -+#ifdef HAVE_GETWUID_R -+ struct passwd *pw, pwx; -+ uid_t uid; -+ char pwbuf[BUFSIZ]; -+ -+ uid = getuid(); -+ if (!getpwuid_r(uid, &pwx, pwbuf, sizeof(pwbuf), &pw) -+ && pw != NULL && pw->pw_dir[0] != 0) -+ home_env = pw->pw_dir; -+#else -+ struct passwd *pw; -+ -+ pw = getpwuid(getuid()); -+ home_env = pw->pw_dir; -+#endif -+ } -+#endif -+ if (home_env) -+ len += strlen(home_env); -+ } -+ expanded_filename = malloc(len); -+ if (expanded_filename == 0) { -+ profile_free_file(prf); -+ return errno; -+ } -+ if (home_env) { -+ strcpy(expanded_filename, home_env); -+ strcat(expanded_filename, filespec+1); -+ } else -+ memcpy(expanded_filename, filespec, len); -+ -+ prf->filespec = expanded_filename; -+ -+ if (strcmp(prf->filespec, default_filename) != 0) { -+ retval = profile_update_file(prf); -+ if (retval) { -+ profile_free_file(prf); -+ return retval; -+ } -+ } -+ -+ *ret_prof = prf; -+ return 0; -+} -+ -+errcode_t profile_update_file(prf_file_t prf) -+{ -+ errcode_t retval; -+#ifdef HAVE_STAT -+ struct stat st; -+#ifdef STAT_ONCE_PER_SECOND -+ time_t now; -+#endif -+#endif -+ FILE *f; -+ char buf[2048]; -+ struct parse_state state; -+ -+ if (prf->flags & PROFILE_FILE_NO_RELOAD) -+ return 0; -+ -+#ifdef HAVE_STAT -+#ifdef STAT_ONCE_PER_SECOND -+ now = time(0); -+ if (now == prf->last_stat && prf->root != NULL) { -+ return 0; -+ } -+#endif -+ if (stat(prf->filespec, &st)) { -+ retval = errno; -+ return retval; -+ } -+#ifdef STAT_ONCE_PER_SECOND -+ prf->last_stat = now; -+#endif -+ if (st.st_mtime == prf->timestamp && prf->root != NULL) { -+ return 0; -+ } -+ if (prf->root) { -+ profile_free_node(prf->root); -+ prf->root = 0; -+ } -+#else -+ /* -+ * If we don't have the stat() call, assume that our in-core -+ * memory image is correct. That is, we won't reread the -+ * profile file if it changes. -+ */ -+ if (prf->root) { -+ return 0; -+ } -+#endif -+ memset(&state, 0, sizeof(struct parse_state)); -+ retval = profile_create_node("(root)", 0, &state.root_section); -+ if (retval) -+ return retval; -+ errno = 0; -+ f = fopen(prf->filespec, "r"); -+ if (f == NULL) { -+ retval = errno; -+ if (retval == 0) -+ retval = ENOENT; -+ return retval; -+ } -+ prf->upd_serial++; -+ while (!feof(f)) { -+ if (fgets(buf, sizeof(buf), f) == NULL) -+ break; -+ retval = parse_line(buf, &state); -+ if (retval) { -+ if (syntax_err_cb) -+ (syntax_err_cb)(prf->filespec, retval, -+ state.line_num); -+ fclose(f); -+ return retval; -+ } -+ } -+ prf->root = state.root_section; -+ -+ fclose(f); -+ -+#ifdef HAVE_STAT -+ prf->timestamp = st.st_mtime; -+#endif -+ return 0; -+} -+ -+void profile_free_file(prf_file_t prf) -+{ -+ if (prf->root) -+ profile_free_node(prf->root); -+ free(prf->filespec); -+ free(prf); -+} -+ -+/* Begin the profile parser */ -+ -+profile_syntax_err_cb_t profile_set_syntax_err_cb(profile_syntax_err_cb_t hook) -+{ -+ profile_syntax_err_cb_t old; -+ -+ old = syntax_err_cb; -+ syntax_err_cb = hook; -+ return(old); -+} -+ -+#define STATE_INIT_COMMENT 0 -+#define STATE_STD_LINE 1 -+#define STATE_GET_OBRACE 2 -+ -+static char *skip_over_blanks(char *cp) -+{ -+ while (*cp && isspace((int) (*cp))) -+ cp++; -+ return cp; -+} -+ -+static int end_or_comment(char ch) -+{ -+ return (ch == 0 || ch == '#' || ch == ';'); -+} -+ -+static char *skip_over_nonblanks(char *cp) -+{ -+ while (!end_or_comment(*cp) && !isspace(*cp)) -+ cp++; -+ return cp; -+} -+ -+static void strip_line(char *line) -+{ -+ char *p = line + strlen(line); -+ while (p > line && (p[-1] == '\n' || p[-1] == '\r')) -+ *p-- = 0; -+} -+ -+static void parse_quoted_string(char *str) -+{ -+ char *to, *from; -+ -+ to = from = str; -+ -+ for (to = from = str; *from && *from != '"'; to++, from++) { -+ if (*from == '\\') { -+ from++; -+ switch (*from) { -+ case 'n': -+ *to = '\n'; -+ break; -+ case 't': -+ *to = '\t'; -+ break; -+ case 'b': -+ *to = '\b'; -+ break; -+ default: -+ *to = *from; -+ } -+ continue; -+ } -+ *to = *from; -+ } -+ *to = '\0'; -+} -+ -+static errcode_t parse_line(char *line, struct parse_state *state) -+{ -+ char *cp, ch, *tag, *value; -+ char *p; -+ errcode_t retval; -+ struct profile_node *node; -+ int do_subsection = 0; -+ void *iter = 0; -+ -+ state->line_num++; -+ if (state->state == STATE_GET_OBRACE) { -+ cp = skip_over_blanks(line); -+ if (*cp != '{') -+ return PROF_MISSING_OBRACE; -+ state->state = STATE_STD_LINE; -+ return 0; -+ } -+ if (state->state == STATE_INIT_COMMENT) { -+ if (line[0] != '[') -+ return 0; -+ state->state = STATE_STD_LINE; -+ } -+ -+ if (*line == 0) -+ return 0; -+ strip_line(line); -+ cp = skip_over_blanks(line); -+ ch = *cp; -+ if (end_or_comment(ch)) -+ return 0; -+ if (ch == '[') { -+ if (state->group_level > 0) -+ return PROF_SECTION_NOTOP; -+ cp++; -+ cp = skip_over_blanks(cp); -+ p = strchr(cp, ']'); -+ if (p == NULL) -+ return PROF_SECTION_SYNTAX; -+ if (*cp == '"') { -+ cp++; -+ parse_quoted_string(cp); -+ } else { -+ *p-- = '\0'; -+ while (isspace(*p) && (p > cp)) -+ *p-- = '\0'; -+ if (*cp == 0) -+ return PROF_SECTION_SYNTAX; -+ } -+ retval = profile_find_node(state->root_section, cp, 0, 1, -+ &iter, &state->current_section); -+ if (retval == PROF_NO_SECTION) { -+ retval = profile_add_node(state->root_section, -+ cp, 0, -+ &state->current_section); -+ if (retval) -+ return retval; -+ } else if (retval) -+ return retval; -+ -+ /* -+ * Finish off the rest of the line. -+ */ -+ cp = p+1; -+ if (*cp == '*') { -+ state->current_section->final = 1; -+ cp++; -+ } -+ /* -+ * Spaces or comments after ']' should not be fatal -+ */ -+ cp = skip_over_blanks(cp); -+ if (!end_or_comment(*cp)) -+ return PROF_SECTION_SYNTAX; -+ return 0; -+ } -+ if (ch == '}') { -+ if (state->group_level == 0) -+ return PROF_EXTRA_CBRACE; -+ if (*(cp+1) == '*') -+ state->current_section->final = 1; -+ state->current_section = state->current_section->parent; -+ state->group_level--; -+ return 0; -+ } -+ /* -+ * Parse the relations -+ */ -+ tag = cp; -+ cp = strchr(cp, '='); -+ if (!cp) -+ return PROF_RELATION_SYNTAX; -+ if (cp == tag) -+ return PROF_RELATION_SYNTAX; -+ *cp = '\0'; -+ if (*tag == '"') { -+ tag++; -+ parse_quoted_string(tag); -+ } else { -+ /* Look for whitespace on left-hand side. */ -+ p = skip_over_nonblanks(tag); -+ if (*p) -+ *p++ = 0; -+ p = skip_over_blanks(p); -+ /* If we have more non-whitespace, it's an error. */ -+ if (*p) -+ return PROF_RELATION_SYNTAX; -+ } -+ -+ cp = skip_over_blanks(cp+1); -+ value = cp; -+ ch = value[0]; -+ if (ch == '"') { -+ value++; -+ parse_quoted_string(value); -+ } else if (end_or_comment(ch)) { -+ do_subsection++; -+ state->state = STATE_GET_OBRACE; -+ } else if (value[0] == '{') { -+ cp = skip_over_blanks(value+1); -+ ch = *cp; -+ if (end_or_comment(ch)) -+ do_subsection++; -+ else -+ return PROF_RELATION_SYNTAX; -+ } else { -+ cp = skip_over_nonblanks(value); -+ p = skip_over_blanks(cp); -+ ch = *p; -+ *cp = 0; -+ if (!end_or_comment(ch)) -+ return PROF_RELATION_SYNTAX; -+ } -+ if (do_subsection) { -+ p = strchr(tag, '*'); -+ if (p) -+ *p = '\0'; -+ retval = profile_add_node(state->current_section, -+ tag, 0, &state->current_section); -+ if (retval) -+ return retval; -+ if (p) -+ state->current_section->final = 1; -+ state->group_level++; -+ return 0; -+ } -+ p = strchr(tag, '*'); -+ if (p) -+ *p = '\0'; -+ profile_add_node(state->current_section, tag, value, &node); -+ if (p) -+ node->final = 1; -+ return 0; -+} -+ -+#ifdef DEBUG_PROGRAM -+/* -+ * Return TRUE if the string begins or ends with whitespace -+ */ -+static int need_double_quotes(char *str) -+{ -+ if (!str || !*str) -+ return 0; -+ if (isspace((int) (*str)) ||isspace((int) (*(str + strlen(str) - 1)))) -+ return 1; -+ if (strchr(str, '\n') || strchr(str, '\t') || strchr(str, '\b') || -+ strchr(str, ' ') || strchr(str, '#') || strchr(str, ';')) -+ return 1; -+ return 0; -+} -+ -+/* -+ * Output a string with double quotes, doing appropriate backquoting -+ * of characters as necessary. -+ */ -+static void output_quoted_string(char *str, void (*cb)(const char *,void *), -+ void *data) -+{ -+ char ch; -+ char buf[2]; -+ -+ cb("\"", data); -+ if (!str) { -+ cb("\"", data); -+ return; -+ } -+ buf[1] = 0; -+ while ((ch = *str++)) { -+ switch (ch) { -+ case '\\': -+ cb("\\\\", data); -+ break; -+ case '\n': -+ cb("\\n", data); -+ break; -+ case '\t': -+ cb("\\t", data); -+ break; -+ case '\b': -+ cb("\\b", data); -+ break; -+ default: -+ /* This would be a lot faster if we scanned -+ forward for the next "interesting" -+ character. */ -+ buf[0] = ch; -+ cb(buf, data); -+ break; -+ } -+ } -+ cb("\"", data); -+} -+ -+#ifndef EOL -+#define EOL "\n" -+#endif -+ -+/* Errors should be returned, not ignored! */ -+static void dump_profile(struct profile_node *root, int level, -+ void (*cb)(const char *, void *), void *data) -+{ -+ int i; -+ struct profile_node *p; -+ void *iter; -+ long retval; -+ -+ iter = 0; -+ do { -+ retval = profile_find_node(root, 0, 0, 0, &iter, &p); -+ if (retval) -+ break; -+ for (i=0; i < level; i++) -+ cb("\t", data); -+ if (need_double_quotes(p->name)) -+ output_quoted_string(p->name, cb, data); -+ else -+ cb(p->name, data); -+ cb(" = ", data); -+ if (need_double_quotes(p->value)) -+ output_quoted_string(p->value, cb, data); -+ else -+ cb(p->value, data); -+ cb(EOL, data); -+ } while (iter != 0); -+ -+ iter = 0; -+ do { -+ retval = profile_find_node(root, 0, 0, 1, &iter, &p); -+ if (retval) -+ break; -+ if (level == 0) { /* [xxx] */ -+ cb("[", data); -+ if (need_double_quotes(p->name)) -+ output_quoted_string(p->name, cb, data); -+ else -+ cb(p->name, data); -+ cb("]", data); -+ cb(p->final ? "*" : "", data); -+ cb(EOL, data); -+ dump_profile(p, level+1, cb, data); -+ cb(EOL, data); -+ } else { /* xxx = { ... } */ -+ for (i=0; i < level; i++) -+ cb("\t", data); -+ if (need_double_quotes(p->name)) -+ output_quoted_string(p->name, cb, data); -+ else -+ cb(p->name, data); -+ cb(" = {", data); -+ cb(EOL, data); -+ dump_profile(p, level+1, cb, data); -+ for (i=0; i < level; i++) -+ cb("\t", data); -+ cb("}", data); -+ cb(p->final ? "*" : "", data); -+ cb(EOL, data); -+ } -+ } while (iter != 0); -+} -+ -+static void dump_profile_to_file_cb(const char *str, void *data) -+{ -+ fputs(str, data); -+} -+ -+errcode_t profile_write_tree_file(struct profile_node *root, FILE *dstfile) -+{ -+ dump_profile(root, 0, dump_profile_to_file_cb, dstfile); -+ return 0; -+} -+ -+struct prof_buf { -+ char *base; -+ size_t cur, max; -+ int err; -+}; -+ -+static void add_data_to_buffer(struct prof_buf *b, const void *d, size_t len) -+{ -+ if (b->err) -+ return; -+ if (b->max - b->cur < len) { -+ size_t newsize; -+ char *newptr; -+ -+ newsize = b->max + (b->max >> 1) + len + 1024; -+ newptr = realloc(b->base, newsize); -+ if (newptr == NULL) { -+ b->err = 1; -+ return; -+ } -+ b->base = newptr; -+ b->max = newsize; -+ } -+ memcpy(b->base + b->cur, d, len); -+ b->cur += len; /* ignore overflow */ -+} -+ -+static void dump_profile_to_buffer_cb(const char *str, void *data) -+{ -+ add_data_to_buffer((struct prof_buf *)data, str, strlen(str)); -+} -+ -+errcode_t profile_write_tree_to_buffer(struct profile_node *root, -+ char **buf) -+{ -+ struct prof_buf prof_buf = { 0, 0, 0, 0 }; -+ -+ dump_profile(root, 0, dump_profile_to_buffer_cb, &prof_buf); -+ if (prof_buf.err) { -+ *buf = NULL; -+ return ENOMEM; -+ } -+ add_data_to_buffer(&prof_buf, "", 1); /* append nul */ -+ if (prof_buf.max - prof_buf.cur > (prof_buf.max >> 3)) { -+ char *newptr = realloc(prof_buf.base, prof_buf.cur); -+ if (newptr) -+ prof_buf.base = newptr; -+ } -+ *buf = prof_buf.base; -+ return 0; -+} -+#endif -+ -+/* -+ * prof_tree.c --- these routines maintain the parse tree of the -+ * config file. -+ * -+ * All of the details of how the tree is stored is abstracted away in -+ * this file; all of the other profile routines build, access, and -+ * modify the tree via the accessor functions found in this file. -+ * -+ * Each node may represent either a relation or a section header. -+ * -+ * A section header must have its value field set to 0, and may a one -+ * or more child nodes, pointed to by first_child. -+ * -+ * A relation has as its value a pointer to allocated memory -+ * containing a string. Its first_child pointer must be null. -+ * -+ */ -+ -+/* -+ * Free a node, and any children -+ */ -+void profile_free_node(struct profile_node *node) -+{ -+ struct profile_node *child, *next; -+ -+ if (node->magic != PROF_MAGIC_NODE) -+ return; -+ -+ free(node->name); -+ free(node->value); -+ -+ for (child=node->first_child; child; child = next) { -+ next = child->next; -+ profile_free_node(child); -+ } -+ node->magic = 0; -+ -+ free(node); -+} -+ -+#ifndef HAVE_STRDUP -+#undef strdup -+#define strdup MYstrdup -+static char *MYstrdup (const char *s) -+{ -+ size_t sz = strlen(s) + 1; -+ char *p = malloc(sz); -+ if (p != 0) -+ memcpy(p, s, sz); -+ return p; -+} -+#endif -+ -+/* -+ * Create a node -+ */ -+errcode_t profile_create_node(const char *name, const char *value, -+ struct profile_node **ret_node) -+{ -+ struct profile_node *new; -+ -+ new = malloc(sizeof(struct profile_node)); -+ if (!new) -+ return ENOMEM; -+ memset(new, 0, sizeof(struct profile_node)); -+ new->name = strdup(name); -+ if (new->name == 0) { -+ profile_free_node(new); -+ return ENOMEM; -+ } -+ if (value) { -+ new->value = strdup(value); -+ if (new->value == 0) { -+ profile_free_node(new); -+ return ENOMEM; -+ } -+ } -+ new->magic = PROF_MAGIC_NODE; -+ -+ *ret_node = new; -+ return 0; -+} -+ -+/* -+ * This function verifies that all of the representation invarients of -+ * the profile are true. If not, we have a programming bug somewhere, -+ * probably in this file. -+ */ -+#ifdef DEBUG_PROGRAM -+errcode_t profile_verify_node(struct profile_node *node) -+{ -+ struct profile_node *p, *last; -+ errcode_t retval; -+ -+ CHECK_MAGIC(node); -+ -+ if (node->value && node->first_child) -+ return PROF_SECTION_WITH_VALUE; -+ -+ last = 0; -+ for (p = node->first_child; p; last = p, p = p->next) { -+ if (p->prev != last) -+ return PROF_BAD_LINK_LIST; -+ if (last && (last->next != p)) -+ return PROF_BAD_LINK_LIST; -+ if (node->group_level+1 != p->group_level) -+ return PROF_BAD_GROUP_LVL; -+ if (p->parent != node) -+ return PROF_BAD_PARENT_PTR; -+ retval = profile_verify_node(p); -+ if (retval) -+ return retval; -+ } -+ return 0; -+} -+#endif -+ -+/* -+ * Add a node to a particular section -+ */ -+errcode_t profile_add_node(struct profile_node *section, const char *name, -+ const char *value, struct profile_node **ret_node) -+{ -+ errcode_t retval; -+ struct profile_node *p, *last, *new; -+ -+ CHECK_MAGIC(section); -+ -+ if (section->value) -+ return PROF_ADD_NOT_SECTION; -+ -+ /* -+ * Find the place to insert the new node. We look for the -+ * place *after* the last match of the node name, since -+ * order matters. -+ */ -+ for (p=section->first_child, last = 0; p; last = p, p = p->next) { -+ int cmp; -+ cmp = strcmp(p->name, name); -+ if (cmp > 0) -+ break; -+ } -+ retval = profile_create_node(name, value, &new); -+ if (retval) -+ return retval; -+ new->group_level = section->group_level+1; -+ new->deleted = 0; -+ new->parent = section; -+ new->prev = last; -+ new->next = p; -+ if (p) -+ p->prev = new; -+ if (last) -+ last->next = new; -+ else -+ section->first_child = new; -+ if (ret_node) -+ *ret_node = new; -+ return 0; -+} -+ -+/* -+ * Iterate through the section, returning the nodes which match -+ * the given name. If name is NULL, then interate through all the -+ * nodes in the section. If section_flag is non-zero, only return the -+ * section which matches the name; don't return relations. If value -+ * is non-NULL, then only return relations which match the requested -+ * value. (The value argument is ignored if section_flag is non-zero.) -+ * -+ * The first time this routine is called, the state pointer must be -+ * null. When this profile_find_node_relation() returns, if the state -+ * pointer is non-NULL, then this routine should be called again. -+ * (This won't happen if section_flag is non-zero, obviously.) -+ * -+ */ -+errcode_t profile_find_node(struct profile_node *section, const char *name, -+ const char *value, int section_flag, void **state, -+ struct profile_node **node) -+{ -+ struct profile_node *p; -+ -+ CHECK_MAGIC(section); -+ p = *state; -+ if (p) { -+ CHECK_MAGIC(p); -+ } else -+ p = section->first_child; -+ -+ for (; p; p = p->next) { -+ if (name && (strcmp(p->name, name))) -+ continue; -+ if (section_flag) { -+ if (p->value) -+ continue; -+ } else { -+ if (!p->value) -+ continue; -+ if (value && (strcmp(p->value, value))) -+ continue; -+ } -+ if (p->deleted) -+ continue; -+ /* A match! */ -+ if (node) -+ *node = p; -+ break; -+ } -+ if (p == 0) { -+ *state = 0; -+ return section_flag ? PROF_NO_SECTION : PROF_NO_RELATION; -+ } -+ /* -+ * OK, we've found one match; now let's try to find another -+ * one. This way, if we return a non-zero state pointer, -+ * there's guaranteed to be another match that's returned. -+ */ -+ for (p = p->next; p; p = p->next) { -+ if (name && (strcmp(p->name, name))) -+ continue; -+ if (section_flag) { -+ if (p->value) -+ continue; -+ } else { -+ if (!p->value) -+ continue; -+ if (value && (strcmp(p->value, value))) -+ continue; -+ } -+ /* A match! */ -+ break; -+ } -+ *state = p; -+ return 0; -+} -+ -+/* -+ * This is a general-purpose iterator for returning all nodes that -+ * match the specified name array. -+ */ -+struct profile_iterator { -+ prf_magic_t magic; -+ profile_t profile; -+ int flags; -+ const char *const *names; -+ const char *name; -+ prf_file_t file; -+ int file_serial; -+ int done_idx; -+ struct profile_node *node; -+ int num; -+}; -+ -+errcode_t -+profile_iterator_create(profile_t profile, const char *const *names, int flags, -+ void **ret_iter) -+{ -+ struct profile_iterator *iter; -+ int done_idx = 0; -+ -+ if (profile == 0) -+ return PROF_NO_PROFILE; -+ if (profile->magic != PROF_MAGIC_PROFILE) -+ return PROF_MAGIC_PROFILE; -+ if (!names) -+ return PROF_BAD_NAMESET; -+ if (!(flags & PROFILE_ITER_LIST_SECTION)) { -+ if (!names[0]) -+ return PROF_BAD_NAMESET; -+ done_idx = 1; -+ } -+ -+ if ((iter = malloc(sizeof(struct profile_iterator))) == NULL) -+ return ENOMEM; -+ -+ iter->magic = PROF_MAGIC_ITERATOR; -+ iter->profile = profile; -+ iter->names = names; -+ iter->flags = flags; -+ iter->file = profile->first_file; -+ iter->done_idx = done_idx; -+ iter->node = 0; -+ iter->num = 0; -+ *ret_iter = iter; -+ return 0; -+} -+ -+void profile_iterator_free(void **iter_p) -+{ -+ struct profile_iterator *iter; -+ -+ if (!iter_p) -+ return; -+ iter = *iter_p; -+ if (!iter || iter->magic != PROF_MAGIC_ITERATOR) -+ return; -+ free(iter); -+ *iter_p = 0; -+} -+ -+/* -+ * Note: the returned character strings in ret_name and ret_value -+ * points to the stored character string in the parse string. Before -+ * this string value is returned to a calling application -+ * (profile_node_iterator is not an exported interface), it should be -+ * strdup()'ed. -+ */ -+errcode_t profile_node_iterator(void **iter_p, struct profile_node **ret_node, -+ char **ret_name, char **ret_value) -+{ -+ struct profile_iterator *iter = *iter_p; -+ struct profile_node *section, *p; -+ const char *const *cpp; -+ errcode_t retval; -+ int skip_num = 0; -+ -+ if (!iter || iter->magic != PROF_MAGIC_ITERATOR) -+ return PROF_MAGIC_ITERATOR; -+ if (iter->file && iter->file->magic != PROF_MAGIC_FILE) -+ return PROF_MAGIC_FILE; -+ /* -+ * If the file has changed, then the node pointer is invalid, -+ * so we'll have search the file again looking for it. -+ */ -+ if (iter->node && (iter->file && -+ iter->file->upd_serial != iter->file_serial)) { -+ iter->flags &= ~PROFILE_ITER_FINAL_SEEN; -+ skip_num = iter->num; -+ iter->node = 0; -+ } -+ if (iter->node && iter->node->magic != PROF_MAGIC_NODE) { -+ return PROF_MAGIC_NODE; -+ } -+get_new_file: -+ if (iter->node == 0) { -+ if (iter->file == 0 || -+ (iter->flags & PROFILE_ITER_FINAL_SEEN)) { -+ profile_iterator_free(iter_p); -+ if (ret_node) -+ *ret_node = 0; -+ if (ret_name) -+ *ret_name = 0; -+ if (ret_value) -+ *ret_value =0; -+ return 0; -+ } -+ if ((retval = profile_update_file(iter->file))) { -+ if (retval == ENOENT || retval == EACCES) { -+ /* XXX memory leak? */ -+ iter->file = iter->file->next; -+ skip_num = 0; -+ retval = 0; -+ goto get_new_file; -+ } else { -+ profile_iterator_free(iter_p); -+ return retval; -+ } -+ } -+ iter->file_serial = iter->file->upd_serial; -+ /* -+ * Find the section to list if we are a LIST_SECTION, -+ * or find the containing section if not. -+ */ -+ section = iter->file->root; -+ for (cpp = iter->names; cpp[iter->done_idx]; cpp++) { -+ for (p=section->first_child; p; p = p->next) { -+ if (!strcmp(p->name, *cpp) && !p->value) -+ break; -+ } -+ if (!p) { -+ section = 0; -+ break; -+ } -+ section = p; -+ if (p->final) -+ iter->flags |= PROFILE_ITER_FINAL_SEEN; -+ } -+ if (!section) { -+ iter->file = iter->file->next; -+ skip_num = 0; -+ goto get_new_file; -+ } -+ iter->name = *cpp; -+ iter->node = section->first_child; -+ } -+ /* -+ * OK, now we know iter->node is set up correctly. Let's do -+ * the search. -+ */ -+ for (p = iter->node; p; p = p->next) { -+ if (iter->name && strcmp(p->name, iter->name)) -+ continue; -+ if ((iter->flags & PROFILE_ITER_SECTIONS_ONLY) && -+ p->value) -+ continue; -+ if ((iter->flags & PROFILE_ITER_RELATIONS_ONLY) && -+ !p->value) -+ continue; -+ if (skip_num > 0) { -+ skip_num--; -+ continue; -+ } -+ if (p->deleted) -+ continue; -+ break; -+ } -+ iter->num++; -+ if (!p) { -+ iter->file = iter->file->next; -+ iter->node = 0; -+ skip_num = 0; -+ goto get_new_file; -+ } -+ if ((iter->node = p->next) == NULL) -+ iter->file = iter->file->next; -+ if (ret_node) -+ *ret_node = p; -+ if (ret_name) -+ *ret_name = p->name; -+ if (ret_value) -+ *ret_value = p->value; -+ return 0; -+} -+ -+ -+/* -+ * prof_get.c --- routines that expose the public interfaces for -+ * querying items from the profile. -+ * -+ */ -+ -+/* -+ * This function only gets the first value from the file; it is a -+ * helper function for profile_get_string, profile_get_integer, etc. -+ */ -+errcode_t profile_get_value(profile_t profile, const char *name, -+ const char *subname, const char *subsubname, -+ const char **ret_value) -+{ -+ errcode_t retval; -+ void *state; -+ char *value; -+ const char *names[4]; -+ -+ names[0] = name; -+ names[1] = subname; -+ names[2] = subsubname; -+ names[3] = 0; -+ -+ if ((retval = profile_iterator_create(profile, names, -+ PROFILE_ITER_RELATIONS_ONLY, -+ &state))) -+ return retval; -+ -+ if ((retval = profile_node_iterator(&state, 0, 0, &value))) -+ goto cleanup; -+ -+ if (value) -+ *ret_value = value; -+ else -+ retval = PROF_NO_RELATION; -+ -+cleanup: -+ profile_iterator_free(&state); -+ return retval; -+} -+ -+errcode_t -+profile_get_string(profile_t profile, const char *name, const char *subname, -+ const char *subsubname, const char *def_val, -+ char **ret_string) -+{ -+ const char *value; -+ errcode_t retval; -+ -+ if (profile) { -+ retval = profile_get_value(profile, name, subname, -+ subsubname, &value); -+ if (retval == PROF_NO_SECTION || retval == PROF_NO_RELATION) -+ value = def_val; -+ else if (retval) -+ return retval; -+ } else -+ value = def_val; -+ -+ if (value) { -+ *ret_string = malloc(strlen(value)+1); -+ if (*ret_string == 0) -+ return ENOMEM; -+ strcpy(*ret_string, value); -+ } else -+ *ret_string = 0; -+ return 0; -+} -+ -+errcode_t -+profile_get_integer(profile_t profile, const char *name, const char *subname, -+ const char *subsubname, int def_val, int *ret_int) -+{ -+ const char *value; -+ errcode_t retval; -+ char *end_value; -+ long ret_long; -+ -+ *ret_int = def_val; -+ if (profile == 0) -+ return 0; -+ -+ retval = profile_get_value(profile, name, subname, subsubname, &value); -+ if (retval == PROF_NO_SECTION || retval == PROF_NO_RELATION) { -+ *ret_int = def_val; -+ return 0; -+ } else if (retval) -+ return retval; -+ -+ if (value[0] == 0) -+ /* Empty string is no good. */ -+ return PROF_BAD_INTEGER; -+ errno = 0; -+ ret_long = strtol(value, &end_value, 0); -+ -+ /* Overflow or underflow. */ -+ if ((ret_long == LONG_MIN || ret_long == LONG_MAX) && errno != 0) -+ return PROF_BAD_INTEGER; -+ /* Value outside "int" range. */ -+ if ((long) (int) ret_long != ret_long) -+ return PROF_BAD_INTEGER; -+ /* Garbage in string. */ -+ if (end_value != value + strlen (value)) -+ return PROF_BAD_INTEGER; -+ -+ -+ *ret_int = ret_long; -+ return 0; -+} -+ -+errcode_t -+profile_get_uint(profile_t profile, const char *name, const char *subname, -+ const char *subsubname, unsigned int def_val, -+ unsigned int *ret_int) -+{ -+ const char *value; -+ errcode_t retval; -+ char *end_value; -+ unsigned long ret_long; -+ -+ *ret_int = def_val; -+ if (profile == 0) -+ return 0; -+ -+ retval = profile_get_value(profile, name, subname, subsubname, &value); -+ if (retval == PROF_NO_SECTION || retval == PROF_NO_RELATION) { -+ *ret_int = def_val; -+ return 0; -+ } else if (retval) -+ return retval; -+ -+ if (value[0] == 0) -+ /* Empty string is no good. */ -+ return PROF_BAD_INTEGER; -+ errno = 0; -+ ret_long = strtoul(value, &end_value, 0); -+ -+ /* Overflow or underflow. */ -+ if ((ret_long == ULONG_MAX) && errno != 0) -+ return PROF_BAD_INTEGER; -+ /* Value outside "int" range. */ -+ if ((unsigned long) (unsigned int) ret_long != ret_long) -+ return PROF_BAD_INTEGER; -+ /* Garbage in string. */ -+ if (end_value != value + strlen (value)) -+ return PROF_BAD_INTEGER; -+ -+ *ret_int = ret_long; -+ return 0; -+} -+ -+errcode_t -+profile_get_double(profile_t profile, const char *name, const char *subname, -+ const char *subsubname, double def_val, double *ret_double) -+{ -+ const char *value; -+ errcode_t retval; -+ char *end_value; -+ double double_val; -+ -+ *ret_double = def_val; -+ if (profile == 0) -+ return 0; -+ -+ retval = profile_get_value(profile, name, subname, subsubname, &value); -+ if (retval == PROF_NO_SECTION || retval == PROF_NO_RELATION) { -+ *ret_double = def_val; -+ return 0; -+ } else if (retval) -+ return retval; -+ -+ if (value[0] == 0) -+ /* Empty string is no good. */ -+ return PROF_BAD_INTEGER; -+ errno = 0; -+ double_val = strtod(value, &end_value); -+ -+ /* Overflow or underflow. */ -+ if (errno != 0) -+ return PROF_BAD_INTEGER; -+ /* Garbage in string. */ -+ if (end_value != value + strlen(value)) -+ return PROF_BAD_INTEGER; -+ -+ *ret_double = double_val; -+ return 0; -+} -+ -+static const char *const conf_yes[] = { -+ "y", "yes", "true", "t", "1", "on", -+ 0, -+}; -+ -+static const char *const conf_no[] = { -+ "n", "no", "false", "nil", "0", "off", -+ 0, -+}; -+ -+static errcode_t -+profile_parse_boolean(const char *s, int *ret_boolean) -+{ -+ const char *const *p; -+ -+ if (ret_boolean == NULL) -+ return PROF_EINVAL; -+ -+ for(p=conf_yes; *p; p++) { -+ if (!strcasecmp(*p,s)) { -+ *ret_boolean = 1; -+ return 0; -+ } -+ } -+ -+ for(p=conf_no; *p; p++) { -+ if (!strcasecmp(*p,s)) { -+ *ret_boolean = 0; -+ return 0; -+ } -+ } -+ -+ return PROF_BAD_BOOLEAN; -+} -+ -+errcode_t -+profile_get_boolean(profile_t profile, const char *name, const char *subname, -+ const char *subsubname, int def_val, int *ret_boolean) -+{ -+ const char *value; -+ errcode_t retval; -+ -+ if (profile == 0) { -+ *ret_boolean = def_val; -+ return 0; -+ } -+ -+ retval = profile_get_value(profile, name, subname, subsubname, &value); -+ if (retval == PROF_NO_SECTION || retval == PROF_NO_RELATION) { -+ *ret_boolean = def_val; -+ return 0; -+ } else if (retval) -+ return retval; -+ -+ return profile_parse_boolean (value, ret_boolean); -+} -+ -+errcode_t -+profile_iterator(void **iter_p, char **ret_name, char **ret_value) -+{ -+ char *name, *value; -+ errcode_t retval; -+ -+ retval = profile_node_iterator(iter_p, 0, &name, &value); -+ if (retval) -+ return retval; -+ -+ if (ret_name) { -+ if (name) { -+ *ret_name = malloc(strlen(name)+1); -+ if (!*ret_name) -+ return ENOMEM; -+ strcpy(*ret_name, name); -+ } else -+ *ret_name = 0; -+ } -+ if (ret_value) { -+ if (value) { -+ *ret_value = malloc(strlen(value)+1); -+ if (!*ret_value) { -+ if (ret_name) { -+ free(*ret_name); -+ *ret_name = 0; -+ } -+ return ENOMEM; -+ } -+ strcpy(*ret_value, value); -+ } else -+ *ret_value = 0; -+ } -+ return 0; -+} -+ -+#ifdef DEBUG_PROGRAM -+ -+/* -+ * test_profile.c --- testing program for the profile routine -+ */ -+ -+#include "argv_parse.h" -+#include "profile_helpers.h" -+ -+const char *program_name = "test_profile"; -+ -+#define PRINT_VALUE 1 -+#define PRINT_VALUES 2 -+ -+static void do_cmd(profile_t profile, char **argv) -+{ -+ errcode_t retval; -+ const char **names, *value; -+ char **values, **cpp; -+ char *cmd; -+ int print_status; -+ -+ cmd = *(argv); -+ names = (const char **) argv + 1; -+ print_status = 0; -+ retval = 0; -+ if (cmd == 0) -+ return; -+ if (!strcmp(cmd, "query")) { -+ retval = profile_get_values(profile, names, &values); -+ print_status = PRINT_VALUES; -+ } else if (!strcmp(cmd, "query1")) { -+ const char *name = 0; -+ const char *subname = 0; -+ const char *subsubname = 0; -+ -+ name = names[0]; -+ if (name) -+ subname = names[1]; -+ if (subname) -+ subsubname = names[2]; -+ if (subsubname && names[3]) { -+ fprintf(stderr, -+ "Only 3 levels are allowed with query1\n"); -+ retval = EINVAL; -+ } else -+ retval = profile_get_value(profile, name, subname, -+ subsubname, &value); -+ print_status = PRINT_VALUE; -+ } else if (!strcmp(cmd, "list_sections")) { -+ retval = profile_get_subsection_names(profile, names, -+ &values); -+ print_status = PRINT_VALUES; -+ } else if (!strcmp(cmd, "list_relations")) { -+ retval = profile_get_relation_names(profile, names, -+ &values); -+ print_status = PRINT_VALUES; -+ } else if (!strcmp(cmd, "dump")) { -+ retval = profile_write_tree_file -+ (profile->first_file->root, stdout); -+#if 0 -+ } else if (!strcmp(cmd, "clear")) { -+ retval = profile_clear_relation(profile, names); -+ } else if (!strcmp(cmd, "update")) { -+ retval = profile_update_relation(profile, names+2, -+ *names, *(names+1)); -+#endif -+ } else if (!strcmp(cmd, "verify")) { -+ retval = profile_verify_node -+ (profile->first_file->root); -+#if 0 -+ } else if (!strcmp(cmd, "rename_section")) { -+ retval = profile_rename_section(profile, names+1, *names); -+ } else if (!strcmp(cmd, "add")) { -+ value = *names; -+ if (strcmp(value, "NULL") == 0) -+ value = NULL; -+ retval = profile_add_relation(profile, names+1, value); -+ } else if (!strcmp(cmd, "flush")) { -+ retval = profile_flush(profile); -+#endif -+ } else { -+ printf("Invalid command.\n"); -+ } -+ if (retval) { -+ com_err(cmd, retval, ""); -+ print_status = 0; -+ } -+ switch (print_status) { -+ case PRINT_VALUE: -+ printf("%s\n", value); -+ break; -+ case PRINT_VALUES: -+ for (cpp = values; *cpp; cpp++) -+ printf("%s\n", *cpp); -+ profile_free_list(values); -+ break; -+ } -+} -+ -+static void do_batchmode(profile_t profile) -+{ -+ int argc, ret; -+ char **argv; -+ char buf[256]; -+ -+ while (!feof(stdin)) { -+ if (fgets(buf, sizeof(buf), stdin) == NULL) -+ break; -+ printf(">%s", buf); -+ ret = argv_parse(buf, &argc, &argv); -+ if (ret != 0) { -+ printf("Argv_parse returned %d!\n", ret); -+ continue; -+ } -+ do_cmd(profile, argv); -+ printf("\n"); -+ argv_free(argv); -+ } -+ profile_release(profile); -+ exit(0); -+ -+} -+ -+void syntax_err_report(const char *filename, long err, int line_num) -+{ -+ fprintf(stderr, "Syntax error in %s, line number %d: %s\n", -+ filename, line_num, error_message(err)); -+ exit(1); -+} -+ -+const char *default_str = "[foo]\n\tbar=quux\n\tsub = {\n\t\twin = true\n}\n"; -+ -+int main(int argc, char **argv) -+{ -+ profile_t profile; -+ long retval; -+ char *cmd; -+ -+ if (argc < 2) { -+ fprintf(stderr, "Usage: %s filename [cmd argset]\n", program_name); -+ exit(1); -+ } -+ -+ initialize_prof_error_table(); -+ -+ profile_set_syntax_err_cb(syntax_err_report); -+ -+ retval = profile_init_path(argv[1], &profile); -+ if (retval) { -+ com_err(program_name, retval, "while initializing profile"); -+ exit(1); -+ } -+ retval = profile_set_default(profile, default_str); -+ if (retval) { -+ com_err(program_name, retval, "while setting default"); -+ exit(1); -+ } -+ -+ cmd = *(argv+2); -+ if (!cmd || !strcmp(cmd, "batch")) -+ do_batchmode(profile); -+ else -+ do_cmd(profile, argv+2); -+ profile_release(profile); -+ -+ return 0; -+} -+ -+#endif -diff --git a/lib/support/profile.h b/lib/support/profile.h -new file mode 100644 -index 0000000..4cc10eb ---- /dev/null -+++ b/lib/support/profile.h -@@ -0,0 +1,107 @@ -+/* -+ * profile.h -+ * -+ * Copyright (C) 2005 by Theodore Ts'o. -+ * -+ * %Begin-Header% -+ * This file may be redistributed under the terms of the GNU Public -+ * License. -+ * %End-Header% -+ * -+ * Copyright (C) 1985-2005 by the Massachusetts Institute of Technology. -+ * -+ * All rights reserved. -+ * -+ * Export of this software from the United States of America may require -+ * a specific license from the United States Government. It is the -+ * responsibility of any person or organization contemplating export to -+ * obtain such a license before exporting. -+ * -+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and -+ * distribute this software and its documentation for any purpose and -+ * without fee is hereby granted, provided that the above copyright -+ * notice appear in all copies and that both that copyright notice and -+ * this permission notice appear in supporting documentation, and that -+ * the name of M.I.T. not be used in advertising or publicity pertaining -+ * to distribution of the software without specific, written prior -+ * permission. Furthermore if you modify this software you must label -+ * your software as modified software and not distribute it in such a -+ * fashion that it might be confused with the original MIT software. -+ * M.I.T. makes no representations about the suitability of this software -+ * for any purpose. It is provided "as is" without express or implied -+ * warranty. -+ * -+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR -+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED -+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. -+ */ -+ -+#ifndef _PROFILE_H -+#define _PROFILE_H -+ -+typedef struct _profile_t *profile_t; -+ -+typedef void (*profile_syntax_err_cb_t)(const char *file, long err, -+ int line_num); -+ -+/* -+ * Used by the profile iterator in prof_get.c -+ */ -+#define PROFILE_ITER_LIST_SECTION 0x0001 -+#define PROFILE_ITER_SECTIONS_ONLY 0x0002 -+#define PROFILE_ITER_RELATIONS_ONLY 0x0004 -+ -+#ifdef __cplusplus -+extern "C" { -+#endif /* __cplusplus */ -+ -+long profile_init -+ (const char * *files, profile_t *ret_profile); -+ -+void profile_release -+ (profile_t profile); -+ -+long profile_set_default -+ (profile_t profile, const char *def_string); -+ -+long profile_get_string -+ (profile_t profile, const char *name, const char *subname, -+ const char *subsubname, const char *def_val, -+ char **ret_string); -+long profile_get_integer -+ (profile_t profile, const char *name, const char *subname, -+ const char *subsubname, int def_val, -+ int *ret_default); -+ -+long profile_get_uint -+ (profile_t profile, const char *name, const char *subname, -+ const char *subsubname, unsigned int def_val, -+ unsigned int *ret_int); -+ -+long profile_get_double -+ (profile_t profile, const char *name, const char *subname, -+ const char *subsubname, double def_val, -+ double *ret_float); -+ -+long profile_get_boolean -+ (profile_t profile, const char *name, const char *subname, -+ const char *subsubname, int def_val, -+ int *ret_default); -+ -+long profile_iterator_create -+ (profile_t profile, const char *const *names, -+ int flags, void **ret_iter); -+ -+void profile_iterator_free -+ (void **iter_p); -+ -+long profile_iterator -+ (void **iter_p, char **ret_name, char **ret_value); -+ -+profile_syntax_err_cb_t profile_set_syntax_err_cb(profile_syntax_err_cb_t hook); -+ -+#ifdef __cplusplus -+} -+#endif /* __cplusplus */ -+ -+#endif /* _KRB5_H */ -diff --git a/lib/support/profile_helpers.c b/lib/support/profile_helpers.c -new file mode 100644 -index 0000000..9c9080a ---- /dev/null -+++ b/lib/support/profile_helpers.c -@@ -0,0 +1,310 @@ -+/* -+ * profile_helpers.c -- Helper functions for the profile library -+ * -+ * These functions are not part of the "core" profile library, and do -+ * not require access to the internal functions and data structures of -+ * the profile library. They are mainly convenience functions for -+ * programs that want to do something unusual such as obtaining the -+ * list of sections or relations, or accessing multiple values from a -+ * relation that is listed more than once. This functionality can all -+ * be done using the profile_iterator abstraction, but it is less -+ * convenient. -+ * -+ * Copyright (C) 2006 by Theodore Ts'o. -+ * -+ * %Begin-Header% -+ * This file may be redistributed under the terms of the GNU Public -+ * License. -+ * %End-Header% -+ */ -+ -+#include "config.h" -+#include -+#include -+#include -+ -+#include -+#include "profile.h" -+#include "prof_err.h" -+ -+/* -+ * These functions --- init_list(), end_list(), and add_to_list() are -+ * internal functions used to build up a null-terminated char ** list -+ * of strings to be returned by functions like profile_get_values. -+ * -+ * The profile_string_list structure is used for internal booking -+ * purposes to build up the list, which is returned in *ret_list by -+ * the end_list() function. -+ * -+ * The publicly exported interface for freeing char** list is -+ * profile_free_list(). -+ */ -+ -+struct profile_string_list { -+ char **list; -+ int num; -+ int max; -+}; -+ -+/* -+ * Initialize the string list abstraction. -+ */ -+static errcode_t init_list(struct profile_string_list *list) -+{ -+ list->num = 0; -+ list->max = 10; -+ list->list = malloc(list->max * sizeof(char *)); -+ if (list->list == 0) -+ return ENOMEM; -+ list->list[0] = 0; -+ return 0; -+} -+ -+/* -+ * Free any memory left over in the string abstraction, returning the -+ * built up list in *ret_list if it is non-null. -+ */ -+static void end_list(struct profile_string_list *list, char ***ret_list) -+{ -+ char **cp; -+ -+ if (list == 0) -+ return; -+ -+ if (ret_list) { -+ *ret_list = list->list; -+ return; -+ } else { -+ for (cp = list->list; *cp; cp++) -+ free(*cp); -+ free(list->list); -+ } -+ list->num = list->max = 0; -+ list->list = 0; -+} -+ -+/* -+ * Add a string to the list. -+ */ -+static errcode_t add_to_list(struct profile_string_list *list, char *str) -+{ -+ char **newlist; -+ int newmax; -+ -+ if (list->num+1 >= list->max) { -+ newmax = list->max + 10; -+ newlist = realloc(list->list, newmax * sizeof(char *)); -+ if (newlist == 0) -+ return ENOMEM; -+ list->max = newmax; -+ list->list = newlist; -+ } -+ -+ list->list[list->num++] = str; -+ list->list[list->num] = 0; -+ return 0; -+} -+ -+/* -+ * Return TRUE if the string is already a member of the list. -+ */ -+static int is_list_member(struct profile_string_list *list, const char *str) -+{ -+ char **cpp; -+ -+ if (!list->list) -+ return 0; -+ -+ for (cpp = list->list; *cpp; cpp++) { -+ if (!strcmp(*cpp, str)) -+ return 1; -+ } -+ return 0; -+} -+ -+/* -+ * This function frees a null-terminated list as returned by -+ * profile_get_values. -+ */ -+void profile_free_list(char **list) -+{ -+ char **cp; -+ -+ if (list == 0) -+ return; -+ -+ for (cp = list; *cp; cp++) -+ free(*cp); -+ free(list); -+} -+ -+errcode_t -+profile_get_values(profile_t profile, const char *const *names, -+ char ***ret_values) -+{ -+ errcode_t retval; -+ void *state; -+ char *value; -+ struct profile_string_list values; -+ -+ if ((retval = profile_iterator_create(profile, names, -+ PROFILE_ITER_RELATIONS_ONLY, -+ &state))) -+ return retval; -+ -+ if ((retval = init_list(&values))) -+ return retval; -+ -+ do { -+ if ((retval = profile_iterator(&state, 0, &value))) -+ goto cleanup; -+ if (value) -+ add_to_list(&values, value); -+ } while (state); -+ -+ if (values.num == 0) { -+ retval = PROF_NO_RELATION; -+ goto cleanup; -+ } -+ -+ end_list(&values, ret_values); -+ return 0; -+ -+cleanup: -+ end_list(&values, 0); -+ return retval; -+} -+ -+/* -+ * This function will return the list of the names of subections in the -+ * under the specified section name. -+ */ -+errcode_t -+profile_get_subsection_names(profile_t profile, const char **names, -+ char ***ret_names) -+{ -+ errcode_t retval; -+ void *state; -+ char *name; -+ struct profile_string_list values; -+ -+ if ((retval = profile_iterator_create(profile, names, -+ PROFILE_ITER_LIST_SECTION | PROFILE_ITER_SECTIONS_ONLY, -+ &state))) -+ return retval; -+ -+ if ((retval = init_list(&values))) -+ return retval; -+ -+ do { -+ if ((retval = profile_iterator(&state, &name, 0))) -+ goto cleanup; -+ if (name) -+ add_to_list(&values, name); -+ } while (state); -+ -+ end_list(&values, ret_names); -+ return 0; -+ -+cleanup: -+ end_list(&values, 0); -+ return retval; -+} -+ -+/* -+ * This function will return the list of the names of relations in the -+ * under the specified section name. -+ */ -+errcode_t -+profile_get_relation_names(profile_t profile, const char **names, -+ char ***ret_names) -+{ -+ errcode_t retval; -+ void *state; -+ char *name; -+ struct profile_string_list values; -+ -+ if ((retval = profile_iterator_create(profile, names, -+ PROFILE_ITER_LIST_SECTION | PROFILE_ITER_RELATIONS_ONLY, -+ &state))) -+ return retval; -+ -+ if ((retval = init_list(&values))) -+ return retval; -+ -+ do { -+ if ((retval = profile_iterator(&state, &name, 0))) -+ goto cleanup; -+ if (name) { -+ if (is_list_member(&values, name)) -+ free(name); -+ else -+ add_to_list(&values, name); -+ } -+ } while (state); -+ -+ end_list(&values, ret_names); -+ return 0; -+ -+cleanup: -+ end_list(&values, 0); -+ return retval; -+} -+ -+ -+void -+profile_release_string(char *str) -+{ -+ free(str); -+} -+ -+errcode_t -+profile_init_path(const char * filepath, -+ profile_t *ret_profile) -+{ -+ int n_entries, i; -+ unsigned int ent_len; -+ const char *s, *t; -+ char **filenames; -+ errcode_t retval; -+ -+ /* count the distinct filename components */ -+ for(s = filepath, n_entries = 1; *s; s++) { -+ if (*s == ':') -+ n_entries++; -+ } -+ -+ /* the array is NULL terminated */ -+ filenames = (char **) malloc((n_entries+1) * sizeof(char*)); -+ if (filenames == 0) -+ return ENOMEM; -+ -+ /* measure, copy, and skip each one */ -+ for(s = filepath, i=0; (t = strchr(s, ':')) || (t=s+strlen(s)); s=t+1, i++) { -+ ent_len = t-s; -+ filenames[i] = (char*) malloc(ent_len + 1); -+ if (filenames[i] == 0) { -+ /* if malloc fails, free the ones that worked */ -+ while(--i >= 0) free(filenames[i]); -+ free(filenames); -+ return ENOMEM; -+ } -+ strncpy(filenames[i], s, ent_len); -+ filenames[i][ent_len] = 0; -+ if (*t == 0) { -+ i++; -+ break; -+ } -+ } -+ /* cap the array */ -+ filenames[i] = 0; -+ -+ retval = profile_init((const char **) filenames, -+ ret_profile); -+ -+ /* count back down and free the entries */ -+ while(--i >= 0) free(filenames[i]); -+ free(filenames); -+ -+ return retval; -+} -diff --git a/lib/support/profile_helpers.h b/lib/support/profile_helpers.h -new file mode 100644 -index 0000000..af63ca5 ---- /dev/null -+++ b/lib/support/profile_helpers.h -@@ -0,0 +1,28 @@ -+/* -+ * profile_helpers.h -- Function prototypes for profile helper functions -+ * -+ * Copyright (C) 2006 by Theodore Ts'o. -+ * -+ * %Begin-Header% -+ * This file may be redistributed under the terms of the GNU Public -+ * License. -+ * %End-Header% -+ */ -+ -+long profile_get_values -+ (profile_t profile, const char *const *names, char ***ret_values); -+ -+void profile_free_list -+ (char **list); -+ -+long profile_get_relation_names -+ (profile_t profile, const char **names, char ***ret_names); -+ -+long profile_get_subsection_names -+ (profile_t profile, const char **names, char ***ret_names); -+ -+void profile_release_string (char *str); -+ -+long profile_init_path -+ (const char * filelist, profile_t *ret_profile); -+ -diff --git a/lib/support/quotaio.c b/lib/support/quotaio.c -new file mode 100644 -index 0000000..3af82f7 ---- /dev/null -+++ b/lib/support/quotaio.c -@@ -0,0 +1,407 @@ -+/** quotaio.c -+ * -+ * Generic IO operations on quotafiles -+ * Jan Kara - sponsored by SuSE CR -+ * Aditya Kali - Ported to e2fsprogs -+ */ -+ -+#include "config.h" -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "common.h" -+#include "quotaio.h" -+ -+static const char * const extensions[MAXQUOTAS] = {"user", "group"}; -+static const char * const basenames[] = { -+ "", /* undefined */ -+ "quota", /* QFMT_VFS_OLD */ -+ "aquota", /* QFMT_VFS_V0 */ -+ "", /* QFMT_OCFS2 */ -+ "aquota" /* QFMT_VFS_V1 */ -+}; -+ -+/* Header in all newer quotafiles */ -+struct disk_dqheader { -+ __le32 dqh_magic; -+ __le32 dqh_version; -+} __attribute__ ((packed)); -+ -+/** -+ * Convert type of quota to written representation -+ */ -+const char *type2name(int type) -+{ -+ return extensions[type]; -+} -+ -+/** -+ * Creates a quota file name for given type and format. -+ */ -+const char *quota_get_qf_name(int type, int fmt, char *buf) -+{ -+ if (!buf) -+ return NULL; -+ snprintf(buf, QUOTA_NAME_LEN, "%s.%s", -+ basenames[fmt], extensions[type]); -+ -+ return buf; -+} -+ -+/* -+ * Set grace time if needed -+ */ -+void update_grace_times(struct dquot *q) -+{ -+ time_t now; -+ -+ time(&now); -+ if (q->dq_dqb.dqb_bsoftlimit && toqb(q->dq_dqb.dqb_curspace) > -+ q->dq_dqb.dqb_bsoftlimit) { -+ if (!q->dq_dqb.dqb_btime) -+ q->dq_dqb.dqb_btime = -+ now + q->dq_h->qh_info.dqi_bgrace; -+ } else { -+ q->dq_dqb.dqb_btime = 0; -+ } -+ -+ if (q->dq_dqb.dqb_isoftlimit && q->dq_dqb.dqb_curinodes > -+ q->dq_dqb.dqb_isoftlimit) { -+ if (!q->dq_dqb.dqb_itime) -+ q->dq_dqb.dqb_itime = -+ now + q->dq_h->qh_info.dqi_igrace; -+ } else { -+ q->dq_dqb.dqb_itime = 0; -+ } -+} -+ -+static int compute_num_blocks_proc(ext2_filsys fs EXT2FS_ATTR((unused)), -+ blk64_t *blocknr EXT2FS_ATTR((unused)), -+ e2_blkcnt_t blockcnt EXT2FS_ATTR((unused)), -+ blk64_t ref_block EXT2FS_ATTR((unused)), -+ int ref_offset EXT2FS_ATTR((unused)), -+ void *private) -+{ -+ blk64_t *num_blocks = private; -+ -+ *num_blocks += 1; -+ return 0; -+} -+ -+errcode_t quota_inode_truncate(ext2_filsys fs, ext2_ino_t ino) -+{ -+ struct ext2_inode inode; -+ errcode_t err; -+ -+ if ((err = ext2fs_read_inode(fs, ino, &inode))) -+ return err; -+ -+ if ((ino == EXT4_USR_QUOTA_INO) || (ino == EXT4_GRP_QUOTA_INO)) { -+ inode.i_dtime = fs->now ? fs->now : time(0); -+ if (!ext2fs_inode_has_valid_blocks2(fs, &inode)) -+ return 0; -+ err = ext2fs_punch(fs, ino, &inode, NULL, 0, ~0ULL); -+ if (err) -+ return err; -+ fs->flags &= ~EXT2_FLAG_SUPER_ONLY; -+ memset(&inode, 0, sizeof(struct ext2_inode)); -+ } else { -+ inode.i_flags &= ~EXT2_IMMUTABLE_FL; -+ } -+ err = ext2fs_write_inode(fs, ino, &inode); -+ return err; -+} -+ -+static ext2_off64_t compute_inode_size(ext2_filsys fs, ext2_ino_t ino) -+{ -+ blk64_t num_blocks = 0; -+ -+ ext2fs_block_iterate3(fs, ino, -+ BLOCK_FLAG_READ_ONLY, -+ NULL, -+ compute_num_blocks_proc, -+ &num_blocks); -+ return num_blocks * fs->blocksize; -+} -+ -+/* Functions to read/write quota file. */ -+static unsigned int quota_write_nomount(struct quota_file *qf, -+ ext2_loff_t offset, -+ void *buf, unsigned int size) -+{ -+ ext2_file_t e2_file = qf->e2_file; -+ unsigned int bytes_written = 0; -+ errcode_t err; -+ -+ err = ext2fs_file_llseek(e2_file, offset, EXT2_SEEK_SET, NULL); -+ if (err) { -+ log_err("ext2fs_file_llseek failed: %ld", err); -+ return 0; -+ } -+ -+ err = ext2fs_file_write(e2_file, buf, size, &bytes_written); -+ if (err) { -+ log_err("ext2fs_file_write failed: %ld", err); -+ return 0; -+ } -+ -+ /* Correct inode.i_size is set in end_io. */ -+ return bytes_written; -+} -+ -+static unsigned int quota_read_nomount(struct quota_file *qf, -+ ext2_loff_t offset, -+ void *buf, unsigned int size) -+{ -+ ext2_file_t e2_file = qf->e2_file; -+ unsigned int bytes_read = 0; -+ errcode_t err; -+ -+ err = ext2fs_file_llseek(e2_file, offset, EXT2_SEEK_SET, NULL); -+ if (err) { -+ log_err("ext2fs_file_llseek failed: %ld", err); -+ return 0; -+ } -+ -+ err = ext2fs_file_read(e2_file, buf, size, &bytes_read); -+ if (err) { -+ log_err("ext2fs_file_read failed: %ld", err); -+ return 0; -+ } -+ -+ return bytes_read; -+} -+ -+/* -+ * Detect quota format and initialize quota IO -+ */ -+errcode_t quota_file_open(quota_ctx_t qctx, struct quota_handle *h, -+ ext2_ino_t qf_ino, int type, int fmt, int flags) -+{ -+ ext2_filsys fs = qctx->fs; -+ ext2_file_t e2_file; -+ errcode_t err; -+ int allocated_handle = 0; -+ -+ if (type >= MAXQUOTAS) -+ return EINVAL; -+ -+ if (fmt == -1) -+ fmt = QFMT_VFS_V1; -+ -+ err = ext2fs_read_bitmaps(fs); -+ if (err) -+ return err; -+ -+ if (qf_ino == 0) { -+ if (type == USRQUOTA) -+ qf_ino = fs->super->s_usr_quota_inum; -+ else -+ qf_ino = fs->super->s_grp_quota_inum; -+ } -+ -+ log_debug("Opening quota ino=%lu, type=%d", qf_ino, type); -+ err = ext2fs_file_open(fs, qf_ino, flags, &e2_file); -+ if (err) { -+ log_err("ext2fs_file_open failed: %s", error_message(err)); -+ return err; -+ } -+ -+ if (!h) { -+ if (qctx->quota_file[type]) { -+ h = qctx->quota_file[type]; -+ if (((flags & EXT2_FILE_WRITE) == 0) || -+ (h->qh_file_flags & EXT2_FILE_WRITE)) -+ return 0; -+ (void) quota_file_close(qctx, h); -+ } -+ err = ext2fs_get_mem(sizeof(struct quota_handle), &h); -+ if (err) { -+ log_err("Unable to allocate quota handle"); -+ return err; -+ } -+ allocated_handle = 1; -+ } -+ -+ h->qh_qf.e2_file = e2_file; -+ h->qh_qf.fs = fs; -+ h->qh_qf.ino = qf_ino; -+ h->e2fs_write = quota_write_nomount; -+ h->e2fs_read = quota_read_nomount; -+ h->qh_file_flags = flags; -+ h->qh_io_flags = 0; -+ h->qh_type = type; -+ h->qh_fmt = fmt; -+ memset(&h->qh_info, 0, sizeof(h->qh_info)); -+ h->qh_ops = "afile_ops_2; -+ -+ if (h->qh_ops->check_file && -+ (h->qh_ops->check_file(h, type, fmt) == 0)) { -+ log_err("qh_ops->check_file failed"); -+ goto errout; -+ } -+ -+ if (h->qh_ops->init_io && (h->qh_ops->init_io(h) < 0)) { -+ log_err("qh_ops->init_io failed"); -+ goto errout; -+ } -+ if (allocated_handle) -+ qctx->quota_file[type] = h; -+ -+ return 0; -+errout: -+ ext2fs_file_close(e2_file); -+ if (allocated_handle) -+ ext2fs_free_mem(&h); -+ return -1; -+} -+ -+static errcode_t quota_inode_init_new(ext2_filsys fs, ext2_ino_t ino) -+{ -+ struct ext2_inode inode; -+ errcode_t err = 0; -+ -+ err = ext2fs_read_inode(fs, ino, &inode); -+ if (err) { -+ log_err("ex2fs_read_inode failed"); -+ return err; -+ } -+ -+ if (EXT2_I_SIZE(&inode)) -+ quota_inode_truncate(fs, ino); -+ -+ memset(&inode, 0, sizeof(struct ext2_inode)); -+ ext2fs_iblk_set(fs, &inode, 0); -+ inode.i_atime = inode.i_mtime = -+ inode.i_ctime = fs->now ? fs->now : time(0); -+ inode.i_links_count = 1; -+ inode.i_mode = LINUX_S_IFREG | 0600; -+ inode.i_flags |= EXT2_IMMUTABLE_FL; -+ if (fs->super->s_feature_incompat & -+ EXT3_FEATURE_INCOMPAT_EXTENTS) -+ inode.i_flags |= EXT4_EXTENTS_FL; -+ -+ err = ext2fs_write_new_inode(fs, ino, &inode); -+ if (err) { -+ log_err("ext2fs_write_new_inode failed: %ld", err); -+ return err; -+ } -+ return err; -+} -+ -+/* -+ * Create new quotafile of specified format on given filesystem -+ */ -+errcode_t quota_file_create(struct quota_handle *h, ext2_filsys fs, int type, int fmt) -+{ -+ ext2_file_t e2_file; -+ int err; -+ unsigned long qf_inum; -+ -+ if (fmt == -1) -+ fmt = QFMT_VFS_V1; -+ -+ h->qh_qf.fs = fs; -+ if (type == USRQUOTA) -+ qf_inum = EXT4_USR_QUOTA_INO; -+ else if (type == GRPQUOTA) -+ qf_inum = EXT4_GRP_QUOTA_INO; -+ else -+ return -1; -+ -+ err = ext2fs_read_bitmaps(fs); -+ if (err) -+ goto out_err; -+ -+ err = quota_inode_init_new(fs, qf_inum); -+ if (err) { -+ log_err("init_new_quota_inode failed"); -+ goto out_err; -+ } -+ h->qh_qf.ino = qf_inum; -+ h->qh_file_flags = EXT2_FILE_WRITE | EXT2_FILE_CREATE; -+ h->e2fs_write = quota_write_nomount; -+ h->e2fs_read = quota_read_nomount; -+ -+ log_debug("Creating quota ino=%lu, type=%d", qf_inum, type); -+ err = ext2fs_file_open(fs, qf_inum, h->qh_file_flags, &e2_file); -+ if (err) { -+ log_err("ext2fs_file_open failed: %d", err); -+ goto out_err; -+ } -+ h->qh_qf.e2_file = e2_file; -+ -+ h->qh_io_flags = 0; -+ h->qh_type = type; -+ h->qh_fmt = fmt; -+ memset(&h->qh_info, 0, sizeof(h->qh_info)); -+ h->qh_ops = "afile_ops_2; -+ -+ if (h->qh_ops->new_io && (h->qh_ops->new_io(h) < 0)) { -+ log_err("qh_ops->new_io failed"); -+ goto out_err1; -+ } -+ -+ return 0; -+ -+out_err1: -+ ext2fs_file_close(e2_file); -+out_err: -+ -+ if (qf_inum) -+ quota_inode_truncate(fs, qf_inum); -+ -+ return -1; -+} -+ -+/* -+ * Close quotafile and release handle -+ */ -+errcode_t quota_file_close(quota_ctx_t qctx, struct quota_handle *h) -+{ -+ if (h->qh_io_flags & IOFL_INFODIRTY) { -+ if (h->qh_ops->write_info && h->qh_ops->write_info(h) < 0) -+ return -1; -+ h->qh_io_flags &= ~IOFL_INFODIRTY; -+ } -+ -+ if (h->qh_ops->end_io && h->qh_ops->end_io(h) < 0) -+ return -1; -+ if (h->qh_qf.e2_file) { -+ __u64 new_size, size; -+ -+ new_size = compute_inode_size(h->qh_qf.fs, h->qh_qf.ino); -+ ext2fs_file_flush(h->qh_qf.e2_file); -+ if (ext2fs_file_get_lsize(h->qh_qf.e2_file, &size)) -+ new_size = 0; -+ if (size != new_size) -+ ext2fs_file_set_size2(h->qh_qf.e2_file, new_size); -+ ext2fs_file_close(h->qh_qf.e2_file); -+ } -+ if (qctx->quota_file[h->qh_type] == h) -+ ext2fs_free_mem(&qctx->quota_file[h->qh_type]); -+ return 0; -+} -+ -+/* -+ * Create empty quota structure -+ */ -+struct dquot *get_empty_dquot(void) -+{ -+ struct dquot *dquot; -+ -+ if (ext2fs_get_memzero(sizeof(struct dquot), &dquot)) { -+ log_err("Failed to allocate dquot"); -+ return NULL; -+ } -+ -+ dquot->dq_id = -1; -+ return dquot; -+} -diff --git a/lib/support/quotaio.h b/lib/support/quotaio.h -new file mode 100644 -index 0000000..9d580ae ---- /dev/null -+++ b/lib/support/quotaio.h -@@ -0,0 +1,223 @@ -+/** quotaio.h -+ * -+ * Interface to the quota library. -+ * -+ * The quota library provides interface for creating and updating the quota -+ * files and the ext4 superblock fields. It supports the new VFS_V1 quota -+ * format. The quota library also provides support for keeping track of quotas -+ * in memory. -+ * The typical way to use the quota library is as follows: -+ * { -+ * quota_ctx_t qctx; -+ * -+ * quota_init_context(&qctx, fs, -1); -+ * { -+ * quota_compute_usage(qctx, -1); -+ * AND/OR -+ * quota_data_add/quota_data_sub/quota_data_inodes(); -+ * } -+ * quota_write_inode(qctx, USRQUOTA); -+ * quota_write_inode(qctx, GRPQUOTA); -+ * quota_release_context(&qctx); -+ * } -+ * -+ * This initial version does not support reading the quota files. This support -+ * will be added in near future. -+ * -+ * Aditya Kali -+ * Header of IO operations for quota utilities -+ * -+ * Jan Kara -+ */ -+ -+#ifndef GUARD_QUOTAIO_H -+#define GUARD_QUOTAIO_H -+ -+#include -+#include -+#include -+ -+#include "ext2fs/ext2_fs.h" -+#include "ext2fs/ext2fs.h" -+#include "dqblk_v2.h" -+ -+typedef int64_t qsize_t; /* Type in which we store size limitations */ -+ -+#define MAXQUOTAS 2 -+#define USRQUOTA 0 -+#define GRPQUOTA 1 -+ -+typedef struct quota_ctx *quota_ctx_t; -+struct dict_t; -+ -+struct quota_ctx { -+ ext2_filsys fs; -+ struct dict_t *quota_dict[MAXQUOTAS]; -+ struct quota_handle *quota_file[MAXQUOTAS]; -+}; -+ -+/* -+ * Definitions of magics and versions of current quota files -+ */ -+#define INITQMAGICS {\ -+ 0xd9c01f11, /* USRQUOTA */\ -+ 0xd9c01927 /* GRPQUOTA */\ -+} -+ -+/* Size of blocks in which are counted size limits in generic utility parts */ -+#define QUOTABLOCK_BITS 10 -+#define QUOTABLOCK_SIZE (1 << QUOTABLOCK_BITS) -+#define toqb(x) (((x) + QUOTABLOCK_SIZE - 1) >> QUOTABLOCK_BITS) -+ -+/* Quota format type IDs */ -+#define QFMT_VFS_OLD 1 -+#define QFMT_VFS_V0 2 -+#define QFMT_VFS_V1 4 -+ -+/* -+ * The following constants define the default amount of time given a user -+ * before the soft limits are treated as hard limits (usually resulting -+ * in an allocation failure). The timer is started when the user crosses -+ * their soft limit, it is reset when they go below their soft limit. -+ */ -+#define MAX_IQ_TIME 604800 /* (7*24*60*60) 1 week */ -+#define MAX_DQ_TIME 604800 /* (7*24*60*60) 1 week */ -+ -+#define IOFL_INFODIRTY 0x01 /* Did info change? */ -+ -+struct quotafile_ops; -+ -+/* Generic information about quotafile */ -+struct util_dqinfo { -+ time_t dqi_bgrace; /* Block grace time for given quotafile */ -+ time_t dqi_igrace; /* Inode grace time for given quotafile */ -+ union { -+ struct v2_mem_dqinfo v2_mdqi; -+ } u; /* Format specific info about quotafile */ -+}; -+ -+struct quota_file { -+ ext2_filsys fs; -+ ext2_ino_t ino; -+ ext2_file_t e2_file; -+}; -+ -+/* Structure for one opened quota file */ -+struct quota_handle { -+ int qh_type; /* Type of quotafile */ -+ int qh_fmt; /* Quotafile format */ -+ int qh_file_flags; -+ int qh_io_flags; /* IO flags for file */ -+ struct quota_file qh_qf; -+ unsigned int (*e2fs_read)(struct quota_file *qf, ext2_loff_t offset, -+ void *buf, unsigned int size); -+ unsigned int (*e2fs_write)(struct quota_file *qf, ext2_loff_t offset, -+ void *buf, unsigned int size); -+ struct quotafile_ops *qh_ops; /* Operations on quotafile */ -+ struct util_dqinfo qh_info; /* Generic quotafile info */ -+}; -+ -+/* Utility quota block */ -+struct util_dqblk { -+ qsize_t dqb_ihardlimit; -+ qsize_t dqb_isoftlimit; -+ qsize_t dqb_curinodes; -+ qsize_t dqb_bhardlimit; -+ qsize_t dqb_bsoftlimit; -+ qsize_t dqb_curspace; -+ time_t dqb_btime; -+ time_t dqb_itime; -+ union { -+ struct v2_mem_dqblk v2_mdqb; -+ } u; /* Format specific dquot information */ -+}; -+ -+/* Structure for one loaded quota */ -+struct dquot { -+ struct dquot *dq_next; /* Pointer to next dquot in the list */ -+ qid_t dq_id; /* ID dquot belongs to */ -+ int dq_flags; /* Some flags for utils */ -+ struct quota_handle *dq_h; /* Handle of quotafile for this dquot */ -+ struct util_dqblk dq_dqb; /* Parsed data of dquot */ -+}; -+ -+#define DQF_SEEN 0x0001 -+ -+/* Structure of quotafile operations */ -+struct quotafile_ops { -+ /* Check whether quotafile is in our format */ -+ int (*check_file) (struct quota_handle *h, int type, int fmt); -+ /* Open quotafile */ -+ int (*init_io) (struct quota_handle *h); -+ /* Create new quotafile */ -+ int (*new_io) (struct quota_handle *h); -+ /* Write all changes and close quotafile */ -+ int (*end_io) (struct quota_handle *h); -+ /* Write info about quotafile */ -+ int (*write_info) (struct quota_handle *h); -+ /* Read dquot into memory */ -+ struct dquot *(*read_dquot) (struct quota_handle *h, qid_t id); -+ /* Write given dquot to disk */ -+ int (*commit_dquot) (struct dquot *dquot); -+ /* Scan quotafile and call callback on every structure */ -+ int (*scan_dquots) (struct quota_handle *h, -+ int (*process_dquot) (struct dquot *dquot, -+ void *data), -+ void *data); -+ /* Function to print format specific file information */ -+ int (*report) (struct quota_handle *h, int verbose); -+}; -+ -+/* This might go into a special header file but that sounds a bit silly... */ -+extern struct quotafile_ops quotafile_ops_meta; -+ -+/* Open existing quotafile of given type (and verify its format) on given -+ * filesystem. */ -+errcode_t quota_file_open(quota_ctx_t qctx, struct quota_handle *h, -+ ext2_ino_t qf_ino, int type, int fmt, int flags); -+ -+ -+/* Create new quotafile of specified format on given filesystem */ -+errcode_t quota_file_create(struct quota_handle *h, ext2_filsys fs, -+ int type, int fmt); -+ -+/* Close quotafile */ -+errcode_t quota_file_close(quota_ctx_t qctx, struct quota_handle *h); -+ -+/* Get empty quota structure */ -+struct dquot *get_empty_dquot(void); -+ -+errcode_t quota_inode_truncate(ext2_filsys fs, ext2_ino_t ino); -+ -+const char *type2name(int type); -+ -+void update_grace_times(struct dquot *q); -+ -+/* size for the buffer returned by quota_get_qf_name(); must be greater -+ than maxlen of extensions[] and fmtnames[] (plus 2) found in quotaio.c */ -+#define QUOTA_NAME_LEN 16 -+ -+const char *quota_get_qf_name(int type, int fmt, char *buf); -+ -+/* In mkquota.c */ -+errcode_t quota_init_context(quota_ctx_t *qctx, ext2_filsys fs, int qtype); -+void quota_data_inodes(quota_ctx_t qctx, struct ext2_inode *inode, ext2_ino_t ino, -+ int adjust); -+void quota_data_add(quota_ctx_t qctx, struct ext2_inode *inode, ext2_ino_t ino, -+ qsize_t space); -+void quota_data_sub(quota_ctx_t qctx, struct ext2_inode *inode, ext2_ino_t ino, -+ qsize_t space); -+errcode_t quota_write_inode(quota_ctx_t qctx, int qtype); -+errcode_t quota_update_limits(quota_ctx_t qctx, ext2_ino_t qf_ino, int type); -+errcode_t quota_compute_usage(quota_ctx_t qctx); -+void quota_release_context(quota_ctx_t *qctx); -+ -+errcode_t quota_remove_inode(ext2_filsys fs, int qtype); -+int quota_file_exists(ext2_filsys fs, int qtype); -+void quota_set_sb_inum(ext2_filsys fs, ext2_ino_t ino, int qtype); -+errcode_t quota_compare_and_update(quota_ctx_t qctx, int qtype, -+ int *usage_inconsistent); -+ -+ -+ -+#endif /* GUARD_QUOTAIO_H */ -diff --git a/lib/support/quotaio_tree.c b/lib/support/quotaio_tree.c -new file mode 100644 -index 0000000..e7f3e95 ---- /dev/null -+++ b/lib/support/quotaio_tree.c -@@ -0,0 +1,662 @@ -+/* -+ * Implementation of new quotafile format -+ * -+ * Jan Kara - sponsored by SuSE CR -+ */ -+ -+#include "config.h" -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "common.h" -+#include "quotaio_tree.h" -+#include "quotaio.h" -+ -+typedef char *dqbuf_t; -+ -+#define freedqbuf(buf) ext2fs_free_mem(&buf) -+ -+static inline dqbuf_t getdqbuf(void) -+{ -+ dqbuf_t buf; -+ if (ext2fs_get_memzero(QT_BLKSIZE, &buf)) { -+ log_err("Failed to allocate dqbuf"); -+ return NULL; -+ } -+ -+ return buf; -+} -+ -+/* Is given dquot empty? */ -+int qtree_entry_unused(struct qtree_mem_dqinfo *info, char *disk) -+{ -+ int i; -+ -+ for (i = 0; i < info->dqi_entry_size; i++) -+ if (disk[i]) -+ return 0; -+ return 1; -+} -+ -+int qtree_dqstr_in_blk(struct qtree_mem_dqinfo *info) -+{ -+ return (QT_BLKSIZE - sizeof(struct qt_disk_dqdbheader)) / -+ info->dqi_entry_size; -+} -+ -+static int get_index(qid_t id, int depth) -+{ -+ return (id >> ((QT_TREEDEPTH - depth - 1) * 8)) & 0xff; -+} -+ -+static inline void mark_quotafile_info_dirty(struct quota_handle *h) -+{ -+ h->qh_io_flags |= IOFL_INFODIRTY; -+} -+ -+/* Read given block */ -+static void read_blk(struct quota_handle *h, unsigned int blk, dqbuf_t buf) -+{ -+ int err; -+ -+ err = h->e2fs_read(&h->qh_qf, blk << QT_BLKSIZE_BITS, buf, -+ QT_BLKSIZE); -+ if (err < 0) -+ log_err("Cannot read block %u: %s", blk, strerror(errno)); -+ else if (err != QT_BLKSIZE) -+ memset(buf + err, 0, QT_BLKSIZE - err); -+} -+ -+/* Write block */ -+static int write_blk(struct quota_handle *h, unsigned int blk, dqbuf_t buf) -+{ -+ int err; -+ -+ err = h->e2fs_write(&h->qh_qf, blk << QT_BLKSIZE_BITS, buf, -+ QT_BLKSIZE); -+ if (err < 0 && errno != ENOSPC) -+ log_err("Cannot write block (%u): %s", blk, strerror(errno)); -+ if (err != QT_BLKSIZE) -+ return -ENOSPC; -+ return 0; -+} -+ -+/* Get free block in file (either from free list or create new one) */ -+static int get_free_dqblk(struct quota_handle *h) -+{ -+ dqbuf_t buf = getdqbuf(); -+ struct qt_disk_dqdbheader *dh = (struct qt_disk_dqdbheader *)buf; -+ struct qtree_mem_dqinfo *info = &h->qh_info.u.v2_mdqi.dqi_qtree; -+ int blk; -+ -+ if (!buf) -+ return -ENOMEM; -+ -+ if (info->dqi_free_blk) { -+ blk = info->dqi_free_blk; -+ read_blk(h, blk, buf); -+ info->dqi_free_blk = ext2fs_le32_to_cpu(dh->dqdh_next_free); -+ } else { -+ memset(buf, 0, QT_BLKSIZE); -+ /* Assure block allocation... */ -+ if (write_blk(h, info->dqi_blocks, buf) < 0) { -+ freedqbuf(buf); -+ log_err("Cannot allocate new quota block " -+ "(out of disk space)."); -+ return -ENOSPC; -+ } -+ blk = info->dqi_blocks++; -+ } -+ mark_quotafile_info_dirty(h); -+ freedqbuf(buf); -+ return blk; -+} -+ -+/* Put given block to free list */ -+static void put_free_dqblk(struct quota_handle *h, dqbuf_t buf, -+ unsigned int blk) -+{ -+ struct qt_disk_dqdbheader *dh = (struct qt_disk_dqdbheader *)buf; -+ struct qtree_mem_dqinfo *info = &h->qh_info.u.v2_mdqi.dqi_qtree; -+ -+ dh->dqdh_next_free = ext2fs_cpu_to_le32(info->dqi_free_blk); -+ dh->dqdh_prev_free = ext2fs_cpu_to_le32(0); -+ dh->dqdh_entries = ext2fs_cpu_to_le16(0); -+ info->dqi_free_blk = blk; -+ mark_quotafile_info_dirty(h); -+ write_blk(h, blk, buf); -+} -+ -+/* Remove given block from the list of blocks with free entries */ -+static void remove_free_dqentry(struct quota_handle *h, dqbuf_t buf, -+ unsigned int blk) -+{ -+ dqbuf_t tmpbuf = getdqbuf(); -+ struct qt_disk_dqdbheader *dh = (struct qt_disk_dqdbheader *)buf; -+ unsigned int nextblk = ext2fs_le32_to_cpu(dh->dqdh_next_free), prevblk = -+ -+ ext2fs_le32_to_cpu(dh->dqdh_prev_free); -+ -+ if (!tmpbuf) -+ return; -+ -+ if (nextblk) { -+ read_blk(h, nextblk, tmpbuf); -+ ((struct qt_disk_dqdbheader *)tmpbuf)->dqdh_prev_free = -+ dh->dqdh_prev_free; -+ write_blk(h, nextblk, tmpbuf); -+ } -+ if (prevblk) { -+ read_blk(h, prevblk, tmpbuf); -+ ((struct qt_disk_dqdbheader *)tmpbuf)->dqdh_next_free = -+ dh->dqdh_next_free; -+ write_blk(h, prevblk, tmpbuf); -+ } else { -+ h->qh_info.u.v2_mdqi.dqi_qtree.dqi_free_entry = nextblk; -+ mark_quotafile_info_dirty(h); -+ } -+ freedqbuf(tmpbuf); -+ dh->dqdh_next_free = dh->dqdh_prev_free = ext2fs_cpu_to_le32(0); -+ write_blk(h, blk, buf); /* No matter whether write succeeds -+ * block is out of list */ -+} -+ -+/* Insert given block to the beginning of list with free entries */ -+static void insert_free_dqentry(struct quota_handle *h, dqbuf_t buf, -+ unsigned int blk) -+{ -+ dqbuf_t tmpbuf = getdqbuf(); -+ struct qt_disk_dqdbheader *dh = (struct qt_disk_dqdbheader *)buf; -+ struct qtree_mem_dqinfo *info = &h->qh_info.u.v2_mdqi.dqi_qtree; -+ -+ if (!tmpbuf) -+ return; -+ -+ dh->dqdh_next_free = ext2fs_cpu_to_le32(info->dqi_free_entry); -+ dh->dqdh_prev_free = ext2fs_cpu_to_le32(0); -+ write_blk(h, blk, buf); -+ if (info->dqi_free_entry) { -+ read_blk(h, info->dqi_free_entry, tmpbuf); -+ ((struct qt_disk_dqdbheader *)tmpbuf)->dqdh_prev_free = -+ ext2fs_cpu_to_le32(blk); -+ write_blk(h, info->dqi_free_entry, tmpbuf); -+ } -+ freedqbuf(tmpbuf); -+ info->dqi_free_entry = blk; -+ mark_quotafile_info_dirty(h); -+} -+ -+/* Find space for dquot */ -+static unsigned int find_free_dqentry(struct quota_handle *h, -+ struct dquot *dquot, int *err) -+{ -+ int blk, i; -+ struct qt_disk_dqdbheader *dh; -+ struct qtree_mem_dqinfo *info = &h->qh_info.u.v2_mdqi.dqi_qtree; -+ char *ddquot; -+ dqbuf_t buf; -+ -+ *err = 0; -+ buf = getdqbuf(); -+ if (!buf) { -+ *err = -ENOMEM; -+ return 0; -+ } -+ -+ dh = (struct qt_disk_dqdbheader *)buf; -+ if (info->dqi_free_entry) { -+ blk = info->dqi_free_entry; -+ read_blk(h, blk, buf); -+ } else { -+ blk = get_free_dqblk(h); -+ if (blk < 0) { -+ freedqbuf(buf); -+ *err = blk; -+ return 0; -+ } -+ memset(buf, 0, QT_BLKSIZE); -+ info->dqi_free_entry = blk; -+ mark_quotafile_info_dirty(h); -+ } -+ -+ /* Block will be full? */ -+ if (ext2fs_le16_to_cpu(dh->dqdh_entries) + 1 >= -+ qtree_dqstr_in_blk(info)) -+ remove_free_dqentry(h, buf, blk); -+ -+ dh->dqdh_entries = -+ ext2fs_cpu_to_le16(ext2fs_le16_to_cpu(dh->dqdh_entries) + 1); -+ /* Find free structure in block */ -+ ddquot = buf + sizeof(struct qt_disk_dqdbheader); -+ for (i = 0; -+ i < qtree_dqstr_in_blk(info) && !qtree_entry_unused(info, ddquot); -+ i++) -+ ddquot += info->dqi_entry_size; -+ -+ if (i == qtree_dqstr_in_blk(info)) -+ log_err("find_free_dqentry(): Data block full unexpectedly."); -+ -+ write_blk(h, blk, buf); -+ dquot->dq_dqb.u.v2_mdqb.dqb_off = -+ (blk << QT_BLKSIZE_BITS) + sizeof(struct qt_disk_dqdbheader) + -+ i * info->dqi_entry_size; -+ freedqbuf(buf); -+ return blk; -+} -+ -+/* Insert reference to structure into the trie */ -+static int do_insert_tree(struct quota_handle *h, struct dquot *dquot, -+ unsigned int * treeblk, int depth) -+{ -+ dqbuf_t buf; -+ int newson = 0, newact = 0; -+ __le32 *ref; -+ unsigned int newblk; -+ int ret = 0; -+ -+ log_debug("inserting in tree: treeblk=%u, depth=%d", *treeblk, depth); -+ buf = getdqbuf(); -+ if (!buf) -+ return -ENOMEM; -+ -+ if (!*treeblk) { -+ ret = get_free_dqblk(h); -+ if (ret < 0) -+ goto out_buf; -+ *treeblk = ret; -+ memset(buf, 0, QT_BLKSIZE); -+ newact = 1; -+ } else { -+ read_blk(h, *treeblk, buf); -+ } -+ -+ ref = (__le32 *) buf; -+ newblk = ext2fs_le32_to_cpu(ref[get_index(dquot->dq_id, depth)]); -+ if (!newblk) -+ newson = 1; -+ if (depth == QT_TREEDEPTH - 1) { -+ if (newblk) -+ log_err("Inserting already present quota entry " -+ "(block %u).", -+ ref[get_index(dquot->dq_id, depth)]); -+ newblk = find_free_dqentry(h, dquot, &ret); -+ } else { -+ ret = do_insert_tree(h, dquot, &newblk, depth + 1); -+ } -+ -+ if (newson && ret >= 0) { -+ ref[get_index(dquot->dq_id, depth)] = -+ ext2fs_cpu_to_le32(newblk); -+ write_blk(h, *treeblk, buf); -+ } else if (newact && ret < 0) { -+ put_free_dqblk(h, buf, *treeblk); -+ } -+ -+out_buf: -+ freedqbuf(buf); -+ return ret; -+} -+ -+/* Wrapper for inserting quota structure into tree */ -+static void dq_insert_tree(struct quota_handle *h, struct dquot *dquot) -+{ -+ unsigned int tmp = QT_TREEOFF; -+ -+ if (do_insert_tree(h, dquot, &tmp, 0) < 0) -+ log_err("Cannot write quota (id %u): %s", -+ (unsigned int) dquot->dq_id, strerror(errno)); -+} -+ -+/* Write dquot to file */ -+void qtree_write_dquot(struct dquot *dquot) -+{ -+ ssize_t ret; -+ char *ddquot; -+ struct quota_handle *h = dquot->dq_h; -+ struct qtree_mem_dqinfo *info = -+ &dquot->dq_h->qh_info.u.v2_mdqi.dqi_qtree; -+ log_debug("writing ddquot 1: off=%llu, info->dqi_entry_size=%u", -+ dquot->dq_dqb.u.v2_mdqb.dqb_off, -+ info->dqi_entry_size); -+ ret = ext2fs_get_mem(info->dqi_entry_size, &ddquot); -+ if (ret) { -+ errno = ENOMEM; -+ log_err("Quota write failed (id %u): %s", -+ (unsigned int)dquot->dq_id, strerror(errno)); -+ return; -+ } -+ memset(ddquot, 0, info->dqi_entry_size); -+ -+ if (!dquot->dq_dqb.u.v2_mdqb.dqb_off) -+ dq_insert_tree(dquot->dq_h, dquot); -+ info->dqi_ops->mem2disk_dqblk(ddquot, dquot); -+ log_debug("writing ddquot 2: off=%llu, info->dqi_entry_size=%u", -+ dquot->dq_dqb.u.v2_mdqb.dqb_off, -+ info->dqi_entry_size); -+ ret = h->e2fs_write(&h->qh_qf, dquot->dq_dqb.u.v2_mdqb.dqb_off, ddquot, -+ info->dqi_entry_size); -+ -+ if (ret != info->dqi_entry_size) { -+ if (ret > 0) -+ errno = ENOSPC; -+ log_err("Quota write failed (id %u): %s", -+ (unsigned int)dquot->dq_id, strerror(errno)); -+ } -+ ext2fs_free_mem(&ddquot); -+} -+ -+/* Free dquot entry in data block */ -+static void free_dqentry(struct quota_handle *h, struct dquot *dquot, -+ unsigned int blk) -+{ -+ struct qt_disk_dqdbheader *dh; -+ struct qtree_mem_dqinfo *info = &h->qh_info.u.v2_mdqi.dqi_qtree; -+ dqbuf_t buf = getdqbuf(); -+ -+ if (!buf) -+ return; -+ -+ if (dquot->dq_dqb.u.v2_mdqb.dqb_off >> QT_BLKSIZE_BITS != blk) -+ log_err("Quota structure has offset to other block (%u) " -+ "than it should (%u).", blk, -+ (unsigned int) (dquot->dq_dqb.u.v2_mdqb.dqb_off >> -+ QT_BLKSIZE_BITS)); -+ -+ read_blk(h, blk, buf); -+ dh = (struct qt_disk_dqdbheader *)buf; -+ dh->dqdh_entries = -+ ext2fs_cpu_to_le16(ext2fs_le16_to_cpu(dh->dqdh_entries) - 1); -+ -+ if (!ext2fs_le16_to_cpu(dh->dqdh_entries)) { /* Block got free? */ -+ remove_free_dqentry(h, buf, blk); -+ put_free_dqblk(h, buf, blk); -+ } else { -+ memset(buf + (dquot->dq_dqb.u.v2_mdqb.dqb_off & -+ ((1 << QT_BLKSIZE_BITS) - 1)), -+ 0, info->dqi_entry_size); -+ -+ /* First free entry? */ -+ if (ext2fs_le16_to_cpu(dh->dqdh_entries) == -+ qtree_dqstr_in_blk(info) - 1) -+ /* This will also write data block */ -+ insert_free_dqentry(h, buf, blk); -+ else -+ write_blk(h, blk, buf); -+ } -+ dquot->dq_dqb.u.v2_mdqb.dqb_off = 0; -+ freedqbuf(buf); -+} -+ -+/* Remove reference to dquot from tree */ -+static void remove_tree(struct quota_handle *h, struct dquot *dquot, -+ unsigned int * blk, int depth) -+{ -+ dqbuf_t buf = getdqbuf(); -+ unsigned int newblk; -+ __le32 *ref = (__le32 *) buf; -+ -+ if (!buf) -+ return; -+ -+ read_blk(h, *blk, buf); -+ newblk = ext2fs_le32_to_cpu(ref[get_index(dquot->dq_id, depth)]); -+ if (depth == QT_TREEDEPTH - 1) { -+ free_dqentry(h, dquot, newblk); -+ newblk = 0; -+ } else { -+ remove_tree(h, dquot, &newblk, depth + 1); -+ } -+ -+ if (!newblk) { -+ int i; -+ -+ ref[get_index(dquot->dq_id, depth)] = ext2fs_cpu_to_le32(0); -+ -+ /* Block got empty? */ -+ for (i = 0; i < QT_BLKSIZE && !buf[i]; i++); -+ -+ /* Don't put the root block into the free block list */ -+ if (i == QT_BLKSIZE && *blk != QT_TREEOFF) { -+ put_free_dqblk(h, buf, *blk); -+ *blk = 0; -+ } else { -+ write_blk(h, *blk, buf); -+ } -+ } -+ freedqbuf(buf); -+} -+ -+/* Delete dquot from tree */ -+void qtree_delete_dquot(struct dquot *dquot) -+{ -+ unsigned int tmp = QT_TREEOFF; -+ -+ if (!dquot->dq_dqb.u.v2_mdqb.dqb_off) /* Even not allocated? */ -+ return; -+ remove_tree(dquot->dq_h, dquot, &tmp, 0); -+} -+ -+/* Find entry in block */ -+static ext2_loff_t find_block_dqentry(struct quota_handle *h, -+ struct dquot *dquot, unsigned int blk) -+{ -+ struct qtree_mem_dqinfo *info = &h->qh_info.u.v2_mdqi.dqi_qtree; -+ dqbuf_t buf = getdqbuf(); -+ int i; -+ char *ddquot = buf + sizeof(struct qt_disk_dqdbheader); -+ -+ if (!buf) -+ return -ENOMEM; -+ -+ read_blk(h, blk, buf); -+ for (i = 0; -+ i < qtree_dqstr_in_blk(info) && !info->dqi_ops->is_id(ddquot, dquot); -+ i++) -+ ddquot += info->dqi_entry_size; -+ -+ if (i == qtree_dqstr_in_blk(info)) -+ log_err("Quota for id %u referenced but not present.", -+ dquot->dq_id); -+ freedqbuf(buf); -+ return (blk << QT_BLKSIZE_BITS) + sizeof(struct qt_disk_dqdbheader) + -+ i * info->dqi_entry_size; -+} -+ -+/* Find entry for given id in the tree */ -+static ext2_loff_t find_tree_dqentry(struct quota_handle *h, -+ struct dquot *dquot, -+ unsigned int blk, int depth) -+{ -+ dqbuf_t buf = getdqbuf(); -+ ext2_loff_t ret = 0; -+ __le32 *ref = (__le32 *) buf; -+ -+ if (!buf) -+ return -ENOMEM; -+ -+ read_blk(h, blk, buf); -+ ret = 0; -+ blk = ext2fs_le32_to_cpu(ref[get_index(dquot->dq_id, depth)]); -+ if (!blk) /* No reference? */ -+ goto out_buf; -+ if (depth < QT_TREEDEPTH - 1) -+ ret = find_tree_dqentry(h, dquot, blk, depth + 1); -+ else -+ ret = find_block_dqentry(h, dquot, blk); -+out_buf: -+ freedqbuf(buf); -+ return ret; -+} -+ -+/* Find entry for given id in the tree - wrapper function */ -+static inline ext2_loff_t find_dqentry(struct quota_handle *h, -+ struct dquot *dquot) -+{ -+ return find_tree_dqentry(h, dquot, QT_TREEOFF, 0); -+} -+ -+/* -+ * Read dquot from disk. -+ */ -+struct dquot *qtree_read_dquot(struct quota_handle *h, qid_t id) -+{ -+ struct qtree_mem_dqinfo *info = &h->qh_info.u.v2_mdqi.dqi_qtree; -+ ext2_loff_t offset; -+ ssize_t ret; -+ char *ddquot; -+ struct dquot *dquot = get_empty_dquot(); -+ -+ if (!dquot) -+ return NULL; -+ if (ext2fs_get_mem(info->dqi_entry_size, &ddquot)) { -+ ext2fs_free_mem(&dquot); -+ return NULL; -+ } -+ -+ dquot->dq_id = id; -+ dquot->dq_h = h; -+ dquot->dq_dqb.u.v2_mdqb.dqb_off = 0; -+ memset(&dquot->dq_dqb, 0, sizeof(struct util_dqblk)); -+ -+ offset = find_dqentry(h, dquot); -+ if (offset > 0) { -+ dquot->dq_dqb.u.v2_mdqb.dqb_off = offset; -+ ret = h->e2fs_read(&h->qh_qf, offset, ddquot, -+ info->dqi_entry_size); -+ if (ret != info->dqi_entry_size) { -+ if (ret > 0) -+ errno = EIO; -+ log_err("Cannot read quota structure for id %u: %s", -+ dquot->dq_id, strerror(errno)); -+ } -+ info->dqi_ops->disk2mem_dqblk(dquot, ddquot); -+ } -+ ext2fs_free_mem(&ddquot); -+ return dquot; -+} -+ -+/* -+ * Scan all dquots in file and call callback on each -+ */ -+#define set_bit(bmp, ind) ((bmp)[(ind) >> 3] |= (1 << ((ind) & 7))) -+#define get_bit(bmp, ind) ((bmp)[(ind) >> 3] & (1 << ((ind) & 7))) -+ -+static int report_block(struct dquot *dquot, unsigned int blk, char *bitmap, -+ int (*process_dquot) (struct dquot *, void *), -+ void *data) -+{ -+ struct qtree_mem_dqinfo *info = -+ &dquot->dq_h->qh_info.u.v2_mdqi.dqi_qtree; -+ dqbuf_t buf = getdqbuf(); -+ struct qt_disk_dqdbheader *dh; -+ char *ddata; -+ int entries, i; -+ -+ if (!buf) -+ return 0; -+ -+ set_bit(bitmap, blk); -+ read_blk(dquot->dq_h, blk, buf); -+ dh = (struct qt_disk_dqdbheader *)buf; -+ ddata = buf + sizeof(struct qt_disk_dqdbheader); -+ entries = ext2fs_le16_to_cpu(dh->dqdh_entries); -+ for (i = 0; i < qtree_dqstr_in_blk(info); -+ i++, ddata += info->dqi_entry_size) -+ if (!qtree_entry_unused(info, ddata)) { -+ dquot->dq_dqb.u.v2_mdqb.dqb_off = -+ (blk << QT_BLKSIZE_BITS) + -+ sizeof(struct qt_disk_dqdbheader) + -+ i * info->dqi_entry_size; -+ info->dqi_ops->disk2mem_dqblk(dquot, ddata); -+ if (process_dquot(dquot, data) < 0) -+ break; -+ } -+ freedqbuf(buf); -+ return entries; -+} -+ -+static void check_reference(struct quota_handle *h, unsigned int blk) -+{ -+ if (blk >= h->qh_info.u.v2_mdqi.dqi_qtree.dqi_blocks) -+ log_err("Illegal reference (%u >= %u) in %s quota file. " -+ "Quota file is probably corrupted.\n" -+ "Please run e2fsck (8) to fix it.", -+ blk, -+ h->qh_info.u.v2_mdqi.dqi_qtree.dqi_blocks, -+ type2name(h->qh_type)); -+} -+ -+static int report_tree(struct dquot *dquot, unsigned int blk, int depth, -+ char *bitmap, -+ int (*process_dquot) (struct dquot *, void *), -+ void *data) -+{ -+ int entries = 0, i; -+ dqbuf_t buf = getdqbuf(); -+ __le32 *ref = (__le32 *) buf; -+ -+ if (!buf) -+ return 0; -+ -+ read_blk(dquot->dq_h, blk, buf); -+ if (depth == QT_TREEDEPTH - 1) { -+ for (i = 0; i < QT_BLKSIZE >> 2; i++) { -+ blk = ext2fs_le32_to_cpu(ref[i]); -+ check_reference(dquot->dq_h, blk); -+ if (blk && !get_bit(bitmap, blk)) -+ entries += report_block(dquot, blk, bitmap, -+ process_dquot, data); -+ } -+ } else { -+ for (i = 0; i < QT_BLKSIZE >> 2; i++) { -+ blk = ext2fs_le32_to_cpu(ref[i]); -+ if (blk) { -+ check_reference(dquot->dq_h, blk); -+ entries += report_tree(dquot, blk, depth + 1, -+ bitmap, process_dquot, -+ data); -+ } -+ } -+ } -+ freedqbuf(buf); -+ return entries; -+} -+ -+static unsigned int find_set_bits(char *bmp, int blocks) -+{ -+ unsigned int i, used = 0; -+ -+ for (i = 0; i < blocks; i++) -+ if (get_bit(bmp, i)) -+ used++; -+ return used; -+} -+ -+int qtree_scan_dquots(struct quota_handle *h, -+ int (*process_dquot) (struct dquot *, void *), -+ void *data) -+{ -+ char *bitmap; -+ struct v2_mem_dqinfo *v2info = &h->qh_info.u.v2_mdqi; -+ struct qtree_mem_dqinfo *info = &v2info->dqi_qtree; -+ struct dquot *dquot = get_empty_dquot(); -+ -+ if (!dquot) -+ return -1; -+ -+ dquot->dq_h = h; -+ if (ext2fs_get_memzero((info->dqi_blocks + 7) >> 3, &bitmap)) { -+ ext2fs_free_mem(&dquot); -+ return -1; -+ } -+ v2info->dqi_used_entries = report_tree(dquot, QT_TREEOFF, 0, bitmap, -+ process_dquot, data); -+ v2info->dqi_data_blocks = find_set_bits(bitmap, info->dqi_blocks); -+ ext2fs_free_mem(&bitmap); -+ ext2fs_free_mem(&dquot); -+ return 0; -+} -diff --git a/lib/support/quotaio_tree.h b/lib/support/quotaio_tree.h -new file mode 100644 -index 0000000..0db0ca1 ---- /dev/null -+++ b/lib/support/quotaio_tree.h -@@ -0,0 +1,64 @@ -+/* -+ * Definitions of structures for vfsv0 quota format -+ */ -+ -+#ifndef _LINUX_QUOTA_TREE_H -+#define _LINUX_QUOTA_TREE_H -+ -+#include -+ -+typedef __u32 qid_t; /* Type in which we store ids in memory */ -+ -+#define QT_TREEOFF 1 /* Offset of tree in file in blocks */ -+#define QT_TREEDEPTH 4 /* Depth of quota tree */ -+#define QT_BLKSIZE_BITS 10 -+#define QT_BLKSIZE (1 << QT_BLKSIZE_BITS) /* Size of block with quota -+ * structures */ -+ -+/* -+ * Structure of header of block with quota structures. It is padded to 16 bytes -+ * so there will be space for exactly 21 quota-entries in a block -+ */ -+struct qt_disk_dqdbheader { -+ __le32 dqdh_next_free; /* Number of next block with free -+ * entry */ -+ __le32 dqdh_prev_free; /* Number of previous block with free -+ * entry */ -+ __le16 dqdh_entries; /* Number of valid entries in block */ -+ __le16 dqdh_pad1; -+ __le32 dqdh_pad2; -+} __attribute__ ((packed)); -+ -+struct dquot; -+struct quota_handle; -+ -+/* Operations */ -+struct qtree_fmt_operations { -+ /* Convert given entry from in memory format to disk one */ -+ void (*mem2disk_dqblk)(void *disk, struct dquot *dquot); -+ /* Convert given entry from disk format to in memory one */ -+ void (*disk2mem_dqblk)(struct dquot *dquot, void *disk); -+ /* Is this structure for given id? */ -+ int (*is_id)(void *disk, struct dquot *dquot); -+}; -+ -+/* Inmemory copy of version specific information */ -+struct qtree_mem_dqinfo { -+ unsigned int dqi_blocks; /* # of blocks in quota file */ -+ unsigned int dqi_free_blk; /* First block in list of free blocks */ -+ unsigned int dqi_free_entry; /* First block with free entry */ -+ unsigned int dqi_entry_size; /* Size of quota entry in quota file */ -+ struct qtree_fmt_operations *dqi_ops; /* Operations for entry -+ * manipulation */ -+}; -+ -+void qtree_write_dquot(struct dquot *dquot); -+struct dquot *qtree_read_dquot(struct quota_handle *h, qid_t id); -+void qtree_delete_dquot(struct dquot *dquot); -+int qtree_entry_unused(struct qtree_mem_dqinfo *info, char *disk); -+int qtree_scan_dquots(struct quota_handle *h, -+ int (*process_dquot) (struct dquot *, void *), void *data); -+ -+int qtree_dqstr_in_blk(struct qtree_mem_dqinfo *info); -+ -+#endif /* _LINUX_QUOTAIO_TREE_H */ -diff --git a/lib/support/quotaio_v2.c b/lib/support/quotaio_v2.c -new file mode 100644 -index 0000000..38be2a3 ---- /dev/null -+++ b/lib/support/quotaio_v2.c -@@ -0,0 +1,285 @@ -+/* -+ * Implementation of new quotafile format -+ * -+ * Jan Kara - sponsored by SuSE CR -+ */ -+ -+#include "config.h" -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "common.h" -+#include "quotaio_v2.h" -+#include "dqblk_v2.h" -+#include "quotaio.h" -+#include "quotaio_tree.h" -+ -+static int v2_check_file(struct quota_handle *h, int type, int fmt); -+static int v2_init_io(struct quota_handle *h); -+static int v2_new_io(struct quota_handle *h); -+static int v2_write_info(struct quota_handle *h); -+static struct dquot *v2_read_dquot(struct quota_handle *h, qid_t id); -+static int v2_commit_dquot(struct dquot *dquot); -+static int v2_scan_dquots(struct quota_handle *h, -+ int (*process_dquot) (struct dquot *dquot, -+ void *data), -+ void *data); -+static int v2_report(struct quota_handle *h, int verbose); -+ -+struct quotafile_ops quotafile_ops_2 = { -+ .check_file = v2_check_file, -+ .init_io = v2_init_io, -+ .new_io = v2_new_io, -+ .write_info = v2_write_info, -+ .read_dquot = v2_read_dquot, -+ .commit_dquot = v2_commit_dquot, -+ .scan_dquots = v2_scan_dquots, -+ .report = v2_report, -+}; -+ -+/* -+ * Copy dquot from disk to memory -+ */ -+static void v2r1_disk2memdqblk(struct dquot *dquot, void *dp) -+{ -+ struct util_dqblk *m = &dquot->dq_dqb; -+ struct v2r1_disk_dqblk *d = dp, empty; -+ -+ dquot->dq_id = ext2fs_le32_to_cpu(d->dqb_id); -+ m->dqb_ihardlimit = ext2fs_le64_to_cpu(d->dqb_ihardlimit); -+ m->dqb_isoftlimit = ext2fs_le64_to_cpu(d->dqb_isoftlimit); -+ m->dqb_bhardlimit = ext2fs_le64_to_cpu(d->dqb_bhardlimit); -+ m->dqb_bsoftlimit = ext2fs_le64_to_cpu(d->dqb_bsoftlimit); -+ m->dqb_curinodes = ext2fs_le64_to_cpu(d->dqb_curinodes); -+ m->dqb_curspace = ext2fs_le64_to_cpu(d->dqb_curspace); -+ m->dqb_itime = ext2fs_le64_to_cpu(d->dqb_itime); -+ m->dqb_btime = ext2fs_le64_to_cpu(d->dqb_btime); -+ -+ memset(&empty, 0, sizeof(struct v2r1_disk_dqblk)); -+ empty.dqb_itime = ext2fs_cpu_to_le64(1); -+ if (!memcmp(&empty, dp, sizeof(struct v2r1_disk_dqblk))) -+ m->dqb_itime = 0; -+} -+ -+/* -+ * Copy dquot from memory to disk -+ */ -+static void v2r1_mem2diskdqblk(void *dp, struct dquot *dquot) -+{ -+ struct util_dqblk *m = &dquot->dq_dqb; -+ struct v2r1_disk_dqblk *d = dp; -+ -+ d->dqb_ihardlimit = ext2fs_cpu_to_le64(m->dqb_ihardlimit); -+ d->dqb_isoftlimit = ext2fs_cpu_to_le64(m->dqb_isoftlimit); -+ d->dqb_bhardlimit = ext2fs_cpu_to_le64(m->dqb_bhardlimit); -+ d->dqb_bsoftlimit = ext2fs_cpu_to_le64(m->dqb_bsoftlimit); -+ d->dqb_curinodes = ext2fs_cpu_to_le64(m->dqb_curinodes); -+ d->dqb_curspace = ext2fs_cpu_to_le64(m->dqb_curspace); -+ d->dqb_itime = ext2fs_cpu_to_le64(m->dqb_itime); -+ d->dqb_btime = ext2fs_cpu_to_le64(m->dqb_btime); -+ d->dqb_id = ext2fs_cpu_to_le32(dquot->dq_id); -+ if (qtree_entry_unused(&dquot->dq_h->qh_info.u.v2_mdqi.dqi_qtree, dp)) -+ d->dqb_itime = ext2fs_cpu_to_le64(1); -+} -+ -+static int v2r1_is_id(void *dp, struct dquot *dquot) -+{ -+ struct v2r1_disk_dqblk *d = dp; -+ struct qtree_mem_dqinfo *info = -+ &dquot->dq_h->qh_info.u.v2_mdqi.dqi_qtree; -+ -+ if (qtree_entry_unused(info, dp)) -+ return 0; -+ return ext2fs_le32_to_cpu(d->dqb_id) == dquot->dq_id; -+} -+ -+static struct qtree_fmt_operations v2r1_fmt_ops = { -+ .mem2disk_dqblk = v2r1_mem2diskdqblk, -+ .disk2mem_dqblk = v2r1_disk2memdqblk, -+ .is_id = v2r1_is_id, -+}; -+ -+/* -+ * Copy dqinfo from disk to memory -+ */ -+static inline void v2_disk2memdqinfo(struct util_dqinfo *m, -+ struct v2_disk_dqinfo *d) -+{ -+ m->dqi_bgrace = ext2fs_le32_to_cpu(d->dqi_bgrace); -+ m->dqi_igrace = ext2fs_le32_to_cpu(d->dqi_igrace); -+ m->u.v2_mdqi.dqi_flags = ext2fs_le32_to_cpu(d->dqi_flags) & V2_DQF_MASK; -+ m->u.v2_mdqi.dqi_qtree.dqi_blocks = ext2fs_le32_to_cpu(d->dqi_blocks); -+ m->u.v2_mdqi.dqi_qtree.dqi_free_blk = -+ ext2fs_le32_to_cpu(d->dqi_free_blk); -+ m->u.v2_mdqi.dqi_qtree.dqi_free_entry = -+ ext2fs_le32_to_cpu(d->dqi_free_entry); -+} -+ -+/* -+ * Copy dqinfo from memory to disk -+ */ -+static inline void v2_mem2diskdqinfo(struct v2_disk_dqinfo *d, -+ struct util_dqinfo *m) -+{ -+ d->dqi_bgrace = ext2fs_cpu_to_le32(m->dqi_bgrace); -+ d->dqi_igrace = ext2fs_cpu_to_le32(m->dqi_igrace); -+ d->dqi_flags = ext2fs_cpu_to_le32(m->u.v2_mdqi.dqi_flags & V2_DQF_MASK); -+ d->dqi_blocks = ext2fs_cpu_to_le32(m->u.v2_mdqi.dqi_qtree.dqi_blocks); -+ d->dqi_free_blk = -+ ext2fs_cpu_to_le32(m->u.v2_mdqi.dqi_qtree.dqi_free_blk); -+ d->dqi_free_entry = -+ ext2fs_cpu_to_le32(m->u.v2_mdqi.dqi_qtree.dqi_free_entry); -+} -+ -+static int v2_read_header(struct quota_handle *h, struct v2_disk_dqheader *dqh) -+{ -+ if (h->e2fs_read(&h->qh_qf, 0, dqh, sizeof(struct v2_disk_dqheader)) != -+ sizeof(struct v2_disk_dqheader)) -+ return 0; -+ -+ return 1; -+} -+ -+/* -+ * Check whether given quota file is in our format -+ */ -+static int v2_check_file(struct quota_handle *h, int type, int fmt) -+{ -+ struct v2_disk_dqheader dqh; -+ int file_magics[] = INITQMAGICS; -+ int be_magic; -+ -+ if (fmt != QFMT_VFS_V1) -+ return 0; -+ -+ if (!v2_read_header(h, &dqh)) -+ return 0; -+ -+ be_magic = ext2fs_be32_to_cpu((__force __be32)dqh.dqh_magic); -+ if (be_magic == file_magics[type]) { -+ log_err("Your quota file is stored in wrong endianity"); -+ return 0; -+ } -+ if (V2_VERSION != ext2fs_le32_to_cpu(dqh.dqh_version)) -+ return 0; -+ return 1; -+} -+ -+/* -+ * Open quotafile -+ */ -+static int v2_init_io(struct quota_handle *h) -+{ -+ struct v2_disk_dqinfo ddqinfo; -+ -+ h->qh_info.u.v2_mdqi.dqi_qtree.dqi_entry_size = -+ sizeof(struct v2r1_disk_dqblk); -+ h->qh_info.u.v2_mdqi.dqi_qtree.dqi_ops = &v2r1_fmt_ops; -+ -+ /* Read information about quotafile */ -+ if (h->e2fs_read(&h->qh_qf, V2_DQINFOOFF, &ddqinfo, -+ sizeof(ddqinfo)) != sizeof(ddqinfo)) -+ return -1; -+ v2_disk2memdqinfo(&h->qh_info, &ddqinfo); -+ return 0; -+} -+ -+/* -+ * Initialize new quotafile -+ */ -+static int v2_new_io(struct quota_handle *h) -+{ -+ int file_magics[] = INITQMAGICS; -+ struct v2_disk_dqheader ddqheader; -+ struct v2_disk_dqinfo ddqinfo; -+ -+ if (h->qh_fmt != QFMT_VFS_V1) -+ return -1; -+ -+ /* Write basic quota header */ -+ ddqheader.dqh_magic = ext2fs_cpu_to_le32(file_magics[h->qh_type]); -+ ddqheader.dqh_version = ext2fs_cpu_to_le32(V2_VERSION); -+ if (h->e2fs_write(&h->qh_qf, 0, &ddqheader, sizeof(ddqheader)) != -+ sizeof(ddqheader)) -+ return -1; -+ -+ /* Write information about quotafile */ -+ h->qh_info.dqi_bgrace = MAX_DQ_TIME; -+ h->qh_info.dqi_igrace = MAX_IQ_TIME; -+ h->qh_info.u.v2_mdqi.dqi_flags = 0; -+ h->qh_info.u.v2_mdqi.dqi_qtree.dqi_blocks = QT_TREEOFF + 1; -+ h->qh_info.u.v2_mdqi.dqi_qtree.dqi_free_blk = 0; -+ h->qh_info.u.v2_mdqi.dqi_qtree.dqi_free_entry = 0; -+ h->qh_info.u.v2_mdqi.dqi_qtree.dqi_entry_size = -+ sizeof(struct v2r1_disk_dqblk); -+ h->qh_info.u.v2_mdqi.dqi_qtree.dqi_ops = &v2r1_fmt_ops; -+ v2_mem2diskdqinfo(&ddqinfo, &h->qh_info); -+ if (h->e2fs_write(&h->qh_qf, V2_DQINFOOFF, &ddqinfo, -+ sizeof(ddqinfo)) != -+ sizeof(ddqinfo)) -+ return -1; -+ -+ return 0; -+} -+ -+/* -+ * Write information (grace times to file) -+ */ -+static int v2_write_info(struct quota_handle *h) -+{ -+ struct v2_disk_dqinfo ddqinfo; -+ -+ v2_mem2diskdqinfo(&ddqinfo, &h->qh_info); -+ if (h->e2fs_write(&h->qh_qf, V2_DQINFOOFF, &ddqinfo, sizeof(ddqinfo)) != -+ sizeof(ddqinfo)) -+ return -1; -+ -+ return 0; -+} -+ -+/* -+ * Read dquot from disk -+ */ -+static struct dquot *v2_read_dquot(struct quota_handle *h, qid_t id) -+{ -+ return qtree_read_dquot(h, id); -+} -+ -+/* -+ * Commit changes of dquot to disk - it might also mean deleting it when quota -+ * became fake one and user has no blocks. -+ * User can process use 'errno' to detect errstr. -+ */ -+static int v2_commit_dquot(struct dquot *dquot) -+{ -+ struct util_dqblk *b = &dquot->dq_dqb; -+ -+ if (!b->dqb_curspace && !b->dqb_curinodes && !b->dqb_bsoftlimit && -+ !b->dqb_isoftlimit && !b->dqb_bhardlimit && !b->dqb_ihardlimit) -+ qtree_delete_dquot(dquot); -+ else -+ qtree_write_dquot(dquot); -+ return 0; -+} -+ -+static int v2_scan_dquots(struct quota_handle *h, -+ int (*process_dquot) (struct dquot *, void *), -+ void *data) -+{ -+ return qtree_scan_dquots(h, process_dquot, data); -+} -+ -+/* Report information about quotafile. -+ * TODO: Not used right now, but we should be able to use this when we add -+ * support to debugfs to read quota files. -+ */ -+static int v2_report(struct quota_handle *h EXT2FS_ATTR((unused)), -+ int verbose EXT2FS_ATTR((unused))) -+{ -+ log_err("Not Implemented."); -+ return -1; -+} -diff --git a/lib/support/quotaio_v2.h b/lib/support/quotaio_v2.h -new file mode 100644 -index 0000000..de2db27 ---- /dev/null -+++ b/lib/support/quotaio_v2.h -@@ -0,0 +1,54 @@ -+/* -+ * -+ * Header file for disk format of new quotafile format -+ * -+ */ -+ -+#ifndef GUARD_QUOTAIO_V2_H -+#define GUARD_QUOTAIO_V2_H -+ -+#include -+#include "quotaio.h" -+ -+/* Offset of info header in file */ -+#define V2_DQINFOOFF sizeof(struct v2_disk_dqheader) -+/* Supported version of quota-tree format */ -+#define V2_VERSION 1 -+ -+struct v2_disk_dqheader { -+ __le32 dqh_magic; /* Magic number identifying file */ -+ __le32 dqh_version; /* File version */ -+} __attribute__ ((packed)); -+ -+/* Flags for version specific files */ -+#define V2_DQF_MASK 0x0000 /* Mask for all valid ondisk flags */ -+ -+/* Header with type and version specific information */ -+struct v2_disk_dqinfo { -+ __le32 dqi_bgrace; /* Time before block soft limit becomes -+ * hard limit */ -+ __le32 dqi_igrace; /* Time before inode soft limit becomes -+ * hard limit */ -+ __le32 dqi_flags; /* Flags for quotafile (DQF_*) */ -+ __le32 dqi_blocks; /* Number of blocks in file */ -+ __le32 dqi_free_blk; /* Number of first free block in the list */ -+ __le32 dqi_free_entry; /* Number of block with at least one -+ * free entry */ -+} __attribute__ ((packed)); -+ -+struct v2r1_disk_dqblk { -+ __le32 dqb_id; /* id this quota applies to */ -+ __le32 dqb_pad; -+ __le64 dqb_ihardlimit; /* absolute limit on allocated inodes */ -+ __le64 dqb_isoftlimit; /* preferred inode limit */ -+ __le64 dqb_curinodes; /* current # allocated inodes */ -+ __le64 dqb_bhardlimit; /* absolute limit on disk space -+ * (in QUOTABLOCK_SIZE) */ -+ __le64 dqb_bsoftlimit; /* preferred limit on disk space -+ * (in QUOTABLOCK_SIZE) */ -+ __le64 dqb_curspace; /* current space occupied (in bytes) */ -+ __le64 dqb_btime; /* time limit for excessive disk use */ -+ __le64 dqb_itime; /* time limit for excessive inode use */ -+} __attribute__ ((packed)); -+ -+#endif -diff --git a/lib/uuid/Android.mk b/lib/uuid/Android.mk -new file mode 100644 -index 0000000..85cb1b7 ---- /dev/null -+++ b/lib/uuid/Android.mk -@@ -0,0 +1,68 @@ -+LOCAL_PATH := $(call my-dir) -+ -+libext2_uuid_src_files := \ -+ clear.c \ -+ compare.c \ -+ copy.c \ -+ gen_uuid.c \ -+ isnull.c \ -+ pack.c \ -+ parse.c \ -+ unpack.c \ -+ unparse.c \ -+ uuid_time.c -+ -+ -+libext2_uuid_c_includes := external/e2fsprogs/lib -+ -+libext2_uuid_cflags := -O2 -g -W -Wall -+ -+libext2_uuid_system_shared_libraries := libc -+ -+include $(CLEAR_VARS) -+ -+LOCAL_SRC_FILES := $(libext2_uuid_src_files) -+LOCAL_C_INCLUDES := $(libext2_uuid_c_includes) -+LOCAL_CFLAGS := $(libext2_uuid_cflags) -+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH) -+LOCAL_SYSTEM_SHARED_LIBRARIES := $(libext2_uuid_system_shared_libraries) -+LOCAL_MODULE := libext2_uuid -+LOCAL_MODULE_TAGS := optional -+ -+include $(BUILD_SHARED_LIBRARY) -+ -+include $(CLEAR_VARS) -+ -+LOCAL_SRC_FILES := $(libext2_uuid_src_files) -+LOCAL_C_INCLUDES := $(libext2_uuid_c_includes) -+LOCAL_CFLAGS := $(libext2_uuid_cflags) -+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH) -+LOCAL_MODULE := libext2_uuid_host -+LOCAL_MODULE_TAGS := optional -+ -+include $(BUILD_HOST_SHARED_LIBRARY) -+ -+ -+include $(CLEAR_VARS) -+ -+LOCAL_SRC_FILES := $(libext2_uuid_src_files) -+LOCAL_C_INCLUDES := $(libext2_uuid_c_includes) -+LOCAL_CFLAGS := $(libext2_uuid_cflags) -+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH) -+LOCAL_STATIC_LIBRARIES := libc -+LOCAL_MODULE := libext2_uuid_static -+LOCAL_MODULE_TAGS := optional -+ -+include $(BUILD_STATIC_LIBRARY) -+ -+ -+include $(CLEAR_VARS) -+ -+LOCAL_SRC_FILES := $(libext2_uuid_src_files) -+LOCAL_C_INCLUDES := $(libext2_uuid_c_includes) -+LOCAL_CFLAGS := $(libext2_uuid_cflags) -+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH) -+LOCAL_MODULE := libext2_uuid_host -+LOCAL_MODULE_TAGS := optional -+ -+include $(BUILD_HOST_STATIC_LIBRARY) -diff --git a/lib/uuid/Makefile.in b/lib/uuid/Makefile.in -index 74ca478..acdcea6 100644 ---- a/lib/uuid/Makefile.in -+++ b/lib/uuid/Makefile.in -@@ -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 $< -@@ -166,8 +167,9 @@ uninstall:: - $(RM) -f $(DESTDIR)$(man3dir)/uuid_generate_random.3 $(DESTDIR)$(man3dir)/uuid_generate_time.3 - - clean:: -- $(RM) -f \#* *.s *.o *.a *~ *.bak core profiled/* uuid.h -- $(RM) -f ../libuuid.a ../libuuid_p.a tst_uuid uuid_time $(SMANPAGES) -+ $(RM) -f \#* *.s *.o *.a *~ *.bak core profiled/* uuid.h \ -+ ../libuuid.a ../libuuid_p.a tst_uuid uuid_time \ -+ uuid.pc uuid_types.h $(SMANPAGES) - - check:: tst_uuid - LD_LIBRARY_PATH=$(LIB) DYLD_LIBRARY_PATH=$(LIB) ./tst_uuid -diff --git a/lib/uuid/gen_uuid.c b/lib/uuid/gen_uuid.c -index 22b4513..794c585 100644 ---- a/lib/uuid/gen_uuid.c -+++ b/lib/uuid/gen_uuid.c -@@ -425,6 +425,7 @@ try_again: - return 0; - } - -+#if defined(USE_UUIDD) && defined(HAVE_SYS_UN_H) - static ssize_t read_all(int fd, char *buf, size_t count) - { - ssize_t ret; -@@ -475,8 +476,12 @@ static void close_all_fds(void) - open("/dev/null", O_RDWR); - } - } -+#endif /* defined(USE_UUIDD) && defined(HAVE_SYS_UN_H) */ - -- -+#pragma GCC diagnostic push -+#if !defined(USE_UUIDD) || !defined(HAVE_SYS_UN_H) -+#pragma GCC diagnostic ignored "-Wunused-parameter" -+#endif - /* - * Try using the uuidd daemon to generate the UUID - * -@@ -559,6 +564,7 @@ fail: - #endif - return -1; - } -+#pragma GCC diagnostic pop - - void uuid__generate_time(uuid_t out, int *num) - { -diff --git a/misc/Android.mk b/misc/Android.mk -new file mode 100644 -index 0000000..2ea323a ---- /dev/null -+++ b/misc/Android.mk -@@ -0,0 +1,375 @@ -+LOCAL_PATH := $(call my-dir) -+ -+######################################################################### -+# Build mke2fs -+mke2fs_src_files := \ -+ mke2fs.c \ -+ util.c \ -+ mk_hugefiles.c \ -+ default_profile.c \ -+ create_inode.c -+ -+mke2fs_c_includes := \ -+ external/e2fsprogs/lib \ -+ external/e2fsprogs/e2fsck -+ -+mke2fs_cflags := -O2 -g -W -Wall -+ -+mke2fs_shared_libraries := \ -+ libext2fs \ -+ libext2_blkid \ -+ libext2_uuid \ -+ libext2_quota \ -+ libext2_com_err \ -+ libext2_e2p -+ -+mke2fs_system_shared_libraries := libc -+ -+include $(CLEAR_VARS) -+ -+LOCAL_SRC_FILES := $(mke2fs_src_files) -+LOCAL_C_INCLUDES := $(mke2fs_c_includes) -+LOCAL_CFLAGS := $(mke2fs_cflags) -+LOCAL_SYSTEM_SHARED_LIBRARIES := $(mke2fs_system_shared_libraries) -+LOCAL_SHARED_LIBRARIES := $(mke2fs_shared_libraries) -+LOCAL_MODULE := mke2fs -+LOCAL_MODULE_TAGS := optional -+include $(BUILD_EXECUTABLE) -+ -+include $(CLEAR_VARS) -+ -+LOCAL_SRC_FILES := $(mke2fs_src_files) -+LOCAL_C_INCLUDES := $(mke2fs_c_includes) -+LOCAL_CFLAGS := $(mke2fs_cflags) -+LOCAL_SHARED_LIBRARIES := $(addsuffix _host, $(mke2fs_shared_libraries)) -+LOCAL_MODULE := mke2fs_host -+LOCAL_MODULE_STEM := mke2fs -+LOCAL_MODULE_TAGS := optional -+ -+include $(BUILD_HOST_EXECUTABLE) -+ -+########################################################################### -+# Build tune2fs -+# -+tune2fs_src_files := \ -+ tune2fs.c \ -+ util.c -+ -+tune2fs_c_includes := \ -+ external/e2fsprogs/lib \ -+ external/e2fsprogs/e2fsck -+ -+tune2fs_cflags := -O2 -g -W -Wall -+ -+tune2fs_shared_libraries := \ -+ libext2fs \ -+ libext2_com_err \ -+ libext2_blkid \ -+ libext2_quota \ -+ libext2_uuid \ -+ libext2_e2p -+ -+tune2fs_system_shared_libraries := libc -+ -+ -+tune2fs_static_libraries := \ -+ libext2_com_err \ -+ libext2_blkid \ -+ libext2_quota \ -+ libext2_uuid_static \ -+ libext2_e2p \ -+ libext2fs -+ -+tune2fs_system_static_libraries := libc -+ -+include $(CLEAR_VARS) -+ -+LOCAL_SRC_FILES := $(tune2fs_src_files) -+LOCAL_C_INCLUDES := $(tune2fs_c_includes) -+LOCAL_CFLAGS := $(tune2fs_cflags) -+LOCAL_SHARED_LIBRARIES := $(tune2fs_shared_libraries) -+LOCAL_SYSTEM_SHARED_LIBRARIES := $(tune2fs_system_shared_libraries) -+LOCAL_MODULE := tune2fs -+LOCAL_MODULE_TAGS := optional -+ -+include $(BUILD_EXECUTABLE) -+ -+include $(CLEAR_VARS) -+ -+LOCAL_SRC_FILES := $(tune2fs_src_files) -+LOCAL_C_INCLUDES := $(tune2fs_c_includes) -+LOCAL_CFLAGS := $(tune2fs_cflags) -+LOCAL_STATIC_LIBRARIES := $(tune2fs_static_libraries) $(tune2fs_system_static_libraries) -+LOCAL_FORCE_STATIC_EXECUTABLE := true -+LOCAL_MODULE := tune2fs_static -+LOCAL_MODULE_TAGS := optional -+ -+include $(BUILD_EXECUTABLE) -+ -+include $(CLEAR_VARS) -+ -+LOCAL_SRC_FILES := $(tune2fs_src_files) -+LOCAL_C_INCLUDES := $(tune2fs_c_includes) -+LOCAL_CFLAGS := $(tune2fs_cflags) -DBUILD_AS_LIB -+LOCAL_STATIC_LIBRARIES := $(tune2fs_static_libraries) $(tune2fs_system_static_libraries) -+LOCAL_MODULE := libtune2fs -+LOCAL_MODULE_TAGS := optional -+ -+include $(BUILD_STATIC_LIBRARY) -+ -+include $(CLEAR_VARS) -+ -+LOCAL_SRC_FILES := $(tune2fs_src_files) -+LOCAL_C_INCLUDES := $(tune2fs_c_includes) -+LOCAL_CFLAGS := $(tune2fs_cflags) -+LOCAL_SHARED_LIBRARIES := $(addsuffix _host, $(tune2fs_shared_libraries)) -+LOCAL_MODULE := tune2fs_host -+LOCAL_MODULE_STEM := tune2fs -+LOCAL_MODULE_TAGS := optional -+ -+include $(BUILD_HOST_EXECUTABLE) -+ -+######################################################################### -+# Build badblocks -+# -+include $(CLEAR_VARS) -+ -+badblocks_src_files := \ -+ badblocks.c -+ -+badblocks_c_includes := \ -+ external/e2fsprogs/lib -+ -+badblocks_cflags := -O2 -g -W -Wall -+ -+badblocks_shared_libraries := \ -+ libext2fs \ -+ libext2_com_err \ -+ libext2_uuid \ -+ libext2_blkid \ -+ libext2_e2p -+ -+badblocks_system_shared_libraries := libc -+ -+include $(CLEAR_VARS) -+ -+LOCAL_SRC_FILES := $(badblocks_src_files) -+LOCAL_C_INCLUDES := $(badblocks_c_includes) -+LOCAL_CFLAGS := $(badblocks_cflags) -+LOCAL_SHARED_LIBRARIES := $(badblocks_shared_libraries) -+LOCAL_SYSTEM_SHARED_LIBRARIES := $(badblocks_system_shared_libraries) -+LOCAL_MODULE := badblocks -+LOCAL_MODULE_TAGS := optional -+ -+include $(BUILD_EXECUTABLE) -+ -+include $(CLEAR_VARS) -+ -+LOCAL_SRC_FILES := $(badblocks_src_files) -+LOCAL_C_INCLUDES := $(badblocks_c_includes) -+LOCAL_CFLAGS := $(badblocks_cflags) -+LOCAL_SHARED_LIBRARIES := $(addsuffix _host, $(badblocks_shared_libraries)) -+LOCAL_MODULE := badblocks_host -+LOCAL_MODULE_STEM := badblocks -+LOCAL_MODULE_TAGS := optional -+ -+include $(BUILD_HOST_EXECUTABLE) -+ -+######################################################################### -+# Build chattr -+# -+include $(CLEAR_VARS) -+ -+chattr_src_files := \ -+ chattr.c -+ -+chattr_c_includes := \ -+ external/e2fsprogs/lib -+ -+chattr_cflags := -O2 -g -W -Wall -+ -+chattr_shared_libraries := \ -+ libext2_com_err \ -+ libext2_e2p -+ -+chattr_system_shared_libraries := libc -+ -+include $(CLEAR_VARS) -+ -+LOCAL_SRC_FILES := $(chattr_src_files) -+LOCAL_C_INCLUDES := $(chattr_c_includes) -+LOCAL_CFLAGS := $(chattr_cflags) -+LOCAL_SHARED_LIBRARIES := $(chattr_shared_libraries) -+LOCAL_SYSTEM_SHARED_LIBRARIES := $(chattr_system_shared_libraries) -+LOCAL_MODULE := chattr -+LOCAL_MODULE_TAGS := optional -+ -+include $(BUILD_EXECUTABLE) -+ -+include $(CLEAR_VARS) -+ -+LOCAL_SRC_FILES := $(chattr_src_files) -+LOCAL_C_INCLUDES := $(chattr_c_includes) -+LOCAL_CFLAGS := $(chattr_cflags) -+LOCAL_SHARED_LIBRARIES := $(addsuffix _host, $(chattr_shared_libraries)) -+LOCAL_MODULE := chattr_host -+LOCAL_MODULE_STEM := chattr -+LOCAL_MODULE_TAGS := optional -+ -+include $(BUILD_HOST_EXECUTABLE) -+ -+######################################################################### -+# Build lsattr -+# -+include $(CLEAR_VARS) -+ -+lsattr_src_files := \ -+ lsattr.c -+ -+lsattr_c_includes := \ -+ external/e2fsprogs/lib -+ -+lsattr_cflags := -O2 -g -W -Wall -+ -+lsattr_shared_libraries := \ -+ libext2_com_err \ -+ libext2_e2p -+ -+lsattr_system_shared_libraries := libc -+ -+include $(CLEAR_VARS) -+ -+LOCAL_SRC_FILES := $(lsattr_src_files) -+LOCAL_C_INCLUDES := $(lsattr_c_includes) -+LOCAL_CFLAGS := $(lsattr_cflags) -+LOCAL_SHARED_LIBRARIES := $(lsattr_shared_libraries) -+LOCAL_SYSTEM_SHARED_LIBRARIES := $(lsattr_system_shared_libraries) -+LOCAL_MODULE := lsattr -+LOCAL_MODULE_TAGS := optional -+ -+include $(BUILD_EXECUTABLE) -+ -+include $(CLEAR_VARS) -+ -+LOCAL_SRC_FILES := $(lsattr_src_files) -+LOCAL_C_INCLUDES := $(lsattr_c_includes) -+LOCAL_CFLAGS := $(lsattr_cflags) -+LOCAL_SHARED_LIBRARIES := $(addsuffix _host, $(lsattr_shared_libraries)) -+LOCAL_MODULE := lsattr_host -+LOCAL_MODULE_STEM := lsattr -+LOCAL_MODULE_TAGS := optional -+ -+include $(BUILD_HOST_EXECUTABLE) -+ -+######################################################################### -+# Build blkid -+# -+include $(CLEAR_VARS) -+ -+blkid_src_files := \ -+ blkid.c -+ -+blkid_c_includes := \ -+ external/e2fsprogs/lib -+ -+blkid_cflags := -O2 -g -W -Wall -+ -+blkid_shared_libraries := \ -+ libext2fs \ -+ libext2_blkid \ -+ libext2_com_err \ -+ libext2_e2p -+ -+blkid_system_shared_libraries := libc -+ -+include $(CLEAR_VARS) -+ -+LOCAL_SRC_FILES := $(blkid_src_files) -+LOCAL_C_INCLUDES := $(blkid_c_includes) -+LOCAL_CFLAGS := $(blkid_cflags) -+LOCAL_SHARED_LIBRARIES := $(blkid_shared_libraries) -+LOCAL_SYSTEM_SHARED_LIBRARIES := $(blkid_system_shared_libraries) -+LOCAL_MODULE := blkid -+LOCAL_MODULE_TAGS := optional -+ -+include $(BUILD_EXECUTABLE) -+ -+######################################################################### -+# Build e4crypt -+e4crypt_src_files := e4crypt.c -+ -+e4crypt_c_includes := \ -+ external/e2fsprogs/lib -+ -+e4crypt_cflags := -O2 -g -W -Wall -+ -+e4crypt_shared_libraries := libext2fs libext2_uuid -+ -+e4crypt_system_shared_libraries := libc -+ -+include $(CLEAR_VARS) -+ -+LOCAL_SRC_FILES := $(e4crypt_src_files) -+LOCAL_C_INCLUDES := $(e4crypt_c_includes) -+LOCAL_CFLAGS := $(e4crypt_cflags) -+LOCAL_SYSTEM_SHARED_LIBRARIES := $(e4crypt_system_shared_libraries) -+LOCAL_SHARED_LIBRARIES := $(e4crypt_shared_libraries) -+LOCAL_MODULE := e4crypt -+LOCAL_MODULE_TAGS := optional -+include $(BUILD_EXECUTABLE) -+ -+include $(CLEAR_VARS) -+ -+LOCAL_SRC_FILES := $(e4crypt_src_files) -+LOCAL_C_INCLUDES := $(e4crypt_c_includes) -+LOCAL_CFLAGS := $(e4crypt_cflags) -+LOCAL_SHARED_LIBRARIES := $(addsuffix _host, $(e4crypt_shared_libraries)) -+LOCAL_MODULE := e4crypt_host -+LOCAL_MODULE_STEM := e4crypt -+LOCAL_MODULE_TAGS := optional -+ -+include $(BUILD_HOST_EXECUTABLE) -+ -+########################################################################### -+# Build e2image -+# -+e2image_src_files := \ -+ e2image.c -+ -+e2image_c_includes := \ -+ external/e2fsprogs/lib -+ -+e2image_cflags := -O2 -g -W -Wall -+ -+e2image_shared_libraries := \ -+ libext2fs \ -+ libext2_blkid \ -+ libext2_com_err \ -+ libext2_quota -+ -+e2image_system_shared_libraries := libc -+ -+include $(CLEAR_VARS) -+ -+LOCAL_SRC_FILES := $(e2image_src_files) -+LOCAL_C_INCLUDES := $(e2image_c_includes) -+mke2fs_c_includesLOCAL_CFLAGS := $(e2image_cflags) -+LOCAL_SHARED_LIBRARIES := $(e2image_shared_libraries) -+LOCAL_SYSTEM_SHARED_LIBRARIES := $(e2image_system_shared_libraries) -+LOCAL_MODULE := e2image -+LOCAL_MODULE_TAGS := optional -+ -+include $(BUILD_EXECUTABLE) -+ -+include $(CLEAR_VARS) -+ -+LOCAL_SRC_FILES := $(e2image_src_files) -+LOCAL_C_INCLUDES := $(e2image_c_includes) -+LOCAL_CFLAGS := $(e2image_cflags) -+LOCAL_SHARED_LIBRARIES := $(addsuffix _host, $(e2image_shared_libraries)) -+LOCAL_MODULE := e2image_host -+LOCAL_MODULE_STEM := e2image -+LOCAL_MODULE_TAGS := optional -+ -+include $(BUILD_HOST_EXECUTABLE) -+ -diff --git a/misc/Makefile.in b/misc/Makefile.in -index c203fb4..52cd5bb 100644 ---- a/misc/Makefile.in -+++ b/misc/Makefile.in -@@ -14,6 +14,9 @@ INSTALL = @INSTALL@ - @DEFRAG_CMT@@LINUX_CMT@E4DEFRAG_PROG= e4defrag - @DEFRAG_CMT@@LINUX_CMT@E4DEFRAG_MAN= e4defrag.8 - -+@LINUX_CMT@E4CRYPT_PROG = e4crypt -+@LINUX_CMT@E4CRYPT_MAN= e4crypt.8 -+ - @IMAGER_CMT@E2IMAGE_PROG= e2image - @IMAGER_CMT@E2IMAGE_MAN= e2image.8 - -@@ -27,13 +30,16 @@ INSTALL = @INSTALL@ - @BLKID_CMT@FINDFS_LINK= findfs - @BLKID_CMT@FINDFS_MAN= findfs.8 - -+@FUSE_CMT@FUSE_PROG= fuse2fs -+ - SPROGS= mke2fs badblocks tune2fs dumpe2fs $(BLKID_PROG) logsave \ - $(E2IMAGE_PROG) @FSCK_PROG@ e2undo --USPROGS= mklost+found filefrag e2freefrag $(UUIDD_PROG) $(E4DEFRAG_PROG) -+USPROGS= mklost+found filefrag e2freefrag $(UUIDD_PROG) \ -+ $(E4DEFRAG_PROG) $(E4CRYPT_PROG) $(FUSE_PROG) - SMANPAGES= tune2fs.8 mklost+found.8 mke2fs.8 dumpe2fs.8 badblocks.8 \ - e2label.8 $(FINDFS_MAN) $(BLKID_MAN) $(E2IMAGE_MAN) \ - logsave.8 filefrag.8 e2freefrag.8 e2undo.8 \ -- $(UUIDD_MAN) $(E4DEFRAG_MAN) @FSCK_MAN@ -+ $(UUIDD_MAN) $(E4DEFRAG_MAN) $(E4CRYPT_MAN) @FSCK_MAN@ - FMANPAGES= mke2fs.conf.5 ext4.5 - - UPROGS= chattr lsattr @UUID_CMT@ uuidgen -@@ -43,8 +49,8 @@ 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 -+MKE2FS_OBJS= mke2fs.o util.o default_profile.o mk_hugefiles.o \ -+ create_inode.o - CHATTR_OBJS= chattr.o - LSATTR_OBJS= lsattr.o - UUIDGEN_OBJS= uuidgen.o -@@ -57,13 +63,17 @@ BLKID_OBJS= blkid.o - FILEFRAG_OBJS= filefrag.o - E2UNDO_OBJS= e2undo.o - E4DEFRAG_OBJS= e4defrag.o -+E4CRYPT_OBJS= e4crypt.o - E2FREEFRAG_OBJS= e2freefrag.o -+E2FUZZ_OBJS= e2fuzz.o -+FUSE2FS_OBJS= fuse2fs.o journal.o recovery.o revoke.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 -@@ -78,54 +88,59 @@ PROFILED_FILEFRAG_OBJS= profiled/filefrag.o - PROFILED_E2FREEFRAG_OBJS= profiled/e2freefrag.o - PROFILED_E2UNDO_OBJS= profiled/e2undo.o - PROFILED_E4DEFRAG_OBJS= profiled/e4defrag.o -+PROFILED_E4CRYPT_OBJS= profiled/e4crypt.o -+PROFILED_FUSE2FS_OJBS= profiled/fuse2fs.o profiled/journal.o \ -+ profiled/recovery.o profiled/revoke.o - - SRCS= $(srcdir)/tune2fs.c $(srcdir)/mklost+found.c $(srcdir)/mke2fs.c $(srcdir)/mk_hugefiles.c \ - $(srcdir)/chattr.c $(srcdir)/lsattr.c $(srcdir)/dumpe2fs.c \ - $(srcdir)/badblocks.c $(srcdir)/fsck.c $(srcdir)/util.c \ - $(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)/ismounted.c $(srcdir)/e2undo.c \ -+ $(srcdir)/e2freefrag.c $(srcdir)/create_inode.c \ -+ $(srcdir)/fuse2fs.c \ -+ $(srcdir)/../debugfs/journal.c $(srcdir)/../e2fsck/revoke.c \ -+ $(srcdir)/../e2fsck/recovery.c - --LIBS= $(LIBEXT2FS) $(LIBCOM_ERR) --DEPLIBS= $(LIBEXT2FS) $(DEPLIBCOM_ERR) --PROFILED_LIBS= $(PROFILED_LIBEXT2FS) $(PROFILED_LIBCOM_ERR) --PROFILED_DEPLIBS= $(PROFILED_LIBEXT2FS) $(DEPPROFILED_LIBCOM_ERR) -+LIBS= $(LIBEXT2FS) $(LIBCOM_ERR) $(LIBSUPPORT) -+DEPLIBS= $(LIBEXT2FS) $(DEPLIBCOM_ERR) $(DEPLIBSUPPORT) -+PROFILED_LIBS= $(PROFILED_LIBEXT2FS) $(PROFILED_LIBCOM_ERR) $(LIBSUPPORT) -+PROFILED_DEPLIBS= $(PROFILED_LIBEXT2FS) $(DEPPROFILED_LIBCOM_ERR) $(DEPLIBSUPPORT) - --STATIC_LIBS= $(STATIC_LIBEXT2FS) $(STATIC_LIBCOM_ERR) --STATIC_DEPLIBS= $(STATIC_LIBEXT2FS) $(DEPSTATIC_LIBCOM_ERR) -+STATIC_LIBS= $(STATIC_LIBEXT2FS) $(STATIC_LIBCOM_ERR) $(LIBSUPPORT) -+STATIC_DEPLIBS= $(STATIC_LIBEXT2FS) $(DEPSTATIC_LIBCOM_ERR) $(DEPLIBSUPPORT) - --LIBS_E2P= $(LIBE2P) $(LIBCOM_ERR) --DEPLIBS_E2P= $(LIBE2P) $(DEPLIBCOM_ERR) -+LIBS_E2P= $(LIBE2P) $(LIBCOM_ERR) -+DEPLIBS_E2P= $(LIBE2P) $(DEPLIBCOM_ERR) - - COMPILE_ET=$(top_builddir)/lib/et/compile_et --build-tree - -+# This nastyness is needed because of jfs_user.h hackery; when we finally -+# clean up this mess, we should be able to drop it -+JOURNAL_CFLAGS = -I$(srcdir)/../e2fsck $(ALL_CFLAGS) -DDEBUGFS -+DEPEND_CFLAGS = -I$(top_srcdir)/e2fsck -+ - .c.o: - $(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) $(E4CRYPT_PROGS) e2fuzz - - @PROFILE_CMT@all:: tune2fs.profiled blkid.profiled e2image.profiled \ - e2undo.profiled mke2fs.profiled dumpe2fs.profiled fsck.profiled \ - logsave.profiled filefrag.profiled uuidgen.profiled $(UUIDD_PROFILED) \ -- e2image.profiled e4defrag.profiled e2freefrag.profiled -+ e2image.profiled e4defrag.profiled e4crypt.profiled \ -+ e2freefrag.profiled - - profiled: - @PROFILE_CMT@ $(E) " MKDIR $@" - @PROFILE_CMT@ $(Q) mkdir profiled - --prof_err.c prof_err.h: $(srcdir)/../e2fsck/prof_err.et -- $(E) " COMPILE_ET prof_err.et" -- $(Q) $(COMPILE_ET) $(srcdir)/../e2fsck/prof_err.et -- --profile.h: $(top_srcdir)/e2fsck/profile.h -- $(E) " CP $<" -- $(Q) cp $< $@ -- - mke2fs.conf: $(srcdir)/mke2fs.conf.in - if test -f $(srcdir)/mke2fs.conf.custom.in ; then \ - cp $(srcdir)/mke2fs.conf.custom.in mke2fs.conf; \ -@@ -137,12 +152,6 @@ default_profile.c: mke2fs.conf $(srcdir)/profile-to-c.awk - $(E) " PROFILE_TO_C mke2fs.conf" - $(Q) $(AWK) -f $(srcdir)/profile-to-c.awk < mke2fs.conf \ - > default_profile.c --profile.o: -- $(E) " CC $<" -- $(Q) $(CC) -c $(ALL_CFLAGS) $(srcdir)/../e2fsck/profile.c -o $@ --@PROFILE_CMT@ $(Q) $(CC) $(ALL_CFLAGS) -g -pg -o profiled/profile.o -c \ --@PROFILE_CMT@ $(srcdir)/../e2fsck/profile.c -- - findsuper: findsuper.o - $(E) " LD $@" - $(Q) $(CC) $(ALL_LDFLAGS) -o findsuper findsuper.o $(LIBS) $(SYSLIBS) -@@ -157,26 +166,27 @@ e2initrd_helper: e2initrd_helper.o $(DEPLIBS) $(DEPLIBBLKID) $(LIBEXT2FS) - $(LIBBLKID) $(LIBEXT2FS) $(LIBINTL) $(SYSLIBS) - - tune2fs: $(TUNE2FS_OBJS) $(DEPLIBS) $(DEPLIBS_E2P) $(DEPLIBBLKID) \ -- $(DEPLIBUUID) $(DEPLIBQUOTA) $(LIBEXT2FS) -+ $(DEPLIBUUID) $(LIBEXT2FS) - $(E) " LD $@" - $(Q) $(CC) $(ALL_LDFLAGS) -o tune2fs $(TUNE2FS_OBJS) $(LIBS) \ -- $(LIBBLKID) $(LIBUUID) $(LIBQUOTA) $(LIBEXT2FS) $(LIBS_E2P) \ -- $(LIBINTL) $(SYSLIBS) -+ $(LIBBLKID) $(LIBUUID) $(LIBEXT2FS) $(LIBS_E2P) \ -+ $(LIBINTL) $(SYSLIBS) $(LIBBLKID) $(LIBMAGIC) - - tune2fs.static: $(TUNE2FS_OBJS) $(STATIC_DEPLIBS) $(STATIC_LIBE2P) $(DEPSTATIC_LIBBLKID) - $(E) " LD $@" - $(Q) $(CC) $(LDFLAGS_STATIC) -o tune2fs.static $(TUNE2FS_OBJS) \ - $(STATIC_LIBS) $(STATIC_LIBBLKID) $(STATIC_LIBUUID) \ -- $(STATIC_LIBQUOTA) $(STATIC_LIBE2P) $(LIBINTL) $(SYSLIBS) -+ $(STATIC_LIBE2P) $(LIBINTL) $(SYSLIBS) \ -+ $(STATIC_LIBBLKID) $(LIBMAGIC) - - tune2fs.profiled: $(TUNE2FS_OBJS) $(PROFILED_DEPLIBS) \ -- $(PROFILED_E2P) $(DEPPROFILED_LIBBLKID) $(DEPPROFILED_LIBUUID) \ -- $(DEPPROFILED_LIBQUOTA) -+ $(PROFILED_E2P) $(DEPPROFILED_LIBBLKID) $(DEPPROFILED_LIBUUID) - $(E) " LD $@" - $(Q) $(CC) $(ALL_LDFLAGS) -g -pg -o tune2fs.profiled \ - $(PROFILED_TUNE2FS_OBJS) $(PROFILED_LIBBLKID) \ -- $(PROFILED_LIBUUID) $(PROFILED_LIBQUOTA) $(PROFILED_LIBE2P) \ -- $(LIBINTL) $(PROFILED_LIBS) $(SYSLIBS) -+ $(PROFILED_LIBUUID) $(PROFILED_LIBE2P) \ -+ $(LIBINTL) $(PROFILED_LIBS) $(SYSLIBS) $(PROFILED_LIBBLKID) \ -+ $(LIBMAGIC) - - blkid: $(BLKID_OBJS) $(DEPLIBBLKID) $(LIBEXT2FS) - $(E) " LD $@" -@@ -194,15 +204,16 @@ blkid.profiled: $(BLKID_OBJS) $(DEPPROFILED_LIBBLKID) \ - $(Q) $(CC) $(ALL_LDFLAGS) -g -pg -o blkid.profiled $(PROFILED_BLKID_OBJS) \ - $(PROFILED_LIBBLKID) $(LIBINTL) $(PROFILED_LIBEXT2FS) $(SYSLIBS) - --e2image: $(E2IMAGE_OBJS) $(DEPLIBS) -+e2image: $(E2IMAGE_OBJS) $(DEPLIBS) $(DEPLIBBLKID) - $(E) " LD $@" - $(Q) $(CC) $(ALL_LDFLAGS) -o e2image $(E2IMAGE_OBJS) $(LIBS) \ -- $(LIBINTL) $(SYSLIBS) -+ $(LIBINTL) $(SYSLIBS) $(LIBBLKID) $(LIBMAGIC) - --e2image.profiled: $(E2IMAGE_OBJS) $(PROFILED_DEPLIBS) -+e2image.profiled: $(E2IMAGE_OBJS) $(PROFILED_DEPLIBS) $(DEPLIBBLKID) - $(E) " LD $@" - $(Q) $(CC) $(ALL_LDFLAGS) -g -pg -o e2image.profiled \ -- $(PROFILED_E2IMAGE_OBJS) $(PROFILED_LIBS) $(LIBINTL) $(SYSLIBS) -+ $(PROFILED_E2IMAGE_OBJS) $(PROFILED_LIBS) $(LIBINTL) $(SYSLIBS) \ -+ $(LIBBLKID) $(LIBMAGIC) - - e2undo: $(E2UNDO_OBJS) $(DEPLIBS) - $(E) " LD $@" -@@ -219,11 +230,22 @@ e4defrag: $(E4DEFRAG_OBJS) $(DEPLIBS) - $(Q) $(CC) $(ALL_LDFLAGS) -o e4defrag $(E4DEFRAG_OBJS) $(LIBS) \ - $(SYSLIBS) - -+e4crypt: $(E4CRYPT_OBJS) $(DEPLIBS) $(DEPSTATIC_LIBUUID) -+ $(E) " LD $@" -+ $(Q) $(CC) $(ALL_LDFLAGS) -o e4crypt $(E4CRYPT_OBJS) \ -+ $(STATIC_LIBUUID) $(STATIC_LIBS) -+ - e4defrag.profiled: $(E4DEFRAG_OBJS) $(PROFILED_DEPLIBS) - $(E) " LD $@" - $(Q) $(CC) $(ALL_LDFLAGS) -g -pg -o e4defrag.profiled \ - $(PROFILED_E4DEFRAG_OBJS) $(PROFILED_LIBS) $(SYSLIBS) - -+e4crypt.profiled: $(E4CRYPT_OBJS) $(DEPPROFILED_LIBUUID) $(PROFILED_DEPLIBS) -+ $(E) " LD $@" -+ $(Q) $(CC) $(ALL_LDFLAGS) -g -pg -o e4crypt.profiled \ -+ $(PROFILED_E4CRYPT_OBJS) $(PROFILED_LIBUUID) $(PROFILED_LIBS) \ -+ $(SYSLIBS) -+ - base_device: base_device.c - $(E) " LD $@" - $(Q) $(CC) $(ALL_CFLAGS) $(ALL_LDFLAGS) $(srcdir)/base_device.c \ -@@ -239,27 +261,27 @@ mklost+found: $(MKLPF_OBJS) - $(LIBINTL) $(SYSLIBS) - - mke2fs: $(MKE2FS_OBJS) $(DEPLIBS) $(LIBE2P) $(DEPLIBBLKID) $(DEPLIBUUID) \ -- $(DEPLIBQUOTA) $(LIBEXT2FS) -+ $(LIBEXT2FS) - $(E) " LD $@" - $(Q) $(CC) $(ALL_LDFLAGS) -o mke2fs $(MKE2FS_OBJS) $(LIBS) $(LIBBLKID) \ -- $(LIBUUID) $(LIBQUOTA) $(LIBEXT2FS) $(LIBE2P) $(LIBINTL) \ -- $(SYSLIBS) -+ $(LIBUUID) $(LIBEXT2FS) $(LIBE2P) $(LIBINTL) \ -+ $(SYSLIBS) $(LIBMAGIC) - - mke2fs.static: $(MKE2FS_OBJS) $(STATIC_DEPLIBS) $(STATIC_LIBE2P) $(DEPSTATIC_LIBUUID) \ -- $(DEPSTATIC_LIBQUOTA) $(DEPSTATIC_LIBBLKID) -+ $(DEPSTATIC_LIBBLKID) - $(E) " LD $@" - $(Q) $(CC) $(ALL_LDFLAGS) -static -o mke2fs.static $(MKE2FS_OBJS) \ -- $(STATIC_LIBQUOTA) $(STATIC_LIBS) $(STATIC_LIBE2P) \ -- $(STATIC_LIBBLKID) $(STATIC_LIBUUID) $(LIBINTL) $(SYSLIBS) -+ $(STATIC_LIBS) $(STATIC_LIBE2P) \ -+ $(STATIC_LIBBLKID) $(STATIC_LIBUUID) $(LIBINTL) $(SYSLIBS) \ -+ $(LIBMAGIC) - - mke2fs.profiled: $(MKE2FS_OBJS) $(PROFILED_DEPLIBS) \ -- $(PROFILED_LIBE2P) $(PROFILED_DEPLIBBLKID) $(PROFILED_DEPLIBUUID) \ -- $(PROFILED_LIBQUOTA) -+ $(PROFILED_LIBE2P) $(PROFILED_DEPLIBBLKID) $(PROFILED_DEPLIBUUID) - $(E) " LD $@" - $(Q) $(CC) $(ALL_LDFLAGS) -g -pg -o mke2fs.profiled \ - $(PROFILED_MKE2FS_OBJS) $(PROFILED_LIBBLKID) \ -- $(PROFILED_LIBUUID) $(PROFILED_LIBQUOTA) $(PROFILED_LIBE2P) \ -- $(LIBINTL) $(PROFILED_LIBS) $(SYSLIBS) -+ $(PROFILED_LIBUUID) $(PROFILED_LIBE2P) \ -+ $(LIBINTL) $(PROFILED_LIBS) $(SYSLIBS) $(LIBMAGIC) - - chattr: $(CHATTR_OBJS) $(DEPLIBS_E2P) - $(E) " LD $@" -@@ -292,17 +314,19 @@ uuidd.profiled: $(UUIDD_OBJS) $(PROFILED_DEPLIBUUID) - $(Q) $(CC) $(ALL_LDFLAGS) -g -pg -o uuidd.profiled $(PROFILED_UUIDD_OBJS) \ - $(PROFILED_LIBUUID) $(LIBINTL) $(SYSLIBS) - --dumpe2fs: $(DUMPE2FS_OBJS) $(DEPLIBS) $(DEPLIBS_E2P) $(DEPLIBUUID) -+dumpe2fs: $(DUMPE2FS_OBJS) $(DEPLIBS) $(DEPLIBS_E2P) $(DEPLIBUUID) $(DEPLIBBLKID) - $(E) " LD $@" - $(Q) $(CC) $(ALL_LDFLAGS) -o dumpe2fs $(DUMPE2FS_OBJS) $(LIBS) \ -- $(LIBS_E2P) $(LIBUUID) $(LIBINTL) $(SYSLIBS) -+ $(LIBS_E2P) $(LIBUUID) $(LIBINTL) $(SYSLIBS) $(LIBBLKID) \ -+ $(LIBMAGIC) - - dumpe2fs.profiled: $(DUMPE2FS_OBJS) $(PROFILED_DEPLIBS) \ -- $(PROFILED_LIBE2P) $(PROFILED_DEPLIBUUID) -+ $(PROFILED_LIBE2P) $(PROFILED_DEPLIBUUID) $(PROFILED_DEPLIBBLKID) - $(E) " LD $@" - $(Q) $(CC) $(ALL_LDFLAGS) -g -pg -o dumpe2fs.profiled \ - $(PROFILED_DUMPE2FS_OBJS) $(PROFILED_LIBS) \ -- $(PROFILED_LIBE2P) $(PROFILED_LIBUUID) $(LIBINTL) $(SYSLIBS) -+ $(PROFILED_LIBE2P) $(PROFILED_LIBUUID) $(LIBINTL) $(SYSLIBS) \ -+ $(PROFILED_LIBBLKID) $(LIBMAGIC) - - fsck: $(FSCK_OBJS) $(DEPLIBBLKID) - $(E) " LD $@" -@@ -344,6 +368,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) \ -+ $(LIBEXT2FS) -+ $(E) " LD $@" -+ $(Q) $(CC) $(ALL_LDFLAGS) -o e2fuzz $(E2FUZZ_OBJS) $(LIBS) \ -+ $(LIBBLKID) $(LIBUUID) $(LIBEXT2FS) $(SYSLIBS) -+ - filefrag: $(FILEFRAG_OBJS) - $(E) " LD $@" - $(Q) $(CC) $(ALL_LDFLAGS) -o filefrag $(FILEFRAG_OBJS) $(SYSLIBS) -@@ -353,6 +383,27 @@ filefrag.profiled: $(FILEFRAG_OBJS) - $(Q) $(CC) $(ALL_LDFLAGS) -g -pg -o filefrag.profiled \ - $(PROFILED_FILEFRAG_OBJS) - -+fuse2fs: $(FUSE2FS_OBJS) $(DEPLIBS) $(DEPLIBBLKID) $(DEPLIBUUID) \ -+ $(LIBEXT2FS) -+ $(E) " LD $@" -+ $(Q) $(CC) $(ALL_LDFLAGS) -o fuse2fs $(FUSE2FS_OBJS) $(LIBS) \ -+ $(LIBFUSE) $(LIBBLKID) $(LIBUUID) $(LIBEXT2FS) $(LIBINTL) -+ -+journal.o: $(srcdir)/../debugfs/journal.c -+ $(E) " CC $@" -+ $(Q) $(CC) -c $(JOURNAL_CFLAGS) -I$(srcdir) \ -+ $(srcdir)/../debugfs/journal.c -o $@ -+ -+recovery.o: $(srcdir)/../e2fsck/recovery.c -+ $(E) " CC $@" -+ $(Q) $(CC) -c $(JOURNAL_CFLAGS) -I$(srcdir) \ -+ $(srcdir)/../e2fsck/recovery.c -o $@ -+ -+revoke.o: $(srcdir)/../e2fsck/revoke.c -+ $(E) " CC $@" -+ $(Q) $(CC) -c $(JOURNAL_CFLAGS) -I$(srcdir) \ -+ $(srcdir)/../e2fsck/revoke.c -o $@ -+ - tst_ismounted: $(srcdir)/ismounted.c $(STATIC_LIBEXT2FS) $(DEPLIBCOM_ERR) - $(E) " LD $@" - $(CC) -o tst_ismounted $(srcdir)/ismounted.c -DDEBUG $(ALL_CFLAGS) \ -@@ -398,6 +449,10 @@ e4defrag.8: $(DEP_SUBSTITUTE) $(srcdir)/e4defrag.8.in - $(E) " SUBST $@" - $(Q) $(SUBSTITUTE_UPTIME) $(srcdir)/e4defrag.8.in e4defrag.8 - -+e4crypt.8: $(DEP_SUBSTITUTE) $(srcdir)/e4crypt.8.in -+ $(E) " SUBST $@" -+ $(Q) $(SUBSTITUTE_UPTIME) $(srcdir)/e4crypt.8.in e4crypt.8 -+ - dumpe2fs.8: $(DEP_SUBSTITUTE) $(srcdir)/dumpe2fs.8.in - $(E) " SUBST $@" - $(Q) $(SUBSTITUTE_UPTIME) $(srcdir)/dumpe2fs.8.in dumpe2fs.8 -@@ -610,7 +665,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 -@@ -628,16 +683,16 @@ tune2fs.o: $(srcdir)/tune2fs.c $(top_builddir)/lib/config.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 \ -- $(top_srcdir)/lib/e2p/e2p.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 $(srcdir)/util.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)/version.h $(srcdir)/nls-enable.h -+ $(top_srcdir)/lib/ext2fs/kernel-list.h $(top_srcdir)/lib/support/plausible.h \ -+ $(top_srcdir)/lib/support/quotaio.h $(top_srcdir)/lib/support/dqblk_v2.h \ -+ $(top_srcdir)/lib/support/quotaio_tree.h $(top_srcdir)/lib/e2p/e2p.h \ -+ $(srcdir)/util.h $(top_srcdir)/version.h \ -+ $(top_srcdir)/lib/support/nls-enable.h - mklost+found.o: $(srcdir)/mklost+found.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)/version.h \ -- $(srcdir)/nls-enable.h -+ $(top_srcdir)/lib/support/nls-enable.h - mke2fs.o: $(srcdir)/mke2fs.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 \ -@@ -645,11 +700,13 @@ 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 -+ $(srcdir)/util.h $(top_srcdir)/lib/support/nls-enable.h \ -+ $(top_srcdir)/lib/support/plausible.h $(top_srcdir)/lib/support/profile.h \ -+ $(top_builddir)/lib/support/prof_err.h $(top_srcdir)/version.h \ -+ $(top_srcdir)/lib/support/quotaio.h $(top_srcdir)/lib/ext2fs/ext2fs.h \ -+ $(top_srcdir)/lib/support/dqblk_v2.h \ -+ $(top_srcdir)/lib/support/quotaio_tree.h $(srcdir)/mke2fs.h \ -+ $(srcdir)/create_inode.h $(top_srcdir)/lib/e2p/e2p.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 \ -@@ -658,26 +715,29 @@ mk_hugefiles.o: $(srcdir)/mk_hugefiles.c $(top_builddir)/lib/config.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 $(srcdir)/nls-enable.h \ -- $(srcdir)/mke2fs.h -+ $(srcdir)/util.h $(top_srcdir)/lib/support/profile.h \ -+ $(top_builddir)/lib/support/prof_err.h \ -+ $(top_srcdir)/lib/support/nls-enable.h $(srcdir)/mke2fs.h - chattr.o: $(srcdir)/chattr.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/et/com_err.h \ -- $(top_srcdir)/lib/e2p/e2p.h $(top_srcdir)/version.h $(srcdir)/nls-enable.h -+ $(top_srcdir)/lib/e2p/e2p.h $(top_srcdir)/lib/support/nls-enable.h \ -+ $(top_srcdir)/version.h - lsattr.o: $(srcdir)/lsattr.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/et/com_err.h \ -- $(top_srcdir)/lib/e2p/e2p.h $(top_srcdir)/version.h $(srcdir)/nls-enable.h -+ $(top_srcdir)/lib/e2p/e2p.h $(top_srcdir)/lib/support/nls-enable.h \ -+ $(top_srcdir)/version.h - dumpe2fs.o: $(srcdir)/dumpe2fs.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 \ -- $(top_srcdir)/lib/e2p/e2p.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)/version.h \ -- $(srcdir)/nls-enable.h -+ $(top_srcdir)/lib/e2p/e2p.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/support/nls-enable.h $(top_srcdir)/lib/support/plausible.h \ -+ $(top_srcdir)/version.h - badblocks.o: $(srcdir)/badblocks.c $(top_builddir)/lib/config.h \ - $(top_builddir)/lib/dirpaths.h $(top_srcdir)/lib/et/com_err.h \ - $(top_srcdir)/lib/ext2fs/ext2_io.h $(top_srcdir)/lib/ext2fs/ext2_fs.h \ -@@ -685,10 +745,10 @@ badblocks.o: $(srcdir)/badblocks.c $(top_builddir)/lib/config.h \ - $(top_srcdir)/lib/ext2fs/ext3_extents.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 -+ $(top_srcdir)/lib/support/nls-enable.h - fsck.o: $(srcdir)/fsck.c $(top_builddir)/lib/config.h \ - $(top_builddir)/lib/dirpaths.h $(top_srcdir)/version.h \ -- $(srcdir)/nls-enable.h $(srcdir)/fsck.h -+ $(top_srcdir)/lib/support/nls-enable.h $(srcdir)/fsck.h - util.o: $(srcdir)/util.c $(top_builddir)/lib/config.h \ - $(top_builddir)/lib/dirpaths.h $(top_srcdir)/lib/et/com_err.h \ - $(top_srcdir)/lib/e2p/e2p.h $(top_srcdir)/lib/ext2fs/ext2_fs.h \ -@@ -696,9 +756,9 @@ 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)/nls-enable.h $(srcdir)/util.h -+ $(top_srcdir)/lib/support/nls-enable.h $(srcdir)/util.h - uuidgen.o: $(srcdir)/uuidgen.c $(top_builddir)/lib/config.h \ -- $(top_builddir)/lib/dirpaths.h $(srcdir)/nls-enable.h -+ $(top_builddir)/lib/dirpaths.h $(top_srcdir)/lib/support/nls-enable.h - blkid.o: $(srcdir)/blkid.c $(top_builddir)/lib/config.h \ - $(top_builddir)/lib/dirpaths.h $(top_srcdir)/lib/ext2fs/ext2fs.h \ - $(top_builddir)/lib/ext2fs/ext2_types.h $(top_srcdir)/lib/ext2fs/ext2_fs.h \ -@@ -719,17 +779,13 @@ base_device.o: $(srcdir)/base_device.c $(top_builddir)/lib/config.h \ - ismounted.o: $(srcdir)/ismounted.c $(top_builddir)/lib/config.h \ - $(top_builddir)/lib/dirpaths.h $(srcdir)/fsck.h \ - $(top_srcdir)/lib/et/com_err.h --profile.o: $(srcdir)/../e2fsck/profile.c $(top_builddir)/lib/config.h \ -- $(top_builddir)/lib/dirpaths.h $(top_srcdir)/lib/et/com_err.h \ -- $(srcdir)/../e2fsck/profile.h prof_err.h - e2undo.o: $(srcdir)/e2undo.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_builddir)/lib/dirpaths.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 -+ $(top_srcdir)/lib/support/nls-enable.h - e2freefrag.o: $(srcdir)/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 \ -@@ -737,3 +793,51 @@ e2freefrag.o: $(srcdir)/e2freefrag.c $(top_builddir)/lib/config.h \ - $(top_srcdir)/lib/ext2fs/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \ - $(top_srcdir)/lib/ext2fs/ext2_ext_attr.h $(top_srcdir)/lib/ext2fs/bitops.h \ - $(srcdir)/e2freefrag.h -+create_inode.o: $(srcdir)/create_inode.c $(top_builddir)/lib/config.h \ -+ $(top_builddir)/lib/dirpaths.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 \ -+ $(top_srcdir)/lib/ext2fs/fiemap.h $(srcdir)/create_inode.h \ -+ $(top_srcdir)/lib/e2p/e2p.h $(top_srcdir)/lib/support/nls-enable.h -+fuse2fs.o: $(srcdir)/fuse2fs.c $(top_builddir)/lib/config.h \ -+ $(top_builddir)/lib/dirpaths.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 -+journal.o: $(srcdir)/../debugfs/journal.c $(top_builddir)/lib/config.h \ -+ $(top_builddir)/lib/dirpaths.h $(top_srcdir)/e2fsck/jfs_user.h \ -+ $(top_srcdir)/e2fsck/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 \ -+ $(top_srcdir)/lib/support/profile.h $(top_builddir)/lib/support/prof_err.h \ -+ $(top_srcdir)/lib/support/quotaio.h $(top_srcdir)/lib/support/dqblk_v2.h \ -+ $(top_srcdir)/lib/support/quotaio_tree.h \ -+ $(top_srcdir)/lib/ext2fs/kernel-jbd.h $(top_srcdir)/lib/ext2fs/jfs_compat.h \ -+ $(top_srcdir)/lib/ext2fs/kernel-list.h -+revoke.o: $(srcdir)/../e2fsck/revoke.c $(srcdir)/../e2fsck/jfs_user.h \ -+ $(srcdir)/../e2fsck/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 \ -+ $(top_srcdir)/lib/support/profile.h $(top_builddir)/lib/support/prof_err.h \ -+ $(top_srcdir)/lib/support/quotaio.h $(top_srcdir)/lib/support/dqblk_v2.h \ -+ $(top_srcdir)/lib/support/quotaio_tree.h \ -+ $(top_srcdir)/lib/ext2fs/kernel-jbd.h $(top_srcdir)/lib/ext2fs/jfs_compat.h \ -+ $(top_srcdir)/lib/ext2fs/kernel-list.h -+recovery.o: $(srcdir)/../e2fsck/recovery.c $(srcdir)/../e2fsck/jfs_user.h \ -+ $(srcdir)/../e2fsck/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 \ -+ $(top_srcdir)/lib/support/profile.h $(top_builddir)/lib/support/prof_err.h \ -+ $(top_srcdir)/lib/support/quotaio.h $(top_srcdir)/lib/support/dqblk_v2.h \ -+ $(top_srcdir)/lib/support/quotaio_tree.h \ -+ $(top_srcdir)/lib/ext2fs/kernel-jbd.h $(top_srcdir)/lib/ext2fs/jfs_compat.h \ -+ $(top_srcdir)/lib/ext2fs/kernel-list.h -diff --git a/misc/badblocks.c b/misc/badblocks.c -index 2c28ee0..0c4019a 100644 ---- a/misc/badblocks.c -+++ b/misc/badblocks.c -@@ -59,7 +59,7 @@ extern int optind; - #include "ext2fs/ext2_io.h" - #include "ext2fs/ext2_fs.h" - #include "ext2fs/ext2fs.h" --#include "nls-enable.h" -+#include "support/nls-enable.h" - - #ifndef O_LARGEFILE - #define O_LARGEFILE 0 -diff --git a/misc/chattr.1.in b/misc/chattr.1.in -index 75b3ed8..33ef9a2 100644 ---- a/misc/chattr.1.in -+++ b/misc/chattr.1.in -@@ -107,8 +107,8 @@ The 'e' attribute indicates that the file is using extents for mapping - the blocks on disk. It may not be removed using - .BR chattr (1). - .PP --The 'E' attribute is used by the experimental compression patches to --indicate that a compressed file has a compression error. It may not be -+The 'E' attribute is used by the experimental encryption patches to -+indicate that the file has been encrypted. It may not be - set or reset using - .BR chattr (1), - although it can be displayed by -diff --git a/misc/chattr.c b/misc/chattr.c -index f130108..e55d693 100644 ---- a/misc/chattr.c -+++ b/misc/chattr.c -@@ -51,9 +51,9 @@ - - #include "et/com_err.h" - #include "e2p/e2p.h" -+#include "support/nls-enable.h" - - #include "../version.h" --#include "nls-enable.h" - - static const char * program_name = "chattr"; - -diff --git a/misc/create_inode.c b/misc/create_inode.c -new file mode 100644 -index 0000000..1738c36 ---- /dev/null -+++ b/misc/create_inode.c -@@ -0,0 +1,899 @@ -+/* -+ * create_inode.c --- create an inode -+ * -+ * Copyright (C) 2014 Robert Yang -+ * -+ * %Begin-Header% -+ * This file may be redistributed under the terms of the GNU library -+ * General Public License, version 2. -+ * %End-Header% -+ */ -+ -+#define _FILE_OFFSET_BITS 64 -+#define _LARGEFILE64_SOURCE 1 -+#define _GNU_SOURCE 1 -+ -+#include "config.h" -+#include -+#include -+#include -+#include /* for PATH_MAX */ -+#ifdef HAVE_ATTR_XATTR_H -+#include -+#endif -+#include -+#include -+#include -+#include -+ -+#include "create_inode.h" -+#include "support/nls-enable.h" -+ -+/* 64KiB is the minimium blksize to best minimize system call overhead. */ -+#define COPY_FILE_BUFLEN 65536 -+ -+static int ext2_file_type(unsigned int mode) -+{ -+ if (LINUX_S_ISREG(mode)) -+ return EXT2_FT_REG_FILE; -+ -+ if (LINUX_S_ISDIR(mode)) -+ return EXT2_FT_DIR; -+ -+ if (LINUX_S_ISCHR(mode)) -+ return EXT2_FT_CHRDEV; -+ -+ if (LINUX_S_ISBLK(mode)) -+ return EXT2_FT_BLKDEV; -+ -+ if (LINUX_S_ISLNK(mode)) -+ return EXT2_FT_SYMLINK; -+ -+ if (LINUX_S_ISFIFO(mode)) -+ return EXT2_FT_FIFO; -+ -+ if (LINUX_S_ISSOCK(mode)) -+ return EXT2_FT_SOCK; -+ -+ return 0; -+} -+ -+/* 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, -+ ext2_file_type(inode.i_mode)); -+ 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, -+ ext2_file_type(inode.i_mode)); -+ } -+ 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; -+} -+ -+/* Set the uid, gid, mode and time for the inode */ -+static errcode_t set_inode_extra(ext2_filsys fs, 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; -+ } -+ -+ 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; -+ -+ retval = ext2fs_write_inode(fs, ino, &inode); -+ if (retval) -+ com_err(__func__, retval, _("while writing inode %u"), ino); -+ return retval; -+} -+ -+#ifdef HAVE_LLISTXATTR -+static errcode_t set_inode_xattr(ext2_filsys fs, ext2_ino_t ino, -+ const char *filename) -+{ -+ errcode_t retval, close_retval; -+ struct ext2_xattr_handle *handle; -+ ssize_t size, value_size; -+ char *list = NULL; -+ int i; -+ -+ size = llistxattr(filename, NULL, 0); -+ if (size == -1) { -+ retval = errno; -+ com_err(__func__, retval, _("while listing attributes of \"%s\""), -+ filename); -+ return retval; -+ } 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, _("while allocating memory")); -+ goto out; -+ } -+ -+ size = llistxattr(filename, list, size); -+ if (size == -1) { -+ retval = errno; -+ com_err(__func__, retval, _("while listing attributes of \"%s\""), -+ filename); -+ goto out; -+ } -+ -+ for (i = 0; i < size; i += strlen(&list[i]) + 1) { -+ const char *name = &list[i]; -+ char *value; -+ -+ value_size = lgetxattr(filename, name, NULL, 0); -+ if (value_size == -1) { -+ retval = errno; -+ com_err(__func__, retval, -+ _("while reading attribute \"%s\" of \"%s\""), -+ name, filename); -+ break; -+ } -+ -+ retval = ext2fs_get_mem(value_size, &value); -+ if (retval) { -+ com_err(__func__, retval, _("while allocating memory")); -+ break; -+ } -+ -+ value_size = lgetxattr(filename, name, value, value_size); -+ if (value_size == -1) { -+ ext2fs_free_mem(&value); -+ retval = errno; -+ com_err(__func__, retval, -+ _("while reading attribute \"%s\" of \"%s\""), -+ name, filename); -+ break; -+ } -+ -+ retval = ext2fs_xattr_set(handle, name, value, value_size); -+ ext2fs_free_mem(&value); -+ if (retval) { -+ com_err(__func__, retval, -+ _("while writing attribute \"%s\" to inode %u"), -+ name, 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; -+ return 0; -+} -+#else /* HAVE_LLISTXATTR */ -+static errcode_t set_inode_xattr(ext2_filsys fs EXT2FS_ATTR((unused)), -+ ext2_ino_t ino EXT2FS_ATTR((unused)), -+ const char *filename EXT2FS_ATTR((unused))) -+{ -+ 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; -+ } -+ -+ retval = ext2fs_new_inode(fs, cwd, 010755, 0, &ino); -+ if (retval) { -+ com_err(__func__, retval, _("while allocating inode \"%s\""), -+ name); -+ 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, _("while creating inode \"%s\""), name); -+ 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 writing 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; -+ -+ 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; -+ -+ 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; -+ } -+ retval = ext2fs_symlink(fs, parent_ino, 0, name, target); -+ } -+ if (retval) -+ com_err("ext2fs_symlink", retval, -+ _("while creating symlink \"%s\""), name); -+ return retval; -+} -+ -+/* Make a directory in the fs */ -+errcode_t do_mkdir_internal(ext2_filsys fs, ext2_ino_t cwd, const char *name, -+ ext2_ino_t root) -+{ -+ char *cp; -+ ext2_ino_t parent_ino; -+ errcode_t retval; -+ -+ -+ cp = strrchr(name, '/'); -+ if (cp) { -+ *cp = 0; -+ retval = ext2fs_namei(fs, root, cwd, name, &parent_ino); -+ if (retval) { -+ com_err(name, retval, _("while looking up \"%s\""), -+ name); -+ return retval; -+ } -+ name = cp+1; -+ } else -+ parent_ino = cwd; -+ -+ 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; -+ } -+ retval = ext2fs_mkdir(fs, parent_ino, 0, name); -+ } -+ if (retval) -+ com_err("ext2fs_mkdir", retval, -+ _("while creating directory \"%s\""), name); -+ return retval; -+} -+ -+#if !defined HAVE_PREAD64 && !defined HAVE_PREAD -+static ssize_t my_pread(int fd, void *buf, size_t count, off_t offset) -+{ -+ if (lseek(fd, offset, SEEK_SET) < 0) -+ return 0; -+ -+ return read(fd, buf, count); -+} -+#endif /* !defined HAVE_PREAD64 && !defined HAVE_PREAD */ -+ -+static errcode_t copy_file_range(ext2_filsys fs, int fd, ext2_file_t e2_file, -+ off_t start, off_t end, char *buf, -+ char *zerobuf) -+{ -+ off_t off, bpos; -+ ssize_t got, blen; -+ unsigned int written; -+ char *ptr; -+ errcode_t err = 0; -+ -+ for (off = start; off < end; off += COPY_FILE_BUFLEN) { -+#ifdef HAVE_PREAD64 -+ got = pread64(fd, buf, COPY_FILE_BUFLEN, off); -+#elif HAVE_PREAD -+ got = pread(fd, buf, COPY_FILE_BUFLEN, off); -+#else -+ got = my_pread(fd, buf, COPY_FILE_BUFLEN, off); -+#endif -+ if (got < 0) { -+ err = errno; -+ goto fail; -+ } -+ for (bpos = 0, ptr = buf; bpos < got; bpos += fs->blocksize) { -+ blen = fs->blocksize; -+ if (blen > got - bpos) -+ blen = got - bpos; -+ if (memcmp(ptr, zerobuf, blen) == 0) { -+ ptr += blen; -+ continue; -+ } -+ err = ext2fs_file_lseek(e2_file, off + bpos, -+ EXT2_SEEK_SET, NULL); -+ if (err) -+ goto fail; -+ while (blen > 0) { -+ err = ext2fs_file_write(e2_file, ptr, blen, -+ &written); -+ if (err) -+ goto fail; -+ if (written == 0) { -+ err = EIO; -+ goto fail; -+ } -+ blen -= written; -+ ptr += written; -+ } -+ } -+ } -+fail: -+ return err; -+} -+ -+static errcode_t try_lseek_copy(ext2_filsys fs, int fd, struct stat *statbuf, -+ ext2_file_t e2_file, char *buf, char *zerobuf) -+{ -+#if defined(SEEK_DATA) && defined(SEEK_HOLE) -+ off_t data = 0, hole; -+ off_t data_blk, hole_blk; -+ errcode_t err; -+ -+ /* Try to use SEEK_DATA and SEEK_HOLE */ -+ while (data < statbuf->st_size) { -+ data = lseek(fd, data, SEEK_DATA); -+ if (data < 0) { -+ if (errno == ENXIO) -+ break; -+ return EXT2_ET_UNIMPLEMENTED; -+ } -+ hole = lseek(fd, data, SEEK_HOLE); -+ if (hole < 0) -+ return EXT2_ET_UNIMPLEMENTED; -+ -+ data_blk = data & ~(fs->blocksize - 1); -+ hole_blk = (hole + (fs->blocksize - 1)) & ~(fs->blocksize - 1); -+ err = copy_file_range(fs, fd, e2_file, data_blk, hole_blk, buf, -+ zerobuf); -+ if (err) -+ return err; -+ -+ data = hole; -+ } -+ -+ return err; -+#else -+ return EXT2_ET_UNIMPLEMENTED; -+#endif /* SEEK_DATA and SEEK_HOLE */ -+} -+ -+static errcode_t try_fiemap_copy(ext2_filsys fs, int fd, ext2_file_t e2_file, -+ char *buf, char *zerobuf) -+{ -+#if defined(FS_IOC_FIEMAP) -+#define EXTENT_MAX_COUNT 512 -+ struct fiemap *fiemap_buf; -+ struct fiemap_extent *ext_buf, *ext; -+ int ext_buf_size, fie_buf_size; -+ off_t pos = 0; -+ unsigned int i; -+ errcode_t err; -+ -+ ext_buf_size = EXTENT_MAX_COUNT * sizeof(struct fiemap_extent); -+ fie_buf_size = sizeof(struct fiemap) + ext_buf_size; -+ -+ err = ext2fs_get_memzero(fie_buf_size, &fiemap_buf); -+ if (err) -+ return err; -+ -+ ext_buf = fiemap_buf->fm_extents; -+ memset(fiemap_buf, 0, fie_buf_size); -+ fiemap_buf->fm_length = FIEMAP_MAX_OFFSET; -+ fiemap_buf->fm_flags |= FIEMAP_FLAG_SYNC; -+ fiemap_buf->fm_extent_count = EXTENT_MAX_COUNT; -+ -+ do { -+ fiemap_buf->fm_start = pos; -+ memset(ext_buf, 0, ext_buf_size); -+ err = ioctl(fd, FS_IOC_FIEMAP, fiemap_buf); -+ if (err < 0 && (errno == EOPNOTSUPP || errno == ENOTTY)) { -+ err = EXT2_ET_UNIMPLEMENTED; -+ goto out; -+ } else if (err < 0 || fiemap_buf->fm_mapped_extents == 0) { -+ err = errno; -+ goto out; -+ } -+ for (i = 0, ext = ext_buf; i < fiemap_buf->fm_mapped_extents; -+ i++, ext++) { -+ err = copy_file_range(fs, fd, e2_file, ext->fe_logical, -+ ext->fe_logical + ext->fe_length, -+ buf, zerobuf); -+ if (err) -+ goto out; -+ } -+ -+ ext--; -+ /* Record file's logical offset this time */ -+ pos = ext->fe_logical + ext->fe_length; -+ /* -+ * If fm_extents array has been filled and -+ * there are extents left, continue to cycle. -+ */ -+ } while (fiemap_buf->fm_mapped_extents == EXTENT_MAX_COUNT && -+ !(ext->fe_flags & FIEMAP_EXTENT_LAST)); -+out: -+ ext2fs_free_mem(&fiemap_buf); -+ return err; -+#else -+ return EXT2_ET_UNIMPLEMENTED; -+#endif /* FS_IOC_FIEMAP */ -+} -+ -+static errcode_t copy_file(ext2_filsys fs, int fd, struct stat *statbuf, -+ ext2_ino_t ino) -+{ -+ ext2_file_t e2_file; -+ char *buf = NULL, *zerobuf = NULL; -+ errcode_t err, close_err; -+ -+ err = ext2fs_file_open(fs, ino, EXT2_FILE_WRITE, &e2_file); -+ if (err) -+ return err; -+ -+ err = ext2fs_get_mem(COPY_FILE_BUFLEN, &buf); -+ if (err) -+ goto out; -+ -+ err = ext2fs_get_memzero(fs->blocksize, &zerobuf); -+ if (err) -+ goto out; -+ -+ err = try_lseek_copy(fs, fd, statbuf, e2_file, buf, zerobuf); -+ if (err != EXT2_ET_UNIMPLEMENTED) -+ goto out; -+ -+ err = try_fiemap_copy(fs, fd, e2_file, buf, zerobuf); -+ if (err != EXT2_ET_UNIMPLEMENTED) -+ goto out; -+ -+ err = copy_file_range(fs, fd, e2_file, 0, statbuf->st_size, buf, -+ zerobuf); -+out: -+ ext2fs_free_mem(&zerobuf); -+ ext2fs_free_mem(&buf); -+ close_err = ext2fs_file_close(e2_file); -+ if (err == 0) -+ err = close_err; -+ return err; -+} -+ -+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; -+ -+ fd = ext2fs_open_file(src, O_RDONLY, 0); -+ if (fd < 0) { -+ retval = errno; -+ com_err(__func__, retval, _("while opening \"%s\" to copy"), -+ src); -+ return retval; -+ } -+ if (fstat(fd, &statbuf) < 0) { -+ retval = errno; -+ goto out; -+ } -+ -+ retval = ext2fs_namei(fs, root, cwd, dest, &newfile); -+ if (retval == 0) { -+ retval = EXT2_ET_FILE_EXISTS; -+ goto out; -+ } -+ -+ retval = ext2fs_new_inode(fs, cwd, 010755, 0, &newfile); -+ if (retval) -+ goto out; -+#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) -+ goto out; -+ retval = ext2fs_link(fs, cwd, dest, newfile, -+ EXT2_FT_REG_FILE); -+ } -+ if (retval) -+ goto out; -+ 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) -+ goto out; -+ 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) { -+ ext2_extent_handle_t handle; -+ -+ inode.i_flags &= ~EXT4_EXTENTS_FL; -+ retval = ext2fs_extent_open2(fs, newfile, &inode, &handle); -+ if (retval) -+ goto out; -+ ext2fs_extent_free(handle); -+ } -+ -+ retval = ext2fs_write_new_inode(fs, newfile, &inode); -+ if (retval) -+ goto out; -+ if (inode.i_flags & EXT4_INLINE_DATA_FL) { -+ retval = ext2fs_inline_data_init(fs, newfile); -+ if (retval) -+ goto out; -+ } -+ if (LINUX_S_ISREG(inode.i_mode)) { -+ retval = copy_file(fs, fd, &statbuf, newfile); -+ if (retval) -+ goto out; -+ } -+out: -+ 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) { -+ retval = errno; -+ com_err(__func__, retval, -+ _("while changing working directory to \"%s\""), -+ source_dir); -+ return retval; -+ } -+ -+ if (!(dh = opendir("."))) { -+ retval = errno; -+ com_err(__func__, retval, -+ _("while opening directory \"%s\""), source_dir); -+ return retval; -+ } -+ -+ while ((dent = readdir(dh))) { -+ if ((!strcmp(dent->d_name, ".")) || -+ (!strcmp(dent->d_name, ".."))) -+ continue; -+ if (lstat(dent->d_name, &st)) { -+ retval = errno; -+ com_err(__func__, retval, _("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) { -+ retval = errno; -+ com_err(__func__, retval, -+ _("while trying to read link \"%s\""), -+ name); -+ 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: -+ /* Don't choke on /lost+found */ -+ if (parent_ino == EXT2_ROOT_INO && -+ strcmp(name, "lost+found") == 0) -+ goto find_lnf; -+ retval = do_mkdir_internal(fs, parent_ino, name, -+ root); -+ if (retval) { -+ com_err(__func__, retval, -+ _("while making dir \"%s\""), name); -+ goto out; -+ } -+find_lnf: -+ 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) -+ goto out; -+ if (chdir("..")) { -+ retval = errno; -+ com_err(__func__, retval, -+ _("while changing directory")); -+ 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, _("while looking up \"%s\""), -+ name); -+ goto out; -+ } -+ -+ retval = set_inode_extra(fs, 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) { -+ retval = EXT2_ET_NO_MEMORY; -+ com_err(name, retval, -+ _("while saving inode data")); -+ 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; -+ -+ if (!(fs->flags & EXT2_FLAG_RW)) { -+ com_err(__func__, 0, "Filesystem opened readonly"); -+ return EROFS; -+ } -+ -+ hdlinks.count = 0; -+ hdlinks.size = HDLINK_CNT; -+ hdlinks.hdl = realloc(NULL, hdlinks.size * sizeof(struct hdlink_s)); -+ if (hdlinks.hdl == NULL) { -+ retval = errno; -+ com_err(__func__, retval, _("while allocating memory")); -+ return retval; -+ } -+ -+ 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 -index 0000000..cf49df2 ---- /dev/null -+++ b/misc/create_inode.h -@@ -0,0 +1,41 @@ -+#ifndef _CREATE_INODE_H -+#define _CREATE_INODE_H -+ -+#include -+#include -+#include -+#include "et/com_err.h" -+#include "e2p/e2p.h" -+#include "ext2fs/ext2fs.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, 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 */ -diff --git a/misc/dumpe2fs.8.in b/misc/dumpe2fs.8.in -index befaf94..8d9a559 100644 ---- a/misc/dumpe2fs.8.in -+++ b/misc/dumpe2fs.8.in -@@ -8,7 +8,7 @@ dumpe2fs \- dump ext2/ext3/ext4 filesystem information - .SH SYNOPSIS - .B dumpe2fs - [ --.B \-bfhixV -+.B \-bfghixV - ] - [ - .B \-o superblock=\fIsuperblock -@@ -49,6 +49,14 @@ is examining the remains of a very badly corrupted filesystem. - force dumpe2fs to display a filesystem even though it may have some - filesystem feature flags which dumpe2fs may not understand (and which - can cause some of dumpe2fs's display to be suspect). -+.TP -+.B \-g -+display the group descriptor information in a machine readable colon-separated -+value format. The fields displayed are the group number; the number of the -+first block in the group; the superblock location (or -1 if not present); the -+range of blocks used by the group descriptors (or -1 if not present); the block -+bitmap location; the inode bitmap location; and the range of blocks used by the -+inode table. - .TP - .B \-h - only display the superblock information and not any of the block -diff --git a/misc/dumpe2fs.c b/misc/dumpe2fs.c -index 4185d6e..9e1e5d0 100644 ---- a/misc/dumpe2fs.c -+++ b/misc/dumpe2fs.c -@@ -37,11 +37,12 @@ extern int optind; - - #include "ext2fs/ext2fs.h" - #include "e2p/e2p.h" --#include "jfs_user.h" -+#include "ext2fs/kernel-jbd.h" - #include - -+#include "support/nls-enable.h" -+#include "support/plausible.h" - #include "../version.h" --#include "nls-enable.h" - - #define in_use(m, x) (ext2fs_test_bit ((x), (m))) - -@@ -52,9 +53,9 @@ static int blocks64 = 0; - - static void usage(void) - { -- fprintf (stderr, _("Usage: %s [-bfhixV] [-o superblock=] " -+ fprintf(stderr, _("Usage: %s [-bfghixV] [-o superblock=] " - "[-o blocksize=] device\n"), program_name); -- exit (1); -+ exit(1); - } - - static void print_number(unsigned long long num) -@@ -121,7 +122,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", -@@ -150,7 +151,7 @@ static void print_bg_rel_offset(ext2_filsys fs, blk64_t block, int itable, - } - } - --static void list_desc (ext2_filsys fs) -+static void list_desc(ext2_filsys fs, int grp_only) - { - unsigned long i; - blk64_t first_block, last_block; -@@ -187,6 +188,8 @@ static void list_desc (ext2_filsys fs) - old_desc_blocks = fs->super->s_first_meta_bg; - else - old_desc_blocks = fs->desc_blocks; -+ if (grp_only) -+ printf("group:block:super:gdt:bbitmap:ibitmap:itable\n"); - for (i = 0; i < fs->group_desc_count; i++) { - first_block = ext2fs_group_first_block2(fs, i); - last_block = ext2fs_group_last_block2(fs, i); -@@ -194,20 +197,39 @@ static void list_desc (ext2_filsys fs) - ext2fs_super_and_bgd_loc2(fs, i, &super_blk, - &old_desc_blk, &new_desc_blk, 0); - -- printf (_("Group %lu: (Blocks "), i); -+ if (grp_only) { -+ printf("%lu:%llu:", i, first_block); -+ if (i == 0 || super_blk) -+ printf("%llu:", super_blk); -+ else -+ printf("-1:"); -+ if (old_desc_blk) { -+ print_range(old_desc_blk, -+ old_desc_blk + old_desc_blocks - 1); -+ printf(":"); -+ } else if (new_desc_blk) -+ printf("%llu:", new_desc_blk); -+ else -+ printf("-1:"); -+ printf("%llu:%llu:%llu\n", -+ ext2fs_block_bitmap_loc(fs, i), -+ ext2fs_inode_bitmap_loc(fs, i), -+ ext2fs_inode_table_loc(fs, i)); -+ continue; -+ } -+ -+ printf(_("Group %lu: (Blocks "), i); - 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); - -- printf(_(" Checksum 0x%04x"), csum); -+ printf(_(" csum 0x%04x"), csum); - if (csum != exp_csum) - printf(_(" (EXPECTED 0x%04x)"), exp_csum); -- printf(_(", unused inodes %u\n"), -- ext2fs_bg_itable_unused(fs, i)); - } -+ print_bg_opts(fs, i); - has_super = ((i==0) || super_blk); - if (has_super) { - printf (_(" %s superblock at "), -@@ -236,10 +258,22 @@ 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); -- fputs(_(", Inode bitmap at "), stdout); -+ if (fs->super->s_feature_ro_compat & -+ EXT4_FEATURE_RO_COMPAT_METADATA_CSUM) -+ printf(_(", csum 0x%08x"), -+ ext2fs_block_bitmap_checksum(fs, i)); -+ if (getenv("DUMPE2FS_IGNORE_80COL")) -+ fputs(_(","), stdout); -+ else -+ fputs(_("\n "), stdout); -+ 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 +360,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 +438,17 @@ 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_V3)) || -+ (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)); -@@ -404,8 +459,9 @@ static void print_journal_information(ext2_filsys fs) - errcode_t retval; - char buf[1024]; - char str[80]; -- unsigned int i; -+ unsigned int i, j, printed = 0; - journal_superblock_t *jsb; -+ __u32 *mask_ptr, mask, m; - - /* Get the journal superblock */ - if ((retval = io_channel_read_blk64(fs->io, -@@ -424,6 +480,29 @@ 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_V3)) || -+ (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("%s", _("Journal features: ")); -+ for (i = 0, mask_ptr = &jsb->s_feature_compat; i < 3; i++, mask_ptr++) { -+ mask = be32_to_cpu(*mask_ptr); -+ for (j = 0, m = 1; j < 32; j++, m <<= 1) { -+ if (mask & m) { -+ printf(" %s", e2p_jrnl_feature2string(i, m)); -+ printed++; -+ } -+ } -+ } -+ - printf(_("\nJournal block size: %u\n" - "Journal length: %u\n" - "Journal first block: %u\n" -@@ -531,6 +610,7 @@ int main (int argc, char ** argv) - int flags; - int header_only = 0; - int c; -+ int grp_only = 0; - - #ifdef ENABLE_NLS - setlocale(LC_MESSAGES, ""); -@@ -545,7 +625,7 @@ int main (int argc, char ** argv) - if (argc && *argv) - program_name = *argv; - -- while ((c = getopt (argc, argv, "bfhixVo:")) != EOF) { -+ while ((c = getopt(argc, argv, "bfghixVo:")) != EOF) { - switch (c) { - case 'b': - print_badblocks++; -@@ -553,6 +633,9 @@ int main (int argc, char ** argv) - case 'f': - force++; - break; -+ case 'g': -+ grp_only++; -+ break; - case 'h': - header_only++; - break; -@@ -585,7 +668,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; -@@ -600,10 +683,19 @@ 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); - printf("%s", _("Couldn't find valid filesystem superblock.\n")); -+ if (retval == EXT2_ET_BAD_MAGIC) -+ check_plausibility(device_name, CHECK_FS_EXIST, NULL); - exit (1); - } - fs->default_bitmap_type = EXT2FS_BMAP64_RBTREE; -@@ -612,6 +704,8 @@ int main (int argc, char ** argv) - if (print_badblocks) { - list_bad_blocks(fs, 1); - } else { -+ if (grp_only) -+ goto just_descriptors; - list_super (fs->super); - if (fs->super->s_feature_incompat & - EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) { -@@ -628,8 +722,17 @@ 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); -- list_desc (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")); -+just_descriptors: -+ list_desc(fs, grp_only); - if (retval) { - printf(_("\n%s: %s: error reading bitmaps: %s\n"), - program_name, device_name, -diff --git a/misc/e2fuzz.c b/misc/e2fuzz.c -new file mode 100644 -index 0000000..5e33239 ---- /dev/null -+++ b/misc/e2fuzz.c -@@ -0,0 +1,370 @@ -+/* -+ * 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 -+#include -+#include -+#include -+#include -+#ifdef HAVE_GETOPT_H -+#include -+#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; -+ -+#if !defined HAVE_PWRITE64 && !defined HAVE_PWRITE -+static ssize_t my_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 /* !defined HAVE_PWRITE64 && !defined HAVE_PWRITE */ -+ -+static int getseed(void) -+{ -+ int r; -+ int fd; -+ -+ fd = open("/dev/urandom", O_RDONLY); -+ if (fd < 0) { -+ perror("open"); -+ exit(0); -+ } -+ if (read(fd, &r, sizeof(r)) != sizeof(r)) -+ printf("Unable to read random seed!\n"); -+ close(fd); -+ return r; -+} -+ -+struct find_block { -+ ext2_ino_t ino; -+ ext2fs_block_bitmap bmap; -+ struct ext2_inode *inode; -+ blk64_t corrupt_blocks; -+}; -+ -+static int find_block_helper(ext2_filsys fs EXT2FS_ATTR((unused)), -+ blk64_t *blocknr, e2_blkcnt_t blockcnt, -+ blk64_t ref_blk EXT2FS_ATTR((unused)), -+ int ref_offset EXT2FS_ATTR((unused)), -+ 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; -+} -+ -+static 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; -+} -+ -+static uint64_t rand_num(uint64_t min, uint64_t max) -+{ -+ uint64_t x; -+ unsigned 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))); -+} -+ -+static 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; -+ off_t 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 %zu in block %zu to 0x%x\n", -+ off % fs->blocksize, off / fs->blocksize, c); -+ if (dryrun) -+ continue; -+#ifdef HAVE_PWRITE64 -+ if (pwrite64(fd, &c, sizeof(c), off) != sizeof(c)) { -+ perror(fsname); -+ goto fail3; -+ } -+#elif HAVE_PWRITE -+ if (pwrite(fd, &c, sizeof(c), off) != sizeof(c)) { -+ perror(fsname); -+ goto fail3; -+ } -+#else -+ if (my_pwrite(fd, &c, sizeof(c), off) != sizeof(c)) { -+ perror(fsname); -+ goto fail3; -+ } -+#endif -+ } -+ 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; -+} -+ -+static 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 -index 0000000..389f2ca ---- /dev/null -+++ b/misc/e2fuzz.sh -@@ -0,0 +1,327 @@ -+#!/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 e2fsck 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 * 4 / 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}/" -type f 2> /dev/null | head -n 50000 | while read f; do -+ attr -l "$f" > /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 -+ mv "$f" "$f.longer" > /dev/null 2>> "${OPS_LOG}" -+ 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}" -+ pass_img_sz="$(stat -c '%s' "${PASS_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 -+ -+ fsck_img_sz="$(stat -c '%s' "${FSCK_IMG}")" -+ if [ "${fsck_img_sz}" -ne "${pass_img_sz}" ]; then -+ echo "++ fsck image size changed" -+ exit 3 -+ fi -+ done -+ fsck_loop_ret=$? -+ if [ "${fsck_loop_ret}" -gt 0 ]; then -+ break; -+ fi -+ fi -+ -+ echo "+++ check fs for round 2" -+ FSCK_LOG="${TESTDIR}/e2fuzz-${pass}-round2.log" -+ e2fsck -fn "${FSCK_IMG}" ${EXTENDED_FSCK_OPTS} >> "${FSCK_LOG}" 2>&1 -+ res=$? -+ if [ "${res}" -ne 0 ]; then -+ echo "++++ fsck failed." -+ exit 1 -+ fi -+ -+ echo "++ mount image (2)" -+ mount "${FSCK_IMG}" "${TESTMNT}" -o loop -+ res=$? -+ -+ if [ "${res}" -eq 0 ]; then -+ echo "+++ ls -laR (2)" -+ ls -laR "${TESTMNT}/test.1/" > /dev/null 2> "${OPS_LOG}" -+ -+ echo "+++ cat files (2)" -+ find "${TESTMNT}/test.1/" -type f -size -1048576k -print0 | xargs -0 cat > /dev/null 2>> "${OPS_LOG}" -+ -+ echo "+++ expand (2)" -+ find "${TESTMNT}/" -type f 2> /dev/null | head -n 50000 | while read f; do -+ attr -l "$f" > /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 -+ mv "$f" "$f.longer" > /dev/null 2>> "${OPS_LOG}" -+ done -+ sync -+ -+ echo "+++ create files (2)" -+ cp -pRdu "${SRCDIR}" "${TESTMNT}/test.moo" 2>> "${OPS_LOG}" -+ sync -+ -+ echo "+++ remove files (2)" -+ 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 -+ -+ echo "+++ check fs (2)" -+ e2fsck -fn "${FSCK_IMG}" >> "${FSCK_LOG}" 2>&1 -+ res=$? -+ if [ "${res}" -ne 0 ]; then -+ echo "++ fsck failed." -+ exit 1 -+ fi -+ else -+ echo "++ mount(2) failed with ${res}" -+ exit 1 -+ fi -+ rm -rf "${FSCK_IMG}" "${PASS_IMG}" "${FUZZ_LOG}" "${TESTDIR}"/e2fuzz*.log -+done -+ -+exit $ret -diff --git a/misc/e2image.c b/misc/e2image.c -index 82fe3e8..e9b4ae2 100644 ---- a/misc/e2image.c -+++ b/misc/e2image.c -@@ -10,8 +10,12 @@ - * %End-Header% - */ - -+#ifndef _LARGEFILE_SOURCE - #define _LARGEFILE_SOURCE -+#endif -+#ifndef _LARGEFILE64_SOURCE - #define _LARGEFILE64_SOURCE -+#endif - - #include "config.h" - #include -@@ -45,8 +49,9 @@ extern int optind; - #include "ext2fs/e2image.h" - #include "ext2fs/qcow2.h" - -+#include "support/nls-enable.h" -+#include "support/plausible.h" - #include "../version.h" --#include "nls-enable.h" - - #define QCOW_OFLAG_COPIED (1LL << 63) - #define NO_BLK ((blk64_t) -1) -@@ -419,9 +424,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); -@@ -1580,6 +1583,8 @@ int main (int argc, char ** argv) - com_err (program_name, retval, _("while trying to open %s"), - device_name); - fputs(_("Couldn't find valid filesystem superblock.\n"), stdout); -+ if (retval == EXT2_ET_BAD_MAGIC) -+ check_plausibility(device_name, CHECK_FS_EXIST, NULL); - exit(1); - } - -diff --git a/misc/e2initrd_helper.c b/misc/e2initrd_helper.c -index 765716d..436aab8 100644 ---- a/misc/e2initrd_helper.c -+++ b/misc/e2initrd_helper.c -@@ -35,9 +35,9 @@ extern char *optarg; - #include "ext2fs/ext2_fs.h" - #include "ext2fs/ext2fs.h" - #include "blkid/blkid.h" -+#include "support/nls-enable.h" - - #include "../version.h" --#include "nls-enable.h" - - static const char * program_name = "e2initrd_helper"; - static char * device_name; -diff --git a/misc/e2label.c b/misc/e2label.c -index bc87a42..526a62c 100644 ---- a/misc/e2label.c -+++ b/misc/e2label.c -@@ -33,7 +33,7 @@ extern int optind; - #ifdef HAVE_ERRNO_H - #include - #endif --#include "nls-enable.h" -+#include "support/nls-enable.h" - - #define EXT2_SUPER_MAGIC 0xEF53 - -diff --git a/misc/e2undo.8.in b/misc/e2undo.8.in -index 4bf0798..71e8a7b 100644 ---- a/misc/e2undo.8.in -+++ b/misc/e2undo.8.in -@@ -10,6 +10,12 @@ e2undo \- Replay an undo log for an ext2/ext3/ext4 filesystem - [ - .B \-f - ] -+[ -+.B \-n -+] -+[ -+.B \-v -+] - .I undo_log device - .SH DESCRIPTION - .B e2undo -@@ -24,13 +30,18 @@ used to undo a failed operation by an e2fsprogs program. - .B \-f - Normally, - .B e2undo --will check the filesystem UUID and last modified time to make sure the --undo log matches with the filesystem on the device. If they do not --match, -+will check the filesystem superblock to make sure the undo log matches -+with the filesystem on the device. If they do not match, - .B e2undo - will refuse to apply the undo log as a safety mechanism. The - .B \-f - option disables this safety mechanism. -+.TP -+.B \-n -+Dry-run; do not actually write blocks back to the filesystem. -+.TP -+.B \-v -+Report which block we're currently replaying. - .SH AUTHOR - .B e2undo - was written by Aneesh Kumar K.V. (aneesh.kumar@linux.vnet.ibm.com) -diff --git a/misc/e2undo.c b/misc/e2undo.c -index a43c26f..7c7326a 100644 ---- a/misc/e2undo.c -+++ b/misc/e2undo.c -@@ -20,115 +20,278 @@ - #if HAVE_ERRNO_H - #include - #endif --#include "ext2fs/tdb.h" -+#include - #include "ext2fs/ext2fs.h" --#include "nls-enable.h" -+#include "support/nls-enable.h" - --static unsigned char mtime_key[] = "filesystem MTIME"; --static unsigned char uuid_key[] = "filesystem UUID"; --static unsigned char blksize_key[] = "filesystem BLKSIZE"; -+#undef DEBUG -+ -+#ifdef DEBUG -+# define dbg_printf(f, a...) do {printf(f, ## a); fflush(stdout); } while (0) -+#else -+# define dbg_printf(f, a...) -+#endif -+ -+/* -+ * Undo file format: The file is cut up into undo_header.block_size blocks. -+ * The first block contains the header. -+ * The second block contains the superblock. -+ * There is then a repeating series of blocks as follows: -+ * A key block, which contains undo_keys to map the following data blocks. -+ * Data blocks -+ * (Note that there are pointers to the first key block and the sb, so this -+ * order isn't strictly necessary.) -+ */ -+#define E2UNDO_MAGIC "E2UNDO02" -+#define KEYBLOCK_MAGIC 0xCADECADE -+ -+#define E2UNDO_STATE_FINISHED 0x1 /* undo file is complete */ -+ -+#define E2UNDO_MIN_BLOCK_SIZE 1024 /* undo blocks are no less than 1KB */ -+#define E2UNDO_MAX_BLOCK_SIZE 1048576 /* undo blocks are no more than 1MB */ -+ -+struct undo_header { -+ char magic[8]; /* "E2UNDO02" */ -+ __le64 num_keys; /* how many keys? */ -+ __le64 super_offset; /* where in the file is the superblock copy? */ -+ __le64 key_offset; /* where do the key/data block chunks start? */ -+ __le32 block_size; /* block size of the undo file */ -+ __le32 fs_block_size; /* block size of the target device */ -+ __le32 sb_crc; /* crc32c of the superblock */ -+ __le32 state; /* e2undo state flags */ -+ __le32 f_compat; /* compatible features (none so far) */ -+ __le32 f_incompat; /* incompatible features (none so far) */ -+ __le32 f_rocompat; /* ro compatible features (none so far) */ -+ __u8 padding[448]; /* padding */ -+ __le32 header_crc; /* crc32c of the header (but not this field) */ -+}; -+ -+#define E2UNDO_MAX_EXTENT_BLOCKS 512 /* max extent size, in blocks */ -+ -+struct undo_key { -+ __le64 fsblk; /* where in the fs does the block go */ -+ __le32 blk_crc; /* crc32c of the block */ -+ __le32 size; /* how many bytes in this block? */ -+}; -+ -+struct undo_key_block { -+ __le32 magic; /* KEYBLOCK_MAGIC number */ -+ __le32 crc; /* block checksum */ -+ __le64 reserved; /* zero */ -+ -+ struct undo_key keys[0]; /* keys, which come immediately after */ -+}; -+ -+struct undo_key_info { -+ blk64_t fsblk; -+ blk64_t fileblk; -+ __u32 blk_crc; -+ unsigned int size; -+}; -+ -+struct undo_context { -+ struct undo_header hdr; -+ io_channel undo_file; -+ unsigned int blocksize, fs_blocksize; -+ blk64_t super_block; -+ size_t num_keys; -+ struct undo_key_info *keys; -+}; -+#define KEYS_PER_BLOCK(d) (((d)->blocksize / sizeof(struct undo_key)) - 1) - - static char *prg_name; -+static char *undo_file; - - static void usage(void) - { - fprintf(stderr, -- _("Usage: %s \n"), prg_name); -+ _("Usage: %s [-f] [-h] [-n] [-v] \n"), prg_name); - exit(1); - } - --static int check_filesystem(TDB_CONTEXT *tdb, io_channel channel) -+static void dump_header(struct undo_header *hdr) -+{ -+ printf("nr keys:\t%llu\n", ext2fs_le64_to_cpu(hdr->num_keys)); -+ printf("super block:\t%llu\n", ext2fs_le64_to_cpu(hdr->super_offset)); -+ printf("key block:\t%llu\n", ext2fs_le64_to_cpu(hdr->key_offset)); -+ printf("block size:\t%u\n", ext2fs_le32_to_cpu(hdr->block_size)); -+ printf("fs block size:\t%u\n", ext2fs_le32_to_cpu(hdr->fs_block_size)); -+ printf("super crc:\t0x%x\n", ext2fs_le32_to_cpu(hdr->sb_crc)); -+ printf("state:\t\t0x%x\n", ext2fs_le32_to_cpu(hdr->state)); -+ printf("compat:\t\t0x%x\n", ext2fs_le32_to_cpu(hdr->f_compat)); -+ printf("incompat:\t0x%x\n", ext2fs_le32_to_cpu(hdr->f_incompat)); -+ printf("rocompat:\t0x%x\n", ext2fs_le32_to_cpu(hdr->f_rocompat)); -+ printf("header crc:\t0x%x\n", ext2fs_le32_to_cpu(hdr->header_crc)); -+} -+ -+static void print_undo_mismatch(struct ext2_super_block *fs_super, -+ struct ext2_super_block *undo_super) -+{ -+ printf("%s", -+ _("The file system superblock doesn't match the undo file.\n")); -+ if (memcmp(fs_super->s_uuid, undo_super->s_uuid, -+ sizeof(fs_super->s_uuid))) -+ printf("%s", _("UUID does not match.\n")); -+ if (fs_super->s_mtime != undo_super->s_mtime) -+ printf("%s", _("Last mount time does not match.\n")); -+ if (fs_super->s_wtime != undo_super->s_wtime) -+ printf("%s", _("Last write time does not match.\n")); -+ if (fs_super->s_kbytes_written != undo_super->s_kbytes_written) -+ printf("%s", _("Lifetime write counter does not match.\n")); -+} -+ -+static int check_filesystem(struct undo_context *ctx, io_channel channel) - { -- __u32 s_mtime; -- __u8 s_uuid[16]; -+ struct ext2_super_block super, *sb; -+ char *buf; -+ __u32 sb_crc; - errcode_t retval; -- TDB_DATA tdb_key, tdb_data; -- struct ext2_super_block super; - - io_channel_set_blksize(channel, SUPERBLOCK_OFFSET); - retval = io_channel_read_blk64(channel, 1, -SUPERBLOCK_SIZE, &super); - if (retval) { - com_err(prg_name, retval, -- "%s", _("Failed to read the file system data \n")); -+ "%s", _("while reading filesystem superblock.")); - return retval; - } - -- tdb_key.dptr = mtime_key; -- tdb_key.dsize = sizeof(mtime_key); -- tdb_data = tdb_fetch(tdb, tdb_key); -- if (!tdb_data.dptr) { -- retval = EXT2_ET_TDB_SUCCESS + tdb_error(tdb); -- com_err(prg_name, retval, -- _("Failed tdb_fetch %s\n"), tdb_errorstr(tdb)); -+ /* -+ * Compare the FS and the undo file superblock so that we can't apply -+ * e2undo "patches" out of order. -+ */ -+ retval = ext2fs_get_mem(ctx->blocksize, &buf); -+ if (retval) { -+ com_err(prg_name, retval, "%s", _("while allocating memory")); - return retval; - } -- -- s_mtime = *(__u32 *)tdb_data.dptr; -- if (super.s_mtime != s_mtime) { -- -- com_err(prg_name, 0, -- _("The file system Mount time didn't match %u\n"), -- s_mtime); -- -- return -1; -+ retval = io_channel_read_blk64(ctx->undo_file, ctx->super_block, -+ -SUPERBLOCK_SIZE, buf); -+ if (retval) { -+ com_err(prg_name, retval, "%s", _("while fetching superblock")); -+ goto out; - } -- -- -- tdb_key.dptr = uuid_key; -- tdb_key.dsize = sizeof(uuid_key); -- tdb_data = tdb_fetch(tdb, tdb_key); -- if (!tdb_data.dptr) { -- retval = EXT2_ET_TDB_SUCCESS + tdb_error(tdb); -- com_err(prg_name, retval, -- _("Failed tdb_fetch %s\n"), tdb_errorstr(tdb)); -- return retval; -+ sb = (struct ext2_super_block *)buf; -+ sb->s_magic = ~sb->s_magic; -+ if (memcmp(&super, buf, sizeof(super))) { -+ print_undo_mismatch(&super, (struct ext2_super_block *)buf); -+ retval = -1; -+ goto out; - } -- memcpy(s_uuid, tdb_data.dptr, sizeof(s_uuid)); -- if (memcmp(s_uuid, super.s_uuid, sizeof(s_uuid))) { -- com_err(prg_name, 0, "%s", -- _("The file system UUID didn't match \n")); -- return -1; -+ sb_crc = ext2fs_crc32c_le(~0, (unsigned char *)buf, SUPERBLOCK_SIZE); -+ if (ext2fs_le32_to_cpu(ctx->hdr.sb_crc) != sb_crc) { -+ fprintf(stderr, -+ _("Undo file superblock checksum doesn't match.\n")); -+ retval = -1; -+ goto out; - } - -- return 0; -+out: -+ ext2fs_free_mem(&buf); -+ return retval; - } - --static int set_blk_size(TDB_CONTEXT *tdb, io_channel channel) -+static int key_compare(const void *a, const void *b) - { -- int block_size; -- errcode_t retval; -- TDB_DATA tdb_key, tdb_data; -+ const struct undo_key_info *ka, *kb; - -- tdb_key.dptr = blksize_key; -- tdb_key.dsize = sizeof(blksize_key); -- tdb_data = tdb_fetch(tdb, tdb_key); -- if (!tdb_data.dptr) { -- retval = EXT2_ET_TDB_SUCCESS + tdb_error(tdb); -- com_err(prg_name, retval, -- _("Failed tdb_fetch %s\n"), tdb_errorstr(tdb)); -+ ka = a; -+ kb = b; -+ return ext2fs_le64_to_cpu(ka->fsblk) - -+ ext2fs_le64_to_cpu(kb->fsblk); -+} -+ -+static int e2undo_setup_tdb(const char *name, io_manager *io_ptr) -+{ -+ errcode_t retval = 0; -+ const char *tdb_dir; -+ char *tdb_file = NULL; -+ char *dev_name, *tmp_name; -+ -+ /* (re)open a specific undo file */ -+ if (undo_file && undo_file[0] != 0) { -+ retval = set_undo_io_backing_manager(*io_ptr); -+ if (retval) -+ goto err; -+ *io_ptr = undo_io_manager; -+ retval = set_undo_io_backup_file(undo_file); -+ if (retval) -+ goto err; -+ printf(_("Overwriting existing filesystem; this can be undone " -+ "using the command:\n" -+ " e2undo %s %s\n\n"), -+ undo_file, name); - return retval; - } - -- block_size = *(int *)tdb_data.dptr; --#ifdef DEBUG -- printf("Block size %d\n", block_size); --#endif -- io_channel_set_blksize(channel, block_size); -+ /* -+ * Configuration via a conf file would be -+ * nice -+ */ -+ tdb_dir = getenv("E2FSPROGS_UNDO_DIR"); -+ if (!tdb_dir) -+ tdb_dir = "/var/lib/e2fsprogs"; -+ -+ if (!strcmp(tdb_dir, "none") || (tdb_dir[0] == 0) || -+ access(tdb_dir, W_OK)) -+ return 0; -+ -+ tmp_name = strdup(name); -+ if (!tmp_name) -+ goto errout; -+ dev_name = basename(tmp_name); -+ tdb_file = malloc(strlen(tdb_dir) + 8 + strlen(dev_name) + 7 + 1); -+ if (!tdb_file) { -+ free(tmp_name); -+ goto errout; -+ } -+ sprintf(tdb_file, "%s/e2undo-%s.e2undo", tdb_dir, dev_name); -+ free(tmp_name); - -+ if ((unlink(tdb_file) < 0) && (errno != ENOENT)) { -+ retval = errno; -+ com_err(prg_name, retval, -+ _("while trying to delete %s"), tdb_file); -+ goto errout; -+ } -+ -+ retval = set_undo_io_backing_manager(*io_ptr); -+ if (retval) -+ goto errout; -+ *io_ptr = undo_io_manager; -+ retval = set_undo_io_backup_file(tdb_file); -+ if (retval) -+ goto errout; -+ printf(_("Overwriting existing filesystem; this can be undone " -+ "using the command:\n" -+ " e2undo %s %s\n\n"), -+ tdb_file, name); -+ -+ free(tdb_file); - return 0; -+errout: -+ free(tdb_file); -+err: -+ com_err(prg_name, retval, "while trying to setup undo file\n"); -+ return retval; - } - - int main(int argc, char *argv[]) - { -- int c,force = 0; -- TDB_CONTEXT *tdb; -- TDB_DATA key, data; -+ int c, force = 0, dry_run = 0, verbose = 0, dump = 0; - io_channel channel; - errcode_t retval; -- int mount_flags; -- blk64_t blk_num; -+ int mount_flags, csum_error = 0, io_error = 0; -+ size_t i, keys_per_block; - char *device_name, *tdb_file; - io_manager manager = unix_io_manager; -+ struct undo_context undo_ctx; -+ char *buf; -+ struct undo_key_block *keyb; -+ struct undo_key *dkey; -+ struct undo_key_info *ikey; -+ __u32 key_crc, blk_crc, hdr_crc; -+ blk64_t lblk; -+ ext2_filsys fs; - - #ifdef ENABLE_NLS - setlocale(LC_MESSAGES, ""); -@@ -140,13 +303,25 @@ int main(int argc, char *argv[]) - add_error_table(&et_ext2_error_table); - - prg_name = argv[0]; -- while((c = getopt(argc, argv, "f")) != EOF) { -+ while ((c = getopt(argc, argv, "fhnvz:")) != EOF) { - switch (c) { -- case 'f': -- force = 1; -- break; -- default: -- usage(); -+ case 'f': -+ force = 1; -+ break; -+ case 'h': -+ dump = 1; -+ break; -+ case 'n': -+ dry_run = 1; -+ break; -+ case 'v': -+ verbose = 1; -+ break; -+ case 'z': -+ undo_file = optarg; -+ break; -+ default: -+ usage(); - } - } - -@@ -156,70 +331,274 @@ int main(int argc, char *argv[]) - tdb_file = argv[optind]; - device_name = argv[optind+1]; - -- tdb = tdb_open(tdb_file, 0, 0, O_RDONLY, 0600); -+ if (undo_file && strcmp(tdb_file, undo_file) == 0) { -+ printf(_("Will not write to an undo file while replaying it.\n")); -+ exit(1); -+ } - -- if (!tdb) { -+ /* Interpret the undo file */ -+ retval = manager->open(tdb_file, IO_FLAG_EXCLUSIVE, -+ &undo_ctx.undo_file); -+ if (retval) { - com_err(prg_name, errno, -- _("Failed tdb_open %s\n"), tdb_file); -+ _("while opening undo file `%s'\n"), tdb_file); -+ exit(1); -+ } -+ retval = io_channel_read_blk64(undo_ctx.undo_file, 0, -+ -(int)sizeof(undo_ctx.hdr), -+ &undo_ctx.hdr); -+ if (retval) { -+ com_err(prg_name, retval, _("while reading undo file")); -+ exit(1); -+ } -+ if (memcmp(undo_ctx.hdr.magic, E2UNDO_MAGIC, -+ sizeof(undo_ctx.hdr.magic))) { -+ fprintf(stderr, _("%s: Not an undo file.\n"), tdb_file); -+ exit(1); -+ } -+ if (dump) { -+ dump_header(&undo_ctx.hdr); -+ exit(1); -+ } -+ hdr_crc = ext2fs_crc32c_le(~0, (unsigned char *)&undo_ctx.hdr, -+ sizeof(struct undo_header) - -+ sizeof(__u32)); -+ if (!force && ext2fs_le32_to_cpu(undo_ctx.hdr.header_crc) != hdr_crc) { -+ fprintf(stderr, _("%s: Header checksum doesn't match.\n"), -+ tdb_file); -+ exit(1); -+ } -+ undo_ctx.blocksize = ext2fs_le32_to_cpu(undo_ctx.hdr.block_size); -+ undo_ctx.fs_blocksize = ext2fs_le32_to_cpu(undo_ctx.hdr.fs_block_size); -+ if (undo_ctx.blocksize == 0 || undo_ctx.fs_blocksize == 0) { -+ fprintf(stderr, _("%s: Corrupt undo file header.\n"), tdb_file); -+ exit(1); -+ } -+ if (!force && undo_ctx.blocksize > E2UNDO_MAX_BLOCK_SIZE) { -+ fprintf(stderr, _("%s: Undo block size too large.\n"), -+ tdb_file); -+ exit(1); -+ } -+ if (!force && undo_ctx.blocksize < E2UNDO_MIN_BLOCK_SIZE) { -+ fprintf(stderr, _("%s: Undo block size too small.\n"), -+ tdb_file); -+ exit(1); -+ } -+ undo_ctx.super_block = ext2fs_le64_to_cpu(undo_ctx.hdr.super_offset); -+ undo_ctx.num_keys = ext2fs_le64_to_cpu(undo_ctx.hdr.num_keys); -+ io_channel_set_blksize(undo_ctx.undo_file, undo_ctx.blocksize); -+ if (!force && (undo_ctx.hdr.f_compat || undo_ctx.hdr.f_incompat || -+ undo_ctx.hdr.f_rocompat)) { -+ fprintf(stderr, _("%s: Unknown undo file feature set.\n"), -+ tdb_file); - exit(1); - } - -+ /* open the fs */ - retval = ext2fs_check_if_mounted(device_name, &mount_flags); - if (retval) { - com_err(prg_name, retval, _("Error while determining whether " -- "%s is mounted.\n"), device_name); -+ "%s is mounted."), device_name); - exit(1); - } - - if (mount_flags & EXT2_MF_MOUNTED) { - com_err(prg_name, retval, "%s", _("e2undo should only be run " -- "on unmounted file system\n")); -+ "on unmounted filesystems")); - exit(1); - } - -+ if (undo_file) { -+ retval = e2undo_setup_tdb(device_name, &manager); -+ if (retval) -+ exit(1); -+ } -+ - retval = manager->open(device_name, -- IO_FLAG_EXCLUSIVE | IO_FLAG_RW, &channel); -+ IO_FLAG_EXCLUSIVE | (dry_run ? 0 : IO_FLAG_RW), -+ &channel); - if (retval) { - com_err(prg_name, retval, -- _("Failed to open %s\n"), device_name); -+ _("while opening `%s'"), device_name); - exit(1); - } - -- if (!force && check_filesystem(tdb, channel)) { -+ if (!force && check_filesystem(&undo_ctx, channel)) - exit(1); -- } - -- if (set_blk_size(tdb, channel)) { -+ /* prepare to read keys */ -+ retval = ext2fs_get_mem(sizeof(struct undo_key_info) * undo_ctx.num_keys, -+ &undo_ctx.keys); -+ if (retval) { -+ com_err(prg_name, retval, "%s", _("while allocating memory")); -+ exit(1); -+ } -+ ikey = undo_ctx.keys; -+ retval = ext2fs_get_mem(undo_ctx.blocksize, &keyb); -+ if (retval) { -+ com_err(prg_name, retval, "%s", _("while allocating memory")); -+ exit(1); -+ } -+ retval = ext2fs_get_mem(E2UNDO_MAX_EXTENT_BLOCKS * undo_ctx.blocksize, -+ &buf); -+ if (retval) { -+ com_err(prg_name, retval, "%s", _("while allocating memory")); - exit(1); - } - -- for (key = tdb_firstkey(tdb); key.dptr; key = tdb_nextkey(tdb, key)) { -- if (!strcmp((char *) key.dptr, (char *) mtime_key) || -- !strcmp((char *) key.dptr, (char *) uuid_key) || -- !strcmp((char *) key.dptr, (char *) blksize_key)) { -- continue; -+ /* load keys */ -+ keys_per_block = KEYS_PER_BLOCK(&undo_ctx); -+ lblk = ext2fs_le64_to_cpu(undo_ctx.hdr.key_offset); -+ dbg_printf("nr_keys=%lu, kpb=%zu, blksz=%u\n", -+ undo_ctx.num_keys, keys_per_block, undo_ctx.blocksize); -+ for (i = 0; i < undo_ctx.num_keys; i += keys_per_block) { -+ size_t j, max_j; -+ __le32 crc; -+ -+ retval = io_channel_read_blk64(undo_ctx.undo_file, -+ lblk, 1, keyb); -+ if (retval) { -+ com_err(prg_name, retval, "%s", _("while reading keys")); -+ if (force) { -+ io_error = 1; -+ undo_ctx.num_keys = i - 1; -+ break; -+ } -+ exit(1); - } - -- data = tdb_fetch(tdb, key); -- if (!data.dptr) { -- com_err(prg_name, 0, -- _("Failed tdb_fetch %s\n"), tdb_errorstr(tdb)); -+ /* check keys */ -+ if (!force && -+ ext2fs_le32_to_cpu(keyb->magic) != KEYBLOCK_MAGIC) { -+ fprintf(stderr, _("%s: wrong key magic at %llu\n"), -+ tdb_file, lblk); - exit(1); - } -- blk_num = *(blk64_t *)key.dptr; -- printf(_("Replayed transaction of size %zd at location %llu\n"), -- data.dsize, blk_num); -- retval = io_channel_write_blk64(channel, blk_num, -- -data.dsize, data.dptr); -- if (retval == -1) { -- com_err(prg_name, retval, -- _("Failed write %s\n"), -- strerror(errno)); -+ crc = keyb->crc; -+ keyb->crc = 0; -+ key_crc = ext2fs_crc32c_le(~0, (unsigned char *)keyb, -+ undo_ctx.blocksize); -+ if (!force && ext2fs_le32_to_cpu(crc) != key_crc) { -+ fprintf(stderr, -+ _("%s: key block checksum error at %llu.\n"), -+ tdb_file, lblk); - exit(1); - } -+ -+ /* load keys from key block */ -+ lblk++; -+ max_j = undo_ctx.num_keys - i; -+ if (max_j > keys_per_block) -+ max_j = keys_per_block; -+ for (j = 0, dkey = keyb->keys; -+ j < max_j; -+ j++, ikey++, dkey++) { -+ ikey->fsblk = ext2fs_le64_to_cpu(dkey->fsblk); -+ ikey->fileblk = lblk; -+ ikey->blk_crc = ext2fs_le32_to_cpu(dkey->blk_crc); -+ ikey->size = ext2fs_le32_to_cpu(dkey->size); -+ lblk += (ikey->size + undo_ctx.blocksize - 1) / -+ undo_ctx.blocksize; -+ -+ if (E2UNDO_MAX_EXTENT_BLOCKS * undo_ctx.blocksize < -+ ikey->size) { -+ com_err(prg_name, retval, -+ _("%s: block %llu is too long."), -+ tdb_file, ikey->fsblk); -+ exit(1); -+ } -+ -+ /* check each block's crc */ -+ retval = io_channel_read_blk64(undo_ctx.undo_file, -+ ikey->fileblk, -+ -(int)ikey->size, -+ buf); -+ if (retval) { -+ com_err(prg_name, retval, -+ _("while fetching block %llu."), -+ ikey->fileblk); -+ if (!force) -+ exit(1); -+ io_error = 1; -+ continue; -+ } -+ -+ blk_crc = ext2fs_crc32c_le(~0, (unsigned char *)buf, -+ ikey->size); -+ if (blk_crc != ikey->blk_crc) { -+ fprintf(stderr, -+ _("checksum error in filesystem block " -+ "%llu (undo blk %llu)\n"), -+ ikey->fsblk, ikey->fileblk); -+ if (!force) -+ exit(1); -+ csum_error = 1; -+ } -+ } - } -+ ext2fs_free_mem(&keyb); -+ -+ /* sort keys in fs block order */ -+ qsort(undo_ctx.keys, undo_ctx.num_keys, sizeof(struct undo_key_info), -+ key_compare); -+ -+ /* replay */ -+ io_channel_set_blksize(channel, undo_ctx.fs_blocksize); -+ for (i = 0, ikey = undo_ctx.keys; i < undo_ctx.num_keys; i++, ikey++) { -+ retval = io_channel_read_blk64(undo_ctx.undo_file, -+ ikey->fileblk, -+ -(int)ikey->size, -+ buf); -+ if (retval) { -+ com_err(prg_name, retval, -+ _("while fetching block %llu."), -+ ikey->fileblk); -+ io_error = 1; -+ continue; -+ } -+ -+ if (verbose) -+ printf("Replayed block of size %u from %llu to %llu\n", -+ ikey->size, ikey->fileblk, ikey->fsblk); -+ if (dry_run) -+ continue; -+ retval = io_channel_write_blk64(channel, ikey->fsblk, -+ -(int)ikey->size, buf); -+ if (retval) { -+ com_err(prg_name, retval, -+ _("while writing block %llu."), ikey->fsblk); -+ io_error = 1; -+ } -+ } -+ -+ if (csum_error) -+ fprintf(stderr, _("Undo file corruption; run e2fsck NOW!\n")); -+ if (io_error) -+ fprintf(stderr, _("IO error during replay; run e2fsck NOW!\n")); -+ if (!(ext2fs_le32_to_cpu(undo_ctx.hdr.state) & E2UNDO_STATE_FINISHED)) { -+ force = 1; -+ fprintf(stderr, _("Incomplete undo record; run e2fsck.\n")); -+ } -+ ext2fs_free_mem(&buf); -+ ext2fs_free_mem(&undo_ctx.keys); - io_channel_close(channel); -- tdb_close(tdb); - -- return 0; -+ /* If there were problems, try to force a fsck */ -+ if (!dry_run && (force || csum_error || io_error)) { -+ retval = ext2fs_open2(device_name, NULL, -+ EXT2_FLAG_RW | EXT2_FLAG_64BITS, 0, 0, -+ manager, &fs); -+ if (retval) -+ goto out; -+ fs->super->s_state &= ~EXT2_VALID_FS; -+ if (csum_error || io_error) -+ fs->super->s_state |= EXT2_ERROR_FS; -+ ext2fs_mark_super_dirty(fs); -+ ext2fs_close_free(&fs); -+ } -+ -+out: -+ io_channel_close(undo_ctx.undo_file); -+ -+ return csum_error; - } -diff --git a/misc/e4crypt.8.in b/misc/e4crypt.8.in -new file mode 100644 -index 0000000..e03f20b ---- /dev/null -+++ b/misc/e4crypt.8.in -@@ -0,0 +1,48 @@ -+.TH E4CRYPT 8 "@E2FSPROGS_MONTH@ @E2FSPROGS_YEAR@" "E2fsprogs version @E2FSPROGS_VERSION@" -+.SH NAME -+e4crypt \- ext4 filesystem encryption utility -+.SH SYNOPSIS -+.B e4crypt \-a \-S -+.I salt -+[ -+.B \-k -+.I keyring -+] -+[ -+.I path\fR ... -+] -+.br -+.B e4crypt \-s -+.I policy -+.I path\fR ... -+.SH DESCRIPTION -+.B e4crypt -+performs encryption management for ext4 file systems. -+.SH COMMANDS -+.TP -+.B e4crypt add_key -S \fR[\fB -k \fIkeyring\fR ] [\fB-v\fR] [\fB-q\fR] [ \fI path\fR ... ] -+Prompts the user for a passphrase and inserts it into the specified -+keyring. If no keyring is specified, e4crypt will use the session -+keyring if it exists or the user session keyring if it does not. -+.IP -+If one or more directory paths are specified, e4crypt will try to -+set the policy of those directories to use the key just entered by -+the user. -+.TP -+.B e4crypt new_session -+Give the invoking process (typically a shell) a new session keyring, -+discarding its old session keyring. -+.TP -+.B set_policy -s \fIpolicy path\fR ... -+Sets the policy for the directories specified on the command line. -+All directories must be empty to set the policy; if the directory -+already has a policy established, e4crypt will validate that it the -+policy matches what was specified. A policy is an encryption key -+identifier consisting of 16 hexadecimal characters. -+.SH AUTHOR -+Written by Michael Halcrow , Ildar Muslukhov -+, and Theodore Ts'o -+.SH SEE ALSO -+.BR keyctl (1), -+.BR mke2fs (8), -+.BR mount (8). -diff --git a/misc/e4crypt.c b/misc/e4crypt.c -new file mode 100644 -index 0000000..ad95bd2 ---- /dev/null -+++ b/misc/e4crypt.c -@@ -0,0 +1,881 @@ -+/* -+ * e4crypt.c - ext4 encryption management utility -+ * -+ * Copyright (c) 2014 Google, Inc. -+ * SHA512 implementation from libtomcrypt. -+ * -+ * Authors: Michael Halcrow , -+ * Ildar Muslukhov -+ */ -+ -+#ifndef _LARGEFILE_SOURCE -+#define _LARGEFILE_SOURCE -+#endif -+ -+#ifndef _LARGEFILE64_SOURCE -+#define _LARGEFILE64_SOURCE -+#endif -+ -+#ifndef _GNU_SOURCE -+#define _GNU_SOURCE -+#endif -+ -+#include "config.h" -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#if !defined(HAVE_ADD_KEY) || !defined(HAVE_KEYCTL) -+#include -+#endif -+#ifdef HAVE_SYS_KEY_H -+#include -+#endif -+ -+#include "ext2fs/ext2_fs.h" -+#include "ext2fs/ext2fs.h" -+#include "uuid/uuid.h" -+ -+/* special process keyring shortcut IDs */ -+#define KEY_SPEC_THREAD_KEYRING -1 -+#define KEY_SPEC_PROCESS_KEYRING -2 -+#define KEY_SPEC_SESSION_KEYRING -3 -+#define KEY_SPEC_USER_KEYRING -4 -+#define KEY_SPEC_USER_SESSION_KEYRING -5 -+#define KEY_SPEC_GROUP_KEYRING -6 -+ -+#define KEYCTL_GET_KEYRING_ID 0 -+#define KEYCTL_JOIN_SESSION_KEYRING 1 -+#define KEYCTL_DESCRIBE 6 -+#define KEYCTL_SEARCH 10 -+#define KEYCTL_SESSION_TO_PARENT 18 -+ -+typedef __s32 key_serial_t; -+ -+#define EXT4_KEY_REF_STR_BUF_SIZE ((EXT4_KEY_DESCRIPTOR_SIZE * 2) + 1) -+ -+#ifndef EXT4_IOC_GET_ENCRYPTION_PWSALT -+#define EXT4_IOC_GET_ENCRYPTION_PWSALT _IOW('f', 20, __u8[16]) -+#endif -+ -+#define OPT_VERBOSE 0x0001 -+#define OPT_QUIET 0x0002 -+ -+int options; -+ -+#ifndef HAVE_KEYCTL -+static long keyctl(int cmd, ...) -+{ -+ va_list va; -+ unsigned long arg2, arg3, arg4, arg5; -+ -+ va_start(va, cmd); -+ arg2 = va_arg(va, unsigned long); -+ arg3 = va_arg(va, unsigned long); -+ arg4 = va_arg(va, unsigned long); -+ arg5 = va_arg(va, unsigned long); -+ va_end(va); -+ return syscall(__NR_keyctl, cmd, arg2, arg3, arg4, arg5); -+} -+#endif -+ -+#ifndef HAVE_ADD_KEY -+static key_serial_t add_key(const char *type, const char *description, -+ const void *payload, size_t plen, -+ key_serial_t keyring) -+{ -+ return syscall(__NR_add_key, type, description, payload, -+ plen, keyring); -+} -+#endif -+ -+static const unsigned char *hexchars = (const unsigned char *) "0123456789abcdef"; -+static const size_t hexchars_size = 16; -+ -+#define SHA512_LENGTH 64 -+#define EXT2FS_KEY_TYPE_LOGON "logon" -+#define EXT2FS_KEY_DESC_PREFIX "ext4:" -+#define EXT2FS_KEY_DESC_PREFIX_SIZE 5 -+ -+#define EXT4_IOC_SET_ENCRYPTION_POLICY _IOR('f', 19, struct ext4_encryption_policy) -+#define EXT4_IOC_GET_ENCRYPTION_POLICY _IOW('f', 21, struct ext4_encryption_policy) -+ -+static int int_log2(int arg) -+{ -+ int l = 0; -+ -+ arg >>= 1; -+ while (arg) { -+ l++; -+ arg >>= 1; -+ } -+ return l; -+} -+ -+static void validate_paths(int argc, char *argv[], int path_start_index) -+{ -+ int x; -+ int valid = 1; -+ struct stat st; -+ -+ for (x = path_start_index; x < argc; x++) { -+ int ret = access(argv[x], W_OK); -+ if (ret) { -+ invalid: -+ perror(argv[x]); -+ valid = 0; -+ continue; -+ } -+ ret = stat(argv[x], &st); -+ if (ret < 0) -+ goto invalid; -+ if (!S_ISDIR(st.st_mode)) { -+ fprintf(stderr, "%s is not a directory\n", argv[x]); -+ goto invalid; -+ } -+ } -+ if (!valid) -+ exit(1); -+} -+ -+static int hex2byte(const char *hex, size_t hex_size, unsigned char *bytes, -+ size_t bytes_size) -+{ -+ size_t x; -+ unsigned char *h, *l; -+ -+ if (hex_size % 2) -+ return -EINVAL; -+ for (x = 0; x < hex_size; x += 2) { -+ h = memchr(hexchars, hex[x], hexchars_size); -+ if (!h) -+ return -EINVAL; -+ l = memchr(hexchars, hex[x + 1], hexchars_size); -+ if (!l) -+ return -EINVAL; -+ if ((x >> 1) >= bytes_size) -+ return -EINVAL; -+ bytes[x >> 1] = (((unsigned char)(h - hexchars) << 4) + -+ (unsigned char)(l - hexchars)); -+ } -+ return 0; -+} -+ -+/* -+ * Salt handling -+ */ -+struct salt { -+ unsigned char *salt; -+ char key_ref_str[EXT4_KEY_REF_STR_BUF_SIZE]; -+ unsigned char key_desc[EXT4_KEY_DESCRIPTOR_SIZE]; -+ unsigned char key[EXT4_MAX_KEY_SIZE]; -+ size_t salt_len; -+}; -+struct salt *salt_list; -+unsigned num_salt; -+unsigned max_salt; -+char in_passphrase[EXT4_MAX_PASSPHRASE_SIZE]; -+ -+static struct salt *find_by_salt(unsigned char *salt, size_t salt_len) -+{ -+ unsigned int i; -+ struct salt *p; -+ -+ for (i = 0, p = salt_list; i < num_salt; i++, p++) -+ if ((p->salt_len == salt_len) && -+ !memcmp(p->salt, salt, salt_len)) -+ return p; -+ return NULL; -+} -+ -+static void add_salt(unsigned char *salt, size_t salt_len) -+{ -+ if (find_by_salt(salt, salt_len)) -+ return; -+ if (num_salt >= max_salt) { -+ max_salt = num_salt + 10; -+ salt_list = realloc(salt_list, max_salt * sizeof(struct salt)); -+ if (!salt_list) { -+ fprintf(stderr, "Couldn't allocate salt list\n"); -+ exit(1); -+ } -+ } -+ salt_list[num_salt].salt = salt; -+ salt_list[num_salt].salt_len = salt_len; -+ num_salt++; -+} -+ -+static void clear_secrets(void) -+{ -+ if (salt_list) { -+ memset(salt_list, 0, sizeof(struct salt) * max_salt); -+ free(salt_list); -+ salt_list = NULL; -+ } -+ memset(in_passphrase, 0, sizeof(in_passphrase)); -+} -+ -+static void die_signal_handler(int signum EXT2FS_ATTR((unused)), -+ siginfo_t *siginfo EXT2FS_ATTR((unused)), -+ void *context EXT2FS_ATTR((unused))) -+{ -+ clear_secrets(); -+ exit(-1); -+} -+ -+static void sigcatcher_setup(void) -+{ -+ struct sigaction sa; -+ -+ memset(&sa, 0, sizeof(struct sigaction)); -+ sa.sa_sigaction = die_signal_handler; -+ sa.sa_flags = SA_SIGINFO; -+ -+ sigaction(SIGHUP, &sa, 0); -+ sigaction(SIGINT, &sa, 0); -+ sigaction(SIGQUIT, &sa, 0); -+ sigaction(SIGFPE, &sa, 0); -+ sigaction(SIGILL, &sa, 0); -+ sigaction(SIGBUS, &sa, 0); -+ sigaction(SIGSEGV, &sa, 0); -+ sigaction(SIGABRT, &sa, 0); -+ sigaction(SIGPIPE, &sa, 0); -+ sigaction(SIGALRM, &sa, 0); -+ sigaction(SIGTERM, &sa, 0); -+ sigaction(SIGUSR1, &sa, 0); -+ sigaction(SIGUSR2, &sa, 0); -+ sigaction(SIGPOLL, &sa, 0); -+ sigaction(SIGPROF, &sa, 0); -+ sigaction(SIGSYS, &sa, 0); -+ sigaction(SIGTRAP, &sa, 0); -+ sigaction(SIGVTALRM, &sa, 0); -+ sigaction(SIGXCPU, &sa, 0); -+ sigaction(SIGXFSZ, &sa, 0); -+} -+ -+ -+#define PARSE_FLAGS_NOTSUPP_OK 0x0001 -+#define PARSE_FLAGS_FORCE_FN 0x0002 -+ -+static void parse_salt(char *salt_str, int flags) -+{ -+ unsigned char buf[EXT4_MAX_SALT_SIZE]; -+ char *cp = salt_str; -+ unsigned char *salt_buf; -+ int fd, ret, salt_len = 0; -+ -+ if (flags & PARSE_FLAGS_FORCE_FN) -+ goto salt_from_filename; -+ if (strncmp(cp, "s:", 2) == 0) { -+ cp += 2; -+ salt_len = strlen(cp); -+ if (salt_len >= EXT4_MAX_SALT_SIZE) -+ goto invalid_salt; -+ strncpy((char *) buf, cp, sizeof(buf)); -+ } else if (cp[0] == '/') { -+ salt_from_filename: -+ fd = open(cp, O_RDONLY | O_DIRECTORY); -+ if (fd == -1 && errno == ENOTDIR) -+ fd = open(cp, O_RDONLY); -+ if (fd == -1) { -+ perror(cp); -+ exit(1); -+ } -+ ret = ioctl(fd, EXT4_IOC_GET_ENCRYPTION_PWSALT, &buf); -+ close(fd); -+ if (ret < 0) { -+ if (flags & PARSE_FLAGS_NOTSUPP_OK) -+ return; -+ perror("EXT4_IOC_GET_ENCRYPTION_PWSALT"); -+ exit(1); -+ } -+ if (options & OPT_VERBOSE) { -+ char tmp[80]; -+ uuid_unparse(buf, tmp); -+ printf("%s has pw salt %s\n", cp, tmp); -+ } -+ salt_len = 16; -+ } else if (strncmp(cp, "f:", 2) == 0) { -+ cp += 2; -+ goto salt_from_filename; -+ } else if (strncmp(cp, "0x", 2) == 0) { -+ unsigned char *h, *l; -+ -+ cp += 2; -+ if (strlen(cp) & 1) -+ goto invalid_salt; -+ while (*cp) { -+ if (salt_len >= EXT4_MAX_SALT_SIZE) -+ goto invalid_salt; -+ h = memchr(hexchars, *cp++, hexchars_size); -+ l = memchr(hexchars, *cp++, hexchars_size); -+ if (!h || !l) -+ goto invalid_salt; -+ buf[salt_len++] = -+ (((unsigned char)(h - hexchars) << 4) + -+ (unsigned char)(l - hexchars)); -+ } -+ } else if (uuid_parse(cp, buf) == 0) { -+ salt_len = 16; -+ } else { -+ invalid_salt: -+ fprintf(stderr, "Invalid salt: %s\n", salt_str); -+ exit(1); -+ } -+ salt_buf = malloc(salt_len); -+ if (!salt_buf) { -+ fprintf(stderr, "Couldn't allocate salt\n"); -+ exit(1); -+ } -+ memcpy(salt_buf, buf, salt_len); -+ add_salt(salt_buf, salt_len); -+} -+ -+static void set_policy(struct salt *set_salt, int pad, -+ int argc, char *argv[], int path_start_index) -+{ -+ struct salt *salt; -+ struct ext4_encryption_policy policy; -+ uuid_t uu; -+ int fd; -+ int x; -+ int rc; -+ -+ if ((pad != 4) && (pad != 8) && -+ (pad != 16) && (pad != 32)) { -+ fprintf(stderr, "Invalid padding %d\n", pad); -+ exit(1); -+ } -+ -+ for (x = path_start_index; x < argc; x++) { -+ fd = open(argv[x], O_DIRECTORY); -+ if (fd == -1) { -+ perror(argv[x]); -+ exit(1); -+ } -+ if (set_salt) -+ salt = set_salt; -+ else { -+ if (ioctl(fd, EXT4_IOC_GET_ENCRYPTION_PWSALT, -+ &uu) < 0) { -+ perror("EXT4_IOC_GET_ENCRYPTION_PWSALT"); -+ exit(1); -+ } -+ salt = find_by_salt(uu, sizeof(uu)); -+ if (!salt) { -+ fprintf(stderr, "Couldn't find salt!?!\n"); -+ exit(1); -+ } -+ } -+ policy.version = 0; -+ policy.contents_encryption_mode = -+ EXT4_ENCRYPTION_MODE_AES_256_XTS; -+ policy.filenames_encryption_mode = -+ EXT4_ENCRYPTION_MODE_AES_256_CTS; -+ policy.flags = int_log2(pad >> 2); -+ memcpy(policy.master_key_descriptor, salt->key_desc, -+ EXT4_KEY_DESCRIPTOR_SIZE); -+ rc = ioctl(fd, EXT4_IOC_SET_ENCRYPTION_POLICY, &policy); -+ close(fd); -+ if (rc) { -+ printf("Error [%s] setting policy.\nThe key descriptor " -+ "[%s] may not match the existing encryption " -+ "context for directory [%s].\n", -+ strerror(errno), salt->key_ref_str, argv[x]); -+ continue; -+ } -+ printf("Key with descriptor [%s] applied to %s.\n", -+ salt->key_ref_str, argv[x]); -+ } -+} -+ -+static void pbkdf2_sha512(const char *passphrase, struct salt *salt, -+ unsigned int count, -+ unsigned char derived_key[EXT4_MAX_KEY_SIZE]) -+{ -+ size_t passphrase_size = strlen(passphrase); -+ unsigned char buf[SHA512_LENGTH + EXT4_MAX_PASSPHRASE_SIZE] = {0}; -+ unsigned char tempbuf[SHA512_LENGTH] = {0}; -+ char final[SHA512_LENGTH] = {0}; -+ unsigned char saltbuf[EXT4_MAX_SALT_SIZE + EXT4_MAX_PASSPHRASE_SIZE] = {0}; -+ int actual_buf_len = SHA512_LENGTH + passphrase_size; -+ int actual_saltbuf_len = EXT4_MAX_SALT_SIZE + passphrase_size; -+ unsigned int x, y; -+ __u32 *final_u32 = (__u32 *)final; -+ __u32 *temp_u32 = (__u32 *)tempbuf; -+ -+ if (passphrase_size > EXT4_MAX_PASSPHRASE_SIZE) { -+ printf("Passphrase size is %zd; max is %d.\n", passphrase_size, -+ EXT4_MAX_PASSPHRASE_SIZE); -+ exit(1); -+ } -+ if (salt->salt_len > EXT4_MAX_SALT_SIZE) { -+ printf("Salt size is %zd; max is %d.\n", salt->salt_len, -+ EXT4_MAX_SALT_SIZE); -+ exit(1); -+ } -+ assert(EXT4_MAX_KEY_SIZE <= SHA512_LENGTH); -+ -+ memcpy(saltbuf, salt->salt, salt->salt_len); -+ memcpy(&saltbuf[EXT4_MAX_SALT_SIZE], passphrase, passphrase_size); -+ -+ memcpy(&buf[SHA512_LENGTH], passphrase, passphrase_size); -+ -+ for (x = 0; x < count; ++x) { -+ if (x == 0) { -+ ext2fs_sha512(saltbuf, actual_saltbuf_len, tempbuf); -+ } else { -+ /* -+ * buf: [previous hash || passphrase] -+ */ -+ memcpy(buf, tempbuf, SHA512_LENGTH); -+ ext2fs_sha512(buf, actual_buf_len, tempbuf); -+ } -+ for (y = 0; y < (sizeof(final) / sizeof(*final_u32)); ++y) -+ final_u32[y] = final_u32[y] ^ temp_u32[y]; -+ } -+ memcpy(derived_key, final, EXT4_MAX_KEY_SIZE); -+} -+ -+static int disable_echo(struct termios *saved_settings) -+{ -+ struct termios current_settings; -+ int rc = 0; -+ -+ rc = tcgetattr(0, ¤t_settings); -+ if (rc) -+ return rc; -+ *saved_settings = current_settings; -+ current_settings.c_lflag &= ~ECHO; -+ rc = tcsetattr(0, TCSANOW, ¤t_settings); -+ -+ return rc; -+} -+ -+static void get_passphrase(char *passphrase, int len) -+{ -+ char *p; -+ struct termios current_settings; -+ -+ assert(len > 0); -+ disable_echo(¤t_settings); -+ p = fgets(passphrase, len, stdin); -+ tcsetattr(0, TCSANOW, ¤t_settings); -+ printf("\n"); -+ if (!p) { -+ printf("Aborting.\n"); -+ exit(1); -+ } -+ p = strrchr(passphrase, '\n'); -+ if (!p) -+ p = passphrase + len - 1; -+ *p = '\0'; -+} -+ -+struct keyring_map { -+ char name[4]; -+ size_t name_len; -+ int code; -+}; -+ -+static const struct keyring_map keyrings[] = { -+ {"@us", 3, KEY_SPEC_USER_SESSION_KEYRING}, -+ {"@u", 2, KEY_SPEC_USER_KEYRING}, -+ {"@s", 2, KEY_SPEC_SESSION_KEYRING}, -+ {"@g", 2, KEY_SPEC_GROUP_KEYRING}, -+ {"@p", 2, KEY_SPEC_PROCESS_KEYRING}, -+ {"@t", 2, KEY_SPEC_THREAD_KEYRING}, -+}; -+ -+static int get_keyring_id(const char *keyring) -+{ -+ unsigned int x; -+ char *end; -+ -+ /* -+ * If no keyring is specified, by default use either the user -+ * session key ring or the session keyring. Fetching the -+ * session keyring will return the user session keyring if no -+ * session keyring has been set. -+ * -+ * We need to do this instead of simply adding the key to -+ * KEY_SPEC_SESSION_KEYRING since trying to add a key to a -+ * session keyring that does not yet exist will cause the -+ * kernel to create a session keyring --- which wil then get -+ * garbage collected as soon as e4crypt exits. -+ * -+ * The fact that the keyctl system call and the add_key system -+ * call treats KEY_SPEC_SESSION_KEYRING differently when a -+ * session keyring does not exist is very unfortunate and -+ * confusing, but so it goes... -+ */ -+ if (keyring == NULL) -+ return keyctl(KEYCTL_GET_KEYRING_ID, -+ KEY_SPEC_SESSION_KEYRING, 0); -+ for (x = 0; x < (sizeof(keyrings) / sizeof(keyrings[0])); ++x) { -+ if (strcmp(keyring, keyrings[x].name) == 0) { -+ return keyrings[x].code; -+ } -+ } -+ x = strtoul(keyring, &end, 10); -+ if (*end == '\0') { -+ if (keyctl(KEYCTL_DESCRIBE, x, NULL, 0) < 0) -+ return 0; -+ return x; -+ } -+ return 0; -+} -+ -+static void generate_key_ref_str(struct salt *salt) -+{ -+ unsigned char key_ref1[SHA512_LENGTH]; -+ unsigned char key_ref2[SHA512_LENGTH]; -+ int x; -+ -+ ext2fs_sha512(salt->key, EXT4_MAX_KEY_SIZE, key_ref1); -+ ext2fs_sha512(key_ref1, SHA512_LENGTH, key_ref2); -+ memcpy(salt->key_desc, key_ref2, EXT4_KEY_DESCRIPTOR_SIZE); -+ for (x = 0; x < EXT4_KEY_DESCRIPTOR_SIZE; ++x) { -+ sprintf(&salt->key_ref_str[x * 2], "%02x", -+ salt->key_desc[x]); -+ } -+ salt->key_ref_str[EXT4_KEY_REF_STR_BUF_SIZE - 1] = '\0'; -+} -+ -+static void insert_key_into_keyring(const char *keyring, struct salt *salt) -+{ -+ int keyring_id = get_keyring_id(keyring); -+ struct ext4_encryption_key key; -+ char key_ref_full[EXT2FS_KEY_DESC_PREFIX_SIZE + -+ EXT4_KEY_REF_STR_BUF_SIZE]; -+ int rc; -+ -+ if (keyring_id == 0) { -+ printf("Invalid keyring [%s].\n", keyring); -+ exit(1); -+ } -+ sprintf(key_ref_full, "%s%s", EXT2FS_KEY_DESC_PREFIX, -+ salt->key_ref_str); -+ rc = keyctl(KEYCTL_SEARCH, keyring_id, EXT2FS_KEY_TYPE_LOGON, -+ key_ref_full, 0); -+ if (rc != -1) { -+ if ((options & OPT_QUIET) == 0) -+ printf("Key with descriptor [%s] already exists\n", -+ salt->key_ref_str); -+ return; -+ } else if ((rc == -1) && (errno != ENOKEY)) { -+ printf("keyctl_search failed: %s\n", strerror(errno)); -+ if (errno == -EINVAL) -+ printf("Keyring [%s] is not available.\n", keyring); -+ exit(1); -+ } -+ key.mode = EXT4_ENCRYPTION_MODE_AES_256_XTS; -+ memcpy(key.raw, salt->key, EXT4_MAX_KEY_SIZE); -+ key.size = EXT4_MAX_KEY_SIZE; -+ rc = add_key(EXT2FS_KEY_TYPE_LOGON, key_ref_full, (void *)&key, -+ sizeof(key), keyring_id); -+ if (rc == -1) { -+ if (errno == EDQUOT) { -+ printf("Error adding key to keyring; quota exceeded\n"); -+ } else { -+ printf("Error adding key with key descriptor [%s]: " -+ "%s\n", salt->key_ref_str, strerror(errno)); -+ } -+ exit(1); -+ } else { -+ if ((options & OPT_QUIET) == 0) -+ printf("Added key with descriptor [%s]\n", -+ salt->key_ref_str); -+ } -+} -+ -+static void get_default_salts(void) -+{ -+ FILE *f = setmntent("/etc/mtab", "r"); -+ struct mntent *mnt; -+ -+ while (f && ((mnt = getmntent(f)) != NULL)) { -+ if (strcmp(mnt->mnt_type, "ext4") || -+ access(mnt->mnt_dir, R_OK)) -+ continue; -+ parse_salt(mnt->mnt_dir, PARSE_FLAGS_NOTSUPP_OK); -+ } -+ endmntent(f); -+} -+ -+/* Functions which implement user commands */ -+ -+struct cmd_desc { -+ const char *cmd_name; -+ void (*cmd_func)(int, char **, const struct cmd_desc *); -+ const char *cmd_desc; -+ const char *cmd_help; -+ int cmd_flags; -+}; -+ -+#define CMD_HIDDEN 0x0001 -+ -+static void do_help(int argc, char **argv, const struct cmd_desc *cmd); -+ -+#define add_key_desc "adds a key to the user's keyring" -+#define add_key_help \ -+"e4crypt add_key -S salt [ -k keyring ] [-v] [-q] [ path ... ]\n\n" \ -+"Prompts the user for a passphrase and inserts it into the specified\n" \ -+"keyring. If no keyring is specified, e4crypt will use the session\n" \ -+"keyring if it exists or the user session keyring if it does not.\n\n" \ -+"If one or more directory paths are specified, e4crypt will try to\n" \ -+"set the policy of those directories to use the key just entered by\n" \ -+"the user.\n" -+ -+static void do_add_key(int argc, char **argv, const struct cmd_desc *cmd) -+{ -+ struct salt *salt; -+ char *keyring = NULL; -+ int i, opt, pad = 4; -+ unsigned j; -+ -+ while ((opt = getopt(argc, argv, "k:S:p:vq")) != -1) { -+ switch (opt) { -+ case 'k': -+ /* Specify a keyring. */ -+ keyring = optarg; -+ break; -+ case 'p': -+ pad = atoi(optarg); -+ break; -+ case 'S': -+ /* Salt value for passphrase. */ -+ parse_salt(optarg, 0); -+ break; -+ case 'v': -+ options |= OPT_VERBOSE; -+ break; -+ case 'q': -+ options |= OPT_QUIET; -+ break; -+ default: -+ fprintf(stderr, "Unrecognized option: %c\n", opt); -+ case '?': -+ fputs("USAGE:\n ", stderr); -+ fputs(cmd->cmd_help, stderr); -+ exit(1); -+ } -+ } -+ if (num_salt == 0) -+ get_default_salts(); -+ if (num_salt == 0) { -+ fprintf(stderr, "No salt values available\n"); -+ exit(1); -+ } -+ validate_paths(argc, argv, optind); -+ for (i = optind; i < argc; i++) -+ parse_salt(argv[i], PARSE_FLAGS_FORCE_FN); -+ printf("Enter passphrase (echo disabled): "); -+ get_passphrase(in_passphrase, sizeof(in_passphrase)); -+ for (j = 0, salt = salt_list; j < num_salt; j++, salt++) { -+ pbkdf2_sha512(in_passphrase, salt, -+ EXT4_PBKDF2_ITERATIONS, salt->key); -+ generate_key_ref_str(salt); -+ insert_key_into_keyring(keyring, salt); -+ } -+ if (optind != argc) -+ set_policy(NULL, pad, argc, argv, optind); -+ clear_secrets(); -+ exit(0); -+} -+ -+#define set_policy_desc "sets a policy for directories" -+#define set_policy_help \ -+"e4crypt set_policy policy path ... \n\n" \ -+"Sets the policy for the directories specified on the command line.\n" \ -+"All directories must be empty to set the policy; if the directory\n" \ -+"already has a policy established, e4crypt will validate that it the\n" \ -+"policy matches what was specified. A policy is an encryption key\n" \ -+"identifier consisting of 16 hexadecimal characters.\n" -+ -+static void do_set_policy(int argc, char **argv, const struct cmd_desc *cmd) -+{ -+ struct salt saltbuf; -+ int c, pad = 4; -+ -+ while ((c = getopt (argc, argv, "p:")) != EOF) { -+ switch (c) { -+ case 'p': -+ pad = atoi(optarg); -+ break; -+ } -+ } -+ -+ if (argc < optind + 2) { -+ fprintf(stderr, "Missing required argument(s).\n\n"); -+ fputs("USAGE:\n ", stderr); -+ fputs(cmd->cmd_help, stderr); -+ exit(1); -+ } -+ -+ printf("arg %s\n", argv[optind]); -+ exit(0); -+ -+ strcpy(saltbuf.key_ref_str, argv[optind]); -+ if ((strlen(argv[optind]) != (EXT4_KEY_DESCRIPTOR_SIZE * 2)) || -+ hex2byte(argv[optind], (EXT4_KEY_DESCRIPTOR_SIZE * 2), -+ saltbuf.key_desc, EXT4_KEY_DESCRIPTOR_SIZE)) { -+ printf("Invalid key descriptor [%s]. Valid characters " -+ "are 0-9 and a-f, lower case. " -+ "Length must be %d.\n", -+ argv[optind], (EXT4_KEY_DESCRIPTOR_SIZE * 2)); -+ exit(1); -+ } -+ validate_paths(argc, argv, optind+1); -+ set_policy(&saltbuf, pad, argc, argv, optind+1); -+ exit(0); -+} -+ -+#define get_policy_desc "get the encryption for directories" -+#define get_policy_help \ -+"e4crypt get_policy path ... \n\n" \ -+"Gets the policy for the directories specified on the command line.\n" -+ -+static void do_get_policy(int argc, char **argv, const struct cmd_desc *cmd) -+{ -+ struct ext4_encryption_policy policy; -+ struct stat st; -+ int i, j, fd, rc; -+ -+ if (argc < 2) { -+ fprintf(stderr, "Missing required argument(s).\n\n"); -+ fputs("USAGE:\n ", stderr); -+ fputs(cmd->cmd_help, stderr); -+ exit(1); -+ } -+ -+ for (i = 1; i < argc; i++) { -+ if (stat(argv[i], &st) < 0) { -+ perror(argv[i]); -+ continue; -+ } -+ fd = open(argv[i], -+ S_ISDIR(st.st_mode) ? O_DIRECTORY : O_RDONLY); -+ if (fd == -1) { -+ perror(argv[i]); -+ exit(1); -+ } -+ rc = ioctl(fd, EXT4_IOC_GET_ENCRYPTION_POLICY, &policy); -+ close(fd); -+ if (rc) { -+ printf("Error getting policy for %s: %s\n", -+ argv[i], strerror(errno)); -+ continue; -+ } -+ printf("%s: ", argv[i]); -+ for (j = 0; j < EXT4_KEY_DESCRIPTOR_SIZE; j++) { -+ printf("%02x", (unsigned char) policy.master_key_descriptor[j]); -+ } -+ fputc('\n', stdout); -+ } -+ exit(0); -+} -+ -+#define new_session_desc "given the invoking process a new session keyring" -+#define new_session_help \ -+"e4crypt new_sessoin\n\n" \ -+"Give the invoking process (typically a shell) a new session keyring,\n" \ -+"discarding its old session keyring.\n" -+ -+static void do_new_session(int argc, char **argv EXT2FS_ATTR((unused)), -+ const struct cmd_desc *cmd) -+{ -+ long keyid, ret; -+ -+ if (argc > 1) { -+ fputs("Excess arguments\n\n", stderr); -+ fputs(cmd->cmd_help, stderr); -+ exit(1); -+ } -+ keyid = keyctl(KEYCTL_JOIN_SESSION_KEYRING, NULL); -+ if (keyid < 0) { -+ perror("KEYCTL_JOIN_SESSION_KEYRING"); -+ exit(1); -+ } -+ ret = keyctl(KEYCTL_SESSION_TO_PARENT, NULL); -+ if (ret < 0) { -+ perror("KEYCTL_SESSION_TO_PARENT"); -+ exit(1); -+ } -+ printf("Switched invoking process to new session keyring %ld\n", keyid); -+ exit(0); -+} -+ -+#define CMD(name) { #name, do_##name, name##_desc, name##_help, 0 } -+#define _CMD(name) { #name, do_##name, NULL, NULL, CMD_HIDDEN } -+ -+const struct cmd_desc cmd_list[] = { -+ _CMD(help), -+ CMD(add_key), -+ CMD(get_policy), -+ CMD(new_session), -+ CMD(set_policy), -+ { NULL, NULL, NULL, NULL, 0 } -+}; -+ -+static void do_help(int argc, char **argv, -+ const struct cmd_desc *cmd EXT2FS_ATTR((unused))) -+{ -+ const struct cmd_desc *p; -+ -+ if (argc > 1) { -+ for (p = cmd_list; p->cmd_name; p++) { -+ if (p->cmd_flags & CMD_HIDDEN) -+ continue; -+ if (strcmp(p->cmd_name, argv[1]) == 0) { -+ putc('\n', stdout); -+ fputs("USAGE:\n ", stdout); -+ fputs(p->cmd_help, stdout); -+ exit(0); -+ } -+ } -+ printf("Unknown command: %s\n\n", argv[1]); -+ } -+ -+ fputs("Available commands:\n", stdout); -+ for (p = cmd_list; p->cmd_name; p++) { -+ if (p->cmd_flags & CMD_HIDDEN) -+ continue; -+ printf(" %-20s %s\n", p->cmd_name, p->cmd_desc); -+ } -+ printf("\nTo get more information on a commnd, " -+ "type 'e4crypt help cmd'\n"); -+ exit(0); -+} -+ -+int main(int argc, char *argv[]) -+{ -+ const struct cmd_desc *cmd; -+ -+ if (argc < 2) -+ do_help(argc, argv, cmd_list); -+ -+ sigcatcher_setup(); -+ for (cmd = cmd_list; cmd->cmd_name; cmd++) { -+ if (strcmp(cmd->cmd_name, argv[1]) == 0) { -+ cmd->cmd_func(argc-1, argv+1, cmd); -+ exit(0); -+ } -+ } -+ printf("Unknown command: %s\n\n", argv[1]); -+ do_help(1, argv, cmd_list); -+ return 0; -+} -diff --git a/misc/e4defrag.c b/misc/e4defrag.c -index d0eac60..3f949d0 100644 ---- a/misc/e4defrag.c -+++ b/misc/e4defrag.c -@@ -387,8 +387,10 @@ static int page_in_core(int fd, struct move_extent defrag_data, - *page_num = 0; - *page_num = (length + pagesize - 1) / pagesize; - *vec = (unsigned char *)calloc(*page_num, 1); -- if (*vec == NULL) -+ if (*vec == NULL) { -+ munmap(page, length); - return -1; -+ } - - /* Get information on whether pages are in core */ - if (mincore(page, (size_t)length, *vec) == -1 || -diff --git a/misc/ext4.5.in b/misc/ext4.5.in -index a862a34..9a77243 100644 ---- a/misc/ext4.5.in -+++ b/misc/ext4.5.in -@@ -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 -@@ -199,17 +202,17 @@ available in the resize inode. - This ext4 feature provides multiple mount protection (MMP). MMP helps to - protect the filesystem from being multiply mounted and is useful in - shared storage environments. --@QUOTA_MAN_COMMENT@.TP --@QUOTA_MAN_COMMENT@.B quota --@QUOTA_MAN_COMMENT@.br --@QUOTA_MAN_COMMENT@Create quota inodes (inode #3 for userquota and inode --@QUOTA_MAN_COMMENT@#4 for group quota) and set them in the superblock. --@QUOTA_MAN_COMMENT@With this feature, the quotas will be enabled --@QUOTA_MAN_COMMENT@automatically when the filesystem is mounted. --@QUOTA_MAN_COMMENT@.IP --@QUOTA_MAN_COMMENT@Causes the quota files (i.e., user.quota and --@QUOTA_MAN_COMMENT@group.quota which existed --@QUOTA_MAN_COMMENT@in the older quota design) to be hidden inodes. -+.TP -+.B quota -+.br -+Create quota inodes (inode #3 for userquota and inode -+#4 for group quota) and set them in the superblock. -+With this feature, the quotas will be enabled -+automatically when the filesystem is mounted. -+.IP -+Causes the quota files (i.e., user.quota and -+group.quota which existed -+in the older quota design) to be hidden inodes. - .TP - .B resize_inode - .br -diff --git a/misc/filefrag.c b/misc/filefrag.c -index c1a8684..5bcde91 100644 ---- a/misc/filefrag.c -+++ b/misc/filefrag.c -@@ -20,7 +20,13 @@ int main(void) { - exit(EXIT_FAILURE); - } - #else -+#ifndef _LARGEFILE_SOURCE -+#define _LARGEFILE_SOURCE -+#endif -+#ifndef _LARGEFILE64_SOURCE - #define _LARGEFILE64_SOURCE -+#endif -+ - - #include - #include -@@ -181,7 +187,8 @@ static void print_extent_info(struct fiemap_extent *fm_extent, int cur_ex, - print_flag(&fe_flags, mask, flags, hex); - } - -- if (fm_extent->fe_logical + fm_extent->fe_length >= st->st_size) -+ if (fm_extent->fe_logical + fm_extent->fe_length >= -+ (unsigned long long) st->st_size) - strcat(flags, "eof,"); - - /* Remove trailing comma, if any */ -@@ -198,7 +205,7 @@ static void print_extent_info(struct fiemap_extent *fm_extent, int cur_ex, - static int filefrag_fiemap(int fd, int blk_shift, int *num_extents, - ext2fs_struct_stat *st) - { -- char buf[16384]; -+ __u64 buf[2048]; /* __u64 for proper field alignment */ - struct fiemap *fiemap = (struct fiemap *)buf; - struct fiemap_extent *fm_ext = &fiemap->fm_extents[0]; - int count = (sizeof(buf) - sizeof(*fiemap)) / -@@ -287,8 +294,8 @@ static int filefrag_fibmap(int fd, int blk_shift, int *num_extents, - const long bpib = st->st_blksize / 4; - int count; - -+ memset(&fm_ext, 0, sizeof(fm_ext)); - if (force_extent) { -- memset(&fm_ext, 0, sizeof(fm_ext)); - fm_ext.fe_flags = FIEMAP_EXTENT_MERGED; - } - -@@ -331,15 +338,17 @@ static int filefrag_fibmap(int fd, int blk_shift, int *num_extents, - blk_shift, st); - fm_ext.fe_length = 0; - (*num_extents)++; -+ fm_ext.fe_logical = logical; -+ fm_ext.fe_physical = block * st->st_blksize; - } else if (last_block && (block != last_block + 1)) { - if (verbose) - printf("Discontinuity: Block %ld is at %lu (was " - "%lu)\n", i, block, last_block + 1); - fm_ext.fe_length = 0; - (*num_extents)++; -+ fm_ext.fe_logical = logical; -+ fm_ext.fe_physical = block * st->st_blksize; - } -- fm_ext.fe_logical = logical; -- fm_ext.fe_physical = block * st->st_blksize; - fm_ext.fe_length += st->st_blksize; - last_block = block; - } -diff --git a/misc/findsuper.c b/misc/findsuper.c -index eb9130b..ce649de 100644 ---- a/misc/findsuper.c -+++ b/misc/findsuper.c -@@ -94,7 +94,7 @@ - - #include "ext2fs/ext2_fs.h" - #include "ext2fs/ext2fs.h" --#include "nls-enable.h" -+#include "support/nls-enable.h" - - #undef DEBUG - -diff --git a/misc/fsck.c b/misc/fsck.c -index 826aaeb..147ea94 100644 ---- a/misc/fsck.c -+++ b/misc/fsck.c -@@ -59,7 +59,7 @@ - #endif - - #include "../version.h" --#include "nls-enable.h" -+#include "support/nls-enable.h" - #include "fsck.h" - #include "blkid/blkid.h" - -diff --git a/misc/fuse2fs.c b/misc/fuse2fs.c -new file mode 100644 -index 0000000..5b89821 ---- /dev/null -+++ b/misc/fuse2fs.c -@@ -0,0 +1,3919 @@ -+/* -+ * fuse2fs.c - FUSE server for e2fsprogs. -+ * -+ * Copyright (C) 2014 Oracle. -+ * -+ * %Begin-Header% -+ * This file may be redistributed under the terms of the GNU Public -+ * License. -+ * %End-Header% -+ */ -+#define _FILE_OFFSET_BITS 64 -+#define FUSE_USE_VERSION 29 -+#ifndef _GNU_SOURCE -+#define _GNU_SOURCE -+#endif -+#include "config.h" -+#include -+#ifdef __linux__ -+# include -+# include -+# include -+# define FUSE_PLATFORM_OPTS ",nonempty,big_writes" -+# ifdef HAVE_SYS_ACL_H -+# define TRANSLATE_LINUX_ACLS -+# endif -+#else -+# define FUSE_PLATFORM_OPTS "" -+#endif -+#ifdef TRANSLATE_LINUX_ACLS -+# include -+#endif -+#include -+#include -+#include -+#include -+#include "ext2fs/ext2fs.h" -+#include "ext2fs/ext2_fs.h" -+ -+#ifdef ENABLE_NLS -+#include -+#include -+#define _(a) (gettext(a)) -+#ifdef gettext_noop -+#define N_(a) gettext_noop(a) -+#else -+#define N_(a) (a) -+#endif -+#define P_(singular, plural, n) (ngettext(singular, plural, n)) -+#ifndef NLS_CAT_NAME -+#define NLS_CAT_NAME "e2fsprogs" -+#endif -+#ifndef LOCALEDIR -+#define LOCALEDIR "/usr/share/locale" -+#endif -+#else -+#define _(a) (a) -+#define N_(a) a -+#define P_(singular, plural, n) ((n) == 1 ? (singular) : (plural)) -+#endif -+ -+static ext2_filsys global_fs; /* Try not to use this directly */ -+ -+#undef DEBUG -+ -+#ifdef DEBUG -+# define dbg_printf(f, a...) do {printf("FUSE2FS-" f, ## a); \ -+ fflush(stdout); \ -+} while (0) -+#else -+# define dbg_printf(f, a...) -+#endif -+ -+#if FUSE_VERSION >= FUSE_MAKE_VERSION(2, 8) -+# ifdef _IOR -+# ifdef _IOW -+# define SUPPORT_I_FLAGS -+# endif -+# endif -+#endif -+ -+#ifdef FALLOC_FL_KEEP_SIZE -+# define FL_KEEP_SIZE_FLAG FALLOC_FL_KEEP_SIZE -+# define SUPPORT_FALLOCATE -+#else -+# define FL_KEEP_SIZE_FLAG (0) -+#endif -+ -+#ifdef FALLOC_FL_PUNCH_HOLE -+# define FL_PUNCH_HOLE_FLAG FALLOC_FL_PUNCH_HOLE -+#else -+# define FL_PUNCH_HOLE_FLAG (0) -+#endif -+ -+errcode_t ext2fs_run_ext3_journal(ext2_filsys *fs); -+ -+/* ACL translation stuff */ -+#ifdef TRANSLATE_LINUX_ACLS -+/* -+ * Copied from acl_ea.h in libacl source; ACLs have to be sent to and from fuse -+ * in this format... at least on Linux. -+ */ -+#define ACL_EA_ACCESS "system.posix_acl_access" -+#define ACL_EA_DEFAULT "system.posix_acl_default" -+ -+#define ACL_EA_VERSION 0x0002 -+ -+typedef struct { -+ u_int16_t e_tag; -+ u_int16_t e_perm; -+ u_int32_t e_id; -+} acl_ea_entry; -+ -+typedef struct { -+ u_int32_t a_version; -+ acl_ea_entry a_entries[0]; -+} acl_ea_header; -+ -+static inline size_t acl_ea_size(int count) -+{ -+ return sizeof(acl_ea_header) + count * sizeof(acl_ea_entry); -+} -+ -+static inline int acl_ea_count(size_t size) -+{ -+ if (size < sizeof(acl_ea_header)) -+ return -1; -+ size -= sizeof(acl_ea_header); -+ if (size % sizeof(acl_ea_entry)) -+ return -1; -+ return size / sizeof(acl_ea_entry); -+} -+ -+/* -+ * ext4 ACL structures, copied from fs/ext4/acl.h. -+ */ -+#define EXT4_ACL_VERSION 0x0001 -+ -+typedef struct { -+ __u16 e_tag; -+ __u16 e_perm; -+ __u32 e_id; -+} ext4_acl_entry; -+ -+typedef struct { -+ __u16 e_tag; -+ __u16 e_perm; -+} ext4_acl_entry_short; -+ -+typedef struct { -+ __u32 a_version; -+} ext4_acl_header; -+ -+static inline size_t ext4_acl_size(int count) -+{ -+ if (count <= 4) { -+ return sizeof(ext4_acl_header) + -+ count * sizeof(ext4_acl_entry_short); -+ } else { -+ return sizeof(ext4_acl_header) + -+ 4 * sizeof(ext4_acl_entry_short) + -+ (count - 4) * sizeof(ext4_acl_entry); -+ } -+} -+ -+static inline int ext4_acl_count(size_t size) -+{ -+ ssize_t s; -+ -+ size -= sizeof(ext4_acl_header); -+ s = size - 4 * sizeof(ext4_acl_entry_short); -+ if (s < 0) { -+ if (size % sizeof(ext4_acl_entry_short)) -+ return -1; -+ return size / sizeof(ext4_acl_entry_short); -+ } -+ if (s % sizeof(ext4_acl_entry)) -+ return -1; -+ return s / sizeof(ext4_acl_entry) + 4; -+} -+ -+static errcode_t fuse_to_ext4_acl(acl_ea_header *facl, size_t facl_sz, -+ ext4_acl_header **eacl, size_t *eacl_sz) -+{ -+ int i, facl_count; -+ ext4_acl_header *h; -+ size_t h_sz; -+ ext4_acl_entry *e; -+ acl_ea_entry *a; -+ unsigned char *hptr; -+ errcode_t err; -+ -+ facl_count = acl_ea_count(facl_sz); -+ h_sz = ext4_acl_size(facl_count); -+ if (facl_count < 0 || facl->a_version != ACL_EA_VERSION) -+ return EXT2_ET_INVALID_ARGUMENT; -+ -+ err = ext2fs_get_mem(h_sz, &h); -+ if (err) -+ return err; -+ -+ h->a_version = ext2fs_cpu_to_le32(EXT4_ACL_VERSION); -+ hptr = (unsigned char *) (h + 1); -+ for (i = 0, a = facl->a_entries; i < facl_count; i++, a++) { -+ e = (ext4_acl_entry *) hptr; -+ e->e_tag = ext2fs_cpu_to_le16(a->e_tag); -+ e->e_perm = ext2fs_cpu_to_le16(a->e_perm); -+ -+ switch (a->e_tag) { -+ case ACL_USER: -+ case ACL_GROUP: -+ e->e_id = ext2fs_cpu_to_le32(a->e_id); -+ hptr += sizeof(ext4_acl_entry); -+ break; -+ case ACL_USER_OBJ: -+ case ACL_GROUP_OBJ: -+ case ACL_MASK: -+ case ACL_OTHER: -+ hptr += sizeof(ext4_acl_entry_short); -+ break; -+ default: -+ err = EXT2_ET_INVALID_ARGUMENT; -+ goto out; -+ } -+ } -+ -+ *eacl = h; -+ *eacl_sz = h_sz; -+ return err; -+out: -+ ext2fs_free_mem(&h); -+ return err; -+} -+ -+static errcode_t ext4_to_fuse_acl(acl_ea_header **facl, size_t *facl_sz, -+ ext4_acl_header *eacl, size_t eacl_sz) -+{ -+ int i, eacl_count; -+ acl_ea_header *f; -+ ext4_acl_entry *e; -+ acl_ea_entry *a; -+ size_t f_sz; -+ unsigned char *hptr; -+ errcode_t err; -+ -+ eacl_count = ext4_acl_count(eacl_sz); -+ f_sz = acl_ea_size(eacl_count); -+ if (eacl_count < 0 || -+ eacl->a_version != ext2fs_cpu_to_le32(EXT4_ACL_VERSION)) -+ return EXT2_ET_INVALID_ARGUMENT; -+ -+ err = ext2fs_get_mem(f_sz, &f); -+ if (err) -+ return err; -+ -+ f->a_version = ACL_EA_VERSION; -+ hptr = (unsigned char *) (eacl + 1); -+ for (i = 0, a = f->a_entries; i < eacl_count; i++, a++) { -+ e = (ext4_acl_entry *) hptr; -+ a->e_tag = ext2fs_le16_to_cpu(e->e_tag); -+ a->e_perm = ext2fs_le16_to_cpu(e->e_perm); -+ -+ switch (a->e_tag) { -+ case ACL_USER: -+ case ACL_GROUP: -+ a->e_id = ext2fs_le32_to_cpu(e->e_id); -+ hptr += sizeof(ext4_acl_entry); -+ break; -+ case ACL_USER_OBJ: -+ case ACL_GROUP_OBJ: -+ case ACL_MASK: -+ case ACL_OTHER: -+ hptr += sizeof(ext4_acl_entry_short); -+ break; -+ default: -+ err = EXT2_ET_INVALID_ARGUMENT; -+ goto out; -+ } -+ } -+ -+ *facl = f; -+ *facl_sz = f_sz; -+ return err; -+out: -+ ext2fs_free_mem(&f); -+ return err; -+} -+#endif /* TRANSLATE_LINUX_ACLS */ -+ -+/* -+ * ext2_file_t contains a struct inode, so we can't leave files open. -+ * Use this as a proxy instead. -+ */ -+#define FUSE2FS_FILE_MAGIC (0xEF53DEAFUL) -+struct fuse2fs_file_handle { -+ unsigned long magic; -+ ext2_ino_t ino; -+ int open_flags; -+}; -+ -+/* Main program context */ -+#define FUSE2FS_MAGIC (0xEF53DEADUL) -+struct fuse2fs { -+ unsigned long magic; -+ ext2_filsys fs; -+ pthread_mutex_t bfl; -+ int panic_on_error; -+ int minixdf; -+ int alloc_all_blocks; -+ FILE *err_fp; -+ unsigned int next_generation; -+}; -+ -+#define FUSE2FS_CHECK_MAGIC(fs, ptr, num) do {if ((ptr)->magic != (num)) \ -+ return translate_error((fs), 0, EXT2_ET_MAGIC_EXT2_FILE); \ -+} while (0) -+ -+#define FUSE2FS_CHECK_CONTEXT(ptr) do {if ((ptr)->magic != FUSE2FS_MAGIC) \ -+ return translate_error(global_fs, 0, EXT2_ET_BAD_MAGIC); \ -+} while (0) -+ -+static int __translate_error(ext2_filsys fs, errcode_t err, ext2_ino_t ino, -+ const char *file, int line); -+#define translate_error(fs, ino, err) __translate_error((fs), (err), (ino), \ -+ __FILE__, __LINE__) -+ -+/* for macosx */ -+#ifndef W_OK -+# define W_OK 2 -+#endif -+ -+#ifndef R_OK -+# define R_OK 4 -+#endif -+ -+#define EXT4_EPOCH_BITS 2 -+#define EXT4_EPOCH_MASK ((1 << EXT4_EPOCH_BITS) - 1) -+#define EXT4_NSEC_MASK (~0UL << EXT4_EPOCH_BITS) -+ -+/* -+ * Extended fields will fit into an inode if the filesystem was formatted -+ * with large inodes (-I 256 or larger) and there are not currently any EAs -+ * consuming all of the available space. For new inodes we always reserve -+ * enough space for the kernel's known extended fields, but for inodes -+ * created with an old kernel this might not have been the case. None of -+ * the extended inode fields is critical for correct filesystem operation. -+ * This macro checks if a certain field fits in the inode. Note that -+ * inode-size = GOOD_OLD_INODE_SIZE + i_extra_isize -+ */ -+#define EXT4_FITS_IN_INODE(ext4_inode, field) \ -+ ((offsetof(typeof(*ext4_inode), field) + \ -+ sizeof((ext4_inode)->field)) \ -+ <= ((size_t) EXT2_GOOD_OLD_INODE_SIZE + \ -+ (ext4_inode)->i_extra_isize)) \ -+ -+static inline __u32 ext4_encode_extra_time(const struct timespec *time) -+{ -+ __u32 extra = sizeof(time->tv_sec) > 4 ? -+ ((time->tv_sec - (__s32)time->tv_sec) >> 32) & -+ EXT4_EPOCH_MASK : 0; -+ return extra | (time->tv_nsec << EXT4_EPOCH_BITS); -+} -+ -+static inline void ext4_decode_extra_time(struct timespec *time, __u32 extra) -+{ -+ if (sizeof(time->tv_sec) > 4 && (extra & EXT4_EPOCH_MASK)) { -+ __u64 extra_bits = extra & EXT4_EPOCH_MASK; -+ /* -+ * Prior to kernel 3.14?, we had a broken decode function, -+ * wherein we effectively did this: -+ * if (extra_bits == 3) -+ * extra_bits = 0; -+ */ -+ time->tv_sec += extra_bits << 32; -+ } -+ time->tv_nsec = ((extra) & EXT4_NSEC_MASK) >> EXT4_EPOCH_BITS; -+} -+ -+#define EXT4_INODE_SET_XTIME(xtime, timespec, raw_inode) \ -+do { \ -+ (raw_inode)->xtime = (timespec)->tv_sec; \ -+ if (EXT4_FITS_IN_INODE(raw_inode, xtime ## _extra)) \ -+ (raw_inode)->xtime ## _extra = \ -+ ext4_encode_extra_time(timespec); \ -+} while (0) -+ -+#define EXT4_EINODE_SET_XTIME(xtime, timespec, raw_inode) \ -+do { \ -+ if (EXT4_FITS_IN_INODE(raw_inode, xtime)) \ -+ (raw_inode)->xtime = (timespec)->tv_sec; \ -+ if (EXT4_FITS_IN_INODE(raw_inode, xtime ## _extra)) \ -+ (raw_inode)->xtime ## _extra = \ -+ ext4_encode_extra_time(timespec); \ -+} while (0) -+ -+#define EXT4_INODE_GET_XTIME(xtime, timespec, raw_inode) \ -+do { \ -+ (timespec)->tv_sec = (signed)((raw_inode)->xtime); \ -+ if (EXT4_FITS_IN_INODE(raw_inode, xtime ## _extra)) \ -+ ext4_decode_extra_time((timespec), \ -+ (raw_inode)->xtime ## _extra); \ -+ else \ -+ (timespec)->tv_nsec = 0; \ -+} while (0) -+ -+#define EXT4_EINODE_GET_XTIME(xtime, timespec, raw_inode) \ -+do { \ -+ if (EXT4_FITS_IN_INODE(raw_inode, xtime)) \ -+ (timespec)->tv_sec = \ -+ (signed)((raw_inode)->xtime); \ -+ if (EXT4_FITS_IN_INODE(raw_inode, xtime ## _extra)) \ -+ ext4_decode_extra_time((timespec), \ -+ raw_inode->xtime ## _extra); \ -+ else \ -+ (timespec)->tv_nsec = 0; \ -+} while (0) -+ -+static void get_now(struct timespec *now) -+{ -+#ifdef CLOCK_REALTIME -+ if (!clock_gettime(CLOCK_REALTIME, now)) -+ return; -+#endif -+ -+ now->tv_sec = time(NULL); -+ now->tv_nsec = 0; -+} -+ -+static void increment_version(struct ext2_inode_large *inode) -+{ -+ __u64 ver; -+ -+ ver = inode->osd1.linux1.l_i_version; -+ if (EXT4_FITS_IN_INODE(inode, i_version_hi)) -+ ver |= (__u64)inode->i_version_hi << 32; -+ ver++; -+ inode->osd1.linux1.l_i_version = ver; -+ if (EXT4_FITS_IN_INODE(inode, i_version_hi)) -+ inode->i_version_hi = ver >> 32; -+} -+ -+static void init_times(struct ext2_inode_large *inode) -+{ -+ struct timespec now; -+ -+ get_now(&now); -+ EXT4_INODE_SET_XTIME(i_atime, &now, inode); -+ EXT4_INODE_SET_XTIME(i_ctime, &now, inode); -+ EXT4_INODE_SET_XTIME(i_mtime, &now, inode); -+ EXT4_EINODE_SET_XTIME(i_crtime, &now, inode); -+ increment_version(inode); -+} -+ -+static int update_ctime(ext2_filsys fs, ext2_ino_t ino, -+ struct ext2_inode_large *pinode) -+{ -+ errcode_t err; -+ struct timespec now; -+ struct ext2_inode_large inode; -+ -+ get_now(&now); -+ -+ /* If user already has a inode buffer, just update that */ -+ if (pinode) { -+ increment_version(pinode); -+ EXT4_INODE_SET_XTIME(i_ctime, &now, pinode); -+ return 0; -+ } -+ -+ /* Otherwise we have to read-modify-write the inode */ -+ memset(&inode, 0, sizeof(inode)); -+ err = ext2fs_read_inode_full(fs, ino, (struct ext2_inode *)&inode, -+ sizeof(inode)); -+ if (err) -+ return translate_error(fs, ino, err); -+ -+ increment_version(&inode); -+ EXT4_INODE_SET_XTIME(i_ctime, &now, &inode); -+ -+ err = ext2fs_write_inode_full(fs, ino, (struct ext2_inode *)&inode, -+ sizeof(inode)); -+ if (err) -+ return translate_error(fs, ino, err); -+ -+ return 0; -+} -+ -+static int update_atime(ext2_filsys fs, ext2_ino_t ino) -+{ -+ errcode_t err; -+ struct ext2_inode_large inode, *pinode; -+ struct timespec atime, mtime, now; -+ -+ if (!(fs->flags & EXT2_FLAG_RW)) -+ return 0; -+ memset(&inode, 0, sizeof(inode)); -+ err = ext2fs_read_inode_full(fs, ino, (struct ext2_inode *)&inode, -+ sizeof(inode)); -+ if (err) -+ return translate_error(fs, ino, err); -+ -+ pinode = &inode; -+ EXT4_INODE_GET_XTIME(i_atime, &atime, pinode); -+ EXT4_INODE_GET_XTIME(i_mtime, &mtime, pinode); -+ get_now(&now); -+ /* -+ * If atime is newer than mtime and atime hasn't been updated in thirty -+ * seconds, skip the atime update. Same idea as Linux "relatime". -+ */ -+ if (atime.tv_sec >= mtime.tv_sec && atime.tv_sec >= now.tv_sec - 30) -+ return 0; -+ EXT4_INODE_SET_XTIME(i_atime, &now, &inode); -+ -+ err = ext2fs_write_inode_full(fs, ino, (struct ext2_inode *)&inode, -+ sizeof(inode)); -+ if (err) -+ return translate_error(fs, ino, err); -+ -+ return 0; -+} -+ -+static int update_mtime(ext2_filsys fs, ext2_ino_t ino, -+ struct ext2_inode_large *pinode) -+{ -+ errcode_t err; -+ struct ext2_inode_large inode; -+ struct timespec now; -+ -+ if (pinode) { -+ get_now(&now); -+ EXT4_INODE_SET_XTIME(i_mtime, &now, pinode); -+ EXT4_INODE_SET_XTIME(i_ctime, &now, pinode); -+ increment_version(pinode); -+ return 0; -+ } -+ -+ memset(&inode, 0, sizeof(inode)); -+ err = ext2fs_read_inode_full(fs, ino, (struct ext2_inode *)&inode, -+ sizeof(inode)); -+ if (err) -+ return translate_error(fs, ino, err); -+ -+ get_now(&now); -+ EXT4_INODE_SET_XTIME(i_mtime, &now, &inode); -+ EXT4_INODE_SET_XTIME(i_ctime, &now, &inode); -+ increment_version(&inode); -+ -+ err = ext2fs_write_inode_full(fs, ino, (struct ext2_inode *)&inode, -+ sizeof(inode)); -+ if (err) -+ return translate_error(fs, ino, err); -+ -+ return 0; -+} -+ -+static int ext2_file_type(unsigned int mode) -+{ -+ if (LINUX_S_ISREG(mode)) -+ return EXT2_FT_REG_FILE; -+ -+ if (LINUX_S_ISDIR(mode)) -+ return EXT2_FT_DIR; -+ -+ if (LINUX_S_ISCHR(mode)) -+ return EXT2_FT_CHRDEV; -+ -+ if (LINUX_S_ISBLK(mode)) -+ return EXT2_FT_BLKDEV; -+ -+ if (LINUX_S_ISLNK(mode)) -+ return EXT2_FT_SYMLINK; -+ -+ if (LINUX_S_ISFIFO(mode)) -+ return EXT2_FT_FIFO; -+ -+ if (LINUX_S_ISSOCK(mode)) -+ return EXT2_FT_SOCK; -+ -+ return 0; -+} -+ -+static int fs_can_allocate(struct fuse2fs *ff, blk64_t num) -+{ -+ ext2_filsys fs = ff->fs; -+ blk64_t reserved; -+ -+ dbg_printf("%s: Asking for %llu; alloc_all=%d total=%llu free=%llu " -+ "rsvd=%llu\n", __func__, num, ff->alloc_all_blocks, -+ ext2fs_blocks_count(fs->super), -+ ext2fs_free_blocks_count(fs->super), -+ ext2fs_r_blocks_count(fs->super)); -+ if (num > ext2fs_blocks_count(fs->super)) -+ return 0; -+ -+ if (ff->alloc_all_blocks) -+ return 1; -+ -+ /* -+ * Different meaning for r_blocks -- libext2fs has bugs where the FS -+ * can get corrupted if it totally runs out of blocks. Avoid this -+ * by refusing to allocate any of the reserve blocks to anybody. -+ */ -+ reserved = ext2fs_r_blocks_count(fs->super); -+ if (reserved == 0) -+ reserved = ext2fs_blocks_count(fs->super) / 10; -+ return ext2fs_free_blocks_count(fs->super) > reserved + num; -+} -+ -+static int fs_writeable(ext2_filsys fs) -+{ -+ return (fs->flags & EXT2_FLAG_RW) && (fs->super->s_error_count == 0); -+} -+ -+static int check_inum_access(ext2_filsys fs, ext2_ino_t ino, mode_t mask) -+{ -+ struct fuse_context *ctxt = fuse_get_context(); -+ struct ext2_inode inode; -+ mode_t perms; -+ errcode_t err; -+ -+ /* no writing to read-only or broken fs */ -+ if ((mask & W_OK) && !fs_writeable(fs)) -+ return -EROFS; -+ -+ err = ext2fs_read_inode(fs, ino, &inode); -+ if (err) -+ return translate_error(fs, ino, err); -+ perms = inode.i_mode & 0777; -+ -+ dbg_printf("access ino=%d mask=e%s%s%s perms=0%o fuid=%d fgid=%d " -+ "uid=%d gid=%d\n", ino, -+ (mask & R_OK ? "r" : ""), (mask & W_OK ? "w" : ""), -+ (mask & X_OK ? "x" : ""), perms, inode.i_uid, inode.i_gid, -+ ctxt->uid, ctxt->gid); -+ -+ /* existence check */ -+ if (mask == 0) -+ return 0; -+ -+ /* is immutable? */ -+ if ((mask & W_OK) && -+ (inode.i_flags & EXT2_IMMUTABLE_FL)) -+ return -EACCES; -+ -+ /* Figure out what root's allowed to do */ -+ if (ctxt->uid == 0) { -+ /* Non-file access always ok */ -+ if (!LINUX_S_ISREG(inode.i_mode)) -+ return 0; -+ -+ /* R/W access to a file always ok */ -+ if (!(mask & X_OK)) -+ return 0; -+ -+ /* X access to a file ok if a user/group/other can X */ -+ if (perms & 0111) -+ return 0; -+ -+ /* Trying to execute a file that's not executable. BZZT! */ -+ return -EACCES; -+ } -+ -+ /* allow owner, if perms match */ -+ if (inode.i_uid == ctxt->uid) { -+ if ((mask & (perms >> 6)) == mask) -+ return 0; -+ return -EACCES; -+ } -+ -+ /* allow group, if perms match */ -+ if (inode.i_gid == ctxt->gid) { -+ if ((mask & (perms >> 3)) == mask) -+ return 0; -+ return -EACCES; -+ } -+ -+ /* otherwise check other */ -+ if ((mask & perms) == mask) -+ return 0; -+ return -EACCES; -+} -+ -+static void op_destroy(void *p EXT2FS_ATTR((unused))) -+{ -+ struct fuse_context *ctxt = fuse_get_context(); -+ struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data; -+ ext2_filsys fs; -+ errcode_t err; -+ -+ if (ff->magic != FUSE2FS_MAGIC) { -+ translate_error(global_fs, 0, EXT2_ET_BAD_MAGIC); -+ return; -+ } -+ fs = ff->fs; -+ dbg_printf("%s: dev=%s\n", __func__, fs->device_name); -+ if (fs->flags & EXT2_FLAG_RW) { -+ fs->super->s_state |= EXT2_VALID_FS; -+ if (fs->super->s_error_count) -+ fs->super->s_state |= EXT2_ERROR_FS; -+ ext2fs_mark_super_dirty(fs); -+ err = ext2fs_set_gdt_csum(fs); -+ if (err) -+ translate_error(fs, 0, err); -+ -+ err = ext2fs_flush2(fs, 0); -+ if (err) -+ translate_error(fs, 0, err); -+ } -+} -+ -+static void *op_init(struct fuse_conn_info *conn) -+{ -+ struct fuse_context *ctxt = fuse_get_context(); -+ struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data; -+ ext2_filsys fs; -+ errcode_t err; -+ -+ if (ff->magic != FUSE2FS_MAGIC) { -+ translate_error(global_fs, 0, EXT2_ET_BAD_MAGIC); -+ return NULL; -+ } -+ fs = ff->fs; -+ dbg_printf("%s: dev=%s\n", __func__, fs->device_name); -+#ifdef FUSE_CAP_IOCTL_DIR -+ conn->want |= FUSE_CAP_IOCTL_DIR; -+#endif -+ if (fs->flags & EXT2_FLAG_RW) { -+ fs->super->s_mnt_count++; -+ fs->super->s_mtime = time(NULL); -+ fs->super->s_state &= ~EXT2_VALID_FS; -+ ext2fs_mark_super_dirty(fs); -+ err = ext2fs_flush2(fs, 0); -+ if (err) -+ translate_error(fs, 0, err); -+ } -+ return ff; -+} -+ -+static blkcnt_t blocks_from_inode(ext2_filsys fs, -+ struct ext2_inode_large *inode) -+{ -+ blkcnt_t b; -+ -+ b = inode->i_blocks; -+ if (fs->super->s_feature_ro_compat & EXT4_FEATURE_RO_COMPAT_HUGE_FILE) -+ b += ((long long) inode->osd2.linux2.l_i_blocks_hi) << 32; -+ -+ if (!(fs->super->s_feature_ro_compat & -+ EXT4_FEATURE_RO_COMPAT_HUGE_FILE) || -+ !(inode->i_flags & EXT4_HUGE_FILE_FL)) -+ b *= fs->blocksize / 512; -+ b *= EXT2FS_CLUSTER_RATIO(fs); -+ -+ return b; -+} -+ -+static int stat_inode(ext2_filsys fs, ext2_ino_t ino, struct stat *statbuf) -+{ -+ struct ext2_inode_large inode; -+ dev_t fakedev = 0; -+ errcode_t err; -+ int ret = 0; -+ struct timespec tv; -+ -+ memset(&inode, 0, sizeof(inode)); -+ err = ext2fs_read_inode_full(fs, ino, (struct ext2_inode *)&inode, -+ sizeof(inode)); -+ if (err) -+ return translate_error(fs, ino, err); -+ -+ memcpy(&fakedev, fs->super->s_uuid, sizeof(fakedev)); -+ statbuf->st_dev = fakedev; -+ statbuf->st_ino = ino; -+ statbuf->st_mode = inode.i_mode; -+ statbuf->st_nlink = inode.i_links_count; -+ statbuf->st_uid = inode.i_uid; -+ statbuf->st_gid = inode.i_gid; -+ statbuf->st_size = EXT2_I_SIZE(&inode); -+ statbuf->st_blksize = fs->blocksize; -+ statbuf->st_blocks = blocks_from_inode(fs, &inode); -+ EXT4_INODE_GET_XTIME(i_atime, &tv, &inode); -+ statbuf->st_atime = tv.tv_sec; -+ EXT4_INODE_GET_XTIME(i_mtime, &tv, &inode); -+ statbuf->st_mtime = tv.tv_sec; -+ EXT4_INODE_GET_XTIME(i_ctime, &tv, &inode); -+ statbuf->st_ctime = tv.tv_sec; -+ if (LINUX_S_ISCHR(inode.i_mode) || -+ LINUX_S_ISBLK(inode.i_mode)) { -+ if (inode.i_block[0]) -+ statbuf->st_rdev = inode.i_block[0]; -+ else -+ statbuf->st_rdev = inode.i_block[1]; -+ } -+ -+ return ret; -+} -+ -+static int op_getattr(const char *path, struct stat *statbuf) -+{ -+ struct fuse_context *ctxt = fuse_get_context(); -+ struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data; -+ ext2_filsys fs; -+ ext2_ino_t ino; -+ errcode_t err; -+ int ret = 0; -+ -+ FUSE2FS_CHECK_CONTEXT(ff); -+ fs = ff->fs; -+ dbg_printf("%s: path=%s\n", __func__, path); -+ pthread_mutex_lock(&ff->bfl); -+ err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, path, &ino); -+ if (err) { -+ ret = translate_error(fs, 0, err); -+ goto out; -+ } -+ ret = stat_inode(fs, ino, statbuf); -+out: -+ pthread_mutex_unlock(&ff->bfl); -+ return ret; -+} -+ -+static int op_readlink(const char *path, char *buf, size_t len) -+{ -+ struct fuse_context *ctxt = fuse_get_context(); -+ struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data; -+ ext2_filsys fs; -+ errcode_t err; -+ ext2_ino_t ino; -+ struct ext2_inode inode; -+ unsigned int got; -+ ext2_file_t file; -+ int ret = 0; -+ -+ FUSE2FS_CHECK_CONTEXT(ff); -+ fs = ff->fs; -+ dbg_printf("%s: path=%s\n", __func__, path); -+ pthread_mutex_lock(&ff->bfl); -+ err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, path, &ino); -+ if (err || ino == 0) { -+ ret = translate_error(fs, 0, err); -+ goto out; -+ } -+ -+ err = ext2fs_read_inode(fs, ino, &inode); -+ if (err) { -+ ret = translate_error(fs, ino, err); -+ goto out; -+ } -+ -+ if (!LINUX_S_ISLNK(inode.i_mode)) { -+ ret = -EINVAL; -+ goto out; -+ } -+ -+ len--; -+ if (inode.i_size < len) -+ len = inode.i_size; -+ if (ext2fs_inode_data_blocks2(fs, &inode) || -+ (inode.i_flags & EXT4_INLINE_DATA_FL)) { -+ /* big/inline symlink */ -+ -+ err = ext2fs_file_open(fs, ino, 0, &file); -+ if (err) { -+ ret = translate_error(fs, ino, err); -+ goto out; -+ } -+ -+ err = ext2fs_file_read(file, buf, len, &got); -+ if (err || got != len) { -+ ext2fs_file_close(file); -+ ret = translate_error(fs, ino, err); -+ goto out2; -+ } -+ -+out2: -+ err = ext2fs_file_close(file); -+ if (ret) -+ goto out; -+ if (err) { -+ ret = translate_error(fs, ino, err); -+ goto out; -+ } -+ } else -+ /* inline symlink */ -+ memcpy(buf, (char *)inode.i_block, len); -+ buf[len] = 0; -+ -+ if (fs_writeable(fs)) { -+ ret = update_atime(fs, ino); -+ if (ret) -+ goto out; -+ } -+ -+out: -+ pthread_mutex_unlock(&ff->bfl); -+ return ret; -+} -+ -+static int op_mknod(const char *path, mode_t mode, dev_t dev) -+{ -+ struct fuse_context *ctxt = fuse_get_context(); -+ struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data; -+ ext2_filsys fs; -+ ext2_ino_t parent, child; -+ char *temp_path = strdup(path); -+ errcode_t err; -+ char *node_name, a; -+ int filetype; -+ struct ext2_inode_large inode; -+ int ret = 0; -+ -+ FUSE2FS_CHECK_CONTEXT(ff); -+ fs = ff->fs; -+ dbg_printf("%s: path=%s mode=0%o dev=0x%x\n", __func__, path, mode, -+ (unsigned int)dev); -+ if (!temp_path) { -+ ret = -ENOMEM; -+ goto out; -+ } -+ node_name = strrchr(temp_path, '/'); -+ if (!node_name) { -+ ret = -ENOMEM; -+ goto out; -+ } -+ node_name++; -+ a = *node_name; -+ *node_name = 0; -+ -+ pthread_mutex_lock(&ff->bfl); -+ if (!fs_can_allocate(ff, 2)) { -+ ret = -ENOSPC; -+ goto out2; -+ } -+ -+ err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, temp_path, -+ &parent); -+ if (err) { -+ ret = translate_error(fs, 0, err); -+ goto out2; -+ } -+ -+ ret = check_inum_access(fs, parent, W_OK); -+ if (ret) -+ goto out2; -+ -+ *node_name = a; -+ -+ if (LINUX_S_ISCHR(mode)) -+ filetype = EXT2_FT_CHRDEV; -+ else if (LINUX_S_ISBLK(mode)) -+ filetype = EXT2_FT_BLKDEV; -+ else if (LINUX_S_ISFIFO(mode)) -+ filetype = EXT2_FT_FIFO; -+ else if (LINUX_S_ISSOCK(mode)) -+ filetype = EXT2_FT_SOCK; -+ else { -+ ret = -EINVAL; -+ goto out2; -+ } -+ -+ err = ext2fs_new_inode(fs, parent, mode, 0, &child); -+ if (err) { -+ ret = translate_error(fs, 0, err); -+ goto out2; -+ } -+ -+ dbg_printf("%s: create ino=%d/name=%s in dir=%d\n", __func__, child, -+ node_name, parent); -+ err = ext2fs_link(fs, parent, node_name, child, filetype); -+ if (err == EXT2_ET_DIR_NO_SPACE) { -+ err = ext2fs_expand_dir(fs, parent); -+ if (err) { -+ ret = translate_error(fs, parent, err); -+ goto out2; -+ } -+ -+ err = ext2fs_link(fs, parent, node_name, child, -+ filetype); -+ } -+ if (err) { -+ ret = translate_error(fs, parent, err); -+ goto out2; -+ } -+ -+ ret = update_mtime(fs, parent, NULL); -+ if (ret) -+ goto out2; -+ -+ memset(&inode, 0, sizeof(inode)); -+ inode.i_mode = mode; -+ -+ if (dev & ~0xFFFF) -+ inode.i_block[1] = dev; -+ else -+ inode.i_block[0] = dev; -+ inode.i_links_count = 1; -+ inode.i_extra_isize = sizeof(struct ext2_inode_large) - -+ EXT2_GOOD_OLD_INODE_SIZE; -+ -+ err = ext2fs_write_new_inode(fs, child, (struct ext2_inode *)&inode); -+ if (err) { -+ ret = translate_error(fs, child, err); -+ goto out2; -+ } -+ -+ inode.i_generation = ff->next_generation++; -+ init_times(&inode); -+ err = ext2fs_write_inode_full(fs, child, (struct ext2_inode *)&inode, -+ sizeof(inode)); -+ if (err) { -+ ret = translate_error(fs, child, err); -+ goto out2; -+ } -+ -+ ext2fs_inode_alloc_stats2(fs, child, 1, 0); -+ -+out2: -+ pthread_mutex_unlock(&ff->bfl); -+out: -+ free(temp_path); -+ return ret; -+} -+ -+static int op_mkdir(const char *path, mode_t mode) -+{ -+ struct fuse_context *ctxt = fuse_get_context(); -+ struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data; -+ ext2_filsys fs; -+ ext2_ino_t parent, child; -+ char *temp_path = strdup(path); -+ errcode_t err; -+ char *node_name, a; -+ struct ext2_inode_large inode; -+ char *block; -+ blk64_t blk; -+ int ret = 0; -+ mode_t parent_sgid; -+ -+ FUSE2FS_CHECK_CONTEXT(ff); -+ fs = ff->fs; -+ dbg_printf("%s: path=%s mode=0%o\n", __func__, path, mode); -+ if (!temp_path) { -+ ret = -ENOMEM; -+ goto out; -+ } -+ node_name = strrchr(temp_path, '/'); -+ if (!node_name) { -+ ret = -ENOMEM; -+ goto out; -+ } -+ node_name++; -+ a = *node_name; -+ *node_name = 0; -+ -+ pthread_mutex_lock(&ff->bfl); -+ if (!fs_can_allocate(ff, 1)) { -+ ret = -ENOSPC; -+ goto out2; -+ } -+ -+ err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, temp_path, -+ &parent); -+ if (err) { -+ ret = translate_error(fs, 0, err); -+ goto out2; -+ } -+ -+ ret = check_inum_access(fs, parent, W_OK); -+ if (ret) -+ goto out2; -+ -+ /* Is the parent dir sgid? */ -+ err = ext2fs_read_inode_full(fs, parent, (struct ext2_inode *)&inode, -+ sizeof(inode)); -+ if (err) { -+ ret = translate_error(fs, parent, err); -+ goto out2; -+ } -+ parent_sgid = inode.i_mode & S_ISGID; -+ -+ *node_name = a; -+ -+ err = ext2fs_mkdir(fs, parent, 0, node_name); -+ if (err == EXT2_ET_DIR_NO_SPACE) { -+ err = ext2fs_expand_dir(fs, parent); -+ if (err) { -+ ret = translate_error(fs, parent, err); -+ goto out2; -+ } -+ -+ err = ext2fs_mkdir(fs, parent, 0, node_name); -+ } -+ if (err) { -+ ret = translate_error(fs, parent, err); -+ goto out2; -+ } -+ -+ ret = update_mtime(fs, parent, NULL); -+ if (ret) -+ goto out2; -+ -+ /* Still have to update the uid/gid of the dir */ -+ err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, temp_path, -+ &child); -+ if (err) { -+ ret = translate_error(fs, 0, err); -+ goto out2; -+ } -+ dbg_printf("%s: created ino=%d/path=%s in dir=%d\n", __func__, child, -+ node_name, parent); -+ -+ memset(&inode, 0, sizeof(inode)); -+ err = ext2fs_read_inode_full(fs, child, (struct ext2_inode *)&inode, -+ sizeof(inode)); -+ if (err) { -+ ret = translate_error(fs, child, err); -+ goto out2; -+ } -+ -+ inode.i_uid = ctxt->uid; -+ inode.i_gid = ctxt->gid; -+ inode.i_mode = LINUX_S_IFDIR | (mode & ~(S_ISUID | fs->umask)) | -+ parent_sgid; -+ inode.i_generation = ff->next_generation++; -+ -+ err = ext2fs_write_inode_full(fs, child, (struct ext2_inode *)&inode, -+ sizeof(inode)); -+ if (err) { -+ ret = translate_error(fs, child, err); -+ goto out2; -+ } -+ -+ /* Rewrite the directory block checksum, having set i_generation */ -+ if ((inode.i_flags & EXT4_INLINE_DATA_FL) || -+ !EXT2_HAS_RO_COMPAT_FEATURE(fs->super, -+ EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) -+ goto out2; -+ err = ext2fs_new_dir_block(fs, child, parent, &block); -+ if (err) { -+ ret = translate_error(fs, child, err); -+ goto out2; -+ } -+ err = ext2fs_bmap2(fs, child, (struct ext2_inode *)&inode, NULL, 0, 0, -+ NULL, &blk); -+ if (err) { -+ ret = translate_error(fs, child, err); -+ goto out3; -+ } -+ err = ext2fs_write_dir_block4(fs, blk, block, 0, child); -+ if (err) { -+ ret = translate_error(fs, child, err); -+ goto out3; -+ } -+ -+out3: -+ ext2fs_free_mem(&block); -+out2: -+ pthread_mutex_unlock(&ff->bfl); -+out: -+ free(temp_path); -+ return ret; -+} -+ -+static int unlink_file_by_name(ext2_filsys fs, const char *path) -+{ -+ errcode_t err; -+ ext2_ino_t dir; -+ char *filename = strdup(path); -+ char *base_name; -+ int ret; -+ -+ base_name = strrchr(filename, '/'); -+ if (base_name) { -+ *base_name++ = '\0'; -+ err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, filename, -+ &dir); -+ if (err) { -+ free(filename); -+ return translate_error(fs, 0, err); -+ } -+ } else { -+ dir = EXT2_ROOT_INO; -+ base_name = filename; -+ } -+ -+ ret = check_inum_access(fs, dir, W_OK); -+ if (ret) { -+ free(filename); -+ return ret; -+ } -+ -+ dbg_printf("%s: unlinking name=%s from dir=%d\n", __func__, -+ base_name, dir); -+ err = ext2fs_unlink(fs, dir, base_name, 0, 0); -+ free(filename); -+ if (err) -+ return translate_error(fs, dir, err); -+ -+ return update_mtime(fs, dir, NULL); -+} -+ -+static int remove_inode(struct fuse2fs *ff, ext2_ino_t ino) -+{ -+ ext2_filsys fs = ff->fs; -+ errcode_t err; -+ struct ext2_inode_large inode; -+ int ret = 0; -+ -+ memset(&inode, 0, sizeof(inode)); -+ err = ext2fs_read_inode_full(fs, ino, (struct ext2_inode *)&inode, -+ sizeof(inode)); -+ if (err) { -+ ret = translate_error(fs, ino, err); -+ goto out; -+ } -+ dbg_printf("%s: put ino=%d links=%d\n", __func__, ino, -+ inode.i_links_count); -+ -+ switch (inode.i_links_count) { -+ case 0: -+ return 0; /* XXX: already done? */ -+ case 1: -+ inode.i_links_count--; -+ inode.i_dtime = fs->now ? fs->now : time(0); -+ break; -+ default: -+ inode.i_links_count--; -+ } -+ -+ ret = update_ctime(fs, ino, &inode); -+ if (ret) -+ goto out; -+ -+ if (inode.i_links_count) -+ goto write_out; -+ -+ /* Nobody holds this file; free its blocks! */ -+ err = ext2fs_free_ext_attr(fs, ino, &inode); -+ if (err) -+ goto write_out; -+ -+ if (ext2fs_inode_has_valid_blocks2(fs, (struct ext2_inode *)&inode)) { -+ err = ext2fs_punch(fs, ino, (struct ext2_inode *)&inode, NULL, -+ 0, ~0ULL); -+ if (err) { -+ ret = translate_error(fs, ino, err); -+ goto write_out; -+ } -+ } -+ -+ ext2fs_inode_alloc_stats2(fs, ino, -1, -+ LINUX_S_ISDIR(inode.i_mode)); -+ -+write_out: -+ err = ext2fs_write_inode_full(fs, ino, (struct ext2_inode *)&inode, -+ sizeof(inode)); -+ if (err) { -+ ret = translate_error(fs, ino, err); -+ goto out; -+ } -+out: -+ return ret; -+} -+ -+static int __op_unlink(struct fuse2fs *ff, const char *path) -+{ -+ ext2_filsys fs = ff->fs; -+ ext2_ino_t ino; -+ errcode_t err; -+ int ret = 0; -+ -+ err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, path, &ino); -+ if (err) { -+ ret = translate_error(fs, 0, err); -+ goto out; -+ } -+ -+ ret = unlink_file_by_name(fs, path); -+ if (ret) -+ goto out; -+ -+ ret = remove_inode(ff, ino); -+ if (ret) -+ goto out; -+out: -+ return ret; -+} -+ -+static int op_unlink(const char *path) -+{ -+ struct fuse_context *ctxt = fuse_get_context(); -+ struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data; -+ int ret; -+ -+ FUSE2FS_CHECK_CONTEXT(ff); -+ pthread_mutex_lock(&ff->bfl); -+ ret = __op_unlink(ff, path); -+ pthread_mutex_unlock(&ff->bfl); -+ return ret; -+} -+ -+struct rd_struct { -+ ext2_ino_t parent; -+ int empty; -+}; -+ -+static int rmdir_proc(ext2_ino_t dir EXT2FS_ATTR((unused)), -+ int entry EXT2FS_ATTR((unused)), -+ struct ext2_dir_entry *dirent, -+ int offset EXT2FS_ATTR((unused)), -+ int blocksize EXT2FS_ATTR((unused)), -+ char *buf EXT2FS_ATTR((unused)), -+ void *private) -+{ -+ struct rd_struct *rds = (struct rd_struct *) private; -+ -+ if (dirent->inode == 0) -+ return 0; -+ if (((dirent->name_len & 0xFF) == 1) && (dirent->name[0] == '.')) -+ return 0; -+ if (((dirent->name_len & 0xFF) == 2) && (dirent->name[0] == '.') && -+ (dirent->name[1] == '.')) { -+ rds->parent = dirent->inode; -+ return 0; -+ } -+ rds->empty = 0; -+ return 0; -+} -+ -+static int __op_rmdir(struct fuse2fs *ff, const char *path) -+{ -+ ext2_filsys fs = ff->fs; -+ ext2_ino_t child; -+ errcode_t err; -+ struct ext2_inode_large inode; -+ struct rd_struct rds; -+ int ret = 0; -+ -+ err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, path, &child); -+ if (err) { -+ ret = translate_error(fs, 0, err); -+ goto out; -+ } -+ dbg_printf("%s: rmdir path=%s ino=%d\n", __func__, path, child); -+ -+ rds.parent = 0; -+ rds.empty = 1; -+ -+ err = ext2fs_dir_iterate2(fs, child, 0, 0, rmdir_proc, &rds); -+ if (err) { -+ ret = translate_error(fs, child, err); -+ goto out; -+ } -+ -+ if (rds.empty == 0) { -+ ret = -ENOTEMPTY; -+ goto out; -+ } -+ -+ ret = unlink_file_by_name(fs, path); -+ if (ret) -+ goto out; -+ /* Directories have to be "removed" twice. */ -+ ret = remove_inode(ff, child); -+ if (ret) -+ goto out; -+ ret = remove_inode(ff, child); -+ if (ret) -+ goto out; -+ -+ if (rds.parent) { -+ dbg_printf("%s: decr dir=%d link count\n", __func__, -+ rds.parent); -+ err = ext2fs_read_inode_full(fs, rds.parent, -+ (struct ext2_inode *)&inode, -+ sizeof(inode)); -+ if (err) { -+ ret = translate_error(fs, rds.parent, err); -+ goto out; -+ } -+ if (inode.i_links_count > 1) -+ inode.i_links_count--; -+ ret = update_mtime(fs, rds.parent, &inode); -+ if (ret) -+ goto out; -+ err = ext2fs_write_inode_full(fs, rds.parent, -+ (struct ext2_inode *)&inode, -+ sizeof(inode)); -+ if (err) { -+ ret = translate_error(fs, rds.parent, err); -+ goto out; -+ } -+ } -+ -+out: -+ return ret; -+} -+ -+static int op_rmdir(const char *path) -+{ -+ struct fuse_context *ctxt = fuse_get_context(); -+ struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data; -+ int ret; -+ -+ FUSE2FS_CHECK_CONTEXT(ff); -+ pthread_mutex_lock(&ff->bfl); -+ ret = __op_rmdir(ff, path); -+ pthread_mutex_unlock(&ff->bfl); -+ return ret; -+} -+ -+static int op_symlink(const char *src, const char *dest) -+{ -+ struct fuse_context *ctxt = fuse_get_context(); -+ struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data; -+ ext2_filsys fs; -+ ext2_ino_t parent, child; -+ char *temp_path = strdup(dest); -+ errcode_t err; -+ char *node_name, a; -+ struct ext2_inode_large inode; -+ int ret = 0; -+ -+ FUSE2FS_CHECK_CONTEXT(ff); -+ fs = ff->fs; -+ dbg_printf("%s: symlink %s to %s\n", __func__, src, dest); -+ if (!temp_path) { -+ ret = -ENOMEM; -+ goto out; -+ } -+ node_name = strrchr(temp_path, '/'); -+ if (!node_name) { -+ ret = -ENOMEM; -+ goto out; -+ } -+ node_name++; -+ a = *node_name; -+ *node_name = 0; -+ -+ pthread_mutex_lock(&ff->bfl); -+ err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, temp_path, -+ &parent); -+ *node_name = a; -+ if (err) { -+ ret = translate_error(fs, 0, err); -+ goto out2; -+ } -+ -+ ret = check_inum_access(fs, parent, W_OK); -+ if (ret) -+ goto out2; -+ -+ -+ /* Create symlink */ -+ err = ext2fs_symlink(fs, parent, 0, node_name, src); -+ if (err == EXT2_ET_DIR_NO_SPACE) { -+ err = ext2fs_expand_dir(fs, parent); -+ if (err) { -+ ret = translate_error(fs, parent, err); -+ goto out2; -+ } -+ -+ err = ext2fs_symlink(fs, parent, 0, node_name, src); -+ } -+ if (err) { -+ ret = translate_error(fs, parent, err); -+ goto out2; -+ } -+ -+ /* Update parent dir's mtime */ -+ ret = update_mtime(fs, parent, NULL); -+ if (ret) -+ goto out2; -+ -+ /* Still have to update the uid/gid of the symlink */ -+ err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, temp_path, -+ &child); -+ if (err) { -+ ret = translate_error(fs, 0, err); -+ goto out2; -+ } -+ dbg_printf("%s: symlinking ino=%d/name=%s to dir=%d\n", __func__, -+ child, node_name, parent); -+ -+ memset(&inode, 0, sizeof(inode)); -+ err = ext2fs_read_inode_full(fs, child, (struct ext2_inode *)&inode, -+ sizeof(inode)); -+ if (err) { -+ ret = translate_error(fs, child, err); -+ goto out2; -+ } -+ -+ inode.i_uid = ctxt->uid; -+ inode.i_gid = ctxt->gid; -+ inode.i_generation = ff->next_generation++; -+ -+ err = ext2fs_write_inode_full(fs, child, (struct ext2_inode *)&inode, -+ sizeof(inode)); -+ if (err) { -+ ret = translate_error(fs, child, err); -+ goto out2; -+ } -+out2: -+ pthread_mutex_unlock(&ff->bfl); -+out: -+ free(temp_path); -+ return ret; -+} -+ -+struct update_dotdot { -+ ext2_ino_t new_dotdot; -+}; -+ -+static int update_dotdot_helper(ext2_ino_t dir EXT2FS_ATTR((unused)), -+ int entry EXT2FS_ATTR((unused)), -+ struct ext2_dir_entry *dirent, -+ int offset EXT2FS_ATTR((unused)), -+ int blocksize EXT2FS_ATTR((unused)), -+ char *buf EXT2FS_ATTR((unused)), -+ void *priv_data) -+{ -+ struct update_dotdot *ud = priv_data; -+ -+ if (ext2fs_dirent_name_len(dirent) == 2 && -+ dirent->name[0] == '.' && dirent->name[1] == '.') { -+ dirent->inode = ud->new_dotdot; -+ return DIRENT_CHANGED | DIRENT_ABORT; -+ } -+ -+ return 0; -+} -+ -+static int op_rename(const char *from, const char *to) -+{ -+ struct fuse_context *ctxt = fuse_get_context(); -+ struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data; -+ ext2_filsys fs; -+ errcode_t err; -+ ext2_ino_t from_ino, to_ino, to_dir_ino, from_dir_ino; -+ char *temp_to = NULL, *temp_from = NULL; -+ char *cp, a; -+ struct ext2_inode inode; -+ struct update_dotdot ud; -+ int ret = 0; -+ -+ FUSE2FS_CHECK_CONTEXT(ff); -+ fs = ff->fs; -+ dbg_printf("%s: renaming %s to %s\n", __func__, from, to); -+ pthread_mutex_lock(&ff->bfl); -+ if (!fs_can_allocate(ff, 5)) { -+ ret = -ENOSPC; -+ goto out; -+ } -+ -+ err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, from, &from_ino); -+ if (err || from_ino == 0) { -+ ret = translate_error(fs, 0, err); -+ goto out; -+ } -+ -+ err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, to, &to_ino); -+ if (err && err != EXT2_ET_FILE_NOT_FOUND) { -+ ret = translate_error(fs, 0, err); -+ goto out; -+ } -+ -+ if (err == EXT2_ET_FILE_NOT_FOUND) -+ to_ino = 0; -+ -+ /* Already the same file? */ -+ if (to_ino != 0 && to_ino == from_ino) { -+ ret = 0; -+ goto out; -+ } -+ -+ temp_to = strdup(to); -+ if (!temp_to) { -+ ret = -ENOMEM; -+ goto out; -+ } -+ -+ temp_from = strdup(from); -+ if (!temp_from) { -+ ret = -ENOMEM; -+ goto out2; -+ } -+ -+ /* Find parent dir of the source and check write access */ -+ cp = strrchr(temp_from, '/'); -+ if (!cp) { -+ ret = -EINVAL; -+ goto out2; -+ } -+ -+ a = *(cp + 1); -+ *(cp + 1) = 0; -+ err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, temp_from, -+ &from_dir_ino); -+ *(cp + 1) = a; -+ if (err) { -+ ret = translate_error(fs, 0, err); -+ goto out2; -+ } -+ if (from_dir_ino == 0) { -+ ret = -ENOENT; -+ goto out2; -+ } -+ -+ ret = check_inum_access(fs, from_dir_ino, W_OK); -+ if (ret) -+ goto out2; -+ -+ /* Find parent dir of the destination and check write access */ -+ cp = strrchr(temp_to, '/'); -+ if (!cp) { -+ ret = -EINVAL; -+ goto out2; -+ } -+ -+ a = *(cp + 1); -+ *(cp + 1) = 0; -+ err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, temp_to, -+ &to_dir_ino); -+ *(cp + 1) = a; -+ if (err) { -+ ret = translate_error(fs, 0, err); -+ goto out2; -+ } -+ if (to_dir_ino == 0) { -+ ret = -ENOENT; -+ goto out2; -+ } -+ -+ ret = check_inum_access(fs, to_dir_ino, W_OK); -+ if (ret) -+ goto out2; -+ -+ /* If the target exists, unlink it first */ -+ if (to_ino != 0) { -+ err = ext2fs_read_inode(fs, to_ino, &inode); -+ if (err) { -+ ret = translate_error(fs, to_ino, err); -+ goto out2; -+ } -+ -+ dbg_printf("%s: unlinking %s ino=%d\n", __func__, -+ LINUX_S_ISDIR(inode.i_mode) ? "dir" : "file", -+ to_ino); -+ if (LINUX_S_ISDIR(inode.i_mode)) -+ ret = __op_rmdir(ff, to); -+ else -+ ret = __op_unlink(ff, to); -+ if (ret) -+ goto out2; -+ } -+ -+ /* Get ready to do the move */ -+ err = ext2fs_read_inode(fs, from_ino, &inode); -+ if (err) { -+ ret = translate_error(fs, from_ino, err); -+ goto out2; -+ } -+ -+ /* Link in the new file */ -+ dbg_printf("%s: linking ino=%d/path=%s to dir=%d\n", __func__, -+ from_ino, cp + 1, to_dir_ino); -+ err = ext2fs_link(fs, to_dir_ino, cp + 1, from_ino, -+ ext2_file_type(inode.i_mode)); -+ if (err == EXT2_ET_DIR_NO_SPACE) { -+ err = ext2fs_expand_dir(fs, to_dir_ino); -+ if (err) { -+ ret = translate_error(fs, to_dir_ino, err); -+ goto out2; -+ } -+ -+ err = ext2fs_link(fs, to_dir_ino, cp + 1, from_ino, -+ ext2_file_type(inode.i_mode)); -+ } -+ if (err) { -+ ret = translate_error(fs, to_dir_ino, err); -+ goto out2; -+ } -+ -+ /* Update '..' pointer if dir */ -+ err = ext2fs_read_inode(fs, from_ino, &inode); -+ if (err) { -+ ret = translate_error(fs, from_ino, err); -+ goto out2; -+ } -+ -+ if (LINUX_S_ISDIR(inode.i_mode)) { -+ ud.new_dotdot = to_dir_ino; -+ dbg_printf("%s: updating .. entry for dir=%d\n", __func__, -+ to_dir_ino); -+ err = ext2fs_dir_iterate2(fs, from_ino, 0, NULL, -+ update_dotdot_helper, &ud); -+ if (err) { -+ ret = translate_error(fs, from_ino, err); -+ goto out2; -+ } -+ -+ /* Decrease from_dir_ino's links_count */ -+ dbg_printf("%s: moving linkcount from dir=%d to dir=%d\n", -+ __func__, from_dir_ino, to_dir_ino); -+ err = ext2fs_read_inode(fs, from_dir_ino, &inode); -+ if (err) { -+ ret = translate_error(fs, from_dir_ino, err); -+ goto out2; -+ } -+ inode.i_links_count--; -+ err = ext2fs_write_inode(fs, from_dir_ino, &inode); -+ if (err) { -+ ret = translate_error(fs, from_dir_ino, err); -+ goto out2; -+ } -+ -+ /* Increase to_dir_ino's links_count */ -+ err = ext2fs_read_inode(fs, to_dir_ino, &inode); -+ if (err) { -+ ret = translate_error(fs, to_dir_ino, err); -+ goto out2; -+ } -+ inode.i_links_count++; -+ err = ext2fs_write_inode(fs, to_dir_ino, &inode); -+ if (err) { -+ ret = translate_error(fs, to_dir_ino, err); -+ goto out2; -+ } -+ } -+ -+ /* Update timestamps */ -+ ret = update_ctime(fs, from_ino, NULL); -+ if (ret) -+ goto out2; -+ -+ ret = update_mtime(fs, to_dir_ino, NULL); -+ if (ret) -+ goto out2; -+ -+ /* Remove the old file */ -+ ret = unlink_file_by_name(fs, from); -+ if (ret) -+ goto out2; -+ -+ /* Flush the whole mess out */ -+ err = ext2fs_flush2(fs, 0); -+ if (err) -+ ret = translate_error(fs, 0, err); -+ -+out2: -+ free(temp_from); -+ free(temp_to); -+out: -+ pthread_mutex_unlock(&ff->bfl); -+ return ret; -+} -+ -+static int op_link(const char *src, const char *dest) -+{ -+ struct fuse_context *ctxt = fuse_get_context(); -+ struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data; -+ ext2_filsys fs; -+ char *temp_path = strdup(dest); -+ errcode_t err; -+ char *node_name, a; -+ ext2_ino_t parent, ino; -+ struct ext2_inode_large inode; -+ int ret = 0; -+ -+ FUSE2FS_CHECK_CONTEXT(ff); -+ fs = ff->fs; -+ dbg_printf("%s: src=%s dest=%s\n", __func__, src, dest); -+ if (!temp_path) { -+ ret = -ENOMEM; -+ goto out; -+ } -+ node_name = strrchr(temp_path, '/'); -+ if (!node_name) { -+ ret = -ENOMEM; -+ goto out; -+ } -+ node_name++; -+ a = *node_name; -+ *node_name = 0; -+ -+ pthread_mutex_lock(&ff->bfl); -+ if (!fs_can_allocate(ff, 2)) { -+ ret = -ENOSPC; -+ goto out2; -+ } -+ -+ err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, temp_path, -+ &parent); -+ *node_name = a; -+ if (err) { -+ err = -ENOENT; -+ goto out2; -+ } -+ -+ ret = check_inum_access(fs, parent, W_OK); -+ if (ret) -+ goto out2; -+ -+ -+ err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, src, &ino); -+ if (err || ino == 0) { -+ ret = translate_error(fs, 0, err); -+ goto out2; -+ } -+ -+ memset(&inode, 0, sizeof(inode)); -+ err = ext2fs_read_inode_full(fs, ino, (struct ext2_inode *)&inode, -+ sizeof(inode)); -+ if (err) { -+ ret = translate_error(fs, ino, err); -+ goto out2; -+ } -+ -+ inode.i_links_count++; -+ ret = update_ctime(fs, ino, &inode); -+ if (ret) -+ goto out2; -+ -+ err = ext2fs_write_inode_full(fs, ino, (struct ext2_inode *)&inode, -+ sizeof(inode)); -+ if (err) { -+ ret = translate_error(fs, ino, err); -+ goto out2; -+ } -+ -+ dbg_printf("%s: linking ino=%d/name=%s to dir=%d\n", __func__, ino, -+ node_name, parent); -+ err = ext2fs_link(fs, parent, node_name, ino, -+ ext2_file_type(inode.i_mode)); -+ if (err == EXT2_ET_DIR_NO_SPACE) { -+ err = ext2fs_expand_dir(fs, parent); -+ if (err) { -+ ret = translate_error(fs, parent, err); -+ goto out2; -+ } -+ -+ err = ext2fs_link(fs, parent, node_name, ino, -+ ext2_file_type(inode.i_mode)); -+ } -+ if (err) { -+ ret = translate_error(fs, parent, err); -+ goto out2; -+ } -+ -+ ret = update_mtime(fs, parent, NULL); -+ if (ret) -+ goto out2; -+ -+out2: -+ pthread_mutex_unlock(&ff->bfl); -+out: -+ free(temp_path); -+ return ret; -+} -+ -+static int op_chmod(const char *path, mode_t mode) -+{ -+ struct fuse_context *ctxt = fuse_get_context(); -+ struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data; -+ ext2_filsys fs; -+ errcode_t err; -+ ext2_ino_t ino; -+ struct ext2_inode_large inode; -+ int ret = 0; -+ -+ FUSE2FS_CHECK_CONTEXT(ff); -+ fs = ff->fs; -+ pthread_mutex_lock(&ff->bfl); -+ err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, path, &ino); -+ if (err) { -+ ret = translate_error(fs, 0, err); -+ goto out; -+ } -+ dbg_printf("%s: path=%s mode=0%o ino=%d\n", __func__, path, mode, ino); -+ -+ memset(&inode, 0, sizeof(inode)); -+ err = ext2fs_read_inode_full(fs, ino, (struct ext2_inode *)&inode, -+ sizeof(inode)); -+ if (err) { -+ ret = translate_error(fs, ino, err); -+ goto out; -+ } -+ -+ if (ctxt->uid != 0 && ctxt->uid != inode.i_uid) { -+ ret = -EPERM; -+ goto out; -+ } -+ -+ /* -+ * XXX: We should really check that the inode gid is not in /any/ -+ * of the user's groups, but FUSE only tells us about the primary -+ * group. -+ */ -+ if (ctxt->uid != 0 && ctxt->gid != inode.i_gid) -+ mode &= ~S_ISGID; -+ -+ inode.i_mode &= ~0xFFF; -+ inode.i_mode |= mode & 0xFFF; -+ ret = update_ctime(fs, ino, &inode); -+ if (ret) -+ goto out; -+ -+ err = ext2fs_write_inode_full(fs, ino, (struct ext2_inode *)&inode, -+ sizeof(inode)); -+ if (err) { -+ ret = translate_error(fs, ino, err); -+ goto out; -+ } -+ -+out: -+ pthread_mutex_unlock(&ff->bfl); -+ return ret; -+} -+ -+static int op_chown(const char *path, uid_t owner, gid_t group) -+{ -+ struct fuse_context *ctxt = fuse_get_context(); -+ struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data; -+ ext2_filsys fs; -+ errcode_t err; -+ ext2_ino_t ino; -+ struct ext2_inode_large inode; -+ int ret = 0; -+ -+ FUSE2FS_CHECK_CONTEXT(ff); -+ fs = ff->fs; -+ pthread_mutex_lock(&ff->bfl); -+ err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, path, &ino); -+ if (err) { -+ ret = translate_error(fs, 0, err); -+ goto out; -+ } -+ dbg_printf("%s: path=%s owner=%d group=%d ino=%d\n", __func__, -+ path, owner, group, ino); -+ -+ memset(&inode, 0, sizeof(inode)); -+ err = ext2fs_read_inode_full(fs, ino, (struct ext2_inode *)&inode, -+ sizeof(inode)); -+ if (err) { -+ ret = translate_error(fs, ino, err); -+ goto out; -+ } -+ -+ /* FUSE seems to feed us ~0 to mean "don't change" */ -+ if (owner != (uid_t) ~0) { -+ /* Only root gets to change UID. */ -+ if (ctxt->uid != 0 && -+ !(inode.i_uid == ctxt->uid && owner == ctxt->uid)) { -+ ret = -EPERM; -+ goto out; -+ } -+ inode.i_uid = owner; -+ } -+ -+ if (group != (gid_t) ~0) { -+ /* Only root or the owner get to change GID. */ -+ if (ctxt->uid != 0 && inode.i_uid != ctxt->uid) { -+ ret = -EPERM; -+ goto out; -+ } -+ -+ /* XXX: We /should/ check group membership but FUSE */ -+ inode.i_gid = group; -+ } -+ -+ ret = update_ctime(fs, ino, &inode); -+ if (ret) -+ goto out; -+ -+ err = ext2fs_write_inode_full(fs, ino, (struct ext2_inode *)&inode, -+ sizeof(inode)); -+ if (err) { -+ ret = translate_error(fs, ino, err); -+ goto out; -+ } -+ -+out: -+ pthread_mutex_unlock(&ff->bfl); -+ return ret; -+} -+ -+static int op_truncate(const char *path, off_t len) -+{ -+ struct fuse_context *ctxt = fuse_get_context(); -+ struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data; -+ ext2_filsys fs; -+ errcode_t err; -+ ext2_ino_t ino; -+ ext2_file_t file; -+ int ret = 0; -+ -+ FUSE2FS_CHECK_CONTEXT(ff); -+ fs = ff->fs; -+ pthread_mutex_lock(&ff->bfl); -+ err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, path, &ino); -+ if (err || ino == 0) { -+ ret = translate_error(fs, 0, err); -+ goto out; -+ } -+ dbg_printf("%s: ino=%d len=%jd\n", __func__, ino, len); -+ -+ ret = check_inum_access(fs, ino, W_OK); -+ if (ret) -+ goto out; -+ -+ err = ext2fs_file_open(fs, ino, EXT2_FILE_WRITE, &file); -+ if (err) { -+ ret = translate_error(fs, ino, err); -+ goto out; -+ } -+ -+ err = ext2fs_file_set_size2(file, len); -+ if (err) { -+ ret = translate_error(fs, ino, err); -+ goto out2; -+ } -+ -+out2: -+ err = ext2fs_file_close(file); -+ if (ret) -+ goto out; -+ if (err) { -+ ret = translate_error(fs, ino, err); -+ goto out; -+ } -+ -+ ret = update_mtime(fs, ino, NULL); -+ -+out: -+ pthread_mutex_unlock(&ff->bfl); -+ return err; -+} -+ -+#ifdef __linux__ -+static void detect_linux_executable_open(int kernel_flags, int *access_check, -+ int *e2fs_open_flags) -+{ -+ /* -+ * On Linux, execve will bleed __FMODE_EXEC into the file mode flags, -+ * and FUSE is more than happy to let that slip through. -+ */ -+ if (kernel_flags & 0x20) { -+ *access_check = X_OK; -+ *e2fs_open_flags &= ~EXT2_FILE_WRITE; -+ } -+} -+#else -+static void detect_linux_executable_open(int kernel_flags, int *access_check, -+ int *e2fs_open_flags) -+{ -+ /* empty */ -+} -+#endif /* __linux__ */ -+ -+static int __op_open(struct fuse2fs *ff, const char *path, -+ struct fuse_file_info *fp) -+{ -+ ext2_filsys fs = ff->fs; -+ errcode_t err; -+ struct fuse2fs_file_handle *file; -+ int check = 0, ret = 0; -+ -+ dbg_printf("%s: path=%s\n", __func__, path); -+ err = ext2fs_get_mem(sizeof(*file), &file); -+ if (err) -+ return translate_error(fs, 0, err); -+ file->magic = FUSE2FS_FILE_MAGIC; -+ -+ file->open_flags = 0; -+ switch (fp->flags & O_ACCMODE) { -+ case O_RDONLY: -+ check = R_OK; -+ break; -+ case O_WRONLY: -+ check = W_OK; -+ file->open_flags |= EXT2_FILE_WRITE; -+ break; -+ case O_RDWR: -+ check = R_OK | W_OK; -+ file->open_flags |= EXT2_FILE_WRITE; -+ break; -+ } -+ -+ detect_linux_executable_open(fp->flags, &check, &file->open_flags); -+ -+ if (fp->flags & O_CREAT) -+ file->open_flags |= EXT2_FILE_CREATE; -+ -+ err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, path, &file->ino); -+ if (err || file->ino == 0) { -+ ret = translate_error(fs, 0, err); -+ goto out; -+ } -+ dbg_printf("%s: ino=%d\n", __func__, file->ino); -+ -+ ret = check_inum_access(fs, file->ino, check); -+ if (ret) { -+ /* -+ * In a regular (Linux) fs driver, the kernel will open -+ * binaries for reading if the user has --x privileges (i.e. -+ * execute without read). Since the kernel doesn't have any -+ * way to tell us if it's opening a file via execve, we'll -+ * just assume that allowing access is ok if asking for ro mode -+ * fails but asking for x mode succeeds. Of course we can -+ * also employ undocumented hacks (see above). -+ */ -+ if (check == R_OK) { -+ ret = check_inum_access(fs, file->ino, X_OK); -+ if (ret) -+ goto out; -+ } else -+ goto out; -+ } -+ fp->fh = (uint64_t)file; -+ -+out: -+ if (ret) -+ ext2fs_free_mem(&file); -+ return ret; -+} -+ -+static int op_open(const char *path, struct fuse_file_info *fp) -+{ -+ struct fuse_context *ctxt = fuse_get_context(); -+ struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data; -+ int ret; -+ -+ FUSE2FS_CHECK_CONTEXT(ff); -+ pthread_mutex_lock(&ff->bfl); -+ ret = __op_open(ff, path, fp); -+ pthread_mutex_unlock(&ff->bfl); -+ return ret; -+} -+ -+static int op_read(const char *path EXT2FS_ATTR((unused)), char *buf, -+ size_t len, off_t offset, -+ struct fuse_file_info *fp) -+{ -+ struct fuse_context *ctxt = fuse_get_context(); -+ struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data; -+ struct fuse2fs_file_handle *fh = (struct fuse2fs_file_handle *)fp->fh; -+ ext2_filsys fs; -+ ext2_file_t efp; -+ errcode_t err; -+ unsigned int got = 0; -+ int ret = 0; -+ -+ FUSE2FS_CHECK_CONTEXT(ff); -+ fs = ff->fs; -+ FUSE2FS_CHECK_MAGIC(fs, fh, FUSE2FS_FILE_MAGIC); -+ dbg_printf("%s: ino=%d off=%jd len=%jd\n", __func__, fh->ino, offset, -+ len); -+ pthread_mutex_lock(&ff->bfl); -+ err = ext2fs_file_open(fs, fh->ino, fh->open_flags, &efp); -+ if (err) { -+ ret = translate_error(fs, fh->ino, err); -+ goto out; -+ } -+ -+ err = ext2fs_file_llseek(efp, offset, SEEK_SET, NULL); -+ if (err) { -+ ret = translate_error(fs, fh->ino, err); -+ goto out2; -+ } -+ -+ err = ext2fs_file_read(efp, buf, len, &got); -+ if (err) { -+ ret = translate_error(fs, fh->ino, err); -+ goto out2; -+ } -+ -+out2: -+ err = ext2fs_file_close(efp); -+ if (ret) -+ goto out; -+ if (err) { -+ ret = translate_error(fs, fh->ino, err); -+ goto out; -+ } -+ -+ if (fs_writeable(fs)) { -+ ret = update_atime(fs, fh->ino); -+ if (ret) -+ goto out; -+ } -+out: -+ pthread_mutex_unlock(&ff->bfl); -+ return got ? (int) got : ret; -+} -+ -+static int op_write(const char *path EXT2FS_ATTR((unused)), -+ const char *buf, size_t len, off_t offset, -+ struct fuse_file_info *fp) -+{ -+ struct fuse_context *ctxt = fuse_get_context(); -+ struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data; -+ struct fuse2fs_file_handle *fh = (struct fuse2fs_file_handle *)fp->fh; -+ ext2_filsys fs; -+ ext2_file_t efp; -+ errcode_t err; -+ unsigned int got = 0; -+ int ret = 0; -+ -+ FUSE2FS_CHECK_CONTEXT(ff); -+ fs = ff->fs; -+ FUSE2FS_CHECK_MAGIC(fs, fh, FUSE2FS_FILE_MAGIC); -+ dbg_printf("%s: ino=%d off=%jd len=%jd\n", __func__, fh->ino, offset, -+ len); -+ pthread_mutex_lock(&ff->bfl); -+ if (!fs_writeable(fs)) { -+ ret = -EROFS; -+ goto out; -+ } -+ -+ if (!fs_can_allocate(ff, len / fs->blocksize)) { -+ ret = -ENOSPC; -+ goto out; -+ } -+ -+ err = ext2fs_file_open(fs, fh->ino, fh->open_flags, &efp); -+ if (err) { -+ ret = translate_error(fs, fh->ino, err); -+ goto out; -+ } -+ -+ err = ext2fs_file_llseek(efp, offset, SEEK_SET, NULL); -+ if (err) { -+ ret = translate_error(fs, fh->ino, err); -+ goto out2; -+ } -+ -+ err = ext2fs_file_write(efp, buf, len, &got); -+ if (err) { -+ ret = translate_error(fs, fh->ino, err); -+ goto out2; -+ } -+ -+ err = ext2fs_file_flush(efp); -+ if (err) { -+ got = 0; -+ ret = translate_error(fs, fh->ino, err); -+ goto out2; -+ } -+ -+out2: -+ err = ext2fs_file_close(efp); -+ if (ret) -+ goto out; -+ if (err) { -+ ret = translate_error(fs, fh->ino, err); -+ goto out; -+ } -+ -+ ret = update_mtime(fs, fh->ino, NULL); -+ if (ret) -+ goto out; -+ -+out: -+ pthread_mutex_unlock(&ff->bfl); -+ return got ? (int) got : ret; -+} -+ -+static int op_release(const char *path EXT2FS_ATTR((unused)), -+ struct fuse_file_info *fp) -+{ -+ struct fuse_context *ctxt = fuse_get_context(); -+ struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data; -+ struct fuse2fs_file_handle *fh = (struct fuse2fs_file_handle *)fp->fh; -+ ext2_filsys fs; -+ errcode_t err; -+ int ret = 0; -+ -+ FUSE2FS_CHECK_CONTEXT(ff); -+ fs = ff->fs; -+ FUSE2FS_CHECK_MAGIC(fs, fh, FUSE2FS_FILE_MAGIC); -+ dbg_printf("%s: ino=%d\n", __func__, fh->ino); -+ pthread_mutex_lock(&ff->bfl); -+ if (fs_writeable(fs) && fh->open_flags & EXT2_FILE_WRITE) { -+ err = ext2fs_flush2(fs, EXT2_FLAG_FLUSH_NO_SYNC); -+ if (err) -+ ret = translate_error(fs, fh->ino, err); -+ } -+ fp->fh = 0; -+ pthread_mutex_unlock(&ff->bfl); -+ -+ ext2fs_free_mem(&fh); -+ -+ return ret; -+} -+ -+static int op_fsync(const char *path EXT2FS_ATTR((unused)), -+ int datasync EXT2FS_ATTR((unused)), -+ struct fuse_file_info *fp) -+{ -+ struct fuse_context *ctxt = fuse_get_context(); -+ struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data; -+ struct fuse2fs_file_handle *fh = (struct fuse2fs_file_handle *)fp->fh; -+ ext2_filsys fs; -+ errcode_t err; -+ int ret = 0; -+ -+ FUSE2FS_CHECK_CONTEXT(ff); -+ fs = ff->fs; -+ FUSE2FS_CHECK_MAGIC(fs, fh, FUSE2FS_FILE_MAGIC); -+ dbg_printf("%s: ino=%d\n", __func__, fh->ino); -+ /* For now, flush everything, even if it's slow */ -+ pthread_mutex_lock(&ff->bfl); -+ if (fs_writeable(fs) && fh->open_flags & EXT2_FILE_WRITE) { -+ err = ext2fs_flush2(fs, 0); -+ if (err) -+ ret = translate_error(fs, fh->ino, err); -+ } -+ pthread_mutex_unlock(&ff->bfl); -+ -+ return ret; -+} -+ -+static int op_statfs(const char *path EXT2FS_ATTR((unused)), -+ struct statvfs *buf) -+{ -+ struct fuse_context *ctxt = fuse_get_context(); -+ struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data; -+ ext2_filsys fs; -+ uint64_t fsid, *f; -+ blk64_t overhead, reserved, free; -+ -+ FUSE2FS_CHECK_CONTEXT(ff); -+ fs = ff->fs; -+ dbg_printf("%s: path=%s\n", __func__, path); -+ buf->f_bsize = fs->blocksize; -+ buf->f_frsize = 0; -+ -+ if (ff->minixdf) -+ overhead = 0; -+ else -+ overhead = fs->desc_blocks + -+ fs->group_desc_count * -+ (fs->inode_blocks_per_group + 2); -+ reserved = ext2fs_r_blocks_count(fs->super); -+ if (!reserved) -+ reserved = ext2fs_blocks_count(fs->super) / 10; -+ free = ext2fs_free_blocks_count(fs->super); -+ -+ buf->f_blocks = ext2fs_blocks_count(fs->super) - overhead; -+ buf->f_bfree = free; -+ if (free < reserved) -+ buf->f_bavail = 0; -+ else -+ buf->f_bavail = free - reserved; -+ buf->f_files = fs->super->s_inodes_count; -+ buf->f_ffree = fs->super->s_free_inodes_count; -+ buf->f_favail = fs->super->s_free_inodes_count; -+ f = (uint64_t *)fs->super->s_uuid; -+ fsid = *f; -+ f++; -+ fsid ^= *f; -+ buf->f_fsid = fsid; -+ buf->f_flag = 0; -+ if (fs->flags & EXT2_FLAG_RW) -+ buf->f_flag |= ST_RDONLY; -+ buf->f_namemax = EXT2_NAME_LEN; -+ -+ return 0; -+} -+ -+typedef errcode_t (*xattr_xlate_get)(void **cooked_buf, size_t *cooked_sz, -+ const void *raw_buf, size_t raw_sz); -+typedef errcode_t (*xattr_xlate_set)(const void *cooked_buf, size_t cooked_sz, -+ const void **raw_buf, size_t *raw_sz); -+struct xattr_translate { -+ const char *prefix; -+ xattr_xlate_get get; -+ xattr_xlate_set set; -+}; -+ -+#define XATTR_TRANSLATOR(p, g, s) \ -+ {.prefix = (p), \ -+ .get = (xattr_xlate_get)(g), \ -+ .set = (xattr_xlate_set)(s)} -+ -+static struct xattr_translate xattr_translators[] = { -+#ifdef TRANSLATE_LINUX_ACLS -+ XATTR_TRANSLATOR(ACL_EA_ACCESS, ext4_to_fuse_acl, fuse_to_ext4_acl), -+ XATTR_TRANSLATOR(ACL_EA_DEFAULT, ext4_to_fuse_acl, fuse_to_ext4_acl), -+#endif -+ XATTR_TRANSLATOR(NULL, NULL, NULL), -+}; -+#undef XATTR_TRANSLATOR -+ -+static int op_getxattr(const char *path, const char *key, char *value, -+ size_t len) -+{ -+ struct fuse_context *ctxt = fuse_get_context(); -+ struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data; -+ ext2_filsys fs; -+ struct ext2_xattr_handle *h; -+ struct xattr_translate *xt; -+ void *ptr, *cptr; -+ size_t plen, clen; -+ ext2_ino_t ino; -+ errcode_t err; -+ int ret = 0; -+ -+ FUSE2FS_CHECK_CONTEXT(ff); -+ fs = ff->fs; -+ pthread_mutex_lock(&ff->bfl); -+ if (!EXT2_HAS_COMPAT_FEATURE(fs->super, -+ EXT2_FEATURE_COMPAT_EXT_ATTR)) { -+ ret = -ENOTSUP; -+ goto out; -+ } -+ -+ err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, path, &ino); -+ if (err || ino == 0) { -+ ret = translate_error(fs, 0, err); -+ goto out; -+ } -+ dbg_printf("%s: ino=%d\n", __func__, ino); -+ -+ ret = check_inum_access(fs, ino, R_OK); -+ if (ret) -+ goto out; -+ -+ err = ext2fs_xattrs_open(fs, ino, &h); -+ if (err) { -+ ret = translate_error(fs, ino, err); -+ goto out; -+ } -+ -+ err = ext2fs_xattrs_read(h); -+ if (err) { -+ ret = translate_error(fs, ino, err); -+ goto out2; -+ } -+ -+ err = ext2fs_xattr_get(h, key, &ptr, &plen); -+ if (err) { -+ ret = translate_error(fs, ino, err); -+ goto out2; -+ } -+ -+ for (xt = xattr_translators; xt->prefix != NULL; xt++) { -+ if (strncmp(key, xt->prefix, strlen(xt->prefix)) == 0) { -+ err = xt->get(&cptr, &clen, ptr, plen); -+ if (err) -+ goto out3; -+ ext2fs_free_mem(&ptr); -+ ptr = cptr; -+ plen = clen; -+ } -+ } -+ -+ if (!len) { -+ ret = plen; -+ } else if (len < plen) { -+ ret = -ERANGE; -+ } else { -+ memcpy(value, ptr, plen); -+ ret = plen; -+ } -+ -+out3: -+ ext2fs_free_mem(&ptr); -+out2: -+ err = ext2fs_xattrs_close(&h); -+ if (err) -+ ret = translate_error(fs, ino, err); -+out: -+ pthread_mutex_unlock(&ff->bfl); -+ -+ return ret; -+} -+ -+static int count_buffer_space(char *name, char *value EXT2FS_ATTR((unused)), -+ size_t value_len EXT2FS_ATTR((unused)), -+ void *data) -+{ -+ unsigned int *x = data; -+ -+ *x = *x + strlen(name) + 1; -+ return 0; -+} -+ -+static int copy_names(char *name, char *value EXT2FS_ATTR((unused)), -+ size_t value_len EXT2FS_ATTR((unused)), void *data) -+{ -+ char **b = data; -+ -+ strncpy(*b, name, strlen(name)); -+ *b = *b + strlen(name) + 1; -+ -+ return 0; -+} -+ -+static int op_listxattr(const char *path, char *names, size_t len) -+{ -+ struct fuse_context *ctxt = fuse_get_context(); -+ struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data; -+ ext2_filsys fs; -+ struct ext2_xattr_handle *h; -+ unsigned int bufsz; -+ ext2_ino_t ino; -+ errcode_t err; -+ int ret = 0; -+ -+ FUSE2FS_CHECK_CONTEXT(ff); -+ fs = ff->fs; -+ pthread_mutex_lock(&ff->bfl); -+ if (!EXT2_HAS_COMPAT_FEATURE(fs->super, -+ EXT2_FEATURE_COMPAT_EXT_ATTR)) { -+ ret = -ENOTSUP; -+ goto out; -+ } -+ -+ err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, path, &ino); -+ if (err || ino == 0) { -+ ret = translate_error(fs, ino, err); -+ goto out; -+ } -+ dbg_printf("%s: ino=%d\n", __func__, ino); -+ -+ ret = check_inum_access(fs, ino, R_OK); -+ if (ret) -+ goto out2; -+ -+ err = ext2fs_xattrs_open(fs, ino, &h); -+ if (err) { -+ ret = translate_error(fs, ino, err); -+ goto out; -+ } -+ -+ err = ext2fs_xattrs_read(h); -+ if (err) { -+ ret = translate_error(fs, ino, err); -+ goto out2; -+ } -+ -+ /* Count buffer space needed for names */ -+ bufsz = 0; -+ err = ext2fs_xattrs_iterate(h, count_buffer_space, &bufsz); -+ if (err) { -+ ret = translate_error(fs, ino, err); -+ goto out2; -+ } -+ -+ if (len == 0) { -+ ret = bufsz; -+ goto out2; -+ } else if (len < bufsz) { -+ ret = -ERANGE; -+ goto out2; -+ } -+ -+ /* Copy names out */ -+ memset(names, 0, len); -+ err = ext2fs_xattrs_iterate(h, copy_names, &names); -+ if (err) { -+ ret = translate_error(fs, ino, err); -+ goto out2; -+ } -+ ret = bufsz; -+out2: -+ err = ext2fs_xattrs_close(&h); -+ if (err) -+ ret = translate_error(fs, ino, err); -+out: -+ pthread_mutex_unlock(&ff->bfl); -+ -+ return ret; -+} -+ -+static int op_setxattr(const char *path EXT2FS_ATTR((unused)), -+ const char *key, const char *value, -+ size_t len, int flags EXT2FS_ATTR((unused))) -+{ -+ struct fuse_context *ctxt = fuse_get_context(); -+ struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data; -+ ext2_filsys fs; -+ struct ext2_xattr_handle *h; -+ struct xattr_translate *xt; -+ const void *cvalue; -+ size_t clen; -+ ext2_ino_t ino; -+ errcode_t err; -+ int ret = 0; -+ -+ FUSE2FS_CHECK_CONTEXT(ff); -+ fs = ff->fs; -+ pthread_mutex_lock(&ff->bfl); -+ if (!EXT2_HAS_COMPAT_FEATURE(fs->super, -+ EXT2_FEATURE_COMPAT_EXT_ATTR)) { -+ ret = -ENOTSUP; -+ goto out; -+ } -+ -+ err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, path, &ino); -+ if (err || ino == 0) { -+ ret = translate_error(fs, 0, err); -+ goto out; -+ } -+ dbg_printf("%s: ino=%d\n", __func__, ino); -+ -+ ret = check_inum_access(fs, ino, W_OK); -+ if (ret == -EACCES) { -+ ret = -EPERM; -+ goto out; -+ } else if (ret) -+ goto out; -+ -+ err = ext2fs_xattrs_open(fs, ino, &h); -+ if (err) { -+ ret = translate_error(fs, ino, err); -+ goto out; -+ } -+ -+ err = ext2fs_xattrs_read(h); -+ if (err) { -+ ret = translate_error(fs, ino, err); -+ goto out2; -+ } -+ -+ cvalue = value; -+ clen = len; -+ for (xt = xattr_translators; xt->prefix != NULL; xt++) { -+ if (strncmp(key, xt->prefix, strlen(xt->prefix)) == 0) { -+ err = xt->set(value, len, &cvalue, &clen); -+ if (err) -+ goto out3; -+ } -+ } -+ -+ err = ext2fs_xattr_set(h, key, cvalue, clen); -+ if (err) { -+ ret = translate_error(fs, ino, err); -+ goto out3; -+ } -+ -+ err = ext2fs_xattrs_write(h); -+ if (err) { -+ ret = translate_error(fs, ino, err); -+ goto out3; -+ } -+ -+ ret = update_ctime(fs, ino, NULL); -+out3: -+ if (cvalue != value) -+ ext2fs_free_mem(&cvalue); -+out2: -+ err = ext2fs_xattrs_close(&h); -+ if (!ret && err) -+ ret = translate_error(fs, ino, err); -+out: -+ pthread_mutex_unlock(&ff->bfl); -+ -+ return ret; -+} -+ -+static int op_removexattr(const char *path, const char *key) -+{ -+ struct fuse_context *ctxt = fuse_get_context(); -+ struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data; -+ ext2_filsys fs; -+ struct ext2_xattr_handle *h; -+ ext2_ino_t ino; -+ errcode_t err; -+ int ret = 0; -+ -+ FUSE2FS_CHECK_CONTEXT(ff); -+ fs = ff->fs; -+ pthread_mutex_lock(&ff->bfl); -+ if (!EXT2_HAS_COMPAT_FEATURE(fs->super, -+ EXT2_FEATURE_COMPAT_EXT_ATTR)) { -+ ret = -ENOTSUP; -+ goto out; -+ } -+ -+ if (!fs_can_allocate(ff, 1)) { -+ ret = -ENOSPC; -+ goto out; -+ } -+ -+ err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, path, &ino); -+ if (err || ino == 0) { -+ ret = translate_error(fs, 0, err); -+ goto out; -+ } -+ dbg_printf("%s: ino=%d\n", __func__, ino); -+ -+ ret = check_inum_access(fs, ino, W_OK); -+ if (ret) -+ goto out; -+ -+ err = ext2fs_xattrs_open(fs, ino, &h); -+ if (err) { -+ ret = translate_error(fs, ino, err); -+ goto out; -+ } -+ -+ err = ext2fs_xattrs_read(h); -+ if (err) { -+ ret = translate_error(fs, ino, err); -+ goto out2; -+ } -+ -+ err = ext2fs_xattr_remove(h, key); -+ if (err) { -+ ret = translate_error(fs, ino, err); -+ goto out2; -+ } -+ -+ err = ext2fs_xattrs_write(h); -+ if (err) { -+ ret = translate_error(fs, ino, err); -+ goto out2; -+ } -+ -+ ret = update_ctime(fs, ino, NULL); -+out2: -+ err = ext2fs_xattrs_close(&h); -+ if (err) -+ ret = translate_error(fs, ino, err); -+out: -+ pthread_mutex_unlock(&ff->bfl); -+ -+ return ret; -+} -+ -+struct readdir_iter { -+ void *buf; -+ fuse_fill_dir_t func; -+}; -+ -+static int op_readdir_iter(ext2_ino_t dir EXT2FS_ATTR((unused)), -+ int entry EXT2FS_ATTR((unused)), -+ struct ext2_dir_entry *dirent, -+ int offset EXT2FS_ATTR((unused)), -+ int blocksize EXT2FS_ATTR((unused)), -+ char *buf EXT2FS_ATTR((unused)), void *data) -+{ -+ struct readdir_iter *i = data; -+ char namebuf[EXT2_NAME_LEN + 1]; -+ int ret; -+ -+ memcpy(namebuf, dirent->name, dirent->name_len & 0xFF); -+ namebuf[dirent->name_len & 0xFF] = 0; -+ ret = i->func(i->buf, namebuf, NULL, 0); -+ if (ret) -+ return DIRENT_ABORT; -+ -+ return 0; -+} -+ -+static int op_readdir(const char *path EXT2FS_ATTR((unused)), -+ void *buf, fuse_fill_dir_t fill_func, -+ off_t offset EXT2FS_ATTR((unused)), -+ struct fuse_file_info *fp) -+{ -+ struct fuse_context *ctxt = fuse_get_context(); -+ struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data; -+ struct fuse2fs_file_handle *fh = (struct fuse2fs_file_handle *)fp->fh; -+ ext2_filsys fs; -+ errcode_t err; -+ struct readdir_iter i; -+ int ret = 0; -+ -+ FUSE2FS_CHECK_CONTEXT(ff); -+ fs = ff->fs; -+ FUSE2FS_CHECK_MAGIC(fs, fh, FUSE2FS_FILE_MAGIC); -+ dbg_printf("%s: ino=%d\n", __func__, fh->ino); -+ pthread_mutex_lock(&ff->bfl); -+ i.buf = buf; -+ i.func = fill_func; -+ err = ext2fs_dir_iterate2(fs, fh->ino, 0, NULL, op_readdir_iter, &i); -+ if (err) { -+ ret = translate_error(fs, fh->ino, err); -+ goto out; -+ } -+ -+ if (fs_writeable(fs)) { -+ ret = update_atime(fs, fh->ino); -+ if (ret) -+ goto out; -+ } -+out: -+ pthread_mutex_unlock(&ff->bfl); -+ return ret; -+} -+ -+static int op_access(const char *path, int mask) -+{ -+ struct fuse_context *ctxt = fuse_get_context(); -+ struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data; -+ ext2_filsys fs; -+ errcode_t err; -+ ext2_ino_t ino; -+ int ret = 0; -+ -+ FUSE2FS_CHECK_CONTEXT(ff); -+ fs = ff->fs; -+ dbg_printf("%s: path=%s mask=0x%x\n", __func__, path, mask); -+ pthread_mutex_lock(&ff->bfl); -+ err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, path, &ino); -+ if (err || ino == 0) { -+ ret = translate_error(fs, 0, err); -+ goto out; -+ } -+ -+ ret = check_inum_access(fs, ino, mask); -+ if (ret) -+ goto out; -+ -+out: -+ pthread_mutex_unlock(&ff->bfl); -+ return ret; -+} -+ -+static int op_create(const char *path, mode_t mode, struct fuse_file_info *fp) -+{ -+ struct fuse_context *ctxt = fuse_get_context(); -+ struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data; -+ ext2_filsys fs; -+ ext2_ino_t parent, child; -+ char *temp_path = strdup(path); -+ errcode_t err; -+ char *node_name, a; -+ int filetype; -+ struct ext2_inode_large inode; -+ int ret = 0; -+ -+ FUSE2FS_CHECK_CONTEXT(ff); -+ fs = ff->fs; -+ dbg_printf("%s: path=%s mode=0%o\n", __func__, path, mode); -+ if (!temp_path) { -+ ret = -ENOMEM; -+ goto out; -+ } -+ node_name = strrchr(temp_path, '/'); -+ if (!node_name) { -+ ret = -ENOMEM; -+ goto out; -+ } -+ node_name++; -+ a = *node_name; -+ *node_name = 0; -+ -+ pthread_mutex_lock(&ff->bfl); -+ if (!fs_can_allocate(ff, 1)) { -+ ret = -ENOSPC; -+ goto out2; -+ } -+ -+ err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, temp_path, -+ &parent); -+ if (err) { -+ ret = translate_error(fs, 0, err); -+ goto out2; -+ } -+ -+ ret = check_inum_access(fs, parent, W_OK); -+ if (ret) -+ goto out2; -+ -+ *node_name = a; -+ -+ filetype = ext2_file_type(mode); -+ -+ err = ext2fs_new_inode(fs, parent, mode, 0, &child); -+ if (err) { -+ ret = translate_error(fs, parent, err); -+ goto out2; -+ } -+ -+ dbg_printf("%s: creating ino=%d/name=%s in dir=%d\n", __func__, child, -+ node_name, parent); -+ err = ext2fs_link(fs, parent, node_name, child, filetype); -+ if (err == EXT2_ET_DIR_NO_SPACE) { -+ err = ext2fs_expand_dir(fs, parent); -+ if (err) { -+ ret = translate_error(fs, parent, err); -+ goto out2; -+ } -+ -+ err = ext2fs_link(fs, parent, node_name, child, -+ filetype); -+ } -+ if (err) { -+ ret = translate_error(fs, parent, err); -+ goto out2; -+ } -+ -+ ret = update_mtime(fs, parent, NULL); -+ if (ret) -+ goto out2; -+ -+ memset(&inode, 0, sizeof(inode)); -+ inode.i_mode = mode; -+ inode.i_links_count = 1; -+ inode.i_extra_isize = sizeof(struct ext2_inode_large) - -+ EXT2_GOOD_OLD_INODE_SIZE; -+ if (fs->super->s_feature_incompat & EXT3_FEATURE_INCOMPAT_EXTENTS) { -+ ext2_extent_handle_t handle; -+ -+ inode.i_flags &= ~EXT4_EXTENTS_FL; -+ ret = ext2fs_extent_open2(fs, child, -+ (struct ext2_inode *)&inode, &handle); -+ if (ret) -+ return ret; -+ ext2fs_extent_free(handle); -+ } -+ -+ err = ext2fs_write_new_inode(fs, child, (struct ext2_inode *)&inode); -+ if (err) { -+ ret = translate_error(fs, child, err); -+ goto out2; -+ } -+ -+ inode.i_generation = ff->next_generation++; -+ init_times(&inode); -+ err = ext2fs_write_inode_full(fs, child, (struct ext2_inode *)&inode, -+ sizeof(inode)); -+ if (err) { -+ ret = translate_error(fs, child, err); -+ goto out2; -+ } -+ -+ ext2fs_inode_alloc_stats2(fs, child, 1, 0); -+ -+ ret = __op_open(ff, path, fp); -+ if (ret) -+ goto out2; -+out2: -+ pthread_mutex_unlock(&ff->bfl); -+out: -+ free(temp_path); -+ return ret; -+} -+ -+static int op_ftruncate(const char *path EXT2FS_ATTR((unused)), -+ off_t len, struct fuse_file_info *fp) -+{ -+ struct fuse_context *ctxt = fuse_get_context(); -+ struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data; -+ struct fuse2fs_file_handle *fh = (struct fuse2fs_file_handle *)fp->fh; -+ ext2_filsys fs; -+ ext2_file_t efp; -+ errcode_t err; -+ int ret = 0; -+ -+ FUSE2FS_CHECK_CONTEXT(ff); -+ fs = ff->fs; -+ FUSE2FS_CHECK_MAGIC(fs, fh, FUSE2FS_FILE_MAGIC); -+ dbg_printf("%s: ino=%d len=%jd\n", __func__, fh->ino, len); -+ pthread_mutex_lock(&ff->bfl); -+ if (!fs_writeable(fs)) { -+ ret = -EROFS; -+ goto out; -+ } -+ -+ err = ext2fs_file_open(fs, fh->ino, fh->open_flags, &efp); -+ if (err) { -+ ret = translate_error(fs, fh->ino, err); -+ goto out; -+ } -+ -+ err = ext2fs_file_set_size2(efp, len); -+ if (err) { -+ ret = translate_error(fs, fh->ino, err); -+ goto out2; -+ } -+ -+out2: -+ err = ext2fs_file_close(efp); -+ if (ret) -+ goto out; -+ if (err) { -+ ret = translate_error(fs, fh->ino, err); -+ goto out; -+ } -+ -+ ret = update_mtime(fs, fh->ino, NULL); -+ if (ret) -+ goto out; -+ -+out: -+ pthread_mutex_unlock(&ff->bfl); -+ return 0; -+} -+ -+static int op_fgetattr(const char *path EXT2FS_ATTR((unused)), -+ struct stat *statbuf, -+ struct fuse_file_info *fp) -+{ -+ struct fuse_context *ctxt = fuse_get_context(); -+ struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data; -+ ext2_filsys fs; -+ struct fuse2fs_file_handle *fh = (struct fuse2fs_file_handle *)fp->fh; -+ int ret = 0; -+ -+ FUSE2FS_CHECK_CONTEXT(ff); -+ fs = ff->fs; -+ FUSE2FS_CHECK_MAGIC(fs, fh, FUSE2FS_FILE_MAGIC); -+ dbg_printf("%s: ino=%d\n", __func__, fh->ino); -+ pthread_mutex_lock(&ff->bfl); -+ ret = stat_inode(fs, fh->ino, statbuf); -+ pthread_mutex_unlock(&ff->bfl); -+ -+ return ret; -+} -+ -+static int op_utimens(const char *path, const struct timespec ctv[2]) -+{ -+ struct fuse_context *ctxt = fuse_get_context(); -+ struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data; -+ struct timespec tv[2]; -+ ext2_filsys fs; -+ errcode_t err; -+ ext2_ino_t ino; -+ struct ext2_inode_large inode; -+ int ret = 0; -+ -+ FUSE2FS_CHECK_CONTEXT(ff); -+ fs = ff->fs; -+ pthread_mutex_lock(&ff->bfl); -+ err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, path, &ino); -+ if (err) { -+ ret = translate_error(fs, 0, err); -+ goto out; -+ } -+ dbg_printf("%s: ino=%d\n", __func__, ino); -+ -+ ret = check_inum_access(fs, ino, W_OK); -+ if (ret) -+ goto out; -+ -+ memset(&inode, 0, sizeof(inode)); -+ err = ext2fs_read_inode_full(fs, ino, (struct ext2_inode *)&inode, -+ sizeof(inode)); -+ if (err) { -+ ret = translate_error(fs, ino, err); -+ goto out; -+ } -+ -+ tv[0] = ctv[0]; -+ tv[1] = ctv[1]; -+#ifdef UTIME_NOW -+ if (tv[0].tv_nsec == UTIME_NOW) -+ get_now(tv); -+ if (tv[1].tv_nsec == UTIME_NOW) -+ get_now(tv + 1); -+#endif /* UTIME_NOW */ -+#ifdef UTIME_OMIT -+ if (tv[0].tv_nsec != UTIME_OMIT) -+ EXT4_INODE_SET_XTIME(i_atime, tv, &inode); -+ if (tv[1].tv_nsec != UTIME_OMIT) -+ EXT4_INODE_SET_XTIME(i_mtime, tv + 1, &inode); -+#endif /* UTIME_OMIT */ -+ ret = update_ctime(fs, ino, &inode); -+ if (ret) -+ goto out; -+ -+ err = ext2fs_write_inode_full(fs, ino, (struct ext2_inode *)&inode, -+ sizeof(inode)); -+ if (err) { -+ ret = translate_error(fs, ino, err); -+ goto out; -+ } -+ -+out: -+ pthread_mutex_unlock(&ff->bfl); -+ return ret; -+} -+ -+#ifdef SUPPORT_I_FLAGS -+static int ioctl_getflags(ext2_filsys fs, struct fuse2fs_file_handle *fh, -+ void *data) -+{ -+ errcode_t err; -+ struct ext2_inode_large inode; -+ -+ FUSE2FS_CHECK_MAGIC(fs, fh, FUSE2FS_FILE_MAGIC); -+ dbg_printf("%s: ino=%d\n", __func__, fh->ino); -+ memset(&inode, 0, sizeof(inode)); -+ err = ext2fs_read_inode_full(fs, fh->ino, (struct ext2_inode *)&inode, -+ sizeof(inode)); -+ if (err) -+ return translate_error(fs, fh->ino, err); -+ -+ *(__u32 *)data = inode.i_flags & EXT2_FL_USER_VISIBLE; -+ return 0; -+} -+ -+#define FUSE2FS_MODIFIABLE_IFLAGS \ -+ (EXT2_IMMUTABLE_FL | EXT2_APPEND_FL | EXT2_NODUMP_FL | \ -+ EXT2_NOATIME_FL | EXT3_JOURNAL_DATA_FL | EXT2_DIRSYNC_FL | \ -+ EXT2_TOPDIR_FL) -+ -+static int ioctl_setflags(ext2_filsys fs, struct fuse2fs_file_handle *fh, -+ void *data) -+{ -+ errcode_t err; -+ struct ext2_inode_large inode; -+ int ret; -+ __u32 flags = *(__u32 *)data; -+ struct fuse_context *ctxt = fuse_get_context(); -+ -+ FUSE2FS_CHECK_MAGIC(fs, fh, FUSE2FS_FILE_MAGIC); -+ dbg_printf("%s: ino=%d\n", __func__, fh->ino); -+ memset(&inode, 0, sizeof(inode)); -+ err = ext2fs_read_inode_full(fs, fh->ino, (struct ext2_inode *)&inode, -+ sizeof(inode)); -+ if (err) -+ return translate_error(fs, fh->ino, err); -+ -+ if (ctxt->uid != 0 && inode.i_uid != ctxt->uid) -+ return -EPERM; -+ -+ if ((inode.i_flags ^ flags) & ~FUSE2FS_MODIFIABLE_IFLAGS) -+ return -EINVAL; -+ -+ inode.i_flags = (inode.i_flags & ~FUSE2FS_MODIFIABLE_IFLAGS) | -+ (flags & FUSE2FS_MODIFIABLE_IFLAGS); -+ -+ ret = update_ctime(fs, fh->ino, &inode); -+ if (ret) -+ return ret; -+ -+ err = ext2fs_write_inode_full(fs, fh->ino, (struct ext2_inode *)&inode, -+ sizeof(inode)); -+ if (err) -+ return translate_error(fs, fh->ino, err); -+ -+ return 0; -+} -+ -+static int ioctl_getversion(ext2_filsys fs, struct fuse2fs_file_handle *fh, -+ void *data) -+{ -+ errcode_t err; -+ struct ext2_inode_large inode; -+ -+ FUSE2FS_CHECK_MAGIC(fs, fh, FUSE2FS_FILE_MAGIC); -+ dbg_printf("%s: ino=%d\n", __func__, fh->ino); -+ memset(&inode, 0, sizeof(inode)); -+ err = ext2fs_read_inode_full(fs, fh->ino, (struct ext2_inode *)&inode, -+ sizeof(inode)); -+ if (err) -+ return translate_error(fs, fh->ino, err); -+ -+ *(__u32 *)data = inode.i_generation; -+ return 0; -+} -+ -+static int ioctl_setversion(ext2_filsys fs, struct fuse2fs_file_handle *fh, -+ void *data) -+{ -+ errcode_t err; -+ struct ext2_inode_large inode; -+ int ret; -+ __u32 generation = *(__u32 *)data; -+ struct fuse_context *ctxt = fuse_get_context(); -+ -+ FUSE2FS_CHECK_MAGIC(fs, fh, FUSE2FS_FILE_MAGIC); -+ dbg_printf("%s: ino=%d\n", __func__, fh->ino); -+ memset(&inode, 0, sizeof(inode)); -+ err = ext2fs_read_inode_full(fs, fh->ino, (struct ext2_inode *)&inode, -+ sizeof(inode)); -+ if (err) -+ return translate_error(fs, fh->ino, err); -+ -+ if (ctxt->uid != 0 && inode.i_uid != ctxt->uid) -+ return -EPERM; -+ -+ inode.i_generation = generation; -+ -+ ret = update_ctime(fs, fh->ino, &inode); -+ if (ret) -+ return ret; -+ -+ err = ext2fs_write_inode_full(fs, fh->ino, (struct ext2_inode *)&inode, -+ sizeof(inode)); -+ if (err) -+ return translate_error(fs, fh->ino, err); -+ -+ return 0; -+} -+#endif /* SUPPORT_I_FLAGS */ -+ -+#ifdef FITRIM -+static int ioctl_fitrim(ext2_filsys fs, struct fuse2fs_file_handle *fh, -+ void *data) -+{ -+ struct fstrim_range *fr = data; -+ blk64_t start, end, max_blocks, b, cleared; -+ errcode_t err = 0; -+ -+ start = fr->start / fs->blocksize; -+ end = (fr->start + fr->len - 1) / fs->blocksize; -+ dbg_printf("%s: start=%llu end=%llu\n", __func__, start, end); -+ -+ if (start < fs->super->s_first_data_block) -+ start = fs->super->s_first_data_block; -+ if (start >= ext2fs_blocks_count(fs->super)) -+ start = ext2fs_blocks_count(fs->super) - 1; -+ -+ if (end < fs->super->s_first_data_block) -+ end = fs->super->s_first_data_block; -+ if (end >= ext2fs_blocks_count(fs->super)) -+ end = ext2fs_blocks_count(fs->super) - 1; -+ -+ cleared = 0; -+ max_blocks = 2048ULL * 1024 * 1024 / fs->blocksize; -+ -+ fr->len = 0; -+ while (start <= end) { -+ err = ext2fs_find_first_zero_block_bitmap2(fs->block_map, -+ start, end, &start); -+ if (err == ENOENT) -+ return 0; -+ else if (err) -+ return translate_error(fs, fh->ino, err); -+ -+ b = start + max_blocks < end ? start + max_blocks : end; -+ err = ext2fs_find_first_set_block_bitmap2(fs->block_map, -+ start, b, &b); -+ if (err && err != ENOENT) -+ return translate_error(fs, fh->ino, err); -+ if (b - start >= fr->minlen) { -+ err = io_channel_discard(fs->io, start, b - start); -+ if (err) -+ return translate_error(fs, fh->ino, err); -+ cleared += b - start; -+ fr->len = cleared * fs->blocksize; -+ } -+ start = b + 1; -+ } -+ -+ return err; -+} -+#endif /* FITRIM */ -+ -+#if FUSE_VERSION >= FUSE_MAKE_VERSION(2, 8) -+static int op_ioctl(const char *path EXT2FS_ATTR((unused)), int cmd, -+ void *arg EXT2FS_ATTR((unused)), -+ struct fuse_file_info *fp, -+ unsigned int flags EXT2FS_ATTR((unused)), void *data) -+{ -+ struct fuse_context *ctxt = fuse_get_context(); -+ struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data; -+ struct fuse2fs_file_handle *fh = (struct fuse2fs_file_handle *)fp->fh; -+ ext2_filsys fs; -+ int ret = 0; -+ -+ FUSE2FS_CHECK_CONTEXT(ff); -+ fs = ff->fs; -+ pthread_mutex_lock(&ff->bfl); -+ switch ((unsigned long) cmd) { -+#ifdef SUPPORT_I_FLAGS -+ case EXT2_IOC_GETFLAGS: -+ ret = ioctl_getflags(fs, fh, data); -+ break; -+ case EXT2_IOC_SETFLAGS: -+ ret = ioctl_setflags(fs, fh, data); -+ break; -+ case EXT2_IOC_GETVERSION: -+ ret = ioctl_getversion(fs, fh, data); -+ break; -+ case EXT2_IOC_SETVERSION: -+ ret = ioctl_setversion(fs, fh, data); -+ break; -+#endif -+#ifdef FITRIM -+ case FITRIM: -+ ret = ioctl_fitrim(fs, fh, data); -+ break; -+#endif -+ default: -+ dbg_printf("%s: Unknown ioctl %d\n", __func__, cmd); -+ ret = -ENOTTY; -+ } -+ pthread_mutex_unlock(&ff->bfl); -+ -+ return ret; -+} -+#endif /* FUSE 28 */ -+ -+static int op_bmap(const char *path, size_t blocksize EXT2FS_ATTR((unused)), -+ uint64_t *idx) -+{ -+ struct fuse_context *ctxt = fuse_get_context(); -+ struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data; -+ ext2_filsys fs; -+ ext2_ino_t ino; -+ errcode_t err; -+ int ret = 0; -+ -+ FUSE2FS_CHECK_CONTEXT(ff); -+ fs = ff->fs; -+ pthread_mutex_lock(&ff->bfl); -+ err = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, path, &ino); -+ if (err) { -+ ret = translate_error(fs, 0, err); -+ goto out; -+ } -+ dbg_printf("%s: ino=%d blk=%"PRIu64"\n", __func__, ino, *idx); -+ -+ err = ext2fs_bmap2(fs, ino, NULL, NULL, 0, *idx, 0, (blk64_t *)idx); -+ if (err) { -+ ret = translate_error(fs, ino, err); -+ goto out; -+ } -+ -+out: -+ pthread_mutex_unlock(&ff->bfl); -+ return ret; -+} -+ -+#if FUSE_VERSION >= FUSE_MAKE_VERSION(2, 9) -+# ifdef SUPPORT_FALLOCATE -+static int fallocate_helper(struct fuse_file_info *fp, int mode, off_t offset, -+ off_t len) -+{ -+ struct fuse_context *ctxt = fuse_get_context(); -+ struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data; -+ struct fuse2fs_file_handle *fh = (struct fuse2fs_file_handle *)fp->fh; -+ ext2_filsys fs; -+ struct ext2_inode_large inode; -+ blk64_t start, end; -+ __u64 fsize; -+ errcode_t err; -+ int flags; -+ -+ FUSE2FS_CHECK_CONTEXT(ff); -+ fs = ff->fs; -+ FUSE2FS_CHECK_MAGIC(fs, fh, FUSE2FS_FILE_MAGIC); -+ start = offset / fs->blocksize; -+ end = (offset + len - 1) / fs->blocksize; -+ dbg_printf("%s: ino=%d mode=0x%x start=%jd end=%llu\n", __func__, -+ fh->ino, mode, offset / fs->blocksize, end); -+ if (!fs_can_allocate(ff, len / fs->blocksize)) -+ return -ENOSPC; -+ -+ memset(&inode, 0, sizeof(inode)); -+ err = ext2fs_read_inode_full(fs, fh->ino, (struct ext2_inode *)&inode, -+ sizeof(inode)); -+ if (err) -+ return err; -+ fsize = EXT2_I_SIZE(&inode); -+ -+ /* Allocate a bunch of blocks */ -+ flags = (mode & FL_KEEP_SIZE_FLAG ? 0 : -+ EXT2_FALLOCATE_INIT_BEYOND_EOF); -+ err = ext2fs_fallocate(fs, flags, fh->ino, -+ (struct ext2_inode *)&inode, -+ ~0ULL, start, end - start + 1); -+ if (err && err != EXT2_ET_BLOCK_ALLOC_FAIL) -+ return translate_error(fs, fh->ino, err); -+ -+ /* Update i_size */ -+ if (!(mode & FL_KEEP_SIZE_FLAG)) { -+ if ((__u64) offset + len > fsize) { -+ err = ext2fs_inode_size_set(fs, -+ (struct ext2_inode *)&inode, -+ offset + len); -+ if (err) -+ return translate_error(fs, fh->ino, err); -+ } -+ } -+ -+ err = update_mtime(fs, fh->ino, &inode); -+ if (err) -+ return err; -+ -+ err = ext2fs_write_inode_full(fs, fh->ino, (struct ext2_inode *)&inode, -+ sizeof(inode)); -+ if (err) -+ return translate_error(fs, fh->ino, err); -+ -+ return err; -+} -+ -+static errcode_t clean_block_middle(ext2_filsys fs, ext2_ino_t ino, -+ struct ext2_inode_large *inode, off_t offset, -+ off_t len, char **buf) -+{ -+ blk64_t blk; -+ off_t residue; -+ int retflags; -+ errcode_t err; -+ -+ residue = offset % fs->blocksize; -+ if (residue == 0) -+ return 0; -+ -+ if (!*buf) { -+ err = ext2fs_get_mem(fs->blocksize, buf); -+ if (err) -+ return err; -+ } -+ -+ err = ext2fs_bmap2(fs, ino, (struct ext2_inode *)inode, *buf, 0, -+ offset / fs->blocksize, &retflags, &blk); -+ if (err) -+ return err; -+ if (!blk || (retflags & BMAP_RET_UNINIT)) -+ return 0; -+ -+ err = io_channel_read_blk(fs->io, blk, 1, *buf); -+ if (err) -+ return err; -+ -+ memset(*buf + residue, 0, len); -+ -+ return io_channel_write_blk(fs->io, blk, 1, *buf); -+} -+ -+static errcode_t clean_block_edge(ext2_filsys fs, ext2_ino_t ino, -+ struct ext2_inode_large *inode, off_t offset, -+ int clean_before, char **buf) -+{ -+ blk64_t blk; -+ int retflags; -+ off_t residue; -+ errcode_t err; -+ -+ residue = offset % fs->blocksize; -+ if (residue == 0) -+ return 0; -+ -+ if (!*buf) { -+ err = ext2fs_get_mem(fs->blocksize, buf); -+ if (err) -+ return err; -+ } -+ -+ err = ext2fs_bmap2(fs, ino, (struct ext2_inode *)inode, *buf, 0, -+ offset / fs->blocksize, &retflags, &blk); -+ if (err) -+ return err; -+ -+ err = io_channel_read_blk(fs->io, blk, 1, *buf); -+ if (err) -+ return err; -+ if (!blk || (retflags & BMAP_RET_UNINIT)) -+ return 0; -+ -+ if (clean_before) -+ memset(*buf, 0, residue); -+ else -+ memset(*buf + residue, 0, fs->blocksize - residue); -+ -+ return io_channel_write_blk(fs->io, blk, 1, *buf); -+} -+ -+static int punch_helper(struct fuse_file_info *fp, int mode, off_t offset, -+ off_t len) -+{ -+ struct fuse_context *ctxt = fuse_get_context(); -+ struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data; -+ struct fuse2fs_file_handle *fh = (struct fuse2fs_file_handle *)fp->fh; -+ ext2_filsys fs; -+ struct ext2_inode_large inode; -+ blk64_t start, end; -+ errcode_t err; -+ char *buf = NULL; -+ -+ FUSE2FS_CHECK_CONTEXT(ff); -+ fs = ff->fs; -+ FUSE2FS_CHECK_MAGIC(fs, fh, FUSE2FS_FILE_MAGIC); -+ dbg_printf("%s: offset=%jd len=%jd\n", __func__, offset, len); -+ -+ /* kernel ext4 punch requires this flag to be set */ -+ if (!(mode & FL_KEEP_SIZE_FLAG)) -+ return -EINVAL; -+ -+ /* Punch out a bunch of blocks */ -+ start = (offset + fs->blocksize - 1) / fs->blocksize; -+ end = (offset + len - fs->blocksize) / fs->blocksize; -+ dbg_printf("%s: ino=%d mode=0x%x start=%llu end=%llu\n", __func__, -+ fh->ino, mode, start, end); -+ -+ memset(&inode, 0, sizeof(inode)); -+ err = ext2fs_read_inode_full(fs, fh->ino, (struct ext2_inode *)&inode, -+ sizeof(inode)); -+ if (err) -+ return translate_error(fs, fh->ino, err); -+ -+ /* Zero everything before the first block and after the last block */ -+ if ((offset / fs->blocksize) == ((offset + len) / fs->blocksize)) -+ err = clean_block_middle(fs, fh->ino, &inode, offset, -+ len, &buf); -+ else { -+ err = clean_block_edge(fs, fh->ino, &inode, offset, 0, &buf); -+ if (!err) -+ err = clean_block_edge(fs, fh->ino, &inode, -+ offset + len, 1, &buf); -+ } -+ if (buf) -+ ext2fs_free_mem(&buf); -+ if (err) -+ return translate_error(fs, fh->ino, err); -+ -+ /* Unmap full blocks in the middle */ -+ if (start <= end) { -+ err = ext2fs_punch(fs, fh->ino, (struct ext2_inode *)&inode, -+ NULL, start, end); -+ if (err) -+ return translate_error(fs, fh->ino, err); -+ } -+ -+ err = update_mtime(fs, fh->ino, &inode); -+ if (err) -+ return err; -+ -+ err = ext2fs_write_inode_full(fs, fh->ino, (struct ext2_inode *)&inode, -+ sizeof(inode)); -+ if (err) -+ return translate_error(fs, fh->ino, err); -+ -+ return 0; -+} -+ -+static int op_fallocate(const char *path EXT2FS_ATTR((unused)), int mode, -+ off_t offset, off_t len, -+ struct fuse_file_info *fp) -+{ -+ struct fuse_context *ctxt = fuse_get_context(); -+ struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data; -+ ext2_filsys fs = ff->fs; -+ int ret; -+ -+ /* Catch unknown flags */ -+ if (mode & ~(FL_PUNCH_HOLE_FLAG | FL_KEEP_SIZE_FLAG)) -+ return -EINVAL; -+ -+ pthread_mutex_lock(&ff->bfl); -+ if (!fs_writeable(fs)) { -+ ret = -EROFS; -+ goto out; -+ } -+ if (mode & FL_PUNCH_HOLE_FLAG) -+ ret = punch_helper(fp, mode, offset, len); -+ else -+ ret = fallocate_helper(fp, mode, offset, len); -+out: -+ pthread_mutex_unlock(&ff->bfl); -+ -+ return ret; -+} -+# endif /* SUPPORT_FALLOCATE */ -+#endif /* FUSE 29 */ -+ -+static struct fuse_operations fs_ops = { -+ .init = op_init, -+ .destroy = op_destroy, -+ .getattr = op_getattr, -+ .readlink = op_readlink, -+ .mknod = op_mknod, -+ .mkdir = op_mkdir, -+ .unlink = op_unlink, -+ .rmdir = op_rmdir, -+ .symlink = op_symlink, -+ .rename = op_rename, -+ .link = op_link, -+ .chmod = op_chmod, -+ .chown = op_chown, -+ .truncate = op_truncate, -+ .open = op_open, -+ .read = op_read, -+ .write = op_write, -+ .statfs = op_statfs, -+ .release = op_release, -+ .fsync = op_fsync, -+ .setxattr = op_setxattr, -+ .getxattr = op_getxattr, -+ .listxattr = op_listxattr, -+ .removexattr = op_removexattr, -+ .opendir = op_open, -+ .readdir = op_readdir, -+ .releasedir = op_release, -+ .fsyncdir = op_fsync, -+ .access = op_access, -+ .create = op_create, -+ .ftruncate = op_ftruncate, -+ .fgetattr = op_fgetattr, -+ .utimens = op_utimens, -+#if FUSE_VERSION >= FUSE_MAKE_VERSION(2, 9) -+# if defined(UTIME_NOW) || defined(UTIME_OMIT) -+ .flag_utime_omit_ok = 1, -+# endif -+#endif -+ .bmap = op_bmap, -+#ifdef SUPERFLUOUS -+ .lock = op_lock, -+ .poll = op_poll, -+#endif -+#if FUSE_VERSION >= FUSE_MAKE_VERSION(2, 8) -+ .ioctl = op_ioctl, -+ .flag_nullpath_ok = 1, -+#endif -+#if FUSE_VERSION >= FUSE_MAKE_VERSION(2, 9) -+ .flag_nopath = 1, -+# ifdef SUPPORT_FALLOCATE -+ .fallocate = op_fallocate, -+# endif -+#endif -+}; -+ -+static int get_random_bytes(void *p, size_t sz) -+{ -+ int fd; -+ ssize_t r; -+ -+ fd = open("/dev/urandom", O_RDONLY); -+ if (fd < 0) { -+ perror("/dev/urandom"); -+ return 0; -+ } -+ -+ r = read(fd, p, sz); -+ -+ close(fd); -+ return (size_t) r == sz; -+} -+ -+static void print_help(const char *progname) -+{ -+ printf(_("Usage: %s dev mntpt [-o options] [fuse_args]\n"), progname); -+} -+ -+int main(int argc, char *argv[]) -+{ -+ errcode_t err; -+ char *tok, *arg, *logfile; -+ int i; -+ int readwrite = 1, panic_on_error = 0, minixdf = 0; -+ struct fuse2fs *ff; -+ char extra_args[BUFSIZ]; -+ int ret = 0, flags = EXT2_FLAG_64BITS | EXT2_FLAG_EXCLUSIVE; -+ -+ if (argc < 2) { -+ print_help(argv[0]); -+ return 1; -+ } -+ -+ for (i = 1; i < argc; i++) { -+ if (strcmp(argv[i], "--help") == 0) { -+ print_help(argv[0]); -+ return 1; -+ } -+ } -+ -+ for (i = 1; i < argc - 1; i++) { -+ if (strcmp(argv[i], "-o")) -+ continue; -+ arg = argv[i + 1]; -+ while ((tok = strtok(arg, ","))) { -+ arg = NULL; -+ if (!strcmp(tok, "ro")) -+ readwrite = 0; -+ else if (!strcmp(tok, "errors=panic")) -+ panic_on_error = 1; -+ else if (!strcmp(tok, "minixdf")) -+ minixdf = 1; -+ } -+ } -+ -+ if (!readwrite) -+ printf("%s", _("Mounting read-only.\n")); -+ -+#ifdef ENABLE_NLS -+ setlocale(LC_MESSAGES, ""); -+ setlocale(LC_CTYPE, ""); -+ bindtextdomain(NLS_CAT_NAME, LOCALEDIR); -+ textdomain(NLS_CAT_NAME); -+ set_com_err_gettext(gettext); -+#endif -+ add_error_table(&et_ext2_error_table); -+ -+ ff = calloc(1, sizeof(*ff)); -+ if (!ff) { -+ perror("init"); -+ return 1; -+ } -+ ff->magic = FUSE2FS_MAGIC; -+ ff->panic_on_error = panic_on_error; -+ ff->minixdf = minixdf; -+ -+ /* Set up error logging */ -+ logfile = getenv("FUSE2FS_LOGFILE"); -+ if (logfile) { -+ ff->err_fp = fopen(logfile, "a"); -+ if (!ff->err_fp) { -+ perror(logfile); -+ goto out_nofs; -+ } -+ } else -+ ff->err_fp = stderr; -+ -+ /* Will we allow users to allocate every last block? */ -+ if (getenv("FUSE2FS_ALLOC_ALL_BLOCKS")) { -+ printf(_("%s: Allowing users to allocate all blocks. " -+ "This is dangerous!\n"), argv[1]); -+ ff->alloc_all_blocks = 1; -+ } -+ -+ /* Start up the fs (while we still can use stdout) */ -+ ret = 2; -+ if (readwrite) -+ flags |= EXT2_FLAG_RW; -+ err = ext2fs_open2(argv[1], NULL, flags, 0, 0, unix_io_manager, -+ &global_fs); -+ if (err) { -+ printf(_("%s: %s.\n"), argv[1], error_message(err)); -+ printf(_("Please run e2fsck -fy %s.\n"), argv[1]); -+ goto out_nofs; -+ } -+ ff->fs = global_fs; -+ global_fs->priv_data = ff; -+ -+ ret = 3; -+ if (EXT2_HAS_INCOMPAT_FEATURE(global_fs->super, -+ EXT3_FEATURE_INCOMPAT_RECOVER)) { -+ if (readwrite) { -+ printf(_("%s: recovering journal\n"), argv[1]); -+ err = ext2fs_run_ext3_journal(&global_fs); -+ if (err) { -+ printf(_("%s: %s.\n"), argv[1], -+ error_message(err)); -+ printf(_("Please run e2fsck -fy %s.\n"), -+ argv[1]); -+ goto out; -+ } -+ global_fs->super->s_feature_incompat &= -+ ~EXT3_FEATURE_INCOMPAT_RECOVER; -+ ext2fs_mark_super_dirty(global_fs); -+ } else { -+ printf("%s", _("Journal needs recovery; running " -+ "`e2fsck -E journal_only' is required.\n")); -+ goto out; -+ } -+ } -+ -+ if (readwrite) { -+ if (EXT2_HAS_COMPAT_FEATURE(global_fs->super, -+ EXT3_FEATURE_COMPAT_HAS_JOURNAL)) -+ printf(_("%s: Writing to the journal is not supported.\n"), -+ argv[1]); -+ err = ext2fs_read_inode_bitmap(global_fs); -+ if (err) { -+ translate_error(global_fs, 0, err); -+ goto out; -+ } -+ err = ext2fs_read_block_bitmap(global_fs); -+ if (err) { -+ translate_error(global_fs, 0, err); -+ goto out; -+ } -+ } -+ -+ if (!(global_fs->super->s_state & EXT2_VALID_FS)) -+ printf("%s", _("Warning: Mounting unchecked fs, running e2fsck " -+ "is recommended.\n")); -+ if (global_fs->super->s_max_mnt_count > 0 && -+ global_fs->super->s_mnt_count >= global_fs->super->s_max_mnt_count) -+ printf("%s", _("Warning: Maximal mount count reached, running " -+ "e2fsck is recommended.\n")); -+ if (global_fs->super->s_checkinterval > 0 && -+ global_fs->super->s_lastcheck + -+ global_fs->super->s_checkinterval <= time(0)) -+ printf("%s", _("Warning: Check time reached; running e2fsck " -+ "is recommended.\n")); -+ if (global_fs->super->s_last_orphan) -+ printf("%s", -+ _("Orphans detected; running e2fsck is recommended.\n")); -+ -+ if (global_fs->super->s_state & EXT2_ERROR_FS) { -+ printf("%s", -+ _("Errors detected; running e2fsck is required.\n")); -+ goto out; -+ } -+ -+ /* Initialize generation counter */ -+ get_random_bytes(&ff->next_generation, sizeof(unsigned int)); -+ -+ /* Stuff in some fuse parameters of our own */ -+ snprintf(extra_args, BUFSIZ, "-okernel_cache,subtype=ext4,use_ino," -+ "fsname=%s,attr_timeout=0,allow_other" FUSE_PLATFORM_OPTS, -+ argv[1]); -+ argv[0] = argv[1]; -+ argv[1] = argv[2]; -+ argv[2] = extra_args; -+ -+ pthread_mutex_init(&ff->bfl, NULL); -+ fuse_main(argc, argv, &fs_ops, ff); -+ pthread_mutex_destroy(&ff->bfl); -+ -+ ret = 0; -+out: -+ err = ext2fs_close(global_fs); -+ if (err) -+ com_err(argv[0], err, "while closing fs"); -+ global_fs = NULL; -+out_nofs: -+ free(ff); -+ -+ return ret; -+} -+ -+static int __translate_error(ext2_filsys fs, errcode_t err, ext2_ino_t ino, -+ const char *file, int line) -+{ -+ struct timespec now; -+ int ret = err; -+ struct fuse2fs *ff = fs->priv_data; -+ int is_err = 0; -+ -+ /* Translate ext2 error to unix error code */ -+ if (err < EXT2_ET_BASE) -+ goto no_translation; -+ switch (err) { -+ case EXT2_ET_NO_MEMORY: -+ case EXT2_ET_TDB_ERR_OOM: -+ ret = -ENOMEM; -+ break; -+ case EXT2_ET_INVALID_ARGUMENT: -+ case EXT2_ET_LLSEEK_FAILED: -+ ret = -EINVAL; -+ break; -+ case EXT2_ET_NO_DIRECTORY: -+ ret = -ENOTDIR; -+ break; -+ case EXT2_ET_FILE_NOT_FOUND: -+ ret = -ENOENT; -+ break; -+ case EXT2_ET_DIR_NO_SPACE: -+ is_err = 1; -+ case EXT2_ET_TOOSMALL: -+ case EXT2_ET_BLOCK_ALLOC_FAIL: -+ case EXT2_ET_INODE_ALLOC_FAIL: -+ case EXT2_ET_EA_NO_SPACE: -+ ret = -ENOSPC; -+ break; -+ case EXT2_ET_SYMLINK_LOOP: -+ ret = -EMLINK; -+ break; -+ case EXT2_ET_FILE_TOO_BIG: -+ ret = -EFBIG; -+ break; -+ case EXT2_ET_TDB_ERR_EXISTS: -+ case EXT2_ET_FILE_EXISTS: -+ ret = -EEXIST; -+ break; -+ case EXT2_ET_MMP_FAILED: -+ case EXT2_ET_MMP_FSCK_ON: -+ ret = -EBUSY; -+ break; -+ case EXT2_ET_EA_KEY_NOT_FOUND: -+#ifdef ENODATA -+ ret = -ENODATA; -+#else -+ ret = -ENOENT; -+#endif -+ break; -+ /* Sometimes fuse returns a garbage file handle pointer to us... */ -+ case EXT2_ET_MAGIC_EXT2_FILE: -+ ret = -EFAULT; -+ break; -+ case EXT2_ET_UNIMPLEMENTED: -+ ret = -EOPNOTSUPP; -+ break; -+ default: -+ is_err = 1; -+ ret = -EIO; -+ break; -+ } -+ -+no_translation: -+ if (!is_err) -+ return ret; -+ -+ if (ino) -+ fprintf(ff->err_fp, "FUSE2FS (%s): %s (inode #%d) at %s:%d.\n", -+ fs && fs->device_name ? fs->device_name : "???", -+ error_message(err), ino, file, line); -+ else -+ fprintf(ff->err_fp, "FUSE2FS (%s): %s at %s:%d.\n", -+ fs && fs->device_name ? fs->device_name : "???", -+ error_message(err), file, line); -+ fflush(ff->err_fp); -+ -+ /* Make a note in the error log */ -+ get_now(&now); -+ fs->super->s_last_error_time = now.tv_sec; -+ fs->super->s_last_error_ino = ino; -+ fs->super->s_last_error_line = line; -+ fs->super->s_last_error_block = err; /* Yeah... */ -+ strncpy((char *)fs->super->s_last_error_func, file, -+ sizeof(fs->super->s_last_error_func)); -+ if (fs->super->s_first_error_time == 0) { -+ fs->super->s_first_error_time = now.tv_sec; -+ fs->super->s_first_error_ino = ino; -+ fs->super->s_first_error_line = line; -+ fs->super->s_first_error_block = err; -+ strncpy((char *)fs->super->s_first_error_func, file, -+ sizeof(fs->super->s_first_error_func)); -+ } -+ -+ fs->super->s_error_count++; -+ ext2fs_mark_super_dirty(fs); -+ ext2fs_flush(fs); -+ if (ff->panic_on_error) -+ abort(); -+ -+ return ret; -+} -diff --git a/misc/jfs_user.h b/misc/jfs_user.h -deleted file mode 100644 -index 3070cd5..0000000 ---- a/misc/jfs_user.h -+++ /dev/null -@@ -1,8 +0,0 @@ --#ifndef _JFS_USER_H --#define _JFS_USER_H -- --typedef unsigned short kdev_t; -- --#include -- --#endif /* _JFS_USER_H */ -diff --git a/misc/logsave.c b/misc/logsave.c -index f6cc42a..6a624de 100644 ---- a/misc/logsave.c -+++ b/misc/logsave.c -@@ -219,7 +219,7 @@ static int run_program(char **argv) - sprintf(buffer, "died with signal %d\n", - WTERMSIG(status)); - send_output(buffer, 0, SEND_BOTH); -- rc = 1; -+ return 1; - } - rc = 0; - } -diff --git a/misc/lsattr.c b/misc/lsattr.c -index e5e5969..f6b4384 100644 ---- a/misc/lsattr.c -+++ b/misc/lsattr.c -@@ -43,8 +43,8 @@ extern char *optarg; - #include "et/com_err.h" - #include "e2p/e2p.h" - -+#include "support/nls-enable.h" - #include "../version.h" --#include "nls-enable.h" - - #ifdef __GNUC__ - #define EXT2FS_ATTR(x) __attribute__(x) -diff --git a/misc/mk_hugefiles.c b/misc/mk_hugefiles.c -index 5f56a79..888b184 100644 ---- a/misc/mk_hugefiles.c -+++ b/misc/mk_hugefiles.c -@@ -45,9 +45,9 @@ extern int optind; - #include "e2p/e2p.h" - #include "ext2fs/ext2fs.h" - #include "util.h" --#include "profile.h" --#include "prof_err.h" --#include "nls-enable.h" -+#include "support/profile.h" -+#include "support/prof_err.h" -+#include "support/nls-enable.h" - #include "mke2fs.h" - - static int uid; -@@ -258,12 +258,7 @@ static errcode_t mk_hugefile(ext2_filsys fs, blk64_t num, - - { - errcode_t retval; -- blk64_t lblk, bend = 0; -- __u64 size; -- blk64_t left; -- blk64_t count = 0; - struct ext2_inode inode; -- ext2_extent_handle_t handle; - - retval = ext2fs_new_inode(fs, 0, LINUX_S_IFREG, NULL, ino); - if (retval) -@@ -283,85 +278,20 @@ static errcode_t mk_hugefile(ext2_filsys fs, blk64_t num, - - ext2fs_inode_alloc_stats2(fs, *ino, +1, 0); - -- retval = ext2fs_extent_open2(fs, *ino, &inode, &handle); -+ if (EXT2_HAS_INCOMPAT_FEATURE(fs->super, -+ EXT3_FEATURE_INCOMPAT_EXTENTS)) -+ inode.i_flags |= EXT4_EXTENTS_FL; -+ retval = ext2fs_fallocate(fs, -+ EXT2_FALLOCATE_FORCE_INIT | -+ EXT2_FALLOCATE_ZERO_BLOCKS, -+ *ino, &inode, goal, 0, num); - if (retval) - return retval; -- -- lblk = 0; -- left = num ? num : 1; -- while (left) { -- blk64_t pblk, end; -- blk64_t n = left; -- -- retval = ext2fs_find_first_zero_block_bitmap2(fs->block_map, -- goal, ext2fs_blocks_count(fs->super) - 1, &end); -- if (retval) -- goto errout; -- goal = end; -- -- retval = ext2fs_find_first_set_block_bitmap2(fs->block_map, goal, -- ext2fs_blocks_count(fs->super) - 1, &bend); -- if (retval == ENOENT) { -- bend = ext2fs_blocks_count(fs->super); -- if (num == 0) -- left = 0; -- } -- if (!num || bend - goal < left) -- n = bend - goal; -- pblk = goal; -- if (num) -- left -= n; -- goal += n; -- count += n; -- ext2fs_block_alloc_stats_range(fs, pblk, n, +1); -- -- if (zero_hugefile) { -- blk64_t ret_blk; -- retval = ext2fs_zero_blocks2(fs, pblk, n, -- &ret_blk, NULL); -- -- if (retval) -- com_err(program_name, retval, -- _("while zeroing block %llu " -- "for hugefile"), ret_blk); -- } -- -- while (n) { -- blk64_t l = n; -- struct ext2fs_extent newextent; -- -- if (l > EXT_INIT_MAX_LEN) -- l = EXT_INIT_MAX_LEN; -- -- newextent.e_len = l; -- newextent.e_pblk = pblk; -- newextent.e_lblk = lblk; -- newextent.e_flags = 0; -- -- retval = ext2fs_extent_insert(handle, -- EXT2_EXTENT_INSERT_AFTER, &newextent); -- if (retval) -- return retval; -- pblk += l; -- lblk += l; -- n -= l; -- } -- } -- -- retval = ext2fs_read_inode(fs, *ino, &inode); -+ retval = ext2fs_inode_size_set(fs, &inode, num * fs->blocksize); - if (retval) -- goto errout; -- -- retval = ext2fs_iblk_add_blocks(fs, &inode, -- count / EXT2FS_CLUSTER_RATIO(fs)); -- if (retval) -- goto errout; -- size = (__u64) count * fs->blocksize; -- retval = ext2fs_inode_size_set(fs, &inode, size); -- if (retval) -- goto errout; -+ return retval; - -- retval = ext2fs_write_new_inode(fs, *ino, &inode); -+ retval = ext2fs_write_inode(fs, *ino, &inode); - if (retval) - goto errout; - -@@ -379,13 +309,7 @@ retry: - goto retry; - } - -- if (retval) -- goto errout; -- - errout: -- if (handle) -- ext2fs_extent_free(handle); -- - return retval; - } - -@@ -476,6 +400,10 @@ errcode_t mk_hugefiles(ext2_filsys fs, const char *device_name) - if (!get_bool_from_profile(fs_types, "make_hugefiles", 0)) - return 0; - -+ if (!EXT2_HAS_INCOMPAT_FEATURE(fs->super, -+ EXT3_FEATURE_INCOMPAT_EXTENTS)) -+ return EXT2_ET_EXTENT_NOT_SUPPORTED; -+ - uid = get_int_from_profile(fs_types, "hugefiles_uid", 0); - gid = get_int_from_profile(fs_types, "hugefiles_gid", 0); - fs->umask = get_int_from_profile(fs_types, "hugefiles_umask", 077); -@@ -529,10 +457,10 @@ errcode_t mk_hugefiles(ext2_filsys fs, const char *device_name) - - fs_blocks = ext2fs_free_blocks_count(fs->super); - if (fs_blocks < num_slack + align) -- return ENOMEM; -+ return ENOSPC; - fs_blocks -= num_slack + align; - if (num_blocks && num_blocks > fs_blocks) -- return ENOMEM; -+ return ENOSPC; - if (num_blocks == 0 && num_files == 0) - num_files = 1; - -@@ -568,6 +496,8 @@ errcode_t mk_hugefiles(ext2_filsys fs, const char *device_name) - printf(_("with %llu blocks each"), num_blocks); - fputs(": ", stdout); - } -+ if (num_blocks == 0) -+ num_blocks = ext2fs_blocks_count(fs->super) - goal; - for (i=0; i < num_files; i++) { - ext2_ino_t ino; - -diff --git a/misc/mke2fs.8.in b/misc/mke2fs.8.in -index 1002eae..429ceba 100644 ---- a/misc/mke2fs.8.in -+++ b/misc/mke2fs.8.in -@@ -18,6 +18,10 @@ mke2fs \- create an ext2/ext3/ext4 filesystem - .I block-size - ] - [ -+.B \-d -+.I root-directory -+] -+[ - .B \-D - ] - [ -@@ -109,6 +113,14 @@ mke2fs \- create an ext2/ext3/ext4 filesystem - [ - .B \-V - ] -+[ -+.B \-e -+.I errors-behavior -+] -+[ -+.B \-z -+.I undo_file -+] - .I device - [ - .I fs-size -@@ -225,12 +237,35 @@ enabled. (See the - man page for more details about bigalloc.) The default cluster size if - bigalloc is enabled is 16 times the block size. - .TP -+.BI \-d " root-directory" -+Copy the contents of the given directory into the root directory of the -+filesystem. -+.TP - .B \-D - Use direct I/O when writing to the disk. This avoids mke2fs dirtying a - 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 -@@ -342,13 +377,13 @@ as default. - .TP - .BI nodiscard - Do not attempt to discard blocks at mkfs time. --@QUOTA_MAN_COMMENT@.TP --@QUOTA_MAN_COMMENT@.BI quotatype --@QUOTA_MAN_COMMENT@Specify which quota type ('usr' or 'grp') is to be --@QUOTA_MAN_COMMENT@initialized. This option has effect only if the --@QUOTA_MAN_COMMENT@.B quota --@QUOTA_MAN_COMMENT@feature is set. Without this extended option, the default --@QUOTA_MAN_COMMENT@behavior is to initialize both user and group quotas. -+.TP -+.BI quotatype -+Specify which quota type ('usr' or 'grp') is to be -+initialized. This option has effect only if the -+.B quota -+feature is set. Without this extended option, the default -+behavior is to initialize both user and group quotas. - .RE - .TP - .BI \-f " fragment-size" -@@ -619,18 +654,26 @@ kernels only support revision 0 filesystems. The default is to - create revision 1 filesystems. - .TP - .B \-S --Write superblock and group descriptors only. This is useful if all of -+Write superblock and group descriptors only. This is an extreme -+measure to be taken only in the very unlikely case that all of - the superblock and backup superblocks are corrupted, and a last-ditch --recovery method is desired. It causes -+recovery method is desired by experienced users. It causes - .B mke2fs --to reinitialize the --superblock and group descriptors, while not touching the inode table --and the block and inode bitmaps. The -+to reinitialize the superblock and group descriptors, while not -+touching the inode table and the block and inode bitmaps. The - .B e2fsck - program should be run immediately after this option is used, and there --is no guarantee that any data will be salvageable. It is critical to --specify the correct filesystem blocksize when using this option, --or there is no chance of recovery. -+is no guarantee that any data will be salvageable. Due to the wide -+variety of possible options to -+.BR mke2fs -+that affect the on-disk layout, is critical to specify exactly the same -+the same format options, such as blocksize, fs-type, feature flags, and -+other tunables when using this option, or the filesystem will be further -+corrupted. In some cases, such as filesystems that have been resized, -+or have had features enabled after format time, it is impossible to -+overwrite all of the superblocks corretly, and at least some filesystem -+corruption will occur. It is best to run this on a full copy of the -+filesystem so other options can be tried if this doesn't work. - .\" .TP - .\" .BI \-t " test" - .\" Check the device for bad blocks before creating the file system -@@ -708,6 +751,17 @@ Verbose execution. - Print the version number of - .B mke2fs - and exit. -+.TP -+.BI \-z " undo_file" -+Before overwriting a file system block, write the old contents of the block to -+an undo file. This undo file can be used with e2undo(8) to restore the old -+contents of the file system should something go wrong. If the empty string is -+passed as the undo_file argument, the undo file will be written to a file named -+mke2fs-\fIdevice\fR.e2undo in the directory specified via the -+\fIE2FSPROGS_UNDO_DIR\fR environment variable or the \fIundo_dir\fR directive -+in the configuration file. -+ -+WARNING: The undo file cannot be used to recover from a power or system crash. - .SH ENVIRONMENT - .TP - .BI MKE2FS_SYNC -diff --git a/misc/mke2fs.c b/misc/mke2fs.c -index a14e62e..179a4d1 100644 ---- a/misc/mke2fs.c -+++ b/misc/mke2fs.c -@@ -16,13 +16,12 @@ - * 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 - #include - #include --#include - #include - #include - #ifdef __linux__ -@@ -45,25 +44,22 @@ extern int optind; - #include - #endif - #include --#include --#include - #include - #include - #include - - #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 "support/nls-enable.h" -+#include "support/plausible.h" -+#include "support/profile.h" -+#include "support/prof_err.h" - #include "../version.h" --#include "nls-enable.h" --#include "quota/quotaio.h" -+#include "support/quotaio.h" - #include "mke2fs.h" -+#include "create_inode.h" - - #define STRIDE_LENGTH 8 - -@@ -113,23 +109,29 @@ 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 char *undo_file; - - 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] " -- "[-jnqvDFKSV] device [blocks-count]\n"), -+ "\t[-t fs-type] [-T usage-type ] [-U UUID] [-e errors_behavior]" -+ "[-z undo_file]\n" -+ "\t[-jnqvDFKSV] device [blocks-count]\n"), - program_name); - exit(1); - } -@@ -193,7 +195,7 @@ static int is_before_linux_ver(unsigned int major, unsigned int minor, - if (linux_version_code == 0) - return 0; - -- return linux_version_code < KERNEL_VERSION(major, minor, rev); -+ return linux_version_code < (int) KERNEL_VERSION(major, minor, rev); - } - #else - static int is_before_linux_ver(unsigned int major, unsigned int minor, -@@ -339,6 +341,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; -@@ -402,12 +423,14 @@ static void write_inode_tables(ext2_filsys fs, int lazy_flag, int itable_zeroed) - ext2fs_bg_flags_set(fs, i, EXT2_BG_INODE_ZEROED); - ext2fs_group_desc_csum_set(fs, i); - } -- retval = ext2fs_zero_blocks2(fs, blk, num, &blk, &num); -- if (retval) { -- fprintf(stderr, _("\nCould not write %d " -- "blocks in inode table starting at %llu: %s\n"), -- num, blk, error_message(retval)); -- exit(1); -+ if (!itable_zeroed) { -+ retval = ext2fs_zero_blocks2(fs, blk, num, &blk, &num); -+ if (retval) { -+ fprintf(stderr, _("\nCould not write %d " -+ "blocks in inode table starting at %llu: %s\n"), -+ num, blk, error_message(retval)); -+ exit(1); -+ } - } - if (sync_kludge) { - if (sync_kludge == 1) -@@ -416,9 +439,14 @@ static void write_inode_tables(ext2_filsys fs, int lazy_flag, int itable_zeroed) - sync(); - } - } -- 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) -@@ -599,7 +627,6 @@ static void create_journal_dev(ext2_filsys fs) - count -= c; - ext2fs_numeric_progress_update(fs, &progress, blk); - } -- ext2fs_zero_blocks2(0, 0, 0, 0, 0); - - ext2fs_numeric_progress_close(fs, &progress, NULL); - write_superblock: -@@ -707,6 +734,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 +1077,9 @@ 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| -+ EXT4_FEATURE_INCOMPAT_ENCRYPT, - /* R/O compat */ - EXT2_FEATURE_RO_COMPAT_LARGE_FILE| - EXT4_FEATURE_RO_COMPAT_HUGE_FILE| -@@ -1042,10 +1088,8 @@ static __u32 ok_features[3] = { - EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER| - EXT4_FEATURE_RO_COMPAT_GDT_CSUM| - EXT4_FEATURE_RO_COMPAT_BIGALLOC| --#ifdef CONFIG_QUOTA - EXT4_FEATURE_RO_COMPAT_QUOTA| --#endif -- 0 -+ EXT4_FEATURE_RO_COMPAT_METADATA_CSUM - }; - - -@@ -1174,15 +1218,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) -@@ -1354,11 +1394,11 @@ static const char *default_files[] = { "", 0 }; - * device's alignment offset, if any, or a negative error. - */ - static int get_device_geometry(const char *file, -- struct ext2_super_block *fs_param, -- int psector_size) -+ struct ext2_super_block *param, -+ unsigned int psector_size) - { - int rc = -1; -- int blocksize; -+ unsigned int blocksize; - blkid_probe pr; - blkid_topology tp; - unsigned long min_io; -@@ -1379,7 +1419,7 @@ static int get_device_geometry(const char *file, - - min_io = blkid_topology_get_minimum_io_size(tp); - opt_io = blkid_topology_get_optimal_io_size(tp); -- blocksize = EXT2_BLOCK_SIZE(fs_param); -+ blocksize = EXT2_BLOCK_SIZE(param); - if ((min_io == 0) && (psector_size > blocksize)) - min_io = psector_size; - if ((opt_io == 0) && min_io) -@@ -1389,9 +1429,9 @@ static int get_device_geometry(const char *file, - - /* setting stripe/stride to blocksize is pointless */ - if (min_io > blocksize) -- fs_param->s_raid_stride = min_io / blocksize; -+ param->s_raid_stride = min_io / blocksize; - if (opt_io > blocksize) -- fs_param->s_raid_stripe_width = opt_io / blocksize; -+ param->s_raid_stripe_width = opt_io / blocksize; - - rc = blkid_topology_get_alignment_offset(tp); - out: -@@ -1512,7 +1552,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:Vz:")) != EOF) { - switch (c) { - case 'b': - blocksize = parse_num_blocks2(optarg, -1); -@@ -1555,6 +1595,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 +1765,9 @@ profile_error: - case 'U': - fs_uuid = optarg; - break; -+ case 'd': -+ root_dir = optarg; -+ break; - case 'v': - verbose = 1; - break; -@@ -1718,6 +1775,9 @@ profile_error: - /* Print version number and exit */ - show_version_only++; - break; -+ case 'z': -+ undo_file = optarg; -+ break; - default: - usage(); - } -@@ -1896,10 +1956,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); -@@ -2040,7 +2130,8 @@ profile_error: - reserved_ratio = 0; - fs_param.s_feature_incompat = EXT3_FEATURE_INCOMPAT_JOURNAL_DEV; - fs_param.s_feature_compat = 0; -- fs_param.s_feature_ro_compat = 0; -+ fs_param.s_feature_ro_compat &= -+ EXT4_FEATURE_RO_COMPAT_METADATA_CSUM; - } - - /* Check the user's mkfs options for 64bit */ -@@ -2088,7 +2179,8 @@ profile_error: - } - - #ifdef HAVE_BLKID_PROBE_GET_TOPOLOGY -- retval = get_device_geometry(device_name, &fs_param, psector_size); -+ retval = get_device_geometry(device_name, &fs_param, -+ (unsigned int) psector_size); - if (retval < 0) { - fprintf(stderr, - _("warning: Unable to get device geometry for %s\n"), -@@ -2126,6 +2218,14 @@ profile_error: - blocksize, sys_page_size); - } - -+ /* Metadata checksumming wasn't totally stable before 3.18. */ -+ if (is_before_linux_ver(3, 18, 0) && -+ (fs_param.s_feature_ro_compat & -+ EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) -+ fprintf(stderr, _("Suggestion: Use Linux kernel >= 3.18 for " -+ "improved stability of the metadata and journal " -+ "checksum features.\n")); -+ - /* - * On newer kernels we do have lazy_itable_init support. So pick the - * right default in case ext4 module is not loaded. -@@ -2173,6 +2273,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)) { -@@ -2198,7 +2305,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) && -@@ -2257,6 +2365,20 @@ 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, -+ _("%d byte inodes are too small for inline data; " -+ "specify larger size"), -+ 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; -@@ -2326,7 +2448,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; -@@ -2374,6 +2497,21 @@ static int mke2fs_setup_tdb(const char *name, io_manager *io_ptr) - char *dev_name, *tmp_name; - int free_tdb_dir = 0; - -+ /* (re)open a specific undo file */ -+ if (undo_file && undo_file[0] != 0) { -+ retval = set_undo_io_backing_manager(*io_ptr); -+ if (retval) -+ goto err; -+ *io_ptr = undo_io_manager; -+ retval = set_undo_io_backup_file(undo_file); -+ if (retval) -+ goto err; -+ printf(_("Overwriting existing filesystem; this can be undone " -+ "using the command:\n" -+ " e2undo %s %s\n\n"), undo_file, name); -+ return retval; -+ } -+ - /* - * Configuration via a conf file would be - * nice -@@ -2407,10 +2545,14 @@ static int mke2fs_setup_tdb(const char *name, io_manager *io_ptr) - - if ((unlink(tdb_file) < 0) && (errno != ENOENT)) { - retval = errno; -+ com_err(program_name, retval, -+ _("while trying to delete %s"), tdb_file); - goto errout; - } - -- set_undo_io_backing_manager(*io_ptr); -+ retval = set_undo_io_backing_manager(*io_ptr); -+ if (retval) -+ goto errout; - *io_ptr = undo_io_manager; - retval = set_undo_io_backup_file(tdb_file); - if (retval) -@@ -2428,6 +2570,7 @@ errout: - if (free_tdb_dir) - free(tdb_dir); - free(tdb_file); -+err: - com_err(program_name, retval, "%s", - _("while trying to setup undo file\n")); - return retval; -@@ -2534,6 +2677,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; -@@ -2567,7 +2742,7 @@ int main (int argc, char *argv[]) - #endif - io_ptr = unix_io_manager; - -- if (should_do_undo(device_name)) { -+ if (undo_file != NULL || should_do_undo(device_name)) { - retval = mke2fs_setup_tdb(device_name, &io_ptr); - if (retval) - exit(1); -@@ -2596,6 +2771,35 @@ 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_INCOMPAT_FEATURE(fs->super, -+ EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) && -+ 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) || -@@ -2633,6 +2837,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; - -@@ -2653,6 +2858,7 @@ int main (int argc, char *argv[]) - } - } else - uuid_generate(fs->super->s_uuid); -+ ext2fs_init_csum_seed(fs); - - /* - * Initialize the directory index variables -@@ -2729,6 +2935,19 @@ int main (int argc, char *argv[]) - sizeof(fs->super->s_last_mounted)); - } - -+ /* Set current default encryption algorithms for data and -+ * filename encryption */ -+ if (fs->super->s_feature_incompat & EXT4_FEATURE_INCOMPAT_ENCRYPT) { -+ fs->super->s_encrypt_algos[0] = -+ EXT4_ENCRYPTION_MODE_AES_256_XTS; -+ fs->super->s_encrypt_algos[1] = -+ EXT4_ENCRYPTION_MODE_AES_256_CTS; -+ } -+ -+ 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); - -@@ -2738,6 +2957,7 @@ int main (int argc, char *argv[]) - if (fs->super->s_feature_incompat & - EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) { - create_journal_dev(fs); -+ printf("\n"); - exit(ext2fs_close_free(&fs) ? 1 : 0); - } - -@@ -2771,16 +2991,20 @@ int main (int argc, char *argv[]) - } - - if (super_only) { -+ check_plausibility(device_name, CHECK_FS_EXIST, NULL); -+ printf(_("%s may be further corrupted by superblock rewrite\n"), -+ device_name); -+ if (!force) -+ proceed_question(proceed_delay); - fs->super->s_state |= EXT2_ERROR_FS; - fs->flags &= ~(EXT2_FLAG_IB_DIRTY|EXT2_FLAG_BB_DIRTY); -- /* -+ /* - * The command "mke2fs -S" is used to recover - * corrupted file systems, so do not mark any of the - * 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); - } -@@ -2918,6 +3142,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", -+ _("while populating file system")); -+ exit(1); -+ } else if (!quiet) -+ printf("%s", _("done\n")); -+ } - - if (!quiet) - printf("%s", _("Writing superblocks and " -diff --git a/misc/mke2fs.conf.5.in b/misc/mke2fs.conf.5.in -index 19458ac..ad6c11b 100644 ---- a/misc/mke2fs.conf.5.in -+++ b/misc/mke2fs.conf.5.in -@@ -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 -diff --git a/misc/mke2fs.conf.in b/misc/mke2fs.conf.in -index 47f59cc..a049d61 100644 ---- a/misc/mke2fs.conf.in -+++ b/misc/mke2fs.conf.in -@@ -11,12 +11,11 @@ - features = has_journal - } - ext4 = { -- features = has_journal,extent,huge_file,flex_bg,uninit_bg,dir_nlink,extra_isize -- auto_64-bit_support = 1 -+ features = has_journal,extent,huge_file,flex_bg,metadata_csum,64bit,dir_nlink,extra_isize - 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 - } -diff --git a/misc/mklost+found.c b/misc/mklost+found.c -index 134e824..c061357 100644 ---- a/misc/mklost+found.c -+++ b/misc/mklost+found.c -@@ -25,7 +25,7 @@ - - #include "ext2fs/ext2_fs.h" - #include "../version.h" --#include "nls-enable.h" -+#include "support/nls-enable.h" - - #define LPF "lost+found" - -diff --git a/misc/nls-enable.h b/misc/nls-enable.h -deleted file mode 100644 -index a91dcc1..0000000 ---- a/misc/nls-enable.h -+++ /dev/null -@@ -1,21 +0,0 @@ --#ifdef ENABLE_NLS --#include --#include --#define _(a) (gettext (a)) --#ifdef gettext_noop --#define N_(a) gettext_noop (a) --#else --#define N_(a) (a) --#endif --#define P_(singular, plural, n) (ngettext (singular, plural, n)) --#ifndef NLS_CAT_NAME --#define NLS_CAT_NAME "e2fsprogs" --#endif --#ifndef LOCALEDIR --#define LOCALEDIR "/usr/share/locale" --#endif --#else --#define _(a) (a) --#define N_(a) a --#define P_(singular, plural, n) ((n) == 1 ? (singular) : (plural)) --#endif -diff --git a/misc/partinfo.c b/misc/partinfo.c -index c461e80..2b69c89 100644 ---- a/misc/partinfo.c -+++ b/misc/partinfo.c -@@ -18,7 +18,7 @@ - #include - #include - #include --#include "nls-enable.h" -+#include "support/nls-enable.h" - - #if defined(__linux__) && defined(_IO) && !defined(BLKGETSIZE) - #define BLKGETSIZE _IO(0x12,96) /* return device size */ -diff --git a/misc/tune2fs.8.in b/misc/tune2fs.8.in -index c50d475..b5a1d3b 100644 ---- a/misc/tune2fs.8.in -+++ b/misc/tune2fs.8.in -@@ -88,6 +88,10 @@ tune2fs \- adjust tunable filesystem parameters on ext2/ext3/ext4 filesystems - .B \-U - .I UUID - ] -+[ -+.B \-z -+.I undo_file -+] - device - .SH DESCRIPTION - .BI tune2fs -@@ -333,7 +337,7 @@ Create a journal stored in the filesystem of size - .I journal-size - megabytes. The size of the journal must be at least 1024 filesystem blocks - (i.e., 1MB if using 1k blocks, 4MB if using 4k blocks, etc.) --and may be no more than 102,400 filesystem blocks. -+and may be no more than 10,240,000 filesystem blocks. - There must be enough free space in the filesystem to create a journal of - that size. - .TP -@@ -563,9 +567,12 @@ only supports clearing this filesystem feature. - .TP - .B mmp - Enable or disable multiple mount protection (MMP) feature. --@QUOTA_MAN_COMMENT@.TP --@QUOTA_MAN_COMMENT@.B quota --@QUOTA_MAN_COMMENT@Enable internal file system quota inodes. -+.TP -+.B quota -+Enable internal file system quota inodes. -+.TP -+.B read-only -+Force the kernel to mount the file system read-only. - .TP - .B sparse_super - Limit the number of backup superblocks to save space on large filesystems. -@@ -684,6 +691,16 @@ or - .IR /dev/urandom , - .B tune2fs - will automatically use a time-based UUID instead of a randomly-generated UUID. -+.TP -+.BI \-z " undo_file" -+Before overwriting a file system block, write the old contents of the block to -+an undo file. This undo file can be used with e2undo(8) to restore the old -+contents of the file system should something go wrong. If the empty string is -+passed as the undo_file argument, the undo file will be written to a file named -+tune2fs-\fIdevice\fR.e2undo in the directory specified via the -+\fIE2FSPROGS_UNDO_DIR\fR environment variable. -+ -+WARNING: The undo file cannot be used to recover from a power or system crash. - .SH BUGS - We haven't found any bugs yet. That doesn't mean there aren't any... - .SH AUTHOR -diff --git a/misc/tune2fs.c b/misc/tune2fs.c -index 61078cc..f9ce38c 100644 ---- a/misc/tune2fs.c -+++ b/misc/tune2fs.c -@@ -54,16 +54,17 @@ extern int optind; - - #include "ext2fs/ext2_fs.h" - #include "ext2fs/ext2fs.h" -+#include "ext2fs/kernel-jbd.h" - #include "et/com_err.h" -+#include "support/plausible.h" -+#include "support/quotaio.h" - #include "uuid/uuid.h" - #include "e2p/e2p.h" --#include "jfs_user.h" - #include "util.h" - #include "blkid/blkid.h" --#include "quota/quotaio.h" - - #include "../version.h" --#include "nls-enable.h" -+#include "support/nls-enable.h" - - #define QOPT_ENABLE (1) - #define QOPT_DISABLE (-1) -@@ -95,6 +96,10 @@ static char *extended_cmd; - static unsigned long new_inode_size; - static char *ext_mount_opts; - static int usrquota, grpquota; -+static int rewrite_checksums; -+static int feature_64bit; -+static int fsck_requested; -+static char *undo_file; - - int journal_size, journal_flags; - char *journal_device; -@@ -110,6 +115,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); -@@ -121,16 +128,14 @@ static void usage(void) - _("Usage: %s [-c max_mounts_count] [-e errors_behavior] " - "[-g group]\n" - "\t[-i interval[d|m|w]] [-j] [-J journal_options] [-l]\n" -- "\t[-m reserved_blocks_percent] " -- "[-o [^]mount_options[,...]] [-p mmp_update_interval]\n" -- "\t[-r reserved_blocks_count] [-u user] [-C mount_count] " -- "[-L volume_label]\n" -- "\t[-M last_mounted_dir] [-O [^]feature[,...]]\n" --#ifdef CONFIG_QUOTA -- "\t[-Q quota_options]\n" --#endif -+ "\t[-m reserved_blocks_percent] [-o [^]mount_options[,...]]\n" -+ "\t[-p mmp_update_interval] [-r reserved_blocks_count] " -+ "[-u user]\n" -+ "\t[-C mount_count] [-L volume_label] [-M last_mounted_dir]\n" -+ "\t[-O [^]feature[,...]] [-Q quota_options]\n" - "\t[-E extended-option[,...]] [-T last_check_time] " -- "[-U UUID]\n\t[ -I new_inode_size ] device\n"), program_name); -+ "[-U UUID]\n\t[-I new_inode_size] [-z undo_file] device\n"), -+ program_name); - exit(1); - } - -@@ -142,17 +147,19 @@ static __u32 ok_features[3] = { - EXT2_FEATURE_INCOMPAT_FILETYPE | - EXT3_FEATURE_INCOMPAT_EXTENTS | - EXT4_FEATURE_INCOMPAT_FLEX_BG | -- EXT4_FEATURE_INCOMPAT_MMP, -+ EXT4_FEATURE_INCOMPAT_MMP | -+ EXT4_FEATURE_INCOMPAT_64BIT | -+ EXT4_FEATURE_INCOMPAT_ENCRYPT, - /* R/O compat */ - EXT2_FEATURE_RO_COMPAT_LARGE_FILE | - 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 -+ EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER | - EXT4_FEATURE_RO_COMPAT_QUOTA | --#endif -- EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER -+ EXT4_FEATURE_RO_COMPAT_METADATA_CSUM | -+ EXT4_FEATURE_RO_COMPAT_READONLY - }; - - static __u32 clear_ok_features[3] = { -@@ -163,16 +170,17 @@ static __u32 clear_ok_features[3] = { - /* Incompat */ - EXT2_FEATURE_INCOMPAT_FILETYPE | - EXT4_FEATURE_INCOMPAT_FLEX_BG | -- EXT4_FEATURE_INCOMPAT_MMP, -+ EXT4_FEATURE_INCOMPAT_MMP | -+ EXT4_FEATURE_INCOMPAT_64BIT, - /* R/O compat */ - EXT2_FEATURE_RO_COMPAT_LARGE_FILE | - EXT4_FEATURE_RO_COMPAT_HUGE_FILE| - EXT4_FEATURE_RO_COMPAT_DIR_NLINK| - EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE| --#ifdef CONFIG_QUOTA -+ EXT4_FEATURE_RO_COMPAT_GDT_CSUM | - EXT4_FEATURE_RO_COMPAT_QUOTA | --#endif -- EXT4_FEATURE_RO_COMPAT_GDT_CSUM -+ EXT4_FEATURE_RO_COMPAT_METADATA_CSUM | -+ EXT4_FEATURE_RO_COMPAT_READONLY - }; - - /** -@@ -181,7 +189,6 @@ static __u32 clear_ok_features[3] = { - static int get_journal_sb(ext2_filsys jfs, char buf[SUPERBLOCK_SIZE]) - { - int retval; -- int start; - journal_superblock_t *jsb; - - if (!(jfs->super->s_feature_incompat & -@@ -226,7 +233,7 @@ static int remove_journal_device(ext2_filsys fs) - { - char *journal_path; - ext2_filsys jfs; -- char buf[SUPERBLOCK_SIZE]; -+ char buf[SUPERBLOCK_SIZE] __attribute__ ((aligned(8))); - journal_superblock_t *jsb; - int i, nr_users; - errcode_t retval; -@@ -374,6 +381,7 @@ static errcode_t remove_journal_inode(ext2_filsys fs) - return retval; - } - fs->super->s_journal_inum = 0; -+ memset(fs->super->s_jnl_blocks, 0, sizeof(fs->super->s_jnl_blocks)); - ext2fs_mark_super_dirty(fs); - - return 0; -@@ -406,29 +414,555 @@ 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; -+ fsck_requested++; -+ 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; - - if (requested++) - return; -+ fsck_requested++; - fs->super->s_state &= ~EXT2_VALID_FS; - printf("\n%s\n", _(please_fsck)); - if (mount_flags & EXT2_MF_READONLY) - printf("%s", _("(and reboot afterwards!)\n")); - } - -+static void convert_64bit(ext2_filsys fs, int direction) -+{ -+ if (!direction) -+ return; -+ -+ /* -+ * Is resize2fs going to demand a fsck run? Might as well tell the -+ * user now. -+ */ -+ if (!fsck_requested && -+ ((fs->super->s_state & EXT2_ERROR_FS) || -+ !(fs->super->s_state & EXT2_VALID_FS) || -+ fs->super->s_lastcheck < fs->super->s_mtime)) -+ request_fsck_afterwards(fs); -+ if (fsck_requested) -+ fprintf(stderr, _("After running e2fsck, please run `resize2fs %s %s"), -+ direction > 0 ? "-b" : "-s", fs->device_name); -+ else -+ fprintf(stderr, _("Please run `resize2fs %s %s"), -+ direction > 0 ? "-b" : "-s", fs->device_name); -+ -+ if (undo_file) -+ fprintf(stderr, _(" -z \"%s\""), undo_file); -+ if (direction > 0) -+ fprintf(stderr, _("' to enable 64-bit mode.\n")); -+ else -+ fprintf(stderr, _("' to disable 64-bit mode.\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; -+ errcode_t errcode; -+ struct ext2_extent_info info; -+ -+ if (!(inode->i_flags & EXT4_EXTENTS_FL) || -+ !EXT2_HAS_RO_COMPAT_FEATURE(fs->super, -+ EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) -+ return 0; -+ -+ errcode = ext2fs_extent_open(fs, ino, &handle); -+ if (errcode) -+ return errcode; -+ -+ errcode = ext2fs_extent_get(handle, EXT2_EXTENT_ROOT, &extent); -+ if (errcode) -+ goto out; -+ -+ do { -+ errcode = ext2fs_extent_get_info(handle, &info); -+ if (errcode) -+ break; -+ -+ /* -+ * If this is the first extent in an extent block that we -+ * haven't visited, rewrite the extent to force the ETB -+ * checksum to be rewritten. -+ */ -+ if (info.curr_entry == 1 && info.curr_level != 0 && -+ !(extent.e_flags & EXT2_EXTENT_FLAGS_SECOND_VISIT)) { -+ errcode = ext2fs_extent_replace(handle, 0, &extent); -+ if (errcode) -+ break; -+ } -+ -+ /* Skip to the end of a block of leaf nodes */ -+ if (extent.e_flags & EXT2_EXTENT_FLAGS_LEAF) { -+ errcode = ext2fs_extent_get(handle, -+ EXT2_EXTENT_LAST_SIB, -+ &extent); -+ if (errcode) -+ break; -+ } -+ -+ errcode = ext2fs_extent_get(handle, EXT2_EXTENT_NEXT, &extent); -+ } while (errcode == 0); -+ -+out: -+ /* Ok if we run off the end */ -+ if (errcode == EXT2_ET_EXTENT_NO_NEXT) -+ errcode = 0; -+ ext2fs_extent_free(handle); -+ 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 = NULL; -+ 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 errcode_t 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; -+ -+ /* 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); -+ fs->super->s_feature_ro_compat &= ~csum_feature_flag; -+ if (retval) { -+ com_err("disable_uninit_bg", retval, -+ "while reading bitmaps"); -+ request_fsck_afterwards(fs); -+ return retval; -+ } -+ ext2fs_mark_ib_dirty(fs); -+ ext2fs_mark_bb_dirty(fs); -+ -+ /* 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); -+ return retval; -+ } -+ } -+ -+ /* 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); -+ -+ return 0; -+} -+ - /* - * 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; -+ errcode_t err; - - #define FEATURE_ON(type, mask) (!(old_features[(type)] & (mask)) && \ - ((&sb->s_feature_compat)[(type)] & (mask))) -@@ -606,33 +1140,135 @@ 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); -+ EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) { -+ if (check_fsck_needed(fs)) -+ exit(1); -+ if (mount_flags & EXT2_MF_MOUNTED) { -+ fputs(_("Cannot enable metadata_csum on a mounted " -+ "filesystem!\n"), stderr); -+ exit(1); - } -- fs->flags &= ~EXT2_FLAG_SUPER_ONLY; -+ 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. " -+ "Re-run with -O extent 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. " -+ "Run resize2fs -b to rectify.\n")); -+ 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_METADATA_CSUM)) { -+ __u32 test_features[3]; -+ -+ if (check_fsck_needed(fs)) -+ exit(1); -+ if (mount_flags & EXT2_MF_MOUNTED) { -+ fputs(_("Cannot disable metadata_csum on a mounted " -+ "filesystem!\n"), stderr); -+ exit(1); -+ } -+ rewrite_checksums = 1; -+ -+ /* Enable uninit_bg unless the user expressly turned it off */ -+ memcpy(test_features, old_features, sizeof(test_features)); -+ test_features[E2P_FEATURE_RO_INCOMPAT] |= -+ EXT4_FEATURE_RO_COMPAT_GDT_CSUM; -+ e2p_edit_feature2(features, test_features, ok_features, -+ clear_ok_features, NULL, NULL); -+ if (test_features[E2P_FEATURE_RO_INCOMPAT] & -+ EXT4_FEATURE_RO_COMPAT_GDT_CSUM) -+ fs->super->s_feature_ro_compat |= -+ EXT4_FEATURE_RO_COMPAT_GDT_CSUM; -+ -+ /* -+ * 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)) { -+ err = disable_uninit_bg(fs, -+ EXT4_FEATURE_RO_COMPAT_METADATA_CSUM); -+ if (err) -+ return 1; -+ } 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)) { -- 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; -+ err = disable_uninit_bg(fs, -+ EXT4_FEATURE_RO_COMPAT_GDT_CSUM); -+ if (err) -+ return 1; -+ } -+ -+ /* -+ * We don't actually toggle 64bit; resize2fs does that. But this -+ * must come after the metadata_csum feature_on so that it won't -+ * complain about the lack of 64bit. -+ */ -+ if (FEATURE_ON(E2P_FEATURE_INCOMPAT, -+ EXT4_FEATURE_INCOMPAT_64BIT)) { -+ if (mount_flags & EXT2_MF_MOUNTED) { -+ fprintf(stderr, _("Cannot enable 64-bit mode " -+ "while mounted!\n")); -+ exit(1); - } -- fs->flags &= ~EXT2_FLAG_SUPER_ONLY; -+ sb->s_feature_incompat &= ~EXT4_FEATURE_INCOMPAT_64BIT; -+ feature_64bit = 1; -+ } -+ if (FEATURE_OFF(E2P_FEATURE_INCOMPAT, -+ EXT4_FEATURE_INCOMPAT_64BIT)) { -+ if (mount_flags & EXT2_MF_MOUNTED) { -+ fprintf(stderr, _("Cannot disable 64-bit mode " -+ "while mounted!\n")); -+ exit(1); -+ } -+ sb->s_feature_incompat |= EXT4_FEATURE_INCOMPAT_64BIT; -+ feature_64bit = -1; - } - - if (FEATURE_ON(E2P_FEATURE_RO_INCOMPAT, -@@ -665,6 +1301,13 @@ mmp_error: - grpquota = QOPT_DISABLE; - } - -+ if (FEATURE_ON(E2P_FEATURE_INCOMPAT, EXT4_FEATURE_INCOMPAT_ENCRYPT)) { -+ fs->super->s_encrypt_algos[0] = -+ EXT4_ENCRYPTION_MODE_AES_256_XTS; -+ fs->super->s_encrypt_algos[1] = -+ EXT4_ENCRYPTION_MODE_AES_256_CTS; -+ } -+ - if (sb->s_rev_level == EXT2_GOOD_OLD_REV && - (sb->s_feature_compat || sb->s_feature_ro_compat || - sb->s_feature_incompat)) -@@ -789,8 +1432,7 @@ static void handle_quota_options(ext2_filsys fs) - quota_compute_usage(qctx); - - if (usrquota == QOPT_ENABLE && !fs->super->s_usr_quota_inum) { -- if ((qf_ino = quota_file_exists(fs, USRQUOTA, -- QFMT_VFS_V1)) > 0) -+ if ((qf_ino = quota_file_exists(fs, USRQUOTA)) > 0) - quota_update_limits(qctx, qf_ino, USRQUOTA); - quota_write_inode(qctx, USRQUOTA); - } else if (usrquota == QOPT_DISABLE) { -@@ -798,8 +1440,7 @@ static void handle_quota_options(ext2_filsys fs) - } - - if (grpquota == QOPT_ENABLE && !fs->super->s_grp_quota_inum) { -- if ((qf_ino = quota_file_exists(fs, GRPQUOTA, -- QFMT_VFS_V1)) > 0) -+ if ((qf_ino = quota_file_exists(fs, GRPQUOTA)) > 0) - quota_update_limits(qctx, qf_ino, GRPQUOTA); - quota_write_inode(qctx, GRPQUOTA); - } else if (grpquota == QOPT_DISABLE) { -@@ -820,7 +1461,6 @@ static void handle_quota_options(ext2_filsys fs) - return; - } - --#ifdef CONFIG_QUOTA - static void parse_quota_opts(const char *opts) - { - char *buf, *token, *next, *p; -@@ -863,7 +1503,6 @@ static void parse_quota_opts(const char *opts) - } - free(buf); - } --#endif - - static void parse_e2label_options(int argc, char ** argv) - { -@@ -925,13 +1564,9 @@ static void parse_tune2fs_options(int argc, char **argv) - char *tmp; - struct group *gr; - struct passwd *pw; -- char optstring[100] = "c:e:fg:i:jlm:o:r:s:u:C:E:I:J:L:M:O:T:U:"; -+ char optstring[100] = "c:e:fg:i:jlm:o:r:s:u:C:E:I:J:L:M:O:T:U:z:Q:"; - --#ifdef CONFIG_QUOTA -- strcat(optstring, "Q:"); --#endif - open_flag = 0; -- - printf("tune2fs %s (%s)\n", E2FSPROGS_VERSION, E2FSPROGS_DATE); - while ((c = getopt(argc, argv, optstring)) != EOF) - switch (c) { -@@ -1087,13 +1722,11 @@ static void parse_tune2fs_options(int argc, char **argv) - features_cmd = optarg; - open_flag = EXT2_FLAG_RW; - break; --#ifdef CONFIG_QUOTA - case 'Q': - Q_flag = 1; - parse_quota_opts(optarg); - open_flag = EXT2_FLAG_RW; - break; --#endif - case 'r': - reserved_blocks = strtoul(optarg, &tmp, 0); - if (*tmp) { -@@ -1159,6 +1792,9 @@ static void parse_tune2fs_options(int argc, char **argv) - open_flag = EXT2_FLAG_RW; - I_flag = 1; - break; -+ case 'z': -+ undo_file = optarg; -+ break; - default: - usage(); - } -@@ -1700,6 +2336,8 @@ static int expand_inode_table(ext2_filsys fs, unsigned long new_ino_size) - - /* Update the meta data */ - fs->inode_blocks_per_group = new_ino_blks_per_grp; -+ ext2fs_free_inode_cache(fs->icache); -+ fs->icache = 0; - fs->super->s_inode_size = new_ino_size; - - err_out: -@@ -1874,27 +2512,29 @@ static int tune2fs_setup_tdb(const char *name, io_manager *io_ptr) - { - errcode_t retval = 0; - const char *tdb_dir; -- char *tdb_file; -+ char *tdb_file = NULL; - char *dev_name, *tmp_name; - --#if 0 /* FIXME!! */ -+ /* (re)open a specific undo file */ -+ if (undo_file && undo_file[0] != 0) { -+ retval = set_undo_io_backing_manager(*io_ptr); -+ if (retval) -+ goto err; -+ *io_ptr = undo_io_manager; -+ retval = set_undo_io_backup_file(undo_file); -+ if (retval) -+ goto err; -+ printf(_("Overwriting existing filesystem; this can be undone " -+ "using the command:\n" -+ " e2undo %s %s\n\n"), -+ undo_file, name); -+ return retval; -+ } -+ - /* - * Configuration via a conf file would be - * nice - */ -- profile_get_string(profile, "scratch_files", -- "directory", 0, 0, -- &tdb_dir); --#endif -- tmp_name = strdup(name); -- if (!tmp_name) { -- alloc_fn_fail: -- com_err(program_name, ENOMEM, "%s", -- _("Couldn't allocate memory for tdb filename\n")); -- return ENOMEM; -- } -- dev_name = basename(tmp_name); -- - tdb_dir = getenv("E2FSPROGS_UNDO_DIR"); - if (!tdb_dir) - tdb_dir = "/var/lib/e2fsprogs"; -@@ -1903,31 +2543,47 @@ static int tune2fs_setup_tdb(const char *name, io_manager *io_ptr) - access(tdb_dir, W_OK)) - return 0; - -+ tmp_name = strdup(name); -+ if (!tmp_name) -+ goto errout; -+ dev_name = basename(tmp_name); - tdb_file = malloc(strlen(tdb_dir) + 9 + strlen(dev_name) + 7 + 1); -- if (!tdb_file) -- goto alloc_fn_fail; -+ if (!tdb_file) { -+ free(tmp_name); -+ goto errout; -+ } - sprintf(tdb_file, "%s/tune2fs-%s.e2undo", tdb_dir, dev_name); -+ free(tmp_name); - - if ((unlink(tdb_file) < 0) && (errno != ENOENT)) { - retval = errno; - com_err(program_name, retval, - _("while trying to delete %s"), tdb_file); -- free(tdb_file); -- return retval; -+ goto errout; - } - -- set_undo_io_backing_manager(*io_ptr); -+ retval = set_undo_io_backing_manager(*io_ptr); -+ if (retval) -+ goto errout; - *io_ptr = undo_io_manager; -- set_undo_io_backup_file(tdb_file); -- printf(_("To undo the tune2fs operation please run " -- "the command\n e2undo %s %s\n\n"), -+ retval = set_undo_io_backup_file(tdb_file); -+ if (retval) -+ goto errout; -+ printf(_("Overwriting existing filesystem; this can be undone " -+ "using the command:\n" -+ " e2undo %s %s\n\n"), - tdb_file, name); -+ - free(tdb_file); -- free(tmp_name); -+ return 0; -+errout: -+ free(tdb_file); -+err: -+ com_err("tune2fs", retval, "while trying to setup undo file\n"); - return retval; - } - --int -+static int - fs_update_journal_user(struct ext2_super_block *sb, __u8 old_uuid[UUID_SIZE]) - { - int retval, nr_users, start; -@@ -1936,7 +2592,7 @@ fs_update_journal_user(struct ext2_super_block *sb, __u8 old_uuid[UUID_SIZE]) - __u8 *j_uuid; - char *journal_path; - char uuid[UUID_STR_SIZE]; -- char buf[SUPERBLOCK_SIZE]; -+ char buf[SUPERBLOCK_SIZE] __attribute__ ((aligned(8))); - - if (!(sb->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL) || - uuid_is_null(sb->s_journal_uuid)) -@@ -1992,13 +2648,18 @@ fs_update_journal_user(struct ext2_super_block *sb, __u8 old_uuid[UUID_SIZE]) - return 0; - } - -+#ifndef BUILD_AS_LIB - int main(int argc, char **argv) -+#else -+int tune2fs_main(int argc, char **argv) -+#endif /* BUILD_AS_LIB */ - { - errcode_t retval; - ext2_filsys fs; - struct ext2_super_block *sb; - io_manager io_ptr, io_ptr_orig = NULL; - int rc = 0; -+ char default_undo_file[1] = { 0 }; - - #ifdef ENABLE_NLS - setlocale(LC_MESSAGES, ""); -@@ -2032,7 +2693,7 @@ retry_open: - if ((open_flag & EXT2_FLAG_RW) == 0 || f_flag) - open_flag |= EXT2_FLAG_SKIP_MMP; - -- open_flag |= EXT2_FLAG_64BITS; -+ open_flag |= EXT2_FLAG_64BITS | EXT2_FLAG_JOURNAL_DEV_OK; - - /* keep the filesystem struct around to dump MMP data */ - open_flag |= EXT2_FLAG_NOFREE_ON_ERROR; -@@ -2055,6 +2716,8 @@ retry_open: - fprintf(stderr, - _("MMP block magic is bad. Try to fix it by " - "running:\n'e2fsck -f %s'\n"), device_name); -+ else if (retval == EXT2_ET_BAD_MAGIC) -+ check_plausibility(device_name, CHECK_FS_EXIST, NULL); - else if (retval != EXT2_ET_MMP_FAILED) - fprintf(stderr, "%s", - _("Couldn't find valid filesystem superblock.\n")); -@@ -2062,9 +2725,15 @@ retry_open: - ext2fs_free(fs); - exit(1); - } -+ if (EXT2_HAS_INCOMPAT_FEATURE(fs->super, -+ EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)) { -+ fprintf(stderr, "%s", _("Cannot modify a journal device.\n")); -+ ext2fs_free(fs); -+ exit(1); -+ } - fs->default_bitmap_type = EXT2FS_BMAP64_RBTREE; - -- if (I_flag && !io_ptr_orig) { -+ if (I_flag) { - /* - * Check the inode size is right so we can issue an - * error message and bail before setting up the tdb -@@ -2088,11 +2757,15 @@ retry_open: - rc = 1; - goto closefs; - } -- - /* - * If inode resize is requested use the - * Undo I/O manager - */ -+ undo_file = default_undo_file; -+ } -+ -+ /* Set up an undo file */ -+ if (undo_file && io_ptr_orig == NULL) { - io_ptr_orig = io_ptr; - retval = tune2fs_setup_tdb(device_name, &io_ptr); - if (retval) { -@@ -2279,11 +2952,10 @@ retry_open: - if (U_flag) { - int set_csum = 0; - dgrp_t i; -- char buf[SUPERBLOCK_SIZE]; -+ char buf[SUPERBLOCK_SIZE] __attribute__ ((aligned(8))); - __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. -@@ -2323,6 +2995,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); -@@ -2352,7 +3025,11 @@ 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 (I_flag) { - if (mount_flags & EXT2_MF_MOUNTED) { - fputs(_("The inode size may only be " -@@ -2374,10 +3051,16 @@ retry_open: - * We want to update group descriptor also - * with the new free inode count - */ -+ if (rewrite_checksums) -+ fs->flags |= EXT2_FLAG_IGNORE_CSUM_ERRORS; - fs->flags &= ~EXT2_FLAG_SUPER_ONLY; -- if (resize_inode(fs, new_inode_size) == 0) { -+ retval = resize_inode(fs, new_inode_size); -+ if (rewrite_checksums) -+ fs->flags &= ~EXT2_FLAG_IGNORE_CSUM_ERRORS; -+ if (retval == 0) { - printf(_("Setting inode size %lu\n"), - new_inode_size); -+ rewrite_checksums = 1; - } else { - printf("%s", _("Failed to change inode size\n")); - rc = 1; -@@ -2385,6 +3068,9 @@ retry_open: - } - } - -+ if (rewrite_checksums) -+ rewrite_metadata_checksums(fs); -+ - if (l_flag) - list_super(sb); - if (stride_set) { -@@ -2412,8 +3098,11 @@ retry_open: - closefs: - if (rc) { - ext2fs_mmp_stop(fs); -+#ifndef BUILD_AS_LIB - exit(1); -+#endif - } - -+ convert_64bit(fs, feature_64bit); - return (ext2fs_close_free(&fs) ? 1 : 0); - } -diff --git a/misc/tune2fs.h b/misc/tune2fs.h -new file mode 100644 -index 0000000..897e336 ---- /dev/null -+++ b/misc/tune2fs.h -@@ -0,0 +1,13 @@ -+/* -+ * tune2fs.h - Change the file system parameters on an ext2 file system -+ * -+ * %Begin-Header% -+ * This file may be redistributed under the terms of the GNU Public -+ * License. -+ * %End-Header% -+ */ -+ -+/* Takes exactly the same args as the tune2fs exectuable. -+ * Is the entrypoint for libtune2fs. -+ */ -+int tune2fs_main(int argc, char **argv); -diff --git a/misc/util.c b/misc/util.c -index 2898830..36cea7b 100644 ---- a/misc/util.c -+++ b/misc/util.c -@@ -9,8 +9,12 @@ - * %End-Header% - */ - -+#ifndef _LARGEFILE_SOURCE - #define _LARGEFILE_SOURCE -+#endif -+#ifndef _LARGEFILE64_SOURCE - #define _LARGEFILE64_SOURCE -+#endif - - #include "config.h" - #include -@@ -37,7 +41,7 @@ - #include "e2p/e2p.h" - #include "ext2fs/ext2_fs.h" - #include "ext2fs/ext2fs.h" --#include "nls-enable.h" -+#include "support/nls-enable.h" - #include "blkid/blkid.h" - #include "util.h" - -@@ -75,7 +79,7 @@ char *get_progname(char *argv_zero) - - static jmp_buf alarm_env; - --static void alarm_signal(int signal) -+static void alarm_signal(int signal EXT2FS_ATTR((unused))) - { - longjmp(alarm_env, 1); - } -@@ -108,203 +112,6 @@ void proceed_question(int delay) - signal(SIGALRM, SIG_IGN); - } - --static void print_ext2_info(const char *device) -- --{ -- struct ext2_super_block *sb; -- ext2_filsys fs; -- errcode_t retval; -- time_t tm; -- char buf[80]; -- -- retval = ext2fs_open2(device, 0, EXT2_FLAG_64BITS, 0, 0, -- unix_io_manager, &fs); -- if (retval) -- return; -- sb = fs->super; -- -- if (sb->s_mtime) { -- tm = sb->s_mtime; -- if (sb->s_last_mounted[0]) { -- memset(buf, 0, sizeof(buf)); -- strncpy(buf, sb->s_last_mounted, -- sizeof(sb->s_last_mounted)); -- printf(_("\tlast mounted on %s on %s"), buf, -- ctime(&tm)); -- } else -- printf(_("\tlast mounted on %s"), ctime(&tm)); -- } else if (sb->s_mkfs_time) { -- tm = sb->s_mkfs_time; -- printf(_("\tcreated on %s"), ctime(&tm)); -- } else if (sb->s_wtime) { -- tm = sb->s_wtime; -- printf(_("\tlast modified on %s"), ctime(&tm)); -- } -- ext2fs_close_free(&fs); --} -- --/* -- * return 1 if there is no partition table, 0 if a partition table is -- * detected, and -1 on an error. -- */ --static int check_partition_table(const char *device) --{ --#ifdef HAVE_BLKID_PROBE_ENABLE_PARTITIONS -- blkid_probe pr; -- const char *value; -- int ret; -- -- pr = blkid_new_probe_from_filename(device); -- if (!pr) -- return -1; -- -- ret = blkid_probe_enable_partitions(pr, 1); -- if (ret < 0) -- goto errout; -- -- ret = blkid_probe_enable_superblocks(pr, 0); -- if (ret < 0) -- goto errout; -- -- ret = blkid_do_fullprobe(pr); -- if (ret < 0) -- goto errout; -- -- ret = blkid_probe_lookup_value(pr, "PTTYPE", &value, NULL); -- if (ret == 0) -- fprintf(stderr, _("Found a %s partition table in %s\n"), -- value, device); -- else -- ret = 1; -- --errout: -- blkid_free_probe(pr); -- return ret; --#else -- return -1; --#endif --} -- --/* -- * return 1 if the device looks plausible, creating the file if necessary -- */ --int check_plausibility(const char *device, int flags, int *ret_is_dev) --{ -- int fd, ret, is_dev = 0; -- ext2fs_struct_stat s; -- int fl = O_RDONLY; -- blkid_cache cache = NULL; -- char *fs_type = NULL; -- char *fs_label = NULL; -- -- fd = ext2fs_open_file(device, fl, 0666); -- if ((fd < 0) && (errno == ENOENT) && (flags & NO_SIZE)) { -- fprintf(stderr, _("The file %s does not exist and no " -- "size was specified.\n"), device); -- exit(1); -- } -- if ((fd < 0) && (errno == ENOENT) && (flags & CREATE_FILE)) { -- fl |= O_CREAT; -- fd = ext2fs_open_file(device, fl, 0666); -- if (fd >= 0 && (flags & VERBOSE_CREATE)) -- printf(_("Creating regular file %s\n"), device); -- } -- if (fd < 0) { -- fprintf(stderr, _("Could not open %s: %s\n"), -- device, error_message(errno)); -- if (errno == ENOENT) -- fputs(_("\nThe device apparently does not exist; " -- "did you specify it correctly?\n"), stderr); -- exit(1); -- } -- -- if (ext2fs_fstat(fd, &s) < 0) { -- perror("stat"); -- exit(1); -- } -- close(fd); -- -- if (S_ISBLK(s.st_mode)) -- is_dev = 1; --#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) -- /* On FreeBSD, all disk devices are character specials */ -- if (S_ISCHR(s.st_mode)) -- is_dev = 1; --#endif -- if (ret_is_dev) -- *ret_is_dev = is_dev; -- -- if ((flags & CHECK_BLOCK_DEV) && !is_dev) { -- printf(_("%s is not a block special device.\n"), device); -- return 0; -- } -- -- /* -- * Note: we use the older-style blkid API's here because we -- * want as much functionality to be available when using the -- * internal blkid library, when e2fsprogs is compiled for -- * non-Linux systems that will probably not have the libraries -- * from util-linux available. We only use the newer -- * blkid-probe interfaces to access functionality not -- * available in the original blkid library. -- */ -- if ((flags & CHECK_FS_EXIST) && blkid_get_cache(&cache, NULL) >= 0) { -- fs_type = blkid_get_tag_value(cache, "TYPE", device); -- if (fs_type) -- fs_label = blkid_get_tag_value(cache, "LABEL", device); -- blkid_put_cache(cache); -- } -- -- if (fs_type) { -- if (fs_label) -- printf(_("%s contains a %s file system " -- "labelled '%s'\n"), device, fs_type, fs_label); -- else -- printf(_("%s contains a %s file system\n"), device, -- fs_type); -- if (strncmp(fs_type, "ext", 3) == 0) -- print_ext2_info(device); -- free(fs_type); -- free(fs_label); -- return 0; -- } -- -- ret = check_partition_table(device); -- if (ret >= 0) -- return ret; -- --#ifdef HAVE_LINUX_MAJOR_H --#ifndef MAJOR --#define MAJOR(dev) ((dev)>>8) --#define MINOR(dev) ((dev) & 0xff) --#endif --#ifndef SCSI_BLK_MAJOR --#ifdef SCSI_DISK0_MAJOR --#ifdef SCSI_DISK8_MAJOR --#define SCSI_DISK_MAJOR(M) ((M) == SCSI_DISK0_MAJOR || \ -- ((M) >= SCSI_DISK1_MAJOR && (M) <= SCSI_DISK7_MAJOR) || \ -- ((M) >= SCSI_DISK8_MAJOR && (M) <= SCSI_DISK15_MAJOR)) --#else --#define SCSI_DISK_MAJOR(M) ((M) == SCSI_DISK0_MAJOR || \ -- ((M) >= SCSI_DISK1_MAJOR && (M) <= SCSI_DISK7_MAJOR)) --#endif /* defined(SCSI_DISK8_MAJOR) */ --#define SCSI_BLK_MAJOR(M) (SCSI_DISK_MAJOR((M)) || (M) == SCSI_CDROM_MAJOR) --#else --#define SCSI_BLK_MAJOR(M) ((M) == SCSI_DISK_MAJOR || (M) == SCSI_CDROM_MAJOR) --#endif /* defined(SCSI_DISK0_MAJOR) */ --#endif /* defined(SCSI_BLK_MAJOR) */ -- if (((MAJOR(s.st_rdev) == HD_MAJOR && -- MINOR(s.st_rdev)%64 == 0) || -- (SCSI_BLK_MAJOR(MAJOR(s.st_rdev)) && -- MINOR(s.st_rdev)%16 == 0))) { -- printf(_("%s is entire device, not just one partition!\n"), -- device); -- return 0; -- } --#endif -- return 1; --} -- - void check_mount(const char *device, int force, const char *type) - { - errcode_t retval; -diff --git a/misc/util.h b/misc/util.h -index f3827dd..49b4b9c 100644 ---- a/misc/util.h -+++ b/misc/util.h -@@ -15,22 +15,11 @@ extern int journal_flags; - extern char *journal_device; - extern char *journal_location_string; - --/* -- * Flags for check_plausibility() -- */ --#define CHECK_BLOCK_DEV 0x0001 --#define CREATE_FILE 0x0002 --#define CHECK_FS_EXIST 0x0004 --#define VERBOSE_CREATE 0x0008 --#define NO_SIZE 0x0010 -- - #ifndef HAVE_STRCASECMP - extern int strcasecmp (char *s1, char *s2); - #endif - extern char *get_progname(char *argv_zero); - extern void proceed_question(int delay); --extern int check_plausibility(const char *device, int flags, -- int *ret_is_dev); - extern void parse_journal_opts(const char *opts); - extern void check_mount(const char *device, int force, const char *type); - extern unsigned int figure_journal_size(int size, ext2_filsys fs); -diff --git a/misc/uuidd.c b/misc/uuidd.c -index 02ca6be..4db3fa9 100644 ---- a/misc/uuidd.c -+++ b/misc/uuidd.c -@@ -35,7 +35,7 @@ extern int optind; - #endif - #include "uuid/uuid.h" - #include "uuid/uuidd.h" --#include "nls-enable.h" -+#include "support/nls-enable.h" - #include "ext2fs/ext2fs.h" - - #ifdef __GNUC__ -diff --git a/misc/uuidgen.c b/misc/uuidgen.c -index f181d19..1233f3d 100644 ---- a/misc/uuidgen.c -+++ b/misc/uuidgen.c -@@ -22,7 +22,7 @@ extern char *optarg; - extern int optind; - #endif - #include "uuid/uuid.h" --#include "nls-enable.h" -+#include "support/nls-enable.h" - - #define DO_TYPE_TIME 1 - #define DO_TYPE_RANDOM 2 -diff --git a/resize/Android.mk b/resize/Android.mk -new file mode 100644 -index 0000000..1cbd01e ---- /dev/null -+++ b/resize/Android.mk -@@ -0,0 +1,45 @@ -+LOCAL_PATH := $(call my-dir) -+ -+resize2fs_src_files := \ -+ extent.c \ -+ resize2fs.c \ -+ main.c \ -+ online.c \ -+ sim_progress.c \ -+ resource_track.c -+ -+resize2fs_c_includes := external/e2fsprogs/lib -+ -+resize2fs_cflags := -O2 -g -W -Wall -+ -+resize2fs_shared_libraries := \ -+ libext2fs \ -+ libext2_com_err \ -+ libext2_e2p \ -+ libext2_uuid \ -+ libext2_blkid -+ -+resize2fs_system_shared_libraries := libc -+ -+include $(CLEAR_VARS) -+ -+LOCAL_SRC_FILES := $(resize2fs_src_files) -+LOCAL_C_INCLUDES := $(resize2fs_c_includes) -+LOCAL_CFLAGS := $(resize2fs_cflags) -+LOCAL_SHARED_LIBRARIES := $(resize2fs_shared_libraries) -+LOCAL_SYSTEM_SHARED_LIBRARIES := $(resize2fs_system_shared_libraries) -+LOCAL_MODULE := resize2fs -+LOCAL_MODULE_TAGS := optional -+include $(BUILD_EXECUTABLE) -+ -+include $(CLEAR_VARS) -+ -+LOCAL_SRC_FILES := $(resize2fs_src_files) -+LOCAL_C_INCLUDES := $(resize2fs_c_includes) -+LOCAL_CFLAGS := $(resize2fs_cflags) -+LOCAL_SHARED_LIBRARIES := $(addsuffix _host, $(resize2fs_shared_libraries)) -+LOCAL_MODULE := resize2fs_host -+LOCAL_MODULE_STEM := resize2fs -+LOCAL_MODULE_TAGS := optional -+ -+include $(BUILD_HOST_EXECUTABLE) -diff --git a/resize/Makefile.in b/resize/Makefile.in -index 29f55d0..ecd8619 100644 ---- a/resize/Makefile.in -+++ b/resize/Makefile.in -@@ -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) - -diff --git a/resize/main.c b/resize/main.c -index 9a35af0..3be458f 100644 ---- a/resize/main.c -+++ b/resize/main.c -@@ -12,8 +12,12 @@ - * %End-Header% - */ - -+#ifndef _LARGEFILE_SOURCE - #define _LARGEFILE_SOURCE -+#endif -+#ifndef _LARGEFILE64_SOURCE - #define _LARGEFILE64_SOURCE -+#endif - - #include "config.h" - #ifdef HAVE_GETOPT_H -@@ -29,6 +33,7 @@ extern int optind; - #include - #include - #include -+#include - - #include "e2p/e2p.h" - -@@ -42,7 +47,8 @@ static char *device_name, *io_options; - static void usage (char *prog) - { - fprintf (stderr, _("Usage: %s [-d debug_flags] [-f] [-F] [-M] [-P] " -- "[-p] device [new_size]\n\n"), prog); -+ "[-p] device [-b|-s|new_size] [-z undo_file]\n\n"), -+ prog); - - exit (1); - } -@@ -105,6 +111,7 @@ static void determine_fs_stride(ext2_filsys fs) - unsigned long long sum; - unsigned int has_sb, prev_has_sb = 0, num; - int i_stride, b_stride; -+ int flexbg_size = 1 << fs->super->s_log_groups_per_flex; - - if (fs->stride) - return; -@@ -120,7 +127,8 @@ static void determine_fs_stride(ext2_filsys fs) - ext2fs_inode_bitmap_loc(fs, group - 1) - - fs->super->s_blocks_per_group; - if (b_stride != i_stride || -- b_stride < 0) -+ b_stride < 0 || -+ (flexbg_size > 1 && (group % flexbg_size == 0))) - goto next; - - /* printf("group %d has stride %d\n", group, b_stride); */ -@@ -160,6 +168,81 @@ static void bigalloc_check(ext2_filsys fs, int force) - } - } - -+static int resize2fs_setup_tdb(const char *device_name, char *undo_file, -+ io_manager *io_ptr) -+{ -+ errcode_t retval = ENOMEM; -+ char *tdb_dir = NULL, *tdb_file = NULL; -+ char *dev_name, *tmp_name; -+ -+ /* (re)open a specific undo file */ -+ if (undo_file && undo_file[0] != 0) { -+ retval = set_undo_io_backing_manager(*io_ptr); -+ if (retval) -+ goto err; -+ *io_ptr = undo_io_manager; -+ retval = set_undo_io_backup_file(undo_file); -+ if (retval) -+ goto err; -+ printf(_("Overwriting existing filesystem; this can be undone " -+ "using the command:\n" -+ " e2undo %s %s\n\n"), -+ undo_file, device_name); -+ return retval; -+ } -+ -+ /* -+ * Configuration via a conf file would be -+ * nice -+ */ -+ tdb_dir = getenv("E2FSPROGS_UNDO_DIR"); -+ if (!tdb_dir) -+ tdb_dir = "/var/lib/e2fsprogs"; -+ -+ if (!strcmp(tdb_dir, "none") || (tdb_dir[0] == 0) || -+ access(tdb_dir, W_OK)) -+ return 0; -+ -+ tmp_name = strdup(device_name); -+ if (!tmp_name) -+ goto errout; -+ dev_name = basename(tmp_name); -+ tdb_file = malloc(strlen(tdb_dir) + 11 + strlen(dev_name) + 7 + 1); -+ if (!tdb_file) { -+ free(tmp_name); -+ goto errout; -+ } -+ sprintf(tdb_file, "%s/resize2fs-%s.e2undo", tdb_dir, dev_name); -+ free(tmp_name); -+ -+ if ((unlink(tdb_file) < 0) && (errno != ENOENT)) { -+ retval = errno; -+ com_err(program_name, retval, -+ _("while trying to delete %s"), tdb_file); -+ goto errout; -+ } -+ -+ retval = set_undo_io_backing_manager(*io_ptr); -+ if (retval) -+ goto errout; -+ *io_ptr = undo_io_manager; -+ retval = set_undo_io_backup_file(tdb_file); -+ if (retval) -+ goto errout; -+ printf(_("Overwriting existing filesystem; this can be undone " -+ "using the command:\n" -+ " e2undo %s %s\n\n"), tdb_file, device_name); -+ -+ free(tdb_file); -+ return 0; -+errout: -+ free(tdb_file); -+err: -+ com_err(program_name, retval, "%s", -+ _("while trying to setup undo file\n")); -+ return retval; -+} -+ - int main (int argc, char ** argv) - { - errcode_t retval; -@@ -184,7 +267,7 @@ int main (int argc, char ** argv) - unsigned int blocksize; - long sysval; - int len, mount_flags; -- char *mtpt; -+ char *mtpt, *undo_file = NULL; - - #ifdef ENABLE_NLS - setlocale(LC_MESSAGES, ""); -@@ -201,7 +284,7 @@ int main (int argc, char ** argv) - if (argc && *argv) - program_name = *argv; - -- while ((c = getopt (argc, argv, "d:fFhMPpS:")) != EOF) { -+ while ((c = getopt(argc, argv, "d:fFhMPpS:bsz:")) != EOF) { - switch (c) { - case 'h': - usage(program_name); -@@ -227,6 +310,15 @@ int main (int argc, char ** argv) - case 'S': - use_stride = atoi(optarg); - break; -+ case 'b': -+ flags |= RESIZE_ENABLE_64BIT; -+ break; -+ case 's': -+ flags |= RESIZE_DISABLE_64BIT; -+ break; -+ case 'z': -+ undo_file = optarg; -+ break; - default: - usage(program_name); - } -@@ -310,7 +402,11 @@ int main (int argc, char ** argv) - io_flags = EXT2_FLAG_RW | EXT2_FLAG_EXCLUSIVE; - - io_flags |= EXT2_FLAG_64BITS; -- -+ if (undo_file) { -+ retval = resize2fs_setup_tdb(device_name, undo_file, &io_ptr); -+ if (retval) -+ exit(1); -+ } - retval = ext2fs_open2(device_name, io_options, io_flags, - 0, 0, io_ptr, &fs); - if (retval) { -@@ -411,6 +507,10 @@ int main (int argc, char ** argv) - if (sys_page_size > blocksize) - new_size &= ~((sys_page_size / blocksize)-1); - } -+ /* If changing 64bit, don't change the filesystem size. */ -+ if (flags & (RESIZE_DISABLE_64BIT | RESIZE_ENABLE_64BIT)) { -+ new_size = ext2fs_blocks_count(fs->super); -+ } - if (!EXT2_HAS_INCOMPAT_FEATURE(fs->super, - EXT4_FEATURE_INCOMPAT_64BIT)) { - /* Take 16T down to 2^32-1 blocks */ -@@ -462,20 +562,58 @@ int main (int argc, char ** argv) - blocksize / 1024, new_size); - exit(1); - } -- if (new_size == ext2fs_blocks_count(fs->super)) { -+ if ((flags & RESIZE_DISABLE_64BIT) && (flags & RESIZE_ENABLE_64BIT)) { -+ fprintf(stderr, _("Cannot set and unset 64bit feature.\n")); -+ exit(1); -+ } else if (flags & (RESIZE_DISABLE_64BIT | RESIZE_ENABLE_64BIT)) { -+ if (new_size >= (1ULL << 32)) { -+ fprintf(stderr, _("Cannot change the 64bit feature " -+ "on a filesystem that is larger than " -+ "2^32 blocks.\n")); -+ exit(1); -+ } -+ if (mount_flags & EXT2_MF_MOUNTED) { -+ fprintf(stderr, _("Cannot change the 64bit feature " -+ "while the filesystem is mounted.\n")); -+ exit(1); -+ } -+ if (flags & RESIZE_ENABLE_64BIT && -+ !EXT2_HAS_INCOMPAT_FEATURE(fs->super, -+ EXT3_FEATURE_INCOMPAT_EXTENTS)) { -+ fprintf(stderr, _("Please enable the extents feature " -+ "with tune2fs before enabling the 64bit " -+ "feature.\n")); -+ exit(1); -+ } -+ } else if (new_size == ext2fs_blocks_count(fs->super)) { - fprintf(stderr, _("The filesystem is already %llu (%dk) " - "blocks long. Nothing to do!\n\n"), new_size, - blocksize / 1024); - exit(0); - } -+ if ((flags & RESIZE_ENABLE_64BIT) && -+ EXT2_HAS_INCOMPAT_FEATURE(fs->super, EXT4_FEATURE_INCOMPAT_64BIT)) { -+ fprintf(stderr, _("The filesystem is already 64-bit.\n")); -+ exit(0); -+ } -+ if ((flags & RESIZE_DISABLE_64BIT) && -+ !EXT2_HAS_INCOMPAT_FEATURE(fs->super, EXT4_FEATURE_INCOMPAT_64BIT)) { -+ fprintf(stderr, _("The filesystem is already 32-bit.\n")); -+ exit(0); -+ } - if (mount_flags & EXT2_MF_MOUNTED) { - bigalloc_check(fs, force); - retval = online_resize_fs(fs, mtpt, &new_size, flags); - } else { - bigalloc_check(fs, force); -- printf(_("Resizing the filesystem on " -- "%s to %llu (%dk) blocks.\n"), -- device_name, new_size, blocksize / 1024); -+ if (flags & RESIZE_ENABLE_64BIT) -+ printf(_("Converting the filesystem to 64-bit.\n")); -+ else if (flags & RESIZE_DISABLE_64BIT) -+ printf(_("Converting the filesystem to 32-bit.\n")); -+ else -+ printf(_("Resizing the filesystem on " -+ "%s to %llu (%dk) blocks.\n"), -+ device_name, new_size, blocksize / 1024); - retval = resize_fs(fs, &new_size, flags, - ((flags & RESIZE_PERCENT_COMPLETE) ? - resize_progress_func : 0)); -diff --git a/resize/resize2fs.8.in b/resize/resize2fs.8.in -index 86495c6..d2738e9 100644 ---- a/resize/resize2fs.8.in -+++ b/resize/resize2fs.8.in -@@ -8,7 +8,7 @@ resize2fs \- ext2/ext3/ext4 file system resizer - .SH SYNOPSIS - .B resize2fs - [ --.B \-fFpPM -+.B \-fFpPMbs - ] - [ - .B \-d -@@ -18,6 +18,10 @@ resize2fs \- ext2/ext3/ext4 file system resizer - .B \-S - .I RAID-stride - ] -+[ -+.B \-z -+.I undo_file -+] - .I device - [ - .I size -@@ -86,8 +90,21 @@ to shrink the size of filesystem. Then you may use - to shrink the size of the partition. When shrinking the size of - the partition, make sure you do not make it smaller than the new size - of the ext2 filesystem! -+.PP -+The -+.B \-b -+and -+.B \-s -+options enable and disable the 64bit feature, respectively. The resize2fs -+program will, of course, take care of resizing the block group descriptors -+and moving other data blocks out of the way, as needed. It is not possible -+to resize the filesystem concurrent with changing the 64bit status. - .SH OPTIONS - .TP -+.B \-b -+Turns on the 64bit feature, resizes the group descriptors as necessary, and -+moves other metadata out of the way. -+.TP - .B \-d \fIdebug-flags - Turns on various resize2fs debugging features, if they have been compiled - into the binary. -@@ -127,12 +144,25 @@ of what the program is doing. - .B \-P - Print the minimum size of the filesystem and exit. - .TP -+.B \-s -+Turns off the 64bit feature and frees blocks that are no longer in use. -+.TP - .B \-S \fIRAID-stride - The - .B resize2fs - program will heuristically determine the RAID stride that was specified - when the filesystem was created. This option allows the user to - explicitly specify a RAID stride setting to be used by resize2fs instead. -+.TP -+.BI \-z " undo_file" -+Before overwriting a file system block, write the old contents of the block to -+an undo file. This undo file can be used with e2undo(8) to restore the old -+contents of the file system should something go wrong. If the empty string is -+passed as the undo_file argument, the undo file will be written to a file named -+resize2fs-\fIdevice\fR.e2undo in the directory specified via the -+\fIE2FSPROGS_UNDO_DIR\fR environment variable. -+ -+WARNING: The undo file cannot be used to recover from a power or system crash. - .SH KNOWN BUGS - The minimum size of the filesystem as estimated by resize2fs may be - incorrect, especially for filesystems with 1k and 2k blocksizes. -diff --git a/resize/resize2fs.c b/resize/resize2fs.c -index a2806b1..07c6a0c 100644 ---- a/resize/resize2fs.c -+++ b/resize/resize2fs.c -@@ -56,6 +56,9 @@ static errcode_t mark_table_blocks(ext2_filsys fs, - static errcode_t clear_sparse_super2_last_group(ext2_resize_t rfs); - static errcode_t reserve_sparse_super2_last_group(ext2_resize_t rfs, - ext2fs_block_bitmap meta_bmap); -+static errcode_t resize_group_descriptors(ext2_resize_t rfs, blk64_t new_size); -+static errcode_t move_bg_metadata(ext2_resize_t rfs); -+static errcode_t zero_high_bits_in_inodes(ext2_resize_t rfs); - - /* - * Some helper CPP macros -@@ -122,13 +125,30 @@ errcode_t resize_fs(ext2_filsys fs, blk64_t *new_size, int flags, - if (retval) - goto errout; - -+ init_resource_track(&rtrack, "resize_group_descriptors", fs->io); -+ retval = resize_group_descriptors(rfs, *new_size); -+ if (retval) -+ goto errout; -+ print_resource_track(rfs, &rtrack, fs->io); -+ -+ init_resource_track(&rtrack, "move_bg_metadata", fs->io); -+ retval = move_bg_metadata(rfs); -+ if (retval) -+ goto errout; -+ print_resource_track(rfs, &rtrack, fs->io); -+ -+ init_resource_track(&rtrack, "zero_high_bits_in_metadata", fs->io); -+ retval = zero_high_bits_in_inodes(rfs); -+ if (retval) -+ goto errout; -+ print_resource_track(rfs, &rtrack, fs->io); -+ - init_resource_track(&rtrack, "adjust_superblock", fs->io); - retval = adjust_superblock(rfs, *new_size); - if (retval) - goto errout; - print_resource_track(rfs, &rtrack, fs->io); - -- - init_resource_track(&rtrack, "fix_uninit_block_bitmaps 2", fs->io); - fix_uninit_block_bitmaps(rfs->new_fs); - print_resource_track(rfs, &rtrack, fs->io); -@@ -198,6 +218,10 @@ errcode_t resize_fs(ext2_filsys fs, blk64_t *new_size, int flags, - if (retval) - goto errout; - -+ retval = ext2fs_set_gdt_csum(rfs->new_fs); -+ if (retval) -+ goto errout; -+ - rfs->new_fs->super->s_state &= ~EXT2_ERROR_FS; - rfs->new_fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY; - -@@ -231,6 +255,322 @@ errout: - return retval; - } - -+/* Keep the size of the group descriptor region constant */ -+static void adjust_reserved_gdt_blocks(ext2_filsys old_fs, ext2_filsys fs) -+{ -+ if ((fs->super->s_feature_compat & -+ EXT2_FEATURE_COMPAT_RESIZE_INODE) && -+ (old_fs->desc_blocks != fs->desc_blocks)) { -+ int new; -+ -+ new = ((int) fs->super->s_reserved_gdt_blocks) + -+ (old_fs->desc_blocks - fs->desc_blocks); -+ if (new < 0) -+ new = 0; -+ if (new > (int) fs->blocksize/4) -+ new = fs->blocksize/4; -+ fs->super->s_reserved_gdt_blocks = new; -+ } -+} -+ -+/* Toggle 64bit mode */ -+static errcode_t resize_group_descriptors(ext2_resize_t rfs, blk64_t new_size) -+{ -+ void *o, *n, *new_group_desc; -+ dgrp_t i; -+ int copy_size; -+ errcode_t retval; -+ -+ if (!(rfs->flags & (RESIZE_DISABLE_64BIT | RESIZE_ENABLE_64BIT))) -+ return 0; -+ -+ if (new_size != ext2fs_blocks_count(rfs->new_fs->super) || -+ ext2fs_blocks_count(rfs->new_fs->super) >= (1ULL << 32) || -+ (rfs->flags & RESIZE_DISABLE_64BIT && -+ rfs->flags & RESIZE_ENABLE_64BIT)) -+ return EXT2_ET_INVALID_ARGUMENT; -+ -+ if (rfs->flags & RESIZE_DISABLE_64BIT) { -+ rfs->new_fs->super->s_feature_incompat &= -+ ~EXT4_FEATURE_INCOMPAT_64BIT; -+ rfs->new_fs->super->s_desc_size = EXT2_MIN_DESC_SIZE; -+ } else if (rfs->flags & RESIZE_ENABLE_64BIT) { -+ rfs->new_fs->super->s_feature_incompat |= -+ EXT4_FEATURE_INCOMPAT_64BIT; -+ rfs->new_fs->super->s_desc_size = EXT2_MIN_DESC_SIZE_64BIT; -+ } -+ -+ if (EXT2_DESC_SIZE(rfs->old_fs->super) == -+ EXT2_DESC_SIZE(rfs->new_fs->super)) -+ return 0; -+ -+ o = rfs->new_fs->group_desc; -+ rfs->new_fs->desc_blocks = ext2fs_div_ceil( -+ rfs->old_fs->group_desc_count, -+ EXT2_DESC_PER_BLOCK(rfs->new_fs->super)); -+ retval = ext2fs_get_arrayzero(rfs->new_fs->desc_blocks, -+ rfs->old_fs->blocksize, &new_group_desc); -+ if (retval) -+ return retval; -+ -+ n = new_group_desc; -+ -+ if (EXT2_DESC_SIZE(rfs->old_fs->super) <= -+ EXT2_DESC_SIZE(rfs->new_fs->super)) -+ copy_size = EXT2_DESC_SIZE(rfs->old_fs->super); -+ else -+ copy_size = EXT2_DESC_SIZE(rfs->new_fs->super); -+ for (i = 0; i < rfs->old_fs->group_desc_count; i++) { -+ memcpy(n, o, copy_size); -+ n += EXT2_DESC_SIZE(rfs->new_fs->super); -+ o += EXT2_DESC_SIZE(rfs->old_fs->super); -+ } -+ -+ ext2fs_free_mem(&rfs->new_fs->group_desc); -+ rfs->new_fs->group_desc = new_group_desc; -+ -+ for (i = 0; i < rfs->old_fs->group_desc_count; i++) -+ ext2fs_group_desc_csum_set(rfs->new_fs, i); -+ -+ adjust_reserved_gdt_blocks(rfs->old_fs, rfs->new_fs); -+ -+ return 0; -+} -+ -+/* Move bitmaps/inode tables out of the way. */ -+static errcode_t move_bg_metadata(ext2_resize_t rfs) -+{ -+ dgrp_t i; -+ blk64_t b, c, d, old_desc_blocks, new_desc_blocks, j; -+ ext2fs_block_bitmap old_map, new_map; -+ int old, new; -+ errcode_t retval; -+ int cluster_ratio; -+ -+ if (!(rfs->flags & (RESIZE_DISABLE_64BIT | RESIZE_ENABLE_64BIT))) -+ return 0; -+ -+ retval = ext2fs_allocate_block_bitmap(rfs->old_fs, "oldfs", &old_map); -+ if (retval) -+ return retval; -+ -+ retval = ext2fs_allocate_block_bitmap(rfs->new_fs, "newfs", &new_map); -+ if (retval) -+ goto out; -+ -+ if (EXT2_HAS_INCOMPAT_FEATURE(rfs->old_fs->super, -+ EXT2_FEATURE_INCOMPAT_META_BG)) { -+ old_desc_blocks = rfs->old_fs->super->s_first_meta_bg; -+ new_desc_blocks = rfs->new_fs->super->s_first_meta_bg; -+ } else { -+ old_desc_blocks = rfs->old_fs->desc_blocks + -+ rfs->old_fs->super->s_reserved_gdt_blocks; -+ new_desc_blocks = rfs->new_fs->desc_blocks + -+ rfs->new_fs->super->s_reserved_gdt_blocks; -+ } -+ -+ /* Construct bitmaps of super/descriptor blocks in old and new fs */ -+ for (i = 0; i < rfs->old_fs->group_desc_count; i++) { -+ retval = ext2fs_super_and_bgd_loc2(rfs->old_fs, i, &b, &c, &d, -+ NULL); -+ if (retval) -+ goto out; -+ if (b) -+ ext2fs_mark_block_bitmap2(old_map, b); -+ for (j = 0; c != 0 && j < old_desc_blocks; j++) -+ ext2fs_mark_block_bitmap2(old_map, c + j); -+ if (d) -+ ext2fs_mark_block_bitmap2(old_map, d); -+ -+ retval = ext2fs_super_and_bgd_loc2(rfs->new_fs, i, &b, &c, &d, -+ NULL); -+ if (retval) -+ goto out; -+ if (b) -+ ext2fs_mark_block_bitmap2(new_map, b); -+ for (j = 0; c != 0 && j < new_desc_blocks; j++) -+ ext2fs_mark_block_bitmap2(new_map, c + j); -+ if (d) -+ ext2fs_mark_block_bitmap2(new_map, d); -+ } -+ -+ cluster_ratio = EXT2FS_CLUSTER_RATIO(rfs->new_fs); -+ -+ /* Find changes in block allocations for bg metadata */ -+ for (b = EXT2FS_B2C(rfs->old_fs, -+ rfs->old_fs->super->s_first_data_block); -+ b < ext2fs_blocks_count(rfs->new_fs->super); -+ b += cluster_ratio) { -+ old = ext2fs_test_block_bitmap2(old_map, b); -+ new = ext2fs_test_block_bitmap2(new_map, b); -+ -+ if (old && !new) { -+ /* mark old_map, unmark new_map */ -+ if (cluster_ratio == 1) -+ ext2fs_unmark_block_bitmap2( -+ rfs->new_fs->block_map, b); -+ } else if (!old && new) -+ ; /* unmark old_map, mark new_map */ -+ else { -+ ext2fs_unmark_block_bitmap2(old_map, b); -+ ext2fs_unmark_block_bitmap2(new_map, b); -+ } -+ } -+ -+ /* -+ * new_map now shows blocks that have been newly allocated. -+ * old_map now shows blocks that have been newly freed. -+ */ -+ -+ /* -+ * Move any conflicting bitmaps and inode tables. Ensure that we -+ * don't try to free clusters associated with bitmaps or tables. -+ */ -+ for (i = 0; i < rfs->old_fs->group_desc_count; i++) { -+ b = ext2fs_block_bitmap_loc(rfs->new_fs, i); -+ if (ext2fs_test_block_bitmap2(new_map, b)) -+ ext2fs_block_bitmap_loc_set(rfs->new_fs, i, 0); -+ else if (ext2fs_test_block_bitmap2(old_map, b)) -+ ext2fs_unmark_block_bitmap2(old_map, b); -+ -+ b = ext2fs_inode_bitmap_loc(rfs->new_fs, i); -+ if (ext2fs_test_block_bitmap2(new_map, b)) -+ ext2fs_inode_bitmap_loc_set(rfs->new_fs, i, 0); -+ else if (ext2fs_test_block_bitmap2(old_map, b)) -+ ext2fs_unmark_block_bitmap2(old_map, b); -+ -+ c = ext2fs_inode_table_loc(rfs->new_fs, i); -+ for (b = 0; -+ b < rfs->new_fs->inode_blocks_per_group; -+ b++) { -+ if (ext2fs_test_block_bitmap2(new_map, b + c)) -+ ext2fs_inode_table_loc_set(rfs->new_fs, i, 0); -+ else if (ext2fs_test_block_bitmap2(old_map, b + c)) -+ ext2fs_unmark_block_bitmap2(old_map, b + c); -+ } -+ } -+ -+ /* Free unused clusters */ -+ for (b = 0; -+ cluster_ratio > 1 && b < ext2fs_blocks_count(rfs->new_fs->super); -+ b += cluster_ratio) -+ if (ext2fs_test_block_bitmap2(old_map, b)) -+ ext2fs_unmark_block_bitmap2(rfs->new_fs->block_map, b); -+out: -+ if (old_map) -+ ext2fs_free_block_bitmap(old_map); -+ if (new_map) -+ ext2fs_free_block_bitmap(new_map); -+ return retval; -+} -+ -+/* Zero out the high bits of extent fields */ -+static errcode_t zero_high_bits_in_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; -+ -+ op = EXT2_EXTENT_NEXT_SIB; -+ -+ if (extent.e_pblk > (1ULL << 32)) { -+ extent.e_pblk &= (1ULL << 32) - 1; -+ 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; -+ ext2fs_extent_free(handle); -+ return errcode; -+} -+ -+/* Zero out the high bits of inodes. */ -+static errcode_t zero_high_bits_in_inodes(ext2_resize_t rfs) -+{ -+ ext2_filsys fs = rfs->old_fs; -+ int length = EXT2_INODE_SIZE(fs->super); -+ struct ext2_inode *inode = NULL; -+ ext2_inode_scan scan = NULL; -+ errcode_t retval; -+ ext2_ino_t ino; -+ -+ if (!(rfs->flags & (RESIZE_DISABLE_64BIT | RESIZE_ENABLE_64BIT))) -+ return 0; -+ -+ if (fs->super->s_creator_os != EXT2_OS_LINUX) -+ return 0; -+ -+ retval = ext2fs_open_inode_scan(fs, 0, &scan); -+ if (retval) -+ return retval; -+ -+ 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)) -+ continue; -+ -+ /* -+ * Here's how we deal with high block number fields: -+ * -+ * - i_size_high has been been written out with i_size_lo -+ * since the ext2 days, so no conversion is needed. -+ * -+ * - i_blocks_hi is guarded by both the huge_file feature and -+ * inode flags and has always been written out with -+ * i_blocks_lo if the feature is set. The field is only -+ * ever read if both feature and inode flag are set, so -+ * we don't need to zero it now. -+ * -+ * - i_file_acl_high can be uninitialized, so zero it if -+ * it isn't already. -+ */ -+ if (inode->osd2.linux2.l_i_file_acl_high) { -+ inode->osd2.linux2.l_i_file_acl_high = 0; -+ retval = ext2fs_write_inode_full(fs, ino, inode, -+ length); -+ if (retval) -+ goto out; -+ } -+ -+ retval = zero_high_bits_in_extents(fs, ino, inode); -+ if (retval) -+ goto out; -+ } while (ino); -+ -+out: -+ if (inode) -+ ext2fs_free_mem(&inode); -+ if (scan) -+ ext2fs_close_inode_scan(scan); -+ return retval; -+} -+ - /* - * Clean up the bitmaps for unitialized bitmaps - */ -@@ -240,8 +580,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++) { -@@ -455,7 +794,8 @@ retry: - /* - * Reallocate the group descriptors as necessary. - */ -- if (old_fs->desc_blocks != fs->desc_blocks) { -+ if (EXT2_DESC_SIZE(old_fs->super) == EXT2_DESC_SIZE(fs->super) && -+ old_fs->desc_blocks != fs->desc_blocks) { - retval = ext2fs_resize_mem(old_fs->desc_blocks * - fs->blocksize, - fs->desc_blocks * fs->blocksize, -@@ -474,20 +814,11 @@ retry: - * number of descriptor blocks, then adjust - * s_reserved_gdt_blocks if possible to avoid needing to move - * the inode table either now or in the future. -+ * -+ * Note: If we're converting to 64bit mode, we did this earlier. - */ -- if ((fs->super->s_feature_compat & -- EXT2_FEATURE_COMPAT_RESIZE_INODE) && -- (old_fs->desc_blocks != fs->desc_blocks)) { -- int new; -- -- new = ((int) fs->super->s_reserved_gdt_blocks) + -- (old_fs->desc_blocks - fs->desc_blocks); -- if (new < 0) -- new = 0; -- if (new > (int) fs->blocksize/4) -- new = fs->blocksize/4; -- fs->super->s_reserved_gdt_blocks = new; -- } -+ if (EXT2_DESC_SIZE(old_fs->super) == EXT2_DESC_SIZE(fs->super)) -+ adjust_reserved_gdt_blocks(old_fs, fs); - - if ((fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_META_BG) && - (fs->super->s_first_meta_bg > fs->desc_blocks)) { -@@ -572,9 +903,9 @@ 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); -- if (access("/sys/fs/ext4/features/lazy_itable_init", F_OK) == 0) -+ csum_flag = ext2fs_has_group_desc_csum(fs); -+ if (!getenv("RESIZE2FS_FORCE_ITABLE_INIT") && -+ 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) - old_desc_blocks = fs->super->s_first_meta_bg; -@@ -731,9 +1062,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; - } -@@ -762,11 +1091,11 @@ static errcode_t adjust_superblock(ext2_resize_t rfs, blk64_t new_size) - /* - * Write out the new inode table - */ -- retval = io_channel_write_blk64(fs->io, -- ext2fs_inode_table_loc(fs, i), -- fs->inode_blocks_per_group, -- rfs->itable_buf); -- if (retval) goto errout; -+ retval = ext2fs_zero_blocks2(fs, ext2fs_inode_table_loc(fs, i), -+ fs->inode_blocks_per_group, NULL, -+ NULL); -+ if (retval) -+ goto errout; - - io_channel_flush(fs->io); - if (rfs->progress) { -@@ -889,9 +1218,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 +1316,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 -@@ -1019,7 +1347,9 @@ static errcode_t blocks_to_move(ext2_resize_t rfs) - if (retval) - goto errout; - -- if (old_blocks == new_blocks) { -+ if (EXT2_DESC_SIZE(rfs->old_fs->super) == -+ EXT2_DESC_SIZE(rfs->new_fs->super) && -+ old_blocks == new_blocks) { - retval = 0; - goto errout; - } -@@ -1047,7 +1377,7 @@ static errcode_t blocks_to_move(ext2_resize_t rfs) - } - - for (i = 0; i < max_groups; i++) { -- if (!ext2fs_bg_has_super(fs, i)) { -+ if (!ext2fs_bg_has_super(old_fs, i)) { - group_blk += fs->super->s_blocks_per_group; - continue; - } -@@ -1284,7 +1614,8 @@ static blk64_t get_new_block(ext2_resize_t rfs) - } - } - --static errcode_t resize2fs_get_alloc_block(ext2_filsys fs, blk64_t goal, -+static errcode_t resize2fs_get_alloc_block(ext2_filsys fs, -+ blk64_t goal EXT2FS_ATTR((unused)), - blk64_t *ret) - { - ext2_resize_t rfs = (ext2_resize_t) fs->priv_data; -@@ -1461,10 +1792,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 +1821,13 @@ 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 (pb->is_dir) { - retval = ext2fs_add_dir_block2(fs->dblist, pb->ino, - block, (int) blockcnt); -@@ -1532,6 +1867,106 @@ 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 = NULL; -+ 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; -+} -+ -+/* Rewrite extents */ -+static errcode_t rewrite_extents(ext2_filsys fs, ext2_ino_t ino) -+{ -+ ext2_extent_handle_t handle; -+ struct ext2fs_extent extent; -+ errcode_t errcode; -+ struct ext2_extent_info info; -+ -+ errcode = ext2fs_extent_open(fs, ino, &handle); -+ if (errcode) -+ return errcode; -+ -+ errcode = ext2fs_extent_get(handle, EXT2_EXTENT_ROOT, &extent); -+ if (errcode) -+ goto out; -+ -+ do { -+ errcode = ext2fs_extent_get_info(handle, &info); -+ if (errcode) -+ break; -+ -+ /* -+ * If this is the first extent in an extent block that we -+ * haven't visited, rewrite the extent to force the ETB -+ * checksum to be rewritten. -+ */ -+ if (info.curr_entry == 1 && info.curr_level != 0 && -+ !(extent.e_flags & EXT2_EXTENT_FLAGS_SECOND_VISIT)) { -+ errcode = ext2fs_extent_replace(handle, 0, &extent); -+ if (errcode) -+ break; -+ } -+ -+ /* Skip to the end of a block of leaf nodes */ -+ if (extent.e_flags & EXT2_EXTENT_FLAGS_LEAF) { -+ errcode = ext2fs_extent_get(handle, -+ EXT2_EXTENT_LAST_SIB, -+ &extent); -+ if (errcode) -+ break; -+ } -+ -+ errcode = ext2fs_extent_get(handle, EXT2_EXTENT_NEXT, &extent); -+ } while (errcode == 0); -+ -+out: -+ /* Ok if we run off the end */ -+ if (errcode == EXT2_ET_EXTENT_NO_NEXT) -+ errcode = 0; -+ ext2fs_extent_free(handle); -+ return errcode; -+} -+ -+static void quiet_com_err_proc(const char *whoami EXT2FS_ATTR((unused)), -+ errcode_t code EXT2FS_ATTR((unused)), -+ const char *fmt EXT2FS_ATTR((unused)), -+ va_list args EXT2FS_ATTR((unused))) -+{ -+} -+ - static errcode_t inode_scan_and_fix(ext2_resize_t rfs) - { - struct process_block_struct pb; -@@ -1541,8 +1976,6 @@ static errcode_t inode_scan_and_fix(ext2_resize_t rfs) - errcode_t retval; - 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 <= -@@ -1550,16 +1983,7 @@ static errcode_t inode_scan_and_fix(ext2_resize_t rfs) - !rfs->bmap) - return 0; - -- /* -- * Save the original size of the old filesystem, and -- * temporarily set the size to be the new size if the new size -- * is larger. We need to do this to avoid catching an error -- * by the block iterator routines -- */ -- orig_size = ext2fs_blocks_count(rfs->old_fs->super); -- if (orig_size < ext2fs_blocks_count(rfs->new_fs->super)) -- ext2fs_blocks_count_set(rfs->old_fs->super, -- ext2fs_blocks_count(rfs->new_fs->super)); -+ set_com_err_hook(quiet_com_err_proc); - - retval = ext2fs_open_inode_scan(rfs->old_fs, 0, &scan); - if (retval) goto errout; -@@ -1605,37 +2029,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 +2049,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,11 +2066,60 @@ 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; -+ -+ /* Rewrite extent block checksums with new inode number */ -+ if (EXT2_HAS_RO_COMPAT_FEATURE(rfs->old_fs->super, -+ EXT4_FEATURE_RO_COMPAT_METADATA_CSUM) && -+ (inode->i_flags & EXT4_EXTENTS_FL)) { -+ rfs->old_fs->flags |= EXT2_FLAG_IGNORE_CSUM_ERRORS; -+ retval = rewrite_extents(rfs->old_fs, new_inode); -+ rfs->old_fs->flags &= ~EXT2_FLAG_IGNORE_CSUM_ERRORS; -+ 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); - - errout: -- ext2fs_blocks_count_set(rfs->old_fs->super, orig_size); -+ reset_com_err_hook(); - if (rfs->bmap) { - ext2fs_free_extent_table(rfs->bmap); - rfs->bmap = 0; -@@ -1706,6 +2157,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 +2168,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 +2199,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 +2229,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) { -@@ -2052,7 +2515,7 @@ static errcode_t reserve_sparse_super2_last_group(ext2_resize_t rfs, - if (retval) - return retval; - -- if (!sb) { -+ if (last_bg && !sb) { - fputs(_("Should never happen! No sb in last super_sparse bg?\n"), - stderr); - exit(1); -@@ -2112,15 +2575,11 @@ static errcode_t fix_resize_inode(ext2_filsys fs) - { - struct ext2_inode inode; - errcode_t retval; -- char *block_buf = NULL; - - if (!(fs->super->s_feature_compat & - EXT2_FEATURE_COMPAT_RESIZE_INODE)) - return 0; - -- retval = ext2fs_get_mem(fs->blocksize, &block_buf); -- if (retval) goto errout; -- - retval = ext2fs_read_inode(fs, EXT2_RESIZE_INO, &inode); - if (retval) goto errout; - -@@ -2140,19 +2599,16 @@ static errcode_t fix_resize_inode(ext2_filsys fs) - exit(1); - } - -- memset(block_buf, 0, fs->blocksize); -- -- retval = io_channel_write_blk64(fs->io, inode.i_block[EXT2_DIND_BLOCK], -- 1, block_buf); -- if (retval) goto errout; -+ retval = ext2fs_zero_blocks2(fs, inode.i_block[EXT2_DIND_BLOCK], 1, -+ NULL, NULL); -+ if (retval) -+ goto errout; - - retval = ext2fs_create_resize_inode(fs); - if (retval) - goto errout; - - errout: -- if (block_buf) -- ext2fs_free_mem(&block_buf); - return retval; - } - -diff --git a/resize/resize2fs.h b/resize/resize2fs.h -index 7aeab91..829fcd8 100644 ---- a/resize/resize2fs.h -+++ b/resize/resize2fs.h -@@ -82,6 +82,9 @@ typedef struct ext2_sim_progress *ext2_sim_progmeter; - #define RESIZE_PERCENT_COMPLETE 0x0100 - #define RESIZE_VERBOSE 0x0200 - -+#define RESIZE_ENABLE_64BIT 0x0400 -+#define RESIZE_DISABLE_64BIT 0x0800 -+ - /* - * This structure is used for keeping track of how much resources have - * been used for a particular resize2fs pass. -diff --git a/tests/Makefile.in b/tests/Makefile.in -index 37a043e..60cf655 100644 ---- a/tests/Makefile.in -+++ b/tests/Makefile.in -@@ -16,8 +16,8 @@ all:: @DO_TEST_SUITE@ test_one test_script - test_one: $(srcdir)/test_one.in Makefile mke2fs.conf - @echo "Creating test_one script..." - @echo "#!/bin/sh" > test_one --@HTREE_CMT@ @echo "HTREE=y" >> test_one --@QUOTA_CMT@ @echo "QUOTA=y" >> test_one -+ @echo "HTREE=y" >> test_one -+ @echo "QUOTA=y" >> test_one - @echo "SRCDIR=@srcdir@" >> test_one - @echo "DIFF_OPTS=@UNI_DIFF_OPTS@" >> test_one - @cat $(srcdir)/test_one.in >> test_one -diff --git a/tests/d_dumpe2fs_group_only/expect b/tests/d_dumpe2fs_group_only/expect -new file mode 100644 -index 0000000..78f97a2 ---- /dev/null -+++ b/tests/d_dumpe2fs_group_only/expect -@@ -0,0 +1,51 @@ -+Creating filesystem with 1048576 4k blocks and 262144 inodes -+Superblock backups stored on blocks: -+ 32768, 98304, 163840, 229376, 294912, 819200, 884736 -+ -+Allocating group tables: done -+Writing inode tables: done -+Creating journal (32768 blocks): done -+Writing superblocks and filesystem accounting information: done -+ -+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/262144 files (0.0% non-contiguous), 51278/1048576 blocks -+Exit status is 0 -+dumpe2fs output -+ -+group:block:super:gdt:bbitmap:ibitmap:itable -+0:0:0:1-1:257:273:289 -+1:32768:32768:32769-32769:258:274:801 -+2:65536:-1:-1:259:275:1313 -+3:98304:98304:98305-98305:260:276:1825 -+4:131072:-1:-1:261:277:2337 -+5:163840:163840:163841-163841:262:278:2849 -+6:196608:-1:-1:263:279:3361 -+7:229376:229376:229377-229377:264:280:3873 -+8:262144:-1:-1:265:281:4385 -+9:294912:294912:294913-294913:266:282:4897 -+10:327680:-1:-1:267:283:5409 -+11:360448:-1:-1:268:284:5921 -+12:393216:-1:-1:269:285:6433 -+13:425984:-1:-1:270:286:6945 -+14:458752:-1:-1:271:287:7457 -+15:491520:-1:-1:272:288:7969 -+16:524288:-1:-1:524288:524304:524320 -+17:557056:-1:-1:524289:524305:524832 -+18:589824:-1:-1:524290:524306:525344 -+19:622592:-1:-1:524291:524307:525856 -+20:655360:-1:-1:524292:524308:526368 -+21:688128:-1:-1:524293:524309:526880 -+22:720896:-1:-1:524294:524310:527392 -+23:753664:-1:-1:524295:524311:527904 -+24:786432:-1:-1:524296:524312:528416 -+25:819200:819200:819201-819201:524297:524313:528928 -+26:851968:-1:-1:524298:524314:529440 -+27:884736:884736:884737-884737:524299:524315:529952 -+28:917504:-1:-1:524300:524316:530464 -+29:950272:-1:-1:524301:524317:530976 -+30:983040:-1:-1:524302:524318:531488 -+31:1015808:-1:-1:524303:524319:532000 -diff --git a/tests/d_dumpe2fs_group_only/name b/tests/d_dumpe2fs_group_only/name -new file mode 100644 -index 0000000..096c020 ---- /dev/null -+++ b/tests/d_dumpe2fs_group_only/name -@@ -0,0 +1 @@ -+dumpe2fs group only mode -diff --git a/tests/d_dumpe2fs_group_only/script b/tests/d_dumpe2fs_group_only/script -new file mode 100644 -index 0000000..50481f0 ---- /dev/null -+++ b/tests/d_dumpe2fs_group_only/script -@@ -0,0 +1,49 @@ -+if [ $(uname -s) = "Darwin" ]; then -+ # creates a 4GB filesystem -+ echo "$test_name: $DESCRIPTION: skipped for HFS+ (no sparse files)" -+ return 0 -+fi -+ -+if test -x $DEBUGFS_EXE; then -+ -+FSCK_OPT=-fy -+OUT=$test_name.log -+if [ -f $test_dir/expect.gz ]; then -+ EXP=$test_name.tmp -+ gunzip < $test_dir/expect.gz > $EXP1 -+else -+ EXP=$test_dir/expect -+fi -+ -+cp /dev/null $OUT -+ -+$MKE2FS -F -o Linux -b 4096 -O has_journal -T ext4 $TMPFILE 1048576 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT 2>&1 -+ -+$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 -+status=$? -+echo Exit status is $status >> $OUT.new -+sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT -+rm -f $OUT.new -+ -+echo "dumpe2fs output" >> $OUT -+$DUMPE2FS -g $TMPFILE 2>&1 | sed -f $cmd_dir/filter.sed >> $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 IMAGE FSCK_OPT OUT EXP -+ -+else #if test -x $DEBUGFS_EXE; then -+ echo "$test_name: $test_description: skipped" -+fi -diff --git a/tests/d_fallocate/expect.gz b/tests/d_fallocate/expect.gz -new file mode 100644 -index 0000000..3e6ffc3 -Binary files /dev/null and b/tests/d_fallocate/expect.gz differ -diff --git a/tests/d_fallocate/name b/tests/d_fallocate/name -new file mode 100644 -index 0000000..72d0ed3 ---- /dev/null -+++ b/tests/d_fallocate/name -@@ -0,0 +1 @@ -+fallocate sparse files and big files -diff --git a/tests/d_fallocate/script b/tests/d_fallocate/script -new file mode 100644 -index 0000000..ae8956e ---- /dev/null -+++ b/tests/d_fallocate/script -@@ -0,0 +1,175 @@ -+if test -x $DEBUGFS_EXE; then -+ -+FSCK_OPT=-fy -+OUT=$test_name.log -+if [ -f $test_dir/expect.gz ]; then -+ EXP=$test_name.tmp -+ gunzip < $test_dir/expect.gz > $EXP -+else -+ EXP=$test_dir/expect -+fi -+ -+cp /dev/null $OUT -+ -+cat > $TMPFILE.conf << ENDL -+[fs_types] -+ext4 = { -+ base_features = sparse_super,filetype,resize_inode,dir_index,ext_attr,^has_journal,extent,huge_file,flex_bg,uninit_bg,dir_nlink,extra_isize,64bit -+ blocksize = 1024 -+ inode_size = 256 -+ inode_ratio = 16384 -+} -+ENDL -+MKE2FS_CONFIG=$TMPFILE.conf $MKE2FS -F -o Linux -b 1024 -O ^bigalloc -T ext4 $TMPFILE 65536 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT 2>&1 -+rm -rf $TMPFILE.conf -+ -+$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 -+status=$? -+echo Exit status is $status >> $OUT.new -+sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT -+rm -f $OUT.new -+ -+echo "debugfs write files" >> $OUT -+make_file() { -+ name="$1" -+ start="$2" -+ flag="$3" -+ -+ cat << ENDL -+write /dev/null $name -+sif /$name size 40960 -+eo /$name -+set_bmap $flag 10 $((start + 10)) -+set_bmap $flag 13 $((start + 13)) -+set_bmap $flag 26 $((start + 26)) -+set_bmap $flag 29 $((start + 29)) -+ec -+sif /$name blocks 8 -+setb $((start + 10)) -+setb $((start + 13)) -+setb $((start + 26)) -+setb $((start + 29)) -+ENDL -+} -+ -+#Files we create: -+# a: fallocate a 40k file -+# b*: falloc sparse file starting at b* -+# c*: falloc spare file ending at c* -+# d: midcluster to midcluster, surrounding sparse -+# e: partial middle cluster alloc -+# f: one big file -+# g*: falloc sparse init file starting at g* -+# h*: falloc sparse init file ending at h* -+# i: midcluster to midcluster, surrounding sparse init -+# j: partial middle cluster alloc -+# k: one big init file -+base=5000 -+cat > $TMPFILE.cmd << ENDL -+write /dev/null a -+sif /a size 40960 -+fallocate /a 0 39 -+ENDL -+echo "ex /a" >> $TMPFILE.cmd2 -+ -+make_file sample $base --uninit >> $TMPFILE.cmd -+echo "ex /sample" >> $TMPFILE.cmd2 -+base=10000 -+ -+for i in 8 9 10 11 12 13 14 15; do -+ make_file b$i $(($base + (40 * ($i - 8)))) --uninit >> $TMPFILE.cmd -+ echo "fallocate /b$i $i 39" >> $TMPFILE.cmd -+ echo "ex /b$i" >> $TMPFILE.cmd2 -+done -+ -+for i in 24 25 26 27 28 29 30 31; do -+ make_file c$i $(($base + 320 + (40 * ($i - 24)))) --uninit >> $TMPFILE.cmd -+ echo "fallocate /c$i 0 $i" >> $TMPFILE.cmd -+ echo "ex /c$i" >> $TMPFILE.cmd2 -+done -+ -+make_file d $(($base + 640)) --uninit >> $TMPFILE.cmd -+echo "fallocate /d 4 35" >> $TMPFILE.cmd -+echo "ex /d" >> $TMPFILE.cmd2 -+ -+make_file e $(($base + 680)) --uninit >> $TMPFILE.cmd -+echo "fallocate /e 19 20" >> $TMPFILE.cmd -+echo "ex /e" >> $TMPFILE.cmd2 -+ -+cat >> $TMPFILE.cmd << ENDL -+write /dev/null f -+sif /f size 1024 -+eo /f -+set_bmap --uninit 0 9000 -+ec -+sif /f blocks 2 -+setb 9000 -+fallocate /f 0 8999 -+ENDL -+echo "ex /f" >> $TMPFILE.cmd2 -+ -+# Now do it again, but with initialized blocks -+base=20000 -+for i in 8 9 10 11 12 13 14 15; do -+ make_file g$i $(($base + (40 * ($i - 8)))) >> $TMPFILE.cmd -+ echo "fallocate /g$i $i 39" >> $TMPFILE.cmd -+ echo "ex /g$i" >> $TMPFILE.cmd2 -+done -+ -+for i in 24 25 26 27 28 29 30 31; do -+ make_file h$i $(($base + 320 + (40 * ($i - 24)))) >> $TMPFILE.cmd -+ echo "fallocate /h$i 0 $i" >> $TMPFILE.cmd -+ echo "ex /h$i" >> $TMPFILE.cmd2 -+done -+ -+make_file i $(($base + 640)) >> $TMPFILE.cmd -+echo "fallocate /i 4 35" >> $TMPFILE.cmd -+echo "ex /i" >> $TMPFILE.cmd2 -+ -+make_file j $(($base + 680)) >> $TMPFILE.cmd -+echo "fallocate /j 19 20" >> $TMPFILE.cmd -+echo "ex /j" >> $TMPFILE.cmd2 -+ -+cat >> $TMPFILE.cmd << ENDL -+write /dev/null k -+sif /k size 1024 -+eo /k -+set_bmap 0 19000 -+ec -+sif /k blocks 2 -+setb 19000 -+fallocate /k 0 8999 -+sif /k size 9216000 -+ENDL -+echo "ex /k" >> $TMPFILE.cmd2 -+ -+$DEBUGFS_EXE -w -f $TMPFILE.cmd $TMPFILE > /dev/null 2>&1 -+$DEBUGFS_EXE -f $TMPFILE.cmd2 $TMPFILE >> $OUT.new 2>&1 -+sed -f $cmd_dir/filter.sed < $OUT.new >> $OUT -+rm -rf $OUT.new $TMPFILE.cmd $TMPFILE.cmd2 -+ -+$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 -+status=$? -+echo Exit status is $status >> $OUT.new -+sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT -+rm -f $OUT.new -+ -+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 IMAGE FSCK_OPT OUT EXP -+ -+else #if test -x $DEBUGFS_EXE; then -+ echo "$test_name: $test_description: skipped" -+fi -diff --git a/tests/d_fallocate_bigalloc/expect.gz b/tests/d_fallocate_bigalloc/expect.gz -new file mode 100644 -index 0000000..8640bc2 -Binary files /dev/null and b/tests/d_fallocate_bigalloc/expect.gz differ -diff --git a/tests/d_fallocate_bigalloc/name b/tests/d_fallocate_bigalloc/name -new file mode 100644 -index 0000000..915645c ---- /dev/null -+++ b/tests/d_fallocate_bigalloc/name -@@ -0,0 +1 @@ -+fallocate sparse files and big files with bigalloc -diff --git a/tests/d_fallocate_bigalloc/script b/tests/d_fallocate_bigalloc/script -new file mode 100644 -index 0000000..6b6bf97 ---- /dev/null -+++ b/tests/d_fallocate_bigalloc/script -@@ -0,0 +1,176 @@ -+if test -x $DEBUGFS_EXE; then -+ -+FSCK_OPT=-fy -+OUT=$test_name.log -+if [ -f $test_dir/expect.gz ]; then -+ EXP=$test_name.tmp -+ gunzip < $test_dir/expect.gz > $EXP -+else -+ EXP=$test_dir/expect -+fi -+ -+cp /dev/null $OUT -+ -+cat > $TMPFILE.conf << ENDL -+[fs_types] -+ext4 = { -+ cluster_size = 8192 -+ base_features = sparse_super,filetype,resize_inode,dir_index,ext_attr,^has_journal,extent,huge_file,flex_bg,uninit_bg,dir_nlink,extra_isize,64bit -+ blocksize = 1024 -+ inode_size = 256 -+ inode_ratio = 16384 -+} -+ENDL -+MKE2FS_CONFIG=$TMPFILE.conf $MKE2FS -F -o Linux -b 1024 -O bigalloc -T ext4 $TMPFILE 65536 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT 2>&1 -+rm -rf $TMPFILE.conf -+ -+$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 -+status=$? -+echo Exit status is $status >> $OUT.new -+sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT -+rm -f $OUT.new -+ -+echo "debugfs write files" >> $OUT -+make_file() { -+ name="$1" -+ start="$2" -+ flag="$3" -+ -+ cat << ENDL -+write /dev/null $name -+sif /$name size 40960 -+eo /$name -+set_bmap $flag 10 $((start + 10)) -+set_bmap $flag 13 $((start + 13)) -+set_bmap $flag 26 $((start + 26)) -+set_bmap $flag 29 $((start + 29)) -+ec -+sif /$name blocks 32 -+setb $((start + 10)) -+setb $((start + 13)) -+setb $((start + 26)) -+setb $((start + 29)) -+ENDL -+} -+ -+#Files we create: -+# a: fallocate a 40k file -+# b*: falloc sparse file starting at b* -+# c*: falloc spare file ending at c* -+# d: midcluster to midcluster, surrounding sparse -+# e: partial middle cluster alloc -+# f: one big file -+# g*: falloc sparse init file starting at g* -+# h*: falloc sparse init file ending at h* -+# i: midcluster to midcluster, surrounding sparse init -+# j: partial middle cluster alloc -+# k: one big init file -+base=5000 -+cat > $TMPFILE.cmd << ENDL -+write /dev/null a -+sif /a size 40960 -+fallocate /a 0 39 -+ENDL -+echo "ex /a" >> $TMPFILE.cmd2 -+ -+make_file sample $base --uninit >> $TMPFILE.cmd -+echo "ex /sample" >> $TMPFILE.cmd2 -+base=10000 -+ -+for i in 8 9 10 11 12 13 14 15; do -+ make_file b$i $(($base + (40 * ($i - 8)))) --uninit >> $TMPFILE.cmd -+ echo "fallocate /b$i $i 39" >> $TMPFILE.cmd -+ echo "ex /b$i" >> $TMPFILE.cmd2 -+done -+ -+for i in 24 25 26 27 28 29 30 31; do -+ make_file c$i $(($base + 320 + (40 * ($i - 24)))) --uninit >> $TMPFILE.cmd -+ echo "fallocate /c$i 0 $i" >> $TMPFILE.cmd -+ echo "ex /c$i" >> $TMPFILE.cmd2 -+done -+ -+make_file d $(($base + 640)) --uninit >> $TMPFILE.cmd -+echo "fallocate /d 4 35" >> $TMPFILE.cmd -+echo "ex /d" >> $TMPFILE.cmd2 -+ -+make_file e $(($base + 680)) --uninit >> $TMPFILE.cmd -+echo "fallocate /e 19 20" >> $TMPFILE.cmd -+echo "ex /e" >> $TMPFILE.cmd2 -+ -+cat >> $TMPFILE.cmd << ENDL -+write /dev/null f -+sif /f size 1024 -+eo /f -+set_bmap --uninit 0 9000 -+ec -+sif /f blocks 16 -+setb 9000 -+fallocate /f 0 8999 -+ENDL -+echo "ex /f" >> $TMPFILE.cmd2 -+ -+# Now do it again, but with initialized blocks -+base=20000 -+for i in 8 9 10 11 12 13 14 15; do -+ make_file g$i $(($base + (40 * ($i - 8)))) >> $TMPFILE.cmd -+ echo "fallocate /g$i $i 39" >> $TMPFILE.cmd -+ echo "ex /g$i" >> $TMPFILE.cmd2 -+done -+ -+for i in 24 25 26 27 28 29 30 31; do -+ make_file h$i $(($base + 320 + (40 * ($i - 24)))) >> $TMPFILE.cmd -+ echo "fallocate /h$i 0 $i" >> $TMPFILE.cmd -+ echo "ex /h$i" >> $TMPFILE.cmd2 -+done -+ -+make_file i $(($base + 640)) >> $TMPFILE.cmd -+echo "fallocate /i 4 35" >> $TMPFILE.cmd -+echo "ex /i" >> $TMPFILE.cmd2 -+ -+make_file j $(($base + 680)) >> $TMPFILE.cmd -+echo "fallocate /j 19 20" >> $TMPFILE.cmd -+echo "ex /j" >> $TMPFILE.cmd2 -+ -+cat >> $TMPFILE.cmd << ENDL -+write /dev/null k -+sif /k size 1024 -+eo /k -+set_bmap 0 19000 -+ec -+sif /k blocks 16 -+setb 19000 -+fallocate /k 0 8999 -+sif /k size 9216000 -+ENDL -+echo "ex /k" >> $TMPFILE.cmd2 -+ -+$DEBUGFS_EXE -w -f $TMPFILE.cmd $TMPFILE > /dev/null 2>&1 -+$DEBUGFS_EXE -f $TMPFILE.cmd2 $TMPFILE >> $OUT.new 2>&1 -+sed -f $cmd_dir/filter.sed < $OUT.new >> $OUT -+rm -rf $OUT.new $TMPFILE.cmd $TMPFILE.cmd2 -+ -+$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 -+status=$? -+echo Exit status is $status >> $OUT.new -+sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT -+rm -f $OUT.new -+ -+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 IMAGE FSCK_OPT OUT EXP -+ -+else #if test -x $DEBUGFS_EXE; then -+ echo "$test_name: $test_description: skipped" -+fi -diff --git a/tests/d_fallocate_blkmap/expect b/tests/d_fallocate_blkmap/expect -new file mode 100644 -index 0000000..f7ae606 ---- /dev/null -+++ b/tests/d_fallocate_blkmap/expect -@@ -0,0 +1,58 @@ -+Creating filesystem with 65536 1k blocks and 4096 inodes -+Superblock backups stored on blocks: -+ 8193, 24577, 40961, 57345 -+ -+Allocating group tables: done -+Writing inode tables: done -+Writing superblocks and filesystem accounting information: done -+ -+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/4096 files (0.0% non-contiguous), 2340/65536 blocks -+Exit status is 0 -+debugfs write files -+debugfs: stat /a -+Inode: 12 Type: regular Mode: 0666 Flags: 0x0 -+Generation: 0 Version: 0x00000000:00000000 -+User: 0 Group: 0 Size: 40960 -+File ACL: 0 Directory ACL: 0 -+Links: 1 Blockcount: 82 -+Fragment: Address: 0 Number: 0 Size: 0 -+Size of extra inode fields: 28 -+BLOCKS: -+(0-1):1312-1313, (2-11):8000-8009, (IND):8010, (12-39):8011-8038 -+TOTAL: 41 -+ -+debugfs: stat /b -+Inode: 13 Type: regular Mode: 0666 Flags: 0x0 -+Generation: 0 Version: 0x00000000:00000000 -+User: 0 Group: 0 Size: 10240000 -+File ACL: 0 Directory ACL: 0 -+Links: 1 Blockcount: 20082 -+Fragment: Address: 0 Number: 0 Size: 0 -+Size of extra inode fields: 28 -+BLOCKS: -+(0-11):10000-10011, (IND):10012, (12-267):10013-10268, (DIND):10269, (IND):10270, (268-523):10271-10526, (IND):10527, (524-779):10528-10783, (IND):10784, (780-1035):10785-11040, (IND):11041, (1036-1291):11042-11297, (IND):11298, (1292-1547):11299-11554, (IND):11555, (1548-1803):11556-11811, (IND):11812, (1804-2059):11813-12068, (IND):12069, (2060-2315):12070-12325, (IND):12326, (2316-2571):12327-12582, (IND):12583, (2572-2827):12584-12839, (IND):12840, (2828-3083):12841-13096, (IND):13097, (3084-3339):13098-13353, (IND):13354, (3340-3595):13355-13610, (IND):13611, (3596-3851):13612-13867, (IND):13868, (3852-4107):13869-14124, (IND):14125, (4108-4363):14126-14381, (IND):14382, (4364-4619):14383-14638, (IND):14639, (4620-4875):14640-14895, (IND):14896, (4876-5131):14897-15152, (IND):15153, (5132-5387):15154-15409, (IND):15410, (5388-5643):15411-15666, (IND):15667, (5644-5899):15668-15923, (IND):15924, (5900-6155):15925-16180, (IND):16181, (6156-6411):16182-16437, (IND):16438, (6412-6667):16439-16694, (IND):16695, (6668-6923):16696-16951, (IND):16952, (6924-7179):16953-17208, (IND):17209, (7180-7435):17210-17465, (IND):17466, (7436-7691):17467-17722, (IND):17723, (7692-7947):17724-17979, (IND):17980, (7948-8203):17981-18236, (IND):18237, (8204-8459):18238-18493, (IND):18494, (8460-8715):18495-18750, (IND):18751, (8716-8971):18752-19007, (IND):19008, (8972-9227):19009-19264, (IND):19265, (9228-9483):19266-19521, (IND):19522, (9484-9739):19523-19778, (IND):19779, (9740-9995):19780-20035, (IND):20036, (9996-9999):20037-20040 -+TOTAL: 10041 -+ -+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 -+Free blocks count wrong for group #0 (6841, counted=6840). -+Fix? yes -+ -+Free blocks count wrong for group #1 (1551, counted=1550). -+Fix? yes -+ -+Free blocks count wrong (53116, counted=53114). -+Fix? yes -+ -+ -+test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** -+test_filesys: 13/4096 files (7.7% non-contiguous), 12422/65536 blocks -+Exit status is 1 -diff --git a/tests/d_fallocate_blkmap/name b/tests/d_fallocate_blkmap/name -new file mode 100644 -index 0000000..ba2b61d ---- /dev/null -+++ b/tests/d_fallocate_blkmap/name -@@ -0,0 +1 @@ -+fallocate sparse files and big files on a blockmap fs -diff --git a/tests/d_fallocate_blkmap/script b/tests/d_fallocate_blkmap/script -new file mode 100644 -index 0000000..9c48cbc ---- /dev/null -+++ b/tests/d_fallocate_blkmap/script -@@ -0,0 +1,85 @@ -+if test -x $DEBUGFS_EXE; then -+ -+FSCK_OPT=-fy -+OUT=$test_name.log -+if [ -f $test_dir/expect.gz ]; then -+ EXP=$test_name.tmp -+ gunzip < $test_dir/expect.gz > $EXP1 -+else -+ EXP=$test_dir/expect -+fi -+ -+cp /dev/null $OUT -+ -+cat > $TMPFILE.conf << ENDL -+[fs_types] -+ext4 = { -+ base_features = sparse_super,filetype,resize_inode,dir_index,ext_attr,^has_journal,^extent,huge_file,flex_bg,uninit_bg,dir_nlink,extra_isize,^64bit -+ blocksize = 1024 -+ inode_size = 256 -+ inode_ratio = 16384 -+} -+ENDL -+MKE2FS_CONFIG=$TMPFILE.conf $MKE2FS -F -o Linux -b 1024 -O ^bigalloc -T ext4 $TMPFILE 65536 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT 2>&1 -+rm -rf $TMPFILE.conf -+ -+$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 -+status=$? -+echo Exit status is $status >> $OUT.new -+sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT -+rm -f $OUT.new -+ -+echo "debugfs write files" >> $OUT -+ -+#Files we create: -+# a: fallocate a 40k file -+# k: one big file -+base=5000 -+cat > $TMPFILE.cmd << ENDL -+write /dev/null a -+sif /a bmap[2] 8000 -+sif /a size 40960 -+sif /a i_blocks 2 -+setb 8000 -+fallocate /a 0 39 -+ -+write /dev/null b -+sif /b size 10240000 -+sif /b bmap[0] 10000 -+sif /b i_blocks 2 -+setb 10000 -+fallocate /b 0 9999 -+ENDL -+echo "stat /a" >> $TMPFILE.cmd2 -+echo "stat /b" >> $TMPFILE.cmd2 -+ -+$DEBUGFS_EXE -w -f $TMPFILE.cmd $TMPFILE > /dev/null 2>&1 -+$DEBUGFS_EXE -f $TMPFILE.cmd2 $TMPFILE >> $OUT.new 2>&1 -+sed -f $cmd_dir/filter.sed -e '/^.*time:.*$/d' < $OUT.new >> $OUT -+rm -rf $OUT.new $TMPFILE.cmd $TMPFILE.cmd2 -+ -+$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 -+status=$? -+echo Exit status is $status >> $OUT.new -+sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT -+rm -f $OUT.new -+ -+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 IMAGE FSCK_OPT OUT EXP -+ -+else #if test -x $DEBUGFS_EXE; then -+ echo "$test_name: $test_description: skipped" -+fi -diff --git a/tests/d_inline_dump/expect b/tests/d_inline_dump/expect -new file mode 100644 -index 0000000..c84f64d ---- /dev/null -+++ b/tests/d_inline_dump/expect -@@ -0,0 +1,95 @@ -+*** long file -+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 -+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 -+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 -+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 -+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 -+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 -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 -index 0000000..dfc1a9c ---- /dev/null -+++ b/tests/d_inline_dump/name -@@ -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 -index 0000000..7199453 ---- /dev/null -+++ b/tests/d_inline_dump/script -@@ -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 2>&1 | $CLEAN_OUTPUT >> $OUT 2>&1 -+echo "*** short file" >> $OUT -+$DEBUGFS -R 'stat /shortfile' $TMPFILE 2>&1 | $CLEAN_OUTPUT >> $OUT 2>&1 -+echo >> $OUT -+ -+echo "*** long dir" >> $OUT -+$DEBUGFS -R 'stat /dir' $TMPFILE 2>&1 | $CLEAN_OUTPUT >> $OUT 2>&1 -+echo "*** short dir" >> $OUT -+$DEBUGFS -R 'stat /shortdir' $TMPFILE 2>&1 | $CLEAN_OUTPUT >> $OUT 2>&1 -+echo >> $OUT -+ -+echo "*** long link" >> $OUT -+$DEBUGFS -R 'stat /link' $TMPFILE 2>&1 | $CLEAN_OUTPUT >> $OUT 2>&1 -+echo "*** short link" >> $OUT -+$DEBUGFS -R 'stat /shortlink' $TMPFILE 2>&1 | $CLEAN_OUTPUT >> $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 -diff --git a/tests/d_punch/expect b/tests/d_punch/expect -new file mode 100644 -index 0000000..2b39f8e ---- /dev/null -+++ b/tests/d_punch/expect -@@ -0,0 +1,176 @@ -+Creating filesystem with 65536 1k blocks and 4096 inodes -+Superblock backups stored on blocks: -+ 8193, 24577, 40961, 57345 -+ -+Allocating group tables: done -+Writing inode tables: done -+Writing superblocks and filesystem accounting information: done -+ -+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/4096 files (0.0% non-contiguous), 2345/65536 blocks -+Exit status is 0 -+debugfs write files -+debugfs: ex /a -+Level Entries Logical Physical Length Flags -+debugfs: ex /sample -+Level Entries Logical Physical Length Flags -+ 0/ 1 1/ 1 0 - 4294967295 1323 0 -+ 1/ 1 1/ 5 0 - 9 1313 - 1322 10 Uninit -+ 1/ 1 2/ 5 11 - 12 1324 - 1325 2 Uninit -+ 1/ 1 3/ 5 14 - 25 1327 - 1338 12 Uninit -+ 1/ 1 4/ 5 27 - 28 1340 - 1341 2 Uninit -+ 1/ 1 5/ 5 30 - 39 1343 - 1352 10 Uninit -+debugfs: ex /b8 -+Level Entries Logical Physical Length Flags -+ 0/ 1 1/ 1 0 - 4294967295 1390 0 -+ 1/ 1 1/ 4 0 - 0 1326 - 1326 1 Uninit -+ 1/ 1 2/ 4 1 - 1 1339 - 1339 1 Uninit -+ 1/ 1 3/ 4 2 - 2 1342 - 1342 1 Uninit -+ 1/ 1 4/ 4 3 - 7 1353 - 1357 5 Uninit -+debugfs: ex /b9 -+Level Entries Logical Physical Length Flags -+ 0/ 1 1/ 1 0 - 4294967295 1368 0 -+ 1/ 1 1/ 1 0 - 8 1358 - 1366 9 Uninit -+debugfs: ex /b10 -+Level Entries Logical Physical Length Flags -+ 0/ 1 1/ 1 0 - 4294967295 1378 0 -+ 1/ 1 1/ 2 0 - 0 1367 - 1367 1 Uninit -+ 1/ 1 2/ 2 1 - 9 1369 - 1377 9 Uninit -+debugfs: ex /b11 -+Level Entries Logical Physical Length Flags -+ 0/ 1 1/ 1 0 - 4294967295 1389 0 -+ 1/ 1 1/ 1 0 - 9 1379 - 1388 10 Uninit -+debugfs: ex /b12 -+Level Entries Logical Physical Length Flags -+ 0/ 1 1/ 1 0 - 4294967295 1401 0 -+ 1/ 1 1/ 2 0 - 9 1391 - 1400 10 Uninit -+ 1/ 1 2/ 2 11 - 11 1402 - 1402 1 Uninit -+debugfs: ex /b13 -+Level Entries Logical Physical Length Flags -+ 0/ 1 1/ 1 0 - 4294967295 1413 0 -+ 1/ 1 1/ 2 0 - 9 1403 - 1412 10 Uninit -+ 1/ 1 2/ 2 11 - 12 1414 - 1415 2 Uninit -+debugfs: ex /b14 -+Level Entries Logical Physical Length Flags -+ 0/ 1 1/ 1 0 - 4294967295 1426 0 -+ 1/ 1 1/ 2 0 - 9 1416 - 1425 10 Uninit -+ 1/ 1 2/ 2 11 - 12 1427 - 1428 2 Uninit -+debugfs: ex /b15 -+Level Entries Logical Physical Length Flags -+ 0/ 1 1/ 1 0 - 4294967295 1439 0 -+ 1/ 1 1/ 3 0 - 9 1429 - 1438 10 Uninit -+ 1/ 1 2/ 3 11 - 12 1440 - 1441 2 Uninit -+ 1/ 1 3/ 3 14 - 14 1443 - 1443 1 Uninit -+debugfs: ex /c24 -+Level Entries Logical Physical Length Flags -+ 0/ 1 1/ 1 25 - 4294967295 1453 4294967271 -+ 1/ 1 1/ 3 25 - 25 1468 - 1468 1 Uninit -+ 1/ 1 2/ 3 27 - 28 1470 - 1471 2 Uninit -+ 1/ 1 3/ 3 30 - 39 1473 - 1482 10 Uninit -+debugfs: ex /c25 -+Level Entries Logical Physical Length Flags -+ 0/ 1 1/ 1 27 - 4294967295 1483 4294967269 -+ 1/ 1 1/ 2 27 - 28 1485 - 1486 2 Uninit -+ 1/ 1 2/ 2 30 - 39 1488 - 1497 10 Uninit -+debugfs: ex /c26 -+Level Entries Logical Physical Length Flags -+ 0/ 1 1/ 1 27 - 4294967295 1484 4294967269 -+ 1/ 1 1/ 2 27 - 28 1498 - 1499 2 Uninit -+ 1/ 1 2/ 2 30 - 39 1501 - 1510 10 Uninit -+debugfs: ex /c27 -+Level Entries Logical Physical Length Flags -+ 0/ 1 1/ 1 28 - 4294967295 1487 4294967268 -+ 1/ 1 1/ 2 28 - 28 1512 - 1512 1 Uninit -+ 1/ 1 2/ 2 30 - 39 1514 - 1523 10 Uninit -+debugfs: ex /c28 -+Level Entries Logical Physical Length Flags -+ 0/ 1 1/ 1 30 - 4294967295 1500 4294967266 -+ 1/ 1 1/ 1 30 - 39 1526 - 1535 10 Uninit -+debugfs: ex /c29 -+Level Entries Logical Physical Length Flags -+ 0/ 1 1/ 1 30 - 4294967295 1511 4294967266 -+ 1/ 1 1/ 1 30 - 39 1537 - 1546 10 Uninit -+debugfs: ex /c30 -+Level Entries Logical Physical Length Flags -+ 0/ 1 1/ 1 31 - 4294967295 1513 4294967265 -+ 1/ 1 1/ 1 31 - 39 1549 - 1557 9 Uninit -+debugfs: ex /c31 -+Level Entries Logical Physical Length Flags -+ 0/ 1 1/ 1 32 - 4294967295 1524 4294967264 -+ 1/ 1 1/ 1 32 - 39 1560 - 1567 8 Uninit -+debugfs: ex /d -+Level Entries Logical Physical Length Flags -+ 0/ 1 1/ 1 0 - 4294967295 1525 0 -+ 1/ 1 1/ 3 0 - 0 1442 - 1442 1 Uninit -+ 1/ 1 2/ 3 1 - 3 1444 - 1446 3 Uninit -+ 1/ 1 3/ 3 36 - 39 1573 - 1576 4 Uninit -+debugfs: ex /e -+Level Entries Logical Physical Length Flags -+ 0/ 1 1/ 1 0 - 4294967295 1547 0 -+ 1/ 1 1/ 11 0 - 5 1447 - 1452 6 Uninit -+ 1/ 1 2/ 11 6 - 9 1454 - 1457 4 Uninit -+ 1/ 1 3/ 11 11 - 12 1459 - 1460 2 Uninit -+ 1/ 1 4/ 11 14 - 18 1462 - 1466 5 Uninit -+ 1/ 1 5/ 11 21 - 21 1472 - 1472 1 Uninit -+ 1/ 1 6/ 11 22 - 22 1536 - 1536 1 Uninit -+ 1/ 1 7/ 11 23 - 23 1548 - 1548 1 Uninit -+ 1/ 1 8/ 11 24 - 25 1558 - 1559 2 Uninit -+ 1/ 1 9/ 11 27 - 28 1569 - 1570 2 Uninit -+ 1/ 1 10/ 11 30 - 30 1572 - 1572 1 Uninit -+ 1/ 1 11/ 11 31 - 39 1577 - 1585 9 Uninit -+debugfs: ex /f -+Level Entries Logical Physical Length Flags -+ 0/ 0 1/ 2 0 - 0 9000 - 9000 1 Uninit -+ 0/ 0 2/ 2 8999 - 8999 17999 - 17999 1 Uninit -+Pass 1: Checking inodes, blocks, and sizes -+Inode 15 extent tree (at level 1) could be shorter. Fix? yes -+ -+Inode 16 extent tree (at level 1) could be shorter. Fix? yes -+ -+Inode 17 extent tree (at level 1) could be shorter. Fix? yes -+ -+Inode 18 extent tree (at level 1) could be shorter. Fix? yes -+ -+Inode 19 extent tree (at level 1) could be shorter. Fix? yes -+ -+Inode 20 extent tree (at level 1) could be shorter. Fix? yes -+ -+Inode 21 extent tree (at level 1) could be shorter. Fix? yes -+ -+Inode 22 extent tree (at level 1) could be shorter. Fix? yes -+ -+Inode 23 extent tree (at level 1) could be shorter. Fix? yes -+ -+Inode 24 extent tree (at level 1) could be shorter. Fix? yes -+ -+Inode 25 extent tree (at level 1) could be shorter. Fix? yes -+ -+Inode 26 extent tree (at level 1) could be shorter. Fix? yes -+ -+Inode 27 extent tree (at level 1) could be shorter. Fix? yes -+ -+Inode 28 extent tree (at level 1) could be shorter. Fix? yes -+ -+Inode 29 extent tree (at level 1) could be shorter. Fix? yes -+ -+Inode 30 extent tree (at level 1) could be shorter. Fix? yes -+ -+Pass 1E: Optimizing extent trees -+Pass 2: Checking directory structure -+Pass 3: Checking directory connectivity -+Pass 4: Checking reference counts -+Pass 5: Checking group summary information -+Free blocks count wrong for group #1 (7934, counted=7933). -+Fix? yes -+ -+Free blocks count wrong (62939, counted=62938). -+Fix? yes -+ -+ -+test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** -+test_filesys: 32/4096 files (43.8% non-contiguous), 2598/65536 blocks -+Exit status is 1 -diff --git a/tests/d_punch/name b/tests/d_punch/name -new file mode 100644 -index 0000000..724639f ---- /dev/null -+++ b/tests/d_punch/name -@@ -0,0 +1 @@ -+punch sparse files and big files -diff --git a/tests/d_punch/script b/tests/d_punch/script -new file mode 100644 -index 0000000..7a77c69 ---- /dev/null -+++ b/tests/d_punch/script -@@ -0,0 +1,129 @@ -+if test -x $DEBUGFS_EXE; then -+ -+FSCK_OPT=-fy -+OUT=$test_name.log -+if [ -f $test_dir/expect.gz ]; then -+ EXP=$test_name.tmp -+ gunzip < $test_dir/expect.gz > $EXP1 -+else -+ EXP=$test_dir/expect -+fi -+ -+cp /dev/null $OUT -+ -+cat > $TMPFILE.conf << ENDL -+[fs_types] -+ext4 = { -+ base_features = sparse_super,filetype,resize_inode,dir_index,ext_attr,^has_journal,extent,huge_file,flex_bg,uninit_bg,dir_nlink,extra_isize,64bit -+ blocksize = 1024 -+ inode_size = 256 -+ inode_ratio = 16384 -+} -+ENDL -+MKE2FS_CONFIG=$TMPFILE.conf $MKE2FS -F -o Linux -b 1024 -O ^bigalloc -T ext4 $TMPFILE 65536 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT 2>&1 -+rm -rf $TMPFILE.conf -+ -+$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 -+status=$? -+echo Exit status is $status >> $OUT.new -+sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT -+rm -f $OUT.new -+ -+echo "debugfs write files" >> $OUT -+make_file() { -+ name="$1" -+ start="$2" -+ flag="$3" -+ -+ cat << ENDL -+write /dev/null $name -+fallocate /$name 0 39 -+punch /$name 10 10 -+punch /$name 13 13 -+punch /$name 26 26 -+punch /$name 29 29 -+ENDL -+} -+ -+#Files we create: -+# a: punch a 40k file -+# b*: punch sparse file starting at b* -+# c*: punch spare file ending at c* -+# d: midcluster to midcluster, surrounding sparse -+# e: partial middle cluster alloc -+# f: one big file -+base=5000 -+cat > $TMPFILE.cmd << ENDL -+write /dev/null a -+fallocate /a 0 39 -+punch /a 0 39 -+ENDL -+echo "ex /a" >> $TMPFILE.cmd2 -+ -+make_file sample $base --uninit >> $TMPFILE.cmd -+echo "ex /sample" >> $TMPFILE.cmd2 -+base=10000 -+ -+for i in 8 9 10 11 12 13 14 15; do -+ make_file b$i $(($base + (40 * ($i - 8)))) --uninit >> $TMPFILE.cmd -+ echo "punch /b$i $i 39" >> $TMPFILE.cmd -+ echo "ex /b$i" >> $TMPFILE.cmd2 -+done -+ -+for i in 24 25 26 27 28 29 30 31; do -+ make_file c$i $(($base + 320 + (40 * ($i - 24)))) --uninit >> $TMPFILE.cmd -+ echo "punch /c$i 0 $i" >> $TMPFILE.cmd -+ echo "ex /c$i" >> $TMPFILE.cmd2 -+done -+ -+make_file d $(($base + 640)) --uninit >> $TMPFILE.cmd -+echo "punch /d 4 35" >> $TMPFILE.cmd -+echo "ex /d" >> $TMPFILE.cmd2 -+ -+make_file e $(($base + 680)) --uninit >> $TMPFILE.cmd -+echo "punch /e 19 20" >> $TMPFILE.cmd -+echo "ex /e" >> $TMPFILE.cmd2 -+ -+cat >> $TMPFILE.cmd << ENDL -+write /dev/null f -+sif /f size 1024 -+eo /f -+set_bmap --uninit 0 9000 -+ec -+sif /f blocks 2 -+setb 9000 -+fallocate /f 0 8999 -+punch /f 1 8998 -+ENDL -+echo "ex /f" >> $TMPFILE.cmd2 -+ -+$DEBUGFS_EXE -w -f $TMPFILE.cmd $TMPFILE > /dev/null 2>&1 -+$DEBUGFS_EXE -f $TMPFILE.cmd2 $TMPFILE >> $OUT.new 2>&1 -+sed -f $cmd_dir/filter.sed < $OUT.new >> $OUT -+rm -rf $OUT.new $TMPFILE.cmd $TMPFILE.cmd2 -+ -+$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 -+status=$? -+echo Exit status is $status >> $OUT.new -+sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT -+rm -f $OUT.new -+ -+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 IMAGE FSCK_OPT OUT EXP -+ -+else #if test -x $DEBUGFS_EXE; then -+ echo "$test_name: $test_description: skipped" -+fi -diff --git a/tests/d_punch_bigalloc/expect b/tests/d_punch_bigalloc/expect -new file mode 100644 -index 0000000..0138c3a ---- /dev/null -+++ b/tests/d_punch_bigalloc/expect -@@ -0,0 +1,175 @@ -+ -+Warning: the bigalloc feature is still under development -+See https://ext4.wiki.kernel.org/index.php/Bigalloc for more information -+ -+Creating filesystem with 65536 1k blocks and 4096 inodes -+ -+Allocating group tables: done -+Writing inode tables: done -+Writing superblocks and filesystem accounting information: done -+ -+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/4096 files (9.1% non-contiguous), 1144/65536 blocks -+Exit status is 0 -+debugfs write files -+debugfs: ex /a -+Level Entries Logical Physical Length Flags -+debugfs: ex /sample -+Level Entries Logical Physical Length Flags -+ 0/ 1 1/ 1 0 - 4294967295 1184 0 -+ 1/ 1 1/ 5 0 - 9 1144 - 1153 10 Uninit -+ 1/ 1 2/ 5 11 - 12 1155 - 1156 2 Uninit -+ 1/ 1 3/ 5 14 - 25 1158 - 1169 12 Uninit -+ 1/ 1 4/ 5 27 - 28 1171 - 1172 2 Uninit -+ 1/ 1 5/ 5 30 - 39 1174 - 1183 10 Uninit -+debugfs: ex /b8 -+Level Entries Logical Physical Length Flags -+ 0/ 1 1/ 1 0 - 4294967295 1232 0 -+ 1/ 1 1/ 1 0 - 7 1192 - 1199 8 Uninit -+debugfs: ex /b9 -+Level Entries Logical Physical Length Flags -+ 0/ 1 1/ 1 0 - 4294967295 1248 0 -+ 1/ 1 1/ 1 0 - 8 1200 - 1208 9 Uninit -+debugfs: ex /b10 -+Level Entries Logical Physical Length Flags -+ 0/ 1 1/ 1 0 - 4294967295 1272 0 -+ 1/ 1 1/ 1 0 - 9 1216 - 1225 10 Uninit -+debugfs: ex /b11 -+Level Entries Logical Physical Length Flags -+ 0/ 1 1/ 1 0 - 4294967295 1296 0 -+ 1/ 1 1/ 2 0 - 7 1240 - 1247 8 Uninit -+ 1/ 1 2/ 2 8 - 9 1256 - 1257 2 Uninit -+debugfs: ex /b12 -+Level Entries Logical Physical Length Flags -+ 0/ 1 1/ 1 0 - 4294967295 1320 0 -+ 1/ 1 1/ 3 0 - 7 1264 - 1271 8 Uninit -+ 1/ 1 2/ 3 8 - 9 1280 - 1281 2 Uninit -+ 1/ 1 3/ 3 11 - 11 1283 - 1283 1 Uninit -+debugfs: ex /b13 -+Level Entries Logical Physical Length Flags -+ 0/ 1 1/ 1 0 - 4294967295 1344 0 -+ 1/ 1 1/ 3 0 - 7 1288 - 1295 8 Uninit -+ 1/ 1 2/ 3 8 - 9 1304 - 1305 2 Uninit -+ 1/ 1 3/ 3 11 - 12 1307 - 1308 2 Uninit -+debugfs: ex /b14 -+Level Entries Logical Physical Length Flags -+ 0/ 1 1/ 1 0 - 4294967295 1368 0 -+ 1/ 1 1/ 3 0 - 7 1312 - 1319 8 Uninit -+ 1/ 1 2/ 3 8 - 9 1328 - 1329 2 Uninit -+ 1/ 1 3/ 3 11 - 12 1331 - 1332 2 Uninit -+debugfs: ex /b15 -+Level Entries Logical Physical Length Flags -+ 0/ 1 1/ 1 0 - 4294967295 1392 0 -+ 1/ 1 1/ 4 0 - 7 1336 - 1343 8 Uninit -+ 1/ 1 2/ 4 8 - 9 1352 - 1353 2 Uninit -+ 1/ 1 3/ 4 11 - 12 1355 - 1356 2 Uninit -+ 1/ 1 4/ 4 14 - 14 1358 - 1358 1 Uninit -+debugfs: ex /c24 -+Level Entries Logical Physical Length Flags -+ 0/ 1 1/ 1 25 - 4294967295 1416 4294967271 -+ 1/ 1 1/ 3 25 - 25 1401 - 1401 1 Uninit -+ 1/ 1 2/ 3 27 - 28 1403 - 1404 2 Uninit -+ 1/ 1 3/ 3 30 - 39 1406 - 1415 10 Uninit -+debugfs: ex /c25 -+Level Entries Logical Physical Length Flags -+ 0/ 1 1/ 1 27 - 4294967295 1440 4294967269 -+ 1/ 1 1/ 2 27 - 28 1427 - 1428 2 Uninit -+ 1/ 1 2/ 2 30 - 39 1430 - 1439 10 Uninit -+debugfs: ex /c26 -+Level Entries Logical Physical Length Flags -+ 0/ 1 1/ 1 27 - 4294967295 1464 4294967269 -+ 1/ 1 1/ 2 27 - 28 1451 - 1452 2 Uninit -+ 1/ 1 2/ 2 30 - 39 1454 - 1463 10 Uninit -+debugfs: ex /c27 -+Level Entries Logical Physical Length Flags -+ 0/ 1 1/ 1 28 - 4294967295 1488 4294967268 -+ 1/ 1 1/ 2 28 - 28 1476 - 1476 1 Uninit -+ 1/ 1 2/ 2 30 - 39 1478 - 1487 10 Uninit -+debugfs: ex /c28 -+Level Entries Logical Physical Length Flags -+ 0/ 1 1/ 1 30 - 4294967295 1512 4294967266 -+ 1/ 1 1/ 1 30 - 39 1502 - 1511 10 Uninit -+debugfs: ex /c29 -+Level Entries Logical Physical Length Flags -+ 0/ 1 1/ 1 30 - 4294967295 1536 4294967266 -+ 1/ 1 1/ 1 30 - 39 1526 - 1535 10 Uninit -+debugfs: ex /c30 -+Level Entries Logical Physical Length Flags -+ 0/ 1 1/ 1 31 - 4294967295 1560 4294967265 -+ 1/ 1 1/ 1 31 - 39 1551 - 1559 9 Uninit -+debugfs: ex /c31 -+Level Entries Logical Physical Length Flags -+ 0/ 1 1/ 1 32 - 4294967295 1584 4294967264 -+ 1/ 1 1/ 1 32 - 39 1576 - 1583 8 Uninit -+debugfs: ex /d -+Level Entries Logical Physical Length Flags -+ 0/ 1 1/ 1 0 - 4294967295 1600 0 -+ 1/ 1 1/ 2 0 - 3 1360 - 1363 4 Uninit -+ 1/ 1 2/ 2 36 - 39 1596 - 1599 4 Uninit -+debugfs: ex /e -+Level Entries Logical Physical Length Flags -+ 0/ 1 1/ 1 0 - 4294967295 1624 0 -+ 1/ 1 1/ 8 0 - 9 1376 - 1385 10 Uninit -+ 1/ 1 2/ 8 11 - 12 1387 - 1388 2 Uninit -+ 1/ 1 3/ 8 14 - 15 1390 - 1391 2 Uninit -+ 1/ 1 4/ 8 16 - 18 1568 - 1570 3 Uninit -+ 1/ 1 5/ 8 21 - 23 1573 - 1575 3 Uninit -+ 1/ 1 6/ 8 24 - 25 1608 - 1609 2 Uninit -+ 1/ 1 7/ 8 27 - 28 1611 - 1612 2 Uninit -+ 1/ 1 8/ 8 30 - 39 1614 - 1623 10 Uninit -+debugfs: ex /f -+Level Entries Logical Physical Length Flags -+ 0/ 0 1/ 2 0 - 0 9000 - 9000 1 Uninit -+ 0/ 0 2/ 2 8999 - 8999 17999 - 17999 1 Uninit -+Pass 1: Checking inodes, blocks, and sizes -+Inode 14 extent tree (at level 1) could be shorter. Fix? yes -+ -+Inode 15 extent tree (at level 1) could be shorter. Fix? yes -+ -+Inode 16 extent tree (at level 1) could be shorter. Fix? yes -+ -+Inode 17 extent tree (at level 1) could be shorter. Fix? yes -+ -+Inode 18 extent tree (at level 1) could be shorter. Fix? yes -+ -+Inode 19 extent tree (at level 1) could be shorter. Fix? yes -+ -+Inode 20 extent tree (at level 1) could be shorter. Fix? yes -+ -+Inode 22 extent tree (at level 1) could be shorter. Fix? yes -+ -+Inode 23 extent tree (at level 1) could be shorter. Fix? yes -+ -+Inode 24 extent tree (at level 1) could be shorter. Fix? yes -+ -+Inode 25 extent tree (at level 1) could be shorter. Fix? yes -+ -+Inode 26 extent tree (at level 1) could be shorter. Fix? yes -+ -+Inode 27 extent tree (at level 1) could be shorter. Fix? yes -+ -+Inode 28 extent tree (at level 1) could be shorter. Fix? yes -+ -+Inode 29 extent tree (at level 1) could be shorter. Fix? yes -+ -+Inode 30 extent tree (at level 1) could be shorter. Fix? yes -+ -+Pass 1E: Optimizing extent trees -+Pass 2: Checking directory structure -+Pass 3: Checking directory connectivity -+Pass 4: Checking reference counts -+Pass 5: Checking group summary information -+Free blocks count wrong for group #0 (8003, counted=8002). -+Fix? yes -+ -+Free blocks count wrong (64024, counted=64016). -+Fix? yes -+ -+ -+test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** -+test_filesys: 32/4096 files (43.8% non-contiguous), 1520/65536 blocks -+Exit status is 1 -diff --git a/tests/d_punch_bigalloc/name b/tests/d_punch_bigalloc/name -new file mode 100644 -index 0000000..6d61ebe ---- /dev/null -+++ b/tests/d_punch_bigalloc/name -@@ -0,0 +1 @@ -+punch sparse files and big files with bigalloc -diff --git a/tests/d_punch_bigalloc/script b/tests/d_punch_bigalloc/script -new file mode 100644 -index 0000000..6eb0571 ---- /dev/null -+++ b/tests/d_punch_bigalloc/script -@@ -0,0 +1,130 @@ -+if test -x $DEBUGFS_EXE; then -+ -+FSCK_OPT=-fy -+OUT=$test_name.log -+if [ -f $test_dir/expect.gz ]; then -+ EXP=$test_name.tmp -+ gunzip < $test_dir/expect.gz > $EXP1 -+else -+ EXP=$test_dir/expect -+fi -+ -+cp /dev/null $OUT -+ -+cat > $TMPFILE.conf << ENDL -+[fs_types] -+ext4 = { -+ cluster_size = 8192 -+ base_features = sparse_super,filetype,resize_inode,dir_index,ext_attr,^has_journal,extent,huge_file,flex_bg,uninit_bg,dir_nlink,extra_isize,64bit -+ blocksize = 1024 -+ inode_size = 256 -+ inode_ratio = 16384 -+} -+ENDL -+MKE2FS_CONFIG=$TMPFILE.conf $MKE2FS -F -o Linux -b 1024 -O bigalloc -T ext4 $TMPFILE 65536 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT 2>&1 -+rm -rf $TMPFILE.conf -+ -+$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 -+status=$? -+echo Exit status is $status >> $OUT.new -+sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT -+rm -f $OUT.new -+ -+echo "debugfs write files" >> $OUT -+make_file() { -+ name="$1" -+ start="$2" -+ flag="$3" -+ -+ cat << ENDL -+write /dev/null $name -+fallocate /$name 0 39 -+punch /$name 10 10 -+punch /$name 13 13 -+punch /$name 26 26 -+punch /$name 29 29 -+ENDL -+} -+ -+#Files we create: -+# a: punch a 40k file -+# b*: punch sparse file starting at b* -+# c*: punch spare file ending at c* -+# d: midcluster to midcluster, surrounding sparse -+# e: partial middle cluster alloc -+# f: one big file -+base=5000 -+cat > $TMPFILE.cmd << ENDL -+write /dev/null a -+fallocate /a 0 39 -+punch /a 0 39 -+ENDL -+echo "ex /a" >> $TMPFILE.cmd2 -+ -+make_file sample $base --uninit >> $TMPFILE.cmd -+echo "ex /sample" >> $TMPFILE.cmd2 -+base=10000 -+ -+for i in 8 9 10 11 12 13 14 15; do -+ make_file b$i $(($base + (40 * ($i - 8)))) --uninit >> $TMPFILE.cmd -+ echo "punch /b$i $i 39" >> $TMPFILE.cmd -+ echo "ex /b$i" >> $TMPFILE.cmd2 -+done -+ -+for i in 24 25 26 27 28 29 30 31; do -+ make_file c$i $(($base + 320 + (40 * ($i - 24)))) --uninit >> $TMPFILE.cmd -+ echo "punch /c$i 0 $i" >> $TMPFILE.cmd -+ echo "ex /c$i" >> $TMPFILE.cmd2 -+done -+ -+make_file d $(($base + 640)) --uninit >> $TMPFILE.cmd -+echo "punch /d 4 35" >> $TMPFILE.cmd -+echo "ex /d" >> $TMPFILE.cmd2 -+ -+make_file e $(($base + 680)) --uninit >> $TMPFILE.cmd -+echo "punch /e 19 20" >> $TMPFILE.cmd -+echo "ex /e" >> $TMPFILE.cmd2 -+ -+cat >> $TMPFILE.cmd << ENDL -+write /dev/null f -+sif /f size 1024 -+eo /f -+set_bmap --uninit 0 9000 -+ec -+sif /f blocks 16 -+setb 9000 -+fallocate /f 0 8999 -+punch /f 1 8998 -+ENDL -+echo "ex /f" >> $TMPFILE.cmd2 -+ -+$DEBUGFS_EXE -w -f $TMPFILE.cmd $TMPFILE > /dev/null 2>&1 -+$DEBUGFS_EXE -f $TMPFILE.cmd2 $TMPFILE >> $OUT.new 2>&1 -+sed -f $cmd_dir/filter.sed < $OUT.new >> $OUT -+rm -rf $OUT.new $TMPFILE.cmd $TMPFILE.cmd2 -+ -+$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 -+status=$? -+echo Exit status is $status >> $OUT.new -+sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT -+rm -f $OUT.new -+ -+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 IMAGE FSCK_OPT OUT EXP -+ -+else #if test -x $DEBUGFS_EXE; then -+ echo "$test_name: $test_description: skipped" -+fi -diff --git a/tests/d_special_files/expect b/tests/d_special_files/expect -index 2b2dbfa..f729b0f 100644 ---- a/tests/d_special_files/expect -+++ b/tests/d_special_files/expect -@@ -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 -index 0000000..4db5414 ---- /dev/null -+++ b/tests/d_xattr_edits/expect -@@ -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 -f d_xattr_edits.tmp / user.file_based_xattr -+Exit status is 0 -+ea_list / -+Extended attributes: -+ user.file_based_xattr = "12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567\012" (108) -+Exit status is 0 -+ea_get -f d_xattr_edits.ver.tmp / user.file_based_xattr -+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 -index 0000000..c0c428c ---- /dev/null -+++ b/tests/d_xattr_edits/name -@@ -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 -index 0000000..2e356e8 ---- /dev/null -+++ b/tests/d_xattr_edits/script -@@ -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 -R "ea_set / user.joe smith" $TMPFILE >> $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 -R "ea_set / user.moo FEE_FIE_FOE_FUMMMMMM" $TMPFILE >> $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 -R "ea_list /" $TMPFILE >> $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 -R "ea_get / user.moo" $TMPFILE >> $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 -R "ea_get / nosuchea" $TMPFILE >> $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 -R "ea_rm / user.moo" $TMPFILE >> $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 -R "ea_rm / nosuchea" $TMPFILE >> $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 -R "ea_list /" $TMPFILE >> $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 -R "ea_get / user.moo" $TMPFILE >> $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 -R "ea_rm / user.joe" $TMPFILE >> $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 -R "ea_list /" $TMPFILE >> $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 -f $TEST_DATA / user.file_based_xattr" > $OUT.new -+$DEBUGFS -w -R "ea_set -f $TEST_DATA / user.file_based_xattr" $TMPFILE >> $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 -R "ea_list /" $TMPFILE >> $OUT.new 2>&1 -+status=$? -+echo Exit status is $status >> $OUT.new -+sed -f $cmd_dir/filter.sed $OUT.new >> $OUT -+ -+echo "ea_get -f $VERIFY_DATA / user.file_based_xattr" > $OUT.new -+$DEBUGFS -w -R "ea_get -f $VERIFY_DATA / user.file_based_xattr" $TMPFILE >> $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/defaults/j_script b/tests/defaults/j_script -new file mode 100644 -index 0000000..7a3b34f ---- /dev/null -+++ b/tests/defaults/j_script -@@ -0,0 +1 @@ -+. $cmd_dir/run_e2fsck -diff --git a/tests/f_bad_bbitmap/expect.1 b/tests/f_bad_bbitmap/expect.1 -new file mode 100644 -index 0000000..71ad1bb ---- /dev/null -+++ b/tests/f_bad_bbitmap/expect.1 -@@ -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 -index 0000000..411e656 ---- /dev/null -+++ b/tests/f_bad_bbitmap/expect.2 -@@ -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 -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 -index 0000000..923ddcb ---- /dev/null -+++ b/tests/f_bad_bbitmap/name -@@ -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 -index 0000000..ca8f77f ---- /dev/null -+++ b/tests/f_bad_bmap_csum/expect.1 -@@ -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 -index 0000000..411e656 ---- /dev/null -+++ b/tests/f_bad_bmap_csum/expect.2 -@@ -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 -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 -index 0000000..df19fe3 ---- /dev/null -+++ b/tests/f_bad_bmap_csum/name -@@ -0,0 +1 @@ -+bad block/inode bitmap csum (metadata_csum) -diff --git a/tests/f_bad_disconnected_inode/expect.1 b/tests/f_bad_disconnected_inode/expect.1 -index 11862f6..c5ea7bf 100644 ---- a/tests/f_bad_disconnected_inode/expect.1 -+++ b/tests/f_bad_disconnected_inode/expect.1 -@@ -2,10 +2,13 @@ Pass 1: Checking inodes, blocks, and sizes - Inode 1 has EXTENTS_FL flag set on filesystem without extents support. - Clear? yes - --Inode 15 has EXTENTS_FL flag set on filesystem without extents support. -+Inode 14 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. -+Inode 15 has INLINE_DATA_FL flag on filesystem without inline data support. -+Clear? yes -+ -+Inode 16 has INLINE_DATA_FL flag on filesystem without inline data support. - Clear? yes - - Pass 2: Checking directory structure -@@ -21,12 +24,6 @@ Clear? yes - Inode 13 (...) has invalid mode (0117003). - Clear? yes - --i_file_acl for inode 14 (...) is 2892851642, should be zero. --Clear? yes -- --Inode 14 (...) has invalid mode (0154247). --Clear? yes -- - Pass 5: Checking group summary information - Block bitmap differences: -(9--19) - Fix? yes -@@ -37,15 +34,9 @@ Fix? yes - Free blocks count wrong (79, counted=91). - Fix? yes - --Free inodes count wrong for group #0 (6, counted=5). --Fix? yes -- - Directories count wrong for group #0 (3, counted=2). - Fix? yes - --Free inodes count wrong (6, counted=5). --Fix? yes -- - - test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** - test_filesys: 11/16 files (0.0% non-contiguous), 9/100 blocks -diff --git a/tests/f_bad_gdt_csum/expect.1 b/tests/f_bad_gdt_csum/expect.1 -new file mode 100644 -index 0000000..e14c897 ---- /dev/null -+++ b/tests/f_bad_gdt_csum/expect.1 -@@ -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 -index 0000000..411e656 ---- /dev/null -+++ b/tests/f_bad_gdt_csum/expect.2 -@@ -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 -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 -index 0000000..fe2c601 ---- /dev/null -+++ b/tests/f_bad_gdt_csum/name -@@ -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 -index 0000000..ea17523 ---- /dev/null -+++ b/tests/f_bad_ibitmap/expect.1 -@@ -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 -index 0000000..411e656 ---- /dev/null -+++ b/tests/f_bad_ibitmap/expect.2 -@@ -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 -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 -index 0000000..76ec12d ---- /dev/null -+++ b/tests/f_bad_ibitmap/name -@@ -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 -index 0000000..b3c628d ---- /dev/null -+++ b/tests/f_bad_inode_csum/expect.1 -@@ -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 -index 0000000..b97a902 ---- /dev/null -+++ b/tests/f_bad_inode_csum/expect.2 -@@ -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 -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 -index 0000000..68bf7ce ---- /dev/null -+++ b/tests/f_bad_inode_csum/name -@@ -0,0 +1 @@ -+inode table corruption (metadata_csum) -diff --git a/tests/f_badcluster/expect b/tests/f_badcluster/expect -index 6cfffb7..65a1641 100644 ---- a/tests/f_badcluster/expect -+++ b/tests/f_badcluster/expect -@@ -19,12 +19,14 @@ Inode 18 logical block 3 (physical block 1201) violates cluster allocation rules - Will fix in pass 1B. - Inode 18, i_blocks is 32, should be 64. Fix? yes - -+Inode 15 on bigalloc filesystem cannot be block mapped. 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 -@@ -65,19 +67,20 @@ File /g (inode #18, mod time Tue Jun 17 08:00:50 2014) - has 1 multiply-claimed block(s), shared with 0 file(s): - Clone multiply-claimed blocks? yes - -+Pass 1E: Optimizing extent trees - Pass 2: Checking directory structure - Pass 3: Checking directory connectivity - Pass 4: Checking reference counts - Pass 5: Checking group summary information --Free blocks count wrong for group #0 (50, counted=47). -+Free blocks count wrong for group #0 (51, counted=48). - Fix? yes - --Free blocks count wrong (800, counted=752). -+Free blocks count wrong (816, counted=768). - Fix? yes - - - test_fs: ***** FILE SYSTEM WAS MODIFIED ***** --test_fs: 18/128 files (22.2% non-contiguous), 1296/2048 blocks -+test_fs: 18/128 files (22.2% non-contiguous), 1280/2048 blocks - Pass 1: Checking inodes, blocks, and sizes - Inode 12, i_blocks is 64, should be 32. Fix? yes - -@@ -94,21 +97,21 @@ Pass 5: Checking group summary information - Block bitmap differences: -(1168--1200) - Fix? yes - --Free blocks count wrong for group #0 (47, counted=50). -+Free blocks count wrong for group #0 (48, counted=51). - Fix? yes - --Free blocks count wrong (752, counted=800). -+Free blocks count wrong (768, counted=816). - Fix? yes - - - test_fs: ***** FILE SYSTEM WAS MODIFIED ***** --test_fs: 18/128 files (5.6% non-contiguous), 1248/2048 blocks -+test_fs: 18/128 files (5.6% non-contiguous), 1232/2048 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 --test_fs: 18/128 files (5.6% non-contiguous), 1248/2048 blocks -+test_fs: 18/128 files (5.6% non-contiguous), 1232/2048 blocks - debugfs: stat /a - Inode: 12 Type: regular Mode: 0644 Flags: 0x80000 - Generation: 1117152157 Version: 0x00000001 -@@ -146,19 +149,16 @@ mtime: 0x539ff5b2 -- Tue Jun 17 08:00:50 2014 - EXTENTS: - (0-1):1216-1217, (2):1218 - debugfs: stat /d --Inode: 15 Type: regular Mode: 0644 Flags: 0x0 -+Inode: 15 Type: regular Mode: 0644 Flags: 0x80000 - Generation: 1117152160 Version: 0x00000001 - User: 0 Group: 0 Size: 3072 - File ACL: 0 Directory ACL: 0 --Links: 1 Blockcount: 32 -+Links: 1 Blockcount: 0 - Fragment: Address: 0 Number: 0 Size: 0 - ctime: 0x539ff5b2 -- Tue Jun 17 08:00:50 2014 - atime: 0x539ff5b2 -- Tue Jun 17 08:00:50 2014 - mtime: 0x539ff5b2 -- Tue Jun 17 08:00:50 2014 --BLOCKS: --(TIND):1650 --TOTAL: 1 -- -+EXTENTS: - debugfs: stat /e - Inode: 16 Type: regular Mode: 0644 Flags: 0x80000 - Generation: 1117152161 Version: 0x00000001 -diff --git a/tests/f_badcluster/script b/tests/f_badcluster/script -index 56b4b7f..ea9e488 100644 ---- a/tests/f_badcluster/script -+++ b/tests/f_badcluster/script -@@ -8,7 +8,7 @@ if test -x $DEBUGFS_EXE; then - $FSCK -fy $TMPFILE 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT - for i in a b c d e f g; do echo "stat /$i"; done > $TMPFILE.tmp - echo "quit" >> $TMPFILE.tmp -- $DEBUGFS_EXE -f $TMPFILE.tmp $TMPFILE >> $OUT -+ $DEBUGFS_EXE -f $TMPFILE.tmp $TMPFILE 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT - rm -f $TMPFILE.tmp - - cmp -s $OUT $EXP -diff --git a/tests/f_badjour_indblks/expect.1 b/tests/f_badjour_indblks/expect.1 -index 7ccc59b..cb8054c 100644 ---- a/tests/f_badjour_indblks/expect.1 -+++ b/tests/f_badjour_indblks/expect.1 -@@ -1,7 +1,7 @@ - Superblock has an invalid journal (inode 8). - Clear? yes - --*** ext3 journal has been deleted - filesystem is now ext2 only *** -+*** journal has been deleted *** - - Adding dirhash hint to filesystem. - -@@ -25,7 +25,7 @@ Recreate journal? yes - - Creating journal (1024 blocks): Done. - --*** journal has been re-created - filesystem is now ext3 again *** -+*** journal has been regenerated *** - - test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** - test_filesys: 11/256 files (0.0% non-contiguous), 1111/8192 blocks -diff --git a/tests/f_badjourblks/expect.1 b/tests/f_badjourblks/expect.1 -index 34c6658..5483a0d 100644 ---- a/tests/f_badjourblks/expect.1 -+++ b/tests/f_badjourblks/expect.1 -@@ -1,7 +1,7 @@ - Superblock has an invalid journal (inode 8). - Clear? yes - --*** ext3 journal has been deleted - filesystem is now ext2 only *** -+*** journal has been deleted *** - - Pass 1: Checking inodes, blocks, and sizes - Journal inode is not in use, but contains data. Clear? yes -@@ -23,7 +23,7 @@ Recreate journal? yes - - Creating journal (1024 blocks): Done. - --*** journal has been re-created - filesystem is now ext3 again *** -+*** journal has been regenerated *** - - test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** - test_filesys: 11/256 files (0.0% non-contiguous), 1079/8192 blocks -diff --git a/tests/f_bb_in_bb/expect.1 b/tests/f_bb_in_bb/expect.1 -new file mode 100644 -index 0000000..1d719e5 ---- /dev/null -+++ b/tests/f_bb_in_bb/expect.1 -@@ -0,0 +1,17 @@ -+Pass 1: Checking inodes, blocks, and sizes -+Bad block list says the bad block list inode is bad. Clear inode? yes -+ -+Pass 2: Checking directory structure -+Pass 3: Checking directory connectivity -+Pass 4: Checking reference counts -+Pass 5: Checking group summary information -+Free blocks count wrong for group #0 (493, counted=494). -+Fix? yes -+ -+Free blocks count wrong (493, counted=494). -+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_bb_in_bb/expect.2 b/tests/f_bb_in_bb/expect.2 -new file mode 100644 -index 0000000..411e656 ---- /dev/null -+++ b/tests/f_bb_in_bb/expect.2 -@@ -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_bb_in_bb/image.gz b/tests/f_bb_in_bb/image.gz -new file mode 100644 -index 0000000..e2c46c0 -Binary files /dev/null and b/tests/f_bb_in_bb/image.gz differ -diff --git a/tests/f_bb_in_bb/name b/tests/f_bb_in_bb/name -new file mode 100644 -index 0000000..88727e1 ---- /dev/null -+++ b/tests/f_bb_in_bb/name -@@ -0,0 +1 @@ -+bad block inode table block in bad block list -diff --git a/tests/f_bbfile/expect.1 b/tests/f_bbfile/expect.1 -index 1d639f6..ec1a36e 100644 ---- a/tests/f_bbfile/expect.1 -+++ b/tests/f_bbfile/expect.1 -@@ -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_cloneblock_alloc_error/expect.1 b/tests/f_cloneblock_alloc_error/expect.1 -new file mode 100644 -index 0000000..24fe1ff ---- /dev/null -+++ b/tests/f_cloneblock_alloc_error/expect.1 -@@ -0,0 +1,36 @@ -+Pass 1: Checking inodes, blocks, and sizes -+Inode 12, i_size is 0, should be 2015232. 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 13: 8 -+Multiply-claimed block(s) in inode 14: 8 -+Pass 1C: Scanning directories for inodes with multiply-claimed blocks -+Pass 1D: Reconciling multiply-claimed blocks -+(There are 2 inodes containing multiply-claimed blocks.) -+ -+File /b (inode #13, mod time Wed Jan 21 03:41:55 2015) -+ has 1 multiply-claimed block(s), shared with 1 file(s): -+ /c (inode #14, mod time Wed Jan 21 03:42:37 2015) -+Clone multiply-claimed blocks? yes -+ -+clone_file: Could not allocate block in ext2 filesystem returned from clone_file_block -+Couldn't clone file: Could not allocate block in ext2 filesystem -+Delete file? yes -+ -+File /c (inode #14, mod time Wed Jan 21 03:42:37 2015) -+ has 1 multiply-claimed block(s), shared with 1 file(s): -+ /b (inode #13, mod time Wed Jan 21 03:41:55 2015) -+Multiply-claimed blocks already reassigned or cloned. -+ -+Pass 2: Checking directory structure -+Entry 'b' in / (2) has deleted/unused inode 13. Clear? yes -+ -+Pass 3: Checking directory connectivity -+Pass 4: Checking reference counts -+Pass 5: Checking group summary information -+ -+test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** -+test_filesys: 13/128 files (7.7% non-contiguous), 512/512 blocks -+Exit status is 1 -diff --git a/tests/f_cloneblock_alloc_error/expect.2 b/tests/f_cloneblock_alloc_error/expect.2 -new file mode 100644 -index 0000000..f7781ec ---- /dev/null -+++ b/tests/f_cloneblock_alloc_error/expect.2 -@@ -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: 13/128 files (7.7% non-contiguous), 512/512 blocks -+Exit status is 0 -diff --git a/tests/f_cloneblock_alloc_error/image.gz b/tests/f_cloneblock_alloc_error/image.gz -new file mode 100644 -index 0000000..ed01df1 -Binary files /dev/null and b/tests/f_cloneblock_alloc_error/image.gz differ -diff --git a/tests/f_cloneblock_alloc_error/name b/tests/f_cloneblock_alloc_error/name -new file mode 100644 -index 0000000..9196e89 ---- /dev/null -+++ b/tests/f_cloneblock_alloc_error/name -@@ -0,0 +1 @@ -+decrement badcount after remapping duplicate block -diff --git a/tests/f_collapse_extent_tree/expect.1 b/tests/f_collapse_extent_tree/expect.1 -new file mode 100644 -index 0000000..e2eb65e ---- /dev/null -+++ b/tests/f_collapse_extent_tree/expect.1 -@@ -0,0 +1,16 @@ -+debugfs: ex /a -+Level Entries Logical Physical Length Flags -+ 0/ 1 1/ 1 0 - 0 9 1 -+ 1/ 1 1/ 1 0 - 0 10 - 10 1 -+Pass 1: Checking inodes, blocks, and sizes -+Inode 12 extent tree (at level 1) could be shorter. Fix? yes -+ -+Pass 1E: Optimizing extent trees -+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_collapse_extent_tree/expect.2 b/tests/f_collapse_extent_tree/expect.2 -new file mode 100644 -index 0000000..a1d28b1 ---- /dev/null -+++ b/tests/f_collapse_extent_tree/expect.2 -@@ -0,0 +1,10 @@ -+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 -+debugfs: ex /a -+Level Entries Logical Physical Length Flags -+ 0/ 0 1/ 1 0 - 0 10 - 10 1 -diff --git a/tests/f_collapse_extent_tree/image.gz b/tests/f_collapse_extent_tree/image.gz -new file mode 100644 -index 0000000..97036cc -Binary files /dev/null and b/tests/f_collapse_extent_tree/image.gz differ -diff --git a/tests/f_collapse_extent_tree/name b/tests/f_collapse_extent_tree/name -new file mode 100644 -index 0000000..83e506f ---- /dev/null -+++ b/tests/f_collapse_extent_tree/name -@@ -0,0 +1 @@ -+extent tree can be collapsed one level -diff --git a/tests/f_collapse_extent_tree/script b/tests/f_collapse_extent_tree/script -new file mode 100644 -index 0000000..ee18438 ---- /dev/null -+++ b/tests/f_collapse_extent_tree/script -@@ -0,0 +1,118 @@ -+if [ "$DESCRIPTION"x != x ]; then -+ test_description="$DESCRIPTION" -+fi -+if [ "$IMAGE"x = x ]; then -+ IMAGE=$test_dir/image.gz -+fi -+ -+if [ "$FSCK_OPT"x = x ]; then -+ FSCK_OPT=-yf -+fi -+ -+if [ "$SECOND_FSCK_OPT"x = x ]; then -+ SECOND_FSCK_OPT=-yf -+fi -+ -+if [ "$OUT1"x = x ]; then -+ OUT1=$test_name.1.log -+fi -+ -+if [ "$OUT2"x = x ]; then -+ OUT2=$test_name.2.log -+fi -+ -+if [ "$EXP1"x = x ]; then -+ if [ -f $test_dir/expect.1.gz ]; then -+ EXP1=$test_name.1.tmp -+ gunzip < $test_dir/expect.1.gz > $EXP1 -+ else -+ EXP1=$test_dir/expect.1 -+ fi -+fi -+ -+if [ "$EXP2"x = x ]; then -+ if [ -f $test_dir/expect.2.gz ]; then -+ EXP2=$test_name.2.tmp -+ gunzip < $test_dir/expect.2.gz > $EXP2 -+ else -+ EXP2=$test_dir/expect.2 -+ fi -+fi -+ -+if [ "$SKIP_GUNZIP" != "true" ] ; then -+ gunzip < $IMAGE > $TMPFILE -+fi -+ -+cp /dev/null $OUT1 -+ -+eval $PREP_CMD -+ -+echo 'ex /a' > $TMPFILE.cmd -+$DEBUGFS -f $TMPFILE.cmd $TMPFILE > $OUT1.new 2>&1 -+rm -rf $TMPFILE.cmd -+$FSCK $FSCK_OPT -N test_filesys $TMPFILE >> $OUT1.new 2>&1 -+status=$? -+echo Exit status is $status >> $OUT1.new -+sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT1.new >> $OUT1 -+rm -f $OUT1.new -+ -+if [ "$ONE_PASS_ONLY" != "true" ]; then -+ $FSCK $SECOND_FSCK_OPT -N test_filesys $TMPFILE > $OUT2.new 2>&1 -+ status=$? -+ echo Exit status is $status >> $OUT2.new -+ echo 'ex /a' > $TMPFILE.cmd -+ $DEBUGFS -f $TMPFILE.cmd $TMPFILE >> $OUT2.new 2>&1 -+ rm -rf $TMPFILE.cmd -+ sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT2.new > $OUT2 -+ rm -f $OUT2.new -+fi -+ -+eval $AFTER_CMD -+ -+if [ "$SKIP_VERIFY" != "true" ] ; then -+ rm -f $test_name.ok $test_name.failed -+ cmp -s $OUT1 $EXP1 -+ status1=$? -+ if [ "$ONE_PASS_ONLY" != "true" ]; then -+ cmp -s $OUT2 $EXP2 -+ status2=$? -+ else -+ status2=0 -+ fi -+ if [ "$PASS_ZERO" = "true" ]; then -+ cmp -s $test_name.0.log $test_dir/expect.0 -+ status3=$? -+ else -+ status3=0 -+ fi -+ -+ if [ -z "$test_description" ] ; then -+ description="$test_name" -+ else -+ description="$test_name: $test_description" -+ fi -+ -+ if [ "$status1" -eq 0 -a "$status2" -eq 0 -a "$status3" -eq 0 ] ; then -+ echo "$description: ok" -+ touch $test_name.ok -+ else -+ echo "$description: failed" -+ rm -f $test_name.failed -+ if [ "$PASS_ZERO" = "true" ]; then -+ diff $DIFF_OPTS $test_dir/expect.0 \ -+ $test_name.0.log >> $test_name.failed -+ fi -+ diff $DIFF_OPTS $EXP1 $OUT1 >> $test_name.failed -+ if [ "$ONE_PASS_ONLY" != "true" ]; then -+ diff $DIFF_OPTS $EXP2 $OUT2 >> $test_name.failed -+ fi -+ fi -+ rm -f tmp_expect -+fi -+ -+if [ "$SKIP_CLEANUP" != "true" ] ; then -+ unset IMAGE FSCK_OPT SECOND_FSCK_OPT OUT1 OUT2 EXP1 EXP2 -+ unset SKIP_VERIFY SKIP_CLEANUP SKIP_GUNZIP ONE_PASS_ONLY PREP_CMD -+ unset DESCRIPTION SKIP_UNLINK AFTER_CMD PASS_ZERO -+fi -+ -diff --git a/tests/f_compress_extent_tree_level/expect.1 b/tests/f_compress_extent_tree_level/expect.1 -new file mode 100644 -index 0000000..1159f24 ---- /dev/null -+++ b/tests/f_compress_extent_tree_level/expect.1 -@@ -0,0 +1,23 @@ -+debugfs: ex /a -+Level Entries Logical Physical Length Flags -+ 0/ 1 1/ 2 0 - 16 9 17 -+ 1/ 1 1/ 4 0 - 0 10 - 10 1 -+ 1/ 1 2/ 4 11 - 11 100 - 100 1 -+ 1/ 1 3/ 4 13 - 13 101 - 101 1 -+ 1/ 1 4/ 4 15 - 15 102 - 102 1 -+ 0/ 1 2/ 2 17 - 21 12 5 -+ 1/ 1 1/ 3 17 - 17 103 - 103 1 -+ 1/ 1 2/ 3 19 - 19 104 - 104 1 -+ 1/ 1 3/ 3 21 - 21 105 - 105 1 -+Pass 1: Checking inodes, blocks, and sizes -+Inode 12 extent tree (at (level 1) could be narrower. Fix? yes -+ -+Pass 1E: Optimizing extent trees -+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 (8.3% non-contiguous), 26/512 blocks -+Exit status is 1 -diff --git a/tests/f_compress_extent_tree_level/expect.2 b/tests/f_compress_extent_tree_level/expect.2 -new file mode 100644 -index 0000000..07d1082 ---- /dev/null -+++ b/tests/f_compress_extent_tree_level/expect.2 -@@ -0,0 +1,17 @@ -+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), 26/512 blocks -+Exit status is 0 -+debugfs: ex /a -+Level Entries Logical Physical Length Flags -+ 0/ 1 1/ 1 0 - 21 9 22 -+ 1/ 1 1/ 7 0 - 0 10 - 10 1 -+ 1/ 1 2/ 7 11 - 11 100 - 100 1 -+ 1/ 1 3/ 7 13 - 13 101 - 101 1 -+ 1/ 1 4/ 7 15 - 15 102 - 102 1 -+ 1/ 1 5/ 7 17 - 17 103 - 103 1 -+ 1/ 1 6/ 7 19 - 19 104 - 104 1 -+ 1/ 1 7/ 7 21 - 21 105 - 105 1 -diff --git a/tests/f_compress_extent_tree_level/image.gz b/tests/f_compress_extent_tree_level/image.gz -new file mode 100644 -index 0000000..a552a58 -Binary files /dev/null and b/tests/f_compress_extent_tree_level/image.gz differ -diff --git a/tests/f_compress_extent_tree_level/name b/tests/f_compress_extent_tree_level/name -new file mode 100644 -index 0000000..fde4f4a ---- /dev/null -+++ b/tests/f_compress_extent_tree_level/name -@@ -0,0 +1 @@ -+compress an extent tree level -diff --git a/tests/f_compress_extent_tree_level/script b/tests/f_compress_extent_tree_level/script -new file mode 100644 -index 0000000..ee18438 ---- /dev/null -+++ b/tests/f_compress_extent_tree_level/script -@@ -0,0 +1,118 @@ -+if [ "$DESCRIPTION"x != x ]; then -+ test_description="$DESCRIPTION" -+fi -+if [ "$IMAGE"x = x ]; then -+ IMAGE=$test_dir/image.gz -+fi -+ -+if [ "$FSCK_OPT"x = x ]; then -+ FSCK_OPT=-yf -+fi -+ -+if [ "$SECOND_FSCK_OPT"x = x ]; then -+ SECOND_FSCK_OPT=-yf -+fi -+ -+if [ "$OUT1"x = x ]; then -+ OUT1=$test_name.1.log -+fi -+ -+if [ "$OUT2"x = x ]; then -+ OUT2=$test_name.2.log -+fi -+ -+if [ "$EXP1"x = x ]; then -+ if [ -f $test_dir/expect.1.gz ]; then -+ EXP1=$test_name.1.tmp -+ gunzip < $test_dir/expect.1.gz > $EXP1 -+ else -+ EXP1=$test_dir/expect.1 -+ fi -+fi -+ -+if [ "$EXP2"x = x ]; then -+ if [ -f $test_dir/expect.2.gz ]; then -+ EXP2=$test_name.2.tmp -+ gunzip < $test_dir/expect.2.gz > $EXP2 -+ else -+ EXP2=$test_dir/expect.2 -+ fi -+fi -+ -+if [ "$SKIP_GUNZIP" != "true" ] ; then -+ gunzip < $IMAGE > $TMPFILE -+fi -+ -+cp /dev/null $OUT1 -+ -+eval $PREP_CMD -+ -+echo 'ex /a' > $TMPFILE.cmd -+$DEBUGFS -f $TMPFILE.cmd $TMPFILE > $OUT1.new 2>&1 -+rm -rf $TMPFILE.cmd -+$FSCK $FSCK_OPT -N test_filesys $TMPFILE >> $OUT1.new 2>&1 -+status=$? -+echo Exit status is $status >> $OUT1.new -+sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT1.new >> $OUT1 -+rm -f $OUT1.new -+ -+if [ "$ONE_PASS_ONLY" != "true" ]; then -+ $FSCK $SECOND_FSCK_OPT -N test_filesys $TMPFILE > $OUT2.new 2>&1 -+ status=$? -+ echo Exit status is $status >> $OUT2.new -+ echo 'ex /a' > $TMPFILE.cmd -+ $DEBUGFS -f $TMPFILE.cmd $TMPFILE >> $OUT2.new 2>&1 -+ rm -rf $TMPFILE.cmd -+ sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT2.new > $OUT2 -+ rm -f $OUT2.new -+fi -+ -+eval $AFTER_CMD -+ -+if [ "$SKIP_VERIFY" != "true" ] ; then -+ rm -f $test_name.ok $test_name.failed -+ cmp -s $OUT1 $EXP1 -+ status1=$? -+ if [ "$ONE_PASS_ONLY" != "true" ]; then -+ cmp -s $OUT2 $EXP2 -+ status2=$? -+ else -+ status2=0 -+ fi -+ if [ "$PASS_ZERO" = "true" ]; then -+ cmp -s $test_name.0.log $test_dir/expect.0 -+ status3=$? -+ else -+ status3=0 -+ fi -+ -+ if [ -z "$test_description" ] ; then -+ description="$test_name" -+ else -+ description="$test_name: $test_description" -+ fi -+ -+ if [ "$status1" -eq 0 -a "$status2" -eq 0 -a "$status3" -eq 0 ] ; then -+ echo "$description: ok" -+ touch $test_name.ok -+ else -+ echo "$description: failed" -+ rm -f $test_name.failed -+ if [ "$PASS_ZERO" = "true" ]; then -+ diff $DIFF_OPTS $test_dir/expect.0 \ -+ $test_name.0.log >> $test_name.failed -+ fi -+ diff $DIFF_OPTS $EXP1 $OUT1 >> $test_name.failed -+ if [ "$ONE_PASS_ONLY" != "true" ]; then -+ diff $DIFF_OPTS $EXP2 $OUT2 >> $test_name.failed -+ fi -+ fi -+ rm -f tmp_expect -+fi -+ -+if [ "$SKIP_CLEANUP" != "true" ] ; then -+ unset IMAGE FSCK_OPT SECOND_FSCK_OPT OUT1 OUT2 EXP1 EXP2 -+ unset SKIP_VERIFY SKIP_CLEANUP SKIP_GUNZIP ONE_PASS_ONLY PREP_CMD -+ unset DESCRIPTION SKIP_UNLINK AFTER_CMD PASS_ZERO -+fi -+ -diff --git a/tests/f_convert_bmap/expect.1 b/tests/f_convert_bmap/expect.1 -new file mode 100644 -index 0000000..7d2ca86 ---- /dev/null -+++ b/tests/f_convert_bmap/expect.1 -@@ -0,0 +1,26 @@ -+debugfs: stat /a -+Inode: 12 Type: regular Mode: 0644 Flags: 0x0 -+Generation: 1573716129 Version: 0x00000000:00000001 -+User: 0 Group: 0 Size: 524288 -+File ACL: 0 Directory ACL: 0 -+Links: 1 Blockcount: 1030 -+Fragment: Address: 0 Number: 0 Size: 0 -+ ctime: 0x5457f87a:62ae2980 -- Mon Nov 3 21:49:46 2014 -+ atime: 0x5457f87a:61ba0598 -- Mon Nov 3 21:49:46 2014 -+ mtime: 0x5457f87a:62ae2980 -- Mon Nov 3 21:49:46 2014 -+crtime: 0x5457f87a:61ba0598 -- Mon Nov 3 21:49:46 2014 -+Size of extra inode fields: 28 -+BLOCKS: -+(0-11):1025-1036, (IND):24, (12-267):1037-1292, (DIND):25, (IND):41, (268-511):1293-1536 -+TOTAL: 515 -+ -+Pass 1: Checking inodes, blocks, and sizes -+Pass 1E: Optimizing extent trees -+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 (8.3% non-contiguous), 570/2048 blocks -+Exit status is 1 -diff --git a/tests/f_convert_bmap/expect.2 b/tests/f_convert_bmap/expect.2 -new file mode 100644 -index 0000000..632d411 ---- /dev/null -+++ b/tests/f_convert_bmap/expect.2 -@@ -0,0 +1,10 @@ -+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), 570/2048 blocks -+Exit status is 0 -+debugfs: ex /a -+Level Entries Logical Physical Length Flags -+ 0/ 0 1/ 1 0 - 511 1025 - 1536 512 -diff --git a/tests/f_convert_bmap/image.gz b/tests/f_convert_bmap/image.gz -new file mode 100644 -index 0000000..7c22532 -Binary files /dev/null and b/tests/f_convert_bmap/image.gz differ -diff --git a/tests/f_convert_bmap/name b/tests/f_convert_bmap/name -new file mode 100644 -index 0000000..67e0d47 ---- /dev/null -+++ b/tests/f_convert_bmap/name -@@ -0,0 +1 @@ -+convert blockmap file to extents file -diff --git a/tests/f_convert_bmap/script b/tests/f_convert_bmap/script -new file mode 100644 -index 0000000..f6b6f62 ---- /dev/null -+++ b/tests/f_convert_bmap/script -@@ -0,0 +1,117 @@ -+if [ "$DESCRIPTION"x != x ]; then -+ test_description="$DESCRIPTION" -+fi -+if [ "$IMAGE"x = x ]; then -+ IMAGE=$test_dir/image.gz -+fi -+ -+if [ "$FSCK_OPT"x = x ]; then -+ FSCK_OPT=-yf -+fi -+ -+if [ "$SECOND_FSCK_OPT"x = x ]; then -+ SECOND_FSCK_OPT=-yf -+fi -+ -+if [ "$OUT1"x = x ]; then -+ OUT1=$test_name.1.log -+fi -+ -+if [ "$OUT2"x = x ]; then -+ OUT2=$test_name.2.log -+fi -+ -+if [ "$EXP1"x = x ]; then -+ if [ -f $test_dir/expect.1.gz ]; then -+ EXP1=$test_name.1.tmp -+ gunzip < $test_dir/expect.1.gz > $EXP1 -+ else -+ EXP1=$test_dir/expect.1 -+ fi -+fi -+ -+if [ "$EXP2"x = x ]; then -+ if [ -f $test_dir/expect.2.gz ]; then -+ EXP2=$test_name.2.tmp -+ gunzip < $test_dir/expect.2.gz > $EXP2 -+ else -+ EXP2=$test_dir/expect.2 -+ fi -+fi -+ -+if [ "$SKIP_GUNZIP" != "true" ] ; then -+ gunzip < $IMAGE > $TMPFILE -+fi -+ -+cp /dev/null $OUT1 -+ -+eval $PREP_CMD -+ -+echo 'stat /a' > $TMPFILE.cmd -+$DEBUGFS -f $TMPFILE.cmd $TMPFILE > $OUT1.new 2>&1 -+rm -rf $TMPFILE.cmd -+$TUNE2FS -O extent $TMPFILE >> $OUT1.new 2>&1 -+$FSCK $FSCK_OPT -E bmap2extent -N test_filesys $TMPFILE >> $OUT1.new 2>&1 -+status=$? -+echo Exit status is $status >> $OUT1.new -+sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT1.new >> $OUT1 -+rm -f $OUT1.new -+ -+$FSCK $SECOND_FSCK_OPT -N test_filesys $TMPFILE > $OUT2.new 2>&1 -+status=$? -+echo Exit status is $status >> $OUT2.new -+echo 'ex /a' > $TMPFILE.cmd -+$DEBUGFS -f $TMPFILE.cmd $TMPFILE >> $OUT2.new 2>&1 -+rm -rf $TMPFILE.cmd -+sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT2.new > $OUT2 -+rm -f $OUT2.new -+ -+eval $AFTER_CMD -+ -+if [ "$SKIP_VERIFY" != "true" ] ; then -+ rm -f $test_name.ok $test_name.failed -+ cmp -s $OUT1 $EXP1 -+ status1=$? -+ if [ "$ONE_PASS_ONLY" != "true" ]; then -+ cmp -s $OUT2 $EXP2 -+ status2=$? -+ else -+ status2=0 -+ fi -+ if [ "$PASS_ZERO" = "true" ]; then -+ cmp -s $test_name.0.log $test_dir/expect.0 -+ status3=$? -+ else -+ status3=0 -+ fi -+ -+ if [ -z "$test_description" ] ; then -+ description="$test_name" -+ else -+ description="$test_name: $test_description" -+ fi -+ -+ if [ "$status1" -eq 0 -a "$status2" -eq 0 -a "$status3" -eq 0 ] ; then -+ echo "$description: ok" -+ touch $test_name.ok -+ else -+ echo "$description: failed" -+ rm -f $test_name.failed -+ if [ "$PASS_ZERO" = "true" ]; then -+ diff $DIFF_OPTS $test_dir/expect.0 \ -+ $test_name.0.log >> $test_name.failed -+ fi -+ diff $DIFF_OPTS $EXP1 $OUT1 >> $test_name.failed -+ if [ "$ONE_PASS_ONLY" != "true" ]; then -+ diff $DIFF_OPTS $EXP2 $OUT2 >> $test_name.failed -+ fi -+ fi -+ rm -f tmp_expect -+fi -+ -+if [ "$SKIP_CLEANUP" != "true" ] ; then -+ unset IMAGE FSCK_OPT SECOND_FSCK_OPT OUT1 OUT2 EXP1 EXP2 -+ unset SKIP_VERIFY SKIP_CLEANUP SKIP_GUNZIP ONE_PASS_ONLY PREP_CMD -+ unset DESCRIPTION SKIP_UNLINK AFTER_CMD PASS_ZERO -+fi -+ -diff --git a/tests/f_convert_bmap_and_extent/expect.1 b/tests/f_convert_bmap_and_extent/expect.1 -new file mode 100644 -index 0000000..7af91aa ---- /dev/null -+++ b/tests/f_convert_bmap_and_extent/expect.1 -@@ -0,0 +1,33 @@ -+debugfs: stat /a -+Inode: 12 Type: regular Mode: 0644 Flags: 0x0 -+Generation: 1573716129 Version: 0x00000000:00000001 -+User: 0 Group: 0 Size: 524288 -+File ACL: 0 Directory ACL: 0 -+Links: 1 Blockcount: 1030 -+Fragment: Address: 0 Number: 0 Size: 0 -+ ctime: 0x5457f87a:62ae2980 -- Mon Nov 3 21:49:46 2014 -+ atime: 0x5457f87a:61ba0598 -- Mon Nov 3 21:49:46 2014 -+ mtime: 0x5457f87a:62ae2980 -- Mon Nov 3 21:49:46 2014 -+crtime: 0x5457f87a:61ba0598 -- Mon Nov 3 21:49:46 2014 -+Size of extra inode fields: 28 -+BLOCKS: -+(0-11):1025-1036, (IND):24, (12-267):1037-1292, (DIND):25, (IND):41, (268-511):1293-1536 -+TOTAL: 515 -+ -+debugfs: ex /zero -+Level Entries Logical Physical Length Flags -+ 0/ 1 1/ 1 0 - 8 28 9 -+ 1/ 1 1/ 4 0 - 0 27 - 27 1 -+ 1/ 1 2/ 4 2 - 2 29 - 29 1 -+ 1/ 1 3/ 4 4 - 4 31 - 31 1 -+ 1/ 1 4/ 4 6 - 6 33 - 33 1 -+Pass 1: Checking inodes, blocks, and sizes -+Pass 1E: Optimizing extent trees -+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: 13/128 files (15.4% non-contiguous), 574/2048 blocks -+Exit status is 1 -diff --git a/tests/f_convert_bmap_and_extent/expect.2 b/tests/f_convert_bmap_and_extent/expect.2 -new file mode 100644 -index 0000000..73765ea ---- /dev/null -+++ b/tests/f_convert_bmap_and_extent/expect.2 -@@ -0,0 +1,16 @@ -+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: 13/128 files (7.7% non-contiguous), 574/2048 blocks -+Exit status is 0 -+debugfs: ex /a -+Level Entries Logical Physical Length Flags -+ 0/ 0 1/ 1 0 - 511 1025 - 1536 512 -+debugfs: ex /zero -+Level Entries Logical Physical Length Flags -+ 0/ 0 1/ 4 0 - 0 27 - 27 1 -+ 0/ 0 2/ 4 2 - 2 29 - 29 1 -+ 0/ 0 3/ 4 4 - 4 31 - 31 1 -+ 0/ 0 4/ 4 6 - 6 33 - 33 1 -diff --git a/tests/f_convert_bmap_and_extent/image.gz b/tests/f_convert_bmap_and_extent/image.gz -new file mode 100644 -index 0000000..916b493 -Binary files /dev/null and b/tests/f_convert_bmap_and_extent/image.gz differ -diff --git a/tests/f_convert_bmap_and_extent/name b/tests/f_convert_bmap_and_extent/name -new file mode 100644 -index 0000000..c9394c6 ---- /dev/null -+++ b/tests/f_convert_bmap_and_extent/name -@@ -0,0 +1 @@ -+convert blockmap and extents files to extents files -diff --git a/tests/f_convert_bmap_and_extent/script b/tests/f_convert_bmap_and_extent/script -new file mode 100644 -index 0000000..203ab25 ---- /dev/null -+++ b/tests/f_convert_bmap_and_extent/script -@@ -0,0 +1,119 @@ -+if [ "$DESCRIPTION"x != x ]; then -+ test_description="$DESCRIPTION" -+fi -+if [ "$IMAGE"x = x ]; then -+ IMAGE=$test_dir/image.gz -+fi -+ -+if [ "$FSCK_OPT"x = x ]; then -+ FSCK_OPT=-yf -+fi -+ -+if [ "$SECOND_FSCK_OPT"x = x ]; then -+ SECOND_FSCK_OPT=-yf -+fi -+ -+if [ "$OUT1"x = x ]; then -+ OUT1=$test_name.1.log -+fi -+ -+if [ "$OUT2"x = x ]; then -+ OUT2=$test_name.2.log -+fi -+ -+if [ "$EXP1"x = x ]; then -+ if [ -f $test_dir/expect.1.gz ]; then -+ EXP1=$test_name.1.tmp -+ gunzip < $test_dir/expect.1.gz > $EXP1 -+ else -+ EXP1=$test_dir/expect.1 -+ fi -+fi -+ -+if [ "$EXP2"x = x ]; then -+ if [ -f $test_dir/expect.2.gz ]; then -+ EXP2=$test_name.2.tmp -+ gunzip < $test_dir/expect.2.gz > $EXP2 -+ else -+ EXP2=$test_dir/expect.2 -+ fi -+fi -+ -+if [ "$SKIP_GUNZIP" != "true" ] ; then -+ gunzip < $IMAGE > $TMPFILE -+fi -+ -+cp /dev/null $OUT1 -+ -+eval $PREP_CMD -+ -+echo 'stat /a' > $TMPFILE.cmd -+echo 'ex /zero' >> $TMPFILE.cmd -+$DEBUGFS -f $TMPFILE.cmd $TMPFILE > $OUT1.new 2>&1 -+rm -rf $TMPFILE.cmd -+$TUNE2FS -O extent $TMPFILE >> $OUT1.new 2>&1 -+$FSCK $FSCK_OPT -E bmap2extent -N test_filesys $TMPFILE >> $OUT1.new 2>&1 -+status=$? -+echo Exit status is $status >> $OUT1.new -+sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT1.new >> $OUT1 -+rm -f $OUT1.new -+ -+$FSCK $SECOND_FSCK_OPT -N test_filesys $TMPFILE > $OUT2.new 2>&1 -+status=$? -+echo Exit status is $status >> $OUT2.new -+echo 'ex /a' > $TMPFILE.cmd -+echo 'ex /zero' >> $TMPFILE.cmd -+$DEBUGFS -f $TMPFILE.cmd $TMPFILE >> $OUT2.new 2>&1 -+rm -rf $TMPFILE.cmd -+sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT2.new > $OUT2 -+rm -f $OUT2.new -+ -+eval $AFTER_CMD -+ -+if [ "$SKIP_VERIFY" != "true" ] ; then -+ rm -f $test_name.ok $test_name.failed -+ cmp -s $OUT1 $EXP1 -+ status1=$? -+ if [ "$ONE_PASS_ONLY" != "true" ]; then -+ cmp -s $OUT2 $EXP2 -+ status2=$? -+ else -+ status2=0 -+ fi -+ if [ "$PASS_ZERO" = "true" ]; then -+ cmp -s $test_name.0.log $test_dir/expect.0 -+ status3=$? -+ else -+ status3=0 -+ fi -+ -+ if [ -z "$test_description" ] ; then -+ description="$test_name" -+ else -+ description="$test_name: $test_description" -+ fi -+ -+ if [ "$status1" -eq 0 -a "$status2" -eq 0 -a "$status3" -eq 0 ] ; then -+ echo "$description: ok" -+ touch $test_name.ok -+ else -+ echo "$description: failed" -+ rm -f $test_name.failed -+ if [ "$PASS_ZERO" = "true" ]; then -+ diff $DIFF_OPTS $test_dir/expect.0 \ -+ $test_name.0.log >> $test_name.failed -+ fi -+ diff $DIFF_OPTS $EXP1 $OUT1 >> $test_name.failed -+ if [ "$ONE_PASS_ONLY" != "true" ]; then -+ diff $DIFF_OPTS $EXP2 $OUT2 >> $test_name.failed -+ fi -+ fi -+ rm -f tmp_expect -+fi -+ -+if [ "$SKIP_CLEANUP" != "true" ] ; then -+ unset IMAGE FSCK_OPT SECOND_FSCK_OPT OUT1 OUT2 EXP1 EXP2 -+ unset SKIP_VERIFY SKIP_CLEANUP SKIP_GUNZIP ONE_PASS_ONLY PREP_CMD -+ unset DESCRIPTION SKIP_UNLINK AFTER_CMD PASS_ZERO -+fi -+ -diff --git a/tests/f_corrupt_dirent_tail/expect.1 b/tests/f_corrupt_dirent_tail/expect.1 -new file mode 100644 -index 0000000..0813755 ---- /dev/null -+++ b/tests/f_corrupt_dirent_tail/expect.1 -@@ -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 -index 0000000..c42466d ---- /dev/null -+++ b/tests/f_corrupt_dirent_tail/expect.2 -@@ -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 -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 -index 0000000..08259a3 ---- /dev/null -+++ b/tests/f_corrupt_dirent_tail/name -@@ -0,0 +1 @@ -+rebuild a directory with corrupt dirent tail -diff --git a/tests/f_create_symlinks/expect b/tests/f_create_symlinks/expect -new file mode 100644 -index 0000000..47fa468 ---- /dev/null -+++ b/tests/f_create_symlinks/expect -@@ -0,0 +1,69 @@ -+mke2fs -q -F -o Linux -b 1024 -g 256 -O inline_data,extents -I 256 test.img 1024 -+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), 441/1024 blocks -+Exit status is 0 -+debugfs -R "symlink /l_30 /xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" test.img -+debugfs -R "symlink /l_70 /xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" test.img -+debugfs -R "symlink /l_500 /xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" test.img -+debugfs -R "symlink /l_1023 /xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" test.img -+debugfs -R "symlink /l_1024 /xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" test.img -+ext2fs_symlink: Invalid argument passed to ext2 library while creating symlink "l_1024" -+symlink: Invalid argument passed to ext2 library -+debugfs -R "symlink /l_1500 /xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" test.img -+ext2fs_symlink: Invalid argument passed to ext2 library while creating symlink "l_1500" -+symlink: Invalid argument passed to ext2 library -+debugfs -R "stat /l_30" test.img -+Inode: 12 Type: symlink Mode: 0777 Flags: 0x0 -+Generation: 0 Version: 0x00000000:00000000 -+User: 0 Group: 0 Size: 31 -+File ACL: 0 Directory ACL: 0 -+Links: 1 Blockcount: 0 -+Fragment: Address: 0 Number: 0 Size: 0 -+Size of extra inode fields: 28 -+Fast link dest: "/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" -+debugfs -R "stat /l_70" test.img -+Inode: 13 Type: symlink Mode: 0777 Flags: 0x10000000 -+Generation: 0 Version: 0x00000000:00000000 -+User: 0 Group: 0 Size: 71 -+File ACL: 0 Directory ACL: 0 -+Links: 1 Blockcount: 0 -+Fragment: Address: 0 Number: 0 Size: 0 -+Size of extra inode fields: 28 -+Extended attributes: -+ system.data (11) -+Fast link dest: "/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" -+debugfs -R "stat /l_500" test.img -+Inode: 14 Type: symlink Mode: 0777 Flags: 0x80000 -+Generation: 0 Version: 0x00000000:00000000 -+User: 0 Group: 0 Size: 501 -+File ACL: 0 Directory ACL: 0 -+Links: 1 Blockcount: 2 -+Fragment: Address: 0 Number: 0 Size: 0 -+Size of extra inode fields: 28 -+EXTENTS: -+(0):153 -+debugfs -R "stat /l_1023" test.img -+Inode: 15 Type: symlink Mode: 0777 Flags: 0x80000 -+Generation: 0 Version: 0x00000000:00000000 -+User: 0 Group: 0 Size: 1024 -+File ACL: 0 Directory ACL: 0 -+Links: 1 Blockcount: 2 -+Fragment: Address: 0 Number: 0 Size: 0 -+Size of extra inode fields: 28 -+EXTENTS: -+(0):154 -+debugfs -R "stat /l_1024" test.img -+/l_1024: File not found by ext2_lookup -+debugfs -R "stat /l_1500" test.img -+/l_1500: File not found by ext2_lookup -+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 (0.0% non-contiguous), 443/1024 blocks -+Exit status is 0 -diff --git a/tests/f_create_symlinks/name b/tests/f_create_symlinks/name -new file mode 100644 -index 0000000..0930e79 ---- /dev/null -+++ b/tests/f_create_symlinks/name -@@ -0,0 +1 @@ -+create fast, inlinedata, and regular symlinks -diff --git a/tests/f_create_symlinks/script b/tests/f_create_symlinks/script -new file mode 100644 -index 0000000..529848f ---- /dev/null -+++ b/tests/f_create_symlinks/script -@@ -0,0 +1,64 @@ -+if test -x $DEBUGFS_EXE; then -+ -+FSCK_OPT=-yf -+OUT=$test_name.log -+if [ -f $test_dir/expect.gz ]; then -+ EXP=$test_name.tmp -+ gunzip < $test_dir/expect.gz > $EXP1 -+else -+ EXP=$test_dir/expect -+fi -+ -+cp /dev/null $OUT -+ -+dd if=/dev/zero of=$TMPFILE bs=1k count=512 > /dev/null 2>&1 -+ -+echo mke2fs -q -F -o Linux -b 1024 -g 256 -O inline_data,extents -I 256 test.img 1024 >> $OUT -+$MKE2FS -q -F -o Linux -b 1024 -g 256 -O inline_data,extents -I 256 $TMPFILE 1024 2>&1 | -+ sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" >> $OUT -+ -+$FSCK $FSCK_OPT -N test_filesys $TMPFILE > $OUT.new 2>&1 -+status=$? -+echo Exit status is $status >> $OUT.new -+sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT -+rm -f $OUT.new -+ -+for i in 30 70 500 1023 1024 1500; do -+ echo "debugfs -R \"symlink /l_$i /$(perl -e "print 'x' x $i;")\" test.img" >> $OUT -+ $DEBUGFS -w -R "symlink /l_$i /$(perl -e "print 'x' x $i;")" $TMPFILE \ -+ 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT -+done -+ -+for i in 30 70 500 1023 1024 1500; do -+ echo "debugfs -R \"stat /l_$i\" test.img" >> $OUT -+ $DEBUGFS -R "stat /l_$i" $TMPFILE 2>&1 | \ -+ sed -f $cmd_dir/filter.sed | grep -v "time: " >> $OUT -+done -+ -+/bin/cp $TMPFILE /tmp/foo.img -+ -+$FSCK $FSCK_OPT -N test_filesys $TMPFILE > $OUT.new 2>&1 -+status=$? -+echo Exit status is $status >> $OUT.new -+sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT -+rm -f $OUT.new -+ -+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 IMAGE FSCK_OPT OUT EXP -+ -+else #if test -a -x $DEBUGFS_EXE; then -+ echo "$test_name: $test_description: skipped" -+fi -diff --git a/tests/f_deleted_inode_bad_csum/expect.1 b/tests/f_deleted_inode_bad_csum/expect.1 -new file mode 100644 -index 0000000..8420361 ---- /dev/null -+++ b/tests/f_deleted_inode_bad_csum/expect.1 -@@ -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 -index 0000000..eb48b40 ---- /dev/null -+++ b/tests/f_deleted_inode_bad_csum/expect.2 -@@ -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 -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 -index 0000000..516701a ---- /dev/null -+++ b/tests/f_deleted_inode_bad_csum/name -@@ -0,0 +1 @@ -+deleted inode with a bad csum that wasn't getting fixed (metadata_csum) -diff --git a/tests/f_detect_junk/expect b/tests/f_detect_junk/expect -new file mode 100644 -index 0000000..f3300de ---- /dev/null -+++ b/tests/f_detect_junk/expect -@@ -0,0 +1,25 @@ -+*** e2fsck -+ext2fs_open2: Bad magic number in super-block -+../e2fsck/e2fsck: Superblock invalid, trying backup blocks... -+../e2fsck/e2fsck: Bad magic number in super-block while trying to open test.img -+ -+The superblock could not be read or does not describe a valid ext2/ext3/ext4 -+filesystem. If the device is valid and it really contains an ext2/ext3/ext4 -+filesystem (and not swap or ufs or something else), then the superblock -+is corrupt, and you might try running e2fsck with an alternate superblock: -+ e2fsck -b 8193 -+ or -+ e2fsck -b 32768 -+ -+test.img contains `PNG image data, 148 x 31, 8-bit/color RGBA, non-interlaced' data -+*** debugfs -+test.img: Bad magic number in super-block while opening filesystem -+test.img contains `PNG image data, 148 x 31, 8-bit/color RGBA, non-interlaced' data -+*** tune2fs -+../misc/tune2fs: Bad magic number in super-block while trying to open test.img -+test.img contains `PNG image data, 148 x 31, 8-bit/color RGBA, non-interlaced' data -+*** mke2fs -+Creating filesystem with 16384 1k blocks and 4096 inodes -+Superblock backups stored on blocks: -+ 8193 -+ -diff --git a/tests/f_detect_junk/expect.nodebugfs b/tests/f_detect_junk/expect.nodebugfs -new file mode 100644 -index 0000000..0d4ba54 ---- /dev/null -+++ b/tests/f_detect_junk/expect.nodebugfs -@@ -0,0 +1,23 @@ -+*** e2fsck -+ext2fs_open2: Bad magic number in super-block -+../e2fsck/e2fsck: Superblock invalid, trying backup blocks... -+../e2fsck/e2fsck: Bad magic number in super-block while trying to open test.img -+ -+The superblock could not be read or does not describe a valid ext2/ext3/ext4 -+filesystem. If the device is valid and it really contains an ext2/ext3/ext4 -+filesystem (and not swap or ufs or something else), then the superblock -+is corrupt, and you might try running e2fsck with an alternate superblock: -+ e2fsck -b 8193 -+ or -+ e2fsck -b 32768 -+ -+test.img contains `PNG image data, 148 x 31, 8-bit/color RGBA, non-interlaced' data -+*** debugfs -+*** tune2fs -+../misc/tune2fs: Bad magic number in super-block while trying to open test.img -+test.img contains `PNG image data, 148 x 31, 8-bit/color RGBA, non-interlaced' data -+*** mke2fs -+Creating filesystem with 16384 1k blocks and 4096 inodes -+Superblock backups stored on blocks: -+ 8193 -+ -diff --git a/tests/f_detect_junk/image.bz2 b/tests/f_detect_junk/image.bz2 -new file mode 100644 -index 0000000..3d52600 -Binary files /dev/null and b/tests/f_detect_junk/image.bz2 differ -diff --git a/tests/f_detect_junk/name b/tests/f_detect_junk/name -new file mode 100644 -index 0000000..81cf655 ---- /dev/null -+++ b/tests/f_detect_junk/name -@@ -0,0 +1 @@ -+detect non-fs file data -diff --git a/tests/f_detect_junk/script b/tests/f_detect_junk/script -new file mode 100644 -index 0000000..2721c79 ---- /dev/null -+++ b/tests/f_detect_junk/script -@@ -0,0 +1,44 @@ -+#!/bin/bash -+ -+if [ "$(grep -c 'define HAVE_MAGIC_H' ../lib/config.h)" -gt 0 ]; then -+ -+FSCK_OPT=-fn -+IMAGE=$test_dir/image.bz2 -+ -+bzip2 -d < $IMAGE > $TMPFILE -+dd if=/dev/zero of=$TMPFILE conv=notrunc oflag=append bs=1024k count=16 > /dev/null 2>&1 -+ -+# Run fsck to fix things? -+if [ -x $DEBUGFS_EXE ]; then -+ EXP=$test_dir/expect -+else -+ EXP=$test_dir/expect.nodebugfs -+fi -+OUT=$test_name.log -+rm -rf $test_name.failed $test_name.ok -+ -+echo "*** e2fsck" > $OUT -+$FSCK $FSCK_OPT $TMPFILE >> $OUT 2>&1 -+echo "*** debugfs" >> $OUT -+test -x $DEBUGFS_EXE && $DEBUGFS_EXE -R 'quit' $TMPFILE >> $OUT 2>&1 -+echo "*** tune2fs" >> $OUT -+$TUNE2FS -i 0 $TMPFILE >> $OUT 2>&1 -+echo "*** mke2fs" >> $OUT -+$MKE2FS -n $TMPFILE >> $OUT 2>&1 -+ -+sed -f $cmd_dir/filter.sed -e "s|$TMPFILE|test.img|g" < $OUT > $OUT.new -+mv $OUT.new $OUT -+ -+# Figure out what happened -+if cmp -s $EXP $OUT; then -+ echo "$test_name: $test_description: ok" -+ touch $test_name.ok -+else -+ echo "$test_name: $test_description: failed" -+ diff -u $EXP $OUT >> $test_name.failed -+fi -+unset EXP OUT FSCK_OPT IMAGE -+ -+else #if HAVE_MAGIC_H -+ echo "$test_name: $test_description: skipped" -+fi -diff --git a/tests/f_detect_xfs/expect b/tests/f_detect_xfs/expect -new file mode 100644 -index 0000000..4ab6e5b ---- /dev/null -+++ b/tests/f_detect_xfs/expect -@@ -0,0 +1,25 @@ -+*** e2fsck -+ext2fs_open2: Bad magic number in super-block -+../e2fsck/e2fsck: Superblock invalid, trying backup blocks... -+../e2fsck/e2fsck: Bad magic number in super-block while trying to open test.img -+ -+The superblock could not be read or does not describe a valid ext2/ext3/ext4 -+filesystem. If the device is valid and it really contains an ext2/ext3/ext4 -+filesystem (and not swap or ufs or something else), then the superblock -+is corrupt, and you might try running e2fsck with an alternate superblock: -+ e2fsck -b 8193 -+ or -+ e2fsck -b 32768 -+ -+test.img contains a xfs file system labelled 'test_filsys' -+*** debugfs -+test.img: Bad magic number in super-block while opening filesystem -+test.img contains a xfs file system labelled 'test_filsys' -+*** tune2fs -+../misc/tune2fs: Bad magic number in super-block while trying to open test.img -+test.img contains a xfs file system labelled 'test_filsys' -+*** mke2fs -+Creating filesystem with 16384 1k blocks and 4096 inodes -+Superblock backups stored on blocks: -+ 8193 -+ -diff --git a/tests/f_detect_xfs/expect.nodebugfs b/tests/f_detect_xfs/expect.nodebugfs -new file mode 100644 -index 0000000..d3b7935 ---- /dev/null -+++ b/tests/f_detect_xfs/expect.nodebugfs -@@ -0,0 +1,23 @@ -+*** e2fsck -+ext2fs_open2: Bad magic number in super-block -+../e2fsck/e2fsck: Superblock invalid, trying backup blocks... -+../e2fsck/e2fsck: Bad magic number in super-block while trying to open test.img -+ -+The superblock could not be read or does not describe a valid ext2/ext3/ext4 -+filesystem. If the device is valid and it really contains an ext2/ext3/ext4 -+filesystem (and not swap or ufs or something else), then the superblock -+is corrupt, and you might try running e2fsck with an alternate superblock: -+ e2fsck -b 8193 -+ or -+ e2fsck -b 32768 -+ -+test.img contains a xfs file system labelled 'test_filsys' -+*** debugfs -+*** tune2fs -+../misc/tune2fs: Bad magic number in super-block while trying to open test.img -+test.img contains a xfs file system labelled 'test_filsys' -+*** mke2fs -+Creating filesystem with 16384 1k blocks and 4096 inodes -+Superblock backups stored on blocks: -+ 8193 -+ -diff --git a/tests/f_detect_xfs/image.bz2 b/tests/f_detect_xfs/image.bz2 -new file mode 100644 -index 0000000..9dc5e44 -Binary files /dev/null and b/tests/f_detect_xfs/image.bz2 differ -diff --git a/tests/f_detect_xfs/name b/tests/f_detect_xfs/name -new file mode 100644 -index 0000000..d5b9b82 ---- /dev/null -+++ b/tests/f_detect_xfs/name -@@ -0,0 +1 @@ -+detect xfs filesystem -diff --git a/tests/f_detect_xfs/script b/tests/f_detect_xfs/script -new file mode 100644 -index 0000000..b32ba85 ---- /dev/null -+++ b/tests/f_detect_xfs/script -@@ -0,0 +1,37 @@ -+#!/bin/bash -+ -+FSCK_OPT=-fn -+IMAGE=$test_dir/image.bz2 -+ -+bzip2 -d < $IMAGE > $TMPFILE -+ -+# Run fsck to fix things? -+if [ -x $DEBUGFS_EXE ]; then -+ EXP=$test_dir/expect -+else -+ EXP=$test_dir/expect.nodebugfs -+fi -+OUT=$test_name.log -+rm -rf $test_name.failed $test_name.ok -+ -+echo "*** e2fsck" > $OUT -+$FSCK $FSCK_OPT $TMPFILE >> $OUT 2>&1 -+echo "*** debugfs" >> $OUT -+test -x $DEBUGFS_EXE && $DEBUGFS_EXE -R 'quit' $TMPFILE >> $OUT 2>&1 -+echo "*** tune2fs" >> $OUT -+$TUNE2FS -i 0 $TMPFILE >> $OUT 2>&1 -+echo "*** mke2fs" >> $OUT -+$MKE2FS -n $TMPFILE >> $OUT 2>&1 -+ -+sed -f $cmd_dir/filter.sed -e "s|$TMPFILE|test.img|g" < $OUT > $OUT.new -+mv $OUT.new $OUT -+ -+# Figure out what happened -+if cmp -s $EXP $OUT; then -+ echo "$test_name: $test_description: ok" -+ touch $test_name.ok -+else -+ echo "$test_name: $test_description: failed" -+ diff -u $EXP $OUT >> $test_name.failed -+fi -+unset EXP OUT FSCK_OPT IMAGE -diff --git a/tests/f_dir_bad_csum/expect.1 b/tests/f_dir_bad_csum/expect.1 -new file mode 100644 -index 0000000..94e72da ---- /dev/null -+++ b/tests/f_dir_bad_csum/expect.1 -@@ -0,0 +1,56 @@ -+Pass 1: Checking inodes, blocks, and sizes -+Pass 2: Checking directory structure -+Directory inode 12, block #0: directory passes checks but fails checksum. -+Fix? yes -+ -+Directory inode 13, block #0, offset 0: directory has no checksum. -+Fix? yes -+ -+Directory inode 14, block #0, offset 0: directory has no 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 (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 -index 0000000..f5a3e5f ---- /dev/null -+++ b/tests/f_dir_bad_csum/expect.2 -@@ -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 -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 -index 0000000..140ae45 ---- /dev/null -+++ b/tests/f_dir_bad_csum/name -@@ -0,0 +1 @@ -+dir block w/ missing/bad csum, no tail, or dir block corruption (metadata_csum) -diff --git a/tests/f_dup/expect.1 b/tests/f_dup/expect.1 -index e7128f3..075e62c 100644 ---- a/tests/f_dup/expect.1 -+++ b/tests/f_dup/expect.1 -@@ -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.) -diff --git a/tests/f_dup2/expect.1 b/tests/f_dup2/expect.1 -index 0476005..69aa21b 100644 ---- a/tests/f_dup2/expect.1 -+++ b/tests/f_dup2/expect.1 -@@ -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.) -diff --git a/tests/f_dup_ba/expect.1 b/tests/f_dup_ba/expect.1 -index f0ad457..f4581c4 100644 ---- a/tests/f_dup_ba/expect.1 -+++ b/tests/f_dup_ba/expect.1 -@@ -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.) -diff --git a/tests/f_dup_resize/expect.1 b/tests/f_dup_resize/expect.1 -index dd8fe05..aaf7769 100644 ---- a/tests/f_dup_resize/expect.1 -+++ b/tests/f_dup_resize/expect.1 -@@ -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.) -diff --git a/tests/f_dupfsblks/expect.1 b/tests/f_dupfsblks/expect.1 -index 3f70109..6751986 100644 ---- a/tests/f_dupfsblks/expect.1 -+++ b/tests/f_dupfsblks/expect.1 -@@ -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 -diff --git a/tests/f_dupsuper/expect.1 b/tests/f_dupsuper/expect.1 -index 830370a..2107e2d 100644 ---- a/tests/f_dupsuper/expect.1 -+++ b/tests/f_dupsuper/expect.1 -@@ -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 -index 0000000..4fc365f ---- /dev/null -+++ b/tests/f_ea_bad_csum/expect.1 -@@ -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 -index 0000000..d83fdfb ---- /dev/null -+++ b/tests/f_ea_bad_csum/expect.2 -@@ -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 -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 -index 0000000..958b244 ---- /dev/null -+++ b/tests/f_ea_bad_csum/name -@@ -0,0 +1 @@ -+EA block with bad checksum (metadata_csum) -diff --git a/tests/f_ea_value_crash/expect.1 b/tests/f_ea_value_crash/expect.1 -new file mode 100644 -index 0000000..8315358 ---- /dev/null -+++ b/tests/f_ea_value_crash/expect.1 -@@ -0,0 +1,15 @@ -+Pass 1: Checking inodes, blocks, and sizes -+Inode 12 has INLINE_DATA_FL flag but extended attribute not found. Truncate? yes -+ -+Inode 12 extended attribute is corrupt (allocation collision). Clear? yes -+ -+Inode 13 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: 13/128 files (0.0% non-contiguous), 17/512 blocks -+Exit status is 1 -diff --git a/tests/f_ea_value_crash/expect.2 b/tests/f_ea_value_crash/expect.2 -new file mode 100644 -index 0000000..06886a4 ---- /dev/null -+++ b/tests/f_ea_value_crash/expect.2 -@@ -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: 13/128 files (0.0% non-contiguous), 17/512 blocks -+Exit status is 0 -diff --git a/tests/f_ea_value_crash/image.gz b/tests/f_ea_value_crash/image.gz -new file mode 100644 -index 0000000..c45fb0e -Binary files /dev/null and b/tests/f_ea_value_crash/image.gz differ -diff --git a/tests/f_ea_value_crash/name b/tests/f_ea_value_crash/name -new file mode 100644 -index 0000000..194bbed ---- /dev/null -+++ b/tests/f_ea_value_crash/name -@@ -0,0 +1 @@ -+extended attribute value conflicts with key -diff --git a/tests/f_encrypted_lpf/expect.1 b/tests/f_encrypted_lpf/expect.1 -new file mode 100644 -index 0000000..7e215b7 ---- /dev/null -+++ b/tests/f_encrypted_lpf/expect.1 -@@ -0,0 +1,27 @@ -+Pass 1: Checking inodes, blocks, and sizes -+Pass 2: Checking directory structure -+Pass 3: Checking directory connectivity -+Unconnected directory inode 12 (/???) -+Connect to /lost+found? yes -+ -+/lost+found is encrypted -+Clear? yes -+ -+/lost+found not found. Create? yes -+ -+Restarting e2fsck from the beginning... -+Pass 1: Checking inodes, blocks, and sizes -+Pass 2: Checking directory structure -+Pass 3: Checking directory connectivity -+Unconnected directory inode 11 (/???) -+Connect to /lost+found? yes -+ -+Pass 3A: Optimizing directories -+Pass 4: Checking reference counts -+Inode 12 ref count is 3, should be 2. Fix? yes -+ -+Pass 5: Checking group summary information -+ -+test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** -+test_filesys: 13/64 files (0.0% non-contiguous), 13/100 blocks -+Exit status is 1 -diff --git a/tests/f_encrypted_lpf/expect.2 b/tests/f_encrypted_lpf/expect.2 -new file mode 100644 -index 0000000..6a59947 ---- /dev/null -+++ b/tests/f_encrypted_lpf/expect.2 -@@ -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: 13/64 files (0.0% non-contiguous), 13/100 blocks -+Exit status is 0 -diff --git a/tests/f_encrypted_lpf/image.gz b/tests/f_encrypted_lpf/image.gz -new file mode 100644 -index 0000000..7c89e07 -Binary files /dev/null and b/tests/f_encrypted_lpf/image.gz differ -diff --git a/tests/f_encrypted_lpf/name b/tests/f_encrypted_lpf/name -new file mode 100644 -index 0000000..b74259c ---- /dev/null -+++ b/tests/f_encrypted_lpf/name -@@ -0,0 +1 @@ -+encrypted lost+found directory -diff --git a/tests/f_expandroot_create_lnf/expect.1 b/tests/f_expandroot_create_lnf/expect.1 -new file mode 100644 -index 0000000..9593dbf ---- /dev/null -+++ b/tests/f_expandroot_create_lnf/expect.1 -@@ -0,0 +1,12 @@ -+Pass 1: Checking inodes, blocks, and sizes -+Pass 2: Checking directory structure -+Pass 3: Checking directory connectivity -+/lost+found not found. Create? yes -+ -+Pass 3A: Optimizing directories -+Pass 4: Checking reference counts -+Pass 5: Checking group summary information -+ -+test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** -+test_filesys: 16/64 files (0.0% non-contiguous), 33/1024 blocks -+Exit status is 1 -diff --git a/tests/f_expandroot_create_lnf/expect.2 b/tests/f_expandroot_create_lnf/expect.2 -new file mode 100644 -index 0000000..5eec1f0 ---- /dev/null -+++ b/tests/f_expandroot_create_lnf/expect.2 -@@ -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: 16/64 files (6.3% non-contiguous), 33/1024 blocks -+Exit status is 0 -diff --git a/tests/f_expandroot_create_lnf/image.gz b/tests/f_expandroot_create_lnf/image.gz -new file mode 100644 -index 0000000..ccdbfa7 -Binary files /dev/null and b/tests/f_expandroot_create_lnf/image.gz differ -diff --git a/tests/f_expandroot_create_lnf/name b/tests/f_expandroot_create_lnf/name -new file mode 100644 -index 0000000..f22542b ---- /dev/null -+++ b/tests/f_expandroot_create_lnf/name -@@ -0,0 +1 @@ -+no space in root to create lost+found entry -diff --git a/tests/f_extent_bad_node/expect.1 b/tests/f_extent_bad_node/expect.1 -index 0c0bc28..81c25a3 100644 ---- a/tests/f_extent_bad_node/expect.1 -+++ b/tests/f_extent_bad_node/expect.1 -@@ -2,8 +2,11 @@ Pass 1: Checking inodes, blocks, and sizes - Inode 12 has an invalid extent node (blk 22, lblk 0) - Clear? yes - -+Inode 12 extent tree (at level 1) could be shorter. Fix? yes -+ - Inode 12, i_blocks is 16, should be 8. Fix? yes - -+Pass 1E: Optimizing extent trees - Pass 2: Checking directory structure - Pass 3: Checking directory connectivity - Pass 4: Checking reference counts -@@ -11,13 +14,13 @@ Pass 5: Checking group summary information - Block bitmap differences: -(21--23) -25 - Fix? yes - --Free blocks count wrong for group #0 (71, counted=75). -+Free blocks count wrong for group #0 (73, counted=77). - Fix? yes - --Free blocks count wrong (71, counted=75). -+Free blocks count wrong (73, counted=77). - Fix? yes - - - test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** --test_filesys: 12/16 files (0.0% non-contiguous), 25/100 blocks -+test_filesys: 12/16 files (0.0% non-contiguous), 23/100 blocks - Exit status is 1 -diff --git a/tests/f_extent_bad_node/expect.2 b/tests/f_extent_bad_node/expect.2 -index 568c792..b78b193 100644 ---- a/tests/f_extent_bad_node/expect.2 -+++ b/tests/f_extent_bad_node/expect.2 -@@ -3,5 +3,5 @@ Pass 2: Checking directory structure - Pass 3: Checking directory connectivity - Pass 4: Checking reference counts - Pass 5: Checking group summary information --test_filesys: 12/16 files (0.0% non-contiguous), 25/100 blocks -+test_filesys: 12/16 files (0.0% non-contiguous), 23/100 blocks - Exit status is 0 -diff --git a/tests/f_extent_bad_node/name b/tests/f_extent_bad_node/name -index 9c9d79f..0b4ab8c 100644 ---- a/tests/f_extent_bad_node/name -+++ b/tests/f_extent_bad_node/name -@@ -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 -index 0000000..7b412b8 ---- /dev/null -+++ b/tests/f_extent_int_bad_csum/expect.1 -@@ -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, 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 -index 0000000..6f73d98 ---- /dev/null -+++ b/tests/f_extent_int_bad_csum/expect.2 -@@ -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 -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 -index 0000000..87317e3 ---- /dev/null -+++ b/tests/f_extent_int_bad_csum/name -@@ -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 -index 0000000..3d2fb58 ---- /dev/null -+++ b/tests/f_extent_int_bad_extent/expect.1 -@@ -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 -index 0000000..4e72e41 ---- /dev/null -+++ b/tests/f_extent_int_bad_extent/expect.2 -@@ -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 -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 -index 0000000..e22f6b4 ---- /dev/null -+++ b/tests/f_extent_int_bad_extent/name -@@ -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 -index 0000000..52091ac ---- /dev/null -+++ b/tests/f_extent_int_bad_magic/expect.1 -@@ -0,0 +1,26 @@ -+Pass 1: Checking inodes, blocks, and sizes -+Inode 12 has an invalid extent node (blk 1295, lblk 0) -+Clear? yes -+ -+Inode 12 extent tree (at level 1) could be shorter. Fix? yes -+ -+Inode 12, i_blocks is 712, should be 0. Fix? yes -+ -+Pass 1E: Optimizing extent trees -+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 -index 0000000..283cc1f ---- /dev/null -+++ b/tests/f_extent_int_bad_magic/expect.2 -@@ -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 -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 -index 0000000..a451e9a ---- /dev/null -+++ b/tests/f_extent_int_bad_magic/name -@@ -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 -index 0000000..86e501a ---- /dev/null -+++ b/tests/f_extent_leaf_bad_csum/expect.1 -@@ -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, 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 -index 0000000..a564763 ---- /dev/null -+++ b/tests/f_extent_leaf_bad_csum/expect.2 -@@ -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 -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 -index 0000000..62a2285 ---- /dev/null -+++ b/tests/f_extent_leaf_bad_csum/name -@@ -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 -index 0000000..f96a8a9 ---- /dev/null -+++ b/tests/f_extent_leaf_bad_extent/expect.1 -@@ -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 -index 0000000..de1727c ---- /dev/null -+++ b/tests/f_extent_leaf_bad_extent/expect.2 -@@ -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 -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 -index 0000000..1bd8bd1 ---- /dev/null -+++ b/tests/f_extent_leaf_bad_extent/name -@@ -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 -index 0000000..4c1777c ---- /dev/null -+++ b/tests/f_extent_leaf_bad_magic/expect.1 -@@ -0,0 +1,26 @@ -+Pass 1: Checking inodes, blocks, and sizes -+Inode 12 has an invalid extent node (blk 1604, lblk 0) -+Clear? yes -+ -+Inode 12 extent tree (at level 1) could be shorter. Fix? yes -+ -+Inode 12, i_blocks is 18, should be 0. Fix? yes -+ -+Pass 1E: Optimizing extent trees -+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 -index 0000000..283cc1f ---- /dev/null -+++ b/tests/f_extent_leaf_bad_magic/expect.2 -@@ -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 -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 -index 0000000..e9f756e ---- /dev/null -+++ b/tests/f_extent_leaf_bad_magic/name -@@ -0,0 +1 @@ -+bad magic number in leaf extent (metadata_csum) -diff --git a/tests/f_extent_oobounds/expect.1 b/tests/f_extent_oobounds/expect.1 -index 3164ea0..59e1952 100644 ---- a/tests/f_extent_oobounds/expect.1 -+++ b/tests/f_extent_oobounds/expect.1 -@@ -3,8 +3,11 @@ Inode 12, end of extent exceeds allowed value - (logical block 15, physical block 200, len 30) - Clear? yes - -+Inode 12 extent tree (at (level 1) could be narrower. Fix? yes -+ - Inode 12, i_blocks is 154, should be 94. Fix? yes - -+Pass 1E: Optimizing extent trees - Pass 2: Checking directory structure - Pass 3: Checking directory connectivity - Pass 4: Checking reference counts -@@ -12,13 +15,13 @@ Pass 5: Checking group summary information - Block bitmap differences: -(200--229) - Fix? yes - --Free blocks count wrong for group #0 (156, counted=186). -+Free blocks count wrong for group #0 (158, counted=188). - Fix? yes - --Free blocks count wrong (156, counted=186). -+Free blocks count wrong (158, counted=188). - Fix? yes - - - test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** --test_filesys: 12/32 files (8.3% non-contiguous), 70/256 blocks -+test_filesys: 12/32 files (8.3% non-contiguous), 68/256 blocks - Exit status is 1 -diff --git a/tests/f_extent_oobounds/expect.2 b/tests/f_extent_oobounds/expect.2 -index 22c4f2c..0729283 100644 ---- a/tests/f_extent_oobounds/expect.2 -+++ b/tests/f_extent_oobounds/expect.2 -@@ -3,5 +3,5 @@ Pass 2: Checking directory structure - Pass 3: Checking directory connectivity - Pass 4: Checking reference counts - Pass 5: Checking group summary information --test_filesys: 12/32 files (8.3% non-contiguous), 70/256 blocks -+test_filesys: 12/32 files (8.3% non-contiguous), 68/256 blocks - Exit status is 0 -diff --git a/tests/f_extent_oobounds/script b/tests/f_extent_oobounds/script -index b00b031..54674ca 100644 ---- a/tests/f_extent_oobounds/script -+++ b/tests/f_extent_oobounds/script -@@ -7,6 +7,9 @@ dd if=/dev/zero of=$TMPFILE bs=1k count=256 > /dev/null 2>&1 - $MKE2FS -Ft ext4 $TMPFILE > /dev/null 2>&1 - $DEBUGFS -w $TMPFILE << EOF > /dev/null 2>&1 - write /dev/null testfile -+setb 100 15 -+setb 130 30 -+setb 200 30 - extent_open testfile - insert_node 0 15 100 - insert_node --after 15 15 115 -@@ -22,9 +25,6 @@ extent_open testfile - extent_close - set_inode_field testfile i_size 61400 - set_inode_field testfile i_blocks 154 --setb 100 15 --setb 130 30 --setb 200 30 - set_bg 0 free_blocks_count 156 - set_bg 0 bg_checksum calc - set_super_value free_blocks_count 156 -diff --git a/tests/f_extent_too_deep/expect.1 b/tests/f_extent_too_deep/expect.1 -new file mode 100644 -index 0000000..a595482 ---- /dev/null -+++ b/tests/f_extent_too_deep/expect.1 -@@ -0,0 +1,23 @@ -+debugfs: ex /a -+Level Entries Logical Physical Length Flags -+ 0/ 7 1/ 1 0 - 0 12 1 -+ 1/ 7 1/ 1 0 - 0 13 1 -+ 2/ 7 1/ 1 0 - 0 14 1 -+ 3/ 7 1/ 1 0 - 0 15 1 -+ 4/ 7 1/ 1 0 - 0 16 1 -+ 5/ 7 1/ 1 0 - 0 17 1 -+ 6/ 7 1/ 1 0 - 0 9 1 -+ 7/ 7 1/ 1 0 - 0 10 - 10 1 -+Pass 1: Checking inodes, blocks, and sizes -+Inode 12 extent tree could be more shallow (7; could be <= 4) -+Fix? yes -+ -+Pass 1E: Optimizing extent trees -+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_extent_too_deep/expect.2 b/tests/f_extent_too_deep/expect.2 -new file mode 100644 -index 0000000..a1d28b1 ---- /dev/null -+++ b/tests/f_extent_too_deep/expect.2 -@@ -0,0 +1,10 @@ -+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 -+debugfs: ex /a -+Level Entries Logical Physical Length Flags -+ 0/ 0 1/ 1 0 - 0 10 - 10 1 -diff --git a/tests/f_extent_too_deep/image.gz b/tests/f_extent_too_deep/image.gz -new file mode 100644 -index 0000000..0f5adff -Binary files /dev/null and b/tests/f_extent_too_deep/image.gz differ -diff --git a/tests/f_extent_too_deep/name b/tests/f_extent_too_deep/name -new file mode 100644 -index 0000000..7e8654a ---- /dev/null -+++ b/tests/f_extent_too_deep/name -@@ -0,0 +1 @@ -+extent tree is deeper than it needs to be -diff --git a/tests/f_extent_too_deep/script b/tests/f_extent_too_deep/script -new file mode 100644 -index 0000000..ee18438 ---- /dev/null -+++ b/tests/f_extent_too_deep/script -@@ -0,0 +1,118 @@ -+if [ "$DESCRIPTION"x != x ]; then -+ test_description="$DESCRIPTION" -+fi -+if [ "$IMAGE"x = x ]; then -+ IMAGE=$test_dir/image.gz -+fi -+ -+if [ "$FSCK_OPT"x = x ]; then -+ FSCK_OPT=-yf -+fi -+ -+if [ "$SECOND_FSCK_OPT"x = x ]; then -+ SECOND_FSCK_OPT=-yf -+fi -+ -+if [ "$OUT1"x = x ]; then -+ OUT1=$test_name.1.log -+fi -+ -+if [ "$OUT2"x = x ]; then -+ OUT2=$test_name.2.log -+fi -+ -+if [ "$EXP1"x = x ]; then -+ if [ -f $test_dir/expect.1.gz ]; then -+ EXP1=$test_name.1.tmp -+ gunzip < $test_dir/expect.1.gz > $EXP1 -+ else -+ EXP1=$test_dir/expect.1 -+ fi -+fi -+ -+if [ "$EXP2"x = x ]; then -+ if [ -f $test_dir/expect.2.gz ]; then -+ EXP2=$test_name.2.tmp -+ gunzip < $test_dir/expect.2.gz > $EXP2 -+ else -+ EXP2=$test_dir/expect.2 -+ fi -+fi -+ -+if [ "$SKIP_GUNZIP" != "true" ] ; then -+ gunzip < $IMAGE > $TMPFILE -+fi -+ -+cp /dev/null $OUT1 -+ -+eval $PREP_CMD -+ -+echo 'ex /a' > $TMPFILE.cmd -+$DEBUGFS -f $TMPFILE.cmd $TMPFILE > $OUT1.new 2>&1 -+rm -rf $TMPFILE.cmd -+$FSCK $FSCK_OPT -N test_filesys $TMPFILE >> $OUT1.new 2>&1 -+status=$? -+echo Exit status is $status >> $OUT1.new -+sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT1.new >> $OUT1 -+rm -f $OUT1.new -+ -+if [ "$ONE_PASS_ONLY" != "true" ]; then -+ $FSCK $SECOND_FSCK_OPT -N test_filesys $TMPFILE > $OUT2.new 2>&1 -+ status=$? -+ echo Exit status is $status >> $OUT2.new -+ echo 'ex /a' > $TMPFILE.cmd -+ $DEBUGFS -f $TMPFILE.cmd $TMPFILE >> $OUT2.new 2>&1 -+ rm -rf $TMPFILE.cmd -+ sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT2.new > $OUT2 -+ rm -f $OUT2.new -+fi -+ -+eval $AFTER_CMD -+ -+if [ "$SKIP_VERIFY" != "true" ] ; then -+ rm -f $test_name.ok $test_name.failed -+ cmp -s $OUT1 $EXP1 -+ status1=$? -+ if [ "$ONE_PASS_ONLY" != "true" ]; then -+ cmp -s $OUT2 $EXP2 -+ status2=$? -+ else -+ status2=0 -+ fi -+ if [ "$PASS_ZERO" = "true" ]; then -+ cmp -s $test_name.0.log $test_dir/expect.0 -+ status3=$? -+ else -+ status3=0 -+ fi -+ -+ if [ -z "$test_description" ] ; then -+ description="$test_name" -+ else -+ description="$test_name: $test_description" -+ fi -+ -+ if [ "$status1" -eq 0 -a "$status2" -eq 0 -a "$status3" -eq 0 ] ; then -+ echo "$description: ok" -+ touch $test_name.ok -+ else -+ echo "$description: failed" -+ rm -f $test_name.failed -+ if [ "$PASS_ZERO" = "true" ]; then -+ diff $DIFF_OPTS $test_dir/expect.0 \ -+ $test_name.0.log >> $test_name.failed -+ fi -+ diff $DIFF_OPTS $EXP1 $OUT1 >> $test_name.failed -+ if [ "$ONE_PASS_ONLY" != "true" ]; then -+ diff $DIFF_OPTS $EXP2 $OUT2 >> $test_name.failed -+ fi -+ fi -+ rm -f tmp_expect -+fi -+ -+if [ "$SKIP_CLEANUP" != "true" ] ; then -+ unset IMAGE FSCK_OPT SECOND_FSCK_OPT OUT1 OUT2 EXP1 EXP2 -+ unset SKIP_VERIFY SKIP_CLEANUP SKIP_GUNZIP ONE_PASS_ONLY PREP_CMD -+ unset DESCRIPTION SKIP_UNLINK AFTER_CMD PASS_ZERO -+fi -+ -diff --git a/tests/f_extents/expect.1 b/tests/f_extents/expect.1 -index 2abe32e..e9d9e5b 100644 ---- a/tests/f_extents/expect.1 -+++ b/tests/f_extents/expect.1 -@@ -6,15 +6,25 @@ Inode 12 has an invalid extent - (logical block 0, invalid physical block 21994527527949, len 17) - Clear? yes - -+Inode 12 extent tree (at level 1) could be shorter. Fix? yes -+ - Inode 12, i_blocks is 34, should be 0. Fix? yes - - Inode 13 missing EXTENT_FL, but is in extents format - Fix? yes - -+Inode 16 has a duplicate extent mapping -+ (logical block 3, invalid physical block 4613, len 2) -+Clear? yes -+ -+Inode 16, i_blocks is 16, should be 12. Fix? yes -+ - Inode 17 has an invalid extent - (logical block 0, invalid physical block 22011707397135, len 15) - Clear? yes - -+Inode 17 extent tree (at level 1) could be shorter. Fix? yes -+ - Inode 17, i_blocks is 32, should be 0. Fix? yes - - Error while reading over extent tree in inode 18: Corrupt extent header -@@ -22,19 +32,23 @@ 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 1E: Optimizing extent trees - Pass 2: Checking directory structure - Entry 'fbad-flag' in / (2) has deleted/unused inode 18. Clear? yes - - Pass 3: Checking directory connectivity - Pass 4: Checking reference counts - Pass 5: Checking group summary information --Block bitmap differences: -1081 +4611 -(5121--5142) -+Block bitmap differences: -1081 +4611 -(4613--4614) -(5121--5142) - Fix? yes - --Free blocks count wrong for group #0 (7081, counted=7098). -+Free blocks count wrong for group #0 (7081, counted=7100). - Fix? yes - --Free blocks count wrong (7081, counted=7098). -+Free blocks count wrong (7081, counted=7100). - Fix? yes - - Inode bitmap differences: -18 -@@ -48,5 +62,5 @@ Fix? yes - - - test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** --test_filesys: 18/256 files (0.0% non-contiguous), 1094/8192 blocks -+test_filesys: 18/256 files (5.6% non-contiguous), 1092/8192 blocks - Exit status is 1 -diff --git a/tests/f_extents/expect.2 b/tests/f_extents/expect.2 -index 6162cdf..5c9d6a6 100644 ---- a/tests/f_extents/expect.2 -+++ b/tests/f_extents/expect.2 -@@ -3,5 +3,5 @@ Pass 2: Checking directory structure - Pass 3: Checking directory connectivity - Pass 4: Checking reference counts - Pass 5: Checking group summary information --test_filesys: 18/256 files (0.0% non-contiguous), 1094/8192 blocks -+test_filesys: 18/256 files (5.6% non-contiguous), 1092/8192 blocks - Exit status is 0 -diff --git a/tests/f_extents2/expect.1 b/tests/f_extents2/expect.1 -index fa7f6eb..180568b 100644 ---- a/tests/f_extents2/expect.1 -+++ b/tests/f_extents2/expect.1 -@@ -55,7 +55,7 @@ Pass 2: Checking directory structure - Pass 3: Checking directory connectivity - Pass 4: Checking reference counts - Pass 5: Checking group summary information --Block bitmap differences: -(26--34) -(154--199) -+Block bitmap differences: -(25--33) -(154--199) - Fix? yes - - Free blocks count wrong for group #0 (65535, counted=55). -diff --git a/tests/f_holedir4/expect.1 b/tests/f_holedir4/expect.1 -new file mode 100644 -index 0000000..1e66fb6 ---- /dev/null -+++ b/tests/f_holedir4/expect.1 -@@ -0,0 +1,68 @@ -+Pass 1: Checking inodes, blocks, and sizes -+Directory inode 12 block 211 should be at block 25. Fix? yes -+ -+Inode 12, i_size is 4096, should be 110592. Fix? yes -+ -+Inode 12, i_blocks is 128, should be 256. Fix? yes -+ -+Pass 2: Checking directory structure -+Directory inode 12 has an unallocated block #2. Allocate? yes -+ -+Directory inode 12 has an unallocated block #3. Allocate? yes -+ -+Directory inode 12 has an unallocated block #4. Allocate? yes -+ -+Directory inode 12 has an unallocated block #5. Allocate? yes -+ -+Directory inode 12 has an unallocated block #6. Allocate? yes -+ -+Directory inode 12 has an unallocated block #7. Allocate? yes -+ -+Directory inode 12 has an unallocated block #8. Allocate? yes -+ -+Directory inode 12 has an unallocated block #9. Allocate? yes -+ -+Directory inode 12 has an unallocated block #10. Allocate? yes -+ -+Directory inode 12 has an unallocated block #11. Allocate? yes -+ -+Directory inode 12 has an unallocated block #12. Allocate? yes -+ -+Directory inode 12 has an unallocated block #13. Allocate? yes -+ -+Directory inode 12 has an unallocated block #14. Allocate? yes -+ -+Directory inode 12 has an unallocated block #15. Allocate? yes -+ -+Directory inode 12 has an unallocated block #16. Allocate? yes -+ -+Directory inode 12 has an unallocated block #17. Allocate? yes -+ -+Directory inode 12 has an unallocated block #18. Allocate? yes -+ -+Directory inode 12 has an unallocated block #19. Allocate? yes -+ -+Directory inode 12 has an unallocated block #20. Allocate? yes -+ -+Directory inode 12 has an unallocated block #21. Allocate? yes -+ -+Directory inode 12 has an unallocated block #22. Allocate? yes -+ -+Directory inode 12 has an unallocated block #23. Allocate? yes -+ -+Directory inode 12 has an unallocated block #24. Allocate? yes -+ -+Pass 3: Checking directory connectivity -+Pass 3A: Optimizing directories -+Pass 4: Checking reference counts -+Pass 5: Checking group summary information -+Free blocks count wrong for group #0 (26, counted=25). -+Fix? yes -+ -+Free blocks count wrong (416, counted=400). -+Fix? yes -+ -+ -+test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** -+test_filesys: 13/32 files (7.7% non-contiguous), 112/512 blocks -+Exit status is 1 -diff --git a/tests/f_holedir4/expect.2 b/tests/f_holedir4/expect.2 -new file mode 100644 -index 0000000..1f0e351 ---- /dev/null -+++ b/tests/f_holedir4/expect.2 -@@ -0,0 +1,11 @@ -+Pass 1: Checking inodes, blocks, and sizes -+Inode 12, i_blocks is 3072, should be 128. 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: 13/32 files (0.0% non-contiguous), 112/512 blocks -+Exit status is 1 -diff --git a/tests/f_holedir4/image.gz b/tests/f_holedir4/image.gz -new file mode 100644 -index 0000000..8ab1245 -Binary files /dev/null and b/tests/f_holedir4/image.gz differ -diff --git a/tests/f_holedir4/name b/tests/f_holedir4/name -new file mode 100644 -index 0000000..5eb55c1 ---- /dev/null -+++ b/tests/f_holedir4/name -@@ -0,0 +1 @@ -+bigalloc directory with hole and misaligned extent after hole -diff --git a/tests/f_htree_bad_csum/expect.1 b/tests/f_htree_bad_csum/expect.1 -new file mode 100644 -index 0000000..258362b ---- /dev/null -+++ b/tests/f_htree_bad_csum/expect.1 -@@ -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 -index 0000000..7e3523b ---- /dev/null -+++ b/tests/f_htree_bad_csum/expect.2 -@@ -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 -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 -index 0000000..ebfc3ea ---- /dev/null -+++ b/tests/f_htree_bad_csum/name -@@ -0,0 +1 @@ -+htree block w/ missing/bad csum, bad protective dirent, or htree index corruption (metadata_csum) -diff --git a/tests/f_htree_leaf_csum/expect.1 b/tests/f_htree_leaf_csum/expect.1 -new file mode 100644 -index 0000000..d6b179e ---- /dev/null -+++ b/tests/f_htree_leaf_csum/expect.1 -@@ -0,0 +1,12 @@ -+Pass 1: Checking inodes, blocks, and sizes -+Pass 2: Checking directory structure -+Directory inode 12, block #1: directory passes checks but fails checksum. -+Fix? yes -+ -+Pass 3: Checking directory connectivity -+Pass 4: Checking reference counts -+Pass 5: Checking group summary information -+ -+test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** -+test_filesys: 430/512 files (0.2% non-contiguous), 45/512 blocks -+Exit status is 1 -diff --git a/tests/f_htree_leaf_csum/expect.2 b/tests/f_htree_leaf_csum/expect.2 -new file mode 100644 -index 0000000..1609785 ---- /dev/null -+++ b/tests/f_htree_leaf_csum/expect.2 -@@ -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: 430/512 files (0.2% non-contiguous), 45/512 blocks -+Exit status is 0 -diff --git a/tests/f_htree_leaf_csum/image.gz b/tests/f_htree_leaf_csum/image.gz -new file mode 100644 -index 0000000..f2e4619 -Binary files /dev/null and b/tests/f_htree_leaf_csum/image.gz differ -diff --git a/tests/f_htree_leaf_csum/name b/tests/f_htree_leaf_csum/name -new file mode 100644 -index 0000000..43c6ada ---- /dev/null -+++ b/tests/f_htree_leaf_csum/name -@@ -0,0 +1 @@ -+bad csum in htree leaf block -diff --git a/tests/f_idata_and_extents/expect.1 b/tests/f_idata_and_extents/expect.1 -new file mode 100644 -index 0000000..7f7fbf3 ---- /dev/null -+++ b/tests/f_idata_and_extents/expect.1 -@@ -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 -index 0000000..307d3f6 ---- /dev/null -+++ b/tests/f_idata_and_extents/expect.2 -@@ -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 -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 -index 0000000..362ce0e ---- /dev/null -+++ b/tests/f_idata_and_extents/name -@@ -0,0 +1 @@ -+conflicting extents and inline_data inode flags -diff --git a/tests/f_ind_inode_collision/expect.1 b/tests/f_ind_inode_collision/expect.1 -new file mode 100644 -index 0000000..012cd9f ---- /dev/null -+++ b/tests/f_ind_inode_collision/expect.1 -@@ -0,0 +1,147 @@ -+Pass 1: Checking inodes, blocks, and sizes -+Inode 12 block 41 conflicts with critical metadata, skipping block checks. -+Inode 12 block 40 conflicts with critical metadata, skipping block checks. -+Inode 12 block 34 conflicts with critical metadata, skipping block checks. -+Illegal block number passed to ext2fs_test_block_bitmap #16777215 for metadata block map -+Inode 12 block 1 conflicts with critical metadata, skipping block checks. -+Inode 12, i_size is 33, should be 25227264. Fix? yes -+ -+Inode 12, i_blocks is 999, should be 184. 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 2: 3 -+Multiply-claimed block(s) in inode 7: 11 -+Multiply-claimed block(s) in inode 11: 4--7 -+Multiply-claimed block(s) in inode 12: 41 40Illegal block number passed to ext2fs_test_block_bitmap #1421529376 for multiply claimed block map -+Illegal block number passed to ext2fs_test_block_bitmap #1421529376 for multiply claimed block map -+Illegal block number passed to ext2fs_test_block_bitmap #1421529376 for multiply claimed block map -+Illegal block number passed to ext2fs_test_block_bitmap #16877 for multiply claimed block map -+Illegal block number passed to ext2fs_test_block_bitmap #4096 for multiply claimed block map -+Illegal block number passed to ext2fs_test_block_bitmap #1421529376 for multiply claimed block map -+Illegal block number passed to ext2fs_test_block_bitmap #1421529376 for multiply claimed block map -+Illegal block number passed to ext2fs_test_block_bitmap #1421529376 for multiply claimed block map -+Illegal block number passed to ext2fs_test_block_bitmap #196608 for multiply claimed block map -+ 34 8 3Illegal block number passed to ext2fs_test_block_bitmap #1421529376 for multiply claimed block map -+Illegal block number passed to ext2fs_test_block_bitmap #33152 for multiply claimed block map -+Illegal block number passed to ext2fs_test_block_bitmap #4243456 for multiply claimed block map -+Illegal block number passed to ext2fs_test_block_bitmap #1421529376 for multiply claimed block map -+Illegal block number passed to ext2fs_test_block_bitmap #1421529376 for multiply claimed block map -+Illegal block number passed to ext2fs_test_block_bitmap #1421529376 for multiply claimed block map -+Illegal block number passed to ext2fs_test_block_bitmap #65536 for multiply claimed block map -+ 28 8 11 1Illegal block number passed to ext2fs_test_block_bitmap #1421529376 for multiply claimed block map -+Illegal block number passed to ext2fs_test_block_bitmap #16832 for multiply claimed block map -+Illegal block number passed to ext2fs_test_block_bitmap #16384 for multiply claimed block map -+Illegal block number passed to ext2fs_test_block_bitmap #1421529376 for multiply claimed block map -+Illegal block number passed to ext2fs_test_block_bitmap #1421529376 for multiply claimed block map -+Illegal block number passed to ext2fs_test_block_bitmap #1421529376 for multiply claimed block map -+Illegal block number passed to ext2fs_test_block_bitmap #131072 for multiply claimed block map -+ 28 4--7Illegal block number passed to ext2fs_test_block_bitmap #1421529376 for multiply claimed block map -+Illegal block number passed to ext2fs_test_block_bitmap #33206 for multiply claimed block map -+Illegal block number passed to ext2fs_test_block_bitmap #25227264 for multiply claimed block map -+Illegal block number passed to ext2fs_test_block_bitmap #1421529397 for multiply claimed block map -+Illegal block number passed to ext2fs_test_block_bitmap #1421529397 for multiply claimed block map -+Illegal block number passed to ext2fs_test_block_bitmap #1421529397 for multiply claimed block map -+Illegal block number passed to ext2fs_test_block_bitmap #65536 for multiply claimed block map -+ 28 41Illegal block number passed to ext2fs_test_block_bitmap #1421529397 for multiply claimed block map -+Illegal block number passed to ext2fs_test_block_bitmap #16777215 for multiply claimed block map -+ 28 -+Error while iterating over blocks in inode 12 (pass1b): Illegal indirect block found -+Pass 1C: Scanning directories for inodes with multiply-claimed blocks -+Pass 1D: Reconciling multiply-claimed blocks -+(There are 3 inodes containing multiply-claimed blocks.) -+ -+File / (inode #2, mod time Sat Jan 17 21:16:16 2015) -+ has 1 multiply-claimed block(s), shared with 1 file(s): -+ /a (inode #12, mod time Sat Jan 17 21:16:37 2015) -+Clone multiply-claimed blocks? yes -+ -+File /lost+found (inode #11, mod time Sat Jan 17 21:16:16 2015) -+ has 4 multiply-claimed block(s), shared with 1 file(s): -+ /a (inode #12, mod time Sat Jan 17 21:16:37 2015) -+Clone multiply-claimed blocks? yes -+ -+File /a (inode #12, mod time Sat Jan 17 21:16:37 2015) -+ has 17 multiply-claimed block(s), shared with 4 file(s): -+ -+ /lost+found (inode #11, mod time Sat Jan 17 21:16:16 2015) -+ (inode #7, mod time Sat Jan 17 21:16:16 2015) -+ / (inode #2, mod time Sat Jan 17 21:16:16 2015) -+Clone multiply-claimed blocks? yes -+ -+Illegal block number passed to ext2fs_test_block_bitmap #1421529376 for multiply claimed block map -+Illegal block number passed to ext2fs_test_block_bitmap #1421529376 for multiply claimed block map -+Illegal block number passed to ext2fs_test_block_bitmap #1421529376 for multiply claimed block map -+Illegal block number passed to ext2fs_test_block_bitmap #16877 for multiply claimed block map -+Illegal block number passed to ext2fs_test_block_bitmap #4096 for multiply claimed block map -+Illegal block number passed to ext2fs_test_block_bitmap #1421529376 for multiply claimed block map -+Illegal block number passed to ext2fs_test_block_bitmap #1421529376 for multiply claimed block map -+Illegal block number passed to ext2fs_test_block_bitmap #1421529376 for multiply claimed block map -+Illegal block number passed to ext2fs_test_block_bitmap #196608 for multiply claimed block map -+Illegal block number passed to ext2fs_test_block_bitmap #1421529376 for multiply claimed block map -+Illegal block number passed to ext2fs_test_block_bitmap #33152 for multiply claimed block map -+Illegal block number passed to ext2fs_test_block_bitmap #4243456 for multiply claimed block map -+Illegal block number passed to ext2fs_test_block_bitmap #1421529376 for multiply claimed block map -+Illegal block number passed to ext2fs_test_block_bitmap #1421529376 for multiply claimed block map -+Illegal block number passed to ext2fs_test_block_bitmap #1421529376 for multiply claimed block map -+Illegal block number passed to ext2fs_test_block_bitmap #65536 for multiply claimed block map -+Illegal block number passed to ext2fs_test_block_bitmap #1421529376 for multiply claimed block map -+Illegal block number passed to ext2fs_test_block_bitmap #16832 for multiply claimed block map -+Illegal block number passed to ext2fs_test_block_bitmap #16384 for multiply claimed block map -+Illegal block number passed to ext2fs_test_block_bitmap #1421529376 for multiply claimed block map -+Illegal block number passed to ext2fs_test_block_bitmap #1421529376 for multiply claimed block map -+Illegal block number passed to ext2fs_test_block_bitmap #1421529376 for multiply claimed block map -+Illegal block number passed to ext2fs_test_block_bitmap #131072 for multiply claimed block map -+Illegal block number passed to ext2fs_test_block_bitmap #1421529376 for multiply claimed block map -+Illegal block number passed to ext2fs_test_block_bitmap #33206 for multiply claimed block map -+Illegal block number passed to ext2fs_test_block_bitmap #25227264 for multiply claimed block map -+Illegal block number passed to ext2fs_test_block_bitmap #1421529397 for multiply claimed block map -+Illegal block number passed to ext2fs_test_block_bitmap #1421529397 for multiply claimed block map -+Illegal block number passed to ext2fs_test_block_bitmap #1421529397 for multiply claimed block map -+Illegal block number passed to ext2fs_test_block_bitmap #65536 for multiply claimed block map -+Illegal block number passed to ext2fs_test_block_bitmap #1421529397 for multiply claimed block map -+Illegal block number passed to ext2fs_test_block_bitmap #16777215 for multiply claimed block map -+Pass 2: Checking directory structure -+Restarting e2fsck from the beginning... -+Pass 1: Checking inodes, blocks, and sizes -+Inode 12 has illegal block(s). Clear? yes -+ -+Illegal block #1038 (1421529376) in inode 12. CLEARED. -+Illegal block #1039 (1421529376) in inode 12. CLEARED. -+Illegal block #1040 (1421529376) in inode 12. CLEARED. -+Illegal block #1100 (16877) in inode 12. CLEARED. -+Illegal block #1101 (4096) in inode 12. CLEARED. -+Illegal block #1102 (1421529376) in inode 12. CLEARED. -+Illegal block #1103 (1421529376) in inode 12. CLEARED. -+Illegal block #1104 (1421529376) in inode 12. CLEARED. -+Illegal block #1106 (196608) in inode 12. CLEARED. -+Illegal block #1136 (1421529376) in inode 12. CLEARED. -+Illegal block #1420 (33152) in inode 12. CLEARED. -+Too many illegal blocks in inode 12. -+Clear inode? yes -+ -+Restarting e2fsck from the beginning... -+Pass 1: Checking inodes, blocks, and sizes -+Pass 2: Checking directory structure -+Entry 'a' in / (2) has deleted/unused inode 12. Clear? yes -+ -+Pass 3: Checking directory connectivity -+Pass 4: Checking reference counts -+Pass 5: Checking group summary information -+Block bitmap differences: -(3--7) -(15--17) -(19--24) -+Fix? yes -+ -+Inode bitmap differences: -12 -+Fix? yes -+ -+Free inodes count wrong for group #0 (116, counted=117). -+Fix? yes -+ -+Free inodes count wrong (116, counted=117). -+Fix? yes -+ -+ -+test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** -+test_filesys: 11/128 files (9.1% non-contiguous), 18/512 blocks -+Exit status is 1 -diff --git a/tests/f_ind_inode_collision/expect.2 b/tests/f_ind_inode_collision/expect.2 -new file mode 100644 -index 0000000..d0a6dac ---- /dev/null -+++ b/tests/f_ind_inode_collision/expect.2 -@@ -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), 18/512 blocks -+Exit status is 0 -diff --git a/tests/f_ind_inode_collision/image.gz b/tests/f_ind_inode_collision/image.gz -new file mode 100644 -index 0000000..924d220 -Binary files /dev/null and b/tests/f_ind_inode_collision/image.gz differ -diff --git a/tests/f_ind_inode_collision/name b/tests/f_ind_inode_collision/name -new file mode 100644 -index 0000000..11feee3 ---- /dev/null -+++ b/tests/f_ind_inode_collision/name -@@ -0,0 +1 @@ -+multiple *ind collisions with critical metadata -diff --git a/tests/f_inlinedata_dirblocks/expect.1 b/tests/f_inlinedata_dirblocks/expect.1 -new file mode 100644 -index 0000000..e3d0ee2 ---- /dev/null -+++ b/tests/f_inlinedata_dirblocks/expect.1 -@@ -0,0 +1,25 @@ -+Pass 1: Checking inodes, blocks, and sizes -+Pass 2: Checking directory structure -+Entry '..' in ??? (12) has invalid inode #: 1752440867. -+Clear? yes -+ -+Directory inode 12, block #0, offset 4: directory corrupted -+Salvage? yes -+ -+Directory inode 12, block #1, offset 0: directory corrupted -+Salvage? yes -+ -+Pass 3: Checking directory connectivity -+'..' in /aoo (12) is ??? (1752440867), should be / (2). -+Fix? yes -+ -+Error while adjusting inode count on inode 0 -+Pass 4: Checking reference counts -+Pass 5: Checking group summary information -+Directories count wrong for group #0 (2, counted=3). -+Fix? yes -+ -+ -+test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** -+test_filesys: 12/128 files (0.0% non-contiguous), 17/512 blocks -+Exit status is 1 -diff --git a/tests/f_inlinedata_dirblocks/expect.2 b/tests/f_inlinedata_dirblocks/expect.2 -new file mode 100644 -index 0000000..3b6073e ---- /dev/null -+++ b/tests/f_inlinedata_dirblocks/expect.2 -@@ -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), 17/512 blocks -+Exit status is 0 -diff --git a/tests/f_inlinedata_dirblocks/image.gz b/tests/f_inlinedata_dirblocks/image.gz -new file mode 100644 -index 0000000..4cd64e0 -Binary files /dev/null and b/tests/f_inlinedata_dirblocks/image.gz differ -diff --git a/tests/f_inlinedata_dirblocks/name b/tests/f_inlinedata_dirblocks/name -new file mode 100644 -index 0000000..a226758 ---- /dev/null -+++ b/tests/f_inlinedata_dirblocks/name -@@ -0,0 +1 @@ -+check inline dir as two dirent blocks -diff --git a/tests/f_inlinedata_repair/expect.1 b/tests/f_inlinedata_repair/expect.1 -new file mode 100644 -index 0000000..9c84b14 ---- /dev/null -+++ b/tests/f_inlinedata_repair/expect.1 -@@ -0,0 +1,58 @@ -+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 -+ -+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 -+ -+Symlink /1 (inode #12) is invalid. -+Clear? yes -+ -+Symlink /3 (inode #14) is invalid. -+Clear? yes -+ -+Inode 38 (/B) has invalid mode (00). -+Clear? yes -+ -+Inode 36 (/A) has invalid mode (00). -+Clear? yes -+ -+Pass 3: Checking directory connectivity -+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 -+ -+Pass 5: Checking group summary information -+ -+test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** -+test_filesys: 26/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 -index 0000000..69d874e ---- /dev/null -+++ b/tests/f_inlinedata_repair/expect.2 -@@ -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: 26/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 -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 -index 0000000..7e7e898 ---- /dev/null -+++ b/tests/f_inlinedata_repair/name -@@ -0,0 +1 @@ -+repair corrupt inline data files -diff --git a/tests/f_inlinedir_detector/expect.1 b/tests/f_inlinedir_detector/expect.1 -new file mode 100644 -index 0000000..72b7519 ---- /dev/null -+++ b/tests/f_inlinedir_detector/expect.1 -@@ -0,0 +1,20 @@ -+Pass 1: Checking inodes, blocks, and sizes -+Special (device/socket/fifo) file (inode 12) has extents -+or inline-data flag set. Clear? yes -+ -+Special (device/socket/fifo) inode 12 has non-zero size. Fix? yes -+ -+Inode 13 is a named pipe but it looks like it is really a directory. -+Fix? yes -+ -+Pass 2: Checking directory structure -+Entry 'moo' in / (2) has an incorrect filetype (was 1, should be 5). -+Fix? yes -+ -+Pass 3: Checking directory connectivity -+Pass 4: Checking reference counts -+Pass 5: Checking group summary information -+ -+test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** -+test_filesys: 13/128 files (0.0% non-contiguous), 17/512 blocks -+Exit status is 1 -diff --git a/tests/f_inlinedir_detector/expect.2 b/tests/f_inlinedir_detector/expect.2 -new file mode 100644 -index 0000000..06886a4 ---- /dev/null -+++ b/tests/f_inlinedir_detector/expect.2 -@@ -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: 13/128 files (0.0% non-contiguous), 17/512 blocks -+Exit status is 0 -diff --git a/tests/f_inlinedir_detector/image.gz b/tests/f_inlinedir_detector/image.gz -new file mode 100644 -index 0000000..34b4518 -Binary files /dev/null and b/tests/f_inlinedir_detector/image.gz differ -diff --git a/tests/f_inlinedir_detector/name b/tests/f_inlinedir_detector/name -new file mode 100644 -index 0000000..3368af5 ---- /dev/null -+++ b/tests/f_inlinedir_detector/name -@@ -0,0 +1 @@ -+detect inline dirs correctly -diff --git a/tests/f_inode_ea_collision/expect.1 b/tests/f_inode_ea_collision/expect.1 -new file mode 100644 -index 0000000..a67a5f1 ---- /dev/null -+++ b/tests/f_inode_ea_collision/expect.1 -@@ -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 -index 0000000..5a7ca86 ---- /dev/null -+++ b/tests/f_inode_ea_collision/expect.2 -@@ -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 -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 -index 0000000..b64119e ---- /dev/null -+++ b/tests/f_inode_ea_collision/name -@@ -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 -index 0000000..00cdced ---- /dev/null -+++ b/tests/f_itable_collision/expect.1 -@@ -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): -+ -+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 -index 0000000..4abc600 ---- /dev/null -+++ b/tests/f_itable_collision/expect.2 -@@ -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 -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 -index 0000000..dab3d45 ---- /dev/null -+++ b/tests/f_itable_collision/name -@@ -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 -index 0000000..52b69a2 ---- /dev/null -+++ b/tests/f_itable_collision/script -@@ -0,0 +1,37 @@ -+#!/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 -+ -+# 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 -N test_filesys $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 -N test_filesys $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 -diff --git a/tests/f_jnl_64bit/expect.0 b/tests/f_jnl_64bit/expect.0 -index 2007f03..5cef2d8 100644 ---- a/tests/f_jnl_64bit/expect.0 -+++ b/tests/f_jnl_64bit/expect.0 -@@ -1,189 +1,97 @@ - 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_jnl_errno/expect.0 b/tests/f_jnl_errno/expect.0 -index 6dad72a..2a9426d 100644 ---- a/tests/f_jnl_errno/expect.0 -+++ b/tests/f_jnl_errno/expect.0 -@@ -40,7 +40,8 @@ Journal start: 0 - Group 0: (Blocks 1-8191) [ITABLE_ZEROED] - Primary superblock at 1, Group descriptors at 2-2 - Reserved GDT blocks at 3-33 -- Block bitmap at 34 (+33), Inode bitmap at 50 (+49) -+ Block bitmap at 34 (+33) -+ Inode bitmap at 50 (+49) - Inode table at 66-321 (+65) - 6862 free blocks, 2037 free inodes, 2 directories, 2037 unused inodes - Free blocks: 1330-8191 -diff --git a/tests/f_jnl_etb_alloc_fail/expect.1 b/tests/f_jnl_etb_alloc_fail/expect.1 -new file mode 100644 -index 0000000..243a151 ---- /dev/null -+++ b/tests/f_jnl_etb_alloc_fail/expect.1 -@@ -0,0 +1,31 @@ -+Superblock has an invalid journal (inode 8). -+Clear? yes -+ -+*** journal has been deleted *** -+ -+Superblock has_journal flag is clear, but a journal is present. -+Clear? yes -+ -+Pass 1: Checking inodes, blocks, and sizes -+Journal inode is not in use, but contains data. Clear? 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: -(32--33) -(35--49) -(83--511) -(513--1087) -1089 -+Fix? yes -+ -+Free blocks count wrong for group #0 (0, counted=1022). -+Fix? yes -+ -+Free blocks count wrong (0, counted=1022). -+Fix? yes -+ -+Recreate journal? yes -+ -+Creating journal (1024 blocks): Could not allocate block in ext2 filesystem: while trying to create journal -+ -+test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** -+test_filesys: 12/128 files (8.3% non-contiguous), 2048/2048 blocks -+Exit status is 1 -diff --git a/tests/f_jnl_etb_alloc_fail/expect.2 b/tests/f_jnl_etb_alloc_fail/expect.2 -new file mode 100644 -index 0000000..69859dd ---- /dev/null -+++ b/tests/f_jnl_etb_alloc_fail/expect.2 -@@ -0,0 +1,20 @@ -+Pass 1: Checking inodes, blocks, and sizes -+Journal inode is not in use, but contains data. Clear? 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: -(32--33) -(35--49) -(83--511) -(513--1087) -1089 -+Fix? yes -+ -+Free blocks count wrong for group #0 (0, counted=1022). -+Fix? yes -+ -+Free blocks count wrong (0, counted=1022). -+Fix? yes -+ -+ -+test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** -+test_filesys: 12/128 files (8.3% non-contiguous), 1026/2048 blocks -+Exit status is 1 -diff --git a/tests/f_jnl_etb_alloc_fail/image.gz b/tests/f_jnl_etb_alloc_fail/image.gz -new file mode 100644 -index 0000000..4cf2dbf -Binary files /dev/null and b/tests/f_jnl_etb_alloc_fail/image.gz differ -diff --git a/tests/f_jnl_etb_alloc_fail/name b/tests/f_jnl_etb_alloc_fail/name -new file mode 100644 -index 0000000..7651fdc ---- /dev/null -+++ b/tests/f_jnl_etb_alloc_fail/name -@@ -0,0 +1 @@ -+can't allocate extent tree block while recreating journal -diff --git a/tests/f_miss_journal/expect.1 b/tests/f_miss_journal/expect.1 -index 6ec8b38..d435952 100644 ---- a/tests/f_miss_journal/expect.1 -+++ b/tests/f_miss_journal/expect.1 -@@ -1,7 +1,7 @@ - Superblock has an invalid journal (inode 8). - Clear? yes - --*** ext3 journal has been deleted - filesystem is now ext2 only *** -+*** journal has been deleted *** - - Pass 1: Checking inodes, blocks, and sizes - Pass 2: Checking directory structure -@@ -21,7 +21,7 @@ Recreate journal? yes - - Creating journal (1024 blocks): Done. - --*** journal has been re-created - filesystem is now ext3 again *** -+*** journal has been regenerated *** - - test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** - test_filesys: 11/256 files (0.0% non-contiguous), 1079/2048 blocks -diff --git a/tests/f_no/expect b/tests/f_no/expect -new file mode 100644 -index 0000000..e7b619d ---- /dev/null -+++ b/tests/f_no/expect -@@ -0,0 +1,48 @@ -+Pass 1: Checking inodes, blocks, and sizes -+Inode 12 has an invalid extent -+ (logical block 0, invalid physical block 999999999, len 1) -+Clear? no -+Inode 12 has an invalid extent -+ (logical block 1, invalid physical block 9999999999, len 1) -+Clear? no -+Inode 13 is in use, but has dtime set. Fix? no -+Inode 13 has an invalid extent -+ (logical block 1, invalid physical block 8888888888888, len 1) -+Clear? no -+Inode 13 has an invalid extent -+ (logical block 0, invalid physical block 888888888888, len 1) -+Clear? no -+Inode 14 is in use, but has dtime set. Fix? no -+Inode 14 has an invalid extent -+ (logical block 300, invalid physical block 777777777777, len 300) -+Clear? no -+Inode 14 has an invalid extent -+ (logical block 0, invalid physical block 7777777777, len 1) -+Clear? no -+Inode 14, i_blocks is 52574694748113, should be 0. Fix? no -+Pass 2: Checking directory structure -+Extended attribute block for inode 12 (/a) is invalid (999999). -+Clear? no -+Extended attribute block for inode 13 (/b) is invalid (298954296). -+Clear? no -+Extended attribute block for inode 14 (/c) is invalid (388697201). -+Clear? no -+Pass 3: Checking directory connectivity -+Pass 4: Checking reference counts -+Inode 12 ref count is 34463, should be 1. Fix? no -+Inode 13 ref count is 9999, should be 1. Fix? no -+Inode 14 ref count is 12241, should be 1. Fix? no -+Pass 5: Checking group summary information -+Block bitmap differences: -202 -381 -457 -+Fix? no -+Free blocks count wrong for group #0 (0, counted=491). -+Fix? no -+Free blocks count wrong (494, counted=491). -+Fix? no -+Free inodes count wrong for group #0 (4294967293, counted=114). -+Fix? no -+ -+test_filesys: ********** WARNING: Filesystem still has errors ********** -+ -+test_filesys: 14/128 files (0.0% non-contiguous), 18/512 blocks -+Exit status is 4 -diff --git a/tests/f_no/script b/tests/f_no/script -new file mode 100644 -index 0000000..2a67e77 ---- /dev/null -+++ b/tests/f_no/script -@@ -0,0 +1,27 @@ -+test_description="e2fsck with repeated no" -+FSCK_OPT=-f -+OUT=$test_name.log -+EXP=$test_dir/expect -+ -+gunzip < $test_dir/../f_yesall/image.gz > $TMPFILE -+ -+rm -rf $OUT -+echo "nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn" | E2FSCK_FORCE_INTERACTIVE=y $FSCK $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 -+rm -f $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 -+ rm -f tmp_expect -+fi -+ -+unset IMAGE FSCK_OPT OUT EXP -diff --git a/tests/f_no_cache_corrupt_inode/expect.1 b/tests/f_no_cache_corrupt_inode/expect.1 -new file mode 100644 -index 0000000..4f82f75 ---- /dev/null -+++ b/tests/f_no_cache_corrupt_inode/expect.1 -@@ -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 -index 0000000..1b43315 ---- /dev/null -+++ b/tests/f_no_cache_corrupt_inode/expect.2 -@@ -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 -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 -index 0000000..fb213e2 ---- /dev/null -+++ b/tests/f_no_cache_corrupt_inode/name -@@ -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 -index 0000000..986fe12 ---- /dev/null -+++ b/tests/f_nospc_create_lnf/expect.1 -@@ -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 -index 0000000..e9757f8 ---- /dev/null -+++ b/tests/f_nospc_create_lnf/expect.2 -@@ -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 -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 -index 0000000..df6c932 ---- /dev/null -+++ b/tests/f_nospc_create_lnf/name -@@ -0,0 +1 @@ -+no space to create lost+found -diff --git a/tests/f_opt_extent/expect b/tests/f_opt_extent/expect -new file mode 100644 -index 0000000..6d4863b ---- /dev/null -+++ b/tests/f_opt_extent/expect -@@ -0,0 +1,55 @@ -+tune2fs metadata_csum test -+Creating filesystem with 524288 1k blocks and 65536 inodes -+Superblock backups stored on blocks: -+ 8193, 24577, 40961, 57345, 73729, 204801, 221185, 401409 -+ -+Allocating group tables: done -+Writing inode tables: done -+Creating journal (16384 blocks): done -+Creating 477 huge file(s) with 1024 blocks each: done -+Writing superblocks and filesystem accounting information: done -+ -+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 -+ -+Exit status is 0 -+Pass 1: Checking inodes, blocks, and sizes -+Pass 2: Checking directory structure -+Pass 3: Checking directory connectivity -+Pass 3A: Optimizing directories -+Pass 4: Checking reference counts -+Pass 5: Checking group summary information -+ -+ -+ -+Change in FS metadata: -+@@ -10,7 +10,7 @@ -+ Inode count: 65536 -+ Block count: 524288 -+ Reserved block count: 26214 -+-Free blocks: 570 -++Free blocks: 567 -+ Free inodes: 65047 -+ First block: 1 -+ Block size: 1024 -+@@ -47,8 +47,8 @@ -+ Block bitmap at 262 (+261) -+ Inode bitmap at 278 (+277) -+ Inode table at 294-549 (+293) -+- 21 free blocks, 535 free inodes, 3 directories, 535 unused inodes -+- Free blocks: 4414-4434 -++ 18 free blocks, 535 free inodes, 3 directories, 535 unused inodes -++ Free blocks: 4417-4434 -+ Free inodes: 490-1024 -+ Group 1: (Blocks 8193-16384) [INODE_UNINIT] -+ Backup superblock at 8193, Group descriptors at 8194-8197 -+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 -+ -+Exit status is 0 -diff --git a/tests/f_opt_extent/name b/tests/f_opt_extent/name -new file mode 100644 -index 0000000..7d4389c ---- /dev/null -+++ b/tests/f_opt_extent/name -@@ -0,0 +1 @@ -+optimize extent tree -diff --git a/tests/f_opt_extent/script b/tests/f_opt_extent/script -new file mode 100644 -index 0000000..2da5e91 ---- /dev/null -+++ b/tests/f_opt_extent/script -@@ -0,0 +1,64 @@ -+FSCK_OPT=-fn -+OUT=$test_name.log -+EXP=$test_dir/expect -+CONF=$TMPFILE.conf -+ -+cat > $CONF << ENDL -+[fs_types] -+ ext4h = { -+ features = has_journal,extent,huge_file,flex_bg,uninit_bg,dir_nlink,extra_isize,sparse_super,filetype,dir_index,ext_attr,resize_inode,64bit,metadata_csum -+ blocksize = 1024 -+ inode_size = 256 -+ make_hugefiles = true -+ hugefiles_dir = /xyz -+ hugefiles_slack = 0 -+ hugefiles_name = aaaaa -+ hugefiles_digits = 4 -+ hugefiles_size = 1M -+ zero_hugefiles = false -+ } -+ENDL -+ -+echo "tune2fs metadata_csum test" > $OUT -+ -+MKE2FS_CONFIG=$CONF $MKE2FS -F -T ext4h $TMPFILE 524288 >> $OUT 2>&1 -+rm -rf $CONF -+ -+# dump and check -+$DUMPE2FS $TMPFILE 2> /dev/null | grep '^Group 0:' -B99 -A20 | sed -f $cmd_dir/filter.sed > $OUT.before -+$FSCK $FSCK_OPT -N test_filesys $TMPFILE >> $OUT 2>&1 -+status=$? -+echo Exit status is $status >> $OUT -+ -+# check -+$FSCK -fyD -N test_filesys $TMPFILE >> $OUT 2>&1 -+ -+# dump and check -+$DUMPE2FS $TMPFILE 2> /dev/null | grep '^Group 0:' -B99 -A20 | sed -f $cmd_dir/filter.sed > $OUT.after -+echo "Change in FS metadata:" >> $OUT -+diff -u $OUT.before $OUT.after | tail -n +3 >> $OUT -+$FSCK $FSCK_OPT -N test_filesys $TMPFILE >> $OUT 2>&1 -+status=$? -+echo Exit status is $status >> $OUT -+ -+rm $TMPFILE $OUT.before $OUT.after -+ -+# -+# Do the verification -+# -+ -+sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" -e 's/test_filesys:.*//g' < $OUT > $OUT.new -+mv $OUT.new $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 IMAGE FSCK_OPT OUT EXP CONF -diff --git a/tests/f_opt_extent_ext3/expect b/tests/f_opt_extent_ext3/expect -new file mode 100644 -index 0000000..1761471 ---- /dev/null -+++ b/tests/f_opt_extent_ext3/expect -@@ -0,0 +1,44 @@ -+rebuild extent metadata_csum test -+Creating filesystem with 524288 1k blocks and 65536 inodes -+Superblock backups stored on blocks: -+ 8193, 24577, 40961, 57345, 73729, 204801, 221185, 401409 -+ -+Allocating group tables: done -+Writing inode tables: done -+Creating journal (16384 blocks): done -+mke2fs: Operation not supported for inodes containing extents while creating huge files -+Writing superblocks and filesystem accounting information: done -+ -+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 -+ -+Exit status is 0 -+Pass 1: Checking inodes, blocks, and sizes -+Pass 2: Checking directory structure -+Pass 3: Checking directory connectivity -+Pass 3A: Optimizing directories -+Pass 4: Checking reference counts -+Pass 5: Checking group summary information -+ -+ -+ -+Change in FS metadata: -+@@ -2,7 +2,7 @@ -+ Last mounted on: -+ Filesystem magic number: 0xEF53 -+ Filesystem revision #: 1 (dynamic) -+-Filesystem features: has_journal ext_attr resize_inode dir_index filetype sparse_super large_file huge_file dir_nlink -++Filesystem features: has_journal ext_attr resize_inode dir_index filetype extent sparse_super large_file huge_file dir_nlink -+ Default mount options: user_xattr acl -+ Filesystem state: clean -+ Errors behavior: Continue -+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 -+ -+Exit status is 0 -diff --git a/tests/f_opt_extent_ext3/name b/tests/f_opt_extent_ext3/name -new file mode 100644 -index 0000000..b369685 ---- /dev/null -+++ b/tests/f_opt_extent_ext3/name -@@ -0,0 +1 @@ -+convert ext3 to extent tree -diff --git a/tests/f_opt_extent_ext3/script b/tests/f_opt_extent_ext3/script -new file mode 100644 -index 0000000..931eae7 ---- /dev/null -+++ b/tests/f_opt_extent_ext3/script -@@ -0,0 +1,65 @@ -+FSCK_OPT=-fn -+OUT=$test_name.log -+EXP=$test_dir/expect -+CONF=$TMPFILE.conf -+ -+cat > $CONF << ENDL -+[fs_types] -+ ext4h = { -+ features = has_journal,^extent,huge_file,^flex_bg,^uninit_bg,dir_nlink,^extra_isize,sparse_super,filetype,dir_index,ext_attr,resize_inode,^64bit,^metadata_csum -+ blocksize = 1024 -+ inode_size = 256 -+ make_hugefiles = true -+ hugefiles_dir = / -+ num_hugefiles = 100 -+ hugefiles_slack = 0 -+ hugefiles_name = aaaaa -+ hugefiles_digits = 4 -+ hugefiles_size = 1M -+ zero_hugefiles = false -+ } -+ENDL -+ -+echo "rebuild extent metadata_csum test" > $OUT -+ -+MKE2FS_CONFIG=$CONF $MKE2FS -F -T ext4h $TMPFILE 524288 >> $OUT 2>&1 -+rm -rf $CONF -+ -+# dump and check -+$DUMPE2FS $TMPFILE 2> /dev/null | grep '^Group 0:' -B99 -A20 | sed -f $cmd_dir/filter.sed > $OUT.before -+$FSCK $FSCK_OPT -N test_filesys $TMPFILE >> $OUT 2>&1 -+status=$? -+echo Exit status is $status >> $OUT -+ -+# check -+$FSCK -fyD -N test_filesys -E bmap2extent $TMPFILE >> $OUT 2>&1 -+ -+# dump and check -+$DUMPE2FS $TMPFILE 2> /dev/null | grep '^Group 0:' -B99 -A20 | sed -f $cmd_dir/filter.sed > $OUT.after -+echo "Change in FS metadata:" >> $OUT -+diff -u $OUT.before $OUT.after | tail -n +3 >> $OUT -+$FSCK $FSCK_OPT -N test_filesys $TMPFILE >> $OUT 2>&1 -+status=$? -+echo Exit status is $status >> $OUT -+ -+rm $TMPFILE $OUT.before $OUT.after -+ -+# -+# Do the verification -+# -+ -+sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" -e 's/test_filesys:.*//g' < $OUT > $OUT.new -+mv $OUT.new $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 IMAGE FSCK_OPT OUT EXP CONF -diff --git a/tests/f_rebuild_csum_rootdir/expect.1 b/tests/f_rebuild_csum_rootdir/expect.1 -new file mode 100644 -index 0000000..4df58f9 ---- /dev/null -+++ b/tests/f_rebuild_csum_rootdir/expect.1 -@@ -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 (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 -index 0000000..033f1bf ---- /dev/null -+++ b/tests/f_rebuild_csum_rootdir/expect.2 -@@ -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 -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 -index 0000000..b246f48 ---- /dev/null -+++ b/tests/f_rebuild_csum_rootdir/name -@@ -0,0 +1 @@ -+force fsck to rebuild a corrupted rootdir w/ metadata_csum -diff --git a/tests/f_short_encrypted_dirent/expect.1 b/tests/f_short_encrypted_dirent/expect.1 -new file mode 100644 -index 0000000..bc64922 ---- /dev/null -+++ b/tests/f_short_encrypted_dirent/expect.1 -@@ -0,0 +1,17 @@ -+Pass 1: Checking inodes, blocks, and sizes -+Pass 2: Checking directory structure -+Encrypted entry 'motd' in /get_shorty (12) is too short. -+Clear? yes -+ -+Pass 3: Checking directory connectivity -+Pass 4: Checking reference counts -+Unattached inode 13 -+Connect to /lost+found? yes -+ -+Inode 13 ref count is 2, should be 1. Fix? yes -+ -+Pass 5: Checking group summary information -+ -+test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** -+test_filesys: 13/16 files (0.0% non-contiguous), 23/100 blocks -+Exit status is 1 -diff --git a/tests/f_short_encrypted_dirent/expect.2 b/tests/f_short_encrypted_dirent/expect.2 -new file mode 100644 -index 0000000..636c6e9 ---- /dev/null -+++ b/tests/f_short_encrypted_dirent/expect.2 -@@ -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: 13/16 files (0.0% non-contiguous), 23/100 blocks -+Exit status is 0 -diff --git a/tests/f_short_encrypted_dirent/image.gz b/tests/f_short_encrypted_dirent/image.gz -new file mode 100644 -index 0000000..a35bfb2 -Binary files /dev/null and b/tests/f_short_encrypted_dirent/image.gz differ -diff --git a/tests/f_short_encrypted_dirent/name b/tests/f_short_encrypted_dirent/name -new file mode 100644 -index 0000000..a35028a ---- /dev/null -+++ b/tests/f_short_encrypted_dirent/name -@@ -0,0 +1 @@ -+short encrypted directory entry -diff --git a/tests/f_super_bad_csum/expect.1 b/tests/f_super_bad_csum/expect.1 -new file mode 100644 -index 0000000..25ced5c ---- /dev/null -+++ b/tests/f_super_bad_csum/expect.1 -@@ -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 -index 0000000..dd20919 ---- /dev/null -+++ b/tests/f_super_bad_csum/expect.2 -@@ -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 -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 -index 0000000..745562f ---- /dev/null -+++ b/tests/f_super_bad_csum/name -@@ -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 -index 0000000..cfd4189 ---- /dev/null -+++ b/tests/f_super_bad_csum/script -@@ -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 -diff --git a/tests/f_trunc_dirent_header/expect.1 b/tests/f_trunc_dirent_header/expect.1 -new file mode 100644 -index 0000000..33ce473 ---- /dev/null -+++ b/tests/f_trunc_dirent_header/expect.1 -@@ -0,0 +1,15 @@ -+Pass 1: Checking inodes, blocks, and sizes -+Pass 2: Checking directory structure -+Directory inode 15, block #0, offset 4092: directory corrupted -+Salvage? yes -+ -+Directory inode 13, block #1, offset 28: directory corrupted -+Salvage? yes -+ -+Pass 3: Checking directory connectivity -+Pass 4: Checking reference counts -+Pass 5: Checking group summary information -+ -+test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** -+test_filesys: 32/128 files (0.0% non-contiguous), 18/512 blocks -+Exit status is 1 -diff --git a/tests/f_trunc_dirent_header/expect.2 b/tests/f_trunc_dirent_header/expect.2 -new file mode 100644 -index 0000000..df81c9d ---- /dev/null -+++ b/tests/f_trunc_dirent_header/expect.2 -@@ -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: 32/128 files (0.0% non-contiguous), 18/512 blocks -+Exit status is 0 -diff --git a/tests/f_trunc_dirent_header/image.gz b/tests/f_trunc_dirent_header/image.gz -new file mode 100644 -index 0000000..9c59bf4 -Binary files /dev/null and b/tests/f_trunc_dirent_header/image.gz differ -diff --git a/tests/f_trunc_dirent_header/name b/tests/f_trunc_dirent_header/name -new file mode 100644 -index 0000000..e244dbf ---- /dev/null -+++ b/tests/f_trunc_dirent_header/name -@@ -0,0 +1 @@ -+no space for dirent header at end of buf -diff --git a/tests/f_uninit_cat/expect b/tests/f_uninit_cat/expect -new file mode 100644 -index 0000000..0c0a5cf -Binary files /dev/null and b/tests/f_uninit_cat/expect differ -diff --git a/tests/f_uninit_cat/image.gz b/tests/f_uninit_cat/image.gz -new file mode 100644 -index 0000000..d2ae66c -Binary files /dev/null and b/tests/f_uninit_cat/image.gz differ -diff --git a/tests/f_uninit_cat/name b/tests/f_uninit_cat/name -new file mode 100644 -index 0000000..f6b5674 ---- /dev/null -+++ b/tests/f_uninit_cat/name -@@ -0,0 +1 @@ -+cat a file with uninit blocks -diff --git a/tests/f_uninit_cat/script b/tests/f_uninit_cat/script -new file mode 100755 -index 0000000..1655bb0 ---- /dev/null -+++ b/tests/f_uninit_cat/script -@@ -0,0 +1,37 @@ -+#!/bin/bash -+ -+if test -x $DEBUGFS_EXE; then -+FSCK_OPT=-fy -+IMAGE=$test_dir/image.gz -+ -+gzip -d < $IMAGE > $TMPFILE -+#e2label $TMPFILE test_filesys -+ -+# Run fsck to fix things? -+EXP=$test_dir/expect -+OUT=$test_name.log -+rm -rf $test_name.failed $test_name.ok -+ -+$FSCK $FSCK_OPT -N test_filesys $TMPFILE 2>&1 | sed -f $cmd_dir/filter.sed > $OUT -+echo "Exit status is $?" >> $OUT -+ -+echo "debugfs cat uninit file" >> $OUT -+echo "ex /a" > $TMPFILE.cmd -+echo "cat /a" >> $TMPFILE.cmd -+$DEBUGFS_EXE -w -f $TMPFILE.cmd $TMPFILE >> $OUT.new 2>&1 -+echo >> $OUT.new -+sed -f $cmd_dir/filter.sed < $OUT.new >> $OUT -+rm -rf $OUT.new $TMPFILE -+ -+# Figure out what happened -+if cmp -s $EXP $OUT; then -+ echo "$test_name: $test_description: ok" -+ touch $test_name.ok -+else -+ echo "$test_name: $test_description: failed" -+ diff -u $EXP $OUT >> $test_name.failed -+fi -+unset EXP OUT FSCK_OPT IMAGE -+else #if test -a -x $DEBUGFS_EXE; then -+ echo "$test_name: $test_description: skipped" -+fi -diff --git a/tests/f_write_ea_no_extra_isize/expect.1 b/tests/f_write_ea_no_extra_isize/expect.1 -new file mode 100644 -index 0000000..b7e7438 ---- /dev/null -+++ b/tests/f_write_ea_no_extra_isize/expect.1 -@@ -0,0 +1,12 @@ -+Pass 1: Checking inodes, blocks, and sizes -+Pass 2: Checking directory structure -+Directory inode 12, block #0, offset 4: directory corrupted -+Salvage? yes -+ -+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), 17/512 blocks -+Exit status is 1 -diff --git a/tests/f_write_ea_no_extra_isize/expect.2 b/tests/f_write_ea_no_extra_isize/expect.2 -new file mode 100644 -index 0000000..3b6073e ---- /dev/null -+++ b/tests/f_write_ea_no_extra_isize/expect.2 -@@ -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), 17/512 blocks -+Exit status is 0 -diff --git a/tests/f_write_ea_no_extra_isize/image.gz b/tests/f_write_ea_no_extra_isize/image.gz -new file mode 100644 -index 0000000..928daff -Binary files /dev/null and b/tests/f_write_ea_no_extra_isize/image.gz differ -diff --git a/tests/f_write_ea_no_extra_isize/name b/tests/f_write_ea_no_extra_isize/name -new file mode 100644 -index 0000000..200e365 ---- /dev/null -+++ b/tests/f_write_ea_no_extra_isize/name -@@ -0,0 +1 @@ -+write EA when i_extra_size is zero -diff --git a/tests/f_write_ea_toobig_extra_isize/expect.1 b/tests/f_write_ea_toobig_extra_isize/expect.1 -new file mode 100644 -index 0000000..b7e7438 ---- /dev/null -+++ b/tests/f_write_ea_toobig_extra_isize/expect.1 -@@ -0,0 +1,12 @@ -+Pass 1: Checking inodes, blocks, and sizes -+Pass 2: Checking directory structure -+Directory inode 12, block #0, offset 4: directory corrupted -+Salvage? yes -+ -+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), 17/512 blocks -+Exit status is 1 -diff --git a/tests/f_write_ea_toobig_extra_isize/expect.2 b/tests/f_write_ea_toobig_extra_isize/expect.2 -new file mode 100644 -index 0000000..3b6073e ---- /dev/null -+++ b/tests/f_write_ea_toobig_extra_isize/expect.2 -@@ -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), 17/512 blocks -+Exit status is 0 -diff --git a/tests/f_write_ea_toobig_extra_isize/image.gz b/tests/f_write_ea_toobig_extra_isize/image.gz -new file mode 100644 -index 0000000..291924b -Binary files /dev/null and b/tests/f_write_ea_toobig_extra_isize/image.gz differ -diff --git a/tests/f_write_ea_toobig_extra_isize/name b/tests/f_write_ea_toobig_extra_isize/name -new file mode 100644 -index 0000000..a5ed718 ---- /dev/null -+++ b/tests/f_write_ea_toobig_extra_isize/name -@@ -0,0 +1 @@ -+write EA when i_extra_size is too big for EA -diff --git a/tests/f_write_ea_toosmall_extra_isize/expect.1 b/tests/f_write_ea_toosmall_extra_isize/expect.1 -new file mode 100644 -index 0000000..eecfc9d ---- /dev/null -+++ b/tests/f_write_ea_toosmall_extra_isize/expect.1 -@@ -0,0 +1,15 @@ -+Pass 1: Checking inodes, blocks, and sizes -+Inode 12 has a extra size (1) which is invalid -+Fix? yes -+ -+Pass 2: Checking directory structure -+Directory inode 12, block #0, offset 4: directory corrupted -+Salvage? yes -+ -+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), 17/512 blocks -+Exit status is 1 -diff --git a/tests/f_write_ea_toosmall_extra_isize/expect.2 b/tests/f_write_ea_toosmall_extra_isize/expect.2 -new file mode 100644 -index 0000000..3b6073e ---- /dev/null -+++ b/tests/f_write_ea_toosmall_extra_isize/expect.2 -@@ -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), 17/512 blocks -+Exit status is 0 -diff --git a/tests/f_write_ea_toosmall_extra_isize/image.gz b/tests/f_write_ea_toosmall_extra_isize/image.gz -new file mode 100644 -index 0000000..78a0149 -Binary files /dev/null and b/tests/f_write_ea_toosmall_extra_isize/image.gz differ -diff --git a/tests/f_write_ea_toosmall_extra_isize/name b/tests/f_write_ea_toosmall_extra_isize/name -new file mode 100644 -index 0000000..718c12c ---- /dev/null -+++ b/tests/f_write_ea_toosmall_extra_isize/name -@@ -0,0 +1 @@ -+write EA when i_extra_size is too small to make sense -diff --git a/tests/f_yes/expect b/tests/f_yes/expect -new file mode 100644 -index 0000000..c73e620 ---- /dev/null -+++ b/tests/f_yes/expect -@@ -0,0 +1,45 @@ -+Pass 1: Checking inodes, blocks, and sizes -+Inode 12 has an invalid extent -+ (logical block 0, invalid physical block 999999999, len 1) -+Clear? yes -+Inode 12 has an invalid extent -+ (logical block 1, invalid physical block 9999999999, len 1) -+Clear? yes -+Inode 13 is in use, but has dtime set. Fix? yes -+Inode 13 has an invalid extent -+ (logical block 1, invalid physical block 8888888888888, len 1) -+Clear? yes -+Inode 13 has an invalid extent -+ (logical block 0, invalid physical block 888888888888, len 1) -+Clear? yes -+Inode 14 is in use, but has dtime set. Fix? yes -+Inode 14 has an invalid extent -+ (logical block 300, invalid physical block 777777777777, len 300) -+Clear? yes -+Inode 14 has an invalid extent -+ (logical block 0, invalid physical block 7777777777, len 1) -+Clear? yes -+Inode 14, i_blocks is 52574694748113, should be 0. Fix? yes -+Pass 2: Checking directory structure -+Extended attribute block for inode 12 (/a) is invalid (999999). -+Clear ('a' enables 'yes' to all) ? yes -+Extended attribute block for inode 13 (/b) is invalid (298954296). -+Clear ('a' enables 'yes' to all) ? yes -+Extended attribute block for inode 14 (/c) is invalid (388697201). -+Clear ('a' enables 'yes' to all) ? yes -+Pass 3: Checking directory connectivity -+Pass 4: Checking reference counts -+Inode 12 ref count is 34463, should be 1. Fix ('a' enables 'yes' to all) ? yes -+Inode 13 ref count is 9999, should be 1. Fix? yes -+Inode 14 ref count is 12241, should be 1. Fix? yes -+Pass 5: Checking group summary information -+Block bitmap differences: -202 -381 -457 -+Fix? yes -+Free blocks count wrong for group #0 (0, counted=494). -+Fix? yes -+Free inodes count wrong for group #0 (4294967293, counted=114). -+Fix? yes -+ -+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_yes/script b/tests/f_yes/script -new file mode 100644 -index 0000000..4e114c5 ---- /dev/null -+++ b/tests/f_yes/script -@@ -0,0 +1,27 @@ -+test_description="e2fsck with repeated yes" -+FSCK_OPT=-f -+OUT=$test_name.log -+EXP=$test_dir/expect -+ -+gunzip < $test_dir/../f_yesall/image.gz > $TMPFILE -+ -+rm -rf $OUT -+echo "yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy" | E2FSCK_FORCE_INTERACTIVE=y $FSCK $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 -+rm -f $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 -+ rm -f tmp_expect -+fi -+ -+unset IMAGE FSCK_OPT OUT EXP -diff --git a/tests/f_yesall/expect b/tests/f_yesall/expect -new file mode 100644 -index 0000000..f6d3c2b ---- /dev/null -+++ b/tests/f_yesall/expect -@@ -0,0 +1,62 @@ -+Pass 1: Checking inodes, blocks, and sizes -+Inode 12 has an invalid extent -+ (logical block 0, invalid physical block 999999999, len 1) -+Clear? yes to all -+Inode 12 has an invalid extent -+ (logical block 1, invalid physical block 9999999999, len 1) -+Clear? yes -+ -+Inode 13 is in use, but has dtime set. Fix? yes -+ -+Inode 13 has an invalid extent -+ (logical block 1, invalid physical block 8888888888888, len 1) -+Clear? yes -+ -+Inode 13 has an invalid extent -+ (logical block 0, invalid physical block 888888888888, len 1) -+Clear? yes -+ -+Inode 14 is in use, but has dtime set. Fix? yes -+ -+Inode 14 has an invalid extent -+ (logical block 300, invalid physical block 777777777777, len 300) -+Clear? yes -+ -+Inode 14 has an invalid extent -+ (logical block 0, invalid physical block 7777777777, len 1) -+Clear? yes -+ -+Inode 14, i_blocks is 52574694748113, should be 0. Fix? yes -+ -+Pass 2: Checking directory structure -+Extended attribute block for inode 12 (/a) is invalid (999999). -+Clear? yes -+ -+Extended attribute block for inode 13 (/b) is invalid (298954296). -+Clear? yes -+ -+Extended attribute block for inode 14 (/c) is invalid (388697201). -+Clear? yes -+ -+Pass 3: Checking directory connectivity -+Pass 4: Checking reference counts -+Inode 12 ref count is 34463, should be 1. Fix? yes -+ -+Inode 13 ref count is 9999, should be 1. Fix? yes -+ -+Inode 14 ref count is 12241, should be 1. Fix? yes -+ -+Pass 5: Checking group summary information -+Block bitmap differences: -202 -381 -457 -+Fix? yes -+ -+Free blocks count wrong for group #0 (0, counted=494). -+Fix? yes -+ -+Free inodes count wrong for group #0 (4294967293, counted=114). -+Fix? yes -+ -+ -+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_yesall/image.gz b/tests/f_yesall/image.gz -new file mode 100644 -index 0000000..0f8b205 -Binary files /dev/null and b/tests/f_yesall/image.gz differ -diff --git a/tests/f_yesall/script b/tests/f_yesall/script -new file mode 100644 -index 0000000..c3721ff ---- /dev/null -+++ b/tests/f_yesall/script -@@ -0,0 +1,27 @@ -+test_description="e2fsck with yes-to-all" -+FSCK_OPT=-f -+OUT=$test_name.log -+EXP=$test_dir/expect -+ -+gunzip < $test_dir/image.gz > $TMPFILE -+ -+rm -rf $OUT -+echo "annnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn" | E2FSCK_FORCE_INTERACTIVE=y $FSCK $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 -+rm -f $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 -+ rm -f tmp_expect -+fi -+ -+unset IMAGE FSCK_OPT OUT EXP -diff --git a/tests/f_yesthenall/expect b/tests/f_yesthenall/expect -new file mode 100644 -index 0000000..1fc3bde ---- /dev/null -+++ b/tests/f_yesthenall/expect -@@ -0,0 +1,52 @@ -+Pass 1: Checking inodes, blocks, and sizes -+Inode 12 has an invalid extent -+ (logical block 0, invalid physical block 999999999, len 1) -+Clear? yes -+Inode 12 has an invalid extent -+ (logical block 1, invalid physical block 9999999999, len 1) -+Clear? yes -+Inode 13 is in use, but has dtime set. Fix? yes -+Inode 13 has an invalid extent -+ (logical block 1, invalid physical block 8888888888888, len 1) -+Clear? yes -+Inode 13 has an invalid extent -+ (logical block 0, invalid physical block 888888888888, len 1) -+Clear? yes -+Inode 14 is in use, but has dtime set. Fix? yes -+Inode 14 has an invalid extent -+ (logical block 300, invalid physical block 777777777777, len 300) -+Clear? yes -+Inode 14 has an invalid extent -+ (logical block 0, invalid physical block 7777777777, len 1) -+Clear? yes -+Inode 14, i_blocks is 52574694748113, should be 0. Fix? yes -+Pass 2: Checking directory structure -+Extended attribute block for inode 12 (/a) is invalid (999999). -+Clear ('a' enables 'yes' to all) ? yes -+Extended attribute block for inode 13 (/b) is invalid (298954296). -+Clear ('a' enables 'yes' to all) ? yes to all -+Extended attribute block for inode 14 (/c) is invalid (388697201). -+Clear? yes -+ -+Pass 3: Checking directory connectivity -+Pass 4: Checking reference counts -+Inode 12 ref count is 34463, should be 1. Fix? yes -+ -+Inode 13 ref count is 9999, should be 1. Fix? yes -+ -+Inode 14 ref count is 12241, should be 1. Fix? yes -+ -+Pass 5: Checking group summary information -+Block bitmap differences: -202 -381 -457 -+Fix? yes -+ -+Free blocks count wrong for group #0 (0, counted=494). -+Fix? yes -+ -+Free inodes count wrong for group #0 (4294967293, counted=114). -+Fix? yes -+ -+ -+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_yesthenall/script b/tests/f_yesthenall/script -new file mode 100644 -index 0000000..eb11c23 ---- /dev/null -+++ b/tests/f_yesthenall/script -@@ -0,0 +1,27 @@ -+test_description="e2fsck with yes then yes-to-all" -+FSCK_OPT=-f -+OUT=$test_name.log -+EXP=$test_dir/expect -+ -+gunzip < $test_dir/../f_yesall/image.gz > $TMPFILE -+ -+rm -rf $OUT -+echo "yyyyyyyyyyannnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn" | E2FSCK_FORCE_INTERACTIVE=y $FSCK $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 -+rm -f $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 -+ rm -f tmp_expect -+fi -+ -+unset IMAGE FSCK_OPT OUT EXP -diff --git a/tests/f_yesthenno/expect b/tests/f_yesthenno/expect -new file mode 100644 -index 0000000..de55f47 ---- /dev/null -+++ b/tests/f_yesthenno/expect -@@ -0,0 +1,50 @@ -+Pass 1: Checking inodes, blocks, and sizes -+Inode 12 has an invalid extent -+ (logical block 0, invalid physical block 999999999, len 1) -+Clear? yes -+Inode 12 has an invalid extent -+ (logical block 1, invalid physical block 9999999999, len 1) -+Clear? yes -+Inode 13 is in use, but has dtime set. Fix? yes -+Inode 13 has an invalid extent -+ (logical block 1, invalid physical block 8888888888888, len 1) -+Clear? yes -+Inode 13 has an invalid extent -+ (logical block 0, invalid physical block 888888888888, len 1) -+Clear? yes -+Inode 14 is in use, but has dtime set. Fix? yes -+Inode 14 has an invalid extent -+ (logical block 300, invalid physical block 777777777777, len 300) -+Clear? yes -+Inode 14 has an invalid extent -+ (logical block 0, invalid physical block 7777777777, len 1) -+Clear? yes -+Inode 14, i_blocks is 52574694748113, should be 0. Fix? yes -+Pass 2: Checking directory structure -+Extended attribute block for inode 12 (/a) is invalid (999999). -+Clear ('a' enables 'yes' to all) ? yes -+Extended attribute block for inode 13 (/b) is invalid (298954296). -+Clear ('a' enables 'yes' to all) ? no -+Extended attribute block for inode 14 (/c) is invalid (388697201). -+Clear? no -+Pass 3: Checking directory connectivity -+Pass 4: Checking reference counts -+Inode 12 ref count is 34463, should be 1. Fix? no -+Inode 13 ref count is 9999, should be 1. Fix? no -+Inode 14 ref count is 12241, should be 1. Fix? no -+Pass 5: Checking group summary information -+Block bitmap differences: -202 -381 -457 -+Fix? no -+Free blocks count wrong for group #0 (0, counted=491). -+Fix? no -+Free blocks count wrong (494, counted=491). -+Fix? no -+Free inodes count wrong for group #0 (4294967293, counted=114). -+Fix? no -+ -+test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** -+ -+test_filesys: ********** WARNING: Filesystem still has errors ********** -+ -+test_filesys: 14/128 files (0.0% non-contiguous), 18/512 blocks -+Exit status is 4 -diff --git a/tests/f_yesthenno/script b/tests/f_yesthenno/script -new file mode 100644 -index 0000000..f41b78b ---- /dev/null -+++ b/tests/f_yesthenno/script -@@ -0,0 +1,27 @@ -+test_description="e2fsck with yes then no" -+FSCK_OPT=-f -+OUT=$test_name.log -+EXP=$test_dir/expect -+ -+gunzip < $test_dir/../f_yesall/image.gz > $TMPFILE -+ -+rm -rf $OUT -+echo "yyyyyyyyyynnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn" | E2FSCK_FORCE_INTERACTIVE=y $FSCK $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 -+rm -f $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 -+ rm -f tmp_expect -+fi -+ -+unset IMAGE FSCK_OPT OUT EXP -diff --git a/tests/filter.sed b/tests/filter.sed -index 91b956b..4a630bf 100644 ---- a/tests/filter.sed -+++ b/tests/filter.sed -@@ -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 -@@ -13,7 +18,11 @@ s/\\015//g - /^Lifetime writes:/d - /^Maximum mount count:/d - /^Next check after:/d -+/^Suggestion:/d - /Reserved blocks uid:/s/ (user .*)// - /Reserved blocks gid:/s/ (group .*)// - /whichever comes first/d - /^ Checksum /d -+s/, csum 0x\([0-9a-f]*\)//g -+s/ csum 0x\([0-9a-f]*\)//g -+/^Checksum:/d -diff --git a/tests/j_corrupt_commit_csum/expect b/tests/j_corrupt_commit_csum/expect -new file mode 100644 -index 0000000..d799772 ---- /dev/null -+++ b/tests/j_corrupt_commit_csum/expect -@@ -0,0 +1,18 @@ -+test_filesys: recovering journal -+Journal transaction 3 was corrupt, replay was aborted. -+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), 1092/2048 blocks -+Exit status is 0 -+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), 1092/2048 blocks -+Exit status is 0 -+debugfs: cat /a -+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadebugfs: -diff --git a/tests/j_corrupt_commit_csum/image.gz b/tests/j_corrupt_commit_csum/image.gz -new file mode 100644 -index 0000000..334fcd0 -Binary files /dev/null and b/tests/j_corrupt_commit_csum/image.gz differ -diff --git a/tests/j_corrupt_commit_csum/name b/tests/j_corrupt_commit_csum/name -new file mode 100644 -index 0000000..05a99ea ---- /dev/null -+++ b/tests/j_corrupt_commit_csum/name -@@ -0,0 +1 @@ -+corrupt commit csum (csum v3) -diff --git a/tests/j_corrupt_commit_csum/script b/tests/j_corrupt_commit_csum/script -new file mode 100644 -index 0000000..9c16975 ---- /dev/null -+++ b/tests/j_corrupt_commit_csum/script -@@ -0,0 +1,52 @@ -+if test -x $DEBUGFS_EXE; then -+ -+IMAGE=$test_dir/image.gz -+FSCK_OPT=-fy -+OUT=$test_name.log -+if [ -f $test_dir/expect.gz ]; then -+ EXP=$test_name.tmp -+ gunzip < $test_dir/expect.gz > $EXP1 -+else -+ EXP=$test_dir/expect -+fi -+ -+cp /dev/null $OUT -+ -+gzip -d < $IMAGE > $TMPFILE -+ -+$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 -+status=$? -+echo Exit status is $status >> $OUT.new -+sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT -+rm -f $OUT.new -+ -+$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 -+status=$? -+echo Exit status is $status >> $OUT.new -+sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT -+rm -f $OUT.new -+ -+echo "cat /a" > $TMPFILE.cmd -+echo >> $TMPFILE.cmd -+$DEBUGFS_EXE -f $TMPFILE.cmd $TMPFILE 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT -+rm -f $TMPFILE.cmd -+ -+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 IMAGE FSCK_OPT OUT EXP -+ -+else #if test -x $DEBUGFS_EXE; then -+ echo "$test_name: $test_description: skipped" -+fi -diff --git a/tests/j_corrupt_commit_tid/expect b/tests/j_corrupt_commit_tid/expect -new file mode 100644 -index 0000000..0a7df89 ---- /dev/null -+++ b/tests/j_corrupt_commit_tid/expect -@@ -0,0 +1,17 @@ -+test_filesys: recovering journal -+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), 1092/2048 blocks -+Exit status is 0 -+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), 1092/2048 blocks -+Exit status is 0 -+debugfs: cat /a -+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadebugfs: -diff --git a/tests/j_corrupt_commit_tid/image.gz b/tests/j_corrupt_commit_tid/image.gz -new file mode 100644 -index 0000000..988e5c6 -Binary files /dev/null and b/tests/j_corrupt_commit_tid/image.gz differ -diff --git a/tests/j_corrupt_commit_tid/name b/tests/j_corrupt_commit_tid/name -new file mode 100644 -index 0000000..9b4054c ---- /dev/null -+++ b/tests/j_corrupt_commit_tid/name -@@ -0,0 +1 @@ -+corrupt commit tid (csum v3) -diff --git a/tests/j_corrupt_commit_tid/script b/tests/j_corrupt_commit_tid/script -new file mode 100644 -index 0000000..9c16975 ---- /dev/null -+++ b/tests/j_corrupt_commit_tid/script -@@ -0,0 +1,52 @@ -+if test -x $DEBUGFS_EXE; then -+ -+IMAGE=$test_dir/image.gz -+FSCK_OPT=-fy -+OUT=$test_name.log -+if [ -f $test_dir/expect.gz ]; then -+ EXP=$test_name.tmp -+ gunzip < $test_dir/expect.gz > $EXP1 -+else -+ EXP=$test_dir/expect -+fi -+ -+cp /dev/null $OUT -+ -+gzip -d < $IMAGE > $TMPFILE -+ -+$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 -+status=$? -+echo Exit status is $status >> $OUT.new -+sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT -+rm -f $OUT.new -+ -+$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 -+status=$? -+echo Exit status is $status >> $OUT.new -+sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT -+rm -f $OUT.new -+ -+echo "cat /a" > $TMPFILE.cmd -+echo >> $TMPFILE.cmd -+$DEBUGFS_EXE -f $TMPFILE.cmd $TMPFILE 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT -+rm -f $TMPFILE.cmd -+ -+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 IMAGE FSCK_OPT OUT EXP -+ -+else #if test -x $DEBUGFS_EXE; then -+ echo "$test_name: $test_description: skipped" -+fi -diff --git a/tests/j_corrupt_descr_csum/expect b/tests/j_corrupt_descr_csum/expect -new file mode 100644 -index 0000000..4e5ec6a ---- /dev/null -+++ b/tests/j_corrupt_descr_csum/expect -@@ -0,0 +1,18 @@ -+test_filesys: recovering journal -+../e2fsck/e2fsck: Input/output error while recovering ext3 journal of test_filesys -+ -+test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** -+ -+test_filesys: ********** WARNING: Filesystem still has errors ********** -+ -+Exit status is 12 -+test_filesys: recovering journal -+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), 1093/2048 blocks -+Exit status is 0 -+debugfs: cat /a -+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadebugfs: -diff --git a/tests/j_corrupt_descr_csum/image.gz b/tests/j_corrupt_descr_csum/image.gz -new file mode 100644 -index 0000000..2a81e5d -Binary files /dev/null and b/tests/j_corrupt_descr_csum/image.gz differ -diff --git a/tests/j_corrupt_descr_csum/name b/tests/j_corrupt_descr_csum/name -new file mode 100644 -index 0000000..e15ccfb ---- /dev/null -+++ b/tests/j_corrupt_descr_csum/name -@@ -0,0 +1 @@ -+corrupt descr csum (csum v3) -diff --git a/tests/j_corrupt_descr_csum/script b/tests/j_corrupt_descr_csum/script -new file mode 100644 -index 0000000..9c16975 ---- /dev/null -+++ b/tests/j_corrupt_descr_csum/script -@@ -0,0 +1,52 @@ -+if test -x $DEBUGFS_EXE; then -+ -+IMAGE=$test_dir/image.gz -+FSCK_OPT=-fy -+OUT=$test_name.log -+if [ -f $test_dir/expect.gz ]; then -+ EXP=$test_name.tmp -+ gunzip < $test_dir/expect.gz > $EXP1 -+else -+ EXP=$test_dir/expect -+fi -+ -+cp /dev/null $OUT -+ -+gzip -d < $IMAGE > $TMPFILE -+ -+$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 -+status=$? -+echo Exit status is $status >> $OUT.new -+sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT -+rm -f $OUT.new -+ -+$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 -+status=$? -+echo Exit status is $status >> $OUT.new -+sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT -+rm -f $OUT.new -+ -+echo "cat /a" > $TMPFILE.cmd -+echo >> $TMPFILE.cmd -+$DEBUGFS_EXE -f $TMPFILE.cmd $TMPFILE 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT -+rm -f $TMPFILE.cmd -+ -+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 IMAGE FSCK_OPT OUT EXP -+ -+else #if test -x $DEBUGFS_EXE; then -+ echo "$test_name: $test_description: skipped" -+fi -diff --git a/tests/j_corrupt_descr_tid/expect b/tests/j_corrupt_descr_tid/expect -new file mode 100644 -index 0000000..00bd2d5 ---- /dev/null -+++ b/tests/j_corrupt_descr_tid/expect -@@ -0,0 +1,17 @@ -+test_filesys: recovering journal -+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), 1093/2048 blocks -+Exit status is 0 -+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), 1093/2048 blocks -+Exit status is 0 -+debugfs: cat /a -+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadebugfs: -diff --git a/tests/j_corrupt_descr_tid/image.gz b/tests/j_corrupt_descr_tid/image.gz -new file mode 100644 -index 0000000..3ad88f9 -Binary files /dev/null and b/tests/j_corrupt_descr_tid/image.gz differ -diff --git a/tests/j_corrupt_descr_tid/name b/tests/j_corrupt_descr_tid/name -new file mode 100644 -index 0000000..2325d6d ---- /dev/null -+++ b/tests/j_corrupt_descr_tid/name -@@ -0,0 +1 @@ -+corrupt descr tid (csum v3) -diff --git a/tests/j_corrupt_descr_tid/script b/tests/j_corrupt_descr_tid/script -new file mode 100644 -index 0000000..9c16975 ---- /dev/null -+++ b/tests/j_corrupt_descr_tid/script -@@ -0,0 +1,52 @@ -+if test -x $DEBUGFS_EXE; then -+ -+IMAGE=$test_dir/image.gz -+FSCK_OPT=-fy -+OUT=$test_name.log -+if [ -f $test_dir/expect.gz ]; then -+ EXP=$test_name.tmp -+ gunzip < $test_dir/expect.gz > $EXP1 -+else -+ EXP=$test_dir/expect -+fi -+ -+cp /dev/null $OUT -+ -+gzip -d < $IMAGE > $TMPFILE -+ -+$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 -+status=$? -+echo Exit status is $status >> $OUT.new -+sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT -+rm -f $OUT.new -+ -+$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 -+status=$? -+echo Exit status is $status >> $OUT.new -+sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT -+rm -f $OUT.new -+ -+echo "cat /a" > $TMPFILE.cmd -+echo >> $TMPFILE.cmd -+$DEBUGFS_EXE -f $TMPFILE.cmd $TMPFILE 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT -+rm -f $TMPFILE.cmd -+ -+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 IMAGE FSCK_OPT OUT EXP -+ -+else #if test -x $DEBUGFS_EXE; then -+ echo "$test_name: $test_description: skipped" -+fi -diff --git a/tests/j_corrupt_ext_jnl_sb_block/expect b/tests/j_corrupt_ext_jnl_sb_block/expect -new file mode 100644 -index 0000000..e638e11 ---- /dev/null -+++ b/tests/j_corrupt_ext_jnl_sb_block/expect -@@ -0,0 +1,5 @@ -+External journal does not support this filesystem -+ -+test_filesys: ********** WARNING: Filesystem still has errors ********** -+ -+Exit status is 12 -diff --git a/tests/j_corrupt_ext_jnl_sb_block/image.tar.bz2 b/tests/j_corrupt_ext_jnl_sb_block/image.tar.bz2 -new file mode 100644 -index 0000000..efb382f -Binary files /dev/null and b/tests/j_corrupt_ext_jnl_sb_block/image.tar.bz2 differ -diff --git a/tests/j_corrupt_ext_jnl_sb_block/name b/tests/j_corrupt_ext_jnl_sb_block/name -new file mode 100644 -index 0000000..a5188be ---- /dev/null -+++ b/tests/j_corrupt_ext_jnl_sb_block/name -@@ -0,0 +1 @@ -+corrupt external journal fs superblock block (metadata_csum) -diff --git a/tests/j_corrupt_ext_jnl_sb_block/script b/tests/j_corrupt_ext_jnl_sb_block/script -new file mode 100644 -index 0000000..02b8e65 ---- /dev/null -+++ b/tests/j_corrupt_ext_jnl_sb_block/script -@@ -0,0 +1,36 @@ -+FSCK_OPT=-fy -+OUT=$test_name.log -+if [ -f $test_dir/expect.gz ]; then -+ EXP=$test_name.tmp -+ gunzip < $test_dir/expect.gz > $EXP1 -+else -+ EXP=$test_dir/expect -+fi -+ -+cp /dev/null $OUT -+ -+bzip2 -dc < $test_dir/image.tar.bz2 | tar x -+test -d "$JOURNAL_DUMP_DIR" -a -w "$JOURNAL_DUMP_DIR" && cp $test_name.img "$JOURNAL_DUMP_DIR/$test_name.img" -+test -d "$JOURNAL_DUMP_DIR" -a -w "$JOURNAL_DUMP_DIR" && cp $test_name.img.jnl "$JOURNAL_DUMP_DIR/$test_name.img.jnl" -+ -+$FSCK $FSCK_OPT -N test_filesys -j $test_name.img.jnl $test_name.img > $OUT.new 2>&1 -+status=$? -+echo Exit status is $status >> $OUT.new -+sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT -+rm -f $OUT.new -+ -+rm -f $TMPFILE $test_name.img $test_name.img.jnl -+ -+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 IMAGE FSCK_OPT OUT EXP -diff --git a/tests/j_corrupt_ext_jnl_sb_csum/expect b/tests/j_corrupt_ext_jnl_sb_csum/expect -new file mode 100644 -index 0000000..70a4fe7 ---- /dev/null -+++ b/tests/j_corrupt_ext_jnl_sb_csum/expect -@@ -0,0 +1,25 @@ -+External journal superblock checksum does not match superblock. Fix? yes -+ -+test_filesys: recovering journal -+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: +(1--31) +34 +(50--82) -+Fix? yes -+ -+Inode bitmap differences: +(1--11) -+Fix? yes -+ -+ -+test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** -+test_filesys: 11/128 files (0.0% non-contiguous), 66/2048 blocks -+Exit status is 1 -+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), 66/2048 blocks -+Exit status is 0 -diff --git a/tests/j_corrupt_ext_jnl_sb_csum/image.tar.bz2 b/tests/j_corrupt_ext_jnl_sb_csum/image.tar.bz2 -new file mode 100644 -index 0000000..d04d584 -Binary files /dev/null and b/tests/j_corrupt_ext_jnl_sb_csum/image.tar.bz2 differ -diff --git a/tests/j_corrupt_ext_jnl_sb_csum/name b/tests/j_corrupt_ext_jnl_sb_csum/name -new file mode 100644 -index 0000000..c182f81 ---- /dev/null -+++ b/tests/j_corrupt_ext_jnl_sb_csum/name -@@ -0,0 +1 @@ -+corrupt external journal fs superblock csum (metadata_csum) -diff --git a/tests/j_corrupt_ext_jnl_sb_csum/script b/tests/j_corrupt_ext_jnl_sb_csum/script -new file mode 100644 -index 0000000..7a110bf ---- /dev/null -+++ b/tests/j_corrupt_ext_jnl_sb_csum/script -@@ -0,0 +1,42 @@ -+FSCK_OPT=-fy -+OUT=$test_name.log -+if [ -f $test_dir/expect.gz ]; then -+ EXP=$test_name.tmp -+ gunzip < $test_dir/expect.gz > $EXP1 -+else -+ EXP=$test_dir/expect -+fi -+ -+cp /dev/null $OUT -+ -+bzip2 -dc < $test_dir/image.tar.bz2 | tar x -+test -d "$JOURNAL_DUMP_DIR" -a -w "$JOURNAL_DUMP_DIR" && cp $test_name.img "$JOURNAL_DUMP_DIR/$test_name.img" -+test -d "$JOURNAL_DUMP_DIR" -a -w "$JOURNAL_DUMP_DIR" && cp $test_name.img.jnl "$JOURNAL_DUMP_DIR/$test_name.img.jnl" -+ -+$FSCK $FSCK_OPT -N test_filesys -j $test_name.img.jnl $test_name.img > $OUT.new 2>&1 -+status=$? -+echo Exit status is $status >> $OUT.new -+sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT -+rm -f $OUT.new -+ -+$FSCK $FSCK_OPT -N test_filesys -j $test_name.img.jnl $test_name.img > $OUT.new 2>&1 -+status=$? -+echo Exit status is $status >> $OUT.new -+sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT -+rm -f $OUT.new -+ -+rm -f $TMPFILE $test_name.img $test_name.img.jnl -+ -+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 IMAGE FSCK_OPT OUT EXP -diff --git a/tests/j_corrupt_journal_block/expect b/tests/j_corrupt_journal_block/expect -new file mode 100644 -index 0000000..bc75707 ---- /dev/null -+++ b/tests/j_corrupt_journal_block/expect -@@ -0,0 +1,20 @@ -+test_filesys: recovering journal -+JBD2: Invalid checksum recovering block 1090 in log -+../e2fsck/e2fsck: Input/output error while recovering ext3 journal of test_filesys -+ -+test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** -+ -+test_filesys: ********** WARNING: Filesystem still has errors ********** -+ -+Exit status is 12 -+test_filesys: recovering journal -+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), 1093/2048 blocks -+Exit status is 0 -+debugfs: cat /a -+bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccdddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddebugfs: -+ -diff --git a/tests/j_corrupt_journal_block/image.gz b/tests/j_corrupt_journal_block/image.gz -new file mode 100644 -index 0000000..6ab196e -Binary files /dev/null and b/tests/j_corrupt_journal_block/image.gz differ -diff --git a/tests/j_corrupt_journal_block/name b/tests/j_corrupt_journal_block/name -new file mode 100644 -index 0000000..5d862cd ---- /dev/null -+++ b/tests/j_corrupt_journal_block/name -@@ -0,0 +1 @@ -+corrupt journal block (csum v3) -diff --git a/tests/j_corrupt_journal_block/script b/tests/j_corrupt_journal_block/script -new file mode 100644 -index 0000000..2bce973 ---- /dev/null -+++ b/tests/j_corrupt_journal_block/script -@@ -0,0 +1,53 @@ -+if test -x $DEBUGFS_EXE; then -+ -+IMAGE=$test_dir/image.gz -+FSCK_OPT=-fy -+OUT=$test_name.log -+if [ -f $test_dir/expect.gz ]; then -+ EXP=$test_name.tmp -+ gunzip < $test_dir/expect.gz > $EXP1 -+else -+ EXP=$test_dir/expect -+fi -+ -+cp /dev/null $OUT -+ -+gzip -d < $IMAGE > $TMPFILE -+ -+$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 -+status=$? -+echo Exit status is $status >> $OUT.new -+sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT -+rm -f $OUT.new -+ -+$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 -+status=$? -+echo Exit status is $status >> $OUT.new -+sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT -+rm -f $OUT.new -+ -+echo "cat /a" > $TMPFILE.cmd -+echo >> $TMPFILE.cmd -+$DEBUGFS_EXE -f $TMPFILE.cmd $TMPFILE 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT -+echo >> $OUT -+rm -f $TMPFILE.cmd -+ -+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 IMAGE FSCK_OPT OUT EXP -+ -+else #if test -x $DEBUGFS_EXE; then -+ echo "$test_name: $test_description: skipped" -+fi -diff --git a/tests/j_corrupt_revoke_block/expect b/tests/j_corrupt_revoke_block/expect -new file mode 100644 -index 0000000..c357f53 ---- /dev/null -+++ b/tests/j_corrupt_revoke_block/expect -@@ -0,0 +1,17 @@ -+test_filesys: recovering journal -+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), 1092/2048 blocks -+Exit status is 0 -+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), 1092/2048 blocks -+Exit status is 0 -+debugfs: cat /a -+bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbdebugfs: -diff --git a/tests/j_corrupt_revoke_block/image.gz b/tests/j_corrupt_revoke_block/image.gz -new file mode 100644 -index 0000000..b165d00 -Binary files /dev/null and b/tests/j_corrupt_revoke_block/image.gz differ -diff --git a/tests/j_corrupt_revoke_block/name b/tests/j_corrupt_revoke_block/name -new file mode 100644 -index 0000000..c7a0088 ---- /dev/null -+++ b/tests/j_corrupt_revoke_block/name -@@ -0,0 +1 @@ -+corrupt revoke block (csum v3) -diff --git a/tests/j_corrupt_revoke_block/script b/tests/j_corrupt_revoke_block/script -new file mode 100644 -index 0000000..9c16975 ---- /dev/null -+++ b/tests/j_corrupt_revoke_block/script -@@ -0,0 +1,52 @@ -+if test -x $DEBUGFS_EXE; then -+ -+IMAGE=$test_dir/image.gz -+FSCK_OPT=-fy -+OUT=$test_name.log -+if [ -f $test_dir/expect.gz ]; then -+ EXP=$test_name.tmp -+ gunzip < $test_dir/expect.gz > $EXP1 -+else -+ EXP=$test_dir/expect -+fi -+ -+cp /dev/null $OUT -+ -+gzip -d < $IMAGE > $TMPFILE -+ -+$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 -+status=$? -+echo Exit status is $status >> $OUT.new -+sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT -+rm -f $OUT.new -+ -+$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 -+status=$? -+echo Exit status is $status >> $OUT.new -+sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT -+rm -f $OUT.new -+ -+echo "cat /a" > $TMPFILE.cmd -+echo >> $TMPFILE.cmd -+$DEBUGFS_EXE -f $TMPFILE.cmd $TMPFILE 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT -+rm -f $TMPFILE.cmd -+ -+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 IMAGE FSCK_OPT OUT EXP -+ -+else #if test -x $DEBUGFS_EXE; then -+ echo "$test_name: $test_description: skipped" -+fi -diff --git a/tests/j_corrupt_revoke_csum/expect b/tests/j_corrupt_revoke_csum/expect -new file mode 100644 -index 0000000..c357f53 ---- /dev/null -+++ b/tests/j_corrupt_revoke_csum/expect -@@ -0,0 +1,17 @@ -+test_filesys: recovering journal -+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), 1092/2048 blocks -+Exit status is 0 -+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), 1092/2048 blocks -+Exit status is 0 -+debugfs: cat /a -+bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbdebugfs: -diff --git a/tests/j_corrupt_revoke_csum/image.gz b/tests/j_corrupt_revoke_csum/image.gz -new file mode 100644 -index 0000000..f505592 -Binary files /dev/null and b/tests/j_corrupt_revoke_csum/image.gz differ -diff --git a/tests/j_corrupt_revoke_csum/name b/tests/j_corrupt_revoke_csum/name -new file mode 100644 -index 0000000..b63ea23 ---- /dev/null -+++ b/tests/j_corrupt_revoke_csum/name -@@ -0,0 +1 @@ -+corrupt revoke csum (csum v3) -diff --git a/tests/j_corrupt_revoke_csum/script b/tests/j_corrupt_revoke_csum/script -new file mode 100644 -index 0000000..9c16975 ---- /dev/null -+++ b/tests/j_corrupt_revoke_csum/script -@@ -0,0 +1,52 @@ -+if test -x $DEBUGFS_EXE; then -+ -+IMAGE=$test_dir/image.gz -+FSCK_OPT=-fy -+OUT=$test_name.log -+if [ -f $test_dir/expect.gz ]; then -+ EXP=$test_name.tmp -+ gunzip < $test_dir/expect.gz > $EXP1 -+else -+ EXP=$test_dir/expect -+fi -+ -+cp /dev/null $OUT -+ -+gzip -d < $IMAGE > $TMPFILE -+ -+$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 -+status=$? -+echo Exit status is $status >> $OUT.new -+sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT -+rm -f $OUT.new -+ -+$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 -+status=$? -+echo Exit status is $status >> $OUT.new -+sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT -+rm -f $OUT.new -+ -+echo "cat /a" > $TMPFILE.cmd -+echo >> $TMPFILE.cmd -+$DEBUGFS_EXE -f $TMPFILE.cmd $TMPFILE 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT -+rm -f $TMPFILE.cmd -+ -+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 IMAGE FSCK_OPT OUT EXP -+ -+else #if test -x $DEBUGFS_EXE; then -+ echo "$test_name: $test_description: skipped" -+fi -diff --git a/tests/j_corrupt_revoke_rcount/expect.1 b/tests/j_corrupt_revoke_rcount/expect.1 -new file mode 100644 -index 0000000..97324f3 ---- /dev/null -+++ b/tests/j_corrupt_revoke_rcount/expect.1 -@@ -0,0 +1,8 @@ -+test_filesys: recovering journal -+../e2fsck/e2fsck: Invalid argument while recovering ext3 journal of test_filesys -+ -+test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** -+ -+test_filesys: ********** WARNING: Filesystem still has errors ********** -+ -+Exit status is 12 -diff --git a/tests/j_corrupt_revoke_rcount/expect.2 b/tests/j_corrupt_revoke_rcount/expect.2 -new file mode 100644 -index 0000000..c569901 ---- /dev/null -+++ b/tests/j_corrupt_revoke_rcount/expect.2 -@@ -0,0 +1,8 @@ -+test_filesys: recovering journal -+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/512 files (9.1% non-contiguous), 1066/2048 blocks -+Exit status is 0 -diff --git a/tests/j_corrupt_revoke_rcount/image.gz b/tests/j_corrupt_revoke_rcount/image.gz -new file mode 100644 -index 0000000..c8b19e8 -Binary files /dev/null and b/tests/j_corrupt_revoke_rcount/image.gz differ -diff --git a/tests/j_corrupt_revoke_rcount/name b/tests/j_corrupt_revoke_rcount/name -new file mode 100644 -index 0000000..92b523e ---- /dev/null -+++ b/tests/j_corrupt_revoke_rcount/name -@@ -0,0 +1 @@ -+corrupt revoke r_count buffer overflow -diff --git a/tests/j_corrupt_sb_csum/expect b/tests/j_corrupt_sb_csum/expect -new file mode 100644 -index 0000000..5c88a09 ---- /dev/null -+++ b/tests/j_corrupt_sb_csum/expect -@@ -0,0 +1,21 @@ -+Journal superblock is corrupt. -+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: ***** FILE SYSTEM WAS MODIFIED ***** -+test_filesys: 12/128 files (8.3% non-contiguous), 1092/2048 blocks -+Exit status is 1 -+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), 1092/2048 blocks -+Exit status is 0 -+debugfs: cat /a -+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadebugfs: -diff --git a/tests/j_corrupt_sb_csum/image.gz b/tests/j_corrupt_sb_csum/image.gz -new file mode 100644 -index 0000000..ee92f6b -Binary files /dev/null and b/tests/j_corrupt_sb_csum/image.gz differ -diff --git a/tests/j_corrupt_sb_csum/name b/tests/j_corrupt_sb_csum/name -new file mode 100644 -index 0000000..921a0fd ---- /dev/null -+++ b/tests/j_corrupt_sb_csum/name -@@ -0,0 +1 @@ -+corrupt sb csum (csum v3) -diff --git a/tests/j_corrupt_sb_csum/script b/tests/j_corrupt_sb_csum/script -new file mode 100644 -index 0000000..9c16975 ---- /dev/null -+++ b/tests/j_corrupt_sb_csum/script -@@ -0,0 +1,52 @@ -+if test -x $DEBUGFS_EXE; then -+ -+IMAGE=$test_dir/image.gz -+FSCK_OPT=-fy -+OUT=$test_name.log -+if [ -f $test_dir/expect.gz ]; then -+ EXP=$test_name.tmp -+ gunzip < $test_dir/expect.gz > $EXP1 -+else -+ EXP=$test_dir/expect -+fi -+ -+cp /dev/null $OUT -+ -+gzip -d < $IMAGE > $TMPFILE -+ -+$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 -+status=$? -+echo Exit status is $status >> $OUT.new -+sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT -+rm -f $OUT.new -+ -+$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 -+status=$? -+echo Exit status is $status >> $OUT.new -+sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT -+rm -f $OUT.new -+ -+echo "cat /a" > $TMPFILE.cmd -+echo >> $TMPFILE.cmd -+$DEBUGFS_EXE -f $TMPFILE.cmd $TMPFILE 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT -+rm -f $TMPFILE.cmd -+ -+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 IMAGE FSCK_OPT OUT EXP -+ -+else #if test -x $DEBUGFS_EXE; then -+ echo "$test_name: $test_description: skipped" -+fi -diff --git a/tests/j_corrupt_sb_magic/expect b/tests/j_corrupt_sb_magic/expect -new file mode 100644 -index 0000000..d1dae88 ---- /dev/null -+++ b/tests/j_corrupt_sb_magic/expect -@@ -0,0 +1,42 @@ -+Superblock has an invalid journal (inode 8). -+Clear? yes -+ -+*** journal has been deleted *** -+ -+Superblock has_journal flag is clear, but a journal is present. -+Clear? yes -+ -+Pass 1: Checking inodes, blocks, and sizes -+Journal inode is not in use, but contains data. Clear? 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: -(32--33) -(35--49) -(83--1089) -+Fix? yes -+ -+Free blocks count wrong for group #0 (956, counted=1980). -+Fix? yes -+ -+Free blocks count wrong (956, counted=1980). -+Fix? yes -+ -+Recreate journal? yes -+ -+Creating journal (1024 blocks): Done. -+ -+*** journal has been regenerated *** -+ -+test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** -+test_filesys: 12/128 files (0.0% non-contiguous), 1092/2048 blocks -+Exit status is 1 -+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), 1092/2048 blocks -+Exit status is 0 -+debugfs: cat /a -+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadebugfs: -diff --git a/tests/j_corrupt_sb_magic/image.gz b/tests/j_corrupt_sb_magic/image.gz -new file mode 100644 -index 0000000..5d895e7 -Binary files /dev/null and b/tests/j_corrupt_sb_magic/image.gz differ -diff --git a/tests/j_corrupt_sb_magic/name b/tests/j_corrupt_sb_magic/name -new file mode 100644 -index 0000000..dc781aa ---- /dev/null -+++ b/tests/j_corrupt_sb_magic/name -@@ -0,0 +1 @@ -+corrupt sb magic (csum v3) -diff --git a/tests/j_corrupt_sb_magic/script b/tests/j_corrupt_sb_magic/script -new file mode 100644 -index 0000000..9c16975 ---- /dev/null -+++ b/tests/j_corrupt_sb_magic/script -@@ -0,0 +1,52 @@ -+if test -x $DEBUGFS_EXE; then -+ -+IMAGE=$test_dir/image.gz -+FSCK_OPT=-fy -+OUT=$test_name.log -+if [ -f $test_dir/expect.gz ]; then -+ EXP=$test_name.tmp -+ gunzip < $test_dir/expect.gz > $EXP1 -+else -+ EXP=$test_dir/expect -+fi -+ -+cp /dev/null $OUT -+ -+gzip -d < $IMAGE > $TMPFILE -+ -+$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 -+status=$? -+echo Exit status is $status >> $OUT.new -+sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT -+rm -f $OUT.new -+ -+$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 -+status=$? -+echo Exit status is $status >> $OUT.new -+sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT -+rm -f $OUT.new -+ -+echo "cat /a" > $TMPFILE.cmd -+echo >> $TMPFILE.cmd -+$DEBUGFS_EXE -f $TMPFILE.cmd $TMPFILE 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT -+rm -f $TMPFILE.cmd -+ -+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 IMAGE FSCK_OPT OUT EXP -+ -+else #if test -x $DEBUGFS_EXE; then -+ echo "$test_name: $test_description: skipped" -+fi -diff --git a/tests/j_ext_dumpe2fs/expect b/tests/j_ext_dumpe2fs/expect -new file mode 100644 -index 0000000..8dc95cd ---- /dev/null -+++ b/tests/j_ext_dumpe2fs/expect -@@ -0,0 +1,54 @@ -+e2fsck external journal -+../e2fsck/e2fsck: Filesystem has unsupported feature(s) while trying to open test.img -+ -+The superblock could not be read or does not describe a valid ext2/ext3/ext4 -+filesystem. If the device is valid and it really contains an ext2/ext3/ext4 -+filesystem (and not swap or ufs or something else), then the superblock -+is corrupt, and you might try running e2fsck with an alternate superblock: -+ e2fsck -b 8193 -+ or -+ e2fsck -b 32768 -+ -+Exit status is 8 -+dumpe2fs external journal -+Filesystem volume name: -+Last mounted on: -+Filesystem magic number: 0xEF53 -+Filesystem revision #: 1 (dynamic) -+Filesystem features: journal_dev metadata_csum -+Default mount options: user_xattr acl block_validity -+Filesystem state: clean -+Errors behavior: Continue -+Filesystem OS type: Linux -+Inode count: 0 -+Block count: 2048 -+Reserved block count: 0 -+Free blocks: 0 -+Free inodes: 0 -+First block: 1 -+Block size: 1024 -+Fragment size: 1024 -+Blocks per group: 8192 -+Fragments per group: 8192 -+Inodes per group: 0 -+Inode blocks per group: 0 -+Mount count: 0 -+Check interval: 0 () -+Reserved blocks uid: 0 -+Reserved blocks gid: 0 -+First inode: 11 -+Inode size: 256 -+Required extra isize: 28 -+Desired extra isize: 28 -+Default directory hash: half_md4 -+Checksum type: crc32c -+Journal checksum type: crc32c -+Journal checksum: 0x661e816f -+Journal features: journal_64bit journal_checksum_v3 -+Journal block size: 1024 -+Journal length: 2048 -+Journal first block: 3 -+Journal sequence: 0x00000003 -+Journal start: 0 -+Journal number of users: 1 -+Journal users: 117f752e-f27d-4f6f-a652-072586a29b82 -diff --git a/tests/j_ext_dumpe2fs/image.gz b/tests/j_ext_dumpe2fs/image.gz -new file mode 100644 -index 0000000..781b591 -Binary files /dev/null and b/tests/j_ext_dumpe2fs/image.gz differ -diff --git a/tests/j_ext_dumpe2fs/name b/tests/j_ext_dumpe2fs/name -new file mode 100644 -index 0000000..60d276c ---- /dev/null -+++ b/tests/j_ext_dumpe2fs/name -@@ -0,0 +1 @@ -+dumpe2fs of external journal device -diff --git a/tests/j_ext_dumpe2fs/script b/tests/j_ext_dumpe2fs/script -new file mode 100644 -index 0000000..1611c45 ---- /dev/null -+++ b/tests/j_ext_dumpe2fs/script -@@ -0,0 +1,40 @@ -+FSCK_OPT=-fy -+OUT=$test_name.log -+if [ -f $test_dir/expect.gz ]; then -+ EXP=$test_name.tmp -+ gunzip < $test_dir/expect.gz > $EXP1 -+else -+ EXP=$test_dir/expect -+fi -+ -+cp /dev/null $OUT -+ -+gunzip < $test_dir/image.gz > $TMPFILE -+ -+echo "e2fsck external journal" >> $OUT -+$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 -+status=$? -+echo Exit status is $status >> $OUT.new -+sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT -+rm -f $OUT.new -+ -+echo "dumpe2fs external journal" >> $OUT -+$DUMPE2FS $TMPFILE > $OUT.new 2>&1 -+sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT -+rm -f $OUT.new -+ -+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 IMAGE FSCK_OPT OUT EXP -diff --git a/tests/j_ext_long_revoke_trans/expect b/tests/j_ext_long_revoke_trans/expect -new file mode 100644 -index 0000000..ed19872 ---- /dev/null -+++ b/tests/j_ext_long_revoke_trans/expect -@@ -0,0 +1,91 @@ -+Creating filesystem with 262144 1k blocks and 0 inodes -+Superblock backups stored on blocks: -+ -+Zeroing journal device:  -+Creating filesystem with 262144 1k blocks and 16384 inodes -+Superblock backups stored on blocks: -+ 8193, 24577, 40961, 57345, 73729, 204801, 221185 -+ -+Allocating group tables: done -+Writing inode tables: done -+Writing superblocks and filesystem accounting information: done -+ -+debugfs add journal device/UUID -+debugfs: feature has_journal -+Filesystem features: has_journal ext_attr resize_inode dir_index filetype extent flex_bg sparse_super huge_file uninit_bg dir_nlink extra_isize -+debugfs: ssv journal_dev 0x9999 -+debugfs: ssv journal_uuid 1db3f677-6832-4adb-bafc-8e4059c30a34 -+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/16384 files (0.0% non-contiguous), 6239/262144 blocks -+Exit status is 0 -+debugfs write journal -+debugfs: logdump -c -+Ext2 superblock header found. -+Journal starts at block 3, transaction 1 -+Found expected sequence 1, type 1 (descriptor block) at block 3 -+Found expected sequence 1, type 1 (descriptor block) at block 128 -+Found expected sequence 1, type 1 (descriptor block) at block 253 -+Found expected sequence 1, type 1 (descriptor block) at block 378 -+Found expected sequence 1, type 1 (descriptor block) at block 503 -+Found expected sequence 1, type 1 (descriptor block) at block 628 -+Found expected sequence 1, type 1 (descriptor block) at block 753 -+Found expected sequence 1, type 1 (descriptor block) at block 878 -+Found expected sequence 1, type 1 (descriptor block) at block 1003 -+Found expected sequence 1, type 1 (descriptor block) at block 1128 -+Found expected sequence 1, type 1 (descriptor block) at block 1253 -+Found expected sequence 1, type 1 (descriptor block) at block 1378 -+Found expected sequence 1, type 1 (descriptor block) at block 1503 -+Found expected sequence 1, type 1 (descriptor block) at block 1628 -+Found expected sequence 1, type 1 (descriptor block) at block 1753 -+Found expected sequence 1, type 1 (descriptor block) at block 1878 -+Found expected sequence 1, type 1 (descriptor block) at block 2003 -+Found expected sequence 1, type 1 (descriptor block) at block 2128 -+Found expected sequence 1, type 1 (descriptor block) at block 2253 -+Found expected sequence 1, type 1 (descriptor block) at block 2378 -+Found expected sequence 1, type 1 (descriptor block) at block 2503 -+Found expected sequence 1, type 1 (descriptor block) at block 2628 -+Found expected sequence 1, type 1 (descriptor block) at block 2753 -+Found expected sequence 1, type 1 (descriptor block) at block 2878 -+Found expected sequence 1, type 1 (descriptor block) at block 3003 -+Found expected sequence 1, type 1 (descriptor block) at block 3128 -+Found expected sequence 1, type 1 (descriptor block) at block 3253 -+Found expected sequence 1, type 1 (descriptor block) at block 3378 -+Found expected sequence 1, type 1 (descriptor block) at block 3503 -+Found expected sequence 1, type 1 (descriptor block) at block 3628 -+Found expected sequence 1, type 1 (descriptor block) at block 3753 -+Found expected sequence 1, type 1 (descriptor block) at block 3878 -+Found expected sequence 1, type 1 (descriptor block) at block 4003 -+Found expected sequence 1, type 1 (descriptor block) at block 4128 -+Found expected sequence 1, type 2 (commit block) at block 4135 -+Found expected sequence 2, type 5 (revoke table) at block 4136 -+Found expected sequence 2, type 5 (revoke table) at block 4137 -+Found expected sequence 2, type 5 (revoke table) at block 4138 -+Found expected sequence 2, type 5 (revoke table) at block 4139 -+Found expected sequence 2, type 5 (revoke table) at block 4140 -+Found expected sequence 2, type 5 (revoke table) at block 4141 -+Found expected sequence 2, type 5 (revoke table) at block 4142 -+Found expected sequence 2, type 5 (revoke table) at block 4143 -+Found expected sequence 2, type 5 (revoke table) at block 4144 -+Found expected sequence 2, type 5 (revoke table) at block 4145 -+Found expected sequence 2, type 5 (revoke table) at block 4146 -+Found expected sequence 2, type 5 (revoke table) at block 4147 -+Found expected sequence 2, type 5 (revoke table) at block 4148 -+Found expected sequence 2, type 5 (revoke table) at block 4149 -+Found expected sequence 2, type 5 (revoke table) at block 4150 -+Found expected sequence 2, type 5 (revoke table) at block 4151 -+Found expected sequence 2, type 5 (revoke table) at block 4152 -+Found expected sequence 2, type 2 (commit block) at block 4153 -+No magic number at block 4154: end of journal. -+debugfs fsck -+test_filesys: recovering journal -+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/16384 files (0.0% non-contiguous), 6239/262144 blocks -+Exit status is 0 -diff --git a/tests/j_ext_long_revoke_trans/name b/tests/j_ext_long_revoke_trans/name -new file mode 100644 -index 0000000..777010d ---- /dev/null -+++ b/tests/j_ext_long_revoke_trans/name -@@ -0,0 +1 @@ -+revoked transaction nuking free space w/ ext. journal -diff --git a/tests/j_ext_long_revoke_trans/script b/tests/j_ext_long_revoke_trans/script -new file mode 100644 -index 0000000..fe45c72 ---- /dev/null -+++ b/tests/j_ext_long_revoke_trans/script -@@ -0,0 +1,77 @@ -+if test -x $DEBUGFS_EXE; then -+ -+FSCK_OPT=-fy -+OUT=$test_name.log -+if [ -f $test_dir/expect.gz ]; then -+ EXP=$test_name.tmp -+ gunzip < $test_dir/expect.gz > $EXP1 -+else -+ EXP=$test_dir/expect -+fi -+ -+cp /dev/null $OUT -+ -+JNLFILE=$TMPFILE.jnl -+ -+touch $JNLFILE -+$MKE2FS -F -o Linux -b 1024 -O journal_dev -T ext4 -U 1db3f677-6832-4adb-bafc-8e4059c30a34 $JNLFILE 262144 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT 2>&1 -+$MKE2FS -F -o Linux -b 1024 -O ^has_journal -T ext4 $TMPFILE 262144 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT 2>&1 -+ -+echo "debugfs add journal device/UUID" >> $OUT -+$DEBUGFS -w -f - $TMPFILE <<-EOF >> $OUT.new 2>&1 -+ feature has_journal -+ ssv journal_dev 0x9999 -+ ssv journal_uuid 1db3f677-6832-4adb-bafc-8e4059c30a34 -+EOF -+sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT -+rm -f $OUT.new -+ -+$FSCK -fy -N test_filesys -j $JNLFILE $TMPFILE > $OUT.new 2>&1 -+status=$? -+echo Exit status is $status >> $OUT.new -+sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT -+rm -f $OUT.new -+ -+echo "debugfs write journal" >> $OUT -+echo "jo -f $JNLFILE" > $TMPFILE.cmd -+echo "jw -b 259-4356 /dev/zero" >> $TMPFILE.cmd -+echo "jc" >> $TMPFILE.cmd -+echo "jo -f $JNLFILE" >> $TMPFILE.cmd -+echo "jw -r 259-4356 /dev/zero" >> $TMPFILE.cmd -+echo "jc" >> $TMPFILE.cmd -+$DEBUGFS_EXE -w -f $TMPFILE.cmd $TMPFILE 2>> $OUT.new > /dev/null -+sed -f $cmd_dir/filter.sed < $OUT.new >> $OUT -+rm -rf $OUT.new -+ -+test -d "$JOURNAL_DUMP_DIR" -a -w "$JOURNAL_DUMP_DIR" && cp "$TMPFILE" "$JOURNAL_DUMP_DIR/$test_name.img" -+test -d "$JOURNAL_DUMP_DIR" -a -w "$JOURNAL_DUMP_DIR" && cp "$JNLFILE" "$JOURNAL_DUMP_DIR/$test_name.img.jnl" -+echo "logdump -c -f $JNLFILE" > $TMPFILE.cmd -+$DEBUGFS_EXE -f $TMPFILE.cmd $TMPFILE 2>&1 | sed -f $cmd_dir/filter.sed -e 's/logdump -c -f.*/logdump -c/g' >> $OUT -+rm -rf $TMPFILE.cmd -+ -+echo "debugfs fsck" >> $OUT -+$FSCK -fy -N test_filesys -j $JNLFILE $TMPFILE > $OUT.new 2>&1 -+status=$? -+echo Exit status is $status >> $OUT.new -+sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT -+rm -f $OUT.new -+ -+rm -f $TMPFILE $JNLFILE -+ -+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 IMAGE FSCK_OPT OUT EXP JNLFILE -+ -+else #if test -x $DEBUGFS_EXE; then -+ echo "$test_name: $test_description: skipped" -+fi -diff --git a/tests/j_ext_long_trans/expect b/tests/j_ext_long_trans/expect -new file mode 100644 -index 0000000..d379610 ---- /dev/null -+++ b/tests/j_ext_long_trans/expect -@@ -0,0 +1,104 @@ -+Creating filesystem with 262144 1k blocks and 0 inodes -+Superblock backups stored on blocks: -+ -+Zeroing journal device:  -+Creating filesystem with 262144 1k blocks and 16384 inodes -+Superblock backups stored on blocks: -+ 8193, 24577, 40961, 57345, 73729, 204801, 221185 -+ -+Allocating group tables: done -+Writing inode tables: done -+Writing superblocks and filesystem accounting information: done -+ -+debugfs add journal device/UUID -+debugfs: feature has_journal -+Filesystem features: has_journal ext_attr resize_inode dir_index filetype extent flex_bg sparse_super huge_file uninit_bg dir_nlink extra_isize -+debugfs: ssv journal_dev 0x9999 -+debugfs: ssv journal_uuid 1db3f677-6832-4adb-bafc-8e4059c30a34 -+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/16384 files (0.0% non-contiguous), 6239/262144 blocks -+Exit status is 0 -+debugfs write journal -+debugfs: logdump -c -+Ext2 superblock header found. -+Journal starts at block 3, transaction 1 -+Found expected sequence 1, type 1 (descriptor block) at block 3 -+Found expected sequence 1, type 1 (descriptor block) at block 128 -+Found expected sequence 1, type 1 (descriptor block) at block 253 -+Found expected sequence 1, type 1 (descriptor block) at block 378 -+Found expected sequence 1, type 1 (descriptor block) at block 503 -+Found expected sequence 1, type 1 (descriptor block) at block 628 -+Found expected sequence 1, type 1 (descriptor block) at block 753 -+Found expected sequence 1, type 1 (descriptor block) at block 878 -+Found expected sequence 1, type 1 (descriptor block) at block 1003 -+Found expected sequence 1, type 1 (descriptor block) at block 1128 -+Found expected sequence 1, type 1 (descriptor block) at block 1253 -+Found expected sequence 1, type 1 (descriptor block) at block 1378 -+Found expected sequence 1, type 1 (descriptor block) at block 1503 -+Found expected sequence 1, type 1 (descriptor block) at block 1628 -+Found expected sequence 1, type 1 (descriptor block) at block 1753 -+Found expected sequence 1, type 1 (descriptor block) at block 1878 -+Found expected sequence 1, type 1 (descriptor block) at block 2003 -+Found expected sequence 1, type 1 (descriptor block) at block 2128 -+Found expected sequence 1, type 1 (descriptor block) at block 2253 -+Found expected sequence 1, type 1 (descriptor block) at block 2378 -+Found expected sequence 1, type 1 (descriptor block) at block 2503 -+Found expected sequence 1, type 1 (descriptor block) at block 2628 -+Found expected sequence 1, type 1 (descriptor block) at block 2753 -+Found expected sequence 1, type 1 (descriptor block) at block 2878 -+Found expected sequence 1, type 1 (descriptor block) at block 3003 -+Found expected sequence 1, type 1 (descriptor block) at block 3128 -+Found expected sequence 1, type 1 (descriptor block) at block 3253 -+Found expected sequence 1, type 1 (descriptor block) at block 3378 -+Found expected sequence 1, type 1 (descriptor block) at block 3503 -+Found expected sequence 1, type 1 (descriptor block) at block 3628 -+Found expected sequence 1, type 1 (descriptor block) at block 3753 -+Found expected sequence 1, type 1 (descriptor block) at block 3878 -+Found expected sequence 1, type 1 (descriptor block) at block 4003 -+Found expected sequence 1, type 1 (descriptor block) at block 4128 -+Found expected sequence 1, type 2 (commit block) at block 4135 -+No magic number at block 4136: end of journal. -+debugfs fsck -+test_filesys: recovering journal -+Resize inode not valid. Recreate? yes -+ -+Pass 1: Checking inodes, blocks, and sizes -+Root inode is not a directory. Clear? yes -+ -+Pass 2: Checking directory structure -+Pass 3: Checking directory connectivity -+Root inode not allocated. Allocate? yes -+ -+/lost+found not found. Create? yes -+ -+Pass 4: Checking reference counts -+Pass 5: Checking group summary information -+Block bitmap differences: +(1--259) +275 +(291--418) +2341 -+Fix? yes -+ -+Free blocks count wrong for group #0 (5838, counted=5851). -+Fix? yes -+ -+Free blocks count wrong (255903, counted=255916). -+Fix? yes -+ -+Inode bitmap differences: +1 +(3--10) -+Fix? yes -+ -+Free inodes count wrong for group #0 (500, counted=501). -+Fix? yes -+ -+Directories count wrong for group #0 (3, counted=2). -+Fix? yes -+ -+Free inodes count wrong (16372, counted=16373). -+Fix? yes -+ -+ -+test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** -+test_filesys: 11/16384 files (0.0% non-contiguous), 6228/262144 blocks -+Exit status is 1 -diff --git a/tests/j_ext_long_trans/name b/tests/j_ext_long_trans/name -new file mode 100644 -index 0000000..8ae5722 ---- /dev/null -+++ b/tests/j_ext_long_trans/name -@@ -0,0 +1 @@ -+transaction nuking free space w/ ext. journal -diff --git a/tests/j_ext_long_trans/script b/tests/j_ext_long_trans/script -new file mode 100644 -index 0000000..f71e5a4 ---- /dev/null -+++ b/tests/j_ext_long_trans/script -@@ -0,0 +1,74 @@ -+if test -x $DEBUGFS_EXE; then -+ -+FSCK_OPT=-fy -+OUT=$test_name.log -+if [ -f $test_dir/expect.gz ]; then -+ EXP=$test_name.tmp -+ gunzip < $test_dir/expect.gz > $EXP1 -+else -+ EXP=$test_dir/expect -+fi -+ -+cp /dev/null $OUT -+ -+JNLFILE=$TMPFILE.jnl -+ -+touch $JNLFILE -+$MKE2FS -F -o Linux -b 1024 -O journal_dev -T ext4 -U 1db3f677-6832-4adb-bafc-8e4059c30a34 $JNLFILE 262144 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT 2>&1 -+$MKE2FS -F -o Linux -b 1024 -O ^has_journal -T ext4 $TMPFILE 262144 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT 2>&1 -+ -+echo "debugfs add journal device/UUID" >> $OUT -+$DEBUGFS -w -f - $TMPFILE <<- EOF >> $OUT.new 2>&1 -+ feature has_journal -+ ssv journal_dev 0x9999 -+ ssv journal_uuid 1db3f677-6832-4adb-bafc-8e4059c30a34 -+EOF -+sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT -+rm -f $OUT.new -+ -+$FSCK -fy -N test_filesys -j $JNLFILE $TMPFILE > $OUT.new 2>&1 -+status=$? -+echo Exit status is $status >> $OUT.new -+sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT -+rm -f $OUT.new -+ -+echo "debugfs write journal" >> $OUT -+echo "jo -f $JNLFILE" > $TMPFILE.cmd -+echo "jw -b 259-4356 /dev/zero" >> $TMPFILE.cmd -+echo "jc" >> $TMPFILE.cmd -+$DEBUGFS_EXE -w -f $TMPFILE.cmd $TMPFILE 2>> $OUT.new > /dev/null -+sed -f $cmd_dir/filter.sed < $OUT.new >> $OUT -+rm -rf $OUT.new -+ -+test -d "$JOURNAL_DUMP_DIR" -a -w "$JOURNAL_DUMP_DIR" && cp "$TMPFILE" "$JOURNAL_DUMP_DIR/$test_name.img" -+test -d "$JOURNAL_DUMP_DIR" -a -w "$JOURNAL_DUMP_DIR" && cp "$JNLFILE" "$JOURNAL_DUMP_DIR/$test_name.img.jnl" -+echo "logdump -c -f $JNLFILE" > $TMPFILE.cmd -+$DEBUGFS_EXE -f $TMPFILE.cmd $TMPFILE 2>&1 | sed -f $cmd_dir/filter.sed -e 's/logdump -c -f.*/logdump -c/g' >> $OUT -+rm -rf $TMPFILE.cmd -+ -+echo "debugfs fsck" >> $OUT -+$FSCK -fy -N test_filesys -j $JNLFILE $TMPFILE > $OUT.new 2>&1 -+status=$? -+echo Exit status is $status >> $OUT.new -+sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT -+rm -f $OUT.new -+ -+rm -f $TMPFILE $JNLFILE -+ -+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 IMAGE FSCK_OPT OUT EXP JNLFILE -+ -+else #if test -x $DEBUGFS_EXE; then -+ echo "$test_name: $test_description: skipped" -+fi -diff --git a/tests/j_long_revoke_trans/expect b/tests/j_long_revoke_trans/expect -new file mode 100644 -index 0000000..c0730e6 ---- /dev/null -+++ b/tests/j_long_revoke_trans/expect -@@ -0,0 +1,81 @@ -+Creating filesystem with 262144 1k blocks and 16384 inodes -+Superblock backups stored on blocks: -+ 8193, 24577, 40961, 57345, 73729, 204801, 221185 -+ -+Allocating group tables: done -+Writing inode tables: done -+Creating journal (8192 blocks): done -+Writing superblocks and filesystem accounting information: done -+ -+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/16384 files (0.0% non-contiguous), 14431/262144 blocks -+Exit status is 0 -+debugfs write journal -+debugfs: logdump -c -+Journal starts at block 1, transaction 1 -+Found expected sequence 1, type 1 (descriptor block) at block 1 -+Found expected sequence 1, type 1 (descriptor block) at block 126 -+Found expected sequence 1, type 1 (descriptor block) at block 251 -+Found expected sequence 1, type 1 (descriptor block) at block 376 -+Found expected sequence 1, type 1 (descriptor block) at block 501 -+Found expected sequence 1, type 1 (descriptor block) at block 626 -+Found expected sequence 1, type 1 (descriptor block) at block 751 -+Found expected sequence 1, type 1 (descriptor block) at block 876 -+Found expected sequence 1, type 1 (descriptor block) at block 1001 -+Found expected sequence 1, type 1 (descriptor block) at block 1126 -+Found expected sequence 1, type 1 (descriptor block) at block 1251 -+Found expected sequence 1, type 1 (descriptor block) at block 1376 -+Found expected sequence 1, type 1 (descriptor block) at block 1501 -+Found expected sequence 1, type 1 (descriptor block) at block 1626 -+Found expected sequence 1, type 1 (descriptor block) at block 1751 -+Found expected sequence 1, type 1 (descriptor block) at block 1876 -+Found expected sequence 1, type 1 (descriptor block) at block 2001 -+Found expected sequence 1, type 1 (descriptor block) at block 2126 -+Found expected sequence 1, type 1 (descriptor block) at block 2251 -+Found expected sequence 1, type 1 (descriptor block) at block 2376 -+Found expected sequence 1, type 1 (descriptor block) at block 2501 -+Found expected sequence 1, type 1 (descriptor block) at block 2626 -+Found expected sequence 1, type 1 (descriptor block) at block 2751 -+Found expected sequence 1, type 1 (descriptor block) at block 2876 -+Found expected sequence 1, type 1 (descriptor block) at block 3001 -+Found expected sequence 1, type 1 (descriptor block) at block 3126 -+Found expected sequence 1, type 1 (descriptor block) at block 3251 -+Found expected sequence 1, type 1 (descriptor block) at block 3376 -+Found expected sequence 1, type 1 (descriptor block) at block 3501 -+Found expected sequence 1, type 1 (descriptor block) at block 3626 -+Found expected sequence 1, type 1 (descriptor block) at block 3751 -+Found expected sequence 1, type 1 (descriptor block) at block 3876 -+Found expected sequence 1, type 1 (descriptor block) at block 4001 -+Found expected sequence 1, type 1 (descriptor block) at block 4126 -+Found expected sequence 1, type 2 (commit block) at block 4133 -+Found expected sequence 2, type 5 (revoke table) at block 4134 -+Found expected sequence 2, type 5 (revoke table) at block 4135 -+Found expected sequence 2, type 5 (revoke table) at block 4136 -+Found expected sequence 2, type 5 (revoke table) at block 4137 -+Found expected sequence 2, type 5 (revoke table) at block 4138 -+Found expected sequence 2, type 5 (revoke table) at block 4139 -+Found expected sequence 2, type 5 (revoke table) at block 4140 -+Found expected sequence 2, type 5 (revoke table) at block 4141 -+Found expected sequence 2, type 5 (revoke table) at block 4142 -+Found expected sequence 2, type 5 (revoke table) at block 4143 -+Found expected sequence 2, type 5 (revoke table) at block 4144 -+Found expected sequence 2, type 5 (revoke table) at block 4145 -+Found expected sequence 2, type 5 (revoke table) at block 4146 -+Found expected sequence 2, type 5 (revoke table) at block 4147 -+Found expected sequence 2, type 5 (revoke table) at block 4148 -+Found expected sequence 2, type 5 (revoke table) at block 4149 -+Found expected sequence 2, type 5 (revoke table) at block 4150 -+Found expected sequence 2, type 2 (commit block) at block 4151 -+No magic number at block 4152: end of journal. -+test_filesys: recovering journal -+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/16384 files (0.0% non-contiguous), 14431/262144 blocks -+Exit status is 0 -diff --git a/tests/j_long_revoke_trans/name b/tests/j_long_revoke_trans/name -new file mode 100644 -index 0000000..3cbb2cd ---- /dev/null -+++ b/tests/j_long_revoke_trans/name -@@ -0,0 +1 @@ -+revoked transaction nuking free space -diff --git a/tests/j_long_revoke_trans/script b/tests/j_long_revoke_trans/script -new file mode 100644 -index 0000000..4a0c5d1 ---- /dev/null -+++ b/tests/j_long_revoke_trans/script -@@ -0,0 +1,62 @@ -+if test -x $DEBUGFS_EXE; then -+ -+FSCK_OPT=-fy -+OUT=$test_name.log -+if [ -f $test_dir/expect.gz ]; then -+ EXP=$test_name.tmp -+ gunzip < $test_dir/expect.gz > $EXP1 -+else -+ EXP=$test_dir/expect -+fi -+ -+cp /dev/null $OUT -+ -+$MKE2FS -F -o Linux -b 1024 -O has_journal -T ext4 $TMPFILE 262144 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT 2>&1 -+ -+$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 -+status=$? -+echo Exit status is $status >> $OUT.new -+sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT -+rm -f $OUT.new -+ -+echo "debugfs write journal" >> $OUT -+echo "jo" > $TMPFILE.cmd -+echo "jw -b 259-4356 /dev/zero" >> $TMPFILE.cmd -+echo "jc" >> $TMPFILE.cmd -+echo "jo" >> $TMPFILE.cmd -+echo "jw -r 259-4356" >> $TMPFILE.cmd -+echo "jc" >> $TMPFILE.cmd -+$DEBUGFS_EXE -w -f $TMPFILE.cmd $TMPFILE 2>> $OUT.new > /dev/null -+sed -f $cmd_dir/filter.sed < $OUT.new >> $OUT -+rm -rf $OUT.new -+ -+test -d "$JOURNAL_DUMP_DIR" -a -w "$JOURNAL_DUMP_DIR" && cp "$TMPFILE" "$JOURNAL_DUMP_DIR/$test_name.img" -+echo "logdump -c" > $TMPFILE.cmd -+$DEBUGFS_EXE -f $TMPFILE.cmd $TMPFILE 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT -+rm -rf $TMPFILE.cmd -+ -+$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 -+status=$? -+echo Exit status is $status >> $OUT.new -+sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT -+rm -f $OUT.new -+ -+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 IMAGE FSCK_OPT OUT EXP -+ -+else #if test -x $DEBUGFS_EXE; then -+ echo "$test_name: $test_description: skipped" -+fi -diff --git a/tests/j_long_revoke_trans_mcsum_32bit/expect b/tests/j_long_revoke_trans_mcsum_32bit/expect -new file mode 100644 -index 0000000..664a301 ---- /dev/null -+++ b/tests/j_long_revoke_trans_mcsum_32bit/expect -@@ -0,0 +1,117 @@ -+64-bit filesystem support is not enabled. The larger fields afforded by this feature enable full-strength checksumming. Pass -O 64bit to rectify. -+Creating filesystem with 524288 1k blocks and 32768 inodes -+Superblock backups stored on blocks: -+ 8193, 24577, 40961, 57345, 73729, 204801, 221185, 401409 -+ -+Allocating group tables: done -+Writing inode tables: done -+Creating journal (16384 blocks): done -+Writing superblocks and filesystem accounting information: done -+ -+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/32768 files (0.0% non-contiguous), 27050/524288 blocks -+Exit status is 0 -+Journal features: (none) -+debugfs write journal -+Journal features: journal_incompat_revoke journal_checksum_v3 -+debugfs: logdump -c -+Journal starts at block 1, transaction 1 -+Found expected sequence 1, type 1 (descriptor block) at block 1 -+Found expected sequence 1, type 1 (descriptor block) at block 64 -+Found expected sequence 1, type 1 (descriptor block) at block 127 -+Found expected sequence 1, type 1 (descriptor block) at block 190 -+Found expected sequence 1, type 1 (descriptor block) at block 253 -+Found expected sequence 1, type 1 (descriptor block) at block 316 -+Found expected sequence 1, type 1 (descriptor block) at block 379 -+Found expected sequence 1, type 1 (descriptor block) at block 442 -+Found expected sequence 1, type 1 (descriptor block) at block 505 -+Found expected sequence 1, type 1 (descriptor block) at block 568 -+Found expected sequence 1, type 1 (descriptor block) at block 631 -+Found expected sequence 1, type 1 (descriptor block) at block 694 -+Found expected sequence 1, type 1 (descriptor block) at block 757 -+Found expected sequence 1, type 1 (descriptor block) at block 820 -+Found expected sequence 1, type 1 (descriptor block) at block 883 -+Found expected sequence 1, type 1 (descriptor block) at block 946 -+Found expected sequence 1, type 1 (descriptor block) at block 1009 -+Found expected sequence 1, type 1 (descriptor block) at block 1072 -+Found expected sequence 1, type 1 (descriptor block) at block 1135 -+Found expected sequence 1, type 1 (descriptor block) at block 1198 -+Found expected sequence 1, type 1 (descriptor block) at block 1261 -+Found expected sequence 1, type 1 (descriptor block) at block 1324 -+Found expected sequence 1, type 1 (descriptor block) at block 1387 -+Found expected sequence 1, type 1 (descriptor block) at block 1450 -+Found expected sequence 1, type 1 (descriptor block) at block 1513 -+Found expected sequence 1, type 1 (descriptor block) at block 1576 -+Found expected sequence 1, type 1 (descriptor block) at block 1639 -+Found expected sequence 1, type 1 (descriptor block) at block 1702 -+Found expected sequence 1, type 1 (descriptor block) at block 1765 -+Found expected sequence 1, type 1 (descriptor block) at block 1828 -+Found expected sequence 1, type 1 (descriptor block) at block 1891 -+Found expected sequence 1, type 1 (descriptor block) at block 1954 -+Found expected sequence 1, type 1 (descriptor block) at block 2017 -+Found expected sequence 1, type 1 (descriptor block) at block 2080 -+Found expected sequence 1, type 1 (descriptor block) at block 2143 -+Found expected sequence 1, type 1 (descriptor block) at block 2206 -+Found expected sequence 1, type 1 (descriptor block) at block 2269 -+Found expected sequence 1, type 1 (descriptor block) at block 2332 -+Found expected sequence 1, type 1 (descriptor block) at block 2395 -+Found expected sequence 1, type 1 (descriptor block) at block 2458 -+Found expected sequence 1, type 1 (descriptor block) at block 2521 -+Found expected sequence 1, type 1 (descriptor block) at block 2584 -+Found expected sequence 1, type 1 (descriptor block) at block 2647 -+Found expected sequence 1, type 1 (descriptor block) at block 2710 -+Found expected sequence 1, type 1 (descriptor block) at block 2773 -+Found expected sequence 1, type 1 (descriptor block) at block 2836 -+Found expected sequence 1, type 1 (descriptor block) at block 2899 -+Found expected sequence 1, type 1 (descriptor block) at block 2962 -+Found expected sequence 1, type 1 (descriptor block) at block 3025 -+Found expected sequence 1, type 1 (descriptor block) at block 3088 -+Found expected sequence 1, type 1 (descriptor block) at block 3151 -+Found expected sequence 1, type 1 (descriptor block) at block 3214 -+Found expected sequence 1, type 1 (descriptor block) at block 3277 -+Found expected sequence 1, type 1 (descriptor block) at block 3340 -+Found expected sequence 1, type 1 (descriptor block) at block 3403 -+Found expected sequence 1, type 1 (descriptor block) at block 3466 -+Found expected sequence 1, type 1 (descriptor block) at block 3529 -+Found expected sequence 1, type 1 (descriptor block) at block 3592 -+Found expected sequence 1, type 1 (descriptor block) at block 3655 -+Found expected sequence 1, type 1 (descriptor block) at block 3718 -+Found expected sequence 1, type 1 (descriptor block) at block 3781 -+Found expected sequence 1, type 1 (descriptor block) at block 3844 -+Found expected sequence 1, type 1 (descriptor block) at block 3907 -+Found expected sequence 1, type 1 (descriptor block) at block 3970 -+Found expected sequence 1, type 1 (descriptor block) at block 4033 -+Found expected sequence 1, type 1 (descriptor block) at block 4096 -+Found expected sequence 1, type 1 (descriptor block) at block 4159 -+Found expected sequence 1, type 2 (commit block) at block 4165 -+Found expected sequence 2, type 5 (revoke table) at block 4166 -+Found expected sequence 2, type 5 (revoke table) at block 4167 -+Found expected sequence 2, type 5 (revoke table) at block 4168 -+Found expected sequence 2, type 5 (revoke table) at block 4169 -+Found expected sequence 2, type 5 (revoke table) at block 4170 -+Found expected sequence 2, type 5 (revoke table) at block 4171 -+Found expected sequence 2, type 5 (revoke table) at block 4172 -+Found expected sequence 2, type 5 (revoke table) at block 4173 -+Found expected sequence 2, type 5 (revoke table) at block 4174 -+Found expected sequence 2, type 5 (revoke table) at block 4175 -+Found expected sequence 2, type 5 (revoke table) at block 4176 -+Found expected sequence 2, type 5 (revoke table) at block 4177 -+Found expected sequence 2, type 5 (revoke table) at block 4178 -+Found expected sequence 2, type 5 (revoke table) at block 4179 -+Found expected sequence 2, type 5 (revoke table) at block 4180 -+Found expected sequence 2, type 5 (revoke table) at block 4181 -+Found expected sequence 2, type 5 (revoke table) at block 4182 -+Found expected sequence 2, type 2 (commit block) at block 4183 -+No magic number at block 4184: end of journal. -+test_filesys: recovering journal -+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/32768 files (0.0% non-contiguous), 27050/524288 blocks -+Exit status is 0 -diff --git a/tests/j_long_revoke_trans_mcsum_32bit/name b/tests/j_long_revoke_trans_mcsum_32bit/name -new file mode 100644 -index 0000000..3d78c07 ---- /dev/null -+++ b/tests/j_long_revoke_trans_mcsum_32bit/name -@@ -0,0 +1 @@ -+revoked transaction nuking free space on 32bit,metadata_csum -diff --git a/tests/j_long_revoke_trans_mcsum_32bit/script b/tests/j_long_revoke_trans_mcsum_32bit/script -new file mode 100644 -index 0000000..fc0d0ad ---- /dev/null -+++ b/tests/j_long_revoke_trans_mcsum_32bit/script -@@ -0,0 +1,67 @@ -+if test -x $DEBUGFS_EXE; then -+ -+FSCK_OPT=-fy -+OUT=$test_name.log -+if [ -f $test_dir/expect.gz ]; then -+ EXP=$test_name.tmp -+ gunzip < $test_dir/expect.gz > $EXP1 -+else -+ EXP=$test_dir/expect -+fi -+ -+cp /dev/null $OUT -+ -+$MKE2FS -F -o Linux -b 1024 -O ^64bit,has_journal,metadata_csum -T ext4 $TMPFILE 524288 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT 2>&1 -+ -+$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 -+status=$? -+echo Exit status is $status >> $OUT.new -+sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT -+rm -f $OUT.new -+ -+$DUMPE2FS $TMPFILE 2>&1 | grep '^Journal features:' >> $OUT -+ -+echo "debugfs write journal" >> $OUT -+echo "jo -c" > $TMPFILE.cmd -+echo "jw -b 260-4356 /dev/zero" >> $TMPFILE.cmd -+echo "jc" >> $TMPFILE.cmd -+echo "jo" >> $TMPFILE.cmd -+echo "jw -r 260-4356" >> $TMPFILE.cmd -+echo "jc" >> $TMPFILE.cmd -+#$DEBUGFS_EXE -w $TMPFILE -f $TMPFILE.cmd >> $OUT 2>&1 -+$DEBUGFS_EXE -w -f $TMPFILE.cmd $TMPFILE 2>> $OUT.new > /dev/null -+sed -f $cmd_dir/filter.sed < $OUT.new >> $OUT -+rm -rf $OUT.new -+ -+$DUMPE2FS $TMPFILE 2>&1 | grep '^Journal features:' >> $OUT -+ -+test -d "$JOURNAL_DUMP_DIR" -a -w "$JOURNAL_DUMP_DIR" && cp "$TMPFILE" "$JOURNAL_DUMP_DIR/$test_name.img" -+echo "logdump -c" > $TMPFILE.cmd -+$DEBUGFS_EXE -f $TMPFILE.cmd $TMPFILE 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT -+rm -rf $TMPFILE.cmd -+ -+$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 -+status=$? -+echo Exit status is $status >> $OUT.new -+sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT -+rm -f $OUT.new -+ -+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 IMAGE FSCK_OPT OUT EXP -+ -+else #if test -x $DEBUGFS_EXE; then -+ echo "$test_name: $test_description: skipped" -+fi -diff --git a/tests/j_long_revoke_trans_mcsum_64bit/expect b/tests/j_long_revoke_trans_mcsum_64bit/expect -new file mode 100644 -index 0000000..29dc407 ---- /dev/null -+++ b/tests/j_long_revoke_trans_mcsum_64bit/expect -@@ -0,0 +1,132 @@ -+Creating filesystem with 524288 1k blocks and 32768 inodes -+Superblock backups stored on blocks: -+ 8193, 24577, 40961, 57345, 73729, 204801, 221185, 401409 -+ -+Allocating group tables: done -+Writing inode tables: done -+Creating journal (16384 blocks): done -+Writing superblocks and filesystem accounting information: done -+ -+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/32768 files (0.0% non-contiguous), 27068/524288 blocks -+Exit status is 0 -+Journal features: (none) -+debugfs write journal -+Journal features: journal_incompat_revoke journal_64bit journal_checksum_v3 -+debugfs: logdump -c -+Journal starts at block 1, transaction 1 -+Found expected sequence 1, type 1 (descriptor block) at block 1 -+Found expected sequence 1, type 1 (descriptor block) at block 64 -+Found expected sequence 1, type 1 (descriptor block) at block 127 -+Found expected sequence 1, type 1 (descriptor block) at block 190 -+Found expected sequence 1, type 1 (descriptor block) at block 253 -+Found expected sequence 1, type 1 (descriptor block) at block 316 -+Found expected sequence 1, type 1 (descriptor block) at block 379 -+Found expected sequence 1, type 1 (descriptor block) at block 442 -+Found expected sequence 1, type 1 (descriptor block) at block 505 -+Found expected sequence 1, type 1 (descriptor block) at block 568 -+Found expected sequence 1, type 1 (descriptor block) at block 631 -+Found expected sequence 1, type 1 (descriptor block) at block 694 -+Found expected sequence 1, type 1 (descriptor block) at block 757 -+Found expected sequence 1, type 1 (descriptor block) at block 820 -+Found expected sequence 1, type 1 (descriptor block) at block 883 -+Found expected sequence 1, type 1 (descriptor block) at block 946 -+Found expected sequence 1, type 1 (descriptor block) at block 1009 -+Found expected sequence 1, type 1 (descriptor block) at block 1072 -+Found expected sequence 1, type 1 (descriptor block) at block 1135 -+Found expected sequence 1, type 1 (descriptor block) at block 1198 -+Found expected sequence 1, type 1 (descriptor block) at block 1261 -+Found expected sequence 1, type 1 (descriptor block) at block 1324 -+Found expected sequence 1, type 1 (descriptor block) at block 1387 -+Found expected sequence 1, type 1 (descriptor block) at block 1450 -+Found expected sequence 1, type 1 (descriptor block) at block 1513 -+Found expected sequence 1, type 1 (descriptor block) at block 1576 -+Found expected sequence 1, type 1 (descriptor block) at block 1639 -+Found expected sequence 1, type 1 (descriptor block) at block 1702 -+Found expected sequence 1, type 1 (descriptor block) at block 1765 -+Found expected sequence 1, type 1 (descriptor block) at block 1828 -+Found expected sequence 1, type 1 (descriptor block) at block 1891 -+Found expected sequence 1, type 1 (descriptor block) at block 1954 -+Found expected sequence 1, type 1 (descriptor block) at block 2017 -+Found expected sequence 1, type 1 (descriptor block) at block 2080 -+Found expected sequence 1, type 1 (descriptor block) at block 2143 -+Found expected sequence 1, type 1 (descriptor block) at block 2206 -+Found expected sequence 1, type 1 (descriptor block) at block 2269 -+Found expected sequence 1, type 1 (descriptor block) at block 2332 -+Found expected sequence 1, type 1 (descriptor block) at block 2395 -+Found expected sequence 1, type 1 (descriptor block) at block 2458 -+Found expected sequence 1, type 1 (descriptor block) at block 2521 -+Found expected sequence 1, type 1 (descriptor block) at block 2584 -+Found expected sequence 1, type 1 (descriptor block) at block 2647 -+Found expected sequence 1, type 1 (descriptor block) at block 2710 -+Found expected sequence 1, type 1 (descriptor block) at block 2773 -+Found expected sequence 1, type 1 (descriptor block) at block 2836 -+Found expected sequence 1, type 1 (descriptor block) at block 2899 -+Found expected sequence 1, type 1 (descriptor block) at block 2962 -+Found expected sequence 1, type 1 (descriptor block) at block 3025 -+Found expected sequence 1, type 1 (descriptor block) at block 3088 -+Found expected sequence 1, type 1 (descriptor block) at block 3151 -+Found expected sequence 1, type 1 (descriptor block) at block 3214 -+Found expected sequence 1, type 1 (descriptor block) at block 3277 -+Found expected sequence 1, type 1 (descriptor block) at block 3340 -+Found expected sequence 1, type 1 (descriptor block) at block 3403 -+Found expected sequence 1, type 1 (descriptor block) at block 3466 -+Found expected sequence 1, type 1 (descriptor block) at block 3529 -+Found expected sequence 1, type 1 (descriptor block) at block 3592 -+Found expected sequence 1, type 1 (descriptor block) at block 3655 -+Found expected sequence 1, type 1 (descriptor block) at block 3718 -+Found expected sequence 1, type 1 (descriptor block) at block 3781 -+Found expected sequence 1, type 1 (descriptor block) at block 3844 -+Found expected sequence 1, type 1 (descriptor block) at block 3907 -+Found expected sequence 1, type 1 (descriptor block) at block 3970 -+Found expected sequence 1, type 1 (descriptor block) at block 4033 -+Found expected sequence 1, type 1 (descriptor block) at block 4096 -+Found expected sequence 1, type 1 (descriptor block) at block 4159 -+Found expected sequence 1, type 2 (commit block) at block 4165 -+Found expected sequence 2, type 5 (revoke table) at block 4166 -+Found expected sequence 2, type 5 (revoke table) at block 4167 -+Found expected sequence 2, type 5 (revoke table) at block 4168 -+Found expected sequence 2, type 5 (revoke table) at block 4169 -+Found expected sequence 2, type 5 (revoke table) at block 4170 -+Found expected sequence 2, type 5 (revoke table) at block 4171 -+Found expected sequence 2, type 5 (revoke table) at block 4172 -+Found expected sequence 2, type 5 (revoke table) at block 4173 -+Found expected sequence 2, type 5 (revoke table) at block 4174 -+Found expected sequence 2, type 5 (revoke table) at block 4175 -+Found expected sequence 2, type 5 (revoke table) at block 4176 -+Found expected sequence 2, type 5 (revoke table) at block 4177 -+Found expected sequence 2, type 5 (revoke table) at block 4178 -+Found expected sequence 2, type 5 (revoke table) at block 4179 -+Found expected sequence 2, type 5 (revoke table) at block 4180 -+Found expected sequence 2, type 5 (revoke table) at block 4181 -+Found expected sequence 2, type 5 (revoke table) at block 4182 -+Found expected sequence 2, type 5 (revoke table) at block 4183 -+Found expected sequence 2, type 5 (revoke table) at block 4184 -+Found expected sequence 2, type 5 (revoke table) at block 4185 -+Found expected sequence 2, type 5 (revoke table) at block 4186 -+Found expected sequence 2, type 5 (revoke table) at block 4187 -+Found expected sequence 2, type 5 (revoke table) at block 4188 -+Found expected sequence 2, type 5 (revoke table) at block 4189 -+Found expected sequence 2, type 5 (revoke table) at block 4190 -+Found expected sequence 2, type 5 (revoke table) at block 4191 -+Found expected sequence 2, type 5 (revoke table) at block 4192 -+Found expected sequence 2, type 5 (revoke table) at block 4193 -+Found expected sequence 2, type 5 (revoke table) at block 4194 -+Found expected sequence 2, type 5 (revoke table) at block 4195 -+Found expected sequence 2, type 5 (revoke table) at block 4196 -+Found expected sequence 2, type 5 (revoke table) at block 4197 -+Found expected sequence 2, type 5 (revoke table) at block 4198 -+Found expected sequence 2, type 2 (commit block) at block 4199 -+No magic number at block 4200: end of journal. -+test_filesys: recovering journal -+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/32768 files (0.0% non-contiguous), 27068/524288 blocks -+Exit status is 0 -diff --git a/tests/j_long_revoke_trans_mcsum_64bit/name b/tests/j_long_revoke_trans_mcsum_64bit/name -new file mode 100644 -index 0000000..809900b ---- /dev/null -+++ b/tests/j_long_revoke_trans_mcsum_64bit/name -@@ -0,0 +1 @@ -+revoked transaction nuking free space on 64bit,metadata_csum -diff --git a/tests/j_long_revoke_trans_mcsum_64bit/script b/tests/j_long_revoke_trans_mcsum_64bit/script -new file mode 100644 -index 0000000..e206f88 ---- /dev/null -+++ b/tests/j_long_revoke_trans_mcsum_64bit/script -@@ -0,0 +1,67 @@ -+if test -x $DEBUGFS_EXE; then -+ -+FSCK_OPT=-fy -+OUT=$test_name.log -+if [ -f $test_dir/expect.gz ]; then -+ EXP=$test_name.tmp -+ gunzip < $test_dir/expect.gz > $EXP1 -+else -+ EXP=$test_dir/expect -+fi -+ -+cp /dev/null $OUT -+ -+$MKE2FS -F -o Linux -b 1024 -O 64bit,has_journal,metadata_csum -T ext4 $TMPFILE 524288 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT 2>&1 -+ -+$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 -+status=$? -+echo Exit status is $status >> $OUT.new -+sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT -+rm -f $OUT.new -+ -+$DUMPE2FS $TMPFILE 2>&1 | grep '^Journal features:' >> $OUT -+ -+echo "debugfs write journal" >> $OUT -+echo "jo -c" > $TMPFILE.cmd -+echo "jw -b 262-4358 /dev/zero" >> $TMPFILE.cmd -+echo "jc" >> $TMPFILE.cmd -+echo "jo" >> $TMPFILE.cmd -+echo "jw -r 262-4358" >> $TMPFILE.cmd -+echo "jc" >> $TMPFILE.cmd -+#$DEBUGFS_EXE -w $TMPFILE -f $TMPFILE.cmd >> $OUT 2>&1 -+$DEBUGFS_EXE -w -f $TMPFILE.cmd $TMPFILE 2>> $OUT.new > /dev/null -+sed -f $cmd_dir/filter.sed < $OUT.new >> $OUT -+rm -rf $OUT.new -+ -+$DUMPE2FS $TMPFILE 2>&1 | grep '^Journal features:' >> $OUT -+ -+test -d "$JOURNAL_DUMP_DIR" -a -w "$JOURNAL_DUMP_DIR" && cp "$TMPFILE" "$JOURNAL_DUMP_DIR/$test_name.img" -+echo "logdump -c" > $TMPFILE.cmd -+$DEBUGFS_EXE -f $TMPFILE.cmd $TMPFILE 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT -+rm -rf $TMPFILE.cmd -+ -+$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 -+status=$? -+echo Exit status is $status >> $OUT.new -+sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT -+rm -f $OUT.new -+ -+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 IMAGE FSCK_OPT OUT EXP -+ -+else #if test -x $DEBUGFS_EXE; then -+ echo "$test_name: $test_description: skipped" -+fi -diff --git a/tests/j_long_trans/expect b/tests/j_long_trans/expect -new file mode 100644 -index 0000000..7a17541 ---- /dev/null -+++ b/tests/j_long_trans/expect -@@ -0,0 +1,107 @@ -+Creating filesystem with 262144 1k blocks and 16384 inodes -+Superblock backups stored on blocks: -+ 8193, 24577, 40961, 57345, 73729, 204801, 221185 -+ -+Allocating group tables: done -+Writing inode tables: done -+Creating journal (8192 blocks): done -+Writing superblocks and filesystem accounting information: done -+ -+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/16384 files (0.0% non-contiguous), 14431/262144 blocks -+Exit status is 0 -+debugfs write journal -+debugfs: logdump -c -+Journal starts at block 1, transaction 1 -+Found expected sequence 1, type 1 (descriptor block) at block 1 -+Found expected sequence 1, type 1 (descriptor block) at block 126 -+Found expected sequence 1, type 1 (descriptor block) at block 251 -+Found expected sequence 1, type 1 (descriptor block) at block 376 -+Found expected sequence 1, type 1 (descriptor block) at block 501 -+Found expected sequence 1, type 1 (descriptor block) at block 626 -+Found expected sequence 1, type 1 (descriptor block) at block 751 -+Found expected sequence 1, type 1 (descriptor block) at block 876 -+Found expected sequence 1, type 1 (descriptor block) at block 1001 -+Found expected sequence 1, type 1 (descriptor block) at block 1126 -+Found expected sequence 1, type 1 (descriptor block) at block 1251 -+Found expected sequence 1, type 1 (descriptor block) at block 1376 -+Found expected sequence 1, type 1 (descriptor block) at block 1501 -+Found expected sequence 1, type 1 (descriptor block) at block 1626 -+Found expected sequence 1, type 1 (descriptor block) at block 1751 -+Found expected sequence 1, type 1 (descriptor block) at block 1876 -+Found expected sequence 1, type 1 (descriptor block) at block 2001 -+Found expected sequence 1, type 1 (descriptor block) at block 2126 -+Found expected sequence 1, type 1 (descriptor block) at block 2251 -+Found expected sequence 1, type 1 (descriptor block) at block 2376 -+Found expected sequence 1, type 1 (descriptor block) at block 2501 -+Found expected sequence 1, type 1 (descriptor block) at block 2626 -+Found expected sequence 1, type 1 (descriptor block) at block 2751 -+Found expected sequence 1, type 1 (descriptor block) at block 2876 -+Found expected sequence 1, type 1 (descriptor block) at block 3001 -+Found expected sequence 1, type 1 (descriptor block) at block 3126 -+Found expected sequence 1, type 1 (descriptor block) at block 3251 -+Found expected sequence 1, type 1 (descriptor block) at block 3376 -+Found expected sequence 1, type 1 (descriptor block) at block 3501 -+Found expected sequence 1, type 1 (descriptor block) at block 3626 -+Found expected sequence 1, type 1 (descriptor block) at block 3751 -+Found expected sequence 1, type 1 (descriptor block) at block 3876 -+Found expected sequence 1, type 1 (descriptor block) at block 4001 -+Found expected sequence 1, type 1 (descriptor block) at block 4126 -+Found expected sequence 1, type 2 (commit block) at block 4133 -+No magic number at block 4134: end of journal. -+test_filesys: recovering journal -+Superblock has an invalid journal (inode 8). -+Clear? yes -+ -+*** journal has been deleted *** -+ -+Resize inode not valid. Recreate? yes -+ -+Pass 1: Checking inodes, blocks, and sizes -+Root inode is not a directory. Clear? yes -+ -+Pass 2: Checking directory structure -+Pass 3: Checking directory connectivity -+Root inode not allocated. Allocate? yes -+ -+/lost+found not found. Create? yes -+ -+Pass 4: Checking reference counts -+Pass 5: Checking group summary information -+Block bitmap differences: +(1--259) +273 +275 +289 +(291--418) +(2083--2210) +2341 -+Fix? yes -+ -+Free blocks count wrong for group #0 (5838, counted=5851). -+Fix? yes -+ -+Free blocks count wrong for group #14 (0, counted=8192). -+Fix? yes -+ -+Free blocks count wrong (247711, counted=255916). -+Fix? yes -+ -+Inode bitmap differences: +1 +(3--10) -+Fix? yes -+ -+Free inodes count wrong for group #0 (500, counted=501). -+Fix? yes -+ -+Directories count wrong for group #0 (3, counted=2). -+Fix? yes -+ -+Free inodes count wrong (16372, counted=16373). -+Fix? yes -+ -+Recreate journal? yes -+ -+Creating journal (8192 blocks): Done. -+ -+*** journal has been regenerated *** -+ -+test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** -+test_filesys: 11/16384 files (0.0% non-contiguous), 14420/262144 blocks -+Exit status is 1 -diff --git a/tests/j_long_trans/name b/tests/j_long_trans/name -new file mode 100644 -index 0000000..7a70f8f ---- /dev/null -+++ b/tests/j_long_trans/name -@@ -0,0 +1 @@ -+transaction nuking free space -diff --git a/tests/j_long_trans/script b/tests/j_long_trans/script -new file mode 100644 -index 0000000..68172c4 ---- /dev/null -+++ b/tests/j_long_trans/script -@@ -0,0 +1,59 @@ -+if test -x $DEBUGFS_EXE; then -+ -+FSCK_OPT=-fy -+OUT=$test_name.log -+if [ -f $test_dir/expect.gz ]; then -+ EXP=$test_name.tmp -+ gunzip < $test_dir/expect.gz > $EXP1 -+else -+ EXP=$test_dir/expect -+fi -+ -+cp /dev/null $OUT -+ -+$MKE2FS -F -o Linux -b 1024 -O has_journal -T ext4 $TMPFILE 262144 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT 2>&1 -+ -+$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 -+status=$? -+echo Exit status is $status >> $OUT.new -+sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT -+rm -f $OUT.new -+ -+echo "debugfs write journal" >> $OUT -+echo "jo" > $TMPFILE.cmd -+echo "jw -b 259-4356 /dev/zero" >> $TMPFILE.cmd -+echo "jc" >> $TMPFILE.cmd -+$DEBUGFS_EXE -w -f $TMPFILE.cmd $TMPFILE 2>> $OUT.new > /dev/null -+sed -f $cmd_dir/filter.sed < $OUT.new >> $OUT -+rm -rf $OUT.new -+ -+test -d "$JOURNAL_DUMP_DIR" -a -w "$JOURNAL_DUMP_DIR" && cp "$TMPFILE" "$JOURNAL_DUMP_DIR/$test_name.img" -+echo "logdump -c" > $TMPFILE.cmd -+$DEBUGFS_EXE -f $TMPFILE.cmd $TMPFILE 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT -+rm -rf $TMPFILE.cmd -+ -+$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 -+status=$? -+echo Exit status is $status >> $OUT.new -+sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT -+rm -f $OUT.new -+ -+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 IMAGE FSCK_OPT OUT EXP -+ -+else #if test -x $DEBUGFS_EXE; then -+ echo "$test_name: $test_description: skipped" -+fi -diff --git a/tests/j_long_trans_mcsum_32bit/expect b/tests/j_long_trans_mcsum_32bit/expect -new file mode 100644 -index 0000000..a808d9f ---- /dev/null -+++ b/tests/j_long_trans_mcsum_32bit/expect -@@ -0,0 +1,146 @@ -+64-bit filesystem support is not enabled. The larger fields afforded by this feature enable full-strength checksumming. Pass -O 64bit to rectify. -+Creating filesystem with 524288 1k blocks and 32768 inodes -+Superblock backups stored on blocks: -+ 8193, 24577, 40961, 57345, 73729, 204801, 221185, 401409 -+ -+Allocating group tables: done -+Writing inode tables: done -+Creating journal (16384 blocks): done -+Writing superblocks and filesystem accounting information: done -+ -+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/32768 files (0.0% non-contiguous), 27050/524288 blocks -+Exit status is 0 -+Journal features: (none) -+debugfs write journal -+Journal features: journal_checksum_v3 -+debugfs: logdump -c -+Journal starts at block 1, transaction 1 -+Found expected sequence 1, type 1 (descriptor block) at block 1 -+Found expected sequence 1, type 1 (descriptor block) at block 64 -+Found expected sequence 1, type 1 (descriptor block) at block 127 -+Found expected sequence 1, type 1 (descriptor block) at block 190 -+Found expected sequence 1, type 1 (descriptor block) at block 253 -+Found expected sequence 1, type 1 (descriptor block) at block 316 -+Found expected sequence 1, type 1 (descriptor block) at block 379 -+Found expected sequence 1, type 1 (descriptor block) at block 442 -+Found expected sequence 1, type 1 (descriptor block) at block 505 -+Found expected sequence 1, type 1 (descriptor block) at block 568 -+Found expected sequence 1, type 1 (descriptor block) at block 631 -+Found expected sequence 1, type 1 (descriptor block) at block 694 -+Found expected sequence 1, type 1 (descriptor block) at block 757 -+Found expected sequence 1, type 1 (descriptor block) at block 820 -+Found expected sequence 1, type 1 (descriptor block) at block 883 -+Found expected sequence 1, type 1 (descriptor block) at block 946 -+Found expected sequence 1, type 1 (descriptor block) at block 1009 -+Found expected sequence 1, type 1 (descriptor block) at block 1072 -+Found expected sequence 1, type 1 (descriptor block) at block 1135 -+Found expected sequence 1, type 1 (descriptor block) at block 1198 -+Found expected sequence 1, type 1 (descriptor block) at block 1261 -+Found expected sequence 1, type 1 (descriptor block) at block 1324 -+Found expected sequence 1, type 1 (descriptor block) at block 1387 -+Found expected sequence 1, type 1 (descriptor block) at block 1450 -+Found expected sequence 1, type 1 (descriptor block) at block 1513 -+Found expected sequence 1, type 1 (descriptor block) at block 1576 -+Found expected sequence 1, type 1 (descriptor block) at block 1639 -+Found expected sequence 1, type 1 (descriptor block) at block 1702 -+Found expected sequence 1, type 1 (descriptor block) at block 1765 -+Found expected sequence 1, type 1 (descriptor block) at block 1828 -+Found expected sequence 1, type 1 (descriptor block) at block 1891 -+Found expected sequence 1, type 1 (descriptor block) at block 1954 -+Found expected sequence 1, type 1 (descriptor block) at block 2017 -+Found expected sequence 1, type 1 (descriptor block) at block 2080 -+Found expected sequence 1, type 1 (descriptor block) at block 2143 -+Found expected sequence 1, type 1 (descriptor block) at block 2206 -+Found expected sequence 1, type 1 (descriptor block) at block 2269 -+Found expected sequence 1, type 1 (descriptor block) at block 2332 -+Found expected sequence 1, type 1 (descriptor block) at block 2395 -+Found expected sequence 1, type 1 (descriptor block) at block 2458 -+Found expected sequence 1, type 1 (descriptor block) at block 2521 -+Found expected sequence 1, type 1 (descriptor block) at block 2584 -+Found expected sequence 1, type 1 (descriptor block) at block 2647 -+Found expected sequence 1, type 1 (descriptor block) at block 2710 -+Found expected sequence 1, type 1 (descriptor block) at block 2773 -+Found expected sequence 1, type 1 (descriptor block) at block 2836 -+Found expected sequence 1, type 1 (descriptor block) at block 2899 -+Found expected sequence 1, type 1 (descriptor block) at block 2962 -+Found expected sequence 1, type 1 (descriptor block) at block 3025 -+Found expected sequence 1, type 1 (descriptor block) at block 3088 -+Found expected sequence 1, type 1 (descriptor block) at block 3151 -+Found expected sequence 1, type 1 (descriptor block) at block 3214 -+Found expected sequence 1, type 1 (descriptor block) at block 3277 -+Found expected sequence 1, type 1 (descriptor block) at block 3340 -+Found expected sequence 1, type 1 (descriptor block) at block 3403 -+Found expected sequence 1, type 1 (descriptor block) at block 3466 -+Found expected sequence 1, type 1 (descriptor block) at block 3529 -+Found expected sequence 1, type 1 (descriptor block) at block 3592 -+Found expected sequence 1, type 1 (descriptor block) at block 3655 -+Found expected sequence 1, type 1 (descriptor block) at block 3718 -+Found expected sequence 1, type 1 (descriptor block) at block 3781 -+Found expected sequence 1, type 1 (descriptor block) at block 3844 -+Found expected sequence 1, type 1 (descriptor block) at block 3907 -+Found expected sequence 1, type 1 (descriptor block) at block 3970 -+Found expected sequence 1, type 1 (descriptor block) at block 4033 -+Found expected sequence 1, type 1 (descriptor block) at block 4096 -+Found expected sequence 1, type 1 (descriptor block) at block 4159 -+Found expected sequence 1, type 2 (commit block) at block 4165 -+No magic number at block 4166: end of journal. -+test_filesys: recovering journal -+Superblock has an invalid journal (inode 8). -+Clear? yes -+ -+*** journal has been deleted *** -+ -+Resize inode not valid. Recreate? yes -+ -+Pass 1: Checking inodes, blocks, and sizes -+Root inode is not a directory. Clear? yes -+ -+Pass 2: Checking directory structure -+Pass 3: Checking directory connectivity -+Root inode not allocated. Allocate? yes -+ -+/lost+found not found. Create? yes -+ -+Pass 4: Checking reference counts -+Pass 5: Checking group summary information -+Block bitmap differences: +(1--260) +276 +(292--419) +2342 -(139265--155648) -+Fix? yes -+ -+Free blocks count wrong for group #0 (5837, counted=5850). -+Fix? yes -+ -+Free blocks count wrong for group #17 (0, counted=8192). -+Fix? yes -+ -+Free blocks count wrong for group #18 (0, counted=8192). -+Fix? yes -+ -+Free blocks count wrong (497236, counted=513633). -+Fix? yes -+ -+Inode bitmap differences: +1 +(3--10) -+Fix? yes -+ -+Free inodes count wrong for group #0 (500, counted=501). -+Fix? yes -+ -+Directories count wrong for group #0 (3, counted=2). -+Fix? yes -+ -+Free inodes count wrong (32756, counted=32757). -+Fix? yes -+ -+Recreate journal? yes -+ -+Creating journal (16384 blocks): Done. -+ -+*** journal has been regenerated *** -+ -+test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** -+test_filesys: 11/32768 files (0.0% non-contiguous), 27039/524288 blocks -+Exit status is 1 -diff --git a/tests/j_long_trans_mcsum_32bit/name b/tests/j_long_trans_mcsum_32bit/name -new file mode 100644 -index 0000000..ac43f51 ---- /dev/null -+++ b/tests/j_long_trans_mcsum_32bit/name -@@ -0,0 +1 @@ -+transaction nuking free space on 32bit,metadata_csum -diff --git a/tests/j_long_trans_mcsum_32bit/script b/tests/j_long_trans_mcsum_32bit/script -new file mode 100644 -index 0000000..4722242 ---- /dev/null -+++ b/tests/j_long_trans_mcsum_32bit/script -@@ -0,0 +1,63 @@ -+if test -x $DEBUGFS_EXE; then -+ -+FSCK_OPT=-fy -+OUT=$test_name.log -+if [ -f $test_dir/expect.gz ]; then -+ EXP=$test_name.tmp -+ gunzip < $test_dir/expect.gz > $EXP1 -+else -+ EXP=$test_dir/expect -+fi -+ -+cp /dev/null $OUT -+ -+$MKE2FS -F -o Linux -b 1024 -O ^64bit,has_journal,metadata_csum -T ext4 $TMPFILE 524288 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT 2>&1 -+ -+$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 -+status=$? -+echo Exit status is $status >> $OUT.new -+sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT -+rm -f $OUT.new -+ -+$DUMPE2FS $TMPFILE 2>&1 | grep '^Journal features:' >> $OUT -+ -+echo "debugfs write journal" >> $OUT -+echo "jo -c" > $TMPFILE.cmd -+echo "jw -b 260-4356 /dev/zero" >> $TMPFILE.cmd -+echo "jc" >> $TMPFILE.cmd -+$DEBUGFS_EXE -w -f $TMPFILE.cmd $TMPFILE 2>> $OUT.new > /dev/null -+sed -f $cmd_dir/filter.sed < $OUT.new >> $OUT -+rm -rf $OUT.new -+ -+$DUMPE2FS $TMPFILE 2>&1 | grep '^Journal features:' >> $OUT -+ -+test -d "$JOURNAL_DUMP_DIR" -a -w "$JOURNAL_DUMP_DIR" && cp "$TMPFILE" "$JOURNAL_DUMP_DIR/$test_name.img" -+echo "logdump -c" > $TMPFILE.cmd -+$DEBUGFS_EXE -f $TMPFILE.cmd $TMPFILE 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT -+rm -rf $TMPFILE.cmd -+ -+$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 -+status=$? -+echo Exit status is $status >> $OUT.new -+sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT -+rm -f $OUT.new -+ -+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 IMAGE FSCK_OPT OUT EXP -+ -+else #if test -x $DEBUGFS_EXE; then -+ echo "$test_name: $test_description: skipped" -+fi -diff --git a/tests/j_long_trans_mcsum_64bit/expect b/tests/j_long_trans_mcsum_64bit/expect -new file mode 100644 -index 0000000..76e109a ---- /dev/null -+++ b/tests/j_long_trans_mcsum_64bit/expect -@@ -0,0 +1,145 @@ -+Creating filesystem with 524288 1k blocks and 32768 inodes -+Superblock backups stored on blocks: -+ 8193, 24577, 40961, 57345, 73729, 204801, 221185, 401409 -+ -+Allocating group tables: done -+Writing inode tables: done -+Creating journal (16384 blocks): done -+Writing superblocks and filesystem accounting information: done -+ -+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/32768 files (0.0% non-contiguous), 27068/524288 blocks -+Exit status is 0 -+Journal features: (none) -+debugfs write journal -+Journal features: journal_64bit journal_checksum_v3 -+debugfs: logdump -c -+Journal starts at block 1, transaction 1 -+Found expected sequence 1, type 1 (descriptor block) at block 1 -+Found expected sequence 1, type 1 (descriptor block) at block 64 -+Found expected sequence 1, type 1 (descriptor block) at block 127 -+Found expected sequence 1, type 1 (descriptor block) at block 190 -+Found expected sequence 1, type 1 (descriptor block) at block 253 -+Found expected sequence 1, type 1 (descriptor block) at block 316 -+Found expected sequence 1, type 1 (descriptor block) at block 379 -+Found expected sequence 1, type 1 (descriptor block) at block 442 -+Found expected sequence 1, type 1 (descriptor block) at block 505 -+Found expected sequence 1, type 1 (descriptor block) at block 568 -+Found expected sequence 1, type 1 (descriptor block) at block 631 -+Found expected sequence 1, type 1 (descriptor block) at block 694 -+Found expected sequence 1, type 1 (descriptor block) at block 757 -+Found expected sequence 1, type 1 (descriptor block) at block 820 -+Found expected sequence 1, type 1 (descriptor block) at block 883 -+Found expected sequence 1, type 1 (descriptor block) at block 946 -+Found expected sequence 1, type 1 (descriptor block) at block 1009 -+Found expected sequence 1, type 1 (descriptor block) at block 1072 -+Found expected sequence 1, type 1 (descriptor block) at block 1135 -+Found expected sequence 1, type 1 (descriptor block) at block 1198 -+Found expected sequence 1, type 1 (descriptor block) at block 1261 -+Found expected sequence 1, type 1 (descriptor block) at block 1324 -+Found expected sequence 1, type 1 (descriptor block) at block 1387 -+Found expected sequence 1, type 1 (descriptor block) at block 1450 -+Found expected sequence 1, type 1 (descriptor block) at block 1513 -+Found expected sequence 1, type 1 (descriptor block) at block 1576 -+Found expected sequence 1, type 1 (descriptor block) at block 1639 -+Found expected sequence 1, type 1 (descriptor block) at block 1702 -+Found expected sequence 1, type 1 (descriptor block) at block 1765 -+Found expected sequence 1, type 1 (descriptor block) at block 1828 -+Found expected sequence 1, type 1 (descriptor block) at block 1891 -+Found expected sequence 1, type 1 (descriptor block) at block 1954 -+Found expected sequence 1, type 1 (descriptor block) at block 2017 -+Found expected sequence 1, type 1 (descriptor block) at block 2080 -+Found expected sequence 1, type 1 (descriptor block) at block 2143 -+Found expected sequence 1, type 1 (descriptor block) at block 2206 -+Found expected sequence 1, type 1 (descriptor block) at block 2269 -+Found expected sequence 1, type 1 (descriptor block) at block 2332 -+Found expected sequence 1, type 1 (descriptor block) at block 2395 -+Found expected sequence 1, type 1 (descriptor block) at block 2458 -+Found expected sequence 1, type 1 (descriptor block) at block 2521 -+Found expected sequence 1, type 1 (descriptor block) at block 2584 -+Found expected sequence 1, type 1 (descriptor block) at block 2647 -+Found expected sequence 1, type 1 (descriptor block) at block 2710 -+Found expected sequence 1, type 1 (descriptor block) at block 2773 -+Found expected sequence 1, type 1 (descriptor block) at block 2836 -+Found expected sequence 1, type 1 (descriptor block) at block 2899 -+Found expected sequence 1, type 1 (descriptor block) at block 2962 -+Found expected sequence 1, type 1 (descriptor block) at block 3025 -+Found expected sequence 1, type 1 (descriptor block) at block 3088 -+Found expected sequence 1, type 1 (descriptor block) at block 3151 -+Found expected sequence 1, type 1 (descriptor block) at block 3214 -+Found expected sequence 1, type 1 (descriptor block) at block 3277 -+Found expected sequence 1, type 1 (descriptor block) at block 3340 -+Found expected sequence 1, type 1 (descriptor block) at block 3403 -+Found expected sequence 1, type 1 (descriptor block) at block 3466 -+Found expected sequence 1, type 1 (descriptor block) at block 3529 -+Found expected sequence 1, type 1 (descriptor block) at block 3592 -+Found expected sequence 1, type 1 (descriptor block) at block 3655 -+Found expected sequence 1, type 1 (descriptor block) at block 3718 -+Found expected sequence 1, type 1 (descriptor block) at block 3781 -+Found expected sequence 1, type 1 (descriptor block) at block 3844 -+Found expected sequence 1, type 1 (descriptor block) at block 3907 -+Found expected sequence 1, type 1 (descriptor block) at block 3970 -+Found expected sequence 1, type 1 (descriptor block) at block 4033 -+Found expected sequence 1, type 1 (descriptor block) at block 4096 -+Found expected sequence 1, type 1 (descriptor block) at block 4159 -+Found expected sequence 1, type 2 (commit block) at block 4165 -+No magic number at block 4166: end of journal. -+test_filesys: recovering journal -+Superblock has an invalid journal (inode 8). -+Clear? yes -+ -+*** journal has been deleted *** -+ -+Resize inode not valid. Recreate? yes -+ -+Pass 1: Checking inodes, blocks, and sizes -+Root inode is not a directory. Clear? yes -+ -+Pass 2: Checking directory structure -+Pass 3: Checking directory connectivity -+Root inode not allocated. Allocate? yes -+ -+/lost+found not found. Create? yes -+ -+Pass 4: Checking reference counts -+Pass 5: Checking group summary information -+Block bitmap differences: +(1--262) +278 +(294--421) +2344 -(139265--155648) -+Fix? yes -+ -+Free blocks count wrong for group #0 (5835, counted=5848). -+Fix? yes -+ -+Free blocks count wrong for group #17 (0, counted=8192). -+Fix? yes -+ -+Free blocks count wrong for group #18 (0, counted=8192). -+Fix? yes -+ -+Free blocks count wrong (497218, counted=513615). -+Fix? yes -+ -+Inode bitmap differences: +1 +(3--10) -+Fix? yes -+ -+Free inodes count wrong for group #0 (500, counted=501). -+Fix? yes -+ -+Directories count wrong for group #0 (3, counted=2). -+Fix? yes -+ -+Free inodes count wrong (32756, counted=32757). -+Fix? yes -+ -+Recreate journal? yes -+ -+Creating journal (16384 blocks): Done. -+ -+*** journal has been regenerated *** -+ -+test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** -+test_filesys: 11/32768 files (0.0% non-contiguous), 27057/524288 blocks -+Exit status is 1 -diff --git a/tests/j_long_trans_mcsum_64bit/name b/tests/j_long_trans_mcsum_64bit/name -new file mode 100644 -index 0000000..9dab338 ---- /dev/null -+++ b/tests/j_long_trans_mcsum_64bit/name -@@ -0,0 +1 @@ -+transaction nuking free space on 64bit,metadata_csum -diff --git a/tests/j_long_trans_mcsum_64bit/script b/tests/j_long_trans_mcsum_64bit/script -new file mode 100644 -index 0000000..65ca1b7 ---- /dev/null -+++ b/tests/j_long_trans_mcsum_64bit/script -@@ -0,0 +1,63 @@ -+if test -x $DEBUGFS_EXE; then -+ -+FSCK_OPT=-fy -+OUT=$test_name.log -+if [ -f $test_dir/expect.gz ]; then -+ EXP=$test_name.tmp -+ gunzip < $test_dir/expect.gz > $EXP1 -+else -+ EXP=$test_dir/expect -+fi -+ -+cp /dev/null $OUT -+ -+$MKE2FS -F -o Linux -b 1024 -O 64bit,has_journal,metadata_csum -T ext4 $TMPFILE 524288 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT 2>&1 -+ -+$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 -+status=$? -+echo Exit status is $status >> $OUT.new -+sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT -+rm -f $OUT.new -+ -+$DUMPE2FS $TMPFILE 2>&1 | grep '^Journal features:' >> $OUT -+ -+echo "debugfs write journal" >> $OUT -+echo "jo -c" > $TMPFILE.cmd -+echo "jw -b 262-4358 /dev/zero" >> $TMPFILE.cmd -+echo "jc" >> $TMPFILE.cmd -+$DEBUGFS_EXE -w -f $TMPFILE.cmd $TMPFILE 2>> $OUT.new > /dev/null -+sed -f $cmd_dir/filter.sed < $OUT.new >> $OUT -+rm -rf $OUT.new -+ -+$DUMPE2FS $TMPFILE 2>&1 | grep '^Journal features:' >> $OUT -+ -+test -d "$JOURNAL_DUMP_DIR" -a -w "$JOURNAL_DUMP_DIR" && cp "$TMPFILE" "$JOURNAL_DUMP_DIR/$test_name.img" -+echo "logdump -c" > $TMPFILE.cmd -+$DEBUGFS_EXE -f $TMPFILE.cmd $TMPFILE 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT -+rm -rf $TMPFILE.cmd -+ -+$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 -+status=$? -+echo Exit status is $status >> $OUT.new -+sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT -+rm -f $OUT.new -+ -+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 IMAGE FSCK_OPT OUT EXP -+ -+else #if test -x $DEBUGFS_EXE; then -+ echo "$test_name: $test_description: skipped" -+fi -diff --git a/tests/j_recover_csum2_32bit/expect.1 b/tests/j_recover_csum2_32bit/expect.1 -new file mode 100644 -index 0000000..491784a ---- /dev/null -+++ b/tests/j_recover_csum2_32bit/expect.1 -@@ -0,0 +1,16 @@ -+test_filesys: recovering journal -+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: +(1--259) +265 +(274--275) +281 +(290--418) +(1059--1186) +(2211--2352) -+Fix? yes -+ -+Inode bitmap differences: +(1--11) -+Fix? yes -+ -+ -+test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** -+test_filesys: 11/8192 files (0.0% non-contiguous), 7739/131072 blocks -+Exit status is 0 -diff --git a/tests/j_recover_csum2_32bit/expect.2 b/tests/j_recover_csum2_32bit/expect.2 -new file mode 100644 -index 0000000..d223026 ---- /dev/null -+++ b/tests/j_recover_csum2_32bit/expect.2 -@@ -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/8192 files (0.0% non-contiguous), 7739/131072 blocks -+Exit status is 0 -diff --git a/tests/j_recover_csum2_32bit/image.bz2 b/tests/j_recover_csum2_32bit/image.bz2 -new file mode 100644 -index 0000000..2212edd -Binary files /dev/null and b/tests/j_recover_csum2_32bit/image.bz2 differ -diff --git a/tests/j_recover_csum2_32bit/name b/tests/j_recover_csum2_32bit/name -new file mode 100644 -index 0000000..6fd378c ---- /dev/null -+++ b/tests/j_recover_csum2_32bit/name -@@ -0,0 +1 @@ -+recover 32-bit journal checksum v2 -diff --git a/tests/j_recover_csum2_32bit/script b/tests/j_recover_csum2_32bit/script -new file mode 100755 -index 0000000..4b0ec48 ---- /dev/null -+++ b/tests/j_recover_csum2_32bit/script -@@ -0,0 +1,31 @@ -+#!/bin/bash -+ -+FSCK_OPT=-fy -+IMAGE=$test_dir/image.bz2 -+ -+bzip2 -d < $IMAGE > $TMPFILE -+ -+# 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 -N test_filesys $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 -N test_filesys $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 -diff --git a/tests/j_recover_csum2_64bit/expect.1 b/tests/j_recover_csum2_64bit/expect.1 -new file mode 100644 -index 0000000..491784a ---- /dev/null -+++ b/tests/j_recover_csum2_64bit/expect.1 -@@ -0,0 +1,16 @@ -+test_filesys: recovering journal -+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: +(1--259) +265 +(274--275) +281 +(290--418) +(1059--1186) +(2211--2352) -+Fix? yes -+ -+Inode bitmap differences: +(1--11) -+Fix? yes -+ -+ -+test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** -+test_filesys: 11/8192 files (0.0% non-contiguous), 7739/131072 blocks -+Exit status is 0 -diff --git a/tests/j_recover_csum2_64bit/expect.2 b/tests/j_recover_csum2_64bit/expect.2 -new file mode 100644 -index 0000000..d223026 ---- /dev/null -+++ b/tests/j_recover_csum2_64bit/expect.2 -@@ -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/8192 files (0.0% non-contiguous), 7739/131072 blocks -+Exit status is 0 -diff --git a/tests/j_recover_csum2_64bit/image.bz2 b/tests/j_recover_csum2_64bit/image.bz2 -new file mode 100644 -index 0000000..acf1dae -Binary files /dev/null and b/tests/j_recover_csum2_64bit/image.bz2 differ -diff --git a/tests/j_recover_csum2_64bit/name b/tests/j_recover_csum2_64bit/name -new file mode 100644 -index 0000000..1770502 ---- /dev/null -+++ b/tests/j_recover_csum2_64bit/name -@@ -0,0 +1 @@ -+recover 64-bit journal checksum v2 -diff --git a/tests/j_recover_csum2_64bit/script b/tests/j_recover_csum2_64bit/script -new file mode 100755 -index 0000000..4b0ec48 ---- /dev/null -+++ b/tests/j_recover_csum2_64bit/script -@@ -0,0 +1,31 @@ -+#!/bin/bash -+ -+FSCK_OPT=-fy -+IMAGE=$test_dir/image.bz2 -+ -+bzip2 -d < $IMAGE > $TMPFILE -+ -+# 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 -N test_filesys $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 -N test_filesys $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 -diff --git a/tests/j_short_revoke_trans/expect b/tests/j_short_revoke_trans/expect -new file mode 100644 -index 0000000..e83c5ea ---- /dev/null -+++ b/tests/j_short_revoke_trans/expect -@@ -0,0 +1,32 @@ -+Creating filesystem with 65536 4k blocks and 16384 inodes -+Superblock backups stored on blocks: -+ 32768 -+ -+Allocating group tables: done -+Writing inode tables: done -+Creating journal (4096 blocks): done -+Writing superblocks and filesystem accounting information: done -+ -+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/16384 files (0.0% non-contiguous), 5164/65536 blocks -+Exit status is 0 -+debugfs write journal -+debugfs: logdump -c -+Journal starts at block 1, transaction 1 -+Found expected sequence 1, type 1 (descriptor block) at block 1 -+Found expected sequence 1, type 2 (commit block) at block 6 -+Found expected sequence 2, type 5 (revoke table) at block 7 -+Found expected sequence 2, type 2 (commit block) at block 8 -+No magic number at block 9: end of journal. -+test_filesys: recovering journal -+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/16384 files (0.0% non-contiguous), 5164/65536 blocks -+Exit status is 0 -diff --git a/tests/j_short_revoke_trans/name b/tests/j_short_revoke_trans/name -new file mode 100644 -index 0000000..5470018 ---- /dev/null -+++ b/tests/j_short_revoke_trans/name -@@ -0,0 +1 @@ -+revoke blocks of transaction nuking bitmaps -diff --git a/tests/j_short_revoke_trans/script b/tests/j_short_revoke_trans/script -new file mode 100644 -index 0000000..4eec436 ---- /dev/null -+++ b/tests/j_short_revoke_trans/script -@@ -0,0 +1,64 @@ -+if test -x $DEBUGFS_EXE; then -+ -+FSCK_OPT=-fy -+OUT=$test_name.log -+if [ -f $test_dir/expect.gz ]; then -+ EXP=$test_name.tmp -+ gunzip < $test_dir/expect.gz > $EXP1 -+else -+ EXP=$test_dir/expect -+fi -+ -+cp /dev/null $OUT -+ -+$MKE2FS -F -o Linux -b 4096 -O has_journal -T ext4 $TMPFILE 65536 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT 2>&1 -+ -+$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 -+status=$? -+echo Exit status is $status >> $OUT.new -+sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT -+rm -f $OUT.new -+ -+bitmaps="$($DUMPE2FS $TMPFILE 2>&1 | grep 'bitmap at' | sed -e 's/^.*bitmap at \([0-9]*\).*$/\1/g' | tr '\n' ',')" -+ -+echo "debugfs write journal" >> $OUT -+echo "jo" > $TMPFILE.cmd -+echo "jw -b $bitmaps /dev/zero" >> $TMPFILE.cmd -+echo "jc" >> $TMPFILE.cmd -+echo "jo" >> $TMPFILE.cmd -+echo "jw -r $bitmaps" >> $TMPFILE.cmd -+echo "jc" >> $TMPFILE.cmd -+$DEBUGFS_EXE -w -f $TMPFILE.cmd $TMPFILE 2>> $OUT.new > /dev/null -+sed -f $cmd_dir/filter.sed < $OUT.new >> $OUT -+rm -rf $OUT.new -+ -+test -d "$JOURNAL_DUMP_DIR" -a -w "$JOURNAL_DUMP_DIR" && cp "$TMPFILE" "$JOURNAL_DUMP_DIR/$test_name.img" -+echo "logdump -c" > $TMPFILE.cmd -+$DEBUGFS_EXE -f $TMPFILE.cmd $TMPFILE 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT -+rm -rf $TMPFILE.cmd -+ -+$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 -+status=$? -+echo Exit status is $status >> $OUT.new -+sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT -+rm -f $OUT.new -+ -+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 IMAGE FSCK_OPT OUT EXP -+ -+else #if test -x $DEBUGFS_EXE; then -+ echo "$test_name: $test_description: skipped" -+fi -diff --git a/tests/j_short_revoke_trans_mcsum_64bit/expect b/tests/j_short_revoke_trans_mcsum_64bit/expect -new file mode 100644 -index 0000000..2b0eeb3 ---- /dev/null -+++ b/tests/j_short_revoke_trans_mcsum_64bit/expect -@@ -0,0 +1,34 @@ -+Creating filesystem with 131072 4k blocks and 32768 inodes -+Superblock backups stored on blocks: -+ 32768, 98304 -+ -+Allocating group tables: done -+Writing inode tables: done -+Creating journal (4096 blocks): done -+Writing superblocks and filesystem accounting information: done -+ -+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/32768 files (0.0% non-contiguous), 6353/131072 blocks -+Exit status is 0 -+Journal features: (none) -+debugfs write journal -+Journal features: journal_incompat_revoke journal_64bit journal_checksum_v3 -+debugfs: logdump -c -+Journal starts at block 1, transaction 1 -+Found expected sequence 1, type 1 (descriptor block) at block 1 -+Found expected sequence 1, type 2 (commit block) at block 10 -+Found expected sequence 2, type 5 (revoke table) at block 11 -+Found expected sequence 2, type 2 (commit block) at block 12 -+No magic number at block 13: end of journal. -+test_filesys: recovering journal -+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/32768 files (0.0% non-contiguous), 6353/131072 blocks -+Exit status is 0 -diff --git a/tests/j_short_revoke_trans_mcsum_64bit/name b/tests/j_short_revoke_trans_mcsum_64bit/name -new file mode 100644 -index 0000000..fb286fd ---- /dev/null -+++ b/tests/j_short_revoke_trans_mcsum_64bit/name -@@ -0,0 +1 @@ -+revoke blocks of transaction nuking the bitmaps on 64bit,metadata_csum -diff --git a/tests/j_short_revoke_trans_mcsum_64bit/script b/tests/j_short_revoke_trans_mcsum_64bit/script -new file mode 100644 -index 0000000..c943efa ---- /dev/null -+++ b/tests/j_short_revoke_trans_mcsum_64bit/script -@@ -0,0 +1,68 @@ -+if test -x $DEBUGFS_EXE; then -+ -+FSCK_OPT=-fy -+OUT=$test_name.log -+if [ -f $test_dir/expect.gz ]; then -+ EXP=$test_name.tmp -+ gunzip < $test_dir/expect.gz > $EXP1 -+else -+ EXP=$test_dir/expect -+fi -+ -+cp /dev/null $OUT -+ -+$MKE2FS -F -o Linux -b 4096 -O 64bit,has_journal,metadata_csum -T ext4 $TMPFILE 131072 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT 2>&1 -+ -+$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 -+status=$? -+echo Exit status is $status >> $OUT.new -+sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT -+rm -f $OUT.new -+ -+bitmaps="$($DUMPE2FS $TMPFILE 2>&1 | grep 'bitmap at' | sed -e 's/^.*bitmap at \([0-9]*\).*$/\1/g' | tr '\n' ',')" -+ -+$DUMPE2FS $TMPFILE 2>&1 | grep '^Journal features:' >> $OUT -+ -+echo "debugfs write journal" >> $OUT -+echo "jo -c" > $TMPFILE.cmd -+echo "jw -b $bitmaps /dev/zero" >> $TMPFILE.cmd -+echo "jc" >> $TMPFILE.cmd -+echo "jo" >> $TMPFILE.cmd -+echo "jw -r $bitmaps" >> $TMPFILE.cmd -+echo "jc" >> $TMPFILE.cmd -+$DEBUGFS_EXE -w -f $TMPFILE.cmd $TMPFILE 2>> $OUT.new > /dev/null -+sed -f $cmd_dir/filter.sed < $OUT.new >> $OUT -+rm -rf $OUT.new -+ -+$DUMPE2FS $TMPFILE 2>&1 | grep '^Journal features:' >> $OUT -+ -+test -d "$JOURNAL_DUMP_DIR" -a -w "$JOURNAL_DUMP_DIR" && cp "$TMPFILE" "$JOURNAL_DUMP_DIR/$test_name.img" -+echo "logdump -c" > $TMPFILE.cmd -+$DEBUGFS_EXE -f $TMPFILE.cmd $TMPFILE 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT -+rm -rf $TMPFILE.cmd -+ -+$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 -+status=$? -+echo Exit status is $status >> $OUT.new -+sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT -+rm -f $OUT.new -+ -+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 IMAGE FSCK_OPT OUT EXP -+ -+else #if test -x $DEBUGFS_EXE; then -+ echo "$test_name: $test_description: skipped" -+fi -diff --git a/tests/j_short_trans/expect b/tests/j_short_trans/expect -new file mode 100644 -index 0000000..bcc8fe8 ---- /dev/null -+++ b/tests/j_short_trans/expect -@@ -0,0 +1,38 @@ -+Creating filesystem with 65536 4k blocks and 16384 inodes -+Superblock backups stored on blocks: -+ 32768 -+ -+Allocating group tables: done -+Writing inode tables: done -+Creating journal (4096 blocks): done -+Writing superblocks and filesystem accounting information: done -+ -+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/16384 files (0.0% non-contiguous), 5164/65536 blocks -+Exit status is 0 -+debugfs write journal -+debugfs: logdump -c -+Journal starts at block 1, transaction 1 -+Found expected sequence 1, type 1 (descriptor block) at block 1 -+Found expected sequence 1, type 2 (commit block) at block 6 -+No magic number at block 7: end of journal. -+test_filesys: recovering journal -+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: +(0--1050) +(32768--36880) -+Fix? yes -+ -+Inode bitmap differences: +(1--11) -+Fix? yes -+ -+ -+test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** -+test_filesys: 11/16384 files (0.0% non-contiguous), 5164/65536 blocks -+Exit status is 1 -diff --git a/tests/j_short_trans/name b/tests/j_short_trans/name -new file mode 100644 -index 0000000..730fbad ---- /dev/null -+++ b/tests/j_short_trans/name -@@ -0,0 +1 @@ -+transaction nuking the bitmaps -diff --git a/tests/j_short_trans/script b/tests/j_short_trans/script -new file mode 100644 -index 0000000..852e7a5 ---- /dev/null -+++ b/tests/j_short_trans/script -@@ -0,0 +1,61 @@ -+if test -x $DEBUGFS_EXE; then -+ -+FSCK_OPT=-fy -+OUT=$test_name.log -+if [ -f $test_dir/expect.gz ]; then -+ EXP=$test_name.tmp -+ gunzip < $test_dir/expect.gz > $EXP1 -+else -+ EXP=$test_dir/expect -+fi -+ -+cp /dev/null $OUT -+ -+$MKE2FS -F -o Linux -b 4096 -O has_journal -T ext4 $TMPFILE 65536 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT 2>&1 -+ -+$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 -+status=$? -+echo Exit status is $status >> $OUT.new -+sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT -+rm -f $OUT.new -+ -+bitmaps="$($DUMPE2FS $TMPFILE 2>&1 | grep 'bitmap at' | sed -e 's/^.*bitmap at \([0-9]*\).*$/\1/g' | tr '\n' ',')" -+ -+echo "debugfs write journal" >> $OUT -+echo "jo" > $TMPFILE.cmd -+echo "jw -b $bitmaps /dev/zero" >> $TMPFILE.cmd -+echo "jc" >> $TMPFILE.cmd -+$DEBUGFS_EXE -w -f $TMPFILE.cmd $TMPFILE 2>> $OUT.new > /dev/null -+sed -f $cmd_dir/filter.sed < $OUT.new >> $OUT -+rm -rf $OUT.new -+ -+test -d "$JOURNAL_DUMP_DIR" -a -w "$JOURNAL_DUMP_DIR" && cp "$TMPFILE" "$JOURNAL_DUMP_DIR/$test_name.img" -+echo "logdump -c" > $TMPFILE.cmd -+$DEBUGFS_EXE -f $TMPFILE.cmd $TMPFILE 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT -+rm -rf $TMPFILE.cmd -+ -+$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 -+status=$? -+echo Exit status is $status >> $OUT.new -+sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT -+rm -f $OUT.new -+ -+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 IMAGE FSCK_OPT OUT EXP -+ -+else #if test -x $DEBUGFS_EXE; then -+ echo "$test_name: $test_description: skipped" -+fi -diff --git a/tests/j_short_trans_64bit/expect b/tests/j_short_trans_64bit/expect -new file mode 100644 -index 0000000..f9971eb ---- /dev/null -+++ b/tests/j_short_trans_64bit/expect -@@ -0,0 +1,40 @@ -+Creating filesystem with 65536 4k blocks and 16384 inodes -+Superblock backups stored on blocks: -+ 32768 -+ -+Allocating group tables: done -+Writing inode tables: done -+Creating journal (4096 blocks): done -+Writing superblocks and filesystem accounting information: done -+ -+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/16384 files (0.0% non-contiguous), 5196/65536 blocks -+Exit status is 0 -+Journal features: (none) -+debugfs write journal -+Journal features: journal_64bit -+debugfs: logdump -c -+Journal starts at block 1, transaction 1 -+Found expected sequence 1, type 1 (descriptor block) at block 1 -+Found expected sequence 1, type 2 (commit block) at block 6 -+No magic number at block 7: end of journal. -+test_filesys: recovering journal -+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: +(0--1066) +(32768--36896) -+Fix? yes -+ -+Inode bitmap differences: +(1--11) -+Fix? yes -+ -+ -+test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** -+test_filesys: 11/16384 files (0.0% non-contiguous), 5196/65536 blocks -+Exit status is 1 -diff --git a/tests/j_short_trans_64bit/name b/tests/j_short_trans_64bit/name -new file mode 100644 -index 0000000..17b70d0 ---- /dev/null -+++ b/tests/j_short_trans_64bit/name -@@ -0,0 +1 @@ -+transaction nuking the bitmaps on 64bit -diff --git a/tests/j_short_trans_64bit/script b/tests/j_short_trans_64bit/script -new file mode 100644 -index 0000000..994fa21 ---- /dev/null -+++ b/tests/j_short_trans_64bit/script -@@ -0,0 +1,65 @@ -+if test -x $DEBUGFS_EXE; then -+ -+FSCK_OPT=-fy -+OUT=$test_name.log -+if [ -f $test_dir/expect.gz ]; then -+ EXP=$test_name.tmp -+ gunzip < $test_dir/expect.gz > $EXP1 -+else -+ EXP=$test_dir/expect -+fi -+ -+cp /dev/null $OUT -+ -+$MKE2FS -F -o Linux -b 4096 -O 64bit,has_journal -T ext4 $TMPFILE 65536 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT 2>&1 -+ -+$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 -+status=$? -+echo Exit status is $status >> $OUT.new -+sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT -+rm -f $OUT.new -+ -+bitmaps="$($DUMPE2FS $TMPFILE 2>&1 | grep 'bitmap at' | sed -e 's/^.*bitmap at \([0-9]*\).*$/\1/g' | tr '\n' ',')" -+ -+$DUMPE2FS $TMPFILE 2>&1 | grep '^Journal features:' >> $OUT -+ -+echo "debugfs write journal" >> $OUT -+echo "jo" > $TMPFILE.cmd -+echo "jw -b $bitmaps /dev/zero" >> $TMPFILE.cmd -+echo "jc" >> $TMPFILE.cmd -+$DEBUGFS_EXE -w -f $TMPFILE.cmd $TMPFILE 2>> $OUT.new > /dev/null -+sed -f $cmd_dir/filter.sed < $OUT.new >> $OUT -+rm -rf $OUT.new -+ -+$DUMPE2FS $TMPFILE 2>&1 | grep '^Journal features:' >> $OUT -+ -+test -d "$JOURNAL_DUMP_DIR" -a -w "$JOURNAL_DUMP_DIR" && cp "$TMPFILE" "$JOURNAL_DUMP_DIR/$test_name.img" -+echo "logdump -c" > $TMPFILE.cmd -+$DEBUGFS_EXE -f $TMPFILE.cmd $TMPFILE 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT -+rm -rf $TMPFILE.cmd -+ -+$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 -+status=$? -+echo Exit status is $status >> $OUT.new -+sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT -+rm -f $OUT.new -+ -+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 IMAGE FSCK_OPT OUT EXP -+ -+else #if test -x $DEBUGFS_EXE; then -+ echo "$test_name: $test_description: skipped" -+fi -diff --git a/tests/j_short_trans_mcsum_64bit/expect b/tests/j_short_trans_mcsum_64bit/expect -new file mode 100644 -index 0000000..d876ff0 ---- /dev/null -+++ b/tests/j_short_trans_mcsum_64bit/expect -@@ -0,0 +1,40 @@ -+Creating filesystem with 131072 4k blocks and 32768 inodes -+Superblock backups stored on blocks: -+ 32768, 98304 -+ -+Allocating group tables: done -+Writing inode tables: done -+Creating journal (4096 blocks): done -+Writing superblocks and filesystem accounting information: done -+ -+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/32768 files (0.0% non-contiguous), 6353/131072 blocks -+Exit status is 0 -+Journal features: (none) -+debugfs write journal -+Journal features: journal_64bit journal_checksum_v3 -+debugfs: logdump -c -+Journal starts at block 1, transaction 1 -+Found expected sequence 1, type 1 (descriptor block) at block 1 -+Found expected sequence 1, type 2 (commit block) at block 10 -+No magic number at block 11: end of journal. -+test_filesys: recovering journal -+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: +(0--65) +(67--69) +(71--584) +(1097--2126) +(65536--69631) +(98304--98368) -+Fix? yes -+ -+Inode bitmap differences: +(1--11) -+Fix? yes -+ -+ -+test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** -+test_filesys: 11/32768 files (0.0% non-contiguous), 6353/131072 blocks -+Exit status is 1 -diff --git a/tests/j_short_trans_mcsum_64bit/name b/tests/j_short_trans_mcsum_64bit/name -new file mode 100644 -index 0000000..4751cc2 ---- /dev/null -+++ b/tests/j_short_trans_mcsum_64bit/name -@@ -0,0 +1 @@ -+transaction nuking the bitmaps on 64bit,metadata_csum -diff --git a/tests/j_short_trans_mcsum_64bit/script b/tests/j_short_trans_mcsum_64bit/script -new file mode 100644 -index 0000000..024346a ---- /dev/null -+++ b/tests/j_short_trans_mcsum_64bit/script -@@ -0,0 +1,65 @@ -+if test -x $DEBUGFS_EXE; then -+ -+FSCK_OPT=-fy -+OUT=$test_name.log -+if [ -f $test_dir/expect.gz ]; then -+ EXP=$test_name.tmp -+ gunzip < $test_dir/expect.gz > $EXP1 -+else -+ EXP=$test_dir/expect -+fi -+ -+cp /dev/null $OUT -+ -+$MKE2FS -F -o Linux -b 4096 -O 64bit,has_journal,metadata_csum -T ext4 $TMPFILE 131072 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT 2>&1 -+ -+$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 -+status=$? -+echo Exit status is $status >> $OUT.new -+sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT -+rm -f $OUT.new -+ -+bitmaps="$($DUMPE2FS $TMPFILE 2>&1 | grep 'bitmap at' | sed -e 's/^.*bitmap at \([0-9]*\).*$/\1/g' | tr '\n' ',')" -+ -+$DUMPE2FS $TMPFILE 2>&1 | grep '^Journal features:' >> $OUT -+ -+echo "debugfs write journal" >> $OUT -+echo "jo -c" > $TMPFILE.cmd -+echo "jw -b $bitmaps /dev/zero" >> $TMPFILE.cmd -+echo "jc" >> $TMPFILE.cmd -+$DEBUGFS_EXE -w -f $TMPFILE.cmd $TMPFILE 2>> $OUT.new > /dev/null -+sed -f $cmd_dir/filter.sed < $OUT.new >> $OUT -+rm -rf $OUT.new -+ -+$DUMPE2FS $TMPFILE 2>&1 | grep '^Journal features:' >> $OUT -+ -+test -d "$JOURNAL_DUMP_DIR" -a -w "$JOURNAL_DUMP_DIR" && cp "$TMPFILE" "$JOURNAL_DUMP_DIR/$test_name.img" -+echo "logdump -c" > $TMPFILE.cmd -+$DEBUGFS_EXE -f $TMPFILE.cmd $TMPFILE 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT -+rm -rf $TMPFILE.cmd -+ -+$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 -+status=$? -+echo Exit status is $status >> $OUT.new -+sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT -+rm -f $OUT.new -+ -+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 IMAGE FSCK_OPT OUT EXP -+ -+else #if test -x $DEBUGFS_EXE; then -+ echo "$test_name: $test_description: skipped" -+fi -diff --git a/tests/j_short_trans_old_csum/expect b/tests/j_short_trans_old_csum/expect -new file mode 100644 -index 0000000..29ac27f ---- /dev/null -+++ b/tests/j_short_trans_old_csum/expect -@@ -0,0 +1,40 @@ -+Creating filesystem with 65536 4k blocks and 16384 inodes -+Superblock backups stored on blocks: -+ 32768 -+ -+Allocating group tables: done -+Writing inode tables: done -+Creating journal (4096 blocks): done -+Writing superblocks and filesystem accounting information: done -+ -+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/16384 files (0.0% non-contiguous), 5164/65536 blocks -+Exit status is 0 -+Journal features: (none) -+debugfs write journal -+Journal features: journal_checksum -+debugfs: logdump -c -+Journal starts at block 1, transaction 1 -+Found expected sequence 1, type 1 (descriptor block) at block 1 -+Found expected sequence 1, type 2 (commit block) at block 6 -+No magic number at block 7: end of journal. -+test_filesys: recovering journal -+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: +(0--1050) +(32768--36880) -+Fix? yes -+ -+Inode bitmap differences: +(1--11) -+Fix? yes -+ -+ -+test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** -+test_filesys: 11/16384 files (0.0% non-contiguous), 5164/65536 blocks -+Exit status is 1 -diff --git a/tests/j_short_trans_old_csum/name b/tests/j_short_trans_old_csum/name -new file mode 100644 -index 0000000..2e81f94 ---- /dev/null -+++ b/tests/j_short_trans_old_csum/name -@@ -0,0 +1 @@ -+transaction nuking the bitmaps with old journal checksum (v1) -diff --git a/tests/j_short_trans_old_csum/script b/tests/j_short_trans_old_csum/script -new file mode 100644 -index 0000000..56f8bcb ---- /dev/null -+++ b/tests/j_short_trans_old_csum/script -@@ -0,0 +1,65 @@ -+if test -x $DEBUGFS_EXE; then -+ -+FSCK_OPT=-fy -+OUT=$test_name.log -+if [ -f $test_dir/expect.gz ]; then -+ EXP=$test_name.tmp -+ gunzip < $test_dir/expect.gz > $EXP1 -+else -+ EXP=$test_dir/expect -+fi -+ -+cp /dev/null $OUT -+ -+$MKE2FS -F -o Linux -b 4096 -O has_journal -T ext4 $TMPFILE 65536 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT 2>&1 -+ -+$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 -+status=$? -+echo Exit status is $status >> $OUT.new -+sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT -+rm -f $OUT.new -+ -+bitmaps="$($DUMPE2FS $TMPFILE 2>&1 | grep 'bitmap at' | sed -e 's/^.*bitmap at \([0-9]*\).*$/\1/g' | tr '\n' ',')" -+ -+$DUMPE2FS $TMPFILE 2>&1 | grep '^Journal features:' >> $OUT -+ -+echo "debugfs write journal" >> $OUT -+echo "jo -c" > $TMPFILE.cmd -+echo "jw -b $bitmaps /dev/zero" >> $TMPFILE.cmd -+echo "jc" >> $TMPFILE.cmd -+$DEBUGFS_EXE -w -f $TMPFILE.cmd $TMPFILE 2>> $OUT.new > /dev/null -+sed -f $cmd_dir/filter.sed < $OUT.new >> $OUT -+rm -rf $OUT.new -+ -+$DUMPE2FS $TMPFILE 2>&1 | grep '^Journal features:' >> $OUT -+ -+test -d "$JOURNAL_DUMP_DIR" -a -w "$JOURNAL_DUMP_DIR" && cp "$TMPFILE" "$JOURNAL_DUMP_DIR/$test_name.img" -+echo "logdump -c" > $TMPFILE.cmd -+$DEBUGFS_EXE -f $TMPFILE.cmd $TMPFILE 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT -+rm -rf $TMPFILE.cmd -+ -+$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 -+status=$? -+echo Exit status is $status >> $OUT.new -+sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT -+rm -f $OUT.new -+ -+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 IMAGE FSCK_OPT OUT EXP -+ -+else #if test -x $DEBUGFS_EXE; then -+ echo "$test_name: $test_description: skipped" -+fi -diff --git a/tests/j_short_trans_open_recover/expect b/tests/j_short_trans_open_recover/expect -new file mode 100644 -index 0000000..be6e363 ---- /dev/null -+++ b/tests/j_short_trans_open_recover/expect -@@ -0,0 +1,43 @@ -+Creating filesystem with 65536 4k blocks and 16384 inodes -+Superblock backups stored on blocks: -+ 32768 -+ -+Allocating group tables: done -+Writing inode tables: done -+Creating journal (4096 blocks): done -+Writing superblocks and filesystem accounting information: done -+ -+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/16384 files (0.0% non-contiguous), 5164/65536 blocks -+Exit status is 0 -+debugfs write journal -+debugfs: logdump -c -+Journal starts at block 1, transaction 1 -+Found expected sequence 1, type 1 (descriptor block) at block 1 -+Found expected sequence 1, type 2 (commit block) at block 6 -+No magic number at block 7: end of journal. -+debugfs can't recover open journal -+debugfs: jo -+debugfs: jr -+Please close the journal before recovering it. -+debugfs: jc -+test_filesys: recovering journal -+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: +(0--1050) +(32768--36880) -+Fix? yes -+ -+Inode bitmap differences: +(1--11) -+Fix? yes -+ -+ -+test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** -+test_filesys: 11/16384 files (0.0% non-contiguous), 5164/65536 blocks -+Exit status is 1 -diff --git a/tests/j_short_trans_open_recover/name b/tests/j_short_trans_open_recover/name -new file mode 100644 -index 0000000..892e95c ---- /dev/null -+++ b/tests/j_short_trans_open_recover/name -@@ -0,0 +1 @@ -+ensure we can't recover the journal with journal open -diff --git a/tests/j_short_trans_open_recover/script b/tests/j_short_trans_open_recover/script -new file mode 100644 -index 0000000..2a016df ---- /dev/null -+++ b/tests/j_short_trans_open_recover/script -@@ -0,0 +1,69 @@ -+if test -x $DEBUGFS_EXE; then -+ -+FSCK_OPT=-fy -+OUT=$test_name.log -+if [ -f $test_dir/expect.gz ]; then -+ EXP=$test_name.tmp -+ gunzip < $test_dir/expect.gz > $EXP1 -+else -+ EXP=$test_dir/expect -+fi -+ -+cp /dev/null $OUT -+ -+$MKE2FS -F -o Linux -b 4096 -O has_journal -T ext4 $TMPFILE 65536 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT 2>&1 -+ -+$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 -+status=$? -+echo Exit status is $status >> $OUT.new -+sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT -+rm -f $OUT.new -+ -+bitmaps="$($DUMPE2FS $TMPFILE 2>&1 | grep 'bitmap at' | sed -e 's/^.*bitmap at \([0-9]*\).*$/\1/g' | tr '\n' ',')" -+ -+echo "debugfs write journal" >> $OUT -+echo "jo" > $TMPFILE.cmd -+echo "jw -b $bitmaps /dev/zero" >> $TMPFILE.cmd -+echo "jc" >> $TMPFILE.cmd -+$DEBUGFS_EXE -w -f $TMPFILE.cmd $TMPFILE 2>> $OUT.new > /dev/null -+sed -f $cmd_dir/filter.sed < $OUT.new >> $OUT -+rm -rf $OUT.new -+ -+test -d "$JOURNAL_DUMP_DIR" -a -w "$JOURNAL_DUMP_DIR" && cp "$TMPFILE" "$JOURNAL_DUMP_DIR/$test_name.img" -+echo "logdump -c" > $TMPFILE.cmd -+$DEBUGFS_EXE -f $TMPFILE.cmd $TMPFILE 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT -+rm -rf $TMPFILE.cmd -+ -+echo "debugfs can't recover open journal" >> $OUT -+echo "jo" > $TMPFILE.cmd -+echo "jr" >> $TMPFILE.cmd -+echo "jc" >> $TMPFILE.cmd -+$DEBUGFS_EXE -w -f $TMPFILE.cmd $TMPFILE > $OUT.new 2>&1 -+sed -f $cmd_dir/filter.sed < $OUT.new >> $OUT -+rm -rf $OUT.new -+ -+$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 -+status=$? -+echo Exit status is $status >> $OUT.new -+sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT -+rm -f $OUT.new -+ -+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 IMAGE FSCK_OPT OUT EXP -+ -+else #if test -x $DEBUGFS_EXE; then -+ echo "$test_name: $test_description: skipped" -+fi -diff --git a/tests/j_short_trans_recover/expect b/tests/j_short_trans_recover/expect -new file mode 100644 -index 0000000..7586733 ---- /dev/null -+++ b/tests/j_short_trans_recover/expect -@@ -0,0 +1,40 @@ -+Creating filesystem with 65536 4k blocks and 16384 inodes -+Superblock backups stored on blocks: -+ 32768 -+ -+Allocating group tables: done -+Writing inode tables: done -+Creating journal (4096 blocks): done -+Writing superblocks and filesystem accounting information: done -+ -+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/16384 files (0.0% non-contiguous), 5164/65536 blocks -+Exit status is 0 -+debugfs write journal -+debugfs: logdump -c -+Journal starts at block 1, transaction 1 -+Found expected sequence 1, type 1 (descriptor block) at block 1 -+Found expected sequence 1, type 2 (commit block) at block 7 -+Found expected sequence 2, type 5 (revoke table) at block 8 -+Found expected sequence 2, type 2 (commit block) at block 9 -+No magic number at block 10: end of journal. -+debugfs recover journal -+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: +(0--1050) +(32768--36880) -+Fix? yes -+ -+Inode bitmap differences: +(1--11) -+Fix? yes -+ -+ -+test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** -+test_filesys: 11/16384 files (0.0% non-contiguous), 5164/65536 blocks -+Exit status is 1 -diff --git a/tests/j_short_trans_recover/name b/tests/j_short_trans_recover/name -new file mode 100644 -index 0000000..54e3553 ---- /dev/null -+++ b/tests/j_short_trans_recover/name -@@ -0,0 +1 @@ -+transaction nuking the bitmaps (debugfs recovery) -diff --git a/tests/j_short_trans_recover/script b/tests/j_short_trans_recover/script -new file mode 100644 -index 0000000..33d2345 ---- /dev/null -+++ b/tests/j_short_trans_recover/script -@@ -0,0 +1,70 @@ -+if test -x $DEBUGFS_EXE; then -+ -+FSCK_OPT=-fy -+OUT=$test_name.log -+if [ -f $test_dir/expect.gz ]; then -+ EXP=$test_name.tmp -+ gunzip < $test_dir/expect.gz > $EXP1 -+else -+ EXP=$test_dir/expect -+fi -+ -+cp /dev/null $OUT -+ -+$MKE2FS -F -o Linux -b 4096 -O has_journal -T ext4 $TMPFILE 65536 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT 2>&1 -+ -+$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 -+status=$? -+echo Exit status is $status >> $OUT.new -+sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT -+rm -f $OUT.new -+ -+bitmaps="$($DUMPE2FS $TMPFILE 2>&1 | grep 'bitmap at' | sed -e 's/^.*bitmap at \([0-9]*\).*$/\1/g' | tr '\n' ',')" -+ -+echo "debugfs write journal" >> $OUT -+echo "jo" > $TMPFILE.cmd -+echo "jw -b 333,$bitmaps /dev/zero" >> $TMPFILE.cmd -+echo "jc" >> $TMPFILE.cmd -+echo "jo" >> $TMPFILE.cmd -+echo "jw -r 333" >> $TMPFILE.cmd -+echo "jc" >> $TMPFILE.cmd -+$DEBUGFS_EXE -w -f $TMPFILE.cmd $TMPFILE 2>> $OUT.new > /dev/null -+sed -f $cmd_dir/filter.sed < $OUT.new >> $OUT -+rm -rf $OUT.new -+ -+test -d "$JOURNAL_DUMP_DIR" -a -w "$JOURNAL_DUMP_DIR" && cp "$TMPFILE" "$JOURNAL_DUMP_DIR/$test_name.img" -+echo "logdump -c" > $TMPFILE.cmd -+$DEBUGFS_EXE -f $TMPFILE.cmd $TMPFILE 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT -+rm -rf $TMPFILE.cmd -+ -+echo "debugfs recover journal" >> $OUT -+echo "jr" > $TMPFILE.cmd -+$DEBUGFS_EXE -w -f $TMPFILE.cmd $TMPFILE 2>> $OUT.new > /dev/null -+sed -f $cmd_dir/filter.sed < $OUT.new >> $OUT -+rm -rf $OUT.new -+ -+$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 -+status=$? -+echo Exit status is $status >> $OUT.new -+sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT -+rm -f $OUT.new -+ -+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 IMAGE FSCK_OPT OUT EXP -+ -+else #if test -x $DEBUGFS_EXE; then -+ echo "$test_name: $test_description: skipped" -+fi -diff --git a/tests/j_short_trans_recover_mcsum_64bit/expect b/tests/j_short_trans_recover_mcsum_64bit/expect -new file mode 100644 -index 0000000..9cc3309 ---- /dev/null -+++ b/tests/j_short_trans_recover_mcsum_64bit/expect -@@ -0,0 +1,42 @@ -+Creating filesystem with 131072 4k blocks and 32768 inodes -+Superblock backups stored on blocks: -+ 32768, 98304 -+ -+Allocating group tables: done -+Writing inode tables: done -+Creating journal (4096 blocks): done -+Writing superblocks and filesystem accounting information: done -+ -+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/32768 files (0.0% non-contiguous), 6353/131072 blocks -+Exit status is 0 -+Journal features: (none) -+debugfs write journal -+Journal features: journal_incompat_revoke journal_64bit journal_checksum_v3 -+debugfs: logdump -c -+Journal starts at block 1, transaction 1 -+Found expected sequence 1, type 1 (descriptor block) at block 1 -+Found expected sequence 1, type 2 (commit block) at block 11 -+Found expected sequence 2, type 5 (revoke table) at block 12 -+Found expected sequence 2, type 2 (commit block) at block 13 -+No magic number at block 14: end of journal. -+debugfs recover journal -+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: +(0--65) +(67--69) +(71--584) +(1097--2126) +(65536--69631) +(98304--98368) -+Fix? yes -+ -+Inode bitmap differences: +(1--11) -+Fix? yes -+ -+ -+test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** -+test_filesys: 11/32768 files (0.0% non-contiguous), 6353/131072 blocks -+Exit status is 1 -diff --git a/tests/j_short_trans_recover_mcsum_64bit/name b/tests/j_short_trans_recover_mcsum_64bit/name -new file mode 100644 -index 0000000..7ccdcb0 ---- /dev/null -+++ b/tests/j_short_trans_recover_mcsum_64bit/name -@@ -0,0 +1 @@ -+uncommitted transaction nuking the bitmaps on 64bit,metadata_csum (debugfs recover) -diff --git a/tests/j_short_trans_recover_mcsum_64bit/script b/tests/j_short_trans_recover_mcsum_64bit/script -new file mode 100644 -index 0000000..b6c8c49 ---- /dev/null -+++ b/tests/j_short_trans_recover_mcsum_64bit/script -@@ -0,0 +1,74 @@ -+if test -x $DEBUGFS_EXE; then -+ -+FSCK_OPT=-fy -+OUT=$test_name.log -+if [ -f $test_dir/expect.gz ]; then -+ EXP=$test_name.tmp -+ gunzip < $test_dir/expect.gz > $EXP1 -+else -+ EXP=$test_dir/expect -+fi -+ -+cp /dev/null $OUT -+ -+$MKE2FS -F -o Linux -b 4096 -O 64bit,has_journal,metadata_csum -T ext4 $TMPFILE 131072 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT 2>&1 -+ -+$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 -+status=$? -+echo Exit status is $status >> $OUT.new -+sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT -+rm -f $OUT.new -+ -+bitmaps="$($DUMPE2FS $TMPFILE 2>&1 | grep 'bitmap at' | sed -e 's/^.*bitmap at \([0-9]*\).*$/\1/g' | tr '\n' ',')" -+ -+$DUMPE2FS $TMPFILE 2>&1 | grep '^Journal features:' >> $OUT -+ -+echo "debugfs write journal" >> $OUT -+echo "jo -c" > $TMPFILE.cmd -+echo "jw -b 333,$bitmaps /dev/zero" >> $TMPFILE.cmd -+echo "jc" >> $TMPFILE.cmd -+echo "jo" >> $TMPFILE.cmd -+echo "jw -r 333" >> $TMPFILE.cmd -+echo "jc" >> $TMPFILE.cmd -+$DEBUGFS_EXE -w -f $TMPFILE.cmd $TMPFILE 2>> $OUT.new > /dev/null -+sed -f $cmd_dir/filter.sed < $OUT.new >> $OUT -+rm -rf $OUT.new -+ -+$DUMPE2FS $TMPFILE 2>&1 | grep '^Journal features:' >> $OUT -+ -+test -d "$JOURNAL_DUMP_DIR" -a -w "$JOURNAL_DUMP_DIR" && cp "$TMPFILE" "$JOURNAL_DUMP_DIR/$test_name.img" -+echo "logdump -c" > $TMPFILE.cmd -+$DEBUGFS_EXE -f $TMPFILE.cmd $TMPFILE 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT -+rm -rf $TMPFILE.cmd -+ -+echo "debugfs recover journal" >> $OUT -+echo "jr" > $TMPFILE.cmd -+$DEBUGFS_EXE -w -f $TMPFILE.cmd $TMPFILE 2>> $OUT.new > /dev/null -+sed -f $cmd_dir/filter.sed < $OUT.new >> $OUT -+rm -rf $OUT.new -+ -+$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 -+status=$? -+echo Exit status is $status >> $OUT.new -+sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT -+rm -f $OUT.new -+ -+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 IMAGE FSCK_OPT OUT EXP -+ -+else #if test -x $DEBUGFS_EXE; then -+ echo "$test_name: $test_description: skipped" -+fi -diff --git a/tests/j_short_uncommitted_trans/expect b/tests/j_short_uncommitted_trans/expect -new file mode 100644 -index 0000000..dedddb5 ---- /dev/null -+++ b/tests/j_short_uncommitted_trans/expect -@@ -0,0 +1,26 @@ -+Creating filesystem with 65536 4k blocks and 16384 inodes -+Superblock backups stored on blocks: -+ 32768 -+ -+Allocating group tables: done -+Writing inode tables: done -+Creating journal (4096 blocks): done -+Writing superblocks and filesystem accounting information: done -+ -+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/16384 files (0.0% non-contiguous), 5164/65536 blocks -+Exit status is 0 -+debugfs write journal -+debugfs: logdump -c -+Journal starts at block 0, transaction 1 -+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/16384 files (0.0% non-contiguous), 5164/65536 blocks -+Exit status is 0 -diff --git a/tests/j_short_uncommitted_trans/name b/tests/j_short_uncommitted_trans/name -new file mode 100644 -index 0000000..b617231 ---- /dev/null -+++ b/tests/j_short_uncommitted_trans/name -@@ -0,0 +1 @@ -+uncommitted transaction nuking bitmaps -diff --git a/tests/j_short_uncommitted_trans/script b/tests/j_short_uncommitted_trans/script -new file mode 100644 -index 0000000..a1fc3b4 ---- /dev/null -+++ b/tests/j_short_uncommitted_trans/script -@@ -0,0 +1,61 @@ -+if test -x $DEBUGFS_EXE; then -+ -+FSCK_OPT=-fy -+OUT=$test_name.log -+if [ -f $test_dir/expect.gz ]; then -+ EXP=$test_name.tmp -+ gunzip < $test_dir/expect.gz > $EXP1 -+else -+ EXP=$test_dir/expect -+fi -+ -+cp /dev/null $OUT -+ -+$MKE2FS -F -o Linux -b 4096 -O has_journal -T ext4 $TMPFILE 65536 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT 2>&1 -+ -+$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 -+status=$? -+echo Exit status is $status >> $OUT.new -+sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT -+rm -f $OUT.new -+ -+bitmaps="$($DUMPE2FS $TMPFILE 2>&1 | grep 'bitmap at' | sed -e 's/^.*bitmap at \([0-9]*\).*$/\1/g' | tr '\n' ',')" -+ -+echo "debugfs write journal" >> $OUT -+echo "jo" > $TMPFILE.cmd -+echo "jw -b $bitmaps -c /dev/zero" >> $TMPFILE.cmd -+echo "jc" >> $TMPFILE.cmd -+$DEBUGFS_EXE -w -f $TMPFILE.cmd $TMPFILE 2>> $OUT.new > /dev/null -+sed -f $cmd_dir/filter.sed < $OUT.new >> $OUT -+rm -rf $OUT.new -+ -+test -d "$JOURNAL_DUMP_DIR" -a -w "$JOURNAL_DUMP_DIR" && cp "$TMPFILE" "$JOURNAL_DUMP_DIR/$test_name.img" -+echo "logdump -c" > $TMPFILE.cmd -+$DEBUGFS_EXE -f $TMPFILE.cmd $TMPFILE 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT -+rm -rf $TMPFILE.cmd -+ -+$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 -+status=$? -+echo Exit status is $status >> $OUT.new -+sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT -+rm -f $OUT.new -+ -+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 IMAGE FSCK_OPT OUT EXP -+ -+else #if test -x $DEBUGFS_EXE; then -+ echo "$test_name: $test_description: skipped" -+fi -diff --git a/tests/j_short_uncommitted_trans_mcsum_64bit/expect b/tests/j_short_uncommitted_trans_mcsum_64bit/expect -new file mode 100644 -index 0000000..3effc94 ---- /dev/null -+++ b/tests/j_short_uncommitted_trans_mcsum_64bit/expect -@@ -0,0 +1,28 @@ -+Creating filesystem with 131072 4k blocks and 32768 inodes -+Superblock backups stored on blocks: -+ 32768, 98304 -+ -+Allocating group tables: done -+Writing inode tables: done -+Creating journal (4096 blocks): done -+Writing superblocks and filesystem accounting information: done -+ -+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/32768 files (0.0% non-contiguous), 6353/131072 blocks -+Exit status is 0 -+Journal features: (none) -+debugfs write journal -+Journal features: journal_64bit journal_checksum_v3 -+debugfs: logdump -c -+Journal starts at block 0, transaction 1 -+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/32768 files (0.0% non-contiguous), 6353/131072 blocks -+Exit status is 0 -diff --git a/tests/j_short_uncommitted_trans_mcsum_64bit/name b/tests/j_short_uncommitted_trans_mcsum_64bit/name -new file mode 100644 -index 0000000..9771f4b ---- /dev/null -+++ b/tests/j_short_uncommitted_trans_mcsum_64bit/name -@@ -0,0 +1 @@ -+uncommitted transaction nuking the bitmaps on 64bit,metadata_csum -diff --git a/tests/j_short_uncommitted_trans_mcsum_64bit/script b/tests/j_short_uncommitted_trans_mcsum_64bit/script -new file mode 100644 -index 0000000..a0b8c7f ---- /dev/null -+++ b/tests/j_short_uncommitted_trans_mcsum_64bit/script -@@ -0,0 +1,65 @@ -+if test -x $DEBUGFS_EXE; then -+ -+FSCK_OPT=-fy -+OUT=$test_name.log -+if [ -f $test_dir/expect.gz ]; then -+ EXP=$test_name.tmp -+ gunzip < $test_dir/expect.gz > $EXP1 -+else -+ EXP=$test_dir/expect -+fi -+ -+cp /dev/null $OUT -+ -+$MKE2FS -F -o Linux -b 4096 -O 64bit,has_journal,metadata_csum -T ext4 $TMPFILE 131072 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT 2>&1 -+ -+$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 -+status=$? -+echo Exit status is $status >> $OUT.new -+sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT -+rm -f $OUT.new -+ -+bitmaps="$($DUMPE2FS $TMPFILE 2>&1 | grep 'bitmap at' | sed -e 's/^.*bitmap at \([0-9]*\).*$/\1/g' | tr '\n' ',')" -+ -+$DUMPE2FS $TMPFILE 2>&1 | grep '^Journal features:' >> $OUT -+ -+echo "debugfs write journal" >> $OUT -+echo "jo -c" > $TMPFILE.cmd -+echo "jw -b $bitmaps /dev/zero -c" >> $TMPFILE.cmd -+echo "jc" >> $TMPFILE.cmd -+$DEBUGFS_EXE -w -f $TMPFILE.cmd $TMPFILE 2>> $OUT.new > /dev/null -+sed -f $cmd_dir/filter.sed < $OUT.new >> $OUT -+rm -rf $OUT.new -+ -+$DUMPE2FS $TMPFILE 2>&1 | grep '^Journal features:' >> $OUT -+ -+test -d "$JOURNAL_DUMP_DIR" -a -w "$JOURNAL_DUMP_DIR" && cp "$TMPFILE" "$JOURNAL_DUMP_DIR/$test_name.img" -+echo "logdump -c" > $TMPFILE.cmd -+$DEBUGFS_EXE -f $TMPFILE.cmd $TMPFILE 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT -+rm -rf $TMPFILE.cmd -+ -+$FSCK -fy -N test_filesys $TMPFILE > $OUT.new 2>&1 -+status=$? -+echo Exit status is $status >> $OUT.new -+sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" $OUT.new >> $OUT -+rm -f $OUT.new -+ -+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 IMAGE FSCK_OPT OUT EXP -+ -+else #if test -x $DEBUGFS_EXE; then -+ echo "$test_name: $test_description: skipped" -+fi -diff --git a/tests/m_64bit_flexbg/expect.1 b/tests/m_64bit_flexbg/expect.1 -index 3635318..cfa3bc9 100644 ---- a/tests/m_64bit_flexbg/expect.1 -+++ b/tests/m_64bit_flexbg/expect.1 -@@ -48,7 +48,8 @@ Default directory hash: half_md4 - Group 0: (Blocks 1-1023) - Primary superblock at 1, Group descriptors at 2-2 - Reserved GDT blocks at 3-9 -- Block bitmap at 10 (+9), Inode bitmap at 26 (+25) -+ Block bitmap at 10 (+9) -+ Inode bitmap at 26 (+25) - Inode table at 42-57 (+41) - 982 free blocks, 117 free inodes, 2 directories - Free blocks: 24-25, 28-41, 58-1023 -diff --git a/tests/m_bigjournal/expect.1 b/tests/m_bigjournal/expect.1 -index 7246739..61d85f9 100644 ---- a/tests/m_bigjournal/expect.1 -+++ b/tests/m_bigjournal/expect.1 -@@ -52,8 +52,8 @@ Group 0: (Blocks 0-32767) - Reserved GDT blocks at 2-672 - Block bitmap at 673 (+673), Inode bitmap at 757 (+757) - Inode table at 841-841 (+841) -- 31836 free blocks, 5 free inodes, 2 directories, 5 unused inodes -- Free blocks: 932-32767 -+ 31837 free blocks, 5 free inodes, 2 directories, 5 unused inodes -+ Free blocks: 931-32767 - Free inodes: 12-16 - Group 1: (Blocks 32768-65535) [INODE_UNINIT, BLOCK_UNINIT] - Backup superblock at 32768, Group descriptors at 32769-32769 -@@ -297,11 +297,11 @@ Group 38: (Blocks 1245184-1277951) [INODE_UNINIT, BLOCK_UNINIT] - 32768 free blocks, 16 free inodes, 0 directories, 16 unused inodes - Free blocks: 1245184-1277951 - Free inodes: 609-624 --Group 39: (Blocks 1277952-1310719) [INODE_UNINIT, BLOCK_UNINIT] -+Group 39: (Blocks 1277952-1310719) [INODE_UNINIT] - Block bitmap at 712 (bg #0 + 712), Inode bitmap at 796 (bg #0 + 796) - Inode table at 880-880 (bg #0 + 880) -- 32768 free blocks, 16 free inodes, 0 directories, 16 unused inodes -- Free blocks: 1277952-1310719 -+ 32767 free blocks, 16 free inodes, 0 directories, 16 unused inodes -+ Free blocks: 1277952-1310718 - Free inodes: 625-640 - Group 40: (Blocks 1310720-1343487) [INODE_UNINIT] - Block bitmap at 713 (bg #0 + 713), Inode bitmap at 797 (bg #0 + 797) -diff --git a/tests/m_bigjournal/script b/tests/m_bigjournal/script -index 4c1ed9a..96ea082 100644 ---- a/tests/m_bigjournal/script -+++ b/tests/m_bigjournal/script -@@ -1,8 +1,12 @@ - DESCRIPTION="journal over 4GB in size" - FS_SIZE=11000000 -+DUMPE2FS_IGNORE_80COL=1 -+export DUMPE2FS_IGNORE_80COL - MKE2FS_OPTS="-t ext4 -G 512 -N 1280 -J size=5000 -q -E lazy_journal_init,lazy_itable_init,nodiscard" - if [ $(uname -s) = "Darwin" ]; then -+ # creates a 44GB filesystem - echo "$test_name: $DESCRIPTION: skipped for HFS+ (no sparse files)" - return 0 - fi - . $cmd_dir/run_mke2fs -+unset DUMPE2FS_IGNORE_80COL -diff --git a/tests/m_dasd_bs/expect.1 b/tests/m_dasd_bs/expect.1 -index 75a401d..0e55e8f 100644 ---- a/tests/m_dasd_bs/expect.1 -+++ b/tests/m_dasd_bs/expect.1 -@@ -48,7 +48,8 @@ Default directory hash: half_md4 - Group 0: (Blocks 0-16383) - Primary superblock at 0, Group descriptors at 1-1 - Reserved GDT blocks at 2-32 -- Block bitmap at 33 (+33), Inode bitmap at 34 (+34) -+ Block bitmap at 33 (+33) -+ Inode bitmap at 34 (+34) - Inode table at 35-546 (+35) - 15827 free blocks, 8181 free inodes, 2 directories - Free blocks: 557-16383 -@@ -56,7 +57,8 @@ Group 0: (Blocks 0-16383) - Group 1: (Blocks 16384-32767) - Backup superblock at 16384, Group descriptors at 16385-16385 - Reserved GDT blocks at 16386-16416 -- Block bitmap at 16417 (+33), Inode bitmap at 16418 (+34) -+ Block bitmap at 16417 (+33) -+ Inode bitmap at 16418 (+34) - Inode table at 16419-16930 (+35) - 15837 free blocks, 8192 free inodes, 0 directories - Free blocks: 16931-32767 -diff --git a/tests/m_desc_size_128/script b/tests/m_desc_size_128/script -index de3def9..a4def21 100644 ---- a/tests/m_desc_size_128/script -+++ b/tests/m_desc_size_128/script -@@ -1,4 +1,7 @@ - DESCRIPTION="enable 128-byte group descriptor on mkfs" - FS_SIZE=131072 -+DUMPE2FS_IGNORE_80COL=1 -+export DUMPE2FS_IGNORE_80COL - MKE2FS_OPTS="-b 1024 -O 64bit,extents -g 1024 -N 8192 -E desc_size=128" - . $cmd_dir/run_mke2fs -+unset DUMPE2FS_IGNORE_80COL -diff --git a/tests/m_devdir/script b/tests/m_devdir/script -new file mode 100644 -index 0000000..5f26699 ---- /dev/null -+++ b/tests/m_devdir/script -@@ -0,0 +1,33 @@ -+if test -x $DEBUGFS_EXE; then -+ -+test_description="create fs image from /dev" -+MKFS_DIR=/dev -+OUT=$test_name.log -+ -+$MKE2FS -q -F -o Linux -T ext4 -O metadata_csum,64bit -E lazy_itable_init=1 -b 1024 -d $MKFS_DIR $TMPFILE 16384 > $OUT 2>&1 -+mkfs_status=$? -+ -+$DUMPE2FS $TMPFILE >> $OUT 2>&1 -+$DEBUGFS -R 'ls /' $TMPFILE >> $OUT 2>&1 -+ -+$FSCK -f -n $TMPFILE >> $OUT 2>&1 -+fsck_status=$? -+ -+sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" < $OUT > $OUT.tmp -+mv $OUT.tmp $OUT -+ -+if [ $mkfs_status -ne 0 ]; then -+ echo "$test_name: $test_description: skipped" -+elif [ $mkfs_status -eq 0 ] && [ $fsck_status -eq 0 ]; then -+ echo "$test_name: $test_description: ok" -+ touch $test_name.ok -+else -+ echo "$test_name: $test_description: failed" -+fi -+ -+rm -rf $TMPFILE.cmd $OUT.sed -+unset MKFS_DIR OUT EXP -+ -+else #if test -x $DEBUGFS_EXE; then -+ echo "$test_name: $test_description: skipped" -+fi -diff --git a/tests/m_extent_journal/script b/tests/m_extent_journal/script -index 5e0cac2..efade21 100644 ---- a/tests/m_extent_journal/script -+++ b/tests/m_extent_journal/script -@@ -1,4 +1,7 @@ - DESCRIPTION="extent-mapped journal" - FS_SIZE=65536 -+DUMPE2FS_IGNORE_80COL=1 -+export DUMPE2FS_IGNORE_80COL - MKE2FS_OPTS="-O extents -j" - . $cmd_dir/run_mke2fs -+unset DUMPE2FS_IGNORE_80COL -diff --git a/tests/m_hugefile/expect b/tests/m_hugefile/expect -new file mode 100644 -index 0000000..82a6031 ---- /dev/null -+++ b/tests/m_hugefile/expect -@@ -0,0 +1,36 @@ -+mke2fs -F -T hugefile test.img 4T -+Creating filesystem with 1073741824 4k blocks and 1048576 inodes -+Superblock backups stored on blocks: -+ -+Allocating group tables: done -+Writing inode tables: done -+Creating 1 huge file(s) : done -+Writing superblocks and filesystem accounting information: done -+ -+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 -+ -+Exit status is 0 -+debugfs -R "extents /store/big-data" test.img | head -+Level Entries Logical Physical Length Flags -+ 0/ 2 1/ 1 0 - 1073610751 131070 1073610752 -+ 1/ 2 1/ 97 0 - 11108351 131071 11108352 -+ 2/ 2 1/339 0 - 32767 131072 - 163839 32768 -+ 2/ 2 2/339 32768 - 65535 163840 - 196607 32768 -+ 2/ 2 3/339 65536 - 98303 196608 - 229375 32768 -+ 2/ 2 4/339 98304 - 131071 229376 - 262143 32768 -+ 2/ 2 5/339 131072 - 163839 262144 - 294911 32768 -+ 2/ 2 6/339 163840 - 196607 294912 - 327679 32768 -+ 2/ 2 7/339 196608 - 229375 327680 - 360447 32768 -+ 2/ 2 8/339 229376 - 262143 360448 - 393215 32768 -+ 2/ 2 9/339 262144 - 294911 393216 - 425983 32768 -+ 2/ 2 10/339 294912 - 327679 425984 - 458751 32768 -+ 2/ 2 11/339 327680 - 360447 458752 - 491519 32768 -+ 2/ 2 12/339 360448 - 393215 491520 - 524287 32768 -+ 2/ 2 13/339 393216 - 425983 524288 - 557055 32768 -+ 2/ 2 14/339 425984 - 458751 557056 - 589823 32768 -+ 2/ 2 15/339 458752 - 491519 589824 - 622591 32768 -+ 2/ 2 16/339 491520 - 524287 622592 - 655359 32768 -diff --git a/tests/m_hugefile/name b/tests/m_hugefile/name -new file mode 100644 -index 0000000..0a28399 ---- /dev/null -+++ b/tests/m_hugefile/name -@@ -0,0 +1 @@ -+create a hugefile fs with a single huge file -diff --git a/tests/m_hugefile/script b/tests/m_hugefile/script -new file mode 100644 -index 0000000..5619f64 ---- /dev/null -+++ b/tests/m_hugefile/script -@@ -0,0 +1,67 @@ -+FSCK_OPT=-fn -+OUT=$test_name.log -+EXP=$test_dir/expect -+CONF=$TMPFILE.conf -+ -+if [ $(uname -s) = "Darwin" ]; then -+ # creates a 4TB filesystem -+ echo "$test_name: $DESCRIPTION: skipped for HFS+ (no sparse files)" -+ return 0 -+fi -+ -+#gzip -d < $EXP.gz > $EXP -+ -+cat > $CONF << ENDL -+[fs_types] -+ hugefile = { -+ features = extent,huge_file,flex_bg,uninit_bg,dir_nlink,extra_isize,^resize_inode,sparse_super2 -+ hash_alg = half_md4 -+ num_backup_sb = 0 -+ packed_meta_blocks = 1 -+ make_hugefiles = 1 -+ inode_ratio = 4194304 -+ hugefiles_dir = /store -+ hugefiles_name = big-data -+ hugefiles_digits = 0 -+ hugefiles_size = 0 -+ hugefiles_align = 256M -+ num_hugefiles = 1 -+ zero_hugefiles = false -+ flex_bg_size = 262144 -+ } -+ENDL -+ -+echo "mke2fs -F -T hugefile test.img 4T" > $OUT -+MKE2FS_CONFIG=$CONF $MKE2FS -F -T hugefile $TMPFILE 4T >> $OUT 2>&1 -+rm -rf $CONF -+ -+# check the file system if we get this far, we succeeded... -+$FSCK $FSCK_OPT -N test_filesys $TMPFILE >> $OUT 2>&1 -+status=$? -+echo Exit status is $status >> $OUT -+ -+echo 'debugfs -R "extents /store/big-data" test.img | head' >> $OUT -+ -+$DEBUGFS -R "extents /store/big-data" $TMPFILE 2>&1 | head -n 20 >> $OUT 2>&1 -+ -+rm $TMPFILE -+ -+# -+# Do the verification -+# -+ -+sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" -e 's/test_filesys:.*//g' < $OUT > $OUT.new -+mv $OUT.new $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 IMAGE FSCK_OPT OUT EXP CONF -diff --git a/tests/m_hugefile_slack/expect b/tests/m_hugefile_slack/expect -index 96a628a..f740cdb 100644 ---- a/tests/m_hugefile_slack/expect -+++ b/tests/m_hugefile_slack/expect -@@ -1,4 +1,4 @@ --tune2fs test -+mke2fs -F -T ext4h -I 128 test.img 786432 - Creating filesystem with 786432 1k blocks and 98304 inodes - Superblock backups stored on blocks: - 8193, 24577, 40961, 57345, 73729, 204801, 221185, 401409, 663553 -diff --git a/tests/m_hugefile_slack/script b/tests/m_hugefile_slack/script -index eecb2d7..3a0f057 100644 ---- a/tests/m_hugefile_slack/script -+++ b/tests/m_hugefile_slack/script -@@ -1,5 +1,3 @@ --if test -x $RESIZE2FS_EXE -a -x $DEBUGFS_EXE; then -- - FSCK_OPT=-fn - OUT=$test_name.log - EXP=$test_dir/expect -@@ -23,8 +21,7 @@ cat > $CONF << ENDL - } - ENDL - --echo "tune2fs test" > $OUT -- -+echo "mke2fs -F -T ext4h -I 128 test.img 786432" > $OUT - MKE2FS_CONFIG=$CONF $MKE2FS -F -T ext4h -I 128 $TMPFILE 786432 >> $OUT 2>&1 - rm -rf $CONF - -@@ -54,8 +51,3 @@ else - fi - - unset IMAGE FSCK_OPT OUT EXP CONF -- --else #if test -x $RESIZE2FS_EXE -a -x $DEBUGFS_EXE; then -- echo "$test_name: $test_description: skipped" --fi -- -diff --git a/tests/m_large_file/expect.1 b/tests/m_large_file/expect.1 -index 8ab2711..4acca41 100644 ---- a/tests/m_large_file/expect.1 -+++ b/tests/m_large_file/expect.1 -@@ -48,7 +48,8 @@ Default directory hash: half_md4 - Group 0: (Blocks 0-16383) - Primary superblock at 0, Group descriptors at 1-1 - Reserved GDT blocks at 2-4 -- Block bitmap at 5 (+5), Inode bitmap at 6 (+6) -+ Block bitmap at 5 (+5) -+ Inode bitmap at 6 (+6) - Inode table at 7-10 (+7) - 16367 free blocks, 53 free inodes, 2 directories - Free blocks: 17-16383 -diff --git a/tests/m_mcsum_extjournal/expect b/tests/m_mcsum_extjournal/expect -new file mode 100644 -index 0000000..ef895f8 ---- /dev/null -+++ b/tests/m_mcsum_extjournal/expect -@@ -0,0 +1,5 @@ -+Creating filesystem with 4096 1k blocks and 0 inodes -+Superblock backups stored on blocks: -+ -+Zeroing journal device:  -+Filesystem features: journal_dev metadata_csum -diff --git a/tests/m_mcsum_extjournal/name b/tests/m_mcsum_extjournal/name -new file mode 100644 -index 0000000..7df8389 ---- /dev/null -+++ b/tests/m_mcsum_extjournal/name -@@ -0,0 +1 @@ -+create external journal with sb checksum (metadata_csum) -diff --git a/tests/m_mcsum_extjournal/script b/tests/m_mcsum_extjournal/script -new file mode 100644 -index 0000000..624bf02 ---- /dev/null -+++ b/tests/m_mcsum_extjournal/script -@@ -0,0 +1,29 @@ -+FSCK_OPT=-fy -+OUT=$test_name.log -+if [ -f $test_dir/expect.gz ]; then -+ EXP=$test_name.tmp -+ gunzip < $test_dir/expect.gz > $EXP1 -+else -+ EXP=$test_dir/expect -+fi -+ -+cp /dev/null $OUT -+ -+$MKE2FS -F -o Linux -b 1024 -O journal_dev,metadata_csum -T ext4 $TMPFILE 4096 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT 2>&1 -+$DUMPE2FS -h $TMPFILE 2>&1 | grep 'Filesystem features:' >> $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 IMAGE FSCK_OPT OUT EXP -diff --git a/tests/m_meta_bg/script b/tests/m_meta_bg/script -index 7ca2bea..5e285b4 100644 ---- a/tests/m_meta_bg/script -+++ b/tests/m_meta_bg/script -@@ -1,4 +1,7 @@ - DESCRIPTION="meta blockgroup feature" - FS_SIZE=131072 -+DUMPE2FS_IGNORE_80COL=1 -+export DUMPE2FS_IGNORE_80COL - MKE2FS_OPTS="-O meta_bg,sparse_super,^resize_inode -g 1024" - . $cmd_dir/run_mke2fs -+unset DUMPE2FS_IGNORE_80COL -diff --git a/tests/m_minrootdir/expect b/tests/m_minrootdir/expect -new file mode 100644 -index 0000000..41a713f ---- /dev/null -+++ b/tests/m_minrootdir/expect -@@ -0,0 +1,216 @@ -+create fs -+Filesystem volume name: -+Last mounted on: -+Filesystem magic number: 0xEF53 -+Filesystem revision #: 1 (dynamic) -+Filesystem features: ext_attr dir_index filetype extent 64bit flex_bg sparse_super huge_file dir_nlink extra_isize metadata_csum -+Default mount options: (none) -+Filesystem state: clean -+Errors behavior: Continue -+Filesystem OS type: Linux -+Inode count: 1024 -+Block count: 16384 -+Reserved block count: 819 -+Free blocks: 16065 -+Free inodes: 1006 -+First block: 1 -+Block size: 1024 -+Fragment size: 1024 -+Group descriptor size: 64 -+Blocks per group: 8192 -+Fragments per group: 8192 -+Inodes per group: 512 -+Inode blocks per group: 128 -+Flex block group size: 16 -+Mount count: 0 -+Check interval: 15552000 (6 months) -+Reserved blocks uid: 0 -+Reserved blocks gid: 0 -+First inode: 11 -+Inode size: 256 -+Required extra isize: 28 -+Desired extra isize: 28 -+Default directory hash: half_md4 -+Checksum type: crc32c -+ -+ -+Group 0: (Blocks 1-8192) -+ Primary superblock at 1, Group descriptors at 2-2 -+ Block bitmap at 3 (+2) -+ Inode bitmap at 5 (+4) -+ Inode table at 7-134 (+6) -+ 7876 free blocks, 494 free inodes, 4 directories, 494 unused inodes -+ Free blocks: 317-8192 -+ Free inodes: 19-512 -+Group 1: (Blocks 8193-16383) [INODE_UNINIT] -+ Backup superblock at 8193, Group descriptors at 8194-8194 -+ Block bitmap at 4 (bg #0 + 3) -+ Inode bitmap at 6 (bg #0 + 5) -+ Inode table at 135-262 (bg #0 + 134) -+ 8189 free blocks, 512 free inodes, 0 directories, 512 unused inodes -+ Free blocks: 8195-16383 -+ Free inodes: 513-1024 -+debugfs: stat /emptyfile -+Inode: III Type: regular -+Size: 0 -+Fragment: Address: 0 Number: 0 Size: 0 -+debugfs: stat /bigfile -+Inode: III Type: regular -+Size: 32768 -+Fragment: Address: 0 Number: 0 Size: 0 -+debugfs: stat /sparsefile -+Inode: III Type: regular -+Size: 1073741825 -+Fragment: Address: 0 Number: 0 Size: 0 -+debugfs: stat /bigzerofile -+Inode: III Type: regular -+Size: 1073741825 -+Fragment: Address: 0 Number: 0 Size: 0 -+debugfs: stat /fifo -+debugfs: stat /emptydir -+Inode: III Type: directory -+Size: 1024 -+Fragment: Address: 0 Number: 0 Size: 0 -+debugfs: stat /dir -+Inode: III Type: directory -+Size: 1024 -+Fragment: Address: 0 Number: 0 Size: 0 -+debugfs: stat /dir/file -+Inode: III Type: regular -+Size: 8 -+Fragment: Address: 0 Number: 0 Size: 0 -+debugfs: ex /emptyfile -+Level Entries Logical Physical Length Flags -+debugfs: ex /bigfile -+Level Entries Logical Physical Length Flags -+X 0/0 1/1 0-31 AAA-BBB 32 -+debugfs: ex /sparsefile -+Level Entries Logical Physical Length Flags -+Y 0/1 1/1 1-1048576 AAA 1048576 -+X 1/1 1/5 1-1 AAA-BBB 1 -+X 1/1 2/5 512-512 AAA-BBB 1 -+X 1/1 3/5 1024-1024 AAA-BBB 1 -+X 1/1 4/5 524288-524288 AAA-BBB 1 -+X 1/1 5/5 1048576-1048576 AAA-BBB 1 -+debugfs: ex /bigzerofile -+Level Entries Logical Physical Length Flags -+debugfs: ex /dir -+Level Entries Logical Physical Length Flags -+X 0/0 1/1 0-0 AAA-BBB 1 -+debugfs: ex /dir/file -+Level Entries Logical Physical Length Flags -+X 0/0 1/1 0-0 AAA-BBB 1 -+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.img: 18/1024 files (0.0% non-contiguous), 319/16384 blocks -+minify fs -+Setting reserved blocks percentage to 0% (0 blocks) -+Resizing the filesystem on test.img to 338 (1k) blocks. -+The filesystem on test.img is now 338 (1k) blocks long. -+ -+Filesystem volume name: -+Last mounted on: -+Filesystem magic number: 0xEF53 -+Filesystem revision #: 1 (dynamic) -+Filesystem features: ext_attr dir_index filetype extent 64bit flex_bg sparse_super huge_file dir_nlink extra_isize metadata_csum -+Default mount options: (none) -+Filesystem state: clean -+Errors behavior: Continue -+Filesystem OS type: Linux -+Inode count: 512 -+Block count: 338 -+Reserved block count: 0 -+Free blocks: 151 -+Free inodes: 494 -+First block: 1 -+Block size: 1024 -+Fragment size: 1024 -+Group descriptor size: 64 -+Blocks per group: 8192 -+Fragments per group: 8192 -+Inodes per group: 512 -+Inode blocks per group: 128 -+Flex block group size: 16 -+Mount count: 0 -+Check interval: 15552000 (6 months) -+Reserved blocks uid: 0 -+Reserved blocks gid: 0 -+First inode: 11 -+Inode size: 256 -+Required extra isize: 28 -+Desired extra isize: 28 -+Default directory hash: half_md4 -+Checksum type: crc32c -+ -+ -+Group 0: (Blocks 1-337) -+ Primary superblock at 1, Group descriptors at 2-2 -+ Block bitmap at 3 (+2) -+ Inode bitmap at 5 (+4) -+ Inode table at 7-134 (+6) -+ 151 free blocks, 494 free inodes, 4 directories, 494 unused inodes -+ Free blocks: 4, 6, 135-262, 317-337 -+ Free inodes: 19-512 -+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.img: 18/512 files (0.0% non-contiguous), 187/338 blocks -+minify fs (2) -+Setting reserved blocks percentage to 0% (0 blocks) -+Resizing the filesystem on test.img to 188 (1k) blocks. -+The filesystem on test.img is now 188 (1k) blocks long. -+ -+Filesystem volume name: -+Last mounted on: -+Filesystem magic number: 0xEF53 -+Filesystem revision #: 1 (dynamic) -+Filesystem features: ext_attr dir_index filetype extent 64bit flex_bg sparse_super huge_file dir_nlink extra_isize metadata_csum -+Default mount options: (none) -+Filesystem state: clean -+Errors behavior: Continue -+Filesystem OS type: Linux -+Inode count: 512 -+Block count: 188 -+Reserved block count: 0 -+Free blocks: 1 -+Free inodes: 494 -+First block: 1 -+Block size: 1024 -+Fragment size: 1024 -+Group descriptor size: 64 -+Blocks per group: 8192 -+Fragments per group: 8192 -+Inodes per group: 512 -+Inode blocks per group: 128 -+Flex block group size: 16 -+Mount count: 0 -+Check interval: 15552000 (6 months) -+Reserved blocks uid: 0 -+Reserved blocks gid: 0 -+First inode: 11 -+Inode size: 256 -+Required extra isize: 28 -+Desired extra isize: 28 -+Default directory hash: half_md4 -+Checksum type: crc32c -+ -+ -+Group 0: (Blocks 1-187) -+ Primary superblock at 1, Group descriptors at 2-2 -+ Block bitmap at 3 (+2) -+ Inode bitmap at 5 (+4) -+ Inode table at 7-134 (+6) -+ 1 free blocks, 494 free inodes, 4 directories, 494 unused inodes -+ Free blocks: 187 -+ Free inodes: 19-512 -+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.img: 18/512 files (5.6% non-contiguous), 187/188 blocks -diff --git a/tests/m_minrootdir/output.sed b/tests/m_minrootdir/output.sed -new file mode 100644 -index 0000000..2e76967 ---- /dev/null -+++ b/tests/m_minrootdir/output.sed -@@ -0,0 +1,5 @@ -+s/^[[:space:]]*\([0-9]*\)\/[[:space:]]*\([0-9]*\)[[:space:]]*\([0-9]*\)\/[[:space:]]*\([0-9]*\)[[:space:]]*\([0-9]*\)[[:space:]]*-[[:space:]]*\([0-9]*\)[[:space:]]*[0-9]*[[:space:]]*-[[:space:]]*[0-9]*[[:space:]]*\([0-9]*\)/X \1\/\2 \3\/\4 \5-\6 AAA-BBB \7/g -+s/^[[:space:]]*\([0-9]*\)\/[[:space:]]*\([0-9]*\)[[:space:]]*\([0-9]*\)\/[[:space:]]*\([0-9]*\)[[:space:]]*\([0-9]*\)[[:space:]]*-[[:space:]]*\([0-9]*\)[[:space:]]*[0-9]*[[:space:]]*\([0-9]*\)/Y \1\/\2 \3\/\4 \5-\6 AAA \7/g -+s/Mode:.*$//g -+s/User:.*Size:/Size:/g -+s/^Inode: [0-9]*/Inode: III/g -diff --git a/tests/m_minrootdir/script b/tests/m_minrootdir/script -new file mode 100644 -index 0000000..662e76f ---- /dev/null -+++ b/tests/m_minrootdir/script -@@ -0,0 +1,81 @@ -+if test -x $DEBUGFS_EXE -a -x $RESIZE2FS_EXE; then -+ -+test_description="create fs image from dir, then minimize it" -+MKFS_DIR=$TMPFILE.dir -+OUT=$test_name.log -+EXP=$test_dir/expect -+ -+rm -rf $MKFS_DIR -+mkdir -p $MKFS_DIR -+mkdir $MKFS_DIR/dir -+mkdir $MKFS_DIR/emptydir -+dd if=/dev/zero of=$MKFS_DIR/bigzerofile bs=1 count=1 seek=1073741824 2> /dev/null -+echo "M" | dd of=$MKFS_DIR/sparsefile bs=1 count=1 seek=1024 2> /dev/null -+echo "M" | dd of=$MKFS_DIR/sparsefile bs=1 count=1 seek=524288 conv=notrunc 2> /dev/null -+echo "M" | dd of=$MKFS_DIR/sparsefile bs=1 count=1 seek=1048576 conv=notrunc 2> /dev/null -+echo "M" | dd of=$MKFS_DIR/sparsefile bs=1 count=1 seek=536870912 conv=notrunc 2> /dev/null -+echo "M" | dd of=$MKFS_DIR/sparsefile bs=1 count=1 seek=1073741824 conv=notrunc 2> /dev/null -+dd if=/dev/zero bs=1024 count=32 2> /dev/null | tr '\0' 'a' > $MKFS_DIR/bigfile -+touch $MKFS_DIR/emptyfile -+echo "Test me" > $MKFS_DIR/dir/file -+ -+echo "create fs" > $OUT -+$MKE2FS -q -F -o Linux -T ext4 -O ^has_journal,metadata_csum,64bit,^resize_inode -E lazy_itable_init=1 -b 1024 -d $MKFS_DIR $TMPFILE 16384 >> $OUT 2>&1 -+ -+$DUMPE2FS $TMPFILE >> $OUT 2>&1 -+cat > $TMPFILE.cmd << ENDL -+stat /emptyfile -+stat /bigfile -+stat /sparsefile -+stat /bigzerofile -+stat /fifo -+stat /emptydir -+stat /dir -+stat /dir/file -+ENDL -+$DEBUGFS -f $TMPFILE.cmd $TMPFILE 2>&1 | egrep "(stat|Size:|Type:)" | sed -f $test_dir/output.sed >> $OUT -+ -+cat > $TMPFILE.cmd << ENDL -+ex /emptyfile -+ex /bigfile -+ex /sparsefile -+ex /bigzerofile -+ex /dir -+ex /dir/file -+ENDL -+$DEBUGFS -f $TMPFILE.cmd $TMPFILE 2>&1 | sed -f $test_dir/output.sed >> $OUT -+$FSCK -f -n $TMPFILE >> $OUT 2>&1 -+ -+echo "minify fs" >> $OUT -+$TUNE2FS -m 0 $TMPFILE >> $OUT 2>&1 -+$RESIZE2FS -M $TMPFILE >> $OUT 2>&1 -+$DUMPE2FS $TMPFILE >> $OUT 2>&1 -+$FSCK -f -n $TMPFILE >> $OUT 2>&1 -+ -+echo "minify fs (2)" >> $OUT -+$TUNE2FS -m 0 $TMPFILE >> $OUT 2>&1 -+$RESIZE2FS -M $TMPFILE >> $OUT 2>&1 -+$DUMPE2FS $TMPFILE >> $OUT 2>&1 -+$FSCK -f -n $TMPFILE >> $OUT 2>&1 -+ -+sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" < $OUT > $OUT.tmp -+mv $OUT.tmp $OUT -+ -+# 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 -+ -+rm -rf $TMPFILE.cmd $MKFS_DIR $OUT.sed -+unset MKFS_DIR OUT EXP -+ -+else #if test -x $DEBUGFS_EXE -a -x RESIZE2FS_EXE; then -+ echo "$test_name: $test_description: skipped" -+fi -diff --git a/tests/m_mmp/expect.1 b/tests/m_mmp/expect.1 -index aec0a84..a1452e6 100644 ---- a/tests/m_mmp/expect.1 -+++ b/tests/m_mmp/expect.1 -@@ -51,7 +51,8 @@ MMP update interval: 5 - Group 0: (Blocks 0-32767) - Primary superblock at 0, Group descriptors at 1-1 - Reserved GDT blocks at 2-16 -- Block bitmap at 17 (+17), Inode bitmap at 18 (+18) -+ Block bitmap at 17 (+17) -+ Inode bitmap at 18 (+18) - Inode table at 19-1042 (+19) - 31718 free blocks, 32757 free inodes, 2 directories - Free blocks: 1050-32767 -@@ -59,7 +60,8 @@ Group 0: (Blocks 0-32767) - Group 1: (Blocks 32768-65535) - Backup superblock at 32768, Group descriptors at 32769-32769 - Reserved GDT blocks at 32770-32784 -- Block bitmap at 32785 (+17), Inode bitmap at 32786 (+18) -+ Block bitmap at 32785 (+17) -+ Inode bitmap at 32786 (+18) - Inode table at 32787-33810 (+19) - 31725 free blocks, 32768 free inodes, 0 directories - Free blocks: 33811-65535 -diff --git a/tests/m_mmp_bad_csum/expect b/tests/m_mmp_bad_csum/expect -new file mode 100644 -index 0000000..e15e7b4 ---- /dev/null -+++ b/tests/m_mmp_bad_csum/expect -@@ -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 -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 -index 0000000..61c31d4 ---- /dev/null -+++ b/tests/m_mmp_bad_csum/name -@@ -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 -index 0000000..09e870c ---- /dev/null -+++ b/tests/m_mmp_bad_csum/script -@@ -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_name.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 -index 0000000..b5dfb89 ---- /dev/null -+++ b/tests/m_mmp_bad_magic/.log -@@ -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 -index 0000000..b5dfb89 ---- /dev/null -+++ b/tests/m_mmp_bad_magic/expect -@@ -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 -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 -index 0000000..15a2d4d ---- /dev/null -+++ b/tests/m_mmp_bad_magic/name -@@ -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 -index 0000000..09e870c ---- /dev/null -+++ b/tests/m_mmp_bad_magic/script -@@ -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_name.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_no_opt/script b/tests/m_no_opt/script -index 6d1d0eb..223f117 100644 ---- a/tests/m_no_opt/script -+++ b/tests/m_no_opt/script -@@ -1,4 +1,7 @@ - DESCRIPTION="no filesystem extensions" - FS_SIZE=65536 -+DUMPE2FS_IGNORE_80COL=1 -+export DUMPE2FS_IGNORE_80COL - MKE2FS_OPTS="-O ^sparse_super,^filetype,^resize_inode,^dir_index,^ext_attr" - . $cmd_dir/run_mke2fs -+unset DUMPE2FS_IGNORE_80COL -diff --git a/tests/m_quota/script b/tests/m_quota/script -index 36ab630..fe63939 100644 ---- a/tests/m_quota/script -+++ b/tests/m_quota/script -@@ -5,4 +5,7 @@ if [ "$QUOTA" != "y" ]; then - echo "$test_name: $DESCRIPTION: skipped" - return 0 - fi -+DUMPE2FS_IGNORE_80COL=1 -+export DUMPE2FS_IGNORE_80COL - . $cmd_dir/run_mke2fs -+unset DUMPE2FS_IGNORE_80COL -diff --git a/tests/m_raid_opt/script b/tests/m_raid_opt/script -index 296fe94..8c859e0 100644 ---- a/tests/m_raid_opt/script -+++ b/tests/m_raid_opt/script -@@ -1,4 +1,7 @@ - DESCRIPTION="raid options" - FS_SIZE=131072 - MKE2FS_OPTS="-E stride=13 -O sparse_super -g 1024" -+DUMPE2FS_IGNORE_80COL=1 -+export DUMPE2FS_IGNORE_80COL - . $cmd_dir/run_mke2fs -+unset DUMPE2FS_IGNORE_80COL -diff --git a/tests/m_root_owner/expect.1 b/tests/m_root_owner/expect.1 -index cd94993..30d119e 100644 ---- a/tests/m_root_owner/expect.1 -+++ b/tests/m_root_owner/expect.1 -@@ -46,7 +46,8 @@ Default directory hash: half_md4 - Group 0: (Blocks 1-1023) - Primary superblock at 1, Group descriptors at 2-2 - Reserved GDT blocks at 3-5 -- Block bitmap at 6 (+5), Inode bitmap at 7 (+6) -+ Block bitmap at 6 (+5) -+ Inode bitmap at 7 (+6) - Inode table at 8-23 (+7) - 986 free blocks, 117 free inodes, 2 directories - Free blocks: 38-1023 -diff --git a/tests/m_rootdir/expect b/tests/m_rootdir/expect -new file mode 100644 -index 0000000..a5314f1 ---- /dev/null -+++ b/tests/m_rootdir/expect -@@ -0,0 +1,117 @@ -+Filesystem volume name: -+Last mounted on: -+Filesystem magic number: 0xEF53 -+Filesystem revision #: 1 (dynamic) -+Filesystem features: has_journal ext_attr resize_inode dir_index filetype extent 64bit flex_bg sparse_super huge_file dir_nlink extra_isize metadata_csum -+Default mount options: (none) -+Filesystem state: clean -+Errors behavior: Continue -+Filesystem OS type: Linux -+Inode count: 1024 -+Block count: 16384 -+Reserved block count: 819 -+Free blocks: 14786 -+Free inodes: 1005 -+First block: 1 -+Block size: 1024 -+Fragment size: 1024 -+Group descriptor size: 64 -+Reserved GDT blocks: 127 -+Blocks per group: 8192 -+Fragments per group: 8192 -+Inodes per group: 512 -+Inode blocks per group: 128 -+Flex block group size: 16 -+Mount count: 0 -+Check interval: 15552000 (6 months) -+Reserved blocks uid: 0 -+Reserved blocks gid: 0 -+First inode: 11 -+Inode size: 256 -+Required extra isize: 28 -+Desired extra isize: 28 -+Journal inode: 8 -+Default directory hash: half_md4 -+Journal backup: inode blocks -+Checksum type: crc32c -+Journal features: (none) -+Journal size: 1024k -+Journal length: 1024 -+Journal sequence: 0x00000001 -+Journal start: 0 -+ -+ -+Group 0: (Blocks 1-8192) -+ Primary superblock at 1, Group descriptors at 2-2 -+ Reserved GDT blocks at 3-129 -+ Block bitmap at 130 (+129) -+ Inode bitmap at 132 (+131) -+ Inode table at 134-261 (+133) -+ 7748 free blocks, 493 free inodes, 4 directories, 493 unused inodes -+ Free blocks: 445-8192 -+ Free inodes: 20-512 -+Group 1: (Blocks 8193-16383) [INODE_UNINIT] -+ Backup superblock at 8193, Group descriptors at 8194-8194 -+ Reserved GDT blocks at 8195-8321 -+ Block bitmap at 131 (bg #0 + 130) -+ Inode bitmap at 133 (bg #0 + 132) -+ Inode table at 262-389 (bg #0 + 261) -+ 7038 free blocks, 512 free inodes, 0 directories, 512 unused inodes -+ Free blocks: 9346-16383 -+ Free inodes: 513-1024 -+debugfs: stat /emptyfile -+Inode: III Type: regular -+Size: 0 -+Fragment: Address: 0 Number: 0 Size: 0 -+debugfs: stat /bigfile -+Inode: III Type: regular -+Size: 32768 -+Fragment: Address: 0 Number: 0 Size: 0 -+debugfs: stat /sparsefile -+Inode: III Type: regular -+Size: 1073741825 -+Fragment: Address: 0 Number: 0 Size: 0 -+debugfs: stat /bigzerofile -+Inode: III Type: regular -+Size: 1073741825 -+Fragment: Address: 0 Number: 0 Size: 0 -+debugfs: stat /fifo -+debugfs: stat /emptydir -+Inode: III Type: directory -+Size: 1024 -+Fragment: Address: 0 Number: 0 Size: 0 -+debugfs: stat /dir -+Inode: III Type: directory -+Size: 1024 -+Fragment: Address: 0 Number: 0 Size: 0 -+debugfs: stat /dir/file -+Inode: III Type: regular -+Size: 8 -+Fragment: Address: 0 Number: 0 Size: 0 -+debugfs: ex /emptyfile -+Level Entries Logical Physical Length Flags -+debugfs: ex /bigfile -+Level Entries Logical Physical Length Flags -+X 0/0 1/1 0-31 AAA-BBB 32 -+debugfs: ex /sparsefile -+Level Entries Logical Physical Length Flags -+Y 0/1 1/1 1-1048576 AAA 1048576 -+X 1/1 1/5 1-1 AAA-BBB 1 -+X 1/1 2/5 512-512 AAA-BBB 1 -+X 1/1 3/5 1024-1024 AAA-BBB 1 -+X 1/1 4/5 524288-524288 AAA-BBB 1 -+X 1/1 5/5 1048576-1048576 AAA-BBB 1 -+debugfs: ex /bigzerofile -+Level Entries Logical Physical Length Flags -+debugfs: ex /dir -+Level Entries Logical Physical Length Flags -+X 0/0 1/1 0-0 AAA-BBB 1 -+debugfs: ex /dir/file -+Level Entries Logical Physical Length Flags -+X 0/0 1/1 0-0 AAA-BBB 1 -+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.img: 19/1024 files (0.0% non-contiguous), 1598/16384 blocks -diff --git a/tests/m_rootdir/output.sed b/tests/m_rootdir/output.sed -new file mode 100644 -index 0000000..2e76967 ---- /dev/null -+++ b/tests/m_rootdir/output.sed -@@ -0,0 +1,5 @@ -+s/^[[:space:]]*\([0-9]*\)\/[[:space:]]*\([0-9]*\)[[:space:]]*\([0-9]*\)\/[[:space:]]*\([0-9]*\)[[:space:]]*\([0-9]*\)[[:space:]]*-[[:space:]]*\([0-9]*\)[[:space:]]*[0-9]*[[:space:]]*-[[:space:]]*[0-9]*[[:space:]]*\([0-9]*\)/X \1\/\2 \3\/\4 \5-\6 AAA-BBB \7/g -+s/^[[:space:]]*\([0-9]*\)\/[[:space:]]*\([0-9]*\)[[:space:]]*\([0-9]*\)\/[[:space:]]*\([0-9]*\)[[:space:]]*\([0-9]*\)[[:space:]]*-[[:space:]]*\([0-9]*\)[[:space:]]*[0-9]*[[:space:]]*\([0-9]*\)/Y \1\/\2 \3\/\4 \5-\6 AAA \7/g -+s/Mode:.*$//g -+s/User:.*Size:/Size:/g -+s/^Inode: [0-9]*/Inode: III/g -diff --git a/tests/m_rootdir/script b/tests/m_rootdir/script -new file mode 100644 -index 0000000..fbe1b31 ---- /dev/null -+++ b/tests/m_rootdir/script -@@ -0,0 +1,71 @@ -+if test -x $DEBUGFS_EXE; then -+ -+test_description="create fs image from dir" -+MKFS_DIR=$TMPFILE.dir -+OUT=$test_name.log -+EXP=$test_dir/expect -+ -+rm -rf $MKFS_DIR -+mkdir -p $MKFS_DIR -+touch $MKFS_DIR/emptyfile -+dd if=/dev/zero bs=1024 count=32 2> /dev/null | tr '\0' 'a' > $MKFS_DIR/bigfile -+echo "M" | dd of=$MKFS_DIR/sparsefile bs=1 count=1 seek=1024 2> /dev/null -+echo "M" | dd of=$MKFS_DIR/sparsefile bs=1 count=1 seek=524288 conv=notrunc 2> /dev/null -+echo "M" | dd of=$MKFS_DIR/sparsefile bs=1 count=1 seek=1048576 conv=notrunc 2> /dev/null -+echo "M" | dd of=$MKFS_DIR/sparsefile bs=1 count=1 seek=536870912 conv=notrunc 2> /dev/null -+echo "M" | dd of=$MKFS_DIR/sparsefile bs=1 count=1 seek=1073741824 conv=notrunc 2> /dev/null -+dd if=/dev/zero of=$MKFS_DIR/bigzerofile bs=1 count=1 seek=1073741824 2> /dev/null -+ln $MKFS_DIR/bigzerofile $MKFS_DIR/bigzerofile_hardlink -+ln -s /silly_bs_link $MKFS_DIR/silly_bs_link -+mkdir $MKFS_DIR/emptydir -+mkdir $MKFS_DIR/dir -+echo "Test me" > $MKFS_DIR/dir/file -+ -+$MKE2FS -q -F -o Linux -T ext4 -O metadata_csum,64bit -E lazy_itable_init=1 -b 1024 -d $MKFS_DIR $TMPFILE 16384 > $OUT 2>&1 -+ -+$DUMPE2FS $TMPFILE >> $OUT 2>&1 -+cat > $TMPFILE.cmd << ENDL -+stat /emptyfile -+stat /bigfile -+stat /sparsefile -+stat /bigzerofile -+stat /fifo -+stat /emptydir -+stat /dir -+stat /dir/file -+ENDL -+$DEBUGFS -f $TMPFILE.cmd $TMPFILE 2>&1 | egrep "(stat|Size:|Type:)" | sed -f $test_dir/output.sed >> $OUT -+ -+cat > $TMPFILE.cmd << ENDL -+ex /emptyfile -+ex /bigfile -+ex /sparsefile -+ex /bigzerofile -+ex /dir -+ex /dir/file -+ENDL -+$DEBUGFS -f $TMPFILE.cmd $TMPFILE 2>&1 | sed -f $test_dir/output.sed >> $OUT 2>&1 -+ -+$FSCK -f -n $TMPFILE >> $OUT 2>&1 -+ -+sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" < $OUT > $OUT.tmp -+mv $OUT.tmp $OUT -+ -+# 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 -+ -+rm -rf $TMPFILE.cmd $MKFS_DIR $OUT.sed -+unset MKFS_DIR OUT EXP -+ -+else #if test -x $DEBUGFS_EXE; then -+ echo "$test_name: $test_description: skipped" -+fi -diff --git a/tests/m_std/script b/tests/m_std/script -index a2f2cda..61c50c7 100644 ---- a/tests/m_std/script -+++ b/tests/m_std/script -@@ -1,3 +1,6 @@ - DESCRIPTION="standard filesystem options" -+DUMPE2FS_IGNORE_80COL=1 -+export DUMPE2FS_IGNORE_80COL - FS_SIZE=65536 - . $cmd_dir/run_mke2fs -+unset DUMPE2FS_IGNORE_80COL -diff --git a/tests/m_uninit/script b/tests/m_uninit/script -index 0b565ac..d4d373a 100644 ---- a/tests/m_uninit/script -+++ b/tests/m_uninit/script -@@ -1,4 +1,7 @@ - DESCRIPTION="uninitialized group feature" -+DUMPE2FS_IGNORE_80COL=1 -+export DUMPE2FS_IGNORE_80COL - FS_SIZE=131072 - MKE2FS_OPTS="-O uninit_bg" - . $cmd_dir/run_mke2fs -+unset DUMPE2FS_IGNORE_80COL -diff --git a/tests/progs/Makefile.in b/tests/progs/Makefile.in -index 44d04b5..22d9417 100644 ---- a/tests/progs/Makefile.in -+++ b/tests/progs/Makefile.in -@@ -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) - -diff --git a/tests/r_32to64bit/expect b/tests/r_32to64bit/expect -new file mode 100644 -index 0000000..f5fa56b ---- /dev/null -+++ b/tests/r_32to64bit/expect -@@ -0,0 +1,94 @@ -+resize2fs test -+Creating filesystem with 524288 1k blocks and 65536 inodes -+Superblock backups stored on blocks: -+ 8193, 24577, 40961, 57345, 73729, 204801, 221185, 401409 -+ -+Allocating group tables: done -+Writing inode tables: done -+Creating journal (16384 blocks): done -+Creating 477 huge file(s) with 1024 blocks each: done -+Writing superblocks and filesystem accounting information: done -+ -+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 -+ -+Exit status is 0 -+resize2fs test.img -b -+Converting the filesystem to 64-bit. -+The filesystem on test.img is now 524288 (1k) blocks long. -+ -+Exit status is 0 -+Change in FS metadata: -+@@ -2,7 +2,7 @@ -+ Last mounted on: -+ Filesystem magic number: 0xEF53 -+ Filesystem revision #: 1 (dynamic) -+-Filesystem features: has_journal ext_attr resize_inode dir_index filetype extent flex_bg sparse_super large_file huge_file uninit_bg dir_nlink extra_isize -++Filesystem features: has_journal ext_attr resize_inode dir_index filetype extent 64bit flex_bg sparse_super large_file huge_file uninit_bg dir_nlink extra_isize -+ Default mount options: user_xattr acl -+ Filesystem state: clean -+ Errors behavior: Continue -+@@ -15,7 +15,8 @@ -+ First block: 1 -+ Block size: 1024 -+ Fragment size: 1024 -+-Reserved GDT blocks: 256 -++Group descriptor size: 64 -++Reserved GDT blocks: 254 -+ Blocks per group: 8192 -+ Fragments per group: 8192 -+ Inodes per group: 1024 -+@@ -40,16 +41,16 @@ -+ -+ -+ group:block:super:gdt:bbitmap:ibitmap:itable -+-0:1:1:2-3:260:276:292 -+-1:8193:8193:8194-8195:261:277:548 -++0:1:1:2-5:260:276:292 -++1:8193:8193:8194-8197:261:277:548 -+ 2:16385:-1:-1:262:278:804 -+-3:24577:24577:24578-24579:263:279:1060 -++3:24577:24577:24578-24581:263:279:1060 -+ 4:32769:-1:-1:264:280:1316 -+-5:40961:40961:40962-40963:265:281:1572 -++5:40961:40961:40962-40965:265:281:1572 -+ 6:49153:-1:-1:266:282:1828 -+-7:57345:57345:57346-57347:267:283:2084 -++7:57345:57345:57346-57349:267:283:2084 -+ 8:65537:-1:-1:268:284:2340 -+-9:73729:73729:73730-73731:269:285:2596 -++9:73729:73729:73730-73733:269:285:2596 -+ 10:81921:-1:-1:270:286:2852 -+ 11:90113:-1:-1:271:287:3108 -+ 12:98305:-1:-1:272:288:3364 -+@@ -65,9 +66,9 @@ -+ 22:180225:-1:-1:131079:131095:132641 -+ 23:188417:-1:-1:131080:131096:132897 -+ 24:196609:-1:-1:131081:131097:133153 -+-25:204801:204801:204802-204803:131082:131098:133409 -++25:204801:204801:204802-204805:131082:131098:133409 -+ 26:212993:-1:-1:131083:131099:133665 -+-27:221185:221185:221186-221187:131084:131100:133921 -++27:221185:221185:221186-221189:131084:131100:133921 -+ 28:229377:-1:-1:131085:131101:134177 -+ 29:237569:-1:-1:131086:131102:134433 -+ 30:245761:-1:-1:131087:131103:134689 -+@@ -89,7 +90,7 @@ -+ 46:376833:-1:-1:262159:262175:265761 -+ 47:385025:-1:-1:262160:262176:266017 -+ 48:393217:-1:-1:393217:393233:393249 -+-49:401409:401409:401410-401411:393218:393234:393505 -++49:401409:401409:401410-401413:393218:393234:393505 -+ 50:409601:-1:-1:393219:393235:393761 -+ 51:417793:-1:-1:393220:393236:394017 -+ 52:425985:-1:-1:393221:393237:394273 -+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 -+ -+Exit status is 0 -diff --git a/tests/r_32to64bit/name b/tests/r_32to64bit/name -new file mode 100644 -index 0000000..fb45fab ---- /dev/null -+++ b/tests/r_32to64bit/name -@@ -0,0 +1 @@ -+convert flex_bg 32bit fs to 64bit fs -diff --git a/tests/r_32to64bit/script b/tests/r_32to64bit/script -new file mode 100644 -index 0000000..de08bfb ---- /dev/null -+++ b/tests/r_32to64bit/script -@@ -0,0 +1,74 @@ -+if test -x $RESIZE2FS_EXE -a -x $DEBUGFS_EXE; then -+ -+FSCK_OPT=-fn -+OUT=$test_name.log -+EXP=$test_dir/expect -+CONF=$TMPFILE.conf -+ -+cat > $CONF << ENDL -+[fs_types] -+ ext4h = { -+ features = has_journal,extent,huge_file,flex_bg,uninit_bg,dir_nlink,extra_isize,sparse_super,filetype,dir_index,ext_attr,resize_inode -+ blocksize = 1024 -+ inode_size = 256 -+ make_hugefiles = true -+ hugefiles_dir = / -+ hugefiles_slack = 0 -+ hugefiles_name = aaaaa -+ hugefiles_digits = 4 -+ hugefiles_size = 1M -+ zero_hugefiles = false -+ } -+ENDL -+ -+echo "resize2fs test" > $OUT -+ -+MKE2FS_CONFIG=$CONF $MKE2FS -F -T ext4h $TMPFILE 524288 >> $OUT 2>&1 -+rm -rf $CONF -+ -+# dump and check -+($DUMPE2FS -h $TMPFILE; $DUMPE2FS -g $TMPFILE) 2> /dev/null | sed -f $cmd_dir/filter.sed > $OUT.before -+$FSCK $FSCK_OPT -N test_filesys $TMPFILE >> $OUT 2>&1 -+status=$? -+echo Exit status is $status >> $OUT -+ -+# resize it -+echo "resize2fs test.img -b" >> $OUT -+$RESIZE2FS -b -f $TMPFILE 2>&1 >> $OUT 2>&1 -+status=$? -+echo Exit status is $status >> $OUT -+ -+# dump and check -+($DUMPE2FS -h $TMPFILE; $DUMPE2FS -g $TMPFILE) 2> /dev/null | sed -f $cmd_dir/filter.sed > $OUT.after -+echo "Change in FS metadata:" >> $OUT -+diff -u $OUT.before $OUT.after | tail -n +3 >> $OUT -+$FSCK $FSCK_OPT -N test_filesys $TMPFILE >> $OUT 2>&1 -+status=$? -+echo Exit status is $status >> $OUT -+ -+rm $TMPFILE $OUT.before $OUT.after -+ -+# -+# Do the verification -+# -+ -+sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" -e 's/test_filesys:.*//g' < $OUT > $OUT.new -+mv $OUT.new $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 IMAGE FSCK_OPT OUT EXP CONF -+ -+else #if test -x $RESIZE2FS_EXE -a -x $DEBUGFS_EXE; then -+ echo "$test_name: $test_description: skipped" -+fi -+ -diff --git a/tests/r_32to64bit_expand_full/expect b/tests/r_32to64bit_expand_full/expect -new file mode 100644 -index 0000000..f9e30f3 ---- /dev/null -+++ b/tests/r_32to64bit_expand_full/expect -@@ -0,0 +1,139 @@ -+resize2fs test -+Creating filesystem with 786432 1k blocks and 98304 inodes -+Superblock backups stored on blocks: -+ 8193, 24577, 40961, 57345, 73729, 204801, 221185, 401409, 663553 -+ -+Allocating group tables: done -+Writing inode tables: done -+Creating journal (16384 blocks): done -+Creating 727 huge file(s) with 1024 blocks each: done -+Writing superblocks and filesystem accounting information: done -+ -+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 -+ -+Exit status is 0 -+resize2fs -b test.img -+Converting the filesystem to 64-bit. -+The filesystem on test.img is now 786432 (1k) blocks long. -+ -+resize2fs test.img -+Resizing the filesystem on test.img to 1179648 (1k) blocks. -+The filesystem on test.img is now 1179648 (1k) blocks long. -+ -+Exit status is 0 -+Change in FS metadata: -+@@ -1,15 +1,15 @@ -+ -+ group:block:super:gdt:bbitmap:ibitmap:itable -+-0:1:1:2-7:8:9:10 -+-1:8193:8193:8194-8199:8200:8201:8202 -++0:1:1:2-10:266:267:268 -++1:8193:8193:8194-8202:8458:8459:8460 -+ 2:16385:-1:-1:16385:16386:16387 -+-3:24577:24577:24578-24583:24584:24585:24586 -++3:24577:24577:24578-24586:24842:24843:24844 -+ 4:32769:-1:-1:32769:32770:32771 -+-5:40961:40961:40962-40967:40968:40969:40970 -++5:40961:40961:40962-40970:41226:41227:41228 -+ 6:49153:-1:-1:49153:49154:49155 -+-7:57345:57345:57346-57351:57352:57353:57354 -++7:57345:57345:57346-57354:57610:57611:57612 -+ 8:65537:-1:-1:65537:65538:65539 -+-9:73729:73729:73730-73735:73736:73737:73738 -++9:73729:73729:73730-73738:73994:73995:73996 -+ 10:81921:-1:-1:81921:81922:81923 -+ 11:90113:-1:-1:90113:90114:90115 -+ 12:98305:-1:-1:98305:98306:98307 -+@@ -25,9 +25,9 @@ -+ 22:180225:-1:-1:180225:180226:180227 -+ 23:188417:-1:-1:188417:188418:188419 -+ 24:196609:-1:-1:196609:196610:196611 -+-25:204801:204801:204802-204807:204808:204809:204810 -++25:204801:204801:204802-204810:205066:205067:205068 -+ 26:212993:-1:-1:212993:212994:212995 -+-27:221185:221185:221186-221191:221192:221193:221194 -++27:221185:221185:221186-221194:221450:221451:221452 -+ 28:229377:-1:-1:229377:229378:229379 -+ 29:237569:-1:-1:237569:237570:237571 -+ 30:245761:-1:-1:245761:245762:245763 -+@@ -49,7 +49,7 @@ -+ 46:376833:-1:-1:376833:376834:376835 -+ 47:385025:-1:-1:385025:385026:385027 -+ 48:393217:-1:-1:393217:393218:393219 -+-49:401409:401409:401410-401415:401416:401417:401418 -++49:401409:401409:401410-401418:401674:401675:401676 -+ 50:409601:-1:-1:409601:409602:409603 -+ 51:417793:-1:-1:417793:417794:417795 -+ 52:425985:-1:-1:425985:425986:425987 -+@@ -81,7 +81,7 @@ -+ 78:638977:-1:-1:638977:638978:638979 -+ 79:647169:-1:-1:647169:647170:647171 -+ 80:655361:-1:-1:655361:655362:655363 -+-81:663553:663553:663554-663559:663560:663561:663562 -++81:663553:663553:663554-663562:663818:663819:663820 -+ 82:671745:-1:-1:671745:671746:671747 -+ 83:679937:-1:-1:679937:679938:679939 -+ 84:688129:-1:-1:688129:688130:688131 -+@@ -96,3 +96,51 @@ -+ 93:761857:-1:-1:761857:761858:761859 -+ 94:770049:-1:-1:770049:770050:770051 -+ 95:778241:-1:-1:778241:778242:778243 -++96:786433:-1:-1:786433:786434:786435 -++97:794625:-1:-1:794625:794626:794627 -++98:802817:-1:-1:802817:802818:802819 -++99:811009:-1:-1:811009:811010:811011 -++100:819201:-1:-1:819201:819202:819203 -++101:827393:-1:-1:827393:827394:827395 -++102:835585:-1:-1:835585:835586:835587 -++103:843777:-1:-1:843777:843778:843779 -++104:851969:-1:-1:851969:851970:851971 -++105:860161:-1:-1:860161:860162:860163 -++106:868353:-1:-1:868353:868354:868355 -++107:876545:-1:-1:876545:876546:876547 -++108:884737:-1:-1:884737:884738:884739 -++109:892929:-1:-1:892929:892930:892931 -++110:901121:-1:-1:901121:901122:901123 -++111:909313:-1:-1:909313:909314:909315 -++112:917505:-1:-1:917505:917506:917507 -++113:925697:-1:-1:925697:925698:925699 -++114:933889:-1:-1:933889:933890:933891 -++115:942081:-1:-1:942081:942082:942083 -++116:950273:-1:-1:950273:950274:950275 -++117:958465:-1:-1:958465:958466:958467 -++118:966657:-1:-1:966657:966658:966659 -++119:974849:-1:-1:974849:974850:974851 -++120:983041:-1:-1:983041:983042:983043 -++121:991233:-1:-1:991233:991234:991235 -++122:999425:-1:-1:999425:999426:999427 -++123:1007617:-1:-1:1007617:1007618:1007619 -++124:1015809:-1:-1:1015809:1015810:1015811 -++125:1024001:1024001:1024002-1024010:1024011:1024012:1024013 -++126:1032193:-1:-1:1032193:1032194:1032195 -++127:1040385:-1:-1:1040385:1040386:1040387 -++128:1048577:-1:-1:1048577:1048578:1048579 -++129:1056769:-1:-1:1056769:1056770:1056771 -++130:1064961:-1:-1:1064961:1064962:1064963 -++131:1073153:-1:-1:1073153:1073154:1073155 -++132:1081345:-1:-1:1081345:1081346:1081347 -++133:1089537:-1:-1:1089537:1089538:1089539 -++134:1097729:-1:-1:1097729:1097730:1097731 -++135:1105921:-1:-1:1105921:1105922:1105923 -++136:1114113:-1:-1:1114113:1114114:1114115 -++137:1122305:-1:-1:1122305:1122306:1122307 -++138:1130497:-1:-1:1130497:1130498:1130499 -++139:1138689:-1:-1:1138689:1138690:1138691 -++140:1146881:-1:-1:1146881:1146882:1146883 -++141:1155073:-1:-1:1155073:1155074:1155075 -++142:1163265:-1:-1:1163265:1163266:1163267 -++143:1171457:-1:-1:1171457:1171458:1171459 -+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 -+ -+Exit status is 0 -diff --git a/tests/r_32to64bit_expand_full/name b/tests/r_32to64bit_expand_full/name -new file mode 100644 -index 0000000..2f04601 ---- /dev/null -+++ b/tests/r_32to64bit_expand_full/name -@@ -0,0 +1 @@ -+convert a totally full filesystem to 64bit, then expand -diff --git a/tests/r_32to64bit_expand_full/script b/tests/r_32to64bit_expand_full/script -new file mode 100644 -index 0000000..7a57084 ---- /dev/null -+++ b/tests/r_32to64bit_expand_full/script -@@ -0,0 +1,83 @@ -+if test -x $RESIZE2FS_EXE -a -x $DEBUGFS_EXE; then -+ -+FSCK_OPT=-fn -+OUT=$test_name.log -+EXP=$test_dir/expect -+CONF=$TMPFILE.conf -+ -+#gzip -d < $EXP.gz > $EXP -+ -+cat > $CONF << ENDL -+[fs_types] -+ ext4h = { -+ features = has_journal,extent,huge_file,uninit_bg,dir_nlink,extra_isize,sparse_super,filetype,dir_index,ext_attr,^resize_inode,^meta_bg,^flex_bg -+ blocksize = 1024 -+ inode_size = 256 -+ make_hugefiles = true -+ hugefiles_dir = / -+ hugefiles_slack = 0 -+ hugefiles_name = aaaaa -+ hugefiles_digits = 4 -+ hugefiles_size = 1M -+ zero_hugefiles = false -+ } -+ENDL -+ -+echo "resize2fs test" > $OUT -+ -+MKE2FS_CONFIG=$CONF $MKE2FS -F -T ext4h $TMPFILE 786432 >> $OUT 2>&1 -+rm -rf $CONF -+ -+# check -+$FSCK $FSCK_OPT -N test_filesys $TMPFILE >> $OUT 2>&1 -+status=$? -+echo Exit status is $status >> $OUT -+ -+# convert it -+echo "resize2fs -b test.img" >> $OUT -+$RESIZE2FS -b -f $TMPFILE 2>&1 >> $OUT 2>&1 -+$DUMPE2FS -g $TMPFILE 2>&1 >> $OUT.before 2> /dev/null -+ -+# grow it -+echo "resize2fs test.img" >> $OUT -+dd if=/dev/zero of=$TMPFILE conv=notrunc bs=1 count=1 seek=1207959552 2> /dev/null -+$RESIZE2FS -f $TMPFILE 2>&1 >> $OUT 2>&1 -+status=$? -+echo Exit status is $status >> $OUT -+ -+# dump and check -+$DUMPE2FS -g $TMPFILE 2>&1 >> $OUT.after 2> /dev/null -+echo "Change in FS metadata:" >> $OUT -+diff -u $OUT.before $OUT.after | tail -n +3 >> $OUT -+$FSCK $FSCK_OPT -N test_filesys $TMPFILE >> $OUT 2>&1 -+status=$? -+echo Exit status is $status >> $OUT -+ -+rm $TMPFILE -+ -+# -+# Do the verification -+# -+ -+sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" -e 's/test_filesys:.*//g' < $OUT > $OUT.new -+mv $OUT.new $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 -+ -+rm $OUT.before $OUT.after -+ -+unset IMAGE FSCK_OPT OUT EXP CONF -+ -+else #if test -x $RESIZE2FS_EXE -a -x $DEBUGFS_EXE; then -+ echo "$test_name: $test_description: skipped" -+fi -+ -diff --git a/tests/r_32to64bit_meta/expect b/tests/r_32to64bit_meta/expect -new file mode 100644 -index 0000000..0eacd45 ---- /dev/null -+++ b/tests/r_32to64bit_meta/expect -@@ -0,0 +1,80 @@ -+resize2fs test -+Creating filesystem with 524288 1k blocks and 65536 inodes -+Superblock backups stored on blocks: -+ 8193, 24577, 40961, 57345, 73729, 204801, 221185, 401409 -+ -+Allocating group tables: done -+Writing inode tables: done -+Creating journal (16384 blocks): done -+Creating 479 huge file(s) with 1024 blocks each: done -+Writing superblocks and filesystem accounting information: done -+ -+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 -+ -+Exit status is 0 -+resize2fs test.img -b -+Converting the filesystem to 64-bit. -+The filesystem on test.img is now 524288 (1k) blocks long. -+ -+Exit status is 0 -+Change in FS metadata: -+@@ -2,7 +2,7 @@ -+ Last mounted on: -+ Filesystem magic number: 0xEF53 -+ Filesystem revision #: 1 (dynamic) -+-Filesystem features: has_journal ext_attr dir_index filetype meta_bg extent flex_bg sparse_super large_file huge_file uninit_bg dir_nlink extra_isize -++Filesystem features: has_journal ext_attr dir_index filetype meta_bg extent 64bit flex_bg sparse_super large_file huge_file uninit_bg dir_nlink extra_isize -+ Default mount options: user_xattr acl -+ Filesystem state: clean -+ Errors behavior: Continue -+@@ -10,11 +10,12 @@ -+ Inode count: 65536 -+ Block count: 524288 -+ Reserved block count: 26214 -+-Free blocks: 858 -++Free blocks: 852 -+ Free inodes: 65046 -+ First block: 1 -+ Block size: 1024 -+ Fragment size: 1024 -++Group descriptor size: 64 -+ Blocks per group: 8192 -+ Fragments per group: 8192 -+ Inodes per group: 1024 -+@@ -54,9 +55,9 @@ -+ 12:98305:-1:-1:15:31:3107 -+ 13:106497:-1:-1:16:32:3363 -+ 14:114689:-1:-1:17:33:3619 -+-15:122881:-1:-1:18:34:3875 -+-16:131073:-1:-1:131073:131089:131105 -+-17:139265:-1:-1:131074:131090:131361 -++15:122881:-1:122881:18:34:3875 -++16:131073:-1:131073:135201:131089:131105 -++17:139265:-1:139265:131074:131090:131361 -+ 18:147457:-1:-1:131075:131091:131617 -+ 19:155649:-1:-1:131076:131092:131873 -+ 20:163841:-1:-1:131077:131093:132129 -+@@ -86,9 +87,9 @@ -+ 44:360449:-1:-1:262158:262174:265250 -+ 45:368641:-1:-1:262159:262175:265506 -+ 46:376833:-1:-1:262160:262176:265762 -+-47:385025:-1:-1:262161:262177:266018 -+-48:393217:-1:-1:393217:393233:393249 -+-49:401409:401409:-1:393218:393234:393505 -++47:385025:-1:385025:262161:262177:266018 -++48:393217:-1:393217:397345:393233:393249 -++49:401409:401409:401410:393218:393234:393505 -+ 50:409601:-1:-1:393219:393235:393761 -+ 51:417793:-1:-1:393220:393236:394017 -+ 52:425985:-1:-1:393221:393237:394273 -+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 -+ -+Exit status is 0 -diff --git a/tests/r_32to64bit_meta/name b/tests/r_32to64bit_meta/name -new file mode 100644 -index 0000000..d83492e ---- /dev/null -+++ b/tests/r_32to64bit_meta/name -@@ -0,0 +1 @@ -+convert meta_bg 32bit fs to 64bit fs -diff --git a/tests/r_32to64bit_meta/script b/tests/r_32to64bit_meta/script -new file mode 100644 -index 0000000..25872c4 ---- /dev/null -+++ b/tests/r_32to64bit_meta/script -@@ -0,0 +1,74 @@ -+if test -x $RESIZE2FS_EXE -a -x $DEBUGFS_EXE; then -+ -+FSCK_OPT=-fn -+OUT=$test_name.log -+EXP=$test_dir/expect -+CONF=$TMPFILE.conf -+ -+cat > $CONF << ENDL -+[fs_types] -+ ext4h = { -+ features = has_journal,extent,huge_file,flex_bg,uninit_bg,dir_nlink,extra_isize,sparse_super,filetype,dir_index,ext_attr,meta_bg,^resize_inode -+ blocksize = 1024 -+ inode_size = 256 -+ make_hugefiles = true -+ hugefiles_dir = / -+ hugefiles_slack = 0 -+ hugefiles_name = aaaaa -+ hugefiles_digits = 4 -+ hugefiles_size = 1M -+ zero_hugefiles = false -+ } -+ENDL -+ -+echo "resize2fs test" > $OUT -+ -+MKE2FS_CONFIG=$CONF $MKE2FS -F -T ext4h $TMPFILE 524288 >> $OUT 2>&1 -+rm -rf $CONF -+ -+# dump and check -+($DUMPE2FS -h $TMPFILE; $DUMPE2FS -g $TMPFILE) 2> /dev/null | sed -f $cmd_dir/filter.sed > $OUT.before -+$FSCK $FSCK_OPT -N test_filesys $TMPFILE >> $OUT 2>&1 -+status=$? -+echo Exit status is $status >> $OUT -+ -+# resize it -+echo "resize2fs test.img -b" >> $OUT -+$RESIZE2FS -b -f $TMPFILE 2>&1 >> $OUT 2>&1 -+status=$? -+echo Exit status is $status >> $OUT -+ -+# dump and check -+($DUMPE2FS -h $TMPFILE; $DUMPE2FS -g $TMPFILE) 2> /dev/null | sed -f $cmd_dir/filter.sed > $OUT.after -+echo "Change in FS metadata:" >> $OUT -+diff -u $OUT.before $OUT.after | tail -n +3 >> $OUT -+$FSCK $FSCK_OPT -N test_filesys $TMPFILE >> $OUT 2>&1 -+status=$? -+echo Exit status is $status >> $OUT -+ -+rm $TMPFILE $OUT.before $OUT.after -+ -+# -+# Do the verification -+# -+ -+sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" -e 's/test_filesys:.*//g' < $OUT > $OUT.new -+mv $OUT.new $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 IMAGE FSCK_OPT OUT EXP CONF -+ -+else #if test -x $RESIZE2FS_EXE -a -x $DEBUGFS_EXE; then -+ echo "$test_name: $test_description: skipped" -+fi -+ -diff --git a/tests/r_32to64bit_move_itable/expect b/tests/r_32to64bit_move_itable/expect -new file mode 100644 -index 0000000..b51663d ---- /dev/null -+++ b/tests/r_32to64bit_move_itable/expect -@@ -0,0 +1,107 @@ -+resize2fs test -+Creating filesystem with 786432 1k blocks and 98304 inodes -+Superblock backups stored on blocks: -+ 8193, 24577, 40961, 57345, 73729, 204801, 221185, 401409, 663553 -+ -+Allocating group tables: done -+Writing inode tables: done -+Creating journal (16384 blocks): done -+Creating 727 huge file(s) with 1024 blocks each: done -+Writing superblocks and filesystem accounting information: done -+ -+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 -+ -+Exit status is 0 -+resize2fs test.img -b -+Converting the filesystem to 64-bit. -+The filesystem on test.img is now 786432 (1k) blocks long. -+ -+Exit status is 0 -+Change in FS metadata: -+@@ -2,7 +2,7 @@ -+ Last mounted on: -+ Filesystem magic number: 0xEF53 -+ Filesystem revision #: 1 (dynamic) -+-Filesystem features: has_journal ext_attr dir_index filetype extent sparse_super large_file huge_file uninit_bg dir_nlink extra_isize -++Filesystem features: has_journal ext_attr dir_index filetype extent 64bit sparse_super large_file huge_file uninit_bg dir_nlink extra_isize -+ Default mount options: user_xattr acl -+ Filesystem state: clean -+ Errors behavior: Continue -+@@ -10,11 +10,12 @@ -+ Inode count: 98304 -+ Block count: 786432 -+ Reserved block count: 39321 -+-Free blocks: 764 -++Free blocks: 734 -+ Free inodes: 97566 -+ First block: 1 -+ Block size: 1024 -+ Fragment size: 1024 -++Group descriptor size: 64 -+ Blocks per group: 8192 -+ Fragments per group: 8192 -+ Inodes per group: 1024 -+@@ -38,16 +39,16 @@ -+ -+ -+ group:block:super:gdt:bbitmap:ibitmap:itable -+-0:1:1:2-4:5:6:7 -+-1:8193:8193:8194-8196:8197:8198:8199 -++0:1:1:2-7:8:9:10 -++1:8193:8193:8194-8199:8200:8201:8202 -+ 2:16385:-1:-1:16385:16386:16387 -+-3:24577:24577:24578-24580:24581:24582:24583 -++3:24577:24577:24578-24583:24584:24585:24586 -+ 4:32769:-1:-1:32769:32770:32771 -+-5:40961:40961:40962-40964:40965:40966:40967 -++5:40961:40961:40962-40967:40968:40969:40970 -+ 6:49153:-1:-1:49153:49154:49155 -+-7:57345:57345:57346-57348:57349:57350:57351 -++7:57345:57345:57346-57351:57352:57353:57354 -+ 8:65537:-1:-1:65537:65538:65539 -+-9:73729:73729:73730-73732:73733:73734:73735 -++9:73729:73729:73730-73735:73736:73737:73738 -+ 10:81921:-1:-1:81921:81922:81923 -+ 11:90113:-1:-1:90113:90114:90115 -+ 12:98305:-1:-1:98305:98306:98307 -+@@ -63,9 +64,9 @@ -+ 22:180225:-1:-1:180225:180226:180227 -+ 23:188417:-1:-1:188417:188418:188419 -+ 24:196609:-1:-1:196609:196610:196611 -+-25:204801:204801:204802-204804:204805:204806:204807 -++25:204801:204801:204802-204807:204808:204809:204810 -+ 26:212993:-1:-1:212993:212994:212995 -+-27:221185:221185:221186-221188:221189:221190:221191 -++27:221185:221185:221186-221191:221192:221193:221194 -+ 28:229377:-1:-1:229377:229378:229379 -+ 29:237569:-1:-1:237569:237570:237571 -+ 30:245761:-1:-1:245761:245762:245763 -+@@ -87,7 +88,7 @@ -+ 46:376833:-1:-1:376833:376834:376835 -+ 47:385025:-1:-1:385025:385026:385027 -+ 48:393217:-1:-1:393217:393218:393219 -+-49:401409:401409:401410-401412:401413:401414:401415 -++49:401409:401409:401410-401415:401416:401417:401418 -+ 50:409601:-1:-1:409601:409602:409603 -+ 51:417793:-1:-1:417793:417794:417795 -+ 52:425985:-1:-1:425985:425986:425987 -+@@ -119,7 +120,7 @@ -+ 78:638977:-1:-1:638977:638978:638979 -+ 79:647169:-1:-1:647169:647170:647171 -+ 80:655361:-1:-1:655361:655362:655363 -+-81:663553:663553:663554-663556:663557:663558:663559 -++81:663553:663553:663554-663559:663560:663561:663562 -+ 82:671745:-1:-1:671745:671746:671747 -+ 83:679937:-1:-1:679937:679938:679939 -+ 84:688129:-1:-1:688129:688130:688131 -+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 -+ -+Exit status is 0 -diff --git a/tests/r_32to64bit_move_itable/name b/tests/r_32to64bit_move_itable/name -new file mode 100644 -index 0000000..7e6bb25 ---- /dev/null -+++ b/tests/r_32to64bit_move_itable/name -@@ -0,0 +1 @@ -+convert 32bit fs to 64bit fs, forcing inode table move -diff --git a/tests/r_32to64bit_move_itable/script b/tests/r_32to64bit_move_itable/script -new file mode 100644 -index 0000000..c188acd ---- /dev/null -+++ b/tests/r_32to64bit_move_itable/script -@@ -0,0 +1,74 @@ -+if test -x $RESIZE2FS_EXE -a -x $DEBUGFS_EXE; then -+ -+FSCK_OPT=-fn -+OUT=$test_name.log -+EXP=$test_dir/expect -+CONF=$TMPFILE.conf -+ -+cat > $CONF << ENDL -+[fs_types] -+ ext4h = { -+ features = has_journal,extent,huge_file,uninit_bg,dir_nlink,extra_isize,sparse_super,filetype,dir_index,ext_attr,^resize_inode,^meta_bg,^flex_bg -+ blocksize = 1024 -+ inode_size = 256 -+ make_hugefiles = true -+ hugefiles_dir = / -+ hugefiles_slack = 0 -+ hugefiles_name = aaaaa -+ hugefiles_digits = 4 -+ hugefiles_size = 1M -+ zero_hugefiles = false -+ } -+ENDL -+ -+echo "resize2fs test" > $OUT -+ -+MKE2FS_CONFIG=$CONF $MKE2FS -F -T ext4h $TMPFILE 786432 >> $OUT 2>&1 -+rm -rf $CONF -+ -+# dump and check -+($DUMPE2FS -h $TMPFILE; $DUMPE2FS -g $TMPFILE) 2> /dev/null | sed -f $cmd_dir/filter.sed > $OUT.before -+$FSCK $FSCK_OPT -N test_filesys $TMPFILE >> $OUT 2>&1 -+status=$? -+echo Exit status is $status >> $OUT -+ -+# convert it -+echo "resize2fs test.img -b" >> $OUT -+$RESIZE2FS -b -f $TMPFILE 2>&1 >> $OUT 2>&1 -+status=$? -+echo Exit status is $status >> $OUT -+ -+# dump and check -+($DUMPE2FS -h $TMPFILE; $DUMPE2FS -g $TMPFILE) 2> /dev/null | sed -f $cmd_dir/filter.sed > $OUT.after -+echo "Change in FS metadata:" >> $OUT -+diff -u $OUT.before $OUT.after | tail -n +3 >> $OUT -+$FSCK $FSCK_OPT -N test_filesys $TMPFILE >> $OUT 2>&1 -+status=$? -+echo Exit status is $status >> $OUT -+ -+rm $TMPFILE $OUT.before $OUT.after -+ -+# -+# Do the verification -+# -+ -+sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" -e 's/test_filesys:.*//g' < $OUT > $OUT.new -+mv $OUT.new $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 IMAGE FSCK_OPT OUT EXP CONF -+ -+else #if test -x $RESIZE2FS_EXE -a -x $DEBUGFS_EXE; then -+ echo "$test_name: $test_description: skipped" -+fi -+ -diff --git a/tests/r_64to32bit/expect b/tests/r_64to32bit/expect -new file mode 100644 -index 0000000..13e94a2 ---- /dev/null -+++ b/tests/r_64to32bit/expect -@@ -0,0 +1,98 @@ -+resize2fs test -+Creating filesystem with 524288 1k blocks and 65536 inodes -+Superblock backups stored on blocks: -+ 8193, 24577, 40961, 57345, 73729, 204801, 221185, 401409 -+ -+Allocating group tables: done -+Writing inode tables: done -+Creating journal (16384 blocks): done -+Creating 477 huge file(s) with 1024 blocks each: done -+Writing superblocks and filesystem accounting information: done -+ -+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 -+ -+Exit status is 0 -+resize2fs test.img -s -+Converting the filesystem to 32-bit. -+The filesystem on test.img is now 524288 (1k) blocks long. -+ -+Exit status is 0 -+Change in FS metadata: -+@@ -2,7 +2,7 @@ -+ Last mounted on: -+ Filesystem magic number: 0xEF53 -+ Filesystem revision #: 1 (dynamic) -+-Filesystem features: has_journal ext_attr resize_inode dir_index filetype extent 64bit flex_bg sparse_super large_file huge_file uninit_bg dir_nlink extra_isize -++Filesystem features: has_journal ext_attr resize_inode dir_index filetype extent flex_bg sparse_super large_file huge_file uninit_bg dir_nlink extra_isize -+ Default mount options: user_xattr acl -+ Filesystem state: clean -+ Errors behavior: Continue -+@@ -10,12 +10,11 @@ -+ Inode count: 65536 -+ Block count: 524288 -+ Reserved block count: 26214 -+-Free blocks: 571 -++Free blocks: 589 -+ Free inodes: 65048 -+ First block: 1 -+ Block size: 1024 -+ Fragment size: 1024 -+-Group descriptor size: 64 -+ Reserved GDT blocks: 256 -+ Blocks per group: 8192 -+ Fragments per group: 8192 -+@@ -41,16 +40,16 @@ -+ -+ -+ group:block:super:gdt:bbitmap:ibitmap:itable -+-0:1:1:2-5:262:278:294 -+-1:8193:8193:8194-8197:263:279:550 -++0:1:1:2-3:262:278:294 -++1:8193:8193:8194-8195:263:279:550 -+ 2:16385:-1:-1:264:280:806 -+-3:24577:24577:24578-24581:265:281:1062 -++3:24577:24577:24578-24579:265:281:1062 -+ 4:32769:-1:-1:266:282:1318 -+-5:40961:40961:40962-40965:267:283:1574 -++5:40961:40961:40962-40963:267:283:1574 -+ 6:49153:-1:-1:268:284:1830 -+-7:57345:57345:57346-57349:269:285:2086 -++7:57345:57345:57346-57347:269:285:2086 -+ 8:65537:-1:-1:270:286:2342 -+-9:73729:73729:73730-73733:271:287:2598 -++9:73729:73729:73730-73731:271:287:2598 -+ 10:81921:-1:-1:272:288:2854 -+ 11:90113:-1:-1:273:289:3110 -+ 12:98305:-1:-1:274:290:3366 -+@@ -66,9 +65,9 @@ -+ 22:180225:-1:-1:131079:131095:132641 -+ 23:188417:-1:-1:131080:131096:132897 -+ 24:196609:-1:-1:131081:131097:133153 -+-25:204801:204801:204802-204805:131082:131098:133409 -++25:204801:204801:204802-204803:131082:131098:133409 -+ 26:212993:-1:-1:131083:131099:133665 -+-27:221185:221185:221186-221189:131084:131100:133921 -++27:221185:221185:221186-221187:131084:131100:133921 -+ 28:229377:-1:-1:131085:131101:134177 -+ 29:237569:-1:-1:131086:131102:134433 -+ 30:245761:-1:-1:131087:131103:134689 -+@@ -90,7 +89,7 @@ -+ 46:376833:-1:-1:262159:262175:265761 -+ 47:385025:-1:-1:262160:262176:266017 -+ 48:393217:-1:-1:393217:393233:393249 -+-49:401409:401409:401410-401413:393218:393234:393505 -++49:401409:401409:401410-401411:393218:393234:393505 -+ 50:409601:-1:-1:393219:393235:393761 -+ 51:417793:-1:-1:393220:393236:394017 -+ 52:425985:-1:-1:393221:393237:394273 -+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 -+ -+Exit status is 0 -diff --git a/tests/r_64to32bit/name b/tests/r_64to32bit/name -new file mode 100644 -index 0000000..4c82371 ---- /dev/null -+++ b/tests/r_64to32bit/name -@@ -0,0 +1 @@ -+convert flex_bg 64bit fs to 32bit fs -diff --git a/tests/r_64to32bit/script b/tests/r_64to32bit/script -new file mode 100644 -index 0000000..5d959f0 ---- /dev/null -+++ b/tests/r_64to32bit/script -@@ -0,0 +1,76 @@ -+if test -x $RESIZE2FS_EXE -a -x $DEBUGFS_EXE; then -+ -+FSCK_OPT=-fn -+OUT=$test_name.log -+EXP=$test_dir/expect -+CONF=$TMPFILE.conf -+ -+cat > $CONF << ENDL -+[fs_types] -+ ext4h = { -+ features = has_journal,extent,huge_file,flex_bg,uninit_bg,dir_nlink,extra_isize,sparse_super,filetype,dir_index,ext_attr,resize_inode,64bit -+ blocksize = 1024 -+ inode_size = 256 -+ make_hugefiles = true -+ hugefiles_dir = / -+ hugefiles_slack = 0 -+ hugefiles_name = aaaaa -+ hugefiles_digits = 4 -+ hugefiles_size = 1M -+ zero_hugefiles = false -+ } -+ENDL -+ -+echo "resize2fs test" > $OUT -+ -+MKE2FS_CONFIG=$CONF $MKE2FS -F -T ext4h $TMPFILE 524288 >> $OUT 2>&1 -+rm -rf $CONF -+ -+# dump and check -+($DUMPE2FS -h $TMPFILE; $DUMPE2FS -g $TMPFILE) 2> /dev/null | sed -f $cmd_dir/filter.sed > $OUT.before -+$FSCK $FSCK_OPT -N test_filesys $TMPFILE >> $OUT 2>&1 -+status=$? -+echo Exit status is $status >> $OUT -+ -+# resize it -+echo "resize2fs test.img -s" >> $OUT -+$RESIZE2FS -s -f $TMPFILE 2>&1 >> $OUT 2>&1 -+status=$? -+echo Exit status is $status >> $OUT -+ -+# dump and check -+($DUMPE2FS -h $TMPFILE; $DUMPE2FS -g $TMPFILE) 2> /dev/null | sed -f $cmd_dir/filter.sed > $OUT.after -+echo "Change in FS metadata:" >> $OUT -+diff -u $OUT.before $OUT.after | tail -n +3 >> $OUT -+$FSCK $FSCK_OPT -N test_filesys $TMPFILE >> $OUT 2>&1 -+status=$? -+echo Exit status is $status >> $OUT -+ -+rm $TMPFILE -+ -+# -+# Do the verification -+# -+ -+sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" -e 's/test_filesys:.*//g' < $OUT > $OUT.new -+mv $OUT.new $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 -+ -+rm $OUT.before $OUT.after -+ -+unset IMAGE FSCK_OPT OUT EXP CONF -+ -+else #if test -x $RESIZE2FS_EXE -a -x $DEBUGFS_EXE; then -+ echo "$test_name: $test_description: skipped" -+fi -+ -diff --git a/tests/r_64to32bit_meta/expect b/tests/r_64to32bit_meta/expect -new file mode 100644 -index 0000000..d6e2dcc ---- /dev/null -+++ b/tests/r_64to32bit_meta/expect -@@ -0,0 +1,80 @@ -+resize2fs test -+Creating filesystem with 524288 1k blocks and 65536 inodes -+Superblock backups stored on blocks: -+ 8193, 24577, 40961, 57345, 73729, 204801, 221185, 401409 -+ -+Allocating group tables: done -+Writing inode tables: done -+Creating journal (16384 blocks): done -+Creating 479 huge file(s) with 1024 blocks each: done -+Writing superblocks and filesystem accounting information: done -+ -+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 -+ -+Exit status is 0 -+resize2fs test.img -s -+Converting the filesystem to 32-bit. -+The filesystem on test.img is now 524288 (1k) blocks long. -+ -+Exit status is 0 -+Change in FS metadata: -+@@ -2,7 +2,7 @@ -+ Last mounted on: -+ Filesystem magic number: 0xEF53 -+ Filesystem revision #: 1 (dynamic) -+-Filesystem features: has_journal ext_attr dir_index filetype meta_bg extent 64bit flex_bg sparse_super large_file huge_file uninit_bg dir_nlink extra_isize -++Filesystem features: has_journal ext_attr dir_index filetype meta_bg extent flex_bg sparse_super large_file huge_file uninit_bg dir_nlink extra_isize -+ Default mount options: user_xattr acl -+ Filesystem state: clean -+ Errors behavior: Continue -+@@ -10,12 +10,11 @@ -+ Inode count: 65536 -+ Block count: 524288 -+ Reserved block count: 26214 -+-Free blocks: 852 -++Free blocks: 858 -+ Free inodes: 65046 -+ First block: 1 -+ Block size: 1024 -+ Fragment size: 1024 -+-Group descriptor size: 64 -+ Blocks per group: 8192 -+ Fragments per group: 8192 -+ Inodes per group: 1024 -+@@ -55,9 +54,9 @@ -+ 12:98305:-1:-1:15:31:3107 -+ 13:106497:-1:-1:16:32:3363 -+ 14:114689:-1:-1:17:33:3619 -+-15:122881:-1:122881:18:34:3875 -+-16:131073:-1:131073:131074:131090:131106 -+-17:139265:-1:139265:131075:131091:131362 -++15:122881:-1:-1:18:34:3875 -++16:131073:-1:-1:131074:131090:131106 -++17:139265:-1:-1:131075:131091:131362 -+ 18:147457:-1:-1:131076:131092:131618 -+ 19:155649:-1:-1:131077:131093:131874 -+ 20:163841:-1:-1:131078:131094:132130 -+@@ -87,9 +86,9 @@ -+ 44:360449:-1:-1:262158:262174:265250 -+ 45:368641:-1:-1:262159:262175:265506 -+ 46:376833:-1:-1:262160:262176:265762 -+-47:385025:-1:385025:262161:262177:266018 -+-48:393217:-1:393217:393218:393234:393250 -+-49:401409:401409:401410:393219:393235:393506 -++47:385025:-1:-1:262161:262177:266018 -++48:393217:-1:-1:393218:393234:393250 -++49:401409:401409:-1:393219:393235:393506 -+ 50:409601:-1:-1:393220:393236:393762 -+ 51:417793:-1:-1:393221:393237:394018 -+ 52:425985:-1:-1:393222:393238:394274 -+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 -+ -+Exit status is 0 -diff --git a/tests/r_64to32bit_meta/name b/tests/r_64to32bit_meta/name -new file mode 100644 -index 0000000..e99ed8b ---- /dev/null -+++ b/tests/r_64to32bit_meta/name -@@ -0,0 +1 @@ -+convert meta_bg 64bit fs to 32bit fs -diff --git a/tests/r_64to32bit_meta/script b/tests/r_64to32bit_meta/script -new file mode 100644 -index 0000000..5a02e26 ---- /dev/null -+++ b/tests/r_64to32bit_meta/script -@@ -0,0 +1,76 @@ -+if test -x $RESIZE2FS_EXE -a -x $DEBUGFS_EXE; then -+ -+FSCK_OPT=-fn -+OUT=$test_name.log -+EXP=$test_dir/expect -+CONF=$TMPFILE.conf -+ -+cat > $CONF << ENDL -+[fs_types] -+ ext4h = { -+ features = has_journal,extent,huge_file,flex_bg,uninit_bg,dir_nlink,extra_isize,sparse_super,filetype,dir_index,ext_attr,meta_bg,^resize_inode,64bit -+ blocksize = 1024 -+ inode_size = 256 -+ make_hugefiles = true -+ hugefiles_dir = / -+ hugefiles_slack = 0 -+ hugefiles_name = aaaaa -+ hugefiles_digits = 4 -+ hugefiles_size = 1M -+ zero_hugefiles = false -+ } -+ENDL -+ -+echo "resize2fs test" > $OUT -+ -+MKE2FS_CONFIG=$CONF $MKE2FS -F -T ext4h $TMPFILE 524288 >> $OUT 2>&1 -+rm -rf $CONF -+ -+# dump and check -+($DUMPE2FS -h $TMPFILE; $DUMPE2FS -g $TMPFILE) 2> /dev/null | sed -f $cmd_dir/filter.sed > $OUT.before -+$FSCK $FSCK_OPT -N test_filesys $TMPFILE >> $OUT 2>&1 -+status=$? -+echo Exit status is $status >> $OUT -+ -+# resize it -+echo "resize2fs test.img -s" >> $OUT -+$RESIZE2FS -s -f $TMPFILE 2>&1 >> $OUT 2>&1 -+status=$? -+echo Exit status is $status >> $OUT -+ -+# dump and check -+($DUMPE2FS -h $TMPFILE; $DUMPE2FS -g $TMPFILE) 2> /dev/null | sed -f $cmd_dir/filter.sed > $OUT.after -+echo "Change in FS metadata:" >> $OUT -+diff -u $OUT.before $OUT.after | tail -n +3 >> $OUT -+$FSCK $FSCK_OPT -N test_filesys $TMPFILE >> $OUT 2>&1 -+status=$? -+echo Exit status is $status >> $OUT -+ -+rm $TMPFILE -+ -+# -+# Do the verification -+# -+ -+sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" -e 's/test_filesys:.*//g' < $OUT > $OUT.new -+mv $OUT.new $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 -+ -+rm $OUT.before $OUT.after -+ -+unset IMAGE FSCK_OPT OUT EXP CONF -+ -+else #if test -x $RESIZE2FS_EXE -a -x $DEBUGFS_EXE; then -+ echo "$test_name: $test_description: skipped" -+fi -+ -diff --git a/tests/r_expand_full/expect b/tests/r_expand_full/expect -new file mode 100644 -index 0000000..c80baa2 ---- /dev/null -+++ b/tests/r_expand_full/expect -@@ -0,0 +1,375 @@ -+resize2fs test -+Creating filesystem with 786432 1k blocks and 98304 inodes -+Superblock backups stored on blocks: -+ 8193, 24577, 40961, 57345, 73729, 204801, 221185, 401409, 663553 -+ -+Allocating group tables: done -+Writing inode tables: done -+Creating journal (16384 blocks): done -+Creating 727 huge file(s) with 1024 blocks each: done -+Writing superblocks and filesystem accounting information: done -+ -+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 -+ -+Exit status is 0 -+resize2fs test.img -+Resizing the filesystem on test.img to 3145728 (1k) blocks. -+The filesystem on test.img is now 3145728 (1k) blocks long. -+ -+Exit status is 0 -+Change in FS metadata: -+@@ -1,15 +1,15 @@ -+ -+ group:block:super:gdt:bbitmap:ibitmap:itable -+-0:1:1:2-4:5:6:7 -+-1:8193:8193:8194-8196:8197:8198:8199 -++0:1:1:2-13:263:264:265 -++1:8193:8193:8194-8205:8455:8456:8457 -+ 2:16385:-1:-1:16385:16386:16387 -+-3:24577:24577:24578-24580:24581:24582:24583 -++3:24577:24577:24578-24589:24839:24840:24841 -+ 4:32769:-1:-1:32769:32770:32771 -+-5:40961:40961:40962-40964:40965:40966:40967 -++5:40961:40961:40962-40973:41223:41224:41225 -+ 6:49153:-1:-1:49153:49154:49155 -+-7:57345:57345:57346-57348:57349:57350:57351 -++7:57345:57345:57346-57357:57607:57608:57609 -+ 8:65537:-1:-1:65537:65538:65539 -+-9:73729:73729:73730-73732:73733:73734:73735 -++9:73729:73729:73730-73741:73991:73992:73993 -+ 10:81921:-1:-1:81921:81922:81923 -+ 11:90113:-1:-1:90113:90114:90115 -+ 12:98305:-1:-1:98305:98306:98307 -+@@ -25,9 +25,9 @@ -+ 22:180225:-1:-1:180225:180226:180227 -+ 23:188417:-1:-1:188417:188418:188419 -+ 24:196609:-1:-1:196609:196610:196611 -+-25:204801:204801:204802-204804:204805:204806:204807 -++25:204801:204801:204802-204813:205063:205064:205065 -+ 26:212993:-1:-1:212993:212994:212995 -+-27:221185:221185:221186-221188:221189:221190:221191 -++27:221185:221185:221186-221197:221447:221448:221449 -+ 28:229377:-1:-1:229377:229378:229379 -+ 29:237569:-1:-1:237569:237570:237571 -+ 30:245761:-1:-1:245761:245762:245763 -+@@ -49,7 +49,7 @@ -+ 46:376833:-1:-1:376833:376834:376835 -+ 47:385025:-1:-1:385025:385026:385027 -+ 48:393217:-1:-1:393217:393218:393219 -+-49:401409:401409:401410-401412:401413:401414:401415 -++49:401409:401409:401410-401421:401671:401672:401673 -+ 50:409601:-1:-1:409601:409602:409603 -+ 51:417793:-1:-1:417793:417794:417795 -+ 52:425985:-1:-1:425985:425986:425987 -+@@ -81,7 +81,7 @@ -+ 78:638977:-1:-1:638977:638978:638979 -+ 79:647169:-1:-1:647169:647170:647171 -+ 80:655361:-1:-1:655361:655362:655363 -+-81:663553:663553:663554-663556:663557:663558:663559 -++81:663553:663553:663554-663565:663815:663816:663817 -+ 82:671745:-1:-1:671745:671746:671747 -+ 83:679937:-1:-1:679937:679938:679939 -+ 84:688129:-1:-1:688129:688130:688131 -+@@ -96,3 +96,291 @@ -+ 93:761857:-1:-1:761857:761858:761859 -+ 94:770049:-1:-1:770049:770050:770051 -+ 95:778241:-1:-1:778241:778242:778243 -++96:786433:-1:-1:786433:786434:786435 -++97:794625:-1:-1:794625:794626:794627 -++98:802817:-1:-1:802817:802818:802819 -++99:811009:-1:-1:811009:811010:811011 -++100:819201:-1:-1:819201:819202:819203 -++101:827393:-1:-1:827393:827394:827395 -++102:835585:-1:-1:835585:835586:835587 -++103:843777:-1:-1:843777:843778:843779 -++104:851969:-1:-1:851969:851970:851971 -++105:860161:-1:-1:860161:860162:860163 -++106:868353:-1:-1:868353:868354:868355 -++107:876545:-1:-1:876545:876546:876547 -++108:884737:-1:-1:884737:884738:884739 -++109:892929:-1:-1:892929:892930:892931 -++110:901121:-1:-1:901121:901122:901123 -++111:909313:-1:-1:909313:909314:909315 -++112:917505:-1:-1:917505:917506:917507 -++113:925697:-1:-1:925697:925698:925699 -++114:933889:-1:-1:933889:933890:933891 -++115:942081:-1:-1:942081:942082:942083 -++116:950273:-1:-1:950273:950274:950275 -++117:958465:-1:-1:958465:958466:958467 -++118:966657:-1:-1:966657:966658:966659 -++119:974849:-1:-1:974849:974850:974851 -++120:983041:-1:-1:983041:983042:983043 -++121:991233:-1:-1:991233:991234:991235 -++122:999425:-1:-1:999425:999426:999427 -++123:1007617:-1:-1:1007617:1007618:1007619 -++124:1015809:-1:-1:1015809:1015810:1015811 -++125:1024001:1024001:1024002-1024013:1024014:1024015:1024016 -++126:1032193:-1:-1:1032193:1032194:1032195 -++127:1040385:-1:-1:1040385:1040386:1040387 -++128:1048577:-1:-1:1048577:1048578:1048579 -++129:1056769:-1:-1:1056769:1056770:1056771 -++130:1064961:-1:-1:1064961:1064962:1064963 -++131:1073153:-1:-1:1073153:1073154:1073155 -++132:1081345:-1:-1:1081345:1081346:1081347 -++133:1089537:-1:-1:1089537:1089538:1089539 -++134:1097729:-1:-1:1097729:1097730:1097731 -++135:1105921:-1:-1:1105921:1105922:1105923 -++136:1114113:-1:-1:1114113:1114114:1114115 -++137:1122305:-1:-1:1122305:1122306:1122307 -++138:1130497:-1:-1:1130497:1130498:1130499 -++139:1138689:-1:-1:1138689:1138690:1138691 -++140:1146881:-1:-1:1146881:1146882:1146883 -++141:1155073:-1:-1:1155073:1155074:1155075 -++142:1163265:-1:-1:1163265:1163266:1163267 -++143:1171457:-1:-1:1171457:1171458:1171459 -++144:1179649:-1:-1:1179649:1179650:1179651 -++145:1187841:-1:-1:1187841:1187842:1187843 -++146:1196033:-1:-1:1196033:1196034:1196035 -++147:1204225:-1:-1:1204225:1204226:1204227 -++148:1212417:-1:-1:1212417:1212418:1212419 -++149:1220609:-1:-1:1220609:1220610:1220611 -++150:1228801:-1:-1:1228801:1228802:1228803 -++151:1236993:-1:-1:1236993:1236994:1236995 -++152:1245185:-1:-1:1245185:1245186:1245187 -++153:1253377:-1:-1:1253377:1253378:1253379 -++154:1261569:-1:-1:1261569:1261570:1261571 -++155:1269761:-1:-1:1269761:1269762:1269763 -++156:1277953:-1:-1:1277953:1277954:1277955 -++157:1286145:-1:-1:1286145:1286146:1286147 -++158:1294337:-1:-1:1294337:1294338:1294339 -++159:1302529:-1:-1:1302529:1302530:1302531 -++160:1310721:-1:-1:1310721:1310722:1310723 -++161:1318913:-1:-1:1318913:1318914:1318915 -++162:1327105:-1:-1:1327105:1327106:1327107 -++163:1335297:-1:-1:1335297:1335298:1335299 -++164:1343489:-1:-1:1343489:1343490:1343491 -++165:1351681:-1:-1:1351681:1351682:1351683 -++166:1359873:-1:-1:1359873:1359874:1359875 -++167:1368065:-1:-1:1368065:1368066:1368067 -++168:1376257:-1:-1:1376257:1376258:1376259 -++169:1384449:-1:-1:1384449:1384450:1384451 -++170:1392641:-1:-1:1392641:1392642:1392643 -++171:1400833:-1:-1:1400833:1400834:1400835 -++172:1409025:-1:-1:1409025:1409026:1409027 -++173:1417217:-1:-1:1417217:1417218:1417219 -++174:1425409:-1:-1:1425409:1425410:1425411 -++175:1433601:-1:-1:1433601:1433602:1433603 -++176:1441793:-1:-1:1441793:1441794:1441795 -++177:1449985:-1:-1:1449985:1449986:1449987 -++178:1458177:-1:-1:1458177:1458178:1458179 -++179:1466369:-1:-1:1466369:1466370:1466371 -++180:1474561:-1:-1:1474561:1474562:1474563 -++181:1482753:-1:-1:1482753:1482754:1482755 -++182:1490945:-1:-1:1490945:1490946:1490947 -++183:1499137:-1:-1:1499137:1499138:1499139 -++184:1507329:-1:-1:1507329:1507330:1507331 -++185:1515521:-1:-1:1515521:1515522:1515523 -++186:1523713:-1:-1:1523713:1523714:1523715 -++187:1531905:-1:-1:1531905:1531906:1531907 -++188:1540097:-1:-1:1540097:1540098:1540099 -++189:1548289:-1:-1:1548289:1548290:1548291 -++190:1556481:-1:-1:1556481:1556482:1556483 -++191:1564673:-1:-1:1564673:1564674:1564675 -++192:1572865:-1:-1:1572865:1572866:1572867 -++193:1581057:-1:-1:1581057:1581058:1581059 -++194:1589249:-1:-1:1589249:1589250:1589251 -++195:1597441:-1:-1:1597441:1597442:1597443 -++196:1605633:-1:-1:1605633:1605634:1605635 -++197:1613825:-1:-1:1613825:1613826:1613827 -++198:1622017:-1:-1:1622017:1622018:1622019 -++199:1630209:-1:-1:1630209:1630210:1630211 -++200:1638401:-1:-1:1638401:1638402:1638403 -++201:1646593:-1:-1:1646593:1646594:1646595 -++202:1654785:-1:-1:1654785:1654786:1654787 -++203:1662977:-1:-1:1662977:1662978:1662979 -++204:1671169:-1:-1:1671169:1671170:1671171 -++205:1679361:-1:-1:1679361:1679362:1679363 -++206:1687553:-1:-1:1687553:1687554:1687555 -++207:1695745:-1:-1:1695745:1695746:1695747 -++208:1703937:-1:-1:1703937:1703938:1703939 -++209:1712129:-1:-1:1712129:1712130:1712131 -++210:1720321:-1:-1:1720321:1720322:1720323 -++211:1728513:-1:-1:1728513:1728514:1728515 -++212:1736705:-1:-1:1736705:1736706:1736707 -++213:1744897:-1:-1:1744897:1744898:1744899 -++214:1753089:-1:-1:1753089:1753090:1753091 -++215:1761281:-1:-1:1761281:1761282:1761283 -++216:1769473:-1:-1:1769473:1769474:1769475 -++217:1777665:-1:-1:1777665:1777666:1777667 -++218:1785857:-1:-1:1785857:1785858:1785859 -++219:1794049:-1:-1:1794049:1794050:1794051 -++220:1802241:-1:-1:1802241:1802242:1802243 -++221:1810433:-1:-1:1810433:1810434:1810435 -++222:1818625:-1:-1:1818625:1818626:1818627 -++223:1826817:-1:-1:1826817:1826818:1826819 -++224:1835009:-1:-1:1835009:1835010:1835011 -++225:1843201:-1:-1:1843201:1843202:1843203 -++226:1851393:-1:-1:1851393:1851394:1851395 -++227:1859585:-1:-1:1859585:1859586:1859587 -++228:1867777:-1:-1:1867777:1867778:1867779 -++229:1875969:-1:-1:1875969:1875970:1875971 -++230:1884161:-1:-1:1884161:1884162:1884163 -++231:1892353:-1:-1:1892353:1892354:1892355 -++232:1900545:-1:-1:1900545:1900546:1900547 -++233:1908737:-1:-1:1908737:1908738:1908739 -++234:1916929:-1:-1:1916929:1916930:1916931 -++235:1925121:-1:-1:1925121:1925122:1925123 -++236:1933313:-1:-1:1933313:1933314:1933315 -++237:1941505:-1:-1:1941505:1941506:1941507 -++238:1949697:-1:-1:1949697:1949698:1949699 -++239:1957889:-1:-1:1957889:1957890:1957891 -++240:1966081:-1:-1:1966081:1966082:1966083 -++241:1974273:-1:-1:1974273:1974274:1974275 -++242:1982465:-1:-1:1982465:1982466:1982467 -++243:1990657:1990657:1990658-1990669:1990670:1990671:1990672 -++244:1998849:-1:-1:1998849:1998850:1998851 -++245:2007041:-1:-1:2007041:2007042:2007043 -++246:2015233:-1:-1:2015233:2015234:2015235 -++247:2023425:-1:-1:2023425:2023426:2023427 -++248:2031617:-1:-1:2031617:2031618:2031619 -++249:2039809:-1:-1:2039809:2039810:2039811 -++250:2048001:-1:-1:2048001:2048002:2048003 -++251:2056193:-1:-1:2056193:2056194:2056195 -++252:2064385:-1:-1:2064385:2064386:2064387 -++253:2072577:-1:-1:2072577:2072578:2072579 -++254:2080769:-1:-1:2080769:2080770:2080771 -++255:2088961:-1:-1:2088961:2088962:2088963 -++256:2097153:-1:-1:2097153:2097154:2097155 -++257:2105345:-1:-1:2105345:2105346:2105347 -++258:2113537:-1:-1:2113537:2113538:2113539 -++259:2121729:-1:-1:2121729:2121730:2121731 -++260:2129921:-1:-1:2129921:2129922:2129923 -++261:2138113:-1:-1:2138113:2138114:2138115 -++262:2146305:-1:-1:2146305:2146306:2146307 -++263:2154497:-1:-1:2154497:2154498:2154499 -++264:2162689:-1:-1:2162689:2162690:2162691 -++265:2170881:-1:-1:2170881:2170882:2170883 -++266:2179073:-1:-1:2179073:2179074:2179075 -++267:2187265:-1:-1:2187265:2187266:2187267 -++268:2195457:-1:-1:2195457:2195458:2195459 -++269:2203649:-1:-1:2203649:2203650:2203651 -++270:2211841:-1:-1:2211841:2211842:2211843 -++271:2220033:-1:-1:2220033:2220034:2220035 -++272:2228225:-1:-1:2228225:2228226:2228227 -++273:2236417:-1:-1:2236417:2236418:2236419 -++274:2244609:-1:-1:2244609:2244610:2244611 -++275:2252801:-1:-1:2252801:2252802:2252803 -++276:2260993:-1:-1:2260993:2260994:2260995 -++277:2269185:-1:-1:2269185:2269186:2269187 -++278:2277377:-1:-1:2277377:2277378:2277379 -++279:2285569:-1:-1:2285569:2285570:2285571 -++280:2293761:-1:-1:2293761:2293762:2293763 -++281:2301953:-1:-1:2301953:2301954:2301955 -++282:2310145:-1:-1:2310145:2310146:2310147 -++283:2318337:-1:-1:2318337:2318338:2318339 -++284:2326529:-1:-1:2326529:2326530:2326531 -++285:2334721:-1:-1:2334721:2334722:2334723 -++286:2342913:-1:-1:2342913:2342914:2342915 -++287:2351105:-1:-1:2351105:2351106:2351107 -++288:2359297:-1:-1:2359297:2359298:2359299 -++289:2367489:-1:-1:2367489:2367490:2367491 -++290:2375681:-1:-1:2375681:2375682:2375683 -++291:2383873:-1:-1:2383873:2383874:2383875 -++292:2392065:-1:-1:2392065:2392066:2392067 -++293:2400257:-1:-1:2400257:2400258:2400259 -++294:2408449:-1:-1:2408449:2408450:2408451 -++295:2416641:-1:-1:2416641:2416642:2416643 -++296:2424833:-1:-1:2424833:2424834:2424835 -++297:2433025:-1:-1:2433025:2433026:2433027 -++298:2441217:-1:-1:2441217:2441218:2441219 -++299:2449409:-1:-1:2449409:2449410:2449411 -++300:2457601:-1:-1:2457601:2457602:2457603 -++301:2465793:-1:-1:2465793:2465794:2465795 -++302:2473985:-1:-1:2473985:2473986:2473987 -++303:2482177:-1:-1:2482177:2482178:2482179 -++304:2490369:-1:-1:2490369:2490370:2490371 -++305:2498561:-1:-1:2498561:2498562:2498563 -++306:2506753:-1:-1:2506753:2506754:2506755 -++307:2514945:-1:-1:2514945:2514946:2514947 -++308:2523137:-1:-1:2523137:2523138:2523139 -++309:2531329:-1:-1:2531329:2531330:2531331 -++310:2539521:-1:-1:2539521:2539522:2539523 -++311:2547713:-1:-1:2547713:2547714:2547715 -++312:2555905:-1:-1:2555905:2555906:2555907 -++313:2564097:-1:-1:2564097:2564098:2564099 -++314:2572289:-1:-1:2572289:2572290:2572291 -++315:2580481:-1:-1:2580481:2580482:2580483 -++316:2588673:-1:-1:2588673:2588674:2588675 -++317:2596865:-1:-1:2596865:2596866:2596867 -++318:2605057:-1:-1:2605057:2605058:2605059 -++319:2613249:-1:-1:2613249:2613250:2613251 -++320:2621441:-1:-1:2621441:2621442:2621443 -++321:2629633:-1:-1:2629633:2629634:2629635 -++322:2637825:-1:-1:2637825:2637826:2637827 -++323:2646017:-1:-1:2646017:2646018:2646019 -++324:2654209:-1:-1:2654209:2654210:2654211 -++325:2662401:-1:-1:2662401:2662402:2662403 -++326:2670593:-1:-1:2670593:2670594:2670595 -++327:2678785:-1:-1:2678785:2678786:2678787 -++328:2686977:-1:-1:2686977:2686978:2686979 -++329:2695169:-1:-1:2695169:2695170:2695171 -++330:2703361:-1:-1:2703361:2703362:2703363 -++331:2711553:-1:-1:2711553:2711554:2711555 -++332:2719745:-1:-1:2719745:2719746:2719747 -++333:2727937:-1:-1:2727937:2727938:2727939 -++334:2736129:-1:-1:2736129:2736130:2736131 -++335:2744321:-1:-1:2744321:2744322:2744323 -++336:2752513:-1:-1:2752513:2752514:2752515 -++337:2760705:-1:-1:2760705:2760706:2760707 -++338:2768897:-1:-1:2768897:2768898:2768899 -++339:2777089:-1:-1:2777089:2777090:2777091 -++340:2785281:-1:-1:2785281:2785282:2785283 -++341:2793473:-1:-1:2793473:2793474:2793475 -++342:2801665:-1:-1:2801665:2801666:2801667 -++343:2809857:2809857:2809858-2809869:2809870:2809871:2809872 -++344:2818049:-1:-1:2818049:2818050:2818051 -++345:2826241:-1:-1:2826241:2826242:2826243 -++346:2834433:-1:-1:2834433:2834434:2834435 -++347:2842625:-1:-1:2842625:2842626:2842627 -++348:2850817:-1:-1:2850817:2850818:2850819 -++349:2859009:-1:-1:2859009:2859010:2859011 -++350:2867201:-1:-1:2867201:2867202:2867203 -++351:2875393:-1:-1:2875393:2875394:2875395 -++352:2883585:-1:-1:2883585:2883586:2883587 -++353:2891777:-1:-1:2891777:2891778:2891779 -++354:2899969:-1:-1:2899969:2899970:2899971 -++355:2908161:-1:-1:2908161:2908162:2908163 -++356:2916353:-1:-1:2916353:2916354:2916355 -++357:2924545:-1:-1:2924545:2924546:2924547 -++358:2932737:-1:-1:2932737:2932738:2932739 -++359:2940929:-1:-1:2940929:2940930:2940931 -++360:2949121:-1:-1:2949121:2949122:2949123 -++361:2957313:-1:-1:2957313:2957314:2957315 -++362:2965505:-1:-1:2965505:2965506:2965507 -++363:2973697:-1:-1:2973697:2973698:2973699 -++364:2981889:-1:-1:2981889:2981890:2981891 -++365:2990081:-1:-1:2990081:2990082:2990083 -++366:2998273:-1:-1:2998273:2998274:2998275 -++367:3006465:-1:-1:3006465:3006466:3006467 -++368:3014657:-1:-1:3014657:3014658:3014659 -++369:3022849:-1:-1:3022849:3022850:3022851 -++370:3031041:-1:-1:3031041:3031042:3031043 -++371:3039233:-1:-1:3039233:3039234:3039235 -++372:3047425:-1:-1:3047425:3047426:3047427 -++373:3055617:-1:-1:3055617:3055618:3055619 -++374:3063809:-1:-1:3063809:3063810:3063811 -++375:3072001:-1:-1:3072001:3072002:3072003 -++376:3080193:-1:-1:3080193:3080194:3080195 -++377:3088385:-1:-1:3088385:3088386:3088387 -++378:3096577:-1:-1:3096577:3096578:3096579 -++379:3104769:-1:-1:3104769:3104770:3104771 -++380:3112961:-1:-1:3112961:3112962:3112963 -++381:3121153:-1:-1:3121153:3121154:3121155 -++382:3129345:-1:-1:3129345:3129346:3129347 -++383:3137537:-1:-1:3137537:3137538:3137539 -+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 -+ -+Exit status is 0 -diff --git a/tests/r_expand_full/name b/tests/r_expand_full/name -new file mode 100644 -index 0000000..af40cba ---- /dev/null -+++ b/tests/r_expand_full/name -@@ -0,0 +1 @@ -+expand a totally full filesystem -diff --git a/tests/r_expand_full/script b/tests/r_expand_full/script -new file mode 100644 -index 0000000..a2c09db ---- /dev/null -+++ b/tests/r_expand_full/script -@@ -0,0 +1,79 @@ -+if test -x $RESIZE2FS_EXE -a -x $DEBUGFS_EXE; then -+ -+FSCK_OPT=-fn -+OUT=$test_name.log -+EXP=$test_dir/expect -+CONF=$TMPFILE.conf -+ -+#gzip -d < $EXP.gz > $EXP -+ -+cat > $CONF << ENDL -+[fs_types] -+ ext4h = { -+ features = has_journal,extent,huge_file,uninit_bg,dir_nlink,extra_isize,sparse_super,filetype,dir_index,ext_attr,^resize_inode,^meta_bg,^flex_bg -+ blocksize = 1024 -+ inode_size = 256 -+ make_hugefiles = true -+ hugefiles_dir = / -+ hugefiles_slack = 0 -+ hugefiles_name = aaaaa -+ hugefiles_digits = 4 -+ hugefiles_size = 1M -+ zero_hugefiles = false -+ } -+ENDL -+ -+echo "resize2fs test" > $OUT -+ -+MKE2FS_CONFIG=$CONF $MKE2FS -F -T ext4h $TMPFILE 786432 >> $OUT 2>&1 -+rm -rf $CONF -+ -+# dump and check -+$DUMPE2FS -g $TMPFILE 2>&1 >> $OUT.before 2> /dev/null -+$FSCK $FSCK_OPT -N test_filesys $TMPFILE >> $OUT 2>&1 -+status=$? -+echo Exit status is $status >> $OUT -+ -+# convert it -+echo "resize2fs test.img" >> $OUT -+dd if=/dev/zero of=$TMPFILE conv=notrunc bs=1 count=1 seek=3221225471 2> /dev/null -+$RESIZE2FS -f $TMPFILE 2>&1 >> $OUT 2>&1 -+status=$? -+echo Exit status is $status >> $OUT -+ -+# dump and check -+$DUMPE2FS -g $TMPFILE 2>&1 >> $OUT.after 2> /dev/null -+echo "Change in FS metadata:" >> $OUT -+diff -u $OUT.before $OUT.after | tail -n +3 >> $OUT -+$FSCK $FSCK_OPT -N test_filesys $TMPFILE >> $OUT 2>&1 -+status=$? -+echo Exit status is $status >> $OUT -+ -+rm $TMPFILE -+ -+# -+# Do the verification -+# -+ -+sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" -e 's/test_filesys:.*//g' < $OUT > $OUT.new -+mv $OUT.new $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 -+ -+rm $OUT.before $OUT.after -+ -+unset IMAGE FSCK_OPT OUT EXP CONF -+ -+else #if test -x $RESIZE2FS_EXE -a -x $DEBUGFS_EXE; then -+ echo "$test_name: $test_description: skipped" -+fi -+ -diff --git a/tests/r_fixup_lastbg/expect b/tests/r_fixup_lastbg/expect -new file mode 100644 -index 0000000..96b154a ---- /dev/null -+++ b/tests/r_fixup_lastbg/expect -@@ -0,0 +1,39 @@ -+Creating filesystem with 20000 1k blocks and 1248 inodes -+Superblock backups stored on blocks: -+ 8193 -+ -+Allocating group tables: done -+Writing inode tables: done -+Creating journal (1024 blocks): done -+Writing superblocks and filesystem accounting information: done -+ -+Group 2: (Blocks 16385-19999) [INODE_UNINIT, ITABLE_ZEROED] -+ Block bitmap at 83 (bg #0 + 82) -+ Inode bitmap at 86 (bg #0 + 85) -+ Inode table at 295-398 (bg #0 + 294) -+ 3615 free blocks, 416 free inodes, 0 directories, 416 unused inodes -+ Free blocks: 16385-19999 -+ Free inodes: 833-1248 -+Group 2: (Blocks 16385-19999) -+ Block bitmap at 83 (bg #0 + 82) -+ Inode bitmap at 86 (bg #0 + 85) -+ Inode table at 295-398 (bg #0 + 294) -+ 3615 free blocks, 416 free inodes, 0 directories -+ Free blocks: 16385-19999 -+ Free inodes: 833-1248 -+Resizing the filesystem on test.img to 20004 (1k) blocks. -+The filesystem on test.img is now 20004 (1k) blocks long. -+ -+Group 2: (Blocks 16385-20003) [INODE_UNINIT] -+ Block bitmap at 83 (bg #0 + 82) -+ Inode bitmap at 86 (bg #0 + 85) -+ Inode table at 295-398 (bg #0 + 294) -+ 3619 free blocks, 416 free inodes, 0 directories, 416 unused inodes -+ Free blocks: 16385-20003 -+ Free inodes: 833-1248 -+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.img: 11/1248 files (0.0% non-contiguous), 1517/20004 blocks -diff --git a/tests/r_fixup_lastbg/script b/tests/r_fixup_lastbg/script -new file mode 100755 -index 0000000..6a5c5af ---- /dev/null -+++ b/tests/r_fixup_lastbg/script -@@ -0,0 +1,37 @@ -+if test -x $RESIZE2FS_EXE -a -x $DEBUGFS_EXE; then -+test_description="fix up last bg when expanding within the last bg" -+ -+EXP=$test_dir/expect -+OUT=$test_name.out -+LOG=$test_name.log -+E2FSCK=../e2fsck/e2fsck -+ -+$MKE2FS -T ext4 -b 1024 -F -U 56d3ee50-8532-4f29-8181-d7c6ea4a94a6 $TMPFILE 20000 > $OUT 2>&1 -+$DUMPE2FS $TMPFILE 2>&1 | grep -A10 '^Group 2:' >> $OUT -+$DEBUGFS -R "set_bg 2 itable_unused 0" -w $TMPFILE > /dev/null 2>&1 -+$DEBUGFS -R "set_bg 2 flags 0" -w $TMPFILE > /dev/null 2>&1 -+$DEBUGFS -R "set_bg 2 checksum 0xd318" -w $TMPFILE > /dev/null 2>&1 -+$DUMPE2FS $TMPFILE 2>&1 | grep -A10 '^Group 2:' >> $OUT -+#dd if=/dev/zero of=$TMPFILE bs=1 count=1 seek=$((1024 * 20004)) conv=notrunc >> $OUT 2> /dev/null -+$RESIZE2FS_EXE -f -p $TMPFILE 20004 >> $OUT 2>&1 -+$DUMPE2FS $TMPFILE 2>&1 | grep -A10 '^Group 2:' >> $OUT -+$E2FSCK -fy $TMPFILE >> $OUT 2>&1 -+ -+sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" < $OUT > $LOG -+rm -rf $OUT -+ -+cmp -s $LOG $EXP -+RC=$? -+if [ $RC -eq 0 ]; then -+ echo "$test_name: $test_description: ok" -+ touch $test_name.ok -+else -+ echo "$test_name: $test_description: failed" -+ diff -u $EXP $LOG > $test_name.failed -+fi -+ -+unset EXP LOG OUT E2FSCK -+ -+else #if test -x $RESIZE2FS_EXE -a -x $DEBUGFS_EXE; then -+ echo "$test_name: $test_description: skipped" -+fi -diff --git a/tests/r_fixup_lastbg_big/expect b/tests/r_fixup_lastbg_big/expect -new file mode 100644 -index 0000000..edaabaf ---- /dev/null -+++ b/tests/r_fixup_lastbg_big/expect -@@ -0,0 +1,45 @@ -+Creating filesystem with 20000 1k blocks and 1248 inodes -+Superblock backups stored on blocks: -+ 8193 -+ -+Allocating group tables: done -+Writing inode tables: done -+Creating journal (1024 blocks): done -+Writing superblocks and filesystem accounting information: done -+ -+Group 2: (Blocks 16385-19999) [INODE_UNINIT, ITABLE_ZEROED] -+ Block bitmap at 83 (bg #0 + 82) -+ Inode bitmap at 86 (bg #0 + 85) -+ Inode table at 295-398 (bg #0 + 294) -+ 3615 free blocks, 416 free inodes, 0 directories, 416 unused inodes -+ Free blocks: 16385-19999 -+ Free inodes: 833-1248 -+Group 2: (Blocks 16385-19999) -+ Block bitmap at 83 (bg #0 + 82) -+ Inode bitmap at 86 (bg #0 + 85) -+ Inode table at 295-398 (bg #0 + 294) -+ 3615 free blocks, 416 free inodes, 0 directories -+ Free blocks: 16385-19999 -+ Free inodes: 833-1248 -+Resizing the filesystem on test.img to 40000 (1k) blocks. -+Begin pass 1 (max = 2) -+Extending the inode table ----------------------------------------XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX -+The filesystem on test.img is now 40000 (1k) blocks long. -+ -+Group 2: (Blocks 16385-24576) [INODE_UNINIT, BLOCK_UNINIT] -+ Block bitmap at 83 (bg #0 + 82) -+ Inode bitmap at 86 (bg #0 + 85) -+ Inode table at 295-398 (bg #0 + 294) -+ 8192 free blocks, 416 free inodes, 0 directories, 416 unused inodes -+ Free blocks: 16385-24576 -+ Free inodes: 833-1248 -+Group 3: (Blocks 24577-32768) [INODE_UNINIT, ITABLE_ZEROED] -+ Backup superblock at 24577, Group descriptors at 24578-24578 -+ Reserved GDT blocks at 24579-24656 -+ Block bitmap at 413 (bg #0 + 412) -+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.img: 11/2080 files (0.0% non-contiguous), 1809/40000 blocks -diff --git a/tests/r_fixup_lastbg_big/script b/tests/r_fixup_lastbg_big/script -new file mode 100755 -index 0000000..97d9fd4 ---- /dev/null -+++ b/tests/r_fixup_lastbg_big/script -@@ -0,0 +1,37 @@ -+if test -x $RESIZE2FS_EXE -a -x $DEBUGFS_EXE; then -+test_description="fix up last bg when expanding beyond the last bg" -+ -+EXP=$test_dir/expect -+OUT=$test_name.out -+LOG=$test_name.log -+E2FSCK=../e2fsck/e2fsck -+ -+$MKE2FS -T ext4 -b 1024 -F -U 56d3ee50-8532-4f29-8181-d7c6ea4a94a6 $TMPFILE 20000 > $OUT 2>&1 -+$DUMPE2FS $TMPFILE 2>&1 | grep -A10 '^Group 2:' >> $OUT -+$DEBUGFS -R "set_bg 2 itable_unused 0" -w $TMPFILE > /dev/null 2>&1 -+$DEBUGFS -R "set_bg 2 flags 0" -w $TMPFILE > /dev/null 2>&1 -+$DEBUGFS -R "set_bg 2 checksum 0xd318" -w $TMPFILE > /dev/null 2>&1 -+$DUMPE2FS $TMPFILE 2>&1 | grep -A10 '^Group 2:' >> $OUT -+dd if=/dev/zero of=$TMPFILE bs=1 count=1 seek=$((1024 * 40000)) conv=notrunc >> $OUT 2> /dev/null -+RESIZE2FS_FORCE_ITABLE_INIT=1 $RESIZE2FS_EXE -f -p $TMPFILE >> $OUT 2>&1 -+$DUMPE2FS $TMPFILE 2>&1 | grep -A10 '^Group 2:' >> $OUT -+$E2FSCK -fy $TMPFILE >> $OUT 2>&1 -+ -+sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" < $OUT > $LOG -+rm -rf $OUT -+ -+cmp -s $LOG $EXP -+RC=$? -+if [ $RC -eq 0 ]; then -+ echo "$test_name: $test_description: ok" -+ touch $test_name.ok -+else -+ echo "$test_name: $test_description: failed" -+ diff -u $EXP $LOG > $test_name.failed -+fi -+ -+unset EXP LOG OUT E2FSCK -+ -+else #if test -x $RESIZE2FS_EXE -a -x $DEBUGFS_EXE; then -+ echo "$test_name: $test_description: skipped" -+fi -diff --git a/tests/r_inline_xattr/expect b/tests/r_inline_xattr/expect -index b2f1ccd..3feba08 100644 ---- a/tests/r_inline_xattr/expect -+++ b/tests/r_inline_xattr/expect -@@ -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 (1k) 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/r_move_itable/script b/tests/r_move_itable/script -index e567888..3f02a79 100644 ---- a/tests/r_move_itable/script -+++ b/tests/r_move_itable/script -@@ -33,7 +33,7 @@ $DEBUGFS -R "set_super_value mkfs_time 0" -w $TMPFILE >/dev/null 2>&1 - $TUNE2FS -c 20 -U clear $TMPFILE >/dev/null 2>&1 - - echo dumpe2fs test.img >> $OUT --$DUMPE2FS $TMPFILE 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT -+$DUMPE2FS $TMPFILE 2>&1 | sed -f $cmd_dir/filter.sed -e '/Block bitmap.*$/N;s/\n Inode bitmap/, Inode bitmap/g' >> $OUT - - echo "--------------------------------" >> $OUT - -@@ -53,7 +53,7 @@ $DEBUGFS -R "set_super_value mkfs_time 0" -w $TMPFILE >/dev/null 2>&1 - $TUNE2FS -c 20 -U clear $TMPFILE >/dev/null 2>&1 - - echo dumpe2fs test.img >> $OUT --$DUMPE2FS $TMPFILE 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT -+$DUMPE2FS $TMPFILE 2>&1 | sed -f $cmd_dir/filter.sed -e '/Block bitmap.*$/N;s/\n Inode bitmap/, Inode bitmap/g' >> $OUT - - echo "--------------------------------" >> $OUT - -@@ -73,7 +73,7 @@ $DEBUGFS -R "set_super_value mkfs_time 0" -w $TMPFILE >/dev/null 2>&1 - $TUNE2FS -c 20 -U clear $TMPFILE >/dev/null 2>&1 - - echo dumpe2fs test.img >> $OUT --$DUMPE2FS $TMPFILE 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT -+$DUMPE2FS $TMPFILE 2>&1 | sed -f $cmd_dir/filter.sed -e '/Block bitmap.*$/N;s/\n Inode bitmap/, Inode bitmap/g' >> $OUT - - echo "--------------------------------" >> $OUT - -@@ -93,7 +93,7 @@ $DEBUGFS -R "set_super_value mkfs_time 0" -w $TMPFILE >/dev/null 2>&1 - $TUNE2FS -c 20 -U clear $TMPFILE >/dev/null 2>&1 - - echo dumpe2fs test.img >> $OUT --$DUMPE2FS $TMPFILE 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT -+$DUMPE2FS $TMPFILE 2>&1 | sed -f $cmd_dir/filter.sed -e '/Block bitmap.*$/N;s/\n Inode bitmap/, Inode bitmap/g' >> $OUT - - rm -f $TMPFILE - -diff --git a/tests/r_resize_inode/script b/tests/r_resize_inode/script -index 0f12138..4e3eb19 100644 ---- a/tests/r_resize_inode/script -+++ b/tests/r_resize_inode/script -@@ -33,7 +33,7 @@ $DEBUGFS -R "set_super_value mkfs_time 0" -w $TMPFILE >/dev/null 2>&1 - $TUNE2FS -c 20 -U clear $TMPFILE >/dev/null 2>&1 - - echo dumpe2fs test.img >> $OUT --$DUMPE2FS $TMPFILE 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT -+$DUMPE2FS $TMPFILE 2>&1 | sed -f $cmd_dir/filter.sed -e '/Block bitmap.*$/N;s/\n Inode bitmap/, Inode bitmap/g' >> $OUT - - echo "--------------------------------" >> $OUT - -@@ -59,7 +59,7 @@ $DEBUGFS -R "set_super_value mkfs_time 0" -w $TMPFILE >/dev/null 2>&1 - $TUNE2FS -c 20 -U clear $TMPFILE >/dev/null 2>&1 - - echo dumpe2fs test.img >> $OUT --$DUMPE2FS $TMPFILE 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT -+$DUMPE2FS $TMPFILE 2>&1 | sed -f $cmd_dir/filter.sed -e '/Block bitmap.*$/N;s/\n Inode bitmap/, Inode bitmap/g' >> $OUT - - echo "--------------------------------" >> $OUT - -@@ -79,7 +79,7 @@ $DEBUGFS -R "set_super_value mkfs_time 0" -w $TMPFILE >/dev/null 2>&1 - $TUNE2FS -c 20 -U clear $TMPFILE >/dev/null 2>&1 - - echo dumpe2fs test.img >> $OUT --$DUMPE2FS $TMPFILE 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT -+$DUMPE2FS $TMPFILE 2>&1 | sed -f $cmd_dir/filter.sed -e '/Block bitmap.*$/N;s/\n Inode bitmap/, Inode bitmap/g' >> $OUT - - rm -f $TMPFILE - cmp -s $OUT $EXP -diff --git a/tests/scripts/resize_test b/tests/scripts/resize_test -index 0633e0c..dfd45ac 100755 ---- a/tests/scripts/resize_test -+++ b/tests/scripts/resize_test -@@ -67,7 +67,7 @@ fi - echo $FSCK -fy $TMPFILE >> $LOG 2>&1 - if ! $FSCK -fy $TMPFILE >> $LOG 2>&1 - then -- dumpe2fs $TMPFILE >> $LOG -+ $DUMPE2FS $TMPFILE >> $LOG - return 1 - fi - -@@ -97,7 +97,7 @@ fi - echo $FSCK -fy $TMPFILE >> $LOG 2>&1 - if ! $FSCK -fy $TMPFILE >> $LOG 2>&1 - then -- dumpe2fs $TMPFILE >> $LOG -+ $DUMPE2FS $TMPFILE >> $LOG - return 1 - fi - -@@ -122,7 +122,7 @@ fi - echo $FSCK -fy $TMPFILE >> $LOG 2>&1 - if ! $FSCK -fy $TMPFILE >> $LOG 2>&1 - then -- dumpe2fs $TMPFILE >> $LOG -+ $DUMPE2FS $TMPFILE >> $LOG - return 1 - fi - -@@ -147,7 +147,7 @@ fi - echo $FSCK -fy $TMPFILE >> $LOG 2>&1 - if ! $FSCK -fy $TMPFILE >> $LOG 2>&1 - then -- dumpe2fs $TMPFILE >> $LOG -+ $DUMPE2FS $TMPFILE >> $LOG - return 1 - fi - -diff --git a/tests/t_disable_mcsum/expect b/tests/t_disable_mcsum/expect -new file mode 100644 -index 0000000..e04f26a ---- /dev/null -+++ b/tests/t_disable_mcsum/expect -@@ -0,0 +1,45 @@ -+tune2fs ^metadata_csum test -+Creating filesystem with 524288 1k blocks and 65536 inodes -+Superblock backups stored on blocks: -+ 8193, 24577, 40961, 57345, 73729, 204801, 221185, 401409 -+ -+Allocating group tables: done -+Writing inode tables: done -+Creating journal (16384 blocks): done -+Creating 477 huge file(s) with 1024 blocks each: done -+Writing superblocks and filesystem accounting information: done -+ -+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 -+ -+Exit status is 0 -+tune2fs -O ^metadata_csum test.img -+Exit status is 0 -+Change in FS metadata: -+@@ -2,7 +2,7 @@ -+ Last mounted on: -+ Filesystem magic number: 0xEF53 -+ Filesystem revision #: 1 (dynamic) -+-Filesystem features: has_journal ext_attr resize_inode dir_index filetype extent 64bit flex_bg sparse_super large_file huge_file dir_nlink extra_isize metadata_csum -++Filesystem features: has_journal ext_attr resize_inode dir_index filetype extent 64bit flex_bg sparse_super large_file huge_file uninit_bg dir_nlink extra_isize -+ Default mount options: user_xattr acl -+ Filesystem state: clean -+ Errors behavior: Continue -+@@ -33,7 +33,6 @@ -+ Journal inode: 8 -+ Default directory hash: half_md4 -+ Journal backup: inode blocks -+-Checksum type: crc32c -+ Journal features: (none) -+ Journal size: 16M -+ Journal length: 16384 -+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 -+ -+Exit status is 0 -diff --git a/tests/t_disable_mcsum/name b/tests/t_disable_mcsum/name -new file mode 100644 -index 0000000..cf9dc8d ---- /dev/null -+++ b/tests/t_disable_mcsum/name -@@ -0,0 +1 @@ -+disable metadata_csum -diff --git a/tests/t_disable_mcsum/script b/tests/t_disable_mcsum/script -new file mode 100644 -index 0000000..7f1b3b4 ---- /dev/null -+++ b/tests/t_disable_mcsum/script -@@ -0,0 +1,67 @@ -+FSCK_OPT=-fn -+OUT=$test_name.log -+EXP=$test_dir/expect -+CONF=$TMPFILE.conf -+ -+cat > $CONF << ENDL -+[fs_types] -+ ext4h = { -+ features = has_journal,extent,huge_file,flex_bg,uninit_bg,dir_nlink,extra_isize,sparse_super,filetype,dir_index,ext_attr,resize_inode,64bit,metadata_csum -+ blocksize = 1024 -+ inode_size = 256 -+ make_hugefiles = true -+ hugefiles_dir = / -+ hugefiles_slack = 0 -+ hugefiles_name = aaaaa -+ hugefiles_digits = 4 -+ hugefiles_size = 1M -+ zero_hugefiles = false -+ } -+ENDL -+ -+echo "tune2fs ^metadata_csum test" > $OUT -+ -+MKE2FS_CONFIG=$CONF $MKE2FS -F -T ext4h $TMPFILE 524288 >> $OUT 2>&1 -+rm -rf $CONF -+ -+# dump and check -+$DUMPE2FS $TMPFILE 2> /dev/null | grep '^Group 0:' -B99 -A20 | sed -f $cmd_dir/filter.sed > $OUT.before -+$FSCK $FSCK_OPT -N test_filesys $TMPFILE >> $OUT 2>&1 -+status=$? -+echo Exit status is $status >> $OUT -+ -+# remove mcsum -+echo "tune2fs -O ^metadata_csum test.img" >> $OUT -+$TUNE2FS -O ^metadata_csum $TMPFILE >> $OUT 2>&1 -+status=$? -+echo Exit status is $status >> $OUT -+ -+# dump and check -+$DUMPE2FS $TMPFILE 2> /dev/null | grep '^Group 0:' -B99 -A20 | sed -f $cmd_dir/filter.sed > $OUT.after -+echo "Change in FS metadata:" >> $OUT -+diff -u $OUT.before $OUT.after | tail -n +3 >> $OUT -+$FSCK $FSCK_OPT -N test_filesys $TMPFILE >> $OUT 2>&1 -+status=$? -+echo Exit status is $status >> $OUT -+ -+rm $TMPFILE $OUT.before $OUT.after -+ -+# -+# Do the verification -+# -+ -+sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" -e 's/test_filesys:.*//g' < $OUT > $OUT.new -+mv $OUT.new $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 IMAGE FSCK_OPT OUT EXP CONF -diff --git a/tests/t_disable_mcsum_noinitbg/expect b/tests/t_disable_mcsum_noinitbg/expect -new file mode 100644 -index 0000000..a022631 ---- /dev/null -+++ b/tests/t_disable_mcsum_noinitbg/expect -@@ -0,0 +1,68 @@ -+tune2fs ^metadata_csum test -+Creating filesystem with 524288 1k blocks and 65536 inodes -+Superblock backups stored on blocks: -+ 8193, 24577, 40961, 57345, 73729, 204801, 221185, 401409 -+ -+Allocating group tables: done -+Writing inode tables: done -+Creating journal (16384 blocks): done -+Creating 477 huge file(s) with 1024 blocks each: done -+Writing superblocks and filesystem accounting information: done -+ -+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 -+ -+Exit status is 0 -+tune2fs -O ^metadata_csum,^uninit_bg test.img -+Exit status is 0 -+Change in FS metadata: -+@@ -2,7 +2,7 @@ -+ Last mounted on: -+ Filesystem magic number: 0xEF53 -+ Filesystem revision #: 1 (dynamic) -+-Filesystem features: has_journal ext_attr resize_inode dir_index filetype extent 64bit flex_bg sparse_super large_file huge_file dir_nlink extra_isize metadata_csum -++Filesystem features: has_journal ext_attr resize_inode dir_index filetype extent 64bit flex_bg sparse_super large_file huge_file dir_nlink extra_isize -+ Default mount options: user_xattr acl -+ Filesystem state: clean -+ Errors behavior: Continue -+@@ -33,7 +33,6 @@ -+ Journal inode: 8 -+ Default directory hash: half_md4 -+ Journal backup: inode blocks -+-Checksum type: crc32c -+ Journal features: (none) -+ Journal size: 16M -+ Journal length: 16384 -+@@ -47,18 +46,18 @@ -+ Block bitmap at 262 (+261) -+ Inode bitmap at 278 (+277) -+ Inode table at 294-549 (+293) -+- 21 free blocks, 536 free inodes, 2 directories, 536 unused inodes -++ 21 free blocks, 536 free inodes, 2 directories -+ Free blocks: 4413-4433 -+ Free inodes: 489-1024 -+-Group 1: (Blocks 8193-16384) [INODE_UNINIT] -++Group 1: (Blocks 8193-16384) -+ Backup superblock at 8193, Group descriptors at 8194-8197 -+ Reserved GDT blocks at 8198-8453 -+ Block bitmap at 263 (bg #0 + 262) -+ Inode bitmap at 279 (bg #0 + 278) -+ Inode table at 550-805 (bg #0 + 549) -+- 0 free blocks, 1024 free inodes, 0 directories, 1024 unused inodes -++ 0 free blocks, 1024 free inodes, 0 directories -+ Free blocks: -+ Free inodes: 1025-2048 -+-Group 2: (Blocks 16385-24576) [INODE_UNINIT] -++Group 2: (Blocks 16385-24576) -+ Block bitmap at 264 (bg #0 + 263) -+ Inode bitmap at 280 (bg #0 + 279) -+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 -+ -+Exit status is 0 -diff --git a/tests/t_disable_mcsum_noinitbg/name b/tests/t_disable_mcsum_noinitbg/name -new file mode 100644 -index 0000000..4b906be ---- /dev/null -+++ b/tests/t_disable_mcsum_noinitbg/name -@@ -0,0 +1 @@ -+disable metadata_csum and uninit_bg -diff --git a/tests/t_disable_mcsum_noinitbg/script b/tests/t_disable_mcsum_noinitbg/script -new file mode 100644 -index 0000000..db49864 ---- /dev/null -+++ b/tests/t_disable_mcsum_noinitbg/script -@@ -0,0 +1,67 @@ -+FSCK_OPT=-fn -+OUT=$test_name.log -+EXP=$test_dir/expect -+CONF=$TMPFILE.conf -+ -+cat > $CONF << ENDL -+[fs_types] -+ ext4h = { -+ features = has_journal,extent,huge_file,flex_bg,uninit_bg,dir_nlink,extra_isize,sparse_super,filetype,dir_index,ext_attr,resize_inode,64bit,metadata_csum -+ blocksize = 1024 -+ inode_size = 256 -+ make_hugefiles = true -+ hugefiles_dir = / -+ hugefiles_slack = 0 -+ hugefiles_name = aaaaa -+ hugefiles_digits = 4 -+ hugefiles_size = 1M -+ zero_hugefiles = false -+ } -+ENDL -+ -+echo "tune2fs ^metadata_csum test" > $OUT -+ -+MKE2FS_CONFIG=$CONF $MKE2FS -F -T ext4h $TMPFILE 524288 >> $OUT 2>&1 -+rm -rf $CONF -+ -+# dump and check -+$DUMPE2FS $TMPFILE 2> /dev/null | grep '^Group 0:' -B99 -A20 | sed -f $cmd_dir/filter.sed > $OUT.before -+$FSCK $FSCK_OPT -N test_filesys $TMPFILE >> $OUT 2>&1 -+status=$? -+echo Exit status is $status >> $OUT -+ -+# remove mcsum -+echo "tune2fs -O ^metadata_csum,^uninit_bg test.img" >> $OUT -+$TUNE2FS -O ^metadata_csum,^uninit_bg $TMPFILE >> $OUT 2>&1 -+status=$? -+echo Exit status is $status >> $OUT -+ -+# dump and check -+$DUMPE2FS $TMPFILE 2> /dev/null | grep '^Group 0:' -B99 -A20 | sed -f $cmd_dir/filter.sed > $OUT.after -+echo "Change in FS metadata:" >> $OUT -+diff -u $OUT.before $OUT.after | tail -n +3 >> $OUT -+$FSCK $FSCK_OPT -N test_filesys $TMPFILE >> $OUT 2>&1 -+status=$? -+echo Exit status is $status >> $OUT -+ -+rm $TMPFILE $OUT.before $OUT.after -+ -+# -+# Do the verification -+# -+ -+sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" -e 's/test_filesys:.*//g' < $OUT > $OUT.new -+mv $OUT.new $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 IMAGE FSCK_OPT OUT EXP CONF -diff --git a/tests/t_disable_mcsum_yesinitbg/expect b/tests/t_disable_mcsum_yesinitbg/expect -new file mode 100644 -index 0000000..df3d6c0 ---- /dev/null -+++ b/tests/t_disable_mcsum_yesinitbg/expect -@@ -0,0 +1,45 @@ -+tune2fs ^metadata_csum test -+Creating filesystem with 524288 1k blocks and 65536 inodes -+Superblock backups stored on blocks: -+ 8193, 24577, 40961, 57345, 73729, 204801, 221185, 401409 -+ -+Allocating group tables: done -+Writing inode tables: done -+Creating journal (16384 blocks): done -+Creating 477 huge file(s) with 1024 blocks each: done -+Writing superblocks and filesystem accounting information: done -+ -+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 -+ -+Exit status is 0 -+tune2fs -O ^metadata_csum,uninit_bg test.img -+Exit status is 0 -+Change in FS metadata: -+@@ -2,7 +2,7 @@ -+ Last mounted on: -+ Filesystem magic number: 0xEF53 -+ Filesystem revision #: 1 (dynamic) -+-Filesystem features: has_journal ext_attr resize_inode dir_index filetype extent 64bit flex_bg sparse_super large_file huge_file dir_nlink extra_isize metadata_csum -++Filesystem features: has_journal ext_attr resize_inode dir_index filetype extent 64bit flex_bg sparse_super large_file huge_file uninit_bg dir_nlink extra_isize -+ Default mount options: user_xattr acl -+ Filesystem state: clean -+ Errors behavior: Continue -+@@ -33,7 +33,6 @@ -+ Journal inode: 8 -+ Default directory hash: half_md4 -+ Journal backup: inode blocks -+-Checksum type: crc32c -+ Journal features: (none) -+ Journal size: 16M -+ Journal length: 16384 -+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 -+ -+Exit status is 0 -diff --git a/tests/t_disable_mcsum_yesinitbg/name b/tests/t_disable_mcsum_yesinitbg/name -new file mode 100644 -index 0000000..880de1c ---- /dev/null -+++ b/tests/t_disable_mcsum_yesinitbg/name -@@ -0,0 +1 @@ -+disable metadata_csum and enable uninit_bg -diff --git a/tests/t_disable_mcsum_yesinitbg/script b/tests/t_disable_mcsum_yesinitbg/script -new file mode 100644 -index 0000000..2d04041 ---- /dev/null -+++ b/tests/t_disable_mcsum_yesinitbg/script -@@ -0,0 +1,67 @@ -+FSCK_OPT=-fn -+OUT=$test_name.log -+EXP=$test_dir/expect -+CONF=$TMPFILE.conf -+ -+cat > $CONF << ENDL -+[fs_types] -+ ext4h = { -+ features = has_journal,extent,huge_file,flex_bg,uninit_bg,dir_nlink,extra_isize,sparse_super,filetype,dir_index,ext_attr,resize_inode,64bit,metadata_csum -+ blocksize = 1024 -+ inode_size = 256 -+ make_hugefiles = true -+ hugefiles_dir = / -+ hugefiles_slack = 0 -+ hugefiles_name = aaaaa -+ hugefiles_digits = 4 -+ hugefiles_size = 1M -+ zero_hugefiles = false -+ } -+ENDL -+ -+echo "tune2fs ^metadata_csum test" > $OUT -+ -+MKE2FS_CONFIG=$CONF $MKE2FS -F -T ext4h $TMPFILE 524288 >> $OUT 2>&1 -+rm -rf $CONF -+ -+# dump and check -+$DUMPE2FS $TMPFILE 2> /dev/null | grep '^Group 0:' -B99 -A20 | sed -f $cmd_dir/filter.sed > $OUT.before -+$FSCK $FSCK_OPT -N test_filesys $TMPFILE >> $OUT 2>&1 -+status=$? -+echo Exit status is $status >> $OUT -+ -+# remove mcsum -+echo "tune2fs -O ^metadata_csum,uninit_bg test.img" >> $OUT -+$TUNE2FS -O ^metadata_csum,uninit_bg $TMPFILE >> $OUT 2>&1 -+status=$? -+echo Exit status is $status >> $OUT -+ -+# dump and check -+$DUMPE2FS $TMPFILE 2> /dev/null | grep '^Group 0:' -B99 -A20 | sed -f $cmd_dir/filter.sed > $OUT.after -+echo "Change in FS metadata:" >> $OUT -+diff -u $OUT.before $OUT.after | tail -n +3 >> $OUT -+$FSCK $FSCK_OPT -N test_filesys $TMPFILE >> $OUT 2>&1 -+status=$? -+echo Exit status is $status >> $OUT -+ -+rm $TMPFILE $OUT.before $OUT.after -+ -+# -+# Do the verification -+# -+ -+sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" -e 's/test_filesys:.*//g' < $OUT > $OUT.new -+mv $OUT.new $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 IMAGE FSCK_OPT OUT EXP CONF -diff --git a/tests/t_enable_mcsum/expect b/tests/t_enable_mcsum/expect -new file mode 100644 -index 0000000..2ee3c27 ---- /dev/null -+++ b/tests/t_enable_mcsum/expect -@@ -0,0 +1,78 @@ -+tune2fs metadata_csum test -+Creating filesystem with 524288 1k blocks and 65536 inodes -+Superblock backups stored on blocks: -+ 8193, 24577, 40961, 57345, 73729, 204801, 221185, 401409 -+ -+Allocating group tables: done -+Writing inode tables: done -+Creating journal (16384 blocks): done -+Creating 477 huge file(s) with 1024 blocks each: done -+Writing superblocks and filesystem accounting information: done -+ -+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 -+ -+Exit status is 0 -+tune2fs -O metadata_csum test.img -+ -+Please run e2fsck -D on the filesystem. -+ -+Exit status is 0 -+test_filesys was not cleanly unmounted, check forced. -+Pass 1: Checking inodes, blocks, and sizes -+Pass 2: Checking directory structure -+Pass 3: Checking directory connectivity -+Pass 3A: Optimizing directories -+Pass 4: Checking reference counts -+Pass 5: Checking group summary information -+ -+ -+ -+Change in FS metadata: -+@@ -2,7 +2,7 @@ -+ Last mounted on: -+ Filesystem magic number: 0xEF53 -+ Filesystem revision #: 1 (dynamic) -+-Filesystem features: has_journal ext_attr resize_inode dir_index filetype extent 64bit flex_bg sparse_super large_file huge_file uninit_bg dir_nlink extra_isize -++Filesystem features: has_journal ext_attr resize_inode dir_index filetype extent 64bit flex_bg sparse_super large_file huge_file dir_nlink extra_isize metadata_csum -+ Default mount options: user_xattr acl -+ Filesystem state: clean -+ Errors behavior: Continue -+@@ -10,7 +10,7 @@ -+ Inode count: 65536 -+ Block count: 524288 -+ Reserved block count: 26214 -+-Free blocks: 571 -++Free blocks: 568 -+ Free inodes: 65048 -+ First block: 1 -+ Block size: 1024 -+@@ -33,6 +33,7 @@ -+ Journal inode: 8 -+ Default directory hash: half_md4 -+ Journal backup: inode blocks -++Checksum type: crc32c -+ Journal features: (none) -+ Journal size: 16M -+ Journal length: 16384 -+@@ -46,8 +47,8 @@ -+ Block bitmap at 262 (+261) -+ Inode bitmap at 278 (+277) -+ Inode table at 294-549 (+293) -+- 21 free blocks, 536 free inodes, 2 directories, 536 unused inodes -+- Free blocks: 4413-4433 -++ 18 free blocks, 536 free inodes, 2 directories, 536 unused inodes -++ Free blocks: 4413, 4417-4433 -+ Free inodes: 489-1024 -+ Group 1: (Blocks 8193-16384) [INODE_UNINIT] -+ Backup superblock at 8193, Group descriptors at 8194-8197 -+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 -+ -+Exit status is 0 -diff --git a/tests/t_enable_mcsum/name b/tests/t_enable_mcsum/name -new file mode 100644 -index 0000000..22f295a ---- /dev/null -+++ b/tests/t_enable_mcsum/name -@@ -0,0 +1 @@ -+enable metadata_csum -diff --git a/tests/t_enable_mcsum/script b/tests/t_enable_mcsum/script -new file mode 100644 -index 0000000..5239eb3 ---- /dev/null -+++ b/tests/t_enable_mcsum/script -@@ -0,0 +1,70 @@ -+FSCK_OPT=-fn -+OUT=$test_name.log -+EXP=$test_dir/expect -+CONF=$TMPFILE.conf -+ -+cat > $CONF << ENDL -+[fs_types] -+ ext4h = { -+ features = has_journal,extent,huge_file,flex_bg,uninit_bg,dir_nlink,extra_isize,sparse_super,filetype,dir_index,ext_attr,resize_inode,64bit -+ blocksize = 1024 -+ inode_size = 256 -+ make_hugefiles = true -+ hugefiles_dir = / -+ hugefiles_slack = 0 -+ hugefiles_name = aaaaa -+ hugefiles_digits = 4 -+ hugefiles_size = 1M -+ zero_hugefiles = false -+ } -+ENDL -+ -+echo "tune2fs metadata_csum test" > $OUT -+ -+MKE2FS_CONFIG=$CONF $MKE2FS -F -T ext4h $TMPFILE 524288 >> $OUT 2>&1 -+rm -rf $CONF -+ -+# dump and check -+$DUMPE2FS $TMPFILE 2> /dev/null | grep '^Group 0:' -B99 -A20 | sed -f $cmd_dir/filter.sed > $OUT.before -+$FSCK $FSCK_OPT -N test_filesys $TMPFILE >> $OUT 2>&1 -+status=$? -+echo Exit status is $status >> $OUT -+ -+# add mcsum -+echo "tune2fs -O metadata_csum test.img" >> $OUT -+$TUNE2FS -O metadata_csum $TMPFILE >> $OUT 2>&1 -+status=$? -+echo Exit status is $status >> $OUT -+ -+# check -+$FSCK -yD -N test_filesys $TMPFILE >> $OUT 2>&1 -+ -+# dump and check -+$DUMPE2FS $TMPFILE 2> /dev/null | grep '^Group 0:' -B99 -A20 | sed -f $cmd_dir/filter.sed > $OUT.after -+echo "Change in FS metadata:" >> $OUT -+diff -u $OUT.before $OUT.after | tail -n +3 >> $OUT -+$FSCK $FSCK_OPT -N test_filesys $TMPFILE >> $OUT 2>&1 -+status=$? -+echo Exit status is $status >> $OUT -+ -+rm $TMPFILE $OUT.before $OUT.after -+ -+# -+# Do the verification -+# -+ -+sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" -e 's/test_filesys:.*//g' < $OUT > $OUT.new -+mv $OUT.new $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 IMAGE FSCK_OPT OUT EXP CONF -diff --git a/tests/t_enable_mcsum_ext3/expect b/tests/t_enable_mcsum_ext3/expect -new file mode 100644 -index 0000000..0f761a9 ---- /dev/null -+++ b/tests/t_enable_mcsum_ext3/expect -@@ -0,0 +1,74 @@ -+tune2fs metadata_csum test -+Creating filesystem with 524288 1k blocks and 65536 inodes -+Superblock backups stored on blocks: -+ 8193, 24577, 40961, 57345, 73729, 204801, 221185, 401409 -+ -+Allocating group tables: done -+Writing inode tables: done -+Creating journal (16384 blocks): done -+mke2fs: Operation not supported for inodes containing extents while creating huge files -+Writing superblocks and filesystem accounting information: done -+ -+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 -+ -+Exit status is 0 -+tune2fs -O metadata_csum test.img -+Extents are not enabled. The file extent tree can be checksummed, whereas block maps cannot. Not enabling extents reduces the coverage of metadata checksumming. Re-run with -O extent to rectify. -+64-bit filesystem support is not enabled. The larger fields afforded by this feature enable full-strength checksumming. Run resize2fs -b to rectify. -+Exit status is 0 -+ -+Change in FS metadata: -+@@ -2,7 +2,7 @@ -+ Last mounted on: -+ Filesystem magic number: 0xEF53 -+ Filesystem revision #: 1 (dynamic) -+-Filesystem features: has_journal ext_attr resize_inode dir_index filetype sparse_super large_file -++Filesystem features: has_journal ext_attr resize_inode dir_index filetype sparse_super large_file metadata_csum -+ Default mount options: user_xattr acl -+ Filesystem state: clean -+ Errors behavior: Continue -+@@ -29,6 +29,7 @@ -+ Journal inode: 8 -+ Default directory hash: half_md4 -+ Journal backup: inode blocks -++Checksum type: crc32c -+ Journal features: (none) -+ Journal size: 16M -+ Journal length: 16384 -+@@ -36,7 +37,7 @@ -+ Journal start: 0 -+ -+ -+-Group 0: (Blocks 1-8192) -++Group 0: (Blocks 1-8192) [ITABLE_ZEROED] -+ Primary superblock at 1, Group descriptors at 2-3 -+ Reserved GDT blocks at 4-259 -+ Block bitmap at 260 (+259) -+@@ -45,7 +46,7 @@ -+ 0 free blocks, 1013 free inodes, 2 directories -+ Free blocks: -+ Free inodes: 12-1024 -+-Group 1: (Blocks 8193-16384) -++Group 1: (Blocks 8193-16384) [ITABLE_ZEROED] -+ Backup superblock at 8193, Group descriptors at 8194-8195 -+ Reserved GDT blocks at 8196-8451 -+ Block bitmap at 8452 (+259) -+@@ -54,6 +55,6 @@ -+ 0 free blocks, 1024 free inodes, 0 directories -+ Free blocks: -+ Free inodes: 1025-2048 -+-Group 2: (Blocks 16385-24576) -++Group 2: (Blocks 16385-24576) [ITABLE_ZEROED] -+ Block bitmap at 16385 (+0) -+ Inode bitmap at 16386 (+1) -+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 -+ -+Exit status is 0 -diff --git a/tests/t_enable_mcsum_ext3/name b/tests/t_enable_mcsum_ext3/name -new file mode 100644 -index 0000000..d9a29c8 ---- /dev/null -+++ b/tests/t_enable_mcsum_ext3/name -@@ -0,0 +1 @@ -+enable metadata_csum on ext3 fs -diff --git a/tests/t_enable_mcsum_ext3/script b/tests/t_enable_mcsum_ext3/script -new file mode 100644 -index 0000000..ac63866 ---- /dev/null -+++ b/tests/t_enable_mcsum_ext3/script -@@ -0,0 +1,70 @@ -+FSCK_OPT=-fn -+OUT=$test_name.log -+EXP=$test_dir/expect -+CONF=$TMPFILE.conf -+ -+cat > $CONF << ENDL -+[fs_types] -+ ext4h = { -+ features = has_journal,^extent,^huge_file,^flex_bg,^uninit_bg,^dir_nlink,^extra_isize,sparse_super,filetype,dir_index,ext_attr,resize_inode,^64bit -+ blocksize = 1024 -+ inode_size = 128 -+ make_hugefiles = true -+ hugefiles_dir = / -+ num_hugefiles = 10 -+ hugefiles_name = aaaaa -+ hugefiles_digits = 4 -+ hugefiles_size = 1M -+ zero_hugefiles = false -+ } -+ENDL -+ -+echo "tune2fs metadata_csum test" > $OUT -+ -+MKE2FS_CONFIG=$CONF $MKE2FS -F -T ext4h $TMPFILE 524288 >> $OUT 2>&1 -+rm -rf $CONF -+ -+# dump and check -+$DUMPE2FS $TMPFILE 2> /dev/null | grep '^Group 0:' -B99 -A20 | sed -f $cmd_dir/filter.sed > $OUT.before -+$FSCK $FSCK_OPT -N test_filesys $TMPFILE >> $OUT 2>&1 -+status=$? -+echo Exit status is $status >> $OUT -+ -+# add mcsum -+echo "tune2fs -O metadata_csum test.img" >> $OUT -+$TUNE2FS -O metadata_csum $TMPFILE >> $OUT 2>&1 -+status=$? -+echo Exit status is $status >> $OUT -+ -+# check -+$FSCK -yD -N test_filesys $TMPFILE >> $OUT 2>&1 -+ -+# dump and check -+$DUMPE2FS $TMPFILE 2> /dev/null | grep '^Group 0:' -B99 -A20 | sed -f $cmd_dir/filter.sed > $OUT.after -+echo "Change in FS metadata:" >> $OUT -+diff -u $OUT.before $OUT.after | tail -n +3 >> $OUT -+$FSCK $FSCK_OPT -N test_filesys $TMPFILE >> $OUT 2>&1 -+status=$? -+echo Exit status is $status >> $OUT -+ -+rm $TMPFILE $OUT.before $OUT.after -+ -+# -+# Do the verification -+# -+ -+sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" -e 's/test_filesys:.*//g' < $OUT > $OUT.new -+mv $OUT.new $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 IMAGE FSCK_OPT OUT EXP CONF -diff --git a/tests/t_enable_mcsum_initbg/expect b/tests/t_enable_mcsum_initbg/expect -new file mode 100644 -index 0000000..d3b4444 ---- /dev/null -+++ b/tests/t_enable_mcsum_initbg/expect -@@ -0,0 +1,98 @@ -+tune2fs metadata_csum test -+Creating filesystem with 524288 1k blocks and 65536 inodes -+Superblock backups stored on blocks: -+ 8193, 24577, 40961, 57345, 73729, 204801, 221185, 401409 -+ -+Allocating group tables: done -+Writing inode tables: done -+Creating journal (16384 blocks): done -+Creating 477 huge file(s) with 1024 blocks each: done -+Writing superblocks and filesystem accounting information: done -+ -+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 -+ -+Exit status is 0 -+tune2fs -O metadata_csum test.img -+ -+Please run e2fsck -D on the filesystem. -+ -+Exit status is 0 -+test_filesys was not cleanly unmounted, check forced. -+Pass 1: Checking inodes, blocks, and sizes -+Pass 2: Checking directory structure -+Pass 3: Checking directory connectivity -+Pass 3A: Optimizing directories -+Pass 4: Checking reference counts -+Pass 5: Checking group summary information -+ -+ -+ -+Change in FS metadata: -+@@ -2,7 +2,7 @@ -+ Last mounted on: -+ Filesystem magic number: 0xEF53 -+ Filesystem revision #: 1 (dynamic) -+-Filesystem features: has_journal ext_attr resize_inode dir_index filetype extent 64bit flex_bg sparse_super large_file huge_file dir_nlink extra_isize -++Filesystem features: has_journal ext_attr resize_inode dir_index filetype extent 64bit flex_bg sparse_super large_file huge_file dir_nlink extra_isize metadata_csum -+ Default mount options: user_xattr acl -+ Filesystem state: clean -+ Errors behavior: Continue -+@@ -10,7 +10,7 @@ -+ Inode count: 65536 -+ Block count: 524288 -+ Reserved block count: 26214 -+-Free blocks: 571 -++Free blocks: 568 -+ Free inodes: 65048 -+ First block: 1 -+ Block size: 1024 -+@@ -33,6 +33,7 @@ -+ Journal inode: 8 -+ Default directory hash: half_md4 -+ Journal backup: inode blocks -++Checksum type: crc32c -+ Journal features: (none) -+ Journal size: 16M -+ Journal length: 16384 -+@@ -40,24 +41,24 @@ -+ Journal start: 0 -+ -+ -+-Group 0: (Blocks 1-8192) -++Group 0: (Blocks 1-8192) [ITABLE_ZEROED] -+ Primary superblock at 1, Group descriptors at 2-5 -+ Reserved GDT blocks at 6-261 -+ Block bitmap at 262 (+261) -+ Inode bitmap at 278 (+277) -+ Inode table at 294-549 (+293) -+- 21 free blocks, 536 free inodes, 2 directories -+- Free blocks: 4413-4433 -++ 18 free blocks, 536 free inodes, 2 directories, 536 unused inodes -++ Free blocks: 4413, 4417-4433 -+ Free inodes: 489-1024 -+-Group 1: (Blocks 8193-16384) -++Group 1: (Blocks 8193-16384) [INODE_UNINIT, ITABLE_ZEROED] -+ Backup superblock at 8193, Group descriptors at 8194-8197 -+ Reserved GDT blocks at 8198-8453 -+ Block bitmap at 263 (bg #0 + 262) -+ Inode bitmap at 279 (bg #0 + 278) -+ Inode table at 550-805 (bg #0 + 549) -+- 0 free blocks, 1024 free inodes, 0 directories -++ 0 free blocks, 1024 free inodes, 0 directories, 1024 unused inodes -+ Free blocks: -+ Free inodes: 1025-2048 -+-Group 2: (Blocks 16385-24576) -++Group 2: (Blocks 16385-24576) [INODE_UNINIT, ITABLE_ZEROED] -+ Block bitmap at 264 (bg #0 + 263) -+ Inode bitmap at 280 (bg #0 + 279) -+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 -+ -+Exit status is 0 -diff --git a/tests/t_enable_mcsum_initbg/name b/tests/t_enable_mcsum_initbg/name -new file mode 100644 -index 0000000..291eb6b ---- /dev/null -+++ b/tests/t_enable_mcsum_initbg/name -@@ -0,0 +1 @@ -+enable metadata_csum when ^uninit_bg -diff --git a/tests/t_enable_mcsum_initbg/script b/tests/t_enable_mcsum_initbg/script -new file mode 100644 -index 0000000..35c4541 ---- /dev/null -+++ b/tests/t_enable_mcsum_initbg/script -@@ -0,0 +1,70 @@ -+FSCK_OPT=-fn -+OUT=$test_name.log -+EXP=$test_dir/expect -+CONF=$TMPFILE.conf -+ -+cat > $CONF << ENDL -+[fs_types] -+ ext4h = { -+ features = has_journal,extent,huge_file,flex_bg,^uninit_bg,dir_nlink,extra_isize,sparse_super,filetype,dir_index,ext_attr,resize_inode,64bit -+ blocksize = 1024 -+ inode_size = 256 -+ make_hugefiles = true -+ hugefiles_dir = / -+ hugefiles_slack = 0 -+ hugefiles_name = aaaaa -+ hugefiles_digits = 4 -+ hugefiles_size = 1M -+ zero_hugefiles = false -+ } -+ENDL -+ -+echo "tune2fs metadata_csum test" > $OUT -+ -+MKE2FS_CONFIG=$CONF $MKE2FS -F -T ext4h $TMPFILE 524288 >> $OUT 2>&1 -+rm -rf $CONF -+ -+# dump and check -+$DUMPE2FS $TMPFILE 2> /dev/null | grep '^Group 0:' -B99 -A20 | sed -f $cmd_dir/filter.sed > $OUT.before -+$FSCK $FSCK_OPT -N test_filesys $TMPFILE >> $OUT 2>&1 -+status=$? -+echo Exit status is $status >> $OUT -+ -+# add mcsum -+echo "tune2fs -O metadata_csum test.img" >> $OUT -+$TUNE2FS -O metadata_csum $TMPFILE >> $OUT 2>&1 -+status=$? -+echo Exit status is $status >> $OUT -+ -+# check -+$FSCK -yD -N test_filesys $TMPFILE >> $OUT 2>&1 -+ -+# dump and check -+$DUMPE2FS $TMPFILE 2> /dev/null | grep '^Group 0:' -B99 -A20 | sed -f $cmd_dir/filter.sed > $OUT.after -+echo "Change in FS metadata:" >> $OUT -+diff -u $OUT.before $OUT.after | tail -n +3 >> $OUT -+$FSCK $FSCK_OPT -N test_filesys $TMPFILE >> $OUT 2>&1 -+status=$? -+echo Exit status is $status >> $OUT -+ -+rm $TMPFILE $OUT.before $OUT.after -+ -+# -+# Do the verification -+# -+ -+sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" -e 's/test_filesys:.*//g' < $OUT > $OUT.new -+mv $OUT.new $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 IMAGE FSCK_OPT OUT EXP CONF -diff --git a/tests/t_ext_jnl_fail/expect b/tests/t_ext_jnl_fail/expect -new file mode 100644 -index 0000000..db0aecb ---- /dev/null -+++ b/tests/t_ext_jnl_fail/expect -@@ -0,0 +1,6 @@ -+Creating filesystem with 4096 1k blocks and 0 inodes -+Superblock backups stored on blocks: -+ -+Zeroing journal device:  -+tune2fs external journal -+Cannot modify a journal device. -diff --git a/tests/t_ext_jnl_fail/name b/tests/t_ext_jnl_fail/name -new file mode 100644 -index 0000000..2fe7d04 ---- /dev/null -+++ b/tests/t_ext_jnl_fail/name -@@ -0,0 +1 @@ -+tune2fs fail external journal -diff --git a/tests/t_ext_jnl_fail/script b/tests/t_ext_jnl_fail/script -new file mode 100644 -index 0000000..bb31cc7 ---- /dev/null -+++ b/tests/t_ext_jnl_fail/script -@@ -0,0 +1,30 @@ -+FSCK_OPT=-fy -+OUT=$test_name.log -+if [ -f $test_dir/expect.gz ]; then -+ EXP=$test_name.tmp -+ gunzip < $test_dir/expect.gz > $EXP1 -+else -+ EXP=$test_dir/expect -+fi -+ -+cp /dev/null $OUT -+ -+$MKE2FS -F -o Linux -b 1024 -O journal_dev,metadata_csum -T ext4 $TMPFILE 4096 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT 2>&1 -+echo "tune2fs external journal" >> $OUT -+$TUNE2FS -i 0 $TMPFILE 2>&1 | sed -f $cmd_dir/filter.sed >> $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 IMAGE FSCK_OPT OUT EXP -diff --git a/tests/t_iexpand_full/expect b/tests/t_iexpand_full/expect -new file mode 100644 -index 0000000..3eb1715 ---- /dev/null -+++ b/tests/t_iexpand_full/expect -@@ -0,0 +1,38 @@ -+tune2fs test -+Creating filesystem with 786432 1k blocks and 98304 inodes -+Superblock backups stored on blocks: -+ 8193, 24577, 40961, 57345, 73729, 204801, 221185, 401409, 663553 -+ -+Allocating group tables: done -+Writing inode tables: done -+Creating journal (16384 blocks): done -+Creating 6368 huge file(s) with 117 blocks each: done -+Writing superblocks and filesystem accounting information: done -+ -+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 -+ -+Exit status is 0 -+tune2fs -I 256 test.img -+Setting inode size 256 -+Exit status is 0 -+Change in FS metadata: -+@@ -13 +13 @@ -+-Free blocks: 12301 -++Free blocks: 12 -+@@ -22 +22 @@ -+-Inode blocks per group: 128 -++Inode blocks per group: 256 -+@@ -28 +28 @@ -+-Inode size: 128 -++Inode size: 256 -+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 -+ -+Exit status is 0 -diff --git a/tests/t_iexpand_full/name b/tests/t_iexpand_full/name -new file mode 100644 -index 0000000..2241b34 ---- /dev/null -+++ b/tests/t_iexpand_full/name -@@ -0,0 +1 @@ -+expand inodes on a totally full filesystem -diff --git a/tests/t_iexpand_full/script b/tests/t_iexpand_full/script -new file mode 100644 -index 0000000..f8565a7 ---- /dev/null -+++ b/tests/t_iexpand_full/script -@@ -0,0 +1,85 @@ -+if test -x $RESIZE2FS_EXE -a -x $DEBUGFS_EXE; then -+ -+if [ $(uname -s) = "Darwin" ]; then -+ # creates a 3GB filesystem -+ echo "$test_name: $DESCRIPTION: skipped for HFS+ (no sparse files)" -+ return 0 -+fi -+ -+FSCK_OPT=-fn -+OUT=$test_name.log -+EXP=$test_dir/expect -+CONF=$TMPFILE.conf -+ -+#gzip -d < $EXP.gz > $EXP -+ -+cat > $CONF << ENDL -+[fs_types] -+ ext4h = { -+ features = has_journal,extent,huge_file,uninit_bg,dir_nlink,extra_isize,sparse_super,filetype,dir_index,ext_attr,^resize_inode,^meta_bg,^flex_bg,metadata_csum,64bit -+ blocksize = 1024 -+ inode_size = 256 -+ make_hugefiles = true -+ hugefiles_dir = / -+ hugefiles_slack = 12000K -+ hugefiles_name = aaaaa -+ hugefiles_digits = 4 -+ hugefiles_size = 117K -+ zero_hugefiles = false -+ } -+ENDL -+ -+echo "tune2fs test" > $OUT -+ -+MKE2FS_CONFIG=$CONF $MKE2FS -F -T ext4h -I 128 $TMPFILE 786432 >> $OUT 2>&1 -+rm -rf $CONF -+ -+# dump and check -+($DUMPE2FS -h $TMPFILE; $DUMPE2FS -g $TMPFILE) 2>&1 | sed -f $cmd_dir/filter.sed -e '/^Checksum:.*/d' >> $OUT.before 2> /dev/null -+$FSCK $FSCK_OPT -N test_filesys $TMPFILE >> $OUT 2>&1 -+status=$? -+echo Exit status is $status >> $OUT -+ -+# convert it -+echo "tune2fs -I 256 test.img" >> $OUT -+dd if=/dev/zero of=$TMPFILE conv=notrunc bs=1 count=1 seek=3221225471 2> /dev/null -+$TUNE2FS -I 256 $TMPFILE >> $OUT 2>&1 -+status=$? -+echo Exit status is $status >> $OUT -+ -+# dump and check -+($DUMPE2FS -h $TMPFILE; $DUMPE2FS -g $TMPFILE) 2>&1 | sed -f $cmd_dir/filter.sed -e '/^Checksum:.*/d' >> $OUT.after 2> /dev/null -+echo "Change in FS metadata:" >> $OUT -+diff -U 0 $OUT.before $OUT.after | sed -e '/^---.*/d' -e '/^+++.*/d' >> $OUT -+$FSCK $FSCK_OPT -N test_filesys $TMPFILE >> $OUT 2>&1 -+status=$? -+echo Exit status is $status >> $OUT -+ -+rm $TMPFILE -+ -+# -+# Do the verification -+# -+ -+sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" -e 's/test_filesys:.*//g' < $OUT > $OUT.new -+mv $OUT.new $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 -+ -+rm $OUT.before $OUT.after -+ -+unset IMAGE FSCK_OPT OUT EXP CONF -+ -+else #if test -x $RESIZE2FS_EXE -a -x $DEBUGFS_EXE; then -+ echo "$test_name: $test_description: skipped" -+fi -+ -diff --git a/tests/t_iexpand_mcsum/expect b/tests/t_iexpand_mcsum/expect -new file mode 100644 -index 0000000..2a6d705 ---- /dev/null -+++ b/tests/t_iexpand_mcsum/expect -@@ -0,0 +1,54 @@ -+tune2fs test -+Creating filesystem with 786432 1k blocks and 98304 inodes -+Superblock backups stored on blocks: -+ 8193, 24577, 40961, 57345, 73729, 204801, 221185, 401409, 663553 -+ -+Allocating group tables: done -+Writing inode tables: done -+Creating journal (16384 blocks): done -+Creating 6334 huge file(s) with 117 blocks each: done -+Writing superblocks and filesystem accounting information: done -+ -+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 -+ -+Exit status is 0 -+tune2fs -I 256 -O metadata_csum test.img -+Setting inode size 256 -+ -+Please run e2fsck -D on the filesystem. -+ -+Exit status is 0 -+Backing up journal inode block information. -+ -+Pass 1: Checking inodes, blocks, and sizes -+Pass 2: Checking directory structure -+Pass 3: Checking directory connectivity -+Pass 3A: Optimizing directories -+Pass 4: Checking reference counts -+Pass 5: Checking group summary information -+ -+ -+ -+Change in FS metadata: -+@@ -5 +5 @@ -+-Filesystem features: has_journal ext_attr dir_index filetype extent 64bit sparse_super large_file huge_file uninit_bg dir_nlink extra_isize -++Filesystem features: has_journal ext_attr dir_index filetype extent 64bit sparse_super large_file huge_file dir_nlink extra_isize metadata_csum -+@@ -21 +21 @@ -+-Inode blocks per group: 128 -++Inode blocks per group: 256 -+@@ -27 +27 @@ -+-Inode size: 128 -++Inode size: 256 -+@@ -30,0 +31 @@ -++Checksum type: crc32c -+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 -+ -+Exit status is 0 -diff --git a/tests/t_iexpand_mcsum/name b/tests/t_iexpand_mcsum/name -new file mode 100644 -index 0000000..e767715 ---- /dev/null -+++ b/tests/t_iexpand_mcsum/name -@@ -0,0 +1 @@ -+expand inodes and turn on metadata_csum -diff --git a/tests/t_iexpand_mcsum/script b/tests/t_iexpand_mcsum/script -new file mode 100644 -index 0000000..4b584d3 ---- /dev/null -+++ b/tests/t_iexpand_mcsum/script -@@ -0,0 +1,85 @@ -+if test -x $RESIZE2FS_EXE -a -x $DEBUGFS_EXE; then -+if [ $(uname -s) = "Darwin" ]; then -+ # creates a 3GB filesystem -+ echo "$test_name: $DESCRIPTION: skipped for HFS+ (no sparse files)" -+ return 0 -+fi -+ -+FSCK_OPT=-fn -+OUT=$test_name.log -+EXP=$test_dir/expect -+CONF=$TMPFILE.conf -+ -+#gzip -d < $EXP.gz > $EXP -+ -+cat > $CONF << ENDL -+[fs_types] -+ ext4h = { -+ features = has_journal,extent,huge_file,uninit_bg,dir_nlink,extra_isize,sparse_super,filetype,dir_index,ext_attr,^resize_inode,^meta_bg,^flex_bg,^metadata_csum,64bit -+ blocksize = 1024 -+ inode_size = 256 -+ make_hugefiles = true -+ hugefiles_dir = / -+ hugefiles_slack = 16000K -+ hugefiles_name = aaaaa -+ hugefiles_digits = 4 -+ hugefiles_size = 117K -+ zero_hugefiles = false -+ } -+ENDL -+ -+echo "tune2fs test" > $OUT -+ -+MKE2FS_CONFIG=$CONF $MKE2FS -F -T ext4h -I 128 $TMPFILE 786432 >> $OUT 2>&1 -+rm -rf $CONF -+ -+# dump and check -+($DUMPE2FS -h $TMPFILE | grep -v '^Free blocks:'; $DUMPE2FS -g $TMPFILE) 2>&1 | sed -f $cmd_dir/filter.sed -e '/^Checksum:.*/d' >> $OUT.before 2> /dev/null -+$FSCK $FSCK_OPT -N test_filesys $TMPFILE >> $OUT 2>&1 -+status=$? -+echo Exit status is $status >> $OUT -+ -+# convert it -+echo "tune2fs -I 256 -O metadata_csum test.img" >> $OUT -+dd if=/dev/zero of=$TMPFILE conv=notrunc bs=1 count=1 seek=3221225471 2> /dev/null -+$TUNE2FS -I 256 -O metadata_csum $TMPFILE >> $OUT 2>&1 -+status=$? -+echo Exit status is $status >> $OUT -+$FSCK -N test_filesys -y -f -D $TMPFILE >> $OUT 2>&1 -+ -+# dump and check -+($DUMPE2FS -h $TMPFILE | grep -v '^Free blocks:'; $DUMPE2FS -g $TMPFILE) 2>&1 | sed -f $cmd_dir/filter.sed -e '/^Checksum:.*/d' >> $OUT.after 2> /dev/null -+echo "Change in FS metadata:" >> $OUT -+diff -U 0 $OUT.before $OUT.after | sed -e '/^---.*/d' -e '/^+++.*/d' >> $OUT -+$FSCK $FSCK_OPT -N test_filesys $TMPFILE >> $OUT 2>&1 -+status=$? -+echo Exit status is $status >> $OUT -+ -+rm $TMPFILE -+ -+# -+# Do the verification -+# -+ -+sed -f $cmd_dir/filter.sed -e "s;$TMPFILE;test.img;" -e 's/test_filesys:.*//g' < $OUT > $OUT.new -+mv $OUT.new $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 -+ -+rm $OUT.before $OUT.after -+ -+unset IMAGE FSCK_OPT OUT EXP CONF -+ -+else #if test -x $RESIZE2FS_EXE -a -x $DEBUGFS_EXE; then -+ echo "$test_name: $test_description: skipped" -+fi -+ -diff --git a/tests/t_mke2fs_errors/expect b/tests/t_mke2fs_errors/expect -new file mode 100644 -index 0000000..78514bd ---- /dev/null -+++ b/tests/t_mke2fs_errors/expect -@@ -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 -index 0000000..a5c553b ---- /dev/null -+++ b/tests/t_mke2fs_errors/script -@@ -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 -T test_suite -F $TMPFILE > /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 -T test_suite -F $TMPFILE > /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 -T test_suite -F $TMPFILE > /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 -T test_suite -e panic -F $TMPFILE > /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 -index 0000000..61e9eaa ---- /dev/null -+++ b/tests/t_uninit_bg_rm/expect -@@ -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 -index 0000000..308ef25 ---- /dev/null -+++ b/tests/t_uninit_bg_rm/script -@@ -0,0 +1,56 @@ -+test_description="remove uninit_bg" -+OUT=$test_name.log -+FSCK_OPT=-yf -+EXP=$test_dir/expect -+ -+if [ $(uname -s) = "Darwin" ]; then -+ # creates a 10GB filesystem -+ echo "$test_name: $DESCRIPTION: skipped for HFS+ (no sparse files)" -+ return 0 -+fi -+ -+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 -diff --git a/tests/test_config b/tests/test_config -index dbc36fe..7f39157 100644 ---- a/tests/test_config -+++ b/tests/test_config -@@ -17,9 +17,11 @@ TEST_BITS="../debugfs/debugfs" - RESIZE2FS_EXE="../resize/resize2fs" - RESIZE2FS="$USE_VALGRIND $RESIZE2FS_EXE" - E2UNDO_EXE="../misc/e2undo" -+E2UNDO="$USE_VALGRIND $E2UNDO_EXE" - TEST_REL=../tests/progs/test_rel - TEST_ICOUNT=../tests/progs/test_icount - CRCSUM=../tests/progs/crcsum -+CLEAN_OUTPUT="sed -f $cmd_dir/filter.sed" - LD_LIBRARY_PATH=../lib:../lib/ext2fs:../lib/e2p:../lib/et:../lib/ss:${LD_LIBRARY_PATH} - DYLD_LIBRARY_PATH=../lib:../lib/ext2fs:../lib/e2p:../lib/et:../lib/ss:${DYLD_LIBRARY_PATH} - export LD_LIBRARY_PATH -diff --git a/tests/u_compound_bad_rollback/script b/tests/u_compound_bad_rollback/script -new file mode 100644 -index 0000000..f54da7f ---- /dev/null -+++ b/tests/u_compound_bad_rollback/script -@@ -0,0 +1,62 @@ -+test_description="e2undo with mke2fs/tune2fs/resize2fs/e2fsck -z" -+if test -x $RESIZE2FS_EXE -a -x $E2UNDO_EXE; then -+ -+TDB_FILE=${TMPDIR:-/tmp}/resize2fs-$(basename $TMPFILE).e2undo -+OUT=$test_name.log -+rm -f $TDB_FILE >/dev/null 2>&1 -+ -+echo compound e2undo rollback test > $OUT -+ -+dd if=/dev/zero of=$TMPFILE bs=1k count=512 > /dev/null 2>&1 -+crc0=`$CRCSUM $TMPFILE` -+echo $CRCSUM before mke2fs $crc0 >> $OUT -+ -+echo mke2fs -q -F -o Linux -T ext4 -O ^metadata_csum,64bit -E lazy_itable_init=1 -b 1024 -z $TDB_FILE.0 $TMPFILE 256 >> $OUT -+$MKE2FS -q -F -o Linux -T ext4 -O ^metadata_csum,64bit -E lazy_itable_init=1 -b 1024 -z $TDB_FILE.0 $TMPFILE 256 >> $OUT 2>&1 -+crc1=`$CRCSUM $TMPFILE` -+echo $CRCSUM after mke2fs $crc1 >> $OUT -+ -+echo using tune2fs to test e2undo >> $OUT -+$TUNE2FS -O metadata_csum -z $TDB_FILE.1 $TMPFILE >> $OUT 2>&1 -+crc2=`$CRCSUM $TMPFILE` -+echo $CRCSUM after tune2fs $crc2 >> $OUT -+ -+echo using resize2fs to test e2undo >> $OUT -+$RESIZE2FS -z $TDB_FILE.2 $TMPFILE 512 >> $OUT 2>&1 -+crc3=`$CRCSUM $TMPFILE` -+echo $CRCSUM after resize2fs $crc3 >> $OUT -+ -+echo using e2fsck to test e2undo >> $OUT -+$FSCK -f -y -D -z $TDB_FILE.3 $TMPFILE >> $OUT 2>&1 -+crc4=`$CRCSUM $TMPFILE` -+echo $CRCSUM after e2fsck $crc4 >> $OUT -+ -+echo roll back mke2fs >> $OUT -+$E2UNDO $TDB_FILE.0 $TMPFILE >> $OUT 2>&1 -+crc0_2=`$CRCSUM $TMPFILE` -+echo $CRCSUM after e2undo mke2fs $crc0_2 >> $OUT -+ -+echo roll back tune2fs >> $OUT -+$E2UNDO $TDB_FILE.1 $TMPFILE >> $OUT 2>&1 -+crc1_2=`$CRCSUM $TMPFILE` -+echo $CRCSUM after e2undo tune2fs $crc1_2 >> $OUT -+ -+echo roll back resize2fs >> $OUT -+$E2UNDO $TDB_FILE.2 $TMPFILE >> $OUT 2>&1 -+crc2_2=`$CRCSUM $TMPFILE` -+echo $CRCSUM after e2undo resize2fs $crc2_2 >> $OUT -+ -+echo roll back e2fsck >> $OUT -+$E2UNDO $TDB_FILE.3 $TMPFILE >> $OUT 2>&1 -+crc3_2=`$CRCSUM $TMPFILE` -+echo $CRCSUM after e2undo e2fsck $crc3_2 >> $OUT -+ -+if [ $crc4 = $crc0_2 ] && [ $crc4 = $crc1_2 ] && [ $crc4 = $crc2_2 ] && [ $crc3 = $crc3_2 ]; then -+ echo "$test_name: $test_description: ok" -+ touch $test_name.ok -+else -+ ln -f $test_name.log $test_name.failed -+ echo "$test_name: $test_description: failed" -+fi -+rm -f $TDB_FILE.0 $TDB_FILE.1 $TDB_FILE.2 $TDB_FILE.3 $TMPFILE -+fi -diff --git a/tests/u_compound_rollback/script b/tests/u_compound_rollback/script -new file mode 100644 -index 0000000..0c1fbcc ---- /dev/null -+++ b/tests/u_compound_rollback/script -@@ -0,0 +1,62 @@ -+test_description="e2undo with mke2fs/tune2fs/resize2fs/e2fsck -z" -+if test -x $RESIZE2FS_EXE -a -x $E2UNDO_EXE; then -+ -+TDB_FILE=${TMPDIR:-/tmp}/resize2fs-$(basename $TMPFILE).e2undo -+OUT=$test_name.log -+rm -f $TDB_FILE >/dev/null 2>&1 -+ -+echo compound e2undo rollback test > $OUT -+ -+dd if=/dev/zero of=$TMPFILE bs=1k count=512 > /dev/null 2>&1 -+crc0=`$CRCSUM $TMPFILE` -+echo $CRCSUM before mke2fs $crc0 >> $OUT -+ -+echo mke2fs -q -F -o Linux -T ext4 -O ^metadata_csum,64bit -E lazy_itable_init=1 -b 1024 -z $TDB_FILE.0 $TMPFILE 256 >> $OUT -+$MKE2FS -q -F -o Linux -T ext4 -O ^metadata_csum,64bit -E lazy_itable_init=1 -b 1024 -z $TDB_FILE.0 $TMPFILE 256 >> $OUT 2>&1 -+crc1=`$CRCSUM $TMPFILE` -+echo $CRCSUM after mke2fs $crc1 >> $OUT -+ -+echo using tune2fs to test e2undo >> $OUT -+$TUNE2FS -O metadata_csum -z $TDB_FILE.1 $TMPFILE >> $OUT 2>&1 -+crc2=`$CRCSUM $TMPFILE` -+echo $CRCSUM after tune2fs $crc2 >> $OUT -+ -+echo using resize2fs to test e2undo >> $OUT -+$RESIZE2FS -z $TDB_FILE.2 $TMPFILE 512 >> $OUT 2>&1 -+crc3=`$CRCSUM $TMPFILE` -+echo $CRCSUM after resize2fs $crc3 >> $OUT -+ -+echo using e2fsck to test e2undo >> $OUT -+$FSCK -f -y -D -z $TDB_FILE.3 $TMPFILE >> $OUT 2>&1 -+crc4=`$CRCSUM $TMPFILE` -+echo $CRCSUM after e2fsck $crc4 >> $OUT -+ -+echo roll back e2fsck >> $OUT -+$E2UNDO $TDB_FILE.3 $TMPFILE >> $OUT 2>&1 -+crc3_2=`$CRCSUM $TMPFILE` -+echo $CRCSUM after e2undo e2fsck $crc3_2 >> $OUT -+ -+echo roll back resize2fs >> $OUT -+$E2UNDO $TDB_FILE.2 $TMPFILE >> $OUT 2>&1 -+crc2_2=`$CRCSUM $TMPFILE` -+echo $CRCSUM after e2undo resize2fs $crc2_2 >> $OUT -+ -+echo roll back tune2fs >> $OUT -+$E2UNDO $TDB_FILE.1 $TMPFILE >> $OUT 2>&1 -+crc1_2=`$CRCSUM $TMPFILE` -+echo $CRCSUM after e2undo tune2fs $crc1_2 >> $OUT -+ -+echo roll back mke2fs >> $OUT -+$E2UNDO $TDB_FILE.0 $TMPFILE >> $OUT 2>&1 -+crc0_2=`$CRCSUM $TMPFILE` -+echo $CRCSUM after e2undo mke2fs $crc0_2 >> $OUT -+ -+if [ $crc0 = $crc0_2 ] && [ $crc1 = $crc1_2 ] && [ $crc2 = $crc2_2 ] && [ $crc3 = $crc3_2 ]; then -+ echo "$test_name: $test_description: ok" -+ touch $test_name.ok -+else -+ ln -f $test_name.log $test_name.failed -+ echo "$test_name: $test_description: failed" -+fi -+rm -f $TDB_FILE.0 $TDB_FILE.1 $TDB_FILE.2 $TDB_FILE.3 $TMPFILE -+fi -diff --git a/tests/u_corrupt_blk_csum/script b/tests/u_corrupt_blk_csum/script -new file mode 100644 -index 0000000..ee16552 ---- /dev/null -+++ b/tests/u_corrupt_blk_csum/script -@@ -0,0 +1,38 @@ -+test_description="corrupt e2undo block data" -+if test -x $E2UNDO_EXE; then -+ -+E2FSPROGS_UNDO_DIR=${TMPDIR:-/tmp} -+export E2FSPROGS_UNDO_DIR -+TDB_FILE=$E2FSPROGS_UNDO_DIR/tune2fs-$(basename $TMPFILE).e2undo -+OUT=$test_name.log -+rm -f $TDB_FILE >/dev/null 2>&1 -+ -+dd if=/dev/zero of=$TMPFILE bs=1k count=512 > /dev/null 2>&1 -+ -+echo mke2fs -q -F -o Linux -b 1024 $TMPFILE > $OUT -+$MKE2FS -q -F -o Linux -I 128 -b 1024 $TMPFILE >> $OUT 2>&1 -+crc0=`$CRCSUM $TMPFILE` -+echo $CRCSUM before tune2fs $crc0 >> $OUT -+ -+echo using tune2fs to test e2undo >> $OUT -+$TUNE2FS -I 256 $TMPFILE >> $OUT 2>&1 -+crc1=`$CRCSUM $TMPFILE` -+echo $CRCSUM after tune2fs $crc1 >> $OUT -+ -+undo_blks=$(( $(stat -c '%s' $TDB_FILE 2>/dev/null || stat -f '%z' $TDB_FILE 2>/dev/null) / 1024 )) -+dd if=/dev/zero of=$TDB_FILE bs=1024 count=1 seek=$((undo_blks - 2)) conv=notrunc > /dev/null 2>&1 -+ -+$E2UNDO $TDB_FILE $TMPFILE >> $OUT 2>&1 -+res=$? -+crc2=`$CRCSUM $TMPFILE` -+echo $CRCSUM after e2undo $crc2 >> $OUT -+ -+if [ $res -ne 0 ] && [ $crc2 = $crc1 ] && [ $crc2 != $crc0 ]; then -+ echo "$test_name: $test_description: ok" -+ touch $test_name.ok -+else -+ ln -f $test_name.log $test_name.failed -+ echo "$test_name: $test_description: failed" -+fi -+rm -f $TDB_FILE $TMPFILE -+fi -diff --git a/tests/u_corrupt_blk_csum_force/script b/tests/u_corrupt_blk_csum_force/script -new file mode 100644 -index 0000000..ba82726 ---- /dev/null -+++ b/tests/u_corrupt_blk_csum_force/script -@@ -0,0 +1,38 @@ -+test_description="force replay of corrupt e2undo block data" -+if test -x $E2UNDO_EXE; then -+ -+E2FSPROGS_UNDO_DIR=${TMPDIR:-/tmp} -+export E2FSPROGS_UNDO_DIR -+TDB_FILE=$E2FSPROGS_UNDO_DIR/tune2fs-$(basename $TMPFILE).e2undo -+OUT=$test_name.log -+rm -f $TDB_FILE >/dev/null 2>&1 -+ -+dd if=/dev/zero of=$TMPFILE bs=1k count=512 > /dev/null 2>&1 -+ -+echo mke2fs -q -F -o Linux -b 1024 $TMPFILE > $OUT -+$MKE2FS -q -F -o Linux -I 128 -b 1024 $TMPFILE >> $OUT 2>&1 -+crc0=`$CRCSUM $TMPFILE` -+echo $CRCSUM before tune2fs $crc0 >> $OUT -+ -+echo using tune2fs to test e2undo >> $OUT -+$TUNE2FS -I 256 $TMPFILE >> $OUT 2>&1 -+crc1=`$CRCSUM $TMPFILE` -+echo $CRCSUM after tune2fs $crc1 >> $OUT -+ -+undo_blks=$(( $(stat -c '%s' $TDB_FILE 2>/dev/null || stat -f '%z' $TDB_FILE 2>/dev/null) / 1024 )) -+dd if=/dev/zero of=$TDB_FILE bs=1024 count=1 seek=$((undo_blks - 2)) conv=notrunc > /dev/null 2>&1 -+ -+$E2UNDO -f $TDB_FILE $TMPFILE >> $OUT 2>&1 -+res=$? -+crc2=`$CRCSUM $TMPFILE` -+echo $CRCSUM after e2undo $crc2 >> $OUT -+ -+if [ $crc2 != $crc1 ] && [ $crc2 != $crc0 ]; then -+ echo "$test_name: $test_description: ok" -+ touch $test_name.ok -+else -+ ln -f $test_name.log $test_name.failed -+ echo "$test_name: $test_description: failed" -+fi -+rm -f $TDB_FILE $TMPFILE -+fi -diff --git a/tests/u_corrupt_hdr_csum/script b/tests/u_corrupt_hdr_csum/script -new file mode 100644 -index 0000000..32c38c8 ---- /dev/null -+++ b/tests/u_corrupt_hdr_csum/script -@@ -0,0 +1,37 @@ -+test_description="corrupt e2undo header" -+if test -x $E2UNDO_EXE; then -+ -+E2FSPROGS_UNDO_DIR=${TMPDIR:-/tmp} -+export E2FSPROGS_UNDO_DIR -+TDB_FILE=$E2FSPROGS_UNDO_DIR/tune2fs-$(basename $TMPFILE).e2undo -+OUT=$test_name.log -+rm -f $TDB_FILE >/dev/null 2>&1 -+ -+dd if=/dev/zero of=$TMPFILE bs=1k count=512 > /dev/null 2>&1 -+ -+echo mke2fs -q -F -o Linux -b 1024 $TMPFILE > $OUT -+$MKE2FS -q -F -o Linux -I 128 -b 1024 $TMPFILE >> $OUT 2>&1 -+crc0=`$CRCSUM $TMPFILE` -+echo $CRCSUM before tune2fs $crc0 >> $OUT -+ -+echo using tune2fs to test e2undo >> $OUT -+$TUNE2FS -I 256 $TMPFILE >> $OUT 2>&1 -+crc1=`$CRCSUM $TMPFILE` -+echo $CRCSUM after tune2fs $crc1 >> $OUT -+ -+dd if=/dev/zero of=$TDB_FILE bs=256 count=1 seek=1 conv=notrunc > /dev/null 2>&1 -+ -+$E2UNDO $TDB_FILE $TMPFILE >> $OUT 2>&1 -+res=$? -+crc2=`$CRCSUM $TMPFILE` -+echo $CRCSUM after e2undo $crc2 >> $OUT -+ -+if [ $res -ne 0 ]; then -+ echo "$test_name: $test_description: ok" -+ touch $test_name.ok -+else -+ ln -f $test_name.log $test_name.failed -+ echo "$test_name: $test_description: failed" -+fi -+rm -f $TDB_FILE $TMPFILE -+fi -diff --git a/tests/u_corrupt_key_csum/script b/tests/u_corrupt_key_csum/script -new file mode 100644 -index 0000000..d07556b ---- /dev/null -+++ b/tests/u_corrupt_key_csum/script -@@ -0,0 +1,37 @@ -+test_description="corrupt e2undo key data" -+if test -x $E2UNDO_EXE; then -+ -+E2FSPROGS_UNDO_DIR=${TMPDIR:-/tmp} -+export E2FSPROGS_UNDO_DIR -+TDB_FILE=$E2FSPROGS_UNDO_DIR/tune2fs-$(basename $TMPFILE).e2undo -+OUT=$test_name.log -+rm -f $TDB_FILE >/dev/null 2>&1 -+ -+dd if=/dev/zero of=$TMPFILE bs=1k count=512 > /dev/null 2>&1 -+ -+echo mke2fs -q -F -o Linux -b 1024 $TMPFILE > $OUT -+$MKE2FS -q -F -o Linux -I 128 -b 1024 $TMPFILE >> $OUT 2>&1 -+crc0=`$CRCSUM $TMPFILE` -+echo $CRCSUM before tune2fs $crc0 >> $OUT -+ -+echo using tune2fs to test e2undo >> $OUT -+$TUNE2FS -I 256 $TMPFILE >> $OUT 2>&1 -+crc1=`$CRCSUM $TMPFILE` -+echo $CRCSUM after tune2fs $crc1 >> $OUT -+ -+undo_blks=$(( $(stat -c '%s' $TDB_FILE 2>/dev/null || stat -f '%z' $TDB_FILE 2>/dev/null) / 1024 )) -+dd if=/dev/zero of=$TDB_FILE bs=1024 count=1 seek=$((undo_blks - 1)) conv=notrunc > /dev/null 2>&1 -+ -+$E2UNDO $TDB_FILE $TMPFILE >> $OUT 2>&1 -+crc2=`$CRCSUM $TMPFILE` -+echo $CRCSUM after e2undo $crc2 >> $OUT -+ -+if [ $crc0 != $crc1 ] && [ $crc1 = $crc2 ]; then -+ echo "$test_name: $test_description: ok" -+ touch $test_name.ok -+else -+ ln -f $test_name.log $test_name.failed -+ echo "$test_name: $test_description: failed" -+fi -+rm -f $TDB_FILE $TMPFILE -+fi -diff --git a/tests/u_debugfs_opt/script b/tests/u_debugfs_opt/script -new file mode 100644 -index 0000000..bb93917 ---- /dev/null -+++ b/tests/u_debugfs_opt/script -@@ -0,0 +1,32 @@ -+test_description="e2undo with debugfs -z" -+if test -x $E2UNDO_EXE -a -x $DEBUGFS_EXE; then -+ -+TDB_FILE=${TMPDIR:-/tmp}/tune2fs-$(basename $TMPFILE).e2undo -+OUT=$test_name.log -+rm -f $TDB_FILE >/dev/null 2>&1 -+ -+dd if=/dev/zero of=$TMPFILE bs=1k count=512 > /dev/null 2>&1 -+ -+echo mke2fs -q -F -o Linux -T ext4 -O ^metadata_csum,64bit -E lazy_itable_init=1 -b 1024 $TMPFILE > $OUT -+$MKE2FS -q -F -o Linux -T ext4 -O ^metadata_csum,64bit -E lazy_itable_init=1 -b 1024 $TMPFILE >> $OUT 2>&1 -+crc0=`$CRCSUM $TMPFILE` -+echo $CRCSUM before debugfs $crc0 >> $OUT -+ -+echo using debugfs to test e2undo >> $OUT -+$DEBUGFS -w -z $TDB_FILE -R 'zap -p 0x55 0' $TMPFILE >> $OUT 2>&1 -+crc1=`$CRCSUM $TMPFILE` -+echo $CRCSUM after debugfs $crc1 >> $OUT -+ -+$E2UNDO $TDB_FILE $TMPFILE >> $OUT 2>&1 -+crc2=`$CRCSUM $TMPFILE` -+echo $CRCSUM after e2undo $crc2 >> $OUT -+ -+if [ $crc0 = $crc2 ] && [ $crc1 != $crc2 ]; then -+ echo "$test_name: $test_description: ok" -+ touch $test_name.ok -+else -+ ln -f $test_name.log $test_name.failed -+ echo "$test_name: $test_description: failed" -+fi -+rm -f $TDB_FILE $TMPFILE -+fi -diff --git a/tests/u_dryrun/script b/tests/u_dryrun/script -new file mode 100644 -index 0000000..b90ef47 ---- /dev/null -+++ b/tests/u_dryrun/script -@@ -0,0 +1,32 @@ -+test_description="e2undo dry run" -+if test -x $E2UNDO_EXE; then -+ -+TDB_FILE=${TMPDIR:-/tmp}/tune2fs-$(basename $TMPFILE).e2undo -+OUT=$test_name.log -+rm -f $TDB_FILE >/dev/null 2>&1 -+ -+dd if=/dev/zero of=$TMPFILE bs=1k count=512 > /dev/null 2>&1 -+ -+echo mke2fs -q -F -o Linux -T ext4 -O ^metadata_csum,64bit -E lazy_itable_init=1 -b 1024 $TMPFILE > $OUT -+$MKE2FS -q -F -o Linux -T ext4 -O ^metadata_csum,64bit -E lazy_itable_init=1 -b 1024 $TMPFILE >> $OUT 2>&1 -+crc0=`$CRCSUM $TMPFILE` -+echo $CRCSUM before tune2fs $crc0 >> $OUT -+ -+echo using tune2fs to test e2undo >> $OUT -+$TUNE2FS -O metadata_csum -z $TDB_FILE $TMPFILE >> $OUT 2>&1 -+crc1=`$CRCSUM $TMPFILE` -+echo $CRCSUM after tune2fs $crc1 >> $OUT -+ -+$E2UNDO -n $TDB_FILE $TMPFILE >> $OUT 2>&1 -+crc2=`$CRCSUM $TMPFILE` -+echo $CRCSUM after e2undo $crc2 >> $OUT -+ -+if [ $crc1 = $crc2 ] && [ $crc1 != $crc0 ]; then -+ echo "$test_name: $test_description: ok" -+ touch $test_name.ok -+else -+ ln -f $test_name.log $test_name.failed -+ echo "$test_name: $test_description: failed" -+fi -+rm -f $TDB_FILE $TMPFILE -+fi -diff --git a/tests/u_e2fsck_opt/script b/tests/u_e2fsck_opt/script -new file mode 100644 -index 0000000..d61cd2b ---- /dev/null -+++ b/tests/u_e2fsck_opt/script -@@ -0,0 +1,32 @@ -+test_description="e2undo with e2fsck -z" -+if test -x $E2UNDO_EXE; then -+ -+TDB_FILE=${TMPDIR:-/tmp}/e2fsck-$(basename $TMPFILE).e2undo -+OUT=$test_name.log -+rm -f $TDB_FILE >/dev/null 2>&1 -+ -+dd if=/dev/zero of=$TMPFILE bs=1k count=512 > /dev/null 2>&1 -+ -+echo mke2fs -q -F -o Linux -T ext4 -O ^metadata_csum,64bit -E lazy_itable_init=1 -b 1024 $TMPFILE > $OUT -+$MKE2FS -q -F -o Linux -T ext4 -O ^metadata_csum,64bit -E lazy_itable_init=1 -b 1024 $TMPFILE >> $OUT 2>&1 -+crc0=`$CRCSUM $TMPFILE` -+echo $CRCSUM before e2fsck $crc0 >> $OUT -+ -+echo using e2fsck to test e2undo >> $OUT -+$FSCK -f -y -z $TDB_FILE $TMPFILE >> $OUT 2>&1 -+crc1=`$CRCSUM $TMPFILE` -+echo $CRCSUM after e2fsck $crc1 >> $OUT -+ -+$E2UNDO $TDB_FILE $TMPFILE >> $OUT 2>&1 -+crc2=`$CRCSUM $TMPFILE` -+echo $CRCSUM after e2undo $crc2 >> $OUT -+ -+if [ $crc0 = $crc2 ] && [ $crc1 != $crc2 ]; then -+ echo "$test_name: $test_description: ok" -+ touch $test_name.ok -+else -+ ln -f $test_name.log $test_name.failed -+ echo "$test_name: $test_description: failed" -+fi -+rm -f $TDB_FILE $TMPFILE -+fi -diff --git a/tests/u_errorout/script b/tests/u_errorout/script -new file mode 100644 -index 0000000..20c53de ---- /dev/null -+++ b/tests/u_errorout/script -@@ -0,0 +1,49 @@ -+test_description="e2undo a failed command" -+if test -x $RESIZE2FS_EXE -a -x $E2UNDO_EXE; then -+ -+TDB_FILE=${TMPDIR:-/tmp}/resize2fs-$(basename $TMPFILE).e2undo -+OUT=$test_name.log -+rm -f $TDB_FILE >/dev/null 2>&1 -+ -+echo check that we cant append a bad undo file > $OUT -+ -+dd if=/dev/zero of=$TMPFILE bs=1k count=512 > /dev/null 2>&1 -+crc0=`$CRCSUM $TMPFILE` -+echo $CRCSUM before mke2fs $crc0 >> $OUT -+ -+CONF=$TMPFILE.conf -+cat > $CONF << ENDL -+[fs_types] -+ ext4h = { -+ features = ^has_journal,extent,huge_file,flex_bg,uninit_bg,dir_nlink,extra_isize,sparse_super,filetype,dir_index,ext_attr,resize_inode -+ blocksize = 4096 -+ inode_size = 256 -+ make_hugefiles = true -+ hugefiles_dir = / -+ hugefiles_slack = 0 -+ hugefiles_name = aaaaa -+ hugefiles_digits = 4 -+ hugefiles_size = 1K -+ zero_hugefiles = false -+ } -+ENDL -+ -+echo mke2fs -q -F -o Linux -T ext4h -O ^metadata_csum,^64bit -E lazy_itable_init=1 -b 1024 -z $TDB_FILE.0 $TMPFILE 524288 >> $OUT -+MKE2FS_CONFIG=$CONF $MKE2FS -q -F -o Linux -T ext4h -O ^metadata_csum,^64bit -E lazy_itable_init=1 -b 1024 -z $TDB_FILE.0 -d /etc/ $TMPFILE >> $OUT 2>&1 -+crc1=`$CRCSUM $TMPFILE` -+echo $CRCSUM after mke2fs $crc1 >> $OUT -+ -+echo roll back mke2fs >> $OUT -+$E2UNDO $TDB_FILE.0 $TMPFILE >> $OUT 2>&1 -+crc2=`$CRCSUM $TMPFILE` -+echo $CRCSUM after e2undo mke2fs $crc2 >> $OUT -+ -+if [ $crc0 != $crc1 ] && [ $crc1 != $crc2 ] && [ $crc0 = $crc2 ]; then -+ echo "$test_name: $test_description: ok" -+ touch $test_name.ok -+else -+ ln -f $test_name.log $test_name.failed -+ echo "$test_name: $test_description: failed" -+fi -+rm -f $TDB_FILE.0 $TMPFILE $CONF -+fi -diff --git a/tests/u_force/script b/tests/u_force/script -new file mode 100644 -index 0000000..ef39e24 ---- /dev/null -+++ b/tests/u_force/script -@@ -0,0 +1,40 @@ -+test_description="e2undo force" -+if test -x $E2UNDO_EXE; then -+ -+TDB_FILE=${TMPDIR:-/tmp}/tune2fs-$(basename $TMPFILE).e2undo -+OUT=$test_name.log -+rm -f $TDB_FILE >/dev/null 2>&1 -+ -+dd if=/dev/zero of=$TMPFILE bs=1k count=512 > /dev/null 2>&1 -+ -+echo mke2fs -q -F -o Linux -T ext4 -O ^metadata_csum,64bit -E lazy_itable_init=1 -b 1024 $TMPFILE > $OUT -+$MKE2FS -q -F -o Linux -T ext4 -O ^metadata_csum,64bit -E lazy_itable_init=1 -b 1024 $TMPFILE >> $OUT 2>&1 -+crc0=`$CRCSUM $TMPFILE` -+echo $CRCSUM before tune2fs $crc0 >> $OUT -+ -+echo using tune2fs to test e2undo >> $OUT -+$TUNE2FS -O metadata_csum -z $TDB_FILE $TMPFILE >> $OUT 2>&1 -+crc1=`$CRCSUM $TMPFILE` -+echo $CRCSUM after tune2fs $crc1 >> $OUT -+ -+dd if=/dev/zero of=$TDB_FILE bs=4 count=1 seek=127 conv=notrunc 2> /dev/null -+ -+$E2UNDO $TDB_FILE $TMPFILE >> $OUT 2>&1 -+crc2=`$CRCSUM $TMPFILE` -+echo $CRCSUM after e2undo $crc2 >> $OUT -+ -+$E2UNDO -f $TDB_FILE $TMPFILE >> $OUT 2>&1 -+crc3=`$CRCSUM $TMPFILE` -+echo $CRCSUM after e2undo -f $crc3 >> $OUT -+ -+MUST_FSCK=$($DUMPE2FS $TMPFILE 2> /dev/null | grep 'Filesystem state:.*not clean' -c ) -+ -+if [ $MUST_FSCK -eq 1 ] && [ $crc0 != $crc3 ] && [ $crc1 = $crc2 ] && [ $crc2 != $crc0 ]; then -+ echo "$test_name: $test_description: ok" -+ touch $test_name.ok -+else -+ ln -f $test_name.log $test_name.failed -+ echo "$test_name: $test_description: failed" -+fi -+rm -f $TDB_FILE $TMPFILE -+fi -diff --git a/tests/u_force_dryrun/script b/tests/u_force_dryrun/script -new file mode 100644 -index 0000000..92d7624 ---- /dev/null -+++ b/tests/u_force_dryrun/script -@@ -0,0 +1,38 @@ -+test_description="force dry-run replay of corrupt e2undo block data" -+if test -x $E2UNDO_EXE; then -+ -+E2FSPROGS_UNDO_DIR=${TMPDIR:-/tmp} -+export E2FSPROGS_UNDO_DIR -+TDB_FILE=$E2FSPROGS_UNDO_DIR/tune2fs-$(basename $TMPFILE).e2undo -+OUT=$test_name.log -+rm -f $TDB_FILE >/dev/null 2>&1 -+ -+dd if=/dev/zero of=$TMPFILE bs=1k count=512 > /dev/null 2>&1 -+ -+echo mke2fs -q -F -o Linux -b 1024 $TMPFILE > $OUT -+$MKE2FS -q -F -o Linux -I 128 -b 1024 $TMPFILE >> $OUT 2>&1 -+crc0=`$CRCSUM $TMPFILE` -+echo $CRCSUM before tune2fs $crc0 >> $OUT -+ -+echo using tune2fs to test e2undo >> $OUT -+$TUNE2FS -I 256 $TMPFILE >> $OUT 2>&1 -+crc1=`$CRCSUM $TMPFILE` -+echo $CRCSUM after tune2fs $crc1 >> $OUT -+ -+undo_blks=$(( $(stat -c '%s' $TDB_FILE 2>/dev/null || stat -f '%z' $TDB_FILE 2>/dev/null) / 1024 )) -+dd if=/dev/zero of=$TDB_FILE bs=1024 count=1 seek=$((undo_blks - 2)) conv=notrunc > /dev/null 2>&1 -+ -+$E2UNDO -f -n $TDB_FILE $TMPFILE >> $OUT 2>&1 -+res=$? -+crc2=`$CRCSUM $TMPFILE` -+echo $CRCSUM after e2undo $crc2 >> $OUT -+ -+if [ $crc2 = $crc1 ] && [ $crc2 != $crc0 ]; then -+ echo "$test_name: $test_description: ok" -+ touch $test_name.ok -+else -+ ln -f $test_name.log $test_name.failed -+ echo "$test_name: $test_description: failed" -+fi -+rm -f $TDB_FILE $TMPFILE -+fi -diff --git a/tests/u_incomplete/script b/tests/u_incomplete/script -new file mode 100644 -index 0000000..7bc7858 ---- /dev/null -+++ b/tests/u_incomplete/script -@@ -0,0 +1,38 @@ -+test_description="e2undo with incomplete undo file" -+if test -x $E2UNDO_EXE; then -+ -+TDB_FILE=${TMPDIR:-/tmp}/tune2fs-$(basename $TMPFILE).e2undo -+OUT=$test_name.log -+rm -f $TDB_FILE >/dev/null 2>&1 -+ -+dd if=/dev/zero of=$TMPFILE bs=1k count=512 > /dev/null 2>&1 -+ -+echo mke2fs -q -F -o Linux -T ext4 -O ^metadata_csum,64bit -E lazy_itable_init=1 -b 1024 $TMPFILE > $OUT -+$MKE2FS -q -F -o Linux -T ext4 -O ^metadata_csum,64bit -E lazy_itable_init=1 -b 1024 $TMPFILE >> $OUT 2>&1 -+crc0=`$CRCSUM $TMPFILE` -+echo $CRCSUM before tune2fs $crc0 >> $OUT -+ -+echo using tune2fs to test e2undo >> $OUT -+UNDO_IO_SIMULATE_UNFINISHED=1 $TUNE2FS -O metadata_csum -z $TDB_FILE $TMPFILE >> $OUT 2>&1 -+crc1=`$CRCSUM $TMPFILE` -+echo $CRCSUM after tune2fs $crc1 >> $OUT -+ -+$E2UNDO $TDB_FILE $TMPFILE >> $OUT 2>&1 -+crc2=`$CRCSUM $TMPFILE` -+echo $CRCSUM after e2undo $crc2 >> $OUT -+ -+$FSCK -y $TMPFILE >> $OUT 2>&1 -+fsck_res=$? -+crc3=`$CRCSUM $TMPFILE` -+echo $CRCSUM after fsck $crc3 >> $OUT -+echo fsck result $fsck_res >> $OUT -+ -+if [ $crc0 != $crc2 ] && [ $crc1 != $crc2 ] && [ $crc0 != $crc1 ] && [ $fsck_res -eq 1 ]; then -+ echo "$test_name: $test_description: ok" -+ touch $test_name.ok -+else -+ ln -f $test_name.log $test_name.failed -+ echo "$test_name: $test_description: failed" -+fi -+rm -f $TDB_FILE $TMPFILE -+fi -diff --git a/tests/u_mke2fs/script b/tests/u_mke2fs/script -index d249ddd..f1041a9 100644 ---- a/tests/u_mke2fs/script -+++ b/tests/u_mke2fs/script -@@ -1,7 +1,7 @@ - test_description="e2undo with mke2fs" - if test -x $E2UNDO_EXE; then - --E2FSPROGS_UNDO_DIR=/tmp -+E2FSPROGS_UNDO_DIR=${TMPDIR:-/tmp} - export E2FSPROGS_UNDO_DIR - TDB_FILE=$E2FSPROGS_UNDO_DIR/mke2fs-$(basename $TMPFILE).e2undo - OUT=$test_name.log -@@ -19,7 +19,7 @@ $MKE2FS -q -F -o Linux -I 256 -O uninit_bg -E lazy_itable_init=1 -b 1024 $TMPFIL - new_crc=`$CRCSUM $TMPFILE` - echo $CRCSUM after mke2fs $new_crc >> $OUT - --$E2UNDO_EXE $TDB_FILE $TMPFILE >> $OUT 2>&1 -+$E2UNDO $TDB_FILE $TMPFILE >> $OUT 2>&1 - new_crc=`$CRCSUM $TMPFILE` - echo $CRCSUM after e2undo $new_crc >> $OUT - -diff --git a/tests/u_mke2fs_opt/script b/tests/u_mke2fs_opt/script -new file mode 100644 -index 0000000..db62ab2 ---- /dev/null -+++ b/tests/u_mke2fs_opt/script -@@ -0,0 +1,32 @@ -+test_description="e2undo with mke2fs -z" -+if test -x $E2UNDO_EXE; then -+ -+TDB_FILE=${TMPDIR:-/tmp}/mke2fs-$(basename $TMPFILE).e2undo -+OUT=$test_name.log -+rm -f $TDB_FILE >/dev/null 2>&1 -+ -+dd if=/dev/zero of=$TMPFILE bs=1k count=512 > /dev/null 2>&1 -+ -+echo mke2fs -F -o Linux -I 128 -b 1024 test.img > $OUT -+$MKE2FS -F -o Linux -I 128 -b 1024 $TMPFILE >> $OUT 2>&1 -+crc0=`$CRCSUM $TMPFILE` -+echo $CRCSUM before mke2fs $crc0 >> $OUT -+ -+echo using mke2fs to test e2undo >> $OUT -+$MKE2FS -q -F -o Linux -T ext4 -E lazy_itable_init=1 -b 1024 -z $TDB_FILE $TMPFILE >> $OUT 2>&1 -+crc1=`$CRCSUM $TMPFILE` -+echo $CRCSUM after mke2fs $crc1 >> $OUT -+ -+$E2UNDO $TDB_FILE $TMPFILE >> $OUT 2>&1 -+crc2=`$CRCSUM $TMPFILE` -+echo $CRCSUM after e2undo $crc2 >> $OUT -+ -+if [ $crc0 = $crc2 ] && [ $crc1 != $crc2 ]; then -+ echo "$test_name: $test_description: ok" -+ touch $test_name.ok -+else -+ ln -f $test_name.log $test_name.failed -+ echo "$test_name: $test_description: failed" -+fi -+rm -f $TDB_FILE $TMPFILE -+fi -diff --git a/tests/u_mke2fs_opt_oddsize/script b/tests/u_mke2fs_opt_oddsize/script -new file mode 100644 -index 0000000..23e0b9e ---- /dev/null -+++ b/tests/u_mke2fs_opt_oddsize/script -@@ -0,0 +1,31 @@ -+test_description="e2undo with mke2fs -z and non-32k-aligned bdev size" -+if test -x $E2UNDO_EXE; then -+ -+TDB_FILE=${TMPDIR:-/tmp}/mke2fs-$(basename $TMPFILE).e2undo -+OUT=$test_name.log -+rm -f $TDB_FILE >/dev/null 2>&1 -+ -+dd if=/dev/zero of=$TMPFILE bs=1k count=512 > /dev/null 2>&1 -+yes "abc123abc123abc" | dd bs=1k count=8 >> $TMPFILE 2> /dev/null -+ -+crc0=`$CRCSUM $TMPFILE` -+echo $CRCSUM before mke2fs $crc0 > $OUT -+ -+echo using mke2fs to test e2undo >> $OUT -+$MKE2FS -q -F -o Linux -T ext4 -E lazy_itable_init=1 -b 1024 -z $TDB_FILE $TMPFILE >> $OUT 2>&1 -+crc1=`$CRCSUM $TMPFILE` -+echo $CRCSUM after mke2fs $crc1 >> $OUT -+ -+$E2UNDO $TDB_FILE $TMPFILE >> $OUT 2>&1 -+crc2=`$CRCSUM $TMPFILE` -+echo $CRCSUM after e2undo $crc2 >> $OUT -+ -+if [ $crc0 = $crc2 ] && [ $crc1 != $crc2 ]; then -+ echo "$test_name: $test_description: ok" -+ touch $test_name.ok -+else -+ ln -f $test_name.log $test_name.failed -+ echo "$test_name: $test_description: failed" -+fi -+rm -f $TDB_FILE $TMPFILE -+fi -diff --git a/tests/u_not_undo/script b/tests/u_not_undo/script -new file mode 100644 -index 0000000..2f07d1b ---- /dev/null -+++ b/tests/u_not_undo/script -@@ -0,0 +1,28 @@ -+test_description="e2undo a non-undo file" -+if test -x $E2UNDO_EXE; then -+ -+TDB_FILE=${TMPDIR:-/tmp}/tune2fs-$(basename $TMPFILE).e2undo -+OUT=$test_name.log -+rm -f $TDB_FILE >/dev/null 2>&1 -+ -+dd if=/dev/zero of=$TMPFILE bs=1k count=512 > /dev/null 2>&1 -+dd if=/dev/zero of=$TDB_FILE bs=1k count=512 > /dev/null 2>&1 -+ -+crc0=`$CRCSUM $TMPFILE` -+echo $CRCSUM before e2undo $crc0 > $OUT -+ -+od -tx1 -Ad -c < $TDB_FILE >> $OUT -+ -+$E2UNDO $TDB_FILE $TMPFILE >> $OUT 2>&1 -+crc3=`$CRCSUM $TMPFILE` -+echo $CRCSUM after e2undo $crc3 >> $OUT -+ -+if [ $crc3 = $crc0 ]; then -+ echo "$test_name: $test_description: ok" -+ touch $test_name.ok -+else -+ ln -f $test_name.log $test_name.failed -+ echo "$test_name: $test_description: failed" -+fi -+rm -f $TDB_FILE $TMPFILE -+fi -diff --git a/tests/u_onefile_bad/script b/tests/u_onefile_bad/script -new file mode 100644 -index 0000000..60c9a2e ---- /dev/null -+++ b/tests/u_onefile_bad/script -@@ -0,0 +1,115 @@ -+test_description="check that we cant append a bad undo file" -+if test -x $RESIZE2FS_EXE -a -x $E2UNDO_EXE; then -+ -+TDB_FILE=${TMPDIR:-/tmp}/resize2fs-$(basename $TMPFILE).e2undo -+OUT=$test_name.log -+rm -f $TDB_FILE >/dev/null 2>&1 -+fail=0 -+ -+echo check that we cant append a bad undo file > $OUT -+ -+dd if=/dev/zero of=$TMPFILE bs=1k count=512 > /dev/null 2>&1 -+crc0=`$CRCSUM $TMPFILE` -+echo $CRCSUM before mke2fs $crc0 >> $OUT -+ -+CONF=$TMPFILE.conf -+cat > $CONF << ENDL -+[fs_types] -+ ext4h = { -+ features = has_journal,extent,huge_file,flex_bg,uninit_bg,dir_nlink,extra_isize,sparse_super,filetype,dir_index,ext_attr,resize_inode -+ blocksize = 4096 -+ inode_size = 256 -+ make_hugefiles = true -+ hugefiles_dir = / -+ hugefiles_slack = 0 -+ hugefiles_name = aaaaa -+ hugefiles_digits = 4 -+ hugefiles_size = 1M -+ zero_hugefiles = false -+ } -+ENDL -+ -+echo mke2fs -q -F -o Linux -T ext4h -O ^metadata_csum,^64bit -E lazy_itable_init=1 -b 4096 -z $TDB_FILE.0 $TMPFILE 524288 >> $OUT -+MKE2FS_CONFIG=$CONF $MKE2FS -q -F -o Linux -T ext4h -O ^metadata_csum,^64bit -E lazy_itable_init=1 -b 4096 -z $TDB_FILE.0 $TMPFILE >> $OUT 2>&1 -+crc1=`$CRCSUM $TMPFILE` -+echo $CRCSUM after mke2fs $crc1 >> $OUT -+features="$($DUMPE2FS -h $TMPFILE 2> /dev/null | grep 'Filesystem features:')" -+if [ "$(echo "${features}" | grep "metadata_csum" -c)" -gt 0 ] || [ "$(echo "${features}" | grep 64bit -c)" -gt 0 ]; then -+ echo "FS features: ${features}" >> $OUT -+ echo "Should not have 64bit or metadata_csum set" >> $OUT -+ fail=1 -+fi -+$FSCK -f -n $TMPFILE >> $OUT 2>&1 || fail=1 -+ -+echo using resize2fs to test e2undo >> $OUT -+$RESIZE2FS -z $TDB_FILE.1 -b $TMPFILE >> $OUT 2>&1 -+crc2=`$CRCSUM $TMPFILE` -+echo $CRCSUM after resize2fs $crc2 >> $OUT -+features="$($DUMPE2FS -h $TMPFILE 2> /dev/null | grep 'Filesystem features:')" -+if [ "$(echo "${features}" | grep "metadata_csum" -c)" -gt 0 ] || [ "$(echo "${features}" | grep 64bit -c)" -lt 1 ]; then -+ echo "FS features: ${features}" >> $OUT -+ echo "Should have 64bit but not metadata_csum set" >> $OUT -+ fail=1 -+fi -+$FSCK -f -n $TMPFILE >> $OUT 2>&1 || fail=1 -+ -+echo corrupt $TDB_FILE.1 >> $OUT -+dd if=/dev/zero of=$TDB_FILE.1 bs=4096 count=1 skip=1 2> /dev/null -+ -+echo using tune2fs to test e2undo >> $OUT -+$TUNE2FS -O metadata_csum -z $TDB_FILE.1 $TMPFILE >> $OUT 2>&1 -+crc3=`$CRCSUM $TMPFILE` -+echo $CRCSUM after tune2fs $crc3 >> $OUT -+features="$($DUMPE2FS -h $TMPFILE 2> /dev/null | grep 'Filesystem features:')" -+if [ "$(echo "${features}" | grep "metadata_csum" -c)" -gt 0 ] || [ "$(echo "${features}" | grep 64bit -c)" -lt 1 ]; then -+ echo "FS features: ${features}" >> $OUT -+ echo "Should have 64bit but not metadata_csum set" >> $OUT -+ fail=1 -+fi -+$FSCK -f -n $TMPFILE >> $OUT 2>&1 || fail=1 -+ -+echo using e2fsck to test e2undo >> $OUT -+$FSCK -f -y -D -z $TDB_FILE.1 $TMPFILE >> $OUT 2>&1 -+crc4=`$CRCSUM $TMPFILE` -+echo $CRCSUM after e2fsck $crc4 >> $OUT -+features="$($DUMPE2FS -h $TMPFILE 2> /dev/null | grep 'Filesystem features:')" -+if [ "$(echo "${features}" | grep "metadata_csum" -c)" -gt 0 ] || [ "$(echo "${features}" | grep 64bit -c)" -lt 1 ]; then -+ echo "FS features: ${features}" >> $OUT -+ echo "Should have 64bit but not metadata_csum set" >> $OUT -+ fail=1 -+fi -+$FSCK -f -n $TMPFILE >> $OUT 2>&1 || fail=1 -+ -+echo roll back e2fsck/tune2fs/resize2fs >> $OUT -+$E2UNDO $TDB_FILE.1 $TMPFILE >> $OUT 2>&1 -+crc1_2=`$CRCSUM $TMPFILE` -+echo $CRCSUM after e2undo e2fsck/tune2fs/resize2fs $crc1_2 >> $OUT -+features="$($DUMPE2FS -h $TMPFILE 2> /dev/null | grep 'Filesystem features:')" -+if [ "$(echo "${features}" | grep "metadata_csum" -c)" -gt 0 ] || [ "$(echo "${features}" | grep 64bit -c)" -lt 1 ]; then -+ echo "FS features: ${features}" >> $OUT -+ echo "Should have 64bit but not metadata_csum set" >> $OUT -+ fail=1 -+fi -+$FSCK -f -n $TMPFILE >> $OUT 2>&1 || fail=1 -+ -+echo roll back mke2fs >> $OUT -+$E2UNDO $TDB_FILE.0 $TMPFILE >> $OUT 2>&1 -+crc0_2=`$CRCSUM $TMPFILE` -+echo $CRCSUM after e2undo mke2fs $crc0_2 >> $OUT -+features="$($DUMPE2FS -h $TMPFILE 2> /dev/null | grep 'Filesystem features:')" -+if [ "$(echo "${features}" | grep "metadata_csum" -c)" -gt 0 ] || [ "$(echo "${features}" | grep 64bit -c)" -lt 1 ]; then -+ echo "FS features: ${features}" >> $OUT -+ echo "Should have 64bit but not metadata_csum set" >> $OUT -+ fail=1 -+fi -+$FSCK -f -n $TMPFILE >> $OUT 2>&1 || fail=1 -+ -+if [ $fail -eq 0 ] && [ $crc0 != $crc1 ] && [ $crc1 != $crc2 ] && [ $crc2 = $crc3 ] && [ $crc3 = $crc4 ] && [ $crc1_2 = $crc2 ] && [ $crc0_2 = $crc2 ]; then -+ echo "$test_name: $test_description: ok" -+ touch $test_name.ok -+else -+ ln -f $test_name.log $test_name.failed -+ echo "$test_name: $test_description: failed" -+fi -+rm -f $TDB_FILE.0 $TDB_FILE.1 $TMPFILE $CONF -+fi -diff --git a/tests/u_resize2fs_opt/script b/tests/u_resize2fs_opt/script -new file mode 100644 -index 0000000..fe1e04d ---- /dev/null -+++ b/tests/u_resize2fs_opt/script -@@ -0,0 +1,32 @@ -+test_description="e2undo with resize2fs -z" -+if test -x $RESIZE2FS_EXE -a -x $E2UNDO_EXE; then -+ -+TDB_FILE=${TMPDIR:-/tmp}/resize2fs-$(basename $TMPFILE).e2undo -+OUT=$test_name.log -+rm -f $TDB_FILE >/dev/null 2>&1 -+ -+dd if=/dev/zero of=$TMPFILE bs=1k count=512 > /dev/null 2>&1 -+ -+echo mke2fs -q -F -o Linux -T ext4 -O ^metadata_csum,64bit -E lazy_itable_init=1 -b 1024 $TMPFILE 256 > $OUT -+$MKE2FS -q -F -o Linux -T ext4 -O ^metadata_csum,64bit -E lazy_itable_init=1 -b 1024 $TMPFILE 256 >> $OUT 2>&1 -+crc0=`$CRCSUM $TMPFILE` -+echo $CRCSUM before resize2fs $crc0 >> $OUT -+ -+echo using resize2fs to test e2undo >> $OUT -+$RESIZE2FS -z $TDB_FILE $TMPFILE 512 >> $OUT 2>&1 -+crc1=`$CRCSUM $TMPFILE` -+echo $CRCSUM after resize2fs $crc1 >> $OUT -+ -+$E2UNDO $TDB_FILE $TMPFILE >> $OUT 2>&1 -+crc2=`$CRCSUM $TMPFILE` -+echo $CRCSUM after e2undo $crc2 >> $OUT -+ -+if [ $crc0 = $crc2 ] && [ $crc1 != $crc2 ]; then -+ echo "$test_name: $test_description: ok" -+ touch $test_name.ok -+else -+ ln -f $test_name.log $test_name.failed -+ echo "$test_name: $test_description: failed" -+fi -+rm -f $TDB_FILE $TMPFILE -+fi -diff --git a/tests/u_revert_64bitmcsum_onefile/script b/tests/u_revert_64bitmcsum_onefile/script -new file mode 100644 -index 0000000..f1d7c2b ---- /dev/null -+++ b/tests/u_revert_64bitmcsum_onefile/script -@@ -0,0 +1,112 @@ -+test_description="convert fs to 64bit,metadata_csum and revert as one undo file" -+if test -x $RESIZE2FS_EXE -a -x $E2UNDO_EXE; then -+ -+TDB_FILE=${TMPDIR:-/tmp}/resize2fs-$(basename $TMPFILE).e2undo -+OUT=$test_name.log -+rm -f $TDB_FILE >/dev/null 2>&1 -+fail=0 -+ -+echo convert fs to 64bit,metadata_csum and revert both changes as one undo file > $OUT -+ -+dd if=/dev/zero of=$TMPFILE bs=1k count=512 > /dev/null 2>&1 -+crc0=`$CRCSUM $TMPFILE` -+echo $CRCSUM before mke2fs $crc0 >> $OUT -+ -+CONF=$TMPFILE.conf -+cat > $CONF << ENDL -+[fs_types] -+ ext4h = { -+ features = has_journal,extent,huge_file,flex_bg,uninit_bg,dir_nlink,extra_isize,sparse_super,filetype,dir_index,ext_attr,resize_inode -+ blocksize = 4096 -+ inode_size = 256 -+ make_hugefiles = true -+ hugefiles_dir = / -+ hugefiles_slack = 0 -+ hugefiles_name = aaaaa -+ hugefiles_digits = 4 -+ hugefiles_size = 1M -+ zero_hugefiles = false -+ } -+ENDL -+ -+echo mke2fs -q -F -o Linux -T ext4h -O ^metadata_csum,^64bit -E lazy_itable_init=1 -b 4096 -z $TDB_FILE.0 $TMPFILE 524288 >> $OUT -+MKE2FS_CONFIG=$CONF $MKE2FS -q -F -o Linux -T ext4h -O ^metadata_csum,^64bit -E lazy_itable_init=1 -b 4096 -z $TDB_FILE.0 $TMPFILE >> $OUT 2>&1 -+crc1=`$CRCSUM $TMPFILE` -+echo $CRCSUM after mke2fs $crc1 >> $OUT -+features="$($DUMPE2FS -h $TMPFILE 2> /dev/null | grep 'Filesystem features:')" -+if [ "$(echo "${features}" | grep "metadata_csum" -c)" -gt 0 ] || [ "$(echo "${features}" | grep 64bit -c)" -gt 0 ]; then -+ echo "FS features: ${features}" >> $OUT -+ echo "Should not have 64bit or metadata_csum set" >> $OUT -+ fail=1 -+fi -+$FSCK -f -n $TMPFILE >> $OUT 2>&1 || fail=1 -+ -+echo using resize2fs to test e2undo >> $OUT -+$RESIZE2FS -z $TDB_FILE.1 -b $TMPFILE >> $OUT 2>&1 -+crc2=`$CRCSUM $TMPFILE` -+echo $CRCSUM after resize2fs $crc2 >> $OUT -+features="$($DUMPE2FS -h $TMPFILE 2> /dev/null | grep 'Filesystem features:')" -+if [ "$(echo "${features}" | grep "metadata_csum" -c)" -gt 0 ] || [ "$(echo "${features}" | grep 64bit -c)" -lt 1 ]; then -+ echo "FS features: ${features}" >> $OUT -+ echo "Should have 64bit but not metadata_csum set" >> $OUT -+ fail=1 -+fi -+$FSCK -f -n $TMPFILE >> $OUT 2>&1 || fail=1 -+ -+echo using tune2fs to test e2undo >> $OUT -+$TUNE2FS -O metadata_csum -z $TDB_FILE.1 $TMPFILE >> $OUT 2>&1 -+crc3=`$CRCSUM $TMPFILE` -+echo $CRCSUM after tune2fs $crc3 >> $OUT -+features="$($DUMPE2FS -h $TMPFILE 2> /dev/null | grep 'Filesystem features:')" -+if [ "$(echo "${features}" | grep "metadata_csum" -c)" -lt 1 ] || [ "$(echo "${features}" | grep 64bit -c)" -lt 1 ]; then -+ echo "FS features: ${features}" >> $OUT -+ echo "Should have 64bit and metadata_csum set" >> $OUT -+ fail=1 -+fi -+$FSCK -f -n $TMPFILE >> $OUT 2>&1 || fail=1 -+ -+echo using e2fsck to test e2undo >> $OUT -+$FSCK -f -y -D -z $TDB_FILE.1 $TMPFILE >> $OUT 2>&1 -+crc4=`$CRCSUM $TMPFILE` -+echo $CRCSUM after e2fsck $crc4 >> $OUT -+features="$($DUMPE2FS -h $TMPFILE 2> /dev/null | grep 'Filesystem features:')" -+if [ "$(echo "${features}" | grep "metadata_csum" -c)" -lt 1 ] || [ "$(echo "${features}" | grep 64bit -c)" -lt 1 ]; then -+ echo "FS features: ${features}" >> $OUT -+ echo "Should have 64bit and metadata_csum set" >> $OUT -+ fail=1 -+fi -+$FSCK -f -n $TMPFILE >> $OUT 2>&1 || fail=1 -+ -+echo roll back e2fsck/tune2fs/resize2fs >> $OUT -+$E2UNDO $TDB_FILE.1 $TMPFILE >> $OUT 2>&1 -+crc1_2=`$CRCSUM $TMPFILE` -+echo $CRCSUM after e2undo e2fsck/tune2fs/resize2fs $crc1_2 >> $OUT -+features="$($DUMPE2FS -h $TMPFILE 2> /dev/null | grep 'Filesystem features:')" -+if [ "$(echo "${features}" | grep "metadata_csum" -c)" -gt 0 ] || [ "$(echo "${features}" | grep 64bit -c)" -gt 0 ]; then -+ echo "FS features: ${features}" >> $OUT -+ echo "Should not have 64bit or metadata_csum set" >> $OUT -+ fail=1 -+fi -+$FSCK -f -n $TMPFILE >> $OUT 2>&1 || fail=1 -+ -+echo roll back mke2fs >> $OUT -+$E2UNDO $TDB_FILE.0 $TMPFILE >> $OUT 2>&1 -+crc0_2=`$CRCSUM $TMPFILE` -+echo $CRCSUM after e2undo mke2fs $crc0_2 >> $OUT -+features="$($DUMPE2FS -h $TMPFILE 2> /dev/null | grep 'Filesystem features:')" -+if [ -n "${features}" ]; then -+ echo "FS features: ${features}" >> $OUT -+ echo "Should not have any features set" >> $OUT -+ fail=1 -+fi -+$FSCK -f -n $TMPFILE >> $OUT 2>&1 && fail=1 -+ -+if [ $fail -eq 0 ] && [ $crc0 = $crc0_2 ] && [ $crc1 = $crc1_2 ]; then -+ echo "$test_name: $test_description: ok" -+ touch $test_name.ok -+else -+ ln -f $test_name.log $test_name.failed -+ echo "$test_name: $test_description: failed" -+fi -+rm -f $TDB_FILE.0 $TDB_FILE.1 $TMPFILE $CONF -+fi -diff --git a/tests/u_revert_all_onefile/script b/tests/u_revert_all_onefile/script -new file mode 100644 -index 0000000..27b3b23 ---- /dev/null -+++ b/tests/u_revert_all_onefile/script -@@ -0,0 +1,100 @@ -+test_description="convert fs to 64bit,metadata_csum and revert as one undo file" -+if test -x $RESIZE2FS_EXE -a -x $E2UNDO_EXE; then -+ -+TDB_FILE=${TMPDIR:-/tmp}/resize2fs-$(basename $TMPFILE).e2undo -+OUT=$test_name.log -+rm -f $TDB_FILE >/dev/null 2>&1 -+fail=0 -+ -+echo convert fs to 64bit,metadata_csum and revert both changes as one undo file > $OUT -+ -+dd if=/dev/zero of=$TMPFILE bs=1k count=512 > /dev/null 2>&1 -+crc0=`$CRCSUM $TMPFILE` -+echo $CRCSUM before mke2fs $crc0 >> $OUT -+ -+CONF=$TMPFILE.conf -+cat > $CONF << ENDL -+[fs_types] -+ ext4h = { -+ features = has_journal,extent,huge_file,flex_bg,uninit_bg,dir_nlink,extra_isize,sparse_super,filetype,dir_index,ext_attr,resize_inode -+ blocksize = 4096 -+ inode_size = 256 -+ make_hugefiles = true -+ hugefiles_dir = / -+ hugefiles_slack = 0 -+ hugefiles_name = aaaaa -+ hugefiles_digits = 4 -+ hugefiles_size = 1M -+ zero_hugefiles = false -+ } -+ENDL -+ -+echo mke2fs -q -F -o Linux -T ext4h -O ^metadata_csum,^64bit -E lazy_itable_init=1 -b 4096 -z $TDB_FILE.0 $TMPFILE 524288 >> $OUT -+MKE2FS_CONFIG=$CONF $MKE2FS -q -F -o Linux -T ext4h -O ^metadata_csum,^64bit -E lazy_itable_init=1 -b 4096 -z $TDB_FILE.0 $TMPFILE >> $OUT 2>&1 -+crc1=`$CRCSUM $TMPFILE` -+echo $CRCSUM after mke2fs $crc1 >> $OUT -+features="$($DUMPE2FS -h $TMPFILE 2> /dev/null | grep 'Filesystem features:')" -+if [ "$(echo "${features}" | grep "metadata_csum" -c)" -gt 0 ] || [ "$(echo "${features}" | grep 64bit -c)" -gt 0 ]; then -+ echo "FS features: ${features}" >> $OUT -+ echo "Should not have 64bit or metadata_csum set" >> $OUT -+ fail=1 -+fi -+$FSCK -f -n $TMPFILE >> $OUT 2>&1 || fail=1 -+ -+echo using resize2fs to test e2undo >> $OUT -+$RESIZE2FS -z $TDB_FILE.0 -b $TMPFILE >> $OUT 2>&1 -+crc2=`$CRCSUM $TMPFILE` -+echo $CRCSUM after resize2fs $crc2 >> $OUT -+features="$($DUMPE2FS -h $TMPFILE 2> /dev/null | grep 'Filesystem features:')" -+if [ "$(echo "${features}" | grep "metadata_csum" -c)" -gt 0 ] || [ "$(echo "${features}" | grep 64bit -c)" -lt 1 ]; then -+ echo "FS features: ${features}" >> $OUT -+ echo "Should have 64bit but not metadata_csum set" >> $OUT -+ fail=1 -+fi -+$FSCK -f -n $TMPFILE >> $OUT 2>&1 || fail=1 -+ -+echo using tune2fs to test e2undo >> $OUT -+$TUNE2FS -O metadata_csum -z $TDB_FILE.0 $TMPFILE >> $OUT 2>&1 -+crc3=`$CRCSUM $TMPFILE` -+echo $CRCSUM after tune2fs $crc3 >> $OUT -+features="$($DUMPE2FS -h $TMPFILE 2> /dev/null | grep 'Filesystem features:')" -+if [ "$(echo "${features}" | grep "metadata_csum" -c)" -lt 1 ] || [ "$(echo "${features}" | grep 64bit -c)" -lt 1 ]; then -+ echo "FS features: ${features}" >> $OUT -+ echo "Should have 64bit and metadata_csum set" >> $OUT -+ fail=1 -+fi -+$FSCK -f -n $TMPFILE >> $OUT 2>&1 || fail=1 -+ -+echo using e2fsck to test e2undo >> $OUT -+$FSCK -f -y -D -z $TDB_FILE.0 $TMPFILE >> $OUT 2>&1 -+crc4=`$CRCSUM $TMPFILE` -+echo $CRCSUM after e2fsck $crc4 >> $OUT -+features="$($DUMPE2FS -h $TMPFILE 2> /dev/null | grep 'Filesystem features:')" -+if [ "$(echo "${features}" | grep "metadata_csum" -c)" -lt 1 ] || [ "$(echo "${features}" | grep 64bit -c)" -lt 1 ]; then -+ echo "FS features: ${features}" >> $OUT -+ echo "Should have 64bit and metadata_csum set" >> $OUT -+ fail=1 -+fi -+$FSCK -f -n $TMPFILE >> $OUT 2>&1 || fail=1 -+ -+echo roll back e2fsck/tune2fs/resize2fs/mke2fs >> $OUT -+$E2UNDO $TDB_FILE.0 $TMPFILE >> $OUT 2>&1 -+crc0_2=`$CRCSUM $TMPFILE` -+echo $CRCSUM after e2undo e2fsck/tune2fs/resize2fs/mke2fs $crc1_2 >> $OUT -+features="$($DUMPE2FS -h $TMPFILE 2> /dev/null | grep 'Filesystem features:')" -+if [ -n "${features}" ]; then -+ echo "FS features: ${features}" >> $OUT -+ echo "Should not have any features set" >> $OUT -+ fail=1 -+fi -+$FSCK -f -n $TMPFILE >> $OUT 2>&1 && fail=1 -+ -+if [ $fail -eq 0 ] && [ $crc0 = $crc0_2 ]; then -+ echo "$test_name: $test_description: ok" -+ touch $test_name.ok -+else -+ ln -f $test_name.log $test_name.failed -+ echo "$test_name: $test_description: failed" -+fi -+rm -f $TDB_FILE.0 $TDB_FILE.1 $TMPFILE $CONF -+fi -diff --git a/tests/u_revert_upgrade_to_64bitmcsum/script b/tests/u_revert_upgrade_to_64bitmcsum/script -new file mode 100644 -index 0000000..6120d00 ---- /dev/null -+++ b/tests/u_revert_upgrade_to_64bitmcsum/script -@@ -0,0 +1,136 @@ -+test_description="convert fs to 64bit,metadata_csum and revert both changes" -+if test -x $RESIZE2FS_EXE -a -x $E2UNDO_EXE; then -+ -+TDB_FILE=${TMPDIR:-/tmp}/resize2fs-$(basename $TMPFILE).e2undo -+OUT=$test_name.log -+rm -f $TDB_FILE >/dev/null 2>&1 -+fail=0 -+ -+echo convert fs to 64bit,metadata_csum and revert both changes > $OUT -+ -+dd if=/dev/zero of=$TMPFILE bs=1k count=512 > /dev/null 2>&1 -+crc0=`$CRCSUM $TMPFILE` -+echo $CRCSUM before mke2fs $crc0 >> $OUT -+ -+CONF=$TMPFILE.conf -+cat > $CONF << ENDL -+[fs_types] -+ ext4h = { -+ features = has_journal,extent,huge_file,flex_bg,uninit_bg,dir_nlink,extra_isize,sparse_super,filetype,dir_index,ext_attr,resize_inode -+ blocksize = 4096 -+ inode_size = 256 -+ make_hugefiles = true -+ hugefiles_dir = / -+ hugefiles_slack = 0 -+ hugefiles_name = aaaaa -+ hugefiles_digits = 4 -+ hugefiles_size = 1M -+ zero_hugefiles = false -+ } -+ENDL -+ -+echo mke2fs -q -F -o Linux -T ext4h -O ^metadata_csum,^64bit -E lazy_itable_init=1 -b 4096 -z $TDB_FILE.0 $TMPFILE 524288 >> $OUT -+MKE2FS_CONFIG=$CONF $MKE2FS -q -F -o Linux -T ext4h -O ^metadata_csum,^64bit -E lazy_itable_init=1 -b 4096 -z $TDB_FILE.0 $TMPFILE >> $OUT 2>&1 -+crc1=`$CRCSUM $TMPFILE` -+echo $CRCSUM after mke2fs $crc1 >> $OUT -+features="$($DUMPE2FS -h $TMPFILE 2> /dev/null | grep 'Filesystem features:')" -+if [ "$(echo "${features}" | grep "metadata_csum" -c)" -gt 0 ] || [ "$(echo "${features}" | grep 64bit -c)" -gt 0 ]; then -+ echo "FS features: ${features}" >> $OUT -+ echo "Should not have 64bit or metadata_csum set" >> $OUT -+ fail=1 -+fi -+$FSCK -f -n $TMPFILE >> $OUT 2>&1 || fail=1 -+ -+echo using resize2fs to test e2undo >> $OUT -+$RESIZE2FS -z $TDB_FILE.1 -b $TMPFILE >> $OUT 2>&1 -+crc2=`$CRCSUM $TMPFILE` -+echo $CRCSUM after resize2fs $crc2 >> $OUT -+features="$($DUMPE2FS -h $TMPFILE 2> /dev/null | grep 'Filesystem features:')" -+if [ "$(echo "${features}" | grep "metadata_csum" -c)" -gt 0 ] || [ "$(echo "${features}" | grep 64bit -c)" -lt 1 ]; then -+ echo "FS features: ${features}" >> $OUT -+ echo "Should have 64bit but not metadata_csum set" >> $OUT -+ fail=1 -+fi -+$FSCK -f -n $TMPFILE >> $OUT 2>&1 || fail=1 -+ -+echo using tune2fs to test e2undo >> $OUT -+$TUNE2FS -O metadata_csum -z $TDB_FILE.2 $TMPFILE >> $OUT 2>&1 -+crc3=`$CRCSUM $TMPFILE` -+echo $CRCSUM after tune2fs $crc3 >> $OUT -+features="$($DUMPE2FS -h $TMPFILE 2> /dev/null | grep 'Filesystem features:')" -+if [ "$(echo "${features}" | grep "metadata_csum" -c)" -lt 1 ] || [ "$(echo "${features}" | grep 64bit -c)" -lt 1 ]; then -+ echo "FS features: ${features}" >> $OUT -+ echo "Should have 64bit and metadata_csum set" >> $OUT -+ fail=1 -+fi -+$FSCK -f -n $TMPFILE >> $OUT 2>&1 || fail=1 -+ -+echo using e2fsck to test e2undo >> $OUT -+$FSCK -f -y -D -z $TDB_FILE.3 $TMPFILE >> $OUT 2>&1 -+crc4=`$CRCSUM $TMPFILE` -+echo $CRCSUM after e2fsck $crc4 >> $OUT -+features="$($DUMPE2FS -h $TMPFILE 2> /dev/null | grep 'Filesystem features:')" -+if [ "$(echo "${features}" | grep "metadata_csum" -c)" -lt 1 ] || [ "$(echo "${features}" | grep 64bit -c)" -lt 1 ]; then -+ echo "FS features: ${features}" >> $OUT -+ echo "Should have 64bit and metadata_csum set" >> $OUT -+ fail=1 -+fi -+$FSCK -f -n $TMPFILE >> $OUT 2>&1 || fail=1 -+ -+echo roll back e2fsck >> $OUT -+$E2UNDO $TDB_FILE.3 $TMPFILE >> $OUT 2>&1 -+crc3_2=`$CRCSUM $TMPFILE` -+echo $CRCSUM after e2undo e2fsck $crc3_2 >> $OUT -+features="$($DUMPE2FS -h $TMPFILE 2> /dev/null | grep 'Filesystem features:')" -+if [ "$(echo "${features}" | grep "metadata_csum" -c)" -lt 1 ] || [ "$(echo "${features}" | grep 64bit -c)" -lt 1 ]; then -+ echo "FS features: ${features}" >> $OUT -+ echo "Should have 64bit and metadata_csum set" >> $OUT -+ fail=1 -+fi -+$FSCK -f -n $TMPFILE >> $OUT 2>&1 || fail=1 -+ -+echo roll back tune2fs >> $OUT -+$E2UNDO $TDB_FILE.2 $TMPFILE >> $OUT 2>&1 -+crc2_2=`$CRCSUM $TMPFILE` -+echo $CRCSUM after e2undo tune2fs $crc2_2 >> $OUT -+features="$($DUMPE2FS -h $TMPFILE 2> /dev/null | grep 'Filesystem features:')" -+if [ "$(echo "${features}" | grep "metadata_csum" -c)" -gt 0 ] || [ "$(echo "${features}" | grep 64bit -c)" -lt 1 ]; then -+ echo "FS features: ${features}" >> $OUT -+ echo "Should have 64bit but not metadata_csum set" >> $OUT -+ fail=1 -+fi -+$FSCK -f -n $TMPFILE >> $OUT 2>&1 || fail=1 -+ -+echo roll back resize2fs >> $OUT -+$E2UNDO $TDB_FILE.1 $TMPFILE >> $OUT 2>&1 -+crc1_2=`$CRCSUM $TMPFILE` -+echo $CRCSUM after e2undo resize2fs $crc1_2 >> $OUT -+features="$($DUMPE2FS -h $TMPFILE 2> /dev/null | grep 'Filesystem features:')" -+if [ "$(echo "${features}" | grep "metadata_csum" -c)" -gt 0 ] || [ "$(echo "${features}" | grep 64bit -c)" -gt 0 ]; then -+ echo "FS features: ${features}" >> $OUT -+ echo "Should not have 64bit or metadata_csum set" >> $OUT -+ fail=1 -+fi -+$FSCK -f -n $TMPFILE >> $OUT 2>&1 || fail=1 -+ -+echo roll back mke2fs >> $OUT -+$E2UNDO $TDB_FILE.0 $TMPFILE >> $OUT 2>&1 -+crc0_2=`$CRCSUM $TMPFILE` -+echo $CRCSUM after e2undo mke2fs $crc0_2 >> $OUT -+features="$($DUMPE2FS -h $TMPFILE 2> /dev/null | grep 'Filesystem features:')" -+if [ -n "${features}" ]; then -+ echo "FS features: ${features}" >> $OUT -+ echo "Should not have any features set" >> $OUT -+ fail=1 -+fi -+$FSCK -f -n $TMPFILE >> $OUT 2>&1 && fail=1 -+ -+if [ $fail -eq 0 ] && [ $crc0 = $crc0_2 ] && [ $crc1 = $crc1_2 ] && [ $crc2 = $crc2_2 ] && [ $crc3 = $crc3_2 ]; then -+ echo "$test_name: $test_description: ok" -+ touch $test_name.ok -+else -+ ln -f $test_name.log $test_name.failed -+ echo "$test_name: $test_description: failed" -+fi -+rm -f $TDB_FILE.0 $TDB_FILE.1 $TDB_FILE.2 $TDB_FILE.3 $TMPFILE $CONF -+fi -diff --git a/tests/u_tune2fs/script b/tests/u_tune2fs/script -index a443f5a..aa5f379 100644 ---- a/tests/u_tune2fs/script -+++ b/tests/u_tune2fs/script -@@ -1,7 +1,7 @@ - test_description="e2undo with tune2fs" - if test -x $E2UNDO_EXE; then - --E2FSPROGS_UNDO_DIR=/tmp -+E2FSPROGS_UNDO_DIR=${TMPDIR:-/tmp} - export E2FSPROGS_UNDO_DIR - TDB_FILE=$E2FSPROGS_UNDO_DIR/tune2fs-$(basename $TMPFILE).e2undo - OUT=$test_name.log -@@ -19,7 +19,7 @@ $TUNE2FS -I 256 $TMPFILE >> $OUT 2>&1 - new_crc=`$CRCSUM $TMPFILE` - echo $CRCSUM after tune2fs $new_crc >> $OUT - --$E2UNDO_EXE $TDB_FILE $TMPFILE >> $OUT 2>&1 -+$E2UNDO $TDB_FILE $TMPFILE >> $OUT 2>&1 - new_crc=`$CRCSUM $TMPFILE` - echo $CRCSUM after e2undo $new_crc >> $OUT - -diff --git a/tests/u_tune2fs_opt/script b/tests/u_tune2fs_opt/script -new file mode 100644 -index 0000000..c4810b9 ---- /dev/null -+++ b/tests/u_tune2fs_opt/script -@@ -0,0 +1,32 @@ -+test_description="e2undo with tune2fs -z" -+if test -x $E2UNDO_EXE; then -+ -+TDB_FILE=${TMPDIR:-/tmp}/tune2fs-$(basename $TMPFILE).e2undo -+OUT=$test_name.log -+rm -f $TDB_FILE >/dev/null 2>&1 -+ -+dd if=/dev/zero of=$TMPFILE bs=1k count=512 > /dev/null 2>&1 -+ -+echo mke2fs -q -F -o Linux -T ext4 -O ^metadata_csum,64bit -E lazy_itable_init=1 -b 1024 $TMPFILE > $OUT -+$MKE2FS -q -F -o Linux -T ext4 -O ^metadata_csum,64bit -E lazy_itable_init=1 -b 1024 $TMPFILE >> $OUT 2>&1 -+crc0=`$CRCSUM $TMPFILE` -+echo $CRCSUM before tune2fs $crc0 >> $OUT -+ -+echo using tune2fs to test e2undo >> $OUT -+$TUNE2FS -O metadata_csum -z $TDB_FILE $TMPFILE >> $OUT 2>&1 -+crc1=`$CRCSUM $TMPFILE` -+echo $CRCSUM after tune2fs $crc1 >> $OUT -+ -+$E2UNDO $TDB_FILE $TMPFILE >> $OUT 2>&1 -+crc2=`$CRCSUM $TMPFILE` -+echo $CRCSUM after e2undo $crc2 >> $OUT -+ -+if [ $crc0 = $crc2 ] && [ $crc1 != $crc2 ]; then -+ echo "$test_name: $test_description: ok" -+ touch $test_name.ok -+else -+ ln -f $test_name.log $test_name.failed -+ echo "$test_name: $test_description: failed" -+fi -+rm -f $TDB_FILE $TMPFILE -+fi -diff --git a/tests/u_undo_undo/script b/tests/u_undo_undo/script -new file mode 100644 -index 0000000..726a453 ---- /dev/null -+++ b/tests/u_undo_undo/script -@@ -0,0 +1,54 @@ -+test_description="undo e2undo" -+if test -x $E2UNDO_EXE; then -+ -+TDB_FILE=${TMPDIR:-/tmp}/e2fsck-$(basename $TMPFILE).e2undo -+TDB_FILE2=${TMPDIR:-/tmp}/e2undo-$(basename $TMPFILE).e2undo -+OUT=$test_name.log -+rm -f $TDB_FILE $TDB_FILE2 >/dev/null 2>&1 -+ -+dd if=/dev/zero of=$TMPFILE bs=1k count=512 > /dev/null 2>&1 -+ -+echo mke2fs -q -F -o Linux -T ext4 -O ^metadata_csum,64bit -E lazy_itable_init=1 -b 1024 $TMPFILE > $OUT -+$MKE2FS -q -F -o Linux -T ext4 -O ^metadata_csum,64bit -E lazy_itable_init=1 -b 1024 $TMPFILE >> $OUT 2>&1 -+crc0=`$CRCSUM $TMPFILE` -+echo $CRCSUM before e2fsck $crc0 >> $OUT -+ -+echo using e2fsck to test e2undo >> $OUT -+$FSCK -f -y -D -z $TDB_FILE $TMPFILE >> $OUT 2>&1 -+crc1=`$CRCSUM $TMPFILE` -+echo $CRCSUM after e2fsck $crc1 >> $OUT -+ -+echo e2undo the e2fsck >> $OUT -+$E2UNDO -z $TDB_FILE2 $TDB_FILE $TMPFILE >> $OUT 2>&1 -+crc2=`$CRCSUM $TMPFILE` -+echo $CRCSUM after e2undo $crc2 >> $OUT -+ -+echo e2undo the e2undo >> $OUT -+$E2UNDO $TDB_FILE2 $TMPFILE >> $OUT 2>&1 -+crc3=`$CRCSUM $TMPFILE` -+echo $CRCSUM after e2undo $crc3 >> $OUT -+ -+echo e2undo the e2undo the e2undo >> $OUT -+$E2UNDO $TDB_FILE $TMPFILE >> $OUT 2>&1 -+crc4=`$CRCSUM $TMPFILE` -+echo $CRCSUM after e2undo $crc4 >> $OUT -+ -+$E2UNDO -h $TDB_FILE $TMPFILE >> $OUT 2>&1 -+$E2UNDO -h $TDB_FILE2 $TMPFILE >> $OUT 2>&1 -+ -+$E2UNDO -z $TDB_FILE2 $TDB_FILE2 $TMPFILE >> $OUT 2>&1 -+ -+crc5=`$CRCSUM $TMPFILE` -+echo $CRCSUM after failed e2undo $crc5 >> $OUT -+ -+echo $crc0 $crc1 $crc2 $crc3 $crc4 $crc5 >> $OUT -+ -+if [ $crc0 = $crc2 ] && [ $crc2 = $crc4 ] && [ $crc5 = $crc4 ] && [ $crc1 = $crc3 ] && [ $crc1 != $crc2 ]; then -+ echo "$test_name: $test_description: ok" -+ touch $test_name.ok -+else -+ ln -f $test_name.log $test_name.failed -+ echo "$test_name: $test_description: failed" -+fi -+rm -f $TDB_FILE $TDB_FILE2 $TMPFILE -+fi -diff --git a/tests/u_wrong_fs/script b/tests/u_wrong_fs/script -new file mode 100644 -index 0000000..dbf0d6b ---- /dev/null -+++ b/tests/u_wrong_fs/script -@@ -0,0 +1,36 @@ -+test_description="e2undo on the wrong fs" -+if test -x $E2UNDO_EXE; then -+ -+TDB_FILE=${TMPDIR:-/tmp}/tune2fs-$(basename $TMPFILE).e2undo -+OUT=$test_name.log -+rm -f $TDB_FILE >/dev/null 2>&1 -+ -+dd if=/dev/zero of=$TMPFILE bs=1k count=512 > /dev/null 2>&1 -+ -+echo mke2fs -q -F -o Linux -T ext4 -O ^metadata_csum,64bit -E lazy_itable_init=1 -b 1024 $TMPFILE > $OUT -+$MKE2FS -q -F -o Linux -T ext4 -O ^metadata_csum,64bit -E lazy_itable_init=1 -b 1024 $TMPFILE >> $OUT 2>&1 -+crc0=`$CRCSUM $TMPFILE` -+echo $CRCSUM before tune2fs $crc0 >> $OUT -+ -+echo using tune2fs to test e2undo >> $OUT -+$TUNE2FS -O metadata_csum -z $TDB_FILE $TMPFILE >> $OUT 2>&1 -+crc1=`$CRCSUM $TMPFILE` -+echo $CRCSUM after tune2fs $crc1 >> $OUT -+ -+$MKE2FS -q -F -o Linux -T ext4 -O ^metadata_csum,64bit -E lazy_itable_init=1 -b 1024 $TMPFILE >> $OUT 2>&1 -+crc2=`$CRCSUM $TMPFILE` -+echo $CRCSUM after re-mke2fs $crc2 >> $OUT -+ -+$E2UNDO $TDB_FILE $TMPFILE >> $OUT 2>&1 -+crc3=`$CRCSUM $TMPFILE` -+echo $CRCSUM after e2undo $crc3 >> $OUT -+ -+if [ $crc3 = $crc2 ] && [ $crc2 != $crc1 ]; then -+ echo "$test_name: $test_description: ok" -+ touch $test_name.ok -+else -+ ln -f $test_name.log $test_name.failed -+ echo "$test_name: $test_description: failed" -+fi -+rm -f $TDB_FILE $TMPFILE -+fi -diff --git a/util/Makefile.in b/util/Makefile.in -index d235fff..96117d9 100644 ---- a/util/Makefile.in -+++ b/util/Makefile.in -@@ -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 - -@@ -52,7 +53,7 @@ tarballs: gen-tarball - - clean:: - $(RM) -f $(PROGS) \#* *.s *.o *.a *~ core *.tar.gz gen-tarball \ -- copy-sparse dirpaths.h -+ copy-sparse dirpaths.h install-symlink - - mostlyclean: clean - -diff --git a/util/android_config.h b/util/android_config.h -new file mode 100644 -index 0000000..51db487 ---- /dev/null -+++ b/util/android_config.h -@@ -0,0 +1,51 @@ -+/* work around bug in AndroidConfig.h */ -+#ifdef HAVE_MALLOC_H -+#undef HAVE_MALLOC_H -+#define HAVE_MALLOC_H 1 -+#endif -+ -+#define ROOT_SYSCONFDIR "/etc" -+ -+#define DISABLE_BACKTRACE 1 -+#define HAVE_DIRENT_H 1 -+#define HAVE_ERRNO_H 1 -+#define HAVE_EXT2_IOCTLS 1 -+#define HAVE_FALLOCATE 1 -+#define HAVE_GETOPT_H 1 -+#define HAVE_GETPAGESIZE 1 -+#define HAVE_GETPWUID_R 1 -+#define HAVE_INTPTR_T 1 -+#define HAVE_INTTYPES_H 1 -+#define HAVE_LINUX_FD_H 1 -+#define HAVE_LSEEK64 1 -+#define HAVE_LSEEK64_PROTOTYPE 1 -+#define HAVE_MMAP 1 -+#define HAVE_NETINET_IN_H 1 -+#define HAVE_NET_IF_H 1 -+#define HAVE_POSIX_MEMALIGN 1 -+#define HAVE_PREAD 1 -+#define HAVE_PREAD64 1 -+#define HAVE_PWRITE 1 -+#define HAVE_PWRITE64 1 -+#define HAVE_SETJMP_H 1 -+#define HAVE_SNPRINTF 1 -+#define HAVE_STDLIB_H 1 -+#define HAVE_STRCASECMP 1 -+#define HAVE_STRDUP 1 -+#define HAVE_STRINGS_H 1 -+#define HAVE_STRPTIME 1 -+#define HAVE_SYSCONF 1 -+#define HAVE_SYS_IOCTL_H 1 -+#define HAVE_SYS_MMAN_H 1 -+#define HAVE_SYS_MOUNT_H 1 -+#define HAVE_SYS_PARAM_H 1 -+#define HAVE_SYS_PRCTL_H 1 -+#define HAVE_SYS_RESOURCE_H 1 -+#define HAVE_SYS_SELECT_H 1 -+#define HAVE_SYS_STAT_H 1 -+#define HAVE_SYS_TIME_H 1 -+#define HAVE_SYS_TYPES_H 1 -+#define HAVE_SYS_WAIT_H 1 -+#define HAVE_TYPE_SSIZE_T 1 -+#define HAVE_UNISTD_H 1 -+#define HAVE_UTIME_H 1 -diff --git a/util/android_types.h b/util/android_types.h -new file mode 100644 -index 0000000..2b3e78f ---- /dev/null -+++ b/util/android_types.h -@@ -0,0 +1,39 @@ -+/* -+ * If linux/types.h is already been included, assume it has defined -+ * everything we need. (cross fingers) Other header files may have -+ * also defined the types that we need. -+ */ -+#if (!defined(_LINUX_TYPES_H) && !defined(_BLKID_TYPES_H) && \ -+ !defined(_EXT2_TYPES_H)) -+#define _EXT2_TYPES_H -+ -+typedef unsigned char __u8; -+typedef __signed__ char __s8; -+typedef unsigned short __u16; -+typedef __signed__ short __s16; -+typedef unsigned int __u32; -+typedef __signed__ int __s32; -+typedef unsigned long long __u64; -+typedef __signed__ long long __s64; -+#endif -+ -+/* endian checking stuff */ -+#ifndef EXT2_ENDIAN_H_ -+#define EXT2_ENDIAN_H_ -+ -+#ifdef __CHECKER__ -+#define __bitwise __attribute__((bitwise)) -+#define __force __attribute__((force)) -+#else -+#define __bitwise -+#define __force -+#endif -+ -+typedef __u16 __bitwise __le16; -+typedef __u32 __bitwise __le32; -+typedef __u64 __bitwise __le64; -+typedef __u16 __bitwise __be16; -+typedef __u32 __bitwise __be32; -+typedef __u64 __bitwise __be64; -+ -+#endif /* EXT2_ENDIAN_H_ */ -diff --git a/util/gen-android-files b/util/gen-android-files -new file mode 100755 -index 0000000..0c1888d ---- /dev/null -+++ b/util/gen-android-files -@@ -0,0 +1,61 @@ -+#!/bin/sh -+ -+ANDROID_GENERATED_FILES="lib/ext2fs/ext2_err.c lib/ext2fs/ext2_err.h \ -+ lib/ss/ss_err.c lib/ss/ss_err.h lib/support/prof_err.c \ -+ lib/support/prof_err.h \ -+ lib/blkid/blkid_types.h lib/uuid/uuid_types.h \ -+ lib/ext2fs/ext2_types.h lib/config.h lib/blkid/blkid.h \ -+ lib/uuid/uuid.h lib/ext2fs/crc32c_table.h misc/default_profile.c \ -+ lib/ss/std_rqs.c debugfs/debug_cmds.c debugfs/ro_debug_cmds.c \ -+ debugfs/extent_cmds.c debugfs/e2freefrag.c debugfs/create_inode.c \ -+ debugfs/recovery.c debugfs/revoke.c \ -+ MODULE_LICENSE_GPL" -+ -+SS_DIR=$(pwd)/lib/ss -+MK_CMDS=/tmp/mk_cmds$$.sh -+ -+sed -e "s;@SS_DIR@;$SS_DIR;" < $SS_DIR/mk_cmds.sh.in \ -+ | sed -e "s/@AWK@/awk/" | sed -e "s/@SED@/sed/" > $MK_CMDS -+ -+sed -e "s/@E2FSPROGS_VERSION@/$(git describe)/" < lib/ext2fs/ext2_err.et.in > lib/ext2fs/ext2_err.et -+ -+for i in lib/ss/ss_err lib/support/prof_err lib/ext2fs/ext2_err -+do -+ rm -f $i.c $i.h -+ awk -f lib/et/et_c.awk outfile=$i.c outfn=$(basename $i.c) $i.et -+ awk -f lib/et/et_h.awk outfile=$i.h outfn=$(basename $i.h) $i.et -+done -+ -+for i in lib/ss/std_rqs debugfs/debug_cmds debugfs/ro_debug_cmds \ -+ debugfs/extent_cmds -+do -+ /bin/sh $MK_CMDS $i.ct -+ mv -f $(basename $i).c $i.c -+done -+ -+rm -f $MK_CMDS -+ -+cp lib/blkid/blkid.h.in lib/blkid/blkid.h -+cp lib/uuid/uuid.h.in lib/uuid/uuid.h -+cp util/android_types.h lib/ext2fs/ext2_types.h -+cp util/android_types.h lib/blkid/blkid_types.h -+cp util/android_types.h lib/uuid/uuid_types.h -+cp util/android_config.h lib/config.h -+cp misc/e2freefrag.c misc/create_inode.c debugfs/ -+cp e2fsck/recovery.c e2fsck/revoke.c debugfs/ -+ -+gcc -o gen_crc32ctable lib/ext2fs/gen_crc32ctable.c -+./gen_crc32ctable > lib/ext2fs/crc32c_table.h -+ -+awk -f misc/profile-to-c.awk < misc/mke2fs.conf.in > misc/default_profile.c -+ -+rm -f ./gen_crc32table ./gen_crc32ctable lib/ext2fs/ext2_err.et -+ -+touch MODULE_LICENSE_GPL -+ -+git add -f $ANDROID_GENERATED_FILES -+if test -f COPYING -+then -+ git mv COPYING NOTICE -+fi -+git commit -m "Update generated files for Android" -diff --git a/util/static-analysis-cleanup b/util/static-analysis-cleanup -new file mode 100644 -index 0000000..6749259 ---- /dev/null -+++ b/util/static-analysis-cleanup -@@ -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 -diff --git a/util/subst.c b/util/subst.c -index 91f6d44..f36adb4 100644 ---- a/util/subst.c -+++ b/util/subst.c -@@ -24,6 +24,9 @@ - #include - #include - #include -+#ifdef HAVE_SYS_TIME_H -+#include -+#endif - - #ifdef HAVE_GETOPT_H - #include -@@ -444,6 +447,8 @@ int main(int argc, char **argv) - } - if (old) - fclose(old); -+ if (newfn) -+ free(newfn); - return (0); - } - -diff --git a/util/subst.conf.in b/util/subst.conf.in -index 64fde7a..0e074d8 100644 ---- a/util/subst.conf.in -+++ b/util/subst.conf.in -@@ -18,5 +18,3 @@ $prefix @prefix@ - # Enable the documentation for the journal device mke2fs, tune2fs, and - # e2fsck's man page - JDEV --# Enable documentation for quota feature in mke2fs --QUOTA_MAN_COMMENT @QUOTA_MAN_COMMENT@ -diff --git a/util/symlinks.c b/util/symlinks.c -index abb33f8..600effa 100644 ---- a/util/symlinks.c -+++ b/util/symlinks.c -@@ -1,6 +1,10 @@ - #define _FILE_OFFSET_BITS 64 -+#ifndef _LARGEFILE_SOURCE - #define _LARGEFILE_SOURCE -+#endif -+#ifndef _LARGEFILE64_SOURCE - #define _LARGEFILE64_SOURCE -+#endif - - #include - #ifndef _POSIX_SOURCE -@@ -166,7 +170,7 @@ static void fix_symlink (char *path, dev_t my_dev) - struct stat stbuf, lstbuf; - int c, fix_abs = 0, fix_messy = 0, fix_long = 0; - -- if ((c = readlink(path, lpath, sizeof(lpath))) == -1) { -+ if ((c = readlink(path, lpath, sizeof(lpath) - 1)) == -1) { - perror(path); - return; - } -diff --git a/version.h b/version.h -index 66fe254..a9c47e3 100644 ---- 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.13" --#define E2FSPROGS_DATE "17-May-2015" -+#define E2FSPROGS_VERSION "1.43-WIP" -+#define E2FSPROGS_DATE "18-May-2015" diff -Nru e2fsprogs-1.42.13/debian/patches/format e2fsprogs-1.42.13/debian/patches/format --- e2fsprogs-1.42.13/debian/patches/format 2014-07-26 21:54:09.000000000 +0000 +++ e2fsprogs-1.42.13/debian/patches/format 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -3.0 (quilt) diff -Nru e2fsprogs-1.42.13/debian/patches/series e2fsprogs-1.42.13/debian/patches/series --- e2fsprogs-1.42.13/debian/patches/series 1970-01-01 00:00:00.000000000 +0000 +++ e2fsprogs-1.42.13/debian/patches/series 2015-11-29 18:48:29.000000000 +0000 @@ -0,0 +1,2 @@ +01-20151129.patch +02-enable-e4encrypt.patch