X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;f=src%2Fnames.c;h=03eece6655a44b629ab25ec99ee0008548e53206;hb=85cf996677770c517b4b6c138155c79d7c86b28f;hp=dcad3d76b709f228055a789353d3793b76abbd26;hpb=6c1654791d7a412f57fae3c944dd540ecd35d239;p=chaz%2Ftar diff --git a/src/names.c b/src/names.c index dcad3d7..03eece6 100644 --- a/src/names.c +++ b/src/names.c @@ -1,7 +1,7 @@ /* Various processing of names. Copyright (C) 1988, 1992, 1994, 1996, 1997, 1998, 1999, 2000, 2001, - 2003, 2004 Free Software Foundation, Inc. + 2003, 2004, 2005 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the @@ -15,9 +15,9 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., - 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include "system.h" +#include #include #include @@ -56,6 +56,8 @@ 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) @@ -64,7 +66,7 @@ uid_to_uname (uid_t uid, char **uname) if (uid != 0 && uid == cached_no_such_uid) { - *uname = strdup (""); + *uname = xstrdup (""); return; } @@ -79,11 +81,11 @@ uid_to_uname (uid_t uid, char **uname) else { cached_no_such_uid = uid; - *uname = strdup (""); + *uname = xstrdup (""); return; } } - *uname = strdup (cached_uname); + *uname = xstrdup (cached_uname); } /* Given GID, find the corresponding GNAME. */ @@ -94,7 +96,7 @@ gid_to_gname (gid_t gid, char **gname) if (gid != 0 && gid == cached_no_such_gid) { - *gname = strdup (""); + *gname = xstrdup (""); return; } @@ -109,11 +111,11 @@ gid_to_gname (gid_t gid, char **gname) else { cached_no_such_gid = gid; - *gname = strdup (""); + *gname = xstrdup (""); return; } } - *gname = strdup (cached_gname); + *gname = xstrdup (cached_gname); } /* Given UNAME, set the corresponding UID and return 1, or else, return 0. */ @@ -207,10 +209,10 @@ name_add (const char *name) } name_array[names++] = name; } + /* Names from external name file. */ -static FILE *name_file; /* file to read names from */ static char *name_buffer; /* buffer to hold the current file name */ static size_t name_buffer_length; /* allocated length of name_buffer */ @@ -231,17 +233,6 @@ name_init (void) { name_buffer = xmalloc (NAME_FIELD_SIZE + 2); name_buffer_length = NAME_FIELD_SIZE; - - if (files_from_option) - { - if (!strcmp (files_from_option, "-")) - { - request_stdin ("-T"); - name_file = stdin; - } - else if (name_file = fopen (files_from_option, "r"), !name_file) - open_fatal (files_from_option); - } } void @@ -251,47 +242,6 @@ name_term (void) free (name_array); } -/* Read the next filename from name_file and null-terminate it. Put - it into name_buffer, reallocating and adjusting name_buffer_length - if necessary. Return 0 at end of file, 1 otherwise. */ -static int -read_name_from_file (void) -{ - int character; - size_t counter = 0; - - /* FIXME: getc may be called even if character was EOF the last time here. */ - - /* FIXME: This + 2 allocation might serve no purpose. */ - - while (character = getc (name_file), - character != EOF && character != filename_terminator) - { - if (counter == name_buffer_length) - { - if (name_buffer_length * 2 < name_buffer_length) - xalloc_die (); - name_buffer_length *= 2; - name_buffer = xrealloc (name_buffer, name_buffer_length + 2); - } - name_buffer[counter++] = character; - } - - if (counter == 0 && character == EOF) - return 0; - - if (counter == name_buffer_length) - { - if (name_buffer_length * 2 < name_buffer_length) - xalloc_die (); - name_buffer_length *= 2; - name_buffer = xrealloc (name_buffer, name_buffer_length + 2); - } - name_buffer[counter] = '\0'; - - return 1; -} - /* Get the next name from ARGV or the file of names. Result is in static storage and can't be relied upon across two calls. @@ -309,37 +259,25 @@ name_next (int change_dirs) if (filename_terminator == '\0') change_dirs = 0; - while (1) + while (name_index != names) { - /* Get a name, either from file or from saved arguments. */ - - if (name_index == names) - { - if (! name_file) - break; - if (! read_name_from_file ()) - break; - } - else + size_t source_len; + source = name_array[name_index++]; + source_len = strlen (source); + if (name_buffer_length < source_len) { - size_t source_len; - source = name_array[name_index++]; - source_len = strlen (source); - if (name_buffer_length < source_len) + do { - do - { - name_buffer_length *= 2; - if (! name_buffer_length) - xalloc_die (); - } - while (name_buffer_length < source_len); - - free (name_buffer); - name_buffer = xmalloc (name_buffer_length + 2); + name_buffer_length *= 2; + if (! name_buffer_length) + xalloc_die (); } - strcpy (name_buffer, source); + while (name_buffer_length < source_len); + + free (name_buffer); + name_buffer = xmalloc (name_buffer_length + 2); } + strcpy (name_buffer, source); /* Zap trailing slashes. */ @@ -357,28 +295,17 @@ name_next (int change_dirs) chdir_flag = 1; else { - unquote_string (name_buffer); + if (unquote_option) + unquote_string (name_buffer); + if (incremental_option) + register_individual_file (name_buffer); return name_buffer; } } - /* No more names in file. */ - - if (name_file && chdir_flag) - FATAL_ERROR ((0, 0, _("Missing file name after -C"))); - return 0; } -/* Close the name file, if any. */ -void -name_close (void) -{ - if (name_file && name_file != stdin) - if (fclose (name_file) != 0) - close_error (name_buffer); -} - /* Gather names in a list for scanning. Could hash them later if we really care. @@ -502,7 +429,8 @@ addname (char const *string, int change_dir) name->firstch = 1; /* assume first char is literal */ name->change_dir = change_dir; name->dir_contents = 0; - + name->explicit = 1; + if (string && is_pattern (string)) { name->regexp = 1; @@ -515,10 +443,10 @@ addname (char const *string, int change_dir) return name; } -/* Find a match for PATH (whose string length is LENGTH) in the name +/* Find a match for FILE_NAME (whose string length is LENGTH) in the name list. */ static struct name * -namelist_match (char const *path, size_t length) +namelist_match (char const *file_name, size_t length, bool exact) { struct name *p; @@ -526,47 +454,49 @@ namelist_match (char const *path, size_t length) { /* If first chars don't match, quick skip. */ - if (p->firstch && p->name[0] != path[0]) + if (p->firstch && p->name[0] != file_name[0]) continue; if (p->regexp - ? fnmatch (p->name, path, recursion_option) == 0 + ? fnmatch (p->name, file_name, recursion_option) == 0 + : exact ? (p->length == length + && memcmp (file_name, p->name, length) == 0) : (p->length <= length - && (path[p->length] == '\0' - || (ISSLASH (path[p->length]) && recursion_option)) - && memcmp (path, p->name, p->length) == 0)) + && (file_name[p->length] == '\0' + || (ISSLASH (file_name[p->length]) && recursion_option)) + && memcmp (file_name, p->name, p->length) == 0)) return p; } return 0; } -/* Return true if and only if name PATH (from an archive) matches any +/* Return true if and only if name FILE_NAME (from an archive) matches any name from the namelist. */ int -name_match (const char *path) +name_match (const char *file_name) { - size_t length = strlen (path); + size_t length = strlen (file_name); while (1) { struct name *cursor = namelist; if (!cursor) - return ! files_from_option; + return 1; if (cursor->fake) { chdir_do (cursor->change_dir); namelist = 0; nametail = &namelist; - return ! files_from_option; + return 1; } - cursor = namelist_match (path, length); + cursor = namelist_match (file_name, length, false); if (cursor) { - if (!(ISSLASH (path[cursor->length]) && recursion_option) + if (!(ISSLASH (file_name[cursor->length]) && recursion_option) || cursor->found_count == 0) cursor->found_count++; /* remember it matched */ if (starting_file_option) @@ -612,6 +542,8 @@ all_names_found (struct tar_stat_info *p) struct name const *cursor; size_t len; + if (test_label_option) + return true; if (!p->file_name || occurrence_option == 0 || p->had_trailing_slash) return false; len = strlen (p->file_name); @@ -750,8 +682,8 @@ compare_names (struct name const *n1, struct name const *n2) static void add_hierarchy_to_namelist (struct name *name, dev_t device) { - char *path = name->name; - char *buffer = get_directory_contents (path, device); + char *file_name = name->name; + char *buffer = get_directory_contents (file_name, device); if (! buffer) name->dir_contents = "\0\0\0\0"; @@ -768,7 +700,7 @@ add_hierarchy_to_namelist (struct name *name, dev_t device) int change_dir = name->change_dir; name->dir_contents = buffer; - strcpy (namebuf, path); + strcpy (namebuf, file_name); if (! ISSLASH (namebuf[name_length - 1])) { namebuf[name_length++] = '/'; @@ -780,6 +712,8 @@ add_hierarchy_to_namelist (struct name *name, dev_t device) string_length = strlen (string); if (*string == 'D') { + struct name *np; + if (allocated_length <= name_length + string_length) { do @@ -793,8 +727,9 @@ add_hierarchy_to_namelist (struct name *name, dev_t device) namebuf = xrealloc (namebuf, allocated_length + 1); } strcpy (namebuf + name_length, string + 1); - add_hierarchy_to_namelist (addname (namebuf, change_dir), - device); + np = addname (namebuf, change_dir); + np->explicit = 0; + add_hierarchy_to_namelist (np, device); } } @@ -854,18 +789,22 @@ collect_and_sort_names (void) name->found_count = 0; } -/* This is like name_match, except that it returns a pointer to the - name it matched, and doesn't set FOUND in structure. The caller - will have to do that if it wants to. Oh, and if the namelist is - empty, it returns null, unlike name_match, which returns TRUE. */ +/* This is like name_match, except that + 1. It returns a pointer to the name it matched, and doesn't set FOUND + in structure. The caller will have to do that if it wants to. + 2. If the namelist is empty, it returns null, unlike name_match, which + returns TRUE. + 3. The second argument (EXACT) controls matching algorithm. If it + is TRUE, the exact matching is used. However, regular expressions are + always matched as such, no matter what the value of EXACT is. */ struct name * -name_scan (const char *path) +name_scan (const char *file_name, bool exact) { - size_t length = strlen (path); + size_t length = strlen (file_name); while (1) { - struct name *cursor = namelist_match (path, length); + struct name *cursor = namelist_match (file_name, length, exact); if (cursor) return cursor; @@ -916,18 +855,18 @@ blank_name_list (void) name->found_count = 0; } -/* Yield a newly allocated file name consisting of PATH concatenated to - NAME, with an intervening slash if PATH does not already end in one. */ +/* Yield a newly allocated file name consisting of FILE_NAME concatenated to + NAME, with an intervening slash if FILE_NAME does not already end in one. */ char * -new_name (const char *path, const char *name) +new_name (const char *file_name, const char *name) { - size_t pathlen = strlen (path); + size_t file_name_len = strlen (file_name); size_t namesize = strlen (name) + 1; - int slash = pathlen && ! ISSLASH (path[pathlen - 1]); - char *buffer = xmalloc (pathlen + slash + namesize); - memcpy (buffer, path, pathlen); - buffer[pathlen] = '/'; - memcpy (buffer + pathlen + slash, name, namesize); + int slash = file_name_len && ! ISSLASH (file_name[file_name_len - 1]); + char *buffer = xmalloc (file_name_len + slash + namesize); + memcpy (buffer, file_name, file_name_len); + buffer[file_name_len] = '/'; + memcpy (buffer + file_name_len + slash, name, namesize); return buffer; } @@ -935,54 +874,7 @@ new_name (const char *path, const char *name) bool excluded_name (char const *name) { - return excluded_filename (excluded, name + FILESYSTEM_PREFIX_LEN (name)); -} - -/* Hash tables of strings. */ - -/* Calculate the hash of a string. */ -static unsigned -hash_string_hasher (void const *name, unsigned n_buckets) -{ - return hash_string (name, n_buckets); -} - -/* Compare two strings for equality. */ -static bool -hash_string_compare (void const *name1, void const *name2) -{ - return strcmp (name1, name2) == 0; -} - -/* Return zero if TABLE contains a copy of STRING; otherwise, insert a - copy of STRING to TABLE and return 1. */ -static bool -hash_string_insert (Hash_table **table, char const *string) -{ - Hash_table *t = *table; - char *s = xstrdup (string); - char *e; - - if (! ((t - || (*table = t = hash_initialize (0, 0, hash_string_hasher, - hash_string_compare, 0))) - && (e = hash_insert (t, s)))) - xalloc_die (); - - if (e == s) - return 1; - else - { - free (s); - return 0; - } -} - -/* Return 1 if TABLE contains STRING. */ -static bool -hash_string_lookup (Hash_table const *table, char const *string) -{ - return table && hash_lookup (table, string); + return excluded_file_name (excluded, name + FILE_SYSTEM_PREFIX_LEN (name)); } /* Names to avoid dumping. */ @@ -1001,89 +893,39 @@ is_avoided_name (char const *name) { return hash_string_lookup (avoided_name_table, name); } + -/* Return a safer suffix of FILE_NAME, or "." if it has no safer - suffix. Check for fully specified file names and other atrocities. - Warn the user if we do not return NAME. If LINK_TARGET is 1, - FILE_NAME is the target of a hard link, not a member name. */ +static Hash_table *individual_file_table; -char * -safer_name_suffix (char const *file_name, bool link_target) +static void +register_individual_file (char const *name) { - char const *p; - - if (absolute_names_option) - p = file_name; - else - { - /* Skip file system prefixes, leading pathnames that contain - "..", and leading slashes. */ - - size_t prefix_len = FILESYSTEM_PREFIX_LEN (file_name); - - for (p = file_name + prefix_len; *p; ) - { - if (p[0] == '.' && p[1] == '.' && (ISSLASH (p[2]) || !p[2])) - prefix_len = p + 2 - file_name; + struct stat st; - do - { - char c = *p++; - if (ISSLASH (c)) - break; - } - while (*p); - } - - for (p = file_name + prefix_len; ISSLASH (*p); p++) - continue; - prefix_len = p - file_name; + if (deref_stat (dereference_option, name, &st) != 0) + return; /* Will be complained about later */ + if (S_ISDIR (st.st_mode)) + return; - if (prefix_len) - { - static Hash_table *prefix_table[2]; - char *prefix = alloca (prefix_len + 1); - memcpy (prefix, file_name, prefix_len); - prefix[prefix_len] = '\0'; - - if (hash_string_insert (&prefix_table[link_target], prefix)) - { - static char const *const diagnostic[] = - { - N_("Removing leading `%s' from member names"), - N_("Removing leading `%s' from hard link targets") - }; - WARN ((0, 0, _(diagnostic[link_target]), prefix)); - } - } - } - - if (! *p) - { - if (p == file_name) - { - static char const *const diagnostic[] = - { - N_("Substituting `.' for empty member name"), - N_("Substituting `.' for empty hard link target") - }; - WARN ((0, 0, _(diagnostic[link_target]))); - } - - p = "."; - } + hash_string_insert (&individual_file_table, name); +} - return (char *) p; +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 - stripping NUM leading path name components. NUM must be + stripping NUM leading file name components. NUM must be positive. */ size_t stripped_prefix_len (char const *file_name, size_t num) { - char const *p = file_name + FILESYSTEM_PREFIX_LEN (file_name); + char const *p = file_name + FILE_SYSTEM_PREFIX_LEN (file_name); while (ISSLASH (*p)) p++; while (*p) @@ -1101,11 +943,11 @@ stripped_prefix_len (char const *file_name, size_t num) return -1; } -/* Return nonzero if NAME contains ".." as a path name component. */ +/* Return nonzero if NAME contains ".." as a file name component. */ bool contains_dot_dot (char const *name) { - char const *p = name + FILESYSTEM_PREFIX_LEN (name); + char const *p = name + FILE_SYSTEM_PREFIX_LEN (name); for (;; p++) {