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

📄 xattr.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
			discard_metapage(ea_buf->mp);			dbFree(inode, blkno, (s64) blocks_needed);			goto clean_up;		}		goto size_check;	}	ea_buf->flag = EA_EXTENT;	ea_buf->mp = read_metapage(inode, addressDXD(&ji->ea),				   lengthDXD(&ji->ea) << sb->s_blocksize_bits,				   1);	if (ea_buf->mp == NULL) {		rc = -EIO;		goto clean_up;	}	ea_buf->xattr = ea_buf->mp->data;	ea_buf->max_size = (ea_size + sb->s_blocksize - 1) &	    ~(sb->s_blocksize - 1);      size_check:	if (EALIST_SIZE(ea_buf->xattr) != ea_size) {		printk(KERN_ERR "ea_get: invalid extended attribute\n");		print_hex_dump(KERN_ERR, "", DUMP_PREFIX_ADDRESS, 16, 1,				     ea_buf->xattr, ea_size, 1);		ea_release(inode, ea_buf);		rc = -EIO;		goto clean_up;	}	return ea_size;      clean_up:	/* Rollback quota allocation */	if (quota_allocation)		DQUOT_FREE_BLOCK(inode, quota_allocation);	return (rc);}static void ea_release(struct inode *inode, struct ea_buffer *ea_buf){	if (ea_buf->flag & EA_MALLOC)		kfree(ea_buf->xattr);	else if (ea_buf->flag & EA_EXTENT) {		assert(ea_buf->mp);		release_metapage(ea_buf->mp);		if (ea_buf->flag & EA_NEW)			dbFree(inode, addressDXD(&ea_buf->new_ea),			       lengthDXD(&ea_buf->new_ea));	}}static int ea_put(tid_t tid, struct inode *inode, struct ea_buffer *ea_buf,		  int new_size){	struct jfs_inode_info *ji = JFS_IP(inode);	unsigned long old_blocks, new_blocks;	int rc = 0;	if (new_size == 0) {		ea_release(inode, ea_buf);		ea_buf = NULL;	} else if (ea_buf->flag & EA_INLINE) {		assert(new_size <= sizeof (ji->i_inline_ea));		ji->mode2 &= ~INLINEEA;		ea_buf->new_ea.flag = DXD_INLINE;		DXDsize(&ea_buf->new_ea, new_size);		DXDaddress(&ea_buf->new_ea, 0);		DXDlength(&ea_buf->new_ea, 0);	} else if (ea_buf->flag & EA_MALLOC) {		rc = ea_write(inode, ea_buf->xattr, new_size, &ea_buf->new_ea);		kfree(ea_buf->xattr);	} else if (ea_buf->flag & EA_NEW) {		/* We have already allocated a new dxd */		flush_metapage(ea_buf->mp);	} else {		/* ->xattr must point to original ea's metapage */		rc = ea_write(inode, ea_buf->xattr, new_size, &ea_buf->new_ea);		discard_metapage(ea_buf->mp);	}	if (rc)		return rc;	old_blocks = new_blocks = 0;	if (ji->ea.flag & DXD_EXTENT) {		invalidate_dxd_metapages(inode, ji->ea);		old_blocks = lengthDXD(&ji->ea);	}	if (ea_buf) {		txEA(tid, inode, &ji->ea, &ea_buf->new_ea);		if (ea_buf->new_ea.flag & DXD_EXTENT) {			new_blocks = lengthDXD(&ea_buf->new_ea);			if (ji->ea.flag & DXD_INLINE)				ji->mode2 |= INLINEEA;		}		ji->ea = ea_buf->new_ea;	} else {		txEA(tid, inode, &ji->ea, NULL);		if (ji->ea.flag & DXD_INLINE)			ji->mode2 |= INLINEEA;		ji->ea.flag = 0;		ji->ea.size = 0;	}	/* If old blocks exist, they must be removed from quota allocation. */	if (old_blocks)		DQUOT_FREE_BLOCK(inode, old_blocks);	inode->i_ctime = CURRENT_TIME;	return 0;}/* * can_set_system_xattr * * This code is specific to the system.* namespace.  It contains policy * which doesn't belong in the main xattr codepath. */static int can_set_system_xattr(struct inode *inode, const char *name,				const void *value, size_t value_len){#ifdef CONFIG_JFS_POSIX_ACL	struct posix_acl *acl;	int rc;	if (!is_owner_or_cap(inode))		return -EPERM;	/*	 * POSIX_ACL_XATTR_ACCESS is tied to i_mode	 */	if (strcmp(name, POSIX_ACL_XATTR_ACCESS) == 0) {		acl = posix_acl_from_xattr(value, value_len);		if (IS_ERR(acl)) {			rc = PTR_ERR(acl);			printk(KERN_ERR "posix_acl_from_xattr returned %d\n",			       rc);			return rc;		}		if (acl) {			mode_t mode = inode->i_mode;			rc = posix_acl_equiv_mode(acl, &mode);			posix_acl_release(acl);			if (rc < 0) {				printk(KERN_ERR				       "posix_acl_equiv_mode returned %d\n",				       rc);				return rc;			}			inode->i_mode = mode;			mark_inode_dirty(inode);		}		/*		 * We're changing the ACL.  Get rid of the cached one		 */		acl =JFS_IP(inode)->i_acl;		if (acl != JFS_ACL_NOT_CACHED)			posix_acl_release(acl);		JFS_IP(inode)->i_acl = JFS_ACL_NOT_CACHED;		return 0;	} else if (strcmp(name, POSIX_ACL_XATTR_DEFAULT) == 0) {		acl = posix_acl_from_xattr(value, value_len);		if (IS_ERR(acl)) {			rc = PTR_ERR(acl);			printk(KERN_ERR "posix_acl_from_xattr returned %d\n",			       rc);			return rc;		}		posix_acl_release(acl);		/*		 * We're changing the default ACL.  Get rid of the cached one		 */		acl =JFS_IP(inode)->i_default_acl;		if (acl && (acl != JFS_ACL_NOT_CACHED))			posix_acl_release(acl);		JFS_IP(inode)->i_default_acl = JFS_ACL_NOT_CACHED;		return 0;	}#endif			/* CONFIG_JFS_POSIX_ACL */	return -EOPNOTSUPP;}/* * Most of the permission checking is done by xattr_permission in the vfs. * The local file system is responsible for handling the system.* namespace. * We also need to verify that this is a namespace that we recognize. */static int can_set_xattr(struct inode *inode, const char *name,			 const void *value, size_t value_len){	if (!strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN))		return can_set_system_xattr(inode, name, value, value_len);	/*	 * Don't allow setting an attribute in an unknown namespace.	 */	if (strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN) &&	    strncmp(name, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN) &&	    strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN) &&	    strncmp(name, XATTR_OS2_PREFIX, XATTR_OS2_PREFIX_LEN))		return -EOPNOTSUPP;	return 0;}int __jfs_setxattr(tid_t tid, struct inode *inode, const char *name,		   const void *value, size_t value_len, int flags){	struct jfs_ea_list *ealist;	struct jfs_ea *ea, *old_ea = NULL, *next_ea = NULL;	struct ea_buffer ea_buf;	int old_ea_size = 0;	int xattr_size;	int new_size;	int namelen = strlen(name);	char *os2name = NULL;	int found = 0;	int rc;	int length;	if (strncmp(name, XATTR_OS2_PREFIX, XATTR_OS2_PREFIX_LEN) == 0) {		os2name = kmalloc(namelen - XATTR_OS2_PREFIX_LEN + 1,				  GFP_KERNEL);		if (!os2name)			return -ENOMEM;		strcpy(os2name, name + XATTR_OS2_PREFIX_LEN);		name = os2name;		namelen -= XATTR_OS2_PREFIX_LEN;	}	down_write(&JFS_IP(inode)->xattr_sem);	xattr_size = ea_get(inode, &ea_buf, 0);	if (xattr_size < 0) {		rc = xattr_size;		goto out;	}      again:	ealist = (struct jfs_ea_list *) ea_buf.xattr;	new_size = sizeof (struct jfs_ea_list);	if (xattr_size) {		for (ea = FIRST_EA(ealist); ea < END_EALIST(ealist);		     ea = NEXT_EA(ea)) {			if ((namelen == ea->namelen) &&			    (memcmp(name, ea->name, namelen) == 0)) {				found = 1;				if (flags & XATTR_CREATE) {					rc = -EEXIST;					goto release;				}				old_ea = ea;				old_ea_size = EA_SIZE(ea);				next_ea = NEXT_EA(ea);			} else				new_size += EA_SIZE(ea);		}	}	if (!found) {		if (flags & XATTR_REPLACE) {			rc = -ENODATA;			goto release;		}		if (value == NULL) {			rc = 0;			goto release;		}	}	if (value)		new_size += sizeof (struct jfs_ea) + namelen + 1 + value_len;	if (new_size > ea_buf.max_size) {		/*		 * We need to allocate more space for merged ea list.		 * We should only have loop to again: once.		 */		ea_release(inode, &ea_buf);		xattr_size = ea_get(inode, &ea_buf, new_size);		if (xattr_size < 0) {			rc = xattr_size;			goto out;		}		goto again;	}	/* Remove old ea of the same name */	if (found) {		/* number of bytes following target EA */		length = (char *) END_EALIST(ealist) - (char *) next_ea;		if (length > 0)			memmove(old_ea, next_ea, length);		xattr_size -= old_ea_size;	}	/* Add new entry to the end */	if (value) {		if (xattr_size == 0)			/* Completely new ea list */			xattr_size = sizeof (struct jfs_ea_list);		ea = (struct jfs_ea *) ((char *) ealist + xattr_size);		ea->flag = 0;		ea->namelen = namelen;		ea->valuelen = (cpu_to_le16(value_len));		memcpy(ea->name, name, namelen);		ea->name[namelen] = 0;		if (value_len)			memcpy(&ea->name[namelen + 1], value, value_len);		xattr_size += EA_SIZE(ea);	}	/* DEBUG - If we did this right, these number match */	if (xattr_size != new_size) {		printk(KERN_ERR		       "jfs_xsetattr: xattr_size = %d, new_size = %d\n",		       xattr_size, new_size);		rc = -EINVAL;		goto release;	}	/*	 * If we're left with an empty list, there's no ea	 */	if (new_size == sizeof (struct jfs_ea_list))		new_size = 0;	ealist->size = cpu_to_le32(new_size);	rc = ea_put(tid, inode, &ea_buf, new_size);	goto out;      release:	ea_release(inode, &ea_buf);      out:	up_write(&JFS_IP(inode)->xattr_sem);	kfree(os2name);	return rc;}int jfs_setxattr(struct dentry *dentry, const char *name, const void *value,		 size_t value_len, int flags){	struct inode *inode = dentry->d_inode;	struct jfs_inode_info *ji = JFS_IP(inode);	int rc;	tid_t tid;	if ((rc = can_set_xattr(inode, name, value, value_len)))		return rc;	if (value == NULL) {	/* empty EA, do not remove */		value = "";		value_len = 0;	}	tid = txBegin(inode->i_sb, 0);	mutex_lock(&ji->commit_mutex);	rc = __jfs_setxattr(tid, dentry->d_inode, name, value, value_len,			    flags);	if (!rc)		rc = txCommit(tid, 1, &inode, 0);	txEnd(tid);	mutex_unlock(&ji->commit_mutex);	return rc;}ssize_t __jfs_getxattr(struct inode *inode, const char *name, void *data,		       size_t buf_size){	struct jfs_ea_list *ealist;	struct jfs_ea *ea;	struct ea_buffer ea_buf;	int xattr_size;	ssize_t size;	int namelen = strlen(name);	char *os2name = NULL;	char *value;	if (strncmp(name, XATTR_OS2_PREFIX, XATTR_OS2_PREFIX_LEN) == 0) {		os2name = kmalloc(namelen - XATTR_OS2_PREFIX_LEN + 1,				  GFP_KERNEL);		if (!os2name)			return -ENOMEM;		strcpy(os2name, name + XATTR_OS2_PREFIX_LEN);		name = os2name;		namelen -= XATTR_OS2_PREFIX_LEN;	}	down_read(&JFS_IP(inode)->xattr_sem);	xattr_size = ea_get(inode, &ea_buf, 0);	if (xattr_size < 0) {		size = xattr_size;		goto out;	}	if (xattr_size == 0)		goto not_found;	ealist = (struct jfs_ea_list *) ea_buf.xattr;	/* Find the named attribute */	for (ea = FIRST_EA(ealist); ea < END_EALIST(ealist); ea = NEXT_EA(ea))		if ((namelen == ea->namelen) &&		    memcmp(name, ea->name, namelen) == 0) {			/* Found it */			size = le16_to_cpu(ea->valuelen);			if (!data)				goto release;			else if (size > buf_size) {				size = -ERANGE;				goto release;			}			value = ((char *) &ea->name) + ea->namelen + 1;			memcpy(data, value, size);			goto release;		}      not_found:	size = -ENODATA;      release:	ea_release(inode, &ea_buf);      out:	up_read(&JFS_IP(inode)->xattr_sem);	kfree(os2name);	return size;}ssize_t jfs_getxattr(struct dentry *dentry, const char *name, void *data,		     size_t buf_size){	int err;	err = __jfs_getxattr(dentry->d_inode, name, data, buf_size);	return err;}/* * No special permissions are needed to list attributes except for trusted.* */static inline int can_list(struct jfs_ea *ea){	return (strncmp(ea->name, XATTR_TRUSTED_PREFIX,			    XATTR_TRUSTED_PREFIX_LEN) ||		capable(CAP_SYS_ADMIN));}ssize_t jfs_listxattr(struct dentry * dentry, char *data, size_t buf_size){	struct inode *inode = dentry->d_inode;	char *buffer;	ssize_t size = 0;	int xattr_size;	struct jfs_ea_list *ealist;	struct jfs_ea *ea;	struct ea_buffer ea_buf;	down_read(&JFS_IP(inode)->xattr_sem);	xattr_size = ea_get(inode, &ea_buf, 0);	if (xattr_size < 0) {		size = xattr_size;		goto out;	}	if (xattr_size == 0)		goto release;	ealist = (struct jfs_ea_list *) ea_buf.xattr;	/* compute required size of list */	for (ea = FIRST_EA(ealist); ea < END_EALIST(ealist); ea = NEXT_EA(ea)) {		if (can_list(ea))			size += name_size(ea) + 1;	}	if (!data)		goto release;	if (size > buf_size) {		size = -ERANGE;		goto release;	}	/* Copy attribute names to buffer */	buffer = data;	for (ea = FIRST_EA(ealist); ea < END_EALIST(ealist); ea = NEXT_EA(ea)) {		if (can_list(ea)) {			int namelen = copy_name(buffer, ea);			buffer += namelen + 1;		}	}      release:	ea_release(inode, &ea_buf);      out:	up_read(&JFS_IP(inode)->xattr_sem);	return size;}int jfs_removexattr(struct dentry *dentry, const char *name){	struct inode *inode = dentry->d_inode;	struct jfs_inode_info *ji = JFS_IP(inode);	int rc;	tid_t tid;	if ((rc = can_set_xattr(inode, name, NULL, 0)))		return rc;	tid = txBegin(inode->i_sb, 0);	mutex_lock(&ji->commit_mutex);	rc = __jfs_setxattr(tid, dentry->d_inode, name, NULL, 0, XATTR_REPLACE);	if (!rc)		rc = txCommit(tid, 1, &inode, 0);	txEnd(tid);	mutex_unlock(&ji->commit_mutex);	return rc;}#ifdef CONFIG_JFS_SECURITYint jfs_init_security(tid_t tid, struct inode *inode, struct inode *dir){	int rc;	size_t len;	void *value;	char *suffix;	char *name;	rc = security_inode_init_security(inode, dir, &suffix, &value, &len);	if (rc) {		if (rc == -EOPNOTSUPP)			return 0;		return rc;	}	name = kmalloc(XATTR_SECURITY_PREFIX_LEN + 1 + strlen(suffix),		       GFP_NOFS);	if (!name) {		rc = -ENOMEM;		goto kmalloc_failed;	}	strcpy(name, XATTR_SECURITY_PREFIX);	strcpy(name + XATTR_SECURITY_PREFIX_LEN, suffix);	rc = __jfs_setxattr(tid, inode, name, value, len, 0);	kfree(name);kmalloc_failed:	kfree(suffix);	kfree(value);	return rc;}#endif

⌨️ 快捷键说明

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