diff options
| author | Vyacheslav Dubeyko <slava@dubeyko.com> | 2013-02-27 20:03:04 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-02-27 22:10:10 -0500 |
| commit | 324ef39a8a4f693035d63527f16100ed27310ecc (patch) | |
| tree | 1814515cf6139fe1b4ebae8d6641c9ec6293d396 /fs | |
| parent | 127e5f5ae51eff44c9bff673f24e8587caa4e29f (diff) | |
hfsplus: add support of manipulation by attributes file
Add support of manipulation by attributes file.
Signed-off-by: Vyacheslav Dubeyko <slava@dubeyko.com>
Reported-by: Hin-Tak Leung <htl10@users.sourceforge.net>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Jan Kara <jack@suse.cz>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs')
| -rw-r--r-- | fs/hfsplus/Makefile | 4 | ||||
| -rw-r--r-- | fs/hfsplus/bfind.c | 93 | ||||
| -rw-r--r-- | fs/hfsplus/bnode.c | 6 | ||||
| -rw-r--r-- | fs/hfsplus/brec.c | 23 | ||||
| -rw-r--r-- | fs/hfsplus/btree.c | 8 | ||||
| -rw-r--r-- | fs/hfsplus/catalog.c | 36 | ||||
| -rw-r--r-- | fs/hfsplus/dir.c | 55 | ||||
| -rw-r--r-- | fs/hfsplus/extents.c | 4 | ||||
| -rw-r--r-- | fs/hfsplus/hfsplus_fs.h | 52 | ||||
| -rw-r--r-- | fs/hfsplus/inode.c | 18 | ||||
| -rw-r--r-- | fs/hfsplus/ioctl.c | 108 | ||||
| -rw-r--r-- | fs/hfsplus/super.c | 56 | ||||
| -rw-r--r-- | fs/hfsplus/unicode.c | 7 |
13 files changed, 287 insertions, 183 deletions
diff --git a/fs/hfsplus/Makefile b/fs/hfsplus/Makefile index 3cc0df730156..09d278bb7b91 100644 --- a/fs/hfsplus/Makefile +++ b/fs/hfsplus/Makefile | |||
| @@ -5,5 +5,5 @@ | |||
| 5 | obj-$(CONFIG_HFSPLUS_FS) += hfsplus.o | 5 | obj-$(CONFIG_HFSPLUS_FS) += hfsplus.o |
| 6 | 6 | ||
| 7 | hfsplus-objs := super.o options.o inode.o ioctl.o extents.o catalog.o dir.o btree.o \ | 7 | hfsplus-objs := super.o options.o inode.o ioctl.o extents.o catalog.o dir.o btree.o \ |
| 8 | bnode.o brec.o bfind.o tables.o unicode.o wrapper.o bitmap.o part_tbl.o | 8 | bnode.o brec.o bfind.o tables.o unicode.o wrapper.o bitmap.o part_tbl.o \ |
| 9 | 9 | attributes.o xattr.o xattr_user.o xattr_security.o xattr_trusted.o | |
diff --git a/fs/hfsplus/bfind.c b/fs/hfsplus/bfind.c index 5d799c13205f..d73c98d1ee99 100644 --- a/fs/hfsplus/bfind.c +++ b/fs/hfsplus/bfind.c | |||
| @@ -24,7 +24,19 @@ int hfs_find_init(struct hfs_btree *tree, struct hfs_find_data *fd) | |||
| 24 | fd->key = ptr + tree->max_key_len + 2; | 24 | fd->key = ptr + tree->max_key_len + 2; |
| 25 | dprint(DBG_BNODE_REFS, "find_init: %d (%p)\n", | 25 | dprint(DBG_BNODE_REFS, "find_init: %d (%p)\n", |
| 26 | tree->cnid, __builtin_return_address(0)); | 26 | tree->cnid, __builtin_return_address(0)); |
| 27 | mutex_lock(&tree->tree_lock); | 27 | switch (tree->cnid) { |
| 28 | case HFSPLUS_CAT_CNID: | ||
| 29 | mutex_lock_nested(&tree->tree_lock, CATALOG_BTREE_MUTEX); | ||
| 30 | break; | ||
| 31 | case HFSPLUS_EXT_CNID: | ||
| 32 | mutex_lock_nested(&tree->tree_lock, EXTENTS_BTREE_MUTEX); | ||
| 33 | break; | ||
| 34 | case HFSPLUS_ATTR_CNID: | ||
| 35 | mutex_lock_nested(&tree->tree_lock, ATTR_BTREE_MUTEX); | ||
| 36 | break; | ||
| 37 | default: | ||
| 38 | BUG(); | ||
| 39 | } | ||
| 28 | return 0; | 40 | return 0; |
| 29 | } | 41 | } |
| 30 | 42 | ||
| @@ -38,15 +50,73 @@ void hfs_find_exit(struct hfs_find_data *fd) | |||
| 38 | fd->tree = NULL; | 50 | fd->tree = NULL; |
| 39 | } | 51 | } |
| 40 | 52 | ||
| 41 | /* Find the record in bnode that best matches key (not greater than...)*/ | 53 | int hfs_find_1st_rec_by_cnid(struct hfs_bnode *bnode, |
| 42 | int __hfs_brec_find(struct hfs_bnode *bnode, struct hfs_find_data *fd) | 54 | struct hfs_find_data *fd, |
| 55 | int *begin, | ||
| 56 | int *end, | ||
| 57 | int *cur_rec) | ||
| 58 | { | ||
| 59 | __be32 cur_cnid, search_cnid; | ||
| 60 | |||
| 61 | if (bnode->tree->cnid == HFSPLUS_EXT_CNID) { | ||
| 62 | cur_cnid = fd->key->ext.cnid; | ||
| 63 | search_cnid = fd->search_key->ext.cnid; | ||
| 64 | } else if (bnode->tree->cnid == HFSPLUS_CAT_CNID) { | ||
| 65 | cur_cnid = fd->key->cat.parent; | ||
| 66 | search_cnid = fd->search_key->cat.parent; | ||
| 67 | } else if (bnode->tree->cnid == HFSPLUS_ATTR_CNID) { | ||
| 68 | cur_cnid = fd->key->attr.cnid; | ||
| 69 | search_cnid = fd->search_key->attr.cnid; | ||
| 70 | } else | ||
| 71 | BUG(); | ||
| 72 | |||
| 73 | if (cur_cnid == search_cnid) { | ||
| 74 | (*end) = (*cur_rec); | ||
| 75 | if ((*begin) == (*end)) | ||
| 76 | return 1; | ||
| 77 | } else { | ||
| 78 | if (be32_to_cpu(cur_cnid) < be32_to_cpu(search_cnid)) | ||
| 79 | (*begin) = (*cur_rec) + 1; | ||
| 80 | else | ||
| 81 | (*end) = (*cur_rec) - 1; | ||
| 82 | } | ||
| 83 | |||
| 84 | return 0; | ||
| 85 | } | ||
| 86 | |||
| 87 | int hfs_find_rec_by_key(struct hfs_bnode *bnode, | ||
| 88 | struct hfs_find_data *fd, | ||
| 89 | int *begin, | ||
| 90 | int *end, | ||
| 91 | int *cur_rec) | ||
| 43 | { | 92 | { |
| 44 | int cmpval; | 93 | int cmpval; |
| 94 | |||
| 95 | cmpval = bnode->tree->keycmp(fd->key, fd->search_key); | ||
| 96 | if (!cmpval) { | ||
| 97 | (*end) = (*cur_rec); | ||
| 98 | return 1; | ||
| 99 | } | ||
| 100 | if (cmpval < 0) | ||
| 101 | (*begin) = (*cur_rec) + 1; | ||
| 102 | else | ||
| 103 | *(end) = (*cur_rec) - 1; | ||
| 104 | |||
| 105 | return 0; | ||
| 106 | } | ||
| 107 | |||
| 108 | /* Find the record in bnode that best matches key (not greater than...)*/ | ||
| 109 | int __hfs_brec_find(struct hfs_bnode *bnode, struct hfs_find_data *fd, | ||
| 110 | search_strategy_t rec_found) | ||
| 111 | { | ||
| 45 | u16 off, len, keylen; | 112 | u16 off, len, keylen; |
| 46 | int rec; | 113 | int rec; |
| 47 | int b, e; | 114 | int b, e; |
| 48 | int res; | 115 | int res; |
| 49 | 116 | ||
| 117 | if (!rec_found) | ||
| 118 | BUG(); | ||
| 119 | |||
| 50 | b = 0; | 120 | b = 0; |
| 51 | e = bnode->num_recs - 1; | 121 | e = bnode->num_recs - 1; |
| 52 | res = -ENOENT; | 122 | res = -ENOENT; |
| @@ -59,17 +129,12 @@ int __hfs_brec_find(struct hfs_bnode *bnode, struct hfs_find_data *fd) | |||
| 59 | goto fail; | 129 | goto fail; |
| 60 | } | 130 | } |
| 61 | hfs_bnode_read(bnode, fd->key, off, keylen); | 131 | hfs_bnode_read(bnode, fd->key, off, keylen); |
| 62 | cmpval = bnode->tree->keycmp(fd->key, fd->search_key); | 132 | if (rec_found(bnode, fd, &b, &e, &rec)) { |
| 63 | if (!cmpval) { | ||
| 64 | e = rec; | ||
| 65 | res = 0; | 133 | res = 0; |
| 66 | goto done; | 134 | goto done; |
| 67 | } | 135 | } |
| 68 | if (cmpval < 0) | ||
| 69 | b = rec + 1; | ||
| 70 | else | ||
| 71 | e = rec - 1; | ||
| 72 | } while (b <= e); | 136 | } while (b <= e); |
| 137 | |||
| 73 | if (rec != e && e >= 0) { | 138 | if (rec != e && e >= 0) { |
| 74 | len = hfs_brec_lenoff(bnode, e, &off); | 139 | len = hfs_brec_lenoff(bnode, e, &off); |
| 75 | keylen = hfs_brec_keylen(bnode, e); | 140 | keylen = hfs_brec_keylen(bnode, e); |
| @@ -79,19 +144,21 @@ int __hfs_brec_find(struct hfs_bnode *bnode, struct hfs_find_data *fd) | |||
| 79 | } | 144 | } |
| 80 | hfs_bnode_read(bnode, fd->key, off, keylen); | 145 | hfs_bnode_read(bnode, fd->key, off, keylen); |
| 81 | } | 146 | } |
| 147 | |||
| 82 | done: | 148 | done: |
| 83 | fd->record = e; | 149 | fd->record = e; |
| 84 | fd->keyoffset = off; | 150 | fd->keyoffset = off; |
| 85 | fd->keylength = keylen; | 151 | fd->keylength = keylen; |
| 86 | fd->entryoffset = off + keylen; | 152 | fd->entryoffset = off + keylen; |
| 87 | fd->entrylength = len - keylen; | 153 | fd->entrylength = len - keylen; |
| 154 | |||
| 88 | fail: | 155 | fail: |
| 89 | return res; | 156 | return res; |
| 90 | } | 157 | } |
| 91 | 158 | ||
| 92 | /* Traverse a B*Tree from the root to a leaf finding best fit to key */ | 159 | /* Traverse a B*Tree from the root to a leaf finding best fit to key */ |
| 93 | /* Return allocated copy of node found, set recnum to best record */ | 160 | /* Return allocated copy of node found, set recnum to best record */ |
| 94 | int hfs_brec_find(struct hfs_find_data *fd) | 161 | int hfs_brec_find(struct hfs_find_data *fd, search_strategy_t do_key_compare) |
| 95 | { | 162 | { |
| 96 | struct hfs_btree *tree; | 163 | struct hfs_btree *tree; |
| 97 | struct hfs_bnode *bnode; | 164 | struct hfs_bnode *bnode; |
| @@ -122,7 +189,7 @@ int hfs_brec_find(struct hfs_find_data *fd) | |||
| 122 | goto invalid; | 189 | goto invalid; |
| 123 | bnode->parent = parent; | 190 | bnode->parent = parent; |
| 124 | 191 | ||
| 125 | res = __hfs_brec_find(bnode, fd); | 192 | res = __hfs_brec_find(bnode, fd, do_key_compare); |
| 126 | if (!height) | 193 | if (!height) |
| 127 | break; | 194 | break; |
| 128 | if (fd->record < 0) | 195 | if (fd->record < 0) |
| @@ -149,7 +216,7 @@ int hfs_brec_read(struct hfs_find_data *fd, void *rec, int rec_len) | |||
| 149 | { | 216 | { |
| 150 | int res; | 217 | int res; |
| 151 | 218 | ||
| 152 | res = hfs_brec_find(fd); | 219 | res = hfs_brec_find(fd, hfs_find_rec_by_key); |
| 153 | if (res) | 220 | if (res) |
| 154 | return res; | 221 | return res; |
| 155 | if (fd->entrylength > rec_len) | 222 | if (fd->entrylength > rec_len) |
diff --git a/fs/hfsplus/bnode.c b/fs/hfsplus/bnode.c index 1c42cc5b899f..5c125ce6bd72 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) | |||
| 62 | 62 | ||
| 63 | tree = node->tree; | 63 | tree = node->tree; |
| 64 | if (node->type == HFS_NODE_LEAF || | 64 | if (node->type == HFS_NODE_LEAF || |
| 65 | tree->attributes & HFS_TREE_VARIDXKEYS) | 65 | tree->attributes & HFS_TREE_VARIDXKEYS || |
| 66 | node->tree->cnid == HFSPLUS_ATTR_CNID) | ||
| 66 | key_len = hfs_bnode_read_u16(node, off) + 2; | 67 | key_len = hfs_bnode_read_u16(node, off) + 2; |
| 67 | else | 68 | else |
| 68 | key_len = tree->max_key_len + 2; | 69 | key_len = tree->max_key_len + 2; |
| @@ -314,7 +315,8 @@ void hfs_bnode_dump(struct hfs_bnode *node) | |||
| 314 | if (i && node->type == HFS_NODE_INDEX) { | 315 | if (i && node->type == HFS_NODE_INDEX) { |
| 315 | int tmp; | 316 | int tmp; |
| 316 | 317 | ||
| 317 | if (node->tree->attributes & HFS_TREE_VARIDXKEYS) | 318 | if (node->tree->attributes & HFS_TREE_VARIDXKEYS || |
| 319 | node->tree->cnid == HFSPLUS_ATTR_CNID) | ||
| 318 | tmp = hfs_bnode_read_u16(node, key_off) + 2; | 320 | tmp = hfs_bnode_read_u16(node, key_off) + 2; |
| 319 | else | 321 | else |
| 320 | tmp = node->tree->max_key_len + 2; | 322 | tmp = node->tree->max_key_len + 2; |
diff --git a/fs/hfsplus/brec.c b/fs/hfsplus/brec.c index 2a734cfccc92..298d4e45604b 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) | |||
| 36 | return 0; | 36 | return 0; |
| 37 | 37 | ||
| 38 | if ((node->type == HFS_NODE_INDEX) && | 38 | if ((node->type == HFS_NODE_INDEX) && |
| 39 | !(node->tree->attributes & HFS_TREE_VARIDXKEYS)) { | 39 | !(node->tree->attributes & HFS_TREE_VARIDXKEYS) && |
| 40 | (node->tree->cnid != HFSPLUS_ATTR_CNID)) { | ||
| 40 | retval = node->tree->max_key_len + 2; | 41 | retval = node->tree->max_key_len + 2; |
| 41 | } else { | 42 | } else { |
| 42 | recoff = hfs_bnode_read_u16(node, | 43 | recoff = hfs_bnode_read_u16(node, |
| @@ -151,12 +152,13 @@ skip: | |||
| 151 | 152 | ||
| 152 | /* get index key */ | 153 | /* get index key */ |
| 153 | hfs_bnode_read_key(new_node, fd->search_key, 14); | 154 | hfs_bnode_read_key(new_node, fd->search_key, 14); |
| 154 | __hfs_brec_find(fd->bnode, fd); | 155 | __hfs_brec_find(fd->bnode, fd, hfs_find_rec_by_key); |
| 155 | 156 | ||
| 156 | hfs_bnode_put(new_node); | 157 | hfs_bnode_put(new_node); |
| 157 | new_node = NULL; | 158 | new_node = NULL; |
| 158 | 159 | ||
| 159 | if (tree->attributes & HFS_TREE_VARIDXKEYS) | 160 | if ((tree->attributes & HFS_TREE_VARIDXKEYS) || |
| 161 | (tree->cnid == HFSPLUS_ATTR_CNID)) | ||
| 160 | key_len = be16_to_cpu(fd->search_key->key_len) + 2; | 162 | key_len = be16_to_cpu(fd->search_key->key_len) + 2; |
| 161 | else { | 163 | else { |
| 162 | fd->search_key->key_len = | 164 | fd->search_key->key_len = |
| @@ -201,7 +203,7 @@ again: | |||
| 201 | hfs_bnode_put(node); | 203 | hfs_bnode_put(node); |
| 202 | node = fd->bnode = parent; | 204 | node = fd->bnode = parent; |
| 203 | 205 | ||
| 204 | __hfs_brec_find(node, fd); | 206 | __hfs_brec_find(node, fd, hfs_find_rec_by_key); |
| 205 | goto again; | 207 | goto again; |
| 206 | } | 208 | } |
| 207 | hfs_bnode_write_u16(node, | 209 | hfs_bnode_write_u16(node, |
| @@ -367,12 +369,13 @@ again: | |||
| 367 | parent = hfs_bnode_find(tree, node->parent); | 369 | parent = hfs_bnode_find(tree, node->parent); |
| 368 | if (IS_ERR(parent)) | 370 | if (IS_ERR(parent)) |
| 369 | return PTR_ERR(parent); | 371 | return PTR_ERR(parent); |
| 370 | __hfs_brec_find(parent, fd); | 372 | __hfs_brec_find(parent, fd, hfs_find_rec_by_key); |
| 371 | hfs_bnode_dump(parent); | 373 | hfs_bnode_dump(parent); |
| 372 | rec = fd->record; | 374 | rec = fd->record; |
| 373 | 375 | ||
| 374 | /* size difference between old and new key */ | 376 | /* size difference between old and new key */ |
| 375 | if (tree->attributes & HFS_TREE_VARIDXKEYS) | 377 | if ((tree->attributes & HFS_TREE_VARIDXKEYS) || |
| 378 | (tree->cnid == HFSPLUS_ATTR_CNID)) | ||
| 376 | newkeylen = hfs_bnode_read_u16(node, 14) + 2; | 379 | newkeylen = hfs_bnode_read_u16(node, 14) + 2; |
| 377 | else | 380 | else |
| 378 | fd->keylength = newkeylen = tree->max_key_len + 2; | 381 | fd->keylength = newkeylen = tree->max_key_len + 2; |
| @@ -427,7 +430,7 @@ skip: | |||
| 427 | hfs_bnode_read_key(new_node, fd->search_key, 14); | 430 | hfs_bnode_read_key(new_node, fd->search_key, 14); |
| 428 | cnid = cpu_to_be32(new_node->this); | 431 | cnid = cpu_to_be32(new_node->this); |
| 429 | 432 | ||
| 430 | __hfs_brec_find(fd->bnode, fd); | 433 | __hfs_brec_find(fd->bnode, fd, hfs_find_rec_by_key); |
| 431 | hfs_brec_insert(fd, &cnid, sizeof(cnid)); | 434 | hfs_brec_insert(fd, &cnid, sizeof(cnid)); |
| 432 | hfs_bnode_put(fd->bnode); | 435 | hfs_bnode_put(fd->bnode); |
| 433 | hfs_bnode_put(new_node); | 436 | hfs_bnode_put(new_node); |
| @@ -495,13 +498,15 @@ static int hfs_btree_inc_height(struct hfs_btree *tree) | |||
| 495 | /* insert old root idx into new root */ | 498 | /* insert old root idx into new root */ |
| 496 | node->parent = tree->root; | 499 | node->parent = tree->root; |
| 497 | if (node->type == HFS_NODE_LEAF || | 500 | if (node->type == HFS_NODE_LEAF || |
| 498 | tree->attributes & HFS_TREE_VARIDXKEYS) | 501 | tree->attributes & HFS_TREE_VARIDXKEYS || |
| 502 | tree->cnid == HFSPLUS_ATTR_CNID) | ||
| 499 | key_size = hfs_bnode_read_u16(node, 14) + 2; | 503 | key_size = hfs_bnode_read_u16(node, 14) + 2; |
| 500 | else | 504 | else |
| 501 | key_size = tree->max_key_len + 2; | 505 | key_size = tree->max_key_len + 2; |
| 502 | hfs_bnode_copy(new_node, 14, node, 14, key_size); | 506 | hfs_bnode_copy(new_node, 14, node, 14, key_size); |
| 503 | 507 | ||
| 504 | if (!(tree->attributes & HFS_TREE_VARIDXKEYS)) { | 508 | if (!(tree->attributes & HFS_TREE_VARIDXKEYS) && |
| 509 | (tree->cnid != HFSPLUS_ATTR_CNID)) { | ||
| 505 | key_size = tree->max_key_len + 2; | 510 | key_size = tree->max_key_len + 2; |
| 506 | hfs_bnode_write_u16(new_node, 14, tree->max_key_len); | 511 | hfs_bnode_write_u16(new_node, 14, tree->max_key_len); |
| 507 | } | 512 | } |
diff --git a/fs/hfsplus/btree.c b/fs/hfsplus/btree.c index 685d07d0ed18..efb689c21a95 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) | |||
| 98 | set_bit(HFSPLUS_SB_CASEFOLD, &HFSPLUS_SB(sb)->flags); | 98 | set_bit(HFSPLUS_SB_CASEFOLD, &HFSPLUS_SB(sb)->flags); |
| 99 | } | 99 | } |
| 100 | break; | 100 | break; |
| 101 | case HFSPLUS_ATTR_CNID: | ||
| 102 | if (tree->max_key_len != HFSPLUS_ATTR_KEYLEN - sizeof(u16)) { | ||
| 103 | printk(KERN_ERR "hfs: invalid attributes max_key_len %d\n", | ||
| 104 | tree->max_key_len); | ||
| 105 | goto fail_page; | ||
| 106 | } | ||
| 107 | tree->keycmp = hfsplus_attr_bin_cmp_key; | ||
| 108 | break; | ||
| 101 | default: | 109 | default: |
| 102 | printk(KERN_ERR "hfs: unknown B*Tree requested\n"); | 110 | printk(KERN_ERR "hfs: unknown B*Tree requested\n"); |
| 103 | goto fail_page; | 111 | goto fail_page; |
diff --git a/fs/hfsplus/catalog.c b/fs/hfsplus/catalog.c index 798d9c4c5e71..840d71edd193 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, | |||
| 45 | 45 | ||
| 46 | key->cat.parent = cpu_to_be32(parent); | 46 | key->cat.parent = cpu_to_be32(parent); |
| 47 | if (str) { | 47 | if (str) { |
| 48 | hfsplus_asc2uni(sb, &key->cat.name, str->name, str->len); | 48 | hfsplus_asc2uni(sb, &key->cat.name, HFSPLUS_MAX_STRLEN, |
| 49 | str->name, str->len); | ||
| 49 | len = be16_to_cpu(key->cat.name.length); | 50 | len = be16_to_cpu(key->cat.name.length); |
| 50 | } else { | 51 | } else { |
| 51 | key->cat.name.length = 0; | 52 | key->cat.name.length = 0; |
| @@ -167,7 +168,8 @@ static int hfsplus_fill_cat_thread(struct super_block *sb, | |||
| 167 | entry->type = cpu_to_be16(type); | 168 | entry->type = cpu_to_be16(type); |
| 168 | entry->thread.reserved = 0; | 169 | entry->thread.reserved = 0; |
| 169 | entry->thread.parentID = cpu_to_be32(parentid); | 170 | entry->thread.parentID = cpu_to_be32(parentid); |
| 170 | hfsplus_asc2uni(sb, &entry->thread.nodeName, str->name, str->len); | 171 | hfsplus_asc2uni(sb, &entry->thread.nodeName, HFSPLUS_MAX_STRLEN, |
| 172 | str->name, str->len); | ||
| 171 | return 10 + be16_to_cpu(entry->thread.nodeName.length) * 2; | 173 | return 10 + be16_to_cpu(entry->thread.nodeName.length) * 2; |
| 172 | } | 174 | } |
| 173 | 175 | ||
| @@ -198,7 +200,7 @@ int hfsplus_find_cat(struct super_block *sb, u32 cnid, | |||
| 198 | hfsplus_cat_build_key_uni(fd->search_key, | 200 | hfsplus_cat_build_key_uni(fd->search_key, |
| 199 | be32_to_cpu(tmp.thread.parentID), | 201 | be32_to_cpu(tmp.thread.parentID), |
| 200 | &tmp.thread.nodeName); | 202 | &tmp.thread.nodeName); |
| 201 | return hfs_brec_find(fd); | 203 | return hfs_brec_find(fd, hfs_find_rec_by_key); |
| 202 | } | 204 | } |
| 203 | 205 | ||
| 204 | int hfsplus_create_cat(u32 cnid, struct inode *dir, | 206 | int hfsplus_create_cat(u32 cnid, struct inode *dir, |
| @@ -221,7 +223,7 @@ int hfsplus_create_cat(u32 cnid, struct inode *dir, | |||
| 221 | S_ISDIR(inode->i_mode) ? | 223 | S_ISDIR(inode->i_mode) ? |
| 222 | HFSPLUS_FOLDER_THREAD : HFSPLUS_FILE_THREAD, | 224 | HFSPLUS_FOLDER_THREAD : HFSPLUS_FILE_THREAD, |
| 223 | dir->i_ino, str); | 225 | dir->i_ino, str); |
| 224 | err = hfs_brec_find(&fd); | 226 | err = hfs_brec_find(&fd, hfs_find_rec_by_key); |
| 225 | if (err != -ENOENT) { | 227 | if (err != -ENOENT) { |
| 226 | if (!err) | 228 | if (!err) |
| 227 | err = -EEXIST; | 229 | err = -EEXIST; |
| @@ -233,7 +235,7 @@ int hfsplus_create_cat(u32 cnid, struct inode *dir, | |||
| 233 | 235 | ||
| 234 | hfsplus_cat_build_key(sb, fd.search_key, dir->i_ino, str); | 236 | hfsplus_cat_build_key(sb, fd.search_key, dir->i_ino, str); |
| 235 | entry_size = hfsplus_cat_build_record(&entry, cnid, inode); | 237 | entry_size = hfsplus_cat_build_record(&entry, cnid, inode); |
| 236 | err = hfs_brec_find(&fd); | 238 | err = hfs_brec_find(&fd, hfs_find_rec_by_key); |
| 237 | if (err != -ENOENT) { | 239 | if (err != -ENOENT) { |
| 238 | /* panic? */ | 240 | /* panic? */ |
| 239 | if (!err) | 241 | if (!err) |
| @@ -253,7 +255,7 @@ int hfsplus_create_cat(u32 cnid, struct inode *dir, | |||
| 253 | 255 | ||
| 254 | err1: | 256 | err1: |
| 255 | hfsplus_cat_build_key(sb, fd.search_key, cnid, NULL); | 257 | hfsplus_cat_build_key(sb, fd.search_key, cnid, NULL); |
| 256 | if (!hfs_brec_find(&fd)) | 258 | if (!hfs_brec_find(&fd, hfs_find_rec_by_key)) |
| 257 | hfs_brec_remove(&fd); | 259 | hfs_brec_remove(&fd); |
| 258 | err2: | 260 | err2: |
| 259 | hfs_find_exit(&fd); | 261 | hfs_find_exit(&fd); |
| @@ -279,7 +281,7 @@ int hfsplus_delete_cat(u32 cnid, struct inode *dir, struct qstr *str) | |||
| 279 | int len; | 281 | int len; |
| 280 | 282 | ||
| 281 | hfsplus_cat_build_key(sb, fd.search_key, cnid, NULL); | 283 | hfsplus_cat_build_key(sb, fd.search_key, cnid, NULL); |
| 282 | err = hfs_brec_find(&fd); | 284 | err = hfs_brec_find(&fd, hfs_find_rec_by_key); |
| 283 | if (err) | 285 | if (err) |
| 284 | goto out; | 286 | goto out; |
| 285 | 287 | ||
| @@ -296,7 +298,7 @@ int hfsplus_delete_cat(u32 cnid, struct inode *dir, struct qstr *str) | |||
| 296 | } else | 298 | } else |
| 297 | hfsplus_cat_build_key(sb, fd.search_key, dir->i_ino, str); | 299 | hfsplus_cat_build_key(sb, fd.search_key, dir->i_ino, str); |
| 298 | 300 | ||
| 299 | err = hfs_brec_find(&fd); | 301 | err = hfs_brec_find(&fd, hfs_find_rec_by_key); |
| 300 | if (err) | 302 | if (err) |
| 301 | goto out; | 303 | goto out; |
| 302 | 304 | ||
| @@ -326,7 +328,7 @@ int hfsplus_delete_cat(u32 cnid, struct inode *dir, struct qstr *str) | |||
| 326 | goto out; | 328 | goto out; |
| 327 | 329 | ||
| 328 | hfsplus_cat_build_key(sb, fd.search_key, cnid, NULL); | 330 | hfsplus_cat_build_key(sb, fd.search_key, cnid, NULL); |
| 329 | err = hfs_brec_find(&fd); | 331 | err = hfs_brec_find(&fd, hfs_find_rec_by_key); |
| 330 | if (err) | 332 | if (err) |
| 331 | goto out; | 333 | goto out; |
| 332 | 334 | ||
| @@ -337,6 +339,12 @@ int hfsplus_delete_cat(u32 cnid, struct inode *dir, struct qstr *str) | |||
| 337 | dir->i_size--; | 339 | dir->i_size--; |
| 338 | dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC; | 340 | dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC; |
| 339 | hfsplus_mark_inode_dirty(dir, HFSPLUS_I_CAT_DIRTY); | 341 | hfsplus_mark_inode_dirty(dir, HFSPLUS_I_CAT_DIRTY); |
| 342 | |||
| 343 | if (type == HFSPLUS_FILE || type == HFSPLUS_FOLDER) { | ||
| 344 | if (HFSPLUS_SB(sb)->attr_tree) | ||
| 345 | hfsplus_delete_all_attrs(dir, cnid); | ||
| 346 | } | ||
| 347 | |||
| 340 | out: | 348 | out: |
| 341 | hfs_find_exit(&fd); | 349 | hfs_find_exit(&fd); |
| 342 | 350 | ||
| @@ -363,7 +371,7 @@ int hfsplus_rename_cat(u32 cnid, | |||
| 363 | 371 | ||
| 364 | /* find the old dir entry and read the data */ | 372 | /* find the old dir entry and read the data */ |
| 365 | hfsplus_cat_build_key(sb, src_fd.search_key, src_dir->i_ino, src_name); | 373 | hfsplus_cat_build_key(sb, src_fd.search_key, src_dir->i_ino, src_name); |
| 366 | err = hfs_brec_find(&src_fd); | 374 | err = hfs_brec_find(&src_fd, hfs_find_rec_by_key); |
| 367 | if (err) | 375 | if (err) |
| 368 | goto out; | 376 | goto out; |
| 369 | if (src_fd.entrylength > sizeof(entry) || src_fd.entrylength < 0) { | 377 | if (src_fd.entrylength > sizeof(entry) || src_fd.entrylength < 0) { |
| @@ -376,7 +384,7 @@ int hfsplus_rename_cat(u32 cnid, | |||
| 376 | 384 | ||
| 377 | /* create new dir entry with the data from the old entry */ | 385 | /* create new dir entry with the data from the old entry */ |
| 378 | hfsplus_cat_build_key(sb, dst_fd.search_key, dst_dir->i_ino, dst_name); | 386 | hfsplus_cat_build_key(sb, dst_fd.search_key, dst_dir->i_ino, dst_name); |
| 379 | err = hfs_brec_find(&dst_fd); | 387 | err = hfs_brec_find(&dst_fd, hfs_find_rec_by_key); |
| 380 | if (err != -ENOENT) { | 388 | if (err != -ENOENT) { |
| 381 | if (!err) | 389 | if (!err) |
| 382 | err = -EEXIST; | 390 | err = -EEXIST; |
| @@ -391,7 +399,7 @@ int hfsplus_rename_cat(u32 cnid, | |||
| 391 | 399 | ||
| 392 | /* finally remove the old entry */ | 400 | /* finally remove the old entry */ |
| 393 | hfsplus_cat_build_key(sb, src_fd.search_key, src_dir->i_ino, src_name); | 401 | hfsplus_cat_build_key(sb, src_fd.search_key, src_dir->i_ino, src_name); |
| 394 | err = hfs_brec_find(&src_fd); | 402 | err = hfs_brec_find(&src_fd, hfs_find_rec_by_key); |
| 395 | if (err) | 403 | if (err) |
| 396 | goto out; | 404 | goto out; |
| 397 | err = hfs_brec_remove(&src_fd); | 405 | err = hfs_brec_remove(&src_fd); |
| @@ -402,7 +410,7 @@ int hfsplus_rename_cat(u32 cnid, | |||
| 402 | 410 | ||
| 403 | /* remove old thread entry */ | 411 | /* remove old thread entry */ |
| 404 | hfsplus_cat_build_key(sb, src_fd.search_key, cnid, NULL); | 412 | hfsplus_cat_build_key(sb, src_fd.search_key, cnid, NULL); |
| 405 | err = hfs_brec_find(&src_fd); | 413 | err = hfs_brec_find(&src_fd, hfs_find_rec_by_key); |
| 406 | if (err) | 414 | if (err) |
| 407 | goto out; | 415 | goto out; |
| 408 | type = hfs_bnode_read_u16(src_fd.bnode, src_fd.entryoffset); | 416 | type = hfs_bnode_read_u16(src_fd.bnode, src_fd.entryoffset); |
| @@ -414,7 +422,7 @@ int hfsplus_rename_cat(u32 cnid, | |||
| 414 | hfsplus_cat_build_key(sb, dst_fd.search_key, cnid, NULL); | 422 | hfsplus_cat_build_key(sb, dst_fd.search_key, cnid, NULL); |
| 415 | entry_size = hfsplus_fill_cat_thread(sb, &entry, type, | 423 | entry_size = hfsplus_fill_cat_thread(sb, &entry, type, |
| 416 | dst_dir->i_ino, dst_name); | 424 | dst_dir->i_ino, dst_name); |
| 417 | err = hfs_brec_find(&dst_fd); | 425 | err = hfs_brec_find(&dst_fd, hfs_find_rec_by_key); |
| 418 | if (err != -ENOENT) { | 426 | if (err != -ENOENT) { |
| 419 | if (!err) | 427 | if (!err) |
| 420 | err = -EEXIST; | 428 | err = -EEXIST; |
diff --git a/fs/hfsplus/dir.c b/fs/hfsplus/dir.c index 074e04589248..031c24e50521 100644 --- a/fs/hfsplus/dir.c +++ b/fs/hfsplus/dir.c | |||
| @@ -15,6 +15,7 @@ | |||
| 15 | 15 | ||
| 16 | #include "hfsplus_fs.h" | 16 | #include "hfsplus_fs.h" |
| 17 | #include "hfsplus_raw.h" | 17 | #include "hfsplus_raw.h" |
| 18 | #include "xattr.h" | ||
| 18 | 19 | ||
| 19 | static inline void hfsplus_instantiate(struct dentry *dentry, | 20 | static inline void hfsplus_instantiate(struct dentry *dentry, |
| 20 | struct inode *inode, u32 cnid) | 21 | struct inode *inode, u32 cnid) |
| @@ -138,7 +139,7 @@ static int hfsplus_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
| 138 | if (err) | 139 | if (err) |
| 139 | return err; | 140 | return err; |
| 140 | hfsplus_cat_build_key(sb, fd.search_key, inode->i_ino, NULL); | 141 | hfsplus_cat_build_key(sb, fd.search_key, inode->i_ino, NULL); |
| 141 | err = hfs_brec_find(&fd); | 142 | err = hfs_brec_find(&fd, hfs_find_rec_by_key); |
| 142 | if (err) | 143 | if (err) |
| 143 | goto out; | 144 | goto out; |
| 144 | 145 | ||
| @@ -421,6 +422,15 @@ static int hfsplus_symlink(struct inode *dir, struct dentry *dentry, | |||
| 421 | if (res) | 422 | if (res) |
| 422 | goto out_err; | 423 | goto out_err; |
| 423 | 424 | ||
| 425 | res = hfsplus_init_inode_security(inode, dir, &dentry->d_name); | ||
| 426 | if (res == -EOPNOTSUPP) | ||
| 427 | res = 0; /* Operation is not supported. */ | ||
| 428 | else if (res) { | ||
| 429 | /* Try to delete anyway without error analysis. */ | ||
| 430 | hfsplus_delete_cat(inode->i_ino, dir, &dentry->d_name); | ||
| 431 | goto out_err; | ||
| 432 | } | ||
| 433 | |||
| 424 | hfsplus_instantiate(dentry, inode, inode->i_ino); | 434 | hfsplus_instantiate(dentry, inode, inode->i_ino); |
| 425 | mark_inode_dirty(inode); | 435 | mark_inode_dirty(inode); |
| 426 | goto out; | 436 | goto out; |
| @@ -450,15 +460,26 @@ static int hfsplus_mknod(struct inode *dir, struct dentry *dentry, | |||
| 450 | init_special_inode(inode, mode, rdev); | 460 | init_special_inode(inode, mode, rdev); |
| 451 | 461 | ||
| 452 | res = hfsplus_create_cat(inode->i_ino, dir, &dentry->d_name, inode); | 462 | res = hfsplus_create_cat(inode->i_ino, dir, &dentry->d_name, inode); |
| 453 | if (res) { | 463 | if (res) |
| 454 | clear_nlink(inode); | 464 | goto failed_mknod; |
| 455 | hfsplus_delete_inode(inode); | 465 | |
| 456 | iput(inode); | 466 | res = hfsplus_init_inode_security(inode, dir, &dentry->d_name); |
| 457 | goto out; | 467 | if (res == -EOPNOTSUPP) |
| 468 | res = 0; /* Operation is not supported. */ | ||
| 469 | else if (res) { | ||
| 470 | /* Try to delete anyway without error analysis. */ | ||
| 471 | hfsplus_delete_cat(inode->i_ino, dir, &dentry->d_name); | ||
| 472 | goto failed_mknod; | ||
| 458 | } | 473 | } |
| 459 | 474 | ||
| 460 | hfsplus_instantiate(dentry, inode, inode->i_ino); | 475 | hfsplus_instantiate(dentry, inode, inode->i_ino); |
| 461 | mark_inode_dirty(inode); | 476 | mark_inode_dirty(inode); |
| 477 | goto out; | ||
| 478 | |||
| 479 | failed_mknod: | ||
| 480 | clear_nlink(inode); | ||
| 481 | hfsplus_delete_inode(inode); | ||
| 482 | iput(inode); | ||
| 462 | out: | 483 | out: |
| 463 | mutex_unlock(&sbi->vh_mutex); | 484 | mutex_unlock(&sbi->vh_mutex); |
| 464 | return res; | 485 | return res; |
| @@ -499,15 +520,19 @@ static int hfsplus_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
| 499 | } | 520 | } |
| 500 | 521 | ||
| 501 | const struct inode_operations hfsplus_dir_inode_operations = { | 522 | const struct inode_operations hfsplus_dir_inode_operations = { |
| 502 | .lookup = hfsplus_lookup, | 523 | .lookup = hfsplus_lookup, |
| 503 | .create = hfsplus_create, | 524 | .create = hfsplus_create, |
| 504 | .link = hfsplus_link, | 525 | .link = hfsplus_link, |
| 505 | .unlink = hfsplus_unlink, | 526 | .unlink = hfsplus_unlink, |
| 506 | .mkdir = hfsplus_mkdir, | 527 | .mkdir = hfsplus_mkdir, |
| 507 | .rmdir = hfsplus_rmdir, | 528 | .rmdir = hfsplus_rmdir, |
| 508 | .symlink = hfsplus_symlink, | 529 | .symlink = hfsplus_symlink, |
| 509 | .mknod = hfsplus_mknod, | 530 | .mknod = hfsplus_mknod, |
| 510 | .rename = hfsplus_rename, | 531 | .rename = hfsplus_rename, |
| 532 | .setxattr = generic_setxattr, | ||
| 533 | .getxattr = generic_getxattr, | ||
| 534 | .listxattr = hfsplus_listxattr, | ||
| 535 | .removexattr = hfsplus_removexattr, | ||
| 511 | }; | 536 | }; |
| 512 | 537 | ||
| 513 | const struct file_operations hfsplus_dir_operations = { | 538 | const struct file_operations hfsplus_dir_operations = { |
diff --git a/fs/hfsplus/extents.c b/fs/hfsplus/extents.c index eba76eab6d62..a94f0f779d5e 100644 --- a/fs/hfsplus/extents.c +++ b/fs/hfsplus/extents.c | |||
| @@ -95,7 +95,7 @@ static void __hfsplus_ext_write_extent(struct inode *inode, | |||
| 95 | HFSPLUS_IS_RSRC(inode) ? | 95 | HFSPLUS_IS_RSRC(inode) ? |
| 96 | HFSPLUS_TYPE_RSRC : HFSPLUS_TYPE_DATA); | 96 | HFSPLUS_TYPE_RSRC : HFSPLUS_TYPE_DATA); |
| 97 | 97 | ||
| 98 | res = hfs_brec_find(fd); | 98 | res = hfs_brec_find(fd, hfs_find_rec_by_key); |
| 99 | if (hip->extent_state & HFSPLUS_EXT_NEW) { | 99 | if (hip->extent_state & HFSPLUS_EXT_NEW) { |
| 100 | if (res != -ENOENT) | 100 | if (res != -ENOENT) |
| 101 | return; | 101 | return; |
| @@ -154,7 +154,7 @@ static inline int __hfsplus_ext_read_extent(struct hfs_find_data *fd, | |||
| 154 | 154 | ||
| 155 | hfsplus_ext_build_key(fd->search_key, cnid, block, type); | 155 | hfsplus_ext_build_key(fd->search_key, cnid, block, type); |
| 156 | fd->key->ext.cnid = 0; | 156 | fd->key->ext.cnid = 0; |
| 157 | res = hfs_brec_find(fd); | 157 | res = hfs_brec_find(fd, hfs_find_rec_by_key); |
| 158 | if (res && res != -ENOENT) | 158 | if (res && res != -ENOENT) |
| 159 | return res; | 159 | return res; |
| 160 | if (fd->key->ext.cnid != fd->search_key->ext.cnid || | 160 | 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 a6da86b1b4c1..05b11f36024c 100644 --- a/fs/hfsplus/hfsplus_fs.h +++ b/fs/hfsplus/hfsplus_fs.h | |||
| @@ -23,6 +23,7 @@ | |||
| 23 | #define DBG_SUPER 0x00000010 | 23 | #define DBG_SUPER 0x00000010 |
| 24 | #define DBG_EXTENT 0x00000020 | 24 | #define DBG_EXTENT 0x00000020 |
| 25 | #define DBG_BITMAP 0x00000040 | 25 | #define DBG_BITMAP 0x00000040 |
| 26 | #define DBG_ATTR_MOD 0x00000080 | ||
| 26 | 27 | ||
| 27 | #if 0 | 28 | #if 0 |
| 28 | #define DBG_MASK (DBG_EXTENT|DBG_INODE|DBG_BNODE_MOD) | 29 | #define DBG_MASK (DBG_EXTENT|DBG_INODE|DBG_BNODE_MOD) |
| @@ -46,6 +47,13 @@ typedef int (*btree_keycmp)(const hfsplus_btree_key *, | |||
| 46 | 47 | ||
| 47 | #define NODE_HASH_SIZE 256 | 48 | #define NODE_HASH_SIZE 256 |
| 48 | 49 | ||
| 50 | /* B-tree mutex nested subclasses */ | ||
| 51 | enum hfsplus_btree_mutex_classes { | ||
| 52 | CATALOG_BTREE_MUTEX, | ||
| 53 | EXTENTS_BTREE_MUTEX, | ||
| 54 | ATTR_BTREE_MUTEX, | ||
| 55 | }; | ||
| 56 | |||
| 49 | /* An HFS+ BTree held in memory */ | 57 | /* An HFS+ BTree held in memory */ |
| 50 | struct hfs_btree { | 58 | struct hfs_btree { |
| 51 | struct super_block *sb; | 59 | struct super_block *sb; |
| @@ -223,6 +231,7 @@ struct hfsplus_inode_info { | |||
| 223 | #define HFSPLUS_I_CAT_DIRTY 1 /* has changes in the catalog tree */ | 231 | #define HFSPLUS_I_CAT_DIRTY 1 /* has changes in the catalog tree */ |
| 224 | #define HFSPLUS_I_EXT_DIRTY 2 /* has changes in the extent tree */ | 232 | #define HFSPLUS_I_EXT_DIRTY 2 /* has changes in the extent tree */ |
| 225 | #define HFSPLUS_I_ALLOC_DIRTY 3 /* has changes in the allocation file */ | 233 | #define HFSPLUS_I_ALLOC_DIRTY 3 /* has changes in the allocation file */ |
| 234 | #define HFSPLUS_I_ATTR_DIRTY 4 /* has changes in the attributes tree */ | ||
| 226 | 235 | ||
| 227 | #define HFSPLUS_IS_RSRC(inode) \ | 236 | #define HFSPLUS_IS_RSRC(inode) \ |
| 228 | test_bit(HFSPLUS_I_RSRC, &HFSPLUS_I(inode)->flags) | 237 | test_bit(HFSPLUS_I_RSRC, &HFSPLUS_I(inode)->flags) |
| @@ -302,7 +311,7 @@ static inline unsigned short hfsplus_min_io_size(struct super_block *sb) | |||
| 302 | #define hfs_brec_remove hfsplus_brec_remove | 311 | #define hfs_brec_remove hfsplus_brec_remove |
| 303 | #define hfs_find_init hfsplus_find_init | 312 | #define hfs_find_init hfsplus_find_init |
| 304 | #define hfs_find_exit hfsplus_find_exit | 313 | #define hfs_find_exit hfsplus_find_exit |
| 305 | #define __hfs_brec_find __hplusfs_brec_find | 314 | #define __hfs_brec_find __hfsplus_brec_find |
| 306 | #define hfs_brec_find hfsplus_brec_find | 315 | #define hfs_brec_find hfsplus_brec_find |
| 307 | #define hfs_brec_read hfsplus_brec_read | 316 | #define hfs_brec_read hfsplus_brec_read |
| 308 | #define hfs_brec_goto hfsplus_brec_goto | 317 | #define hfs_brec_goto hfsplus_brec_goto |
| @@ -324,10 +333,33 @@ static inline unsigned short hfsplus_min_io_size(struct super_block *sb) | |||
| 324 | */ | 333 | */ |
| 325 | #define HFSPLUS_IOC_BLESS _IO('h', 0x80) | 334 | #define HFSPLUS_IOC_BLESS _IO('h', 0x80) |
| 326 | 335 | ||
| 336 | typedef int (*search_strategy_t)(struct hfs_bnode *, | ||
| 337 | struct hfs_find_data *, | ||
| 338 | int *, int *, int *); | ||
| 339 | |||
| 327 | /* | 340 | /* |
| 328 | * Functions in any *.c used in other files | 341 | * Functions in any *.c used in other files |
| 329 | */ | 342 | */ |
| 330 | 343 | ||
| 344 | /* attributes.c */ | ||
| 345 | int hfsplus_create_attr_tree_cache(void); | ||
| 346 | void hfsplus_destroy_attr_tree_cache(void); | ||
| 347 | hfsplus_attr_entry *hfsplus_alloc_attr_entry(void); | ||
| 348 | void hfsplus_destroy_attr_entry(hfsplus_attr_entry *entry_p); | ||
| 349 | int hfsplus_attr_bin_cmp_key(const hfsplus_btree_key *, | ||
| 350 | const hfsplus_btree_key *); | ||
| 351 | int hfsplus_attr_build_key(struct super_block *, hfsplus_btree_key *, | ||
| 352 | u32, const char *); | ||
| 353 | void hfsplus_attr_build_key_uni(hfsplus_btree_key *key, | ||
| 354 | u32 cnid, | ||
| 355 | struct hfsplus_attr_unistr *name); | ||
| 356 | int hfsplus_find_attr(struct super_block *, u32, | ||
| 357 | const char *, struct hfs_find_data *); | ||
| 358 | int hfsplus_attr_exists(struct inode *inode, const char *name); | ||
| 359 | int hfsplus_create_attr(struct inode *, const char *, const void *, size_t); | ||
| 360 | int hfsplus_delete_attr(struct inode *, const char *); | ||
| 361 | int hfsplus_delete_all_attrs(struct inode *dir, u32 cnid); | ||
| 362 | |||
| 331 | /* bitmap.c */ | 363 | /* bitmap.c */ |
| 332 | int hfsplus_block_allocate(struct super_block *, u32, u32, u32 *); | 364 | int hfsplus_block_allocate(struct super_block *, u32, u32, u32 *); |
| 333 | int hfsplus_block_free(struct super_block *, u32, u32); | 365 | int hfsplus_block_free(struct super_block *, u32, u32); |
| @@ -369,8 +401,15 @@ int hfs_brec_remove(struct hfs_find_data *); | |||
| 369 | /* bfind.c */ | 401 | /* bfind.c */ |
| 370 | int hfs_find_init(struct hfs_btree *, struct hfs_find_data *); | 402 | int hfs_find_init(struct hfs_btree *, struct hfs_find_data *); |
| 371 | void hfs_find_exit(struct hfs_find_data *); | 403 | void hfs_find_exit(struct hfs_find_data *); |
| 372 | int __hfs_brec_find(struct hfs_bnode *, struct hfs_find_data *); | 404 | int hfs_find_1st_rec_by_cnid(struct hfs_bnode *, |
| 373 | int hfs_brec_find(struct hfs_find_data *); | 405 | struct hfs_find_data *, |
| 406 | int *, int *, int *); | ||
| 407 | int hfs_find_rec_by_key(struct hfs_bnode *, | ||
| 408 | struct hfs_find_data *, | ||
| 409 | int *, int *, int *); | ||
| 410 | int __hfs_brec_find(struct hfs_bnode *, struct hfs_find_data *, | ||
| 411 | search_strategy_t); | ||
| 412 | int hfs_brec_find(struct hfs_find_data *, search_strategy_t); | ||
| 374 | int hfs_brec_read(struct hfs_find_data *, void *, int); | 413 | int hfs_brec_read(struct hfs_find_data *, void *, int); |
| 375 | int hfs_brec_goto(struct hfs_find_data *, int); | 414 | int hfs_brec_goto(struct hfs_find_data *, int); |
| 376 | 415 | ||
| @@ -417,11 +456,6 @@ int hfsplus_file_fsync(struct file *file, loff_t start, loff_t end, | |||
| 417 | 456 | ||
| 418 | /* ioctl.c */ | 457 | /* ioctl.c */ |
| 419 | long hfsplus_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); | 458 | long hfsplus_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); |
| 420 | int hfsplus_setxattr(struct dentry *dentry, const char *name, | ||
| 421 | const void *value, size_t size, int flags); | ||
| 422 | ssize_t hfsplus_getxattr(struct dentry *dentry, const char *name, | ||
| 423 | void *value, size_t size); | ||
| 424 | ssize_t hfsplus_listxattr(struct dentry *dentry, char *buffer, size_t size); | ||
| 425 | 459 | ||
| 426 | /* options.c */ | 460 | /* options.c */ |
| 427 | int hfsplus_parse_options(char *, struct hfsplus_sb_info *); | 461 | int hfsplus_parse_options(char *, struct hfsplus_sb_info *); |
| @@ -446,7 +480,7 @@ int hfsplus_strcmp(const struct hfsplus_unistr *, | |||
| 446 | int hfsplus_uni2asc(struct super_block *, | 480 | int hfsplus_uni2asc(struct super_block *, |
| 447 | const struct hfsplus_unistr *, char *, int *); | 481 | const struct hfsplus_unistr *, char *, int *); |
| 448 | int hfsplus_asc2uni(struct super_block *, | 482 | int hfsplus_asc2uni(struct super_block *, |
| 449 | struct hfsplus_unistr *, const char *, int); | 483 | struct hfsplus_unistr *, int, const char *, int); |
| 450 | int hfsplus_hash_dentry(const struct dentry *dentry, | 484 | int hfsplus_hash_dentry(const struct dentry *dentry, |
| 451 | const struct inode *inode, struct qstr *str); | 485 | const struct inode *inode, struct qstr *str); |
| 452 | int hfsplus_compare_dentry(const struct dentry *parent, | 486 | int hfsplus_compare_dentry(const struct dentry *parent, |
diff --git a/fs/hfsplus/inode.c b/fs/hfsplus/inode.c index dcd05be5344b..160ccc9cdb4b 100644 --- a/fs/hfsplus/inode.c +++ b/fs/hfsplus/inode.c | |||
| @@ -17,6 +17,7 @@ | |||
| 17 | 17 | ||
| 18 | #include "hfsplus_fs.h" | 18 | #include "hfsplus_fs.h" |
| 19 | #include "hfsplus_raw.h" | 19 | #include "hfsplus_raw.h" |
| 20 | #include "xattr.h" | ||
| 20 | 21 | ||
| 21 | static int hfsplus_readpage(struct file *file, struct page *page) | 22 | static int hfsplus_readpage(struct file *file, struct page *page) |
| 22 | { | 23 | { |
| @@ -348,6 +349,18 @@ int hfsplus_file_fsync(struct file *file, loff_t start, loff_t end, | |||
| 348 | error = error2; | 349 | error = error2; |
| 349 | } | 350 | } |
| 350 | 351 | ||
| 352 | if (test_and_clear_bit(HFSPLUS_I_ATTR_DIRTY, &hip->flags)) { | ||
| 353 | if (sbi->attr_tree) { | ||
| 354 | error2 = | ||
| 355 | filemap_write_and_wait( | ||
| 356 | sbi->attr_tree->inode->i_mapping); | ||
| 357 | if (!error) | ||
| 358 | error = error2; | ||
| 359 | } else { | ||
| 360 | printk(KERN_ERR "hfs: sync non-existent attributes tree\n"); | ||
| 361 | } | ||
| 362 | } | ||
| 363 | |||
| 351 | if (test_and_clear_bit(HFSPLUS_I_ALLOC_DIRTY, &hip->flags)) { | 364 | if (test_and_clear_bit(HFSPLUS_I_ALLOC_DIRTY, &hip->flags)) { |
| 352 | error2 = filemap_write_and_wait(sbi->alloc_file->i_mapping); | 365 | error2 = filemap_write_and_wait(sbi->alloc_file->i_mapping); |
| 353 | if (!error) | 366 | if (!error) |
| @@ -365,9 +378,10 @@ int hfsplus_file_fsync(struct file *file, loff_t start, loff_t end, | |||
| 365 | static const struct inode_operations hfsplus_file_inode_operations = { | 378 | static const struct inode_operations hfsplus_file_inode_operations = { |
| 366 | .lookup = hfsplus_file_lookup, | 379 | .lookup = hfsplus_file_lookup, |
| 367 | .setattr = hfsplus_setattr, | 380 | .setattr = hfsplus_setattr, |
| 368 | .setxattr = hfsplus_setxattr, | 381 | .setxattr = generic_setxattr, |
| 369 | .getxattr = hfsplus_getxattr, | 382 | .getxattr = generic_getxattr, |
| 370 | .listxattr = hfsplus_listxattr, | 383 | .listxattr = hfsplus_listxattr, |
| 384 | .removexattr = hfsplus_removexattr, | ||
| 371 | }; | 385 | }; |
| 372 | 386 | ||
| 373 | static const struct file_operations hfsplus_file_operations = { | 387 | static const struct file_operations hfsplus_file_operations = { |
diff --git a/fs/hfsplus/ioctl.c b/fs/hfsplus/ioctl.c index e3c4c4209428..d3ff5cc317d7 100644 --- a/fs/hfsplus/ioctl.c +++ b/fs/hfsplus/ioctl.c | |||
| @@ -16,7 +16,6 @@ | |||
| 16 | #include <linux/fs.h> | 16 | #include <linux/fs.h> |
| 17 | #include <linux/mount.h> | 17 | #include <linux/mount.h> |
| 18 | #include <linux/sched.h> | 18 | #include <linux/sched.h> |
| 19 | #include <linux/xattr.h> | ||
| 20 | #include <asm/uaccess.h> | 19 | #include <asm/uaccess.h> |
| 21 | #include "hfsplus_fs.h" | 20 | #include "hfsplus_fs.h" |
| 22 | 21 | ||
| @@ -151,110 +150,3 @@ long hfsplus_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | |||
| 151 | return -ENOTTY; | 150 | return -ENOTTY; |
| 152 | } | 151 | } |
| 153 | } | 152 | } |
| 154 | |||
| 155 | int hfsplus_setxattr(struct dentry *dentry, const char *name, | ||
| 156 | const void *value, size_t size, int flags) | ||
| 157 | { | ||
| 158 | struct inode *inode = dentry->d_inode; | ||
| 159 | struct hfs_find_data fd; | ||
| 160 | hfsplus_cat_entry entry; | ||
| 161 | struct hfsplus_cat_file *file; | ||
| 162 | int res; | ||
| 163 | |||
| 164 | if (!S_ISREG(inode->i_mode) || HFSPLUS_IS_RSRC(inode)) | ||
| 165 | return -EOPNOTSUPP; | ||
| 166 | |||
| 167 | res = hfs_find_init(HFSPLUS_SB(inode->i_sb)->cat_tree, &fd); | ||
| 168 | if (res) | ||
| 169 | return res; | ||
| 170 | res = hfsplus_find_cat(inode->i_sb, inode->i_ino, &fd); | ||
| 171 | if (res) | ||
| 172 | goto out; | ||
| 173 | hfs_bnode_read(fd.bnode, &entry, fd.entryoffset, | ||
| 174 | sizeof(struct hfsplus_cat_file)); | ||
| 175 | file = &entry.file; | ||
| 176 | |||
| 177 | if (!strcmp(name, "hfs.type")) { | ||
| 178 | if (size == 4) | ||
| 179 | memcpy(&file->user_info.fdType, value, 4); | ||
| 180 | else | ||
| 181 | res = -ERANGE; | ||
| 182 | } else if (!strcmp(name, "hfs.creator")) { | ||
| 183 | if (size == 4) | ||
| 184 | memcpy(&file->user_info.fdCreator, value, 4); | ||
| 185 | else | ||
| 186 | res = -ERANGE; | ||
| 187 | } else | ||
| 188 | res = -EOPNOTSUPP; | ||
| 189 | if (!res) { | ||
| 190 | hfs_bnode_write(fd.bnode, &entry, fd.entryoffset, | ||
| 191 | sizeof(struct hfsplus_cat_file)); | ||
| 192 | hfsplus_mark_inode_dirty(inode, HFSPLUS_I_CAT_DIRTY); | ||
| 193 | } | ||
| 194 | out: | ||
| 195 | hfs_find_exit(&fd); | ||
| 196 | return res; | ||
| 197 | } | ||
| 198 | |||
| 199 | ssize_t hfsplus_getxattr(struct dentry *dentry, const char *name, | ||
| 200 | void *value, size_t size) | ||
| 201 | { | ||
| 202 | struct inode *inode = dentry->d_inode; | ||
| 203 | struct hfs_find_data fd; | ||
| 204 | hfsplus_cat_entry entry; | ||
| 205 | struct hfsplus_cat_file *file; | ||
| 206 | ssize_t res = 0; | ||
| 207 | |||
| 208 | if (!S_ISREG(inode->i_mode) || HFSPLUS_IS_RSRC(inode)) | ||
| 209 | return -EOPNOTSUPP; | ||
| 210 | |||
| 211 | if (size) { | ||
| 212 | res = hfs_find_init(HFSPLUS_SB(inode->i_sb)->cat_tree, &fd); | ||
| 213 | if (res) | ||
| 214 | return res; | ||
| 215 | res = hfsplus_find_cat(inode->i_sb, inode->i_ino, &fd); | ||
| 216 | if (res) | ||
| 217 | goto out; | ||
| 218 | hfs_bnode_read(fd.bnode, &entry, fd.entryoffset, | ||
| 219 | sizeof(struct hfsplus_cat_file)); | ||
| 220 | } | ||
| 221 | file = &entry.file; | ||
| 222 | |||
| 223 | if (!strcmp(name, "hfs.type")) { | ||
| 224 | if (size >= 4) { | ||
| 225 | memcpy(value, &file->user_info.fdType, 4); | ||
| 226 | res = 4; | ||
| 227 | } else | ||
| 228 | res = size ? -ERANGE : 4; | ||
| 229 | } else if (!strcmp(name, "hfs.creator")) { | ||
| 230 | if (size >= 4) { | ||
| 231 | memcpy(value, &file->user_info.fdCreator, 4); | ||
| 232 | res = 4; | ||
| 233 | } else | ||
| 234 | res = size ? -ERANGE : 4; | ||
| 235 | } else | ||
| 236 | res = -EOPNOTSUPP; | ||
| 237 | out: | ||
| 238 | if (size) | ||
| 239 | hfs_find_exit(&fd); | ||
| 240 | return res; | ||
| 241 | } | ||
| 242 | |||
| 243 | #define HFSPLUS_ATTRLIST_SIZE (sizeof("hfs.creator")+sizeof("hfs.type")) | ||
| 244 | |||
| 245 | ssize_t hfsplus_listxattr(struct dentry *dentry, char *buffer, size_t size) | ||
| 246 | { | ||
| 247 | struct inode *inode = dentry->d_inode; | ||
| 248 | |||
| 249 | if (!S_ISREG(inode->i_mode) || HFSPLUS_IS_RSRC(inode)) | ||
| 250 | return -EOPNOTSUPP; | ||
| 251 | |||
| 252 | if (!buffer || !size) | ||
| 253 | return HFSPLUS_ATTRLIST_SIZE; | ||
| 254 | if (size < HFSPLUS_ATTRLIST_SIZE) | ||
| 255 | return -ERANGE; | ||
| 256 | strcpy(buffer, "hfs.type"); | ||
| 257 | strcpy(buffer + sizeof("hfs.type"), "hfs.creator"); | ||
| 258 | |||
| 259 | return HFSPLUS_ATTRLIST_SIZE; | ||
| 260 | } | ||
diff --git a/fs/hfsplus/super.c b/fs/hfsplus/super.c index 796198d26553..974c26f96fae 100644 --- a/fs/hfsplus/super.c +++ b/fs/hfsplus/super.c | |||
| @@ -20,6 +20,7 @@ static struct inode *hfsplus_alloc_inode(struct super_block *sb); | |||
| 20 | static void hfsplus_destroy_inode(struct inode *inode); | 20 | static void hfsplus_destroy_inode(struct inode *inode); |
| 21 | 21 | ||
| 22 | #include "hfsplus_fs.h" | 22 | #include "hfsplus_fs.h" |
| 23 | #include "xattr.h" | ||
| 23 | 24 | ||
| 24 | static int hfsplus_system_read_inode(struct inode *inode) | 25 | static int hfsplus_system_read_inode(struct inode *inode) |
| 25 | { | 26 | { |
| @@ -118,6 +119,7 @@ static int hfsplus_system_write_inode(struct inode *inode) | |||
| 118 | case HFSPLUS_ATTR_CNID: | 119 | case HFSPLUS_ATTR_CNID: |
| 119 | fork = &vhdr->attr_file; | 120 | fork = &vhdr->attr_file; |
| 120 | tree = sbi->attr_tree; | 121 | tree = sbi->attr_tree; |
| 122 | break; | ||
| 121 | default: | 123 | default: |
| 122 | return -EIO; | 124 | return -EIO; |
| 123 | } | 125 | } |
| @@ -191,6 +193,12 @@ static int hfsplus_sync_fs(struct super_block *sb, int wait) | |||
| 191 | error2 = filemap_write_and_wait(sbi->ext_tree->inode->i_mapping); | 193 | error2 = filemap_write_and_wait(sbi->ext_tree->inode->i_mapping); |
| 192 | if (!error) | 194 | if (!error) |
| 193 | error = error2; | 195 | error = error2; |
| 196 | if (sbi->attr_tree) { | ||
| 197 | error2 = | ||
| 198 | filemap_write_and_wait(sbi->attr_tree->inode->i_mapping); | ||
| 199 | if (!error) | ||
| 200 | error = error2; | ||
| 201 | } | ||
| 194 | error2 = filemap_write_and_wait(sbi->alloc_file->i_mapping); | 202 | error2 = filemap_write_and_wait(sbi->alloc_file->i_mapping); |
| 195 | if (!error) | 203 | if (!error) |
| 196 | error = error2; | 204 | error = error2; |
| @@ -281,6 +289,7 @@ static void hfsplus_put_super(struct super_block *sb) | |||
| 281 | hfsplus_sync_fs(sb, 1); | 289 | hfsplus_sync_fs(sb, 1); |
| 282 | } | 290 | } |
| 283 | 291 | ||
| 292 | hfs_btree_close(sbi->attr_tree); | ||
| 284 | hfs_btree_close(sbi->cat_tree); | 293 | hfs_btree_close(sbi->cat_tree); |
| 285 | hfs_btree_close(sbi->ext_tree); | 294 | hfs_btree_close(sbi->ext_tree); |
| 286 | iput(sbi->alloc_file); | 295 | iput(sbi->alloc_file); |
| @@ -477,12 +486,20 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent) | |||
| 477 | printk(KERN_ERR "hfs: failed to load catalog file\n"); | 486 | printk(KERN_ERR "hfs: failed to load catalog file\n"); |
| 478 | goto out_close_ext_tree; | 487 | goto out_close_ext_tree; |
| 479 | } | 488 | } |
| 489 | if (vhdr->attr_file.total_blocks != 0) { | ||
| 490 | sbi->attr_tree = hfs_btree_open(sb, HFSPLUS_ATTR_CNID); | ||
| 491 | if (!sbi->attr_tree) { | ||
| 492 | printk(KERN_ERR "hfs: failed to load attributes file\n"); | ||
| 493 | goto out_close_cat_tree; | ||
| 494 | } | ||
| 495 | } | ||
| 496 | sb->s_xattr = hfsplus_xattr_handlers; | ||
| 480 | 497 | ||
| 481 | inode = hfsplus_iget(sb, HFSPLUS_ALLOC_CNID); | 498 | inode = hfsplus_iget(sb, HFSPLUS_ALLOC_CNID); |
| 482 | if (IS_ERR(inode)) { | 499 | if (IS_ERR(inode)) { |
| 483 | printk(KERN_ERR "hfs: failed to load allocation file\n"); | 500 | printk(KERN_ERR "hfs: failed to load allocation file\n"); |
| 484 | err = PTR_ERR(inode); | 501 | err = PTR_ERR(inode); |
| 485 | goto out_close_cat_tree; | 502 | goto out_close_attr_tree; |
| 486 | } | 503 | } |
| 487 | sbi->alloc_file = inode; | 504 | sbi->alloc_file = inode; |
| 488 | 505 | ||
| @@ -542,10 +559,27 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent) | |||
| 542 | } | 559 | } |
| 543 | err = hfsplus_create_cat(sbi->hidden_dir->i_ino, root, | 560 | err = hfsplus_create_cat(sbi->hidden_dir->i_ino, root, |
| 544 | &str, sbi->hidden_dir); | 561 | &str, sbi->hidden_dir); |
| 545 | mutex_unlock(&sbi->vh_mutex); | 562 | if (err) { |
| 546 | if (err) | 563 | mutex_unlock(&sbi->vh_mutex); |
| 564 | goto out_put_hidden_dir; | ||
| 565 | } | ||
| 566 | |||
| 567 | err = hfsplus_init_inode_security(sbi->hidden_dir, | ||
| 568 | root, &str); | ||
| 569 | if (err == -EOPNOTSUPP) | ||
| 570 | err = 0; /* Operation is not supported. */ | ||
| 571 | else if (err) { | ||
| 572 | /* | ||
| 573 | * Try to delete anyway without | ||
| 574 | * error analysis. | ||
| 575 | */ | ||
| 576 | hfsplus_delete_cat(sbi->hidden_dir->i_ino, | ||
| 577 | root, &str); | ||
| 578 | mutex_unlock(&sbi->vh_mutex); | ||
| 547 | goto out_put_hidden_dir; | 579 | goto out_put_hidden_dir; |
| 580 | } | ||
| 548 | 581 | ||
| 582 | mutex_unlock(&sbi->vh_mutex); | ||
| 549 | hfsplus_mark_inode_dirty(sbi->hidden_dir, | 583 | hfsplus_mark_inode_dirty(sbi->hidden_dir, |
| 550 | HFSPLUS_I_CAT_DIRTY); | 584 | HFSPLUS_I_CAT_DIRTY); |
| 551 | } | 585 | } |
| @@ -562,6 +596,8 @@ out_put_root: | |||
| 562 | sb->s_root = NULL; | 596 | sb->s_root = NULL; |
| 563 | out_put_alloc_file: | 597 | out_put_alloc_file: |
| 564 | iput(sbi->alloc_file); | 598 | iput(sbi->alloc_file); |
| 599 | out_close_attr_tree: | ||
| 600 | hfs_btree_close(sbi->attr_tree); | ||
| 565 | out_close_cat_tree: | 601 | out_close_cat_tree: |
| 566 | hfs_btree_close(sbi->cat_tree); | 602 | hfs_btree_close(sbi->cat_tree); |
| 567 | out_close_ext_tree: | 603 | out_close_ext_tree: |
| @@ -635,9 +671,20 @@ static int __init init_hfsplus_fs(void) | |||
| 635 | hfsplus_init_once); | 671 | hfsplus_init_once); |
| 636 | if (!hfsplus_inode_cachep) | 672 | if (!hfsplus_inode_cachep) |
| 637 | return -ENOMEM; | 673 | return -ENOMEM; |
| 674 | err = hfsplus_create_attr_tree_cache(); | ||
| 675 | if (err) | ||
| 676 | goto destroy_inode_cache; | ||
| 638 | err = register_filesystem(&hfsplus_fs_type); | 677 | err = register_filesystem(&hfsplus_fs_type); |
| 639 | if (err) | 678 | if (err) |
| 640 | kmem_cache_destroy(hfsplus_inode_cachep); | 679 | goto destroy_attr_tree_cache; |
| 680 | return 0; | ||
| 681 | |||
| 682 | destroy_attr_tree_cache: | ||
| 683 | hfsplus_destroy_attr_tree_cache(); | ||
| 684 | |||
| 685 | destroy_inode_cache: | ||
| 686 | kmem_cache_destroy(hfsplus_inode_cachep); | ||
| 687 | |||
| 641 | return err; | 688 | return err; |
| 642 | } | 689 | } |
| 643 | 690 | ||
| @@ -650,6 +697,7 @@ static void __exit exit_hfsplus_fs(void) | |||
| 650 | * destroy cache. | 697 | * destroy cache. |
| 651 | */ | 698 | */ |
| 652 | rcu_barrier(); | 699 | rcu_barrier(); |
| 700 | hfsplus_destroy_attr_tree_cache(); | ||
| 653 | kmem_cache_destroy(hfsplus_inode_cachep); | 701 | kmem_cache_destroy(hfsplus_inode_cachep); |
| 654 | } | 702 | } |
| 655 | 703 | ||
diff --git a/fs/hfsplus/unicode.c b/fs/hfsplus/unicode.c index a32998f29f0b..2c2e47dcfdd8 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) | |||
| 295 | return hfsplus_decompose_table + (off / 4); | 295 | return hfsplus_decompose_table + (off / 4); |
| 296 | } | 296 | } |
| 297 | 297 | ||
| 298 | int hfsplus_asc2uni(struct super_block *sb, struct hfsplus_unistr *ustr, | 298 | int hfsplus_asc2uni(struct super_block *sb, |
| 299 | struct hfsplus_unistr *ustr, int max_unistr_len, | ||
| 299 | const char *astr, int len) | 300 | const char *astr, int len) |
| 300 | { | 301 | { |
| 301 | int size, dsize, decompose; | 302 | int size, dsize, decompose; |
| @@ -303,7 +304,7 @@ int hfsplus_asc2uni(struct super_block *sb, struct hfsplus_unistr *ustr, | |||
| 303 | wchar_t c; | 304 | wchar_t c; |
| 304 | 305 | ||
| 305 | decompose = !test_bit(HFSPLUS_SB_NODECOMPOSE, &HFSPLUS_SB(sb)->flags); | 306 | decompose = !test_bit(HFSPLUS_SB_NODECOMPOSE, &HFSPLUS_SB(sb)->flags); |
| 306 | while (outlen < HFSPLUS_MAX_STRLEN && len > 0) { | 307 | while (outlen < max_unistr_len && len > 0) { |
| 307 | size = asc2unichar(sb, astr, len, &c); | 308 | size = asc2unichar(sb, astr, len, &c); |
| 308 | 309 | ||
| 309 | if (decompose) | 310 | if (decompose) |
| @@ -311,7 +312,7 @@ int hfsplus_asc2uni(struct super_block *sb, struct hfsplus_unistr *ustr, | |||
| 311 | else | 312 | else |
| 312 | dstr = NULL; | 313 | dstr = NULL; |
| 313 | if (dstr) { | 314 | if (dstr) { |
| 314 | if (outlen + dsize > HFSPLUS_MAX_STRLEN) | 315 | if (outlen + dsize > max_unistr_len) |
| 315 | break; | 316 | break; |
| 316 | do { | 317 | do { |
| 317 | ustr->unicode[outlen++] = cpu_to_be16(*dstr++); | 318 | ustr->unicode[outlen++] = cpu_to_be16(*dstr++); |
