/* Copyright (c) 2011-2012 Red Hat, Inc. This file is part of GlusterFS. This file is licensed to you under your choice of the GNU Lesser General Public License, version 3 or any later version (LGPLv3 or later), or the GNU General Public License, version 2 (GPLv2), in all cases as published by the Free Software Foundation. */ #include #include #include "posix-acl.h" #include "posix-acl-xattr.h" int posix_ace_cmp (const void *val1, const void *val2) { const struct posix_ace *ace1 = NULL; const struct posix_ace *ace2 = NULL; int ret = 0; ace1 = val1; ace2 = val2; ret = (ace1->tag - ace2->tag); if (!ret) ret = (ace1->id - ace2->id); return ret; } void posix_acl_normalize (xlator_t *this, struct posix_acl *acl) { qsort (acl->entries, acl->count, sizeof (struct posix_ace *), posix_ace_cmp); } struct posix_acl * posix_acl_from_xattr (xlator_t *this, const char *xattr_buf, int xattr_size) { struct posix_acl_xattr_header *header = NULL; struct posix_acl_xattr_entry *entry = NULL; struct posix_acl *acl = NULL; struct posix_ace *ace = NULL; int size = 0; int count = 0; int i = 0; size = xattr_size; if (size < sizeof (*header)) return NULL; size -= sizeof (*header); if (size % sizeof (*entry)) return NULL; count = size / sizeof (*entry); header = (struct posix_acl_xattr_header *) (xattr_buf); entry = (struct posix_acl_xattr_entry *) (header + 1); if (header->version != htole32 (POSIX_ACL_VERSION)) return NULL; acl = posix_acl_new (this, count); if (!acl) return NULL; ace = acl->entries; for (i = 0; i < count; i++) { ace->tag = letoh16 (entry->tag); ace->perm = letoh16 (entry->perm); switch (ace->tag) { case POSIX_ACL_USER_OBJ: case POSIX_ACL_MASK: case POSIX_ACL_OTHER: ace->id = POSIX_ACL_UNDEFINED_ID; break; case POSIX_ACL_GROUP: case POSIX_ACL_USER: case POSIX_ACL_GROUP_OBJ: ace->id = letoh32 (entry->id); break; default: goto err; } ace++; entry++; } posix_acl_normalize (this, acl); return acl; err: posix_acl_destroy (this, acl); return NULL; } int posix_acl_to_xattr (xlator_t *this, struct posix_acl *acl, char *xattr_buf, int xattr_size) { int size = 0; struct posix_acl_xattr_header *header = NULL; struct posix_acl_xattr_entry *entry = NULL; struct posix_ace *ace = NULL; int i = 0; size = sizeof (*header) + (acl->count * sizeof (*entry)); if (xattr_size < size) return size; header = (struct posix_acl_xattr_header *) (xattr_buf); entry = (struct posix_acl_xattr_entry *) (header + 1); ace = acl->entries; header->version = htole32 (POSIX_ACL_VERSION); for (i = 0; i < acl->count; i++) { entry->tag = htole16 (ace->tag); entry->perm = htole16 (ace->perm); switch (ace->tag) { case POSIX_ACL_USER: case POSIX_ACL_GROUP: entry->id = htole32 (ace->id); break; default: entry->id = POSIX_ACL_UNDEFINED_ID; break; } ace++; entry++; } return 0; } int posix_acl_matches_xattr (xlator_t *this, struct posix_acl *acl, const char *buf, int size) { struct posix_acl *acl2 = NULL; int ret = 1; acl2 = posix_acl_from_xattr (this, buf, size); if (!acl2) return 0; if (acl->count != acl2->count) { ret = 0; goto out; } if (memcmp (acl->entries, acl2->entries, (acl->count * sizeof (struct posix_ace)))) ret = 0; out: posix_acl_destroy (this, acl2); return ret; }