From 4fb150238bcb88373c318d3fe52979fb735dc405 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zolt=C3=A1n=20Reegn?= Date: Wed, 13 Sep 2023 15:14:50 +0200 Subject: [PATCH] Fix symlink behaviour (#1020) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fix symlink behaviour Make sure to evaluate symlinks when the path is not absolute and not local. Otherwise just fall back to regular absolute paths. Signed-off-by: Zoltán Reegn --- pkg/filesystem/fs.go | 63 ++++++++++++++++++++++++++++++++------- pkg/filesystem/fs_test.go | 53 +++++++++++++++++++++++++------- 2 files changed, 95 insertions(+), 21 deletions(-) diff --git a/pkg/filesystem/fs.go b/pkg/filesystem/fs.go index 2f7d8e55..ed1ccfcf 100644 --- a/pkg/filesystem/fs.go +++ b/pkg/filesystem/fs.go @@ -34,17 +34,18 @@ type FileSystem struct { Getwd func() (string, error) Chdir func(string) error Abs func(string) (string, error) + EvalSymlinks func(string) (string, error) } func DefaultFileSystem() *FileSystem { dfs := FileSystem{ - ReadDir: os.ReadDir, - DeleteFile: os.Remove, - Stat: os.Stat, - Glob: filepath.Glob, - Getwd: os.Getwd, - Chdir: os.Chdir, - Abs: filepath.Abs, + ReadDir: os.ReadDir, + DeleteFile: os.Remove, + Stat: os.Stat, + Glob: filepath.Glob, + Getwd: os.Getwd, + Chdir: os.Chdir, + EvalSymlinks: filepath.EvalSymlinks, } dfs.Stat = dfs.stat @@ -52,6 +53,7 @@ func DefaultFileSystem() *FileSystem { dfs.FileExistsAt = dfs.fileExistsAtDefault dfs.DirectoryExistsAt = dfs.directoryExistsDefault dfs.FileExists = dfs.fileExistsDefault + dfs.Abs = dfs.absDefault return &dfs } @@ -91,7 +93,9 @@ func FromFileSystem(params FileSystem) *FileSystem { if params.Abs != nil { dfs.Abs = params.Abs } - + if params.EvalSymlinks != nil { + dfs.EvalSymlinks = params.EvalSymlinks + } return dfs } @@ -110,13 +114,20 @@ func (filesystem *FileSystem) readFile(name string) ([]byte, error) { } func (filesystem *FileSystem) fileExistsAtDefault(path string) bool { + path, err := filesystem.resolveSymlinks(path) + if err != nil { + return false + } fileInfo, err := filesystem.Stat(path) return err == nil && fileInfo.Mode().IsRegular() } func (filesystem *FileSystem) fileExistsDefault(path string) (bool, error) { - _, err := filesystem.Stat(path) - + path, err := filesystem.resolveSymlinks(path) + if err != nil { + return false, err + } + _, err = filesystem.Stat(path) if err != nil { if os.IsNotExist(err) { return false, nil @@ -127,6 +138,38 @@ func (filesystem *FileSystem) fileExistsDefault(path string) (bool, error) { } func (filesystem *FileSystem) directoryExistsDefault(path string) bool { + path, err := filesystem.resolveSymlinks(path) + if err != nil { + return false + } fileInfo, err := filesystem.Stat(path) return err == nil && fileInfo.Mode().IsDir() } + +func (filesystem *FileSystem) resolveSymlinks(path string) (string, error) { + if !filepath.IsAbs(path) && !filepath.IsLocal(path) { + basePath, err := filesystem.Getwd() + if err != nil { + return "", err + } + + basePath, err = filesystem.EvalSymlinks(basePath) + if err != nil { + return "", err + } + path, err := filesystem.EvalSymlinks(filepath.Join(basePath, path)) + if err != nil { + return "", err + } + return path, nil + } + return path, nil +} + +func (filesystem *FileSystem) absDefault(path string) (string, error) { + path, err := filesystem.resolveSymlinks(path) + if err != nil { + return "", err + } + return filepath.Abs(path) +} diff --git a/pkg/filesystem/fs_test.go b/pkg/filesystem/fs_test.go index 5f1e01f3..60fed13e 100644 --- a/pkg/filesystem/fs_test.go +++ b/pkg/filesystem/fs_test.go @@ -12,28 +12,58 @@ import ( func NewTestFileSystem() FileSystem { replaceffs := FileSystem{ Stat: func(s string) (os.FileInfo, error) { - if strings.HasPrefix(s, "existing_file") { + if strings.HasSuffix(s, "existing_file.txt") { return fileStat{mode: 0}, nil } - if strings.HasPrefix(s, "existing_dir") { + if strings.HasSuffix(s, "existing_dir") { return fileStat{mode: fs.ModeDir}, nil } return nil, errors.New("Error") }, + Getwd: func() (string, error) { + return "/test/dir", nil + }, + EvalSymlinks: func(s string) (string, error) { + if s == "/test/dir" { + return "/real/dir", nil + } else { + return s, nil + } + }, } return *FromFileSystem(replaceffs) } +func TestFs_resolveSymlinks(t *testing.T) { + ffs := NewTestFileSystem() + path, _ := ffs.resolveSymlinks("../existing_file.txt") + if path != "/real/existing_file.txt" { + t.Errorf("Expected absolute path %s but got %s", "/real/existing_file.txt", path) + } + path, _ = ffs.resolveSymlinks("./existing_file.txt") + if path != "./existing_file.txt" { + t.Errorf("Expected local path %s but got %s", "./existing_file.txt", path) + } + path, _ = ffs.resolveSymlinks("existing_file.txt") + if path != "existing_file.txt" { + t.Errorf("Expected local path %s but got %s", "existing_file.txt", path) + } + path, _ = ffs.resolveSymlinks("/a/b/c/existing_file.txt") + if path != "/a/b/c/existing_file.txt" { + t.Errorf("Expected absolute path %s but got %s", "/a/b/c/existing_file.txt", path) + } +} + func TestFs_fileExistsDefault(t *testing.T) { ffs := NewTestFileSystem() - var exists, _ = ffs.FileExists("existing_file.txt") + exists, _ := ffs.FileExists("existing_file.txt") if !exists { t.Errorf("Expected file %s, not found", "existing_file.txt") } - exists, _ = ffs.FileExists("non_existing_file.txt") + exists, _ = ffs.FileExists("missing_file.txt") if exists { - t.Errorf("Not expected file %s, found", "non_existing_file.txt") + t.Errorf("Not expected file %s, found", "missing_file.txt") } dfs := DefaultFileSystem() @@ -46,14 +76,14 @@ func TestFs_fileExistsDefault(t *testing.T) { func TestFs_fileExistsAtDefault(t *testing.T) { ffs := NewTestFileSystem() - var exists = ffs.FileExistsAt("existing_file.txt") + exists := ffs.FileExistsAt("existing_file.txt") if !exists { t.Errorf("Expected file %s, not found", "existing_file.txt") } - exists = ffs.FileExistsAt("non_existing_file.txt") + exists = ffs.FileExistsAt("missing_file.txt") if exists { - t.Errorf("Not expected file %s, found", "non_existing_file.txt") + t.Errorf("Not expected file %s, found", "missing_file.txt") } exists = ffs.FileExistsAt("existing_dir") @@ -70,12 +100,12 @@ func TestFs_fileExistsAtDefault(t *testing.T) { func TestFs_directoryExistsDefault(t *testing.T) { ffs := NewTestFileSystem() - var exists = ffs.DirectoryExistsAt("existing_dir") + exists := ffs.DirectoryExistsAt("existing_dir") if !exists { t.Errorf("Expected file %s, not found", "existing_dir") } - exists = ffs.DirectoryExistsAt("not_existing_dir") + exists = ffs.DirectoryExistsAt("missing_dir") if exists { t.Errorf("Not expected file %s, found", "existing_dir") } @@ -148,7 +178,8 @@ func TestFs_DefaultBuilder(t *testing.T) { ffs.Stat == nil || ffs.Getwd == nil || ffs.Chdir == nil || - ffs.Abs == nil { + ffs.Abs == nil || + ffs.EvalSymlinks == nil { t.Errorf("Missing functions in DefaultFileSystem") } }