213 lines
5.7 KiB
C
213 lines
5.7 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"
|
|
|
|
/* relocation rules: we have an item (it is taken from "non-insertable"
|
|
leaf). It has original key yet. We check to see if object with this
|
|
key is remapped. Object can be only remapped if it is not a piece
|
|
of directory */
|
|
|
|
/* in list of this structures we store what has been relocated. */
|
|
struct relocated {
|
|
unsigned long old_dir_id;
|
|
unsigned long old_objectid;
|
|
|
|
unsigned long new_objectid;
|
|
|
|
struct relocated * next;
|
|
};
|
|
|
|
/* all relocated files will be linked into lost+found directory at the
|
|
beginning of semantic pass */
|
|
static struct relocated * relocated_list = NULL;
|
|
|
|
__u32 fsck_relocate_get_oid (reiserfs_key_t * key) {
|
|
struct relocated *cur = relocated_list;
|
|
|
|
while (cur) {
|
|
if (cur->old_dir_id == reiserfs_key_get_did (key) &&
|
|
cur->old_objectid == reiserfs_key_get_oid (key))
|
|
/* object is relocated already */
|
|
return cur->new_objectid;
|
|
cur = cur->next;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* return objectid the object has to be remapped with */
|
|
__u32 fsck_relocate_oid(reiserfs_key_t * key) {
|
|
struct relocated * cur;
|
|
__u32 cur_id;
|
|
|
|
if ((cur_id = fsck_relocate_get_oid (key)) != 0)
|
|
return cur_id;
|
|
|
|
cur = misc_getmem (sizeof (struct relocated));
|
|
cur->old_dir_id = reiserfs_key_get_did (key);
|
|
cur->old_objectid = reiserfs_key_get_oid (key);
|
|
cur->new_objectid = id_map_alloc(proper_id_map(fs));
|
|
cur->next = relocated_list;
|
|
relocated_list = cur;
|
|
pass_2_stat (fs)->relocated ++;
|
|
/*
|
|
fsck_log ("relocation: %K is relocated to [%lu, %lu]\n",
|
|
key, reiserfs_key_get_did (key), cur->new_objectid);
|
|
*/
|
|
return cur->new_objectid;
|
|
}
|
|
|
|
/* relocated files get added into lost+found with slightly different names */
|
|
static __u64 link_one (struct relocated * file) {
|
|
char name[REISERFS_NAME_MAX];
|
|
reiserfs_key_t obj_key;
|
|
__u64 len = 0;
|
|
int entry_len;
|
|
|
|
name[0] = '\0';
|
|
sprintf(name, "%lu,%lu", file->old_dir_id, file->new_objectid);
|
|
reiserfs_key_set_did (&obj_key, file->old_dir_id);
|
|
reiserfs_key_set_oid (&obj_key, file->new_objectid);
|
|
|
|
/* 0 for fsck_need does not mean too much - it would make effect if there
|
|
* were no this directory yet. But /lost_found is there already */
|
|
entry_len = reiserfs_direntry_entry_estimate(name, fs->lost_format);
|
|
len = reiserfs_tree_insert_entry (fs, &lost_found_dir_key, name, entry_len,
|
|
&obj_key, 0/*fsck_need*/);
|
|
return len;
|
|
}
|
|
|
|
void fsck_relocate_mklinked(reiserfs_key_t *new_key) {
|
|
struct relocated *cur = relocated_list;
|
|
struct relocated *prev = NULL;
|
|
|
|
while (cur) {
|
|
if (cur->old_dir_id == reiserfs_key_get_did(new_key) &&
|
|
cur->new_objectid == reiserfs_key_get_oid(new_key))
|
|
break;
|
|
|
|
prev = cur;
|
|
cur = cur->next;
|
|
}
|
|
|
|
if (cur) {
|
|
/* len = link_func(cur); */
|
|
|
|
if (prev)
|
|
prev->next = cur->next;
|
|
else
|
|
relocated_list = cur->next;
|
|
|
|
misc_freemem (cur);
|
|
}
|
|
}
|
|
|
|
void fsck_relocate_link_all (void) {
|
|
struct relocated * tmp;
|
|
|
|
while (relocated_list) {
|
|
link_one (relocated_list);
|
|
tmp = relocated_list;
|
|
relocated_list = relocated_list->next;
|
|
misc_freemem (tmp);
|
|
}
|
|
}
|
|
|
|
/* check whether there are any directory items with this key
|
|
Returns:
|
|
0 is relocation is not needed;
|
|
1 is the whole file relocation is needed;
|
|
2 if a new item only relocation is needed.
|
|
*/
|
|
__u32 fsck_relocate_check (reiserfs_ih_t * ih, int isdir) {
|
|
const reiserfs_key_t * rkey;
|
|
reiserfs_ih_t * path_ih;
|
|
reiserfs_path_t path;
|
|
reiserfs_key_t key;
|
|
int found_dir;
|
|
|
|
/* starting with the leftmost item with this key */
|
|
key = ih->ih_key;
|
|
reiserfs_key_set_sec (KEY_FORMAT_1, &key, OFFSET_SD, TYPE_STAT_DATA);
|
|
|
|
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 with this key */
|
|
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;
|
|
}
|
|
|
|
found_dir = reiserfs_dir(path_ih, REISERFS_PATH_ITEM (&path));
|
|
|
|
if (reiserfs_ih_stat (path_ih)) {
|
|
if (reiserfs_ih_ischeck (path_ih)) {
|
|
/* we have checked it already */
|
|
reiserfs_tree_pathrelse (&path);
|
|
|
|
if ((found_dir && isdir) || (!found_dir && !isdir)) {
|
|
/* If the item being inserted and the found one are
|
|
both either directory ones of not directory ones,
|
|
no relocation is needed. */
|
|
return 0;
|
|
}
|
|
|
|
/* If new one is a dirrectory one, relocate file in the tree. */
|
|
if (isdir) return 1;
|
|
|
|
/* If new one is file and there is a directory in the tree, return
|
|
id for the relocation, allocate it if needed. */
|
|
return fsck_relocate_oid (&path_ih->ih_key);
|
|
} else {
|
|
reiserfs_ih_mkcheck (path_ih);
|
|
reiserfs_buffer_mkdirty (REISERFS_PATH_LEAF(&path));
|
|
}
|
|
}
|
|
|
|
reiserfs_tree_pathrelse (&path);
|
|
|
|
if (isdir) {
|
|
/* If directory, force relocate as it costs nothing for
|
|
the directory, and do not spend time on this check. */
|
|
return 1;
|
|
}
|
|
|
|
/* ok, item found, but make sure that it is not a directory one */
|
|
if (found_dir) {
|
|
/* item of directory found. so, we have to relocate the file */
|
|
return 1;
|
|
}
|
|
|
|
key = path_ih->ih_key;
|
|
reiserfs_key_set_off (KEY_FORMAT_1, &key,
|
|
reiserfs_key_get_off (&key) + 1);
|
|
}
|
|
|
|
return 0;
|
|
}
|