📄 pass2.c
字号:
/* * Copyright 1996-2004 by Hans Reiser, licensing governed by * reiserfsprogs/README */#include "fsck.h"/* on pass2 we take leaves which could not be inserted into tree during pass1 and insert each item separately. It is possible that items of different objects with the same key can be found. We treat that in the following way: we put it into tree with new key and link it into /lost+found directory with name made of dir,oid. When coming item is a directory - we delete object from the tree, put it back with different key, link it to /lost+found directory and insert directory as it is *//* 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;static __u32 get_relocated_objectid_from_list (struct key * key) { struct relocated *cur = relocated_list; while (cur) { if (cur->old_dir_id == get_key_dirid (key) && cur->old_objectid == get_key_objectid (key)) /* object is relocated already */ return cur->new_objectid; cur = cur->next; } return 0;}/* return objectid the object has to be remapped with */__u32 objectid_for_relocation (struct key * key){ struct relocated * cur; __u32 cur_id; if ((cur_id = get_relocated_objectid_from_list (key)) != 0) return cur_id; cur = getmem (sizeof (struct relocated)); cur->old_dir_id = get_key_dirid (key); cur->old_objectid = get_key_objectid (key); cur->new_objectid = id_map_alloc(proper_id_map(fs)); cur->next = relocated_list; relocated_list = cur;/* fsck_log ("relocation: (%K) is relocated to (%lu, %lu)\n", key, get_key_dirid (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; struct key obj_key; __u64 len = 0; asprintf (&name, "%lu,%lu", file->old_dir_id, file->new_objectid); set_key_dirid (&obj_key, file->old_dir_id); set_key_objectid (&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 */ len = reiserfs_add_entry (fs, &lost_found_dir_key, name, name_length(name, lost_found_dir_format), &obj_key, 0/*fsck_need*/); pass_2_stat (fs)->relocated ++; free (name); return len;}void linked_already(struct key *new_key /*, link_func_t link_func*/) { struct relocated *cur = relocated_list; struct relocated *prev = NULL; while (cur) { if (cur->old_dir_id == get_key_dirid(new_key) && cur->new_objectid == get_key_objectid(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; freemem (cur); }}void link_relocated_files (void){ struct relocated * tmp; int count; count = 0; while (relocated_list) { link_one (relocated_list); tmp = relocated_list; relocated_list = relocated_list->next; freemem (tmp); count ++; }}/* this item is in tree. All unformatted pointer are correct. Do not check them */void save_item (struct si ** head, struct item_head * ih, char * item, __u32 blocknr){ struct si * si, * cur; si = getmem (sizeof (*si)); si->si_dnm_data = getmem (get_ih_item_len(ih)); /*si->si_blocknr = blocknr;*/ memcpy (&(si->si_ih), ih, IH_SIZE); memcpy (si->si_dnm_data, item, get_ih_item_len(ih)); if (*head == 0) *head = si; else { cur = *head; while (cur->si_next) cur = cur->si_next; cur->si_next = si; } return;}struct si * save_and_delete_file_item (struct si * si, struct path * path){ struct buffer_head * bh = PATH_PLAST_BUFFER (path); struct item_head * ih = PATH_PITEM_HEAD (path); save_item (&si, ih, B_I_PITEM (bh, ih), bh->b_blocknr); /* delete item temporary - do not free unformatted nodes */ reiserfsck_delete_item (path, 1/*temporary*/); return si;}/* check whether there are any directory items with this key */int should_relocate (struct item_head * ih){ struct key key; struct key * rkey; struct path path; struct item_head * path_ih; /* starting with the leftmost item with this key */ key = ih->ih_key; set_type_and_offset (KEY_FORMAT_1, &key, SD_OFFSET, TYPE_STAT_DATA); 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 with this key */ pathrelse (&path); break; } 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; } if (is_stat_data_ih (path_ih)) { fix_obviously_wrong_sd_mode (&path); if (ih_checked (path_ih)) { /* we have checked it already */ pathrelse (&path); if (get_relocated_objectid_from_list (&path_ih->ih_key)) return 1; /* it was relocated */ break; } else { mark_ih_checked (path_ih); mark_buffer_dirty (get_bh(&path)); } } /* 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_direntry_ih (path_ih))) { /* item of directory found. so, we have to relocate the file */ pathrelse (&path); return 1; } key = path_ih->ih_key; set_offset (KEY_FORMAT_1, &key, get_offset (&key) + 1); pathrelse (&path); } return 0;}/* this works for both new and old stat data */#define st_mode(sd) le16_to_cpu(((struct stat_data *)(sd))->sd_mode)#define st_mtime_v1(sd) le32_to_cpu(((struct stat_data_v1 *)(sd))->sd_mtime)#define st_mtime_v2(sd) le32_to_cpu(((struct stat_data *)(sd))->sd_mtime)/* either both sd-s are new of both are old */static void overwrite_stat_data (struct item_head * new_ih, void * new_item, struct path * path){ __u16 new_mode, old_mode; get_sd_mode (new_ih, new_item, &new_mode); get_sd_mode (get_ih (path), get_item (path), &old_mode); if (S_ISREG (new_mode) && !S_ISREG (old_mode)) { /* in tree we have not regular file - overwrite its stat data with stat data of regular file */ memcpy (get_item (path), new_item, get_ih_item_len (get_ih (path))); mark_buffer_dirty (get_bh (path)); return; } if (S_ISREG (old_mode) && !S_ISREG (new_mode)) { /* new stat data is not a stat data of regular file, keep regular file stat data in tree */ return; } /* if coming stat data has newer mtime - use that */ if (stat_data_v1 (new_ih)) { if (st_mtime_v1 (new_item) > st_mtime_v1 (get_item (path))) { memcpy (get_item (path), new_item, SD_V1_SIZE); mark_buffer_dirty (get_bh (path)); } } else { if (st_mtime_v2 (new_item) > st_mtime_v2 (get_item (path))) { memcpy (get_item (path), new_item, SD_SIZE); mark_buffer_dirty (get_bh (path)); } } return;}/* insert sd item if it does not exist, overwrite it otherwise */static void put_sd_into_tree (struct item_head * new_ih, char * new_item){ struct path path; if (!not_a_directory (new_item)) { /* new item is a stat data of a directory. So we have to relocate all items which have the same short key and are of not a directory */ rewrite_file (new_ih, 1, 0/*do not change new_ih*/); } else { /* new item is a stat data of something else but directory. If there are items of directory - we have to relocate the file */ if (should_relocate (new_ih)) rewrite_file (new_ih, 1, 1/*change new_ih*/); } /* if we will have to insert item into tree - it is ready */ zero_nlink (new_ih, new_item); mark_item_unreachable (new_ih); /* we are sure now that if we are inserting stat data of a directory - there are no items with the same key which are not items of a directory, and that if we are inserting stat data is of not a directory - it either has new key already or there are no items with this key which are items of a directory */ if (reiserfs_search_by_key_4 (fs, &(new_ih->ih_key), &path) == ITEM_FOUND) { /* this stat data is found */ if (get_ih_key_format (get_ih(&path)) != get_ih_key_format (new_ih)) { /* in tree stat data and a new one are of different formats */ fsck_log ("put_sd_into_tree: Inserting the StatData %K, mode (%M)...", &(new_ih->ih_key), st_mode (new_item)); if (stat_data_v1 (new_ih)) { /* sd to be inserted is of V1, where as sd in the tree is of V2 */ fsck_log ("found newer in the tree, mode (%M), insersion was skipped.\n", st_mode (get_item (&path))); pathrelse (&path); } else { /* the stat data in the tree is sd_v1 */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -