]> Dogcows Code - chaz/tar/blob - src/names.c
Fix use of uninitialized memory
[chaz/tar] / src / names.c
1 /* Various processing of names.
2
3 Copyright 1988, 1992, 1994, 1996-2001, 2003-2007, 2009, 2013 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 3, 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, see <http://www.gnu.org/licenses/>. */
18
19 #include <system.h>
20
21 #include <fnmatch.h>
22 #include <hash.h>
23 #include <quotearg.h>
24 #include <wordsplit.h>
25
26 #include "common.h"
27 \f
28 /* User and group names. */
29
30 /* Make sure you link with the proper libraries if you are running the
31 Yellow Peril (thanks for the good laugh, Ian J.!), or, euh... NIS.
32 This code should also be modified for non-UNIX systems to do something
33 reasonable. */
34
35 static char *cached_uname;
36 static char *cached_gname;
37
38 static uid_t cached_uid; /* valid only if cached_uname is not empty */
39 static gid_t cached_gid; /* valid only if cached_gname is not empty */
40
41 /* These variables are valid only if nonempty. */
42 static char *cached_no_such_uname;
43 static char *cached_no_such_gname;
44
45 /* These variables are valid only if nonzero. It's not worth optimizing
46 the case for weird systems where 0 is not a valid uid or gid. */
47 static uid_t cached_no_such_uid;
48 static gid_t cached_no_such_gid;
49
50 /* Given UID, find the corresponding UNAME. */
51 void
52 uid_to_uname (uid_t uid, char **uname)
53 {
54 struct passwd *passwd;
55
56 if (uid != 0 && uid == cached_no_such_uid)
57 {
58 *uname = xstrdup ("");
59 return;
60 }
61
62 if (!cached_uname || uid != cached_uid)
63 {
64 passwd = getpwuid (uid);
65 if (passwd)
66 {
67 cached_uid = uid;
68 assign_string (&cached_uname, passwd->pw_name);
69 }
70 else
71 {
72 cached_no_such_uid = uid;
73 *uname = xstrdup ("");
74 return;
75 }
76 }
77 *uname = xstrdup (cached_uname);
78 }
79
80 /* Given GID, find the corresponding GNAME. */
81 void
82 gid_to_gname (gid_t gid, char **gname)
83 {
84 struct group *group;
85
86 if (gid != 0 && gid == cached_no_such_gid)
87 {
88 *gname = xstrdup ("");
89 return;
90 }
91
92 if (!cached_gname || gid != cached_gid)
93 {
94 group = getgrgid (gid);
95 if (group)
96 {
97 cached_gid = gid;
98 assign_string (&cached_gname, group->gr_name);
99 }
100 else
101 {
102 cached_no_such_gid = gid;
103 *gname = xstrdup ("");
104 return;
105 }
106 }
107 *gname = xstrdup (cached_gname);
108 }
109
110 /* Given UNAME, set the corresponding UID and return 1, or else, return 0. */
111 int
112 uname_to_uid (char const *uname, uid_t *uidp)
113 {
114 struct passwd *passwd;
115
116 if (cached_no_such_uname
117 && strcmp (uname, cached_no_such_uname) == 0)
118 return 0;
119
120 if (!cached_uname
121 || uname[0] != cached_uname[0]
122 || strcmp (uname, cached_uname) != 0)
123 {
124 passwd = getpwnam (uname);
125 if (passwd)
126 {
127 cached_uid = passwd->pw_uid;
128 assign_string (&cached_uname, passwd->pw_name);
129 }
130 else
131 {
132 assign_string (&cached_no_such_uname, uname);
133 return 0;
134 }
135 }
136 *uidp = cached_uid;
137 return 1;
138 }
139
140 /* Given GNAME, set the corresponding GID and return 1, or else, return 0. */
141 int
142 gname_to_gid (char const *gname, gid_t *gidp)
143 {
144 struct group *group;
145
146 if (cached_no_such_gname
147 && strcmp (gname, cached_no_such_gname) == 0)
148 return 0;
149
150 if (!cached_gname
151 || gname[0] != cached_gname[0]
152 || strcmp (gname, cached_gname) != 0)
153 {
154 group = getgrnam (gname);
155 if (group)
156 {
157 cached_gid = group->gr_gid;
158 assign_string (&cached_gname, gname);
159 }
160 else
161 {
162 assign_string (&cached_no_such_gname, gname);
163 return 0;
164 }
165 }
166 *gidp = cached_gid;
167 return 1;
168 }
169
170 \f
171 static struct name *
172 make_name (const char *file_name)
173 {
174 struct name *p = xzalloc (sizeof (*p));
175 if (!file_name)
176 file_name = "";
177 p->name = xstrdup (file_name);
178 p->length = strlen (p->name);
179 return p;
180 }
181
182 static void
183 free_name (struct name *p)
184 {
185 if (p)
186 {
187 free (p->name);
188 free (p->caname);
189 free (p);
190 }
191 }
192
193 \f
194 /* Names from the command call. */
195
196 static struct name *namelist; /* first name in list, if any */
197 static struct name *nametail; /* end of name list */
198
199 /* File name arguments are processed in two stages: first a
200 name_array (see below) is filled, then the names from it
201 are moved into the namelist.
202
203 This awkward process is needed only to implement --same-order option,
204 which is meant to help process large archives on machines with
205 limited memory. With this option on, namelist contains at most one
206 entry, which diminishes the memory consumption.
207
208 However, I very much doubt if we still need this -- Sergey */
209
210 /* A name_array element contains entries of three types: */
211
212 #define NELT_NAME 0 /* File name */
213 #define NELT_CHDIR 1 /* Change directory request */
214 #define NELT_FMASK 2 /* Change fnmatch options request */
215 #define NELT_FILE 3 /* Read file names from that file */
216
217 struct name_elt /* A name_array element. */
218 {
219 char type; /* Element type, see NELT_* constants above */
220 union
221 {
222 const char *name; /* File or directory name */
223 int matching_flags;/* fnmatch options if type == NELT_FMASK */
224 struct
225 {
226 const char *name;/* File name */
227 int term; /* File name terminator in the list */
228 FILE *fp;
229 } file;
230 } v;
231 };
232
233 static struct name_elt *name_array; /* store an array of names */
234 static size_t allocated_entries; /* how big is the array? */
235 static size_t entries; /* how many entries does it have? */
236 static size_t scanned; /* how many of the entries have we scanned? */
237 size_t name_count; /* how many of the entries are names? */
238
239 /* Check the size of name_array, reallocating it as necessary. */
240 static void
241 check_name_alloc (void)
242 {
243 if (entries == allocated_entries)
244 {
245 if (allocated_entries == 0)
246 allocated_entries = 10; /* Set initial allocation */
247 name_array = x2nrealloc (name_array, &allocated_entries,
248 sizeof (name_array[0]));
249 }
250 }
251
252 /* Add to name_array the file NAME with fnmatch options MATCHING_FLAGS */
253 void
254 name_add_name (const char *name, int matching_flags)
255 {
256 static int prev_flags = 0; /* FIXME: Or EXCLUDE_ANCHORED? */
257 struct name_elt *ep;
258
259 check_name_alloc ();
260 ep = &name_array[entries++];
261 if (prev_flags != matching_flags)
262 {
263 ep->type = NELT_FMASK;
264 ep->v.matching_flags = matching_flags;
265 prev_flags = matching_flags;
266 check_name_alloc ();
267 ep = &name_array[entries++];
268 }
269 ep->type = NELT_NAME;
270 ep->v.name = name;
271 name_count++;
272 }
273
274 /* Add to name_array a chdir request for the directory NAME */
275 void
276 name_add_dir (const char *name)
277 {
278 struct name_elt *ep;
279 check_name_alloc ();
280 ep = &name_array[entries++];
281 ep->type = NELT_CHDIR;
282 ep->v.name = name;
283 }
284
285 void
286 name_add_file (const char *name, int term)
287 {
288 struct name_elt *ep;
289 check_name_alloc ();
290 ep = &name_array[entries++];
291 ep->type = NELT_FILE;
292 ep->v.file.name = name;
293 ep->v.file.term = term;
294 ep->v.file.fp = NULL;
295 }
296 \f
297 /* Names from external name file. */
298
299 static char *name_buffer; /* buffer to hold the current file name */
300 static size_t name_buffer_length; /* allocated length of name_buffer */
301
302 /* Set up to gather file names for tar. They can either come from a
303 file or were saved from decoding arguments. */
304 void
305 name_init (void)
306 {
307 name_buffer = xmalloc (NAME_FIELD_SIZE + 2);
308 name_buffer_length = NAME_FIELD_SIZE;
309 }
310
311 void
312 name_term (void)
313 {
314 free (name_buffer);
315 free (name_array);
316 }
317 \f
318 /* Prevent recursive inclusion of the same file */
319 struct file_id_list
320 {
321 struct file_id_list *next;
322 ino_t ino;
323 dev_t dev;
324 };
325
326 static struct file_id_list *file_id_list;
327
328 static void
329 add_file_id (const char *filename)
330 {
331 struct file_id_list *p;
332 struct stat st;
333
334 if (stat (filename, &st))
335 stat_fatal (filename);
336 for (p = file_id_list; p; p = p->next)
337 if (p->ino == st.st_ino && p->dev == st.st_dev)
338 {
339 FATAL_ERROR ((0, 0, _("%s: file list already read"),
340 quotearg_colon (filename)));
341 }
342 p = xmalloc (sizeof *p);
343 p->next = file_id_list;
344 p->ino = st.st_ino;
345 p->dev = st.st_dev;
346 file_id_list = p;
347 }
348 \f
349 enum read_file_list_state /* Result of reading file name from the list file */
350 {
351 file_list_success, /* OK, name read successfully */
352 file_list_end, /* End of list file */
353 file_list_zero, /* Zero separator encountered where it should not */
354 file_list_skip /* Empty (zero-length) entry encountered, skip it */
355 };
356
357 /* Read from FP a sequence of characters up to TERM and put them
358 into STK.
359 */
360 static enum read_file_list_state
361 read_name_from_file (struct name_elt *ent)
362 {
363 int c;
364 size_t counter = 0;
365 FILE *fp = ent->v.file.fp;
366 int term = ent->v.file.term;
367
368 for (c = getc (fp); c != EOF && c != term; c = getc (fp))
369 {
370 if (counter == name_buffer_length)
371 name_buffer = x2realloc (name_buffer, &name_buffer_length);
372 name_buffer[counter++] = c;
373 if (c == 0)
374 {
375 /* We have read a zero separator. The file possibly is
376 zero-separated */
377 return file_list_zero;
378 }
379 }
380
381 if (counter == 0 && c != EOF)
382 return file_list_skip;
383
384 if (counter == name_buffer_length)
385 name_buffer = x2realloc (name_buffer, &name_buffer_length);
386 name_buffer[counter] = 0;
387
388 return (counter == 0 && c == EOF) ? file_list_end : file_list_success;
389 }
390
391 static int
392 handle_option (const char *str)
393 {
394 struct wordsplit ws;
395 int i;
396
397 while (*str && isspace (*str))
398 ;
399 if (*str != '-')
400 return 1;
401
402 ws.ws_offs = 1;
403 if (wordsplit (str, &ws, WRDSF_DEFFLAGS|WRDSF_DOOFFS))
404 FATAL_ERROR ((0, 0, _("cannot split string '%s': %s"),
405 str, wordsplit_strerror (&ws)));
406 ws.ws_wordv[0] = program_invocation_short_name;
407 more_options (ws.ws_wordc+ws.ws_offs, ws.ws_wordv);
408 for (i = 0; i < ws.ws_wordc+ws.ws_offs; i++)
409 ws.ws_wordv[i] = NULL;
410
411 wordsplit_free (&ws);
412 return 0;
413 }
414
415 static int
416 read_next_name (struct name_elt *ent, struct name_elt *ret)
417 {
418 if (!ent->v.file.fp)
419 {
420 if (!strcmp (ent->v.file.name, "-"))
421 {
422 request_stdin ("-T");
423 ent->v.file.fp = stdin;
424 }
425 else
426 {
427 add_file_id (ent->v.file.name);
428 if ((ent->v.file.fp = fopen (ent->v.file.name, "r")) == NULL)
429 open_fatal (ent->v.file.name);
430 }
431 }
432
433 while (1)
434 {
435 switch (read_name_from_file (ent))
436 {
437 case file_list_skip:
438 continue;
439
440 case file_list_zero:
441 WARNOPT (WARN_FILENAME_WITH_NULS,
442 (0, 0, N_("%s: file name read contains nul character"),
443 quotearg_colon (ent->v.file.name)));
444 ent->v.file.term = 0;
445 /* fall through */
446 case file_list_success:
447 if (handle_option (name_buffer) == 0)
448 continue;
449 ret->type = NELT_NAME;
450 ret->v.name = name_buffer;
451 return 0;
452
453 case file_list_end:
454 if (strcmp (ent->v.file.name, "-"))
455 fclose (ent->v.file.fp);
456 ent->v.file.fp = NULL;
457 return 1;
458 }
459 }
460 }
461 \f
462 static void
463 copy_name (struct name_elt *ep)
464 {
465 const char *source;
466 size_t source_len;
467 char *cursor;
468
469 source = ep->v.name;
470 source_len = strlen (source);
471 if (name_buffer_length < source_len)
472 {
473 do
474 {
475 name_buffer_length *= 2;
476 if (! name_buffer_length)
477 xalloc_die ();
478 }
479 while (name_buffer_length < source_len);
480
481 free (name_buffer);
482 name_buffer = xmalloc(name_buffer_length + 2);
483 }
484 strcpy (name_buffer, source);
485
486 /* Zap trailing slashes. */
487 cursor = name_buffer + strlen (name_buffer) - 1;
488 while (cursor > name_buffer && ISSLASH (*cursor))
489 *cursor-- = '\0';
490 }
491
492 \f
493 static int matching_flags; /* exclude_fnmatch options */
494
495 /* Get the next NELT_NAME element from name_array. Result is in
496 static storage and can't be relied upon across two calls.
497
498 If CHANGE_DIRS is true, treat any entries of type NELT_CHDIR as
499 the request to change to the given directory.
500
501 Entries of type NELT_FMASK cause updates of the matching_flags
502 value. */
503 static struct name_elt *
504 name_next_elt (int change_dirs)
505 {
506 static struct name_elt entry;
507
508 while (scanned != entries)
509 {
510 struct name_elt *ep;
511
512 ep = &name_array[scanned];
513 if (ep->type == NELT_FMASK)
514 {
515 matching_flags = ep->v.matching_flags;
516 ++scanned;
517 continue;
518 }
519
520 switch (ep->type)
521 {
522 case NELT_FILE:
523 if (read_next_name (ep, &entry) == 0)
524 return &entry;
525 ++scanned;
526 continue;
527
528 case NELT_CHDIR:
529 if (change_dirs)
530 {
531 ++scanned;
532 copy_name (ep);
533 if (chdir (name_buffer) < 0)
534 chdir_fatal (name_buffer);
535 break;
536 }
537 /* fall trhough */
538 case NELT_NAME:
539 ++scanned;
540 copy_name (ep);
541 if (unquote_option)
542 unquote_string (name_buffer);
543 entry.type = ep->type;
544 entry.v.name = name_buffer;
545 return &entry;
546 }
547 }
548
549 return NULL;
550 }
551
552 const char *
553 name_next (int change_dirs)
554 {
555 struct name_elt *nelt = name_next_elt (change_dirs);
556 return nelt ? nelt->v.name : NULL;
557 }
558
559 /* Gather names in a list for scanning. Could hash them later if we
560 really care.
561
562 If the names are already sorted to match the archive, we just read
563 them one by one. name_gather reads the first one, and it is called
564 by name_match as appropriate to read the next ones. At EOF, the
565 last name read is just left in the buffer. This option lets users
566 of small machines extract an arbitrary number of files by doing
567 "tar t" and editing down the list of files. */
568
569 void
570 name_gather (void)
571 {
572 /* Buffer able to hold a single name. */
573 static struct name *buffer = NULL;
574
575 struct name_elt *ep;
576
577 if (same_order_option)
578 {
579 static int change_dir;
580
581 while ((ep = name_next_elt (0)) && ep->type == NELT_CHDIR)
582 change_dir = chdir_arg (xstrdup (ep->v.name));
583
584 if (ep)
585 {
586 free_name (buffer);
587 buffer = make_name (ep->v.name);
588 buffer->change_dir = change_dir;
589 buffer->next = 0;
590 buffer->found_count = 0;
591 buffer->matching_flags = matching_flags;
592 buffer->directory = NULL;
593 buffer->parent = NULL;
594 buffer->cmdline = true;
595
596 namelist = nametail = buffer;
597 }
598 else if (change_dir)
599 addname (0, change_dir, false, NULL);
600 }
601 else
602 {
603 /* Non sorted names -- read them all in. */
604 int change_dir = 0;
605
606 for (;;)
607 {
608 int change_dir0 = change_dir;
609 while ((ep = name_next_elt (0)) && ep->type == NELT_CHDIR)
610 change_dir = chdir_arg (xstrdup (ep->v.name));
611
612 if (ep)
613 addname (ep->v.name, change_dir, true, NULL);
614 else
615 {
616 if (change_dir != change_dir0)
617 addname (NULL, change_dir, false, NULL);
618 break;
619 }
620 }
621 }
622 }
623
624 /* Add a name to the namelist. */
625 struct name *
626 addname (char const *string, int change_dir, bool cmdline, struct name *parent)
627 {
628 struct name *name = make_name (string);
629
630 name->prev = nametail;
631 name->next = NULL;
632 name->found_count = 0;
633 name->matching_flags = matching_flags;
634 name->change_dir = change_dir;
635 name->directory = NULL;
636 name->parent = parent;
637 name->cmdline = cmdline;
638
639 if (nametail)
640 nametail->next = name;
641 else
642 namelist = name;
643 nametail = name;
644 return name;
645 }
646
647 /* Find a match for FILE_NAME (whose string length is LENGTH) in the name
648 list. */
649 static struct name *
650 namelist_match (char const *file_name, size_t length)
651 {
652 struct name *p;
653
654 for (p = namelist; p; p = p->next)
655 {
656 if (p->name[0]
657 && exclude_fnmatch (p->name, file_name, p->matching_flags))
658 return p;
659 }
660
661 return NULL;
662 }
663
664 void
665 remname (struct name *name)
666 {
667 struct name *p;
668
669 if ((p = name->prev) != NULL)
670 p->next = name->next;
671 else
672 namelist = name->next;
673
674 if ((p = name->next) != NULL)
675 p->prev = name->prev;
676 else
677 nametail = name->prev;
678 }
679
680 /* Return true if and only if name FILE_NAME (from an archive) matches any
681 name from the namelist. */
682 bool
683 name_match (const char *file_name)
684 {
685 size_t length = strlen (file_name);
686
687 while (1)
688 {
689 struct name *cursor = namelist;
690
691 if (!cursor)
692 return true;
693
694 if (cursor->name[0] == 0)
695 {
696 chdir_do (cursor->change_dir);
697 namelist = NULL;
698 nametail = NULL;
699 return true;
700 }
701
702 cursor = namelist_match (file_name, length);
703 if (cursor)
704 {
705 if (!(ISSLASH (file_name[cursor->length]) && recursion_option)
706 || cursor->found_count == 0)
707 cursor->found_count++; /* remember it matched */
708 if (starting_file_option)
709 {
710 free (namelist);
711 namelist = NULL;
712 nametail = NULL;
713 }
714 chdir_do (cursor->change_dir);
715
716 /* We got a match. */
717 return ISFOUND (cursor);
718 }
719
720 /* Filename from archive not found in namelist. If we have the whole
721 namelist here, just return 0. Otherwise, read the next name in and
722 compare it. If this was the last name, namelist->found_count will
723 remain on. If not, we loop to compare the newly read name. */
724
725 if (same_order_option && namelist->found_count)
726 {
727 name_gather (); /* read one more */
728 if (namelist->found_count)
729 return false;
730 }
731 else
732 return false;
733 }
734 }
735
736 /* Returns true if all names from the namelist were processed.
737 P is the stat_info of the most recently processed entry.
738 The decision is postponed until the next entry is read if:
739
740 1) P ended with a slash (i.e. it was a directory)
741 2) P matches any entry from the namelist *and* represents a subdirectory
742 or a file lying under this entry (in the terms of directory structure).
743
744 This is necessary to handle contents of directories. */
745 bool
746 all_names_found (struct tar_stat_info *p)
747 {
748 struct name const *cursor;
749 size_t len;
750
751 if (!p->file_name || occurrence_option == 0 || p->had_trailing_slash)
752 return false;
753 len = strlen (p->file_name);
754 for (cursor = namelist; cursor; cursor = cursor->next)
755 {
756 if ((cursor->name[0] && !WASFOUND (cursor))
757 || (len >= cursor->length && ISSLASH (p->file_name[cursor->length])))
758 return false;
759 }
760 return true;
761 }
762
763 static int
764 regex_usage_warning (const char *name)
765 {
766 static int warned_once = 0;
767
768 if (warn_regex_usage && fnmatch_pattern_has_wildcards (name, 0))
769 {
770 warned_once = 1;
771 WARN ((0, 0,
772 _("Pattern matching characters used in file names")));
773 WARN ((0, 0,
774 _("Use --wildcards to enable pattern matching,"
775 " or --no-wildcards to suppress this warning")));
776 }
777 return warned_once;
778 }
779
780 /* Print the names of things in the namelist that were not matched. */
781 void
782 names_notfound (void)
783 {
784 struct name const *cursor;
785
786 for (cursor = namelist; cursor; cursor = cursor->next)
787 if (!WASFOUND (cursor) && cursor->name[0])
788 {
789 regex_usage_warning (cursor->name);
790 ERROR ((0, 0,
791 (cursor->found_count == 0) ?
792 _("%s: Not found in archive") :
793 _("%s: Required occurrence not found in archive"),
794 quotearg_colon (cursor->name)));
795 }
796
797 /* Don't bother freeing the name list; we're about to exit. */
798 namelist = NULL;
799 nametail = NULL;
800
801 if (same_order_option)
802 {
803 const char *name;
804
805 while ((name = name_next (1)) != NULL)
806 {
807 regex_usage_warning (name);
808 ERROR ((0, 0, _("%s: Not found in archive"),
809 quotearg_colon (name)));
810 }
811 }
812 }
813
814 void
815 label_notfound (void)
816 {
817 struct name const *cursor;
818
819 if (!namelist)
820 return;
821
822 for (cursor = namelist; cursor; cursor = cursor->next)
823 if (WASFOUND (cursor))
824 return;
825
826 if (verbose_option)
827 error (0, 0, _("Archive label mismatch"));
828 set_exit_status (TAREXIT_DIFFERS);
829
830 for (cursor = namelist; cursor; cursor = cursor->next)
831 {
832 if (regex_usage_warning (cursor->name))
833 break;
834 }
835
836 /* Don't bother freeing the name list; we're about to exit. */
837 namelist = NULL;
838 nametail = NULL;
839
840 if (same_order_option)
841 {
842 const char *name;
843
844 while ((name = name_next (1)) != NULL
845 && regex_usage_warning (name) == 0)
846 ;
847 }
848 }
849 \f
850 /* Sorting name lists. */
851
852 /* Sort *singly* linked LIST of names, of given LENGTH, using COMPARE
853 to order names. Return the sorted list. Note that after calling
854 this function, the 'prev' links in list elements are messed up.
855
856 Apart from the type 'struct name' and the definition of SUCCESSOR,
857 this is a generic list-sorting function, but it's too painful to
858 make it both generic and portable
859 in C. */
860
861 static struct name *
862 merge_sort_sll (struct name *list, int length,
863 int (*compare) (struct name const*, struct name const*))
864 {
865 struct name *first_list;
866 struct name *second_list;
867 int first_length;
868 int second_length;
869 struct name *result;
870 struct name **merge_point;
871 struct name *cursor;
872 int counter;
873
874 # define SUCCESSOR(name) ((name)->next)
875
876 if (length == 1)
877 return list;
878
879 if (length == 2)
880 {
881 if ((*compare) (list, SUCCESSOR (list)) > 0)
882 {
883 result = SUCCESSOR (list);
884 SUCCESSOR (result) = list;
885 SUCCESSOR (list) = 0;
886 return result;
887 }
888 return list;
889 }
890
891 first_list = list;
892 first_length = (length + 1) / 2;
893 second_length = length / 2;
894 for (cursor = list, counter = first_length - 1;
895 counter;
896 cursor = SUCCESSOR (cursor), counter--)
897 continue;
898 second_list = SUCCESSOR (cursor);
899 SUCCESSOR (cursor) = 0;
900
901 first_list = merge_sort_sll (first_list, first_length, compare);
902 second_list = merge_sort_sll (second_list, second_length, compare);
903
904 merge_point = &result;
905 while (first_list && second_list)
906 if ((*compare) (first_list, second_list) < 0)
907 {
908 cursor = SUCCESSOR (first_list);
909 *merge_point = first_list;
910 merge_point = &SUCCESSOR (first_list);
911 first_list = cursor;
912 }
913 else
914 {
915 cursor = SUCCESSOR (second_list);
916 *merge_point = second_list;
917 merge_point = &SUCCESSOR (second_list);
918 second_list = cursor;
919 }
920 if (first_list)
921 *merge_point = first_list;
922 else
923 *merge_point = second_list;
924
925 return result;
926
927 #undef SUCCESSOR
928 }
929
930 /* Sort doubly linked LIST of names, of given LENGTH, using COMPARE
931 to order names. Return the sorted list. */
932 static struct name *
933 merge_sort (struct name *list, int length,
934 int (*compare) (struct name const*, struct name const*))
935 {
936 struct name *head, *p, *prev;
937 head = merge_sort_sll (list, length, compare);
938 /* Fixup prev pointers */
939 for (prev = NULL, p = head; p; prev = p, p = p->next)
940 p->prev = prev;
941 return head;
942 }
943
944 /* A comparison function for sorting names. Put found names last;
945 break ties by string comparison. */
946
947 static int
948 compare_names_found (struct name const *n1, struct name const *n2)
949 {
950 int found_diff = WASFOUND (n2) - WASFOUND (n1);
951 return found_diff ? found_diff : strcmp (n1->name, n2->name);
952 }
953
954 /* Simple comparison by names. */
955 static int
956 compare_names (struct name const *n1, struct name const *n2)
957 {
958 return strcmp (n1->name, n2->name);
959 }
960
961 \f
962 /* Add all the dirs under ST to the namelist NAME, descending the
963 directory hierarchy recursively. */
964
965 static void
966 add_hierarchy_to_namelist (struct tar_stat_info *st, struct name *name)
967 {
968 const char *buffer;
969
970 name->directory = scan_directory (st);
971 buffer = directory_contents (name->directory);
972 if (buffer)
973 {
974 struct name *child_head = NULL, *child_tail = NULL;
975 size_t name_length = name->length;
976 size_t allocated_length = (name_length >= NAME_FIELD_SIZE
977 ? name_length + NAME_FIELD_SIZE
978 : NAME_FIELD_SIZE);
979 char *namebuf = xmalloc (allocated_length + 1);
980 /* FIXME: + 2 above? */
981 const char *string;
982 size_t string_length;
983 int change_dir = name->change_dir;
984
985 strcpy (namebuf, name->name);
986 if (! ISSLASH (namebuf[name_length - 1]))
987 {
988 namebuf[name_length++] = '/';
989 namebuf[name_length] = '\0';
990 }
991
992 for (string = buffer; *string; string += string_length + 1)
993 {
994 string_length = strlen (string);
995 if (*string == 'D')
996 {
997 struct name *np;
998 struct tar_stat_info subdir;
999 int subfd;
1000
1001 if (allocated_length <= name_length + string_length)
1002 {
1003 do
1004 {
1005 allocated_length *= 2;
1006 if (! allocated_length)
1007 xalloc_die ();
1008 }
1009 while (allocated_length <= name_length + string_length);
1010
1011 namebuf = xrealloc (namebuf, allocated_length + 1);
1012 }
1013 strcpy (namebuf + name_length, string + 1);
1014 np = addname (namebuf, change_dir, false, name);
1015 if (!child_head)
1016 child_head = np;
1017 else
1018 child_tail->sibling = np;
1019 child_tail = np;
1020
1021 tar_stat_init (&subdir);
1022 subdir.parent = st;
1023 if (st->fd < 0)
1024 {
1025 subfd = -1;
1026 errno = - st->fd;
1027 }
1028 else
1029 subfd = subfile_open (st, string + 1,
1030 open_read_flags | O_DIRECTORY);
1031 if (subfd < 0)
1032 open_diag (namebuf);
1033 else
1034 {
1035 subdir.fd = subfd;
1036 if (fstat (subfd, &subdir.stat) != 0)
1037 stat_diag (namebuf);
1038 else if (! (O_DIRECTORY || S_ISDIR (subdir.stat.st_mode)))
1039 {
1040 errno = ENOTDIR;
1041 open_diag (namebuf);
1042 }
1043 else
1044 {
1045 subdir.orig_file_name = xstrdup (namebuf);
1046 add_hierarchy_to_namelist (&subdir, np);
1047 restore_parent_fd (&subdir);
1048 }
1049 }
1050
1051 tar_stat_destroy (&subdir);
1052 }
1053 }
1054
1055 free (namebuf);
1056 name->child = child_head;
1057 }
1058 }
1059 \f
1060 /* Auxiliary functions for hashed table of struct name's. */
1061
1062 static size_t
1063 name_hash (void const *entry, size_t n_buckets)
1064 {
1065 struct name const *name = entry;
1066 return hash_string (name->caname, n_buckets);
1067 }
1068
1069 /* Compare two directories for equality of their names. */
1070 static bool
1071 name_compare (void const *entry1, void const *entry2)
1072 {
1073 struct name const *name1 = entry1;
1074 struct name const *name2 = entry2;
1075 return strcmp (name1->caname, name2->caname) == 0;
1076 }
1077
1078 \f
1079 /* Rebase 'name' member of CHILD and all its siblings to
1080 the new PARENT. */
1081 static void
1082 rebase_child_list (struct name *child, struct name *parent)
1083 {
1084 size_t old_prefix_len = child->parent->length;
1085 size_t new_prefix_len = parent->length;
1086 char *new_prefix = parent->name;
1087
1088 for (; child; child = child->sibling)
1089 {
1090 size_t size = child->length - old_prefix_len + new_prefix_len;
1091 char *newp = xmalloc (size + 1);
1092 strcpy (newp, new_prefix);
1093 strcat (newp, child->name + old_prefix_len);
1094 free (child->name);
1095 child->name = newp;
1096 child->length = size;
1097
1098 rebase_directory (child->directory,
1099 child->parent->name, old_prefix_len,
1100 new_prefix, new_prefix_len);
1101 }
1102 }
1103
1104 /* Collect all the names from argv[] (or whatever), expand them into a
1105 directory tree, and sort them. This gets only subdirectories, not
1106 all files. */
1107
1108 void
1109 collect_and_sort_names (void)
1110 {
1111 struct name *name;
1112 struct name *next_name, *prev_name = NULL;
1113 int num_names;
1114 Hash_table *nametab;
1115
1116 name_gather ();
1117
1118 if (!namelist)
1119 addname (".", 0, false, NULL);
1120
1121 if (listed_incremental_option)
1122 {
1123 switch (chdir_count ())
1124 {
1125 case 0:
1126 break;
1127
1128 case 1:
1129 if (namelist->change_dir == 0)
1130 USAGE_ERROR ((0, 0,
1131 _("Using -C option inside file list is not "
1132 "allowed with --listed-incremental")));
1133 break;
1134
1135 default:
1136 USAGE_ERROR ((0, 0,
1137 _("Only one -C option is allowed with "
1138 "--listed-incremental")));
1139 }
1140
1141 read_directory_file ();
1142 }
1143
1144 num_names = 0;
1145 for (name = namelist; name; name = name->next, num_names++)
1146 {
1147 struct tar_stat_info st;
1148
1149 if (name->found_count || name->directory)
1150 continue;
1151 if (name->matching_flags & EXCLUDE_WILDCARDS)
1152 /* NOTE: EXCLUDE_ANCHORED is not relevant here */
1153 /* FIXME: just skip regexps for now */
1154 continue;
1155 chdir_do (name->change_dir);
1156
1157 if (name->name[0] == 0)
1158 continue;
1159
1160 tar_stat_init (&st);
1161
1162 if (deref_stat (name->name, &st.stat) != 0)
1163 {
1164 stat_diag (name->name);
1165 continue;
1166 }
1167 if (S_ISDIR (st.stat.st_mode))
1168 {
1169 int dir_fd = openat (chdir_fd, name->name,
1170 open_read_flags | O_DIRECTORY);
1171 if (dir_fd < 0)
1172 open_diag (name->name);
1173 else
1174 {
1175 st.fd = dir_fd;
1176 if (fstat (dir_fd, &st.stat) != 0)
1177 stat_diag (name->name);
1178 else if (O_DIRECTORY || S_ISDIR (st.stat.st_mode))
1179 {
1180 st.orig_file_name = xstrdup (name->name);
1181 name->found_count++;
1182 add_hierarchy_to_namelist (&st, name);
1183 }
1184 }
1185 }
1186
1187 tar_stat_destroy (&st);
1188 }
1189
1190 namelist = merge_sort (namelist, num_names, compare_names);
1191
1192 num_names = 0;
1193 nametab = hash_initialize (0, 0,
1194 name_hash,
1195 name_compare, NULL);
1196 for (name = namelist; name; name = next_name)
1197 {
1198 next_name = name->next;
1199 name->caname = normalize_filename (name->name);
1200 if (prev_name)
1201 {
1202 struct name *p = hash_lookup (nametab, name);
1203 if (p)
1204 {
1205 /* Keep the one listed in the command line */
1206 if (!name->parent)
1207 {
1208 if (p->child)
1209 rebase_child_list (p->child, name);
1210 hash_delete (nametab, name);
1211 /* FIXME: remove_directory (p->caname); ? */
1212 remname (p);
1213 free_name (p);
1214 num_names--;
1215 }
1216 else
1217 {
1218 if (name->child)
1219 rebase_child_list (name->child, p);
1220 /* FIXME: remove_directory (name->caname); ? */
1221 remname (name);
1222 free_name (name);
1223 continue;
1224 }
1225 }
1226 }
1227 name->found_count = 0;
1228 if (!hash_insert (nametab, name))
1229 xalloc_die ();
1230 prev_name = name;
1231 num_names++;
1232 }
1233 nametail = prev_name;
1234 hash_free (nametab);
1235
1236 namelist = merge_sort (namelist, num_names, compare_names_found);
1237
1238 if (listed_incremental_option)
1239 {
1240 for (name = namelist; name && name->name[0] == 0; name++)
1241 ;
1242 if (name)
1243 append_incremental_renames (name->directory);
1244 }
1245 }
1246
1247 /* This is like name_match, except that
1248 1. It returns a pointer to the name it matched, and doesn't set FOUND
1249 in structure. The caller will have to do that if it wants to.
1250 2. If the namelist is empty, it returns null, unlike name_match, which
1251 returns TRUE. */
1252 struct name *
1253 name_scan (const char *file_name)
1254 {
1255 size_t length = strlen (file_name);
1256
1257 while (1)
1258 {
1259 struct name *cursor = namelist_match (file_name, length);
1260 if (cursor)
1261 return cursor;
1262
1263 /* Filename from archive not found in namelist. If we have the whole
1264 namelist here, just return 0. Otherwise, read the next name in and
1265 compare it. If this was the last name, namelist->found_count will
1266 remain on. If not, we loop to compare the newly read name. */
1267
1268 if (same_order_option && namelist && namelist->found_count)
1269 {
1270 name_gather (); /* read one more */
1271 if (namelist->found_count)
1272 return 0;
1273 }
1274 else
1275 return 0;
1276 }
1277 }
1278
1279 /* This returns a name from the namelist which doesn't have ->found
1280 set. It sets ->found before returning, so successive calls will
1281 find and return all the non-found names in the namelist. */
1282 struct name *gnu_list_name;
1283
1284 struct name const *
1285 name_from_list (void)
1286 {
1287 if (!gnu_list_name)
1288 gnu_list_name = namelist;
1289 while (gnu_list_name
1290 && (gnu_list_name->found_count || gnu_list_name->name[0] == 0))
1291 gnu_list_name = gnu_list_name->next;
1292 if (gnu_list_name)
1293 {
1294 gnu_list_name->found_count++;
1295 chdir_do (gnu_list_name->change_dir);
1296 return gnu_list_name;
1297 }
1298 return NULL;
1299 }
1300
1301 void
1302 blank_name_list (void)
1303 {
1304 struct name *name;
1305
1306 gnu_list_name = 0;
1307 for (name = namelist; name; name = name->next)
1308 name->found_count = 0;
1309 }
1310
1311 /* Yield a newly allocated file name consisting of FILE_NAME concatenated to
1312 NAME, with an intervening slash if FILE_NAME does not already end in one. */
1313 char *
1314 new_name (const char *file_name, const char *name)
1315 {
1316 size_t file_name_len = strlen (file_name);
1317 size_t namesize = strlen (name) + 1;
1318 int slash = file_name_len && ! ISSLASH (file_name[file_name_len - 1]);
1319 char *buffer = xmalloc (file_name_len + slash + namesize);
1320 memcpy (buffer, file_name, file_name_len);
1321 buffer[file_name_len] = '/';
1322 memcpy (buffer + file_name_len + slash, name, namesize);
1323 return buffer;
1324 }
1325
1326 /* Return nonzero if file NAME is excluded. */
1327 bool
1328 excluded_name (char const *name)
1329 {
1330 return excluded_file_name (excluded, name + FILE_SYSTEM_PREFIX_LEN (name));
1331 }
1332 \f
1333
1334 /* Return the size of the prefix of FILE_NAME that is removed after
1335 stripping NUM leading file name components. NUM must be
1336 positive. */
1337
1338 size_t
1339 stripped_prefix_len (char const *file_name, size_t num)
1340 {
1341 char const *p = file_name + FILE_SYSTEM_PREFIX_LEN (file_name);
1342 while (ISSLASH (*p))
1343 p++;
1344 while (*p)
1345 {
1346 bool slash = ISSLASH (*p);
1347 p++;
1348 if (slash)
1349 {
1350 if (--num == 0)
1351 return p - file_name;
1352 while (ISSLASH (*p))
1353 p++;
1354 }
1355 }
1356 return -1;
1357 }
1358 \f
1359 /* Return nonzero if NAME contains ".." as a file name component. */
1360 bool
1361 contains_dot_dot (char const *name)
1362 {
1363 char const *p = name + FILE_SYSTEM_PREFIX_LEN (name);
1364
1365 for (;; p++)
1366 {
1367 if (p[0] == '.' && p[1] == '.' && (ISSLASH (p[2]) || !p[2]))
1368 return 1;
1369
1370 while (! ISSLASH (*p))
1371 {
1372 if (! *p++)
1373 return 0;
1374 }
1375 }
1376 }
This page took 0.089068 seconds and 5 git commands to generate.