]> Dogcows Code - chaz/tar/blob - src/incremen.c
Optimize searches for directory structures by keeping a pointer to struct directory...
[chaz/tar] / src / incremen.c
1 /* GNU dump extensions to tar.
2
3 Copyright (C) 1988, 1992, 1993, 1994, 1996, 1997, 1999, 2000, 2001,
4 2003, 2004, 2005, 2006, 2007, 2008, 2009 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 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, write to the Free Software Foundation, Inc.,
18 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
19
20 #include <system.h>
21 #include <hash.h>
22 #include <quotearg.h>
23 #include "common.h"
24
25 /* Incremental dump specialities. */
26
27 /* Which child files to save under a directory. */
28 enum children
29 {
30 NO_CHILDREN,
31 CHANGED_CHILDREN,
32 ALL_CHILDREN
33 };
34
35 #define DIRF_INIT 0x0001 /* directory structure is initialized
36 (procdir called at least once) */
37 #define DIRF_NFS 0x0002 /* directory is mounted on nfs */
38 #define DIRF_FOUND 0x0004 /* directory is found on fs */
39 #define DIRF_NEW 0x0008 /* directory is new (not found
40 in the previous dump) */
41 #define DIRF_RENAMED 0x0010 /* directory is renamed */
42
43 #define DIR_IS_INITED(d) ((d)->flags & DIRF_INIT)
44 #define DIR_IS_NFS(d) ((d)->flags & DIRF_NFS)
45 #define DIR_IS_FOUND(d) ((d)->flags & DIRF_FOUND)
46 #define DIR_IS_NEW(d) ((d)->flags & DIRF_NEW)
47 #define DIR_IS_RENAMED(d) ((d)->flags & DIRF_RENAMED)
48
49 #define DIR_SET_FLAG(d,f) (d)->flags |= (f)
50 #define DIR_CLEAR_FLAG(d,f) (d)->flags &= ~(f)
51
52 struct dumpdir /* Dump directory listing */
53 {
54 char *contents; /* Actual contents */
55 size_t total; /* Total number of elements */
56 size_t elc; /* Number of D/N/Y elements. */
57 char **elv; /* Array of D/N/Y elements */
58 };
59
60 /* Directory attributes. */
61 struct directory
62 {
63 struct directory *next;
64 struct timespec mtime; /* Modification time */
65 dev_t device_number; /* device number for directory */
66 ino_t inode_number; /* inode number for directory */
67 struct dumpdir *dump; /* Directory contents */
68 struct dumpdir *idump; /* Initial contents if the directory was
69 rescanned */
70 enum children children; /* What to save under this directory */
71 unsigned flags; /* See DIRF_ macros above */
72 struct directory *orig; /* If the directory was renamed, points to
73 the original directory structure */
74 const char *tagfile; /* Tag file, if the directory falls under
75 exclusion_tag_under */
76 char *caname; /* canonical name */
77 char *name; /* file name of directory */
78 };
79
80 struct dumpdir *
81 dumpdir_create0 (const char *contents, const char *cmask)
82 {
83 struct dumpdir *dump;
84 size_t i, total, ctsize, len;
85 char *p;
86 const char *q;
87
88 for (i = 0, total = 0, ctsize = 1, q = contents; *q; total++, q += len)
89 {
90 len = strlen (q) + 1;
91 ctsize += len;
92 if (!cmask || strchr (cmask, *q))
93 i++;
94 }
95 dump = xmalloc (sizeof (*dump) + ctsize);
96 dump->contents = (char*)(dump + 1);
97 memcpy (dump->contents, contents, ctsize);
98 dump->total = total;
99 dump->elc = i;
100 dump->elv = xcalloc (i + 1, sizeof (dump->elv[0]));
101
102 for (i = 0, p = dump->contents; *p; p += strlen (p) + 1)
103 {
104 if (!cmask || strchr (cmask, *p))
105 dump->elv[i++] = p + 1;
106 }
107 dump->elv[i] = NULL;
108 return dump;
109 }
110
111 struct dumpdir *
112 dumpdir_create (const char *contents)
113 {
114 return dumpdir_create0 (contents, "YND");
115 }
116
117 void
118 dumpdir_free (struct dumpdir *dump)
119 {
120 free (dump->elv);
121 free (dump);
122 }
123
124 static int
125 compare_dirnames (const void *first, const void *second)
126 {
127 char const *const *name1 = first;
128 char const *const *name2 = second;
129 return strcmp (*name1, *name2);
130 }
131
132 /* Locate NAME in the dumpdir array DUMP.
133 Return pointer to the slot in DUMP->contents, or NULL if not found */
134 char *
135 dumpdir_locate (struct dumpdir *dump, const char *name)
136 {
137 char **ptr;
138 if (!dump)
139 return NULL;
140
141 ptr = bsearch (&name, dump->elv, dump->elc, sizeof (dump->elv[0]),
142 compare_dirnames);
143 return ptr ? *ptr - 1: NULL;
144 }
145
146 struct dumpdir_iter
147 {
148 struct dumpdir *dump; /* Dumpdir being iterated */
149 int all; /* Iterate over all entries, not only D/N/Y */
150 size_t next; /* Index of the next element */
151 };
152
153 char *
154 dumpdir_next (struct dumpdir_iter *itr)
155 {
156 size_t cur = itr->next;
157 char *ret = NULL;
158
159 if (itr->all)
160 {
161 ret = itr->dump->contents + cur;
162 if (*ret == 0)
163 return NULL;
164 itr->next += strlen (ret) + 1;
165 }
166 else if (cur < itr->dump->elc)
167 {
168 ret = itr->dump->elv[cur] - 1;
169 itr->next++;
170 }
171
172 return ret;
173 }
174
175 char *
176 dumpdir_first (struct dumpdir *dump, int all, struct dumpdir_iter **pitr)
177 {
178 struct dumpdir_iter *itr = xmalloc (sizeof (*itr));
179 itr->dump = dump;
180 itr->all = all;
181 itr->next = 0;
182 *pitr = itr;
183 return dumpdir_next (itr);
184 }
185
186 /* Return size in bytes of the dumpdir array P */
187 size_t
188 dumpdir_size (const char *p)
189 {
190 size_t totsize = 0;
191
192 while (*p)
193 {
194 size_t size = strlen (p) + 1;
195 totsize += size;
196 p += size;
197 }
198 return totsize + 1;
199 }
200
201 \f
202 static struct directory *dirhead, *dirtail;
203 static Hash_table *directory_table;
204 static Hash_table *directory_meta_table;
205
206 #if HAVE_ST_FSTYPE_STRING
207 static char const nfs_string[] = "nfs";
208 # define NFS_FILE_STAT(st) (strcmp ((st).st_fstype, nfs_string) == 0)
209 #else
210 # define ST_DEV_MSB(st) (~ (dev_t) 0 << (sizeof (st).st_dev * CHAR_BIT - 1))
211 # define NFS_FILE_STAT(st) (((st).st_dev & ST_DEV_MSB (st)) != 0)
212 #endif
213
214 /* Calculate the hash of a directory. */
215 static size_t
216 hash_directory_canonical_name (void const *entry, size_t n_buckets)
217 {
218 struct directory const *directory = entry;
219 return hash_string (directory->caname, n_buckets);
220 }
221
222 /* Compare two directories for equality of their names. */
223 static bool
224 compare_directory_canonical_names (void const *entry1, void const *entry2)
225 {
226 struct directory const *directory1 = entry1;
227 struct directory const *directory2 = entry2;
228 return strcmp (directory1->caname, directory2->caname) == 0;
229 }
230
231 static size_t
232 hash_directory_meta (void const *entry, size_t n_buckets)
233 {
234 struct directory const *directory = entry;
235 /* FIXME: Work out a better algorytm */
236 return (directory->device_number + directory->inode_number) % n_buckets;
237 }
238
239 /* Compare two directories for equality of their device and inode numbers. */
240 static bool
241 compare_directory_meta (void const *entry1, void const *entry2)
242 {
243 struct directory const *directory1 = entry1;
244 struct directory const *directory2 = entry2;
245 return directory1->device_number == directory2->device_number
246 && directory1->inode_number == directory2->inode_number;
247 }
248
249 /* Make a directory entry for given relative NAME and canonical name CANAME.
250 The latter is "stolen", i.e. the returned directory contains pointer to
251 it. */
252 static struct directory *
253 make_directory (const char *name, char *caname)
254 {
255 size_t namelen = strlen (name);
256 struct directory *directory = xmalloc (sizeof (*directory));
257 directory->next = NULL;
258 directory->dump = directory->idump = NULL;
259 directory->orig = NULL;
260 directory->flags = false;
261 if (namelen && ISSLASH (name[namelen - 1]))
262 namelen--;
263 directory->name = xmalloc (namelen + 1);
264 memcpy (directory->name, name, namelen);
265 directory->name[namelen] = 0;
266 directory->caname = caname;
267 directory->tagfile = NULL;
268 return directory;
269 }
270
271 static void
272 free_directory (struct directory *dir)
273 {
274 free (dir->caname);
275 free (dir->name);
276 free (dir);
277 }
278
279 static struct directory *
280 attach_directory (const char *name)
281 {
282 char *cname = normalize_filename (name);
283 struct directory *dir = make_directory (name, cname);
284 if (dirtail)
285 dirtail->next = dir;
286 else
287 dirhead = dir;
288 dirtail = dir;
289 return dir;
290 }
291
292 \f
293 void
294 dirlist_replace_prefix (const char *pref, const char *repl)
295 {
296 struct directory *dp;
297 size_t pref_len = strlen (pref);
298 size_t repl_len = strlen (repl);
299 for (dp = dirhead; dp; dp = dp->next)
300 replace_prefix (&dp->name, pref, pref_len, repl, repl_len);
301 }
302
303 /* Create and link a new directory entry for directory NAME, having a
304 device number DEV and an inode number INO, with NFS indicating
305 whether it is an NFS device and FOUND indicating whether we have
306 found that the directory exists. */
307 static struct directory *
308 note_directory (char const *name, struct timespec mtime,
309 dev_t dev, ino_t ino, bool nfs, bool found,
310 const char *contents)
311 {
312 struct directory *directory = attach_directory (name);
313
314 directory->mtime = mtime;
315 directory->device_number = dev;
316 directory->inode_number = ino;
317 directory->children = CHANGED_CHILDREN;
318 if (nfs)
319 DIR_SET_FLAG (directory, DIRF_NFS);
320 if (found)
321 DIR_SET_FLAG (directory, DIRF_FOUND);
322 if (contents)
323 directory->dump = dumpdir_create (contents);
324 else
325 directory->dump = NULL;
326
327 if (! ((directory_table
328 || (directory_table = hash_initialize (0, 0,
329 hash_directory_canonical_name,
330 compare_directory_canonical_names, 0)))
331 && hash_insert (directory_table, directory)))
332 xalloc_die ();
333
334 if (! ((directory_meta_table
335 || (directory_meta_table = hash_initialize (0, 0,
336 hash_directory_meta,
337 compare_directory_meta,
338 0)))
339 && hash_insert (directory_meta_table, directory)))
340 xalloc_die ();
341
342 return directory;
343 }
344
345 /* Return a directory entry for a given file NAME, or zero if none found. */
346 static struct directory *
347 find_directory (const char *name)
348 {
349 if (! directory_table)
350 return 0;
351 else
352 {
353 char *caname = normalize_filename (name);
354 struct directory *dir = make_directory (name, caname);
355 struct directory *ret = hash_lookup (directory_table, dir);
356 free_directory (dir);
357 return ret;
358 }
359 }
360
361 #if 0
362 /* Remove directory entry for the given CANAME */
363 void
364 remove_directory (const char *caname)
365 {
366 struct directory *dir = make_directory (caname, xstrdup (caname));
367 struct directory *ret = hash_delete (directory_table, dir);
368 if (ret)
369 free_directory (ret);
370 free_directory (dir);
371 }
372 #endif
373
374 /* If first OLD_PREFIX_LEN bytes of DIR->NAME name match OLD_PREFIX,
375 replace them with NEW_PREFIX. */
376 void
377 rebase_directory (struct directory *dir,
378 const char *old_prefix, size_t old_prefix_len,
379 const char *new_prefix, size_t new_prefix_len)
380 {
381 replace_prefix (&dir->name, old_prefix, old_prefix_len,
382 new_prefix, new_prefix_len);
383 }
384
385 /* Return a directory entry for a given combination of device and inode
386 numbers, or zero if none found. */
387 static struct directory *
388 find_directory_meta (dev_t dev, ino_t ino)
389 {
390 if (! directory_meta_table)
391 return 0;
392 else
393 {
394 struct directory *dir = make_directory ("", NULL);
395 struct directory *ret;
396 dir->device_number = dev;
397 dir->inode_number = ino;
398 ret = hash_lookup (directory_meta_table, dir);
399 free_directory (dir);
400 return ret;
401 }
402 }
403
404 void
405 update_parent_directory (const char *name)
406 {
407 struct directory *directory;
408 char *p;
409
410 p = dir_name (name);
411 directory = find_directory (p);
412 if (directory)
413 {
414 struct stat st;
415 if (deref_stat (dereference_option, p, &st) != 0)
416 stat_diag (name);
417 else
418 directory->mtime = get_stat_mtime (&st);
419 }
420 free (p);
421 }
422
423 #define PD_FORCE_CHILDREN 0x10
424 #define PD_FORCE_INIT 0x20
425 #define PD_CHILDREN(f) ((f) & 3)
426
427 static struct directory *
428 procdir (const char *name_buffer, struct stat *stat_data,
429 dev_t device,
430 int flag,
431 char *entry)
432 {
433 struct directory *directory;
434 bool nfs = NFS_FILE_STAT (*stat_data);
435
436 if ((directory = find_directory (name_buffer)) != NULL)
437 {
438 if (DIR_IS_INITED (directory))
439 {
440 if (flag & PD_FORCE_INIT)
441 {
442 assign_string (&directory->name, name_buffer);
443 }
444 else
445 {
446 *entry = 'N'; /* Avoid duplicating this directory */
447 return directory;
448 }
449 }
450
451 if (strcmp (directory->name, name_buffer))
452 {
453 *entry = 'N';
454 return directory;
455 }
456
457 /* With NFS, the same file can have two different devices
458 if an NFS directory is mounted in multiple locations,
459 which is relatively common when automounting.
460 To avoid spurious incremental redumping of
461 directories, consider all NFS devices as equal,
462 relying on the i-node to establish differences. */
463
464 if (! ((!check_device_option
465 || (DIR_IS_NFS (directory) && nfs)
466 || directory->device_number == stat_data->st_dev)
467 && directory->inode_number == stat_data->st_ino))
468 {
469 /* FIXME: find_directory_meta ignores nfs */
470 struct directory *d = find_directory_meta (stat_data->st_dev,
471 stat_data->st_ino);
472 if (d)
473 {
474 if (strcmp (d->name, name_buffer))
475 {
476 WARNOPT (WARN_RENAME_DIRECTORY,
477 (0, 0,
478 _("%s: Directory has been renamed from %s"),
479 quotearg_colon (name_buffer),
480 quote_n (1, d->name)));
481 directory->orig = d;
482 DIR_SET_FLAG (directory, DIRF_RENAMED);
483 dirlist_replace_prefix (d->name, name_buffer);
484 }
485 directory->children = CHANGED_CHILDREN;
486 }
487 else
488 {
489 WARNOPT (WARN_RENAME_DIRECTORY,
490 (0, 0, _("%s: Directory has been renamed"),
491 quotearg_colon (name_buffer)));
492 directory->children = ALL_CHILDREN;
493 directory->device_number = stat_data->st_dev;
494 directory->inode_number = stat_data->st_ino;
495 }
496 if (nfs)
497 DIR_SET_FLAG (directory, DIRF_NFS);
498 }
499 else
500 directory->children = CHANGED_CHILDREN;
501
502 DIR_SET_FLAG (directory, DIRF_FOUND);
503 }
504 else
505 {
506 struct directory *d = find_directory_meta (stat_data->st_dev,
507 stat_data->st_ino);
508
509 directory = note_directory (name_buffer,
510 get_stat_mtime(stat_data),
511 stat_data->st_dev,
512 stat_data->st_ino,
513 nfs,
514 true,
515 NULL);
516
517 if (d)
518 {
519 if (strcmp (d->name, name_buffer))
520 {
521 WARNOPT (WARN_RENAME_DIRECTORY,
522 (0, 0, _("%s: Directory has been renamed from %s"),
523 quotearg_colon (name_buffer),
524 quote_n (1, d->name)));
525 directory->orig = d;
526 DIR_SET_FLAG (directory, DIRF_RENAMED);
527 dirlist_replace_prefix (d->name, name_buffer);
528 }
529 directory->children = CHANGED_CHILDREN;
530 }
531 else
532 {
533 DIR_SET_FLAG (directory, DIRF_NEW);
534 WARNOPT (WARN_NEW_DIRECTORY,
535 (0, 0, _("%s: Directory is new"),
536 quotearg_colon (name_buffer)));
537 directory->children =
538 (listed_incremental_option
539 || (OLDER_STAT_TIME (*stat_data, m)
540 || (after_date_option
541 && OLDER_STAT_TIME (*stat_data, c))))
542 ? ALL_CHILDREN
543 : CHANGED_CHILDREN;
544 }
545 }
546
547 /* If the directory is on another device and --one-file-system was given,
548 omit it... */
549 if (one_file_system_option && device != stat_data->st_dev
550 /* ... except if it was explicitely given in the command line */
551 && !is_individual_file (name_buffer))
552 directory->children = NO_CHILDREN;
553 else if (flag & PD_FORCE_CHILDREN)
554 {
555 directory->children = PD_CHILDREN(flag);
556 if (directory->children == NO_CHILDREN)
557 *entry = 'N';
558 }
559
560 DIR_SET_FLAG (directory, DIRF_INIT);
561
562 if (directory->children != NO_CHILDREN)
563 {
564 const char *tag_file_name;
565
566 switch (check_exclusion_tags (name_buffer, &tag_file_name))
567 {
568 case exclusion_tag_all:
569 /* This warning can be duplicated by code in dump_file0, but only
570 in case when the topmost directory being archived contains
571 an exclusion tag. */
572 exclusion_tag_warning (name_buffer, tag_file_name,
573 _("directory not dumped"));
574 *entry = 'N';
575 directory->children = NO_CHILDREN;
576 break;
577
578 case exclusion_tag_contents:
579 exclusion_tag_warning (name_buffer, tag_file_name,
580 _("contents not dumped"));
581 directory->children = NO_CHILDREN;
582 break;
583
584 case exclusion_tag_under:
585 exclusion_tag_warning (name_buffer, tag_file_name,
586 _("contents not dumped"));
587 directory->tagfile = tag_file_name;
588 break;
589
590 case exclusion_tag_none:
591 break;
592 }
593 }
594
595 return directory;
596 }
597
598 /* Compare dumpdir array from DIRECTORY with directory listing DIR and
599 build a new dumpdir template.
600
601 DIR must be returned by a previous call to savedir().
602
603 File names in DIRECTORY->dump->contents must be sorted
604 alphabetically.
605
606 DIRECTORY->dump is replaced with the created template. Each entry is
607 prefixed with ' ' if it was present in DUMP and with 'Y' otherwise. */
608
609 void
610 makedumpdir (struct directory *directory, const char *dir)
611 {
612 size_t i,
613 dirsize, /* Number of elements in DIR */
614 len; /* Length of DIR, including terminating nul */
615 const char *p;
616 char const **array;
617 char *new_dump, *new_dump_ptr;
618 struct dumpdir *dump;
619
620 if (directory->children == ALL_CHILDREN)
621 dump = NULL;
622 else if (DIR_IS_RENAMED (directory))
623 dump = directory->orig->idump ?
624 directory->orig->idump : directory->orig->dump;
625 else
626 dump = directory->dump;
627
628 /* Count the size of DIR and the number of elements it contains */
629 dirsize = 0;
630 len = 0;
631 for (p = dir; *p; p += strlen (p) + 1, dirsize++)
632 len += strlen (p) + 2;
633 len++;
634
635 /* Create a sorted directory listing */
636 array = xcalloc (dirsize, sizeof array[0]);
637 for (i = 0, p = dir; *p; p += strlen (p) + 1, i++)
638 array[i] = p;
639
640 qsort (array, dirsize, sizeof (array[0]), compare_dirnames);
641
642 /* Prepare space for new dumpdir */
643 new_dump = xmalloc (len);
644 new_dump_ptr = new_dump;
645
646 /* Fill in the dumpdir template */
647 for (i = 0; i < dirsize; i++)
648 {
649 const char *loc = dumpdir_locate (dump, array[i]);
650 if (loc)
651 {
652 if (directory->tagfile)
653 *new_dump_ptr = strcmp (directory->tagfile, array[i]) == 0 ?
654 ' ' : 'I';
655 else
656 *new_dump_ptr = ' ';
657 new_dump_ptr++;
658 }
659 else if (directory->tagfile)
660 *new_dump_ptr++ = strcmp (directory->tagfile, array[i]) == 0 ?
661 ' ' : 'I';
662 else
663 *new_dump_ptr++ = 'Y'; /* New entry */
664
665 /* Copy the file name */
666 for (p = array[i]; (*new_dump_ptr++ = *p++); )
667 ;
668 }
669 *new_dump_ptr = 0;
670 directory->idump = directory->dump;
671 directory->dump = dumpdir_create0 (new_dump, NULL);
672 free (array);
673 }
674
675 /* Recursively scan the given directory DIR.
676 DEVICE is the device number where DIR resides (for --one-file-system).
677 If CMDLINE is true, the directory name was explicitly listed in the
678 command line.
679 Unless *PDIR is NULL, store there a pointer to the struct directory
680 describing DIR. */
681 struct directory *
682 scan_directory (char *dir, dev_t device, bool cmdline)
683 {
684 char *dirp = savedir (dir); /* for scanning directory */
685 char *name_buffer; /* directory, `/', and directory member */
686 size_t name_buffer_size; /* allocated size of name_buffer, minus 2 */
687 size_t name_length; /* used length in name_buffer */
688 struct stat stat_data;
689 struct directory *directory;
690 char ch;
691
692 if (! dirp)
693 savedir_error (dir);
694
695 name_buffer_size = strlen (dir) + NAME_FIELD_SIZE;
696 name_buffer = xmalloc (name_buffer_size + 2);
697 strcpy (name_buffer, dir);
698 zap_slashes (name_buffer);
699
700 if (deref_stat (dereference_option, name_buffer, &stat_data))
701 {
702 stat_diag (name_buffer);
703 /* FIXME: used to be
704 children = CHANGED_CHILDREN;
705 but changed to: */
706 free (name_buffer);
707 free (dirp);
708 return NULL;
709 }
710
711 directory = procdir (name_buffer, &stat_data, device,
712 (cmdline ? PD_FORCE_INIT : 0),
713 &ch);
714
715 name_length = strlen (name_buffer);
716 if (! ISSLASH (name_buffer[name_length - 1]))
717 {
718 name_buffer[name_length] = DIRECTORY_SEPARATOR;
719 /* name_buffer has been allocated an extra slot */
720 name_buffer[++name_length] = 0;
721 }
722
723 if (dirp && directory->children != NO_CHILDREN)
724 {
725 char *entry; /* directory entry being scanned */
726 size_t entrylen; /* length of directory entry */
727 dumpdir_iter_t itr;
728
729 makedumpdir (directory, dirp);
730
731 for (entry = dumpdir_first (directory->dump, 1, &itr);
732 entry;
733 entry = dumpdir_next (itr))
734 {
735 entrylen = strlen (entry);
736 if (name_buffer_size <= entrylen - 1 + name_length)
737 {
738 do
739 name_buffer_size += NAME_FIELD_SIZE;
740 while (name_buffer_size <= entrylen - 1 + name_length);
741 name_buffer = xrealloc (name_buffer, name_buffer_size + 2);
742 }
743 strcpy (name_buffer + name_length, entry + 1);
744
745 if (*entry == 'I') /* Ignored entry */
746 *entry = 'N';
747 else if (excluded_name (name_buffer))
748 *entry = 'N';
749 else
750 {
751 if (deref_stat (dereference_option, name_buffer, &stat_data))
752 {
753 stat_diag (name_buffer);
754 *entry = 'N';
755 continue;
756 }
757
758 if (S_ISDIR (stat_data.st_mode))
759 {
760 int pd_flag = 0;
761 if (!recursion_option)
762 pd_flag |= PD_FORCE_CHILDREN | NO_CHILDREN;
763 else if (directory->children == ALL_CHILDREN)
764 pd_flag |= PD_FORCE_CHILDREN | ALL_CHILDREN;
765 *entry = 'D';
766 procdir (name_buffer, &stat_data, device, pd_flag, entry);
767 }
768
769 else if (one_file_system_option && device != stat_data.st_dev)
770 *entry = 'N';
771
772 else if (*entry == 'Y')
773 /* New entry, skip further checks */;
774
775 /* FIXME: if (S_ISHIDDEN (stat_data.st_mode))?? */
776
777 else if (OLDER_STAT_TIME (stat_data, m)
778 && (!after_date_option
779 || OLDER_STAT_TIME (stat_data, c)))
780 *entry = 'N';
781 else
782 *entry = 'Y';
783 }
784 }
785 free (itr);
786 }
787
788 free (name_buffer);
789 if (dirp)
790 free (dirp);
791
792 return directory;
793 }
794
795 /* Return pointer to the contents of the directory DIR */
796 const char *
797 directory_contents (struct directory *dir)
798 {
799 if (!dir)
800 return NULL;
801 return dir->dump ? dir->dump->contents : NULL;
802 }
803
804 /* A "safe" version of directory_contents, which never returns NULL. */
805 const char *
806 safe_directory_contents (struct directory *dir)
807 {
808 const char *ret = directory_contents (dir);
809 return ret ? ret : "\0\0\0\0";
810 }
811
812 void
813 name_fill_directory (struct name *name, dev_t device, bool cmdline)
814 {
815 name->directory = scan_directory (name->name, device, cmdline);
816 }
817
818 \f
819 static void
820 obstack_code_rename (struct obstack *stk, char *from, char *to)
821 {
822 char *s;
823
824 s = from[0] == 0 ? from :
825 safer_name_suffix (from, false, absolute_names_option);
826 obstack_1grow (stk, 'R');
827 obstack_grow (stk, s, strlen (s) + 1);
828
829 s = to[0] == 0 ? to:
830 safer_name_suffix (to, false, absolute_names_option);
831 obstack_1grow (stk, 'T');
832 obstack_grow (stk, s, strlen (s) + 1);
833 }
834
835 static void
836 store_rename (struct directory *dir, struct obstack *stk)
837 {
838 if (DIR_IS_RENAMED (dir))
839 {
840 struct directory *prev, *p;
841
842 /* Detect eventual cycles and clear DIRF_RENAMED flag, so these entries
843 are ignored when hit by this function next time.
844 If the chain forms a cycle, prev points to the entry DIR is renamed
845 from. In this case it still retains DIRF_RENAMED flag, which will be
846 cleared in the `else' branch below */
847 for (prev = dir; prev && prev->orig != dir; prev = prev->orig)
848 DIR_CLEAR_FLAG (prev, DIRF_RENAMED);
849
850 if (prev == NULL)
851 {
852 for (p = dir; p && p->orig; p = p->orig)
853 obstack_code_rename (stk, p->orig->name, p->name);
854 }
855 else
856 {
857 char *temp_name;
858
859 DIR_CLEAR_FLAG (prev, DIRF_RENAMED);
860
861 /* Break the cycle by using a temporary name for one of its
862 elements.
863 First, create a temp name stub entry. */
864 temp_name = dir_name (dir->name);
865 obstack_1grow (stk, 'X');
866 obstack_grow (stk, temp_name, strlen (temp_name) + 1);
867
868 obstack_code_rename (stk, dir->name, "");
869
870 for (p = dir; p != prev; p = p->orig)
871 obstack_code_rename (stk, p->orig->name, p->name);
872
873 obstack_code_rename (stk, "", prev->name);
874 }
875 }
876 }
877
878 void
879 append_incremental_renames (struct directory *dir)
880 {
881 struct obstack stk;
882 size_t size;
883 struct directory *dp;
884 const char *dump;
885
886 if (dirhead == NULL)
887 return;
888
889 obstack_init (&stk);
890 dump = directory_contents (dir);
891 if (dump)
892 {
893 size = dumpdir_size (dump) - 1;
894 obstack_grow (&stk, dump, size);
895 }
896 else
897 size = 0;
898
899 for (dp = dirhead; dp; dp = dp->next)
900 store_rename (dp, &stk);
901
902 if (obstack_object_size (&stk) != size)
903 {
904 obstack_1grow (&stk, 0);
905 dumpdir_free (dir->dump);
906 dir->dump = dumpdir_create (obstack_finish (&stk));
907 }
908 obstack_free (&stk, NULL);
909 }
910
911 \f
912
913 static FILE *listed_incremental_stream;
914
915 /* Version of incremental format snapshots (directory files) used by this
916 tar. Currently it is supposed to be a single decimal number. 0 means
917 incremental snapshots as per tar version before 1.15.2.
918
919 The current tar version supports incremental versions from
920 0 up to TAR_INCREMENTAL_VERSION, inclusive.
921 It is able to create only snapshots of TAR_INCREMENTAL_VERSION */
922
923 #define TAR_INCREMENTAL_VERSION 2
924
925 /* Read incremental snapshot formats 0 and 1 */
926 static void
927 read_incr_db_01 (int version, const char *initbuf)
928 {
929 int n;
930 uintmax_t u;
931 time_t sec;
932 long int nsec;
933 char *buf = 0;
934 size_t bufsize;
935 char *ebuf;
936 long lineno = 1;
937
938 if (version == 1)
939 {
940 if (getline (&buf, &bufsize, listed_incremental_stream) <= 0)
941 {
942 read_error (listed_incremental_option);
943 free (buf);
944 return;
945 }
946 ++lineno;
947 }
948 else
949 {
950 buf = strdup (initbuf);
951 bufsize = strlen (buf) + 1;
952 }
953
954 sec = TYPE_MINIMUM (time_t);
955 nsec = -1;
956 errno = 0;
957 u = strtoumax (buf, &ebuf, 10);
958 if (!errno && TYPE_MAXIMUM (time_t) < u)
959 errno = ERANGE;
960 if (errno || buf == ebuf)
961 ERROR ((0, errno, "%s:%ld: %s",
962 quotearg_colon (listed_incremental_option),
963 lineno,
964 _("Invalid time stamp")));
965 else
966 {
967 sec = u;
968
969 if (version == 1 && *ebuf)
970 {
971 char const *buf_ns = ebuf + 1;
972 errno = 0;
973 u = strtoumax (buf_ns, &ebuf, 10);
974 if (!errno && BILLION <= u)
975 errno = ERANGE;
976 if (errno || buf_ns == ebuf)
977 {
978 ERROR ((0, errno, "%s:%ld: %s",
979 quotearg_colon (listed_incremental_option),
980 lineno,
981 _("Invalid time stamp")));
982 sec = TYPE_MINIMUM (time_t);
983 }
984 else
985 nsec = u;
986 }
987 else
988 {
989 /* pre-1 incremental format does not contain nanoseconds */
990 nsec = 0;
991 }
992 }
993 newer_mtime_option.tv_sec = sec;
994 newer_mtime_option.tv_nsec = nsec;
995
996
997 while (0 < (n = getline (&buf, &bufsize, listed_incremental_stream)))
998 {
999 dev_t dev;
1000 ino_t ino;
1001 bool nfs = buf[0] == '+';
1002 char *strp = buf + nfs;
1003 struct timespec mtime;
1004
1005 lineno++;
1006
1007 if (buf[n - 1] == '\n')
1008 buf[n - 1] = '\0';
1009
1010 if (version == 1)
1011 {
1012 errno = 0;
1013 u = strtoumax (strp, &ebuf, 10);
1014 if (!errno && TYPE_MAXIMUM (time_t) < u)
1015 errno = ERANGE;
1016 if (errno || strp == ebuf || *ebuf != ' ')
1017 {
1018 ERROR ((0, errno, "%s:%ld: %s",
1019 quotearg_colon (listed_incremental_option), lineno,
1020 _("Invalid modification time (seconds)")));
1021 sec = (time_t) -1;
1022 }
1023 else
1024 sec = u;
1025 strp = ebuf;
1026
1027 errno = 0;
1028 u = strtoumax (strp, &ebuf, 10);
1029 if (!errno && BILLION <= u)
1030 errno = ERANGE;
1031 if (errno || strp == ebuf || *ebuf != ' ')
1032 {
1033 ERROR ((0, errno, "%s:%ld: %s",
1034 quotearg_colon (listed_incremental_option), lineno,
1035 _("Invalid modification time (nanoseconds)")));
1036 nsec = -1;
1037 }
1038 else
1039 nsec = u;
1040 mtime.tv_sec = sec;
1041 mtime.tv_nsec = nsec;
1042 strp = ebuf;
1043 }
1044 else
1045 memset (&mtime, 0, sizeof mtime);
1046
1047 errno = 0;
1048 u = strtoumax (strp, &ebuf, 10);
1049 if (!errno && TYPE_MAXIMUM (dev_t) < u)
1050 errno = ERANGE;
1051 if (errno || strp == ebuf || *ebuf != ' ')
1052 {
1053 ERROR ((0, errno, "%s:%ld: %s",
1054 quotearg_colon (listed_incremental_option), lineno,
1055 _("Invalid device number")));
1056 dev = (dev_t) -1;
1057 }
1058 else
1059 dev = u;
1060 strp = ebuf;
1061
1062 errno = 0;
1063 u = strtoumax (strp, &ebuf, 10);
1064 if (!errno && TYPE_MAXIMUM (ino_t) < u)
1065 errno = ERANGE;
1066 if (errno || strp == ebuf || *ebuf != ' ')
1067 {
1068 ERROR ((0, errno, "%s:%ld: %s",
1069 quotearg_colon (listed_incremental_option), lineno,
1070 _("Invalid inode number")));
1071 ino = (ino_t) -1;
1072 }
1073 else
1074 ino = u;
1075 strp = ebuf;
1076
1077 strp++;
1078 unquote_string (strp);
1079 note_directory (strp, mtime, dev, ino, nfs, false, NULL);
1080 }
1081 free (buf);
1082 }
1083
1084 /* Read a nul-terminated string from FP and store it in STK.
1085 Store the number of bytes read (including nul terminator) in PCOUNT.
1086
1087 Return the last character read or EOF on end of file. */
1088 static int
1089 read_obstack (FILE *fp, struct obstack *stk, size_t *pcount)
1090 {
1091 int c;
1092 size_t i;
1093
1094 for (i = 0, c = getc (fp); c != EOF && c != 0; c = getc (fp), i++)
1095 obstack_1grow (stk, c);
1096 obstack_1grow (stk, 0);
1097
1098 *pcount = i;
1099 return c;
1100 }
1101
1102 /* Read from file FP a nul-terminated string and convert it to
1103 intmax_t. Return the resulting value in PVAL. Assume '-' has
1104 already been read.
1105
1106 Throw a fatal error if the string cannot be converted or if the
1107 converted value is less than MIN_VAL. */
1108
1109 static void
1110 read_negative_num (FILE *fp, intmax_t min_val, intmax_t *pval)
1111 {
1112 int c;
1113 size_t i;
1114 char buf[INT_BUFSIZE_BOUND (intmax_t)];
1115 char *ep;
1116 buf[0] = '-';
1117
1118 for (i = 1; ISDIGIT (c = getc (fp)); i++)
1119 {
1120 if (i == sizeof buf - 1)
1121 FATAL_ERROR ((0, 0, _("Field too long while reading snapshot file")));
1122 buf[i] = c;
1123 }
1124
1125 if (c < 0)
1126 {
1127 if (ferror (fp))
1128 FATAL_ERROR ((0, errno, _("Read error in snapshot file")));
1129 else
1130 FATAL_ERROR ((0, 0, _("Unexpected EOF in snapshot file")));
1131 }
1132
1133 buf[i] = 0;
1134 errno = 0;
1135 *pval = strtoimax (buf, &ep, 10);
1136 if (c || errno || *pval < min_val)
1137 FATAL_ERROR ((0, errno, _("Unexpected field value in snapshot file")));
1138 }
1139
1140 /* Read from file FP a nul-terminated string and convert it to
1141 uintmax_t. Return the resulting value in PVAL. Assume C has
1142 already been read.
1143
1144 Throw a fatal error if the string cannot be converted or if the
1145 converted value exceeds MAX_VAL.
1146
1147 Return the last character read or EOF on end of file. */
1148
1149 static int
1150 read_unsigned_num (int c, FILE *fp, uintmax_t max_val, uintmax_t *pval)
1151 {
1152 size_t i;
1153 char buf[UINTMAX_STRSIZE_BOUND], *ep;
1154
1155 for (i = 0; ISDIGIT (c); i++)
1156 {
1157 if (i == sizeof buf - 1)
1158 FATAL_ERROR ((0, 0, _("Field too long while reading snapshot file")));
1159 buf[i] = c;
1160 c = getc (fp);
1161 }
1162
1163 if (c < 0)
1164 {
1165 if (ferror (fp))
1166 FATAL_ERROR ((0, errno, _("Read error in snapshot file")));
1167 else if (i == 0)
1168 return c;
1169 else
1170 FATAL_ERROR ((0, 0, _("Unexpected EOF in snapshot file")));
1171 }
1172
1173 buf[i] = 0;
1174 errno = 0;
1175 *pval = strtoumax (buf, &ep, 10);
1176 if (c || errno || max_val < *pval)
1177 FATAL_ERROR ((0, errno, _("Unexpected field value in snapshot file")));
1178 return c;
1179 }
1180
1181 /* Read from file FP a nul-terminated string and convert it to
1182 uintmax_t. Return the resulting value in PVAL.
1183
1184 Throw a fatal error if the string cannot be converted or if the
1185 converted value exceeds MAX_VAL.
1186
1187 Return the last character read or EOF on end of file. */
1188
1189 static int
1190 read_num (FILE *fp, uintmax_t max_val, uintmax_t *pval)
1191 {
1192 return read_unsigned_num (getc (fp), fp, max_val, pval);
1193 }
1194
1195 /* Read from FP two NUL-terminated strings representing a struct
1196 timespec. Return the resulting value in PVAL.
1197
1198 Throw a fatal error if the string cannot be converted. */
1199
1200 static void
1201 read_timespec (FILE *fp, struct timespec *pval)
1202 {
1203 int c = getc (fp);
1204 intmax_t i;
1205 uintmax_t u;
1206
1207 if (c == '-')
1208 {
1209 read_negative_num (fp, TYPE_MINIMUM (time_t), &i);
1210 c = 0;
1211 pval->tv_sec = i;
1212 }
1213 else
1214 {
1215 c = read_unsigned_num (c, fp, TYPE_MAXIMUM (time_t), &u);
1216 pval->tv_sec = u;
1217 }
1218
1219 if (c || read_num (fp, BILLION - 1, &u))
1220 FATAL_ERROR ((0, 0, "%s: %s",
1221 quotearg_colon (listed_incremental_option),
1222 _("Unexpected EOF in snapshot file")));
1223 pval->tv_nsec = u;
1224 }
1225
1226 /* Read incremental snapshot format 2 */
1227 static void
1228 read_incr_db_2 ()
1229 {
1230 uintmax_t u;
1231 struct obstack stk;
1232
1233 obstack_init (&stk);
1234
1235 read_timespec (listed_incremental_stream, &newer_mtime_option);
1236
1237 for (;;)
1238 {
1239 struct timespec mtime;
1240 dev_t dev;
1241 ino_t ino;
1242 bool nfs;
1243 char *name;
1244 char *content;
1245 size_t s;
1246
1247 if (read_num (listed_incremental_stream, 1, &u))
1248 return; /* Normal return */
1249
1250 nfs = u;
1251
1252 read_timespec (listed_incremental_stream, &mtime);
1253
1254 if (read_num (listed_incremental_stream, TYPE_MAXIMUM (dev_t), &u))
1255 break;
1256 dev = u;
1257
1258 if (read_num (listed_incremental_stream, TYPE_MAXIMUM (ino_t), &u))
1259 break;
1260 ino = u;
1261
1262 if (read_obstack (listed_incremental_stream, &stk, &s))
1263 break;
1264
1265 name = obstack_finish (&stk);
1266
1267 while (read_obstack (listed_incremental_stream, &stk, &s) == 0 && s > 1)
1268 ;
1269 if (getc (listed_incremental_stream) != 0)
1270 FATAL_ERROR ((0, 0, "%s: %s",
1271 quotearg_colon (listed_incremental_option),
1272 _("Missing record terminator")));
1273
1274 content = obstack_finish (&stk);
1275 note_directory (name, mtime, dev, ino, nfs, false, content);
1276 obstack_free (&stk, content);
1277 }
1278 FATAL_ERROR ((0, 0, "%s: %s",
1279 quotearg_colon (listed_incremental_option),
1280 _("Unexpected EOF in snapshot file")));
1281 }
1282
1283 /* Read incremental snapshot file (directory file).
1284 If the file has older incremental version, make sure that it is processed
1285 correctly and that tar will use the most conservative backup method among
1286 possible alternatives (i.e. prefer ALL_CHILDREN over CHANGED_CHILDREN,
1287 etc.) This ensures that the snapshots are updated to the recent version
1288 without any loss of data. */
1289 void
1290 read_directory_file (void)
1291 {
1292 int fd;
1293 char *buf = 0;
1294 size_t bufsize;
1295 int flags = O_RDWR | O_CREAT;
1296
1297 if (incremental_level == 0)
1298 flags |= O_TRUNC;
1299 /* Open the file for both read and write. That way, we can write
1300 it later without having to reopen it, and don't have to worry if
1301 we chdir in the meantime. */
1302 fd = open (listed_incremental_option, flags, MODE_RW);
1303 if (fd < 0)
1304 {
1305 open_error (listed_incremental_option);
1306 return;
1307 }
1308
1309 listed_incremental_stream = fdopen (fd, "r+");
1310 if (! listed_incremental_stream)
1311 {
1312 open_error (listed_incremental_option);
1313 close (fd);
1314 return;
1315 }
1316
1317 if (0 < getline (&buf, &bufsize, listed_incremental_stream))
1318 {
1319 char *ebuf;
1320 uintmax_t incremental_version;
1321
1322 if (strncmp (buf, PACKAGE_NAME, sizeof PACKAGE_NAME - 1) == 0)
1323 {
1324 ebuf = buf + sizeof PACKAGE_NAME - 1;
1325 if (*ebuf++ != '-')
1326 ERROR((1, 0, _("Bad incremental file format")));
1327 for (; *ebuf != '-'; ebuf++)
1328 if (!*ebuf)
1329 ERROR((1, 0, _("Bad incremental file format")));
1330
1331 incremental_version = strtoumax (ebuf + 1, NULL, 10);
1332 }
1333 else
1334 incremental_version = 0;
1335
1336 switch (incremental_version)
1337 {
1338 case 0:
1339 case 1:
1340 read_incr_db_01 (incremental_version, buf);
1341 break;
1342
1343 case TAR_INCREMENTAL_VERSION:
1344 read_incr_db_2 ();
1345 break;
1346
1347 default:
1348 ERROR ((1, 0, _("Unsupported incremental format version: %"PRIuMAX),
1349 incremental_version));
1350 }
1351
1352 }
1353
1354 if (ferror (listed_incremental_stream))
1355 read_error (listed_incremental_option);
1356 if (buf)
1357 free (buf);
1358 }
1359
1360 /* Output incremental data for the directory ENTRY to the file DATA.
1361 Return nonzero if successful, preserving errno on write failure. */
1362 static bool
1363 write_directory_file_entry (void *entry, void *data)
1364 {
1365 struct directory const *directory = entry;
1366 FILE *fp = data;
1367
1368 if (DIR_IS_FOUND (directory))
1369 {
1370 char buf[UINTMAX_STRSIZE_BOUND];
1371 char *s;
1372
1373 s = DIR_IS_NFS (directory) ? "1" : "0";
1374 fwrite (s, 2, 1, fp);
1375 s = (TYPE_SIGNED (time_t)
1376 ? imaxtostr (directory->mtime.tv_sec, buf)
1377 : umaxtostr (directory->mtime.tv_sec, buf));
1378 fwrite (s, strlen (s) + 1, 1, fp);
1379 s = umaxtostr (directory->mtime.tv_nsec, buf);
1380 fwrite (s, strlen (s) + 1, 1, fp);
1381 s = umaxtostr (directory->device_number, buf);
1382 fwrite (s, strlen (s) + 1, 1, fp);
1383 s = umaxtostr (directory->inode_number, buf);
1384 fwrite (s, strlen (s) + 1, 1, fp);
1385
1386 fwrite (directory->name, strlen (directory->name) + 1, 1, fp);
1387 if (directory->dump)
1388 {
1389 const char *p;
1390 dumpdir_iter_t itr;
1391
1392 for (p = dumpdir_first (directory->dump, 0, &itr);
1393 p;
1394 p = dumpdir_next (itr))
1395 fwrite (p, strlen (p) + 1, 1, fp);
1396 free (itr);
1397 }
1398 fwrite ("\0\0", 2, 1, fp);
1399 }
1400
1401 return ! ferror (fp);
1402 }
1403
1404 void
1405 write_directory_file (void)
1406 {
1407 FILE *fp = listed_incremental_stream;
1408 char buf[UINTMAX_STRSIZE_BOUND];
1409 char *s;
1410
1411 if (! fp)
1412 return;
1413
1414 if (fseek (fp, 0L, SEEK_SET) != 0)
1415 seek_error (listed_incremental_option);
1416 if (sys_truncate (fileno (fp)) != 0)
1417 truncate_error (listed_incremental_option);
1418
1419 fprintf (fp, "%s-%s-%d\n", PACKAGE_NAME, PACKAGE_VERSION,
1420 TAR_INCREMENTAL_VERSION);
1421
1422 s = (TYPE_SIGNED (time_t)
1423 ? imaxtostr (start_time.tv_sec, buf)
1424 : umaxtostr (start_time.tv_sec, buf));
1425 fwrite (s, strlen (s) + 1, 1, fp);
1426 s = umaxtostr (start_time.tv_nsec, buf);
1427 fwrite (s, strlen (s) + 1, 1, fp);
1428
1429 if (! ferror (fp) && directory_table)
1430 hash_do_for_each (directory_table, write_directory_file_entry, fp);
1431
1432 if (ferror (fp))
1433 write_error (listed_incremental_option);
1434 if (fclose (fp) != 0)
1435 close_error (listed_incremental_option);
1436 }
1437
1438 \f
1439 /* Restoration of incremental dumps. */
1440
1441 static void
1442 get_gnu_dumpdir (struct tar_stat_info *stat_info)
1443 {
1444 size_t size;
1445 size_t copied;
1446 union block *data_block;
1447 char *to;
1448 char *archive_dir;
1449
1450 size = stat_info->stat.st_size;
1451
1452 archive_dir = xmalloc (size);
1453 to = archive_dir;
1454
1455 set_next_block_after (current_header);
1456 mv_begin (stat_info);
1457
1458 for (; size > 0; size -= copied)
1459 {
1460 mv_size_left (size);
1461 data_block = find_next_block ();
1462 if (!data_block)
1463 ERROR ((1, 0, _("Unexpected EOF in archive")));
1464 copied = available_space_after (data_block);
1465 if (copied > size)
1466 copied = size;
1467 memcpy (to, data_block->buffer, copied);
1468 to += copied;
1469 set_next_block_after ((union block *)
1470 (data_block->buffer + copied - 1));
1471 }
1472
1473 mv_end ();
1474
1475 stat_info->dumpdir = archive_dir;
1476 stat_info->skipped = true; /* For skip_member() and friends
1477 to work correctly */
1478 }
1479
1480 /* Return T if STAT_INFO represents a dumpdir archive member.
1481 Note: can invalidate current_header. It happens if flush_archive()
1482 gets called within get_gnu_dumpdir() */
1483 bool
1484 is_dumpdir (struct tar_stat_info *stat_info)
1485 {
1486 if (stat_info->is_dumpdir && !stat_info->dumpdir)
1487 get_gnu_dumpdir (stat_info);
1488 return stat_info->is_dumpdir;
1489 }
1490
1491 static bool
1492 dumpdir_ok (char *dumpdir)
1493 {
1494 char *p;
1495 int has_tempdir = 0;
1496 int expect = 0;
1497
1498 for (p = dumpdir; *p; p += strlen (p) + 1)
1499 {
1500 if (expect && *p != expect)
1501 {
1502 ERROR ((0, 0,
1503 _("Malformed dumpdir: expected '%c' but found %#3o"),
1504 expect, *p));
1505 return false;
1506 }
1507 switch (*p)
1508 {
1509 case 'X':
1510 if (has_tempdir)
1511 {
1512 ERROR ((0, 0,
1513 _("Malformed dumpdir: 'X' duplicated")));
1514 return false;
1515 }
1516 else
1517 has_tempdir = 1;
1518 break;
1519
1520 case 'R':
1521 if (p[1] == 0)
1522 {
1523 if (!has_tempdir)
1524 {
1525 ERROR ((0, 0,
1526 _("Malformed dumpdir: empty name in 'R'")));
1527 return false;
1528 }
1529 else
1530 has_tempdir = 0;
1531 }
1532 expect = 'T';
1533 break;
1534
1535 case 'T':
1536 if (expect != 'T')
1537 {
1538 ERROR ((0, 0,
1539 _("Malformed dumpdir: 'T' not preceeded by 'R'")));
1540 return false;
1541 }
1542 if (p[1] == 0 && !has_tempdir)
1543 {
1544 ERROR ((0, 0,
1545 _("Malformed dumpdir: empty name in 'T'")));
1546 return false;
1547 }
1548 expect = 0;
1549 break;
1550
1551 case 'N':
1552 case 'Y':
1553 case 'D':
1554 break;
1555
1556 default:
1557 /* FIXME: bail out? */
1558 break;
1559 }
1560 }
1561
1562 if (expect)
1563 {
1564 ERROR ((0, 0,
1565 _("Malformed dumpdir: expected '%c' but found end of data"),
1566 expect));
1567 return false;
1568 }
1569
1570 if (has_tempdir)
1571 WARNOPT (WARN_BAD_DUMPDIR,
1572 (0, 0, _("Malformed dumpdir: 'X' never used")));
1573
1574 return true;
1575 }
1576
1577 /* Examine the directories under directory_name and delete any
1578 files that were not there at the time of the back-up. */
1579 static bool
1580 try_purge_directory (char const *directory_name)
1581 {
1582 char *current_dir;
1583 char *cur, *arc, *p;
1584 char *temp_stub = NULL;
1585 struct dumpdir *dump;
1586
1587 if (!is_dumpdir (&current_stat_info))
1588 return false;
1589
1590 current_dir = savedir (directory_name);
1591
1592 if (!current_dir)
1593 /* The directory doesn't exist now. It'll be created. In any
1594 case, we don't have to delete any files out of it. */
1595 return false;
1596
1597 /* Verify if dump directory is sane */
1598 if (!dumpdir_ok (current_stat_info.dumpdir))
1599 return false;
1600
1601 /* Process renames */
1602 for (arc = current_stat_info.dumpdir; *arc; arc += strlen (arc) + 1)
1603 {
1604 if (*arc == 'X')
1605 {
1606 #define TEMP_DIR_TEMPLATE "tar.XXXXXX"
1607 size_t len = strlen (arc + 1);
1608 temp_stub = xrealloc (temp_stub, len + 1 + sizeof TEMP_DIR_TEMPLATE);
1609 memcpy (temp_stub, arc + 1, len);
1610 temp_stub[len] = '/';
1611 memcpy (temp_stub + len + 1, TEMP_DIR_TEMPLATE,
1612 sizeof TEMP_DIR_TEMPLATE);
1613 if (!mkdtemp (temp_stub))
1614 {
1615 ERROR ((0, errno,
1616 _("Cannot create temporary directory using template %s"),
1617 quote (temp_stub)));
1618 free (temp_stub);
1619 free (current_dir);
1620 return false;
1621 }
1622 }
1623 else if (*arc == 'R')
1624 {
1625 char *src, *dst;
1626 src = arc + 1;
1627 arc += strlen (arc) + 1;
1628 dst = arc + 1;
1629
1630 /* Ensure that neither source nor destination are absolute file
1631 names (unless permitted by -P option), and that they do not
1632 contain dubious parts (e.g. ../).
1633
1634 This is an extra safety precaution. Besides, it might be
1635 necessary to extract from archives created with tar versions
1636 prior to 1.19. */
1637
1638 if (*src)
1639 src = safer_name_suffix (src, false, absolute_names_option);
1640 if (*dst)
1641 dst = safer_name_suffix (dst, false, absolute_names_option);
1642
1643 if (*src == 0)
1644 src = temp_stub;
1645 else if (*dst == 0)
1646 dst = temp_stub;
1647
1648 if (!rename_directory (src, dst))
1649 {
1650 free (temp_stub);
1651 free (current_dir);
1652 /* FIXME: Make sure purge_directory(dst) will return
1653 immediately */
1654 return false;
1655 }
1656 }
1657 }
1658
1659 free (temp_stub);
1660
1661 /* Process deletes */
1662 dump = dumpdir_create (current_stat_info.dumpdir);
1663 p = NULL;
1664 for (cur = current_dir; *cur; cur += strlen (cur) + 1)
1665 {
1666 const char *entry;
1667 struct stat st;
1668 if (p)
1669 free (p);
1670 p = new_name (directory_name, cur);
1671
1672 if (deref_stat (false, p, &st))
1673 {
1674 if (errno != ENOENT) /* FIXME: Maybe keep a list of renamed
1675 dirs and check it here? */
1676 {
1677 stat_diag (p);
1678 WARN ((0, 0, _("%s: Not purging directory: unable to stat"),
1679 quotearg_colon (p)));
1680 }
1681 continue;
1682 }
1683
1684 if (!(entry = dumpdir_locate (dump, cur))
1685 || (*entry == 'D' && !S_ISDIR (st.st_mode))
1686 || (*entry == 'Y' && S_ISDIR (st.st_mode)))
1687 {
1688 if (one_file_system_option && st.st_dev != root_device)
1689 {
1690 WARN ((0, 0,
1691 _("%s: directory is on a different device: not purging"),
1692 quotearg_colon (p)));
1693 continue;
1694 }
1695
1696 if (! interactive_option || confirm ("delete", p))
1697 {
1698 if (verbose_option)
1699 fprintf (stdlis, _("%s: Deleting %s\n"),
1700 program_name, quote (p));
1701 if (! remove_any_file (p, RECURSIVE_REMOVE_OPTION))
1702 {
1703 int e = errno;
1704 ERROR ((0, e, _("%s: Cannot remove"), quotearg_colon (p)));
1705 }
1706 }
1707 }
1708 }
1709 free (p);
1710 dumpdir_free (dump);
1711
1712 free (current_dir);
1713 return true;
1714 }
1715
1716 void
1717 purge_directory (char const *directory_name)
1718 {
1719 if (!try_purge_directory (directory_name))
1720 skip_member ();
1721 }
1722
1723 void
1724 list_dumpdir (char *buffer, size_t size)
1725 {
1726 int state = 0;
1727 while (size)
1728 {
1729 switch (*buffer)
1730 {
1731 case 'Y':
1732 case 'N':
1733 case 'D':
1734 case 'R':
1735 case 'T':
1736 case 'X':
1737 fprintf (stdlis, "%c", *buffer);
1738 if (state == 0)
1739 {
1740 fprintf (stdlis, " ");
1741 state = 1;
1742 }
1743 buffer++;
1744 size--;
1745 break;
1746
1747 case 0:
1748 fputc ('\n', stdlis);
1749 buffer++;
1750 size--;
1751 state = 0;
1752 break;
1753
1754 default:
1755 fputc (*buffer, stdlis);
1756 buffer++;
1757 size--;
1758 }
1759 }
1760 }
This page took 0.112551 seconds and 5 git commands to generate.