-$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)
==================================================================
-VERSION= 0.4b37
-DATE= July 7, 2004
+VERSION= 0.4b40
+DATE= May 2, 2005
AR= @AR@
CC= @CC@
-$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.
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
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
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
-$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:
---------------
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).
* 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>
__u16 di_uidhigh;
__u16 di_gidhigh;
__u32 di_spare;
+ __u16 di_extraisize;
+ __u16 di_pad2;
};
#define di_rdev di_db[0]
* 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 $
*/
/*
#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.
#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_ */
/* 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
# 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.
READLINE=""
echo "Not including readline support"
else
- READLINE="-lreadline -ltermcap"
+ READLINE="yes"
cat >>confdefs.h <<\_ACEOF
#define HAVE_READLINE 1
fi
else
- READLINE="-lreadline -ltermcap"
+ READLINE="yes"
cat >>confdefs.h <<\_ACEOF
#define HAVE_READLINE 1
fi;
-
# Check whether --enable-oldstylefscript or --disable-oldstylefscript was given.
if test "${enable_oldstylefscript+set}" = set; then
enableval="$enable_oldstylefscript"
{ (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
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
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
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
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
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
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
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
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
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
+dump (0.4b40-1) unstable; urgency=low
+
+ * new upstream version, closes: #289210, #291644, #307423
+ * add debconf-2.0 as an alternate dependency
+ * updated Swedish translation from Daniel Nylander, closes: #330316
+ * remove /var/lib/dumpdates on purge, since we created it on install,
+ closes: #330363
+ * update dependencies in light of libreadline5-dev, closes: #326374
+ * rebuild ensures fresh version of zlib in case we've been vulnerable
+ to CAN-2005-2096, closes: #317966
+ * merge Vietnamese translation, closes: #311599
+ * merge Czech translation, closes: #315825
+ * update debhelper compatibility level, plus a few tweaks to pacify lintian
+
+ -- Bdale Garbee <bdale@gag.com> Wed, 28 Sep 2005 00:50:29 -0600
+
dump (0.4b37-2) unstable; urgency=low
* merge updated de.po, closes: #281076
db_go
fi
-if [ -f /etc/dumpdates -a ! -f /var/lib/dumpdates ]; then
+if [ -f /etc/dumpdates ] && [ -f /var/lib/dumpdates ]; then
# moving from etc to var
db_input medium dump/moving_from_etc_to_var || true
db_go
Section: utils
Priority: optional
Maintainer: Bdale Garbee <bdale@gag.com>
-Build-Depends: autoconf, comerr-dev, debhelper (>= 4.1.16), e2fslibs-dev, libbz2-dev, libreadline4-dev, zlib1g-dev, libblkid-dev, uuid-dev
-Standards-Version: 3.6.1.0
+Build-Depends: autoconf, comerr-dev, debhelper (>= 4.1.16), e2fslibs-dev, libbz2-dev, libreadline5-dev | libreadline-dev, zlib1g-dev, libblkid-dev, uuid-dev
+Standards-Version: 3.6.2.1
Package: dump
Architecture: any
-Depends: ${shlibs:Depends}, debconf (>= 0.5.00), tar (>= 1.13.92-3)
+Depends: ${shlibs:Depends}, debconf (>= 0.5.00) | debconf-2.0, tar (>= 1.13.92-3)
Description: 4.4bsd dump and restore for ext2 filesystems
Dump examines files on a filesystem and determines which files need to be
backed up. These files are copied to the given disk, tape or other storage
--- /dev/null
+#
+# Translators, if you are not familiar with the PO format, gettext
+# documentation is worth reading, especially sections dedicated to
+# this format, e.g. by running:
+# info -n '(gettext)PO Files'
+# info -n '(gettext)Header Entry'
+#
+# Some information specific to po-debconf are available at
+# /usr/share/doc/po-debconf/README-trans
+# or http://www.debian.org/intl/l10n/po-debconf/README-trans
+#
+# Developers do not need to manually edit POT or PO files.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: dump\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2003-08-19 16:21-0600\n"
+"PO-Revision-Date: 2005-06-25 17:53+0200\n"
+"Last-Translator: Miroslav Kure <kurem@debian.cz>\n"
+"Language-Team: Czech <debian-l10n-czech@lists.debian.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#. Description
+#: ../templates:3
+msgid "/etc/dumpdates is a symlink, dump will look in /var/lib/dumpdates"
+msgstr "/etc/dumpdates je symbolický odkaz, dump hledá /var/lib/dumpdates"
+
+#. Description
+#: ../templates:3
+msgid ""
+"Your /etc/dumpdates is a symlink. Dump will look for dumpdates in /var/lib/"
+"dumpdates. A symlink in /etc/dumpdates adds no known value (as nothing "
+"outside the dump package is known to use it) and is likely to confuse "
+"someone eventually. The most likely reason for this symlink to exist is "
+"that you once had a much earlier version of the Debian dump package "
+"installed that behaved poorly. Please remove /etc/dumpdates."
+msgstr ""
+"/etc/dumpdates je symbolický odkaz. Dump bude hledat dumpdates ve /var/lib/"
+"dumpdates. Odkaz /etc/dumpdates nepřináší nic užitečného, protože vyjma "
+"balíku dump jej nic jiného nepoužívá a dříve či později někoho zmate. "
+"Nejpravděpodobnější vysvětlení pro existenci tohoto odkazu je, že jste "
+"kdysi dávno používali prastarou verzi balíku dump. Odstraňte prosím "
+"odkaz /etc/dumpdates."
+
+#. Description
+#: ../templates:13
+msgid "Moving existing /etc/dumpdates to /var/lib for FHS compliance."
+msgstr ""
+"Přesouvám stávající /etc/dumpdates do /var/lib kvůli kompatibilitě s FHS."
-#
-# Translators, if you are not familiar with the PO format, gettext
-# documentation is worth reading, especially sections dedicated to
-# this format, e.g. by running:
-# info -n '(gettext)PO Files'
-# info -n '(gettext)Header Entry'
-#
-# Some information specific to po-debconf are available at
-# /usr/share/doc/po-debconf/README-trans
-# or http://www.debian.org/intl/l10n/po-debconf/README-trans
-#
-# Developers do not need to manually edit POT or PO files.
-#
-#, fuzzy
+# Translators, if you are not familiar with the PO format, gettext
+# documentation is worth reading, especially sections dedicated to
+# this format, e.g. by running:
+# info -n '(gettext)PO Files'
+# info -n '(gettext)Header Entry'
+# Some information specific to po-debconf are available at
+# /usr/share/doc/po-debconf/README-trans
+# or http://www.debian.org/intl/l10n/po-debconf/README-trans
+# Developers do not need to manually edit POT or PO files.
+# , fuzzy
+#
+#
msgid ""
msgstr ""
-"Project-Id-Version: PACKAGE VERSION\n"
+"Project-Id-Version: dump 0.4b37-2\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2003-08-19 16:21-0600\n"
-"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
-"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
-"Language-Team: LANGUAGE <LL@li.org>\n"
+"PO-Revision-Date: 2005-09-27 15:47-0700\n"
+"Last-Translator: Daniel Nylander <po@danielnylander.se>\n"
+"Language-Team: Swedish <sv@li.org>\n"
"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=ISO-8859-1\n"
-"Content-Transfer-Encoding: 8bit\n"
+"Content-Type: text/plain; charset=iso-8859-1\n"
+"Content-Transfer-Encoding: 8bit"
#. Description
#: ../templates:3
"someone eventually. The most likely reason for this symlink to exist is "
"that you once had a much earlier version of the Debian dump package "
"installed that behaved poorly. Please remove /etc/dumpdates."
-msgstr ""
+msgstr "Din /etc/dumpdates fil är en symbolisk länk. Dump kommer att leta efter dumpdatum i /var/lib/dumpdates. En symbolisk länk i /etc/dumpdates saknar värde och skapar bara förvirring. Ett antagande är att filen existerar sedan en gammal version av dump som blev installerad felaktigt. Var vänlig och radera /etc/dumpdates."
#. Description
#: ../templates:13
#~ "Your /etc/dumpdates is a symlink. Dump will look for dumpdates in /var/"
#~ "lib/dumpdates. Please fix things."
#~ msgstr ""
-#~ "Din /etc/dumpdates är en symlänk. Dump kommer att kolla efter dumpdates "
-#~ "i /var/lib/dumpdates. Var snäll och fixa till detta."
+#~ "Din /etc/dumpdates är en symlänk. Dump kommer att kolla efter dumpdates "
+#~ "i /var/lib/dumpdates. Var snäll och fixa till detta."
--- /dev/null
+# Vietnamese Translation for dump.
+# Copyright © 2005 Free Software Foundation, Inc.
+# Clytie Siddall <clytie@riverland.net.au>, 2005.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: dump 0.4b37-1\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2003-08-19 16:21-0600\n"
+"PO-Revision-Date: 2005-06-02 15:39+0930\n"
+"Last-Translator: Clytie Siddall <clytie@riverland.net.au>\n"
+"Language-Team: Vietnamese <gnomevi-list@lists.sourceforge.net>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=utf-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=1; plural=0\n"
+
+#. Description
+#: ../templates:3
+msgid "/etc/dumpdates is a symlink, dump will look in /var/lib/dumpdates"
+msgstr "/etc/dumpdates là một liên kết tượng trưng nên trình dump sẽ tìm trong /var/lib/dumpdates"
+
+#. Description
+#: ../templates:3
+msgid ""
+"Your /etc/dumpdates is a symlink. Dump will look for dumpdates in /var/lib/"
+"dumpdates. A symlink in /etc/dumpdates adds no known value (as nothing "
+"outside the dump package is known to use it) and is likely to confuse "
+"someone eventually. The most likely reason for this symlink to exist is "
+"that you once had a much earlier version of the Debian dump package "
+"installed that behaved poorly. Please remove /etc/dumpdates."
+msgstr "/etc/dumpdates của bạn là một liên kết tượng trưng, nên trình dump sẽ tìm dumpdates (ngày đổ) trong /var/lib/dumpdates. Một liên kết tượng trưng trong /etc/dumpdates không thêm giá trị hữu ích nào (vì không có gì ở ngoại gói dump sẽ dùng nó) và rất có thể sẽ làm cho người dùng lẫn lộn cuối cùng. Có liên kết tượng trưng ấy rất có thể vì trước này bạn đã cài đặt một phiên bản nhiều cũ hơn của gói tin dump Debian mà không hoạt động cho đúng. Hãy loại bỏ /etc/dumpdates."
+
+#. Description
+#: ../templates:13
+msgid "Moving existing /etc/dumpdates to /var/lib for FHS compliance."
+msgstr "Đang di chuyển /etc/dumpdates đã có vào /var/lib để tương tác với FHS."
. /usr/share/debconf/confmodule
-if [ -f /etc/dumpdates -a ! -f /var/lib/dumpdates ]; then
+if [ -f /etc/dumpdates ] && [ ! -f /var/lib/dumpdates ]; then
mv /etc/dumpdates /var/lib/dumpdates
fi
--- /dev/null
+#!/bin/sh -e
+
+rm -f /var/lib/dumpdates
+
+#DEBHELPER#
dh_clean -k
dh_installdirs
make install \
- SBINDIR=`pwd`/debian/tmp/sbin \
- MANDIR=`pwd`/debian/tmp/usr/share/man/man8
+ SBINDIR=`pwd`/debian/dump/sbin \
+ MANDIR=`pwd`/debian/dump/usr/share/man/man8
- mv debian/tmp/usr/share/man/man8/rmt.8 \
- debian/tmp/usr/share/man/man8/rmt-dump.8
- mv debian/tmp/sbin/rmt debian/tmp/usr/sbin/rmt-dump
+ mv debian/dump/usr/share/man/man8/rmt.8 \
+ debian/dump/usr/share/man/man8/rmt-dump.8
+ mv debian/dump/sbin/rmt debian/dump/usr/sbin/rmt-dump
- (cd debian/tmp/sbin ; rm -f rdump rrestore ; \
+ (cd debian/dump/sbin ; rm -f rdump rrestore ; \
ln -s dump rdump ; ln -s restore rrestore )
- (cd debian/tmp/usr/share/man/man8 ; rm -f rdump* rrestore* ; \
+ (cd debian/dump/usr/share/man/man8 ; rm -f rdump* rrestore* ; \
ln -s dump.8.gz rdump.8.gz ; ln -s restore.8.gz rrestore.8.gz )
dh_installdocs KNOWNBUGS MAINTAINERS README THANKS TODO
dh_installexamples examples/*
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/*
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
%{_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.
.\" 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
.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
.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
#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>
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)
}
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;
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
#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>
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)
*/
SETINO(ino, usedinomap);
+ if (NODUMP_FLAG(dp))
+ do_exclude_ino(ino, "nodump attribute");
+
if (mode == IFDIR)
SETINO(ino, dumpdirmap);
if (WANTTODUMP(dp, ino)) {
return;
}
if (mode == IFDIR) {
- if ( NODUMP_FLAG(dp) || exclude_ino(ino) )
+ if (exclude_ino(ino))
CLRINO(ino, usedinomap);
*dirskipped = 1;
}
}
#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.
*
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;
spcl.c_count = 0;
writeheader(ino);
spcl.c_flags &= ~DR_METAONLY;
+ dump_xattr(ino, dp);
return;
}
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__ */
case S_IFCHR:
case S_IFBLK:
writeheader(ino);
+ dump_xattr(ino, dp);
return;
default:
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));
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);
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);
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;
}
(void)free(cdc.buf);
+ dump_xattr(ino, dp);
}
#endif /* __linux__ */
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);
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);
--- /dev/null
+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
--- /dev/null
+#!/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
-# $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@
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
#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>
uid_t uid;
gid_t gid;
unsigned int flags;
+ char xattr;
};
/*
};
#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));
{
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,
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);
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;
}
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)
(void) chmod(cp, node.mode);
if (node.flags)
#ifdef __linux__
- (void) fsetflags(cp, node.flags);
+ (void) lsetflags(cp, node.flags);
#else
#ifdef sunos
#else
#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;
}
}
*/
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)
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;
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);
}
/*
* 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 $
*/
/*-
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));
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 *));
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 *));
#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>
static const char *stdin_opt = NULL;
char *bot_script = NULL;
dump_ino_t volinfo[TP_NINOS];
+int wdfd;
#ifdef USE_QFA
FILE *gTapeposfp;
else
setinput(inputdev);
+ wdfd = open(".", O_RDONLY);
+ if (wdfd < 0)
+ err(1, "can't get current directory");
+
if (argc == 0 && !filelist) {
argc = 1;
*--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)
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");
.\" 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
[\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
.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
#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>
{
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);
+ }
}
}
}
* 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);
+ }
}
}
}
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);
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);
}
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
} 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
}
* 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 $
*/
/*
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
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 */
exit(2); \
}
+#define XATTR_MAXSIZE 4096
#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 */
/*
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
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')
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)
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)
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);
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);
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");
+ }
}
}
struct symtableheader {
int32_t volno;
int32_t stringsize;
+ int32_t hashsize;
int32_t entrytblsize;
time_t dumptime;
time_t dumpdate;
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)
(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));
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;
hdr.maxino = maxino;
hdr.entrytblsize = entrytblsize;
hdr.stringsize = stroff;
+ hdr.hashsize = hashoff;
hdr.dumptime = dumptime;
hdr.dumpdate = dumpdate;
hdr.ntrec = ntrec;
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)
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];
}
#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>
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));
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
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:
{
#ifdef HAVE_LCHOWN
(void) lchown(name, luid, lgid);
#endif
+ extractattr(name);
return (GOOD);
}
(void) chmod(name, mode);
if (flags)
#ifdef __linux__
- (void) fsetflags(name, flags);
+ (void) lsetflags(name, flags);
#else
#ifdef sunos
{
#endif
#endif
skipfile();
+ extractattr(name);
utimes(name, timep);
return (GOOD);
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
#endif
#endif
skipfile();
+ extractattr(name);
utimes(name, timep);
return (GOOD);
(void) chmod(name, mode);
if (flags)
#ifdef __linux__
- (void) fsetflags(name, flags);
+ (void) lsetflags(name, flags);
#else
#ifdef sunos
{
(void) chflags(name, flags);
#endif
#endif
+ extractattr(name);
utimes(name, timep);
return (GOOD);
}
/* 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)
u_int32_t uid;
u_int32_t gid;
char path[MAXPATHLEN], fname[MAXPATHLEN];
- int toto;
curfile.name = name;
curfile.action = USING;
(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);
}
}
#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
*/
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;
static void
xtrfilefinderinfo(char *buf, size_t size)
{
- if (Nflag)
- return;
bcopy(buf, &gFndrInfo, size);
}
#endif /* DUMP_MACOSX */
{
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';
}
/*
}
#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];
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);
}
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;
}
}
#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
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);
}
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;
case IFDIR:
skipfile();
+ compareattr(name);
return;
case IFLNK: {
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;
}
do_compare_error;
return;
}
+ compareattr(name);
return;
}
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;
}
unlink(tmpfile);
#endif
#endif /* COMPARE_ONTHEFLY */
+ compareattr(name);
return;
}
/* NOTREACHED */
#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>
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);
*/
#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
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)
if (yflag)
return;
if (reply("abort") == GOOD) {
- if (reply("dump core") == GOOD)
+ if (reply("dump core") == GOOD) {
+ fchdir(wdfd);
abort();
+ }
exit(1);
}
}
(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);
+}
--- /dev/null
+/*
+ * 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);
+}
+