]> Dogcows Code - chaz/tar/blob - src/names.c
(_GNU_SOURCE): Remove; autoconf now does this.
[chaz/tar] / src / names.c
1 /* Various processing of names.
2 Copyright 1988, 92, 94, 96, 97, 98, 99, 2000 Free Software Foundation, Inc.
3
4 This program is free software; you can redistribute it and/or modify it
5 under the terms of the GNU General Public License as published by the
6 Free Software Foundation; either version 2, or (at your option) any later
7 version.
8
9 This program is distributed in the hope that it will be useful, but
10 WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
12 Public License for more details.
13
14 You should have received a copy of the GNU General Public License along
15 with this program; if not, write to the Free Software Foundation, Inc.,
16 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
17
18 #include "system.h"
19
20 #include <fnmatch.h>
21 #include <grp.h>
22 #include <hash.h>
23 #include <pwd.h>
24 #include <quotearg.h>
25
26 #include "common.h"
27 \f
28 /* User and group names. */
29
30 struct group *getgrnam ();
31 struct passwd *getpwnam ();
32 #if ! HAVE_DECL_GETPWUID
33 struct passwd *getpwuid ();
34 #endif
35 #if ! HAVE_DECL_GETGRGID
36 struct group *getgrgid ();
37 #endif
38
39 /* Make sure you link with the proper libraries if you are running the
40 Yellow Peril (thanks for the good laugh, Ian J.!), or, euh... NIS.
41 This code should also be modified for non-UNIX systems to do something
42 reasonable. */
43
44 static char cached_uname[UNAME_FIELD_SIZE];
45 static char cached_gname[GNAME_FIELD_SIZE];
46
47 static uid_t cached_uid; /* valid only if cached_uname is not empty */
48 static gid_t cached_gid; /* valid only if cached_gname is not empty */
49
50 /* These variables are valid only if nonempty. */
51 static char cached_no_such_uname[UNAME_FIELD_SIZE];
52 static char cached_no_such_gname[GNAME_FIELD_SIZE];
53
54 /* These variables are valid only if nonzero. It's not worth optimizing
55 the case for weird systems where 0 is not a valid uid or gid. */
56 static uid_t cached_no_such_uid;
57 static gid_t cached_no_such_gid;
58
59 /* Given UID, find the corresponding UNAME. */
60 void
61 uid_to_uname (uid_t uid, char uname[UNAME_FIELD_SIZE])
62 {
63 struct passwd *passwd;
64
65 if (uid != 0 && uid == cached_no_such_uid)
66 {
67 *uname = '\0';
68 return;
69 }
70
71 if (!cached_uname[0] || uid != cached_uid)
72 {
73 passwd = getpwuid (uid);
74 if (passwd)
75 {
76 cached_uid = uid;
77 strncpy (cached_uname, passwd->pw_name, UNAME_FIELD_SIZE);
78 }
79 else
80 {
81 cached_no_such_uid = uid;
82 *uname = '\0';
83 return;
84 }
85 }
86 strncpy (uname, cached_uname, UNAME_FIELD_SIZE);
87 }
88
89 /* Given GID, find the corresponding GNAME. */
90 void
91 gid_to_gname (gid_t gid, char gname[GNAME_FIELD_SIZE])
92 {
93 struct group *group;
94
95 if (gid != 0 && gid == cached_no_such_gid)
96 {
97 *gname = '\0';
98 return;
99 }
100
101 if (!cached_gname[0] || gid != cached_gid)
102 {
103 group = getgrgid (gid);
104 if (group)
105 {
106 cached_gid = gid;
107 strncpy (cached_gname, group->gr_name, GNAME_FIELD_SIZE);
108 }
109 else
110 {
111 cached_no_such_gid = gid;
112 *gname = '\0';
113 return;
114 }
115 }
116 strncpy (gname, cached_gname, GNAME_FIELD_SIZE);
117 }
118
119 /* Given UNAME, set the corresponding UID and return 1, or else, return 0. */
120 int
121 uname_to_uid (char uname[UNAME_FIELD_SIZE], uid_t *uidp)
122 {
123 struct passwd *passwd;
124
125 if (cached_no_such_uname[0]
126 && strncmp (uname, cached_no_such_uname, UNAME_FIELD_SIZE) == 0)
127 return 0;
128
129 if (!cached_uname[0]
130 || uname[0] != cached_uname[0]
131 || strncmp (uname, cached_uname, UNAME_FIELD_SIZE) != 0)
132 {
133 passwd = getpwnam (uname);
134 if (passwd)
135 {
136 cached_uid = passwd->pw_uid;
137 strncpy (cached_uname, uname, UNAME_FIELD_SIZE);
138 }
139 else
140 {
141 strncpy (cached_no_such_uname, uname, UNAME_FIELD_SIZE);
142 return 0;
143 }
144 }
145 *uidp = cached_uid;
146 return 1;
147 }
148
149 /* Given GNAME, set the corresponding GID and return 1, or else, return 0. */
150 int
151 gname_to_gid (char gname[GNAME_FIELD_SIZE], gid_t *gidp)
152 {
153 struct group *group;
154
155 if (cached_no_such_gname[0]
156 && strncmp (gname, cached_no_such_gname, GNAME_FIELD_SIZE) == 0)
157 return 0;
158
159 if (!cached_gname[0]
160 || gname[0] != cached_gname[0]
161 || strncmp (gname, cached_gname, GNAME_FIELD_SIZE) != 0)
162 {
163 group = getgrnam (gname);
164 if (group)
165 {
166 cached_gid = group->gr_gid;
167 strncpy (cached_gname, gname, GNAME_FIELD_SIZE);
168 }
169 else
170 {
171 strncpy (cached_no_such_gname, gname, GNAME_FIELD_SIZE);
172 return 0;
173 }
174 }
175 *gidp = cached_gid;
176 return 1;
177 }
178 \f
179 /* Names from the command call. */
180
181 static struct name *namelist; /* first name in list, if any */
182 static struct name **nametail = &namelist; /* end of name list */
183 static const char **name_array; /* store an array of names */
184 static int allocated_names; /* how big is the array? */
185 static int names; /* how many entries does it have? */
186 static int name_index; /* how many of the entries have we scanned? */
187
188 /* Initialize structures. */
189 void
190 init_names (void)
191 {
192 allocated_names = 10;
193 name_array = xmalloc (sizeof (const char *) * allocated_names);
194 names = 0;
195 }
196
197 /* Add NAME at end of name_array, reallocating it as necessary. */
198 void
199 name_add (const char *name)
200 {
201 if (names == allocated_names)
202 {
203 allocated_names *= 2;
204 name_array =
205 xrealloc (name_array, sizeof (const char *) * allocated_names);
206 }
207 name_array[names++] = name;
208 }
209 \f
210 /* Names from external name file. */
211
212 static FILE *name_file; /* file to read names from */
213 static char *name_buffer; /* buffer to hold the current file name */
214 static size_t name_buffer_length; /* allocated length of name_buffer */
215
216 /* FIXME: I should better check more closely. It seems at first glance that
217 is_pattern is only used when reading a file, and ignored for all
218 command line arguments. */
219
220 static inline int
221 is_pattern (const char *string)
222 {
223 return strchr (string, '*') || strchr (string, '[') || strchr (string, '?');
224 }
225
226 /* Set up to gather file names for tar. They can either come from a
227 file or were saved from decoding arguments. */
228 void
229 name_init (int argc, char *const *argv)
230 {
231 name_buffer = xmalloc (NAME_FIELD_SIZE + 2);
232 name_buffer_length = NAME_FIELD_SIZE;
233
234 if (files_from_option)
235 {
236 if (!strcmp (files_from_option, "-"))
237 {
238 request_stdin ("-T");
239 name_file = stdin;
240 }
241 else if (name_file = fopen (files_from_option, "r"), !name_file)
242 open_fatal (files_from_option);
243 }
244 }
245
246 void
247 name_term (void)
248 {
249 free (name_buffer);
250 free (name_array);
251 }
252
253 /* Read the next filename from name_file and null-terminate it. Put
254 it into name_buffer, reallocating and adjusting name_buffer_length
255 if necessary. Return 0 at end of file, 1 otherwise. */
256 static int
257 read_name_from_file (void)
258 {
259 int character;
260 size_t counter = 0;
261
262 /* FIXME: getc may be called even if character was EOF the last time here. */
263
264 /* FIXME: This + 2 allocation might serve no purpose. */
265
266 while (character = getc (name_file),
267 character != EOF && character != filename_terminator)
268 {
269 if (counter == name_buffer_length)
270 {
271 name_buffer_length += NAME_FIELD_SIZE;
272 name_buffer = xrealloc (name_buffer, name_buffer_length + 2);
273 }
274 name_buffer[counter++] = character;
275 }
276
277 if (counter == 0 && character == EOF)
278 return 0;
279
280 if (counter == name_buffer_length)
281 {
282 name_buffer_length += NAME_FIELD_SIZE;
283 name_buffer = xrealloc (name_buffer, name_buffer_length + 2);
284 }
285 name_buffer[counter] = '\0';
286
287 return 1;
288 }
289
290 /* Get the next name from ARGV or the file of names. Result is in
291 static storage and can't be relied upon across two calls.
292
293 If CHANGE_DIRS is true, treat a filename of the form "-C" as
294 meaning that the next filename is the name of a directory to change
295 to. If filename_terminator is NUL, CHANGE_DIRS is effectively
296 always false. */
297 char *
298 name_next (int change_dirs)
299 {
300 const char *source;
301 char *cursor;
302 int chdir_flag = 0;
303
304 if (filename_terminator == '\0')
305 change_dirs = 0;
306
307 while (1)
308 {
309 /* Get a name, either from file or from saved arguments. */
310
311 if (name_index == names)
312 {
313 if (! name_file)
314 break;
315 if (! read_name_from_file ())
316 break;
317 }
318 else
319 {
320 source = name_array[name_index++];
321 if (strlen (source) > name_buffer_length)
322 {
323 free (name_buffer);
324 name_buffer_length = strlen (source);
325 name_buffer = xmalloc (name_buffer_length + 2);
326 }
327 strcpy (name_buffer, source);
328 }
329
330 /* Zap trailing slashes. */
331
332 cursor = name_buffer + strlen (name_buffer) - 1;
333 while (cursor > name_buffer && *cursor == '/')
334 *cursor-- = '\0';
335
336 if (chdir_flag)
337 {
338 if (chdir (name_buffer) < 0)
339 chdir_fatal (name_buffer);
340 chdir_flag = 0;
341 }
342 else if (change_dirs && strcmp (name_buffer, "-C") == 0)
343 chdir_flag = 1;
344 else
345 {
346 unquote_string (name_buffer);
347 return name_buffer;
348 }
349 }
350
351 /* No more names in file. */
352
353 if (name_file && chdir_flag)
354 FATAL_ERROR ((0, 0, _("Missing file name after -C")));
355
356 return 0;
357 }
358
359 /* Close the name file, if any. */
360 void
361 name_close (void)
362 {
363 if (name_file && name_file != stdin)
364 if (fclose (name_file) != 0)
365 close_error (name_buffer);
366 }
367
368 /* Gather names in a list for scanning. Could hash them later if we
369 really care.
370
371 If the names are already sorted to match the archive, we just read
372 them one by one. name_gather reads the first one, and it is called
373 by name_match as appropriate to read the next ones. At EOF, the
374 last name read is just left in the buffer. This option lets users
375 of small machines extract an arbitrary number of files by doing
376 "tar t" and editing down the list of files. */
377
378 void
379 name_gather (void)
380 {
381 /* Buffer able to hold a single name. */
382 static struct name *buffer;
383 static size_t allocated_length;
384
385 char const *name;
386
387 if (same_order_option)
388 {
389 static int change_dir;
390
391 if (allocated_length == 0)
392 {
393 allocated_length = sizeof (struct name) + NAME_FIELD_SIZE;
394 buffer = xmalloc (allocated_length);
395 /* FIXME: This memset is overkill, and ugly... */
396 memset (buffer, 0, allocated_length);
397 }
398
399 while ((name = name_next (0)) && strcmp (name, "-C") == 0)
400 {
401 char const *dir = name_next (0);
402 if (! dir)
403 FATAL_ERROR ((0, 0, _("Missing file name after -C")));
404 change_dir = chdir_arg (xstrdup (dir));
405 }
406
407 if (name)
408 {
409 buffer->length = strlen (name);
410 if (sizeof (struct name) + buffer->length >= allocated_length)
411 {
412 allocated_length = sizeof (struct name) + buffer->length;
413 buffer = xrealloc (buffer, allocated_length);
414 }
415 buffer->change_dir = change_dir;
416 memcpy (buffer->name, name, buffer->length + 1);
417 buffer->next = 0;
418 buffer->found = 0;
419
420 namelist = buffer;
421 nametail = &namelist->next;
422 }
423 }
424 else
425 {
426 /* Non sorted names -- read them all in. */
427 int change_dir = 0;
428
429 for (;;)
430 {
431 int change_dir0 = change_dir;
432 while ((name = name_next (0)) && strcmp (name, "-C") == 0)
433 {
434 char const *dir = name_next (0);
435 if (! dir)
436 FATAL_ERROR ((0, 0, _("Missing file name after -C")));
437 change_dir = chdir_arg (xstrdup (dir));
438 }
439 if (name)
440 addname (name, change_dir);
441 else
442 {
443 if (change_dir != change_dir0)
444 addname (0, change_dir);
445 break;
446 }
447 }
448 }
449 }
450
451 /* Add a name to the namelist. */
452 struct name *
453 addname (char const *string, int change_dir)
454 {
455 struct name *name;
456 size_t length;
457
458 length = string ? strlen (string) : 0;
459 name = xmalloc (sizeof (struct name) + length);
460 memset (name, 0, sizeof (struct name) + length);
461 name->next = 0;
462
463 if (string)
464 {
465 name->fake = 0;
466 name->length = length;
467 memcpy (name->name, string, length + 1);
468 }
469 else
470 name->fake = 1;
471
472 name->found = 0;
473 name->regexp = 0; /* assume not a regular expression */
474 name->firstch = 1; /* assume first char is literal */
475 name->change_dir = change_dir;
476 name->dir_contents = 0;
477
478 if (string && is_pattern (string))
479 {
480 name->regexp = 1;
481 if (string[0] == '*' || string[0] == '[' || string[0] == '?')
482 name->firstch = 0;
483 }
484
485 *nametail = name;
486 nametail = &name->next;
487 return name;
488 }
489
490 /* Return true if and only if name PATH (from an archive) matches any
491 name from the namelist. */
492 int
493 name_match (const char *path)
494 {
495 size_t length = strlen (path);
496
497 while (1)
498 {
499 struct name *cursor = namelist;
500
501 if (!cursor)
502 return ! files_from_option;
503
504 if (cursor->fake)
505 {
506 chdir_do (cursor->change_dir);
507 namelist = 0;
508 nametail = &namelist;
509 return ! files_from_option;
510 }
511
512 for (; cursor; cursor = cursor->next)
513 {
514 /* If first chars don't match, quick skip. */
515
516 if (cursor->firstch && cursor->name[0] != path[0])
517 continue;
518
519 if (cursor->regexp
520 ? fnmatch (cursor->name, path, FNM_LEADING_DIR) == 0
521 : (cursor->length <= length
522 && (path[cursor->length] == '\0'
523 || path[cursor->length] == '/')
524 && memcmp (path, cursor->name, cursor->length) == 0))
525 {
526 cursor->found = 1; /* remember it matched */
527 if (starting_file_option)
528 {
529 free (namelist);
530 namelist = 0;
531 nametail = &namelist;
532 }
533 chdir_do (cursor->change_dir);
534
535 /* We got a match. */
536 return 1;
537 }
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 will remain
543 on. If not, we loop to compare the newly read name. */
544
545 if (same_order_option && namelist->found)
546 {
547 name_gather (); /* read one more */
548 if (namelist->found)
549 return 0;
550 }
551 else
552 return 0;
553 }
554 }
555
556 /* Print the names of things in the namelist that were not matched. */
557 void
558 names_notfound (void)
559 {
560 struct name *cursor;
561 struct name *next;
562
563 for (cursor = namelist; cursor; cursor = next)
564 {
565 next = cursor->next;
566 if (!cursor->found && !cursor->fake)
567 ERROR ((0, 0, _("%s: Not found in archive"),
568 quotearg_colon (cursor->name)));
569
570 /* We could free the list, but the process is about to die anyway, so
571 save some CPU time. Amigas and other similarly broken software
572 will need to waste the time, though. */
573
574 #ifdef amiga
575 if (!same_order_option)
576 free (cursor);
577 #endif
578 }
579 namelist = 0;
580 nametail = &namelist;
581
582 if (same_order_option)
583 {
584 char *name;
585
586 while (name = name_next (1), name)
587 ERROR ((0, 0, _("%s: Not found in archive"),
588 quotearg_colon (name)));
589 }
590 }
591 \f
592 /* Sorting name lists. */
593
594 /* Sort linked LIST of names, of given LENGTH, using COMPARE to order
595 names. Return the sorted list. Apart from the type `struct name'
596 and the definition of SUCCESSOR, this is a generic list-sorting
597 function, but it's too painful to make it both generic and portable
598 in C. */
599
600 static struct name *
601 merge_sort (struct name *list, int length,
602 int (*compare) (struct name const*, struct name const*))
603 {
604 struct name *first_list;
605 struct name *second_list;
606 int first_length;
607 int second_length;
608 struct name *result;
609 struct name **merge_point;
610 struct name *cursor;
611 int counter;
612
613 # define SUCCESSOR(name) ((name)->next)
614
615 if (length == 1)
616 return list;
617
618 if (length == 2)
619 {
620 if ((*compare) (list, SUCCESSOR (list)) > 0)
621 {
622 result = SUCCESSOR (list);
623 SUCCESSOR (result) = list;
624 SUCCESSOR (list) = 0;
625 return result;
626 }
627 return list;
628 }
629
630 first_list = list;
631 first_length = (length + 1) / 2;
632 second_length = length / 2;
633 for (cursor = list, counter = first_length - 1;
634 counter;
635 cursor = SUCCESSOR (cursor), counter--)
636 continue;
637 second_list = SUCCESSOR (cursor);
638 SUCCESSOR (cursor) = 0;
639
640 first_list = merge_sort (first_list, first_length, compare);
641 second_list = merge_sort (second_list, second_length, compare);
642
643 merge_point = &result;
644 while (first_list && second_list)
645 if ((*compare) (first_list, second_list) < 0)
646 {
647 cursor = SUCCESSOR (first_list);
648 *merge_point = first_list;
649 merge_point = &SUCCESSOR (first_list);
650 first_list = cursor;
651 }
652 else
653 {
654 cursor = SUCCESSOR (second_list);
655 *merge_point = second_list;
656 merge_point = &SUCCESSOR (second_list);
657 second_list = cursor;
658 }
659 if (first_list)
660 *merge_point = first_list;
661 else
662 *merge_point = second_list;
663
664 return result;
665
666 #undef SUCCESSOR
667 }
668
669 /* A comparison function for sorting names. Put found names last;
670 break ties by string comparison. */
671
672 static int
673 compare_names (struct name const *n1, struct name const *n2)
674 {
675 int found_diff = n2->found - n1->found;
676 return found_diff ? found_diff : strcmp (n1->name, n2->name);
677 }
678 \f
679 /* Add all the dirs under NAME, which names a directory, to the namelist.
680 DIRSIZE is the size of the directory, or -1 if not known.
681 If any of the files is a directory, recurse on the subdirectory.
682 DEVICE is the device not to leave, if the -l option is specified. */
683
684 static void
685 add_hierarchy_to_namelist (struct name *name, off_t dirsize, dev_t device)
686 {
687 char *path = name->name;
688 char *buffer = get_directory_contents (path, dirsize, device);
689
690 if (! buffer)
691 name->dir_contents = "\0\0\0\0";
692 else
693 {
694 size_t name_length = name->length;
695 size_t allocated_length = (name_length >= NAME_FIELD_SIZE
696 ? name_length + NAME_FIELD_SIZE
697 : NAME_FIELD_SIZE);
698 char *name_buffer = xmalloc (allocated_length + 1);
699 /* FIXME: + 2 above? */
700 char *string;
701 size_t string_length;
702 int change_dir = name->change_dir;
703
704 name->dir_contents = buffer;
705 strcpy (name_buffer, path);
706 if (name_buffer[name_length - 1] != '/')
707 {
708 name_buffer[name_length++] = '/';
709 name_buffer[name_length] = '\0';
710 }
711
712 for (string = buffer; *string; string += string_length + 1)
713 {
714 string_length = strlen (string);
715 if (*string == 'D')
716 {
717 if (name_length + string_length >= allocated_length)
718 {
719 while (name_length + string_length >= allocated_length)
720 allocated_length += NAME_FIELD_SIZE;
721 name_buffer = xrealloc (name_buffer, allocated_length + 1);
722 }
723 strcpy (name_buffer + name_length, string + 1);
724 add_hierarchy_to_namelist (addname (name_buffer, change_dir),
725 -1, device);
726 }
727 }
728
729 free (name_buffer);
730 }
731 }
732 \f
733 /* Collect all the names from argv[] (or whatever), expand them into a
734 directory tree, and sort them. This gets only subdirectories, not
735 all files. */
736
737 void
738 collect_and_sort_names (void)
739 {
740 struct name *name;
741 struct name *next_name;
742 int num_names;
743 struct stat statbuf;
744
745 name_gather ();
746
747 if (listed_incremental_option)
748 read_directory_file ();
749
750 if (!namelist)
751 addname (".", 0);
752
753 for (name = namelist; name; name = next_name)
754 {
755 next_name = name->next;
756 if (name->found || name->dir_contents)
757 continue;
758 if (name->regexp) /* FIXME: just skip regexps for now */
759 continue;
760 chdir_do (name->change_dir);
761 if (name->fake)
762 continue;
763
764 if (deref_stat (dereference_option, name->name, &statbuf) != 0)
765 {
766 stat_error (name->name);
767 continue;
768 }
769 if (S_ISDIR (statbuf.st_mode))
770 {
771 name->found = 1;
772 add_hierarchy_to_namelist (name, statbuf.st_size, statbuf.st_dev);
773 }
774 }
775
776 num_names = 0;
777 for (name = namelist; name; name = name->next)
778 num_names++;
779 namelist = merge_sort (namelist, num_names, compare_names);
780
781 for (name = namelist; name; name = name->next)
782 name->found = 0;
783 }
784
785 /* This is like name_match, except that it returns a pointer to the
786 name it matched, and doesn't set FOUND in structure. The caller
787 will have to do that if it wants to. Oh, and if the namelist is
788 empty, it returns null, unlike name_match, which returns TRUE. */
789 struct name *
790 name_scan (const char *path)
791 {
792 size_t length = strlen (path);
793
794 while (1)
795 {
796 struct name *cursor = namelist;
797
798 if (!cursor)
799 return 0;
800
801 for (; cursor; cursor = cursor->next)
802 {
803 /* If first chars don't match, quick skip. */
804
805 if (cursor->firstch && cursor->name[0] != path[0])
806 continue;
807
808 if (cursor->regexp
809 ? fnmatch (cursor->name, path, FNM_LEADING_DIR) == 0
810 : (cursor->length <= length
811 && (path[cursor->length] == '\0'
812 || path[cursor->length] == '/')
813 && memcmp (path, cursor->name, cursor->length) == 0))
814 return cursor; /* we got a match */
815 }
816
817 /* Filename from archive not found in namelist. If we have the whole
818 namelist here, just return 0. Otherwise, read the next name in and
819 compare it. If this was the last name, namelist->found will remain
820 on. If not, we loop to compare the newly read name. */
821
822 if (same_order_option && namelist->found)
823 {
824 name_gather (); /* read one more */
825 if (namelist->found)
826 return 0;
827 }
828 else
829 return 0;
830 }
831 }
832
833 /* This returns a name from the namelist which doesn't have ->found
834 set. It sets ->found before returning, so successive calls will
835 find and return all the non-found names in the namelist. */
836 struct name *gnu_list_name;
837
838 char *
839 name_from_list (void)
840 {
841 if (!gnu_list_name)
842 gnu_list_name = namelist;
843 while (gnu_list_name && (gnu_list_name->found | gnu_list_name->fake))
844 gnu_list_name = gnu_list_name->next;
845 if (gnu_list_name)
846 {
847 gnu_list_name->found = 1;
848 chdir_do (gnu_list_name->change_dir);
849 return gnu_list_name->name;
850 }
851 return 0;
852 }
853
854 void
855 blank_name_list (void)
856 {
857 struct name *name;
858
859 gnu_list_name = 0;
860 for (name = namelist; name; name = name->next)
861 name->found = 0;
862 }
863
864 /* Yield a newly allocated file name consisting of PATH concatenated to
865 NAME, with an intervening slash if PATH does not already end in one. */
866 char *
867 new_name (const char *path, const char *name)
868 {
869 size_t pathlen = strlen (path);
870 size_t namesize = strlen (name) + 1;
871 int slash = pathlen && path[pathlen - 1] != '/';
872 char *buffer = xmalloc (pathlen + slash + namesize);
873 memcpy (buffer, path, pathlen);
874 buffer[pathlen] = '/';
875 memcpy (buffer + pathlen + slash, name, namesize);
876 return buffer;
877 }
878
879 /* Return nonzero if file NAME is excluded. Exclude a name if its
880 prefix matches a pattern that contains slashes, or if one of its
881 components matches a pattern that contains no slashes. */
882 int
883 excluded_name (char const *name)
884 {
885 char const *p;
886 name += FILESYSTEM_PREFIX_LEN (name);
887
888 if (excluded_filename (excluded_with_slash, name,
889 FNM_FILE_NAME | FNM_LEADING_DIR))
890 return 1;
891
892 for (p = name; *p; p++)
893 if (((p == name || ISSLASH (p[-1])) && !ISSLASH (p[0]))
894 && excluded_filename (excluded_without_slash, p,
895 FNM_FILE_NAME | FNM_LEADING_DIR))
896 return 1;
897
898 return 0;
899 }
900 \f
901 /* Names to avoid dumping. */
902 static Hash_table *avoided_name_table;
903
904 /* Calculate the hash of an avoided name. */
905 static unsigned
906 hash_avoided_name (void const *name, unsigned n_buckets)
907 {
908 return hash_string (name, n_buckets);
909 }
910
911 /* Compare two avoided names for equality. */
912 static bool
913 compare_avoided_names (void const *name1, void const *name2)
914 {
915 return strcmp (name1, name2) == 0;
916 }
917
918 /* Remember to not archive NAME. */
919 void
920 add_avoided_name (char const *name)
921 {
922 if (! ((avoided_name_table
923 || (avoided_name_table = hash_initialize (0, 0, hash_avoided_name,
924 compare_avoided_names, 0)))
925 && hash_insert (avoided_name_table, xstrdup (name))))
926 xalloc_die ();
927 }
928
929 /* Should NAME be avoided when archiving? */
930 int
931 is_avoided_name (char const *name)
932 {
933 return avoided_name_table && hash_lookup (avoided_name_table, name);
934 }
This page took 0.073196 seconds and 5 git commands to generate.