fs/reader: return proper error on invalid filename

This commit is contained in:
Michael Eischer 2025-04-11 22:07:31 +02:00
parent ddd48f1e98
commit 9f39e8a1d3
5 changed files with 30 additions and 20 deletions

View File

@ -591,10 +591,13 @@ func runBackup(ctx context.Context, opts BackupOptions, gopts GlobalOptions, ter
return err return err
} }
} }
targetFS = fs.NewReader(filename, source, fs.ReaderOptions{ targetFS, err = fs.NewReader(filename, source, fs.ReaderOptions{
ModTime: timeStamp, ModTime: timeStamp,
Mode: 0644, Mode: 0644,
}) })
if err != nil {
return fmt.Errorf("failed to backup from stdin: %w", err)
}
targets = []string{filename} targets = []string{filename}
} }

View File

@ -174,10 +174,11 @@ func TestArchiverSaveFileReaderFS(t *testing.T) {
ts := time.Now() ts := time.Now()
filename := "xx" filename := "xx"
readerFs := fs.NewReader(filename, io.NopCloser(strings.NewReader(test.Data)), fs.ReaderOptions{ readerFs, err := fs.NewReader(filename, io.NopCloser(strings.NewReader(test.Data)), fs.ReaderOptions{
ModTime: ts, ModTime: ts,
Mode: 0123, Mode: 0123,
}) })
rtest.OK(t, err)
node, stats := saveFile(t, repo, filename, readerFs) node, stats := saveFile(t, repo, filename, readerFs)
@ -286,11 +287,11 @@ func TestArchiverSaveReaderFS(t *testing.T) {
ts := time.Now() ts := time.Now()
filename := "xx" filename := "xx"
readerFs := fs.NewReader(filename, io.NopCloser(strings.NewReader(test.Data)), fs.ReaderOptions{ readerFs, err := fs.NewReader(filename, io.NopCloser(strings.NewReader(test.Data)), fs.ReaderOptions{
ModTime: ts, ModTime: ts,
Mode: 0123, Mode: 0123,
}) })
rtest.OK(t, err)
arch := New(repo, readerFs, Options{}) arch := New(repo, readerFs, Options{})
arch.Error = func(item string, err error) error { arch.Error = func(item string, err error) error {
t.Errorf("archiver error for %v: %v", item, err) t.Errorf("archiver error for %v: %v", item, err)

View File

@ -42,9 +42,12 @@ type readerItem struct {
// statically ensure that Local implements FS. // statically ensure that Local implements FS.
var _ FS = &Reader{} var _ FS = &Reader{}
func NewReader(name string, r io.ReadCloser, opts ReaderOptions) *Reader { func NewReader(name string, r io.ReadCloser, opts ReaderOptions) (*Reader, error) {
items := make(map[string]readerItem) items := make(map[string]readerItem)
name = readerCleanPath(name) name = readerCleanPath(name)
if name == "/" {
return nil, fmt.Errorf("invalid filename specified")
}
isFile := true isFile := true
for { for {
@ -89,7 +92,7 @@ func NewReader(name string, r io.ReadCloser, opts ReaderOptions) *Reader {
} }
return &Reader{ return &Reader{
items: items, items: items,
} }, nil
} }
func readerCleanPath(name string) string { func readerCleanPath(name string) string {

View File

@ -185,15 +185,16 @@ func TestFSReader(t *testing.T) {
tests = append(tests, createFileTest(filename, now, data)...) tests = append(tests, createFileTest(filename, now, data)...)
tests = append(tests, createDirTest("", now)...) tests = append(tests, createDirTest("", now)...)
for _, test := range tests { for _, tst := range tests {
fs := NewReader(filename, io.NopCloser(bytes.NewReader(data)), ReaderOptions{ fs, err := NewReader(filename, io.NopCloser(bytes.NewReader(data)), ReaderOptions{
Mode: 0644, Mode: 0644,
Size: int64(len(data)), Size: int64(len(data)),
ModTime: now, ModTime: now,
}) })
test.OK(t, err)
t.Run(test.name, func(t *testing.T) { t.Run(tst.name, func(t *testing.T) {
test.f(t, fs) tst.f(t, fs)
}) })
} }
} }
@ -211,15 +212,16 @@ func TestFSReaderNested(t *testing.T) {
tests = append(tests, createDirTest("foo", now)...) tests = append(tests, createDirTest("foo", now)...)
tests = append(tests, createDirTest("foo/sub", now)...) tests = append(tests, createDirTest("foo/sub", now)...)
for _, test := range tests { for _, tst := range tests {
fs := NewReader(filename, io.NopCloser(bytes.NewReader(data)), ReaderOptions{ fs, err := NewReader(filename, io.NopCloser(bytes.NewReader(data)), ReaderOptions{
Mode: 0644, Mode: 0644,
Size: int64(len(data)), Size: int64(len(data)),
ModTime: now, ModTime: now,
}) })
test.OK(t, err)
t.Run(test.name, func(t *testing.T) { t.Run(tst.name, func(t *testing.T) {
test.f(t, fs) tst.f(t, fs)
}) })
} }
} }
@ -244,12 +246,12 @@ func TestFSReaderDir(t *testing.T) {
for _, tst := range tests { for _, tst := range tests {
t.Run(tst.name, func(t *testing.T) { t.Run(tst.name, func(t *testing.T) {
fs := NewReader(tst.filename, io.NopCloser(bytes.NewReader(data)), ReaderOptions{ fs, err := NewReader(tst.filename, io.NopCloser(bytes.NewReader(data)), ReaderOptions{
Mode: 0644, Mode: 0644,
Size: int64(len(data)), Size: int64(len(data)),
ModTime: now, ModTime: now,
}) })
test.OK(t, err)
dir := path.Dir(tst.filename) dir := path.Dir(tst.filename)
for { for {
if dir == "/" || dir == "." { if dir == "/" || dir == "." {
@ -294,12 +296,12 @@ func TestFSReaderMinFileSize(t *testing.T) {
for _, tst := range tests { for _, tst := range tests {
t.Run(tst.name, func(t *testing.T) { t.Run(tst.name, func(t *testing.T) {
fs := NewReader("testfile", io.NopCloser(strings.NewReader(tst.data)), ReaderOptions{ fs, err := NewReader("testfile", io.NopCloser(strings.NewReader(tst.data)), ReaderOptions{
Mode: 0644, Mode: 0644,
ModTime: time.Now(), ModTime: time.Now(),
AllowEmptyFile: tst.allowEmpty, AllowEmptyFile: tst.allowEmpty,
}) })
test.OK(t, err)
f, err := fs.OpenFile("testfile", O_RDONLY, false) f, err := fs.OpenFile("testfile", O_RDONLY, false)
test.OK(t, err) test.OK(t, err)

View File

@ -908,11 +908,12 @@ func TestRestorerSparseFiles(t *testing.T) {
var zeros [1<<20 + 13]byte var zeros [1<<20 + 13]byte
target := fs.NewReader("/zeros", io.NopCloser(bytes.NewReader(zeros[:])), fs.ReaderOptions{ target, err := fs.NewReader("/zeros", io.NopCloser(bytes.NewReader(zeros[:])), fs.ReaderOptions{
Mode: 0600, Mode: 0600,
}) })
rtest.OK(t, err)
sc := archiver.NewScanner(target) sc := archiver.NewScanner(target)
err := sc.Scan(context.TODO(), []string{"/zeros"}) err = sc.Scan(context.TODO(), []string{"/zeros"})
rtest.OK(t, err) rtest.OK(t, err)
arch := archiver.New(repo, target, archiver.Options{}) arch := archiver.New(repo, target, archiver.Options{})