mirror of https://github.com/vitalif/e2fsprogs
Compare commits
19 Commits
debian-1.4
...
master
Author | SHA1 | Date |
---|---|---|
Vitaliy Filippov | 6e4fa6e281 | |
Vitaliy Filippov | b331d80fba | |
Vitaliy Filippov | f99c7a2e12 | |
Vitaliy Filippov | b9b963d427 | |
Vitaliy Filippov | f58c260dc4 | |
Vitaliy Filippov | 152890aa45 | |
Vitaliy Filippov | 63039f4bac | |
Vitaliy Filippov | 7e0136332c | |
Vitaliy Filippov | b3782b2e5b | |
Vitaliy Filippov | 460c0af190 | |
Vitaliy Filippov | 2051d63a83 | |
Theodore Ts'o | e703ba4b42 | |
Theodore Ts'o | d6cad379eb | |
Theodore Ts'o | 4e52870eeb | |
Theodore Ts'o | 047d5d774f | |
Theodore Ts'o | a7b27f11a1 | |
Theodore Ts'o | 8d7a63921f | |
Theodore Ts'o | f3bc1561c8 | |
Theodore Ts'o | 254195627f |
|
@ -5,6 +5,7 @@ build.static
|
|||
FILES
|
||||
^core
|
||||
*~
|
||||
patches
|
||||
Makefile
|
||||
*.bak
|
||||
*.diff
|
||||
|
@ -160,6 +161,8 @@ misc/e2initrd_helper
|
|||
misc/e2label.8
|
||||
misc/e2undo
|
||||
misc/e2undo.8
|
||||
misc/e2patch
|
||||
misc/e2patch.8
|
||||
misc/e4defrag
|
||||
misc/e4defrag.8
|
||||
misc/ext4.5
|
||||
|
|
|
@ -68,8 +68,8 @@ pkgconfigdir = $(libdir)/pkgconfig
|
|||
@ifGNUmake@ endif
|
||||
@ifGNUmake@ endif
|
||||
|
||||
@ifNotGNUmake@ CHECK_CMD=@true
|
||||
@ifNotGNUmake@ CPPHECK_CMD=@true
|
||||
@ifNotGNUmake@ CHECK_CMD=true
|
||||
@ifNotGNUmake@ CPPCHECK_CMD=true
|
||||
|
||||
CC = @CC@
|
||||
BUILD_CC = @BUILD_CC@
|
||||
|
|
2
README
2
README
|
@ -1,4 +1,4 @@
|
|||
This is the new version (1.43.2) of the second extended file
|
||||
This is the new version (1.43.3) of the second extended file
|
||||
system management programs.
|
||||
|
||||
From time to time, I release new versions of e2fsprogs, to fix
|
||||
|
|
|
@ -1,3 +1,31 @@
|
|||
E2fsprogs 1.43.3 (September 4, 2016)
|
||||
====================================
|
||||
|
||||
Fix e2fsck's handling of timestamps on 32-bit systems.
|
||||
|
||||
E2fsck will now check, and if necessary repair the extra isize fields
|
||||
in the inode and superblock.
|
||||
|
||||
Fix crashes on architectures such as sparc64 that are sensitive to
|
||||
unaligned pointer derferences in the journal recovery code when
|
||||
journal checksums are enabled.
|
||||
|
||||
Programming notes
|
||||
-----------------
|
||||
|
||||
Support reproducible builds by not capturing the build directory into
|
||||
the mk_cmds and compile_et scripts. Also fix debian build rules to
|
||||
ensure build reproducibility.
|
||||
|
||||
Fix debian build rules to ensure build reproducibility and to avoid
|
||||
hiding the linker flags for e2fsck.static so the build hardening log
|
||||
scanner can properly audit the build.
|
||||
|
||||
Fix compatibility with FreeBSD's pmake and teach the configure script
|
||||
to force the creation of pmake-compatible Makefiles if the
|
||||
FORCE_NATIVE_MAKE environment variable is set to a non-empty value.
|
||||
|
||||
|
||||
E2fsprogs 1.43.2 (September 1, 2016)
|
||||
====================================
|
||||
|
||||
|
|
|
@ -108,7 +108,12 @@ AC_DEFUN(
|
|||
[CHECK_GNU_MAKE], [ AC_CACHE_CHECK( for GNU make,_cv_gnu_make_command,
|
||||
_cv_gnu_make_command='' ;
|
||||
dnl Search all the common names for GNU make
|
||||
for a in "$MAKE" make gmake gnumake ; do
|
||||
if test -n "$FORCE_NATIVE_MAKE" ; then
|
||||
MAKES="make"
|
||||
else
|
||||
MAKES="make gmake gnumake"
|
||||
fi
|
||||
for a in "$MAKE" $MAKES ; do
|
||||
if test -z "$a" ; then continue ; fi ;
|
||||
if ( sh -c "$a --version" 2> /dev/null | grep GNU 2>&1 > /dev/null ) ; then
|
||||
_cv_gnu_make_command=$a ;
|
||||
|
|
|
@ -11515,7 +11515,12 @@ if ${_cv_gnu_make_command+:} false; then :
|
|||
$as_echo_n "(cached) " >&6
|
||||
else
|
||||
_cv_gnu_make_command='' ;
|
||||
for a in "$MAKE" make gmake gnumake ; do
|
||||
if test -n "$FORCE_NATIVE_MAKE" ; then
|
||||
MAKES="make"
|
||||
else
|
||||
MAKES="make gmake gnumake"
|
||||
fi
|
||||
for a in "$MAKE" $MAKES ; do
|
||||
if test -z "$a" ; then continue ; fi ;
|
||||
if ( sh -c "$a --version" 2> /dev/null | grep GNU 2>&1 > /dev/null ) ; then
|
||||
_cv_gnu_make_command=$a ;
|
||||
|
|
|
@ -1,3 +1,13 @@
|
|||
e2fsprogs (1.43.3-1) unstable; urgency=medium
|
||||
|
||||
* Fix e2fsck's handling of timestamps on 32-bit system (Closes: #836559)
|
||||
* E2fsck will sanity check and repair the extra isize fields in inodes
|
||||
and the superblock.
|
||||
* Fix sparc64 crashes when dereferencing unaligned integers in journal
|
||||
blocks when metdata checksums are enabled.
|
||||
|
||||
-- Theodore Y. Ts'o <tytso@mit.edu> Sun, 04 Sep 2016 20:41:21 -0400
|
||||
|
||||
e2fsprogs (1.43.2-2) unstable; urgency=medium
|
||||
|
||||
* Fix build reproducibility problems
|
||||
|
|
|
@ -1,21 +0,0 @@
|
|||
Description: Enable metadata_csum by default
|
||||
For debian testing let's be more aggressive about testing the
|
||||
metadata_csum feature.
|
||||
From: Theodore Y. Ts'o <tytso@mit.edu>
|
||||
|
||||
--- e2fsprogs-1.43.orig/misc/mke2fs.conf.in
|
||||
+++ e2fsprogs-1.43/misc/mke2fs.conf.in
|
||||
@@ -11,11 +11,11 @@
|
||||
features = has_journal
|
||||
}
|
||||
ext4 = {
|
||||
- features = has_journal,extent,huge_file,flex_bg,64bit,dir_nlink,extra_isize
|
||||
+ 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,inline_data,64bit,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
|
||||
}
|
|
@ -1,262 +0,0 @@
|
|||
Description: Fix build reproducibility for mk_cmds and compile_et
|
||||
The mk_cmds and compile_et scripts include the build directory, which
|
||||
breaks the build reproducibility goal of Debian.
|
||||
From: Theodore Ts'o <tytso@mit.edu>
|
||||
|
||||
diff --git a/configure b/configure
|
||||
index 03e24d1..0ac5dcb 100755
|
||||
--- a/configure
|
||||
+++ b/configure
|
||||
@@ -633,8 +633,6 @@ BUILD_CFLAGS
|
||||
MKINSTALLDIRS
|
||||
INCLUDES
|
||||
DO_TEST_SUITE
|
||||
-ET_DIR
|
||||
-SS_DIR
|
||||
LDFLAGS_STATIC
|
||||
root_sysconfdir
|
||||
root_libdir
|
||||
@@ -13805,10 +13803,6 @@ $as_echo "#define _INTL_REDIRECT_MACROS 1" >>confdefs.h
|
||||
|
||||
;;
|
||||
esac
|
||||
-SS_DIR=`cd ${srcdir}/lib/ss; pwd`
|
||||
-ET_DIR=`cd ${srcdir}/lib/et; pwd`
|
||||
-
|
||||
-
|
||||
if test "$cross_compiling" = yes ; then
|
||||
DO_TEST_SUITE=
|
||||
else
|
||||
diff --git a/configure.ac b/configure.ac
|
||||
index a387dfd..1c73301 100644
|
||||
--- a/configure.ac
|
||||
+++ b/configure.ac
|
||||
@@ -1400,13 +1400,6 @@ darwin*)
|
||||
;;
|
||||
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
|
||||
diff --git a/debugfs/Makefile.in b/debugfs/Makefile.in
|
||||
index c22b8c0..a3fe13e 100644
|
||||
--- a/debugfs/Makefile.in
|
||||
+++ b/debugfs/Makefile.in
|
||||
@@ -14,7 +14,7 @@ INSTALL = @INSTALL@
|
||||
PROGS= debugfs
|
||||
MANPAGES= debugfs.8
|
||||
|
||||
-MK_CMDS= _SS_DIR_OVERRIDE=../lib/ss ../lib/ss/mk_cmds
|
||||
+MK_CMDS= _SS_DIR_OVERRIDE=$(srcdir)/../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 \
|
||||
diff --git a/e2fsck/Makefile.in b/e2fsck/Makefile.in
|
||||
index 06d9f55..6f626f4 100644
|
||||
--- a/e2fsck/Makefile.in
|
||||
+++ b/e2fsck/Makefile.in
|
||||
@@ -34,7 +34,7 @@ PROFILED_DEPLIBS= $(DEPPROFILED_LIBSUPPORT) $(PROFILED_LIBEXT2FS) \
|
||||
$(DEPPROFILED_LIBCOM_ERR) $(DEPPROFILED_LIBBLKID) \
|
||||
$(DEPPROFILED_LIBUUID) $(DEPPROFILED_LIBE2P)
|
||||
|
||||
-COMPILE_ET=$(top_builddir)/lib/et/compile_et --build-tree
|
||||
+COMPILE_ET= _ET_DIR_OVERRIDE=$(srcdir)/../lib/et/et ../lib/et/compile_et
|
||||
|
||||
.c.o:
|
||||
$(E) " CC $<"
|
||||
diff --git a/lib/et/Makefile.in b/lib/et/Makefile.in
|
||||
index cb75ab8..476f189 100644
|
||||
--- a/lib/et/Makefile.in
|
||||
+++ b/lib/et/Makefile.in
|
||||
@@ -140,7 +140,7 @@ uninstall::
|
||||
check:: compile_et
|
||||
for i in $(srcdir)/test_cases/*.et ; do \
|
||||
t=`basename $$i | sed -e 's/.et//'`; \
|
||||
- ./compile_et --build-tree $$i ; \
|
||||
+ _ET_DIR_OVERRIDE=$(srcdir) ./compile_et $$i ; \
|
||||
diff -c $(srcdir)/test_cases/$$t.c $$t.c > $$t.failed; \
|
||||
if [ $$? -ne 0 ]; then echo Test case $$t failed; exit 1 ; fi ; \
|
||||
diff -c $(srcdir)/test_cases/$$t.h $$t.h >> $$t.failed; \
|
||||
diff --git a/lib/et/compile_et.sh.in b/lib/et/compile_et.sh.in
|
||||
index c2861f4..4c4ba17 100644
|
||||
--- a/lib/et/compile_et.sh.in
|
||||
+++ b/lib/et/compile_et.sh.in
|
||||
@@ -4,8 +4,7 @@
|
||||
|
||||
datarootdir=@datarootdir@
|
||||
AWK=@AWK@
|
||||
-DIR="${DIR-@datadir@/et}"
|
||||
-ET_DIR="${ET_DIR-@ET_DIR@}"
|
||||
+DIR=@datadir@/et
|
||||
|
||||
if test "$1" = "--build-tree" ; then
|
||||
shift;
|
||||
@@ -29,13 +28,13 @@ do
|
||||
fi
|
||||
done
|
||||
|
||||
+if test -n "$_ET_DIR_OVERRIDE" ; then
|
||||
+ DIR="$_ET_DIR_OVERRIDE";
|
||||
+fi
|
||||
+
|
||||
if test ! -f "$DIR/et_h.awk" || test ! -f "$DIR/et_c.awk" ; then
|
||||
- DIR="$ET_DIR"
|
||||
-# echo "Falling back to $DIR..."
|
||||
- if test ! -f "$DIR/et_h.awk" || test ! -f "$DIR/et_c.awk" ; then
|
||||
- echo "compile_et: Couldn't find compile_et's template files."
|
||||
- exit 1
|
||||
- fi
|
||||
+ echo "compile_et: Couldn't find compile_et's template files."
|
||||
+ exit 1
|
||||
fi
|
||||
|
||||
ROOT=`echo $1 | sed -e s/.et$//`
|
||||
diff --git a/lib/ext2fs/Makefile.in b/lib/ext2fs/Makefile.in
|
||||
index 461920c..6a3656d 100644
|
||||
--- a/lib/ext2fs/Makefile.in
|
||||
+++ b/lib/ext2fs/Makefile.in
|
||||
@@ -13,7 +13,8 @@ DEBUGFS_CFLAGS = -I$(srcdir)/../../e2fsck $(ALL_CFLAGS) -DDEBUGFS
|
||||
|
||||
@DEBUGFS_CMT@DEBUGFS_LIB_OBJS = bb_compat.o inode_io.o write_bb_file.o
|
||||
|
||||
-MK_CMDS= _SS_DIR_OVERRIDE=../ss ../ss/mk_cmds
|
||||
+MK_CMDS= _SS_DIR_OVERRIDE=$(srcdir)/../ss ../ss/mk_cmds
|
||||
+COMPILE_ET= _ET_DIR_OVERRIDE=$(srcdir)/../et ../et/compile_et
|
||||
|
||||
@RESIZER_CMT@RESIZE_LIB_OBJS = dupfs.o
|
||||
@TEST_IO_CMT@TEST_IO_LIB_OBJS = test_io.o
|
||||
@@ -254,8 +255,6 @@ all:: ext2fs.pc
|
||||
@ELF_CMT@ $(Q) $(CC) $(ALL_CFLAGS_SHLIB) -fPIC -shared -o elfshared/$*.o -c $<
|
||||
@BSDLIB_CMT@ $(Q) $(CC) $(ALL_CFLAGS_SHLIB) $(BSDLIB_PIC_FLAG) -o pic/$*.o -c $<
|
||||
|
||||
-COMPILE_ET=../et/compile_et --build-tree
|
||||
-
|
||||
DISTFILES= Makefile *.c *.h image
|
||||
|
||||
ext2_err.et: $(DEP_SUBSTITUTE) $(srcdir)/ext2_err.et.in
|
||||
diff --git a/lib/ss/Makefile.in b/lib/ss/Makefile.in
|
||||
index 255b58b..f4953f0 100644
|
||||
--- a/lib/ss/Makefile.in
|
||||
+++ b/lib/ss/Makefile.in
|
||||
@@ -28,8 +28,8 @@ BSDLIB_MYDIR = ss
|
||||
BSDLIB_INSTALL_DIR = $(root_libdir)
|
||||
|
||||
TAGS=etags
|
||||
-COMPILE_ET=../et/compile_et --build-tree
|
||||
-MK_CMDS=_SS_DIR_OVERRIDE=. ./mk_cmds
|
||||
+MK_CMDS= _SS_DIR_OVERRIDE=$(srcdir) ./mk_cmds
|
||||
+COMPILE_ET= _ET_DIR_OVERRIDE=$(srcdir)/../et ../et/compile_et
|
||||
|
||||
.c.o:
|
||||
$(E) " CC $<"
|
||||
diff --git a/lib/ss/mk_cmds.sh.in b/lib/ss/mk_cmds.sh.in
|
||||
index a8976a4..0abc19d 100644
|
||||
--- a/lib/ss/mk_cmds.sh.in
|
||||
+++ b/lib/ss/mk_cmds.sh.in
|
||||
@@ -3,8 +3,7 @@
|
||||
#
|
||||
|
||||
datarootdir=@datarootdir@
|
||||
-DIR="${DIR-@datadir@/ss}"
|
||||
-SS_DIR="@SS_DIR@"
|
||||
+DIR=@datadir@/ss
|
||||
AWK=@AWK@
|
||||
SED=@SED@
|
||||
|
||||
@@ -30,12 +29,8 @@ if test -n "$_SS_DIR_OVERRIDE" ; then
|
||||
fi
|
||||
|
||||
if test ! -f $DIR/ct_c.sed || test ! -f $DIR/ct_c.awk ; then
|
||||
- DIR="$SS_DIR"
|
||||
-# echo "Falling back to $DIR..."
|
||||
- if test ! -f "$DIR/ct_c.sed" || test ! -f "$DIR/ct_c.awk" ; then
|
||||
- echo "mk_cmds: Couldn't find mk_cmds's template files."
|
||||
- exit 1
|
||||
- fi
|
||||
+ echo "mk_cmds: Couldn't find mk_cmds's template files."
|
||||
+ exit 1
|
||||
fi
|
||||
|
||||
FILE="$1"
|
||||
diff --git a/lib/support/Makefile.in b/lib/support/Makefile.in
|
||||
index 5beaaac..112ba24 100644
|
||||
--- a/lib/support/Makefile.in
|
||||
+++ b/lib/support/Makefile.in
|
||||
@@ -41,7 +41,7 @@ LIBDIR= support
|
||||
@MAKEFILE_LIBRARY@
|
||||
@MAKEFILE_PROFILE@
|
||||
|
||||
-COMPILE_ET=$(top_builddir)/lib/et/compile_et --build-tree
|
||||
+COMPILE_ET= _ET_DIR_OVERRIDE=$(srcdir)/../et ../et/compile_et
|
||||
|
||||
.c.o:
|
||||
$(E) " CC $<"
|
||||
diff --git a/misc/Makefile.in b/misc/Makefile.in
|
||||
index e487692..d6436c2 100644
|
||||
--- a/misc/Makefile.in
|
||||
+++ b/misc/Makefile.in
|
||||
@@ -115,7 +115,7 @@ STATIC_DEPLIBS= $(DEPLIBSUPPORT) $(STATIC_LIBEXT2FS) $(DEPSTATIC_LIBCOM_ERR)
|
||||
LIBS_E2P= $(LIBE2P) $(LIBCOM_ERR)
|
||||
DEPLIBS_E2P= $(LIBE2P) $(DEPLIBCOM_ERR)
|
||||
|
||||
-COMPILE_ET=$(top_builddir)/lib/et/compile_et --build-tree
|
||||
+COMPILE_ET= _ET_DIR_OVERRIDE=$(srcdir)/../lib/et/et ../lib/et/compile_et
|
||||
|
||||
# This nastyness is needed because of jfs_user.h hackery; when we finally
|
||||
# clean up this mess, we should be able to drop it
|
||||
diff --git a/tests/progs/Makefile.in b/tests/progs/Makefile.in
|
||||
index 22d9417..f6a31b9 100644
|
||||
--- a/tests/progs/Makefile.in
|
||||
+++ b/tests/progs/Makefile.in
|
||||
@@ -11,7 +11,7 @@ INSTALL = @INSTALL@
|
||||
|
||||
@MCONFIG@
|
||||
|
||||
-MK_CMDS= _SS_DIR_OVERRIDE=../../lib/ss ../../lib/ss/mk_cmds
|
||||
+MK_CMDS= _SS_DIR_OVERRIDE=$(srcdir)/../../lib/ss ../../lib/ss/mk_cmds
|
||||
|
||||
PROGS= test_icount crcsum
|
||||
|
||||
diff --git a/util/gen-android-files b/util/gen-android-files
|
||||
index 994337b..ebd8778 100755
|
||||
--- a/util/gen-android-files
|
||||
+++ b/util/gen-android-files
|
||||
@@ -14,8 +14,8 @@ ANDROID_GENERATED_FILES="lib/ext2fs/ext2_err.c lib/ext2fs/ext2_err.h \
|
||||
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/@AWK@/awk/" < $SS_DIR/mk_cmds.sh.in \
|
||||
+ | 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
|
||||
|
||||
@@ -29,7 +29,7 @@ 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
|
||||
+ _SS_DIR_OVERRIDE=lib/ss /bin/sh $MK_CMDS $i.ct
|
||||
mv -f $(basename $i).c $i.c
|
||||
done
|
||||
|
||||
diff --git a/util/subst.conf.in b/util/subst.conf.in
|
||||
index ada11e7..fbc044d 100644
|
||||
--- a/util/subst.conf.in
|
||||
+++ b/util/subst.conf.in
|
||||
@@ -1,7 +1,5 @@
|
||||
AWK @AWK@
|
||||
SED @SED@
|
||||
-ET_DIR @ET_DIR@
|
||||
-SS_DIR @SS_DIR@
|
||||
E2FSPROGS_MONTH @E2FSPROGS_MONTH@
|
||||
E2FSPROGS_YEAR @E2FSPROGS_YEAR@
|
||||
E2FSPROGS_VERSION @E2FSPROGS_VERSION@
|
|
@ -1,2 +0,0 @@
|
|||
enable-metadata_csum-by-default
|
||||
fix-build-reproducibility-in-mk_cmds-and-compile_et
|
|
@ -1,7 +1,7 @@
|
|||
\input texinfo @c -*-texinfo-*-
|
||||
@c %**start of header
|
||||
@setfilename libext2fs.info
|
||||
@settitle The EXT2FS Library (version 1.43.2)
|
||||
@settitle The EXT2FS Library (version 1.43.3)
|
||||
@synindex tp fn
|
||||
@comment %**end of header
|
||||
|
||||
|
@ -60,7 +60,7 @@ by the author.
|
|||
|
||||
@title The EXT2FS Library
|
||||
@subtitle The EXT2FS Library
|
||||
@subtitle Version 1.43.2
|
||||
@subtitle Version 1.43.3
|
||||
@subtitle September 2016
|
||||
|
||||
@author by Theodore Ts'o
|
||||
|
@ -101,7 +101,7 @@ by the Foundation.
|
|||
|
||||
@top The EXT2FS Library
|
||||
|
||||
This manual documents the EXT2FS Library, version 1.43.2.
|
||||
This manual documents the EXT2FS Library, version 1.43.3.
|
||||
|
||||
@menu
|
||||
* Introduction to the EXT2FS Library::
|
||||
|
|
|
@ -345,6 +345,12 @@ or
|
|||
.B \-p
|
||||
options.
|
||||
.TP
|
||||
.BI \-T " patch_file"
|
||||
Do not apply changes to the real filesystem; write updates into a sparse file
|
||||
named 'patch_file' to safely apply them later with e2patch(8) utility.
|
||||
You'll also be able to create a backup before applying patch and safely
|
||||
restore it in case of power outage or system crash.
|
||||
.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
|
||||
|
|
|
@ -391,6 +391,9 @@ struct e2fsck_struct {
|
|||
*/
|
||||
ext2fs_inode_bitmap inodes_to_rebuild;
|
||||
|
||||
/* Patch file */
|
||||
char *patch_file;
|
||||
|
||||
/* Undo file */
|
||||
char *undo_file;
|
||||
};
|
||||
|
|
|
@ -488,10 +488,14 @@ static void check_inode_extra_space(e2fsck_t ctx, struct problem_context *pctx)
|
|||
* implementations should never allow i_extra_isize to be 0
|
||||
*/
|
||||
if (inode->i_extra_isize &&
|
||||
(inode->i_extra_isize < min || inode->i_extra_isize > max)) {
|
||||
(inode->i_extra_isize < min || inode->i_extra_isize > max ||
|
||||
inode->i_extra_isize & 3)) {
|
||||
if (!fix_problem(ctx, PR_1_EXTRA_ISIZE, pctx))
|
||||
return;
|
||||
inode->i_extra_isize = min;
|
||||
if (inode->i_extra_isize < min || inode->i_extra_isize > max)
|
||||
inode->i_extra_isize = sb->s_want_extra_isize;
|
||||
else
|
||||
inode->i_extra_isize = (inode->i_extra_isize + 3) & ~3;
|
||||
e2fsck_write_inode_full(ctx, pctx->ino, pctx->inode,
|
||||
EXT2_INODE_SIZE(sb), "pass1");
|
||||
return;
|
||||
|
@ -512,9 +516,9 @@ static void check_inode_extra_space(e2fsck_t ctx, struct problem_context *pctx)
|
|||
* If the inode's extended atime (ctime, crtime, mtime) is stored in
|
||||
* the old, invalid format, repair it.
|
||||
*/
|
||||
if ((sizeof(time_t) <= 4) ||
|
||||
(((sizeof(time_t) > 4) &&
|
||||
ctx->now < EXT4_EXTRA_NEGATIVE_DATE_CUTOFF)) &&
|
||||
if (((sizeof(time_t) <= 4) ||
|
||||
(((sizeof(time_t) > 4) &&
|
||||
ctx->now < EXT4_EXTRA_NEGATIVE_DATE_CUTOFF))) &&
|
||||
(CHECK_INODE_EXTRA_NEGATIVE_EPOCH(inode, atime) ||
|
||||
CHECK_INODE_EXTRA_NEGATIVE_EPOCH(inode, ctime) ||
|
||||
CHECK_INODE_EXTRA_NEGATIVE_EPOCH(inode, crtime) ||
|
||||
|
|
|
@ -477,6 +477,16 @@ static struct e2fsck_problem problem_table[] = {
|
|||
N_("Error initializing quota context in support library: %m\n"),
|
||||
PROMPT_NULL, PR_FATAL },
|
||||
|
||||
/* Bad s_min_extra_isize in superblock */
|
||||
{ PR_0_BAD_MIN_EXTRA_ISIZE,
|
||||
N_("Bad required extra isize in @S (%N). "),
|
||||
PROMPT_FIX, 0 },
|
||||
|
||||
/* Bad s_min_extra_isize in superblock */
|
||||
{ PR_0_BAD_WANT_EXTRA_ISIZE,
|
||||
N_("Bad desired extra isize in @S (%N). "),
|
||||
PROMPT_FIX, 0 },
|
||||
|
||||
/* Pass 1 errors */
|
||||
|
||||
/* Pass 1: Checking inodes, blocks, and sizes */
|
||||
|
|
|
@ -274,6 +274,12 @@ struct problem_context {
|
|||
/* Error initializing quota context */
|
||||
#define PR_0_QUOTA_INIT_CTX 0x00004C
|
||||
|
||||
/* Bad s_min_extra_isize in superblock */
|
||||
#define PR_0_BAD_MIN_EXTRA_ISIZE 0x00004D
|
||||
|
||||
/* Bad s_want_extra_isize in superblock */
|
||||
#define PR_0_BAD_WANT_EXTRA_ISIZE 0x00004E
|
||||
|
||||
|
||||
/*
|
||||
* Pass 1 errors
|
||||
|
|
|
@ -338,12 +338,24 @@ int journal_skip_recovery(journal_t *journal)
|
|||
return err;
|
||||
}
|
||||
|
||||
static inline __u32 get_be32(__be32 *p)
|
||||
{
|
||||
unsigned char *cp = (unsigned char *) p;
|
||||
__u32 ret;
|
||||
|
||||
ret = *cp++;
|
||||
ret = (ret << 8) + *cp++;
|
||||
ret = (ret << 8) + *cp++;
|
||||
ret = (ret << 8) + *cp++;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline unsigned long long read_tag_block(journal_t *journal,
|
||||
journal_block_tag_t *tag)
|
||||
{
|
||||
unsigned long long block = ext2fs_be32_to_cpu(tag->t_blocknr);
|
||||
unsigned long long block = get_be32(&tag->t_blocknr);
|
||||
if (jfs_has_feature_64bit(journal))
|
||||
block |= (u64)ext2fs_be32_to_cpu(tag->t_blocknr_high) << 32;
|
||||
block |= (u64)get_be32(&tag->t_blocknr_high) << 32;
|
||||
return block;
|
||||
}
|
||||
|
||||
|
|
|
@ -578,7 +578,35 @@ void check_super_block(e2fsck_t ctx)
|
|||
ext2fs_mark_super_dirty(fs);
|
||||
}
|
||||
}
|
||||
|
||||
if (EXT2_INODE_SIZE(sb) > EXT2_GOOD_OLD_INODE_SIZE) {
|
||||
unsigned min =
|
||||
sizeof(((struct ext2_inode_large *) 0)->i_extra_isize) +
|
||||
sizeof(((struct ext2_inode_large *) 0)->i_checksum_hi);
|
||||
unsigned max = EXT2_INODE_SIZE(sb) - EXT2_GOOD_OLD_INODE_SIZE;
|
||||
pctx.num = sb->s_min_extra_isize;
|
||||
if (sb->s_min_extra_isize &&
|
||||
(sb->s_min_extra_isize < min ||
|
||||
sb->s_min_extra_isize > max ||
|
||||
sb->s_min_extra_isize & 3) &&
|
||||
fix_problem(ctx, PR_0_BAD_MIN_EXTRA_ISIZE, &pctx)) {
|
||||
sb->s_min_extra_isize =
|
||||
(sizeof(struct ext2_inode_large) -
|
||||
EXT2_GOOD_OLD_INODE_SIZE);
|
||||
ext2fs_mark_super_dirty(fs);
|
||||
}
|
||||
pctx.num = sb->s_want_extra_isize;
|
||||
if (sb->s_want_extra_isize &&
|
||||
(sb->s_want_extra_isize < min ||
|
||||
sb->s_want_extra_isize > max ||
|
||||
sb->s_want_extra_isize & 3) &&
|
||||
fix_problem(ctx, PR_0_BAD_WANT_EXTRA_ISIZE, &pctx)) {
|
||||
sb->s_want_extra_isize =
|
||||
(sizeof(struct ext2_inode_large) -
|
||||
EXT2_GOOD_OLD_INODE_SIZE);
|
||||
ext2fs_mark_super_dirty(fs);
|
||||
}
|
||||
}
|
||||
|
||||
/* Are metadata_csum and uninit_bg both set? */
|
||||
if (ext2fs_has_feature_metadata_csum(fs->super) &&
|
||||
ext2fs_has_feature_gdt_csum(fs->super) &&
|
||||
|
|
|
@ -76,7 +76,7 @@ static void usage(e2fsck_t ctx)
|
|||
fprintf(stderr,
|
||||
_("Usage: %s [-panyrcdfktvDFV] [-b superblock] [-B blocksize]\n"
|
||||
"\t\t[-l|-L bad_blocks_file] [-C fd] [-j external_journal]\n"
|
||||
"\t\t[-E extended-options] [-z undo_file] device\n"),
|
||||
"\t\t[-E extended-options] [-T patch_file] [-z undo_file] device\n"),
|
||||
ctx->program_name);
|
||||
|
||||
fprintf(stderr, "%s", _("\nEmergency help:\n"
|
||||
|
@ -92,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"
|
||||
" -T patch_file Create a patch file instead of applying changes to real FS\n"
|
||||
" -z undo_file Create an undo file\n"
|
||||
));
|
||||
|
||||
|
@ -804,7 +805,7 @@ static errcode_t PRS(int argc, char *argv[], e2fsck_t *ret_ctx)
|
|||
|
||||
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)
|
||||
while ((c = getopt(argc, argv, "panyrcC:B:dE:fvtFVM:b:I:j:P:l:L:N:SsDkT:z:")) != EOF)
|
||||
switch (c) {
|
||||
case 'C':
|
||||
ctx->progress = e2fsck_update_progress;
|
||||
|
@ -936,6 +937,9 @@ static errcode_t PRS(int argc, char *argv[], e2fsck_t *ret_ctx)
|
|||
case 'k':
|
||||
keep_bad_blocks++;
|
||||
break;
|
||||
case 'T':
|
||||
ctx->patch_file = optarg;
|
||||
break;
|
||||
case 'z':
|
||||
ctx->undo_file = optarg;
|
||||
break;
|
||||
|
@ -1233,6 +1237,19 @@ check_error:
|
|||
return retval;
|
||||
}
|
||||
|
||||
static int e2fsck_setup_patch(e2fsck_t ctx, io_manager *io_ptr)
|
||||
{
|
||||
set_patch_io_backing_manager(*io_ptr);
|
||||
set_patch_io_patch_file(ctx->patch_file);
|
||||
*io_ptr = patch_io_manager;
|
||||
printf(_("To make backup before applying changes run:\n"
|
||||
" e2patch backup %s %s %s.backup\n"
|
||||
"Then, to apply the operation to the real filesystem run:\n"
|
||||
" e2patch apply %s %s\n"),
|
||||
ctx->device_name, ctx->patch_file, ctx->patch_file, ctx->device_name, ctx->patch_file);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int e2fsck_setup_tdb(e2fsck_t ctx, io_manager *io_ptr)
|
||||
{
|
||||
errcode_t retval = ENOMEM;
|
||||
|
@ -1430,7 +1447,11 @@ restart:
|
|||
flags &= ~EXT2_FLAG_EXCLUSIVE;
|
||||
}
|
||||
|
||||
if (ctx->undo_file) {
|
||||
if (ctx->patch_file) {
|
||||
retval = e2fsck_setup_patch(ctx, &io_ptr);
|
||||
if (retval)
|
||||
exit(FSCK_ERROR);
|
||||
} else if (ctx->undo_file) {
|
||||
retval = e2fsck_setup_tdb(ctx, &io_ptr);
|
||||
if (retval)
|
||||
exit(FSCK_ERROR);
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
Begin3
|
||||
Title: EXT2 Filesystem utilities
|
||||
Version: 1.43.2
|
||||
Entered-date: 2016-09-01
|
||||
Version: 1.43.3
|
||||
Entered-date: 2016-09-04
|
||||
Description: The filesystem utilities for the EXT2, EXT3, and EXT4
|
||||
filesystems, including e2fsck, mke2fs, dumpe2fs, and others.
|
||||
Keywords: utilities, filesystem, Ext2fs, ext3, ext4
|
||||
Author: tytso@mit.edu (Theodore Tso)
|
||||
Maintained-by: tytso@mit.edu (Theodore Tso)
|
||||
Primary-site: ftp.kernel.org /pub/linux/kernel/people/tytso/e2fsprogs
|
||||
7224kB e2fsprogs-1.43.2.tar.gz
|
||||
644kB e2fsprogs-libs-1.43.2.tar.gz
|
||||
1kB e2fsprogs-1.43.2.lsm
|
||||
7224kB e2fsprogs-1.43.3.tar.gz
|
||||
644kB e2fsprogs-libs-1.43.3.tar.gz
|
||||
1kB e2fsprogs-1.43.3.lsm
|
||||
Alternate-site: download.sourceforge.net /pub/sourceforge/e2fsprogs
|
||||
Platforms: linux 1.2.x/1.3.x/2.0.x/2.1.x/2.2.x/2.3.x/2.4.x/2.5.x/2.6.x/3.x/4.x
|
||||
Copying-policy: GPL-2/LGPL-2
|
||||
|
|
|
@ -117,6 +117,7 @@ exit 0
|
|||
%{_root_sbindir}/e2image
|
||||
%{_root_sbindir}/e2label
|
||||
%{_root_sbindir}/e2undo
|
||||
%{_root_sbindir}/e2patch
|
||||
%{_root_sbindir}/findfs
|
||||
%{_root_sbindir}/fsck
|
||||
%{_root_sbindir}/fsck.ext2
|
||||
|
@ -168,6 +169,7 @@ exit 0
|
|||
%{_mandir}/man8/e2image.8*
|
||||
%{_mandir}/man8/e2label.8*
|
||||
%{_mandir}/man8/e2undo.8*
|
||||
%{_mandir}/man8/e2patch.8*
|
||||
%{_mandir}/man8/fsck.8*
|
||||
%{_mandir}/man8/logsave.8*
|
||||
%{_mandir}/man8/mke2fs.8*
|
||||
|
|
|
@ -75,6 +75,8 @@ libext2fs_src_files := \
|
|||
swapfs.c \
|
||||
symlink.c \
|
||||
undo_io.c \
|
||||
patch.c \
|
||||
patch_io.c \
|
||||
unix_io.c \
|
||||
unlink.c \
|
||||
valid_blk.c \
|
||||
|
|
|
@ -124,6 +124,8 @@ OBJS= $(DEBUGFS_LIB_OBJS) $(RESIZE_LIB_OBJS) $(E2IMAGE_LIB_OBJS) \
|
|||
symlink.o \
|
||||
$(TDB_OBJ) \
|
||||
undo_io.o \
|
||||
patch.o \
|
||||
patch_io.o \
|
||||
unix_io.o \
|
||||
unlink.o \
|
||||
valid_blk.o \
|
||||
|
@ -211,6 +213,8 @@ SRCS= ext2_err.c \
|
|||
$(srcdir)/tst_getsize.c \
|
||||
$(srcdir)/tst_iscan.c \
|
||||
$(srcdir)/undo_io.c \
|
||||
$(srcdir)/patch.c \
|
||||
$(srcdir)/patch_io.c \
|
||||
$(srcdir)/unix_io.c \
|
||||
$(srcdir)/unlink.c \
|
||||
$(srcdir)/valid_blk.c \
|
||||
|
@ -1099,6 +1103,18 @@ undo_io.o: $(srcdir)/undo_io.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
|
||||
patch.o: $(srcdir)/patch.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
|
||||
patch_io.o: $(srcdir)/patch_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 \
|
||||
$(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
|
||||
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 \
|
||||
|
|
|
@ -185,8 +185,9 @@ struct ext2_group_desc *ext2fs_group_desc(ext2_filsys fs,
|
|||
struct opaque_ext2_group_desc *gdp,
|
||||
dgrp_t group)
|
||||
{
|
||||
return (struct ext2_group_desc *)((char *)gdp +
|
||||
group * EXT2_DESC_SIZE(fs->super));
|
||||
int desc_size = EXT2_DESC_SIZE(fs->super) & ~7;
|
||||
|
||||
return (struct ext2_group_desc *)((char *)gdp + group * desc_size);
|
||||
}
|
||||
|
||||
/* Do the same but as an ext4 group desc for internal use here */
|
||||
|
|
|
@ -539,4 +539,7 @@ ec EXT2_ET_BAD_CRC,
|
|||
ec EXT2_ET_CORRUPT_JOURNAL_SB,
|
||||
"The journal superblock is corrupt"
|
||||
|
||||
ec EXT2_ET_INODE_CORRUPTED,
|
||||
"Inode is corrupted"
|
||||
|
||||
end
|
||||
|
|
|
@ -145,6 +145,11 @@ extern io_manager undo_io_manager;
|
|||
extern errcode_t set_undo_io_backing_manager(io_manager manager);
|
||||
extern errcode_t set_undo_io_backup_file(char *file_name);
|
||||
|
||||
/* patch_io.c */
|
||||
extern io_manager patch_io_manager;
|
||||
extern errcode_t set_patch_io_backing_manager(io_manager manager);
|
||||
extern errcode_t set_patch_io_patch_file(char *file_name);
|
||||
|
||||
/* test_io.c */
|
||||
extern io_manager test_io_manager, test_io_backing_manager;
|
||||
extern void (*test_io_cb_read_blk)
|
||||
|
|
|
@ -554,6 +554,10 @@ errcode_t ext2fs_xattrs_write(struct ext2_xattr_handle *handle)
|
|||
memset(p + EXT2_GOOD_OLD_INODE_SIZE, 0, extra);
|
||||
inode->i_extra_isize = extra;
|
||||
}
|
||||
if (inode->i_extra_isize & 3) {
|
||||
err = EXT2_ET_INODE_CORRUPTED;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Force the inlinedata attr to the front and the empty entries
|
||||
|
@ -806,6 +810,10 @@ errcode_t ext2fs_xattrs_read(struct ext2_xattr_handle *handle)
|
|||
inode->i_extra_isize +
|
||||
sizeof(__u32))
|
||||
goto read_ea_block;
|
||||
if (inode->i_extra_isize & 3) {
|
||||
err = EXT2_ET_INODE_CORRUPTED;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Look for EA in the inode */
|
||||
memcpy(&ea_inode_magic, ((char *) inode) + EXT2_GOOD_OLD_INODE_SIZE +
|
||||
|
|
|
@ -0,0 +1,228 @@
|
|||
/**
|
||||
* patch.c --- Common "patch" file functions
|
||||
*
|
||||
* Copyright (c) Vitaliy Filippov <vitalif@mail.ru> 2014
|
||||
* License: GNU GPLv2 or later
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#define _LARGEFILE_SOURCE
|
||||
#define _LARGEFILE64_SOURCE
|
||||
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include "patch.h"
|
||||
|
||||
errcode_t ext2fs_patch_retry_read(int fd, ssize_t size, void *buf)
|
||||
{
|
||||
ssize_t r, done = 0;
|
||||
while (done < size)
|
||||
{
|
||||
r = read(fd, buf+done, size-done);
|
||||
if (!r || (r < 0 && errno != EAGAIN))
|
||||
break;
|
||||
done += r;
|
||||
}
|
||||
if (done < size)
|
||||
return errno;
|
||||
return 0;
|
||||
}
|
||||
|
||||
errcode_t ext2fs_patch_retry_write(int fd, ssize_t size, const void *buf)
|
||||
{
|
||||
ssize_t r, done = 0;
|
||||
while (done < size)
|
||||
{
|
||||
r = write(fd, buf+done, size-done);
|
||||
if (r <= 0 && errno != EAGAIN)
|
||||
break;
|
||||
done += r;
|
||||
}
|
||||
if (done < size)
|
||||
return errno;
|
||||
return 0;
|
||||
}
|
||||
|
||||
errcode_t ext2fs_patch_retry_read_at(int fd, unsigned long long offset, ssize_t size, void *buf)
|
||||
{
|
||||
if ((unsigned long long)ext2fs_llseek(fd, offset, SEEK_SET) != offset)
|
||||
return errno ? errno : EXT2_ET_LLSEEK_FAILED;
|
||||
return ext2fs_patch_retry_read(fd, size, buf);
|
||||
}
|
||||
|
||||
errcode_t ext2fs_patch_retry_write_at(int fd, unsigned long long offset, ssize_t size, const void *buf)
|
||||
{
|
||||
if ((unsigned long long)ext2fs_llseek(fd, offset, SEEK_SET) != offset)
|
||||
return errno ? errno : EXT2_ET_LLSEEK_FAILED;
|
||||
return ext2fs_patch_retry_write(fd, size, buf);
|
||||
}
|
||||
|
||||
errcode_t ext2fs_patch_read_bmap(struct ext2fs_patch_file *data)
|
||||
{
|
||||
errcode_t retval = 0;
|
||||
int bufsize = 65536;
|
||||
blk64_t i, r;
|
||||
void *buf = malloc(bufsize);
|
||||
if (!buf)
|
||||
return ENOMEM;
|
||||
ext2fs_llseek(data->patch_fd, data->block_size, SEEK_SET);
|
||||
for (i = 0; i < data->size/8; )
|
||||
{
|
||||
r = bufsize;
|
||||
if (data->size/8 - i < r)
|
||||
r = data->size/8 - i;
|
||||
retval = ext2fs_patch_retry_read(data->patch_fd, r, buf);
|
||||
if (retval)
|
||||
goto out;
|
||||
ext2fs_set_generic_bmap_range(data->bmap, i*8, r*8, buf);
|
||||
i += r;
|
||||
}
|
||||
out:
|
||||
free(buf);
|
||||
return retval;
|
||||
}
|
||||
|
||||
errcode_t ext2fs_patch_write_bmap(struct ext2fs_patch_file *data)
|
||||
{
|
||||
errcode_t retval = 0;
|
||||
int bufsize = 65536;
|
||||
blk64_t i, r;
|
||||
struct patchbd_super s;
|
||||
void *buf = malloc(bufsize);
|
||||
if (!buf)
|
||||
return ENOMEM;
|
||||
ext2fs_llseek(data->patch_fd, data->block_size, SEEK_SET);
|
||||
for (i = 0; i < data->size/8; )
|
||||
{
|
||||
r = bufsize;
|
||||
if (data->size/8 - i < r)
|
||||
r = data->size/8 - i;
|
||||
ext2fs_get_generic_bmap_range(data->bmap, i*8, r*8, buf);
|
||||
retval = ext2fs_patch_retry_write(data->patch_fd, r, buf);
|
||||
if (retval)
|
||||
goto out;
|
||||
i += r;
|
||||
}
|
||||
ext2fs_llseek(data->patch_fd, 0, SEEK_SET);
|
||||
s.magic = PATCHBD_MAGIC;
|
||||
s.patch_block = data->block_size;
|
||||
s.patch_size = data->size;
|
||||
write(data->patch_fd, &s, sizeof(struct patchbd_super));
|
||||
out:
|
||||
free(buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
errcode_t ext2fs_patch_open(struct ext2fs_patch_file *data, char *patch_file, int flags)
|
||||
{
|
||||
errcode_t retval = 0;
|
||||
ext2_loff_t size;
|
||||
struct patchbd_super s;
|
||||
data->block_size = 0;
|
||||
data->size = 0;
|
||||
data->offset = 0;
|
||||
data->bmap = NULL;
|
||||
data->patch_file = strdup(patch_file);
|
||||
data->patch_fd = open(data->patch_file, flags|O_RDWR, 0666);
|
||||
if (data->patch_fd < 0)
|
||||
return errno;
|
||||
size = ext2fs_llseek(data->patch_fd, 0, SEEK_END);
|
||||
if (size < 0)
|
||||
return errno;
|
||||
if (size > 0)
|
||||
{
|
||||
size = ext2fs_llseek(data->patch_fd, 0, SEEK_SET);
|
||||
read(data->patch_fd, &s, sizeof(struct patchbd_super));
|
||||
if (s.magic != PATCHBD_MAGIC)
|
||||
return 0;
|
||||
data->block_size = s.patch_block;
|
||||
// if (data->block_size != 4096)
|
||||
// return EINVAL;
|
||||
data->size = s.patch_size;
|
||||
retval = ext2fs_patch_init_bmap(data, NULL);
|
||||
if (retval)
|
||||
return retval;
|
||||
retval = ext2fs_patch_read_bmap(data);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
errcode_t ext2fs_patch_close(struct ext2fs_patch_file *data)
|
||||
{
|
||||
if (data)
|
||||
{
|
||||
if (data->bmap)
|
||||
{
|
||||
if (data->patch_fd >= 0)
|
||||
ext2fs_patch_write_bmap(data);
|
||||
ext2fs_free_generic_bmap(data->bmap);
|
||||
data->bmap = NULL;
|
||||
}
|
||||
if (data->patch_fd >= 0)
|
||||
{
|
||||
close(data->patch_fd);
|
||||
data->patch_fd = -1;
|
||||
}
|
||||
if (data->patch_file)
|
||||
{
|
||||
free(data->patch_file);
|
||||
data->patch_file = NULL;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
errcode_t ext2fs_patch_init_bmap(struct ext2fs_patch_file *data, io_channel channel)
|
||||
{
|
||||
errcode_t retval = 0;
|
||||
if (!data->bmap)
|
||||
{
|
||||
if (channel)
|
||||
{
|
||||
// channel is optional parameter, if passed, means 'take size from channel'
|
||||
data->block_size = channel->block_size;
|
||||
// if (data->block_size != 4096)
|
||||
// return EINVAL;
|
||||
retval = ext2fs_get_device_size2(channel->name, data->block_size, &data->size);
|
||||
if (retval)
|
||||
return retval;
|
||||
}
|
||||
else if (!data->block_size || !data->size)
|
||||
return EINVAL;
|
||||
retval = ext2fs_make_generic_bitmap(EXT2_ET_MAGIC_BLOCK_BITMAP, NULL,
|
||||
0, data->size, data->size, "overwritten blocks", 0, &data->bmap);
|
||||
data->offset = data->block_size + ((((data->size+7)>>3)+(data->block_size-1))&~(data->block_size-1));
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
errcode_t ext2fs_patch_write_blk64(struct ext2fs_patch_file *data, unsigned long long block, int count, const void *buf)
|
||||
{
|
||||
ssize_t size;
|
||||
if (!data->bmap)
|
||||
return EINVAL;
|
||||
if (count < 0)
|
||||
{
|
||||
if ((unsigned)-count > data->block_size)
|
||||
return EINVAL;
|
||||
size = -count;
|
||||
count = 1;
|
||||
}
|
||||
else
|
||||
size = count*data->block_size;
|
||||
ext2fs_mark_block_bitmap_range2(data->bmap, block, count);
|
||||
return ext2fs_patch_retry_write_at(data->patch_fd, data->offset + block*data->block_size, size, buf);
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
/**
|
||||
* patch.h --- Common "patch" file functions
|
||||
*
|
||||
* Patch file format:
|
||||
* 1) sparse data blocks - same size as the patched filesystem, but only changed blocks are written
|
||||
* 2) updated block bitmap - fs_size/block_size/8 bytes
|
||||
* 3) 4 byte FS block size
|
||||
* 4) 8 byte FS size in blocks
|
||||
*
|
||||
* Copyright (c) Vitaliy Filippov <vitalif@mail.ru> 2014
|
||||
* License: GNU GPLv2 or later
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef E2_PATCH_H
|
||||
#define E2_PATCH_H
|
||||
|
||||
#include "ext2_fs.h"
|
||||
#include "ext2fs.h"
|
||||
|
||||
#define PATCHBD_MAGIC 0x44623950 // P9bD
|
||||
|
||||
struct ext2fs_patch_file
|
||||
{
|
||||
char *patch_file;
|
||||
int patch_fd;
|
||||
__u32 block_size;
|
||||
blk64_t size;
|
||||
ext2_loff_t offset;
|
||||
ext2fs_generic_bitmap bmap;
|
||||
};
|
||||
|
||||
struct patchbd_super
|
||||
{
|
||||
__u32 magic;
|
||||
__u32 patch_block;
|
||||
__u64 patch_size;
|
||||
};
|
||||
|
||||
errcode_t ext2fs_patch_retry_read(int fd, ssize_t size, void *buf);
|
||||
errcode_t ext2fs_patch_retry_write(int fd, ssize_t size, const void *buf);
|
||||
errcode_t ext2fs_patch_retry_read_at(int fd, unsigned long long offset, ssize_t size, void *buf);
|
||||
errcode_t ext2fs_patch_retry_write_at(int fd, unsigned long long offset, ssize_t size, const void *buf);
|
||||
errcode_t ext2fs_patch_read_bmap(struct ext2fs_patch_file *data);
|
||||
errcode_t ext2fs_patch_write_bmap(struct ext2fs_patch_file *data);
|
||||
errcode_t ext2fs_patch_open(struct ext2fs_patch_file *data, char *patch_file, int flags);
|
||||
errcode_t ext2fs_patch_close(struct ext2fs_patch_file *data);
|
||||
errcode_t ext2fs_patch_init_bmap(struct ext2fs_patch_file *data, io_channel channel);
|
||||
errcode_t ext2fs_patch_write_blk64(struct ext2fs_patch_file *data, unsigned long long block, int count, const void *buf);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,375 @@
|
|||
/*
|
||||
* patch_io.c --- This is the "patch" io manager that writes the new data into
|
||||
* a separate sparse file to apply it later.
|
||||
*
|
||||
* Copyright (c) Vitaliy Filippov <vitalif@mail.ru> 2014
|
||||
* License: GNU GPLv2 or later
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#define _LARGEFILE_SOURCE
|
||||
#define _LARGEFILE64_SOURCE
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "ext2_fs.h"
|
||||
#include "ext2fs.h"
|
||||
|
||||
#include "patch.h"
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define ATTR(x) __attribute__(x)
|
||||
#else
|
||||
#define ATTR(x)
|
||||
#endif
|
||||
|
||||
#define EXT2_CHECK_MAGIC(struct, code) if ((struct)->magic != (code)) return (code)
|
||||
|
||||
struct patch_private_data
|
||||
{
|
||||
int magic;
|
||||
struct ext2fs_patch_file patch;
|
||||
/* The backing io channel */
|
||||
io_channel real;
|
||||
/* to support offset in unix I/O manager */
|
||||
ext2_loff_t offset;
|
||||
};
|
||||
|
||||
static errcode_t patch_open(const char *name, int flags, io_channel *channel);
|
||||
static errcode_t patch_close(io_channel channel);
|
||||
static errcode_t patch_set_blksize(io_channel channel, int blksize);
|
||||
static errcode_t patch_read_blk64(io_channel channel, unsigned long long block, int count, void *data);
|
||||
static errcode_t patch_write_blk64(io_channel channel, unsigned long long block, int count, const void *data);
|
||||
static errcode_t patch_read_blk(io_channel channel, unsigned long block, int count, void *data);
|
||||
static errcode_t patch_write_blk(io_channel channel, unsigned long block, int count, const void *data);
|
||||
static errcode_t patch_flush(io_channel channel);
|
||||
static errcode_t patch_write_byte(io_channel channel, unsigned long offset, int size, const void *data);
|
||||
static errcode_t patch_set_option(io_channel channel, const char *option, const char *arg);
|
||||
static errcode_t patch_get_stats(io_channel channel, io_stats *stats);
|
||||
|
||||
static struct struct_io_manager struct_patch_manager = {
|
||||
EXT2_ET_MAGIC_IO_MANAGER,
|
||||
"Patch I/O Manager",
|
||||
patch_open,
|
||||
patch_close,
|
||||
patch_set_blksize,
|
||||
patch_read_blk,
|
||||
patch_write_blk,
|
||||
patch_flush,
|
||||
patch_write_byte,
|
||||
patch_set_option,
|
||||
patch_get_stats,
|
||||
patch_read_blk64,
|
||||
patch_write_blk64,
|
||||
};
|
||||
|
||||
io_manager patch_io_manager = &struct_patch_manager;
|
||||
static char *patch_file;
|
||||
static io_manager patch_io_backing_manager;
|
||||
|
||||
errcode_t set_patch_io_backing_manager(io_manager manager)
|
||||
{
|
||||
patch_io_backing_manager = manager;
|
||||
return 0;
|
||||
}
|
||||
|
||||
errcode_t set_patch_io_patch_file(char *file)
|
||||
{
|
||||
patch_file = file;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static errcode_t patch_open(const char *name, int flags, io_channel *channel)
|
||||
{
|
||||
io_channel io = NULL;
|
||||
struct patch_private_data *data = NULL;
|
||||
errcode_t retval;
|
||||
|
||||
if (name == 0)
|
||||
return EXT2_ET_BAD_DEVICE_NAME;
|
||||
retval = ext2fs_get_mem(sizeof(struct struct_io_channel), &io);
|
||||
if (retval)
|
||||
goto cleanup;
|
||||
memset(io, 0, sizeof(struct struct_io_channel));
|
||||
io->magic = EXT2_ET_MAGIC_IO_CHANNEL;
|
||||
retval = ext2fs_get_mem(sizeof(struct patch_private_data), &data);
|
||||
if (retval)
|
||||
goto cleanup;
|
||||
|
||||
io->manager = patch_io_manager;
|
||||
retval = ext2fs_get_mem(strlen(name)+1, &io->name);
|
||||
if (retval)
|
||||
goto cleanup;
|
||||
|
||||
strcpy(io->name, name);
|
||||
io->private_data = data;
|
||||
io->block_size = 1024;
|
||||
io->read_error = 0;
|
||||
io->write_error = 0;
|
||||
io->refcount = 1;
|
||||
|
||||
memset(data, 0, sizeof(struct patch_private_data));
|
||||
data->magic = EXT2_ET_MAGIC_UNIX_IO_CHANNEL;
|
||||
|
||||
if (patch_io_backing_manager)
|
||||
{
|
||||
retval = patch_io_backing_manager->open(name, flags & ~IO_FLAG_RW, &data->real);
|
||||
if (retval)
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (patch_file)
|
||||
{
|
||||
retval = ext2fs_patch_open(&data->patch, patch_file, O_CREAT);
|
||||
if (retval)
|
||||
goto cleanup;
|
||||
if (data->patch.block_size)
|
||||
{
|
||||
retval = io_channel_set_blksize(data->real, data->patch.block_size);
|
||||
if (retval)
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
*channel = io;
|
||||
return 0;
|
||||
|
||||
cleanup:
|
||||
if (data)
|
||||
{
|
||||
ext2fs_patch_close(&data->patch);
|
||||
if (data->real)
|
||||
io_channel_close(data->real);
|
||||
ext2fs_free_mem(&data);
|
||||
}
|
||||
if (io)
|
||||
{
|
||||
if (io->name)
|
||||
ext2fs_free_mem(&io->name);
|
||||
ext2fs_free_mem(&io);
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
static errcode_t patch_close(io_channel channel)
|
||||
{
|
||||
struct patch_private_data *data;
|
||||
errcode_t retval = 0;
|
||||
|
||||
EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
|
||||
data = (struct patch_private_data *) channel->private_data;
|
||||
EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
|
||||
|
||||
if (--channel->refcount > 0)
|
||||
return 0;
|
||||
|
||||
ext2fs_patch_close(&data->patch);
|
||||
if (data->real)
|
||||
retval = io_channel_close(data->real);
|
||||
ext2fs_free_mem(&channel->private_data);
|
||||
if (channel->name)
|
||||
ext2fs_free_mem(&channel->name);
|
||||
ext2fs_free_mem(&channel);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static errcode_t patch_set_blksize(io_channel channel, int blksize)
|
||||
{
|
||||
struct patch_private_data *data;
|
||||
errcode_t retval = 0;
|
||||
|
||||
EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
|
||||
data = (struct patch_private_data *) channel->private_data;
|
||||
EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
|
||||
|
||||
channel->block_size = (unsigned)blksize;
|
||||
if (data->patch.block_size && data->patch.block_size != (unsigned)blksize)
|
||||
return EINVAL;
|
||||
if (data->real)
|
||||
retval = io_channel_set_blksize(data->real, blksize);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static errcode_t patch_read_blk64(io_channel channel, unsigned long long block, int count, void *buf)
|
||||
{
|
||||
errcode_t retval = 0;
|
||||
struct patch_private_data *data;
|
||||
int b, n;
|
||||
|
||||
EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
|
||||
data = (struct patch_private_data *) channel->private_data;
|
||||
EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
|
||||
|
||||
if (count < 0)
|
||||
{
|
||||
if (-count <= channel->block_size)
|
||||
{
|
||||
if (data->patch.bmap && ext2fs_test_generic_bitmap(data->patch.bmap, block))
|
||||
retval = ext2fs_patch_retry_read_at(data->patch.patch_fd, data->patch.offset + block*channel->block_size, -count, buf);
|
||||
else
|
||||
retval = io_channel_read_blk64(data->real, block, count, buf);
|
||||
return retval;
|
||||
}
|
||||
else
|
||||
return EINVAL;
|
||||
}
|
||||
for (b = 0; b < count; )
|
||||
{
|
||||
for (n = 0; (b+n < count) && data->patch.bmap && ext2fs_test_generic_bitmap(data->patch.bmap, block+b+n); n++) {}
|
||||
if (n > 0)
|
||||
{
|
||||
retval = ext2fs_patch_retry_read_at(data->patch.patch_fd, data->patch.offset + (block+b)*channel->block_size, n*channel->block_size, buf+b*channel->block_size);
|
||||
if (retval)
|
||||
break;
|
||||
b += n;
|
||||
}
|
||||
for (n = 0; (b+n < count) && (!data->patch.bmap || !ext2fs_test_generic_bitmap(data->patch.bmap, block+b+n)); n++) {}
|
||||
if (n > 0)
|
||||
{
|
||||
retval = io_channel_read_blk64(data->real, block+b, n, buf+b*channel->block_size);
|
||||
if (retval)
|
||||
break;
|
||||
b += n;
|
||||
}
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static errcode_t patch_read_blk(io_channel channel, unsigned long block, int count, void *buf)
|
||||
{
|
||||
return patch_read_blk64(channel, block, count, buf);
|
||||
}
|
||||
|
||||
static errcode_t patch_write_blk64(io_channel channel, unsigned long long block, int count, const void *buf)
|
||||
{
|
||||
struct patch_private_data *data;
|
||||
errcode_t retval = 0;
|
||||
|
||||
EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
|
||||
data = (struct patch_private_data *) channel->private_data;
|
||||
EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
|
||||
|
||||
retval = ext2fs_patch_init_bmap(&data->patch, channel);
|
||||
if (retval)
|
||||
return retval;
|
||||
// libext2fs changes block size to 1024 in order to write the superblock, so we must support it...
|
||||
if ((__u32)channel->block_size < data->patch.block_size)
|
||||
{
|
||||
void *buf2 = NULL;
|
||||
unsigned long long block_real = block / (data->patch.block_size / channel->block_size);
|
||||
int count_real = ( (block % (data->patch.block_size / channel->block_size))
|
||||
+ (count > 0 ? count*channel->block_size : -count)
|
||||
+ data->patch.block_size - 1 ) / data->patch.block_size;
|
||||
retval = ext2fs_get_mem(count_real * data->patch.block_size, &buf2);
|
||||
if (retval)
|
||||
goto out;
|
||||
retval = patch_read_blk64(channel, block_real, count_real, buf2);
|
||||
if (retval)
|
||||
goto out;
|
||||
memcpy(buf2 + (block % (data->patch.block_size / channel->block_size)) * channel->block_size,
|
||||
buf, (count > 0 ? count*channel->block_size : -count));
|
||||
retval = ext2fs_patch_write_blk64(&data->patch, block_real, count_real, buf2);
|
||||
out:
|
||||
if (buf2)
|
||||
ext2fs_free_mem(&buf2);
|
||||
return retval;
|
||||
}
|
||||
else if ((__u32)channel->block_size > data->patch.block_size)
|
||||
{
|
||||
return EXT2_ET_UNIMPLEMENTED;
|
||||
}
|
||||
return ext2fs_patch_write_blk64(&data->patch, block, count, buf);
|
||||
}
|
||||
|
||||
static errcode_t patch_write_blk(io_channel channel, unsigned long block, int count, const void *buf)
|
||||
{
|
||||
return patch_write_blk64(channel, block, count, buf);
|
||||
}
|
||||
|
||||
static errcode_t patch_write_byte(io_channel channel, unsigned long offset, int size, const void *buf)
|
||||
{
|
||||
return EXT2_ET_UNIMPLEMENTED;
|
||||
}
|
||||
|
||||
/*
|
||||
* Flush data buffers to disk.
|
||||
*/
|
||||
static errcode_t patch_flush(io_channel channel)
|
||||
{
|
||||
errcode_t retval = 0;
|
||||
struct patch_private_data *data;
|
||||
|
||||
EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
|
||||
data = (struct patch_private_data *) channel->private_data;
|
||||
EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
|
||||
|
||||
if (data->real)
|
||||
retval = io_channel_flush(data->real);
|
||||
if (data->patch.patch_fd)
|
||||
fsync(data->patch.patch_fd);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static errcode_t patch_set_option(io_channel channel, const char *option, const char *arg)
|
||||
{
|
||||
errcode_t retval = 0;
|
||||
struct patch_private_data *data;
|
||||
unsigned long tmp;
|
||||
char *end;
|
||||
|
||||
EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
|
||||
data = (struct patch_private_data *) channel->private_data;
|
||||
EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
|
||||
|
||||
/*
|
||||
* Need to support offset option to work with
|
||||
* Unix I/O manager
|
||||
*/
|
||||
if (data->real && data->real->manager->set_option)
|
||||
retval = data->real->manager->set_option(data->real, option, arg);
|
||||
if (!retval && !strcmp(option, "offset"))
|
||||
{
|
||||
if (!arg)
|
||||
return EXT2_ET_INVALID_ARGUMENT;
|
||||
|
||||
tmp = strtoul(arg, &end, 0);
|
||||
if (*end)
|
||||
return EXT2_ET_INVALID_ARGUMENT;
|
||||
data->offset = tmp;
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
static errcode_t patch_get_stats(io_channel channel, io_stats *stats)
|
||||
{
|
||||
errcode_t retval = 0;
|
||||
struct patch_private_data *data;
|
||||
|
||||
EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
|
||||
data = (struct patch_private_data *) channel->private_data;
|
||||
EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
|
||||
|
||||
if (data->real)
|
||||
retval = (data->real->manager->get_stats)(data->real, stats);
|
||||
|
||||
return retval;
|
||||
}
|
|
@ -307,6 +307,8 @@ void ext2fs_swap_inode_full(ext2_filsys fs, struct ext2_inode_large *t,
|
|||
/* this is error case: i_extra_size is too large */
|
||||
return;
|
||||
}
|
||||
if (extra_isize & 3)
|
||||
return; /* Illegal inode extra_isize */
|
||||
|
||||
inode_size = EXT2_GOOD_OLD_INODE_SIZE + extra_isize;
|
||||
if (inode_includes(inode_size, i_checksum_hi))
|
||||
|
|
|
@ -300,6 +300,7 @@ static errcode_t raw_write_blk(io_channel channel,
|
|||
goto short_write;
|
||||
size -= actual;
|
||||
buf += actual;
|
||||
location += actual;
|
||||
}
|
||||
return 0;
|
||||
|
||||
|
|
|
@ -33,12 +33,12 @@ INSTALL = @INSTALL@
|
|||
@FUSE_CMT@FUSE_PROG= fuse2fs
|
||||
|
||||
SPROGS= mke2fs badblocks tune2fs dumpe2fs $(BLKID_PROG) logsave \
|
||||
$(E2IMAGE_PROG) @FSCK_PROG@ e2undo
|
||||
$(E2IMAGE_PROG) @FSCK_PROG@ e2undo e2patch
|
||||
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 \
|
||||
logsave.8 filefrag.8 e2freefrag.8 e2undo.8 e2patch.8 \
|
||||
$(UUIDD_MAN) $(E4DEFRAG_MAN) $(E4CRYPT_MAN) @FSCK_MAN@
|
||||
FMANPAGES= mke2fs.conf.5 ext4.5
|
||||
|
||||
|
@ -63,6 +63,7 @@ FSCK_OBJS= fsck.o base_device.o ismounted.o
|
|||
BLKID_OBJS= blkid.o
|
||||
FILEFRAG_OBJS= filefrag.o
|
||||
E2UNDO_OBJS= e2undo.o
|
||||
E2PATCH_OBJS= e2patch.o
|
||||
E4DEFRAG_OBJS= e4defrag.o
|
||||
E4CRYPT_OBJS= e4crypt.o
|
||||
E2FREEFRAG_OBJS= e2freefrag.o
|
||||
|
@ -88,6 +89,7 @@ PROFILED_BLKID_OBJS= profiled/blkid.o
|
|||
PROFILED_FILEFRAG_OBJS= profiled/filefrag.o
|
||||
PROFILED_E2FREEFRAG_OBJS= profiled/e2freefrag.o
|
||||
PROFILED_E2UNDO_OBJS= profiled/e2undo.o
|
||||
PROFILED_E2PATCH_OBJS= profiled/e2patch.o
|
||||
PROFILED_E4DEFRAG_OBJS= profiled/e4defrag.o
|
||||
PROFILED_E4CRYPT_OBJS= profiled/e4crypt.o
|
||||
PROFILED_FUSE2FS_OJBS= profiled/fuse2fs.o profiled/journal.o \
|
||||
|
@ -98,7 +100,7 @@ SRCS= $(srcdir)/tune2fs.c $(srcdir)/mklost+found.c $(srcdir)/mke2fs.c $(srcdir)/
|
|||
$(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)/e2undo.c \
|
||||
$(srcdir)/ismounted.c $(srcdir)/e2undo.c $(srcdir)/e2patch.c \
|
||||
$(srcdir)/e2freefrag.c $(srcdir)/create_inode.c \
|
||||
$(srcdir)/fuse2fs.c \
|
||||
$(srcdir)/../debugfs/journal.c $(srcdir)/../e2fsck/revoke.c \
|
||||
|
@ -133,7 +135,7 @@ all:: profiled $(SPROGS) $(UPROGS) $(USPROGS) $(SMANPAGES) $(UMANPAGES) \
|
|||
$(FMANPAGES) $(LPROGS) $(E4DEFRAG_PROG) $(E4CRYPT_PROGS) e2fuzz
|
||||
|
||||
@PROFILE_CMT@all:: tune2fs.profiled blkid.profiled e2image.profiled \
|
||||
e2undo.profiled mke2fs.profiled dumpe2fs.profiled fsck.profiled \
|
||||
e2undo.profiled e2patch.profiled mke2fs.profiled dumpe2fs.profiled fsck.profiled \
|
||||
logsave.profiled filefrag.profiled uuidgen.profiled $(UUIDD_PROFILED) \
|
||||
e2image.profiled e4defrag.profiled e4crypt.profiled \
|
||||
e2freefrag.profiled
|
||||
|
@ -226,6 +228,16 @@ e2undo.profiled: $(E2UNDO_OBJS) $(PROFILED_DEPLIBS)
|
|||
$(Q) $(CC) $(ALL_LDFLAGS) -g -pg -o e2undo.profiled \
|
||||
$(PROFILED_E2UNDO_OBJS) $(PROFILED_LIBS) $(LIBINTL) $(SYSLIBS)
|
||||
|
||||
e2patch: $(E2PATCH_OBJS) $(DEPLIBS)
|
||||
$(E) " LD $@"
|
||||
$(Q) $(CC) $(ALL_LDFLAGS) -o e2patch $(E2PATCH_OBJS) $(LIBS) \
|
||||
$(LIBINTL) $(SYSLIBS)
|
||||
|
||||
e2patch.profiled: $(E2PATCH_OBJS) $(PROFILED_DEPLIBS)
|
||||
$(E) " LD $@"
|
||||
$(Q) $(CC) $(ALL_LDFLAGS) -g -pg -o e2patch.profiled \
|
||||
$(PROFILED_E2PATCH_OBJS) $(PROFILED_LIBS) $(LIBINTL) $(SYSLIBS)
|
||||
|
||||
e4defrag: $(E4DEFRAG_OBJS) $(DEPLIBS)
|
||||
$(E) " LD $@"
|
||||
$(Q) $(CC) $(ALL_LDFLAGS) -o e4defrag $(E4DEFRAG_OBJS) $(LIBS) \
|
||||
|
@ -439,6 +451,10 @@ e2undo.8: $(DEP_SUBSTITUTE) $(srcdir)/e2undo.8.in
|
|||
$(E) " SUBST $@"
|
||||
$(Q) $(SUBSTITUTE_UPTIME) $(srcdir)/e2undo.8.in e2undo.8
|
||||
|
||||
e2patch.8: $(DEP_SUBSTITUTE) $(srcdir)/e2patch.8.in
|
||||
$(E) " SUBST $@"
|
||||
$(Q) $(SUBSTITUTE_UPTIME) $(srcdir)/e2patch.8.in e2patch.8
|
||||
|
||||
findfs.8: $(DEP_SUBSTITUTE) $(srcdir)/findfs.8.in
|
||||
$(E) " SUBST $@"
|
||||
$(Q) $(SUBSTITUTE_UPTIME) $(srcdir)/findfs.8.in findfs.8
|
||||
|
@ -669,7 +685,7 @@ clean::
|
|||
e2initrd_helper partinfo prof_err.[ch] default_profile.c \
|
||||
uuidd e2image tune2fs.static tst_ismounted fsck.profiled \
|
||||
blkid.profiled tune2fs.profiled e2image.profiled \
|
||||
e2undo.profiled mke2fs.profiled dumpe2fs.profiled \
|
||||
e2undo.profiled e2patch.profiled mke2fs.profiled dumpe2fs.profiled \
|
||||
logsave.profiled filefrag.profiled uuidgen.profiled \
|
||||
uuidd.profiled e2image.profiled e2fuzz mke2fs.conf \
|
||||
profiled/*.o \#* *.s *.o *.a *~ core gmon.out
|
||||
|
@ -792,6 +808,12 @@ e2undo.o: $(srcdir)/e2undo.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 \
|
||||
$(top_srcdir)/lib/support/nls-enable.h
|
||||
e2patch.o: $(srcdir)/e2patch.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
|
||||
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 \
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
.TH E2PATCH 8 "@E2FSPROGS_MONTH@ @E2FSPROGS_YEAR@" "E2fsprogs version @E2FSPROGS_VERSION@"
|
||||
.SH NAME
|
||||
e2patch \- patch tool for safely applying libext2fs patch files to block devices
|
||||
.SH SYNOPSIS
|
||||
.B e2patch backup \fI<device>\fR \fI<patch_file>\fR \fI<backup_file>\fR
|
||||
.br
|
||||
.B e2patch apply \fI<device>\fR \fI<patch_file>\fR
|
||||
.SH DESCRIPTION
|
||||
.B e2patch
|
||||
applies and restores "patches" produced by e2fsprogs with patch file option
|
||||
(\fBresize2fs -T <patch_file>\fR) to block devices.
|
||||
.PP
|
||||
"Patch files" are sparse files containing overwritten device blocks and
|
||||
a block bitmap.
|
||||
.PP
|
||||
"Patch files" are faster, safer and simpler to use than "undo files"
|
||||
(\fBe2undo\fR and \fBresize2fs -z <undo_file>\fR), even though their original
|
||||
design goal is similar.
|
||||
.SH COMMANDS
|
||||
.TP
|
||||
.B e2patch backup \fI<device>\fR \fI<patch_file>\fR \fI<backup_file>\fR
|
||||
Creates a backup in <backup_file> for restoring after bad patch <patch_file>.
|
||||
Backup can then also be applied with \fBe2patch apply\fR
|
||||
.TP
|
||||
.B e2patch apply \fI<device>\fR \fI<patch_file>\fR
|
||||
Apply <patch_file> to <device>.
|
||||
.SH AUTHOR
|
||||
Written by Vitaliy Filippov <vitalif@mail.ru>
|
||||
.SH SEE ALSO
|
||||
.BR resize2fs (8),
|
||||
.BR e2undo (8).
|
|
@ -0,0 +1,166 @@
|
|||
/**
|
||||
* e2patch.c --- Utility to apply/restore patches created by patch_io_manager.
|
||||
*
|
||||
* Copyright (c) Vitaliy Filippov <vitalif@mail.ru> 2014
|
||||
* License: GNU GPLv2 or later
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "ext2fs/ext2_fs.h"
|
||||
#include "ext2fs/ext2fs.h"
|
||||
|
||||
#include "ext2fs/patch.h"
|
||||
|
||||
#define BUF 0x10000
|
||||
#define _(a) (a)
|
||||
|
||||
errcode_t make_backup_patch(char *device, char *io_options, char *patch_file, char *backup_file)
|
||||
{
|
||||
io_manager mgr = unix_io_manager;
|
||||
io_channel io;
|
||||
errcode_t retval;
|
||||
blk64_t blk, start, buf_blocks;
|
||||
int eq;
|
||||
void *buf = NULL;
|
||||
struct ext2fs_patch_file patch = { 0 }, backup = { 0 };
|
||||
retval = mgr->open(device, IO_FLAG_EXCLUSIVE, &io);
|
||||
if (retval) goto out;
|
||||
if (io_options &&
|
||||
(retval = io_channel_set_options(io, io_options)))
|
||||
goto out;
|
||||
retval = ext2fs_patch_open(&patch, patch_file, 0);
|
||||
if (retval) goto out;
|
||||
retval = ext2fs_patch_open(&backup, backup_file, O_CREAT);
|
||||
if (retval) goto out;
|
||||
backup.block_size = patch.block_size;
|
||||
backup.size = patch.size;
|
||||
ext2fs_patch_init_bmap(&backup, NULL);
|
||||
buf_blocks = BUF/patch.block_size;
|
||||
retval = mgr->set_blksize(io, patch.block_size);
|
||||
if (retval) goto out;
|
||||
buf = malloc(BUF);
|
||||
for (start = 0, blk = 0; blk <= patch.size; blk++)
|
||||
{
|
||||
if ((eq = !ext2fs_test_generic_bitmap(patch.bmap, blk)) || blk >= patch.size || blk-start >= buf_blocks)
|
||||
{
|
||||
if (start != blk)
|
||||
{
|
||||
retval = io_channel_read_blk64(io, start, blk-start, buf);
|
||||
if (retval) goto out;
|
||||
retval = ext2fs_patch_write_blk64(&backup, start, blk-start, buf);
|
||||
if (retval) goto out;
|
||||
}
|
||||
start = blk+eq;
|
||||
}
|
||||
}
|
||||
out:
|
||||
if (buf)
|
||||
free(buf);
|
||||
ext2fs_patch_close(&backup);
|
||||
ext2fs_patch_close(&patch);
|
||||
mgr->close(io);
|
||||
return retval;
|
||||
}
|
||||
|
||||
errcode_t apply_patch(char *device, char *io_options, char *patch_file)
|
||||
{
|
||||
io_manager mgr = unix_io_manager;
|
||||
io_channel io;
|
||||
errcode_t retval;
|
||||
blk64_t blk, start, buf_blocks;
|
||||
int eq;
|
||||
void *buf = NULL;
|
||||
struct ext2fs_patch_file patch = { 0 };
|
||||
retval = mgr->open(device, IO_FLAG_EXCLUSIVE|IO_FLAG_RW, &io);
|
||||
if (retval) goto out;
|
||||
if (io_options &&
|
||||
(retval = io_channel_set_options(io, io_options)))
|
||||
goto out;
|
||||
retval = ext2fs_patch_open(&patch, patch_file, 0);
|
||||
if (retval) goto out;
|
||||
buf_blocks = BUF/patch.block_size;
|
||||
retval = mgr->set_blksize(io, patch.block_size);
|
||||
if (retval) goto out;
|
||||
buf = malloc(BUF);
|
||||
for (start = 0, blk = 0; blk <= patch.size; blk++)
|
||||
{
|
||||
if ((eq = blk < patch.size && !ext2fs_test_generic_bitmap(patch.bmap, blk)) || blk >= patch.size || blk-start >= buf_blocks)
|
||||
{
|
||||
if (start != blk)
|
||||
{
|
||||
retval = ext2fs_patch_retry_read_at(patch.patch_fd, patch.offset + start*patch.block_size, (blk-start)*patch.block_size, buf);
|
||||
if (retval) goto out;
|
||||
retval = io_channel_write_blk64(io, start, blk-start, buf);
|
||||
if (retval) goto out;
|
||||
}
|
||||
start = blk+eq;
|
||||
}
|
||||
}
|
||||
out:
|
||||
if (buf)
|
||||
free(buf);
|
||||
ext2fs_patch_close(&patch);
|
||||
mgr->close(io);
|
||||
return retval;
|
||||
}
|
||||
|
||||
int main(int narg, char **args)
|
||||
{
|
||||
errcode_t retval;
|
||||
char *io_options = NULL;
|
||||
if (narg >= 5 && !strcmp(args[1], "backup"))
|
||||
{
|
||||
io_options = strchr(args[2], '?');
|
||||
if (io_options)
|
||||
*io_options++ = 0;
|
||||
retval = make_backup_patch(args[2], io_options, args[3], args[4]);
|
||||
}
|
||||
else if (narg >= 4 && !strcmp(args[1], "apply"))
|
||||
{
|
||||
io_options = strchr(args[2], '?');
|
||||
if (io_options)
|
||||
*io_options++ = 0;
|
||||
retval = apply_patch(args[2], io_options, args[3]);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf(
|
||||
"Patch tool for safely applying changes to block devices\n"
|
||||
"License: GNU GPLv2 or later\n"
|
||||
"Copyright (c) Vitaliy Filippov, 2014\n\n"
|
||||
"To create a backup for restoring after bad patch:\n"
|
||||
" e2patch backup <filesystem> <patch_file> <backup_file>\n"
|
||||
"To apply a patch:\n"
|
||||
" e2patch apply <filesystem> <patch_file>\n"
|
||||
);
|
||||
return 0;
|
||||
}
|
||||
if (retval)
|
||||
{
|
||||
com_err("e2patch", retval, _("while trying to %s"), args[1]);
|
||||
}
|
||||
return 0;
|
||||
}
|
|
@ -474,6 +474,10 @@ static int frag_report(const char *filename)
|
|||
}
|
||||
|
||||
if (force_bmap || rc < 0) { /* FIEMAP failed, try FIBMAP instead */
|
||||
if (numblocks > (unsigned long)-1L) {
|
||||
fprintf(stderr, "%s: File too big to use FIBMAP\n", filename);
|
||||
goto out_close;
|
||||
}
|
||||
expected = filefrag_fibmap(fd, blk_shift, &num_extents,
|
||||
&st, numblocks, is_ext2);
|
||||
if (expected < 0) {
|
||||
|
|
|
@ -11,11 +11,11 @@
|
|||
features = has_journal
|
||||
}
|
||||
ext4 = {
|
||||
features = has_journal,extent,huge_file,flex_bg,metadata_csum,64bit,dir_nlink,extra_isize
|
||||
features = has_journal,extent,huge_file,flex_bg,64bit,dir_nlink,extra_isize
|
||||
inode_size = 256
|
||||
}
|
||||
ext4dev = {
|
||||
features = has_journal,extent,huge_file,flex_bg,metadata_csum,inline_data,64bit,dir_nlink,extra_isize
|
||||
features = has_journal,extent,huge_file,flex_bg,inline_data,64bit,dir_nlink,extra_isize
|
||||
inode_size = 256
|
||||
options = test_fs=1
|
||||
}
|
||||
|
|
|
@ -43,6 +43,7 @@ misc/e2image.c
|
|||
misc/e2initrd_helper.c
|
||||
misc/e2label.c
|
||||
misc/e2undo.c
|
||||
misc/e2patch.c
|
||||
misc/e4crypt.c
|
||||
misc/e4defrag.c
|
||||
misc/filefrag.c
|
||||
|
|
614
po/e2fsprogs.pot
614
po/e2fsprogs.pot
File diff suppressed because it is too large
Load Diff
BIN
po/zh_CN.gmo
BIN
po/zh_CN.gmo
Binary file not shown.
895
po/zh_CN.po
895
po/zh_CN.po
File diff suppressed because it is too large
Load Diff
|
@ -46,8 +46,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 [-b|-s|new_size] [-z undo_file]\n\n"),
|
||||
fprintf (stderr, _("Usage: %s [-d debug_flags] [-f] [-F] [-M] [-N new_inodes] [-P] "
|
||||
"[-p] device [-b|-s|new_size] [-T patch_file] [-z undo_file]\n\n"),
|
||||
prog);
|
||||
|
||||
exit (1);
|
||||
|
@ -167,6 +167,20 @@ static void bigalloc_check(ext2_filsys fs, int force)
|
|||
}
|
||||
}
|
||||
|
||||
static int resize2fs_setup_patch(const char *device, char *patch_file,
|
||||
io_manager *io_ptr)
|
||||
{
|
||||
set_patch_io_backing_manager(*io_ptr);
|
||||
set_patch_io_patch_file(patch_file);
|
||||
*io_ptr = patch_io_manager;
|
||||
printf(_("To make backup before applying changes run:\n"
|
||||
" e2patch backup %s %s %s.backup\n"
|
||||
"Then, to apply the operation to the real filesystem run:\n"
|
||||
" e2patch apply %s %s\n"),
|
||||
device, patch_file, patch_file, device, patch_file);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int resize2fs_setup_tdb(const char *device, char *undo_file,
|
||||
io_manager *io_ptr)
|
||||
{
|
||||
|
@ -258,6 +272,7 @@ int main (int argc, char ** argv)
|
|||
blk64_t new_size = 0;
|
||||
blk64_t max_size = 0;
|
||||
blk64_t min_size = 0;
|
||||
__u32 new_inodes = 0;
|
||||
io_manager io_ptr;
|
||||
char *new_size_str = 0;
|
||||
int use_stride = -1;
|
||||
|
@ -267,7 +282,7 @@ int main (int argc, char ** argv)
|
|||
unsigned int blocksize;
|
||||
long sysval;
|
||||
int len, mount_flags;
|
||||
char *mtpt, *undo_file = NULL;
|
||||
char *mtpt, *undo_file = NULL, *patch_file = NULL;
|
||||
|
||||
#ifdef ENABLE_NLS
|
||||
setlocale(LC_MESSAGES, "");
|
||||
|
@ -284,7 +299,7 @@ int main (int argc, char ** argv)
|
|||
if (argc && *argv)
|
||||
program_name = *argv;
|
||||
|
||||
while ((c = getopt(argc, argv, "d:fFhMPpS:bsz:")) != EOF) {
|
||||
while ((c = getopt(argc, argv, "d:fFhMPN:pS:bsT:z:")) != EOF) {
|
||||
switch (c) {
|
||||
case 'h':
|
||||
usage(program_name);
|
||||
|
@ -301,6 +316,9 @@ int main (int argc, char ** argv)
|
|||
case 'P':
|
||||
print_min_size = 1;
|
||||
break;
|
||||
case 'N':
|
||||
new_inodes = strtoul(optarg, 0, 0);
|
||||
break;
|
||||
case 'd':
|
||||
flags |= atoi(optarg);
|
||||
break;
|
||||
|
@ -316,6 +334,9 @@ int main (int argc, char ** argv)
|
|||
case 's':
|
||||
flags |= RESIZE_DISABLE_64BIT;
|
||||
break;
|
||||
case 'T':
|
||||
patch_file = optarg;
|
||||
break;
|
||||
case 'z':
|
||||
undo_file = optarg;
|
||||
break;
|
||||
|
@ -402,7 +423,11 @@ int main (int argc, char ** argv)
|
|||
io_flags = EXT2_FLAG_RW | EXT2_FLAG_EXCLUSIVE;
|
||||
|
||||
io_flags |= EXT2_FLAG_64BITS;
|
||||
if (undo_file) {
|
||||
if (patch_file) {
|
||||
retval = resize2fs_setup_patch(device_name, patch_file, &io_ptr);
|
||||
if (retval)
|
||||
exit(1);
|
||||
} else if (undo_file) {
|
||||
retval = resize2fs_setup_tdb(device_name, undo_file, &io_ptr);
|
||||
if (retval)
|
||||
exit(1);
|
||||
|
@ -583,7 +608,7 @@ int main (int argc, char ** argv)
|
|||
"feature.\n"));
|
||||
exit(1);
|
||||
}
|
||||
} else if (new_size == ext2fs_blocks_count(fs->super)) {
|
||||
} else if (new_size == ext2fs_blocks_count(fs->super) && !new_inodes) {
|
||||
fprintf(stderr, _("The filesystem is already %llu (%dk) "
|
||||
"blocks long. Nothing to do!\n\n"), new_size,
|
||||
blocksize / 1024);
|
||||
|
@ -612,7 +637,7 @@ int main (int argc, char ** argv)
|
|||
printf(_("Resizing the filesystem on "
|
||||
"%s to %llu (%dk) blocks.\n"),
|
||||
device_name, new_size, blocksize / 1024);
|
||||
retval = resize_fs(fs, &new_size, flags,
|
||||
retval = resize_fs(fs, &new_size, new_inodes, flags,
|
||||
((flags & RESIZE_PERCENT_COMPLETE) ?
|
||||
resize_progress_func : 0));
|
||||
}
|
||||
|
|
|
@ -159,6 +159,12 @@ 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 \-T " patch_file"
|
||||
Do not apply changes to the real filesystem; write updates into a sparse file
|
||||
named 'patch_file' to safely apply them later with e2patch(8) utility.
|
||||
You'll also be able to create a backup before applying patch and safely
|
||||
restore it in case of power outage or system crash.
|
||||
.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
|
||||
|
|
|
@ -45,19 +45,21 @@ static void fix_uninit_block_bitmaps(ext2_filsys fs);
|
|||
static errcode_t adjust_superblock(ext2_resize_t rfs, blk64_t new_size);
|
||||
static errcode_t blocks_to_move(ext2_resize_t rfs);
|
||||
static errcode_t block_mover(ext2_resize_t rfs);
|
||||
static errcode_t inodes_to_move(ext2_resize_t rfs);
|
||||
static errcode_t inode_scan_and_fix(ext2_resize_t rfs);
|
||||
static errcode_t inode_ref_fix(ext2_resize_t rfs);
|
||||
static errcode_t move_itables(ext2_resize_t rfs);
|
||||
static errcode_t move_inode_tables(ext2_resize_t rfs);
|
||||
static errcode_t fix_resize_inode(ext2_filsys fs);
|
||||
static errcode_t ext2fs_calculate_summary_stats(ext2_filsys fs);
|
||||
static errcode_t fix_sb_journal_backup(ext2_filsys fs);
|
||||
static errcode_t mark_table_blocks(ext2_filsys fs,
|
||||
ext2fs_block_bitmap bmap);
|
||||
ext2fs_block_bitmap bmap, int skip_inode_tables);
|
||||
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 move_bg_metadata(ext2_resize_t rfs, __u32 new_inodes);
|
||||
static errcode_t zero_high_bits_in_inodes(ext2_resize_t rfs);
|
||||
|
||||
/*
|
||||
|
@ -94,7 +96,7 @@ static int lazy_itable_init;
|
|||
/*
|
||||
* This is the top-level routine which does the dirty deed....
|
||||
*/
|
||||
errcode_t resize_fs(ext2_filsys fs, blk64_t *new_size, int flags,
|
||||
errcode_t resize_fs(ext2_filsys fs, blk64_t *new_size, __u32 new_inodes, int flags,
|
||||
errcode_t (*progress)(ext2_resize_t rfs, int pass,
|
||||
unsigned long cur,
|
||||
unsigned long max_val))
|
||||
|
@ -142,7 +144,7 @@ errcode_t resize_fs(ext2_filsys fs, blk64_t *new_size, int flags,
|
|||
print_resource_track(rfs, &rtrack, fs->io);
|
||||
|
||||
init_resource_track(&rtrack, "move_bg_metadata", fs->io);
|
||||
retval = move_bg_metadata(rfs);
|
||||
retval = move_bg_metadata(rfs, new_inodes);
|
||||
if (retval)
|
||||
goto errout;
|
||||
print_resource_track(rfs, &rtrack, fs->io);
|
||||
|
@ -188,6 +190,18 @@ errcode_t resize_fs(ext2_filsys fs, blk64_t *new_size, int flags,
|
|||
goto errout;
|
||||
print_resource_track(rfs, &rtrack, fs->io);
|
||||
|
||||
init_resource_track(&rtrack, "inodes_to_move", fs->io);
|
||||
retval = inodes_to_move(rfs);
|
||||
if (retval)
|
||||
goto errout;
|
||||
print_resource_track(rfs, &rtrack, fs->io);
|
||||
|
||||
init_resource_track(&rtrack, "move_inode_tables", fs->io);
|
||||
retval = move_inode_tables(rfs);
|
||||
if (retval)
|
||||
goto errout;
|
||||
print_resource_track(rfs, &rtrack, fs->io);
|
||||
|
||||
init_resource_track(&rtrack, "inode_scan_and_fix", fs->io);
|
||||
retval = inode_scan_and_fix(rfs);
|
||||
if (retval)
|
||||
|
@ -200,11 +214,11 @@ errcode_t resize_fs(ext2_filsys fs, blk64_t *new_size, int flags,
|
|||
goto errout;
|
||||
print_resource_track(rfs, &rtrack, fs->io);
|
||||
|
||||
init_resource_track(&rtrack, "move_itables", fs->io);
|
||||
/* init_resource_track(&rtrack, "move_itables", fs->io);
|
||||
retval = move_itables(rfs);
|
||||
if (retval)
|
||||
goto errout;
|
||||
print_resource_track(rfs, &rtrack, fs->io);
|
||||
print_resource_track(rfs, &rtrack, fs->io);*/
|
||||
|
||||
retval = clear_sparse_super2_last_group(rfs);
|
||||
if (retval)
|
||||
|
@ -344,8 +358,39 @@ static errcode_t resize_group_descriptors(ext2_resize_t rfs, blk64_t new_size)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inode table resizing:
|
||||
* 1) move_bg_metadata(), calls set_inode_count(): set new inode count
|
||||
* 2) adjust_superblock(): extend bitmaps, write group descriptors
|
||||
* 3) blocks_to_move(): allocate new inode tables and, when extending inode tables,
|
||||
* mark extra blocks needed for new inode tables as 'blocks to move'
|
||||
* 4) block_mover(): move blocks out of the way as usual
|
||||
* 5) inodes_to_move(): when shrinking inode tables, move inodes from the end
|
||||
* of each group's inode table (still operating on old fs inode tables).
|
||||
* it would be possible to rewrite blocks on step 7, but we need to read
|
||||
* extents, and they may be overwritten by inode tables on step 6.
|
||||
* so, rewrite blocks used by inodes here!
|
||||
* 6) move_inode_tables(): move inode tables
|
||||
* 7) inode_scan_and_fix(): rewrite all inode, extent, extattr and ACL checksums
|
||||
* 8) inode_ref_fix(): translate inode numbers (operating on new fs inode tables)
|
||||
*/
|
||||
static int set_inode_count(ext2_filsys fs, __u32 new_inodes)
|
||||
{
|
||||
__u32 old_ipg = fs->super->s_inodes_per_group;
|
||||
__u32 new_ipg = ((new_inodes + fs->group_desc_count - 1) / fs->group_desc_count);
|
||||
new_ipg = (((new_ipg * EXT2_INODE_SIZE(fs->super)) + EXT2_BLOCK_SIZE(fs->super) - 1) / EXT2_BLOCK_SIZE(fs->super))
|
||||
* EXT2_BLOCK_SIZE(fs->super) / EXT2_INODE_SIZE(fs->super);
|
||||
if (new_ipg == old_ipg)
|
||||
return -1;
|
||||
fs->inode_blocks_per_group = new_ipg * EXT2_INODE_SIZE(fs->super) / EXT2_BLOCK_SIZE(fs->super);
|
||||
fs->super->s_inodes_per_group = new_ipg;
|
||||
fs->super->s_inodes_count = fs->group_desc_count * fs->super->s_inodes_per_group;
|
||||
fs->super->s_free_inodes_count += fs->group_desc_count * (new_ipg - old_ipg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Move bitmaps/inode tables out of the way. */
|
||||
static errcode_t move_bg_metadata(ext2_resize_t rfs)
|
||||
static errcode_t move_bg_metadata(ext2_resize_t rfs, __u32 new_inodes)
|
||||
{
|
||||
dgrp_t i;
|
||||
blk64_t b, c, d, old_desc_blocks, new_desc_blocks, j;
|
||||
|
@ -354,7 +399,12 @@ static errcode_t move_bg_metadata(ext2_resize_t rfs)
|
|||
errcode_t retval;
|
||||
int cluster_ratio;
|
||||
|
||||
if (!(rfs->flags & (RESIZE_DISABLE_64BIT | RESIZE_ENABLE_64BIT)))
|
||||
if (new_inodes) {
|
||||
if (set_inode_count(rfs->new_fs, new_inodes) != 0)
|
||||
new_inodes = 0;
|
||||
}
|
||||
|
||||
if (!new_inodes && !(rfs->flags & (RESIZE_DISABLE_64BIT | RESIZE_ENABLE_64BIT)))
|
||||
return 0;
|
||||
|
||||
retval = ext2fs_allocate_block_bitmap(rfs->old_fs, "oldfs", &old_map);
|
||||
|
@ -644,7 +694,7 @@ static errcode_t free_gdp_blocks(ext2_filsys fs,
|
|||
if (retval)
|
||||
goto out;
|
||||
|
||||
retval = mark_table_blocks(fs, bg_map);
|
||||
retval = mark_table_blocks(fs, bg_map, 0);
|
||||
if (retval)
|
||||
goto out;
|
||||
}
|
||||
|
@ -1011,7 +1061,7 @@ retry:
|
|||
* number of the block group descriptors.
|
||||
*/
|
||||
if (reserve_blocks)
|
||||
mark_table_blocks(fs, reserve_blocks);
|
||||
mark_table_blocks(fs, reserve_blocks, 0);
|
||||
|
||||
errout:
|
||||
return (retval);
|
||||
|
@ -1145,7 +1195,7 @@ errout:
|
|||
* filesystem meta-data blocks.
|
||||
*/
|
||||
static errcode_t mark_table_blocks(ext2_filsys fs,
|
||||
ext2fs_block_bitmap bmap)
|
||||
ext2fs_block_bitmap bmap, int skip_inode_tables)
|
||||
{
|
||||
dgrp_t i;
|
||||
blk64_t blk;
|
||||
|
@ -1156,10 +1206,12 @@ static errcode_t mark_table_blocks(ext2_filsys fs,
|
|||
/*
|
||||
* Mark the blocks used for the inode table
|
||||
*/
|
||||
blk = ext2fs_inode_table_loc(fs, i);
|
||||
if (blk)
|
||||
ext2fs_mark_block_bitmap_range2(bmap, blk,
|
||||
fs->inode_blocks_per_group);
|
||||
if (!skip_inode_tables) {
|
||||
blk = ext2fs_inode_table_loc(fs, i);
|
||||
if (blk)
|
||||
ext2fs_mark_block_bitmap_range2(bmap, blk,
|
||||
fs->inode_blocks_per_group);
|
||||
}
|
||||
|
||||
/*
|
||||
* Mark block used for the block bitmap
|
||||
|
@ -1283,12 +1335,69 @@ static errcode_t blocks_to_move(ext2_resize_t rfs)
|
|||
if (retval)
|
||||
return retval;
|
||||
|
||||
retval = mark_table_blocks(old_fs, meta_bmap);
|
||||
retval = mark_table_blocks(old_fs, meta_bmap, 0);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
fs = rfs->new_fs;
|
||||
|
||||
/**
|
||||
* If we're resizing inode tables, we need to reallocate all of them
|
||||
*/
|
||||
if (rfs->old_fs->inode_blocks_per_group != fs->inode_blocks_per_group) {
|
||||
dgrp_t flexbg_size, flex_count, grp_in_flex;
|
||||
ext2fs_block_bitmap empty_bmap;
|
||||
/* // this is how mke2fs allocates inode tables...
|
||||
retval = ext2fs_make_generic_bitmap(EXT2_ET_MAGIC_BLOCK_BITMAP, fs,
|
||||
fs->super->s_first_data_block,
|
||||
ext2fs_blocks_count(fs->super)-1,
|
||||
ext2fs_blocks_count(fs->super)-1, "subcluster inode table bitmap", 0, &empty_bmap);*/
|
||||
retval = ext2fs_allocate_block_bitmap(fs, _("metadata without inode tables"), &empty_bmap);
|
||||
if (retval) {
|
||||
return retval;
|
||||
}
|
||||
retval = mark_table_blocks(fs, empty_bmap, 1);
|
||||
if (retval) {
|
||||
return retval;
|
||||
}
|
||||
if (EXT2_HAS_INCOMPAT_FEATURE(fs->super, EXT4_FEATURE_INCOMPAT_FLEX_BG)
|
||||
&& fs->super->s_log_groups_per_flex) {
|
||||
flexbg_size = 1 << fs->super->s_log_groups_per_flex;
|
||||
} else {
|
||||
flexbg_size = 1;
|
||||
}
|
||||
flex_count = (fs->group_desc_count + flexbg_size - 1) / flexbg_size;
|
||||
for (g = 0; g < fs->group_desc_count; g++) {
|
||||
ext2fs_inode_table_loc_set(fs, g, 0);
|
||||
retval = ext2fs_allocate_group_table(fs, g, empty_bmap);
|
||||
if (retval) {
|
||||
return retval;
|
||||
}
|
||||
/* ext2fs_mark_block_bitmap_range2(empty_bmap,
|
||||
ext2fs_inode_table_loc(fs, g), fs->inode_blocks_per_group);*/
|
||||
group_blk = ext2fs_inode_table_loc(fs, g);
|
||||
if (g > 0 && group_blk < ext2fs_inode_table_loc(fs, g-1)+fs->inode_blocks_per_group) {
|
||||
ext2fs_unmark_block_bitmap_range2(fs->block_map, group_blk, fs->inode_blocks_per_group);
|
||||
group_blk = ext2fs_inode_table_loc(fs, g-1)+fs->inode_blocks_per_group;
|
||||
ext2fs_inode_table_loc_set(fs, g, group_blk);
|
||||
ext2fs_group_desc_csum_set(fs, g);
|
||||
ext2fs_mark_block_bitmap_range2(fs->block_map, group_blk, fs->inode_blocks_per_group);
|
||||
}
|
||||
group_blk += fs->inode_blocks_per_group;
|
||||
// We may need to move some blocks away (mainly if extending inode tables)
|
||||
for (blk = ext2fs_inode_table_loc(fs, g); blk < group_blk; blk++) {
|
||||
if (blk < ext2fs_blocks_count(old_fs->super) &&
|
||||
ext2fs_test_block_bitmap2(old_fs->block_map, blk) &&
|
||||
!ext2fs_test_block_bitmap2(meta_bmap, blk)) {
|
||||
ext2fs_mark_block_bitmap2(rfs->move_blocks, blk);
|
||||
rfs->needed_blocks++;
|
||||
}
|
||||
ext2fs_mark_block_bitmap2(rfs->reserve_blocks, blk);
|
||||
}
|
||||
}
|
||||
ext2fs_free_block_bitmap(empty_bmap);
|
||||
}
|
||||
|
||||
/*
|
||||
* If we're shrinking the filesystem, we need to move any
|
||||
* group's metadata blocks (either allocation bitmaps or the
|
||||
|
@ -1387,7 +1496,7 @@ static errcode_t blocks_to_move(ext2_resize_t rfs)
|
|||
if (retval)
|
||||
goto errout;
|
||||
|
||||
retval = mark_table_blocks(fs, new_meta_bmap);
|
||||
retval = mark_table_blocks(fs, new_meta_bmap, 0);
|
||||
if (retval)
|
||||
goto errout;
|
||||
}
|
||||
|
@ -1848,7 +1957,7 @@ static int process_block(ext2_filsys fs, blk64_t *block_nr,
|
|||
}
|
||||
}
|
||||
|
||||
if (pb->is_dir) {
|
||||
if (pb->is_dir && fs->dblist) {
|
||||
retval = ext2fs_add_dir_block2(fs->dblist, pb->ino,
|
||||
block, (int) blockcnt);
|
||||
if (retval) {
|
||||
|
@ -1895,27 +2004,27 @@ static errcode_t migrate_ea_block(ext2_resize_t rfs, ext2_ino_t ino,
|
|||
errcode_t err = 0;
|
||||
|
||||
/* No EA block or no remapping? Quit early. */
|
||||
if (ext2fs_file_acl_block(rfs->old_fs, inode) == 0 || !rfs->bmap)
|
||||
if (ext2fs_file_acl_block(rfs->new_fs, inode) == 0 || !rfs->bmap)
|
||||
return 0;
|
||||
new_block = extent_translate(rfs->old_fs, rfs->bmap,
|
||||
ext2fs_file_acl_block(rfs->old_fs, inode));
|
||||
new_block = extent_translate(rfs->new_fs, rfs->bmap,
|
||||
ext2fs_file_acl_block(rfs->new_fs, inode));
|
||||
if (new_block == 0)
|
||||
return 0;
|
||||
|
||||
/* Set the new ACL block */
|
||||
ext2fs_file_acl_block_set(rfs->old_fs, inode, new_block);
|
||||
ext2fs_file_acl_block_set(rfs->new_fs, inode, new_block);
|
||||
|
||||
/* Update checksum */
|
||||
if (ext2fs_has_feature_metadata_csum(rfs->new_fs->super)) {
|
||||
err = ext2fs_get_mem(rfs->old_fs->blocksize, &buf);
|
||||
err = ext2fs_get_mem(rfs->new_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;
|
||||
rfs->new_fs->flags |= EXT2_FLAG_IGNORE_CSUM_ERRORS;
|
||||
err = ext2fs_read_ext_attr3(rfs->new_fs, new_block, buf, ino);
|
||||
rfs->new_fs->flags &= ~EXT2_FLAG_IGNORE_CSUM_ERRORS;
|
||||
if (err)
|
||||
goto out;
|
||||
err = ext2fs_write_ext_attr3(rfs->old_fs, new_block, buf, ino);
|
||||
err = ext2fs_write_ext_attr3(rfs->new_fs, new_block, buf, ino);
|
||||
if (err)
|
||||
goto out;
|
||||
}
|
||||
|
@ -1986,52 +2095,62 @@ static void quiet_com_err_proc(const char *whoami EXT2FS_ATTR((unused)),
|
|||
{
|
||||
}
|
||||
|
||||
static errcode_t inode_scan_and_fix(ext2_resize_t rfs)
|
||||
#define TRANSLATE_IPG(ino,old_fs,new_fs) (1 + (((ino)-1) % (old_fs)->super->s_inodes_per_group) + \
|
||||
((ino)-1) / (old_fs)->super->s_inodes_per_group * (new_fs)->super->s_inodes_per_group)
|
||||
|
||||
/**
|
||||
* Move inodes and rewrite references to blocks moved in blocks_to_move()
|
||||
*/
|
||||
static errcode_t inodes_to_move(ext2_resize_t rfs)
|
||||
{
|
||||
struct process_block_struct pb;
|
||||
ext2_ino_t ino, new_inode;
|
||||
ext2_ino_t ino, new_inode, tr_ino;
|
||||
struct ext2_inode *inode = NULL;
|
||||
ext2_inode_scan scan = NULL;
|
||||
errcode_t retval;
|
||||
dgrp_t g, old_g;
|
||||
char *block_buf = 0;
|
||||
ext2_ino_t start_to_move;
|
||||
int inode_size;
|
||||
int shrink_inodes = rfs->old_fs->inode_blocks_per_group > rfs->new_fs->inode_blocks_per_group;
|
||||
int change_inodes = rfs->old_fs->inode_blocks_per_group != rfs->new_fs->inode_blocks_per_group;
|
||||
|
||||
if ((rfs->old_fs->group_desc_count <=
|
||||
rfs->new_fs->group_desc_count) &&
|
||||
!rfs->bmap)
|
||||
!rfs->bmap &&
|
||||
!change_inodes)
|
||||
return 0;
|
||||
|
||||
set_com_err_hook(quiet_com_err_proc);
|
||||
|
||||
retval = ext2fs_open_inode_scan(rfs->old_fs, 0, &scan);
|
||||
if (retval) goto errout;
|
||||
|
||||
retval = ext2fs_init_dblist(rfs->old_fs, 0);
|
||||
if (retval) goto errout;
|
||||
retval = ext2fs_get_array(rfs->old_fs->blocksize, 3, &block_buf);
|
||||
if (retval) goto errout;
|
||||
|
||||
start_to_move = (rfs->new_fs->group_desc_count *
|
||||
rfs->new_fs->super->s_inodes_per_group);
|
||||
|
||||
if (rfs->progress) {
|
||||
retval = (rfs->progress)(rfs, E2_RSZ_INODE_SCAN_PASS,
|
||||
0, rfs->old_fs->group_desc_count);
|
||||
if (retval)
|
||||
goto errout;
|
||||
rfs->old_fs->super->s_inodes_per_group);
|
||||
for (ino = start_to_move+1; ino <= rfs->old_fs->group_desc_count * rfs->old_fs->super->s_inodes_per_group; ino++) {
|
||||
ext2fs_mark_inode_bitmap2(rfs->old_fs->inode_map, ino);
|
||||
}
|
||||
ext2fs_set_inode_callback(scan, progress_callback, (void *) rfs);
|
||||
pb.rfs = rfs;
|
||||
pb.inode = inode;
|
||||
pb.error = 0;
|
||||
new_inode = EXT2_FIRST_INODE(rfs->new_fs->super);
|
||||
if (shrink_inodes) {
|
||||
for (g = 0; g < rfs->old_fs->group_desc_count; g++) {
|
||||
ext2_ino_t first_ino = 1+rfs->old_fs->super->s_inodes_per_group*g;
|
||||
for (ino = first_ino+rfs->new_fs->super->s_inodes_per_group; ino < first_ino+rfs->old_fs->super->s_inodes_per_group; ino++) {
|
||||
ext2fs_mark_inode_bitmap2(rfs->old_fs->inode_map, ino);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
retval = ext2fs_get_array(rfs->new_fs->blocksize, 3, &block_buf);
|
||||
if (retval) goto errout;
|
||||
|
||||
inode_size = EXT2_INODE_SIZE(rfs->new_fs->super);
|
||||
inode = malloc(inode_size);
|
||||
if (!inode) {
|
||||
retval = ENOMEM;
|
||||
goto errout;
|
||||
}
|
||||
pb.rfs = rfs;
|
||||
pb.inode = inode;
|
||||
pb.error = 0;
|
||||
|
||||
/*
|
||||
* First, copy all of the inodes that need to be moved
|
||||
* elsewhere in the inode table
|
||||
|
@ -2045,78 +2164,68 @@ static errcode_t inode_scan_and_fix(ext2_resize_t rfs)
|
|||
if (inode->i_links_count == 0 && ino != EXT2_RESIZE_INO)
|
||||
continue; /* inode not in use */
|
||||
|
||||
pb.is_dir = LINUX_S_ISDIR(inode->i_mode);
|
||||
pb.changed = 0;
|
||||
|
||||
/* Remap EA block */
|
||||
retval = migrate_ea_block(rfs, ino, inode, &pb.changed);
|
||||
if (retval)
|
||||
goto errout;
|
||||
|
||||
new_inode = ino;
|
||||
if (ino <= start_to_move)
|
||||
goto remap_blocks; /* Don't need to move inode. */
|
||||
if (ino > start_to_move ||
|
||||
(shrink_inodes && (ino-1) % rfs->old_fs->super->s_inodes_per_group >= rfs->new_fs->super->s_inodes_per_group))
|
||||
{
|
||||
/*
|
||||
* 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->old_fs, 0, 0, 0, &new_inode);
|
||||
if (retval)
|
||||
goto errout;
|
||||
|
||||
/*
|
||||
* 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)
|
||||
goto errout;
|
||||
/* Translate inode number according to new inodes_per_group */
|
||||
tr_ino = TRANSLATE_IPG(new_inode, rfs->old_fs, rfs->new_fs);
|
||||
|
||||
ext2fs_inode_alloc_stats2(rfs->new_fs, new_inode, +1,
|
||||
pb.is_dir);
|
||||
inode->i_ctime = time(0);
|
||||
retval = ext2fs_write_inode_full(rfs->old_fs, new_inode,
|
||||
inode, inode_size);
|
||||
if (retval)
|
||||
goto errout;
|
||||
pb.changed = 0;
|
||||
old_g = ext2fs_group_of_ino(rfs->old_fs, ino);
|
||||
ext2fs_inode_alloc_stats2(rfs->old_fs, new_inode, +1, LINUX_S_ISDIR(inode->i_mode));
|
||||
if (old_g < rfs->new_fs->group_desc_count)
|
||||
{
|
||||
/*
|
||||
* Don't bother to adjust free_inodes_count for group because freed
|
||||
* inodes will be accounted as part of inodes_per_group change
|
||||
*/
|
||||
if (LINUX_S_ISDIR(inode->i_mode))
|
||||
ext2fs_bg_used_dirs_count_set(rfs->new_fs, old_g, ext2fs_bg_used_dirs_count(rfs->new_fs, old_g) - 1);
|
||||
ext2fs_group_desc_csum_set(rfs->new_fs, old_g);
|
||||
}
|
||||
ext2fs_inode_alloc_stats2(rfs->new_fs, tr_ino, +1, LINUX_S_ISDIR(inode->i_mode));
|
||||
inode->i_ctime = time(0);
|
||||
retval = ext2fs_write_inode_full(rfs->old_fs, new_inode, inode, inode_size);
|
||||
if (retval)
|
||||
goto errout;
|
||||
|
||||
#ifdef RESIZE2FS_DEBUG
|
||||
if (rfs->flags & RESIZE_DEBUG_INODEMAP)
|
||||
printf("Inode moved %u->%u\n", ino, new_inode);
|
||||
if (rfs->flags & RESIZE_DEBUG_INODEMAP)
|
||||
printf("Inode moved %u->%u\n", ino, new_inode);
|
||||
#endif
|
||||
if (!rfs->imap) {
|
||||
retval = ext2fs_create_extent_table(&rfs->imap, 0);
|
||||
if (retval)
|
||||
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;
|
||||
if (!rfs->imap) {
|
||||
retval = ext2fs_create_extent_table(&rfs->imap, 0);
|
||||
if (retval)
|
||||
goto errout;
|
||||
}
|
||||
ext2fs_add_extent_entry(rfs->imap, ino, new_inode);
|
||||
|
||||
/* Rewrite extent block checksums with new inode number */
|
||||
if (ext2fs_has_feature_metadata_csum(rfs->old_fs->super) &&
|
||||
(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;
|
||||
// continue with rewritten inode number
|
||||
ino = new_inode;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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.
|
||||
* Update inodes to point to new blocks.
|
||||
*/
|
||||
if (ext2fs_inode_has_valid_blocks2(rfs->old_fs, inode) &&
|
||||
(rfs->bmap || pb.is_dir)) {
|
||||
pb.ino = new_inode;
|
||||
pb.old_ino = ino;
|
||||
if (ext2fs_inode_has_valid_blocks2(rfs->old_fs, inode) && rfs->bmap) {
|
||||
pb.changed = 0;
|
||||
pb.is_dir = LINUX_S_ISDIR(inode->i_mode);
|
||||
pb.ino = ino;
|
||||
pb.old_ino = ino; // FIXME debug output will show translated inodes
|
||||
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,
|
||||
ino, 0, block_buf,
|
||||
process_block, &pb);
|
||||
rfs->old_fs->flags &= ~EXT2_FLAG_IGNORE_CSUM_ERRORS;
|
||||
if (retval)
|
||||
|
@ -2125,16 +2234,134 @@ remap_blocks:
|
|||
retval = pb.error;
|
||||
goto errout;
|
||||
}
|
||||
} else if ((inode->i_flags & EXT4_INLINE_DATA_FL) &&
|
||||
(rfs->bmap || pb.is_dir)) {
|
||||
}
|
||||
}
|
||||
|
||||
errout:
|
||||
if (scan)
|
||||
ext2fs_close_inode_scan(scan);
|
||||
if (block_buf)
|
||||
ext2fs_free_mem(&block_buf);
|
||||
free(inode);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remap extattr blocks, rewrite inode and extattr checksums
|
||||
* and schedule directory blocks for inode remapping
|
||||
*/
|
||||
static errcode_t inode_scan_and_fix(ext2_resize_t rfs)
|
||||
{
|
||||
struct process_block_struct pb;
|
||||
ext2_ino_t ino, tr_ino;
|
||||
struct ext2_inode *inode = NULL;
|
||||
ext2_inode_scan scan = NULL;
|
||||
errcode_t retval;
|
||||
dgrp_t g;
|
||||
char *block_buf = 0;
|
||||
int inode_size;
|
||||
int change_inodes = rfs->old_fs->inode_blocks_per_group != rfs->new_fs->inode_blocks_per_group;
|
||||
|
||||
if ((rfs->old_fs->group_desc_count <=
|
||||
rfs->new_fs->group_desc_count) &&
|
||||
!rfs->bmap &&
|
||||
!change_inodes)
|
||||
return 0;
|
||||
|
||||
set_com_err_hook(quiet_com_err_proc);
|
||||
|
||||
retval = ext2fs_open_inode_scan(rfs->new_fs, 0, &scan);
|
||||
if (retval) goto errout;
|
||||
|
||||
retval = ext2fs_init_dblist(rfs->new_fs, 0);
|
||||
if (retval) goto errout;
|
||||
retval = ext2fs_get_array(rfs->new_fs->blocksize, 3, &block_buf);
|
||||
if (retval) goto errout;
|
||||
|
||||
if (rfs->progress) {
|
||||
retval = (rfs->progress)(rfs, E2_RSZ_INODE_SCAN_PASS,
|
||||
0, rfs->new_fs->group_desc_count);
|
||||
if (retval)
|
||||
goto errout;
|
||||
}
|
||||
ext2fs_set_inode_callback(scan, progress_callback, (void *) rfs);
|
||||
inode_size = EXT2_INODE_SIZE(rfs->new_fs->super);
|
||||
inode = malloc(inode_size);
|
||||
if (!inode) {
|
||||
retval = ENOMEM;
|
||||
goto errout;
|
||||
}
|
||||
pb.rfs = rfs;
|
||||
pb.inode = inode;
|
||||
pb.error = 0;
|
||||
/*
|
||||
* First, copy all of the inodes that need to be moved
|
||||
* elsewhere in the inode table
|
||||
*/
|
||||
while (1) {
|
||||
rfs->new_fs->flags |= EXT2_FLAG_IGNORE_CSUM_ERRORS;
|
||||
retval = ext2fs_get_next_inode_full(scan, &ino, inode, inode_size);
|
||||
rfs->new_fs->flags &= ~EXT2_FLAG_IGNORE_CSUM_ERRORS;
|
||||
if (retval) goto errout;
|
||||
if (!ino)
|
||||
break;
|
||||
|
||||
if (inode->i_links_count == 0 && ino != EXT2_RESIZE_INO)
|
||||
continue; /* inode not in use */
|
||||
|
||||
pb.is_dir = LINUX_S_ISDIR(inode->i_mode);
|
||||
pb.changed = change_inodes;
|
||||
|
||||
/* Remap EA block */
|
||||
retval = migrate_ea_block(rfs, ino, inode, &pb.changed);
|
||||
if (retval)
|
||||
goto errout;
|
||||
|
||||
if (pb.changed)
|
||||
retval = ext2fs_write_inode_full(rfs->new_fs,
|
||||
ino,
|
||||
inode, inode_size);
|
||||
if (retval)
|
||||
goto errout;
|
||||
|
||||
/* Rewrite extent block checksums with new inode number */
|
||||
if (ext2fs_has_feature_metadata_csum(rfs->new_fs->super) &&
|
||||
(inode->i_flags & EXT4_EXTENTS_FL)) {
|
||||
rfs->new_fs->flags |= EXT2_FLAG_IGNORE_CSUM_ERRORS;
|
||||
retval = rewrite_extents(rfs->new_fs, ino);
|
||||
rfs->new_fs->flags &= ~EXT2_FLAG_IGNORE_CSUM_ERRORS;
|
||||
if (retval)
|
||||
goto errout;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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->new_fs, inode) && pb.is_dir) {
|
||||
pb.ino = ino;
|
||||
pb.old_ino = ino; // FIXME: Debug output will show translated inodes
|
||||
pb.has_extents = inode->i_flags & EXT4_EXTENTS_FL;
|
||||
rfs->new_fs->flags |= EXT2_FLAG_IGNORE_CSUM_ERRORS;
|
||||
retval = ext2fs_block_iterate3(rfs->new_fs,
|
||||
ino, 0, block_buf,
|
||||
process_block, &pb);
|
||||
rfs->new_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) && pb.is_dir) {
|
||||
/* inline data dir; update it too */
|
||||
retval = ext2fs_add_dir_block2(rfs->old_fs->dblist,
|
||||
new_inode, 0, 0);
|
||||
retval = ext2fs_add_dir_block2(rfs->new_fs->dblist,
|
||||
tr_ino, 0, 0);
|
||||
if (retval)
|
||||
goto errout;
|
||||
}
|
||||
}
|
||||
io_channel_flush(rfs->old_fs->io);
|
||||
io_channel_flush(rfs->new_fs->io);
|
||||
|
||||
errout:
|
||||
reset_com_err_hook();
|
||||
|
@ -2150,6 +2377,140 @@ errout:
|
|||
return retval;
|
||||
}
|
||||
|
||||
static errcode_t move_inode_tables(ext2_resize_t rfs)
|
||||
{
|
||||
dgrp_t g, end_g, group_count;
|
||||
dgrp_t move_start, move_count;
|
||||
__u32 old_ipg = rfs->old_fs->super->s_inodes_per_group;
|
||||
__u32 new_ipg = rfs->new_fs->super->s_inodes_per_group;
|
||||
__u32 old_ibg = rfs->old_fs->inode_blocks_per_group;
|
||||
__u32 new_ibg = rfs->new_fs->inode_blocks_per_group;
|
||||
int retval;
|
||||
blk64_t size, blk, ib;
|
||||
int change_inodes = old_ibg != new_ibg;
|
||||
__u32 unused, ino, old_ino, i;
|
||||
ext2fs_block_bitmap meta_bmap = NULL;
|
||||
|
||||
retval = ext2fs_allocate_block_bitmap(rfs->new_fs, _("meta-data blocks"), &meta_bmap);
|
||||
if (retval)
|
||||
return retval;
|
||||
retval = mark_table_blocks(rfs->new_fs, meta_bmap, 1);
|
||||
|
||||
printf("inode blocks per group: %u to %u\n", old_ibg, new_ibg);
|
||||
size = old_ibg;
|
||||
size = size < new_ibg ? size : new_ibg;
|
||||
move_count = 0;
|
||||
group_count = rfs->new_fs->group_desc_count;
|
||||
group_count = group_count < rfs->old_fs->group_desc_count ? group_count : rfs->old_fs->group_desc_count;
|
||||
for (g = 0; g < group_count; g++)
|
||||
{
|
||||
if (change_inodes)
|
||||
{
|
||||
/*
|
||||
* new_fs may have incorrect itable_unused because we're not adjusting it
|
||||
* before calling inode_alloc_stats2 in inodes_to_move().
|
||||
* and it's OK to take free_inodes_count from old_fs because any inodes
|
||||
* that are freed may only lay in shrinked inode table areas.
|
||||
*/
|
||||
unused = ext2fs_bg_itable_unused(rfs->old_fs, g);
|
||||
if (new_ipg < old_ipg && unused < old_ipg-new_ipg)
|
||||
unused = 0;
|
||||
else
|
||||
unused = unused + new_ipg - old_ipg;
|
||||
ext2fs_bg_itable_unused_set(rfs->new_fs, g, unused);
|
||||
ext2fs_bg_free_inodes_count_set(rfs->new_fs, g,
|
||||
ext2fs_bg_free_inodes_count(rfs->old_fs, g) + new_ipg - old_ipg);
|
||||
ext2fs_group_desc_csum_set(rfs->new_fs, g);
|
||||
}
|
||||
printf("g%u = [%u?] %u->%u free=%u->%u unused=%u->%u\n", g,
|
||||
g > 0 ? ext2fs_inode_table_loc(rfs->old_fs, g-1)+old_ibg : 0,
|
||||
ext2fs_inode_table_loc(rfs->old_fs, g),
|
||||
ext2fs_inode_table_loc(rfs->new_fs, g),
|
||||
ext2fs_bg_free_inodes_count(rfs->old_fs, g),
|
||||
ext2fs_bg_free_inodes_count(rfs->new_fs, g),
|
||||
ext2fs_bg_itable_unused(rfs->old_fs, g),
|
||||
ext2fs_bg_itable_unused(rfs->new_fs, g));
|
||||
if (change_inodes || ext2fs_inode_table_loc(rfs->new_fs, g) != ext2fs_inode_table_loc(rfs->old_fs, g))
|
||||
{
|
||||
move_count++;
|
||||
if (move_count == 1)
|
||||
move_start = g;
|
||||
// check for overlap
|
||||
if (g < rfs->new_fs->group_desc_count-1 &&
|
||||
ext2fs_inode_table_loc(rfs->new_fs, g)+new_ibg > ext2fs_inode_table_loc(rfs->old_fs, g+1))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (move_count > 0)
|
||||
{
|
||||
end_g = g;
|
||||
for (i = 0, g = move_start+move_count-1; i < move_count; i++, g--)
|
||||
{
|
||||
if (!ext2fs_has_group_desc_csum(rfs->new_fs) ||
|
||||
!ext2fs_bg_flags_test(rfs->new_fs, g, EXT2_BG_INODE_UNINIT))
|
||||
{
|
||||
retval = io_channel_read_blk64(rfs->new_fs->io, ext2fs_inode_table_loc(rfs->old_fs, g), size, rfs->itable_buf);
|
||||
if (retval)
|
||||
return retval;
|
||||
retval = io_channel_write_blk64(rfs->new_fs->io, ext2fs_inode_table_loc(rfs->new_fs, g), size, rfs->itable_buf);
|
||||
if (retval)
|
||||
return retval;
|
||||
if (new_ibg > old_ibg)
|
||||
{
|
||||
retval = ext2fs_zero_blocks2(rfs->new_fs,
|
||||
ext2fs_inode_table_loc(rfs->new_fs, g)+old_ibg,
|
||||
new_ibg-old_ibg, NULL, NULL);
|
||||
if (retval)
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
blk = ext2fs_inode_table_loc(rfs->old_fs, g);
|
||||
for (ib = 0; ib < old_ibg; ib++)
|
||||
if (!ext2fs_test_block_bitmap2(meta_bmap, blk+ib))
|
||||
ext2fs_unmark_block_bitmap2(rfs->new_fs->block_map, blk+ib);
|
||||
ext2fs_mark_block_bitmap_range2(rfs->new_fs->block_map, ext2fs_inode_table_loc(rfs->new_fs, g), new_ibg);
|
||||
}
|
||||
move_start = move_count = 0;
|
||||
g = end_g;
|
||||
}
|
||||
}
|
||||
|
||||
if (old_ipg < new_ipg)
|
||||
{
|
||||
for (g = 0; g < group_count; g++)
|
||||
{
|
||||
for (i = 0, old_ino = 1 + old_ipg*g, ino = 1 + new_ipg*g; i < old_ipg; i++, ino++, old_ino++)
|
||||
{
|
||||
if (ext2fs_test_inode_bitmap2(rfs->old_fs->inode_map, old_ino))
|
||||
ext2fs_mark_inode_bitmap2(rfs->new_fs->inode_map, ino);
|
||||
else
|
||||
ext2fs_unmark_inode_bitmap2(rfs->new_fs->inode_map, ino);
|
||||
}
|
||||
for (i = old_ipg, ino = 1 + new_ipg*g + old_ipg; i < new_ipg; i++, ino++)
|
||||
ext2fs_unmark_inode_bitmap2(rfs->new_fs->inode_map, ino);
|
||||
}
|
||||
}
|
||||
else if (old_ipg > new_ipg)
|
||||
{
|
||||
dgrp_t n;
|
||||
for (n = 0, g = group_count-1; n < group_count; n++, g--)
|
||||
{
|
||||
for (i = 0, old_ino = 1 + old_ipg*g, ino = 1 + new_ipg*g; i < new_ipg; i++, ino++, old_ino++)
|
||||
{
|
||||
if (ext2fs_test_inode_bitmap2(rfs->old_fs->inode_map, old_ino))
|
||||
ext2fs_mark_inode_bitmap2(rfs->new_fs->inode_map, ino);
|
||||
else
|
||||
ext2fs_unmark_inode_bitmap2(rfs->new_fs->inode_map, ino);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ext2fs_free_block_bitmap(meta_bmap);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------
|
||||
*
|
||||
* Resize processing, phase 4.
|
||||
|
@ -2176,9 +2537,10 @@ static int check_and_change_inodes(ext2_ino_t dir,
|
|||
ext2_ino_t new_inode;
|
||||
errcode_t retval;
|
||||
int ret = 0;
|
||||
ext2_ino_t old_dir = TRANSLATE_IPG(dir, is->rfs->new_fs, is->rfs->old_fs);
|
||||
|
||||
if (is->rfs->progress && offset == 0) {
|
||||
io_channel_flush(is->rfs->old_fs->io);
|
||||
io_channel_flush(is->rfs->new_fs->io);
|
||||
is->err = (is->rfs->progress)(is->rfs,
|
||||
E2_RSZ_INODE_REF_UPD_PASS,
|
||||
++is->num, is->max_dirs);
|
||||
|
@ -2191,16 +2553,25 @@ static int check_and_change_inodes(ext2_ino_t dir,
|
|||
* old fs, then we must rewrite all dir blocks with new checksums.
|
||||
*/
|
||||
if (ext2fs_has_feature_metadata_csum(is->rfs->old_fs->super) &&
|
||||
!ext2fs_test_inode_bitmap2(is->rfs->old_fs->inode_map, dir))
|
||||
!ext2fs_test_inode_bitmap2(is->rfs->old_fs->inode_map, old_dir))
|
||||
ret |= DIRENT_CHANGED;
|
||||
|
||||
if (!dirent->inode)
|
||||
{
|
||||
if (old_dir != dir)
|
||||
ret |= DIRENT_CHANGED;
|
||||
return ret;
|
||||
}
|
||||
|
||||
new_inode = ext2fs_extent_translate(is->rfs->imap, dirent->inode);
|
||||
|
||||
new_inode = 0;
|
||||
if (is->rfs->imap)
|
||||
new_inode = ext2fs_extent_translate(is->rfs->imap, dirent->inode);
|
||||
if (!new_inode)
|
||||
new_inode = dirent->inode;
|
||||
new_inode = TRANSLATE_IPG(new_inode, is->rfs->old_fs, is->rfs->new_fs);
|
||||
if (new_inode == dirent->inode && old_dir == dir)
|
||||
return ret;
|
||||
|
||||
#ifdef RESIZE2FS_DEBUG
|
||||
if (is->rfs->flags & RESIZE_DEBUG_INODEMAP)
|
||||
printf("Inode translate (dir=%u, name=%.*s, %u->%u)\n",
|
||||
|
@ -2211,10 +2582,10 @@ static int check_and_change_inodes(ext2_ino_t dir,
|
|||
dirent->inode = new_inode;
|
||||
|
||||
/* Update the directory mtime and ctime */
|
||||
retval = ext2fs_read_inode(is->rfs->old_fs, dir, &inode);
|
||||
retval = ext2fs_read_inode(is->rfs->new_fs, dir, &inode);
|
||||
if (retval == 0) {
|
||||
inode.i_mtime = inode.i_ctime = time(0);
|
||||
is->err = ext2fs_write_inode(is->rfs->old_fs, dir, &inode);
|
||||
is->err = ext2fs_write_inode(is->rfs->new_fs, dir, &inode);
|
||||
if (is->err)
|
||||
return ret | DIRENT_ABORT;
|
||||
}
|
||||
|
@ -2226,8 +2597,9 @@ static errcode_t inode_ref_fix(ext2_resize_t rfs)
|
|||
{
|
||||
errcode_t retval;
|
||||
struct istruct is;
|
||||
int change_inodes = rfs->old_fs->inode_blocks_per_group != rfs->new_fs->inode_blocks_per_group;
|
||||
|
||||
if (!rfs->imap)
|
||||
if (!change_inodes && !rfs->imap)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
|
@ -2235,7 +2607,7 @@ static errcode_t inode_ref_fix(ext2_resize_t rfs)
|
|||
* inode references
|
||||
*/
|
||||
is.num = 0;
|
||||
is.max_dirs = ext2fs_dblist_count2(rfs->old_fs->dblist);
|
||||
is.max_dirs = ext2fs_dblist_count2(rfs->new_fs->dblist);
|
||||
is.rfs = rfs;
|
||||
is.err = 0;
|
||||
|
||||
|
@ -2246,11 +2618,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,
|
||||
rfs->new_fs->flags |= EXT2_FLAG_IGNORE_CSUM_ERRORS;
|
||||
retval = ext2fs_dblist_dir_iterate(rfs->new_fs->dblist,
|
||||
DIRENT_FLAG_INCLUDE_EMPTY, 0,
|
||||
check_and_change_inodes, &is);
|
||||
rfs->old_fs->flags &= ~EXT2_FLAG_IGNORE_CSUM_ERRORS;
|
||||
rfs->new_fs->flags &= ~EXT2_FLAG_IGNORE_CSUM_ERRORS;
|
||||
if (retval)
|
||||
goto errout;
|
||||
if (is.err) {
|
||||
|
@ -2263,7 +2635,8 @@ static errcode_t inode_ref_fix(ext2_resize_t rfs)
|
|||
is.max_dirs, is.max_dirs);
|
||||
|
||||
errout:
|
||||
ext2fs_free_extent_table(rfs->imap);
|
||||
if (rfs->imap)
|
||||
ext2fs_free_extent_table(rfs->imap);
|
||||
rfs->imap = 0;
|
||||
return retval;
|
||||
}
|
||||
|
@ -2319,7 +2692,7 @@ static errcode_t move_itables(ext2_resize_t rfs)
|
|||
if (retval)
|
||||
return retval;
|
||||
|
||||
retval = mark_table_blocks(fs, new_bmap);
|
||||
retval = mark_table_blocks(fs, new_bmap, 0);
|
||||
if (retval)
|
||||
goto errout;
|
||||
}
|
||||
|
@ -2431,7 +2804,7 @@ static errcode_t move_itables(ext2_resize_t rfs)
|
|||
goto errout;
|
||||
}
|
||||
}
|
||||
mark_table_blocks(fs, fs->block_map);
|
||||
mark_table_blocks(fs, fs->block_map, 0);
|
||||
ext2fs_flush(fs);
|
||||
#ifdef RESIZE2FS_DEBUG
|
||||
if (rfs->flags & RESIZE_DEBUG_ITABLEMOVE)
|
||||
|
|
|
@ -141,7 +141,7 @@ struct ext2_resize_struct {
|
|||
|
||||
|
||||
/* prototypes */
|
||||
extern errcode_t resize_fs(ext2_filsys fs, blk64_t *new_size, int flags,
|
||||
extern errcode_t resize_fs(ext2_filsys fs, blk64_t *new_size, __u32 new_inodes, int flags,
|
||||
errcode_t (*progress)(ext2_resize_t rfs,
|
||||
int pass, unsigned long cur,
|
||||
unsigned long max));
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
Bad required extra isize in superblock (1). Fix? yes
|
||||
|
||||
Bad desired extra isize in superblock (1024). 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: 11/32 files (0.0% non-contiguous), 28/200 blocks
|
||||
Exit status is 1
|
|
@ -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/32 files (0.0% non-contiguous), 28/200 blocks
|
||||
Exit status is 0
|
Binary file not shown.
|
@ -0,0 +1 @@
|
|||
check invalid extra_isize fields in superblock
|
|
@ -1,4 +1,7 @@
|
|||
Pass 1: Checking inodes, blocks, and sizes
|
||||
Inode 12 has a extra size (126) which is invalid
|
||||
Fix? yes
|
||||
|
||||
Pass 2: Checking directory structure
|
||||
Directory inode 12, block #0, offset 4: directory corrupted
|
||||
Salvage? yes
|
||||
|
|
Loading…
Reference in New Issue