X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;f=src%2Fnames.c;h=ee68749bb921be22ce3b13bcfeb3a4e8be8be205;hb=91b2d65e9dccae981f308a659d6c7bdd32285598;hp=eb17636965266518352d6e5b94b0eb2b2f63bdb8;hpb=421568c00226bb0a63e6b8e3cdb3a1793200b719;p=chaz%2Ftar diff --git a/src/names.c b/src/names.c index eb17636..ee68749 100644 --- a/src/names.c +++ b/src/names.c @@ -1,7 +1,7 @@ /* Various processing of names. - Copyright 1988, 1992, 1994, 1996, 1997, 1998, 1999, 2000, 2001 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 @@ -43,15 +43,15 @@ struct group *getgrgid (); This code should also be modified for non-UNIX systems to do something reasonable. */ -static char cached_uname[UNAME_FIELD_SIZE]; -static char cached_gname[GNAME_FIELD_SIZE]; +static char *cached_uname; +static char *cached_gname; static uid_t cached_uid; /* valid only if cached_uname is not empty */ static gid_t cached_gid; /* valid only if cached_gname is not empty */ /* These variables are valid only if nonempty. */ -static char cached_no_such_uname[UNAME_FIELD_SIZE]; -static char cached_no_such_gname[GNAME_FIELD_SIZE]; +static char *cached_no_such_uname; +static char *cached_no_such_gname; /* These variables are valid only if nonzero. It's not worth optimizing the case for weird systems where 0 is not a valid uid or gid. */ @@ -60,87 +60,87 @@ static gid_t cached_no_such_gid; /* Given UID, find the corresponding UNAME. */ void -uid_to_uname (uid_t uid, char uname[UNAME_FIELD_SIZE]) +uid_to_uname (uid_t uid, char **uname) { struct passwd *passwd; if (uid != 0 && uid == cached_no_such_uid) { - *uname = '\0'; + *uname = strdup (""); return; } - if (!cached_uname[0] || uid != cached_uid) + if (!cached_uname || uid != cached_uid) { passwd = getpwuid (uid); if (passwd) { cached_uid = uid; - strncpy (cached_uname, passwd->pw_name, UNAME_FIELD_SIZE); + assign_string (&cached_uname, passwd->pw_name); } else { cached_no_such_uid = uid; - *uname = '\0'; + *uname = strdup (""); return; } } - strncpy (uname, cached_uname, UNAME_FIELD_SIZE); + *uname = strdup (cached_uname); } /* Given GID, find the corresponding GNAME. */ void -gid_to_gname (gid_t gid, char gname[GNAME_FIELD_SIZE]) +gid_to_gname (gid_t gid, char **gname) { struct group *group; if (gid != 0 && gid == cached_no_such_gid) { - *gname = '\0'; + *gname = strdup (""); return; } - if (!cached_gname[0] || gid != cached_gid) + if (!cached_gname || gid != cached_gid) { group = getgrgid (gid); if (group) { cached_gid = gid; - strncpy (cached_gname, group->gr_name, GNAME_FIELD_SIZE); + assign_string (&cached_gname, group->gr_name); } else { cached_no_such_gid = gid; - *gname = '\0'; + *gname = strdup (""); return; } } - strncpy (gname, cached_gname, GNAME_FIELD_SIZE); + *gname = strdup (cached_gname); } /* Given UNAME, set the corresponding UID and return 1, or else, return 0. */ int -uname_to_uid (char uname[UNAME_FIELD_SIZE], uid_t *uidp) +uname_to_uid (char *uname, uid_t *uidp) { struct passwd *passwd; - if (cached_no_such_uname[0] - && strncmp (uname, cached_no_such_uname, UNAME_FIELD_SIZE) == 0) + if (cached_no_such_uname + && strcmp (uname, cached_no_such_uname) == 0) return 0; - if (!cached_uname[0] + if (!cached_uname || uname[0] != cached_uname[0] - || strncmp (uname, cached_uname, UNAME_FIELD_SIZE) != 0) + || strcmp (uname, cached_uname) != 0) { passwd = getpwnam (uname); if (passwd) { cached_uid = passwd->pw_uid; - strncpy (cached_uname, uname, UNAME_FIELD_SIZE); + assign_string (&cached_uname, passwd->pw_name); } else { - strncpy (cached_no_such_uname, uname, UNAME_FIELD_SIZE); + assign_string (&cached_no_such_uname, uname); return 0; } } @@ -150,33 +150,34 @@ uname_to_uid (char uname[UNAME_FIELD_SIZE], uid_t *uidp) /* Given GNAME, set the corresponding GID and return 1, or else, return 0. */ int -gname_to_gid (char gname[GNAME_FIELD_SIZE], gid_t *gidp) +gname_to_gid (char *gname, gid_t *gidp) { struct group *group; - if (cached_no_such_gname[0] - && strncmp (gname, cached_no_such_gname, GNAME_FIELD_SIZE) == 0) + if (cached_no_such_gname + && strcmp (gname, cached_no_such_gname) == 0) return 0; - if (!cached_gname[0] + if (!cached_gname || gname[0] != cached_gname[0] - || strncmp (gname, cached_gname, GNAME_FIELD_SIZE) != 0) + || strcmp (gname, cached_gname) != 0) { group = getgrnam (gname); if (group) { cached_gid = group->gr_gid; - strncpy (cached_gname, gname, GNAME_FIELD_SIZE); + assign_string (&cached_gname, gname); } else { - strncpy (cached_no_such_gname, gname, GNAME_FIELD_SIZE); + assign_string (&cached_no_such_gname, gname); return 0; } } *gidp = cached_gid; return 1; } + /* Names from the command call. */ @@ -531,7 +532,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' || ISSLASH (path[p->length])) + && (path[p->length] == '\0' + || (ISSLASH (path[p->length]) && recursion_option)) && memcmp (path, p->name, p->length) == 0)) return p; } @@ -572,7 +574,7 @@ name_match (const char *path) nametail = &namelist; } chdir_do (cursor->change_dir); - + /* We got a match. */ return 1; } @@ -896,46 +898,184 @@ 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. */ +/* Return nonzero if file NAME is excluded. */ bool excluded_name (char const *name) { 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; +} + +char const * +cut_path_elements (char const *file_name, size_t num) +{ + char const *p = file_name; + if (ISSLASH (*p)) + p++; + for (; *p; p++) + { + if (ISSLASH (*p)) + { + if (--num == 0) + return p + 1; + } + } + return NULL; +} + +/* 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)); + } }