--- src/create.c.orig 2007-06-01 03:17:10.000000000 -0700 +++ src/create.c 2008-08-18 19:10:08.000000000 -0700 @@ -26,6 +26,15 @@ #include "common.h" #include <hash.h> +#ifdef __APPLE__ +#include <copyfile.h> +#include <libgen.h> +#include <paths.h> + +int copyfile_on = 0; +char *copyfile_fname = NULL; +#endif + struct link { dev_t dev; @@ -1485,9 +1494,18 @@ 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, absolute_names_option)); + } + else + { assign_string (&st->orig_file_name, p); assign_string (&st->file_name, safer_name_suffix (p, false, absolute_names_option)); + } transform_name (&st->file_name); @@ -1777,6 +1795,40 @@ dump_file (const char *p, int top_level, dev_t parent_device) { struct tar_stat_info st; + +#ifdef __APPLE__ + if (!getenv(COPYFILE_DISABLE_VAR) && !strncmp(basename(p), "._", 2)) { + return; + } + + if (!getenv(COPYFILE_DISABLE_VAR) && strncmp(basename(p), "._", 2)) + { + char *tmpdir = getenv("TMPDIR"), *md_p; + asprintf(&md_p, "%s/tar.md.XXXXXXXX", tmpdir ? tmpdir : _PATH_TMP); + asprintf(©file_fname, "%s/._%s", dirname(p), basename(p)); + + if (copyfile(p, NULL, 0, COPYFILE_CHECK | COPYFILE_NOFOLLOW | COPYFILE_ACL | COPYFILE_XATTR)) + { + copyfile_on = 1; + tar_stat_init (&st); + + if(mktemp(md_p)) + { + if (copyfile(p, md_p, 0, COPYFILE_PACK | COPYFILE_NOFOLLOW | COPYFILE_ACL | COPYFILE_XATTR) == 0) + dump_file0 (&st, md_p, top_level, parent_device); + else + WARN((0, 0, "copyfile pack (%s) failed: %s", p, strerror(errno))); + } + + 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); if (listed_incremental_option) --- src/extract.c.orig 2007-06-08 01:14:42.000000000 -0700 +++ src/extract.c 2008-08-18 19:10:08.000000000 -0700 @@ -27,6 +27,19 @@ #include "common.h" +#ifdef __APPLE__ +#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 + static 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) */ @@ -1200,6 +1213,9 @@ { char typeflag; tar_extractor_t fun; +#ifdef __APPLE__ + struct copyfile_list_entry_t *cle = NULL; +#endif set_next_block_after (current_header); decode_header (current_header, ¤t_stat_info, ¤t_format, 1); @@ -1240,7 +1256,31 @@ if (prepare_to_extract (current_stat_info.file_name, typeflag, &fun)) { - if (fun && (*fun) (current_stat_info.file_name, typeflag) +#ifdef __APPLE__ + if (strncmp(basename(current_stat_info.file_name), "._", 2) == 0) { + if ((cle = calloc(1, sizeof(struct copyfile_list_entry_t))) == NULL) + goto err; + if ((cle->src = strdup(current_stat_info.file_name)) == NULL) + goto err; + if (asprintf(&cle->tmp, "%s.XXX", current_stat_info.file_name) == -1) + goto err; + if (mktemp(cle->tmp) == NULL) + goto err; + if (asprintf(&cle->dst, "%s/%s", dirname(current_stat_info.file_name), basename(current_stat_info.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); + cle = NULL; + } + } + } +#endif + if (fun && (*fun) (cle ? cle->tmp : current_stat_info.file_name, typeflag) && backup_option) undo_last_backup (); } --- src/list.c.orig 2007-06-08 01:14:42.000000000 -0700 +++ src/list.c 2008-08-18 19:10:08.000000000 -0700 @@ -23,6 +23,19 @@ #include <inttostr.h> #include <quotearg.h> +#ifdef __APPLE__ +#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)) @@ -68,6 +81,12 @@ enum read_header prev_status; struct timespec mtime; +#ifdef __APPLE__ + int disable_copyfile = (getenv(COPYFILE_DISABLE_VAR) != NULL); + struct copyfile_list_entry_t *cle; + LIST_INIT(©file_list); +#endif + base64_init (); name_gather (); @@ -195,6 +214,28 @@ } while (!all_names_found (¤t_stat_info)); +#ifdef __APPLE__ + LIST_FOREACH(cle, ©file_list, link) + { + if(!disable_copyfile && copyfile(cle->tmp, cle->dst, 0, COPYFILE_UNPACK | COPYFILE_NOFOLLOW | COPYFILE_ACL | COPYFILE_XATTR) == 0) + { + unlink(cle->tmp); + } + else + { + if (!disable_copyfile) + { + WARN((0, 0, "copyfile unpack (%s) failed: %s", cle->dst, strerror(errno))); + } + rename(cle->tmp, cle->src); + } + + free(cle->tmp); + free(cle->dst); + free(cle->src); + } +#endif + close_archive (); names_notfound (); /* print names not found */ } --- lib/version-etc.c.orig 2008-08-18 19:17:17.000000000 -0700 +++ lib/version-etc.c 2008-08-18 19:19:10.000000000 -0700 @@ -74,6 +74,8 @@ "), stream); + fputs (_("Modified to support extended attributes.\n"), stream); + switch (n_authors) { case 0: