]> Dogcows Code - chaz/tar/blob - src/names.c
Remove lint.
[chaz/tar] / src / names.c
1 /* Various processing of names.
2 Copyright (C) 1988, 92, 94, 96, 97, 98, 1999 Free Software Foundation, Inc.
3
4 This program is free software; you can redistribute it and/or modify it
5 under the terms of the GNU General Public License as published by the
6 Free Software Foundation; either version 2, or (at your option) any later
7 version.
8
9 This program is distributed in the hope that it will be useful, but
10 WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
12 Public License for more details.
13
14 You should have received a copy of the GNU General Public License along
15 with this program; if not, write to the Free Software Foundation, Inc.,
16 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
17
18 /* Enable GNU extensions in fnmatch.h. */
19 #ifndef _GNU_SOURCE
20 # define _GNU_SOURCE 1
21 #endif
22
23 #include "system.h"
24
25 #include <pwd.h>
26 #include <grp.h>
27 #include <fnmatch.h>
28
29 #include "common.h"
30 \f
31 /* User and group names. */
32
33 extern struct group *getgrnam ();
34 extern struct passwd *getpwnam ();
35 #if !HAVE_GETPWUID
36 extern struct passwd *getpwuid ();
37 #endif
38 #if !HAVE_GETGRGID
39 extern struct group *getgrgid ();
40 #endif
41
42 /* Make sure you link with the proper libraries if you are running the
43 Yellow Peril (thanks for the good laugh, Ian J.!), or, euh... NIS.
44 This code should also be modified for non-UNIX systems to do something
45 reasonable. */
46
47 static char cached_uname[UNAME_FIELD_SIZE];
48 static char cached_gname[GNAME_FIELD_SIZE];
49
50 static uid_t cached_uid; /* valid only if cached_uname is not empty */
51 static gid_t cached_gid; /* valid only if cached_gname is not empty */
52
53 /* These variables are valid only if nonempty. */
54 static char cached_no_such_uname[UNAME_FIELD_SIZE];
55 static char cached_no_such_gname[GNAME_FIELD_SIZE];
56
57 /* These variables are valid only if nonzero. It's not worth optimizing
58 the case for weird systems where 0 is not a valid uid or gid. */
59 static uid_t cached_no_such_uid;
60 static gid_t cached_no_such_gid;
61
62 /*------------------------------------------.
63 | Given UID, find the corresponding UNAME. |
64 `------------------------------------------*/
65
66 void
67 uid_to_uname (uid_t uid, char uname[UNAME_FIELD_SIZE])
68 {
69 struct passwd *passwd;
70
71 if (uid != 0 && uid == cached_no_such_uid)
72 {
73 *uname = '\0';
74 return;
75 }
76
77 if (!cached_uname[0] || uid != cached_uid)
78 {
79 passwd = getpwuid (uid);
80 if (passwd)
81 {
82 cached_uid = uid;
83 strncpy (cached_uname, passwd->pw_name, UNAME_FIELD_SIZE);
84 }
85 else
86 {
87 cached_no_such_uid = uid;
88 *uname = '\0';
89 return;
90 }
91 }
92 strncpy (uname, cached_uname, UNAME_FIELD_SIZE);
93 }
94
95 /*------------------------------------------.
96 | Given GID, find the corresponding GNAME. |
97 `------------------------------------------*/
98
99 void
100 gid_to_gname (gid_t gid, char gname[GNAME_FIELD_SIZE])
101 {
102 struct group *group;
103
104 if (gid != 0 && gid == cached_no_such_gid)
105 {
106 *gname = '\0';
107 return;
108 }
109
110 if (!cached_gname[0] || gid != cached_gid)
111 {
112 setgrent (); /* FIXME: why?! */
113 group = getgrgid (gid);
114 if (group)
115 {
116 cached_gid = gid;
117 strncpy (cached_gname, group->gr_name, GNAME_FIELD_SIZE);
118 }
119 else
120 {
121 cached_no_such_gid = gid;
122 *gname = '\0';
123 return;
124 }
125 }
126 strncpy (gname, cached_gname, GNAME_FIELD_SIZE);
127 }
128
129 /*-------------------------------------------------------------------------.
130 | Given UNAME, set the corresponding UID and return 1, or else, return 0. |
131 `-------------------------------------------------------------------------*/
132
133 int
134 uname_to_uid (char uname[UNAME_FIELD_SIZE], uid_t *uidp)
135 {
136 struct passwd *passwd;
137
138 if (cached_no_such_uname[0]
139 && strncmp (uname, cached_no_such_uname, UNAME_FIELD_SIZE) == 0)
140 return 0;
141
142 if (!cached_uname[0]
143 || uname[0] != cached_uname[0]
144 || strncmp (uname, cached_uname, UNAME_FIELD_SIZE) != 0)
145 {
146 passwd = getpwnam (uname);
147 if (passwd)
148 {
149 cached_uid = passwd->pw_uid;
150 strncpy (cached_uname, uname, UNAME_FIELD_SIZE);
151 }
152 else
153 {
154 strncpy (cached_no_such_uname, uname, UNAME_FIELD_SIZE);
155 return 0;
156 }
157 }
158 *uidp = cached_uid;
159 return 1;
160 }
161
162 /*-------------------------------------------------------------------------.
163 | Given GNAME, set the corresponding GID and return 1, or else, return 0. |
164 `-------------------------------------------------------------------------*/
165
166 int
167 gname_to_gid (char gname[GNAME_FIELD_SIZE], gid_t *gidp)
168 {
169 struct group *group;
170
171 if (cached_no_such_gname[0]
172 && strncmp (gname, cached_no_such_gname, GNAME_FIELD_SIZE) == 0)
173 return 0;
174
175 if (!cached_gname[0]
176 || gname[0] != cached_gname[0]
177 || strncmp (gname, cached_gname, GNAME_FIELD_SIZE) != 0)
178 {
179 group = getgrnam (gname);
180 if (group)
181 {
182 cached_gid = group->gr_gid;
183 strncpy (cached_gname, gname, GNAME_FIELD_SIZE);
184 }
185 else
186 {
187 strncpy (cached_no_such_gname, gname, GNAME_FIELD_SIZE);
188 return 0;
189 }
190 }
191 *gidp = cached_gid;
192 return 1;
193 }
194 \f
195 /* Names from the command call. */
196
197 static const char **name_array; /* store an array of names */
198 static int allocated_names; /* how big is the array? */
199 static int names; /* how many entries does it have? */
200 static int name_index; /* how many of the entries have we scanned? */
201
202 /*------------------------.
203 | Initialize structures. |
204 `------------------------*/
205
206 void
207 init_names (void)
208 {
209 allocated_names = 10;
210 name_array = xmalloc (sizeof (const char *) * allocated_names);
211 names = 0;
212 }
213
214 /*--------------------------------------------------------------.
215 | Add NAME at end of name_array, reallocating it as necessary. |
216 `--------------------------------------------------------------*/
217
218 void
219 name_add (const char *name)
220 {
221 if (names == allocated_names)
222 {
223 allocated_names *= 2;
224 name_array =
225 xrealloc (name_array, sizeof (const char *) * allocated_names);
226 }
227 name_array[names++] = name;
228 }
229 \f
230 /* Names from external name file. */
231
232 static FILE *name_file; /* file to read names from */
233 static char *name_buffer; /* buffer to hold the current file name */
234 static size_t name_buffer_length; /* allocated length of name_buffer */
235
236 /*---.
237 | ? |
238 `---*/
239
240 /* FIXME: I should better check more closely. It seems at first glance that
241 is_pattern is only used when reading a file, and ignored for all
242 command line arguments. */
243
244 static inline int
245 is_pattern (const char *string)
246 {
247 return strchr (string, '*') || strchr (string, '[') || strchr (string, '?');
248 }
249
250 /*-----------------------------------------------------------------------.
251 | Set up to gather file names for tar. They can either come from a file |
252 | or were saved from decoding arguments. |
253 `-----------------------------------------------------------------------*/
254
255 void
256 name_init (int argc, char *const *argv)
257 {
258 name_buffer = xmalloc (NAME_FIELD_SIZE + 2);
259 name_buffer_length = NAME_FIELD_SIZE;
260
261 if (files_from_option)
262 {
263 if (!strcmp (files_from_option, "-"))
264 {
265 request_stdin ("-T");
266 name_file = stdin;
267 }
268 else if (name_file = fopen (files_from_option, "r"), !name_file)
269 FATAL_ERROR ((0, errno, _("Cannot open file %s"), files_from_option));
270 }
271 }
272
273 /*---.
274 | ? |
275 `---*/
276
277 void
278 name_term (void)
279 {
280 free (name_buffer);
281 free (name_array);
282 }
283
284 /*---------------------------------------------------------------------.
285 | Read the next filename from name_file and null-terminate it. Put it |
286 | into name_buffer, reallocating and adjusting name_buffer_length if |
287 | necessary. Return 0 at end of file, 1 otherwise. |
288 `---------------------------------------------------------------------*/
289
290 static int
291 read_name_from_file (void)
292 {
293 int character;
294 size_t counter = 0;
295
296 /* FIXME: getc may be called even if character was EOF the last time here. */
297
298 /* FIXME: This + 2 allocation might serve no purpose. */
299
300 while (character = getc (name_file),
301 character != EOF && character != filename_terminator)
302 {
303 if (counter == name_buffer_length)
304 {
305 name_buffer_length += NAME_FIELD_SIZE;
306 name_buffer = xrealloc (name_buffer, name_buffer_length + 2);
307 }
308 name_buffer[counter++] = character;
309 }
310
311 if (counter == 0 && character == EOF)
312 return 0;
313
314 if (counter == name_buffer_length)
315 {
316 name_buffer_length += NAME_FIELD_SIZE;
317 name_buffer = xrealloc (name_buffer, name_buffer_length + 2);
318 }
319 name_buffer[counter] = '\0';
320
321 return 1;
322 }
323
324 /*------------------------------------------------------------------------.
325 | Get the next name from ARGV or the file of names. Result is in static |
326 | storage and can't be relied upon across two calls. |
327 | |
328 | If CHANGE_DIRS is true, treat a filename of the form "-C" as meaning |
329 | that the next filename is the name of a directory to change to. If |
330 | `filename_terminator' is NUL, CHANGE_DIRS is effectively always false. |
331 `------------------------------------------------------------------------*/
332
333 char *
334 name_next (int change_dirs)
335 {
336 const char *source;
337 char *cursor;
338 int chdir_flag = 0;
339
340 if (filename_terminator == '\0')
341 change_dirs = 0;
342
343 while (1)
344 {
345 /* Get a name, either from file or from saved arguments. */
346
347 if (name_file)
348 {
349 if (!read_name_from_file ())
350 break;
351 }
352 else
353 {
354 if (name_index == names)
355 break;
356
357 source = name_array[name_index++];
358 if (strlen (source) > name_buffer_length)
359 {
360 free (name_buffer);
361 name_buffer_length = strlen (source);
362 name_buffer = xmalloc (name_buffer_length + 2);
363 }
364 strcpy (name_buffer, source);
365 }
366
367 /* Zap trailing slashes. */
368
369 cursor = name_buffer + strlen (name_buffer) - 1;
370 while (cursor > name_buffer && *cursor == '/')
371 *cursor-- = '\0';
372
373 if (chdir_flag)
374 {
375 chdir_from_initial_wd (name_buffer);
376 chdir_flag = 0;
377 }
378 else if (change_dirs && strcmp (name_buffer, "-C") == 0)
379 chdir_flag = 1;
380 else
381 {
382 unquote_string (name_buffer);
383 return name_buffer;
384 }
385 }
386
387 /* No more names in file. */
388
389 if (name_file && chdir_flag)
390 FATAL_ERROR ((0, 0, _("Missing file name after -C")));
391
392 return 0;
393 }
394
395 /*------------------------------.
396 | Close the name file, if any. |
397 `------------------------------*/
398
399 void
400 name_close (void)
401 {
402 if (name_file && name_file != stdin)
403 if (fclose (name_file) == EOF)
404 ERROR ((0, errno, "%s", name_buffer));
405 }
406
407 /*-------------------------------------------------------------------------.
408 | Gather names in a list for scanning. Could hash them later if we really |
409 | care. |
410 | |
411 | If the names are already sorted to match the archive, we just read them |
412 | one by one. name_gather reads the first one, and it is called by |
413 | name_match as appropriate to read the next ones. At EOF, the last name |
414 | read is just left in the buffer. This option lets users of small |
415 | machines extract an arbitrary number of files by doing "tar t" and |
416 | editing down the list of files. |
417 `-------------------------------------------------------------------------*/
418
419 void
420 name_gather (void)
421 {
422 /* Buffer able to hold a single name. */
423 static struct name *buffer;
424 static size_t allocated_length;
425
426 char const *name;
427
428 if (same_order_option)
429 {
430 char *change_dir = 0;
431
432 if (allocated_length == 0)
433 {
434 allocated_length = sizeof (struct name) + NAME_FIELD_SIZE;
435 buffer = xmalloc (allocated_length);
436 /* FIXME: This memset is overkill, and ugly... */
437 memset (buffer, 0, allocated_length);
438 }
439
440 while ((name = name_next (0)) && strcmp (name, "-C") == 0)
441 {
442 char const *dir = name_next (0);
443 if (! dir)
444 FATAL_ERROR ((0, 0, _("Missing file name after -C")));
445 if (change_dir)
446 free (change_dir);
447 change_dir = xstrdup (dir);
448 }
449
450 if (name)
451 {
452 buffer->length = strlen (name);
453 if (sizeof (struct name) + buffer->length >= allocated_length)
454 {
455 allocated_length = sizeof (struct name) + buffer->length;
456 buffer = xrealloc (buffer, allocated_length);
457 }
458 buffer->change_dir = change_dir;
459 strncpy (buffer->name, name, buffer->length);
460 buffer->name[buffer->length] = 0;
461 buffer->next = 0;
462 buffer->found = 0;
463
464 /* FIXME: Poorly named globals, indeed... */
465 namelist = buffer;
466 namelast = namelist;
467 }
468 else if (change_dir)
469 free (change_dir);
470
471 return;
472 }
473
474 /* Non sorted names -- read them all in. */
475
476 for (;;)
477 {
478 char *change_dir = 0;
479 while ((name = name_next (0)) && strcmp (name, "-C") == 0)
480 {
481 char const *dir = name_next (0);
482 if (! dir)
483 FATAL_ERROR ((0, 0, _("Missing file name after -C")));
484 if (change_dir)
485 free (change_dir);
486 change_dir = xstrdup (dir);
487 }
488 if (name)
489 addname (name, change_dir);
490 else
491 {
492 if (change_dir)
493 addname (0, change_dir);
494 break;
495 }
496 }
497 }
498
499 /*-----------------------------.
500 | Add a name to the namelist. |
501 `-----------------------------*/
502
503 void
504 addname (char const *string, char const *change_dir)
505 {
506 struct name *name;
507 size_t length;
508
509 length = string ? strlen (string) : 0;
510 name = xmalloc (sizeof (struct name) + length);
511 memset (name, 0, sizeof (struct name) + length);
512 name->next = 0;
513
514 if (string)
515 {
516 name->fake = 0;
517 name->length = length;
518 memcpy (name->name, string, length + 1);
519 }
520 else
521 name->fake = 1;
522
523 name->found = 0;
524 name->regexp = 0; /* assume not a regular expression */
525 name->firstch = 1; /* assume first char is literal */
526 name->change_dir = change_dir;
527 name->dir_contents = 0;
528
529 if (string && is_pattern (string))
530 {
531 name->regexp = 1;
532 if (string[0] == '*' || string[0] == '[' || string[0] == '?')
533 name->firstch = 0;
534 }
535
536 if (namelast)
537 namelast->next = name;
538 namelast = name;
539 if (!namelist)
540 namelist = name;
541 }
542
543 /*------------------------------------------------------------------------.
544 | Return true if and only if name PATH (from an archive) matches any name |
545 | from the namelist. |
546 `------------------------------------------------------------------------*/
547
548 int
549 name_match (const char *path)
550 {
551 size_t length = strlen (path);
552 char const *change_dir = 0;
553
554 while (1)
555 {
556 struct name *cursor = namelist;
557
558 if (!cursor)
559 return ! files_from_option;
560
561 if (cursor->fake)
562 {
563 chdir_from_initial_wd (cursor->change_dir);
564 namelist = 0;
565 return ! files_from_option;
566 }
567
568 for (; cursor; cursor = cursor->next)
569 {
570 if (cursor->change_dir)
571 change_dir = cursor->change_dir;
572
573 /* If first chars don't match, quick skip. */
574
575 if (cursor->firstch && cursor->name[0] != path[0])
576 continue;
577
578 if (cursor->regexp
579 ? fnmatch (cursor->name, path, FNM_LEADING_DIR) == 0
580 : (cursor->length <= length
581 && (path[cursor->length] == '\0'
582 || path[cursor->length] == '/')
583 && memcmp (path, cursor->name, cursor->length) == 0))
584 {
585 cursor->found = 1; /* remember it matched */
586 if (starting_file_option)
587 {
588 free (namelist);
589 namelist = 0;
590 }
591 chdir_from_initial_wd (change_dir);
592
593 /* We got a match. */
594 return 1;
595 }
596 }
597
598 /* Filename from archive not found in namelist. If we have the whole
599 namelist here, just return 0. Otherwise, read the next name in and
600 compare it. If this was the last name, namelist->found will remain
601 on. If not, we loop to compare the newly read name. */
602
603 if (same_order_option && namelist->found)
604 {
605 name_gather (); /* read one more */
606 if (namelist->found)
607 return 0;
608 }
609 else
610 return 0;
611 }
612 }
613
614 /*------------------------------------------------------------------.
615 | Print the names of things in the namelist that were not matched. |
616 `------------------------------------------------------------------*/
617
618 void
619 names_notfound (void)
620 {
621 struct name *cursor;
622 struct name *next;
623
624 for (cursor = namelist; cursor; cursor = next)
625 {
626 next = cursor->next;
627 if (!cursor->found && !cursor->fake)
628 ERROR ((0, 0, _("%s: Not found in archive"), cursor->name));
629
630 /* We could free the list, but the process is about to die anyway, so
631 save some CPU time. Amigas and other similarly broken software
632 will need to waste the time, though. */
633
634 #ifdef amiga
635 if (!same_order_option)
636 free (cursor);
637 #endif
638 }
639 namelist = 0;
640 namelast = 0;
641
642 if (same_order_option)
643 {
644 char *name;
645
646 while (name = name_next (1), name)
647 ERROR ((0, 0, _("%s: Not found in archive"), name));
648 }
649 }
650
651 /*---.
652 | ? |
653 `---*/
654
655 void
656 name_expand (void)
657 {
658 }
659
660 /*-------------------------------------------------------------------------.
661 | This is like name_match, except that it returns a pointer to the name it |
662 | matched, and doesn't set FOUND in structure. The caller will have to do |
663 | that if it wants to. Oh, and if the namelist is empty, it returns null, |
664 | unlike name_match, which returns TRUE. |
665 `-------------------------------------------------------------------------*/
666
667 struct name *
668 name_scan (const char *path)
669 {
670 size_t length = strlen (path);
671
672 while (1)
673 {
674 struct name *cursor = namelist;
675
676 if (!cursor)
677 return 0;
678
679 for (; cursor; cursor = cursor->next)
680 {
681 /* If first chars don't match, quick skip. */
682
683 if (cursor->firstch && cursor->name[0] != path[0])
684 continue;
685
686 if (cursor->regexp
687 ? fnmatch (cursor->name, path, FNM_LEADING_DIR) == 0
688 : (cursor->length <= length
689 && (path[cursor->length] == '\0'
690 || path[cursor->length] == '/')
691 && memcmp (path, cursor->name, cursor->length) == 0))
692 return cursor; /* we got a match */
693 }
694
695 /* Filename from archive not found in namelist. If we have the whole
696 namelist here, just return 0. Otherwise, read the next name in and
697 compare it. If this was the last name, namelist->found will remain
698 on. If not, we loop to compare the newly read name. */
699
700 if (same_order_option && namelist->found)
701 {
702 name_gather (); /* read one more */
703 if (namelist->found)
704 return 0;
705 }
706 else
707 return 0;
708 }
709 }
710
711 /*-----------------------------------------------------------------------.
712 | This returns a name from the namelist which doesn't have ->found set. |
713 | It sets ->found before returning, so successive calls will find and |
714 | return all the non-found names in the namelist |
715 `-----------------------------------------------------------------------*/
716
717 struct name *gnu_list_name;
718
719 char *
720 name_from_list (void)
721 {
722 if (!gnu_list_name)
723 gnu_list_name = namelist;
724 while (gnu_list_name && gnu_list_name->found)
725 gnu_list_name = gnu_list_name->next;
726 if (gnu_list_name)
727 {
728 gnu_list_name->found = 1;
729 chdir_from_initial_wd (gnu_list_name->change_dir);
730 return gnu_list_name->name;
731 }
732 return 0;
733 }
734
735 /*---.
736 | ? |
737 `---*/
738
739 void
740 blank_name_list (void)
741 {
742 struct name *name;
743
744 gnu_list_name = 0;
745 for (name = namelist; name; name = name->next)
746 name->found = 0;
747 }
748
749 /*---.
750 | ? |
751 `---*/
752
753 char *
754 new_name (const char *path, const char *name)
755 {
756 char *buffer = xmalloc (strlen (path) + strlen (name) + 2);
757
758 sprintf (buffer, "%s/%s", path, name);
759 return buffer;
760 }
761
762 /* Return nonzero if file NAME is excluded. Exclude a name if its
763 prefix matches a pattern that contains slashes, or if one of its
764 components matches a pattern that contains no slashes. */
765 int
766 excluded_name (char const *name)
767 {
768 char const *p;
769 name += FILESYSTEM_PREFIX_LEN (name);
770
771 if (excluded_filename (excluded_with_slash, name,
772 FNM_FILE_NAME | FNM_LEADING_DIR))
773 return 1;
774
775 for (p = name; *p; p++)
776 if ((p == name || (ISSLASH (p[-1]) && !ISSLASH (p[0])))
777 && excluded_filename (excluded_without_slash, p,
778 FNM_FILE_NAME | FNM_LEADING_DIR))
779 return 1;
780
781 return 0;
782 }
This page took 0.076262 seconds and 5 git commands to generate.