2 * linux/fs/hfsplus/bfind.c
5 * Brad Boyer (flar@allandria.com)
6 * (C) 2003 Ardis Technologies <roman@ardistech.com>
8 * Search routines for btrees
11 #include <linux/slab.h>
12 #include "hfsplus_fs.h"
14 int hfs_find_init(struct hfs_btree
*tree
, struct hfs_find_data
*fd
)
20 ptr
= kmalloc(tree
->max_key_len
* 2 + 4, GFP_KERNEL
);
24 fd
->key
= ptr
+ tree
->max_key_len
+ 2;
25 dprint(DBG_BNODE_REFS
, "find_init: %d (%p)\n",
26 tree
->cnid
, __builtin_return_address(0));
28 case HFSPLUS_CAT_CNID
:
29 mutex_lock_nested(&tree
->tree_lock
, CATALOG_BTREE_MUTEX
);
31 case HFSPLUS_EXT_CNID
:
32 mutex_lock_nested(&tree
->tree_lock
, EXTENTS_BTREE_MUTEX
);
34 case HFSPLUS_ATTR_CNID
:
35 mutex_lock_nested(&tree
->tree_lock
, ATTR_BTREE_MUTEX
);
43 void hfs_find_exit(struct hfs_find_data
*fd
)
45 hfs_bnode_put(fd
->bnode
);
46 kfree(fd
->search_key
);
47 dprint(DBG_BNODE_REFS
, "find_exit: %d (%p)\n",
48 fd
->tree
->cnid
, __builtin_return_address(0));
49 mutex_unlock(&fd
->tree
->tree_lock
);
53 int hfs_find_1st_rec_by_cnid(struct hfs_bnode
*bnode
,
54 struct hfs_find_data
*fd
,
59 __be32 cur_cnid
, search_cnid
;
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
;
73 if (cur_cnid
== search_cnid
) {
75 if ((*begin
) == (*end
))
78 if (be32_to_cpu(cur_cnid
) < be32_to_cpu(search_cnid
))
79 (*begin
) = (*cur_rec
) + 1;
81 (*end
) = (*cur_rec
) - 1;
87 int hfs_find_rec_by_key(struct hfs_bnode
*bnode
,
88 struct hfs_find_data
*fd
,
95 cmpval
= bnode
->tree
->keycmp(fd
->key
, fd
->search_key
);
101 (*begin
) = (*cur_rec
) + 1;
103 *(end
) = (*cur_rec
) - 1;
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
)
112 u16 off
, len
, keylen
;
121 e
= bnode
->num_recs
- 1;
125 len
= hfs_brec_lenoff(bnode
, rec
, &off
);
126 keylen
= hfs_brec_keylen(bnode
, rec
);
131 hfs_bnode_read(bnode
, fd
->key
, off
, keylen
);
132 if (rec_found(bnode
, fd
, &b
, &e
, &rec
)) {
138 if (rec
!= e
&& e
>= 0) {
139 len
= hfs_brec_lenoff(bnode
, e
, &off
);
140 keylen
= hfs_brec_keylen(bnode
, e
);
145 hfs_bnode_read(bnode
, fd
->key
, off
, keylen
);
151 fd
->keylength
= keylen
;
152 fd
->entryoffset
= off
+ keylen
;
153 fd
->entrylength
= len
- keylen
;
159 /* Traverse a B*Tree from the root to a leaf finding best fit to key */
160 /* Return allocated copy of node found, set recnum to best record */
161 int hfs_brec_find(struct hfs_find_data
*fd
, search_strategy_t do_key_compare
)
163 struct hfs_btree
*tree
;
164 struct hfs_bnode
*bnode
;
171 hfs_bnode_put(fd
->bnode
);
176 height
= tree
->depth
;
180 bnode
= hfs_bnode_find(tree
, nidx
);
182 res
= PTR_ERR(bnode
);
186 if (bnode
->height
!= height
)
188 if (bnode
->type
!= (--height
? HFS_NODE_INDEX
: HFS_NODE_LEAF
))
190 bnode
->parent
= parent
;
192 res
= __hfs_brec_find(bnode
, fd
, do_key_compare
);
199 hfs_bnode_read(bnode
, &data
, fd
->entryoffset
, 4);
200 nidx
= be32_to_cpu(data
);
201 hfs_bnode_put(bnode
);
207 printk(KERN_ERR
"hfs: inconsistency in B*Tree (%d,%d,%d,%u,%u)\n",
208 height
, bnode
->height
, bnode
->type
, nidx
, parent
);
211 hfs_bnode_put(bnode
);
215 int hfs_brec_read(struct hfs_find_data
*fd
, void *rec
, int rec_len
)
219 res
= hfs_brec_find(fd
, hfs_find_rec_by_key
);
222 if (fd
->entrylength
> rec_len
)
224 hfs_bnode_read(fd
->bnode
, rec
, fd
->entryoffset
, fd
->entrylength
);
228 int hfs_brec_goto(struct hfs_find_data
*fd
, int cnt
)
230 struct hfs_btree
*tree
;
231 struct hfs_bnode
*bnode
;
233 u16 off
, len
, keylen
;
240 while (cnt
> fd
->record
) {
241 cnt
-= fd
->record
+ 1;
242 fd
->record
= bnode
->num_recs
- 1;
248 hfs_bnode_put(bnode
);
249 bnode
= hfs_bnode_find(tree
, idx
);
251 res
= PTR_ERR(bnode
);
258 while (cnt
>= bnode
->num_recs
- fd
->record
) {
259 cnt
-= bnode
->num_recs
- fd
->record
;
266 hfs_bnode_put(bnode
);
267 bnode
= hfs_bnode_find(tree
, idx
);
269 res
= PTR_ERR(bnode
);
277 len
= hfs_brec_lenoff(bnode
, fd
->record
, &off
);
278 keylen
= hfs_brec_keylen(bnode
, fd
->record
);
284 fd
->keylength
= keylen
;
285 fd
->entryoffset
= off
+ keylen
;
286 fd
->entrylength
= len
- keylen
;
287 hfs_bnode_read(bnode
, fd
->key
, off
, keylen
);