forked from TrueCloudLab/restic
backup: support specifying volume instead of path on Windows
"C:" (volume name) versus "C:\" (path)
This commit is contained in:
parent
a0f2dfbc19
commit
4fcedb4bae
3 changed files with 85 additions and 1 deletions
19
changelog/unreleased/issue-2004
Normal file
19
changelog/unreleased/issue-2004
Normal file
|
@ -0,0 +1,19 @@
|
|||
Bugfix: Correctly handle passing volume name to `backup` command
|
||||
|
||||
On Windows, when the specified backup target only included the volume
|
||||
name without a trailing slash, for example, `C:`, then restoring the
|
||||
resulting snapshot would result in an error. Note that using `C:\`
|
||||
as backup target worked correctly.
|
||||
|
||||
Specifying volume names now works correctly.
|
||||
|
||||
To restore snapshots created before this bugfix, use the `<snapshot>:<subpath>`
|
||||
syntax. For a snapshot with ID `12345678` and a backup of `C:`, the following
|
||||
command can be used:
|
||||
|
||||
```
|
||||
restic restore 12345678:/C/C:./ --target output/folder
|
||||
```
|
||||
|
||||
https://github.com/restic/restic/issues/2004
|
||||
https://github.com/restic/restic/pull/5028
|
|
@ -715,7 +715,12 @@ func resolveRelativeTargets(filesys fs.FS, targets []string) ([]string, error) {
|
|||
debug.Log("targets before resolving: %v", targets)
|
||||
result := make([]string, 0, len(targets))
|
||||
for _, target := range targets {
|
||||
target = filesys.Clean(target)
|
||||
if target != "" && filesys.VolumeName(target) == target {
|
||||
// special case to allow users to also specify a volume name "C:" instead of a path "C:\"
|
||||
target = target + filesys.Separator()
|
||||
} else {
|
||||
target = filesys.Clean(target)
|
||||
}
|
||||
pc, _ := pathComponents(filesys, target, false)
|
||||
if len(pc) > 0 {
|
||||
result = append(result, target)
|
||||
|
|
|
@ -1448,6 +1448,66 @@ func TestArchiverSnapshot(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestResolveRelativeTargetsSpecial(t *testing.T) {
|
||||
var tests = []struct {
|
||||
name string
|
||||
targets []string
|
||||
expected []string
|
||||
win bool
|
||||
}{
|
||||
{
|
||||
name: "basic relative path",
|
||||
targets: []string{filepath.FromSlash("some/path")},
|
||||
expected: []string{filepath.FromSlash("some/path")},
|
||||
},
|
||||
{
|
||||
name: "partial relative path",
|
||||
targets: []string{filepath.FromSlash("../some/path")},
|
||||
expected: []string{filepath.FromSlash("../some/path")},
|
||||
},
|
||||
{
|
||||
name: "basic absolute path",
|
||||
targets: []string{filepath.FromSlash("/some/path")},
|
||||
expected: []string{filepath.FromSlash("/some/path")},
|
||||
},
|
||||
{
|
||||
name: "volume name",
|
||||
targets: []string{"C:"},
|
||||
expected: []string{"C:\\"},
|
||||
win: true,
|
||||
},
|
||||
{
|
||||
name: "volume root path",
|
||||
targets: []string{"C:\\"},
|
||||
expected: []string{"C:\\"},
|
||||
win: true,
|
||||
},
|
||||
{
|
||||
name: "UNC path",
|
||||
targets: []string{"\\\\server\\volume"},
|
||||
expected: []string{"\\\\server\\volume\\"},
|
||||
win: true,
|
||||
},
|
||||
{
|
||||
name: "UNC path with trailing slash",
|
||||
targets: []string{"\\\\server\\volume\\"},
|
||||
expected: []string{"\\\\server\\volume\\"},
|
||||
win: true,
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
if test.win && runtime.GOOS != "windows" {
|
||||
t.Skip("skip test on unix")
|
||||
}
|
||||
|
||||
targets, err := resolveRelativeTargets(&fs.Local{}, test.targets)
|
||||
rtest.OK(t, err)
|
||||
rtest.Equals(t, test.expected, targets)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestArchiverSnapshotSelect(t *testing.T) {
|
||||
var tests = []struct {
|
||||
name string
|
||||
|
|
Loading…
Reference in a new issue