X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;f=src%2Fnames.c;h=99a60bdea612120d04ffd440261765ef8e394751;hb=4e59b9d7e33feb6712a1d482650f8786abbadcdf;hp=ebcd3e722d3c59fced2a73240cf6e8e48a5d670f;hpb=fb93b996c8401d68e4c159ff0b80a5415d9b4f13;p=chaz%2Ftar diff --git a/src/names.c b/src/names.c index ebcd3e7..99a60bd 100644 --- a/src/names.c +++ b/src/names.c @@ -1,5 +1,7 @@ /* Various processing of names. - Copyright 1988, 92, 94, 96, 97, 98, 99, 2000 Free Software Foundation, Inc. + + Copyright (C) 1988, 1992, 1994, 1996, 1997, 1998, 1999, 2000, 2001, + 2003 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 @@ -268,7 +270,9 @@ read_name_from_file (void) { if (counter == name_buffer_length) { - name_buffer_length += NAME_FIELD_SIZE; + 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; @@ -279,7 +283,9 @@ read_name_from_file (void) if (counter == name_buffer_length) { - name_buffer_length += NAME_FIELD_SIZE; + 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'; @@ -317,11 +323,20 @@ name_next (int change_dirs) } else { + size_t source_len; source = name_array[name_index++]; - if (strlen (source) > name_buffer_length) + source_len = strlen (source); + if (name_buffer_length < source_len) { + do + { + name_buffer_length *= 2; + if (! name_buffer_length) + xalloc_die (); + } + while (name_buffer_length < source_len); + free (name_buffer); - name_buffer_length = strlen (source); name_buffer = xmalloc (name_buffer_length + 2); } strcpy (name_buffer, source); @@ -330,7 +345,7 @@ name_next (int change_dirs) /* Zap trailing slashes. */ cursor = name_buffer + strlen (name_buffer) - 1; - while (cursor > name_buffer && *cursor == '/') + while (cursor > name_buffer && ISSLASH (*cursor)) *cursor-- = '\0'; if (chdir_flag) @@ -380,7 +395,7 @@ name_gather (void) { /* Buffer able to hold a single name. */ static struct name *buffer; - static size_t allocated_length; + static size_t allocated_size; char const *name; @@ -388,12 +403,12 @@ name_gather (void) { static int change_dir; - if (allocated_length == 0) + if (allocated_size == 0) { - allocated_length = sizeof (struct name) + NAME_FIELD_SIZE; - buffer = xmalloc (allocated_length); + allocated_size = offsetof (struct name, name) + NAME_FIELD_SIZE + 1; + buffer = xmalloc (allocated_size); /* FIXME: This memset is overkill, and ugly... */ - memset (buffer, 0, allocated_length); + memset (buffer, 0, allocated_size); } while ((name = name_next (0)) && strcmp (name, "-C") == 0) @@ -406,14 +421,23 @@ name_gather (void) if (name) { + size_t needed_size; buffer->length = strlen (name); - if (sizeof (struct name) + buffer->length >= allocated_length) + needed_size = offsetof (struct name, name) + buffer->length + 1; + if (allocated_size < needed_size) { - allocated_length = sizeof (struct name) + buffer->length; - buffer = xrealloc (buffer, allocated_length); + do + { + allocated_size *= 2; + if (! allocated_size) + xalloc_die (); + } + while (allocated_size < needed_size); + + buffer = xrealloc (buffer, allocated_size); } buffer->change_dir = change_dir; - memcpy (buffer->name, name, buffer->length + 1); + strcpy (buffer->name, name); buffer->next = 0; buffer->found = 0; @@ -452,23 +476,26 @@ name_gather (void) struct name * addname (char const *string, int change_dir) { - struct name *name; - size_t length; - - length = string ? strlen (string) : 0; - name = xmalloc (sizeof (struct name) + length); - memset (name, 0, sizeof (struct name) + length); - name->next = 0; + size_t length = string ? strlen (string) : 0; + struct name *name = xmalloc (offsetof (struct name, name) + length + 1); if (string) { name->fake = 0; - name->length = length; - memcpy (name->name, string, length + 1); + strcpy (name->name, string); } else - name->fake = 1; + { + name->fake = 1; + /* FIXME: This initialization (and the byte of memory that it + initializes) is probably not needed, but we are currently in + bug-fix mode so we'll leave it in for now. */ + name->name[0] = 0; + } + + name->next = 0; + name->length = length; name->found = 0; name->regexp = 0; /* assume not a regular expression */ name->firstch = 1; /* assume first char is literal */ @@ -504,7 +531,8 @@ namelist_match (char const *path, size_t length) if (p->regexp ? fnmatch (p->name, path, recursion_option) == 0 : (p->length <= length - && (path[p->length] == '\0' || path[p->length] == '/') + && (path[p->length] == '\0' + || (ISSLASH (path[p->length]) && recursion_option)) && memcmp (path, p->name, p->length) == 0)) return p; } @@ -545,7 +573,7 @@ name_match (const char *path) nametail = &namelist; } chdir_do (cursor->change_dir); - + /* We got a match. */ return 1; } @@ -679,15 +707,14 @@ compare_names (struct name const *n1, struct name const *n2) } /* Add all the dirs under NAME, which names a directory, to the namelist. - DIRSIZE is the size of the directory, or -1 if not known. 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. */ static void -add_hierarchy_to_namelist (struct name *name, off_t dirsize, dev_t device) +add_hierarchy_to_namelist (struct name *name, dev_t device) { char *path = name->name; - char *buffer = get_directory_contents (path, dirsize, device); + char *buffer = get_directory_contents (path, device); if (! buffer) name->dir_contents = "\0\0\0\0"; @@ -705,7 +732,7 @@ add_hierarchy_to_namelist (struct name *name, off_t dirsize, dev_t device) name->dir_contents = buffer; strcpy (name_buffer, path); - if (name_buffer[name_length - 1] != '/') + if (! ISSLASH (name_buffer[name_length - 1])) { name_buffer[name_length++] = '/'; name_buffer[name_length] = '\0'; @@ -716,15 +743,21 @@ add_hierarchy_to_namelist (struct name *name, off_t dirsize, dev_t device) string_length = strlen (string); if (*string == 'D') { - if (name_length + string_length >= allocated_length) + if (allocated_length <= name_length + string_length) { - while (name_length + string_length >= allocated_length) - allocated_length += NAME_FIELD_SIZE; + do + { + allocated_length *= 2; + if (! allocated_length) + xalloc_die (); + } + while (allocated_length <= name_length + string_length); + name_buffer = xrealloc (name_buffer, allocated_length + 1); } strcpy (name_buffer + name_length, string + 1); add_hierarchy_to_namelist (addname (name_buffer, change_dir), - -1, device); + device); } } @@ -765,13 +798,16 @@ collect_and_sort_names (void) if (deref_stat (dereference_option, name->name, &statbuf) != 0) { - stat_error (name->name); + if (ignore_failed_read_option) + stat_warn (name->name); + else + stat_error (name->name); continue; } if (S_ISDIR (statbuf.st_mode)) { name->found = 1; - add_hierarchy_to_namelist (name, statbuf.st_size, statbuf.st_dev); + add_hierarchy_to_namelist (name, statbuf.st_dev); } } @@ -853,7 +889,7 @@ new_name (const char *path, const char *name) { size_t pathlen = strlen (path); size_t namesize = strlen (name) + 1; - int slash = pathlen && path[pathlen - 1] != '/'; + int slash = pathlen && ! ISSLASH (path[pathlen - 1]); char *buffer = xmalloc (pathlen + slash + namesize); memcpy (buffer, path, pathlen); buffer[pathlen] = '/'; @@ -861,59 +897,167 @@ new_name (const char *path, const char *name) return buffer; } -/* Return nonzero if file NAME is excluded. Exclude a name if its - prefix matches a pattern that contains slashes, or if one of its - components matches a pattern that contains no slashes. */ -int +/* Return nonzero if file NAME is excluded. */ +bool excluded_name (char const *name) { - char const *p; - name += FILESYSTEM_PREFIX_LEN (name); - - if (excluded_filename (excluded_with_slash, name, - FNM_FILE_NAME | recursion_option)) - return 1; - - for (p = name; *p; p++) - if (((p == name || ISSLASH (p[-1])) && !ISSLASH (p[0])) - && excluded_filename (excluded_without_slash, p, - FNM_FILE_NAME | FNM_LEADING_DIR)) - return 1; - - return 0; + return excluded_filename (excluded, name + FILESYSTEM_PREFIX_LEN (name)); } -/* Names to avoid dumping. */ -static Hash_table *avoided_name_table; +/* Hash tables of strings. */ -/* Calculate the hash of an avoided name. */ +/* Calculate the hash of a string. */ static unsigned -hash_avoided_name (void const *name, unsigned n_buckets) +hash_string_hasher (void const *name, unsigned n_buckets) { return hash_string (name, n_buckets); } -/* Compare two avoided names for equality. */ +/* Compare two strings for equality. */ static bool -compare_avoided_names (void const *name1, void const *name2) +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); +} + +/* Names to avoid dumping. */ +static Hash_table *avoided_name_table; + /* Remember to not archive NAME. */ void add_avoided_name (char const *name) { - if (! ((avoided_name_table - || (avoided_name_table = hash_initialize (0, 0, hash_avoided_name, - compare_avoided_names, 0))) - && hash_insert (avoided_name_table, xstrdup (name)))) - xalloc_die (); + hash_string_insert (&avoided_name_table, name); } /* Should NAME be avoided when archiving? */ -int +bool is_avoided_name (char const *name) { - return avoided_name_table && hash_lookup (avoided_name_table, 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. */ + +char * +safer_name_suffix (char const *file_name, bool link_target) +{ + 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; + + 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 (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 = "."; + } + + return (char *) p; +} + +/* Return nonzero if NAME contains ".." as a path name component. */ +bool +contains_dot_dot (char const *name) +{ + char const *p = name + FILESYSTEM_PREFIX_LEN (name); + + for (;; p++) + { + if (p[0] == '.' && p[1] == '.' && (ISSLASH (p[2]) || !p[2])) + return 1; + + do + { + if (! *p++) + return 0; + } + while (! ISSLASH (*p)); + } }