(dumpdir_locate,obstack_code_rename,purge_directory): Re-implement renaming. Introduce
X control code. (make_tmp_dir_name): Remove
This commit is contained in:
210
src/incremen.c
210
src/incremen.c
@@ -343,11 +343,12 @@ dumpdir_locate (const char *dump, const char *name)
|
||||
if (dump)
|
||||
while (*dump)
|
||||
{
|
||||
/* Ignore 'R' (rename) entries, since they break alphabetical ordering.
|
||||
/* 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 (*dump != 'R')
|
||||
if (!strchr ("RX", *dump))
|
||||
{
|
||||
int rc = strcmp (dump + 1, name);
|
||||
if (rc == 0)
|
||||
@@ -556,49 +557,6 @@ get_directory_contents (char *dir_name, dev_t device)
|
||||
}
|
||||
|
||||
|
||||
static bool
|
||||
try_pos (char *name, int pos, const char *dumpdir)
|
||||
{
|
||||
int i;
|
||||
static char namechars[] =
|
||||
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
||||
|
||||
if (pos > 0)
|
||||
for (i = 0; i < sizeof namechars; i++)
|
||||
{
|
||||
name[pos] = namechars[i];
|
||||
if (!dumpdir_locate (dumpdir, name)
|
||||
|| try_pos (name, pos-1, dumpdir))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool
|
||||
create_temp_name (char *name, const char *dumpdir)
|
||||
{
|
||||
size_t pos = strlen (name) - 6;
|
||||
return try_pos (name + pos, 5, dumpdir);
|
||||
}
|
||||
|
||||
char *
|
||||
make_tmp_dir_name (const char *name)
|
||||
{
|
||||
char *dirname = dir_name (name);
|
||||
char *tmp_name = NULL;
|
||||
struct directory *dir = find_directory (dirname);
|
||||
|
||||
tmp_name = new_name (dirname, "000000");
|
||||
if (!create_temp_name (tmp_name, dir ? dir->contents : NULL))
|
||||
{
|
||||
free (tmp_name);
|
||||
tmp_name = NULL;
|
||||
}
|
||||
free (dirname);
|
||||
return tmp_name;
|
||||
}
|
||||
|
||||
static void
|
||||
obstack_code_rename (struct obstack *stk, char *from, char *to)
|
||||
{
|
||||
@@ -639,14 +597,17 @@ rename_handler (void *data, void *proc_data)
|
||||
|
||||
/* Break the cycle by using a temporary name for one of its
|
||||
elements.
|
||||
FIXME: Leave the choice of the name to the extractor. */
|
||||
temp_name = make_tmp_dir_name (dir->name);
|
||||
obstack_code_rename (stk, dir->name, temp_name);
|
||||
First, create a temp name stub entry. */
|
||||
temp_name = dir_name (dir->name);
|
||||
obstack_1grow (stk, 'X');
|
||||
obstack_grow (stk, temp_name, strlen (temp_name) + 1);
|
||||
|
||||
obstack_code_rename (stk, dir->name, "");
|
||||
|
||||
for (p = dir; p != prev; p = p->orig)
|
||||
obstack_code_rename (stk, p->orig->name, p->name);
|
||||
|
||||
obstack_code_rename (stk, temp_name, prev->name);
|
||||
obstack_code_rename (stk, "", prev->name);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
@@ -1173,50 +1134,160 @@ is_dumpdir (struct tar_stat_info *stat_info)
|
||||
return stat_info->is_dumpdir;
|
||||
}
|
||||
|
||||
static bool
|
||||
dumpdir_ok (char *dumpdir)
|
||||
{
|
||||
char *p;
|
||||
int has_tempdir = 0;
|
||||
int expect = 0;
|
||||
|
||||
for (p = dumpdir; *p; p += strlen (p) + 1)
|
||||
{
|
||||
if (expect && *p != expect)
|
||||
{
|
||||
ERROR ((0, 0,
|
||||
_("Malformed dumpdir: expected '%c' but found %#3o"),
|
||||
expect, *p));
|
||||
return false;
|
||||
}
|
||||
switch (*p)
|
||||
{
|
||||
case 'X':
|
||||
if (has_tempdir)
|
||||
{
|
||||
ERROR ((0, 0,
|
||||
_("Malformed dumpdir: 'X' duplicated")));
|
||||
return false;
|
||||
}
|
||||
else
|
||||
has_tempdir = 1;
|
||||
break;
|
||||
|
||||
case 'R':
|
||||
if (p[1] == 0)
|
||||
{
|
||||
if (!has_tempdir)
|
||||
{
|
||||
ERROR ((0, 0,
|
||||
_("Malformed dumpdir: empty name in 'R'")));
|
||||
return false;
|
||||
}
|
||||
else
|
||||
has_tempdir = 0;
|
||||
}
|
||||
expect = 'T';
|
||||
break;
|
||||
|
||||
case 'T':
|
||||
if (expect != 'T')
|
||||
{
|
||||
ERROR ((0, 0,
|
||||
_("Malformed dumpdir: 'T' not preceeded by 'R'")));
|
||||
return false;
|
||||
}
|
||||
if (p[1] == 0 && !has_tempdir)
|
||||
{
|
||||
ERROR ((0, 0,
|
||||
_("Malformed dumpdir: empty name in 'T'")));
|
||||
return false;
|
||||
}
|
||||
expect = 0;
|
||||
break;
|
||||
|
||||
case 'N':
|
||||
case 'Y':
|
||||
case 'D':
|
||||
break;
|
||||
|
||||
default:
|
||||
/* FIXME: bail out? */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (expect)
|
||||
{
|
||||
ERROR ((0, 0,
|
||||
_("Malformed dumpdir: expected '%c' but found end of data"),
|
||||
expect));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (has_tempdir)
|
||||
WARN ((0, 0, _("Malformed dumpdir: 'X' never used")));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Examine the directories under directory_name and delete any
|
||||
files that were not there at the time of the back-up. */
|
||||
void
|
||||
purge_directory (char const *directory_name)
|
||||
static bool
|
||||
try_purge_directory (char const *directory_name)
|
||||
{
|
||||
char *current_dir;
|
||||
char *cur, *arc, *p;
|
||||
|
||||
char *temp_stub = NULL;
|
||||
|
||||
if (!is_dumpdir (¤t_stat_info))
|
||||
{
|
||||
skip_member ();
|
||||
return;
|
||||
}
|
||||
return false;
|
||||
|
||||
current_dir = savedir (directory_name);
|
||||
|
||||
if (!current_dir)
|
||||
{
|
||||
/* The directory doesn't exist now. It'll be created. In any
|
||||
case, we don't have to delete any files out of it. */
|
||||
|
||||
skip_member ();
|
||||
return;
|
||||
}
|
||||
/* The directory doesn't exist now. It'll be created. In any
|
||||
case, we don't have to delete any files out of it. */
|
||||
return false;
|
||||
|
||||
/* Verify if dump directory is sane */
|
||||
if (!dumpdir_ok (current_stat_info.dumpdir))
|
||||
return false;
|
||||
|
||||
/* Process renames */
|
||||
for (arc = current_stat_info.dumpdir; *arc; arc += strlen (arc) + 1)
|
||||
{
|
||||
if (*arc == 'R')
|
||||
if (*arc == 'X')
|
||||
{
|
||||
#define TEMP_DIR_TEMPLATE "tar.XXXXXX"
|
||||
size_t len = strlen (arc + 1);
|
||||
temp_stub = xrealloc (temp_stub, len + 1 + sizeof TEMP_DIR_TEMPLATE);
|
||||
memcpy (temp_stub, arc + 1, len);
|
||||
temp_stub[len] = '/';
|
||||
memcpy (temp_stub + len + 1, TEMP_DIR_TEMPLATE,
|
||||
sizeof TEMP_DIR_TEMPLATE);
|
||||
if (!mkdtemp (temp_stub))
|
||||
{
|
||||
ERROR ((0, errno,
|
||||
_("Cannot create temporary directory using template %s"),
|
||||
quote (temp_stub)));
|
||||
free (temp_stub);
|
||||
free (current_dir);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (*arc == 'R')
|
||||
{
|
||||
char *src, *dst;
|
||||
src = arc + 1;
|
||||
arc += strlen (arc) + 1;
|
||||
dst = arc + 1;
|
||||
|
||||
if (*src == 0)
|
||||
src = temp_stub;
|
||||
else if (*dst == 0)
|
||||
dst = temp_stub;
|
||||
|
||||
if (!rename_directory (src, dst))
|
||||
{
|
||||
free (temp_stub);
|
||||
free (current_dir);
|
||||
/* FIXME: Make sure purge_directory(dst) will return
|
||||
immediately */
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
free (temp_stub);
|
||||
|
||||
/* Process deletes */
|
||||
p = NULL;
|
||||
@@ -1267,8 +1338,16 @@ purge_directory (char const *directory_name)
|
||||
free (p);
|
||||
|
||||
free (current_dir);
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
purge_directory (char const *directory_name)
|
||||
{
|
||||
if (!try_purge_directory (directory_name))
|
||||
skip_member ();
|
||||
}
|
||||
|
||||
void
|
||||
list_dumpdir (char *buffer, size_t size)
|
||||
{
|
||||
@@ -1281,6 +1360,7 @@ list_dumpdir (char *buffer, size_t size)
|
||||
case 'D':
|
||||
case 'R':
|
||||
case 'T':
|
||||
case 'X':
|
||||
fprintf (stdlis, "%c ", *buffer);
|
||||
buffer++;
|
||||
size--;
|
||||
|
||||
Reference in New Issue
Block a user