diff --git a/storage/fs_windows.go b/storage/fs_windows.go index 3d34efb5a..8074fcb47 100644 --- a/storage/fs_windows.go +++ b/storage/fs_windows.go @@ -9,6 +9,13 @@ import ( "strings" "syscall" "time" + "unsafe" +) + +// Load the SetEntriesInAclW Win API function +var ( + modadvapi32 = windows.NewLazySystemDLL("advapi32.dll") + procSetEntriesInAclW = modadvapi32.NewProc("SetEntriesInAclW") ) func GetFileTime(filename string) (time.Time, time.Time, time.Time, error) { @@ -118,6 +125,11 @@ func SetFileUserGroup(filename, userId, groupId string) error { return err } + err = addCreatorOwnerAclToFile(filename) + if err != nil { + return err + } + return nil } @@ -147,3 +159,66 @@ func StringSidAsName(strSID string) (name string, err error) { } return name, nil } + +// addCreatorOwnerAclToFile is required because on Windows systems, a new file doesn +func addCreatorOwnerAclToFile(filename string) error { + // Get the DACL security descriptor from the filename + sd, err := windows.GetNamedSecurityInfo(filename, windows.SE_FILE_OBJECT, windows.DACL_SECURITY_INFORMATION) + if err != nil { + return err + } + + // Get the DACL from the security descriptor + dacl, _, err := sd.DACL() + if err != nil { + return err + } + + // Create a SID for the CREATOR_OWNER + sid, err := windows.StringToSid("S-1-3-0") + if err != nil { + return err + } + + // Create an access control entry (ACE) for the CREATOR_OWNER SID + ace := windows.EXPLICIT_ACCESS{ + AccessPermissions: windows.GENERIC_ALL, + AccessMode: windows.GRANT_ACCESS, + Trustee: windows.TRUSTEE{ + TrusteeForm: windows.TRUSTEE_IS_SID, + TrusteeType: windows.TRUSTEE_IS_USER, + TrusteeValue: windows.TrusteeValueFromSID(sid), + }, + } + + newAcl := new(windows.ACL) + newAclH := windows.Handle(unsafe.Pointer(newAcl)) + entries := []windows.EXPLICIT_ACCESS{ace} + if err := SetEntriesInAcl( + entries, + windows.Handle(unsafe.Pointer(dacl)), + &newAclH, + ); err != nil { + return err + } + + // Set the updated security descriptor of the file + err = windows.SetNamedSecurityInfo(filename, windows.SE_FILE_OBJECT, windows.DACL_SECURITY_INFORMATION|windows.UNPROTECTED_DACL_SECURITY_INFORMATION, nil, nil, newAcl, nil) + if err != nil { + return err + } + return nil +} + +func SetEntriesInAcl(entries []windows.EXPLICIT_ACCESS, oldAcl windows.Handle, newAcl *windows.Handle) error { + ret, _, _ := procSetEntriesInAclW.Call( + uintptr(len(entries)), + uintptr(unsafe.Pointer(&entries[0])), + uintptr(oldAcl), + uintptr(unsafe.Pointer(newAcl)), + ) + if ret != 0 { + return windows.Errno(ret) + } + return nil +}