diff --git a/pkg/idtools/idtools_unix.go b/pkg/idtools/idtools_unix.go index ff7968f854..b5e9c84075 100644 --- a/pkg/idtools/idtools_unix.go +++ b/pkg/idtools/idtools_unix.go @@ -10,6 +10,7 @@ import ( "path/filepath" "strings" "sync" + "syscall" "github.com/docker/docker/pkg/system" "github.com/opencontainers/runc/libcontainer/user" @@ -29,6 +30,9 @@ func mkdirAs(path string, mode os.FileMode, ownerUID, ownerGID int, mkAll, chown stat, err := system.Stat(path) if err == nil { + if !stat.IsDir() { + return &os.PathError{"mkdir", path, syscall.ENOTDIR} + } if !chownExisting { return nil } diff --git a/pkg/idtools/idtools_unix_test.go b/pkg/idtools/idtools_unix_test.go index afefdb34d0..396ff202d5 100644 --- a/pkg/idtools/idtools_unix_test.go +++ b/pkg/idtools/idtools_unix_test.go @@ -378,6 +378,20 @@ func TestLookupUserAndGroupThatDoesNotExist(t *testing.T) { assert.Error(t, err) } +// TestMkdirIsNotDir checks that mkdirAs() function (used by MkdirAll...) +// returns a correct error in case a directory which it is about to create +// already exists but is a file (rather than a directory). +func TestMkdirIsNotDir(t *testing.T) { + file, err := ioutil.TempFile("", t.Name()) + if err != nil { + t.Fatalf("Couldn't create temp dir: %v", err) + } + defer os.Remove(file.Name()) + + err = mkdirAs(file.Name(), 0755, 0, 0, false, false) + assert.EqualError(t, err, "mkdir "+file.Name()+": not a directory") +} + func RequiresRoot(t *testing.T) { skip.IfCondition(t, os.Getuid() != 0, "skipping test that requires root") } diff --git a/pkg/system/stat_unix.go b/pkg/system/stat_unix.go index 91c7d121cc..9dcec6afbd 100644 --- a/pkg/system/stat_unix.go +++ b/pkg/system/stat_unix.go @@ -47,6 +47,11 @@ func (s StatT) Mtim() syscall.Timespec { return s.mtim } +// IsDir reports whether s describes a directory. +func (s StatT) IsDir() bool { + return s.mode&syscall.S_IFDIR != 0 +} + // Stat takes a path to a file and returns // a system.StatT type pertaining to that file. //