From a8fbe46119adbd89f827a75c75b9e97d392f1842 Mon Sep 17 00:00:00 2001 From: Nikita Pivkin Date: Fri, 27 Sep 2024 08:03:46 +0600 Subject: [PATCH] fix: allow access to '..' in mapfs (#7575) Signed-off-by: nikpivkin --- pkg/mapfs/fs.go | 12 ++++++++---- pkg/mapfs/fs_test.go | 23 +++++++++++++++++++++++ pkg/mapfs/testdata/subdir/..foo.txt | 0 pkg/mapfs/testdata/subdir/foo.txt | 0 4 files changed, 31 insertions(+), 4 deletions(-) create mode 100644 pkg/mapfs/testdata/subdir/..foo.txt create mode 100644 pkg/mapfs/testdata/subdir/foo.txt diff --git a/pkg/mapfs/fs.go b/pkg/mapfs/fs.go index 4cba59263c37..5ce894b8101c 100644 --- a/pkg/mapfs/fs.go +++ b/pkg/mapfs/fs.go @@ -123,7 +123,7 @@ func (m *FS) CopyFilesUnder(dir string) error { // Stat returns a FileInfo describing the file. func (m *FS) Stat(name string) (fs.FileInfo, error) { - if strings.HasPrefix(name, "../") && m.underlyingRoot != "" { + if m.isPathAboveRoot(name) { return os.Stat(filepath.Join(m.underlyingRoot, name)) } @@ -145,7 +145,7 @@ func (m *FS) Stat(name string) (fs.FileInfo, error) { // ReadDir reads the named directory // and returns a list of directory entries sorted by filename. func (m *FS) ReadDir(name string) ([]fs.DirEntry, error) { - if strings.HasPrefix(name, "../") && m.underlyingRoot != "" { + if m.isPathAboveRoot(name) { return os.ReadDir(filepath.Join(m.underlyingRoot, name)) } return m.root.ReadDir(cleanPath(name)) @@ -153,7 +153,7 @@ func (m *FS) ReadDir(name string) ([]fs.DirEntry, error) { // Open opens the named file for reading. func (m *FS) Open(name string) (fs.File, error) { - if strings.HasPrefix(name, "../") && m.underlyingRoot != "" { + if m.isPathAboveRoot(name) { return os.Open(filepath.Join(m.underlyingRoot, name)) } return m.root.Open(cleanPath(name)) @@ -188,7 +188,7 @@ func (m *FS) MkdirAll(path string, perm fs.FileMode) error { // The caller is permitted to modify the returned byte slice. // This method should return a copy of the underlying data. func (m *FS) ReadFile(name string) ([]byte, error) { - if strings.HasPrefix(name, "../") && m.underlyingRoot != "" { + if m.isPathAboveRoot(name) { return os.ReadFile(filepath.Join(m.underlyingRoot, name)) } @@ -245,3 +245,7 @@ func cleanPath(path string) string { path = strings.TrimLeft(path, "/") // Remove the leading slash return path } + +func (m *FS) isPathAboveRoot(name string) bool { + return (name == ".." || strings.HasPrefix(name, "../")) && m.underlyingRoot != "" +} diff --git a/pkg/mapfs/fs_test.go b/pkg/mapfs/fs_test.go index 22b659d7f387..d00d5626a9a9 100644 --- a/pkg/mapfs/fs_test.go +++ b/pkg/mapfs/fs_test.go @@ -478,3 +478,26 @@ func TestFS_RemoveAll(t *testing.T) { require.ErrorIs(t, err, fs.ErrNotExist) }) } + +func TestFS_WithUnderlyingRoot(t *testing.T) { + root := "testdata/subdir" + fsys := mapfs.New(mapfs.WithUnderlyingRoot(root)) + require.NoError(t, fsys.WriteFile("foo.txt", root+"/foo.txt")) + require.NoError(t, fsys.WriteFile("..foo.txt", root+"/..foo.txt")) + + fi, err := fsys.Stat("..") + require.NoError(t, err) + assert.True(t, fi.IsDir()) + + fi, err = fsys.Stat("../hello.txt") + require.NoError(t, err) + assert.False(t, fi.IsDir()) + + fi, err = fsys.Stat("foo.txt") + require.NoError(t, err) + assert.False(t, fi.IsDir()) + + fi, err = fsys.Stat("..foo.txt") + require.NoError(t, err) + assert.False(t, fi.IsDir()) +} diff --git a/pkg/mapfs/testdata/subdir/..foo.txt b/pkg/mapfs/testdata/subdir/..foo.txt new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/pkg/mapfs/testdata/subdir/foo.txt b/pkg/mapfs/testdata/subdir/foo.txt new file mode 100644 index 000000000000..e69de29bb2d1