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 savedir_error (path
);
195 name_buffer_size
= strlen (path
) + NAME_FIELD_SIZE
;
196 name_buffer
= xmalloc (name_buffer_size
+ 2);
197 strcpy (name_buffer
, path
);
198 if (! ISSLASH (path
[strlen (path
) - 1]))
199 strcat (name_buffer
, "/");
200 name_length
= strlen (name_buffer
);
202 directory
= find_directory (path
);
203 children
= directory
? directory
->children
: CHANGED_CHILDREN
;
205 accumulator
= new_accumulator ();
207 if (dirp
&& children
!= NO_CHILDREN
)
209 (entrylen
= strlen (entry
)) != 0;
210 entry
+= entrylen
+ 1)
212 if (name_buffer_size
<= entrylen
+ name_length
)
215 name_buffer_size
+= NAME_FIELD_SIZE
;
216 while (name_buffer_size
<= entrylen
+ name_length
);
217 name_buffer
= xrealloc (name_buffer
, name_buffer_size
+ 2);
219 strcpy (name_buffer
+ name_length
, entry
);
221 if (excluded_name (name_buffer
))
222 add_to_accumulator (accumulator
, "N", 1);
225 struct stat stat_data
;
227 if (deref_stat (dereference_option
, name_buffer
, &stat_data
))
229 stat_diag (name_buffer
);
233 if (S_ISDIR (stat_data
.st_mode
))
235 bool nfs
= NFS_FILE_STAT (stat_data
);
237 if (directory
= find_directory (name_buffer
), directory
)
239 /* With NFS, the same file can have two different devices
240 if an NFS directory is mounted in multiple locations,
241 which is relatively common when automounting.
242 To avoid spurious incremental redumping of
243 directories, consider all NFS devices as equal,
244 relying on the i-node to establish differences. */
246 if (! (((directory
->nfs
& nfs
)
247 || directory
->device_number
== stat_data
.st_dev
)
248 && directory
->inode_number
== stat_data
.st_ino
))
251 WARN ((0, 0, _("%s: Directory has been renamed"),
252 quotearg_colon (name_buffer
)));
253 directory
->children
= ALL_CHILDREN
;
254 directory
->nfs
= nfs
;
255 directory
->device_number
= stat_data
.st_dev
;
256 directory
->inode_number
= stat_data
.st_ino
;
258 directory
->found
= 1;
263 WARN ((0, 0, _("%s: Directory is new"),
264 quotearg_colon (name_buffer
)));
265 directory
= note_directory (name_buffer
,
267 stat_data
.st_ino
, nfs
, 1);
268 directory
->children
=
269 ((listed_incremental_option
270 || newer_mtime_option
<= stat_data
.st_mtime
271 || (after_date_option
&&
272 newer_ctime_option
<= stat_data
.st_ctime
))
277 if (one_file_system_option
&& device
!= stat_data
.st_dev
)
278 directory
->children
= NO_CHILDREN
;
279 else if (children
== ALL_CHILDREN
)
280 directory
->children
= ALL_CHILDREN
;
282 add_to_accumulator (accumulator
, "D", 1);
285 else if (one_file_system_option
&& device
!= stat_data
.st_dev
)
286 add_to_accumulator (accumulator
, "N", 1);
289 else if (S_ISHIDDEN (stat_data
.st_mode
))
291 add_to_accumulator (accumulator
, "D", 1);
292 add_to_accumulator (accumulator
, entry
, entrylen
);
293 add_to_accumulator (accumulator
, "A", 2);
299 if (children
== CHANGED_CHILDREN
300 && stat_data
.st_mtime
< newer_mtime_option
301 && (!after_date_option
302 || stat_data
.st_ctime
< newer_ctime_option
))
303 add_to_accumulator (accumulator
, "N", 1);
305 add_to_accumulator (accumulator
, "Y", 1);
308 add_to_accumulator (accumulator
, entry
, entrylen
+ 1);
311 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 bool 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 (sys_truncate (fileno (fp
)) != 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 (char const *directory_name
)
516 union block
*data_block
;
519 current_dir
= savedir (directory_name
);
523 /* The directory doesn't exist now. It'll be created. In any
524 case, we don't have to delete any files out of it. */
530 size
= current_stat_info
.stat
.st_size
;
531 if (size
!= current_stat_info
.stat
.st_size
)
533 archive_dir
= xmalloc (size
);
535 for (; size
> 0; size
-= copied
)
537 data_block
= find_next_block ();
540 ERROR ((0, 0, _("Unexpected EOF in archive")));
541 break; /* FIXME: What happens then? */
543 copied
= available_space_after (data_block
);
546 memcpy (to
, data_block
->buffer
, copied
);
548 set_next_block_after ((union block
*)
549 (data_block
->buffer
+ copied
- 1));
552 for (cur
= current_dir
; *cur
; cur
+= strlen (cur
) + 1)
554 for (arc
= archive_dir
; *arc
; arc
+= strlen (arc
) + 1)
557 if (!strcmp (arc
, cur
))
562 char *p
= new_name (directory_name
, cur
);
563 if (! interactive_option
|| confirm ("delete", p
))
566 fprintf (stdlis
, _("%s: Deleting %s\n"),
567 program_name
, quote (p
));
568 if (! remove_any_file (p
, 1))
571 ERROR ((0, e
, _("%s: Cannot remove"), quotearg_colon (p
)));