From b94eed6d03bd9f34f1d6336af8ea682804eb15b4 Mon Sep 17 00:00:00 2001 From: Sergey Poznyakoff Date: Mon, 5 May 2008 21:30:57 +0000 Subject: [PATCH] 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. --- configure.ac | 2 +- src/common.h | 14 ++- src/compare.c | 2 +- src/incremen.c | 256 ++++++++++++++++++++++++++++++---------------- src/names.c | 4 +- tests/incr03.at | 2 + tests/incr04.at | 2 + tests/rename02.at | 2 + tests/rename03.at | 2 + 9 files changed, 194 insertions(+), 92 deletions(-) diff --git a/configure.ac b/configure.ac index fd4b2fa..27d2e32 100644 --- a/configure.ac +++ b/configure.ac @@ -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]) diff --git a/src/common.h b/src/common.h index 9e0a3fb..f43673b 100644 --- a/src/common.h +++ b/src/common.h @@ -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); diff --git a/src/compare.c b/src/compare.c index f372304..66205cb 100644 --- a/src/compare.c +++ b/src/compare.c @@ -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; diff --git a/src/incremen.c b/src/incremen.c index d75b844..372061d 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, 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 (¤t_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; } diff --git a/src/names.c b/src/names.c index 585ad39..73b8741 100644 --- a/src/names.c +++ b/src/names.c @@ -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; diff --git a/tests/incr03.at b/tests/incr03.at index 50b440f..08421bb 100644 --- a/tests/incr03.at +++ b/tests/incr03.at @@ -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 diff --git a/tests/incr04.at b/tests/incr04.at index 279d3bb..885b0ef 100644 --- a/tests/incr04.at +++ b/tests/incr04.at @@ -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 diff --git a/tests/rename02.at b/tests/rename02.at index 7feada0..2c8ca0d 100644 --- a/tests/rename02.at +++ b/tests/rename02.at @@ -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 diff --git a/tests/rename03.at b/tests/rename03.at index bbddea3..d08c9fc 100644 --- a/tests/rename03.at +++ b/tests/rename03.at @@ -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 -- 2.45.2