diff options
| author | Ophestra <cat@gensokyo.uk> | 2026-10-13 18:55:52 +0900 |
|---|---|---|
| committer | Ophestra <cat@gensokyo.uk> | 2026-10-13 18:55:52 +0900 |
| commit | 0abf367b1334b76f5e8f989cf0c07b5d00b25868 (patch) | |
| tree | 9d78aae80b86770762e5d86358fd1d89c18c3f35 /internal/acl/libacl-helper.c | |
| parent | 11e395a1a7453b93c695e849bd93d8c2c0af6aef (diff) | |
internal/acl: skip superfluous acl_set_file
This slightly reduces startup latency.
Signed-off-by: Ophestra <cat@gensokyo.uk>
Diffstat (limited to 'internal/acl/libacl-helper.c')
| -rw-r--r-- | internal/acl/libacl-helper.c | 87 |
1 files changed, 65 insertions, 22 deletions
diff --git a/internal/acl/libacl-helper.c b/internal/acl/libacl-helper.c index 259dfb2b..065c1928 100644 --- a/internal/acl/libacl-helper.c +++ b/internal/acl/libacl-helper.c @@ -4,18 +4,22 @@ #include <stdlib.h> #include <sys/acl.h> -int hakurei_acl_update_file_by_uid(const char *path_p, uid_t uid, - acl_perm_t *perms, size_t plen) { - int ret; +enum hakurei_acl_status hakurei_update_acl( + const char *path_p, + uid_t uid, + acl_perm_t perms) { + enum hakurei_acl_status ret; + bool v; int i; - acl_t acl; + acl_t acl, acl_d = NULL; acl_entry_t entry; acl_tag_t tag_type; void *qualifier_p; acl_permset_t permset; + acl_perm_t has_perms; - ret = -1; /* acl_get_file */ + ret = HAKUREI_ACL_GET_FILE; acl = acl_get_file(path_p, ACL_TYPE_ACCESS); if (acl == NULL) goto out; @@ -23,13 +27,13 @@ int hakurei_acl_update_file_by_uid(const char *path_p, uid_t uid, /* prune entries by uid */ for (i = acl_get_entry(acl, ACL_FIRST_ENTRY, &entry); i == 1; i = acl_get_entry(acl, ACL_NEXT_ENTRY, &entry)) { - ret = -2; /* acl_get_tag_type */ + ret = HAKUREI_ACL_GET_TAG_TYPE; if (acl_get_tag_type(entry, &tag_type) != 0) goto out; if (tag_type != ACL_USER) continue; - ret = -3; /* acl_get_qualifier */ + ret = HAKUREI_ACL_GET_QUALIFIER; qualifier_p = acl_get_qualifier(entry); if (qualifier_p == NULL) goto out; @@ -39,52 +43,91 @@ int hakurei_acl_update_file_by_uid(const char *path_p, uid_t uid, if (!v) continue; - ret = -4; /* acl_delete_entry */ + ret = HAKUREI_ACL_GET_PERMSET; + if (acl_get_permset(entry, &permset) != 0) + goto out; + + if (perms == 0) + goto delete; + + /* this is quite ugly, but the standard makes it impossible to directly + * obtain these bits */ + has_perms = 0; +#define COPY_PERM_BIT(perm) \ + do { \ + ret = HAKUREI_ACL_GET_PERM; \ + i = acl_get_perm(permset, perm); \ + if (i < 0) \ + goto out; \ + if (i > 0) \ + has_perms |= perm; \ + } while (0) + COPY_PERM_BIT(ACL_READ); + COPY_PERM_BIT(ACL_WRITE); + COPY_PERM_BIT(ACL_EXECUTE); + + if (perms == has_perms) { + ret = HAKUREI_ACL_DUP; + acl_d = acl_dup(acl); + if (acl_d == NULL) + goto out; + + ret = HAKUREI_ACL_CALC_MASK; + if (acl_calc_mask(&acl_d) != 0) + goto out; + + ret = HAKUREI_ACL_OK; + if (acl_cmp(acl, acl_d) == 0) + goto out; + } + + delete: + ret = HAKUREI_ACL_DELETE_ENTRY; if (acl_delete_entry(acl, entry) != 0) goto out; } - if (plen == 0) + if (perms == 0) goto set; - ret = -5; /* acl_create_entry */ + ret = HAKUREI_ACL_CREATE_ENTRY; if (acl_create_entry(&acl, &entry) != 0) goto out; - ret = -6; /* acl_get_permset */ + ret = HAKUREI_ACL_GET_PERMSET; if (acl_get_permset(entry, &permset) != 0) goto out; - ret = -7; /* acl_add_perm */ - for (i = 0; i < plen; i++) { - if (acl_add_perm(permset, perms[i]) != 0) - goto out; - } + ret = HAKUREI_ACL_ADD_PERM; + if (acl_add_perm(permset, perms) != 0) + goto out; - ret = -8; /* acl_set_tag_type */ + ret = HAKUREI_ACL_SET_TAG_TYPE; if (acl_set_tag_type(entry, ACL_USER) != 0) goto out; - ret = -9; /* acl_set_qualifier */ + ret = HAKUREI_ACL_SET_QUALIFIER; if (acl_set_qualifier(entry, (void *)&uid) != 0) goto out; set: - ret = -10; /* acl_calc_mask */ + ret = HAKUREI_ACL_CALC_MASK; if (acl_calc_mask(&acl) != 0) goto out; - ret = -11; /* acl_valid */ + ret = HAKUREI_ACL_VALID; if (acl_valid(acl) != 0) goto out; - ret = -12; /* acl_set_file */ + ret = HAKUREI_ACL_SET_FILE; if (acl_set_file(path_p, ACL_TYPE_ACCESS, acl) == 0) - ret = 0; + ret = HAKUREI_ACL_OK; out: free((void *)path_p); if (acl != NULL) acl_free((void *)acl); + if (acl_d != NULL) + acl_free((void *)acl_d); return ret; } |
