1 /* GNU dump extensions to tar.
3 Copyright 1988, 1992, 1993, 1994, 1996, 1997, 1999, 2000, 2001 Free
4 Software Foundation, Inc.
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
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.
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 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
26 /* Variable sized generic character buffers. */
35 /* Amount of space guaranteed just after a reallocation. */
36 #define ACCUMULATOR_SLACK 50
38 /* Return the accumulated data from an ACCUMULATOR buffer. */
40 get_accumulator (struct accumulator *accumulator)
42 return accumulator->pointer;
45 /* Allocate and return a new accumulator buffer. */
46 static struct accumulator *
47 new_accumulator (void)
49 struct accumulator *accumulator
50 = xmalloc (sizeof (struct accumulator));
52 accumulator->allocated = ACCUMULATOR_SLACK;
53 accumulator->pointer = xmalloc (ACCUMULATOR_SLACK);
54 accumulator->length = 0;
58 /* Deallocate an ACCUMULATOR buffer. */
60 delete_accumulator (struct accumulator *accumulator)
62 free (accumulator->pointer);
66 /* At the end of an ACCUMULATOR buffer, add a DATA block of SIZE bytes. */
68 add_to_accumulator (struct accumulator *accumulator,
69 const char *data, size_t size)
71 if (accumulator->length + size > accumulator->allocated)
73 accumulator->allocated = accumulator->length + size + ACCUMULATOR_SLACK;
74 accumulator->pointer =
75 xrealloc (accumulator->pointer, accumulator->allocated);
77 memcpy (accumulator->pointer + accumulator->length, data, size);
78 accumulator->length += size;
81 /* Incremental dump specialities. */
83 /* Which child files to save under a directory. */
84 enum children {NO_CHILDREN, CHANGED_CHILDREN, ALL_CHILDREN};
86 /* Directory attributes. */
89 dev_t device_number; /* device number for directory */
90 ino_t inode_number; /* inode number for directory */
91 enum children children;
94 char name[1]; /* path name of directory */
97 static Hash_table *directory_table;
99 #if HAVE_ST_FSTYPE_STRING
100 static char const nfs_string[] = "nfs";
101 # define NFS_FILE_STAT(st) (strcmp ((st).st_fstype, nfs_string) == 0)
103 # define ST_DEV_MSB(st) (~ (dev_t) 0 << (sizeof (st).st_dev * CHAR_BIT - 1))
104 # define NFS_FILE_STAT(st) (((st).st_dev & ST_DEV_MSB (st)) != 0)
107 /* Calculate the hash of a directory. */
109 hash_directory (void const *entry, unsigned n_buckets)
111 struct directory const *directory = entry;
112 return hash_string (directory->name, n_buckets);
115 /* Compare two directories for equality. */
117 compare_directories (void const *entry1, void const *entry2)
119 struct directory const *directory1 = entry1;
120 struct directory const *directory2 = entry2;
121 return strcmp (directory1->name, directory2->name) == 0;
124 /* Create and link a new directory entry for directory NAME, having a
125 device number DEV and an inode number INO, with NFS indicating
126 whether it is an NFS device and FOUND indicating whether we have
127 found that the directory exists. */
128 static struct directory *
129 note_directory (char const *name, dev_t dev, ino_t ino, bool nfs, bool found)
131 size_t size = offsetof (struct directory, name) + strlen (name) + 1;
132 struct directory *directory = xmalloc (size);
134 directory->device_number = dev;
135 directory->inode_number = ino;
136 directory->children = CHANGED_CHILDREN;
137 directory->nfs = nfs;
138 directory->found = found;
139 strcpy (directory->name, name);
141 if (! ((directory_table
142 || (directory_table = hash_initialize (0, 0, hash_directory,
143 compare_directories, 0)))
144 && hash_insert (directory_table, directory)))
150 /* Return a directory entry for a given path NAME, or zero if none found. */
151 static struct directory *
152 find_directory (char *name)
154 if (! directory_table)
158 size_t size = offsetof (struct directory, name) + strlen (name) + 1;
159 struct directory *dir = alloca (size);
160 strcpy (dir->name, name);
161 return hash_lookup (directory_table, dir);
166 compare_dirents (const void *first, const void *second)
168 return strcmp ((*(char *const *) first) + 1,
169 (*(char *const *) second) + 1);
173 get_directory_contents (char *path, dev_t device)
175 struct accumulator *accumulator;
177 /* Recursively scan the given PATH. */
180 char *dirp = savedir (path); /* for scanning directory */
181 char const *entry; /* directory entry being scanned */
182 size_t entrylen; /* length of directory entry */
183 char *name_buffer; /* directory, `/', and directory member */
184 size_t name_buffer_size; /* allocated size of name_buffer, minus 2 */
185 size_t name_length; /* used length in name_buffer */
186 struct directory *directory; /* for checking if already already seen */
187 enum children children;
190 savedir_error (path);
193 name_buffer_size = strlen (path) + NAME_FIELD_SIZE;
194 name_buffer = xmalloc (name_buffer_size + 2);
195 strcpy (name_buffer, path);
196 if (! ISSLASH (path[strlen (path) - 1]))
197 strcat (name_buffer, "/");
198 name_length = strlen (name_buffer);
200 directory = find_directory (path);
201 children = directory ? directory->children : CHANGED_CHILDREN;
203 accumulator = new_accumulator ();
205 if (children != NO_CHILDREN)
207 (entrylen = strlen (entry)) != 0;
208 entry += entrylen + 1)
210 if (name_buffer_size <= entrylen + name_length)
213 name_buffer_size += NAME_FIELD_SIZE;
214 while (name_buffer_size <= entrylen + name_length);
215 name_buffer = xrealloc (name_buffer, name_buffer_size + 2);
217 strcpy (name_buffer + name_length, entry);
219 if (excluded_name (name_buffer))
220 add_to_accumulator (accumulator, "N", 1);
223 struct stat stat_data;
225 if (deref_stat (dereference_option, name_buffer, &stat_data))
227 if (ignore_failed_read_option)
228 stat_warn (name_buffer);
230 stat_error (name_buffer);
234 if (S_ISDIR (stat_data.st_mode))
236 bool nfs = NFS_FILE_STAT (stat_data);
238 if (directory = find_directory (name_buffer), directory)
240 /* With NFS, the same file can have two different devices
241 if an NFS directory is mounted in multiple locations,
242 which is relatively common when automounting.
243 To avoid spurious incremental redumping of
244 directories, consider all NFS devices as equal,
245 relying on the i-node to establish differences. */
247 if (! (((directory->nfs & nfs)
248 || directory->device_number == stat_data.st_dev)
249 && directory->inode_number == stat_data.st_ino))
252 WARN ((0, 0, _("%s: Directory has been renamed"),
253 quotearg_colon (name_buffer)));
254 directory->children = ALL_CHILDREN;
255 directory->nfs = nfs;
256 directory->device_number = stat_data.st_dev;
257 directory->inode_number = stat_data.st_ino;
259 directory->found = 1;
264 WARN ((0, 0, _("%s: Directory is new"),
265 quotearg_colon (name_buffer)));
266 directory = note_directory (name_buffer,
268 stat_data.st_ino, nfs, 1);
269 directory->children =
270 ((listed_incremental_option
271 || newer_mtime_option <= stat_data.st_mtime
272 || (after_date_option &&
273 newer_ctime_option <= stat_data.st_ctime))
278 if (one_file_system_option && device != stat_data.st_dev)
279 directory->children = NO_CHILDREN;
280 else if (children == ALL_CHILDREN)
281 directory->children = ALL_CHILDREN;
283 add_to_accumulator (accumulator, "D", 1);
286 else if (one_file_system_option && device != stat_data.st_dev)
287 add_to_accumulator (accumulator, "N", 1);
290 else if (S_ISHIDDEN (stat_data.st_mode))
292 add_to_accumulator (accumulator, "D", 1);
293 add_to_accumulator (accumulator, entry, entrylen);
294 add_to_accumulator (accumulator, "A", 2);
300 if (children == CHANGED_CHILDREN
301 && stat_data.st_mtime < newer_mtime_option
302 && (!after_date_option
303 || stat_data.st_ctime < newer_ctime_option))
304 add_to_accumulator (accumulator, "N", 1);
306 add_to_accumulator (accumulator, "Y", 1);
309 add_to_accumulator (accumulator, entry, entrylen + 1);
312 add_to_accumulator (accumulator, "\000\000", 2);
318 /* Sort the contents of the directory, now that we have it all. */
321 char *pointer = get_accumulator (accumulator);
329 for (cursor = pointer; *cursor; cursor += strlen (cursor) + 1)
334 delete_accumulator (accumulator);
338 array = xmalloc (sizeof (char *) * (counter + 1));
340 array_cursor = array;
341 for (cursor = pointer; *cursor; cursor += strlen (cursor) + 1)
342 *array_cursor++ = cursor;
345 qsort (array, counter, sizeof (char *), compare_dirents);
347 buffer = xmalloc (cursor - pointer + 2);
350 for (array_cursor = array; *array_cursor; array_cursor++)
352 char *string = *array_cursor;
354 while ((*cursor++ = *string++))
359 delete_accumulator (accumulator);
365 static FILE *listed_incremental_stream;
368 read_directory_file (void)
375 /* Open the file for both read and write. That way, we can write
376 it later without having to reopen it, and don't have to worry if
377 we chdir in the meantime. */
378 fd = open (listed_incremental_option, O_RDWR | O_CREAT, MODE_RW);
381 open_error (listed_incremental_option);
385 fp = fdopen (fd, "r+");
388 open_error (listed_incremental_option);
393 listed_incremental_stream = fp;
395 if (0 < getline (&buf, &bufsize, fp))
400 unsigned long u = (errno = 0, strtoul (buf, &ebuf, 10));
402 if (buf == ebuf || (u == 0 && errno == EINVAL))
403 ERROR ((0, 0, "%s:1: %s", quotearg_colon (listed_incremental_option),
404 _("Invalid time stamp")));
405 else if (t != u || (u == -1 && errno == ERANGE))
406 ERROR ((0, 0, "%s:1: %s", quotearg_colon (listed_incremental_option),
407 _("Time stamp out of range")));
409 newer_mtime_option = t;
411 while (0 < (n = getline (&buf, &bufsize, fp)))
415 int nfs = buf[0] == '+';
416 char *strp = buf + nfs;
420 if (buf[n - 1] == '\n')
424 dev = u = strtoul (strp, &ebuf, 10);
425 if (strp == ebuf || (u == 0 && errno == EINVAL))
426 ERROR ((0, 0, "%s:%ld: %s",
427 quotearg_colon (listed_incremental_option), lineno,
428 _("Invalid device number")));
429 else if (dev != u || (u == -1 && errno == ERANGE))
430 ERROR ((0, 0, "%s:%ld: %s",
431 quotearg_colon (listed_incremental_option), lineno,
432 _("Device number out of range")));
436 ino = u = strtoul (strp, &ebuf, 10);
437 if (strp == ebuf || (u == 0 && errno == EINVAL))
438 ERROR ((0, 0, "%s:%ld: %s",
439 quotearg_colon (listed_incremental_option), lineno,
440 _("Invalid inode number")));
441 else if (ino != u || (u == -1 && errno == ERANGE))
442 ERROR ((0, 0, "%s:%ld: %s",
443 quotearg_colon (listed_incremental_option), lineno,
444 _("Inode number out of range")));
448 unquote_string (strp);
449 note_directory (strp, dev, ino, nfs, 0);
454 read_error (listed_incremental_option);
459 /* Output incremental data for the directory ENTRY to the file DATA.
460 Return nonzero if successful, preserving errno on write failure. */
462 write_directory_file_entry (void *entry, void *data)
464 struct directory const *directory = entry;
467 if (directory->found)
470 char *str = quote_copy_string (directory->name);
471 fprintf (fp, "+%lu %lu %s\n" + ! directory->nfs,
472 (unsigned long) directory->device_number,
473 (unsigned long) directory->inode_number,
474 str ? str : directory->name);
481 return ! ferror (fp);
485 write_directory_file (void)
487 FILE *fp = listed_incremental_stream;
492 if (fseek (fp, 0L, SEEK_SET) != 0)
493 seek_error (listed_incremental_option);
494 if (ftruncate (fileno (fp), (off_t) 0) != 0)
495 truncate_error (listed_incremental_option);
497 fprintf (fp, "%lu\n", (unsigned long) start_time);
498 if (! ferror (fp) && directory_table)
499 hash_do_for_each (directory_table, write_directory_file_entry, fp);
501 write_error (listed_incremental_option);
502 if (fclose (fp) != 0)
503 close_error (listed_incremental_option);
506 /* Restoration of incremental dumps. */
509 gnu_restore (size_t skipcrud)
516 union block *data_block;
519 #define CURRENT_FILE_NAME (skipcrud + current_file_name)
521 current_dir = savedir (CURRENT_FILE_NAME);
525 /* The directory doesn't exist now. It'll be created. In any
526 case, we don't have to delete any files out of it. */
532 size = current_stat.st_size;
533 if (size != current_stat.st_size)
535 archive_dir = xmalloc (size);
537 for (; size > 0; size -= copied)
539 data_block = find_next_block ();
542 ERROR ((0, 0, _("Unexpected EOF in archive")));
543 break; /* FIXME: What happens then? */
545 copied = available_space_after (data_block);
548 memcpy (to, data_block->buffer, copied);
550 set_next_block_after ((union block *)
551 (data_block->buffer + copied - 1));
554 for (cur = current_dir; *cur; cur += strlen (cur) + 1)
556 for (arc = archive_dir; *arc; arc += strlen (arc) + 1)
559 if (!strcmp (arc, cur))
564 char *p = new_name (CURRENT_FILE_NAME, cur);
565 if (! interactive_option || confirm ("delete", p))
568 fprintf (stdlis, _("%s: Deleting %s\n"),
569 program_name, quote (p));
570 if (! remove_any_file (p, 1))
573 ERROR ((0, e, _("%s: Cannot remove"), quotearg_colon (p)));
583 #undef CURRENT_FILE_NAME