| /* |
| * Copyright 2000-2004 by Hans Reiser, licensing governed by |
| * reiserfsprogs/README |
| */ |
| |
| #ifdef HAVE_CONFIG_H |
| # include <config.h> |
| #endif |
| |
| #include "reiserfs/libreiserfs.h" |
| #include "misc/unaligned.h" |
| #include "misc/malloc.h" |
| |
| static int reiserfs_tree_search (reiserfs_filsys_t * fs, |
| const reiserfs_key_t * key, |
| reiserfs_path_t * path, |
| misc_comp_func_t comp_func) |
| { |
| reiserfs_bh_t * bh; |
| unsigned long block; |
| reiserfs_path_element_t * curr; |
| int retval; |
| |
| |
| block = reiserfs_sb_get_root (fs->fs_ondisk_sb); |
| if (reiserfs_fs_block(fs, block) != BT_UNKNOWN) |
| return IO_ERROR; |
| |
| path->path_length = REISERFS_PATH_OFFILL; |
| while (1) { |
| curr = REISERFS_PATH_ELEM (path, ++ path->path_length); |
| bh = curr->pe_buffer = reiserfs_buffer_read (fs->fs_dev, block, |
| fs->fs_blocksize); |
| if (bh == 0) { |
| path->path_length --; |
| reiserfs_tree_pathrelse (path); |
| return ITEM_NOT_FOUND; |
| } |
| |
| retval = misc_bin_search (key, reiserfs_ih_key_at (bh, 0), |
| reiserfs_node_items (bh), |
| reiserfs_leaf_head (bh) ? |
| REISERFS_IH_SIZE : REISERFS_KEY_SIZE, |
| &(curr->pe_position), comp_func); |
| |
| if (retval == 1) { |
| /* key found, return if this is leaf level */ |
| if (reiserfs_leaf_head (bh)) { |
| path->pos_in_item = 0; |
| return ITEM_FOUND; |
| } |
| curr->pe_position ++; |
| } else { |
| /* key not found in the node */ |
| if (reiserfs_leaf_head (bh)) |
| return ITEM_NOT_FOUND; |
| } |
| |
| block = reiserfs_dc_get_nr (reiserfs_int_at (bh, curr->pe_position)); |
| |
| if (reiserfs_fs_block(fs, block) != BT_UNKNOWN) |
| return IO_ERROR; |
| } |
| |
| printf ("reiserfs_tree_search: you can not get here\n"); |
| return ITEM_NOT_FOUND; |
| } |
| |
| int reiserfs_tree_search_body (reiserfs_filsys_t * fs, |
| const reiserfs_key_t * key, |
| reiserfs_path_t * path) |
| { |
| return reiserfs_tree_search (fs, key, path, reiserfs_key_comp3); |
| } |
| |
| |
| int reiserfs_tree_search_item (reiserfs_filsys_t * fs, |
| const reiserfs_key_t * key, |
| reiserfs_path_t * path) |
| { |
| return reiserfs_tree_search (fs, key, path, reiserfs_key_comp); |
| } |
| |
| |
| /* key is key of byte in the regular file. This searches in tree |
| through items and in the found item as well */ |
| int reiserfs_tree_search_position (reiserfs_filsys_t * fs, |
| const reiserfs_key_t * key, |
| reiserfs_path_t * path) |
| { |
| const reiserfs_key_t * next_key; |
| reiserfs_bh_t * bh; |
| reiserfs_ih_t * ih; |
| |
| if (reiserfs_tree_search_body (fs, key, path) == ITEM_FOUND) { |
| ih = REISERFS_PATH_IH (path); |
| |
| if (!reiserfs_ih_direct (ih) && !reiserfs_ih_ext (ih)) |
| return DIRECTORY_FOUND; |
| |
| path->pos_in_item = 0; |
| return POSITION_FOUND; |
| } |
| |
| bh = REISERFS_PATH_LEAF (path); |
| ih = REISERFS_PATH_IH (path); |
| |
| if (REISERFS_PATH_LEAF_POS (path) == 0) { |
| /* previous item does not exist, that means we are in leftmost leaf of |
| * the tree */ |
| if (!reiserfs_key_comp2 (&ih->ih_key, key)) { |
| if (!reiserfs_ih_direct (ih) && !reiserfs_ih_ext (ih)) |
| return DIRECTORY_FOUND; |
| return POSITION_NOT_FOUND; |
| } |
| return FILE_NOT_FOUND; |
| } |
| |
| /* take previous item */ |
| REISERFS_PATH_LEAF_POS (path) --; |
| ih --; |
| |
| if (reiserfs_key_comp2 (&ih->ih_key, key) || reiserfs_ih_stat(ih)) { |
| /* previous item belongs to another object or is a stat data, check |
| * next item */ |
| REISERFS_PATH_LEAF_POS (path) ++; |
| if (REISERFS_PATH_LEAF_POS (path) < reiserfs_node_items (bh)) |
| /* next key is in the same node */ |
| next_key = reiserfs_ih_key_at (bh, REISERFS_PATH_LEAF_POS (path)); |
| else |
| next_key = reiserfs_tree_rkey (path, fs); |
| if (next_key == 0 || reiserfs_key_comp2 (next_key, key)) { |
| /* there is no any part of such file in the tree */ |
| path->pos_in_item = 0; |
| return FILE_NOT_FOUND; |
| } |
| |
| if (reiserfs_key_dir (next_key)) { |
| reiserfs_warning (stderr, "reiserfs_tree_search_position: looking " |
| "for %k found a directory with the same key\n", |
| next_key); |
| |
| return DIRECTORY_FOUND; |
| } |
| |
| /* next item is the part of this file */ |
| path->pos_in_item = 0; |
| return POSITION_NOT_FOUND; |
| } |
| |
| if (reiserfs_ih_dir (ih)) { |
| return DIRECTORY_FOUND; |
| } |
| |
| if (reiserfs_ih_stat(ih)) { |
| REISERFS_PATH_LEAF_POS (path) ++; |
| return FILE_NOT_FOUND; |
| } |
| |
| /* previous item is part of desired file */ |
| if (reiserfs_item_has_key (ih, key, bh->b_size)) { |
| path->pos_in_item = reiserfs_key_get_off (key) - |
| reiserfs_key_get_off (&ih->ih_key); |
| |
| if (reiserfs_ih_ext (ih) ) |
| path->pos_in_item /= bh->b_size; |
| return POSITION_FOUND; |
| } |
| |
| path->pos_in_item = reiserfs_ih_ext (ih) ? reiserfs_ext_count (ih) : |
| reiserfs_ih_get_len (ih); |
| |
| return POSITION_NOT_FOUND; |
| } |
| |
| const reiserfs_key_t * reiserfs_tree_lkey (reiserfs_path_t * path, |
| reiserfs_filsys_t * fs) |
| { |
| int pos, offset = path->path_length; |
| reiserfs_bh_t * bh; |
| reiserfs_sb_t * sb; |
| |
| sb = fs->fs_ondisk_sb; |
| |
| if (offset < REISERFS_PATH_OFFINIT) |
| misc_die ("reiserfs_tree_lkey: illegal offset in the path (%d)", offset); |
| |
| /* While not higher in path than first element. */ |
| while (offset-- > REISERFS_PATH_OFFINIT) { |
| if (! reiserfs_buffer_uptodate (REISERFS_PATH_BUFFER (path, offset)) ) |
| misc_die ("reiserfs_tree_lkey: parent is not uptodate"); |
| |
| /* Parent at the path is not in the tree now. */ |
| if (! REISERFS_NODE_INTREE (bh = REISERFS_PATH_BUFFER (path, offset))) |
| misc_die ("reiserfs_tree_lkey: buffer on the path is not in tree"); |
| |
| /* Check whether position in the parent is correct. */ |
| if ((pos = REISERFS_PATH_POS (path, offset)) > reiserfs_node_items (bh)) |
| misc_die ("reiserfs_tree_lkey: invalid position (%d) in the path", pos); |
| |
| /* Check whether parent at the path really points to the child. */ |
| if (reiserfs_dc_get_nr (reiserfs_int_at (bh, pos)) != |
| REISERFS_PATH_BUFFER (path, offset + 1)->b_blocknr) |
| { |
| misc_die ("reiserfs_tree_lkey: invalid block number (%d). Must be %ld", |
| reiserfs_dc_get_nr (reiserfs_int_at (bh, pos)), |
| REISERFS_PATH_BUFFER (path, offset + 1)->b_blocknr); |
| } |
| |
| /* Return delimiting key if position in the parent is not equal to zero. */ |
| if (pos) return reiserfs_int_key_at(bh, pos - 1); |
| } |
| |
| /* Return MIN_KEY if we are in the root of the buffer tree. */ |
| if ( REISERFS_PATH_BUFFER(path, REISERFS_PATH_OFFINIT)->b_blocknr |
| != reiserfs_sb_get_root (sb) ) |
| { |
| misc_die("reiserfs_tree_lkey: invalid root block number (%lu). Must be (%u).", |
| REISERFS_PATH_BUFFER(path, REISERFS_PATH_OFFINIT)->b_blocknr, |
| reiserfs_sb_get_root (sb)); |
| } |
| |
| /* there is no left delimiting key */ |
| return &MIN_KEY; |
| } |
| |
| const reiserfs_key_t * reiserfs_tree_rkey (reiserfs_path_t * path, |
| reiserfs_filsys_t * fs) |
| { |
| int pos, offset = path->path_length; |
| reiserfs_bh_t * bh; |
| reiserfs_sb_t * sb; |
| |
| sb = fs->fs_ondisk_sb; |
| |
| if (offset < REISERFS_PATH_OFFINIT) |
| misc_die ("reiserfs_tree_rkey: illegal offset in the path (%d)", offset); |
| |
| while (offset-- > REISERFS_PATH_OFFINIT) { |
| if (! reiserfs_buffer_uptodate (REISERFS_PATH_BUFFER (path, offset))) |
| misc_die ("reiserfs_tree_rkey: parent is not uptodate"); |
| |
| /* Parent at the path is not in the tree now. */ |
| if (! REISERFS_NODE_INTREE (bh = REISERFS_PATH_BUFFER (path, offset))) |
| misc_die ("reiserfs_tree_rkey: buffer on the path is not in tree"); |
| |
| /* Check whether position in the parrent is correct. */ |
| if ((pos = REISERFS_PATH_POS (path, offset)) > reiserfs_node_items (bh)) |
| misc_die ("reiserfs_tree_rkey: invalid position (%d) in the path", pos); |
| |
| /* Check whether parent at the path really points to the child. */ |
| if (reiserfs_dc_get_nr (reiserfs_int_at (bh, pos)) != |
| REISERFS_PATH_BUFFER (path, offset + 1)->b_blocknr) |
| { |
| misc_die ("reiserfs_tree_rkey: invalid block number (%d). Must be %ld", |
| reiserfs_dc_get_nr (reiserfs_int_at (bh, pos)), |
| REISERFS_PATH_BUFFER (path, offset + 1)->b_blocknr); |
| } |
| |
| /* Return delimiting key if position in the parent is not the |
| last one. */ |
| if (pos != reiserfs_node_items (bh)) |
| return reiserfs_int_key_at (bh, pos); |
| } |
| |
| /* Return MAX_KEY if we are in the root of the buffer tree. */ |
| if ( REISERFS_PATH_BUFFER(path, REISERFS_PATH_OFFINIT)->b_blocknr != |
| reiserfs_sb_get_root (sb) ) |
| { |
| misc_die ("reiserfs_tree_rkey: invalid root block number (%lu). Must be (%u).", |
| REISERFS_PATH_BUFFER(path, REISERFS_PATH_OFFINIT)->b_blocknr, |
| reiserfs_sb_get_root (sb)); |
| } |
| |
| /* there is no right delimiting key */ |
| return &MAX_KEY; |
| } |
| |
| const reiserfs_key_t *reiserfs_tree_next_key(reiserfs_path_t *path, |
| reiserfs_filsys_t *fs) |
| { |
| if (REISERFS_PATH_LEAF_POS (path) < |
| reiserfs_node_items (REISERFS_PATH_LEAF (path)) - 1) |
| { |
| return reiserfs_ih_key_at(REISERFS_PATH_LEAF (path), |
| REISERFS_PATH_LEAF_POS (path) + 1); |
| } |
| |
| return reiserfs_tree_rkey (path, fs); |
| } |
| |
| static int comp_dir_entries (const void * p1, const void * p2) { |
| __u32 off1, off2; |
| |
| off1 = d32_get((__u32 *)p1, 0); |
| off2 = *(__u32 *)p2; |
| |
| if (off1 < off2) |
| return -1; |
| if (off1 > off2) |
| return 1; |
| return 0; |
| } |
| |
| |
| /* NOTE: this only should be used to look for keys who exists */ |
| int reiserfs_tree_search_entry (reiserfs_filsys_t * fs, |
| const reiserfs_key_t * key, |
| reiserfs_path_t * path) |
| { |
| reiserfs_bh_t * bh; |
| int item_pos; |
| reiserfs_ih_t * ih; |
| reiserfs_key_t tmpkey; |
| __u32 offset; |
| |
| if (reiserfs_tree_search_item (fs, key, path) == ITEM_FOUND) { |
| path->pos_in_item = 0; |
| return POSITION_FOUND; |
| } |
| |
| bh = REISERFS_PATH_LEAF (path); |
| item_pos = REISERFS_PATH_LEAF_POS (path); |
| ih = REISERFS_PATH_IH (path); |
| |
| if (item_pos == 0) { |
| /* key is less than the smallest key in the tree */ |
| if (reiserfs_key_comp2 (&(ih->ih_key), key)) |
| /* there are no items of that directory */ |
| return DIRECTORY_NOT_FOUND; |
| |
| if (!reiserfs_ih_dir (ih)) { |
| reiserfs_panic ("reiserfs_tree_search_entry: found item " |
| "is not of directory type %H", ih); |
| } |
| |
| /* key we looked for should be here */ |
| path->pos_in_item = 0; |
| return POSITION_NOT_FOUND; |
| } |
| |
| /* take previous item */ |
| item_pos --; |
| ih --; |
| REISERFS_PATH_LEAF_POS (path) --; |
| |
| if (reiserfs_key_comp2 (&(ih->ih_key), key) || !reiserfs_ih_dir (ih)) { |
| /* previous item belongs to another object or is stat data, check next |
| item */ |
| |
| item_pos ++; |
| REISERFS_PATH_LEAF_POS (path) ++; |
| |
| if (item_pos < reiserfs_node_items (bh)) { |
| /* next item is in the same node */ |
| ih ++; |
| if (reiserfs_key_comp2 (&(ih->ih_key), key)) { |
| /* there are no items of that directory */ |
| path->pos_in_item = 0; |
| return DIRECTORY_NOT_FOUND; |
| } |
| |
| if (!reiserfs_ih_dir (ih)) |
| reiserfs_panic ("reiserfs_tree_search_entry: %k is not a directory", |
| key); |
| } else { |
| /* next item is in right neighboring node */ |
| const reiserfs_key_t * next_key = reiserfs_tree_rkey (path, fs); |
| |
| if (next_key == 0 || reiserfs_key_comp2 (next_key, key)) { |
| /* there are no items of that directory */ |
| path->pos_in_item = 0; |
| return DIRECTORY_NOT_FOUND; |
| } |
| |
| if (!reiserfs_key_dir (next_key)) |
| reiserfs_panic ("reiserfs_tree_search_entry: %k is not a directory", |
| key); |
| |
| /* we got right delimiting key - search for it - the entry will be |
| pasted in position 0 */ |
| reiserfs_key_copy (&tmpkey, next_key); |
| reiserfs_tree_pathrelse (path); |
| if (reiserfs_tree_search_item (fs, &tmpkey, path) != ITEM_FOUND || |
| REISERFS_PATH_LEAF_POS (path) != 0) |
| { |
| reiserfs_panic ("reiserfs_tree_search_entry: item " |
| "corresponding to delimiting key %k " |
| "not found", &tmpkey); |
| } |
| } |
| |
| /* next item is the part of this directory */ |
| path->pos_in_item = 0; |
| return POSITION_NOT_FOUND; |
| } |
| |
| /* previous item is part of desired directory */ |
| offset = reiserfs_key_get_off1 (key); |
| if (misc_bin_search (&offset, reiserfs_deh (bh, ih), |
| reiserfs_ih_get_entries (ih), |
| REISERFS_DEH_SIZE, &(path->pos_in_item), |
| comp_dir_entries) == 1) |
| { |
| return POSITION_FOUND; |
| } |
| |
| return POSITION_NOT_FOUND; |
| } |
| |
| int reiserfs_tree_delete_entry (reiserfs_filsys_t * fs, reiserfs_key_t * key) |
| { |
| reiserfs_path_t path; |
| reiserfs_tb_t tb; |
| reiserfs_ih_t * ih; |
| reiserfs_deh_t * deh; |
| int entry_len; |
| |
| if (reiserfs_tree_search_entry (fs, key, &path) != POSITION_FOUND) { |
| reiserfs_tree_pathrelse (&path); |
| return 1; |
| } |
| |
| ih = REISERFS_PATH_IH (&path); |
| if (reiserfs_ih_get_entries (ih) == 1) { |
| |
| reiserfs_tb_init (&tb, fs, &path, |
| -(REISERFS_IH_SIZE + reiserfs_ih_get_len (ih))); |
| |
| if (reiserfs_fix_nodes (M_DELETE, &tb, 0) != CARRY_ON) { |
| reiserfs_unfix_nodes (&tb); |
| return 1; |
| } |
| reiserfs_tb_balance (&tb, 0, 0, M_DELETE, 0); |
| return 0; |
| } |
| |
| deh = reiserfs_deh (REISERFS_PATH_LEAF (&path), ih) + path.pos_in_item; |
| entry_len = reiserfs_direntry_entry_len (ih, deh, path.pos_in_item); |
| reiserfs_tb_init (&tb, fs, &path, -(REISERFS_DEH_SIZE + entry_len)); |
| |
| if (reiserfs_fix_nodes (M_CUT, &tb, 0) != CARRY_ON) { |
| reiserfs_unfix_nodes (&tb); |
| return 1; |
| } |
| reiserfs_tb_balance (&tb, 0, 0, M_CUT, 0); |
| return 0; |
| } |
| |
| static void free_unformatted_nodes (reiserfs_filsys_t * fs, |
| reiserfs_path_t * path, |
| int start, int end) |
| { |
| __u32 * item = REISERFS_PATH_ITEM(path); |
| unsigned int i; |
| |
| for (i = start; i < end; i ++) { |
| __u32 unfm = d32_get (item, i); |
| |
| if (unfm != 0) |
| reiserfs_node_forget(fs, unfm); |
| } |
| } |
| |
| void reiserfs_tree_delete (reiserfs_filsys_t * fs, |
| reiserfs_path_t * path, |
| int temporary) |
| { |
| reiserfs_tb_t tb; |
| reiserfs_ih_t * ih = REISERFS_PATH_IH (path); |
| |
| if (reiserfs_ih_ext (ih) && !temporary) |
| free_unformatted_nodes (fs, path, 0, reiserfs_ext_count (ih)); |
| |
| reiserfs_tb_init (&tb, fs, path, |
| -(REISERFS_IH_SIZE + reiserfs_ih_get_len(ih))); |
| |
| if (reiserfs_fix_nodes (M_DELETE, &tb, 0/*ih*/) != CARRY_ON) |
| misc_die ("reiserfs_tree_delete: reiserfs_fix_nodes failed"); |
| |
| reiserfs_tb_balance (&tb, 0, 0, M_DELETE, 0/*zero num*/); |
| } |
| |
| void reiserfs_tree_delete_unit (reiserfs_filsys_t *fs, |
| reiserfs_path_t * path, |
| int cut_size) |
| { |
| reiserfs_ih_t * ih = REISERFS_PATH_IH (path); |
| reiserfs_tb_t tb; |
| |
| if (cut_size >= 0) { |
| misc_die ("reiserfs_tree_delete_unit: cut size == %d", cut_size); |
| } |
| |
| if (reiserfs_ih_ext (ih)) |
| free_unformatted_nodes(fs, path, (reiserfs_ih_get_len(ih) + cut_size) / |
| REISERFS_EXT_SIZE, reiserfs_ext_count (ih)); |
| |
| reiserfs_tb_init (&tb, fs, path, cut_size); |
| |
| if (reiserfs_fix_nodes (M_CUT, &tb, 0) != CARRY_ON) |
| misc_die ("reiserfs_tree_delete_unit: reiserfs_fix_nodes failed"); |
| |
| reiserfs_tb_balance (&tb, 0, 0, M_CUT, 0/*zero num*/); |
| } |
| |
| void reiserfs_tree_insert_unit (reiserfs_filsys_t * fs, |
| reiserfs_path_t * path, |
| const void * body, int size) |
| { |
| reiserfs_tb_t tb; |
| |
| reiserfs_tb_init (&tb, fs, path, size); |
| |
| if (reiserfs_fix_nodes (M_PASTE, &tb, 0/*ih*/) != CARRY_ON) |
| reiserfs_panic ("reiserfs_tree_insert_unit: " |
| "reiserfs_fix_nodes failed"); |
| |
| reiserfs_tb_balance (&tb, 0, body, M_PASTE, 0/*zero num*/); |
| } |
| |
| void reiserfs_tree_insert (reiserfs_filsys_t * fs, |
| reiserfs_path_t * path, |
| reiserfs_ih_t * ih, |
| const void * body) |
| { |
| reiserfs_tb_t tb; |
| |
| reiserfs_tb_init (&tb, fs, path, REISERFS_IH_SIZE + |
| reiserfs_ih_get_len(ih)); |
| |
| if (reiserfs_fix_nodes (M_INSERT, &tb, ih) != CARRY_ON) |
| misc_die ("reiserfs_tree_insert: reiserfs_fix_nodes failed"); |
| |
| reiserfs_tb_balance (&tb, ih, body, M_INSERT, 0/*zero num*/); |
| } |
| |
| /* if name is found in a directory - return 1 and set path to the name, |
| otherwise return 0 and reiserfs_tree_pathrelse path */ |
| int reiserfs_tree_scan_name (reiserfs_filsys_t * fs, |
| reiserfs_key_t * dir, |
| char * name, |
| reiserfs_path_t * path) |
| { |
| const reiserfs_key_t * rdkey; |
| reiserfs_key_t entry_key; |
| reiserfs_deh_t * deh; |
| reiserfs_ih_t * ih; |
| int i, retval; |
| |
| reiserfs_key_set_did (&entry_key, reiserfs_key_get_did (dir)); |
| reiserfs_key_set_oid (&entry_key, reiserfs_key_get_oid (dir)); |
| reiserfs_key_set_off1 (&entry_key, 0); |
| reiserfs_key_set_uni (&entry_key, UNI_DE); |
| |
| |
| if (reiserfs_tree_search_entry (fs, &entry_key, path) == |
| DIRECTORY_NOT_FOUND) |
| { |
| reiserfs_tree_pathrelse (path); |
| return 0; |
| } |
| |
| do { |
| ih = REISERFS_PATH_IH (path); |
| deh = reiserfs_deh (REISERFS_PATH_LEAF (path), ih) + path->pos_in_item; |
| for (i = path->pos_in_item; i < reiserfs_ih_get_entries (ih); i ++, deh ++) |
| { |
| /* the name in directory has the same hash as the given name */ |
| if ((reiserfs_direntry_name_len (ih, deh, i) == |
| (int)strlen (name)) && |
| !memcmp (reiserfs_deh_name (deh, i), name, strlen (name))) |
| { |
| path->pos_in_item = i; |
| return 1; |
| } |
| } |
| |
| rdkey = reiserfs_tree_rkey (path, fs); |
| if (!rdkey || reiserfs_key_comp2 (rdkey, dir)) { |
| reiserfs_tree_pathrelse (path); |
| return 0; |
| } |
| |
| if (!reiserfs_key_dir (rdkey)) |
| reiserfs_panic ("reiserfs_tree_scan_name: can not find name in " |
| "broken directory yet"); |
| |
| /* first name of that item may be a name we are looking for */ |
| entry_key = *rdkey; |
| reiserfs_tree_pathrelse (path); |
| retval = reiserfs_tree_search_entry (fs, &entry_key, path); |
| |
| if (retval != POSITION_FOUND) |
| reiserfs_panic ("reiserfs_tree_scan_name: wrong delimiting " |
| "key in the tree"); |
| } while (1); |
| |
| return 0; |
| } |
| |
| |
| /* returns 0 if name is not found in a directory and 1 if name is |
| found. Stores key found in the entry in 'key'. Returns minimal not used |
| generation counter in 'min_gen_counter'. dies if found object is not a |
| directory. */ |
| int reiserfs_tree_search_name (reiserfs_filsys_t * fs, |
| const reiserfs_key_t * dir, |
| char * name, |
| unsigned int * min_gen_counter, |
| reiserfs_key_t * key) |
| { |
| const reiserfs_key_t * rdkey; |
| reiserfs_key_t entry_key; |
| REISERFS_PATH_INIT (path); |
| reiserfs_deh_t * deh; |
| reiserfs_ih_t * ih; |
| __u32 hash; |
| int retval; |
| int i; |
| |
| |
| reiserfs_key_set_did (&entry_key, reiserfs_key_get_did (dir)); |
| reiserfs_key_set_oid (&entry_key, reiserfs_key_get_oid (dir)); |
| if (!strcmp (name, ".")) |
| hash = OFFSET_DOT; |
| else if (!strcmp (name, "..")) |
| hash = OFFSET_DOT_DOT; |
| else |
| hash = reiserfs_hash_value (fs->hash, name, strlen (name)); |
| reiserfs_key_set_off1 (&entry_key, hash); |
| reiserfs_key_set_uni (&entry_key, UNI_DE); |
| |
| *min_gen_counter = 0; |
| |
| if (reiserfs_tree_search_entry (fs, &entry_key, &path) == |
| DIRECTORY_NOT_FOUND) |
| { |
| reiserfs_tree_pathrelse (&path); |
| return 0; |
| } |
| |
| do { |
| ih = REISERFS_PATH_IH (&path); |
| deh = reiserfs_deh (REISERFS_PATH_LEAF (&path), ih) + path.pos_in_item; |
| for (i = path.pos_in_item; i < reiserfs_ih_get_entries (ih); i ++, deh ++) { |
| if (OFFSET_HASH (reiserfs_deh_get_off (deh)) != OFFSET_HASH (hash)) |
| { |
| /* all entries having the same hash were scanned */ |
| reiserfs_tree_pathrelse (&path); |
| return 0; |
| } |
| |
| if (OFFSET_GEN (reiserfs_deh_get_off (deh)) == |
| *min_gen_counter) |
| { |
| (*min_gen_counter) ++; |
| } |
| |
| if ((reiserfs_direntry_name_len (ih, deh, i) == |
| (int)strlen (name)) && |
| (!memcmp (reiserfs_deh_name (deh, i), name, strlen (name)))) |
| { |
| /* entry found in the directory */ |
| if (key) { |
| memset (key, 0, sizeof (reiserfs_key_t)); |
| reiserfs_key_set_did (key, reiserfs_deh_get_did (deh)); |
| reiserfs_key_set_oid (key, reiserfs_deh_get_obid (deh)); |
| } |
| reiserfs_tree_pathrelse (&path); |
| return 1;//reiserfs_deh_get_obid (deh) ? reiserfs_deh_get_obid (deh) : 1; |
| } |
| } |
| |
| rdkey = reiserfs_tree_rkey (&path, fs); |
| if (!rdkey || reiserfs_key_comp2 (rdkey, dir)) { |
| reiserfs_tree_pathrelse (&path); |
| return 0; |
| } |
| |
| if (!reiserfs_key_dir (rdkey)) |
| reiserfs_panic ("reiserfs_tree_search_name: can not find name " |
| "in broken directory yet"); |
| |
| /* next item is the item of the directory we are looking name in */ |
| if (OFFSET_HASH (reiserfs_key_get_off (rdkey)) != hash) { |
| /* but there is no names with given hash */ |
| reiserfs_tree_pathrelse (&path); |
| return 0; |
| } |
| |
| /* first name of that item may be a name we are looking for */ |
| entry_key = *rdkey; |
| reiserfs_tree_pathrelse (&path); |
| retval = reiserfs_tree_search_entry (fs, &entry_key, &path); |
| if (retval != POSITION_FOUND) |
| reiserfs_panic ("reiserfs_tree_search_name: wrong delimiting " |
| "key in the tree"); |
| |
| } while (1); |
| |
| return 0; |
| } |
| |
| |
| /* compose directory entry: dir entry head and name itself */ |
| static char * make_entry (char * entry, char * name, |
| const reiserfs_key_t * key, |
| __u32 offset) |
| { |
| reiserfs_deh_t * deh; |
| __u16 state; |
| |
| if (!entry) |
| entry = misc_getmem (REISERFS_DEH_SIZE + MISC_ROUND_UP (strlen (name))); |
| |
| memset (entry, 0, REISERFS_DEH_SIZE + MISC_ROUND_UP (strlen (name))); |
| deh = (reiserfs_deh_t *)entry; |
| |
| reiserfs_deh_set_loc (deh, 0); |
| reiserfs_deh_set_off (deh, offset); |
| state = (1 << DEH_Visible2); |
| reiserfs_deh_set_state (deh, state); |
| |
| /* key of object entry will point to */ |
| reiserfs_deh_set_did (deh, reiserfs_key_get_did (key)); |
| reiserfs_deh_set_obid (deh, reiserfs_key_get_oid (key)); |
| |
| memcpy ((char *)(deh + 1), name, strlen (name)); |
| return entry; |
| } |
| |
| /* add new name into a directory. If it exists in a directory - do |
| nothing */ |
| int reiserfs_tree_insert_entry (reiserfs_filsys_t * fs, |
| const reiserfs_key_t * dir, |
| char * name, int name_len, |
| const reiserfs_key_t * key, |
| __u16 fsck_need) |
| { |
| reiserfs_ih_t entry_ih = {{0,}, }; |
| char * entry; |
| int retval; |
| REISERFS_PATH_INIT(path); |
| unsigned int gen_counter; |
| int item_len; |
| __u32 hash; |
| |
| if (reiserfs_tree_search_name (fs, dir, name, &gen_counter, 0)) |
| /* entry is in the directory already or directory was not found */ |
| return 0; |
| |
| /* compose entry key to look for its place in the tree */ |
| reiserfs_key_set_did (&(entry_ih.ih_key), reiserfs_key_get_did (dir)); |
| reiserfs_key_set_oid (&(entry_ih.ih_key), reiserfs_key_get_oid (dir)); |
| if (!strcmp (name, ".")) |
| hash = OFFSET_DOT; |
| else if (!strcmp (name, "..")) |
| hash = OFFSET_DOT_DOT; |
| else |
| hash = reiserfs_hash_value (fs->hash, name, strlen (name)) + gen_counter; |
| reiserfs_key_set_off1 (&(entry_ih.ih_key), hash); |
| reiserfs_key_set_uni (&(entry_ih.ih_key), UNI_DE); |
| |
| reiserfs_ih_set_format (&entry_ih, KEY_FORMAT_1); |
| reiserfs_ih_set_entries (&entry_ih, 1); |
| |
| item_len = REISERFS_DEH_SIZE + name_len; |
| /* |
| if (reiserfs_super_format (fs->fs_ondisk_sb) == REISERFS_FORMAT_3_5) |
| item_len = REISERFS_DEH_SIZE + strlen (name); |
| else if (reiserfs_super_format (fs->fs_ondisk_sb) == REISERFS_FORMAT_3_6) |
| item_len = REISERFS_DEH_SIZE + MISC_ROUND_UP (strlen (name)); |
| else |
| reiserfs_panic ("unknown fs format"); |
| */ |
| |
| reiserfs_ih_set_len (&entry_ih, item_len); |
| |
| /* fsck may need to insert item which was not reached yet */ |
| reiserfs_ih_set_flags (&entry_ih, fsck_need); |
| |
| entry = make_entry (0, name, key, |
| reiserfs_key_get_off (&(entry_ih.ih_key))); |
| |
| retval = reiserfs_tree_search_entry (fs, &(entry_ih.ih_key), &path); |
| switch (retval) { |
| case POSITION_NOT_FOUND: |
| reiserfs_tree_insert_unit (fs, &path, entry, item_len); |
| break; |
| |
| case DIRECTORY_NOT_FOUND: |
| reiserfs_deh_set_loc ((reiserfs_deh_t *)entry, REISERFS_DEH_SIZE); |
| reiserfs_tree_insert (fs, &path, &entry_ih, entry); |
| break; |
| |
| default: |
| reiserfs_panic ("reiserfs_tree_insert_entry: looking for %k (inserting " |
| "name \"%s\") reiserfs_tree_search_entry returned %d", |
| &(entry_ih.ih_key), name, retval); |
| } |
| |
| misc_freemem (entry); |
| return item_len; |
| } |
| |
| |
| /* inserts new or old stat data of a __DIRECTORY__ (unreachable, nlinks == 0) */ |
| int reiserfs_tree_create_stat (reiserfs_filsys_t * fs, |
| reiserfs_path_t * path, |
| const reiserfs_key_t * key, |
| item_modify_t modify) |
| { |
| reiserfs_ih_t ih; |
| reiserfs_sd_t sd; |
| int key_format; |
| |
| if (fs->fs_format == REISERFS_FORMAT_3_5) |
| key_format = KEY_FORMAT_1; |
| else |
| key_format = KEY_FORMAT_2; |
| |
| memset(&sd, 0, sizeof(sd)); |
| reiserfs_stat_init (fs->fs_blocksize, key_format, reiserfs_key_get_did (key), |
| reiserfs_key_get_oid (key), &ih, &sd); |
| |
| if (modify) |
| modify (&ih, &sd); |
| |
| reiserfs_tree_insert (fs, path, &ih, &sd); |
| return key_format; |
| } |
| |
| __u16 reiserfs_tree_root (reiserfs_filsys_t * fs, |
| item_modify_t modify, |
| __u16 ih_flags) |
| { |
| __u16 format; |
| REISERFS_PATH_INIT (path); |
| |
| |
| /* is there root's stat data */ |
| if (reiserfs_tree_search_item (fs, &root_dir_key, &path) == ITEM_NOT_FOUND) { |
| format = reiserfs_tree_create_stat (fs, &path, &root_dir_key, modify); |
| } else { |
| reiserfs_ih_t * ih = REISERFS_PATH_IH (&path); |
| |
| if (!reiserfs_ih_stat (ih)) |
| reiserfs_panic ("It must be root's stat data %k\n", &ih->ih_key); |
| |
| format = (reiserfs_ih_get_len (REISERFS_PATH_IH (&path)) == REISERFS_SD_SIZE) ? |
| KEY_FORMAT_2 : KEY_FORMAT_1; |
| |
| reiserfs_tree_pathrelse (&path); |
| } |
| |
| /* add "." and ".." if any of them do not exist. Last two |
| parameters say: 0 - entry is not added on lost_found pass and 1 |
| - mark item unreachable */ |
| |
| reiserfs_tree_insert_entry (fs, &root_dir_key, ".", |
| reiserfs_direntry_entry_estimate (".", format), |
| &root_dir_key, ih_flags); |
| reiserfs_tree_insert_entry (fs, &root_dir_key, "..", |
| reiserfs_direntry_entry_estimate ("..", format), |
| &parent_root_dir_key, ih_flags); |
| |
| return format; |
| } |
| |
| /* Release all buffers in the path. */ |
| void reiserfs_tree_pathrelse (reiserfs_path_t * p_s_search_path) |
| { |
| int n_path_offset = p_s_search_path->path_length; |
| |
| while ( n_path_offset > REISERFS_PATH_OFFILL ) |
| reiserfs_buffer_close(REISERFS_PATH_BUFFER(p_s_search_path, n_path_offset--)); |
| |
| p_s_search_path->path_length = REISERFS_PATH_OFFILL; |
| } |
| |
| int reiserfs_tree_left_mergeable (reiserfs_filsys_t * s, reiserfs_path_t * path) |
| { |
| reiserfs_ih_t * right; |
| reiserfs_bh_t * bh; |
| int retval; |
| |
| right = reiserfs_ih_at (REISERFS_PATH_LEAF (path), 0); |
| |
| bh = reiserfs_tree_left_neighbor (s, path); |
| if (bh == 0) { |
| return 0; |
| } |
| retval = reiserfs_leaf_mergeable (reiserfs_ih_at (bh, reiserfs_node_items (bh) - 1), |
| right, bh->b_size); |
| reiserfs_buffer_close (bh); |
| return retval; |
| } |
| |
| int reiserfs_tree_right_mergeable (reiserfs_filsys_t * s, reiserfs_path_t * path) |
| { |
| reiserfs_ih_t * left; |
| reiserfs_bh_t * bh; |
| int retval; |
| |
| left = reiserfs_ih_at (REISERFS_PATH_LEAF (path), |
| reiserfs_node_items (REISERFS_PATH_LEAF (path)) - 1); |
| |
| bh = reiserfs_tree_right_neighbor (s, path); |
| if (bh == 0) { |
| return 0; |
| } |
| retval = reiserfs_leaf_mergeable (left, reiserfs_ih_at (bh, 0), bh->b_size); |
| reiserfs_buffer_close (bh); |
| return retval; |
| } |
| |
| /* return 1 if left and right nodes can be packed into 1 node. 0 otherwise */ |
| int reiserfs_tree_node_mergeable(reiserfs_bh_t * left, |
| reiserfs_bh_t * right) |
| { |
| reiserfs_ih_t *ih = reiserfs_ih_at (left, reiserfs_node_items (left) - 1); |
| |
| if (reiserfs_node_free (left) >= reiserfs_node_used (right) - |
| (reiserfs_leaf_mergeable (ih, reiserfs_ih_at(right, 0), left->b_size) |
| ? REISERFS_IH_SIZE : 0)) |
| { |
| return 1; |
| } |
| |
| return 0; |
| } |
| |
| /* A simple 2 nodes merge operation. */ |
| int reiserfs_tree_merge(reiserfs_filsys_t *fs, |
| reiserfs_path_t *dst_path, |
| reiserfs_path_t *src_path) |
| { |
| reiserfs_bufinfo_t dest_bi; |
| reiserfs_bufinfo_t src_bi; |
| int num, res; |
| |
| src_bi.bi_bh = REISERFS_PATH_LEAF (src_path); |
| src_bi.bi_parent = REISERFS_PATH_UPPARENT (src_path, 0); |
| src_bi.bi_position = REISERFS_PATH_UPPARENT_POS (src_path, 0); |
| |
| dest_bi.bi_bh = REISERFS_PATH_LEAF(dst_path); |
| dest_bi.bi_parent = REISERFS_PATH_UPPARENT (dst_path, 0); |
| dest_bi.bi_position = REISERFS_PATH_UPPARENT_POS (dst_path, 0); |
| |
| num = reiserfs_node_items(src_bi.bi_bh); |
| res = reiserfs_lb_copy (fs, &dest_bi, src_bi.bi_bh, |
| FIRST_TO_LAST, num, -1); |
| |
| /* Delete all but the very first one. */ |
| reiserfs_lb_delete (fs, &src_bi, FIRST_TO_LAST, 1, num - 1, -1); |
| |
| /* Delete the very first one and rebalance the tree. */ |
| REISERFS_PATH_LEAF_POS (src_path) = 0; |
| reiserfs_tree_delete (fs, src_path, 0); |
| return res; |
| } |
| |