struct posix_acl * xfs_get_acl(struct inode *inode, int type) { struct xfs_inode *ip = XFS_I(inode); struct posix_acl *acl; struct xfs_acl *xfs_acl; int len = sizeof(struct xfs_acl); unsigned char *ea_name; int error; acl = get_cached_acl(inode, type); if (acl != ACL_NOT_CACHED) return acl; switch (type) { case ACL_TYPE_ACCESS: ea_name = SGI_ACL_FILE; break; case ACL_TYPE_DEFAULT: ea_name = SGI_ACL_DEFAULT; break; default: BUG(); } /* * If we have a cached ACLs value just return it, not need to * go out to the disk. */ xfs_acl = kzalloc(sizeof(struct xfs_acl), GFP_KERNEL); if (!xfs_acl) return ERR_PTR(-ENOMEM); error = -xfs_attr_get(ip, ea_name, (unsigned char *)xfs_acl, &len, ATTR_ROOT); if (error) { /* * If the attribute doesn't exist make sure we have a negative * cache entry, for any other error assume it is transient and * leave the cache entry as ACL_NOT_CACHED. */ if (error == -ENOATTR) { acl = NULL; goto out_update_cache; } goto out; } acl = xfs_acl_from_disk(xfs_acl); if (IS_ERR(acl)) goto out; out_update_cache: set_cached_acl(inode, type, acl); out: kfree(xfs_acl); return acl; }
/* * Validate an ACL */ static int xfs_acl_valid( struct xfs_mount *mp, struct xfs_acl *daclp) { struct xfs_icacl *aclp = NULL; struct xfs_icacl_entry *entry, *e; int user = 0, group = 0, other = 0, mask = 0, mask_required = 0; int i, j; if (daclp == NULL) goto acl_invalid; switch (xfs_acl_from_disk(mp, &aclp, daclp)) { case ENOMEM: return 0; case EINVAL: goto acl_invalid; default: break; } for (i = 0; i < aclp->acl_cnt; i++) { entry = &aclp->acl_entry[i]; if (entry->ae_perm & ~(ACL_READ|ACL_WRITE|ACL_EXECUTE)) goto acl_invalid; switch (entry->ae_tag) { case ACL_USER_OBJ: if (user++) goto acl_invalid; break; case ACL_GROUP_OBJ: if (group++) goto acl_invalid; break; case ACL_OTHER: if (other++) goto acl_invalid; break; case ACL_USER: case ACL_GROUP: for (j = i + 1; j < aclp->acl_cnt; j++) { e = &aclp->acl_entry[j]; if (e->ae_id == entry->ae_id && e->ae_tag == entry->ae_tag) goto acl_invalid; } mask_required++; break; case ACL_MASK: if (mask++) goto acl_invalid; break; default: goto acl_invalid; } } if (!user || !group || !other || (mask_required && !mask)) goto acl_invalid; free(aclp); return 0; acl_invalid: free(aclp); errno = EINVAL; return (-1); }