Browse Source

Fix restoring of directory timestamps from
incremental archives.
(directories_first): New variable.
(prepare_to_extract): Set directories_first
(extract_archive): Call apply_nonancestor_delayed_set_stat() only
if not extracting from an incremental archive

Sergey Poznyakoff 19 years ago
parent
commit
5249a99377
1 changed files with 30 additions and 6 deletions
  1. 30 6
      src/extract.c

+ 30 - 6
src/extract.c

@@ -30,6 +30,11 @@
 static bool we_are_root;	/* true if our effective uid == 0 */
 static bool we_are_root;	/* true if our effective uid == 0 */
 static mode_t newdir_umask;	/* umask when creating new directories */
 static mode_t newdir_umask;	/* umask when creating new directories */
 static mode_t current_umask;	/* current umask (which is set to 0 if -p) */
 static mode_t current_umask;	/* current umask (which is set to 0 if -p) */
+static bool directories_first;  /* Directory members precede non-directory
+				   ones in the archive. This is detected for
+				   incremental archives only. This variable
+				   helps correctly restore directory
+				   timestamps */
 
 
 /* Status of the permissions of a file that we are extracting.  */
 /* Status of the permissions of a file that we are extracting.  */
 enum permstatus
 enum permstatus
@@ -321,7 +326,19 @@ set_stat (char const *file_name,
    once we stop extracting files into that directory.
    once we stop extracting files into that directory.
    If not restoring permissions, remember to invert the
    If not restoring permissions, remember to invert the
    INVERT_PERMISSIONS bits from the file's current permissions.
    INVERT_PERMISSIONS bits from the file's current permissions.
-   PERMSTATUS specifies the status of the file's permissions.  */
+   PERMSTATUS specifies the status of the file's permissions.
+
+   NOTICE: this works only if the archive has usual member order, i.e.
+   directory, then the files in that directory. Incremental archive have
+   somewhat reversed order: first go subdirectories, then all other
+   members. To help cope with this case the variable directories_first
+   is set by prepare_to_extract.
+
+   If an archive was explicitely created so that its member order is
+   reversed, some directory timestamps can be restored incorrectly,
+   e.g.:
+       tar --no-recursion -cf archive dir dir/subdir dir/subdir/file
+*/
 static void
 static void
 delay_set_stat (char const *file_name, struct tar_stat_info const *st,
 delay_set_stat (char const *file_name, struct tar_stat_info const *st,
 		mode_t invert_permissions, enum permstatus permstatus)
 		mode_t invert_permissions, enum permstatus permstatus)
@@ -615,7 +632,8 @@ extract_dir (char *file_name, int typeflag)
   else if (typeflag == GNUTYPE_DUMPDIR)
   else if (typeflag == GNUTYPE_DUMPDIR)
     skip_member ();
     skip_member ();
 
 
-  mode = (current_stat_info.stat.st_mode | (we_are_root ? 0 : MODE_WXUSR)) & MODE_RWX;
+  mode = (current_stat_info.stat.st_mode |
+	   (we_are_root ? 0 : MODE_WXUSR)) & MODE_RWX;
 
 
   while ((status = mkdir (file_name, mode)))
   while ((status = mkdir (file_name, mode)))
     {
     {
@@ -1089,6 +1107,8 @@ prepare_to_extract (char const *file_name, int typeflag, tar_extractor_t *fun)
     case DIRTYPE:
     case DIRTYPE:
     case GNUTYPE_DUMPDIR:
     case GNUTYPE_DUMPDIR:
       *fun = extract_dir;
       *fun = extract_dir;
+      if (current_stat_info.dumpdir)
+	directories_first = true;
       break;
       break;
 
 
     case GNUTYPE_VOLHDR:
     case GNUTYPE_VOLHDR:
@@ -1180,7 +1200,8 @@ extract_archive (void)
                                  false, absolute_names_option);
                                  false, absolute_names_option);
   if (strip_name_components)
   if (strip_name_components)
     {
     {
-      size_t prefix_len = stripped_prefix_len (file_name, strip_name_components);
+      size_t prefix_len = stripped_prefix_len (file_name,
+					       strip_name_components);
       if (prefix_len == (size_t) -1)
       if (prefix_len == (size_t) -1)
 	{
 	{
 	  skip_member ();
 	  skip_member ();
@@ -1189,8 +1210,12 @@ extract_archive (void)
       file_name += prefix_len;
       file_name += prefix_len;
     }
     }
 
 
-  apply_nonancestor_delayed_set_stat (file_name, 0);
-
+  /* Restore stats for all non-ancestor directories, unless
+     it is an incremental archive.
+     (see NOTICE in the comment to delay_set_stat above) */
+  if (!directories_first)
+    apply_nonancestor_delayed_set_stat (file_name, 0);
+      
   /* Take a safety backup of a previously existing file.  */
   /* Take a safety backup of a previously existing file.  */
 
 
   if (backup_option)
   if (backup_option)
@@ -1204,7 +1229,6 @@ extract_archive (void)
       }
       }
 
 
   /* Extract the archive entry according to its type.  */
   /* Extract the archive entry according to its type.  */
-
   /* KLUDGE */
   /* KLUDGE */
   typeflag = sparse_member_p (&current_stat_info) ?
   typeflag = sparse_member_p (&current_stat_info) ?
                   GNUTYPE_SPARSE : current_header->header.typeflag;
                   GNUTYPE_SPARSE : current_header->header.typeflag;