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

📄 xattr.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * linux/fs/ext3/xattr.c * * Copyright (C) 2001-2003 Andreas Gruenbacher, <agruen@suse.de> * * Fix by Harrison Xing <harrison@mountainviewdata.com>. * Ext3 code with a lot of help from Eric Jarman <ejarman@acm.org>. * Extended attributes for symlinks and special files added per *  suggestion of Luka Renko <luka.renko@hermes.si>. * xattr consolidation Copyright (c) 2004 James Morris <jmorris@redhat.com>, *  Red Hat Inc. * ea-in-inode support by Alex Tomas <alex@clusterfs.com> aka bzzz *  and Andreas Gruenbacher <agruen@suse.de>. *//* * Extended attributes are stored directly in inodes (on file systems with * inodes bigger than 128 bytes) and on additional disk blocks. The i_file_acl * field contains the block number if an inode uses an additional block. All * attributes must fit in the inode and one additional block. Blocks that * contain the identical set of attributes may be shared among several inodes. * Identical blocks are detected by keeping a cache of blocks that have * recently been accessed. * * The attributes in inodes and on blocks have a different header; the entries * are stored in the same format: * *   +------------------+ *   | header           | *   | entry 1          | | *   | entry 2          | | growing downwards *   | entry 3          | v *   | four null bytes  | *   | . . .            | *   | value 1          | ^ *   | value 3          | | growing upwards *   | value 2          | | *   +------------------+ * * The header is followed by multiple entry descriptors. In disk blocks, the * entry descriptors are kept sorted. In inodes, they are unsorted. The * attribute values are aligned to the end of the block in no specific order. * * Locking strategy * ---------------- * EXT3_I(inode)->i_file_acl is protected by EXT3_I(inode)->xattr_sem. * EA blocks are only changed if they are exclusive to an inode, so * holding xattr_sem also means that nothing but the EA block's reference * count can change. Multiple writers to the same block are synchronized * by the buffer lock. */#include <linux/init.h>#include <linux/fs.h>#include <linux/slab.h>#include <linux/ext3_jbd.h>#include <linux/ext3_fs.h>#include <linux/mbcache.h>#include <linux/quotaops.h>#include <linux/rwsem.h>#include "xattr.h"#include "acl.h"#define BHDR(bh) ((struct ext3_xattr_header *)((bh)->b_data))#define ENTRY(ptr) ((struct ext3_xattr_entry *)(ptr))#define BFIRST(bh) ENTRY(BHDR(bh)+1)#define IS_LAST_ENTRY(entry) (*(__u32 *)(entry) == 0)#define IHDR(inode, raw_inode) \	((struct ext3_xattr_ibody_header *) \		((void *)raw_inode + \		 EXT3_GOOD_OLD_INODE_SIZE + \		 EXT3_I(inode)->i_extra_isize))#define IFIRST(hdr) ((struct ext3_xattr_entry *)((hdr)+1))#ifdef EXT3_XATTR_DEBUG# define ea_idebug(inode, f...) do { \		printk(KERN_DEBUG "inode %s:%lu: ", \			inode->i_sb->s_id, inode->i_ino); \		printk(f); \		printk("\n"); \	} while (0)# define ea_bdebug(bh, f...) do { \		char b[BDEVNAME_SIZE]; \		printk(KERN_DEBUG "block %s:%lu: ", \			bdevname(bh->b_bdev, b), \			(unsigned long) bh->b_blocknr); \		printk(f); \		printk("\n"); \	} while (0)#else# define ea_idebug(f...)# define ea_bdebug(f...)#endifstatic void ext3_xattr_cache_insert(struct buffer_head *);static struct buffer_head *ext3_xattr_cache_find(struct inode *,						 struct ext3_xattr_header *,						 struct mb_cache_entry **);static void ext3_xattr_rehash(struct ext3_xattr_header *,			      struct ext3_xattr_entry *);static struct mb_cache *ext3_xattr_cache;static struct xattr_handler *ext3_xattr_handler_map[] = {	[EXT3_XATTR_INDEX_USER]		     = &ext3_xattr_user_handler,#ifdef CONFIG_EXT3_FS_POSIX_ACL	[EXT3_XATTR_INDEX_POSIX_ACL_ACCESS]  = &ext3_xattr_acl_access_handler,	[EXT3_XATTR_INDEX_POSIX_ACL_DEFAULT] = &ext3_xattr_acl_default_handler,#endif	[EXT3_XATTR_INDEX_TRUSTED]	     = &ext3_xattr_trusted_handler,#ifdef CONFIG_EXT3_FS_SECURITY	[EXT3_XATTR_INDEX_SECURITY]	     = &ext3_xattr_security_handler,#endif};struct xattr_handler *ext3_xattr_handlers[] = {	&ext3_xattr_user_handler,	&ext3_xattr_trusted_handler,#ifdef CONFIG_EXT3_FS_POSIX_ACL	&ext3_xattr_acl_access_handler,	&ext3_xattr_acl_default_handler,#endif#ifdef CONFIG_EXT3_FS_SECURITY	&ext3_xattr_security_handler,#endif	NULL};static inline struct xattr_handler *ext3_xattr_handler(int name_index){	struct xattr_handler *handler = NULL;	if (name_index > 0 && name_index < ARRAY_SIZE(ext3_xattr_handler_map))		handler = ext3_xattr_handler_map[name_index];	return handler;}/* * Inode operation listxattr() * * dentry->d_inode->i_mutex: don't care */ssize_text3_listxattr(struct dentry *dentry, char *buffer, size_t size){	return ext3_xattr_list(dentry->d_inode, buffer, size);}static intext3_xattr_check_names(struct ext3_xattr_entry *entry, void *end){	while (!IS_LAST_ENTRY(entry)) {		struct ext3_xattr_entry *next = EXT3_XATTR_NEXT(entry);		if ((void *)next >= end)			return -EIO;		entry = next;	}	return 0;}static inline intext3_xattr_check_block(struct buffer_head *bh){	int error;	if (BHDR(bh)->h_magic != cpu_to_le32(EXT3_XATTR_MAGIC) ||	    BHDR(bh)->h_blocks != cpu_to_le32(1))		return -EIO;	error = ext3_xattr_check_names(BFIRST(bh), bh->b_data + bh->b_size);	return error;}static inline intext3_xattr_check_entry(struct ext3_xattr_entry *entry, size_t size){	size_t value_size = le32_to_cpu(entry->e_value_size);	if (entry->e_value_block != 0 || value_size > size ||	    le16_to_cpu(entry->e_value_offs) + value_size > size)		return -EIO;	return 0;}static intext3_xattr_find_entry(struct ext3_xattr_entry **pentry, int name_index,		      const char *name, size_t size, int sorted){	struct ext3_xattr_entry *entry;	size_t name_len;	int cmp = 1;	if (name == NULL)		return -EINVAL;	name_len = strlen(name);	entry = *pentry;	for (; !IS_LAST_ENTRY(entry); entry = EXT3_XATTR_NEXT(entry)) {		cmp = name_index - entry->e_name_index;		if (!cmp)			cmp = name_len - entry->e_name_len;		if (!cmp)			cmp = memcmp(name, entry->e_name, name_len);		if (cmp <= 0 && (sorted || cmp == 0))			break;	}	*pentry = entry;	if (!cmp && ext3_xattr_check_entry(entry, size))			return -EIO;	return cmp ? -ENODATA : 0;}static intext3_xattr_block_get(struct inode *inode, int name_index, const char *name,		     void *buffer, size_t buffer_size){	struct buffer_head *bh = NULL;	struct ext3_xattr_entry *entry;	size_t size;	int error;	ea_idebug(inode, "name=%d.%s, buffer=%p, buffer_size=%ld",		  name_index, name, buffer, (long)buffer_size);	error = -ENODATA;	if (!EXT3_I(inode)->i_file_acl)		goto cleanup;	ea_idebug(inode, "reading block %u", EXT3_I(inode)->i_file_acl);	bh = sb_bread(inode->i_sb, EXT3_I(inode)->i_file_acl);	if (!bh)		goto cleanup;	ea_bdebug(bh, "b_count=%d, refcount=%d",		atomic_read(&(bh->b_count)), le32_to_cpu(BHDR(bh)->h_refcount));	if (ext3_xattr_check_block(bh)) {bad_block:	ext3_error(inode->i_sb, __FUNCTION__,			   "inode %lu: bad block "E3FSBLK, inode->i_ino,			   EXT3_I(inode)->i_file_acl);		error = -EIO;		goto cleanup;	}	ext3_xattr_cache_insert(bh);	entry = BFIRST(bh);	error = ext3_xattr_find_entry(&entry, name_index, name, bh->b_size, 1);	if (error == -EIO)		goto bad_block;	if (error)		goto cleanup;	size = le32_to_cpu(entry->e_value_size);	if (buffer) {		error = -ERANGE;		if (size > buffer_size)			goto cleanup;		memcpy(buffer, bh->b_data + le16_to_cpu(entry->e_value_offs),		       size);	}	error = size;cleanup:	brelse(bh);	return error;}static intext3_xattr_ibody_get(struct inode *inode, int name_index, const char *name,		     void *buffer, size_t buffer_size){	struct ext3_xattr_ibody_header *header;	struct ext3_xattr_entry *entry;	struct ext3_inode *raw_inode;	struct ext3_iloc iloc;	size_t size;	void *end;	int error;	if (!(EXT3_I(inode)->i_state & EXT3_STATE_XATTR))		return -ENODATA;	error = ext3_get_inode_loc(inode, &iloc);	if (error)		return error;	raw_inode = ext3_raw_inode(&iloc);	header = IHDR(inode, raw_inode);	entry = IFIRST(header);	end = (void *)raw_inode + EXT3_SB(inode->i_sb)->s_inode_size;	error = ext3_xattr_check_names(entry, end);	if (error)		goto cleanup;	error = ext3_xattr_find_entry(&entry, name_index, name,				      end - (void *)entry, 0);	if (error)		goto cleanup;	size = le32_to_cpu(entry->e_value_size);	if (buffer) {		error = -ERANGE;		if (size > buffer_size)			goto cleanup;		memcpy(buffer, (void *)IFIRST(header) +		       le16_to_cpu(entry->e_value_offs), size);	}	error = size;cleanup:	brelse(iloc.bh);	return error;}/* * ext3_xattr_get() * * Copy an extended attribute into the buffer * provided, or compute the buffer size required. * Buffer is NULL to compute the size of the buffer required. * * Returns a negative error number on failure, or the number of bytes * used / required on success. */intext3_xattr_get(struct inode *inode, int name_index, const char *name,	       void *buffer, size_t buffer_size){	int error;	down_read(&EXT3_I(inode)->xattr_sem);	error = ext3_xattr_ibody_get(inode, name_index, name, buffer,				     buffer_size);	if (error == -ENODATA)		error = ext3_xattr_block_get(inode, name_index, name, buffer,					     buffer_size);	up_read(&EXT3_I(inode)->xattr_sem);	return error;}static intext3_xattr_list_entries(struct inode *inode, struct ext3_xattr_entry *entry,			char *buffer, size_t buffer_size){	size_t rest = buffer_size;	for (; !IS_LAST_ENTRY(entry); entry = EXT3_XATTR_NEXT(entry)) {		struct xattr_handler *handler =			ext3_xattr_handler(entry->e_name_index);		if (handler) {			size_t size = handler->list(inode, buffer, rest,						    entry->e_name,						    entry->e_name_len);			if (buffer) {				if (size > rest)					return -ERANGE;				buffer += size;			}			rest -= size;		}	}	return buffer_size - rest;}static intext3_xattr_block_list(struct inode *inode, char *buffer, size_t buffer_size){	struct buffer_head *bh = NULL;	int error;	ea_idebug(inode, "buffer=%p, buffer_size=%ld",		  buffer, (long)buffer_size);	error = 0;	if (!EXT3_I(inode)->i_file_acl)		goto cleanup;	ea_idebug(inode, "reading block %u", EXT3_I(inode)->i_file_acl);	bh = sb_bread(inode->i_sb, EXT3_I(inode)->i_file_acl);	error = -EIO;	if (!bh)		goto cleanup;	ea_bdebug(bh, "b_count=%d, refcount=%d",		atomic_read(&(bh->b_count)), le32_to_cpu(BHDR(bh)->h_refcount));	if (ext3_xattr_check_block(bh)) {		ext3_error(inode->i_sb, __FUNCTION__,			   "inode %lu: bad block "E3FSBLK, inode->i_ino,			   EXT3_I(inode)->i_file_acl);		error = -EIO;		goto cleanup;	}	ext3_xattr_cache_insert(bh);	error = ext3_xattr_list_entries(inode, BFIRST(bh), buffer, buffer_size);cleanup:	brelse(bh);	return error;}static intext3_xattr_ibody_list(struct inode *inode, char *buffer, size_t buffer_size){	struct ext3_xattr_ibody_header *header;	struct ext3_inode *raw_inode;	struct ext3_iloc iloc;	void *end;	int error;	if (!(EXT3_I(inode)->i_state & EXT3_STATE_XATTR))		return 0;	error = ext3_get_inode_loc(inode, &iloc);	if (error)		return error;	raw_inode = ext3_raw_inode(&iloc);	header = IHDR(inode, raw_inode);	end = (void *)raw_inode + EXT3_SB(inode->i_sb)->s_inode_size;	error = ext3_xattr_check_names(IFIRST(header), end);	if (error)		goto cleanup;	error = ext3_xattr_list_entries(inode, IFIRST(header),					buffer, buffer_size);cleanup:	brelse(iloc.bh);	return error;}/* * ext3_xattr_list() * * Copy a list of attribute names into the buffer * provided, or compute the buffer size required. * Buffer is NULL to compute the size of the buffer required. * * Returns a negative error number on failure, or the number of bytes * used / required on success. */intext3_xattr_list(struct inode *inode, char *buffer, size_t buffer_size){	int i_error, b_error;	down_read(&EXT3_I(inode)->xattr_sem);	i_error = ext3_xattr_ibody_list(inode, buffer, buffer_size);	if (i_error < 0) {		b_error = 0;	} else {		if (buffer) {			buffer += i_error;			buffer_size -= i_error;

⌨️ 快捷键说明

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