/* GNU dump extensions to tar.
Copyright (C) 1988, 1992, 1993, 1994, 1996, 1997, 1999, 2000, 2001,
- 2003 Free Software Foundation, Inc.
+ 2003, 2004, 2005 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
- 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
-#include "system.h"
+#include <system.h>
#include <getline.h>
#include <hash.h>
#include <quotearg.h>
#include "common.h"
-#define obstack_chunk_alloc xmalloc
-#define obstack_chunk_free free
-#include <obstack.h>
/* Incremental dump specialities. */
enum children children;
bool nfs;
bool found;
- char name[1]; /* path name of directory */
+ char name[1]; /* file name of directory */
};
static Hash_table *directory_table;
#endif
/* Calculate the hash of a directory. */
-static unsigned
-hash_directory (void const *entry, unsigned n_buckets)
+static size_t
+hash_directory (void const *entry, size_t n_buckets)
{
struct directory const *directory = entry;
return hash_string (directory->name, n_buckets);
return directory;
}
-/* Return a directory entry for a given path NAME, or zero if none found. */
+/* Return a directory entry for a given file NAME, or zero if none found. */
static struct directory *
find_directory (char *name)
{
(*(char *const *) second) + 1);
}
-/* Recursively scan the given PATH. */
+/* Recursively scan the given directory. */
static void
-scan_path (struct obstack *stk, char *path, dev_t device)
+scan_directory (struct obstack *stk, char *dir_name, dev_t device)
{
- char *dirp = savedir (path); /* for scanning directory */
+ char *dirp = savedir (dir_name); /* for scanning directory */
char const *entry; /* directory entry being scanned */
size_t entrylen; /* length of directory entry */
char *name_buffer; /* directory, `/', and directory member */
size_t name_buffer_size; /* allocated size of name_buffer, minus 2 */
size_t name_length; /* used length in name_buffer */
- struct directory *directory; /* for checking if already already seen */
+ struct directory *directory; /* for checking if already seen */
enum children children;
if (! dirp)
{
- savedir_error (path);
+ savedir_error (dir_name);
}
errno = 0;
- name_buffer_size = strlen (path) + NAME_FIELD_SIZE;
+ name_buffer_size = strlen (dir_name) + NAME_FIELD_SIZE;
name_buffer = xmalloc (name_buffer_size + 2);
- strcpy (name_buffer, path);
- if (! ISSLASH (path[strlen (path) - 1]))
+ strcpy (name_buffer, dir_name);
+ if (! ISSLASH (dir_name[strlen (dir_name) - 1]))
strcat (name_buffer, "/");
name_length = strlen (name_buffer);
- directory = find_directory (path);
+ directory = find_directory (dir_name);
children = directory ? directory->children : CHANGED_CHILDREN;
-
+
if (dirp && children != NO_CHILDREN)
for (entry = dirp;
(entrylen = strlen (entry)) != 0;
name_buffer = xrealloc (name_buffer, name_buffer_size + 2);
}
strcpy (name_buffer + name_length, entry);
-
+
if (excluded_name (name_buffer))
obstack_1grow (stk, 'N');
else
{
struct stat stat_data;
-
+
if (deref_stat (dereference_option, name_buffer, &stat_data))
{
stat_diag (name_buffer);
continue;
}
-
+
if (S_ISDIR (stat_data.st_mode))
{
bool nfs = NFS_FILE_STAT (stat_data);
-
- if (directory = find_directory (name_buffer), directory)
+
+ if ((directory = find_directory (name_buffer)) != NULL)
{
/* With NFS, the same file can have two different devices
if an NFS directory is mounted in multiple locations,
To avoid spurious incremental redumping of
directories, consider all NFS devices as equal,
relying on the i-node to establish differences. */
-
+
if (! (((directory->nfs & nfs)
|| directory->device_number == stat_data.st_dev)
&& directory->inode_number == stat_data.st_ino))
stat_data.st_ino, nfs, 1);
directory->children =
((listed_incremental_option
- || newer_mtime_option <= stat_data.st_mtime
- || (after_date_option &&
- newer_ctime_option <= stat_data.st_ctime))
+ || OLDER_STAT_TIME (stat_data, m)
+ || (after_date_option
+ && OLDER_STAT_TIME (stat_data, c)))
? ALL_CHILDREN
: CHANGED_CHILDREN);
}
-
+
if (one_file_system_option && device != stat_data.st_dev)
directory->children = NO_CHILDREN;
else if (children == ALL_CHILDREN)
else
if (children == CHANGED_CHILDREN
- && stat_data.st_mtime < newer_mtime_option
- && (!after_date_option
- || stat_data.st_ctime < newer_ctime_option))
+ && OLDER_STAT_TIME (stat_data, m)
+ && (!after_date_option || OLDER_STAT_TIME (stat_data, c)))
obstack_1grow (stk, 'N');
else
obstack_1grow (stk, 'Y');
}
-
+
obstack_grow (stk, entry, entrylen + 1);
}
obstack_grow (stk, "\000\000", 2);
-
+
free (name_buffer);
if (dirp)
free (dirp);
}
-/* Sort the contents of the obstack, anr convert it to the char * */
+/* Sort the contents of the obstack, and convert it to the char * */
static char *
sort_obstack (struct obstack *stk)
{
char *buffer;
char **array;
char **array_cursor;
-
+
counter = 0;
for (cursor = pointer; *cursor; cursor += strlen (cursor) + 1)
counter++;
-
+
if (!counter)
return NULL;
array = obstack_alloc (stk, sizeof (char *) * (counter + 1));
-
+
array_cursor = array;
for (cursor = pointer; *cursor; cursor += strlen (cursor) + 1)
*array_cursor++ = cursor;
for (array_cursor = array; *array_cursor; array_cursor++)
{
char *string = *array_cursor;
-
+
while ((*cursor++ = *string++))
continue;
}
}
char *
-get_directory_contents (char *path, dev_t device)
+get_directory_contents (char *dir_name, dev_t device)
{
struct obstack stk;
char *buffer;
obstack_init (&stk);
- scan_path (&stk, path, device);
+ scan_directory (&stk, dir_name, device);
buffer = sort_obstack (&stk);
obstack_free (&stk, NULL);
- return buffer;;
+ return buffer;
}
\f
char *ebuf;
int n;
long lineno = 1;
- unsigned long u = (errno = 0, strtoul (buf, &ebuf, 10));
+ uintmax_t u = (errno = 0, strtoumax (buf, &ebuf, 10));
time_t t = u;
+
if (buf == ebuf || (u == 0 && errno == EINVAL))
ERROR ((0, 0, "%s:1: %s", quotearg_colon (listed_incremental_option),
_("Invalid time stamp")));
- else if (t != u || (u == -1 && errno == ERANGE))
+ else if (t != u)
ERROR ((0, 0, "%s:1: %s", quotearg_colon (listed_incremental_option),
_("Time stamp out of range")));
else
- newer_mtime_option = t;
+ {
+ /* FIXME: This should also input nanoseconds, but that will be a
+ change in file format. */
+ newer_mtime_option.tv_sec = t;
+ newer_mtime_option.tv_nsec = 0;
+ }
while (0 < (n = getline (&buf, &bufsize, fp)))
{
buf[n - 1] = '\0';
errno = 0;
- dev = u = strtoul (strp, &ebuf, 10);
- if (strp == ebuf || (u == 0 && errno == EINVAL))
+ dev = u = strtoumax (strp, &ebuf, 10);
+ if (!isspace (*ebuf))
ERROR ((0, 0, "%s:%ld: %s",
quotearg_colon (listed_incremental_option), lineno,
_("Invalid device number")));
- else if (dev != u || (u == -1 && errno == ERANGE))
+ else if (dev != u)
ERROR ((0, 0, "%s:%ld: %s",
quotearg_colon (listed_incremental_option), lineno,
_("Device number out of range")));
strp = ebuf;
errno = 0;
- ino = u = strtoul (strp, &ebuf, 10);
- if (strp == ebuf || (u == 0 && errno == EINVAL))
+ ino = u = strtoumax (strp, &ebuf, 10);
+ if (!isspace (*ebuf))
ERROR ((0, 0, "%s:%ld: %s",
quotearg_colon (listed_incremental_option), lineno,
_("Invalid inode number")));
- else if (ino != u || (u == -1 && errno == ERANGE))
+ else if (ino != u)
ERROR ((0, 0, "%s:%ld: %s",
quotearg_colon (listed_incremental_option), lineno,
_("Inode number out of range")));
if (directory->found)
{
int e;
+ char buf[UINTMAX_STRSIZE_BOUND];
char *str = quote_copy_string (directory->name);
- fprintf (fp, "+%lu %lu %s\n" + ! directory->nfs,
- (unsigned long) directory->device_number,
- (unsigned long) directory->inode_number,
- str ? str : directory->name);
+
+ if (directory->nfs)
+ fprintf (fp, "+");
+ fprintf (fp, "%s ", umaxtostr (directory->device_number, buf));
+ fprintf (fp, "%s ", umaxtostr (directory->inode_number, buf));
+ fprintf (fp, "%s\n", str ? str : directory->name);
+
e = errno;
if (str)
free (str);
if (sys_truncate (fileno (fp)) != 0)
truncate_error (listed_incremental_option);
- fprintf (fp, "%lu\n", (unsigned long) start_time);
+ /* FIXME: This should also output nanoseconds, but that will be a
+ change in file format. */
+ fprintf (fp, "%lu\n", (unsigned long int) start_time.tv_sec);
if (! ferror (fp) && directory_table)
hash_do_for_each (directory_table, write_directory_file_entry, fp);
if (ferror (fp))
if (fclose (fp) != 0)
close_error (listed_incremental_option);
}
+
\f
/* Restoration of incremental dumps. */
+/* Examine the directories under directory_name and delete any
+ files that were not there at the time of the back-up. */
void
-gnu_restore (char const *directory_name)
+purge_directory (char const *directory_name)
{
char *archive_dir;
char *current_dir;
}
if (*arc == '\0')
{
+ struct stat st;
char *p = new_name (directory_name, cur);
+
+ if (deref_stat (false, p, &st))
+ {
+ stat_diag (p);
+ WARN((0, 0, _("%s: Not purging directory: unable to stat"),
+ quotearg_colon (p)));
+ continue;
+ }
+ else if (one_file_system_option && st.st_dev != root_device)
+ {
+ WARN((0, 0,
+ _("%s: directory is on a different device: not purging"),
+ quotearg_colon (p)));
+ continue;
+ }
+
if (! interactive_option || confirm ("delete", p))
{
if (verbose_option)
fprintf (stdlis, _("%s: Deleting %s\n"),
program_name, quote (p));
- if (! remove_any_file (p, 1))
+ if (! remove_any_file (p, RECURSIVE_REMOVE_OPTION))
{
int e = errno;
ERROR ((0, e, _("%s: Cannot remove"), quotearg_colon (p)));