From 6791230320fa9f8ae9df3e90d5c52d85621828a0 Mon Sep 17 00:00:00 2001 From: Darren Stahl Date: Wed, 27 Jan 2016 13:03:09 -0800 Subject: [PATCH] Combine SetupWorkingDirectory for Linux and Windows Signed-off-by: Darren Stahl --- container/container.go | 28 +++++++++++++++++++- container/container_unix.go | 33 ++++-------------------- container/container_windows.go | 21 ++++++++++----- integration-cli/docker_cli_build_test.go | 17 ++++++++++++ integration-cli/docker_cli_run_test.go | 2 +- 5 files changed, 65 insertions(+), 36 deletions(-) diff --git a/container/container.go b/container/container.go index ea083c52bc..c92e3de4d1 100644 --- a/container/container.go +++ b/container/container.go @@ -22,6 +22,7 @@ import ( "github.com/docker/docker/pkg/promise" "github.com/docker/docker/pkg/signal" "github.com/docker/docker/pkg/symlink" + "github.com/docker/docker/pkg/system" "github.com/docker/docker/runconfig" "github.com/docker/docker/volume" containertypes "github.com/docker/engine-api/types/container" @@ -183,6 +184,30 @@ func (container *Container) WriteHostConfig() error { return json.NewEncoder(f).Encode(&container.HostConfig) } +// SetupWorkingDirectory sets up the container's working directory as set in container.Config.WorkingDir +func (container *Container) SetupWorkingDirectory() error { + if container.Config.WorkingDir == "" { + return nil + } + container.Config.WorkingDir = filepath.Clean(container.Config.WorkingDir) + + pth, err := container.GetResourcePath(container.Config.WorkingDir) + if err != nil { + return err + } + + if err := system.MkdirAll(pth, 0755); err != nil { + pthInfo, err2 := os.Stat(pth) + if err2 == nil && pthInfo != nil && !pthInfo.IsDir() { + return derr.ErrorCodeNotADir.WithArgs(container.Config.WorkingDir) + } + + return err + } + + return nil +} + // GetResourcePath evaluates `path` in the scope of the container's BaseFS, with proper path // sanitisation. Symlinks are all scoped to the BaseFS of the container, as // though the container's BaseFS was `/`. @@ -199,7 +224,8 @@ func (container *Container) WriteHostConfig() error { func (container *Container) GetResourcePath(path string) (string, error) { // IMPORTANT - These are paths on the OS where the daemon is running, hence // any filepath operations must be done in an OS agnostic way. - cleanPath := filepath.Join(string(os.PathSeparator), path) + + cleanPath := cleanResourcePath(path) r, e := symlink.FollowSymlinkInScope(filepath.Join(container.BaseFS, cleanPath), container.BaseFS) return r, e } diff --git a/container/container_unix.go b/container/container_unix.go index 22c7544179..b7e6728509 100644 --- a/container/container_unix.go +++ b/container/container_unix.go @@ -398,34 +398,6 @@ func (container *Container) BuildCreateEndpointOptions(n libnetwork.Network, epC return createOptions, nil } -// SetupWorkingDirectory sets up the container's working directory as set in container.Config.WorkingDir -func (container *Container) SetupWorkingDirectory() error { - if container.Config.WorkingDir == "" { - return nil - } - container.Config.WorkingDir = filepath.Clean(container.Config.WorkingDir) - - pth, err := container.GetResourcePath(container.Config.WorkingDir) - if err != nil { - return err - } - - pthInfo, err := os.Stat(pth) - if err != nil { - if !os.IsNotExist(err) { - return err - } - - if err := system.MkdirAll(pth, 0755); err != nil { - return err - } - } - if pthInfo != nil && !pthInfo.IsDir() { - return derr.ErrorCodeNotADir.WithArgs(container.Config.WorkingDir) - } - return nil -} - // appendNetworkMounts appends any network mounts to the array of mount points passed in func appendNetworkMounts(container *Container, volumeMounts []volume.MountPoint) ([]volume.MountPoint, error) { for _, mnt := range container.NetworkMounts() { @@ -768,3 +740,8 @@ func (container *Container) TmpfsMounts() []execdriver.Mount { } return mounts } + +// cleanResourcePath cleans a resource path and prepares to combine with mnt path +func cleanResourcePath(path string) string { + return filepath.Join(string(os.PathSeparator), path) +} diff --git a/container/container_windows.go b/container/container_windows.go index af68086f8d..61a8994244 100644 --- a/container/container_windows.go +++ b/container/container_windows.go @@ -3,6 +3,9 @@ package container import ( + "os" + "path/filepath" + "github.com/docker/docker/daemon/execdriver" "github.com/docker/docker/volume" "github.com/docker/engine-api/types/container" @@ -22,12 +25,6 @@ func (container *Container) CreateDaemonEnvironment(linkedEnv []string) []string return container.Config.Env } -// SetupWorkingDirectory initializes the container working directory. -// This is a NOOP In windows. -func (container *Container) SetupWorkingDirectory() error { - return nil -} - // UnmountIpcMounts unmount Ipc related mounts. // This is a NOOP on windows. func (container *Container) UnmountIpcMounts(unmount func(pth string) error) { @@ -59,3 +56,15 @@ func (container *Container) UpdateContainer(hostConfig *container.HostConfig) er func appendNetworkMounts(container *Container, volumeMounts []volume.MountPoint) ([]volume.MountPoint, error) { return volumeMounts, nil } + +// cleanResourcePath cleans a resource path by removing C:\ syntax, and prepares +// to combine with a volume path +func cleanResourcePath(path string) string { + if len(path) >= 2 { + c := path[0] + if path[1] == ':' && ('a' <= c && c <= 'z' || 'A' <= c && c <= 'Z') { + path = path[2:] + } + } + return filepath.Join(string(os.PathSeparator), path) +} diff --git a/integration-cli/docker_cli_build_test.go b/integration-cli/docker_cli_build_test.go index 42bfc6be87..2c157d59cc 100644 --- a/integration-cli/docker_cli_build_test.go +++ b/integration-cli/docker_cli_build_test.go @@ -6568,3 +6568,20 @@ func (s *DockerSuite) TestBuildFailsGitNotCallable(c *check.C) { c.Assert(err, checker.NotNil) c.Assert(out, checker.Contains, "unable to prepare context: unable to find 'git': ") } + +// TestBuildWorkdirWindowsPath tests that a Windows style path works as a workdir +func (s *DockerSuite) TestBuildWorkdirWindowsPath(c *check.C) { + testRequires(c, DaemonIsWindows) + name := "testbuildworkdirwindowspath" + + _, err := buildImage(name, ` + FROM windowsservercore + RUN mkdir C:\\work + WORKDIR C:\\work + RUN if "%CD%" NEQ "C:\work" exit -1 + `, true) + + if err != nil { + c.Fatal(err) + } +} diff --git a/integration-cli/docker_cli_run_test.go b/integration-cli/docker_cli_run_test.go index f09e3f67c8..0ff2668572 100644 --- a/integration-cli/docker_cli_run_test.go +++ b/integration-cli/docker_cli_run_test.go @@ -1723,7 +1723,7 @@ func (s *DockerSuite) TestRunWorkdirExistsAndIsFile(c *check.C) { expected := "Cannot mkdir: /bin/cat is not a directory" if daemonPlatform == "windows" { existingFile = `\windows\system32\ntdll.dll` - expected = "The directory name is invalid" + expected = `Cannot mkdir: \windows\system32\ntdll.dll is not a directory.` } out, exitCode, err := dockerCmdWithError("run", "-w", existingFile, "busybox")