⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 acl.c

📁 linux 内核源代码
💻 C
字号:
/* * JFFS2 -- Journalling Flash File System, Version 2. * * Copyright © 2006  NEC Corporation * * Created by KaiGai Kohei <kaigai@ak.jp.nec.com> * * For licensing information, see the file 'LICENCE' in this directory. * */#include <linux/kernel.h>#include <linux/slab.h>#include <linux/fs.h>#include <linux/sched.h>#include <linux/time.h>#include <linux/crc32.h>#include <linux/jffs2.h>#include <linux/xattr.h>#include <linux/posix_acl_xattr.h>#include <linux/mtd/mtd.h>#include "nodelist.h"static size_t jffs2_acl_size(int count){	if (count <= 4) {		return sizeof(struct jffs2_acl_header)		       + count * sizeof(struct jffs2_acl_entry_short);	} else {		return sizeof(struct jffs2_acl_header)		       + 4 * sizeof(struct jffs2_acl_entry_short)		       + (count - 4) * sizeof(struct jffs2_acl_entry);	}}static int jffs2_acl_count(size_t size){	size_t s;	size -= sizeof(struct jffs2_acl_header);	s = size - 4 * sizeof(struct jffs2_acl_entry_short);	if (s < 0) {		if (size % sizeof(struct jffs2_acl_entry_short))			return -1;		return size / sizeof(struct jffs2_acl_entry_short);	} else {		if (s % sizeof(struct jffs2_acl_entry))			return -1;		return s / sizeof(struct jffs2_acl_entry) + 4;	}}static struct posix_acl *jffs2_acl_from_medium(void *value, size_t size){	void *end = value + size;	struct jffs2_acl_header *header = value;	struct jffs2_acl_entry *entry;	struct posix_acl *acl;	uint32_t ver;	int i, count;	if (!value)		return NULL;	if (size < sizeof(struct jffs2_acl_header))		return ERR_PTR(-EINVAL);	ver = je32_to_cpu(header->a_version);	if (ver != JFFS2_ACL_VERSION) {		JFFS2_WARNING("Invalid ACL version. (=%u)\n", ver);		return ERR_PTR(-EINVAL);	}	value += sizeof(struct jffs2_acl_header);	count = jffs2_acl_count(size);	if (count < 0)		return ERR_PTR(-EINVAL);	if (count == 0)		return NULL;	acl = posix_acl_alloc(count, GFP_KERNEL);	if (!acl)		return ERR_PTR(-ENOMEM);	for (i=0; i < count; i++) {		entry = value;		if (value + sizeof(struct jffs2_acl_entry_short) > end)			goto fail;		acl->a_entries[i].e_tag = je16_to_cpu(entry->e_tag);		acl->a_entries[i].e_perm = je16_to_cpu(entry->e_perm);		switch (acl->a_entries[i].e_tag) {			case ACL_USER_OBJ:			case ACL_GROUP_OBJ:			case ACL_MASK:			case ACL_OTHER:				value += sizeof(struct jffs2_acl_entry_short);				acl->a_entries[i].e_id = ACL_UNDEFINED_ID;				break;			case ACL_USER:			case ACL_GROUP:				value += sizeof(struct jffs2_acl_entry);				if (value > end)					goto fail;				acl->a_entries[i].e_id = je32_to_cpu(entry->e_id);				break;			default:				goto fail;		}	}	if (value != end)		goto fail;	return acl; fail:	posix_acl_release(acl);	return ERR_PTR(-EINVAL);}static void *jffs2_acl_to_medium(const struct posix_acl *acl, size_t *size){	struct jffs2_acl_header *header;	struct jffs2_acl_entry *entry;	void *e;	size_t i;	*size = jffs2_acl_size(acl->a_count);	header = kmalloc(sizeof(*header) + acl->a_count * sizeof(*entry), GFP_KERNEL);	if (!header)		return ERR_PTR(-ENOMEM);	header->a_version = cpu_to_je32(JFFS2_ACL_VERSION);	e = header + 1;	for (i=0; i < acl->a_count; i++) {		entry = e;		entry->e_tag = cpu_to_je16(acl->a_entries[i].e_tag);		entry->e_perm = cpu_to_je16(acl->a_entries[i].e_perm);		switch(acl->a_entries[i].e_tag) {			case ACL_USER:			case ACL_GROUP:				entry->e_id = cpu_to_je32(acl->a_entries[i].e_id);				e += sizeof(struct jffs2_acl_entry);				break;			case ACL_USER_OBJ:			case ACL_GROUP_OBJ:			case ACL_MASK:			case ACL_OTHER:				e += sizeof(struct jffs2_acl_entry_short);				break;			default:				goto fail;		}	}	return header; fail:	kfree(header);	return ERR_PTR(-EINVAL);}static struct posix_acl *jffs2_iget_acl(struct inode *inode, struct posix_acl **i_acl){	struct posix_acl *acl = JFFS2_ACL_NOT_CACHED;	spin_lock(&inode->i_lock);	if (*i_acl != JFFS2_ACL_NOT_CACHED)		acl = posix_acl_dup(*i_acl);	spin_unlock(&inode->i_lock);	return acl;}static void jffs2_iset_acl(struct inode *inode, struct posix_acl **i_acl, struct posix_acl *acl){	spin_lock(&inode->i_lock);	if (*i_acl != JFFS2_ACL_NOT_CACHED)		posix_acl_release(*i_acl);	*i_acl = posix_acl_dup(acl);	spin_unlock(&inode->i_lock);}struct posix_acl *jffs2_get_acl(struct inode *inode, int type){	struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);	struct posix_acl *acl;	char *value = NULL;	int rc, xprefix;	switch (type) {	case ACL_TYPE_ACCESS:		acl = jffs2_iget_acl(inode, &f->i_acl_access);		if (acl != JFFS2_ACL_NOT_CACHED)			return acl;		xprefix = JFFS2_XPREFIX_ACL_ACCESS;		break;	case ACL_TYPE_DEFAULT:		acl = jffs2_iget_acl(inode, &f->i_acl_default);		if (acl != JFFS2_ACL_NOT_CACHED)			return acl;		xprefix = JFFS2_XPREFIX_ACL_DEFAULT;		break;	default:		return ERR_PTR(-EINVAL);	}	rc = do_jffs2_getxattr(inode, xprefix, "", NULL, 0);	if (rc > 0) {		value = kmalloc(rc, GFP_KERNEL);		if (!value)			return ERR_PTR(-ENOMEM);		rc = do_jffs2_getxattr(inode, xprefix, "", value, rc);	}	if (rc > 0) {		acl = jffs2_acl_from_medium(value, rc);	} else if (rc == -ENODATA || rc == -ENOSYS) {		acl = NULL;	} else {		acl = ERR_PTR(rc);	}	if (value)		kfree(value);	if (!IS_ERR(acl)) {		switch (type) {		case ACL_TYPE_ACCESS:			jffs2_iset_acl(inode, &f->i_acl_access, acl);			break;		case ACL_TYPE_DEFAULT:			jffs2_iset_acl(inode, &f->i_acl_default, acl);			break;		}	}	return acl;}static int __jffs2_set_acl(struct inode *inode, int xprefix, struct posix_acl *acl){	char *value = NULL;	size_t size = 0;	int rc;	if (acl) {		value = jffs2_acl_to_medium(acl, &size);		if (IS_ERR(value))			return PTR_ERR(value);	}	rc = do_jffs2_setxattr(inode, xprefix, "", value, size, 0);	if (!value && rc == -ENODATA)		rc = 0;	kfree(value);	return rc;}static int jffs2_set_acl(struct inode *inode, int type, struct posix_acl *acl){	struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);	int rc, xprefix;	if (S_ISLNK(inode->i_mode))		return -EOPNOTSUPP;	switch (type) {	case ACL_TYPE_ACCESS:		xprefix = JFFS2_XPREFIX_ACL_ACCESS;		if (acl) {			mode_t mode = inode->i_mode;			rc = posix_acl_equiv_mode(acl, &mode);			if (rc < 0)				return rc;			if (inode->i_mode != mode) {				struct iattr attr;				attr.ia_valid = ATTR_MODE;				attr.ia_mode = mode;				rc = jffs2_do_setattr(inode, &attr);				if (rc < 0)					return rc;			}			if (rc == 0)				acl = NULL;		}		break;	case ACL_TYPE_DEFAULT:		xprefix = JFFS2_XPREFIX_ACL_DEFAULT;		if (!S_ISDIR(inode->i_mode))			return acl ? -EACCES : 0;		break;	default:		return -EINVAL;	}	rc = __jffs2_set_acl(inode, xprefix, acl);	if (!rc) {		switch(type) {		case ACL_TYPE_ACCESS:			jffs2_iset_acl(inode, &f->i_acl_access, acl);			break;		case ACL_TYPE_DEFAULT:			jffs2_iset_acl(inode, &f->i_acl_default, acl);			break;		}	}	return rc;}static int jffs2_check_acl(struct inode *inode, int mask){	struct posix_acl *acl;	int rc;	acl = jffs2_get_acl(inode, ACL_TYPE_ACCESS);	if (IS_ERR(acl))		return PTR_ERR(acl);	if (acl) {		rc = posix_acl_permission(inode, acl, mask);		posix_acl_release(acl);		return rc;	}	return -EAGAIN;}int jffs2_permission(struct inode *inode, int mask, struct nameidata *nd){	return generic_permission(inode, mask, jffs2_check_acl);}int jffs2_init_acl_pre(struct inode *dir_i, struct inode *inode, int *i_mode){	struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);	struct posix_acl *acl, *clone;	int rc;	f->i_acl_default = NULL;	f->i_acl_access = NULL;	if (S_ISLNK(*i_mode))		return 0;	/* Symlink always has no-ACL */	acl = jffs2_get_acl(dir_i, ACL_TYPE_DEFAULT);	if (IS_ERR(acl))		return PTR_ERR(acl);	if (!acl) {		*i_mode &= ~current->fs->umask;	} else {		if (S_ISDIR(*i_mode))			jffs2_iset_acl(inode, &f->i_acl_default, acl);		clone = posix_acl_clone(acl, GFP_KERNEL);		if (!clone)			return -ENOMEM;		rc = posix_acl_create_masq(clone, (mode_t *)i_mode);		if (rc < 0)			return rc;		if (rc > 0)			jffs2_iset_acl(inode, &f->i_acl_access, clone);		posix_acl_release(clone);	}	return 0;}int jffs2_init_acl_post(struct inode *inode){	struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);	int rc;	if (f->i_acl_default) {		rc = __jffs2_set_acl(inode, JFFS2_XPREFIX_ACL_DEFAULT, f->i_acl_default);		if (rc)			return rc;	}	if (f->i_acl_access) {		rc = __jffs2_set_acl(inode, JFFS2_XPREFIX_ACL_ACCESS, f->i_acl_access);		if (rc)			return rc;	}	return 0;}void jffs2_clear_acl(struct jffs2_inode_info *f){	if (f->i_acl_access && f->i_acl_access != JFFS2_ACL_NOT_CACHED) {		posix_acl_release(f->i_acl_access);		f->i_acl_access = JFFS2_ACL_NOT_CACHED;	}	if (f->i_acl_default && f->i_acl_default != JFFS2_ACL_NOT_CACHED) {		posix_acl_release(f->i_acl_default);		f->i_acl_default = JFFS2_ACL_NOT_CACHED;	}}int jffs2_acl_chmod(struct inode *inode){	struct posix_acl *acl, *clone;	int rc;	if (S_ISLNK(inode->i_mode))		return -EOPNOTSUPP;	acl = jffs2_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;	rc = posix_acl_chmod_masq(clone, inode->i_mode);	if (!rc)		rc = jffs2_set_acl(inode, ACL_TYPE_ACCESS, clone);	posix_acl_release(clone);	return rc;}static size_t jffs2_acl_access_listxattr(struct inode *inode, char *list, size_t list_size,					 const char *name, size_t name_len){	const int retlen = sizeof(POSIX_ACL_XATTR_ACCESS);	if (list && retlen <= list_size)		strcpy(list, POSIX_ACL_XATTR_ACCESS);	return retlen;}static size_t jffs2_acl_default_listxattr(struct inode *inode, char *list, size_t list_size,					  const char *name, size_t name_len){	const int retlen = sizeof(POSIX_ACL_XATTR_DEFAULT);	if (list && retlen <= list_size)		strcpy(list, POSIX_ACL_XATTR_DEFAULT);	return retlen;}static int jffs2_acl_getxattr(struct inode *inode, int type, void *buffer, size_t size){	struct posix_acl *acl;	int rc;	acl = jffs2_get_acl(inode, type);	if (IS_ERR(acl))		return PTR_ERR(acl);	if (!acl)		return -ENODATA;	rc = posix_acl_to_xattr(acl, buffer, size);	posix_acl_release(acl);	return rc;}static int jffs2_acl_access_getxattr(struct inode *inode, const char *name, void *buffer, size_t size){	if (name[0] != '\0')		return -EINVAL;	return jffs2_acl_getxattr(inode, ACL_TYPE_ACCESS, buffer, size);}static int jffs2_acl_default_getxattr(struct inode *inode, const char *name, void *buffer, size_t size){	if (name[0] != '\0')		return -EINVAL;	return jffs2_acl_getxattr(inode, ACL_TYPE_DEFAULT, buffer, size);}static int jffs2_acl_setxattr(struct inode *inode, int type, const void *value, size_t size){	struct posix_acl *acl;	int rc;	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) {			rc = posix_acl_valid(acl);			if (rc)				goto out;		}	} else {		acl = NULL;	}	rc = jffs2_set_acl(inode, type, acl); out:	posix_acl_release(acl);	return rc;}static int jffs2_acl_access_setxattr(struct inode *inode, const char *name,				     const void *buffer, size_t size, int flags){	if (name[0] != '\0')		return -EINVAL;	return jffs2_acl_setxattr(inode, ACL_TYPE_ACCESS, buffer, size);}static int jffs2_acl_default_setxattr(struct inode *inode, const char *name,				      const void *buffer, size_t size, int flags){	if (name[0] != '\0')		return -EINVAL;	return jffs2_acl_setxattr(inode, ACL_TYPE_DEFAULT, buffer, size);}struct xattr_handler jffs2_acl_access_xattr_handler = {	.prefix	= POSIX_ACL_XATTR_ACCESS,	.list	= jffs2_acl_access_listxattr,	.get	= jffs2_acl_access_getxattr,	.set	= jffs2_acl_access_setxattr,};struct xattr_handler jffs2_acl_default_xattr_handler = {	.prefix	= POSIX_ACL_XATTR_DEFAULT,	.list	= jffs2_acl_default_listxattr,	.get	= jffs2_acl_default_getxattr,	.set	= jffs2_acl_default_setxattr,};

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -