]> Dogcows Code - chaz/tar/blob - src/incremen.c
* NEWS: Remove support for mangled names.
[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 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. */
29 enum 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. */
54 struct 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
69 static Hash_table *directory_table;
70 static 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. */
81 static size_t
82 hash_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. */
89 static bool
90 compare_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
97 static size_t
98 hash_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. */
106 static bool
107 compare_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 */
116 static struct directory *
117 make_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. */
135 static struct directory *
136 note_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. */
177 static struct directory *
178 find_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. */
193 static struct directory *
194 find_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
210 void
211 update_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
229 static struct directory *
230 procdir (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 */
339 const char *
340 dumpdir_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 */
364 size_t
365 dumpdir_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
378 static int
379 compare_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
395 void
396 makedumpdir (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. */
455 static char *
456 scan_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
552 char *
553 get_directory_contents (char *dir_name, dev_t device)
554 {
555 return scan_directory (dir_name, device);
556 }
557
558 \f
559 static void
560 obstack_code_rename (struct obstack *stk, char *from, char *to)
561 {
562 obstack_1grow (stk, 'R');
563 obstack_grow (stk, from, strlen (from) + 1);
564 obstack_1grow (stk, 'T');
565 obstack_grow (stk, to, strlen (to) + 1);
566 }
567
568 static bool
569 rename_handler (void *data, void *proc_data)
570 {
571 struct directory *dir = data;
572 struct obstack *stk = proc_data;
573
574 if (DIR_IS_RENAMED (dir))
575 {
576 struct directory *prev, *p;
577
578 /* Detect eventual cycles and clear DIRF_RENAMED flag, so this entries
579 are ignored when hit by this function next time.
580 If the chain forms a cycle, prev points to the entry DIR is renamed
581 from. In this case it still retains DIRF_RENAMED flag, which will be
582 cleared in the `else' branch below */
583 for (prev = dir; prev && prev->orig != dir; prev = prev->orig)
584 DIR_CLEAR_FLAG (prev, DIRF_RENAMED);
585
586 if (prev == NULL)
587 {
588 for (p = dir; p && p->orig; p = p->orig)
589 obstack_code_rename (stk, p->orig->name, p->name);
590 }
591 else
592 {
593 char *temp_name;
594
595 DIR_CLEAR_FLAG (prev, DIRF_RENAMED);
596
597 /* Break the cycle by using a temporary name for one of its
598 elements.
599 First, create a temp name stub entry. */
600 temp_name = dir_name (dir->name);
601 obstack_1grow (stk, 'X');
602 obstack_grow (stk, temp_name, strlen (temp_name) + 1);
603
604 obstack_code_rename (stk, dir->name, "");
605
606 for (p = dir; p != prev; p = p->orig)
607 obstack_code_rename (stk, p->orig->name, p->name);
608
609 obstack_code_rename (stk, "", prev->name);
610 }
611 }
612 return true;
613 }
614
615 const char *
616 append_incremental_renames (const char *dump)
617 {
618 struct obstack stk;
619 size_t size;
620
621 if (directory_table == NULL)
622 return dump;
623
624 obstack_init (&stk);
625 if (dump)
626 {
627 size = dumpdir_size (dump) - 1;
628 obstack_grow (&stk, dump, size);
629 }
630 else
631 size = 0;
632
633 hash_do_for_each (directory_table, rename_handler, &stk);
634 if (obstack_object_size (&stk) != size)
635 {
636 obstack_1grow (&stk, 0);
637 dump = obstack_finish (&stk);
638 }
639 else
640 obstack_free (&stk, NULL);
641 return dump;
642 }
643
644 \f
645
646 static FILE *listed_incremental_stream;
647
648 /* Version of incremental format snapshots (directory files) used by this
649 tar. Currently it is supposed to be a single decimal number. 0 means
650 incremental snapshots as per tar version before 1.15.2.
651
652 The current tar version supports incremental versions from
653 0 up to TAR_INCREMENTAL_VERSION, inclusive.
654 It is able to create only snapshots of TAR_INCREMENTAL_VERSION */
655
656 #define TAR_INCREMENTAL_VERSION 2
657
658 /* Read incremental snapshot formats 0 and 1 */
659 static void
660 read_incr_db_01 (int version, const char *initbuf)
661 {
662 int n;
663 uintmax_t u;
664 time_t sec;
665 long int nsec;
666 char *buf = 0;
667 size_t bufsize;
668 char *ebuf;
669 long lineno = 1;
670
671 if (version == 1)
672 {
673 if (getline (&buf, &bufsize, listed_incremental_stream) <= 0)
674 {
675 read_error (listed_incremental_option);
676 free (buf);
677 return;
678 }
679 ++lineno;
680 }
681 else
682 {
683 buf = strdup (initbuf);
684 bufsize = strlen (buf) + 1;
685 }
686
687 sec = TYPE_MINIMUM (time_t);
688 nsec = -1;
689 errno = 0;
690 u = strtoumax (buf, &ebuf, 10);
691 if (!errno && TYPE_MAXIMUM (time_t) < u)
692 errno = ERANGE;
693 if (errno || buf == ebuf)
694 ERROR ((0, errno, "%s:%ld: %s",
695 quotearg_colon (listed_incremental_option),
696 lineno,
697 _("Invalid time stamp")));
698 else
699 {
700 sec = u;
701
702 if (version == 1 && *ebuf)
703 {
704 char const *buf_ns = ebuf + 1;
705 errno = 0;
706 u = strtoumax (buf_ns, &ebuf, 10);
707 if (!errno && BILLION <= u)
708 errno = ERANGE;
709 if (errno || buf_ns == ebuf)
710 {
711 ERROR ((0, errno, "%s:%ld: %s",
712 quotearg_colon (listed_incremental_option),
713 lineno,
714 _("Invalid time stamp")));
715 sec = TYPE_MINIMUM (time_t);
716 }
717 else
718 nsec = u;
719 }
720 else
721 {
722 /* pre-1 incremental format does not contain nanoseconds */
723 nsec = 0;
724 }
725 }
726 newer_mtime_option.tv_sec = sec;
727 newer_mtime_option.tv_nsec = nsec;
728
729
730 while (0 < (n = getline (&buf, &bufsize, listed_incremental_stream)))
731 {
732 dev_t dev;
733 ino_t ino;
734 bool nfs = buf[0] == '+';
735 char *strp = buf + nfs;
736 struct timespec mtime;
737
738 lineno++;
739
740 if (buf[n - 1] == '\n')
741 buf[n - 1] = '\0';
742
743 if (version == 1)
744 {
745 errno = 0;
746 u = strtoumax (strp, &ebuf, 10);
747 if (!errno && TYPE_MAXIMUM (time_t) < u)
748 errno = ERANGE;
749 if (errno || strp == ebuf || *ebuf != ' ')
750 {
751 ERROR ((0, errno, "%s:%ld: %s",
752 quotearg_colon (listed_incremental_option), lineno,
753 _("Invalid modification time (seconds)")));
754 sec = (time_t) -1;
755 }
756 else
757 sec = u;
758 strp = ebuf;
759
760 errno = 0;
761 u = strtoumax (strp, &ebuf, 10);
762 if (!errno && BILLION <= u)
763 errno = ERANGE;
764 if (errno || strp == ebuf || *ebuf != ' ')
765 {
766 ERROR ((0, errno, "%s:%ld: %s",
767 quotearg_colon (listed_incremental_option), lineno,
768 _("Invalid modification time (nanoseconds)")));
769 nsec = -1;
770 }
771 else
772 nsec = u;
773 mtime.tv_sec = sec;
774 mtime.tv_nsec = nsec;
775 strp = ebuf;
776 }
777 else
778 memset (&mtime, 0, sizeof mtime);
779
780 errno = 0;
781 u = strtoumax (strp, &ebuf, 10);
782 if (!errno && TYPE_MAXIMUM (dev_t) < u)
783 errno = ERANGE;
784 if (errno || strp == ebuf || *ebuf != ' ')
785 {
786 ERROR ((0, errno, "%s:%ld: %s",
787 quotearg_colon (listed_incremental_option), lineno,
788 _("Invalid device number")));
789 dev = (dev_t) -1;
790 }
791 else
792 dev = u;
793 strp = ebuf;
794
795 errno = 0;
796 u = strtoumax (strp, &ebuf, 10);
797 if (!errno && TYPE_MAXIMUM (ino_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 inode number")));
804 ino = (ino_t) -1;
805 }
806 else
807 ino = u;
808 strp = ebuf;
809
810 strp++;
811 unquote_string (strp);
812 note_directory (strp, mtime, dev, ino, nfs, false, NULL);
813 }
814 free (buf);
815 }
816
817 /* Read a nul-terminated string from FP and store it in STK.
818 Store the number of bytes read (including nul terminator) in PCOUNT.
819
820 Return the last character read or EOF on end of file. */
821 static int
822 read_obstack (FILE *fp, struct obstack *stk, size_t *pcount)
823 {
824 int c;
825 size_t i;
826
827 for (i = 0, c = getc (fp); c != EOF && c != 0; c = getc (fp), i++)
828 obstack_1grow (stk, c);
829 obstack_1grow (stk, 0);
830
831 *pcount = i;
832 return c;
833 }
834
835 /* Read from file FP a nul-terminated string and convert it to
836 intmax_t. Return the resulting value in PVAL. Assume '-' has
837 already been read.
838
839 Throw a fatal error if the string cannot be converted or if the
840 converted value is less than MIN_VAL. */
841
842 static void
843 read_negative_num (FILE *fp, intmax_t min_val, intmax_t *pval)
844 {
845 int c;
846 size_t i;
847 char buf[INT_BUFSIZE_BOUND (intmax_t)];
848 char *ep;
849 buf[0] = '-';
850
851 for (i = 1; ISDIGIT (c = getc (fp)); i++)
852 {
853 if (i == sizeof buf - 1)
854 FATAL_ERROR ((0, 0, _("Field too long while reading snapshot file")));
855 buf[i] = c;
856 }
857
858 if (c < 0)
859 {
860 if (ferror (fp))
861 FATAL_ERROR ((0, errno, _("Read error in snapshot file")));
862 else
863 FATAL_ERROR ((0, 0, _("Unexpected EOF in snapshot file")));
864 }
865
866 buf[i] = 0;
867 errno = 0;
868 *pval = strtoimax (buf, &ep, 10);
869 if (c || errno || *pval < min_val)
870 FATAL_ERROR ((0, errno, _("Unexpected field value in snapshot file")));
871 }
872
873 /* Read from file FP a nul-terminated string and convert it to
874 uintmax_t. Return the resulting value in PVAL. Assume C has
875 already been read.
876
877 Throw a fatal error if the string cannot be converted or if the
878 converted value exceeds MAX_VAL.
879
880 Return the last character read or EOF on end of file. */
881
882 static int
883 read_unsigned_num (int c, FILE *fp, uintmax_t max_val, uintmax_t *pval)
884 {
885 size_t i;
886 char buf[UINTMAX_STRSIZE_BOUND], *ep;
887
888 for (i = 0; ISDIGIT (c); i++)
889 {
890 if (i == sizeof buf - 1)
891 FATAL_ERROR ((0, 0, _("Field too long while reading snapshot file")));
892 buf[i] = c;
893 c = getc (fp);
894 }
895
896 if (c < 0)
897 {
898 if (ferror (fp))
899 FATAL_ERROR ((0, errno, _("Read error in snapshot file")));
900 else if (i == 0)
901 return c;
902 else
903 FATAL_ERROR ((0, 0, _("Unexpected EOF in snapshot file")));
904 }
905
906 buf[i] = 0;
907 errno = 0;
908 *pval = strtoumax (buf, &ep, 10);
909 if (c || errno || max_val < *pval)
910 FATAL_ERROR ((0, errno, _("Unexpected field value in snapshot file")));
911 return c;
912 }
913
914 /* Read from file FP a nul-terminated string and convert it to
915 uintmax_t. Return the resulting value in PVAL.
916
917 Throw a fatal error if the string cannot be converted or if the
918 converted value exceeds MAX_VAL.
919
920 Return the last character read or EOF on end of file. */
921
922 static int
923 read_num (FILE *fp, uintmax_t max_val, uintmax_t *pval)
924 {
925 return read_unsigned_num (getc (fp), fp, max_val, pval);
926 }
927
928 /* Read from FP two NUL-terminated strings representing a struct
929 timespec. Return the resulting value in PVAL.
930
931 Throw a fatal error if the string cannot be converted. */
932
933 static void
934 read_timespec (FILE *fp, struct timespec *pval)
935 {
936 int c = getc (fp);
937 intmax_t i;
938 uintmax_t u;
939
940 if (c == '-')
941 {
942 read_negative_num (fp, TYPE_MINIMUM (time_t), &i);
943 c = 0;
944 pval->tv_sec = i;
945 }
946 else
947 {
948 c = read_unsigned_num (c, fp, TYPE_MAXIMUM (time_t), &u);
949 pval->tv_sec = u;
950 }
951
952 if (c || read_num (fp, BILLION - 1, &u))
953 FATAL_ERROR ((0, 0, "%s: %s",
954 quotearg_colon (listed_incremental_option),
955 _("Unexpected EOF in snapshot file")));
956 pval->tv_nsec = u;
957 }
958
959 /* Read incremental snapshot format 2 */
960 static void
961 read_incr_db_2 ()
962 {
963 uintmax_t u;
964 struct obstack stk;
965
966 obstack_init (&stk);
967
968 read_timespec (listed_incremental_stream, &newer_mtime_option);
969
970 for (;;)
971 {
972 struct timespec mtime;
973 dev_t dev;
974 ino_t ino;
975 bool nfs;
976 char *name;
977 char *content;
978 size_t s;
979
980 if (read_num (listed_incremental_stream, 1, &u))
981 return; /* Normal return */
982
983 nfs = u;
984
985 read_timespec (listed_incremental_stream, &mtime);
986
987 if (read_num (listed_incremental_stream, TYPE_MAXIMUM (dev_t), &u))
988 break;
989 dev = u;
990
991 if (read_num (listed_incremental_stream, TYPE_MAXIMUM (ino_t), &u))
992 break;
993 ino = u;
994
995 if (read_obstack (listed_incremental_stream, &stk, &s))
996 break;
997
998 name = obstack_finish (&stk);
999
1000 while (read_obstack (listed_incremental_stream, &stk, &s) == 0 && s > 1)
1001 ;
1002 if (getc (listed_incremental_stream) != 0)
1003 FATAL_ERROR ((0, 0, "%s: %s",
1004 quotearg_colon (listed_incremental_option),
1005 _("Missing record terminator")));
1006
1007 content = obstack_finish (&stk);
1008 note_directory (name, mtime, dev, ino, nfs, false, content);
1009 obstack_free (&stk, content);
1010 }
1011 FATAL_ERROR ((0, 0, "%s: %s",
1012 quotearg_colon (listed_incremental_option),
1013 _("Unexpected EOF in snapshot file")));
1014 }
1015
1016 /* Read incremental snapshot file (directory file).
1017 If the file has older incremental version, make sure that it is processed
1018 correctly and that tar will use the most conservative backup method among
1019 possible alternatives (i.e. prefer ALL_CHILDREN over CHANGED_CHILDREN,
1020 etc.) This ensures that the snapshots are updated to the recent version
1021 without any loss of data. */
1022 void
1023 read_directory_file (void)
1024 {
1025 int fd;
1026 char *buf = 0;
1027 size_t bufsize;
1028
1029 /* Open the file for both read and write. That way, we can write
1030 it later without having to reopen it, and don't have to worry if
1031 we chdir in the meantime. */
1032 fd = open (listed_incremental_option, O_RDWR | O_CREAT, MODE_RW);
1033 if (fd < 0)
1034 {
1035 open_error (listed_incremental_option);
1036 return;
1037 }
1038
1039 listed_incremental_stream = fdopen (fd, "r+");
1040 if (! listed_incremental_stream)
1041 {
1042 open_error (listed_incremental_option);
1043 close (fd);
1044 return;
1045 }
1046
1047 if (0 < getline (&buf, &bufsize, listed_incremental_stream))
1048 {
1049 char *ebuf;
1050 uintmax_t incremental_version;
1051
1052 if (strncmp (buf, PACKAGE_NAME, sizeof PACKAGE_NAME - 1) == 0)
1053 {
1054 ebuf = buf + sizeof PACKAGE_NAME - 1;
1055 if (*ebuf++ != '-')
1056 ERROR((1, 0, _("Bad incremental file format")));
1057 for (; *ebuf != '-'; ebuf++)
1058 if (!*ebuf)
1059 ERROR((1, 0, _("Bad incremental file format")));
1060
1061 incremental_version = strtoumax (ebuf + 1, NULL, 10);
1062 }
1063 else
1064 incremental_version = 0;
1065
1066 switch (incremental_version)
1067 {
1068 case 0:
1069 case 1:
1070 read_incr_db_01 (incremental_version, buf);
1071 break;
1072
1073 case TAR_INCREMENTAL_VERSION:
1074 read_incr_db_2 ();
1075 break;
1076
1077 default:
1078 ERROR ((1, 0, _("Unsupported incremental format version: %"PRIuMAX),
1079 incremental_version));
1080 }
1081
1082 }
1083
1084 if (ferror (listed_incremental_stream))
1085 read_error (listed_incremental_option);
1086 if (buf)
1087 free (buf);
1088 }
1089
1090 /* Output incremental data for the directory ENTRY to the file DATA.
1091 Return nonzero if successful, preserving errno on write failure. */
1092 static bool
1093 write_directory_file_entry (void *entry, void *data)
1094 {
1095 struct directory const *directory = entry;
1096 FILE *fp = data;
1097
1098 if (DIR_IS_FOUND (directory))
1099 {
1100 char buf[UINTMAX_STRSIZE_BOUND];
1101 char *s;
1102
1103 s = DIR_IS_NFS (directory) ? "1" : "0";
1104 fwrite (s, 2, 1, fp);
1105 s = (TYPE_SIGNED (time_t)
1106 ? imaxtostr (directory->mtime.tv_sec, buf)
1107 : umaxtostr (directory->mtime.tv_sec, buf));
1108 fwrite (s, strlen (s) + 1, 1, fp);
1109 s = umaxtostr (directory->mtime.tv_nsec, buf);
1110 fwrite (s, strlen (s) + 1, 1, fp);
1111 s = umaxtostr (directory->device_number, buf);
1112 fwrite (s, strlen (s) + 1, 1, fp);
1113 s = umaxtostr (directory->inode_number, buf);
1114 fwrite (s, strlen (s) + 1, 1, fp);
1115
1116 fwrite (directory->name, strlen (directory->name) + 1, 1, fp);
1117 if (directory->contents)
1118 {
1119 char *p;
1120 for (p = directory->contents; *p; p += strlen (p) + 1)
1121 {
1122 if (strchr ("YND", *p))
1123 fwrite (p, strlen (p) + 1, 1, fp);
1124 }
1125 }
1126 fwrite ("\0\0", 2, 1, fp);
1127 }
1128
1129 return ! ferror (fp);
1130 }
1131
1132 void
1133 write_directory_file (void)
1134 {
1135 FILE *fp = listed_incremental_stream;
1136 char buf[UINTMAX_STRSIZE_BOUND];
1137 char *s;
1138
1139 if (! fp)
1140 return;
1141
1142 if (fseek (fp, 0L, SEEK_SET) != 0)
1143 seek_error (listed_incremental_option);
1144 if (sys_truncate (fileno (fp)) != 0)
1145 truncate_error (listed_incremental_option);
1146
1147 fprintf (fp, "%s-%s-%d\n", PACKAGE_NAME, PACKAGE_VERSION,
1148 TAR_INCREMENTAL_VERSION);
1149
1150 s = (TYPE_SIGNED (time_t)
1151 ? imaxtostr (start_time.tv_sec, buf)
1152 : umaxtostr (start_time.tv_sec, buf));
1153 fwrite (s, strlen (s) + 1, 1, fp);
1154 s = umaxtostr (start_time.tv_nsec, buf);
1155 fwrite (s, strlen (s) + 1, 1, fp);
1156
1157 if (! ferror (fp) && directory_table)
1158 hash_do_for_each (directory_table, write_directory_file_entry, fp);
1159
1160 if (ferror (fp))
1161 write_error (listed_incremental_option);
1162 if (fclose (fp) != 0)
1163 close_error (listed_incremental_option);
1164 }
1165
1166 \f
1167 /* Restoration of incremental dumps. */
1168
1169 static void
1170 get_gnu_dumpdir (struct tar_stat_info *stat_info)
1171 {
1172 size_t size;
1173 size_t copied;
1174 union block *data_block;
1175 char *to;
1176 char *archive_dir;
1177
1178 size = stat_info->stat.st_size;
1179
1180 archive_dir = xmalloc (size);
1181 to = archive_dir;
1182
1183 set_next_block_after (current_header);
1184 mv_begin (stat_info);
1185
1186 for (; size > 0; size -= copied)
1187 {
1188 mv_size_left (size);
1189 data_block = find_next_block ();
1190 if (!data_block)
1191 ERROR ((1, 0, _("Unexpected EOF in archive")));
1192 copied = available_space_after (data_block);
1193 if (copied > size)
1194 copied = size;
1195 memcpy (to, data_block->buffer, copied);
1196 to += copied;
1197 set_next_block_after ((union block *)
1198 (data_block->buffer + copied - 1));
1199 }
1200
1201 mv_end ();
1202
1203 stat_info->dumpdir = archive_dir;
1204 stat_info->skipped = true; /* For skip_member() and friends
1205 to work correctly */
1206 }
1207
1208 /* Return T if STAT_INFO represents a dumpdir archive member.
1209 Note: can invalidate current_header. It happens if flush_archive()
1210 gets called within get_gnu_dumpdir() */
1211 bool
1212 is_dumpdir (struct tar_stat_info *stat_info)
1213 {
1214 if (stat_info->is_dumpdir && !stat_info->dumpdir)
1215 get_gnu_dumpdir (stat_info);
1216 return stat_info->is_dumpdir;
1217 }
1218
1219 static bool
1220 dumpdir_ok (char *dumpdir)
1221 {
1222 char *p;
1223 int has_tempdir = 0;
1224 int expect = 0;
1225
1226 for (p = dumpdir; *p; p += strlen (p) + 1)
1227 {
1228 if (expect && *p != expect)
1229 {
1230 ERROR ((0, 0,
1231 _("Malformed dumpdir: expected '%c' but found %#3o"),
1232 expect, *p));
1233 return false;
1234 }
1235 switch (*p)
1236 {
1237 case 'X':
1238 if (has_tempdir)
1239 {
1240 ERROR ((0, 0,
1241 _("Malformed dumpdir: 'X' duplicated")));
1242 return false;
1243 }
1244 else
1245 has_tempdir = 1;
1246 break;
1247
1248 case 'R':
1249 if (p[1] == 0)
1250 {
1251 if (!has_tempdir)
1252 {
1253 ERROR ((0, 0,
1254 _("Malformed dumpdir: empty name in 'R'")));
1255 return false;
1256 }
1257 else
1258 has_tempdir = 0;
1259 }
1260 expect = 'T';
1261 break;
1262
1263 case 'T':
1264 if (expect != 'T')
1265 {
1266 ERROR ((0, 0,
1267 _("Malformed dumpdir: 'T' not preceeded by 'R'")));
1268 return false;
1269 }
1270 if (p[1] == 0 && !has_tempdir)
1271 {
1272 ERROR ((0, 0,
1273 _("Malformed dumpdir: empty name in 'T'")));
1274 return false;
1275 }
1276 expect = 0;
1277 break;
1278
1279 case 'N':
1280 case 'Y':
1281 case 'D':
1282 break;
1283
1284 default:
1285 /* FIXME: bail out? */
1286 break;
1287 }
1288 }
1289
1290 if (expect)
1291 {
1292 ERROR ((0, 0,
1293 _("Malformed dumpdir: expected '%c' but found end of data"),
1294 expect));
1295 return false;
1296 }
1297
1298 if (has_tempdir)
1299 WARN ((0, 0, _("Malformed dumpdir: 'X' never used")));
1300
1301 return true;
1302 }
1303
1304 /* Examine the directories under directory_name and delete any
1305 files that were not there at the time of the back-up. */
1306 static bool
1307 try_purge_directory (char const *directory_name)
1308 {
1309 char *current_dir;
1310 char *cur, *arc, *p;
1311 char *temp_stub = NULL;
1312
1313 if (!is_dumpdir (&current_stat_info))
1314 return false;
1315
1316 current_dir = savedir (directory_name);
1317
1318 if (!current_dir)
1319 /* The directory doesn't exist now. It'll be created. In any
1320 case, we don't have to delete any files out of it. */
1321 return false;
1322
1323 /* Verify if dump directory is sane */
1324 if (!dumpdir_ok (current_stat_info.dumpdir))
1325 return false;
1326
1327 /* Process renames */
1328 for (arc = current_stat_info.dumpdir; *arc; arc += strlen (arc) + 1)
1329 {
1330 if (*arc == 'X')
1331 {
1332 #define TEMP_DIR_TEMPLATE "tar.XXXXXX"
1333 size_t len = strlen (arc + 1);
1334 temp_stub = xrealloc (temp_stub, len + 1 + sizeof TEMP_DIR_TEMPLATE);
1335 memcpy (temp_stub, arc + 1, len);
1336 temp_stub[len] = '/';
1337 memcpy (temp_stub + len + 1, TEMP_DIR_TEMPLATE,
1338 sizeof TEMP_DIR_TEMPLATE);
1339 if (!mkdtemp (temp_stub))
1340 {
1341 ERROR ((0, errno,
1342 _("Cannot create temporary directory using template %s"),
1343 quote (temp_stub)));
1344 free (temp_stub);
1345 free (current_dir);
1346 return false;
1347 }
1348 }
1349 else if (*arc == 'R')
1350 {
1351 char *src, *dst;
1352 src = arc + 1;
1353 arc += strlen (arc) + 1;
1354 dst = arc + 1;
1355
1356 if (*src == 0)
1357 src = temp_stub;
1358 else if (*dst == 0)
1359 dst = temp_stub;
1360
1361 if (!rename_directory (src, dst))
1362 {
1363 free (temp_stub);
1364 free (current_dir);
1365 /* FIXME: Make sure purge_directory(dst) will return
1366 immediately */
1367 return false;
1368 }
1369 }
1370 }
1371
1372 free (temp_stub);
1373
1374 /* Process deletes */
1375 p = NULL;
1376 for (cur = current_dir; *cur; cur += strlen (cur) + 1)
1377 {
1378 const char *entry;
1379 struct stat st;
1380 if (p)
1381 free (p);
1382 p = new_name (directory_name, cur);
1383
1384 if (deref_stat (false, p, &st))
1385 {
1386 if (errno != ENOENT) /* FIXME: Maybe keep a list of renamed
1387 dirs and check it here? */
1388 {
1389 stat_diag (p);
1390 WARN ((0, 0, _("%s: Not purging directory: unable to stat"),
1391 quotearg_colon (p)));
1392 }
1393 continue;
1394 }
1395
1396 if (!(entry = dumpdir_locate (current_stat_info.dumpdir, cur))
1397 || (*entry == 'D' && !S_ISDIR (st.st_mode))
1398 || (*entry == 'Y' && S_ISDIR (st.st_mode)))
1399 {
1400 if (one_file_system_option && st.st_dev != root_device)
1401 {
1402 WARN ((0, 0,
1403 _("%s: directory is on a different device: not purging"),
1404 quotearg_colon (p)));
1405 continue;
1406 }
1407
1408 if (! interactive_option || confirm ("delete", p))
1409 {
1410 if (verbose_option)
1411 fprintf (stdlis, _("%s: Deleting %s\n"),
1412 program_name, quote (p));
1413 if (! remove_any_file (p, RECURSIVE_REMOVE_OPTION))
1414 {
1415 int e = errno;
1416 ERROR ((0, e, _("%s: Cannot remove"), quotearg_colon (p)));
1417 }
1418 }
1419 }
1420 }
1421 free (p);
1422
1423 free (current_dir);
1424 return true;
1425 }
1426
1427 void
1428 purge_directory (char const *directory_name)
1429 {
1430 if (!try_purge_directory (directory_name))
1431 skip_member ();
1432 }
1433
1434 void
1435 list_dumpdir (char *buffer, size_t size)
1436 {
1437 while (size)
1438 {
1439 switch (*buffer)
1440 {
1441 case 'Y':
1442 case 'N':
1443 case 'D':
1444 case 'R':
1445 case 'T':
1446 case 'X':
1447 fprintf (stdlis, "%c ", *buffer);
1448 buffer++;
1449 size--;
1450 break;
1451
1452 case 0:
1453 fputc ('\n', stdlis);
1454 buffer++;
1455 size--;
1456 break;
1457
1458 default:
1459 fputc (*buffer, stdlis);
1460 buffer++;
1461 size--;
1462 }
1463 }
1464 }
This page took 0.098248 seconds and 4 git commands to generate.