aboutsummaryrefslogtreecommitdiffhomepage
path: root/acl/c.go
diff options
context:
space:
mode:
authorOphestra Umiker <cat@ophivana.moe>2024-09-16 20:32:07 +0900
committerOphestra Umiker <cat@ophivana.moe>2024-09-16 20:32:07 +0900
commit03c24c51224e85eb96527a512f5f0483464fc810 (patch)
tree2feede4d9448fc881b0d4b8a193c0c82f6627221 /acl/c.go
parent8bdae74ebe172239573bab9fca634cf350cbd29d (diff)
move acl and xcb binding packages to top level
These packages are reasonably clean and do not interact with other packages. Signed-off-by: Ophestra Umiker <cat@ophivana.moe>
Diffstat (limited to 'acl/c.go')
-rw-r--r--acl/c.go99
1 files changed, 99 insertions, 0 deletions
diff --git a/acl/c.go b/acl/c.go
new file mode 100644
index 00000000..89bc0469
--- /dev/null
+++ b/acl/c.go
@@ -0,0 +1,99 @@
+package acl
+
+import (
+ "errors"
+ "fmt"
+ "syscall"
+ "unsafe"
+)
+
+//#include <stdlib.h>
+//#include <sys/acl.h>
+//#include <acl/libacl.h>
+//#cgo linux LDFLAGS: -lacl
+import "C"
+
+type acl struct {
+ val C.acl_t
+ freed bool
+}
+
+func aclGetFile(path string, t C.acl_type_t) (*acl, error) {
+ p := C.CString(path)
+ a, err := C.acl_get_file(p, t)
+ C.free(unsafe.Pointer(p))
+
+ if errors.Is(err, syscall.ENODATA) {
+ err = nil
+ }
+ return &acl{val: a, freed: false}, err
+}
+
+func (a *acl) setFile(path string, t C.acl_type_t) error {
+ if C.acl_valid(a.val) != 0 {
+ return fmt.Errorf("invalid acl")
+ }
+
+ p := C.CString(path)
+ _, err := C.acl_set_file(p, t, a.val)
+ C.free(unsafe.Pointer(p))
+ return err
+}
+
+func (a *acl) removeEntry(tt C.acl_tag_t, tq int) error {
+ var e C.acl_entry_t
+
+ // get first entry
+ if r, err := C.acl_get_entry(a.val, C.ACL_FIRST_ENTRY, &e); err != nil {
+ return err
+ } else if r == 0 {
+ // return on acl with no entries
+ return nil
+ }
+
+ for {
+ if r, err := C.acl_get_entry(a.val, C.ACL_NEXT_ENTRY, &e); err != nil {
+ return err
+ } else if r == 0 {
+ // return on drained acl
+ return nil
+ }
+
+ var (
+ q int
+ t C.acl_tag_t
+ )
+
+ // get current entry tag type
+ if _, err := C.acl_get_tag_type(e, &t); err != nil {
+ return err
+ }
+
+ // get current entry qualifier
+ if rq, err := C.acl_get_qualifier(e); err != nil {
+ // neither ACL_USER nor ACL_GROUP
+ if errors.Is(err, syscall.EINVAL) {
+ continue
+ }
+
+ return err
+ } else {
+ q = *(*int)(rq)
+ C.acl_free(rq)
+ }
+
+ // delete on match
+ if t == tt && q == tq {
+ _, err := C.acl_delete_entry(a.val, e)
+ return err
+ }
+ }
+}
+
+func (a *acl) free() {
+ if a.freed {
+ panic("acl already freed")
+ }
+ C.acl_free(unsafe.Pointer(a.val))
+ a.freed = true
+}