diff --git a/builder/dockerfile/dispatchers_windows.go b/builder/dockerfile/dispatchers_windows.go index 5a40ae09d3..e890c3ae18 100644 --- a/builder/dockerfile/dispatchers_windows.go +++ b/builder/dockerfile/dispatchers_windows.go @@ -10,6 +10,8 @@ import ( "github.com/docker/docker/pkg/system" ) +var pattern = regexp.MustCompile(`^[a-zA-Z]:\.$`) + // normaliseWorkdir normalises a user requested working directory in a // platform sematically consistent way. func normaliseWorkdir(current string, requested string) (string, error) { @@ -17,8 +19,27 @@ func normaliseWorkdir(current string, requested string) (string, error) { return "", fmt.Errorf("cannot normalise nothing") } - current = filepath.FromSlash(current) - requested = filepath.FromSlash(requested) + // `filepath.Clean` will replace "" with "." so skip in that case + if current != "" { + current = filepath.Clean(current) + } + if requested != "" { + requested = filepath.Clean(requested) + } + + // If either current or requested in Windows is: + // C: + // C:. + // then an error will be thrown as the definition for the above + // refers to `current directory on drive C:` + // Since filepath.Clean() will automatically normalize the above + // to `C:.`, we only need to check the last format + if pattern.MatchString(current) { + return "", fmt.Errorf("%s is not a directory. If you are specifying a drive letter, please add a trailing '\\'", current) + } + if pattern.MatchString(requested) { + return "", fmt.Errorf("%s is not a directory. If you are specifying a drive letter, please add a trailing '\\'", requested) + } // Target semantics is C:\somefolder, specifically in the format: // UPPERCASEDriveLetter-Colon-Backslash-FolderName. We are already diff --git a/builder/dockerfile/dispatchers_windows_test.go b/builder/dockerfile/dispatchers_windows_test.go index 4c53713197..3319c06582 100644 --- a/builder/dockerfile/dispatchers_windows_test.go +++ b/builder/dockerfile/dispatchers_windows_test.go @@ -7,9 +7,15 @@ import "testing" func TestNormaliseWorkdir(t *testing.T) { tests := []struct{ current, requested, expected, etext string }{ {``, ``, ``, `cannot normalise nothing`}, + {``, `C:`, ``, `C:. is not a directory. If you are specifying a drive letter, please add a trailing '\'`}, + {``, `C:.`, ``, `C:. is not a directory. If you are specifying a drive letter, please add a trailing '\'`}, + {`c:`, `\a`, ``, `c:. is not a directory. If you are specifying a drive letter, please add a trailing '\'`}, + {`c:.`, `\a`, ``, `c:. is not a directory. If you are specifying a drive letter, please add a trailing '\'`}, {``, `a`, `C:\a`, ``}, {``, `c:\foo`, `C:\foo`, ``}, + {``, `c:\\foo`, `C:\foo`, ``}, {``, `\foo`, `C:\foo`, ``}, + {``, `\\foo`, `C:\foo`, ``}, {``, `/foo`, `C:\foo`, ``}, {``, `C:/foo`, `C:\foo`, ``}, {`C:\foo`, `bar`, `C:\foo\bar`, ``}, @@ -20,15 +26,15 @@ func TestNormaliseWorkdir(t *testing.T) { r, e := normaliseWorkdir(i.current, i.requested) if i.etext != "" && e == nil { - t.Fatalf("TestNormaliseWorkingDir Expected error %s", i.etext) + t.Fatalf("TestNormaliseWorkingDir Expected error %s for '%s' '%s', got no error", i.etext, i.current, i.requested) } if i.etext != "" && e.Error() != i.etext { - t.Fatalf("TestNormaliseWorkingDir Expected error %s, got %s", i.etext, e.Error()) + t.Fatalf("TestNormaliseWorkingDir Expected error %s for '%s' '%s', got %s", i.etext, i.current, i.requested, e.Error()) } if r != i.expected { - t.Fatalf("TestNormaliseWorkingDir Expected %s for %s %s", i.expected, i.current, i.requested) + t.Fatalf("TestNormaliseWorkingDir Expected '%s' for '%s' '%s', got '%s'", i.expected, i.current, i.requested, r) } } }