(_GNU_SOURCE): Remove; autoconf now does this.
Include <hash.h>. (getpwuid, getgrgid): Declare only if system headers don't. (gid_to_gname): Don't invoke setgrent. (namelist): Now static, not global. (nametail): New var. All uses of namelast changed to use nametail, with one extra level of indirection. (name_gather): Use memcpy instead of strncpy + assignment of NUL. (name_match): Set nametail too, when setting namelist to null. (add_hierarchy_to_namelist): Change type of dir arg from char * to struct name *, so that we don't have to look up the name again here. Get change_dir from dir rather than as a separate arg. Add dirsize arg, and pass it along to get_directory_contents. Remove unnecessary check of directory type. (new_name): Do not append a slash if PATH already ends in one. (avoided_names, struct avoided_name): Remove. (avoided_name_table): New var, replacing avoided_names. (hash_avoided_name, compare_avoided_names): New function. (add_avoided_name, is_avoided_name): Use hash table rather than linked list.
This commit is contained in:
264
src/names.c
264
src/names.c
@@ -1,5 +1,5 @@
|
||||
/* Various processing of names.
|
||||
Copyright (C) 1988, 92, 94, 96, 97, 98, 1999 Free Software Foundation, Inc.
|
||||
Copyright 1988, 92, 94, 96, 97, 98, 99, 2000 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,29 +15,25 @@
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
/* Enable GNU extensions in fnmatch.h. */
|
||||
#ifndef _GNU_SOURCE
|
||||
# define _GNU_SOURCE 1
|
||||
#endif
|
||||
|
||||
#include "system.h"
|
||||
|
||||
#include <pwd.h>
|
||||
#include <grp.h>
|
||||
#include <fnmatch.h>
|
||||
#include <grp.h>
|
||||
#include <hash.h>
|
||||
#include <pwd.h>
|
||||
#include <quotearg.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
/* User and group names. */
|
||||
|
||||
extern struct group *getgrnam ();
|
||||
extern struct passwd *getpwnam ();
|
||||
#if !HAVE_GETPWUID
|
||||
extern struct passwd *getpwuid ();
|
||||
struct group *getgrnam ();
|
||||
struct passwd *getpwnam ();
|
||||
#if ! HAVE_DECL_GETPWUID
|
||||
struct passwd *getpwuid ();
|
||||
#endif
|
||||
#if !HAVE_GETGRGID
|
||||
extern struct group *getgrgid ();
|
||||
#if ! HAVE_DECL_GETGRGID
|
||||
struct group *getgrgid ();
|
||||
#endif
|
||||
|
||||
/* Make sure you link with the proper libraries if you are running the
|
||||
@@ -60,10 +56,7 @@ static char cached_no_such_gname[GNAME_FIELD_SIZE];
|
||||
static uid_t cached_no_such_uid;
|
||||
static gid_t cached_no_such_gid;
|
||||
|
||||
/*------------------------------------------.
|
||||
| Given UID, find the corresponding UNAME. |
|
||||
`------------------------------------------*/
|
||||
|
||||
/* Given UID, find the corresponding UNAME. */
|
||||
void
|
||||
uid_to_uname (uid_t uid, char uname[UNAME_FIELD_SIZE])
|
||||
{
|
||||
@@ -93,10 +86,7 @@ uid_to_uname (uid_t uid, char uname[UNAME_FIELD_SIZE])
|
||||
strncpy (uname, cached_uname, UNAME_FIELD_SIZE);
|
||||
}
|
||||
|
||||
/*------------------------------------------.
|
||||
| Given GID, find the corresponding GNAME. |
|
||||
`------------------------------------------*/
|
||||
|
||||
/* Given GID, find the corresponding GNAME. */
|
||||
void
|
||||
gid_to_gname (gid_t gid, char gname[GNAME_FIELD_SIZE])
|
||||
{
|
||||
@@ -110,7 +100,6 @@ gid_to_gname (gid_t gid, char gname[GNAME_FIELD_SIZE])
|
||||
|
||||
if (!cached_gname[0] || gid != cached_gid)
|
||||
{
|
||||
setgrent (); /* FIXME: why?! */
|
||||
group = getgrgid (gid);
|
||||
if (group)
|
||||
{
|
||||
@@ -127,10 +116,7 @@ gid_to_gname (gid_t gid, char gname[GNAME_FIELD_SIZE])
|
||||
strncpy (gname, cached_gname, GNAME_FIELD_SIZE);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------.
|
||||
| Given UNAME, set the corresponding UID and return 1, or else, return 0. |
|
||||
`-------------------------------------------------------------------------*/
|
||||
|
||||
/* 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)
|
||||
{
|
||||
@@ -160,10 +146,7 @@ uname_to_uid (char uname[UNAME_FIELD_SIZE], uid_t *uidp)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------.
|
||||
| Given GNAME, set the corresponding GID and return 1, or else, return 0. |
|
||||
`-------------------------------------------------------------------------*/
|
||||
|
||||
/* 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)
|
||||
{
|
||||
@@ -195,15 +178,14 @@ gname_to_gid (char gname[GNAME_FIELD_SIZE], gid_t *gidp)
|
||||
|
||||
/* Names from the command call. */
|
||||
|
||||
static struct name *namelist; /* first name in list, if any */
|
||||
static struct name **nametail = &namelist; /* end of name list */
|
||||
static const char **name_array; /* store an array of names */
|
||||
static int allocated_names; /* how big is the array? */
|
||||
static int names; /* how many entries does it have? */
|
||||
static int name_index; /* how many of the entries have we scanned? */
|
||||
|
||||
/*------------------------.
|
||||
| Initialize structures. |
|
||||
`------------------------*/
|
||||
|
||||
/* Initialize structures. */
|
||||
void
|
||||
init_names (void)
|
||||
{
|
||||
@@ -212,10 +194,7 @@ init_names (void)
|
||||
names = 0;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------.
|
||||
| Add NAME at end of name_array, reallocating it as necessary. |
|
||||
`--------------------------------------------------------------*/
|
||||
|
||||
/* Add NAME at end of name_array, reallocating it as necessary. */
|
||||
void
|
||||
name_add (const char *name)
|
||||
{
|
||||
@@ -234,10 +213,6 @@ 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 */
|
||||
|
||||
/*---.
|
||||
| ? |
|
||||
`---*/
|
||||
|
||||
/* FIXME: I should better check more closely. It seems at first glance that
|
||||
is_pattern is only used when reading a file, and ignored for all
|
||||
command line arguments. */
|
||||
@@ -248,11 +223,8 @@ is_pattern (const char *string)
|
||||
return strchr (string, '*') || strchr (string, '[') || strchr (string, '?');
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------.
|
||||
| Set up to gather file names for tar. They can either come from a file |
|
||||
| or were saved from decoding arguments. |
|
||||
`-----------------------------------------------------------------------*/
|
||||
|
||||
/* 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)
|
||||
{
|
||||
@@ -271,10 +243,6 @@ name_init (int argc, char *const *argv)
|
||||
}
|
||||
}
|
||||
|
||||
/*---.
|
||||
| ? |
|
||||
`---*/
|
||||
|
||||
void
|
||||
name_term (void)
|
||||
{
|
||||
@@ -282,12 +250,9 @@ 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. |
|
||||
`---------------------------------------------------------------------*/
|
||||
|
||||
/* 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)
|
||||
{
|
||||
@@ -322,15 +287,13 @@ read_name_from_file (void)
|
||||
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. |
|
||||
| |
|
||||
| If CHANGE_DIRS is true, treat a filename of the form "-C" as meaning |
|
||||
| that the next filename is the name of a directory to change to. If |
|
||||
| `filename_terminator' is NUL, CHANGE_DIRS is effectively always false. |
|
||||
`------------------------------------------------------------------------*/
|
||||
/* 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.
|
||||
|
||||
If CHANGE_DIRS is true, treat a filename of the form "-C" as
|
||||
meaning that the next filename is the name of a directory to change
|
||||
to. If filename_terminator is NUL, CHANGE_DIRS is effectively
|
||||
always false. */
|
||||
char *
|
||||
name_next (int change_dirs)
|
||||
{
|
||||
@@ -393,10 +356,7 @@ name_next (int change_dirs)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*------------------------------.
|
||||
| Close the name file, if any. |
|
||||
`------------------------------*/
|
||||
|
||||
/* Close the name file, if any. */
|
||||
void
|
||||
name_close (void)
|
||||
{
|
||||
@@ -405,17 +365,15 @@ name_close (void)
|
||||
close_error (name_buffer);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------.
|
||||
| Gather names in a list for scanning. Could hash them later if we really |
|
||||
| care. |
|
||||
| |
|
||||
| If the names are already sorted to match the archive, we just read them |
|
||||
| one by one. name_gather reads the first one, and it is called by |
|
||||
| name_match as appropriate to read the next ones. At EOF, the last name |
|
||||
| read is just left in the buffer. This option lets users of small |
|
||||
| machines extract an arbitrary number of files by doing "tar t" and |
|
||||
| editing down the list of files. |
|
||||
`-------------------------------------------------------------------------*/
|
||||
/* Gather names in a list for scanning. Could hash them later if we
|
||||
really care.
|
||||
|
||||
If the names are already sorted to match the archive, we just read
|
||||
them one by one. name_gather reads the first one, and it is called
|
||||
by name_match as appropriate to read the next ones. At EOF, the
|
||||
last name read is just left in the buffer. This option lets users
|
||||
of small machines extract an arbitrary number of files by doing
|
||||
"tar t" and editing down the list of files. */
|
||||
|
||||
void
|
||||
name_gather (void)
|
||||
@@ -455,14 +413,12 @@ name_gather (void)
|
||||
buffer = xrealloc (buffer, allocated_length);
|
||||
}
|
||||
buffer->change_dir = change_dir;
|
||||
strncpy (buffer->name, name, buffer->length);
|
||||
buffer->name[buffer->length] = 0;
|
||||
memcpy (buffer->name, name, buffer->length + 1);
|
||||
buffer->next = 0;
|
||||
buffer->found = 0;
|
||||
|
||||
/* FIXME: Poorly named globals, indeed... */
|
||||
namelist = buffer;
|
||||
namelast = namelist;
|
||||
nametail = &namelist->next;
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -492,11 +448,8 @@ name_gather (void)
|
||||
}
|
||||
}
|
||||
|
||||
/*-----------------------------.
|
||||
| Add a name to the namelist. |
|
||||
`-----------------------------*/
|
||||
|
||||
void
|
||||
/* Add a name to the namelist. */
|
||||
struct name *
|
||||
addname (char const *string, int change_dir)
|
||||
{
|
||||
struct name *name;
|
||||
@@ -529,18 +482,13 @@ addname (char const *string, int change_dir)
|
||||
name->firstch = 0;
|
||||
}
|
||||
|
||||
if (namelast)
|
||||
namelast->next = name;
|
||||
namelast = name;
|
||||
if (!namelist)
|
||||
namelist = name;
|
||||
*nametail = name;
|
||||
nametail = &name->next;
|
||||
return name;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------.
|
||||
| Return true if and only if name PATH (from an archive) matches any name |
|
||||
| from the namelist. |
|
||||
`------------------------------------------------------------------------*/
|
||||
|
||||
/* Return true if and only if name PATH (from an archive) matches any
|
||||
name from the namelist. */
|
||||
int
|
||||
name_match (const char *path)
|
||||
{
|
||||
@@ -557,6 +505,7 @@ name_match (const char *path)
|
||||
{
|
||||
chdir_do (cursor->change_dir);
|
||||
namelist = 0;
|
||||
nametail = &namelist;
|
||||
return ! files_from_option;
|
||||
}
|
||||
|
||||
@@ -579,6 +528,7 @@ name_match (const char *path)
|
||||
{
|
||||
free (namelist);
|
||||
namelist = 0;
|
||||
nametail = &namelist;
|
||||
}
|
||||
chdir_do (cursor->change_dir);
|
||||
|
||||
@@ -603,10 +553,7 @@ name_match (const char *path)
|
||||
}
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------.
|
||||
| Print the names of things in the namelist that were not matched. |
|
||||
`------------------------------------------------------------------*/
|
||||
|
||||
/* Print the names of things in the namelist that were not matched. */
|
||||
void
|
||||
names_notfound (void)
|
||||
{
|
||||
@@ -630,7 +577,7 @@ names_notfound (void)
|
||||
#endif
|
||||
}
|
||||
namelist = 0;
|
||||
namelast = 0;
|
||||
nametail = &namelist;
|
||||
|
||||
if (same_order_option)
|
||||
{
|
||||
@@ -729,29 +676,22 @@ compare_names (struct name const *n1, struct name const *n2)
|
||||
return found_diff ? found_diff : strcmp (n1->name, n2->name);
|
||||
}
|
||||
|
||||
/* Add all the dirs in PATH, which is a directory, to the namelist.
|
||||
/* 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.
|
||||
CHANGE_DIR is the number of the directory that PATH is relative to.
|
||||
DEVICE is the device not to leave, if the -l option is specified. */
|
||||
|
||||
static void
|
||||
add_hierarchy_to_namelist (char *path, int change_dir, dev_t device)
|
||||
add_hierarchy_to_namelist (struct name *name, off_t dirsize, dev_t device)
|
||||
{
|
||||
char *buffer = get_directory_contents (path, device);
|
||||
char *path = name->name;
|
||||
char *buffer = get_directory_contents (path, dirsize, device);
|
||||
|
||||
{
|
||||
struct name *name;
|
||||
|
||||
for (name = namelist; name; name = name->next)
|
||||
if (strcmp (name->name, path) == 0)
|
||||
break;
|
||||
if (name)
|
||||
name->dir_contents = buffer ? buffer : "\0\0\0\0";
|
||||
}
|
||||
|
||||
if (buffer)
|
||||
if (! buffer)
|
||||
name->dir_contents = "\0\0\0\0";
|
||||
else
|
||||
{
|
||||
size_t name_length = strlen (path);
|
||||
size_t name_length = name->length;
|
||||
size_t allocated_length = (name_length >= NAME_FIELD_SIZE
|
||||
? name_length + NAME_FIELD_SIZE
|
||||
: NAME_FIELD_SIZE);
|
||||
@@ -759,7 +699,9 @@ add_hierarchy_to_namelist (char *path, int change_dir, dev_t device)
|
||||
/* FIXME: + 2 above? */
|
||||
char *string;
|
||||
size_t string_length;
|
||||
int change_dir = name->change_dir;
|
||||
|
||||
name->dir_contents = buffer;
|
||||
strcpy (name_buffer, path);
|
||||
if (name_buffer[name_length - 1] != '/')
|
||||
{
|
||||
@@ -779,9 +721,8 @@ add_hierarchy_to_namelist (char *path, int change_dir, dev_t device)
|
||||
name_buffer = xrealloc (name_buffer, allocated_length + 1);
|
||||
}
|
||||
strcpy (name_buffer + name_length, string + 1);
|
||||
addname (name_buffer, change_dir);
|
||||
if (*string == 'D')
|
||||
add_hierarchy_to_namelist (name_buffer, change_dir, device);
|
||||
add_hierarchy_to_namelist (addname (name_buffer, change_dir),
|
||||
-1, device);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -828,8 +769,7 @@ collect_and_sort_names (void)
|
||||
if (S_ISDIR (statbuf.st_mode))
|
||||
{
|
||||
name->found = 1;
|
||||
add_hierarchy_to_namelist (name->name, name->change_dir,
|
||||
statbuf.st_dev);
|
||||
add_hierarchy_to_namelist (name, statbuf.st_size, statbuf.st_dev);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -842,13 +782,10 @@ collect_and_sort_names (void)
|
||||
name->found = 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 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. */
|
||||
struct name *
|
||||
name_scan (const char *path)
|
||||
{
|
||||
@@ -893,12 +830,9 @@ name_scan (const char *path)
|
||||
}
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------.
|
||||
| This returns a name from the namelist which doesn't have ->found set. |
|
||||
| It sets ->found before returning, so successive calls will find and |
|
||||
| return all the non-found names in the namelist |
|
||||
`-----------------------------------------------------------------------*/
|
||||
|
||||
/* This returns a name from the namelist which doesn't have ->found
|
||||
set. It sets ->found before returning, so successive calls will
|
||||
find and return all the non-found names in the namelist. */
|
||||
struct name *gnu_list_name;
|
||||
|
||||
char *
|
||||
@@ -917,10 +851,6 @@ name_from_list (void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*---.
|
||||
| ? |
|
||||
`---*/
|
||||
|
||||
void
|
||||
blank_name_list (void)
|
||||
{
|
||||
@@ -931,16 +861,18 @@ blank_name_list (void)
|
||||
name->found = 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. */
|
||||
char *
|
||||
new_name (const char *path, const char *name)
|
||||
{
|
||||
char *buffer = xmalloc (strlen (path) + strlen (name) + 2);
|
||||
|
||||
sprintf (buffer, "%s/%s", path, name);
|
||||
size_t pathlen = strlen (path);
|
||||
size_t namesize = strlen (name) + 1;
|
||||
int slash = pathlen && path[pathlen - 1] != '/';
|
||||
char *buffer = xmalloc (pathlen + slash + namesize);
|
||||
memcpy (buffer, path, pathlen);
|
||||
buffer[pathlen] = '/';
|
||||
memcpy (buffer + pathlen + slash, name, namesize);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
@@ -967,32 +899,36 @@ excluded_name (char const *name)
|
||||
}
|
||||
|
||||
/* Names to avoid dumping. */
|
||||
static Hash_table *avoided_name_table;
|
||||
|
||||
struct avoided_name
|
||||
/* Calculate the hash of an avoided name. */
|
||||
static unsigned
|
||||
hash_avoided_name (void const *name, unsigned n_buckets)
|
||||
{
|
||||
struct avoided_name const *next;
|
||||
char name[1];
|
||||
};
|
||||
return hash_string (name, n_buckets);
|
||||
}
|
||||
|
||||
static struct avoided_name *avoided_names;
|
||||
/* Compare two avoided names for equality. */
|
||||
static bool
|
||||
compare_avoided_names (void const *name1, void const *name2)
|
||||
{
|
||||
return strcmp (name1, name2) == 0;
|
||||
}
|
||||
|
||||
/* Remember to not archive NAME. */
|
||||
void
|
||||
add_avoided_name (char const *name)
|
||||
{
|
||||
struct avoided_name *p = xmalloc (sizeof *p + strlen (name));
|
||||
p->next = avoided_names;
|
||||
avoided_names = p;
|
||||
strcpy (p->name, 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 ();
|
||||
}
|
||||
|
||||
/* Should NAME be avoided when archiving? */
|
||||
int
|
||||
is_avoided_name (char const *name)
|
||||
{
|
||||
struct avoided_name const *p;
|
||||
for (p = avoided_names; p; p = p->next)
|
||||
if (strcmp (p->name, name) == 0)
|
||||
return 1;
|
||||
return 0;
|
||||
return avoided_name_table && hash_lookup (avoided_name_table, name);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user