]> Dogcows Code - chaz/tar/blobdiff - src/extract.c
Update copyright year to 2006.
[chaz/tar] / src / extract.c
index 2689f547684a317574927089cb6069f9fc770376..a630bb799dea386b9f4e598a37c6b6f35baad50e 100644 (file)
@@ -1,7 +1,7 @@
 /* Extract files from a tar archive.
 
    Copyright (C) 1988, 1992, 1993, 1994, 1996, 1997, 1998, 1999, 2000,
-   2001, 2003, 2004, 2005 Free Software Foundation, Inc.
+   2001, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
 
    Written by John Gilmore, on 1985-11-19.
 
@@ -115,19 +115,6 @@ extr_init (void)
   same_permissions_option += we_are_root;
   same_owner_option += we_are_root;
 
-  /* Save 'root device' to avoid purging mount points.
-     FIXME: Should the same be done after handling -C option ? */
-  if (one_file_system_option)
-    {
-      struct stat st;
-      char *dir = xgetcwd ();
-
-      if (deref_stat (true, dir, &st))
-       stat_diag (dir);
-      else
-       root_device = st.st_dev;
-    }
-
   /* Option -p clears the kernel umask, so it does not affect proper
      restoration of file permissions.  New intermediate directories will
      comply with umask at start of program.  */
@@ -321,7 +308,19 @@ set_stat (char const *file_name,
    once we stop extracting files into that directory.
    If not restoring permissions, remember to invert the
    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
+   delay_directory_restore_option 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/file1 foo dir/file2
+*/
 static void
 delay_set_stat (char const *file_name, struct tar_stat_info const *st,
                mode_t invert_permissions, enum permstatus permstatus)
@@ -469,7 +468,7 @@ file_newer_p (const char *file_name, struct tar_stat_info *tar_stat)
       return errno != ENOENT;
     }
   if (!S_ISDIR (st.st_mode)
-      && timespec_cmp (tar_stat->mtime, get_stat_mtime (&st)) <= 0)
+      && tar_timespec_cmp (tar_stat->mtime, get_stat_mtime (&st)) <= 0)
     {
       return true;
     }
@@ -609,13 +608,27 @@ extract_dir (char *file_name, int typeflag)
   mode_t mode;
   int interdir_made = 0;
 
+  /* Save 'root device' to avoid purging mount points. */
+  if (one_file_system_option && root_device == 0)
+    {
+      struct stat st;
+      char *dir = xgetcwd ();
+
+      if (deref_stat (true, dir, &st))
+       stat_diag (dir);
+      else
+       root_device = st.st_dev;
+      free (dir);
+    }
+
   if (incremental_option)
     /* Read the entry and delete files that aren't listed in the archive.  */
     purge_directory (file_name);
   else if (typeflag == GNUTYPE_DUMPDIR)
     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)))
     {
@@ -739,17 +752,13 @@ extract_file (char *file_name, int typeflag)
        }
     }
 
+  mv_begin (&current_stat_info);
   if (current_stat_info.is_sparse)
     sparse_extract_file (fd, &current_stat_info, &size);
   else
     for (size = current_stat_info.stat.st_size; size > 0; )
       {
-       if (multi_volume_option)
-         {
-           assign_string (&save_name, current_stat_info.orig_file_name);
-           save_totsize = current_stat_info.stat.st_size;
-           save_sizeleft = size;
-         }
+       mv_size_left (size);
 
        /* Locate data, determine max length writeable, write it,
           block that we have used the data, then check if the write
@@ -783,8 +792,7 @@ extract_file (char *file_name, int typeflag)
 
   skip_file (size);
 
-  if (multi_volume_option)
-    assign_string (&save_name, 0);
+  mv_end ();
 
   /* If writing to stdout, don't try to do anything to the filename;
      it doesn't exist, or we don't want to touch it anyway.  */
@@ -1094,6 +1102,8 @@ prepare_to_extract (char const *file_name, int typeflag, tar_extractor_t *fun)
     case DIRTYPE:
     case GNUTYPE_DUMPDIR:
       *fun = extract_dir;
+      if (current_stat_info.is_dumpdir)
+       delay_directory_restore_option = true;
       break;
 
     case GNUTYPE_VOLHDR:
@@ -1185,7 +1195,8 @@ extract_archive (void)
                                  false, absolute_names_option);
   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)
        {
          skip_member ();
@@ -1194,7 +1205,11 @@ extract_archive (void)
       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 (!delay_directory_restore_option)
+    apply_nonancestor_delayed_set_stat (file_name, 0);
 
   /* Take a safety backup of a previously existing file.  */
 
@@ -1209,7 +1224,6 @@ extract_archive (void)
       }
 
   /* Extract the archive entry according to its type.  */
-
   /* KLUDGE */
   typeflag = sparse_member_p (&current_stat_info) ?
                   GNUTYPE_SPARSE : current_header->header.typeflag;
This page took 0.022831 seconds and 4 git commands to generate.