Version 1.20.

* configure.ac: Raise version number to 1.20
* src/compare.c (diff_dumpdir): const.
* src/common.h (dumpdir_t,dumpdir_iter_t): New data types.
(dumpdir_create0,dumpdir_create,dumpdir_free,dumpdir_locate)
(dumpdir_first,dumpdir_next): New functions.
* src/incremen.c (dumpdir_create0,dumpdir_create,dumpdir_free)
(dumpdir_first,dumpdir_next): New functions.
(dumpdir_locate): Rewrite using binary search.
(struct directory): Change members char *contents, *icontents to
struct dumpdir *dump, *idump. All references updated.
(note_directory): Last arg is const.
* src/names.c (add_hierarchy_to_namelist): buffer is const.
* tests/incr03.at, tests/incr04.at, tests/rename02.at,
tests/rename03.at: Insert calls to sleep between creation of files
and adding them to the archive.
This commit is contained in:
Sergey Poznyakoff
2008-05-05 21:30:57 +00:00
parent 192860abb8
commit b94eed6d03
9 changed files with 194 additions and 92 deletions

View File

@@ -18,7 +18,7 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301, USA.
AC_INIT([GNU tar], [1.19.90], [bug-tar@gnu.org])
AC_INIT([GNU tar], [1.20], [bug-tar@gnu.org])
AC_CONFIG_SRCDIR([src/tar.c])
AC_CONFIG_AUX_DIR([build-aux])
AC_CONFIG_HEADERS([config.h:config.hin])

View File

@@ -1,7 +1,7 @@
/* Common declarations for the tar program.
Copyright (C) 1988, 1992, 1993, 1994, 1996, 1997, 1999, 2000, 2001,
2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
2003, 2004, 2005, 2006, 2007, 2008 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
@@ -489,8 +489,18 @@ bool rename_directory (char *src, char *dst);
void delete_archive_members (void);
/* Module incremen.c. */
typedef struct dumpdir *dumpdir_t;
typedef struct dumpdir_iter *dumpdir_iter_t;
char *get_directory_contents (char *dir_name, dev_t device);
dumpdir_t dumpdir_create0 (const char *contents, const char *cmask);
dumpdir_t dumpdir_create (const char *contents);
void dumpdir_free (dumpdir_t);
char *dumpdir_locate (dumpdir_t dump, const char *name);
char *dumpdir_next (dumpdir_iter_t itr);
char *dumpdir_first (dumpdir_t dump, int all, dumpdir_iter_t *pitr);
const char *get_directory_contents (char *dir_name, dev_t device);
const char *append_incremental_renames (const char *dump);
void read_directory_file (void);
void write_directory_file (void);

View File

@@ -366,7 +366,7 @@ dumpdir_cmp (const char *a, const char *b)
static void
diff_dumpdir (void)
{
char *dumpdir_buffer;
const char *dumpdir_buffer;
dev_t dev = 0;
struct stat stat_data;

View File

@@ -1,7 +1,7 @@
/* GNU dump extensions to tar.
Copyright (C) 1988, 1992, 1993, 1994, 1996, 1997, 1999, 2000, 2001,
2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
2003, 2004, 2005, 2006, 2007, 2008 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
@@ -49,14 +49,22 @@ enum children
#define DIR_SET_FLAG(d,f) (d)->flags |= (f)
#define DIR_CLEAR_FLAG(d,f) (d)->flags &= ~(f)
struct dumpdir /* Dump directory listing */
{
char *contents; /* Actual contents */
size_t total; /* Total number of elements */
size_t elc; /* Number of D/N/Y elements. */
char **elv; /* Array of D/N/Y elements */
};
/* Directory attributes. */
struct directory
{
struct timespec mtime; /* Modification time */
dev_t device_number; /* device number for directory */
ino_t inode_number; /* inode number for directory */
char *contents; /* Directory contents */
char *icontents; /* Initial contents if the directory was
struct dumpdir *dump; /* Directory contents */
struct dumpdir *idump; /* Initial contents if the directory was
rescanned */
enum children children; /* What to save under this directory */
unsigned flags; /* See DIRF_ macros above */
@@ -67,6 +75,127 @@ struct directory
char name[1]; /* file name of directory */
};
struct dumpdir *
dumpdir_create0 (const char *contents, const char *cmask)
{
struct dumpdir *dump;
size_t i, total, ctsize, len;
const char *p;
for (i = 0, total = 0, ctsize = 1, p = contents; *p; total++, p += len)
{
len = strlen (p) + 1;
ctsize += len;
if (!cmask || strchr (cmask, *p))
i++;
}
dump = xmalloc (sizeof (*dump) + ctsize);
dump->contents = (char*)(dump + 1);
memcpy (dump->contents, contents, ctsize);
dump->total = total;
dump->elc = i;
dump->elv = xcalloc (i + 1, sizeof (dump->elv[0]));
for (i = 0, p = dump->contents; *p; p += strlen (p) + 1)
{
if (!cmask || strchr (cmask, *p))
dump->elv[i++] = p + 1;
}
dump->elv[i] = NULL;
return dump;
}
struct dumpdir *
dumpdir_create (const char *contents)
{
return dumpdir_create0 (contents, "YND");
}
void
dumpdir_free (struct dumpdir *dump)
{
free (dump->elv);
free (dump);
}
static int
compare_dirnames (const void *first, const void *second)
{
char const *const *name1 = first;
char const *const *name2 = second;
return strcmp (*name1, *name2);
}
/* Locate NAME in the dumpdir array DUMP.
Return pointer to the slot in DUMP->contents, or NULL if not found */
char *
dumpdir_locate (struct dumpdir *dump, const char *name)
{
char **ptr;
if (!dump)
return NULL;
ptr = bsearch (&name, dump->elv, dump->elc, sizeof (dump->elv[0]),
compare_dirnames);
return ptr ? *ptr - 1: NULL;
}
struct dumpdir_iter
{
struct dumpdir *dump; /* Dumpdir being iterated */
int all; /* Iterate over all entries, not only D/N/Y */
size_t next; /* Index of the next element */
};
char *
dumpdir_next (struct dumpdir_iter *itr)
{
size_t cur = itr->next;
char *ret = NULL;
if (itr->all)
{
ret = itr->dump->contents + cur;
if (*ret == 0)
return NULL;
itr->next += strlen (ret) + 1;
}
else if (cur < itr->dump->elc)
{
ret = itr->dump->elv[cur] - 1;
itr->next++;
}
return ret;
}
char *
dumpdir_first (struct dumpdir *dump, int all, struct dumpdir_iter **pitr)
{
struct dumpdir_iter *itr = xmalloc (sizeof (*itr));
itr->dump = dump;
itr->all = all;
itr->next = 0;
*pitr = itr;
return dumpdir_next (itr);
}
/* Return size in bytes of the dumpdir array P */
size_t
dumpdir_size (const char *p)
{
size_t totsize = 0;
while (*p)
{
size_t size = strlen (p) + 1;
totsize += size;
p += size;
}
return totsize + 1;
}
static Hash_table *directory_table;
static Hash_table *directory_meta_table;
@@ -120,7 +249,7 @@ make_directory (const char *name)
size_t namelen = strlen (name);
size_t size = offsetof (struct directory, name) + namelen + 1;
struct directory *directory = xmalloc (size);
directory->contents = directory->icontents = NULL;
directory->dump = directory->idump = NULL;
directory->orig = NULL;
directory->flags = false;
strcpy (directory->name, name);
@@ -136,7 +265,8 @@ make_directory (const char *name)
found that the directory exists. */
static struct directory *
note_directory (char const *name, struct timespec mtime,
dev_t dev, ino_t ino, bool nfs, bool found, char *contents)
dev_t dev, ino_t ino, bool nfs, bool found,
const char *contents)
{
struct directory *directory = make_directory (name);
@@ -149,13 +279,9 @@ note_directory (char const *name, struct timespec mtime,
if (found)
DIR_SET_FLAG (directory, DIRF_FOUND);
if (contents)
{
size_t size = dumpdir_size (contents);
directory->contents = xmalloc (size);
memcpy (directory->contents, contents, size);
}
directory->dump = dumpdir_create (contents);
else
directory->contents = NULL;
directory->dump = NULL;
if (! ((directory_table
|| (directory_table = hash_initialize (0, 0,
@@ -371,64 +497,15 @@ procdir (char *name_buffer, struct stat *stat_data,
return directory;
}
/* Locate NAME in the dumpdir array DUMP.
Return pointer to the slot in the array, or NULL if not found */
const char *
dumpdir_locate (const char *dump, const char *name)
{
if (dump)
while (*dump)
{
/* Ignore 'R' (rename) and 'X' (tempname) entries, since they break
alphabetical ordering.
They normally do not occur in dumpdirs from the snapshot files,
but this function is also used by purge_directory, which operates
on a dumpdir from the archive, hence the need for this test. */
if (!strchr ("RX", *dump))
{
int rc = strcmp (dump + 1, name);
if (rc == 0)
return dump;
if (rc > 1)
break;
}
dump += strlen (dump) + 1;
}
return NULL;
}
/* Return size in bytes of the dumpdir array P */
size_t
dumpdir_size (const char *p)
{
size_t totsize = 0;
while (*p)
{
size_t size = strlen (p) + 1;
totsize += size;
p += size;
}
return totsize + 1;
}
static int
compare_dirnames (const void *first, const void *second)
{
char const *const *name1 = first;
char const *const *name2 = second;
return strcmp (*name1, *name2);
}
/* Compare dumpdir array from DIRECTORY with directory listing DIR and
build a new dumpdir template.
DIR must be returned by a previous call to savedir().
File names in DIRECTORY->contents must be sorted
File names in DIRECTORY->dump->contents must be sorted
alphabetically.
DIRECTORY->contents is replaced with the created template. Each entry is
DIRECTORY->dump is replaced with the created template. Each entry is
prefixed with ' ' if it was present in DUMP and with 'Y' otherwise. */
void
@@ -440,15 +517,15 @@ makedumpdir (struct directory *directory, const char *dir)
const char *p;
char const **array;
char *new_dump, *new_dump_ptr;
const char *dump;
struct dumpdir *dump;
if (directory->children == ALL_CHILDREN)
dump = NULL;
else if (DIR_IS_RENAMED (directory))
dump = directory->orig->icontents ?
directory->orig->icontents : directory->orig->contents;
dump = directory->orig->idump ?
directory->orig->idump : directory->orig->dump;
else
dump = directory->contents;
dump = directory->dump;
/* Count the size of DIR and the number of elements it contains */
dirsize = 0;
@@ -476,11 +553,10 @@ makedumpdir (struct directory *directory, const char *dir)
{
if (directory->tagfile)
*new_dump_ptr = strcmp (directory->tagfile, array[i]) == 0 ?
' ' : 'I';
' ' : 'I';
else
*new_dump_ptr = ' ';
new_dump_ptr++;
dump = loc + strlen (loc) + 1;
}
else if (directory->tagfile)
*new_dump_ptr++ = strcmp (directory->tagfile, array[i]) == 0 ?
@@ -493,13 +569,13 @@ makedumpdir (struct directory *directory, const char *dir)
;
}
*new_dump_ptr = 0;
directory->icontents = directory->contents;
directory->contents = new_dump;
directory->idump = directory->dump;
directory->dump = dumpdir_create0 (new_dump, NULL);
free (array);
}
/* Recursively scan the given directory. */
static char *
static const char *
scan_directory (char *dir, dev_t device)
{
char *dirp = savedir (dir); /* for scanning directory */
@@ -535,15 +611,17 @@ scan_directory (char *dir, dev_t device)
if (dirp && directory->children != NO_CHILDREN)
{
char *entry; /* directory entry being scanned */
char *entry; /* directory entry being scanned */
size_t entrylen; /* length of directory entry */
dumpdir_iter_t itr;
makedumpdir (directory, dirp);
for (entry = directory->contents;
(entrylen = strlen (entry)) != 0;
entry += entrylen + 1)
for (entry = dumpdir_first (directory->dump, 1, &itr);
entry;
entry = dumpdir_next (itr))
{
entrylen = strlen (entry);
if (name_buffer_size <= entrylen - 1 + name_length)
{
do
@@ -590,16 +668,17 @@ scan_directory (char *dir, dev_t device)
*entry = 'Y';
}
}
free (itr);
}
free (name_buffer);
if (dirp)
free (dirp);
return directory->contents;
return directory->dump ? directory->dump->contents : NULL;
}
char *
const char *
get_directory_contents (char *dir, dev_t device)
{
return scan_directory (dir, device);
@@ -1171,14 +1250,16 @@ write_directory_file_entry (void *entry, void *data)
fwrite (s, strlen (s) + 1, 1, fp);
fwrite (directory->name, strlen (directory->name) + 1, 1, fp);
if (directory->contents)
if (directory->dump)
{
char *p;
for (p = directory->contents; *p; p += strlen (p) + 1)
{
if (strchr ("YND", *p))
fwrite (p, strlen (p) + 1, 1, fp);
}
const char *p;
dumpdir_iter_t itr;
for (p = dumpdir_first (directory->dump, 0, &itr);
p;
p = dumpdir_next (itr))
fwrite (p, strlen (p) + 1, 1, fp);
free (itr);
}
fwrite ("\0\0", 2, 1, fp);
}
@@ -1366,6 +1447,7 @@ try_purge_directory (char const *directory_name)
char *current_dir;
char *cur, *arc, *p;
char *temp_stub = NULL;
struct dumpdir *dump;
if (!is_dumpdir (&current_stat_info))
return false;
@@ -1442,6 +1524,7 @@ try_purge_directory (char const *directory_name)
free (temp_stub);
/* Process deletes */
dump = dumpdir_create (current_stat_info.dumpdir);
p = NULL;
for (cur = current_dir; *cur; cur += strlen (cur) + 1)
{
@@ -1463,7 +1546,7 @@ try_purge_directory (char const *directory_name)
continue;
}
if (!(entry = dumpdir_locate (current_stat_info.dumpdir, cur))
if (!(entry = dumpdir_locate (dump, cur))
|| (*entry == 'D' && !S_ISDIR (st.st_mode))
|| (*entry == 'Y' && S_ISDIR (st.st_mode)))
{
@@ -1489,7 +1572,8 @@ try_purge_directory (char const *directory_name)
}
}
free (p);
dumpdir_free (dump);
free (current_dir);
return true;
}

View File

@@ -734,7 +734,7 @@ static void
add_hierarchy_to_namelist (struct name *name, dev_t device)
{
char *file_name = name->name;
char *buffer = get_directory_contents (file_name, device);
const char *buffer = get_directory_contents (file_name, device);
if (! buffer)
name->dir_contents = "\0\0\0\0";
@@ -746,7 +746,7 @@ add_hierarchy_to_namelist (struct name *name, dev_t device)
: NAME_FIELD_SIZE);
char *namebuf = xmalloc (allocated_length + 1);
/* FIXME: + 2 above? */
char *string;
const char *string;
size_t string_length;
int change_dir = name->change_dir;

View File

@@ -34,6 +34,8 @@ mkdir directory
genfile --file=directory/x
genfile --file=directory/y
sleep 1
tar -cf archive.1 -g db directory
mv directory/x directory/z

View File

@@ -38,6 +38,8 @@ awk 'BEGIN {
printf("NAME_PREFIX[%03d]\n", i);
}' < /dev/null | genfile --files-from -
sleep 1
echo "Initial dump"
tar cvf a0.tar -g a.sna a
mv a/b a/c

View File

@@ -34,6 +34,8 @@ genfile --file foo/bar/file.r
mkdir foo/bar/baz
genfile --file foo/bar/baz/file.z
sleep 1
echo "Creating base archive"
tar -g incr -cf arch.1 -v foo

View File

@@ -39,6 +39,8 @@ genfile --file foo/b/fileb
mkdir foo/c
genfile --file foo/c/filec
sleep 1
echo "First dump"
echo "First dump">&2
tar -g incr -cf arch.1 -v foo 2>tmperr