bfind.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:10k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  1. /*
  2.  * linux/fs/hfs/bfind.c
  3.  *
  4.  * Copyright (C) 1995, 1996  Paul H. Hargrove
  5.  * This file may be distributed under the terms of the GNU General Public License.
  6.  *
  7.  * This file contains the code to access records in a btree.
  8.  *
  9.  * "XXX" in a comment is a note to myself to consider changing something.
  10.  *
  11.  * In function preconditions the term "valid" applied to a pointer to
  12.  * a structure means that the pointer is non-NULL and the structure it
  13.  * points to has all fields initialized to consistent values.
  14.  */
  15. #include "hfs_btree.h"
  16. /*================ Global functions ================*/
  17. /*
  18.  * hfs_brec_relse()
  19.  *
  20.  * Description:
  21.  *   This function releases some of the nodes associated with a brec.
  22.  * Input Variable(s):
  23.  *   struct hfs_brec *brec: pointer to the brec to release some nodes from.
  24.  *   struct hfs_belem *elem: the last node to release or NULL for all
  25.  * Output Variable(s):
  26.  *   NONE
  27.  * Returns:
  28.  *   void
  29.  * Preconditions:
  30.  *   'brec' points to a "valid" (struct hfs_brec)
  31.  * Postconditions: 
  32.  *   All nodes between the indicated node and the beginning of the path
  33.  *    are released.
  34.  */
  35. void hfs_brec_relse(struct hfs_brec *brec, struct hfs_belem *elem)
  36. {
  37. if (!elem) {
  38. elem = brec->bottom;
  39. }
  40. while (brec->top <= elem) {
  41. hfs_bnode_relse(&brec->top->bnr);
  42. ++brec->top;
  43. }
  44. }
  45. /*
  46.  * hfs_bfind()
  47.  *
  48.  * Description:
  49.  *   This function has sole responsibility for locating existing
  50.  *   records in a B-tree.  Given a B-tree and a key it locates the
  51.  *   "greatest" record "less than or equal to" the given key.  The
  52.  *   exact behavior is determined by the bits of the flags variable as
  53.  *   follows:
  54.  *     ('flags' & HFS_LOCK_MASK):
  55.  *      The lock_type argument to be used when calling hfs_bnode_find().
  56.  *     HFS_BFIND_EXACT: only accept an exact match, otherwise take the
  57.  * "largest" record less than 'target' as a "match"
  58.  *     HFS_BFIND_LOCK: request HFS_LOCK_WRITE access to the node containing
  59.  * the "matching" record when it is located
  60.  *     HFS_BPATH_FIRST: keep access to internal nodes when accessing their
  61.  *      first child.
  62.  *     HFS_BPATH_OVERFLOW: keep access to internal nodes when the accessed
  63.  *      child is too full to insert another pointer record.
  64.  *     HFS_BPATH_UNDERFLOW: keep access to internal nodes when the accessed
  65.  *      child is would be less than half full upon removing a pointer record.
  66.  * Input Variable(s):
  67.  *   struct hfs_brec *brec: pointer to the (struct hfs_brec) to hold
  68.  *    the search results.
  69.  *   struct hfs_bkey *target: pointer to the (struct hfs_bkey)
  70.  *    to search for
  71.  *   int flags: bitwise OR of flags which determine the function's behavior
  72.  * Output Variable(s):
  73.  *   'brec' contains the results of the search on success or is invalid
  74.  *    on failure.
  75.  * Returns:
  76.  *   int: 0 or 1 on success or an error code on failure:
  77.  *     -EINVAL: one of the input variables was NULL.
  78.  *     -ENOENT: tree is valid but empty or no "matching" record was located.
  79.  *  If the HFS_BFIND_EXACT bit of 'flags' is not set then the case of no
  80.  *  matching record will give a 'brec' with a 'record' field of zero
  81.  *  rather than returning this error.
  82.  *     -EIO: an I/O operation or an assertion about the structure of a
  83.  *       valid B-tree failed indicating corruption of either the B-tree
  84.  *       structure on the disk or one of the in-core structures representing
  85.  *       the B-tree.
  86.  *  (This could also be returned if a kmalloc() call failed in a
  87.  *  subordinate routine that is intended to get the data from the
  88.  *  disk or the buffer cache.)
  89.  * Preconditions:
  90.  *   'brec' is NULL or points to a (struct hfs_brec) with a 'tree' field
  91.  *    which points to a valid (struct hfs_btree).
  92.  *   'target' is NULL or points to a "valid" (struct hfs_bkey)
  93.  * Postconditions:
  94.  *   If 'brec', 'brec->tree' or 'target' is NULL then -EINVAL is returned.
  95.  *   If 'brec', 'brec->tree' and 'target' are non-NULL but the tree
  96.  *   is empty then -ENOENT is returned.
  97.  *   If 'brec', 'brec->tree' and 'target' are non-NULL but the call to
  98.  *   hfs_brec_init() fails then '*brec' is NULL and -EIO is returned.
  99.  *   If 'brec', 'brec->tree' and 'target' are non-NULL and the tree is
  100.  *   non-empty then the tree is searched as follows:
  101.  *    If any call to hfs_brec_next() fails or returns a node that is
  102.  *     neither an index node nor a leaf node then -EIO is returned to
  103.  *     indicate that the B-tree or buffer-cache are corrupted.
  104.  *    If every record in the tree is "greater than" the given key
  105.  *     and the HFS_BFIND_EXACT bit of 'flags' is set then -ENOENT is returned.
  106.  *    If every record in the tree is "greater than" the given key
  107.  *     and the HFS_BFIND_EXACT bit of 'flags' is clear then 'brec' refers
  108.  *     to the first leaf node in the tree and has a 'record' field of
  109.  *     zero, and 1 is returned.
  110.  *    If a "matching" record is located with key "equal to" 'target'
  111.  *     then the return value is 0 and 'brec' indicates the record.
  112.  *    If a "matching" record is located with key "greater than" 'target'
  113.  *     then the behavior is determined as follows:
  114.  * If the HFS_BFIND_EXACT bit of 'flags' is not set then 1 is returned
  115.  *       and 'brec' refers to the "matching" record.
  116.  * If the HFS_BFIND_EXACT bit of 'flags' is set then -ENOENT is returned.
  117.  *    If the return value is non-negative and the HFS_BFIND_LOCK bit of
  118.  *     'flags' is set then hfs_brec_lock() is called on the bottom element
  119.  *     of 'brec' before returning.
  120.  */
  121. int hfs_bfind(struct hfs_brec *brec, struct hfs_btree *tree,
  122.       const struct hfs_bkey *target, int flags)
  123. {
  124. struct hfs_belem *curr;
  125. struct hfs_bkey *key;
  126. struct hfs_bnode *bn;
  127. int result, ntype;
  128. /* check for invalid arguments */
  129. if (!brec || (tree->magic != HFS_BTREE_MAGIC) || !target) {
  130. return -EINVAL;
  131. }
  132. /* check for empty tree */
  133. if (!tree->root || !tree->bthNRecs) {
  134. return -ENOENT;
  135. }
  136. /* start search at root of tree */
  137. if (!(curr = hfs_brec_init(brec, tree, flags))) {
  138. return -EIO;
  139. }
  140. /* traverse the tree */
  141. do {
  142. bn = curr->bnr.bn;
  143. if (!curr->record) {
  144. hfs_warn("hfs_bfind: empty bnoden");
  145. hfs_brec_relse(brec, NULL);
  146. return -EIO;
  147. }
  148. /* reverse linear search yielding largest key "less
  149.    than or equal to" 'target'.
  150.    It is questionable whether a binary search would be
  151.    significantly faster */
  152. do {
  153. key = belem_key(curr);
  154. if (!key->KeyLen) {
  155. hfs_warn("hfs_bfind: empty keyn");
  156. hfs_brec_relse(brec, NULL);
  157. return -EIO;
  158. }
  159. result = (tree->compare)(target, key);
  160. } while ((result<0) && (--curr->record));
  161. ntype = bn->ndType;
  162. /* see if all keys > target */
  163. if (!curr->record) {
  164. if (bn->ndBLink) {
  165. /* at a node other than the left-most at a
  166.    given level it means the parent had an
  167.    incorrect key for this child */
  168. hfs_brec_relse(brec, NULL);
  169. hfs_warn("hfs_bfind: corrupted b-tree %d.n",
  170.  (int)ntohl(tree->entry.cnid));
  171. return -EIO;
  172. }
  173. if (flags & HFS_BFIND_EXACT) {
  174. /* we're not going to find it */
  175. hfs_brec_relse(brec, NULL);
  176. return -ENOENT;
  177. }
  178. if (ntype == ndIndxNode) {
  179. /* since we are at the left-most node at
  180.    the current level and looking for the
  181.    predecessor of 'target' keep going down */
  182. curr->record = 1;
  183. } else {
  184. /* we're at first leaf so fall through */
  185. }
  186. }
  187. /* get next node if necessary */
  188. if ((ntype == ndIndxNode) && !(curr = hfs_brec_next(brec))) {
  189. return -EIO;
  190. }
  191. } while (ntype == ndIndxNode);
  192. if (key->KeyLen > tree->bthKeyLen) {
  193. hfs_warn("hfs_bfind: oversized keyn");
  194. hfs_brec_relse(brec, NULL);
  195. return -EIO;
  196. }
  197. if (ntype != ndLeafNode) {
  198. hfs_warn("hfs_bfind: invalid node type %02x in node %d of "
  199.          "btree %dn", bn->ndType, bn->node,
  200.          (int)ntohl(tree->entry.cnid));
  201. hfs_brec_relse(brec, NULL);
  202. return -EIO;
  203. }
  204. if ((flags & HFS_BFIND_EXACT) && result) {
  205. hfs_brec_relse(brec, NULL);
  206. return -ENOENT;
  207. }
  208. if (!(flags & HFS_BPATH_MASK)) {
  209. hfs_brec_relse(brec, brec->bottom-1);
  210. }
  211. if (flags & HFS_BFIND_LOCK) {
  212. hfs_brec_lock(brec, brec->bottom);
  213. }
  214. brec->key  = brec_key(brec);
  215. brec->data = bkey_record(brec->key);
  216. return result ? 1 : 0;
  217. }
  218. /*
  219.  * hfs_bsucc()
  220.  *
  221.  * Description:
  222.  *   This function overwrites '*brec' with its successor in the B-tree,
  223.  *   obtaining the same type of access.
  224.  * Input Variable(s):
  225.  *   struct hfs_brec *brec: address of the (struct hfs_brec) to overwrite
  226.  *    with its successor
  227.  * Output Variable(s):
  228.  *   struct hfs_brec *brec: address of the successor of the original
  229.  *    '*brec' or to invalid data
  230.  * Returns:
  231.  *   int: 0 on success, or one of -EINVAL, -EIO, or -EINVAL on failure
  232.  * Preconditions:
  233.  *   'brec' pointers to a "valid" (struct hfs_brec)
  234.  * Postconditions:
  235.  *   If the given '*brec' is not "valid" -EINVAL is returned and
  236.  *    '*brec' is unchanged.
  237.  *   If the given 'brec' is "valid" but has no successor then -ENOENT
  238.  *    is returned and '*brec' is invalid.
  239.  *   If a call to hfs_bnode_find() is necessary to find the successor,
  240.  *    but fails then -EIO is returned and '*brec' is invalid.
  241.  *   If none of the three previous conditions prevents finding the
  242.  *    successor of '*brec', then 0 is returned, and '*brec' is overwritten
  243.  *    with the (struct hfs_brec) for its successor.
  244.  *   In the cases when '*brec' is invalid, the old records is freed.
  245.  */
  246. int hfs_bsucc(struct hfs_brec *brec, int count)
  247. {
  248. struct hfs_belem *belem;
  249. struct hfs_bnode *bn;
  250. if (!brec || !(belem = brec->bottom) || (belem != brec->top) ||
  251.     !(bn = belem->bnr.bn) || (bn->magic != HFS_BNODE_MAGIC) ||
  252.     !bn->tree || (bn->tree->magic != HFS_BTREE_MAGIC) ||
  253.     !hfs_buffer_ok(bn->buf)) {
  254. hfs_warn("hfs_bsucc: invalid/corrupt arguments.n");
  255. return -EINVAL;
  256. }
  257. while (count) {
  258. int left = bn->ndNRecs - belem->record;
  259. if (left < count) {
  260. struct hfs_bnode_ref old;
  261. hfs_u32 node;
  262. /* Advance to next node */
  263. if (!(node = bn->ndFLink)) {
  264. hfs_brec_relse(brec, belem);
  265. return -ENOENT;
  266. }
  267. if (node == bn->node) {
  268. hfs_warn("hfs_bsucc: corrupt btreen");
  269. hfs_brec_relse(brec, belem);
  270. return -EIO;
  271. }
  272. old = belem->bnr;
  273. belem->bnr = hfs_bnode_find(brec->tree, node,
  274.     belem->bnr.lock_type);
  275. hfs_bnode_relse(&old);
  276. if (!(bn = belem->bnr.bn)) {
  277. return -EIO;
  278. }
  279. belem->record = 1;
  280. count -= (left + 1);
  281. } else {
  282. belem->record += count;
  283. break;
  284. }
  285. }
  286. brec->key  = belem_key(belem);
  287. brec->data = bkey_record(brec->key);
  288. if (brec->key->KeyLen > brec->tree->bthKeyLen) {
  289. hfs_warn("hfs_bsucc: oversized keyn");
  290. hfs_brec_relse(brec, NULL);
  291. return -EIO;
  292. }
  293. return 0;
  294. }