From mboxrd@z Thu Jan 1 00:00:00 1970 From: Hin-Tak Leung Subject: Re: [PATCH 4/4] hfsplus: add support of manipulation by attributes file Date: Sat, 15 Sep 2012 01:11:50 +0100 Message-ID: <5053C7C6.5080800@users.sourceforge.net> References: Mime-Version: 1.0 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit Cc: linux-fsdevel@vger.kernel.org To: Vyacheslav Dubeyko Return-path: Received: from nm3-vm0.bullet.mail.ukl.yahoo.com ([217.146.183.228]:32262 "HELO nm3-vm0.bullet.mail.ukl.yahoo.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with SMTP id S1752247Ab2IOARg (ORCPT ); Fri, 14 Sep 2012 20:17:36 -0400 In-Reply-To: Sender: linux-fsdevel-owner@vger.kernel.org List-ID: Vyacheslav Dubeyko wrote: > Hi, > > This patch adds support of manipulation by attributes file. > > With the best regards, > Vyacheslav Dubeyko. > -- > From: Vyacheslav Dubeyko > 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 > Signed-off-by: Vyacheslav Dubeyko 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++); >