Blame SOURCES/tar-1.26-fix-symlink-eating-bug.patch

a4d85a
diff --git a/gnu/stat-time.h b/gnu/stat-time.h
a4d85a
index 1dc4098..7b8428e 100644
a4d85a
--- a/gnu/stat-time.h
a4d85a
+++ b/gnu/stat-time.h
a4d85a
@@ -144,7 +144,7 @@ get_stat_mtime (struct stat const *st)
a4d85a
 }
a4d85a
 
a4d85a
 /* Return *ST's birth time, if available; otherwise return a value
a4d85a
-   with negative tv_nsec.  */
a4d85a
+   with tv_sec and tv_nsec both equal to -1.  */
a4d85a
 static inline struct timespec
a4d85a
 get_stat_birthtime (struct stat const *st)
a4d85a
 {
a4d85a
@@ -163,7 +163,7 @@ get_stat_birthtime (struct stat const *st)
a4d85a
   t.tv_sec = st->st_ctime;
a4d85a
   t.tv_nsec = 0;
a4d85a
 #else
a4d85a
-  /* Birth time is not supported.  Set tv_sec to avoid undefined behavior.  */
a4d85a
+  /* Birth time is not supported.  */
a4d85a
   t.tv_sec = -1;
a4d85a
   t.tv_nsec = -1;
a4d85a
   /* Avoid a "parameter unused" warning.  */
a4d85a
@@ -177,10 +177,12 @@ get_stat_birthtime (struct stat const *st)
a4d85a
      using zero.  Attempt to work around this problem.  Alas, this can
a4d85a
      report failure even for valid time stamps.  Also, NetBSD
a4d85a
      sometimes returns junk in the birth time fields; work around this
a4d85a
-     bug if it it is detected.  There's no need to detect negative
a4d85a
-     tv_nsec junk as negative tv_nsec already indicates an error.  */
a4d85a
-  if (t.tv_sec == 0 || 1000000000 <= t.tv_nsec)
a4d85a
-    t.tv_nsec = -1;
a4d85a
+     bug if it is detected.  */
a4d85a
+  if (! (t.tv_sec && 0 <= t.tv_nsec && t.tv_nsec < 1000000000))
a4d85a
+    {
a4d85a
+      t.tv_sec = -1;
a4d85a
+      t.tv_nsec = -1;
a4d85a
+    }
a4d85a
 #endif
a4d85a
 
a4d85a
   return t;
a4d85a
diff --git a/src/extract.c b/src/extract.c
a4d85a
index 340beea..3afb95d 100644
a4d85a
--- a/src/extract.c
a4d85a
+++ b/src/extract.c
a4d85a
@@ -119,12 +119,15 @@ struct delayed_link
a4d85a
     /* The next delayed link in the list.  */
a4d85a
     struct delayed_link *next;
a4d85a
 
a4d85a
-    /* The device, inode number and ctime of the placeholder.  Use
a4d85a
-       ctime, not mtime, to make false matches less likely if some
a4d85a
-       other process removes the placeholder.  */
a4d85a
+    /* The device, inode number and birthtime of the placeholder.
a4d85a
+       birthtime.tv_nsec is negative if the birthtime is not available.
a4d85a
+       Don't use mtime as this would allow for false matches if some
a4d85a
+       other process removes the placeholder.  Don't use ctime as
a4d85a
+       this would cause race conditions and other screwups, e.g.,
a4d85a
+       when restoring hard-linked symlinks.  */
a4d85a
     dev_t dev;
a4d85a
     ino_t ino;
a4d85a
-    struct timespec ctime;
a4d85a
+    struct timespec birthtime;
a4d85a
 
a4d85a
     /* True if the link is symbolic.  */
a4d85a
     bool is_symlink;
a4d85a
@@ -1200,7 +1203,7 @@ create_placeholder_file (char *file_name, bool is_symlink, bool *interdir_made)
a4d85a
       delayed_link_head = p;
a4d85a
       p->dev = st.st_dev;
a4d85a
       p->ino = st.st_ino;
a4d85a
-      p->ctime = get_stat_ctime (&st);
a4d85a
+      p->birthtime = get_stat_birthtime (&st);
a4d85a
       p->is_symlink = is_symlink;
a4d85a
       if (is_symlink)
a4d85a
 	{
a4d85a
@@ -1265,7 +1268,8 @@ extract_link (char *file_name, int typeflag)
a4d85a
 	      if (ds->change_dir == chdir_current
a4d85a
 		  && ds->dev == st1.st_dev
a4d85a
 		  && ds->ino == st1.st_ino
a4d85a
-		  && timespec_cmp (ds->ctime, get_stat_ctime (&st1)) == 0)
a4d85a
+		  && (timespec_cmp (ds->birthtime, get_stat_birthtime (&st1))
a4d85a
+		      == 0))
a4d85a
 		{
a4d85a
 		  struct string_list *p =  xmalloc (offsetof (struct string_list, string)
a4d85a
 						    + strlen (file_name) + 1);
a4d85a
@@ -1638,7 +1642,7 @@ apply_delayed_links (void)
a4d85a
 	  if (fstatat (chdir_fd, source, &st, AT_SYMLINK_NOFOLLOW) == 0
a4d85a
 	      && st.st_dev == ds->dev
a4d85a
 	      && st.st_ino == ds->ino
a4d85a
-	      && timespec_cmp (get_stat_ctime (&st), ds->ctime) == 0)
a4d85a
+	      && timespec_cmp (get_stat_birthtime (&st), ds->birthtime) == 0)
a4d85a
 	    {
a4d85a
 	      /* Unlink the placeholder, then create a hard link if possible,
a4d85a
 		 a symbolic link otherwise.  */