diff options
author | robi <robi> | 2011-04-25 16:31:51 +0000 |
---|---|---|
committer | robi <robi> | 2011-04-25 16:31:51 +0000 |
commit | 062b2e06421dfca976edd8ef5d2f18756be095bf (patch) | |
tree | 1cad1ca69f6b2a8090a832b05d2eb00091c21c8d /src | |
parent | fc9a751d28b4484e6d12c6bae3560030675158dc (diff) |
new: disaster recovery
Diffstat (limited to 'src')
-rw-r--r-- | src/ext4magic.c | 69 | ||||
-rw-r--r-- | src/imap_search.c | 74 | ||||
-rw-r--r-- | src/journal.c | 106 | ||||
-rw-r--r-- | src/util.c | 1 | ||||
-rw-r--r-- | src/util.h | 2 |
5 files changed, 191 insertions, 61 deletions
diff --git a/src/ext4magic.c b/src/ext4magic.c index 061490a..f284870 100644 --- a/src/ext4magic.c +++ b/src/ext4magic.c @@ -78,6 +78,9 @@ void print_version ( void ) printf("CPU is little endian.\n"); else printf("CPU is big endian.\n"); +#ifdef EXPERT_MODE + printf("Expert Mode is activ\n"); +#endif } @@ -248,7 +251,7 @@ errout: //subfunction for main void print_modus_error(){ - char message0[] = "Invalide parameter : only input of one modus allowed [ -M | -m | -R | -r | -L | -l | -H ]\n"; + char message0[] = "Invalide parameter : only input of one modus allowed [ -M | -m | -R | -r | -L | -l | -H | D ]\n"; fprintf(stderr,"%s",message0); } @@ -267,6 +270,7 @@ int c; int open_flags = EXT2_FLAG_SOFTSUPP_FEATURES; int exit_status = 0 ; int recovermodus = 0 ; +int disaster = 0; int recoverquality = DELETED_OPT; // default use also delete dir entry char *j_file_name = NULL; char *pathname = NULL; @@ -306,9 +310,9 @@ t_after = t_before - 86400 ; // decode arguments #ifdef EXPERT_MODE -while ((c = getopt (argc, argv, "TJRMLlmrQSxi:t:j:f:Vd:B:b:a:I:Hs:n:c")) != EOF) { +while ((c = getopt (argc, argv, "TJRMLlmrQSxi:t:j:f:Vd:B:b:a:I:Hs:n:cD")) != EOF) { #else -while ((c = getopt (argc, argv, "TJRMLlmrQSxi:t:j:f:Vd:B:b:a:I:H")) != EOF) { +while ((c = getopt (argc, argv, "TJRMLlmrSxi:t:j:f:Vd:B:b:a:I:H")) != EOF) { #endif switch (c) { case 'M': @@ -489,10 +493,6 @@ while ((c = getopt (argc, argv, "TJRMLlmrQSxi:t:j:f:Vd:B:b:a:I:H")) != EOF) { format = 1; break; - case 'Q': - mode |= HIGH_QUALITY; - break; - case 'j': j_file_name = optarg; retval = stat (j_file_name, &filestat); @@ -514,11 +514,28 @@ while ((c = getopt (argc, argv, "TJRMLlmrQSxi:t:j:f:Vd:B:b:a:I:H")) != EOF) { pathname = malloc(512); strcpy(pathname,optarg); break; + #ifdef EXPERT_MODE - case 'c': + case 'Q': + mode |= HIGH_QUALITY; + break; + + case 'c': // use a backup journal inode journal_backup=1; break; + case 'D': // Disaster recovery + if(mode & RECOVER_INODE){ + print_modus_error(); + exitval = EXIT_FAILURE ; + goto errout; + } + mode |= RECOVER_INODE; + mode |= READ_JOURNAL; + recovermodus = RECOV_ALL ; + disaster = 2; + break; + case 's': blocksize = parse_ulong(optarg, argv[0], "block size", 0); @@ -632,14 +649,24 @@ while ((c = getopt (argc, argv, "TJRMLlmrQSxi:t:j:f:Vd:B:b:a:I:H")) != EOF) { //-------------------------------------------------------------------------------------------- // check any parameter an options // check time option -if (mode && magicscan){ - printf("Warning: Activate magic scan function, may be some command line options ignored\n"); - mode &= MASK_MAGIC_SCAN; +if ((mode && magicscan) || disaster){ + printf("Warning: Activate magic-scan or disaster-recovery function, may be some command line options ignored\n"); inode_nr = EXT2_ROOT_INO; t_before = (__u32) now_time; - if ((!(mode & INPUT_TIME)) || (t_after == t_before - 86400)){ - t_after = get_last_delete_time(current_fs); - mode |= INPUT_TIME; + if (disaster){ + t_after = t_before - 60; + printf("Start ext4magic Disaster Recovery\n"); + } + else{ + mode &= MASK_MAGIC_SCAN; + if ((!(mode & INPUT_TIME)) || (t_after == t_before - 86400)){ + t_after = get_last_delete_time(current_fs); + if (! (t_after + 1) ){ + exitval = EXIT_FAILURE ; + goto errout; + } + mode |= INPUT_TIME; + } } } @@ -971,8 +998,8 @@ if ((mode & COMMAND_INODE) && (mode & RECOVER_INODE)) print_coll_list(t_after, t_before, format); //Magic step 1 + 2 +3 if (imap){ - imap_search(des_dir, t_after, t_before); -// I think imap is no longer needed from here, free the allocated memory + imap_search(des_dir, t_after, t_before, disaster ); + // we use imap as a flag for the disaster mode ext2fs_free_inode_bitmap(imap); imap = NULL; if (bmap && (!(current_fs->super->s_feature_incompat & EXT3_FEATURE_INCOMPAT_EXTENTS))) @@ -994,6 +1021,16 @@ if ((mode & COMMAND_INODE) && (mode & RECOVER_INODE)) } else fprintf(stdout,"No undeled inode %u in journal found\n",inode_nr); + +#ifdef EXPERT_MODE + if (disaster && imap){ + // Nothing worked, trying to recover all undeleted files under catastrophic conditions + printf("Force a disaster recovery\n"); + imap_search(des_dir, t_after, t_before, disaster ); + ext2fs_free_inode_bitmap(imap); + imap = NULL; + } +#endif if (i_list) ring_del(i_list); } diff --git a/src/imap_search.c b/src/imap_search.c index 421ec9d..54578a2 100644 --- a/src/imap_search.c +++ b/src/imap_search.c @@ -63,18 +63,23 @@ for (group = 0 ; group < current_fs->group_desc_count ; group++){ gdp = ¤t_fs->group_desc[group]; zero_flag = 0; - // 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; + 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; + } - // 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; @@ -96,32 +101,47 @@ for (group = 0 ; group < current_fs->group_desc_count ; group++){ 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 ((! 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; + 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 ){ + if (LINUX_S_ISDIR(mode) && ( flag & 0x01) ){ sprintf(pathname,"<%lu>",inode_nr); struct dir_list_head_t * dir = NULL; - 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); + 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){ + 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); @@ -181,9 +201,9 @@ if (recovername && dirname){ retval = rename(recovername, dirname); rename_hardlink_path(recovername, dirname); } -//#ifdef DEBUG +#ifdef DEBUG printf("move return: %d : ernno %d : %s -> %s\n",retval, errno, recovername, dirname); -//#endif +#endif } } free(recovername); @@ -195,11 +215,11 @@ return retval; //2 step search for journalinode, will find some lost directory and files -void imap_search(char* des_dir, __u32 t_after, __u32 t_before){ +void imap_search(char* des_dir, __u32 t_after, __u32 t_before , int disaster ){ printf("MAGIC-1 : start lost directory search\n"); - search_imap_inode(des_dir, t_after, t_before, 1); //search for lost fragments of directorys + search_imap_inode(des_dir, t_after, t_before, 1 | disaster ); //search for lost fragments of directorys printf("MAGIC-2 : start lost file search\n"); - search_imap_inode(des_dir, t_after, t_before, 0); //search for lost files + search_imap_inode(des_dir, t_after, t_before, 0 | disaster ); //search for lost files return; } diff --git a/src/journal.c b/src/journal.c index d7c6927..9c5bc79 100644 --- a/src/journal.c +++ b/src/journal.c @@ -42,7 +42,7 @@ #include "util.h" #include "journal.h" -enum journal_location {JOURNAL_IS_INTERNAL, JOURNAL_IS_EXTERNAL}; +enum journal_location {JOURNAL_IS_INTERNAL, JOURNAL_IS_EXTERNAL, JOURNAL_IS_DUMMY}; //flags for journaldescriptor control #define ANY_BLOCK ((blk_t) -1) @@ -57,6 +57,7 @@ struct journal_source enum journal_location where; int fd; ext2_file_t file; + char* j_dummy; }; @@ -140,6 +141,7 @@ static void journal_superblock_to_cpu ( __u32 *jsb ) extern int journal_open( char *journal_file_name, int journal_backup_flag ) { char *journal_dev_name = NULL; + char *dummy_journal = NULL; int journal_fd = 0; ext2_ino_t journal_inum; struct ext2_inode journal_inode; @@ -164,6 +166,7 @@ extern int journal_open( char *journal_file_name, int journal_backup_flag ) journal_source.where = JOURNAL_IS_EXTERNAL; journal_source.fd = journal_fd; journal_source.file = NULL; + journal_source.j_dummy = NULL; printf("Using external Journal at File %s \n",journal_file_name); } else if ((journal_inum = jsb_pointer->s_journal_inum)) { @@ -186,14 +189,65 @@ extern int journal_open( char *journal_file_name, int journal_backup_flag ) retval = ext2fs_file_open2(current_fs, journal_inum, &journal_inode, 0, &journal_file); +#ifdef EXPERT_MODE + if (journal_backup_flag){ + //check the Journal Magic Number + char* jsb_buffer = NULL; + int got; + journal_superblock_t* jsb; + + jsb_buffer = malloc(1024); + journal_source.where = JOURNAL_IS_INTERNAL; + journal_source.file = journal_file; + if ((jsb_buffer) && (! read_journal_block(0,jsb_buffer, 1024, &got))){ + jsb = (journal_superblock_t *) jsb_buffer; + if ((be32_to_cpu(jsb->s_header.h_magic) != JFS_MAGIC_NUMBER) || + (current_fs->blocksize != be32_to_cpu(jsb->s_blocksize))) { + retval = 1; + } + free(jsb_buffer); + } + else return JOURNAL_ERROR ; + } +#endif if (retval) { fprintf(stderr," Error %d while opening journal\n",retval); +#ifdef EXPERT_MODE + if (journal_backup_flag) { + journal_superblock_t *jsb; + +//the journal is defect, create a insubstantial blank journal + dummy_journal = (char*) malloc(current_fs->blocksize * 2); + if (dummy_journal){ + memset (dummy_journal,0,current_fs->blocksize *2); + jsb = (journal_superblock_t*) dummy_journal; + jsb->s_header.h_magic = htonl(JFS_MAGIC_NUMBER); + jsb->s_header.h_blocktype = htonl(JFS_SUPERBLOCK_V2); + jsb->s_blocksize = htonl(current_fs->blocksize); + jsb->s_maxlen = htonl(2); + jsb->s_nr_users = htonl(1); + jsb->s_first = htonl(1); + jsb->s_sequence = htonl(1); + memcpy(jsb->s_uuid, current_fs->super->s_uuid, sizeof(current_fs->super->s_uuid)); + journal_source.where = JOURNAL_IS_DUMMY; + journal_source.file = NULL; + journal_source.fd = -1 ; + journal_source.j_dummy = dummy_journal; + printf("Journal defect, using a dummy Journal\n"); + }else + goto errout; + } + else +#endif goto errout; } - journal_source.where = JOURNAL_IS_INTERNAL; - journal_source.file = journal_file; - journal_source.fd = -1 ; - printf("Using %s internal Journal at Inode %d\n",(journal_backup_flag)?"a recovered":"",journal_inum); + else { + journal_source.where = JOURNAL_IS_INTERNAL; + journal_source.file = journal_file; + journal_source.fd = -1 ; + journal_source.j_dummy = NULL; + printf("Using %s internal Journal at Inode %d\n",(journal_backup_flag)?"a recovered":"",journal_inum); + } } else { char uuid[37]; @@ -236,15 +290,25 @@ extern int journal_close(void) free(pt_buff); pt_buff = NULL; } - - if ((journal_source.where == JOURNAL_IS_INTERNAL) && (journal_source.file)){ - ext2fs_file_close(journal_source.file); - journal_source.file = NULL; - } - else if (journal_source.fd > 0) { - close(journal_source.fd); - journal_source.fd = -1; + switch (journal_source.where){ + case JOURNAL_IS_DUMMY : + if (journal_source.j_dummy){ + free(journal_source.j_dummy); + journal_source.j_dummy = NULL; } + break; + case JOURNAL_IS_INTERNAL : + if (journal_source.file){ + ext2fs_file_close(journal_source.file); + journal_source.file = NULL; + } + break; + case JOURNAL_IS_EXTERNAL : + if (journal_source.fd > 0) { + close(journal_source.fd); + journal_source.fd = -1; + } + } return (JOURNAL_CLOSE); } @@ -273,8 +337,8 @@ int dump_journal_block( __u32 block_nr , int flag){ int read_journal_block(off_t offset, char *buf, int size, unsigned int *got) { int retval; - - if (journal_source.where == JOURNAL_IS_EXTERNAL) { + switch (journal_source.where) { + case JOURNAL_IS_EXTERNAL : if (lseek(journal_source.fd, offset, SEEK_SET) < 0) { retval = errno; fprintf(stderr,"Error %d while seeking in reading journal",retval); @@ -285,14 +349,22 @@ int read_journal_block(off_t offset, char *buf, int size, unsigned int *got) *got = retval; retval = 0; } else retval = errno; - } else { + break; + case JOURNAL_IS_INTERNAL : retval = ext2fs_file_lseek(journal_source.file, offset, EXT2_SEEK_SET, NULL); if (retval) { fprintf(stderr,"Error %d while seeking in reading journal",retval); return retval; } retval = ext2fs_file_read(journal_source.file, buf, size, got); - } + break; + case JOURNAL_IS_DUMMY : + if((offset + size) > (2 *current_fs->blocksize)) retval = -1 ; + memcpy(buf,journal_source.j_dummy + offset,size); + *got = (unsigned int) size; + retval = 0; + break; + } if (retval) fprintf(stderr,"Error %d while reading journal",retval); @@ -340,6 +340,7 @@ if(!flag) first = last; free(buf); buf = NULL; } + if (! first) fprintf(stderr,"Warning: No time window found, because no found a deleted inode\n"); return first - 1 ; } @@ -171,7 +171,7 @@ int check_dir(char*);//check if the target directory existent //public functions imap_search.c -void imap_search(char* , __u32, __u32 ); // search inode by imap (step1 + step2) +void imap_search(char* , __u32, __u32 ,int ); // search inode by imap (step1 + step2) int check_find_dir(char*, ext2_ino_t, char*, char*); //check if the directory always recovert; then move |