@@ -17,8 +17,10 @@ limitations under the License.
17
17
package filesystem
18
18
19
19
import (
20
+ "fmt"
20
21
"os"
21
22
"path/filepath"
23
+ "runtime"
22
24
"strings"
23
25
"time"
24
26
)
@@ -75,6 +77,32 @@ func (fs *DefaultFs) MkdirAll(path string, perm os.FileMode) error {
75
77
return os .MkdirAll (fs .prefix (path ), perm )
76
78
}
77
79
80
+ // MkdirAllWithPathCheck checks if path exists already. If not, it creates a directory
81
+ // named path, along with any necessary parents, and returns nil, or else returns an error.
82
+ // Permission bits perm (before umask) are used for all directories that
83
+ // MkdirAllWithPathCheck creates.
84
+ // If path is already a directory, MkdirAllWithPathCheck does nothing and returns nil.
85
+ // NOTE: In case of Windows NTFS, mount points are implemented as reparse-point
86
+ // (similar to symlink) and do not represent actual directory. Hence Directory existence
87
+ // check for windows NTFS will NOT check for dir, but for symlink presence.
88
+ func MkdirAllWithPathCheck (path string , perm os.FileMode ) error {
89
+ if dir , err := os .Lstat (path ); err == nil {
90
+ // If the path exists already,
91
+ // 1. for Unix/Linux OS, check if the path is directory.
92
+ // 2. for windows NTFS, check if the path is symlink instead of directory.
93
+ if dir .IsDir () ||
94
+ (runtime .GOOS == "windows" && (dir .Mode ()& os .ModeSymlink != 0 )) {
95
+ return nil
96
+ }
97
+ return fmt .Errorf ("path %v exists but is not a directory" , path )
98
+ }
99
+ // If existence of path not known, attempt to create it.
100
+ if err := os .MkdirAll (path , perm ); err != nil {
101
+ return err
102
+ }
103
+ return nil
104
+ }
105
+
78
106
// Chtimes via os.Chtimes
79
107
func (fs * DefaultFs ) Chtimes (name string , atime time.Time , mtime time.Time ) error {
80
108
return os .Chtimes (fs .prefix (name ), atime , mtime )
0 commit comments