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

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