cherry-pick an upstream commit at Paul Eggert's suggestion
[debian/tar] / debian / patches / link-extraction-fix
1 Description: link extraction fix
2  tar (1.26+dfsg-6) unstable; urgency=low
3  .
4    * cherry-pick upstream commit at Paul Eggert's suggestion to address link
5      extraction issue, closes: #452365
6 Author: Bdale Garbee <bdale@gag.com>
7 Bug-Debian: http://bugs.debian.org/452365
8
9 --- tar-1.26+dfsg.orig/src/extract.c
10 +++ tar-1.26+dfsg/src/extract.c
11 @@ -110,12 +110,15 @@ struct delayed_link
12      /* The next delayed link in the list.  */
13      struct delayed_link *next;
14  
15 -    /* The device, inode number and ctime of the placeholder.  Use
16 -       ctime, not mtime, to make false matches less likely if some
17 -       other process removes the placeholder.  */
18 +    /* The device, inode number and birthtime of the placeholder.
19 +       birthtime.tv_nsec is negative if the birthtime is not available.
20 +       Don't use mtime as this would allow for false matches if some
21 +       other process removes the placeholder.  Don't use ctime as
22 +       this would cause race conditions and other screwups, e.g.,
23 +       when restoring hard-linked symlinks.  */
24      dev_t dev;
25      ino_t ino;
26 -    struct timespec ctime;
27 +    struct timespec birthtime;
28  
29      /* True if the link is symbolic.  */
30      bool is_symlink;
31 @@ -268,6 +271,15 @@ set_mode (char const *file_name,
32      }
33  }
34  
35 +/* Return true if A and B are the same birthtimes.
36 +   Unavailable birthtimes, which have negative tv_nsec members,
37 +   all compare equal to each other.  */
38 +static bool
39 +same_birthtime (struct timespec a, struct timespec b)
40 +{
41 +  return (a.tv_nsec == b.tv_nsec && (a.tv_nsec < 0 || a.tv_sec == b.tv_sec));
42 +}
43 +
44  /* Check time after successfully setting FILE_NAME's time stamp to T.  */
45  static void
46  check_time (char const *file_name, struct timespec t)
47 @@ -1076,7 +1088,7 @@ create_placeholder_file (char *file_name
48        delayed_link_head = p;
49        p->dev = st.st_dev;
50        p->ino = st.st_ino;
51 -      p->ctime = get_stat_ctime (&st);
52 +      p->birthtime = get_stat_birthtime (&st);
53        p->is_symlink = is_symlink;
54        if (is_symlink)
55         {
56 @@ -1134,7 +1146,7 @@ extract_link (char *file_name, int typef
57               if (ds->change_dir == chdir_current
58                   && ds->dev == st1.st_dev
59                   && ds->ino == st1.st_ino
60 -                 && timespec_cmp (ds->ctime, get_stat_ctime (&st1)) == 0)
61 +                 && same_birthtime (ds->birthtime, get_stat_birthtime (&st1)))
62                 {
63                   struct string_list *p =  xmalloc (offsetof (struct string_list, string)
64                                                     + strlen (file_name) + 1);
65 @@ -1500,7 +1512,7 @@ apply_delayed_links (void)
66           if (fstatat (chdir_fd, source, &st, AT_SYMLINK_NOFOLLOW) == 0
67               && st.st_dev == ds->dev
68               && st.st_ino == ds->ino
69 -             && timespec_cmp (get_stat_ctime (&st), ds->ctime) == 0)
70 +             && same_birthtime (get_stat_birthtime (&st), ds->birthtime))
71             {
72               /* Unlink the placeholder, then create a hard link if possible,
73                  a symbolic link otherwise.  */