From 0b2ca41df10ac4d69127e4fedca5d64531d9d1d7 Mon Sep 17 00:00:00 2001 From: Bdale Garbee Date: Wed, 28 Sep 2005 00:50:29 -0600 Subject: [PATCH] Imported Debian patch 0.4b40-1 --- CHANGES | 99 +++++- MCONFIG.in | 4 +- THANKS | 7 +- TODO | 7 +- compat/include/bsdcompat.h | 4 +- compat/include/protocols/dumprestore.h | 10 +- config.h.in | 4 + configure | 179 +++++++++- configure.in | 36 +- debian/changelog | 16 + debian/compat | 1 + debian/config | 2 +- debian/control | 6 +- debian/po/cs.po | 52 +++ debian/po/sv.po | 44 ++- debian/po/vi.po | 37 +++ debian/postinst | 2 +- debian/postrm | 5 + debian/rules | 14 +- dump.lsm | 6 +- dump.spec | 8 +- dump/dump.8.in | 8 +- dump/tape.c | 22 +- dump/traverse.c | 92 ++++- examples/dump_on_cd_3/README | 16 + examples/dump_on_cd_3/dump_disk | 100 ++++++ restore/Makefile.in | 6 +- restore/dirs.c | 174 +++++++++- restore/extern.h | 12 +- restore/main.c | 11 +- restore/restore.8.in | 8 +- restore/restore.c | 125 +++---- restore/restore.h | 8 +- restore/symtab.c | 164 +++++++-- restore/tape.c | 220 ++++++++++-- restore/utilities.c | 71 +++- restore/xattr.c | 444 +++++++++++++++++++++++++ 37 files changed, 1763 insertions(+), 261 deletions(-) create mode 100644 debian/compat create mode 100644 debian/po/cs.po create mode 100644 debian/po/vi.po create mode 100644 debian/postrm create mode 100644 examples/dump_on_cd_3/README create mode 100755 examples/dump_on_cd_3/dump_disk create mode 100644 restore/xattr.c diff --git a/CHANGES b/CHANGES index 501bc16..c4d497d 100644 --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,101 @@ -$Id: CHANGES,v 1.254 2004/07/07 13:34:06 stelian Exp $ +$Id: CHANGES,v 1.275 2005/05/02 15:13:40 stelian Exp $ + +Changes between versions 0.4b39 and 0.4b40 (released May 2, 2005) +================================================================= + +1. Changed restore to emit warnings (instead of emitting a fatal + error) if a file (or a directory) is unavailable for a + comparision (if the user doesn't have the necessary permissions + to access it for example). Thanks to Kenneth Porter + for the bug report. + +2. Re-done the 'do not save directory entries to non-dumped inodes + (excluded from dump)' feature. The previous implementation + worked well for excluded directories but not for regular files. + Thanks to Kenneth Porter for the bug + report. + +3. Fixed a bug in dump where the tape size was miscalculated when + the user used -d/-s to specify the tape characteristics. Thanks + to Philip Goisman for reporting + the bug. + +4. Fixed another bug introduced in restore with the hashtree + implementation. This one caused restore to stop saying + "removenode: non-empty directory" in some cases. + +5. Added support for dumping and restoring ext2/3 extended + attributes (EA), like the access control lists (ACL) or + the security labels used by SELinux. + +Changes between versions 0.4b38 and 0.4b39 (released January 21, 2005) +====================================================================== + +1. The newly added dump_on_cd_3 example was buggy, replace it + with an updated version from Andrew Basterfield + . + +2. Made restore to chdir() back into the initial directory when + dumping core while aborting a comparision operation. The + previous behaviour was to write the corefile at the root of + the directory being compared, which could very well be + read only and preventing the corefile generation. Thanks + to Kenneth Porter for the bug report. + +3. Silenced the failure to call fgetflags() when comparing an + entry which has no ext2 attributes (as in lsattr()). + +4. Fix a brown paper bug in restore -C which broke restore and + caused modifications on the filesystem being compared + (directories containing a file with the same name as the + directory get renamed to RSTTMP...). Thanks to Kenneth Porter + for finding the bug and helping me + reproduce it. + +5. Made restore -C force the -N flag (no writing allowed on + the disk) in order to prevent more bugs like the above one. + +Changes between versions 0.4b37 and 0.4b38 (released January 7, 2005) +===================================================================== + +1. Fix a couple of troff syntax bugs in the man pages. + Thanks to Eric Raymond for the patch. + +2. Made restore use either libncurses or libtermcap, depending + on which one is available at configure time. + +3. Fixed restore negative size display bug when comparing a + dump containing files over 2GB. Thanks to Steve Bonds + for the bug report. + +4. Do not save directory entries to non-dumped inodes + (excluded from dump). This will eliminate the 'missing + file' warnings when doing 'restore -C'. + +5. Fix dump crash when backuping a huge (2TB) filesystem, + due to a bogus calculation on the inode map size. + Thanks to Kevin B. Haines for + submitting the bug and testing the fix. + +6. Fix a problem in restore where the final \0 in the symbolic + link names could have been lost, generating corrupt filenames. + Thanks to Kyle Wilson for reporting the + bug. + +7. Implemented a hash list for the directory names in restore. + The linear list used before caused problems in interactive + restores when dealing with directories having thousands of + entries. Thanks to Brian Ristuccia + for reporting the bug. + +8. Improved restore -C, this time including the directory + attributes into the comparision. + +9. Made restore understand tapes containing EA/ACLs (which will + be dumped by the next version of dump). In this version + extended attributes on the tape are ignored, for full EA/ACL + support wait for the next version or try the experimental EA + patch. Changes between versions 0.4b36 and 0.4b37 (released July 7, 2004) ================================================================== diff --git a/MCONFIG.in b/MCONFIG.in index e20399e..8bce8b0 100644 --- a/MCONFIG.in +++ b/MCONFIG.in @@ -1,5 +1,5 @@ -VERSION= 0.4b37 -DATE= July 7, 2004 +VERSION= 0.4b40 +DATE= May 2, 2005 AR= @AR@ CC= @CC@ diff --git a/THANKS b/THANKS index 3e2854c..cb7596d 100644 --- a/THANKS +++ b/THANKS @@ -1,4 +1,4 @@ -$Id: THANKS,v 1.85 2004/07/01 09:14:48 stelian Exp $ +$Id: THANKS,v 1.89 2004/12/14 14:07:56 stelian Exp $ Dump and restore were written by the people of the CSRG at the University of California, Berkeley. @@ -52,6 +52,7 @@ Arcady Genkin antipode@users.sourceforge.net Uwe Gohlke uwe@ugsoft.de Ian Gordon iangordon@users.sourceforge.net Ted Grzesik tedgyz@roostme.com +Kevin B. Haines K.B.Haines@rl.ac.uk Mike Harris mharris@redhat.com Andreas Hasenack andreas@conectiva.com.br Christian Haul haul@informatik.tu-darmstadt.de @@ -96,9 +97,10 @@ David B. Peterson dave@toppledwagon.com Trent Piepho xyzzy@speakeasy.org Dave Platt dplatt@snulbug.mtview.ca.us Kenneth Porter shiva@well.com -Eric S. Raymond esr@minx.thyrsus.com +Eric S. Raymond esr@thyrsus.com Graham Reed greed@users.sourceforge.net Gunther Reiszig gunther@mit.edu +Brian Ristuccia bristuccia@starentnetworks.com David Ronis ronis@ronispc.chem.mcgill.ca Dietrich Rothe d-rothe@users.sourceforge.net Bernhard Sadlowski sadlowsk@Mathematik.Uni-Bielefeld.DE @@ -128,6 +130,7 @@ Daniel Veillard Daniel.Veillard@imag.fr Jason Venner jason@idiom.com John I Wang jiwang@users.sourceforge.net Christian Weisgerber naddy@mips.rhein-neckar.de +Kyle Wilson kyle.wilson@amd.com Kim Yong-jun loveyou@hackerslab.org John Yu jky@it.bu.edu Ian Zimmerman itz@speakeasy.org diff --git a/TODO b/TODO index d3d4102..349b1d1 100644 --- a/TODO +++ b/TODO @@ -1,4 +1,4 @@ -$Id: TODO,v 1.24 2002/01/25 14:59:53 stelian Exp $ +$Id: TODO,v 1.25 2005/05/02 15:10:44 stelian Exp $ Need to verify: --------------- @@ -31,7 +31,4 @@ All others: 5. Make a bootable dump tape? I don't know if it is possible... -6. EA/ACL support in dump (requested by Michael Ju. Tokarev - . - -7. Better readline completition in restore (escape spaces etc). +6. Better readline completition in restore (escape spaces etc). diff --git a/compat/include/bsdcompat.h b/compat/include/bsdcompat.h index 4b9b907..7bc2160 100644 --- a/compat/include/bsdcompat.h +++ b/compat/include/bsdcompat.h @@ -5,7 +5,7 @@ * Stelian Pop , 1999-2000 * Stelian Pop - Alcôve , 2000-2002 * - * $Id: bsdcompat.h,v 1.23 2004/07/01 09:14:48 stelian Exp $ + * $Id: bsdcompat.h,v 1.24 2005/05/02 15:10:45 stelian Exp $ */ #include @@ -130,6 +130,8 @@ struct dinode { __u16 di_uidhigh; __u16 di_gidhigh; __u32 di_spare; + __u16 di_extraisize; + __u16 di_pad2; }; #define di_rdev di_db[0] diff --git a/compat/include/protocols/dumprestore.h b/compat/include/protocols/dumprestore.h index fc43715..816a83f 100644 --- a/compat/include/protocols/dumprestore.h +++ b/compat/include/protocols/dumprestore.h @@ -5,7 +5,7 @@ * Stelian Pop , 1999-2000 * Stelian Pop - Alcôve , 2000-2002 * - * $Id: dumprestore.h,v 1.22 2004/07/01 09:14:49 stelian Exp $ + * $Id: dumprestore.h,v 1.24 2005/05/02 15:10:46 stelian Exp $ */ /* @@ -150,8 +150,7 @@ union u_spcl { #define EXT_REGULAR 0 #define EXT_MACOSFNDRINFO 1 #define EXT_MACOSRESFORK 2 -#define EXT_ACL 3 - +#define EXT_XATTR 3 /* * compression flags for the tapebuf header. @@ -172,4 +171,9 @@ struct tapebuf { #endif }; +/* used for EA on tape */ +#define EXT2_GOOD_OLD_INODE_SIZE 128 +#define EXT2_XATTR_MAGIC 0xEA020000 /* block EA */ +#define EXT2_XATTR_MAGIC2 0xEA020001 /* in inode EA */ + #endif /* !_DUMPRESTORE_H_ */ diff --git a/config.h.in b/config.h.in index 799b2f0..828ef11 100644 --- a/config.h.in +++ b/config.h.in @@ -21,6 +21,10 @@ /* Define to 1 if you have the header file. */ #undef HAVE_EXT2FS_EXT2_FS_H +/* Define this if your ext2fs libs have the ext2fs_read_inode_full function. + */ +#undef HAVE_EXT2FS_READ_INODE_FULL + /* Define if we have the ext2_ino_t type (from e2fsprogs 1.20+). */ #undef HAVE_EXT2_INO_T diff --git a/configure b/configure index fde7bb1..522d7b4 100755 --- a/configure +++ b/configure @@ -309,7 +309,7 @@ ac_includes_default="\ # include #endif" -ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS SET_MAKE LN_S CP MV RM AR ac_ct_AR RANLIB ac_ct_RANLIB PATCH ac_ct_PATCH CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA CPP EGREP DUMPDEBUG RESTOREDEBUG STATIC RMTDIR ERMT CRYPTO OPTDEFS READLINE LD CCOPTS LDOPTS BINOWNER BINGRP BINMODE MANOWNER MANGRP MANMODE DUMPDATESPATH BLKID ZLIB BZLIB top_builddir LIBOBJS LTLIBOBJS' +ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS SET_MAKE LN_S CP MV RM AR ac_ct_AR RANLIB ac_ct_RANLIB PATCH ac_ct_PATCH CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA CPP EGREP DUMPDEBUG RESTOREDEBUG STATIC RMTDIR ERMT CRYPTO OPTDEFS LD CCOPTS LDOPTS BINOWNER BINGRP BINMODE MANOWNER MANGRP MANMODE DUMPDATESPATH BLKID READLINE ZLIB BZLIB top_builddir LIBOBJS LTLIBOBJS' ac_subst_files='MCONFIG' # Initialize some variables set by options. @@ -3537,7 +3537,7 @@ then READLINE="" echo "Not including readline support" else - READLINE="-lreadline -ltermcap" + READLINE="yes" cat >>confdefs.h <<\_ACEOF #define HAVE_READLINE 1 @@ -3547,7 +3547,7 @@ _ACEOF fi else - READLINE="-lreadline -ltermcap" + READLINE="yes" cat >>confdefs.h <<\_ACEOF #define HAVE_READLINE 1 @@ -3557,7 +3557,6 @@ echo "Including readline support by default" fi; - # Check whether --enable-oldstylefscript or --disable-oldstylefscript was given. if test "${enable_oldstylefscript+set}" = set; then enableval="$enable_oldstylefscript" @@ -3937,6 +3936,84 @@ echo "$as_me: error: You need to install the Ext2fs libraries from the E2fsprogs { (exit 1); exit 1; }; } fi +echo "$as_me:$LINENO: checking for ext2fs_read_inode_full in -lext2fs" >&5 +echo $ECHO_N "checking for ext2fs_read_inode_full in -lext2fs... $ECHO_C" >&6 +if test "${ac_cv_lib_ext2fs_ext2fs_read_inode_full+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lext2fs -lcom_err $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char ext2fs_read_inode_full (); +int +main () +{ +ext2fs_read_inode_full (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_ext2fs_ext2fs_read_inode_full=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_lib_ext2fs_ext2fs_read_inode_full=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_ext2fs_ext2fs_read_inode_full" >&5 +echo "${ECHO_T}$ac_cv_lib_ext2fs_ext2fs_read_inode_full" >&6 +if test $ac_cv_lib_ext2fs_ext2fs_read_inode_full = yes; then + rif=yes +else + rif=no +fi + +if test "$rif" = yes; then + +cat >>confdefs.h <<\_ACEOF +#define HAVE_EXT2FS_READ_INODE_FULL 1 +_ACEOF + +fi + for ac_header in ext2fs/ext2_fs.h do @@ -4244,6 +4321,76 @@ _ACEOF fi +echo "$as_me:$LINENO: checking for tgetent in -lncurses" >&5 +echo $ECHO_N "checking for tgetent in -lncurses... $ECHO_C" >&6 +if test "${ac_cv_lib_ncurses_tgetent+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lncurses $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char tgetent (); +int +main () +{ +tgetent (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_lib_ncurses_tgetent=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_lib_ncurses_tgetent=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_lib_ncurses_tgetent" >&5 +echo "${ECHO_T}$ac_cv_lib_ncurses_tgetent" >&6 +if test $ac_cv_lib_ncurses_tgetent = yes; then + ncurses_lib=yes +else + ncurses_lib=no +fi + echo "$as_me:$LINENO: checking for tgetent in -ltermcap" >&5 echo $ECHO_N "checking for tgetent in -ltermcap... $ECHO_C" >&6 if test "${ac_cv_lib_termcap_tgetent+set}" = set; then @@ -4314,13 +4461,19 @@ else termcap_lib=no fi -if test "$termcap_lib" = no; then - if test "$READLINE" = "-lreadline -ltermcap"; then - { { echo "$as_me:$LINENO: error: You need to install the GNU termcap library or configure without --enable-readline" >&5 -echo "$as_me: error: You need to install the GNU termcap library or configure without --enable-readline" >&2;} + +if test "$ncurses_lib" = no -a "$termcap_lib" = no; then + if test "$READLINE" = "yes"; then + { { echo "$as_me:$LINENO: error: You need to install the ncurses or termcap library or configure without --enable-readline" >&5 +echo "$as_me: error: You need to install the ncurses or termcap library or configure without --enable-readline" >&2;} { (exit 1); exit 1; }; } fi fi +if test "$ncurses_lib" = yes; then + rdllib="-lncurses" +elif test "$termcap_lib" = yes; then + rdllib="-ltermcap" +fi echo "$as_me:$LINENO: checking for readline/readline.h" >&5 echo $ECHO_N "checking for readline/readline.h... $ECHO_C" >&6 @@ -4377,7 +4530,7 @@ if test "${ac_cv_lib_readline_readline+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_check_lib_save_LIBS=$LIBS -LIBS="-lreadline "-ltermcap" $LIBS" +LIBS="-lreadline $rdllib $LIBS" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF @@ -4442,12 +4595,16 @@ else fi if test "$readline_h" = no -o "$readline_lib" = no; then - if test "$READLINE" = "-lreadline -ltermcap"; then + if test "$READLINE" = "yes"; then { { echo "$as_me:$LINENO: error: You need to install the GNU readline library or configure without --enable-readline" >&5 echo "$as_me: error: You need to install the GNU readline library or configure without --enable-readline" >&2;} { (exit 1); exit 1; }; } fi fi +if test "$READLINE" = yes; then + READLINE="-lreadline $rdllib" +fi + echo "$as_me:$LINENO: checking for rl_completion_matches in -lreadline" >&5 echo $ECHO_N "checking for rl_completion_matches in -lreadline... $ECHO_C" >&6 @@ -6126,7 +6283,6 @@ s,@RMTDIR@,$RMTDIR,;t t s,@ERMT@,$ERMT,;t t s,@CRYPTO@,$CRYPTO,;t t s,@OPTDEFS@,$OPTDEFS,;t t -s,@READLINE@,$READLINE,;t t s,@LD@,$LD,;t t s,@CCOPTS@,$CCOPTS,;t t s,@LDOPTS@,$LDOPTS,;t t @@ -6138,6 +6294,7 @@ s,@MANGRP@,$MANGRP,;t t s,@MANMODE@,$MANMODE,;t t s,@DUMPDATESPATH@,$DUMPDATESPATH,;t t s,@BLKID@,$BLKID,;t t +s,@READLINE@,$READLINE,;t t s,@ZLIB@,$ZLIB,;t t s,@BZLIB@,$BZLIB,;t t s,@top_builddir@,$top_builddir,;t t diff --git a/configure.in b/configure.in index bcafc46..3788737 100644 --- a/configure.in +++ b/configure.in @@ -161,16 +161,15 @@ then READLINE="" echo "Not including readline support" else - READLINE="-lreadline -ltermcap" + READLINE="yes" AC_DEFINE([HAVE_READLINE],1,[Define if you want to include readline support.]) echo "Including readline support" fi , -READLINE="-lreadline -ltermcap" +READLINE="yes" AC_DEFINE([HAVE_READLINE],1,[Define if you want to include readline support.]) echo "Including readline support by default" ) -AC_SUBST(READLINE) dnl dnl Handle --enable-oldsylefscript @@ -394,6 +393,14 @@ if test "$ext2fs_h" = no -o "$ext2fs_lib" = no; then AC_MSG_ERROR(You need to install the Ext2fs libraries from the E2fsprogs distribution first - hint: make install-libs) fi +dnl +dnl Check for ext2fs_read_inode_full +dnl +AC_CHECK_LIB(ext2fs, ext2fs_read_inode_full, [rif=yes], [rif=no], [-lcom_err]) +if test "$rif" = yes; then + AC_DEFINE([HAVE_EXT2FS_READ_INODE_FULL],1,[Define this if your ext2fs libs have the ext2fs_read_inode_full function.]) +fi + dnl dnl Try to use ext2_fs.h header from libext2fs instead of from the kernel dnl @@ -443,25 +450,36 @@ fi AC_SUBST(BLKID) dnl -dnl Check for termcap libraries +dnl Check for ncurses or termcap libraries dnl +AC_CHECK_LIB(ncurses, tgetent, [ncurses_lib=yes], [ncurses_lib=no]) AC_CHECK_LIB(termcap, tgetent, [termcap_lib=yes], [termcap_lib=no]) -if test "$termcap_lib" = no; then - if test "$READLINE" = "-lreadline -ltermcap"; then - AC_MSG_ERROR(You need to install the GNU termcap library or configure without --enable-readline) + +if test "$ncurses_lib" = no -a "$termcap_lib" = no; then + if test "$READLINE" = "yes"; then + AC_MSG_ERROR(You need to install the ncurses or termcap library or configure without --enable-readline) fi fi +if test "$ncurses_lib" = yes; then + rdllib="-lncurses" +elif test "$termcap_lib" = yes; then + rdllib="-ltermcap" +fi dnl dnl Check for readline headers and libraries dnl AC_CHECK_HEADER(readline/readline.h, [readline_h=yes], [readline_h=no], [-]) -AC_CHECK_LIB(readline, readline, [readline_lib=yes], [readline_lib=no], "-ltermcap") +AC_CHECK_LIB(readline, readline, [readline_lib=yes], [readline_lib=no], $rdllib) if test "$readline_h" = no -o "$readline_lib" = no; then - if test "$READLINE" = "-lreadline -ltermcap"; then + if test "$READLINE" = "yes"; then AC_MSG_ERROR(You need to install the GNU readline library or configure without --enable-readline) fi fi +if test "$READLINE" = yes; then + READLINE="-lreadline $rdllib" +fi +AC_SUBST(READLINE) dnl dnl Check for rl_completion_matches diff --git a/debian/changelog b/debian/changelog index 39ea000..fa233d4 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,19 @@ +dump (0.4b40-1) unstable; urgency=low + + * new upstream version, closes: #289210, #291644, #307423 + * add debconf-2.0 as an alternate dependency + * updated Swedish translation from Daniel Nylander, closes: #330316 + * remove /var/lib/dumpdates on purge, since we created it on install, + closes: #330363 + * update dependencies in light of libreadline5-dev, closes: #326374 + * rebuild ensures fresh version of zlib in case we've been vulnerable + to CAN-2005-2096, closes: #317966 + * merge Vietnamese translation, closes: #311599 + * merge Czech translation, closes: #315825 + * update debhelper compatibility level, plus a few tweaks to pacify lintian + + -- Bdale Garbee Wed, 28 Sep 2005 00:50:29 -0600 + dump (0.4b37-2) unstable; urgency=low * merge updated de.po, closes: #281076 diff --git a/debian/compat b/debian/compat new file mode 100644 index 0000000..b8626c4 --- /dev/null +++ b/debian/compat @@ -0,0 +1 @@ +4 diff --git a/debian/config b/debian/config index 4489656..1d8f82e 100644 --- a/debian/config +++ b/debian/config @@ -13,7 +13,7 @@ if [ -L /etc/dumpdates ]; then db_go fi -if [ -f /etc/dumpdates -a ! -f /var/lib/dumpdates ]; then +if [ -f /etc/dumpdates ] && [ -f /var/lib/dumpdates ]; then # moving from etc to var db_input medium dump/moving_from_etc_to_var || true db_go diff --git a/debian/control b/debian/control index 83785a0..75dad1a 100644 --- a/debian/control +++ b/debian/control @@ -2,12 +2,12 @@ Source: dump Section: utils Priority: optional Maintainer: Bdale Garbee -Build-Depends: autoconf, comerr-dev, debhelper (>= 4.1.16), e2fslibs-dev, libbz2-dev, libreadline4-dev, zlib1g-dev, libblkid-dev, uuid-dev -Standards-Version: 3.6.1.0 +Build-Depends: autoconf, comerr-dev, debhelper (>= 4.1.16), e2fslibs-dev, libbz2-dev, libreadline5-dev | libreadline-dev, zlib1g-dev, libblkid-dev, uuid-dev +Standards-Version: 3.6.2.1 Package: dump Architecture: any -Depends: ${shlibs:Depends}, debconf (>= 0.5.00), tar (>= 1.13.92-3) +Depends: ${shlibs:Depends}, debconf (>= 0.5.00) | debconf-2.0, tar (>= 1.13.92-3) Description: 4.4bsd dump and restore for ext2 filesystems Dump examines files on a filesystem and determines which files need to be backed up. These files are copied to the given disk, tape or other storage diff --git a/debian/po/cs.po b/debian/po/cs.po new file mode 100644 index 0000000..7cc808f --- /dev/null +++ b/debian/po/cs.po @@ -0,0 +1,52 @@ +# +# Translators, if you are not familiar with the PO format, gettext +# documentation is worth reading, especially sections dedicated to +# this format, e.g. by running: +# info -n '(gettext)PO Files' +# info -n '(gettext)Header Entry' +# +# Some information specific to po-debconf are available at +# /usr/share/doc/po-debconf/README-trans +# or http://www.debian.org/intl/l10n/po-debconf/README-trans +# +# Developers do not need to manually edit POT or PO files. +# +msgid "" +msgstr "" +"Project-Id-Version: dump\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2003-08-19 16:21-0600\n" +"PO-Revision-Date: 2005-06-25 17:53+0200\n" +"Last-Translator: Miroslav Kure \n" +"Language-Team: Czech \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. Description +#: ../templates:3 +msgid "/etc/dumpdates is a symlink, dump will look in /var/lib/dumpdates" +msgstr "/etc/dumpdates je symbolický odkaz, dump hledá /var/lib/dumpdates" + +#. Description +#: ../templates:3 +msgid "" +"Your /etc/dumpdates is a symlink. Dump will look for dumpdates in /var/lib/" +"dumpdates. A symlink in /etc/dumpdates adds no known value (as nothing " +"outside the dump package is known to use it) and is likely to confuse " +"someone eventually. The most likely reason for this symlink to exist is " +"that you once had a much earlier version of the Debian dump package " +"installed that behaved poorly. Please remove /etc/dumpdates." +msgstr "" +"/etc/dumpdates je symbolický odkaz. Dump bude hledat dumpdates ve /var/lib/" +"dumpdates. Odkaz /etc/dumpdates nepřináší nic užitečného, protože vyjma " +"balíku dump jej nic jiného nepoužívá a dříve či později někoho zmate. " +"Nejpravděpodobnější vysvětlení pro existenci tohoto odkazu je, že jste " +"kdysi dávno používali prastarou verzi balíku dump. Odstraňte prosím " +"odkaz /etc/dumpdates." + +#. Description +#: ../templates:13 +msgid "Moving existing /etc/dumpdates to /var/lib for FHS compliance." +msgstr "" +"Přesouvám stávající /etc/dumpdates do /var/lib kvůli kompatibilitě s FHS." diff --git a/debian/po/sv.po b/debian/po/sv.po index 9181b1f..96bdef2 100644 --- a/debian/po/sv.po +++ b/debian/po/sv.po @@ -1,28 +1,26 @@ -# -# Translators, if you are not familiar with the PO format, gettext -# documentation is worth reading, especially sections dedicated to -# this format, e.g. by running: -# info -n '(gettext)PO Files' -# info -n '(gettext)Header Entry' -# -# Some information specific to po-debconf are available at -# /usr/share/doc/po-debconf/README-trans -# or http://www.debian.org/intl/l10n/po-debconf/README-trans -# -# Developers do not need to manually edit POT or PO files. -# -#, fuzzy +# Translators, if you are not familiar with the PO format, gettext +# documentation is worth reading, especially sections dedicated to +# this format, e.g. by running: +# info -n '(gettext)PO Files' +# info -n '(gettext)Header Entry' +# Some information specific to po-debconf are available at +# /usr/share/doc/po-debconf/README-trans +# or http://www.debian.org/intl/l10n/po-debconf/README-trans +# Developers do not need to manually edit POT or PO files. +# , fuzzy +# +# msgid "" msgstr "" -"Project-Id-Version: PACKAGE VERSION\n" +"Project-Id-Version: dump 0.4b37-2\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2003-08-19 16:21-0600\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language-Team: LANGUAGE \n" +"PO-Revision-Date: 2005-09-27 15:47-0700\n" +"Last-Translator: Daniel Nylander \n" +"Language-Team: Swedish \n" "MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=ISO-8859-1\n" -"Content-Transfer-Encoding: 8bit\n" +"Content-Type: text/plain; charset=iso-8859-1\n" +"Content-Transfer-Encoding: 8bit" #. Description #: ../templates:3 @@ -38,7 +36,7 @@ msgid "" "someone eventually. The most likely reason for this symlink to exist is " "that you once had a much earlier version of the Debian dump package " "installed that behaved poorly. Please remove /etc/dumpdates." -msgstr "" +msgstr "Din /etc/dumpdates fil är en symbolisk länk. Dump kommer att leta efter dumpdatum i /var/lib/dumpdates. En symbolisk länk i /etc/dumpdates saknar värde och skapar bara förvirring. Ett antagande är att filen existerar sedan en gammal version av dump som blev installerad felaktigt. Var vänlig och radera /etc/dumpdates." #. Description #: ../templates:13 @@ -49,5 +47,5 @@ msgstr "Flyttar existerande /etc/dumpdates till /var/lib f #~ "Your /etc/dumpdates is a symlink. Dump will look for dumpdates in /var/" #~ "lib/dumpdates. Please fix things." #~ msgstr "" -#~ "Din /etc/dumpdates är en symlänk. Dump kommer att kolla efter dumpdates " -#~ "i /var/lib/dumpdates. Var snäll och fixa till detta." +#~ "Din /etc/dumpdates är en symlänk. Dump kommer att kolla efter dumpdates " +#~ "i /var/lib/dumpdates. Var snäll och fixa till detta." diff --git a/debian/po/vi.po b/debian/po/vi.po new file mode 100644 index 0000000..ffa3a16 --- /dev/null +++ b/debian/po/vi.po @@ -0,0 +1,37 @@ +# Vietnamese Translation for dump. +# Copyright © 2005 Free Software Foundation, Inc. +# Clytie Siddall , 2005. +# +msgid "" +msgstr "" +"Project-Id-Version: dump 0.4b37-1\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2003-08-19 16:21-0600\n" +"PO-Revision-Date: 2005-06-02 15:39+0930\n" +"Last-Translator: Clytie Siddall \n" +"Language-Team: Vietnamese \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0\n" + +#. Description +#: ../templates:3 +msgid "/etc/dumpdates is a symlink, dump will look in /var/lib/dumpdates" +msgstr "/etc/dumpdates là một liên kết tượng trưng nên trình dump sẽ tìm trong /var/lib/dumpdates" + +#. Description +#: ../templates:3 +msgid "" +"Your /etc/dumpdates is a symlink. Dump will look for dumpdates in /var/lib/" +"dumpdates. A symlink in /etc/dumpdates adds no known value (as nothing " +"outside the dump package is known to use it) and is likely to confuse " +"someone eventually. The most likely reason for this symlink to exist is " +"that you once had a much earlier version of the Debian dump package " +"installed that behaved poorly. Please remove /etc/dumpdates." +msgstr "/etc/dumpdates cá»§a bạn là một liên kết tượng trưng, nên trình dump sẽ tìm dumpdates (ngày đổ) trong /var/lib/dumpdates. Một liên kết tượng trưng trong /etc/dumpdates không thêm giá trị hữu ích nào (vì không có gì ở ngoại gói dump sẽ dùng nó) và rất có thể sẽ làm cho người dùng lẫn lộn cuối cùng. Có liên kết tượng trưng ấy rất có thể vì trước này bạn đã cài đặt một phiên bản nhiều cÅ© hÆ¡n cá»§a gói tin dump Debian mà không hoạt động cho đúng. Hãy loại bỏ /etc/dumpdates." + +#. Description +#: ../templates:13 +msgid "Moving existing /etc/dumpdates to /var/lib for FHS compliance." +msgstr "Đang di chuyển /etc/dumpdates đã có vào /var/lib để tương tác với FHS." diff --git a/debian/postinst b/debian/postinst index 4b13729..f7bc154 100644 --- a/debian/postinst +++ b/debian/postinst @@ -4,7 +4,7 @@ set -e . /usr/share/debconf/confmodule -if [ -f /etc/dumpdates -a ! -f /var/lib/dumpdates ]; then +if [ -f /etc/dumpdates ] && [ ! -f /var/lib/dumpdates ]; then mv /etc/dumpdates /var/lib/dumpdates fi diff --git a/debian/postrm b/debian/postrm new file mode 100644 index 0000000..f5ca1ce --- /dev/null +++ b/debian/postrm @@ -0,0 +1,5 @@ +#!/bin/sh -e + +rm -f /var/lib/dumpdates + +#DEBHELPER# diff --git a/debian/rules b/debian/rules index 4c603dd..7aa812b 100755 --- a/debian/rules +++ b/debian/rules @@ -27,16 +27,16 @@ binary-arch: build dh_clean -k dh_installdirs make install \ - SBINDIR=`pwd`/debian/tmp/sbin \ - MANDIR=`pwd`/debian/tmp/usr/share/man/man8 + SBINDIR=`pwd`/debian/dump/sbin \ + MANDIR=`pwd`/debian/dump/usr/share/man/man8 - mv debian/tmp/usr/share/man/man8/rmt.8 \ - debian/tmp/usr/share/man/man8/rmt-dump.8 - mv debian/tmp/sbin/rmt debian/tmp/usr/sbin/rmt-dump + mv debian/dump/usr/share/man/man8/rmt.8 \ + debian/dump/usr/share/man/man8/rmt-dump.8 + mv debian/dump/sbin/rmt debian/dump/usr/sbin/rmt-dump - (cd debian/tmp/sbin ; rm -f rdump rrestore ; \ + (cd debian/dump/sbin ; rm -f rdump rrestore ; \ ln -s dump rdump ; ln -s restore rrestore ) - (cd debian/tmp/usr/share/man/man8 ; rm -f rdump* rrestore* ; \ + (cd debian/dump/usr/share/man/man8 ; rm -f rdump* rrestore* ; \ ln -s dump.8.gz rdump.8.gz ; ln -s restore.8.gz rrestore.8.gz ) dh_installdocs KNOWNBUGS MAINTAINERS README THANKS TODO dh_installexamples examples/* diff --git a/dump.lsm b/dump.lsm index 73f53f7..043c2e2 100644 --- a/dump.lsm +++ b/dump.lsm @@ -1,13 +1,13 @@ Begin3 Title: dump and restore for Ext2fs -Version: 0.4b37 -Entered-date: 07JUL04 +Version: 0.4b40 +Entered-date: 01MAY05 Description: Port of the 4.4BSD dump and restore backup suite Keywords: backup, filesystem, Ext2fs Author: University of California, Berkeley Maintained-by: stelian@popies.net (Stelian Pop) Primary-site: http://dump.sourceforge.net/ - 0kB dump-0.4b37.tar.gz + 0kB dump-0.4b40.tar.gz 0 dump.lsm Original-site: ftp.freebsd.org /pub/bsd-sources/4.4BSD-Lite2/sbin dump/* diff --git a/dump.spec b/dump.spec index ae0c08e..6d90193 100644 --- a/dump.spec +++ b/dump.spec @@ -4,7 +4,7 @@ Summary: Programs for backing up and restoring ext2/ext3 filesystems. Name: dump -Version: 0.4b37 +Version: 0.4b40 Release: 1 License: BSD URL: http://dump.sourceforge.net @@ -136,6 +136,12 @@ rm -rf %{buildroot} %{_sbindir}/rrestore.static %changelog +* Fri Jan 21 2005 Stelian Pop +- dump 0.4b39 released, first packaging. + +* Fri Jan 7 2005 Stelian Pop +- dump 0.4b38 released, first packaging. + * Wed Jul 7 2004 Stelian Pop - dump 0.4b37 released, first packaging. diff --git a/dump/dump.8.in b/dump/dump.8.in index 487302d..a6bf3f0 100644 --- a/dump/dump.8.in +++ b/dump/dump.8.in @@ -26,7 +26,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.\" $Id: dump.8.in,v 1.56 2004/04/21 08:55:48 stelian Exp $ +.\" $Id: dump.8.in,v 1.57 2004/07/13 08:17:32 stelian Exp $ .\" .TH DUMP 8 "version __VERSION__ of __DATE__" BSD "System management commands" .SH NAME @@ -57,9 +57,6 @@ dump \- ext2/3 filesystem backup .PP .B dump [\fB\-W \fR| \fB\-w\fR] -.PP -(The 4.3BSD option syntax is implemented for backward compatibility but is not -documented here.) .SH DESCRIPTION .B Dump examines files on an ext2/3 filesystem and determines which files need to be @@ -530,6 +527,9 @@ set of tapes per dumped file system is used, also on a cyclical basis. .PP After several months or so, the daily and weekly tapes should get rotated out of the dump cycle and fresh tapes brought in. +.PP +(The 4.3BSD option syntax is implemented for backward compatibility but is not +documented here.) .SH ENVIRONMENT .TP .B TAPE diff --git a/dump/tape.c b/dump/tape.c index 2df4d1e..89f630d 100644 --- a/dump/tape.c +++ b/dump/tape.c @@ -37,7 +37,7 @@ #ifndef lint static const char rcsid[] = - "$Id: tape.c,v 1.86 2004/07/07 11:07:29 stelian Exp $"; + "$Id: tape.c,v 1.88 2005/03/02 08:46:55 stelian Exp $"; #endif /* not lint */ #include @@ -420,6 +420,10 @@ flushtape(void) int siz = (char *)nextblock - (char *)slp->req; + /* make sure returned has sane values in case we don't read + * them from the slave in this pass */ + returned.unclen = returned.clen = writesize; + slp->req[trecno].count = 0; /* Sentinel */ if (dump_atomic_write( slp->fd, (char *)slp->req, siz) != siz) @@ -475,10 +479,14 @@ flushtape(void) } blks = 0; - if (spcl.c_type != TS_END) { - for (i = 0; i < spcl.c_count; i++) - if (spcl.c_addr[i] != 0) - blks++; + if (spcl.c_type == TS_CLRI || spcl.c_type == TS_BITS) + blks = spcl.c_count; + else { + if (spcl.c_type != TS_END) { + for (i = 0; i < spcl.c_count; i++) + if (spcl.c_addr[i] != 0) + blks++; + } } slp->count = lastspclrec + blks + 1 - spcl.c_tapea; slp->tapea = spcl.c_tapea; @@ -616,6 +624,10 @@ rollforward(void) tslp = &slaves[SLAVES]; ntb = (union u_spcl *)tslp->tblock[1]; + /* make sure returned has sane values in case we don't read + * them from the slave in this pass */ + returned.unclen = returned.clen = writesize; + /* * Each of the N slaves should have requests that need to * be replayed on the next tape. Use the extra slave buffers diff --git a/dump/traverse.c b/dump/traverse.c index 4104799..64c32a5 100644 --- a/dump/traverse.c +++ b/dump/traverse.c @@ -37,7 +37,7 @@ #ifndef lint static const char rcsid[] = - "$Id: traverse.c,v 1.61 2004/07/01 09:14:49 stelian Exp $"; + "$Id: traverse.c,v 1.66 2005/05/02 15:10:46 stelian Exp $"; #endif /* not lint */ #include @@ -100,6 +100,7 @@ static void dmpindir __P((dump_ino_t ino, daddr_t blk, int level, fsizeT *size)) static int searchdir __P((dump_ino_t ino, daddr_t blkno, long size, long filesize)); #endif static void mapfileino __P((dump_ino_t ino, struct dinode const *dp, long *tapesize, int *dirskipped)); +static void dump_xattr __P((dump_ino_t ino, struct dinode *dp)); #ifdef HAVE_EXT2_JOURNAL_INUM #define ext2_journal_ino(sb) (sb->s_journal_inum) @@ -283,6 +284,9 @@ mapfileino(dump_ino_t ino, struct dinode const *dp, long *tapesize, int *dirskip */ SETINO(ino, usedinomap); + if (NODUMP_FLAG(dp)) + do_exclude_ino(ino, "nodump attribute"); + if (mode == IFDIR) SETINO(ino, dumpdirmap); if (WANTTODUMP(dp, ino)) { @@ -296,7 +300,7 @@ mapfileino(dump_ino_t ino, struct dinode const *dp, long *tapesize, int *dirskip return; } if (mode == IFDIR) { - if ( NODUMP_FLAG(dp) || exclude_ino(ino) ) + if (exclude_ino(ino)) CLRINO(ino, usedinomap); *dirskipped = 1; } @@ -793,6 +797,68 @@ dumponeblock(UNUSED(ext2_filsys fs), blk_t *blocknr, e2_blkcnt_t blockcnt, } #endif +static void +dump_xattr(dump_ino_t ino, struct dinode *dp) { + + if (dp->di_extraisize != 0) { +#ifdef HAVE_EXT2FS_READ_INODE_FULL + char inode[EXT2_INODE_SIZE(fs->super)]; + errcode_t err; + u_int32_t *magic; + + memset(inode, 0, EXT2_INODE_SIZE(fs->super)); + err = ext2fs_read_inode_full(fs, (ext2_ino_t)ino, + (struct ext2_inode *) inode, + EXT2_INODE_SIZE(fs->super)); + if (err) { + com_err(disk, err, "while reading inode #%ld\n", (long)ino); + exit(X_ABORT); + } + + magic = (void *)inode + EXT2_GOOD_OLD_INODE_SIZE + dp->di_extraisize; + if (*magic == EXT2_XATTR_MAGIC) { + char xattr[EXT2_INODE_SIZE(fs->super)]; + int i; + char *cp; + + if (vflag) + msg("dumping EA (inode) in inode #%ld\n", (long)ino); + memset(xattr, 0, EXT2_INODE_SIZE(fs->super)); + memcpy(xattr, (void *)magic, + EXT2_INODE_SIZE(fs->super) - + (EXT2_GOOD_OLD_INODE_SIZE + dp->di_extraisize)); + magic = (u_int32_t *)xattr; + *magic = EXT2_XATTR_MAGIC2; + + spcl.c_type = TS_INODE; + spcl.c_dinode.di_size = EXT2_INODE_SIZE(fs->super); + spcl.c_flags |= DR_EXTATTRIBUTES; + spcl.c_extattributes = EXT_XATTR; + spcl.c_count = howmany(EXT2_INODE_SIZE(fs->super), TP_BSIZE); + writeheader(ino); + for (i = 0, cp = xattr; i < spcl.c_count; i++, cp += TP_BSIZE) + writerec(cp, 0); + spcl.c_flags &= ~DR_EXTATTRIBUTES; + spcl.c_extattributes = 0; + } +#endif + } + + if (dp->di_file_acl) { + + if (vflag) + msg("dumping EA (block) in inode #%ld\n", (long)ino); + + spcl.c_type = TS_INODE; + spcl.c_dinode.di_size = sblock->fs_bsize; + spcl.c_flags |= DR_EXTATTRIBUTES; + spcl.c_extattributes = EXT_XATTR; + blksout(&dp->di_file_acl, EXT2_FRAGS_PER_BLOCK(fs->super), ino); + spcl.c_flags &= ~DR_EXTATTRIBUTES; + spcl.c_extattributes = 0; + } +} + /* * Dump passes 3 and 4. * @@ -839,8 +905,6 @@ dumpino(struct dinode *dp, dump_ino_t ino, int metaonly) nbi.di_gen = dp->di_gen; nbi.di_uid = (((int32_t)dp->di_uidhigh) << 16) | dp->di_uid; nbi.di_gid = (((int32_t)dp->di_gidhigh) << 16) | dp->di_gid; - if (dp->di_file_acl) - msg("ACLs in inode #%ld won't be dumped\n", (long)ino); memmove(&spcl.c_dinode, &nbi, sizeof(nbi)); #else /* __linux__ */ spcl.c_dinode = *dp; @@ -853,6 +917,7 @@ dumpino(struct dinode *dp, dump_ino_t ino, int metaonly) spcl.c_count = 0; writeheader(ino); spcl.c_flags &= ~DR_METAONLY; + dump_xattr(ino, dp); return; } @@ -883,6 +948,7 @@ dumpino(struct dinode *dp, dump_ino_t ino, int metaonly) memmove(buf, dp->di_db, (u_long)dp->di_size); buf[dp->di_size] = '\0'; writerec(buf, 0); + dump_xattr(ino, dp); return; } #endif /* __linux__ */ @@ -913,6 +979,7 @@ dumpino(struct dinode *dp, dump_ino_t ino, int metaonly) case S_IFCHR: case S_IFBLK: writeheader(ino); + dump_xattr(ino, dp); return; default: @@ -928,8 +995,10 @@ dumpino(struct dinode *dp, dump_ino_t ino, int metaonly) else cnt = howmany(i_size, sblock->fs_fsize); blksout(&dp->di_db[0], cnt, ino); - if ((quad_t) (size = i_size - NDADDR * sblock->fs_bsize) <= 0) + if ((quad_t) (size = i_size - NDADDR * sblock->fs_bsize) <= 0) { + dump_xattr(ino, dp); return; + } #ifdef __linux__ bc.max = NINDIR(sblock) * EXT2_FRAGS_PER_BLOCK(fs->super); bc.buf = (int *)malloc (bc.max * sizeof (int)); @@ -953,6 +1022,7 @@ dumpino(struct dinode *dp, dump_ino_t ino, int metaonly) blksout (bc.buf, bc.cnt, bc.ino); } free(bc.buf); + dump_xattr(ino, dp); #else for (ind_level = 0; ind_level < NIADDR; ind_level++) { dmpindir(ino, dp->di_ib[ind_level], ind_level, &size); @@ -985,6 +1055,10 @@ convert_dir(struct ext2_dir_entry *dirent, UNUSED(int offset), struct direct *dp; int reclen; + /* do not save entries to excluded inodes */ + if (exclude_ino(dirent->inode)) + return 0; + p = (struct convert_dir_context *)private; reclen = EXT2_DIR_REC_LEN((dirent->name_len & 0xFF) + 1); @@ -1097,8 +1171,6 @@ dumpdirino(struct dinode *dp, dump_ino_t ino) nbi.di_gen = dp->di_gen; nbi.di_uid = (((int32_t)dp->di_uidhigh) << 16) | dp->di_uid; nbi.di_gid = (((int32_t)dp->di_gidhigh) << 16) | dp->di_gid; - if (dp->di_file_acl) - msg("ACLs in inode #%ld won't be dumped\n", (long)ino); memmove(&spcl.c_dinode, &nbi, sizeof(nbi)); #else /* __linux__ */ spcl.c_dinode = *dp; @@ -1135,6 +1207,7 @@ dumpdirino(struct dinode *dp, dump_ino_t ino) } (void)free(cdc.buf); + dump_xattr(ino, dp); } #endif /* __linux__ */ @@ -1241,6 +1314,7 @@ dumpmap(char *map, int type, dump_ino_t ino) spcl.c_type = type; spcl.c_count = howmany(mapsize * sizeof(char), TP_BSIZE); + spcl.c_dinode.di_size = mapsize; writeheader(ino); for (i = 0, cp = map; i < spcl.c_count; i++, cp += TP_BSIZE) writerec(cp, 0); @@ -1291,7 +1365,11 @@ getino(dump_ino_t inum) errcode_t err; curino = inum; +#ifdef HAVE_EXT2FS_READ_INODE_FULL + err = ext2fs_read_inode_full(fs, (ext2_ino_t)inum, (struct ext2_inode *) &dinode, sizeof(struct dinode)); +#else err = ext2fs_read_inode(fs, (ext2_ino_t)inum, (struct ext2_inode *) &dinode); +#endif if (err) { com_err(disk, err, "while reading inode #%ld\n", (long)inum); exit(X_ABORT); diff --git a/examples/dump_on_cd_3/README b/examples/dump_on_cd_3/README new file mode 100644 index 0000000..c632be6 --- /dev/null +++ b/examples/dump_on_cd_3/README @@ -0,0 +1,16 @@ +I took the dump_on_cd_2/EN/* scripts and merged the pair of scripts into one +script, which checks it's arguments to tell whether or not it is called from +dump and acts accordingly. + +The script commandline takes dump arguments except -f (output file/device), -F +(script to run after each volume is finished) and -B (volume size) which are +overridden. + +You can use the script to backup to CD with cdrtecord from cdrtools or to +DVD with either cdrtools with DVD support or growisofs from dvd+rw-tools. +You must configure the burning process by adjusting the variables at the top +of the script. + +Andrew Basterfield + +bob@cemetery.homeunix.org diff --git a/examples/dump_on_cd_3/dump_disk b/examples/dump_on_cd_3/dump_disk new file mode 100755 index 0000000..3e9200d --- /dev/null +++ b/examples/dump_on_cd_3/dump_disk @@ -0,0 +1,100 @@ +#!/bin/sh + +# This script dumps the specified Filesystem via dump on a CD/DVD +# DISK_CAPACITY defines the capacity in MB per disk. +# The script's own name $0 is passed via the -F option of dump +# When using cdrecord/dvdrecord and at least for my DVD-Recorder (a PHILIPS +# DVR-A03) it is necessary to define the tracksize for the next track before +# the DVD is written. This is done via the -tsize option of cdrecord. Since +# tsize takes its arguments in Bytes, the shell cannot compute the value +# correctly anymore (value too high), so I use bc. + +# Set this to 4300 for DVD and 650 or 700 for CD +#DISK_CAPACITY=10 # testing +#DISK_CAPACITY=650 +DISK_CAPACITY=4300 + +BSIZE="$(echo "$DISK_CAPACITY*1024" | bc -l )" +TSIZE="$(echo "$DISK_CAPACITY*1024*1024" | bc -l )" + +# This is used for testing +#RECORD_BIN="dd of=/dev/null bs=1k if=" + +# This is for writing to CD with cdrtools, this uses track-at-once mode +# in case cdrtools does not support disk-at-once with your burner +#RECORD_BIN="/usr/bin/cdrecord dev=0,0,0 fs=64M speed=2 -eject -tao -pad -tsize=$TSIZE -data " + +# This is for writing to DVD with cdrtools with DVD support, this has to +# use disk-at-once mode. +#RECORD_BIN="/usr/bin/cdrecord dev=0,0,0 fs=64M speed=2 -eject -dao -pad -tsize=$TSIZE -data " + +# This is for writing to DVD with growisofs +RECORD_BIN="/usr/bin/growisofs -Z /dev/dvd=" + +FIFO="/tmp/dump.$$.fifo" +DUMP="/sbin/dump" + +cleanup() { + rm -f $FIFO +} + +error_exit() { + retcode=$? + echo >&2 "Error $retcode: exiting" + exit $retcode +} + +trap error_exit ERR + +write_output() { + # supplied info from "dump -F": + # $1 = filename + # $2 = sequence number + echo "Please insert disk No. $(($2+1))" + ANSWER="" + while [ "$ANSWER" != "y" ] ; do + echo -n "Is the disk ready? (y/n) " + read &2 "Usage: $0 " + echo >&2 "See 'man dump' for dump options" + echo >&2 "the dump options -F -f -B are not required and are overridden" + exit 1 +fi + +set -m # We need proper job control + +if [ "$#" = "2" ] && [ -p "$1" ]; then + write_output "$@" || (kill $$ >/dev/null 2>&1; exit 1) + exit 0 +else + mkfifo $FIFO + trap cleanup EXIT + if write_output "$FIFO" "0"; then + if $DUMP "$@" -F "$0" -f "$FIFO" -B$BSIZE; then + echo "Waiting for background writing process to complete" + wait % # Wait for the background writing process + else + kill % >/dev/null 2>&1 # or kill it + exit 1 + fi + exit 0 + else + kill % >/dev/null 2>&1 # Kill the background writing process + exit 1 + fi +fi diff --git a/restore/Makefile.in b/restore/Makefile.in index cdc2004..79e03ea 100644 --- a/restore/Makefile.in +++ b/restore/Makefile.in @@ -1,4 +1,4 @@ -# $Id: Makefile.in,v 1.12 2003/05/08 21:11:39 stelian Exp $ +# $Id: Makefile.in,v 1.13 2005/05/02 15:10:46 stelian Exp $ top_srcdir= @top_srcdir@ srcdir= @srcdir@ @@ -16,9 +16,9 @@ PROG= restore RPROG= rrestore LINKS= ${SBINDIR}/restore ${SBINDIR}/rrestore SRCS= dirs.c interactive.c main.c restore.c symtab.c tape.c \ - utilities.c + utilities.c xattr.c OBJS= dirs.o interactive.o main.o restore.o symtab.o tape.o \ - utilities.o ../common/dumprmt.o + utilities.o xattr.o ../common/dumprmt.o MAN8= restore.8 RMAN8= rrestore.8 diff --git a/restore/dirs.c b/restore/dirs.c index 2a23f94..b049f49 100644 --- a/restore/dirs.c +++ b/restore/dirs.c @@ -42,7 +42,7 @@ #ifndef lint static const char rcsid[] = - "$Id: dirs.c,v 1.28 2004/05/25 10:39:30 stelian Exp $"; + "$Id: dirs.c,v 1.32 2005/05/02 15:10:46 stelian Exp $"; #endif /* not lint */ #include @@ -114,6 +114,7 @@ struct modeinfo { uid_t uid; gid_t gid; unsigned int flags; + char xattr; }; /* @@ -148,9 +149,11 @@ struct odirect { }; #if defined(__linux__) || defined(sunos) -static struct inotab *allocinotab __P((dump_ino_t, struct new_bsd_inode *, OFF_T)); +static struct inotab *allocinotab __P((dump_ino_t, OFF_T)); +static void savemodeinfo __P((dump_ino_t, struct new_bsd_inode *, char *)); #else -static struct inotab *allocinotab __P((dump_ino_t, struct dinode *, OFF_T)); +static struct inotab *allocinotab __P((dump_ino_t, OFF_T)); +static void savemodeinfo __P((dump_ino_t, struct dinode *, char *)); #endif static void dcvt __P((struct odirect *, struct direct *)); static void flushent __P((void)); @@ -177,13 +180,16 @@ extractdirs(int genmode) { int i; #if defined(__linux__) || defined(sunos) - struct new_bsd_inode *ip; + struct new_bsd_inode ip; #else - struct dinode *ip; + struct dinode ip; #endif struct inotab *itp; struct direct nulldir; int fd; + char xattr[XATTR_MAXSIZE]; + int xattr_found = 0; + dump_ino_t ino; Vprintf(stdout, "Extract directories from tape\n"); (void) snprintf(dirfile, sizeof(dirfile), "%s/rstdir%ld", tmpdir, @@ -222,8 +228,8 @@ extractdirs(int genmode) for (;;) { curfile.name = ""; curfile.action = USING; - ip = curfile.dip; - if (ip == NULL || (ip->di_mode & IFMT) != IFDIR) { + ino = curfile.ino; + if (curfile.dip == NULL || (curfile.dip->di_mode & IFMT) != IFDIR) { if ( fclose(df) == EOF ) err(1, "cannot write to file %s", dirfile); dirp = opendirfile(dirfile); @@ -236,8 +242,30 @@ extractdirs(int genmode) panic("Root directory is not on tape\n"); return; } - itp = allocinotab(curfile.ino, ip, seekpt); + memcpy(&ip, curfile.dip, sizeof(ip)); + itp = allocinotab(ino, seekpt); getfile(putdir, xtrnull); + xattr_found = 0; + while (spcl.c_flags & DR_EXTATTRIBUTES) { + switch (spcl.c_extattributes) { + case EXT_MACOSFNDRINFO: + msg("MacOSX attributes not supported, skipping\n"); + skipfile(); + break; + case EXT_MACOSRESFORK: + msg("MacOSX attributes not supported, skipping\n"); + skipfile(); + break; + case EXT_XATTR: + if (readxattr(xattr) == GOOD) + xattr_found = 1; + break; + } + } + if (xattr_found) + savemodeinfo(ino, &ip, xattr); + else + savemodeinfo(ino, &ip, NULL); putent(&nulldir); flushent(); itp->t_size = seekpt - itp->t_seekpt; @@ -654,9 +682,15 @@ setdirmodes(int flags) } clearerr(mf); for (;;) { + char xattr[XATTR_MAXSIZE]; (void) fread((char *)&node, 1, sizeof(struct modeinfo), mf); if (feof(mf)) break; + if (node.xattr) { + (void) fread(xattr, 1, XATTR_MAXSIZE, mf); + if (feof(mf)) + break; + } ep = lookupino(node.ino); if (command == 'i' || command == 'x') { if (ep == NULL) @@ -678,7 +712,7 @@ setdirmodes(int flags) (void) chmod(cp, node.mode); if (node.flags) #ifdef __linux__ - (void) fsetflags(cp, node.flags); + (void) lsetflags(cp, node.flags); #else #ifdef sunos #else @@ -686,6 +720,105 @@ setdirmodes(int flags) #endif #endif utimes(cp, node.timep); + if (node.xattr) + xattr_extract(cp, xattr); + ep->e_flags &= ~NEW; + } + } + if (ferror(mf)) + panic("error setting directory modes\n"); + (void) fclose(mf); +} + +/* + * In restore -C mode, tests the attributes for all directories + */ +void +comparedirmodes(void) +{ + FILE *mf; + struct modeinfo node; + struct entry *ep; + char *cp; + + Vprintf(stdout, "Compare directories modes, owner, attributes.\n"); + if (modefile[0] == '#') { + panic("modefile not defined\n"); + fprintf(stderr, "directory mode, owner, and times not set\n"); + return; + } + mf = fopen(modefile, "r"); + if (mf == NULL) { + warn("fopen"); + fprintf(stderr, "cannot open mode file %s\n", modefile); + fprintf(stderr, "directory mode, owner, and times not set\n"); + return; + } + clearerr(mf); + for (;;) { + char xattr[XATTR_MAXSIZE]; + (void) fread((char *)&node, 1, sizeof(struct modeinfo), mf); + if (feof(mf)) + break; + if (node.xattr) { + (void) fread(xattr, 1, XATTR_MAXSIZE, mf); + if (feof(mf)) + break; + } + ep = lookupino(node.ino); + if (ep == NULL) { + panic("cannot find directory inode %d\n", node.ino); + } else { + cp = myname(ep); + struct STAT sb; + unsigned long newflags; + + if (LSTAT(cp, &sb) < 0) { + warn("unable to stat %s", cp); + do_compare_error; + continue; + } + + Vprintf(stdout, "comparing directory %s\n", cp); + + if (sb.st_mode != node.mode) { + fprintf(stderr, "%s: mode changed from 0%o to 0%o.\n", + cp, node.mode & 07777, sb.st_mode & 07777); + do_compare_error; + } + if (sb.st_uid != node.uid) { + fprintf(stderr, "%s: uid changed from %d to %d.\n", + cp, node.uid, sb.st_uid); + do_compare_error; + } + if (sb.st_gid != node.gid) { + fprintf(stderr, "%s: gid changed from %d to %d.\n", + cp, node.gid, sb.st_gid); + do_compare_error; + } +#ifdef __linux__ + if (lgetflags(cp, &newflags) < 0) { + if (node.flags != 0) { + warn("%s: lgetflags failed", cp); + do_compare_error; + } + } + else { + if (newflags != node.flags) { + fprintf(stderr, "%s: flags changed from 0x%08x to 0x%08lx.\n", + cp, node.flags, newflags); + do_compare_error; + } + } +#endif + if (node.xattr) { + if (xattr_compare(cp, xattr) == FAIL) + do_compare_error; + } + else { + if (xattr_compare(cp, NULL) == FAIL) + do_compare_error; + } ep->e_flags &= ~NEW; } } @@ -751,13 +884,12 @@ inodetype(dump_ino_t ino) */ static struct inotab * #if defined(__linux__) || defined(sunos) -allocinotab(dump_ino_t ino, struct new_bsd_inode *dip, OFF_T seekpt) +allocinotab(dump_ino_t ino, OFF_T seekpt) #else -allocinotab(dump_ino_t ino, struct dinode *dip, OFF_T seekpt) +allocinotab(dump_ino_t ino, OFF_T seekpt) #endif { struct inotab *itp; - struct modeinfo node; itp = calloc(1, sizeof(struct inotab)); if (itp == NULL) @@ -766,8 +898,19 @@ allocinotab(dump_ino_t ino, struct dinode *dip, OFF_T seekpt) inotab[INOHASH(ino)] = itp; itp->t_ino = ino; itp->t_seekpt = seekpt; + return itp; +} + +static void +#if defined(__linux__) || defined(sunos) +savemodeinfo(dump_ino_t ino, struct new_bsd_inode *dip, char *xattr) { +#else +savemodeinfo(dump_ino_t ino, struct dinode *dip, char *xattr) { +#endif + struct modeinfo node; + if (mf == NULL) - return (itp); + return; node.ino = ino; #if defined(__linux__) || defined(sunos) node.timep[0].tv_sec = dip->di_atime.tv_sec; @@ -784,9 +927,12 @@ allocinotab(dump_ino_t ino, struct dinode *dip, OFF_T seekpt) node.flags = dip->di_flags; node.uid = dip->di_uid; node.gid = dip->di_gid; + node.xattr = xattr ? 1 : 0; if ( fwrite((char *)&node, 1, sizeof(struct modeinfo), mf) != sizeof(struct modeinfo) ) err(1,"cannot write to file %s", modefile); - return (itp); + if (xattr) + if ( fwrite(xattr, 1, XATTR_MAXSIZE, mf) != XATTR_MAXSIZE) + err(1,"cannot write to file %s", modefile); } /* diff --git a/restore/extern.h b/restore/extern.h index e2702ed..16e2440 100644 --- a/restore/extern.h +++ b/restore/extern.h @@ -5,7 +5,7 @@ * Stelian Pop , 1999-2000 * Stelian Pop - Alcôve , 2000-2002 * - * $Id: extern.h,v 1.23 2003/10/26 16:05:48 stelian Exp $ + * $Id: extern.h,v 1.25 2005/05/02 15:10:46 stelian Exp $ */ /*- @@ -107,6 +107,7 @@ void rst_closedir __P((RST_DIR *dirp)); void runcmdshell __P((void)); char *savename __P((char *)); void setdirmodes __P((int)); +void comparedirmodes __P((void)); void setinput __P((char *)); void setup __P((void)); void skipdirs __P((void)); @@ -131,6 +132,9 @@ int fsetflags __P((const char *, unsigned long)); int fgetflags __P((const char *, unsigned long *)); int setflags __P((int, unsigned long)); +int lsetflags __P((const char *, unsigned long)); +int lgetflags __P((const char *, unsigned long *)); + #ifdef USE_QFA int Inode2Tapepos __P((dump_ino_t, long *, long long *, int)); int GetTapePos __P((long long *)); @@ -152,5 +156,7 @@ int extractresourceufs __P((char *)); int CreateAppleDoubleFileRes __P((char *, FndrFileInfo *, mode_t, int, struct timeval *, u_int32_t, u_int32_t)); #endif - - +void skipxattr __P((void)); +int readxattr __P((char *)); +int xattr_compare __P((char *, char *)); +int xattr_extract __P((char *, char *)); diff --git a/restore/main.c b/restore/main.c index f53d740..dfbe8c6 100644 --- a/restore/main.c +++ b/restore/main.c @@ -37,7 +37,7 @@ #ifndef lint static const char rcsid[] = - "$Id: main.c,v 1.46 2004/04/13 13:04:33 stelian Exp $"; + "$Id: main.c,v 1.49 2005/01/14 13:04:56 stelian Exp $"; #endif /* not lint */ #include @@ -112,6 +112,7 @@ char filesys[NAMELEN]; static const char *stdin_opt = NULL; char *bot_script = NULL; dump_ino_t volinfo[TP_NINOS]; +int wdfd; #ifdef USE_QFA FILE *gTapeposfp; @@ -356,6 +357,10 @@ main(int argc, char *argv[]) else setinput(inputdev); + wdfd = open(".", O_RDONLY); + if (wdfd < 0) + err(1, "can't get current directory"); + if (argc == 0 && !filelist) { argc = 1; *--argv = "."; @@ -419,6 +424,7 @@ main(int argc, char *argv[]) Vprintf(stdout, "Begin compare restore\n"); compare_ignore_not_found = 0; compare_errors = 0; + Nflag = 1; setup(); printf("filesys = %s\n", filesys); if (STAT(filesys, &stbuf) < 0) @@ -427,9 +433,10 @@ main(int argc, char *argv[]) err(1, "cannot cd to %s", filesys); compare_ignore_not_found = dumptime > 0; initsymtable((char *)0); - extractdirs(0); + extractdirs(1); treescan(".", ROOTINO, nodeupdates); compareleaves(); + comparedirmodes(); checkrestore(); if (compare_errors) { printf("Some files were modified!\n"); diff --git a/restore/restore.8.in b/restore/restore.8.in index d7f934b..1d92342 100644 --- a/restore/restore.8.in +++ b/restore/restore.8.in @@ -25,7 +25,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.\" $Id: restore.8.in,v 1.31 2003/06/11 13:01:36 stelian Exp $ +.\" $Id: restore.8.in,v 1.32 2004/07/13 08:17:32 stelian Exp $ .\" .TH RESTORE 8 "version __VERSION__ of __DATE__" BSD "System management commands" .SH NAME @@ -102,9 +102,6 @@ restore \- restore files or file systems from backups made with dump [\fB\-T \fIdirectory\fR] [\fB\-X \fIfilelist\fR] [ \fIfile ... \fR] -.PP -(The 4.3BSD option syntax is implemented for backward compatibility but is not -documented here.) .SH DESCRIPTION The .B restore @@ -541,6 +538,9 @@ may be an ordinary file or .B \-y Do not ask the user whether to abort the restore in the event of an error. Always try to skip over the bad block(s) and continue. +.PP +(The 4.3BSD option syntax is implemented for backward compatibility but is not +documented here.) .SH DIAGNOSTICS Complains if it gets a read error. If .B y diff --git a/restore/restore.c b/restore/restore.c index b95e356..94e0bb6 100644 --- a/restore/restore.c +++ b/restore/restore.c @@ -37,7 +37,7 @@ #ifndef lint static const char rcsid[] = - "$Id: restore.c,v 1.33 2003/11/22 16:52:16 stelian Exp $"; + "$Id: restore.c,v 1.36 2005/03/18 22:12:55 stelian Exp $"; #endif /* not lint */ #include @@ -572,19 +572,24 @@ findunreflinks(void) { struct entry *ep, *np; dump_ino_t i; + int j; Vprintf(stdout, "Find unreferenced names.\n"); for (i = ROOTINO; i < maxino; i++) { ep = lookupino(i); if (ep == NULL || ep->e_type == LEAF || TSTINO(i, dumpmap) == 0) continue; - for (np = ep->e_entries; np != NULL; np = np->e_sibling) { - if (np->e_flags == 0) { - Dprintf(stdout, - "%s: remove unreferenced name\n", - myname(np)); - removeleaf(np); - freeentry(np); + if (ep->e_entries == NULL) + continue; + for (j = 0; j < DIRHASH_SIZE; j++) { + for (np = ep->e_entries[j]; np != NULL; np = np->e_sibling) { + if (np->e_flags == 0) { + Dprintf(stdout, + "%s: remove unreferenced name\n", + myname(np)); + removeleaf(np); + freeentry(np); + } } } } @@ -592,15 +597,19 @@ findunreflinks(void) * Any leaves remaining in removed directories is unreferenced. */ for (ep = removelist; ep != NULL; ep = ep->e_next) { - for (np = ep->e_entries; np != NULL; np = np->e_sibling) { - if (np->e_type == LEAF) { - if (np->e_flags != 0) - badentry(np, "unreferenced with flags"); - Dprintf(stdout, - "%s: remove unreferenced name\n", - myname(np)); - removeleaf(np); - freeentry(np); + if (ep->e_entries == NULL) + continue; + for (j = 0; j < DIRHASH_SIZE; j++) { + for (np = ep->e_entries[j]; np != NULL; np = np->e_sibling) { + if (np->e_type == LEAF) { + if (np->e_flags != 0) + badentry(np, "unreferenced with flags"); + Dprintf(stdout, + "%s: remove unreferenced name\n", + myname(np)); + removeleaf(np); + freeentry(np); + } } } } @@ -626,10 +635,19 @@ removeoldnodes(void) change = 0; prev = &removelist; for (ep = removelist; ep != NULL; ep = *prev) { + int docont = 0; if (ep->e_entries != NULL) { - prev = &ep->e_next; - continue; + int i; + for (i = 0; i < DIRHASH_SIZE; i++) { + if (ep->e_entries[i] != NULL) { + prev = &ep->e_next; + docont = 1; + break; + } + } } + if (docont) + continue; *prev = ep->e_next; removenode(ep); freeentry(ep); @@ -651,7 +669,10 @@ compare_entry(struct entry *ep, int do_compare) badentry(ep, "unexpected file on tape"); do_compare_error; } - if (do_compare) (void) comparefile(myname(ep)); + if (do_compare) { + (void) comparefile(myname(ep)); + skipxattr(); + } ep->e_flags &= ~(NEW|EXTRACT); } @@ -807,39 +828,9 @@ createleaves(char *symtabfile) else doremove = 0; (void) extractfile(ep, doremove); + skipxattr(); ep->e_flags &= ~(NEW|EXTRACT); -finderres: - if ((first == curfile.ino) && (spcl.c_flags & DR_EXTATTRIBUTES)) { - switch (spcl.c_extattributes) { - case EXT_MACOSFNDRINFO: -#ifdef DUMP_MACOSX - (void)extractfinderinfoufs(myname(ep)); -#else - msg("MacOSX not supported in this version, skipping\n"); - skipfile(); -#endif - break; - case EXT_MACOSRESFORK: -#ifdef DUMP_MACOSX - (void)extractresourceufs(myname(ep)); -#else - msg("MacOSX not supported in this version, skipping\n"); - skipfile(); -#endif - break; - case EXT_ACL: - msg("ACLs not supported in this version, skipping\n"); - skipfile(); - break; - default: - msg("unexpected inode extension %ld, skipping\n", spcl.c_extattributes); - skipfile(); - break; - } - goto finderres; - } - /* * We checkpoint the restore after every tape reel, so * as to simplify the amount of work required by the @@ -1070,37 +1061,7 @@ createfiles(void) } else { #endif /* USE_QFA */ (void) extractfile(ep, 0); - -finderres: - if ((next == curfile.ino) && (spcl.c_flags & DR_EXTATTRIBUTES)) { - switch (spcl.c_extattributes) { - case EXT_MACOSFNDRINFO: -#ifdef DUMP_MACOSX - (void)extractfinderinfoufs(myname(ep)); -#else - msg("MacOSX not supported in this version, skipping\n"); - skipfile(); -#endif - break; - case EXT_MACOSRESFORK: -#ifdef DUMP_MACOSX - (void)extractresourceufs(myname(ep)); -#else - msg("MacOSX not supported in this version, skipping\n"); - skipfile(); -#endif - break; - case EXT_ACL: - msg("ACLs not supported in this version, skipping\n"); - skipfile(); - break; - default: - msg("unexpected inode extension %ld, skipping\n", spcl.c_extattributes); - skipfile(); - break; - } - goto finderres; - } + skipxattr(); #ifdef USE_QFA } diff --git a/restore/restore.h b/restore/restore.h index bf6284b..4f5236f 100644 --- a/restore/restore.h +++ b/restore/restore.h @@ -5,7 +5,7 @@ * Stelian Pop , 1999-2000 * Stelian Pop - Alcôve , 2000-2002 * - * $Id: restore.h,v 1.29 2004/04/13 13:04:33 stelian Exp $ + * $Id: restore.h,v 1.32 2005/05/02 15:10:46 stelian Exp $ */ /* @@ -91,6 +91,9 @@ extern int compare_ignore_not_found; extern int compare_errors; /* did we encounter any compare errors? */ extern char filesys[NAMELEN];/* name of dumped filesystem */ extern dump_ino_t volinfo[]; /* which inode on which volume archive info */ +extern int wdfd; /* original working directory */ + +#define DIRHASH_SIZE 1024 /* * Each file in the file system is described by one of these entries @@ -105,7 +108,7 @@ struct entry { struct entry *e_parent; /* pointer to parent directory (..) */ struct entry *e_sibling; /* next element in this directory (.) */ struct entry *e_links; /* hard links to this inode */ - struct entry *e_entries; /* for directories, their entries */ + struct entry **e_entries; /* for directories, their entries */ struct entry *e_next; /* hash chain list */ }; /* types */ @@ -194,3 +197,4 @@ char smtcpath[2048]; exit(2); \ } +#define XATTR_MAXSIZE 4096 diff --git a/restore/symtab.c b/restore/symtab.c index 3e6d3fc..b69259a 100644 --- a/restore/symtab.c +++ b/restore/symtab.c @@ -37,7 +37,7 @@ #ifndef lint static const char rcsid[] = - "$Id: symtab.c,v 1.22 2003/10/26 16:05:48 stelian Exp $"; + "$Id: symtab.c,v 1.25 2005/03/30 13:34:00 stelian Exp $"; #endif /* not lint */ /* @@ -100,6 +100,25 @@ static long entrytblsize; static void addino __P((dump_ino_t, struct entry *)); static struct entry *lookupparent __P((char *)); static void removeentry __P((struct entry *)); +static int dir_hash __P((char *)); + +/* + * Returns a hash given a file name + */ +static int +dir_hash(char *name) +{ + unsigned long hash0 = 0x12a3fe2d, hash1 = 0x37abe8f9; + int len = strlen(name); + + while (len--) { + unsigned long hash = hash1 + (hash0 ^ (*name++ * 7152373)); + if (hash & 0x80000000) hash -= 0x7fffffff; + hash1 = hash0; + hash0 = hash; + } + return hash0 % DIRHASH_SIZE; +} /* * Look up an entry by inode number @@ -166,21 +185,51 @@ deleteino(dump_ino_t inum) struct entry * lookupname(char *name) { - struct entry *ep; + struct entry *ep, *oldep; char *np, *cp; char buf[MAXPATHLEN]; + ep = lookupino(ROOTINO); + cp = name; - for (ep = lookupino(ROOTINO); ep != NULL; ep = ep->e_entries) { + if (*cp == '.') + ++cp; + if (*cp == '/') + ++cp; + if (*cp == '\0') + return ep; + + while (ep != NULL) { for (np = buf; *cp != '/' && *cp != '\0' && np < &buf[sizeof(buf)]; ) *np++ = *cp++; if (np == &buf[sizeof(buf)]) break; *np = '\0'; - for ( ; ep != NULL; ep = ep->e_sibling) - if (strcmp(ep->e_name, buf) == 0) - break; + + oldep = ep; + + if (ep->e_entries != NULL) { + + ep = ep->e_entries[dir_hash(buf)]; + for ( ; ep != NULL; ep = ep->e_sibling) + if (strcmp(ep->e_name, buf) == 0) + break; + + /* search all hash lists for renamed inodes */ + if (ep == NULL) { + int j; + for (j = 0; j < DIRHASH_SIZE; j++) { + ep = oldep->e_entries[j]; + for ( ; ep != NULL; ep = ep->e_sibling) + if (strcmp(ep->e_name, buf) == 0) + break; + if (ep != NULL) + break; + } + } + } + if (ep == NULL) break; if (*cp++ == '\0') @@ -256,6 +305,11 @@ addentry(char *name, dump_ino_t inum, int type) errx(1, "no memory to extend symbol table"); } np->e_type = type & ~LINK; + if (type & NODE) { + np->e_entries = calloc(1, DIRHASH_SIZE * sizeof(struct entry *)); + if (np->e_entries == NULL) + panic("unable to allocate directory entries\n"); + } ep = lookupparent(name); if (ep == NULL) { if (inum != ROOTINO || lookupino(ROOTINO) != NULL) @@ -269,8 +323,8 @@ addentry(char *name, dump_ino_t inum, int type) np->e_name = savename(strrchr(name, '/') + 1); np->e_namlen = strlen(np->e_name); np->e_parent = ep; - np->e_sibling = ep->e_entries; - ep->e_entries = np; + np->e_sibling = ep->e_entries[dir_hash(np->e_name)]; + ep->e_entries[dir_hash(np->e_name)] = np; if (type & LINK) { ep = lookupino(inum); if (ep == NULL) @@ -300,8 +354,13 @@ freeentry(struct entry *ep) if (ep->e_type == NODE) { if (ep->e_links != NULL) badentry(ep, "freeing referenced directory"); - if (ep->e_entries != NULL) - badentry(ep, "freeing non-empty directory"); + if (ep->e_entries != NULL) { + int i; + for (i = 0; i < DIRHASH_SIZE; i++) { + if (ep->e_entries[i] != NULL) + badentry(ep, "freeing non-empty directory"); + } + } } if (ep->e_ino != 0) { np = lookupino(ep->e_ino); @@ -344,8 +403,8 @@ moveentry(struct entry *ep, char *newname) if (np != ep->e_parent) { removeentry(ep); ep->e_parent = np; - ep->e_sibling = np->e_entries; - np->e_entries = ep; + ep->e_sibling = np->e_entries[dir_hash(ep->e_name)]; + np->e_entries[dir_hash(ep->e_name)] = ep; } cp = strrchr(newname, '/') + 1; freename(ep->e_name); @@ -363,20 +422,40 @@ moveentry(struct entry *ep, char *newname) static void removeentry(struct entry *ep) { - struct entry *np; + struct entry *np = ep->e_parent; + struct entry *entry = np->e_entries[dir_hash(ep->e_name)]; - np = ep->e_parent; - if (np->e_entries == ep) { - np->e_entries = ep->e_sibling; + if (entry == ep) { + np->e_entries[dir_hash(ep->e_name)] = ep->e_sibling; } else { - for (np = np->e_entries; np != NULL; np = np->e_sibling) { + for (np = entry; np != NULL; np = np->e_sibling) { if (np->e_sibling == ep) { np->e_sibling = ep->e_sibling; break; } } - if (np == NULL) + if (np == NULL) { + + /* search all hash lists for renamed inodes */ + int j; + for (j = 0; j < DIRHASH_SIZE; j++) { + np = ep->e_parent; + entry = np->e_entries[j]; + if (entry == ep) { + np->e_entries[j] = ep->e_sibling; + return; + } + else { + for (np = entry; np != NULL; np = np->e_sibling) { + if (np->e_sibling == ep) { + np->e_sibling = ep->e_sibling; + return; + } + } + } + } badentry(ep, "cannot find entry in parent list"); + } } } @@ -449,6 +528,7 @@ freename(char *name) struct symtableheader { int32_t volno; int32_t stringsize; + int32_t hashsize; int32_t entrytblsize; time_t dumptime; time_t dumpdate; @@ -466,9 +546,10 @@ dumpsymtable(char *filename, long checkpt) struct entry *ep, *tep; dump_ino_t i; struct entry temp, *tentry; - long mynum = 1, stroff = 0; + long mynum = 1, stroff = 0, hashoff = 0; FILE *fd; struct symtableheader hdr; + struct entry *temphash[DIRHASH_SIZE]; Vprintf(stdout, "Check pointing the restore\n"); if (Nflag) @@ -490,11 +571,28 @@ dumpsymtable(char *filename, long checkpt) (int)allocsize(ep->e_namlen), fd); } } + /* + * Write out e_entries tables + */ + for (i = WINO; i <= maxino; i++) { + for (ep = lookupino(i); ep != NULL; ep = ep->e_links) { + if (ep->e_entries != NULL) { + int j; + memcpy(temphash, ep->e_entries, DIRHASH_SIZE * sizeof(struct entry *)); + for (j = 0; j < DIRHASH_SIZE; j++) { + if (temphash[j]) + temphash[j] = (struct entry *)ep->e_entries[j]->e_index; + } + fwrite(temphash, DIRHASH_SIZE, sizeof(struct entry *), fd); + } + } + } /* * Convert pointers to indexes, and output */ tep = &temp; stroff = 0; + hashoff = 0; for (i = WINO; i <= maxino; i++) { for (ep = lookupino(i); ep != NULL; ep = ep->e_links) { memmove(tep, ep, sizeof(struct entry)); @@ -507,9 +605,10 @@ dumpsymtable(char *filename, long checkpt) if (ep->e_sibling != NULL) tep->e_sibling = (struct entry *)ep->e_sibling->e_index; - if (ep->e_entries != NULL) - tep->e_entries = - (struct entry *)ep->e_entries->e_index; + if (ep->e_entries != NULL) { + tep->e_entries = (struct entry **)hashoff; + hashoff += DIRHASH_SIZE * sizeof(struct entry *); + } if (ep->e_next != NULL) tep->e_next = (struct entry *)ep->e_next->e_index; @@ -530,6 +629,7 @@ dumpsymtable(char *filename, long checkpt) hdr.maxino = maxino; hdr.entrytblsize = entrytblsize; hdr.stringsize = stroff; + hdr.hashsize = hashoff; hdr.dumptime = dumptime; hdr.dumpdate = dumpdate; hdr.ntrec = ntrec; @@ -612,12 +712,14 @@ initsymtable(char *filename) panic("initsymtable called from command %c\n", command); break; } - resizemaps(maxino, hdr.maxino); - maxino = hdr.maxino; + if (hdr.maxino > maxino) { + resizemaps(maxino, hdr.maxino); + maxino = hdr.maxino; + } entrytblsize = hdr.entrytblsize; entry = (struct entry **) (base + tblsize - (entrytblsize * sizeof(struct entry *))); - baseep = (struct entry *)(base + hdr.stringsize - sizeof(struct entry)); + baseep = (struct entry *)(base + hdr.stringsize + hdr.hashsize - sizeof(struct entry)); lep = (struct entry *)entry; for (i = 0; i < entrytblsize; i++) { if (entry[i] == NULL) @@ -631,8 +733,16 @@ initsymtable(char *filename) ep->e_sibling = &baseep[(long)ep->e_sibling]; if (ep->e_links != NULL) ep->e_links = &baseep[(long)ep->e_links]; - if (ep->e_entries != NULL) - ep->e_entries = &baseep[(long)ep->e_entries]; + if (ep->e_type == NODE) { + int i; + ep->e_entries = (struct entry **)(base + hdr.stringsize + (long)ep->e_entries); + for (i = 0; i < DIRHASH_SIZE; i++) { + if (ep->e_entries[i]) + ep->e_entries[i] = &baseep[(long)ep->e_entries[i]]; + } + } + else + ep->e_entries = NULL; if (ep->e_next != NULL) ep->e_next = &baseep[(long)ep->e_next]; } diff --git a/restore/tape.c b/restore/tape.c index 2f344db..e60921b 100644 --- a/restore/tape.c +++ b/restore/tape.c @@ -42,7 +42,7 @@ #ifndef lint static const char rcsid[] = - "$Id: tape.c,v 1.81 2004/05/25 10:39:31 stelian Exp $"; + "$Id: tape.c,v 1.89 2005/05/02 15:10:46 stelian Exp $"; #endif /* not lint */ #include @@ -167,7 +167,10 @@ static void xtrlnkskip __P((char *, size_t)); static void xtrmap __P((char *, size_t)); static void xtrmapskip __P((char *, size_t)); static void xtrskip __P((char *, size_t)); +static void xtrxattr __P((char *, size_t)); static void setmagtapein __P((void)); +static int extractattr __P((char *)); +static void compareattr __P((char *)); #if defined(HAVE_ZLIB) || defined(HAVE_BZLIB) || defined(HAVE_LZO) static void newcomprbuf __P((int)); @@ -194,6 +197,9 @@ static void xtrcmpskip __P((char *, size_t)); static int readmapflag; static int readingmaps; /* set to 1 while reading the maps */ +static char xattrbuf[XATTR_MAXSIZE]; +static int xattrlen; + #ifdef DUMP_MACOSX static DumpFinderInfo gFndrInfo; #endif @@ -840,14 +846,19 @@ extractfile(struct entry *ep, int doremove) return (GOOD); case IFDIR: + { + int ret; if (mflag) { if (ep == NULL || ep->e_flags & EXTRACT) panic("unextracted directory %s\n", name); skipfile(); return (GOOD); } - Vprintf(stdout, "extract file %s\n", name); - return (genliteraldir(name, curfile.ino)); + Vprintf(stdout, "extract dir %s\n", name); + ret = genliteraldir(name, curfile.ino); + extractattr(name); + return ret; + } case IFLNK: { @@ -873,6 +884,7 @@ extractfile(struct entry *ep, int doremove) #ifdef HAVE_LCHOWN (void) lchown(name, luid, lgid); #endif + extractattr(name); return (GOOD); } @@ -895,7 +907,7 @@ extractfile(struct entry *ep, int doremove) (void) chmod(name, mode); if (flags) #ifdef __linux__ - (void) fsetflags(name, flags); + (void) lsetflags(name, flags); #else #ifdef sunos { @@ -907,6 +919,7 @@ extractfile(struct entry *ep, int doremove) #endif #endif skipfile(); + extractattr(name); utimes(name, timep); return (GOOD); @@ -931,8 +944,8 @@ extractfile(struct entry *ep, int doremove) if (flags) #ifdef __linux__ { - warn("%s: fsetflags called on a special file", name); - (void) fsetflags(name, flags); + warn("%s: lsetflags called on a special file", name); + (void) lsetflags(name, flags); } #else #ifdef sunos @@ -948,6 +961,7 @@ extractfile(struct entry *ep, int doremove) #endif #endif skipfile(); + extractattr(name); utimes(name, timep); return (GOOD); @@ -979,7 +993,7 @@ extractfile(struct entry *ep, int doremove) (void) chmod(name, mode); if (flags) #ifdef __linux__ - (void) fsetflags(name, flags); + (void) lsetflags(name, flags); #else #ifdef sunos { @@ -990,6 +1004,7 @@ extractfile(struct entry *ep, int doremove) (void) chflags(name, flags); #endif #endif + extractattr(name); utimes(name, timep); return (GOOD); } @@ -997,6 +1012,44 @@ extractfile(struct entry *ep, int doremove) /* NOTREACHED */ } +static int +extractattr(char *path) +{ + while (spcl.c_flags & DR_EXTATTRIBUTES) { + switch (spcl.c_extattributes) { + case EXT_MACOSFNDRINFO: +#ifdef DUMP_MACOSX + (void)extractfinderinfoufs(path); +#else + msg("MacOSX not supported in this version, skipping\n"); + skipfile(); +#endif + break; + case EXT_MACOSRESFORK: +#ifdef DUMP_MACOSX + (void)extractresourceufs(path); +#else + msg("MacOSX not supported in this version, skipping\n"); + skipfile(); +#endif + break; + case EXT_XATTR: { + char xattr[XATTR_MAXSIZE]; + + if (readxattr(xattr) == GOOD) { + xattr_extract(path, xattr); + break; + } + } + default: + msg("unexpected inode extension %ld, skipping\n", spcl.c_extattributes); + skipfile(); + break; + } + } + return GOOD; +} + #ifdef DUMP_MACOSX int extractfinderinfoufs(char *name) @@ -1009,7 +1062,6 @@ extractfinderinfoufs(char *name) u_int32_t uid; u_int32_t gid; char path[MAXPATHLEN], fname[MAXPATHLEN]; - int toto; curfile.name = name; curfile.action = USING; @@ -1161,7 +1213,7 @@ extractresourceufs(char *name) (void) fchown(ofile, uid, gid); (void) fchmod(ofile, mode); (void) close(ofile); - (void) fsetflags(oFileRsrc, flags); + (void) lsetflags(oFileRsrc, flags); utimes(oFileRsrc, timep); return (GOOD); } @@ -1169,6 +1221,29 @@ extractresourceufs(char *name) } #endif /* DUMP_MACOSX */ +int +readxattr(char *buffer) +{ + if (dflag) + msg("reading EA data for inode %lu\n", curfile.ino); + + curfile.name = "EA block"; + if (curfile.dip->di_size > XATTR_MAXSIZE) { + fprintf(stderr, "EA size too big (%ld)", (long)curfile.dip->di_size); + skipfile(); + return (FAIL); + } + + memset(xattrbuf, 0, XATTR_MAXSIZE); + xattrlen = 0; + + getfile(xtrxattr, xtrnull); + + memcpy(buffer, xattrbuf, XATTR_MAXSIZE); + + return (GOOD); +} + /* * skip over bit maps on the tape */ @@ -1191,6 +1266,17 @@ skipfile(void) getfile(xtrnull, xtrnull); } +/* + * skip over any extended attributes. + */ +void +skipxattr(void) +{ + + while (spcl.c_flags & DR_EXTATTRIBUTES) + skipfile(); +} + /* * Extract a file from the tape. * When an allocated block is found it is passed to the fill function; @@ -1290,8 +1376,6 @@ xtrfile(char *buf, size_t size) static void xtrfilefinderinfo(char *buf, size_t size) { - if (Nflag) - return; bcopy(buf, &gFndrInfo, size); } #endif /* DUMP_MACOSX */ @@ -1317,10 +1401,13 @@ xtrlnkfile(char *buf, size_t size) { pathlen += size; - if (pathlen > MAXPATHLEN) + if (pathlen > MAXPATHLEN) { + buf[size - 1] = '\0'; errx(1, "symbolic link name: %s->%s%s; too long %d", curfile.name, lnkbuf, buf, pathlen); + } (void) strcat(lnkbuf, buf); + lnkbuf[pathlen] = '\0'; } /* @@ -1424,9 +1511,20 @@ xtrcmpskip(UNUSED(char *buf), size_t size) } #endif /* COMPARE_ONTHEFLY */ +static void +xtrxattr(char *buf, size_t size) +{ + if (xattrlen + size > XATTR_MAXSIZE) { + fprintf(stderr, "EA size too big (%ld)", (long)xattrlen + size); + return; + } + memcpy(xattrbuf + xattrlen, buf, size); + xattrlen += size; +} + #if !COMPARE_ONTHEFLY static int -do_cmpfiles(int fd_tape, int fd_disk, long size) +do_cmpfiles(int fd_tape, int fd_disk, OFF_T size) { static char buf_tape[BUFSIZ]; static char buf_disk[BUFSIZ]; @@ -1468,15 +1566,15 @@ cmpfiles(char *tapefile, char *diskfile, struct STAT *sbuf_disk) int fd_tape, fd_disk; if (STAT(tapefile, &sbuf_tape) != 0) { - panic("Can't lstat tmp file %s: %s\n", tapefile, + panic("can't lstat tmp file %s: %s\n", tapefile, strerror(errno)); do_compare_error; } if (sbuf_disk->st_size != sbuf_tape.st_size) { fprintf(stderr, - "%s: size changed from %ld to %ld.\n", - diskfile, (long)sbuf_tape.st_size, (long)sbuf_disk->st_size); + "%s: size changed from %lld to %lld.\n", + diskfile, (long long)sbuf_tape.st_size, (long long)sbuf_disk->st_size); do_compare_error; #ifdef COMPARE_FAIL_KEEP_FILE return (0); @@ -1486,12 +1584,12 @@ cmpfiles(char *tapefile, char *diskfile, struct STAT *sbuf_disk) } if ((fd_tape = OPEN(tapefile, O_RDONLY)) < 0) { - panic("Can't open %s: %s\n", tapefile, strerror(errno)); + panic("can't open %s: %s\n", tapefile, strerror(errno)); do_compare_error; } if ((fd_disk = OPEN(diskfile, O_RDONLY)) < 0) { close(fd_tape); - panic("Can't open %s: %s\n", diskfile, strerror(errno)); + panic("can't open %s: %s\n", diskfile, strerror(errno)); do_compare_error; } @@ -1536,6 +1634,43 @@ cmpfiles(char *tapefile, char *diskfile, struct STAT *sbuf_disk) } #endif /* !COMPARE_ONTHEFLY */ +static void +compareattr(char *name) +{ + int xattr_done = 0; + + while (spcl.c_flags & DR_EXTATTRIBUTES) { + switch (spcl.c_extattributes) { + case EXT_MACOSFNDRINFO: + msg("MacOSX not supported for comparision in this version, skipping\n"); + skipfile(); + break; + case EXT_MACOSRESFORK: + msg("MacOSX not supported for comparision in this version, skipping\n"); + skipfile(); + break; + case EXT_XATTR: { + char xattr[XATTR_MAXSIZE]; + + if (readxattr(xattr) == GOOD) { + if (xattr_compare(name, xattr) == FAIL) + do_compare_error; + xattr_done = 1; + } + else + do_compare_error; + break; + } + default: + msg("unexpected inode extension %ld, skipping\n", spcl.c_extattributes); + skipfile(); + break; + } + } + if (!xattr_done && xattr_compare(name, NULL) == FAIL) + do_compare_error; +} + #if !COMPARE_ONTHEFLY static char tmpfilename[MAXPATHLEN]; #endif @@ -1543,17 +1678,23 @@ static char tmpfilename[MAXPATHLEN]; void comparefile(char *name) { - unsigned int mode; + mode_t mode; + uid_t uid; + uid_t gid; + unsigned int flags; + unsigned long newflags; struct STAT sb; int r; #if !COMPARE_ONTHEFLY static char *tmpfile = NULL; struct STAT stemp; #endif - curfile.name = name; curfile.action = USING; mode = curfile.dip->di_mode; + flags = curfile.dip->di_flags; + uid = curfile.dip->di_uid; + gid = curfile.dip->di_gid; if ((mode & IFMT) == IFSOCK) { Vprintf(stdout, "skipped socket %s\n", name); @@ -1562,20 +1703,45 @@ comparefile(char *name) } if ((r = LSTAT(name, &sb)) != 0) { - warn("%s: does not exist (%d)", name, r); + warn("unable to stat %s", name); do_compare_error; skipfile(); return; } - Vprintf(stdout, "comparing %s (size: %ld, mode: 0%o)\n", name, - (long)sb.st_size, mode); + Vprintf(stdout, "comparing %s (size: %lld, mode: 0%o)\n", name, + (long long)sb.st_size, mode); if (sb.st_mode != mode) { fprintf(stderr, "%s: mode changed from 0%o to 0%o.\n", name, mode & 07777, sb.st_mode & 07777); do_compare_error; } + if (sb.st_uid != uid) { + fprintf(stderr, "%s: uid changed from %d to %d.\n", + name, uid, sb.st_uid); + do_compare_error; + } + if (sb.st_gid != gid) { + fprintf(stderr, "%s: gid changed from %d to %d.\n", + name, gid, sb.st_gid); + do_compare_error; + } +#ifdef __linux__ + if (lgetflags(name, &newflags) < 0) { + if (flags != 0) { + warn("%s: lgetflags failed", name); + do_compare_error; + } + } + else { + if (newflags != flags) { + fprintf(stderr, "%s: flags changed from 0x%08x to 0x%08lx.\n", + name, flags, newflags); + do_compare_error; + } + } +#endif if (spcl.c_flags & DR_METAONLY) { skipfile(); return; @@ -1591,6 +1757,7 @@ comparefile(char *name) case IFDIR: skipfile(); + compareattr(name); return; case IFLNK: { @@ -1614,7 +1781,7 @@ comparefile(char *name) return; } if ((lsize = readlink(name, lbuf, MAXPATHLEN)) < 0) { - panic("readlink of %s failed: %s", name, + panic("readlink of %s failed: %s\n", name, strerror(errno)); do_compare_error; } @@ -1626,6 +1793,7 @@ comparefile(char *name) do_compare_error; return; } + compareattr(name); return; } @@ -1650,12 +1818,13 @@ comparefile(char *name) do_compare_error; } skipfile(); + compareattr(name); return; case IFREG: #if COMPARE_ONTHEFLY if ((ifile = OPEN(name, O_RDONLY)) < 0) { - panic("Can't open %s: %s\n", name, strerror(errno)); + warn("can't open %s", name); skipfile(); do_compare_error; } @@ -1698,6 +1867,7 @@ comparefile(char *name) unlink(tmpfile); #endif #endif /* COMPARE_ONTHEFLY */ + compareattr(name); return; } /* NOTREACHED */ diff --git a/restore/utilities.c b/restore/utilities.c index e0db9af..f17bd9c 100644 --- a/restore/utilities.c +++ b/restore/utilities.c @@ -37,7 +37,7 @@ #ifndef lint static const char rcsid[] = - "$Id: utilities.c,v 1.24 2003/11/22 16:52:16 stelian Exp $"; + "$Id: utilities.c,v 1.28 2005/03/30 13:21:45 stelian Exp $"; #endif /* not lint */ #include @@ -187,8 +187,13 @@ removenode(struct entry *ep) if (ep->e_type != NODE) badentry(ep, "removenode: not a node"); - if (ep->e_entries != NULL) - badentry(ep, "removenode: non-empty directory"); + if (ep->e_entries != NULL) { + int i; + for (i = 0; i < DIRHASH_SIZE; i++) { + if (ep->e_entries[i] != NULL) + badentry(ep, "removenode: non-empty directory"); + } + } ep->e_flags |= REMOVED; ep->e_flags &= ~TMPNAME; cp = myname(ep); @@ -264,10 +269,10 @@ linkit(char *existing, char *new, int type) */ #ifdef sunos #else - if (fgetflags (existing, &s) != -1 && - fsetflags (existing, 0) != -1) { + if (lgetflags (existing, &s) != -1 && + lsetflags (existing, 0) != -1) { ret = link(existing, new); - fsetflags(existing, s); + lsetflags(existing, s); } #endif #endif @@ -371,8 +376,15 @@ badentry(struct entry *ep, const char *msg) fprintf(stderr, "parent name %s\n", myname(ep->e_parent)); if (ep->e_sibling != NULL) fprintf(stderr, "sibling name: %s\n", myname(ep->e_sibling)); - if (ep->e_entries != NULL) - fprintf(stderr, "next entry name: %s\n", myname(ep->e_entries)); + if (ep->e_entries != NULL) { + int i; + for (i = 0; i < DIRHASH_SIZE; i++) { + if (ep->e_entries[i] != NULL) { + fprintf(stderr, "next entry name: %s\n", myname(ep->e_entries[i])); + break; + } + } + } if (ep->e_links != NULL) fprintf(stderr, "next link name: %s\n", myname(ep->e_links)); if (ep->e_next != NULL) @@ -475,8 +487,10 @@ panic(fmt, va_alist) if (yflag) return; if (reply("abort") == GOOD) { - if (reply("dump core") == GOOD) + if (reply("dump core") == GOOD) { + fchdir(wdfd); abort(); + } exit(1); } } @@ -712,9 +726,46 @@ CreateAppleDoubleFileRes(char *oFile, FndrFileInfo *finderinfo, mode_t mode, int (void)fchown(fdout, uid, gid); (void)fchmod(fdout, mode); close(fdout); - (void)fsetflags(oFile, flags); + (void)lsetflags(oFile, flags); utimes(oFile, timep); free(pp); return err; } #endif /* DUMP_MACOSX */ + +int +lgetflags(const char *path, unsigned long *flags) +{ + int err; + struct STAT sb; + + err = LSTAT(path, &sb); + if (err < 0) + return err; + + if (S_ISLNK(sb.st_mode) || S_ISFIFO(sb.st_mode)) { + // no way to get/set flags on a symlink + *flags = 0; + return 0; + } + else + return fgetflags(path, flags); +} + +int +lsetflags(const char *path, unsigned long flags) +{ + int err; + struct STAT sb; + + err = LSTAT(path, &sb); + if (err < 0) + return err; + + if (S_ISLNK(sb.st_mode) || S_ISFIFO(sb.st_mode)) { + // no way to get/set flags on a symlink + return 0; + } + else + return fsetflags(path, flags); +} diff --git a/restore/xattr.c b/restore/xattr.c new file mode 100644 index 0000000..6da39eb --- /dev/null +++ b/restore/xattr.c @@ -0,0 +1,444 @@ +/* + * Copyright (c) 1999-2004 + * Stelian Pop , 1999-2004 + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static const char rcsid[] = + "$Id: xattr.c,v 1.1 2005/05/02 15:10:47 stelian Exp $"; +#endif /* not lint */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "restore.h" +#include "extern.h" +#include "pathnames.h" + +/* + * Data structures below taken from the kernel + */ + +/* Maximum number of references to one attribute block */ +#define EXT2_XATTR_REFCOUNT_MAX 1024 + +/* Name indexes */ +#define EXT2_XATTR_INDEX_MAX 10 +#define EXT2_XATTR_INDEX_USER 1 +#define EXT2_XATTR_INDEX_POSIX_ACL_ACCESS 2 +#define EXT2_XATTR_INDEX_POSIX_ACL_DEFAULT 3 +#define EXT2_XATTR_INDEX_TRUSTED 4 +#define EXT2_XATTR_INDEX_LUSTRE 5 +#define EXT2_XATTR_INDEX_SECURITY 6 + +struct ext2_xattr_header { + u_int32_t h_magic; /* magic number for identification */ + u_int32_t h_refcount; /* reference count */ + u_int32_t h_blocks; /* number of disk blocks used */ + u_int32_t h_hash; /* hash value of all attributes */ + u_int32_t h_reserved[4]; /* zero right now */ +}; + +struct ext3_xattr_ibody_header { + u_int32_t h_magic; /* magic number for identification */ +}; + +struct ext2_xattr_entry { + u_char e_name_len; /* length of name */ + u_char e_name_index; /* attribute name index */ + u_int16_t e_value_offs; /* offset in disk block of value */ + u_int32_t e_value_block; /* disk block attribute is stored on (n/i) */ + u_int32_t e_value_size; /* size of attribute value */ + u_int32_t e_hash; /* hash value of name and value */ + char e_name[0]; /* attribute name */ +}; + +#define EXT2_XATTR_PAD_BITS 2 +#define EXT2_XATTR_PAD (1<e_name_len)) ) +#define EXT3_XATTR_SIZE(size) \ + (((size) + EXT2_XATTR_ROUND) & ~EXT2_XATTR_ROUND) + +#define HDR(buffer) ((struct ext2_xattr_header *)(buffer)) +#define ENTRY(ptr) ((struct ext2_xattr_entry *)(ptr)) +#define IS_LAST_ENTRY(entry) (*(__u32 *)(entry) == 0) + +#define BFIRST(buffer) ENTRY(HDR(buffer)+1) +#define IFIRST(buffer) ENTRY(((struct ext3_xattr_ibody_header *)(buffer))+1) + +#define FIRST_ENTRY(buffer) \ + ((HDR(buffer)->h_magic == EXT2_XATTR_MAGIC2) ? \ + IFIRST(buffer) : \ + BFIRST(buffer)) + +/* + * On-block xattr value offsets start at the beginning of the block, but + * on-inode xattr value offsets start after the initial header + * (ext3_xattr_ibody_header). + */ +#define VALUE_OFFSET(buffer, entry) \ + (((HDR(buffer)->h_magic == EXT2_XATTR_MAGIC2) ? \ + (entry)->e_value_offs + sizeof(struct ext3_xattr_ibody_header) : \ + (entry)->e_value_offs)) + +/* + * xattr syscalls do not exist yet in libc, get our own copy here, + * taken from libattr. + */ +#if defined (__i386__) +# define HAVE_XATTR_SYSCALLS 1 +# define __NR_lsetxattr 227 +# define __NR_lgetxattr 230 +# define __NR_llistxattr 233 +#elif defined (__sparc__) +# define HAVE_XATTR_SYSCALLS 1 +# define __NR_lsetxattr 170 +# define __NR_lgetxattr 173 +# define __NR_llistxattr 179 +#elif defined (__ia64__) +# define HAVE_XATTR_SYSCALLS 1 +# define __NR_lsetxattr 1218 +# define __NR_lgetxattr 1221 +# define __NR_llistxattr 1224 +#elif defined (__powerpc__) +# define HAVE_XATTR_SYSCALLS 1 +# define __NR_lsetxattr 210 +# define __NR_lgetxattr 213 +# define __NR_llistxattr 216 +#elif defined (__x86_64__) +# define HAVE_XATTR_SYSCALLS 1 +# define __NR_lsetxattr 189 +# define __NR_lgetxattr 192 +# define __NR_llistxattr 195 +#elif defined (__s390__) +# define HAVE_XATTR_SYSCALLS 1 +# define __NR_lsetxattr 225 +# define __NR_lgetxattr 228 +# define __NR_llistxattr 231 +#elif defined (__arm__) +# define HAVE_XATTR_SYSCALLS 1 +# define __NR_SYSCALL_BASE 0x900000 +# define __NR_lsetxattr (__NR_SYSCALL_BASE+227) +# define __NR_lgetxattr (__NR_SYSCALL_BASE+230) +# define __NR_llistxattr (__NR_SYSCALL_BASE+233) +#elif defined (__mips64__) +# define HAVE_XATTR_SYSCALLS 1 +# define __NR_Linux 5000 +# define __NR_lsetxattr (__NR_Linux + 218) +# define __NR_lgetxattr (__NR_Linux + 221) +# define __NR_llistxattr (__NR_Linux + 224) +#elif defined (__mips__) +# define HAVE_XATTR_SYSCALLS 1 +# define __NR_Linux 4000 +# define __NR_lsetxattr (__NR_Linux + 225) +# define __NR_lgetxattr (__NR_Linux + 228) +# define __NR_llistxattr (__NR_Linux + 231) +#elif defined (__alpha__) +# define HAVE_XATTR_SYSCALLS 1 +# define __NR_lsetxattr 383 +# define __NR_lgetxattr 386 +# define __NR_llistxattr 389 +#elif defined (__mc68000__) +# define HAVE_XATTR_SYSCALLS 1 +# define __NR_lsetxattr 224 +# define __NR_lgetxattr 227 +# define __NR_llistxattr 230 +#else +# warning "Extended attribute syscalls undefined for this architecture" +# define HAVE_XATTR_SYSCALLS 0 +#endif + +#if HAVE_XATTR_SYSCALLS +# define SYSCALL(args...) syscall(args) +#else +# define SYSCALL(args...) ( errno = ENOSYS, -1 ) +#endif + +static int lsetxattr __P((const char *, const char *, void *, size_t, int)); +static ssize_t lgetxattr __P((const char *, const char *, void *, size_t)); +static ssize_t llistxattr __P((const char *, char *, size_t)); +static int xattr_cb_list __P((char *, char *, int, void *)); +static int xattr_cb_set __P((char *, char *, int, void *)); +static int xattr_cb_compare __P((char *, char *, int, void *)); +static int xattr_verify __P((char *)); +static int xattr_count __P((char *, int *)); +static int xattr_walk __P((char *, int (*)(char *, char *, int, void *), void *)); + +static int +lsetxattr(const char *path, const char *name, void *value, size_t size, int flags) +{ + return SYSCALL(__NR_lsetxattr, path, name, value, size, flags); +} + +static ssize_t +lgetxattr(const char *path, const char *name, void *value, size_t size) +{ + return SYSCALL(__NR_lgetxattr, path, name, value, size); +} + +static ssize_t +llistxattr(const char *path, char *list, size_t size) +{ + return SYSCALL(__NR_llistxattr, path, list, size); +} + +/* + * Dump code starts here :) + */ + +static int +xattr_cb_list(char *name, char *value, int valuelen, void *private) +{ + value[valuelen] = '\0'; + printf("EA: %s:%s\n", name, value); + + return GOOD; +} + +static int +xattr_cb_set(char *name, char *value, int valuelen, void *private) +{ + char *path = (char *)private; + + if (lsetxattr(path, name, value, valuelen, 0) < 0) { + warn("lsetxattr %s failed", path); + return FAIL; + } + return GOOD; +} + +static int +xattr_cb_compare(char *name, char *value, int valuelen, void *private) +{ + char *path = (char *)private; + char valuef[XATTR_MAXSIZE]; + int valuesz; + + valuesz = lgetxattr(path, name, valuef, XATTR_MAXSIZE); + if (valuesz < 0) { + warn("%s: lgetxattr failed\n", path); + return FAIL; + } + + if (valuesz != valuelen) { + fprintf(stderr, "%s: EA %s value changed\n", path, value); + return FAIL; + } + + if (memcmp(value, valuef, valuelen)) { + fprintf(stderr, "%s: EA %s value changed\n", path, value); + return FAIL; + } + + return GOOD; +} + +static int +xattr_verify(char *buffer) +{ + struct ext2_xattr_entry *entry; + char *end; + + end = buffer + XATTR_MAXSIZE; + + if (Bcvt) + swabst("4i", (u_char *)buffer); + + if (HDR(buffer)->h_magic != EXT2_XATTR_MAGIC && + HDR(buffer)->h_magic != EXT2_XATTR_MAGIC2) { + fprintf(stderr, "error in EA block 1\n"); + fprintf(stderr, "magic = %x\n", HDR(buffer)->h_magic); + + return FAIL; + } + + /* check the on-disk data structure */ + entry = FIRST_ENTRY(buffer); + if (Bcvt) + swabst("2b1s3i", (u_char *)entry); + while (!IS_LAST_ENTRY(entry)) { + struct ext2_xattr_entry *next = EXT2_XATTR_NEXT(entry); + + if ((char *)next >= end) { + fprintf(stderr, "error in EA block\n"); + return FAIL; + } + entry = next; + if (Bcvt) + swabst("2b1s3i", (u_char *)entry); + } + return GOOD; +} + +static int +xattr_count(char *buffer, int *count) +{ + struct ext2_xattr_entry *entry; + int result = 0; + + /* list the attribute names */ + for (entry = FIRST_ENTRY(buffer); !IS_LAST_ENTRY(entry); + entry = EXT2_XATTR_NEXT(entry)) + result++; + + *count = result; + return GOOD; +} + +static int +xattr_walk(char *buffer, int (*xattr_cb)(char *, char *, int, void *), void *private) +{ + struct ext2_xattr_entry *entry; + + /* list the attribute names */ + for (entry = FIRST_ENTRY(buffer); !IS_LAST_ENTRY(entry); + entry = EXT2_XATTR_NEXT(entry)) { + char name[XATTR_MAXSIZE], value[XATTR_MAXSIZE]; + int off; + + switch (entry->e_name_index) { + case EXT2_XATTR_INDEX_USER: + strcpy(name, "user."); + break; + case EXT2_XATTR_INDEX_POSIX_ACL_ACCESS: + case EXT2_XATTR_INDEX_POSIX_ACL_DEFAULT: + strcpy(name, "system."); + break; + case EXT2_XATTR_INDEX_TRUSTED: + strcpy(name, "trusted."); + break; + case EXT2_XATTR_INDEX_LUSTRE: + strcpy(name, "lustre."); + break; + case EXT2_XATTR_INDEX_SECURITY: + strcpy(name, "security."); + break; + default: + fprintf(stderr, "Unknown EA index\n"); + return FAIL; + } + + off = strlen(name); + memcpy(name + off, entry->e_name, entry->e_name_len); + name[off + entry->e_name_len] = '\0'; + + + memcpy(value, buffer + VALUE_OFFSET(buffer, entry), entry->e_value_size); + + if (xattr_cb(name, value, entry->e_value_size, private) != GOOD) + return FAIL; + } + + return GOOD; +} + +int +xattr_compare(char *path, char *buffer) +{ + int countf, countt; + char *names = NULL, *end_names, *name; + + countf = llistxattr(path, NULL, 0); + if (countf < 0) { + warn("%s: llistxattr failed", path); + return FAIL; + } + + names = malloc(countf + 1); + if (!names) { + warn("%s: llistxattr failed", path); + return FAIL; + } + + countf = llistxattr(path, names, countf); + if (countf < 0) { + warn("%s: llistxattr failed", path); + free(names); + return FAIL; + } + + names[countf] = '\0'; + end_names = names + countf; + + countf = 0; + for (name = names; name != end_names; name = strchr(name, '\0') + 1) { + if (!*name) + continue; + countf++; + } + + free(names); + + if (buffer) { + if (xattr_verify(buffer) == FAIL) + return FAIL; + + if (xattr_count(buffer, &countt) == FAIL) + return FAIL; + } + else + countt = 0; + + if (countf != countt) { + fprintf(stderr, "%s: EA count changed from %d to %d\n", path, countt, countf); + return FAIL; + } + + if (!buffer) + return GOOD; + + return xattr_walk(buffer, xattr_cb_compare, path); +} + +int +xattr_extract(char *path, char *buffer) +{ + if (dflag) { + fprintf(stderr, "xattr_extract(%s)\n", path); + xattr_walk(buffer, xattr_cb_list, NULL); + } + + if (xattr_verify(buffer) == FAIL) + return FAIL; + + return xattr_walk(buffer, xattr_cb_set, path); +} + -- 2.47.2