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