From: Sergey Poznyakoff Date: Thu, 8 Jun 2006 14:43:05 +0000 (+0000) Subject: (dumpdir_locate,obstack_code_rename,purge_directory): Re-implement renaming. Introduce X-Git-Url: https://git.dogcows.com/gitweb?p=chaz%2Ftar;a=commitdiff_plain;h=2d2e1d411e09126a7ed82ad774e24082914a51ce (dumpdir_locate,obstack_code_rename,purge_directory): Re-implement renaming. Introduce X control code. (make_tmp_dir_name): Remove --- diff --git a/src/incremen.c b/src/incremen.c index 354caf4..c0d515d 100644 --- a/src/incremen.c +++ b/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--;