Files
reiserfsprogs/fsck/semantic_check.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

925 lines
24 KiB
C

/*
* Copyright 1996-2004 by Hans Reiser, licensing governed by reiserfsprogs/README
*/
#include "fsck.h"
static struct reiserfs_key *trunc_links = NULL;
static __u32 links_num = 0;
int wrong_mode(struct reiserfs_key *key, __u16 * mode, __u64 real_size,
int symlink);
int wrong_st_blocks(struct reiserfs_key *key, __u32 * blocks, __u32 sd_blocks,
__u16 mode, int new_format);
int wrong_st_size(struct reiserfs_key *key, unsigned long long max_file_size,
int blocksize, __u64 * size, __u64 sd_size, int type);
int wrong_first_direct_byte(struct reiserfs_key *key, int blocksize,
__u32 * first_direct_byte,
__u32 sd_first_direct_byte, __u32 size);
void get_object_key(struct reiserfs_de_head *deh, struct reiserfs_key *key,
struct reiserfs_key *entry_key, struct item_head *ih);
void print_name(char *name, int len);
void erase_name(int len);
struct reiserfs_path_key {
struct short_key {
__u32 k_dir_id;
__u32 k_objectid;
} key;
struct reiserfs_path_key *next, *prev;
};
struct reiserfs_path_key *head_key = NULL;
struct reiserfs_path_key *tail_key = NULL;
static int check_path_key(struct reiserfs_key *key)
{
struct reiserfs_path_key *cur = head_key;
while (cur != NULL) {
if (!comp_short_keys(&cur->key, key)) {
fsck_log
("\nsemantic check: The directory %k has 2 names.",
key);
return LOOP_FOUND;
}
cur = cur->next;
}
return 0;
}
static int add_path_key(struct reiserfs_key *key)
{
if (check_path_key(key))
return LOOP_FOUND;
if (tail_key == NULL) {
tail_key = getmem(sizeof(struct reiserfs_path_key));
head_key = tail_key;
tail_key->prev = NULL;
} else {
tail_key->next = getmem(sizeof(struct reiserfs_path_key));
tail_key->next->prev = tail_key;
tail_key = tail_key->next;
}
copy_short_key(&tail_key->key, key);
tail_key->next = NULL;
return 0;
}
void del_path_key()
{
if (tail_key == NULL)
die("Wrong path_key structure");
if (tail_key->prev == NULL) {
freemem(tail_key);
tail_key = head_key = NULL;
} else {
tail_key = tail_key->prev;
freemem(tail_key->next);
tail_key->next = NULL;
}
}
/* path is path to stat data. If file will be relocated - new_ih will contain
a key file was relocated with */
static int check_check_regular_file(struct reiserfs_path *path, void *sd,
struct item_head *new_ih)
{
int is_new_file;
// struct reiserfs_key key, sd_key;
__u16 mode;
__u32 nlink;
__u64 real_size, sd_size;
__u32 blocks, sd_blocks; /* proper values and value in stat data */
__u32 first_direct_byte, sd_first_direct_byte;
struct item_head *ih, sd_ih;
int fix_sd;
int symlnk = 0;
int retval = OK;
__u32 tmp_position;
ih = get_ih(path);
if (new_ih) {
/* this objectid is used already */
*new_ih = *ih;
pathrelse(path);
rewrite_file(new_ih, 1, 1);
linked_already(&new_ih->ih_key);
one_less_corruption(fs, FIXABLE);
sem_pass_stat(fs)->oid_sharing_files_relocated++;
retval = RELOCATED;
if (reiserfs_search_by_key_4(fs, &(new_ih->ih_key), path) ==
ITEM_NOT_FOUND)
reiserfs_panic
("check_check_regular_file: Could not find a StatData of "
"the relocated file %K", &new_ih->ih_key);
/* stat data is marked unreachable again due to relocation, fix that */
ih = get_ih(path);
sd = get_item(path);
}
if (get_ih_item_len(ih) == SD_SIZE)
is_new_file = 1;
else
is_new_file = 0;
get_sd_nlink(ih, sd, &nlink);
get_sd_mode(ih, sd, &mode);
get_sd_size(ih, sd, &sd_size);
get_sd_blocks(ih, sd, &sd_blocks);
/*
if (fsck_mode (fs) == FSCK_FIX_FIXABLE) {
// check and set nlink first
nlink ++;
set_sd_nlink (ih, sd, &nlink);
mark_buffer_dirty (bh);
if (nlink > 1)
return OK;
}
*/
if (!is_new_file)
get_sd_first_direct_byte(ih, sd, &sd_first_direct_byte);
if (S_ISLNK(mode))
symlnk = 1;
sd_ih = *ih;
// sd_key = sd_ih.ih_key;
pathrelse(path);
if (are_file_items_correct
(&sd_ih, sd, &real_size, &blocks, 0 /* do not mark reachable */ ,
&symlnk) != 1) {
one_more_corruption(fs, FATAL);
fsck_log
("check_regular_file: The file %K with the corrupted structure found\n",
&sd_ih.ih_key);
} else {
fix_sd = 0;
fix_sd += wrong_mode(&sd_ih.ih_key, &mode, real_size, symlnk);
if (!is_new_file)
fix_sd +=
wrong_first_direct_byte(&sd_ih.ih_key,
fs->fs_blocksize,
&first_direct_byte,
sd_first_direct_byte,
real_size);
if (reiserfs_bin_search
(&sd_ih.ih_key, trunc_links, links_num,
sizeof(sd_ih.ih_key), &tmp_position,
comp_short_keys) != POSITION_FOUND) {
fix_sd +=
wrong_st_size(&sd_ih.ih_key,
is_new_file ? MAX_FILE_SIZE_V2 :
MAX_FILE_SIZE_V1, fs->fs_blocksize,
&real_size, sd_size,
symlnk ? TYPE_SYMLINK : 0);
} else {
real_size = sd_size;
}
fix_sd +=
wrong_st_blocks(&sd_ih.ih_key, &blocks, sd_blocks, mode,
is_new_file);
if (fix_sd) {
if (fsck_mode(fs) == FSCK_FIX_FIXABLE) {
struct buffer_head *bh;
/* find stat data and correct it */
set_type_and_offset(KEY_FORMAT_1, &sd_ih.ih_key,
SD_OFFSET, TYPE_STAT_DATA);
if (reiserfs_search_by_key_4
(fs, &sd_ih.ih_key, path) != ITEM_FOUND) {
fsck_log
("check_regular_file: A StatData of the file %K cannot be "
"found\n", &sd_ih.ih_key);
one_more_corruption(fs, FATAL);
return STAT_DATA_NOT_FOUND;
}
bh = get_bh(path);
ih = get_ih(path);
sd = get_item(path);
set_sd_size(ih, sd, &real_size);
set_sd_blocks(ih, sd, &blocks);
set_sd_mode(ih, sd, &mode);
if (!is_new_file)
set_sd_first_direct_byte(ih, sd,
&first_direct_byte);
mark_buffer_dirty(bh);
} else {
fsck_check_stat(fs)->fixable_corruptions +=
fix_sd;
}
}
}
return retval;
}
/* returns buffer, containing found directory item.*/
static char *get_next_directory_item(struct reiserfs_key *key, /* on return this will contain key of next item in the tree */
struct reiserfs_key *parent,
struct item_head *ih, __u32 * pos_in_item,
int dir_format)
{
INITIALIZE_REISERFS_PATH(path);
char *dir_item;
struct reiserfs_key *rdkey;
struct buffer_head *bh;
struct reiserfs_de_head *deh;
int i;
int retval;
start_again:
retval = reiserfs_search_by_entry_key(fs, key, &path);
if (retval != POSITION_FOUND && get_offset(key) != DOT_OFFSET)
reiserfs_panic
("get_next_directory_item: The current directory %k cannot be found",
key);
/* leaf containing directory item */
bh = PATH_PLAST_BUFFER(&path);
*pos_in_item = path.pos_in_item;
*ih = *get_ih(&path);
deh = B_I_DEH(bh, ih);
/* position was not found for '.' or there is no '..' */
if (retval != POSITION_FOUND || ((get_offset(key) == DOT_OFFSET) &&
(get_ih_entry_count(ih) < 2
|| name_in_entry_length(ih, deh + 1,
1) != 2
|| strncmp(name_in_entry(deh + 1, 1),
"..", 2)))) {
fsck_log
("get_next_directory_item: The %s %k cannot be found in %k",
(retval == POSITION_NOT_FOUND) ? "entry" : "directory",
key, &ih->ih_key);
if (fsck_mode(fs) == FSCK_FIX_FIXABLE) {
/* add "." and ".." exist */
pathrelse(&path);
reiserfs_add_entry(fs, key, ".",
name_length(".", dir_format), key,
0);
reiserfs_add_entry(fs, key, "..",
name_length("..", dir_format),
parent, 0);
fsck_log(" - entry was added\n");
goto start_again;
} else {
one_more_corruption(fs, FIXABLE);
fsck_log("\n");
if (retval == DIRECTORY_NOT_FOUND)
return 0;
}
}
/* make sure, that ".." exists as well */
/*
if (get_offset (key) == DOT_OFFSET) {
if (get_ih_entry_count (ih) < 2 ||
name_in_entry_length (ih, deh + 1, 1) != 2 ||
strncmp (name_in_entry (deh + 1, 1), "..", 2))
{
fsck_log ("get_next_directory_item: \"..\" not found in %H\n", ih);
pathrelse (&path);
return 0;
}
}
*/
/* mark hidden entries as visible, set "." and ".." correctly */
deh += *pos_in_item;
for (i = *pos_in_item; i < get_ih_entry_count(ih); i++, deh++) {
/* int namelen;
char * name;
name = name_in_entry (deh, i);
namelen = name_in_entry_length (ih, deh, i);
if (de_hidden (deh)) // handled in check_tree
reiserfs_panic ("get_next_directory_item: item %k: hidden entry %d \'%.*s\'\n",
key, i, namelen, name);
*/
if (get_deh_offset(deh) == DOT_OFFSET) {
if (not_of_one_file(&(deh->deh2_dir_id), key)) {
/* "." must point to the directory it is in */
//deh->deh_objectid != REISERFS_ROOT_PARENT_OBJECTID)/*????*/ {
fsck_log
("get_next_directory_item: The entry \".\" of the directory %K "
"pointes to %K, instead of %K", key,
(struct reiserfs_key
*)(&(deh->deh2_dir_id)), key);
if (fsck_mode(fs) == FSCK_FIX_FIXABLE) {
set_deh_dirid(deh, get_key_dirid(key));
set_deh_objectid(deh,
get_key_objectid(key));
mark_buffer_dirty(bh);
fsck_log(" - corrected\n");
} else {
one_more_corruption(fs, FIXABLE);
fsck_log("\n");
}
}
}
if (get_deh_offset(deh) == DOT_DOT_OFFSET) {
/* set ".." so that it points to the correct parent directory */
if (comp_short_keys(&(deh->deh2_dir_id), parent)) {
fsck_log
("get_next_directory_item: The entry \"..\" of the directory %K "
"pointes to %K, instead of %K", key,
(struct reiserfs_key
*)(&(deh->deh2_dir_id)));
if (fsck_mode(fs) == FSCK_FIX_FIXABLE) {
set_deh_dirid(deh,
get_key_dirid(parent));
set_deh_objectid(deh,
get_key_objectid
(parent));
mark_buffer_dirty(bh);
fsck_log(" - corrected\n");
} else {
one_more_corruption(fs, FIXABLE);
fsck_log("\n");
}
}
}
}
/* copy directory item to the temporary buffer */
dir_item = getmem(get_ih_item_len(ih));
memcpy(dir_item, B_I_PITEM(bh, ih), get_ih_item_len(ih));
/* next item key */
if (PATH_LAST_POSITION(&path) == (B_NR_ITEMS(bh) - 1) &&
(rdkey = uget_rkey(&path)))
copy_key(key, rdkey);
else {
set_key_dirid(key, 0);
set_key_objectid(key, 0);
}
if (fsck_mode(fs) == FSCK_REBUILD)
mark_item_reachable(get_ih(&path), bh);
pathrelse(&path);
return dir_item;
}
/* semantic pass of --check */
static int check_semantic_pass(struct reiserfs_key *key,
struct reiserfs_key *parent, int dot_dot,
struct item_head *new_ih)
{
struct reiserfs_path path;
void *sd;
__u32 nlink;
int is_new_dir;
struct buffer_head *bh;
struct item_head *ih;
int retval;
char *dir_item;
__u32 pos_in_item;
struct item_head tmp_ih;
struct reiserfs_key next_item_key, entry_key, object_key;
__u64 dir_size = 0;
__u32 blocks;
__u64 sd_size;
__u32 sd_blocks;
int fix_sd;
/*int relocate; */
int dir_format = 0;
__u16 mode;
retval = OK;
/* start_again: when directory was relocated */
if (!KEY_IS_STAT_DATA_KEY(key)) {
fsck_log
("check_semantic_pass: The key %k must be key of a StatData\n",
key);
one_more_corruption(fs, FATAL);
return STAT_DATA_NOT_FOUND;
}
/* look for stat data of an object */
if (reiserfs_search_by_key_4(fs, key, &path) == ITEM_NOT_FOUND) {
pathrelse(&path);
return STAT_DATA_NOT_FOUND;
}
/* stat data has been found */
ih = get_ih(&path);
sd = get_item(&path);
get_sd_nlink(ih, sd, &nlink);
/* It seems quite difficult to relocate objects on fix-fixable -
* rewrite_file calls reiserfs_file_write which can convert tails
* to unfm, plus unreachable, was_tail flags, etc. */
#if 0
if (( /* relocate = */ should_be_relocated(&ih->ih_key))) {
/*
if (fsck_mode(fs) == FSCK_CHECK)
relocate = 0;
*/
one_more_corruption(fs, FATAL);
}
#endif
if (fix_obviously_wrong_sd_mode(&path)) {
one_more_corruption(fs, FIXABLE);
pathrelse(&path);
return OK;
}
if (nlink == 0) {
fsck_log
("%s: block %lu: The StatData %k has bad nlink number (%u)\n",
__FUNCTION__, get_bh(&path)->b_blocknr, &ih->ih_key,
nlink);
one_more_corruption(fs, FATAL);
}
if (not_a_directory(sd)) {
fsck_check_stat(fs)->files++;
retval =
check_check_regular_file(&path, sd,
/* relocate ? new_ih : */ 0);
pathrelse(&path);
return retval;
}
/*
if (relocate) {
if (!new_ih)
reiserfs_panic ("check_semantic_pass: Memory is not prepared for relocation of "
"%K", &ih->ih_key);
*new_ih = *ih;
pathrelse (&path);
sem_pass_stat (fs)->oid_sharing_dirs_relocated ++;
relocate_dir (new_ih, 1);
linked_already(&new_ih->ih_key);
one_less_corruption (fs, FIXABLE);
*key = new_ih->ih_key;
retval = RELOCATED;
goto start_again;
}
*/
/*
if (fsck_mode (fs) == FSCK_FIX_FIXABLE) {
// it looks like stat data of a directory found
if (nlink) {
// we saw this directory already
if (!dot_dot) {
// this name is not ".." - and hard links are not allowed on directories
pathrelse (&path);
return STAT_DATA_NOT_FOUND;
} else {
// ".." found
nlink ++;
set_sd_nlink (ih, sd, &nlink);
mark_buffer_dirty (get_bh (&path));
pathrelse (&path);
return OK;
}
} // do not run it for dot_dot on check at all
nlink = 2;
if (get_key_objectid (key) == REISERFS_ROOT_OBJECTID)
nlink ++;
set_sd_nlink (ih, sd, &nlink);
mark_buffer_dirty (get_bh (&path));
}
*/
/* directory stat data found */
if (get_ih_item_len(ih) == SD_SIZE)
is_new_dir = 1;
else
is_new_dir = 0;
/* save stat data's size and st_blocks */
get_sd_size(ih, sd, &sd_size);
get_sd_blocks(ih, sd, &sd_blocks);
get_sd_mode(ih, sd, &mode);
dir_format =
(get_ih_item_len(get_ih(&path)) ==
SD_SIZE) ? KEY_FORMAT_2 : KEY_FORMAT_1;
/* release path pointing to stat data */
pathrelse(&path);
fsck_check_stat(fs)->dirs++;
set_key_dirid(&next_item_key, get_key_dirid(key));
set_key_objectid(&next_item_key, get_key_objectid(key));
set_key_offset_v1(&next_item_key, DOT_OFFSET);
set_key_uniqueness(&next_item_key, DIRENTRY_UNIQUENESS);
dir_size = 0;
while ((dir_item =
get_next_directory_item(&next_item_key, parent, &tmp_ih,
&pos_in_item, dir_format)) != 0) {
/* dir_item is copy of the item in separately allocated memory,
item_key is a key of next item in the tree */
int i;
char *name = 0;
int namelen, entry_len;
struct reiserfs_de_head *deh =
(struct reiserfs_de_head *)dir_item + pos_in_item;
for (i = pos_in_item; i < get_ih_entry_count(&tmp_ih);
i++, deh++) {
struct item_head relocated_ih;
int ret = OK;
if (name) {
free(name);
name = 0;
}
namelen = name_in_entry_length(&tmp_ih, deh, i);
asprintf(&name, "%.*s", namelen, name_in_entry(deh, i));
entry_len = entry_length(&tmp_ih, deh, i);
get_object_key(deh, &object_key, &entry_key, &tmp_ih);
if ((dir_format == KEY_FORMAT_2)
&& (entry_len % 8 != 0)) {
/* not alighed directory of new format - delete it */
if (fsck_mode(fs) == FSCK_FIX_FIXABLE) {
fsck_log
("Entry %K (\"%.*s\") in the directory %K is not formated "
"properly - deleted\n",
(struct reiserfs_key *)&(deh->
deh2_dir_id),
namelen, name, &tmp_ih.ih_key);
reiserfs_remove_entry(fs, &entry_key);
entry_len =
name_length(name, dir_format);
reiserfs_add_entry(fs, key, name,
entry_len,
(struct reiserfs_key
*)&(deh->
deh2_dir_id),
0);
} else {
fsck_log
("Entry %K (\"%.*s\") in the directory %K is not formated "
"properly.\n",
(struct reiserfs_key *)&(deh->
deh2_dir_id),
namelen, name, &tmp_ih.ih_key);
one_more_corruption(fs, FIXABLE);
}
}
print_name(name, namelen);
if (!is_properly_hashed
(fs, name, namelen, get_deh_offset(deh))) {
one_more_corruption(fs, FATAL);
fsck_log
("check_semantic_pass: Hash mismatch detected for (%.*s) in "
"directory %K\n", namelen, name,
&tmp_ih.ih_key);
}
if (is_dot(name, namelen)
|| (is_dot_dot(name, namelen))) {
/* do not go through "." and ".." */
ret = OK;
} else {
if ((ret = add_path_key(&object_key)) == 0) {
ret =
check_semantic_pass(&object_key,
key,
is_dot_dot(name,
namelen),
&relocated_ih);
del_path_key();
}
}
erase_name(namelen);
/* check what check_semantic_tree returned */
switch (ret) {
case OK:
dir_size += DEH_SIZE + entry_len;
break;
case STAT_DATA_NOT_FOUND:
fsck_log
("check_semantic_pass: Name \"%.*s\" in directory %K points to "
"nowhere\n", namelen, name,
&tmp_ih.ih_key);
case LOOP_FOUND:
if (fsck_mode(fs) == FSCK_FIX_FIXABLE) {
reiserfs_remove_entry(fs, &entry_key);
fsck_log(" - removed");
} else {
one_more_corruption(fs, FIXABLE);
}
fsck_log("\n");
break;
case DIRECTORY_HAS_NO_ITEMS:
fsck_log
("check_semantic_pass: Name \"%.*s\" in directory %K points a "
"directory without body\n", namelen, name,
&tmp_ih.ih_key);
/* fixme: stat data should be deleted as well */
/*
if (fsck_fix_fixable (fs)) {
reiserfs_remove_entry (fs, &entry_key);
fsck_data(fs)->deleted_entries ++;
fsck_log (" - removed");
}
fsck_log ("\n"); */
break;
case RELOCATED:
/* file was relocated, update key in corresponding directory entry */
if (reiserfs_search_by_entry_key
(fs, &entry_key, &path) != POSITION_FOUND) {
fsck_log
("Cannot find a name of the relocated file %K in the directory "
"%K\n", &entry_key,
&tmp_ih.ih_key);
} else {
/* update key dir entry points to */
struct reiserfs_de_head *tmp_deh;
tmp_deh =
B_I_DEH(get_bh(&path),
get_ih(&path)) +
path.pos_in_item;
fsck_log
("The directory %K pointing to %K (\"%.*s\") updated to point "
"to ", &tmp_ih.ih_key,
&tmp_deh->deh2_dir_id, namelen,
name);
set_deh_dirid(tmp_deh,
get_key_dirid
(&relocated_ih.ih_key));
set_deh_objectid(tmp_deh,
get_key_objectid
(&relocated_ih.
ih_key));
fsck_log("%K (\"%.*s\")\n",
&tmp_deh->deh2_dir_id, namelen,
name);
mark_buffer_dirty(get_bh(&path));
}
dir_size += DEH_SIZE + entry_len;
pathrelse(&path);
break;
}
} /* for */
freemem(dir_item);
free(name);
name = 0;
if (not_of_one_file(&next_item_key, key))
/* next key is not of this directory */
break;
} /* while (dir_item) */
if (dir_size == 0)
/* FIXME: is it possible? */
return DIRECTORY_HAS_NO_ITEMS;
/* calc correct value of sd_blocks field of stat data */
blocks = dir_size2st_blocks(dir_size);
fix_sd = 0;
fix_sd += wrong_st_blocks(key, &blocks, sd_blocks, mode, is_new_dir);
fix_sd +=
wrong_st_size(key, is_new_dir ? MAX_FILE_SIZE_V2 : MAX_FILE_SIZE_V1,
fs->fs_blocksize, &dir_size, sd_size, TYPE_DIRENTRY);
if (fix_sd) {
if (fsck_mode(fs) == FSCK_FIX_FIXABLE) {
/* we have to fix either sd_size or sd_blocks, so look for stat data again */
if (reiserfs_search_by_key_4(fs, key, &path) !=
ITEM_FOUND) {
fsck_log
("check_semantic_tree: The StatData of the file %K was not found\n",
key);
one_more_corruption(fs, FATAL);
return STAT_DATA_NOT_FOUND;
}
bh = get_bh(&path);
ih = get_ih(&path);
sd = get_item(&path);
set_sd_size(ih, sd, &dir_size);
set_sd_blocks(ih, sd, &blocks);
mark_buffer_dirty(bh);
pathrelse(&path);
} else {
fsck_check_stat(fs)->fixable_corruptions += fix_sd;
}
}
return retval;
}
int check_safe_links()
{
struct reiserfs_path safe_link_path, path;
struct reiserfs_key safe_link_key = { -1, 0, {{0, 0}} };
struct reiserfs_key key = { 0, 0, {{0, 0}} };
struct reiserfs_key *rkey;
struct item_head *tmp_ih;
while (1) {
if (get_key_dirid(&safe_link_key) == 0)
break;
reiserfs_search_by_key_4(fs, &safe_link_key, &safe_link_path);
if (get_blkh_nr_items(B_BLK_HEAD(get_bh(&safe_link_path))) <=
PATH_LAST_POSITION(&safe_link_path)) {
pathrelse(&safe_link_path);
break;
}
tmp_ih = get_ih(&safe_link_path);
if (get_key_dirid(&tmp_ih->ih_key) != (__u32) - 1 ||
get_key_objectid(&tmp_ih->ih_key) == (__u32) - 1) {
pathrelse(&safe_link_path);
break;
}
if (get_ih_item_len(tmp_ih) != 4)
reiserfs_panic("Safe Link %k cannot be of the size %d",
&tmp_ih->ih_key,
get_ih_item_len(tmp_ih));
set_key_dirid(&key,
d32_get((__u32 *) get_item(&safe_link_path), 0));
set_key_objectid(&key, get_key_objectid(&tmp_ih->ih_key));
if ((rkey = reiserfs_next_key(&safe_link_path)) == NULL)
set_key_dirid(&safe_link_key, 0);
else
safe_link_key = *rkey;
if (reiserfs_search_by_key_4(fs, &key, &path) == ITEM_NOT_FOUND) {
/*sware on check, delete on fix-fixable */
if (fsck_mode(fs) == FSCK_CHECK) {
fsck_log
("Invalid safe link %k: cannot find the pointed object (%K)\n",
&tmp_ih->ih_key, &key);
one_more_corruption(fs, FIXABLE);
} else if (fsck_mode(fs) == FSCK_FIX_FIXABLE) {
fsck_log
("Invalid safe link %k: cannot find the pointed object (%K) - "
"safe link was deleted\n", &tmp_ih->ih_key,
&key);
d32_put((__u32 *) get_item(&safe_link_path), 0,
0);
pathrelse(&path);
reiserfsck_delete_item(&safe_link_path, 0);
continue;
}
} else if (get_offset(&tmp_ih->ih_key) == 0x1) {
/* Truncate */
if (!not_a_directory(get_item(&path))) {
/*truncate on directory should not happen */
/*sware on check, delete on fix-fixable */
if (fsck_mode(fs) == FSCK_CHECK) {
fsck_log
("Invalid 'truncate' safe link %k, cannot happen for "
"directory (%K)\n",
&tmp_ih->ih_key, &key);
one_more_corruption(fs, FIXABLE);
} else if (fsck_mode(fs) == FSCK_FIX_FIXABLE) {
fsck_log
("Invalid 'truncate' safe link %k, cannot happen for "
"a directory (%K) - safe link was deleted\n",
&tmp_ih->ih_key, &key);
d32_put((__u32 *)
get_item(&safe_link_path), 0,
0);
pathrelse(&path);
reiserfsck_delete_item(&safe_link_path,
0);
continue;
}
} else {
/* save 'safe truncate links' to avoid swaring on wrong sizes. */
__u32 position;
if (reiserfs_bin_search
(&key, trunc_links, links_num, sizeof(key),
&position,
comp_short_keys) != POSITION_FOUND) {
blocklist__insert_in_position(&key,
(void *)
&trunc_links,
&links_num,
sizeof
(key),
&position);
}
}
}
pathrelse(&path);
pathrelse(&safe_link_path);
}
return OK;
}
void release_safe_links()
{
freemem(trunc_links);
}
/* called when --check is given */
void semantic_check(void)
{
if (fsck_data(fs)->check.bad_nodes) {
fsck_progress("Bad nodes were found, Semantic pass skipped\n");
goto clean;
}
if (fsck_data(fs)->check.fatal_corruptions) {
fsck_progress
("Fatal corruptions were found, Semantic pass skipped\n");
goto clean;
}
fsck_progress("Checking Semantic tree:\n");
if (fsck_mode(fs) == FSCK_FIX_FIXABLE) {
/*create new_bitmap, and initialize new_bitmap & allocable bitmap */
fsck_new_bitmap(fs) =
reiserfs_create_bitmap(get_sb_block_count
(fs->fs_ondisk_sb));
reiserfs_bitmap_copy(fsck_new_bitmap(fs), fs->fs_bitmap2);
fsck_allocable_bitmap(fs) =
reiserfs_create_bitmap(get_sb_block_count
(fs->fs_ondisk_sb));
reiserfs_bitmap_copy(fsck_allocable_bitmap(fs), fs->fs_bitmap2);
fs->block_allocator = reiserfsck_reiserfs_new_blocknrs;
fs->block_deallocator = reiserfsck_reiserfs_free_block;
}
check_safe_links();
if (check_semantic_pass(&root_dir_key, &parent_root_dir_key, 0, 0) !=
OK) {
fsck_log("check_semantic_tree: No root directory found");
one_more_corruption(fs, FATAL);
}
release_safe_links();
if (fsck_mode(fs) == FSCK_FIX_FIXABLE) {
reiserfs_delete_bitmap(fs->fs_bitmap2);
reiserfs_bitmap_delta(fsck_new_bitmap(fs),
fsck_deallocate_bitmap(fs));
fs->fs_bitmap2 = fsck_new_bitmap(fs);
reiserfs_delete_bitmap(fsck_allocable_bitmap(fs));
fsck_allocable_bitmap(fs) = NULL;
set_sb_free_blocks(fs->fs_ondisk_sb,
reiserfs_bitmap_zeros(fs->fs_bitmap2));
mark_buffer_dirty(fs->fs_super_bh);
add_badblock_list(fs, 1);
}
fsck_progress("finished\n");
clean:
if (fsck_deallocate_bitmap(fs))
reiserfs_delete_bitmap(fsck_deallocate_bitmap(fs));
}