| author | Christophe Grenier <grenier@cgsecurity.org> | 2010-04-27 06:39:24 (GMT) |
|---|---|---|
| committer | Christophe Grenier <grenier@cgsecurity.org> | 2010-04-27 06:39:24 (GMT) |
| commit | c1afbdf78024f1590b7805244ddc40ba16297379 (patch) | |
| tree | e2f5a9d72e1a59569cfcb21342c5cfaa4419086a | |
| parent | 8ee9f770fa81752c44b9bfc38e04ab88eafeec4a (diff) | |
PhotoRec: modify internals for brute-force recovery
| -rw-r--r-- | src/fat_unformat.c | 3 | ||||
| -rw-r--r-- | src/fidentify.c | 6 | ||||
| -rw-r--r-- | src/filegen.c | 5 | ||||
| -rw-r--r-- | src/filegen.h | 5 | ||||
| -rw-r--r-- | src/phbf.c | 932 | ||||
| -rw-r--r-- | src/phbf.h | 2 | ||||
| -rw-r--r-- | src/phbs.c | 3 | ||||
| -rw-r--r-- | src/photorec.c | 60 | ||||
| -rw-r--r-- | src/phrecn.c | 9 |
9 files changed, 748 insertions, 277 deletions
diff --git a/src/fat_unformat.c b/src/fat_unformat.c index e915ae6..0b39f58 100644 --- a/src/fat_unformat.c +++ b/src/fat_unformat.c @@ -182,9 +182,10 @@ static int fat_unformat_aux(disk_t *disk, partition_t *partition, const int verb const unsigned int read_size=(blocksize>65536?blocksize:65536); alloc_data_t *current_search_space; file_recovery_t file_recovery; + reset_file_recovery(&file_recovery); + file_recovery.blocksize=blocksize; buffer_start=(unsigned char *)MALLOC(READ_SIZE); buffer=buffer_start; - reset_file_recovery(&file_recovery); start_time=time(NULL); previous_time=start_time; current_search_space=td_list_entry(list_search_space->list.prev, alloc_data_t, list); diff --git a/src/fidentify.c b/src/fidentify.c index 42ad9bd..2795455 100644 --- a/src/fidentify.c +++ b/src/fidentify.c @@ -65,11 +65,12 @@ static int file_identify(const char *filename) unsigned int buffer_size; const unsigned int read_size=(blocksize>65536?blocksize:65536); file_recovery_t file_recovery; + reset_file_recovery(&file_recovery); + file_recovery.blocksize=blocksize; buffer_size=blocksize + READ_SIZE; buffer_start=(unsigned char *)MALLOC(buffer_size); buffer_olddata=buffer_start; buffer=buffer_olddata + blocksize; - reset_file_recovery(&file_recovery); file=fopen(filename, "rb"); if(file==NULL) return -1; @@ -81,8 +82,9 @@ static int file_identify(const char *filename) } fclose(file); { - file_recovery_t file_recovery_new; struct td_list_head *tmpl; + file_recovery_t file_recovery_new; + file_recovery_new.blocksize=blocksize; file_recovery_new.file_stat=NULL; td_list_for_each(tmpl, &file_check_list.list) { diff --git a/src/filegen.c b/src/filegen.c index bdd7e10..d90da73 100644 --- a/src/filegen.c +++ b/src/filegen.c @@ -309,6 +309,11 @@ void reset_file_recovery(file_recovery_t *file_recovery) file_recovery->file_rename=NULL; file_recovery->offset_error=0; file_recovery->offset_ok=0; + file_recovery->checkpoint_status=0; + file_recovery->checkpoint_offset=0; +// file_recovery->blocksize=512; + file_recovery->flags=0; + file_recovery->extra=0; } file_stat_t * init_file_stats(file_enable_t *files_enable) diff --git a/src/filegen.h b/src/filegen.h index dc3ba36..1fc1cde 100644 --- a/src/filegen.h +++ b/src/filegen.h @@ -73,6 +73,7 @@ struct file_recovery_struct uint64_t min_filesize; uint64_t offset_ok; uint64_t offset_error; + uint64_t extra; /* extra bytes between offset_ok and offset_error */ uint64_t calculated_file_size; int (*data_check)(const unsigned char*buffer, const unsigned int buffer_size, file_recovery_t *file_recovery); /* data_check returns 0: bad, 1: EOF not found, 2: EOF @@ -80,6 +81,10 @@ struct file_recovery_struct */ void (*file_check)(file_recovery_t *file_recovery); void (*file_rename)(const char *old_filename); + uint64_t checkpoint_offset; + int checkpoint_status; /* 0=suspend at offset_checkpoint if offset_checkpoint>0, 1=resume at offset_checkpoint */ + unsigned int blocksize; + unsigned int flags; }; struct file_hint_struct @@ -68,10 +68,39 @@ #include "phbf.h" #include "phnc.h" +//#define DEBUG_BF +//#define DEBUG_BF2 #define READ_SIZE 1024*512 extern file_check_list_t file_check_list; +extern uint64_t free_list_allocation_end; -static int photorec_bf_aux(disk_t *disk_car, partition_t *partition, const int paranoid, const char *recup_dir, const int interface, file_stat_t *file_stats, unsigned int *file_nbr, file_recovery_t *file_recovery, const unsigned int blocksize, alloc_data_t *list_search_space, alloc_data_t *current_search_space, const time_t real_start_time, unsigned int *dir_num, const photorec_status_t status); +static int photorec_bf_aux(disk_t *disk_car, partition_t *partition, const char *recup_dir, const int interface, file_stat_t *file_stats, unsigned int *file_nbr, file_recovery_t *file_recovery, const unsigned int blocksize, alloc_data_t *list_search_space, alloc_data_t *current_search_space, const time_t real_start_time, unsigned int *dir_num, const photorec_status_t status, const int phase); +static int photorec_bf_frag(disk_t *disk_car, partition_t *partition, const char *recup_dir, const int interface, file_stat_t *file_stats, unsigned int *file_nbr, file_recovery_t *file_recovery, const unsigned int blocksize, alloc_data_t *list_search_space, alloc_data_t *start_search_space, const time_t real_start_time, unsigned int *dir_num, const photorec_status_t status, const int phase, alloc_data_t **current_search_space, uint64_t *offset, unsigned char *buffer, unsigned char *block_buffer, const unsigned int frag); + +#ifdef DEBUG_BF +static void list_space_used(const file_recovery_t *file_recovery, const unsigned int sector_size) +{ + struct td_list_head *tmp; + uint64_t file_size=0; + if(file_recovery->filename==NULL) + return; + log_info("%s\t",file_recovery->filename); + td_list_for_each(tmp, &file_recovery->location.list) + { + const alloc_list_t *element=td_list_entry(tmp, alloc_list_t, list); + if(element->data>0) + { + log_info(" %lu-%lu", (unsigned long)(element->start/sector_size), (unsigned long)(element->end/sector_size)); + file_size+=(element->end-element->start+1); + } + else + { + log_info(" (%lu-%lu)", (unsigned long)(element->start/sector_size), (unsigned long)(element->end/sector_size)); + } + } + log_info("\n"); +} +#endif static inline void file_recovery_cpy(file_recovery_t *dst, file_recovery_t *src) { @@ -100,342 +129,707 @@ static inline void list_append_block(alloc_list_t *list, const uint64_t offset, } } -int photorec_bf(disk_t *disk_car, partition_t *partition, const int verbose, const int paranoid, const char *recup_dir, const int interface, file_stat_t *file_stats, unsigned int *file_nbr, const unsigned int blocksize, alloc_data_t *list_search_space, const time_t real_start_time, unsigned int *dir_num, const photorec_status_t status, const unsigned int pass) +static struct td_list_head *next_file(struct td_list_head *search_walker, alloc_data_t *list_search_space) +{ + struct td_list_head *tmp_walker; + for(tmp_walker=search_walker->next; + tmp_walker!=&list_search_space->list; + tmp_walker=tmp_walker->next) + { + alloc_data_t *tmp; + tmp=td_list_entry(tmp_walker, alloc_data_t, list); + if(tmp->file_stat!=NULL && tmp->file_stat->file_hint!=NULL) + return tmp_walker; + } + return search_walker; +} + +int photorec_bf(disk_t *disk_car, partition_t *partition, const int verbose, const char *recup_dir, const int interface, file_stat_t *file_stats, unsigned int *file_nbr, const unsigned int blocksize, alloc_data_t *list_search_space, const time_t real_start_time, unsigned int *dir_num, const photorec_status_t status, const unsigned int pass) { struct td_list_head *search_walker = NULL; - struct td_list_head *n= NULL; + struct td_list_head *p= NULL; unsigned char *buffer_start; const unsigned int read_size=(blocksize>65536?blocksize:65536); unsigned int buffer_size; int ind_stop=0; int pass2=pass; + int phase; buffer_size=blocksize+READ_SIZE; buffer_start=(unsigned char *)MALLOC(buffer_size); - for(search_walker=list_search_space->list.prev, n=search_walker->prev; - search_walker!=&list_search_space->list && ind_stop==0; - search_walker=n,n=search_walker->prev) + for(phase=0; phase<2; phase++) { - alloc_data_t *current_search_space; - unsigned char *buffer; - unsigned char *buffer_olddata; - uint64_t offset; - int need_to_check_file; - file_recovery_t file_recovery; - current_search_space=td_list_entry(search_walker, alloc_data_t, list); - offset=current_search_space->start; - buffer_olddata=buffer_start; - buffer=buffer_olddata+blocksize; - reset_file_recovery(&file_recovery); - memset(buffer_olddata, 0, blocksize); - disk_car->pread(disk_car, buffer, READ_SIZE, offset); + const unsigned int file_nbr_phase_old=*file_nbr; + for(search_walker=list_search_space->list.prev, p=search_walker->prev; + search_walker!=&list_search_space->list && ind_stop==0; + p=search_walker->prev) + { + alloc_data_t *current_search_space; + unsigned char *buffer; + unsigned char *buffer_olddata; + uint64_t offset; + int need_to_check_file; + int go_backward=1; + file_recovery_t file_recovery; + reset_file_recovery(&file_recovery); + file_recovery.blocksize=blocksize; + current_search_space=td_list_entry(search_walker, alloc_data_t, list); + offset=current_search_space->start; + buffer_olddata=buffer_start; + buffer=buffer_olddata+blocksize; + memset(buffer_olddata, 0, blocksize); + disk_car->pread(disk_car, buffer, READ_SIZE, offset); + info_list_search_space(list_search_space, current_search_space, disk_car->sector_size, 0, verbose); #ifdef DEBUG_BF - info_list_search_space(list_search_space, current_search_space, disk_car->sector_size, 0, verbose); #endif - log_flush(); + log_flush(); - do - { - uint64_t old_offset=offset; - need_to_check_file=0; - if(offset==current_search_space->start) + do { - file_recovery_t file_recovery_new; - struct td_list_head *tmpl; - file_recovery_new.file_stat=NULL; - td_list_for_each(tmpl, &file_check_list.list) + uint64_t old_offset=offset; + need_to_check_file=0; + if(offset==current_search_space->start) { - struct td_list_head *tmp; - const file_check_list_t *pos=td_list_entry(tmpl, file_check_list_t, list); - td_list_for_each(tmp, &pos->file_checks[pos->has_value==0?0:buffer[pos->offset]].list) + struct td_list_head *tmpl; + file_recovery_t file_recovery_new; + file_recovery_new.blocksize=blocksize; + file_recovery_new.file_stat=NULL; + td_list_for_each(tmpl, &file_check_list.list) { - const file_check_t *file_check=td_list_entry(tmp, file_check_t, list); - if((file_check->length==0 || memcmp(buffer + file_check->offset, file_check->value, file_check->length)==0) && - file_check->header_check(buffer, read_size, 0, &file_recovery, &file_recovery_new)!=0) + struct td_list_head *tmp; + const file_check_list_t *pos=td_list_entry(tmpl, file_check_list_t, list); + td_list_for_each(tmp, &pos->file_checks[pos->has_value==0?0:buffer[pos->offset]].list) { - file_recovery_new.file_stat=file_check->file_stat; - break; + const file_check_t *file_check=td_list_entry(tmp, file_check_t, list); + if((file_check->length==0 || memcmp(buffer + file_check->offset, file_check->value, file_check->length)==0) && + file_check->header_check(buffer, read_size, 0, &file_recovery, &file_recovery_new)!=0) + { + file_recovery_new.file_stat=file_check->file_stat; + break; + } } + if(file_recovery_new.file_stat!=NULL) + break; } if(file_recovery_new.file_stat!=NULL) - break; + { + file_recovery_new.location.start=offset; + if(verbose>0) + { + log_info("%s header found at sector %lu\n", + ((file_recovery_new.extension!=NULL && file_recovery_new.extension[0]!='\0')? + file_recovery_new.extension:file_recovery_new.file_stat->file_hint->description), + (unsigned long)((offset-partition->part_offset)/disk_car->sector_size)); + } + if(file_recovery.file_stat==NULL) + { /* Header found => file found */ + file_recovery_cpy(&file_recovery, &file_recovery_new); + } + else if(file_recovery_new.file_stat->file_hint!=NULL) + { + if(verbose>0) + log_verbose("New file found => stop the recovery of current file\n"); + need_to_check_file=1; + } + } + else if(file_recovery.file_stat==NULL) + need_to_check_file=1; /* No header found => no file => stop */ + } + if(file_recovery.file_stat!=NULL && file_recovery.handle==NULL) + { /* Create new file */ + set_filename(&file_recovery, recup_dir, *dir_num, disk_car, partition, 0); + if(file_recovery.file_stat->file_hint->recover==1) + { + if(!(file_recovery.handle=fopen(file_recovery.filename,"w+b"))) + { + log_critical("Cannot create file %s: %s\n", file_recovery.filename, strerror(errno)); + ind_stop=2; + } + } + } + if(need_to_check_file==0 && file_recovery.handle!=NULL) + { + if(file_recovery.handle!=NULL) + { + if(fwrite(buffer,blocksize,1,file_recovery.handle)<1) + { + log_critical("Cannot write to file %s:%s\n", file_recovery.filename, strerror(errno)); + ind_stop=3; + } + } + if(file_recovery.file_stat!=NULL) + { + int res=1; + // log_info("add sector %llu\n", (long long unsigned)(offset/512)); + list_append_block(&file_recovery.location, offset, blocksize,1); + if(file_recovery.data_check!=NULL) + res=file_recovery.data_check(buffer_olddata, 2*blocksize, &file_recovery); + file_recovery.file_size+=blocksize; + file_recovery.file_size_on_disk+=blocksize; + if(res==2) + { /* EOF found */ + need_to_check_file=1; + } + } + if(file_recovery.file_stat!=NULL && file_recovery.file_stat->file_hint->max_filesize>0 && file_recovery.file_size>=file_recovery.file_stat->file_hint->max_filesize) + { + log_verbose("File should not be bigger than %llu, stop adding data\n", + (long long unsigned)file_recovery.file_stat->file_hint->max_filesize); + need_to_check_file=1; + } + } + get_next_sector(list_search_space, ¤t_search_space, &offset, blocksize); + if(current_search_space==list_search_space) + need_to_check_file=1; + if(need_to_check_file==0) + { + buffer_olddata+=blocksize; + buffer+=blocksize; + if(old_offset+blocksize!=offset || buffer+read_size>buffer_start+buffer_size) + { + memcpy(buffer_start, buffer_olddata, blocksize); + buffer_olddata=buffer_start; + buffer=buffer_olddata+blocksize; + if(verbose>1) + { + log_verbose("Reading sector %10lu/%lu\n", + (unsigned long)((offset-partition->part_offset)/disk_car->sector_size), + (unsigned long)((partition->part_size-1)/disk_car->sector_size)); + } + disk_car->pread(disk_car, buffer, READ_SIZE, offset); + } + } + } while(need_to_check_file==0); + if(need_to_check_file==1) + { + uint64_t offset_next_file=0; + struct td_list_head *tmp_walker; + const unsigned int file_nbr_old=*file_nbr; + /* find the offset of the next file */ + for(tmp_walker=search_walker; + tmp_walker!=&list_search_space->list && offset_next_file==0; + tmp_walker=tmp_walker->next) + { + alloc_data_t *tmp; + tmp=td_list_entry(tmp_walker, alloc_data_t, list); + if(tmp->file_stat!=NULL && tmp->file_stat->file_hint!=NULL) + offset_next_file=tmp->start; + } + + file_recovery.flags=1; + if(file_finish(&file_recovery, recup_dir, 2, file_nbr, blocksize, list_search_space, ¤t_search_space, &offset, dir_num, status, disk_car)<0) + { /* BF */ + current_search_space=td_list_entry(search_walker, alloc_data_t, list); + ind_stop=photorec_bf_aux(disk_car, partition, recup_dir, interface, file_stats, file_nbr, &file_recovery, blocksize, list_search_space, current_search_space, real_start_time, dir_num, status, phase); + pass2++; + if(file_nbr_old < *file_nbr && free_list_allocation_end > offset_next_file) + go_backward=0; +#ifdef DEBUG_BF + log_info("file_nbr_old %u, file_nbr=%u\n", file_nbr_old, *file_nbr); + log_info("free_list_allocation_end %llu, offset_next_file %llu\n", + (long long unsigned)free_list_allocation_end, + (long long unsigned)offset_next_file); +#endif } - if(file_recovery_new.file_stat!=NULL) - { - file_recovery_new.location.start=offset; - if(verbose>0) - { - log_info("%s header found at sector %lu\n", - ((file_recovery_new.extension!=NULL && file_recovery_new.extension[0]!='\0')? - file_recovery_new.extension:file_recovery_new.file_stat->file_hint->description), - (unsigned long)((offset-partition->part_offset)/disk_car->sector_size)); - } - if(file_recovery.file_stat==NULL) - { /* Header found => file found */ - file_recovery_cpy(&file_recovery, &file_recovery_new); - } - else if(file_recovery_new.file_stat->file_hint!=NULL) - { - if(verbose>0) - log_verbose("New file found => stop the recovery of current file\n"); - need_to_check_file=1; - } - } - else if(file_recovery.file_stat==NULL) - need_to_check_file=1; /* No header found => no file => stop */ } - if(file_recovery.file_stat!=NULL && file_recovery.handle==NULL) - { /* Create new file */ - set_filename(&file_recovery, recup_dir, *dir_num, disk_car, partition, 0); - if(file_recovery.file_stat->file_hint->recover==1) - { - if(!(file_recovery.handle=fopen(file_recovery.filename,"w+b"))) - { - log_critical("Cannot create file %s: %s\n", file_recovery.filename, strerror(errno)); - ind_stop=2; - } - } + search_walker=p; + if(go_backward==0) + { +#ifdef DEBUG_BF + log_info("go_backward==0\n"); +#endif + search_walker=next_file(search_walker, list_search_space); } - if(file_recovery.handle!=NULL) + } + log_info("phase=%d +%u\n", phase, *file_nbr - file_nbr_phase_old); + } + free(buffer_start); +#ifdef HAVE_NCURSES + photorec_info(stdscr, file_stats); +#endif + return ind_stop; +} + +/* + * 0: file found + * 1: stop by user + * 2: stop + * 3: fragment found + * 4: eof + * 5: file not found + * */ +static int photorec_bf_pad(disk_t *disk_car, const char *recup_dir, unsigned int *file_nbr, file_recovery_t *file_recovery, const unsigned int blocksize, alloc_data_t *list_search_space, unsigned int *dir_num, const photorec_status_t status, const int phase, const uint64_t file_offset, alloc_data_t **current_search_space, uint64_t *offset, unsigned char *buffer, unsigned char *block_buffer) +{ + { /* Add remaining data blocs */ + unsigned int nbr; + uint64_t offset_error_tmp; + file_recovery->offset_error=file_offset; + do + { + uint64_t file_size_backup; + nbr=0; + offset_error_tmp=file_recovery->offset_error; + fseek(file_recovery->handle, file_recovery->file_size, SEEK_SET); +#if 1 + if(file_recovery->data_check!=NULL) { - if(file_recovery.handle!=NULL) + int stop=0; + memset(buffer, 0, blocksize); + while(*current_search_space != list_search_space && + stop==0 && + file_recovery->file_size < file_recovery->offset_error+1000*blocksize) { - if(fwrite(buffer,blocksize,1,file_recovery.handle)<1) - { - log_critical("Cannot write to file %s:%s\n", file_recovery.filename, strerror(errno)); - ind_stop=3; + if( + ((*current_search_space)->start!=*offset && phase!=1) || + (*current_search_space)->file_stat==NULL || + (*current_search_space)->file_stat->file_hint==NULL) + { + disk_car->pread(disk_car, block_buffer, blocksize, *offset); + if(file_recovery->data_check(buffer, 2*blocksize, file_recovery)!=1) + { + stop=1; + } + if(fwrite(block_buffer, blocksize, 1, file_recovery->handle)<1) + { + log_critical("Cannot write to file %s:%s\n", file_recovery->filename, strerror(errno)); + fclose(file_recovery->handle); + file_recovery->handle=NULL; + return 2; + } + list_append_block(&file_recovery->location, *offset, blocksize, 1); + file_recovery->file_size+=blocksize; + file_recovery->file_size_on_disk+=blocksize; + nbr++; + memcpy(buffer, block_buffer, blocksize); } + get_next_sector(list_search_space, current_search_space, offset, blocksize); } - if(file_recovery.file_stat!=NULL) + } + else +#endif + { + while(*current_search_space != list_search_space && + file_recovery->file_size < file_recovery->offset_error+100*blocksize) { - int res=1; - list_append_block(&file_recovery.location, offset, blocksize,1); - if(file_recovery.data_check!=NULL) - res=file_recovery.data_check(buffer_olddata, 2*blocksize, &file_recovery); - file_recovery.file_size+=blocksize; - file_recovery.file_size_on_disk+=blocksize; - if(res==2) - { /* EOF found */ - need_to_check_file=1; + if((*current_search_space)->start!=*offset || + (*current_search_space)->file_stat==NULL || + (*current_search_space)->file_stat->file_hint==NULL) + { + disk_car->pread(disk_car, block_buffer, blocksize, *offset); + if(fwrite(block_buffer, blocksize, 1, file_recovery->handle)<1) + { + log_critical("Cannot write to file %s:%s\n", file_recovery->filename, strerror(errno)); + fclose(file_recovery->handle); + file_recovery->handle=NULL; + return 2; + } + list_append_block(&file_recovery->location, *offset, blocksize, 1); + file_recovery->file_size+=blocksize; + nbr++; } + get_next_sector(list_search_space, current_search_space, offset, blocksize); } - if(file_recovery.file_stat!=NULL && file_recovery.file_stat->file_hint->max_filesize>0 && file_recovery.file_size>=file_recovery.file_stat->file_hint->max_filesize) - { - log_verbose("File should not be bigger than %llu, stop adding data\n", - (long long unsigned)file_recovery.file_stat->file_hint->max_filesize); - need_to_check_file=1; - } } - get_next_sector(list_search_space, ¤t_search_space, &offset, blocksize); - if(current_search_space==list_search_space) - need_to_check_file=1; - if(need_to_check_file==0) +#ifdef DEBUG_BF + log_trace("BF "); + list_space_used(file_recovery, 512); +#endif + file_size_backup=file_recovery->file_size; + /* FIXME flags=0 */ + file_recovery->flags=(phase==1?0:1); +// file_recovery->flags=1; + file_recovery->offset_error=0; + file_recovery->offset_ok=0; + file_recovery->calculated_file_size=0; + file_recovery->file_check(file_recovery); + file_recovery->file_size=file_size_backup; +#ifdef DEBUG_BF + log_trace("offset_error=%llu offset_error_tmp=%llu nbr=%u blocksize=%u\n", + (long long unsigned) file_recovery->offset_error, + (long long unsigned) offset_error_tmp, + nbr, + blocksize); +#endif + } while(file_recovery->offset_error > offset_error_tmp + nbr /2 * blocksize); + } +#ifdef DEBUG_BF + log_info("photorec_bf_aux %s split file at %llu, error %llu\n", + file_recovery->filename, + (long long unsigned)file_offset, + (long long unsigned)file_recovery->offset_error); +#endif + if(file_recovery->offset_error==0) + { /* Recover the file */ +#ifdef DEBUG_BF + log_info("photorec_bf_aux, call file_finish\n"); +#endif + file_finish(file_recovery, recup_dir, 2, file_nbr, blocksize, list_search_space, current_search_space, offset, dir_num, status, disk_car); + return 0; + } + /* FIXME +4096 => +blocksize*/ + /* 21/11/2009: 2 blocksize */ + else if(file_recovery->offset_error/blocksize*blocksize >= (file_offset / blocksize * blocksize + 2 * blocksize)) + { /* Try to recover file composed of multiple fragments */ +#ifdef DEBUG_BF + log_info("%s multiple fragment %llu -> %llu, blocksize %u\n", + file_recovery->filename, + (unsigned long long)file_offset, + (unsigned long long)file_recovery->offset_error, + blocksize); + list_space_used(file_recovery, 512); +#endif + return 3; + } + return 5; +} + +static int photorec_bf_frag_fast(disk_t *disk_car, partition_t *partition, const char *recup_dir, const int interface, file_stat_t *file_stats, unsigned int *file_nbr, file_recovery_t *file_recovery, const unsigned int blocksize, alloc_data_t *list_search_space, alloc_data_t *start_search_space, const time_t real_start_time, unsigned int *dir_num, const photorec_status_t status, const int phase, alloc_data_t **current_search_space, uint64_t *offset, unsigned char *buffer, unsigned char *block_buffer, const unsigned int frag) +{ + const uint64_t original_offset_error=file_recovery->offset_error; + const uint64_t original_offset_ok=file_recovery->offset_ok; + const int blocs_to_skip=file_recovery->extra / blocksize; + unsigned int i; + int ind_stop=0; + log_info("photorec_bf_frag_fast %s, original_offset_ok=%llu, original_offset_error=%llu, blocs_to_skip=%u, extra=%llu\n", + file_recovery->filename, + (long long unsigned)original_offset_ok, + (long long unsigned)original_offset_error, + blocs_to_skip, + (long long unsigned)file_recovery->extra); +#ifdef DEBUG_BF + log_info("Frag %u\n", frag); +#endif +/* + * offset_ok=0 + * offset_error=2 + * blocksize=3 + * 0 1 2 3 4 5 6 7 + * 0 1 5 6 7 + * 0 2 5 6 7 + * 0 3 5 6 7 + * 0 4 5 6 7 + * + */ + file_recovery->extra=0; + for(i=0; i<blocs_to_skip; i++) + { + unsigned int j,k; + int res; + *current_search_space=start_search_space; + *offset=start_search_space->start; + file_recovery->checkpoint_status=0; + file_recovery->checkpoint_offset=original_offset_ok/blocksize*blocksize; + file_recovery->calculated_file_size=0; + file_recovery->file_size=0; + file_recovery->file_size_on_disk=0; + for(file_recovery->file_size = 0; + file_recovery->file_size <= original_offset_ok/blocksize*blocksize; + ) + { + /* FIXME: Handle ext2/ext3 */ + if(file_recovery->data_check!=NULL) { - buffer_olddata+=blocksize; - buffer+=blocksize; - if(old_offset+blocksize!=offset || buffer+read_size>buffer_start+buffer_size) - { - memcpy(buffer_start, buffer_olddata, blocksize); - buffer_olddata=buffer_start; - buffer=buffer_olddata+blocksize; - if(verbose>1) - { - log_verbose("Reading sector %10lu/%lu\n", - (unsigned long)((offset-partition->part_offset)/disk_car->sector_size), - (unsigned long)((partition->part_size-1)/disk_car->sector_size)); - } - disk_car->pread(disk_car, buffer, READ_SIZE, offset); - } + disk_car->pread(disk_car, block_buffer, blocksize, *offset); + file_recovery->data_check(buffer, 2*blocksize, file_recovery); + memcpy(buffer, block_buffer, blocksize); } - } while(need_to_check_file==0); - if(need_to_check_file==1) + file_recovery->file_size+=blocksize; + file_recovery->file_size_on_disk+=blocksize; + get_next_sector(list_search_space, current_search_space, offset, blocksize); + } + list_truncate(&file_recovery->location, file_recovery->file_size); + for(j=0; j<i; j++) + { + get_next_sector(list_search_space, current_search_space, offset, blocksize); + } + for(k=original_offset_ok/blocksize+1; k<original_offset_error/blocksize; k++) { - if(file_finish(&file_recovery,recup_dir,paranoid,file_nbr, blocksize, list_search_space, ¤t_search_space, &offset, dir_num,status,disk_car)<0) - { /* BF */ - current_search_space=td_list_entry(search_walker, alloc_data_t, list); - ind_stop=photorec_bf_aux(disk_car, partition, paranoid, recup_dir, interface, file_stats, file_nbr, &file_recovery, blocksize, list_search_space, current_search_space, real_start_time, dir_num, status); - pass2++; + disk_car->pread(disk_car, block_buffer, blocksize, *offset); + if(file_recovery->data_check(buffer, 2*blocksize, file_recovery)!=1) + { + ind_stop=1; + } + if(fwrite(block_buffer, blocksize, 1, file_recovery->handle)<1) + { + log_critical("Cannot write to file %s:%s\n", file_recovery->filename, strerror(errno)); + fclose(file_recovery->handle); + file_recovery->handle=NULL; + return 2; } + list_append_block(&file_recovery->location, *offset, blocksize, 1); + file_recovery->file_size+=blocksize; + file_recovery->file_size_on_disk+=blocksize; + memcpy(buffer, block_buffer, blocksize); + get_next_sector(list_search_space, current_search_space, offset, blocksize); } + for(; j<blocs_to_skip; j++) + { + get_next_sector(list_search_space, current_search_space, offset, blocksize); + } + res=photorec_bf_pad(disk_car, recup_dir, file_nbr, file_recovery, blocksize, list_search_space, dir_num, status, phase, file_recovery->offset_error, current_search_space, offset, buffer, block_buffer); + if(res==3) + { + if(frag>5) + return 5; + res=photorec_bf_frag(disk_car, partition, recup_dir, interface, file_stats, file_nbr, file_recovery, blocksize, list_search_space, start_search_space, real_start_time, dir_num, status, phase, current_search_space, offset, buffer, block_buffer, frag+1); + } + if(res<=2) + return res; + if(res==4) + return 5; } - free(buffer_start); + return 5; +} + +static int photorec_bf_frag(disk_t *disk_car, partition_t *partition, const char *recup_dir, const int interface, file_stat_t *file_stats, unsigned int *file_nbr, file_recovery_t *file_recovery, const unsigned int blocksize, alloc_data_t *list_search_space, alloc_data_t *start_search_space, const time_t real_start_time, unsigned int *dir_num, const photorec_status_t status, const int phase, alloc_data_t **current_search_space, uint64_t *offset, unsigned char *buffer, unsigned char *block_buffer, const unsigned int frag) +{ + uint64_t file_offset; + const uint64_t original_offset_error=file_recovery->offset_error; + int testbf=0; +#if 1 + if(file_recovery->extra > 0 && + file_recovery->offset_error / blocksize > file_recovery->offset_ok / blocksize && + file_recovery->offset_ok > 0) + { + int res=photorec_bf_frag_fast(disk_car, partition, recup_dir, interface, file_stats, file_nbr, file_recovery, blocksize, list_search_space, start_search_space, real_start_time, dir_num, status, phase, current_search_space, offset, buffer, block_buffer, frag); + if(res!=5) + return res; + } +#endif + log_info("photorec_bf_frag %s, original_offset_ok=%llu, original_offset_error=%llu, blocs_to_skip=%llu\n", + file_recovery->filename, + (long long unsigned)file_recovery->offset_ok, + (long long unsigned)file_recovery->offset_error, + (long long unsigned)file_recovery->extra); +#ifdef DEBUG_BF + log_info("Frag %u\n", frag); +#endif + for(file_offset=original_offset_error/blocksize*blocksize; + file_offset >= blocksize && + (original_offset_error+blocksize-1)/blocksize*blocksize < file_offset+8*512; + file_offset -= blocksize) + { + alloc_data_t *extractblock_search_space; + uint64_t extrablock_offset; + int blocs_to_skip; + file_recovery_t file_recovery_backup; + file_recovery->checkpoint_status=0; + file_recovery->checkpoint_offset = file_offset; + file_recovery->calculated_file_size=0; + if(file_recovery->data_check!=NULL) + { + *current_search_space=start_search_space; + *offset=start_search_space->start; + for(file_recovery->file_size = 0; + file_recovery->file_size < file_offset; + file_recovery->file_size += blocksize) + { + disk_car->pread(disk_car, block_buffer, blocksize, *offset); + /* FIXME: Handle ext2/ext3 */ + file_recovery->data_check(buffer, 2*blocksize, file_recovery); + memcpy(buffer, block_buffer, blocksize); + get_next_sector(list_search_space, current_search_space, offset, blocksize); + } + } + list_truncate(&file_recovery->location, file_offset); + file_recovery->file_size=file_offset; + file_recovery->file_size_on_disk=file_recovery->file_size; + /* Set extractblock_search_space & extrablock_offset to the begining of the potential extra block */ + /* FIXME */ +#ifdef DEBUG_BF + log_debug("Set extractblock_search_space & extrablock_offset to the begining of the potential extra block\n"); + log_info("photorec_bf_aux %s split file at %llu\n", + file_recovery->filename, + (long long unsigned)file_offset); + // list_space_used(file_recovery, 512); +#endif + /* Get the last block added to the file */ + extrablock_offset=0; + if(!td_list_empty(&file_recovery->location.list)) + { + const alloc_list_t *element=td_list_entry(file_recovery->location.list.prev, alloc_list_t, list); + extrablock_offset=element->end/blocksize*blocksize; + } + /* Get the corresponding search_place */ + extractblock_search_space=td_list_entry(list_search_space->list.next, alloc_data_t, list); + while(extractblock_search_space != list_search_space && + !(extractblock_search_space->start <= extrablock_offset && + extrablock_offset <= extractblock_search_space->end)) + extractblock_search_space=td_list_entry(extractblock_search_space->list.next, alloc_data_t, list); + /* Update extractblock_search_space & extrablock_offset */ + get_next_sector(list_search_space, &extractblock_search_space, &extrablock_offset, blocksize); + /* */ + file_recovery->offset_error=0; +#ifdef DEBUG_BF + log_info("extrablock_offset=%llu sectors\n", (long long unsigned)(extrablock_offset/512)); +#endif + memcpy(&file_recovery_backup, file_recovery, sizeof(file_recovery_backup)); + { + /* FIXME 16 100 250 */ + for(blocs_to_skip=-2; + blocs_to_skip<5000 && + (file_recovery->offset_error==0 || + (phase==0 && (file_recovery->offset_error >= file_offset || blocs_to_skip<16)) || + (phase==1 && (file_recovery->offset_error + blocksize >= file_offset || blocs_to_skip<100)) || + (phase==2 && blocs_to_skip<10) + ); + blocs_to_skip++,testbf++) + { + memcpy(file_recovery, &file_recovery_backup, sizeof(file_recovery_backup)); + *current_search_space=extractblock_search_space; + *offset=extrablock_offset; +#ifdef DEBUG_BF + log_info("photorec_bf_aux %s split file at %llu, skip=%u\n", + file_recovery->filename, + (long long unsigned)file_offset, blocs_to_skip); +#endif + file_recovery->offset_error=0; + list_truncate(&file_recovery->location,file_offset); + if( interface != 0) + { + static time_t previous_time=0; + time_t current_time; + current_time=time(NULL); + if(current_time>previous_time) + { + int ind_stop=0; + previous_time=current_time; #ifdef HAVE_NCURSES - photorec_info(stdscr, file_stats); + ind_stop=photorec_progressbar(stdscr, testbf, status, file_recovery->location.start, disk_car, partition, *file_nbr, current_time-real_start_time, file_stats); #endif - return ind_stop; + if(ind_stop!=0) + { + file_recovery->flags=0; + file_finish(file_recovery, recup_dir, 2, file_nbr, blocksize, list_search_space, current_search_space, offset, dir_num, status, disk_car); + log_info("photorec_bf_aux, user choose to stop\n"); + return 1; + } + } + } + /* Skip extra blocs */ +#ifdef DEBUG_BF + log_debug("Skip %u extra blocs\n", blocs_to_skip); +#endif + // log_info("%s Skip %u extra blocs\n", file_recovery->filename, blocs_to_skip); + if(blocs_to_skip < 0) + { + int i; + for(i=0; i< 2+blocs_to_skip; i++) + { + get_next_header(list_search_space, current_search_space, offset); + } + } + else + { + int i; + for(i=0; i<blocs_to_skip; i++) + { + get_next_sector(list_search_space, current_search_space, offset, blocksize); + if(*current_search_space==list_search_space) + return 5; + } + } + + switch(photorec_bf_pad(disk_car, recup_dir, file_nbr, file_recovery, blocksize, list_search_space, dir_num, status, phase, file_offset, current_search_space, offset, buffer, block_buffer)) + { + case 0: + return 0; + case 2: + return 2; + case 3: + if(frag>5) + return 5; + switch(photorec_bf_frag(disk_car, partition, recup_dir, interface, file_stats, file_nbr, file_recovery, blocksize, list_search_space, start_search_space, real_start_time, dir_num, status, phase, current_search_space, offset, buffer, block_buffer, frag+1)) + { + case 0: + return 0; + case 1: + return 1; + case 2: + return 2; + case 5: +#if 0 + /* TODO: Continue to iterate blocs_to_skip */ + if(file_recovery->offset_error/blocksize*blocksize >= (file_offset / blocksize * blocksize + 30 * blocksize)) + return 5; + break; +#else + return 5; +#endif + } + break; + case 4: + return 5; + } + } + } +#ifdef DEBUG_BF + log_info("blocs_to_skip=%u offset_error=0x%llx file_offset=0x%llx\n", + blocs_to_skip, + (long long unsigned)file_recovery->offset_error, (long long unsigned)file_offset); +#endif + } + return 5; } -static int photorec_bf_aux(disk_t *disk_car, partition_t *partition, const int paranoid, const char *recup_dir, const int interface, file_stat_t *file_stats, unsigned int *file_nbr, file_recovery_t *file_recovery, const unsigned int blocksize, alloc_data_t *list_search_space, alloc_data_t *start_search_space, const time_t real_start_time, unsigned int *dir_num, const photorec_status_t status) +static int photorec_bf_aux(disk_t *disk_car, partition_t *partition, const char *recup_dir, const int interface, file_stat_t *file_stats, unsigned int *file_nbr, file_recovery_t *file_recovery, const unsigned int blocksize, alloc_data_t *list_search_space, alloc_data_t *start_search_space, const time_t real_start_time, unsigned int *dir_num, const photorec_status_t status, const int phase) { uint64_t offset; - uint64_t original_offset_error; - long int save_seek; + unsigned char *buffer; unsigned char *block_buffer; - unsigned int i; int ind_stop; - int testbf=0; - time_t previous_time=0; alloc_data_t *current_search_space; //Init. of the brute force -#ifdef DEBUG_BF - log_trace("photorec_bf_aux location.start=%lu\n", - (long unsigned)(file_recovery->location.start/disk_car->sector_size)); -#endif - original_offset_error=file_recovery->offset_error; - file_recovery->handle=fopen(file_recovery->filename, "w+b"); if(file_recovery->handle==NULL) { log_critical("Brute Force : Cannot create file %s: %s\n", file_recovery->filename, strerror(errno)); return 2; } - block_buffer=(unsigned char *) MALLOC(sizeof(unsigned char)*blocksize); + buffer=(unsigned char *) MALLOC(2*blocksize); + block_buffer=&buffer[blocksize]; current_search_space=start_search_space; /* We have offset==start_search_space->start==file_recovery->location.start */ - offset=start_search_space->start;; + offset=start_search_space->start; - // Writing the file until the error location -#ifdef DEBUG_BF - log_debug("Writing the file until the error location %llu\n", (long long unsigned)original_offset_error); +#ifdef DEBUG_BF2 + log_trace("photorec_bf_aux location.start=%llu, ok at %llu, bad at %llu\n", + (long long unsigned)(file_recovery->location.start/disk_car->sector_size), + (long long unsigned)file_recovery->offset_ok, + (long long unsigned)file_recovery->offset_error); #endif - //FIXME: Handle ext2/ext3, handle fwrite return value - file_recovery->file_size=0; - for(i=0; i<(original_offset_error+blocksize-1)/blocksize; i++) + file_recovery->blocksize=blocksize; + // Writing the file until the error location + for(file_recovery->file_size = 0; +// file_recovery->file_size + blocksize -1 < file_recovery->offset_error; + file_recovery->file_size < file_recovery->offset_error; + file_recovery->file_size += blocksize) { disk_car->pread(disk_car, block_buffer, blocksize, offset); - fwrite(block_buffer, blocksize, 1, file_recovery->handle); + /* FIXME: Handle ext2/ext3 */ + if(fwrite(block_buffer, blocksize, 1, file_recovery->handle)<1) + { + log_critical("Cannot write to file %s:%s\n", file_recovery->filename, strerror(errno)); + fclose(file_recovery->handle); + file_recovery->handle=NULL; + free(buffer); + return 2; + } list_append_block(&file_recovery->location, offset, blocksize, 1); - file_recovery->file_size+=blocksize; get_next_sector(list_search_space, ¤t_search_space, &offset, blocksize); } + file_recovery->file_size_on_disk=file_recovery->file_size; + file_recovery->offset_error=file_recovery->file_size; #ifdef DEBUG_BF log_trace("BF Amorce "); - list_space_used(file_recovery, blocksize); + list_space_used(file_recovery, 512); log_trace("\n"); #endif - //Main Loop - do - { - uint64_t file_offset; + ind_stop=photorec_bf_frag(disk_car, partition, recup_dir, interface, file_stats, file_nbr, file_recovery, blocksize, list_search_space, start_search_space, real_start_time, dir_num, status, phase, ¤t_search_space, &offset, buffer, block_buffer, 0); + if(ind_stop==5) ind_stop=0; - for(file_offset=(original_offset_error+blocksize-1)/blocksize*blocksize; - file_offset >= blocksize && (original_offset_error+blocksize-1)/blocksize*blocksize<file_offset+8*512 && ind_stop==0; - file_offset -= blocksize) - { - alloc_data_t *extractblock_search_space; - uint64_t extrablock_offset; - unsigned int blocs_to_skip; - /* Set extractblock_search_space & extrablock_offset to the begining of the potential extra block */ -#ifdef DEBUG_BF - log_debug("Set extractblock_search_space & extrablock_offset to the begining of the potential extra block\n"); -#endif - /* Get the last block added to the file */ - extrablock_offset=0; - if(!td_list_empty(&file_recovery->location.list)) - { - const alloc_list_t *element=td_list_entry(file_recovery->location.list.prev, alloc_list_t, list); - extrablock_offset=element->end/blocksize*blocksize; - } - /* Get the corresponding search_place */ - extractblock_search_space=td_list_entry(list_search_space->list.next, alloc_data_t, list); - while(extractblock_search_space != list_search_space && - !(extractblock_search_space->start <= extrablock_offset && - extrablock_offset <= extractblock_search_space->end)) - extractblock_search_space=td_list_entry(extractblock_search_space->list.next, alloc_data_t, list); - /* Update extractblock_search_space & extrablock_offset */ - get_next_sector(list_search_space, &extractblock_search_space, &extrablock_offset, blocksize); - /* */ - for(blocs_to_skip=1; blocs_to_skip<=250 && ind_stop==0; blocs_to_skip++) - { - offset=extrablock_offset; - current_search_space=extractblock_search_space; - testbf++; - if(interface!=0) - { - time_t current_time; - current_time=time(NULL); - if(current_time>previous_time) - { - previous_time=current_time; -#ifdef HAVE_NCURSES - ind_stop=photorec_progressbar(stdscr, testbf, status, file_recovery->location.start, disk_car, partition, *file_nbr, current_time-real_start_time, file_stats); -#endif - if(ind_stop!=0) - { - file_finish(file_recovery, recup_dir, paranoid, file_nbr, blocksize, list_search_space, ¤t_search_space, &offset, dir_num, status, disk_car); - free(block_buffer); - return ind_stop; - } - } - } - fseek(file_recovery->handle,file_offset,SEEK_SET); - list_truncate(&file_recovery->location,file_offset); - file_recovery->file_size=file_offset; - /* Skip extra blocs */ -#ifdef DEBUG_BF - log_debug("Skip %u extra blocs\n", blocs_to_skip); -#endif - for(i=0; i<blocs_to_skip; i++) - { - get_next_sector(list_search_space, ¤t_search_space, &offset, blocksize); - } - { /* Add remaining data blocs */ - uint64_t offset_error_tmp; - file_recovery->offset_error=original_offset_error; - do - { - offset_error_tmp=file_recovery->offset_error; - file_recovery->file_size=file_offset; - - for (;file_recovery->file_size < file_recovery->offset_error+100*blocksize && - current_search_space != list_search_space; - file_recovery->file_size+=blocksize) - { - /* FIXME: handle fwrite return value */ - disk_car->pread(disk_car, block_buffer, blocksize, offset); - fwrite(block_buffer, blocksize, 1, file_recovery->handle); - list_append_block(&file_recovery->location, offset, blocksize, 1); - get_next_sector(list_search_space, ¤t_search_space, &offset, blocksize); - } - save_seek=ftell(file_recovery->handle); -#ifdef DEBUG_BF - log_trace("BF "); - list_space_used(file_recovery, blocksize); -#endif - file_recovery->offset_error=0; - file_recovery->calculated_file_size=0; - file_recovery->file_check(file_recovery); -#ifdef DEBUG_BF - log_trace("offset_error %llu %llu\n", - (long long unsigned) file_recovery->offset_error, - (long long unsigned) offset_error_tmp); - log_flush(); -#endif - fseek(file_recovery->handle, save_seek, SEEK_SET); - } while(file_recovery->offset_error/blocksize*blocksize > offset_error_tmp/blocksize*blocksize); - } - if(file_recovery->offset_error==0) - { /* Recover the file */ - file_finish(file_recovery,recup_dir,paranoid,file_nbr,blocksize,list_search_space,¤t_search_space, &offset, dir_num,status,disk_car); - free(block_buffer); - return ind_stop; - } - else if(file_recovery->offset_error/blocksize*blocksize >= original_offset_error+4096) - { /* Try to recover file composed of multiple fragments */ - log_info("%s multiple fragment %llu -> %llu\n", file_recovery->filename, - (unsigned long long)original_offset_error, - (unsigned long long)file_recovery->offset_error); - log_flush(); - original_offset_error=file_recovery->offset_error; - ind_stop=2; - } - } - } - } while(ind_stop==2); /* Cleanup */ - file_finish(file_recovery,recup_dir,paranoid,file_nbr,blocksize,list_search_space,¤t_search_space, &offset, dir_num,status,disk_car); - free(block_buffer); + file_finish(file_recovery,recup_dir,2, file_nbr,blocksize,list_search_space,¤t_search_space, &offset, dir_num,status,disk_car); + free(buffer); return ind_stop; } - - @@ -23,7 +23,7 @@ extern "C" { #endif #ifdef HAVE_NCURSES -int photorec_bf(disk_t *disk_car, partition_t *partition, const int verbose, const int paranoid, const char *recup_dir, const int interface, file_stat_t *file_stats, unsigned int *file_nbr, const unsigned int blocksize, alloc_data_t *list_search_space, const time_t real_start_time, unsigned int *dir_num, const photorec_status_t status, const unsigned int pass); +int photorec_bf(disk_t *disk_car, partition_t *partition, const int verbose, const char *recup_dir, const int interface, file_stat_t *file_stats, unsigned int *file_nbr, const unsigned int blocksize, alloc_data_t *list_search_space, const time_t real_start_time, unsigned int *dir_num, const photorec_status_t status, const unsigned int pass); #endif #ifdef __cplusplus } /* closing brace for extern "C" */ @@ -99,11 +99,12 @@ int photorec_find_blocksize(disk_t *disk_car, partition_t *partition, const int const unsigned int read_size=((*blocksize)>65536?(*blocksize):65536); alloc_data_t *current_search_space; file_recovery_t file_recovery; + reset_file_recovery(&file_recovery); + file_recovery.blocksize=*blocksize; buffer_size=(*blocksize)+READ_SIZE; buffer_start=(unsigned char *)MALLOC(buffer_size); buffer_olddata=buffer_start; buffer=buffer_olddata+(*blocksize); - reset_file_recovery(&file_recovery); start_time=time(NULL); previous_time=start_time; memset(buffer_olddata,0,(*blocksize)); diff --git a/src/photorec.c b/src/photorec.c index 061be3b..a3c24e7 100644 --- a/src/photorec.c +++ b/src/photorec.c @@ -54,6 +54,7 @@ static void update_search_space(const file_recovery_t *file_recovery, alloc_data_t *list_search_space, alloc_data_t **new_current_search_space, uint64_t *offset, const unsigned int blocksize); static void update_search_space_aux(alloc_data_t *list_search_space, uint64_t start, uint64_t end, alloc_data_t **new_current_search_space, uint64_t *offset); static alloc_data_t *file_truncate(alloc_data_t *space, file_recovery_t *file, const unsigned int sector_size, const unsigned int blocksize); +static alloc_data_t *file_error(alloc_data_t *space, file_recovery_t *file, const unsigned int blocksize); static void list_free_add(const file_recovery_t *file_recovery, alloc_data_t *list_search_space); static void list_space_used(const file_recovery_t *file_recovery, const unsigned int sector_size); @@ -546,6 +547,8 @@ void update_blocksize(unsigned int blocksize, alloc_data_t *list_search_space, c } } +uint64_t free_list_allocation_end=0; + static void free_list_allocation(alloc_list_t *list_allocation) { struct td_list_head *tmp = NULL; @@ -554,6 +557,7 @@ static void free_list_allocation(alloc_list_t *list_allocation) { alloc_list_t *allocated_space; allocated_space=td_list_entry(tmp, alloc_list_t, list); + free_list_allocation_end=allocated_space->end; td_list_del(tmp); free(allocated_space); } @@ -726,6 +730,8 @@ alloc_data_t *file_finish2(file_recovery_t *file_recovery, const char *recup_dir if(file_recovery->file_size==0) { /* File hasn't been sucessfully recovered */ + if(file_recovery->offset_error>0) + datanext=file_error(list_search_space, file_recovery, blocksize); } else { @@ -831,6 +837,60 @@ static alloc_data_t *file_truncate(alloc_data_t *space, file_recovery_t *file, c return datanext; } +static alloc_data_t *file_error_aux(alloc_data_t *space, alloc_data_t *file, const uint64_t file_size, const unsigned int blocksize) +{ + struct td_list_head *tmp; + struct td_list_head *next; + uint64_t size=0; + const uint64_t file_size_on_disk=(file_size+blocksize-1)/blocksize*blocksize; + for(tmp=&file->list, next=tmp->next; tmp!=&space->list; tmp=next, next=tmp->next) + { + alloc_data_t *element=td_list_entry(tmp, alloc_data_t, list); + if(size >= file_size) + return NULL; + if(element->data>0) + { + if(size + (element->end-element->start+1) <= file_size_on_disk) + { + size=size + (element->end-element->start+1); + } + else if(file_size_on_disk > size) + { + if(element->file_stat==NULL) + return NULL; + if(next!=&space->list) + { + alloc_data_t *new_element; + new_element=td_list_entry(next, alloc_data_t, list); + if(element->end+1==new_element->start && new_element->file_stat==NULL) + { + log_info("GOT IT\n"); + new_element->start-=file_size_on_disk - size; + element->end=new_element->start - 1; + return new_element; + } + } + { + alloc_data_t *new_element; + new_element=(alloc_data_t*)MALLOC(sizeof(*new_element)); + memcpy(new_element, element, sizeof(*new_element)); + new_element->start+=file_size_on_disk - size; + new_element->file_stat=NULL; + td_list_add(&new_element->list, &element->list); + element->end=new_element->start - 1; + return new_element; + } + } + } + } + return NULL; +} + +static alloc_data_t *file_error(alloc_data_t *space, file_recovery_t *file, const unsigned int blocksize) +{ + return file_error_aux(space, file->loc, file->offset_error, blocksize); +} + void free_search_space(alloc_data_t *list_search_space) { struct td_list_head *search_walker = NULL; diff --git a/src/phrecn.c b/src/phrecn.c index 4d9d63d..c4ce95b 100644 --- a/src/phrecn.c +++ b/src/phrecn.c @@ -191,11 +191,12 @@ static int photorec_aux(disk_t *disk_car, partition_t *partition, const int verb const unsigned int read_size=(blocksize>65536?blocksize:65536); alloc_data_t *current_search_space; file_recovery_t file_recovery; + reset_file_recovery(&file_recovery); + file_recovery.blocksize=blocksize; buffer_size=blocksize + READ_SIZE; buffer_start=(unsigned char *)MALLOC(buffer_size); buffer_olddata=buffer_start; buffer=buffer_olddata+blocksize; - reset_file_recovery(&file_recovery); start_time=time(NULL); previous_time=start_time; memset(buffer_olddata,0,blocksize); @@ -228,6 +229,7 @@ static int photorec_aux(disk_t *disk_car, partition_t *partition, const int verb #endif { file_recovery_t file_recovery_new; + file_recovery_new.blocksize=blocksize; if(file_recovery.file_stat!=NULL && file_recovery.file_stat->file_hint->min_header_distance > 0 && file_recovery.file_size<=file_recovery.file_stat->file_hint->min_header_distance) @@ -690,9 +692,10 @@ static void test_files(disk_t *disk, partition_t *partition, alloc_data_t *list_ alloc_data_t *current_search_space=list_search_space; uint64_t offset; file_recovery_t file_recovery; + reset_file_recovery(&file_recovery); + file_recovery->blocksize=512; offset=current_search_space->start; /* Recover a file with a known location */ - reset_file_recovery(&file_recovery); test_files_aux(disk, partition, &file_recovery, recup_dir, *dir_num, 1289*512, (1304+1)*512-1); test_files_aux(disk, partition, &file_recovery, recup_dir, *dir_num, 2881*512, (3259+1)*512-1); file_finish(&file_recovery, recup_dir, 1, file_nbr, disk->sector_size, list_search_space, ¤t_search_space, &offset, dir_num, STATUS_EXT2_OFF, disk); @@ -780,7 +783,7 @@ int photorec(disk_t *disk_car, partition_t *partition, const int verbose, const } else if(status==STATUS_EXT2_ON_BF || status==STATUS_EXT2_OFF_BF) { - ind_stop=photorec_bf(disk_car, partition, verbose, paranoid, recup_dir, interface, file_stats, &file_nbr, blocksize, list_search_space, real_start_time, &dir_num, status, pass); + ind_stop=photorec_bf(disk_car, partition, verbose, recup_dir, interface, file_stats, &file_nbr, blocksize, list_search_space, real_start_time, &dir_num, status, pass); session_save(list_search_space, disk_car, partition, files_enable, blocksize, paranoid, keep_corrupted_file, mode_ext2, expert, lowmem, carve_free_space_only, verbose); } else |
