1 /*
2
3 File: qphotorec.cpp
4
5 Copyright (C) 2009-2014 Christophe GRENIER <grenier@cgsecurity.org>
6
7 This software is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License along
18 with this program; if not, write the Free Software Foundation, Inc., 51
19 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20
21 */
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26 #ifdef HAVE_STDLIB_H
27 #include <stdlib.h>
28 #endif
29 #include <stdarg.h>
30 #ifdef HAVE_UNISTD_H
31 #include <unistd.h> /* unlink, ftruncate */
32 #endif
33 #ifdef HAVE_STRING_H
34 #include <string.h>
35 #endif
36 #ifdef HAVE_TIME_H
37 #include <time.h>
38 #endif
39 #ifdef HAVE_SYS_TIME_H
40 #include <sys/time.h>
41 #endif
42 #ifdef HAVE_SYS_STAT_H
43 #include <sys/stat.h>
44 #endif
45 #include <ctype.h> /* tolower */
46 #ifdef HAVE_LOCALE_H
47 #include <locale.h> /* setlocale */
48 #endif
49 #ifdef HAVE_SIGNAL_H
50 #include <signal.h>
51 #endif
52 #ifdef HAVE_SYS_WAIT_H
53 #include <sys/wait.h>
54 #endif
55 #include <errno.h>
56 #ifdef HAVE_TIME_H
57 #include <time.h>
58 #endif
59 #include <QApplication>
60 #include <QLayoutItem>
61 #include <QLabel>
62 #include <QLayout>
63 #include <QTableView>
64 #include <QHeaderView>
65 #include <QStandardItemModel>
66 #include <QStandardItem>
67 #include <QDialogButtonBox>
68 #include <QSortFilterProxyModel>
69 #include <QGroupBox>
70 #include <QRadioButton>
71 #include <QFileDialog>
72 #include <QComboBox>
73 #include <QTimer>
74 #include <QMessageBox>
75 #include <QTextDocument>
76 #include "types.h"
77 #include "common.h"
78 #include "hdcache.h"
79 #include "hdaccess.h"
80 #include "fnctdsk.h"
81 #include "filegen.h"
82 #include "sessionp.h"
83 #include "intrf.h"
84 #include "partauto.h"
85 #include "phcfg.h"
86 #include "log.h"
87 #include "log_part.h"
88 #include "qphotorec.h"
89
90 extern const arch_fnct_t arch_none;
91 extern file_enable_t list_file_enable[];
92
QPhotorec(QWidget * my_parent)93 QPhotorec::QPhotorec(QWidget *my_parent) : QWidget(my_parent)
94 {
95 const int verbose=1;
96 const int testdisk_mode=TESTDISK_O_RDONLY|TESTDISK_O_READAHEAD_32K;
97 list_disk_t *element_disk;
98
99 list_disk=NULL;
100 selected_disk=NULL;
101 list_part=NULL;
102 selected_partition=NULL;
103
104 params=(struct ph_param *)MALLOC(sizeof(*params));
105 params->recup_dir=NULL;
106 params->cmd_device=NULL;
107 params->cmd_run=NULL;
108 params->carve_free_space_only=1;
109 params->disk=NULL;
110 params->partition=NULL;
111
112 options=(struct ph_options *)MALLOC(sizeof(*options));
113 options->paranoid=1;
114 options->keep_corrupted_file=0;
115 options->mode_ext2=0;
116 options->expert=0;
117 options->lowmem=0;
118 options->verbose=0;
119 options->list_file_format=list_file_enable;
120 reset_list_file_enable(options->list_file_format);
121
122 stop_the_recovery=false;
123
124 setWindowIcon( QPixmap( ":res/photorec_64x64.png" ) );
125 this->setWindowTitle(tr("QPhotoRec"));
126 QVBoxLayout *mainLayout = new QVBoxLayout();
127 this->setLayout(mainLayout);
128
129 list_disk=hd_parse(NULL, verbose, testdisk_mode);
130
131 hd_update_all_geometry(list_disk, verbose);
132 /* Activate the cache, even if photorec has its own */
133 for(element_disk=list_disk;element_disk!=NULL;element_disk=element_disk->next)
134 element_disk->disk=new_diskcache(element_disk->disk,testdisk_mode);
135 if(list_disk==NULL)
136 {
137 no_disk_warning();
138 }
139 else
140 select_disk(list_disk->disk);
141 setupUI();
142 }
143
~QPhotorec()144 QPhotorec::~QPhotorec()
145 {
146 // session_save(list_search_space, params, options);
147 part_free_list(list_part);
148 delete_list_disk(list_disk);
149 free(options);
150 free(params);
151 }
152
setExistingDirectory()153 void QPhotorec::setExistingDirectory()
154 {
155 QString directory = QFileDialog::getExistingDirectory(this,
156 tr("Please select a destination to save the recovered files to."),
157 directoryLabel->text(),
158 QFileDialog::ShowDirsOnly);
159 if (!directory.isEmpty())
160 {
161 directoryLabel->setText(directory);
162 buttons_updateUI();
163 }
164 }
165
newSourceFile()166 void QPhotorec::newSourceFile()
167 {
168 const int testdisk_mode=TESTDISK_O_RDONLY|TESTDISK_O_READAHEAD_32K;
169 QString filename = QFileDialog::getOpenFileName(this,
170 tr("Please select a raw file"),
171 "",
172 tr("Raw Files (*.dd *.raw *.img)"));
173 if(!filename.isEmpty())
174 {
175 disk_t *new_disk=NULL;
176 QByteArray filenameArray= (filename).toUtf8();
177 list_disk=insert_new_disk_aux(list_disk, file_test_availability(filenameArray.constData(), options->verbose, testdisk_mode), &new_disk);
178 if(new_disk!=NULL)
179 {
180 select_disk(new_disk);
181 HDDlistWidget_updateUI();
182 PartListWidget_updateUI();
183 }
184 }
185 }
186
partition_selected()187 void QPhotorec::partition_selected()
188 {
189 if(PartListWidget->selectedItems().count()<=0)
190 return;
191 list_part_t *tmp;
192 const QString& s = PartListWidget->selectedItems()[0]->text();
193 if(s.compare("")==0)
194 {
195 const QString& s2 = PartListWidget->selectedItems()[2]->text();
196 for(tmp=list_part; tmp!=NULL; tmp=tmp->next)
197 {
198 partition_t *part=tmp->part;
199 if(part->order==NO_ORDER && s2.compare(arch_none.get_partition_typename(part))==0)
200 {
201 selected_partition=part;
202 buttons_updateUI();
203 return ;
204 }
205 }
206 if(list_part!=NULL)
207 {
208 selected_partition=list_part->part;
209 buttons_updateUI();
210 return ;
211 }
212 return ;
213 }
214 for(tmp=list_part; tmp!=NULL; tmp=tmp->next)
215 {
216 partition_t *part=tmp->part;
217 if(QString::number(part->order).compare(s)==0)
218 {
219 selected_partition=part;
220 buttons_updateUI();
221 return ;
222 }
223 }
224 }
225
PartListWidget_updateUI()226 void QPhotorec::PartListWidget_updateUI()
227 {
228 list_part_t *element;
229 PartListWidget->setRowCount(0);
230 PartListWidget->setSortingEnabled(false);
231 for(element=list_part; element!=NULL; element=element->next)
232 {
233 const partition_t *partition=element->part;
234 if(partition->status!=STATUS_EXT_IN_EXT)
235 {
236 const arch_fnct_t *arch=partition->arch;
237 const int currentRow = PartListWidget->rowCount();
238 PartListWidget->setRowCount(currentRow + 1);
239 if(partition->order==NO_ORDER)
240 {
241 QTableWidgetItem *item = new QTableWidgetItem();
242 item->setData(0, "");
243 PartListWidget->setItem(currentRow, 0, item);
244 }
245 else
246 {
247 QTableWidgetItem *item = new QTableWidgetItem();
248 item->setData(0, partition->order);
249 PartListWidget->setItem(currentRow, 0, item);
250 }
251 {
252 QTableWidgetItem *item=new QTableWidgetItem(QString(get_partition_status(partition)));
253 item->setTextAlignment(Qt::AlignHCenter| Qt::AlignVCenter);
254 PartListWidget->setItem(currentRow, 1, item);
255 }
256 if(arch->get_partition_typename(partition)!=NULL)
257 PartListWidget->setItem(currentRow, 2, new QTableWidgetItem(QString(arch->get_partition_typename(partition))));
258 else if(arch->get_part_type)
259 PartListWidget->setItem(currentRow, 2, new QTableWidgetItem(tr("Sys=") + QString::number(arch->get_part_type(partition))));
260 else
261 PartListWidget->setItem(currentRow, 2, new QTableWidgetItem(tr("Unknown")));
262 if(partition->upart_type>0)
263 {
264 QTableWidgetItem *item=new QTableWidgetItem(QString(arch_none.get_partition_typename(partition)));
265 item->setToolTip(QString(partition->info));
266 PartListWidget->setItem(currentRow, 3, item);
267 }
268 else
269 {
270 PartListWidget->setItem(currentRow, 3, new QTableWidgetItem(""));
271 }
272 {
273 char sizeinfo[32];
274 QTableWidgetItem *item;
275 size_to_unit(partition->part_size, &sizeinfo[0]);
276 item=new QTableWidgetItem(QString(sizeinfo));
277 item->setTextAlignment(Qt::AlignRight | Qt::AlignVCenter);
278 PartListWidget->setItem(currentRow, 4, item);
279 /* Select the partition if it's already known */
280 if(selected_partition == partition)
281 PartListWidget->setCurrentItem(item);
282 }
283 {
284 QString partname="";
285 if(partition->partname[0]!='\0')
286 {
287 partname.sprintf("[%s]", partition->partname);
288 }
289 if(partition->fsname[0]!='\0')
290 {
291 QString fsname;
292 fsname.sprintf(" [%s]", partition->fsname);
293 partname.append(fsname);
294 }
295 PartListWidget->setItem(currentRow, 5, new QTableWidgetItem(partname));
296 }
297 }
298 }
299 PartListWidget->setSortingEnabled(true);
300 PartListWidget->sortByColumn(0, Qt::AscendingOrder);
301 PartListWidget->resizeColumnsToContents();
302 }
303
select_disk(disk_t * disk)304 void QPhotorec::select_disk(disk_t *disk)
305 {
306 if(disk==NULL)
307 return ;
308 selected_disk=disk;
309 selected_partition=NULL;
310 autodetect_arch(selected_disk, &arch_none);
311 log_info("%s\n", selected_disk->description_short(selected_disk));
312 part_free_list(list_part);
313 list_part=init_list_part(selected_disk, NULL);
314 /* If only whole disk is listed, select it */
315 /* If there is the whole disk and only one partition, select the partition */
316 if(list_part!=NULL)
317 {
318 if(list_part->next==NULL)
319 selected_partition=list_part->part;
320 else if(list_part->next->next==NULL)
321 selected_partition=list_part->next->part;
322 }
323 log_all_partitions(selected_disk, list_part);
324 }
325
disk_changed(int index)326 void QPhotorec::disk_changed(int index)
327 {
328 int i;
329 list_disk_t *element_disk;
330 for(element_disk=list_disk, i=0;
331 element_disk!=NULL;
332 element_disk=element_disk->next, i++)
333 {
334 if(i==index)
335 {
336 select_disk(element_disk->disk);
337 PartListWidget_updateUI();
338 return;
339 }
340 }
341 if(i==index)
342 {
343 newSourceFile();
344 }
345 }
346
copyright(QWidget * qwparent)347 QWidget *QPhotorec::copyright(QWidget * qwparent)
348 {
349 QWidget *C_widget = new QWidget(qwparent);
350 QLabel *t_logo=new QLabel(C_widget);
351 QPixmap pixmap_img = QPixmap(":res/photorec_64x64.png");
352 t_logo->setPixmap(pixmap_img);
353
354 QSizePolicy c_sizePolicy(QSizePolicy::Maximum, QSizePolicy::Preferred);
355 t_logo->setSizePolicy(c_sizePolicy);
356
357 QLabel *t_copy=new QLabel(C_widget);
358
359 t_copy->setText( "PhotoRec " + QString(VERSION) + ", Data Recovery Utility, " + QString(TESTDISKDATE) + "<br>\nCopyright (C) Christophe GRENIER <<a href=\"mailto:grenier@cgsecurity.org\">grenier@cgsecurity.org</a>><br>\n<a href=\"https://www.cgsecurity.org/\">https://www.cgsecurity.org</a>");
360 t_copy->setTextFormat(Qt::RichText);
361 t_copy->setTextInteractionFlags(Qt::TextBrowserInteraction);
362 t_copy->setOpenExternalLinks(true);
363
364 QHBoxLayout *C_layout = new QHBoxLayout(C_widget);
365 C_layout->addStretch(1);
366 C_layout->addWidget(t_logo);
367 C_layout->addWidget(t_copy);
368 C_layout->addStretch(1);
369 C_widget->setLayout(C_layout);
370 return C_widget;
371 }
372
373 /* TODO replace by a warning */
no_disk_warning()374 int QPhotorec::no_disk_warning()
375 {
376 QString msg;
377 msg=tr("No harddisk found");
378 #if defined(__CYGWIN__) || defined(__MINGW32__)
379 msg=tr("No harddisk found\n"
380 "You need to be administrator to use this program.\n"
381 "Under Win9x, use the DOS version instead.\n"
382 "Under Vista or later, select this program, right-click and choose \"Run as administrator\".");
383 #elif defined(DJGPP)
384 #else
385 #ifdef HAVE_GETEUID
386 if(geteuid()!=0)
387 {
388 msg=tr("No harddisk found\n"
389 "You need to be root to use PhotoRec.");
390 }
391 #endif
392 #endif
393 return QMessageBox::warning(this,tr("No Disk!"), msg, QMessageBox::Ok);
394 }
395
buttons_updateUI()396 void QPhotorec::buttons_updateUI()
397 {
398 if(selected_disk==NULL || selected_partition==NULL)
399 {
400 button_search->setEnabled(false);
401 qwholeRadioButton->setChecked(true);
402 qfreeRadioButton->setEnabled(false);
403 return ;
404 }
405 if(selected_partition->upart_type==UP_EXT2 || selected_partition->upart_type==UP_EXT3 || selected_partition->upart_type==UP_EXT4)
406 qextRadioButton->setChecked(true);
407 else
408 qfatRadioButton->setChecked(true);
409 switch(selected_partition->upart_type)
410 {
411 case UP_EXFAT:
412 case UP_FAT12:
413 case UP_FAT16:
414 case UP_FAT32:
415 #if defined(HAVE_LIBNTFS) || defined(HAVE_LIBNTFS3G)
416 case UP_NTFS:
417 #endif
418 #ifdef HAVE_LIBEXT2FS
419 case UP_EXT2:
420 case UP_EXT3:
421 case UP_EXT4:
422 #endif
423 qfreeRadioButton->setEnabled(true);
424 qfreeRadioButton->setChecked(true);
425 break;
426 default:
427 qwholeRadioButton->setChecked(true);
428 qfreeRadioButton->setEnabled(false);
429 break;
430 }
431 button_search->setEnabled(!directoryLabel->text().isEmpty());
432 }
433
HDDlistWidget_updateUI()434 void QPhotorec::HDDlistWidget_updateUI()
435 {
436 list_disk_t *element_disk;
437 int i;
438 HDDlistWidget->clear();
439 for(element_disk=list_disk, i=0;
440 element_disk!=NULL;
441 element_disk=element_disk->next, i++)
442 {
443 disk_t *disk=element_disk->disk;
444 QString description=disk->description_short(disk);
445 if(disk->serial_no!=NULL)
446 description += ", S/N:" + QString(disk->serial_no);
447 HDDlistWidget->addItem(
448 QIcon::fromTheme("drive-harddisk", QIcon(":res/gnome/drive-harddisk.png")),
449 description);
450 if(disk==selected_disk)
451 HDDlistWidget->setCurrentIndex(i);
452 }
453 HDDlistWidget->addItem(
454 QIcon::fromTheme("application-x-cd-image", QIcon(":res/gnome/application-x-cd-image.png")),
455 tr("Add a raw disk image..."));
456 }
457
setupUI()458 void QPhotorec::setupUI()
459 {
460 QWidget *t_copy = copyright(this);
461 QLabel *t_free_soft = new QLabel(tr("PhotoRec is free software, and comes with ABSOLUTELY NO WARRANTY."));
462 QLabel *t_select = new QLabel(tr("Please select a media to recover from"));
463
464 HDDlistWidget = new QComboBox();
465 HDDlistWidget->setToolTip(tr("Disk capacity must be correctly detected for a successful recovery.\n"
466 "If a disk listed above has an incorrect size, check HD jumper settings and BIOS\n"
467 "detection, and install the latest OS patches and disk drivers.")
468 );
469
470 QStringList oLabel;
471 oLabel.append("");
472 oLabel.append(tr("Flags"));
473 oLabel.append(tr("Type"));
474 oLabel.append(tr("File System"));
475 oLabel.append(tr("Size"));
476 oLabel.append(tr("Label"));
477
478 PartListWidget= new QTableWidget();
479 PartListWidget->setEditTriggers(QAbstractItemView::NoEditTriggers);
480 PartListWidget->setSelectionBehavior(QAbstractItemView::SelectRows);
481 PartListWidget->setSelectionMode(QAbstractItemView::SingleSelection);
482 PartListWidget->verticalHeader()->hide();
483 PartListWidget->setShowGrid(false);
484 PartListWidget->setColumnCount( 6 );
485 PartListWidget->setHorizontalHeaderLabels( oLabel );
486 PartListWidget_updateUI();
487
488 QGroupBox *groupBox1;
489 QGroupBox *groupBox2;
490
491 groupBox1 = new QGroupBox(tr("File System type"));
492 qextRadioButton = new QRadioButton(tr("ext2/ext3/ext4 filesystem"));
493 qfatRadioButton = new QRadioButton(tr("FAT/NTFS/HFS+/ReiserFS/..."));
494 qfatRadioButton->setChecked(true);
495
496 groupBox2 = new QGroupBox();
497 qfreeRadioButton = new QRadioButton(tr("Free: Scan for file from unallocated space only"));
498 qwholeRadioButton = new QRadioButton(tr("Whole: Extract files from whole partition"));
499 qfreeRadioButton->setEnabled(false);
500 qwholeRadioButton->setChecked(true);
501
502
503 QVBoxLayout *groupBox1Layout = new QVBoxLayout;
504 QVBoxLayout *groupBox2Layout = new QVBoxLayout;
505
506 groupBox1Layout->addWidget(qextRadioButton);
507 groupBox1Layout->addWidget(qfatRadioButton);
508 groupBox1->setLayout(groupBox1Layout);
509
510 groupBox2Layout->addWidget(qfreeRadioButton);
511 groupBox2Layout->addWidget(qwholeRadioButton);
512 groupBox2->setLayout(groupBox2Layout);
513
514 QWidget *groupBox= new QWidget();
515 QHBoxLayout *groupBoxLayout = new QHBoxLayout;
516 groupBoxLayout->addWidget(groupBox1);
517 groupBoxLayout->addWidget(groupBox2);
518 groupBox->setLayout(groupBoxLayout);
519
520
521 QLabel *dstWidget= new QLabel(tr("Please select a destination to save the recovered files to."));
522 directoryLabel=new QLineEdit("");
523 QPushButton *dst_button = new QPushButton(
524 QIcon::fromTheme("folder", QIcon(":res/gnome/folder.png")),
525 tr("&Browse"));
526
527 QWidget *dst_widget= new QWidget(this);
528 QWidget *dst_widget2= new QWidget(this);
529
530 QHBoxLayout *dst_widgetLayout2 = new QHBoxLayout;
531 dst_widgetLayout2->addWidget(directoryLabel);
532 dst_widgetLayout2->addWidget(dst_button);
533 dst_widget2->setLayout(dst_widgetLayout2);
534
535 QVBoxLayout *dst_widgetLayout = new QVBoxLayout;
536 dst_widgetLayout->addWidget(dstWidget);
537 dst_widgetLayout->addWidget(dst_widget2);
538 dst_widget->setLayout(dst_widgetLayout);
539
540
541 button_search = new QPushButton(QIcon::fromTheme("go-next", QIcon(":res/gnome/go-next.png")), tr("&Search"));
542 button_search->setEnabled(false);
543 QPushButton *button_quit= new QPushButton(QIcon::fromTheme("application-exit", QIcon(":res/gnome/application-exit.png")), tr("&Quit"));
544 QPushButton *button_about= new QPushButton(QIcon::fromTheme("help-about", QIcon(":res/gnome/help-about.png")), tr("&About"));
545 QPushButton *button_formats= new QPushButton(QIcon::fromTheme("image-x-generic.png", QIcon(":res/gnome/image-x-generic.png")),tr("&File Formats"));
546
547 QWidget *B_widget = new QWidget(this);
548 QHBoxLayout *B_layout = new QHBoxLayout(B_widget);
549 B_layout->addWidget(button_about);
550 B_layout->addWidget(button_formats);
551 B_layout->addWidget(button_search);
552 B_layout->addWidget(button_quit);
553 B_widget->setLayout(B_layout);
554
555 clearWidgets();
556 // QLayout *mainLayout = this->layout();
557 delete this->layout();
558 QVBoxLayout *mainLayout = new QVBoxLayout();
559 mainLayout->addWidget(t_copy);
560 mainLayout->addWidget(t_free_soft);
561 mainLayout->addWidget(t_select);
562 mainLayout->addWidget(HDDlistWidget);
563 mainLayout->addWidget(PartListWidget);
564 mainLayout->addWidget(groupBox);
565 mainLayout->addWidget(dst_widget);
566 mainLayout->addWidget(B_widget);
567 this->setLayout(mainLayout);
568
569 HDDlistWidget_updateUI();
570 buttons_updateUI();
571
572 connect(button_about, SIGNAL(clicked()), this, SLOT(qphotorec_about()) );
573 connect(button_formats, SIGNAL(clicked()), this, SLOT(qphotorec_formats()) );
574 connect(button_search, SIGNAL(clicked()), this, SLOT(qphotorec_search()) );
575 connect(button_quit, SIGNAL(clicked()), qApp, SLOT(quit()) );
576 connect(HDDlistWidget, SIGNAL(activated(int)),this,SLOT(disk_changed(int)));
577 connect(PartListWidget, SIGNAL(itemSelectionChanged()), this, SLOT(partition_selected()));
578 connect(dst_button, SIGNAL(clicked()), this, SLOT(setExistingDirectory()));
579 connect(directoryLabel, SIGNAL(editingFinished()), this, SLOT(buttons_updateUI()));
580 }
581
clearWidgets()582 void QPhotorec::clearWidgets()
583 {
584 while(1)
585 {
586 QLayoutItem *layoutwidget;
587 layoutwidget = this->layout()->takeAt(0);
588 if(layoutwidget==NULL)
589 return ;
590 layoutwidget->widget()->hide();
591 layoutwidget->widget()->deleteLater();
592 }
593 }
594
photorec_info(const file_stat_t * file_stats)595 void QPhotorec::photorec_info(const file_stat_t *file_stats)
596 {
597 unsigned int i;
598 unsigned int nbr;
599 unsigned int others=0;
600 if(file_stats==NULL)
601 return ;
602 file_stat_t *new_file_stats;
603 filestatsWidget->setRowCount(0);
604 for(i=0;file_stats[i].file_hint!=NULL;i++);
605 nbr=i;
606 if(nbr==0)
607 return ;
608 new_file_stats=(file_stat_t*)MALLOC(nbr*sizeof(file_stat_t));
609 memcpy(new_file_stats, file_stats, nbr*sizeof(file_stat_t));
610 qsort(new_file_stats, nbr, sizeof(file_stat_t), sorfile_stat_ts);
611 for(i=0; i<10 && i<nbr && new_file_stats[i].recovered>0; i++)
612 {
613 QTableWidgetItem *item;
614 filestatsWidget->setRowCount(i+1);
615 if(new_file_stats[i].file_hint->extension!=NULL)
616 {
617 item = new QTableWidgetItem(new_file_stats[i].file_hint->extension);
618 filestatsWidget->setItem(i, 0, item);
619 }
620 item = new QTableWidgetItem();
621 item->setData(0, new_file_stats[i].recovered);
622 filestatsWidget->setItem(i, 1, item);
623 }
624 for(; i<nbr && new_file_stats[i].recovered>0; i++)
625 others+=new_file_stats[i].recovered;
626 if(others>0)
627 {
628 QTableWidgetItem *item;
629 filestatsWidget->setRowCount(11);
630 item = new QTableWidgetItem("others");
631 filestatsWidget->setItem(10, 0, item);
632 item = new QTableWidgetItem();
633 item->setData(0, others);
634 filestatsWidget->setItem(10, 1, item);
635 }
636 free(new_file_stats);
637 }
638
qphotorec_search_updateUI()639 void QPhotorec::qphotorec_search_updateUI()
640 {
641 const partition_t *partition=params->partition;
642 const unsigned int sector_size=params->disk->sector_size;
643 QString tmp;
644 QString txt = QString(directoryLabel->text()).toHtmlEscaped();
645 folder_txt->setText(tr("Destination:")+" <a href=\"file://" + txt + "/" +
646 DEFAULT_RECUP_DIR + "." + QString::number(params->dir_num) + "\">" +
647 txt + "</a>");
648 if(params->status==STATUS_QUIT)
649 {
650 tmp=QString(tr("Recovery completed"));
651 }
652 else if(params->status==STATUS_EXT2_ON_BF || params->status==STATUS_EXT2_OFF_BF)
653 {
654 const unsigned long sectors_remaining=(params->offset-partition->part_offset)/sector_size;
655 tmp=QString(tr("Bruteforce %1 sectors remaining (test %2)").arg(sectors_remaining).arg(params->pass));
656 }
657 else
658 {
659 const unsigned long long sector_current=(params->offset>partition->part_offset && params->offset < partition->part_size ?
660 ((params->offset-partition->part_offset)/sector_size):
661 0);
662 const unsigned long long sector_total=partition->part_size/sector_size;
663 tmp=QString(tr("Pass %1 - Reading sector %2/%3").arg(params->pass).arg(sector_current).arg(sector_total));
664 }
665 progress_info->setText(tmp);
666
667 if(params->status==STATUS_FIND_OFFSET)
668 tmp=QString(tr("%1/10 headers found").arg(params->file_nbr));
669 else
670 tmp=QString(tr("%1 files found").arg(params->file_nbr));
671 progress_filefound->setText(tmp);
672
673 if(params->status==STATUS_QUIT)
674 {
675 progress_bar->setMinimum(0);
676 progress_bar->setMaximum(100);
677 progress_bar->setValue(100);
678 }
679 else if(params->status==STATUS_FIND_OFFSET)
680 {
681 progress_bar->setMinimum(0);
682 progress_bar->setMaximum(10);
683 progress_bar->setValue(params->file_nbr);
684 }
685 else
686 {
687 progress_bar->setMinimum(0);
688 progress_bar->setMaximum(100);
689 progress_bar->setValue((params->offset-partition->part_offset)*100/ partition->part_size);
690 }
691 photorec_info(params->file_stats);
692 }
693
qphotorec_search_setupUI()694 void QPhotorec::qphotorec_search_setupUI()
695 {
696 clearWidgets();
697 delete this->layout();
698 QVBoxLayout *mainLayout = new QVBoxLayout();
699 QWidget *t_copy = copyright(this);
700
701 QSizePolicy c_sizePolicy(QSizePolicy::Maximum, QSizePolicy::Preferred);
702
703 QLabel *disk_img=new QLabel();
704 QPixmap disk_pixmap = QPixmap(":res/gnome/drive-harddisk.png");
705 disk_img->setPixmap(disk_pixmap);
706 disk_img->setSizePolicy(c_sizePolicy);
707
708 QLabel *disk_txt=new QLabel();
709 disk_txt->setText(selected_disk->description_short(selected_disk));
710
711 QWidget *diskWidget = new QWidget();
712 QHBoxLayout *diskWidgetLayout = new QHBoxLayout(diskWidget);
713 diskWidgetLayout->addWidget(disk_img);
714 diskWidgetLayout->addWidget(disk_txt);
715 diskWidget->setLayout(diskWidgetLayout);
716
717 QLabel *folder_img=new QLabel();
718 QPixmap *folder_pixmap = new QPixmap(":res/gnome/folder.png");
719 folder_img->setPixmap(*folder_pixmap);
720 folder_img->setSizePolicy(c_sizePolicy);
721
722 folder_txt=new QLabel();
723 folder_txt->setTextFormat(Qt::RichText);
724 folder_txt->setTextInteractionFlags(Qt::TextBrowserInteraction);
725 folder_txt->setOpenExternalLinks(true);
726
727 QWidget *folderWidget = new QWidget();
728 QHBoxLayout *folderWidgetLayout = new QHBoxLayout(folderWidget);
729 folderWidgetLayout->addWidget(folder_img);
730 folderWidgetLayout->addWidget(folder_txt);
731 folderWidget->setLayout(folderWidgetLayout);
732
733
734 progress_info=new QLabel();
735 progress_filefound=new QLabel();
736 progress_bar=new QProgressBar();
737
738 QWidget *progressWidget = new QWidget();
739 QHBoxLayout *progressWidgetLayout = new QHBoxLayout(progressWidget);
740 progressWidgetLayout->addWidget(progress_info);
741 progressWidgetLayout->addWidget(progress_bar);
742 progressWidgetLayout->addWidget(progress_filefound);
743 progressWidget->setLayout(progressWidgetLayout);
744
745 QWidget *progressWidget2 = new QWidget();
746 QHBoxLayout *progressWidgetLayout2 = new QHBoxLayout(progressWidget2);
747 // TODO
748 // progressWidgetLayout2->addWidget(progress_elapsed);
749 // progressWidgetLayout2->addWidget(progress_eta);
750 progressWidget2->setLayout(progressWidgetLayout2);
751
752 QStringList oLabel;
753 oLabel.append(tr("File family"));
754 oLabel.append(tr("Number of files recovered"));
755
756 filestatsWidget=new QTableWidget();
757 filestatsWidget->setEditTriggers(QAbstractItemView::NoEditTriggers);
758 filestatsWidget->setSelectionBehavior(QAbstractItemView::SelectRows);
759 filestatsWidget->setSelectionMode(QAbstractItemView::SingleSelection);
760 filestatsWidget->verticalHeader()->hide();
761 filestatsWidget->setColumnCount( 2 );
762 filestatsWidget->setHorizontalHeaderLabels( oLabel );
763 filestatsWidget->resizeColumnsToContents();
764
765 QPushButton *button_quit= new QPushButton(QIcon::fromTheme("application-exit", QIcon(":res/gnome/application-exit.png")), tr("&Quit"));
766 mainLayout->addWidget(t_copy);
767 mainLayout->addWidget(diskWidget);
768 mainLayout->addWidget(folderWidget);
769 mainLayout->addWidget(progressWidget);
770 mainLayout->addWidget(progressWidget2);
771 mainLayout->addWidget(filestatsWidget);
772 mainLayout->addWidget(button_quit);
773 this->setLayout(mainLayout);
774
775 connect( button_quit, SIGNAL(clicked()), this, SLOT(stop_and_quit()) );
776 connect(this, SIGNAL(finished()), qApp, SLOT(quit()));
777
778 timer = new QTimer(this);
779 timer->setInterval(500);
780 connect(timer, SIGNAL(timeout()), this, SLOT(qphotorec_search_updateUI()));
781 }
782
stop_and_quit()783 void QPhotorec::stop_and_quit()
784 {
785 stop_the_recovery=true;
786 emit finished();
787 }
788
photorec(alloc_data_t * list_search_space)789 int QPhotorec::photorec(alloc_data_t *list_search_space)
790 {
791 pstatus_t ind_stop=PSTATUS_OK;
792 const unsigned int blocksize_is_known=params->blocksize;
793 params_reset(params, options);
794 /* make the first recup_dir */
795 params->dir_num=photorec_mkdir(params->recup_dir, params->dir_num);
796 for(params->pass=0; params->status!=STATUS_QUIT; params->pass++)
797 {
798 timer->start();
799 switch(params->status)
800 {
801 case STATUS_UNFORMAT:
802 /* FIXME */
803 break;
804 case STATUS_FIND_OFFSET:
805 {
806 uint64_t start_offset=0;
807 if(blocksize_is_known>0)
808 {
809 ind_stop=PSTATUS_OK;
810 if(!td_list_empty(&list_search_space->list))
811 start_offset=(td_list_entry(list_search_space->list.next, alloc_data_t, list))->start % params->blocksize;
812 }
813 else
814 {
815 ind_stop=photorec_find_blocksize(list_search_space);
816 params->blocksize=find_blocksize(list_search_space, params->disk->sector_size, &start_offset);
817 }
818 update_blocksize(params->blocksize, list_search_space, start_offset);
819 }
820 break;
821 case STATUS_EXT2_ON_BF:
822 case STATUS_EXT2_OFF_BF:
823 /* FIXME */
824 break;
825 default:
826 ind_stop=photorec_aux(list_search_space);
827 break;
828 }
829 timer->stop();
830 qphotorec_search_updateUI();
831 session_save(list_search_space, params, options);
832 switch(ind_stop)
833 {
834 case PSTATUS_EACCES:
835 {
836 int ret=QMessageBox::warning(this,
837 tr("QPhotoRec: Failed to create file!"),
838 tr("Failed to create file! Please choose another destination"),
839 QMessageBox::Ok| QMessageBox::Cancel, QMessageBox::Ok);
840 if(ret==QMessageBox::Cancel)
841 {
842 params->status=STATUS_QUIT;
843 }
844 else
845 {
846 setExistingDirectory();
847 free(params->recup_dir);
848 QByteArray byteArray = (directoryLabel->text() + "/" + DEFAULT_RECUP_DIR).toUtf8();
849 params->recup_dir=strdup(byteArray.constData());
850 params->dir_num=photorec_mkdir(params->recup_dir, params->dir_num);
851 }
852 }
853 break;
854 case PSTATUS_ENOSPC:
855 {
856 int ret=QMessageBox::warning(this,
857 tr("QPhotoRec: Not enough space!"),
858 tr("There is not enough space left! Please free disk space and/or choose another destination"),
859 QMessageBox::Ok| QMessageBox::Cancel, QMessageBox::Ok);
860 if(ret==QMessageBox::Cancel)
861 {
862 params->status=STATUS_QUIT;
863 }
864 else
865 {
866 setExistingDirectory();
867 free(params->recup_dir);
868 QByteArray byteArray = (directoryLabel->text() + "/" + DEFAULT_RECUP_DIR).toUtf8();
869 params->recup_dir=strdup(byteArray.constData());
870 params->dir_num=photorec_mkdir(params->recup_dir, params->dir_num);
871 }
872 }
873 break;
874 case PSTATUS_OK:
875 status_inc(params, options);
876 if(params->status==STATUS_QUIT)
877 unlink("photorec.ses");
878 break;
879 case PSTATUS_STOP:
880 params->status=STATUS_QUIT;
881 break;
882 }
883 update_stats(params->file_stats, list_search_space);
884 qphotorec_search_updateUI();
885 }
886 free_search_space(list_search_space);
887 free_header_check();
888 free(params->file_stats);
889 params->file_stats=NULL;
890 return 0;
891 }
892
qphotorec_search()893 void QPhotorec::qphotorec_search()
894 {
895 if(selected_disk==NULL || selected_partition==NULL)
896 return;
897 alloc_data_t list_search_space;
898 TD_INIT_LIST_HEAD(&list_search_space.list);
899
900 QByteArray byteArray = (directoryLabel->text() + "/" + DEFAULT_RECUP_DIR).toUtf8();
901 params->recup_dir=strdup(byteArray.constData());
902 params->carve_free_space_only=qfreeRadioButton->isChecked();
903 params->disk=selected_disk;
904 params->partition=selected_partition;
905 log_partition(selected_disk, selected_partition);
906
907 options->mode_ext2=qextRadioButton->isChecked();
908
909 qphotorec_search_setupUI();
910 if(td_list_empty(&list_search_space.list))
911 {
912 init_search_space(&list_search_space, params->disk, params->partition);
913 }
914 if(params->carve_free_space_only>0)
915 {
916 params->blocksize=remove_used_space(params->disk, params->partition, &list_search_space);
917 }
918 photorec(&list_search_space);
919 free(params->recup_dir);
920 params->recup_dir=NULL;
921 }
922
qphotorec_about()923 void QPhotorec::qphotorec_about()
924 {
925 QPixmap pixmap_img = QPixmap(":res/photorec_64x64.png");
926 QMessageBox msg;
927 msg.setText(tr("QPhotoRec is 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.\n\nQPhotoRec is 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.\n\nYou should have received a copy of the GNU General Public License along with QPhotoRec. If not, see <http://www.gnu.org/licenses/>."));
928 msg.setWindowTitle(tr("QPhotoRec: About"));
929 msg.addButton(QMessageBox::Close);
930 msg.setIconPixmap(pixmap_img);
931 msg.exec();
932 }
933
qphotorec_formats()934 void QPhotorec::qphotorec_formats()
935 {
936 file_enable_t *file_enable;
937 QStringList list;
938 formats=new QListWidget();
939 for(file_enable=list_file_enable;
940 file_enable->file_hint!=NULL;
941 file_enable++)
942 {
943 QListWidgetItem * item;
944 char descr[128];
945 sprintf(descr, "%-4s %s",
946 (file_enable->file_hint->extension!=NULL?
947 file_enable->file_hint->extension:""),
948 file_enable->file_hint->description);
949 item = new QListWidgetItem(descr, formats);
950 if(file_enable->enable)
951 item->setCheckState (Qt::Checked);
952 else
953 item->setCheckState (Qt::Unchecked);
954 }
955
956 QDialog fenetre3;
957 fenetre3.setWindowTitle("QPhotoRec: "+tr("File Formats"));
958 QDialogButtonBox buttonBox(Qt::Horizontal);
959
960 QPushButton *bt_reset= new QPushButton(tr("&Reset"));
961 QPushButton *bt_restore= new QPushButton(tr("Res&tore"));
962
963 buttonBox.addButton(bt_reset, QDialogButtonBox::ResetRole);
964 buttonBox.addButton(bt_restore, QDialogButtonBox::ResetRole);
965 buttonBox.addButton(QDialogButtonBox::Ok);
966 QVBoxLayout vbox;
967 vbox.addWidget(formats);
968 vbox.addWidget(&buttonBox);
969 fenetre3.setLayout(&vbox);
970 connect(&buttonBox, SIGNAL(accepted()), &fenetre3, SLOT(accept()));
971 connect(bt_reset, SIGNAL(clicked()), this, SLOT(formats_reset()));
972 connect(bt_restore, SIGNAL(clicked()), this, SLOT(formats_restore()));
973 fenetre3.exec();
974 int i;
975 for (i = 0, file_enable=list_file_enable;
976 i < formats->count() && file_enable->file_hint!=NULL;
977 i++, file_enable++)
978 {
979 QListWidgetItem *item = formats->item(i);
980 file_enable->enable=(item->checkState()==Qt::Checked?1:0);
981 }
982 }
983
formats_reset()984 void QPhotorec::formats_reset()
985 {
986 for (int i = 0; i < formats->count(); i++) {
987 QListWidgetItem *item = formats->item(i);
988 item->setCheckState (Qt::Unchecked);
989 }
990 }
991
formats_restore()992 void QPhotorec::formats_restore()
993 {
994 file_enable_t *file_enable;
995 int i;
996 for (i = 0, file_enable=list_file_enable;
997 i < formats->count() && file_enable->file_hint!=NULL;
998 i++, file_enable++)
999 {
1000 QListWidgetItem *item = formats->item(i);
1001 if(file_enable->file_hint->enable_by_default)
1002 item->setCheckState (Qt::Checked);
1003 else
1004 item->setCheckState (Qt::Unchecked);
1005 }
1006 }
1007