]> git.gag.com Git - debian/tar/blob - src/names.c
(cached_no_such_uname, cached_no_such_gname, cached_no_such_uid,
[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 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 #if 0
383         if (!exclude_option || !check_exclude (name_buffer))
384 #endif
385           {
386             unquote_string (name_buffer);
387             return name_buffer;
388           }
389     }
390
391   /* No more names in file.  */
392
393   if (name_file && chdir_flag)
394     FATAL_ERROR ((0, 0, _("Missing file name after -C")));
395
396   return NULL;
397 }
398
399 /*------------------------------.
400 | Close the name file, if any.  |
401 `------------------------------*/
402
403 void
404 name_close (void)
405 {
406   if (name_file != NULL && name_file != stdin)
407     if (fclose (name_file) == EOF)
408       ERROR ((0, errno, "%s", name_buffer));
409 }
410
411 /*-------------------------------------------------------------------------.
412 | Gather names in a list for scanning.  Could hash them later if we really |
413 | care.                                                                    |
414 |                                                                          |
415 | If the names are already sorted to match the archive, we just read them  |
416 | one by one.  name_gather reads the first one, and it is called by        |
417 | name_match as appropriate to read the next ones.  At EOF, the last name  |
418 | read is just left in the buffer.  This option lets users of small        |
419 | machines extract an arbitrary number of files by doing "tar t" and       |
420 | editing down the list of files.                                          |
421 `-------------------------------------------------------------------------*/
422
423 void
424 name_gather (void)
425 {
426   /* Buffer able to hold a single name.  */
427   static struct name *buffer;
428   static size_t allocated_length = 0;
429
430   char *name;
431
432   if (same_order_option)
433     {
434       if (allocated_length == 0)
435         {
436           allocated_length = sizeof (struct name) + NAME_FIELD_SIZE;
437           buffer = (struct name *) xmalloc (allocated_length);
438           /* FIXME: This memset is overkill, and ugly...  */
439           memset (buffer, 0, allocated_length);
440         }
441       name = name_next (0);
442       if (name)
443         {
444           if (strcmp (name, "-C") == 0)
445             {
446               char *copy = xstrdup (name_next (0));
447
448               name = name_next (0);
449               if (!name)
450                 FATAL_ERROR ((0, 0, _("Missing file name after -C")));
451               buffer->change_dir = copy;
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           strncpy (buffer->name, name, (size_t) buffer->length);
460           buffer->name[buffer->length] = 0;
461           buffer->next = NULL;
462           buffer->found = 0;
463
464           /* FIXME: Poorly named globals, indeed...  */
465           namelist = buffer;
466           namelast = namelist;
467         }
468       return;
469     }
470
471   /* Non sorted names -- read them all in.  */
472
473   while (name = name_next (0), name)
474     addname (name);
475 }
476
477 /*-----------------------------.
478 | Add a name to the namelist.  |
479 `-----------------------------*/
480
481 void
482 addname (const char *string)
483 {
484   /* FIXME: This is ugly.  How is memory managed?  */
485   static char *chdir_name = NULL;
486
487   struct name *name;
488   size_t length;
489
490   if (strcmp (string, "-C") == 0)
491     {
492       chdir_name = xstrdup (name_next (0));
493       string = name_next (0);
494       if (!chdir_name)
495         FATAL_ERROR ((0, 0, _("Missing file name after -C")));
496
497       if (chdir_name[0] != '/')
498         {
499           char *path = xmalloc (PATH_MAX);
500
501           /* FIXME: Shouldn't we use xgetcwd?  */
502 #if HAVE_GETCWD
503           if (!getcwd (path, PATH_MAX))
504             FATAL_ERROR ((0, 0, _("Could not get current directory")));
505 #else
506           char *getwd ();
507
508           if (!getwd (path))
509             FATAL_ERROR ((0, 0, _("Could not get current directory: %s"),
510                           path));
511 #endif
512           chdir_name = new_name (path, chdir_name);
513           free (path);
514         }
515     }
516
517   length = string ? strlen (string) : 0;
518   name = (struct name *) xmalloc (sizeof (struct name) + length);
519   memset (name, 0, sizeof (struct name) + length);
520   name->next = NULL;
521
522   if (string)
523     {
524       name->fake = 0;
525       name->length = length;
526       /* FIXME: Possibly truncating a string, here?  Tss, tss, tss!  */
527       strncpy (name->name, string, length);
528       name->name[length] = '\0';
529     }
530   else
531     name->fake = 1;
532
533   name->found = 0;
534   name->regexp = 0;             /* assume not a regular expression */
535   name->firstch = 1;            /* assume first char is literal */
536   name->change_dir = chdir_name;
537   name->dir_contents = 0;
538
539   if (string && is_pattern (string))
540     {
541       name->regexp = 1;
542       if (string[0] == '*' || string[0] == '[' || string[0] == '?')
543         name->firstch = 0;
544     }
545
546   if (namelast)
547     namelast->next = name;
548   namelast = name;
549   if (!namelist)
550     namelist = name;
551 }
552
553 /*------------------------------------------------------------------------.
554 | Return true if and only if name PATH (from an archive) matches any name |
555 | from the namelist.                                                      |
556 `------------------------------------------------------------------------*/
557
558 int
559 name_match (const char *path)
560 {
561   size_t length = strlen (path);
562
563   while (1)
564     {
565       struct name *cursor = namelist;
566
567       if (!cursor)
568         return 1;               /* empty namelist is easy */
569
570       if (cursor->fake)
571         {
572           if (cursor->change_dir && chdir (cursor->change_dir))
573             FATAL_ERROR ((0, errno, _("Cannot change to directory %s"),
574                           cursor->change_dir));
575           namelist = 0;
576           return 1;
577         }
578
579       for (; cursor; cursor = cursor->next)
580         {
581           /* If first chars don't match, quick skip.  */
582
583           if (cursor->firstch && cursor->name[0] != path[0])
584             continue;
585
586           /* Regular expressions (shell globbing, actually).  */
587
588           if (cursor->regexp)
589             {
590               if (fnmatch (cursor->name, path, FNM_LEADING_DIR) == 0)
591                 {
592                   cursor->found = 1; /* remember it matched */
593                   if (starting_file_option)
594                     {
595                       free (namelist);
596                       namelist = NULL;
597                     }
598                   if (cursor->change_dir && chdir (cursor->change_dir))
599                     FATAL_ERROR ((0, errno, _("Cannot change to directory %s"),
600                                   cursor->change_dir));
601
602                   /* We got a match.  */
603                   return 1;
604                 }
605               continue;
606             }
607
608           /* Plain Old Strings.  */
609
610           if (cursor->length <= length
611                                 /* archive length >= specified */
612               && (path[cursor->length] == '\0'
613                   || path[cursor->length] == '/')
614                                 /* full match on file/dirname */
615               && strncmp (path, cursor->name, cursor->length) == 0)
616                                 /* name compare */
617             {
618               cursor->found = 1;        /* remember it matched */
619               if (starting_file_option)
620                 {
621                   free ((void *) namelist);
622                   namelist = 0;
623                 }
624               if (cursor->change_dir && chdir (cursor->change_dir))
625                 FATAL_ERROR ((0, errno, _("Cannot change to directory %s"),
626                               cursor->change_dir));
627
628               /* We got a match.  */
629               return 1;
630             }
631         }
632
633       /* Filename from archive not found in namelist.  If we have the whole
634          namelist here, just return 0.  Otherwise, read the next name in and
635          compare it.  If this was the last name, namelist->found will remain
636          on.  If not, we loop to compare the newly read name.  */
637
638       if (same_order_option && namelist->found)
639         {
640           name_gather ();       /* read one more */
641           if (namelist->found)
642             return 0;
643         }
644       else
645         return 0;
646     }
647 }
648
649 /*------------------------------------------------------------------.
650 | Print the names of things in the namelist that were not matched.  |
651 `------------------------------------------------------------------*/
652
653 void
654 names_notfound (void)
655 {
656   struct name *cursor;
657   struct name *next;
658
659   for (cursor = namelist; cursor; cursor = next)
660     {
661       next = cursor->next;
662       if (!cursor->found && !cursor->fake)
663         ERROR ((0, 0, _("%s: Not found in archive"), cursor->name));
664
665       /* We could free the list, but the process is about to die anyway, so
666          save some CPU time.  Amigas and other similarly broken software
667          will need to waste the time, though.  */
668
669 #ifdef amiga
670       if (!same_order_option)
671         free (cursor);
672 #endif
673     }
674   namelist = (struct name *) NULL;
675   namelast = (struct name *) NULL;
676
677   if (same_order_option)
678     {
679       char *name;
680
681       while (name = name_next (1), name)
682         ERROR ((0, 0, _("%s: Not found in archive"), name));
683     }
684 }
685
686 /*---.
687 | ?  |
688 `---*/
689
690 void
691 name_expand (void)
692 {
693 }
694
695 /*-------------------------------------------------------------------------.
696 | This is like name_match, except that it returns a pointer to the name it |
697 | matched, and doesn't set FOUND in structure.  The caller will have to do |
698 | that if it wants to.  Oh, and if the namelist is empty, it returns NULL, |
699 | unlike name_match, which returns TRUE.                                   |
700 `-------------------------------------------------------------------------*/
701
702 struct name *
703 name_scan (const char *path)
704 {
705   size_t length = strlen (path);
706
707   while (1)
708     {
709       struct name *cursor = namelist;
710
711       if (!cursor)
712         return NULL;            /* empty namelist is easy */
713
714       for (; cursor; cursor = cursor->next)
715         {
716           /* If first chars don't match, quick skip.  */
717
718           if (cursor->firstch && cursor->name[0] != path[0])
719             continue;
720
721           /* Regular expressions.  */
722
723           if (cursor->regexp)
724             {
725               if (fnmatch (cursor->name, path, FNM_LEADING_DIR) == 0)
726                 return cursor;  /* we got a match */
727               continue;
728             }
729
730           /* Plain Old Strings.  */
731
732           if (cursor->length <= length
733                                 /* archive length >= specified */
734               && (path[cursor->length] == '\0'
735                   || path[cursor->length] == '/')
736                                 /* full match on file/dirname */
737               && strncmp (path, cursor->name, cursor->length) == 0)
738                                 /* name compare */
739             return cursor;      /* we got a match */
740         }
741
742       /* Filename from archive not found in namelist.  If we have the whole
743          namelist here, just return 0.  Otherwise, read the next name in and
744          compare it.  If this was the last name, namelist->found will remain
745          on.  If not, we loop to compare the newly read name.  */
746
747       if (same_order_option && namelist->found)
748         {
749           name_gather ();       /* read one more */
750           if (namelist->found)
751             return NULL;
752         }
753       else
754         return NULL;
755     }
756 }
757
758 /*-----------------------------------------------------------------------.
759 | This returns a name from the namelist which doesn't have ->found set.  |
760 | It sets ->found before returning, so successive calls will find and    |
761 | return all the non-found names in the namelist                         |
762 `-----------------------------------------------------------------------*/
763
764 struct name *gnu_list_name = NULL;
765
766 char *
767 name_from_list (void)
768 {
769   if (!gnu_list_name)
770     gnu_list_name = namelist;
771   while (gnu_list_name && gnu_list_name->found)
772     gnu_list_name = gnu_list_name->next;
773   if (gnu_list_name)
774     {
775       gnu_list_name->found = 1;
776       if (gnu_list_name->change_dir)
777         if (chdir (gnu_list_name->change_dir) < 0)
778           FATAL_ERROR ((0, errno, _("Cannot change to directory %s"),
779                         gnu_list_name->change_dir));
780       return gnu_list_name->name;
781     }
782   return NULL;
783 }
784
785 /*---.
786 | ?  |
787 `---*/
788
789 void
790 blank_name_list (void)
791 {
792   struct name *name;
793
794   gnu_list_name = 0;
795   for (name = namelist; name; name = name->next)
796     name->found = 0;
797 }
798
799 /*---.
800 | ?  |
801 `---*/
802
803 char *
804 new_name (const char *path, const char *name)
805 {
806   char *buffer = (char *) xmalloc (strlen (path) + strlen (name) + 2);
807
808   sprintf (buffer, "%s/%s", path, name);
809   return buffer;
810 }
811 \f
812 /* Excludes names.  */
813
814 static char *exclude_pool = NULL;
815 static size_t exclude_pool_size = 0;
816 static size_t allocated_exclude_pool_size = 0;
817
818 static char **simple_exclude_array = NULL;
819 static int simple_excludes = 0;
820 static int allocated_simple_excludes = 0;
821
822 static char **pattern_exclude_array = NULL;
823 static int pattern_excludes = 0;
824 static int allocated_pattern_excludes = 0;
825
826 /*---.
827 | ?  |
828 `---*/
829
830 void
831 add_exclude (char *name)
832 {
833   size_t name_size;
834
835   unquote_string (name);        /* FIXME: unquote in all cases?  If ever? */
836   name_size = strlen (name) + 1;
837
838   if (exclude_pool_size + name_size > allocated_exclude_pool_size)
839     {
840       char *previous_exclude_pool = exclude_pool;
841       char **cursor;
842
843       allocated_exclude_pool_size = exclude_pool_size + name_size + 1024;
844       exclude_pool = (char *)
845         xrealloc (exclude_pool, allocated_exclude_pool_size);
846
847       for (cursor = simple_exclude_array;
848            cursor < simple_exclude_array + simple_excludes;
849            cursor++)
850         *cursor = exclude_pool + (*cursor - previous_exclude_pool);
851       for (cursor = pattern_exclude_array;
852            cursor < pattern_exclude_array + pattern_excludes;
853            cursor++)
854         *cursor = exclude_pool + (*cursor - previous_exclude_pool);
855     }
856
857   if (is_pattern (name))
858     {
859       if (pattern_excludes == allocated_pattern_excludes)
860         {
861           allocated_pattern_excludes += 32;
862           pattern_exclude_array = (char **)
863             xrealloc (pattern_exclude_array,
864                       allocated_pattern_excludes * sizeof (char *));
865         }
866       pattern_exclude_array[pattern_excludes++]
867         = exclude_pool + exclude_pool_size;
868     }
869   else
870     {
871       if (simple_excludes == allocated_simple_excludes)
872         {
873           allocated_simple_excludes += 32;
874           simple_exclude_array = (char **)
875             xrealloc (simple_exclude_array,
876                       allocated_simple_excludes * sizeof (char *));
877         }
878       simple_exclude_array[simple_excludes++]
879         = exclude_pool + exclude_pool_size;
880     }
881
882   strcpy (exclude_pool + exclude_pool_size, name);
883   exclude_pool_size += name_size;
884 }
885
886 /*---.
887 | ?  |
888 `---*/
889
890 void
891 add_exclude_file (const char *name)
892 {
893   FILE *file;
894   char buffer[1024];
895
896   if (strcmp (name, "-"))
897     file = fopen (name, "r");
898   else
899     {
900       request_stdin ("-X");
901       file = stdin;
902     }
903   if (!file)
904     FATAL_ERROR ((0, errno, _("Cannot open %s"), name));
905
906   while (fgets (buffer, 1024, file))
907     {
908       char *end_of_line = strrchr (buffer, '\n');
909
910       if (end_of_line)
911         *end_of_line = '\0';
912       add_exclude (buffer);
913     }
914   if (fclose (file) == EOF)
915     ERROR ((0, errno, "%s", name));
916 }
917
918 /*------------------------------------------------------------------.
919 | Returns true if the file NAME should not be added nor extracted.  |
920 `------------------------------------------------------------------*/
921
922 int
923 check_exclude (const char *name)
924 {
925   int counter;
926
927   for (counter = 0; counter < pattern_excludes; counter++)
928     if (fnmatch (pattern_exclude_array[counter], name, FNM_LEADING_DIR) == 0)
929       return 1;
930
931   for (counter = 0; counter < simple_excludes; counter++)
932     {
933       /* Accept the output from strstr only if it is the last part of the
934          string.  FIXME: Find a faster way to do this.  */
935
936       char *string = strstr (name, simple_exclude_array[counter]);
937
938       if (string
939           && (string == name || string[-1] == '/')
940           && string[strlen (simple_exclude_array[counter])] == '\0')
941         return 1;
942     }
943   return 0;
944 }