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

📄 stree.c

📁 reiserfsprogs-3.6.19.tar.gz 源码 给有需要的人!
💻 C
字号:
/* *  Copyright 1996-2004 by Hans Reiser, licensing governed by  *  reiserfsprogs/README *//* *  Written by Anatoly P. Pinchuk pap@namesys.botik.ru *  Programm System Institute *  Pereslavl-Zalessky Russia *//* *  This file contains functions dealing with internal tree * * comp_keys * comp_short_keys * bin_search * get_lkey * get_rkey * key_in_buffer * decrement_bcount * decrement_counters_in_path * pathrelse * search_by_key * search_for_position_by_key * comp_items * prepare_for_delete_or_cut * calc_deleted_bytes_number * init_tb_struct * reiserfs_delete_item * indirect_to_direct * maybe_indirect_to_direct * reiserfs_cut_from_item * reiserfs_cut_dir_entry * reiserfs_paste_into_item * reiserfs_insert_item */#include "includes.h"/* Does the buffer contain a disk block which is in the tree. */inline int B_IS_IN_TREE (struct buffer_head * p_s_bh){    return ( get_blkh_level (B_BLK_HEAD (p_s_bh)) != FREE_LEVEL );}/* Compare keys using REISERFS_SHORT_KEY_LEN fields. Returns:  -1 if key1 < key2            0 if key1 = key2            1 if key1 > key2*/int comp_short_keys (const void * k1, const void * k2){    int n_key_length = REISERFS_SHORT_KEY_LEN;    __u32 * p_s_key1 = (__u32 *)k1;    __u32 * p_s_key2 = (__u32 *)k2;    __u32 u1, u2;    for( ; n_key_length--; ++p_s_key1, ++p_s_key2 ) {	u1 = d32_get(p_s_key1, 0) ;	u2 = d32_get(p_s_key2, 0) ;	if ( u1 < u2 )	    return -1;	if ( u1 > u2 )	    return 1;    }    return 0;}int comp_keys_3 (const void * p1, const void * p2){    int retval;    const struct key * k1 = p1;    const struct key * k2 = p2;    loff_t off1, off2;    retval = comp_short_keys (k1, k2);    if (retval)	return retval;    off1 = get_offset(k1) ;    off2 = get_offset(k2) ;    if (off1 < off2)	return -1;    if (off1 > off2)	return 1;    return 0;}/* Compare keys using all 4 key fields. Returns:  -1 if key1 < key2            0 if key1 = key2            1 if key1 > key2*/int comp_keys (const void * p1, const void * p2){    int retval;    const struct key * k1 = p1;    const struct key * k2 = p2;    __u32 u1, u2;    retval = comp_keys_3 (k1, k2);    if (retval)	return retval;    u1 = get_type (k1);    u2 = get_type (k2);    if (u1 < u2)        return -1;    if (u1 > u2)        return 1;    return 0;}/************************************************************************** *  Binary search toolkit function                                        * *  Search for an item in the array by the item key                       * *  Returns:    1 if found,  0 if not found;                              * *        *p_n_pos = number of the searched element if found, else the    * *        number of the first element that is larger than p_v_key.        * **************************************************************************//* For those not familiar with binary search: n_lbound is the leftmost item that it could be, n_rbound the rightmost item that it could be.  We examine the item halfway between n_lbound and n_rbound, and that tells us either that we can increase n_lbound, or decrease n_rbound, or that we have found it, or if n_lbound <= n_rbound that there are no possible items, and we have not found it. With each examination we cut the number of possible items it could be by one more than half rounded down, or we find it. */inline	int bin_search (              void    * p_v_key,    /* Key to search for.                   */	      void    * p_v_base,   /* First item in the array.             */	      int       p_n_num,    /* Number of items in the array.        */	      int       p_n_width,  /* Item size in the array.				       searched. Lest the reader be				       confused, note that this is crafted				       as a general function, and when it				       is applied specifically to the array				       of item headers in a node, p_n_width				       is actually the item header size not				       the item size.                      */	      int     * p_n_pos     /* Number of the searched for element. */            ) {    int   n_rbound, n_lbound, n_j;    for ( n_j = ((n_rbound = p_n_num - 1) + (n_lbound = 0))/2; n_lbound <= n_rbound; n_j = (n_rbound + n_lbound)/2 )	switch( COMP_KEYS((struct key *)((char * )p_v_base + n_j * p_n_width), p_v_key) )  {	case -1: n_lbound = n_j + 1; continue;	case  1: n_rbound = n_j - 1; continue;	case  0: *p_n_pos = n_j;     return ITEM_FOUND; /* Key found in the array.  */	}    /* bin_search did not find given key, it returns position of key,     that is minimal and greater than the given one. */    *p_n_pos = n_lbound;    return ITEM_NOT_FOUND;}/* Minimal possible key. It is never in the tree. */struct key  MIN_KEY = {0, 0, {{0, 0},}};/* Maximal possible key. It is never in the tree. */struct key  MAX_KEY = {0xffffffff, 0xffffffff, {{0xffffffff, 0xffffffff},}};/* Get delimiting key of the buffer by looking for it in the buffers in the   path, starting from the bottom of the path, and going upwards.  We must   check the path's validity at each step.  If the key is not in the path,   there is no delimiting key in the tree (buffer is first or last buffer in   tree), and in this case we return a special key, either MIN_KEY or   MAX_KEY. */struct key * get_lkey (struct path * p_s_chk_path,		       reiserfs_filsys_t * fs){    struct reiserfs_super_block * sb;    int  n_position, n_path_offset = p_s_chk_path->path_length;    struct buffer_head  * p_s_parent;      sb = fs->fs_ondisk_sb;    /* While not higher in path than first element. */    while ( n_path_offset-- > FIRST_PATH_ELEMENT_OFFSET ) {	/* Parent at the path is not in the tree now. */	if ( ! B_IS_IN_TREE(p_s_parent = PATH_OFFSET_PBUFFER(p_s_chk_path, n_path_offset)) )	    return &MAX_KEY;	/* Check whether position in the parent is correct. */	if ( (n_position = PATH_OFFSET_POSITION(p_s_chk_path, n_path_offset)) > B_NR_ITEMS(p_s_parent) )	    return &MAX_KEY;	/* Check whether parent at the path really points to the child. */	if ( get_dc_child_blocknr (B_N_CHILD (p_s_parent, n_position)) !=	     PATH_OFFSET_PBUFFER(p_s_chk_path, n_path_offset + 1)->b_blocknr )	    return &MAX_KEY;	/* Return delimiting key if position in the parent is not equal to zero. */	if ( n_position )	    return B_N_PDELIM_KEY(p_s_parent, n_position - 1);    }    /* Return MIN_KEY if we are in the root of the buffer tree. */    if ( PATH_OFFSET_PBUFFER(p_s_chk_path, FIRST_PATH_ELEMENT_OFFSET)->b_blocknr ==	 get_sb_root_block (sb) )	return &MIN_KEY;    return  &MAX_KEY;}/* Get delimiting key of the buffer at the path and its right neighbor. */struct key * get_rkey (struct path * p_s_chk_path,		       reiserfs_filsys_t * fs){    struct reiserfs_super_block * sb;    int                   n_position,	n_path_offset = p_s_chk_path->path_length;    struct buffer_head  * p_s_parent;    sb = fs->fs_ondisk_sb;    while ( n_path_offset-- > FIRST_PATH_ELEMENT_OFFSET ) {	/* Parent at the path is not in the tree now. */	if ( ! B_IS_IN_TREE(p_s_parent = PATH_OFFSET_PBUFFER(p_s_chk_path, n_path_offset)) )	    return &MIN_KEY;	/* Check whether position in the parrent is correct. */	if ( (n_position = PATH_OFFSET_POSITION(p_s_chk_path, n_path_offset)) > B_NR_ITEMS(p_s_parent) )	    return &MIN_KEY;	/* Check whether parent at the path really points to the child. */	if ( get_dc_child_blocknr (B_N_CHILD (p_s_parent, n_position)) !=	     PATH_OFFSET_PBUFFER(p_s_chk_path, n_path_offset + 1)->b_blocknr )	    return &MIN_KEY;	/* Return delimiting key if position in the parent is not the last one. */	if ( n_position != B_NR_ITEMS(p_s_parent) )	    return B_N_PDELIM_KEY(p_s_parent, n_position);    }    /* Return MAX_KEY if we are in the root of the buffer tree. */    if ( PATH_OFFSET_PBUFFER(p_s_chk_path, FIRST_PATH_ELEMENT_OFFSET)->b_blocknr ==	 get_sb_root_block (sb) )	return &MAX_KEY;    return  &MIN_KEY;}/* Check whether a key is contained in the tree rooted from a buffer at a   path.  This works by looking at the left and right delimiting keys for the   buffer in the last path_element in the path.  These delimiting keys are   stored at least one level above that buffer in the tree. If the buffer is   the first or last node in the tree order then one of the delimiting keys   may be absent, and in this case get_lkey and get_rkey return a special key   which is MIN_KEY or MAX_KEY. */static  inline  int key_in_buffer (    struct path         * p_s_chk_path, /* Path which should be checked.  */    struct key          * p_s_key,      /* Key which should be checked.   */    reiserfs_filsys_t  * fs        /* Super block pointer.           */    ) {    if ( COMP_KEYS(get_lkey(p_s_chk_path, fs), p_s_key) == 1 )	return 0;    if ( COMP_KEYS(p_s_key, get_rkey(p_s_chk_path, fs)) != -1 )	return 0;    return 1;}/* Release all buffers in the path. */void  pathrelse (struct path * p_s_search_path) {    int n_path_offset = p_s_search_path->path_length;        while ( n_path_offset > ILLEGAL_PATH_ELEMENT_OFFSET )	brelse(PATH_OFFSET_PBUFFER(p_s_search_path, n_path_offset--));    p_s_search_path->path_length = ILLEGAL_PATH_ELEMENT_OFFSET;}/************************************************************************** * Algorithm   SearchByKey                                                * *             look for item in internal tree on the disk by its key      * * Input:  p_s_sb   -  super block                                        * *         p_s_key  - pointer to the key to search                        * * Output: true value -  1 - found,  0 - not found                        * *         p_s_search_path - path from the root to the needed leaf        * **************************************************************************//* This function fills up the path from the root to the leaf as it   descends the tree looking for the key.  It uses reiserfs_bread to   try to find buffers in the cache given their block number.  If it   does not find them in the cache it reads them from disk.  For each   node search_by_key finds using reiserfs_bread it then uses   bin_search to look through that node.  bin_search will find the   position of the block_number of the next node if it is looking   through an internal node.  If it is looking through a leaf node   bin_search will find the position of the item which has key either   equal to given key, or which is the maximal key less than the given   key.  search_by_key returns a path that must be checked for the   correctness of the top of the path but need not be checked for the   correctness of the bottom of the path */int search_by_key (reiserfs_filsys_t * fs,		   struct key * p_s_key,        /* Key to search */		   struct path * p_s_search_path,/* This structure was						    allocated and						    initialized by the						    calling						    function. It is						    filled up by this						    function.  */		   int  n_stop_level)   /* How far down the tree to search.*/{    struct reiserfs_super_block * sb;    int n_block_number,	expected_level,	n_block_size    = fs->fs_blocksize;    struct buffer_head  *       p_s_bh;    struct path_element *       p_s_last_element;    int				n_retval;    sb = fs->fs_ondisk_sb;    n_block_number = get_sb_root_block (sb);    expected_level = get_sb_tree_height (sb);        /* As we add each node to a path we increase its count.  This       means that we must be careful to release all nodes in a path       before we either discard the path struct or re-use the path       struct, as we do here. */    pathrelse (p_s_search_path);    /* With each iteration of this loop we search through the items in       the current node, and calculate the next current node(next path       element) for the next iteration of this loop.. */    while ( 1 ) {	/* prep path to have another element added to it. */	p_s_last_element = PATH_OFFSET_PELEMENT(p_s_search_path, ++p_s_search_path->path_length);	expected_level --;	/* Read the next tree node, and set the last element in the           path to have a pointer to it. */	if ( ! (p_s_bh = p_s_last_element->pe_buffer =		bread (fs->fs_dev, n_block_number, n_block_size)) ) {	    p_s_search_path->path_length --;	    pathrelse(p_s_search_path);	    return IO_ERROR;	}	/* It is possible that schedule occured. We must check whether	   the key to search is still in the tree rooted from the	   current buffer. If not then repeat search from the root. */	if (!B_IS_IN_TREE (p_s_bh) || 	    ! key_in_buffer(p_s_search_path, p_s_key, fs))	    reiserfs_panic ("search_by_key: something wrong with the tree");	/* make sure, that the node contents look like a node of           certain level */	if (!is_tree_node (p_s_bh, expected_level)) {	    print_block (stderr, 0, p_s_bh, 3, -1, -1);	    reiserfs_panic ("search_by_key: expected level %d", expected_level);	}	/* ok, we have acquired next formatted node in the tree */	n_retval = bin_search (p_s_key, B_N_PITEM_HEAD(p_s_bh, 0), B_NR_ITEMS(p_s_bh),			       is_leaf_node (p_s_bh) ? IH_SIZE : KEY_SIZE, &(p_s_last_element->pe_position));	if (get_blkh_level (B_BLK_HEAD (p_s_bh)) == n_stop_level)	    return n_retval;	/* we are not in the stop level */	if (n_retval == ITEM_FOUND)	    /* item has been found, so we choose the pointer which is               to the right of the found one */	    p_s_last_element->pe_position++;	/* if item was not found we choose the position which is to	   the left of the found item. This requires no code,	   bin_search did it already.*/	/* So we have chosen a position in the current node which is	   an internal node.  Now we calculate child block number by	   position in the node. */	n_block_number = get_dc_child_blocknr (B_N_CHILD (p_s_bh, p_s_last_element->pe_position));    }}int bin_search_in_dir_item (struct item_head * ih, struct reiserfs_de_head * deh, 			    struct key * key, int * pos_in_item){    int rbound, lbound, j;    lbound = 0;    rbound = get_ih_entry_count (ih) - 1;    for (j = (rbound + lbound) / 2; lbound <= rbound; j = (rbound + lbound) / 2) {	if (get_offset (key) < get_deh_offset (deh + j)) {	    rbound = j - 1;	    continue;	}	if (get_offset (key) > get_deh_offset (deh + j)) {	    lbound = j + 1;	    continue;	}	/* key found */	*pos_in_item = j;	return POSITION_FOUND;    }        *pos_in_item = lbound;    return POSITION_NOT_FOUND;}

⌨️ 快捷键说明

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