mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	current->fs->umask is what most of fs_struct users are doing. Put that into a helper function. Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
		
			
				
	
	
		
			197 lines
		
	
	
	
		
			4.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			197 lines
		
	
	
	
		
			4.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 * fs/generic_acl.c
 | 
						|
 *
 | 
						|
 * (C) 2005 Andreas Gruenbacher <agruen@suse.de>
 | 
						|
 *
 | 
						|
 * This file is released under the GPL.
 | 
						|
 */
 | 
						|
 | 
						|
#include <linux/sched.h>
 | 
						|
#include <linux/fs.h>
 | 
						|
#include <linux/generic_acl.h>
 | 
						|
 | 
						|
/**
 | 
						|
 * generic_acl_list  -  Generic xattr_handler->list() operation
 | 
						|
 * @ops:	Filesystem specific getacl and setacl callbacks
 | 
						|
 */
 | 
						|
size_t
 | 
						|
generic_acl_list(struct inode *inode, struct generic_acl_operations *ops,
 | 
						|
		 int type, char *list, size_t list_size)
 | 
						|
{
 | 
						|
	struct posix_acl *acl;
 | 
						|
	const char *name;
 | 
						|
	size_t size;
 | 
						|
 | 
						|
	acl = ops->getacl(inode, type);
 | 
						|
	if (!acl)
 | 
						|
		return 0;
 | 
						|
	posix_acl_release(acl);
 | 
						|
 | 
						|
	switch(type) {
 | 
						|
		case ACL_TYPE_ACCESS:
 | 
						|
			name = POSIX_ACL_XATTR_ACCESS;
 | 
						|
			break;
 | 
						|
 | 
						|
		case ACL_TYPE_DEFAULT:
 | 
						|
			name = POSIX_ACL_XATTR_DEFAULT;
 | 
						|
			break;
 | 
						|
 | 
						|
		default:
 | 
						|
			return 0;
 | 
						|
	}
 | 
						|
	size = strlen(name) + 1;
 | 
						|
	if (list && size <= list_size)
 | 
						|
		memcpy(list, name, size);
 | 
						|
	return size;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * generic_acl_get  -  Generic xattr_handler->get() operation
 | 
						|
 * @ops:	Filesystem specific getacl and setacl callbacks
 | 
						|
 */
 | 
						|
int
 | 
						|
generic_acl_get(struct inode *inode, struct generic_acl_operations *ops,
 | 
						|
		int type, void *buffer, size_t size)
 | 
						|
{
 | 
						|
	struct posix_acl *acl;
 | 
						|
	int error;
 | 
						|
 | 
						|
	acl = ops->getacl(inode, type);
 | 
						|
	if (!acl)
 | 
						|
		return -ENODATA;
 | 
						|
	error = posix_acl_to_xattr(acl, buffer, size);
 | 
						|
	posix_acl_release(acl);
 | 
						|
 | 
						|
	return error;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * generic_acl_set  -  Generic xattr_handler->set() operation
 | 
						|
 * @ops:	Filesystem specific getacl and setacl callbacks
 | 
						|
 */
 | 
						|
int
 | 
						|
generic_acl_set(struct inode *inode, struct generic_acl_operations *ops,
 | 
						|
		int type, const void *value, size_t size)
 | 
						|
{
 | 
						|
	struct posix_acl *acl = NULL;
 | 
						|
	int error;
 | 
						|
 | 
						|
	if (S_ISLNK(inode->i_mode))
 | 
						|
		return -EOPNOTSUPP;
 | 
						|
	if (!is_owner_or_cap(inode))
 | 
						|
		return -EPERM;
 | 
						|
	if (value) {
 | 
						|
		acl = posix_acl_from_xattr(value, size);
 | 
						|
		if (IS_ERR(acl))
 | 
						|
			return PTR_ERR(acl);
 | 
						|
	}
 | 
						|
	if (acl) {
 | 
						|
		mode_t mode;
 | 
						|
 | 
						|
		error = posix_acl_valid(acl);
 | 
						|
		if (error)
 | 
						|
			goto failed;
 | 
						|
		switch(type) {
 | 
						|
			case ACL_TYPE_ACCESS:
 | 
						|
				mode = inode->i_mode;
 | 
						|
				error = posix_acl_equiv_mode(acl, &mode);
 | 
						|
				if (error < 0)
 | 
						|
					goto failed;
 | 
						|
				inode->i_mode = mode;
 | 
						|
				if (error == 0) {
 | 
						|
					posix_acl_release(acl);
 | 
						|
					acl = NULL;
 | 
						|
				}
 | 
						|
				break;
 | 
						|
 | 
						|
			case ACL_TYPE_DEFAULT:
 | 
						|
				if (!S_ISDIR(inode->i_mode)) {
 | 
						|
					error = -EINVAL;
 | 
						|
					goto failed;
 | 
						|
				}
 | 
						|
				break;
 | 
						|
		}
 | 
						|
	}
 | 
						|
	ops->setacl(inode, type, acl);
 | 
						|
	error = 0;
 | 
						|
failed:
 | 
						|
	posix_acl_release(acl);
 | 
						|
	return error;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * generic_acl_init  -  Take care of acl inheritance at @inode create time
 | 
						|
 * @ops:	Filesystem specific getacl and setacl callbacks
 | 
						|
 *
 | 
						|
 * Files created inside a directory with a default ACL inherit the
 | 
						|
 * directory's default ACL.
 | 
						|
 */
 | 
						|
int
 | 
						|
generic_acl_init(struct inode *inode, struct inode *dir,
 | 
						|
		 struct generic_acl_operations *ops)
 | 
						|
{
 | 
						|
	struct posix_acl *acl = NULL;
 | 
						|
	mode_t mode = inode->i_mode;
 | 
						|
	int error;
 | 
						|
 | 
						|
	inode->i_mode = mode & ~current_umask();
 | 
						|
	if (!S_ISLNK(inode->i_mode))
 | 
						|
		acl = ops->getacl(dir, ACL_TYPE_DEFAULT);
 | 
						|
	if (acl) {
 | 
						|
		struct posix_acl *clone;
 | 
						|
 | 
						|
		if (S_ISDIR(inode->i_mode)) {
 | 
						|
			clone = posix_acl_clone(acl, GFP_KERNEL);
 | 
						|
			error = -ENOMEM;
 | 
						|
			if (!clone)
 | 
						|
				goto cleanup;
 | 
						|
			ops->setacl(inode, ACL_TYPE_DEFAULT, clone);
 | 
						|
			posix_acl_release(clone);
 | 
						|
		}
 | 
						|
		clone = posix_acl_clone(acl, GFP_KERNEL);
 | 
						|
		error = -ENOMEM;
 | 
						|
		if (!clone)
 | 
						|
			goto cleanup;
 | 
						|
		error = posix_acl_create_masq(clone, &mode);
 | 
						|
		if (error >= 0) {
 | 
						|
			inode->i_mode = mode;
 | 
						|
			if (error > 0)
 | 
						|
				ops->setacl(inode, ACL_TYPE_ACCESS, clone);
 | 
						|
		}
 | 
						|
		posix_acl_release(clone);
 | 
						|
	}
 | 
						|
	error = 0;
 | 
						|
 | 
						|
cleanup:
 | 
						|
	posix_acl_release(acl);
 | 
						|
	return error;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * generic_acl_chmod  -  change the access acl of @inode upon chmod()
 | 
						|
 * @ops:	FIlesystem specific getacl and setacl callbacks
 | 
						|
 *
 | 
						|
 * A chmod also changes the permissions of the owner, group/mask, and
 | 
						|
 * other ACL entries.
 | 
						|
 */
 | 
						|
int
 | 
						|
generic_acl_chmod(struct inode *inode, struct generic_acl_operations *ops)
 | 
						|
{
 | 
						|
	struct posix_acl *acl, *clone;
 | 
						|
	int error = 0;
 | 
						|
 | 
						|
	if (S_ISLNK(inode->i_mode))
 | 
						|
		return -EOPNOTSUPP;
 | 
						|
	acl = ops->getacl(inode, ACL_TYPE_ACCESS);
 | 
						|
	if (acl) {
 | 
						|
		clone = posix_acl_clone(acl, GFP_KERNEL);
 | 
						|
		posix_acl_release(acl);
 | 
						|
		if (!clone)
 | 
						|
			return -ENOMEM;
 | 
						|
		error = posix_acl_chmod_masq(clone, inode->i_mode);
 | 
						|
		if (!error)
 | 
						|
			ops->setacl(inode, ACL_TYPE_ACCESS, clone);
 | 
						|
		posix_acl_release(clone);
 | 
						|
	}
 | 
						|
	return error;
 | 
						|
}
 |