summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristophe Grenier <grenier@cgsecurity.org>2013-05-19 19:36:32 +0200
committerChristophe Grenier <grenier@cgsecurity.org>2013-05-19 19:36:32 +0200
commit52a3073519c00bd15bbb9f15772ca9faaf53b4c9 (patch)
treed816d5f512374f6504d4d0e8e62612137b1123b0
parenteb755fce2d588e40f4f1359d84695050c37bea5a (diff)
QPhotoRec: functional version
-rw-r--r--src/Makefile.am9
-rw-r--r--src/qmainrec.cpp72
-rw-r--r--src/qphbs.cpp214
-rw-r--r--src/qphotorec.cpp723
-rw-r--r--src/qphotorec.h64
-rw-r--r--src/qphotorec.qrc10
-rw-r--r--src/qpsearch.cpp415
7 files changed, 1404 insertions, 103 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 15370af..d3d621c 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -302,13 +302,13 @@ 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
-qphotorec_SOURCES = qmainrec.cpp qphotorec.cpp qphotorec.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
+qphotorec_SOURCES = qmainrec.cpp qphotorec.cpp qphotorec.h qphotorec.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
-nodist_qphotorec_SOURCES = moc_qphotorec.cpp
+nodist_qphotorec_SOURCES = moc_qphotorec.cpp rcc_qphotorec.cpp
fidentify_SOURCES = fidentify.c common.c common.h phcfg.c phcfg.h setdate.c setdate.h $(file_C) $(file_H) log.c log.h crc.c crc.h fat_common.c suspend_no.c
-CLEANFILES = moc_*.cpp
+CLEANFILES = nodist_qphotorec_SOURCES
DISTCLEANFILES = *~ core
small: $(sbin_PROGRAMS) $(bin_PROGRAMS)
@@ -319,6 +319,9 @@ extras: $(EXTRA_PROGRAMS)
moc_qphotorec.cpp: qphotorec.h
$(MOC) $< -o $@
+rcc_qphotorec.cpp: qphotorec.qrc
+ $(RCC) $< -o $@
+
Android.mk: Makefile.am
androgenizer \
-:PROJECT photorec \
diff --git a/src/qmainrec.cpp b/src/qmainrec.cpp
index 539cd49..fe41de8 100644
--- a/src/qmainrec.cpp
+++ b/src/qmainrec.cpp
@@ -1,11 +1,73 @@
+/*
+
+ File: qmainrec.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 <QApplication>
+#include <stdio.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_TIME_H
+#include <time.h>
+#endif
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
#include "qphotorec.h"
+#include "log.h"
+#include "misc.h"
+#include "dir.h"
+#include "ext2_dir.h"
+#include "ewf.h"
+#include "file_jpg.h"
+#include "ntfs_dir.h"
int main(int argc, char *argv[])
{
- QApplication a(argc, argv);
- QPhotorec *p = new QPhotorec();
- p->showMaximized();
- p->show();
- return a.exec();
+ QApplication a(argc, argv);
+ int log_errno=0;
+ time_t my_time;
+ FILE *log_handle;
+ log_handle=log_open("qphotorec.log", TD_LOG_CREATE, &log_errno);
+#ifdef HAVE_DUP2
+ dup2(fileno(log_handle),2);
+#endif
+ my_time=time(NULL);
+ log_info("\n\n%s",ctime(&my_time));
+ log_info("PhotoRec %s, Data Recovery Utility, %s\nChristophe GRENIER <grenier@cgsecurity.org>\nhttp://www.cgsecurity.org\n", VERSION, TESTDISKDATE);
+ log_info("OS: %s\n" , get_os());
+ log_info("Compiler: %s\n", get_compiler());
+ log_info("Compilation date: %s\n", get_compilation_date());
+ log_info("ext2fs lib: %s, ntfs lib: %s, ewf lib: %s, libjpeg: %s\n",
+ td_ext2fs_version(), td_ntfs_version(), td_ewf_version(), td_jpeg_version());
+
+ QPhotorec *p = new QPhotorec();
+ p->showMaximized();
+ p->show();
+ int ret=a.exec();
+ delete p;
+ log_close();
+ return ret;
}
diff --git a/src/qphbs.cpp b/src/qphbs.cpp
new file mode 100644
index 0000000..0d81d73
--- /dev/null
+++ b/src/qphbs.cpp
@@ -0,0 +1,214 @@
+/*
+
+ File: qphbs.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 <QCoreApplication>
+#include "types.h"
+#include "common.h"
+#include "intrf.h"
+#include "list.h"
+#include "filegen.h"
+#include "log.h"
+#include "file_tar.h"
+#include "pnext.h"
+#include "file_found.h"
+#include "qphotorec.h"
+
+#define READ_SIZE 1024*512
+extern const file_hint_t file_hint_tar;
+extern file_check_list_t file_check_list;
+
+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;
+}
+
+pstatus_t QPhotorec::photorec_find_blocksize(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);
+ alloc_data_t *current_search_space;
+ file_recovery_t file_recovery;
+
+ 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_entry(list_search_space->list.next, 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->offset=offset;
+ QCoreApplication::processEvents();
+ params->disk->pread(params->disk, buffer, READ_SIZE, offset);
+ while(current_search_space!=list_search_space)
+ {
+ uint64_t old_offset=offset;
+ {
+ file_recovery_t file_recovery_new;
+ 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 */
+ }
+ else
+ {
+ 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 *tmp2=td_list_entry_const(tmpl, const 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_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, 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)
+ {
+ int res=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 */
+ 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, &current_search_space, &offset, blocksize);
+ params->offset=offset;
+ }
+ 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_XXX
+ 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
+ }
+ {
+ time_t current_time;
+ current_time=time(NULL);
+ if(current_time>previous_time)
+ {
+ previous_time=current_time;
+ QCoreApplication::processEvents();
+ if(stop_the_recovery)
+ {
+ log_info("PhotoRec has been stopped\n");
+ current_search_space=list_search_space;
+ }
+ }
+ }
+ }
+ } /* end while(current_search_space!=list_search_space) */
+ free(buffer_start);
+ return PSTATUS_OK;
+}
diff --git a/src/qphotorec.cpp b/src/qphotorec.cpp
index 821f8d8..42c4275 100644
--- a/src/qphotorec.cpp
+++ b/src/qphotorec.cpp
@@ -38,15 +38,33 @@
#include <QLayoutItem>
#include <QLabel>
#include <QLayout>
+#include <QTableView>
+#include <QHeaderView>
+#include <QStandardItemModel>
+#include <QStandardItem>
+#include <QSortFilterProxyModel>
+#include <QGroupBox>
+#include <QRadioButton>
+#include <QFileDialog>
+#include <QComboBox>
+#include <QTimer>
+#include <QMessageBox>
#include "types.h"
#include "common.h"
#include "hdcache.h"
#include "hdaccess.h"
#include "fnctdsk.h"
#include "filegen.h"
-#include "photorec.h"
-#include "qphotorec.h"
+#include "sessionp.h"
#include "intrf.h"
+#include "partauto.h"
+#include "phcfg.h"
+#include "log.h"
+#include "log_part.h"
+#include "qphotorec.h"
+
+extern const arch_fnct_t arch_none;
+extern file_enable_t list_file_enable[];
QPhotorec::QPhotorec(QWidget *my_parent) : QWidget(my_parent)
{
@@ -54,6 +72,36 @@ QPhotorec::QPhotorec(QWidget *my_parent) : QWidget(my_parent)
const int testdisk_mode=TESTDISK_O_RDONLY|TESTDISK_O_READAHEAD_32K;
list_disk_t *element_disk;
+ list_disk=NULL;
+ selected_disk=NULL;
+ list_part=NULL;
+ selected_partition=NULL;
+
+ params=(struct ph_param *)MALLOC(sizeof(*params));
+ params->recup_dir=NULL;
+ params->cmd_device=NULL;
+ params->cmd_run=NULL;
+ params->carve_free_space_only=1;
+ params->disk=NULL;
+ params->partition=NULL;
+
+ options=(struct ph_options *)MALLOC(sizeof(*options));
+ options->paranoid=1;
+ options->keep_corrupted_file=0;
+ options->mode_ext2=0;
+ options->expert=0;
+ options->lowmem=0;
+ options->verbose=0;
+ options->list_file_format=list_file_enable;
+ reset_list_file_enable(options->list_file_format);
+
+ stop_the_recovery=false;
+
+ setWindowIcon( QPixmap( ":res/photorec_64x64.png" ) );
+ this->setWindowTitle(tr("QPhotoRec"));
+ QVBoxLayout *mainLayout = new QVBoxLayout();
+ this->setLayout(mainLayout);
+
list_disk=hd_parse(NULL, verbose, testdisk_mode);
hd_update_all_geometry(list_disk, verbose);
@@ -61,152 +109,373 @@ QPhotorec::QPhotorec(QWidget *my_parent) : QWidget(my_parent)
for(element_disk=list_disk;element_disk!=NULL;element_disk=element_disk->next)
element_disk->disk=new_diskcache(element_disk->disk,testdisk_mode);
if(list_disk==NULL)
- no_disk();
- else
- disk_sel();
+ {
+ no_disk_warning();
+ }
+ setupUI();
}
-void QPhotorec::partition_selection(disk_t *disk)
+QPhotorec::~QPhotorec()
{
- list_part_t *list_part;
- list_part_t *element;
- QLabel *t_copy = new QLabel("PhotoRec 6.14-WIP, Data Recovery Utility, May 2012\nChristophe GRENIER <grenier@cgsecurity.org>\nhttp://www.cgsecurity.org");
- QLabel *t_disk = new QLabel(disk->description_short(disk));
- QPushButton *button_proceed = new QPushButton("&Proceed");
- QPushButton *button_quit= new QPushButton("&Quit");
+// session_save(list_search_space, params, options);
+ part_free_list(list_part);
+ delete_list_disk(list_disk);
+ free(options);
+ free(params);
+}
- QWidget *B_widget = new QWidget(this);
- QHBoxLayout *B_layout = new QHBoxLayout(B_widget);
- B_layout->addWidget(button_proceed);
- B_layout->addWidget(button_quit);
- B_widget->setLayout(B_layout);
+void QPhotorec::setExistingDirectory()
+{
+ QString directory = QFileDialog::getExistingDirectory(this,
+ "getExistingDirectory()",
+ directoryLabel->text(),
+ QFileDialog::ShowDirsOnly);
+ if (!directory.isEmpty())
+ {
+ directoryLabel->setText(directory);
+ buttons_updateUI();
+ }
+}
- PartListWidget= new QListWidget();
- list_part=disk->arch->read_part(disk, 0, 0);
+void QPhotorec::partition_selected()
+{
+ if(PartListWidget->selectedItems().count()<=0)
+ return;
+ list_part_t *tmp;
+ const QString& s = PartListWidget->selectedItems()[0]->text();
+ if(s.compare("")==0)
{
- int insert_error=0;
- partition_t *partition_wd;
- partition_wd=new_whole_disk(disk);
- list_part=insert_new_partition(list_part, partition_wd, 0, &insert_error);
- if(insert_error>0)
+ const QString& s2 = PartListWidget->selectedItems()[2]->text();
+ for(tmp=list_part; tmp!=NULL; tmp=tmp->next)
{
- free(partition_wd);
+ partition_t *part=tmp->part;
+ if(part->order==NO_ORDER && s2.compare(arch_none.get_partition_typename(part))==0)
+ {
+ selected_partition=part;
+ buttons_updateUI();
+ return ;
+ }
}
+ return ;
}
- if(list_part==NULL)
- return;
- for(element=list_part; element!=NULL; element=element->next)
+ for(tmp=list_part; tmp!=NULL; tmp=tmp->next)
{
- const char *msg;
- msg=aff_part_aux(AFF_PART_ORDER|AFF_PART_STATUS, disk, element->part);
- PartListWidget->addItem(msg);
+ partition_t *part=tmp->part;
+ if(QString::number(part->order).compare(s)==0)
+ {
+ selected_partition=part;
+ buttons_updateUI();
+ return ;
+ }
}
-
- clearWidgets();
- QLayout *mainLayout = this->layout();
-// this->setWindowTitle(tr("QPhotoRec: partition selection"));
-
- mainLayout->addWidget(t_copy);
- mainLayout->addWidget(t_disk);
- mainLayout->addWidget(PartListWidget);
- mainLayout->addWidget(B_widget);
-
- this->setLayout(mainLayout);
-
- connect( button_quit, SIGNAL(clicked()), qApp, SLOT(quit()) );
-// connect( button_proceed, SIGNAL(clicked()), this, SLOT(partition_selected()));
-// connect( PartListWidget, SIGNAL(itemDoubleClicked(QListWidgetItem *)), this, SLOT(partition_selected()));
}
-void QPhotorec::disk_selected()
+void QPhotorec::PartListWidget_updateUI()
{
- if(HDDlistWidget->selectedItems().count()==1)
+ list_part_t *element;
+ PartListWidget->setRowCount(0);
+ PartListWidget->setSortingEnabled(false);
+ for(element=list_part; element!=NULL; element=element->next)
{
- list_disk_t *element_disk;
- const QString& s = HDDlistWidget->selectedItems()[0]->text();
- for(element_disk=list_disk;element_disk!=NULL;element_disk=element_disk->next)
+ const partition_t *partition=element->part;
+ if(partition->status!=STATUS_EXT_IN_EXT)
{
- disk_t *disk=element_disk->disk;
- if(QString(disk->description_short(disk)).compare(s)==0)
+ const arch_fnct_t *arch=partition->arch;
+ const int currentRow = PartListWidget->rowCount();
+ PartListWidget->setRowCount(currentRow + 1);
+ if(partition->order==NO_ORDER)
+ {
+ QTableWidgetItem *item = new QTableWidgetItem();
+ item->setData(0, "");
+ PartListWidget->setItem(currentRow, 0, item);
+ }
+ else
{
- return partition_selection(disk);
+ QTableWidgetItem *item = new QTableWidgetItem();
+ item->setData(0, partition->order);
+ PartListWidget->setItem(currentRow, 0, item);
+ }
+ {
+ QTableWidgetItem *item=new QTableWidgetItem(QString(get_partition_status(partition)));
+ item->setTextAlignment(Qt::AlignHCenter| Qt::AlignVCenter);
+ PartListWidget->setItem(currentRow, 1, item);
+ }
+ if(arch->get_partition_typename(partition)!=NULL)
+ PartListWidget->setItem(currentRow, 2, new QTableWidgetItem(QString(arch->get_partition_typename(partition))));
+ else if(arch->get_part_type)
+ PartListWidget->setItem(currentRow, 2, new QTableWidgetItem("Sys=" + QString::number(arch->get_part_type(partition))));
+ else
+ PartListWidget->setItem(currentRow, 2, new QTableWidgetItem("Unknown"));
+ if(partition->upart_type>0)
+ {
+ QTableWidgetItem *item=new QTableWidgetItem(QString(arch_none.get_partition_typename(partition)));
+ item->setToolTip(QString(partition->info));
+ PartListWidget->setItem(currentRow, 3, item);
+ }
+ else
+ {
+ PartListWidget->setItem(currentRow, 3, new QTableWidgetItem(""));
+ }
+ {
+ char sizeinfo[32];
+ QTableWidgetItem *item;
+ size_to_unit(partition->part_size, &sizeinfo[0]);
+ item=new QTableWidgetItem(QString(sizeinfo));
+ item->setTextAlignment(Qt::AlignRight | Qt::AlignVCenter);
+ PartListWidget->setItem(currentRow, 4, item);
+ }
+ {
+ QString partname="";
+ if(partition->partname[0]!='\0')
+ {
+ partname.sprintf("[%s]", partition->partname);
+ }
+ if(partition->fsname[0]!='\0')
+ {
+ QString fsname;
+ fsname.sprintf(" [%s]", partition->fsname);
+ partname.append(fsname);
+ }
+ PartListWidget->setItem(currentRow, 5, new QTableWidgetItem(partname));
}
}
}
+ PartListWidget->setSortingEnabled(true);
+ PartListWidget->sortByColumn(0, Qt::AscendingOrder);
+ PartListWidget->resizeColumnsToContents();
}
-void QPhotorec::no_disk()
+void QPhotorec::disk_changed(int index)
{
- this->setWindowTitle(tr("QPhotoRec"));
- QLabel *t_copy = new QLabel("PhotoRec 6.14-WIP, Data Recovery Utility, May 2012\nChristophe GRENIER <grenier@cgsecurity.org>\nhttp://www.cgsecurity.org");
- QLabel *t_free_soft = new QLabel("PhotoRec is free software, and\ncomes with ABSOLUTELY NO WARRANTY.");
- QLabel *t_no_disk = new QLabel("No harddisk found\n");
+ int i;
+ list_disk_t *element_disk;
+ for(element_disk=list_disk, i=0;
+ element_disk!=NULL;
+ element_disk=element_disk->next, i++)
+ {
+ if(i==index)
+ {
+ selected_disk=element_disk->disk;
+ selected_partition=NULL;
+ autodetect_arch(selected_disk, &arch_none);
+ log_info("%s\n", selected_disk->description_short(selected_disk));
+ part_free_list(list_part);
+ list_part=init_list_part(selected_disk, NULL);
+ log_all_partitions(selected_disk, list_part);
+ PartListWidget_updateUI();
+ return;
+ }
+ }
+}
+
+QWidget *QPhotorec::copyright(QWidget * qwparent)
+{
+ QWidget *C_widget = new QWidget(qwparent);
+ QLabel *t_logo=new QLabel(C_widget);
+ QPixmap pixmap_img = QPixmap(":res/photorec_64x64.png");
+ t_logo->setPixmap(pixmap_img);
+
+ QSizePolicy c_sizePolicy(QSizePolicy::Maximum, QSizePolicy::Preferred);
+ t_logo->setSizePolicy(c_sizePolicy);
+
+ QLabel *t_copy=new QLabel(C_widget);
+
+ t_copy->setText( "PhotoRec " + QString(VERSION) + ", Data Recovery Utility, " + QString(TESTDISKDATE) + "<br>\nCopyright (C) Christophe GRENIER &lt;<a href=\"mailto:grenier@cgsecurity.org\">grenier@cgsecurity.org</a>&gt;<br>\n<a href=\"http://www.cgsecurity.org/\">http://www.cgsecurity.org</a>");
+ t_copy->setTextFormat(Qt::RichText);
+ t_copy->setTextInteractionFlags(Qt::TextBrowserInteraction);
+ t_copy->setOpenExternalLinks(true);
+
+ QHBoxLayout *C_layout = new QHBoxLayout(C_widget);
+ C_layout->addStretch(1);
+ C_layout->addWidget(t_logo);
+ C_layout->addWidget(t_copy);
+ C_layout->addStretch(1);
+ C_widget->setLayout(C_layout);
+ return C_widget;
+}
+
+/* TODO replace by a warning */
+int QPhotorec::no_disk_warning()
+{
+ const char *msg;
+ msg="No harddisk found";
#if defined(__CYGWIN__) || defined(__MINGW32__)
- t_no_disk->setText("No harddisk found\n"
- "You need to be administrator to use this program.\n"
- "Under Win9x, use the DOS version instead.\n"
- "Under Vista or later, select this program, right-click and choose \"Run as administrator\".\n");
+ msg="No harddisk found\n"
+ "You need to be administrator to use this program.\n"
+ "Under Win9x, use the DOS version instead.\n"
+ "Under Vista or later, select this program, right-click and choose \"Run as administrator\".";
#elif defined(DJGPP)
#else
#ifdef HAVE_GETEUID
if(geteuid()!=0)
{
- t_no_disk->setText("No harddisk found\n"
- "You need to be root to use PhotoRec.");
+ msg="No harddisk found\n"
+ "You need to be root to use PhotoRec.";
}
#endif
#endif
- QPushButton *button_quit= new QPushButton("&Quit");
-
- QVBoxLayout *mainLayout = new QVBoxLayout();
- mainLayout->addWidget(t_copy);
- mainLayout->addWidget(t_free_soft);
- mainLayout->addWidget(t_no_disk);
- mainLayout->addWidget(button_quit);
- this->setLayout(mainLayout);
- connect( button_quit, SIGNAL(clicked()), qApp, SLOT(quit()) );
+ return QMessageBox::warning(this,"No Disk!", msg, QMessageBox::Ok);
}
+void QPhotorec::buttons_updateUI()
+{
+ if(selected_disk==NULL || selected_partition==NULL)
+ {
+ button_search->setEnabled(false);
+ return ;
+ }
+ if(selected_partition->upart_type==UP_EXT2 || selected_partition->upart_type==UP_EXT3 || selected_partition->upart_type==UP_EXT4)
+ qextRadioButton->setChecked(true);
+ else
+ qfatRadioButton->setChecked(true);
+ switch(selected_partition->upart_type)
+ {
+ case UP_EXFAT:
+ case UP_FAT12:
+ case UP_FAT16:
+ case UP_FAT32:
+#if defined(HAVE_LIBNTFS) || defined(HAVE_LIBNTFS3G)
+ case UP_NTFS:
+#endif
+#ifdef HAVE_LIBEXT2FS
+ case UP_EXT2:
+ case UP_EXT3:
+ case UP_EXT4:
+#endif
+ qfreeRadioButton->setEnabled(true);
+ qfreeRadioButton->setChecked(true);
+ break;
+ default:
+ qwholeRadioButton->setChecked(true);
+ qfreeRadioButton->setEnabled(false);
+ break;
+ }
+ button_search->setEnabled(!directoryLabel->text().isEmpty());
+}
-void QPhotorec::disk_sel()
+void QPhotorec::setupUI()
{
list_disk_t *element_disk;
- this->setWindowTitle(tr("QPhotoRec"));
- QLabel *t_copy = new QLabel("PhotoRec 6.14-WIP, Data Recovery Utility, May 2012\nChristophe GRENIER <grenier@cgsecurity.org>\nhttp://www.cgsecurity.org");
+ QWidget *t_copy = copyright(this);
QLabel *t_free_soft = new QLabel("PhotoRec is free software, and\ncomes with ABSOLUTELY NO WARRANTY.");
- QLabel *t_select = new QLabel("Please select a media");
+ QLabel *t_select = new QLabel("Please select a media to recover from");
- HDDlistWidget = new QListWidget();
+ HDDlistWidget = new QComboBox();
for(element_disk=list_disk;element_disk!=NULL;element_disk=element_disk->next)
{
disk_t *disk=element_disk->disk;
- HDDlistWidget->addItem(disk->description_short(disk));
+ HDDlistWidget->addItem(
+ QIcon::fromTheme("drive-harddisk", QIcon(":res/gnome/drive-harddisk.png")),
+ disk->description_short(disk));
}
HDDlistWidget->setToolTip("Disk capacity must be correctly detected for a successful recovery.\n"
"If a disk listed above has incorrect size, check HD jumper settings, BIOS\n"
"detection, and install the latest OS patches and disk drivers."
);
- QPushButton *button_proceed = new QPushButton("&Proceed");
- QPushButton *button_quit= new QPushButton("&Quit");
+ QStringList oLabel;
+ oLabel.append("");
+ oLabel.append("Flags");
+ oLabel.append("Type");
+ oLabel.append("File System");
+ oLabel.append("Size");
+ oLabel.append("Label");
+
+ PartListWidget= new QTableWidget();
+ PartListWidget->setEditTriggers(QAbstractItemView::NoEditTriggers);
+ PartListWidget->setSelectionBehavior(QAbstractItemView::SelectRows);
+ PartListWidget->setSelectionMode(QAbstractItemView::SingleSelection);
+ PartListWidget->verticalHeader()->hide();
+ PartListWidget->setShowGrid(false);
+ PartListWidget->setColumnCount( 6 );
+ PartListWidget->setHorizontalHeaderLabels( oLabel );
+ PartListWidget_updateUI();
+
+ QGroupBox *groupBox1;
+ QGroupBox *groupBox2;
+
+ groupBox1 = new QGroupBox("File System type");
+ qextRadioButton = new QRadioButton("ext2/ext3/ext4 filesystem");
+ qfatRadioButton = new QRadioButton("FAT/NTFS/HFS+/ReiserFS/...");
+ qfatRadioButton->setChecked(true);
+
+ groupBox2 = new QGroupBox();
+ qfreeRadioButton = new QRadioButton("Free: Scan for file from unallocated space only");
+ qwholeRadioButton = new QRadioButton("Whole: Extract files from whole partition");
+ qfreeRadioButton->setEnabled(false);
+ qwholeRadioButton->setChecked(true);
+
+
+ QVBoxLayout *groupBox1Layout = new QVBoxLayout;
+ QVBoxLayout *groupBox2Layout = new QVBoxLayout;
+
+ groupBox1Layout->addWidget(qextRadioButton);
+ groupBox1Layout->addWidget(qfatRadioButton);
+ groupBox1->setLayout(groupBox1Layout);
+
+ groupBox2Layout->addWidget(qfreeRadioButton);
+ groupBox2Layout->addWidget(qwholeRadioButton);
+ groupBox2->setLayout(groupBox2Layout);
+
+ QWidget *groupBox= new QWidget();
+ QHBoxLayout *groupBoxLayout = new QHBoxLayout;
+ groupBoxLayout->addWidget(groupBox1);
+ groupBoxLayout->addWidget(groupBox2);
+ groupBox->setLayout(groupBoxLayout);
+
+
+ QLabel *dstWidget= new QLabel("Please select a destination to save the recovered files.");
+ directoryLabel=new QLineEdit("");
+ QPushButton *dst_button = new QPushButton(
+ QIcon::fromTheme("folder", QIcon(":res/gnome/folder.png")),
+ "&Browse");
+
+ QWidget *dst_widget= new QWidget(this);
+ QWidget *dst_widget2= new QWidget(this);
+
+ QHBoxLayout *dst_widgetLayout2 = new QHBoxLayout;
+ dst_widgetLayout2->addWidget(directoryLabel);
+ dst_widgetLayout2->addWidget(dst_button);
+ dst_widget2->setLayout(dst_widgetLayout2);
+
+ QVBoxLayout *dst_widgetLayout = new QVBoxLayout;
+ dst_widgetLayout->addWidget(dstWidget);
+ dst_widgetLayout->addWidget(dst_widget2);
+ dst_widget->setLayout(dst_widgetLayout);
+
+
+ button_search = new QPushButton(QIcon::fromTheme("go-next", QIcon(":res/gnome/go-next.png")), "&Search");
+ button_search->setEnabled(false);
+ QPushButton *button_quit= new QPushButton(QIcon::fromTheme("application-exit", QIcon(":res/gnome/application-exit.png")), "&Quit");
QWidget *B_widget = new QWidget(this);
QHBoxLayout *B_layout = new QHBoxLayout(B_widget);
- B_layout->addWidget(button_proceed);
+ B_layout->addWidget(button_search);
B_layout->addWidget(button_quit);
B_widget->setLayout(B_layout);
+ clearWidgets();
+// QLayout *mainLayout = this->layout();
+ delete this->layout();
QVBoxLayout *mainLayout = new QVBoxLayout();
mainLayout->addWidget(t_copy);
mainLayout->addWidget(t_free_soft);
mainLayout->addWidget(t_select);
mainLayout->addWidget(HDDlistWidget);
+ mainLayout->addWidget(PartListWidget);
+ mainLayout->addWidget(groupBox);
+ mainLayout->addWidget(dst_widget);
mainLayout->addWidget(B_widget);
this->setLayout(mainLayout);
- connect( button_quit, SIGNAL(clicked()), qApp, SLOT(quit()) );
- connect( button_proceed, SIGNAL(clicked()), this, SLOT(disk_selected()));
- connect( HDDlistWidget, SIGNAL(itemDoubleClicked(QListWidgetItem *)), this, SLOT(disk_selected()));
+ buttons_updateUI();
+
+ connect(button_search, SIGNAL(clicked()), this, SLOT(qphotorec_search()) );
+ connect(button_quit, SIGNAL(clicked()), qApp, SLOT(quit()) );
+ connect(HDDlistWidget, SIGNAL(activated(int)),this,SLOT(disk_changed(int)));
+ connect(PartListWidget, SIGNAL(itemSelectionChanged()), this, SLOT(partition_selected()));
+ connect(dst_button, SIGNAL(clicked()), this, SLOT(setExistingDirectory()));
+ connect(directoryLabel, SIGNAL(editingFinished()), this, SLOT(buttons_updateUI()));
}
void QPhotorec::clearWidgets()
@@ -217,6 +486,288 @@ void QPhotorec::clearWidgets()
layoutwidget = this->layout()->takeAt(0);
if(layoutwidget==NULL)
return ;
+ layoutwidget->widget()->hide();
layoutwidget->widget()->deleteLater();
}
}
+
+void QPhotorec::photorec_info(const file_stat_t *file_stats)
+{
+ unsigned int i;
+ unsigned int nbr;
+ unsigned int others=0;
+ if(file_stats==NULL)
+ return ;
+ file_stat_t *new_file_stats;
+ filestatsWidget->setRowCount(0);
+ for(i=0;file_stats[i].file_hint!=NULL;i++);
+ nbr=i;
+ if(nbr==0)
+ return ;
+ new_file_stats=(file_stat_t*)MALLOC(nbr*sizeof(file_stat_t));
+ memcpy(new_file_stats, file_stats, nbr*sizeof(file_stat_t));
+ qsort(new_file_stats, nbr, sizeof(file_stat_t), sorfile_stat_ts);
+ for(i=0; i<10 && i<nbr && new_file_stats[i].recovered>0; i++)
+ {
+ QTableWidgetItem *item;
+ filestatsWidget->setRowCount(i+1);
+ if(new_file_stats[i].file_hint->extension!=NULL)
+ {
+ item = new QTableWidgetItem(new_file_stats[i].file_hint->extension);
+ filestatsWidget->setItem(i, 0, item);
+ }
+ item = new QTableWidgetItem();
+ item->setData(0, new_file_stats[i].recovered);
+ filestatsWidget->setItem(i, 1, item);
+ }
+ for(; i<nbr && new_file_stats[i].recovered>0; i++)
+ others+=new_file_stats[i].recovered;
+ if(others>0)
+ {
+ QTableWidgetItem *item;
+ filestatsWidget->setRowCount(11);
+ item = new QTableWidgetItem("others");
+ filestatsWidget->setItem(10, 0, item);
+ item = new QTableWidgetItem();
+ item->setData(0, others);
+ filestatsWidget->setItem(10, 1, item);
+ }
+ free(new_file_stats);
+}
+
+void QPhotorec::qphotorec_search_updateUI()
+{
+ const partition_t *partition=params->partition;
+ const unsigned int sector_size=params->disk->sector_size;
+ QString tmp;
+ if(params->status==STATUS_QUIT)
+ {
+ tmp.sprintf("Recovery completed");
+ }
+ else if(params->status==STATUS_EXT2_ON_BF || params->status==STATUS_EXT2_OFF_BF)
+ {
+ tmp.sprintf("Bruteforce %10lu sectors remaining (test %u)",
+ (unsigned long)((params->offset-partition->part_offset)/sector_size),
+ params->pass);
+ }
+ else
+ {
+ tmp.sprintf("Pass %u - Reading sector %10llu/%llu",
+ params->pass,
+ (unsigned long long)((params->offset-partition->part_offset)/sector_size),
+ (unsigned long long)(partition->part_size/sector_size));
+ }
+ progress_info->setText(tmp);
+
+ if(params->status==STATUS_FIND_OFFSET)
+ tmp.sprintf("%u/10 headers found", params->file_nbr);
+ else
+ tmp.sprintf("%u files found", params->file_nbr);
+ progress_filefound->setText(tmp);
+
+ if(params->status==STATUS_QUIT)
+ {
+ progress_bar->setMinimum(0);
+ progress_bar->setMaximum(100);
+ progress_bar->setValue(100);
+ }
+ else if(params->status==STATUS_FIND_OFFSET)
+ {
+ progress_bar->setMinimum(0);
+ progress_bar->setMaximum(10);
+ progress_bar->setValue(params->file_nbr);
+ }
+ else
+ {
+ progress_bar->setMinimum(0);
+ progress_bar->setMaximum(100);
+ progress_bar->setValue((params->offset-partition->part_offset)*100/ partition->part_size);
+ }
+ photorec_info(params->file_stats);
+}
+
+void QPhotorec::qphotorec_search_setupUI()
+{
+ clearWidgets();
+ delete this->layout();
+ QVBoxLayout *mainLayout = new QVBoxLayout();
+ QWidget *t_copy = copyright(this);
+
+ QSizePolicy c_sizePolicy(QSizePolicy::Maximum, QSizePolicy::Preferred);
+
+ QLabel *disk_img=new QLabel();
+ QPixmap *disk_pixmap = new QPixmap(":res/gnome/drive-harddisk.png");
+ disk_img->setPixmap(*disk_pixmap);
+ disk_img->setSizePolicy(c_sizePolicy);
+
+ QLabel *disk_txt=new QLabel();
+ disk_txt->setText(selected_disk->description_short(selected_disk));
+
+ QWidget *diskWidget = new QWidget();
+ QHBoxLayout *diskWidgetLayout = new QHBoxLayout(diskWidget);
+ diskWidgetLayout->addWidget(disk_img);
+ diskWidgetLayout->addWidget(disk_txt);
+ diskWidget->setLayout(diskWidgetLayout);
+
+ QLabel *folder_img=new QLabel();
+ QPixmap *folder_pixmap = new QPixmap(":res/gnome/folder.png");
+ folder_img->setPixmap(*folder_pixmap);
+ folder_img->setSizePolicy(c_sizePolicy);
+
+ QLabel *folder_txt=new QLabel();
+ folder_txt->setText("Destination: " + directoryLabel->text());
+
+ QWidget *folderWidget = new QWidget();
+ QHBoxLayout *folderWidgetLayout = new QHBoxLayout(folderWidget);
+ folderWidgetLayout->addWidget(folder_img);
+ folderWidgetLayout->addWidget(folder_txt);
+ folderWidget->setLayout(folderWidgetLayout);
+
+
+ progress_info=new QLabel();
+ progress_filefound=new QLabel();
+ progress_bar=new QProgressBar();
+
+ QWidget *progressWidget = new QWidget();
+ QHBoxLayout *progressWidgetLayout = new QHBoxLayout(progressWidget);
+ progressWidgetLayout->addWidget(progress_info);
+ progressWidgetLayout->addWidget(progress_bar);
+ progressWidgetLayout->addWidget(progress_filefound);
+ progressWidget->setLayout(progressWidgetLayout);
+
+ QWidget *progressWidget2 = new QWidget();
+ QHBoxLayout *progressWidgetLayout2 = new QHBoxLayout(progressWidget2);
+// TODO
+// progressWidgetLayout2->addWidget(progress_elapsed);
+// progressWidgetLayout2->addWidget(progress_eta);
+ progressWidget2->setLayout(progressWidgetLayout2);
+
+ QStringList oLabel;
+ oLabel.append("File familly");
+ oLabel.append("Number of file recovered");
+
+ filestatsWidget=new QTableWidget();
+ filestatsWidget->setEditTriggers(QAbstractItemView::NoEditTriggers);
+ filestatsWidget->setSelectionBehavior(QAbstractItemView::SelectRows);
+ filestatsWidget->setSelectionMode(QAbstractItemView::SingleSelection);
+ filestatsWidget->verticalHeader()->hide();
+ filestatsWidget->setColumnCount( 2 );
+ filestatsWidget->setHorizontalHeaderLabels( oLabel );
+ filestatsWidget->resizeColumnsToContents();
+
+ QPushButton *button_quit= new QPushButton(QIcon::fromTheme("application-exit", QIcon(":res/gnome/application-exit.png")), "&Quit");
+ mainLayout->addWidget(t_copy);
+ mainLayout->addWidget(diskWidget);
+ mainLayout->addWidget(folderWidget);
+ mainLayout->addWidget(progressWidget);
+ mainLayout->addWidget(progressWidget2);
+ mainLayout->addWidget(filestatsWidget);
+ mainLayout->addWidget(button_quit);
+ this->setLayout(mainLayout);
+
+ connect( button_quit, SIGNAL(clicked()), this, SLOT(stop_and_quit()) );
+ connect(this, SIGNAL(finished()), qApp, SLOT(quit()));
+
+ timer = new QTimer(this);
+ timer->setInterval(500);
+ connect(timer, SIGNAL(timeout()), this, SLOT(qphotorec_search_updateUI()));
+}
+
+void QPhotorec::stop_and_quit()
+{
+ stop_the_recovery=true;
+ emit finished();
+}
+
+int QPhotorec::photorec(alloc_data_t *list_search_space)
+{
+ pstatus_t ind_stop=PSTATUS_OK;
+ const unsigned int blocksize_is_known=params->blocksize;
+ params_reset(params, options);
+ /* make the first recup_dir */
+ params->dir_num=photorec_mkdir(params->recup_dir, params->dir_num);
+ for(params->pass=0; params->status!=STATUS_QUIT; params->pass++)
+ {
+ timer->start();
+ switch(params->status)
+ {
+ case STATUS_UNFORMAT:
+ /* FIXME */
+ break;
+ case STATUS_FIND_OFFSET:
+ {
+ uint64_t start_offset=0;
+ if(blocksize_is_known>0)
+ {
+ ind_stop=PSTATUS_OK;
+ if(!td_list_empty(&list_search_space->list))
+ start_offset=(td_list_entry(list_search_space->list.next, alloc_data_t, list))->start % params->blocksize;
+ }
+ else
+ {
+ ind_stop=photorec_find_blocksize(list_search_space);
+ params->blocksize=find_blocksize(list_search_space, params->disk->sector_size, &start_offset);
+ }
+ update_blocksize(params->blocksize, list_search_space, start_offset);
+ }
+ break;
+ case STATUS_EXT2_ON_BF:
+ case STATUS_EXT2_OFF_BF:
+ /* FIXME */
+ break;
+ default:
+ ind_stop=photorec_aux(list_search_space);
+ break;
+ }
+ timer->stop();
+ qphotorec_search_updateUI();
+ session_save(list_search_space, params, options);
+ switch(ind_stop)
+ {
+ case PSTATUS_OK:
+ status_inc(params, options);
+ if(params->status==STATUS_QUIT)
+ unlink("photorec.ses");
+ break;
+ case PSTATUS_STOP:
+ params->status=STATUS_QUIT;
+ break;
+ }
+ update_stats(params->file_stats, list_search_space);
+ qphotorec_search_updateUI();
+ }
+ free_search_space(list_search_space);
+ free_header_check();
+ free(params->file_stats);
+ params->file_stats=NULL;
+ return 0;
+}
+
+void QPhotorec::qphotorec_search()
+{
+ if(selected_disk==NULL || selected_partition==NULL)
+ return;
+ static alloc_data_t list_search_space={
+ .list = TD_LIST_HEAD_INIT(list_search_space.list)
+ };
+
+ QByteArray byteArray = (directoryLabel->text() + "/" + DEFAULT_RECUP_DIR).toUtf8();
+ params->recup_dir=strdup(byteArray.constData());
+ params->carve_free_space_only=qfreeRadioButton->isChecked();
+ params->disk=selected_disk;
+ params->partition=selected_partition;
+ log_partition(selected_disk, selected_partition);
+
+ options->mode_ext2=qextRadioButton->isChecked();
+
+ qphotorec_search_setupUI();
+ if(td_list_empty(&list_search_space.list))
+ {
+ init_search_space(&list_search_space, params->disk, params->partition);
+ }
+ if(params->carve_free_space_only>0)
+ {
+ params->blocksize=remove_used_space(params->disk, params->partition, &list_search_space);
+ }
+ photorec(&list_search_space);
+}
diff --git a/src/qphotorec.h b/src/qphotorec.h
index 072211d..f5efb36 100644
--- a/src/qphotorec.h
+++ b/src/qphotorec.h
@@ -16,9 +16,17 @@
#endif
#include <QWidget>
#include <QListWidget>
+#include <QComboBox>
+#include <QTableWidget>
#include <QPushButton>
+#include <QLabel>
+#include <QLineEdit>
+#include <QRadioButton>
+#include <QProgressBar>
#include "types.h"
#include "common.h"
+#include "filegen.h"
+#include "photorec.h"
class QPhotorec: public QWidget
{
@@ -26,16 +34,54 @@ class QPhotorec: public QWidget
public:
QPhotorec(QWidget *parent = 0);
- void disk_sel();
- void no_disk();
- void partition_selection(disk_t *disk);
+ ~QPhotorec();
private slots:
- void disk_selected();
- private:
- QListWidget *HDDlistWidget;
- QListWidget *PartListWidget;
- QPushButton *btn;
- list_disk_t *list_disk;
+ /* Setup recovery UI */
+ void disk_changed(int index);
+ void partition_selected();
+ void setExistingDirectory();
+ void qphotorec_search();
+ void buttons_updateUI();
+ /* Recovery UI */
+ void qphotorec_search_updateUI();
+ void stop_and_quit();
+ protected:
+ void setupUI();
void clearWidgets();
+ int no_disk_warning();
+ QWidget *copyright(QWidget * qwparent = 0);
+ QTableWidgetItem *offset_to_item(const disk_t *disk, const uint64_t offset);
+ void PartListWidget_updateUI();
+ int photorec(alloc_data_t *list_search_space);
+ pstatus_t photorec_find_blocksize(alloc_data_t *list_search_space);
+ pstatus_t photorec_aux(alloc_data_t *list_search_space);
+ void qphotorec_search_setupUI();
+ void photorec_info(const file_stat_t *file_stats);
+ signals:
+ void finished();
+ private:
+ /* */
+ list_disk_t *list_disk;
+ disk_t *selected_disk;
+ list_part_t *list_part;
+ partition_t *selected_partition;
+ struct ph_param *params;
+ struct ph_options *options;
+ bool stop_the_recovery;
+ /* Setup recovery UI */
+ QComboBox *HDDlistWidget;
+ QTableWidget *PartListWidget;
+ QLineEdit *directoryLabel;
+ QPushButton *button_search;
+ QRadioButton *qextRadioButton;
+ QRadioButton *qfatRadioButton;
+ QRadioButton *qfreeRadioButton;
+ QRadioButton *qwholeRadioButton;
+ /* Recovery UI */
+ QLabel *progress_info;
+ QLabel *progress_filefound;
+ QProgressBar *progress_bar;
+ QTimer *timer;
+ QTableWidget *filestatsWidget;
};
#endif
diff --git a/src/qphotorec.qrc b/src/qphotorec.qrc
new file mode 100644
index 0000000..d870e9e
--- /dev/null
+++ b/src/qphotorec.qrc
@@ -0,0 +1,10 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource prefix="/res">
+<file>photorec_64x64.png</file>
+<file>gnome/application-exit.png</file>
+<file>gnome/drive-harddisk.png</file>
+<file>gnome/folder.png</file>
+<file>gnome/go-next.png</file>
+<file>gnome/go-previous.png</file>
+</qresource>
+</RCC>
diff --git a/src/qpsearch.cpp b/src/qpsearch.cpp
new file mode 100644
index 0000000..45af322
--- /dev/null
+++ b/src/qpsearch.cpp
@@ -0,0 +1,415 @@
+/*
+
+ File: qpsearch.cpp
+
+ 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_UNISTD_H
+#include <unistd.h>
+#endif
+#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
+#ifdef HAVE_WINDEF_H
+#include <windef.h>
+#endif
+#ifdef HAVE_WINBASE_H
+#include <stdarg.h>
+#include <winbase.h>
+#endif
+#include <QCoreApplication>
+#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 "sessionp.h"
+#include "log.h"
+#include "file_tar.h"
+#include "pnext.h"
+#include "file_found.h"
+#include "psearch.h"
+#include "qphotorec.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;
+
+#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)
+{
+ 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 *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)
+ {
+ 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)
+ {
+ }
+ if(ind_stop==PSTATUS_OK)
+ {
+ time_t current_time;
+ current_time=time(NULL);
+ if(current_time > previous_time)
+ {
+ previous_time=current_time;
+ QCoreApplication::processEvents();
+ 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 */
+ session_save(list_search_space, params, options);
+ next_checkpoint=current_time+5*60;
+ }
+ }
+ }
+ }
+ } /* end while(current_search_space!=list_search_space) */
+ free(buffer_start);
+ return ind_stop;
+}