diff options
author | Sergey Poznyakoff <gray@gnu.org> | 2020-02-15 10:57:35 +0200 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org> | 2020-02-15 11:09:18 +0200 |
commit | 41654f91f08eeff204d2ec2dabf2b81530060aaa (patch) | |
tree | d60e049deacea18c919b23eef9f413a0a75911cb /src/incremen.c | |
parent | 8d90723d306651648f19e32c2c1505aa9a152fe8 (diff) | |
download | tar-41654f91f08eeff204d2ec2dabf2b81530060aaa.tar.gz |
Fix handling of linked rename chains in incremental backups
* src/incremen.c: Change the meaning of the DIRF_RENAMED flag. Now it
marks a directory which is the last one in a chain of renames.
Regular renamed directories are recognized by their orig member being
non-NULL. Directories marked with DIRF_RENAMED start encoding of renames.
(procdir): Clear DIRF_RENAMED flag on directories which are origins for
renames.
(makedumpdir): Use the orig member to check if the directory is a
result of a rename.
(store_rename): Move the check for DIR_IS_RENAMED to the caller. Don't
clear the DIRF_RENAMED, it is not needed any more.
* tests/rename06.at: New test.
* tests/Makefile.am: Add rename06.at
* tests/testsuite.at: Likewise.
Diffstat (limited to 'src/incremen.c')
-rw-r--r-- | src/incremen.c | 81 |
1 files changed, 42 insertions, 39 deletions
diff --git a/src/incremen.c b/src/incremen.c index 42e59092..4265adbd 100644 --- a/src/incremen.c +++ b/src/incremen.c @@ -38,7 +38,15 @@ enum children #define DIRF_FOUND 0x0004 /* directory is found on fs */ #define DIRF_NEW 0x0008 /* directory is new (not found in the previous dump) */ -#define DIRF_RENAMED 0x0010 /* directory is renamed */ +#define DIRF_RENAMED 0x0010 /* Last target in a chain of renames */ +/* A directory which is renamed from another one is recognized by its + orig member, which is not-NULL. This directory may eventually be + the source for another rename, in which case it will be pointed to by + the orig member of another directory structure. The last directory + in such a chain of renames (the one which is not pointed to by any + other orig) is marked with the DIRF_RENAMED flag. This marks a starting + point from which append_incremental_renames starts encoding renames for + this chain. */ #define DIR_IS_INITED(d) ((d)->flags & DIRF_INIT) #define DIR_IS_NFS(d) ((d)->flags & DIRF_NFS) @@ -495,6 +503,7 @@ procdir (const char *name_buffer, struct tar_stat_info *st, quote_n (1, d->name))); directory->orig = d; DIR_SET_FLAG (directory, DIRF_RENAMED); + DIR_CLEAR_FLAG (d, DIRF_RENAMED); dirlist_replace_prefix (d->name, name_buffer); } directory->children = CHANGED_CHILDREN; @@ -537,6 +546,7 @@ procdir (const char *name_buffer, struct tar_stat_info *st, quote_n (1, d->name))); directory->orig = d; DIR_SET_FLAG (directory, DIRF_RENAMED); + DIR_CLEAR_FLAG (d, DIRF_RENAMED); dirlist_replace_prefix (d->name, name_buffer); } directory->children = CHANGED_CHILDREN; @@ -649,7 +659,7 @@ makedumpdir (struct directory *directory, const char *dir) if (directory->children == ALL_CHILDREN) dump = NULL; - else if (DIR_IS_RENAMED (directory)) + else if (directory->orig) dump = directory->orig->idump ? directory->orig->idump : directory->orig->dump; else @@ -878,44 +888,36 @@ obstack_code_rename (struct obstack *stk, char const *from, char const *to) static void store_rename (struct directory *dir, struct obstack *stk) { - if (DIR_IS_RENAMED (dir)) - { - struct directory *prev, *p; - - /* Detect eventual cycles and clear DIRF_RENAMED flag, so these entries - are ignored when hit by this function next time. - If the chain forms a cycle, prev points to the entry DIR is renamed - from. In this case it still retains DIRF_RENAMED flag, which will be - cleared in the 'else' branch below */ - for (prev = dir; prev && prev->orig != dir; prev = prev->orig) - DIR_CLEAR_FLAG (prev, DIRF_RENAMED); - - if (prev == NULL) - { - for (p = dir; p && p->orig; p = p->orig) - obstack_code_rename (stk, p->orig->name, p->name); - } - else - { - char *temp_name; - - DIR_CLEAR_FLAG (prev, DIRF_RENAMED); + struct directory *prev, *p; - /* Break the cycle by using a temporary name for one of its - elements. - 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); + /* Detect eventual cycles. If the chain forms a cycle, prev points to + the entry DIR is renamed from.*/ + for (prev = dir; prev && prev->orig != dir; prev = prev->orig) + ; - 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, "", prev->name); - free (temp_name); - } + if (prev == NULL) + { + for (p = dir; p && p->orig; p = p->orig) + obstack_code_rename (stk, p->orig->name, p->name); + } + else + { + char *temp_name; + + /* Break the cycle by using a temporary name for one of its + elements. + 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, "", prev->name); + free (temp_name); } } @@ -941,7 +943,8 @@ append_incremental_renames (struct directory *dir) size = 0; for (dp = dirhead; dp; dp = dp->next) - store_rename (dp, &stk); + if (DIR_IS_RENAMED (dp)) + store_rename (dp, &stk); /* FIXME: Is this the right thing to do when DIR is null? */ if (dir && obstack_object_size (&stk) != size) |