Signed-off-by: Darren Stahl <darst@microsoft.com>
| ... | ... |
@@ -22,6 +22,7 @@ import ( |
| 22 | 22 |
"github.com/docker/docker/pkg/promise" |
| 23 | 23 |
"github.com/docker/docker/pkg/signal" |
| 24 | 24 |
"github.com/docker/docker/pkg/symlink" |
| 25 |
+ "github.com/docker/docker/pkg/system" |
|
| 25 | 26 |
"github.com/docker/docker/runconfig" |
| 26 | 27 |
"github.com/docker/docker/volume" |
| 27 | 28 |
containertypes "github.com/docker/engine-api/types/container" |
| ... | ... |
@@ -183,6 +184,30 @@ func (container *Container) WriteHostConfig() error {
|
| 183 | 183 |
return json.NewEncoder(f).Encode(&container.HostConfig) |
| 184 | 184 |
} |
| 185 | 185 |
|
| 186 |
+// SetupWorkingDirectory sets up the container's working directory as set in container.Config.WorkingDir |
|
| 187 |
+func (container *Container) SetupWorkingDirectory() error {
|
|
| 188 |
+ if container.Config.WorkingDir == "" {
|
|
| 189 |
+ return nil |
|
| 190 |
+ } |
|
| 191 |
+ container.Config.WorkingDir = filepath.Clean(container.Config.WorkingDir) |
|
| 192 |
+ |
|
| 193 |
+ pth, err := container.GetResourcePath(container.Config.WorkingDir) |
|
| 194 |
+ if err != nil {
|
|
| 195 |
+ return err |
|
| 196 |
+ } |
|
| 197 |
+ |
|
| 198 |
+ if err := system.MkdirAll(pth, 0755); err != nil {
|
|
| 199 |
+ pthInfo, err2 := os.Stat(pth) |
|
| 200 |
+ if err2 == nil && pthInfo != nil && !pthInfo.IsDir() {
|
|
| 201 |
+ return derr.ErrorCodeNotADir.WithArgs(container.Config.WorkingDir) |
|
| 202 |
+ } |
|
| 203 |
+ |
|
| 204 |
+ return err |
|
| 205 |
+ } |
|
| 206 |
+ |
|
| 207 |
+ return nil |
|
| 208 |
+} |
|
| 209 |
+ |
|
| 186 | 210 |
// GetResourcePath evaluates `path` in the scope of the container's BaseFS, with proper path |
| 187 | 211 |
// sanitisation. Symlinks are all scoped to the BaseFS of the container, as |
| 188 | 212 |
// though the container's BaseFS was `/`. |
| ... | ... |
@@ -199,7 +224,8 @@ func (container *Container) WriteHostConfig() error {
|
| 199 | 199 |
func (container *Container) GetResourcePath(path string) (string, error) {
|
| 200 | 200 |
// IMPORTANT - These are paths on the OS where the daemon is running, hence |
| 201 | 201 |
// any filepath operations must be done in an OS agnostic way. |
| 202 |
- cleanPath := filepath.Join(string(os.PathSeparator), path) |
|
| 202 |
+ |
|
| 203 |
+ cleanPath := cleanResourcePath(path) |
|
| 203 | 204 |
r, e := symlink.FollowSymlinkInScope(filepath.Join(container.BaseFS, cleanPath), container.BaseFS) |
| 204 | 205 |
return r, e |
| 205 | 206 |
} |
| ... | ... |
@@ -398,34 +398,6 @@ func (container *Container) BuildCreateEndpointOptions(n libnetwork.Network, epC |
| 398 | 398 |
return createOptions, nil |
| 399 | 399 |
} |
| 400 | 400 |
|
| 401 |
-// SetupWorkingDirectory sets up the container's working directory as set in container.Config.WorkingDir |
|
| 402 |
-func (container *Container) SetupWorkingDirectory() error {
|
|
| 403 |
- if container.Config.WorkingDir == "" {
|
|
| 404 |
- return nil |
|
| 405 |
- } |
|
| 406 |
- container.Config.WorkingDir = filepath.Clean(container.Config.WorkingDir) |
|
| 407 |
- |
|
| 408 |
- pth, err := container.GetResourcePath(container.Config.WorkingDir) |
|
| 409 |
- if err != nil {
|
|
| 410 |
- return err |
|
| 411 |
- } |
|
| 412 |
- |
|
| 413 |
- pthInfo, err := os.Stat(pth) |
|
| 414 |
- if err != nil {
|
|
| 415 |
- if !os.IsNotExist(err) {
|
|
| 416 |
- return err |
|
| 417 |
- } |
|
| 418 |
- |
|
| 419 |
- if err := system.MkdirAll(pth, 0755); err != nil {
|
|
| 420 |
- return err |
|
| 421 |
- } |
|
| 422 |
- } |
|
| 423 |
- if pthInfo != nil && !pthInfo.IsDir() {
|
|
| 424 |
- return derr.ErrorCodeNotADir.WithArgs(container.Config.WorkingDir) |
|
| 425 |
- } |
|
| 426 |
- return nil |
|
| 427 |
-} |
|
| 428 |
- |
|
| 429 | 401 |
// appendNetworkMounts appends any network mounts to the array of mount points passed in |
| 430 | 402 |
func appendNetworkMounts(container *Container, volumeMounts []volume.MountPoint) ([]volume.MountPoint, error) {
|
| 431 | 403 |
for _, mnt := range container.NetworkMounts() {
|
| ... | ... |
@@ -768,3 +740,8 @@ func (container *Container) TmpfsMounts() []execdriver.Mount {
|
| 768 | 768 |
} |
| 769 | 769 |
return mounts |
| 770 | 770 |
} |
| 771 |
+ |
|
| 772 |
+// cleanResourcePath cleans a resource path and prepares to combine with mnt path |
|
| 773 |
+func cleanResourcePath(path string) string {
|
|
| 774 |
+ return filepath.Join(string(os.PathSeparator), path) |
|
| 775 |
+} |
| ... | ... |
@@ -3,6 +3,9 @@ |
| 3 | 3 |
package container |
| 4 | 4 |
|
| 5 | 5 |
import ( |
| 6 |
+ "os" |
|
| 7 |
+ "path/filepath" |
|
| 8 |
+ |
|
| 6 | 9 |
"github.com/docker/docker/daemon/execdriver" |
| 7 | 10 |
"github.com/docker/docker/volume" |
| 8 | 11 |
"github.com/docker/engine-api/types/container" |
| ... | ... |
@@ -22,12 +25,6 @@ func (container *Container) CreateDaemonEnvironment(linkedEnv []string) []string |
| 22 | 22 |
return container.Config.Env |
| 23 | 23 |
} |
| 24 | 24 |
|
| 25 |
-// SetupWorkingDirectory initializes the container working directory. |
|
| 26 |
-// This is a NOOP In windows. |
|
| 27 |
-func (container *Container) SetupWorkingDirectory() error {
|
|
| 28 |
- return nil |
|
| 29 |
-} |
|
| 30 |
- |
|
| 31 | 25 |
// UnmountIpcMounts unmount Ipc related mounts. |
| 32 | 26 |
// This is a NOOP on windows. |
| 33 | 27 |
func (container *Container) UnmountIpcMounts(unmount func(pth string) error) {
|
| ... | ... |
@@ -59,3 +56,15 @@ func (container *Container) UpdateContainer(hostConfig *container.HostConfig) er |
| 59 | 59 |
func appendNetworkMounts(container *Container, volumeMounts []volume.MountPoint) ([]volume.MountPoint, error) {
|
| 60 | 60 |
return volumeMounts, nil |
| 61 | 61 |
} |
| 62 |
+ |
|
| 63 |
+// cleanResourcePath cleans a resource path by removing C:\ syntax, and prepares |
|
| 64 |
+// to combine with a volume path |
|
| 65 |
+func cleanResourcePath(path string) string {
|
|
| 66 |
+ if len(path) >= 2 {
|
|
| 67 |
+ c := path[0] |
|
| 68 |
+ if path[1] == ':' && ('a' <= c && c <= 'z' || 'A' <= c && c <= 'Z') {
|
|
| 69 |
+ path = path[2:] |
|
| 70 |
+ } |
|
| 71 |
+ } |
|
| 72 |
+ return filepath.Join(string(os.PathSeparator), path) |
|
| 73 |
+} |
| ... | ... |
@@ -6568,3 +6568,20 @@ func (s *DockerSuite) TestBuildFailsGitNotCallable(c *check.C) {
|
| 6568 | 6568 |
c.Assert(err, checker.NotNil) |
| 6569 | 6569 |
c.Assert(out, checker.Contains, "unable to prepare context: unable to find 'git': ") |
| 6570 | 6570 |
} |
| 6571 |
+ |
|
| 6572 |
+// TestBuildWorkdirWindowsPath tests that a Windows style path works as a workdir |
|
| 6573 |
+func (s *DockerSuite) TestBuildWorkdirWindowsPath(c *check.C) {
|
|
| 6574 |
+ testRequires(c, DaemonIsWindows) |
|
| 6575 |
+ name := "testbuildworkdirwindowspath" |
|
| 6576 |
+ |
|
| 6577 |
+ _, err := buildImage(name, ` |
|
| 6578 |
+ FROM windowsservercore |
|
| 6579 |
+ RUN mkdir C:\\work |
|
| 6580 |
+ WORKDIR C:\\work |
|
| 6581 |
+ RUN if "%CD%" NEQ "C:\work" exit -1 |
|
| 6582 |
+ `, true) |
|
| 6583 |
+ |
|
| 6584 |
+ if err != nil {
|
|
| 6585 |
+ c.Fatal(err) |
|
| 6586 |
+ } |
|
| 6587 |
+} |
| ... | ... |
@@ -1723,7 +1723,7 @@ func (s *DockerSuite) TestRunWorkdirExistsAndIsFile(c *check.C) {
|
| 1723 | 1723 |
expected := "Cannot mkdir: /bin/cat is not a directory" |
| 1724 | 1724 |
if daemonPlatform == "windows" {
|
| 1725 | 1725 |
existingFile = `\windows\system32\ntdll.dll` |
| 1726 |
- expected = "The directory name is invalid" |
|
| 1726 |
+ expected = `Cannot mkdir: \windows\system32\ntdll.dll is not a directory.` |
|
| 1727 | 1727 |
} |
| 1728 | 1728 |
|
| 1729 | 1729 |
out, exitCode, err := dockerCmdWithError("run", "-w", existingFile, "busybox")
|