Comparar commits
73 Commits
| Autor | SHA1 | Data | |
|---|---|---|---|
| dbcaaa2e75 | |||
| 7879c470b3 | |||
| 3c7545a45f | |||
| 4c1fdf1dee | |||
| 18e25122db | |||
| 439e688906 | |||
| 4198d9f420 | |||
| 06579a5c70 | |||
| df773ea8bb | |||
| e7be4faac8 | |||
| a184c6bec1 | |||
| 1102ac20ac | |||
| 6a4ae63f14 | |||
| 6c6961e4d9 | |||
| 78a798eef3 | |||
| 19dd656989 | |||
| d9fac50e9b | |||
| 9614a94035 | |||
| 5002964546 | |||
| 4cca1ba55f | |||
| 3e99c32582 | |||
| 74ce597f8d | |||
| a27b2d94b3 | |||
| 890e771ec1 | |||
| 5df10cb8f8 | |||
| 9acc974268 | |||
| 42e64026ae | |||
| 78e7d13f9f | |||
| 2d55332a45 | |||
| 72cd9abd4a | |||
| 0d16cf41fe | |||
| 65e4afedc4 | |||
| b76a9654cc | |||
| 38cf459b3e | |||
| ed7416098e | |||
| 517623e457 | |||
| f89bc09fd1 | |||
| f854c5263b | |||
| 70da607e06 | |||
| 4f28b2daad | |||
| 8884fe7236 | |||
| bb3efc5988 | |||
| f6665ccc81 | |||
| f1e9be4fa8 | |||
| 9db23d4df1 | |||
| 9d16ad844c | |||
| b0700ebbab | |||
| 2bda55be81 | |||
| e859d220be | |||
| c3ae5123cb | |||
| a1a5111a8a | |||
| ee211d7609 | |||
| 1fc5a76622 | |||
| a764d7eb86 | |||
| 605a18ff73 | |||
| 92e86641d1 | |||
| c8cfb3160e | |||
| 268fc97a71 | |||
| de2458d892 | |||
| d75b838897 | |||
| 4df7cab72a | |||
| 59c1fdbe05 | |||
| 26234dbf6c | |||
| 05a254b527 | |||
| d282a8380e | |||
| 83dfbb933b | |||
| 100603fdc0 | |||
| 8a70d22af7 | |||
| a63d970e5e | |||
| f6c77fad17 | |||
| 0249a68420 | |||
| aa6f041c36 | |||
| dce3f8c4f6 |
@@ -58,9 +58,6 @@ if( UNIX AND NOT APPLE )
|
||||
endif()
|
||||
####
|
||||
|
||||
# Enable Q_ASSERT etc. in all builds
|
||||
add_definitions( -DQT_FORCE_ASSERTS )
|
||||
|
||||
include(GNUInstallDirs)
|
||||
include(DefineInstallationPaths)
|
||||
include(GenerateExportHeader)
|
||||
|
||||
+5
-4
@@ -1,10 +1,11 @@
|
||||
ChangeLog
|
||||
=========
|
||||
|
||||
version 2.3.0 (2017-0x-xx)
|
||||
* WiP!
|
||||
* WiP Switch Windows and OS X build to 5.6.2
|
||||
* WiP Performance improvements for exclude detection
|
||||
version 2.3.0 (2017-02-xx)
|
||||
* Decreased memory usage during sync
|
||||
* Overlay icons: Lower CPU usage
|
||||
* Allow to not sync the server's external storages by default
|
||||
* Switch Windows and OS X build to 5.6.2
|
||||
* Switch to new ownCloud server WebDAV endpoint
|
||||
* Chunking NG: New file upload chunking algorithmn for ownCloud server 9.2
|
||||
* Allow to sync a folder to multiple different servers (Filename change from .csync_journal.db to _sync_$HASH.db)
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@ set( MIRALL_VERSION_YEAR 2016 )
|
||||
set( MIRALL_SOVERSION 0 )
|
||||
|
||||
if ( NOT DEFINED MIRALL_VERSION_SUFFIX )
|
||||
set( MIRALL_VERSION_SUFFIX "git") #e.g. beta1, beta2, rc1
|
||||
set( MIRALL_VERSION_SUFFIX "beta1") #e.g. beta1, beta2, rc1
|
||||
endif( NOT DEFINED MIRALL_VERSION_SUFFIX )
|
||||
|
||||
if( NOT DEFINED MIRALL_VERSION_BUILD )
|
||||
|
||||
@@ -3,7 +3,7 @@ StrCpy $MUI_FINISHPAGE_SHOWREADME_TEXT_STRING "Показати примітки
|
||||
StrCpy $ConfirmEndProcess_MESSAGEBOX_TEXT "Знайдено процес(и) ${APPLICATION_EXECUTABLE}, які необхідно зупинити.$\nХочете щоб програма установки зробила це самостійно?"
|
||||
StrCpy $ConfirmEndProcess_KILLING_PROCESSES_TEXT "Завершення процесів ${APPLICATION_EXECUTABLE}."
|
||||
StrCpy $ConfirmEndProcess_KILL_NOT_FOUND_TEXT "Не знайдено процеси, які необхідно зупинити!"
|
||||
StrCpy $PageReinstall_NEW_Field_1 "Знайдено застарілу версію програми ${APPLICATION_NAME}. Рекомендуємо її спочатку видалити. Оберіть подальшу дію та натисніть $\"Далі$\"."
|
||||
StrCpy $PageReinstall_NEW_Field_1 "У вашої системі встановлена застаріла версія додатку ${APPLICATION_NAME}. Рекомендуємо видалити її перед початком встановлення поточної версії. Оберіть подальшу дію та натисніть $\"Далі$\"."
|
||||
StrCpy $PageReinstall_NEW_Field_2 "Видалити перед установкою"
|
||||
StrCpy $PageReinstall_NEW_Field_3 "Не видаляти"
|
||||
StrCpy $PageReinstall_NEW_MUI_HEADER_TEXT_TITLE "Установлено"
|
||||
|
||||
@@ -41,7 +41,7 @@ endif (MEM_NULL_TESTS)
|
||||
add_subdirectory(src)
|
||||
|
||||
if (UNIT_TESTING)
|
||||
set(WITH_UNIT_TESTING ON)
|
||||
set(WITH_TESTING ON)
|
||||
|
||||
find_package(CMocka)
|
||||
if (CMOCKA_FOUND)
|
||||
|
||||
@@ -26,4 +26,4 @@
|
||||
#cmakedefine HAVE___MINGW_ASPRINTF 1
|
||||
#cmakedefine HAVE_ASPRINTF 1
|
||||
|
||||
#cmakedefine WITH_UNIT_TESTING 1
|
||||
#cmakedefine WITH_TESTING 1
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
#define CSYNC_LOG_CATEGORY_NAME "csync.exclude"
|
||||
#include "csync_log.h"
|
||||
|
||||
#ifndef WITH_UNIT_TESTING
|
||||
#ifndef WITH_TESTING
|
||||
static
|
||||
#endif
|
||||
int _csync_exclude_add(c_strlist_t **inList, const char *string) {
|
||||
|
||||
@@ -36,7 +36,7 @@ enum csync_exclude_type_e {
|
||||
};
|
||||
typedef enum csync_exclude_type_e CSYNC_EXCLUDE_TYPE;
|
||||
|
||||
#ifdef WITH_UNIT_TESTING
|
||||
#ifdef WITH_TESTING
|
||||
int OCSYNC_EXPORT _csync_exclude_add(c_strlist_t **inList, const char *string);
|
||||
#endif
|
||||
|
||||
|
||||
@@ -50,6 +50,21 @@ Identifying Basic Functionality Problems
|
||||
As an example, after installing the ``cadaver`` app, you can issue the
|
||||
``propget`` command to obtain various properties pertaining to the current
|
||||
directory and also verify WebDAV server connection.
|
||||
|
||||
"CSync unknown error"
|
||||
---------------------
|
||||
|
||||
If you see this error message stop your client, delete the
|
||||
``.csync_journal.db`` file, and then restart your client.
|
||||
There is a ``.csync_journal.db`` file inside the folder of every account
|
||||
configured on your client.
|
||||
|
||||
.. NOTE::
|
||||
Please note that this will also erase some of your settings about which
|
||||
files to download.
|
||||
|
||||
See https://github.com/owncloud/client/issues/5226 for more discussion of this
|
||||
issue.
|
||||
|
||||
|
||||
Isolating other issues
|
||||
|
||||
+64
-8
@@ -646,6 +646,57 @@ X-GNOME-Autostart-Delay=3
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
Comment[oc]=@APPLICATION_NAME@ sincronizacion del client
|
||||
GenericName[oc]=Dorsièr de Sincronizacion
|
||||
@@ -671,7 +722,9 @@ Comment[ja_JP]=@APPLICATION_NAME@ デスクトップ同期クライアント
|
||||
GenericName[ja_JP]=フォルダー同期
|
||||
Name[ja_JP]=@APPLICATION_NAME@ デスクトップ同期クライアント
|
||||
Icon[ja_JP]=@APPLICATION_EXECUTABLE@
|
||||
Comment[el]=@ΟΝΟΜΑ_ΕΦΑΡΜΟΓΗΣ@ συγχρονισμός επιφάνειας εργασίας πελάτη
|
||||
GenericName[el]=Συγχρονισμός φακέλου
|
||||
Name[el]=@ΟΝΟΜΑ_ΕΦΑΡΜΟΓΗΣ@ συγχρονισμός επιφάνειας εργασίας πελάτη
|
||||
Icon[el]=@APPLICATION_EXECUTABLE@
|
||||
Comment[en_GB]=@APPLICATION_NAME@ desktop synchronisation client
|
||||
GenericName[en_GB]=Folder Sync
|
||||
@@ -685,10 +738,13 @@ Comment[de_DE]=@APPLICATION_NAME@ Desktop-Synchronisationsclient
|
||||
GenericName[de_DE]=Ordner-Synchronisation
|
||||
Name[de_DE]=@APPLICATION_NAME@ Desktop-Synchronisationsclient
|
||||
Icon[de_DE]=@APPLICATION_EXECUTABLE@
|
||||
Comment[pl]=@APPLICATION_NAME@ klient synchronizacji dla komputerów stacjonarnych
|
||||
GenericName[pl]=Folder Synchronizacji
|
||||
Name[pl]=@APPLICATION_NAME@ klient synchronizacji dla komputerów stacjonarnych
|
||||
Icon[pl]=@APPLICATION_EXECUTABLE@
|
||||
Comment[bg_BG]=@APPLICATION_NAME@ клиент за десктоп синхронизация
|
||||
GenericName[bg_BG]=Синхронизиране на папката
|
||||
Name[bg_BG]=@APPLICATION_NAME@ клиент десктоп синхронизация
|
||||
Icon[bg_BG]=@APPLICATION_EXECUTABLE@
|
||||
GenericName[fa]=همسان سازی پوشهها
|
||||
Name[fa]=@APPLICATION_EXECUTABLE@ نسخهی همسان سازی مشتری
|
||||
Icon[fa]=@APPLICATION_EXECUTABLE@
|
||||
Comment[fr]=@APPLICATION_NAME@ synchronisation du client
|
||||
GenericName[fr]=Dossier de Synchronisation
|
||||
Name[fr]=@APPLICATION_NAME@ synchronisation du client
|
||||
@@ -724,10 +780,10 @@ Comment[et_EE]=@APPLICATION_NAME@ sünkroonimise klient töölauale
|
||||
GenericName[et_EE]=Kaustade sünkroonimine
|
||||
Name[et_EE]=@APPLICATION_NAME@ sünkroonimise klient töölauale
|
||||
Icon[et_EE]=@APPLICATION_EXECUTABLE@
|
||||
Comment[bg_BG]=@APPLICATION_NAME@ клиент за десктоп синхронизация
|
||||
GenericName[bg_BG]=Синхронизиране на папката
|
||||
Name[bg_BG]=@APPLICATION_NAME@ клиент десктоп синхронизация
|
||||
Icon[bg_BG]=@APPLICATION_EXECUTABLE@
|
||||
Comment[pl]=@APPLICATION_NAME@ klient synchronizacji dla komputerów stacjonarnych
|
||||
GenericName[pl]=Folder Synchronizacji
|
||||
Name[pl]=@APPLICATION_NAME@ klient synchronizacji dla komputerów stacjonarnych
|
||||
Icon[pl]=@APPLICATION_EXECUTABLE@
|
||||
Comment[pt_BR]=@APPLICATION_NAME@ cliente de sincronização do computador
|
||||
GenericName[pt_BR]=Sincronização de Pasta
|
||||
Name[pt_BR]=@APPLICATION_NAME@ cliente de sincronização de desktop
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
project(cmd)
|
||||
set(CMAKE_AUTOMOC TRUE)
|
||||
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti")
|
||||
|
||||
set(cmd_NAME ${APPLICATION_EXECUTABLE}cmd)
|
||||
set(cmd_SRC
|
||||
cmd.cpp
|
||||
|
||||
@@ -3,8 +3,6 @@ set(CMAKE_AUTOMOC TRUE)
|
||||
|
||||
add_subdirectory(updater)
|
||||
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti")
|
||||
|
||||
#TODO Move resources files
|
||||
qt_add_resources(MIRALL_RC_SRC ../../client.qrc)
|
||||
if ( IS_DIRECTORY ${OEM_THEME_DIR} )
|
||||
|
||||
@@ -46,11 +46,17 @@ AccountManager *AccountManager::instance()
|
||||
bool AccountManager::restore()
|
||||
{
|
||||
auto settings = Utility::settingsWithGroup(QLatin1String(accountsC));
|
||||
if (settings->status() != QSettings::NoError) {
|
||||
qDebug() << "Could not read settings from" << settings->fileName()
|
||||
<< settings->status();
|
||||
return false;
|
||||
}
|
||||
|
||||
// If there are no accounts, check the old format.
|
||||
if (settings->childGroups().isEmpty()
|
||||
&& !settings->contains(QLatin1String(versionC))) {
|
||||
return restoreFromLegacySettings();
|
||||
restoreFromLegacySettings();
|
||||
return true;
|
||||
}
|
||||
|
||||
foreach (const auto& accountId, settings->childGroups()) {
|
||||
@@ -69,6 +75,9 @@ bool AccountManager::restore()
|
||||
|
||||
bool AccountManager::restoreFromLegacySettings()
|
||||
{
|
||||
qDebug() << "Migrate: restoreFromLegacySettings, checking settings group"
|
||||
<< Theme::instance()->appName();
|
||||
|
||||
// try to open the correctly themed settings
|
||||
auto settings = Utility::settingsWithGroup(Theme::instance()->appName());
|
||||
|
||||
@@ -86,7 +95,7 @@ bool AccountManager::restoreFromLegacySettings()
|
||||
|
||||
QFileInfo fi( oCCfgFile );
|
||||
if( fi.isReadable() ) {
|
||||
QSettings *oCSettings = new QSettings(oCCfgFile, QSettings::IniFormat);
|
||||
std::unique_ptr<QSettings> oCSettings(new QSettings(oCCfgFile, QSettings::IniFormat));
|
||||
oCSettings->beginGroup(QLatin1String("ownCloud"));
|
||||
|
||||
// Check the theme url to see if it is the same url that the oC config was for
|
||||
@@ -101,9 +110,7 @@ bool AccountManager::restoreFromLegacySettings()
|
||||
qDebug() << "Migrate oC config if " << oCUrl << " == " << overrideUrl << ":"
|
||||
<< (oCUrl == overrideUrl ? "Yes" : "No");
|
||||
if( oCUrl == overrideUrl ) {
|
||||
settings.reset( oCSettings );
|
||||
} else {
|
||||
delete oCSettings;
|
||||
settings = std::move(oCSettings);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -196,8 +203,8 @@ void AccountManager::saveAccountHelper(Account* acc, QSettings& settings, bool s
|
||||
if (acc->_am) {
|
||||
CookieJar* jar = qobject_cast<CookieJar*>(acc->_am->cookieJar());
|
||||
if (jar) {
|
||||
qDebug() << "Saving cookies.";
|
||||
jar->save();
|
||||
qDebug() << "Saving cookies." << acc->cookieJarPath();
|
||||
jar->save(acc->cookieJarPath());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -289,6 +296,8 @@ void AccountManager::deleteAccount(AccountState* account)
|
||||
auto copy = *it; // keep a reference to the shared pointer so it does not delete it just yet
|
||||
_accounts.erase(it);
|
||||
|
||||
QFile::remove(account->account()->cookieJarPath());
|
||||
|
||||
auto settings = Utility::settingsWithGroup(QLatin1String(accountsC));
|
||||
settings->remove(account->account()->id());
|
||||
|
||||
|
||||
@@ -36,7 +36,9 @@ public:
|
||||
|
||||
/**
|
||||
* Creates account objects from a given settings file.
|
||||
* return true if the account was restored
|
||||
*
|
||||
* Returns false if there was an error reading the settings,
|
||||
* but note that settings not existing is not an error.
|
||||
*/
|
||||
bool restore();
|
||||
|
||||
|
||||
@@ -156,7 +156,23 @@ Application::Application(int &argc, char **argv) :
|
||||
|
||||
connect(this, SIGNAL(messageReceived(QString, QObject*)), SLOT(slotParseMessage(QString, QObject*)));
|
||||
|
||||
AccountManager::instance()->restore();
|
||||
if (!AccountManager::instance()->restore()) {
|
||||
// If there is an error reading the account settings, try again
|
||||
// after a couple of seconds, if that fails, give up.
|
||||
// (non-existence is not an error)
|
||||
Utility::sleep(5);
|
||||
if (!AccountManager::instance()->restore()) {
|
||||
qDebug() << "Could not read the account settings, quitting";
|
||||
QMessageBox::critical(
|
||||
0,
|
||||
tr("Error accessing the configuration file"),
|
||||
tr("There was an error while accessing the configuration "
|
||||
"file at %1.").arg(ConfigFile().configFile()),
|
||||
tr("Quit ownCloud"));
|
||||
QTimer::singleShot(0, qApp, SLOT(quit()));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
FolderMan::instance()->setSyncEnabled(true);
|
||||
|
||||
|
||||
@@ -130,7 +130,7 @@ void ShibbolethCredentials::fetchFromKeychain()
|
||||
ReadPasswordJob *job = new ReadPasswordJob(Theme::instance()->appName());
|
||||
job->setSettings(Utility::settingsWithGroup(Theme::instance()->appName(), job).release());
|
||||
job->setInsecureFallback(false);
|
||||
job->setKey(keychainKey(_account->url().toString(), "shibAssertion"));
|
||||
job->setKey(keychainKey(_account->url().toString(), user()));
|
||||
connect(job, SIGNAL(finished(QKeychain::Job*)), SLOT(slotReadJobDone(QKeychain::Job*)));
|
||||
job->start();
|
||||
}
|
||||
@@ -309,7 +309,7 @@ void ShibbolethCredentials::storeShibCookie(const QNetworkCookie &cookie)
|
||||
job->setSettings(Utility::settingsWithGroup(Theme::instance()->appName(), job).release());
|
||||
// we don't really care if it works...
|
||||
//connect(job, SIGNAL(finished(QKeychain::Job*)), SLOT(slotWriteJobDone(QKeychain::Job*)));
|
||||
job->setKey(keychainKey(_account->url().toString(), "shibAssertion"));
|
||||
job->setKey(keychainKey(_account->url().toString(), user()));
|
||||
job->setTextData(QString::fromUtf8(cookie.toRawForm()));
|
||||
job->start();
|
||||
}
|
||||
@@ -318,7 +318,7 @@ void ShibbolethCredentials::removeShibCookie()
|
||||
{
|
||||
DeletePasswordJob *job = new DeletePasswordJob(Theme::instance()->appName());
|
||||
job->setSettings(Utility::settingsWithGroup(Theme::instance()->appName(), job).release());
|
||||
job->setKey(keychainKey(_account->url().toString(), "shibAssertion"));
|
||||
job->setKey(keychainKey(_account->url().toString(), user()));
|
||||
job->start();
|
||||
}
|
||||
|
||||
|
||||
+58
-159
@@ -52,7 +52,6 @@ Folder::Folder(const FolderDefinition& definition,
|
||||
: QObject(parent)
|
||||
, _accountState(accountState)
|
||||
, _definition(definition)
|
||||
, _csyncError(false)
|
||||
, _csyncUnavail(false)
|
||||
, _wipeDb(false)
|
||||
, _proxyDirty(true)
|
||||
@@ -87,8 +86,6 @@ Folder::Folder(const FolderDefinition& definition,
|
||||
|
||||
connect(_accountState.data(), SIGNAL(isConnectedChanged()), this, SIGNAL(canSyncChanged()));
|
||||
connect(_engine.data(), SIGNAL(rootEtag(QString)), this, SLOT(etagRetreivedFromSyncEngine(QString)));
|
||||
connect(_engine.data(), SIGNAL(treeWalkResult(const SyncFileItemVector&)),
|
||||
this, SLOT(slotThreadTreeWalkResult(const SyncFileItemVector&)), Qt::QueuedConnection);
|
||||
|
||||
connect(_engine.data(), SIGNAL(started()), SLOT(slotSyncStarted()), Qt::QueuedConnection);
|
||||
connect(_engine.data(), SIGNAL(finished(bool)), SLOT(slotSyncFinished(bool)), Qt::QueuedConnection);
|
||||
@@ -102,8 +99,8 @@ Folder::Folder(const FolderDefinition& definition,
|
||||
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 &)),
|
||||
this, SLOT(slotItemCompleted(const SyncFileItem &, const PropagatorJob &)));
|
||||
connect(_engine.data(), SIGNAL(itemCompleted(const SyncFileItemPtr &)),
|
||||
this, SLOT(slotItemCompleted(const SyncFileItemPtr &)));
|
||||
connect(_engine.data(), SIGNAL(newBigFolder(QString,bool)),
|
||||
this, SLOT(slotNewBigFolderDiscovered(QString,bool)));
|
||||
connect(_engine.data(), SIGNAL(seenLockedFile(QString)), FolderMan::instance(), SLOT(slotSyncOnceFileUnlocks(QString)));
|
||||
@@ -139,13 +136,13 @@ void Folder::checkLocalPath()
|
||||
} else {
|
||||
// Check directory again
|
||||
if( !FileSystem::fileExists(_definition.localPath, fi) ) {
|
||||
_syncResult.setErrorString(tr("Local folder %1 does not exist.").arg(_definition.localPath));
|
||||
_syncResult.appendErrorString(tr("Local folder %1 does not exist.").arg(_definition.localPath));
|
||||
_syncResult.setStatus( SyncResult::SetupError );
|
||||
} else if( !fi.isDir() ) {
|
||||
_syncResult.setErrorString(tr("%1 should be a folder but is not.").arg(_definition.localPath));
|
||||
_syncResult.appendErrorString(tr("%1 should be a folder but is not.").arg(_definition.localPath));
|
||||
_syncResult.setStatus( SyncResult::SetupError );
|
||||
} else if( !fi.isReadable() ) {
|
||||
_syncResult.setErrorString(tr("%1 is not readable.").arg(_definition.localPath));
|
||||
_syncResult.appendErrorString(tr("%1 is not readable.").arg(_definition.localPath));
|
||||
_syncResult.setStatus( SyncResult::SetupError );
|
||||
}
|
||||
}
|
||||
@@ -268,8 +265,8 @@ SyncResult Folder::syncResult() const
|
||||
|
||||
void Folder::prepareToSync()
|
||||
{
|
||||
_syncResult.reset();
|
||||
_syncResult.setStatus( SyncResult::NotYetStarted );
|
||||
_syncResult.clearErrors();
|
||||
}
|
||||
|
||||
void Folder::slotRunEtagJob()
|
||||
@@ -323,120 +320,33 @@ void Folder::etagRetreivedFromSyncEngine(const QString& etag)
|
||||
}
|
||||
|
||||
|
||||
void Folder::bubbleUpSyncResult()
|
||||
void Folder::showSyncResultPopup()
|
||||
{
|
||||
// count new, removed and updated items
|
||||
int newItems = 0;
|
||||
int removedItems = 0;
|
||||
int updatedItems = 0;
|
||||
int ignoredItems = 0;
|
||||
int renamedItems = 0;
|
||||
int conflictItems = 0;
|
||||
int errorItems = 0;
|
||||
|
||||
SyncFileItemPtr firstItemNew;
|
||||
SyncFileItemPtr firstItemDeleted;
|
||||
SyncFileItemPtr firstItemUpdated;
|
||||
SyncFileItemPtr firstItemRenamed;
|
||||
SyncFileItemPtr firstConflictItem;
|
||||
SyncFileItemPtr firstItemError;
|
||||
|
||||
QElapsedTimer timer;
|
||||
timer.start();
|
||||
|
||||
foreach (const SyncFileItemPtr &item, _syncResult.syncFileItemVector() ) {
|
||||
// Process the item to the gui
|
||||
if( item->_status == SyncFileItem::FatalError || item->_status == SyncFileItem::NormalError ) {
|
||||
//: this displays an error string (%2) for a file %1
|
||||
slotSyncError( tr("%1: %2").arg(item->_file, item->_errorString) );
|
||||
errorItems++;
|
||||
if (!firstItemError) {
|
||||
firstItemError = item;
|
||||
}
|
||||
} else if( item->_status == SyncFileItem::FileIgnored ) {
|
||||
// ignored files don't show up in notifications
|
||||
continue;
|
||||
} else if( item->_status == SyncFileItem::Conflict ) {
|
||||
conflictItems++;
|
||||
if (!firstConflictItem) {
|
||||
firstConflictItem = item;
|
||||
}
|
||||
} else {
|
||||
// add new directories or remove gone away dirs to the watcher
|
||||
if (item->_isDirectory && item->_instruction == CSYNC_INSTRUCTION_NEW ) {
|
||||
FolderMan::instance()->addMonitorPath( alias(), path()+item->_file );
|
||||
}
|
||||
if (item->_isDirectory && item->_instruction == CSYNC_INSTRUCTION_REMOVE ) {
|
||||
FolderMan::instance()->removeMonitorPath( alias(), path()+item->_file );
|
||||
}
|
||||
|
||||
if (!item->hasErrorStatus() && item->_direction == SyncFileItem::Down) {
|
||||
switch (item->_instruction) {
|
||||
case CSYNC_INSTRUCTION_NEW:
|
||||
case CSYNC_INSTRUCTION_TYPE_CHANGE:
|
||||
newItems++;
|
||||
if (!firstItemNew)
|
||||
firstItemNew = item;
|
||||
break;
|
||||
case CSYNC_INSTRUCTION_REMOVE:
|
||||
removedItems++;
|
||||
if (!firstItemDeleted)
|
||||
firstItemDeleted = item;
|
||||
break;
|
||||
case CSYNC_INSTRUCTION_SYNC:
|
||||
updatedItems++;
|
||||
if (!firstItemUpdated)
|
||||
firstItemUpdated = item;
|
||||
break;
|
||||
case CSYNC_INSTRUCTION_ERROR:
|
||||
qDebug() << "Got Instruction ERROR. " << _syncResult.errorString();
|
||||
break;
|
||||
case CSYNC_INSTRUCTION_RENAME:
|
||||
if (!firstItemRenamed) {
|
||||
firstItemRenamed = item;
|
||||
}
|
||||
renamedItems++;
|
||||
break;
|
||||
default:
|
||||
// nothing.
|
||||
break;
|
||||
}
|
||||
} else if( item->_direction == SyncFileItem::None ) { // ignored files counting.
|
||||
if( item->_instruction == CSYNC_INSTRUCTION_IGNORE ) {
|
||||
ignoredItems++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if( _syncResult.firstItemNew() ) {
|
||||
createGuiLog( _syncResult.firstItemNew()->_file, LogStatusNew, _syncResult.numNewItems() );
|
||||
}
|
||||
if( _syncResult.firstItemDeleted() ) {
|
||||
createGuiLog( _syncResult.firstItemDeleted()->_file, LogStatusRemove, _syncResult.numRemovedItems() );
|
||||
}
|
||||
if( _syncResult.firstItemUpdated() ) {
|
||||
createGuiLog( _syncResult.firstItemUpdated()->_file, LogStatusUpdated, _syncResult.numUpdatedItems() );
|
||||
}
|
||||
|
||||
qDebug() << "Processing result list and logging took " << timer.elapsed() << " Milliseconds.";
|
||||
_syncResult.setWarnCount(ignoredItems);
|
||||
|
||||
if( firstItemNew ) {
|
||||
createGuiLog( firstItemNew->_file, LogStatusNew, newItems );
|
||||
}
|
||||
if( firstItemDeleted ) {
|
||||
createGuiLog( firstItemDeleted->_file, LogStatusRemove, removedItems );
|
||||
}
|
||||
if( firstItemUpdated ) {
|
||||
createGuiLog( firstItemUpdated->_file, LogStatusUpdated, updatedItems );
|
||||
}
|
||||
|
||||
if( firstItemRenamed ) {
|
||||
if( _syncResult.firstItemRenamed() ) {
|
||||
LogStatus status(LogStatusRename);
|
||||
// if the path changes it's rather a move
|
||||
QDir renTarget = QFileInfo(firstItemRenamed->_renameTarget).dir();
|
||||
QDir renSource = QFileInfo(firstItemRenamed->_file).dir();
|
||||
QDir renTarget = QFileInfo(_syncResult.firstItemRenamed()->_renameTarget).dir();
|
||||
QDir renSource = QFileInfo(_syncResult.firstItemRenamed()->_file).dir();
|
||||
if(renTarget != renSource) {
|
||||
status = LogStatusMove;
|
||||
}
|
||||
createGuiLog( firstItemRenamed->_originalFile, status, renamedItems, firstItemRenamed->_renameTarget );
|
||||
createGuiLog( _syncResult.firstItemRenamed()->_originalFile, status, _syncResult.numRenamedItems(), _syncResult.firstItemRenamed()->_renameTarget );
|
||||
}
|
||||
|
||||
if( firstConflictItem ) {
|
||||
createGuiLog( firstConflictItem->_file, LogStatusConflict, conflictItems );
|
||||
if( _syncResult.firstConflictItem() ) {
|
||||
createGuiLog( _syncResult.firstConflictItem()->_file, LogStatusConflict, _syncResult.numConflictItems() );
|
||||
}
|
||||
createGuiLog( firstItemError->_file, LogStatusError, errorItems );
|
||||
createGuiLog( _syncResult.firstItemError()->_file, LogStatusError, _syncResult.numErrorItems() );
|
||||
|
||||
qDebug() << "OO folder slotSyncFinished: result: " << int(_syncResult.status());
|
||||
}
|
||||
@@ -575,12 +485,6 @@ void Folder::slotWatchedPathChanged(const QString& path)
|
||||
scheduleThisFolderSoon();
|
||||
}
|
||||
|
||||
void Folder::slotThreadTreeWalkResult(const SyncFileItemVector& items)
|
||||
{
|
||||
_syncResult.setSyncFileItemVector(items);
|
||||
}
|
||||
|
||||
|
||||
void Folder::saveToSettings() const
|
||||
{
|
||||
// Remove first to make sure we don't get duplicates
|
||||
@@ -643,9 +547,6 @@ void Folder::slotTerminateSync()
|
||||
if( _engine->isSyncRunning() ) {
|
||||
_engine->abort();
|
||||
|
||||
// Do not display an error message, user knows his own actions.
|
||||
// _errors.append( tr("The CSync thread terminated.") );
|
||||
// _csyncError = true;
|
||||
setSyncState(SyncResult::SyncAbortRequested);
|
||||
}
|
||||
}
|
||||
@@ -693,10 +594,9 @@ bool Folder::setIgnoredFiles()
|
||||
// a QSet of files to load.
|
||||
ConfigFile cfg;
|
||||
QString systemList = cfg.excludeFile(ConfigFile::SystemScope);
|
||||
if( QFile::exists(systemList) ) {
|
||||
qDebug() << "==== adding system ignore list to csync:" << systemList;
|
||||
_engine->excludedFiles().addExcludeFilePath(systemList);
|
||||
}
|
||||
qDebug() << "==== adding system ignore list to csync:" << systemList;
|
||||
_engine->excludedFiles().addExcludeFilePath(systemList);
|
||||
|
||||
QString userList = cfg.excludeFile(ConfigFile::UserScope);
|
||||
if( QFile::exists(userList) ) {
|
||||
qDebug() << "==== adding user defined ignore list to csync:" << userList;
|
||||
@@ -727,19 +627,17 @@ void Folder::startSync(const QStringList &pathList)
|
||||
qCritical() << "* ERROR csync is still running and new sync requested.";
|
||||
return;
|
||||
}
|
||||
_errors.clear();
|
||||
_csyncError = false;
|
||||
_csyncUnavail = false;
|
||||
|
||||
_timeSinceLastSyncStart.restart();
|
||||
_syncResult.clearErrors();
|
||||
_syncResult.setStatus( SyncResult::SyncPrepare );
|
||||
_syncResult.setSyncFileItemVector(SyncFileItemVector());
|
||||
emit syncStateChange();
|
||||
|
||||
qDebug() << "*** Start syncing " << remoteUrl().toString() << " - client version"
|
||||
<< qPrintable(Theme::instance()->version());
|
||||
|
||||
_fileLog->start(path());
|
||||
|
||||
if (!setIgnoredFiles())
|
||||
{
|
||||
slotSyncError(tr("Could not read system exclude file"));
|
||||
@@ -758,8 +656,6 @@ void Folder::startSync(const QStringList &pathList)
|
||||
|
||||
_engine->setIgnoreHiddenFiles(_definition.ignoreHiddenFiles);
|
||||
|
||||
_fileLog->start(path());
|
||||
|
||||
QMetaObject::invokeMethod(_engine.data(), "startSync", Qt::QueuedConnection);
|
||||
|
||||
emit syncStarted();
|
||||
@@ -790,8 +686,7 @@ void Folder::setDirtyNetworkLimits()
|
||||
|
||||
void Folder::slotSyncError(const QString& err)
|
||||
{
|
||||
_errors.append( err );
|
||||
_csyncError = true;
|
||||
_syncResult.appendErrorString(err);
|
||||
}
|
||||
|
||||
void Folder::slotSyncStarted()
|
||||
@@ -813,29 +708,26 @@ void Folder::slotSyncFinished(bool success)
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
|
||||
<< " SSL " << QSslSocket::sslLibraryVersionString().toUtf8().data()
|
||||
#endif
|
||||
;
|
||||
;
|
||||
|
||||
|
||||
if( _csyncError ) {
|
||||
qDebug() << "-> SyncEngine finished with ERROR, warn count is" << _syncResult.warnCount();
|
||||
bool syncError = !_syncResult.errorStrings().isEmpty();
|
||||
if( syncError ) {
|
||||
qDebug() << "-> SyncEngine finished with ERROR";
|
||||
} else {
|
||||
qDebug() << "-> SyncEngine finished without problem.";
|
||||
}
|
||||
_fileLog->finish();
|
||||
bubbleUpSyncResult();
|
||||
showSyncResultPopup();
|
||||
|
||||
auto anotherSyncNeeded = _engine->isAnotherSyncNeeded();
|
||||
|
||||
if (_csyncError) {
|
||||
if (syncError) {
|
||||
_syncResult.setStatus(SyncResult::Error);
|
||||
qDebug() << " ** error Strings: " << _errors;
|
||||
_syncResult.setErrorStrings( _errors );
|
||||
qDebug() << " * owncloud csync thread finished with error";
|
||||
} else if (_csyncUnavail) {
|
||||
_syncResult.setStatus(SyncResult::Error);
|
||||
qDebug() << " ** csync not available.";
|
||||
} else if( _syncResult.warnCount() > 0 ) {
|
||||
// there have been warnings on the way.
|
||||
} else if( _syncResult.foundFilesNotSynced() ) {
|
||||
_syncResult.setStatus(SyncResult::Problem);
|
||||
} else if( _definition.paused ) {
|
||||
// Maybe the sync was terminated because the user paused the folder
|
||||
@@ -912,23 +804,25 @@ void Folder::slotFolderDiscovered(bool, QString folderName)
|
||||
// and hand the result over to the progress dispatcher.
|
||||
void Folder::slotTransmissionProgress(const ProgressInfo &pi)
|
||||
{
|
||||
if( !pi.isUpdatingEstimates() ) {
|
||||
// this is the beginning of a sync, set the warning level to 0
|
||||
_syncResult.setWarnCount(0);
|
||||
}
|
||||
emit progressInfo(pi);
|
||||
ProgressDispatcher::instance()->setProgressInfo(alias(), pi);
|
||||
}
|
||||
|
||||
// a item is completed: count the errors and forward to the ProgressDispatcher
|
||||
void Folder::slotItemCompleted(const SyncFileItem &item, const PropagatorJob& job)
|
||||
void Folder::slotItemCompleted(const SyncFileItemPtr &item)
|
||||
{
|
||||
if (Progress::isWarningKind(item._status)) {
|
||||
// Count all error conditions.
|
||||
_syncResult.setWarnCount(_syncResult.warnCount()+1);
|
||||
// add new directories or remove gone away dirs to the watcher
|
||||
if (item->_isDirectory && item->_instruction == CSYNC_INSTRUCTION_NEW ) {
|
||||
FolderMan::instance()->addMonitorPath( alias(), path()+item->_file );
|
||||
}
|
||||
_fileLog->logItem(item);
|
||||
emit ProgressDispatcher::instance()->itemCompleted(alias(), item, job);
|
||||
if (item->_isDirectory && item->_instruction == CSYNC_INSTRUCTION_REMOVE ) {
|
||||
FolderMan::instance()->removeMonitorPath( alias(), path()+item->_file );
|
||||
}
|
||||
|
||||
_syncResult.processCompletedItem(item);
|
||||
|
||||
_fileLog->logItem(*item);
|
||||
emit ProgressDispatcher::instance()->itemCompleted(alias(), item);
|
||||
}
|
||||
|
||||
void Folder::slotNewBigFolderDiscovered(const QString &newF, bool isExternal)
|
||||
@@ -989,17 +883,22 @@ void Folder::setSaveBackwardsCompatible(bool save)
|
||||
_saveBackwardsCompatible = save;
|
||||
}
|
||||
|
||||
void Folder::slotAboutToRemoveAllFiles(SyncFileItem::Direction, bool *cancel)
|
||||
void Folder::slotAboutToRemoveAllFiles(SyncFileItem::Direction dir, bool *cancel)
|
||||
{
|
||||
ConfigFile cfgFile;
|
||||
if (!cfgFile.promptDeleteFiles())
|
||||
return;
|
||||
|
||||
QString msg =
|
||||
tr("This sync would remove all the files in the sync folder '%1'.\n"
|
||||
"This might be because the folder was silently reconfigured, or that all "
|
||||
"the files were manually removed.\n"
|
||||
"Are you sure you want to perform this operation?");
|
||||
QString msg = dir == SyncFileItem::Down ?
|
||||
tr("All files in the sync folder '%1' folder were deleted on the server.\n"
|
||||
"These deletes will be synchronized to your local sync folder, making such files "
|
||||
"unavailable unless you have a right to restore. \n"
|
||||
"If you decide to keep the files, they will be re-synced with the server if you have rights to do so.\n"
|
||||
"If you decide to delete the files, they will be unavailable to you, unless you are the owner.") :
|
||||
tr("All the files in your local sync folder '%1' were deleted. These deletes will be "
|
||||
"synchronized with your server, making such files unavailable unless restored.\n"
|
||||
"Are you sure you want to sync those actions with the server?\n"
|
||||
"If this was an accident and you decide to keep your files, they will be re-synced from the server.");
|
||||
QMessageBox msgBox(QMessageBox::Warning, tr("Remove All Files?"),
|
||||
msg.arg(shortGuiLocalPath()));
|
||||
msgBox.addButton(tr("Remove all files"), QMessageBox::DestructiveRole);
|
||||
|
||||
+2
-6
@@ -280,14 +280,12 @@ private slots:
|
||||
|
||||
void slotFolderDiscovered(bool local, QString folderName);
|
||||
void slotTransmissionProgress(const ProgressInfo& pi);
|
||||
void slotItemCompleted(const SyncFileItem&, const PropagatorJob&);
|
||||
void slotItemCompleted(const SyncFileItemPtr&);
|
||||
|
||||
void slotRunEtagJob();
|
||||
void etagRetreived(const QString &);
|
||||
void etagRetreivedFromSyncEngine(const QString &);
|
||||
|
||||
void slotThreadTreeWalkResult(const SyncFileItemVector& ); // after sync is done
|
||||
|
||||
void slotEmitFinishedDelayed();
|
||||
|
||||
void slotNewBigFolderDiscovered(const QString &, bool isExternal);
|
||||
@@ -302,7 +300,7 @@ private slots:
|
||||
private:
|
||||
bool setIgnoredFiles();
|
||||
|
||||
void bubbleUpSyncResult();
|
||||
void showSyncResultPopup();
|
||||
|
||||
void checkLocalPath();
|
||||
|
||||
@@ -325,8 +323,6 @@ private:
|
||||
|
||||
SyncResult _syncResult;
|
||||
QScopedPointer<SyncEngine> _engine;
|
||||
QStringList _errors;
|
||||
bool _csyncError;
|
||||
bool _csyncUnavail;
|
||||
bool _wipeDb;
|
||||
bool _proxyDirty;
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "accountmanager.h"
|
||||
#include "filesystem.h"
|
||||
#include "lockwatcher.h"
|
||||
#include "asserts.h"
|
||||
#include <syncengine.h>
|
||||
|
||||
#ifdef Q_OS_MAC
|
||||
@@ -48,7 +49,7 @@ FolderMan::FolderMan(QObject *parent) :
|
||||
_lockWatcher(new LockWatcher),
|
||||
_appRestartRequired(false)
|
||||
{
|
||||
Q_ASSERT(!_instance);
|
||||
ASSERT(!_instance);
|
||||
_instance = this;
|
||||
|
||||
_socketApi.reset(new SocketApi);
|
||||
@@ -133,12 +134,13 @@ int FolderMan::unloadAndDeleteAllFolders()
|
||||
delete f;
|
||||
cnt++;
|
||||
}
|
||||
ASSERT(_folderMap.isEmpty());
|
||||
|
||||
_lastSyncFolder = 0;
|
||||
_currentSyncFolder = 0;
|
||||
_scheduledFolders.clear();
|
||||
emit scheduleQueueChanged();
|
||||
|
||||
Q_ASSERT(_folderMap.count() == 0);
|
||||
return cnt;
|
||||
}
|
||||
|
||||
@@ -260,7 +262,6 @@ int FolderMan::setupFoldersMigration()
|
||||
{
|
||||
ConfigFile cfg;
|
||||
QDir storageDir(cfg.configPath());
|
||||
storageDir.mkpath(QLatin1String("folders"));
|
||||
_folderConfigPath = cfg.configPath() + QLatin1String("folders");
|
||||
|
||||
qDebug() << "* Setup folders from " << _folderConfigPath << "(migration)";
|
||||
@@ -463,7 +464,7 @@ void FolderMan::slotFolderSyncPaused( Folder *f, bool paused )
|
||||
void FolderMan::slotFolderCanSyncChanged()
|
||||
{
|
||||
Folder *f = qobject_cast<Folder*>(sender());
|
||||
Q_ASSERT(f);
|
||||
ASSERT(f);
|
||||
if (f->canSync()) {
|
||||
_socketApi->slotRegisterPath(f->alias());
|
||||
} else {
|
||||
@@ -1121,7 +1122,7 @@ void FolderMan::setDirtyNetworkLimits()
|
||||
|
||||
SyncResult FolderMan::accountStatus(const QList<Folder*> &folders)
|
||||
{
|
||||
SyncResult overallResult(SyncResult::Undefined);
|
||||
SyncResult overallResult;
|
||||
|
||||
int cnt = folders.count();
|
||||
|
||||
@@ -1235,10 +1236,10 @@ SyncResult FolderMan::accountStatus(const QList<Folder*> &folders)
|
||||
return overallResult;
|
||||
}
|
||||
|
||||
QString FolderMan::statusToString( SyncResult syncStatus, bool paused ) const
|
||||
QString FolderMan::statusToString( SyncResult::Status syncStatus, bool paused ) const
|
||||
{
|
||||
QString folderMessage;
|
||||
switch( syncStatus.status() ) {
|
||||
switch( syncStatus ) {
|
||||
case SyncResult::Undefined:
|
||||
folderMessage = tr( "Undefined State." );
|
||||
break;
|
||||
|
||||
@@ -106,7 +106,7 @@ public:
|
||||
/** Creates a new and empty local directory. */
|
||||
bool startFromScratch( const QString& );
|
||||
|
||||
QString statusToString(SyncResult, bool paused ) const;
|
||||
QString statusToString(SyncResult::Status, bool paused ) const;
|
||||
|
||||
static SyncResult accountStatus( const QList<Folder*> &folders );
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "folderman.h"
|
||||
#include "accountstate.h"
|
||||
#include "utility.h"
|
||||
#include "asserts.h"
|
||||
#include <theme.h>
|
||||
#include <account.h>
|
||||
#include "folderstatusdelegate.h"
|
||||
@@ -480,14 +481,14 @@ QModelIndex FolderStatusModel::parent(const QModelIndex& child) const
|
||||
}
|
||||
auto pathIdx = static_cast<SubFolderInfo*>(child.internalPointer())->_pathIdx;
|
||||
int i = 1;
|
||||
Q_ASSERT(pathIdx.at(0) < _folders.count());
|
||||
ASSERT(pathIdx.at(0) < _folders.count());
|
||||
if (pathIdx.count() == 1) {
|
||||
return createIndex(pathIdx.at(0), 0/*, nullptr*/);
|
||||
}
|
||||
|
||||
const SubFolderInfo *info = &_folders[pathIdx.at(0)];
|
||||
while (i < pathIdx.count() - 1) {
|
||||
Q_ASSERT(pathIdx.at(i) < info->_subs.count());
|
||||
ASSERT(pathIdx.at(i) < info->_subs.count());
|
||||
info = &info->_subs[pathIdx.at(i)];
|
||||
++i;
|
||||
}
|
||||
@@ -576,7 +577,7 @@ void FolderStatusModel::slotGatherPermissions(const QString &href, const QMap<QS
|
||||
auto job = sender();
|
||||
auto permissionMap = job->property(propertyPermissionMap).toMap();
|
||||
job->setProperty(propertyPermissionMap, QVariant()); // avoid a detach of the map while it is modified
|
||||
Q_ASSERT(!href.endsWith(QLatin1Char('/'))); // LsColXMLParser::parse removes the trailing slash before calling us.
|
||||
ASSERT(!href.endsWith(QLatin1Char('/')), "LsColXMLParser::parse should remove the trailing slash before calling us.");
|
||||
permissionMap[href] = *it;
|
||||
job->setProperty(propertyPermissionMap, permissionMap);
|
||||
}
|
||||
@@ -584,7 +585,7 @@ void FolderStatusModel::slotGatherPermissions(const QString &href, const QMap<QS
|
||||
void FolderStatusModel::slotUpdateDirectories(const QStringList &list)
|
||||
{
|
||||
auto job = qobject_cast<LsColJob *>(sender());
|
||||
Q_ASSERT(job);
|
||||
ASSERT(job);
|
||||
QModelIndex idx = qvariant_cast<QPersistentModelIndex>(job->property(propertyParentIndexC));
|
||||
auto parentInfo = infoForIndex(idx);
|
||||
if (!parentInfo) {
|
||||
@@ -715,7 +716,7 @@ void FolderStatusModel::slotUpdateDirectories(const QStringList &list)
|
||||
void FolderStatusModel::slotLscolFinishedWithError(QNetworkReply* r)
|
||||
{
|
||||
auto job = qobject_cast<LsColJob *>(sender());
|
||||
Q_ASSERT(job);
|
||||
ASSERT(job);
|
||||
QModelIndex idx = qvariant_cast<QPersistentModelIndex>(job->property(propertyParentIndexC));
|
||||
if (!idx.isValid()) {
|
||||
return;
|
||||
@@ -730,7 +731,7 @@ void FolderStatusModel::slotLscolFinishedWithError(QNetworkReply* r)
|
||||
if (r->error() == QNetworkReply::ContentNotFoundError) {
|
||||
parentInfo->_fetched = true;
|
||||
} else {
|
||||
Q_ASSERT(!parentInfo->hasLabel());
|
||||
ASSERT(!parentInfo->hasLabel());
|
||||
beginInsertRows(idx, 0, 0);
|
||||
parentInfo->_hasError = true;
|
||||
endInsertRows();
|
||||
@@ -1010,7 +1011,7 @@ void FolderStatusModel::slotFolderSyncStateChange(Folder *f)
|
||||
auto& pi = _folders[folderIndex]._progress;
|
||||
|
||||
SyncResult::Status state = f->syncResult().status();
|
||||
if (f->syncPaused()) {
|
||||
if (!f->canSync()) {
|
||||
// Reset progress info.
|
||||
pi = SubFolderInfo::Progress();
|
||||
} else if (state == SyncResult::NotYetStarted) {
|
||||
@@ -1041,18 +1042,10 @@ void FolderStatusModel::slotFolderSyncStateChange(Folder *f)
|
||||
// update the icon etc. now
|
||||
slotUpdateFolderState(f);
|
||||
|
||||
if (state == SyncResult::Success) {
|
||||
foreach (const SyncFileItemPtr &i, f->syncResult().syncFileItemVector()) {
|
||||
if (i->_isDirectory && (i->_instruction == CSYNC_INSTRUCTION_NEW
|
||||
|| i->_instruction == CSYNC_INSTRUCTION_TYPE_CHANGE
|
||||
|| i->_instruction == CSYNC_INSTRUCTION_REMOVE
|
||||
|| i->_instruction == CSYNC_INSTRUCTION_RENAME)) {
|
||||
// There is a new or a removed folder. reset all data
|
||||
auto & info = _folders[folderIndex];
|
||||
info.resetSubs(this, index(folderIndex));
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (state == SyncResult::Success && f->syncResult().folderStructureWasChanged()) {
|
||||
// There is a new or a removed folder. reset all data
|
||||
auto & info = _folders[folderIndex];
|
||||
info.resetSubs(this, index(folderIndex));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1143,7 +1136,7 @@ void FolderStatusModel::slotSyncNoPendingBigFolders()
|
||||
void FolderStatusModel::slotNewBigFolder()
|
||||
{
|
||||
auto f = qobject_cast<Folder *>(sender());
|
||||
Q_ASSERT(f);
|
||||
ASSERT(f);
|
||||
|
||||
int folderIndex = -1;
|
||||
for (int i = 0; i < _folders.count(); ++i) {
|
||||
|
||||
@@ -482,9 +482,8 @@ void FolderWizardRemotePath::showWarn( const QString& msg ) const
|
||||
FolderWizardSelectiveSync::FolderWizardSelectiveSync(const AccountPtr& account)
|
||||
{
|
||||
QVBoxLayout *layout = new QVBoxLayout(this);
|
||||
_treeView = new SelectiveSyncTreeView(account, this);
|
||||
layout->addWidget(new QLabel(tr("Choose What to Sync: You can optionally deselect remote subfolders you do not wish to synchronize.")));
|
||||
layout->addWidget(_treeView);
|
||||
_selectiveSync = new SelectiveSyncWidget(account, this);
|
||||
layout->addWidget(_selectiveSync);
|
||||
}
|
||||
|
||||
FolderWizardSelectiveSync::~FolderWizardSelectiveSync()
|
||||
@@ -501,13 +500,17 @@ void FolderWizardSelectiveSync::initializePage()
|
||||
QString alias = QFileInfo(targetPath).fileName();
|
||||
if (alias.isEmpty())
|
||||
alias = Theme::instance()->appName();
|
||||
_treeView->setFolderInfo(targetPath, alias);
|
||||
QStringList initialBlacklist;
|
||||
if (Theme::instance()->wizardSelectiveSyncDefaultNothing()) {
|
||||
initialBlacklist = QStringList("/");
|
||||
}
|
||||
_selectiveSync->setFolderInfo(targetPath, alias, initialBlacklist);
|
||||
QWizardPage::initializePage();
|
||||
}
|
||||
|
||||
bool FolderWizardSelectiveSync::validatePage()
|
||||
{
|
||||
wizard()->setProperty("selectiveSyncBlackList", QVariant(_treeView->createBlackList()));
|
||||
wizard()->setProperty("selectiveSyncBlackList", QVariant(_selectiveSync->createBlackList()));
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -517,7 +520,7 @@ void FolderWizardSelectiveSync::cleanupPage()
|
||||
QString alias = QFileInfo(targetPath).fileName();
|
||||
if (alias.isEmpty())
|
||||
alias = Theme::instance()->appName();
|
||||
_treeView->setFolderInfo(targetPath, alias);
|
||||
_selectiveSync->setFolderInfo(targetPath, alias);
|
||||
QWizardPage::cleanupPage();
|
||||
}
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
|
||||
namespace OCC {
|
||||
|
||||
class SelectiveSyncTreeView;
|
||||
class SelectiveSyncWidget;
|
||||
|
||||
class ownCloudInfo;
|
||||
|
||||
@@ -127,7 +127,7 @@ public:
|
||||
virtual void cleanupPage() Q_DECL_OVERRIDE;
|
||||
|
||||
private:
|
||||
SelectiveSyncTreeView *_treeView;
|
||||
SelectiveSyncWidget *_selectiveSync;
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -38,7 +38,8 @@ namespace OCC {
|
||||
|
||||
GeneralSettings::GeneralSettings(QWidget *parent) :
|
||||
QWidget(parent),
|
||||
_ui(new Ui::GeneralSettings)
|
||||
_ui(new Ui::GeneralSettings),
|
||||
_currentlyLoading(false)
|
||||
{
|
||||
_ui->setupUi(this);
|
||||
|
||||
@@ -104,7 +105,12 @@ QSize GeneralSettings::sizeHint() const {
|
||||
|
||||
void GeneralSettings::loadMiscSettings()
|
||||
{
|
||||
#if QT_VERSION < QT_VERSION_CHECK( 5, 4, 0 )
|
||||
QScopedValueRollback<bool> scope(_currentlyLoading);
|
||||
_currentlyLoading = true;
|
||||
#else
|
||||
QScopedValueRollback<bool> scope(_currentlyLoading, true);
|
||||
#endif
|
||||
ConfigFile cfgFile;
|
||||
_ui->monoIconsCheckBox->setChecked(cfgFile.monoIcons());
|
||||
_ui->desktopNotificationsCheckBox->setChecked(cfgFile.optionalDesktopNotifications());
|
||||
|
||||
@@ -52,7 +52,7 @@ private:
|
||||
Ui::GeneralSettings *_ui;
|
||||
QPointer<IgnoreListEditor> _ignoreEditor;
|
||||
QPointer<SyncLogDialog> _syncLogDialog;
|
||||
bool _currentlyLoading = false;
|
||||
bool _currentlyLoading;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include "notificationwidget.h"
|
||||
#include "QProgressIndicator.h"
|
||||
#include "utility.h"
|
||||
#include "asserts.h"
|
||||
|
||||
#include <QPushButton>
|
||||
|
||||
@@ -33,8 +34,8 @@ void NotificationWidget::setActivity(const Activity& activity)
|
||||
{
|
||||
_myActivity = activity;
|
||||
|
||||
Q_ASSERT( !activity._accName.isEmpty() );
|
||||
_accountName = activity._accName;
|
||||
ASSERT(!_accountName.isEmpty());
|
||||
|
||||
// _ui._headerLabel->setText( );
|
||||
_ui._subjectLabel->setVisible( !activity._subject.isEmpty() );
|
||||
|
||||
@@ -27,7 +27,6 @@
|
||||
#include "syncfileitem.h"
|
||||
#include "folder.h"
|
||||
#include "openfilemanager.h"
|
||||
#include "owncloudpropagator.h"
|
||||
#include "activityitemdelegate.h"
|
||||
|
||||
#include "ui_protocolwidget.h"
|
||||
@@ -45,8 +44,8 @@ ProtocolWidget::ProtocolWidget(QWidget *parent) :
|
||||
|
||||
connect(ProgressDispatcher::instance(), SIGNAL(progressInfo(QString,ProgressInfo)),
|
||||
this, SLOT(slotProgressInfo(QString,ProgressInfo)));
|
||||
connect(ProgressDispatcher::instance(), SIGNAL(itemCompleted(QString,SyncFileItem,PropagatorJob)),
|
||||
this, SLOT(slotItemCompleted(QString,SyncFileItem,PropagatorJob)));
|
||||
connect(ProgressDispatcher::instance(), SIGNAL(itemCompleted(QString,SyncFileItemPtr)),
|
||||
this, SLOT(slotItemCompleted(QString,SyncFileItemPtr)));
|
||||
|
||||
connect(_ui->_treeWidget, SIGNAL(itemActivated(QTreeWidgetItem*,int)), SLOT(slotOpenFile(QTreeWidgetItem*,int)));
|
||||
|
||||
@@ -222,15 +221,11 @@ void ProtocolWidget::slotProgressInfo( const QString& folder, const ProgressInfo
|
||||
}
|
||||
}
|
||||
|
||||
void ProtocolWidget::slotItemCompleted(const QString &folder, const SyncFileItem &item, const PropagatorJob &job)
|
||||
void ProtocolWidget::slotItemCompleted(const QString &folder, const SyncFileItemPtr &item)
|
||||
{
|
||||
if (qobject_cast<const PropagateDirectory*>(&job)) {
|
||||
return;
|
||||
}
|
||||
|
||||
QTreeWidgetItem *line = createCompletedTreewidgetItem(folder, item);
|
||||
QTreeWidgetItem *line = createCompletedTreewidgetItem(folder, *item);
|
||||
if(line) {
|
||||
if( item.hasErrorStatus() ) {
|
||||
if( item->hasErrorStatus() ) {
|
||||
_issueItemView->insertTopLevelItem(0, line);
|
||||
emit issueItemCountUpdated(_issueItemView->topLevelItemCount());
|
||||
} else {
|
||||
|
||||
@@ -52,7 +52,7 @@ public:
|
||||
|
||||
public slots:
|
||||
void slotProgressInfo( const QString& folder, const ProgressInfo& progress );
|
||||
void slotItemCompleted( const QString& folder, const SyncFileItem& item, const PropagatorJob& job);
|
||||
void slotItemCompleted( const QString& folder, const SyncFileItemPtr& item);
|
||||
void slotOpenFile( QTreeWidgetItem* item, int );
|
||||
|
||||
protected:
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include "networkjobs.h"
|
||||
#include "theme.h"
|
||||
#include "folderman.h"
|
||||
#include "configfile.h"
|
||||
#include <QDialogButtonBox>
|
||||
#include <QVBoxLayout>
|
||||
#include <QTreeWidget>
|
||||
@@ -29,6 +30,7 @@
|
||||
#include <QScopedValueRollback>
|
||||
#include <QTreeWidgetItem>
|
||||
#include <QLabel>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
namespace OCC {
|
||||
|
||||
@@ -54,32 +56,48 @@ private:
|
||||
}
|
||||
};
|
||||
|
||||
SelectiveSyncTreeView::SelectiveSyncTreeView(AccountPtr account, QWidget* parent)
|
||||
: QTreeWidget(parent), _inserting(false), _account(account)
|
||||
SelectiveSyncWidget::SelectiveSyncWidget(AccountPtr account, QWidget *parent)
|
||||
: QWidget(parent)
|
||||
, _account(account)
|
||||
, _inserting(false)
|
||||
, _folderTree(new QTreeWidget(this))
|
||||
{
|
||||
_loading = new QLabel(tr("Loading ..."), this);
|
||||
connect(this, SIGNAL(itemExpanded(QTreeWidgetItem*)), this, SLOT(slotItemExpanded(QTreeWidgetItem*)));
|
||||
connect(this, SIGNAL(itemChanged(QTreeWidgetItem*,int)), this, SLOT(slotItemChanged(QTreeWidgetItem*,int)));
|
||||
setSortingEnabled(true);
|
||||
sortByColumn(0, Qt::AscendingOrder);
|
||||
setColumnCount(2);
|
||||
_loading = new QLabel(tr("Loading ..."), _folderTree);
|
||||
|
||||
auto layout = new QVBoxLayout(this);
|
||||
layout->setContentsMargins(0, 0, 0, 0);
|
||||
|
||||
auto header = new QLabel(this);
|
||||
header->setText(tr("Deselect remote folders you do not wish to synchronize."));
|
||||
header->setWordWrap(true);
|
||||
layout->addWidget(header);
|
||||
|
||||
layout->addWidget(_folderTree);
|
||||
|
||||
connect(_folderTree, SIGNAL(itemExpanded(QTreeWidgetItem*)),
|
||||
SLOT(slotItemExpanded(QTreeWidgetItem*)));
|
||||
connect(_folderTree, SIGNAL(itemChanged(QTreeWidgetItem*,int)),
|
||||
SLOT(slotItemChanged(QTreeWidgetItem*,int)));
|
||||
_folderTree->setSortingEnabled(true);
|
||||
_folderTree->sortByColumn(0, Qt::AscendingOrder);
|
||||
_folderTree->setColumnCount(2);
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
|
||||
header()->setSectionResizeMode(0, QHeaderView::QHeaderView::ResizeToContents);
|
||||
header()->setSectionResizeMode(1, QHeaderView::QHeaderView::ResizeToContents);
|
||||
_folderTree->header()->setSectionResizeMode(0, QHeaderView::QHeaderView::ResizeToContents);
|
||||
_folderTree->header()->setSectionResizeMode(1, QHeaderView::QHeaderView::ResizeToContents);
|
||||
#else
|
||||
header()->resizeSection(0, sizeHint().width()/2);
|
||||
_folderTree->header()->resizeSection(0, sizeHint().width()/2);
|
||||
#endif
|
||||
header()->setStretchLastSection(true);
|
||||
headerItem()->setText(0, tr("Name"));
|
||||
headerItem()->setText(1, tr("Size"));
|
||||
_folderTree->header()->setStretchLastSection(true);
|
||||
_folderTree->headerItem()->setText(0, tr("Name"));
|
||||
_folderTree->headerItem()->setText(1, tr("Size"));
|
||||
}
|
||||
|
||||
QSize SelectiveSyncTreeView::sizeHint() const
|
||||
QSize SelectiveSyncWidget::sizeHint() const
|
||||
{
|
||||
return QTreeView::sizeHint().expandedTo(QSize(400, 400));
|
||||
return QWidget::sizeHint().expandedTo(QSize(600, 600));
|
||||
}
|
||||
|
||||
void SelectiveSyncTreeView::refreshFolders()
|
||||
void SelectiveSyncWidget::refreshFolders()
|
||||
{
|
||||
LsColJob *job = new LsColJob(_account, _folderPath, this);
|
||||
job->setProperties(QList<QByteArray>() << "resourcetype" << "http://owncloud.org/ns:size");
|
||||
@@ -88,12 +106,12 @@ void SelectiveSyncTreeView::refreshFolders()
|
||||
connect(job, SIGNAL(finishedWithError(QNetworkReply*)),
|
||||
this, SLOT(slotLscolFinishedWithError(QNetworkReply*)));
|
||||
job->start();
|
||||
clear();
|
||||
_folderTree->clear();
|
||||
_loading->show();
|
||||
_loading->move(10,header()->height() + 10);
|
||||
_loading->move(10, _folderTree->header()->height() + 10);
|
||||
}
|
||||
|
||||
void SelectiveSyncTreeView::setFolderInfo(const QString& folderPath, const QString& rootName, const QStringList& oldBlackList)
|
||||
void SelectiveSyncWidget::setFolderInfo(const QString& folderPath, const QString& rootName, const QStringList& oldBlackList)
|
||||
{
|
||||
_folderPath = folderPath;
|
||||
if (_folderPath.startsWith(QLatin1Char('/'))) {
|
||||
@@ -116,7 +134,7 @@ static QTreeWidgetItem* findFirstChild(QTreeWidgetItem *parent, const QString& t
|
||||
return 0;
|
||||
}
|
||||
|
||||
void SelectiveSyncTreeView::recursiveInsert(QTreeWidgetItem* parent, QStringList pathTrail, QString path, qint64 size)
|
||||
void SelectiveSyncWidget::recursiveInsert(QTreeWidgetItem* parent, QStringList pathTrail, QString path, qint64 size)
|
||||
{
|
||||
QFileIconProvider prov;
|
||||
QIcon folderIcon = prov.icon(QFileIconProvider::Folder);
|
||||
@@ -159,13 +177,13 @@ void SelectiveSyncTreeView::recursiveInsert(QTreeWidgetItem* parent, QStringList
|
||||
}
|
||||
}
|
||||
|
||||
void SelectiveSyncTreeView::slotUpdateDirectories(QStringList list)
|
||||
void SelectiveSyncWidget::slotUpdateDirectories(QStringList list)
|
||||
{
|
||||
auto job = qobject_cast<LsColJob *>(sender());
|
||||
QScopedValueRollback<bool> isInserting(_inserting);
|
||||
_inserting = true;
|
||||
|
||||
SelectiveSyncTreeViewItem *root = static_cast<SelectiveSyncTreeViewItem*>(topLevelItem(0));
|
||||
SelectiveSyncTreeViewItem *root = static_cast<SelectiveSyncTreeViewItem*>(_folderTree->topLevelItem(0));
|
||||
|
||||
QUrl url = _account->davUrl();
|
||||
QString pathToRemove = url.path();
|
||||
@@ -206,15 +224,11 @@ void SelectiveSyncTreeView::slotUpdateDirectories(QStringList list)
|
||||
}
|
||||
|
||||
if (!root) {
|
||||
root = new SelectiveSyncTreeViewItem(this);
|
||||
root = new SelectiveSyncTreeViewItem(_folderTree);
|
||||
root->setText(0, _rootName);
|
||||
root->setIcon(0, Theme::instance()->applicationIcon());
|
||||
root->setData(0, Qt::UserRole, QString());
|
||||
if (_oldBlackList.isEmpty()) {
|
||||
root->setCheckState(0, Qt::Checked);
|
||||
} else {
|
||||
root->setCheckState(0, Qt::PartiallyChecked);
|
||||
}
|
||||
root->setCheckState(0, Qt::Checked);
|
||||
qint64 size = job ? job->_sizes.value(pathToRemove, -1) : -1;
|
||||
if (size >= 0) {
|
||||
root->setText(1, Utility::octetsToString(size));
|
||||
@@ -236,10 +250,19 @@ void SelectiveSyncTreeView::slotUpdateDirectories(QStringList list)
|
||||
recursiveInsert(root, paths, path, size);
|
||||
}
|
||||
|
||||
// Root is partially checked if any children are not checked
|
||||
for (int i = 0; i < root->childCount(); ++i) {
|
||||
const auto child = root->child(i);
|
||||
if (child->checkState(0) != Qt::Checked) {
|
||||
root->setCheckState(0, Qt::PartiallyChecked);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
root->setExpanded(true);
|
||||
}
|
||||
|
||||
void SelectiveSyncTreeView::slotLscolFinishedWithError(QNetworkReply *r)
|
||||
void SelectiveSyncWidget::slotLscolFinishedWithError(QNetworkReply *r)
|
||||
{
|
||||
if (r->error() == QNetworkReply::ContentNotFoundError) {
|
||||
_loading->setText(tr("No subfolders currently on the server."));
|
||||
@@ -249,7 +272,7 @@ void SelectiveSyncTreeView::slotLscolFinishedWithError(QNetworkReply *r)
|
||||
_loading->resize(_loading->sizeHint()); // because it's not in a layout
|
||||
}
|
||||
|
||||
void SelectiveSyncTreeView::slotItemExpanded(QTreeWidgetItem *item)
|
||||
void SelectiveSyncWidget::slotItemExpanded(QTreeWidgetItem *item)
|
||||
{
|
||||
QString dir = item->data(0, Qt::UserRole).toString();
|
||||
if (dir.isEmpty()) return;
|
||||
@@ -264,7 +287,7 @@ void SelectiveSyncTreeView::slotItemExpanded(QTreeWidgetItem *item)
|
||||
job->start();
|
||||
}
|
||||
|
||||
void SelectiveSyncTreeView::slotItemChanged(QTreeWidgetItem *item, int col)
|
||||
void SelectiveSyncWidget::slotItemChanged(QTreeWidgetItem *item, int col)
|
||||
{
|
||||
if (col != 0 || _inserting)
|
||||
return;
|
||||
@@ -322,10 +345,10 @@ void SelectiveSyncTreeView::slotItemChanged(QTreeWidgetItem *item, int col)
|
||||
}
|
||||
}
|
||||
|
||||
QStringList SelectiveSyncTreeView::createBlackList(QTreeWidgetItem* root) const
|
||||
QStringList SelectiveSyncWidget::createBlackList(QTreeWidgetItem* root) const
|
||||
{
|
||||
if (!root) {
|
||||
root = topLevelItem(0);
|
||||
root = _folderTree->topLevelItem(0);
|
||||
}
|
||||
if (!root) return QStringList();
|
||||
|
||||
@@ -354,15 +377,15 @@ QStringList SelectiveSyncTreeView::createBlackList(QTreeWidgetItem* root) const
|
||||
return result;
|
||||
}
|
||||
|
||||
QStringList SelectiveSyncTreeView::oldBlackList() const
|
||||
QStringList SelectiveSyncWidget::oldBlackList() const
|
||||
{
|
||||
return _oldBlackList;
|
||||
}
|
||||
|
||||
qint64 SelectiveSyncTreeView::estimatedSize(QTreeWidgetItem* root)
|
||||
qint64 SelectiveSyncWidget::estimatedSize(QTreeWidgetItem* root)
|
||||
{
|
||||
if (!root) {
|
||||
root = topLevelItem(0);
|
||||
root = _folderTree->topLevelItem(0);
|
||||
}
|
||||
if (!root) return -1;
|
||||
|
||||
@@ -396,10 +419,10 @@ SelectiveSyncDialog::SelectiveSyncDialog(AccountPtr account, Folder* folder, QWi
|
||||
_okButton(0) // defined in init()
|
||||
{
|
||||
bool ok;
|
||||
init(account, tr("Unchecked folders will be <b>removed</b> from your local file system and will not be synchronized to this computer anymore"));
|
||||
init(account);
|
||||
QStringList selectiveSyncList = _folder->journalDb()->getSelectiveSyncList(SyncJournalDb::SelectiveSyncBlackList, &ok);
|
||||
if( ok ) {
|
||||
_treeView->setFolderInfo(_folder->remotePath(), _folder->alias(),selectiveSyncList);
|
||||
_selectiveSync->setFolderInfo(_folder->remotePath(), _folder->alias(),selectiveSyncList);
|
||||
} else {
|
||||
_okButton->setEnabled(false);
|
||||
}
|
||||
@@ -411,22 +434,16 @@ SelectiveSyncDialog::SelectiveSyncDialog(AccountPtr account, const QString &fold
|
||||
const QStringList& blacklist, QWidget* parent, Qt::WindowFlags f)
|
||||
: QDialog(parent, f), _folder(0)
|
||||
{
|
||||
init(account,
|
||||
Theme::instance()->wizardSelectiveSyncDefaultNothing() ?
|
||||
tr("Choose What to Sync: Select remote subfolders you wish to synchronize.") :
|
||||
tr("Choose What to Sync: Deselect remote subfolders you do not wish to synchronize."));
|
||||
_treeView->setFolderInfo(folder, folder, blacklist);
|
||||
init(account);
|
||||
_selectiveSync->setFolderInfo(folder, folder, blacklist);
|
||||
}
|
||||
|
||||
void SelectiveSyncDialog::init(const AccountPtr &account, const QString &labelText)
|
||||
void SelectiveSyncDialog::init(const AccountPtr &account)
|
||||
{
|
||||
setWindowTitle(tr("Choose What to Sync"));
|
||||
QVBoxLayout *layout = new QVBoxLayout(this);
|
||||
_treeView = new SelectiveSyncTreeView(account, this);
|
||||
auto label = new QLabel(labelText);
|
||||
label->setWordWrap(true);
|
||||
layout->addWidget(label);
|
||||
layout->addWidget(_treeView);
|
||||
_selectiveSync = new SelectiveSyncWidget(account, this);
|
||||
layout->addWidget(_selectiveSync);
|
||||
QDialogButtonBox *buttonBox = new QDialogButtonBox(Qt::Horizontal);
|
||||
_okButton = buttonBox->addButton(QDialogButtonBox::Ok);
|
||||
connect(_okButton, SIGNAL(clicked()), this, SLOT(accept()));
|
||||
@@ -444,7 +461,7 @@ void SelectiveSyncDialog::accept()
|
||||
if( ! ok ) {
|
||||
return;
|
||||
}
|
||||
QStringList blackList = _treeView->createBlackList();
|
||||
QStringList blackList = _selectiveSync->createBlackList();
|
||||
_folder->journalDb()->setSelectiveSyncList(SyncJournalDb::SelectiveSyncBlackList, blackList);
|
||||
|
||||
FolderMan *folderMan = FolderMan::instance();
|
||||
@@ -467,19 +484,18 @@ void SelectiveSyncDialog::accept()
|
||||
|
||||
QStringList SelectiveSyncDialog::createBlackList() const
|
||||
{
|
||||
return _treeView->createBlackList();
|
||||
return _selectiveSync->createBlackList();
|
||||
}
|
||||
|
||||
QStringList SelectiveSyncDialog::oldBlackList() const
|
||||
{
|
||||
return _treeView->oldBlackList();
|
||||
return _selectiveSync->oldBlackList();
|
||||
}
|
||||
|
||||
qint64 SelectiveSyncDialog::estimatedSize()
|
||||
{
|
||||
return _treeView->estimatedSize();
|
||||
return _selectiveSync->estimatedSize();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -26,40 +26,50 @@ namespace OCC {
|
||||
class Folder;
|
||||
|
||||
/**
|
||||
* @brief The SelectiveSyncTreeView class
|
||||
* @brief The SelectiveSyncWidget contains a folder tree with labels
|
||||
* @ingroup gui
|
||||
*/
|
||||
class SelectiveSyncTreeView : public QTreeWidget {
|
||||
class SelectiveSyncWidget : public QWidget {
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit SelectiveSyncTreeView(AccountPtr account, QWidget* parent = 0);
|
||||
explicit SelectiveSyncWidget(AccountPtr account, QWidget* parent = 0);
|
||||
|
||||
/// Returns a list of blacklisted paths, each including the trailing /
|
||||
QStringList createBlackList(QTreeWidgetItem* root = 0) const;
|
||||
|
||||
/** Returns the oldBlackList passed into setFolderInfo(), except that
|
||||
* a "/" entry is expanded to all top-level folder names.
|
||||
*/
|
||||
QStringList oldBlackList() const;
|
||||
|
||||
// Estimates the total size of checked items (recursively)
|
||||
qint64 estimatedSize(QTreeWidgetItem *root = 0);
|
||||
void refreshFolders();
|
||||
|
||||
// oldBlackList is a list of excluded paths, each including a trailing /
|
||||
void setFolderInfo(const QString &folderPath, const QString &rootName,
|
||||
const QStringList &oldBlackList = QStringList());
|
||||
|
||||
QSize sizeHint() const Q_DECL_OVERRIDE;
|
||||
|
||||
private slots:
|
||||
void slotUpdateDirectories(QStringList);
|
||||
void slotItemExpanded(QTreeWidgetItem *);
|
||||
void slotItemChanged(QTreeWidgetItem*,int);
|
||||
void slotLscolFinishedWithError(QNetworkReply*);
|
||||
private:
|
||||
void refreshFolders();
|
||||
void recursiveInsert(QTreeWidgetItem* parent, QStringList pathTrail, QString path, qint64 size);
|
||||
|
||||
AccountPtr _account;
|
||||
|
||||
QString _folderPath;
|
||||
QString _rootName;
|
||||
QStringList _oldBlackList;
|
||||
|
||||
bool _inserting; // set to true when we are inserting new items on the list
|
||||
AccountPtr _account;
|
||||
QLabel *_loading;
|
||||
|
||||
QTreeWidget *_folderTree;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -85,9 +95,9 @@ public:
|
||||
|
||||
private:
|
||||
|
||||
void init(const AccountPtr &account, const QString &label);
|
||||
void init(const AccountPtr &account);
|
||||
|
||||
SelectiveSyncTreeView *_treeView;
|
||||
SelectiveSyncWidget *_selectiveSync;
|
||||
|
||||
Folder *_folder;
|
||||
QPushButton *_okButton;
|
||||
|
||||
@@ -229,7 +229,7 @@ void ShareLinkWidget::slotSharesFetched(const QList<QSharedPointer<Share>> &shar
|
||||
Q_FOREACH(auto share, shares) {
|
||||
|
||||
if (share->getShareType() == Share::TypeLink) {
|
||||
_share = qSharedPointerObjectCast<LinkShare>(share);
|
||||
_share = qSharedPointerDynamicCast<LinkShare>(share);
|
||||
_ui->pushButton_copy->show();
|
||||
_ui->pushButton_mail->show();
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include "accountstate.h"
|
||||
#include "account.h"
|
||||
#include "capabilities.h"
|
||||
#include "asserts.h"
|
||||
|
||||
#include <QBitArray>
|
||||
#include <QDebug>
|
||||
@@ -60,9 +61,6 @@
|
||||
|
||||
#define DEBUG qDebug() << "SocketApi: "
|
||||
|
||||
Q_DECLARE_METATYPE(OCC::SocketListener)
|
||||
|
||||
|
||||
static inline QString removeTrailingSlash(QString path)
|
||||
{
|
||||
Q_ASSERT(path.endsWith(QLatin1Char('/')));
|
||||
@@ -113,7 +111,7 @@ class SocketListener {
|
||||
public:
|
||||
QIODevice* socket;
|
||||
|
||||
SocketListener(QIODevice* socket = nullptr) : socket(socket) { }
|
||||
SocketListener(QIODevice* socket = 0) : socket(socket) { }
|
||||
|
||||
void sendMessage(const QString& message, bool doWait = false) const
|
||||
{
|
||||
@@ -216,7 +214,7 @@ SocketApi::~SocketApi()
|
||||
DEBUG << "dtor";
|
||||
_localServer.close();
|
||||
// All remaining sockets will be destroyed with _localServer, their parent
|
||||
Q_ASSERT(_listeners.isEmpty() || _listeners.first().socket->parent() == &_localServer);
|
||||
ASSERT(_listeners.isEmpty() || _listeners.first().socket->parent() == &_localServer);
|
||||
_listeners.clear();
|
||||
}
|
||||
|
||||
@@ -231,7 +229,7 @@ void SocketApi::slotNewConnection()
|
||||
connect(socket, SIGNAL(readyRead()), this, SLOT(slotReadSocket()));
|
||||
connect(socket, SIGNAL(disconnected()), this, SLOT(onLostConnection()));
|
||||
connect(socket, SIGNAL(destroyed(QObject*)), this, SLOT(slotSocketDestroyed(QObject*)));
|
||||
Q_ASSERT(socket->readAll().isEmpty());
|
||||
ASSERT(socket->readAll().isEmpty());
|
||||
|
||||
_listeners.append(SocketListener(socket));
|
||||
SocketListener &listener = _listeners.last();
|
||||
@@ -259,7 +257,7 @@ void SocketApi::slotSocketDestroyed(QObject* obj)
|
||||
void SocketApi::slotReadSocket()
|
||||
{
|
||||
QIODevice* socket = qobject_cast<QIODevice*>(sender());
|
||||
Q_ASSERT(socket);
|
||||
ASSERT(socket);
|
||||
SocketListener *listener = &*std::find_if(_listeners.begin(), _listeners.end(), ListenerHasSocketPred(socket));
|
||||
|
||||
while(socket->canReadLine()) {
|
||||
@@ -517,3 +515,5 @@ QString SocketApi::buildRegisterPathMessage(const QString& path)
|
||||
}
|
||||
|
||||
} // namespace OCC
|
||||
|
||||
Q_DECLARE_METATYPE(OCC::SocketListener)
|
||||
|
||||
@@ -145,18 +145,18 @@ void SyncRunFileLog::logItem( const SyncFileItem& item )
|
||||
|
||||
const QChar L = QLatin1Char('|');
|
||||
_out << ts << L;
|
||||
_out << QString::number(item._requestDuration) << L;
|
||||
if( item.log._instruction != CSYNC_INSTRUCTION_RENAME ) {
|
||||
_out << L;
|
||||
if( item._instruction != CSYNC_INSTRUCTION_RENAME ) {
|
||||
_out << item._file << L;
|
||||
} else {
|
||||
_out << item._file << QLatin1String(" -> ") << item._renameTarget << L;
|
||||
}
|
||||
_out << instructionToStr( item.log._instruction ) << L;
|
||||
_out << instructionToStr( item._instruction ) << L;
|
||||
_out << directionToStr( item._direction ) << L;
|
||||
_out << QString::number(item.log._modtime) << L;
|
||||
_out << item.log._etag << L;
|
||||
_out << QString::number(item.log._size) << L;
|
||||
_out << item.log._fileId << L;
|
||||
_out << QString::number(item._modtime) << L;
|
||||
_out << item._etag << L;
|
||||
_out << QString::number(item._size) << L;
|
||||
_out << item._fileId << L;
|
||||
_out << item._status << L;
|
||||
_out << item._errorString << L;
|
||||
_out << QString::number(item._httpErrorCode) << L;
|
||||
|
||||
@@ -44,6 +44,7 @@ void OwncloudShibbolethCredsPage::setupBrowser()
|
||||
// i.e. if someone presses "back"
|
||||
QNetworkAccessManager *qnam = account->networkAccessManager();
|
||||
CookieJar *jar = new CookieJar;
|
||||
jar->restore(account->cookieJarPath());
|
||||
// Implicitly deletes the old cookie jar, and reparents the jar
|
||||
qnam->setCookieJar(jar);
|
||||
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
project(libsync)
|
||||
set(CMAKE_AUTOMOC TRUE)
|
||||
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti")
|
||||
|
||||
configure_file( version.h.in "${CMAKE_CURRENT_BINARY_DIR}/version.h" )
|
||||
|
||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
@@ -172,7 +172,6 @@ void AbstractNetworkJob::slotFinished()
|
||||
|
||||
// get the Date timestamp from reply
|
||||
_responseTimestamp = _reply->rawHeader("Date");
|
||||
_duration = _durationTimer.elapsed();
|
||||
|
||||
if (_followRedirects) {
|
||||
// ### the qWarnings here should be exported via displayErrors() so they
|
||||
@@ -206,11 +205,6 @@ void AbstractNetworkJob::slotFinished()
|
||||
}
|
||||
}
|
||||
|
||||
quint64 AbstractNetworkJob::duration()
|
||||
{
|
||||
return _duration;
|
||||
}
|
||||
|
||||
QByteArray AbstractNetworkJob::responseTimestamp()
|
||||
{
|
||||
return _responseTimestamp;
|
||||
@@ -224,8 +218,6 @@ AbstractNetworkJob::~AbstractNetworkJob()
|
||||
void AbstractNetworkJob::start()
|
||||
{
|
||||
_timer.start();
|
||||
_durationTimer.start();
|
||||
_duration = 0;
|
||||
|
||||
const QUrl url = account()->url();
|
||||
const QString displayUrl = QString( "%1://%2%3").arg(url.scheme()).arg(url.host()).arg(url.path());
|
||||
|
||||
@@ -55,7 +55,6 @@ public:
|
||||
bool ignoreCredentialFailure() const { return _ignoreCredentialFailure; }
|
||||
|
||||
QByteArray responseTimestamp();
|
||||
quint64 duration();
|
||||
|
||||
qint64 timeoutMsec() { return _timer.interval(); }
|
||||
|
||||
@@ -82,8 +81,6 @@ protected:
|
||||
int maxRedirects() const { return 10; }
|
||||
virtual bool finished() = 0;
|
||||
QByteArray _responseTimestamp;
|
||||
QElapsedTimer _durationTimer;
|
||||
quint64 _duration;
|
||||
bool _timedout; // set to true when the timeout slot is received
|
||||
|
||||
// Automatically follows redirects. Note that this only works for
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "creds/abstractcredentials.h"
|
||||
#include "capabilities.h"
|
||||
#include "theme.h"
|
||||
#include "asserts.h"
|
||||
|
||||
#include <QSettings>
|
||||
#include <QMutex>
|
||||
@@ -153,8 +154,9 @@ QUrl Account::davUrl() const
|
||||
*/
|
||||
void Account::clearCookieJar()
|
||||
{
|
||||
Q_ASSERT(qobject_cast<CookieJar*>(_am->cookieJar()));
|
||||
static_cast<CookieJar*>(_am->cookieJar())->setAllCookies(QList<QNetworkCookie>());
|
||||
auto jar = qobject_cast<CookieJar*>(_am->cookieJar());
|
||||
ASSERT(jar);
|
||||
jar->setAllCookies(QList<QNetworkCookie>());
|
||||
emit wantsAccountSaved(this);
|
||||
}
|
||||
|
||||
@@ -169,6 +171,12 @@ void Account::lendCookieJarTo(QNetworkAccessManager *guest)
|
||||
jar->setParent(oldParent); // takes it back
|
||||
}
|
||||
|
||||
QString Account::cookieJarPath()
|
||||
{
|
||||
ConfigFile cfg;
|
||||
return cfg.configPath() + "/cookies" + id() + ".db";
|
||||
}
|
||||
|
||||
void Account::resetNetworkAccessManager()
|
||||
{
|
||||
if (!_credentials || !_am) {
|
||||
|
||||
@@ -172,6 +172,7 @@ public:
|
||||
|
||||
void clearCookieJar();
|
||||
void lendCookieJarTo(QNetworkAccessManager *guest);
|
||||
QString cookieJarPath();
|
||||
|
||||
void resetNetworkAccessManager();
|
||||
QNetworkAccessManager* networkAccessManager();
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
#ifndef OWNCLOUD_ASSERTS_H
|
||||
#define OWNCLOUD_ASSERTS_H
|
||||
|
||||
#include <qglobal.h>
|
||||
|
||||
#if defined(QT_FORCE_ASSERTS) || !defined(QT_NO_DEBUG)
|
||||
#define OC_ASSERT_MSG qFatal
|
||||
#else
|
||||
#define OC_ASSERT_MSG qWarning
|
||||
#endif
|
||||
|
||||
// For overloading macros by argument count
|
||||
// See stackoverflow.com/questions/16683146/can-macros-be-overloaded-by-number-of-arguments
|
||||
#define OC_ASSERT_CAT(A, B) A ## B
|
||||
#define OC_ASSERT_SELECT(NAME, NUM) OC_ASSERT_CAT(NAME ## _, NUM)
|
||||
#define OC_ASSERT_GET_COUNT(_1, _2, _3, COUNT, ...) COUNT
|
||||
#define OC_ASSERT_VA_SIZE(...) OC_ASSERT_GET_COUNT(__VA_ARGS__, 3, 2, 1, 0)
|
||||
|
||||
#define OC_ASSERT_OVERLOAD(NAME, ...) OC_ASSERT_SELECT(NAME, OC_ASSERT_VA_SIZE(__VA_ARGS__))(__VA_ARGS__)
|
||||
|
||||
// Default assert: If the condition is false in debug builds, terminate.
|
||||
//
|
||||
// Prints a message on failure, even in release builds.
|
||||
#define ASSERT(...) OC_ASSERT_OVERLOAD(ASSERT, __VA_ARGS__)
|
||||
#define ASSERT_1(cond) \
|
||||
if (!(cond)) { \
|
||||
OC_ASSERT_MSG("ASSERT: \"%s\" in file %s, line %d", #cond, __FILE__, __LINE__); \
|
||||
} else {}
|
||||
#define ASSERT_2(cond, message) \
|
||||
if (!(cond)) { \
|
||||
OC_ASSERT_MSG("ASSERT: \"%s\" in file %s, line %d with message: %s", #cond, __FILE__, __LINE__, message); \
|
||||
} else {}
|
||||
|
||||
// Enforce condition to be true, even in release builds.
|
||||
//
|
||||
// Prints 'message' and aborts execution if 'cond' is false.
|
||||
#define ENFORCE(...) OC_ASSERT_OVERLOAD(ENFORCE, __VA_ARGS__)
|
||||
#define ENFORCE_1(cond) \
|
||||
if (!(cond)) { \
|
||||
qFatal("ENFORCE: \"%s\" in file %s, line %d", #cond, __FILE__, __LINE__); \
|
||||
} else {}
|
||||
#define ENFORCE_2(cond, message) \
|
||||
if (!(cond)) { \
|
||||
qFatal("ENFORCE: \"%s\" in file %s, line %d with message: %s", #cond, __FILE__, __LINE__, message); \
|
||||
} else {}
|
||||
|
||||
// An assert that is only present in debug builds: typically used for
|
||||
// asserts that are too expensive for release mode.
|
||||
//
|
||||
// Q_ASSERT
|
||||
|
||||
#endif
|
||||
@@ -111,10 +111,10 @@ bool uploadChecksumEnabled()
|
||||
QByteArray contentChecksumType()
|
||||
{
|
||||
static QByteArray type = qgetenv("OWNCLOUD_CONTENT_CHECKSUM_TYPE");
|
||||
if (!type.isNull()) { // can set to "" to disable checksumming
|
||||
return type;
|
||||
if (type.isNull()) { // can set to "" to disable checksumming
|
||||
type = "SHA1";
|
||||
}
|
||||
return "SHA1";
|
||||
return type;
|
||||
}
|
||||
|
||||
ComputeChecksum::ComputeChecksum(QObject* parent)
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include "configfile.h"
|
||||
#include "theme.h"
|
||||
#include "utility.h"
|
||||
#include "asserts.h"
|
||||
|
||||
#include "creds/abstractcredentials.h"
|
||||
|
||||
@@ -139,7 +140,7 @@ void ConfigFile::setOptionalDesktopNotifications(bool show)
|
||||
void ConfigFile::saveGeometry(QWidget *w)
|
||||
{
|
||||
#ifndef TOKEN_AUTH_ONLY
|
||||
Q_ASSERT(!w->objectName().isNull());
|
||||
ASSERT(!w->objectName().isNull());
|
||||
QSettings settings(configFile(), QSettings::IniFormat);
|
||||
settings.beginGroup(w->objectName());
|
||||
settings.setValue(QLatin1String(geometryC), w->saveGeometry());
|
||||
@@ -158,7 +159,7 @@ void ConfigFile::saveGeometryHeader(QHeaderView *header)
|
||||
{
|
||||
#ifndef TOKEN_AUTH_ONLY
|
||||
if(!header) return;
|
||||
Q_ASSERT(!header->objectName().isEmpty());
|
||||
ASSERT(!header->objectName().isEmpty());
|
||||
|
||||
QSettings settings(configFile(), QSettings::IniFormat);
|
||||
settings.beginGroup(header->objectName());
|
||||
@@ -171,7 +172,7 @@ void ConfigFile::restoreGeometryHeader(QHeaderView *header)
|
||||
{
|
||||
#ifndef TOKEN_AUTH_ONLY
|
||||
if(!header) return;
|
||||
Q_ASSERT(!header->objectName().isNull());
|
||||
ASSERT(!header->objectName().isNull());
|
||||
|
||||
QSettings settings(configFile(), QSettings::IniFormat);
|
||||
settings.beginGroup(header->objectName());
|
||||
@@ -230,8 +231,8 @@ QString ConfigFile::excludeFile(Scope scope) const
|
||||
// directories.
|
||||
QFileInfo fi;
|
||||
|
||||
if (scope != SystemScope) {
|
||||
QFileInfo fi;
|
||||
switch (scope) {
|
||||
case UserScope:
|
||||
fi.setFile( configPath(), exclFile );
|
||||
|
||||
if( ! fi.isReadable() ) {
|
||||
@@ -241,12 +242,12 @@ QString ConfigFile::excludeFile(Scope scope) const
|
||||
fi.setFile( configPath(), exclFile );
|
||||
}
|
||||
return fi.absoluteFilePath();
|
||||
} else if (scope != UserScope) {
|
||||
case SystemScope:
|
||||
return ConfigFile::excludeFileFromSystem();
|
||||
} else {
|
||||
Q_ASSERT(false);
|
||||
return QString(); // unreachable
|
||||
}
|
||||
|
||||
ASSERT(false);
|
||||
return QString();
|
||||
}
|
||||
|
||||
QString ConfigFile::excludeFileFromSystem()
|
||||
|
||||
@@ -68,7 +68,6 @@ QDataStream &operator>>(QDataStream &stream, QList<QNetworkCookie> &list)
|
||||
CookieJar::CookieJar(QObject *parent) :
|
||||
QNetworkCookieJar(parent)
|
||||
{
|
||||
restore();
|
||||
}
|
||||
|
||||
CookieJar::~CookieJar()
|
||||
@@ -97,21 +96,21 @@ void CookieJar::clearSessionCookies()
|
||||
setAllCookies(removeExpired(allCookies()));
|
||||
}
|
||||
|
||||
void CookieJar::save()
|
||||
void CookieJar::save(const QString &fileName)
|
||||
{
|
||||
QFile file;
|
||||
file.setFileName(storagePath());
|
||||
qDebug() << storagePath();
|
||||
file.setFileName(fileName);
|
||||
qDebug() << fileName;
|
||||
file.open(QIODevice::WriteOnly);
|
||||
QDataStream stream(&file);
|
||||
stream << removeExpired(allCookies());
|
||||
file.close();
|
||||
}
|
||||
|
||||
void CookieJar::restore()
|
||||
void CookieJar::restore(const QString &fileName)
|
||||
{
|
||||
QFile file;
|
||||
file.setFileName(storagePath());
|
||||
file.setFileName(fileName);
|
||||
file.open(QIODevice::ReadOnly);
|
||||
QDataStream stream(&file);
|
||||
QList<QNetworkCookie> list;
|
||||
@@ -131,10 +130,4 @@ QList<QNetworkCookie> CookieJar::removeExpired(const QList<QNetworkCookie> &cook
|
||||
return updatedList;
|
||||
}
|
||||
|
||||
QString CookieJar::storagePath() const
|
||||
{
|
||||
ConfigFile cfg;
|
||||
return cfg.configPath() + "/cookies.db";
|
||||
}
|
||||
|
||||
} // namespace OCC
|
||||
|
||||
@@ -39,15 +39,13 @@ public:
|
||||
using QNetworkCookieJar::setAllCookies;
|
||||
using QNetworkCookieJar::allCookies;
|
||||
|
||||
void save();
|
||||
void save(const QString &fileName);
|
||||
void restore(const QString &fileName);
|
||||
|
||||
signals:
|
||||
void newCookiesForUrl(const QList<QNetworkCookie>& cookieList, const QUrl& url);
|
||||
private:
|
||||
void restore();
|
||||
QList<QNetworkCookie> removeExpired(const QList<QNetworkCookie> &cookies);
|
||||
QString storagePath() const;
|
||||
|
||||
};
|
||||
|
||||
} // namespace OCC
|
||||
|
||||
@@ -12,10 +12,10 @@
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
|
||||
#include <QString>
|
||||
#include <QDebug>
|
||||
|
||||
#include "asserts.h"
|
||||
#include "creds/abstractcredentials.h"
|
||||
|
||||
namespace OCC
|
||||
@@ -28,7 +28,7 @@ AbstractCredentials::AbstractCredentials()
|
||||
|
||||
void AbstractCredentials::setAccount(Account *account)
|
||||
{
|
||||
Q_ASSERT(!_account);
|
||||
ENFORCE(!_account, "should only setAccount once");
|
||||
_account = account;
|
||||
}
|
||||
|
||||
|
||||
@@ -13,14 +13,17 @@
|
||||
*/
|
||||
|
||||
#include "discoveryphase.h"
|
||||
|
||||
#include "account.h"
|
||||
#include "theme.h"
|
||||
#include "asserts.h"
|
||||
|
||||
#include <csync_private.h>
|
||||
#include <csync_rename.h>
|
||||
#include <qdebug.h>
|
||||
|
||||
#include <qdebug.h>
|
||||
#include <QUrl>
|
||||
#include "account.h"
|
||||
#include <QFileInfo>
|
||||
#include "theme.h"
|
||||
#include <cstring>
|
||||
|
||||
|
||||
@@ -244,7 +247,7 @@ int get_errno_from_http_errcode( int err, const QString & reason ) {
|
||||
|
||||
|
||||
DiscoverySingleDirectoryJob::DiscoverySingleDirectoryJob(const AccountPtr &account, const QString &path, QObject *parent)
|
||||
: QObject(parent), _subPath(path), _account(account), _ignoredFirst(false), _isRootPath(false)
|
||||
: QObject(parent), _subPath(path), _account(account), _ignoredFirst(false), _isRootPath(false), _isExternalStorage(false)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -370,7 +373,7 @@ void DiscoverySingleDirectoryJob::directoryListingIteratedSlot(QString file, con
|
||||
/* All the entries in a external storage have 'M' in their permission. However, for all
|
||||
purposes in the desktop client, we only need to know about the mount points.
|
||||
So replace the 'M' by a 'm' for every sub entries in an external storage */
|
||||
std::replace(std::begin(file_stat->remotePerm), std::end(file_stat->remotePerm),
|
||||
std::replace(file_stat->remotePerm, file_stat->remotePerm + strlen(file_stat->remotePerm),
|
||||
'M', 'm');
|
||||
}
|
||||
|
||||
|
||||
@@ -35,11 +35,12 @@ class Account;
|
||||
*/
|
||||
|
||||
struct SyncOptions {
|
||||
SyncOptions() : _newBigFolderSizeLimit(-1), _confirmExternalStorage(false) {}
|
||||
/** Maximum size (in Bytes) a folder can have without asking for confirmation.
|
||||
* -1 means infinite */
|
||||
qint64 _newBigFolderSizeLimit = -1;
|
||||
qint64 _newBigFolderSizeLimit;
|
||||
/** If a confirmation should be asked for external storages */
|
||||
bool _confirmExternalStorage = false;
|
||||
bool _confirmExternalStorage;
|
||||
};
|
||||
|
||||
|
||||
@@ -117,7 +118,7 @@ private:
|
||||
// Set to true if this is the root path and we need to check the data-fingerprint
|
||||
bool _isRootPath;
|
||||
// If this directory is an external storage (The first item has 'M' in its permission)
|
||||
bool _isExternalStorage = false;
|
||||
bool _isExternalStorage;
|
||||
QPointer<LsColJob> _lsColJob;
|
||||
|
||||
public:
|
||||
|
||||
@@ -47,7 +47,7 @@ void ExcludedFiles::addExcludeFilePath(const QString& path)
|
||||
_excludeFiles.insert(path);
|
||||
}
|
||||
|
||||
#ifdef WITH_UNIT_TESTING
|
||||
#ifdef WITH_TESTING
|
||||
void ExcludedFiles::addExcludeExpr(const QString &expr)
|
||||
{
|
||||
_csync_exclude_add(_excludesPtr, expr.toLatin1().constData());
|
||||
|
||||
@@ -58,7 +58,7 @@ public:
|
||||
const QString& basePath,
|
||||
bool excludeHidden) const;
|
||||
|
||||
#ifdef WITH_UNIT_TESTING
|
||||
#ifdef WITH_TESTING
|
||||
void addExcludeExpr(const QString &expr);
|
||||
#endif
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include "configfile.h"
|
||||
#include "utility.h"
|
||||
#include "account.h"
|
||||
#include "asserts.h"
|
||||
#include <json.h>
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
@@ -172,7 +173,7 @@ void PropagateItemJob::done(SyncFileItem::Status status, const QString &errorStr
|
||||
|
||||
_item->_status = status;
|
||||
|
||||
emit itemCompleted(*_item, *this);
|
||||
emit itemCompleted(_item);
|
||||
emit finished(status);
|
||||
}
|
||||
|
||||
@@ -221,7 +222,7 @@ bool PropagateItemJob::checkForProblemsWithShared(int httpStatusCode, const QStr
|
||||
if( newJob ) {
|
||||
newJob->setRestoreJobMsg(msg);
|
||||
_restoreJob.reset(newJob);
|
||||
connect(_restoreJob.data(), SIGNAL(itemCompleted(const SyncFileItemPtr &, const PropagatorJob &)),
|
||||
connect(_restoreJob.data(), SIGNAL(itemCompleted(const SyncFileItemPtr &)),
|
||||
this, SLOT(slotRestoreJobCompleted(const SyncFileItemPtr &)));
|
||||
QMetaObject::invokeMethod(newJob, "start");
|
||||
}
|
||||
@@ -403,8 +404,8 @@ void OwncloudPropagator::start(const SyncFileItemVector& items)
|
||||
_rootJob->append(it);
|
||||
}
|
||||
|
||||
connect(_rootJob.data(), SIGNAL(itemCompleted(const SyncFileItem &, const PropagatorJob &)),
|
||||
this, SIGNAL(itemCompleted(const SyncFileItem &, const PropagatorJob &)));
|
||||
connect(_rootJob.data(), SIGNAL(itemCompleted(const SyncFileItemPtr &)),
|
||||
this, SIGNAL(itemCompleted(const SyncFileItemPtr &)));
|
||||
connect(_rootJob.data(), SIGNAL(progress(const SyncFileItem &,quint64)), this, SIGNAL(progress(const SyncFileItem &,quint64)));
|
||||
connect(_rootJob.data(), SIGNAL(finished(SyncFileItem::Status)), this, SLOT(emitFinished(SyncFileItem::Status)));
|
||||
connect(_rootJob.data(), SIGNAL(ready()), this, SLOT(scheduleNextJob()), Qt::QueuedConnection);
|
||||
@@ -588,17 +589,12 @@ OwncloudPropagator *PropagatorJob::propagator() const
|
||||
PropagatorJob::JobParallelism PropagateDirectory::parallelism()
|
||||
{
|
||||
// If any of the non-finished sub jobs is not parallel, we have to wait
|
||||
|
||||
// FIXME! we should probably cache this result
|
||||
|
||||
if (_firstJob && _firstJob->_state != Finished) {
|
||||
if (_firstJob->parallelism() != FullParallelism)
|
||||
return WaitForFinished;
|
||||
if (_firstJob && _firstJob->parallelism() != FullParallelism) {
|
||||
return WaitForFinished;
|
||||
}
|
||||
|
||||
// FIXME: use the cached value of finished job
|
||||
for (int i = 0; i < _subJobs.count(); ++i) {
|
||||
if (_subJobs.at(i)->_state != Finished && _subJobs.at(i)->parallelism() != FullParallelism) {
|
||||
if (_subJobs.at(i)->parallelism() != FullParallelism) {
|
||||
return WaitForFinished;
|
||||
}
|
||||
}
|
||||
@@ -629,15 +625,8 @@ bool PropagateDirectory::scheduleNextJob()
|
||||
return false;
|
||||
}
|
||||
|
||||
// cache the value of first unfinished subjob
|
||||
bool stopAtDirectory = false;
|
||||
int i = _firstUnfinishedSubJob;
|
||||
int subJobsCount = _subJobs.count();
|
||||
while (i < subJobsCount && _subJobs.at(i)->_state == Finished) {
|
||||
_firstUnfinishedSubJob = ++i;
|
||||
}
|
||||
|
||||
for (int i = _firstUnfinishedSubJob; i < subJobsCount; ++i) {
|
||||
for (int i = 0; i < _subJobs.size(); ++i) {
|
||||
if (_subJobs.at(i)->_state == Finished) {
|
||||
continue;
|
||||
}
|
||||
@@ -650,7 +639,7 @@ bool PropagateDirectory::scheduleNextJob()
|
||||
return true;
|
||||
}
|
||||
|
||||
Q_ASSERT(_subJobs.at(i)->_state == Running);
|
||||
ASSERT(_subJobs.at(i)->_state == Running);
|
||||
|
||||
auto paral = _subJobs.at(i)->parallelism();
|
||||
if (paral == WaitForFinished) {
|
||||
@@ -665,8 +654,23 @@ bool PropagateDirectory::scheduleNextJob()
|
||||
|
||||
void PropagateDirectory::slotSubJobFinished(SyncFileItem::Status status)
|
||||
{
|
||||
PropagatorJob *subJob = static_cast<PropagatorJob *>(sender());
|
||||
ASSERT(subJob);
|
||||
|
||||
// Delete the job and remove it from our list of jobs.
|
||||
subJob->deleteLater();
|
||||
bool wasFirstJob = false;
|
||||
if (subJob == _firstJob.data()) {
|
||||
wasFirstJob = true;
|
||||
_firstJob.reset();
|
||||
} else {
|
||||
int i = _subJobs.indexOf(subJob);
|
||||
ASSERT(i >= 0);
|
||||
_subJobs.remove(i);
|
||||
}
|
||||
|
||||
if (status == SyncFileItem::FatalError ||
|
||||
(sender() == _firstJob.data() && status != SyncFileItem::Success && status != SyncFileItem::Restoration)) {
|
||||
(wasFirstJob && status != SyncFileItem::Success && status != SyncFileItem::Restoration)) {
|
||||
abort();
|
||||
_state = Finished;
|
||||
emit finished(status);
|
||||
@@ -674,18 +678,10 @@ void PropagateDirectory::slotSubJobFinished(SyncFileItem::Status status)
|
||||
} else if (status == SyncFileItem::NormalError || status == SyncFileItem::SoftError) {
|
||||
_hasError = status;
|
||||
}
|
||||
_runningNow--;
|
||||
_jobsFinished++;
|
||||
|
||||
int totalJobs = _subJobs.count();
|
||||
if (_firstJob) {
|
||||
totalJobs++;
|
||||
}
|
||||
|
||||
// We finished processing all the jobs
|
||||
// check if we finished
|
||||
if (_jobsFinished >= totalJobs) {
|
||||
Q_ASSERT(!_runningNow); // how can we be finished if there are still jobs running now
|
||||
if (!_firstJob && _subJobs.isEmpty()) {
|
||||
finalize();
|
||||
} else {
|
||||
emit ready();
|
||||
@@ -765,7 +761,7 @@ void CleanupPollsJob::start()
|
||||
void CleanupPollsJob::slotPollFinished()
|
||||
{
|
||||
PollJob *job = qobject_cast<PollJob *>(sender());
|
||||
Q_ASSERT(job);
|
||||
ASSERT(job);
|
||||
if (job->_item->_status == SyncFileItem::FatalError) {
|
||||
emit aborted(job->_item->_errorString);
|
||||
deleteLater();
|
||||
|
||||
@@ -114,7 +114,7 @@ signals:
|
||||
/**
|
||||
* Emitted when one item has been completed within a job.
|
||||
*/
|
||||
void itemCompleted(const SyncFileItem &, const PropagatorJob &);
|
||||
void itemCompleted(const SyncFileItemPtr &);
|
||||
|
||||
/**
|
||||
* Emitted when all the sub-jobs have been finished and
|
||||
@@ -192,14 +192,11 @@ public:
|
||||
|
||||
SyncFileItemPtr _item;
|
||||
|
||||
int _jobsFinished; // number of jobs that have completed
|
||||
int _runningNow; // number of subJobs running right now
|
||||
SyncFileItem::Status _hasError; // NoStatus, or NormalError / SoftError if there was an error
|
||||
int _firstUnfinishedSubJob;
|
||||
|
||||
explicit PropagateDirectory(OwncloudPropagator *propagator, const SyncFileItemPtr &item = SyncFileItemPtr(new SyncFileItem))
|
||||
: PropagatorJob(propagator)
|
||||
, _firstJob(0), _item(item), _jobsFinished(0), _runningNow(0), _hasError(SyncFileItem::NoStatus), _firstUnfinishedSubJob(0)
|
||||
, _item(item), _hasError(SyncFileItem::NoStatus)
|
||||
{ }
|
||||
|
||||
virtual ~PropagateDirectory() {
|
||||
@@ -231,11 +228,9 @@ private slots:
|
||||
bool possiblyRunNextJob(PropagatorJob *next) {
|
||||
if (next->_state == NotYetStarted) {
|
||||
connect(next, SIGNAL(finished(SyncFileItem::Status)), this, SLOT(slotSubJobFinished(SyncFileItem::Status)), Qt::QueuedConnection);
|
||||
connect(next, SIGNAL(itemCompleted(const SyncFileItem &, const PropagatorJob &)),
|
||||
this, SIGNAL(itemCompleted(const SyncFileItem &, const PropagatorJob &)));
|
||||
connect(next, SIGNAL(itemCompleted(const SyncFileItemPtr &)), this, SIGNAL(itemCompleted(const SyncFileItemPtr &)));
|
||||
connect(next, SIGNAL(progress(const SyncFileItem &,quint64)), this, SIGNAL(progress(const SyncFileItem &,quint64)));
|
||||
connect(next, SIGNAL(ready()), this, SIGNAL(ready()));
|
||||
_runningNow++;
|
||||
}
|
||||
return next->scheduleNextJob();
|
||||
}
|
||||
@@ -356,7 +351,7 @@ private slots:
|
||||
void scheduleNextJob();
|
||||
|
||||
signals:
|
||||
void itemCompleted(const SyncFileItem &, const PropagatorJob &);
|
||||
void itemCompleted(const SyncFileItemPtr &);
|
||||
void progress(const SyncFileItem&, quint64 bytes);
|
||||
void finished(bool success);
|
||||
|
||||
|
||||
+56
-59
@@ -20,6 +20,7 @@
|
||||
|
||||
#include "ownsql.h"
|
||||
#include "utility.h"
|
||||
#include "asserts.h"
|
||||
|
||||
#define SQLITE_SLEEP_TIME_USEC 100000
|
||||
#define SQLITE_REPEAT_COUNT 20
|
||||
@@ -147,10 +148,8 @@ void SqlDatabase::close()
|
||||
{
|
||||
if( _db ) {
|
||||
SQLITE_DO(sqlite3_close(_db) );
|
||||
if (_errId != SQLITE_OK) {
|
||||
qWarning() << "ERROR When closing DB" << _error;
|
||||
Q_ASSERT(!"SQLite Close Error");
|
||||
}
|
||||
// Fatal because reopening an unclosed db might be problematic.
|
||||
ENFORCE(_errId == SQLITE_OK, "Error when closing DB");
|
||||
_db = 0;
|
||||
}
|
||||
}
|
||||
@@ -223,11 +222,7 @@ int SqlQuery::prepare( const QString& sql, bool allow_failure )
|
||||
if( _errId != SQLITE_OK ) {
|
||||
_error = QString::fromUtf8(sqlite3_errmsg(_db));
|
||||
qWarning() << "Sqlite prepare statement error:" << _error << "in" <<_sql;
|
||||
if (!allow_failure) {
|
||||
qFatal("SQLITE Prepare error: %s in %s",
|
||||
_error.toLocal8Bit().data(),
|
||||
sql.toLocal8Bit().data());
|
||||
}
|
||||
ENFORCE(allow_failure, "SQLITE Prepare error");
|
||||
}
|
||||
}
|
||||
return _errId;
|
||||
@@ -284,61 +279,63 @@ bool SqlQuery::next()
|
||||
void SqlQuery::bindValue(int pos, const QVariant& value)
|
||||
{
|
||||
int res = -1;
|
||||
Q_ASSERT(_stmt);
|
||||
if( _stmt ) {
|
||||
switch (value.type()) {
|
||||
case QVariant::Int:
|
||||
case QVariant::Bool:
|
||||
res = sqlite3_bind_int(_stmt, pos, value.toInt());
|
||||
break;
|
||||
case QVariant::Double:
|
||||
res = sqlite3_bind_double(_stmt, pos, value.toDouble());
|
||||
break;
|
||||
case QVariant::UInt:
|
||||
case QVariant::LongLong:
|
||||
res = sqlite3_bind_int64(_stmt, pos, value.toLongLong());
|
||||
break;
|
||||
case QVariant::DateTime: {
|
||||
const QDateTime dateTime = value.toDateTime();
|
||||
const QString str = dateTime.toString(QLatin1String("yyyy-MM-ddThh:mm:ss.zzz"));
|
||||
res = sqlite3_bind_text16(_stmt, pos, str.utf16(),
|
||||
str.size() * sizeof(ushort), SQLITE_TRANSIENT);
|
||||
break;
|
||||
}
|
||||
case QVariant::Time: {
|
||||
const QTime time = value.toTime();
|
||||
const QString str = time.toString(QLatin1String("hh:mm:ss.zzz"));
|
||||
res = sqlite3_bind_text16(_stmt, pos, str.utf16(),
|
||||
str.size() * sizeof(ushort), SQLITE_TRANSIENT);
|
||||
break;
|
||||
}
|
||||
case QVariant::String: {
|
||||
if( !value.toString().isNull() ) {
|
||||
// lifetime of string == lifetime of its qvariant
|
||||
const QString *str = static_cast<const QString*>(value.constData());
|
||||
res = sqlite3_bind_text16(_stmt, pos, str->utf16(),
|
||||
(str->size()) * sizeof(QChar), SQLITE_TRANSIENT);
|
||||
} else {
|
||||
res = sqlite3_bind_null(_stmt, pos);
|
||||
}
|
||||
break; }
|
||||
case QVariant::ByteArray: {
|
||||
auto ba = value.toByteArray();
|
||||
res = sqlite3_bind_text(_stmt, pos, ba.constData(), ba.size(), SQLITE_TRANSIENT);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
QString str = value.toString();
|
||||
// SQLITE_TRANSIENT makes sure that sqlite buffers the data
|
||||
res = sqlite3_bind_text16(_stmt, pos, str.utf16(),
|
||||
(str.size()) * sizeof(QChar), SQLITE_TRANSIENT);
|
||||
break; }
|
||||
if (!_stmt) {
|
||||
ASSERT(false);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (value.type()) {
|
||||
case QVariant::Int:
|
||||
case QVariant::Bool:
|
||||
res = sqlite3_bind_int(_stmt, pos, value.toInt());
|
||||
break;
|
||||
case QVariant::Double:
|
||||
res = sqlite3_bind_double(_stmt, pos, value.toDouble());
|
||||
break;
|
||||
case QVariant::UInt:
|
||||
case QVariant::LongLong:
|
||||
res = sqlite3_bind_int64(_stmt, pos, value.toLongLong());
|
||||
break;
|
||||
case QVariant::DateTime: {
|
||||
const QDateTime dateTime = value.toDateTime();
|
||||
const QString str = dateTime.toString(QLatin1String("yyyy-MM-ddThh:mm:ss.zzz"));
|
||||
res = sqlite3_bind_text16(_stmt, pos, str.utf16(),
|
||||
str.size() * sizeof(ushort), SQLITE_TRANSIENT);
|
||||
break;
|
||||
}
|
||||
case QVariant::Time: {
|
||||
const QTime time = value.toTime();
|
||||
const QString str = time.toString(QLatin1String("hh:mm:ss.zzz"));
|
||||
res = sqlite3_bind_text16(_stmt, pos, str.utf16(),
|
||||
str.size() * sizeof(ushort), SQLITE_TRANSIENT);
|
||||
break;
|
||||
}
|
||||
case QVariant::String: {
|
||||
if( !value.toString().isNull() ) {
|
||||
// lifetime of string == lifetime of its qvariant
|
||||
const QString *str = static_cast<const QString*>(value.constData());
|
||||
res = sqlite3_bind_text16(_stmt, pos, str->utf16(),
|
||||
(str->size()) * sizeof(QChar), SQLITE_TRANSIENT);
|
||||
} else {
|
||||
res = sqlite3_bind_null(_stmt, pos);
|
||||
}
|
||||
break; }
|
||||
case QVariant::ByteArray: {
|
||||
auto ba = value.toByteArray();
|
||||
res = sqlite3_bind_text(_stmt, pos, ba.constData(), ba.size(), SQLITE_TRANSIENT);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
QString str = value.toString();
|
||||
// SQLITE_TRANSIENT makes sure that sqlite buffers the data
|
||||
res = sqlite3_bind_text16(_stmt, pos, str.utf16(),
|
||||
(str.size()) * sizeof(QChar), SQLITE_TRANSIENT);
|
||||
break; }
|
||||
}
|
||||
if (res != SQLITE_OK) {
|
||||
qDebug() << Q_FUNC_INFO << "ERROR" << value << res;
|
||||
}
|
||||
Q_ASSERT( res == SQLITE_OK );
|
||||
ASSERT( res == SQLITE_OK );
|
||||
}
|
||||
|
||||
bool SqlQuery::nullValue(int index)
|
||||
|
||||
@@ -28,8 +28,6 @@
|
||||
|
||||
namespace OCC {
|
||||
|
||||
class PropagatorJob;
|
||||
|
||||
/**
|
||||
* @brief The ProgressInfo class
|
||||
* @ingroup libsync
|
||||
@@ -252,9 +250,7 @@ signals:
|
||||
/**
|
||||
* @brief: the item was completed by a job
|
||||
*/
|
||||
void itemCompleted(const QString &folder,
|
||||
const SyncFileItem & item,
|
||||
const PropagatorJob & job);
|
||||
void itemCompleted(const QString &folder, const SyncFileItemPtr & item);
|
||||
|
||||
protected:
|
||||
void setProgressInfo(const QString& folder, const ProgressInfo& progress);
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "filesystem.h"
|
||||
#include "propagatorjobs.h"
|
||||
#include "checksums.h"
|
||||
#include "asserts.h"
|
||||
|
||||
#include <json.h>
|
||||
#include <QNetworkAccessManager>
|
||||
@@ -441,7 +442,7 @@ void PropagateDownloadFile::slotGetFinished()
|
||||
propagator()->_activeJobList.removeOne(this);
|
||||
|
||||
GETFileJob *job = qobject_cast<GETFileJob *>(sender());
|
||||
Q_ASSERT(job);
|
||||
ASSERT(job);
|
||||
|
||||
qDebug() << Q_FUNC_INFO << job->reply()->request().url() << "FINISHED WITH STATUS"
|
||||
<< job->reply()->error()
|
||||
@@ -520,7 +521,6 @@ void PropagateDownloadFile::slotGetFinished()
|
||||
// so make sure we have the up-to-date time
|
||||
_item->_modtime = job->lastModified();
|
||||
}
|
||||
_item->_requestDuration = job->duration();
|
||||
_item->_responseTimeStamp = job->responseTimestamp();
|
||||
|
||||
_tmpFile.close();
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include "propagateremotedelete.h"
|
||||
#include "owncloudpropagator_p.h"
|
||||
#include "account.h"
|
||||
#include "asserts.h"
|
||||
|
||||
namespace OCC {
|
||||
|
||||
@@ -81,7 +82,7 @@ void PropagateRemoteDelete::slotDeleteJobFinished()
|
||||
{
|
||||
propagator()->_activeJobList.removeOne(this);
|
||||
|
||||
Q_ASSERT(_job);
|
||||
ASSERT(_job);
|
||||
|
||||
qDebug() << Q_FUNC_INFO << _job->reply()->request().url() << "FINISHED WITH STATUS"
|
||||
<< _job->reply()->error()
|
||||
@@ -104,7 +105,6 @@ void PropagateRemoteDelete::slotDeleteJobFinished()
|
||||
return;
|
||||
}
|
||||
|
||||
_item->_requestDuration = _job->duration();
|
||||
_item->_responseTimeStamp = _job->responseTimestamp();
|
||||
|
||||
// A 404 reply is also considered a success here: We want to make sure
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include "account.h"
|
||||
#include "syncjournalfilerecord.h"
|
||||
#include "propagateremotedelete.h"
|
||||
#include "asserts.h"
|
||||
#include <QFile>
|
||||
|
||||
namespace OCC {
|
||||
@@ -70,7 +71,7 @@ void PropagateRemoteMkdir::slotMkcolJobFinished()
|
||||
{
|
||||
propagator()->_activeJobList.removeOne(this);
|
||||
|
||||
Q_ASSERT(_job);
|
||||
ASSERT(_job);
|
||||
|
||||
qDebug() << Q_FUNC_INFO << _job->reply()->request().url() << "FINISHED WITH STATUS"
|
||||
<< _job->reply()->error()
|
||||
@@ -99,7 +100,6 @@ void PropagateRemoteMkdir::slotMkcolJobFinished()
|
||||
return;
|
||||
}
|
||||
|
||||
_item->_requestDuration = _job->duration();
|
||||
_item->_responseTimeStamp = _job->responseTimestamp();
|
||||
_item->_fileId = _job->reply()->rawHeader("OC-FileId");
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include "account.h"
|
||||
#include "syncjournalfilerecord.h"
|
||||
#include "filesystem.h"
|
||||
#include "asserts.h"
|
||||
#include <QFile>
|
||||
#include <QStringList>
|
||||
#include <QDir>
|
||||
@@ -123,7 +124,7 @@ void PropagateRemoteMove::slotMoveJobFinished()
|
||||
{
|
||||
propagator()->_activeJobList.removeOne(this);
|
||||
|
||||
Q_ASSERT(_job);
|
||||
ASSERT(_job);
|
||||
|
||||
qDebug() << Q_FUNC_INFO << _job->reply()->request().url() << "FINISHED WITH STATUS"
|
||||
<< _job->reply()->error()
|
||||
@@ -145,7 +146,6 @@ void PropagateRemoteMove::slotMoveJobFinished()
|
||||
return;
|
||||
}
|
||||
|
||||
_item->_requestDuration = _job->duration();
|
||||
_item->_responseTimeStamp = _job->responseTimestamp();
|
||||
|
||||
if (_item->_httpErrorCode != 201 ) {
|
||||
@@ -208,8 +208,8 @@ bool PropagateRemoteMove::adjustSelectiveSync(SyncJournalDb *journal, const QStr
|
||||
return false;
|
||||
|
||||
bool changed = false;
|
||||
Q_ASSERT(!from_.endsWith(QLatin1String("/")));
|
||||
Q_ASSERT(!to_.endsWith(QLatin1String("/")));
|
||||
ASSERT(!from_.endsWith(QLatin1String("/")));
|
||||
ASSERT(!to_.endsWith(QLatin1String("/")));
|
||||
QString from = from_ + QLatin1String("/");
|
||||
QString to = to_ + QLatin1String("/");
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include "checksums.h"
|
||||
#include "syncengine.h"
|
||||
#include "propagateremotedelete.h"
|
||||
#include "asserts.h"
|
||||
|
||||
#include <json.h>
|
||||
#include <QNetworkAccessManager>
|
||||
@@ -224,7 +225,9 @@ void PropagateUploadFileCommon::slotComputeContentChecksum()
|
||||
// change during the checksum calculation
|
||||
_item->_modtime = FileSystem::getModTime(filePath);
|
||||
|
||||
#ifdef WITH_TESTING
|
||||
_stopWatch.start();
|
||||
#endif
|
||||
|
||||
QByteArray checksumType = contentChecksumType();
|
||||
|
||||
@@ -251,8 +254,10 @@ void PropagateUploadFileCommon::slotComputeTransmissionChecksum(const QByteArray
|
||||
_item->_contentChecksum = contentChecksum;
|
||||
_item->_contentChecksumType = contentChecksumType;
|
||||
|
||||
#ifdef WITH_TESTING
|
||||
_stopWatch.addLapTime(QLatin1String("ContentChecksum"));
|
||||
_stopWatch.start();
|
||||
#endif
|
||||
|
||||
// Reuse the content checksum as the transmission checksum if possible
|
||||
const auto supportedTransmissionChecksums =
|
||||
@@ -299,7 +304,9 @@ void PropagateUploadFileCommon::slotStartUpload(const QByteArray& transmissionCh
|
||||
done(SyncFileItem::SoftError, tr("File Removed"));
|
||||
return;
|
||||
}
|
||||
#ifdef WITH_TESTING
|
||||
_stopWatch.addLapTime(QLatin1String("TransmissionChecksum"));
|
||||
#endif
|
||||
|
||||
time_t prevModtime = _item->_modtime; // the _item value was set in PropagateUploadFile::start()
|
||||
// but a potential checksum calculation could have taken some time during which the file could
|
||||
@@ -369,7 +376,7 @@ bool UploadDevice::prepareAndOpen(const QString& fileName, qint64 start, qint64
|
||||
|
||||
|
||||
qint64 UploadDevice::writeData(const char* , qint64 ) {
|
||||
Q_ASSERT(!"write to read only device");
|
||||
ASSERT(false, "write to read only device");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -480,7 +487,7 @@ void PropagateUploadFileCommon::startPollJob(const QString& path)
|
||||
void PropagateUploadFileCommon::slotPollFinished()
|
||||
{
|
||||
PollJob *job = qobject_cast<PollJob *>(sender());
|
||||
Q_ASSERT(job);
|
||||
ASSERT(job);
|
||||
|
||||
propagator()->_activeJobList.removeOne(this);
|
||||
|
||||
@@ -569,7 +576,6 @@ QMap<QByteArray, QByteArray> PropagateUploadFileCommon::headers()
|
||||
|
||||
void PropagateUploadFileCommon::finalize()
|
||||
{
|
||||
_item->_requestDuration = _duration.elapsed();
|
||||
_finished = true;
|
||||
|
||||
if (!propagator()->_journal->setFileRecord(SyncJournalFileRecord(*_item, propagator()->getFilePath(_item->_file)))) {
|
||||
|
||||
@@ -183,13 +183,14 @@ class PropagateUploadFileCommon : public PropagateItemJob {
|
||||
Q_OBJECT
|
||||
|
||||
protected:
|
||||
QElapsedTimer _duration;
|
||||
QVector<AbstractNetworkJob*> _jobs; /// network jobs that are currently in transit
|
||||
bool _finished; /// Tells that all the jobs have been finished
|
||||
bool _deleteExisting;
|
||||
bool _finished BITFIELD(1); /// Tells that all the jobs have been finished
|
||||
bool _deleteExisting BITFIELD(1);
|
||||
|
||||
// measure the performance of checksum calc and upload
|
||||
#ifdef WITH_TESTING
|
||||
Utility::StopWatch _stopWatch;
|
||||
#endif
|
||||
|
||||
QByteArray _transmissionChecksum;
|
||||
QByteArray _transmissionChecksumType;
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
#include "syncengine.h"
|
||||
#include "propagateremotemove.h"
|
||||
#include "propagateremotedelete.h"
|
||||
|
||||
#include "asserts.h"
|
||||
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QFileInfo>
|
||||
@@ -80,7 +80,6 @@ QUrl PropagateUploadFileNG::chunkUrl(int chunk)
|
||||
|
||||
void PropagateUploadFileNG::doStartUpload()
|
||||
{
|
||||
_duration.start();
|
||||
propagator()->_activeJobList.append(this);
|
||||
|
||||
const SyncJournalDb::UploadInfo progressInfo = propagator()->_journal->getUploadInfo(_item->_file);
|
||||
@@ -98,6 +97,12 @@ void PropagateUploadFileNG::doStartUpload()
|
||||
this, SLOT(slotPropfindIterate(QString,QMap<QString,QString>)));
|
||||
job->start();
|
||||
return;
|
||||
} else if (progressInfo._valid) {
|
||||
// The upload info is stale. remove the stale chunks on the server
|
||||
_transferId = progressInfo._transferid;
|
||||
// Fire and forget. Any error will be ignored.
|
||||
(new DeleteJob(propagator()->account(), chunkUrl(), this))->start();
|
||||
// startNewUpload will reset the _transferId and the UploadInfo in the db.
|
||||
}
|
||||
|
||||
startNewUpload();
|
||||
@@ -183,7 +188,7 @@ void PropagateUploadFileNG::slotPropfindFinishedWithError()
|
||||
void PropagateUploadFileNG::slotDeleteJobFinished()
|
||||
{
|
||||
auto job = qobject_cast<DeleteJob *>(sender());
|
||||
Q_ASSERT(job);
|
||||
ASSERT(job);
|
||||
_jobs.remove(_jobs.indexOf(job));
|
||||
|
||||
QNetworkReply::NetworkError err = job->reply()->error();
|
||||
@@ -215,7 +220,7 @@ void PropagateUploadFileNG::slotDeleteJobFinished()
|
||||
|
||||
void PropagateUploadFileNG::startNewUpload()
|
||||
{
|
||||
Q_ASSERT(propagator()->_activeJobList.count(this) == 1);
|
||||
ASSERT(propagator()->_activeJobList.count(this) == 1);
|
||||
_transferId = qrand() ^ _item->_modtime ^ (_item->_size << 16) ^ qHash(_item->_file);
|
||||
_sent = 0;
|
||||
_currentChunk = 0;
|
||||
@@ -265,11 +270,12 @@ void PropagateUploadFileNG::startNextChunk()
|
||||
return;
|
||||
|
||||
quint64 fileSize = _item->_size;
|
||||
Q_ASSERT(fileSize >= _sent);
|
||||
ENFORCE(fileSize >= _sent, "Sent data exceeds file size");
|
||||
|
||||
quint64 currentChunkSize = qMin(chunkSize(), fileSize - _sent);
|
||||
|
||||
if (currentChunkSize == 0) {
|
||||
Q_ASSERT(_jobs.isEmpty()); // There should be no running job anymore
|
||||
ASSERT(_jobs.isEmpty());
|
||||
_finished = true;
|
||||
// Finish with a MOVE
|
||||
QString destination = QDir::cleanPath(propagator()->account()->url().path() + QLatin1Char('/')
|
||||
@@ -338,7 +344,8 @@ void PropagateUploadFileNG::startNextChunk()
|
||||
void PropagateUploadFileNG::slotPutFinished()
|
||||
{
|
||||
PUTFileJob *job = qobject_cast<PUTFileJob *>(sender());
|
||||
Q_ASSERT(job);
|
||||
ASSERT(job);
|
||||
|
||||
slotJobDestroyed(job); // remove it from the _jobs list
|
||||
|
||||
qDebug() << job->reply()->request().url() << "FINISHED WITH STATUS"
|
||||
@@ -386,7 +393,7 @@ void PropagateUploadFileNG::slotPutFinished()
|
||||
return;
|
||||
}
|
||||
|
||||
Q_ASSERT(_sent <= _item->_size);
|
||||
ENFORCE(_sent <= _item->_size, "can't send more than size");
|
||||
bool finished = _sent == _item->_size;
|
||||
|
||||
// Check if the file still exists
|
||||
@@ -478,14 +485,16 @@ void PropagateUploadFileNG::slotMoveJobFinished()
|
||||
}
|
||||
_item->_responseTimeStamp = job->responseTimestamp();
|
||||
|
||||
#ifdef WITH_TESTING
|
||||
// performance logging
|
||||
_item->_requestDuration = _stopWatch.stop();
|
||||
quint64 duration = _stopWatch.stop();
|
||||
qDebug() << "*==* duration UPLOAD" << _item->_size
|
||||
<< _stopWatch.durationOfLap(QLatin1String("ContentChecksum"))
|
||||
<< _stopWatch.durationOfLap(QLatin1String("TransmissionChecksum"))
|
||||
<< _item->_requestDuration;
|
||||
<< duration;
|
||||
// The job might stay alive for the whole sync, release this tiny bit of memory.
|
||||
_stopWatch.reset();
|
||||
#endif
|
||||
finalize();
|
||||
}
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include "checksums.h"
|
||||
#include "syncengine.h"
|
||||
#include "propagateremotedelete.h"
|
||||
#include "asserts.h"
|
||||
|
||||
#include <json.h>
|
||||
#include <QNetworkAccessManager>
|
||||
@@ -49,7 +50,6 @@ void PropagateUploadFileV1::doStartUpload()
|
||||
}
|
||||
|
||||
_currentChunk = 0;
|
||||
_duration.start();
|
||||
|
||||
emit progress(*_item, 0);
|
||||
startNextChunk();
|
||||
@@ -172,7 +172,8 @@ void PropagateUploadFileV1::startNextChunk()
|
||||
void PropagateUploadFileV1::slotPutFinished()
|
||||
{
|
||||
PUTFileJob *job = qobject_cast<PUTFileJob *>(sender());
|
||||
Q_ASSERT(job);
|
||||
ASSERT(job);
|
||||
|
||||
slotJobDestroyed(job); // remove it from the _jobs list
|
||||
|
||||
qDebug() << Q_FUNC_INFO << job->reply()->request().url() << "FINISHED WITH STATUS"
|
||||
@@ -340,14 +341,16 @@ void PropagateUploadFileV1::slotPutFinished()
|
||||
done(SyncFileItem::SoftError, "Server does not support X-OC-MTime");
|
||||
}
|
||||
|
||||
#ifdef WITH_TESTING
|
||||
// performance logging
|
||||
_item->_requestDuration = _stopWatch.stop();
|
||||
quint64 duration = _stopWatch.stop();
|
||||
qDebug() << "*==* duration UPLOAD" << _item->_size
|
||||
<< _stopWatch.durationOfLap(QLatin1String("ContentChecksum"))
|
||||
<< _stopWatch.durationOfLap(QLatin1String("TransmissionChecksum"))
|
||||
<< _item->_requestDuration;
|
||||
<< duration;
|
||||
// The job might stay alive for the whole sync, release this tiny bit of memory.
|
||||
_stopWatch.reset();
|
||||
#endif
|
||||
|
||||
finalize();
|
||||
}
|
||||
|
||||
@@ -23,6 +23,8 @@
|
||||
#include "syncfilestatus.h"
|
||||
#include "csync_private.h"
|
||||
#include "filesystem.h"
|
||||
#include "propagateremotedelete.h"
|
||||
#include "asserts.h"
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
#include <windows.h>
|
||||
@@ -75,13 +77,14 @@ SyncEngine::SyncEngine(AccountPtr account, const QString& localPath,
|
||||
, _anotherSyncNeeded(NoFollowUpSync)
|
||||
{
|
||||
qRegisterMetaType<SyncFileItem>("SyncFileItem");
|
||||
qRegisterMetaType<SyncFileItemPtr>("SyncFileItemPtr");
|
||||
qRegisterMetaType<SyncFileItem::Status>("SyncFileItem::Status");
|
||||
qRegisterMetaType<SyncFileStatus>("SyncFileStatus");
|
||||
qRegisterMetaType<SyncFileItemVector>("SyncFileItemVector");
|
||||
qRegisterMetaType<SyncFileItem::Direction>("SyncFileItem::Direction");
|
||||
|
||||
// Everything in the SyncEngine expects a trailing slash for the localPath.
|
||||
Q_ASSERT(localPath.endsWith(QLatin1Char('/')));
|
||||
ASSERT(localPath.endsWith(QLatin1Char('/')));
|
||||
|
||||
csync_create(&_csync_ctx, localPath.toUtf8().data());
|
||||
|
||||
@@ -265,11 +268,11 @@ bool SyncEngine::checkErrorBlacklisting( SyncFileItem &item )
|
||||
return true;
|
||||
}
|
||||
|
||||
void SyncEngine::deleteStaleDownloadInfos()
|
||||
void SyncEngine::deleteStaleDownloadInfos(const SyncFileItemVector &syncItems)
|
||||
{
|
||||
// Find all downloadinfo paths that we want to preserve.
|
||||
QSet<QString> download_file_paths;
|
||||
foreach(const SyncFileItemPtr &it, _syncedItems) {
|
||||
foreach(const SyncFileItemPtr &it, syncItems) {
|
||||
if (it->_direction == SyncFileItem::Down
|
||||
&& it->_type == SyncFileItem::File)
|
||||
{
|
||||
@@ -287,11 +290,11 @@ void SyncEngine::deleteStaleDownloadInfos()
|
||||
}
|
||||
}
|
||||
|
||||
void SyncEngine::deleteStaleUploadInfos()
|
||||
void SyncEngine::deleteStaleUploadInfos(const SyncFileItemVector &syncItems)
|
||||
{
|
||||
// Find all blacklisted paths that we want to preserve.
|
||||
QSet<QString> upload_file_paths;
|
||||
foreach(const SyncFileItemPtr &it, _syncedItems) {
|
||||
foreach(const SyncFileItemPtr &it, syncItems) {
|
||||
if (it->_direction == SyncFileItem::Up
|
||||
&& it->_type == SyncFileItem::File)
|
||||
{
|
||||
@@ -300,14 +303,23 @@ void SyncEngine::deleteStaleUploadInfos()
|
||||
}
|
||||
|
||||
// Delete from journal.
|
||||
_journal->deleteStaleUploadInfos(upload_file_paths);
|
||||
auto ids = _journal->deleteStaleUploadInfos(upload_file_paths);
|
||||
|
||||
// Delete the stales chunk on the server.
|
||||
if (account()->capabilities().chunkingNg()) {
|
||||
foreach (uint transferId, ids) {
|
||||
QUrl url = Utility::concatUrlPath(account()->url(), QLatin1String("remote.php/dav/uploads/")
|
||||
+ account()->davUser() + QLatin1Char('/') + QString::number(transferId));
|
||||
(new DeleteJob(account(), url, this))->start();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SyncEngine::deleteStaleErrorBlacklistEntries()
|
||||
void SyncEngine::deleteStaleErrorBlacklistEntries(const SyncFileItemVector &syncItems)
|
||||
{
|
||||
// Find all blacklisted paths that we want to preserve.
|
||||
QSet<QString> blacklist_file_paths;
|
||||
foreach(const SyncFileItemPtr &it, _syncedItems) {
|
||||
foreach(const SyncFileItemPtr &it, syncItems) {
|
||||
if (it->_hasBlacklistEntry)
|
||||
blacklist_file_paths.insert(it->_file);
|
||||
}
|
||||
@@ -342,7 +354,7 @@ int SyncEngine::treewalkFile( TREE_WALK_FILE *file, bool remote )
|
||||
|
||||
QTextCodec::ConverterState utf8State;
|
||||
static QTextCodec *codec = QTextCodec::codecForName("UTF-8");
|
||||
Q_ASSERT(codec);
|
||||
ASSERT(codec);
|
||||
QString fileUtf8 = codec->toUnicode(file->path, qstrlen(file->path), &utf8State);
|
||||
QString renameTarget;
|
||||
QString key = fileUtf8;
|
||||
@@ -378,9 +390,11 @@ int SyncEngine::treewalkFile( TREE_WALK_FILE *file, bool remote )
|
||||
item->_modtime = file->modtime;
|
||||
} else {
|
||||
if (instruction != CSYNC_INSTRUCTION_NONE) {
|
||||
qDebug() << "ERROR: Instruction" << item->_instruction << "vs" << instruction << "for" << fileUtf8;
|
||||
Q_ASSERT(!"Instructions are both unequal NONE");
|
||||
return -1;
|
||||
qWarning() << "ERROR: Instruction" << item->_instruction << "vs" << instruction << "for" << fileUtf8;
|
||||
ASSERT(false);
|
||||
// Set instruction to NONE for safety.
|
||||
file->instruction = item->_instruction = instruction = CSYNC_INSTRUCTION_NONE;
|
||||
return -1; // should lead to treewalk error
|
||||
}
|
||||
}
|
||||
|
||||
@@ -395,6 +409,8 @@ int SyncEngine::treewalkFile( TREE_WALK_FILE *file, bool remote )
|
||||
}
|
||||
if (file->remotePerm && file->remotePerm[0]) {
|
||||
item->_remotePerm = QByteArray(file->remotePerm);
|
||||
if (remote)
|
||||
_remotePerms[item->_file] = item->_remotePerm;
|
||||
}
|
||||
|
||||
/* The flag "serverHasIgnoredFiles" is true if item in question is a directory
|
||||
@@ -425,10 +441,6 @@ int SyncEngine::treewalkFile( TREE_WALK_FILE *file, bool remote )
|
||||
_seenFiles.insert(renameTarget);
|
||||
}
|
||||
|
||||
if (remote && file->remotePerm && file->remotePerm[0]) {
|
||||
_remotePerms[item->_file] = file->remotePerm;
|
||||
}
|
||||
|
||||
switch(file->error_status) {
|
||||
case CSYNC_STATUS_OK:
|
||||
break;
|
||||
@@ -490,7 +502,7 @@ int SyncEngine::treewalkFile( TREE_WALK_FILE *file, bool remote )
|
||||
item->_status = SyncFileItem::SoftError;
|
||||
break;
|
||||
default:
|
||||
Q_ASSERT("Non handled error-status");
|
||||
ASSERT(false, "Non handled error-status");
|
||||
/* No error string */
|
||||
}
|
||||
|
||||
@@ -641,12 +653,6 @@ int SyncEngine::treewalkFile( TREE_WALK_FILE *file, bool remote )
|
||||
|
||||
_needsUpdate = true;
|
||||
|
||||
item->log._etag = file->etag;
|
||||
item->log._fileId = file->file_id;
|
||||
item->log._instruction = file->instruction;
|
||||
item->log._modtime = file->modtime;
|
||||
item->log._size = file->size;
|
||||
|
||||
item->log._other_etag = file->other.etag;
|
||||
item->log._other_fileId = file->other.file_id;
|
||||
item->log._other_instruction = file->other.instruction;
|
||||
@@ -706,8 +712,11 @@ void SyncEngine::startSync()
|
||||
}
|
||||
}
|
||||
|
||||
Q_ASSERT(!s_anySyncRunning);
|
||||
Q_ASSERT(!_syncRunning);
|
||||
if (s_anySyncRunning || _syncRunning) {
|
||||
ASSERT(false);
|
||||
return;
|
||||
}
|
||||
|
||||
s_anySyncRunning = true;
|
||||
_syncRunning = true;
|
||||
_anotherSyncNeeded = NoFollowUpSync;
|
||||
@@ -742,7 +751,6 @@ void SyncEngine::startSync()
|
||||
qDebug() << "Could not determine free space available at" << _localPath;
|
||||
}
|
||||
|
||||
_syncedItems.clear();
|
||||
_syncItemMap.clear();
|
||||
_needsUpdate = false;
|
||||
|
||||
@@ -889,6 +897,8 @@ void SyncEngine::slotDiscoveryJobFinished(int discoveryResult)
|
||||
_hasForwardInTimeFiles = false;
|
||||
_backInTimeFiles = 0;
|
||||
bool walkOk = true;
|
||||
_remotePerms.clear();
|
||||
_remotePerms.reserve(c_rbtree_size(_csync_ctx->remote.tree));
|
||||
_seenFiles.clear();
|
||||
_temporarilyUnavailablePaths.clear();
|
||||
_renamedFolders.clear();
|
||||
@@ -910,12 +920,12 @@ void SyncEngine::slotDiscoveryJobFinished(int discoveryResult)
|
||||
csync_commit(_csync_ctx);
|
||||
|
||||
// The map was used for merging trees, convert it to a list:
|
||||
_syncedItems = _syncItemMap.values().toVector();
|
||||
SyncFileItemVector syncItems = _syncItemMap.values().toVector();
|
||||
_syncItemMap.clear(); // free memory
|
||||
|
||||
// Adjust the paths for the renames.
|
||||
for (SyncFileItemVector::iterator it = _syncedItems.begin();
|
||||
it != _syncedItems.end(); ++it) {
|
||||
for (SyncFileItemVector::iterator it = syncItems.begin();
|
||||
it != syncItems.end(); ++it) {
|
||||
(*it)->_file = adjustRenamedPath((*it)->_file);
|
||||
}
|
||||
|
||||
@@ -923,7 +933,7 @@ void SyncEngine::slotDiscoveryJobFinished(int discoveryResult)
|
||||
if (_account->serverVersionInt() < 0x080100) {
|
||||
// Server version older than 8.1 don't support these character in filename.
|
||||
static const QRegExp invalidCharRx("[\\\\:?*\"<>|]");
|
||||
for (auto it = _syncedItems.begin(); it != _syncedItems.end(); ++it) {
|
||||
for (auto it = syncItems.begin(); it != syncItems.end(); ++it) {
|
||||
if ((*it)->_direction == SyncFileItem::Up &&
|
||||
(*it)->destination().contains(invalidCharRx)) {
|
||||
(*it)->_errorString = tr("File name contains at least one invalid character");
|
||||
@@ -935,7 +945,7 @@ void SyncEngine::slotDiscoveryJobFinished(int discoveryResult)
|
||||
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);
|
||||
emit aboutToRemoveAllFiles(syncItems.first()->_direction, &cancel);
|
||||
if (cancel) {
|
||||
qDebug() << Q_FUNC_INFO << "Abort sync";
|
||||
finalize(false);
|
||||
@@ -950,7 +960,7 @@ void SyncEngine::slotDiscoveryJobFinished(int discoveryResult)
|
||||
if (!databaseFingerprint.isNull()
|
||||
&& _discoveryMainThread->_dataFingerprint != databaseFingerprint) {
|
||||
qDebug() << "data fingerprint changed, assume restore from backup" << databaseFingerprint << _discoveryMainThread->_dataFingerprint;
|
||||
restoreOldFiles();
|
||||
restoreOldFiles(syncItems);
|
||||
} else if (!_hasForwardInTimeFiles && _backInTimeFiles >= 2 && _account->serverVersionInt() < 0x090100) {
|
||||
// The server before ownCloud 9.1 did not have the data-fingerprint property. So in that
|
||||
// case we use heuristics to detect restored backup. This is disabled with newer version
|
||||
@@ -960,18 +970,18 @@ void SyncEngine::slotDiscoveryJobFinished(int discoveryResult)
|
||||
bool restore = false;
|
||||
emit aboutToRestoreBackup(&restore);
|
||||
if (restore) {
|
||||
restoreOldFiles();
|
||||
restoreOldFiles(syncItems);
|
||||
}
|
||||
}
|
||||
|
||||
// Sort items per destination
|
||||
std::sort(_syncedItems.begin(), _syncedItems.end());
|
||||
std::sort(syncItems.begin(), syncItems.end());
|
||||
|
||||
// make sure everything is allowed
|
||||
checkForPermission();
|
||||
checkForPermission(syncItems);
|
||||
|
||||
// To announce the beginning of the sync
|
||||
emit aboutToPropagate(_syncedItems);
|
||||
emit aboutToPropagate(syncItems);
|
||||
// it's important to do this before ProgressInfo::start(), to announce start of new sync
|
||||
emit transmissionProgress(*_progressInfo);
|
||||
_progressInfo->startEstimateUpdates();
|
||||
@@ -993,8 +1003,8 @@ void SyncEngine::slotDiscoveryJobFinished(int discoveryResult)
|
||||
|
||||
_propagator = QSharedPointer<OwncloudPropagator>(
|
||||
new OwncloudPropagator (_account, _localPath, _remotePath, _journal));
|
||||
connect(_propagator.data(), SIGNAL(itemCompleted(const SyncFileItem &, const PropagatorJob &)),
|
||||
this, SLOT(slotItemCompleted(const SyncFileItem &, const PropagatorJob &)));
|
||||
connect(_propagator.data(), SIGNAL(itemCompleted(const SyncFileItemPtr &)),
|
||||
this, SLOT(slotItemCompleted(const SyncFileItemPtr &)));
|
||||
connect(_propagator.data(), SIGNAL(progress(const SyncFileItem &,quint64)),
|
||||
this, SLOT(slotProgress(const SyncFileItem &,quint64)));
|
||||
connect(_propagator.data(), SIGNAL(finished(bool)), this, SLOT(slotFinished(bool)), Qt::QueuedConnection);
|
||||
@@ -1004,16 +1014,16 @@ void SyncEngine::slotDiscoveryJobFinished(int discoveryResult)
|
||||
// apply the network limits to the propagator
|
||||
setNetworkLimits(_uploadLimit, _downloadLimit);
|
||||
|
||||
deleteStaleDownloadInfos();
|
||||
deleteStaleUploadInfos();
|
||||
deleteStaleErrorBlacklistEntries();
|
||||
deleteStaleDownloadInfos(syncItems);
|
||||
deleteStaleUploadInfos(syncItems);
|
||||
deleteStaleErrorBlacklistEntries(syncItems);
|
||||
_journal->commit("post stale entry removal");
|
||||
|
||||
// Emit the started signal only after the propagator has been set up.
|
||||
if (_needsUpdate)
|
||||
emit(started());
|
||||
|
||||
_propagator->start(_syncedItems);
|
||||
_propagator->start(syncItems);
|
||||
|
||||
qDebug() << "<<#### Post-Reconcile end #################################################### " << _stopWatch.addLapTime(QLatin1String("Post-Reconcile Finished"));
|
||||
}
|
||||
@@ -1050,19 +1060,19 @@ void SyncEngine::setNetworkLimits(int upload, int download)
|
||||
}
|
||||
}
|
||||
|
||||
void SyncEngine::slotItemCompleted(const SyncFileItem &item, const PropagatorJob &job)
|
||||
void SyncEngine::slotItemCompleted(const SyncFileItemPtr &item)
|
||||
{
|
||||
const char * instruction_str = csync_instruction_str(item._instruction);
|
||||
qDebug() << Q_FUNC_INFO << item._file << instruction_str << item._status << item._errorString;
|
||||
const char * instruction_str = csync_instruction_str(item->_instruction);
|
||||
qDebug() << Q_FUNC_INFO << item->_file << instruction_str << item->_status << item->_errorString;
|
||||
|
||||
_progressInfo->setProgressComplete(item);
|
||||
_progressInfo->setProgressComplete(*item);
|
||||
|
||||
if (item._status == SyncFileItem::FatalError) {
|
||||
emit csyncError(item._errorString);
|
||||
if (item->_status == SyncFileItem::FatalError) {
|
||||
emit csyncError(item->_errorString);
|
||||
}
|
||||
|
||||
emit transmissionProgress(*_progressInfo);
|
||||
emit itemCompleted(item, job);
|
||||
emit itemCompleted(item);
|
||||
}
|
||||
|
||||
void SyncEngine::slotFinished(bool success)
|
||||
@@ -1086,7 +1096,6 @@ void SyncEngine::slotFinished(bool success)
|
||||
// files needed propagation
|
||||
emit transmissionProgress(*_progressInfo);
|
||||
|
||||
emit treeWalkResult(_syncedItems);
|
||||
finalize(success);
|
||||
}
|
||||
|
||||
@@ -1107,6 +1116,10 @@ void SyncEngine::finalize(bool success)
|
||||
|
||||
// Delete the propagator only after emitting the signal.
|
||||
_propagator.clear();
|
||||
_remotePerms.clear();
|
||||
_seenFiles.clear();
|
||||
_temporarilyUnavailablePaths.clear();
|
||||
_renamedFolders.clear();
|
||||
|
||||
_clearTouchedFilesTimer.start();
|
||||
}
|
||||
@@ -1136,13 +1149,13 @@ QString SyncEngine::adjustRenamedPath(const QString& original)
|
||||
* Make sure that we are allowed to do what we do by checking the permissions and the selective sync list
|
||||
*
|
||||
*/
|
||||
void SyncEngine::checkForPermission()
|
||||
void SyncEngine::checkForPermission(SyncFileItemVector &syncItems)
|
||||
{
|
||||
bool selectiveListOk;
|
||||
auto selectiveSyncBlackList = _journal->getSelectiveSyncList(SyncJournalDb::SelectiveSyncBlackList, &selectiveListOk);
|
||||
std::sort(selectiveSyncBlackList.begin(), selectiveSyncBlackList.end());
|
||||
|
||||
for (SyncFileItemVector::iterator it = _syncedItems.begin(); it != _syncedItems.end(); ++it) {
|
||||
for (SyncFileItemVector::iterator it = syncItems.begin(); it != syncItems.end(); ++it) {
|
||||
if ((*it)->_direction != SyncFileItem::Up) {
|
||||
// Currently we only check server-side permissions
|
||||
continue;
|
||||
@@ -1159,7 +1172,7 @@ void SyncEngine::checkForPermission()
|
||||
(*it)->_errorString = tr("Ignored because of the \"choose what to sync\" blacklist");
|
||||
|
||||
if ((*it)->_isDirectory) {
|
||||
for (SyncFileItemVector::iterator it_next = it + 1; it_next != _syncedItems.end() && (*it_next)->_file.startsWith(path); ++it_next) {
|
||||
for (SyncFileItemVector::iterator it_next = it + 1; it_next != syncItems.end() && (*it_next)->_file.startsWith(path); ++it_next) {
|
||||
it = it_next;
|
||||
(*it)->_instruction = CSYNC_INSTRUCTION_IGNORE;
|
||||
(*it)->_status = SyncFileItem::FileIgnored;
|
||||
@@ -1184,7 +1197,7 @@ void SyncEngine::checkForPermission()
|
||||
(*it)->_status = SyncFileItem::NormalError;
|
||||
(*it)->_errorString = tr("Not allowed because you don't have permission to add subfolders to that folder");
|
||||
|
||||
for (SyncFileItemVector::iterator it_next = it + 1; it_next != _syncedItems.end() && (*it_next)->destination().startsWith(path); ++it_next) {
|
||||
for (SyncFileItemVector::iterator it_next = it + 1; it_next != syncItems.end() && (*it_next)->destination().startsWith(path); ++it_next) {
|
||||
it = it_next;
|
||||
if ((*it)->_instruction == CSYNC_INSTRUCTION_RENAME) {
|
||||
// The file was most likely moved in this directory.
|
||||
@@ -1244,7 +1257,7 @@ void SyncEngine::checkForPermission()
|
||||
if ((*it)->_isDirectory) {
|
||||
// restore all sub items
|
||||
for (SyncFileItemVector::iterator it_next = it + 1;
|
||||
it_next != _syncedItems.end() && (*it_next)->_file.startsWith(path); ++it_next) {
|
||||
it_next != syncItems.end() && (*it_next)->_file.startsWith(path); ++it_next) {
|
||||
it = it_next;
|
||||
|
||||
if ((*it)->_instruction != CSYNC_INSTRUCTION_REMOVE) {
|
||||
@@ -1270,12 +1283,12 @@ void SyncEngine::checkForPermission()
|
||||
// underneath, propagator sees that.
|
||||
if( (*it)->_isDirectory ) {
|
||||
// put a more descriptive message if a top level share dir really is removed.
|
||||
if( it == _syncedItems.begin() || !(path.startsWith((*(it-1))->_file)) ) {
|
||||
if( it == syncItems.begin() || !(path.startsWith((*(it-1))->_file)) ) {
|
||||
(*it)->_errorString = tr("Local files and share folder removed.");
|
||||
}
|
||||
|
||||
for (SyncFileItemVector::iterator it_next = it + 1;
|
||||
it_next != _syncedItems.end() && (*it_next)->_file.startsWith(path); ++it_next) {
|
||||
it_next != syncItems.end() && (*it_next)->_file.startsWith(path); ++it_next) {
|
||||
it = it_next;
|
||||
}
|
||||
}
|
||||
@@ -1354,7 +1367,7 @@ void SyncEngine::checkForPermission()
|
||||
|
||||
if ((*it)->_isDirectory) {
|
||||
for (SyncFileItemVector::iterator it_next = it + 1;
|
||||
it_next != _syncedItems.end() && (*it_next)->destination().startsWith(path); ++it_next) {
|
||||
it_next != syncItems.end() && (*it_next)->destination().startsWith(path); ++it_next) {
|
||||
it = it_next;
|
||||
(*it)->_instruction = CSYNC_INSTRUCTION_ERROR;
|
||||
(*it)->_status = SyncFileItem::NormalError;
|
||||
@@ -1383,7 +1396,7 @@ QByteArray SyncEngine::getPermissions(const QString& file) const
|
||||
return _remotePerms.value(file);
|
||||
}
|
||||
|
||||
void SyncEngine::restoreOldFiles()
|
||||
void SyncEngine::restoreOldFiles(SyncFileItemVector &syncItems)
|
||||
{
|
||||
/* 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
|
||||
@@ -1391,7 +1404,7 @@ void SyncEngine::restoreOldFiles()
|
||||
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) {
|
||||
for (auto it = syncItems.begin(); it != syncItems.end(); ++it) {
|
||||
if ((*it)->_direction != SyncFileItem::Down)
|
||||
continue;
|
||||
|
||||
|
||||
@@ -47,7 +47,6 @@ namespace OCC {
|
||||
class SyncJournalFileRecord;
|
||||
class SyncJournalDb;
|
||||
class OwncloudPropagator;
|
||||
class PropagatorJob;
|
||||
|
||||
enum AnotherSyncNeeded
|
||||
{
|
||||
@@ -119,10 +118,7 @@ signals:
|
||||
void aboutToPropagate(SyncFileItemVector&);
|
||||
|
||||
// after each item completed by a job (successful or not)
|
||||
void itemCompleted(const SyncFileItem&, const PropagatorJob&);
|
||||
|
||||
// after sync is done
|
||||
void treeWalkResult(const SyncFileItemVector&);
|
||||
void itemCompleted(const SyncFileItemPtr&);
|
||||
|
||||
void transmissionProgress( const ProgressInfo& progress );
|
||||
|
||||
@@ -153,7 +149,7 @@ signals:
|
||||
|
||||
private slots:
|
||||
void slotRootEtagReceived(const QString &);
|
||||
void slotItemCompleted(const SyncFileItem& item, const PropagatorJob & job);
|
||||
void slotItemCompleted(const SyncFileItemPtr& item);
|
||||
void slotFinished(bool success);
|
||||
void slotProgress(const SyncFileItem& item, quint64 curent);
|
||||
void slotDiscoveryJobFinished(int updateResult);
|
||||
@@ -177,13 +173,13 @@ private:
|
||||
|
||||
// Cleans up unnecessary downloadinfo entries in the journal as well
|
||||
// as their temporary files.
|
||||
void deleteStaleDownloadInfos();
|
||||
void deleteStaleDownloadInfos(const SyncFileItemVector &syncItems);
|
||||
|
||||
// Removes stale uploadinfos from the journal.
|
||||
void deleteStaleUploadInfos();
|
||||
void deleteStaleUploadInfos(const SyncFileItemVector &syncItems);
|
||||
|
||||
// Removes stale error blacklist entries from the journal.
|
||||
void deleteStaleErrorBlacklistEntries();
|
||||
void deleteStaleErrorBlacklistEntries(const SyncFileItemVector &syncItems);
|
||||
|
||||
// cleanup and emit the finished signal
|
||||
void finalize(bool success);
|
||||
@@ -193,10 +189,6 @@ private:
|
||||
// Must only be acessed during update and reconcile
|
||||
QMap<QString, SyncFileItemPtr> _syncItemMap;
|
||||
|
||||
// should be called _syncItems (present tense). It's the items from the _syncItemMap but
|
||||
// sorted and re-adjusted based on permissions.
|
||||
SyncFileItemVector _syncedItems;
|
||||
|
||||
AccountPtr _account;
|
||||
CSYNC *_csync_ctx;
|
||||
bool _needsUpdate;
|
||||
@@ -238,13 +230,13 @@ private:
|
||||
* check if we are allowed to propagate everything, and if we are not, adjust the instructions
|
||||
* to recover
|
||||
*/
|
||||
void checkForPermission();
|
||||
void checkForPermission(SyncFileItemVector &syncItems);
|
||||
QByteArray getPermissions(const QString& file) const;
|
||||
|
||||
/**
|
||||
* Instead of downloading files from the server, upload the files to the server
|
||||
*/
|
||||
void restoreOldFiles();
|
||||
void restoreOldFiles(SyncFileItemVector &syncItems);
|
||||
|
||||
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
|
||||
|
||||
@@ -68,7 +68,7 @@ public:
|
||||
_serverHasIgnoredFiles(false), _hasBlacklistEntry(false),
|
||||
_errorMayBeBlacklisted(false), _status(NoStatus),
|
||||
_isRestoration(false),
|
||||
_httpErrorCode(0), _requestDuration(0), _affectedItems(1),
|
||||
_httpErrorCode(0), _affectedItems(1),
|
||||
_instruction(CSYNC_INSTRUCTION_NONE), _modtime(0), _size(0), _inode(0)
|
||||
{
|
||||
}
|
||||
@@ -160,7 +160,6 @@ public:
|
||||
quint16 _httpErrorCode;
|
||||
QString _errorString; // Contains a string only in case of error
|
||||
QByteArray _responseTimeStamp;
|
||||
quint64 _requestDuration;
|
||||
quint32 _affectedItems; // the number of affected items by the operation on this item.
|
||||
// usually this value is 1, but for removes on dirs, it might be much higher.
|
||||
|
||||
@@ -179,15 +178,10 @@ public:
|
||||
QString _directDownloadCookies;
|
||||
|
||||
struct {
|
||||
quint64 _size;
|
||||
time_t _modtime;
|
||||
QByteArray _etag;
|
||||
QByteArray _fileId;
|
||||
quint64 _other_size;
|
||||
time_t _other_modtime;
|
||||
QByteArray _other_etag;
|
||||
QByteArray _other_fileId;
|
||||
enum csync_instructions_e _instruction BITFIELD(16);
|
||||
enum csync_instructions_e _other_instruction BITFIELD(16);
|
||||
} log;
|
||||
};
|
||||
@@ -202,5 +196,6 @@ typedef QVector<SyncFileItemPtr> SyncFileItemVector;
|
||||
}
|
||||
|
||||
Q_DECLARE_METATYPE(OCC::SyncFileItem)
|
||||
Q_DECLARE_METATYPE(OCC::SyncFileItemPtr)
|
||||
|
||||
#endif // SYNCFILEITEM_H
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include "syncengine.h"
|
||||
#include "syncjournaldb.h"
|
||||
#include "syncjournalfilerecord.h"
|
||||
#include "asserts.h"
|
||||
|
||||
namespace OCC {
|
||||
|
||||
@@ -77,8 +78,8 @@ SyncFileStatusTracker::SyncFileStatusTracker(SyncEngine *syncEngine)
|
||||
{
|
||||
connect(syncEngine, SIGNAL(aboutToPropagate(SyncFileItemVector&)),
|
||||
SLOT(slotAboutToPropagate(SyncFileItemVector&)));
|
||||
connect(syncEngine, SIGNAL(itemCompleted(const SyncFileItem&, const PropagatorJob&)),
|
||||
SLOT(slotItemCompleted(const SyncFileItem&)));
|
||||
connect(syncEngine, SIGNAL(itemCompleted(const SyncFileItemPtr&)),
|
||||
SLOT(slotItemCompleted(const SyncFileItemPtr&)));
|
||||
connect(syncEngine, SIGNAL(finished(bool)), SLOT(slotSyncFinished()));
|
||||
connect(syncEngine, SIGNAL(started()), SLOT(slotSyncEngineRunningChanged()));
|
||||
connect(syncEngine, SIGNAL(finished(bool)), SLOT(slotSyncEngineRunningChanged()));
|
||||
@@ -86,7 +87,7 @@ SyncFileStatusTracker::SyncFileStatusTracker(SyncEngine *syncEngine)
|
||||
|
||||
SyncFileStatus SyncFileStatusTracker::fileStatus(const QString& relativePath)
|
||||
{
|
||||
Q_ASSERT(!relativePath.endsWith(QLatin1Char('/')));
|
||||
ASSERT(!relativePath.endsWith(QLatin1Char('/')));
|
||||
|
||||
if (relativePath.isEmpty()) {
|
||||
// This is the root sync folder, it doesn't have an entry in the database and won't be walked by csync, so resolve manually.
|
||||
@@ -121,8 +122,8 @@ SyncFileStatus SyncFileStatusTracker::fileStatus(const QString& relativePath)
|
||||
void SyncFileStatusTracker::slotPathTouched(const QString& fileName)
|
||||
{
|
||||
QString folderPath = _syncEngine->localPath();
|
||||
Q_ASSERT(fileName.startsWith(folderPath));
|
||||
|
||||
ASSERT(fileName.startsWith(folderPath));
|
||||
QString localPath = fileName.mid(folderPath.size());
|
||||
_dirtyPaths.insert(localPath);
|
||||
|
||||
@@ -141,7 +142,7 @@ void SyncFileStatusTracker::incSyncCountAndEmitStatusChanged(const QString &rela
|
||||
|
||||
// We passed from OK to SYNC, increment the parent to keep it marked as
|
||||
// SYNC while we propagate ourselves and our own children.
|
||||
Q_ASSERT(!relativePath.endsWith('/'));
|
||||
ASSERT(!relativePath.endsWith('/'));
|
||||
int lastSlashIndex = relativePath.lastIndexOf('/');
|
||||
if (lastSlashIndex != -1)
|
||||
incSyncCountAndEmitStatusChanged(relativePath.left(lastSlashIndex), UnknownShared);
|
||||
@@ -163,7 +164,7 @@ void SyncFileStatusTracker::decSyncCountAndEmitStatusChanged(const QString &rela
|
||||
emit fileStatusChanged(getSystemDestination(relativePath), status);
|
||||
|
||||
// We passed from SYNC to OK, decrement our parent.
|
||||
Q_ASSERT(!relativePath.endsWith('/'));
|
||||
ASSERT(!relativePath.endsWith('/'));
|
||||
int lastSlashIndex = relativePath.lastIndexOf('/');
|
||||
if (lastSlashIndex != -1)
|
||||
decSyncCountAndEmitStatusChanged(relativePath.left(lastSlashIndex), UnknownShared);
|
||||
@@ -174,7 +175,7 @@ void SyncFileStatusTracker::decSyncCountAndEmitStatusChanged(const QString &rela
|
||||
|
||||
void SyncFileStatusTracker::slotAboutToPropagate(SyncFileItemVector& items)
|
||||
{
|
||||
Q_ASSERT(_syncCount.isEmpty());
|
||||
ASSERT(_syncCount.isEmpty());
|
||||
|
||||
std::map<QString, SyncFileStatus::SyncFileStatusTag> oldProblems;
|
||||
std::swap(_syncProblems, oldProblems);
|
||||
@@ -223,28 +224,28 @@ void SyncFileStatusTracker::slotAboutToPropagate(SyncFileItemVector& items)
|
||||
}
|
||||
}
|
||||
|
||||
void SyncFileStatusTracker::slotItemCompleted(const SyncFileItem &item)
|
||||
void SyncFileStatusTracker::slotItemCompleted(const SyncFileItemPtr &item)
|
||||
{
|
||||
// qDebug() << Q_FUNC_INFO << item.destination() << item._status << item._instruction;
|
||||
|
||||
if (showErrorInSocketApi(item)) {
|
||||
_syncProblems[item._file] = SyncFileStatus::StatusError;
|
||||
invalidateParentPaths(item.destination());
|
||||
} else if (showWarningInSocketApi(item)) {
|
||||
_syncProblems[item._file] = SyncFileStatus::StatusWarning;
|
||||
if (showErrorInSocketApi(*item)) {
|
||||
_syncProblems[item->_file] = SyncFileStatus::StatusError;
|
||||
invalidateParentPaths(item->destination());
|
||||
} else if (showWarningInSocketApi(*item)) {
|
||||
_syncProblems[item->_file] = SyncFileStatus::StatusWarning;
|
||||
} else {
|
||||
_syncProblems.erase(item._file);
|
||||
_syncProblems.erase(item->_file);
|
||||
}
|
||||
|
||||
SharedFlag sharedFlag = item._remotePerm.contains("S") ? Shared : NotShared;
|
||||
if (item._instruction != CSYNC_INSTRUCTION_NONE
|
||||
&& item._instruction != CSYNC_INSTRUCTION_UPDATE_METADATA
|
||||
&& item._instruction != CSYNC_INSTRUCTION_IGNORE
|
||||
&& item._instruction != CSYNC_INSTRUCTION_ERROR) {
|
||||
SharedFlag sharedFlag = item->_remotePerm.contains("S") ? Shared : NotShared;
|
||||
if (item->_instruction != CSYNC_INSTRUCTION_NONE
|
||||
&& item->_instruction != CSYNC_INSTRUCTION_UPDATE_METADATA
|
||||
&& item->_instruction != CSYNC_INSTRUCTION_IGNORE
|
||||
&& item->_instruction != CSYNC_INSTRUCTION_ERROR) {
|
||||
// decSyncCount calls *must* be symetric with incSyncCount calls in slotAboutToPropagate
|
||||
decSyncCountAndEmitStatusChanged(item.destination(), sharedFlag);
|
||||
decSyncCountAndEmitStatusChanged(item->destination(), sharedFlag);
|
||||
} else {
|
||||
emit fileStatusChanged(getSystemDestination(item.destination()), resolveSyncAndErrorStatus(item.destination(), sharedFlag));
|
||||
emit fileStatusChanged(getSystemDestination(item->destination()), resolveSyncAndErrorStatus(item->destination(), sharedFlag));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -277,8 +278,8 @@ SyncFileStatus SyncFileStatusTracker::resolveSyncAndErrorStatus(const QString &r
|
||||
status.set(problemStatus);
|
||||
}
|
||||
|
||||
// The shared status needs to have been fetched from a SyncFileItem or the DB at this point.
|
||||
Q_ASSERT(sharedFlag != UnknownShared);
|
||||
ASSERT(sharedFlag != UnknownShared,
|
||||
"The shared status needs to have been fetched from a SyncFileItem or the DB at this point.");
|
||||
if (sharedFlag == Shared)
|
||||
status.setSharedWithMe(true);
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ signals:
|
||||
|
||||
private slots:
|
||||
void slotAboutToPropagate(SyncFileItemVector& items);
|
||||
void slotItemCompleted(const SyncFileItem& item);
|
||||
void slotItemCompleted(const SyncFileItemPtr& item);
|
||||
void slotSyncFinished();
|
||||
void slotSyncEngineRunningChanged();
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include "utility.h"
|
||||
#include "version.h"
|
||||
#include "filesystem.h"
|
||||
#include "asserts.h"
|
||||
|
||||
#include "../../csync/src/std/c_jhash.h"
|
||||
|
||||
@@ -178,7 +179,7 @@ bool SyncJournalDb::sqlFail( const QString& log, const SqlQuery& query )
|
||||
{
|
||||
commitTransaction();
|
||||
qWarning() << "SQL Error" << log << query.error();
|
||||
Q_ASSERT(!"SQL ERROR");
|
||||
ASSERT(false);
|
||||
_db.close();
|
||||
return false;
|
||||
}
|
||||
@@ -1370,21 +1371,22 @@ void SyncJournalDb::setUploadInfo(const QString& file, const SyncJournalDb::Uplo
|
||||
}
|
||||
}
|
||||
|
||||
bool SyncJournalDb::deleteStaleUploadInfos(const QSet<QString> &keep)
|
||||
QVector<uint> SyncJournalDb::deleteStaleUploadInfos(const QSet<QString> &keep)
|
||||
{
|
||||
QMutexLocker locker(&_mutex);
|
||||
QVector<uint> ids;
|
||||
|
||||
if (!checkConnect()) {
|
||||
return false;
|
||||
return ids;
|
||||
}
|
||||
|
||||
SqlQuery query(_db);
|
||||
query.prepare("SELECT path FROM uploadinfo");
|
||||
query.prepare("SELECT path,transferid FROM uploadinfo");
|
||||
|
||||
if (!query.exec()) {
|
||||
QString err = query.error();
|
||||
qDebug() << "Error creating prepared statement: " << query.lastQuery() << ", Error:" << err;
|
||||
return false;
|
||||
return ids;
|
||||
}
|
||||
|
||||
QStringList superfluousPaths;
|
||||
@@ -1393,10 +1395,12 @@ bool SyncJournalDb::deleteStaleUploadInfos(const QSet<QString> &keep)
|
||||
const QString file = query.stringValue(0);
|
||||
if (!keep.contains(file)) {
|
||||
superfluousPaths.append(file);
|
||||
ids.append(query.intValue(1));
|
||||
}
|
||||
}
|
||||
|
||||
return deleteBatch(*_deleteUploadInfoQuery, superfluousPaths, "uploadinfo");
|
||||
deleteBatch(*_deleteUploadInfoQuery, superfluousPaths, "uploadinfo");
|
||||
return ids;
|
||||
}
|
||||
|
||||
SyncJournalErrorBlacklistRecord SyncJournalDb::errorBlacklistEntry( const QString& file )
|
||||
@@ -1604,7 +1608,7 @@ void SyncJournalDb::setPollInfo(const SyncJournalDb::PollInfo& info)
|
||||
QStringList SyncJournalDb::getSelectiveSyncList(SyncJournalDb::SelectiveSyncListType type, bool *ok )
|
||||
{
|
||||
QStringList result;
|
||||
Q_ASSERT(ok);
|
||||
ASSERT(ok);
|
||||
|
||||
QMutexLocker locker(&_mutex);
|
||||
if( !checkConnect() ) {
|
||||
|
||||
@@ -105,7 +105,8 @@ public:
|
||||
|
||||
UploadInfo getUploadInfo(const QString &file);
|
||||
void setUploadInfo(const QString &file, const UploadInfo &i);
|
||||
bool deleteStaleUploadInfos(const QSet<QString>& keep);
|
||||
// Return the list of transfer ids that were removed.
|
||||
QVector<uint> deleteStaleUploadInfos(const QSet<QString>& keep);
|
||||
|
||||
SyncJournalErrorBlacklistRecord errorBlacklistEntry( const QString& );
|
||||
bool deleteStaleErrorBlacklistEntries(const QSet<QString>& keep);
|
||||
|
||||
@@ -13,19 +13,22 @@
|
||||
*/
|
||||
|
||||
#include "syncresult.h"
|
||||
#include "progressdispatcher.h"
|
||||
|
||||
namespace OCC
|
||||
{
|
||||
|
||||
SyncResult::SyncResult()
|
||||
: _status( Undefined ),
|
||||
_warnCount(0)
|
||||
{
|
||||
}
|
||||
: _status( Undefined )
|
||||
, _foundFilesNotSynced(false)
|
||||
, _folderStructureWasChanged(false)
|
||||
, _numNewItems(0)
|
||||
, _numRemovedItems(0)
|
||||
, _numUpdatedItems(0)
|
||||
, _numRenamedItems(0)
|
||||
, _numConflictItems(0)
|
||||
, _numErrorItems(0)
|
||||
|
||||
SyncResult::SyncResult(SyncResult::Status status )
|
||||
: _status(status),
|
||||
_warnCount(0)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -34,6 +37,11 @@ SyncResult::Status SyncResult::status() const
|
||||
return _status;
|
||||
}
|
||||
|
||||
void SyncResult::reset()
|
||||
{
|
||||
*this = SyncResult();
|
||||
}
|
||||
|
||||
QString SyncResult::statusString() const
|
||||
{
|
||||
QString re;
|
||||
@@ -80,42 +88,17 @@ void SyncResult::setStatus( Status stat )
|
||||
_syncTime = QDateTime::currentDateTime();
|
||||
}
|
||||
|
||||
void SyncResult::setSyncFileItemVector( const SyncFileItemVector& items )
|
||||
{
|
||||
_syncItems = items;
|
||||
}
|
||||
|
||||
SyncFileItemVector SyncResult::syncFileItemVector() const
|
||||
{
|
||||
return _syncItems;
|
||||
}
|
||||
|
||||
QDateTime SyncResult::syncTime() const
|
||||
{
|
||||
return _syncTime;
|
||||
}
|
||||
|
||||
void SyncResult::setWarnCount(int wc)
|
||||
{
|
||||
_warnCount = wc;
|
||||
}
|
||||
|
||||
int SyncResult::warnCount() const
|
||||
{
|
||||
return _warnCount;
|
||||
}
|
||||
|
||||
void SyncResult::setErrorStrings( const QStringList& list )
|
||||
{
|
||||
_errors = list;
|
||||
}
|
||||
|
||||
QStringList SyncResult::errorStrings() const
|
||||
{
|
||||
return _errors;
|
||||
}
|
||||
|
||||
void SyncResult::setErrorString( const QString& err )
|
||||
void SyncResult::appendErrorString( const QString& err )
|
||||
{
|
||||
_errors.append( err );
|
||||
}
|
||||
@@ -141,8 +124,68 @@ QString SyncResult::folder() const
|
||||
return _folder;
|
||||
}
|
||||
|
||||
SyncResult::~SyncResult()
|
||||
void SyncResult::processCompletedItem(const SyncFileItemPtr &item)
|
||||
{
|
||||
if (Progress::isWarningKind(item->_status)) {
|
||||
// Count any error conditions, error strings will have priority anyway.
|
||||
_foundFilesNotSynced = true;
|
||||
}
|
||||
|
||||
if (item->_isDirectory && (item->_instruction == CSYNC_INSTRUCTION_NEW
|
||||
|| item->_instruction == CSYNC_INSTRUCTION_TYPE_CHANGE
|
||||
|| item->_instruction == CSYNC_INSTRUCTION_REMOVE
|
||||
|| item->_instruction == CSYNC_INSTRUCTION_RENAME)) {
|
||||
_folderStructureWasChanged = true;
|
||||
}
|
||||
|
||||
// Process the item to the gui
|
||||
if( item->_status == SyncFileItem::FatalError || item->_status == SyncFileItem::NormalError ) {
|
||||
//: this displays an error string (%2) for a file %1
|
||||
appendErrorString( QObject::tr("%1: %2").arg(item->_file, item->_errorString) );
|
||||
_numErrorItems++;
|
||||
if (!_firstItemError) {
|
||||
_firstItemError = item;
|
||||
}
|
||||
} else if( item->_status == SyncFileItem::Conflict ) {
|
||||
_numConflictItems++;
|
||||
if (!_firstConflictItem) {
|
||||
_firstConflictItem = item;
|
||||
}
|
||||
} else {
|
||||
if (!item->hasErrorStatus() && item->_status != SyncFileItem::FileIgnored && item->_direction == SyncFileItem::Down) {
|
||||
switch (item->_instruction) {
|
||||
case CSYNC_INSTRUCTION_NEW:
|
||||
case CSYNC_INSTRUCTION_TYPE_CHANGE:
|
||||
_numNewItems++;
|
||||
if (!_firstItemNew)
|
||||
_firstItemNew = item;
|
||||
break;
|
||||
case CSYNC_INSTRUCTION_REMOVE:
|
||||
_numRemovedItems++;
|
||||
if (!_firstItemDeleted)
|
||||
_firstItemDeleted = item;
|
||||
break;
|
||||
case CSYNC_INSTRUCTION_SYNC:
|
||||
_numUpdatedItems++;
|
||||
if (!_firstItemUpdated)
|
||||
_firstItemUpdated = item;
|
||||
break;
|
||||
case CSYNC_INSTRUCTION_RENAME:
|
||||
if (!_firstItemRenamed) {
|
||||
_firstItemRenamed = item;
|
||||
}
|
||||
_numRenamedItems++;
|
||||
break;
|
||||
default:
|
||||
// nothing.
|
||||
break;
|
||||
}
|
||||
} else if( item->_direction == SyncFileItem::None ) {
|
||||
if( item->_instruction == CSYNC_INSTRUCTION_IGNORE ) {
|
||||
_foundFilesNotSynced = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
+39
-11
@@ -47,20 +47,13 @@ public:
|
||||
};
|
||||
|
||||
SyncResult();
|
||||
SyncResult( Status status );
|
||||
~SyncResult();
|
||||
void setErrorString( const QString& );
|
||||
void setErrorStrings( const QStringList& );
|
||||
void reset();
|
||||
|
||||
void appendErrorString( const QString& );
|
||||
QString errorString() const;
|
||||
QStringList errorStrings() const;
|
||||
int warnCount() const;
|
||||
void setWarnCount(int wc);
|
||||
void clearErrors();
|
||||
|
||||
// handle a list of changed items.
|
||||
void setSyncFileItemVector( const SyncFileItemVector& );
|
||||
SyncFileItemVector syncFileItemVector() const;
|
||||
|
||||
void setStatus( Status );
|
||||
Status status() const;
|
||||
QString statusString() const;
|
||||
@@ -68,6 +61,25 @@ public:
|
||||
void setFolder(const QString& folder);
|
||||
QString folder() const;
|
||||
|
||||
bool foundFilesNotSynced() const { return _foundFilesNotSynced; }
|
||||
bool folderStructureWasChanged() const { return _folderStructureWasChanged; }
|
||||
|
||||
int numNewItems() const { return _numNewItems; }
|
||||
int numRemovedItems() const { return _numRemovedItems; }
|
||||
int numUpdatedItems() const { return _numUpdatedItems; }
|
||||
int numRenamedItems() const { return _numRenamedItems; }
|
||||
int numConflictItems() const { return _numConflictItems; }
|
||||
int numErrorItems() const { return _numErrorItems; }
|
||||
|
||||
const SyncFileItemPtr& firstItemNew() const { return _firstItemNew; }
|
||||
const SyncFileItemPtr& firstItemDeleted() const { return _firstItemDeleted; }
|
||||
const SyncFileItemPtr& firstItemUpdated() const { return _firstItemUpdated; }
|
||||
const SyncFileItemPtr& firstItemRenamed() const { return _firstItemRenamed; }
|
||||
const SyncFileItemPtr& firstConflictItem() const { return _firstConflictItem; }
|
||||
const SyncFileItemPtr& firstItemError() const { return _firstItemError; }
|
||||
|
||||
void processCompletedItem(const SyncFileItemPtr &item);
|
||||
|
||||
private:
|
||||
Status _status;
|
||||
SyncFileItemVector _syncItems;
|
||||
@@ -77,7 +89,23 @@ private:
|
||||
* when the sync tool support this...
|
||||
*/
|
||||
QStringList _errors;
|
||||
int _warnCount;
|
||||
bool _foundFilesNotSynced;
|
||||
bool _folderStructureWasChanged;
|
||||
|
||||
// count new, removed and updated items
|
||||
int _numNewItems;
|
||||
int _numRemovedItems;
|
||||
int _numUpdatedItems;
|
||||
int _numRenamedItems;
|
||||
int _numConflictItems;
|
||||
int _numErrorItems;
|
||||
|
||||
SyncFileItemPtr _firstItemNew;
|
||||
SyncFileItemPtr _firstItemDeleted;
|
||||
SyncFileItemPtr _firstItemUpdated;
|
||||
SyncFileItemPtr _firstItemRenamed;
|
||||
SyncFileItemPtr _firstConflictItem;
|
||||
SyncFileItemPtr _firstItemError;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ include_directories(${CMAKE_BINARY_DIR}/csync ${CMAKE_BINARY_DIR}/csync/src ${CM
|
||||
include_directories(${CMAKE_SOURCE_DIR}/csync/src/)
|
||||
include_directories(${CMAKE_SOURCE_DIR}/csync/src/std ${CMAKE_SOURCE_DIR}/src)
|
||||
include_directories(${CMAKE_SOURCE_DIR}/src/3rdparty/qtokenizer)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti")
|
||||
|
||||
include(QtVersionAbstraction)
|
||||
setup_qt()
|
||||
@@ -50,6 +49,7 @@ if(HAVE_QT5 AND NOT BUILD_WITH_QT4)
|
||||
owncloud_add_test(SyncFileStatusTracker "syncenginetestutils.h")
|
||||
owncloud_add_test(ChunkingNg "syncenginetestutils.h")
|
||||
owncloud_add_test(UploadReset "syncenginetestutils.h")
|
||||
owncloud_add_benchmark(LargeSync "syncenginetestutils.h")
|
||||
endif(HAVE_QT5 AND NOT BUILD_WITH_QT4)
|
||||
|
||||
SET(FolderMan_SRC ../src/gui/folderman.cpp)
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* This software is in the public domain, furnished "as is", without technical
|
||||
* support, and with no warranty, express or implied, as to its usefulness for
|
||||
* any purpose.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "syncenginetestutils.h"
|
||||
#include <syncengine.h>
|
||||
|
||||
using namespace OCC;
|
||||
|
||||
int numDirs = 0;
|
||||
int numFiles = 0;
|
||||
|
||||
template<int filesPerDir, int dirPerDir, int maxDepth>
|
||||
void addBunchOfFiles(int depth, const QString &path, FileModifier &fi) {
|
||||
for (int fileNum = 1; fileNum <= filesPerDir; ++fileNum) {
|
||||
QString name = QStringLiteral("file") + QString::number(fileNum);
|
||||
fi.insert(path.isEmpty() ? name : path + "/" + name);
|
||||
numFiles++;
|
||||
}
|
||||
if (depth >= maxDepth)
|
||||
return;
|
||||
for (char dirNum = 1; dirNum <= dirPerDir; ++dirNum) {
|
||||
QString name = QStringLiteral("dir") + QString::number(dirNum);
|
||||
QString subPath = path.isEmpty() ? name : path + "/" + name;
|
||||
fi.mkdir(subPath);
|
||||
numDirs++;
|
||||
addBunchOfFiles<filesPerDir, dirPerDir, maxDepth>(depth + 1, subPath, fi);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QCoreApplication app(argc, argv);
|
||||
FakeFolder fakeFolder{FileInfo{}};
|
||||
addBunchOfFiles<10, 8, 4>(0, "", fakeFolder.localModifier());
|
||||
|
||||
qDebug() << "NUMFILES" << numFiles;
|
||||
qDebug() << "NUMDIRS" << numDirs;
|
||||
return fakeFolder.syncOnce() ? 0 : -1;
|
||||
}
|
||||
@@ -24,3 +24,30 @@ macro(owncloud_add_test test_class additional_cpp)
|
||||
add_definitions(-DOWNCLOUD_BIN_PATH=${CMAKE_BINARY_DIR}/bin)
|
||||
add_test(NAME ${OWNCLOUD_TEST_CLASS}Test COMMAND ${OWNCLOUD_TEST_CLASS}Test)
|
||||
endmacro()
|
||||
|
||||
macro(owncloud_add_benchmark test_class additional_cpp)
|
||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${QT_INCLUDES}
|
||||
"${PROJECT_SOURCE_DIR}/src/gui"
|
||||
"${PROJECT_SOURCE_DIR}/src/libsync"
|
||||
"${CMAKE_BINARY_DIR}/src/libsync"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}"
|
||||
)
|
||||
|
||||
set(CMAKE_AUTOMOC TRUE)
|
||||
set(OWNCLOUD_TEST_CLASS ${test_class})
|
||||
string(TOLOWER "${OWNCLOUD_TEST_CLASS}" OWNCLOUD_TEST_CLASS_LOWERCASE)
|
||||
|
||||
add_executable(${OWNCLOUD_TEST_CLASS}Bench benchmarks/bench${OWNCLOUD_TEST_CLASS_LOWERCASE}.cpp ${additional_cpp})
|
||||
qt5_use_modules(${OWNCLOUD_TEST_CLASS}Bench Test Sql Xml Network)
|
||||
|
||||
target_link_libraries(${OWNCLOUD_TEST_CLASS}Bench
|
||||
updater
|
||||
${APPLICATION_EXECUTABLE}sync
|
||||
${QT_QTTEST_LIBRARY}
|
||||
${QT_QTCORE_LIBRARY}
|
||||
)
|
||||
|
||||
add_definitions(-DOWNCLOUD_TEST)
|
||||
add_definitions(-DOWNCLOUD_BIN_PATH=${CMAKE_BINARY_DIR}/bin)
|
||||
endmacro()
|
||||
|
||||
@@ -226,7 +226,7 @@ public:
|
||||
etag = file->etag;
|
||||
return file;
|
||||
}
|
||||
return nullptr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
FileInfo *createDir(const QString &relativePath) {
|
||||
@@ -267,6 +267,15 @@ public:
|
||||
return (parentPath.isEmpty() ? QString() : (parentPath + '/')) + name;
|
||||
}
|
||||
|
||||
void fixupParentPathRecursively() {
|
||||
auto p = path();
|
||||
for (auto it = children.begin(); it != children.end(); ++it) {
|
||||
Q_ASSERT(it.key() == it->name);
|
||||
it->parentPath = p;
|
||||
it->fixupParentPathRecursively();
|
||||
}
|
||||
}
|
||||
|
||||
QString name;
|
||||
bool isDir = true;
|
||||
bool isShared = false;
|
||||
@@ -285,15 +294,6 @@ private:
|
||||
return find(pathComponents, true);
|
||||
}
|
||||
|
||||
void fixupParentPathRecursively() {
|
||||
auto p = path();
|
||||
for (auto it = children.begin(); it != children.end(); ++it) {
|
||||
Q_ASSERT(it.key() == it->name);
|
||||
it->parentPath = p;
|
||||
it->fixupParentPathRecursively();
|
||||
}
|
||||
}
|
||||
|
||||
friend inline QDebug operator<<(QDebug dbg, const FileInfo& fi) {
|
||||
return dbg << "{ " << fi.path() << ": " << fi.children;
|
||||
}
|
||||
@@ -315,7 +315,10 @@ public:
|
||||
QString fileName = getFilePathFromUrl(request.url());
|
||||
Q_ASSERT(!fileName.isNull()); // for root, it should be empty
|
||||
const FileInfo *fileInfo = remoteRootFileInfo.find(fileName);
|
||||
Q_ASSERT(fileInfo);
|
||||
if (!fileInfo) {
|
||||
QMetaObject::invokeMethod(this, "respond404", Qt::QueuedConnection);
|
||||
return;
|
||||
}
|
||||
QString prefix = request.url().path().left(request.url().path().size() - fileName.size());
|
||||
|
||||
// Don't care about the request and just return a full propfind
|
||||
@@ -375,6 +378,13 @@ public:
|
||||
emit finished();
|
||||
}
|
||||
|
||||
Q_INVOKABLE void respond404() {
|
||||
setAttribute(QNetworkRequest::HttpStatusCodeAttribute, 404);
|
||||
setError(InternalServerError, "Not Found");
|
||||
emit metaDataChanged();
|
||||
emit finished();
|
||||
}
|
||||
|
||||
void abort() override { }
|
||||
|
||||
qint64 bytesAvailable() const override { return payload.size() + QIODevice::bytesAvailable(); }
|
||||
@@ -524,7 +534,8 @@ class FakeGetReply : public QNetworkReply
|
||||
Q_OBJECT
|
||||
public:
|
||||
const FileInfo *fileInfo;
|
||||
QByteArray payload;
|
||||
char payload;
|
||||
int size;
|
||||
|
||||
FakeGetReply(FileInfo &remoteRootFileInfo, QNetworkAccessManager::Operation op, const QNetworkRequest &request, QObject *parent)
|
||||
: QNetworkReply{parent} {
|
||||
@@ -540,8 +551,9 @@ public:
|
||||
}
|
||||
|
||||
Q_INVOKABLE void respond() {
|
||||
payload.fill(fileInfo->contentChar, fileInfo->size);
|
||||
setHeader(QNetworkRequest::ContentLengthHeader, payload.size());
|
||||
payload = fileInfo->contentChar;
|
||||
size = fileInfo->size;
|
||||
setHeader(QNetworkRequest::ContentLengthHeader, size);
|
||||
setAttribute(QNetworkRequest::HttpStatusCodeAttribute, 200);
|
||||
setRawHeader("OC-ETag", fileInfo->etag.toLatin1());
|
||||
setRawHeader("ETag", fileInfo->etag.toLatin1());
|
||||
@@ -553,12 +565,12 @@ public:
|
||||
}
|
||||
|
||||
void abort() override { }
|
||||
qint64 bytesAvailable() const override { return payload.size() + QIODevice::bytesAvailable(); }
|
||||
qint64 bytesAvailable() const override { return size + QIODevice::bytesAvailable(); }
|
||||
|
||||
qint64 readData(char *data, qint64 maxlen) override {
|
||||
qint64 len = std::min(qint64{payload.size()}, maxlen);
|
||||
strncpy(data, payload.constData(), len);
|
||||
payload.remove(0, len);
|
||||
qint64 len = std::min(qint64{size}, maxlen);
|
||||
std::fill_n(data, len, payload);
|
||||
size -= len;
|
||||
return len;
|
||||
}
|
||||
};
|
||||
@@ -586,7 +598,7 @@ public:
|
||||
Q_ASSERT(sourceFolder->isDir);
|
||||
int count = 0;
|
||||
int size = 0;
|
||||
char payload = '*';
|
||||
char payload = '\0';
|
||||
|
||||
do {
|
||||
QString chunkName = QString::number(count).rightJustified(8, '0');
|
||||
@@ -596,6 +608,7 @@ public:
|
||||
Q_ASSERT(!x.isDir);
|
||||
Q_ASSERT(x.size > 0); // There should not be empty chunks
|
||||
size += x.size;
|
||||
Q_ASSERT(!payload || payload == x.contentChar);
|
||||
payload = x.contentChar;
|
||||
++count;
|
||||
} while(true);
|
||||
@@ -607,7 +620,12 @@ public:
|
||||
Q_ASSERT(!fileName.isEmpty());
|
||||
|
||||
if ((fileInfo = remoteRootFileInfo.find(fileName))) {
|
||||
QCOMPARE(request.rawHeader("If"), QByteArray("<" + request.rawHeader("Destination") + "> ([\"" + fileInfo->etag.toLatin1() + "\"])"));
|
||||
QVERIFY(request.hasRawHeader("If")); // The client should put this header
|
||||
if (request.rawHeader("If") != QByteArray("<" + request.rawHeader("Destination") +
|
||||
"> ([\"" + fileInfo->etag.toLatin1() + "\"])")) {
|
||||
QMetaObject::invokeMethod(this, "respondPreconditionFailed", Qt::QueuedConnection);
|
||||
return;
|
||||
}
|
||||
fileInfo->size = size;
|
||||
fileInfo->contentChar = payload;
|
||||
} else {
|
||||
@@ -632,6 +650,13 @@ public:
|
||||
emit finished();
|
||||
}
|
||||
|
||||
Q_INVOKABLE void respondPreconditionFailed() {
|
||||
setAttribute(QNetworkRequest::HttpStatusCodeAttribute, 412);
|
||||
setError(InternalServerError, "Precondition Failed");
|
||||
emit metaDataChanged();
|
||||
emit finished();
|
||||
}
|
||||
|
||||
void abort() override { }
|
||||
qint64 readData(char *, qint64) override { return 0; }
|
||||
};
|
||||
@@ -766,6 +791,7 @@ public:
|
||||
QDir rootDir{_tempDir.path()};
|
||||
FileInfo rootTemplate;
|
||||
fromDisk(rootDir, rootTemplate);
|
||||
rootTemplate.fixupParentPathRecursively();
|
||||
return rootTemplate;
|
||||
}
|
||||
|
||||
@@ -792,15 +818,15 @@ public:
|
||||
}
|
||||
|
||||
void execUntilItemCompleted(const QString &relativePath) {
|
||||
QSignalSpy spy(_syncEngine.get(), SIGNAL(itemCompleted(const SyncFileItem &, const PropagatorJob &)));
|
||||
QSignalSpy spy(_syncEngine.get(), SIGNAL(itemCompleted(const SyncFileItemPtr &)));
|
||||
QElapsedTimer t;
|
||||
t.start();
|
||||
while (t.elapsed() < 5000) {
|
||||
spy.clear();
|
||||
QVERIFY(spy.wait());
|
||||
for(const QList<QVariant> &args : spy) {
|
||||
auto item = args[0].value<OCC::SyncFileItem>();
|
||||
if (item.destination() == relativePath)
|
||||
auto item = args[0].value<OCC::SyncFileItemPtr>();
|
||||
if (item->destination() == relativePath)
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -809,7 +835,7 @@ public:
|
||||
|
||||
bool execUntilFinished() {
|
||||
QSignalSpy spy(_syncEngine.get(), SIGNAL(finished(bool)));
|
||||
bool ok = spy.wait(60000);
|
||||
bool ok = spy.wait(3600000);
|
||||
Q_ASSERT(ok && "Sync timed out");
|
||||
return spy[0][0].toBool();
|
||||
}
|
||||
@@ -842,8 +868,8 @@ private:
|
||||
if (diskChild.isDir()) {
|
||||
QDir subDir = dir;
|
||||
subDir.cd(diskChild.fileName());
|
||||
templateFi.children.insert(diskChild.fileName(), FileInfo{diskChild.fileName()});
|
||||
fromDisk(subDir, templateFi.children.last());
|
||||
FileInfo &subFi = templateFi.children[diskChild.fileName()] = FileInfo{diskChild.fileName()};
|
||||
fromDisk(subDir, subFi);
|
||||
} else {
|
||||
QFile f{diskChild.filePath()};
|
||||
f.open(QFile::ReadOnly);
|
||||
|
||||
+188
-23
@@ -11,6 +11,36 @@
|
||||
|
||||
using namespace OCC;
|
||||
|
||||
/* Upload a 1/3 of a file of given size.
|
||||
* fakeFolder needs to be synchronized */
|
||||
static void partialUpload(FakeFolder &fakeFolder, const QString &name, int size)
|
||||
{
|
||||
QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
|
||||
QCOMPARE(fakeFolder.uploadState().children.count(), 0); // The state should be clean
|
||||
|
||||
fakeFolder.localModifier().insert(name, size);
|
||||
// Abort when the upload is at 1/3
|
||||
int sizeWhenAbort = -1;
|
||||
auto con = QObject::connect(&fakeFolder.syncEngine(), &SyncEngine::transmissionProgress,
|
||||
[&](const ProgressInfo &progress) {
|
||||
if (progress.completedSize() > (progress.totalSize() /3 )) {
|
||||
sizeWhenAbort = progress.completedSize();
|
||||
fakeFolder.syncEngine().abort();
|
||||
}
|
||||
});
|
||||
|
||||
QVERIFY(!fakeFolder.syncOnce()); // there should have been an error
|
||||
QObject::disconnect(con);
|
||||
QVERIFY(sizeWhenAbort > 0);
|
||||
QVERIFY(sizeWhenAbort < size);
|
||||
|
||||
QCOMPARE(fakeFolder.uploadState().children.count(), 1); // the transfer was done with chunking
|
||||
auto upStateChildren = fakeFolder.uploadState().children.first().children;
|
||||
QCOMPARE(sizeWhenAbort, std::accumulate(upStateChildren.cbegin(), upStateChildren.cend(), 0,
|
||||
[](int s, const FileInfo &i) { return s + i.size; }));
|
||||
}
|
||||
|
||||
|
||||
class TestChunkingNG : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
@@ -40,38 +70,173 @@ private slots:
|
||||
FakeFolder fakeFolder{FileInfo::A12_B12_C12_S12()};
|
||||
fakeFolder.syncEngine().account()->setCapabilities({ { "dav", QVariantMap{ {"chunking", "1.0"} } } });
|
||||
const int size = 300 * 1000 * 1000; // 300 MB
|
||||
fakeFolder.localModifier().insert("A/a0", size);
|
||||
|
||||
// Abort when the upload is at 1/3
|
||||
int sizeWhenAbort = -1;
|
||||
auto con = QObject::connect(&fakeFolder.syncEngine(), &SyncEngine::transmissionProgress,
|
||||
[&](const ProgressInfo &progress) {
|
||||
if (progress.completedSize() > (progress.totalSize() /3 )) {
|
||||
sizeWhenAbort = progress.completedSize();
|
||||
fakeFolder.syncEngine().abort();
|
||||
}
|
||||
});
|
||||
|
||||
QVERIFY(!fakeFolder.syncOnce()); // there should have been an error
|
||||
QObject::disconnect(con);
|
||||
QVERIFY(sizeWhenAbort > 0);
|
||||
QVERIFY(sizeWhenAbort < size);
|
||||
QCOMPARE(fakeFolder.uploadState().children.count(), 1); // the transfer was done with chunking
|
||||
auto upStateChildren = fakeFolder.uploadState().children.first().children;
|
||||
QCOMPARE(sizeWhenAbort, std::accumulate(upStateChildren.cbegin(), upStateChildren.cend(), 0,
|
||||
[](int s, const FileInfo &i) { return s + i.size; }));
|
||||
|
||||
partialUpload(fakeFolder, "A/a0", size);
|
||||
QCOMPARE(fakeFolder.uploadState().children.count(), 1);
|
||||
auto chunkingId = fakeFolder.uploadState().children.first().name;
|
||||
|
||||
// Add a fake file to make sure it gets deleted
|
||||
fakeFolder.uploadState().children.first().insert("10000", size);
|
||||
QVERIFY(fakeFolder.syncOnce());
|
||||
|
||||
QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
|
||||
QCOMPARE(fakeFolder.currentRemoteState().find("A/a0")->size, size);
|
||||
// The same chunk id was re-used
|
||||
QCOMPARE(fakeFolder.uploadState().children.count(), 1);
|
||||
QCOMPARE(fakeFolder.uploadState().children.first().name, chunkingId);
|
||||
}
|
||||
|
||||
// We modify the file locally after it has been partially uploaded
|
||||
void testRemoveStale1() {
|
||||
|
||||
FakeFolder fakeFolder{FileInfo::A12_B12_C12_S12()};
|
||||
fakeFolder.syncEngine().account()->setCapabilities({ { "dav", QVariantMap{ {"chunking", "1.0"} } } });
|
||||
const int size = 300 * 1000 * 1000; // 300 MB
|
||||
partialUpload(fakeFolder, "A/a0", size);
|
||||
QCOMPARE(fakeFolder.uploadState().children.count(), 1);
|
||||
auto chunkingId = fakeFolder.uploadState().children.first().name;
|
||||
|
||||
|
||||
fakeFolder.localModifier().setContents("A/a0", 'B');
|
||||
fakeFolder.localModifier().appendByte("A/a0");
|
||||
|
||||
QVERIFY(fakeFolder.syncOnce());
|
||||
|
||||
QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
|
||||
QCOMPARE(fakeFolder.uploadState().children.count(), 1); // The same chunk id was re-used
|
||||
QCOMPARE(fakeFolder.currentRemoteState().find("A/a0")->size, size);
|
||||
QCOMPARE(fakeFolder.currentRemoteState().find("A/a0")->size, size + 1);
|
||||
// A different chunk id was used, and the previous one is removed
|
||||
QCOMPARE(fakeFolder.uploadState().children.count(), 1);
|
||||
QVERIFY(fakeFolder.uploadState().children.first().name != chunkingId);
|
||||
}
|
||||
|
||||
// We remove the file locally after it has been partially uploaded
|
||||
void testRemoveStale2() {
|
||||
|
||||
FakeFolder fakeFolder{FileInfo::A12_B12_C12_S12()};
|
||||
fakeFolder.syncEngine().account()->setCapabilities({ { "dav", QVariantMap{ {"chunking", "1.0"} } } });
|
||||
const int size = 300 * 1000 * 1000; // 300 MB
|
||||
partialUpload(fakeFolder, "A/a0", size);
|
||||
QCOMPARE(fakeFolder.uploadState().children.count(), 1);
|
||||
|
||||
fakeFolder.localModifier().remove("A/a0");
|
||||
|
||||
QVERIFY(fakeFolder.syncOnce());
|
||||
QCOMPARE(fakeFolder.uploadState().children.count(), 0);
|
||||
}
|
||||
|
||||
|
||||
void testCreateConflictWhileSyncing() {
|
||||
FakeFolder fakeFolder{FileInfo::A12_B12_C12_S12()};
|
||||
fakeFolder.syncEngine().account()->setCapabilities({ { "dav", QVariantMap{ {"chunking", "1.0"} } } });
|
||||
const int size = 150 * 1000 * 1000; // 150 MB
|
||||
|
||||
// Put a file on the server and download it.
|
||||
fakeFolder.remoteModifier().insert("A/a0", size);
|
||||
QVERIFY(fakeFolder.syncOnce());
|
||||
QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
|
||||
|
||||
// Modify the file localy and start the upload
|
||||
fakeFolder.localModifier().setContents("A/a0", 'B');
|
||||
fakeFolder.localModifier().appendByte("A/a0");
|
||||
|
||||
// But in the middle of the sync, modify the file on the server
|
||||
QMetaObject::Connection con = QObject::connect(&fakeFolder.syncEngine(), &SyncEngine::transmissionProgress,
|
||||
[&](const ProgressInfo &progress) {
|
||||
if (progress.completedSize() > (progress.totalSize() / 2 )) {
|
||||
fakeFolder.remoteModifier().setContents("A/a0", 'C');
|
||||
QObject::disconnect(con);
|
||||
}
|
||||
});
|
||||
|
||||
QVERIFY(!fakeFolder.syncOnce());
|
||||
// There was a precondition failed error, this means wen need to sync again
|
||||
QCOMPARE(fakeFolder.syncEngine().isAnotherSyncNeeded(), ImmediateFollowUp);
|
||||
|
||||
QCOMPARE(fakeFolder.uploadState().children.count(), 1); // We did not clean the chunks at this point
|
||||
|
||||
// Now we will download the server file and create a conflict
|
||||
QVERIFY(fakeFolder.syncOnce());
|
||||
auto localState = fakeFolder.currentLocalState();
|
||||
|
||||
// A0 is the one from the server
|
||||
QCOMPARE(localState.find("A/a0")->size, size);
|
||||
QCOMPARE(localState.find("A/a0")->contentChar, 'C');
|
||||
|
||||
// There is a conflict file with our version
|
||||
auto &stateAChildren = localState.find("A")->children;
|
||||
auto it = std::find_if(stateAChildren.cbegin(), stateAChildren.cend(), [&](const FileInfo &fi) {
|
||||
return fi.name.startsWith("a0_conflict");
|
||||
});
|
||||
QVERIFY(it != stateAChildren.cend());
|
||||
QCOMPARE(it->contentChar, 'B');
|
||||
QCOMPARE(it->size, size+1);
|
||||
|
||||
// Remove the conflict file so the comparison works!
|
||||
fakeFolder.localModifier().remove("A/" + it->name);
|
||||
|
||||
QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
|
||||
|
||||
QCOMPARE(fakeFolder.uploadState().children.count(), 0); // The last sync cleaned the chunks
|
||||
}
|
||||
|
||||
void testModifyLocalFileWhileUploading() {
|
||||
|
||||
FakeFolder fakeFolder{FileInfo::A12_B12_C12_S12()};
|
||||
fakeFolder.syncEngine().account()->setCapabilities({ { "dav", QVariantMap{ {"chunking", "1.0"} } } });
|
||||
const int size = 150 * 1000 * 1000; // 150 MB
|
||||
|
||||
fakeFolder.localModifier().insert("A/a0", size);
|
||||
|
||||
// middle of the sync, modify the file
|
||||
QMetaObject::Connection con = QObject::connect(&fakeFolder.syncEngine(), &SyncEngine::transmissionProgress,
|
||||
[&](const ProgressInfo &progress) {
|
||||
if (progress.completedSize() > (progress.totalSize() / 2 )) {
|
||||
fakeFolder.localModifier().setContents("A/a0", 'B');
|
||||
fakeFolder.localModifier().appendByte("A/a0");
|
||||
QObject::disconnect(con);
|
||||
}
|
||||
});
|
||||
|
||||
QVERIFY(!fakeFolder.syncOnce());
|
||||
|
||||
// There should be a followup sync
|
||||
QCOMPARE(fakeFolder.syncEngine().isAnotherSyncNeeded(), ImmediateFollowUp);
|
||||
|
||||
QCOMPARE(fakeFolder.uploadState().children.count(), 1); // We did not clean the chunks at this point
|
||||
auto chunkingId = fakeFolder.uploadState().children.first().name;
|
||||
|
||||
// Now we make a new sync which should upload the file for good.
|
||||
QVERIFY(fakeFolder.syncOnce());
|
||||
|
||||
QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
|
||||
QCOMPARE(fakeFolder.currentRemoteState().find("A/a0")->size, size+1);
|
||||
|
||||
// A different chunk id was used, and the previous one is removed
|
||||
QCOMPARE(fakeFolder.uploadState().children.count(), 1);
|
||||
QVERIFY(fakeFolder.uploadState().children.first().name != chunkingId);
|
||||
}
|
||||
|
||||
|
||||
void testResumeServerDeletedChunks() {
|
||||
|
||||
FakeFolder fakeFolder{FileInfo::A12_B12_C12_S12()};
|
||||
fakeFolder.syncEngine().account()->setCapabilities({ { "dav", QVariantMap{ {"chunking", "1.0"} } } });
|
||||
const int size = 300 * 1000 * 1000; // 300 MB
|
||||
partialUpload(fakeFolder, "A/a0", size);
|
||||
QCOMPARE(fakeFolder.uploadState().children.count(), 1);
|
||||
auto chunkingId = fakeFolder.uploadState().children.first().name;
|
||||
|
||||
// Delete the chunks on the server
|
||||
fakeFolder.uploadState().children.clear();
|
||||
QVERIFY(fakeFolder.syncOnce());
|
||||
|
||||
QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
|
||||
QCOMPARE(fakeFolder.currentRemoteState().find("A/a0")->size, size);
|
||||
|
||||
// A different chunk id was used
|
||||
QCOMPARE(fakeFolder.uploadState().children.count(), 1);
|
||||
QVERIFY(fakeFolder.uploadState().children.first().name != chunkingId);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
QTEST_GUILESS_MAIN(TestChunkingNG)
|
||||
|
||||
+24
-13
@@ -14,8 +14,8 @@ using namespace OCC;
|
||||
bool itemDidComplete(const QSignalSpy &spy, const QString &path)
|
||||
{
|
||||
for(const QList<QVariant> &args : spy) {
|
||||
SyncFileItem item = args[0].value<SyncFileItem>();
|
||||
if (item.destination() == path)
|
||||
auto item = args[0].value<SyncFileItemPtr>();
|
||||
if (item->destination() == path)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -24,9 +24,9 @@ bool itemDidComplete(const QSignalSpy &spy, const QString &path)
|
||||
bool itemDidCompleteSuccessfully(const QSignalSpy &spy, const QString &path)
|
||||
{
|
||||
for(const QList<QVariant> &args : spy) {
|
||||
SyncFileItem item = args[0].value<SyncFileItem>();
|
||||
if (item.destination() == path)
|
||||
return item._status == SyncFileItem::Success;
|
||||
auto item = args[0].value<SyncFileItemPtr>();
|
||||
if (item->destination() == path)
|
||||
return item->_status == SyncFileItem::Success;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -38,7 +38,7 @@ class TestSyncEngine : public QObject
|
||||
private slots:
|
||||
void testFileDownload() {
|
||||
FakeFolder fakeFolder{FileInfo::A12_B12_C12_S12()};
|
||||
QSignalSpy completeSpy(&fakeFolder.syncEngine(), SIGNAL(itemCompleted(const SyncFileItem &, const PropagatorJob &)));
|
||||
QSignalSpy completeSpy(&fakeFolder.syncEngine(), SIGNAL(itemCompleted(const SyncFileItemPtr &)));
|
||||
fakeFolder.remoteModifier().insert("A/a0");
|
||||
fakeFolder.syncOnce();
|
||||
QVERIFY(itemDidCompleteSuccessfully(completeSpy, "A/a0"));
|
||||
@@ -47,7 +47,7 @@ private slots:
|
||||
|
||||
void testFileUpload() {
|
||||
FakeFolder fakeFolder{FileInfo::A12_B12_C12_S12()};
|
||||
QSignalSpy completeSpy(&fakeFolder.syncEngine(), SIGNAL(itemCompleted(const SyncFileItem &, const PropagatorJob &)));
|
||||
QSignalSpy completeSpy(&fakeFolder.syncEngine(), SIGNAL(itemCompleted(const SyncFileItemPtr &)));
|
||||
fakeFolder.localModifier().insert("A/a0");
|
||||
fakeFolder.syncOnce();
|
||||
QVERIFY(itemDidCompleteSuccessfully(completeSpy, "A/a0"));
|
||||
@@ -56,7 +56,7 @@ private slots:
|
||||
|
||||
void testDirDownload() {
|
||||
FakeFolder fakeFolder{FileInfo::A12_B12_C12_S12()};
|
||||
QSignalSpy completeSpy(&fakeFolder.syncEngine(), SIGNAL(itemCompleted(const SyncFileItem &, const PropagatorJob &)));
|
||||
QSignalSpy completeSpy(&fakeFolder.syncEngine(), SIGNAL(itemCompleted(const SyncFileItemPtr &)));
|
||||
fakeFolder.remoteModifier().mkdir("Y");
|
||||
fakeFolder.remoteModifier().mkdir("Z");
|
||||
fakeFolder.remoteModifier().insert("Z/d0");
|
||||
@@ -69,7 +69,7 @@ private slots:
|
||||
|
||||
void testDirUpload() {
|
||||
FakeFolder fakeFolder{FileInfo::A12_B12_C12_S12()};
|
||||
QSignalSpy completeSpy(&fakeFolder.syncEngine(), SIGNAL(itemCompleted(const SyncFileItem &, const PropagatorJob &)));
|
||||
QSignalSpy completeSpy(&fakeFolder.syncEngine(), SIGNAL(itemCompleted(const SyncFileItemPtr &)));
|
||||
fakeFolder.localModifier().mkdir("Y");
|
||||
fakeFolder.localModifier().mkdir("Z");
|
||||
fakeFolder.localModifier().insert("Z/d0");
|
||||
@@ -82,7 +82,7 @@ private slots:
|
||||
|
||||
void testLocalDelete() {
|
||||
FakeFolder fakeFolder{FileInfo::A12_B12_C12_S12()};
|
||||
QSignalSpy completeSpy(&fakeFolder.syncEngine(), SIGNAL(itemCompleted(const SyncFileItem &, const PropagatorJob &)));
|
||||
QSignalSpy completeSpy(&fakeFolder.syncEngine(), SIGNAL(itemCompleted(const SyncFileItemPtr &)));
|
||||
fakeFolder.remoteModifier().remove("A/a1");
|
||||
fakeFolder.syncOnce();
|
||||
QVERIFY(itemDidCompleteSuccessfully(completeSpy, "A/a1"));
|
||||
@@ -91,7 +91,7 @@ private slots:
|
||||
|
||||
void testRemoteDelete() {
|
||||
FakeFolder fakeFolder{FileInfo::A12_B12_C12_S12()};
|
||||
QSignalSpy completeSpy(&fakeFolder.syncEngine(), SIGNAL(itemCompleted(const SyncFileItem &, const PropagatorJob &)));
|
||||
QSignalSpy completeSpy(&fakeFolder.syncEngine(), SIGNAL(itemCompleted(const SyncFileItemPtr &)));
|
||||
fakeFolder.localModifier().remove("A/a1");
|
||||
fakeFolder.syncOnce();
|
||||
QVERIFY(itemDidCompleteSuccessfully(completeSpy, "A/a1"));
|
||||
@@ -107,7 +107,7 @@ private slots:
|
||||
// fakeFolder.syncOnce();
|
||||
fakeFolder.syncOnce();
|
||||
|
||||
QSignalSpy completeSpy(&fakeFolder.syncEngine(), SIGNAL(itemCompleted(const SyncFileItem &, const PropagatorJob &)));
|
||||
QSignalSpy completeSpy(&fakeFolder.syncEngine(), SIGNAL(itemCompleted(const SyncFileItemPtr &)));
|
||||
// Touch the file without changing the content, shouldn't upload
|
||||
fakeFolder.localModifier().setContents("a1.eml", 'A');
|
||||
// Change the content/size
|
||||
@@ -204,7 +204,7 @@ private slots:
|
||||
QCOMPARE(fakeFolder.currentLocalState(), remoteState);
|
||||
|
||||
expectedServerState = fakeFolder.currentRemoteState();
|
||||
QSignalSpy completeSpy(&fakeFolder.syncEngine(), SIGNAL(itemCompleted(const SyncFileItem &, const PropagatorJob &)));
|
||||
QSignalSpy completeSpy(&fakeFolder.syncEngine(), SIGNAL(itemCompleted(const SyncFileItemPtr &)));
|
||||
fakeFolder.syncOnce(); // This sync should do nothing
|
||||
QCOMPARE(completeSpy.count(), 0);
|
||||
|
||||
@@ -213,6 +213,17 @@ private slots:
|
||||
}
|
||||
}
|
||||
|
||||
void abortAfterFailedMkdir() {
|
||||
FakeFolder fakeFolder{FileInfo{}};
|
||||
QSignalSpy finishedSpy(&fakeFolder.syncEngine(), SIGNAL(finished(bool)));
|
||||
fakeFolder.serverErrorPaths().append("NewFolder");
|
||||
fakeFolder.localModifier().mkdir("NewFolder");
|
||||
// This should be aborted and would otherwise fail in FileInfo::create.
|
||||
fakeFolder.localModifier().insert("NewFolder/NewFile");
|
||||
fakeFolder.syncOnce();
|
||||
QCOMPARE(finishedSpy.size(), 1);
|
||||
QCOMPARE(finishedSpy.first().first().toBool(), false);
|
||||
}
|
||||
};
|
||||
|
||||
QTEST_GUILESS_MAIN(TestSyncEngine)
|
||||
|
||||
+275
-251
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
+275
-251
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
+278
-251
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
+282
-258
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
+272
-247
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
+285
-259
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
+273
-248
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
+273
-248
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
+274
-249
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
+274
-249
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
+275
-251
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
+298
-271
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
+274
-250
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
+274
-249
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
+277
-250
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
+275
-251
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
+275
-251
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
+277
-251
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
+287
-261
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
+276
-252
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
+277
-251
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
+279
-253
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
+275
-251
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
+285
-259
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
Alguns arquivos não foram exibidos porque demasiados arquivos foram alterados neste diff Mostrar Mais
Referência em uma Nova Issue
Bloquear um usuário