]> Dogcows Code - chaz/tar/blob - src/names.c
(_GNU_SOURCE): Define.
[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 = 0;
60 static gid_t cached_no_such_gid = 0;
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 = 0; /* 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 = (const char **)
211 xmalloc (sizeof (const char *) * allocated_names);
212 names = 0;
213 }
214
215 /*--------------------------------------------------------------.
216 | Add NAME at end of name_array, reallocating it as necessary. |
217 `--------------------------------------------------------------*/
218
219 void
220 name_add (const char *name)
221 {
222 if (names == allocated_names)
223 {
224 allocated_names *= 2;
225 name_array = (const char **)
226 xrealloc (name_array, sizeof (const char *) * allocated_names);
227 }
228 name_array[names++] = name;
229 }
230 \f
231 /* Names from external name file. */
232
233 static FILE *name_file; /* file to read names from */
234 static char *name_buffer; /* buffer to hold the current file name */
235 static size_t name_buffer_length; /* allocated length of name_buffer */
236
237 /*---.
238 | ? |
239 `---*/
240
241 /* FIXME: I should better check more closely. It seems at first glance that
242 is_pattern is only used when reading a file, and ignored for all
243 command line arguments. */
244
245 static inline int
246 is_pattern (const char *string)
247 {
248 return strchr (string, '*') || strchr (string, '[') || strchr (string, '?');
249 }
250
251 /*-----------------------------------------------------------------------.
252 | Set up to gather file names for tar. They can either come from a file |
253 | or were saved from decoding arguments. |
254 `-----------------------------------------------------------------------*/
255
256 void
257 name_init (int argc, char *const *argv)
258 {
259 name_buffer = xmalloc (NAME_FIELD_SIZE + 2);
260 name_buffer_length = NAME_FIELD_SIZE;
261
262 if (files_from_option)
263 {
264 if (!strcmp (files_from_option, "-"))
265 {
266 request_stdin ("-T");
267 name_file = stdin;
268 }
269 else if (name_file = fopen (files_from_option, "r"), !name_file)
270 FATAL_ERROR ((0, errno, _("Cannot open file %s"), files_from_option));
271 }
272 }
273
274 /*---.
275 | ? |
276 `---*/
277
278 void
279 name_term (void)
280 {
281 free (name_buffer);
282 free (name_array);
283 }
284
285 /*---------------------------------------------------------------------.
286 | Read the next filename from name_file and null-terminate it. Put it |
287 | into name_buffer, reallocating and adjusting name_buffer_length if |
288 | necessary. Return 0 at end of file, 1 otherwise. |
289 `---------------------------------------------------------------------*/
290
291 static int
292 read_name_from_file (void)
293 {
294 int character;
295 size_t counter = 0;
296
297 /* FIXME: getc may be called even if character was EOF the last time here. */
298
299 /* FIXME: This + 2 allocation might serve no purpose. */
300
301 while (character = getc (name_file),
302 character != EOF && character != filename_terminator)
303 {
304 if (counter == name_buffer_length)
305 {
306 name_buffer_length += NAME_FIELD_SIZE;
307 name_buffer = xrealloc (name_buffer, name_buffer_length + 2);
308 }
309 name_buffer[counter++] = character;
310 }
311
312 if (counter == 0 && character == EOF)
313 return 0;
314
315 if (counter == name_buffer_length)
316 {
317 name_buffer_length += NAME_FIELD_SIZE;
318 name_buffer = xrealloc (name_buffer, name_buffer_length + 2);
319 }
320 name_buffer[counter] = '\0';
321
322 return 1;
323 }
324
325 /*------------------------------------------------------------------------.
326 | Get the next name from ARGV or the file of names. Result is in static |
327 | storage and can't be relied upon across two calls. |
328 | |
329 | If CHANGE_DIRS is true, treat a filename of the form "-C" as meaning |
330 | that the next filename is the name of a directory to change to. If |
331 | `filename_terminator' is NUL, CHANGE_DIRS is effectively always false. |
332 `------------------------------------------------------------------------*/
333
334 char *
335 name_next (int change_dirs)
336 {
337 const char *source;
338 char *cursor;
339 int chdir_flag = 0;
340
341 if (filename_terminator == '\0')
342 change_dirs = 0;
343
344 while (1)
345 {
346 /* Get a name, either from file or from saved arguments. */
347
348 if (name_file)
349 {
350 if (!read_name_from_file ())
351 break;
352 }
353 else
354 {
355 if (name_index == names)
356 break;
357
358 source = name_array[name_index++];
359 if (strlen (source) > name_buffer_length)
360 {
361 free (name_buffer);
362 name_buffer_length = strlen (source);
363 name_buffer = xmalloc (name_buffer_length + 2);
364 }
365 strcpy (name_buffer, source);
366 }
367
368 /* Zap trailing slashes. */
369
370 cursor = name_buffer + strlen (name_buffer) - 1;
371 while (cursor > name_buffer && *cursor == '/')
372 *cursor-- = '\0';
373
374 if (chdir_flag)
375 {
376 if (chdir (name_buffer) < 0)
377 FATAL_ERROR ((0, errno, _("Cannot change to directory %s"),
378 name_buffer));
379 chdir_flag = 0;
380 }
381 else if (change_dirs && strcmp (name_buffer, "-C") == 0)
382 chdir_flag = 1;
383 else
384 {
385 unquote_string (name_buffer);
386 return name_buffer;
387 }
388 }
389
390 /* No more names in file. */
391
392 if (name_file && chdir_flag)
393 FATAL_ERROR ((0, 0, _("Missing file name after -C")));
394
395 return NULL;
396 }
397
398 /*------------------------------.
399 | Close the name file, if any. |
400 `------------------------------*/
401
402 void
403 name_close (void)
404 {
405 if (name_file != NULL && name_file != stdin)
406 if (fclose (name_file) == EOF)
407 ERROR ((0, errno, "%s", name_buffer));
408 }
409
410 /*-------------------------------------------------------------------------.
411 | Gather names in a list for scanning. Could hash them later if we really |
412 | care. |
413 | |
414 | If the names are already sorted to match the archive, we just read them |
415 | one by one. name_gather reads the first one, and it is called by |
416 | name_match as appropriate to read the next ones. At EOF, the last name |
417 | read is just left in the buffer. This option lets users of small |
418 | machines extract an arbitrary number of files by doing "tar t" and |
419 | editing down the list of files. |
420 `-------------------------------------------------------------------------*/
421
422 void
423 name_gather (void)
424 {
425 /* Buffer able to hold a single name. */
426 static struct name *buffer;
427 static size_t allocated_length = 0;
428
429 char *name;
430
431 if (same_order_option)
432 {
433 if (allocated_length == 0)
434 {
435 allocated_length = sizeof (struct name) + NAME_FIELD_SIZE;
436 buffer = (struct name *) xmalloc (allocated_length);
437 /* FIXME: This memset is overkill, and ugly... */
438 memset (buffer, 0, allocated_length);
439 }
440 name = name_next (0);
441 if (name)
442 {
443 if (strcmp (name, "-C") == 0)
444 {
445 char *copy = xstrdup (name_next (0));
446
447 name = name_next (0);
448 if (!name)
449 FATAL_ERROR ((0, 0, _("Missing file name after -C")));
450 buffer->change_dir = copy;
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 = (struct name *) xrealloc (buffer, allocated_length);
457 }
458 strncpy (buffer->name, name, (size_t) buffer->length);
459 buffer->name[buffer->length] = 0;
460 buffer->next = NULL;
461 buffer->found = 0;
462
463 /* FIXME: Poorly named globals, indeed... */
464 namelist = buffer;
465 namelast = namelist;
466 }
467 return;
468 }
469
470 /* Non sorted names -- read them all in. */
471
472 while (name = name_next (0), name)
473 addname (name);
474 }
475
476 /*-----------------------------.
477 | Add a name to the namelist. |
478 `-----------------------------*/
479
480 void
481 addname (const char *string)
482 {
483 /* FIXME: This is ugly. How is memory managed? */
484 static char *chdir_name = NULL;
485
486 struct name *name;
487 size_t length;
488
489 if (strcmp (string, "-C") == 0)
490 {
491 chdir_name = xstrdup (name_next (0));
492 string = name_next (0);
493 if (!chdir_name)
494 FATAL_ERROR ((0, 0, _("Missing file name after -C")));
495
496 if (chdir_name[0] != '/')
497 {
498 char *path = xmalloc (PATH_MAX);
499
500 /* FIXME: Shouldn't we use xgetcwd? */
501 #if HAVE_GETCWD
502 if (!getcwd (path, PATH_MAX))
503 FATAL_ERROR ((0, 0, _("Could not get current directory")));
504 #else
505 char *getwd ();
506
507 if (!getwd (path))
508 FATAL_ERROR ((0, 0, _("Could not get current directory: %s"),
509 path));
510 #endif
511 chdir_name = new_name (path, chdir_name);
512 free (path);
513 }
514 }
515
516 length = string ? strlen (string) : 0;
517 name = (struct name *) xmalloc (sizeof (struct name) + length);
518 memset (name, 0, sizeof (struct name) + length);
519 name->next = NULL;
520
521 if (string)
522 {
523 name->fake = 0;
524 name->length = length;
525 /* FIXME: Possibly truncating a string, here? Tss, tss, tss! */
526 strncpy (name->name, string, length);
527 name->name[length] = '\0';
528 }
529 else
530 name->fake = 1;
531
532 name->found = 0;
533 name->regexp = 0; /* assume not a regular expression */
534 name->firstch = 1; /* assume first char is literal */
535 name->change_dir = chdir_name;
536 name->dir_contents = 0;
537
538 if (string && is_pattern (string))
539 {
540 name->regexp = 1;
541 if (string[0] == '*' || string[0] == '[' || string[0] == '?')
542 name->firstch = 0;
543 }
544
545 if (namelast)
546 namelast->next = name;
547 namelast = name;
548 if (!namelist)
549 namelist = name;
550 }
551
552 /*------------------------------------------------------------------------.
553 | Return true if and only if name PATH (from an archive) matches any name |
554 | from the namelist. |
555 `------------------------------------------------------------------------*/
556
557 int
558 name_match (const char *path)
559 {
560 size_t length = strlen (path);
561
562 while (1)
563 {
564 struct name *cursor = namelist;
565
566 if (!cursor)
567 return 1; /* empty namelist is easy */
568
569 if (cursor->fake)
570 {
571 if (cursor->change_dir && chdir (cursor->change_dir))
572 FATAL_ERROR ((0, errno, _("Cannot change to directory %s"),
573 cursor->change_dir));
574 namelist = 0;
575 return 1;
576 }
577
578 for (; cursor; cursor = cursor->next)
579 {
580 /* If first chars don't match, quick skip. */
581
582 if (cursor->firstch && cursor->name[0] != path[0])
583 continue;
584
585 /* Regular expressions (shell globbing, actually). */
586
587 if (cursor->regexp)
588 {
589 if (fnmatch (cursor->name, path, FNM_LEADING_DIR) == 0)
590 {
591 cursor->found = 1; /* remember it matched */
592 if (starting_file_option)
593 {
594 free (namelist);
595 namelist = NULL;
596 }
597 if (cursor->change_dir && chdir (cursor->change_dir))
598 FATAL_ERROR ((0, errno, _("Cannot change to directory %s"),
599 cursor->change_dir));
600
601 /* We got a match. */
602 return 1;
603 }
604 continue;
605 }
606
607 /* Plain Old Strings. */
608
609 if (cursor->length <= length
610 /* archive length >= specified */
611 && (path[cursor->length] == '\0'
612 || path[cursor->length] == '/')
613 /* full match on file/dirname */
614 && strncmp (path, cursor->name, cursor->length) == 0)
615 /* name compare */
616 {
617 cursor->found = 1; /* remember it matched */
618 if (starting_file_option)
619 {
620 free ((void *) namelist);
621 namelist = 0;
622 }
623 if (cursor->change_dir && chdir (cursor->change_dir))
624 FATAL_ERROR ((0, errno, _("Cannot change to directory %s"),
625 cursor->change_dir));
626
627 /* We got a match. */
628 return 1;
629 }
630 }
631
632 /* Filename from archive not found in namelist. If we have the whole
633 namelist here, just return 0. Otherwise, read the next name in and
634 compare it. If this was the last name, namelist->found will remain
635 on. If not, we loop to compare the newly read name. */
636
637 if (same_order_option && namelist->found)
638 {
639 name_gather (); /* read one more */
640 if (namelist->found)
641 return 0;
642 }
643 else
644 return 0;
645 }
646 }
647
648 /*------------------------------------------------------------------.
649 | Print the names of things in the namelist that were not matched. |
650 `------------------------------------------------------------------*/
651
652 void
653 names_notfound (void)
654 {
655 struct name *cursor;
656 struct name *next;
657
658 for (cursor = namelist; cursor; cursor = next)
659 {
660 next = cursor->next;
661 if (!cursor->found && !cursor->fake)
662 ERROR ((0, 0, _("%s: Not found in archive"), cursor->name));
663
664 /* We could free the list, but the process is about to die anyway, so
665 save some CPU time. Amigas and other similarly broken software
666 will need to waste the time, though. */
667
668 #ifdef amiga
669 if (!same_order_option)
670 free (cursor);
671 #endif
672 }
673 namelist = (struct name *) NULL;
674 namelast = (struct name *) NULL;
675
676 if (same_order_option)
677 {
678 char *name;
679
680 while (name = name_next (1), name)
681 ERROR ((0, 0, _("%s: Not found in archive"), name));
682 }
683 }
684
685 /*---.
686 | ? |
687 `---*/
688
689 void
690 name_expand (void)
691 {
692 }
693
694 /*-------------------------------------------------------------------------.
695 | This is like name_match, except that it returns a pointer to the name it |
696 | matched, and doesn't set FOUND in structure. The caller will have to do |
697 | that if it wants to. Oh, and if the namelist is empty, it returns NULL, |
698 | unlike name_match, which returns TRUE. |
699 `-------------------------------------------------------------------------*/
700
701 struct name *
702 name_scan (const char *path)
703 {
704 size_t length = strlen (path);
705
706 while (1)
707 {
708 struct name *cursor = namelist;
709
710 if (!cursor)
711 return NULL; /* empty namelist is easy */
712
713 for (; cursor; cursor = cursor->next)
714 {
715 /* If first chars don't match, quick skip. */
716
717 if (cursor->firstch && cursor->name[0] != path[0])
718 continue;
719
720 /* Regular expressions. */
721
722 if (cursor->regexp)
723 {
724 if (fnmatch (cursor->name, path, FNM_LEADING_DIR) == 0)
725 return cursor; /* we got a match */
726 continue;
727 }
728
729 /* Plain Old Strings. */
730
731 if (cursor->length <= length
732 /* archive length >= specified */
733 && (path[cursor->length] == '\0'
734 || path[cursor->length] == '/')
735 /* full match on file/dirname */
736 && strncmp (path, cursor->name, cursor->length) == 0)
737 /* name compare */
738 return cursor; /* we got a match */
739 }
740
741 /* Filename from archive not found in namelist. If we have the whole
742 namelist here, just return 0. Otherwise, read the next name in and
743 compare it. If this was the last name, namelist->found will remain
744 on. If not, we loop to compare the newly read name. */
745
746 if (same_order_option && namelist->found)
747 {
748 name_gather (); /* read one more */
749 if (namelist->found)
750 return NULL;
751 }
752 else
753 return NULL;
754 }
755 }
756
757 /*-----------------------------------------------------------------------.
758 | This returns a name from the namelist which doesn't have ->found set. |
759 | It sets ->found before returning, so successive calls will find and |
760 | return all the non-found names in the namelist |
761 `-----------------------------------------------------------------------*/
762
763 struct name *gnu_list_name = NULL;
764
765 char *
766 name_from_list (void)
767 {
768 if (!gnu_list_name)
769 gnu_list_name = namelist;
770 while (gnu_list_name && gnu_list_name->found)
771 gnu_list_name = gnu_list_name->next;
772 if (gnu_list_name)
773 {
774 gnu_list_name->found = 1;
775 if (gnu_list_name->change_dir)
776 if (chdir (gnu_list_name->change_dir) < 0)
777 FATAL_ERROR ((0, errno, _("Cannot change to directory %s"),
778 gnu_list_name->change_dir));
779 return gnu_list_name->name;
780 }
781 return NULL;
782 }
783
784 /*---.
785 | ? |
786 `---*/
787
788 void
789 blank_name_list (void)
790 {
791 struct name *name;
792
793 gnu_list_name = 0;
794 for (name = namelist; name; name = name->next)
795 name->found = 0;
796 }
797
798 /*---.
799 | ? |
800 `---*/
801
802 char *
803 new_name (const char *path, const char *name)
804 {
805 char *buffer = (char *) xmalloc (strlen (path) + strlen (name) + 2);
806
807 sprintf (buffer, "%s/%s", path, name);
808 return buffer;
809 }
810
811 /* Return nonzero if file NAME is excluded. Exclude a name if its
812 prefix matches a pattern that contains slashes, or if one of its
813 components matches a pattern that contains no slashes. */
814 int
815 excluded_name (char const *name)
816 {
817 char const *p;
818 name += FILESYSTEM_PREFIX_LEN (name);
819
820 if (excluded_filename (excluded_with_slash, name,
821 FNM_FILE_NAME | FNM_LEADING_DIR))
822 return 1;
823
824 for (p = name; *p; p++)
825 if ((p == name || (ISSLASH (p[-1]) && !ISSLASH (p[0])))
826 && excluded_filename (excluded_without_slash, p,
827 FNM_FILE_NAME | FNM_LEADING_DIR))
828 return 1;
829
830 return 0;
831 }
This page took 0.078566 seconds and 5 git commands to generate.