acl.c 6.6 KB
Newer Older
J
Josef Bacik 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
/*
 * Copyright (C) 2007 Red Hat.  All rights reserved.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public
 * License v2 as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this program; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 021110-1307, USA.
 */

#include <linux/fs.h>
#include <linux/string.h>
#include <linux/xattr.h>
#include <linux/posix_acl_xattr.h>
J
Josef Bacik 已提交
23
#include <linux/posix_acl.h>
24
#include <linux/sched.h>
25
#include <linux/slab.h>
J
Josef Bacik 已提交
26

J
Josef Bacik 已提交
27
#include "ctree.h"
J
Josef Bacik 已提交
28
#include "btrfs_inode.h"
J
Josef Bacik 已提交
29
#include "xattr.h"
J
Josef Bacik 已提交
30

C
Chris Mason 已提交
31
#ifdef CONFIG_BTRFS_FS_POSIX_ACL
32

J
Josef Bacik 已提交
33 34
static struct posix_acl *btrfs_get_acl(struct inode *inode, int type)
{
35 36
	int size;
	const char *name;
J
Josef Bacik 已提交
37
	char *value = NULL;
38 39 40 41 42
	struct posix_acl *acl;

	acl = get_cached_acl(inode, type);
	if (acl != ACL_NOT_CACHED)
		return acl;
J
Josef Bacik 已提交
43 44 45

	switch (type) {
	case ACL_TYPE_ACCESS:
46
		name = POSIX_ACL_XATTR_ACCESS;
J
Josef Bacik 已提交
47 48
		break;
	case ACL_TYPE_DEFAULT:
49
		name = POSIX_ACL_XATTR_DEFAULT;
J
Josef Bacik 已提交
50 51
		break;
	default:
52
		BUG();
J
Josef Bacik 已提交
53 54
	}

55
	size = __btrfs_getxattr(inode, name, "", 0);
J
Josef Bacik 已提交
56 57 58 59
	if (size > 0) {
		value = kzalloc(size, GFP_NOFS);
		if (!value)
			return ERR_PTR(-ENOMEM);
60
		size = __btrfs_getxattr(inode, name, value, size);
J
Josef Bacik 已提交
61 62
		if (size > 0) {
			acl = posix_acl_from_xattr(value, size);
63 64
			if (IS_ERR(acl))
				return acl;
65
			set_cached_acl(inode, type, acl);
J
Josef Bacik 已提交
66 67
		}
		kfree(value);
C
Chris Mason 已提交
68 69
	} else if (size == -ENOENT || size == -ENODATA || size == 0) {
		/* FIXME, who returns -ENOENT?  I think nobody */
J
Josef Bacik 已提交
70
		acl = NULL;
71
		set_cached_acl(inode, type, acl);
C
Chris Mason 已提交
72 73
	} else {
		acl = ERR_PTR(-EIO);
J
Josef Bacik 已提交
74 75 76 77 78
	}

	return acl;
}

79 80
static int btrfs_xattr_acl_get(struct dentry *dentry, const char *name,
		void *value, size_t size, int type)
J
Josef Bacik 已提交
81 82 83 84
{
	struct posix_acl *acl;
	int ret = 0;

85
	acl = btrfs_get_acl(dentry->d_inode, type);
J
Josef Bacik 已提交
86 87 88 89 90 91 92 93 94 95 96 97 98 99

	if (IS_ERR(acl))
		return PTR_ERR(acl);
	if (acl == NULL)
		return -ENODATA;
	ret = posix_acl_to_xattr(acl, value, size);
	posix_acl_release(acl);

	return ret;
}

/*
 * Needs to be called with fs_mutex held
 */
100 101
static int btrfs_set_acl(struct btrfs_trans_handle *trans,
			 struct inode *inode, struct posix_acl *acl, int type)
J
Josef Bacik 已提交
102
{
103 104
	int ret, size = 0;
	const char *name;
J
Josef Bacik 已提交
105 106 107 108 109 110 111 112 113 114 115 116 117
	char *value = NULL;
	mode_t mode;

	if (acl) {
		ret = posix_acl_valid(acl);
		if (ret < 0)
			return ret;
		ret = 0;
	}

	switch (type) {
	case ACL_TYPE_ACCESS:
		mode = inode->i_mode;
118
		name = POSIX_ACL_XATTR_ACCESS;
119 120 121 122 123 124 125
		if (acl) {
			ret = posix_acl_equiv_mode(acl, &mode);
			if (ret < 0)
				return ret;
			inode->i_mode = mode;
		}
		ret = 0;
J
Josef Bacik 已提交
126 127 128 129
		break;
	case ACL_TYPE_DEFAULT:
		if (!S_ISDIR(inode->i_mode))
			return acl ? -EINVAL : 0;
130
		name = POSIX_ACL_XATTR_DEFAULT;
J
Josef Bacik 已提交
131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148
		break;
	default:
		return -EINVAL;
	}

	if (acl) {
		size = posix_acl_xattr_size(acl->a_count);
		value = kmalloc(size, GFP_NOFS);
		if (!value) {
			ret = -ENOMEM;
			goto out;
		}

		ret = posix_acl_to_xattr(acl, value, size);
		if (ret < 0)
			goto out;
	}

149
	ret = __btrfs_setxattr(trans, inode, name, value, size, 0);
J
Josef Bacik 已提交
150
out:
C
Chris Mason 已提交
151
	kfree(value);
J
Josef Bacik 已提交
152 153

	if (!ret)
154
		set_cached_acl(inode, type, acl);
J
Josef Bacik 已提交
155 156 157

	return ret;
}
Y
Yan 已提交
158

159 160
static int btrfs_xattr_acl_set(struct dentry *dentry, const char *name,
		const void *value, size_t size, int flags, int type)
Y
Yan 已提交
161
{
162
	int ret;
J
Josef Bacik 已提交
163
	struct posix_acl *acl = NULL;
J
Josef Bacik 已提交
164

165 166 167
	if (!is_owner_or_cap(dentry->d_inode))
		return -EPERM;

168 169 170
	if (!IS_POSIXACL(dentry->d_inode))
		return -EOPNOTSUPP;

Y
Yan 已提交
171 172 173 174 175 176
	if (value) {
		acl = posix_acl_from_xattr(value, size);
		if (acl == NULL) {
			value = NULL;
			size = 0;
		} else if (IS_ERR(acl)) {
J
Josef Bacik 已提交
177
			return PTR_ERR(acl);
Y
Yan 已提交
178 179
		}
	}
180

181
	ret = btrfs_set_acl(NULL, dentry->d_inode, acl, type);
J
Josef Bacik 已提交
182 183 184 185

	posix_acl_release(acl);

	return ret;
Y
Yan 已提交
186
}
J
Josef Bacik 已提交
187

188
int btrfs_check_acl(struct inode *inode, int mask, unsigned int flags)
J
Josef Bacik 已提交
189 190 191 192
{
	struct posix_acl *acl;
	int error = -EAGAIN;

193 194
	if (flags & IPERM_FLAG_RCU)
		return -ECHILD;
J
Josef Bacik 已提交
195

196
	acl = btrfs_get_acl(inode, ACL_TYPE_ACCESS);
J
Josef Bacik 已提交
197 198 199 200 201 202 203 204 205 206 207 208 209 210 211
	if (IS_ERR(acl))
		return PTR_ERR(acl);
	if (acl) {
		error = posix_acl_permission(inode, acl, mask);
		posix_acl_release(acl);
	}

	return error;
}

/*
 * btrfs_init_acl is already generally called under fs_mutex, so the locking
 * stuff has been fixed to work with that.  If the locking stuff changes, we
 * need to re-evaluate the acl locking stuff.
 */
212 213
int btrfs_init_acl(struct btrfs_trans_handle *trans,
		   struct inode *inode, struct inode *dir)
J
Josef Bacik 已提交
214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229
{
	struct posix_acl *acl = NULL;
	int ret = 0;

	/* this happens with subvols */
	if (!dir)
		return 0;

	if (!S_ISLNK(inode->i_mode)) {
		if (IS_POSIXACL(dir)) {
			acl = btrfs_get_acl(dir, ACL_TYPE_DEFAULT);
			if (IS_ERR(acl))
				return PTR_ERR(acl);
		}

		if (!acl)
A
Al Viro 已提交
230
			inode->i_mode &= ~current_umask();
J
Josef Bacik 已提交
231 232 233 234 235 236 237
	}

	if (IS_POSIXACL(dir) && acl) {
		struct posix_acl *clone;
		mode_t mode;

		if (S_ISDIR(inode->i_mode)) {
238 239
			ret = btrfs_set_acl(trans, inode, acl,
					    ACL_TYPE_DEFAULT);
J
Josef Bacik 已提交
240 241 242 243 244 245 246 247 248 249 250 251 252 253
			if (ret)
				goto failed;
		}
		clone = posix_acl_clone(acl, GFP_NOFS);
		ret = -ENOMEM;
		if (!clone)
			goto failed;

		mode = inode->i_mode;
		ret = posix_acl_create_masq(clone, &mode);
		if (ret >= 0) {
			inode->i_mode = mode;
			if (ret > 0) {
				/* we need an acl */
254
				ret = btrfs_set_acl(trans, inode, clone,
J
Josef Bacik 已提交
255 256 257
						    ACL_TYPE_ACCESS);
			}
		}
258
		posix_acl_release(clone);
J
Josef Bacik 已提交
259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287
	}
failed:
	posix_acl_release(acl);

	return ret;
}

int btrfs_acl_chmod(struct inode *inode)
{
	struct posix_acl *acl, *clone;
	int ret = 0;

	if (S_ISLNK(inode->i_mode))
		return -EOPNOTSUPP;

	if (!IS_POSIXACL(inode))
		return 0;

	acl = btrfs_get_acl(inode, ACL_TYPE_ACCESS);
	if (IS_ERR(acl) || !acl)
		return PTR_ERR(acl);

	clone = posix_acl_clone(acl, GFP_KERNEL);
	posix_acl_release(acl);
	if (!clone)
		return -ENOMEM;

	ret = posix_acl_chmod_masq(clone, inode->i_mode);
	if (!ret)
288
		ret = btrfs_set_acl(NULL, inode, clone, ACL_TYPE_ACCESS);
J
Josef Bacik 已提交
289 290 291 292

	posix_acl_release(clone);

	return ret;
J
Josef Bacik 已提交
293
}
J
Josef Bacik 已提交
294

295
const struct xattr_handler btrfs_xattr_acl_default_handler = {
J
Josef Bacik 已提交
296
	.prefix = POSIX_ACL_XATTR_DEFAULT,
297 298 299
	.flags	= ACL_TYPE_DEFAULT,
	.get	= btrfs_xattr_acl_get,
	.set	= btrfs_xattr_acl_set,
J
Josef Bacik 已提交
300 301
};

302
const struct xattr_handler btrfs_xattr_acl_access_handler = {
J
Josef Bacik 已提交
303
	.prefix = POSIX_ACL_XATTR_ACCESS,
304 305 306
	.flags	= ACL_TYPE_ACCESS,
	.get	= btrfs_xattr_acl_get,
	.set	= btrfs_xattr_acl_set,
J
Josef Bacik 已提交
307
};
308

C
Chris Mason 已提交
309
#else /* CONFIG_BTRFS_FS_POSIX_ACL */
310 311 312 313 314 315

int btrfs_acl_chmod(struct inode *inode)
{
	return 0;
}

316 317
int btrfs_init_acl(struct btrfs_trans_handle *trans,
		   struct inode *inode, struct inode *dir)
318 319 320 321
{
	return 0;
}

C
Chris Mason 已提交
322
#endif /* CONFIG_BTRFS_FS_POSIX_ACL */