source: trunk/essentials/app-arch/tar/src/incremen.c

Last change on this file was 3342, checked in by bird, 18 years ago

tar 1.16.1

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