From 5bf222859659700b37c10ffc553c91c7fc29818f Mon Sep 17 00:00:00 2001 From: Alexander Neumann Date: Mon, 11 Sep 2017 21:29:37 +0200 Subject: [PATCH] local: Fix creating data dirs --- internal/backend/local/local.go | 5 +++- internal/fs/path_prefix.go | 41 ++++++++++++++++++++++++++ internal/fs/path_prefix_test.go | 52 +++++++++++++++++++++++++++++++++ 3 files changed, 97 insertions(+), 1 deletion(-) create mode 100644 internal/fs/path_prefix.go create mode 100644 internal/fs/path_prefix_test.go diff --git a/internal/backend/local/local.go b/internal/backend/local/local.go index d2dedacbb..fd43332a8 100644 --- a/internal/backend/local/local.go +++ b/internal/backend/local/local.go @@ -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") diff --git a/internal/fs/path_prefix.go b/internal/fs/path_prefix.go new file mode 100644 index 000000000..d5398db12 --- /dev/null +++ b/internal/fs/path_prefix.go @@ -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 +} diff --git a/internal/fs/path_prefix_test.go b/internal/fs/path_prefix_test.go new file mode 100644 index 000000000..dfdc69522 --- /dev/null +++ b/internal/fs/path_prefix_test.go @@ -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) + } + }) + } +}