Files
reiserfsprogs/utils/fsck/relocate.c
T

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;
}