⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 bfind.c

📁 嵌入式系统设计与实验教材二源码linux内核移植与编译
💻 C
字号:
/* * linux/fs/hfs/bfind.c * * Copyright (C) 1995, 1996  Paul H. Hargrove * This file may be distributed under the terms of the GNU General Public License. * * This file contains the code to access records in a btree. * * "XXX" in a comment is a note to myself to consider changing something. * * In function preconditions the term "valid" applied to a pointer to * a structure means that the pointer is non-NULL and the structure it * points to has all fields initialized to consistent values. */#include "hfs_btree.h"/*================ Global functions ================*//* * hfs_brec_relse() * * Description: *   This function releases some of the nodes associated with a brec. * Input Variable(s): *   struct hfs_brec *brec: pointer to the brec to release some nodes from. *   struct hfs_belem *elem: the last node to release or NULL for all * Output Variable(s): *   NONE * Returns: *   void * Preconditions: *   'brec' points to a "valid" (struct hfs_brec) * Postconditions:  *   All nodes between the indicated node and the beginning of the path *    are released. */void hfs_brec_relse(struct hfs_brec *brec, struct hfs_belem *elem){	if (!elem) {		elem = brec->bottom;	}	while (brec->top <= elem) {		hfs_bnode_relse(&brec->top->bnr);		++brec->top;	}}/* * hfs_bfind() * * Description: *   This function has sole responsibility for locating existing *   records in a B-tree.  Given a B-tree and a key it locates the *   "greatest" record "less than or equal to" the given key.  The *   exact behavior is determined by the bits of the flags variable as *   follows: *     ('flags' & HFS_LOCK_MASK): *      The lock_type argument to be used when calling hfs_bnode_find(). *     HFS_BFIND_EXACT: only accept an exact match, otherwise take the *	"largest" record less than 'target' as a "match" *     HFS_BFIND_LOCK: request HFS_LOCK_WRITE access to the node containing *	the "matching" record when it is located *     HFS_BPATH_FIRST: keep access to internal nodes when accessing their *      first child. *     HFS_BPATH_OVERFLOW: keep access to internal nodes when the accessed *      child is too full to insert another pointer record. *     HFS_BPATH_UNDERFLOW: keep access to internal nodes when the accessed *      child is would be less than half full upon removing a pointer record. * Input Variable(s): *   struct hfs_brec *brec: pointer to the (struct hfs_brec) to hold *    the search results. *   struct hfs_bkey *target: pointer to the (struct hfs_bkey) *    to search for *   int flags: bitwise OR of flags which determine the function's behavior * Output Variable(s): *   'brec' contains the results of the search on success or is invalid *    on failure. * Returns: *   int: 0 or 1 on success or an error code on failure: *     -EINVAL: one of the input variables was NULL. *     -ENOENT: tree is valid but empty or no "matching" record was located. *	 If the HFS_BFIND_EXACT bit of 'flags' is not set then the case of no *	 matching record will give a 'brec' with a 'record' field of zero *	 rather than returning this error. *     -EIO: an I/O operation or an assertion about the structure of a *       valid B-tree failed indicating corruption of either the B-tree *       structure on the disk or one of the in-core structures representing *       the B-tree. *	 (This could also be returned if a kmalloc() call failed in a *	 subordinate routine that is intended to get the data from the *	 disk or the buffer cache.) * Preconditions: *   'brec' is NULL or points to a (struct hfs_brec) with a 'tree' field *    which points to a valid (struct hfs_btree). *   'target' is NULL or points to a "valid" (struct hfs_bkey) * Postconditions: *   If 'brec', 'brec->tree' or 'target' is NULL then -EINVAL is returned. *   If 'brec', 'brec->tree' and 'target' are non-NULL but the tree *   is empty then -ENOENT is returned. *   If 'brec', 'brec->tree' and 'target' are non-NULL but the call to *   hfs_brec_init() fails then '*brec' is NULL and -EIO is returned. *   If 'brec', 'brec->tree' and 'target' are non-NULL and the tree is *   non-empty then the tree is searched as follows: *    If any call to hfs_brec_next() fails or returns a node that is *     neither an index node nor a leaf node then -EIO is returned to *     indicate that the B-tree or buffer-cache are corrupted. *    If every record in the tree is "greater than" the given key *     and the HFS_BFIND_EXACT bit of 'flags' is set then -ENOENT is returned. *    If every record in the tree is "greater than" the given key *     and the HFS_BFIND_EXACT bit of 'flags' is clear then 'brec' refers *     to the first leaf node in the tree and has a 'record' field of *     zero, and 1 is returned. *    If a "matching" record is located with key "equal to" 'target' *     then the return value is 0 and 'brec' indicates the record. *    If a "matching" record is located with key "greater than" 'target' *     then the behavior is determined as follows: *	If the HFS_BFIND_EXACT bit of 'flags' is not set then 1 is returned *       and 'brec' refers to the "matching" record. *	If the HFS_BFIND_EXACT bit of 'flags' is set then -ENOENT is returned. *    If the return value is non-negative and the HFS_BFIND_LOCK bit of *     'flags' is set then hfs_brec_lock() is called on the bottom element *     of 'brec' before returning. */int hfs_bfind(struct hfs_brec *brec, struct hfs_btree *tree,	      const struct hfs_bkey *target, int flags){	struct hfs_belem *curr;	struct hfs_bkey *key;	struct hfs_bnode *bn;	int result, ntype;	/* check for invalid arguments */	if (!brec || (tree->magic != HFS_BTREE_MAGIC) || !target) {		return -EINVAL;	}	/* check for empty tree */	if (!tree->root || !tree->bthNRecs) {		return -ENOENT;	}	/* start search at root of tree */	if (!(curr = hfs_brec_init(brec, tree, flags))) {		return -EIO;	}	/* traverse the tree */	do {		bn = curr->bnr.bn;		if (!curr->record) {			hfs_warn("hfs_bfind: empty bnode\n");			hfs_brec_relse(brec, NULL);			return -EIO;		}		/* reverse linear search yielding largest key "less		   than or equal to" 'target'.		   It is questionable whether a binary search would be		   significantly faster */		do {			key = belem_key(curr);			if (!key->KeyLen) {				hfs_warn("hfs_bfind: empty key\n");				hfs_brec_relse(brec, NULL);				return -EIO;			}			result = (tree->compare)(target, key);		} while ((result<0) && (--curr->record));		ntype = bn->ndType;		/* see if all keys > target */		if (!curr->record) {			if (bn->ndBLink) {				/* at a node other than the left-most at a				   given level it means the parent had an				   incorrect key for this child */				hfs_brec_relse(brec, NULL);				hfs_warn("hfs_bfind: corrupted b-tree %d.\n",					 (int)ntohl(tree->entry.cnid));				return -EIO;			}			if (flags & HFS_BFIND_EXACT) {				/* we're not going to find it */				hfs_brec_relse(brec, NULL);				return -ENOENT;			}			if (ntype == ndIndxNode) {				/* since we are at the left-most node at				   the current level and looking for the				   predecessor of 'target' keep going down */				curr->record = 1;			} else {				/* we're at first leaf so fall through */			}		}		/* get next node if necessary */		if ((ntype == ndIndxNode) && !(curr = hfs_brec_next(brec))) {			return -EIO;		}	} while (ntype == ndIndxNode);	if (key->KeyLen > tree->bthKeyLen) {		hfs_warn("hfs_bfind: oversized key\n");		hfs_brec_relse(brec, NULL);		return -EIO;	}	if (ntype != ndLeafNode) {		hfs_warn("hfs_bfind: invalid node type %02x in node %d of "		         "btree %d\n", bn->ndType, bn->node,		         (int)ntohl(tree->entry.cnid));		hfs_brec_relse(brec, NULL);		return -EIO;	}	if ((flags & HFS_BFIND_EXACT) && result) {		hfs_brec_relse(brec, NULL);		return -ENOENT;	}	if (!(flags & HFS_BPATH_MASK)) {		hfs_brec_relse(brec, brec->bottom-1);	}	if (flags & HFS_BFIND_LOCK) {		hfs_brec_lock(brec, brec->bottom);	}	brec->key  = brec_key(brec);	brec->data = bkey_record(brec->key);	return result ? 1 : 0;}/* * hfs_bsucc() * * Description: *   This function overwrites '*brec' with its successor in the B-tree, *   obtaining the same type of access. * Input Variable(s): *   struct hfs_brec *brec: address of the (struct hfs_brec) to overwrite *    with its successor * Output Variable(s): *   struct hfs_brec *brec: address of the successor of the original *    '*brec' or to invalid data * Returns: *   int: 0 on success, or one of -EINVAL, -EIO, or -EINVAL on failure * Preconditions: *   'brec' pointers to a "valid" (struct hfs_brec) * Postconditions: *   If the given '*brec' is not "valid" -EINVAL is returned and *    '*brec' is unchanged. *   If the given 'brec' is "valid" but has no successor then -ENOENT *    is returned and '*brec' is invalid. *   If a call to hfs_bnode_find() is necessary to find the successor, *    but fails then -EIO is returned and '*brec' is invalid. *   If none of the three previous conditions prevents finding the *    successor of '*brec', then 0 is returned, and '*brec' is overwritten *    with the (struct hfs_brec) for its successor. *   In the cases when '*brec' is invalid, the old records is freed. */int hfs_bsucc(struct hfs_brec *brec, int count){	struct hfs_belem *belem;	struct hfs_bnode *bn;	if (!brec || !(belem = brec->bottom) || (belem != brec->top) ||	    !(bn = belem->bnr.bn) || (bn->magic != HFS_BNODE_MAGIC) ||	    !bn->tree || (bn->tree->magic != HFS_BTREE_MAGIC) ||	    !hfs_buffer_ok(bn->buf)) {		hfs_warn("hfs_bsucc: invalid/corrupt arguments.\n");		return -EINVAL;	}	while (count) {		int left = bn->ndNRecs - belem->record;		if (left < count) {			struct hfs_bnode_ref old;			hfs_u32 node;			/* Advance to next node */			if (!(node = bn->ndFLink)) {				hfs_brec_relse(brec, belem);				return -ENOENT;			}			if (node == bn->node) {				hfs_warn("hfs_bsucc: corrupt btree\n");				hfs_brec_relse(brec, belem);				return -EIO;			}			old = belem->bnr;			belem->bnr = hfs_bnode_find(brec->tree, node,						    belem->bnr.lock_type);			hfs_bnode_relse(&old);			if (!(bn = belem->bnr.bn)) {				return -EIO;			}			belem->record = 1;			count -= (left + 1);		} else {			belem->record += count;			break;		}	}	brec->key  = belem_key(belem);	brec->data = bkey_record(brec->key);	if (brec->key->KeyLen > brec->tree->bthKeyLen) {		hfs_warn("hfs_bsucc: oversized key\n");		hfs_brec_relse(brec, NULL);		return -EIO;	}	return 0;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -