bfind.c 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * linux/fs/hfsplus/bfind.c
  4. *
  5. * Copyright (C) 2001
  6. * Brad Boyer (flar@allandria.com)
  7. * (C) 2003 Ardis Technologies <roman@ardistech.com>
  8. *
  9. * Search routines for btrees
  10. */
  11. #include <linux/slab.h>
  12. #include "hfsplus_fs.h"
  13. int hfs_find_init(struct hfs_btree *tree, struct hfs_find_data *fd)
  14. {
  15. void *ptr;
  16. fd->tree = tree;
  17. fd->bnode = NULL;
  18. ptr = kzalloc(tree->max_key_len * 2 + 4, GFP_KERNEL);
  19. if (!ptr)
  20. return -ENOMEM;
  21. fd->search_key = ptr;
  22. fd->key = ptr + tree->max_key_len + 2;
  23. hfs_dbg("cnid %d, caller %ps\n",
  24. tree->cnid, __builtin_return_address(0));
  25. mutex_lock_nested(&tree->tree_lock,
  26. hfsplus_btree_lock_class(tree));
  27. return 0;
  28. }
  29. void hfs_find_exit(struct hfs_find_data *fd)
  30. {
  31. hfs_bnode_put(fd->bnode);
  32. kfree(fd->search_key);
  33. hfs_dbg("cnid %d, caller %ps\n",
  34. fd->tree->cnid, __builtin_return_address(0));
  35. mutex_unlock(&fd->tree->tree_lock);
  36. fd->tree = NULL;
  37. }
  38. int hfs_find_1st_rec_by_cnid(struct hfs_bnode *bnode,
  39. struct hfs_find_data *fd,
  40. int *begin,
  41. int *end,
  42. int *cur_rec)
  43. {
  44. __be32 cur_cnid;
  45. __be32 search_cnid;
  46. if (bnode->tree->cnid == HFSPLUS_EXT_CNID) {
  47. cur_cnid = fd->key->ext.cnid;
  48. search_cnid = fd->search_key->ext.cnid;
  49. } else if (bnode->tree->cnid == HFSPLUS_CAT_CNID) {
  50. cur_cnid = fd->key->cat.parent;
  51. search_cnid = fd->search_key->cat.parent;
  52. } else if (bnode->tree->cnid == HFSPLUS_ATTR_CNID) {
  53. cur_cnid = fd->key->attr.cnid;
  54. search_cnid = fd->search_key->attr.cnid;
  55. } else {
  56. cur_cnid = 0; /* used-uninitialized warning */
  57. search_cnid = 0;
  58. BUG();
  59. }
  60. if (cur_cnid == search_cnid) {
  61. (*end) = (*cur_rec);
  62. if ((*begin) == (*end))
  63. return 1;
  64. } else {
  65. if (be32_to_cpu(cur_cnid) < be32_to_cpu(search_cnid))
  66. (*begin) = (*cur_rec) + 1;
  67. else
  68. (*end) = (*cur_rec) - 1;
  69. }
  70. return 0;
  71. }
  72. int hfs_find_rec_by_key(struct hfs_bnode *bnode,
  73. struct hfs_find_data *fd,
  74. int *begin,
  75. int *end,
  76. int *cur_rec)
  77. {
  78. int cmpval;
  79. cmpval = bnode->tree->keycmp(fd->key, fd->search_key);
  80. if (!cmpval) {
  81. (*end) = (*cur_rec);
  82. return 1;
  83. }
  84. if (cmpval < 0)
  85. (*begin) = (*cur_rec) + 1;
  86. else
  87. *(end) = (*cur_rec) - 1;
  88. return 0;
  89. }
  90. /* Find the record in bnode that best matches key (not greater than...)*/
  91. int __hfs_brec_find(struct hfs_bnode *bnode, struct hfs_find_data *fd,
  92. search_strategy_t rec_found)
  93. {
  94. u16 off, len, keylen;
  95. int rec;
  96. int b, e;
  97. int res;
  98. BUG_ON(!rec_found);
  99. b = 0;
  100. e = bnode->num_recs - 1;
  101. res = -ENOENT;
  102. do {
  103. rec = (e + b) / 2;
  104. len = hfs_brec_lenoff(bnode, rec, &off);
  105. keylen = hfs_brec_keylen(bnode, rec);
  106. if (keylen == 0) {
  107. res = -EINVAL;
  108. goto fail;
  109. }
  110. hfs_bnode_read(bnode, fd->key, off, keylen);
  111. if (rec_found(bnode, fd, &b, &e, &rec)) {
  112. res = 0;
  113. goto done;
  114. }
  115. } while (b <= e);
  116. if (rec != e && e >= 0) {
  117. len = hfs_brec_lenoff(bnode, e, &off);
  118. keylen = hfs_brec_keylen(bnode, e);
  119. if (keylen == 0) {
  120. res = -EINVAL;
  121. goto fail;
  122. }
  123. hfs_bnode_read(bnode, fd->key, off, keylen);
  124. }
  125. done:
  126. fd->record = e;
  127. fd->keyoffset = off;
  128. fd->keylength = keylen;
  129. fd->entryoffset = off + keylen;
  130. fd->entrylength = len - keylen;
  131. fail:
  132. return res;
  133. }
  134. /* Traverse a B*Tree from the root to a leaf finding best fit to key */
  135. /* Return allocated copy of node found, set recnum to best record */
  136. int hfs_brec_find(struct hfs_find_data *fd, search_strategy_t do_key_compare)
  137. {
  138. struct hfs_btree *tree;
  139. struct hfs_bnode *bnode;
  140. u32 nidx, parent;
  141. __be32 data;
  142. int height, res;
  143. fd->record = -1;
  144. fd->keyoffset = -1;
  145. fd->keylength = -1;
  146. fd->entryoffset = -1;
  147. fd->entrylength = -1;
  148. tree = fd->tree;
  149. if (fd->bnode)
  150. hfs_bnode_put(fd->bnode);
  151. fd->bnode = NULL;
  152. nidx = tree->root;
  153. if (!nidx)
  154. return -ENOENT;
  155. height = tree->depth;
  156. res = 0;
  157. parent = 0;
  158. for (;;) {
  159. bnode = hfs_bnode_find(tree, nidx);
  160. if (IS_ERR(bnode)) {
  161. res = PTR_ERR(bnode);
  162. bnode = NULL;
  163. break;
  164. }
  165. if (bnode->height != height)
  166. goto invalid;
  167. if (bnode->type != (--height ? HFS_NODE_INDEX : HFS_NODE_LEAF))
  168. goto invalid;
  169. bnode->parent = parent;
  170. res = __hfs_brec_find(bnode, fd, do_key_compare);
  171. if (!height)
  172. break;
  173. if (fd->record < 0)
  174. goto release;
  175. parent = nidx;
  176. hfs_bnode_read(bnode, &data, fd->entryoffset, 4);
  177. nidx = be32_to_cpu(data);
  178. hfs_bnode_put(bnode);
  179. }
  180. fd->bnode = bnode;
  181. return res;
  182. invalid:
  183. pr_err("inconsistency in B*Tree (%d,%d,%d,%u,%u)\n",
  184. height, bnode->height, bnode->type, nidx, parent);
  185. res = -EIO;
  186. release:
  187. hfs_bnode_put(bnode);
  188. return res;
  189. }
  190. int hfs_brec_read(struct hfs_find_data *fd, void *rec, u32 rec_len)
  191. {
  192. int res;
  193. res = hfs_brec_find(fd, hfs_find_rec_by_key);
  194. if (res)
  195. return res;
  196. if (fd->entrylength > rec_len)
  197. return -EINVAL;
  198. hfs_bnode_read(fd->bnode, rec, fd->entryoffset, fd->entrylength);
  199. return 0;
  200. }
  201. int hfs_brec_goto(struct hfs_find_data *fd, int cnt)
  202. {
  203. struct hfs_btree *tree;
  204. struct hfs_bnode *bnode;
  205. int idx, res = 0;
  206. u16 off, len, keylen;
  207. bnode = fd->bnode;
  208. tree = bnode->tree;
  209. if (cnt < 0) {
  210. cnt = -cnt;
  211. while (cnt > fd->record) {
  212. cnt -= fd->record + 1;
  213. fd->record = bnode->num_recs - 1;
  214. idx = bnode->prev;
  215. if (!idx) {
  216. res = -ENOENT;
  217. goto out;
  218. }
  219. hfs_bnode_put(bnode);
  220. bnode = hfs_bnode_find(tree, idx);
  221. if (IS_ERR(bnode)) {
  222. res = PTR_ERR(bnode);
  223. bnode = NULL;
  224. goto out;
  225. }
  226. }
  227. fd->record -= cnt;
  228. } else {
  229. while (cnt >= bnode->num_recs - fd->record) {
  230. cnt -= bnode->num_recs - fd->record;
  231. fd->record = 0;
  232. idx = bnode->next;
  233. if (!idx) {
  234. res = -ENOENT;
  235. goto out;
  236. }
  237. hfs_bnode_put(bnode);
  238. bnode = hfs_bnode_find(tree, idx);
  239. if (IS_ERR(bnode)) {
  240. res = PTR_ERR(bnode);
  241. bnode = NULL;
  242. goto out;
  243. }
  244. }
  245. fd->record += cnt;
  246. }
  247. len = hfs_brec_lenoff(bnode, fd->record, &off);
  248. keylen = hfs_brec_keylen(bnode, fd->record);
  249. if (keylen == 0) {
  250. res = -EINVAL;
  251. goto out;
  252. }
  253. fd->keyoffset = off;
  254. fd->keylength = keylen;
  255. fd->entryoffset = off + keylen;
  256. fd->entrylength = len - keylen;
  257. hfs_bnode_read(bnode, fd->key, off, keylen);
  258. out:
  259. fd->bnode = bnode;
  260. return res;
  261. }