374 lines
9.4 KiB
C
374 lines
9.4 KiB
C
/*
|
|
* Copyright 1996-2004 by Hans Reiser, licensing governed by
|
|
* reiserfsprogs/README
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
# include <config.h>
|
|
#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);
|
|
}
|
|
|