1 /* GNU dump extensions to tar.
3 Copyright (C) 1988, 1992, 1993, 1994, 1996, 1997, 1999, 2000, 2001,
4 2003 Free 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
;
191 if (ignore_failed_read_option
)
194 savedir_error (path
);
198 name_buffer_size
= strlen (path
) + NAME_FIELD_SIZE
;
199 name_buffer
= xmalloc (name_buffer_size
+ 2);
200 strcpy (name_buffer
, path
);
201 if (! ISSLASH (path
[strlen (path
) - 1]))
202 strcat (name_buffer
, "/");
203 name_length
= strlen (name_buffer
);
205 directory
= find_directory (path
);
206 children
= directory
? directory
->children
: CHANGED_CHILDREN
;
208 accumulator
= new_accumulator ();
210 if (dirp
&& children
!= NO_CHILDREN
)
212 (entrylen
= strlen (entry
)) != 0;
213 entry
+= entrylen
+ 1)
215 if (name_buffer_size
<= entrylen
+ name_length
)
218 name_buffer_size
+= NAME_FIELD_SIZE
;
219 while (name_buffer_size
<= entrylen
+ name_length
);
220 name_buffer
= xrealloc (name_buffer
, name_buffer_size
+ 2);
222 strcpy (name_buffer
+ name_length
, entry
);
224 if (excluded_name (name_buffer
))
225 add_to_accumulator (accumulator
, "N", 1);
228 struct stat stat_data
;
230 if (deref_stat (dereference_option
, name_buffer
, &stat_data
))
232 if (ignore_failed_read_option
)
233 stat_warn (name_buffer
);
235 stat_error (name_buffer
);
239 if (S_ISDIR (stat_data
.st_mode
))
241 bool nfs
= NFS_FILE_STAT (stat_data
);
243 if (directory
= find_directory (name_buffer
), directory
)
245 /* With NFS, the same file can have two different devices
246 if an NFS directory is mounted in multiple locations,
247 which is relatively common when automounting.
248 To avoid spurious incremental redumping of
249 directories, consider all NFS devices as equal,
250 relying on the i-node to establish differences. */
252 if (! (((directory
->nfs
& nfs
)
253 || directory
->device_number
== stat_data
.st_dev
)
254 && directory
->inode_number
== stat_data
.st_ino
))
257 WARN ((0, 0, _("%s: Directory has been renamed"),
258 quotearg_colon (name_buffer
)));
259 directory
->children
= ALL_CHILDREN
;
260 directory
->nfs
= nfs
;
261 directory
->device_number
= stat_data
.st_dev
;
262 directory
->inode_number
= stat_data
.st_ino
;
264 directory
->found
= 1;
269 WARN ((0, 0, _("%s: Directory is new"),
270 quotearg_colon (name_buffer
)));
271 directory
= note_directory (name_buffer
,
273 stat_data
.st_ino
, nfs
, 1);
274 directory
->children
=
275 ((listed_incremental_option
276 || newer_mtime_option
<= stat_data
.st_mtime
277 || (after_date_option
&&
278 newer_ctime_option
<= stat_data
.st_ctime
))
283 if (one_file_system_option
&& device
!= stat_data
.st_dev
)
284 directory
->children
= NO_CHILDREN
;
285 else if (children
== ALL_CHILDREN
)
286 directory
->children
= ALL_CHILDREN
;
288 add_to_accumulator (accumulator
, "D", 1);
291 else if (one_file_system_option
&& device
!= stat_data
.st_dev
)
292 add_to_accumulator (accumulator
, "N", 1);
295 else if (S_ISHIDDEN (stat_data
.st_mode
))
297 add_to_accumulator (accumulator
, "D", 1);
298 add_to_accumulator (accumulator
, entry
, entrylen
);
299 add_to_accumulator (accumulator
, "A", 2);
305 if (children
== CHANGED_CHILDREN
306 && stat_data
.st_mtime
< newer_mtime_option
307 && (!after_date_option
308 || stat_data
.st_ctime
< newer_ctime_option
))
309 add_to_accumulator (accumulator
, "N", 1);
311 add_to_accumulator (accumulator
, "Y", 1);
314 add_to_accumulator (accumulator
, entry
, entrylen
+ 1);
317 add_to_accumulator (accumulator
, "\000\000", 2);
324 /* Sort the contents of the directory, now that we have it all. */
327 char *pointer
= get_accumulator (accumulator
);
335 for (cursor
= pointer
; *cursor
; cursor
+= strlen (cursor
) + 1)
340 delete_accumulator (accumulator
);
344 array
= xmalloc (sizeof (char *) * (counter
+ 1));
346 array_cursor
= array
;
347 for (cursor
= pointer
; *cursor
; cursor
+= strlen (cursor
) + 1)
348 *array_cursor
++ = cursor
;
351 qsort (array
, counter
, sizeof (char *), compare_dirents
);
353 buffer
= xmalloc (cursor
- pointer
+ 2);
356 for (array_cursor
= array
; *array_cursor
; array_cursor
++)
358 char *string
= *array_cursor
;
360 while ((*cursor
++ = *string
++))
365 delete_accumulator (accumulator
);
371 static FILE *listed_incremental_stream
;
374 read_directory_file (void)
381 /* Open the file for both read and write. That way, we can write
382 it later without having to reopen it, and don't have to worry if
383 we chdir in the meantime. */
384 fd
= open (listed_incremental_option
, O_RDWR
| O_CREAT
, MODE_RW
);
387 open_error (listed_incremental_option
);
391 fp
= fdopen (fd
, "r+");
394 open_error (listed_incremental_option
);
399 listed_incremental_stream
= fp
;
401 if (0 < getline (&buf
, &bufsize
, fp
))
406 unsigned long u
= (errno
= 0, strtoul (buf
, &ebuf
, 10));
408 if (buf
== ebuf
|| (u
== 0 && errno
== EINVAL
))
409 ERROR ((0, 0, "%s:1: %s", quotearg_colon (listed_incremental_option
),
410 _("Invalid time stamp")));
411 else if (t
!= u
|| (u
== -1 && errno
== ERANGE
))
412 ERROR ((0, 0, "%s:1: %s", quotearg_colon (listed_incremental_option
),
413 _("Time stamp out of range")));
415 newer_mtime_option
= t
;
417 while (0 < (n
= getline (&buf
, &bufsize
, fp
)))
421 bool nfs
= buf
[0] == '+';
422 char *strp
= buf
+ nfs
;
426 if (buf
[n
- 1] == '\n')
430 dev
= u
= strtoul (strp
, &ebuf
, 10);
431 if (strp
== ebuf
|| (u
== 0 && errno
== EINVAL
))
432 ERROR ((0, 0, "%s:%ld: %s",
433 quotearg_colon (listed_incremental_option
), lineno
,
434 _("Invalid device number")));
435 else if (dev
!= u
|| (u
== -1 && errno
== ERANGE
))
436 ERROR ((0, 0, "%s:%ld: %s",
437 quotearg_colon (listed_incremental_option
), lineno
,
438 _("Device number out of range")));
442 ino
= u
= strtoul (strp
, &ebuf
, 10);
443 if (strp
== ebuf
|| (u
== 0 && errno
== EINVAL
))
444 ERROR ((0, 0, "%s:%ld: %s",
445 quotearg_colon (listed_incremental_option
), lineno
,
446 _("Invalid inode number")));
447 else if (ino
!= u
|| (u
== -1 && errno
== ERANGE
))
448 ERROR ((0, 0, "%s:%ld: %s",
449 quotearg_colon (listed_incremental_option
), lineno
,
450 _("Inode number out of range")));
454 unquote_string (strp
);
455 note_directory (strp
, dev
, ino
, nfs
, 0);
460 read_error (listed_incremental_option
);
465 /* Output incremental data for the directory ENTRY to the file DATA.
466 Return nonzero if successful, preserving errno on write failure. */
468 write_directory_file_entry (void *entry
, void *data
)
470 struct directory
const *directory
= entry
;
473 if (directory
->found
)
476 char *str
= quote_copy_string (directory
->name
);
477 fprintf (fp
, "+%lu %lu %s\n" + ! directory
->nfs
,
478 (unsigned long) directory
->device_number
,
479 (unsigned long) directory
->inode_number
,
480 str
? str
: directory
->name
);
487 return ! ferror (fp
);
491 write_directory_file (void)
493 FILE *fp
= listed_incremental_stream
;
498 if (fseek (fp
, 0L, SEEK_SET
) != 0)
499 seek_error (listed_incremental_option
);
500 if (ftruncate (fileno (fp
), (off_t
) 0) != 0)
501 truncate_error (listed_incremental_option
);
503 fprintf (fp
, "%lu\n", (unsigned long) start_time
);
504 if (! ferror (fp
) && directory_table
)
505 hash_do_for_each (directory_table
, write_directory_file_entry
, fp
);
507 write_error (listed_incremental_option
);
508 if (fclose (fp
) != 0)
509 close_error (listed_incremental_option
);
512 /* Restoration of incremental dumps. */
515 gnu_restore (char const *directory_name
)
522 union block
*data_block
;
525 current_dir
= savedir (directory_name
);
529 /* The directory doesn't exist now. It'll be created. In any
530 case, we don't have to delete any files out of it. */
536 size
= current_stat_info
.stat
.st_size
;
537 if (size
!= current_stat_info
.stat
.st_size
)
539 archive_dir
= xmalloc (size
);
541 for (; size
> 0; size
-= copied
)
543 data_block
= find_next_block ();
546 ERROR ((0, 0, _("Unexpected EOF in archive")));
547 break; /* FIXME: What happens then? */
549 copied
= available_space_after (data_block
);
552 memcpy (to
, data_block
->buffer
, copied
);
554 set_next_block_after ((union block
*)
555 (data_block
->buffer
+ copied
- 1));
558 for (cur
= current_dir
; *cur
; cur
+= strlen (cur
) + 1)
560 for (arc
= archive_dir
; *arc
; arc
+= strlen (arc
) + 1)
563 if (!strcmp (arc
, cur
))
568 char *p
= new_name (directory_name
, cur
);
569 if (! interactive_option
|| confirm ("delete", p
))
572 fprintf (stdlis
, _("%s: Deleting %s\n"),
573 program_name
, quote (p
));
574 if (! remove_any_file (p
, 1))
577 ERROR ((0, e
, _("%s: Cannot remove"), quotearg_colon (p
)));