--- src/buffer.c.orig 2004-12-21 07:09:24.000000000 -0800 +++ src/buffer.c 2008-03-03 19:49:46.000000000 -0800 @@ -368,6 +368,41 @@ return result; } +#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. */ void @@ -508,6 +543,7 @@ sys_detect_dev_null_output (); sys_save_archive_dev_ino (); SET_BINARY_MODE (archive); + init_qtn(archive_name_array[0]); switch (wanted_access) { @@ -1093,6 +1129,8 @@ if (real_s_name) free (real_s_name); free (record_buffer); + + 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 */ @@ -283,6 +290,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 @@ -360,6 +360,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/symlink/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 @@ -400,6 +445,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. */ @@ -739,6 +786,8 @@ #endif /* __APPLE__ */ extract_file: + apply_qtn(fd); + if (current_stat_info.is_sparse) { sparse_extract_file (fd, ¤t_stat_info, &size); @@ -1088,11 +1137,14 @@ directory_exists: if (status == 0 || old_files_option == OVERWRITE_OLD_FILES) + { + apply_qtn_to_path(file_name); delay_set_stat (file_name, ¤t_stat_info.stat, MODE_RWX & (mode ^ current_stat_info.stat.st_mode), (status == 0 ? ARCHIVED_PERMSTATUS : UNKNOWN_PERMSTATUS)); + } break; case GNUTYPE_VOLHDR: --- src/list.c.orig 2008-07-11 19:37:25.000000000 -0700 +++ src/list.c 2008-07-11 19:39:27.000000000 -0700 @@ -227,6 +227,9 @@ } else unlink(cle->tmp); + /* 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);