]> Dogcows Code - chaz/tar/blob - src/names.c
(namelist_match): Allow partial matches only if recursive.
[chaz/tar] / src / names.c
1 /* Various processing of names.
2
3 Copyright (C) 1988, 1992, 1994, 1996, 1997, 1998, 1999, 2000, 2001,
4 2003 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 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 if (name_buffer_length * 2 < name_buffer_length)
274 xalloc_die ();
275 name_buffer_length *= 2;
276 name_buffer = xrealloc (name_buffer, name_buffer_length + 2);
277 }
278 name_buffer[counter++] = character;
279 }
280
281 if (counter == 0 && character == EOF)
282 return 0;
283
284 if (counter == name_buffer_length)
285 {
286 if (name_buffer_length * 2 < name_buffer_length)
287 xalloc_die ();
288 name_buffer_length *= 2;
289 name_buffer = xrealloc (name_buffer, name_buffer_length + 2);
290 }
291 name_buffer[counter] = '\0';
292
293 return 1;
294 }
295
296 /* Get the next name from ARGV or the file of names. Result is in
297 static storage and can't be relied upon across two calls.
298
299 If CHANGE_DIRS is true, treat a filename of the form "-C" as
300 meaning that the next filename is the name of a directory to change
301 to. If filename_terminator is NUL, CHANGE_DIRS is effectively
302 always false. */
303 char *
304 name_next (int change_dirs)
305 {
306 const char *source;
307 char *cursor;
308 int chdir_flag = 0;
309
310 if (filename_terminator == '\0')
311 change_dirs = 0;
312
313 while (1)
314 {
315 /* Get a name, either from file or from saved arguments. */
316
317 if (name_index == names)
318 {
319 if (! name_file)
320 break;
321 if (! read_name_from_file ())
322 break;
323 }
324 else
325 {
326 size_t source_len;
327 source = name_array[name_index++];
328 source_len = strlen (source);
329 if (name_buffer_length < source_len)
330 {
331 do
332 {
333 name_buffer_length *= 2;
334 if (! name_buffer_length)
335 xalloc_die ();
336 }
337 while (name_buffer_length < source_len);
338
339 free (name_buffer);
340 name_buffer = xmalloc (name_buffer_length + 2);
341 }
342 strcpy (name_buffer, source);
343 }
344
345 /* Zap trailing slashes. */
346
347 cursor = name_buffer + strlen (name_buffer) - 1;
348 while (cursor > name_buffer && ISSLASH (*cursor))
349 *cursor-- = '\0';
350
351 if (chdir_flag)
352 {
353 if (chdir (name_buffer) < 0)
354 chdir_fatal (name_buffer);
355 chdir_flag = 0;
356 }
357 else if (change_dirs && strcmp (name_buffer, "-C") == 0)
358 chdir_flag = 1;
359 else
360 {
361 unquote_string (name_buffer);
362 return name_buffer;
363 }
364 }
365
366 /* No more names in file. */
367
368 if (name_file && chdir_flag)
369 FATAL_ERROR ((0, 0, _("Missing file name after -C")));
370
371 return 0;
372 }
373
374 /* Close the name file, if any. */
375 void
376 name_close (void)
377 {
378 if (name_file && name_file != stdin)
379 if (fclose (name_file) != 0)
380 close_error (name_buffer);
381 }
382
383 /* Gather names in a list for scanning. Could hash them later if we
384 really care.
385
386 If the names are already sorted to match the archive, we just read
387 them one by one. name_gather reads the first one, and it is called
388 by name_match as appropriate to read the next ones. At EOF, the
389 last name read is just left in the buffer. This option lets users
390 of small machines extract an arbitrary number of files by doing
391 "tar t" and editing down the list of files. */
392
393 void
394 name_gather (void)
395 {
396 /* Buffer able to hold a single name. */
397 static struct name *buffer;
398 static size_t allocated_size;
399
400 char const *name;
401
402 if (same_order_option)
403 {
404 static int change_dir;
405
406 if (allocated_size == 0)
407 {
408 allocated_size = offsetof (struct name, name) + NAME_FIELD_SIZE + 1;
409 buffer = xmalloc (allocated_size);
410 /* FIXME: This memset is overkill, and ugly... */
411 memset (buffer, 0, allocated_size);
412 }
413
414 while ((name = name_next (0)) && strcmp (name, "-C") == 0)
415 {
416 char const *dir = name_next (0);
417 if (! dir)
418 FATAL_ERROR ((0, 0, _("Missing file name after -C")));
419 change_dir = chdir_arg (xstrdup (dir));
420 }
421
422 if (name)
423 {
424 size_t needed_size;
425 buffer->length = strlen (name);
426 needed_size = offsetof (struct name, name) + buffer->length + 1;
427 if (allocated_size < needed_size)
428 {
429 do
430 {
431 allocated_size *= 2;
432 if (! allocated_size)
433 xalloc_die ();
434 }
435 while (allocated_size < needed_size);
436
437 buffer = xrealloc (buffer, allocated_size);
438 }
439 buffer->change_dir = change_dir;
440 strcpy (buffer->name, name);
441 buffer->next = 0;
442 buffer->found = 0;
443
444 namelist = buffer;
445 nametail = &namelist->next;
446 }
447 }
448 else
449 {
450 /* Non sorted names -- read them all in. */
451 int change_dir = 0;
452
453 for (;;)
454 {
455 int change_dir0 = change_dir;
456 while ((name = name_next (0)) && strcmp (name, "-C") == 0)
457 {
458 char const *dir = name_next (0);
459 if (! dir)
460 FATAL_ERROR ((0, 0, _("Missing file name after -C")));
461 change_dir = chdir_arg (xstrdup (dir));
462 }
463 if (name)
464 addname (name, change_dir);
465 else
466 {
467 if (change_dir != change_dir0)
468 addname (0, change_dir);
469 break;
470 }
471 }
472 }
473 }
474
475 /* Add a name to the namelist. */
476 struct name *
477 addname (char const *string, int change_dir)
478 {
479 size_t length = string ? strlen (string) : 0;
480 struct name *name = xmalloc (offsetof (struct name, name) + length + 1);
481
482 if (string)
483 {
484 name->fake = 0;
485 strcpy (name->name, string);
486 }
487 else
488 {
489 name->fake = 1;
490
491 /* FIXME: This initialization (and the byte of memory that it
492 initializes) is probably not needed, but we are currently in
493 bug-fix mode so we'll leave it in for now. */
494 name->name[0] = 0;
495 }
496
497 name->next = 0;
498 name->length = length;
499 name->found = 0;
500 name->regexp = 0; /* assume not a regular expression */
501 name->firstch = 1; /* assume first char is literal */
502 name->change_dir = change_dir;
503 name->dir_contents = 0;
504
505 if (string && is_pattern (string))
506 {
507 name->regexp = 1;
508 if (string[0] == '*' || string[0] == '[' || string[0] == '?')
509 name->firstch = 0;
510 }
511
512 *nametail = name;
513 nametail = &name->next;
514 return name;
515 }
516
517 /* Find a match for PATH (whose string length is LENGTH) in the name
518 list. */
519 static struct name *
520 namelist_match (char const *path, size_t length)
521 {
522 struct name *p;
523
524 for (p = namelist; p; p = p->next)
525 {
526 /* If first chars don't match, quick skip. */
527
528 if (p->firstch && p->name[0] != path[0])
529 continue;
530
531 if (p->regexp
532 ? fnmatch (p->name, path, recursion_option) == 0
533 : (p->length <= length
534 && (path[p->length] == '\0'
535 || (ISSLASH (path[p->length]) && recursion_option))
536 && memcmp (path, p->name, p->length) == 0))
537 return p;
538 }
539
540 return 0;
541 }
542
543 /* Return true if and only if name PATH (from an archive) matches any
544 name from the namelist. */
545 int
546 name_match (const char *path)
547 {
548 size_t length = strlen (path);
549
550 while (1)
551 {
552 struct name *cursor = namelist;
553
554 if (!cursor)
555 return ! files_from_option;
556
557 if (cursor->fake)
558 {
559 chdir_do (cursor->change_dir);
560 namelist = 0;
561 nametail = &namelist;
562 return ! files_from_option;
563 }
564
565 cursor = namelist_match (path, length);
566 if (cursor)
567 {
568 cursor->found = 1; /* remember it matched */
569 if (starting_file_option)
570 {
571 free (namelist);
572 namelist = 0;
573 nametail = &namelist;
574 }
575 chdir_do (cursor->change_dir);
576
577 /* We got a match. */
578 return 1;
579 }
580
581 /* Filename from archive not found in namelist. If we have the whole
582 namelist here, just return 0. Otherwise, read the next name in and
583 compare it. If this was the last name, namelist->found will remain
584 on. If not, we loop to compare the newly read name. */
585
586 if (same_order_option && namelist->found)
587 {
588 name_gather (); /* read one more */
589 if (namelist->found)
590 return 0;
591 }
592 else
593 return 0;
594 }
595 }
596
597 /* Print the names of things in the namelist that were not matched. */
598 void
599 names_notfound (void)
600 {
601 struct name const *cursor;
602
603 for (cursor = namelist; cursor; cursor = cursor->next)
604 if (!cursor->found && !cursor->fake)
605 ERROR ((0, 0, _("%s: Not found in archive"),
606 quotearg_colon (cursor->name)));
607
608 /* Don't bother freeing the name list; we're about to exit. */
609 namelist = 0;
610 nametail = &namelist;
611
612 if (same_order_option)
613 {
614 char *name;
615
616 while (name = name_next (1), name)
617 ERROR ((0, 0, _("%s: Not found in archive"),
618 quotearg_colon (name)));
619 }
620 }
621 \f
622 /* Sorting name lists. */
623
624 /* Sort linked LIST of names, of given LENGTH, using COMPARE to order
625 names. Return the sorted list. Apart from the type `struct name'
626 and the definition of SUCCESSOR, this is a generic list-sorting
627 function, but it's too painful to make it both generic and portable
628 in C. */
629
630 static struct name *
631 merge_sort (struct name *list, int length,
632 int (*compare) (struct name const*, struct name const*))
633 {
634 struct name *first_list;
635 struct name *second_list;
636 int first_length;
637 int second_length;
638 struct name *result;
639 struct name **merge_point;
640 struct name *cursor;
641 int counter;
642
643 # define SUCCESSOR(name) ((name)->next)
644
645 if (length == 1)
646 return list;
647
648 if (length == 2)
649 {
650 if ((*compare) (list, SUCCESSOR (list)) > 0)
651 {
652 result = SUCCESSOR (list);
653 SUCCESSOR (result) = list;
654 SUCCESSOR (list) = 0;
655 return result;
656 }
657 return list;
658 }
659
660 first_list = list;
661 first_length = (length + 1) / 2;
662 second_length = length / 2;
663 for (cursor = list, counter = first_length - 1;
664 counter;
665 cursor = SUCCESSOR (cursor), counter--)
666 continue;
667 second_list = SUCCESSOR (cursor);
668 SUCCESSOR (cursor) = 0;
669
670 first_list = merge_sort (first_list, first_length, compare);
671 second_list = merge_sort (second_list, second_length, compare);
672
673 merge_point = &result;
674 while (first_list && second_list)
675 if ((*compare) (first_list, second_list) < 0)
676 {
677 cursor = SUCCESSOR (first_list);
678 *merge_point = first_list;
679 merge_point = &SUCCESSOR (first_list);
680 first_list = cursor;
681 }
682 else
683 {
684 cursor = SUCCESSOR (second_list);
685 *merge_point = second_list;
686 merge_point = &SUCCESSOR (second_list);
687 second_list = cursor;
688 }
689 if (first_list)
690 *merge_point = first_list;
691 else
692 *merge_point = second_list;
693
694 return result;
695
696 #undef SUCCESSOR
697 }
698
699 /* A comparison function for sorting names. Put found names last;
700 break ties by string comparison. */
701
702 static int
703 compare_names (struct name const *n1, struct name const *n2)
704 {
705 int found_diff = n2->found - n1->found;
706 return found_diff ? found_diff : strcmp (n1->name, n2->name);
707 }
708 \f
709 /* Add all the dirs under NAME, which names a directory, to the namelist.
710 If any of the files is a directory, recurse on the subdirectory.
711 DEVICE is the device not to leave, if the -l option is specified. */
712
713 static void
714 add_hierarchy_to_namelist (struct name *name, dev_t device)
715 {
716 char *path = name->name;
717 char *buffer = get_directory_contents (path, device);
718
719 if (! buffer)
720 name->dir_contents = "\0\0\0\0";
721 else
722 {
723 size_t name_length = name->length;
724 size_t allocated_length = (name_length >= NAME_FIELD_SIZE
725 ? name_length + NAME_FIELD_SIZE
726 : NAME_FIELD_SIZE);
727 char *name_buffer = xmalloc (allocated_length + 1);
728 /* FIXME: + 2 above? */
729 char *string;
730 size_t string_length;
731 int change_dir = name->change_dir;
732
733 name->dir_contents = buffer;
734 strcpy (name_buffer, path);
735 if (! ISSLASH (name_buffer[name_length - 1]))
736 {
737 name_buffer[name_length++] = '/';
738 name_buffer[name_length] = '\0';
739 }
740
741 for (string = buffer; *string; string += string_length + 1)
742 {
743 string_length = strlen (string);
744 if (*string == 'D')
745 {
746 if (allocated_length <= name_length + string_length)
747 {
748 do
749 {
750 allocated_length *= 2;
751 if (! allocated_length)
752 xalloc_die ();
753 }
754 while (allocated_length <= name_length + string_length);
755
756 name_buffer = xrealloc (name_buffer, allocated_length + 1);
757 }
758 strcpy (name_buffer + name_length, string + 1);
759 add_hierarchy_to_namelist (addname (name_buffer, change_dir),
760 device);
761 }
762 }
763
764 free (name_buffer);
765 }
766 }
767 \f
768 /* Collect all the names from argv[] (or whatever), expand them into a
769 directory tree, and sort them. This gets only subdirectories, not
770 all files. */
771
772 void
773 collect_and_sort_names (void)
774 {
775 struct name *name;
776 struct name *next_name;
777 int num_names;
778 struct stat statbuf;
779
780 name_gather ();
781
782 if (listed_incremental_option)
783 read_directory_file ();
784
785 if (!namelist)
786 addname (".", 0);
787
788 for (name = namelist; name; name = next_name)
789 {
790 next_name = name->next;
791 if (name->found || name->dir_contents)
792 continue;
793 if (name->regexp) /* FIXME: just skip regexps for now */
794 continue;
795 chdir_do (name->change_dir);
796 if (name->fake)
797 continue;
798
799 if (deref_stat (dereference_option, name->name, &statbuf) != 0)
800 {
801 if (ignore_failed_read_option)
802 stat_warn (name->name);
803 else
804 stat_error (name->name);
805 continue;
806 }
807 if (S_ISDIR (statbuf.st_mode))
808 {
809 name->found = 1;
810 add_hierarchy_to_namelist (name, statbuf.st_dev);
811 }
812 }
813
814 num_names = 0;
815 for (name = namelist; name; name = name->next)
816 num_names++;
817 namelist = merge_sort (namelist, num_names, compare_names);
818
819 for (name = namelist; name; name = name->next)
820 name->found = 0;
821 }
822
823 /* This is like name_match, except that it returns a pointer to the
824 name it matched, and doesn't set FOUND in structure. The caller
825 will have to do that if it wants to. Oh, and if the namelist is
826 empty, it returns null, unlike name_match, which returns TRUE. */
827 struct name *
828 name_scan (const char *path)
829 {
830 size_t length = strlen (path);
831
832 while (1)
833 {
834 struct name *cursor = namelist_match (path, length);
835 if (cursor)
836 return cursor;
837
838 /* Filename from archive not found in namelist. If we have the whole
839 namelist here, just return 0. Otherwise, read the next name in and
840 compare it. If this was the last name, namelist->found will remain
841 on. If not, we loop to compare the newly read name. */
842
843 if (same_order_option && namelist && namelist->found)
844 {
845 name_gather (); /* read one more */
846 if (namelist->found)
847 return 0;
848 }
849 else
850 return 0;
851 }
852 }
853
854 /* This returns a name from the namelist which doesn't have ->found
855 set. It sets ->found before returning, so successive calls will
856 find and return all the non-found names in the namelist. */
857 struct name *gnu_list_name;
858
859 char *
860 name_from_list (void)
861 {
862 if (!gnu_list_name)
863 gnu_list_name = namelist;
864 while (gnu_list_name && (gnu_list_name->found | gnu_list_name->fake))
865 gnu_list_name = gnu_list_name->next;
866 if (gnu_list_name)
867 {
868 gnu_list_name->found = 1;
869 chdir_do (gnu_list_name->change_dir);
870 return gnu_list_name->name;
871 }
872 return 0;
873 }
874
875 void
876 blank_name_list (void)
877 {
878 struct name *name;
879
880 gnu_list_name = 0;
881 for (name = namelist; name; name = name->next)
882 name->found = 0;
883 }
884
885 /* Yield a newly allocated file name consisting of PATH concatenated to
886 NAME, with an intervening slash if PATH does not already end in one. */
887 char *
888 new_name (const char *path, const char *name)
889 {
890 size_t pathlen = strlen (path);
891 size_t namesize = strlen (name) + 1;
892 int slash = pathlen && ! ISSLASH (path[pathlen - 1]);
893 char *buffer = xmalloc (pathlen + slash + namesize);
894 memcpy (buffer, path, pathlen);
895 buffer[pathlen] = '/';
896 memcpy (buffer + pathlen + slash, name, namesize);
897 return buffer;
898 }
899
900 /* Return nonzero if file NAME is excluded. */
901 bool
902 excluded_name (char const *name)
903 {
904 return excluded_filename (excluded, name + FILESYSTEM_PREFIX_LEN (name));
905 }
906 \f
907 /* Hash tables of strings. */
908
909 /* Calculate the hash of a string. */
910 static unsigned
911 hash_string_hasher (void const *name, unsigned n_buckets)
912 {
913 return hash_string (name, n_buckets);
914 }
915
916 /* Compare two strings for equality. */
917 static bool
918 hash_string_compare (void const *name1, void const *name2)
919 {
920 return strcmp (name1, name2) == 0;
921 }
922
923 /* Return zero if TABLE contains a copy of STRING; otherwise, insert a
924 copy of STRING to TABLE and return 1. */
925 static bool
926 hash_string_insert (Hash_table **table, char const *string)
927 {
928 Hash_table *t = *table;
929 char *s = xstrdup (string);
930 char *e;
931
932 if (! ((t
933 || (*table = t = hash_initialize (0, 0, hash_string_hasher,
934 hash_string_compare, 0)))
935 && (e = hash_insert (t, s))))
936 xalloc_die ();
937
938 if (e == s)
939 return 1;
940 else
941 {
942 free (s);
943 return 0;
944 }
945 }
946
947 /* Return 1 if TABLE contains STRING. */
948 static bool
949 hash_string_lookup (Hash_table const *table, char const *string)
950 {
951 return table && hash_lookup (table, string);
952 }
953 \f
954 /* Names to avoid dumping. */
955 static Hash_table *avoided_name_table;
956
957 /* Remember to not archive NAME. */
958 void
959 add_avoided_name (char const *name)
960 {
961 hash_string_insert (&avoided_name_table, name);
962 }
963
964 /* Should NAME be avoided when archiving? */
965 bool
966 is_avoided_name (char const *name)
967 {
968 return hash_string_lookup (avoided_name_table, name);
969 }
970 \f
971 /* Return a safer suffix of FILE_NAME, or "." if it has no safer
972 suffix. Check for fully specified file names and other atrocities.
973 Warn the user if we do not return NAME. If LINK_TARGET is 1,
974 FILE_NAME is the target of a hard link, not a member name. */
975
976 char *
977 safer_name_suffix (char const *file_name, bool link_target)
978 {
979 char const *p;
980
981 if (absolute_names_option)
982 p = file_name;
983 else
984 {
985 /* Skip file system prefixes, leading pathnames that contain
986 "..", and leading slashes. */
987
988 size_t prefix_len = FILESYSTEM_PREFIX_LEN (file_name);
989
990 for (p = file_name + prefix_len; *p; )
991 {
992 if (p[0] == '.' && p[1] == '.' && (ISSLASH (p[2]) || !p[2]))
993 prefix_len = p + 2 - file_name;
994
995 do
996 {
997 char c = *p++;
998 if (ISSLASH (c))
999 break;
1000 }
1001 while (*p);
1002 }
1003
1004 for (p = file_name + prefix_len; ISSLASH (*p); p++)
1005 continue;
1006 prefix_len = p - file_name;
1007
1008 if (prefix_len)
1009 {
1010 static Hash_table *prefix_table[2];
1011 char *prefix = alloca (prefix_len + 1);
1012 memcpy (prefix, file_name, prefix_len);
1013 prefix[prefix_len] = '\0';
1014
1015 if (hash_string_insert (&prefix_table[link_target], prefix))
1016 {
1017 static char const *const diagnostic[] =
1018 {
1019 N_("Removing leading `%s' from member names"),
1020 N_("Removing leading `%s' from hard link targets")
1021 };
1022 WARN ((0, 0, _(diagnostic[link_target]), prefix));
1023 }
1024 }
1025 }
1026
1027 if (! *p)
1028 {
1029 if (p == file_name)
1030 {
1031 static char const *const diagnostic[] =
1032 {
1033 N_("Substituting `.' for empty member name"),
1034 N_("Substituting `.' for empty hard link target")
1035 };
1036 WARN ((0, 0, _(diagnostic[link_target])));
1037 }
1038
1039 p = ".";
1040 }
1041
1042 return (char *) p;
1043 }
1044 \f
1045 /* Return nonzero if NAME contains ".." as a path name component. */
1046 bool
1047 contains_dot_dot (char const *name)
1048 {
1049 char const *p = name + FILESYSTEM_PREFIX_LEN (name);
1050
1051 for (;; p++)
1052 {
1053 if (p[0] == '.' && p[1] == '.' && (ISSLASH (p[2]) || !p[2]))
1054 return 1;
1055
1056 do
1057 {
1058 if (! *p++)
1059 return 0;
1060 }
1061 while (! ISSLASH (*p));
1062 }
1063 }
This page took 0.0760110000000001 seconds and 5 git commands to generate.