]> git.sur5r.net Git - bacula/bacula/blobdiff - bacula/src/qt-console/restore/brestore.cpp
Change copyright as per agreement with FSFE
[bacula/bacula] / bacula / src / qt-console / restore / brestore.cpp
index 9e592a9f2680f6348d56502c1958d20d3cfef18e..341a99848850938dd63fd6fc0379ddc2422a27e9 100644 (file)
@@ -1,29 +1,20 @@
 /*
-   Bacula® - The Network Backup Solution
-
-   Copyright (C) 2007-2009 Free Software Foundation Europe e.V.
-
-   The main author of Bacula is Kern Sibbald, with contributions from
-   many others, a complete list can be found in the file AUTHORS.
-   This program is Free Software; you can redistribute it and/or
-   modify it under the terms of version three of the GNU Affero General Public
-   License as published by the Free Software Foundation and included
-   in the file LICENSE.
-
-   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 Affero General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-   02110-1301, USA.
-
-   Bacula® is a registered trademark of Kern Sibbald.
-   The licensor of Bacula is the Free Software Foundation Europe
-   (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
-   Switzerland, email:ftf@fsfeurope.org.
+   Bacula(R) - The Network Backup Solution
+
+   Copyright (C) 2000-2016 Kern Sibbald
+
+   The original author of Bacula is Kern Sibbald, with contributions
+   from many others, a complete list can be found in the file AUTHORS.
+
+   You may use this file and others of this release according to the
+   license defined in the LICENSE file, which includes the Affero General
+   Public License, v3.0 ("AGPLv3") and some additional permissions and
+   terms pursuant to its AGPLv3 Section 7.
+
+   This notice must be preserved when any source code is 
+   conveyed and/or propagated.
+
+   Bacula(R) is a registered trademark of Kern Sibbald.
 */
  
 /*
@@ -38,7 +29,7 @@
 #include "restore.h"
 #include "util/fmtwidgetitem.h"
 
-bRestore::bRestore()
+bRestore::bRestore() : Pages()
 {
    m_name = tr("bRestore");
    m_client = "";
@@ -47,13 +38,14 @@ bRestore::bRestore()
    QTreeWidgetItem* thisitem = mainWin->getFromHash(this);
    thisitem->setIcon(0, QIcon(QString::fromUtf8(":images/browse.png")));
    m_populated = false;
+   m_closeable = false;
    m_current = NULL;
    RestoreList->setAcceptDrops(true);
 }
 
+// Populate client table and job associated
 void bRestore::setClient()
 {
-   Pmsg0(000, "Repopulating client table\n");
    // Select the same client, don't touch
    if (m_client == ClientList->currentText()) {
       return;
@@ -85,19 +77,20 @@ void bRestore::setClient()
 
    QString job;
    QStringList results;
+   QStringList fieldlist;
    if (m_console->sql_cmd(jobQuery, results)) {
-      QStringList fieldlist;
-
       /* Iterate through the record returned from the query */
       foreach (QString resultline, results) {
+         //  0       1          2     3
+         // JobId, StartTime, Level, Name
          fieldlist = resultline.split("\t");
          job = fieldlist[1] + " " + fieldlist[3] + "(" + fieldlist[2] + ") " + fieldlist[0];
-         JobList->addItem(job, QVariant(fieldlist[0]));
+         JobList->addItem(job, QVariant(fieldlist[0])); // set also private value
       }
    }
 }
 
-
+// Compute job associated and update the job cache if needed
 void bRestore::setJob()
 {
    if (JobList->currentIndex() < 1) {
@@ -126,6 +119,7 @@ void bRestore::setJob()
       return;
    }
 
+   // TODO: Can take some time if the job contains many dirs
    m_jobids = results.at(0);
    cmd = ".bvfs_update jobid=" + m_jobids;
    m_console->dir_cmd(cmd, results);
@@ -136,7 +130,13 @@ void bRestore::setJob()
    Pmsg0(000, "update done\n");
 }
 
-extern int decode_stat(char *buf, struct stat *statp, int32_t *LinkFI);
+extern int decode_stat(char *buf, struct stat *statp, int stat_size, int32_t *LinkFI);
+
+// refresh button with a filter or limit/offset change
+void bRestore::refreshView()
+{
+   displayFiles(m_pathid, m_path);
+}
 
 void bRestore::displayFiles(int64_t pathid, QString path)
 {
@@ -145,17 +145,19 @@ void bRestore::displayFiles(int64_t pathid, QString path)
    QStringList fieldlist;
    struct stat statp;
    int32_t LinkFI;
-   int nb;
-   int row=0;
+   int nb = 0;
+   int row = 0;
    Freeze frz_lst(*FileList); /* disable updating*/
    Freeze frz_rev(*FileRevisions); /* disable updating*/
    FileList->clearContents();
    FileRevisions->clearContents();
    FileRevisions->setRowCount(0);
 
+   // If we provide pathid, use it (path can be altered by encoding conversion)
    if (pathid > 0) {
       arg = " pathid=" + QString().setNum(pathid);
 
+      // Choose .. update current path to parent dir
       if (path == "..") {
          if (m_path == "/") {
             m_path = "";
@@ -173,11 +175,20 @@ void bRestore::displayFiles(int64_t pathid, QString path)
       m_path = path;
       arg = " path=\"" + m_path + "\"";
    }
+
+   // If a filter is set, add it to the current query
+   if (FilterEntry->text() != "") {
+      QString tmp = FilterEntry->text();
+      tmp.replace("\"", ".");   // basic escape of "
+      arg += " pattern=\"" + tmp + "\"";
+   }
+
    LocationEntry->setText(m_path);
    QString offset = QString().setNum(Offset1Spin->value());
    QString limit=QString().setNum(Offset2Spin->value() - Offset1Spin->value());
    QString q = ".bvfs_lsdir jobid=" + m_jobids + arg 
       + " limit=" + limit + " offset=" + offset ;
+   if (mainWin->m_miscDebug) qDebug() << q;
    if (m_console->dir_cmd(q, results)) {
       nb = results.size();
       FileList->setRowCount(nb);
@@ -185,15 +196,19 @@ void bRestore::displayFiles(int64_t pathid, QString path)
          int col=0;
          //PathId, FilenameId, fileid, jobid, lstat, path
          fieldlist = resultline.split("\t");
+         /*
+          * Note, the next line zaps variable "item", probably
+          *   because the input data in fieldlist is bad.
+          */
+         decode_stat(fieldlist.at(4).toLocal8Bit().data(), &statp, sizeof(statp),  &LinkFI);
          TableItemFormatter item(*FileList, row++);
          item.setFileType(col++, QString("folder")); // folder or file
          item.setTextFld(col++, fieldlist.at(5)); // path
-         decode_stat(fieldlist.at(4).toLocal8Bit().data(), 
-                     &statp, &LinkFI);
          item.setBytesFld(col++, QString().setNum(statp.st_size));
          item.setDateFld(col++, statp.st_mtime); // date
          fieldlist.replace(3, m_jobids);      // use current jobids selection
-         item.widget(1)->setData(Qt::UserRole, fieldlist.join("\t")); // keep info
+         // keep original info on the first cel that is never empty
+         item.widget(1)->setData(Qt::UserRole, fieldlist.join("\t"));
       }
    }
 
@@ -209,9 +224,10 @@ void bRestore::displayFiles(int64_t pathid, QString path)
          TableItemFormatter item(*FileList, row++);
          item.setTextFld(col++, fieldlist.at(5)); // name
          decode_stat(fieldlist.at(4).toLocal8Bit().data(), 
-                     &statp, &LinkFI);
+                     &statp, sizeof(statp), &LinkFI);
          item.setBytesFld(col++, QString().setNum(statp.st_size));
          item.setDateFld(col++, statp.st_mtime);
+         // keep original info on the first cel that is never empty
          item.widget(1)->setData(Qt::UserRole, fieldlist.join("\t")); // keep info
       }
    }
@@ -231,6 +247,7 @@ void bRestore::PgSeltreeWidgetClicked()
    }
 }
 
+// Display all versions of a file for this client
 void bRestore::displayFileVersion(QString pathid, QString fnid, 
                                   QString client, QString filename)
 {
@@ -264,7 +281,7 @@ void bRestore::displayFileVersion(QString pathid, QString fnid,
          item.setTextFld(col++, fieldlist.at(6)); // Volume
          item.setNumericFld(col++, fieldlist.at(3)); // JobId
          decode_stat(fieldlist.at(4).toLocal8Bit().data(), 
-                     &statp, &LinkFI);
+                     &statp, sizeof(statp), &LinkFI);
          item.setBytesFld(col++, QString().setNum(statp.st_size)); // size
          item.setDateFld(col++, statp.st_mtime); // date
          item.setTextFld(col++, fieldlist.at(5)); // chksum
@@ -274,7 +291,9 @@ void bRestore::displayFileVersion(QString pathid, QString fnid,
          fieldlist.removeLast(); // volname
          fieldlist.removeLast(); // md5
          fieldlist << m_path + filename;
-         item.widget(1)->setData(Qt::UserRole, fieldlist.join("\t")); // keep info
+
+         // keep original info on the first cel that is never empty
+         item.widget(1)->setData(Qt::UserRole, fieldlist.join("\t"));
       }
    }
    FileRevisions->verticalHeader()->hide();
@@ -335,6 +354,7 @@ void bRestore::setupPage()
    connect(MergeChk, SIGNAL(clicked()), this, SLOT(setJob()));
    connect(ClearBp, SIGNAL(clicked()), this, SLOT(clearRestoreList()));
    connect(RestoreBp, SIGNAL(clicked()), this, SLOT(runRestore()));
+   connect(FilterBp, SIGNAL(clicked()), this, SLOT(refreshView()));
    m_populated = true;
 }
 
@@ -342,6 +362,7 @@ bRestore::~bRestore()
 {
 }
 
+// Drag & Drop handling, not so easy...
 void bRestoreTable::mousePressEvent(QMouseEvent *event)
 {
    QTableWidget::mousePressEvent(event);
@@ -370,7 +391,7 @@ void bRestoreTable::mouseMoveEvent(QMouseEvent *event)
    }
 
    QList<QTableWidgetItem *> lst = selectedItems();
-   qDebug() << this << " selectedItems: " << lst;
+   if (mainWin->m_miscDebug) qDebug() << this << " selectedItems: " << lst;
    if (lst.isEmpty()) {
       return;
    }
@@ -414,6 +435,7 @@ void bRestoreTable::dragMoveEvent(QDragMoveEvent *event)
    }
 }
 
+// When user releases the button
 void bRestoreTable::dropEvent(QDropEvent *event)
 {
    int col=1;
@@ -432,11 +454,12 @@ void bRestoreTable::dropEvent(QDropEvent *event)
       }
       item.setTextFld(col++, fields.at(5)); // filename
       decode_stat(fields.at(4).toLocal8Bit().data(), 
-                  &statp, &LinkFI);
+                  &statp, sizeof(statp), &LinkFI);
       item.setBytesFld(col++, QString().setNum(statp.st_size)); // size
       item.setDateFld(col++, statp.st_mtime); // date
       item.setNumericFld(col++, fields.at(3)); // jobid
       item.setNumericFld(col++, fields.at(2)); // fileid
+      // keep original info on the first cel that is never empty
       item.widget(1)->setData(Qt::UserRole, event->mimeData()->text());
       event->acceptProposedAction();
    } else {
@@ -444,6 +467,7 @@ void bRestoreTable::dropEvent(QDropEvent *event)
    }
 }
 
+// Use File Relocation bp
 void bRunRestore::UFRcb()
 {
    if (UseFileRelocationChk->checkState() == Qt::Checked) {
@@ -470,6 +494,7 @@ void bRunRestore::UFRcb()
    }
 }
 
+// Expert mode for file relocation
 void bRunRestore::useRegexp()
 {
    if (UseRegexpChk->checkState() == Qt::Checked) {
@@ -485,6 +510,7 @@ void bRunRestore::useRegexp()
    }
 }
 
+// Display Form to run the restore job
 bRunRestore::bRunRestore(bRestore *parent)
 {
    brestore = parent;
@@ -501,10 +527,13 @@ bRunRestore::bRunRestore(bRestore *parent)
    connect(UseFileRelocationChk, SIGNAL(clicked()), this, SLOT(UFRcb()));
    connect(UseRegexpChk, SIGNAL(clicked()), this, SLOT(useRegexp()));
    connect(ActionBp, SIGNAL(accepted()), this, SLOT(computeRestore()));
+   // TODO: handle multiple restore job
    struct job_defaults jd;
-   jd.job_name = parent->console()->restore_list[0];
-   brestore->console()->get_job_defaults(jd);
-   WhereEntry->setText(jd.where);
+   if (parent->console()->restore_list.size() > 0) {
+      jd.job_name = parent->console()->restore_list[0];
+      brestore->console()->get_job_defaults(jd);
+      WhereEntry->setText(jd.where);
+   }
    computeVolumeList();
 }
 
@@ -523,7 +552,7 @@ void bRestore::get_info_from_selection(QStringList &fileids,
          fileids << lst.at(2);
          jobids << lst.at(3);
          decode_stat(lst.at(4).toLocal8Bit().data(), 
-                     &statp, &LinkFI);
+                     &statp, sizeof(statp), &LinkFI);
          if (LinkFI) {
             findexes << lst.at(3) + "," + QString().setNum(LinkFI);
          }
@@ -536,9 +565,9 @@ void bRestore::get_info_from_selection(QStringList &fileids,
    jobids.removeDuplicates();
    dirids.removeDuplicates();
    findexes.removeDuplicates();
-   qDebug() << fileids << jobids << dirids << findexes;
 }
 
+// To compute volume list with directories, query is much slower
 void bRunRestore::computeVolumeList()
 {
    brestore->get_info_from_selection(m_fileids, m_jobids, m_dirids, m_findexes);
@@ -573,7 +602,7 @@ void bRunRestore::computeVolumeList()
          int col=0;
          TableItemFormatter item(*TableMedia, row++);
          item.setInChanger(col++, fieldlist.at(2));    // inchanger
-         item.setTextFld(col++, fieldlist.at(0)); // Volume
+         item.setTextFld(col++, fieldlist.at(0));      // Volume
       }
    }
    TableMedia->verticalHeader()->hide();
@@ -582,6 +611,83 @@ void bRunRestore::computeVolumeList()
    TableMedia->setEditTriggers(QAbstractItemView::NoEditTriggers);
 }
 
+int64_t bRunRestore::runRestore(QString tablename)
+{
+   QString q;
+   QString tmp;
+
+   tmp = ClientCb->currentText();
+   if (tmp == "") {
+      return 0;
+   }
+   q = "restore client=" + tmp;
+
+   tmp = CommentEntry->text();
+   if (tmp != "") {
+      tmp.replace("\"", " ");
+      q += " comment=\"" + tmp + "\"";
+   }
+
+   tmp = StorageCb->currentText();
+   if (tmp != "") {
+      q += " storage=" + tmp;
+   }
+
+   if (UseFileRelocationChk->checkState() == Qt::Checked) {
+      if (UseRegexpChk->checkState() == Qt::Checked) {
+         tmp = WhereRegexpEntry->text();
+         if (tmp != "") {
+            tmp.replace("\"", "");
+            q += " regexwhere=\"" + tmp + "\"";
+         }
+      } else {
+         QStringList lst;
+         tmp = StripPrefixEntry->text();
+         if (tmp != "") {
+            tmp.replace("\"", "");
+            lst.append("!" + tmp + "!!i");
+         }
+         tmp = AddPrefixEntry->text();
+         if (tmp != "") {
+            tmp.replace("\"", "");
+            lst.append("!^!" + tmp + "!");
+         }
+         tmp = AddSuffixEntry->text();
+         if (tmp != "") {
+            tmp.replace("\"", "");
+            lst.append("!([^/])$!$1" + tmp + "!");
+         }
+         if (lst.size() > 0) {
+            q += " regexwhere=\"" + lst.join(",") + "\"";
+         }
+      }
+   } else {
+      tmp = WhereEntry->text();
+      if (tmp != "") {
+         tmp.replace("\"", "");
+         q += " where=\"" + tmp + "\"";
+      }
+   }
+
+//   q += " priority=" + tmp.setNum(PrioritySb->value());
+//   q += " job=\"" + RestoreCb->currentText() + "\"";
+   q += " file=\"?" + tablename + "\"";
+   q += " when=\"" + WhenEditor->dateTime().toString("yyyy-MM-dd hh:mm:ss") + "\"";
+   q += " done yes";
+   
+   if (mainWin->m_miscDebug) qDebug() << q;
+   QStringList results;
+   if (brestore->console()->dir_cmd(q, results)) {
+      foreach (QString resultline, results) {
+         QStringList fieldlist = resultline.split("=");
+         if (fieldlist.size() == 2) {
+            return fieldlist.at(1).toLongLong();
+         }
+      }
+   }
+   return 0;
+}
+
 void bRunRestore::computeRestore()
 {
    QString q = ".bvfs_restore path=b2123 jobid=" + m_jobids.join(",");
@@ -594,12 +700,13 @@ void bRunRestore::computeRestore()
    if (m_findexes.size() > 0) {
       q += " hardlink=" + m_findexes.join(",");
    }
-   qDebug() << q;
+   if (mainWin->m_miscDebug) qDebug() << q;
 
    QStringList results;
    if (brestore->console()->dir_cmd(q, results)) {
       if (results.size() == 1 && results[0] == "OK") {
-         qDebug() << "Run restore!";
+         int64_t jobid = runRestore("b2123");
+         if (mainWin->m_miscDebug) qDebug() << "jobid=" << jobid;
          q = ".bvfs_cleanup path=b2123";
          brestore->console()->dir_cmd(q, results);
       }