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
add_name(char * name)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
name_match(char * p)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
names_notfound(void)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
name_init(int argc,char ** argv)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
name_next(char * name,Stat * statbuf)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
name_gather(void)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
pushdir(struct dirinfo * info)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
popdir(void)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 }
524