As is seem in the comment of `normaliseWorkdir` for windows:
```
...
// WORKDIR c:\\foo --> C:\foo
// WORKDIR \\foo --> C:\foo
...
```
However, this is not the case in the current implementation because
`filepath.FromSlash` is used and `FromSlash` does not replace multiple
separator with a single one (`file.Clean` does).
So `normaliseWorkdir` does not truly normalize workdir.
This fix changes the implementation of `normaliseWorkdir` and use
`filepath.Clean` instead of `filepath.FromSlash`.
Additional test cases have been added to the unit test.
Signed-off-by: Yong Tang <yong.tang.github@outlook.com>
| ... | ... |
@@ -10,6 +10,8 @@ import ( |
| 10 | 10 |
"github.com/docker/docker/pkg/system" |
| 11 | 11 |
) |
| 12 | 12 |
|
| 13 |
+var pattern = regexp.MustCompile(`^[a-zA-Z]:\.$`) |
|
| 14 |
+ |
|
| 13 | 15 |
// normaliseWorkdir normalises a user requested working directory in a |
| 14 | 16 |
// platform sematically consistent way. |
| 15 | 17 |
func normaliseWorkdir(current string, requested string) (string, error) {
|
| ... | ... |
@@ -17,8 +19,27 @@ func normaliseWorkdir(current string, requested string) (string, error) {
|
| 17 | 17 |
return "", fmt.Errorf("cannot normalise nothing")
|
| 18 | 18 |
} |
| 19 | 19 |
|
| 20 |
- current = filepath.FromSlash(current) |
|
| 21 |
- requested = filepath.FromSlash(requested) |
|
| 20 |
+ // `filepath.Clean` will replace "" with "." so skip in that case |
|
| 21 |
+ if current != "" {
|
|
| 22 |
+ current = filepath.Clean(current) |
|
| 23 |
+ } |
|
| 24 |
+ if requested != "" {
|
|
| 25 |
+ requested = filepath.Clean(requested) |
|
| 26 |
+ } |
|
| 27 |
+ |
|
| 28 |
+ // If either current or requested in Windows is: |
|
| 29 |
+ // C: |
|
| 30 |
+ // C:. |
|
| 31 |
+ // then an error will be thrown as the definition for the above |
|
| 32 |
+ // refers to `current directory on drive C:` |
|
| 33 |
+ // Since filepath.Clean() will automatically normalize the above |
|
| 34 |
+ // to `C:.`, we only need to check the last format |
|
| 35 |
+ if pattern.MatchString(current) {
|
|
| 36 |
+ return "", fmt.Errorf("%s is not a directory. If you are specifying a drive letter, please add a trailing '\\'", current)
|
|
| 37 |
+ } |
|
| 38 |
+ if pattern.MatchString(requested) {
|
|
| 39 |
+ return "", fmt.Errorf("%s is not a directory. If you are specifying a drive letter, please add a trailing '\\'", requested)
|
|
| 40 |
+ } |
|
| 22 | 41 |
|
| 23 | 42 |
// Target semantics is C:\somefolder, specifically in the format: |
| 24 | 43 |
// UPPERCASEDriveLetter-Colon-Backslash-FolderName. We are already |
| ... | ... |
@@ -7,9 +7,15 @@ import "testing" |
| 7 | 7 |
func TestNormaliseWorkdir(t *testing.T) {
|
| 8 | 8 |
tests := []struct{ current, requested, expected, etext string }{
|
| 9 | 9 |
{``, ``, ``, `cannot normalise nothing`},
|
| 10 |
+ {``, `C:`, ``, `C:. is not a directory. If you are specifying a drive letter, please add a trailing '\'`},
|
|
| 11 |
+ {``, `C:.`, ``, `C:. is not a directory. If you are specifying a drive letter, please add a trailing '\'`},
|
|
| 12 |
+ {`c:`, `\a`, ``, `c:. is not a directory. If you are specifying a drive letter, please add a trailing '\'`},
|
|
| 13 |
+ {`c:.`, `\a`, ``, `c:. is not a directory. If you are specifying a drive letter, please add a trailing '\'`},
|
|
| 10 | 14 |
{``, `a`, `C:\a`, ``},
|
| 11 | 15 |
{``, `c:\foo`, `C:\foo`, ``},
|
| 16 |
+ {``, `c:\\foo`, `C:\foo`, ``},
|
|
| 12 | 17 |
{``, `\foo`, `C:\foo`, ``},
|
| 18 |
+ {``, `\\foo`, `C:\foo`, ``},
|
|
| 13 | 19 |
{``, `/foo`, `C:\foo`, ``},
|
| 14 | 20 |
{``, `C:/foo`, `C:\foo`, ``},
|
| 15 | 21 |
{`C:\foo`, `bar`, `C:\foo\bar`, ``},
|
| ... | ... |
@@ -20,15 +26,15 @@ func TestNormaliseWorkdir(t *testing.T) {
|
| 20 | 20 |
r, e := normaliseWorkdir(i.current, i.requested) |
| 21 | 21 |
|
| 22 | 22 |
if i.etext != "" && e == nil {
|
| 23 |
- t.Fatalf("TestNormaliseWorkingDir Expected error %s", i.etext)
|
|
| 23 |
+ t.Fatalf("TestNormaliseWorkingDir Expected error %s for '%s' '%s', got no error", i.etext, i.current, i.requested)
|
|
| 24 | 24 |
} |
| 25 | 25 |
|
| 26 | 26 |
if i.etext != "" && e.Error() != i.etext {
|
| 27 |
- t.Fatalf("TestNormaliseWorkingDir Expected error %s, got %s", i.etext, e.Error())
|
|
| 27 |
+ t.Fatalf("TestNormaliseWorkingDir Expected error %s for '%s' '%s', got %s", i.etext, i.current, i.requested, e.Error())
|
|
| 28 | 28 |
} |
| 29 | 29 |
|
| 30 | 30 |
if r != i.expected {
|
| 31 |
- t.Fatalf("TestNormaliseWorkingDir Expected %s for %s %s", i.expected, i.current, i.requested)
|
|
| 31 |
+ t.Fatalf("TestNormaliseWorkingDir Expected '%s' for '%s' '%s', got '%s'", i.expected, i.current, i.requested, r)
|
|
| 32 | 32 |
} |
| 33 | 33 |
} |
| 34 | 34 |
} |