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