mirror of
https://github.com/octoleo/restic.git
synced 2024-11-26 06:46:34 +00:00
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
@ -383,7 +383,22 @@ func (arch *Archiver) dirWorker(ctx context.Context, wg *sync.WaitGroup, p *rest
|
|||||||
panic("invalid null subtree restic.ID")
|
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{}
|
node := &restic.Node{}
|
||||||
|
Loading…
Reference in New Issue
Block a user