[Pkg-owncloud-commits] [owncloud-client] 13/470: Attempt to recover from backup restoration on the server

Sandro Knauß hefee-guest at moszumanska.debian.org
Thu May 12 16:24:38 UTC 2016


This is an automated email from the git hooks/post-receive script.

hefee-guest pushed a commit to branch master
in repository owncloud-client.

commit 1bb76f534391c6f3f0709a2297b9ae6700b46efd
Author: Olivier Goffart <ogoffart at woboq.com>
Date:   Tue Jan 5 11:47:17 2016 +0100

    Attempt to recover from backup restoration on the server
    
    If all the files bring us to past timestamp, it is possibly a backup
    restoration in the server. In which case we want don't want to just
    overwrite newer files with the older ones.
    
    Issue #2325
---
 src/gui/folder.cpp         | 21 +++++++++++
 src/gui/folder.h           |  2 ++
 src/libsync/syncengine.cpp | 89 +++++++++++++++++++++++++++++++++++++---------
 src/libsync/syncengine.h   | 21 ++++++++++-
 4 files changed, 115 insertions(+), 18 deletions(-)

diff --git a/src/gui/folder.cpp b/src/gui/folder.cpp
index 4f262c2..5d620d2 100644
--- a/src/gui/folder.cpp
+++ b/src/gui/folder.cpp
@@ -914,6 +914,8 @@ void Folder::startSync(const QStringList &pathList)
     //direct connection so the message box is blocking the sync.
     connect(_engine.data(), SIGNAL(aboutToRemoveAllFiles(SyncFileItem::Direction,bool*)),
                     SLOT(slotAboutToRemoveAllFiles(SyncFileItem::Direction,bool*)));
+    connect(_engine.data(), SIGNAL(aboutToRestoreBackup(bool*)),
+            SLOT(slotAboutToRestoreBackup(bool*)));
     connect(_engine.data(), SIGNAL(folderDiscovered(bool,QString)), this, SLOT(slotFolderDiscovered(bool,QString)));
     connect(_engine.data(), SIGNAL(transmissionProgress(ProgressInfo)), this, SLOT(slotTransmissionProgress(ProgressInfo)));
     connect(_engine.data(), SIGNAL(itemCompleted(const SyncFileItem &, const PropagatorJob &)),
@@ -1179,6 +1181,25 @@ void Folder::slotAboutToRemoveAllFiles(SyncFileItem::Direction, bool *cancel)
     }
 }
 
+void Folder::slotAboutToRestoreBackup(bool *restore)
+{
+    QString msg =
+        tr("This sync would reset the files to an erlier time in the sync folder '%1'.\n"
+           "This might be because a backup was restored on the server.\n"
+           "Continuing the sync as normal will cause all your files to be overwritten by an older "
+           "file in an earlier state. "
+           "Do you want to keep your local most recent files as conflict files?");
+    QMessageBox msgBox(QMessageBox::Warning, tr("Backup detected"),
+                       msg.arg(alias()));
+    msgBox.addButton(tr("Normal Synchronisation"), QMessageBox::DestructiveRole);
+    QPushButton* keepBtn = msgBox.addButton(tr("Keep Local Files as Conflict"), QMessageBox::AcceptRole);
+
+    if (msgBox.exec() == -1) {
+        *restore = true;
+        return;
+    }
+    *restore = msgBox.clickedButton() == keepBtn;
+}
 
 
 void FolderDefinition::save(QSettings& settings, const FolderDefinition& folder)
diff --git a/src/gui/folder.h b/src/gui/folder.h
index ea7ad71..1b8c710 100644
--- a/src/gui/folder.h
+++ b/src/gui/folder.h
@@ -222,7 +222,9 @@ public slots:
        */
      void slotTerminateSync();
 
+     // connected to the corresponding signals in the SyncEngine
      void slotAboutToRemoveAllFiles(SyncFileItem::Direction, bool*);
+     void slotAboutToRestoreBackup(bool*);
 
 
      /**
diff --git a/src/libsync/syncengine.cpp b/src/libsync/syncengine.cpp
index cf99c63..54f33a3 100644
--- a/src/libsync/syncengine.cpp
+++ b/src/libsync/syncengine.cpp
@@ -68,6 +68,8 @@ SyncEngine::SyncEngine(AccountPtr account, CSYNC *ctx, const QString& localPath,
   , _progressInfo(new ProgressInfo)
   , _hasNoneFiles(false)
   , _hasRemoveFile(false)
+  , _hasForwardInTimeFiles(false)
+  , _backInTimeFiles(0)
   , _uploadLimit(0)
   , _downloadLimit(0)
   , _newBigFolderSizeLimit(-1)
@@ -541,17 +543,27 @@ int SyncEngine::treewalkFile( TREE_WALK_FILE *file, bool remote )
     case CSYNC_INSTRUCTION_ERROR:
         dir = SyncFileItem::None;
         break;
-    case CSYNC_INSTRUCTION_EVAL:
-    case CSYNC_INSTRUCTION_NEW:
     case CSYNC_INSTRUCTION_SYNC:
-    case CSYNC_INSTRUCTION_STAT_ERROR:
-    default:
-        dir = remote ? SyncFileItem::Down : SyncFileItem::Up;
-        if (!remote && file->instruction == CSYNC_INSTRUCTION_SYNC) {
+        if (!remote) {
             // An upload of an existing file means that the file was left unchanged on the server
             // This counts as a NONE for detecting if all the files on the server were changed
             _hasNoneFiles = true;
+        } else if (!item->_isDirectory) {
+            if (std::difftime(file->modtime, file->other.modtime) < 0) {
+                // We are going back on time
+                _backInTimeFiles++;
+                qDebug() << file->path << "has a timestamp earlier than the local file";
+            } else {
+                _hasForwardInTimeFiles = true;
+            }
         }
+        dir = remote ? SyncFileItem::Down : SyncFileItem::Up;
+        break;
+    case CSYNC_INSTRUCTION_NEW:
+    case CSYNC_INSTRUCTION_EVAL:
+    case CSYNC_INSTRUCTION_STAT_ERROR:
+    default:
+        dir = remote ? SyncFileItem::Down : SyncFileItem::Up;
         break;
     }
 
@@ -812,6 +824,26 @@ void SyncEngine::slotDiscoveryJobFinished(int discoveryResult)
         (*it)->_file = adjustRenamedPath((*it)->_file);
     }
 
+    if (!_hasNoneFiles && _hasRemoveFile) {
+        qDebug() << Q_FUNC_INFO << "All the files are going to be changed, asking the user";
+        bool cancel = false;
+        emit aboutToRemoveAllFiles(_syncedItems.first()->_direction, &cancel);
+        if (cancel) {
+            qDebug() << Q_FUNC_INFO << "Abort sync";
+            finalize(false);
+            return;
+        }
+    }
+    if (!_hasForwardInTimeFiles && _backInTimeFiles >= 2) {
+        qDebug() << "All the changes are bringing files in the past, asking the user";
+        // this typically happen when a backup is restored on the server
+        bool restore = false;
+        emit aboutToRestoreBackup(&restore);
+        if (restore) {
+            restoreOldFiles();
+        }
+    }
+
     // Sort items per destination
     std::sort(_syncedItems.begin(), _syncedItems.end());
 
@@ -824,17 +856,6 @@ void SyncEngine::slotDiscoveryJobFinished(int discoveryResult)
     emit transmissionProgress(*_progressInfo);
     _progressInfo->start();
 
-    if (!_hasNoneFiles && _hasRemoveFile) {
-        qDebug() << Q_FUNC_INFO << "All the files are going to be changed, asking the user";
-        bool cancel = false;
-        emit aboutToRemoveAllFiles(_syncedItems.first()->_direction, &cancel);
-        if (cancel) {
-            qDebug() << Q_FUNC_INFO << "Abort sync";
-            finalize(false);
-            return;
-        }
-    }
-
     // post update phase script: allow to tweak stuff by a custom script in debug mode.
     if( !qgetenv("OWNCLOUD_POST_UPDATE_SCRIPT").isEmpty() ) {
 #ifndef NDEBUG
@@ -1212,6 +1233,40 @@ QByteArray SyncEngine::getPermissions(const QString& file) const
     return _remotePerms.value(file);
 }
 
+void SyncEngine::restoreOldFiles()
+{
+    /* When the server is trying to send us lots of file in the past, this means that a backup
+       was restored in the server.  In that case, we should not simply overwrite the newer file
+       on the file system with the older file from the backup on the server. Instead, we will
+       upload the client file. But we still downloaded the old file in a conflict file just in case
+    */
+
+    for (auto it = _syncedItems.begin(); it != _syncedItems.end(); ++it) {
+        if ((*it)->_direction != SyncFileItem::Down)
+            continue;
+
+        switch ((*it)->_instruction) {
+        case CSYNC_INSTRUCTION_SYNC:
+            qDebug() << "restoreOldFiles: RESTORING" << (*it)->_file;
+            (*it)->_instruction = CSYNC_INSTRUCTION_CONFLICT;
+            break;
+        case CSYNC_INSTRUCTION_REMOVE:
+            qDebug() << "restoreOldFiles: RESTORING" << (*it)->_file;
+            (*it)->_should_update_metadata = true;
+            (*it)->_instruction = CSYNC_INSTRUCTION_NEW;
+            (*it)->_direction = SyncFileItem::Up;
+            break;
+        case CSYNC_INSTRUCTION_RENAME:
+        case CSYNC_INSTRUCTION_NEW:
+            // Ideally we should try to revert the rename or remove, but this would be dangerous
+            // without re-doing the reconcile phase.  So just let it happen.
+            break;
+        default:
+            break;
+        }
+    }
+}
+
 bool SyncEngine::estimateState(QString fn, csync_ftw_type_e t, SyncFileStatus* s)
 {
     Q_UNUSED(t);
diff --git a/src/libsync/syncengine.h b/src/libsync/syncengine.h
index f235c4a..7e29309 100644
--- a/src/libsync/syncengine.h
+++ b/src/libsync/syncengine.h
@@ -120,7 +120,18 @@ signals:
     void finished(bool success);
     void started();
 
+    /**
+     * Emited when the sync engine detects that all the files have been removed or change.
+     * This usually happen when the server was reset or something.
+     * Set *cancel to true in a slot connected from this signal to abort the sync.
+     */
     void aboutToRemoveAllFiles(SyncFileItem::Direction direction, bool *cancel);
+    /**
+     * Emited when the sync engine detects that all the files are changed to dates in the past.
+     * This usually happen when a backup was restored on the server from an earlier date.
+     * Set *restore to true in a slot connected from this signal to re-upload all files.
+     */
+    void aboutToRestoreBackup(bool *restore);
 
     // A new folder was discovered and was not synced because of the confirmation feature
     void newBigFolder(const QString &folder);
@@ -206,8 +217,16 @@ private:
     void checkForPermission();
     QByteArray getPermissions(const QString& file) const;
 
-    bool _hasNoneFiles; // true if there is at least one file with instruction NONE
+    /**
+     * Instead of downloading files from the server, upload the files to the server
+     */
+    void restoreOldFiles();
+
+    bool _hasNoneFiles; // true if there is at least one file which was not changed on the server
     bool _hasRemoveFile; // true if there is at leasr one file with instruction REMOVE
+    bool _hasForwardInTimeFiles; // true if there is at least one file from the server that goes forward in time
+    int _backInTimeFiles; // number of files which goes back in time from the server
+
 
     int _uploadLimit;
     int _downloadLimit;

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-owncloud/owncloud-client.git



More information about the Pkg-owncloud-commits mailing list