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