From 5096f3b49187ec864987e5f7feab86ac1846ee03 Mon Sep 17 00:00:00 2001 From: Garry McNulty Date: Mon, 11 Mar 2019 19:31:52 +0000 Subject: [PATCH 1/4] fs: Update directory check in reader tests (#2063) --- internal/fs/fs_reader_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/fs/fs_reader_test.go b/internal/fs/fs_reader_test.go index 93e8b35ef..e5de286bb 100644 --- a/internal/fs/fs_reader_test.go +++ b/internal/fs/fs_reader_test.go @@ -151,8 +151,8 @@ func verifyDirectoryContentsFI(t testing.TB, fs FS, dir string, want []os.FileIn } func checkFileInfo(t testing.TB, fi os.FileInfo, filename string, modtime time.Time, mode os.FileMode, isdir bool) { - if fi.IsDir() { - t.Errorf("IsDir returned true, want false") + if fi.IsDir() != isdir { + t.Errorf("IsDir returned %t, want %t", fi.IsDir(), isdir) } if fi.Mode() != mode { From f7f14cf8c9612bd0da48ec0313c648f9ad23b2ee Mon Sep 17 00:00:00 2001 From: Garry McNulty Date: Sun, 28 Apr 2019 20:55:31 +0100 Subject: [PATCH 2/4] fs: Add file info base name check in reader tests (#2063) --- internal/fs/fs_reader_test.go | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/internal/fs/fs_reader_test.go b/internal/fs/fs_reader_test.go index e5de286bb..6d7bf4df3 100644 --- a/internal/fs/fs_reader_test.go +++ b/internal/fs/fs_reader_test.go @@ -4,6 +4,7 @@ import ( "bytes" "io/ioutil" "os" + "path" "sort" "strings" "testing" @@ -163,8 +164,12 @@ func checkFileInfo(t testing.TB, fi os.FileInfo, filename string, modtime time.T t.Errorf("ModTime() returned wrong value, want %v, got %v", modtime, fi.ModTime()) } - if fi.Name() != filename { - t.Errorf("Name() returned wrong value, want %q, got %q", filename, fi.Name()) + if path.Base(fi.Name()) != fi.Name() { + t.Errorf("Name() returned is not base, want %q, got %q", path.Base(fi.Name()), fi.Name()) + } + + if fi.Name() != path.Base(filename) { + t.Errorf("Name() returned wrong value, want %q, got %q", path.Base(filename), fi.Name()) } } From 8066195e6e479c0048edb8bcbcebe035fe1c9ab2 Mon Sep 17 00:00:00 2001 From: Garry McNulty Date: Sun, 28 Apr 2019 20:58:10 +0100 Subject: [PATCH 3/4] fs: Handle absolute pathname for --stdin-filename Return valid directory info from Lstat() for parent directories of the specified filename. Previously only "/" and "." were valid directories. Also set directory mode as this is checked by archiver. Closes #2063 --- changelog/unreleased/issue-2063 | 6 +++ internal/fs/fs_reader.go | 27 +++++++++++--- internal/fs/fs_reader_test.go | 65 +++++++++++++++++++++++++++++++-- 3 files changed, 88 insertions(+), 10 deletions(-) create mode 100644 changelog/unreleased/issue-2063 diff --git a/changelog/unreleased/issue-2063 b/changelog/unreleased/issue-2063 new file mode 100644 index 000000000..3840da5be --- /dev/null +++ b/changelog/unreleased/issue-2063 @@ -0,0 +1,6 @@ +Bugfix: Allow absolute path for filename when backing up from stdin + +When backing up from stdin, handle directory path for `--stdin-filename`. +This can be used to specify the full path for the backed-up file. + +https://github.com/restic/restic/issues/2063 diff --git a/internal/fs/fs_reader.go b/internal/fs/fs_reader.go index 27fc46eb6..91fedb263 100644 --- a/internal/fs/fs_reader.go +++ b/internal/fs/fs_reader.go @@ -103,17 +103,32 @@ func (fs *Reader) Stat(name string) (os.FileInfo, error) { // describes the symbolic link. Lstat makes no attempt to follow the link. // If there is an error, it will be of type *PathError. func (fs *Reader) Lstat(name string) (os.FileInfo, error) { + getDirInfo := func(name string) os.FileInfo { + fi := fakeFileInfo{ + name: fs.Base(name), + size: 0, + mode: os.ModeDir | 0755, + modtime: time.Now(), + } + return fi + } + switch name { case fs.Name: return fs.fi(), nil case "/", ".": - fi := fakeFileInfo{ - name: name, - size: 0, - mode: 0755, - modtime: time.Now(), + return getDirInfo(name), nil + } + + dir := fs.Dir(fs.Name) + for { + if dir == "/" || dir == "." { + break } - return fi, nil + if name == dir { + return getDirInfo(name), nil + } + dir = fs.Dir(dir) } return nil, os.ErrNotExist diff --git a/internal/fs/fs_reader_test.go b/internal/fs/fs_reader_test.go index 6d7bf4df3..bb45732f3 100644 --- a/internal/fs/fs_reader_test.go +++ b/internal/fs/fs_reader_test.go @@ -270,7 +270,7 @@ func TestFSReader(t *testing.T) { t.Fatal(err) } - checkFileInfo(t, fi, "/", time.Time{}, 0755, false) + checkFileInfo(t, fi, "/", time.Time{}, os.ModeDir|0755, true) }, }, { @@ -281,7 +281,16 @@ func TestFSReader(t *testing.T) { t.Fatal(err) } - checkFileInfo(t, fi, ".", time.Time{}, 0755, false) + checkFileInfo(t, fi, ".", time.Time{}, os.ModeDir|0755, true) + }, + }, + { + name: "dir/Lstat-error-not-exist", + f: func(t *testing.T, fs FS) { + _, err := fs.Lstat("other") + if err != os.ErrNotExist { + t.Fatal(err) + } }, }, { @@ -292,7 +301,7 @@ func TestFSReader(t *testing.T) { t.Fatal(err) } - checkFileInfo(t, fi, "/", time.Time{}, 0755, false) + checkFileInfo(t, fi, "/", time.Time{}, os.ModeDir|0755, true) }, }, { @@ -303,7 +312,7 @@ func TestFSReader(t *testing.T) { t.Fatal(err) } - checkFileInfo(t, fi, ".", time.Time{}, 0755, false) + checkFileInfo(t, fi, ".", time.Time{}, os.ModeDir|0755, true) }, }, } @@ -324,6 +333,54 @@ func TestFSReader(t *testing.T) { } } +func TestFSReaderDir(t *testing.T) { + data := test.Random(55, 1<<18+588) + now := time.Now() + + var tests = []struct { + name string + filename string + }{ + { + name: "Lstat-absolute", + filename: "/path/to/foobar", + }, + { + name: "Lstat-relative", + filename: "path/to/foobar", + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + fs := &Reader{ + Name: test.filename, + ReadCloser: ioutil.NopCloser(bytes.NewReader(data)), + + Mode: 0644, + Size: int64(len(data)), + ModTime: now, + } + + dir := path.Dir(fs.Name) + for { + if dir == "/" || dir == "." { + break + } + + fi, err := fs.Lstat(dir) + if err != nil { + t.Fatal(err) + } + + checkFileInfo(t, fi, dir, time.Time{}, os.ModeDir|0755, true) + + dir = path.Dir(dir) + } + }) + } +} + func TestFSReaderMinFileSize(t *testing.T) { var tests = []struct { name string From 4429a66b5f896c539e67e2f90df2bfe167563268 Mon Sep 17 00:00:00 2001 From: Garry McNulty Date: Sun, 28 Apr 2019 20:59:35 +0100 Subject: [PATCH 4/4] backup: Convert relative pathname for --stdin-filename to absolute (#2063) --- cmd/restic/cmd_backup.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/cmd/restic/cmd_backup.go b/cmd/restic/cmd_backup.go index a37d3f168..83a4038ad 100644 --- a/cmd/restic/cmd_backup.go +++ b/cmd/restic/cmd_backup.go @@ -8,6 +8,7 @@ import ( "io" "io/ioutil" "os" + "path" "path/filepath" "strconv" "strings" @@ -523,13 +524,14 @@ func runBackup(opts BackupOptions, gopts GlobalOptions, term *termstatus.Termina if !gopts.JSON { p.V("read data from stdin") } + filename := path.Join("/", opts.StdinFilename) targetFS = &fs.Reader{ ModTime: timeStamp, - Name: opts.StdinFilename, + Name: filename, Mode: 0644, ReadCloser: os.Stdin, } - targets = []string{opts.StdinFilename} + targets = []string{filename} } sc := archiver.NewScanner(targetFS)