|
@@ -22,62 +22,10 @@
|
|
|
#include <hash.h>
|
|
|
#include <quotearg.h>
|
|
|
#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));
|
|
|
+#define obstack_chunk_alloc xmalloc
|
|
|
+#define obstack_chunk_free free
|
|
|
+#include <obstack.h>
|
|
|
|
|
|
- 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. */
|
|
@@ -169,83 +117,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 PATH. */
|
|
|
+static void
|
|
|
+scan_path (struct obstack *stk, char *path, 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 (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)
|
|
|
+ {
|
|
|
+ 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;
|
|
|
+
|
|
|
+ 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), 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 (verbose_option)
|
|
|
WARN ((0, 0, _("%s: Directory has been renamed"),
|
|
@@ -255,113 +197,122 @@ 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
|
|
|
+ || 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;
|
|
|
+
|
|
|
+ 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
|
|
|
+ && stat_data.st_mtime < newer_mtime_option
|
|
|
+ && (!after_date_option
|
|
|
+ || stat_data.st_ctime < newer_ctime_option))
|
|
|
+ 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);
|
|
|
- }
|
|
|
-
|
|
|
- add_to_accumulator (accumulator, entry, entrylen + 1);
|
|
|
- }
|
|
|
-
|
|
|
- add_to_accumulator (accumulator, "\000\000", 2);
|
|
|
-
|
|
|
- free (name_buffer);
|
|
|
- if (dirp)
|
|
|
- free (dirp);
|
|
|
- }
|
|
|
-
|
|
|
- /* Sort the contents of the directory, now that we have it all. */
|
|
|
-
|
|
|
- {
|
|
|
- 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;
|
|
|
+ obstack_1grow (stk, 'Y');
|
|
|
+ }
|
|
|
+
|
|
|
+ obstack_grow (stk, entry, entrylen + 1);
|
|
|
}
|
|
|
|
|
|
- array = xmalloc (sizeof (char *) * (counter + 1));
|
|
|
-
|
|
|
- array_cursor = array;
|
|
|
- for (cursor = pointer; *cursor; cursor += strlen (cursor) + 1)
|
|
|
- *array_cursor++ = cursor;
|
|
|
- *array_cursor = 0;
|
|
|
-
|
|
|
- qsort (array, counter, sizeof (char *), compare_dirents);
|
|
|
-
|
|
|
- buffer = xmalloc (cursor - pointer + 2);
|
|
|
-
|
|
|
- cursor = buffer;
|
|
|
- for (array_cursor = array; *array_cursor; array_cursor++)
|
|
|
- {
|
|
|
- char *string = *array_cursor;
|
|
|
+ obstack_grow (stk, "\000\000", 2);
|
|
|
+
|
|
|
+ free (name_buffer);
|
|
|
+ if (dirp)
|
|
|
+ free (dirp);
|
|
|
+}
|
|
|
|
|
|
- while ((*cursor++ = *string++))
|
|
|
- continue;
|
|
|
- }
|
|
|
- *cursor = '\0';
|
|
|
+/* Sort the contents of the obstack, anr 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;
|
|
|
+
|
|
|
+ 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;
|
|
|
+ *array_cursor = 0;
|
|
|
+
|
|
|
+ qsort (array, counter, sizeof (char *), compare_dirents);
|
|
|
+
|
|
|
+ buffer = xmalloc (cursor - pointer + 2);
|
|
|
+
|
|
|
+ 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 *path, dev_t device)
|
|
|
+{
|
|
|
+ struct obstack stk;
|
|
|
+ char *buffer;
|
|
|
+
|
|
|
+ obstack_init (&stk);
|
|
|
+ scan_path (&stk, path, device);
|
|
|
+ buffer = sort_obstack (&stk);
|
|
|
+ obstack_free (&stk, NULL);
|
|
|
+ return buffer;;
|
|
|
}
|
|
|
+
|
|
|
|
|
|
+
|
|
|
static FILE *listed_incremental_stream;
|
|
|
|
|
|
void
|