/* * Copyright 1996-2004 by Hans Reiser, licensing governed by * reiserfsprogs/README */ #ifdef HAVE_CONFIG_H # include #endif #include "reiserfs/libreiserfs.h" #include "misc/bitops.h" void reiserfs_leaf_mkempty (reiserfs_bh_t * bh) { reiserfs_nh_set_items (NODE_HEAD (bh), 0); reiserfs_nh_set_free (NODE_HEAD (bh), REISERFS_NODE_SPACE (bh->b_size)); reiserfs_nh_set_level (NODE_HEAD (bh), LEAF_LEVEL); } __u32 reiserfs_leaf_ibytes (const reiserfs_ih_t * ih, int blocksize) { switch (reiserfs_key_get_type (&ih->ih_key)) { case TYPE_DIRECT: return reiserfs_ih_get_len (ih); case TYPE_EXTENT: return reiserfs_ext_count(ih) * blocksize;// - reiserfs_ih_get_free (ih); case TYPE_STAT_DATA: case TYPE_DIRENTRY: return 0; } reiserfs_warning (stderr, "reiserfs_leaf_ibytes: called for wrong " "type of item %h", ih); return 0; } int reiserfs_leaf_mergeable (reiserfs_ih_t * left, reiserfs_ih_t * right, int bsize) { if (reiserfs_key_comp (&left->ih_key, &right->ih_key) != -1) { reiserfs_panic ("vs-16070: reiserfs_leaf_mergeable: left %k, " "right %k", &(left->ih_key), &(right->ih_key)); } if (reiserfs_key_comp2 (&left->ih_key, &right->ih_key)) return 0; if (reiserfs_key_get_type (&left->ih_key) != reiserfs_key_get_type (&right->ih_key)) { return 0; } /* Directories are always mergeable. If fsck will need to handle dir items separaely too, move it lower. */ if (reiserfs_ih_dir (left)) return 1; /* Merge only items with the same flags. */ if (reiserfs_ih_get_flags(left) != reiserfs_ih_get_flags(right)) return 0; if ((reiserfs_ih_direct (left) || reiserfs_ih_ext (left))) { return (reiserfs_key_get_off (&left->ih_key) + reiserfs_leaf_ibytes (left, bsize) == reiserfs_key_get_off (&right->ih_key)) ? 1 : 0; } return 0; } int reiserfs_leaf_count_items(reiserfs_bh_t *bh) { reiserfs_ih_t * ih; int prev_location; int nr; /* look at the table of item head */ prev_location = bh->b_size; ih = reiserfs_ih_at(bh, 0); nr = 0; while (1) { if (reiserfs_ih_get_loc (ih) + reiserfs_ih_get_len (ih) != prev_location) break; if (reiserfs_ih_get_loc (ih) < REISERFS_IH_SIZE * (nr + 1) + REISERFS_NODEH_SIZE) { break; } if (reiserfs_ih_get_len (ih) > REISERFS_ITEM_MAX (bh->b_size)) break; prev_location = reiserfs_ih_get_loc (ih); ih ++; nr ++; } return nr; } int reiserfs_leaf_free_count(reiserfs_bh_t *bh) { reiserfs_ih_t * ih; int nr; nr = reiserfs_nh_get_items(NODE_HEAD(bh)); ih = reiserfs_ih_at(bh, nr - 1); return (nr ? reiserfs_ih_get_loc (ih) : bh->b_size) - REISERFS_NODEH_SIZE - REISERFS_IH_SIZE * nr; } static int leaf_blkh_correct(reiserfs_bh_t * bh) { unsigned int nr; nr = reiserfs_nh_get_items(NODE_HEAD(bh)); if (nr > ((bh->b_size - REISERFS_NODEH_SIZE) / (REISERFS_IH_SIZE + REISERFS_ITEM_MIN))) { /* item number is too big or too small */ return 0; } return reiserfs_leaf_free_count(bh) == reiserfs_nh_get_free (NODE_HEAD(bh)); } int reiserfs_leaf_estimate_items(reiserfs_bh_t * bh) { int nr = reiserfs_leaf_count_items(bh); return nr >= reiserfs_nh_get_items (NODE_HEAD(bh)) ? reiserfs_nh_get_items (NODE_HEAD(bh)) : nr; } /* for every item call common action and an action corresponding to item type */ void reiserfs_leaf_traverse(reiserfs_bh_t * bh, ih_func_t action, item_func_t * actions) { int i; reiserfs_ih_t * ih; item_func_t iaction; ih = reiserfs_ih_at (bh, 0); for (i = 0; i < reiserfs_nh_get_items (NODE_HEAD (bh)); i ++, ih ++) { if (action) action (ih); iaction = actions[reiserfs_key_get_type (&ih->ih_key)]; if (iaction) iaction (bh, ih); } } /* Returns 0 if not leaf, NT_LEAF if looks correct, NT_IH_ARRAY if looks like corrupted leaf. */ int reiserfs_leaf_valid(reiserfs_bh_t *bh) { int counted; int num; if (!reiserfs_leaf_head (bh)) return 0; counted = reiserfs_leaf_count_items(bh); /* if leaf block header is ok, check item count also. */ if (leaf_blkh_correct(bh)) { num = reiserfs_nh_get_items (NODE_HEAD(bh)); return counted >= num ? NT_LEAF : NT_IH_ARRAY; } /* leaf block header is corrupted, it is ih_array if some items were detected.*/ return counted ? NT_IH_ARRAY : 0; } /* wrappers for operations on one separated leaf */ void reiserfs_leaf_delete_item (reiserfs_filsys_t * fs, reiserfs_bh_t * bh, int item_num) { reiserfs_bufinfo_t bi; bi.bi_bh = bh; bi.bi_parent = 0; bi.bi_position = 0; reiserfs_lb_delete_item (fs, &bi, item_num, 1); } void reiserfs_leaf_delete_entry (reiserfs_filsys_t * fs, reiserfs_bh_t * bh, int item_num, int entry_num, int del_count) { reiserfs_bufinfo_t bi; bi.bi_bh = bh; bi.bi_parent = 0; bi.bi_position = 0; reiserfs_lb_delete_unit (fs, &bi, item_num, entry_num, del_count); } /* ih_key, ih_location and ih_item_len seem correct, check other fields */ static int reiserfs_leaf_ih_correct (reiserfs_ih_t * ih) { int ih_format; int format; /* key format from item_head */ ih_format = reiserfs_ih_get_format (ih); if (ih_format != KEY_FORMAT_1 && ih_format != KEY_FORMAT_2) return 0; /* key format calculated on key */ format = reiserfs_key_format (&ih->ih_key); if (reiserfs_ih_stat (ih)) { /* for stat data we can not find key format from a key itself, so look at the item length */ if (reiserfs_ih_get_len (ih) == REISERFS_SD_SIZE) format = KEY_FORMAT_2; else if (reiserfs_ih_get_len (ih) == REISERFS_SD_SIZE_V1) format = KEY_FORMAT_1; else return 0; } if (format != ih_format) return 0; /* we do not check ih_format.fsck_need as fsck might change it. So, debugreiserfs -p will have to dump it */ return 1; } /* used by debugreisrefs -p only yet */ int reiserfs_leaf_correct_at (reiserfs_filsys_t * fs, reiserfs_ih_t * ih, char * item, unfm_func_t func, int bad_dir) { /* if (!does_key_look_correct (fs, &ih->ih_key)) return 1; if (!reiserfs_leaf_ih_correct (ih)) return 1; */ if (!reiserfs_leaf_ih_correct (ih)) return 1; if (reiserfs_ih_stat (ih) || reiserfs_ih_direct (ih)) return 0; if (reiserfs_ih_dir (ih)) { return reiserfs_direntry_check (fs, ih, item, bad_dir); } if (reiserfs_ih_ext (ih)) { return reiserfs_ext_check (fs, ih, item, func); } return 1; } static int is_symlink = 0; int reiserfs_leaf_print(FILE * fp, reiserfs_filsys_t * fs, reiserfs_bh_t * bh, int print_mode, int first, int last) { reiserfs_ih_t * ih; int i; int from, to; int real_nr, nr; if (!reiserfs_node_formatted (bh, LEAF_LEVEL)) return 1; ih = reiserfs_ih_at (bh,0); real_nr = reiserfs_leaf_count_items(bh); nr = reiserfs_nh_get_items(NODE_HEAD(bh)); reiserfs_warning (fp, "\n===========================================" "========================\n"); reiserfs_warning (fp, "LEAF NODE (%ld) contains %b (real items %d)\n", bh->b_blocknr, bh, real_nr); if (!(misc_test_bit(LP_LEAF_DETAILS, &print_mode))) { reiserfs_warning (fp, "FIRST ITEM_KEY: %k, LAST ITEM KEY: %k\n", &(ih->ih_key), &((ih + real_nr - 1)->ih_key)); return 0; } if (first < 0 || first > real_nr - 1) from = 0; else from = first; if (last < 0 || last > real_nr) to = real_nr; else to = last; reiserfs_warning (fp, "---------------------------------------------" "----------------------------------\n" "|###|type|ilen|f/sp| loc|fmt|fsck| " " key |\n" "| | | |e/cn| | |need| " " |\n"); for (i = from; i < to; i++) { reiserfs_warning (fp, "-----------------------------------------" "--------------------------------------\n" "|%3d|%30H|%s\n", i, ih + i, i >= nr ? " DELETED" : ""); if (reiserfs_ih_stat(ih+i)) { is_symlink = reiserfs_print_stat_data (fp, bh, ih + i, 0/*all times*/); continue; } if (reiserfs_ih_dir(ih+i)) { reiserfs_direntry_print (fp, fs, bh, ih+i); continue; } if (reiserfs_ih_ext(ih+i)) { reiserfs_ext_print (fp, bh, i); continue; } if (reiserfs_ih_direct(ih+i)) { int j = 0; if (is_symlink || misc_test_bit(LP_DIRECT_ITEMS, &print_mode)) { reiserfs_warning (fp, "\""); while (j < reiserfs_ih_get_len (&ih[i])) { if (reiserfs_item_by_ih(bh,ih+i)[j] == 10) reiserfs_warning (fp, "\\n"); else reiserfs_warning (fp, "%c", reiserfs_item_by_ih(bh,ih+i)[j]); j ++; } reiserfs_warning (fp, "\"\n"); } continue; } } reiserfs_warning (fp, "=============================================" "======================\n"); return 0; } __u16 reiserfs_ih_get_format(const reiserfs_ih_t *ih) { return misc_get_bitfield_XX (16, &ih->ih_format, 0, 12); } void reiserfs_ih_set_format(reiserfs_ih_t *ih, __u16 val) { misc_set_bitfield_XX (16, &ih->ih_format, val, 0, 12); } __u16 reiserfs_ih_get_flags(const reiserfs_ih_t *ih) { return misc_get_bitfield_XX (16, &ih->ih_format, 12, 4); } void reiserfs_ih_set_flags(reiserfs_ih_t *ih, __u16 val) { misc_set_bitfield_XX (16, &ih->ih_format, val, 12, 4); }