From d7635378a15c94d0fc527b8e3c1dff951d631f0c Mon Sep 17 00:00:00 2001 From: reubenmiller Date: Tue, 7 Oct 2025 07:45:18 +0200 Subject: [PATCH 1/2] support resolving symbolic links --- pkg/config/home.go | 7 +++++++ pkg/fileutilities/fileutilities.go | 10 ++++++++++ pkg/pathresolver/pathresolver.go | 9 +++++++++ 3 files changed, 26 insertions(+) diff --git a/pkg/config/home.go b/pkg/config/home.go index b7fd84237..e07b59b85 100644 --- a/pkg/config/home.go +++ b/pkg/config/home.go @@ -46,6 +46,13 @@ func (c *Config) GetSessionHomeDir() string { outputDir = filepath.Join(outputDir, DefaultSessionDir) } + // Resolve symbolic link if outputDir is a symlink + if v, err := fileutilities.ResolvePath(outputDir); err == nil { + outputDir = v + } else { + c.Logger.Warnf("Could not resolve path. path=%s, err=%s", outputDir, err) + } + err := fileutilities.CreateDirs(outputDir) if err != nil && c.Logger != nil { c.Logger.Errorf("Sessions directory check failed. path=%s, err=%s", outputDir, err) diff --git a/pkg/fileutilities/fileutilities.go b/pkg/fileutilities/fileutilities.go index 7eb6ea29e..1cd37ce31 100644 --- a/pkg/fileutilities/fileutilities.go +++ b/pkg/fileutilities/fileutilities.go @@ -7,6 +7,7 @@ import ( "net/http" "os" "os/exec" + "path/filepath" "runtime" ) @@ -90,3 +91,12 @@ func DownloadFile(u string, out io.WriteCloser) error { _, err = io.Copy(out, resp.Body) return err } + +// Resolve path if it is a symbolic link, otherwise leave the path untouched +func ResolvePath(v string) (string, error) { + if info, err := os.Lstat(v); err == nil && info.Mode()&os.ModeSymlink != 0 { + resolved, err := filepath.EvalSymlinks(v) + return resolved, err + } + return v, nil +} diff --git a/pkg/pathresolver/pathresolver.go b/pkg/pathresolver/pathresolver.go index 4bf6f1a8a..defa12c43 100644 --- a/pkg/pathresolver/pathresolver.go +++ b/pkg/pathresolver/pathresolver.go @@ -6,6 +6,8 @@ import ( "os" "path/filepath" "strings" + + "github.com/reubenmiller/go-c8y-cli/v2/pkg/fileutilities" ) // ResolvePaths find matching files within a directory. The filenames can be filtered by pattern and extension @@ -14,6 +16,13 @@ func ResolvePaths(sourceDirs []string, pattern string, extensions []string, igno totalErrors := []error{} for _, sourceDir := range sourceDirs { + // Resolve symlink if sourceDir is a symlink + if v, err := fileutilities.ResolvePath(sourceDir); err == nil { + sourceDir = v + } else { + totalErrors = append(totalErrors, err) + continue + } if stat, err := os.Stat(sourceDir); err != nil || !stat.IsDir() { continue From c5143f7c90092e5b8981d836ab3aad7f57447cd8 Mon Sep 17 00:00:00 2001 From: reubenmiller Date: Tue, 7 Oct 2025 07:45:45 +0200 Subject: [PATCH 2/2] use more efficient filepath.WalkDir instead of filepath.Walk --- pkg/cmd/extension/extension.go | 2 +- pkg/cmd/sessions/selectsession/selectsession.go | 3 ++- pkg/pathresolver/pathresolver.go | 3 ++- pkg/zipUtilities/zipUtilities.go | 8 ++++++-- 4 files changed, 11 insertions(+), 5 deletions(-) diff --git a/pkg/cmd/extension/extension.go b/pkg/cmd/extension/extension.go index bb2354b91..897316234 100644 --- a/pkg/cmd/extension/extension.go +++ b/pkg/cmd/extension/extension.go @@ -110,7 +110,7 @@ func (e *Extension) Commands() ([]extensions.Command, error) { path := filepath.Join(e.path, commandsName) commands := make([]extensions.Command, 0) - err := filepath.Walk(path, func(ipath string, info fs.FileInfo, err error) error { + err := filepath.WalkDir(path, func(ipath string, info fs.DirEntry, err error) error { if err != nil { return err } diff --git a/pkg/cmd/sessions/selectsession/selectsession.go b/pkg/cmd/sessions/selectsession/selectsession.go index 0a14a52d1..1a5816add 100644 --- a/pkg/cmd/sessions/selectsession/selectsession.go +++ b/pkg/cmd/sessions/selectsession/selectsession.go @@ -2,6 +2,7 @@ package selectsession import ( "fmt" + "io/fs" "os" "path/filepath" "strings" @@ -65,7 +66,7 @@ func SelectSession(io *iostreams.IOStreams, cfg *config.Config, log *logger.Logg srcdir := cfg.GetSessionHomeDir() log.Infof("using c8y session folder: %s", srcdir) - err = filepath.Walk(srcdir, func(path string, info os.FileInfo, err error) error { + err = filepath.WalkDir(srcdir, func(path string, info fs.DirEntry, err error) error { if err != nil { log.Printf("Prevent panic by handling failure accessing a path %q: %v", path, err) return err diff --git a/pkg/pathresolver/pathresolver.go b/pkg/pathresolver/pathresolver.go index defa12c43..2d45917f4 100644 --- a/pkg/pathresolver/pathresolver.go +++ b/pkg/pathresolver/pathresolver.go @@ -2,6 +2,7 @@ package pathresolver import ( "fmt" + "io/fs" "log" "os" "path/filepath" @@ -28,7 +29,7 @@ func ResolvePaths(sourceDirs []string, pattern string, extensions []string, igno continue } - err := filepath.Walk(sourceDir, func(path string, info os.FileInfo, err error) error { + err := filepath.WalkDir(sourceDir, func(path string, info fs.DirEntry, err error) error { if err != nil { log.Printf("prevent panic by handling failure accessing a path %q: %v\n", path, err) return err diff --git a/pkg/zipUtilities/zipUtilities.go b/pkg/zipUtilities/zipUtilities.go index 5b3d4b047..42c7ce2a7 100644 --- a/pkg/zipUtilities/zipUtilities.go +++ b/pkg/zipUtilities/zipUtilities.go @@ -59,7 +59,7 @@ func zipit(source, target string, excludeRoot bool) error { sourceDir := filepath.Clean(source) - err = filepath.Walk(source, func(path string, info os.FileInfo, err error) error { + err = filepath.WalkDir(source, func(path string, info os.DirEntry, err error) error { if err != nil { return err } @@ -69,7 +69,11 @@ func zipit(source, target string, excludeRoot bool) error { return nil } - header, err := zip.FileInfoHeader(info) + fsInfo, fsInfoErr := info.Info() + if fsInfoErr != nil { + return fsInfoErr + } + header, err := zip.FileInfoHeader(fsInfo) if err != nil { return err }