acl: implement removeEntry in C
All checks were successful
Test / Create distribution (push) Successful in 24s
Test / Run NixOS test (push) Successful in 3m17s

Signed-off-by: Ophestra <cat@gensokyo.uk>
This commit is contained in:
Ophestra 2025-02-17 20:37:10 +09:00
parent 7e69893264
commit 4900cd6d41
Signed by: cat
SSH Key Fingerprint: SHA256:gQ67O0enBZ7UdZypgtspB2FDM1g3GVw8nX0XSdcFw8Q
3 changed files with 59 additions and 70 deletions

47
acl/acl-update.c Normal file
View File

@ -0,0 +1,47 @@
#include "acl-update.h"
#include <stdlib.h>
#include <stdbool.h>
#include <sys/acl.h>
#include <acl/libacl.h>
acl_t f_acl_get_file(const char *path_p, acl_type_t type) {
acl_t acl = acl_get_file(path_p, type);
free((void *)path_p);
return acl;
}
int f_acl_set_file(const char *path_p, acl_type_t type, acl_t acl) {
if (acl_valid(acl) != 0) {
return -1;
}
int ret = acl_set_file(path_p, type, acl);
free((void *)path_p);
return ret;
}
void f_acl_delete_by_uid(acl_t acl, uid_t uid) {
acl_entry_t entry; // acl_get_entry does not store entry_p
acl_tag_t tag_type; // acl_get_tag_type does not store tag_type_p
void *qualifier_p;
bool res;
for (int r = acl_get_entry(acl, ACL_FIRST_ENTRY, &entry); r == 1; r = acl_get_entry(acl, ACL_NEXT_ENTRY, &entry)) {
if (acl_get_tag_type(entry, &tag_type) != 0)
return;
if (tag_type != ACL_USER)
continue;
qualifier_p = acl_get_qualifier(entry);
if (qualifier_p == NULL)
return;
res = *(uid_t *)qualifier_p == uid;
acl_free(qualifier_p);
if (!res)
continue;
acl_delete_entry(acl, entry);
break;
}
}

5
acl/acl-update.h Normal file
View File

@ -0,0 +1,5 @@
#include <sys/acl.h>
acl_t f_acl_get_file(const char *path_p, acl_type_t type);
int f_acl_set_file(const char *path_p, acl_type_t type, acl_t acl);
void f_acl_delete_by_uid(acl_t acl, uid_t uid);

View File

@ -11,30 +11,12 @@ import (
/* /*
#cgo linux pkg-config: --static libacl #cgo linux pkg-config: --static libacl
#include <stdlib.h> #include "acl-update.h"
#include <sys/acl.h>
#include <acl/libacl.h>
static acl_t _go_acl_get_file(const char *path_p, acl_type_t type) {
acl_t acl = acl_get_file(path_p, type);
free((void *)path_p);
return acl;
}
static int _go_acl_set_file(const char *path_p, acl_type_t type, acl_t acl) {
if (acl_valid(acl) != 0) {
return -1;
}
int ret = acl_set_file(path_p, type, acl);
free((void *)path_p);
return ret;
}
*/ */
import "C" import "C"
func getFile(name string, t C.acl_type_t) (*ACL, error) { func getFile(name string, t C.acl_type_t) (*ACL, error) {
a, err := C._go_acl_get_file(C.CString(name), t) a, err := C.f_acl_get_file(C.CString(name), t)
if errors.Is(err, syscall.ENODATA) { if errors.Is(err, syscall.ENODATA) {
err = nil err = nil
} }
@ -43,7 +25,7 @@ func getFile(name string, t C.acl_type_t) (*ACL, error) {
} }
func (acl *ACL) setFile(name string, t C.acl_type_t) error { func (acl *ACL) setFile(name string, t C.acl_type_t) error {
_, err := C._go_acl_set_file(C.CString(name), t, acl.acl) _, err := C.f_acl_set_file(C.CString(name), t, acl.acl)
return err return err
} }
@ -85,54 +67,9 @@ type (
Perm C.acl_perm_t Perm C.acl_perm_t
) )
func (acl *ACL) removeEntry(tt C.acl_tag_t, tq int) error { func (acl *ACL) removeEntry(uid int) error {
var e C.acl_entry_t _, err := C.f_acl_delete_by_uid(acl.acl, C.uid_t(uid))
return err
// get first entry
if r, err := C.acl_get_entry(acl.acl, 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(acl.acl, 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(acl.acl, e)
return err
}
}
} }
// Update replaces ACL_USER entry with qualifier uid. // Update replaces ACL_USER entry with qualifier uid.
@ -146,7 +83,7 @@ func Update(name string, uid int, perms ...Perm) error {
defer a.free() defer a.free()
// remove existing entry // remove existing entry
if err = a.removeEntry(User, uid); err != nil { if err = a.removeEntry(uid); err != nil {
return err return err
} }