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/hfsplus/bfind.c | |
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/hfsplus/bfind.c')
-rw-r--r-- | fs/hfsplus/bfind.c | 93 |
1 files changed, 80 insertions, 13 deletions
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) |