X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;f=src%2Fnames.c;h=a5f2f7e70f346ff1c24e757501fb63790fdfad46;hb=2433f6813ec6a0c00e6c49b8f38725cd4a78c66c;hp=a8a03bb6434df6945826a78aab8474eab1f828a3;hpb=91493ea9b62a24ab139eedd4c919e4fcda9750c3;p=chaz%2Ftar diff --git a/src/names.c b/src/names.c index a8a03bb..a5f2f7e 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 Free Software Foundation, Inc. + 2003, 2004 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 @@ -17,12 +17,10 @@ with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#include "system.h" +#include #include -#include #include -#include #include #include "common.h" @@ -58,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) @@ -120,7 +120,7 @@ gid_to_gname (gid_t gid, char **gname) /* Given UNAME, set the corresponding UID and return 1, or else, return 0. */ int -uname_to_uid (char *uname, uid_t *uidp) +uname_to_uid (char const *uname, uid_t *uidp) { struct passwd *passwd; @@ -150,7 +150,7 @@ uname_to_uid (char *uname, uid_t *uidp) /* Given GNAME, set the corresponding GID and return 1, or else, return 0. */ int -gname_to_gid (char *gname, gid_t *gidp) +gname_to_gid (char const *gname, gid_t *gidp) { struct group *group; @@ -229,7 +229,7 @@ is_pattern (const char *string) /* Set up to gather file names for tar. They can either come from a file or were saved from decoding arguments. */ void -name_init (int argc, char *const *argv) +name_init (void) { name_buffer = xmalloc (NAME_FIELD_SIZE + 2); name_buffer_length = NAME_FIELD_SIZE; @@ -360,6 +360,8 @@ name_next (int change_dirs) else { unquote_string (name_buffer); + if (incremental_option) + register_individual_file (name_buffer); return name_buffer; } } @@ -445,6 +447,8 @@ name_gather (void) namelist = buffer; nametail = &namelist->next; } + else if (change_dir) + addname (0, change_dir); } else { @@ -515,10 +519,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) { struct name *p; @@ -526,27 +530,27 @@ 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 : (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) { @@ -563,10 +567,10 @@ name_match (const char *path) return ! files_from_option; } - cursor = namelist_match (path, length); + cursor = namelist_match (file_name, length); 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) @@ -610,9 +614,11 @@ bool all_names_found (struct tar_stat_info *p) { struct name const *cursor; - size_t len = strlen (p->file_name); - if (occurrence_option == 0 || p->had_trailing_slash) + size_t len; + + if (!p->file_name || occurrence_option == 0 || p->had_trailing_slash) return false; + len = strlen (p->file_name); for (cursor = namelist; cursor; cursor = cursor->next) { if (cursor->regexp @@ -636,10 +642,10 @@ names_notfound (void) ERROR ((0, 0, _("%s: Not found in archive"), quotearg_colon (cursor->name))); else - ERROR ((0, 0, _("%s: Required occurence not found in archive"), + ERROR ((0, 0, _("%s: Required occurrence not found in archive"), quotearg_colon (cursor->name))); } - + /* Don't bother freeing the name list; we're about to exit. */ namelist = 0; nametail = &namelist; @@ -748,8 +754,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"; @@ -759,18 +765,18 @@ add_hierarchy_to_namelist (struct name *name, dev_t device) size_t allocated_length = (name_length >= NAME_FIELD_SIZE ? name_length + NAME_FIELD_SIZE : NAME_FIELD_SIZE); - char *name_buffer = xmalloc (allocated_length + 1); + char *namebuf = xmalloc (allocated_length + 1); /* FIXME: + 2 above? */ char *string; size_t string_length; int change_dir = name->change_dir; name->dir_contents = buffer; - strcpy (name_buffer, path); - if (! ISSLASH (name_buffer[name_length - 1])) + strcpy (namebuf, file_name); + if (! ISSLASH (namebuf[name_length - 1])) { - name_buffer[name_length++] = '/'; - name_buffer[name_length] = '\0'; + namebuf[name_length++] = '/'; + namebuf[name_length] = '\0'; } for (string = buffer; *string; string += string_length + 1) @@ -788,15 +794,15 @@ add_hierarchy_to_namelist (struct name *name, dev_t device) } while (allocated_length <= name_length + string_length); - name_buffer = xrealloc (name_buffer, allocated_length + 1); + namebuf = xrealloc (namebuf, allocated_length + 1); } - strcpy (name_buffer + name_length, string + 1); - add_hierarchy_to_namelist (addname (name_buffer, change_dir), + strcpy (namebuf + name_length, string + 1); + add_hierarchy_to_namelist (addname (namebuf, change_dir), device); } } - free (name_buffer); + free (namebuf); } } @@ -833,10 +839,7 @@ collect_and_sort_names (void) if (deref_stat (dereference_option, name->name, &statbuf) != 0) { - if (ignore_failed_read_option) - stat_warn (name->name); - else - stat_error (name->name); + stat_diag (name->name); continue; } if (S_ISDIR (statbuf.st_mode)) @@ -860,13 +863,13 @@ collect_and_sort_names (void) 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. */ struct name * -name_scan (const char *path) +name_scan (const char *file_name) { - 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); if (cursor) return cursor; @@ -917,18 +920,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; } @@ -936,7 +939,7 @@ new_name (const char *path, const char *name) bool excluded_name (char const *name) { - return excluded_filename (excluded, name + FILESYSTEM_PREFIX_LEN (name)); + return excluded_filename (excluded, name + FILE_SYSTEM_PREFIX_LEN (name)); } /* Hash tables of strings. */ @@ -1002,7 +1005,44 @@ is_avoided_name (char const *name) { return hash_string_lookup (avoided_name_table, 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); +} + + + +static Hash_table *prefix_table[2]; + +/* Return true if file names of some members in the archive were stripped off + their leading components. We could have used + return prefix_table[0] || prefix_table[1] + but the following seems to be safer: */ +bool +removed_prefixes_p (void) +{ + return (prefix_table[0] && hash_get_n_entries (prefix_table[0]) != 0) + || (prefix_table[1] && hash_get_n_entries (prefix_table[1]) != 0); +} + /* 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, @@ -1017,14 +1057,14 @@ safer_name_suffix (char const *file_name, bool link_target) p = file_name; else { - /* Skip file system prefixes, leading pathnames that contain + /* Skip file system prefixes, leading file name components that contain "..", and leading slashes. */ - size_t prefix_len = FILESYSTEM_PREFIX_LEN (file_name); + size_t prefix_len = FILE_SYSTEM_PREFIX_LEN (file_name); for (p = file_name + prefix_len; *p; ) { - if (p[0] == '.' && p[1] == '.' && (ISSLASH (p[2]) || !p[2])) + if (p[0] == '.' && p[1] == '.' && (ISSLASH (p[2]) || !p[2])) prefix_len = p + 2 - file_name; do @@ -1042,7 +1082,6 @@ safer_name_suffix (char const *file_name, bool link_target) 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'; @@ -1068,7 +1107,7 @@ safer_name_suffix (char const *file_name, bool link_target) N_("Substituting `.' for empty member name"), N_("Substituting `.' for empty hard link target") }; - WARN ((0, 0, _(diagnostic[link_target]))); + WARN ((0, 0, "%s", _(diagnostic[link_target]))); } p = "."; @@ -1078,13 +1117,13 @@ safer_name_suffix (char const *file_name, bool link_target) } /* 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) @@ -1102,11 +1141,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++) {