]> git.gag.com Git - debian/tar/blob - src/names.c
version 1.13.10
[debian/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           chdir_from_initial_wd (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 const *name;
428
429   if (same_order_option)
430     {
431       char *change_dir = NULL;
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
441       while ((name = name_next (0)) && strcmp (name, "-C") == 0)
442         {
443           char const *dir = name_next (0);
444           if (! dir)
445             FATAL_ERROR ((0, 0, _("Missing file name after -C")));
446           if (change_dir)
447             free (change_dir);
448           change_dir = xstrdup (dir);
449         }
450
451       if (name)
452         {
453           buffer->length = strlen (name);
454           if (sizeof (struct name) + buffer->length >= allocated_length)
455             {
456               allocated_length = sizeof (struct name) + buffer->length;
457               buffer = (struct name *) xrealloc (buffer, allocated_length);
458             }
459           buffer->change_dir = change_dir;
460           strncpy (buffer->name, name, (size_t) buffer->length);
461           buffer->name[buffer->length] = 0;
462           buffer->next = NULL;
463           buffer->found = 0;
464
465           /* FIXME: Poorly named globals, indeed...  */
466           namelist = buffer;
467           namelast = namelist;
468         }
469       else if (change_dir)
470         free (change_dir);
471
472       return;
473     }
474
475   /* Non sorted names -- read them all in.  */
476
477   for (;;)
478     {
479       char *change_dir = NULL;
480       while ((name = name_next (0)) && strcmp (name, "-C") == 0)
481         {
482           char const *dir = name_next (0);
483           if (! dir)
484             FATAL_ERROR ((0, 0, _("Missing file name after -C")));
485           if (change_dir)
486             free (change_dir);
487           change_dir = xstrdup (dir);
488         }
489       if (name)
490         addname (name, change_dir);
491       else
492         {
493           if (change_dir)
494             free (change_dir);
495           break;
496         }
497     }
498 }
499
500 /*-----------------------------.
501 | Add a name to the namelist.  |
502 `-----------------------------*/
503
504 void
505 addname (char const *string, char const *change_dir)
506 {
507   struct name *name;
508   size_t length;
509
510   length = string ? strlen (string) : 0;
511   name = (struct name *) xmalloc (sizeof (struct name) + length);
512   memset (name, 0, sizeof (struct name) + length);
513   name->next = NULL;
514
515   if (string)
516     {
517       name->fake = 0;
518       name->length = length;
519       /* FIXME: Possibly truncating a string, here?  Tss, tss, tss!  */
520       strncpy (name->name, string, length);
521       name->name[length] = '\0';
522     }
523   else
524     name->fake = 1;
525
526   name->found = 0;
527   name->regexp = 0;             /* assume not a regular expression */
528   name->firstch = 1;            /* assume first char is literal */
529   name->change_dir = change_dir;
530   name->dir_contents = 0;
531
532   if (string && is_pattern (string))
533     {
534       name->regexp = 1;
535       if (string[0] == '*' || string[0] == '[' || string[0] == '?')
536         name->firstch = 0;
537     }
538
539   if (namelast)
540     namelast->next = name;
541   namelast = name;
542   if (!namelist)
543     namelist = name;
544 }
545
546 /*------------------------------------------------------------------------.
547 | Return true if and only if name PATH (from an archive) matches any name |
548 | from the namelist.                                                      |
549 `------------------------------------------------------------------------*/
550
551 int
552 name_match (const char *path)
553 {
554   size_t length = strlen (path);
555
556   while (1)
557     {
558       struct name *cursor = namelist;
559
560       if (!cursor)
561         return 1;               /* empty namelist is easy */
562
563       if (cursor->fake)
564         {
565           chdir_from_initial_wd (cursor->change_dir);
566           namelist = 0;
567           return 1;
568         }
569
570       for (; cursor; cursor = cursor->next)
571         {
572           /* If first chars don't match, quick skip.  */
573
574           if (cursor->firstch && cursor->name[0] != path[0])
575             continue;
576
577           /* Regular expressions (shell globbing, actually).  */
578
579           if (cursor->regexp)
580             {
581               if (fnmatch (cursor->name, path, FNM_LEADING_DIR) == 0)
582                 {
583                   cursor->found = 1; /* remember it matched */
584                   if (starting_file_option)
585                     {
586                       free (namelist);
587                       namelist = NULL;
588                     }
589                   chdir_from_initial_wd (cursor->change_dir);
590
591                   /* We got a match.  */
592                   return 1;
593                 }
594               continue;
595             }
596
597           /* Plain Old Strings.  */
598
599           if (cursor->length <= length
600                                 /* archive length >= specified */
601               && (path[cursor->length] == '\0'
602                   || path[cursor->length] == '/')
603                                 /* full match on file/dirname */
604               && strncmp (path, cursor->name, cursor->length) == 0)
605                                 /* name compare */
606             {
607               cursor->found = 1;        /* remember it matched */
608               if (starting_file_option)
609                 {
610                   free ((void *) namelist);
611                   namelist = 0;
612                 }
613               chdir_from_initial_wd (cursor->change_dir);
614
615               /* We got a match.  */
616               return 1;
617             }
618         }
619
620       /* Filename from archive not found in namelist.  If we have the whole
621          namelist here, just return 0.  Otherwise, read the next name in and
622          compare it.  If this was the last name, namelist->found will remain
623          on.  If not, we loop to compare the newly read name.  */
624
625       if (same_order_option && namelist->found)
626         {
627           name_gather ();       /* read one more */
628           if (namelist->found)
629             return 0;
630         }
631       else
632         return 0;
633     }
634 }
635
636 /*------------------------------------------------------------------.
637 | Print the names of things in the namelist that were not matched.  |
638 `------------------------------------------------------------------*/
639
640 void
641 names_notfound (void)
642 {
643   struct name *cursor;
644   struct name *next;
645
646   for (cursor = namelist; cursor; cursor = next)
647     {
648       next = cursor->next;
649       if (!cursor->found && !cursor->fake)
650         ERROR ((0, 0, _("%s: Not found in archive"), cursor->name));
651
652       /* We could free the list, but the process is about to die anyway, so
653          save some CPU time.  Amigas and other similarly broken software
654          will need to waste the time, though.  */
655
656 #ifdef amiga
657       if (!same_order_option)
658         free (cursor);
659 #endif
660     }
661   namelist = (struct name *) NULL;
662   namelast = (struct name *) NULL;
663
664   if (same_order_option)
665     {
666       char *name;
667
668       while (name = name_next (1), name)
669         ERROR ((0, 0, _("%s: Not found in archive"), name));
670     }
671 }
672
673 /*---.
674 | ?  |
675 `---*/
676
677 void
678 name_expand (void)
679 {
680 }
681
682 /*-------------------------------------------------------------------------.
683 | This is like name_match, except that it returns a pointer to the name it |
684 | matched, and doesn't set FOUND in structure.  The caller will have to do |
685 | that if it wants to.  Oh, and if the namelist is empty, it returns NULL, |
686 | unlike name_match, which returns TRUE.                                   |
687 `-------------------------------------------------------------------------*/
688
689 struct name *
690 name_scan (const char *path)
691 {
692   size_t length = strlen (path);
693
694   while (1)
695     {
696       struct name *cursor = namelist;
697
698       if (!cursor)
699         return NULL;            /* empty namelist is easy */
700
701       for (; cursor; cursor = cursor->next)
702         {
703           /* If first chars don't match, quick skip.  */
704
705           if (cursor->firstch && cursor->name[0] != path[0])
706             continue;
707
708           /* Regular expressions.  */
709
710           if (cursor->regexp)
711             {
712               if (fnmatch (cursor->name, path, FNM_LEADING_DIR) == 0)
713                 return cursor;  /* we got a match */
714               continue;
715             }
716
717           /* Plain Old Strings.  */
718
719           if (cursor->length <= length
720                                 /* archive length >= specified */
721               && (path[cursor->length] == '\0'
722                   || path[cursor->length] == '/')
723                                 /* full match on file/dirname */
724               && strncmp (path, cursor->name, cursor->length) == 0)
725                                 /* name compare */
726             return cursor;      /* we got a match */
727         }
728
729       /* Filename from archive not found in namelist.  If we have the whole
730          namelist here, just return 0.  Otherwise, read the next name in and
731          compare it.  If this was the last name, namelist->found will remain
732          on.  If not, we loop to compare the newly read name.  */
733
734       if (same_order_option && namelist->found)
735         {
736           name_gather ();       /* read one more */
737           if (namelist->found)
738             return NULL;
739         }
740       else
741         return NULL;
742     }
743 }
744
745 /*-----------------------------------------------------------------------.
746 | This returns a name from the namelist which doesn't have ->found set.  |
747 | It sets ->found before returning, so successive calls will find and    |
748 | return all the non-found names in the namelist                         |
749 `-----------------------------------------------------------------------*/
750
751 struct name *gnu_list_name = NULL;
752
753 char *
754 name_from_list (void)
755 {
756   if (!gnu_list_name)
757     gnu_list_name = namelist;
758   while (gnu_list_name && gnu_list_name->found)
759     gnu_list_name = gnu_list_name->next;
760   if (gnu_list_name)
761     {
762       gnu_list_name->found = 1;
763       chdir_from_initial_wd (gnu_list_name->change_dir);
764       return gnu_list_name->name;
765     }
766   return NULL;
767 }
768
769 /*---.
770 | ?  |
771 `---*/
772
773 void
774 blank_name_list (void)
775 {
776   struct name *name;
777
778   gnu_list_name = 0;
779   for (name = namelist; name; name = name->next)
780     name->found = 0;
781 }
782
783 /*---.
784 | ?  |
785 `---*/
786
787 char *
788 new_name (const char *path, const char *name)
789 {
790   char *buffer = (char *) xmalloc (strlen (path) + strlen (name) + 2);
791
792   sprintf (buffer, "%s/%s", path, name);
793   return buffer;
794 }
795
796 /* Return nonzero if file NAME is excluded.  Exclude a name if its
797    prefix matches a pattern that contains slashes, or if one of its
798    components matches a pattern that contains no slashes.  */
799 int
800 excluded_name (char const *name)
801 {
802   char const *p;
803   name += FILESYSTEM_PREFIX_LEN (name);
804
805   if (excluded_filename (excluded_with_slash, name,
806                          FNM_FILE_NAME | FNM_LEADING_DIR))
807     return 1;
808
809   for (p = name; *p; p++)
810     if ((p == name || (ISSLASH (p[-1]) && !ISSLASH (p[0])))
811         && excluded_filename (excluded_without_slash, p,
812                               FNM_FILE_NAME | FNM_LEADING_DIR))
813       return 1;
814
815   return 0;
816 }