github.com/Prakhar-Agarwal-byte/moby@v0.0.0-20231027092010-a14e3e8ab87e/pkg/system/filesys_windows.go (about) 1 package system // import "github.com/Prakhar-Agarwal-byte/moby/pkg/system" 2 3 import ( 4 "os" 5 "regexp" 6 "syscall" 7 "unsafe" 8 9 "golang.org/x/sys/windows" 10 ) 11 12 // SddlAdministratorsLocalSystem is local administrators plus NT AUTHORITY\System. 13 const SddlAdministratorsLocalSystem = "D:P(A;OICI;GA;;;BA)(A;OICI;GA;;;SY)" 14 15 // volumePath is a regular expression to check if a path is a Windows 16 // volume path (e.g., "\\?\Volume{4c1b02c1-d990-11dc-99ae-806e6f6e6963}" 17 // or "\\?\Volume{4c1b02c1-d990-11dc-99ae-806e6f6e6963}\"). 18 var volumePath = regexp.MustCompile(`^\\\\\?\\Volume{[a-z0-9-]+}\\?$`) 19 20 // MkdirAllWithACL is a custom version of os.MkdirAll modified for use on Windows 21 // so that it is both volume path aware, and can create a directory with 22 // an appropriate SDDL defined ACL. 23 func MkdirAllWithACL(path string, _ os.FileMode, sddl string) error { 24 sa, err := makeSecurityAttributes(sddl) 25 if err != nil { 26 return &os.PathError{Op: "mkdirall", Path: path, Err: err} 27 } 28 return mkdirall(path, sa) 29 } 30 31 // MkdirAll is a custom version of os.MkdirAll that is volume path aware for 32 // Windows. It can be used as a drop-in replacement for os.MkdirAll. 33 func MkdirAll(path string, _ os.FileMode) error { 34 return mkdirall(path, nil) 35 } 36 37 // mkdirall is a custom version of os.MkdirAll modified for use on Windows 38 // so that it is both volume path aware, and can create a directory with 39 // a DACL. 40 func mkdirall(path string, perm *windows.SecurityAttributes) error { 41 if volumePath.MatchString(path) { 42 return nil 43 } 44 45 // The rest of this method is largely copied from os.MkdirAll and should be kept 46 // as-is to ensure compatibility. 47 48 // Fast path: if we can tell whether path is a directory or file, stop with success or error. 49 dir, err := os.Stat(path) 50 if err == nil { 51 if dir.IsDir() { 52 return nil 53 } 54 return &os.PathError{Op: "mkdir", Path: path, Err: syscall.ENOTDIR} 55 } 56 57 // Slow path: make sure parent exists and then call Mkdir for path. 58 i := len(path) 59 for i > 0 && os.IsPathSeparator(path[i-1]) { // Skip trailing path separator. 60 i-- 61 } 62 63 j := i 64 for j > 0 && !os.IsPathSeparator(path[j-1]) { // Scan backward over element. 65 j-- 66 } 67 68 if j > 1 { 69 // Create parent. 70 err = mkdirall(fixRootDirectory(path[:j-1]), perm) 71 if err != nil { 72 return err 73 } 74 } 75 76 // Parent now exists; invoke Mkdir and use its result. 77 err = mkdirWithACL(path, perm) 78 if err != nil { 79 // Handle arguments like "foo/." by 80 // double-checking that directory doesn't exist. 81 dir, err1 := os.Lstat(path) 82 if err1 == nil && dir.IsDir() { 83 return nil 84 } 85 return err 86 } 87 return nil 88 } 89 90 // mkdirWithACL creates a new directory. If there is an error, it will be of 91 // type *PathError. . 92 // 93 // This is a modified and combined version of os.Mkdir and windows.Mkdir 94 // in golang to cater for creating a directory am ACL permitting full 95 // access, with inheritance, to any subfolder/file for Built-in Administrators 96 // and Local System. 97 func mkdirWithACL(name string, sa *windows.SecurityAttributes) error { 98 if sa == nil { 99 return os.Mkdir(name, 0) 100 } 101 102 namep, err := windows.UTF16PtrFromString(name) 103 if err != nil { 104 return &os.PathError{Op: "mkdir", Path: name, Err: err} 105 } 106 107 err = windows.CreateDirectory(namep, sa) 108 if err != nil { 109 return &os.PathError{Op: "mkdir", Path: name, Err: err} 110 } 111 return nil 112 } 113 114 // fixRootDirectory fixes a reference to a drive's root directory to 115 // have the required trailing slash. 116 func fixRootDirectory(p string) string { 117 if len(p) == len(`\\?\c:`) { 118 if os.IsPathSeparator(p[0]) && os.IsPathSeparator(p[1]) && p[2] == '?' && os.IsPathSeparator(p[3]) && p[5] == ':' { 119 return p + `\` 120 } 121 } 122 return p 123 } 124 125 func makeSecurityAttributes(sddl string) (*windows.SecurityAttributes, error) { 126 var sa windows.SecurityAttributes 127 sa.Length = uint32(unsafe.Sizeof(sa)) 128 sa.InheritHandle = 1 129 var err error 130 sa.SecurityDescriptor, err = windows.SecurityDescriptorFromString(sddl) 131 if err != nil { 132 return nil, err 133 } 134 return &sa, nil 135 }