/* File: phbs.c Copyright (C) 1998-2009 Christophe GRENIER This software is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifdef HAVE_CONFIG_H #include #endif #include #ifdef HAVE_STDLIB_H #include #endif #ifdef HAVE_STRING_H #include #endif #ifdef HAVE_TIME_H #include #endif #ifdef HAVE_SYS_TIME_H #include #endif #include "types.h" #include "common.h" #include "intrf.h" #ifdef HAVE_NCURSES #include "intrfn.h" #endif #include "list.h" #include "filegen.h" #include "photorec.h" #include "log.h" #include "file_tar.h" #include "pnext.h" #include "phnc.h" #include "phbs.h" #include "file_found.h" #define READ_SIZE 1024*512 #if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_tar) extern const file_hint_t file_hint_tar; #endif extern file_check_list_t file_check_list; extern int need_to_stop; /*@ @ requires \valid(dst); @ requires \valid_read(src); @ requires \separated(src, dst); @*/ static inline void file_recovery_cpy(file_recovery_t *dst, const file_recovery_t *src) { memcpy(dst, src, sizeof(*dst)); dst->location.list.prev=&dst->location.list; dst->location.list.next=&dst->location.list; } pstatus_t photorec_find_blocksize(struct ph_param *params, const struct ph_options *options, alloc_data_t *list_search_space) { uint64_t offset=0; unsigned char *buffer_start; unsigned char *buffer_olddata; unsigned char *buffer; time_t start_time; time_t previous_time; unsigned int buffer_size; const unsigned int blocksize=params->blocksize; const unsigned int read_size=(blocksize>65536?blocksize:65536); /*@ assert read_size >= 65536; */ alloc_data_t *current_search_space; file_recovery_t file_recovery; #ifndef DISABLED_FOR_FRAMAC params->file_nbr=0; 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; start_time=time(NULL); previous_time=start_time; memset(buffer_olddata, 0, blocksize); current_search_space=td_list_first_entry(&list_search_space->list, alloc_data_t, list); if(current_search_space!=list_search_space) offset=current_search_space->start; if(options->verbose>0) info_list_search_space(list_search_space, current_search_space, params->disk->sector_size, 0, options->verbose); params->disk->pread(params->disk, buffer, READ_SIZE, offset); while(current_search_space!=list_search_space) { const uint64_t old_offset=offset; { file_recovery_t file_recovery_new; file_recovery_new.blocksize=blocksize; file_recovery_new.location.start=offset; #if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_tar) if(file_recovery.file_stat!=NULL && file_recovery.file_stat->file_hint==&file_hint_tar && is_valid_tar_header((const struct tar_posix_header *)(buffer-0x200))) { /* Currently saving a tar, do not check the data for know header */ } else #endif { const struct td_list_head *tmpl; file_recovery_new.file_stat=NULL; td_list_for_each(tmpl, &file_check_list.list) { const struct td_list_head *tmp; const file_check_list_t *pos=td_list_entry_const(tmpl, const file_check_list_t, list); td_list_for_each(tmp, &pos->file_checks[buffer[pos->offset]].list) { const file_check_t *file_check=td_list_entry_const(tmp, const file_check_t, list); /*@ assert valid_file_check_node(file_check); */ if((file_check->length==0 || memcmp(buffer + file_check->offset, file_check->value, file_check->length)==0) && file_check->header_check(buffer, read_size, 1, &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 && file_recovery_new.file_stat->file_hint!=NULL) { /* A new file begins, backup file offset */ current_search_space=file_found(current_search_space, offset, file_recovery_new.file_stat); params->file_nbr++; file_recovery_cpy(&file_recovery, &file_recovery_new); } } } /* Check for data EOF */ if(file_recovery.file_stat!=NULL) { data_check_t res=DC_CONTINUE; if(file_recovery.data_check!=NULL) res=file_recovery.data_check(buffer_olddata, 2*blocksize, &file_recovery); file_recovery.file_size+=blocksize; if(res==DC_STOP || res==DC_ERROR) { /* EOF found */ reset_file_recovery(&file_recovery); } } /* Check for maximum filesize */ 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) { reset_file_recovery(&file_recovery); } if(params->file_nbr >= 10) { current_search_space=list_search_space; } else get_next_sector(list_search_space, ¤t_search_space, &offset, blocksize); if(current_search_space==list_search_space) { /* End of disk found => EOF */ reset_file_recovery(&file_recovery); } 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(options->verbose>1) { log_verbose("Reading sector %10llu/%llu\n", (unsigned long long)((offset - params->partition->part_offset) / params->disk->sector_size), (unsigned long long)((params->partition->part_size-1) / params->disk->sector_size)); } if(params->disk->pread(params->disk, buffer, READ_SIZE, offset) != READ_SIZE) { #ifdef HAVE_NCURSES wmove(stdscr,11,0); wclrtoeol(stdscr); wprintw(stdscr,"Error reading sector %10lu\n", (unsigned long)((offset - params->partition->part_offset) / params->disk->sector_size)); #endif } #ifdef HAVE_NCURSES { time_t current_time; current_time=time(NULL); if(current_time>previous_time) { previous_time=current_time; if(photorec_progressbar(stdscr, 0, params, offset, current_time)) { log_info("PhotoRec has been stopped\n"); current_search_space=list_search_space; } } } #endif if(need_to_stop!=0) { log_info("PhotoRec has been stopped\n"); current_search_space=list_search_space; } } } /* end while(current_search_space!=list_search_space) */ free(buffer_start); #endif return PSTATUS_OK; }