]> Dogcows Code - chaz/tar/blob - src/incremen.c
If --one-file-system is given and a
[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 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 {NO_CHILDREN, CHANGED_CHILDREN, ALL_CHILDREN};
30
31 /* Directory attributes. */
32 struct directory
33 {
34 struct timespec mtime; /* Modification time */
35 dev_t device_number; /* device number for directory */
36 ino_t inode_number; /* inode number for directory */
37 enum children children;
38 bool nfs;
39 bool found;
40 char name[1]; /* file name of directory */
41 };
42
43 static Hash_table *directory_table;
44
45 #if HAVE_ST_FSTYPE_STRING
46 static char const nfs_string[] = "nfs";
47 # define NFS_FILE_STAT(st) (strcmp ((st).st_fstype, nfs_string) == 0)
48 #else
49 # define ST_DEV_MSB(st) (~ (dev_t) 0 << (sizeof (st).st_dev * CHAR_BIT - 1))
50 # define NFS_FILE_STAT(st) (((st).st_dev & ST_DEV_MSB (st)) != 0)
51 #endif
52
53 /* Calculate the hash of a directory. */
54 static size_t
55 hash_directory (void const *entry, size_t n_buckets)
56 {
57 struct directory const *directory = entry;
58 return hash_string (directory->name, n_buckets);
59 }
60
61 /* Compare two directories for equality. */
62 static bool
63 compare_directories (void const *entry1, void const *entry2)
64 {
65 struct directory const *directory1 = entry1;
66 struct directory const *directory2 = entry2;
67 return strcmp (directory1->name, directory2->name) == 0;
68 }
69
70 /* Create and link a new directory entry for directory NAME, having a
71 device number DEV and an inode number INO, with NFS indicating
72 whether it is an NFS device and FOUND indicating whether we have
73 found that the directory exists. */
74 static struct directory *
75 note_directory (char const *name, struct timespec mtime,
76 dev_t dev, ino_t ino, bool nfs, bool found)
77 {
78 size_t size = offsetof (struct directory, name) + strlen (name) + 1;
79 struct directory *directory = xmalloc (size);
80
81 directory->mtime = mtime;
82 directory->device_number = dev;
83 directory->inode_number = ino;
84 directory->children = CHANGED_CHILDREN;
85 directory->nfs = nfs;
86 directory->found = found;
87 strcpy (directory->name, name);
88
89 if (! ((directory_table
90 || (directory_table = hash_initialize (0, 0, hash_directory,
91 compare_directories, 0)))
92 && hash_insert (directory_table, directory)))
93 xalloc_die ();
94
95 return directory;
96 }
97
98 /* Return a directory entry for a given file NAME, or zero if none found. */
99 static struct directory *
100 find_directory (char *name)
101 {
102 if (! directory_table)
103 return 0;
104 else
105 {
106 size_t size = offsetof (struct directory, name) + strlen (name) + 1;
107 struct directory *dir = alloca (size);
108 strcpy (dir->name, name);
109 return hash_lookup (directory_table, dir);
110 }
111 }
112
113 void
114 update_parent_directory (const char *name)
115 {
116 struct directory *directory;
117 char *p, *name_buffer;
118
119 p = dir_name (name);
120 name_buffer = xmalloc (strlen (p) + 2);
121 strcpy (name_buffer, p);
122 if (! ISSLASH (p[strlen (p) - 1]))
123 strcat (name_buffer, "/");
124
125 directory = find_directory (name_buffer);
126 free (name_buffer);
127 if (directory)
128 {
129 struct stat st;
130 if (deref_stat (dereference_option, p, &st) != 0)
131 stat_diag (name);
132 else
133 directory->mtime = get_stat_mtime (&st);
134 }
135 free (p);
136 }
137
138 static int
139 compare_dirents (const void *first, const void *second)
140 {
141 return strcmp ((*(char *const *) first) + 1,
142 (*(char *const *) second) + 1);
143 }
144
145 enum children
146 procdir (char *name_buffer, struct stat *stat_data,
147 dev_t device,
148 enum children children,
149 bool verbose)
150 {
151 struct directory *directory;
152 bool nfs = NFS_FILE_STAT (*stat_data);
153
154 if ((directory = find_directory (name_buffer)) != NULL)
155 {
156 /* With NFS, the same file can have two different devices
157 if an NFS directory is mounted in multiple locations,
158 which is relatively common when automounting.
159 To avoid spurious incremental redumping of
160 directories, consider all NFS devices as equal,
161 relying on the i-node to establish differences. */
162
163 if (! (((directory->nfs & nfs)
164 || directory->device_number == stat_data->st_dev)
165 && directory->inode_number == stat_data->st_ino))
166 {
167 if (verbose)
168 WARN ((0, 0, _("%s: Directory has been renamed"),
169 quotearg_colon (name_buffer)));
170 directory->children = ALL_CHILDREN;
171 directory->nfs = nfs;
172 directory->device_number = stat_data->st_dev;
173 directory->inode_number = stat_data->st_ino;
174 }
175 else if (listed_incremental_option)
176 /* Newer modification time can mean that new files were
177 created in the directory or some of the existing files
178 were renamed. */
179 directory->children =
180 timespec_cmp (get_stat_mtime (stat_data), directory->mtime) > 0
181 ? ALL_CHILDREN : CHANGED_CHILDREN;
182
183 directory->found = true;
184 }
185 else
186 {
187 if (verbose)
188 WARN ((0, 0, _("%s: Directory is new"),
189 quotearg_colon (name_buffer)));
190 directory = note_directory (name_buffer,
191 get_stat_mtime(stat_data),
192 stat_data->st_dev,
193 stat_data->st_ino,
194 nfs,
195 true);
196
197 directory->children =
198 (listed_incremental_option
199 || (OLDER_STAT_TIME (*stat_data, m)
200 || (after_date_option
201 && OLDER_STAT_TIME (*stat_data, c))))
202 ? ALL_CHILDREN
203 : CHANGED_CHILDREN;
204 }
205
206 /* If the directory is on another device and --one-file-system was given,
207 omit it... */
208 if (one_file_system_option && device != stat_data->st_dev
209 /* ... except if it was explicitely given in the command line */
210 && !name_scan (name_buffer))
211 directory->children = NO_CHILDREN;
212 else if (children == ALL_CHILDREN)
213 directory->children = ALL_CHILDREN;
214
215 return directory->children;
216 }
217
218
219 /* Recursively scan the given directory. */
220 static void
221 scan_directory (struct obstack *stk, char *dir_name, dev_t device)
222 {
223 char *dirp = savedir (dir_name); /* for scanning directory */
224 char const *entry; /* directory entry being scanned */
225 size_t entrylen; /* length of directory entry */
226 char *name_buffer; /* directory, `/', and directory member */
227 size_t name_buffer_size; /* allocated size of name_buffer, minus 2 */
228 size_t name_length; /* used length in name_buffer */
229 enum children children;
230 struct stat stat_data;
231
232 if (! dirp)
233 savedir_error (dir_name);
234
235 name_buffer_size = strlen (dir_name) + NAME_FIELD_SIZE;
236 name_buffer = xmalloc (name_buffer_size + 2);
237 strcpy (name_buffer, dir_name);
238 if (! ISSLASH (dir_name[strlen (dir_name) - 1]))
239 strcat (name_buffer, "/");
240 name_length = strlen (name_buffer);
241
242 if (deref_stat (dereference_option, name_buffer, &stat_data))
243 {
244 stat_diag (name_buffer);
245 children = CHANGED_CHILDREN;
246 }
247 else
248 children = procdir (name_buffer, &stat_data, device, NO_CHILDREN, false);
249
250 if (dirp && children != NO_CHILDREN)
251 for (entry = dirp;
252 (entrylen = strlen (entry)) != 0;
253 entry += entrylen + 1)
254 {
255 if (name_buffer_size <= entrylen + name_length)
256 {
257 do
258 name_buffer_size += NAME_FIELD_SIZE;
259 while (name_buffer_size <= entrylen + name_length);
260 name_buffer = xrealloc (name_buffer, name_buffer_size + 2);
261 }
262 strcpy (name_buffer + name_length, entry);
263
264 if (excluded_name (name_buffer))
265 obstack_1grow (stk, 'N');
266 else
267 {
268
269 if (deref_stat (dereference_option, name_buffer, &stat_data))
270 {
271 stat_diag (name_buffer);
272 continue;
273 }
274
275 if (S_ISDIR (stat_data.st_mode))
276 {
277 procdir (name_buffer, &stat_data, device, children,
278 verbose_option);
279 obstack_1grow (stk, 'D');
280 }
281
282 else if (one_file_system_option && device != stat_data.st_dev)
283 obstack_1grow (stk, 'N');
284
285 #ifdef S_ISHIDDEN
286 else if (S_ISHIDDEN (stat_data.st_mode))
287 {
288 obstack_1grow (stk, 'D');
289 obstack_grow (stk, entry, entrylen);
290 obstack_grow (stk, "A", 2);
291 continue;
292 }
293 #endif
294
295 else
296 if (children == CHANGED_CHILDREN
297 && OLDER_STAT_TIME (stat_data, m)
298 && (!after_date_option || OLDER_STAT_TIME (stat_data, c)))
299 obstack_1grow (stk, 'N');
300 else
301 obstack_1grow (stk, 'Y');
302 }
303
304 obstack_grow (stk, entry, entrylen + 1);
305 }
306
307 obstack_grow (stk, "\000\000", 2);
308
309 free (name_buffer);
310 if (dirp)
311 free (dirp);
312 }
313
314 /* Sort the contents of the obstack, and convert it to the char * */
315 static char *
316 sort_obstack (struct obstack *stk)
317 {
318 char *pointer = obstack_finish (stk);
319 size_t counter;
320 char *cursor;
321 char *buffer;
322 char **array;
323 char **array_cursor;
324
325 counter = 0;
326 for (cursor = pointer; *cursor; cursor += strlen (cursor) + 1)
327 counter++;
328
329 if (!counter)
330 return NULL;
331
332 array = obstack_alloc (stk, sizeof (char *) * (counter + 1));
333
334 array_cursor = array;
335 for (cursor = pointer; *cursor; cursor += strlen (cursor) + 1)
336 *array_cursor++ = cursor;
337 *array_cursor = 0;
338
339 qsort (array, counter, sizeof (char *), compare_dirents);
340
341 buffer = xmalloc (cursor - pointer + 2);
342
343 cursor = buffer;
344 for (array_cursor = array; *array_cursor; array_cursor++)
345 {
346 char *string = *array_cursor;
347
348 while ((*cursor++ = *string++))
349 continue;
350 }
351 *cursor = '\0';
352 return buffer;
353 }
354
355 char *
356 get_directory_contents (char *dir_name, dev_t device)
357 {
358 struct obstack stk;
359 char *buffer;
360
361 obstack_init (&stk);
362 scan_directory (&stk, dir_name, device);
363 buffer = sort_obstack (&stk);
364 obstack_free (&stk, NULL);
365 return buffer;
366 }
367
368 size_t
369 dumpdir_size (const char *p)
370 {
371 size_t totsize = 0;
372
373 while (*p)
374 {
375 size_t size = strlen (p) + 1;
376 totsize += size;
377 p += size;
378 }
379 return totsize + 1;
380 }
381
382 \f
383
384 static FILE *listed_incremental_stream;
385
386 /* Version of incremental format snapshots (directory files) used by this
387 tar. Currently it is supposed to be a single decimal number. 0 means
388 incremental snapshots as per tar version before 1.15.2.
389
390 The current tar version supports incremental versions from
391 0 up to TAR_INCREMENTAL_VERSION, inclusive.
392 It is able to create only snapshots of TAR_INCREMENTAL_VERSION */
393
394 #define TAR_INCREMENTAL_VERSION 1
395
396 /* Read incremental snapshot file (directory file).
397 If the file has older incremental version, make sure that it is processed
398 correctly and that tar will use the most conservative backup method among
399 possible alternatives (i.e. prefer ALL_CHILDREN over CHANGED_CHILDREN,
400 etc.) This ensures that the snapshots are updated to the recent version
401 without any loss of data. */
402 void
403 read_directory_file (void)
404 {
405 int fd;
406 FILE *fp;
407 char *buf = 0;
408 size_t bufsize;
409
410 /* Open the file for both read and write. That way, we can write
411 it later without having to reopen it, and don't have to worry if
412 we chdir in the meantime. */
413 fd = open (listed_incremental_option, O_RDWR | O_CREAT, MODE_RW);
414 if (fd < 0)
415 {
416 open_error (listed_incremental_option);
417 return;
418 }
419
420 fp = fdopen (fd, "r+");
421 if (! fp)
422 {
423 open_error (listed_incremental_option);
424 close (fd);
425 return;
426 }
427
428 listed_incremental_stream = fp;
429
430 if (0 < getline (&buf, &bufsize, fp))
431 {
432 char *ebuf;
433 int n;
434 long lineno = 1;
435 uintmax_t u;
436 time_t t = u;
437 int incremental_version;
438
439 if (strncmp (buf, PACKAGE_NAME, sizeof PACKAGE_NAME - 1) == 0)
440 {
441 ebuf = buf + sizeof PACKAGE_NAME - 1;
442 if (*ebuf++ != '-')
443 ERROR((1, 0, _("Bad incremental file format")));
444 for (; *ebuf != '-'; ebuf++)
445 if (!*ebuf)
446 ERROR((1, 0, _("Bad incremental file format")));
447
448 incremental_version = (errno = 0, strtoumax (ebuf+1, &ebuf, 10));
449 if (getline (&buf, &bufsize, fp) <= 0)
450 {
451 read_error (listed_incremental_option);
452 free (buf);
453 return;
454 }
455 ++lineno;
456 }
457 else
458 incremental_version = 0;
459
460 if (incremental_version > TAR_INCREMENTAL_VERSION)
461 ERROR((1, 0, _("Unsupported incremental format version: %d"),
462 incremental_version));
463
464 t = u = (errno = 0, strtoumax (buf, &ebuf, 10));
465 if (buf == ebuf || (u == 0 && errno == EINVAL))
466 ERROR ((0, 0, "%s:%ld: %s",
467 quotearg_colon (listed_incremental_option),
468 lineno,
469 _("Invalid time stamp")));
470 else if (t != u)
471 ERROR ((0, 0, "%s:%ld: %s",
472 quotearg_colon (listed_incremental_option),
473 lineno,
474 _("Time stamp out of range")));
475 else if (incremental_version == 1)
476 {
477 newer_mtime_option.tv_sec = t;
478
479 t = u = (errno = 0, strtoumax (buf, &ebuf, 10));
480 if (buf == ebuf || (u == 0 && errno == EINVAL))
481 ERROR ((0, 0, "%s:%ld: %s",
482 quotearg_colon (listed_incremental_option),
483 lineno,
484 _("Invalid time stamp")));
485 else if (t != u)
486 ERROR ((0, 0, "%s:%ld: %s",
487 quotearg_colon (listed_incremental_option),
488 lineno,
489 _("Time stamp out of range")));
490 newer_mtime_option.tv_nsec = t;
491 }
492 else
493 {
494 /* pre-1 incremental format does not contain nanoseconds */
495 newer_mtime_option.tv_sec = t;
496 newer_mtime_option.tv_nsec = 0;
497 }
498
499 while (0 < (n = getline (&buf, &bufsize, fp)))
500 {
501 dev_t dev;
502 ino_t ino;
503 bool nfs = buf[0] == '+';
504 char *strp = buf + nfs;
505 struct timespec mtime;
506
507 lineno++;
508
509 if (buf[n - 1] == '\n')
510 buf[n - 1] = '\0';
511
512 if (incremental_version == 1)
513 {
514 errno = 0;
515 mtime.tv_sec = u = strtoumax (strp, &ebuf, 10);
516 if (!isspace (*ebuf))
517 ERROR ((0, 0, "%s:%ld: %s",
518 quotearg_colon (listed_incremental_option), lineno,
519 _("Invalid modification time (seconds)")));
520 else if (mtime.tv_sec != u)
521 ERROR ((0, 0, "%s:%ld: %s",
522 quotearg_colon (listed_incremental_option), lineno,
523 _("Modification time (seconds) out of range")));
524 strp = ebuf;
525
526 errno = 0;
527 mtime.tv_nsec = u = strtoumax (strp, &ebuf, 10);
528 if (!isspace (*ebuf))
529 ERROR ((0, 0, "%s:%ld: %s",
530 quotearg_colon (listed_incremental_option), lineno,
531 _("Invalid modification time (nanoseconds)")));
532 else if (mtime.tv_nsec != u)
533 ERROR ((0, 0, "%s:%ld: %s",
534 quotearg_colon (listed_incremental_option), lineno,
535 _("Modification time (nanoseconds) out of range")));
536 strp = ebuf;
537 }
538 else
539 memset (&mtime, 0, sizeof mtime);
540
541 errno = 0;
542 dev = u = strtoumax (strp, &ebuf, 10);
543 if (!isspace (*ebuf))
544 ERROR ((0, 0, "%s:%ld: %s",
545 quotearg_colon (listed_incremental_option), lineno,
546 _("Invalid device number")));
547 else if (dev != u)
548 ERROR ((0, 0, "%s:%ld: %s",
549 quotearg_colon (listed_incremental_option), lineno,
550 _("Device number out of range")));
551 strp = ebuf;
552
553 errno = 0;
554 ino = u = strtoumax (strp, &ebuf, 10);
555 if (!isspace (*ebuf))
556 ERROR ((0, 0, "%s:%ld: %s",
557 quotearg_colon (listed_incremental_option), lineno,
558 _("Invalid inode number")));
559 else if (ino != u)
560 ERROR ((0, 0, "%s:%ld: %s",
561 quotearg_colon (listed_incremental_option), lineno,
562 _("Inode number out of range")));
563 strp = ebuf;
564
565 strp++;
566 unquote_string (strp);
567 note_directory (strp, mtime, dev, ino, nfs, 0);
568 }
569 }
570
571 if (ferror (fp))
572 read_error (listed_incremental_option);
573 if (buf)
574 free (buf);
575 }
576
577 /* Output incremental data for the directory ENTRY to the file DATA.
578 Return nonzero if successful, preserving errno on write failure. */
579 static bool
580 write_directory_file_entry (void *entry, void *data)
581 {
582 struct directory const *directory = entry;
583 FILE *fp = data;
584
585 if (directory->found)
586 {
587 int e;
588 char buf[UINTMAX_STRSIZE_BOUND];
589 char *str = quote_copy_string (directory->name);
590
591 if (directory->nfs)
592 fprintf (fp, "+");
593 fprintf (fp, "%s ", umaxtostr (directory->mtime.tv_sec, buf));
594 fprintf (fp, "%s ", umaxtostr (directory->mtime.tv_nsec, buf));
595 fprintf (fp, "%s ", umaxtostr (directory->device_number, buf));
596 fprintf (fp, "%s ", umaxtostr (directory->inode_number, buf));
597 fprintf (fp, "%s\n", str ? str : directory->name);
598
599 e = errno;
600 if (str)
601 free (str);
602 errno = e;
603 }
604
605 return ! ferror (fp);
606 }
607
608 void
609 write_directory_file (void)
610 {
611 FILE *fp = listed_incremental_stream;
612
613 if (! fp)
614 return;
615
616 if (fseek (fp, 0L, SEEK_SET) != 0)
617 seek_error (listed_incremental_option);
618 if (sys_truncate (fileno (fp)) != 0)
619 truncate_error (listed_incremental_option);
620
621 fprintf (fp, "%s-%s-%d\n", PACKAGE_NAME, PACKAGE_VERSION,
622 TAR_INCREMENTAL_VERSION);
623
624 fprintf (fp, "%lu %lu\n",
625 (unsigned long int) start_time.tv_sec,
626 (unsigned long int) start_time.tv_nsec);
627 if (! ferror (fp) && directory_table)
628 hash_do_for_each (directory_table, write_directory_file_entry, fp);
629 if (ferror (fp))
630 write_error (listed_incremental_option);
631 if (fclose (fp) != 0)
632 close_error (listed_incremental_option);
633 }
634
635 \f
636 /* Restoration of incremental dumps. */
637
638 void
639 get_gnu_dumpdir ()
640 {
641 size_t size;
642 size_t copied;
643 union block *data_block;
644 char *to;
645 char *archive_dir;
646
647 size = current_stat_info.stat.st_size;
648 if (size != current_stat_info.stat.st_size)
649 xalloc_die ();
650
651 archive_dir = xmalloc (size);
652 to = archive_dir;
653
654 set_next_block_after (current_header);
655 mv_begin (&current_stat_info);
656
657 for (; size > 0; size -= copied)
658 {
659 mv_size_left (size);
660 data_block = find_next_block ();
661 if (!data_block)
662 ERROR ((1, 0, _("Unexpected EOF in archive")));
663 copied = available_space_after (data_block);
664 if (copied > size)
665 copied = size;
666 memcpy (to, data_block->buffer, copied);
667 to += copied;
668 set_next_block_after ((union block *)
669 (data_block->buffer + copied - 1));
670 }
671
672 mv_end ();
673
674 current_stat_info.stat.st_size = 0; /* For skip_member() and friends
675 to work correctly */
676 current_stat_info.dumpdir = archive_dir;
677 }
678
679
680 /* Examine the directories under directory_name and delete any
681 files that were not there at the time of the back-up. */
682 void
683 purge_directory (char const *directory_name)
684 {
685 char *current_dir;
686 char *cur, *arc;
687
688 if (!current_stat_info.dumpdir)
689 {
690 skip_member ();
691 return;
692 }
693
694 current_dir = savedir (directory_name);
695
696 if (!current_dir)
697 {
698 /* The directory doesn't exist now. It'll be created. In any
699 case, we don't have to delete any files out of it. */
700
701 skip_member ();
702 return;
703 }
704
705 for (cur = current_dir; *cur; cur += strlen (cur) + 1)
706 {
707 for (arc = current_stat_info.dumpdir; *arc; arc += strlen (arc) + 1)
708 {
709 arc++;
710 if (!strcmp (arc, cur))
711 break;
712 }
713 if (*arc == '\0')
714 {
715 struct stat st;
716 char *p = new_name (directory_name, cur);
717
718 if (deref_stat (false, p, &st))
719 {
720 stat_diag (p);
721 WARN((0, 0, _("%s: Not purging directory: unable to stat"),
722 quotearg_colon (p)));
723 continue;
724 }
725 else if (one_file_system_option && st.st_dev != root_device)
726 {
727 WARN((0, 0,
728 _("%s: directory is on a different device: not purging"),
729 quotearg_colon (p)));
730 continue;
731 }
732
733 if (! interactive_option || confirm ("delete", p))
734 {
735 if (verbose_option)
736 fprintf (stdlis, _("%s: Deleting %s\n"),
737 program_name, quote (p));
738 if (! remove_any_file (p, RECURSIVE_REMOVE_OPTION))
739 {
740 int e = errno;
741 ERROR ((0, e, _("%s: Cannot remove"), quotearg_colon (p)));
742 }
743 }
744 free (p);
745 }
746
747 }
748 free (current_dir);
749 }
750
751 void
752 list_dumpdir (char *buffer, size_t size)
753 {
754 while (size)
755 {
756 switch (*buffer)
757 {
758 case 'Y':
759 case 'N':
760 case 'D':
761 fprintf (stdlis, "%c ", *buffer);
762 buffer++;
763 size--;
764 break;
765
766 case 0:
767 fputc ('\n', stdlis);
768 buffer++;
769 size--;
770 break;
771
772 default:
773 fputc (*buffer, stdlis);
774 buffer++;
775 size--;
776 }
777 }
778 }
This page took 0.065664 seconds and 5 git commands to generate.