Files
reiserfsprogs/utils/fsck/ufile.c
T

465 lines
14 KiB
C

/*
* Copyright 1996-2004 by Hans Reiser, licensing governed by
* reiserfsprogs/README
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "fsck.h"
#include "misc/unaligned.h"
#include "misc/malloc.h"
#include <sys/stat.h>
static void cut_last_unfm_pointer (reiserfs_path_t * path,
reiserfs_ih_t * ih)
{
reiserfs_ih_set_free(ih, 0);
if (reiserfs_ext_count (ih) == 1)
reiserfs_tree_delete (fs, path, 0);
else
reiserfs_tree_delete_unit (fs, path, -((int)REISERFS_EXT_SIZE));
}
/*
if this is not a symlink - make it of_this_size;
otherwise find a size and return it in symlink_size;
*/
static unsigned long extent2direct (reiserfs_path_t * path,
__u64 len, int symlink)
{
reiserfs_bh_t * bh = REISERFS_PATH_LEAF (path);
reiserfs_ih_t * ih = REISERFS_PATH_IH (path);
__u32 unfm_ptr;
reiserfs_bh_t * unfm_bh = 0;
reiserfs_ih_t ins_ih;
char * buf;
char bad_drct[fs->fs_blocksize];
/* direct item to insert */
memset (&ins_ih, 0, sizeof (ins_ih));
if (symlink) {
reiserfs_ih_set_format (&ins_ih, KEY_FORMAT_1);
} else {
reiserfs_ih_set_format (&ins_ih, reiserfs_ih_get_format (ih));
}
reiserfs_key_set_did (&ins_ih.ih_key, reiserfs_key_get_did (&ih->ih_key));
reiserfs_key_set_oid (&ins_ih.ih_key, reiserfs_key_get_oid (&ih->ih_key));
reiserfs_key_set_sec (reiserfs_ih_get_format (&ins_ih), &ins_ih.ih_key,
reiserfs_key_get_off (&ih->ih_key) +
(reiserfs_ext_count (ih) - 1) * bh->b_size,
TYPE_DIRECT);
// we do not know what length this item should be
unfm_ptr = d32_get ((__u32 *)REISERFS_PATH_ITEM (path),
reiserfs_ext_count (ih) - 1);
if (unfm_ptr && (unfm_bh = reiserfs_buffer_read(bh->b_dev, unfm_ptr,
bh->b_size)))
{
/* we can read the block */
buf = unfm_bh->b_data;
} else {
/* we cannot read the block */
if (unfm_ptr) {
fsck_log ("%s: Reading of the block (%lu), pointed to by the "
"file %K, failed\n", __FUNCTION__, unfm_ptr, &ih->ih_key);
}
memset (bad_drct, 0, fs->fs_blocksize);
buf = bad_drct;
}
reiserfs_ih_set_len (&ins_ih, (reiserfs_ih_get_format (ih) == KEY_FORMAT_2)
? MISC_ROUND_UP(len) : len);
reiserfs_ih_set_free (&ins_ih, MAX_US_INT);
reiserfs_ih_cltail(ih);
reiserfs_buffer_mkdirty(bh);
// last last unformatted node pointer
path->pos_in_item = reiserfs_ext_count (ih) - 1;
cut_last_unfm_pointer (path, ih);
/* insert direct item */
if (reiserfs_tree_search_item (fs, &(ins_ih.ih_key), path) == ITEM_FOUND) {
reiserfs_panic ("%s: The direct item %k should not exist yet.",
__FUNCTION__, &(ins_ih.ih_key));
}
reiserfs_tree_insert (fs, path, &ins_ih, (const char *)(buf));
reiserfs_buffer_close (unfm_bh);
/* put to stat data offset of first byte in direct item */
return reiserfs_key_get_off (&ins_ih.ih_key); //offset;
}
/* returns 1 when file looks correct, -1 if directory items appeared
there, 0 - only holes in the file found */
/* when it returns, key->k_offset is offset of the last item of file */
/* sd_size is zero if we do not need to convert any extent to direct */
int are_file_items_correct (reiserfs_ih_t * sd_ih,
void * sd,
__u64 * size,
__u32 * blocks,
int mark_passed_items,
int * symlink)
{
const reiserfs_key_t *next_key;
reiserfs_key_t *key;
reiserfs_path_t path;
reiserfs_bh_t * bh;
reiserfs_ih_t * ih;
int next_is_another_object = 0;
__u64 last_unfm_offset = 0;
int retval, was_tail = 0;
int will_convert = 0;
int should_convert;
int had_direct = 0;
long long int gap;
__u32 sd_fdb = 0;
int key_version;
unsigned int i;
__u64 sd_size;
key_version = reiserfs_ih_get_format (sd_ih);
should_convert = (fsck_mode (fs) != FSCK_REBUILD) || mark_passed_items;
key = &sd_ih->ih_key;
reiserfs_stat_get_size (sd_ih, sd, &sd_size);
if (key_version == KEY_FORMAT_1)
reiserfs_stat_get_fdb (sd_ih, sd, &sd_fdb);
reiserfs_key_set_off (key_version, key, 1);
reiserfs_key_set_type (key_version, key, TYPE_DIRECT);
/* correct size and st_blocks */
*size = 0;
*blocks = 0;
path.path_length = REISERFS_PATH_OFFILL;
do {
retval = reiserfs_tree_search_position (fs, key, &path);
if (retval == POSITION_FOUND && path.pos_in_item != 0)
reiserfs_panic ("%s: We look for %k, found %k. Must be found "
"first item byte (position 0).", __FUNCTION__,
key, &(REISERFS_PATH_IH (&path)->ih_key));
switch (retval) {
case POSITION_FOUND:/**/
ih = REISERFS_PATH_IH (&path);
bh = REISERFS_PATH_LEAF (&path);
if (reiserfs_ih_wastail (ih)) {
was_tail = 1;
}
reiserfs_key_set_type (key_version, key,
reiserfs_key_get_type (&ih->ih_key));
if (mark_passed_items == 1) {
fsck_item_mkreach (ih, bh);
}
// does not change path
next_key = reiserfs_tree_next_key(&path, fs);
if (next_key == 0 || reiserfs_key_comp2 (key, next_key) ||
(!reiserfs_key_ext (next_key) &&
!reiserfs_key_direct(next_key)))
{
next_is_another_object = 1;
will_convert = (reiserfs_ih_ext (ih) && sd_size &&
(reiserfs_ext_count (ih) > 0));
if (will_convert) {
last_unfm_offset = reiserfs_key_get_off (key) +
fs->fs_blocksize * (reiserfs_ext_count (ih) - 1);
/* if symlink or
[ 1. sd_size points somewhere into last unfm block
2. one item of the file was direct before for 3_6 ||
FDB points to the tail correctly for 3_5
3. we can have a tail in the file of a such size ] */
will_convert = will_convert &&
(sd_size >= last_unfm_offset) &&
(sd_size < last_unfm_offset + fs->fs_blocksize) &&
!reiserfs_policy_ext (sd_size, sd_size -
last_unfm_offset + 1,
fs->fs_blocksize);
will_convert = will_convert &&
(*symlink ||
((key_version == KEY_FORMAT_1) &&
(sd_fdb == last_unfm_offset)) ||
((key_version == KEY_FORMAT_2) && was_tail));
}
}
if (should_convert) {
*symlink = *symlink &&
(will_convert || reiserfs_key_direct(&ih->ih_key));
if (!(*symlink) && key_version != reiserfs_ih_get_format (ih)) {
if (fsck_mode(fs) == FSCK_CHECK) {
fsck_log("%s: vpf-10250: block %lu, item (%d): The "
"item format (%H) is not equal to SD format "
"(%d)\n", __FUNCTION__, bh->b_blocknr,
REISERFS_PATH_LEAF_POS(&path),ih, key_version);
one_more_corruption (fs, FIXABLE);
} else {
fsck_log("%s: vpf-10280: block %lu, item (%d): The "
"item format (%H) is not equal to SD format "
"(%d) - fixed.\n", __FUNCTION__, bh->b_blocknr,
REISERFS_PATH_LEAF_POS(&path),ih, key_version);
reiserfs_key_set_sec (key_version, &ih->ih_key,
reiserfs_key_get_off (&ih->ih_key),
reiserfs_key_get_type (&ih->ih_key));
reiserfs_ih_set_format(ih, key_version);
reiserfs_buffer_mkdirty(bh);
}
}
if (*symlink && reiserfs_key_direct(&ih->ih_key)) {
/* symlink. Check that it is of KEY_FORMAT_1 */
if (fsck_mode(fs) == FSCK_CHECK) {
if ((reiserfs_ih_get_format(ih) != KEY_FORMAT_1) ||
(reiserfs_key_format(&ih->ih_key) != KEY_FORMAT_1))
{
fsck_log("%s: vpf-10732: block %lu, item (%d): "
"The symlink format (%H) is not equal "
"to 3.5 format (%d)\n",
__FUNCTION__, bh->b_blocknr,
REISERFS_PATH_LEAF_POS(&path),
ih, KEY_FORMAT_1);
one_more_corruption (fs, FIXABLE);
}
} else {
if ((reiserfs_ih_get_format(ih) != KEY_FORMAT_1) ||
(reiserfs_key_format(&ih->ih_key) != KEY_FORMAT_1))
{
fsck_log("%s: vpf-10732: block %lu, item (%d): "
"The symlink format (%H) is not equal "
"to 3.5 format (%d)\n",
__FUNCTION__, bh->b_blocknr,
REISERFS_PATH_LEAF_POS(&path),
ih, KEY_FORMAT_1);
reiserfs_key_set_sec(KEY_FORMAT_1, &ih->ih_key,
reiserfs_key_get_off(&ih->ih_key),
reiserfs_key_get_type(&ih->ih_key));
reiserfs_ih_set_format(ih, KEY_FORMAT_1);
reiserfs_buffer_mkdirty(bh);
}
}
}
if (will_convert)
*size = sd_size;
else
*size = reiserfs_key_get_off (&ih->ih_key) +
reiserfs_leaf_ibytes (ih, fs->fs_blocksize) - 1;
if (reiserfs_key_get_type (&ih->ih_key) == TYPE_EXTENT) {
if (*symlink) /* symlinks must be calculated as dirs */
*blocks = REISERFS_DIR_BLOCKS (*size);
else
for (i = 0; i < reiserfs_ext_count (ih); i ++) {
__u32 * ind = (__u32 *)REISERFS_PATH_ITEM(&path);
if (d32_get(ind, i) != 0)
*blocks += (fs->fs_blocksize >> 9);
}
} else if (reiserfs_key_get_type (&ih->ih_key) == TYPE_DIRECT) {
if (*symlink) /* symlinks must be calculated as dirs */
*blocks = REISERFS_DIR_BLOCKS (*size);
else if (!had_direct)
*blocks += (fs->fs_blocksize >> 9);
/* calculate only the first direct byte */
had_direct++;
}
}
if (next_is_another_object) {
/* next item does not exists or is of another object,
therefore all items of file are correct */
if (will_convert) {
if (fsck_mode (fs) == FSCK_CHECK) {
/* here it can be symlink only */
fsck_log ("%s: The extent item should be converted "
"back to direct %K\n", __FUNCTION__,
&ih->ih_key);
one_more_corruption (fs, FIXABLE);
reiserfs_tree_pathrelse (&path);
} else {
__u32 * ind = (__u32 *)REISERFS_PATH_ITEM(&path);
if (d32_get(ind, reiserfs_ext_count (ih) - 1) == 0)
*blocks += (fs->fs_blocksize >> 9);
/* path is released here. */
sd_fdb = extent2direct (&path, sd_size -
last_unfm_offset + 1,
*symlink);
/* last item of the file is direct item */
reiserfs_key_set_off (key_version, key,
sd_fdb);
reiserfs_key_set_type (key_version, key, TYPE_DIRECT);
}
} else {
reiserfs_tree_pathrelse (&path);
}
return 1;
}
/* next item is item of this file */
if ((gap = must_there_be_a_hole(ih, next_key))) {
/* next item has incorrect offset (hole or overlapping) */
reiserfs_tree_pathrelse (&path);
if (reiserfs_ih_ext(ih) &&
fsck_mode (fs) == FSCK_REBUILD &&
gap < FSCK_MAX_GAP(fs->fs_blocksize))
{
if (gap < 0) {
reiserfs_panic("%s: found items %k, %k are "
"overlapped.\n", __FUNCTION__,
&ih->ih_key, next_key);
}
reiserfs_key_set_off(key_version, key,
reiserfs_key_get_off(&ih->ih_key) +
reiserfs_leaf_ibytes(ih, fs->fs_blocksize));
fsck_tree_rewrite(fs, key,
reiserfs_key_get_off(next_key),
1 << IH_Unreachable);
break;
}
return 0;
}
/* next item exists */
reiserfs_key_set_sec(key_version, key,
reiserfs_key_get_off (next_key),
reiserfs_key_get_type(next_key));
if (reiserfs_key_comp (key, next_key))
reiserfs_panic ("%s: Internal tree is in inconsistent state, "
"the current item key %K and the next key %K "
"must match\n", __FUNCTION__, key, next_key);
reiserfs_tree_pathrelse (&path);
break;
case POSITION_NOT_FOUND:
/* We always must have next key found. Exception is first byte.
It does not have to exist */
if (reiserfs_key_get_off (key) != 1)
reiserfs_panic ("%s: Position (offset == %llu) in the middle "
"of the file %K was not found.", __FUNCTION__,
reiserfs_key_get_off(key), key);
bh = REISERFS_PATH_LEAF (&path);
if (reiserfs_node_items(bh) <= REISERFS_PATH_LEAF_POS(&path))
next_key = reiserfs_tree_next_key(&path, fs);
else
next_key = &REISERFS_PATH_IH(&path)->ih_key;
reiserfs_tree_pathrelse (&path);
gap = reiserfs_key_get_off(next_key);
if (fsck_mode(fs) == FSCK_REBUILD &&
gap < FSCK_MAX_GAP(fs->fs_blocksize) + 1)
{
fsck_tree_rewrite(fs, key, gap, 1 << IH_Unreachable);
break;
}
return 0;
case FILE_NOT_FOUND:
if (reiserfs_key_get_off (key) != 1)
reiserfs_panic ("%s: File %K must be found as we found its "
"StatData.", __FUNCTION__, key);
reiserfs_tree_pathrelse (&path);
return 1;
case DIRECTORY_FOUND:
reiserfs_tree_pathrelse (&path);
return -1;
}
} while (1);
misc_die ("%s: Cannot reach here", __FUNCTION__);
return 0;
}
static int cb_relocate(reiserfs_path_t *path, void *data) {
return 1;
}
/* delete all items and put them back (after that file should have
correct sequence of items.
if @relocate is specified then it relocates items to a new id.
if @adjust_ih is specified then the key in ih is changed also. */
void fsck_file_relocate(reiserfs_key_t *key, int update_key) {
reiserfs_key_t start;
saveitem_t *si;
__u32 oid;
int count;
int moved;
/* Find all items of the file, remove, relocate, insert them. */
oid = 0;
moved = 0;
si = NULL;
start = *key;
reiserfs_key_set_sec(KEY_FORMAT_1, &start, OFFSET_SD, TYPE_STAT_DATA);
while ((count = fsck_tree_delete(&start, &si, 1, cb_relocate, NULL))) {
if (oid == 0)
oid = fsck_relocate_oid(key);
reiserfs_key_set_oid(&(si->si_ih.ih_key), oid);
fsck_tree_insert_item(&(si->si_ih), si->si_dnm_data, 0);
si = fsck_item_free(si);
moved += count;
}
if (moved) {
fsck_log ("%s: %d items of file %K moved to %u oid\n",
__FUNCTION__, moved, key, oid);
}
if (update_key) {
/* If nothing has been relocated but ih needs to be adjusted,
allocate a new oid for relocation. */
if (oid == 0)
oid = fsck_relocate_oid(key);
reiserfs_key_set_oid (key, oid);
}
}