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