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  }