/*
 * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
 * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
 *
 * This copyrighted material is made available to anyone wishing to use,
 * modify, copy, or redistribute it subject to the terms and conditions
 * of the GNU General Public License version 2.
 */

#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/completion.h>
#include <linux/buffer_head.h>
#include <linux/posix_acl.h>
#include <linux/posix_acl_xattr.h>
#include <linux/gfs2_ondisk.h>
#include <linux/lm_interface.h>

#include "gfs2.h"
#include "incore.h"
#include "acl.h"
#include "eaops.h"
#include "eattr.h"
#include "glock.h"
#include "inode.h"
#include "meta_io.h"
#include "trans.h"
#include "util.h"

#define ACL_ACCESS 1
#define ACL_DEFAULT 0

int gfs2_acl_validate_set(struct gfs2_inode *ip, int access,
		      struct gfs2_ea_request *er,
		      int *remove, mode_t *mode)
{
	struct posix_acl *acl;
	int error;

	error = gfs2_acl_validate_remove(ip, access);
	if (error)
		return error;

	if (!er->er_data)
		return -EINVAL;

	acl = posix_acl_from_xattr(er->er_data, er->er_data_len);
	if (IS_ERR(acl))
		return PTR_ERR(acl);
	if (!acl) {
		*remove = 1;
		return 0;
	}

	error = posix_acl_valid(acl);
	if (error)
		goto out;

	if (access) {
		error = posix_acl_equiv_mode(acl, mode);
		if (!error)
			*remove = 1;
		else if (error > 0)
			error = 0;
	}

out:
	posix_acl_release(acl);
	return error;
}

int gfs2_acl_validate_remove(struct gfs2_inode *ip, int access)
{
	if (!GFS2_SB(&ip->i_inode)->sd_args.ar_posix_acl)
		return -EOPNOTSUPP;
	if (!is_owner_or_cap(&ip->i_inode))
		return -EPERM;
	if (S_ISLNK(ip->i_inode.i_mode))
		return -EOPNOTSUPP;
	if (!access && !S_ISDIR(ip->i_inode.i_mode))
		return -EACCES;

	return 0;
}

static int acl_get(struct gfs2_inode *ip, int access, struct posix_acl **acl,
		   struct gfs2_ea_location *el, char **data, unsigned int *len)
{
	struct gfs2_ea_request er;
	struct gfs2_ea_location el_this;
	int error;

	if (!ip->i_di.di_eattr)
		return 0;

	memset(&er, 0, sizeof(struct gfs2_ea_request));
	if (access) {
		er.er_name = GFS2_POSIX_ACL_ACCESS;
		er.er_name_len = GFS2_POSIX_ACL_ACCESS_LEN;
	} else {
		er.er_name = GFS2_POSIX_ACL_DEFAULT;
		er.er_name_len = GFS2_POSIX_ACL_DEFAULT_LEN;
	}
	er.er_type = GFS2_EATYPE_SYS;

	if (!el)
		el = &el_this;

	error = gfs2_ea_find(ip, &er, el);
	if (error)
		return error;
	if (!el->el_ea)
		return 0;
	if (!GFS2_EA_DATA_LEN(el->el_ea))
		goto out;

	er.er_data_len = GFS2_EA_DATA_LEN(el->el_ea);
	er.er_data = kmalloc(er.er_data_len, GFP_KERNEL);
	error = -ENOMEM;
	if (!er.er_data)
		goto out;

	error = gfs2_ea_get_copy(ip, el, er.er_data);
	if (error)
		goto out_kfree;

	if (acl) {
		*acl = posix_acl_from_xattr(er.er_data, er.er_data_len);
		if (IS_ERR(*acl))
			error = PTR_ERR(*acl);
	}

out_kfree:
	if (error || !data)
		kfree(er.er_data);
	else {
		*data = er.er_data;
		*len = er.er_data_len;
	}
out:
	if (error || el == &el_this)
		brelse(el->el_bh);
	return error;
}

/**
 * gfs2_check_acl - Check an ACL to see if we're allowed to do something
 * @inode: the file we want to do something to
 * @mask: what we want to do
 *
 * Returns: errno
 */

int gfs2_check_acl(struct inode *inode, int mask)
{
	struct posix_acl *acl = NULL;
	int error;

	error = acl_get(GFS2_I(inode), ACL_ACCESS, &acl, NULL, NULL, NULL);
	if (error)
		return error;

	if (acl) {
		error = posix_acl_permission(inode, acl, mask);
		posix_acl_release(acl);
		return error;
	}

	return -EAGAIN;
}

static int munge_mode(struct gfs2_inode *ip, mode_t mode)
{
	struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
	struct buffer_head *dibh;
	int error;

	error = gfs2_trans_begin(sdp, RES_DINODE, 0);
	if (error)
		return error;

	error = gfs2_meta_inode_buffer(ip, &dibh);
	if (!error) {
		gfs2_assert_withdraw(sdp,
				(ip->i_inode.i_mode & S_IFMT) == (mode & S_IFMT));
		ip->i_inode.i_mode = mode;
		gfs2_trans_add_bh(ip->i_gl, dibh, 1);
		gfs2_dinode_out(ip, dibh->b_data);
		brelse(dibh);
	}

	gfs2_trans_end(sdp);

	return 0;
}

int gfs2_acl_create(struct gfs2_inode *dip, struct gfs2_inode *ip)
{
	struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode);
	struct posix_acl *acl = NULL, *clone;
	struct gfs2_ea_request er;
	mode_t mode = ip->i_inode.i_mode;
	int error;

	if (!sdp->sd_args.ar_posix_acl)
		return 0;
	if (S_ISLNK(ip->i_inode.i_mode))
		return 0;

	memset(&er, 0, sizeof(struct gfs2_ea_request));
	er.er_type = GFS2_EATYPE_SYS;

	error = acl_get(dip, ACL_DEFAULT, &acl, NULL,
			&er.er_data, &er.er_data_len);
	if (error)
		return error;
	if (!acl) {
		mode &= ~current->fs->umask;
		if (mode != ip->i_inode.i_mode)
			error = munge_mode(ip, mode);
		return error;
	}

	clone = posix_acl_clone(acl, GFP_KERNEL);
	error = -ENOMEM;
	if (!clone)
		goto out;
	posix_acl_release(acl);
	acl = clone;

	if (S_ISDIR(ip->i_inode.i_mode)) {
		er.er_name = GFS2_POSIX_ACL_DEFAULT;
		er.er_name_len = GFS2_POSIX_ACL_DEFAULT_LEN;
		error = gfs2_system_eaops.eo_set(ip, &er);
		if (error)
			goto out;
	}

	error = posix_acl_create_masq(acl, &mode);
	if (error < 0)
		goto out;
	if (error > 0) {
		er.er_name = GFS2_POSIX_ACL_ACCESS;
		er.er_name_len = GFS2_POSIX_ACL_ACCESS_LEN;
		posix_acl_to_xattr(acl, er.er_data, er.er_data_len);
		er.er_mode = mode;
		er.er_flags = GFS2_ERF_MODE;
		error = gfs2_system_eaops.eo_set(ip, &er);
		if (error)
			goto out;
	} else
		munge_mode(ip, mode);

out:
	posix_acl_release(acl);
	kfree(er.er_data);
	return error;
}

int gfs2_acl_chmod(struct gfs2_inode *ip, struct iattr *attr)
{
	struct posix_acl *acl = NULL, *clone;
	struct gfs2_ea_location el;
	char *data;
	unsigned int len;
	int error;

	error = acl_get(ip, ACL_ACCESS, &acl, &el, &data, &len);
	if (error)
		return error;
	if (!acl)
		return gfs2_setattr_simple(ip, attr);

	clone = posix_acl_clone(acl, GFP_KERNEL);
	error = -ENOMEM;
	if (!clone)
		goto out;
	posix_acl_release(acl);
	acl = clone;

	error = posix_acl_chmod_masq(acl, attr->ia_mode);
	if (!error) {
		posix_acl_to_xattr(acl, data, len);
		error = gfs2_ea_acl_chmod(ip, &el, attr, data);
	}

out:
	posix_acl_release(acl);
	brelse(el.el_bh);
	kfree(data);
	return error;
}

