diff options
Diffstat (limited to 'lib/libc/posix1e/acl_delete_entry.c')
-rw-r--r-- | lib/libc/posix1e/acl_delete_entry.c | 100 |
1 files changed, 89 insertions, 11 deletions
diff --git a/lib/libc/posix1e/acl_delete_entry.c b/lib/libc/posix1e/acl_delete_entry.c index 3195fac..7dd60b8 100644 --- a/lib/libc/posix1e/acl_delete_entry.c +++ b/lib/libc/posix1e/acl_delete_entry.c @@ -33,6 +33,39 @@ __FBSDID("$FreeBSD$"); #include "un-namespace.h" #include <errno.h> #include <string.h> +#include <stdio.h> + +#include "acl_support.h" + +static int +_entry_matches(const acl_entry_t a, const acl_entry_t b) +{ + /* + * There is a semantical difference here between NFSv4 and POSIX + * draft ACLs. In POSIX, there may be only one entry for the particular + * user or group. In NFSv4 ACL, there may be any number of them. We're + * trying to be more specific here in that case. + */ + switch (_entry_brand(a)) { + case ACL_BRAND_NFS4: + if (a->ae_tag != b->ae_tag || a->ae_entry_type != b->ae_entry_type) + return (0); + + /* If ae_ids matter, compare them as well. */ + if (a->ae_tag == ACL_USER || a->ae_tag == ACL_GROUP) { + if (a->ae_id != b->ae_id) + return (0); + } + + return (1); + + default: + if ((a->ae_tag == b->ae_tag) && (a->ae_id == b->ae_id)) + return (1); + } + + return (0); +} /* * acl_delete_entry() (23.4.9): remove the ACL entry indicated by entry_d @@ -42,7 +75,7 @@ int acl_delete_entry(acl_t acl, acl_entry_t entry_d) { struct acl *acl_int; - int i; + int i, j, found = 0; if (acl == NULL || entry_d == NULL) { errno = EINVAL; @@ -51,29 +84,74 @@ acl_delete_entry(acl_t acl, acl_entry_t entry_d) acl_int = &acl->ats_acl; + if (_entry_brand(entry_d) != _acl_brand(acl)) { + errno = EINVAL; + return (-1); + } + if ((acl->ats_acl.acl_cnt < 1) || (acl->ats_acl.acl_cnt > ACL_MAX_ENTRIES)) { errno = EINVAL; return (-1); } - for (i = 0; i < acl->ats_acl.acl_cnt; i++) { - /* if this is our entry... */ - if ((acl->ats_acl.acl_entry[i].ae_tag == entry_d->ae_tag) && - (acl->ats_acl.acl_entry[i].ae_id == entry_d->ae_id)) { + for (i = 0; i < acl->ats_acl.acl_cnt;) { + if (_entry_matches(&(acl->ats_acl.acl_entry[i]), entry_d)) { /* ...shift the remaining entries... */ - for (; i < acl->ats_acl.acl_cnt - 1; ++i) - acl->ats_acl.acl_entry[i] = - acl->ats_acl.acl_entry[i+1]; + for (j = i; j < acl->ats_acl.acl_cnt - 1; ++j) + acl->ats_acl.acl_entry[j] = + acl->ats_acl.acl_entry[j+1]; /* ...drop the count and zero the unused entry... */ acl->ats_acl.acl_cnt--; - bzero(&acl->ats_acl.acl_entry[i], + bzero(&acl->ats_acl.acl_entry[j], sizeof(struct acl_entry)); acl->ats_cur_entry = 0; - return (0); - } + + /* Continue with the loop to remove all maching entries. */ + found = 1; + } else + i++; } + if (found) + return (0); errno = EINVAL; return (-1); } + +int +acl_delete_entry_np(acl_t acl, int offset) +{ + struct acl *acl_int; + int i; + + if (acl == NULL) { + errno = EINVAL; + return (-1); + } + + acl_int = &acl->ats_acl; + + if (offset < 0 || offset >= acl_int->acl_cnt) { + errno = EINVAL; + return (-1); + } + + if ((acl->ats_acl.acl_cnt < 1) || + (acl->ats_acl.acl_cnt > ACL_MAX_ENTRIES)) { + errno = EINVAL; + return (-1); + } + + /* ...shift the remaining entries... */ + for (i = offset; i < acl->ats_acl.acl_cnt - 1; ++i) + acl->ats_acl.acl_entry[i] = + acl->ats_acl.acl_entry[i+1]; + /* ...drop the count and zero the unused entry... */ + acl->ats_acl.acl_cnt--; + bzero(&acl->ats_acl.acl_entry[i], + sizeof(struct acl_entry)); + acl->ats_cur_entry = 0; + + return (0); +} |