[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