X-Git-Url: https://git.brokenzipper.com/gitweb?a=blobdiff_plain;f=src%2Fnames.c;h=ba4d509e47ead3bfd99846250f05c623878a11c8;hb=03858cf583ce299b836d8a848967ce290a6bf303;hp=f1e5ab1bee33a8c5af3ea1f7c0482d9dbcdf1cf2;hpb=f6edb92580aa886a2a0189463c19189a050dc62d;p=chaz%2Ftar diff --git a/src/names.c b/src/names.c index f1e5ab1..ba4d509 100644 --- a/src/names.c +++ b/src/names.c @@ -47,8 +47,6 @@ static char *cached_no_such_gname; static uid_t cached_no_such_uid; static gid_t cached_no_such_gid; -static void register_individual_file (char const *name); - /* Given UID, find the corresponding UNAME. */ void uid_to_uname (uid_t uid, char **uname) @@ -226,19 +224,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 +250,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 +270,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 +314,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; @@ -358,8 +358,6 @@ name_next_elt (int change_dirs) { if (unquote_option) unquote_string (name_buffer); - if (incremental_option) - register_individual_file (name_buffer); entry.type = ep->type; entry.v.name = name_buffer; return &entry; @@ -779,17 +777,15 @@ compare_names (struct name const *n1, struct name const *n2) } -/* 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 +813,8 @@ add_hierarchy_to_namelist (struct name *name, dev_t device, bool cmdline) if (*string == 'D') { struct name *np; + struct tar_stat_info subdir; + int subfd; if (allocated_length <= name_length + string_length) { @@ -837,7 +835,38 @@ 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; + 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); } } @@ -900,7 +929,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 +962,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 +975,34 @@ 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 (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); @@ -1099,28 +1147,6 @@ excluded_name (char const *name) { return excluded_file_name (excluded, name + FILE_SYSTEM_PREFIX_LEN (name)); } - -static Hash_table *individual_file_table; - -static void -register_individual_file (char const *name) -{ - struct stat st; - - if (deref_stat (dereference_option, name, &st) != 0) - return; /* Will be complained about later */ - if (S_ISDIR (st.st_mode)) - return; - - hash_string_insert (&individual_file_table, name); -} - -bool -is_individual_file (char const *name) -{ - return hash_string_lookup (individual_file_table, name); -} - /* Return the size of the prefix of FILE_NAME that is removed after