]> Dogcows Code - chaz/tar/blobdiff - src/extract.c
Fix creation of incremental archives when a subdirectory becomes a mountpoint.
[chaz/tar] / src / extract.c
index c52c9ce8f13ccd24e0dc45e3da45a7633245db8b..e35c8f64d4cff763397aec98abedef3c2ee61ea6 100644 (file)
@@ -23,6 +23,7 @@
 #include <quotearg.h>
 #include <errno.h>
 #include <priv-set.h>
+#include <root-uid.h>
 #include <utimens.h>
 
 #include "common.h"
@@ -110,12 +111,15 @@ struct delayed_link
     /* The next delayed link in the list.  */
     struct delayed_link *next;
 
-    /* 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.  */
+    /* The device, inode number and birthtime of the placeholder.
+       birthtime.tv_nsec is negative if the birthtime is not available.
+       Don't use mtime as this would allow for false matches if some
+       other process removes the placeholder.  Don't use ctime as
+       this would cause race conditions and other screwups, e.g.,
+       when restoring hard-linked symlinks.  */
     dev_t dev;
     ino_t ino;
-    struct timespec ctime;
+    struct timespec birthtime;
 
     /* True if the link is symbolic.  */
     bool is_symlink;
@@ -150,7 +154,7 @@ struct string_list
 void
 extr_init (void)
 {
-  we_are_root = geteuid () == 0;
+  we_are_root = geteuid () == ROOT_UID;
   same_permissions_option += we_are_root;
   same_owner_option += we_are_root;
 
@@ -609,9 +613,18 @@ maybe_recoverable (char *file_name, bool regular, bool *interdir_made)
   switch (e)
     {
     case ELOOP:
+
       /* With open ("symlink", O_NOFOLLOW|...), POSIX says errno == ELOOP,
-        but FreeBSD through at least 8.1 uses errno == EMLINK.  */
+        but some operating systems do not conform to the standard.  */
+#ifdef EFTYPE
+      /* NetBSD uses errno == EFTYPE; see <http://gnats.netbsd.org/43154>.  */
+    case EFTYPE:
+#endif
+      /* FreeBSD 8.1 uses errno == EMLINK.  */
     case EMLINK:
+      /* Tru64 5.1B uses errno == ENOTSUP.  */
+    case ENOTSUP:
+
       if (! regular
          || old_files_option != OVERWRITE_OLD_FILES || dereference_option)
        break;
@@ -630,9 +643,14 @@ maybe_recoverable (char *file_name, bool regular, bool *interdir_made)
 
       switch (old_files_option)
        {
-       case KEEP_OLD_FILES:
+       case SKIP_OLD_FILES:
+         WARNOPT (WARN_EXISTING_FILE,
+                  (0, 0, _("%s: skipping existing file"), file_name));
          return RECOVER_SKIP;
 
+       case KEEP_OLD_FILES:
+         return RECOVER_NO;
+
        case KEEP_NEWER_FILES:
          if (file_newer_p (file_name, stp, &current_stat_info))
            break;
@@ -870,7 +888,8 @@ open_output_file (char const *file_name, int typeflag, mode_t mode,
   /* If O_NOFOLLOW is needed but does not work, check for a symlink
      separately.  There's a race condition, but that cannot be avoided
      on hosts lacking O_NOFOLLOW.  */
-  if (! O_NOFOLLOW && overwriting_old_files && ! dereference_option)
+  if (! HAVE_WORKING_O_NOFOLLOW
+      && overwriting_old_files && ! dereference_option)
     {
       struct stat st;
       if (fstatat (chdir_fd, file_name, &st, AT_SYMLINK_NOFOLLOW) == 0
@@ -981,7 +1000,7 @@ extract_file (char *file_name, int typeflag)
        if (written > size)
          written = size;
        errno = 0;
-       count = full_write (fd, data_block->buffer, written);
+       count = blocking_write (fd, data_block->buffer, written);
        size -= written;
 
        set_next_block_after ((union block *)
@@ -1067,7 +1086,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->ctime = get_stat_ctime (&st);
+      p->birthtime = get_stat_birthtime (&st);
       p->is_symlink = is_symlink;
       if (is_symlink)
        {
@@ -1125,7 +1144,8 @@ extract_link (char *file_name, int typeflag)
              if (ds->change_dir == chdir_current
                  && ds->dev == st1.st_dev
                  && ds->ino == st1.st_ino
-                 && timespec_cmp (ds->ctime, get_stat_ctime (&st1)) == 0)
+                 && (timespec_cmp (ds->birthtime, get_stat_birthtime (&st1))
+                     == 0))
                {
                  struct string_list *p =  xmalloc (offsetof (struct string_list, string)
                                                    + strlen (file_name) + 1);
@@ -1367,7 +1387,7 @@ prepare_to_extract (char const *file_name, int typeflag, tar_extractor_t *fun)
     default:
       WARNOPT (WARN_UNKNOWN_CAST,
               (0, 0,
-               _("%s: Unknown file type `%c', extracted as normal file"),
+               _("%s: Unknown file type '%c', extracted as normal file"),
                quotearg_colon (file_name), typeflag));
       *fun = extract_file;
     }
@@ -1491,7 +1511,7 @@ apply_delayed_links (void)
          if (fstatat (chdir_fd, source, &st, AT_SYMLINK_NOFOLLOW) == 0
              && st.st_dev == ds->dev
              && st.st_ino == ds->ino
-             && timespec_cmp (get_stat_ctime (&st), ds->ctime) == 0)
+             && timespec_cmp (get_stat_birthtime (&st), ds->birthtime) == 0)
            {
              /* Unlink the placeholder, then create a hard link if possible,
                 a symbolic link otherwise.  */
This page took 0.029172 seconds and 4 git commands to generate.