system/acl: wrap libacl errors in PathError
All checks were successful
Test / Create distribution (push) Successful in 34s
Test / Sandbox (push) Successful in 1m47s
Test / Hakurei (push) Successful in 3m20s
Test / Hpkg (push) Successful in 3m49s
Test / Sandbox (race detector) (push) Successful in 5m48s
Test / Hakurei (race detector) (push) Successful in 3m9s
Test / Flake checks (push) Successful in 1m35s

This helps determine which libacl function the errno came from.

Signed-off-by: Ophestra <cat@gensokyo.uk>
This commit is contained in:
Ophestra 2025-08-30 13:19:15 +09:00
parent 6aa431d57a
commit 0122593312
Signed by: cat
SSH Key Fingerprint: SHA256:gQ67O0enBZ7UdZypgtspB2FDM1g3GVw8nX0XSdcFw8Q
4 changed files with 125 additions and 9 deletions

View File

@ -29,8 +29,5 @@ func Update(name string, uid int, perms ...Perm) error {
(*C.acl_perm_t)(p), (*C.acl_perm_t)(p),
C.size_t(len(perms)), C.size_t(len(perms)),
) )
if r == 0 { return newAclPathError(name, int(r), err)
return nil
}
return err
} }

View File

@ -6,7 +6,7 @@
int hakurei_acl_update_file_by_uid(const char *path_p, uid_t uid, int hakurei_acl_update_file_by_uid(const char *path_p, uid_t uid,
acl_perm_t *perms, size_t plen) { acl_perm_t *perms, size_t plen) {
int ret = -1; int ret;
bool v; bool v;
int i; int i;
acl_t acl; acl_t acl;
@ -15,51 +15,70 @@ int hakurei_acl_update_file_by_uid(const char *path_p, uid_t uid,
void *qualifier_p; void *qualifier_p;
acl_permset_t permset; acl_permset_t permset;
ret = -1; /* acl_get_file */
acl = acl_get_file(path_p, ACL_TYPE_ACCESS); acl = acl_get_file(path_p, ACL_TYPE_ACCESS);
if (acl == NULL) if (acl == NULL)
goto out; goto out;
// prune entries by uid /* prune entries by uid */
for (i = acl_get_entry(acl, ACL_FIRST_ENTRY, &entry); i == 1; for (i = acl_get_entry(acl, ACL_FIRST_ENTRY, &entry); i == 1;
i = acl_get_entry(acl, ACL_NEXT_ENTRY, &entry)) { i = acl_get_entry(acl, ACL_NEXT_ENTRY, &entry)) {
ret = -2; /* acl_get_tag_type */
if (acl_get_tag_type(entry, &tag_type) != 0) if (acl_get_tag_type(entry, &tag_type) != 0)
return -1; goto out;
if (tag_type != ACL_USER) if (tag_type != ACL_USER)
continue; continue;
ret = -3; /* acl_get_qualifier */
qualifier_p = acl_get_qualifier(entry); qualifier_p = acl_get_qualifier(entry);
if (qualifier_p == NULL) if (qualifier_p == NULL)
return -1; goto out;
v = *(uid_t *)qualifier_p == uid; v = *(uid_t *)qualifier_p == uid;
acl_free(qualifier_p); acl_free(qualifier_p);
if (!v) if (!v)
continue; continue;
acl_delete_entry(acl, entry); ret = -4; /* acl_delete_entry */
if (acl_delete_entry(acl, entry) != 0)
goto out;
} }
if (plen == 0) if (plen == 0)
goto set; goto set;
ret = -5; /* acl_create_entry */
if (acl_create_entry(&acl, &entry) != 0) if (acl_create_entry(&acl, &entry) != 0)
goto out; goto out;
ret = -6; /* acl_get_permset */
if (acl_get_permset(entry, &permset) != 0) if (acl_get_permset(entry, &permset) != 0)
goto out; goto out;
ret = -7; /* acl_add_perm */
for (i = 0; i < plen; i++) { for (i = 0; i < plen; i++) {
if (acl_add_perm(permset, perms[i]) != 0) if (acl_add_perm(permset, perms[i]) != 0)
goto out; goto out;
} }
ret = -8; /* acl_set_tag_type */
if (acl_set_tag_type(entry, ACL_USER) != 0) if (acl_set_tag_type(entry, ACL_USER) != 0)
goto out; goto out;
ret = -9; /* acl_set_qualifier */
if (acl_set_qualifier(entry, (void *)&uid) != 0) if (acl_set_qualifier(entry, (void *)&uid) != 0)
goto out; goto out;
set: set:
ret = -10; /* acl_calc_mask */
if (acl_calc_mask(&acl) != 0) if (acl_calc_mask(&acl) != 0)
goto out; goto out;
ret = -11; /* acl_valid */
if (acl_valid(acl) != 0) if (acl_valid(acl) != 0)
goto out; goto out;
ret = -12; /* acl_set_file */
if (acl_set_file(path_p, ACL_TYPE_ACCESS, acl) == 0) if (acl_set_file(path_p, ACL_TYPE_ACCESS, acl) == 0)
ret = 0; ret = 0;

View File

@ -0,0 +1,40 @@
package acl
import "os"
func newAclPathError(name string, r int, err error) error {
pathError := &os.PathError{Path: name, Err: err}
switch r {
case 0:
return nil
case -1:
pathError.Op = "acl_get_file"
case -2:
pathError.Op = "acl_get_tag_type"
case -3:
pathError.Op = "acl_get_qualifier"
case -4:
pathError.Op = "acl_delete_entry"
case -5:
pathError.Op = "acl_create_entry"
case -6:
pathError.Op = "acl_get_permset"
case -7:
pathError.Op = "acl_add_perm"
case -8:
pathError.Op = "acl_set_tag_type"
case -9:
pathError.Op = "acl_set_qualifier"
case -10:
pathError.Op = "acl_calc_mask"
case -11:
pathError.Op = "acl_valid"
case -12:
pathError.Op = "acl_set_file"
default: // unreachable
pathError.Op = "setfacl"
}
return pathError
}

View File

@ -0,0 +1,60 @@
package acl
import (
"os"
"reflect"
"syscall"
"testing"
"hakurei.app/container"
)
func TestNewAclPathError(t *testing.T) {
testCases := []struct {
name string
path string
r int
err error
want error
}{
{"nil", container.Nonexistent, 0, syscall.ENOTRECOVERABLE, nil},
{"acl_get_file", container.Nonexistent, -1, syscall.ENOTRECOVERABLE,
&os.PathError{Op: "acl_get_file", Path: container.Nonexistent, Err: syscall.ENOTRECOVERABLE}},
{"acl_get_tag_type", container.Nonexistent, -2, syscall.ENOTRECOVERABLE,
&os.PathError{Op: "acl_get_tag_type", Path: container.Nonexistent, Err: syscall.ENOTRECOVERABLE}},
{"acl_get_qualifier", container.Nonexistent, -3, syscall.ENOTRECOVERABLE,
&os.PathError{Op: "acl_get_qualifier", Path: container.Nonexistent, Err: syscall.ENOTRECOVERABLE}},
{"acl_delete_entry", container.Nonexistent, -4, syscall.ENOTRECOVERABLE,
&os.PathError{Op: "acl_delete_entry", Path: container.Nonexistent, Err: syscall.ENOTRECOVERABLE}},
{"acl_create_entry", container.Nonexistent, -5, syscall.ENOTRECOVERABLE,
&os.PathError{Op: "acl_create_entry", Path: container.Nonexistent, Err: syscall.ENOTRECOVERABLE}},
{"acl_get_permset", container.Nonexistent, -6, syscall.ENOTRECOVERABLE,
&os.PathError{Op: "acl_get_permset", Path: container.Nonexistent, Err: syscall.ENOTRECOVERABLE}},
{"acl_add_perm", container.Nonexistent, -7, syscall.ENOTRECOVERABLE,
&os.PathError{Op: "acl_add_perm", Path: container.Nonexistent, Err: syscall.ENOTRECOVERABLE}},
{"acl_set_tag_type", container.Nonexistent, -8, syscall.ENOTRECOVERABLE,
&os.PathError{Op: "acl_set_tag_type", Path: container.Nonexistent, Err: syscall.ENOTRECOVERABLE}},
{"acl_set_qualifier", container.Nonexistent, -9, syscall.ENOTRECOVERABLE,
&os.PathError{Op: "acl_set_qualifier", Path: container.Nonexistent, Err: syscall.ENOTRECOVERABLE}},
{"acl_calc_mask", container.Nonexistent, -10, syscall.ENOTRECOVERABLE,
&os.PathError{Op: "acl_calc_mask", Path: container.Nonexistent, Err: syscall.ENOTRECOVERABLE}},
{"acl_valid", container.Nonexistent, -11, syscall.ENOTRECOVERABLE,
&os.PathError{Op: "acl_valid", Path: container.Nonexistent, Err: syscall.ENOTRECOVERABLE}},
{"acl_set_file", container.Nonexistent, -12, syscall.ENOTRECOVERABLE,
&os.PathError{Op: "acl_set_file", Path: container.Nonexistent, Err: syscall.ENOTRECOVERABLE}},
{"acl", container.Nonexistent, -13, syscall.ENOTRECOVERABLE,
&os.PathError{Op: "setfacl", Path: container.Nonexistent, Err: syscall.ENOTRECOVERABLE}},
{"invalid", container.Nonexistent, -0xdeadbeef, nil,
&os.PathError{Op: "setfacl", Path: container.Nonexistent}},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
err := newAclPathError(tc.path, tc.r, tc.err)
if !reflect.DeepEqual(err, tc.want) {
t.Errorf("newAclPathError: %v, want %v", err, tc.want)
}
})
}
}