Imported Upstream version 0.4b40 upstream/0.4b40
authorBdale Garbee <bdale@gag.com>
Tue, 20 May 2008 05:04:26 +0000 (23:04 -0600)
committerBdale Garbee <bdale@gag.com>
Tue, 20 May 2008 05:04:26 +0000 (23:04 -0600)
27 files changed:
CHANGES
MCONFIG.in
THANKS
TODO
compat/include/bsdcompat.h
compat/include/protocols/dumprestore.h
config.h.in
configure
configure.in
dump.lsm
dump.spec
dump/dump.8.in
dump/tape.c
dump/traverse.c
examples/dump_on_cd_3/README [new file with mode: 0644]
examples/dump_on_cd_3/dump_disk [new file with mode: 0755]
restore/Makefile.in
restore/dirs.c
restore/extern.h
restore/main.c
restore/restore.8.in
restore/restore.c
restore/restore.h
restore/symtab.c
restore/tape.c
restore/utilities.c
restore/xattr.c [new file with mode: 0644]

diff --git a/CHANGES b/CHANGES
index 501bc1655f6f0feed9edcbc5530abea2183395e4..c4d497d8bb13ad4c762245c447916006cd71935e 100644 (file)
--- 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
+       <shiva@sewingwitch.com> 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 <shiva@sewingwitch.com> 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 <goisman@physics.arizona.edu> 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
+       <bob@cemetery.homeunix.org>.
+
+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 <shiva@sewingwitch.com> 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
+       <shiva@sewingwitch.com> 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 <esr@thyrsus.com> 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
+       <sbonds@users.sourceforge.net> 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 <K.B.Haines@rl.ac.uk> 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 <kyle.wilson@amd.com> 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 <bristuccia@starentnetworks.com>
+       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)
 ==================================================================
index e20399ee3e3061e1ca7fec1d63e2d3ee102ee3eb..8bce8b0cec0f6d9687c43c6326472dfe5de77f21 100644 (file)
@@ -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 3e2854cf7845c16b29a100d0a024e25eb67b7036..cb7596d4555a7bcf5acb4be2571272ed5649b6a1 100644 (file)
--- 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 d3d4102b842328f813ba7ae85fddfff29b79153b..349b1d15e0c9421445f06b84ca98d80804334d4f 100644 (file)
--- 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 
-       <mjt@tls.msk.ru>.
-
-7.     Better readline completition in restore (escape spaces etc).
+6.     Better readline completition in restore (escape spaces etc).
index 4b9b9077ac6edacbf38a9e27e2f793a5122a9b52..7bc216038c96b34f9b0804e140a0cbe1699e4e72 100644 (file)
@@ -5,7 +5,7 @@
  *     Stelian Pop <stelian@popies.net>, 1999-2000
  *     Stelian Pop <stelian@popies.net> - Alcôve <www.alcove.com>, 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 <config.h>
@@ -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]
index fc437159619b7ef60349b0a8be15e3d80ebb5a97..816a83f508a33e336ba30b9c74f92876a658b1dd 100644 (file)
@@ -5,7 +5,7 @@
  *     Stelian Pop <stelian@popies.net>, 1999-2000
  *     Stelian Pop <stelian@popies.net> - Alcôve <www.alcove.com>, 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_ */
index 799b2f0ddf4c9cb9c4b4dab4ed25d32b9b2bf294..828ef11b7b5fbfcb871e297ac6360f0208cab18b 100644 (file)
 /* Define to 1 if you have the <ext2fs/ext2_fs.h> 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
 
index 0fb7c6dce80fb9c667595a3dc902fdffdd48eb15..290a7fd2a9ffb49018978a3552e6db79bd28df31 100755 (executable)
--- a/configure
+++ b/configure
@@ -309,7 +309,7 @@ ac_includes_default="\
 # include <unistd.h>
 #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
index bcafc467e8b911da99478bd52c5a7cd2042ca0da..3788737049e9edfe9a492949e03fc264e5f6f2d8 100644 (file)
@@ -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
index 73f53f7adf6eccbc4837e3ddf607dd6f2b783904..043c2e2fd9b5283904c14d99fe7778ab741bd43b 100644 (file)
--- 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/*
index ae0c08e17aab04420f0d9fceb559dedff6ef6260..6d9019384f91ca59aa208bc8fec96b74bccfb587 100644 (file)
--- 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 <stelian@popies.net>
+- dump 0.4b39 released, first packaging.
+
+* Fri Jan  7 2005 Stelian Pop <stelian@popies.net>
+- dump 0.4b38 released, first packaging.
+
 * Wed Jul  7 2004 Stelian Pop <stelian@popies.net>
 - dump 0.4b37 released, first packaging.
 
index 487302d89272b94faadce9e3e18bd003f1103b69..a6bf3f0805ac5ba1e84ca5b56511dee660ade92a 100644 (file)
@@ -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
index 2df4d1e242772338f88bce5b9cf6bbd5e4b48cc7..89f630d278ea3484c4ac8aa8054575a81bcdc7a6 100644 (file)
@@ -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 <config.h>
@@ -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
index 41047999c7d921c07237655e50db09f3840136b3..64c32a5b75fc253e0ef4864c58f9c9c1b3fe81e3 100644 (file)
@@ -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 <config.h>
@@ -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 (file)
index 0000000..c632be6
--- /dev/null
@@ -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 (executable)
index 0000000..3e9200d
--- /dev/null
@@ -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  </dev/tty ANSWER
+               if [ "$ANSWER" == "y" ] ; then
+                       (${RECORD_BIN}${1}) &
+                       return 0
+               elif [ "$ANSWER" == "n" ] ; then
+                       EXIT=""
+                       echo -n "Do you really want to exit? (y/n) "
+                       read </dev/tty EXIT
+                       if [ "$EXIT" == "y" ] ; then
+                               return 1
+                       fi
+               fi
+       done
+}
+
+if [ "$#" = "0" ] || [ "$1" = "-h" ] || [ "$1" = "--help" ]; then
+       echo >&2 "Usage: $0 <dump options>"
+       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
index cdc2004cf1076daf784e0e939990ac04781cdacb..79e03ea609065b0e1a458734e3565386d05be94f 100644 (file)
@@ -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
 
index 2a23f9486b62c940530954b69b1bdf346ff3b8f7..b049f49007801c6caa8c70d755b38ecce9dbc860 100644 (file)
@@ -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 <config.h>
@@ -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 = "<directory file - name unknown>";
                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);
 }
 
 /*
index e2702ed6587de0b58d6adbe985884c76d8a8691b..16e2440e380e9b7d5fa915e183c05433ef8b1d53 100644 (file)
@@ -5,7 +5,7 @@
  *     Stelian Pop <stelian@popies.net>, 1999-2000
  *     Stelian Pop <stelian@popies.net> - Alcôve <www.alcove.com>, 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 *));
index f53d740513c1718b9c156bde174737c15e1edc7a..dfbe8c6ce557ca18d282e67c290b0f8f0ad911ef 100644 (file)
@@ -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 <config.h>
@@ -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");
index d7f934b34e836374e7a2f9c180e839fc01bb8b19..1d9234220e6415a807626bb04c6b719dcefa8e5d 100644 (file)
@@ -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
index b95e3569cd8b79e07c21ecc8c2f13c73fb5c8458..94e0bb6cc8f853c5a4243aeaf0c2dcf738568a2c 100644 (file)
@@ -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 <config.h>
@@ -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
                        }
index bf6284b126c986950fc50c75284b94fafad0ec6e..4f5236f4ac7466c17bbe8bf3c01a4c959db5e6df 100644 (file)
@@ -5,7 +5,7 @@
  *     Stelian Pop <stelian@popies.net>, 1999-2000
  *     Stelian Pop <stelian@popies.net> - Alcôve <www.alcove.com>, 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
index 3e6d3fc2b6674a31a076dcb2eb3204790e1159d3..b69259a7fe9185986fddbe54477cac1c6ace6dfc 100644 (file)
@@ -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];
        }
index 2f344dbc85e87785dc3629c44ce690ee105c13e1..e60921bf3b86b1afff5ce0a8666978da04fe89d7 100644 (file)
@@ -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 <config.h>
@@ -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 */
index e0db9afa83b5c68e9ed70d73e81450901f4a2123..f17bd9ce458a7214ab50050f787c794d79a033a1 100644 (file)
@@ -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 <config.h>
@@ -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 (file)
index 0000000..6da39eb
--- /dev/null
@@ -0,0 +1,444 @@
+/*
+ * Copyright (c) 1999-2004
+ *     Stelian Pop <stelian@popies.net>, 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 <config.h>
+#include <compatlfs.h>
+#include <compaterr.h>
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <bsdcompat.h>
+#include <protocols/dumprestore.h>
+#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<<EXT2_XATTR_PAD_BITS)
+#define EXT2_XATTR_ROUND               (EXT2_XATTR_PAD-1)
+#define EXT2_XATTR_LEN(name_len) \
+       (((name_len) + EXT2_XATTR_ROUND + \
+       sizeof(struct ext2_xattr_entry)) & ~EXT2_XATTR_ROUND)
+#define EXT2_XATTR_NEXT(entry) \
+       ( (struct ext2_xattr_entry *)( \
+         (char *)(entry) + EXT2_XATTR_LEN((entry)->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);
+}
+