]> Dogcows Code - chaz/tar/blobdiff - src/extract.c
tar: use ctime, not mtime, when checking placeholders
[chaz/tar] / src / extract.c
index 0ad5545426d611ae6cd88058cb171395fb4ead81..dad7746e0a702cc960ebc953358258f617ce2ed1 100644 (file)
@@ -80,10 +80,12 @@ struct delayed_link
     /* The next delayed link in the list.  */
     struct delayed_link *next;
 
-    /* The device, inode number and last-modified time of the placeholder.  */
+    /* The device, inode number and ctime of the placeholder.  Use
+       ctime, not mtime, to make false matches less likely if some
+       other process removes the placeholder.  */
     dev_t dev;
     ino_t ino;
-    struct timespec mtime;
+    struct timespec ctime;
 
     /* True if the link is symbolic.  */
     bool is_symlink;
@@ -144,7 +146,7 @@ set_mode (char const *file_name,
          char typeflag)
 {
   mode_t mode;
-  bool failed;
+  int chmod_errno;
 
   if (0 < same_permissions_option
       && permstatus != INTERDIR_PERMSTATUS)
@@ -187,18 +189,24 @@ set_mode (char const *file_name,
       mode = cur_info->st_mode ^ invert_permissions;
     }
 
-  failed = chmod (file_name, mode) != 0;
-  if (failed && errno == EPERM)
+  chmod_errno = chmod (file_name, mode) == 0 ? 0 : errno;
+  if (chmod_errno == EPERM && (mode & S_ISUID) != 0)
     {
-      /* On Solaris, chmod may fail if we don't have PRIV_ALL.  */
+      /* On Solaris, chmod may fail if we don't have PRIV_ALL, because
+        setuid-root files would otherwise be a backdoor.  See
+        http://opensolaris.org/jive/thread.jspa?threadID=95826
+        (2009-09-03).  */
       if (priv_set_restore_linkdir () == 0)
        {
-         failed = chmod (file_name, mode) != 0;
+         chmod_errno = chmod (file_name, mode) == 0 ? 0 : errno;
          priv_set_remove_linkdir ();
        }
     }
-  if (failed)
-    chmod_error_details (file_name, mode);
+  if (chmod_errno)
+    {
+      errno = chmod_errno;
+      chmod_error_details (file_name, mode);
+    }
 }
 
 /* Check time after successfully setting FILE_NAME's time stamp to T.  */
@@ -918,7 +926,7 @@ create_placeholder_file (char *file_name, bool is_symlink, bool *interdir_made)
       delayed_link_head = p;
       p->dev = st.st_dev;
       p->ino = st.st_ino;
-      p->mtime = get_stat_mtime (&st);
+      p->ctime = get_stat_ctime (&st);
       p->is_symlink = is_symlink;
       if (is_symlink)
        {
@@ -984,7 +992,7 @@ extract_link (char *file_name, int typeflag)
            for (; ds; ds = ds->next)
              if (ds->dev == st1.st_dev
                  && ds->ino == st1.st_ino
-                 && timespec_cmp (ds->mtime, get_stat_mtime (&st1)) == 0)
+                 && timespec_cmp (ds->ctime, get_stat_ctime (&st1)) == 0)
                {
                  struct string_list *p =  xmalloc (offsetof (struct string_list, string)
                                                    + strlen (file_name) + 1);
@@ -1271,9 +1279,6 @@ extract_archive (void)
 
   fatal_exit_hook = extract_finish;
 
-  /* Try to disable the ability to unlink a directory.  */
-  priv_set_remove_linkdir ();
-
   set_next_block_after (current_header);
 
   if (!current_stat_info.file_name[0]
@@ -1344,7 +1349,7 @@ apply_delayed_links (void)
          if (lstat (source, &st) == 0
              && st.st_dev == ds->dev
              && st.st_ino == ds->ino
-             && timespec_cmp (get_stat_mtime (&st), ds->mtime) == 0)
+             && timespec_cmp (get_stat_ctime (&st), ds->ctime) == 0)
            {
              /* Unlink the placeholder, then create a hard link if possible,
                 a symbolic link otherwise.  */
This page took 0.025786 seconds and 4 git commands to generate.