/* * Copyright 1996-2004 by Hans Reiser, licensing governed by reiserfsprogs/README */ #include "fsck.h" static struct reiserfs_key *trunc_links = NULL; static __u32 links_num = 0; int wrong_mode(const struct reiserfs_key *key, __u16 * mode, __u64 real_size, int symlink); int wrong_st_blocks(const struct reiserfs_key *key, __u32 * blocks, __u32 sd_blocks, __u16 mode, int new_format); int wrong_st_size(const struct reiserfs_key *key, unsigned long long max_file_size, int blocksize, __u64 * size, __u64 sd_size, int type); int wrong_first_direct_byte(const struct reiserfs_key *key, int blocksize, __u32 * first_direct_byte, __u32 sd_first_direct_byte, __u32 size); void get_object_key(struct reiserfs_de_head *deh, struct reiserfs_key *key, struct reiserfs_key *entry_key, struct item_head *ih); void print_name(char *name, int len); void erase_name(int len); struct reiserfs_path_key { struct short_key { __u32 k_dir_id; __u32 k_objectid; } key; struct reiserfs_path_key *next, *prev; }; static struct reiserfs_path_key *head_key = NULL; static struct reiserfs_path_key *tail_key = NULL; static int check_path_key(const struct reiserfs_key *key) { struct reiserfs_path_key *cur = head_key; while (cur != NULL) { if (!comp_short_keys(&cur->key, key)) { fsck_log ("\nsemantic check: The directory %k has 2 names.", key); return LOOP_FOUND; } cur = cur->next; } return 0; } static int add_path_key(const struct reiserfs_key *key) { if (check_path_key(key)) return LOOP_FOUND; if (tail_key == NULL) { tail_key = getmem(sizeof(struct reiserfs_path_key)); head_key = tail_key; tail_key->prev = NULL; } else { tail_key->next = getmem(sizeof(struct reiserfs_path_key)); tail_key->next->prev = tail_key; tail_key = tail_key->next; } copy_short_key(&tail_key->key, key); tail_key->next = NULL; return 0; } static void del_path_key(void) { if (tail_key == NULL) die("Wrong path_key structure"); if (tail_key->prev == NULL) { freemem(tail_key); tail_key = head_key = NULL; } else { tail_key = tail_key->prev; freemem(tail_key->next); tail_key->next = NULL; } } /* path is path to stat data. If file will be relocated - new_ih will contain a key file was relocated with */ static int check_check_regular_file(struct reiserfs_path *path, void *sd, struct item_head *new_ih) { int is_new_file; // struct reiserfs_key key, sd_key; __u16 mode; __u32 nlink; __u64 real_size, sd_size; __u32 blocks, sd_blocks; /* proper values and value in stat data */ __u32 first_direct_byte, sd_first_direct_byte; struct item_head *ih, sd_ih; int fix_sd; int symlnk = 0; int retval = OK; __u32 tmp_position; ih = tp_item_head(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); one_less_corruption(fs, FIXABLE); 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 ("check_check_regular_file: Could not find a StatData of " "the relocated file %K", &new_ih->ih_key); /* stat data is marked unreachable again due to relocation, fix that */ ih = tp_item_head(path); sd = tp_item_body(path); } if (get_ih_item_len(ih) == SD_SIZE) is_new_file = 1; else is_new_file = 0; get_sd_nlink(ih, sd, &nlink); get_sd_mode(ih, sd, &mode); get_sd_size(ih, sd, &sd_size); get_sd_blocks(ih, sd, &sd_blocks); /* if (fsck_mode (fs) == FSCK_FIX_FIXABLE) { // check and set nlink first nlink ++; set_sd_nlink (ih, sd, &nlink); mark_buffer_dirty (bh); if (nlink > 1) return OK; } */ if (!is_new_file) get_sd_first_direct_byte(ih, sd, &sd_first_direct_byte); if (S_ISLNK(mode)) symlnk = 1; sd_ih = *ih; // sd_key = sd_ih.ih_key; pathrelse(path); if (are_file_items_correct (&sd_ih, sd, &real_size, &blocks, 0 /* do not mark reachable */ , &symlnk) != 1) { one_more_corruption(fs, FATAL); fsck_log ("check_regular_file: The file %K with the corrupted structure found\n", &sd_ih.ih_key); } else { fix_sd = 0; fix_sd += wrong_mode(&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, sd_first_direct_byte, real_size); if (reiserfs_bin_search (&sd_ih.ih_key, trunc_links, links_num, sizeof(sd_ih.ih_key), &tmp_position, comp_short_keys) != POSITION_FOUND) { fix_sd += wrong_st_size(&sd_ih.ih_key, is_new_file ? MAX_FILE_SIZE_V2 : MAX_FILE_SIZE_V1, fs->fs_blocksize, &real_size, sd_size, symlnk ? TYPE_SYMLINK : 0); } else { real_size = sd_size; } fix_sd += wrong_st_blocks(&sd_ih.ih_key, &blocks, sd_blocks, mode, is_new_file); if (fix_sd) { if (fsck_mode(fs) == FSCK_FIX_FIXABLE) { struct buffer_head *bh; /* 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) { fsck_log ("check_regular_file: A StatData of the file %K cannot be " "found\n", &sd_ih.ih_key); one_more_corruption(fs, FATAL); return STAT_DATA_NOT_FOUND; } bh = get_bh(path); ih = tp_item_head(path); sd = tp_item_body(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); } else { fsck_check_stat(fs)->fixable_corruptions += fix_sd; } } } return retval; } /* 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 */ const struct reiserfs_key *parent, struct item_head *ih, __u32 * pos_in_item, int dir_format) { INITIALIZE_REISERFS_PATH(path); char *dir_item; struct reiserfs_key *rdkey; struct buffer_head *bh; struct reiserfs_de_head *deh; int i; int retval; start_again: retval = reiserfs_search_by_entry_key(fs, key, &path); if (retval != POSITION_FOUND && get_offset(key) != DOT_OFFSET) 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 = *tp_item_head(&path); deh = B_I_DEH(bh, ih); /* position was not found for '.' or there is no '..' */ if (retval != POSITION_FOUND || ((get_offset(key) == DOT_OFFSET) && (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 %s %k cannot be found in %k", (retval == POSITION_NOT_FOUND) ? "entry" : "directory", key, &ih->ih_key); if (fsck_mode(fs) == FSCK_FIX_FIXABLE) { /* add "." and ".." exist */ pathrelse(&path); reiserfs_add_entry(fs, key, ".", name_length(".", dir_format), key, 0); reiserfs_add_entry(fs, key, "..", name_length("..", dir_format), parent, 0); fsck_log(" - entry was added\n"); goto start_again; } else { one_more_corruption(fs, FIXABLE); fsck_log("\n"); if (retval == DIRECTORY_NOT_FOUND) return NULL; } } /* 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: \"..\" not found in %H\n", ih); 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)) // handled in check_tree 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); if (fsck_mode(fs) == FSCK_FIX_FIXABLE) { set_deh_dirid(deh, get_key_dirid(key)); set_deh_objectid(deh, get_key_objectid(key)); mark_buffer_dirty(bh); fsck_log(" - corrected\n"); } else { one_more_corruption(fs, FIXABLE); fsck_log("\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))); if (fsck_mode(fs) == FSCK_FIX_FIXABLE) { set_deh_dirid(deh, get_key_dirid(parent)); set_deh_objectid(deh, get_key_objectid (parent)); mark_buffer_dirty(bh); fsck_log(" - corrected\n"); } else { one_more_corruption(fs, FIXABLE); fsck_log("\n"); } } } } /* copy directory item to the temporary buffer */ dir_item = getmem(get_ih_item_len(ih)); memcpy(dir_item, ih_item_body(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(tp_item_head(&path), bh); pathrelse(&path); return dir_item; } /* semantic pass of --check */ static int check_semantic_pass(struct reiserfs_key *key, const struct reiserfs_key *parent, int dot_dot, struct item_head *new_ih) { struct reiserfs_path path; void *sd; __u32 nlink; int is_new_dir; struct buffer_head *bh; struct item_head *ih; int retval; char *dir_item; __u32 pos_in_item; struct item_head tmp_ih; struct reiserfs_key next_item_key, entry_key, object_key; __u64 dir_size = 0; __u32 blocks; __u64 sd_size; __u32 sd_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)) { fsck_log ("check_semantic_pass: The key %k must be key of a StatData\n", key); one_more_corruption(fs, FATAL); return STAT_DATA_NOT_FOUND; } /* look for stat data of an object */ if (reiserfs_search_by_key_4(fs, key, &path) == ITEM_NOT_FOUND) { pathrelse(&path); return STAT_DATA_NOT_FOUND; } /* stat data has been found */ ih = tp_item_head(&path); sd = tp_item_body(&path); get_sd_nlink(ih, sd, &nlink); /* It seems quite difficult to relocate objects on fix-fixable - * rewrite_file calls reiserfs_file_write which can convert tails * to unfm, plus unreachable, was_tail flags, etc. */ #if 0 if (( /* relocate = */ should_be_relocated(&ih->ih_key))) { /* if (fsck_mode(fs) == FSCK_CHECK) relocate = 0; */ one_more_corruption(fs, FATAL); } #endif if (fix_obviously_wrong_sd_mode(&path)) { one_more_corruption(fs, FIXABLE); pathrelse(&path); return OK; } if (nlink == 0) { fsck_log ("%s: block %lu: The StatData %k has bad nlink number (%u)\n", __FUNCTION__, get_bh(&path)->b_blocknr, &ih->ih_key, nlink); one_more_corruption(fs, FATAL); } if (not_a_directory(sd)) { fsck_check_stat(fs)->files++; retval = check_check_regular_file(&path, sd, /* relocate ? new_ih : */ NULL); pathrelse(&path); return retval; } /* if (relocate) { if (!new_ih) reiserfs_panic ("check_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); one_less_corruption (fs, FIXABLE); *key = new_ih->ih_key; retval = RELOCATED; goto start_again; } */ /* if (fsck_mode (fs) == FSCK_FIX_FIXABLE) { // 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 (get_bh (&path)); pathrelse (&path); return OK; } } // do not run it for dot_dot on check at all nlink = 2; if (get_key_objectid (key) == REISERFS_ROOT_OBJECTID) nlink ++; set_sd_nlink (ih, sd, &nlink); mark_buffer_dirty (get_bh (&path)); } */ /* directory stat data found */ if (get_ih_item_len(ih) == SD_SIZE) is_new_dir = 1; else is_new_dir = 0; /* save stat data's size and st_blocks */ get_sd_size(ih, sd, &sd_size); get_sd_blocks(ih, sd, &sd_blocks); get_sd_mode(ih, sd, &mode); dir_format = (get_ih_item_len(tp_item_head(&path)) == SD_SIZE) ? KEY_FORMAT_2 : KEY_FORMAT_1; /* release path pointing to stat data */ pathrelse(&path); fsck_check_stat(fs)->dirs++; set_key_dirid(&next_item_key, get_key_dirid(key)); set_key_objectid(&next_item_key, get_key_objectid(key)); set_key_offset_v1(&next_item_key, DOT_OFFSET); set_key_uniqueness(&next_item_key, DIRENTRY_UNIQUENESS); dir_size = 0; while ((dir_item = get_next_directory_item(&next_item_key, parent, &tmp_ih, &pos_in_item, dir_format)) != NULL) { /* 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 = NULL; 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; int ret = OK; if (name) { free(name); name = NULL; } 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 */ if (fsck_mode(fs) == FSCK_FIX_FIXABLE) { 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); } else { fsck_log ("Entry %K (\"%.*s\") in the directory %K is not formated " "properly.\n", (struct reiserfs_key *)&(deh-> deh2_dir_id), namelen, name, &tmp_ih.ih_key); one_more_corruption(fs, FIXABLE); } } print_name(name, namelen); if (!is_properly_hashed (fs, name, namelen, get_deh_offset(deh))) { one_more_corruption(fs, FATAL); fsck_log ("check_semantic_pass: Hash mismatch detected for (%.*s) in " "directory %K\n", namelen, name, &tmp_ih.ih_key); } if (is_dot(name, namelen) || (is_dot_dot(name, namelen))) { /* do not go through "." and ".." */ ret = OK; } else { if ((ret = add_path_key(&object_key)) == 0) { ret = check_semantic_pass(&object_key, key, is_dot_dot(name, namelen), &relocated_ih); del_path_key(); } } erase_name(namelen); /* check what check_semantic_tree returned */ switch (ret) { case OK: dir_size += DEH_SIZE + entry_len; break; case STAT_DATA_NOT_FOUND: fsck_log ("check_semantic_pass: Name \"%.*s\" in directory %K points to " "nowhere\n", namelen, name, &tmp_ih.ih_key); case LOOP_FOUND: if (fsck_mode(fs) == FSCK_FIX_FIXABLE) { reiserfs_remove_entry(fs, &entry_key); fsck_log(" - removed"); } else { one_more_corruption(fs, FIXABLE); } fsck_log("\n"); break; case DIRECTORY_HAS_NO_ITEMS: fsck_log ("check_semantic_pass: Name \"%.*s\" in directory %K points a " "directory without body\n", namelen, name, &tmp_ih.ih_key); /* fixme: stat data should be deleted as well */ /* if (fsck_fix_fixable (fs)) { reiserfs_remove_entry (fs, &entry_key); fsck_data(fs)->deleted_entries ++; fsck_log (" - removed"); } fsck_log ("\n"); */ 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 ("Cannot find a name of the relocated file %K in the directory " "%K\n", &entry_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), tp_item_head(&path)) + path.pos_in_item; fsck_log ("The directory %K pointing to %K (\"%.*s\") updated to point " "to ", &tmp_ih.ih_key, &tmp_deh->deh2_dir_id, namelen, name); 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 (\"%.*s\")\n", &tmp_deh->deh2_dir_id, namelen, name); mark_buffer_dirty(get_bh(&path)); } dir_size += DEH_SIZE + entry_len; pathrelse(&path); break; } } /* for */ freemem(dir_item); free(name); name = NULL; if (not_of_one_file(&next_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, sd_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, sd_size, TYPE_DIRENTRY); if (fix_sd) { if (fsck_mode(fs) == FSCK_FIX_FIXABLE) { /* 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) { fsck_log ("check_semantic_tree: The StatData of the file %K was not found\n", key); one_more_corruption(fs, FATAL); return STAT_DATA_NOT_FOUND; } bh = get_bh(&path); ih = tp_item_head(&path); sd = tp_item_body(&path); set_sd_size(ih, sd, &dir_size); set_sd_blocks(ih, sd, &blocks); mark_buffer_dirty(bh); pathrelse(&path); } else { fsck_check_stat(fs)->fixable_corruptions += fix_sd; } } return retval; } static int check_safe_links(void) { struct reiserfs_path safe_link_path, path; struct reiserfs_key safe_link_key = { cpu_to_le32(-1), 0, {{0, 0}} }; struct reiserfs_key key = { 0, 0, {{0, 0}} }; struct reiserfs_key *rkey; struct item_head *tmp_ih; while (1) { if (get_key_dirid(&safe_link_key) == 0) break; reiserfs_search_by_key_4(fs, &safe_link_key, &safe_link_path); if (get_blkh_nr_items(B_BLK_HEAD(get_bh(&safe_link_path))) <= PATH_LAST_POSITION(&safe_link_path)) { pathrelse(&safe_link_path); break; } tmp_ih = tp_item_head(&safe_link_path); if (get_key_dirid(&tmp_ih->ih_key) != (__u32) - 1 || get_key_objectid(&tmp_ih->ih_key) == (__u32) - 1) { pathrelse(&safe_link_path); break; } if (get_ih_item_len(tmp_ih) != 4) reiserfs_panic("Safe Link %k cannot be of the size %d", &tmp_ih->ih_key, get_ih_item_len(tmp_ih)); set_key_dirid(&key, d32_get((__le32 *) tp_item_body(&safe_link_path), 0)); set_key_objectid(&key, get_key_objectid(&tmp_ih->ih_key)); if ((rkey = reiserfs_next_key(&safe_link_path)) == NULL) set_key_dirid(&safe_link_key, 0); else safe_link_key = *rkey; if (reiserfs_search_by_key_4(fs, &key, &path) == ITEM_NOT_FOUND) { /*sware on check, delete on fix-fixable */ if (fsck_mode(fs) == FSCK_CHECK) { fsck_log ("Invalid safe link %k: cannot find the pointed object (%K)\n", &tmp_ih->ih_key, &key); one_more_corruption(fs, FIXABLE); } else if (fsck_mode(fs) == FSCK_FIX_FIXABLE) { fsck_log ("Invalid safe link %k: cannot find the pointed object (%K) - " "safe link was deleted\n", &tmp_ih->ih_key, &key); d32_put((__le32 *) tp_item_body(&safe_link_path), 0, 0); pathrelse(&path); reiserfsck_delete_item(&safe_link_path, 0); continue; } } else if (get_offset(&tmp_ih->ih_key) == 0x1) { /* Truncate */ if (!not_a_directory(tp_item_body(&path))) { /*truncate on directory should not happen */ /*sware on check, delete on fix-fixable */ if (fsck_mode(fs) == FSCK_CHECK) { fsck_log ("Invalid 'truncate' safe link %k, cannot happen for " "directory (%K)\n", &tmp_ih->ih_key, &key); one_more_corruption(fs, FIXABLE); } else if (fsck_mode(fs) == FSCK_FIX_FIXABLE) { fsck_log ("Invalid 'truncate' safe link %k, cannot happen for " "a directory (%K) - safe link was deleted\n", &tmp_ih->ih_key, &key); d32_put((__le32 *) tp_item_body(&safe_link_path), 0, 0); pathrelse(&path); reiserfsck_delete_item(&safe_link_path, 0); continue; } } else { /* save 'safe truncate links' to avoid swaring on wrong sizes. */ __u32 position; if (reiserfs_bin_search (&key, trunc_links, links_num, sizeof(key), &position, comp_short_keys) != POSITION_FOUND) { blocklist__insert_in_position(&key, (void *) &trunc_links, &links_num, sizeof (key), &position); } } } pathrelse(&path); pathrelse(&safe_link_path); } return OK; } static void release_safe_links(void) { freemem(trunc_links); } /* called when --check is given */ void semantic_check(void) { if (fsck_data(fs)->check.bad_nodes) { fsck_progress("Bad nodes were found, Semantic pass skipped\n"); goto clean; } if (fsck_data(fs)->check.fatal_corruptions) { fsck_progress ("Fatal corruptions were found, Semantic pass skipped\n"); goto clean; } fsck_progress("Checking Semantic tree:\n"); if (fsck_mode(fs) == FSCK_FIX_FIXABLE) { /*create new_bitmap, and initialize new_bitmap & allocable bitmap */ 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; } check_safe_links(); if (check_semantic_pass(&root_dir_key, &parent_root_dir_key, 0, NULL) != OK) { fsck_log("check_semantic_tree: No root directory found"); one_more_corruption(fs, FATAL); } release_safe_links(); if (fsck_mode(fs) == FSCK_FIX_FIXABLE) { reiserfs_delete_bitmap(fs->fs_bitmap2); reiserfs_bitmap_delta(fsck_new_bitmap(fs), fsck_deallocate_bitmap(fs)); fs->fs_bitmap2 = fsck_new_bitmap(fs); reiserfs_delete_bitmap(fsck_allocable_bitmap(fs)); fsck_allocable_bitmap(fs) = NULL; set_sb_free_blocks(fs->fs_ondisk_sb, reiserfs_bitmap_zeros(fs->fs_bitmap2)); mark_buffer_dirty(fs->fs_super_bh); add_badblock_list(fs, 1); } fsck_progress("finished\n"); clean: if (fsck_deallocate_bitmap(fs)) reiserfs_delete_bitmap(fsck_deallocate_bitmap(fs)); }