From 54b0fbdf770674af1fec82e74212f532725dfd2c Mon Sep 17 00:00:00 2001 From: Anthony Nandaa Date: Tue, 10 Sep 2024 00:55:17 -0700 Subject: [PATCH] fix: util/path: CheckSystemDriveAndRemoveDriveLetter to preserve `/` The call to CheckSystemDriveAndRemoveDriveLetter() does not preserve the trailing `/` or `\\`. This happens because `filepath.Clean()` strips away any trailing slashes. For example `/sample/` will be `\\sample` on Windows and `/sample` on Linux. This function was mainly written for Windows scenarios, which have System Drive Letters like C:/, etc. This was causing cases like `COPY testfile /testdir/` to be intepreted as `COPY testfile /testdir`, and if `testdir` is not explictly created before the call, it ends up being treated as a destination file other than a directory. Fix this by checking that if we have a trailing `/` or `\\`, we preserve it after the call to `filepath.Clean()`. Fixes #5249 PS. Also fixed for cross-building from Linux scenario, taking care for paths like `\\sample\\` that are not changed when run through `filepath.Clean()`, hence the platform specific `hasTrailingSlash` function. Signed-off-by: Anthony Nandaa --- frontend/dockerfile/dockerfile_test.go | 37 ++++++++++++++++++++++++++ util/system/path.go | 18 +++++++++++-- util/system/path_unix.go | 10 +++++++ util/system/path_windows.go | 9 +++++++ 4 files changed, 72 insertions(+), 2 deletions(-) create mode 100644 util/system/path_unix.go create mode 100644 util/system/path_windows.go diff --git a/frontend/dockerfile/dockerfile_test.go b/frontend/dockerfile/dockerfile_test.go index b34c95b4ec73..26a946badfda 100644 --- a/frontend/dockerfile/dockerfile_test.go +++ b/frontend/dockerfile/dockerfile_test.go @@ -152,6 +152,7 @@ var allTests = integration.TestFuncs( testNamedMultiplatformInputContext, testNamedFilteredContext, testEmptyDestDir, + testPreserveDestDirSlash, testCopyLinkDotDestDir, testCopyLinkEmptyDestDir, testCopyChownCreateDest, @@ -547,6 +548,42 @@ RUN cmd /V:on /C "set /p tfcontent= 1 && hasTrailingSlash(origPath) && inputOS == "windows" { + // cleanedPath already comes with platform specific separators + return cleanedPath + string(filepath.Separator) + } + return cleanedPath } diff --git a/util/system/path_unix.go b/util/system/path_unix.go new file mode 100644 index 000000000000..1cc02782435b --- /dev/null +++ b/util/system/path_unix.go @@ -0,0 +1,10 @@ +//go:build !windows +// +build !windows + +package system + +import "strings" + +func hasTrailingSlash(origPath string) bool { + return strings.HasSuffix(origPath, "/") +} diff --git a/util/system/path_windows.go b/util/system/path_windows.go new file mode 100644 index 000000000000..8bb70e732090 --- /dev/null +++ b/util/system/path_windows.go @@ -0,0 +1,9 @@ +package system + +import "strings" + +func hasTrailingSlash(origPath string) bool { + // Windows allows for both \\ and / as path separators. + return strings.HasSuffix(origPath, "\\") || + strings.HasSuffix(origPath, "/") +}