linux-fsdevel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 4/4] hfsplus: add support of manipulation by attributes file
@ 2012-08-20 19:06 Vyacheslav Dubeyko
  2012-09-15  0:11 ` Hin-Tak Leung
  0 siblings, 1 reply; 10+ messages in thread
From: Vyacheslav Dubeyko @ 2012-08-20 19:06 UTC (permalink / raw)
  To: linux-fsdevel; +Cc: Hin-Tak Leung

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>
---
 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++);
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [PATCH 4/4] hfsplus: add support of manipulation by attributes file
  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
  2012-09-15 10:12   ` Vyacheslav Dubeyko
  2012-09-15 13:36   ` Vyacheslav Dubeyko
  0 siblings, 2 replies; 10+ messages in thread
From: Hin-Tak Leung @ 2012-09-15  0:11 UTC (permalink / raw)
  To: Vyacheslav Dubeyko; +Cc: linux-fsdevel

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++);
>

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 4/4] hfsplus: add support of manipulation by attributes file
  2012-09-15  0:11 ` Hin-Tak Leung
@ 2012-09-15 10:12   ` Vyacheslav Dubeyko
  2012-09-15 13:36   ` Vyacheslav Dubeyko
  1 sibling, 0 replies; 10+ messages in thread
From: Vyacheslav Dubeyko @ 2012-09-15 10:12 UTC (permalink / raw)
  To: Hin-Tak Leung; +Cc: linux-fsdevel

Hi,

On Sep 15, 2012, at 4:11 AM, Hin-Tak Leung wrote:

> 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.


Could you share kernel version that you are using?

What utility do you use for getting of extended attributes list? I need more details for issue reproduction.

Could you share some more detailed output of system log related to the issue?

Thanks,
Vyacheslav Dubeyko.


>> ---
>>  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++);
>> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 4/4] hfsplus: add support of manipulation by attributes file
  2012-09-15  0:11 ` Hin-Tak Leung
  2012-09-15 10:12   ` Vyacheslav Dubeyko
@ 2012-09-15 13:36   ` Vyacheslav Dubeyko
  2012-09-15 16:49     ` Hin-Tak Leung
  1 sibling, 1 reply; 10+ messages in thread
From: Vyacheslav Dubeyko @ 2012-09-15 13:36 UTC (permalink / raw)
  To: Hin-Tak Leung; +Cc: linux-fsdevel

Hi Hin-Tak,

On Sep 15, 2012, at 4:11 AM, Hin-Tak Leung wrote:

> 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.
> 

By the way, do you really confident that any file in your /System/Library/Fonts folder have any extended attribute?

On my Mac none file in /System/Library/Fonts folder has any extended attribute. Could you check presence on extended attributes under Mac OS X by means of `xattr -l` command?

With the best regards,
Vyacheslav Dubeyko.


>> ---
>>  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++);
>> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 4/4] hfsplus: add support of manipulation by attributes file
  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
  0 siblings, 2 replies; 10+ messages in thread
From: Hin-Tak Leung @ 2012-09-15 16:49 UTC (permalink / raw)
  To: Vyacheslav Dubeyko; +Cc: linux-fsdevel

--- On Sat, 15/9/12, Vyacheslav Dubeyko <slava@dubeyko.com> wrote:

> Hi Hin-Tak,
> 
> On Sep 15, 2012, at 4:11 AM, Hin-Tak Leung wrote:
> 
> > 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.
> > 
> 
> By the way, do you really confident that any file in your
> /System/Library/Fonts folder have any extended attribute?
> 
> On my Mac none file in /System/Library/Fonts folder has any
> extended attribute. Could you check presence on extended
> attributes under Mac OS X by means of `xattr -l` command?
> 
> With the best regards,
> Vyacheslav Dubeyko.

Sorry, that was a bit brief - I just have access to a Mac OS X 10.7 box from time to time.

- There are 4 font suitecase files, which shows up to have file size zero under linux, but not on Mac OS X. I formatted the thumb drive under Mac Os X and copied with Finder, but of course it might be something I don't understand in the process.

- get a lot of "hfs: xattr searching failed" (about 20-ish per command) when I run getfattr on linux.

- It is a bit confusing apple talking about resource forks and extended attributes as if they are they same thing.

As an aside, one of the older experients, shows it to a few files with  extended attributes "com.apple.decmpfs". I looked it up, apple use this atttribute to implement per-file compression - hiding the file content compressed in the attribute while having the data fork zero. (different and unrelated to the font issue). This happens on mac os X 10.6 onwards.

--- On Sat, 15/9/12, Vyacheslav Dubeyko <slava@dubeyko.com> wrote:

> Hi,
> 
> On Sep 15, 2012, at 4:11 AM, Hin-Tak Leung wrote:
> 
> > 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.
> 
> 
> Could you share kernel version that you are using?
> 
> What utility do you use for getting of extended attributes
> list? I need more details for issue reproduction.
> 
> Could you share some more detailed output of system log
> related to the issue?

I patched over 3.5.3 with just the 4 patches.

I also have some messy scripts based on work from the iphone hackery people to look at details at the low-level.

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 4/4] hfsplus: add support of manipulation by attributes file
  2012-09-15 16:49     ` Hin-Tak Leung
@ 2012-09-16 20:04       ` Vyacheslav Dubeyko
  2012-09-17 19:23       ` Vyacheslav Dubeyko
  1 sibling, 0 replies; 10+ messages in thread
From: Vyacheslav Dubeyko @ 2012-09-16 20:04 UTC (permalink / raw)
  To: htl10; +Cc: linux-fsdevel

Hi,

I have merged extended attributes support code into hfsplus fs driver code of 3.5.4 Linux kernel. And I checked working of this code by means of getfattr and setfattr utilities. Really, getfattr doesn't output the list of extended attributes for a file. But I can't see any warnings in system log in my case. Moreover, I can get extended attribute content by name with getfattr and create extended attribute by means of setfattr successfully.

Did you have any troubles during kernel patching or any warnings during kernel compilation? Maybe your issue is a side effect of not proper patching or my patch set is not prepared properly. I am going to make patching of 3.5.3 kernel for checking this presupposition.

Could you try to check working of getting extended attribute by name? The good way for it can be creation of some file, then, creation of simple extended attribute with some name (setfattr) and trying to get content of extended attribute by name (getfattr). It is strange that you see many warnings in your system log. But maybe operation of getting extended attribute by name will end with success. Could you check it on your side?

I used xattr (dev-python/pyxattr) utility during implementation. All operation (create, get, delete) with extended attributes are working successfully on my side. Currently, I found that xattr utility can output full list of file's extended attributes but getfattr can't. I am going to investigate this issue.  

Moreover, maybe extended attributes "com.apple.decmpfs" has some peculiarities. It needs to investigate it. So, I think that it needs to check functionality on simple use case, firstly.

With the best regards,
Vyacheslav Dubeyko.

On Sep 15, 2012, at 8:49 PM, Hin-Tak Leung wrote:

> --- On Sat, 15/9/12, Vyacheslav Dubeyko <slava@dubeyko.com> wrote:
> 
>> Hi Hin-Tak,
>> 
>> On Sep 15, 2012, at 4:11 AM, Hin-Tak Leung wrote:
>> 
>>> 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.
>>> 
>> 
>> By the way, do you really confident that any file in your
>> /System/Library/Fonts folder have any extended attribute?
>> 
>> On my Mac none file in /System/Library/Fonts folder has any
>> extended attribute. Could you check presence on extended
>> attributes under Mac OS X by means of `xattr -l` command?
>> 
>> With the best regards,
>> Vyacheslav Dubeyko.
> 
> Sorry, that was a bit brief - I just have access to a Mac OS X 10.7 box from time to time.
> 
> - There are 4 font suitecase files, which shows up to have file size zero under linux, but not on Mac OS X. I formatted the thumb drive under Mac Os X and copied with Finder, but of course it might be something I don't understand in the process.
> 
> - get a lot of "hfs: xattr searching failed" (about 20-ish per command) when I run getfattr on linux.
> 
> - It is a bit confusing apple talking about resource forks and extended attributes as if they are they same thing.
> 
> As an aside, one of the older experients, shows it to a few files with  extended attributes "com.apple.decmpfs". I looked it up, apple use this atttribute to implement per-file compression - hiding the file content compressed in the attribute while having the data fork zero. (different and unrelated to the font issue). This happens on mac os X 10.6 onwards.
> 
> --- On Sat, 15/9/12, Vyacheslav Dubeyko <slava@dubeyko.com> wrote:
> 
>> Hi,
>> 
>> On Sep 15, 2012, at 4:11 AM, Hin-Tak Leung wrote:
>> 
>>> 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.
>> 
>> 
>> Could you share kernel version that you are using?
>> 
>> What utility do you use for getting of extended attributes
>> list? I need more details for issue reproduction.
>> 
>> Could you share some more detailed output of system log
>> related to the issue?
> 
> I patched over 3.5.3 with just the 4 patches.
> 
> I also have some messy scripts based on work from the iphone hackery people to look at details at the low-level.
> --
> To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 4/4] hfsplus: add support of manipulation by attributes file
  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
  1 sibling, 1 reply; 10+ messages in thread
From: Vyacheslav Dubeyko @ 2012-09-17 19:23 UTC (permalink / raw)
  To: htl10; +Cc: linux-fsdevel

Hi Hin-Tak,

Now I understand clearly the reason of your issue. This is a side effect of not clean patching of your kernel (3.5.3). I worked with 3.4.6 kernel during implementation and I didn't take into account some changing of hfsplus fs driver in next kernel versions during patch set preparation. The 3.5.3 kernel has changing in super.c file that can't be merged automatically with my patch set. So, if you applied patch set by means of git then super.c file was left unchanged. But patch for super.c contains very important changing which to build attributes tree during file system mount and to destroy ones during umount. Thereby, you have warnings about failed searching in system log because of absence constructed attributes tree in memory.

Currently, I am investigating issue with getting list of attributes by means of getfattr. I am going to prepare new patch set based under last actual kernel version after issue resolving.

With the best regards,
Vyacheslav Dubeyko.

On Sep 15, 2012, at 8:49 PM, Hin-Tak Leung wrote:

> --- On Sat, 15/9/12, Vyacheslav Dubeyko <slava@dubeyko.com> wrote:
> 
>> Hi Hin-Tak,
>> 
>> On Sep 15, 2012, at 4:11 AM, Hin-Tak Leung wrote:
>> 
>>> 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.
>>> 
>> 
>> By the way, do you really confident that any file in your
>> /System/Library/Fonts folder have any extended attribute?
>> 
>> On my Mac none file in /System/Library/Fonts folder has any
>> extended attribute. Could you check presence on extended
>> attributes under Mac OS X by means of `xattr -l` command?
>> 
>> With the best regards,
>> Vyacheslav Dubeyko.
> 
> Sorry, that was a bit brief - I just have access to a Mac OS X 10.7 box from time to time.
> 
> - There are 4 font suitecase files, which shows up to have file size zero under linux, but not on Mac OS X. I formatted the thumb drive under Mac Os X and copied with Finder, but of course it might be something I don't understand in the process.
> 
> - get a lot of "hfs: xattr searching failed" (about 20-ish per command) when I run getfattr on linux.
> 
> - It is a bit confusing apple talking about resource forks and extended attributes as if they are they same thing.
> 
> As an aside, one of the older experients, shows it to a few files with  extended attributes "com.apple.decmpfs". I looked it up, apple use this atttribute to implement per-file compression - hiding the file content compressed in the attribute while having the data fork zero. (different and unrelated to the font issue). This happens on mac os X 10.6 onwards.
> 
> --- On Sat, 15/9/12, Vyacheslav Dubeyko <slava@dubeyko.com> wrote:
> 
>> Hi,
>> 
>> On Sep 15, 2012, at 4:11 AM, Hin-Tak Leung wrote:
>> 
>>> 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.
>> 
>> 
>> Could you share kernel version that you are using?
>> 
>> What utility do you use for getting of extended attributes
>> list? I need more details for issue reproduction.
>> 
>> Could you share some more detailed output of system log
>> related to the issue?
> 
> I patched over 3.5.3 with just the 4 patches.
> 
> I also have some messy scripts based on work from the iphone hackery people to look at details at the low-level.
> --
> To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 4/4] hfsplus: add support of manipulation by attributes file
  2012-09-17 19:23       ` Vyacheslav Dubeyko
@ 2012-09-17 19:52         ` Hin-Tak Leung
  2012-09-17 20:00           ` Vyacheslav Dubeyko
  0 siblings, 1 reply; 10+ messages in thread
From: Hin-Tak Leung @ 2012-09-17 19:52 UTC (permalink / raw)
  To: Vyacheslav Dubeyko; +Cc: linux-fsdevel

Oh, yes, there was a small conflict at the end of super.c when I applied to 3.5.3:

---------------
@@ -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);
 }
 
----------------

3.5.3 does not have the "rcu_barrier();" line for whatever reason - since the chunk seem to mean 'put  "hfsplus_destroy_attr_tree_cache();" towards the end of __exit exit_hfsplus_fs() just before the last line', that's what I did.

But as far as I remember that was the only conflict - that does not sound like what you describe though...

Hin-Tak

--- On Mon, 17/9/12, Vyacheslav Dubeyko <slava@dubeyko.com> wrote:

> Hi Hin-Tak,
> 
> Now I understand clearly the reason of your issue. This is a
> side effect of not clean patching of your kernel (3.5.3). I
> worked with 3.4.6 kernel during implementation and I didn't
> take into account some changing of hfsplus fs driver in next
> kernel versions during patch set preparation. The 3.5.3
> kernel has changing in super.c file that can't be merged
> automatically with my patch set. So, if you applied patch
> set by means of git then super.c file was left unchanged.
> But patch for super.c contains very important changing which
> to build attributes tree during file system mount and to
> destroy ones during umount. Thereby, you have warnings about
> failed searching in system log because of absence
> constructed attributes tree in memory.
> 
> Currently, I am investigating issue with getting list of
> attributes by means of getfattr. I am going to prepare new
> patch set based under last actual kernel version after issue
> resolving.
> 
> With the best regards,
> Vyacheslav Dubeyko.
> 
> On Sep 15, 2012, at 8:49 PM, Hin-Tak Leung wrote:
> 
> > --- On Sat, 15/9/12, Vyacheslav Dubeyko <slava@dubeyko.com>
> wrote:
> > 
> >> Hi Hin-Tak,
> >> 
> >> On Sep 15, 2012, at 4:11 AM, Hin-Tak Leung wrote:
> >> 
> >>> 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.
> >>> 
> >> 
> >> By the way, do you really confident that any file
> in your
> >> /System/Library/Fonts folder have any extended
> attribute?
> >> 
> >> On my Mac none file in /System/Library/Fonts folder
> has any
> >> extended attribute. Could you check presence on
> extended
> >> attributes under Mac OS X by means of `xattr -l`
> command?
> >> 
> >> With the best regards,
> >> Vyacheslav Dubeyko.
> > 
> > Sorry, that was a bit brief - I just have access to a
> Mac OS X 10.7 box from time to time.
> > 
> > - There are 4 font suitecase files, which shows up to
> have file size zero under linux, but not on Mac OS X. I
> formatted the thumb drive under Mac Os X and copied with
> Finder, but of course it might be something I don't
> understand in the process.
> > 
> > - get a lot of "hfs: xattr searching failed" (about
> 20-ish per command) when I run getfattr on linux.
> > 
> > - It is a bit confusing apple talking about resource
> forks and extended attributes as if they are they same
> thing.
> > 
> > As an aside, one of the older experients, shows it to a
> few files with  extended attributes
> "com.apple.decmpfs". I looked it up, apple use this
> atttribute to implement per-file compression - hiding the
> file content compressed in the attribute while having the
> data fork zero. (different and unrelated to the font issue).
> This happens on mac os X 10.6 onwards.
> > 
> > --- On Sat, 15/9/12, Vyacheslav Dubeyko <slava@dubeyko.com>
> wrote:
> > 
> >> Hi,
> >> 
> >> On Sep 15, 2012, at 4:11 AM, Hin-Tak Leung wrote:
> >> 
> >>> 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.
> >> 
> >> 
> >> Could you share kernel version that you are using?
> >> 
> >> What utility do you use for getting of extended
> attributes
> >> list? I need more details for issue reproduction.
> >> 
> >> Could you share some more detailed output of system
> log
> >> related to the issue?
> > 
> > I patched over 3.5.3 with just the 4 patches.
> > 
> > I also have some messy scripts based on work from the
> iphone hackery people to look at details at the low-level.
> > --
> > To unsubscribe from this list: send the line
> "unsubscribe linux-fsdevel" in
> > the body of a message to majordomo@vger.kernel.org
> > More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 
> 
--
To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 4/4] hfsplus: add support of manipulation by attributes file
  2012-09-17 19:52         ` Hin-Tak Leung
@ 2012-09-17 20:00           ` Vyacheslav Dubeyko
  2012-09-17 20:09             ` Hin-Tak Leung
  0 siblings, 1 reply; 10+ messages in thread
From: Vyacheslav Dubeyko @ 2012-09-17 20:00 UTC (permalink / raw)
  To: htl10; +Cc: linux-fsdevel

Hi,

On Sep 17, 2012, at 11:52 PM, Hin-Tak Leung wrote:

> Oh, yes, there was a small conflict at the end of super.c when I applied to 3.5.3:
> 
> ---------------
> @@ -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);
> }
> 
> ----------------
> 
> 3.5.3 does not have the "rcu_barrier();" line for whatever reason - since the chunk seem to mean 'put  "hfsplus_destroy_attr_tree_cache();" towards the end of __exit exit_hfsplus_fs() just before the last line', that's what I did.
> 
> But as far as I remember that was the only conflict - that does not sound like what you describe though...

Did you apply patch set by means of git or patch utility?

With the best regards,
Vyacheslav Dubeyko.

> 
> Hin-Tak
> 
> --- On Mon, 17/9/12, Vyacheslav Dubeyko <slava@dubeyko.com> wrote:
> 
>> Hi Hin-Tak,
>> 
>> Now I understand clearly the reason of your issue. This is a
>> side effect of not clean patching of your kernel (3.5.3). I
>> worked with 3.4.6 kernel during implementation and I didn't
>> take into account some changing of hfsplus fs driver in next
>> kernel versions during patch set preparation. The 3.5.3
>> kernel has changing in super.c file that can't be merged
>> automatically with my patch set. So, if you applied patch
>> set by means of git then super.c file was left unchanged.
>> But patch for super.c contains very important changing which
>> to build attributes tree during file system mount and to
>> destroy ones during umount. Thereby, you have warnings about
>> failed searching in system log because of absence
>> constructed attributes tree in memory.
>> 
>> Currently, I am investigating issue with getting list of
>> attributes by means of getfattr. I am going to prepare new
>> patch set based under last actual kernel version after issue
>> resolving.
>> 
>> With the best regards,
>> Vyacheslav Dubeyko.
>> 
>> On Sep 15, 2012, at 8:49 PM, Hin-Tak Leung wrote:
>>> 


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 4/4] hfsplus: add support of manipulation by attributes file
  2012-09-17 20:00           ` Vyacheslav Dubeyko
@ 2012-09-17 20:09             ` Hin-Tak Leung
  0 siblings, 0 replies; 10+ messages in thread
From: Hin-Tak Leung @ 2012-09-17 20:09 UTC (permalink / raw)
  To: Vyacheslav Dubeyko; +Cc: linux-fsdevel

--- On Mon, 17/9/12, Vyacheslav Dubeyko <slava@dubeyko.com> wrote:

> Hi,
> 
> On Sep 17, 2012, at 11:52 PM, Hin-Tak Leung wrote:
> 
> > Oh, yes, there was a small conflict at the end of
> super.c when I applied to 3.5.3:
> > 
> > ---------------
> > @@ -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);
> > }
> > 
> > ----------------
> > 
> > 3.5.3 does not have the "rcu_barrier();" line for
> whatever reason - since the chunk seem to mean 'put 
> "hfsplus_destroy_attr_tree_cache();" towards the end of
> __exit exit_hfsplus_fs() just before the last line', that's
> what I did.
> > 
> > But as far as I remember that was the only conflict -
> that does not sound like what you describe though...
> 
> Did you apply patch set by means of git or patch utility?

I did "git am < e-mail-dump-from-you", after trying patch --dry-run, and modifying the e-mail-dump by hand as detailed above.

(The actual procedure was more like, try 'git am' first, did not work, did "patch --dry-run", then "patch" to see the actual conflict, then edited the patch by hand, did 'git reset --hard" to get rid of the patch, then "git am" finally).

Hin-Tak

--
To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2012-09-17 20:09 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
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
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

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).