forked from TrueCloudLab/restic
restore: use case insensitive file name comparison on windows
This commit is contained in:
parent
013a6156bd
commit
168fc09d5f
4 changed files with 59 additions and 2 deletions
|
@ -480,11 +480,11 @@ func (res *Restorer) removeUnexpectedFiles(target, location string, expectedFile
|
||||||
|
|
||||||
keep := map[string]struct{}{}
|
keep := map[string]struct{}{}
|
||||||
for _, name := range expectedFilenames {
|
for _, name := range expectedFilenames {
|
||||||
keep[name] = struct{}{}
|
keep[toComparableFilename(name)] = struct{}{}
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, entry := range entries {
|
for _, entry := range entries {
|
||||||
if _, ok := keep[entry]; ok {
|
if _, ok := keep[toComparableFilename(entry)]; ok {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
10
internal/restorer/restorer_unix.go
Normal file
10
internal/restorer/restorer_unix.go
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
//go:build !windows
|
||||||
|
// +build !windows
|
||||||
|
|
||||||
|
package restorer
|
||||||
|
|
||||||
|
// toComparableFilename returns a filename suitable for equality checks. On Windows, it returns the
|
||||||
|
// uppercase version of the string. On all other systems, it returns the unmodified filename.
|
||||||
|
func toComparableFilename(path string) string {
|
||||||
|
return path
|
||||||
|
}
|
13
internal/restorer/restorer_windows.go
Normal file
13
internal/restorer/restorer_windows.go
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
//go:build windows
|
||||||
|
// +build windows
|
||||||
|
|
||||||
|
package restorer
|
||||||
|
|
||||||
|
import "strings"
|
||||||
|
|
||||||
|
// toComparableFilename returns a filename suitable for equality checks. On Windows, it returns the
|
||||||
|
// uppercase version of the string. On all other systems, it returns the unmodified filename.
|
||||||
|
func toComparableFilename(path string) string {
|
||||||
|
// apparently NTFS internally uppercases filenames for comparision
|
||||||
|
return strings.ToUpper(path)
|
||||||
|
}
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"math"
|
"math"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
|
"path/filepath"
|
||||||
"syscall"
|
"syscall"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
@ -539,3 +540,36 @@ func TestDirAttributeCombinationsOverwrite(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestRestoreDeleteCaseInsensitive(t *testing.T) {
|
||||||
|
repo := repository.TestRepository(t)
|
||||||
|
tempdir := rtest.TempDir(t)
|
||||||
|
|
||||||
|
sn, _ := saveSnapshot(t, repo, Snapshot{
|
||||||
|
Nodes: map[string]Node{
|
||||||
|
"anotherfile": File{Data: "content: file\n"},
|
||||||
|
},
|
||||||
|
}, noopGetGenericAttributes)
|
||||||
|
|
||||||
|
// should delete files that no longer exist in the snapshot
|
||||||
|
deleteSn, _ := saveSnapshot(t, repo, Snapshot{
|
||||||
|
Nodes: map[string]Node{
|
||||||
|
"AnotherfilE": File{Data: "content: file\n"},
|
||||||
|
},
|
||||||
|
}, noopGetGenericAttributes)
|
||||||
|
|
||||||
|
res := NewRestorer(repo, sn, Options{})
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
err := res.RestoreTo(ctx, tempdir)
|
||||||
|
rtest.OK(t, err)
|
||||||
|
|
||||||
|
res = NewRestorer(repo, deleteSn, Options{Delete: true})
|
||||||
|
err = res.RestoreTo(ctx, tempdir)
|
||||||
|
rtest.OK(t, err)
|
||||||
|
|
||||||
|
// anotherfile must still exist
|
||||||
|
_, err = os.Stat(filepath.Join(tempdir, "anotherfile"))
|
||||||
|
rtest.OK(t, err)
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue