Skip to content

Commit

Permalink
fs: Handle absolute pathname for --stdin-filename
Browse files Browse the repository at this point in the history
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 restic#2063
  • Loading branch information
garrmcnu committed Apr 28, 2019
1 parent fb78fbb commit 68ddf6f
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 10 deletions.
6 changes: 6 additions & 0 deletions changelog/unreleased/issue-2063
Original file line number Diff line number Diff line change
@@ -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
27 changes: 21 additions & 6 deletions internal/fs/fs_reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
if name == dir {
return getDirInfo(name), nil
}
return fi, nil
dir = fs.Dir(dir)
}

return nil, os.ErrNotExist
Expand Down
65 changes: 61 additions & 4 deletions internal/fs/fs_reader_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
},
},
{
Expand All @@ -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)
}
},
},
{
Expand All @@ -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)
},
},
{
Expand All @@ -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)
},
},
}
Expand All @@ -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
Expand Down

0 comments on commit 68ddf6f

Please sign in to comment.