Optimize searches for directory structures by keeping a pointer to struct directory...
[tar.git] / src / incremen.c
blobaaeda5877ca95fd6af9faa29e6a3dccbdd550cc8
1 /* GNU dump extensions to tar.
3 Copyright (C) 1988, 1992, 1993, 1994, 1996, 1997, 1999, 2000, 2001,
4 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
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.
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.
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. */
20 #include <system.h>
21 #include <hash.h>
22 #include <quotearg.h>
23 #include "common.h"
25 /* Incremental dump specialities. */
27 /* Which child files to save under a directory. */
28 enum children
30 NO_CHILDREN,
31 CHANGED_CHILDREN,
32 ALL_CHILDREN
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 */
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)
49 #define DIR_SET_FLAG(d,f) (d)->flags |= (f)
50 #define DIR_CLEAR_FLAG(d,f) (d)->flags &= ~(f)
52 struct dumpdir /* Dump directory listing */
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 */
60 /* Directory attributes. */
61 struct directory
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 */
80 struct dumpdir *
81 dumpdir_create0 (const char *contents, const char *cmask)
83 struct dumpdir *dump;
84 size_t i, total, ctsize, len;
85 char *p;
86 const char *q;
88 for (i = 0, total = 0, ctsize = 1, q = contents; *q; total++, q += len)
90 len = strlen (q) + 1;
91 ctsize += len;
92 if (!cmask || strchr (cmask, *q))
93 i++;
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]));
102 for (i = 0, p = dump->contents; *p; p += strlen (p) + 1)
104 if (!cmask || strchr (cmask, *p))
105 dump->elv[i++] = p + 1;
107 dump->elv[i] = NULL;
108 return dump;
111 struct dumpdir *
112 dumpdir_create (const char *contents)
114 return dumpdir_create0 (contents, "YND");
117 void
118 dumpdir_free (struct dumpdir *dump)
120 free (dump->elv);
121 free (dump);
124 static int
125 compare_dirnames (const void *first, const void *second)
127 char const *const *name1 = first;
128 char const *const *name2 = second;
129 return strcmp (*name1, *name2);
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)
137 char **ptr;
138 if (!dump)
139 return NULL;
141 ptr = bsearch (&name, dump->elv, dump->elc, sizeof (dump->elv[0]),
142 compare_dirnames);
143 return ptr ? *ptr - 1: NULL;
146 struct dumpdir_iter
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 */
153 char *
154 dumpdir_next (struct dumpdir_iter *itr)
156 size_t cur = itr->next;
157 char *ret = NULL;
159 if (itr->all)
161 ret = itr->dump->contents + cur;
162 if (*ret == 0)
163 return NULL;
164 itr->next += strlen (ret) + 1;
166 else if (cur < itr->dump->elc)
168 ret = itr->dump->elv[cur] - 1;
169 itr->next++;
172 return ret;
175 char *
176 dumpdir_first (struct dumpdir *dump, int all, struct dumpdir_iter **pitr)
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);
186 /* Return size in bytes of the dumpdir array P */
187 size_t
188 dumpdir_size (const char *p)
190 size_t totsize = 0;
192 while (*p)
194 size_t size = strlen (p) + 1;
195 totsize += size;
196 p += size;
198 return totsize + 1;
202 static struct directory *dirhead, *dirtail;
203 static Hash_table *directory_table;
204 static Hash_table *directory_meta_table;
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
214 /* Calculate the hash of a directory. */
215 static size_t
216 hash_directory_canonical_name (void const *entry, size_t n_buckets)
218 struct directory const *directory = entry;
219 return hash_string (directory->caname, n_buckets);
222 /* Compare two directories for equality of their names. */
223 static bool
224 compare_directory_canonical_names (void const *entry1, void const *entry2)
226 struct directory const *directory1 = entry1;
227 struct directory const *directory2 = entry2;
228 return strcmp (directory1->caname, directory2->caname) == 0;
231 static size_t
232 hash_directory_meta (void const *entry, size_t n_buckets)
234 struct directory const *directory = entry;
235 /* FIXME: Work out a better algorytm */
236 return (directory->device_number + directory->inode_number) % n_buckets;
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)
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;
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)
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;
271 static void
272 free_directory (struct directory *dir)
274 free (dir->caname);
275 free (dir->name);
276 free (dir);
279 static struct directory *
280 attach_directory (const char *name)
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;
293 void
294 dirlist_replace_prefix (const char *pref, const char *repl)
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);
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)
312 struct directory *directory = attach_directory (name);
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;
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 ();
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 ();
342 return directory;
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)
349 if (! directory_table)
350 return 0;
351 else
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;
361 #if 0
362 /* Remove directory entry for the given CANAME */
363 void
364 remove_directory (const char *caname)
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);
372 #endif
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)
381 replace_prefix (&dir->name, old_prefix, old_prefix_len,
382 new_prefix, new_prefix_len);
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)
390 if (! directory_meta_table)
391 return 0;
392 else
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;
404 void
405 update_parent_directory (const char *name)
407 struct directory *directory;
408 char *p;
410 p = dir_name (name);
411 directory = find_directory (p);
412 if (directory)
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);
420 free (p);
423 #define PD_FORCE_CHILDREN 0x10
424 #define PD_FORCE_INIT 0x20
425 #define PD_CHILDREN(f) ((f) & 3)
427 static struct directory *
428 procdir (const char *name_buffer, struct stat *stat_data,
429 dev_t device,
430 int flag,
431 char *entry)
433 struct directory *directory;
434 bool nfs = NFS_FILE_STAT (*stat_data);
436 if ((directory = find_directory (name_buffer)) != NULL)
438 if (DIR_IS_INITED (directory))
440 if (flag & PD_FORCE_INIT)
442 assign_string (&directory->name, name_buffer);
444 else
446 *entry = 'N'; /* Avoid duplicating this directory */
447 return directory;
451 if (strcmp (directory->name, name_buffer))
453 *entry = 'N';
454 return directory;
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. */
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))
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)
474 if (strcmp (d->name, name_buffer))
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);
485 directory->children = CHANGED_CHILDREN;
487 else
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;
496 if (nfs)
497 DIR_SET_FLAG (directory, DIRF_NFS);
499 else
500 directory->children = CHANGED_CHILDREN;
502 DIR_SET_FLAG (directory, DIRF_FOUND);
504 else
506 struct directory *d = find_directory_meta (stat_data->st_dev,
507 stat_data->st_ino);
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);
517 if (d)
519 if (strcmp (d->name, name_buffer))
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);
529 directory->children = CHANGED_CHILDREN;
531 else
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;
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)
555 directory->children = PD_CHILDREN(flag);
556 if (directory->children == NO_CHILDREN)
557 *entry = 'N';
560 DIR_SET_FLAG (directory, DIRF_INIT);
562 if (directory->children != NO_CHILDREN)
564 const char *tag_file_name;
566 switch (check_exclusion_tags (name_buffer, &tag_file_name))
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;
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;
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;
590 case exclusion_tag_none:
591 break;
595 return directory;
598 /* Compare dumpdir array from DIRECTORY with directory listing DIR and
599 build a new dumpdir template.
601 DIR must be returned by a previous call to savedir().
603 File names in DIRECTORY->dump->contents must be sorted
604 alphabetically.
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. */
609 void
610 makedumpdir (struct directory *directory, const char *dir)
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;
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;
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++;
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;
640 qsort (array, dirsize, sizeof (array[0]), compare_dirnames);
642 /* Prepare space for new dumpdir */
643 new_dump = xmalloc (len);
644 new_dump_ptr = new_dump;
646 /* Fill in the dumpdir template */
647 for (i = 0; i < dirsize; i++)
649 const char *loc = dumpdir_locate (dump, array[i]);
650 if (loc)
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++;
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 */
665 /* Copy the file name */
666 for (p = array[i]; (*new_dump_ptr++ = *p++); )
669 *new_dump_ptr = 0;
670 directory->idump = directory->dump;
671 directory->dump = dumpdir_create0 (new_dump, NULL);
672 free (array);
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)
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;
692 if (! dirp)
693 savedir_error (dir);
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);
700 if (deref_stat (dereference_option, name_buffer, &stat_data))
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;
711 directory = procdir (name_buffer, &stat_data, device,
712 (cmdline ? PD_FORCE_INIT : 0),
713 &ch);
715 name_length = strlen (name_buffer);
716 if (! ISSLASH (name_buffer[name_length - 1]))
718 name_buffer[name_length] = DIRECTORY_SEPARATOR;
719 /* name_buffer has been allocated an extra slot */
720 name_buffer[++name_length] = 0;
723 if (dirp && directory->children != NO_CHILDREN)
725 char *entry; /* directory entry being scanned */
726 size_t entrylen; /* length of directory entry */
727 dumpdir_iter_t itr;
729 makedumpdir (directory, dirp);
731 for (entry = dumpdir_first (directory->dump, 1, &itr);
732 entry;
733 entry = dumpdir_next (itr))
735 entrylen = strlen (entry);
736 if (name_buffer_size <= entrylen - 1 + name_length)
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);
743 strcpy (name_buffer + name_length, entry + 1);
745 if (*entry == 'I') /* Ignored entry */
746 *entry = 'N';
747 else if (excluded_name (name_buffer))
748 *entry = 'N';
749 else
751 if (deref_stat (dereference_option, name_buffer, &stat_data))
753 stat_diag (name_buffer);
754 *entry = 'N';
755 continue;
758 if (S_ISDIR (stat_data.st_mode))
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);
769 else if (one_file_system_option && device != stat_data.st_dev)
770 *entry = 'N';
772 else if (*entry == 'Y')
773 /* New entry, skip further checks */;
775 /* FIXME: if (S_ISHIDDEN (stat_data.st_mode))?? */
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';
785 free (itr);
788 free (name_buffer);
789 if (dirp)
790 free (dirp);
792 return directory;
795 /* Return pointer to the contents of the directory DIR */
796 const char *
797 directory_contents (struct directory *dir)
799 if (!dir)
800 return NULL;
801 return dir->dump ? dir->dump->contents : NULL;
804 /* A "safe" version of directory_contents, which never returns NULL. */
805 const char *
806 safe_directory_contents (struct directory *dir)
808 const char *ret = directory_contents (dir);
809 return ret ? ret : "\0\0\0\0";
812 void
813 name_fill_directory (struct name *name, dev_t device, bool cmdline)
815 name->directory = scan_directory (name->name, device, cmdline);
819 static void
820 obstack_code_rename (struct obstack *stk, char *from, char *to)
822 char *s;
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);
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);
835 static void
836 store_rename (struct directory *dir, struct obstack *stk)
838 if (DIR_IS_RENAMED (dir))
840 struct directory *prev, *p;
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);
850 if (prev == NULL)
852 for (p = dir; p && p->orig; p = p->orig)
853 obstack_code_rename (stk, p->orig->name, p->name);
855 else
857 char *temp_name;
859 DIR_CLEAR_FLAG (prev, DIRF_RENAMED);
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);
868 obstack_code_rename (stk, dir->name, "");
870 for (p = dir; p != prev; p = p->orig)
871 obstack_code_rename (stk, p->orig->name, p->name);
873 obstack_code_rename (stk, "", prev->name);
878 void
879 append_incremental_renames (struct directory *dir)
881 struct obstack stk;
882 size_t size;
883 struct directory *dp;
884 const char *dump;
886 if (dirhead == NULL)
887 return;
889 obstack_init (&stk);
890 dump = directory_contents (dir);
891 if (dump)
893 size = dumpdir_size (dump) - 1;
894 obstack_grow (&stk, dump, size);
896 else
897 size = 0;
899 for (dp = dirhead; dp; dp = dp->next)
900 store_rename (dp, &stk);
902 if (obstack_object_size (&stk) != size)
904 obstack_1grow (&stk, 0);
905 dumpdir_free (dir->dump);
906 dir->dump = dumpdir_create (obstack_finish (&stk));
908 obstack_free (&stk, NULL);
913 static FILE *listed_incremental_stream;
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.
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 */
923 #define TAR_INCREMENTAL_VERSION 2
925 /* Read incremental snapshot formats 0 and 1 */
926 static void
927 read_incr_db_01 (int version, const char *initbuf)
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;
938 if (version == 1)
940 if (getline (&buf, &bufsize, listed_incremental_stream) <= 0)
942 read_error (listed_incremental_option);
943 free (buf);
944 return;
946 ++lineno;
948 else
950 buf = strdup (initbuf);
951 bufsize = strlen (buf) + 1;
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
967 sec = u;
969 if (version == 1 && *ebuf)
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)
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);
984 else
985 nsec = u;
987 else
989 /* pre-1 incremental format does not contain nanoseconds */
990 nsec = 0;
993 newer_mtime_option.tv_sec = sec;
994 newer_mtime_option.tv_nsec = nsec;
997 while (0 < (n = getline (&buf, &bufsize, listed_incremental_stream)))
999 dev_t dev;
1000 ino_t ino;
1001 bool nfs = buf[0] == '+';
1002 char *strp = buf + nfs;
1003 struct timespec mtime;
1005 lineno++;
1007 if (buf[n - 1] == '\n')
1008 buf[n - 1] = '\0';
1010 if (version == 1)
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 != ' ')
1018 ERROR ((0, errno, "%s:%ld: %s",
1019 quotearg_colon (listed_incremental_option), lineno,
1020 _("Invalid modification time (seconds)")));
1021 sec = (time_t) -1;
1023 else
1024 sec = u;
1025 strp = ebuf;
1027 errno = 0;
1028 u = strtoumax (strp, &ebuf, 10);
1029 if (!errno && BILLION <= u)
1030 errno = ERANGE;
1031 if (errno || strp == ebuf || *ebuf != ' ')
1033 ERROR ((0, errno, "%s:%ld: %s",
1034 quotearg_colon (listed_incremental_option), lineno,
1035 _("Invalid modification time (nanoseconds)")));
1036 nsec = -1;
1038 else
1039 nsec = u;
1040 mtime.tv_sec = sec;
1041 mtime.tv_nsec = nsec;
1042 strp = ebuf;
1044 else
1045 memset (&mtime, 0, sizeof mtime);
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 != ' ')
1053 ERROR ((0, errno, "%s:%ld: %s",
1054 quotearg_colon (listed_incremental_option), lineno,
1055 _("Invalid device number")));
1056 dev = (dev_t) -1;
1058 else
1059 dev = u;
1060 strp = ebuf;
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 != ' ')
1068 ERROR ((0, errno, "%s:%ld: %s",
1069 quotearg_colon (listed_incremental_option), lineno,
1070 _("Invalid inode number")));
1071 ino = (ino_t) -1;
1073 else
1074 ino = u;
1075 strp = ebuf;
1077 strp++;
1078 unquote_string (strp);
1079 note_directory (strp, mtime, dev, ino, nfs, false, NULL);
1081 free (buf);
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.
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)
1091 int c;
1092 size_t i;
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);
1098 *pcount = i;
1099 return c;
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.
1106 Throw a fatal error if the string cannot be converted or if the
1107 converted value is less than MIN_VAL. */
1109 static void
1110 read_negative_num (FILE *fp, intmax_t min_val, intmax_t *pval)
1112 int c;
1113 size_t i;
1114 char buf[INT_BUFSIZE_BOUND (intmax_t)];
1115 char *ep;
1116 buf[0] = '-';
1118 for (i = 1; ISDIGIT (c = getc (fp)); i++)
1120 if (i == sizeof buf - 1)
1121 FATAL_ERROR ((0, 0, _("Field too long while reading snapshot file")));
1122 buf[i] = c;
1125 if (c < 0)
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")));
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")));
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.
1144 Throw a fatal error if the string cannot be converted or if the
1145 converted value exceeds MAX_VAL.
1147 Return the last character read or EOF on end of file. */
1149 static int
1150 read_unsigned_num (int c, FILE *fp, uintmax_t max_val, uintmax_t *pval)
1152 size_t i;
1153 char buf[UINTMAX_STRSIZE_BOUND], *ep;
1155 for (i = 0; ISDIGIT (c); i++)
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);
1163 if (c < 0)
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")));
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;
1181 /* Read from file FP a nul-terminated string and convert it to
1182 uintmax_t. Return the resulting value in PVAL.
1184 Throw a fatal error if the string cannot be converted or if the
1185 converted value exceeds MAX_VAL.
1187 Return the last character read or EOF on end of file. */
1189 static int
1190 read_num (FILE *fp, uintmax_t max_val, uintmax_t *pval)
1192 return read_unsigned_num (getc (fp), fp, max_val, pval);
1195 /* Read from FP two NUL-terminated strings representing a struct
1196 timespec. Return the resulting value in PVAL.
1198 Throw a fatal error if the string cannot be converted. */
1200 static void
1201 read_timespec (FILE *fp, struct timespec *pval)
1203 int c = getc (fp);
1204 intmax_t i;
1205 uintmax_t u;
1207 if (c == '-')
1209 read_negative_num (fp, TYPE_MINIMUM (time_t), &i);
1210 c = 0;
1211 pval->tv_sec = i;
1213 else
1215 c = read_unsigned_num (c, fp, TYPE_MAXIMUM (time_t), &u);
1216 pval->tv_sec = u;
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;
1226 /* Read incremental snapshot format 2 */
1227 static void
1228 read_incr_db_2 ()
1230 uintmax_t u;
1231 struct obstack stk;
1233 obstack_init (&stk);
1235 read_timespec (listed_incremental_stream, &newer_mtime_option);
1237 for (;;)
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;
1247 if (read_num (listed_incremental_stream, 1, &u))
1248 return; /* Normal return */
1250 nfs = u;
1252 read_timespec (listed_incremental_stream, &mtime);
1254 if (read_num (listed_incremental_stream, TYPE_MAXIMUM (dev_t), &u))
1255 break;
1256 dev = u;
1258 if (read_num (listed_incremental_stream, TYPE_MAXIMUM (ino_t), &u))
1259 break;
1260 ino = u;
1262 if (read_obstack (listed_incremental_stream, &stk, &s))
1263 break;
1265 name = obstack_finish (&stk);
1267 while (read_obstack (listed_incremental_stream, &stk, &s) == 0 && s > 1)
1269 if (getc (listed_incremental_stream) != 0)
1270 FATAL_ERROR ((0, 0, "%s: %s",
1271 quotearg_colon (listed_incremental_option),
1272 _("Missing record terminator")));
1274 content = obstack_finish (&stk);
1275 note_directory (name, mtime, dev, ino, nfs, false, content);
1276 obstack_free (&stk, content);
1278 FATAL_ERROR ((0, 0, "%s: %s",
1279 quotearg_colon (listed_incremental_option),
1280 _("Unexpected EOF in snapshot file")));
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)
1292 int fd;
1293 char *buf = 0;
1294 size_t bufsize;
1295 int flags = O_RDWR | O_CREAT;
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)
1305 open_error (listed_incremental_option);
1306 return;
1309 listed_incremental_stream = fdopen (fd, "r+");
1310 if (! listed_incremental_stream)
1312 open_error (listed_incremental_option);
1313 close (fd);
1314 return;
1317 if (0 < getline (&buf, &bufsize, listed_incremental_stream))
1319 char *ebuf;
1320 uintmax_t incremental_version;
1322 if (strncmp (buf, PACKAGE_NAME, sizeof PACKAGE_NAME - 1) == 0)
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")));
1331 incremental_version = strtoumax (ebuf + 1, NULL, 10);
1333 else
1334 incremental_version = 0;
1336 switch (incremental_version)
1338 case 0:
1339 case 1:
1340 read_incr_db_01 (incremental_version, buf);
1341 break;
1343 case TAR_INCREMENTAL_VERSION:
1344 read_incr_db_2 ();
1345 break;
1347 default:
1348 ERROR ((1, 0, _("Unsupported incremental format version: %"PRIuMAX),
1349 incremental_version));
1354 if (ferror (listed_incremental_stream))
1355 read_error (listed_incremental_option);
1356 if (buf)
1357 free (buf);
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)
1365 struct directory const *directory = entry;
1366 FILE *fp = data;
1368 if (DIR_IS_FOUND (directory))
1370 char buf[UINTMAX_STRSIZE_BOUND];
1371 char *s;
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);
1386 fwrite (directory->name, strlen (directory->name) + 1, 1, fp);
1387 if (directory->dump)
1389 const char *p;
1390 dumpdir_iter_t itr;
1392 for (p = dumpdir_first (directory->dump, 0, &itr);
1394 p = dumpdir_next (itr))
1395 fwrite (p, strlen (p) + 1, 1, fp);
1396 free (itr);
1398 fwrite ("\0\0", 2, 1, fp);
1401 return ! ferror (fp);
1404 void
1405 write_directory_file (void)
1407 FILE *fp = listed_incremental_stream;
1408 char buf[UINTMAX_STRSIZE_BOUND];
1409 char *s;
1411 if (! fp)
1412 return;
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);
1419 fprintf (fp, "%s-%s-%d\n", PACKAGE_NAME, PACKAGE_VERSION,
1420 TAR_INCREMENTAL_VERSION);
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);
1429 if (! ferror (fp) && directory_table)
1430 hash_do_for_each (directory_table, write_directory_file_entry, fp);
1432 if (ferror (fp))
1433 write_error (listed_incremental_option);
1434 if (fclose (fp) != 0)
1435 close_error (listed_incremental_option);
1439 /* Restoration of incremental dumps. */
1441 static void
1442 get_gnu_dumpdir (struct tar_stat_info *stat_info)
1444 size_t size;
1445 size_t copied;
1446 union block *data_block;
1447 char *to;
1448 char *archive_dir;
1450 size = stat_info->stat.st_size;
1452 archive_dir = xmalloc (size);
1453 to = archive_dir;
1455 set_next_block_after (current_header);
1456 mv_begin (stat_info);
1458 for (; size > 0; size -= copied)
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));
1473 mv_end ();
1475 stat_info->dumpdir = archive_dir;
1476 stat_info->skipped = true; /* For skip_member() and friends
1477 to work correctly */
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)
1486 if (stat_info->is_dumpdir && !stat_info->dumpdir)
1487 get_gnu_dumpdir (stat_info);
1488 return stat_info->is_dumpdir;
1491 static bool
1492 dumpdir_ok (char *dumpdir)
1494 char *p;
1495 int has_tempdir = 0;
1496 int expect = 0;
1498 for (p = dumpdir; *p; p += strlen (p) + 1)
1500 if (expect && *p != expect)
1502 ERROR ((0, 0,
1503 _("Malformed dumpdir: expected '%c' but found %#3o"),
1504 expect, *p));
1505 return false;
1507 switch (*p)
1509 case 'X':
1510 if (has_tempdir)
1512 ERROR ((0, 0,
1513 _("Malformed dumpdir: 'X' duplicated")));
1514 return false;
1516 else
1517 has_tempdir = 1;
1518 break;
1520 case 'R':
1521 if (p[1] == 0)
1523 if (!has_tempdir)
1525 ERROR ((0, 0,
1526 _("Malformed dumpdir: empty name in 'R'")));
1527 return false;
1529 else
1530 has_tempdir = 0;
1532 expect = 'T';
1533 break;
1535 case 'T':
1536 if (expect != 'T')
1538 ERROR ((0, 0,
1539 _("Malformed dumpdir: 'T' not preceeded by 'R'")));
1540 return false;
1542 if (p[1] == 0 && !has_tempdir)
1544 ERROR ((0, 0,
1545 _("Malformed dumpdir: empty name in 'T'")));
1546 return false;
1548 expect = 0;
1549 break;
1551 case 'N':
1552 case 'Y':
1553 case 'D':
1554 break;
1556 default:
1557 /* FIXME: bail out? */
1558 break;
1562 if (expect)
1564 ERROR ((0, 0,
1565 _("Malformed dumpdir: expected '%c' but found end of data"),
1566 expect));
1567 return false;
1570 if (has_tempdir)
1571 WARNOPT (WARN_BAD_DUMPDIR,
1572 (0, 0, _("Malformed dumpdir: 'X' never used")));
1574 return true;
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)
1582 char *current_dir;
1583 char *cur, *arc, *p;
1584 char *temp_stub = NULL;
1585 struct dumpdir *dump;
1587 if (!is_dumpdir (&current_stat_info))
1588 return false;
1590 current_dir = savedir (directory_name);
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;
1597 /* Verify if dump directory is sane */
1598 if (!dumpdir_ok (current_stat_info.dumpdir))
1599 return false;
1601 /* Process renames */
1602 for (arc = current_stat_info.dumpdir; *arc; arc += strlen (arc) + 1)
1604 if (*arc == 'X')
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))
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;
1623 else if (*arc == 'R')
1625 char *src, *dst;
1626 src = arc + 1;
1627 arc += strlen (arc) + 1;
1628 dst = arc + 1;
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. ../).
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. */
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);
1643 if (*src == 0)
1644 src = temp_stub;
1645 else if (*dst == 0)
1646 dst = temp_stub;
1648 if (!rename_directory (src, dst))
1650 free (temp_stub);
1651 free (current_dir);
1652 /* FIXME: Make sure purge_directory(dst) will return
1653 immediately */
1654 return false;
1659 free (temp_stub);
1661 /* Process deletes */
1662 dump = dumpdir_create (current_stat_info.dumpdir);
1663 p = NULL;
1664 for (cur = current_dir; *cur; cur += strlen (cur) + 1)
1666 const char *entry;
1667 struct stat st;
1668 if (p)
1669 free (p);
1670 p = new_name (directory_name, cur);
1672 if (deref_stat (false, p, &st))
1674 if (errno != ENOENT) /* FIXME: Maybe keep a list of renamed
1675 dirs and check it here? */
1677 stat_diag (p);
1678 WARN ((0, 0, _("%s: Not purging directory: unable to stat"),
1679 quotearg_colon (p)));
1681 continue;
1684 if (!(entry = dumpdir_locate (dump, cur))
1685 || (*entry == 'D' && !S_ISDIR (st.st_mode))
1686 || (*entry == 'Y' && S_ISDIR (st.st_mode)))
1688 if (one_file_system_option && st.st_dev != root_device)
1690 WARN ((0, 0,
1691 _("%s: directory is on a different device: not purging"),
1692 quotearg_colon (p)));
1693 continue;
1696 if (! interactive_option || confirm ("delete", p))
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))
1703 int e = errno;
1704 ERROR ((0, e, _("%s: Cannot remove"), quotearg_colon (p)));
1709 free (p);
1710 dumpdir_free (dump);
1712 free (current_dir);
1713 return true;
1716 void
1717 purge_directory (char const *directory_name)
1719 if (!try_purge_directory (directory_name))
1720 skip_member ();
1723 void
1724 list_dumpdir (char *buffer, size_t size)
1726 int state = 0;
1727 while (size)
1729 switch (*buffer)
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)
1740 fprintf (stdlis, " ");
1741 state = 1;
1743 buffer++;
1744 size--;
1745 break;
1747 case 0:
1748 fputc ('\n', stdlis);
1749 buffer++;
1750 size--;
1751 state = 0;
1752 break;
1754 default:
1755 fputc (*buffer, stdlis);
1756 buffer++;
1757 size--;