};
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]));
}
}
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 */
{
struct name_elt *ep;
check_name_alloc ();
- ep = &name_array[names++];
+ ep = &name_array[entries++];
ep->type = NELT_CHDIR;
ep->v.name = name;
}
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;
}
\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)
{
if (*string == 'D')
{
struct name *np;
+ struct tar_stat_info subdir;
+ int subfd;
if (allocated_length <= name_length + string_length)
{
else
child_tail->sibling = np;
child_tail = np;
- add_hierarchy_to_namelist (np, device, false);
+
+ tar_stat_init (&subdir);
+ subdir.parent = st;
+ if (st->fd < 0)
+ {
+ subfd = -1;
+ errno = - st->fd;
+ }
+ else
+ subfd = subfile_open (st, string + 1,
+ open_read_flags | O_DIRECTORY);
+ if (subfd < 0)
+ open_diag (namebuf);
+ else
+ {
+ subdir.fd = subfd;
+ if (fstat (subfd, &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);
+ restore_parent_fd (&subdir);
+ }
+ }
+
+ tar_stat_destroy (&subdir);
}
}
struct name *name;
struct name *next_name, *prev_name = NULL;
int num_names;
- struct stat statbuf;
Hash_table *nametab;
name_gather ();
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)
if (name->name[0] == 0)
continue;
- if (deref_stat (dereference_option, name->name, &statbuf) != 0)
+ tar_stat_init (&st);
+
+ if (deref_stat (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);
+ int dir_fd = openat (chdir_fd, name->name,
+ open_read_flags | O_DIRECTORY);
+ if (dir_fd < 0)
+ open_diag (name->name);
+ else
+ {
+ st.fd = dir_fd;
+ if (fstat (dir_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);
{
struct stat st;
- if (deref_stat (dereference_option, name, &st) != 0)
+ if (deref_stat (name, &st) != 0)
return; /* Will be complained about later */
if (S_ISDIR (st.st_mode))
return;