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