]> Dogcows Code - chaz/tar/blob - src/incremen.c
Remove not used variables
[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 t = u;
665 char *buf = 0;
666 size_t bufsize;
667 char *ebuf;
668 long lineno = 1;
669
670 if (version == 1)
671 {
672 if (getline (&buf, &bufsize, listed_incremental_stream) <= 0)
673 {
674 read_error (listed_incremental_option);
675 free (buf);
676 return;
677 }
678 ++lineno;
679 }
680 else
681 {
682 buf = strdup (initbuf);
683 bufsize = strlen (buf) + 1;
684 }
685
686 t = u = (errno = 0, strtoumax (buf, &ebuf, 10));
687 if (buf == ebuf || (u == 0 && errno == EINVAL))
688 ERROR ((0, 0, "%s:%ld: %s",
689 quotearg_colon (listed_incremental_option),
690 lineno,
691 _("Invalid time stamp")));
692 else if (t != u)
693 ERROR ((0, 0, "%s:%ld: %s",
694 quotearg_colon (listed_incremental_option),
695 lineno,
696 _("Time stamp out of range")));
697 else if (version == 1)
698 {
699 newer_mtime_option.tv_sec = t;
700
701 t = u = (errno = 0, strtoumax (buf, &ebuf, 10));
702 if (buf == ebuf || (u == 0 && errno == EINVAL))
703 ERROR ((0, 0, "%s:%ld: %s",
704 quotearg_colon (listed_incremental_option),
705 lineno,
706 _("Invalid time stamp")));
707 else if (t != u)
708 ERROR ((0, 0, "%s:%ld: %s",
709 quotearg_colon (listed_incremental_option),
710 lineno,
711 _("Time stamp out of range")));
712 newer_mtime_option.tv_nsec = t;
713 }
714 else
715 {
716 /* pre-1 incremental format does not contain nanoseconds */
717 newer_mtime_option.tv_sec = t;
718 newer_mtime_option.tv_nsec = 0;
719 }
720
721 while (0 < (n = getline (&buf, &bufsize, listed_incremental_stream)))
722 {
723 dev_t dev;
724 ino_t ino;
725 bool nfs = buf[0] == '+';
726 char *strp = buf + nfs;
727 struct timespec mtime;
728
729 lineno++;
730
731 if (buf[n - 1] == '\n')
732 buf[n - 1] = '\0';
733
734 if (version == 1)
735 {
736 errno = 0;
737 mtime.tv_sec = u = strtoumax (strp, &ebuf, 10);
738 if (!isspace (*ebuf))
739 ERROR ((0, 0, "%s:%ld: %s",
740 quotearg_colon (listed_incremental_option), lineno,
741 _("Invalid modification time (seconds)")));
742 else if (mtime.tv_sec != u)
743 ERROR ((0, 0, "%s:%ld: %s",
744 quotearg_colon (listed_incremental_option), lineno,
745 _("Modification time (seconds) out of range")));
746 strp = ebuf;
747
748 errno = 0;
749 mtime.tv_nsec = u = strtoumax (strp, &ebuf, 10);
750 if (!isspace (*ebuf))
751 ERROR ((0, 0, "%s:%ld: %s",
752 quotearg_colon (listed_incremental_option), lineno,
753 _("Invalid modification time (nanoseconds)")));
754 else if (mtime.tv_nsec != u)
755 ERROR ((0, 0, "%s:%ld: %s",
756 quotearg_colon (listed_incremental_option), lineno,
757 _("Modification time (nanoseconds) out of range")));
758 strp = ebuf;
759 }
760 else
761 memset (&mtime, 0, sizeof mtime);
762
763 errno = 0;
764 dev = u = strtoumax (strp, &ebuf, 10);
765 if (!isspace (*ebuf))
766 ERROR ((0, 0, "%s:%ld: %s",
767 quotearg_colon (listed_incremental_option), lineno,
768 _("Invalid device number")));
769 else if (dev != u)
770 ERROR ((0, 0, "%s:%ld: %s",
771 quotearg_colon (listed_incremental_option), lineno,
772 _("Device number out of range")));
773 strp = ebuf;
774
775 errno = 0;
776 ino = u = strtoumax (strp, &ebuf, 10);
777 if (!isspace (*ebuf))
778 ERROR ((0, 0, "%s:%ld: %s",
779 quotearg_colon (listed_incremental_option), lineno,
780 _("Invalid inode number")));
781 else if (ino != u)
782 ERROR ((0, 0, "%s:%ld: %s",
783 quotearg_colon (listed_incremental_option), lineno,
784 _("Inode number out of range")));
785 strp = ebuf;
786
787 strp++;
788 unquote_string (strp);
789 note_directory (strp, mtime, dev, ino, nfs, false, NULL);
790 }
791 free (buf);
792 }
793
794 /* Read a nul-terminated string from FP and store it in STK.
795 Store the number of bytes read (including nul terminator) in PCOUNT.
796
797 Return the last character read or EOF on end of file. */
798 static int
799 read_obstack (FILE *fp, struct obstack *stk, size_t *pcount)
800 {
801 int c;
802 size_t i;
803
804 for (i = 0, c = getc (fp); c != EOF && c != 0; c = getc (fp), i++)
805 obstack_1grow (stk, c);
806 obstack_1grow (stk, 0);
807
808 *pcount = i;
809 return c;
810 }
811
812 /* Read from file FP a nul-terminated string and convert it to
813 uintmax_t. Return the resulting value in PVAL.
814
815 Throw fatal error if the string cannot be converted.
816
817 Return the last character read or EOF on end of file. */
818
819 static int
820 read_num (FILE *fp, uintmax_t *pval)
821 {
822 int c;
823 size_t i;
824 char buf[UINTMAX_STRSIZE_BOUND], *ep;
825
826 for (i = 0, c = getc (fp); c != EOF && c != 0; c = getc (fp), i++)
827 {
828 if (i == sizeof buf - 1)
829 FATAL_ERROR ((0, 0, _("Field too long while reading snapshot file")));
830 buf[i] = c;
831 }
832 buf[i] = 0;
833 *pval = strtoumax (buf, &ep, 10);
834 if (*ep)
835 FATAL_ERROR ((0, 0, _("Unexpected field value in snapshot file")));
836 return c;
837 }
838
839 /* Read incremental snapshot format 2 */
840 static void
841 read_incr_db_2 ()
842 {
843 uintmax_t u;
844 struct obstack stk;
845
846 obstack_init (&stk);
847
848 if (read_num (listed_incremental_stream, &u))
849 FATAL_ERROR ((0, 0, "%s: %s",
850 quotearg_colon (listed_incremental_option),
851 _("Error reading time stamp")));
852 newer_mtime_option.tv_sec = u;
853 if (newer_mtime_option.tv_sec != u)
854 FATAL_ERROR ((0, 0, "%s: %s",
855 quotearg_colon (listed_incremental_option),
856 _("Time stamp out of range")));
857
858 if (read_num (listed_incremental_stream, &u))
859 FATAL_ERROR ((0, 0, "%s: %s",
860 quotearg_colon (listed_incremental_option),
861 _("Error reading time stamp")));
862 newer_mtime_option.tv_nsec = u;
863 if (newer_mtime_option.tv_nsec != u)
864 FATAL_ERROR ((0, 0, "%s: %s",
865 quotearg_colon (listed_incremental_option),
866 _("Time stamp out of range")));
867
868 for (;;)
869 {
870 struct timespec mtime;
871 dev_t dev;
872 ino_t ino;
873 bool nfs;
874 char *name;
875 char *content;
876 size_t s;
877
878 if (read_num (listed_incremental_stream, &u))
879 return; /* Normal return */
880
881 nfs = u;
882
883 if (read_num (listed_incremental_stream, &u))
884 break;
885 mtime.tv_sec = u;
886 if (mtime.tv_sec != u)
887 FATAL_ERROR ((0, 0, "%s: %s",
888 quotearg_colon (listed_incremental_option),
889 _("Modification time (seconds) out of range")));
890
891 if (read_num (listed_incremental_stream, &u))
892 break;
893 mtime.tv_nsec = u;
894 if (mtime.tv_nsec != u)
895 FATAL_ERROR ((0, 0, "%s: %s",
896 quotearg_colon (listed_incremental_option),
897 _("Modification time (nanoseconds) out of range")));
898
899 if (read_num (listed_incremental_stream, &u))
900 break;
901 dev = u;
902 if (dev != u)
903 FATAL_ERROR ((0, 0, "%s: %s",
904 quotearg_colon (listed_incremental_option),
905 _("Device number out of range")));
906
907 if (read_num (listed_incremental_stream, &u))
908 break;
909 ino = u;
910 if (ino != u)
911 FATAL_ERROR ((0, 0, "%s: %s",
912 quotearg_colon (listed_incremental_option),
913 _("Inode number out of range")));
914
915 if (read_obstack (listed_incremental_stream, &stk, &s))
916 break;
917
918 name = obstack_finish (&stk);
919
920 while (read_obstack (listed_incremental_stream, &stk, &s) == 0 && s > 1)
921 ;
922 if (getc (listed_incremental_stream) != 0)
923 FATAL_ERROR ((0, 0, "%s: %s",
924 quotearg_colon (listed_incremental_option),
925 _("Missing record terminator")));
926
927 content = obstack_finish (&stk);
928 note_directory (name, mtime, dev, ino, nfs, false, content);
929 obstack_free (&stk, content);
930 }
931 FATAL_ERROR ((0, 0, "%s: %s",
932 quotearg_colon (listed_incremental_option),
933 _("Unexpected EOF")));
934 }
935
936 /* Read incremental snapshot file (directory file).
937 If the file has older incremental version, make sure that it is processed
938 correctly and that tar will use the most conservative backup method among
939 possible alternatives (i.e. prefer ALL_CHILDREN over CHANGED_CHILDREN,
940 etc.) This ensures that the snapshots are updated to the recent version
941 without any loss of data. */
942 void
943 read_directory_file (void)
944 {
945 int fd;
946 char *buf = 0;
947 size_t bufsize;
948
949 /* Open the file for both read and write. That way, we can write
950 it later without having to reopen it, and don't have to worry if
951 we chdir in the meantime. */
952 fd = open (listed_incremental_option, O_RDWR | O_CREAT, MODE_RW);
953 if (fd < 0)
954 {
955 open_error (listed_incremental_option);
956 return;
957 }
958
959 listed_incremental_stream = fdopen (fd, "r+");
960 if (! listed_incremental_stream)
961 {
962 open_error (listed_incremental_option);
963 close (fd);
964 return;
965 }
966
967 if (0 < getline (&buf, &bufsize, listed_incremental_stream))
968 {
969 char *ebuf;
970 int incremental_version;
971
972 if (strncmp (buf, PACKAGE_NAME, sizeof PACKAGE_NAME - 1) == 0)
973 {
974 ebuf = buf + sizeof PACKAGE_NAME - 1;
975 if (*ebuf++ != '-')
976 ERROR((1, 0, _("Bad incremental file format")));
977 for (; *ebuf != '-'; ebuf++)
978 if (!*ebuf)
979 ERROR((1, 0, _("Bad incremental file format")));
980
981 incremental_version = (errno = 0, strtoumax (ebuf+1, &ebuf, 10));
982 }
983 else
984 incremental_version = 0;
985
986 switch (incremental_version)
987 {
988 case 0:
989 case 1:
990 read_incr_db_01 (incremental_version, buf);
991 break;
992
993 case TAR_INCREMENTAL_VERSION:
994 read_incr_db_2 ();
995 break;
996
997 default:
998 ERROR ((1, 0, _("Unsupported incremental format version: %d"),
999 incremental_version));
1000 }
1001
1002 }
1003
1004 if (ferror (listed_incremental_stream))
1005 read_error (listed_incremental_option);
1006 if (buf)
1007 free (buf);
1008 }
1009
1010 /* Output incremental data for the directory ENTRY to the file DATA.
1011 Return nonzero if successful, preserving errno on write failure. */
1012 static bool
1013 write_directory_file_entry (void *entry, void *data)
1014 {
1015 struct directory const *directory = entry;
1016 FILE *fp = data;
1017
1018 if (DIR_IS_FOUND (directory))
1019 {
1020 char buf[UINTMAX_STRSIZE_BOUND];
1021 char *s;
1022
1023 s = DIR_IS_NFS (directory) ? "1" : "0";
1024 fwrite (s, 2, 1, fp);
1025 s = umaxtostr (directory->mtime.tv_sec, buf);
1026 fwrite (s, strlen (s) + 1, 1, fp);
1027 s = umaxtostr (directory->mtime.tv_nsec, buf);
1028 fwrite (s, strlen (s) + 1, 1, fp);
1029 s = umaxtostr (directory->device_number, buf);
1030 fwrite (s, strlen (s) + 1, 1, fp);
1031 s = umaxtostr (directory->inode_number, buf);
1032 fwrite (s, strlen (s) + 1, 1, fp);
1033
1034 fwrite (directory->name, strlen (directory->name) + 1, 1, fp);
1035 if (directory->contents)
1036 {
1037 char *p;
1038 for (p = directory->contents; *p; p += strlen (p) + 1)
1039 {
1040 if (strchr ("YND", *p))
1041 fwrite (p, strlen (p) + 1, 1, fp);
1042 }
1043 }
1044 fwrite ("\0\0", 2, 1, fp);
1045 }
1046
1047 return ! ferror (fp);
1048 }
1049
1050 void
1051 write_directory_file (void)
1052 {
1053 FILE *fp = listed_incremental_stream;
1054 char buf[UINTMAX_STRSIZE_BOUND];
1055 char *s;
1056
1057 if (! fp)
1058 return;
1059
1060 if (fseek (fp, 0L, SEEK_SET) != 0)
1061 seek_error (listed_incremental_option);
1062 if (sys_truncate (fileno (fp)) != 0)
1063 truncate_error (listed_incremental_option);
1064
1065 fprintf (fp, "%s-%s-%d\n", PACKAGE_NAME, PACKAGE_VERSION,
1066 TAR_INCREMENTAL_VERSION);
1067
1068 s = umaxtostr (start_time.tv_sec, buf);
1069 fwrite (s, strlen (s) + 1, 1, fp);
1070 s = umaxtostr (start_time.tv_nsec, buf);
1071 fwrite (s, strlen (s) + 1, 1, fp);
1072
1073 if (! ferror (fp) && directory_table)
1074 hash_do_for_each (directory_table, write_directory_file_entry, fp);
1075
1076 if (ferror (fp))
1077 write_error (listed_incremental_option);
1078 if (fclose (fp) != 0)
1079 close_error (listed_incremental_option);
1080 }
1081
1082 \f
1083 /* Restoration of incremental dumps. */
1084
1085 static void
1086 get_gnu_dumpdir (struct tar_stat_info *stat_info)
1087 {
1088 size_t size;
1089 size_t copied;
1090 union block *data_block;
1091 char *to;
1092 char *archive_dir;
1093
1094 size = stat_info->stat.st_size;
1095
1096 archive_dir = xmalloc (size);
1097 to = archive_dir;
1098
1099 set_next_block_after (current_header);
1100 mv_begin (stat_info);
1101
1102 for (; size > 0; size -= copied)
1103 {
1104 mv_size_left (size);
1105 data_block = find_next_block ();
1106 if (!data_block)
1107 ERROR ((1, 0, _("Unexpected EOF in archive")));
1108 copied = available_space_after (data_block);
1109 if (copied > size)
1110 copied = size;
1111 memcpy (to, data_block->buffer, copied);
1112 to += copied;
1113 set_next_block_after ((union block *)
1114 (data_block->buffer + copied - 1));
1115 }
1116
1117 mv_end ();
1118
1119 stat_info->dumpdir = archive_dir;
1120 stat_info->skipped = true; /* For skip_member() and friends
1121 to work correctly */
1122 }
1123
1124 /* Return T if STAT_INFO represents a dumpdir archive member.
1125 Note: can invalidate current_header. It happens if flush_archive()
1126 gets called within get_gnu_dumpdir() */
1127 bool
1128 is_dumpdir (struct tar_stat_info *stat_info)
1129 {
1130 if (stat_info->is_dumpdir && !stat_info->dumpdir)
1131 get_gnu_dumpdir (stat_info);
1132 return stat_info->is_dumpdir;
1133 }
1134
1135 static bool
1136 dumpdir_ok (char *dumpdir)
1137 {
1138 char *p;
1139 int has_tempdir = 0;
1140 int expect = 0;
1141
1142 for (p = dumpdir; *p; p += strlen (p) + 1)
1143 {
1144 if (expect && *p != expect)
1145 {
1146 ERROR ((0, 0,
1147 _("Malformed dumpdir: expected '%c' but found %#3o"),
1148 expect, *p));
1149 return false;
1150 }
1151 switch (*p)
1152 {
1153 case 'X':
1154 if (has_tempdir)
1155 {
1156 ERROR ((0, 0,
1157 _("Malformed dumpdir: 'X' duplicated")));
1158 return false;
1159 }
1160 else
1161 has_tempdir = 1;
1162 break;
1163
1164 case 'R':
1165 if (p[1] == 0)
1166 {
1167 if (!has_tempdir)
1168 {
1169 ERROR ((0, 0,
1170 _("Malformed dumpdir: empty name in 'R'")));
1171 return false;
1172 }
1173 else
1174 has_tempdir = 0;
1175 }
1176 expect = 'T';
1177 break;
1178
1179 case 'T':
1180 if (expect != 'T')
1181 {
1182 ERROR ((0, 0,
1183 _("Malformed dumpdir: 'T' not preceeded by 'R'")));
1184 return false;
1185 }
1186 if (p[1] == 0 && !has_tempdir)
1187 {
1188 ERROR ((0, 0,
1189 _("Malformed dumpdir: empty name in 'T'")));
1190 return false;
1191 }
1192 expect = 0;
1193 break;
1194
1195 case 'N':
1196 case 'Y':
1197 case 'D':
1198 break;
1199
1200 default:
1201 /* FIXME: bail out? */
1202 break;
1203 }
1204 }
1205
1206 if (expect)
1207 {
1208 ERROR ((0, 0,
1209 _("Malformed dumpdir: expected '%c' but found end of data"),
1210 expect));
1211 return false;
1212 }
1213
1214 if (has_tempdir)
1215 WARN ((0, 0, _("Malformed dumpdir: 'X' never used")));
1216
1217 return true;
1218 }
1219
1220 /* Examine the directories under directory_name and delete any
1221 files that were not there at the time of the back-up. */
1222 static bool
1223 try_purge_directory (char const *directory_name)
1224 {
1225 char *current_dir;
1226 char *cur, *arc, *p;
1227 char *temp_stub = NULL;
1228
1229 if (!is_dumpdir (&current_stat_info))
1230 return false;
1231
1232 current_dir = savedir (directory_name);
1233
1234 if (!current_dir)
1235 /* The directory doesn't exist now. It'll be created. In any
1236 case, we don't have to delete any files out of it. */
1237 return false;
1238
1239 /* Verify if dump directory is sane */
1240 if (!dumpdir_ok (current_stat_info.dumpdir))
1241 return false;
1242
1243 /* Process renames */
1244 for (arc = current_stat_info.dumpdir; *arc; arc += strlen (arc) + 1)
1245 {
1246 if (*arc == 'X')
1247 {
1248 #define TEMP_DIR_TEMPLATE "tar.XXXXXX"
1249 size_t len = strlen (arc + 1);
1250 temp_stub = xrealloc (temp_stub, len + 1 + sizeof TEMP_DIR_TEMPLATE);
1251 memcpy (temp_stub, arc + 1, len);
1252 temp_stub[len] = '/';
1253 memcpy (temp_stub + len + 1, TEMP_DIR_TEMPLATE,
1254 sizeof TEMP_DIR_TEMPLATE);
1255 if (!mkdtemp (temp_stub))
1256 {
1257 ERROR ((0, errno,
1258 _("Cannot create temporary directory using template %s"),
1259 quote (temp_stub)));
1260 free (temp_stub);
1261 free (current_dir);
1262 return false;
1263 }
1264 }
1265 else if (*arc == 'R')
1266 {
1267 char *src, *dst;
1268 src = arc + 1;
1269 arc += strlen (arc) + 1;
1270 dst = arc + 1;
1271
1272 if (*src == 0)
1273 src = temp_stub;
1274 else if (*dst == 0)
1275 dst = temp_stub;
1276
1277 if (!rename_directory (src, dst))
1278 {
1279 free (temp_stub);
1280 free (current_dir);
1281 /* FIXME: Make sure purge_directory(dst) will return
1282 immediately */
1283 return false;
1284 }
1285 }
1286 }
1287
1288 free (temp_stub);
1289
1290 /* Process deletes */
1291 p = NULL;
1292 for (cur = current_dir; *cur; cur += strlen (cur) + 1)
1293 {
1294 const char *entry;
1295 struct stat st;
1296 if (p)
1297 free (p);
1298 p = new_name (directory_name, cur);
1299
1300 if (!(entry = dumpdir_locate (current_stat_info.dumpdir, cur))
1301 || (*entry == 'D' && S_ISDIR (st.st_mode))
1302 || (*entry == 'Y' && !S_ISDIR (st.st_mode)))
1303 {
1304 if (deref_stat (false, p, &st))
1305 {
1306 if (errno != ENOENT) /* FIXME: Maybe keep a list of renamed
1307 dirs and check it here? */
1308 {
1309 stat_diag (p);
1310 WARN ((0, 0, _("%s: Not purging directory: unable to stat"),
1311 quotearg_colon (p)));
1312 }
1313 continue;
1314 }
1315 else if (one_file_system_option && st.st_dev != root_device)
1316 {
1317 WARN ((0, 0,
1318 _("%s: directory is on a different device: not purging"),
1319 quotearg_colon (p)));
1320 continue;
1321 }
1322
1323 if (! interactive_option || confirm ("delete", p))
1324 {
1325 if (verbose_option)
1326 fprintf (stdlis, _("%s: Deleting %s\n"),
1327 program_name, quote (p));
1328 if (! remove_any_file (p, RECURSIVE_REMOVE_OPTION))
1329 {
1330 int e = errno;
1331 ERROR ((0, e, _("%s: Cannot remove"), quotearg_colon (p)));
1332 }
1333 }
1334 }
1335 }
1336 free (p);
1337
1338 free (current_dir);
1339 return true;
1340 }
1341
1342 void
1343 purge_directory (char const *directory_name)
1344 {
1345 if (!try_purge_directory (directory_name))
1346 skip_member ();
1347 }
1348
1349 void
1350 list_dumpdir (char *buffer, size_t size)
1351 {
1352 while (size)
1353 {
1354 switch (*buffer)
1355 {
1356 case 'Y':
1357 case 'N':
1358 case 'D':
1359 case 'R':
1360 case 'T':
1361 case 'X':
1362 fprintf (stdlis, "%c ", *buffer);
1363 buffer++;
1364 size--;
1365 break;
1366
1367 case 0:
1368 fputc ('\n', stdlis);
1369 buffer++;
1370 size--;
1371 break;
1372
1373 default:
1374 fputc (*buffer, stdlis);
1375 buffer++;
1376 size--;
1377 }
1378 }
1379 }
This page took 0.099028 seconds and 5 git commands to generate.