]> Dogcows Code - chaz/tar/blob - src/incremen.c
(dumpdir_locate,obstack_code_rename,purge_directory): Re-implement renaming. Introduce
[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, *name_buffer;
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 struct name *np;
238
239 if ((directory = find_directory (name_buffer)) != NULL)
240 {
241 if (DIR_IS_INITED (directory))
242 return directory;
243
244 /* With NFS, the same file can have two different devices
245 if an NFS directory is mounted in multiple locations,
246 which is relatively common when automounting.
247 To avoid spurious incremental redumping of
248 directories, consider all NFS devices as equal,
249 relying on the i-node to establish differences. */
250
251 if (! (((DIR_IS_NFS (directory) & nfs)
252 || directory->device_number == stat_data->st_dev)
253 && directory->inode_number == stat_data->st_ino))
254 {
255 /* FIXME: find_directory_meta ignores nfs */
256 struct directory *d = find_directory_meta (stat_data->st_dev,
257 stat_data->st_ino);
258 if (d)
259 {
260 if (verbose_option)
261 WARN ((0, 0, _("%s: Directory has been renamed from %s"),
262 quotearg_colon (name_buffer),
263 quote_n (1, d->name)));
264 directory->orig = d;
265 DIR_SET_FLAG (directory, DIRF_RENAMED);
266 directory->children = CHANGED_CHILDREN;
267 }
268 else
269 {
270 if (verbose_option)
271 WARN ((0, 0, _("%s: Directory has been renamed"),
272 quotearg_colon (name_buffer)));
273 directory->children = ALL_CHILDREN;
274 directory->device_number = stat_data->st_dev;
275 directory->inode_number = stat_data->st_ino;
276 }
277 if (nfs)
278 DIR_SET_FLAG (directory, DIRF_NFS);
279 }
280 else
281 directory->children = CHANGED_CHILDREN;
282
283 DIR_SET_FLAG (directory, DIRF_FOUND);
284 }
285 else
286 {
287 struct directory *d = find_directory_meta (stat_data->st_dev,
288 stat_data->st_ino);
289
290 directory = note_directory (name_buffer,
291 get_stat_mtime(stat_data),
292 stat_data->st_dev,
293 stat_data->st_ino,
294 nfs,
295 true,
296 NULL);
297
298 if (d)
299 {
300 if (verbose)
301 WARN ((0, 0, _("%s: Directory has been renamed from %s"),
302 quotearg_colon (name_buffer),
303 quote_n (1, d->name)));
304 directory->orig = d;
305 DIR_SET_FLAG (directory, DIRF_RENAMED);
306 directory->children = CHANGED_CHILDREN;
307 }
308 else
309 {
310 DIR_SET_FLAG (directory, DIRF_NEW);
311 if (verbose)
312 WARN ((0, 0, _("%s: Directory is new"),
313 quotearg_colon (name_buffer)));
314 directory->children =
315 (listed_incremental_option
316 || (OLDER_STAT_TIME (*stat_data, m)
317 || (after_date_option
318 && OLDER_STAT_TIME (*stat_data, c))))
319 ? ALL_CHILDREN
320 : CHANGED_CHILDREN;
321 }
322 }
323
324 /* If the directory is on another device and --one-file-system was given,
325 omit it... */
326 if (one_file_system_option && device != stat_data->st_dev
327 /* ... except if it was explicitely given in the command line */
328 && !((np = name_scan (name_buffer, true)) && np->explicit))
329 directory->children = NO_CHILDREN;
330 else if (children == ALL_CHILDREN)
331 directory->children = ALL_CHILDREN;
332
333 DIR_SET_FLAG (directory, DIRF_INIT);
334
335 return directory;
336 }
337
338 /* Locate NAME in the dumpdir array DUMP.
339 Return pointer to the slot in the array, or NULL if not found */
340 const char *
341 dumpdir_locate (const char *dump, const char *name)
342 {
343 if (dump)
344 while (*dump)
345 {
346 /* Ignore 'R' (rename) and 'X' (tempname) entries, since they break
347 alphabetical ordering.
348 They normally do not occur in dumpdirs from the snapshot files,
349 but this function is also used by purge_directory, which operates
350 on a dumpdir from the archive, hence the need for this test. */
351 if (!strchr ("RX", *dump))
352 {
353 int rc = strcmp (dump + 1, name);
354 if (rc == 0)
355 return dump;
356 if (rc > 1)
357 break;
358 }
359 dump += strlen (dump) + 1;
360 }
361 return NULL;
362 }
363
364 /* Return size in bytes of the dumpdir array P */
365 size_t
366 dumpdir_size (const char *p)
367 {
368 size_t totsize = 0;
369
370 while (*p)
371 {
372 size_t size = strlen (p) + 1;
373 totsize += size;
374 p += size;
375 }
376 return totsize + 1;
377 }
378
379 static int
380 compare_dirnames (const void *first, const void *second)
381 {
382 return strcmp (*(const char**)first, *(const char**)second);
383 }
384
385 /* Compare dumpdir array from DIRECTORY with directory listing DIR and
386 build a new dumpdir template.
387
388 DIR must be returned by a previous call to savedir().
389
390 File names in DIRECTORY->contents must be sorted
391 alphabetically.
392
393 DIRECTORY->contents is replaced with the created template. Each entry is
394 prefixed with ' ' if it was present in DUMP and with 'Y' otherwise. */
395
396 void
397 makedumpdir (struct directory *directory, const char *dir)
398 {
399 size_t i,
400 dirsize, /* Number of elements in DIR */
401 len; /* Length of DIR, including terminating nul */
402 const char *p;
403 char const **array;
404 char *new_dump, *new_dump_ptr;
405 const char *dump;
406
407 if (directory->children == ALL_CHILDREN)
408 dump = NULL;
409 else if (DIR_IS_RENAMED (directory))
410 dump = directory->orig->icontents ?
411 directory->orig->icontents : directory->orig->contents;
412 else
413 dump = directory->contents;
414
415 /* Count the size of DIR and the number of elements it contains */
416 dirsize = 0;
417 len = 0;
418 for (p = dir; *p; p += strlen (p) + 1, dirsize++)
419 len += strlen (p) + 2;
420 len++;
421
422 /* Create a sorted directory listing */
423 array = xcalloc (dirsize, sizeof array[0]);
424 for (i = 0, p = dir; *p; p += strlen (p) + 1, i++)
425 array[i] = p;
426
427 qsort (array, dirsize, sizeof (array[0]), compare_dirnames);
428
429 /* Prepare space for new dumpdir */
430 new_dump = xmalloc (len);
431 new_dump_ptr = new_dump;
432
433 /* Fill in the dumpdir template */
434 for (i = 0; i < dirsize; i++)
435 {
436 const char *loc = dumpdir_locate (dump, array[i]);
437 if (loc)
438 {
439 *new_dump_ptr++ = ' ';
440 dump = loc + strlen (loc) + 1;
441 }
442 else
443 *new_dump_ptr++ = 'Y'; /* New entry */
444
445 /* Copy the file name */
446 for (p = array[i]; (*new_dump_ptr++ = *p++); )
447 ;
448 }
449 *new_dump_ptr = 0;
450 directory->icontents = directory->contents;
451 directory->contents = new_dump;
452 free (array);
453 }
454
455 /* Recursively scan the given directory. */
456 static char *
457 scan_directory (char *dir_name, dev_t device)
458 {
459 char *dirp = savedir (dir_name); /* for scanning directory */
460 char *name_buffer; /* directory, `/', and directory member */
461 size_t name_buffer_size; /* allocated size of name_buffer, minus 2 */
462 size_t name_length; /* used length in name_buffer */
463 struct stat stat_data;
464 struct directory *directory;
465
466 if (! dirp)
467 savedir_error (dir_name);
468
469 name_buffer_size = strlen (dir_name) + NAME_FIELD_SIZE;
470 name_buffer = xmalloc (name_buffer_size + 2);
471 strcpy (name_buffer, dir_name);
472 if (! ISSLASH (dir_name[strlen (dir_name) - 1]))
473 strcat (name_buffer, "/");
474 name_length = strlen (name_buffer);
475
476 if (deref_stat (dereference_option, name_buffer, &stat_data))
477 {
478 stat_diag (name_buffer);
479 /* FIXME: used to be
480 children = CHANGED_CHILDREN;
481 but changed to: */
482 free (name_buffer);
483 free (dirp);
484 return NULL;
485 }
486
487 directory = procdir (name_buffer, &stat_data, device, NO_CHILDREN, false);
488
489 if (dirp && directory->children != NO_CHILDREN)
490 {
491 char *entry; /* directory entry being scanned */
492 size_t entrylen; /* length of directory entry */
493
494 makedumpdir (directory, dirp);
495
496 for (entry = directory->contents;
497 (entrylen = strlen (entry)) != 0;
498 entry += entrylen + 1)
499 {
500 if (name_buffer_size <= entrylen - 1 + name_length)
501 {
502 do
503 name_buffer_size += NAME_FIELD_SIZE;
504 while (name_buffer_size <= entrylen - 1 + name_length);
505 name_buffer = xrealloc (name_buffer, name_buffer_size + 2);
506 }
507 strcpy (name_buffer + name_length, entry + 1);
508
509 if (excluded_name (name_buffer))
510 *entry = 'N';
511 else
512 {
513 if (deref_stat (dereference_option, name_buffer, &stat_data))
514 {
515 stat_diag (name_buffer);
516 *entry = 'N';
517 continue;
518 }
519
520 if (S_ISDIR (stat_data.st_mode))
521 {
522 procdir (name_buffer, &stat_data, device,
523 directory->children,
524 verbose_option);
525 *entry = 'D';
526 }
527
528 else if (one_file_system_option && device != stat_data.st_dev)
529 *entry = 'N';
530
531 else if (*entry == 'Y')
532 /* New entry, skip further checks */;
533
534 /* FIXME: if (S_ISHIDDEN (stat_data.st_mode))?? */
535
536 else if (OLDER_STAT_TIME (stat_data, m)
537 && (!after_date_option
538 || OLDER_STAT_TIME (stat_data, c)))
539 *entry = 'N';
540 else
541 *entry = 'Y';
542 }
543 }
544 }
545
546 free (name_buffer);
547 if (dirp)
548 free (dirp);
549
550 return directory->contents;
551 }
552
553 char *
554 get_directory_contents (char *dir_name, dev_t device)
555 {
556 return scan_directory (dir_name, device);
557 }
558
559 \f
560 static void
561 obstack_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
569 static bool
570 rename_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
616 const char *
617 append_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 \f
646
647 static FILE *listed_incremental_stream;
648
649 /* Version of incremental format snapshots (directory files) used by this
650 tar. Currently it is supposed to be a single decimal number. 0 means
651 incremental snapshots as per tar version before 1.15.2.
652
653 The current tar version supports incremental versions from
654 0 up to TAR_INCREMENTAL_VERSION, inclusive.
655 It is able to create only snapshots of TAR_INCREMENTAL_VERSION */
656
657 #define TAR_INCREMENTAL_VERSION 2
658
659 /* Read incremental snapshot formats 0 and 1 */
660 static void
661 read_incr_db_01 (int version, const char *initbuf)
662 {
663 int n;
664 uintmax_t u;
665 time_t t = u;
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 t = u = (errno = 0, strtoumax (buf, &ebuf, 10));
688 if (buf == ebuf || (u == 0 && errno == EINVAL))
689 ERROR ((0, 0, "%s:%ld: %s",
690 quotearg_colon (listed_incremental_option),
691 lineno,
692 _("Invalid time stamp")));
693 else if (t != u)
694 ERROR ((0, 0, "%s:%ld: %s",
695 quotearg_colon (listed_incremental_option),
696 lineno,
697 _("Time stamp out of range")));
698 else if (version == 1)
699 {
700 newer_mtime_option.tv_sec = t;
701
702 t = u = (errno = 0, strtoumax (buf, &ebuf, 10));
703 if (buf == ebuf || (u == 0 && errno == EINVAL))
704 ERROR ((0, 0, "%s:%ld: %s",
705 quotearg_colon (listed_incremental_option),
706 lineno,
707 _("Invalid time stamp")));
708 else if (t != u)
709 ERROR ((0, 0, "%s:%ld: %s",
710 quotearg_colon (listed_incremental_option),
711 lineno,
712 _("Time stamp out of range")));
713 newer_mtime_option.tv_nsec = t;
714 }
715 else
716 {
717 /* pre-1 incremental format does not contain nanoseconds */
718 newer_mtime_option.tv_sec = t;
719 newer_mtime_option.tv_nsec = 0;
720 }
721
722 while (0 < (n = getline (&buf, &bufsize, listed_incremental_stream)))
723 {
724 dev_t dev;
725 ino_t ino;
726 bool nfs = buf[0] == '+';
727 char *strp = buf + nfs;
728 struct timespec mtime;
729
730 lineno++;
731
732 if (buf[n - 1] == '\n')
733 buf[n - 1] = '\0';
734
735 if (version == 1)
736 {
737 errno = 0;
738 mtime.tv_sec = u = strtoumax (strp, &ebuf, 10);
739 if (!isspace (*ebuf))
740 ERROR ((0, 0, "%s:%ld: %s",
741 quotearg_colon (listed_incremental_option), lineno,
742 _("Invalid modification time (seconds)")));
743 else if (mtime.tv_sec != u)
744 ERROR ((0, 0, "%s:%ld: %s",
745 quotearg_colon (listed_incremental_option), lineno,
746 _("Modification time (seconds) out of range")));
747 strp = ebuf;
748
749 errno = 0;
750 mtime.tv_nsec = u = strtoumax (strp, &ebuf, 10);
751 if (!isspace (*ebuf))
752 ERROR ((0, 0, "%s:%ld: %s",
753 quotearg_colon (listed_incremental_option), lineno,
754 _("Invalid modification time (nanoseconds)")));
755 else if (mtime.tv_nsec != u)
756 ERROR ((0, 0, "%s:%ld: %s",
757 quotearg_colon (listed_incremental_option), lineno,
758 _("Modification time (nanoseconds) out of range")));
759 strp = ebuf;
760 }
761 else
762 memset (&mtime, 0, sizeof mtime);
763
764 errno = 0;
765 dev = u = strtoumax (strp, &ebuf, 10);
766 if (!isspace (*ebuf))
767 ERROR ((0, 0, "%s:%ld: %s",
768 quotearg_colon (listed_incremental_option), lineno,
769 _("Invalid device number")));
770 else if (dev != u)
771 ERROR ((0, 0, "%s:%ld: %s",
772 quotearg_colon (listed_incremental_option), lineno,
773 _("Device number out of range")));
774 strp = ebuf;
775
776 errno = 0;
777 ino = u = strtoumax (strp, &ebuf, 10);
778 if (!isspace (*ebuf))
779 ERROR ((0, 0, "%s:%ld: %s",
780 quotearg_colon (listed_incremental_option), lineno,
781 _("Invalid inode number")));
782 else if (ino != u)
783 ERROR ((0, 0, "%s:%ld: %s",
784 quotearg_colon (listed_incremental_option), lineno,
785 _("Inode number out of range")));
786 strp = ebuf;
787
788 strp++;
789 unquote_string (strp);
790 note_directory (strp, mtime, dev, ino, nfs, false, NULL);
791 }
792 free (buf);
793 }
794
795 /* Read a nul-terminated string from FP and store it in STK.
796 Store the number of bytes read (including nul terminator) in PCOUNT.
797
798 Return the last character read or EOF on end of file. */
799 static int
800 read_obstack (FILE *fp, struct obstack *stk, size_t *pcount)
801 {
802 int c;
803 size_t i;
804
805 for (i = 0, c = getc (fp); c != EOF && c != 0; c = getc (fp), i++)
806 obstack_1grow (stk, c);
807 obstack_1grow (stk, 0);
808
809 *pcount = i;
810 return c;
811 }
812
813 /* Read from file FP a nul-terminated string and convert it to
814 uintmax_t. Return the resulting value in PVAL.
815
816 Throw fatal error if the string cannot be converted.
817
818 Return the last character read or EOF on end of file. */
819
820 static int
821 read_num (FILE *fp, uintmax_t *pval)
822 {
823 int c;
824 size_t i;
825 char buf[UINTMAX_STRSIZE_BOUND], *ep;
826
827 for (i = 0, c = getc (fp); c != EOF && c != 0; c = getc (fp), i++)
828 {
829 if (i == sizeof buf - 1)
830 FATAL_ERROR ((0, 0, _("Field too long while reading snapshot file")));
831 buf[i] = c;
832 }
833 buf[i] = 0;
834 *pval = strtoumax (buf, &ep, 10);
835 if (*ep)
836 FATAL_ERROR ((0, 0, _("Unexpected field value in snapshot file")));
837 return c;
838 }
839
840 /* Read incremental snapshot format 2 */
841 static void
842 read_incr_db_2 ()
843 {
844 uintmax_t u;
845 struct obstack stk;
846
847 obstack_init (&stk);
848
849 if (read_num (listed_incremental_stream, &u))
850 FATAL_ERROR ((0, 0, "%s: %s",
851 quotearg_colon (listed_incremental_option),
852 _("Error reading time stamp")));
853 newer_mtime_option.tv_sec = u;
854 if (newer_mtime_option.tv_sec != u)
855 FATAL_ERROR ((0, 0, "%s: %s",
856 quotearg_colon (listed_incremental_option),
857 _("Time stamp out of range")));
858
859 if (read_num (listed_incremental_stream, &u))
860 FATAL_ERROR ((0, 0, "%s: %s",
861 quotearg_colon (listed_incremental_option),
862 _("Error reading time stamp")));
863 newer_mtime_option.tv_nsec = u;
864 if (newer_mtime_option.tv_nsec != u)
865 FATAL_ERROR ((0, 0, "%s: %s",
866 quotearg_colon (listed_incremental_option),
867 _("Time stamp out of range")));
868
869 for (;;)
870 {
871 struct timespec mtime;
872 dev_t dev;
873 ino_t ino;
874 bool nfs;
875 char *name;
876 char *content;
877 size_t s;
878
879 if (read_num (listed_incremental_stream, &u))
880 return; /* Normal return */
881
882 nfs = u;
883
884 if (read_num (listed_incremental_stream, &u))
885 break;
886 mtime.tv_sec = u;
887 if (mtime.tv_sec != u)
888 FATAL_ERROR ((0, 0, "%s: %s",
889 quotearg_colon (listed_incremental_option),
890 _("Modification time (seconds) out of range")));
891
892 if (read_num (listed_incremental_stream, &u))
893 break;
894 mtime.tv_nsec = u;
895 if (mtime.tv_nsec != u)
896 FATAL_ERROR ((0, 0, "%s: %s",
897 quotearg_colon (listed_incremental_option),
898 _("Modification time (nanoseconds) out of range")));
899
900 if (read_num (listed_incremental_stream, &u))
901 break;
902 dev = u;
903 if (dev != u)
904 FATAL_ERROR ((0, 0, "%s: %s",
905 quotearg_colon (listed_incremental_option),
906 _("Device number out of range")));
907
908 if (read_num (listed_incremental_stream, &u))
909 break;
910 ino = u;
911 if (ino != u)
912 FATAL_ERROR ((0, 0, "%s: %s",
913 quotearg_colon (listed_incremental_option),
914 _("Inode number out of range")));
915
916 if (read_obstack (listed_incremental_stream, &stk, &s))
917 break;
918
919 name = obstack_finish (&stk);
920
921 while (read_obstack (listed_incremental_stream, &stk, &s) == 0 && s > 1)
922 ;
923 if (getc (listed_incremental_stream) != 0)
924 FATAL_ERROR ((0, 0, "%s: %s",
925 quotearg_colon (listed_incremental_option),
926 _("Missing record terminator")));
927
928 content = obstack_finish (&stk);
929 note_directory (name, mtime, dev, ino, nfs, false, content);
930 obstack_free (&stk, content);
931 }
932 FATAL_ERROR ((0, 0, "%s: %s",
933 quotearg_colon (listed_incremental_option),
934 _("Unexpected EOF")));
935 }
936
937 /* Read incremental snapshot file (directory file).
938 If the file has older incremental version, make sure that it is processed
939 correctly and that tar will use the most conservative backup method among
940 possible alternatives (i.e. prefer ALL_CHILDREN over CHANGED_CHILDREN,
941 etc.) This ensures that the snapshots are updated to the recent version
942 without any loss of data. */
943 void
944 read_directory_file (void)
945 {
946 int fd;
947 char *buf = 0;
948 size_t bufsize;
949 long lineno = 1;
950
951 /* Open the file for both read and write. That way, we can write
952 it later without having to reopen it, and don't have to worry if
953 we chdir in the meantime. */
954 fd = open (listed_incremental_option, O_RDWR | O_CREAT, MODE_RW);
955 if (fd < 0)
956 {
957 open_error (listed_incremental_option);
958 return;
959 }
960
961 listed_incremental_stream = fdopen (fd, "r+");
962 if (! listed_incremental_stream)
963 {
964 open_error (listed_incremental_option);
965 close (fd);
966 return;
967 }
968
969 if (0 < getline (&buf, &bufsize, listed_incremental_stream))
970 {
971 char *ebuf;
972 int incremental_version;
973
974 if (strncmp (buf, PACKAGE_NAME, sizeof PACKAGE_NAME - 1) == 0)
975 {
976 ebuf = buf + sizeof PACKAGE_NAME - 1;
977 if (*ebuf++ != '-')
978 ERROR((1, 0, _("Bad incremental file format")));
979 for (; *ebuf != '-'; ebuf++)
980 if (!*ebuf)
981 ERROR((1, 0, _("Bad incremental file format")));
982
983 incremental_version = (errno = 0, strtoumax (ebuf+1, &ebuf, 10));
984 }
985 else
986 incremental_version = 0;
987
988 switch (incremental_version)
989 {
990 case 0:
991 case 1:
992 read_incr_db_01 (incremental_version, buf);
993 break;
994
995 case TAR_INCREMENTAL_VERSION:
996 read_incr_db_2 ();
997 break;
998
999 default:
1000 ERROR ((1, 0, _("Unsupported incremental format version: %d"),
1001 incremental_version));
1002 }
1003
1004 }
1005
1006 if (ferror (listed_incremental_stream))
1007 read_error (listed_incremental_option);
1008 if (buf)
1009 free (buf);
1010 }
1011
1012 /* Output incremental data for the directory ENTRY to the file DATA.
1013 Return nonzero if successful, preserving errno on write failure. */
1014 static bool
1015 write_directory_file_entry (void *entry, void *data)
1016 {
1017 struct directory const *directory = entry;
1018 FILE *fp = data;
1019
1020 if (DIR_IS_FOUND (directory))
1021 {
1022 char buf[UINTMAX_STRSIZE_BOUND];
1023 char *s;
1024
1025 s = DIR_IS_NFS (directory) ? "1" : "0";
1026 fwrite (s, 2, 1, fp);
1027 s = umaxtostr (directory->mtime.tv_sec, buf);
1028 fwrite (s, strlen (s) + 1, 1, fp);
1029 s = umaxtostr (directory->mtime.tv_nsec, buf);
1030 fwrite (s, strlen (s) + 1, 1, fp);
1031 s = umaxtostr (directory->device_number, buf);
1032 fwrite (s, strlen (s) + 1, 1, fp);
1033 s = umaxtostr (directory->inode_number, buf);
1034 fwrite (s, strlen (s) + 1, 1, fp);
1035
1036 fwrite (directory->name, strlen (directory->name) + 1, 1, fp);
1037 if (directory->contents)
1038 {
1039 char *p;
1040 for (p = directory->contents; *p; p += strlen (p) + 1)
1041 {
1042 if (strchr ("YND", *p))
1043 fwrite (p, strlen (p) + 1, 1, fp);
1044 }
1045 }
1046 fwrite ("\0\0", 2, 1, fp);
1047 }
1048
1049 return ! ferror (fp);
1050 }
1051
1052 void
1053 write_directory_file (void)
1054 {
1055 FILE *fp = listed_incremental_stream;
1056 char buf[UINTMAX_STRSIZE_BOUND];
1057 char *s;
1058
1059 if (! fp)
1060 return;
1061
1062 if (fseek (fp, 0L, SEEK_SET) != 0)
1063 seek_error (listed_incremental_option);
1064 if (sys_truncate (fileno (fp)) != 0)
1065 truncate_error (listed_incremental_option);
1066
1067 fprintf (fp, "%s-%s-%d\n", PACKAGE_NAME, PACKAGE_VERSION,
1068 TAR_INCREMENTAL_VERSION);
1069
1070 s = umaxtostr (start_time.tv_sec, buf);
1071 fwrite (s, strlen (s) + 1, 1, fp);
1072 s = umaxtostr (start_time.tv_nsec, buf);
1073 fwrite (s, strlen (s) + 1, 1, fp);
1074
1075 if (! ferror (fp) && directory_table)
1076 hash_do_for_each (directory_table, write_directory_file_entry, fp);
1077
1078 if (ferror (fp))
1079 write_error (listed_incremental_option);
1080 if (fclose (fp) != 0)
1081 close_error (listed_incremental_option);
1082 }
1083
1084 \f
1085 /* Restoration of incremental dumps. */
1086
1087 static void
1088 get_gnu_dumpdir (struct tar_stat_info *stat_info)
1089 {
1090 size_t size;
1091 size_t copied;
1092 union block *data_block;
1093 char *to;
1094 char *archive_dir;
1095
1096 size = stat_info->stat.st_size;
1097
1098 archive_dir = xmalloc (size);
1099 to = archive_dir;
1100
1101 set_next_block_after (current_header);
1102 mv_begin (stat_info);
1103
1104 for (; size > 0; size -= copied)
1105 {
1106 mv_size_left (size);
1107 data_block = find_next_block ();
1108 if (!data_block)
1109 ERROR ((1, 0, _("Unexpected EOF in archive")));
1110 copied = available_space_after (data_block);
1111 if (copied > size)
1112 copied = size;
1113 memcpy (to, data_block->buffer, copied);
1114 to += copied;
1115 set_next_block_after ((union block *)
1116 (data_block->buffer + copied - 1));
1117 }
1118
1119 mv_end ();
1120
1121 stat_info->dumpdir = archive_dir;
1122 stat_info->skipped = true; /* For skip_member() and friends
1123 to work correctly */
1124 }
1125
1126 /* Return T if STAT_INFO represents a dumpdir archive member.
1127 Note: can invalidate current_header. It happens if flush_archive()
1128 gets called within get_gnu_dumpdir() */
1129 bool
1130 is_dumpdir (struct tar_stat_info *stat_info)
1131 {
1132 if (stat_info->is_dumpdir && !stat_info->dumpdir)
1133 get_gnu_dumpdir (stat_info);
1134 return stat_info->is_dumpdir;
1135 }
1136
1137 static bool
1138 dumpdir_ok (char *dumpdir)
1139 {
1140 char *p;
1141 int has_tempdir = 0;
1142 int expect = 0;
1143
1144 for (p = dumpdir; *p; p += strlen (p) + 1)
1145 {
1146 if (expect && *p != expect)
1147 {
1148 ERROR ((0, 0,
1149 _("Malformed dumpdir: expected '%c' but found %#3o"),
1150 expect, *p));
1151 return false;
1152 }
1153 switch (*p)
1154 {
1155 case 'X':
1156 if (has_tempdir)
1157 {
1158 ERROR ((0, 0,
1159 _("Malformed dumpdir: 'X' duplicated")));
1160 return false;
1161 }
1162 else
1163 has_tempdir = 1;
1164 break;
1165
1166 case 'R':
1167 if (p[1] == 0)
1168 {
1169 if (!has_tempdir)
1170 {
1171 ERROR ((0, 0,
1172 _("Malformed dumpdir: empty name in 'R'")));
1173 return false;
1174 }
1175 else
1176 has_tempdir = 0;
1177 }
1178 expect = 'T';
1179 break;
1180
1181 case 'T':
1182 if (expect != 'T')
1183 {
1184 ERROR ((0, 0,
1185 _("Malformed dumpdir: 'T' not preceeded by 'R'")));
1186 return false;
1187 }
1188 if (p[1] == 0 && !has_tempdir)
1189 {
1190 ERROR ((0, 0,
1191 _("Malformed dumpdir: empty name in 'T'")));
1192 return false;
1193 }
1194 expect = 0;
1195 break;
1196
1197 case 'N':
1198 case 'Y':
1199 case 'D':
1200 break;
1201
1202 default:
1203 /* FIXME: bail out? */
1204 break;
1205 }
1206 }
1207
1208 if (expect)
1209 {
1210 ERROR ((0, 0,
1211 _("Malformed dumpdir: expected '%c' but found end of data"),
1212 expect));
1213 return false;
1214 }
1215
1216 if (has_tempdir)
1217 WARN ((0, 0, _("Malformed dumpdir: 'X' never used")));
1218
1219 return true;
1220 }
1221
1222 /* Examine the directories under directory_name and delete any
1223 files that were not there at the time of the back-up. */
1224 static bool
1225 try_purge_directory (char const *directory_name)
1226 {
1227 char *current_dir;
1228 char *cur, *arc, *p;
1229 char *temp_stub = NULL;
1230
1231 if (!is_dumpdir (&current_stat_info))
1232 return false;
1233
1234 current_dir = savedir (directory_name);
1235
1236 if (!current_dir)
1237 /* The directory doesn't exist now. It'll be created. In any
1238 case, we don't have to delete any files out of it. */
1239 return false;
1240
1241 /* Verify if dump directory is sane */
1242 if (!dumpdir_ok (current_stat_info.dumpdir))
1243 return false;
1244
1245 /* Process renames */
1246 for (arc = current_stat_info.dumpdir; *arc; arc += strlen (arc) + 1)
1247 {
1248 if (*arc == 'X')
1249 {
1250 #define TEMP_DIR_TEMPLATE "tar.XXXXXX"
1251 size_t len = strlen (arc + 1);
1252 temp_stub = xrealloc (temp_stub, len + 1 + sizeof TEMP_DIR_TEMPLATE);
1253 memcpy (temp_stub, arc + 1, len);
1254 temp_stub[len] = '/';
1255 memcpy (temp_stub + len + 1, TEMP_DIR_TEMPLATE,
1256 sizeof TEMP_DIR_TEMPLATE);
1257 if (!mkdtemp (temp_stub))
1258 {
1259 ERROR ((0, errno,
1260 _("Cannot create temporary directory using template %s"),
1261 quote (temp_stub)));
1262 free (temp_stub);
1263 free (current_dir);
1264 return false;
1265 }
1266 }
1267 else if (*arc == 'R')
1268 {
1269 char *src, *dst;
1270 src = arc + 1;
1271 arc += strlen (arc) + 1;
1272 dst = arc + 1;
1273
1274 if (*src == 0)
1275 src = temp_stub;
1276 else if (*dst == 0)
1277 dst = temp_stub;
1278
1279 if (!rename_directory (src, dst))
1280 {
1281 free (temp_stub);
1282 free (current_dir);
1283 /* FIXME: Make sure purge_directory(dst) will return
1284 immediately */
1285 return false;
1286 }
1287 }
1288 }
1289
1290 free (temp_stub);
1291
1292 /* Process deletes */
1293 p = NULL;
1294 for (cur = current_dir; *cur; cur += strlen (cur) + 1)
1295 {
1296 const char *entry;
1297 struct stat st;
1298 if (p)
1299 free (p);
1300 p = new_name (directory_name, cur);
1301
1302 if (!(entry = dumpdir_locate (current_stat_info.dumpdir, cur))
1303 || (*entry == 'D' && S_ISDIR (st.st_mode))
1304 || (*entry == 'Y' && !S_ISDIR (st.st_mode)))
1305 {
1306 if (deref_stat (false, p, &st))
1307 {
1308 if (errno != ENOENT) /* FIXME: Maybe keep a list of renamed
1309 dirs and check it here? */
1310 {
1311 stat_diag (p);
1312 WARN ((0, 0, _("%s: Not purging directory: unable to stat"),
1313 quotearg_colon (p)));
1314 }
1315 continue;
1316 }
1317 else if (one_file_system_option && st.st_dev != root_device)
1318 {
1319 WARN ((0, 0,
1320 _("%s: directory is on a different device: not purging"),
1321 quotearg_colon (p)));
1322 continue;
1323 }
1324
1325 if (! interactive_option || confirm ("delete", p))
1326 {
1327 if (verbose_option)
1328 fprintf (stdlis, _("%s: Deleting %s\n"),
1329 program_name, quote (p));
1330 if (! remove_any_file (p, RECURSIVE_REMOVE_OPTION))
1331 {
1332 int e = errno;
1333 ERROR ((0, e, _("%s: Cannot remove"), quotearg_colon (p)));
1334 }
1335 }
1336 }
1337 }
1338 free (p);
1339
1340 free (current_dir);
1341 return true;
1342 }
1343
1344 void
1345 purge_directory (char const *directory_name)
1346 {
1347 if (!try_purge_directory (directory_name))
1348 skip_member ();
1349 }
1350
1351 void
1352 list_dumpdir (char *buffer, size_t size)
1353 {
1354 while (size)
1355 {
1356 switch (*buffer)
1357 {
1358 case 'Y':
1359 case 'N':
1360 case 'D':
1361 case 'R':
1362 case 'T':
1363 case 'X':
1364 fprintf (stdlis, "%c ", *buffer);
1365 buffer++;
1366 size--;
1367 break;
1368
1369 case 0:
1370 fputc ('\n', stdlis);
1371 buffer++;
1372 size--;
1373 break;
1374
1375 default:
1376 fputc (*buffer, stdlis);
1377 buffer++;
1378 size--;
1379 }
1380 }
1381 }
This page took 0.092132 seconds and 5 git commands to generate.