All of lore.kernel.org
 help / color / mirror / Atom feed
From: Hin-Tak Leung <htl10@users.sourceforge.net>
To: Vyacheslav Dubeyko <slava@dubeyko.com>
Cc: linux-fsdevel@vger.kernel.org
Subject: Re: [PATCH 4/4] hfsplus: add support of manipulation by attributes file
Date: Sat, 15 Sep 2012 01:11:50 +0100	[thread overview]
Message-ID: <5053C7C6.5080800@users.sourceforge.net> (raw)
In-Reply-To: <AA3ED105-D7F0-4551-91BA-5DB134A671D6@dubeyko.com>

Vyacheslav Dubeyko wrote:
> Hi,
>
> This patch adds support of manipulation by attributes file.
>
> With the best regards,
> Vyacheslav Dubeyko.
> --
> From: Vyacheslav Dubeyko <slava@dubeyko.com>
> Subject: [PATCH 4/4] hfsplus: add support of manipulation by attributes file
>
> This patch adds support of manipulation by attributes file.
>
> Reported-by: Hin-Tak Leung <htl10@users.sourceforge.net>
> Signed-off-by: Vyacheslav Dubeyko <slava@dubeyko.com>

NACK. It does not work (i.e. cannot read attributes of files which have them), 
and also generates a lot of warnings, "hfs: xattr searching failed".

The files I looked at are the font suitecase files in the /System/Library/Fonts 
directory.

> ---
>   fs/hfsplus/bfind.c      |   79 +++++++++++++++++++++++++++++++++++++++-------
>   fs/hfsplus/bnode.c      |    6 ++-
>   fs/hfsplus/brec.c       |   23 ++++++++-----
>   fs/hfsplus/btree.c      |    8 +++++
>   fs/hfsplus/catalog.c    |   36 +++++++++++++--------
>   fs/hfsplus/dir.c        |   24 ++++++++------
>   fs/hfsplus/extents.c    |    4 +-
>   fs/hfsplus/hfsplus_fs.h |   41 ++++++++++++++++++++++--
>   fs/hfsplus/inode.c      |   13 ++++++++
>   fs/hfsplus/super.c      |   36 ++++++++++++++++++++-
>   fs/hfsplus/unicode.c    |    7 ++--
>   11 files changed, 219 insertions(+), 58 deletions(-)
>
> diff --git a/fs/hfsplus/bfind.c b/fs/hfsplus/bfind.c
> index 5d799c1..55baffa 100644
> --- a/fs/hfsplus/bfind.c
> +++ b/fs/hfsplus/bfind.c
> @@ -38,15 +38,73 @@ void hfs_find_exit(struct hfs_find_data *fd)
>   	fd->tree = NULL;
>   }
>
> -/* Find the record in bnode that best matches key (not greater than...)*/
> -int __hfs_brec_find(struct hfs_bnode *bnode, struct hfs_find_data *fd)
> +int hfs_find_1st_rec_by_cnid(struct hfs_bnode *bnode,
> +				struct hfs_find_data *fd,
> +				int *begin,
> +				int *end,
> +				int *cur_rec)
> +{
> +	__be32 cur_cnid, search_cnid;
> +
> +	if (bnode->tree->cnid == HFSPLUS_EXT_CNID) {
> +		cur_cnid = fd->key->ext.cnid;
> +		search_cnid = fd->search_key->ext.cnid;
> +	} else if (bnode->tree->cnid == HFSPLUS_CAT_CNID) {
> +		cur_cnid = fd->key->cat.parent;
> +		search_cnid = fd->search_key->cat.parent;
> +	} else if (bnode->tree->cnid == HFSPLUS_ATTR_CNID) {
> +		cur_cnid = fd->key->attr.cnid;
> +		search_cnid = fd->search_key->attr.cnid;
> +	} else
> +		BUG();
> +
> +	if (cur_cnid == search_cnid) {
> +		(*end) = (*cur_rec);
> +		if ((*begin) == (*end))
> +			return 1;
> +	} else {
> +		if (be32_to_cpu(cur_cnid) < be32_to_cpu(search_cnid))
> +			(*begin) = (*cur_rec) + 1;
> +		else
> +			(*end) = (*cur_rec) - 1;
> +	}
> +
> +	return 0;
> +}
> +
> +int hfs_find_rec_by_key(struct hfs_bnode *bnode,
> +				struct hfs_find_data *fd,
> +				int *begin,
> +				int *end,
> +				int *cur_rec)
>   {
>   	int cmpval;
> +
> +	cmpval = bnode->tree->keycmp(fd->key, fd->search_key);
> +	if (!cmpval) {
> +		(*end) = (*cur_rec);
> +		return 1;
> +	}
> +	if (cmpval < 0)
> +		(*begin) = (*cur_rec) + 1;
> +	else
> +		*(end) = (*cur_rec) - 1;
> +
> +	return 0;
> +}
> +
> +/* Find the record in bnode that best matches key (not greater than...)*/
> +int __hfs_brec_find(struct hfs_bnode *bnode, struct hfs_find_data *fd,
> +					search_strategy_t rec_found)
> +{
>   	u16 off, len, keylen;
>   	int rec;
>   	int b, e;
>   	int res;
>
> +	if (!rec_found)
> +		BUG();
> +
>   	b = 0;
>   	e = bnode->num_recs - 1;
>   	res = -ENOENT;
> @@ -59,17 +117,12 @@ int __hfs_brec_find(struct hfs_bnode *bnode, struct hfs_find_data *fd)
>   			goto fail;
>   		}
>   		hfs_bnode_read(bnode, fd->key, off, keylen);
> -		cmpval = bnode->tree->keycmp(fd->key, fd->search_key);
> -		if (!cmpval) {
> -			e = rec;
> +		if (rec_found(bnode, fd, &b, &e, &rec)) {
>   			res = 0;
>   			goto done;
>   		}
> -		if (cmpval < 0)
> -			b = rec + 1;
> -		else
> -			e = rec - 1;
>   	} while (b <= e);
> +
>   	if (rec != e && e >= 0) {
>   		len = hfs_brec_lenoff(bnode, e, &off);
>   		keylen = hfs_brec_keylen(bnode, e);
> @@ -79,19 +132,21 @@ int __hfs_brec_find(struct hfs_bnode *bnode, struct hfs_find_data *fd)
>   		}
>   		hfs_bnode_read(bnode, fd->key, off, keylen);
>   	}
> +
>   done:
>   	fd->record = e;
>   	fd->keyoffset = off;
>   	fd->keylength = keylen;
>   	fd->entryoffset = off + keylen;
>   	fd->entrylength = len - keylen;
> +
>   fail:
>   	return res;
>   }
>
>   /* Traverse a B*Tree from the root to a leaf finding best fit to key */
>   /* Return allocated copy of node found, set recnum to best record */
> -int hfs_brec_find(struct hfs_find_data *fd)
> +int hfs_brec_find(struct hfs_find_data *fd, search_strategy_t do_key_compare)
>   {
>   	struct hfs_btree *tree;
>   	struct hfs_bnode *bnode;
> @@ -122,7 +177,7 @@ int hfs_brec_find(struct hfs_find_data *fd)
>   			goto invalid;
>   		bnode->parent = parent;
>
> -		res = __hfs_brec_find(bnode, fd);
> +		res = __hfs_brec_find(bnode, fd, do_key_compare);
>   		if (!height)
>   			break;
>   		if (fd->record < 0)
> @@ -149,7 +204,7 @@ int hfs_brec_read(struct hfs_find_data *fd, void *rec, int rec_len)
>   {
>   	int res;
>
> -	res = hfs_brec_find(fd);
> +	res = hfs_brec_find(fd, hfs_find_rec_by_key);
>   	if (res)
>   		return res;
>   	if (fd->entrylength > rec_len)
> diff --git a/fs/hfsplus/bnode.c b/fs/hfsplus/bnode.c
> index 1c42cc5..5c125ce 100644
> --- a/fs/hfsplus/bnode.c
> +++ b/fs/hfsplus/bnode.c
> @@ -62,7 +62,8 @@ void hfs_bnode_read_key(struct hfs_bnode *node, void *key, int off)
>
>   	tree = node->tree;
>   	if (node->type == HFS_NODE_LEAF ||
> -	    tree->attributes & HFS_TREE_VARIDXKEYS)
> +	    tree->attributes & HFS_TREE_VARIDXKEYS ||
> +	    node->tree->cnid == HFSPLUS_ATTR_CNID)
>   		key_len = hfs_bnode_read_u16(node, off) + 2;
>   	else
>   		key_len = tree->max_key_len + 2;
> @@ -314,7 +315,8 @@ void hfs_bnode_dump(struct hfs_bnode *node)
>   		if (i && node->type == HFS_NODE_INDEX) {
>   			int tmp;
>
> -			if (node->tree->attributes & HFS_TREE_VARIDXKEYS)
> +			if (node->tree->attributes & HFS_TREE_VARIDXKEYS ||
> +					node->tree->cnid == HFSPLUS_ATTR_CNID)
>   				tmp = hfs_bnode_read_u16(node, key_off) + 2;
>   			else
>   				tmp = node->tree->max_key_len + 2;
> diff --git a/fs/hfsplus/brec.c b/fs/hfsplus/brec.c
> index 2a734cf..298d4e4 100644
> --- a/fs/hfsplus/brec.c
> +++ b/fs/hfsplus/brec.c
> @@ -36,7 +36,8 @@ u16 hfs_brec_keylen(struct hfs_bnode *node, u16 rec)
>   		return 0;
>
>   	if ((node->type == HFS_NODE_INDEX) &&
> -	   !(node->tree->attributes & HFS_TREE_VARIDXKEYS)) {
> +	   !(node->tree->attributes & HFS_TREE_VARIDXKEYS) &&
> +	   (node->tree->cnid != HFSPLUS_ATTR_CNID)) {
>   		retval = node->tree->max_key_len + 2;
>   	} else {
>   		recoff = hfs_bnode_read_u16(node,
> @@ -151,12 +152,13 @@ skip:
>
>   		/* get index key */
>   		hfs_bnode_read_key(new_node, fd->search_key, 14);
> -		__hfs_brec_find(fd->bnode, fd);
> +		__hfs_brec_find(fd->bnode, fd, hfs_find_rec_by_key);
>
>   		hfs_bnode_put(new_node);
>   		new_node = NULL;
>
> -		if (tree->attributes & HFS_TREE_VARIDXKEYS)
> +		if ((tree->attributes & HFS_TREE_VARIDXKEYS) ||
> +				(tree->cnid == HFSPLUS_ATTR_CNID))
>   			key_len = be16_to_cpu(fd->search_key->key_len) + 2;
>   		else {
>   			fd->search_key->key_len =
> @@ -201,7 +203,7 @@ again:
>   		hfs_bnode_put(node);
>   		node = fd->bnode = parent;
>
> -		__hfs_brec_find(node, fd);
> +		__hfs_brec_find(node, fd, hfs_find_rec_by_key);
>   		goto again;
>   	}
>   	hfs_bnode_write_u16(node,
> @@ -367,12 +369,13 @@ again:
>   	parent = hfs_bnode_find(tree, node->parent);
>   	if (IS_ERR(parent))
>   		return PTR_ERR(parent);
> -	__hfs_brec_find(parent, fd);
> +	__hfs_brec_find(parent, fd, hfs_find_rec_by_key);
>   	hfs_bnode_dump(parent);
>   	rec = fd->record;
>
>   	/* size difference between old and new key */
> -	if (tree->attributes & HFS_TREE_VARIDXKEYS)
> +	if ((tree->attributes & HFS_TREE_VARIDXKEYS) ||
> +				(tree->cnid == HFSPLUS_ATTR_CNID))
>   		newkeylen = hfs_bnode_read_u16(node, 14) + 2;
>   	else
>   		fd->keylength = newkeylen = tree->max_key_len + 2;
> @@ -427,7 +430,7 @@ skip:
>   		hfs_bnode_read_key(new_node, fd->search_key, 14);
>   		cnid = cpu_to_be32(new_node->this);
>
> -		__hfs_brec_find(fd->bnode, fd);
> +		__hfs_brec_find(fd->bnode, fd, hfs_find_rec_by_key);
>   		hfs_brec_insert(fd, &cnid, sizeof(cnid));
>   		hfs_bnode_put(fd->bnode);
>   		hfs_bnode_put(new_node);
> @@ -495,13 +498,15 @@ static int hfs_btree_inc_height(struct hfs_btree *tree)
>   		/* insert old root idx into new root */
>   		node->parent = tree->root;
>   		if (node->type == HFS_NODE_LEAF ||
> -		    tree->attributes & HFS_TREE_VARIDXKEYS)
> +				tree->attributes & HFS_TREE_VARIDXKEYS ||
> +				tree->cnid == HFSPLUS_ATTR_CNID)
>   			key_size = hfs_bnode_read_u16(node, 14) + 2;
>   		else
>   			key_size = tree->max_key_len + 2;
>   		hfs_bnode_copy(new_node, 14, node, 14, key_size);
>
> -		if (!(tree->attributes & HFS_TREE_VARIDXKEYS)) {
> +		if (!(tree->attributes & HFS_TREE_VARIDXKEYS) &&
> +				(tree->cnid != HFSPLUS_ATTR_CNID)) {
>   			key_size = tree->max_key_len + 2;
>   			hfs_bnode_write_u16(new_node, 14, tree->max_key_len);
>   		}
> diff --git a/fs/hfsplus/btree.c b/fs/hfsplus/btree.c
> index 21023d9..44294af 100644
> --- a/fs/hfsplus/btree.c
> +++ b/fs/hfsplus/btree.c
> @@ -98,6 +98,14 @@ struct hfs_btree *hfs_btree_open(struct super_block *sb, u32 id)
>   			set_bit(HFSPLUS_SB_CASEFOLD, &HFSPLUS_SB(sb)->flags);
>   		}
>   		break;
> +	case HFSPLUS_ATTR_CNID:
> +		if (tree->max_key_len != HFSPLUS_ATTR_KEYLEN - sizeof(u16)) {
> +			printk(KERN_ERR "hfs: invalid attributes max_key_len %d\n",
> +				tree->max_key_len);
> +			goto fail_page;
> +		}
> +		tree->keycmp = hfsplus_attr_bin_cmp_key;
> +		break;
>   	default:
>   		printk(KERN_ERR "hfs: unknown B*Tree requested\n");
>   		goto fail_page;
> diff --git a/fs/hfsplus/catalog.c b/fs/hfsplus/catalog.c
> index ec2a9c2..c285c8d 100644
> --- a/fs/hfsplus/catalog.c
> +++ b/fs/hfsplus/catalog.c
> @@ -45,7 +45,8 @@ void hfsplus_cat_build_key(struct super_block *sb, hfsplus_btree_key *key,
>
>   	key->cat.parent = cpu_to_be32(parent);
>   	if (str) {
> -		hfsplus_asc2uni(sb, &key->cat.name, str->name, str->len);
> +		hfsplus_asc2uni(sb, &key->cat.name, HFSPLUS_MAX_STRLEN,
> +					str->name, str->len);
>   		len = be16_to_cpu(key->cat.name.length);
>   	} else {
>   		key->cat.name.length = 0;
> @@ -167,7 +168,8 @@ static int hfsplus_fill_cat_thread(struct super_block *sb,
>   	entry->type = cpu_to_be16(type);
>   	entry->thread.reserved = 0;
>   	entry->thread.parentID = cpu_to_be32(parentid);
> -	hfsplus_asc2uni(sb, &entry->thread.nodeName, str->name, str->len);
> +	hfsplus_asc2uni(sb, &entry->thread.nodeName, HFSPLUS_MAX_STRLEN,
> +				str->name, str->len);
>   	return 10 + be16_to_cpu(entry->thread.nodeName.length) * 2;
>   }
>
> @@ -198,7 +200,7 @@ int hfsplus_find_cat(struct super_block *sb, u32 cnid,
>   	hfsplus_cat_build_key_uni(fd->search_key,
>   		be32_to_cpu(tmp.thread.parentID),
>   		&tmp.thread.nodeName);
> -	return hfs_brec_find(fd);
> +	return hfs_brec_find(fd, hfs_find_rec_by_key);
>   }
>
>   int hfsplus_create_cat(u32 cnid, struct inode *dir,
> @@ -221,7 +223,7 @@ int hfsplus_create_cat(u32 cnid, struct inode *dir,
>   		S_ISDIR(inode->i_mode) ?
>   			HFSPLUS_FOLDER_THREAD : HFSPLUS_FILE_THREAD,
>   		dir->i_ino, str);
> -	err = hfs_brec_find(&fd);
> +	err = hfs_brec_find(&fd, hfs_find_rec_by_key);
>   	if (err != -ENOENT) {
>   		if (!err)
>   			err = -EEXIST;
> @@ -233,7 +235,7 @@ int hfsplus_create_cat(u32 cnid, struct inode *dir,
>
>   	hfsplus_cat_build_key(sb, fd.search_key, dir->i_ino, str);
>   	entry_size = hfsplus_cat_build_record(&entry, cnid, inode);
> -	err = hfs_brec_find(&fd);
> +	err = hfs_brec_find(&fd, hfs_find_rec_by_key);
>   	if (err != -ENOENT) {
>   		/* panic? */
>   		if (!err)
> @@ -253,7 +255,7 @@ int hfsplus_create_cat(u32 cnid, struct inode *dir,
>
>   err1:
>   	hfsplus_cat_build_key(sb, fd.search_key, cnid, NULL);
> -	if (!hfs_brec_find(&fd))
> +	if (!hfs_brec_find(&fd, hfs_find_rec_by_key))
>   		hfs_brec_remove(&fd);
>   err2:
>   	hfs_find_exit(&fd);
> @@ -279,7 +281,7 @@ int hfsplus_delete_cat(u32 cnid, struct inode *dir, struct qstr *str)
>   		int len;
>
>   		hfsplus_cat_build_key(sb, fd.search_key, cnid, NULL);
> -		err = hfs_brec_find(&fd);
> +		err = hfs_brec_find(&fd, hfs_find_rec_by_key);
>   		if (err)
>   			goto out;
>
> @@ -296,7 +298,7 @@ int hfsplus_delete_cat(u32 cnid, struct inode *dir, struct qstr *str)
>   	} else
>   		hfsplus_cat_build_key(sb, fd.search_key, dir->i_ino, str);
>
> -	err = hfs_brec_find(&fd);
> +	err = hfs_brec_find(&fd, hfs_find_rec_by_key);
>   	if (err)
>   		goto out;
>
> @@ -326,7 +328,7 @@ int hfsplus_delete_cat(u32 cnid, struct inode *dir, struct qstr *str)
>   		goto out;
>
>   	hfsplus_cat_build_key(sb, fd.search_key, cnid, NULL);
> -	err = hfs_brec_find(&fd);
> +	err = hfs_brec_find(&fd, hfs_find_rec_by_key);
>   	if (err)
>   		goto out;
>
> @@ -337,6 +339,12 @@ int hfsplus_delete_cat(u32 cnid, struct inode *dir, struct qstr *str)
>   	dir->i_size--;
>   	dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC;
>   	hfsplus_mark_inode_dirty(dir, HFSPLUS_I_CAT_DIRTY);
> +
> +	if (type == HFSPLUS_FILE || type == HFSPLUS_FOLDER) {
> +		if (HFSPLUS_SB(sb)->attr_tree)
> +			hfsplus_delete_all_attrs(dir, cnid);
> +	}
> +
>   out:
>   	hfs_find_exit(&fd);
>
> @@ -363,7 +371,7 @@ int hfsplus_rename_cat(u32 cnid,
>
>   	/* find the old dir entry and read the data */
>   	hfsplus_cat_build_key(sb, src_fd.search_key, src_dir->i_ino, src_name);
> -	err = hfs_brec_find(&src_fd);
> +	err = hfs_brec_find(&src_fd, hfs_find_rec_by_key);
>   	if (err)
>   		goto out;
>   	if (src_fd.entrylength > sizeof(entry) || src_fd.entrylength < 0) {
> @@ -376,7 +384,7 @@ int hfsplus_rename_cat(u32 cnid,
>
>   	/* create new dir entry with the data from the old entry */
>   	hfsplus_cat_build_key(sb, dst_fd.search_key, dst_dir->i_ino, dst_name);
> -	err = hfs_brec_find(&dst_fd);
> +	err = hfs_brec_find(&dst_fd, hfs_find_rec_by_key);
>   	if (err != -ENOENT) {
>   		if (!err)
>   			err = -EEXIST;
> @@ -391,7 +399,7 @@ int hfsplus_rename_cat(u32 cnid,
>
>   	/* finally remove the old entry */
>   	hfsplus_cat_build_key(sb, src_fd.search_key, src_dir->i_ino, src_name);
> -	err = hfs_brec_find(&src_fd);
> +	err = hfs_brec_find(&src_fd, hfs_find_rec_by_key);
>   	if (err)
>   		goto out;
>   	err = hfs_brec_remove(&src_fd);
> @@ -402,7 +410,7 @@ int hfsplus_rename_cat(u32 cnid,
>
>   	/* remove old thread entry */
>   	hfsplus_cat_build_key(sb, src_fd.search_key, cnid, NULL);
> -	err = hfs_brec_find(&src_fd);
> +	err = hfs_brec_find(&src_fd, hfs_find_rec_by_key);
>   	if (err)
>   		goto out;
>   	type = hfs_bnode_read_u16(src_fd.bnode, src_fd.entryoffset);
> @@ -414,7 +422,7 @@ int hfsplus_rename_cat(u32 cnid,
>   	hfsplus_cat_build_key(sb, dst_fd.search_key, cnid, NULL);
>   	entry_size = hfsplus_fill_cat_thread(sb, &entry, type,
>   		dst_dir->i_ino, dst_name);
> -	err = hfs_brec_find(&dst_fd);
> +	err = hfs_brec_find(&dst_fd, hfs_find_rec_by_key);
>   	if (err != -ENOENT) {
>   		if (!err)
>   			err = -EEXIST;
> diff --git a/fs/hfsplus/dir.c b/fs/hfsplus/dir.c
> index 6b9f921..ededee4 100644
> --- a/fs/hfsplus/dir.c
> +++ b/fs/hfsplus/dir.c
> @@ -138,7 +138,7 @@ static int hfsplus_readdir(struct file *filp, void *dirent, filldir_t filldir)
>   	if (err)
>   		return err;
>   	hfsplus_cat_build_key(sb, fd.search_key, inode->i_ino, NULL);
> -	err = hfs_brec_find(&fd);
> +	err = hfs_brec_find(&fd, hfs_find_rec_by_key);
>   	if (err)
>   		goto out;
>
> @@ -499,15 +499,19 @@ static int hfsplus_rename(struct inode *old_dir, struct dentry *old_dentry,
>   }
>
>   const struct inode_operations hfsplus_dir_inode_operations = {
> -	.lookup		= hfsplus_lookup,
> -	.create		= hfsplus_create,
> -	.link		= hfsplus_link,
> -	.unlink		= hfsplus_unlink,
> -	.mkdir		= hfsplus_mkdir,
> -	.rmdir		= hfsplus_rmdir,
> -	.symlink	= hfsplus_symlink,
> -	.mknod		= hfsplus_mknod,
> -	.rename		= hfsplus_rename,
> +	.lookup			= hfsplus_lookup,
> +	.create			= hfsplus_create,
> +	.link			= hfsplus_link,
> +	.unlink			= hfsplus_unlink,
> +	.mkdir			= hfsplus_mkdir,
> +	.rmdir			= hfsplus_rmdir,
> +	.symlink		= hfsplus_symlink,
> +	.mknod			= hfsplus_mknod,
> +	.rename			= hfsplus_rename,
> +	.setxattr		= hfsplus_setxattr,
> +	.getxattr		= hfsplus_getxattr,
> +	.listxattr		= hfsplus_listxattr,
> +	.removexattr	= hfsplus_removexattr,
>   };
>
>   const struct file_operations hfsplus_dir_operations = {
> diff --git a/fs/hfsplus/extents.c b/fs/hfsplus/extents.c
> index 5849e3e..87e59e9 100644
> --- a/fs/hfsplus/extents.c
> +++ b/fs/hfsplus/extents.c
> @@ -95,7 +95,7 @@ static void __hfsplus_ext_write_extent(struct inode *inode,
>   			      HFSPLUS_IS_RSRC(inode) ?
>   				HFSPLUS_TYPE_RSRC : HFSPLUS_TYPE_DATA);
>
> -	res = hfs_brec_find(fd);
> +	res = hfs_brec_find(fd, hfs_find_rec_by_key);
>   	if (hip->extent_state & HFSPLUS_EXT_NEW) {
>   		if (res != -ENOENT)
>   			return;
> @@ -154,7 +154,7 @@ static inline int __hfsplus_ext_read_extent(struct hfs_find_data *fd,
>
>   	hfsplus_ext_build_key(fd->search_key, cnid, block, type);
>   	fd->key->ext.cnid = 0;
> -	res = hfs_brec_find(fd);
> +	res = hfs_brec_find(fd, hfs_find_rec_by_key);
>   	if (res && res != -ENOENT)
>   		return res;
>   	if (fd->key->ext.cnid != fd->search_key->ext.cnid ||
> diff --git a/fs/hfsplus/hfsplus_fs.h b/fs/hfsplus/hfsplus_fs.h
> index 558dbb4..03ed580 100644
> --- a/fs/hfsplus/hfsplus_fs.h
> +++ b/fs/hfsplus/hfsplus_fs.h
> @@ -23,6 +23,7 @@
>   #define DBG_SUPER	0x00000010
>   #define DBG_EXTENT	0x00000020
>   #define DBG_BITMAP	0x00000040
> +#define DBG_ATTR_MOD	0x00000080
>
>   #if 0
>   #define DBG_MASK	(DBG_EXTENT|DBG_INODE|DBG_BNODE_MOD)
> @@ -223,6 +224,7 @@ struct hfsplus_inode_info {
>   #define HFSPLUS_I_CAT_DIRTY	1	/* has changes in the catalog tree */
>   #define HFSPLUS_I_EXT_DIRTY	2	/* has changes in the extent tree */
>   #define HFSPLUS_I_ALLOC_DIRTY	3	/* has changes in the allocation file */
> +#define HFSPLUS_I_ATTR_DIRTY	4	/* has changes in the attributes tree */
>
>   #define HFSPLUS_IS_RSRC(inode) \
>   	test_bit(HFSPLUS_I_RSRC, &HFSPLUS_I(inode)->flags)
> @@ -302,7 +304,7 @@ static inline unsigned short hfsplus_min_io_size(struct super_block *sb)
>   #define hfs_brec_remove hfsplus_brec_remove
>   #define hfs_find_init hfsplus_find_init
>   #define hfs_find_exit hfsplus_find_exit
> -#define __hfs_brec_find __hplusfs_brec_find
> +#define __hfs_brec_find __hfsplus_brec_find
>   #define hfs_brec_find hfsplus_brec_find
>   #define hfs_brec_read hfsplus_brec_read
>   #define hfs_brec_goto hfsplus_brec_goto
> @@ -324,10 +326,33 @@ static inline unsigned short hfsplus_min_io_size(struct super_block *sb)
>    */
>   #define HFSPLUS_IOC_BLESS _IO('h', 0x80)
>
> +typedef int (*search_strategy_t)(struct hfs_bnode *,
> +				struct hfs_find_data *,
> +				int *, int *, int *);
> +
>   /*
>    * Functions in any *.c used in other files
>    */
>
> +/* attributes.c */
> +int hfsplus_create_attr_tree_cache(void);
> +void hfsplus_destroy_attr_tree_cache(void);
> +hfsplus_attr_entry *hfsplus_alloc_attr_entry(void);
> +void hfsplus_destroy_attr_entry(hfsplus_attr_entry *entry_p);
> +int hfsplus_attr_bin_cmp_key(const hfsplus_btree_key *,
> +		const hfsplus_btree_key *);
> +int hfsplus_attr_build_key(struct super_block *, hfsplus_btree_key *,
> +			u32, const char *);
> +void hfsplus_attr_build_key_uni(hfsplus_btree_key *key,
> +					u32 cnid,
> +					struct hfsplus_attr_unistr *name);
> +int hfsplus_find_attr(struct super_block *, u32,
> +			const char *, struct hfs_find_data *);
> +int hfsplus_attr_exists(struct inode *inode, const char *name);
> +int hfsplus_create_attr(struct inode *, const char *, const void *, size_t);
> +int hfsplus_delete_attr(struct inode *, const char *);
> +int hfsplus_delete_all_attrs(struct inode *dir, u32 cnid);
> +
>   /* bitmap.c */
>   int hfsplus_block_allocate(struct super_block *, u32, u32, u32 *);
>   int hfsplus_block_free(struct super_block *, u32, u32);
> @@ -369,8 +394,15 @@ int hfs_brec_remove(struct hfs_find_data *);
>   /* bfind.c */
>   int hfs_find_init(struct hfs_btree *, struct hfs_find_data *);
>   void hfs_find_exit(struct hfs_find_data *);
> -int __hfs_brec_find(struct hfs_bnode *, struct hfs_find_data *);
> -int hfs_brec_find(struct hfs_find_data *);
> +int hfs_find_1st_rec_by_cnid(struct hfs_bnode *,
> +				struct hfs_find_data *,
> +				int *, int *, int *);
> +int hfs_find_rec_by_key(struct hfs_bnode *,
> +				struct hfs_find_data *,
> +				int *, int *, int *);
> +int __hfs_brec_find(struct hfs_bnode *, struct hfs_find_data *,
> +				search_strategy_t);
> +int hfs_brec_find(struct hfs_find_data *, search_strategy_t);
>   int hfs_brec_read(struct hfs_find_data *, void *, int);
>   int hfs_brec_goto(struct hfs_find_data *, int);
>
> @@ -422,6 +454,7 @@ int hfsplus_setxattr(struct dentry *dentry, const char *name,
>   ssize_t hfsplus_getxattr(struct dentry *dentry, const char *name,
>   			 void *value, size_t size);
>   ssize_t hfsplus_listxattr(struct dentry *dentry, char *buffer, size_t size);
> +int hfsplus_removexattr(struct dentry *dentry, const char *name);
>
>   /* options.c */
>   int hfsplus_parse_options(char *, struct hfsplus_sb_info *);
> @@ -446,7 +479,7 @@ int hfsplus_strcmp(const struct hfsplus_unistr *,
>   int hfsplus_uni2asc(struct super_block *,
>   		const struct hfsplus_unistr *, char *, int *);
>   int hfsplus_asc2uni(struct super_block *,
> -		struct hfsplus_unistr *, const char *, int);
> +		struct hfsplus_unistr *, int, const char *, int);
>   int hfsplus_hash_dentry(const struct dentry *dentry,
>   		const struct inode *inode, struct qstr *str);
>   int hfsplus_compare_dentry(const struct dentry *parent,
> diff --git a/fs/hfsplus/inode.c b/fs/hfsplus/inode.c
> index 3d8b4a6..98a6210 100644
> --- a/fs/hfsplus/inode.c
> +++ b/fs/hfsplus/inode.c
> @@ -342,6 +342,18 @@ int hfsplus_file_fsync(struct file *file, loff_t start, loff_t end,
>   			error = error2;
>   	}
>
> +	if (test_and_clear_bit(HFSPLUS_I_ATTR_DIRTY, &hip->flags)) {
> +		if (sbi->attr_tree) {
> +			error2 =
> +				filemap_write_and_wait(
> +					    sbi->attr_tree->inode->i_mapping);
> +			if (!error)
> +				error = error2;
> +		} else {
> +			printk(KERN_ERR "hfs: sync non-existent attributes tree\n");
> +		}
> +	}
> +
>   	if (test_and_clear_bit(HFSPLUS_I_ALLOC_DIRTY, &hip->flags)) {
>   		error2 = filemap_write_and_wait(sbi->alloc_file->i_mapping);
>   		if (!error)
> @@ -363,6 +375,7 @@ static const struct inode_operations hfsplus_file_inode_operations = {
>   	.setxattr	= hfsplus_setxattr,
>   	.getxattr	= hfsplus_getxattr,
>   	.listxattr	= hfsplus_listxattr,
> +	.removexattr	= hfsplus_removexattr,
>   };
>
>   static const struct file_operations hfsplus_file_operations = {
> diff --git a/fs/hfsplus/super.c b/fs/hfsplus/super.c
> index 811a84d..250b695 100644
> --- a/fs/hfsplus/super.c
> +++ b/fs/hfsplus/super.c
> @@ -118,6 +118,7 @@ static int hfsplus_system_write_inode(struct inode *inode)
>   	case HFSPLUS_ATTR_CNID:
>   		fork = &vhdr->attr_file;
>   		tree = sbi->attr_tree;
> +		break;
>   	default:
>   		return -EIO;
>   	}
> @@ -185,6 +186,12 @@ static int hfsplus_sync_fs(struct super_block *sb, int wait)
>   	error2 = filemap_write_and_wait(sbi->ext_tree->inode->i_mapping);
>   	if (!error)
>   		error = error2;
> +	if (sbi->attr_tree) {
> +		error2 =
> +		    filemap_write_and_wait(sbi->attr_tree->inode->i_mapping);
> +		if (!error)
> +			error = error2;
> +	}
>   	error2 = filemap_write_and_wait(sbi->alloc_file->i_mapping);
>   	if (!error)
>   		error = error2;
> @@ -272,6 +279,7 @@ static void hfsplus_put_super(struct super_block *sb)
>   		hfsplus_sync_fs(sb, 1);
>   	}
>
> +	hfs_btree_close(sbi->attr_tree);
>   	hfs_btree_close(sbi->cat_tree);
>   	hfs_btree_close(sbi->ext_tree);
>   	iput(sbi->alloc_file);
> @@ -468,12 +476,19 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent)
>   		printk(KERN_ERR "hfs: failed to load catalog file\n");
>   		goto out_close_ext_tree;
>   	}
> +	if (vhdr->attr_file.total_blocks != 0) {
> +		sbi->attr_tree = hfs_btree_open(sb, HFSPLUS_ATTR_CNID);
> +		if (!sbi->attr_tree) {
> +			printk(KERN_ERR "hfs: failed to load attributes file\n");
> +			goto out_close_cat_tree;
> +		}
> +	}
>
>   	inode = hfsplus_iget(sb, HFSPLUS_ALLOC_CNID);
>   	if (IS_ERR(inode)) {
>   		printk(KERN_ERR "hfs: failed to load allocation file\n");
>   		err = PTR_ERR(inode);
> -		goto out_close_cat_tree;
> +		goto out_close_attr_tree;
>   	}
>   	sbi->alloc_file = inode;
>
> @@ -553,6 +568,8 @@ out_put_root:
>   	sb->s_root = NULL;
>   out_put_alloc_file:
>   	iput(sbi->alloc_file);
> +out_close_attr_tree:
> +	hfs_btree_close(sbi->attr_tree);
>   out_close_cat_tree:
>   	hfs_btree_close(sbi->cat_tree);
>   out_close_ext_tree:
> @@ -626,9 +643,23 @@ static int __init init_hfsplus_fs(void)
>   		hfsplus_init_once);
>   	if (!hfsplus_inode_cachep)
>   		return -ENOMEM;
> +
> +	err = hfsplus_create_attr_tree_cache();
> +	if (err)
> +		goto destroy_inode_cache;
> +
>   	err = register_filesystem(&hfsplus_fs_type);
>   	if (err)
> -		kmem_cache_destroy(hfsplus_inode_cachep);
> +		goto destroy_attr_tree_cache;
> +
> +	return 0;
> +
> +destroy_attr_tree_cache:
> +	hfsplus_destroy_attr_tree_cache();
> +
> +destroy_inode_cache:
> +	kmem_cache_destroy(hfsplus_inode_cachep);
> +
>   	return err;
>   }
>
> @@ -641,6 +672,7 @@ static void __exit exit_hfsplus_fs(void)
>   	 * destroy cache.
>   	 */
>   	rcu_barrier();
> +	hfsplus_destroy_attr_tree_cache();
>   	kmem_cache_destroy(hfsplus_inode_cachep);
>   }
>
> diff --git a/fs/hfsplus/unicode.c b/fs/hfsplus/unicode.c
> index a32998f..2c2e47d 100644
> --- a/fs/hfsplus/unicode.c
> +++ b/fs/hfsplus/unicode.c
> @@ -295,7 +295,8 @@ static inline u16 *decompose_unichar(wchar_t uc, int *size)
>   	return hfsplus_decompose_table + (off / 4);
>   }
>
> -int hfsplus_asc2uni(struct super_block *sb, struct hfsplus_unistr *ustr,
> +int hfsplus_asc2uni(struct super_block *sb,
> +		    struct hfsplus_unistr *ustr, int max_unistr_len,
>   		    const char *astr, int len)
>   {
>   	int size, dsize, decompose;
> @@ -303,7 +304,7 @@ int hfsplus_asc2uni(struct super_block *sb, struct hfsplus_unistr *ustr,
>   	wchar_t c;
>
>   	decompose = !test_bit(HFSPLUS_SB_NODECOMPOSE, &HFSPLUS_SB(sb)->flags);
> -	while (outlen < HFSPLUS_MAX_STRLEN && len > 0) {
> +	while (outlen < max_unistr_len && len > 0) {
>   		size = asc2unichar(sb, astr, len, &c);
>
>   		if (decompose)
> @@ -311,7 +312,7 @@ int hfsplus_asc2uni(struct super_block *sb, struct hfsplus_unistr *ustr,
>   		else
>   			dstr = NULL;
>   		if (dstr) {
> -			if (outlen + dsize > HFSPLUS_MAX_STRLEN)
> +			if (outlen + dsize > max_unistr_len)
>   				break;
>   			do {
>   				ustr->unicode[outlen++] = cpu_to_be16(*dstr++);
>

  reply	other threads:[~2012-09-15  0:17 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-08-20 19:06 [PATCH 4/4] hfsplus: add support of manipulation by attributes file Vyacheslav Dubeyko
2012-09-15  0:11 ` Hin-Tak Leung [this message]
2012-09-15 10:12   ` Vyacheslav Dubeyko
2012-09-15 13:36   ` Vyacheslav Dubeyko
2012-09-15 16:49     ` Hin-Tak Leung
2012-09-16 20:04       ` Vyacheslav Dubeyko
2012-09-17 19:23       ` Vyacheslav Dubeyko
2012-09-17 19:52         ` Hin-Tak Leung
2012-09-17 20:00           ` Vyacheslav Dubeyko
2012-09-17 20:09             ` Hin-Tak Leung

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=5053C7C6.5080800@users.sourceforge.net \
    --to=htl10@users.sourceforge.net \
    --cc=linux-fsdevel@vger.kernel.org \
    --cc=slava@dubeyko.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.