forked from TrueCloudLab/restic
Resolve name collisions
At the moment when two items to be saved have the same directory name, restic only saves the first one to the repo. Let's say we have a structure like this: dir1 └── subdir └── file dir2 └── subdir └── file When restic is run on `dir1/subdir` and `dir2/subdir`, it will only save the first `subdir`: $ restic backup dir1/subdir dir2/subdir [...] $ restic ls -l latest drwxr-xr-x 1000 100 0 2017-08-27 20:56:39 /subdir -rw-r--r-- 1000 100 17 2017-08-27 20:56:39 /subdir/file That's obviously a bad thing, caused by an early decision to strip the full path to the files/dirs to save and only leave the last directory. This commit partly resolves this by handling colliding names and resolving the conflicts. Restic will now append a counter to the file (`-123`) until the conflict is resolved. So in the example above, we'll end up with the following structure: $ restic ls -l latest drwxr-xr-x 1000 100 0 2017-08-27 20:56:39 /subdir -rw-r--r-- 1000 100 17 2017-08-27 20:56:39 /subdir/file drwxr-xr-x 1000 100 0 2017-08-27 20:56:46 /subdir-1 -rw-r--r-- 1000 100 17 2017-08-27 20:56:46 /subdir-1/file This partly addresses #549 and closes #1179. At first I thought that the obvious correction would be to archive the full path. But it turns out that collisions may still occur: Suppose you have a file named `foo` in the current directory, and the parent directory also contains a file `foo`. Archiving these with restic also causes a collision, since restic strips the `../` from the first file: $ restic backup ../foo foo This also happens with `tar`, which does not handle the collision and will happily archive two files called `foo`. So, the best way forward is to handle name collisions and archive the whole path. The latter will be tackled in a separate PR.
This commit is contained in:
parent
2444522243
commit
83eb075e3a
1 changed files with 16 additions and 1 deletions
|
@ -383,7 +383,22 @@ func (arch *Archiver) dirWorker(ctx context.Context, wg *sync.WaitGroup, p *rest
|
|||
panic("invalid null subtree restic.ID")
|
||||
}
|
||||
}
|
||||
tree.Insert(node)
|
||||
|
||||
// insert node into tree, resolve name collisions
|
||||
name := node.Name
|
||||
i := 0
|
||||
for {
|
||||
i++
|
||||
err := tree.Insert(node)
|
||||
if err == nil {
|
||||
break
|
||||
}
|
||||
|
||||
newName := fmt.Sprintf("%v-%d", name, i)
|
||||
fmt.Fprintf(os.Stderr, "%v: name collision for %q, renaming to %q\n", filepath.Dir(node.Path), node.Name, newName)
|
||||
node.Name = newName
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
node := &restic.Node{}
|
||||
|
|
Loading…
Reference in a new issue