diff -u --exclude=CVS -r -udbp config.hin config.hin --- config.hin 2004-05-11 01:14:44.000000000 -0700 +++ config.hin 2005-03-21 13:00:28.000000000 -0800 @@ -84,6 +84,12 @@ /* Define to 1 if you have the `clock_settime' function. */ #undef HAVE_CLOCK_SETTIME +/* Define to 1 if you have the `copyfile' function. */ +#undef HAVE_COPYFILE + +/* Define to 1 if you have the <copyfile.h> header file. */ +#undef HAVE_COPYFILE_H + /* Define if the GNU dcgettext() function is already present or preinstalled. */ #undef HAVE_DCGETTEXT diff -u --exclude=CVS -r -udbp configure configure --- configure 2004-05-11 01:13:36.000000000 -0700 +++ configure 2005-03-21 13:00:28.000000000 -0800 @@ -21515,6 +21515,258 @@ else fi +for ac_func in copyfile +do +as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` +echo "$as_me:$LINENO: checking for $ac_func" >&5 +echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6 +if eval "test \"\${$as_ac_var+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func. + For example, HP-UX 11i <limits.h> declares gettimeofday. */ +#define $ac_func innocuous_$ac_func + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func (); below. + Prefer <limits.h> to <assert.h> if __STDC__ is defined, since + <limits.h> exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include <limits.h> +#else +# include <assert.h> +#endif + +#undef $ac_func + +/* 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 $ac_func (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +char (*f) () = $ac_func; +#endif +#ifdef __cplusplus +} +#endif + +int +main () +{ +return f != $ac_func; + ; + 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 + eval "$as_ac_var=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +eval "$as_ac_var=no" +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6 +if test `eval echo '${'$as_ac_var'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + +for ac_header in copyfile.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 +else + # Is the header compilable? +echo "$as_me:$LINENO: checking $ac_header usability" >&5 +echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 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_objext' + { (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_header_compiler=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_header_compiler=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +echo "${ECHO_T}$ac_header_compiler" >&6 + +# Is the header present? +echo "$as_me:$LINENO: checking $ac_header presence" >&5 +echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <$ac_header> +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 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); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + ac_header_preproc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi +rm -f conftest.err conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +echo "${ECHO_T}$ac_header_preproc" >&6 + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in + yes:no: ) + { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 +echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 +echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 +echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 +echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 +echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} + ( + cat <<\_ASBOX +## ------------------------------ ## +## Report this to bug-tar@gnu.org ## +## ------------------------------ ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac +echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + eval "$as_ac_Header=\$ac_header_preproc" +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 + +fi +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + ac_config_files="$ac_config_files Makefile doc/Makefile lib/Makefile po/Makefile.in scripts/Makefile src/Makefile tests/Makefile tests/preset" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure diff -u --exclude=CVS -r -udbp configure.ac configure.ac --- configure.ac 2004-05-11 01:11:48.000000000 -0700 +++ configure.ac 2005-03-21 13:00:28.000000000 -0800 @@ -280,6 +280,8 @@ else BACKUP_SED_COND='/^\#IF_DATE_FORMAT_OK/,/^\#ELSE_DATE_FORMAT_OK/d;/^\#ENDIF_DATE_FORMAT_OK/d' fi +AC_CHECK_FUNCS(copyfile) +AC_CHECK_HEADERS(copyfile.h) AC_OUTPUT([Makefile\ doc/Makefile\ diff -u --exclude=CVS -r -udbp src/create.c src/create.c --- src/create.c 2004-04-26 02:17:20.000000000 -0700 +++ src/create.c 2005-03-21 13:00:28.000000000 -0800 @@ -36,6 +36,14 @@ struct utimbuf #include "common.h" #include <hash.h> +#ifdef HAVE_COPYFILE_H +#include <copyfile.h> +#include <libgen.h> + +int copyfile_on = 0; +char *copyfile_fname = NULL; +#endif + struct link { dev_t dev; @@ -1275,8 +1283,16 @@ dump_file0 (struct tar_stat_info *st, ch if (interactive_option && !confirm ("add", p)) return; + if (copyfile_on) + { + assign_string (&st->orig_file_name, copyfile_fname); + assign_string (&st->file_name, safer_name_suffix (copyfile_fname, false)); + } + else + { assign_string (&st->orig_file_name, p); assign_string (&st->file_name, safer_name_suffix (p, false)); + } if (deref_stat (dereference_option, p, &st->stat) != 0) { @@ -1349,7 +1365,11 @@ dump_file0 (struct tar_stat_info *st, ch if (file_dumpable_p (st)) { +#if HAVE_COPYFILE + fd = open ( copyfile_on ? p : st->orig_file_name, +#else fd = open (st->orig_file_name, +#endif O_RDONLY | O_BINARY); if (fd < 0) { @@ -1495,6 +1515,33 @@ void dump_file (char *p, int top_level, dev_t parent_device) { struct tar_stat_info st; + +#ifdef HAVE_COPYFILE + if (!getenv(COPYFILE_DISABLE_VAR) && strncmp(basename(p), "._", 2)) + { + char *md_p = strdup("/tmp/tar.md.XXXXXX"); + asprintf(©file_fname, "%s/._%s", dirname(p), basename(p)); + + if (copyfile(p, NULL, 0, COPYFILE_CHECK | COPYFILE_METADATA)) + { + copyfile_on = 1; + tar_stat_init (&st); + + if(mktemp(md_p)) + { + copyfile(p, md_p, 0, COPYFILE_METADATA | COPYFILE_PACK); + dump_file0 (&st, md_p, top_level, parent_device); + } + + tar_stat_destroy (&st); + unlink(md_p); + free(copyfile_fname); + copyfile_on = 0; + } + free(md_p); + } +#endif + tar_stat_init (&st); dump_file0 (&st, p, top_level, parent_device); tar_stat_destroy (&st); diff -u --exclude=CVS -r -udbp src/extract.c src/extract.c --- src/extract.c 2004-04-05 00:23:51.000000000 -0700 +++ src/extract.c 2005-03-21 13:01:08.000000000 -0800 @@ -35,6 +35,19 @@ struct utimbuf #include "common.h" +#ifdef HAVE_COPYFILE_H +#include <libgen.h> +#include <sys/queue.h> +#include <copyfile.h> +struct copyfile_list_entry_t { + char *src; + char *dst; + char *tmp; + LIST_ENTRY(copyfile_list_entry_t) link; +} *cle; +extern LIST_HEAD(copyfile_list_t, copyfile_list_entry_t) copyfile_list; +#endif + bool we_are_root; /* true if our effective uid == 0 */ static mode_t newdir_umask; /* umask when creating new directories */ static mode_t current_umask; /* current umask (which is set to 0 if -p) */ @@ -602,6 +615,10 @@ extract_archive (void) int interdir_made = 0; char typeflag; char *file_name; +#if HAVE_COPYFILE + char *tmp; + struct copyfile_list_entry_t *cle; +#endif set_next_block_after (current_header); decode_header (current_header, ¤t_stat_info, ¤t_format, 1); @@ -679,6 +696,35 @@ extract_archive (void) goto extract_file; } +#if HAVE_COPYFILE + if (!strncmp(basename(file_name), "._", 2)) + { + if ((cle = calloc(1, sizeof(struct copyfile_list_entry_t))) == NULL) + goto err; + + if ((cle->src = strdup(file_name)) == NULL) + goto err; + + if(asprintf(&cle->tmp, "%s.XXX", file_name) == -1) + goto err; + + if(mktemp(cle->tmp) == NULL) + goto err; + + if (asprintf(&cle->dst, "%s/%s", dirname(file_name), basename(file_name) + 2) != -1) + LIST_INSERT_HEAD(©file_list, cle, link); + else { + err: + if (cle->src) free(cle->src); + if (cle->dst) free(cle->dst); + if (cle->tmp) free(cle->tmp); + if (cle) free(cle); + break; + } + file_name = cle->tmp; + } +#endif + if (! prepare_to_extract (file_name)) { skip_member (); @@ -790,6 +836,7 @@ extract_archive (void) ? UNKNOWN_PERMSTATUS : ARCHIVED_PERMSTATUS), typeflag); + break; case SYMTYPE: diff -u --exclude=CVS -r -udbp src/list.c src/list.c --- src/list.c 2004-05-10 04:49:09.000000000 -0700 +++ src/list.c 2005-03-21 13:03:26.000000000 -0800 @@ -25,6 +25,19 @@ #include "system.h" #include <quotearg.h> +#if HAVE_COPYFILE +#include <copyfile.h> +#include <sys/param.h> +#include <sys/queue.h> +struct copyfile_list_entry_t { + char *src; + char *dst; + char *tmp; + LIST_ENTRY(copyfile_list_entry_t) link; +} *cle; +LIST_HEAD(copyfile_list_t, copyfile_list_entry_t) copyfile_list; +#endif + #include "common.h" #define max(a, b) ((a) < (b) ? (b) : (a)) @@ -69,6 +82,12 @@ read_and (void (*do_something) (void)) enum read_header status = HEADER_STILL_UNREAD; enum read_header prev_status; +#if HAVE_COPYFILE + int disable_copyfile = (getenv(COPYFILE_DISABLE_VAR) != NULL); + struct copyfile_list_entry_t *cle; + LIST_INIT(©file_list); +#endif + base64_init (); name_gather (); open_archive (ACCESS_READ); @@ -197,6 +216,21 @@ read_and (void (*do_something) (void)) } while (!all_names_found (¤t_stat_info)); +#ifdef HAVE_COPYFILE + LIST_FOREACH(cle, ©file_list, link) + { + if(disable_copyfile || copyfile(cle->tmp, cle->dst, 0, COPYFILE_UNPACK | COPYFILE_XATTR | COPYFILE_ACL)) + { + rename(cle->tmp, cle->src); + } else + unlink(cle->tmp); + + free(cle->tmp); + free(cle->dst); + free(cle->src); + } +#endif + close_archive (); names_notfound (); /* print names not found */ } diff -u --exclude=CVS -r -udbp src/tar.c src/tar.c --- src/tar.c 2004-05-10 04:49:19.000000000 -0700 +++ src/tar.c 2005-03-21 13:00:28.000000000 -0800 @@ -1303,6 +1303,7 @@ You may redistribute it under the terms see the file named COPYING for details.")); puts (_("Written by John Gilmore and Jay Fenlason.")); + puts (_("Modified to support extended attributes.")); exit (TAREXIT_SUCCESS); }