(_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:
Paul Eggert
2000-10-24 06:18:37 +00:00
parent b20005e951
commit 85e724550f

View File

@@ -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);
}