summaryrefslogtreecommitdiffstats
path: root/src/psearchn.c
diff options
context:
space:
mode:
authorChristophe Grenier <grenier@cgsecurity.org>2014-03-30 20:03:31 +0200
committerChristophe Grenier <grenier@cgsecurity.org>2014-03-30 20:03:31 +0200
commit26ea4b911746598d7734d6282746c567eda623cf (patch)
treef3b54010dd6ad1d132cd5bb5ff2d6f074b18241b /src/psearchn.c
parentf013c26602c15900ac88dbcb35b4fcdaa27ff419 (diff)
PhotoRec: when a file is recovered, check again each block after the end of the recovered file
Diffstat (limited to 'src/psearchn.c')
-rw-r--r--src/psearchn.c224
1 files changed, 124 insertions, 100 deletions
diff --git a/src/psearchn.c b/src/psearchn.c
index 5a4721f..1d142d7 100644
--- a/src/psearchn.c
+++ b/src/psearchn.c
@@ -107,6 +107,122 @@ static FILE *fopen_with_retry(const char *path, const char *mode)
}
#endif
+static void photorec_dir_fat(const unsigned char *buffer, const unsigned int read_size, const unsigned long long sector)
+{
+ file_info_t dir_list = {
+ .list = TD_LIST_HEAD_INIT(dir_list.list),
+ .name = NULL
+ };
+ dir_fat_aux(buffer, read_size, 0, &dir_list);
+ if(!td_list_empty(&dir_list.list))
+ {
+ log_info("Sector %llu\n", sector);
+ dir_aff_log(NULL, &dir_list);
+ delete_list_file(&dir_list);
+ }
+}
+
+static pstatus_t photorec_new_file(file_recovery_t *file_recovery, struct ph_param *params, const uint64_t offset)
+{
+ set_filename(file_recovery, params);
+ if(file_recovery->file_stat->file_hint->recover==1)
+ {
+#if defined(__CYGWIN__) || defined(__MINGW32__)
+ file_recovery->handle=fopen_with_retry(file_recovery->filename,"w+b");
+#else
+ file_recovery->handle=fopen(file_recovery->filename,"w+b");
+#endif
+ if(!file_recovery->handle)
+ {
+ log_critical("Cannot create file %s: %s\n", file_recovery->filename, strerror(errno));
+ params->offset=offset;
+ return PSTATUS_EACCES;
+ }
+ }
+ return PSTATUS_OK;
+}
+
+static pstatus_t photorec_header_found(file_recovery_t *file_recovery_new, file_recovery_t *file_recovery, struct ph_param *params, const struct ph_options *options, alloc_data_t *list_search_space, const unsigned char *buffer, int *file_recovered, alloc_data_t **current_search_space, uint64_t *offset)
+{
+ if(file_recovery_new->file_stat!=NULL && file_recovery_new->file_stat->file_hint!=NULL)
+ {
+ file_recovery_new->location.start=*offset;
+ if(file_recovery->file_stat!=NULL)
+ {
+ if(options->verbose > 1)
+ log_trace("A known header has been found, recovery of the previous file is finished\n");
+ *file_recovered=file_finish2(file_recovery, params, options->paranoid, list_search_space);
+ if(*file_recovered==1)
+ get_prev_location(list_search_space, current_search_space, offset, file_recovery->location.start);
+ if(options->lowmem > 0)
+ forget(list_search_space, *current_search_space);
+ }
+ if(*file_recovered==0)
+ {
+ file_recovery_cpy(file_recovery, file_recovery_new);
+ if(options->verbose > 1)
+ {
+ log_info("%s header found at sector %lu\n",
+ ((file_recovery->extension!=NULL && file_recovery->extension[0]!='\0')?
+ file_recovery->extension:file_recovery->file_stat->file_hint->description),
+ (unsigned long)((file_recovery->location.start-params->partition->part_offset)/params->disk->sector_size));
+ log_info("file_recovery->location.start=%lu\n",
+ (unsigned long)(file_recovery->location.start/params->disk->sector_size));
+ }
+
+ if(file_recovery->file_stat->file_hint==&file_hint_dir && options->verbose > 0)
+ { /* FAT directory found, list the file */
+ const unsigned int blocksize=params->blocksize;
+ const unsigned int read_size=(blocksize>65536?blocksize:65536);
+ photorec_dir_fat(buffer, read_size, file_recovery->location.start/params->disk->sector_size);
+ }
+ return photorec_new_file(file_recovery, params, *offset);
+ }
+ }
+ return PSTATUS_OK;
+}
+
+static pstatus_t photorec_check_header(file_recovery_t *file_recovery, struct ph_param *params, const struct ph_options *options, alloc_data_t *list_search_space, const unsigned char *buffer, int *file_recovered, alloc_data_t **current_search_space, uint64_t *offset)
+{
+ struct td_list_head *tmpl;
+ const unsigned int blocksize=params->blocksize;
+ const unsigned int read_size=(blocksize>65536?blocksize:65536);
+ 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)
+ return PSTATUS_OK;
+ if(file_recovery->file_stat!=NULL && file_recovery->file_stat->file_hint==&file_hint_tar &&
+ header_check_tar(buffer-0x200,0x200, 0, file_recovery, &file_recovery_new))
+ { /* Currently saving a tar, do not check the data for know header */
+ if(options->verbose > 1)
+ {
+ log_verbose("Currently saving a tar file, sector %lu.\n",
+ (unsigned long)((*offset-params->partition->part_offset)/params->disk->sector_size));
+ }
+ return PSTATUS_OK;
+ }
+ file_recovery_new.file_stat=NULL;
+ td_list_for_each(tmpl, &file_check_list.list)
+ {
+ struct td_list_head *tmp;
+ const file_check_list_t *pos=td_list_entry(tmpl, file_check_list_t, list);
+ file_recovery_new.location.start=*offset;
+ td_list_for_each(tmp, &pos->file_checks[buffer[pos->offset]].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)
+ {
+ file_recovery_new.file_stat=file_check->file_stat;
+ return photorec_header_found(&file_recovery_new, file_recovery, params, options, list_search_space, buffer, file_recovered, current_search_space, offset);
+ }
+ }
+ }
+ return PSTATUS_OK;
+}
+
pstatus_t photorec_aux(struct ph_param *params, const struct ph_options *options, alloc_data_t *list_search_space)
{
uint64_t offset;
@@ -164,106 +280,7 @@ pstatus_t photorec_aux(struct ph_param *params, const struct ph_options *options
exit(1);
}
#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)
- {
- }
- else if(file_recovery.file_stat!=NULL && file_recovery.file_stat->file_hint==&file_hint_tar &&
- header_check_tar(buffer-0x200,0x200,0,&file_recovery,&file_recovery_new))
- { /* Currently saving a tar, do not check the data for know header */
- if(options->verbose > 1)
- {
- log_verbose("Currently saving a tar file, sector %lu.\n",
- (unsigned long)((offset-params->partition->part_offset)/params->disk->sector_size));
- }
- }
- else
- {
- struct td_list_head *tmpl;
- file_recovery_new.file_stat=NULL;
- td_list_for_each(tmpl, &file_check_list.list)
- {
- struct td_list_head *tmp;
- const file_check_list_t *pos=td_list_entry(tmpl, file_check_list_t, list);
- file_recovery_new.location.start=offset;
- td_list_for_each(tmp, &pos->file_checks[buffer[pos->offset]].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)
- {
- 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)
- {
- file_recovery_new.location.start=offset;
- if(file_recovery.file_stat!=NULL)
- {
- if(options->verbose > 1)
- log_trace("A known header has been found, recovery of the previous file is finished\n");
- file_recovered=file_finish2(&file_recovery, params, options->paranoid, list_search_space);
- if(options->lowmem > 0)
- forget(list_search_space,current_search_space);
- }
- if(file_recovered==0)
- {
- file_recovery_cpy(&file_recovery, &file_recovery_new);
- if(options->verbose > 1)
- {
- log_info("%s header found at sector %lu\n",
- ((file_recovery.extension!=NULL && file_recovery.extension[0]!='\0')?
- file_recovery.extension:file_recovery.file_stat->file_hint->description),
- (unsigned long)((file_recovery.location.start-params->partition->part_offset)/params->disk->sector_size));
- log_info("file_recovery.location.start=%lu\n",
- (unsigned long)(file_recovery.location.start/params->disk->sector_size));
- }
-
- if(file_recovery.file_stat->file_hint==&file_hint_dir && options->verbose > 0)
- { /* FAT directory found, list the file */
- file_info_t dir_list = {
- .list = TD_LIST_HEAD_INIT(dir_list.list),
- .name = NULL
- };
- dir_fat_aux(buffer, read_size, 0, &dir_list);
- if(!td_list_empty(&dir_list.list))
- {
- log_info("Sector %lu\n",
- (unsigned long)(file_recovery.location.start/params->disk->sector_size));
- dir_aff_log(NULL, &dir_list);
- delete_list_file(&dir_list);
- }
- }
- }
- }
- }
- if(file_recovery.file_stat!=NULL && file_recovery.handle==NULL)
- {
- set_filename(&file_recovery, params);
- if(file_recovery.file_stat->file_hint->recover==1)
- {
-#if defined(__CYGWIN__) || defined(__MINGW32__)
- file_recovery.handle=fopen_with_retry(file_recovery.filename,"w+b");
-#else
- file_recovery.handle=fopen(file_recovery.filename,"w+b");
-#endif
- if(!file_recovery.handle)
- {
- log_critical("Cannot create file %s: %s\n", file_recovery.filename, strerror(errno));
- ind_stop=PSTATUS_EACCES;
- params->offset=offset;
- }
- }
- }
- }
+ ind_stop=photorec_check_header(&file_recovery, params, options, list_search_space, buffer, &file_recovered, &current_search_space, &offset);
if(file_recovery.file_stat!=NULL)
{
/* try to skip ext2/ext3 indirect block */
@@ -330,6 +347,8 @@ pstatus_t photorec_aux(struct ph_param *params, const struct ph_options *options
}
if(res==DC_STOP || res==DC_ERROR)
{
+ if(res==DC_ERROR)
+ file_recovery.file_size=0;
file_recovered=file_finish2(&file_recovery, params, options->paranoid, list_search_space);
if(options->lowmem > 0)
forget(list_search_space,current_search_space);
@@ -357,7 +376,10 @@ pstatus_t photorec_aux(struct ph_param *params, const struct ph_options *options
get_prev_file_header(list_search_space, &current_search_space, &offset)==0)
back++;
else
+ {
back=0;
+ get_prev_location(list_search_space, &current_search_space, &offset, file_recovery.location.start);
+ }
}
if(current_search_space==list_search_space)
{
@@ -367,6 +389,8 @@ pstatus_t photorec_aux(struct ph_param *params, const struct ph_options *options
log_trace("End of media\n");
#endif
file_recovered=file_finish2(&file_recovery, params, options->paranoid, list_search_space);
+ if(file_recovered==1)
+ get_prev_location(list_search_space, &current_search_space, &offset, file_recovery.location.start);
if(options->lowmem > 0)
forget(list_search_space,current_search_space);
}