]> Dogcows Code - chaz/tar/blobdiff - src/extract.c
(extract_archive): Use sparse_member_p instead of GNUTYPE_SPARSE.
[chaz/tar] / src / extract.c
index 29b8e9b4f1cf60cfe854fb65ee10108bd1899f06..0feb68c345aa7d2ac49b56f252366894f79670c3 100644 (file)
@@ -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, &current_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, &current_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 (&current_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 (&current_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, &current_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;
 
This page took 0.02416 seconds and 4 git commands to generate.