Imported reiserfsprogs-3.6.20
This commit is contained in:
1 parent
0ed773997f
commit
dac518d099
189 files changed
+43353
-29787
No files matched your search
@@ -0,0 +1,464 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user