]> Dogcows Code - chaz/tar/blobdiff - src/create.c
tar: fix symlink race and symlink transform bug
[chaz/tar] / src / create.c
index 24920db37b967b99ea803d1418c7cb02141100cd..7cdc9782895a988c36764e19cd4b8b191a070638 100644 (file)
@@ -22,6 +22,7 @@
 
 #include <system.h>
 
+#include <areadlink.h>
 #include <quotearg.h>
 
 #include "common.h"
@@ -706,7 +707,7 @@ write_extended (bool global, struct tar_stat_info *st, union block *old_header)
     {
       type = XHDTYPE;
       p = xheader_xhdr_name (st);
-      t = st->stat.st_mtime;
+      t = set_mtime_option ? mtime_option.tv_sec : st->stat.st_mtime;
     }
   xheader_write (type, p, t, &st->xhdr);
   free (p);
@@ -1113,6 +1114,8 @@ dump_dir0 (struct tar_stat_info *st, char const *directory)
   if (!blk)
     return;
 
+  info_attach_exclist (st);
+
   if (incremental_option && archive_format != POSIX_FORMAT)
     blk->header.typeflag = GNUTYPE_DUMPDIR;
   else /* if (standard_option) */
@@ -1210,7 +1213,7 @@ dump_dir0 (struct tar_stat_info *st, char const *directory)
                    name_buf = xrealloc (name_buf, name_size + 1);
                  }
                strcpy (name_buf + name_len, entry);
-               if (!excluded_name (name_buf))
+               if (!excluded_name (name_buf, st))
                  dump_file (st, entry, name_buf);
              }
 
@@ -1288,7 +1291,7 @@ get_directory_entries (struct tar_stat_info *st)
   while (! (st->dirstream = fdopendir (st->fd)))
     if (! open_failure_recover (st))
       return 0;
-  return streamsavedir (st->dirstream);
+  return streamsavedir (st->dirstream, savedir_sort_order);
 }
 
 /* Dump the directory ST.  Return true if successful, false (emitting
@@ -1339,12 +1342,12 @@ create_archive (void)
       collect_and_sort_names ();
 
       while ((p = name_from_list ()) != NULL)
-       if (!excluded_name (p->name))
+       if (!excluded_name (p->name, NULL))
          dump_file (0, p->name, p->name);
 
       blank_name_list ();
       while ((p = name_from_list ()) != NULL)
-       if (!excluded_name (p->name))
+       if (!excluded_name (p->name, NULL))
          {
            struct tar_stat_info st;
            size_t plen = strlen (p->name);
@@ -1358,7 +1361,7 @@ create_archive (void)
            if (! ISSLASH (buffer[plen - 1]))
              buffer[plen++] = DIRECTORY_SEPARATOR;
            tar_stat_init (&st);
-           q = directory_contents (gnu_list_name->directory);
+           q = directory_contents (p->directory);
            if (q)
              while (*q)
                {
@@ -1401,7 +1404,7 @@ create_archive (void)
     {
       const char *name;
       while ((name = name_next (1)) != NULL)
-       if (!excluded_name (name))
+       if (!excluded_name (name, NULL))
          dump_file (0, name, name);
     }
 
@@ -1470,8 +1473,8 @@ dump_hard_link (struct tar_stat_info *st)
          /* We found a link.  */
          char const *link_name = safer_name_suffix (duplicate->name, true,
                                                     absolute_names_option);
-
-         duplicate->nlink--;
+         if (duplicate->nlink)
+           duplicate->nlink--;
 
          block_ordinal = current_block_ordinal ();
          assign_string (&st->link_name, link_name);
@@ -1835,22 +1838,17 @@ dump_file0 (struct tar_stat_info *st, char const *name, char const *p)
 #ifdef HAVE_READLINK
   else if (S_ISLNK (st->stat.st_mode))
     {
-      char *buffer;
-      int size;
-      size_t linklen = st->stat.st_size;
-      if (linklen != st->stat.st_size || linklen + 1 == 0)
-       xalloc_die ();
-      buffer = (char *) alloca (linklen + 1);
-      size = readlinkat (parentfd, name, buffer, linklen + 1);
-      if (size < 0)
+      st->link_name = areadlinkat_with_size (parentfd, name, st->stat.st_size);
+      if (!st->link_name)
        {
+         if (errno == ENOMEM)
+           xalloc_die ();
          file_removed_diag (p, top_level, readlink_diag);
          return;
        }
-      buffer[size] = '\0';
-      assign_string (&st->link_name, buffer);
       transform_name (&st->link_name, XFORM_SYMLINK);
-      if (NAME_FIELD_SIZE - (archive_format == OLDGNU_FORMAT) < size)
+      if (NAME_FIELD_SIZE - (archive_format == OLDGNU_FORMAT)
+         < strlen (st->link_name))
        write_long_link (st);
 
       xattrs_selinux_get (parentfd, name, st, 0);
This page took 0.0228080000000001 seconds and 4 git commands to generate.