static int process_block(ext2_filsys fs, blk_t *block_nr, e2_blkcnt_t blockcnt, blk_t ref_block, int ref_offset, void *priv_data) { struct process_block_struct *pb; errcode_t retval; int ret; blk_t block, orig; pb = (struct process_block_struct *) priv_data; block = orig = *block_nr; ret = 0; /* * Let's see if this is one which we need to relocate */ if (ext2fs_test_block_bitmap(pb->reserve, block)) { do { if (++block >= fs->super->s_blocks_count) block = fs->super->s_first_data_block; if (block == orig) { pb->error = EXT2_ET_BLOCK_ALLOC_FAIL; return BLOCK_ABORT; } } while (ext2fs_test_block_bitmap(pb->reserve, block) || ext2fs_test_block_bitmap(pb->alloc_map, block)); retval = io_channel_read_blk(fs->io, orig, 1, pb->buf); if (retval) { pb->error = retval; return BLOCK_ABORT; } retval = io_channel_write_blk(fs->io, block, 1, pb->buf); if (retval) { pb->error = retval; return BLOCK_ABORT; } *block_nr = block; ext2fs_mark_block_bitmap(pb->alloc_map, block); ret = BLOCK_CHANGED; if (pb->flags & EXT2_BMOVE_DEBUG) printf("ino=%ld, blockcnt=%lld, %u->%u\n", pb->ino, blockcnt, orig, block); } if (pb->add_dir) { retval = ext2fs_add_dir_block(fs->dblist, pb->ino, block, (int) blockcnt); if (retval) { pb->error = retval; ret |= BLOCK_ABORT; } } return ret; }
// Subfunction for "local_block_iterate3()" for check if blocks not allocated and not recovered static int check_block_stat(ext2_filsys fs, blk64_t *blocknr, e2_blkcnt_t blockcnt, blk64_t /*ref_blk*/x, int /*ref_offset*/y, void *priv ) { //FIXME: if (*blocknr >= fs->super->s_blocks_count) return BLOCK_ERROR; struct alloc_recover_stat *stat = priv; if ( ext2fs_test_block_bitmap (fs->block_map, *blocknr )) (stat->allocated)++ ; if ((bmap) && ( ext2fs_test_block_bitmap (bmap, *blocknr ))) (stat->recovered)++ ; return 0; }
void do_dump_unused(int argc EXT2FS_ATTR((unused)), char **argv) { unsigned long blk; unsigned char buf[EXT2_MAX_BLOCK_SIZE]; unsigned int i; errcode_t retval; if (common_args_process(argc, argv, 1, 1, "dump_unused", "", 0)) return; for (blk=current_fs->super->s_first_data_block; blk < current_fs->super->s_blocks_count; blk++) { if (ext2fs_test_block_bitmap(current_fs->block_map,blk)) continue; retval = io_channel_read_blk(current_fs->io, blk, 1, buf); if (retval) { com_err(argv[0], retval, "While reading block\n"); return; } for (i=0; i < current_fs->blocksize; i++) if (buf[i]) break; if (i >= current_fs->blocksize) continue; printf("\nUnused block %lu contains non-zero data:\n\n", blk); for (i=0; i < current_fs->blocksize; i++) fputc(buf[i], stdout); } }
//Subfunction for "local_block_iterate3()" read a blocks of a long symlink static int read_syslink_block ( ext2_filsys fs, blk64_t *blocknr, e2_blkcnt_t blockcnt, blk64_t /*ref_blk*/x, int /*ref_offset*/y, void *priv ) { char *charbuf =((struct privat*)priv)->buf; // __u32 nbytes; errcode_t retval; // int blocksize = fs->blocksize; if (*blocknr >= fs->super->s_blocks_count) return BLOCK_ERROR; if (((struct privat*)priv)->flag){ int allocated = ext2fs_test_block_bitmap ( fs->block_map, *blocknr ); if ( allocated ){ ((struct privat*)priv)->error = 1; // fprintf(stderr,"Block %10lu is allocated.\n",*blocknr); return (BLOCK_ABORT | BLOCK_ERROR); } } retval = io_channel_read_blk ( fs->io, *blocknr, 1, charbuf ); if (retval){ ((struct privat*)priv)->error = retval; return (BLOCK_ERROR); } if (bmap) ext2fs_mark_generic_bitmap(bmap, *blocknr); return 0; }
int empty_pass1(ext2_filsys fs, blk_t *block_nr, e2_blkcnt_t blockcnt, blk_t ref_block, int ref_offset, void *priv_data) { empty_dir_info edi = (empty_dir_info) priv_data; blk_t block, new_block; errcode_t retval; if (blockcnt < 0) return 0; block = *block_nr; do { retval = ext2fs_bmap(fs, edi->ino, &edi->inode, edi->block_buf, 0, edi->logblk, &new_block); if (retval) return DIRENT_ABORT; if (new_block == 0) break; edi->logblk++; } while (ext2fs_test_block_bitmap(edi->empty_dir_blocks, new_block)); if (new_block == block) return 0; if (new_block == 0) edi->freed_blocks++; *block_nr = new_block; return BLOCK_CHANGED; }
//Subfunction for "local_block_iterate3()" for load the first blocks to identify filetype int first_blocks ( ext2_filsys fs, blk64_t *blocknr, e2_blkcnt_t blockcnt, blk64_t /*ref_blk*/x, int /*ref_offset*/y, void *priv ) { char *charbuf = NULL; errcode_t retval; int blocksize = fs->blocksize; if ((blockcnt >= 12) || ((struct privat*)priv)->count >=12) return BLOCK_ABORT; charbuf = (char*)((struct privat*)priv)->buf + (blocksize * blockcnt); if (((struct privat*)priv)->flag){ int allocated = ext2fs_test_block_bitmap ( fs->block_map, *blocknr ); if ( allocated ){ ((struct privat*)priv)->error = BLOCK_ABORT | BLOCK_ERROR ; return (BLOCK_ABORT | BLOCK_ERROR); } } retval = io_channel_read_blk ( fs->io, *blocknr, 1, charbuf ); ((struct privat*)priv)->count = blockcnt; if (retval){ ((struct privat*)priv)->error = BLOCK_ERROR ; return (BLOCK_ERROR); } return retval; }
//Subfunction for "local_block_iterate3()" for recover the blocks of a real file static int write_block ( ext2_filsys fs, blk64_t *blocknr, e2_blkcnt_t blockcnt, blk64_t /*ref_blk*/x, int /*ref_offset*/y, void *priv ) { int fd = ((struct privat*)priv)->fd; char *charbuf =((struct privat*)priv)->buf; __u32 nbytes; errcode_t retval; int blocksize = fs->blocksize; if (*blocknr >= fs->super->s_blocks_count) return BLOCK_ERROR; #ifdef DEBUG printf("%c",(ext2fs_test_block_bitmap ( fs->block_map, *blocknr ))? 'X' : 'O'); #endif if (((struct privat*)priv)->flag){ int allocated = ext2fs_test_block_bitmap ( fs->block_map, *blocknr ); if ( allocated ){ // fprintf(stderr,"Block %10lu is allocated.\n",*blocknr); ((struct privat*)priv)->error = BLOCK_ABORT | BLOCK_ERROR ; return (BLOCK_ABORT | BLOCK_ERROR); } } retval = io_channel_read_blk ( fs->io, *blocknr, 1, charbuf ); if (retval){ ((struct privat*)priv)->error = BLOCK_ERROR ; return (BLOCK_ERROR); } if (bmap) ext2fs_mark_generic_bitmap(bmap, *blocknr); lseek(fd,(unsigned long long )blocksize * blockcnt, SEEK_SET); nbytes = write(fd, charbuf, blocksize); if ((unsigned) nbytes != blocksize){ fprintf(stderr, "Error while writing file\n"); ((struct privat*)priv)->error = BLOCK_ERROR ; return 8; } return retval; }
static int set_bad_block_proc(ext2_filsys fs, blk_t *block_nr, e2_blkcnt_t blockcnt, blk_t ref_block EXT2FS_ATTR((unused)), int ref_offset EXT2FS_ATTR((unused)), void *priv_data) { struct set_badblock_record *rec = (struct set_badblock_record *) priv_data; errcode_t retval; blk_t blk; if (blockcnt >= 0) { /* * Get the next bad block. */ if (!ext2fs_badblocks_list_iterate(rec->bb_iter, &blk)) return BLOCK_ABORT; rec->bad_block_count++; } else { /* * An indirect block; fetch a block from the * previously used indirect block list. The block * most be not marked as used; if so, get another one. * If we run out of reserved indirect blocks, allocate * a new one. */ retry: if (rec->ind_blocks_ptr < rec->ind_blocks_size) { blk = rec->ind_blocks[rec->ind_blocks_ptr++]; if (ext2fs_test_block_bitmap(fs->block_map, blk)) goto retry; } else { retval = ext2fs_new_block(fs, 0, 0, &blk); if (retval) { rec->err = retval; return BLOCK_ABORT; } } retval = io_channel_write_blk(fs->io, blk, 1, rec->block_buf); if (retval) { rec->err = retval; return BLOCK_ABORT; } } /* * Update block counts */ ext2fs_block_alloc_stats(fs, blk, +1); *block_nr = blk; return BLOCK_CHANGED; }
// Subfunction for "local_block_iterate3()" for check if the blocks allocated static int check_block(ext2_filsys fs, blk64_t *blocknr, e2_blkcnt_t blockcnt, blk64_t /*ref_blk*/x, int /*ref_offset*/y, void *priv ) { //FIXME: if (*blocknr >= fs->super->s_blocks_count) return BLOCK_ERROR; struct alloc_stat *stat = priv; if ( ext2fs_test_block_bitmap ( fs->block_map, *blocknr )) (stat->allocated)++ ; else (stat->not_allocated)++ ; if (bmap) ext2fs_mark_generic_bitmap(bmap, *blocknr); return 0; }
/* * Verify the touched map */ static void check_map(void) { int i, j, first=1; unsigned long blk; for (i=0; test_vec[i]; i++) { if (ext2fs_test_block_bitmap(touched_map, test_vec[i])) { printf("Bad block was touched --- %u\n", test_vec[i]); failed++; first_no_comma = 1; } ext2fs_mark_block_bitmap(touched_map, test_vec[i]); } for (i = 0; i < test_fs->group_desc_count; i++) { for (j=0, blk = test_fs->group_desc[i].bg_inode_table; j < test_fs->inode_blocks_per_group; j++, blk++) { if (!ext2fs_test_block_bitmap(touched_map, blk) && !ext2fs_test_block_bitmap(bad_block_map, blk)) { printf("Missing block --- %lu\n", blk); failed++; } } } printf("Bad inodes: "); for (i=1; i <= test_fs->super->s_inodes_count; i++) { if (ext2fs_test_inode_bitmap(bad_inode_map, i)) { if (first) first = 0; else printf(", "); printf("%u", i); } } printf("\n"); }
static void check_block_end(e2fsck_t ctx) { ext2_filsys fs = ctx->fs; blk_t end, save_blocks_count, i; struct problem_context pctx; clear_problem_context(&pctx); end = fs->block_map->start + (EXT2_BLOCKS_PER_GROUP(fs->super) * fs->group_desc_count) - 1; pctx.errcode = ext2fs_fudge_block_bitmap_end(fs->block_map, end, &save_blocks_count); if (pctx.errcode) { pctx.num = 3; fix_problem(ctx, PR_5_FUDGE_BITMAP_ERROR, &pctx); ctx->flags |= E2F_FLAG_ABORT; /* fatal */ return; } if (save_blocks_count == end) return; /* Protect loop from wrap-around if end is maxed */ for (i = save_blocks_count + 1; i <= end && i > save_blocks_count; i++) { if (!ext2fs_test_block_bitmap(fs->block_map, i)) { if (fix_problem(ctx, PR_5_BLOCK_BMAP_PADDING, &pctx)) { for (i = save_blocks_count + 1; i <= end; i++) ext2fs_mark_block_bitmap(fs->block_map, i); ext2fs_mark_bb_dirty(fs); } else ext2fs_unmark_valid(fs); break; } } pctx.errcode = ext2fs_fudge_block_bitmap_end(fs->block_map, save_blocks_count, 0); if (pctx.errcode) { pctx.num = 4; fix_problem(ctx, PR_5_FUDGE_BITMAP_ERROR, &pctx); ctx->flags |= E2F_FLAG_ABORT; /* fatal */ return; } }
static void test_read_blk(unsigned long block, int count, errcode_t err) { int i; if (first_no_comma) first_no_comma = 0; else printf(", "); if (count > 1) printf("%lu-%lu", block, block+count-1); else printf("%lu", block); for (i=0; i < count; i++, block++) { if (ext2fs_test_block_bitmap(touched_map, block)) { printf("\nDuplicate block?!? --- %lu\n", block); failed++; first_no_comma = 1; } ext2fs_mark_block_bitmap(touched_map, block); } }
errcode_t ext2fs_check_desc(ext2_filsys fs) { ext2fs_block_bitmap bmap; errcode_t retval; dgrp_t i; blk_t first_block = fs->super->s_first_data_block; blk_t last_block = fs->super->s_blocks_count-1; blk_t blk, b; int j; EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); retval = ext2fs_allocate_block_bitmap(fs, "check_desc map", &bmap); if (retval) return retval; for (i = 0; i < fs->group_desc_count; i++) ext2fs_reserve_super_and_bgd(fs, i, bmap); for (i = 0; i < fs->group_desc_count; i++) { if (!EXT2_HAS_INCOMPAT_FEATURE(fs->super, EXT4_FEATURE_INCOMPAT_FLEX_BG)) { first_block = ext2fs_group_first_block(fs, i); last_block = ext2fs_group_last_block(fs, i); if (i == (fs->group_desc_count - 1)) last_block = fs->super->s_blocks_count-1; } blk = fs->group_desc[i].bg_block_bitmap; if (blk < first_block || blk > last_block || ext2fs_test_block_bitmap(bmap, blk)) { retval = EXT2_ET_GDESC_BAD_BLOCK_MAP; goto errout; } ext2fs_mark_block_bitmap(bmap, blk); blk = fs->group_desc[i].bg_inode_bitmap; if (blk < first_block || blk > last_block || ext2fs_test_block_bitmap(bmap, blk)) { retval = EXT2_ET_GDESC_BAD_INODE_MAP; goto errout; } ext2fs_mark_block_bitmap(bmap, blk); blk = fs->group_desc[i].bg_inode_table; if (blk < first_block || ((blk + fs->inode_blocks_per_group - 1) > last_block)) { retval = EXT2_ET_GDESC_BAD_INODE_TABLE; goto errout; } for (j = 0, b = blk; j < fs->inode_blocks_per_group; j++, b++) { if (ext2fs_test_block_bitmap(bmap, b)) { retval = EXT2_ET_GDESC_BAD_INODE_TABLE; goto errout; } ext2fs_mark_block_bitmap(bmap, b); } } errout: ext2fs_free_block_bitmap(bmap); return retval; }
// search inode by use imap (step1: flag 1 = only directory ; step2: flag 0 = only file) static void search_imap_inode(char* des_dir, __u32 t_after, __u32 t_before, int flag) { struct ext2_group_desc *gdp; struct ext2_inode_large *inode; //struct dir_list_head_t *dir = NULL; struct ring_buf* i_list = NULL; r_item* item = NULL; int zero_flag, retval, load, x ,i ; char *pathname = NULL; char *i_pathname = NULL; char *buf= NULL; unsigned char *tmp_buf = NULL; __u32 blocksize, inodesize, inode_max, inode_per_group, block_count; __u32 inode_per_block , inode_block_group, group; blk_t block_nr; __u32 c_time, d_time, mode; ext2_ino_t first_block_inode_nr , inode_nr; pathname = malloc(26); blocksize = current_fs->blocksize; inodesize = current_fs->super->s_inode_size; inode_max = current_fs->super->s_inodes_count; inode_per_group = current_fs->super->s_inodes_per_group; buf = malloc(blocksize); if (! (flag & 0x01) ){ tmp_buf = malloc (12 * blocksize); if (!tmp_buf) goto errout; cookie = magic_open(MAGIC_MIME | MAGIC_NO_CHECK_COMPRESS | MAGIC_NO_CHECK_ELF | MAGIC_CONTINUE); if ((! cookie) || magic_load(cookie, NULL)){ fprintf(stderr,"ERROR: can't find libmagic\n"); goto errout; } } inode_per_block = blocksize / inodesize; inode_block_group = inode_per_group / inode_per_block; for (group = 0 ; group < current_fs->group_desc_count ; group++){ #ifdef EXT2_FLAG_64BITS gdp = ext2fs_group_desc(current_fs, current_fs->group_desc, group); #else gdp = ¤t_fs->group_desc[group]; #endif zero_flag = 0; if (!(flag & 0x02)){ //skip this in disaster mode // NEXT GROUP IF INODE NOT INIT if (gdp->bg_flags & (EXT2_BG_INODE_UNINIT)) continue; // SET ZERO-FLAG IF FREE INODES == INODE/GROUP for fast ext3 if (gdp->bg_free_inodes_count == inode_per_group) zero_flag = 1; } //FIXME for struct ext4_group_desc 48/64BIT for (block_nr = gdp->bg_inode_table , block_count = 0 ; block_nr < (gdp->bg_inode_table + inode_block_group); block_nr++, block_count++) { if (!(flag & 0x02)){ //skip this in disaster mode // break if the first block only zero inode if ((block_count ==1) && (zero_flag == (inode_per_block + 1))) break; } //FIXME inode_max ???? first_block_inode_nr = (group * inode_per_group) + (block_count * inode_per_block) + 1; load = 0; for (i = 0; i<inode_per_block;i++){ if ( ! ext2fs_test_block_bitmap(imap,first_block_inode_nr + i)){ load++; break; } } if (load){ retval = read_block ( current_fs , &block_nr , buf); if (retval) return; for (inode_nr = first_block_inode_nr ,x = 0; x < inode_per_block ; inode_nr++ , x++){ if ( ! ext2fs_test_block_bitmap(imap,inode_nr)){ inode = (struct ext2_inode_large*) (buf + (x*inodesize)); c_time = ext2fs_le32_to_cpu(inode->i_ctime); mode = ext2fs_le32_to_cpu(inode->i_mode); if ( ! ( flag & 0x02)) { //no check this inode in disaster mode if ((! c_time ) && (!(inode->i_mode & LINUX_S_IFMT)) ) { if(zero_flag) zero_flag++ ; continue; } d_time = ext2fs_le32_to_cpu(inode->i_dtime); if ( (! d_time) || d_time <= t_after){ ext2fs_mark_generic_bitmap(imap,inode_nr); continue; } } // 1. magical step if (LINUX_S_ISDIR(mode) && ( flag & 0x01) && (pathname)){ sprintf(pathname,"<%lu>",(long unsigned int)inode_nr); struct dir_list_head_t * dir = NULL; if (flag & 0x02){ //disaster mode //only search for undeleted entry dir = get_dir3(NULL,0, inode_nr , "MAGIC-1",pathname, t_after,t_before, 0); if (dir) { lookup_local(des_dir, dir,t_after,t_before, RECOV_ALL | LOST_DIR_SEARCH ); clear_dir_list(dir); } } else{ //search for all dir = get_dir3(NULL,0, inode_nr , "MAGIC-1",pathname, t_after,t_before, DELETED_OPT); if (dir) { lookup_local(des_dir,dir,t_after,t_before,DELETED_OPT|RECOV_ALL|LOST_DIR_SEARCH); clear_dir_list(dir); } } } // 2. magical step if (! (flag & 0x01) ){ i_list = get_j_inode_list(current_fs->super, inode_nr); item = get_undel_inode(i_list,t_after,t_before); ext2fs_mark_generic_bitmap(imap,inode_nr); if (item) { if (! LINUX_S_ISDIR(item->inode->i_mode) ) { i_pathname = identify_filename(i_pathname, tmp_buf, (struct ext2_inode*)item->inode, inode_nr); sprintf(pathname,"<%lu>",(long unsigned int)inode_nr); recover_file(des_dir,"MAGIC-2", ((i_pathname)?i_pathname : pathname), (struct ext2_inode*)item->inode, inode_nr, 0); if(i_pathname){ free(i_pathname); i_pathname = NULL; } } } if (i_list) ring_del(i_list); } } } } } } errout: if (pathname) free(pathname); if(buf) { free(buf); buf = NULL; } if (tmp_buf){ free(tmp_buf); tmp_buf = NULL; } if (cookie){ magic_close(cookie); cookie = 0; } return; }