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

📄 xattr.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
		   size_t buffer_size, int flags){	int err = 0;	struct file *fp;	struct page *page;	char *data;	struct address_space *mapping;	size_t file_pos = 0;	size_t buffer_pos = 0;	struct inode *xinode;	struct iattr newattrs;	__u32 xahash = 0;	if (get_inode_sd_version(inode) == STAT_DATA_V1)		return -EOPNOTSUPP;	/* Empty xattrs are ok, they're just empty files, no hash */	if (buffer && buffer_size)		xahash = xattr_hash(buffer, buffer_size);      open_file:	fp = open_xa_file(inode, name, flags);	if (IS_ERR(fp)) {		err = PTR_ERR(fp);		goto out;	}	xinode = fp->f_path.dentry->d_inode;	REISERFS_I(inode)->i_flags |= i_has_xattr_dir;	/* we need to copy it off.. */	if (xinode->i_nlink > 1) {		fput(fp);		err = reiserfs_xattr_del(inode, name);		if (err < 0)			goto out;		/* We just killed the old one, we're not replacing anymore */		if (flags & XATTR_REPLACE)			flags &= ~XATTR_REPLACE;		goto open_file;	}	/* Resize it so we're ok to write there */	newattrs.ia_size = buffer_size;	newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME;	mutex_lock_nested(&xinode->i_mutex, I_MUTEX_XATTR);	err = notify_change(fp->f_path.dentry, &newattrs);	if (err)		goto out_filp;	mapping = xinode->i_mapping;	while (buffer_pos < buffer_size || buffer_pos == 0) {		size_t chunk;		size_t skip = 0;		size_t page_offset = (file_pos & (PAGE_CACHE_SIZE - 1));		if (buffer_size - buffer_pos > PAGE_CACHE_SIZE)			chunk = PAGE_CACHE_SIZE;		else			chunk = buffer_size - buffer_pos;		page = reiserfs_get_page(xinode, file_pos >> PAGE_CACHE_SHIFT);		if (IS_ERR(page)) {			err = PTR_ERR(page);			goto out_filp;		}		lock_page(page);		data = page_address(page);		if (file_pos == 0) {			struct reiserfs_xattr_header *rxh;			skip = file_pos = sizeof(struct reiserfs_xattr_header);			if (chunk + skip > PAGE_CACHE_SIZE)				chunk = PAGE_CACHE_SIZE - skip;			rxh = (struct reiserfs_xattr_header *)data;			rxh->h_magic = cpu_to_le32(REISERFS_XATTR_MAGIC);			rxh->h_hash = cpu_to_le32(xahash);		}		err = reiserfs_prepare_write(fp, page, page_offset,					    page_offset + chunk + skip);		if (!err) {			if (buffer)				memcpy(data + skip, buffer + buffer_pos, chunk);			err =			    reiserfs_commit_write(fp, page, page_offset,						  page_offset + chunk +						  skip);		}		unlock_page(page);		reiserfs_put_page(page);		buffer_pos += chunk;		file_pos += chunk;		skip = 0;		if (err || buffer_size == 0 || !buffer)			break;	}	/* We can't mark the inode dirty if it's not hashed. This is the case	 * when we're inheriting the default ACL. If we dirty it, the inode	 * gets marked dirty, but won't (ever) make it onto the dirty list until	 * it's synced explicitly to clear I_DIRTY. This is bad. */	if (!hlist_unhashed(&inode->i_hash)) {		inode->i_ctime = CURRENT_TIME_SEC;		mark_inode_dirty(inode);	}      out_filp:	mutex_unlock(&xinode->i_mutex);	fput(fp);      out:	return err;}/* * inode->i_mutex: down */intreiserfs_xattr_get(const struct inode *inode, const char *name, void *buffer,		   size_t buffer_size){	ssize_t err = 0;	struct file *fp;	size_t isize;	size_t file_pos = 0;	size_t buffer_pos = 0;	struct page *page;	struct inode *xinode;	__u32 hash = 0;	if (name == NULL)		return -EINVAL;	/* We can't have xattrs attached to v1 items since they don't have	 * generation numbers */	if (get_inode_sd_version(inode) == STAT_DATA_V1)		return -EOPNOTSUPP;	fp = open_xa_file(inode, name, FL_READONLY);	if (IS_ERR(fp)) {		err = PTR_ERR(fp);		goto out;	}	xinode = fp->f_path.dentry->d_inode;	isize = xinode->i_size;	REISERFS_I(inode)->i_flags |= i_has_xattr_dir;	/* Just return the size needed */	if (buffer == NULL) {		err = isize - sizeof(struct reiserfs_xattr_header);		goto out_dput;	}	if (buffer_size < isize - sizeof(struct reiserfs_xattr_header)) {		err = -ERANGE;		goto out_dput;	}	while (file_pos < isize) {		size_t chunk;		char *data;		size_t skip = 0;		if (isize - file_pos > PAGE_CACHE_SIZE)			chunk = PAGE_CACHE_SIZE;		else			chunk = isize - file_pos;		page = reiserfs_get_page(xinode, file_pos >> PAGE_CACHE_SHIFT);		if (IS_ERR(page)) {			err = PTR_ERR(page);			goto out_dput;		}		lock_page(page);		data = page_address(page);		if (file_pos == 0) {			struct reiserfs_xattr_header *rxh =			    (struct reiserfs_xattr_header *)data;			skip = file_pos = sizeof(struct reiserfs_xattr_header);			chunk -= skip;			/* Magic doesn't match up.. */			if (rxh->h_magic != cpu_to_le32(REISERFS_XATTR_MAGIC)) {				unlock_page(page);				reiserfs_put_page(page);				reiserfs_warning(inode->i_sb,						 "Invalid magic for xattr (%s) "						 "associated with %k", name,						 INODE_PKEY(inode));				err = -EIO;				goto out_dput;			}			hash = le32_to_cpu(rxh->h_hash);		}		memcpy(buffer + buffer_pos, data + skip, chunk);		unlock_page(page);		reiserfs_put_page(page);		file_pos += chunk;		buffer_pos += chunk;		skip = 0;	}	err = isize - sizeof(struct reiserfs_xattr_header);	if (xattr_hash(buffer, isize - sizeof(struct reiserfs_xattr_header)) !=	    hash) {		reiserfs_warning(inode->i_sb,				 "Invalid hash for xattr (%s) associated "				 "with %k", name, INODE_PKEY(inode));		err = -EIO;	}      out_dput:	fput(fp);      out:	return err;}static int__reiserfs_xattr_del(struct dentry *xadir, const char *name, int namelen){	struct dentry *dentry;	struct inode *dir = xadir->d_inode;	int err = 0;	dentry = lookup_one_len(name, xadir, namelen);	if (IS_ERR(dentry)) {		err = PTR_ERR(dentry);		goto out;	} else if (!dentry->d_inode) {		err = -ENODATA;		goto out_file;	}	/* Skip directories.. */	if (S_ISDIR(dentry->d_inode->i_mode))		goto out_file;	if (!is_reiserfs_priv_object(dentry->d_inode)) {		reiserfs_warning(dir->i_sb, "OID %08x [%.*s/%.*s] doesn't have "				 "priv flag set [parent is %sset].",				 le32_to_cpu(INODE_PKEY(dentry->d_inode)->					     k_objectid), xadir->d_name.len,				 xadir->d_name.name, namelen, name,				 is_reiserfs_priv_object(xadir->							 d_inode) ? "" :				 "not ");		dput(dentry);		return -EIO;	}	err = dir->i_op->unlink(dir, dentry);	if (!err)		d_delete(dentry);      out_file:	dput(dentry);      out:	return err;}int reiserfs_xattr_del(struct inode *inode, const char *name){	struct dentry *dir;	int err;	dir = open_xa_dir(inode, FL_READONLY);	if (IS_ERR(dir)) {		err = PTR_ERR(dir);		goto out;	}	err = __reiserfs_xattr_del(dir, name, strlen(name));	dput(dir);	if (!err) {		inode->i_ctime = CURRENT_TIME_SEC;		mark_inode_dirty(inode);	}      out:	return err;}/* The following are side effects of other operations that aren't explicitly * modifying extended attributes. This includes operations such as permissions * or ownership changes, object deletions, etc. */static intreiserfs_delete_xattrs_filler(void *buf, const char *name, int namelen,			      loff_t offset, u64 ino, unsigned int d_type){	struct dentry *xadir = (struct dentry *)buf;	return __reiserfs_xattr_del(xadir, name, namelen);}/* This is called w/ inode->i_mutex downed */int reiserfs_delete_xattrs(struct inode *inode){	struct file *fp;	struct dentry *dir, *root;	int err = 0;	/* Skip out, an xattr has no xattrs associated with it */	if (is_reiserfs_priv_object(inode) ||	    get_inode_sd_version(inode) == STAT_DATA_V1 ||	    !reiserfs_xattrs(inode->i_sb)) {		return 0;	}	reiserfs_read_lock_xattrs(inode->i_sb);	dir = open_xa_dir(inode, FL_READONLY);	reiserfs_read_unlock_xattrs(inode->i_sb);	if (IS_ERR(dir)) {		err = PTR_ERR(dir);		goto out;	} else if (!dir->d_inode) {		dput(dir);		return 0;	}	fp = dentry_open(dir, NULL, O_RDWR);	if (IS_ERR(fp)) {		err = PTR_ERR(fp);		/* dentry_open dputs the dentry if it fails */		goto out;	}	lock_kernel();	err = xattr_readdir(fp, reiserfs_delete_xattrs_filler, dir);	if (err) {		unlock_kernel();		goto out_dir;	}	/* Leftovers besides . and .. -- that's not good. */	if (dir->d_inode->i_nlink <= 2) {		root = get_xa_root(inode->i_sb, XATTR_REPLACE);		reiserfs_write_lock_xattrs(inode->i_sb);		err = vfs_rmdir(root->d_inode, dir);		reiserfs_write_unlock_xattrs(inode->i_sb);		dput(root);	} else {		reiserfs_warning(inode->i_sb,				 "Couldn't remove all entries in directory");	}	unlock_kernel();      out_dir:	fput(fp);      out:	if (!err)		REISERFS_I(inode)->i_flags =		    REISERFS_I(inode)->i_flags & ~i_has_xattr_dir;	return err;}struct reiserfs_chown_buf {	struct inode *inode;	struct dentry *xadir;	struct iattr *attrs;};/* XXX: If there is a better way to do this, I'd love to hear about it */static intreiserfs_chown_xattrs_filler(void *buf, const char *name, int namelen,			     loff_t offset, u64 ino, unsigned int d_type){	struct reiserfs_chown_buf *chown_buf = (struct reiserfs_chown_buf *)buf;	struct dentry *xafile, *xadir = chown_buf->xadir;	struct iattr *attrs = chown_buf->attrs;	int err = 0;	xafile = lookup_one_len(name, xadir, namelen);	if (IS_ERR(xafile))		return PTR_ERR(xafile);	else if (!xafile->d_inode) {		dput(xafile);		return -ENODATA;	}	if (!S_ISDIR(xafile->d_inode->i_mode))		err = notify_change(xafile, attrs);	dput(xafile);	return err;}int reiserfs_chown_xattrs(struct inode *inode, struct iattr *attrs){	struct file *fp;	struct dentry *dir;	int err = 0;	struct reiserfs_chown_buf buf;	unsigned int ia_valid = attrs->ia_valid;	/* Skip out, an xattr has no xattrs associated with it */	if (is_reiserfs_priv_object(inode) ||	    get_inode_sd_version(inode) == STAT_DATA_V1 ||	    !reiserfs_xattrs(inode->i_sb)) {		return 0;	}	reiserfs_read_lock_xattrs(inode->i_sb);	dir = open_xa_dir(inode, FL_READONLY);	reiserfs_read_unlock_xattrs(inode->i_sb);	if (IS_ERR(dir)) {		if (PTR_ERR(dir) != -ENODATA)			err = PTR_ERR(dir);		goto out;	} else if (!dir->d_inode) {		dput(dir);		goto out;	}	fp = dentry_open(dir, NULL, O_RDWR);	if (IS_ERR(fp)) {		err = PTR_ERR(fp);		/* dentry_open dputs the dentry if it fails */		goto out;	}	lock_kernel();	attrs->ia_valid &= (ATTR_UID | ATTR_GID | ATTR_CTIME);	buf.xadir = dir;	buf.attrs = attrs;	buf.inode = inode;	err = xattr_readdir(fp, reiserfs_chown_xattrs_filler, &buf);	if (err) {		unlock_kernel();		goto out_dir;	}	err = notify_change(dir, attrs);	unlock_kernel();

⌨️ 快捷键说明

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