summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorrobi <robi>2011-04-25 16:31:51 +0000
committerrobi <robi>2011-04-25 16:31:51 +0000
commit062b2e06421dfca976edd8ef5d2f18756be095bf (patch)
tree1cad1ca69f6b2a8090a832b05d2eb00091c21c8d /src
parentfc9a751d28b4484e6d12c6bae3560030675158dc (diff)
new: disaster recovery
Diffstat (limited to 'src')
-rw-r--r--src/ext4magic.c69
-rw-r--r--src/imap_search.c74
-rw-r--r--src/journal.c106
-rw-r--r--src/util.c1
-rw-r--r--src/util.h2
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 = &current_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);
diff --git a/src/util.c b/src/util.c
index 21fcecd..1431db0 100644
--- a/src/util.c
+++ b/src/util.c
@@ -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 ;
}
diff --git a/src/util.h b/src/util.h
index 2052491..2979a94 100644
--- a/src/util.h
+++ b/src/util.h
@@ -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