linux-fsdevel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 4/4] hfsplus: add support of manipulation by attributes file
@ 2012-09-23 14:49 Vyacheslav Dubeyko
  2012-10-01 11:24 ` Hin-Tak Leung
  0 siblings, 1 reply; 3+ messages in thread
From: Vyacheslav Dubeyko @ 2012-09-23 14:49 UTC (permalink / raw)
  To: linux-fsdevel, Andrew Morton, Christoph Hellwig, Al Viro; +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 v2 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        |    6 +++-
 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, 210 insertions(+), 49 deletions(-)
 mode change 100644 => 100755 fs/hfsplus/bfind.c
 mode change 100644 => 100755 fs/hfsplus/bnode.c
 mode change 100644 => 100755 fs/hfsplus/brec.c
 mode change 100644 => 100755 fs/hfsplus/btree.c
 mode change 100644 => 100755 fs/hfsplus/catalog.c
 mode change 100644 => 100755 fs/hfsplus/dir.c
 mode change 100644 => 100755 fs/hfsplus/extents.c
 mode change 100644 => 100755 fs/hfsplus/hfsplus_fs.h
 mode change 100644 => 100755 fs/hfsplus/inode.c
 mode change 100644 => 100755 fs/hfsplus/super.c
 mode change 100644 => 100755 fs/hfsplus/unicode.c

diff --git a/fs/hfsplus/bfind.c b/fs/hfsplus/bfind.c
old mode 100644
new mode 100755
index 5d799c1..55baffa
--- 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
old mode 100644
new mode 100755
index 1c42cc5..5c125ce
--- 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
old mode 100644
new mode 100755
index 2a734cf..298d4e4
--- 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
old mode 100644
new mode 100755
index 21023d9..44294af
--- 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
old mode 100644
new mode 100755
index ec2a9c2..c285c8d
--- 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
old mode 100644
new mode 100755
index 6b9f921..40ceeab
--- 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;
 
@@ -508,6 +508,10 @@ const struct inode_operations hfsplus_dir_inode_operations = {
 	.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
old mode 100644
new mode 100755
index 5849e3e..87e59e9
--- 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
old mode 100644
new mode 100755
index 558dbb4..03ed580
--- 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
old mode 100644
new mode 100755
index 3d8b4a6..98a6210
--- 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
old mode 100644
new mode 100755
index fdafb2d..5a7c91e
--- 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,15 +643,30 @@ 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;
 }
 
 static void __exit exit_hfsplus_fs(void)
 {
 	unregister_filesystem(&hfsplus_fs_type);
+	hfsplus_destroy_attr_tree_cache();
 	kmem_cache_destroy(hfsplus_inode_cachep);
 }
 
diff --git a/fs/hfsplus/unicode.c b/fs/hfsplus/unicode.c
old mode 100644
new mode 100755
index a32998f..2c2e47d
--- 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.9.5


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

* Re: [PATCH v2 4/4] hfsplus: add support of manipulation by attributes file
  2012-09-23 14:49 [PATCH v2 4/4] hfsplus: add support of manipulation by attributes file Vyacheslav Dubeyko
@ 2012-10-01 11:24 ` Hin-Tak Leung
  2012-10-01 11:52   ` Vyacheslav Dubeyko
  0 siblings, 1 reply; 3+ messages in thread
From: Hin-Tak Leung @ 2012-10-01 11:24 UTC (permalink / raw)
  To: linux-fsdevel, Andrew Morton, Christoph Hellwig, Al Viro,
	Vyacheslav Dubeyko

--- On Sun, 23/9/12, Vyacheslav Dubeyko <slava@dubeyko.com> 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 v2 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>

Tested-by: Hin-Tak Leung <htl10@users.sourceforge.net>

Tried these 4 patches -together with the 5th which acted on code reviews and feedback. Works okay and fixed the two minor problems I had work v 1 (dubious warnings and interactions with selinux's use of extended atttributes).

There is a small problem though - this set of patches changes the file modes of some of the files, as seen below - just scroll further down... The other patches also touch the file modes where files are modified.

Hin-Tak

> ---
>  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        |   
> 6 +++-
>  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, 210 insertions(+), 49 deletions(-)
>  mode change 100644 => 100755 fs/hfsplus/bfind.c
>  mode change 100644 => 100755 fs/hfsplus/bnode.c
>  mode change 100644 => 100755 fs/hfsplus/brec.c
>  mode change 100644 => 100755 fs/hfsplus/btree.c
>  mode change 100644 => 100755 fs/hfsplus/catalog.c
>  mode change 100644 => 100755 fs/hfsplus/dir.c
>  mode change 100644 => 100755 fs/hfsplus/extents.c
>  mode change 100644 => 100755 fs/hfsplus/hfsplus_fs.h
>  mode change 100644 => 100755 fs/hfsplus/inode.c
>  mode change 100644 => 100755 fs/hfsplus/super.c
>  mode change 100644 => 100755 fs/hfsplus/unicode.c

Here - the file modes should not be touched...

> diff --git a/fs/hfsplus/bfind.c b/fs/hfsplus/bfind.c
> old mode 100644
> new mode 100755
> index 5d799c1..55baffa
> --- 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
> old mode 100644
> new mode 100755
> index 1c42cc5..5c125ce
> --- 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
> old mode 100644
> new mode 100755
> index 2a734cf..298d4e4
> --- 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
> old mode 100644
> new mode 100755
> index 21023d9..44294af
> --- 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
> old mode 100644
> new mode 100755
> index ec2a9c2..c285c8d
> --- 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
> old mode 100644
> new mode 100755
> index 6b9f921..40ceeab
> --- 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;
>  
> @@ -508,6 +508,10 @@ const struct inode_operations
> hfsplus_dir_inode_operations = {
>      .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
> old mode 100644
> new mode 100755
> index 5849e3e..87e59e9
> --- 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
> old mode 100644
> new mode 100755
> index 558dbb4..03ed580
> --- 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
> old mode 100644
> new mode 100755
> index 3d8b4a6..98a6210
> --- 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
> old mode 100644
> new mode 100755
> index fdafb2d..5a7c91e
> --- 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,15 +643,30 @@ 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;
>  }
>  
>  static void __exit exit_hfsplus_fs(void)
>  {
>     
> unregister_filesystem(&hfsplus_fs_type);
> +    hfsplus_destroy_attr_tree_cache();
>     
> kmem_cache_destroy(hfsplus_inode_cachep);
>  }
>  
> diff --git a/fs/hfsplus/unicode.c b/fs/hfsplus/unicode.c
> old mode 100644
> new mode 100755
> index a32998f..2c2e47d
> --- 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.9.5
> 
> 
--
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] 3+ messages in thread

* Re: [PATCH v2 4/4] hfsplus: add support of manipulation by attributes file
  2012-10-01 11:24 ` Hin-Tak Leung
@ 2012-10-01 11:52   ` Vyacheslav Dubeyko
  0 siblings, 0 replies; 3+ messages in thread
From: Vyacheslav Dubeyko @ 2012-10-01 11:52 UTC (permalink / raw)
  To: htl10; +Cc: linux-fsdevel, Andrew Morton, Christoph Hellwig, Al Viro

Hi Hin-Tak,

On Mon, 2012-10-01 at 12:24 +0100, Hin-Tak Leung wrote:
> --- On Sun, 23/9/12, Vyacheslav Dubeyko <slava@dubeyko.com> 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 v2 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>
> 
> Tested-by: Hin-Tak Leung <htl10@users.sourceforge.net>
> 

Thank you.

> Tried these 4 patches -together with the 5th which acted on code reviews and feedback. Works okay and fixed the two minor problems I had work v 1 (dubious warnings and interactions with selinux's use of extended atttributes).
> 
> There is a small problem though - this set of patches changes the file modes of some of the files, as seen below - just scroll further down... The other patches also touch the file modes where files are modified.
> 
> Hin-Tak
> 
> > ---
> >  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        |   
> > 6 +++-
> >  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, 210 insertions(+), 49 deletions(-)
> >  mode change 100644 => 100755 fs/hfsplus/bfind.c
> >  mode change 100644 => 100755 fs/hfsplus/bnode.c
> >  mode change 100644 => 100755 fs/hfsplus/brec.c
> >  mode change 100644 => 100755 fs/hfsplus/btree.c
> >  mode change 100644 => 100755 fs/hfsplus/catalog.c
> >  mode change 100644 => 100755 fs/hfsplus/dir.c
> >  mode change 100644 => 100755 fs/hfsplus/extents.c
> >  mode change 100644 => 100755 fs/hfsplus/hfsplus_fs.h
> >  mode change 100644 => 100755 fs/hfsplus/inode.c
> >  mode change 100644 => 100755 fs/hfsplus/super.c
> >  mode change 100644 => 100755 fs/hfsplus/unicode.c
> 
> Here - the file modes should not be touched...
> 

You are right. This is my mistake that was made during path set preparation.

As I can understand, these file mode changes were not adopted during adding to the -mm tree.

With the best regards,
Vyacheslav Dubeyko.



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

end of thread, other threads:[~2012-10-01 11:53 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-09-23 14:49 [PATCH v2 4/4] hfsplus: add support of manipulation by attributes file Vyacheslav Dubeyko
2012-10-01 11:24 ` Hin-Tak Leung
2012-10-01 11:52   ` Vyacheslav Dubeyko

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