]> Dogcows Code - chaz/tar/blobdiff - src/names.c
tar: more reliable directory traversal when creating archives
[chaz/tar] / src / names.c
index f1e5ab1bee33a8c5af3ea1f7c0482d9dbcdf1cf2..2fc751d81fac59c0faab9515850f7e83891c9c76 100644 (file)
@@ -226,19 +226,20 @@ struct name_elt        /* A name_array element. */
 };
 
 static struct name_elt *name_array;  /* store an array of names */
-static size_t allocated_names;  /* how big is the array? */
-static size_t names;            /* how many entries does it have? */
-static size_t name_index;       /* how many of the entries have we scanned? */
+static size_t allocated_entries; /* how big is the array? */
+static size_t entries;          /* how many entries does it have? */
+static size_t scanned;          /* how many of the entries have we scanned? */
+size_t name_count;              /* how many of the entries are names? */
 
 /* Check the size of name_array, reallocating it as necessary.  */
 static void
 check_name_alloc (void)
 {
-  if (names == allocated_names)
+  if (entries == allocated_entries)
     {
-      if (allocated_names == 0)
-       allocated_names = 10; /* Set initial allocation */
-      name_array = x2nrealloc (name_array, &allocated_names,
+      if (allocated_entries == 0)
+       allocated_entries = 10; /* Set initial allocation */
+      name_array = x2nrealloc (name_array, &allocated_entries,
                               sizeof (name_array[0]));
     }
 }
@@ -251,17 +252,18 @@ name_add_name (const char *name, int matching_flags)
   struct name_elt *ep;
 
   check_name_alloc ();
-  ep = &name_array[names++];
+  ep = &name_array[entries++];
   if (prev_flags != matching_flags)
     {
       ep->type = NELT_FMASK;
       ep->v.matching_flags = matching_flags;
       prev_flags = matching_flags;
       check_name_alloc ();
-      ep = &name_array[names++];
+      ep = &name_array[entries++];
     }
   ep->type = NELT_NAME;
   ep->v.name = name;
+  name_count++;
 }
 
 /* Add to name_array a chdir request for the directory NAME */
@@ -270,7 +272,7 @@ name_add_dir (const char *name)
 {
   struct name_elt *ep;
   check_name_alloc ();
-  ep = &name_array[names++];
+  ep = &name_array[entries++];
   ep->type = NELT_CHDIR;
   ep->v.name = name;
 }
@@ -314,12 +316,12 @@ name_next_elt (int change_dirs)
   const char *source;
   char *cursor;
 
-  while (name_index != names)
+  while (scanned != entries)
     {
       struct name_elt *ep;
       size_t source_len;
 
-      ep = &name_array[name_index++];
+      ep = &name_array[scanned++];
       if (ep->type == NELT_FMASK)
        {
          matching_flags = ep->v.matching_flags;
@@ -779,17 +781,15 @@ compare_names (struct name const *n1, struct name const *n2)
 }
 
 \f
-/* Add all the dirs under NAME, which names a directory, to the namelist.
-   If any of the files is a directory, recurse on the subdirectory.
-   DEVICE is the device not to leave, if the -l option is specified.
-   CMDLINE is true, if the NAME appeared on the command line. */
+/* Add all the dirs under ST to the namelist NAME, descending the
+   directory hierarchy recursively.  */
 
 static void
-add_hierarchy_to_namelist (struct name *name, dev_t device, bool cmdline)
+add_hierarchy_to_namelist (struct tar_stat_info *st, struct name *name)
 {
   const char *buffer;
 
-  name_fill_directory (name, device, cmdline);
+  name->directory = scan_directory (st);
   buffer = directory_contents (name->directory);
   if (buffer)
     {
@@ -817,6 +817,7 @@ add_hierarchy_to_namelist (struct name *name, dev_t device, bool cmdline)
          if (*string == 'D')
            {
              struct name *np;
+             struct tar_stat_info subdir;
 
              if (allocated_length <= name_length + string_length)
                {
@@ -837,7 +838,27 @@ add_hierarchy_to_namelist (struct name *name, dev_t device, bool cmdline)
              else
                child_tail->sibling = np;
              child_tail = np;
-             add_hierarchy_to_namelist (np, device, false);
+
+             tar_stat_init (&subdir);
+             subdir.parent = st;
+             subdir.fd = openat (st->fd, string + 1,
+                                 open_read_flags | O_DIRECTORY);
+             if (subdir.fd < 0)
+               open_diag (namebuf);
+             else if (fstat (subdir.fd, &subdir.stat) != 0)
+               stat_diag (namebuf);
+             else if (! (O_DIRECTORY || S_ISDIR (subdir.stat.st_mode)))
+               {
+                 errno = ENOTDIR;
+                 open_diag (namebuf);
+               }
+             else
+               {
+                 subdir.orig_file_name = xstrdup (namebuf);
+                 add_hierarchy_to_namelist (&subdir, np);
+               }
+
+             tar_stat_destroy (&subdir);
            }
        }
 
@@ -900,7 +921,6 @@ collect_and_sort_names (void)
   struct name *name;
   struct name *next_name, *prev_name = NULL;
   int num_names;
-  struct stat statbuf;
   Hash_table *nametab;
 
   name_gather ();
@@ -934,6 +954,8 @@ collect_and_sort_names (void)
   num_names = 0;
   for (name = namelist; name; name = name->next, num_names++)
     {
+      struct tar_stat_info st;
+
       if (name->found_count || name->directory)
        continue;
       if (name->matching_flags & EXCLUDE_WILDCARDS)
@@ -945,16 +967,29 @@ collect_and_sort_names (void)
       if (name->name[0] == 0)
        continue;
 
-      if (deref_stat (dereference_option, name->name, &statbuf) != 0)
+      tar_stat_init (&st);
+
+      if (deref_stat (dereference_option, name->name, &st.stat) != 0)
        {
          stat_diag (name->name);
          continue;
        }
-      if (S_ISDIR (statbuf.st_mode))
+      if (S_ISDIR (st.stat.st_mode))
        {
-         name->found_count++;
-         add_hierarchy_to_namelist (name, statbuf.st_dev, true);
+         st.fd = open (name->name, open_read_flags | O_DIRECTORY);
+         if (st.fd < 0)
+           open_diag (name->name);
+         else if (fstat (st.fd, &st.stat) != 0)
+           stat_diag (name->name);
+         else if (O_DIRECTORY || S_ISDIR (st.stat.st_mode))
+           {
+             st.orig_file_name = xstrdup (name->name);
+             name->found_count++;
+             add_hierarchy_to_namelist (&st, name);
+           }
        }
+
+      tar_stat_destroy (&st);
     }
 
   namelist = merge_sort (namelist, num_names, compare_names);
This page took 0.027316 seconds and 4 git commands to generate.