(_GNU_SOURCE): Define.
[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           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 }