(dumpdir_locate,obstack_code_rename,purge_directory): Re-implement renaming. Introduce

X control code.
(make_tmp_dir_name): Remove
This commit is contained in:
Sergey Poznyakoff
2006-06-08 14:43:05 +00:00
parent 5591fa407a
commit 2d2e1d411e

View File

@@ -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 (&current_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--;