diff --git a/daemon/volumes.go b/daemon/volumes.go index a4645dab26..f40fdd3e49 100644 --- a/daemon/volumes.go +++ b/daemon/volumes.go @@ -189,10 +189,13 @@ func (container *Container) parseVolumeMountConfig() (map[string]*Mount, error) if _, exists := container.Volumes[path]; exists { continue } - - if stat, err := os.Stat(filepath.Join(container.basefs, path)); err == nil { + realPath, err := container.getResourcePath(path) + if err != nil { + return nil, fmt.Errorf("failed to evaluate the absolute path of symlink") + } + if stat, err := os.Stat(realPath); err == nil { if !stat.IsDir() { - return nil, fmt.Errorf("file exists at %s, can't create volume there") + return nil, fmt.Errorf("file exists at %s, can't create volume there", realPath) } } diff --git a/integration-cli/docker_cli_run_test.go b/integration-cli/docker_cli_run_test.go index 17c22e9b35..0b6e2eddb3 100644 --- a/integration-cli/docker_cli_run_test.go +++ b/integration-cli/docker_cli_run_test.go @@ -475,6 +475,39 @@ func TestRunWithVolumesFromExited(t *testing.T) { logDone("run - regression test for #4979 - volumes-from on exited container") } +// Volume path is a symlink which also exists on the host, and the host side is a file not a dir +// But the volume call is just a normal volume, not a bind mount +func TestRunCreateVolumesInSymlinkDir(t *testing.T) { + testRequires(t, SameHostDaemon) + testRequires(t, NativeExecDriver) + defer deleteAllContainers() + name := "test-volume-symlink" + + dir, err := ioutil.TempDir("", name) + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(dir) + + f, err := os.OpenFile(filepath.Join(dir, "test"), os.O_CREATE, 0700) + if err != nil { + t.Fatal(err) + } + f.Close() + + dockerFile := fmt.Sprintf("FROM busybox\nRUN mkdir -p %s\nRUN ln -s %s /test", dir, dir) + if _, err := buildImage(name, dockerFile, false); err != nil { + t.Fatal(err) + } + defer deleteImages(name) + + if out, _, err := dockerCmd(t, "run", "-v", "/test/test", name); err != nil { + t.Fatal(err, out) + } + + logDone("run - create volume in symlink directory") +} + // Regression test for #4830 func TestRunWithRelativePath(t *testing.T) { defer deleteAllContainers()