From b857efd62dabad9237c3a58255c45c8b7cbc753f Mon Sep 17 00:00:00 2001 From: Gregor Noczinski Date: Mon, 23 Dec 2024 13:34:11 +0100 Subject: [PATCH 1/8] Add junctions workaround. --- pkg/fsutils/fsutils.go | 2 +- pkg/fsutils/fsutils_unix.go | 9 +++++++++ pkg/fsutils/fsutils_windows.go | 35 ++++++++++++++++++++++++++++++++++ 3 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 pkg/fsutils/fsutils_unix.go create mode 100644 pkg/fsutils/fsutils_windows.go diff --git a/pkg/fsutils/fsutils.go b/pkg/fsutils/fsutils.go index 80bb9c5b44f4..91d12e5cd341 100644 --- a/pkg/fsutils/fsutils.go +++ b/pkg/fsutils/fsutils.go @@ -61,7 +61,7 @@ func EvalSymlinks(path string) (string, error) { } var er evalSymlinkRes - er.path, er.err = filepath.EvalSymlinks(path) + er.path, er.err = evalSymlinks(path) evalSymlinkCache.Store(path, er) return er.path, er.err diff --git a/pkg/fsutils/fsutils_unix.go b/pkg/fsutils/fsutils_unix.go new file mode 100644 index 000000000000..68e762cf4bab --- /dev/null +++ b/pkg/fsutils/fsutils_unix.go @@ -0,0 +1,9 @@ +//go:build !windows + +package fsutils + +import "path/filepath" + +func evalSymlinks(path string) (string, error) { + return filepath.EvalSymlinks(path) +} diff --git a/pkg/fsutils/fsutils_windows.go b/pkg/fsutils/fsutils_windows.go new file mode 100644 index 000000000000..8559c8054286 --- /dev/null +++ b/pkg/fsutils/fsutils_windows.go @@ -0,0 +1,35 @@ +//go:build windows + +package fsutils + +import ( + "os" + "path/filepath" + "syscall" +) + +func evalSymlinks(path string) (string, error) { + resolved, err := filepath.EvalSymlinks(path) + if err != nil { + // This is a workaround for the behavior of filepath.EvalSymlinks, which fails with + // syscall.ENOTDIR if the specified path contains a junction on Windows. Junctions + // can occur, for example, when a volume is mounted as a subdirectory inside another + // drive. This can usually happen when using the Dev Drives feature and replacing + // existing directories. See: https://github.com/golang/go/issues/40180 + // + // Since syscall.ENOTDIR is only returned when calling filepath.EvalSymlinks on + // Windows if part of the presented path is a junction and nothing before was a + // symlink, we simply treat this as NOT symlink, because a symlink over the junction + // makes no sense at all. + if err == syscall.ENOTDIR { + if _, sErr := os.Stat(path); sErr == nil { + // If exists, we make the path absolute, to be sure... + if abs, aErr := filepath.Abs(path); aErr == nil { + return abs, nil + } + } + } + return "", err + } + return resolved, nil +} From 5ba1af501c79d9d5518515deca7f034bda2e7ec0 Mon Sep 17 00:00:00 2001 From: Gregor Noczinski Date: Thu, 26 Dec 2024 10:42:21 +0100 Subject: [PATCH 2/8] Apply suggestion Co-authored-by: Simon Sawert --- pkg/fsutils/fsutils_windows.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/fsutils/fsutils_windows.go b/pkg/fsutils/fsutils_windows.go index 8559c8054286..bc1776376149 100644 --- a/pkg/fsutils/fsutils_windows.go +++ b/pkg/fsutils/fsutils_windows.go @@ -21,7 +21,7 @@ func evalSymlinks(path string) (string, error) { // Windows if part of the presented path is a junction and nothing before was a // symlink, we simply treat this as NOT symlink, because a symlink over the junction // makes no sense at all. - if err == syscall.ENOTDIR { + if errors.Is(err, syscall.ENOTDIR) { if _, sErr := os.Stat(path); sErr == nil { // If exists, we make the path absolute, to be sure... if abs, aErr := filepath.Abs(path); aErr == nil { From 39204c76fa0bf7cc0c8c951685b8cafdb6814920 Mon Sep 17 00:00:00 2001 From: Gregor Noczinski Date: Thu, 26 Dec 2024 10:50:35 +0100 Subject: [PATCH 3/8] Apply suggestion --- pkg/fsutils/fsutils_windows.go | 1 + 1 file changed, 1 insertion(+) diff --git a/pkg/fsutils/fsutils_windows.go b/pkg/fsutils/fsutils_windows.go index bc1776376149..7cd5d8dc0afd 100644 --- a/pkg/fsutils/fsutils_windows.go +++ b/pkg/fsutils/fsutils_windows.go @@ -3,6 +3,7 @@ package fsutils import ( + "errors" "os" "path/filepath" "syscall" From dfa826fa6a16d79724ac909cff96d1a3e2d3c7ba Mon Sep 17 00:00:00 2001 From: Gregor Noczinski Date: Thu, 26 Dec 2024 22:27:20 +0100 Subject: [PATCH 4/8] Apply suggestion --- pkg/fsutils/fsutils_windows.go | 39 +++++++++++++++++----------------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/pkg/fsutils/fsutils_windows.go b/pkg/fsutils/fsutils_windows.go index 7cd5d8dc0afd..74ab7a6a73f2 100644 --- a/pkg/fsutils/fsutils_windows.go +++ b/pkg/fsutils/fsutils_windows.go @@ -11,26 +11,27 @@ import ( func evalSymlinks(path string) (string, error) { resolved, err := filepath.EvalSymlinks(path) - if err != nil { - // This is a workaround for the behavior of filepath.EvalSymlinks, which fails with - // syscall.ENOTDIR if the specified path contains a junction on Windows. Junctions - // can occur, for example, when a volume is mounted as a subdirectory inside another - // drive. This can usually happen when using the Dev Drives feature and replacing - // existing directories. See: https://github.com/golang/go/issues/40180 - // - // Since syscall.ENOTDIR is only returned when calling filepath.EvalSymlinks on - // Windows if part of the presented path is a junction and nothing before was a - // symlink, we simply treat this as NOT symlink, because a symlink over the junction - // makes no sense at all. - if errors.Is(err, syscall.ENOTDIR) { - if _, sErr := os.Stat(path); sErr == nil { - // If exists, we make the path absolute, to be sure... - if abs, aErr := filepath.Abs(path); aErr == nil { - return abs, nil - } + if err == nil { + return resolved, nil + } + + // This is a workaround for the behavior of filepath.EvalSymlinks, which fails with + // syscall.ENOTDIR if the specified path contains a junction on Windows. Junctions + // can occur, for example, when a volume is mounted as a subdirectory inside another + // drive. This can usually happen when using the Dev Drives feature and replacing + // existing directories. See: https://github.com/golang/go/issues/40180 + // + // Since syscall.ENOTDIR is only returned when calling filepath.EvalSymlinks on + // Windows if part of the presented path is a junction and nothing before was a + // symlink, we simply treat this as NOT symlink, because a symlink over the junction + // makes no sense at all. + if errors.Is(err, syscall.ENOTDIR) { + if _, sErr := os.Stat(path); sErr == nil { + // If exists, we make the path absolute, to be sure... + if abs, aErr := filepath.Abs(path); aErr == nil { + return abs, nil } } - return "", err } - return resolved, nil + return "", err } From 03b658f65c95f25649f52a5f8e62da78a15651a5 Mon Sep 17 00:00:00 2001 From: Fernandez Ludovic Date: Thu, 26 Dec 2024 22:53:34 +0100 Subject: [PATCH 5/8] review: decrease cyclomatic complexity --- pkg/fsutils/fsutils_windows.go | 44 +++++++++++++++++++--------------- 1 file changed, 25 insertions(+), 19 deletions(-) diff --git a/pkg/fsutils/fsutils_windows.go b/pkg/fsutils/fsutils_windows.go index 74ab7a6a73f2..f15ce8045410 100644 --- a/pkg/fsutils/fsutils_windows.go +++ b/pkg/fsutils/fsutils_windows.go @@ -4,34 +4,40 @@ package fsutils import ( "errors" - "os" "path/filepath" "syscall" ) +// This is a workaround for the behavior of [filepath.EvalSymlinks], +// which fails with [syscall.ENOTDIR] if the specified path contains a junction on Windows. +// Junctions can occur, for example, when a volume is mounted as a subdirectory inside another drive. +// This can usually happen when using the Dev Drives feature and replacing existing directories. +// See: https://github.com/golang/go/issues/40180 +// +// Since [syscall.ENOTDIR] is only returned when calling [filepath.EvalSymlinks] on Windows +// if part of the presented path is a junction and nothing before was a symlink, +// we simply treat this as NOT symlink, +// because a symlink over the junction makes no sense at all. func evalSymlinks(path string) (string, error) { resolved, err := filepath.EvalSymlinks(path) if err == nil { return resolved, nil } - // This is a workaround for the behavior of filepath.EvalSymlinks, which fails with - // syscall.ENOTDIR if the specified path contains a junction on Windows. Junctions - // can occur, for example, when a volume is mounted as a subdirectory inside another - // drive. This can usually happen when using the Dev Drives feature and replacing - // existing directories. See: https://github.com/golang/go/issues/40180 - // - // Since syscall.ENOTDIR is only returned when calling filepath.EvalSymlinks on - // Windows if part of the presented path is a junction and nothing before was a - // symlink, we simply treat this as NOT symlink, because a symlink over the junction - // makes no sense at all. - if errors.Is(err, syscall.ENOTDIR) { - if _, sErr := os.Stat(path); sErr == nil { - // If exists, we make the path absolute, to be sure... - if abs, aErr := filepath.Abs(path); aErr == nil { - return abs, nil - } - } + if !errors.Is(err, syscall.ENOTDIR) { + return "", err } - return "", err + + _, err := os.Stat(path) + if err != nil { + return "", err + } + + // If exists, we make the path absolute, to be sure... + abs, err := filepath.Abs(path) + if err != nil { + return "", err + } + + return abs, nil } From 5cc16fd917375ac55d017a8ad2093b20ece81829 Mon Sep 17 00:00:00 2001 From: Fernandez Ludovic Date: Thu, 26 Dec 2024 22:55:17 +0100 Subject: [PATCH 6/8] review --- pkg/fsutils/fsutils_windows.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/fsutils/fsutils_windows.go b/pkg/fsutils/fsutils_windows.go index f15ce8045410..61e7894e0a15 100644 --- a/pkg/fsutils/fsutils_windows.go +++ b/pkg/fsutils/fsutils_windows.go @@ -28,7 +28,7 @@ func evalSymlinks(path string) (string, error) { return "", err } - _, err := os.Stat(path) + _, err = os.Stat(path) if err != nil { return "", err } From 0b6f2ce4f73bbb39a23403346f47d46b4e3856b7 Mon Sep 17 00:00:00 2001 From: Fernandez Ludovic Date: Thu, 26 Dec 2024 22:58:00 +0100 Subject: [PATCH 7/8] review: simplification --- pkg/fsutils/fsutils_windows.go | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/pkg/fsutils/fsutils_windows.go b/pkg/fsutils/fsutils_windows.go index 61e7894e0a15..d1e1f796cef8 100644 --- a/pkg/fsutils/fsutils_windows.go +++ b/pkg/fsutils/fsutils_windows.go @@ -34,10 +34,5 @@ func evalSymlinks(path string) (string, error) { } // If exists, we make the path absolute, to be sure... - abs, err := filepath.Abs(path) - if err != nil { - return "", err - } - - return abs, nil + return filepath.Abs(path) } From effed5de90e8a1b8e5cf052abf077249a46b080e Mon Sep 17 00:00:00 2001 From: Fernandez Ludovic Date: Thu, 26 Dec 2024 23:19:35 +0100 Subject: [PATCH 8/8] review --- pkg/fsutils/fsutils_windows.go | 1 + 1 file changed, 1 insertion(+) diff --git a/pkg/fsutils/fsutils_windows.go b/pkg/fsutils/fsutils_windows.go index d1e1f796cef8..19efb1cfc245 100644 --- a/pkg/fsutils/fsutils_windows.go +++ b/pkg/fsutils/fsutils_windows.go @@ -4,6 +4,7 @@ package fsutils import ( "errors" + "os" "path/filepath" "syscall" )