QPhotoRec: update the algo to match the one from PhotoRec
This commit is contained in:
parent
c0e81e1f92
commit
37b48a9fd6
6 changed files with 205 additions and 296 deletions
|
@ -360,7 +360,7 @@ photorec_C = photorec.c phcfg.c addpart.c chgarch.c dir.c exfatp.c ext2grp.c ex
|
||||||
photorec_H = photorec.h phcfg.h addpart.h chgarch.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 pdisksel.h phcli.h poptions.h sessionp.h setdate.h dfxml.h
|
photorec_H = photorec.h phcfg.h addpart.h chgarch.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 pdisksel.h phcli.h poptions.h sessionp.h setdate.h dfxml.h
|
||||||
|
|
||||||
photorec_ncurses_C = addpartn.c askloc.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 pdiskseln.c pfree_whole.c phbf.c phbs.c phnc.c phrecn.c ppartseln.c psearchn.c
|
photorec_ncurses_C = addpartn.c askloc.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 pdiskseln.c pfree_whole.c phbf.c phbs.c phnc.c phrecn.c ppartseln.c psearchn.c
|
||||||
photorec_ncurses_H = addpartn.h askloc.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 pdiskseln.h pfree_whole.h pnext.h phbf.h phbs.h phnc.h phrecn.h ppartseln.h psearch.h psearchn.h
|
photorec_ncurses_H = addpartn.h askloc.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 pdiskseln.h pfree_whole.h pnext.h phbf.h phbs.h phnc.h phrecn.h ppartseln.h psearch.h psearchn.h photorec_check_header.h
|
||||||
|
|
||||||
QT_TS = \
|
QT_TS = \
|
||||||
lang/qphotorec.ca.ts \
|
lang/qphotorec.ca.ts \
|
||||||
|
@ -375,7 +375,7 @@ photorec_SOURCES = phmain.c $(photorec_C) $(photorec_H) $(photorec_ncurses_C) $(
|
||||||
|
|
||||||
photorecf_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.c
|
photorecf_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.c
|
||||||
|
|
||||||
qphotorec_SOURCES = qmainrec.cpp qphotorec.cpp qphotorec.h qphotorec.qrc qphotorec_locale.qrc qphbs.cpp qpsearch.cpp psearch.h chgtype.c chgtype.h $(photorec_C) $(photorec_H) $(file_C) $(file_H) $(base_C) $(base_H) partgptro.c $(fs_C) $(fs_H) $(ICON_QPHOTOREC) suspend_no.c $(QT_TS)
|
qphotorec_SOURCES = qmainrec.cpp qphotorec.cpp qphotorec.h qphotorec.qrc qphotorec_locale.qrc qphbs.cpp qpsearch.cpp photorec_check_header.h psearch.h chgtype.c chgtype.h $(photorec_C) $(photorec_H) $(file_C) $(file_H) $(base_C) $(base_H) partgptro.c $(fs_C) $(fs_H) $(ICON_QPHOTOREC) suspend_no.c $(QT_TS)
|
||||||
|
|
||||||
nodist_qphotorec_SOURCES = moc_qphotorec.cpp rcc_qphotorec.cpp rcc_qphotorec_locale.cpp
|
nodist_qphotorec_SOURCES = moc_qphotorec.cpp rcc_qphotorec.cpp rcc_qphotorec_locale.cpp
|
||||||
|
|
||||||
|
|
166
src/photorec_check_header.h
Normal file
166
src/photorec_check_header.h
Normal file
|
@ -0,0 +1,166 @@
|
||||||
|
/*
|
||||||
|
|
||||||
|
File: photorec_check_header.h
|
||||||
|
|
||||||
|
Copyright (C) 2002-2018 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
|
||||||
|
extern const file_hint_t file_hint_tar;
|
||||||
|
extern const file_hint_t file_hint_dir;
|
||||||
|
extern file_check_list_t file_check_list;
|
||||||
|
|
||||||
|
#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 *
|
||||||
|
* antivirus is scanning it, so let's wait a little bit if the creation *
|
||||||
|
* failed. */
|
||||||
|
|
||||||
|
#ifndef HAVE_SLEEP
|
||||||
|
#define sleep(x) Sleep((x)*1000)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static FILE *fopen_with_retry(const char *path, const char *mode)
|
||||||
|
{
|
||||||
|
FILE *handle;
|
||||||
|
if((handle=fopen(path, mode))!=NULL)
|
||||||
|
return handle;
|
||||||
|
#ifdef __MINGW32__
|
||||||
|
Sleep(1000);
|
||||||
|
#else
|
||||||
|
sleep(1);
|
||||||
|
#endif
|
||||||
|
if((handle=fopen(path, mode))!=NULL)
|
||||||
|
return handle;
|
||||||
|
#ifdef __MINGW32__
|
||||||
|
Sleep(2000);
|
||||||
|
#else
|
||||||
|
sleep(2);
|
||||||
|
#endif
|
||||||
|
if((handle=fopen(path, mode))!=NULL)
|
||||||
|
return handle;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
#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;
|
||||||
|
TD_INIT_LIST_HEAD(&dir_list.list);
|
||||||
|
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, pfstatus_t *file_recovered, const uint64_t offset)
|
||||||
|
{
|
||||||
|
*file_recovered=PFSTATUS_BAD;
|
||||||
|
if(file_recovery_new->file_stat==NULL || file_recovery_new->file_stat->file_hint==NULL)
|
||||||
|
return PSTATUS_OK;
|
||||||
|
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==PFSTATUS_OK_TRUNCATED)
|
||||||
|
return PSTATUS_OK;
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline 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, pfstatus_t *file_recovered, const uint64_t offset)
|
||||||
|
{
|
||||||
|
const 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==&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;
|
||||||
|
file_recovery_new.location.start=offset;
|
||||||
|
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);
|
||||||
|
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, offset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return PSTATUS_OK;
|
||||||
|
}
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} /* closing brace for extern "C" */
|
||||||
|
#endif
|
152
src/psearchn.c
152
src/psearchn.c
|
@ -68,147 +68,8 @@
|
||||||
#include "phnc.h"
|
#include "phnc.h"
|
||||||
#endif
|
#endif
|
||||||
#include "psearchn.h"
|
#include "psearchn.h"
|
||||||
|
#include "photorec_check_header.h"
|
||||||
#define READ_SIZE 1024*512
|
#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;
|
|
||||||
|
|
||||||
#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 *
|
|
||||||
* antivirus is scanning it, so let's wait a little bit if the creation *
|
|
||||||
* failed. */
|
|
||||||
|
|
||||||
#ifndef HAVE_SLEEP
|
|
||||||
#define sleep(x) Sleep((x)*1000)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static FILE *fopen_with_retry(const char *path, const char *mode)
|
|
||||||
{
|
|
||||||
FILE *handle;
|
|
||||||
if((handle=fopen(path, mode))!=NULL)
|
|
||||||
return handle;
|
|
||||||
#ifdef __MINGW32__
|
|
||||||
Sleep(1000);
|
|
||||||
#else
|
|
||||||
sleep(1);
|
|
||||||
#endif
|
|
||||||
if((handle=fopen(path, mode))!=NULL)
|
|
||||||
return handle;
|
|
||||||
#ifdef __MINGW32__
|
|
||||||
Sleep(2000);
|
|
||||||
#else
|
|
||||||
sleep(2);
|
|
||||||
#endif
|
|
||||||
if((handle=fopen(path, mode))!=NULL)
|
|
||||||
return handle;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
#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;
|
|
||||||
TD_INIT_LIST_HEAD(&dir_list.list);
|
|
||||||
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, pfstatus_t *file_recovered, const uint64_t offset)
|
|
||||||
{
|
|
||||||
*file_recovered=PFSTATUS_BAD;
|
|
||||||
if(file_recovery_new->file_stat==NULL || file_recovery_new->file_stat->file_hint==NULL)
|
|
||||||
return PSTATUS_OK;
|
|
||||||
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==PFSTATUS_OK_TRUNCATED)
|
|
||||||
return PSTATUS_OK;
|
|
||||||
}
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline 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, pfstatus_t *file_recovered, const uint64_t offset)
|
|
||||||
{
|
|
||||||
const 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==&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;
|
|
||||||
file_recovery_new.location.start=offset;
|
|
||||||
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);
|
|
||||||
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, offset);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return PSTATUS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
pstatus_t photorec_aux(struct ph_param *params, const struct ph_options *options, alloc_data_t *list_search_space)
|
pstatus_t photorec_aux(struct ph_param *params, const struct ph_options *options, alloc_data_t *list_search_space)
|
||||||
{
|
{
|
||||||
|
@ -422,15 +283,6 @@ pstatus_t photorec_aux(struct ph_param *params, const struct ph_options *options
|
||||||
ind_stop=photorec_progressbar(stdscr, params->pass, params, offset, current_time);
|
ind_stop=photorec_progressbar(stdscr, params->pass, params, offset, current_time);
|
||||||
#endif
|
#endif
|
||||||
params->offset=offset;
|
params->offset=offset;
|
||||||
if(current_time >= next_checkpoint)
|
|
||||||
{
|
|
||||||
time_t new_time;
|
|
||||||
/* Save current progress */
|
|
||||||
session_save(list_search_space, params, options);
|
|
||||||
new_time=time(NULL);
|
|
||||||
/* If it takes more then 30s to save the session, save every 15 minutes instead of every 5 minutes */
|
|
||||||
next_checkpoint=new_time+(current_time+30<new_time?15:5)*60;
|
|
||||||
}
|
|
||||||
if(ind_stop!=PSTATUS_OK)
|
if(ind_stop!=PSTATUS_OK)
|
||||||
{
|
{
|
||||||
log_info("PhotoRec has been stopped\n");
|
log_info("PhotoRec has been stopped\n");
|
||||||
|
@ -438,6 +290,8 @@ pstatus_t photorec_aux(struct ph_param *params, const struct ph_options *options
|
||||||
free(buffer_start);
|
free(buffer_start);
|
||||||
return ind_stop;
|
return ind_stop;
|
||||||
}
|
}
|
||||||
|
if(current_time >= next_checkpoint)
|
||||||
|
next_checkpoint=regular_session_save(list_search_space, params, options, current_time);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
168
src/qpsearch.cpp
168
src/qpsearch.cpp
|
@ -65,44 +65,8 @@
|
||||||
#include "file_found.h"
|
#include "file_found.h"
|
||||||
#include "psearch.h"
|
#include "psearch.h"
|
||||||
#include "qphotorec.h"
|
#include "qphotorec.h"
|
||||||
|
#include "photorec_check_header.h"
|
||||||
#define READ_SIZE 1024*512
|
#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;
|
|
||||||
|
|
||||||
#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 *
|
|
||||||
* antivirus is scanning it, so let's wait a little bit if the creation *
|
|
||||||
* failed. */
|
|
||||||
|
|
||||||
#ifndef HAVE_SLEEP
|
|
||||||
#define sleep(x) Sleep((x)*1000)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static FILE *fopen_with_retry(const char *path, const char *mode)
|
|
||||||
{
|
|
||||||
FILE *handle;
|
|
||||||
if((handle=fopen(path, mode))!=NULL)
|
|
||||||
return handle;
|
|
||||||
#ifdef __MINGW32__
|
|
||||||
Sleep(1000);
|
|
||||||
#else
|
|
||||||
sleep(1);
|
|
||||||
#endif
|
|
||||||
if((handle=fopen(path, mode))!=NULL)
|
|
||||||
return handle;
|
|
||||||
#ifdef __MINGW32__
|
|
||||||
Sleep(2000);
|
|
||||||
#else
|
|
||||||
sleep(2);
|
|
||||||
#endif
|
|
||||||
if((handle=fopen(path, mode))!=NULL)
|
|
||||||
return handle;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
pstatus_t QPhotorec::photorec_aux(alloc_data_t *list_search_space)
|
pstatus_t QPhotorec::photorec_aux(alloc_data_t *list_search_space)
|
||||||
{
|
{
|
||||||
|
@ -132,7 +96,7 @@ pstatus_t QPhotorec::photorec_aux(alloc_data_t *list_search_space)
|
||||||
previous_time=start_time;
|
previous_time=start_time;
|
||||||
next_checkpoint=start_time+5*60;
|
next_checkpoint=start_time+5*60;
|
||||||
memset(buffer_olddata,0,blocksize);
|
memset(buffer_olddata,0,blocksize);
|
||||||
current_search_space=td_list_entry(list_search_space->list.next, alloc_data_t, list);
|
current_search_space=td_list_first_entry(&list_search_space->list, alloc_data_t, list);
|
||||||
offset=set_search_start(params, ¤t_search_space, list_search_space);
|
offset=set_search_start(params, ¤t_search_space, list_search_space);
|
||||||
if(options->verbose > 0)
|
if(options->verbose > 0)
|
||||||
info_list_search_space(list_search_space, current_search_space, params->disk->sector_size, 0, options->verbose);
|
info_list_search_space(list_search_space, current_search_space, params->disk->sector_size, 0, options->verbose);
|
||||||
|
@ -143,11 +107,12 @@ pstatus_t QPhotorec::photorec_aux(alloc_data_t *list_search_space)
|
||||||
(unsigned long long)((params->partition->part_size-1)/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);
|
params->disk->pread(params->disk, buffer, READ_SIZE, offset);
|
||||||
|
header_ignored(NULL);
|
||||||
while(current_search_space!=list_search_space)
|
while(current_search_space!=list_search_space)
|
||||||
{
|
{
|
||||||
data_check_t res=DC_SCAN;
|
pfstatus_t file_recovered=PFSTATUS_BAD;
|
||||||
int file_recovered=0;
|
|
||||||
uint64_t old_offset=offset;
|
uint64_t old_offset=offset;
|
||||||
|
data_check_t res=DC_SCAN;
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
log_debug("sector %llu\n",
|
log_debug("sector %llu\n",
|
||||||
(unsigned long long)((offset-params->partition->part_offset)/params->disk->sector_size));
|
(unsigned long long)((offset-params->partition->part_offset)/params->disk->sector_size));
|
||||||
|
@ -161,98 +126,7 @@ pstatus_t QPhotorec::photorec_aux(alloc_data_t *list_search_space)
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
{
|
ind_stop=photorec_check_header(&file_recovery, params, options, list_search_space, buffer, &file_recovered, offset);
|
||||||
file_recovery_t file_recovery_new;
|
|
||||||
file_recovery_new.blocksize=blocksize;
|
|
||||||
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 *tmp2=td_list_entry(tmpl, file_check_list_t, list);
|
|
||||||
td_list_for_each(tmp, &tmp2->file_checks[buffer[tmp2->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;
|
|
||||||
TD_INIT_LIST_HEAD(&dir_list.list);
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(file_recovery.file_stat!=NULL)
|
if(file_recovery.file_stat!=NULL)
|
||||||
{
|
{
|
||||||
/* try to skip ext2/ext3 indirect block */
|
/* try to skip ext2/ext3 indirect block */
|
||||||
|
@ -319,6 +193,8 @@ pstatus_t QPhotorec::photorec_aux(alloc_data_t *list_search_space)
|
||||||
}
|
}
|
||||||
if(res==DC_STOP || res==DC_ERROR)
|
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);
|
file_recovered=file_finish2(&file_recovery, params, options->paranoid, list_search_space);
|
||||||
if(options->lowmem > 0)
|
if(options->lowmem > 0)
|
||||||
forget(list_search_space,current_search_space);
|
forget(list_search_space,current_search_space);
|
||||||
|
@ -327,9 +203,11 @@ pstatus_t QPhotorec::photorec_aux(alloc_data_t *list_search_space)
|
||||||
if(ind_stop!=PSTATUS_OK)
|
if(ind_stop!=PSTATUS_OK)
|
||||||
{
|
{
|
||||||
log_info("PhotoRec has been stopped\n");
|
log_info("PhotoRec has been stopped\n");
|
||||||
current_search_space=list_search_space;
|
file_recovery_aborted(&file_recovery, params, list_search_space);
|
||||||
|
free(buffer_start);
|
||||||
|
return ind_stop;
|
||||||
}
|
}
|
||||||
else if(file_recovered==PFSTATUS_BAD)
|
if(file_recovered==PFSTATUS_BAD)
|
||||||
{
|
{
|
||||||
if(res==DC_SCAN)
|
if(res==DC_SCAN)
|
||||||
{
|
{
|
||||||
|
@ -360,16 +238,18 @@ pstatus_t QPhotorec::photorec_aux(alloc_data_t *list_search_space)
|
||||||
log_trace("End of media\n");
|
log_trace("End of media\n");
|
||||||
#endif
|
#endif
|
||||||
file_recovered=file_finish2(&file_recovery, params, options->paranoid, list_search_space);
|
file_recovered=file_finish2(&file_recovery, params, options->paranoid, list_search_space);
|
||||||
|
if(file_recovered!=PFSTATUS_BAD)
|
||||||
|
get_prev_location_smart(list_search_space, ¤t_search_space, &offset, file_recovery.location.start);
|
||||||
if(options->lowmem > 0)
|
if(options->lowmem > 0)
|
||||||
forget(list_search_space,current_search_space);
|
forget(list_search_space,current_search_space);
|
||||||
}
|
}
|
||||||
buffer_olddata+=blocksize;
|
buffer_olddata+=blocksize;
|
||||||
buffer+=blocksize;
|
buffer+=blocksize;
|
||||||
if(file_recovered==1 ||
|
if(file_recovered!=PFSTATUS_BAD ||
|
||||||
old_offset+blocksize!=offset ||
|
old_offset+blocksize!=offset ||
|
||||||
buffer+read_size>buffer_start+buffer_size)
|
buffer+read_size>buffer_start+buffer_size)
|
||||||
{
|
{
|
||||||
if(file_recovered==1)
|
if(file_recovered!=PFSTATUS_BAD)
|
||||||
memset(buffer_start,0,blocksize);
|
memset(buffer_start,0,blocksize);
|
||||||
else
|
else
|
||||||
memcpy(buffer_start,buffer_olddata,blocksize);
|
memcpy(buffer_start,buffer_olddata,blocksize);
|
||||||
|
@ -391,18 +271,16 @@ pstatus_t QPhotorec::photorec_aux(alloc_data_t *list_search_space)
|
||||||
{
|
{
|
||||||
previous_time=current_time;
|
previous_time=current_time;
|
||||||
QCoreApplication::processEvents();
|
QCoreApplication::processEvents();
|
||||||
|
params->offset=offset;
|
||||||
if(stop_the_recovery)
|
if(stop_the_recovery)
|
||||||
ind_stop=PSTATUS_STOP;
|
|
||||||
if(file_recovery.file_stat!=NULL)
|
|
||||||
params->offset=file_recovery.location.start;
|
|
||||||
else
|
|
||||||
params->offset=offset;
|
|
||||||
if(current_time >= next_checkpoint)
|
|
||||||
{
|
{
|
||||||
/* Save current progress */
|
log_info("QPhotoRec has been stopped\n");
|
||||||
session_save(list_search_space, params, options);
|
file_recovery_aborted(&file_recovery, params, list_search_space);
|
||||||
next_checkpoint=current_time+5*60;
|
free(buffer_start);
|
||||||
|
return PSTATUS_STOP;
|
||||||
}
|
}
|
||||||
|
if(current_time >= next_checkpoint)
|
||||||
|
next_checkpoint=regular_session_save(list_search_space, params, options, current_time);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -317,3 +317,13 @@ int session_save(alloc_data_t *list_free_space, struct ph_param *params, const
|
||||||
fclose(f_session);
|
fclose(f_session);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
time_t regular_session_save(alloc_data_t *list_free_space, struct ph_param *params, const struct ph_options *options, time_t current_time)
|
||||||
|
{
|
||||||
|
time_t new_time;
|
||||||
|
/* Save current progress */
|
||||||
|
session_save(list_free_space, params, options);
|
||||||
|
new_time=time(NULL);
|
||||||
|
/* If it takes more then 30s to save the session, save every 15 minutes instead of every 5 minutes */
|
||||||
|
return new_time+(current_time+30<new_time?15:5)*60;
|
||||||
|
}
|
||||||
|
|
|
@ -25,6 +25,7 @@ extern "C" {
|
||||||
|
|
||||||
int session_load(char **cmd_device, char **current_cmd, alloc_data_t *list_free_space);
|
int session_load(char **cmd_device, char **current_cmd, alloc_data_t *list_free_space);
|
||||||
int session_save(alloc_data_t *list_free_space, struct ph_param *params, const struct ph_options *options);
|
int session_save(alloc_data_t *list_free_space, struct ph_param *params, const struct ph_options *options);
|
||||||
|
time_t regular_session_save(alloc_data_t *list_free_space, struct ph_param *params, const struct ph_options *options, time_t current_time);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
} /* closing brace for extern "C" */
|
} /* closing brace for extern "C" */
|
||||||
|
|
Loading…
Reference in a new issue