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