Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
/* $Source: /u/mark/src/pax/RCS/namelist.c,v $
2
 *
3
 * $Revision: 1.6 $
4
 *
5
 * namelist.c - track filenames given as arguments to tar/cpio/pax
6
 *
7
 * DESCRIPTION
8
 *
9
 *	Arguments may be regular expressions, therefore all agurments will
10
 *	be treated as if they were regular expressions, even if they are
11
 *	not.
12
 *
13
 * AUTHOR
14
 *
15
 *	Mark H. Colburn, NAPS International (mark@jhereg.mn.org)
16
 *
17
 * Sponsored by The USENIX Association for public distribution. 
18
 *
19
 * Copyright (c) 1989 Mark H. Colburn.
20
 * All rights reserved.
21
 *
22
 * Redistribution and use in source and binary forms are permitted
23
 * provided that the above copyright notice is duplicated in all such 
24
 * forms and that any documentation, advertising materials, and other 
25
 * materials related to such distribution and use acknowledge that the 
26
 * software was developed by Mark H. Colburn and sponsored by The 
27
 * USENIX Association. 
28
 *
29
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
30
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
31
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
32
 *
33
 * $Log:	namelist.c,v $
34
 * Revision 1.6  89/02/13  09:14:48  mark
35
 * Fixed problem with directory errors
36
 * 
37
 * Revision 1.5  89/02/12  12:14:00  mark
38
 * Fixed misspellings
39
 * 
40
 * Revision 1.4  89/02/12  11:25:19  mark
41
 * Modifications to compile and link cleanly under USG
42
 * 
43
 * Revision 1.3  89/02/12  10:40:23  mark
44
 * Fixed casting problems
45
 * 
46
 * Revision 1.2  89/02/12  10:04:57  mark
47
 * 1.2 release fixes
48
 * 
49
 * Revision 1.1  88/12/23  18:02:17  mark
50
 * Initial revision
51
 * 
52
 */
53
 
54
#ifndef lint
55
static char *ident = "$Id: namelist.c,v 1.6 89/02/13 09:14:48 mark Exp $";
56
static char *copyright = "Copyright (c) 1989 Mark H. Colburn.\nAll rights reserved.\n";
57
#endif /* ! lint */
58
 
59
 
60
/* Headers */
61
 
62
#include "pax.h"
63
 
64
 
65
/* Type Definitions */
66
 
67
/*
68
 * Structure for keeping track of filenames and lists thereof. 
69
 */
70
struct nm_list {
71
    struct nm_list *next;
72
    short           length;	/* cached strlen(name) */
73
    char            found;	/* A matching file has been found */
74
    char            firstch;	/* First char is literally matched */
75
    char            re;		/* regexp pattern for item */
76
    char            name[1];	/* name of file or rexexp */
77
};
78
 
79
struct dirinfo {
80
    char            dirname[PATH_MAX + 1];	/* name of directory */
81
    OFFSET	    where;	/* current location in directory */
82
    struct dirinfo *next;
83
};
84
 
85
 
86
/* Static Variables */
87
 
88
static struct dirinfo *stack_head = (struct dirinfo *)NULL;
89
 
90
 
91
/* Function Prototypes */
92
 
93
#ifndef __STDC__
94
 
95
static void pushdir();
96
static struct dirinfo *popdir();
97
 
98
#else
99
 
100
static void pushdir(struct dirinfo *info);
101
static struct dirinfo *popdir(void);
102
 
103
#endif
104
 
105
 
106
/* Internal Identifiers */
107
 
108
static struct nm_list *namelast;	/* Points to last name in list */
109
static struct nm_list *namelist;	/* Points to first name in list */
110
 
111
 
112
/* addname -  add a name to the namelist. 
113
 *
114
 * DESCRIPTION
115
 *
116
 *	Addname adds the name given to the name list.  Memory for the
117
 *	namelist structure is dynamically allocated.  If the space for 
118
 *	the structure cannot be allocated, then the program will exit
119
 *	the an out of memory error message and a non-zero return code
120
 *	will be returned to the caller.
121
 *
122
 * PARAMETERS
123
 *
124
 *	char *name	- A pointer to the name to add to the list
125
 */
126
 
127
#ifdef __STDC__
128
 
129
void add_name(char *name)
130
 
131
#else
132
 
133
void add_name(name)
134
char           *name;		/* pointer to name */
135
 
136
#endif
137
{
138
    int             i;		/* Length of string */
139
    struct nm_list *p;		/* Current struct pointer */
140
 
141
    i = strlen(name);
142
    p = (struct nm_list *) malloc((unsigned) (i + sizeof(struct nm_list)));
143
    if (!p) {
144
	fatal("cannot allocate memory for namelist entry\n");
145
    }
146
    p->next = (struct nm_list *)NULL;
147
    p->length = i;
148
    strncpy(p->name, name, i);
149
    p->name[i] = '\0';		/* Null term */
150
    p->found = 0;
151
    p->firstch = isalpha(name[0]);
152
    if (strchr(name, '*') || strchr(name, '[') || strchr(name, '?')) {
153
        p->re = 1;
154
    }
155
    if (namelast) {
156
	namelast->next = p;
157
    }
158
    namelast = p;
159
    if (!namelist) {
160
	namelist = p;
161
    }
162
}
163
 
164
 
165
/* name_match - match a name from an archive with a name from the namelist 
166
 *
167
 * DESCRIPTION
168
 *
169
 *	Name_match attempts to find a name pointed at by p in the namelist.
170
 *	If no namelist is available, then all filenames passed in are
171
 *	assumed to match the filename criteria.  Name_match knows how to
172
 *	match names with regular expressions, etc.
173
 *
174
 * PARAMETERS
175
 *
176
 *	char	*p	- the name to match
177
 *
178
 * RETURNS
179
 *
180
 *	Returns 1 if the name is in the namelist, or no name list is
181
 *	available, otherwise returns 0
182
 *
183
 */
184
 
185
#ifdef __STDC__
186
 
187
int name_match(char *p)
188
 
189
#else
190
 
191
int name_match(p)
192
char           *p;
193
 
194
#endif
195
{
196
    struct nm_list *nlp;
197
    int             len;
198
 
199
    if ((nlp = namelist) == 0) {/* Empty namelist is easy */
200
	return (1);
201
    }
202
    len = strlen(p);
203
    for (; nlp != 0; nlp = nlp->next) {
204
	/* If first chars don't match, quick skip */
205
	if (nlp->firstch && nlp->name[0] != p[0]) {
206
	    continue;
207
	}
208
	/* Regular expressions */
209
	if (nlp->re) {
210
	    if (wildmat(nlp->name, p)) {
211
		nlp->found = 1;	/* Remember it matched */
212
		return (1);	/* We got a match */
213
	    }
214
	    continue;
215
	}
216
	/* Plain Old Strings */
217
	if (nlp->length <= len	/* Archive len >= specified */
218
	    && (p[nlp->length] == '\0' || p[nlp->length] == '/')
219
	    && strncmp(p, nlp->name, nlp->length) == 0) {
220
	    /* Name compare */
221
	    nlp->found = 1;	/* Remember it matched */
222
	    return (1);		/* We got a match */
223
	}
224
    }
225
    return (0);
226
}
227
 
228
 
229
/* names_notfound - print names of files in namelist that were not found 
230
 *
231
 * DESCRIPTION
232
 *
233
 *	Names_notfound scans through the namelist for any files which were
234
 *	named, but for which a matching file was not processed by the
235
 *	archive.  Each of the files is listed on the standard error.
236
 *
237
 */
238
 
239
#ifdef __STDC__
240
 
241
void names_notfound(void)
242
 
243
#else
244
 
245
void names_notfound()
246
 
247
#endif
248
{
249
    struct nm_list *nlp;
250
 
251
    for (nlp = namelist; nlp != 0; nlp = nlp->next) {
252
	if (!nlp->found) {
253
	    fprintf(stderr, "%s: %s not found in archive\n",
254
	            myname, nlp->name);
255
	}
256
	free(nlp);
257
    }
258
    namelist = (struct nm_list *)NULL;
259
    namelast = (struct nm_list *)NULL;
260
}
261
 
262
 
263
/* name_init - set up to gather file names 
264
 *
265
 * DESCRIPTION
266
 *
267
 *	Name_init sets up the namelist pointers so that we may access the
268
 *	command line arguments.  At least the first item of the command
269
 *	line (argv[0]) is assumed to be stripped off, prior to the
270
 *	name_init call.
271
 *
272
 * PARAMETERS
273
 *
274
 *	int	argc	- number of items in argc
275
 *	char	**argv	- pointer to the command line arguments
276
 */
277
 
278
#ifdef __STDC__
279
 
280
void name_init(int argc, char **argv)
281
 
282
#else
283
 
284
void name_init(argc, argv)
285
int             argc;
286
char          **argv;
287
 
288
#endif
289
{
290
    /* Get file names from argv, after options. */
291
    n_argc = argc;
292
    n_argv = argv;
293
}
294
 
295
 
296
/* name_next - get the next name from argv or the name file. 
297
 *
298
 * DESCRIPTION
299
 *
300
 *	Name next finds the next name which is to be processed in the
301
 *	archive.  If the named file is a directory, then the directory
302
 *	is recursively traversed for additional file names.  Directory
303
 *	names and locations within the directory are kept track of by
304
 *	using a directory stack.  See the pushdir/popdir function for
305
 *	more details.
306
 *
307
 * 	The names come from argv, after options or from the standard input.  
308
 *
309
 * PARAMETERS
310
 *
311
 *	name - a pointer to a buffer of at least MAX_PATH + 1 bytes long;
312
 *	statbuf - a pointer to a stat structure
313
 *
314
 * RETURNS
315
 *
316
 *	Returns -1 if there are no names left, (e.g. EOF), otherwise returns 
317
 *	0 
318
 */
319
 
320
#ifdef __STDC__
321
 
322
int name_next(char *name, Stat *statbuf)
323
 
324
#else
325
 
326
int name_next(name, statbuf)
327
char           *name;
328
Stat           *statbuf;
329
 
330
#endif
331
{
332
    int             err = -1;
333
    static int      in_subdir = 0;
334
    static DIR     *dirp;
335
    struct dirent  *d;
336
    static struct dirinfo *curr_dir;
337
    int			len;
338
 
339
    do {
340
	if (names_from_stdin) {
341
	    if (lineget(stdin, name) < 0) {
342
		return (-1);
343
	    }
344
	    if (nameopt(name) < 0) {
345
		continue;
346
	    }
347
	} else {
348
	    if (in_subdir) {
349
		if ((d = readdir(dirp)) != (struct dirent *)NULL) {
350
		    /* Skip . and .. */
351
		    if (strcmp(d->d_name, ".") == 0 ||
352
		        strcmp(d->d_name, "..") == 0) {
353
			    continue;
354
		    }
355
		    if (strlen(d->d_name) + 
356
			strlen(curr_dir->dirname) >= PATH_MAX) {
357
			warn("name too long", d->d_name);
358
			continue;
359
		    }
360
		    strcpy(name, curr_dir->dirname);
361
		    strcat(name, d->d_name);
362
		} else {
363
		    closedir(dirp);
364
		    in_subdir--;
365
		    curr_dir = popdir();
366
		    if (in_subdir) {
367
			errno = 0;
368
			if ((dirp=opendir(curr_dir->dirname)) == (DIR *)NULL) {
369
			    warn(curr_dir->dirname, "error opening directory (1)");
370
			    in_subdir--;
371
			}
372
			seekdir(dirp, curr_dir->where);
373
		    }
374
		    continue;
375
		}
376
	    } else if (optind >= n_argc) {
377
		return (-1);
378
	    } else {
379
		strcpy(name, n_argv[optind++]);
380
	    }
381
	}
382
	if ((err = LSTAT(name, statbuf)) < 0) {
383
	    warn(name, strerror());
384
	    continue;
385
	}
386
	if (!names_from_stdin && (statbuf->sb_mode & S_IFMT) == S_IFDIR) {
387
	    if (in_subdir) {
388
		curr_dir->where = telldir(dirp);
389
		pushdir(curr_dir);
390
		closedir(dirp);
391
	    } 
392
	    in_subdir++;
393
 
394
	    /* Build new prototype name */
395
	    if ((curr_dir = (struct dirinfo *) mem_get(sizeof(struct dirinfo))) 
396
			  == (struct dirinfo *)NULL) {
397
		exit(2);
398
	    }
399
	    strcpy(curr_dir->dirname, name);
400
	    len = strlen(curr_dir->dirname);
401
	    while (len >= 1 && curr_dir->dirname[len - 1] == '/') {
402
		len--;		/* Delete trailing slashes */
403
	    }
404
	    curr_dir->dirname[len++] = '/';	/* Now add exactly one back */
405
	    curr_dir->dirname[len] = '\0';/* Make sure null-terminated */
406
            curr_dir->where = 0;
407
 
408
            errno = 0;
409
            do {
410
                if ((dirp = opendir(curr_dir->dirname)) == (DIR *)NULL) {
411
                     warn(curr_dir->dirname, "error opening directory (2)");
412
                     if (in_subdir > 1) {
413
                          curr_dir = popdir();
414
                     }
415
                     in_subdir--;
416
                     err = -1;
417
                     continue;
418
                } else {
419
                     seekdir(dirp, curr_dir->where);
420
		}
421
	    } while (in_subdir && (! dirp));
422
	}
423
    } while (err < 0);
424
    return (0);
425
}
426
 
427
 
428
/* name_gather - gather names in a list for scanning. 
429
 *
430
 * DESCRIPTION
431
 *
432
 *	Name_gather takes names from the command line and adds them to
433
 *	the name list.
434
 *
435
 * FIXME
436
 *
437
 * 	We could hash the names if we really care about speed here.
438
 */
439
 
440
#ifdef __STDC__
441
 
442
void name_gather(void)
443
 
444
#else
445
 
446
void name_gather()
447
 
448
#endif
449
{
450
     while (optind < n_argc) { 
451
	 add_name(n_argv[optind++]); 
452
     } 
453
}
454
 
455
 
456
/* pushdir - pushes a directory name on the directory stack
457
 *
458
 * DESCRIPTION
459
 *
460
 *	The pushdir function puses the directory structure which is pointed
461
 *	to by "info" onto a stack for later processing.  The information
462
 *	may be retrieved later with a call to popdir().
463
 *
464
 * PARAMETERS
465
 *
466
 *	dirinfo	*info	- pointer to directory structure to save
467
 */
468
 
469
#ifdef __STDC__
470
 
471
static void pushdir(struct dirinfo *info)
472
 
473
#else
474
 
475
static void pushdir(info)
476
struct dirinfo	*info;
477
 
478
#endif
479
{
480
    if  (stack_head == (struct dirinfo *)NULL) {
481
	stack_head = info;
482
	stack_head->next = (struct dirinfo *)NULL;
483
    } else {
484
	info->next = stack_head;
485
	stack_head = info;
486
    } 
487
}
488
 
489
 
490
/* popdir - pop a directory structure off the directory stack.
491
 *
492
 * DESCRIPTION
493
 *
494
 *	The popdir function pops the most recently pushed directory
495
 *	structure off of the directory stack and returns it to the calling
496
 *	function.
497
 *
498
 * RETURNS
499
 *
500
 *	Returns a pointer to the most recently pushed directory structure
501
 *	or NULL if the stack is empty.
502
 */
503
 
504
#ifdef __STDC__
505
 
506
static struct dirinfo *popdir(void)
507
 
508
#else
509
 
510
static struct dirinfo *popdir()
511
 
512
#endif
513
{
514
    struct dirinfo	*tmp;
515
 
516
    if (stack_head == (struct dirinfo *)NULL) {
517
	return((struct dirinfo *)NULL);
518
    } else {
519
	tmp = stack_head;
520
	stack_head = stack_head->next;
521
    }
522
    return(tmp);
523
}