X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;f=src%2Fincremen.c;h=69805a7f779dc72710865febf85182abc4972636;hb=d659cbaccdc1f3279c49107cf15f15a639738529;hp=5feef76667754fa99736a546e8d32649482e03ac;hpb=fc184a85e1cc0a75f8f034a9940e090555bc95bd;p=chaz%2Ftar diff --git a/src/incremen.c b/src/incremen.c index 5feef76..69805a7 100644 --- a/src/incremen.c +++ b/src/incremen.c @@ -1,7 +1,7 @@ /* 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 @@ -15,69 +15,14 @@ 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 #include #include #include #include "common.h" - -/* Variable sized generic character buffers. */ - -struct accumulator -{ - size_t allocated; - size_t length; - char *pointer; -}; - -/* Amount of space guaranteed just after a reallocation. */ -#define ACCUMULATOR_SLACK 50 - -/* Return the accumulated data from an ACCUMULATOR buffer. */ -static char * -get_accumulator (struct accumulator *accumulator) -{ - return accumulator->pointer; -} - -/* Allocate and return a new accumulator buffer. */ -static struct accumulator * -new_accumulator (void) -{ - struct accumulator *accumulator - = xmalloc (sizeof (struct accumulator)); - accumulator->allocated = ACCUMULATOR_SLACK; - accumulator->pointer = xmalloc (ACCUMULATOR_SLACK); - accumulator->length = 0; - return accumulator; -} - -/* Deallocate an ACCUMULATOR buffer. */ -static void -delete_accumulator (struct accumulator *accumulator) -{ - free (accumulator->pointer); - free (accumulator); -} - -/* At the end of an ACCUMULATOR buffer, add a DATA block of SIZE bytes. */ -static void -add_to_accumulator (struct accumulator *accumulator, - const char *data, size_t size) -{ - if (accumulator->length + size > accumulator->allocated) - { - accumulator->allocated = accumulator->length + size + ACCUMULATOR_SLACK; - accumulator->pointer = - xrealloc (accumulator->pointer, accumulator->allocated); - } - memcpy (accumulator->pointer + accumulator->length, data, size); - accumulator->length += size; -} - /* Incremental dump specialities. */ /* Which child files to save under a directory. */ @@ -91,7 +36,7 @@ struct directory 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; @@ -105,8 +50,8 @@ 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); @@ -147,7 +92,7 @@ note_directory (char const *name, dev_t dev, ino_t ino, bool nfs, bool found) 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) { @@ -169,83 +114,77 @@ compare_dirents (const void *first, const void *second) (*(char *const *) second) + 1); } -char * -get_directory_contents (char *path, dev_t device) +/* Recursively scan the given directory. */ +static void +scan_directory (struct obstack *stk, char *dir_name, dev_t device) { - struct accumulator *accumulator; - - /* Recursively scan the given PATH. */ - - { - char *dirp = savedir (path); /* 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 */ - enum children children; - - if (! dirp) + 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 seen */ + enum children children; + + if (! dirp) + { + savedir_error (dir_name); + } + errno = 0; + + name_buffer_size = strlen (dir_name) + NAME_FIELD_SIZE; + name_buffer = xmalloc (name_buffer_size + 2); + strcpy (name_buffer, dir_name); + if (! ISSLASH (dir_name[strlen (dir_name) - 1])) + strcat (name_buffer, "/"); + name_length = strlen (name_buffer); + + directory = find_directory (dir_name); + children = directory ? directory->children : CHANGED_CHILDREN; + + if (dirp && children != NO_CHILDREN) + for (entry = dirp; + (entrylen = strlen (entry)) != 0; + entry += entrylen + 1) { - savedir_error (path); - } - errno = 0; - - name_buffer_size = strlen (path) + NAME_FIELD_SIZE; - name_buffer = xmalloc (name_buffer_size + 2); - strcpy (name_buffer, path); - if (! ISSLASH (path[strlen (path) - 1])) - strcat (name_buffer, "/"); - name_length = strlen (name_buffer); - - directory = find_directory (path); - children = directory ? directory->children : CHANGED_CHILDREN; - - accumulator = new_accumulator (); - - if (dirp && children != NO_CHILDREN) - for (entry = dirp; - (entrylen = strlen (entry)) != 0; - entry += entrylen + 1) - { - if (name_buffer_size <= entrylen + name_length) - { - do - name_buffer_size += NAME_FIELD_SIZE; - while (name_buffer_size <= entrylen + name_length); - name_buffer = xrealloc (name_buffer, name_buffer_size + 2); - } - strcpy (name_buffer + name_length, entry); - - if (excluded_name (name_buffer)) - add_to_accumulator (accumulator, "N", 1); - 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) - { - /* With NFS, the same file can have two different devices - if an NFS directory is mounted in multiple locations, - which is relatively common when automounting. - 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)) + if (name_buffer_size <= entrylen + name_length) + { + do + name_buffer_size += NAME_FIELD_SIZE; + while (name_buffer_size <= entrylen + name_length); + 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)) != NULL) + { + /* With NFS, the same file can have two different devices + if an NFS directory is mounted in multiple locations, + which is relatively common when automounting. + 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)) { if (verbose_option) WARN ((0, 0, _("%s: Directory has been renamed"), @@ -255,113 +194,121 @@ get_directory_contents (char *path, dev_t device) directory->device_number = stat_data.st_dev; directory->inode_number = stat_data.st_ino; } - directory->found = 1; - } - else - { - if (verbose_option) - WARN ((0, 0, _("%s: Directory is new"), - quotearg_colon (name_buffer))); - directory = note_directory (name_buffer, - stat_data.st_dev, - 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)) - ? ALL_CHILDREN - : CHANGED_CHILDREN); - } - - if (one_file_system_option && device != stat_data.st_dev) - directory->children = NO_CHILDREN; - else if (children == ALL_CHILDREN) - directory->children = ALL_CHILDREN; - - add_to_accumulator (accumulator, "D", 1); - } - - else if (one_file_system_option && device != stat_data.st_dev) - add_to_accumulator (accumulator, "N", 1); + directory->found = 1; + } + else + { + if (verbose_option) + WARN ((0, 0, _("%s: Directory is new"), + quotearg_colon (name_buffer))); + directory = note_directory (name_buffer, + stat_data.st_dev, + stat_data.st_ino, nfs, 1); + directory->children = + ((listed_incremental_option + || 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) + directory->children = ALL_CHILDREN; + + obstack_1grow (stk, 'D'); + } + + else if (one_file_system_option && device != stat_data.st_dev) + obstack_1grow (stk, 'N'); #ifdef S_ISHIDDEN - else if (S_ISHIDDEN (stat_data.st_mode)) - { - add_to_accumulator (accumulator, "D", 1); - add_to_accumulator (accumulator, entry, entrylen); - add_to_accumulator (accumulator, "A", 2); - continue; - } + else if (S_ISHIDDEN (stat_data.st_mode)) + { + obstack_1grow (stk, 'D'); + obstack_grow (stk, entry, entrylen); + obstack_grow (stk, "A", 2); + continue; + } #endif + else + if (children == CHANGED_CHILDREN + && OLDER_STAT_TIME (stat_data, m) + && (!after_date_option || OLDER_STAT_TIME (stat_data, c))) + obstack_1grow (stk, 'N'); else - if (children == CHANGED_CHILDREN - && stat_data.st_mtime < newer_mtime_option - && (!after_date_option - || stat_data.st_ctime < newer_ctime_option)) - add_to_accumulator (accumulator, "N", 1); - else - add_to_accumulator (accumulator, "Y", 1); - } + obstack_1grow (stk, 'Y'); + } - add_to_accumulator (accumulator, entry, entrylen + 1); - } + obstack_grow (stk, entry, entrylen + 1); + } - add_to_accumulator (accumulator, "\000\000", 2); + obstack_grow (stk, "\000\000", 2); - free (name_buffer); - if (dirp) - free (dirp); - } + free (name_buffer); + if (dirp) + free (dirp); +} - /* Sort the contents of the directory, now that we have it all. */ +/* Sort the contents of the obstack, and convert it to the char * */ +static char * +sort_obstack (struct obstack *stk) +{ + char *pointer = obstack_finish (stk); + size_t counter; + char *cursor; + char *buffer; + char **array; + char **array_cursor; - { - char *pointer = get_accumulator (accumulator); - size_t counter; - char *cursor; - char *buffer; - char **array; - char **array_cursor; - - counter = 0; - for (cursor = pointer; *cursor; cursor += strlen (cursor) + 1) - counter++; - - if (! counter) - { - delete_accumulator (accumulator); - return 0; - } + counter = 0; + for (cursor = pointer; *cursor; cursor += strlen (cursor) + 1) + counter++; - array = xmalloc (sizeof (char *) * (counter + 1)); + if (!counter) + return NULL; - array_cursor = array; - for (cursor = pointer; *cursor; cursor += strlen (cursor) + 1) - *array_cursor++ = cursor; - *array_cursor = 0; + array = obstack_alloc (stk, sizeof (char *) * (counter + 1)); - qsort (array, counter, sizeof (char *), compare_dirents); + array_cursor = array; + for (cursor = pointer; *cursor; cursor += strlen (cursor) + 1) + *array_cursor++ = cursor; + *array_cursor = 0; - buffer = xmalloc (cursor - pointer + 2); + qsort (array, counter, sizeof (char *), compare_dirents); - cursor = buffer; - for (array_cursor = array; *array_cursor; array_cursor++) - { - char *string = *array_cursor; + buffer = xmalloc (cursor - pointer + 2); - while ((*cursor++ = *string++)) - continue; - } - *cursor = '\0'; + cursor = buffer; + for (array_cursor = array; *array_cursor; array_cursor++) + { + char *string = *array_cursor; + + while ((*cursor++ = *string++)) + continue; + } + *cursor = '\0'; + return buffer; +} - delete_accumulator (accumulator); - free (array); - return buffer; - } +char * +get_directory_contents (char *dir_name, dev_t device) +{ + struct obstack stk; + char *buffer; + + obstack_init (&stk); + scan_directory (&stk, dir_name, device); + buffer = sort_obstack (&stk); + obstack_free (&stk, NULL); + return buffer; } + + static FILE *listed_incremental_stream; void @@ -406,7 +353,12 @@ read_directory_file (void) 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))) { @@ -494,7 +446,9 @@ write_directory_file (void) 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)) @@ -502,11 +456,14 @@ write_directory_file (void) if (fclose (fp) != 0) close_error (listed_incremental_option); } + /* 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; @@ -559,13 +516,30 @@ gnu_restore (char const *directory_name) } if (*arc == '\0') { + struct stat st; char *p = new_name (directory_name, cur); + + if (deref_stat (true, 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)));