NT4/private/posix/programs/pax/namelist.c
2020-09-30 17:12:29 +02:00

554 lines
13 KiB
C

/* $Source: /u/mark/src/pax/RCS/namelist.c,v $
*
* $Revision: 1.6 $
*
* namelist.c - track filenames given as arguments to tar/cpio/pax
*
* DESCRIPTION
*
* Arguments may be regular expressions, therefore all agurments will
* be treated as if they were regular expressions, even if they are
* not.
*
* AUTHOR
*
* Mark H. Colburn, NAPS International (mark@jhereg.mn.org)
*
* Sponsored by The USENIX Association for public distribution.
*
* Copyright (c) 1989 Mark H. Colburn.
* All rights reserved.
*
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice is duplicated in all such
* forms and that any documentation, advertising materials, and other
* materials related to such distribution and use acknowledge that the
* software was developed by Mark H. Colburn and sponsored by The
* USENIX Association.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
* $Log: namelist.c,v $
* Revision 1.6 89/02/13 09:14:48 mark
* Fixed problem with directory errors
*
* Revision 1.5 89/02/12 12:14:00 mark
* Fixed misspellings
*
* Revision 1.4 89/02/12 11:25:19 mark
* Modifications to compile and link cleanly under USG
*
* Revision 1.3 89/02/12 10:40:23 mark
* Fixed casting problems
*
* Revision 1.2 89/02/12 10:04:57 mark
* 1.2 release fixes
*
* Revision 1.1 88/12/23 18:02:17 mark
* Initial revision
*
*/
#ifndef lint
static char *ident = "$Id: namelist.c,v 1.6 89/02/13 09:14:48 mark Exp $";
static char *copyright = "Copyright (c) 1989 Mark H. Colburn.\nAll rights reserved.\n";
#endif /* ! lint */
/* Headers */
#include "pax.h"
/* Type Definitions */
/*
* Structure for keeping track of filenames and lists thereof.
*/
struct nm_list {
struct nm_list *next;
short length; /* cached strlen(name) */
char found; /* A matching file has been found */
char firstch; /* First char is literally matched */
char regexp; /* regexp pattern for item */
char name[1]; /* name of file or rexexp */
};
struct dirinfo {
char dirname[PATH_MAX + 1]; /* name of directory */
OFFSET where; /* current location in directory */
struct dirinfo *next;
};
/* Static Variables */
static struct dirinfo *stack_head = (struct dirinfo *)NULL;
/* Function Prototypes */
#ifndef __STDC__
static void pushdir();
static struct dirinfo *popdir();
#else
static void pushdir(struct dirinfo *info);
static struct dirinfo *popdir(void);
#endif
/* Internal Identifiers */
static struct nm_list *namelast = NULL; /* Points to last name in list */ /* Xn */
static struct nm_list *namelist = NULL; /* Points to first name in list */ /* Xn */
/* addname - add a name to the namelist.
*
* DESCRIPTION
*
* Addname adds the name given to the name list. Memory for the
* namelist structure is dynamically allocated. If the space for
* the structure cannot be allocated, then the program will exit
* the an out of memory error message and a non-zero return code
* will be returned to the caller.
*
* PARAMETERS
*
* char *name - A pointer to the name to add to the list
*/
#ifdef __STDC__
void add_name(char *name)
#else
void add_name(name)
char *name; /* pointer to name */
#endif
{
int i; /* Length of string */
struct nm_list *p; /* Current struct pointer */
#ifdef DF_TRACE_DEBUG
printf("DF_TRACE_DEBUG: void add_name() in namelist.c\n");
#endif
i = strlen(name);
p = (struct nm_list *) malloc((unsigned) (i + sizeof(struct nm_list)));
if (!p) {
fatal("cannot allocate memory for namelist entry\n");
}
p->next = (struct nm_list *)NULL;
p->length = i;
strncpy(p->name, name, i);
p->name[i] = '\0'; /* Null term */
p->found = 0;
p->firstch = isalpha(name[0]);
if (strchr(name, '*') || strchr(name, '[') || strchr(name, '?')) {
p->regexp = 1;
}
if (namelast) {
namelast->next = p;
}
namelast = p;
if (!namelist) {
namelist = p;
}
}
/* name_match - match a name from an archive with a name from the namelist
*
* DESCRIPTION
*
* Name_match attempts to find a name pointed at by p in the namelist.
* If no namelist is available, then all filenames passed in are
* assumed to match the filename criteria. Name_match knows how to
* match names with regular expressions, etc.
*
* PARAMETERS
*
* char *p - the name to match
*
* RETURNS
*
* Returns 1 if the name is in the namelist, or no name list is
* available, otherwise returns 0
*
*/
#ifdef __STDC__
int name_match(char *p)
#else
int name_match(p)
char *p;
#endif
{
struct nm_list *nlp;
int len;
#ifdef DF_TRACE_DEBUG
printf("DF_TRACE_DEBUG: int name_match() in namelist.c\n");
#endif
if ((nlp = namelist) == 0) {/* Empty namelist is easy */
return (1);
}
len = strlen(p);
for (; nlp != 0; nlp = nlp->next) {
/* If first chars don't match, quick skip */
if (nlp->firstch && nlp->name[0] != p[0]) {
continue;
}
/* Regular expressions */
if (nlp->regexp) {
if (wildmat(nlp->name, p)) {
nlp->found = 1; /* Remember it matched */
return (1); /* We got a match */
}
continue;
}
/* Plain Old Strings */
if (nlp->length <= len /* Archive len >= specified */
&& (p[nlp->length] == '\0' || p[nlp->length] == '/')
&& strncmp(p, nlp->name, nlp->length) == 0) {
/* Name compare */
nlp->found = 1; /* Remember it matched */
return (1); /* We got a match */
}
}
return (0);
}
/* names_notfound - print names of files in namelist that were not found
*
* DESCRIPTION
*
* Names_notfound scans through the namelist for any files which were
* named, but for which a matching file was not processed by the
* archive. Each of the files is listed on the standard error.
*
*/
#ifdef __STDC__
void names_notfound(void)
#else
void names_notfound()
#endif
{
struct nm_list *nlp;
#ifdef DF_TRACE_DEBUG
printf("DF_TRACE_DEBUG: void names_notfound() in namelist.c\n");
#endif
for (nlp = namelist; nlp != 0; nlp = nlp->next) {
if (!nlp->found) {
fprintf(stderr, "%s: %s not found in archive\n",
myname, nlp->name);
}
free(nlp);
}
namelist = (struct nm_list *)NULL;
namelast = (struct nm_list *)NULL;
}
/* name_init - set up to gather file names
*
* DESCRIPTION
*
* Name_init sets up the namelist pointers so that we may access the
* command line arguments. At least the first item of the command
* line (argv[0]) is assumed to be stripped off, prior to the
* name_init call.
*
* PARAMETERS
*
* int argc - number of items in argc
* char **argv - pointer to the command line arguments
*/
#ifdef __STDC__
void name_init(int argc, char **argv)
#else
void name_init(argc, argv)
int argc;
char **argv;
#endif
{
/* Get file names from argv, after options. */
n_argc = argc;
n_argv = argv;
}
/* name_next - get the next name from argv or the name file.
*
* DESCRIPTION
*
* Name next finds the next name which is to be processed in the
* archive. If the named file is a directory, then the directory
* is recursively traversed for additional file names. Directory
* names and locations within the directory are kept track of by
* using a directory stack. See the pushdir/popdir function for
* more details.
*
* The names come from argv, after options or from the standard input.
*
* PARAMETERS
*
* name - a pointer to a buffer of at least MAX_PATH + 1 bytes long;
* statbuf - a pointer to a stat structure
*
* RETURNS
*
#ifdef DF_TRACE_DEBUG
printf("DF_TRACE_DEBUG: void name_init() in namelist.c\n");
#endif
* Returns -1 if there are no names left, (e.g. EOF), otherwise returns
* 0
*/
#ifdef __STDC__
int name_next(char *name, Stat *statbuf)
#else
int name_next(name, statbuf)
char *name;
Stat *statbuf;
#endif
{
int err = -1; /* Xn */
static int in_subdir = 0; /* Xn */
static DIR *dirp = NULL; /* Xn */
struct dirent *d; /* Xn */
static struct dirinfo *curr_dir = NULL; /* Xn */
int len; /* Xn */
do {
#ifdef DF_TRACE_DEBUG
printf("DF_TRACE_DEBUG: int name_next() in namelist.c\n");
#endif
if (names_from_stdin) {
if (lineget(stdin, name) < 0) {
return (-1);
}
if (nameopt(name) < 0) {
continue;
}
} else {
if (in_subdir) {
if ((d = readdir(dirp)) != (struct dirent *)NULL) {
/* Skip . and .. */
if (strcmp(d->d_name, ".") == 0 ||
strcmp(d->d_name, "..") == 0) {
continue;
}
#ifdef DF_TRACE_DEBUG
printf("DF_TRACE_DEBUG: strcmp() in namelist.c\n");
#endif
if (strlen(d->d_name) +
strlen(curr_dir->dirname) >= PATH_MAX) {
#ifdef DF_TRACE_DEBUG
printf("DF_TRACE_DEBUG: strlen() in namelist.c\n");
#endif
warn("name too long", d->d_name);
continue;
}
strcpy(name, curr_dir->dirname);
strcat(name, d->d_name);
} else {
closedir(dirp);
in_subdir--;
curr_dir = popdir();
if (in_subdir) {
errno = 0;
if ((dirp=opendir(curr_dir->dirname)) == (DIR *)NULL) {
warn(curr_dir->dirname, "error opening directory (1)");
in_subdir--;
}
seekdir(dirp, curr_dir->where);
}
continue;
}
} else if (optind >= n_argc) {
return (-1);
} else {
strcpy(name, n_argv[optind++]);
}
}
if ((err = LSTAT(name, statbuf)) < 0) {
warn(name, strerror(errno)); /* Xn */
continue;
}
if (!names_from_stdin && (statbuf->sb_mode & S_IFMT) == S_IFDIR) {
if (in_subdir) {
curr_dir->where = telldir(dirp);
pushdir(curr_dir);
closedir(dirp);
}
in_subdir++;
/* Build new prototype name */
if ((curr_dir = (struct dirinfo *) mem_get(sizeof(struct dirinfo)))
== (struct dirinfo *)NULL) {
exit(2);
}
strcpy(curr_dir->dirname, name);
len = strlen(curr_dir->dirname);
while (len >= 1 && curr_dir->dirname[len - 1] == '/') {
len--; /* Delete trailing slashes */
}
curr_dir->dirname[len++] = '/'; /* Now add exactly one back */
curr_dir->dirname[len] = '\0';/* Make sure null-terminated */
curr_dir->where = 0;
errno = 0;
do {
if ((dirp = opendir(curr_dir->dirname)) == (DIR *)NULL) {
warn(curr_dir->dirname, "error opening directory (2)");
if (in_subdir > 1) {
curr_dir = popdir();
}
in_subdir--;
err = -1;
continue;
} else {
seekdir(dirp, curr_dir->where);
}
} while (in_subdir && (! dirp));
}
} while (err < 0);
return (0);
}
/* name_gather - gather names in a list for scanning.
*
* DESCRIPTION
*
* Name_gather takes names from the command line and adds them to
* the name list.
*
* FIXME
*
* We could hash the names if we really care about speed here.
*/
#ifdef __STDC__
void name_gather(void)
#else
void name_gather()
#endif
{
#ifdef DF_TRACE_DEBUG
printf("DF_TRACE_DEBUG: void name_gather() in namelist.c\n");
#endif
while (optind < n_argc) {
add_name(n_argv[optind++]);
}
}
/* pushdir - pushes a directory name on the directory stack
*
* DESCRIPTION
*
* The pushdir function puses the directory structure which is pointed
* to by "info" onto a stack for later processing. The information
* may be retrieved later with a call to popdir().
*
* PARAMETERS
*
* dirinfo *info - pointer to directory structure to save
*/
#ifdef __STDC__
static void pushdir(struct dirinfo *info)
#else
static void pushdir(info)
struct dirinfo *info;
#endif
{
#ifdef DF_TRACE_DEBUG
printf("DF_TRACE_DEBUG: static void pushdir() in namelist.c\n");
#endif
if (stack_head == (struct dirinfo *)NULL) {
stack_head = info;
stack_head->next = (struct dirinfo *)NULL;
} else {
info->next = stack_head;
stack_head = info;
}
}
/* popdir - pop a directory structure off the directory stack.
*
* DESCRIPTION
*
* The popdir function pops the most recently pushed directory
* structure off of the directory stack and returns it to the calling
* function.
*
* RETURNS
*
* Returns a pointer to the most recently pushed directory structure
* or NULL if the stack is empty.
*/
#ifdef __STDC__
static struct dirinfo *popdir(void)
#else
static struct dirinfo *popdir()
#endif
{
struct dirinfo *tmp;
#ifdef DF_TRACE_DEBUG
printf("DF_TRACE_DEBUG: static struct dirinfo *popdir() in namelist.c\n");
#endif
if (stack_head == (struct dirinfo *)NULL) {
return((struct dirinfo *)NULL);
} else {
tmp = stack_head;
stack_head = stack_head->next;
}
return(tmp);
}