1 /*
2 Bacula(R) - The Network Backup Solution
3
4 Copyright (C) 2000-2020 Kern Sibbald
5
6 The original author of Bacula is Kern Sibbald, with contributions
7 from many others, a complete list can be found in the file AUTHORS.
8
9 You may use this file and others of this release according to the
10 license defined in the LICENSE file, which includes the Affero General
11 Public License, v3.0 ("AGPLv3") and some additional permissions and
12 terms pursuant to its AGPLv3 Section 7.
13
14 This notice must be preserved when any source code is
15 conveyed and/or propagated.
16
17 Bacula(R) is a registered trademark of Kern Sibbald.
18 */
19
20 /*
21 *
22 * bRestore Class (Eric's brestore)
23 *
24 * Kern Sibbald, January MMVII
25 *
26 */
27
28 #include "bat.h"
29 #include "restore.h"
30 #include "util/fmtwidgetitem.h"
31
bRestore()32 bRestore::bRestore() : Pages()
33 {
34 m_name = tr("bRestore");
35 m_client = "";
36 setupUi(this);
37 pgInitialize();
38 QTreeWidgetItem* thisitem = mainWin->getFromHash(this);
39 thisitem->setIcon(0, QIcon(QString::fromUtf8(":images/browse.png")));
40 m_populated = false;
41 m_closeable = false;
42 m_current = NULL;
43 RestoreList->setAcceptDrops(true);
44 }
45
46 // Populate client table and job associated
setClient()47 void bRestore::setClient()
48 {
49 // Select the same client, don't touch
50 if (m_client == ClientList->currentText()) {
51 return;
52 }
53 m_client = ClientList->currentText();
54 FileList->clearContents();
55 FileRevisions->clearContents();
56 JobList->clear();
57 JobList->setEnabled(true);
58 LocationEntry->clear();
59 m_path = "";
60 m_pathid = 0;
61
62 if (ClientList->currentIndex() < 1) {
63 JobList->setEnabled(false);
64 return;
65 }
66
67 JobList->addItem("Job list for " + m_client);
68
69 QString jobQuery =
70 "SELECT Job.Jobid AS JobId, Job.StartTime AS StartTime,"
71 " Job.Level AS Level,"
72 " Job.Name AS Name"
73 " FROM Job JOIN Client USING (ClientId)"
74 " WHERE"
75 " Job.JobStatus IN ('T','W') AND Job.Type='B' AND"
76 " Client.Name='" + m_client + "' ORDER BY StartTime DESC" ;
77
78 QString job;
79 QStringList results;
80 QStringList fieldlist;
81 if (m_console->sql_cmd(jobQuery, results)) {
82 /* Iterate through the record returned from the query */
83 foreach (QString resultline, results) {
84 // 0 1 2 3
85 // JobId, StartTime, Level, Name
86 fieldlist = resultline.split("\t");
87 job = fieldlist[1] + " " + fieldlist[3] + "(" + fieldlist[2] + ") " + fieldlist[0];
88 JobList->addItem(job, QVariant(fieldlist[0])); // set also private value
89 }
90 }
91 }
92
93 // Compute job associated and update the job cache if needed
setJob()94 void bRestore::setJob()
95 {
96 if (JobList->currentIndex() < 1) {
97 FileList->clearContents();
98 FileList->setRowCount(0);
99 FileRevisions->clearContents();
100 FileRevisions->setRowCount(0);
101 return ;
102 }
103 QStringList results;
104 QVariant tmp = JobList->itemData(JobList->currentIndex(), Qt::UserRole);
105
106 m_jobids = tmp.toString();
107 QString cmd = ".bvfs_get_jobids jobid=" + m_jobids;
108 if (MergeChk->checkState() == Qt::Checked) {
109 cmd.append(" all");
110 }
111
112 m_console->dir_cmd(cmd, results);
113
114 if (results.size() < 1) {
115 FileList->clearContents();
116 FileList->setRowCount(0);
117 FileRevisions->clearContents();
118 FileRevisions->setRowCount(0);
119 return;
120 }
121
122 // TODO: Can take some time if the job contains many dirs
123 m_jobids = results.at(0);
124 cmd = ".bvfs_update jobid=" + m_jobids;
125 m_console->dir_cmd(cmd, results);
126
127 Pmsg1(0, "jobids=%s\n", m_jobids.toLocal8Bit().constData());
128
129 displayFiles(m_pathid, QString(""));
130 Pmsg0(000, "update done\n");
131 }
132
133 extern int decode_stat(char *buf, struct stat *statp, int stat_size, int32_t *LinkFI);
134
135 // refresh button with a filter or limit/offset change
refreshView()136 void bRestore::refreshView()
137 {
138 displayFiles(m_pathid, m_path);
139 }
140
displayFiles(int64_t pathid,QString path)141 void bRestore::displayFiles(int64_t pathid, QString path)
142 {
143 QString arg;
144 QStringList results;
145 QStringList fieldlist;
146 struct stat statp;
147 int32_t LinkFI;
148 int nb = 0;
149 int row = 0;
150 Freeze frz_lst(*FileList); /* disable updating*/
151 Freeze frz_rev(*FileRevisions); /* disable updating*/
152 FileList->clearContents();
153 FileRevisions->clearContents();
154 FileRevisions->setRowCount(0);
155
156 // If we provide pathid, use it (path can be altered by encoding conversion)
157 if (pathid > 0) {
158 arg = " pathid=" + QString().setNum(pathid);
159
160 // Choose .. update current path to parent dir
161 if (path == "..") {
162 if (m_path == "/") {
163 m_path = "";
164 } else {
165 m_path.remove(QRegExp("[^/]+/$"));
166 }
167
168 } else if (path == "/" && m_path == "") {
169 m_path += path;
170
171 } else if (path != "/" && path != ".") {
172 m_path += path;
173 }
174 } else {
175 m_path = path;
176 arg = " path=\"" + m_path + "\"";
177 }
178
179 // If a filter is set, add it to the current query
180 if (FilterEntry->text() != "") {
181 QString tmp = FilterEntry->text();
182 tmp.replace("\"", "."); // basic escape of "
183 arg += " pattern=\"" + tmp + "\"";
184 }
185
186 LocationEntry->setText(m_path);
187 QString offset = QString().setNum(Offset1Spin->value());
188 QString limit=QString().setNum(Offset2Spin->value() - Offset1Spin->value());
189 QString q = ".bvfs_lsdir jobid=" + m_jobids + arg
190 + " limit=" + limit + " offset=" + offset ;
191 if (mainWin->m_miscDebug) qDebug() << q;
192 if (m_console->dir_cmd(q, results)) {
193 nb = results.size();
194 FileList->setRowCount(nb);
195 foreach (QString resultline, results) {
196 int col=0;
197 //PathId, FilenameId, fileid, jobid, lstat, path
198 fieldlist = resultline.split("\t");
199 /*
200 * Note, the next line zaps variable "item", probably
201 * because the input data in fieldlist is bad.
202 */
203 decode_stat(fieldlist.at(4).toLocal8Bit().data(), &statp, sizeof(statp), &LinkFI);
204 TableItemFormatter item(*FileList, row++);
205 item.setFileType(col++, QString("folder")); // folder or file
206 item.setTextFld(col++, fieldlist.at(5)); // path
207 item.setBytesFld(col++, QString().setNum(statp.st_size));
208 item.setDateFld(col++, statp.st_mtime); // date
209 fieldlist.replace(3, m_jobids); // use current jobids selection
210 // keep original info on the first cel that is never empty
211 item.widget(1)->setData(Qt::UserRole, fieldlist.join("\t"));
212 }
213 }
214
215 results.clear();
216 q = ".bvfs_lsfiles jobid=" + m_jobids + arg
217 + " limit=" + limit + " offset=" + offset ;
218 if (m_console->dir_cmd(q, results)) {
219 FileList->setRowCount(results.size() + nb);
220 foreach (QString resultline, results) {
221 int col=1; // skip icon
222 //PathId, FilenameId, fileid, jobid, lstat, name
223 fieldlist = resultline.split("\t");
224 TableItemFormatter item(*FileList, row++);
225 item.setTextFld(col++, fieldlist.at(5)); // name
226 decode_stat(fieldlist.at(4).toLocal8Bit().data(),
227 &statp, sizeof(statp), &LinkFI);
228 item.setBytesFld(col++, QString().setNum(statp.st_size));
229 item.setDateFld(col++, statp.st_mtime);
230 // keep original info on the first cel that is never empty
231 item.widget(1)->setData(Qt::UserRole, fieldlist.join("\t")); // keep info
232 }
233 }
234 FileList->verticalHeader()->hide();
235 FileList->resizeColumnsToContents();
236 FileList->resizeRowsToContents();
237 FileList->setEditTriggers(QAbstractItemView::NoEditTriggers);
238 }
239
PgSeltreeWidgetClicked()240 void bRestore::PgSeltreeWidgetClicked()
241 {
242 if(!m_populated) {
243 setupPage();
244 }
245 if (!isOnceDocked()) {
246 dockPage();
247 }
248 }
249
250 // Display all versions of a file for this client
displayFileVersion(QString pathid,QString fnid,QString client,QString filename)251 void bRestore::displayFileVersion(QString pathid, QString fnid,
252 QString client, QString filename)
253 {
254 int row=0;
255 struct stat statp;
256 int32_t LinkFI;
257 Freeze frz_rev(*FileRevisions); /* disable updating*/
258 FileRevisions->clearContents();
259
260 QString q = ".bvfs_versions jobid=" + m_jobids +
261 " pathid=" + pathid +
262 " fnid=" + fnid +
263 " client=" + client;
264
265 if (VersionsChk->checkState() == Qt::Checked) {
266 q.append(" versions");
267 }
268
269 QStringList results;
270 QStringList fieldlist;
271 QString tmp;
272 if (m_console->dir_cmd(q, results)) {
273 FileRevisions->setRowCount(results.size());
274 foreach (QString resultline, results) {
275 int col=0;
276 // 0 1 2 3 4 5 6 7
277 //PathId, FilenameId, fileid, jobid, lstat, Md5, VolName, Inchanger
278 fieldlist = resultline.split("\t");
279 TableItemFormatter item(*FileRevisions, row++);
280 item.setInChanger(col++, fieldlist.at(7)); // inchanger
281 item.setTextFld(col++, fieldlist.at(6)); // Volume
282 item.setNumericFld(col++, fieldlist.at(3)); // JobId
283 decode_stat(fieldlist.at(4).toLocal8Bit().data(),
284 &statp, sizeof(statp), &LinkFI);
285 item.setBytesFld(col++, QString().setNum(statp.st_size)); // size
286 item.setDateFld(col++, statp.st_mtime); // date
287 item.setTextFld(col++, fieldlist.at(5)); // chksum
288
289 // Adjust the fieldlist for drag&drop
290 fieldlist.removeLast(); // inchanger
291 fieldlist.removeLast(); // volname
292 fieldlist.removeLast(); // md5
293 fieldlist << m_path + filename;
294
295 // keep original info on the first cel that is never empty
296 item.widget(1)->setData(Qt::UserRole, fieldlist.join("\t"));
297 }
298 }
299 FileRevisions->verticalHeader()->hide();
300 FileRevisions->resizeColumnsToContents();
301 FileRevisions->resizeRowsToContents();
302 FileRevisions->setEditTriggers(QAbstractItemView::NoEditTriggers);
303 }
304
showInfoForFile(QTableWidgetItem * widget)305 void bRestore::showInfoForFile(QTableWidgetItem *widget)
306 {
307 m_current = widget;
308 QTableWidgetItem *first = FileList->item(widget->row(), 1);
309 QStringList lst = first->data(Qt::UserRole).toString().split("\t");
310 if (lst.at(1) == "0") { // no filenameid, should be a path
311 displayFiles(lst.at(0).toLongLong(), lst.at(5));
312 } else {
313 displayFileVersion(lst.at(0), lst.at(1), m_client, lst.at(5));
314 }
315 }
316
applyLocation()317 void bRestore::applyLocation()
318 {
319 displayFiles(0, LocationEntry->text());
320 }
321
clearVersions(QTableWidgetItem * item)322 void bRestore::clearVersions(QTableWidgetItem *item)
323 {
324 if (item != m_current) {
325 FileRevisions->clearContents();
326 FileRevisions->setRowCount(0);
327 }
328 m_current = item ;
329 }
330
clearRestoreList()331 void bRestore::clearRestoreList()
332 {
333 RestoreList->clearContents();
334 RestoreList->setRowCount(0);
335 }
336
runRestore()337 void bRestore::runRestore()
338 {
339 bRunRestore *r = new bRunRestore(this);
340 r->setVisible(true);
341 }
342
setupPage()343 void bRestore::setupPage()
344 {
345 ClientList->addItem("Client list");
346 ClientList->addItems(m_console->client_list);
347 connect(ClientList, SIGNAL(currentIndexChanged(int)), this, SLOT(setClient()));
348 connect(JobList, SIGNAL(currentIndexChanged(int)), this, SLOT(setJob()));
349 connect(FileList, SIGNAL(itemClicked(QTableWidgetItem*)),
350 this, SLOT(clearVersions(QTableWidgetItem *)));
351 connect(FileList, SIGNAL(itemDoubleClicked(QTableWidgetItem*)),
352 this, SLOT(showInfoForFile(QTableWidgetItem *)));
353 connect(LocationBp, SIGNAL(pressed()), this, SLOT(applyLocation()));
354 connect(MergeChk, SIGNAL(clicked()), this, SLOT(setJob()));
355 connect(ClearBp, SIGNAL(clicked()), this, SLOT(clearRestoreList()));
356 connect(RestoreBp, SIGNAL(clicked()), this, SLOT(runRestore()));
357 connect(FilterBp, SIGNAL(clicked()), this, SLOT(refreshView()));
358 m_populated = true;
359 }
360
~bRestore()361 bRestore::~bRestore()
362 {
363 }
364
365 // Drag & Drop handling, not so easy...
mousePressEvent(QMouseEvent * event)366 void bRestoreTable::mousePressEvent(QMouseEvent *event)
367 {
368 QTableWidget::mousePressEvent(event);
369
370 if (event->button() == Qt::LeftButton) {
371 dragStartPosition = event->pos();
372 }
373 }
374
375 // This event permits to send set custom data on drag&drop
376 // Don't forget to call original class if we are not interested
mouseMoveEvent(QMouseEvent * event)377 void bRestoreTable::mouseMoveEvent(QMouseEvent *event)
378 {
379 int lastrow=-1;
380
381 // Look just for drag&drop
382 if (!(event->buttons() & Qt::LeftButton)) {
383 QTableWidget::mouseMoveEvent(event);
384 return;
385 }
386 if ((event->pos() - dragStartPosition).manhattanLength()
387 < QApplication::startDragDistance())
388 {
389 QTableWidget::mouseMoveEvent(event);
390 return;
391 }
392
393 QList<QTableWidgetItem *> lst = selectedItems();
394 if (mainWin->m_miscDebug) qDebug() << this << " selectedItems: " << lst;
395 if (lst.isEmpty()) {
396 return;
397 }
398
399 QDrag *drag = new QDrag(this);
400 QMimeData *mimeData = new QMimeData;
401 for (int i=0; i < lst.size(); i++) {
402 if (lastrow != lst[i]->row()) {
403 lastrow = lst[i]->row();
404 QTableWidgetItem *it = item(lastrow, 1);
405 mimeData->setText(it->data(Qt::UserRole).toString());
406 break; // at this time, we do it one by one
407 }
408 }
409 drag->setMimeData(mimeData);
410 drag->exec();
411 }
412
413 // This event is called when the drag item enters in the destination area
dragEnterEvent(QDragEnterEvent * event)414 void bRestoreTable::dragEnterEvent(QDragEnterEvent *event)
415 {
416 if (event->source() == this) {
417 event->ignore();
418 return;
419 }
420 if (event->mimeData()->hasText()) {
421 event->acceptProposedAction();
422 } else {
423 event->ignore();
424 }
425 }
426
427 // It should not be essential to redefine this event, but it
428 // doesn't work if not defined
dragMoveEvent(QDragMoveEvent * event)429 void bRestoreTable::dragMoveEvent(QDragMoveEvent *event)
430 {
431 if (event->mimeData()->hasText()) {
432 event->acceptProposedAction();
433 } else {
434 event->ignore();
435 }
436 }
437
438 // When user releases the button
dropEvent(QDropEvent * event)439 void bRestoreTable::dropEvent(QDropEvent *event)
440 {
441 int col=1;
442 struct stat statp;
443 int32_t LinkFI;
444 if (event->mimeData()->hasText()) {
445 TableItemFormatter item(*this, rowCount());
446 setRowCount(rowCount() + 1);
447 QStringList fields = event->mimeData()->text().split("\t");
448 if (fields.size() != 6) {
449 event->ignore();
450 return;
451 }
452 if (fields.at(1) == "0") {
453 item.setFileType(0, "folder");
454 }
455 item.setTextFld(col++, fields.at(5)); // filename
456 decode_stat(fields.at(4).toLocal8Bit().data(),
457 &statp, sizeof(statp), &LinkFI);
458 item.setBytesFld(col++, QString().setNum(statp.st_size)); // size
459 item.setDateFld(col++, statp.st_mtime); // date
460 item.setNumericFld(col++, fields.at(3)); // jobid
461 item.setNumericFld(col++, fields.at(2)); // fileid
462 // keep original info on the first cel that is never empty
463 item.widget(1)->setData(Qt::UserRole, event->mimeData()->text());
464 event->acceptProposedAction();
465 } else {
466 event->ignore();
467 }
468 }
469
470 // Use File Relocation bp
UFRcb()471 void bRunRestore::UFRcb()
472 {
473 if (UseFileRelocationChk->checkState() == Qt::Checked) {
474 WhereEntry->setEnabled(false);
475 UseRegexpChk->setEnabled(true);
476 if (UseRegexpChk->checkState() == Qt::Checked) {
477 AddSuffixEntry->setEnabled(false);
478 AddPrefixEntry->setEnabled(false);
479 StripPrefixEntry->setEnabled(false);
480 WhereRegexpEntry->setEnabled(true);
481 } else {
482 AddSuffixEntry->setEnabled(true);
483 AddPrefixEntry->setEnabled(true);
484 StripPrefixEntry->setEnabled(true);
485 WhereRegexpEntry->setEnabled(false);
486 }
487 } else {
488 WhereEntry->setEnabled(true);
489 AddSuffixEntry->setEnabled(false);
490 AddPrefixEntry->setEnabled(false);
491 StripPrefixEntry->setEnabled(false);
492 UseRegexpChk->setEnabled(false);
493 WhereRegexpEntry->setEnabled(false);
494 }
495 }
496
497 // Expert mode for file relocation
useRegexp()498 void bRunRestore::useRegexp()
499 {
500 if (UseRegexpChk->checkState() == Qt::Checked) {
501 AddSuffixEntry->setEnabled(false);
502 AddPrefixEntry->setEnabled(false);
503 StripPrefixEntry->setEnabled(false);
504 WhereRegexpEntry->setEnabled(true);
505 } else {
506 AddSuffixEntry->setEnabled(true);
507 AddPrefixEntry->setEnabled(true);
508 StripPrefixEntry->setEnabled(true);
509 WhereRegexpEntry->setEnabled(false);
510 }
511 }
512
513 // Display Form to run the restore job
bRunRestore(bRestore * parent)514 bRunRestore::bRunRestore(bRestore *parent)
515 {
516 brestore = parent;
517 setupUi(this);
518 ClientCb->addItems(parent->console()->client_list);
519 int i = ClientCb->findText(parent->m_client);
520 if (i >= 0) {
521 ClientCb->setCurrentIndex(i);
522 }
523 StorageCb->addItem(QString(""));
524 RestoreCb->addItems(parent->console()->restore_list);
525 WhenEditor->setDateTime(QDateTime::currentDateTime());
526 StorageCb->addItems(parent->console()->storage_list);
527 connect(UseFileRelocationChk, SIGNAL(clicked()), this, SLOT(UFRcb()));
528 connect(UseRegexpChk, SIGNAL(clicked()), this, SLOT(useRegexp()));
529 connect(ActionBp, SIGNAL(accepted()), this, SLOT(computeRestore()));
530 // TODO: handle multiple restore job
531 struct job_defaults jd;
532 if (parent->console()->restore_list.size() > 0) {
533 jd.job_name = parent->console()->restore_list[0];
534 brestore->console()->get_job_defaults(jd);
535 WhereEntry->setText(jd.where);
536 }
537 computeVolumeList();
538 }
539
get_info_from_selection(QStringList & fileids,QStringList & jobids,QStringList & dirids,QStringList & findexes)540 void bRestore::get_info_from_selection(QStringList &fileids,
541 QStringList &jobids,
542 QStringList &dirids,
543 QStringList &findexes)
544 {
545 struct stat statp;
546 int32_t LinkFI;
547 for (int i=0; i < RestoreList->rowCount(); i++) {
548 QTableWidgetItem *item = RestoreList->item(i, 1);
549 QString data = item->data(Qt::UserRole).toString();
550 QStringList lst = data.split("\t");
551 if (lst.at(1) != "0") { // skip path
552 fileids << lst.at(2);
553 jobids << lst.at(3);
554 decode_stat(lst.at(4).toLocal8Bit().data(),
555 &statp, sizeof(statp), &LinkFI);
556 if (LinkFI) {
557 findexes << lst.at(3) + "," + QString().setNum(LinkFI);
558 }
559 } else {
560 dirids << lst.at(0);
561 jobids << lst.at(3).split(","); // Can have multiple jobids
562 }
563 }
564 fileids.removeDuplicates();
565 jobids.removeDuplicates();
566 dirids.removeDuplicates();
567 findexes.removeDuplicates();
568 }
569
570 // To compute volume list with directories, query is much slower
computeVolumeList()571 void bRunRestore::computeVolumeList()
572 {
573 brestore->get_info_from_selection(m_fileids, m_jobids, m_dirids, m_findexes);
574 if (m_fileids.size() == 0) {
575 return;
576 }
577
578 Freeze frz_lst(*TableMedia); /* disable updating*/
579 QString q =
580 " SELECT DISTINCT VolumeName, Enabled, InChanger "
581 " FROM File, "
582 " ( " // -- Get all media from this job
583 " SELECT MIN(FirstIndex) AS FirstIndex, MAX(LastIndex) AS LastIndex, "
584 " VolumeName, Enabled, Inchanger "
585 " FROM JobMedia JOIN Media USING (MediaId) "
586 " WHERE JobId IN (" + m_jobids.join(",") + ") "
587 " GROUP BY VolumeName,Enabled,InChanger "
588 " ) AS allmedia "
589 " WHERE File.FileId IN (" + m_fileids.join(",") + ") "
590 " AND File.FileIndex >= allmedia.FirstIndex "
591 " AND File.FileIndex <= allmedia.LastIndex ";
592 int row=0;
593 QStringList results;
594 if (brestore->console()->sql_cmd(q, results)) {
595 QStringList fieldlist;
596 TableMedia->setRowCount(results.size());
597 /* Iterate through the record returned from the query */
598 foreach (QString resultline, results) {
599 // 0 1 2
600 //volname, enabled, inchanger
601 fieldlist = resultline.split("\t");
602 int col=0;
603 TableItemFormatter item(*TableMedia, row++);
604 item.setInChanger(col++, fieldlist.at(2)); // inchanger
605 item.setTextFld(col++, fieldlist.at(0)); // Volume
606 }
607 }
608 TableMedia->verticalHeader()->hide();
609 TableMedia->resizeColumnsToContents();
610 TableMedia->resizeRowsToContents();
611 TableMedia->setEditTriggers(QAbstractItemView::NoEditTriggers);
612 }
613
runRestore(QString tablename)614 int64_t bRunRestore::runRestore(QString tablename)
615 {
616 QString q;
617 QString tmp;
618
619 tmp = ClientCb->currentText();
620 if (tmp == "") {
621 return 0;
622 }
623 q = "restore client=" + tmp;
624
625 tmp = CommentEntry->text();
626 if (tmp != "") {
627 tmp.replace("\"", " ");
628 q += " comment=\"" + tmp + "\"";
629 }
630
631 tmp = StorageCb->currentText();
632 if (tmp != "") {
633 q += " storage=" + tmp;
634 }
635
636 if (UseFileRelocationChk->checkState() == Qt::Checked) {
637 if (UseRegexpChk->checkState() == Qt::Checked) {
638 tmp = WhereRegexpEntry->text();
639 if (tmp != "") {
640 tmp.replace("\"", "");
641 q += " regexwhere=\"" + tmp + "\"";
642 }
643 } else {
644 QStringList lst;
645 tmp = StripPrefixEntry->text();
646 if (tmp != "") {
647 tmp.replace("\"", "");
648 lst.append("!" + tmp + "!!i");
649 }
650 tmp = AddPrefixEntry->text();
651 if (tmp != "") {
652 tmp.replace("\"", "");
653 lst.append("!^!" + tmp + "!");
654 }
655 tmp = AddSuffixEntry->text();
656 if (tmp != "") {
657 tmp.replace("\"", "");
658 lst.append("!([^/])$!$1" + tmp + "!");
659 }
660 if (lst.size() > 0) {
661 q += " regexwhere=\"" + lst.join(",") + "\"";
662 }
663 }
664 } else {
665 tmp = WhereEntry->text();
666 if (tmp != "") {
667 tmp.replace("\"", "");
668 q += " where=\"" + tmp + "\"";
669 }
670 }
671
672 // q += " priority=" + tmp.setNum(PrioritySb->value());
673 // q += " job=\"" + RestoreCb->currentText() + "\"";
674 q += " file=\"?" + tablename + "\"";
675 q += " when=\"" + WhenEditor->dateTime().toString("yyyy-MM-dd hh:mm:ss") + "\"";
676 q += " done yes";
677
678 if (mainWin->m_miscDebug) qDebug() << q;
679 QStringList results;
680 if (brestore->console()->dir_cmd(q, results)) {
681 foreach (QString resultline, results) {
682 QStringList fieldlist = resultline.split("=");
683 if (fieldlist.size() == 2) {
684 return fieldlist.at(1).toLongLong();
685 }
686 }
687 }
688 return 0;
689 }
690
computeRestore()691 void bRunRestore::computeRestore()
692 {
693 QString q = ".bvfs_restore path=b2123 jobid=" + m_jobids.join(",");
694 if (m_fileids.size() > 0) {
695 q += " fileid=" + m_fileids.join(",");
696 }
697 if (m_dirids.size() > 0) {
698 q += " dirid=" + m_dirids.join(",");
699 }
700 if (m_findexes.size() > 0) {
701 q += " hardlink=" + m_findexes.join(",");
702 }
703 if (mainWin->m_miscDebug) qDebug() << q;
704
705 QStringList results;
706 if (brestore->console()->dir_cmd(q, results)) {
707 if (results.size() == 1 && results[0] == "OK") {
708 int64_t jobid = runRestore("b2123");
709 if (mainWin->m_miscDebug) qDebug() << "jobid=" << jobid;
710 q = ".bvfs_cleanup path=b2123";
711 brestore->console()->dir_cmd(q, results);
712 }
713 }
714 }
715