blob: 8d91cc4c215e3995c99e35abe625fd3cc83e0088 [file] [log] [blame]
/*
* Copyright 1996-2004 by Hans Reiser, licensing governed by
* reiserfsprogs/README
*/
#include "fsck.h"
/*
* Pass0 scans the used part of the partition. It creates two maps which will
* be used on the pass 1. These are a map of nodes looking like leaves and
* a map of "bad" unformatted nodes. After pass 0 we can detect unformatted
* node pointers pointing to leaves.
*/
/* leaves */
reiserfs_bitmap_t * leaves_bitmap;
#define pass0_is_leaf(block) __is_marked (leaves, block)
#define pass0_mark_leaf(block) __mark (leaves, block)
/* nodes which are referred to from only one indirect item */
reiserfs_bitmap_t * good_unfm_bitmap;
#define pass0_is_good_unfm(block) __is_marked (good_unfm, block)
#define pass0_mark_good_unfm(block) __mark (good_unfm, block)
#define pass0_unmark_good_unfm(block) __unmark (good_unfm, block)
/* nodes which are referred to from more than one indirect item */
reiserfs_bitmap_t * bad_unfm_bitmap;
#define pass0_is_bad_unfm(block) __is_marked (bad_unfm, block)
#define pass0_mark_bad_unfm(block) __mark (bad_unfm, block)
#define pass0_unmark_bad_unfm(block) __unmark (bad_unfm, block)
static int correct_direct_item_offset (__u64 offset, int format) {
if (format == KEY_FORMAT_2) {
return (offset && ((offset - 1) % 8 == 0));
} else {
return (offset);
}
return 0;
}
/* bitmaps which are built on pass 0 and are used on pass 1 */
static void make_aux_bitmaps (reiserfs_filsys_t * fs)
{
struct reiserfs_super_block * sb;
sb = fs->fs_ondisk_sb;
/* bitmap of leaves found on the device */
leaves_bitmap = reiserfs_create_bitmap (get_sb_block_count (sb));
good_unfm_bitmap = reiserfs_create_bitmap (get_sb_block_count (sb));
bad_unfm_bitmap = reiserfs_create_bitmap (get_sb_block_count (sb));
}
void delete_aux_bitmaps (void)
{
reiserfs_delete_bitmap (leaves_bitmap);
reiserfs_delete_bitmap (good_unfm_bitmap);
reiserfs_delete_bitmap (bad_unfm_bitmap);
}
/* register block some indirect item points to */
static void register_unfm (unsigned long block)
{
if (!pass0_is_good_unfm (block) && !pass0_is_bad_unfm (block)) {
/* this block was not pointed by other indirect items yet */
pass0_mark_good_unfm (block);
return;
}
if (pass0_is_good_unfm (block)) {
/* block was pointed once already, unmark it in bitmap of good
unformatted nodes and mark in bitmap of bad pointers */
pass0_unmark_good_unfm (block);
pass0_mark_bad_unfm (block);
return;
}
assert (pass0_is_bad_unfm (block));
}
/* 'upper' item is correct if 'upper + 2' exists and its key is greater than
key of 'upper' */
static int upper_correct (struct buffer_head * bh, struct item_head * upper,
int upper_item_num)
{
if (upper_item_num + 2 < B_NR_ITEMS (bh)) {
if (comp_keys (&upper->ih_key, &(upper + 2)->ih_key) != -1)
/* item-num's item is out of order of order */
return 0;
return 1;
}
/* there is no item above the "bad pair" */
return 2;
}
/* 'lower' item is correct if 'lower - 2' exists and its key is smaller than
key of 'lower' */
static int lower_correct (struct buffer_head * bh, struct item_head * lower,
int lower_item_num)
{
if (lower_item_num - 2 >= 0) {
if (comp_keys (&(lower - 2)->ih_key, &lower->ih_key) != -1)
return 0;
return 1;
}
return 2;
}
/* return 1 if something was changed */
static int correct_key_format (struct item_head * ih, int symlink)
{
int dirty = 0;
if (is_stat_data_ih (ih)) {
/* for stat data we have no way to check whether key format in item
head matches to the key format found from the key directly */
if (get_ih_item_len (ih) == SD_V1_SIZE) {
if (get_ih_key_format (ih) != KEY_FORMAT_1) {
/*fsck_log ("correct_key_format: ih_key_format of (%H) is set to format 1\n",
ih);*/
set_ih_key_format (ih, KEY_FORMAT_1);
return 1;
}
return 0;
}
if (get_ih_item_len (ih) == SD_SIZE) {
if (get_ih_key_format (ih) != KEY_FORMAT_2) {
/*fsck_log ("correct_key_format: ih_key_format of (%H) is set to format 2\n",
ih);*/
set_ih_key_format (ih, KEY_FORMAT_2);
return 1;
}
return 0;
}
die ("stat_data item of the wrong length");
}
if (symlink && is_direct_ih(ih) && (key_format(&ih->ih_key) != KEY_FORMAT_1)) {
/* All symlinks are of 3.5 format */
/*fsck_log ("correct_key_format: Symlink keys should be of 3.5 format. %k - fixed.\n", &ih->ih_key); */
set_type_and_offset(KEY_FORMAT_1, &ih->ih_key, get_offset(&ih->ih_key), get_type(&ih->ih_key));
}
if (key_format (&ih->ih_key) != get_ih_key_format (ih)) {
/*fsck_log ("correct_key_format: ih_key_format of (%H) is set to format found in the key\n",
ih);*/
set_ih_key_format (ih, key_format (&ih->ih_key));
dirty = 1;
}
if (is_direct_ih (ih) && get_offset (&ih->ih_key) > fs->fs_blocksize * 4) {
/*fsck_log ("correct_key_format: %H made of indirect type\n", ih);*/
set_type (key_format (&ih->ih_key), &ih->ih_key, TYPE_INDIRECT);
if (get_offset (&ih->ih_key) % fs->fs_blocksize != 1)
fsck_log ("correct_key_format: Item header's key has the wrong offset %H\n", ih);
dirty = 1;
}
return dirty;
}
#if 0
/* fixme: we might try all available hashes */
static int prob_name (reiserfs_filsys_t * fs,
char ** name, int max_len, __u32 deh_offset)
{
int start; /* */
int len;
for (start = 0; start < max_len; start ++) {
for (len = 0; len < max_len - start; len ++) {
if (is_properly_hashed (fs, *name + start, len + 1, deh_offset)) {
*name = *name + start;
return len + 1;
}
}
}
return 0;
}
#endif
static void hash_hits_init (reiserfs_filsys_t * fs)
{
fsck_data (fs)->rebuild.hash_amount = known_hashes ();
fsck_data (fs)->rebuild.hash_hits = getmem (sizeof (unsigned long) * fsck_data (fs)->rebuild.hash_amount);
return;
}
static void add_hash_hit (reiserfs_filsys_t * fs, int hash_code)
{
fsck_data (fs)->rebuild.hash_hits [hash_code] ++;
}
/* deh_location look reasonable, try to find name length. return 0 if
we failed */
static int try_to_get_name_length (struct item_head * ih, struct reiserfs_de_head * deh,
int i)
{
int len;
if (i == 0 || !de_bad_location (deh - 1)) {
len = name_in_entry_length (ih, deh, i);
return (len > 0) ? len : 0;
}
/* previous entry had bad location so we had no way to find
name length */
return 0;
}
/* define this if you are using -t to debug recovering of corrupted directory
item */
#define DEBUG_VERIFY_DENTRY
#undef DEBUG_VERIFY_DENTRY
/* check directory item and try to recover something */
static int verify_directory_item (reiserfs_filsys_t * fs, struct buffer_head * bh,
int item_num)
{
struct item_head * ih;
struct item_head tmp;
char * item;
struct reiserfs_de_head * deh;
char * name;
int name_len;
int bad, lost_found;
int i, j;
char buf[4096];
int dirty;
int hash_code;
int bad_locations;
int min_entry_size = 1;
#ifdef DEBUG_VERIFY_DENTRY
char * direntries;
#endif
ih = B_N_PITEM_HEAD (bh, item_num);
item = B_I_PITEM (bh,ih);
deh = (struct reiserfs_de_head *)item;
dirty = 0;
bad_locations = 0;
if ( (get_ih_entry_count (ih) > (get_ih_item_len(ih) / (DEH_SIZE + min_entry_size))) ||
(get_ih_entry_count (ih) == 0))
{
set_ih_entry_count (ih, (int)get_ih_item_len(ih) / (DEH_SIZE + min_entry_size));
mark_buffer_dirty (bh);
}
if (get_ih_entry_count (ih) == 0) {
delete_item (fs, bh, item_num);
return -1;
}
/* check deh_location */
for (i = 0; i < get_ih_entry_count (ih); i ++) {
/* silently fix deh_state */
if (get_deh_state (deh + i) != (1 << DEH_Visible2)) {
set_deh_state (deh + i, (1 << DEH_Visible2));
mark_buffer_dirty (bh);
}
if (dir_entry_bad_location (deh + i, ih, !i))
mark_de_bad_location (deh + i);
}
#ifdef DEBUG_VERIFY_DENTRY
direntries = getmem (ih_entry_count (ih) * sizeof (int));
printf ("Entries with bad locations within the directory: ");
for (i = 0; i < ih_entry_count (ih); i ++) {
if (de_bad_location (deh + i))
printf ("%d ", i);
}
printf ("\n");
#endif /* DEBUG_VERIFY_DENTRY */
/* find entries names in which have mismatching deh_offset */
for (i = get_ih_entry_count (ih) - 1; i >= 0; i --) {
if (de_bad (deh + i))
/* bad location */
continue;
if (i) {
if (get_deh_location (deh + i - 1) < get_deh_location (deh + i))
mark_de_bad_location (deh + i - 1);
}
name = name_in_entry (deh + i, i);
/* Although we found a name, we not always can get its length as
it depends on deh_location of previous entry. */
name_len = try_to_get_name_length (ih, deh + i, i);
#ifdef DEBUG_VERIFY_DENTRY
if (name_len == 0)
printf ("Trying to find the name length for %d-th entry\n", i);
#endif /* DEBUG_VERIFY_DENTRY */
if (is_dot (name, name_len)) {
if (i != 0)
fsck_log ("block %lu: item %d: \".\" must be the first entry, but it is the %d-th entry\n",
bh->b_blocknr, item_num, i);
/* check and fix "." */
if (get_deh_offset (deh + i) != DOT_OFFSET) {
set_deh_offset (deh + i, DOT_OFFSET);
mark_buffer_dirty (bh);
}
/* "." must point to the directory it is in */
/*
if (not_of_one_file (&(deh[i].deh2_dir_id), &(ih->ih_key))) {
fsck_log ("verify_direntry: block %lu, item %H has entry \".\" "
"pointing to (%K) instead of (%K)\n",
bh->b_blocknr, ih,
&(deh[i].deh2_dir_id), &(ih->ih_key));
set_deh_dirid (deh + i, get_key_dirid (&ih->ih_key));
set_deh_objectid (deh + i, get_key_objectid (&ih->ih_key));
mark_buffer_dirty (bh);
}
*/
} else if (is_dot_dot (name, name_len)) {
if (i != 1)
fsck_log ("block %lu: item %d: \"..\" is %d-th entry\n",
bh->b_blocknr, item_num, i);
/* check and fix ".." */
if (get_deh_offset (deh + i) != DOT_DOT_OFFSET) {
set_deh_offset (deh + i, DOT_DOT_OFFSET);
mark_buffer_dirty (bh);
}
} else {
int min_length, max_length;
/* check other name */
if (name_len == 0) {
/* we do not know the length of name - we will try to find it */
min_length = 1;
max_length = item + get_ih_item_len (ih) - name;
} else
/* we kow name length, so we will try only one name length */
min_length = max_length = name_len;
hash_code = 0;
for (j = min_length; j <= max_length; j ++) {
hash_code = find_hash_in_use (name, j, get_deh_offset (deh + i),
get_sb_hash_code (fs->fs_ondisk_sb));
/* add_hash_hit (fs, hash_code);*/
if (code2func (hash_code) != 0) {
/* deh_offset matches to some hash of the name */
if (fsck_hash_defined (fs) &&
hash_code != func2code (fs->fs_hash_function)) {
/* wrong hash selected - so we can skip this leaf */
return 1;
}
if (!name_len) {
fsck_log ("%s: block %lu, item %H: Found a name \"%.*s\" for %d-th entry "
"matching to the hash %u.\n", __FUNCTION__,
bh->b_blocknr, ih, j, name, i, get_deh_offset (deh + i));
/* FIXME: if next byte is 0 we think that the name is aligned to 8 byte boundary */
if (i) {
set_deh_location (&deh[i - 1], get_deh_location (deh + i) +
((name[j] || fs->fs_format == REISERFS_FORMAT_3_5) ? j : ROUND_UP (j)));
mark_de_good_location (deh + i - 1);
mark_buffer_dirty (bh);
}
}
break;
}
}
add_hash_hit (fs, hash_code);
if (j == max_length + 1) {
/* deh_offset does not match to anything. it will be
deleted for now, but maybe we could just fix a
deh_offset if it is in ordeer */
mark_de_bad_offset (deh + i);
}
}
} /* for */
#ifdef DEBUG_VERIFY_DENTRY
printf ("Entries with mismatching hash: ");
for (i = 0; i < ih_entry_count (ih); i ++) {
if (de_bad_offset (deh + i))
printf ("%d ", i);
}
printf ("\n");
#endif /* DEBUG_VERIFY_DENTRY */
/* correct deh_locations such that code cutting entries will not get
screwed up */
{
int prev_loc;
int loc_fixed;
prev_loc = get_ih_item_len (ih);
for (i = 0; i < get_ih_entry_count (ih); i ++) {
loc_fixed = 0;
if (de_bad_location (deh + i)) {
set_deh_location (deh + i, prev_loc/* - 1*/);
mark_buffer_dirty (bh);
loc_fixed = 1;
} else {
if (get_deh_location (deh + i) >= prev_loc) {
set_deh_location (deh + i, prev_loc/* - 1*/);
mark_buffer_dirty (bh);
loc_fixed = 1;
}
}
prev_loc = get_deh_location (deh + i);
if (i == get_ih_entry_count (ih) - 1) {
/* last entry starts right after an array of dir entry headers */
if (!de_bad (deh + i) &&
get_deh_location (deh + i) != (DEH_SIZE * get_ih_entry_count (ih))) {
/* free space in the directory item */
fsck_log ("%s: block %lu, item %H: Directory item has a free space - deleting\n",
__FUNCTION__, bh->b_blocknr, ih);
cut_entry (fs, bh, item_num, get_ih_entry_count (ih), 0);
}
if (get_deh_location (deh + i) != (DEH_SIZE * get_ih_entry_count (ih))) {
set_deh_location (&deh[i], (DEH_SIZE * get_ih_entry_count (ih)));
loc_fixed = 1;
mark_buffer_dirty (bh);
}
}
#ifdef DEBUG_VERIFY_DENTRY
if (loc_fixed)
direntries [i] = 1;
#endif
} /* for */
#ifdef DEBUG_VERIFY_DENTRY
printf ("Entries with fixed deh_locations: ");
for (i = 0; i < ih_entry_count (ih); i ++) {
if (direntries [i])
printf ("%d ", i);
}
printf ("\n");
#endif /* DEBUG_VERIFY_DENTRY */
}
#ifdef DEBUG_VERIFY_DENTRY
printf (" N location name\n");
for (i = 0; i < ih_entry_count (ih); i ++) {
if (de_bad (deh + i) ||
(i && de_bad (deh + i - 1)) || /* previous entry marked bad */
(i < ih_entry_count (ih) - 1 && de_bad (deh + i + 1))) { /* next entry is marked bad */
/* print only entries to be deleted and their nearest neighbors */
printf ("%3d: %8d ", i, deh_location (deh + i));
if (de_bad (deh + i))
printf ("will be deleted\n");
else
printf ("\"%.*s\"\n", name_in_entry_length (ih, deh + i, i),
name_in_entry (deh + i, i));
}
}
#endif
bad = lost_found = 0;
tmp = *ih;
/* mark enries of /lost+found as bad */
deh = B_I_DEH (bh, ih);
for (i = 0; i < get_ih_entry_count (ih); i ++, deh ++) {
unsigned int dirid, objectid;
if (de_bad (deh))
continue;
sprintf (buf, "%.*s", name_in_entry_length (ih, deh, i), name_in_entry (deh, i));
if (sscanf (buf, "%d_%d", &dirid, &objectid) != 2)
continue;
if (get_deh_dirid (deh) != dirid || get_deh_objectid (deh) != objectid)
continue;
/* entry in lost+found */
// printf ("%s - will be deleted\n", buf);
lost_found++;
mark_de_bad_offset (deh);
}
/* delete entries which are marked bad */
for (i = 0; i < get_ih_entry_count (ih); i ++) {
deh = B_I_DEH (bh, ih) + i;
if (de_bad (deh)) {
bad ++;
if (get_ih_entry_count (ih) == 1) {
delete_item (fs, bh, item_num);
break;
} else {
cut_entry (fs, bh, item_num, i, 1);
}
i --;
}
}
if (bad == get_ih_entry_count (&tmp)) {
if (lost_found != bad) {
fsck_log ("%s: block %lu, item %H: All entries were deleted from the directory\n",
__FUNCTION__, bh->b_blocknr, &tmp);
}
return -1;
}
deh = B_I_DEH (bh, ih);
if (get_offset (&ih->ih_key) != get_deh_offset (deh)) {
fsck_log ("verify_direntry: block %lu, item %H: Key's offset %k must match the directory's hash (%u) - changed.\n",
bh->b_blocknr, ih, &ih->ih_key, get_deh_offset (deh));
set_offset (key_format (&ih->ih_key), &ih->ih_key, get_deh_offset (deh));
mark_buffer_dirty (bh);
}
if (bad > lost_found)
fsck_log ("pass0: block %lu, item %H: %d entries were deleted\n",
bh->b_blocknr, &tmp, bad - lost_found);
return 0;
}
static __inline__ int does_it_fit_into_dev (__u64 offset, __u64 fs_size) {
/*
Count of unformatted pointers - offset / blocksize
Count of blocks to store them - UNFM_P_SIZE * offset / blocksize / MAX_ITEM_LEN
Size to store it - blocksize * UNFM_P_SIZE * offset / blocksize / MAX_ITEM_LEN
*/
return ( UNFM_P_SIZE * offset / MAX_ITEM_LEN(fs->fs_blocksize) < fs_size) ? 1 : 0;
}
static int is_wrong_short_key (struct key * key) {
if (get_key_dirid (key) == 0 || get_key_objectid (key) == 0 || get_key_objectid (key) == 1 ||
get_key_dirid (key) == ~(__u32)0 || get_key_objectid (key) == ~(__u32)0 ||
get_key_dirid (key) == get_key_objectid (key) ||
/* the alloc=packing_groups used to allow dirid = 1
(get_key_dirid (key) == 1 && get_key_objectid (key) != 2) || */
(get_key_dirid (key) != 1 && get_key_objectid (key) == 2) )
return 1;
return 0;
}
/* 1 if some of fields in the block head of bh look bad */
int leaf_structure_check (reiserfs_filsys_t * fs, struct buffer_head * bh) {
struct block_head * blkh;
int free_space, counted;
blkh = B_BLK_HEAD (bh);
if (!is_leaf_block_head(bh->b_data)) {
/* We should not get here on rebuild. */
fsck_log ("block %lu: The block does not look like a leaf.\n", bh->b_blocknr);
one_more_corruption (fs, FATAL);
return 1;
}
if (get_blkh_nr_items (blkh) == 0)
return 0;
counted = leaf_count_ih(bh->b_data, bh->b_size);
if (counted < get_blkh_nr_items (blkh)) {
fsck_log ("block %lu: The number of items (%lu) is incorrect, should be (%lu)",
bh->b_blocknr, get_blkh_nr_items(blkh), counted);
if (fsck_mode(fs) == FSCK_REBUILD) {
set_blkh_nr_items(blkh, counted);
fsck_log (" - corrected\n");
mark_buffer_dirty (bh);
} else {
fsck_log ("\n");
one_more_corruption (fs, FATAL);
return 1;
}
}
free_space = leaf_free_space_estimate(bh->b_data, bh->b_size);
if (get_blkh_free_space (blkh) != free_space) {
fsck_log ("block %lu: The free space (%lu) is incorrect, should be (%lu)",
bh->b_blocknr, get_blkh_free_space (blkh), free_space);
if (fsck_mode(fs) != FSCK_CHECK && fsck_mode(fs) != FSCK_AUTO) {
set_blkh_free_space (blkh, free_space);
fsck_log (" - corrected\n");
mark_buffer_dirty (bh);
} else {
fsck_log ("\n");
one_more_corruption (fs, FIXABLE);
return 1;
}
}
return 0;
}
/* do this on pass 0 with every leaf marked used */
/* FIXME: we can improve fixing of broken keys: we can ssfe direct items which
go after stat data and have broken keys */
static void pass0_correct_leaf (reiserfs_filsys_t * fs,
struct buffer_head * bh)
{
int file_format = KEY_FORMAT_UNDEFINED;
struct item_head * ih;
__u32 * ind_item;
__u64 fs_size;
__u64 offset;
int symlnk = 0;
int bad_order;
unsigned long unfm_ptr;
// unsigned int nr_items;
int i, j, nr_items;
int dirty = 0;
leaf_structure_check(fs, bh);
/* Delete all safe links. */
for (i = get_blkh_nr_items (B_BLK_HEAD (bh)) - 1; i >= 0; i--) {
if (get_key_dirid (&B_N_PITEM_HEAD (bh, i)->ih_key) == ~(__u32)0) {
delete_item (fs, bh, i);
}
if (get_key_dirid (&B_N_PITEM_HEAD (bh, i)->ih_key) == BADBLOCK_DIRID &&
get_key_objectid (&B_N_PITEM_HEAD (bh, i)->ih_key) == BADBLOCK_OBJID) {
delete_item (fs, bh, i);
}
}
fs_size = (__u64)fs->fs_blocksize * get_sb_block_count (fs->fs_ondisk_sb);
start_again:
ih = B_N_PITEM_HEAD (bh, 0);
bad_order = 0;
for (i = 0; i < (nr_items = get_blkh_nr_items (B_BLK_HEAD (bh))); i ++, ih ++) {
if (is_indirect_ih(ih) && (get_ih_item_len (ih) % 4 != 0)) {
set_type(get_ih_key_format(ih), &ih->ih_key, TYPE_UNKNOWN);
dirty = 1;
}
if (type_unknown (&ih->ih_key)) {
if ((get_ih_item_len (ih) == SD_SIZE) || (get_ih_item_len (ih) == SD_V1_SIZE)) {
set_type_and_offset (KEY_FORMAT_1, &ih->ih_key, SD_OFFSET, TYPE_STAT_DATA);
dirty = 1;
fsck_log("pass0: vpf-10100: block %lu, item (%d): Unknown item type of StatData size,"
" type set to StatData %k\n", bh->b_blocknr, i, &ih->ih_key);
} else {
fsck_log("pass0: vpf-10110: block %lu, item (%d): Unknown item type found %k - deleted\n",
bh->b_blocknr, i, &ih->ih_key);
delete_item (fs, bh, i);
goto start_again;
}
}
if (is_wrong_short_key (&ih->ih_key)) {
/* sometimes stat datas get k_objectid==0 or k_dir_id==0 */
/* if (i == (nr_items - 1)) {
if (i == 0) {
fsck_log ("block %lu: item %d: (%H) id equals 0\n",
bh->b_blocknr, i, ih);
return;
}
// delete last item
fsck_log ("block %lu: item %d: (%H) id equals 0\n",
bh->b_blocknr, i, ih);
delete_item (fs, bh, i - 1);
return;
}
*/
/* FIXME:
18842 19034 0x1 IND (2)
19035 19035 0x0 SD (0)
18842 1 0x1 IND (1)
18842 1 0x1001 DRCT (2)
*/
/* there is next item: if it is not stat data - take its k_dir_id
and k_objectid. if key order will be still wrong - the changed
item will be deleted */
if (i && !is_stat_data_ih (ih)) {
/* previous item has a wrong short_key */
fsck_log ("pass0: vpf-10120: block %lu: item %d: Wrong key %k, corrected to ",
bh->b_blocknr, i, &ih->ih_key);
set_key_dirid (&ih->ih_key, get_key_dirid (&(ih - 1)->ih_key));
set_key_objectid (&ih->ih_key, get_key_objectid (&(ih - 1)->ih_key));
fsck_log ("%k\n", &ih->ih_key);
dirty = 1;
} else if ((i < nr_items - 1) && !is_stat_data_ih (ih + 1)) {
if (!is_wrong_short_key(&(ih + 1)->ih_key)) {
fsck_log ("pass0: vpf-10130: block %lu: item %d: Wrong key %k, corrected to ",
bh->b_blocknr, i, &ih->ih_key);
set_key_dirid (&ih->ih_key, get_key_dirid (&(ih + 1)->ih_key));
set_key_objectid (&ih->ih_key, get_key_objectid (&(ih + 1)->ih_key));
/* set_offset (KEY_FORMAT_1, &ih->ih_key, 0);
set_type (KEY_FORMAT_1, &ih->ih_key, TYPE_STAT_DATA);*/
fsck_log ("%k\n", &ih->ih_key);
dirty = 1;
goto start_again;
} else {
fsck_log ("pass0: vpf-10140: block %lu: items %d and %d have bad short keys %k, %k, both deleted\n",
bh->b_blocknr, i, i+1, &ih->ih_key, &(ih + 1)->ih_key);
delete_item (fs, bh, i);
delete_item (fs, bh, i);
goto start_again;
}
} else {
fsck_log ("pass0: vpf-10150: block %lu: item %d: Wrong key %k, deleted\n",
bh->b_blocknr, i, &ih->ih_key);
delete_item (fs, bh, i);
goto start_again;
}
}
if (i && i + 1 < nr_items) {
if (is_stat_data_ih (ih - 1) && !is_stat_data_ih (ih) &&
!is_direct_ih (ih + 1) && !is_stat_data_ih (ih + 1)) {
/* i or i+1 item should be SD or i+1 should be direct item */
if ((get_ih_item_len (ih) == SD_SIZE) || (get_ih_item_len (ih) == SD_V1_SIZE)) {
/* make i as SD */
fsck_log("pass0: vpf-10400: block %lu, item %d: Wrong order of items - "
"change the type of the key %k to StatData\n", bh->b_blocknr, i, &ih->ih_key);
set_type_and_offset (KEY_FORMAT_1, &ih->ih_key, SD_OFFSET, TYPE_STAT_DATA);
dirty = 1;
} else if ((get_ih_item_len (ih+1) == SD_SIZE) || (get_ih_item_len (ih+1) == SD_V1_SIZE)) {
/* make i+1 as SD */
fsck_log("pass0: vpf-10410: block %lu, item %d: Wrong order of items - "
"change the type of the key %k to StatData\n", bh->b_blocknr, i + 1, &(ih + 1)->ih_key);
set_type_and_offset (KEY_FORMAT_1, &(ih + 1)->ih_key, SD_OFFSET, TYPE_STAT_DATA);
dirty = 1;
} else if (is_indirect_ih(ih)) {
fsck_log("pass0: vpf-10420: block %lu, item %d: Wrong order of items - "
"change the type of the key %k to Direct\n", bh->b_blocknr, i+1, &(ih + 1)->ih_key);
set_type (get_ih_key_format(ih+1), &(ih + 1)->ih_key, TYPE_DIRECT);
dirty = 1;
}
}
}
if (i && ((is_stat_data_ih (ih - 1) &&
!is_stat_data_ih (ih) &&
(get_key_dirid (&(ih - 1)->ih_key) != get_key_dirid (&ih->ih_key))) ||
(is_stat_data_ih (ih) &&
(get_key_dirid (&(ih - 1)->ih_key) > get_key_dirid (&ih->ih_key)))))
{
/* not the same dir_id of the same file or not increasing dir_id of different files */
if ((i > 1) && get_key_dirid (&(ih - 2)->ih_key) == get_key_dirid (&(ih - 1)->ih_key)) {
/* fix i-th */
if (!is_stat_data_ih (ih)) {
fsck_log("pass0: vpf-10430: block %lu, item %d: Wrong order of items - "
"change the dir_id of the key %k to %lu\n",
bh->b_blocknr, i, &ih->ih_key, get_key_dirid (&(ih - 1)->ih_key));
set_key_dirid (&ih->ih_key, get_key_dirid (&(ih - 1)->ih_key));
dirty = 1;
} else if (i + 1 < nr_items) {
fsck_log("pass0: vpf-10440: block %lu, item %d: Wrong order of items - "
"change the dir_id of the key %k to %lu\n",
bh->b_blocknr, i, &ih->ih_key, get_key_dirid (&(ih + 1)->ih_key));
set_key_dirid (&ih->ih_key, get_key_dirid (&(ih + 1)->ih_key));
dirty = 1;
}
} else
if ((i + 1 < nr_items) && get_key_dirid (&ih->ih_key) == get_key_dirid (&(ih + 1)->ih_key)) {
fsck_log("pass0: vpf-10450: block %lu, item %d: Wrong order of items - "
"change the dir_id of the key %k to %lu\n",
bh->b_blocknr, i - 1, &(ih - 1)->ih_key, get_key_dirid (&ih->ih_key));
/* fix (i - 1)-th */
set_key_dirid (&(ih - 1)->ih_key, get_key_dirid (&ih->ih_key));
dirty = 1;
}
}
if (i && i + 1 < nr_items) {
/* there is a previous and a next items */
if ((get_key_dirid (&(ih - 1)->ih_key) == get_key_dirid (&(ih + 1)->ih_key)) &&
(get_key_dirid (&(ih - 1)->ih_key) != get_key_dirid (&ih->ih_key)))
{
fsck_log("pass0: vpf-10460: block %lu, item %d: Wrong order of items - "
"change the dir_id of the key %k to %lu\n",
bh->b_blocknr, i, &ih->ih_key, get_key_dirid (&(ih - 1)->ih_key));
set_key_dirid (&ih->ih_key, get_key_dirid (&(ih - 1)->ih_key));
dirty = 1;
}
if (is_stat_data_ih (ih - 1) && is_indirect_ih (ih) && is_direct_ih (ih + 1)) {
if ((get_key_objectid (&(ih - 1)->ih_key) == get_key_objectid (&(ih + 1)->ih_key)) &&
(get_key_objectid (&(ih - 1)->ih_key) != get_key_objectid (&ih->ih_key)))
{
fsck_log("pass0: vpf-10470: block %lu, item %d: Wrong order of items - "
"change the object_id of the key %k to %lu\n",
bh->b_blocknr, i, &ih->ih_key, get_key_objectid (&(ih - 1)->ih_key));
set_key_objectid (&ih->ih_key, get_key_objectid (&(ih - 1)->ih_key));
dirty = 1;
}
if ((get_key_objectid (&(ih - 1)->ih_key) == get_key_objectid (&ih->ih_key)) &&
(get_key_objectid (&(ih - 1)->ih_key) != get_key_objectid (&(ih + 1)->ih_key)))
{
fsck_log("pass0: vpf-10480: block %lu, item %d: Wrong order of items - "
"change the object_id of the key %k to %lu\n",
bh->b_blocknr, i + 1, &(ih+1)->ih_key, get_key_objectid (&(ih - 1)->ih_key));
set_key_objectid (&(ih + 1)->ih_key, get_key_objectid (&(ih - 1)->ih_key));
dirty = 1;
}
if ((get_key_objectid (&ih->ih_key) == get_key_objectid (&(ih + 1)->ih_key)) &&
(get_key_objectid (&(ih - 1)->ih_key) != get_key_objectid (&(ih + 1)->ih_key)))
{
fsck_log("pass0: vpf-10490: block %lu, item %d: Wrong order of items - "
"change the object_id of the key %k to %lu\n",
bh->b_blocknr, i - 1, &(ih-1)->ih_key, get_key_objectid (&(ih + 1)->ih_key));
set_key_objectid (&(ih - 1)->ih_key, get_key_objectid (&(ih + 1)->ih_key));
dirty = 1;
}
if ((get_key_dirid (&(ih - 1)->ih_key) == get_key_dirid (&ih->ih_key)) &&
(get_key_dirid (&(ih - 1)->ih_key) != get_key_dirid (&(ih + 1)->ih_key)))
{
fsck_log("pass0: vpf-10500: block %lu, item %d: Wrong order of items - "
"change the dir_id of the key %k to %lu\n",
bh->b_blocknr, i + 1, &(ih+1)->ih_key, get_key_dirid (&(ih - 1)->ih_key));
set_key_dirid (&(ih + 1)->ih_key, get_key_dirid (&(ih - 1)->ih_key));
dirty = 1;
}
if ((get_key_dirid (&ih->ih_key) == get_key_dirid (&(ih + 1)->ih_key)) &&
(get_key_dirid (&(ih - 1)->ih_key) != get_key_dirid (&(ih + 1)->ih_key)))
{
fsck_log("pass0: vpf-10510: block %lu, item %d: Wrong order of items - "
"change the dir_id of the key %k to %lu\n",
bh->b_blocknr, i - 1, &(ih-1)->ih_key, get_key_dirid (&(ih + 1)->ih_key));
set_key_dirid (&(ih - 1)->ih_key, get_key_dirid (&(ih + 1)->ih_key));
dirty = 1;
}
}
}
if (i && is_stat_data_ih (ih) &&
get_key_dirid (&(ih - 1)->ih_key) == get_key_dirid (&ih->ih_key) &&
get_key_objectid (&(ih - 1)->ih_key) >= get_key_objectid (&ih->ih_key)) {
if ((i + 1 < nr_items) && !is_stat_data_ih (ih + 1)) {
if (get_key_objectid (&(ih - 1)->ih_key) < get_key_objectid (&(ih + 1)->ih_key)) {
fsck_log("pass0: vpf-10520: block %lu, item %d: Wrong order of items - "
"change the object_id of the key %k to %lu\n",
bh->b_blocknr, i - 1, &(ih-1)->ih_key, get_key_objectid (&(ih + 1)->ih_key));
set_key_objectid (&ih->ih_key, get_key_objectid (&(ih + 1)->ih_key));
dirty = 1;
}
}
}
if (i && is_stat_data_ih (ih - 1) && !is_stat_data_ih (ih) &&
(get_key_objectid (&(ih - 1)->ih_key) != get_key_objectid (&ih->ih_key)))
{
int err = 0;
if (i > 1) {
if (comp_short_keys (&(ih - 2)->ih_key, &(ih - 1)->ih_key) != -1)
misc_set_bit (1, &err);
if (comp_short_keys (&(ih - 2)->ih_key, &ih->ih_key) != -1)
misc_set_bit (2, &err);
}
if (i + 1 < nr_items) {
if (comp_short_keys (&(ih - 1)->ih_key, &(ih + 1)->ih_key) != -1)
misc_set_bit (3, &err);
if (comp_short_keys (&ih->ih_key, &(ih + 1)->ih_key) != -1)
misc_set_bit (4, &err);
}
/*
if ((test_bit (1, err) || test_bit (3, err)) &&
(test_bit (2, err) || test_bit (4, err))) {
// thera are no problem-free keys, delete them both
delete_item (fs, bh, i - 1);
delete_item (fs, bh, i - 1);
goto start_again;
}
*/
if (!misc_test_bit (1, &err) && !misc_test_bit (3, &err) &&
!misc_test_bit (2, &err) && !misc_test_bit (4, &err)) {
if (i <= 1) {
/* take bigger */
if (comp_short_keys (&(ih - 1)->ih_key, &ih->ih_key) == 1) {
fsck_log("pass0: vpf-10530: block %lu, item %d: Wrong order of items - "
"change the object_id of the key %k to %lu\n",
bh->b_blocknr, i, &ih->ih_key, get_key_objectid (&(ih - 1)->ih_key));
set_key_objectid (&ih->ih_key, get_key_objectid (&(ih - 1)->ih_key));
} else {
fsck_log("pass0: vpf-10540: block %lu, item %d: Wrong order of items - "
"change the object_id of the key %k to %lu\n",
bh->b_blocknr, i - 1, &(ih - 1)->ih_key, get_key_objectid (&ih->ih_key));
set_key_objectid (&(ih - 1)->ih_key, get_key_objectid (&ih->ih_key));
}
} else {
/* take smaller */
if (comp_short_keys (&(ih - 1)->ih_key, &ih->ih_key) == 1) {
fsck_log("pass0: vpf-10550: block %lu, item %d: Wrong order of items - "
"change the object_id of the key %k to %lu\n",
bh->b_blocknr, i - 1, &(ih - 1)->ih_key, get_key_objectid (&ih->ih_key));
set_key_objectid (&(ih - 1)->ih_key, get_key_objectid (&ih->ih_key));
} else {
fsck_log("pass0: vpf-10560: block %lu, item %d: Wrong order of items - "
"change the object_id of the key %k to %lu\n",
bh->b_blocknr, i, &ih->ih_key, get_key_objectid (&(ih - 1)->ih_key));
set_key_objectid (&ih->ih_key, get_key_objectid (&(ih - 1)->ih_key));
}
}
dirty = 1;
} else if (!misc_test_bit (1, &err) && !misc_test_bit (3, &err)) {
/* take i - 1 */
fsck_log("pass0: vpf-10590: block %lu, item %d: Wrong order of items - "
"change the object_id of the key %k to %lu\n",
bh->b_blocknr, i, &ih->ih_key, get_key_objectid (&(ih - 1)->ih_key));
set_key_objectid (&ih->ih_key, get_key_objectid (&(ih - 1)->ih_key));
dirty = 1;
} else if (!misc_test_bit (2, &err) && !misc_test_bit (4, &err)) {
/* take i */
fsck_log("pass0: vpf-10600: block %lu, item %d: Wrong order of items - "
"change the object_id of the key %k to %lu\n",
bh->b_blocknr, i - 1, &(ih - 1)->ih_key, get_key_objectid (&ih->ih_key));
set_key_objectid (&(ih - 1)->ih_key, get_key_objectid (&ih->ih_key));
dirty = 1;
}
}
/* this recovers corruptions like the below:
1774 1732 0 0
116262638 1732 1 3
1774 1736 0 0 */
if (i && is_stat_data_ih (ih - 1) && !is_stat_data_ih (ih)) {
if (get_key_objectid (&ih->ih_key) != get_key_objectid (&(ih - 1)->ih_key) ||
get_key_dirid (&ih->ih_key) != get_key_dirid (&(ih - 1)->ih_key) ||
get_offset (&ih->ih_key) != 1) {
if (is_direntry_ih (ih)) {
fsck_log ("pass0: vpf-10160: block %lu: item %d: No \".\" entry found in "
"the first item of a directory\n", bh->b_blocknr, i);
set_key_dirid (&ih->ih_key, get_key_dirid (&(ih - 1)->ih_key));
set_key_objectid (&ih->ih_key, get_key_objectid (&(ih - 1)->ih_key));
dirty = 1;
} else {
fsck_log ("pass0: vpf-10170: block %lu: item %d: Wrong order of items - "
"the item \n\t%H fixed to ", bh->b_blocknr, i, ih);
set_key_dirid (&ih->ih_key, get_key_dirid (&(ih - 1)->ih_key));
set_key_objectid (&ih->ih_key, get_key_objectid (&(ih - 1)->ih_key));
if (get_ih_item_len (ih - 1) == SD_SIZE) {
/* stat data is new, therefore this item is new too */
set_offset (KEY_FORMAT_2, &(ih->ih_key), 1);
if ((get_ih_entry_count (ih) != 0xffff) && (get_ih_item_len (ih) % 4 == 0))
set_type (KEY_FORMAT_2, &(ih->ih_key), TYPE_INDIRECT);
else
set_type (KEY_FORMAT_2, &(ih->ih_key), TYPE_DIRECT);
set_ih_key_format (ih, KEY_FORMAT_2);
} else {
/* stat data is old, therefore this item is old too */
set_offset (KEY_FORMAT_1, &(ih->ih_key), 1);
if ((get_ih_entry_count (ih) != 0xffff) && (get_ih_item_len (ih) % 4 == 0))
set_type (KEY_FORMAT_1, &(ih->ih_key), TYPE_INDIRECT);
else {
set_type (KEY_FORMAT_1, &(ih->ih_key), TYPE_DIRECT);
set_ih_free_space (ih, 0xffff);
}
set_ih_key_format (ih, KEY_FORMAT_1);
}
fsck_log ("\n\t%H\n", ih);
dirty = 1;
}
}
}
/* FIXME: corruptions like:
56702 66802 1 2
56702 65536 0 0
56702 66803 1 2
do not get recovered (both last items will be deleted) */
/* delete item if it is not in correct order of object items */
if (i && not_of_one_file (&ih->ih_key, &(ih - 1)->ih_key) &&
!is_stat_data_ih (ih)) {
fsck_log ("pass0: vpf-10180: block %lu: item %d: The item %k, which follows non StatData item %k, is deleted\n",
bh->b_blocknr, i, &ih->ih_key, &(ih - 1)->ih_key);
delete_item (fs, bh, i);
goto start_again;
}
if (is_stat_data_ih (ih)) {
if (get_offset (&ih->ih_key) != 0) {
set_offset(KEY_FORMAT_1, &ih->ih_key, 0);
dirty = 1;
}
} else if (!is_direntry_ih (ih)) {
/* not SD, not direntry */
if (i && comp_short_keys (&(ih - 1)->ih_key, &ih->ih_key) == 0) {
if (is_stat_data_ih (ih - 1)) {
if (get_offset (&ih->ih_key) != 1) {
set_offset(key_format(&ih->ih_key), &ih->ih_key, 1);
dirty = 1;
}
} else if (is_indirect_ih (ih - 1) && is_direct_ih (ih)) {
if (get_offset (&ih->ih_key) !=
get_offset(&(ih - 1)->ih_key) + I_UNFM_NUM (ih - 1) * fs->fs_blocksize)
{
set_offset(key_format(&ih->ih_key), &ih->ih_key,
get_offset(&(ih - 1)->ih_key) + I_UNFM_NUM (ih - 1) * fs->fs_blocksize);
dirty = 1;
}
} else {
/* if indirect item or not the first direct item in the leaf */
fsck_log("pass0: vpf-10250: block %lu, item %d: The item %k with wrong type is deleted\n",
bh->b_blocknr, i, &ih->ih_key);
delete_item (fs, bh, i);
goto start_again;
}
/* Check the lenght of the direct item; offset should be ok already. */
if (is_direct_ih (ih)) {
if (STORE_TAIL_IN_UNFM (get_offset (&ih->ih_key) + get_ih_item_len (ih) - 1,
get_ih_item_len (ih), bh->b_size))
{
fsck_log("pass0: vpf-10700: block %lu, item %d: The item with wrong offset"
" or length found %k, len % lu - deleted\n", bh->b_blocknr, i, &ih->ih_key,
get_ih_item_len (ih));
delete_item (fs, bh, i);
goto start_again;
}
}
} else {
/*first item in the node or first item of the file */
if (i) {
/* first item of the file, but not SD - delete */
fsck_log("pass0: vpf-10190: block %lu, item %d: The item %k, which follows non StatData"
" item %k, is deleted\n", bh->b_blocknr, i, &ih->ih_key, &(ih - 1)->ih_key );
delete_item (fs, bh, i);
goto start_again;
}
/* indirect or direct is the first in the leaf */
offset = (__u64)get_offset (&ih->ih_key);
if (is_indirect_ih (ih)) {
if (offset % fs->fs_blocksize != 1) {
fsck_log("pass0: vpf-10200: block %lu, item %d: The item %k with wrong offset is deleted\n",
bh->b_blocknr, i, &ih->ih_key);
delete_item (fs, bh, i);
goto start_again;
}
} else if (is_direct_ih (ih)) {
if (!correct_direct_item_offset (get_offset (&ih->ih_key), key_format (&ih->ih_key)) ||
((get_offset (&ih->ih_key) % bh->b_size - 1) + get_ih_item_len (ih) > bh->b_size) ||
STORE_TAIL_IN_UNFM (offset + get_ih_item_len (ih) - 1, get_ih_item_len (ih), bh->b_size))
{
fsck_log("pass0: vpf-10210: block %lu, item %d: The item with wrong offset ",
bh->b_blocknr, i);
fsck_log("or length found %k, len % lu - deleted\n", &ih->ih_key, get_ih_item_len (ih));
delete_item (fs, bh, i);
goto start_again;
}
}
offset += get_bytes_number (ih, fs->fs_blocksize);
if (!does_it_fit_into_dev (offset, fs_size)) {
fsck_log("pass0: vpf-10230: block %lu, item %d: The item offset is is too big %k - deleted\n",
bh->b_blocknr, i, &ih->ih_key);
delete_item (fs, bh, i);
goto start_again;
}
}
}
if (i && comp_keys (&(ih - 1)->ih_key, &ih->ih_key) != -1) {
/* previous item has key not smaller than the key of currect item */
if (is_stat_data_ih (ih - 1) && !is_stat_data_ih (ih)) {
/* fix key of stat data such as if it was stat data of that item */
fsck_log ("pass0: block %lu, items %d, %d: Wrong order of items - make the StatData item %k of the file %k\n",
bh->b_blocknr, i - 1, i, &(ih - 1)->ih_key, &ih->ih_key);
set_key_dirid (&(ih - 1)->ih_key, get_key_dirid (&ih->ih_key));
set_key_objectid (&(ih - 1)->ih_key, get_key_objectid (&ih->ih_key));
set_offset (KEY_FORMAT_1, &(ih - 1)->ih_key, 0);
set_type (KEY_FORMAT_1, &(ih - 1)->ih_key, TYPE_STAT_DATA);
dirty = 1;
} else {
/* ok, we have to delete one of these two - decide which one */
int retval;
/* something will be deleted */
dirty = 1;
retval = upper_correct (bh, ih - 1, i - 1);
switch (retval) {
case 0:
/* delete upper item */
fsck_log ("pass0: block %lu, item %d (upper): Item %k is out of order - deleted\n",
bh->b_blocknr, i - 1, &(ih - 1)->ih_key);
delete_item (fs, bh, i - 1);
goto start_again;
case 1:
/* delete lower item */
fsck_log ("pass0: block %lu, item %d (lower): Item %k is out of order - deleted\n",
bh->b_blocknr, i, &ih->ih_key);
delete_item (fs, bh, i);
goto start_again;
default:
/* upper item was the first item of a node */
/* to make gcc 3.2 do not sware here */;
}
retval = lower_correct (bh, ih, i);
switch (retval) {
case 0:
/* delete lower item */
fsck_log ("pass0: block %lu, item %d (lower): Item %k is out of order - deleted\n",
bh->b_blocknr, i, &ih->ih_key);
delete_item (fs, bh, i);
goto start_again;
case 1:
/* delete upper item */
fsck_log ("pass0: block %lu, %d (upper): Item %k is out of order - deleted\n",
bh->b_blocknr, i - 1, &(ih - 1)->ih_key);
delete_item (fs, bh, i - 1);
goto start_again;
default:
/* only 2 items in the node, how to decide what to delete, go and ask user */
/* to make gcc 3.2 do not sware here */;
}
fsck_log ("pass0: block %lu, items %d and %d: Which of these items looks better (the other will be deleted.)?\n"
"%k\n%k\n", bh->b_blocknr, i-1, i, &(ih - 1)->ih_key, &ih->ih_key);
if (fsck_user_confirmed (fs, "1 or 2?", "1\n", 1))
delete_item (fs, bh, i - 1);
else
delete_item (fs, bh, i);
goto start_again;
}
}
if (is_stat_data_ih (ih) && (get_ih_item_len (ih) != SD_SIZE &&
get_ih_item_len (ih) != SD_V1_SIZE)) {
fsck_log ("pass0: block %lu, item %d: StatData item of wrong length found %H - deleted\n",
bh->b_blocknr, i, ih);
delete_item (fs, bh, i);
goto start_again;
}
dirty += correct_key_format (ih, symlnk);
if (is_stat_data_ih (ih)) {
__u16 mode;
file_format = get_ih_key_format (ih);
get_sd_mode (ih, B_N_PITEM(bh,i), &mode);
symlnk = ( S_ISLNK(mode) ? 1 : 0);
;/*correct_stat_data (fs, bh, i);*/
} else if ( !is_direntry_ih(ih) &&
!(symlnk && is_direct_ih(ih)) &&
(file_format != KEY_FORMAT_UNDEFINED) &&
(file_format != get_ih_key_format (ih)))
{
fsck_log("pass0: vpf-10240: block %lu, item (%d): Item %k, which format (%d) is not equal to StatData "
"format (%d), is deleted\n", bh->b_blocknr, i, &ih->ih_key, get_ih_key_format(ih), file_format);
delete_item (fs, bh, i);
goto start_again;
} else {
file_format = KEY_FORMAT_UNDEFINED;
symlnk = 0;
}
if (i && is_stat_data_ih (ih - 1) && !not_of_one_file (&ih->ih_key, &(ih - 1)->ih_key)) {
__u16 mode;
get_sd_mode (ih - 1, B_I_PITEM (bh, ih - 1), &mode);
if (not_a_directory (B_I_PITEM (bh, ih - 1)) && is_direntry_ih (ih)) {
/* make SD mode SD of dir */
fsck_log ("pass0: block %lu, item %d: The directory %K has the wrong mode (%M), corrected to ",
bh->b_blocknr, i, &ih->ih_key, mode);
mode &= ~S_IFMT;
mode |= S_IFDIR;
fsck_log ("(%M)\n", mode);
set_sd_mode (ih - 1, B_I_PITEM (bh, ih - 1), &mode);
dirty = 1;
} else if (!not_a_directory (B_I_PITEM (bh, ih - 1)) && !is_direntry_ih (ih)) {
/* make SD mode SD of regular file */
fsck_log ("pass0: block %lu, item %d: Not the directory %K has the wrong mode (%M), corrected to ",
bh->b_blocknr, i, &ih->ih_key, mode);
mode &= ~S_IFMT;
mode |= S_IFREG;
fsck_log ("(%M)\n", mode);
set_sd_mode (ih - 1, B_I_PITEM (bh, ih - 1), &mode);
dirty = 1;
}
if (not_a_regfile (B_I_PITEM (bh, ih - 1)) && is_indirect_ih (ih)) {
fsck_log ("pass0: block %lu, item %d: The file %K has the wrong mode (%M), corrected to ",
bh->b_blocknr, i, &ih->ih_key, mode);
mode &= ~S_IFMT;
mode |= S_IFREG;
fsck_log ("(%M)\n", mode);
set_sd_mode (ih - 1, B_I_PITEM (bh, ih - 1), &mode);
dirty = 1;
}
}
if (is_direntry_ih (ih)) {
j = verify_directory_item (fs, bh, i);
if (j == 1) {
/* wrong hash, skip the leaf */
pass_0_stat (fs)->too_old_leaves ++;
mark_buffer_clean (bh);
return;
} else if (j == -1) {
/* item was deleted */
goto start_again;
}
continue;
}
/*DEBUG*/
if (!is_stat_data_ih (ih) && get_offset (&ih->ih_key) == 0)
reiserfs_panic ("block %lu, item %d: Zero offset can have StatData items only, but found %k\n",
bh->b_blocknr, i, &ih->ih_key);
if (!is_indirect_ih (ih))
continue;
/* Darko Palic's filesystem had item: [20079 17328 0xfffb1001 IND, len 4048], format old */
{
struct key tmp_key;
tmp_key = ih->ih_key;
set_offset (key_format (&tmp_key), &tmp_key,
get_offset (&tmp_key) + get_bytes_number (ih, bh->b_size) - 1);
if (get_offset (&tmp_key) < get_offset (&ih->ih_key)) {
fsck_log ("pass0: block %lu, item %d: The item, which has wrong offset %k, is deleted\n",
bh->b_blocknr, i, &ih->ih_key);
delete_item (fs, bh, i);
goto start_again;
}
}
/* temporary ugly fix */
/*
if (i && is_stat_data_ih (ih - 1) && !not_of_one_file (&ih->ih_key, &(ih - 1)->ih_key)) {
__u16 mode;
get_sd_mode (ih - 1, B_I_PITEM (bh, ih - 1), &mode);
if (!S_ISREG (mode)) {
fsck_log ("pass0: block %lu: mode (%M) of file %K having indirect item is fixed to ",
bh->b_blocknr, mode, &ih->ih_key);
mode &= ~S_IFMT;
mode |= S_IFREG;
set_sd_mode (ih - 1, B_I_PITEM (bh, ih - 1), &mode);
fsck_log ("(%M)\n", mode);
dirty = 1;
}
}
*/
ind_item = (__u32 *)B_I_PITEM (bh, ih);
for (j = 0; j < (int)I_UNFM_NUM (ih); j ++) {
unfm_ptr = d32_get (ind_item, j);
if (!unfm_ptr)
continue;
#if 0
if (fsck_mode (fs) == FSCK_ZERO_FILES) {
/* FIXME: this is temporary mode of fsck */
ind_item [j] = 0;
reiserfs_bitmap_clear_bit (fsck_new_bitmap(fs), unfm_ptr);
tmp_zeroed ++;
dirty = 1;
continue;
}
#endif
if (not_data_block (fs, unfm_ptr) || /* journal area or bitmap or super block */
unfm_ptr >= get_sb_block_count (fs->fs_ondisk_sb) || /* garbage in pointer */
(fs->fs_badblocks_bm && /* bad block */
reiserfs_bitmap_test_bit(fs->fs_badblocks_bm, unfm_ptr))) {
pass_0_stat (fs)->wrong_pointers ++;
/*
fsck_log ("pass0: %d-th pointer (%lu) in item %k (leaf block %lu) is wrong\n",
j, unfm_ptr, &ih->ih_key, bh->b_blocknr);
*/
d32_put(ind_item, j, 0);
dirty = 1;
continue;
}
/* mark block in bitmaps of unformatted nodes */
register_unfm (unfm_ptr);
}
}
/* mark all objectids in use */
ih = B_N_PITEM_HEAD (bh, 0);
for (i = 0; i < get_blkh_nr_items (B_BLK_HEAD (bh)); i ++, ih ++) {
struct reiserfs_de_head * deh;
id_map_mark(proper_id_map (fs), get_key_dirid (&ih->ih_key));
id_map_mark(proper_id_map (fs), get_key_objectid (&ih->ih_key));
if (is_direntry_ih(ih)) {
for (j = 0, deh = B_I_DEH (bh, ih); j < get_ih_entry_count (ih); j ++, deh++)
id_map_mark(proper_id_map(fs), get_deh_objectid(deh));
}
}
if (get_blkh_nr_items (B_BLK_HEAD (bh)) < 1) {
/* pass 1 will skip this */
pass_0_stat (fs)->all_contents_removed ++;
// fsck_log ("pass0: block %lu: All items were deleted.\n", bh->b_blocknr);
dirty = 0;
mark_buffer_clean (bh);
} else {
/* pass1 will use this bitmap */
pass0_mark_leaf (bh->b_blocknr);
/*fsck_data (fs)->rebuild.leaves ++;*/
}
if (dirty) {
pass_0_stat (fs)->leaves_corrected ++;
mark_buffer_dirty (bh);
}
}
static int is_bad_sd (struct item_head * ih, char * item)
{
struct stat_data * sd = (struct stat_data *)item;
if (get_key_offset_v1 (&ih->ih_key) || get_key_uniqueness (&ih->ih_key)) {
fsck_log ("vpf-10610: StatData item %k has non zero offset found.\n",
&ih->ih_key);
return 1;
}
if (get_ih_item_len (ih) == SD_V1_SIZE) {
/* looks like old stat data */
if (get_ih_key_format (ih) != KEY_FORMAT_1)
fsck_log ("vpf-10620: StatData item %k has wrong format.\n",
&ih->ih_key);
return 0;
}
if (!S_ISDIR (sd_v2_mode(sd)) && !S_ISREG(sd_v2_mode(sd)) &&
!S_ISCHR (sd_v2_mode(sd)) && !S_ISBLK(sd_v2_mode(sd)) &&
!S_ISLNK (sd_v2_mode(sd)) && !S_ISFIFO(sd_v2_mode(sd)) &&
!S_ISSOCK(sd_v2_mode(sd))) {
/*fsck_log ("file %k unexpected mode encountered 0%o\n", &ih->ih_key, sd_v2_mode(sd))*/;
}
return 0;
}
int is_bad_directory (struct item_head * ih, char * item, int dev, int blocksize)
{
int i;
char * name;
int namelen, entrylen;
struct reiserfs_de_head * deh = (struct reiserfs_de_head *)item;
__u32 prev_offset = 0;
__u16 prev_location = get_ih_item_len (ih);
int min_entry_size = 1;/* we have no way to understand whether the
filesystem wes created in 3.6 format or
converted to it. So, we assume that minimal name
length is 1 */
if (get_ih_item_len (ih) / (DEH_SIZE + min_entry_size) < get_ih_entry_count (ih))
/* entry count is too big */
return 1;
for (i = 0; i < get_ih_entry_count (ih); i ++, deh ++) {
entrylen = entry_length(ih, deh, i);
if (entrylen > (int)REISERFS_MAX_NAME_LEN (blocksize))
return 1;
if (get_deh_offset (deh) <= prev_offset)
return 1;
prev_offset = get_deh_offset (deh);
if (get_deh_location(deh) + entrylen != prev_location)
return 1;
prev_location = get_deh_location (deh);
namelen = name_in_entry_length (ih, deh, i);
name = name_in_entry (deh, i);
if (!is_properly_hashed (fs, name, namelen, get_deh_offset (deh)))
return 1;
}
return 0;
}
/* change incorrect block adresses by 0. Do not consider such item as incorrect */
static int is_bad_indirect (struct item_head * ih, char * item, int dev, int blocksize)
{
unsigned long blocks;
unsigned int i;
int bad = 0;
if (get_ih_item_len(ih) % UNFM_P_SIZE) {
fsck_log ("is_bad_indirect: indirect item of %H of invalid length\n", ih);
return 1;
}
blocks = get_sb_block_count (fs->fs_ondisk_sb);
for (i = 0; i < I_UNFM_NUM (ih); i ++) {
__u32 * ind = (__u32 *)item;
if (d32_get (ind, i) >= blocks) {
bad ++;
fsck_log ("is_bad_indirect: %d-th pointer of item %H looks bad (%lu)\n",
i, ih, d32_get (ind, i));
continue;
}
}
return bad;
}
/* this is used by pass1.c:save_item and check.c:is_leaf_bad */
int is_bad_item (struct buffer_head * bh, struct item_head * ih, char * item)
{
int blocksize, dev;
blocksize = bh->b_size;
dev = bh->b_dev;
// FIXME: refuse transparently bad items
if (get_key_dirid (&ih->ih_key) == get_key_objectid (&ih->ih_key))
return 1;
if (!get_key_dirid (&ih->ih_key) || !get_key_objectid (&ih->ih_key))
return 1;
if (is_stat_data_ih(ih))
return is_bad_sd (ih, item);
if (is_direntry_ih (ih))
return is_bad_directory (ih, item, dev, blocksize);
if (is_indirect_ih (ih))
return is_bad_indirect (ih, item, dev, blocksize);
if (is_direct_ih (ih))
return 0;
return 1;
}
int is_leaf_bad (struct buffer_head * bh)
{
int i;
struct item_head * ih;
int bad = 0;
assert (is_leaf_node (bh));
for (i = 0, ih = B_N_PITEM_HEAD (bh, 0); i < B_NR_ITEMS (bh); i ++, ih ++) {
if (is_bad_item (bh, ih, B_I_PITEM (bh, ih))) {
fsck_log ("is_leaf_bad: block %lu, item %d: The corrupted item found (%H)\n",
bh->b_blocknr, i, ih);
bad = 1;
continue;
}
if (i && bad_pair (fs, bh, i)) {
fsck_log ("is_leaf_bad: block %lu items %d and %d: Wrong order of items:"
"\n\t%H\n\t%H\n", bh->b_blocknr, i - 1, i, ih - 1, ih);
bad = 1;
}
}
return bad;
}
static int is_to_be_read (reiserfs_filsys_t * fs, unsigned long block)
{
return reiserfs_bitmap_test_bit (fsck_source_bitmap (fs), block);
}
static void do_pass_0 (reiserfs_filsys_t * fs)
{
struct buffer_head * bh;
unsigned long i;
int what_node;
unsigned long done = 0, total;
if (fsck_mode (fs) == DO_TEST) {
/* just to test pass0_correct_leaf */
bh = bread (fs->fs_dev, fsck_data (fs)->rebuild.test, fs->fs_blocksize);
if (!bh) {
/* we were reading one block at time, and failed, so mark block bad */
fsck_progress ("%s: Reading of the block %lu failed\n", __FUNCTION__,
fsck_data (fs)->rebuild.test);
reiserfs_free (fs);
exit(0);
}
if (is_leaf_bad (bh)) {
fsck_progress ("############### bad #################\n");
}
pass0_correct_leaf (fs, bh);
print_block (stdout, fs, bh, 3, -1, -1);
if (is_leaf_bad (bh)) {
fsck_progress ("############### still bad #################\n");
}
brelse (bh);
reiserfs_free (fs);
exit(0);
}
total = reiserfs_bitmap_ones (fsck_source_bitmap (fs));
for (i = 0; i < get_sb_block_count (fs->fs_ondisk_sb); i ++) {
if (!is_to_be_read (fs, i))
continue;
print_how_far (fsck_progress_file (fs), &done, total, 1, fsck_quiet (fs));
bh = bread (fs->fs_dev, i, fs->fs_blocksize);
if (!bh) {
/* we were reading one block at time, and failed, so mark block bad */
fsck_progress ("%s: Reading of the block %lu failed\n", __FUNCTION__, i);
continue;
}
if (fs->fs_badblocks_bm && reiserfs_bitmap_test_bit (fs->fs_badblocks_bm, i))
reiserfs_panic ("The block (%lu), specified in badblock list, was read.", i);
if (not_data_block (fs, i)) {
/* block which could not be pointed by indirect item */
if (!(block_of_journal (fs, i) && fsck_data(fs)->rebuild.use_journal_area))
reiserfs_panic ("The block (%lu) from non data area was read.", i);
}
pass_0_stat (fs)->dealt_with ++;
what_node = who_is_this (bh->b_data, bh->b_size);
if ( what_node != THE_LEAF && what_node != HAS_IH_ARRAY ) {
brelse (bh);
continue;
}
pass_0_stat (fs)->leaves ++;
pass0_correct_leaf (fs, bh);
brelse (bh);
}
fsck_progress ("\n");
/* just in case */
id_map_mark(proper_id_map (fs), REISERFS_ROOT_OBJECTID);
}
int is_used_leaf (unsigned long block)
{
return pass0_is_leaf (block);
}
/*
int how_many_leaves_were_there (void)
{
return fsck_data (fs)->rebuild.leaves;
}
*/
/* these are used to correct uformatted node pointers */
int is_bad_unformatted (unsigned long block)
{
return pass0_is_bad_unfm (block);
}
/* these are used to correct uformatted node pointers */
int is_good_unformatted (unsigned long block)
{
return pass0_is_good_unfm (block);
}
/* this is for check only. With this we make sure that all pointers we
put into tree on pass 1 do not point to leaves (FIXME), do not
point to journal, bitmap, etc, do not point out of fs boundary (and
are marked used in on-disk bitmap - this condition skipped for now). */
int still_bad_unfm_ptr_1 (unsigned long block)
{
if (!block)
return 0;
if (pass0_is_leaf (block))
return 1;
if (pass0_is_bad_unfm (block) && !is_bad_unfm_in_tree_once (block))
return 2;
if (not_data_block (fs, block))
return 3;
/*
if (!was_block_used (block))
return 4;
*/
if (block >= get_sb_block_count (fs->fs_ondisk_sb))
return 5;
return 0;
}
/* pointers to data block which get into tree are checked with this */
int still_bad_unfm_ptr_2 (unsigned long block)
{
if (!block)
return 0;
if (is_block_used (block))
return 1;
if (block >= get_sb_block_count (fs->fs_ondisk_sb))
return 1;
return 0;
}
/* these are used to allocate blocks for tree building */
int are_there_allocable_blocks (unsigned int amout_needed) {
if (reiserfs_bitmap_zeros (fsck_allocable_bitmap (fs)) < amout_needed) {
unsigned int zeros = 0, i;
fsck_progress ("Not enough allocable blocks, checking bitmap...");
for (i = 0; i < fsck_allocable_bitmap (fs)->bm_bit_size; i ++) {
if (!reiserfs_bitmap_test_bit (fsck_allocable_bitmap (fs), i))
zeros ++;
}
fsck_progress ("there are %u allocable blocks, btw\n", zeros);
return 0;
}
return 1;
}
unsigned long alloc_block (void)
{
unsigned long block = 0; /* FIXME: start point could be used */
if (reiserfs_bitmap_find_zero_bit (fsck_allocable_bitmap (fs), &block)) {
die ("alloc_block: Allocable blocks counter is wrong");
return 0;
}
reiserfs_bitmap_set_bit (fsck_allocable_bitmap (fs), block);
return block;
}
void make_allocable (unsigned long block)
{
reiserfs_bitmap_clear_bit (fsck_allocable_bitmap (fs), block);
}
static void choose_hash_function (reiserfs_filsys_t * fs)
{
unsigned long max;
unsigned int hash_code;
int i;
if (fsck_hash_defined (fs))
return;
max = 0;
hash_code = func2code (0);
for (i = 0; i < fsck_data (fs)->rebuild.hash_amount; i ++) {
/* remember hash whihc got more hits */
if (fsck_data (fs)->rebuild.hash_hits [i] > max) {
hash_code = i;
max = fsck_data (fs)->rebuild.hash_hits [i];
}
if (fsck_data (fs)->rebuild.hash_hits [i])
fsck_log ("%lu directory entries were hashed with %s hash.\n",
fsck_data (fs)->rebuild.hash_hits [i], code2name(i));
}
if (max == 0 || hash_code == 0) {
/* no names were found. take either super block value or
default */
hash_code = get_sb_hash_code (fs->fs_ondisk_sb);
if (!hash_code)
hash_code = DEFAULT_HASH;
fsck_log ("Could not find a hash in use. Using %s\n",
code2name (hash_code));
}
/* compare the most appropriate hash with the hash set in super block */
if (hash_code != get_sb_hash_code (fs->fs_ondisk_sb)) {
fsck_progress ("Selected hash (%s) does not match to the hash set in the super block (%s).\n",
code2name (hash_code), code2name (get_sb_hash_code (fs->fs_ondisk_sb)));
set_sb_hash_code (fs->fs_ondisk_sb, hash_code);
}
fsck_progress ("\t%s hash is selected\n", code2name (hash_code));
reiserfs_hash (fs) = code2func (hash_code);
}
/* create bitmap of blocks the tree is to be built off */
/* debugreiserfs and pass0 should share this code -s should show
the same as we could recover - test: zero first 32M */
static void init_source_bitmap (reiserfs_filsys_t * fs)
{
FILE * fp;
unsigned long block_count = get_sb_block_count (fs->fs_ondisk_sb);
unsigned long i, j;
unsigned long tmp;
unsigned long block, reserved, bits_amount;
switch (fsck_data (fs)->rebuild.scan_area) {
case ALL_BLOCKS:
fsck_source_bitmap (fs) = reiserfs_create_bitmap (block_count);
reiserfs_bitmap_fill (fsck_source_bitmap (fs));
fsck_progress ("The whole partition (%d blocks) is to be scanned\n",
reiserfs_bitmap_ones (fsck_source_bitmap (fs)));
break;
case USED_BLOCKS:
fsck_progress ("Loading on-disk bitmap .. ");
fsck_source_bitmap (fs) = reiserfs_create_bitmap (block_count);
reiserfs_bitmap_copy (fsck_source_bitmap (fs), fs->fs_bitmap2);
fsck_progress ("ok, %d blocks marked used\n",
reiserfs_bitmap_ones (fsck_source_bitmap (fs)));
break;
case EXTERN_BITMAP:
fp = fopen (fsck_data (fs)->rebuild.bitmap_file_name, "r");
if (!fp) {
reiserfs_exit (EXIT_OPER, "Could not load bitmap: %s\n",
strerror(errno));
}
fsck_source_bitmap (fs) = reiserfs_bitmap_load (fp);
if (!fsck_source_bitmap (fs)) {
reiserfs_exit (EXIT_OPER, "Could not load fitmap from \"%s\"",
fsck_data (fs)->rebuild.bitmap_file_name);
}
fsck_progress ("%d blocks marked used in extern bitmap\n",
reiserfs_bitmap_ones (fsck_source_bitmap (fs)));
fclose (fp);
break;
default:
reiserfs_panic ("No area to scan specified");
}
tmp = 0;
/* unmark bitmaps */
block = fs->fs_super_bh->b_blocknr + 1;
reserved = fsck_source_bitmap(fs)->bm_bit_size;
for (i = 0; i < get_sb_bmap_nr (fs->fs_ondisk_sb); i ++) {
if (!reiserfs_bitmap_test_bit (fsck_source_bitmap (fs), block)) {
/* bitmap is definitely broken, mark all blocks of this bitmap block as used */
bits_amount = (reserved < fs->fs_blocksize * 8) ? reserved : fs->fs_blocksize * 8;
fsck_log("%s: Bitmap %lu (of %lu bits) is wrong - mark all blocks [%lu - %lu] as used\n",
__FUNCTION__, i, bits_amount, i * fs->fs_blocksize * 8,
fs->fs_blocksize * 8 * i + bits_amount);
for (j = i * fs->fs_blocksize * 8; j < i * fs->fs_blocksize * 8 + bits_amount; j++) {
if (!reiserfs_bitmap_test_bit (fsck_source_bitmap(fs), j))
reiserfs_bitmap_set_bit (fsck_source_bitmap(fs), j);
}
}
reiserfs_bitmap_clear_bit (fsck_source_bitmap (fs), block);
reserved -= fs->fs_blocksize * 8;
tmp ++;
/* next block fo bitmap */
if (spread_bitmaps (fs))
block = (block / (fs->fs_blocksize * 8) + 1) * (fs->fs_blocksize * 8);
else
block ++;
}
/* pass 0 will skip super block and journal areas and bitmap blocks, find
how many blocks have to be read */
for (i = 0; i <= fs->fs_super_bh->b_blocknr; i ++) {
if (!reiserfs_bitmap_test_bit (fsck_source_bitmap (fs), i))
continue;
reiserfs_bitmap_clear_bit (fsck_source_bitmap (fs), i);
tmp ++;
}
/* unmark journal area as used if journal is standard or it is non standard
and initialy has been created on a main device */
reserved = get_size_of_journal_or_reserved_area (fs->fs_ondisk_sb);
/* where does journal area (or reserved journal area) start from */
if (!is_new_sb_location (fs->fs_super_bh->b_blocknr, fs->fs_blocksize) &&
!is_old_sb_location (fs->fs_super_bh->b_blocknr, fs->fs_blocksize))
die ("init_source_bitmap: Wrong super block location, you must run --rebuild-sb.");
block = get_journal_start_must (fs);
for (i = block; i < reserved + block; i ++) {
if (!reiserfs_bitmap_test_bit (fsck_source_bitmap (fs), i))
continue;
reiserfs_bitmap_clear_bit (fsck_source_bitmap (fs), i);
tmp ++;
}
if (fs->fs_badblocks_bm)
for (i = 0; i < get_sb_block_count (fs->fs_ondisk_sb); i ++) {
if (reiserfs_bitmap_test_bit (fs->fs_badblocks_bm, i))
reiserfs_bitmap_clear_bit (fsck_source_bitmap (fs), i);
}
fsck_source_bitmap (fs)->bm_set_bits = reiserfs_bitmap_ones (fsck_source_bitmap (fs));
fsck_progress ("Skipping %d blocks (super block, journal, "
"bitmaps) %d blocks will be read\n", tmp, fsck_source_bitmap (fs)->bm_set_bits);
}
static void before_pass_0 (reiserfs_filsys_t * fs)
{
/* bitmap of blocks to be read */
init_source_bitmap (fs);
/* bitmap of leaves, good and bad unformatted */
make_aux_bitmaps (fs);
/* on pass0 all objectids will be marked here as used */
proper_id_map (fs) = id_map_init();
/* pass0 gathers statistics about hash hits */
hash_hits_init (fs);
}
static void save_pass_0_result (reiserfs_filsys_t * fs)
{
FILE * file;
int retval;
/* save bitmaps with which we will be able start reiserfs from
pass 1 */
file = open_file ("temp_fsck_file.deleteme", "w+");
if (!file)
return;
reiserfs_begin_stage_info_save (file, PASS_0_DONE);
reiserfs_bitmap_save (file, leaves_bitmap);
reiserfs_bitmap_save (file, good_unfm_bitmap);
reiserfs_bitmap_save (file, bad_unfm_bitmap);
reiserfs_end_stage_info_save (file);
close_file (file);
retval = rename ("temp_fsck_file.deleteme", state_dump_file (fs));
if (retval != 0)
fsck_progress ("%s: Could not rename the temporary file temp_fsck_file.deleteme to %s",
__FUNCTION__, state_dump_file (fs));
}
/* file 'fp' must contain 3 bitmaps saved during last pass 0: bitmap
of leaves, bitmaps of good and bad unfms*/
void load_pass_0_result (FILE * fp, reiserfs_filsys_t * fs)
{
leaves_bitmap = reiserfs_bitmap_load (fp);
good_unfm_bitmap = reiserfs_bitmap_load (fp);
bad_unfm_bitmap = reiserfs_bitmap_load (fp);
if (!leaves_bitmap || !good_unfm_bitmap || !bad_unfm_bitmap)
fsck_exit ("State dump file seems corrupted. Run without -d");
fsck_source_bitmap (fs) = leaves_bitmap;
/* on pass 1 we do not need proper objectid map */
fsck_progress ("Pass 0 result loaded. %d leaves, %d/%d good/bad data blocks\n",
reiserfs_bitmap_ones (leaves_bitmap),
reiserfs_bitmap_ones (good_unfm_bitmap),
reiserfs_bitmap_ones (bad_unfm_bitmap));
}
static void after_pass_0 (reiserfs_filsys_t * fs)
{
time_t t;
/* update super block: hash, objectid map, fsck state */
choose_hash_function (fs);
id_map_flush(proper_id_map (fs), fs);
set_sb_fs_state (fs->fs_ondisk_sb, PASS_0_DONE);
mark_buffer_dirty (fs->fs_super_bh);
/* write all dirty blocks */
fsck_progress ("Flushing..");
fs->fs_dirt = 1;
reiserfs_flush (fs);
fsck_progress ("finished\n");
stage_report (0, fs);
/* free what we do not need anymore */
reiserfs_delete_bitmap (fsck_source_bitmap (fs));
fsck_source_bitmap (fs) = 0;
if (!fsck_run_one_step (fs)) {
if (fsck_user_confirmed (fs, "Continue? (Yes):", "Yes\n", 1)) {
/* reiserfsck continues */
fsck_source_bitmap (fs) = leaves_bitmap;
return;
}
} else
save_pass_0_result (fs);
id_map_free(proper_id_map (fs));
proper_id_map (fs) = 0;
time (&t);
fsck_progress ("###########\n"
"reiserfsck finished pass 0 at %s"
"###########\n", ctime (&t));
fs->fs_dirt = 1;
reiserfs_close (fs);
exit(0);
}
void pass_0 (reiserfs_filsys_t * fs)
{
if (get_reiserfs_format (fs->fs_ondisk_sb) != fs->fs_format ||
get_reiserfs_format (fs->fs_ondisk_sb) == REISERFS_FORMAT_UNKNOWN)
{
reiserfs_exit (EXIT_OPER, "pass 0: ReiserFS format version mismatch "
"found, you should run --rebuild-sb");
}
fsck_progress ("\nPass 0:\n");
if (fsck_log_file (fs) != stderr)
/* this is just to separate warnings in the log file */
fsck_log ("####### Pass 0 #######\n");
before_pass_0 (fs);
/* scan the partition, find leaves and correct them */
do_pass_0 (fs);
after_pass_0 (fs);
}