Files
reiserfsprogs/fsck/pass0.c
T
Jeff Mahoney 47cff72748 cleanup: run indent with the Linux Kernel style across all code
Over the years, the reiserfs kernel code has been gradually cleaned up
to be more readable. This patch does the same to the progs code.

Signed-off-by: Jeff Mahoney <jeffm@suse.com>
2013-08-26 17:14:42 -04:00

2341 lines
65 KiB
C

/*
* 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 hash_code;
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;
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;
#ifdef DEBUG_VERIFY_DENTRY
int loc_fixed;
#endif
prev_loc = get_ih_item_len(ih);
for (i = 0; i < get_ih_entry_count(ih); i++) {
#ifdef DEBUG_VERIFY_DENTRY
loc_fixed = 0;
#endif
if (de_bad_location(deh + i)) {
set_deh_location(deh + i, prev_loc /* - 1 */ );
mark_buffer_dirty(bh);
#ifdef DEBUG_VERIFY_DENTRY
loc_fixed = 1;
#endif
} else {
if (get_deh_location(deh + i) >= prev_loc) {
set_deh_location(deh + i,
prev_loc /* - 1 */ );
mark_buffer_dirty(bh);
#ifdef DEBUG_VERIFY_DENTRY
loc_fixed = 1;
#endif
}
}
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)));
#ifdef DEBUG_VERIFY_DENTRY
loc_fixed = 1;
#endif
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 reiserfs_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;
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);
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 reiserfs_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 (%u 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, %u 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("%u 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 < reiserfs_fs_bmap_nr(fs); 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 %u blocks (super block, journal, "
"bitmaps) %u 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);
}