From ea017a49c358537c1ed9d785308642ce0b06fa03 Mon Sep 17 00:00:00 2001 From: Alexander Neumann Date: Fri, 25 Aug 2017 21:26:04 +0200 Subject: [PATCH 1/3] local: Add test for #1167 It was discovered that restic creates directories when a non-existing directory is specified as a local repository. --- internal/backend/local/local.go | 2 +- internal/backend/local/local_test.go | 56 ++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+), 1 deletion(-) diff --git a/internal/backend/local/local.go b/internal/backend/local/local.go index 27be5a2b7..e7340fc08 100644 --- a/internal/backend/local/local.go +++ b/internal/backend/local/local.go @@ -35,7 +35,7 @@ func Open(cfg Config) (*Local, error) { be := &Local{Config: cfg, Layout: l} - // create paths for data and refs. MkdirAll does nothing if the directory already exists. + // if data dir exists, make sure that all subdirs also exist for _, d := range be.Paths() { err := fs.MkdirAll(d, backend.Modes.Dir) if err != nil { diff --git a/internal/backend/local/local_test.go b/internal/backend/local/local_test.go index a296fff5e..1d15f5ff9 100644 --- a/internal/backend/local/local_test.go +++ b/internal/backend/local/local_test.go @@ -2,6 +2,8 @@ package local_test import ( "io/ioutil" + "os" + "path/filepath" "testing" "github.com/restic/restic/internal/backend/local" @@ -59,3 +61,57 @@ func TestBackend(t *testing.T) { func BenchmarkBackend(t *testing.B) { newTestSuite(t).RunBenchmarks(t) } + +func readdirnames(t testing.TB, dir string) []string { + f, err := os.Open(dir) + if err != nil { + t.Fatal(err) + } + + entries, err := f.Readdirnames(-1) + if err != nil { + t.Fatal(err) + } + + err = f.Close() + if err != nil { + t.Fatal(err) + } + + return entries +} + +func empty(t testing.TB, dir string) { + entries := readdirnames(t, dir) + if len(entries) != 0 { + t.Fatalf("directory %v is not empty, contains: %v", dir, entries) + } +} + +func openclose(t testing.TB, dir string) { + cfg := local.Config{Path: dir} + + be, err := local.Open(cfg) + if err != nil { + t.Logf("Open returned error %v", err) + } + + if be != nil { + err = be.Close() + if err != nil { + t.Logf("Close returned error %v", err) + } + } +} + +func TestOpenNotExistingDirectory(t *testing.T) { + dir, cleanup := TempDir(t) + defer cleanup() + + // local.Open must not create any files dirs in the repo + openclose(t, filepath.Join(dir, "repo")) + empty(t, dir) + + openclose(t, dir) + empty(t, dir) +} From 3686b1ffe5e467fb79384df20d38bd08ce3cda89 Mon Sep 17 00:00:00 2001 From: Alexander Neumann Date: Sun, 27 Aug 2017 20:38:00 +0200 Subject: [PATCH 2/3] local: Create directories below data/ if it exists --- internal/backend/local/local.go | 34 +++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/internal/backend/local/local.go b/internal/backend/local/local.go index e7340fc08..d2dedacbb 100644 --- a/internal/backend/local/local.go +++ b/internal/backend/local/local.go @@ -25,6 +25,25 @@ var _ restic.Backend = &Local{} const defaultLayout = "default" +// dirExists returns true if the name exists and is a directory. +func dirExists(name string) bool { + f, err := fs.Open(name) + if err != nil { + return false + } + + fi, err := f.Stat() + if err != nil { + return false + } + + if err = f.Close(); err != nil { + return false + } + + return fi.IsDir() +} + // Open opens the local backend as specified by config. func Open(cfg Config) (*Local, error) { debug.Log("open local backend at %v (layout %q)", cfg.Path, cfg.Layout) @@ -36,10 +55,17 @@ func Open(cfg Config) (*Local, error) { be := &Local{Config: cfg, Layout: l} // if data dir exists, make sure that all subdirs also exist - for _, d := range be.Paths() { - err := fs.MkdirAll(d, backend.Modes.Dir) - if err != nil { - return nil, errors.Wrap(err, "MkdirAll") + datadir := be.Dirname(restic.Handle{Type: restic.DataFile}) + if dirExists(datadir) { + for _, d := range be.Paths() { + if _, err := filepath.Rel(datadir, d); err != nil { + continue + } + + err := fs.MkdirAll(d, backend.Modes.Dir) + if err != nil { + return nil, errors.Wrap(err, "MkdirAll") + } } } From f9a934759ff5dfc33bdb72b0eb462ad41568d06d Mon Sep 17 00:00:00 2001 From: Alexander Neumann Date: Sun, 27 Aug 2017 20:52:32 +0200 Subject: [PATCH 3/3] sftp: Improve error handling for non-existing dir --- internal/backend/sftp/sftp.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/internal/backend/sftp/sftp.go b/internal/backend/sftp/sftp.go index a85b9b315..9961ac65c 100644 --- a/internal/backend/sftp/sftp.go +++ b/internal/backend/sftp/sftp.go @@ -141,6 +141,10 @@ func (r *SFTP) checkDataSubdirs() error { // check if all paths for data/ exist entries, err := r.c.ReadDir(datadir) + if r.IsNotExist(err) { + return nil + } + if err != nil { return err }