It has no external consumers, is written with specific behavior (including
some potentially surprising behavior), making it not a good candidate to
carry in the module.
This moves it internal to the daemon as a non-exported utility, so that
it's only accessible where it's currently used.
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
| ... | ... |
@@ -18,7 +18,6 @@ import ( |
| 18 | 18 |
"github.com/docker/docker/daemon/container" |
| 19 | 19 |
"github.com/docker/docker/daemon/internal/mounttree" |
| 20 | 20 |
"github.com/docker/docker/daemon/internal/unshare" |
| 21 |
- "github.com/docker/docker/pkg/fileutils" |
|
| 22 | 21 |
containertypes "github.com/moby/moby/api/types/container" |
| 23 | 22 |
) |
| 24 | 23 |
|
| ... | ... |
@@ -104,7 +103,7 @@ func (daemon *Daemon) openContainerFS(ctr *container.Container) (_ *containerFSV |
| 104 | 104 |
if err != nil {
|
| 105 | 105 |
return err |
| 106 | 106 |
} |
| 107 |
- if err := fileutils.CreateIfNotExists(dest, stat.IsDir()); err != nil {
|
|
| 107 |
+ if err := createIfNotExists(dest, stat.IsDir()); err != nil {
|
|
| 108 | 108 |
return err |
| 109 | 109 |
} |
| 110 | 110 |
|
| ... | ... |
@@ -252,6 +251,27 @@ func (vw *containerFSView) Stat(ctx context.Context, path string) (*containertyp |
| 252 | 252 |
return stat, err |
| 253 | 253 |
} |
| 254 | 254 |
|
| 255 |
+// createIfNotExists creates a file or a directory only if it does not already exist. |
|
| 256 |
+func createIfNotExists(dest string, isDir bool) error {
|
|
| 257 |
+ if _, err := os.Stat(dest); err != nil {
|
|
| 258 |
+ // FIXME(thaJeztah): this ignores any other error (which may include "dest" is of the wrong type, or permission errors). |
|
| 259 |
+ if os.IsNotExist(err) {
|
|
| 260 |
+ if isDir {
|
|
| 261 |
+ return os.MkdirAll(dest, 0o755) |
|
| 262 |
+ } |
|
| 263 |
+ if err := os.MkdirAll(filepath.Dir(dest), 0o755); err != nil {
|
|
| 264 |
+ return err |
|
| 265 |
+ } |
|
| 266 |
+ f, err := os.OpenFile(dest, os.O_CREATE, 0o755) |
|
| 267 |
+ if err != nil {
|
|
| 268 |
+ return err |
|
| 269 |
+ } |
|
| 270 |
+ _ = f.Close() |
|
| 271 |
+ } |
|
| 272 |
+ } |
|
| 273 |
+ return nil |
|
| 274 |
+} |
|
| 275 |
+ |
|
| 255 | 276 |
// makeMountRRO makes the mount recursively read-only. |
| 256 | 277 |
func makeMountRRO(dest string) error {
|
| 257 | 278 |
attr := &unix.MountAttr{
|
| 258 | 279 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,39 @@ |
| 0 |
+package daemon |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "os" |
|
| 4 |
+ "path/filepath" |
|
| 5 |
+ "testing" |
|
| 6 |
+ |
|
| 7 |
+ "gotest.tools/v3/assert" |
|
| 8 |
+) |
|
| 9 |
+ |
|
| 10 |
+func TestCreateIfNotExists(t *testing.T) {
|
|
| 11 |
+ t.Run("directory", func(t *testing.T) {
|
|
| 12 |
+ toCreate := filepath.Join(t.TempDir(), "tocreate") |
|
| 13 |
+ |
|
| 14 |
+ err := createIfNotExists(toCreate, true) |
|
| 15 |
+ assert.NilError(t, err) |
|
| 16 |
+ |
|
| 17 |
+ fileinfo, err := os.Stat(toCreate) |
|
| 18 |
+ assert.NilError(t, err, "Did not create destination") |
|
| 19 |
+ assert.Assert(t, fileinfo.IsDir(), "Should have been a dir, seems it's not") |
|
| 20 |
+ |
|
| 21 |
+ err = createIfNotExists(toCreate, true) |
|
| 22 |
+ assert.NilError(t, err, "Should not fail if already exists") |
|
| 23 |
+ }) |
|
| 24 |
+ t.Run("file", func(t *testing.T) {
|
|
| 25 |
+ toCreate := filepath.Join(t.TempDir(), "file/to/create") |
|
| 26 |
+ |
|
| 27 |
+ err := createIfNotExists(toCreate, false) |
|
| 28 |
+ assert.NilError(t, err) |
|
| 29 |
+ |
|
| 30 |
+ fileinfo, err := os.Stat(toCreate) |
|
| 31 |
+ assert.NilError(t, err, "Did not create destination") |
|
| 32 |
+ |
|
| 33 |
+ assert.Assert(t, !fileinfo.IsDir(), "Should have been a file, but created a directory") |
|
| 34 |
+ |
|
| 35 |
+ err = createIfNotExists(toCreate, true) |
|
| 36 |
+ assert.NilError(t, err, "Should not fail if already exists") |
|
| 37 |
+ }) |
|
| 38 |
+} |
| ... | ... |
@@ -27,23 +27,3 @@ func ReadSymlinkedDirectory(path string) (realPath string, _ error) {
|
| 27 | 27 |
} |
| 28 | 28 |
return realPath, nil |
| 29 | 29 |
} |
| 30 |
- |
|
| 31 |
-// CreateIfNotExists creates a file or a directory only if it does not already exist. |
|
| 32 |
-func CreateIfNotExists(path string, isDir bool) error {
|
|
| 33 |
- if _, err := os.Stat(path); err != nil {
|
|
| 34 |
- if os.IsNotExist(err) {
|
|
| 35 |
- if isDir {
|
|
| 36 |
- return os.MkdirAll(path, 0o755) |
|
| 37 |
- } |
|
| 38 |
- if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil {
|
|
| 39 |
- return err |
|
| 40 |
- } |
|
| 41 |
- f, err := os.OpenFile(path, os.O_CREATE, 0o755) |
|
| 42 |
- if err != nil {
|
|
| 43 |
- return err |
|
| 44 |
- } |
|
| 45 |
- _ = f.Close() |
|
| 46 |
- } |
|
| 47 |
- } |
|
| 48 |
- return nil |
|
| 49 |
-} |
| ... | ... |
@@ -107,35 +107,3 @@ func TestReadSymlinkedDirectoryToFile(t *testing.T) {
|
| 107 | 107 |
t.Errorf("failed to remove symlink: %s", err)
|
| 108 | 108 |
} |
| 109 | 109 |
} |
| 110 |
- |
|
| 111 |
-func TestCreateIfNotExistsDir(t *testing.T) {
|
|
| 112 |
- folderToCreate := filepath.Join(t.TempDir(), "tocreate") |
|
| 113 |
- |
|
| 114 |
- if err := CreateIfNotExists(folderToCreate, true); err != nil {
|
|
| 115 |
- t.Fatal(err) |
|
| 116 |
- } |
|
| 117 |
- fileinfo, err := os.Stat(folderToCreate) |
|
| 118 |
- if err != nil {
|
|
| 119 |
- t.Fatalf("Should have create a folder, got %v", err)
|
|
| 120 |
- } |
|
| 121 |
- |
|
| 122 |
- if !fileinfo.IsDir() {
|
|
| 123 |
- t.Errorf("Should have been a dir, seems it's not")
|
|
| 124 |
- } |
|
| 125 |
-} |
|
| 126 |
- |
|
| 127 |
-func TestCreateIfNotExistsFile(t *testing.T) {
|
|
| 128 |
- fileToCreate := filepath.Join(t.TempDir(), "file/to/create") |
|
| 129 |
- |
|
| 130 |
- if err := CreateIfNotExists(fileToCreate, false); err != nil {
|
|
| 131 |
- t.Error(err) |
|
| 132 |
- } |
|
| 133 |
- fileinfo, err := os.Stat(fileToCreate) |
|
| 134 |
- if err != nil {
|
|
| 135 |
- t.Fatalf("Should have create a file, got %v", err)
|
|
| 136 |
- } |
|
| 137 |
- |
|
| 138 |
- if fileinfo.IsDir() {
|
|
| 139 |
- t.Errorf("Should have been a file, seems it's not")
|
|
| 140 |
- } |
|
| 141 |
-} |