/*
 * Inode operation get_posix_acl().
 *
 * inode->i_sem: don't care
 * BKL: held
 */
struct posix_acl *
ext3_get_acl(struct inode *inode, int type)
{
	const size_t max_size = ext3_acl_size(EXT3_ACL_MAX_ENTRIES);
	struct ext3_inode_info *ei = EXT3_I(inode);
	int name_index;
	char *value;
	struct posix_acl *acl;
	int retval;

	if (!IS_POSIXACL(inode))
		return 0;

	switch(type) {
		case ACL_TYPE_ACCESS:
			if (ei->i_acl != EXT3_ACL_NOT_CACHED)
				return posix_acl_dup(ei->i_acl);
			name_index = EXT3_XATTR_INDEX_POSIX_ACL_ACCESS;
			break;

		case ACL_TYPE_DEFAULT:
			if (ei->i_default_acl != EXT3_ACL_NOT_CACHED)
				return posix_acl_dup(ei->i_default_acl);
			name_index = EXT3_XATTR_INDEX_POSIX_ACL_DEFAULT;
			break;

		default:
			return ERR_PTR(-EINVAL);
	}
	value = kmalloc(max_size, GFP_KERNEL);
	if (!value)
		return ERR_PTR(-ENOMEM);

	retval = ext3_xattr_get(inode, name_index, "", value, max_size);
	acl = ERR_PTR(retval);
	if (retval > 0)
		acl = ext3_acl_from_disk(value, retval);
	else if (retval == -ENODATA || retval == -ENOSYS)
		acl = NULL;
	kfree(value);

	if (!IS_ERR(acl)) {
		switch(type) {
			case ACL_TYPE_ACCESS:
				ei->i_acl = posix_acl_dup(acl);
				break;

			case ACL_TYPE_DEFAULT:
				ei->i_default_acl = posix_acl_dup(acl);
				break;
		}
	}
	return acl;
}
Ejemplo n.º 2
0
/*
 * Convert from in-memory to filesystem representation.
 */
static void *
ext3_acl_to_disk(const struct posix_acl *acl, size_t *size)
{
	ext3_acl_header *ext_acl;
	char *e;
	size_t n;

	*size = ext3_acl_size(acl->a_count);
	ext_acl = (ext3_acl_header *)kmalloc(sizeof(ext3_acl_header) +
		acl->a_count * sizeof(ext3_acl_entry), GFP_KERNEL);
	if (!ext_acl)
		return ERR_PTR(-ENOMEM);
	ext_acl->a_version = cpu_to_le32(EXT3_ACL_VERSION);
	e = (char *)ext_acl + sizeof(ext3_acl_header);
	for (n=0; n < acl->a_count; n++) {
		ext3_acl_entry *entry = (ext3_acl_entry *)e;
		entry->e_tag  = cpu_to_le16(acl->a_entries[n].e_tag);
		entry->e_perm = cpu_to_le16(acl->a_entries[n].e_perm);
		switch(acl->a_entries[n].e_tag) {
			case ACL_USER:
			case ACL_GROUP:
				entry->e_id =
					cpu_to_le32(acl->a_entries[n].e_id);
				e += sizeof(ext3_acl_entry);
				break;

			case ACL_USER_OBJ:
			case ACL_GROUP_OBJ:
			case ACL_MASK:
			case ACL_OTHER:
				e += sizeof(ext3_acl_entry_short);
				break;

			default:
				goto fail;
		}
	}
	return (char *)ext_acl;

fail:
	kfree(ext_acl);
	return ERR_PTR(-EINVAL);
}