Improve listed incremental dumps.

The modified algorithm tries to avoid dumping the same
directory twice and ensures the order of the directories
in the resulting archive is the same, whatever their order
on the command line.  It also fixes the operation of
--listed-incremental -C.

* gnulib.modules: Add canonicalize
* src/common.h (incremental_level): New global.
(check_exclusion_tags): first argument is const.
(get_directory_contents): Add third argument.
(zap_slashes, normalize_filename): New prototypes.
(chdir_count): New prototype.
(WARN_VERBOSE_WARNINGS): New define.
(WARN_ALL): Exclude WARN_VERBOSE_WARNINGS.
* src/compare.c (diff_dumpdir): Update the call to get_directory_contents.
* src/create.c (check_exclusion_tags): First argument is const.
Use ISSLASH and DIRECTORY_SEPARATOR instead of referring to '/'.

* src/incremen.c (struct directory): New member `caname'.
(hash_directory_name): Rename to hash_directory_canonical_name. Operate
on the canonical name.
(compare_directory_names): Rename to compare_directory_canonical_names.
Operate on the canonical name.
(make_directory): Take two arguments.
(free_directory): Free caname.
(attach_directory): Create caname.
(find_directory): Use caname for lookups.
(PD_VERBOSE): Remove.
(PD_FORCE_INIT): New define.
(procdir): First argument is const.
Reinitialize directory if PD_FORCE_INIT bit is set.
Do not use PD_VERBOSE or verbose_option for issuing warnings.
Rely on WARNOPT instead.
Always set *entry.
(scan_directory): Take three arguments. The third one is a boolean
which is true if the directory is explicitly mentioned on the command
line.
(get_directory_contents): Remove.  Use scan_directory instead.
All callers updated.
(read_directory_file): Truncate the file if --level=0 is given.
* src/misc.c: Include canonicalize.h
(zap_slashes, normalize_filename): New functions.
(chdir_count): New function.
* src/names.c (add_hierarchy_to_namelist): Take three arguments, as
get_directory_contents and scan_directory.
(collect_and_sort_names): Allow at most one -C, before file name
arguments.
Read directory file after eventual changing to another directory.
Avoid adding the same directory under different pathnames to
the list.
* src/tar.c: New option --level.

* tests/incr03.at, tests/incr04.at, tests/listed01.at,
tests/listed02.at, tests/rename01.at, tests/rename02.at,
tests/rename03.at: Update for new tar behavior.
* tests/multiv01.at: Do not use --listed-incremental.
This commit is contained in:
Sergey Poznyakoff
2009-08-07 14:52:55 +03:00
parent ac5288c1ac
commit 1bcbbcf1ff
16 changed files with 461 additions and 161 deletions

View File

@@ -1,7 +1,7 @@
/* Miscellaneous functions, not really specific to GNU tar.
Copyright (C) 1988, 1992, 1994, 1995, 1996, 1997, 1999, 2000, 2001,
2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
2003, 2004, 2005, 2006, 2007, 2009 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
@@ -25,6 +25,7 @@
#include <xgetcwd.h>
#include <unlinkdir.h>
#include <utimens.h>
#include <canonicalize.h>
#if HAVE_STROPTS_H
# include <stropts.h>
@@ -214,6 +215,27 @@ unquote_string (char *string)
*destination = '\0';
return result;
}
/* Zap trailing slashes. */
char *
zap_slashes (char *name)
{
char *q;
if (!name || *name == 0)
return name;
q = name + strlen (name) - 1;
while (q > name && ISSLASH (*q))
*q-- = '\0';
return name;
}
char *
normalize_filename (const char *name)
{
return zap_slashes (canonicalize_filename_mode (name, CAN_MISSING));
}
/* Handling numbers. */
@@ -532,17 +554,25 @@ struct wd
static struct wd *wd;
/* The number of working directories in the vector. */
static size_t wds;
static size_t wd_count;
/* The allocated size of the vector. */
static size_t wd_alloc;
int
chdir_count ()
{
if (wd_count == 0)
return wd_count;
return wd_count - 1;
}
/* DIR is the operand of a -C option; add it to vector of chdir targets,
and return the index of its location. */
int
chdir_arg (char const *dir)
{
if (wds == wd_alloc)
if (wd_count == wd_alloc)
{
if (wd_alloc == 0)
{
@@ -552,11 +582,11 @@ chdir_arg (char const *dir)
else
wd = x2nrealloc (wd, &wd_alloc, sizeof *wd);
if (! wds)
if (! wd_count)
{
wd[wds].name = ".";
wd[wds].saved = 0;
wds++;
wd[wd_count].name = ".";
wd[wd_count].saved = 0;
wd_count++;
}
}
@@ -568,12 +598,12 @@ chdir_arg (char const *dir)
for (dir += 2; ISSLASH (*dir); dir++)
continue;
if (! dir[dir[0] == '.'])
return wds - 1;
return wd_count - 1;
}
wd[wds].name = dir;
wd[wds].saved = 0;
return wds++;
wd[wd_count].name = dir;
wd[wd_count].saved = 0;
return wd_count++;
}
/* Change to directory I. If I is 0, change to the initial working