/* * Copyright 2000-2004 by Hans Reiser, licensing governed by * reiserfsprogs/README */ #ifdef HAVE_CONFIG_H # include #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; }