--- src/buffer.c.orig 2004-12-21 07:09:24.000000000 -0800 +++ src/buffer.c 2008-03-03 19:49:46.000000000 -0800 @@ -438,6 +438,41 @@ record_end = record_start + blocking_factor; } +#if HAVE_QUARANTINE +void +init_qtn(const char *file_name) +{ + int fd; + + if (strcmp(file_name, "-") == 0) + return; + + if ((fd = open(file_name, O_RDONLY)) < 0) + return; + + if ((archive_qtn_file = qtn_file_alloc()) != NULL) { + if (qtn_file_init_with_fd(archive_qtn_file, fd) != 0) { + qtn_file_free(archive_qtn_file); + archive_qtn_file = NULL; + } + } + + close(fd); +} + +void +finish_qtn(void) +{ + if (archive_qtn_file != NULL) { + qtn_file_free(archive_qtn_file); + archive_qtn_file = NULL; + } +} +#else +void init_qtn(const char *file_name) {} +void finish_qtn(void) {} +#endif + /* Open an archive file. The argument specifies whether we are reading or writing, or both. */ static void @@ -571,6 +606,7 @@ sys_detect_dev_null_output (); sys_save_archive_dev_ino (); SET_BINARY_MODE (archive); + init_qtn(archive_name_array[0]); switch (wanted_access) { @@ -864,6 +900,8 @@ free (real_s_name); free (record_buffer[0]); free (record_buffer[1]); + + finish_qtn(); } /* Called to initialize the global volume number. */ --- src/common.h.orig 2004-12-21 06:31:58.000000000 -0800 +++ src/common.h 2008-03-03 18:42:03.000000000 -0800 @@ -20,6 +20,13 @@ /* Declare the GNU tar archive format. */ #include "tar.h" +#include <TargetConditionals.h> +#define HAVE_QUARANTINE (!TARGET_OS_EMBEDDED) + +#if HAVE_QUARANTINE +#include <quarantine.h> +#endif + /* The checksum field is filled with this while the checksum is computed. */ #define CHKBLANKS " " /* 8 blanks, no null */ @@ -302,6 +309,9 @@ /* File descriptor for archive file. */ GLOBAL int archive; +#if HAVE_QUARANTINE +GLOBAL qtn_file_t archive_qtn_file; +#endif /* Nonzero when outputting to /dev/null. */ GLOBAL bool dev_null_output; --- src/extract.c.orig 2004-12-21 01:55:12.000000000 -0800 +++ src/extract.c 2008-03-03 19:51:38.000000000 -0800 @@ -413,6 +413,51 @@ quotearg_colon (dir))); } +#if HAVE_QUARANTINE +void +apply_qtn(int fd) +{ + int stat_ok; + struct stat sb; + int qstatus; + + if (archive_qtn_file != NULL) { + stat_ok = (fstat(fd, &sb) == 0); + + if (stat_ok) fchmod(fd, sb.st_mode | S_IWUSR); + qstatus = qtn_file_apply_to_fd(archive_qtn_file, fd); + if (stat_ok) fchmod(fd, sb.st_mode); + + if (qstatus) { + warnx("qtn_file_apply_to_fd: %s", qtn_error(qstatus)); + } + } +} + +void +apply_qtn_to_path(char *path) +{ + int stat_ok; + struct stat sb; + int qstatus; + + if (archive_qtn_file != NULL) { + stat_ok = (stat(path, &sb) == 0); + + if (stat_ok) chmod(path, sb.st_mode | S_IWUSR); + qstatus = qtn_file_apply_to_path(archive_qtn_file, path); + if (stat_ok) chmod(path, sb.st_mode); + + if (qstatus) { + warnx("qtn_file_apply_to_path: %s", qtn_error(qstatus)); + } + } +} +#else +void apply_qtn(int fd) {} +void apply_qtn_to_path(char *path) {} +#endif + /* After a file/link/directory creation has failed, see if it's because some required directory was not present, and if so, create all required directories. Return non-zero if a directory @@ -452,6 +497,8 @@ if (status == 0) { + apply_qtn_to_path(file_name); + /* Create a struct delayed_set_stat even if invert_permissions is zero, because repair_delayed_set_stat may need to update the struct. */ @@ -698,6 +745,7 @@ || old_files_option == DEFAULT_OLD_FILES || old_files_option == OVERWRITE_OLD_FILES) { + apply_qtn_to_path(file_name); if (status == 0) delay_set_stat (file_name, ¤t_stat_info, ((mode ^ current_stat_info.stat.st_mode) @@ -807,6 +854,7 @@ } #endif /* __APPLE__ */ + apply_qtn(fd); mv_begin (¤t_stat_info); if (current_stat_info.is_sparse) sparse_extract_file (fd, ¤t_stat_info, &size); --- src/list.c.orig 2008-07-11 19:37:25.000000000 -0700 +++ src/list.c 2008-07-11 19:39:27.000000000 -0700 @@ -230,6 +230,9 @@ rename(cle->tmp, cle->src); } + /* 5781559: Make sure EAs don't destroy overriding quarantine information. */ + apply_qtn_to_path(cle->dst); + free(cle->tmp); free(cle->dst); free(cle->src);