From da7b9916e52eefcc8f5ea7501213899d076fcfbe Mon Sep 17 00:00:00 2001 From: Jocelyn Turcotte Date: Thu, 17 Mar 2016 12:26:44 +0100 Subject: [PATCH] Move the SocketApi business logic to a libsync SyncFileStatusTracker class This will allow testing this code and avoid going through too many layers to get notified and a file status changed. --- src/gui/accountsettings.cpp | 1 + src/gui/folder.cpp | 70 -------- src/gui/folder.h | 20 +-- src/gui/socketapi.cpp | 149 +---------------- src/libsync/CMakeLists.txt | 1 + src/libsync/syncengine.cpp | 1 + src/libsync/syncengine.h | 7 +- src/libsync/syncfilestatustracker.cpp | 230 ++++++++++++++++++++++++++ src/libsync/syncfilestatustracker.h | 51 ++++++ 9 files changed, 296 insertions(+), 234 deletions(-) create mode 100644 src/libsync/syncfilestatustracker.cpp create mode 100644 src/libsync/syncfilestatustracker.h diff --git a/src/gui/accountsettings.cpp b/src/gui/accountsettings.cpp index 383751bc30..83756bf8b0 100644 --- a/src/gui/accountsettings.cpp +++ b/src/gui/accountsettings.cpp @@ -34,6 +34,7 @@ #include #include +#include #include #include #include diff --git a/src/gui/folder.cpp b/src/gui/folder.cpp index 272d5445ff..9cc7aef0e6 100644 --- a/src/gui/folder.cpp +++ b/src/gui/folder.cpp @@ -99,8 +99,6 @@ Folder::Folder(const FolderDefinition& definition, 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(aboutToPropagate(SyncFileItemVector&)), - this, SLOT(slotAboutToPropagate(SyncFileItemVector&))); connect(_engine.data(), SIGNAL(started()), SLOT(slotSyncStarted()), Qt::QueuedConnection); connect(_engine.data(), SIGNAL(finished(bool)), SLOT(slotSyncFinished(bool)), Qt::QueuedConnection); @@ -595,71 +593,11 @@ void Folder::slotWatchedPathChanged(const QString& path) } } -/** - * Whether this item should get an ERROR icon through the Socket API. - * - * The Socket API should only present serious, permanent errors to the user. - * In particular SoftErrors should just retain their 'needs to be synced' - * icon as the problem is most likely going to resolve itself quickly and - * automatically. - */ -static bool showErrorInSocketApi(const SyncFileItem& item) -{ - const auto status = item._status; - return status == SyncFileItem::NormalError - || status == SyncFileItem::FatalError; -} - -static void addErroredSyncItemPathsToList(const SyncFileItemVector& items, QSet* set) { - foreach (const SyncFileItemPtr &item, items) { - if (showErrorInSocketApi(*item)) { - set->insert(item->_file); - } - } -} - void Folder::slotThreadTreeWalkResult(const SyncFileItemVector& items) { - addErroredSyncItemPathsToList(items, &this->_stateLastSyncItemsWithErrorNew); _syncResult.setSyncFileItemVector(items); } -void Folder::slotAboutToPropagate(SyncFileItemVector& items) -{ - addErroredSyncItemPathsToList(items, &this->_stateLastSyncItemsWithErrorNew); -} - - -bool Folder::estimateState(QString fn, csync_ftw_type_e t, SyncFileStatus* s) -{ - if (t == CSYNC_FTW_TYPE_DIR) { - if (Utility::doesSetContainPrefix(_stateLastSyncItemsWithError, fn)) { - qDebug() << Q_FUNC_INFO << "Folder has error" << fn; - s->set(SyncFileStatus::STATUS_ERROR); - return true; - } - // If sync is running, check _syncedItems, possibly give it STATUS_EVAL (=syncing down) - if (_engine->isSyncRunning()) { - if (_engine->estimateState(fn, t, s)) { - return true; - } - } - return false; - } else if ( t== CSYNC_FTW_TYPE_FILE) { - // check if errorList has the directory/file - if (Utility::doesSetContainPrefix(_stateLastSyncItemsWithError, fn)) { - s->set(SyncFileStatus::STATUS_ERROR); - return true; - } - // If sync running: _syncedItems -> SyncingState - if (_engine->isSyncRunning()) { - if (_engine->estimateState(fn, t, s)) { - return true; - } - } - } - return false; -} void Folder::saveToSettings() const { @@ -873,10 +811,6 @@ void Folder::slotSyncFinished(bool success) - // This is for sync state calculation - _stateLastSyncItemsWithError = _stateLastSyncItemsWithErrorNew; - _stateLastSyncItemsWithErrorNew.clear(); - if (_csyncError) { _syncResult.setStatus(SyncResult::Error); qDebug() << " ** error Strings: " << _errors; @@ -972,10 +906,6 @@ void Folder::slotTransmissionProgress(const ProgressInfo &pi) // a item is completed: count the errors and forward to the ProgressDispatcher void Folder::slotItemCompleted(const SyncFileItem &item, const PropagatorJob& job) { - if (showErrorInSocketApi(item)) { - _stateLastSyncItemsWithErrorNew.insert(item._file); - } - if (Progress::isWarningKind(item._status)) { // Count all error conditions. _syncResult.setWarnCount(_syncResult.warnCount()+1); diff --git a/src/gui/folder.h b/src/gui/folder.h index 59fa7f61fb..a76b9e2557 100644 --- a/src/gui/folder.h +++ b/src/gui/folder.h @@ -26,16 +26,9 @@ #include -#include -#include -#include #include #include -#include -#include -#include - class QThread; class QSettings; @@ -181,8 +174,7 @@ public: // Used by the Socket API SyncJournalDb *journalDb() { return &_journal; } - - bool estimateState(QString fn, csync_ftw_type_e t, SyncFileStatus* s); + SyncEngine &syncEngine() { return *_engine; } RequestEtagJob *etagJob() { return _requestEtagJob; } qint64 msecSinceLastSync() const { return _timeSinceLastSyncDone.elapsed(); } @@ -262,7 +254,6 @@ private slots: void etagRetreived(const QString &); void etagRetreivedFromSyncEngine(const QString &); - void slotAboutToPropagate(SyncFileItemVector& ); void slotThreadTreeWalkResult(const SyncFileItemVector& ); // after sync is done void slotEmitFinishedDelayed(); @@ -304,15 +295,6 @@ private: /// Reset when no follow-up is requested. int _consecutiveFollowUpSyncs; - // SocketAPI: Cache files and folders that had errors so that they can - // get a red ERROR icon. - QSet _stateLastSyncItemsWithErrorNew; // gets moved to _stateLastSyncItemsWithError at end of sync - QSet _stateLastSyncItemsWithError; - - // SocketAPI: A folder is tained if we got a file watcher notification - // for it. It's displayed as EVAL. - QSet _stateTaintedFolders; - SyncJournalDb _journal; ClientProxy _clientProxy; diff --git a/src/gui/socketapi.cpp b/src/gui/socketapi.cpp index 39dc40f88c..b3c7161f6c 100644 --- a/src/gui/socketapi.cpp +++ b/src/gui/socketapi.cpp @@ -23,6 +23,7 @@ #include "utility.h" #include "theme.h" #include "syncjournalfilerecord.h" +#include "syncengine.h" #include "syncfileitem.h" #include "filesystem.h" #include "version.h" @@ -215,7 +216,7 @@ void SocketApi::slotUpdateFolderView(Folder *f) f->syncResult().status() == SyncResult::SetupError ) { broadcastMessage(QLatin1String("STATUS"), f->path() , - this->fileStatus(f, "").toSocketAPIString()); + f->syncEngine().syncFileStatusTracker().fileStatus("").toSocketAPIString()); broadcastMessage(QLatin1String("UPDATE_VIEW"), f->path() ); } else { @@ -235,7 +236,7 @@ void SocketApi::slotItemCompleted(const QString &folder, const SyncFileItem &ite return; } - auto status = this->fileStatus(f, item.destination()); + auto status = f->syncEngine().syncFileStatusTracker().fileStatus(item.destination()); const QString path = f->path() + item.destination(); broadcastMessage(QLatin1String("STATUS"), path, status.toSocketAPIString()); } @@ -330,7 +331,7 @@ void SocketApi::command_RETRIEVE_FILE_STATUS(const QString& argument, QIODevice* statusString = QLatin1String("NOP"); } else { const QString file = QDir::cleanPath(argument).mid(syncFolder->cleanPath().length()+1); - SyncFileStatus fileStatus = this->fileStatus(syncFolder, file); + SyncFileStatus fileStatus = syncFolder->syncEngine().syncFileStatusTracker().fileStatus(file); statusString = fileStatus.toSocketAPIString(); } @@ -367,7 +368,7 @@ void SocketApi::command_SHARE(const QString& localFile, QIODevice* socket) } else { const QString localFileClean = QDir::cleanPath(localFile); const QString file = localFileClean.mid(shareFolder->cleanPath().length()+1); - SyncFileStatus fileStatus = this->fileStatus(shareFolder, file); + SyncFileStatus fileStatus = shareFolder->syncEngine().syncFileStatusTracker().fileStatus(file); // Verify the file is on the server (to our knowledge of course) if (fileStatus.tag() != SyncFileStatus::STATUS_UPTODATE && @@ -423,7 +424,7 @@ void SocketApi::command_SHARE_STATUS(const QString &localFile, QIODevice *socket sendMessage(socket, message); } else { const QString file = QDir::cleanPath(localFile).mid(shareFolder->cleanPath().length()+1); - SyncFileStatus fileStatus = this->fileStatus(shareFolder, file); + SyncFileStatus fileStatus = shareFolder->syncEngine().syncFileStatusTracker().fileStatus(file); // Verify the file is on the server (to our knowledge of course) if (fileStatus.tag() != SyncFileStatus::STATUS_UPTODATE && @@ -478,142 +479,4 @@ QString SocketApi::buildRegisterPathMessage(const QString& path) return message; } -/** - * Get status about a single file. - */ -SyncFileStatus SocketApi::fileStatus(Folder *folder, const QString& systemFileName) -{ - QString file = folder->path(); - QString fileName = systemFileName.normalized(QString::NormalizationForm_C); - QString fileNameSlash = fileName; - - if(fileName != QLatin1String("/") && !fileName.isEmpty()) { - file += fileName; - } - - if( fileName.endsWith(QLatin1Char('/')) ) { - fileName.truncate(fileName.length()-1); - qDebug() << "Removed trailing slash: " << fileName; - } else { - fileNameSlash += QLatin1Char('/'); - } - - const QFileInfo fi(file); - if( !FileSystem::fileExists(file, fi) ) { - qDebug() << "OO File " << file << " is not existing"; - return SyncFileStatus(SyncFileStatus::STATUS_STAT_ERROR); - } - - // file is ignored? - // Qt considers .lnk files symlinks on Windows so we need to work - // around that here. - if( fi.isSymLink() -#ifdef Q_OS_WIN - && fi.suffix() != "lnk" -#endif - ) { - return SyncFileStatus(SyncFileStatus::STATUS_IGNORE); - } - - csync_ftw_type_e type = CSYNC_FTW_TYPE_FILE; - if( fi.isDir() ) { - type = CSYNC_FTW_TYPE_DIR; - } - - // Is it excluded? - if( folder->isFileExcludedRelative(fileName) ) { - return SyncFileStatus(SyncFileStatus::STATUS_IGNORE); - } - - // Error if it is in the selective sync blacklist - foreach(const auto &s, folder->journalDb()->getSelectiveSyncList(SyncJournalDb::SelectiveSyncBlackList)) { - if (fileNameSlash.startsWith(s)) { - return SyncFileStatus(SyncFileStatus::STATUS_ERROR); - } - } - - SyncFileStatus status(SyncFileStatus::STATUS_NONE); - SyncJournalFileRecord rec = folder->journalDb()->getFileRecord(fileName); - - if (folder->estimateState(fileName, type, &status)) { - qDebug() << "Folder estimated status for" << fileName << "to" << status.toSocketAPIString(); - } else if (fileName == "") { - // sync folder itself - switch (folder->syncResult().status()) { - case SyncResult::Undefined: - case SyncResult::NotYetStarted: - case SyncResult::SyncPrepare: - case SyncResult::SyncRunning: - status.set(SyncFileStatus::STATUS_EVAL); - return status; - - case SyncResult::Success: - case SyncResult::Problem: - status.set(SyncFileStatus::STATUS_UPTODATE); - return status; - - case SyncResult::Error: - case SyncResult::SetupError: - case SyncResult::SyncAbortRequested: - status.set(SyncFileStatus::STATUS_ERROR); - return status; - - case SyncResult::Paused: - status.set(SyncFileStatus::STATUS_IGNORE); - return status; - } - } else if (type == CSYNC_FTW_TYPE_DIR) { - if (rec.isValid()) { - status.set(SyncFileStatus::STATUS_UPTODATE); - } else { - qDebug() << "Could not determine state for folder" << fileName << "will set STATUS_NEW"; - status.set(SyncFileStatus::STATUS_NEW); - } - } else if (type == CSYNC_FTW_TYPE_FILE) { - if (rec.isValid()) { - if( FileSystem::getModTime(fi.absoluteFilePath()) == Utility::qDateTimeToTime_t(rec._modtime) ) { - status.set(SyncFileStatus::STATUS_UPTODATE); - } else { - if (rec._remotePerm.isNull() || rec._remotePerm.contains("W") ) { - status.set(SyncFileStatus::STATUS_EVAL); - } else { - status.set(SyncFileStatus::STATUS_ERROR); - } - } - } else { - qDebug() << "Could not determine state for file" << fileName << "will set STATUS_NEW"; - status.set(SyncFileStatus::STATUS_NEW); - } - } - - if (rec.isValid() && rec._remotePerm.contains("S")) - status.setSharedWithMe(true); - - if (status.tag() == SyncFileStatus::STATUS_NEW) { - // check the parent folder if it is shared and if it is allowed to create a file/dir within - QDir d( fi.path() ); - auto parentPath = d.path(); - auto dirRec = folder->journalDb()->getFileRecord(parentPath); - bool isDir = type == CSYNC_FTW_TYPE_DIR; - while( !d.isRoot() && !(d.exists() && dirRec.isValid()) ) { - d.cdUp(); // returns true if the dir exists. - - parentPath = d.path(); - // cut the folder path - dirRec = folder->journalDb()->getFileRecord(parentPath); - - isDir = true; - } - if( dirRec.isValid() && !dirRec._remotePerm.isNull()) { - if( (isDir && !dirRec._remotePerm.contains("K")) - || (!isDir && !dirRec._remotePerm.contains("C")) ) { - status.set(SyncFileStatus::STATUS_ERROR); - } - } - } - return status; -} - - } // namespace OCC - diff --git a/src/libsync/CMakeLists.txt b/src/libsync/CMakeLists.txt index ca56c3e4e0..328d538011 100644 --- a/src/libsync/CMakeLists.txt +++ b/src/libsync/CMakeLists.txt @@ -56,6 +56,7 @@ set(libsync_SRCS propagateremotemkdir.cpp syncengine.cpp syncfilestatus.cpp + syncfilestatustracker.cpp syncjournaldb.cpp syncjournalfilerecord.cpp syncresult.cpp diff --git a/src/libsync/syncengine.cpp b/src/libsync/syncengine.cpp index 6e238cfa13..44864d9998 100644 --- a/src/libsync/syncengine.cpp +++ b/src/libsync/syncengine.cpp @@ -93,6 +93,7 @@ SyncEngine::SyncEngine(AccountPtr account, const QString& localPath, csync_create(&_csync_ctx, localPath.toUtf8().data(), url_string.toUtf8().data()); csync_init(_csync_ctx); _excludedFiles.reset(new ExcludedFiles(&_csync_ctx->excludes)); + _syncFileStatusTracker.reset(new SyncFileStatusTracker(this)); _thread.setObjectName("SyncEngine_Thread"); } diff --git a/src/libsync/syncengine.h b/src/libsync/syncengine.h index b35cbe31fa..f78dad06bb 100644 --- a/src/libsync/syncengine.h +++ b/src/libsync/syncengine.h @@ -35,7 +35,7 @@ #include "syncfileitem.h" #include "progressdispatcher.h" #include "utility.h" -#include "syncfilestatus.h" +#include "syncfilestatustracker.h" #include "accountfwd.h" #include "discoveryphase.h" #include "checksums.h" @@ -75,10 +75,12 @@ public: * -1 means infinite */ void setNewBigFolderSizeLimit(qint64 limit) { _newBigFolderSizeLimit = limit; } + bool ignoreHiddenFiles() const { return _csync_ctx->ignore_hidden_files; } void setIgnoreHiddenFiles(bool ignore) { _csync_ctx->ignore_hidden_files = ignore; } ExcludedFiles &excludedFiles() { return *_excludedFiles; } Utility::StopWatch &stopWatch() { return _stopWatch; } + SyncFileStatusTracker &syncFileStatusTracker() { return *_syncFileStatusTracker; } /* Return true if we detected that another sync is needed to complete the sync */ bool isAnotherSyncNeeded() { return _anotherSyncNeeded; } @@ -93,7 +95,7 @@ public: AccountPtr account() const; SyncJournalDb *journal() const { return _journal; } - + QString localPath() const { return _localPath; } /** * Minimum age, in milisecond, of a file that can be uploaded. * Files more recent than that are not going to be uploaeded as they are considered @@ -211,6 +213,7 @@ private: QScopedPointer _progressInfo; QScopedPointer _excludedFiles; + QScopedPointer _syncFileStatusTracker; Utility::StopWatch _stopWatch; // maps the origin and the target of the folders that have been renamed diff --git a/src/libsync/syncfilestatustracker.cpp b/src/libsync/syncfilestatustracker.cpp new file mode 100644 index 0000000000..e88459ba41 --- /dev/null +++ b/src/libsync/syncfilestatustracker.cpp @@ -0,0 +1,230 @@ +/* + * Copyright (C) by Klaas Freitag + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "syncfilestatustracker.h" +#include "filesystem.h" +#include "syncengine.h" +#include "syncjournaldb.h" +#include "syncjournalfilerecord.h" +#include "utility.h" + +#include +#include + +namespace OCC { + +/** + * Whether this item should get an ERROR icon through the Socket API. + * + * The Socket API should only present serious, permanent errors to the user. + * In particular SoftErrors should just retain their 'needs to be synced' + * icon as the problem is most likely going to resolve itself quickly and + * automatically. + */ +static bool showErrorInSocketApi(const SyncFileItem& item) +{ + const auto status = item._status; + return status == SyncFileItem::NormalError + || status == SyncFileItem::FatalError; +} + +static void addErroredSyncItemPathsToList(const SyncFileItemVector& items, QSet* set) { + foreach (const SyncFileItemPtr &item, items) { + if (showErrorInSocketApi(*item)) { + set->insert(item->_file); + } + } +} + +SyncFileStatusTracker::SyncFileStatusTracker(SyncEngine *syncEngine) + : _syncEngine(syncEngine) +{ + connect(syncEngine, SIGNAL(treeWalkResult(const SyncFileItemVector&)), + this, SLOT(slotThreadTreeWalkResult(const SyncFileItemVector&))); + connect(syncEngine, SIGNAL(aboutToPropagate(SyncFileItemVector&)), + this, SLOT(slotAboutToPropagate(SyncFileItemVector&))); + connect(syncEngine, SIGNAL(finished(bool)), SLOT(slotSyncFinished())); + connect(syncEngine, SIGNAL(itemCompleted(const SyncFileItem &, const PropagatorJob &)), + this, SLOT(slotItemCompleted(const SyncFileItem &))); +} + +bool SyncFileStatusTracker::estimateState(QString fn, csync_ftw_type_e t, SyncFileStatus* s) +{ + if (t == CSYNC_FTW_TYPE_DIR) { + if (Utility::doesSetContainPrefix(_stateLastSyncItemsWithError, fn)) { + qDebug() << Q_FUNC_INFO << "Folder has error" << fn; + s->set(SyncFileStatus::STATUS_ERROR); + return true; + } + // If sync is running, check _syncedItems, possibly give it STATUS_EVAL (=syncing down) + if (_syncEngine->isSyncRunning()) { + if (_syncEngine->estimateState(fn, t, s)) { + return true; + } + } + return false; + } else if ( t== CSYNC_FTW_TYPE_FILE) { + // check if errorList has the directory/file + if (Utility::doesSetContainPrefix(_stateLastSyncItemsWithError, fn)) { + s->set(SyncFileStatus::STATUS_ERROR); + return true; + } + // If sync running: _syncedItems -> SyncingState + if (_syncEngine->isSyncRunning()) { + if (_syncEngine->estimateState(fn, t, s)) { + return true; + } + } + } + return false; +} + + +/** + * Get status about a single file. + */ +SyncFileStatus SyncFileStatusTracker::fileStatus(const QString& systemFileName) +{ + QString file = _syncEngine->localPath(); + QString fileName = systemFileName.normalized(QString::NormalizationForm_C); + QString fileNameSlash = fileName; + + if(fileName != QLatin1String("/") && !fileName.isEmpty()) { + file += fileName; + } + + if( fileName.endsWith(QLatin1Char('/')) ) { + fileName.truncate(fileName.length()-1); + qDebug() << "Removed trailing slash: " << fileName; + } else { + fileNameSlash += QLatin1Char('/'); + } + + const QFileInfo fi(file); + if( !FileSystem::fileExists(file, fi) ) { + qDebug() << "OO File " << file << " is not existing"; + return SyncFileStatus(SyncFileStatus::STATUS_STAT_ERROR); + } + + // file is ignored? + // Qt considers .lnk files symlinks on Windows so we need to work + // around that here. + if( fi.isSymLink() +#ifdef Q_OS_WIN + && fi.suffix() != "lnk" +#endif + ) { + return SyncFileStatus(SyncFileStatus::STATUS_IGNORE); + } + + csync_ftw_type_e type = CSYNC_FTW_TYPE_FILE; + if( fi.isDir() ) { + type = CSYNC_FTW_TYPE_DIR; + } + + // Is it excluded? + if( _syncEngine->excludedFiles().isExcluded(file, _syncEngine->localPath(), _syncEngine->ignoreHiddenFiles()) ) { + return SyncFileStatus(SyncFileStatus::STATUS_IGNORE); + } + + // Error if it is in the selective sync blacklist + foreach(const auto &s, _syncEngine->journal()->getSelectiveSyncList(SyncJournalDb::SelectiveSyncBlackList)) { + if (fileNameSlash.startsWith(s)) { + return SyncFileStatus(SyncFileStatus::STATUS_ERROR); + } + } + + SyncFileStatus status(SyncFileStatus::STATUS_NONE); + SyncJournalFileRecord rec = _syncEngine->journal()->getFileRecord(fileName ); + + if (estimateState(fileName, type, &status)) { + qDebug() << "Folder estimated status for" << fileName << "to" << status.toSocketAPIString(); + } else if (fileName == "") { + // sync folder itself + // FIXME: The new parent folder logic should take over this, treating the root the same as any folder. + } else if (type == CSYNC_FTW_TYPE_DIR) { + if (rec.isValid()) { + status.set(SyncFileStatus::STATUS_UPTODATE); + } else { + qDebug() << "Could not determine state for folder" << fileName << "will set STATUS_NEW"; + status.set(SyncFileStatus::STATUS_NEW); + } + } else if (type == CSYNC_FTW_TYPE_FILE) { + if (rec.isValid()) { + if( FileSystem::getModTime(fi.absoluteFilePath()) == Utility::qDateTimeToTime_t(rec._modtime) ) { + status.set(SyncFileStatus::STATUS_UPTODATE); + } else { + if (rec._remotePerm.isNull() || rec._remotePerm.contains("W") ) { + status.set(SyncFileStatus::STATUS_EVAL); + } else { + status.set(SyncFileStatus::STATUS_ERROR); + } + } + } else { + qDebug() << "Could not determine state for file" << fileName << "will set STATUS_NEW"; + status.set(SyncFileStatus::STATUS_NEW); + } + } + + if (rec.isValid() && rec._remotePerm.contains("S")) + status.setSharedWithMe(true); + + if (status.tag() == SyncFileStatus::STATUS_NEW) { + // check the parent folder if it is shared and if it is allowed to create a file/dir within + QDir d( fi.path() ); + auto parentPath = d.path(); + auto dirRec = _syncEngine->journal()->getFileRecord(parentPath); + bool isDir = type == CSYNC_FTW_TYPE_DIR; + while( !d.isRoot() && !(d.exists() && dirRec.isValid()) ) { + d.cdUp(); // returns true if the dir exists. + + parentPath = d.path(); + // cut the folder path + dirRec = _syncEngine->journal()->getFileRecord(parentPath); + + isDir = true; + } + if( dirRec.isValid() && !dirRec._remotePerm.isNull()) { + if( (isDir && !dirRec._remotePerm.contains("K")) + || (!isDir && !dirRec._remotePerm.contains("C")) ) { + status.set(SyncFileStatus::STATUS_ERROR); + } + } + } + return status; +} + +void SyncFileStatusTracker::slotThreadTreeWalkResult(const SyncFileItemVector& items) +{ + addErroredSyncItemPathsToList(items, &_stateLastSyncItemsWithErrorNew); +} + +void SyncFileStatusTracker::slotAboutToPropagate(SyncFileItemVector& items) +{ + addErroredSyncItemPathsToList(items, &_stateLastSyncItemsWithErrorNew); +} + +void SyncFileStatusTracker::slotSyncFinished() +{ + _stateLastSyncItemsWithError = _stateLastSyncItemsWithErrorNew; + _stateLastSyncItemsWithErrorNew.clear(); +} + +void SyncFileStatusTracker::slotItemCompleted(const SyncFileItem &item) +{ + if (showErrorInSocketApi(item)) { + _stateLastSyncItemsWithErrorNew.insert(item._file); + } +} + +} diff --git a/src/libsync/syncfilestatustracker.h b/src/libsync/syncfilestatustracker.h new file mode 100644 index 0000000000..ac8a8233c6 --- /dev/null +++ b/src/libsync/syncfilestatustracker.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) by Klaas Freitag + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#ifndef SYNCFILESTATUSTRACKER_H +#define SYNCFILESTATUSTRACKER_H + +#include "ownsql.h" +#include "syncfileitem.h" +#include "syncfilestatus.h" +#include +#include + +namespace OCC { + +class SyncEngine; + +class OWNCLOUDSYNC_EXPORT SyncFileStatusTracker : public QObject +{ +public: + SyncFileStatusTracker(SyncEngine *syncEngine); + SyncFileStatus fileStatus(const QString& systemFileName); + +private slots: + void slotThreadTreeWalkResult(const SyncFileItemVector& items); + void slotAboutToPropagate(SyncFileItemVector& items); + void slotSyncFinished(); + void slotItemCompleted(const SyncFileItem &item); + +private: + bool estimateState(QString fn, csync_ftw_type_e t, SyncFileStatus* s); + + SyncEngine *_syncEngine; + // SocketAPI: Cache files and folders that had errors so that they can + // get a red ERROR icon. + QSet _stateLastSyncItemsWithErrorNew; // gets moved to _stateLastSyncItemsWithError at end of sync + QSet _stateLastSyncItemsWithError; +}; + +} + +#endif