diff --git a/daemon/containerfs_linux.go b/daemon/containerfs_linux.go index 06455461a3..410bc38db3 100644 --- a/daemon/containerfs_linux.go +++ b/daemon/containerfs_linux.go @@ -18,7 +18,6 @@ import ( "github.com/docker/docker/daemon/container" "github.com/docker/docker/daemon/internal/mounttree" "github.com/docker/docker/daemon/internal/unshare" - "github.com/docker/docker/pkg/fileutils" containertypes "github.com/moby/moby/api/types/container" ) @@ -104,7 +103,7 @@ func (daemon *Daemon) openContainerFS(ctr *container.Container) (_ *containerFSV if err != nil { return err } - if err := fileutils.CreateIfNotExists(dest, stat.IsDir()); err != nil { + if err := createIfNotExists(dest, stat.IsDir()); err != nil { return err } @@ -252,6 +251,27 @@ func (vw *containerFSView) Stat(ctx context.Context, path string) (*containertyp return stat, err } +// createIfNotExists creates a file or a directory only if it does not already exist. +func createIfNotExists(dest string, isDir bool) error { + if _, err := os.Stat(dest); err != nil { + // FIXME(thaJeztah): this ignores any other error (which may include "dest" is of the wrong type, or permission errors). + if os.IsNotExist(err) { + if isDir { + return os.MkdirAll(dest, 0o755) + } + if err := os.MkdirAll(filepath.Dir(dest), 0o755); err != nil { + return err + } + f, err := os.OpenFile(dest, os.O_CREATE, 0o755) + if err != nil { + return err + } + _ = f.Close() + } + } + return nil +} + // makeMountRRO makes the mount recursively read-only. func makeMountRRO(dest string) error { attr := &unix.MountAttr{ diff --git a/daemon/containerfs_linux_test.go b/daemon/containerfs_linux_test.go new file mode 100644 index 0000000000..7d436442d3 --- /dev/null +++ b/daemon/containerfs_linux_test.go @@ -0,0 +1,39 @@ +package daemon + +import ( + "os" + "path/filepath" + "testing" + + "gotest.tools/v3/assert" +) + +func TestCreateIfNotExists(t *testing.T) { + t.Run("directory", func(t *testing.T) { + toCreate := filepath.Join(t.TempDir(), "tocreate") + + err := createIfNotExists(toCreate, true) + assert.NilError(t, err) + + fileinfo, err := os.Stat(toCreate) + assert.NilError(t, err, "Did not create destination") + assert.Assert(t, fileinfo.IsDir(), "Should have been a dir, seems it's not") + + err = createIfNotExists(toCreate, true) + assert.NilError(t, err, "Should not fail if already exists") + }) + t.Run("file", func(t *testing.T) { + toCreate := filepath.Join(t.TempDir(), "file/to/create") + + err := createIfNotExists(toCreate, false) + assert.NilError(t, err) + + fileinfo, err := os.Stat(toCreate) + assert.NilError(t, err, "Did not create destination") + + assert.Assert(t, !fileinfo.IsDir(), "Should have been a file, but created a directory") + + err = createIfNotExists(toCreate, true) + assert.NilError(t, err, "Should not fail if already exists") + }) +} diff --git a/pkg/fileutils/fileutils.go b/pkg/fileutils/fileutils.go index 2528d0013e..ff3c2ecce2 100644 --- a/pkg/fileutils/fileutils.go +++ b/pkg/fileutils/fileutils.go @@ -27,23 +27,3 @@ func ReadSymlinkedDirectory(path string) (realPath string, _ error) { } return realPath, nil } - -// CreateIfNotExists creates a file or a directory only if it does not already exist. -func CreateIfNotExists(path string, isDir bool) error { - if _, err := os.Stat(path); err != nil { - if os.IsNotExist(err) { - if isDir { - return os.MkdirAll(path, 0o755) - } - if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil { - return err - } - f, err := os.OpenFile(path, os.O_CREATE, 0o755) - if err != nil { - return err - } - _ = f.Close() - } - } - return nil -} diff --git a/pkg/fileutils/fileutils_test.go b/pkg/fileutils/fileutils_test.go index ec370187b2..9b5ced50b2 100644 --- a/pkg/fileutils/fileutils_test.go +++ b/pkg/fileutils/fileutils_test.go @@ -107,35 +107,3 @@ func TestReadSymlinkedDirectoryToFile(t *testing.T) { t.Errorf("failed to remove symlink: %s", err) } } - -func TestCreateIfNotExistsDir(t *testing.T) { - folderToCreate := filepath.Join(t.TempDir(), "tocreate") - - if err := CreateIfNotExists(folderToCreate, true); err != nil { - t.Fatal(err) - } - fileinfo, err := os.Stat(folderToCreate) - if err != nil { - t.Fatalf("Should have create a folder, got %v", err) - } - - if !fileinfo.IsDir() { - t.Errorf("Should have been a dir, seems it's not") - } -} - -func TestCreateIfNotExistsFile(t *testing.T) { - fileToCreate := filepath.Join(t.TempDir(), "file/to/create") - - if err := CreateIfNotExists(fileToCreate, false); err != nil { - t.Error(err) - } - fileinfo, err := os.Stat(fileToCreate) - if err != nil { - t.Fatalf("Should have create a file, got %v", err) - } - - if fileinfo.IsDir() { - t.Errorf("Should have been a file, seems it's not") - } -}