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.30.2