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

1342 lines
36 KiB
C

/*
* Copyright 1996-2004 by Hans Reiser, licensing governed by
* reiserfsprogs/README
*/
#include "fsck.h"
int screen_width;
int screen_curr_pos;
char *screen_savebuffer;
int screen_savebuffer_len;
#define MIN(a, b) (((a)>(b))?(b):(a))
/* semantic pass progress */
void print_name(char *name, int len)
{
int i;
if (fsck_quiet(fs))
return;
if (len + screen_curr_pos + 1 > screen_savebuffer_len) {
char *t;
t = expandmem(screen_savebuffer, screen_savebuffer_len + 1,
len + screen_curr_pos - screen_savebuffer_len +
1);
if (!t) {
fsck_progress("\nOut of memory\n");
return; // ????
}
screen_savebuffer = t;
screen_savebuffer_len = len + screen_curr_pos + 1;
}
strcat(screen_savebuffer, "/");
strncat(screen_savebuffer, name, len);
i = screen_curr_pos;
screen_curr_pos += len + 1;
for (; i < screen_curr_pos; i++)
if (screen_savebuffer[i] < 32)
screen_savebuffer[i] = '?';
screen_savebuffer[screen_curr_pos] = 0;
if (screen_width < screen_curr_pos) {
printf("\r... %.*s", screen_width - 4,
screen_savebuffer + (screen_curr_pos -
(screen_width - 4)));
} else
printf("/%.*s", len, screen_savebuffer + screen_curr_pos - len);
fflush(stdout);
}
void erase_name(int len)
{
int i;
if (fsck_quiet(fs))
return;
if (screen_curr_pos < screen_width) {
screen_curr_pos -= len + 1;
screen_savebuffer[screen_curr_pos] = 0;
for (i = 0; i <= len; i++)
printf("\b");
for (i = 0; i <= len + 1; i++)
printf(" ");
for (i = 0; i <= len + 1; i++)
printf("\b");
} else {
screen_curr_pos -= len + 1;
if (screen_curr_pos < 0)
die("%s: Get out of buffer's data!\n", __FUNCTION__);
screen_savebuffer[screen_curr_pos] = 0;
printf("\r");
if (screen_curr_pos >= screen_width) {
int t_preface = MIN(screen_curr_pos - screen_width, 4);
printf("%.*s%.*s", t_preface, "... ",
screen_width - t_preface - 1,
screen_savebuffer + (screen_curr_pos -
(screen_width -
t_preface)) + 1);
} else {
int space_used = printf("%s", screen_savebuffer);
for (i = space_used; i < screen_width; i++)
printf(" ");
for (i = space_used; i < screen_width; i++)
printf("\b");
}
}
fflush(stdout);
}
/* *size is "real" file size, sd_size - size from stat data */
int wrong_st_size(struct reiserfs_key *key, unsigned long long max_file_size,
int blocksize, __u64 * size, __u64 sd_size, int type)
{
if (sd_size <= max_file_size) {
if (sd_size == *size)
return 0;
if (type == TYPE_DIRENTRY) {
/* directory size must match to the sum of length of its entries */
fsck_log
("vpf-10650: The directory %K has the wrong size in the StatData "
"(%Lu)%s(%Lu)\n", key, sd_size,
fsck_mode(fs) ==
FSCK_CHECK ? ", should be " : " - corrected to ",
*size);
return 1;
}
if (sd_size > *size) {
/* size in stat data can be bigger than size calculated by items */
if (fsck_adjust_file_size(fs) || type == TYPE_SYMLINK) {
/* but it -o is given - fix that */
fsck_log
("vpf-10660: The file %K has too big size in the StatData "
"(%Lu)%s(%Lu)\n", key, sd_size,
fsck_mode(fs) ==
FSCK_CHECK ? ", should be " :
" - corrected to ", *size);
sem_pass_stat(fs)->fixed_sizes++;
return 1;
}
*size = sd_size;
return 0;
}
if (!(*size % blocksize)) {
/* last item is indirect */
if (((sd_size & ~(blocksize - 1)) ==
(*size - blocksize)) && sd_size % blocksize) {
/* size in stat data is correct */
*size = sd_size;
return 0;
}
} else {
/* last item is a direct one */
if (!(*size % 8)) {
if (((sd_size & ~7) == (*size - 8))
&& sd_size % 8) {
/* size in stat data is correct */
*size = sd_size;
return 0;
}
}
}
}
fsck_log
("vpf-10670: The file %K has the wrong size in the StatData (%Lu)%s(%Lu)\n",
key, sd_size,
fsck_mode(fs) == FSCK_CHECK ? ", should be " : " - corrected to ",
*size);
sem_pass_stat(fs)->fixed_sizes++;
return 1;
}
/* sd_blocks is 32 bit only */
/* old stat data shares sd_block and sd_dev - do not wipe sd_rdev out */
/* we should fix it as following:
|------------------------------------------------------------------|
| | 3.6 | 3.5 |
|---------------------------------------------------| |
| | blocks | r_dev|generation | blocks/r_dev |
|------------------------------------------------------------------|
| fifo, sockets | 0 | generation | 0 |
| chr/blk_dev | 0 | maj:min | maj:min |
| file, dir, link | blocks | generation | blocks |
|------------------------------------------------------------------|
*/
int wrong_st_blocks(struct reiserfs_key *key, __u32 * blocks, __u32 sd_blocks,
__u16 mode, int new_format)
{
int ret = 0;
if (S_ISREG(mode) || S_ISLNK(mode) || S_ISDIR(mode)) {
if ((!S_ISLNK(mode) && *blocks != sd_blocks) ||
(S_ISLNK(mode) && *blocks != sd_blocks
&& (ROUND_UP(*blocks) != sd_blocks))) {
fsck_log
("vpf-10680: The %s %K has the wrong block count in the StatData "
"(%u)%s(%u)\n",
S_ISDIR(mode) ? "directory" : S_ISREG(mode) ?
"file" : "link", key, sd_blocks,
fsck_mode(fs) ==
FSCK_CHECK ? ", should be " : " - corrected to ",
*blocks);
ret = 1;
}
} else if (new_format || (S_ISFIFO(mode) || S_ISSOCK(mode))) {
if (sd_blocks != 0) {
fsck_log
("vpf-10690: The object %K has the wrong block count in the StatData "
"(%u)%s(%u)\n", key, sd_blocks,
fsck_mode(fs) ==
FSCK_CHECK ? ", should be " : " - corrected to ",
0);
*blocks = 0;
ret = 1;
}
}
return ret;
}
/*
int wrong_st_rdev (struct reiserfs_key *key, __u32 * sd_rdev, __u16 mode, int new_format)
{
int ret = 0;
if (!new_format)
return 0;
if (!S_ISCHR (mode) && !S_ISBLK (mode)) {
if (*sd_rdev != 0) {
fsck_log ("%s %K has wrong sd_rdev %u, has to be 0\n",
S_ISDIR (mode) ? "dir" : "file", key, *sd_rdev);
*sd_rdev = 0;
ret = 1;
}
}
return ret;
}
*/
/* only regular files and symlinks may have items but stat
data. Symlink should have body */
int wrong_mode(struct reiserfs_key *key, __u16 * mode, __u64 real_size,
int symlink)
{
int retval = 0;
if (S_ISLNK(*mode) && !symlink) {
fsck_log
("The file %K (%M) is too big to be the symlink%s regfile\n",
key, *mode,
fsck_mode(fs) ==
FSCK_CHECK ? ", should be the" : " - corrected " "to the");
*mode &= ~S_IFMT;
*mode |= S_IFREG;
retval = 1;
}
if (ftypelet(*mode) != '?') {
/* mode looks reasonable */
if (S_ISREG(*mode) || S_ISLNK(*mode))
return retval;
/* device, pipe, socket have no items */
if (!real_size)
return retval;
}
/* there are items, so change file mode to regular file. Otherwise
- file bodies do not get deleted */
if (fsck_mode(fs) == FSCK_CHECK) {
fsck_log("The object %K has wrong mode (%M)\n", key, *mode);
} else {
fsck_log
("The object %K has wrong mode (%M) - corrected to %M\n",
key, *mode, (S_IFREG | 0600));
}
*mode = (S_IFREG | 0600);
return 1;
}
/* key is a key of last file item */
int wrong_first_direct_byte(struct reiserfs_key *key, int blocksize,
__u32 * first_direct_byte,
__u32 sd_first_direct_byte, __u32 size)
{
if (!size || is_indirect_key(key)) {
/* there is no direct item */
*first_direct_byte = NO_BYTES_IN_DIRECT_ITEM;
if (sd_first_direct_byte != NO_BYTES_IN_DIRECT_ITEM) {
if (fsck_mode(fs) == FSCK_CHECK) {
fsck_log
("The file %K: The wrong info about the tail in the StatData, "
"first_direct_byte (%d) - should be (%d)\n",
key, sd_first_direct_byte,
*first_direct_byte);
} else {
fsck_log
("The file %K: The wrong info about the tail in the StatData, "
"first_direct_byte (%d) - corrected to (%d)\n",
key, sd_first_direct_byte,
*first_direct_byte);
}
return 1;
}
return 0;
}
/* there is direct item */
*first_direct_byte = (get_offset(key) & ~(blocksize - 1)) + 1;
if (*first_direct_byte != sd_first_direct_byte) {
if (fsck_mode(fs) == FSCK_CHECK) {
fsck_log
("The file %K: The wrong info about the tail in the StatData, "
"first_direct_byte (%d) - should be (%d)\n", key,
sd_first_direct_byte, *first_direct_byte);
} else {
fsck_log
("The file %K: The wrong info about the tail in the StatData, "
"first_direct_byte (%d) - corrected to (%d)\n",
key, sd_first_direct_byte, *first_direct_byte);
}
return 1;
}
return 0;
}
/* delete all items (but directory ones) with the same key 'ih' has
(including stat data of not a directory) and put them back at the
other place */
void relocate_dir(struct item_head *ih, int change_ih)
{
struct reiserfs_key key;
struct reiserfs_key *rkey;
struct reiserfs_path path;
struct item_head *path_ih;
struct si *si;
__u32 new_objectid;
/* starting with the leftmost one - look for all items of file,
store them and delete */
key = ih->ih_key;
set_type_and_offset(KEY_FORMAT_1, &key, SD_OFFSET, TYPE_STAT_DATA);
si = 0;
while (1) {
reiserfs_search_by_key_4(fs, &key, &path);
if (get_item_pos(&path) == B_NR_ITEMS(get_bh(&path))) {
rkey = uget_rkey(&path);
if (rkey && !not_of_one_file(&key, rkey)) {
/* file continues in the right neighbor */
key = *rkey;
pathrelse(&path);
continue;
}
/* there is no more items of a directory */
pathrelse(&path);
break;
}
if (is_stat_data_ih(get_ih(&path)))
fix_obviously_wrong_sd_mode(&path);
path_ih = get_ih(&path);
if (not_of_one_file(&key, &(path_ih->ih_key))) {
/* there are no more item with this key */
pathrelse(&path);
break;
}
/* ok, item found, but make sure that it is not a directory one */
if ((is_stat_data_ih(path_ih)
&& not_a_directory(get_item(&path)))
|| is_direct_ih(path_ih) || is_indirect_ih(path_ih)) {
/* item of not a directory found. Leave it in the
tree. FIXME: should not happen */
key = path_ih->ih_key;
set_offset(KEY_FORMAT_1, &key, get_offset(&key) + 1);
pathrelse(&path);
continue;
}
/* directory stat data ro directory item */
si = save_and_delete_file_item(si, &path);
}
if (!si) {
fsck_log
("relocate_dir: WARNING: No one item of the directory %K found\n",
&key);
return;
}
/* get new objectid for relocation or get objectid with which file
was relocated already */
new_objectid = objectid_for_relocation(&ih->ih_key);
set_key_objectid(&ih->ih_key, new_objectid);
/* put all items removed back into tree */
while (si) {
fsck_log("relocate_dir: Moving %k to ", &si->si_ih.ih_key);
set_key_objectid(&si->si_ih.ih_key, new_objectid);
fsck_log("%k\n", &si->si_ih.ih_key);
if (get_offset(&(si->si_ih.ih_key)) == DOT_OFFSET) {
/* fix "." entry to point to a directtory properly */
struct reiserfs_de_head *deh;
deh = (struct reiserfs_de_head *)si->si_dnm_data;
set_deh_objectid(deh, new_objectid);
}
insert_item_separately(&(si->si_ih), si->si_dnm_data,
1 /*was in tree */ );
si = remove_saved_item(si);
}
}
/* path is path to stat data. If file will be relocated - new_ih will contain
a key file was relocated with */
int rebuild_check_regular_file(struct reiserfs_path *path, void *sd,
struct item_head *new_ih)
{
int is_new_file;
// struct reiserfs_key sd_key;
__u16 mode;
__u32 nlink;
__u64 real_size, saved_size;
__u32 blocks, saved_blocks; /* proper values and value in stat data */
__u32 first_direct_byte, saved_first_direct_byte;
struct buffer_head *bh;
struct item_head *ih, sd_ih;
int fix_sd;
int symlnk = 0;
int retval;
retval = OK;
/* stat data of a file */
ih = get_ih(path);
bh = get_bh(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);
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
("%s: Could not find the StatData of the relocated file %k",
__FUNCTION__, &(new_ih->ih_key));
/* stat data is marked unreachable again due to relocation, fix that */
ih = get_ih(path);
bh = get_bh(path);
mark_item_reachable(ih, bh);
sd = get_item(path);
}
id_map_mark(semantic_id_map(fs), get_key_objectid(&ih->ih_key));
/* check and set nlink first */
get_sd_nlink(ih, sd, &nlink);
nlink++;
set_sd_nlink(ih, sd, &nlink);
mark_buffer_dirty(bh);
if (nlink > 1)
return retval;
/* firts name of a file found */
if (get_ih_item_len(ih) == SD_SIZE)
is_new_file = 1;
else
is_new_file = 0;
get_sd_mode(ih, sd, &mode);
get_sd_size(ih, sd, &saved_size);
get_sd_blocks(ih, sd, &saved_blocks);
if (!is_new_file)
get_sd_first_direct_byte(ih, sd, &saved_first_direct_byte);
/* we met this file first time */
if (S_ISREG(mode)) {
sem_pass_stat(fs)->regular_files++;
} else if (S_ISLNK(mode)) {
symlnk = 1;
sem_pass_stat(fs)->symlinks++;
} else {
sem_pass_stat(fs)->others++;
}
sd_ih = *ih;
// sd_key = sd_ih.ih_key;
pathrelse(path);
if (are_file_items_correct
(&sd_ih, sd, &real_size, &blocks, 1 /*mark items reachable */ ,
&symlnk) != 1) {
/* unpassed items will be deleted in pass 4 as they left unaccessed */
sem_pass_stat(fs)->broken_files++;
}
fix_sd = 0;
fix_sd +=
wrong_mode( /*&sd_key, */ &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,
saved_first_direct_byte, real_size);
fix_sd += wrong_st_size( /*&sd_key, */ &sd_ih.ih_key,
is_new_file ? MAX_FILE_SIZE_V2 :
MAX_FILE_SIZE_V1, fs->fs_blocksize, &real_size,
saved_size, symlnk ? TYPE_SYMLINK : 0);
fix_sd +=
wrong_st_blocks(&sd_ih.ih_key, &blocks, saved_blocks, mode,
is_new_file);
if (fix_sd) {
/* 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)
reiserfs_panic
("%s: The StatData of the file %k could not be found",
__FUNCTION__, &sd_ih.ih_key);
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);
}
return retval;
}
static int is_rootdir_key(struct reiserfs_key *key)
{
if (comp_keys(key, &root_dir_key))
return 0;
return 1;
}
/* 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, /*not in tree */
__u32 * pos_in_item)
{
INITIALIZE_REISERFS_PATH(path);
char *dir_item;
struct reiserfs_key *rdkey;
struct buffer_head *bh;
struct reiserfs_de_head *deh;
int i;
int retval;
if ((retval =
reiserfs_search_by_entry_key(fs, key, &path)) != POSITION_FOUND)
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);
/* 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: The entry \"..\" cannot be found in %k\n",
&ih->ih_key);
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))
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);
set_deh_dirid(deh, get_key_dirid(key));
set_deh_objectid(deh, get_key_objectid(key));
mark_buffer_dirty(bh);
fsck_log(" - corrected\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)), parent);
set_deh_dirid(deh, get_key_dirid(parent));
set_deh_objectid(deh, get_key_objectid(parent));
mark_buffer_dirty(bh);
fsck_log(" - corrected\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;
}
// get key of an object pointed by direntry and the key of the entry itself
void get_object_key(struct reiserfs_de_head *deh, struct reiserfs_key *key,
struct reiserfs_key *entry_key, struct item_head *ih)
{
/* entry points to this key */
set_key_dirid(key, get_deh_dirid(deh));
set_key_objectid(key, get_deh_objectid(deh));
set_key_offset_v1(key, SD_OFFSET);
set_key_uniqueness(key, 0);
/* key of entry */
set_key_dirid(entry_key, get_key_dirid(&ih->ih_key));
set_key_objectid(entry_key, get_key_objectid(&ih->ih_key));
set_key_offset_v1(entry_key, get_deh_offset(deh));
set_key_uniqueness(entry_key, DIRENTRY_UNIQUENESS);
}
int fix_obviously_wrong_sd_mode(struct reiserfs_path *path)
{
struct reiserfs_key *next_key = NULL;
__u16 mode;
int retval = 0;
next_key = reiserfs_next_key(path);
if (!next_key || not_of_one_file(next_key, &get_ih(path)->ih_key))
return 0;
/* next item exists and of the same file. Fix the SD mode */
if (not_a_directory(get_item(path)) && is_direntry_key(next_key)) {
/* make SD mode SD of dir */
get_sd_mode(get_ih(path), get_item(path), &mode);
fsck_log("The directory %K had wrong mode %M",
&get_ih(path)->ih_key, mode);
if (fsck_mode(fs) != FSCK_CHECK) {
mode &= ~S_IFMT;
mode |= S_IFDIR;
fsck_log(" - corrected to %M\n", mode);
set_sd_mode(get_ih(path), get_item(path), &mode);
mark_buffer_dirty(get_bh(path));
} else {
fsck_log("\n");
retval = 1;
}
} else if (!not_a_directory(get_item(path))
&& !is_direntry_key(next_key)) {
/* make SD mode SD of regular file */
get_sd_mode(get_ih(path), get_item(path), &mode);
fsck_log("The file %K had wrong mode %M", &get_ih(path)->ih_key,
mode);
if (fsck_mode(fs) != FSCK_CHECK) {
mode &= ~S_IFMT;
mode |= S_IFREG;
fsck_log(" - corrected to %M\n", mode);
set_sd_mode(get_ih(path), get_item(path), &mode);
mark_buffer_dirty(get_bh(path));
} else {
fsck_log("\n");
retval = 1;
}
}
return retval;
}
/* check recursively the semantic tree. Returns OK if entry points to good
object, STAT_DATA_NOT_FOUND if stat data was not found or RELOCATED when
file was relocated because its objectid was already marked as used by
another file */
int rebuild_semantic_pass(struct reiserfs_key *key, struct reiserfs_key *parent,
int dot_dot, struct item_head *new_ih)
{
struct reiserfs_path path;
void *sd;
int is_new_dir;
__u32 nlink;
struct buffer_head *bh;
struct item_head *ih;
int retval, retval1;
char *dir_item;
__u32 pos_in_item;
struct item_head tmp_ih;
struct reiserfs_key item_key, entry_key, object_key;
__u64 dir_size;
__u32 blocks;
__u64 saved_size;
__u32 saved_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))
reiserfs_panic
("rebuild_semantic_pass: The key %k must be key of a StatData",
key);
/* look for stat data of an object */
if (reiserfs_search_by_key_4(fs, key, &path) == ITEM_NOT_FOUND) {
pathrelse(&path);
if (is_rootdir_key(key))
/* root directory has to exist at this point */
reiserfs_panic
("rebuild_semantic_pass: The root directory StatData was not found");
return STAT_DATA_NOT_FOUND;
}
/* stat data has been found */
bh = get_bh(&path);
ih = get_ih(&path);
sd = get_item(&path);
/* */
get_sd_nlink(ih, sd, &nlink);
relocate = 0;
if (!nlink) {
/* we reached the stat data for the first time */
if (id_map_mark
(semantic_id_map(fs), get_key_objectid(&ih->ih_key))) {
/* calculate number of found files/dirs who are using objectid
which is used by another file */
sem_pass_stat(fs)->oid_sharing++;
if (1 /*fsck_adjust_file_size (fs) */ )
/* this works for files only */
relocate = 1;
}
mark_item_reachable(ih, bh);
}
fix_obviously_wrong_sd_mode(&path);
if (not_a_directory(sd)) {
retval =
rebuild_check_regular_file(&path, sd,
relocate ? new_ih : 0);
pathrelse(&path);
return retval;
}
if (relocate) {
if (!new_ih)
reiserfs_panic
("rebuild_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);
*key = new_ih->ih_key;
retval = RELOCATED;
goto start_again;
}
/* 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(bh);
pathrelse(&path);
return OK;
}
}
/* we see the directory first time */
sem_pass_stat(fs)->directories++;
nlink = 2;
if (get_key_objectid(key) == REISERFS_ROOT_OBJECTID)
nlink++;
set_sd_nlink(ih, sd, &nlink);
mark_buffer_dirty(bh);
if (get_ih_item_len(ih) == SD_SIZE)
is_new_dir = 1;
else
is_new_dir = 0;
/*
{
struct reiserfs_key *tmp;
// check next item: if it is not a directory item of the same file
// therefore sd_mode is corrupted so we just reset it to regular file
// mode
tmp = reiserfs_next_key (&path);
if (tmp && !not_of_one_file (tmp, key) && !is_direntry_key (tmp)) {
__u16 mode;
get_sd_mode (ih, sd, &mode);
fsck_log ("file %K had broken mode %M, ", key, mode);
mode &= ~S_IFMT;
mode |= S_IFREG;
fsck_log ("fixed to %M\n", mode);
set_sd_mode (ih, sd, &mode);
nlink = 0;
set_sd_nlink (ih, sd, &nlink);
retval = rebuild_check_regular_file (&path, sd, 0); //no relocate
pathrelse (&path);
return retval;
}
}
*/
dir_format =
(get_ih_item_len(get_ih(&path)) ==
SD_SIZE) ? KEY_FORMAT_2 : KEY_FORMAT_1;
/* save stat data's size and st_blocks */
get_sd_size(ih, sd, &saved_size);
get_sd_blocks(ih, sd, &saved_blocks);
get_sd_mode(ih, sd, &mode);
/* release path pointing to stat data */
pathrelse(&path);
/* make sure that "." and ".." exist */
reiserfs_add_entry(fs, key, ".", name_length(".", dir_format), key,
1 << IH_Unreachable);
reiserfs_add_entry(fs, key, "..", name_length("..", dir_format), parent,
1 << IH_Unreachable);
set_key_dirid(&item_key, get_key_dirid(key));
set_key_objectid(&item_key, get_key_objectid(key));
set_key_offset_v1(&item_key, DOT_OFFSET);
set_key_uniqueness(&item_key, DIRENTRY_UNIQUENESS);
dir_size = 0;
while ((dir_item =
get_next_directory_item(&item_key, parent, &tmp_ih,
&pos_in_item)) != 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;
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 */
fsck_log
("Entry %K (\"%.*s\") in the directory %K is not formated properly - fixed.\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);
}
/*
if ((dir_format == KEY_FORMAT_1) && (namelen != entry_len)) {
// aligned entry in directory of old format - remove and insert it back
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);
}
*/
if (is_dot(name, namelen)) {
dir_size += DEH_SIZE + entry_len;
continue;
}
print_name(name, namelen);
if (!is_properly_hashed
(fs, name, namelen, get_deh_offset(deh)))
reiserfs_panic
("rebuild_semantic_pass: Hash mismatch detected for (\"%.*s\") in directory %K\n",
namelen, name, &tmp_ih.ih_key);
retval1 =
rebuild_semantic_pass(&object_key, key,
is_dot_dot(name, namelen),
&relocated_ih);
erase_name(namelen);
switch (retval1) {
case OK:
dir_size += DEH_SIZE + entry_len;
break;
case STAT_DATA_NOT_FOUND:
case DIRECTORY_HAS_NO_ITEMS:
if (get_offset(&entry_key) == DOT_DOT_OFFSET &&
get_key_objectid(&object_key) ==
REISERFS_ROOT_PARENT_OBJECTID) {
/* ".." of root directory can not be found */
dir_size += DEH_SIZE + entry_len;
continue;
}
fsck_log
("%s: The entry %K (\"%.*s\") in directory %K points to nowhere - is removed\n",
__FUNCTION__, &object_key, namelen, name,
&tmp_ih.ih_key);
reiserfs_remove_entry(fs, &entry_key);
sem_pass_stat(fs)->deleted_entries++;
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
("WARNING: Cannot find the name of the relocated file %K in the directory %K\n",
&object_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 entry %K (\"%.*s\") in directory %K updated to point to ",
&object_key, namelen, name,
&tmp_ih.ih_key);
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\n", &tmp_deh->deh2_dir_id);
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(&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, saved_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, saved_size,
TYPE_DIRENTRY);
if (fix_sd) {
/* 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)
reiserfs_panic
("rebuild_semantic_pass: The StatData of the file %K was not found",
key);
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);
}
return retval;
}
int is_dot(char *name, int namelen)
{
return (namelen == 1 && name[0] == '.') ? 1 : 0;
}
int is_dot_dot(char *name, int namelen)
{
return (namelen == 2 && name[0] == '.' && name[1] == '.') ? 1 : 0;
}
int not_a_directory(void *sd)
{
/* mode is at the same place and of the same size in both stat
datas (v1 and v2) */
struct stat_data_v1 *sd_v1 = sd;
return !(S_ISDIR(le16_to_cpu(sd_v1->sd_mode)));
}
int not_a_regfile(void *sd)
{
/* mode is at the same place and of the same size in both stat
datas (v1 and v2) */
struct stat_data_v1 *sd_v1 = sd;
return !(S_ISREG(le16_to_cpu(sd_v1->sd_mode)));
}
void zero_nlink(struct item_head *ih, void *sd)
{
int zero = 0;
if (get_ih_item_len(ih) == SD_V1_SIZE
&& get_ih_key_format(ih) != KEY_FORMAT_1) {
fsck_log
("zero_nlink: The StatData %k of the wrong format version (%d) - corrected to (%d)\n",
ih, get_ih_key_format(ih), KEY_FORMAT_1);
set_ih_key_format(ih, KEY_FORMAT_1);
}
if (get_ih_item_len(ih) == SD_SIZE
&& get_ih_key_format(ih) != KEY_FORMAT_2) {
fsck_log
("zero_nlink: The StatData %k of the wrong format version (%d) - corrected to (%d)\n",
ih, get_ih_key_format(ih), KEY_FORMAT_2);
set_ih_key_format(ih, KEY_FORMAT_2);
}
set_sd_nlink(ih, sd, &zero);
}
void modify_item(struct item_head *ih, void *item)
{
zero_nlink(ih, item);
mark_item_unreachable(ih);
}
/* mkreiserfs should have created this */
static void make_sure_lost_found_exists(reiserfs_filsys_t *fs)
{
int retval;
INITIALIZE_REISERFS_PATH(path);
unsigned int gen_counter;
__u32 objectid;
__u64 sd_size;
__u32 sd_blocks;
struct buffer_head *bh;
struct item_head *ih;
void *sd;
int item_len;
/* look for "lost+found" in the root directory */
retval = reiserfs_find_entry(fs, &root_dir_key,
"lost+found", &gen_counter,
&lost_found_dir_key);
if (!retval) {
objectid = id_map_alloc(proper_id_map(fs));
if (!objectid) {
fsck_progress
("Could not allocate an objectid for \"/lost+found\", \
lost files will not be linked\n");
return;
}
set_key_dirid(&lost_found_dir_key, REISERFS_ROOT_OBJECTID);
set_key_objectid(&lost_found_dir_key, objectid);
}
/* look for stat data of "lost+found" */
retval = reiserfs_search_by_key_4(fs, &lost_found_dir_key, &path);
if (retval == ITEM_NOT_FOUND)
lost_found_dir_format =
create_dir_sd(fs, &path, &lost_found_dir_key, modify_item);
else {
struct item_head *ih = get_ih(&path);
if (!is_stat_data_ih(ih))
reiserfs_panic("It must be lost+found's stat data %k\n",
&ih->ih_key);
fix_obviously_wrong_sd_mode(&path);
if (not_a_directory(get_item(&path))) {
fsck_progress
("\"/lost+found\" exists, but it is not a directory, \
lost files will not be linked\n");
set_key_objectid(&lost_found_dir_key, 0);
pathrelse(&path);
return;
}
lost_found_dir_format =
(get_ih_item_len(get_ih(&path)) ==
SD_SIZE) ? KEY_FORMAT_2 : KEY_FORMAT_1;
pathrelse(&path);
}
/* add "." and ".." if any of them do not exist */
reiserfs_add_entry(fs, &lost_found_dir_key, ".",
name_length(".", lost_found_dir_format),
&lost_found_dir_key, 1 << IH_Unreachable);
reiserfs_add_entry(fs, &lost_found_dir_key, "..",
name_length("..", lost_found_dir_format),
&root_dir_key, 1 << IH_Unreachable);
item_len = reiserfs_add_entry(fs, &root_dir_key, "lost+found",
name_length("lost+found",
root_dir_format),
&lost_found_dir_key, 1 << IH_Unreachable);
if (item_len) {
if (reiserfs_search_by_key_4(fs, &root_dir_key, &path) ==
ITEM_NOT_FOUND)
reiserfs_panic
("%s: StatData of the root directory must exists",
__FUNCTION__);
bh = get_bh(&path);
ih = get_ih(&path);
sd = get_item(&path);
get_sd_size(ih, sd, &sd_size);
sd_size += item_len;
set_sd_size(ih, sd, &sd_size);
sd_blocks = dir_size2st_blocks(sd_size);
set_sd_blocks(ih, sd, &sd_blocks);
mark_buffer_dirty(bh);
pathrelse(&path);
}
return;
}
/* Result of the rebuild pass will be saved in the state file which is needed to start
* fsck again from the next pass. */
static void save_rebuild_semantic_result(reiserfs_filsys_t *fs)
{
FILE *file;
int retval;
file = open_file("temp_fsck_file.deleteme", "w+");
if (!file)
return;
reiserfs_begin_stage_info_save(file, SEMANTIC_DONE);
/* Method not implemented yet.
reiserfs_objectid_map_save (file, semantic_id_map (fs));
*/
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));
}
/* we have nothing to load from a state file, but we have to fetch
on-disk bitmap, copy it to allocable bitmap, and fetch objectid
map */
void load_semantic_result(FILE * file, reiserfs_filsys_t *fs)
{
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;
/* we need objectid map on semantic pass to be able to relocate files */
proper_id_map(fs) = id_map_init();
/* Not implemented yet.
fetch_objectid_map (proper_id_map (fs), fs);
semantic_id_map (fs) = reiserfs_objectid_map_load (file);
*/
}
static void before_pass_3(reiserfs_filsys_t *fs)
{
semantic_id_map(fs) = id_map_init();
}
static void after_pass_3(reiserfs_filsys_t *fs)
{
/* update super block: objectid map, fsck state */
set_sb_fs_state(fs->fs_ondisk_sb, SEMANTIC_DONE);
mark_buffer_dirty(fs->fs_super_bh);
/* write all dirty blocks */
fsck_progress("Flushing..");
id_map_flush(proper_id_map(fs), fs);
fs->fs_dirt = 1;
reiserfs_flush_to_ondisk_bitmap(fsck_new_bitmap(fs), fs);
reiserfs_flush(fs);
fsck_progress("finished\n");
stage_report(3, fs);
if (!fsck_run_one_step(fs)) {
if (fsck_user_confirmed(fs, "Continue? (Yes):", "Yes\n", 1))
/* reiserfsck continues */
return;
}
save_rebuild_semantic_result(fs);
id_map_free(proper_id_map(fs));
proper_id_map(fs) = 0;
fs->fs_dirt = 1;
reiserfs_close(fs);
exit(0);
}
/* this is part of rebuild tree */
void pass_3_semantic(reiserfs_filsys_t *fs)
{
before_pass_3(fs);
fsck_progress("Pass 3 (semantic):\n");
/* when warnings go not to stderr - separate them in the log */
if (fsck_log_file(fs) != stderr)
fsck_log("####### Pass 3 #########\n");
if (!fs->fs_hash_function)
reiserfs_panic("Hash function should be selected already");
make_sure_root_dir_exists(fs, modify_item, 1 << IH_Unreachable);
make_sure_lost_found_exists(fs);
id_map_mark(proper_id_map(fs), get_key_objectid(&root_dir_key));
id_map_mark(proper_id_map(fs), get_key_objectid(&lost_found_dir_key));
/* link all relocated files into /lost+found directory */
link_relocated_files();
rebuild_semantic_pass(&root_dir_key, &parent_root_dir_key,
0 /*!dot_dot */ , 0 /*reloc_ih */ );
add_badblock_list(fs, 1);
after_pass_3(fs);
}