]>
Commit | Line | Data |
---|---|---|
9b12e4fe JC |
1 | // +build windows |
2 | ||
3 | package system | |
4 | ||
5 | import ( | |
6 | "os" | |
7 | "path/filepath" | |
8 | "regexp" | |
9 | "strings" | |
10 | "syscall" | |
11 | ) | |
12 | ||
13 | // MkdirAll implementation that is volume path aware for Windows. | |
14 | func MkdirAll(path string, perm os.FileMode) error { | |
15 | if re := regexp.MustCompile(`^\\\\\?\\Volume{[a-z0-9-]+}$`); re.MatchString(path) { | |
16 | return nil | |
17 | } | |
18 | ||
19 | // The rest of this method is copied from os.MkdirAll and should be kept | |
20 | // as-is to ensure compatibility. | |
21 | ||
22 | // Fast path: if we can tell whether path is a directory or file, stop with success or error. | |
23 | dir, err := os.Stat(path) | |
24 | if err == nil { | |
25 | if dir.IsDir() { | |
26 | return nil | |
27 | } | |
28 | return &os.PathError{ | |
29 | Op: "mkdir", | |
30 | Path: path, | |
31 | Err: syscall.ENOTDIR, | |
32 | } | |
33 | } | |
34 | ||
35 | // Slow path: make sure parent exists and then call Mkdir for path. | |
36 | i := len(path) | |
37 | for i > 0 && os.IsPathSeparator(path[i-1]) { // Skip trailing path separator. | |
38 | i-- | |
39 | } | |
40 | ||
41 | j := i | |
42 | for j > 0 && !os.IsPathSeparator(path[j-1]) { // Scan backward over element. | |
43 | j-- | |
44 | } | |
45 | ||
46 | if j > 1 { | |
47 | // Create parent | |
48 | err = MkdirAll(path[0:j-1], perm) | |
49 | if err != nil { | |
50 | return err | |
51 | } | |
52 | } | |
53 | ||
54 | // Parent now exists; invoke Mkdir and use its result. | |
55 | err = os.Mkdir(path, perm) | |
56 | if err != nil { | |
57 | // Handle arguments like "foo/." by | |
58 | // double-checking that directory doesn't exist. | |
59 | dir, err1 := os.Lstat(path) | |
60 | if err1 == nil && dir.IsDir() { | |
61 | return nil | |
62 | } | |
63 | return err | |
64 | } | |
65 | return nil | |
66 | } | |
67 | ||
68 | // IsAbs is a platform-specific wrapper for filepath.IsAbs. On Windows, | |
69 | // golang filepath.IsAbs does not consider a path \windows\system32 as absolute | |
70 | // as it doesn't start with a drive-letter/colon combination. However, in | |
71 | // docker we need to verify things such as WORKDIR /windows/system32 in | |
72 | // a Dockerfile (which gets translated to \windows\system32 when being processed | |
73 | // by the daemon. This SHOULD be treated as absolute from a docker processing | |
74 | // perspective. | |
75 | func IsAbs(path string) bool { | |
76 | if !filepath.IsAbs(path) { | |
77 | if !strings.HasPrefix(path, string(os.PathSeparator)) { | |
78 | return false | |
79 | } | |
80 | } | |
81 | return true | |
82 | } |