Merge pull request #1231 from restic/fix-local-datadir-create

local: Fix creating data dirs
This commit is contained in:
Alexander Neumann 2017-09-13 14:15:30 +02:00
commit e45a21b0b6
4 changed files with 116 additions and 1 deletions

View file

@ -57,11 +57,14 @@ func Open(cfg Config) (*Local, error) {
// if data dir exists, make sure that all subdirs also exist
datadir := be.Dirname(restic.Handle{Type: restic.DataFile})
if dirExists(datadir) {
debug.Log("datadir %v exists", datadir)
for _, d := range be.Paths() {
if _, err := filepath.Rel(datadir, d); err != nil {
if !fs.HasPathPrefix(datadir, d) {
debug.Log("%v is not subdir of datadir %v", d, datadir)
continue
}
debug.Log("MkdirAll %v", d)
err := fs.MkdirAll(d, backend.Modes.Dir)
if err != nil {
return nil, errors.Wrap(err, "MkdirAll")

View file

@ -104,6 +104,20 @@ func openclose(t testing.TB, dir string) {
}
}
func mkdir(t testing.TB, dir string) {
err := os.Mkdir(dir, 0700)
if err != nil {
t.Fatal(err)
}
}
func removeAll(t testing.TB, dir string) {
err := os.RemoveAll(dir)
if err != nil {
t.Fatal(err)
}
}
func TestOpenNotExistingDirectory(t *testing.T) {
dir, cleanup := TempDir(t)
defer cleanup()
@ -114,4 +128,9 @@ func TestOpenNotExistingDirectory(t *testing.T) {
openclose(t, dir)
empty(t, dir)
mkdir(t, filepath.Join(dir, "data"))
openclose(t, dir)
removeAll(t, filepath.Join(dir, "data"))
empty(t, dir)
}

View file

@ -0,0 +1,41 @@
package fs
import (
"path/filepath"
)
// HasPathPrefix returns true if p is a subdir of (or a file within) base. It
// assumes a file system which is case sensitive. For relative paths, false is
// returned.
func HasPathPrefix(base, p string) bool {
if filepath.VolumeName(base) != filepath.VolumeName(p) {
return false
}
if !filepath.IsAbs(base) || !filepath.IsAbs(p) {
return false
}
base = filepath.Clean(base)
p = filepath.Clean(p)
if base == p {
return true
}
for {
dir := filepath.Dir(p)
if base == dir {
return true
}
if p == dir {
break
}
p = dir
}
return false
}

View file

@ -0,0 +1,52 @@
package fs
import (
"path/filepath"
"runtime"
"testing"
)
func fromSlashAbs(p string) string {
if runtime.GOOS == "windows" {
if len(p) > 0 && p[0] == '/' {
p = "c:" + p
}
}
return filepath.FromSlash(p)
}
func TestHasPathPrefix(t *testing.T) {
var tests = []struct {
base, p string
result bool
}{
{"", "", false},
{"/", "", false},
{"/", "x", false},
{"x", "/", false},
{"/", "/x", true},
{"/x", "/y", false},
{"/home/user/foo", "/home", false},
{"/home/user/foo/", "/home", false},
{"/home/user/foo", "/home/", false},
{"/home/user/foo/", "/home/", false},
{"/home/user/foo", "/home/user/foo/bar", true},
{"/home/user/foo", "/home/user/foo/bar/baz/x/y/z", true},
{"/home/user/foo", "/home/user/foobar", false},
{"/home/user/Foo", "/home/user/foo/bar/baz", false},
{"/home/user/foo", "/home/user/Foo/bar/baz", false},
}
for _, test := range tests {
t.Run("", func(t *testing.T) {
base := fromSlashAbs(test.base)
p := fromSlashAbs(test.p)
result := HasPathPrefix(base, p)
if result != test.result {
t.Fatalf("wrong result for HasPathPrefix(%q, %q): want %v, got %v",
base, p, test.result, result)
}
})
}
}