1322 lines
39 KiB
C
1322 lines
39 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/malloc.h"
|
|
#include "misc/device.h"
|
|
#include "util/device.h"
|
|
#include "util/misc.h"
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#define MIN(a, b) (((a)>(b))?(b):(a))
|
|
|
|
/* *size is "real" file size, sd_size - size from stat data */
|
|
int wrong_st_size (const reiserfs_key_t * 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 extent */
|
|
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 (const reiserfs_key_t * 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 && (MISC_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 (reiserfs_key_t * 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 (reiserfs_key_t * 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 (misc_device_typec (*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_fdb (reiserfs_key_t * key, int blocksize,
|
|
__u32 * first_direct_byte,
|
|
__u32 sd_fdb, __u32 size)
|
|
{
|
|
if (!size || reiserfs_key_ext (key)) {
|
|
/* there is no direct item */
|
|
*first_direct_byte = REISERFS_SD_NODIRECT;
|
|
if (sd_fdb != REISERFS_SD_NODIRECT) {
|
|
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_fdb, *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_fdb, *first_direct_byte);
|
|
}
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* there is direct item */
|
|
*first_direct_byte = (reiserfs_key_get_off (key) & ~(blocksize - 1)) + 1;
|
|
if (*first_direct_byte != sd_fdb) {
|
|
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_fdb,
|
|
*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_fdb,
|
|
*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 (reiserfs_ih_t * ih) {
|
|
const reiserfs_key_t * rkey;
|
|
reiserfs_ih_t * path_ih;
|
|
reiserfs_path_t path;
|
|
__u32 new_objectid;
|
|
reiserfs_key_t key;
|
|
saveitem_t * si;
|
|
int moved;
|
|
|
|
/* starting with the leftmost one - look for all items of file,
|
|
store them and delete */
|
|
key = ih->ih_key;
|
|
reiserfs_key_set_sec (KEY_FORMAT_1, &key, OFFSET_SD, TYPE_STAT_DATA);
|
|
|
|
si = 0;
|
|
while (1) {
|
|
reiserfs_tree_search_item (fs, &key, &path);
|
|
|
|
if (REISERFS_PATH_LEAF_POS (&path) ==
|
|
reiserfs_node_items (REISERFS_PATH_LEAF (&path)))
|
|
{
|
|
rkey = reiserfs_tree_rkey (&path, fs);
|
|
if (rkey && !reiserfs_key_comp2 (&key, rkey)) {
|
|
/* file continues in the right neighbor */
|
|
key = *rkey;
|
|
reiserfs_tree_pathrelse (&path);
|
|
continue;
|
|
}
|
|
/* there is no more items of a directory */
|
|
reiserfs_tree_pathrelse (&path);
|
|
break;
|
|
}
|
|
|
|
path_ih = REISERFS_PATH_IH (&path);
|
|
if (reiserfs_key_comp2 (&key, &(path_ih->ih_key))) {
|
|
/* there are no more item with this key */
|
|
reiserfs_tree_pathrelse (&path);
|
|
break;
|
|
}
|
|
|
|
/* ok, item found, but make sure that it is not a directory one */
|
|
if ((reiserfs_ih_stat (path_ih) &&
|
|
not_a_directory (REISERFS_PATH_ITEM (&path))) ||
|
|
reiserfs_ih_direct (path_ih) || reiserfs_ih_ext (path_ih))
|
|
{
|
|
/* item of not a directory found. Leave it in the
|
|
tree. FIXME: should not happen */
|
|
key = path_ih->ih_key;
|
|
reiserfs_key_set_off (KEY_FORMAT_1, &key,
|
|
reiserfs_key_get_off (&key) + 1);
|
|
reiserfs_tree_pathrelse (&path);
|
|
continue;
|
|
}
|
|
|
|
/* directory stat data ro directory item */
|
|
fsck_item_save(&path, &si);
|
|
reiserfs_tree_delete(fs, &path, 1);
|
|
}
|
|
|
|
if (!si) {
|
|
fsck_log ("%s: WARNING: No one item of the directory "
|
|
"%K found\n", __FUNCTION__, &key);
|
|
return;
|
|
}
|
|
|
|
/* get new objectid for relocation or get objectid with which file
|
|
was relocated already */
|
|
new_objectid = fsck_relocate_oid (&ih->ih_key);
|
|
moved = 0;
|
|
|
|
/* put all items removed back into tree */
|
|
while (si) {
|
|
reiserfs_key_set_oid (&si->si_ih.ih_key, new_objectid);
|
|
|
|
if (reiserfs_key_get_off (&(si->si_ih.ih_key)) == OFFSET_DOT) {
|
|
/* fix "." entry to point to a directtory properly */
|
|
reiserfs_deh_t * deh;
|
|
|
|
deh = (reiserfs_deh_t *)si->si_dnm_data;
|
|
reiserfs_deh_set_obid (deh, new_objectid);
|
|
}
|
|
|
|
fsck_tree_insert_item (&(si->si_ih), si->si_dnm_data, 0);
|
|
si = fsck_item_free(si);
|
|
moved++;
|
|
}
|
|
|
|
if (moved) {
|
|
fsck_log("%s: %d items of dir %K are moved to %u oid\n",
|
|
__FUNCTION__, moved, &ih->ih_key, new_objectid);
|
|
}
|
|
|
|
reiserfs_key_set_oid (&ih->ih_key, new_objectid);
|
|
}
|
|
|
|
|
|
|
|
/* 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 (reiserfs_path_t * path, void * sd,
|
|
reiserfs_ih_t * new_ih)
|
|
{
|
|
int is_new_file;
|
|
// reiserfs_key_t 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_fdb;
|
|
|
|
reiserfs_bh_t * bh;
|
|
reiserfs_ih_t * ih, sd_ih;
|
|
int fix_sd;
|
|
int symlnk = 0;
|
|
int retval;
|
|
|
|
retval = OK;
|
|
|
|
/* stat data of a file */
|
|
ih = REISERFS_PATH_IH (path);
|
|
bh = REISERFS_PATH_LEAF (path);
|
|
|
|
if (new_ih) {
|
|
/* this objectid is used already */
|
|
*new_ih = *ih;
|
|
reiserfs_tree_pathrelse (path);
|
|
fsck_file_relocate (&new_ih->ih_key, 1);
|
|
fsck_relocate_mklinked(&new_ih->ih_key);
|
|
sem_pass_stat (fs)->oid_sharing_files_relocated ++;
|
|
retval = RELOCATED;
|
|
if (reiserfs_tree_search_item (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 = REISERFS_PATH_IH (path);
|
|
bh = REISERFS_PATH_LEAF (path);
|
|
fsck_item_mkreach (ih, bh);
|
|
sd = REISERFS_PATH_ITEM (path);
|
|
|
|
}
|
|
|
|
id_map_mark(semantic_id_map(fs), reiserfs_key_get_oid (&ih->ih_key));
|
|
|
|
/* check and set nlink first */
|
|
reiserfs_stat_get_nlink (ih, sd, &nlink);
|
|
nlink ++;
|
|
reiserfs_stat_set_nlink (ih, sd, &nlink);
|
|
reiserfs_buffer_mkdirty (bh);
|
|
|
|
if (nlink > 1)
|
|
return retval;
|
|
|
|
/* firts name of a file found */
|
|
if (reiserfs_ih_get_len (ih) == REISERFS_SD_SIZE)
|
|
is_new_file = 1;
|
|
else
|
|
is_new_file = 0;
|
|
|
|
reiserfs_stat_get_mode (ih, sd, &mode);
|
|
reiserfs_stat_get_size (ih, sd, &saved_size);
|
|
reiserfs_stat_get_blocks (ih, sd, &saved_blocks);
|
|
if (!is_new_file)
|
|
reiserfs_stat_get_fdb (ih, sd, &saved_fdb);
|
|
|
|
/* 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;
|
|
reiserfs_tree_pathrelse (path);
|
|
|
|
if (are_file_items_correct (&sd_ih, sd, &real_size,
|
|
&blocks, 1/*mark reachable*/,
|
|
&symlnk) != 1)
|
|
{
|
|
/* unpassed items will be deleted in pass 4 as they left unaccessed */
|
|
fsck_log("%s: some items of %K are left unaccessed.\n",
|
|
__FUNCTION__, &sd_ih.ih_key);
|
|
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_fdb (&sd_ih.ih_key, fs->fs_blocksize,
|
|
&first_direct_byte, saved_fdb, real_size);
|
|
|
|
fix_sd += wrong_st_size (/*&sd_key,*/ &sd_ih.ih_key,
|
|
is_new_file ? REISERFS_SD_SIZE_MAX_V2 : REISERFS_SD_SIZE_MAX_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 */
|
|
reiserfs_key_set_sec (KEY_FORMAT_1, &sd_ih.ih_key,
|
|
OFFSET_SD, TYPE_STAT_DATA);
|
|
if (reiserfs_tree_search_item (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 = REISERFS_PATH_LEAF (path);
|
|
ih = REISERFS_PATH_IH (path);
|
|
sd = REISERFS_PATH_ITEM (path);
|
|
reiserfs_stat_set_size (ih, sd, &real_size);
|
|
reiserfs_stat_set_blocks (ih, sd, &blocks);
|
|
reiserfs_stat_set_mode (ih, sd, &mode);
|
|
if (!is_new_file)
|
|
reiserfs_stat_set_fdb (ih, sd, &first_direct_byte);
|
|
reiserfs_buffer_mkdirty (bh);
|
|
}
|
|
|
|
return retval;
|
|
}
|
|
|
|
|
|
static int is_rootdir_key (const reiserfs_key_t * key)
|
|
{
|
|
if (reiserfs_key_comp (key, &root_dir_key))
|
|
return 0;
|
|
return 1;
|
|
}
|
|
|
|
|
|
/* returns buffer, containing found directory item.*/
|
|
static char * get_next_directory_item (reiserfs_key_t * key, /* on return this will
|
|
contain key of next item
|
|
in the tree */
|
|
const reiserfs_key_t * parent,
|
|
reiserfs_ih_t * ih,/*not in tree*/
|
|
__u32 * pos_in_item)
|
|
{
|
|
const reiserfs_key_t * rdkey;
|
|
REISERFS_PATH_INIT (path);
|
|
reiserfs_deh_t * deh;
|
|
reiserfs_bh_t * bh;
|
|
char * dir_item;
|
|
int retval;
|
|
int i;
|
|
|
|
|
|
if ((retval = reiserfs_tree_search_entry (fs, key, &path)) != POSITION_FOUND)
|
|
reiserfs_panic ("get_next_directory_item: The current directory %k cannot be "
|
|
"found", key);
|
|
|
|
/* leaf containing directory item */
|
|
bh = REISERFS_PATH_LEAF (&path);
|
|
*pos_in_item = path.pos_in_item;
|
|
*ih = *REISERFS_PATH_IH (&path);
|
|
deh = reiserfs_deh (bh, ih);
|
|
|
|
/* make sure, that ".." exists as well */
|
|
if (reiserfs_key_get_off (key) == OFFSET_DOT) {
|
|
if (reiserfs_ih_get_entries (ih) < 2 ||
|
|
reiserfs_direntry_name_len (ih, deh + 1, 1) != 2 ||
|
|
strncmp (reiserfs_deh_name (deh + 1, 1), "..", 2))
|
|
{
|
|
fsck_log ("get_next_directory_item: The entry \"..\" cannot be "
|
|
"found in %k\n", &ih->ih_key);
|
|
|
|
reiserfs_tree_pathrelse (&path);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/* mark hidden entries as visible, set "." and ".." correctly */
|
|
deh += *pos_in_item;
|
|
for (i = *pos_in_item; i < reiserfs_ih_get_entries (ih); i ++, deh ++) {
|
|
int namelen;
|
|
char * name;
|
|
|
|
name = reiserfs_deh_name (deh, i);
|
|
namelen = reiserfs_direntry_name_len (ih, deh, i);
|
|
|
|
if (reiserfs_deh_get_off (deh) == OFFSET_DOT) {
|
|
if (reiserfs_key_comp2 (&(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 points to %K, instead of %K",
|
|
key, (reiserfs_key_t *)(&(deh->deh2_dir_id)), key);
|
|
|
|
reiserfs_deh_set_did (deh, reiserfs_key_get_did (key));
|
|
reiserfs_deh_set_obid (deh, reiserfs_key_get_oid (key));
|
|
reiserfs_buffer_mkdirty (bh);
|
|
fsck_log (" - corrected\n");
|
|
}
|
|
}
|
|
|
|
if (reiserfs_deh_get_off (deh) == OFFSET_DOT_DOT) {
|
|
/* set ".." so that it points to the correct parent directory */
|
|
if (reiserfs_key_comp2 (&(deh->deh2_dir_id), parent)) {
|
|
fsck_log ("get_next_directory_item: The entry \"..\" of the "
|
|
"directory %K points to %K, instead of %K",
|
|
key, (reiserfs_key_t *)(&(deh->deh2_dir_id)), parent);
|
|
reiserfs_deh_set_did (deh, reiserfs_key_get_did (parent));
|
|
reiserfs_deh_set_obid (deh, reiserfs_key_get_oid (parent));
|
|
reiserfs_buffer_mkdirty (bh);
|
|
fsck_log (" - corrected\n");
|
|
}
|
|
}
|
|
}
|
|
|
|
/* copy directory item to the temporary buffer */
|
|
dir_item = misc_getmem (reiserfs_ih_get_len (ih));
|
|
memcpy (dir_item, reiserfs_item_by_ih (bh, ih), reiserfs_ih_get_len (ih));
|
|
|
|
|
|
/* next item key */
|
|
if ((rdkey = reiserfs_tree_next_key (&path, fs)))
|
|
reiserfs_key_copy (key, rdkey);
|
|
else {
|
|
reiserfs_key_set_did (key, 0);
|
|
reiserfs_key_set_oid (key, 0);
|
|
}
|
|
|
|
if (fsck_mode (fs) == FSCK_REBUILD)
|
|
fsck_item_mkreach (REISERFS_PATH_IH (&path), bh);
|
|
reiserfs_tree_pathrelse (&path);
|
|
|
|
return dir_item;
|
|
}
|
|
|
|
|
|
// get key of an object pointed by direntry and the key of the entry itself
|
|
void get_object_key (reiserfs_deh_t * deh, reiserfs_key_t * key,
|
|
reiserfs_key_t * entry_key, reiserfs_ih_t * ih)
|
|
{
|
|
/* entry points to this key */
|
|
reiserfs_key_set_did (key, reiserfs_deh_get_did (deh));
|
|
reiserfs_key_set_oid (key, reiserfs_deh_get_obid (deh));
|
|
reiserfs_key_set_off1 (key, OFFSET_SD);
|
|
reiserfs_key_set_uni (key, 0);
|
|
|
|
/* key of entry */
|
|
reiserfs_key_set_did (entry_key, reiserfs_key_get_did (&ih->ih_key));
|
|
reiserfs_key_set_oid (entry_key, reiserfs_key_get_oid (&ih->ih_key));
|
|
reiserfs_key_set_off1 (entry_key, reiserfs_deh_get_off (deh));
|
|
reiserfs_key_set_uni (entry_key, UNI_DE);
|
|
}
|
|
|
|
int fix_obviously_wrong_sd_mode (reiserfs_path_t * path) {
|
|
const reiserfs_key_t * next_key;
|
|
__u16 mode;
|
|
int retval = 0;
|
|
|
|
next_key = reiserfs_tree_next_key (path, fs);
|
|
|
|
if (!next_key)
|
|
return 0;
|
|
|
|
if (reiserfs_key_comp2 (next_key, &REISERFS_PATH_IH(path)->ih_key))
|
|
return 0;
|
|
|
|
/* next item exists and of the same file. Fix the SD mode */
|
|
|
|
if (not_a_directory (REISERFS_PATH_ITEM (path)) &&
|
|
reiserfs_key_dir (next_key))
|
|
{
|
|
/* make SD mode SD of dir */
|
|
reiserfs_stat_get_mode (REISERFS_PATH_IH (path),
|
|
REISERFS_PATH_ITEM (path), &mode);
|
|
|
|
fsck_log ("The directory %K had wrong mode %M",
|
|
&REISERFS_PATH_IH(path)->ih_key, mode);
|
|
|
|
if (fsck_mode(fs) != FSCK_CHECK) {
|
|
mode &= ~S_IFMT;
|
|
mode |= S_IFDIR;
|
|
fsck_log (" - corrected to %M\n", mode);
|
|
reiserfs_stat_set_mode (REISERFS_PATH_IH (path),
|
|
REISERFS_PATH_ITEM (path), &mode);
|
|
|
|
reiserfs_buffer_mkdirty (REISERFS_PATH_LEAF(path));
|
|
} else {
|
|
fsck_log ("\n");
|
|
retval = 1;
|
|
}
|
|
} else if (!not_a_directory (REISERFS_PATH_ITEM (path)) &&
|
|
!reiserfs_key_dir (next_key))
|
|
{
|
|
/* make SD mode SD of regular file */
|
|
reiserfs_stat_get_mode (REISERFS_PATH_IH (path),
|
|
REISERFS_PATH_ITEM (path), &mode);
|
|
|
|
fsck_log ("The file %K had wrong mode %M",
|
|
&REISERFS_PATH_IH(path)->ih_key, mode);
|
|
|
|
if (fsck_mode(fs) != FSCK_CHECK) {
|
|
mode &= ~S_IFMT;
|
|
mode |= S_IFREG;
|
|
fsck_log (" - corrected to %M\n", mode);
|
|
reiserfs_stat_set_mode (REISERFS_PATH_IH (path),
|
|
REISERFS_PATH_ITEM (path), &mode);
|
|
|
|
reiserfs_buffer_mkdirty (REISERFS_PATH_LEAF(path));
|
|
} else {
|
|
fsck_log ("\n");
|
|
retval = 1;
|
|
}
|
|
|
|
}
|
|
|
|
return retval;
|
|
}
|
|
|
|
static int is_lost_found (char * name, int namelen)
|
|
{
|
|
return (namelen == 10 && !memcmp(name, "lost+found", 10)) ? 1 : 0;
|
|
}
|
|
|
|
void cb_item_modify (reiserfs_ih_t *ih, void *item) {
|
|
zero_nlink (ih, item);
|
|
reiserfs_ih_mkunreach (ih);
|
|
}
|
|
|
|
/* 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 (reiserfs_key_t * key,
|
|
const reiserfs_key_t * parent,
|
|
int etype, reiserfs_ih_t * new_ih)
|
|
{
|
|
reiserfs_path_t path;
|
|
void * sd;
|
|
int is_new_dir;
|
|
__u32 nlink;
|
|
reiserfs_bh_t * bh;
|
|
reiserfs_ih_t * ih;
|
|
int retval, retval1;
|
|
char * dir_item;
|
|
__u32 pos_in_item;
|
|
reiserfs_ih_t tmp_ih;
|
|
reiserfs_key_t item_key, entry_key, object_key, *found;
|
|
__u64 dir_size;
|
|
__u32 blocks;
|
|
__u64 saved_size;
|
|
__u32 saved_blocks;
|
|
int fix_sd;
|
|
int relocate;
|
|
int dir_format = 0;
|
|
__u16 mode;
|
|
int entry_len;
|
|
|
|
|
|
retval = OK;
|
|
|
|
start_again: /* when directory was relocated */
|
|
|
|
if (!reiserfs_key_stat (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_tree_search_item (fs, key, &path) == ITEM_NOT_FOUND) {
|
|
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");
|
|
/* If an item of the same object is found, create a stat item. */
|
|
found = &REISERFS_PATH_IH(&path)->ih_key;
|
|
if (!reiserfs_key_comp2(key, found)) {
|
|
if (reiserfs_key_dir (found) || reiserfs_key_get_off (key) == 1) {
|
|
sem_pass_stat(fs)->added_sd ++;
|
|
reiserfs_tree_create_stat (fs, &path, key, cb_item_modify);
|
|
reiserfs_tree_pathrelse (&path);
|
|
goto start_again;
|
|
}
|
|
}
|
|
|
|
reiserfs_tree_pathrelse (&path);
|
|
return STAT_DATA_NOT_FOUND;
|
|
}
|
|
|
|
if ((etype == ET_NAME) && !reiserfs_key_comp2(key, &lost_found_dir_key)) {
|
|
/* This is not "lost+found" entry that points to "lost+found" object. */
|
|
reiserfs_tree_pathrelse (&path);
|
|
return DIRECTORY_HAS_NO_ITEMS;
|
|
}
|
|
|
|
/* stat data has been found */
|
|
bh = REISERFS_PATH_LEAF (&path);
|
|
ih = REISERFS_PATH_IH (&path);
|
|
sd = REISERFS_PATH_ITEM(&path);
|
|
|
|
/* */
|
|
reiserfs_stat_get_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), reiserfs_key_get_oid (&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 ++;
|
|
relocate = 1;
|
|
}
|
|
|
|
fsck_item_mkreach (ih, bh);
|
|
}
|
|
|
|
fix_obviously_wrong_sd_mode (&path);
|
|
|
|
if (not_a_directory (sd)) {
|
|
retval = rebuild_check_regular_file (&path, sd, relocate ? new_ih : 0);
|
|
reiserfs_tree_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;
|
|
reiserfs_tree_pathrelse (&path);
|
|
sem_pass_stat (fs)->oid_sharing_dirs_relocated ++;
|
|
relocate_dir (new_ih);
|
|
fsck_relocate_mklinked(&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 (etype != ET_DOT_DOT) {
|
|
/* this name is not ".." - and hard links are not allowed on
|
|
directories */
|
|
reiserfs_tree_pathrelse (&path);
|
|
return STAT_DATA_NOT_FOUND;
|
|
} else {
|
|
/* ".." found */
|
|
nlink ++;
|
|
reiserfs_stat_set_nlink (ih, sd, &nlink);
|
|
reiserfs_buffer_mkdirty (bh);
|
|
reiserfs_tree_pathrelse (&path);
|
|
return OK;
|
|
}
|
|
}
|
|
|
|
|
|
/* we see the directory first time */
|
|
sem_pass_stat (fs)->directories ++;
|
|
nlink = 2;
|
|
if (reiserfs_key_get_oid (key) == REISERFS_ROOT_OBJECTID)
|
|
nlink ++;
|
|
reiserfs_stat_set_nlink (ih, sd, &nlink);
|
|
reiserfs_buffer_mkdirty (bh);
|
|
|
|
if (reiserfs_ih_get_len (ih) == REISERFS_SD_SIZE)
|
|
is_new_dir = 1;
|
|
else
|
|
is_new_dir = 0;
|
|
|
|
|
|
/*
|
|
{
|
|
reiserfs_key_t * 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_tree_next_key (&path);
|
|
if (tmp && !reiserfs_key_comp2 (tmp, key) && !reiserfs_key_dir (tmp)) {
|
|
__u16 mode;
|
|
|
|
reiserfs_stat_get_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);
|
|
reiserfs_stat_set_mode (ih, sd, &mode);
|
|
|
|
nlink = 0;
|
|
reiserfs_stat_set_nlink (ih, sd, &nlink);
|
|
|
|
retval = rebuild_check_regular_file (&path, sd, 0); //no relocate
|
|
reiserfs_tree_pathrelse (&path);
|
|
return retval;
|
|
}
|
|
}
|
|
*/
|
|
|
|
|
|
dir_format = (reiserfs_ih_get_len (REISERFS_PATH_IH (&path)) == REISERFS_SD_SIZE) ?
|
|
KEY_FORMAT_2 : KEY_FORMAT_1;
|
|
|
|
/* save stat data's size and st_blocks */
|
|
reiserfs_stat_get_size (ih, sd, &saved_size);
|
|
reiserfs_stat_get_blocks (ih, sd, &saved_blocks);
|
|
reiserfs_stat_get_mode (ih, sd, &mode);
|
|
|
|
/* release path pointing to stat data */
|
|
reiserfs_tree_pathrelse (&path);
|
|
|
|
/* make sure that "." and ".." exist */
|
|
entry_len = reiserfs_direntry_entry_estimate (".", dir_format);
|
|
reiserfs_tree_insert_entry (fs, key, ".", entry_len, key,
|
|
1 << IH_Unreachable);
|
|
|
|
entry_len = reiserfs_direntry_entry_estimate ("..", dir_format);
|
|
reiserfs_tree_insert_entry (fs, key, "..", entry_len,
|
|
parent, 1 << IH_Unreachable);
|
|
|
|
reiserfs_key_set_did (&item_key, reiserfs_key_get_did (key));
|
|
reiserfs_key_set_oid (&item_key, reiserfs_key_get_oid (key));
|
|
reiserfs_key_set_off1 (&item_key, OFFSET_DOT);
|
|
reiserfs_key_set_uni (&item_key, UNI_DE);
|
|
|
|
|
|
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[REISERFS_NAME_MAX];
|
|
int namelen, entry_len;
|
|
reiserfs_deh_t * deh = (reiserfs_deh_t *)dir_item + pos_in_item;
|
|
|
|
for (i = pos_in_item; i < reiserfs_ih_get_entries (&tmp_ih); i ++, deh ++) {
|
|
reiserfs_ih_t relocated_ih;
|
|
|
|
name[0] = '\0';
|
|
|
|
namelen = reiserfs_direntry_name_len (&tmp_ih, deh, i);
|
|
sprintf(name, "%.*s", namelen, reiserfs_deh_name (deh, i));
|
|
|
|
entry_len = reiserfs_direntry_entry_len (&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",
|
|
(reiserfs_key_t *)&(deh->deh2_dir_id),
|
|
namelen, name, &tmp_ih.ih_key);
|
|
|
|
reiserfs_tree_delete_entry (fs, &entry_key);
|
|
entry_len = reiserfs_direntry_entry_estimate (name, dir_format);
|
|
reiserfs_tree_insert_entry (fs, key, name, entry_len,
|
|
(reiserfs_key_t *)&(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",
|
|
(reiserfs_key_t *)&(deh->deh2_dir_id),
|
|
namelen, name, &tmp_ih.ih_key);
|
|
|
|
reiserfs_tree_delete_entry (fs, &entry_key);
|
|
entry_len = reiserfs_direntry_entry_estimate (name, dir_format);
|
|
reiserfs_tree_insert_entry (fs, key, name, entry_len,
|
|
(reiserfs_key_t *)&(deh->deh2_dir_id), 0);
|
|
}
|
|
*/
|
|
|
|
if (is_dot (name, namelen)) {
|
|
dir_size += REISERFS_DEH_SIZE + entry_len;
|
|
continue;
|
|
}
|
|
|
|
if (!fsck_quiet(fs)) {
|
|
util_misc_print_name (fsck_progress_file(fs),
|
|
name, namelen);
|
|
}
|
|
|
|
if (!reiserfs_hash_correct (&fs->hash, name, namelen,
|
|
reiserfs_deh_get_off (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) ? ET_DOT_DOT :
|
|
reiserfs_key_get_oid (key) == REISERFS_ROOT_OBJECTID &&
|
|
is_lost_found (name, namelen) ? ET_LOST_FOUND : 0,
|
|
&relocated_ih);
|
|
|
|
if (!fsck_quiet(fs)) {
|
|
util_misc_erase_name (fsck_progress_file(fs),
|
|
namelen);
|
|
}
|
|
|
|
switch (retval1) {
|
|
case OK:
|
|
dir_size += REISERFS_DEH_SIZE + entry_len;
|
|
break;
|
|
|
|
case STAT_DATA_NOT_FOUND:
|
|
case DIRECTORY_HAS_NO_ITEMS:
|
|
if (reiserfs_key_get_off (&entry_key) == OFFSET_DOT_DOT &&
|
|
reiserfs_key_get_oid (&object_key) ==
|
|
REISERFS_ROOT_PARENT_OBJECTID)
|
|
{
|
|
/* ".." of root directory can not be found */
|
|
dir_size += REISERFS_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_tree_delete_entry (fs, &entry_key);
|
|
sem_pass_stat (fs)->deleted_entries ++;
|
|
break;
|
|
|
|
case RELOCATED:
|
|
/* file was relocated, update key in directory entry */
|
|
|
|
if (reiserfs_tree_search_entry (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 */
|
|
reiserfs_deh_t * tmp_deh;
|
|
|
|
tmp_deh = reiserfs_deh (REISERFS_PATH_LEAF (&path),
|
|
REISERFS_PATH_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);
|
|
|
|
reiserfs_deh_set_did (tmp_deh, reiserfs_key_get_did (&relocated_ih.ih_key));
|
|
reiserfs_deh_set_obid (tmp_deh,
|
|
reiserfs_key_get_oid (&relocated_ih.ih_key));
|
|
|
|
fsck_log ("%K\n", &tmp_deh->deh2_dir_id);
|
|
reiserfs_buffer_mkdirty (REISERFS_PATH_LEAF (&path));
|
|
}
|
|
|
|
dir_size += REISERFS_DEH_SIZE + entry_len;
|
|
reiserfs_tree_pathrelse (&path);
|
|
break;
|
|
}
|
|
} /* for */
|
|
|
|
misc_freemem (dir_item);
|
|
|
|
if (reiserfs_key_comp2 (&item_key, key) || !reiserfs_key_dir(&item_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 = REISERFS_DIR_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 ? REISERFS_SD_SIZE_MAX_V2 :
|
|
REISERFS_SD_SIZE_MAX_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 SD again */
|
|
if (reiserfs_tree_search_item (fs, key, &path) != ITEM_FOUND)
|
|
reiserfs_panic ("rebuild_semantic_pass: The StatData of the "
|
|
"file %K was not found", key);
|
|
|
|
bh = REISERFS_PATH_LEAF (&path);
|
|
ih = REISERFS_PATH_IH (&path);
|
|
sd = REISERFS_PATH_ITEM (&path);
|
|
|
|
reiserfs_stat_set_size (ih, sd, &dir_size);
|
|
reiserfs_stat_set_blocks (ih, sd, &blocks);
|
|
reiserfs_buffer_mkdirty (bh);
|
|
reiserfs_tree_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) */
|
|
reiserfs_sd_v1_t * 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) */
|
|
reiserfs_sd_v1_t * sd_v1 = sd;
|
|
|
|
return !(S_ISREG (le16_to_cpu (sd_v1->sd_mode)));
|
|
}
|
|
|
|
|
|
|
|
void zero_nlink (reiserfs_ih_t * ih, void * sd)
|
|
{
|
|
int zero = 0;
|
|
|
|
if (reiserfs_ih_get_len (ih) == REISERFS_SD_SIZE_V1 && reiserfs_ih_get_format (ih) !=
|
|
KEY_FORMAT_1)
|
|
{
|
|
fsck_log ("zero_nlink: The StatData %k of the wrong format version "
|
|
"(%d) - corrected to (%d)\n", ih, reiserfs_ih_get_format (ih),
|
|
KEY_FORMAT_1);
|
|
|
|
reiserfs_ih_set_format (ih, KEY_FORMAT_1);
|
|
}
|
|
|
|
if (reiserfs_ih_get_len (ih) == REISERFS_SD_SIZE && reiserfs_ih_get_format (ih) !=
|
|
KEY_FORMAT_2)
|
|
{
|
|
fsck_log ("zero_nlink: The StatData %k of the wrong format version "
|
|
"(%d) - corrected to (%d)\n", ih, reiserfs_ih_get_format (ih),
|
|
KEY_FORMAT_2);
|
|
|
|
reiserfs_ih_set_format (ih, KEY_FORMAT_2);
|
|
}
|
|
|
|
reiserfs_stat_set_nlink (ih, sd, &zero);
|
|
}
|
|
|
|
/* mkreiserfs should have created this */
|
|
static void make_sure_lost_found_exists (reiserfs_filsys_t * fs,
|
|
__u16 root_format)
|
|
{
|
|
int retval;
|
|
REISERFS_PATH_INIT (path);
|
|
unsigned int gen_counter;
|
|
__u32 objectid;
|
|
__u64 sd_size;
|
|
__u32 sd_blocks;
|
|
reiserfs_bh_t * bh;
|
|
reiserfs_ih_t * ih;
|
|
void * sd;
|
|
int item_len;
|
|
int entry_len;
|
|
|
|
|
|
/* look for "lost+found" in the root directory */
|
|
retval = reiserfs_tree_search_name (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;
|
|
}
|
|
reiserfs_key_set_did (&lost_found_dir_key, REISERFS_ROOT_OBJECTID);
|
|
reiserfs_key_set_oid (&lost_found_dir_key, objectid);
|
|
}
|
|
|
|
|
|
/* look for stat data of "lost+found" */
|
|
retval = reiserfs_tree_search_item (fs, &lost_found_dir_key, &path);
|
|
if (retval == ITEM_NOT_FOUND) {
|
|
fs->lost_format = reiserfs_tree_create_stat
|
|
(fs, &path, &lost_found_dir_key, cb_item_modify);
|
|
} else {
|
|
reiserfs_ih_t * ih = REISERFS_PATH_IH (&path);
|
|
|
|
if (!reiserfs_ih_stat (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 (REISERFS_PATH_ITEM (&path))) {
|
|
fsck_progress ("\"/lost+found\" exists, but it is not a "
|
|
"directory, lost files will not be linked\n");
|
|
reiserfs_key_set_oid (&lost_found_dir_key, 0);
|
|
reiserfs_tree_pathrelse (&path);
|
|
return;
|
|
}
|
|
|
|
fs->lost_format = (reiserfs_ih_get_len (REISERFS_PATH_IH (&path)) ==
|
|
REISERFS_SD_SIZE) ? KEY_FORMAT_2 : KEY_FORMAT_1;
|
|
|
|
reiserfs_tree_pathrelse (&path);
|
|
}
|
|
|
|
/* add "." and ".." if any of them do not exist */
|
|
entry_len = reiserfs_direntry_entry_estimate (".", fs->lost_format);
|
|
reiserfs_tree_insert_entry (fs, &lost_found_dir_key, ".", entry_len,
|
|
&lost_found_dir_key, 1 << IH_Unreachable);
|
|
|
|
entry_len = reiserfs_direntry_entry_estimate ("..", fs->lost_format);
|
|
reiserfs_tree_insert_entry (fs, &lost_found_dir_key, "..", entry_len,
|
|
&root_dir_key, 1 << IH_Unreachable);
|
|
|
|
entry_len = reiserfs_direntry_entry_estimate ("lost+found", root_format);
|
|
item_len = reiserfs_tree_insert_entry (fs, &root_dir_key, "lost+found",
|
|
entry_len, &lost_found_dir_key,
|
|
1 << IH_Unreachable);
|
|
|
|
if (item_len) {
|
|
if (reiserfs_tree_search_item (fs, &root_dir_key, &path) ==
|
|
ITEM_NOT_FOUND)
|
|
{
|
|
reiserfs_panic ("%s: StatData of the root directory must exists",
|
|
__FUNCTION__);
|
|
}
|
|
|
|
bh = REISERFS_PATH_LEAF (&path);
|
|
ih = REISERFS_PATH_IH (&path);
|
|
sd = REISERFS_PATH_ITEM(&path);
|
|
|
|
reiserfs_stat_get_size (ih, sd, &sd_size);
|
|
sd_size += item_len;
|
|
reiserfs_stat_set_size (ih, sd, &sd_size);
|
|
sd_blocks = REISERFS_DIR_BLOCKS (sd_size);
|
|
reiserfs_stat_set_blocks (ih, sd, &sd_blocks);
|
|
reiserfs_buffer_mkdirty (bh);
|
|
reiserfs_tree_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 fsck_semantic_save_result (reiserfs_filsys_t * fs) {
|
|
FILE * file;
|
|
int retval;
|
|
|
|
file = util_file_open ("temp_fsck_file.deleteme", "w+");
|
|
if (!file)
|
|
return;
|
|
|
|
fsck_stage_start_put (file, SEMANTIC_DONE);
|
|
reiserfs_objectid_map_save (file, semantic_id_map (fs));
|
|
fsck_stage_end_put (file);
|
|
fclose (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 fsck_semantic_load_result (FILE * file, reiserfs_filsys_t * fs) {
|
|
unsigned int gen_counter;
|
|
REISERFS_PATH_INIT(path);
|
|
|
|
fsck_new_bitmap (fs) = reiserfs_bitmap_create
|
|
(reiserfs_sb_get_blocks (fs->fs_ondisk_sb));
|
|
|
|
reiserfs_bitmap_copy (fsck_new_bitmap (fs), fs->fs_bitmap2);
|
|
|
|
fsck_allocable_bitmap (fs) = reiserfs_bitmap_create
|
|
(reiserfs_sb_get_blocks (fs->fs_ondisk_sb));
|
|
|
|
reiserfs_bitmap_copy (fsck_allocable_bitmap (fs), fs->fs_bitmap2);
|
|
|
|
fs->block_allocator = reiserfsck_new_blocknrs;
|
|
fs->block_deallocator = reiserfsck_free_block;
|
|
|
|
/* we need objectid map on semantic pass to be able to relocate files */
|
|
proper_id_map (fs) = id_map_init();
|
|
|
|
fetch_objectid_map (proper_id_map (fs), fs);
|
|
semantic_id_map (fs) = reiserfs_objectid_map_load (file);
|
|
|
|
/* get the lost_found key. */
|
|
if (!(reiserfs_tree_search_name (fs, &root_dir_key,
|
|
"lost+found", &gen_counter,
|
|
&lost_found_dir_key)))
|
|
{
|
|
reiserfs_panic("Lost&found entry cannot be found in the root dir.");
|
|
}
|
|
|
|
if (reiserfs_tree_search_item (fs, &lost_found_dir_key,
|
|
&path) == ITEM_NOT_FOUND)
|
|
{
|
|
reiserfs_panic("Lost&found StatData item cannot be found.");
|
|
}
|
|
|
|
fs->lost_format = (reiserfs_ih_get_len (REISERFS_PATH_IH (&path)) ==
|
|
REISERFS_SD_SIZE) ? KEY_FORMAT_2 : KEY_FORMAT_1;
|
|
reiserfs_tree_pathrelse (&path);
|
|
}
|
|
|
|
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 */
|
|
reiserfs_sb_set_state (fs->fs_ondisk_sb, SEMANTIC_DONE);
|
|
reiserfs_buffer_mkdirty (fs->fs_super_bh);
|
|
|
|
/* write all dirty blocks */
|
|
fsck_progress ("Flushing..");
|
|
id_map_flush(proper_id_map (fs), fs);
|
|
fs->fs_dirt = 1;
|
|
reiserfs_bitmap_flush (fsck_new_bitmap(fs), fs);
|
|
reiserfs_fs_flush (fs);
|
|
fsck_progress ("finished\n");
|
|
|
|
fsck_stage_report (FS_SEMANTIC, fs);
|
|
|
|
if (!fsck_run_one_step (fs)) {
|
|
if (fsck_info_ask (fs, "Continue? (Yes):", "Yes\n", 1))
|
|
/* reiserfsck continues */
|
|
return;
|
|
}
|
|
|
|
fsck_semantic_save_result (fs);
|
|
|
|
id_map_free(proper_id_map (fs));
|
|
proper_id_map (fs) = 0;
|
|
|
|
fs->fs_dirt = 1;
|
|
reiserfs_fs_close (fs);
|
|
exit(0);
|
|
}
|
|
|
|
/* this is part of rebuild tree */
|
|
void fsck_semantic (reiserfs_filsys_t * fs) {
|
|
__u16 root_format;
|
|
|
|
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->hash)
|
|
reiserfs_panic ("Hash function should be selected already");
|
|
|
|
root_format = reiserfs_tree_root (fs, cb_item_modify, 1 << IH_Unreachable);
|
|
make_sure_lost_found_exists (fs, root_format);
|
|
|
|
id_map_mark(proper_id_map(fs), reiserfs_key_get_oid(&root_dir_key));
|
|
id_map_mark(proper_id_map(fs), reiserfs_key_get_oid(&lost_found_dir_key));
|
|
|
|
/* link all relocated files into /lost+found directory */
|
|
fsck_relocate_link_all();
|
|
|
|
rebuild_semantic_pass ((reiserfs_key_t *)&root_dir_key,
|
|
&parent_root_dir_key, ET_NAME, 0/*reloc_ih*/);
|
|
|
|
if (!fsck_quiet(fs))
|
|
util_misc_fini_name(fsck_progress_file(fs));
|
|
|
|
reiserfs_badblock_flush(fs, 1);
|
|
|
|
after_pass_3 (fs);
|
|
}
|