source: trunk/essentials/app-arch/tar/src/names.c

Last change on this file was 3342, checked in by bird, 18 years ago

tar 1.16.1

File size: 24.7 KB
Line 
1/* Various processing of names.
2
3 Copyright (C) 1988, 1992, 1994, 1996, 1997, 1998, 1999, 2000, 2001,
4 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
5
6 This program is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any later
9 version.
10
11 This program is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
14 Public License for more details.
15
16 You should have received a copy of the GNU General Public License along
17 with this program; if not, write to the Free Software Foundation, Inc.,
18 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
19
20#include <system.h>
21
22#include <fnmatch.h>
23#include <hash.h>
24#include <quotearg.h>
25
26#include "common.h"
27
28
29/* User and group names. */
30
31struct group *getgrnam ();
32struct passwd *getpwnam ();
33#if ! HAVE_DECL_GETPWUID
34struct passwd *getpwuid ();
35#endif
36#if ! HAVE_DECL_GETGRGID
37struct 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
45static char *cached_uname;
46static char *cached_gname;
47
48static uid_t cached_uid; /* valid only if cached_uname is not empty */
49static gid_t cached_gid; /* valid only if cached_gname is not empty */
50
51/* These variables are valid only if nonempty. */
52static char *cached_no_such_uname;
53static char *cached_no_such_gname;
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. */
57static uid_t cached_no_such_uid;
58static gid_t cached_no_such_gid;
59
60static void register_individual_file (char const *name);
61
62/* Given UID, find the corresponding UNAME. */
63void
64uid_to_uname (uid_t uid, char **uname)
65{
66 struct passwd *passwd;
67
68 if (uid != 0 && uid == cached_no_such_uid)
69 {
70 *uname = xstrdup ("");
71 return;
72 }
73
74 if (!cached_uname || uid != cached_uid)
75 {
76 passwd = getpwuid (uid);
77 if (passwd)
78 {
79 cached_uid = uid;
80 assign_string (&cached_uname, passwd->pw_name);
81 }
82 else
83 {
84 cached_no_such_uid = uid;
85 *uname = xstrdup ("");
86 return;
87 }
88 }
89 *uname = xstrdup (cached_uname);
90}
91
92/* Given GID, find the corresponding GNAME. */
93void
94gid_to_gname (gid_t gid, char **gname)
95{
96 struct group *group;
97
98 if (gid != 0 && gid == cached_no_such_gid)
99 {
100 *gname = xstrdup ("");
101 return;
102 }
103
104 if (!cached_gname || gid != cached_gid)
105 {
106 group = getgrgid (gid);
107 if (group)
108 {
109 cached_gid = gid;
110 assign_string (&cached_gname, group->gr_name);
111 }
112 else
113 {
114 cached_no_such_gid = gid;
115 *gname = xstrdup ("");
116 return;
117 }
118 }
119 *gname = xstrdup (cached_gname);
120}
121
122/* Given UNAME, set the corresponding UID and return 1, or else, return 0. */
123int
124uname_to_uid (char const *uname, uid_t *uidp)
125{
126 struct passwd *passwd;
127
128 if (cached_no_such_uname
129 && strcmp (uname, cached_no_such_uname) == 0)
130 return 0;
131
132 if (!cached_uname
133 || uname[0] != cached_uname[0]
134 || strcmp (uname, cached_uname) != 0)
135 {
136 passwd = getpwnam (uname);
137 if (passwd)
138 {
139 cached_uid = passwd->pw_uid;
140 assign_string (&cached_uname, passwd->pw_name);
141 }
142 else
143 {
144 assign_string (&cached_no_such_uname, uname);
145 return 0;
146 }
147 }
148 *uidp = cached_uid;
149 return 1;
150}
151
152/* Given GNAME, set the corresponding GID and return 1, or else, return 0. */
153int
154gname_to_gid (char const *gname, gid_t *gidp)
155{
156 struct group *group;
157
158 if (cached_no_such_gname
159 && strcmp (gname, cached_no_such_gname) == 0)
160 return 0;
161
162 if (!cached_gname
163 || gname[0] != cached_gname[0]
164 || strcmp (gname, cached_gname) != 0)
165 {
166 group = getgrnam (gname);
167 if (group)
168 {
169 cached_gid = group->gr_gid;
170 assign_string (&cached_gname, gname);
171 }
172 else
173 {
174 assign_string (&cached_no_such_gname, gname);
175 return 0;
176 }
177 }
178 *gidp = cached_gid;
179 return 1;
180}
181
182
183
184/* Names from the command call. */
185
186static struct name *namelist; /* first name in list, if any */
187static struct name **nametail = &namelist; /* end of name list */
188
189/* File name arguments are processed in two stages: first a
190 name_array (see below) is filled, then the names from it
191 are moved into the namelist.
192
193 This awkward process is needed only to implement --same-order option,
194 which is meant to help process large archives on machines with
195 limited memory. With this option on, namelist contains at most one
196 entry, which diminishes the memory consumption.
197
198 However, I very much doubt if we still need this -- Sergey */
199
200/* A name_array element contains entries of three types: */
201
202#define NELT_NAME 0 /* File name */
203#define NELT_CHDIR 1 /* Change directory request */
204#define NELT_FMASK 2 /* Change fnmatch options request */
205
206struct name_elt /* A name_array element. */
207{
208 char type; /* Element type, see NELT_* constants above */
209 union
210 {
211 const char *name; /* File or directory name */
212 int matching_flags;/* fnmatch options if type == NELT_FMASK */
213 } v;
214};
215
216static struct name_elt *name_array; /* store an array of names */
217static size_t allocated_names; /* how big is the array? */
218static size_t names; /* how many entries does it have? */
219static size_t name_index; /* how many of the entries have we scanned? */
220
221/* Check the size of name_array, reallocating it as necessary. */
222static void
223check_name_alloc ()
224{
225 if (names == allocated_names)
226 {
227 if (allocated_names == 0)
228 allocated_names = 10; /* Set initial allocation */
229 name_array = x2nrealloc (name_array, &allocated_names,
230 sizeof (name_array[0]));
231 }
232}
233
234/* Add to name_array the file NAME with fnmatch options MATCHING_FLAGS */
235void
236name_add_name (const char *name, int matching_flags)
237{
238 static int prev_flags = 0; /* FIXME: Or EXCLUDE_ANCHORED? */
239 struct name_elt *ep;
240
241 check_name_alloc ();
242 ep = &name_array[names++];
243 if (prev_flags != matching_flags)
244 {
245 ep->type = NELT_FMASK;
246 ep->v.matching_flags = matching_flags;
247 prev_flags = matching_flags;
248 check_name_alloc ();
249 ep = &name_array[names++];
250 }
251 ep->type = NELT_NAME;
252 ep->v.name = name;
253}
254
255/* Add to name_array a chdir request for the directory NAME */
256void
257name_add_dir (const char *name)
258{
259 struct name_elt *ep;
260 check_name_alloc ();
261 ep = &name_array[names++];
262 ep->type = NELT_CHDIR;
263 ep->v.name = name;
264}
265
266
267
268/* Names from external name file. */
269
270static char *name_buffer; /* buffer to hold the current file name */
271static size_t name_buffer_length; /* allocated length of name_buffer */
272
273/* Set up to gather file names for tar. They can either come from a
274 file or were saved from decoding arguments. */
275void
276name_init (void)
277{
278 name_buffer = xmalloc (NAME_FIELD_SIZE + 2);
279 name_buffer_length = NAME_FIELD_SIZE;
280}
281
282void
283name_term (void)
284{
285 free (name_buffer);
286 free (name_array);
287}
288
289static int matching_flags; /* exclude_fnmatch options */
290
291/* Get the next NELT_NAME element from name_array. Result is in
292 static storage and can't be relied upon across two calls.
293
294 If CHANGE_DIRS is true, treat any entries of type NELT_CHDIR as
295 the request to change to the given directory. If filename_terminator
296 is NUL, CHANGE_DIRS is effectively always false.
297
298 Entries of type NELT_FMASK cause updates of the matching_flags
299 value. */
300struct name_elt *
301name_next_elt (int change_dirs)
302{
303 static struct name_elt entry;
304 const char *source;
305 char *cursor;
306
307 if (filename_terminator == '\0')
308 change_dirs = 0;
309
310 while (name_index != names)
311 {
312 struct name_elt *ep;
313 size_t source_len;
314
315 ep = &name_array[name_index++];
316 if (ep->type == NELT_FMASK)
317 {
318 matching_flags = ep->v.matching_flags;
319 continue;
320 }
321
322 source = ep->v.name;
323 source_len = strlen (source);
324 if (name_buffer_length < source_len)
325 {
326 do
327 {
328 name_buffer_length *= 2;
329 if (! name_buffer_length)
330 xalloc_die ();
331 }
332 while (name_buffer_length < source_len);
333
334 free (name_buffer);
335 name_buffer = xmalloc (name_buffer_length + 2);
336 }
337 strcpy (name_buffer, source);
338
339 /* Zap trailing slashes. */
340
341 cursor = name_buffer + strlen (name_buffer) - 1;
342 while (cursor > name_buffer && ISSLASH (*cursor))
343 *cursor-- = '\0';
344
345 if (change_dirs && ep->type == NELT_CHDIR)
346 {
347 if (chdir (name_buffer) < 0)
348 chdir_fatal (name_buffer);
349 }
350 else
351 {
352 if (unquote_option)
353 unquote_string (name_buffer);
354 if (incremental_option)
355 register_individual_file (name_buffer);
356 entry.type = ep->type;
357 entry.v.name = name_buffer;
358 return &entry;
359 }
360 }
361
362 return NULL;
363}
364
365const char *
366name_next (int change_dirs)
367{
368 struct name_elt *nelt = name_next_elt (change_dirs);
369 return nelt ? nelt->v.name : NULL;
370}
371
372/* Gather names in a list for scanning. Could hash them later if we
373 really care.
374
375 If the names are already sorted to match the archive, we just read
376 them one by one. name_gather reads the first one, and it is called
377 by name_match as appropriate to read the next ones. At EOF, the
378 last name read is just left in the buffer. This option lets users
379 of small machines extract an arbitrary number of files by doing
380 "tar t" and editing down the list of files. */
381
382void
383name_gather (void)
384{
385 /* Buffer able to hold a single name. */
386 static struct name *buffer;
387 static size_t allocated_size;
388
389 struct name_elt *ep;
390
391 if (same_order_option)
392 {
393 static int change_dir;
394
395 if (allocated_size == 0)
396 {
397 allocated_size = offsetof (struct name, name) + NAME_FIELD_SIZE + 1;
398 buffer = xmalloc (allocated_size);
399 /* FIXME: This memset is overkill, and ugly... */
400 memset (buffer, 0, allocated_size);
401 }
402
403 while ((ep = name_next_elt (0)) && ep->type == NELT_CHDIR)
404 change_dir = chdir_arg (xstrdup (ep->v.name));
405
406 if (ep)
407 {
408 size_t needed_size;
409
410 buffer->length = strlen (ep->v.name);
411 needed_size = offsetof (struct name, name) + buffer->length + 1;
412 if (allocated_size < needed_size)
413 {
414 do
415 {
416 allocated_size *= 2;
417 if (! allocated_size)
418 xalloc_die ();
419 }
420 while (allocated_size < needed_size);
421
422 buffer = xrealloc (buffer, allocated_size);
423 }
424 buffer->change_dir = change_dir;
425 strcpy (buffer->name, ep->v.name);
426 buffer->next = 0;
427 buffer->found_count = 0;
428 buffer->matching_flags = matching_flags;
429
430 namelist = buffer;
431 nametail = &namelist->next;
432 }
433 else if (change_dir)
434 addname (0, change_dir);
435 }
436 else
437 {
438 /* Non sorted names -- read them all in. */
439 int change_dir = 0;
440
441 for (;;)
442 {
443 int change_dir0 = change_dir;
444 while ((ep = name_next_elt (0)) && ep->type == NELT_CHDIR)
445 change_dir = chdir_arg (xstrdup (ep->v.name));
446
447 if (ep)
448 addname (ep->v.name, change_dir);
449 else
450 {
451 if (change_dir != change_dir0)
452 addname (0, change_dir);
453 break;
454 }
455 }
456 }
457}
458
459/* Add a name to the namelist. */
460struct name *
461addname (char const *string, int change_dir)
462{
463 size_t length = string ? strlen (string) : 0;
464 struct name *name = xmalloc (offsetof (struct name, name) + length + 1);
465
466 if (string)
467 strcpy (name->name, string);
468 else
469 name->name[0] = 0;
470
471 name->next = NULL;
472 name->length = length;
473 name->found_count = 0;
474 name->matching_flags = matching_flags;
475 name->change_dir = change_dir;
476 name->dir_contents = NULL;
477
478 *nametail = name;
479 nametail = &name->next;
480 return name;
481}
482
483/* Find a match for FILE_NAME (whose string length is LENGTH) in the name
484 list. */
485static struct name *
486namelist_match (char const *file_name, size_t length)
487{
488 struct name *p;
489
490 for (p = namelist; p; p = p->next)
491 {
492 if (p->name[0]
493 && exclude_fnmatch (p->name, file_name, p->matching_flags))
494 return p;
495 }
496
497 return NULL;
498}
499
500/* Return true if and only if name FILE_NAME (from an archive) matches any
501 name from the namelist. */
502bool
503name_match (const char *file_name)
504{
505 size_t length = strlen (file_name);
506
507 while (1)
508 {
509 struct name *cursor = namelist;
510
511 if (!cursor)
512 return true;
513
514 if (cursor->name[0] == 0)
515 {
516 chdir_do (cursor->change_dir);
517 namelist = 0;
518 nametail = &namelist;
519 return true;
520 }
521
522 cursor = namelist_match (file_name, length);
523 if (cursor)
524 {
525 if (!(ISSLASH (file_name[cursor->length]) && recursion_option)
526 || cursor->found_count == 0)
527 cursor->found_count++; /* remember it matched */
528 if (starting_file_option)
529 {
530 free (namelist);
531 namelist = 0;
532 nametail = &namelist;
533 }
534 chdir_do (cursor->change_dir);
535
536 /* We got a match. */
537 return ISFOUND (cursor);
538 }
539
540 /* Filename from archive not found in namelist. If we have the whole
541 namelist here, just return 0. Otherwise, read the next name in and
542 compare it. If this was the last name, namelist->found_count will
543 remain on. If not, we loop to compare the newly read name. */
544
545 if (same_order_option && namelist->found_count)
546 {
547 name_gather (); /* read one more */
548 if (namelist->found_count)
549 return false;
550 }
551 else
552 return false;
553 }
554}
555
556/* Returns true if all names from the namelist were processed.
557 P is the stat_info of the most recently processed entry.
558 The decision is postponed until the next entry is read if:
559
560 1) P ended with a slash (i.e. it was a directory)
561 2) P matches any entry from the namelist *and* represents a subdirectory
562 or a file lying under this entry (in the terms of directory structure).
563
564 This is necessary to handle contents of directories. */
565bool
566all_names_found (struct tar_stat_info *p)
567{
568 struct name const *cursor;
569 size_t len;
570
571 if (test_label_option)
572 return true;
573 if (!p->file_name || occurrence_option == 0 || p->had_trailing_slash)
574 return false;
575 len = strlen (p->file_name);
576 for (cursor = namelist; cursor; cursor = cursor->next)
577 {
578 if (cursor->matching_flags /* FIXME: check this */
579 || (!WASFOUND (cursor) && cursor->name[0])
580 || (len >= cursor->length && ISSLASH (p->file_name[cursor->length])))
581 return false;
582 }
583 return true;
584}
585
586static inline int
587is_pattern (const char *string)
588{
589 return strchr (string, '*') || strchr (string, '[') || strchr (string, '?');
590}
591
592static void
593regex_usage_warning (const char *name)
594{
595 static int warned_once = 0;
596
597 if (warn_regex_usage && is_pattern (name))
598 {
599 warned_once = 1;
600 WARN ((0, 0,
601 /* TRANSLATORS: The following three msgids form a single sentence.
602 */
603 _("Pattern matching characters used in file names. Please,")));
604 WARN ((0, 0,
605 _("use --wildcards to enable pattern matching, or --no-wildcards to")));
606 WARN ((0, 0,
607 _("suppress this warning.")));
608 }
609}
610
611/* Print the names of things in the namelist that were not matched. */
612void
613names_notfound (void)
614{
615 struct name const *cursor;
616
617 for (cursor = namelist; cursor; cursor = cursor->next)
618 if (!WASFOUND (cursor) && cursor->name[0])
619 {
620 regex_usage_warning (cursor->name);
621 if (cursor->found_count == 0)
622 ERROR ((0, 0, _("%s: Not found in archive"),
623 quotearg_colon (cursor->name)));
624 else
625 ERROR ((0, 0, _("%s: Required occurrence not found in archive"),
626 quotearg_colon (cursor->name)));
627 }
628
629 /* Don't bother freeing the name list; we're about to exit. */
630 namelist = 0;
631 nametail = &namelist;
632
633 if (same_order_option)
634 {
635 const char *name;
636
637 while ((name = name_next (1)) != NULL)
638 {
639 regex_usage_warning (name);
640 ERROR ((0, 0, _("%s: Not found in archive"),
641 quotearg_colon (name)));
642 }
643 }
644}
645
646
647/* Sorting name lists. */
648
649/* Sort linked LIST of names, of given LENGTH, using COMPARE to order
650 names. Return the sorted list. Apart from the type `struct name'
651 and the definition of SUCCESSOR, this is a generic list-sorting
652 function, but it's too painful to make it both generic and portable
653 in C. */
654
655static struct name *
656merge_sort (struct name *list, int length,
657 int (*compare) (struct name const*, struct name const*))
658{
659 struct name *first_list;
660 struct name *second_list;
661 int first_length;
662 int second_length;
663 struct name *result;
664 struct name **merge_point;
665 struct name *cursor;
666 int counter;
667
668# define SUCCESSOR(name) ((name)->next)
669
670 if (length == 1)
671 return list;
672
673 if (length == 2)
674 {
675 if ((*compare) (list, SUCCESSOR (list)) > 0)
676 {
677 result = SUCCESSOR (list);
678 SUCCESSOR (result) = list;
679 SUCCESSOR (list) = 0;
680 return result;
681 }
682 return list;
683 }
684
685 first_list = list;
686 first_length = (length + 1) / 2;
687 second_length = length / 2;
688 for (cursor = list, counter = first_length - 1;
689 counter;
690 cursor = SUCCESSOR (cursor), counter--)
691 continue;
692 second_list = SUCCESSOR (cursor);
693 SUCCESSOR (cursor) = 0;
694
695 first_list = merge_sort (first_list, first_length, compare);
696 second_list = merge_sort (second_list, second_length, compare);
697
698 merge_point = &result;
699 while (first_list && second_list)
700 if ((*compare) (first_list, second_list) < 0)
701 {
702 cursor = SUCCESSOR (first_list);
703 *merge_point = first_list;
704 merge_point = &SUCCESSOR (first_list);
705 first_list = cursor;
706 }
707 else
708 {
709 cursor = SUCCESSOR (second_list);
710 *merge_point = second_list;
711 merge_point = &SUCCESSOR (second_list);
712 second_list = cursor;
713 }
714 if (first_list)
715 *merge_point = first_list;
716 else
717 *merge_point = second_list;
718
719 return result;
720
721#undef SUCCESSOR
722}
723
724/* A comparison function for sorting names. Put found names last;
725 break ties by string comparison. */
726
727static int
728compare_names (struct name const *n1, struct name const *n2)
729{
730 int found_diff = WASFOUND(n2) - WASFOUND(n1);
731 return found_diff ? found_diff : strcmp (n1->name, n2->name);
732}
733
734
735/* Add all the dirs under NAME, which names a directory, to the namelist.
736 If any of the files is a directory, recurse on the subdirectory.
737 DEVICE is the device not to leave, if the -l option is specified. */
738
739static void
740add_hierarchy_to_namelist (struct name *name, dev_t device)
741{
742 char *file_name = name->name;
743 char *buffer = get_directory_contents (file_name, device);
744
745 if (! buffer)
746 name->dir_contents = "\0\0\0\0";
747 else
748 {
749 size_t name_length = name->length;
750 size_t allocated_length = (name_length >= NAME_FIELD_SIZE
751 ? name_length + NAME_FIELD_SIZE
752 : NAME_FIELD_SIZE);
753 char *namebuf = xmalloc (allocated_length + 1);
754 /* FIXME: + 2 above? */
755 char *string;
756 size_t string_length;
757 int change_dir = name->change_dir;
758
759 name->dir_contents = buffer;
760 strcpy (namebuf, file_name);
761 if (! ISSLASH (namebuf[name_length - 1]))
762 {
763 namebuf[name_length++] = '/';
764 namebuf[name_length] = '\0';
765 }
766
767 for (string = buffer; *string; string += string_length + 1)
768 {
769 string_length = strlen (string);
770 if (*string == 'D')
771 {
772 struct name *np;
773
774 if (allocated_length <= name_length + string_length)
775 {
776 do
777 {
778 allocated_length *= 2;
779 if (! allocated_length)
780 xalloc_die ();
781 }
782 while (allocated_length <= name_length + string_length);
783
784 namebuf = xrealloc (namebuf, allocated_length + 1);
785 }
786 strcpy (namebuf + name_length, string + 1);
787 np = addname (namebuf, change_dir);
788 add_hierarchy_to_namelist (np, device);
789 }
790 }
791
792 free (namebuf);
793 }
794}
795
796
797/* Collect all the names from argv[] (or whatever), expand them into a
798 directory tree, and sort them. This gets only subdirectories, not
799 all files. */
800
801void
802collect_and_sort_names (void)
803{
804 struct name *name;
805 struct name *next_name;
806 int num_names;
807 struct stat statbuf;
808
809 name_gather ();
810
811 if (listed_incremental_option)
812 read_directory_file ();
813
814 if (!namelist)
815 addname (".", 0);
816
817 for (name = namelist; name; name = next_name)
818 {
819 next_name = name->next;
820 if (name->found_count || name->dir_contents)
821 continue;
822 if (name->matching_flags & EXCLUDE_WILDCARDS)
823 /* NOTE: EXCLUDE_ANCHORED is not relevant here */
824 /* FIXME: just skip regexps for now */
825 continue;
826 chdir_do (name->change_dir);
827 if (name->name[0] == 0)
828 continue;
829
830 if (deref_stat (dereference_option, name->name, &statbuf) != 0)
831 {
832 stat_diag (name->name);
833 continue;
834 }
835 if (S_ISDIR (statbuf.st_mode))
836 {
837 name->found_count++;
838 add_hierarchy_to_namelist (name, statbuf.st_dev);
839 }
840 }
841
842 num_names = 0;
843 for (name = namelist; name; name = name->next)
844 num_names++;
845 namelist = merge_sort (namelist, num_names, compare_names);
846
847 for (name = namelist; name; name = name->next)
848 name->found_count = 0;
849
850 if (listed_incremental_option)
851 {
852 for (name = namelist; name && name->name[0] == 0; name++)
853 ;
854 if (name)
855 name->dir_contents = append_incremental_renames (name->dir_contents);
856 }
857}
858
859/* This is like name_match, except that
860 1. It returns a pointer to the name it matched, and doesn't set FOUND
861 in structure. The caller will have to do that if it wants to.
862 2. If the namelist is empty, it returns null, unlike name_match, which
863 returns TRUE. */
864struct name *
865name_scan (const char *file_name)
866{
867 size_t length = strlen (file_name);
868
869 while (1)
870 {
871 struct name *cursor = namelist_match (file_name, length);
872 if (cursor)
873 return cursor;
874
875 /* Filename from archive not found in namelist. If we have the whole
876 namelist here, just return 0. Otherwise, read the next name in and
877 compare it. If this was the last name, namelist->found_count will
878 remain on. If not, we loop to compare the newly read name. */
879
880 if (same_order_option && namelist && namelist->found_count)
881 {
882 name_gather (); /* read one more */
883 if (namelist->found_count)
884 return 0;
885 }
886 else
887 return 0;
888 }
889}
890
891/* This returns a name from the namelist which doesn't have ->found
892 set. It sets ->found before returning, so successive calls will
893 find and return all the non-found names in the namelist. */
894struct name *gnu_list_name;
895
896char *
897name_from_list (void)
898{
899 if (!gnu_list_name)
900 gnu_list_name = namelist;
901 while (gnu_list_name
902 && (gnu_list_name->found_count || gnu_list_name->name[0] == 0))
903 gnu_list_name = gnu_list_name->next;
904 if (gnu_list_name)
905 {
906 gnu_list_name->found_count++;
907 chdir_do (gnu_list_name->change_dir);
908 return gnu_list_name->name;
909 }
910 return 0;
911}
912
913void
914blank_name_list (void)
915{
916 struct name *name;
917
918 gnu_list_name = 0;
919 for (name = namelist; name; name = name->next)
920 name->found_count = 0;
921}
922
923/* Yield a newly allocated file name consisting of FILE_NAME concatenated to
924 NAME, with an intervening slash if FILE_NAME does not already end in one. */
925char *
926new_name (const char *file_name, const char *name)
927{
928 size_t file_name_len = strlen (file_name);
929 size_t namesize = strlen (name) + 1;
930 int slash = file_name_len && ! ISSLASH (file_name[file_name_len - 1]);
931 char *buffer = xmalloc (file_name_len + slash + namesize);
932 memcpy (buffer, file_name, file_name_len);
933 buffer[file_name_len] = '/';
934 memcpy (buffer + file_name_len + slash, name, namesize);
935 return buffer;
936}
937
938/* Return nonzero if file NAME is excluded. */
939bool
940excluded_name (char const *name)
941{
942 return excluded_file_name (excluded, name + FILE_SYSTEM_PREFIX_LEN (name));
943}
944
945
946/* Names to avoid dumping. */
947static Hash_table *avoided_name_table;
948
949/* Remember to not archive NAME. */
950void
951add_avoided_name (char const *name)
952{
953 hash_string_insert (&avoided_name_table, name);
954}
955
956/* Should NAME be avoided when archiving? */
957bool
958is_avoided_name (char const *name)
959{
960 return hash_string_lookup (avoided_name_table, name);
961}
962
963
964
965static Hash_table *individual_file_table;
966
967static void
968register_individual_file (char const *name)
969{
970 struct stat st;
971
972 if (deref_stat (dereference_option, name, &st) != 0)
973 return; /* Will be complained about later */
974 if (S_ISDIR (st.st_mode))
975 return;
976
977 hash_string_insert (&individual_file_table, name);
978}
979
980bool
981is_individual_file (char const *name)
982{
983 return hash_string_lookup (individual_file_table, name);
984}
985
986
987
988
989/* Return the size of the prefix of FILE_NAME that is removed after
990 stripping NUM leading file name components. NUM must be
991 positive. */
992
993size_t
994stripped_prefix_len (char const *file_name, size_t num)
995{
996 char const *p = file_name + FILE_SYSTEM_PREFIX_LEN (file_name);
997 while (ISSLASH (*p))
998 p++;
999 while (*p)
1000 {
1001 bool slash = ISSLASH (*p);
1002 p++;
1003 if (slash)
1004 {
1005 if (--num == 0)
1006 return p - file_name;
1007 while (ISSLASH (*p))
1008 p++;
1009 }
1010 }
1011 return -1;
1012}
1013
1014
1015/* Return nonzero if NAME contains ".." as a file name component. */
1016bool
1017contains_dot_dot (char const *name)
1018{
1019 char const *p = name + FILE_SYSTEM_PREFIX_LEN (name);
1020
1021 for (;; p++)
1022 {
1023 if (p[0] == '.' && p[1] == '.' && (ISSLASH (p[2]) || !p[2]))
1024 return 1;
1025
1026 do
1027 {
1028 if (! *p++)
1029 return 0;
1030 }
1031 while (! ISSLASH (*p));
1032 }
1033}
Note: See TracBrowser for help on using the repository browser.