diff --git a/container.go b/container.go index 62f934884c..223ac811bd 100644 --- a/container.go +++ b/container.go @@ -610,6 +610,7 @@ func (container *Container) Start() (err error) { // Create the requested volumes if they don't exist for volPath := range container.Config.Volumes { volPath = path.Clean(volPath) + volIsDir := true // Skip existing volumes if _, exists := container.Volumes[volPath]; exists { continue @@ -624,6 +625,16 @@ func (container *Container) Start() (err error) { if strings.ToLower(bindMap.Mode) == "rw" { srcRW = true } + if file, err := os.Open(bindMap.SrcPath); err != nil { + return err + } else { + defer file.Close() + if stat, err := file.Stat(); err != nil { + return err + } else { + volIsDir = stat.IsDir() + } + } // Otherwise create an directory in $ROOT/volumes/ and use that } else { c, err := container.runtime.volumes.Create(nil, container, "", "", nil) @@ -640,8 +651,30 @@ func (container *Container) Start() (err error) { container.VolumesRW[volPath] = srcRW // Create the mountpoint rootVolPath := path.Join(container.RootfsPath(), volPath) - if err := os.MkdirAll(rootVolPath, 0755); err != nil { - return err + if volIsDir { + if err := os.MkdirAll(rootVolPath, 0755); err != nil { + return err + } + } + + volPath = path.Join(container.RootfsPath(), volPath) + if _, err := os.Stat(volPath); err != nil { + if os.IsNotExist(err) { + if volIsDir { + if err := os.MkdirAll(volPath, 0755); err != nil { + return err + } + } else { + if err := os.MkdirAll(path.Dir(volPath), 0755); err != nil { + return err + } + if f, err := os.OpenFile(volPath, os.O_CREATE, 0755); err != nil { + return err + } else { + f.Close() + } + } + } } // Do not copy or change permissions if we are mounting from the host diff --git a/integration/container_test.go b/integration/container_test.go index e23e3b4985..b0719d30a3 100644 --- a/integration/container_test.go +++ b/integration/container_test.go @@ -1257,6 +1257,13 @@ func TestBindMounts(t *testing.T) { if _, err := runContainer(eng, r, []string{"-v", fmt.Sprintf("%s:.", tmpDir), "_", "ls", "."}, nil); err == nil { t.Fatal("Container bind mounted illegal directory") } + + // test mount a file + runContainer(eng, r, []string{"-v", fmt.Sprintf("%s/holla:/tmp/holla:rw", tmpDir), "_", "sh", "-c", "echo -n 'yotta' > /tmp/holla"}, t) + content := readFile(path.Join(tmpDir, "holla"), t) // Will fail if the file doesn't exist + if content != "yotta" { + t.Fatal("Container failed to write to bind mount file") + } } // Test that -volumes-from supports both read-only mounts