summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristophe Grenier <grenier@cgsecurity.org>2013-05-16 18:09:15 +0200
committerChristophe Grenier <grenier@cgsecurity.org>2013-05-16 18:09:15 +0200
commit1471f47a5c5b9d69863ec496bd7a57a9b0081d89 (patch)
treef1a551a2d0ba7f5fa3a40f2a599213327b8b8f91
parent478478bbccac2e9ac1197035e832b884ace801b3 (diff)
move ind_block(), file_recovery_cpy() and file_add_data() to psearch.h and photorec_aux() to psearchn.c
-rw-r--r--src/Makefile.am4
-rw-r--r--src/phrecn.c399
-rw-r--r--src/psearch.h60
-rw-r--r--src/psearchn.c385
-rw-r--r--src/psearchn.h30
5 files changed, 478 insertions, 400 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index ee37fd6..15370af 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -295,8 +295,8 @@ photorec_C = photorec.c phcfg.c addpart.c dir.c exfatp.c ext2grp.c ext2_dir.c e
photorec_H = photorec.h phcfg.h addpart.h dir.h exfatp.h ext2grp.h ext2p.h ext2_dir.h ext2_inc.h fat_dir.h fatp.h file_found.h geometry.h memmem.h ntfs_dir.h ntfsp.h ntfs_inc.h poptions.h sessionp.h setdate.h dfxml.h
-photorec_ncurses_C = addpartn.c askloc.c chgarch.c chgarchn.c chgtype.c chgtypen.c fat_cluster.c fat_unformat.c geometryn.c hiddenn.c intrfn.c nodisk.c parti386n.c partgptn.c partmacn.c partsunn.c partxboxn.c pbanner.c pblocksize.c pdisksel.c pfree_whole.c phbf.c phbs.c phnc.c phrecn.c ppartsel.c
-photorec_ncurses_H = addpartn.h askloc.h chgarch.h chgarchn.h chgtype.h chgtypen.h fat_cluster.h fat_unformat.h geometryn.h hiddenn.h intrfn.h nodisk.h parti386n.h partgptn.h partmacn.h partsunn.h partxboxn.h pblocksize.h pdisksel.h pfree_whole.h pnext.h phbf.h phbs.h phnc.h phrecn.h ppartsel.h
+photorec_ncurses_C = addpartn.c askloc.c chgarch.c chgarchn.c chgtype.c chgtypen.c fat_cluster.c fat_unformat.c geometryn.c hiddenn.c intrfn.c nodisk.c parti386n.c partgptn.c partmacn.c partsunn.c partxboxn.c pbanner.c pblocksize.c pdisksel.c pfree_whole.c phbf.c phbs.c phnc.c phrecn.c ppartsel.c psearchn.c
+photorec_ncurses_H = addpartn.h askloc.h chgarch.h chgarchn.h chgtype.h chgtypen.h fat_cluster.h fat_unformat.h geometryn.h hiddenn.h intrfn.h nodisk.h parti386n.h partgptn.h partmacn.h partsunn.h partxboxn.h pblocksize.h pdisksel.h pfree_whole.h pnext.h phbf.h phbs.h phnc.h phrecn.h ppartsel.h psearch.h psearchn.h
photorec_SOURCES = phmain.c $(photorec_C) $(photorec_H) $(photorec_ncurses_C) $(photorec_ncurses_H) $(file_C) $(file_H) $(base_C) $(base_H) partgptro.c $(fs_C) $(fs_H) $(ICON_PHOTOREC) suspend_no.c
diff --git a/src/phrecn.c b/src/phrecn.c
index 821c280..f5432d2 100644
--- a/src/phrecn.c
+++ b/src/phrecn.c
@@ -78,54 +78,16 @@
#include "file_found.h"
#include "dfxml.h"
#include "poptions.h"
+#include "psearchn.h"
/* #define DEBUG */
/* #define DEBUG_BF */
-#define READ_SIZE 1024*512
#define DEFAULT_IMAGE_NAME "image_remaining.dd"
-extern const file_hint_t file_hint_tar;
-extern const file_hint_t file_hint_dir;
extern file_check_list_t file_check_list;
static int interface_cannot_create_file(void);
-/* ==================== INLINE FUNCTIONS ========================= */
-/* Check if the block looks like an indirect/double-indirect block */
-static inline int ind_block(const unsigned char *buffer, const unsigned int blocksize)
-{
- const uint32_t *p32=(const uint32_t *)buffer;
- unsigned int i;
- unsigned int diff=1; /* IND: Indirect block */
- if(le32(p32[0])==0)
- return 0;
- if(le32(p32[1])==le32(p32[0])+blocksize/4+1)
- diff=blocksize/4+1; /* DIND: Double Indirect block */
- for(i=0;i<blocksize/4-1 && le32(p32[i+1])!=0;i++)
- {
- if(le32(p32[i+1])!=le32(p32[i])+diff)
- {
- return 0;
- }
- }
- i++;
- for(;i<blocksize/4 && le32(p32[i])==0;i++);
- if(i<blocksize/4)
- {
- return 0;
- }
- return 1; /* Ok: ind_block points to non-fragmented block */
-}
-
-static inline void file_recovery_cpy(file_recovery_t *dst, file_recovery_t *src)
-{
- memcpy(dst, src, sizeof(*dst));
- dst->location.list.prev=&dst->location.list;
- dst->location.list.next=&dst->location.list;
-}
-
-/* ==================== INLINE FUNCTIONS ========================= */
-
#if defined(__CYGWIN__) || defined(__MINGW32__)
/* Live antivirus protection may open file as soon as they are created by *
* PhotoRec. PhotoRec will not be able to overwrite a file as long as the *
@@ -151,365 +113,6 @@ static FILE *fopen_with_retry(const char *path, const char *mode)
}
#endif
-static inline alloc_data_t *file_add_data(alloc_data_t *data, const uint64_t offset, const unsigned int content)
-{
- if(!(data->start <= offset && offset <= data->end))
- {
- log_critical("file_add_data: bug\n");
- return data;
- }
- if(data->start==offset)
- {
- data->data=content;
- return data;
- }
- if(data->data==content)
- return data;
- {
- alloc_data_t *datanext=(alloc_data_t*)MALLOC(sizeof(*datanext));
- memcpy(datanext, data, sizeof(*datanext));
- data->end=offset-1;
- datanext->start=offset;
- datanext->file_stat=NULL;
- datanext->data=content;
- td_list_add(&datanext->list, &data->list);
- return datanext;
- }
-}
-
-/* photorec_aux()
- * @param struct ph_param *params
- * @param const struct ph_options *options
- * @param alloc_data_t *list_search_space
- *
- * @returns:
- * 0: Completed
- * 1: Stop by user request
- * 2: Cannot create file
- * 3: No space left
- * >0: params->offset is set
- */
-
-static pstatus_t photorec_aux(struct ph_param *params, const struct ph_options *options, alloc_data_t *list_search_space)
-{
- uint64_t offset;
- unsigned char *buffer_start;
- unsigned char *buffer_olddata;
- unsigned char *buffer;
- time_t start_time;
- time_t previous_time;
- time_t next_checkpoint;
- pstatus_t ind_stop=PSTATUS_OK;
- unsigned int buffer_size;
- const unsigned int blocksize=params->blocksize;
- const unsigned int read_size=(blocksize>65536?blocksize:65536);
- uint64_t offset_before_back=0;
- unsigned int back=0;
- alloc_data_t *current_search_space;
- file_recovery_t file_recovery;
- memset(&file_recovery, 0, sizeof(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;
- start_time=time(NULL);
- previous_time=start_time;
- next_checkpoint=start_time+5*60;
- memset(buffer_olddata,0,blocksize);
- current_search_space=td_list_entry(list_search_space->list.next, alloc_data_t, list);
- offset=set_search_start(params, &current_search_space, list_search_space);
- if(options->verbose > 0)
- info_list_search_space(list_search_space, current_search_space, params->disk->sector_size, 0, options->verbose);
- 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));
- }
- params->disk->pread(params->disk, buffer, READ_SIZE, offset);
- while(current_search_space!=list_search_space)
- {
- int file_recovered=0;
- uint64_t old_offset=offset;
-#ifdef DEBUG
- log_debug("sector %llu\n",
- (unsigned long long)((offset-params->partition->part_offset)/params->disk->sector_size));
- if(!(current_search_space->start<=offset && offset<=current_search_space->end))
- {
- log_critical("BUG: offset=%llu not in [%llu-%llu]\n",
- (unsigned long long)(offset/params->disk->sector_size),
- (unsigned long long)(current_search_space->start/params->disk->sector_size),
- (unsigned long long)(current_search_space->end/params->disk->sector_size));
- log_close();
- 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);
- 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)
- {
- current_search_space=file_found(current_search_space, offset, file_recovery_new.file_stat);
- file_recovery_new.loc=current_search_space;
- file_recovery_new.location.start=offset;
- 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, list_search_space, &current_search_space, &offset);
- }
- reset_file_recovery(&file_recovery);
- 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,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;
- }
- }
- }
- }
- if(file_recovery.file_stat!=NULL)
- {
- int res=1;
- /* try to skip ext2/ext3 indirect block */
- if((params->status==STATUS_EXT2_ON || params->status==STATUS_EXT2_ON_SAVE_EVERYTHING) &&
- file_recovery.file_size_on_disk>=12*blocksize &&
- ind_block(buffer,blocksize)!=0)
- {
- current_search_space=file_add_data(current_search_space, offset, 0);
- file_recovery.file_size_on_disk+=blocksize;
- if(options->verbose > 1)
- {
- log_verbose("Skipping sector %10lu/%lu\n",
- (unsigned long)((offset-params->partition->part_offset)/params->disk->sector_size),
- (unsigned long)((params->partition->part_size-1)/params->disk->sector_size));
- }
- memcpy(buffer, buffer_olddata, blocksize);
- }
- else
- {
- 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));
- if(errno==EFBIG)
- {
- /* File is too big for the destination filesystem */
- res=2;
- }
- else
- {
- /* Warn the user */
- ind_stop=PSTATUS_ENOSPC;
- params->offset=file_recovery.location.start;
- }
- }
- }
- if(ind_stop==PSTATUS_OK)
- {
- current_search_space=file_add_data(current_search_space, offset, 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)
- {
- if(options->verbose > 1)
- log_trace("EOF found\n");
- }
- }
- }
- if(res!=2 && file_recovery.file_stat->file_hint->max_filesize>0 && file_recovery.file_size>=file_recovery.file_stat->file_hint->max_filesize)
- {
- res=2;
- log_verbose("File should not be bigger than %llu, stop adding data\n",
- (long long unsigned)file_recovery.file_stat->file_hint->max_filesize);
- }
- if(res!=2 && file_recovery.file_size + blocksize >= PHOTOREC_MAX_SIZE_32 && is_fat(params->partition))
- {
- res=2;
- log_verbose("File should not be bigger than %llu, stop adding data\n",
- (long long unsigned)file_recovery.file_stat->file_hint->max_filesize);
- }
- if(res==2)
- {
- file_recovered=file_finish2(&file_recovery, params, options, list_search_space, &current_search_space, &offset);
- reset_file_recovery(&file_recovery);
- if(options->lowmem > 0)
- forget(list_search_space,current_search_space);
- }
- }
- if(ind_stop!=PSTATUS_OK)
- {
- log_info("PhotoRec has been stopped\n");
- current_search_space=list_search_space;
- }
- else if(file_recovered==0)
- {
- get_next_sector(list_search_space, &current_search_space,&offset,blocksize);
- if(offset > offset_before_back)
- back=0;
- }
- else if(file_recovered>0)
- {
- /* try to recover the previous file, otherwise stay at the current location */
- offset_before_back=offset;
- if(back < 10 &&
- get_prev_file_header(list_search_space, &current_search_space, &offset)==0)
- back++;
- else
- back=0;
- }
- if(current_search_space==list_search_space)
- {
-#ifdef DEBUG_GET_NEXT_SECTOR
- log_trace("current_search_space==list_search_space=%p (prev=%p,next=%p)\n",
- current_search_space, current_search_space->list.prev, current_search_space->list.next);
- log_trace("End of media\n");
-#endif
- file_recovered=file_finish2(&file_recovery, params, options, list_search_space, &current_search_space, &offset);
- reset_file_recovery(&file_recovery);
- if(options->lowmem > 0)
- forget(list_search_space,current_search_space);
- }
- buffer_olddata+=blocksize;
- buffer+=blocksize;
- if(file_recovered==1 ||
- old_offset+blocksize!=offset ||
- buffer+read_size>buffer_start+buffer_size)
- {
- if(file_recovered==1)
- memset(buffer_start,0,blocksize);
- else
- 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
- if(ind_stop==PSTATUS_OK)
- {
- time_t current_time;
- current_time=time(NULL);
- if(current_time>previous_time)
- {
- previous_time=current_time;
- ind_stop=photorec_progressbar(stdscr, params->pass, params, offset, current_time);
- if(file_recovery.file_stat!=NULL)
- params->offset=file_recovery.location.start;
- else
- params->offset=offset;
- if(current_time >= next_checkpoint)
- {
- /* Save current progress */
- session_save(list_search_space, params, options);
- next_checkpoint=current_time+5*60;
- }
- }
- }
-#endif
- }
- } /* end while(current_search_space!=list_search_space) */
- free(buffer_start);
-#ifdef HAVE_NCURSES
- photorec_info(stdscr, params->file_stats);
-#endif
- return ind_stop;
-}
-
#ifdef HAVE_NCURSES
static void recovery_finished(disk_t *disk, const partition_t *partition, const unsigned int file_nbr, const char *recup_dir, const pstatus_t ind_stop)
{
diff --git a/src/psearch.h b/src/psearch.h
new file mode 100644
index 0000000..1f6c860
--- /dev/null
+++ b/src/psearch.h
@@ -0,0 +1,60 @@
+static inline alloc_data_t *file_add_data(alloc_data_t *data, const uint64_t offset, const unsigned int content)
+{
+ if(!(data->start <= offset && offset <= data->end))
+ {
+ log_critical("file_add_data: bug\n");
+ return data;
+ }
+ if(data->start==offset)
+ {
+ data->data=content;
+ return data;
+ }
+ if(data->data==content)
+ return data;
+ {
+ alloc_data_t *datanext=(alloc_data_t*)MALLOC(sizeof(*datanext));
+ memcpy(datanext, data, sizeof(*datanext));
+ data->end=offset-1;
+ datanext->start=offset;
+ datanext->file_stat=NULL;
+ datanext->data=content;
+ td_list_add(&datanext->list, &data->list);
+ return datanext;
+ }
+}
+
+static inline void file_recovery_cpy(file_recovery_t *dst, file_recovery_t *src)
+{
+ memcpy(dst, src, sizeof(*dst));
+ dst->location.list.prev=&dst->location.list;
+ dst->location.list.next=&dst->location.list;
+}
+
+/* Check if the block looks like an indirect/double-indirect block */
+static inline int ind_block(const unsigned char *buffer, const unsigned int blocksize)
+{
+ const uint32_t *p32=(const uint32_t *)buffer;
+ unsigned int i;
+ unsigned int diff=1; /* IND: Indirect block */
+ if(le32(p32[0])==0)
+ return 0;
+ if(le32(p32[1])==le32(p32[0])+blocksize/4+1)
+ diff=blocksize/4+1; /* DIND: Double Indirect block */
+ for(i=0;i<blocksize/4-1 && le32(p32[i+1])!=0;i++)
+ {
+ if(le32(p32[i+1])!=le32(p32[i])+diff)
+ {
+ return 0;
+ }
+ }
+ i++;
+ for(;i<blocksize/4 && le32(p32[i])==0;i++);
+ if(i<blocksize/4)
+ {
+ return 0;
+ }
+ return 1; /* Ok: ind_block points to non-fragmented block */
+}
+
+
diff --git a/src/psearchn.c b/src/psearchn.c
new file mode 100644
index 0000000..6dfd93e
--- /dev/null
+++ b/src/psearchn.c
@@ -0,0 +1,385 @@
+/*
+
+ File: psearchn.c
+
+ Copyright (C) 1998-2013 Christophe GRENIER <grenier@cgsecurity.org>
+
+ 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 <config.h>
+#endif
+
+#include <stdio.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#ifdef HAVE_TIME_H
+#include <time.h>
+#endif
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#include "types.h"
+#include "common.h"
+#include "intrf.h"
+#include <errno.h>
+#include "dir.h"
+#include "fat.h"
+#include "fat_dir.h"
+#include "list.h"
+#include "filegen.h"
+#include "photorec.h"
+#include "sessionp.h"
+#include "log.h"
+#include "file_tar.h"
+#include "pnext.h"
+#include "file_found.h"
+#include "psearch.h"
+#ifdef HAVE_NCURSES
+#include "intrfn.h"
+#include "phnc.h"
+#endif
+#include "psearchn.h"
+
+#define READ_SIZE 1024*512
+extern const file_hint_t file_hint_tar;
+extern const file_hint_t file_hint_dir;
+extern file_check_list_t file_check_list;
+
+pstatus_t photorec_aux(struct ph_param *params, const struct ph_options *options, alloc_data_t *list_search_space)
+{
+ uint64_t offset;
+ unsigned char *buffer_start;
+ unsigned char *buffer_olddata;
+ unsigned char *buffer;
+ time_t start_time;
+ time_t previous_time;
+ time_t next_checkpoint;
+ pstatus_t ind_stop=PSTATUS_OK;
+ unsigned int buffer_size;
+ const unsigned int blocksize=params->blocksize;
+ const unsigned int read_size=(blocksize>65536?blocksize:65536);
+ uint64_t offset_before_back=0;
+ unsigned int back=0;
+ alloc_data_t *current_search_space;
+ file_recovery_t file_recovery;
+ memset(&file_recovery, 0, sizeof(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;
+ start_time=time(NULL);
+ previous_time=start_time;
+ next_checkpoint=start_time+5*60;
+ memset(buffer_olddata,0,blocksize);
+ current_search_space=td_list_entry(list_search_space->list.next, alloc_data_t, list);
+ offset=set_search_start(params, &current_search_space, list_search_space);
+ if(options->verbose > 0)
+ info_list_search_space(list_search_space, current_search_space, params->disk->sector_size, 0, options->verbose);
+ 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));
+ }
+ params->disk->pread(params->disk, buffer, READ_SIZE, offset);
+ while(current_search_space!=list_search_space)
+ {
+ int file_recovered=0;
+ uint64_t old_offset=offset;
+#ifdef DEBUG
+ log_debug("sector %llu\n",
+ (unsigned long long)((offset-params->partition->part_offset)/params->disk->sector_size));
+ if(!(current_search_space->start<=offset && offset<=current_search_space->end))
+ {
+ log_critical("BUG: offset=%llu not in [%llu-%llu]\n",
+ (unsigned long long)(offset/params->disk->sector_size),
+ (unsigned long long)(current_search_space->start/params->disk->sector_size),
+ (unsigned long long)(current_search_space->end/params->disk->sector_size));
+ log_close();
+ 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);
+ 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)
+ {
+ current_search_space=file_found(current_search_space, offset, file_recovery_new.file_stat);
+ file_recovery_new.loc=current_search_space;
+ file_recovery_new.location.start=offset;
+ 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, list_search_space, &current_search_space, &offset);
+ }
+ reset_file_recovery(&file_recovery);
+ 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,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;
+ }
+ }
+ }
+ }
+ if(file_recovery.file_stat!=NULL)
+ {
+ int res=1;
+ /* try to skip ext2/ext3 indirect block */
+ if((params->status==STATUS_EXT2_ON || params->status==STATUS_EXT2_ON_SAVE_EVERYTHING) &&
+ file_recovery.file_size_on_disk>=12*blocksize &&
+ ind_block(buffer,blocksize)!=0)
+ {
+ current_search_space=file_add_data(current_search_space, offset, 0);
+ file_recovery.file_size_on_disk+=blocksize;
+ if(options->verbose > 1)
+ {
+ log_verbose("Skipping sector %10lu/%lu\n",
+ (unsigned long)((offset-params->partition->part_offset)/params->disk->sector_size),
+ (unsigned long)((params->partition->part_size-1)/params->disk->sector_size));
+ }
+ memcpy(buffer, buffer_olddata, blocksize);
+ }
+ else
+ {
+ 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));
+ if(errno==EFBIG)
+ {
+ /* File is too big for the destination filesystem */
+ res=2;
+ }
+ else
+ {
+ /* Warn the user */
+ ind_stop=PSTATUS_ENOSPC;
+ params->offset=file_recovery.location.start;
+ }
+ }
+ }
+ if(ind_stop==PSTATUS_OK)
+ {
+ current_search_space=file_add_data(current_search_space, offset, 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)
+ {
+ if(options->verbose > 1)
+ log_trace("EOF found\n");
+ }
+ }
+ }
+ if(res!=2 && file_recovery.file_stat->file_hint->max_filesize>0 && file_recovery.file_size>=file_recovery.file_stat->file_hint->max_filesize)
+ {
+ res=2;
+ log_verbose("File should not be bigger than %llu, stop adding data\n",
+ (long long unsigned)file_recovery.file_stat->file_hint->max_filesize);
+ }
+ if(res!=2 && file_recovery.file_size + blocksize >= PHOTOREC_MAX_SIZE_32 && is_fat(params->partition))
+ {
+ res=2;
+ log_verbose("File should not be bigger than %llu, stop adding data\n",
+ (long long unsigned)file_recovery.file_stat->file_hint->max_filesize);
+ }
+ if(res==2)
+ {
+ file_recovered=file_finish2(&file_recovery, params, options, list_search_space, &current_search_space, &offset);
+ reset_file_recovery(&file_recovery);
+ if(options->lowmem > 0)
+ forget(list_search_space,current_search_space);
+ }
+ }
+ if(ind_stop!=PSTATUS_OK)
+ {
+ log_info("PhotoRec has been stopped\n");
+ current_search_space=list_search_space;
+ }
+ else if(file_recovered==0)
+ {
+ get_next_sector(list_search_space, &current_search_space,&offset,blocksize);
+ if(offset > offset_before_back)
+ back=0;
+ }
+ else if(file_recovered>0)
+ {
+ /* try to recover the previous file, otherwise stay at the current location */
+ offset_before_back=offset;
+ if(back < 10 &&
+ get_prev_file_header(list_search_space, &current_search_space, &offset)==0)
+ back++;
+ else
+ back=0;
+ }
+ if(current_search_space==list_search_space)
+ {
+#ifdef DEBUG_GET_NEXT_SECTOR
+ log_trace("current_search_space==list_search_space=%p (prev=%p,next=%p)\n",
+ current_search_space, current_search_space->list.prev, current_search_space->list.next);
+ log_trace("End of media\n");
+#endif
+ file_recovered=file_finish2(&file_recovery, params, options, list_search_space, &current_search_space, &offset);
+ reset_file_recovery(&file_recovery);
+ if(options->lowmem > 0)
+ forget(list_search_space,current_search_space);
+ }
+ buffer_olddata+=blocksize;
+ buffer+=blocksize;
+ if(file_recovered==1 ||
+ old_offset+blocksize!=offset ||
+ buffer+read_size>buffer_start+buffer_size)
+ {
+ if(file_recovered==1)
+ memset(buffer_start,0,blocksize);
+ else
+ 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
+ }
+ if(ind_stop==PSTATUS_OK)
+ {
+ 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, params->pass, params, offset, current_time);
+#endif
+ if(file_recovery.file_stat!=NULL)
+ params->offset=file_recovery.location.start;
+ else
+ params->offset=offset;
+ if(current_time >= next_checkpoint)
+ {
+ /* Save current progress */
+ session_save(list_search_space, params, options);
+ next_checkpoint=current_time+5*60;
+ }
+ }
+ }
+ }
+ } /* end while(current_search_space!=list_search_space) */
+ free(buffer_start);
+#ifdef HAVE_NCURSES
+ photorec_info(stdscr, params->file_stats);
+#endif
+ return ind_stop;
+}
diff --git a/src/psearchn.h b/src/psearchn.h
new file mode 100644
index 0000000..481ec00
--- /dev/null
+++ b/src/psearchn.h
@@ -0,0 +1,30 @@
+/*
+
+ File: psearchn.h
+
+ Copyright (C) 2013 Christophe GRENIER <grenier@cgsecurity.org>
+
+ 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 __cplusplus
+extern "C" {
+#endif
+
+pstatus_t photorec_aux(struct ph_param *params, const struct ph_options *options, alloc_data_t *list_search_space);
+
+#ifdef __cplusplus
+} /* closing brace for extern "C" */
+#endif