fork of chmod for windows (from https://github.com/hectane/go-acl)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

168 lines
3.2 KiB

package acl
import (
"os"
"path/filepath"
"unsafe"
"git.sequentialread.com/forest/go-acl/api"
"golang.org/x/sys/windows"
)
func getEffectiveRightsForSid(oldAcl windows.Handle, sid *windows.SID) (uint32, error) {
return api.GetEffectiveRightsFromAcl(oldAcl, sid)
}
func getEffectiveRightsForSidName(oldAcl windows.Handle, sidName string) (uint32, error) {
sid, err := windows.StringToSid(sidName)
if err != nil {
return 0, err
}
return getEffectiveRightsForSid(oldAcl, sid)
}
func getAccessModeForRights(rights uint32) uint32 {
var ret uint32
if rights&PERM_READ == PERM_READ {
ret |= 04
}
if rights&PERM_WRITE == PERM_WRITE {
ret |= 02
}
if rights&PERM_EXECUTE == PERM_EXECUTE {
ret |= 01
}
return ret
}
func GetExplicitAccessMode(name string) (os.FileMode, error) {
var (
oldAcl windows.Handle
secDesc windows.Handle
owner *windows.SID
group *windows.SID
)
path, err := filepath.Abs(name)
if err != nil {
return os.FileMode(0), err
}
err = api.GetNamedSecurityInfo(
path,
api.SE_FILE_OBJECT,
api.DACL_SECURITY_INFORMATION|
api.OWNER_SECURITY_INFORMATION|
api.GROUP_SECURITY_INFORMATION,
&owner,
&group,
&oldAcl,
nil,
&secDesc,
)
if err != nil {
return os.FileMode(0), err
}
defer windows.LocalFree(secDesc)
ownerName, err := owner.String()
if err != nil {
return os.FileMode(0), err
}
groupName, err := group.String()
if err != nil {
return os.FileMode(0), err
}
entries, err := api.GetExplicitEntriesFromAcl(oldAcl)
if err != nil {
return os.FileMode(0), err
}
var mode uint32
if len(entries) > 0 {
for _, item := range entries {
if item.AccessMode == api.GRANT_ACCESS && item.Trustee.TrusteeForm == api.TRUSTEE_IS_SID {
trustee := (*windows.SID)(unsafe.Pointer(item.Trustee.Name))
name, err := trustee.String()
if err != nil {
continue
}
switch name {
case ownerName:
mode |= (getAccessModeForRights(item.AccessPermissions) << 6)
case groupName:
mode |= (getAccessModeForRights(item.AccessPermissions) << 3)
case SID_NAME_EVERYONE:
mode |= getAccessModeForRights(item.AccessPermissions)
}
}
}
}
return os.FileMode(mode), nil
}
func GetEffectiveAccessMode(name string) (os.FileMode, error) {
// get the file's current ACL
var (
oldAcl windows.Handle
secDesc windows.Handle
owner *windows.SID
group *windows.SID
)
path, err := filepath.Abs(name)
if err != nil {
return os.FileMode(0), err
}
err = api.GetNamedSecurityInfo(
path,
api.SE_FILE_OBJECT,
api.DACL_SECURITY_INFORMATION|
api.OWNER_SECURITY_INFORMATION|
api.GROUP_SECURITY_INFORMATION,
&owner,
&group,
&oldAcl,
nil,
&secDesc,
)
if err != nil {
return os.FileMode(0), err
}
defer windows.LocalFree(secDesc)
ownerRights, err := getEffectiveRightsForSid(oldAcl, owner)
if err != nil {
return os.FileMode(0), err
}
groupRights, err := getEffectiveRightsForSid(oldAcl, group)
if err != nil {
return os.FileMode(0), err
}
everyoneRights, err := getEffectiveRightsForSidName(oldAcl, SID_NAME_EVERYONE)
if err != nil {
return os.FileMode(0), err
}
mode := os.FileMode(
getAccessModeForRights(ownerRights)<<6 |
getAccessModeForRights(groupRights)<<3 |
getAccessModeForRights(everyoneRights)<<0)
return mode, nil
}