X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;f=src%2Fextract.c;h=0feb68c345aa7d2ac49b56f252366894f79670c3;hb=3030a247b1e0d4ab25261107bed5ff4afb644b84;hp=29b8e9b4f1cf60cfe854fb65ee10108bd1899f06;hpb=47e73c7a445527ae5b88873c12905c7fe1cfaf78;p=chaz%2Ftar diff --git a/src/extract.c b/src/extract.c index 29b8e9b..0feb68c 100644 --- a/src/extract.c +++ b/src/extract.c @@ -419,6 +419,24 @@ make_directories (char *file_name) return did_something; /* tell them to retry if we made one */ } +static bool +file_newer_p (const char *file_name, struct tar_stat_info *tar_stat) +{ + struct stat st; + + if (stat (file_name, &st)) + { + stat_warn (file_name); + return true; /* Be on the safe side */ + } + if (!S_ISDIR (st.st_mode) + && st.st_mtime >= current_stat_info.stat.st_mtime) + { + return true; + } + return false; +} + /* Prepare to extract a file. Return zero if extraction should not proceed. */ @@ -428,12 +446,27 @@ prepare_to_extract (char const *file_name, bool directory) if (to_stdout_option) return 0; - if (old_files_option == UNLINK_FIRST_OLD_FILES - && !remove_any_file (file_name, recursive_unlink_option) - && errno && errno != ENOENT) + switch (old_files_option) { - unlink_error (file_name); - return 0; + case UNLINK_FIRST_OLD_FILES: + if (!remove_any_file (file_name, recursive_unlink_option) + && errno && errno != ENOENT) + { + unlink_error (file_name); + return 0; + } + break; + + case KEEP_NEWER_FILES: + if (file_newer_p (file_name, ¤t_stat_info)) + { + WARN ((0, 0, _("Current `%s' is newer"), file_name)); + return 0; + } + break; + + default: + break; } return 1; @@ -446,6 +479,8 @@ prepare_to_extract (char const *file_name, bool directory) static int maybe_recoverable (char *file_name, int *interdir_made) { + int e = errno; + if (*interdir_made) return 0; @@ -456,9 +491,17 @@ maybe_recoverable (char *file_name, int *interdir_made) switch (old_files_option) { - default: + case KEEP_OLD_FILES: return 0; + case KEEP_NEWER_FILES: + if (file_newer_p (file_name, ¤t_stat_info)) + { + errno = e; + return 0; + } + /* FALL THROUGH */ + case DEFAULT_OLD_FILES: case NO_OVERWRITE_DIR_OLD_FILES: case OVERWRITE_OLD_FILES: @@ -467,6 +510,9 @@ maybe_recoverable (char *file_name, int *interdir_made) errno = EEXIST; return r; } + + case UNLINK_FIRST_OLD_FILES: + break; } case ENOENT: @@ -553,7 +599,6 @@ extract_archive (void) int openflag; mode_t mode; off_t size; - off_t file_size; int interdir_made = 0; char typeflag; char *file_name; @@ -572,7 +617,7 @@ extract_archive (void) if (verbose_option) print_header (¤t_stat_info, -1); - file_name = safer_name_suffix (current_stat_info.file_name, 0); + file_name = safer_name_suffix (current_stat_info.file_name, false); if (strip_path_elements) { size_t prefix_len = stripped_prefix_len (file_name, strip_path_elements); @@ -600,10 +645,9 @@ extract_archive (void) /* Extract the archive entry according to its type. */ - typeflag = current_header->header.typeflag; - /*KLUDGE*/ - if (current_stat_info.archive_file_size != current_stat_info.stat.st_size) - typeflag = GNUTYPE_SPARSE; + /* KLUDGE */ + typeflag = sparse_member_p (¤t_stat_info) ? + GNUTYPE_SPARSE : current_header->header.typeflag; switch (typeflag) { @@ -680,7 +724,7 @@ extract_archive (void) } extract_file: - if (typeflag == GNUTYPE_SPARSE) + if (current_stat_info.is_sparse) { sparse_extract_file (fd, ¤t_stat_info, &size); } @@ -860,7 +904,8 @@ extract_archive (void) again_link: { - char const *link_name = safer_name_suffix (current_stat_info.link_name, 1); + char const *link_name = safer_name_suffix (current_stat_info.link_name, + true); struct stat st1, st2; int e;