diff --git a/src/libcommon/utility/sourcelocation.h b/src/libcommon/utility/sourcelocation.h new file mode 100644 index 000000000..54eef77c2 --- /dev/null +++ b/src/libcommon/utility/sourcelocation.h @@ -0,0 +1,81 @@ +/* + * Infomaniak kDrive - Desktop + * Copyright (C) 2023-2024 Infomaniak Network SA + * + * 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, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#if defined(_WIN32) +// || defined(__APPLE__) still buggy on macOS +// https://www.reddit.com/r/cpp/comments/1b1pjii/comment/ksg8efc/?utm_source=share&utm_medium=web3x&utm_name=web3xcss&utm_term=1&utm_content=share_button +#define SRC_LOC_AVALAIBALE +#endif + +#ifdef SRC_LOC_AVALAIBALE +#include +#endif // SRC_LOC_AVALAIBALE + +#include +#include + +namespace KDC { + +class SourceLocation { + public: + constexpr SourceLocation() = default; +#ifdef SRC_LOC_AVALAIBALE + [[nodiscard]] static consteval SourceLocation currentLoc( + const std::source_location& loc = std::source_location::current()) { + SourceLocation result; + result._line = loc.line(); + result._fileName = loc.file_name(); + result._functionName = loc.function_name(); + return result; + } +#else +#define currentLoc() \ + currentLocCompatibility(__LINE__, __FILE__, \ + "") // Cannot be used as a default argument as it will be evaluated at the definition site. + [[nodiscard]] static consteval SourceLocation currentLocCompatibility(uint32_t line, const char* file, + const char* function) { + SourceLocation result; + result._line = line; + result._fileName = file; + result._functionName = function; + return result; + } +#endif // SRC_LOC_AVALAIBALE + + [[nodiscard]] uint32_t line() const { return _line; } + [[nodiscard]] std::string fileName() const { return std::filesystem::path(_fileName).filename().string(); } + [[nodiscard]] std::string functionName() const { + std::string str(_functionName); + auto firstParenthesis = str.find_first_of('('); + str = firstParenthesis != std::string::npos + ? str.substr(0, firstParenthesis) + : str; // "namespace::class::function(namespace::args)" -> "namespace::class::function" + auto lastColon = str.find_last_of(':'); + return lastColon != std::string::npos ? str.substr(lastColon + 1) : str; // "namespace::class::function" -> "function" + } + + private: + uint32_t _line = 0; + const char* _fileName = ""; + const char* _functionName = ""; +}; + +} // namespace KDC +// namespace KDC diff --git a/src/libcommon/utility/types.h b/src/libcommon/utility/types.h index 7f16bf1d9..f54e3880c 100644 --- a/src/libcommon/utility/types.h +++ b/src/libcommon/utility/types.h @@ -15,7 +15,6 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - #pragma once #include @@ -28,6 +27,7 @@ #include #include #include +#include "sourcelocation.h" namespace KDC { @@ -230,25 +230,36 @@ enum class ExitCause { MoveToTrashFailed, InvalidName, LiteSyncNotAllowed, + NotPlaceHolder, NetworkTimeout, SocketsDefuncted, // macOS: sockets defuncted by kernel NotFound, QuotaExceeded, FullListParsingError, OperationCanceled, - ShareLinkAlreadyExists + ShareLinkAlreadyExists, + InvalidArgument }; std::string toString(ExitCause e); struct ExitInfo { ExitInfo() = default; - constexpr ExitInfo(const ExitCode &code, const ExitCause &cause) : _code(code), _cause(cause) {} - ExitInfo(const ExitCode &code) : _code(code) {} + constexpr ExitInfo(const ExitCode &code, const ExitCause &cause, + const SourceLocation srcLoc = SourceLocation::currentLoc()) : + _code(code), + _cause(cause), _srcLoc(srcLoc) {} + + ExitInfo(const ExitCode &code, const SourceLocation srcLoc = SourceLocation::currentLoc()) : + _code(code), _srcLoc(srcLoc) {} + const ExitCode &code() const { return _code; } const ExitCause &cause() const { return _cause; } operator ExitCode() const { return _code; } operator ExitCause() const { return _cause; } - explicit operator std::string() const { return "ExitInfo{" + toString(code()) + ", " + toString(cause()) + "}"; } + explicit operator std::string() const { + // Example: "ExitInfo{SystemError-NotFound from (file.cpp:42[functionName])}" + return "ExitInfo{" + toString(code()) + "-" + toString(cause()) + srcLocStr() + "}"; + } constexpr operator bool() const { return _code == ExitCode::Ok; } constexpr explicit operator int() const { return toInt(_code) * 100 + toInt(_cause); } constexpr bool operator==(const ExitInfo &other) const { return _code == other._code && _cause == other._cause; } @@ -256,6 +267,13 @@ struct ExitInfo { private: ExitCode _code{ExitCode::Unknown}; ExitCause _cause{ExitCause::Unknown}; + SourceLocation _srcLoc; + + std::string srcLocStr() const { + if (_code == ExitCode::Ok) return ""; + return " from (" + _srcLoc.fileName() + ":" + std::to_string(_srcLoc.line()) + + (!_srcLoc.functionName().empty() ? "[" + _srcLoc.functionName() + "]" : ""); + } }; std::string toString(ExitInfo e); diff --git a/src/libcommonserver/CMakeLists.txt b/src/libcommonserver/CMakeLists.txt index 2ffa385b4..77fe4a057 100644 --- a/src/libcommonserver/CMakeLists.txt +++ b/src/libcommonserver/CMakeLists.txt @@ -11,6 +11,8 @@ if (UNIX AND CMAKE_BUILD_TYPE MATCHES "RelWithDebInfo") endif () find_package(libzip 1.10.1 REQUIRED) +set(CMAKE_AUTOMOC TRUE) + add_definitions(-DUNICODE) add_definitions(-D_UNICODE) @@ -34,6 +36,9 @@ set(libcommonserver_SRCS # Io io/filestat.h io/iohelper.h io/iohelper.cpp + # Vfs + vfs.h vfs.cpp + plugin.h plugin.cpp ) if(APPLE) diff --git a/src/libcommonserver/vfs.cpp b/src/libcommonserver/vfs.cpp index 3027c1d6c..f7bd779d4 100644 --- a/src/libcommonserver/vfs.cpp +++ b/src/libcommonserver/vfs.cpp @@ -32,10 +32,51 @@ using namespace KDC; -Vfs::Vfs(VfsSetupParams &vfsSetupParams, QObject *parent) : +Vfs::Vfs(const VfsSetupParams &vfsSetupParams, QObject *parent) : QObject(parent), _vfsSetupParams(vfsSetupParams), _extendedLog(false), _started(false) {} -Vfs::~Vfs() {} +void Vfs::starVfsWorkers() { + // Start hydration/dehydration workers + // !!! Disabled for testing because no QEventLoop !!! + if (qApp) { + // Start worker threads + for (int i = 0; i < nbWorkers; i++) { + for (int j = 0; j < s_nb_threads[i]; j++) { + auto *workerThread = new QtLoggingThread(); + _workerInfo[i]._threadList.append(workerThread); + auto *worker = new VfsWorker(this, i, j, logger()); + worker->moveToThread(workerThread); + connect(workerThread, &QThread::started, worker, &VfsWorker::start); + connect(workerThread, &QThread::finished, worker, &QObject::deleteLater); + connect(workerThread, &QThread::finished, workerThread, &QObject::deleteLater); + workerThread->start(); + } + } + } +} + +Vfs::~Vfs() { + // Ask worker threads to stop + for (auto &worker: _workerInfo) { + worker._mutex.lock(); + worker._stop = true; + worker._mutex.unlock(); + worker._queueWC.wakeAll(); + } + + // Force threads to stop if needed + for (auto &worker: _workerInfo) { + for (QThread *thread: qAsConst(worker._threadList)) { + if (thread) { + thread->quit(); + if (!thread->wait(1000)) { + thread->terminate(); + thread->wait(); + } + } + } + } +} QString Vfs::modeToString(KDC::VirtualFileMode virtualFileMode) { // Note: Strings are used for config and must be stable @@ -67,13 +108,13 @@ KDC::VirtualFileMode Vfs::modeFromString(const QString &str) { return {}; } -bool Vfs::start(bool &installationDone, bool &activationDone, bool &connectionDone) { +ExitInfo Vfs::start(bool &installationDone, bool &activationDone, bool &connectionDone) { if (!_started) { - _started = startImpl(installationDone, activationDone, connectionDone); - return _started; + ExitInfo exitInfo = startImpl(installationDone, activationDone, connectionDone); + _started = exitInfo.code() == ExitCode::Ok; + return exitInfo; } - - return true; + return ExitCode::Ok; } void Vfs::stop(bool unregister) { @@ -83,34 +124,105 @@ void Vfs::stop(bool unregister) { } } -VfsOff::VfsOff(VfsSetupParams &vfsSetupParams, QObject *parent) : Vfs(vfsSetupParams, parent) {} - -VfsOff::~VfsOff() {} +ExitInfo Vfs::handleVfsError(const SyncPath &itemPath, const SourceLocation location) const { + if (ExitInfo exitInfo = checkIfPathExists(itemPath, true, location); !exitInfo) { + return exitInfo; + } + return defaultVfsError(location); +} -bool VfsOff::forceStatus(const QString &path, bool isSyncing, int /*progress*/, bool /*isHydrated*/) { - KDC::SyncPath fullPath(_vfsSetupParams._localPath / QStr2Path(path)); +ExitInfo Vfs::checkIfPathExists(const SyncPath &itemPath, bool shouldExist, const SourceLocation location) const { + if (itemPath.empty()) { + LOGW_WARN(logger(), L"Empty path"); + assert(false && "Empty path in a VFS call"); + return {ExitCode::SystemError, ExitCause::NotFound, location}; + } bool exists = false; - KDC::IoError ioError = KDC::IoError::Success; - if (!KDC::IoHelper::checkIfPathExists(fullPath, exists, ioError)) { - LOGW_WARN(logger(), L"Error in IoHelper::checkIfPathExists: " << KDC::Utility::formatIoError(fullPath, ioError).c_str()); - return false; + IoError ioError = IoError::Unknown; + if (!IoHelper::checkIfPathExists(itemPath, exists, ioError)) { + LOGW_WARN(logger(), L"Error in IoHelper::checkIfPathExists: " << Utility::formatIoError(itemPath, ioError)); + return {ExitCode::SystemError, location}; + } + if (ioError == IoError::AccessDenied) { + LOGW_WARN(logger(), L"File access error: " << Utility::formatIoError(itemPath, ioError)); + return {ExitCode::SystemError, ExitCause::FileAccessError, location}; } + if (exists != shouldExist) { + if (shouldExist) { + LOGW_DEBUG(logger(), L"File doesn't exist: " << Utility::formatSyncPath(itemPath)); + return {ExitCode::SystemError, ExitCause::NotFound, location}; + } else { + LOGW_DEBUG(logger(), L"File already exists: " << Utility::formatSyncPath(itemPath)); + return {ExitCode::SystemError, ExitCause::FileAlreadyExist, location}; + } + } + return ExitCode::Ok; +} + +VfsWorker::VfsWorker(Vfs *vfs, int type, int num, log4cplus::Logger logger) : + _vfs(vfs), _type(type), _num(num), _logger(logger) {} - if (!exists) { - LOGW_DEBUG(logger(), L"Item does not exist anymore - path=" << Path2WStr(fullPath).c_str()); - return true; +void VfsWorker::start() { + LOG_DEBUG(logger(), "Worker with type=" << _type << " and num=" << _num << " started"); + + WorkerInfo &workerInfo = _vfs->_workerInfo[_type]; + + forever { + workerInfo._mutex.lock(); + while (workerInfo._queue.empty() && !workerInfo._stop) { + LOG_DEBUG(logger(), "Worker with type=" << _type << " and num=" << _num << " waiting"); + workerInfo._queueWC.wait(&workerInfo._mutex); + } + + if (workerInfo._stop) { + workerInfo._mutex.unlock(); + break; + } + + QString path = workerInfo._queue.back(); + workerInfo._queue.pop_back(); + workerInfo._mutex.unlock(); + + LOG_DEBUG(logger(), "Worker with type=" << _type << " and num=" << _num << " working"); + + switch (_type) { + case workerHydration: + _vfs->hydrate(path); + break; + case workerDehydration: + _vfs->dehydrate(path); + break; + default: + LOG_ERROR(logger(), "Unknown vfs worker type=" << _type); + break; + } } + LOG_DEBUG(logger(), "Worker with type=" << _type << " and num=" << _num << " ended"); +} + +VfsOff::VfsOff(QObject *parent) : Vfs(VfsSetupParams(), parent) {} + +VfsOff::VfsOff(VfsSetupParams &vfsSetupParams, QObject *parent) : Vfs(vfsSetupParams, parent) {} + +VfsOff::~VfsOff() {} + +ExitInfo VfsOff::forceStatus(const SyncPath &pathStd, bool isSyncing, int /*progress*/, bool /*isHydrated*/) { + QString path = SyncName2QStr(pathStd.native()); + KDC::SyncPath fullPath(_vfsSetupParams._localPath / QStr2Path(path)); + if (ExitInfo exitInfo = checkIfPathExists(fullPath, true); !exitInfo) { + return exitInfo; + } // Update Finder LOGW_DEBUG(logger(), L"Send status to the Finder extension for file/directory " << Path2WStr(fullPath).c_str()); QString status = isSyncing ? "SYNC" : "OK"; _vfsSetupParams._executeCommand(QString("STATUS:%1:%2").arg(status, path).toStdString().c_str()); - return true; + return ExitCode::Ok; } -bool VfsOff::startImpl(bool &, bool &, bool &) { - return true; +ExitInfo VfsOff::startImpl(bool &, bool &, bool &) { + return ExitCode::Ok; } static QString modeToPluginName(KDC::VirtualFileMode virtualFileMode) { diff --git a/src/libcommonserver/vfs.h b/src/libcommonserver/vfs.h index 985f5ccbf..28a6c0b7a 100644 --- a/src/libcommonserver/vfs.h +++ b/src/libcommonserver/vfs.h @@ -18,31 +18,49 @@ #pragma once +#include "libcommon/utility/utility.h" #include "libcommon/utility/types.h" #include "libsyncengine/progress/syncfileitem.h" +#include "libcommon/utility/sourcelocation.h" #include +#include #include #include #include +#include +#include +#include +#include #include #include -namespace KDC { +constexpr short nbWorkers = 2; +constexpr short workerHydration = 0; +constexpr short workerDehydration = 1; +namespace KDC { struct VfsSetupParams { int _syncDbId; int _driveId; int _userId; - std::filesystem::path _localPath; - std::filesystem::path _targetPath; + SyncPath _localPath; + SyncPath _targetPath; std::string _namespaceCLSID; KDC::ExecuteCommand _executeCommand; log4cplus::Logger _logger; }; +struct WorkerInfo { + QMutex _mutex; + std::deque _queue; + QWaitCondition _queueWC; + bool _stop = false; + QList _threadList; +}; + /** Interface describing how to deal with virtual/placeholder files. * * There are different ways of representing files locally that will only @@ -59,12 +77,13 @@ class Vfs : public QObject { Q_OBJECT public: + std::array _workerInfo; static QString modeToString(KDC::VirtualFileMode virtualFileMode); static KDC::VirtualFileMode modeFromString(const QString &str); - explicit Vfs(VfsSetupParams &vfsSetupParams, QObject *parent = nullptr); + explicit Vfs(const VfsSetupParams &vfsSetupParams, QObject *parent = nullptr); - virtual ~Vfs(); + ~Vfs() override; inline void setSyncFileStatusCallback(void (*syncFileStatus)(int, const KDC::SyncPath &, KDC::SyncFileStatus &)) { _syncFileStatus = syncFileStatus; @@ -82,8 +101,11 @@ class Vfs : public QObject { /** Initializes interaction with the VFS provider. * * The plugin-specific work is done in startImpl(). + * Possible return values are: + * - ExitCode::Ok: Everything went fine. + * - ExitCode::LiteSyncError, ExitCause::UnableToCreateVfs: The VFS provider could not be started. */ - bool start(bool &installationDone, bool &activationDone, bool &connectionDone); + ExitInfo start(bool &installationDone, bool &activationDone, bool &connectionDone); /// Stop interaction with VFS provider. Like when the client application quits. /// Also deregister the folder with the sync provider, like when a folder is removed. @@ -96,71 +118,105 @@ class Vfs : public QObject { */ virtual bool socketApiPinStateActionsShown() const = 0; - /** Return true when download of a file's data is currently ongoing. - * - * See also the beginHydrating() and doneHydrating() signals. - */ - virtual bool isHydrating() const = 0; - - /** Update placeholder metadata during discovery. + /** Update placeholder metadata. * * If the remote metadata changes, the local placeholder's metadata should possibly * change as well. * - * Returning false and setting error indicates an error. + * Possible return values are: + * - ExitCode::Ok: Everything went fine, the metadata was updated. + * - ExitCode::LogicError, ExitCause::Unknown: The liteSync connector is not initialized. + * - ExitCode::SystemError, ExitCause::Unknown: An unknown error occurred. + * - ExitCode::SystemError, ExitCause::NotFoud: The item could not be found. + * - ExitCode::SystemError, ExitCause::FileAccessError: Missing permissions on the item ot the item is locked. */ - virtual bool updateMetadata(const QString &filePath, time_t creationTime, time_t modtime, qint64 size, - const QByteArray &fileId, QString *error) = 0; + virtual ExitInfo updateMetadata(const SyncPath &filePath, time_t creationTime, time_t modtime, int64_t size, + const NodeId &fileId) = 0; - /// Create a new dehydrated placeholder - virtual bool createPlaceholder(const KDC::SyncPath &relativeLocalPath, const KDC::SyncFileItem &item) = 0; + /** Create a new dehydrated placeholder + * + * Possible return values are: + * - ExitCode::Ok: Everything went fine, the placeholder was created. + * - ExitCode::LogicError, ExitCause::InvalidArgument: relativeLocalPath is empty or item.remoteNodeId is not set. + * - ExitCode::SystemError, ExitCause::Unknown: An unknown error occurred. + * - ExitCode::SystemError, ExitCause::NotFoud: The parent folder does not exist. + * - ExitCode::SystemError, ExitCause::FileAccessError: Missing permissions on the destination folder or it is + * locked. + * - ExitCode::SystemError, ExitCause::FileAlreadyExist: An item with the same name already exists in the destination + * folder. + */ + virtual ExitInfo createPlaceholder(const SyncPath &relativeLocalPath, const SyncFileItem &item) = 0; /** Convert a hydrated placeholder to a dehydrated one. Called from PropagateDownlaod. * * This is different from delete+create because preserving some file metadata * (like pin states) may be essential for some vfs plugins. - */ - virtual bool dehydratePlaceholder(const QString &path) = 0; - - /** Discovery hook: even unchanged files may need UPDATE_METADATA. * - * For instance cfapi vfs wants local hydrated non-placeholder files to - * become hydrated placeholder files. + * * Possible return values are: + * - ExitCode::Ok: Everything went fine, the placeholder is dehydrating (async). + * - ExitCode::LogicError, ExitCause::InvalidArgument: The provided path is empty. + * - ExitCode::SystemError, ExitCause::Unknown: An unknown error occurred. + * - ExitCode::SystemError, ExitCause::NotFoud: The item could not be found. + * - ExitCode::SystemError, ExitCause::FileAccessError: Missing permissions on the item ot the item is locked. + * - ExitCode::SystemError, ExitCause::NotPlaceHolder: The item is not a placeholder. + * folder. */ - virtual bool needsMetadataUpdate(const KDC::SyncFileItem &item) = 0; + virtual ExitInfo dehydratePlaceholder(const SyncPath &path) = 0; /** Convert a new file to a hydrated placeholder. * * Some VFS integrations expect that every file, including those that have all * the remote data, are "placeholders". - * to convert newly downloaded, fully hydrated files into placeholders. * * Implementations must make sure that calling this function on a file that already * is a placeholder is acceptable. * - * replacesFile can optionally contain a filesystem path to a placeholder that this - * new placeholder shall supersede, for rename-replace actions with new downloads, - * for example. + * * Possible return values are: + * - ExitCode::Ok: Everything went fine, the file is now a placeholder. + * - ExitCode::LogicError, ExitCause::InvalidArgument: item.localNodeId is not set. + * - ExitCode::SystemError, ExitCause::Unknown: An unknown error occurred. + * - ExitCode::SystemError, ExitCause::NotFoud: The item could not be found. + * - ExitCode::SystemError, ExitCause::FileAccessError: Missing permissions on the item ot the item is locked. + */ + virtual ExitInfo convertToPlaceholder(const SyncPath &path, const KDC::SyncFileItem &item) = 0; + + /** Update the fetch status of a file. + * + * This is used to update the progress of a file download in the OS file UI. + * + * * Possible return values are: + * - ExitCode::Ok: Everything went fine, the fetch status was updated. + * - ExitCode::SystemError, ExitCause::Unknown: An unknown error occurred. + * - ExitCode::SystemError, ExitCause::NotFoud: The item could not be found. + * - ExitCode::SystemError, ExitCause::FileAccessError: Missing permissions on the item ot the item is locked (The item is + * the file in the sync folder, any error on the tmpItem will lead to SystemError, Unknown). */ - virtual bool convertToPlaceholder(const QString &path, const KDC::SyncFileItem &item) = 0; + virtual ExitInfo updateFetchStatus(const SyncPath &tmpPath, const SyncPath &path, int64_t received, bool &canceled, + bool &finished) = 0; - virtual bool updateFetchStatus(const QString &tmpPath, const QString &path, qint64 received, bool &canceled, - bool &finished) = 0; + /** Force the status of a file. + * + * This is used to force the sync status of a file (isSyncing or not) + * + * * Possible return values are: + * - ExitCode::Ok: Everything went fine, the status was updated. + * - ExitCode::SystemError, ExitCause::Unknown: An unknown error occurred. + * - ExitCode::SystemError, ExitCause::NotFoud: The item could not be found. + * - ExitCode::SystemError, ExitCause::FileAccessError: Missing permissions on the item ot the item is locked. + */ + virtual ExitInfo forceStatus(const SyncPath &path, bool isSyncing, int progress, bool isHydrated = false) = 0; - virtual bool forceStatus(const QString &path, bool isSyncing, int progress, bool isHydrated = false) = 0; virtual bool cleanUpStatuses() { return true; }; - /// Determine whether the file at the given absolute path is a dehydrated placeholder. - virtual bool isDehydratedPlaceholder(const QString &filePath, bool isAbsolutePath = false) = 0; - - /** Similar to isDehydratedPlaceholder() but used from sync discovery. - * - * This function shall set stat->type if appropriate. - * It may rely on stat->path and stat_data (platform specific data). + /** Determine whether the file at the given path is a dehydrated placeholder. * - * Returning true means that type was fully determined. + * * Possible return values are: + * - ExitCode::Ok: Everything went fine, isDehydrated is set to true if the file is a dehydrated placeholder. + * - ExitCode::SystemError, ExitCause::Unknown: An unknown error occurred. + * - ExitCode::SystemError, ExitCause::NotFoud: The item could not be found. + * - ExitCode::SystemError, ExitCause::FileAccessError: Missing permissions on the item ot the item is locked. */ - // virtual bool statTypeVirtualFile(csync_file_stat_t *stat, void *stat_data, const QString &fileDirectory) = 0; + virtual ExitInfo isDehydratedPlaceholder(const SyncPath &filePath, bool &isDehydrated, bool isAbsolutePath = false) = 0; /** Sets the pin state for the item at a path. * @@ -170,8 +226,14 @@ class Vfs : public QObject { * but some vfs plugins will store the pin state in file attributes instead. * * fileRelativePath is relative to the sync folder. Can be "" for root folder. + * + * * Possible return values are: + * - ExitCode::Ok: Everything went fine, the pin state was updated. + * - ExitCode::SystemError, ExitCause::Unknown: An unknown error occurred. + * - ExitCode::SystemError, ExitCause::NotFoud: The item could not be found. + * - ExitCode::SystemError, ExitCause::FileAccessError: Missing permissions on the item ot the item is locked. */ - virtual bool setPinState(const QString &fileRelativePath, KDC::PinState state) = 0; + virtual ExitInfo setPinState(const SyncPath &fileRelativePath, KDC::PinState state) = 0; /** Returns the pin state of an item at a path. * @@ -182,31 +244,64 @@ class Vfs : public QObject { * * Returns none on retrieval error. */ - virtual KDC::PinState pinState(const QString &fileRelativePath) = 0; - virtual bool status(const QString &filePath, bool &isPlaceholder, bool &isHydrated, bool &isSyncing, int &progress) = 0; + virtual KDC::PinState pinState(const SyncPath &fileRelativePath) = 0; - virtual bool setThumbnail(const QString &filePath, const QPixmap &pixmap) = 0; + /** Returns the status of a file. + * + * * Possible return values are: + * - ExitCode::Ok: Everything went fine, the status was retrieved. + * - ExitCode::SystemError, ExitCause::Unknown: An unknown error occurred. + * - ExitCode::SystemError, ExitCause::NotFoud: The item could not be found. + * - ExitCode::SystemError, ExitCause::FileAccessError: Missing permissions on the item ot the item is locked. + */ + virtual ExitInfo status(const SyncPath &filePath, bool &isPlaceholder, bool &isHydrated, bool &isSyncing, + int &progress) = 0; - virtual bool setAppExcludeList() = 0; + /** Set the thumbnail for a file. + * + * * Possible return values are: + * - ExitCode::Ok: Everything went fine, the status was retrieved. + * - ExitCode::SystemError, ExitCause::Unknown: An unknown error occurred. + * - ExitCode::SystemError, ExitCause::NotFoud: The item could not be found. + * - ExitCode::SystemError, ExitCause::FileAccessError: Missing permissions on the item ot the item is locked. + */ + virtual ExitInfo setThumbnail(const SyncPath &filePath, const QPixmap &pixmap) = 0; - virtual bool getFetchingAppList(QHash &appTable) = 0; + /** Set the list of applications that should not be hydrated. + * + * * Possible return values are: + * - ExitCode::Ok: Everything went fine, the list was set. + * - ExitCode::LogicError, ExitCause::Unknown: An unknown error occurred. + */ + virtual ExitInfo setAppExcludeList() = 0; + + /** Set the list of applications that should not be hydrated. + * + * * Possible return values are: + * - ExitCode::Ok: Everything went fine, the list was set. + * - ExitCode::LogicError, ExitCause::Unknown: An unknown error occurred. + */ + virtual ExitInfo getFetchingAppList(QHash &appTable) = 0; - virtual void exclude(const QString &) = 0; - virtual bool isExcluded(const QString &filePath) = 0; + virtual void exclude(const SyncPath &) = 0; + virtual bool isExcluded(const SyncPath &filePath) = 0; - virtual void cancelHydrate(const QString &) {} + virtual void cancelHydrate(const SyncPath &) {} - virtual bool fileStatusChanged(const QString &systemFileName, KDC::SyncFileStatus fileStatus) = 0; + virtual bool fileStatusChanged(const SyncPath &systemFileName, KDC::SyncFileStatus fileStatus) = 0; virtual void convertDirContentToPlaceholder(const QString &, bool) {} - virtual void clearFileAttributes(const QString &) = 0; + virtual void clearFileAttributes(const SyncPath &) = 0; inline void setExtendedLog(bool extendedLog) { _extendedLog = extendedLog; } inline const std::string &namespaceCLSID() { return _vfsSetupParams._namespaceCLSID; } inline void setNamespaceCLSID(const std::string &CLSID) { _vfsSetupParams._namespaceCLSID = CLSID; } + virtual void dehydrate(const QString &path) = 0; + virtual void hydrate(const QString &path) = 0; + signals: /// Emitted when a user-initiated hydration starts void beginHydrating(); @@ -215,6 +310,8 @@ class Vfs : public QObject { protected: VfsSetupParams _vfsSetupParams; + void starVfsWorkers(); + const std::array s_nb_threads = {5, 5}; // Callbacks void (*_syncFileStatus)(int syncDbId, const KDC::SyncPath &itemPath, KDC::SyncFileStatus &status) = nullptr; @@ -233,17 +330,40 @@ class Vfs : public QObject { * Usually some registration needs to be done with the backend. This function * should take care of it if necessary. */ - virtual bool startImpl(bool &installationDone, bool &activationDone, bool &connectionDone) = 0; + virtual ExitInfo startImpl(bool &installationDone, bool &activationDone, bool &connectionDone) = 0; virtual void stopImpl(bool unregister) = 0; - inline log4cplus::Logger logger() { return _vfsSetupParams._logger; } + inline log4cplus::Logger logger() const { return _vfsSetupParams._logger; } + + ExitInfo handleVfsError(const SyncPath &itemPath, const SourceLocation location = SourceLocation::currentLoc()) const; + ExitInfo checkIfPathExists(const SyncPath &itemPath, bool shouldExist, + const SourceLocation location = SourceLocation::currentLoc()) const; + // By default we will return file access error. + inline ExitInfo defaultVfsError(const SourceLocation location = SourceLocation::currentLoc()) const { + return {ExitCode::SystemError, ExitCause::FileAccessError, location}; + } private: bool _extendedLog; bool _started; }; +class VfsWorker : public QObject { + Q_OBJECT + + public: + VfsWorker(Vfs *vfs, int type, int num, log4cplus::Logger logger); + void start(); + + private: + Vfs *_vfs; + int _type; + int _num; + log4cplus::Logger _logger; + + inline log4cplus::Logger logger() { return _logger; } +}; } // namespace KDC Q_DECLARE_INTERFACE(KDC::Vfs, "Vfs") @@ -260,40 +380,49 @@ class VfsOff : public Vfs { Q_INTERFACES(KDC::Vfs) public: + explicit VfsOff(QObject *parent = nullptr); VfsOff(VfsSetupParams &vfsSetupParams, QObject *parent = nullptr); - virtual ~VfsOff(); + ~VfsOff() override; KDC::VirtualFileMode mode() const override { return KDC::VirtualFileMode::Off; } bool socketApiPinStateActionsShown() const override { return false; } - bool isHydrating() const override { return false; } - - bool updateMetadata(const QString &, time_t, time_t, qint64, const QByteArray &, QString *) override { return true; } - bool createPlaceholder(const KDC::SyncPath &, const KDC::SyncFileItem &) override { return true; } - bool dehydratePlaceholder(const QString &) override { return true; } - bool convertToPlaceholder(const QString &, const KDC::SyncFileItem &) override { return true; } - bool updateFetchStatus(const QString &, const QString &, qint64, bool &, bool &) override { return true; } - bool forceStatus(const QString &path, bool isSyncing, int progress, bool isHydrated = false) override; - - bool needsMetadataUpdate(const KDC::SyncFileItem &) override { return false; } - bool isDehydratedPlaceholder(const QString &, bool) override { return false; } - - bool setPinState(const QString &, KDC::PinState) override { return true; } - KDC::PinState pinState(const QString &) override { return KDC::PinState::AlwaysLocal; } - bool status(const QString &, bool &, bool &, bool &, int &) override { return true; } - virtual bool setThumbnail(const QString &, const QPixmap &) override { return true; } - virtual bool setAppExcludeList() override { return true; } - virtual bool getFetchingAppList(QHash &) override { return true; } - virtual void exclude(const QString &) override {} - virtual bool isExcluded(const QString &) override { return false; } - virtual bool fileStatusChanged(const QString &, KDC::SyncFileStatus) override { return true; } - - virtual void clearFileAttributes(const QString &) override {} + + ExitInfo updateMetadata(const SyncPath &, time_t, time_t, int64_t, const NodeId &) override { return ExitCode::Ok; } + ExitInfo createPlaceholder(const KDC::SyncPath &, const KDC::SyncFileItem &) override { return ExitCode::Ok; } + ExitInfo dehydratePlaceholder(const SyncPath &) override { return ExitCode::Ok; } + ExitInfo convertToPlaceholder(const SyncPath &, const KDC::SyncFileItem &) override { return ExitCode::Ok; } + ExitInfo updateFetchStatus(const SyncPath &, const SyncPath &, int64_t, bool &, bool &) override { return ExitCode::Ok; } + ExitInfo forceStatus(const SyncPath &path, bool isSyncing, int progress, bool isHydrated = false) override; + + ExitInfo isDehydratedPlaceholder(const SyncPath &, bool &isDehydrated, bool) override { + isDehydrated = false; + return ExitCode::Ok; + } + + ExitInfo setPinState(const SyncPath &, KDC::PinState) override { return ExitCode::Ok; } + KDC::PinState pinState(const SyncPath &) override { return KDC::PinState::AlwaysLocal; } + ExitInfo status(const SyncPath &, bool &, bool &, bool &, int &) override { return ExitCode::Ok; } + ExitInfo setThumbnail(const SyncPath &, const QPixmap &) override { return ExitCode::Ok; } + ExitInfo setAppExcludeList() override { return ExitCode::Ok; } + ExitInfo getFetchingAppList(QHash &) override { return ExitCode::Ok; } + void exclude(const SyncPath &) override { /*VfsOff*/ + } + bool isExcluded(const SyncPath &) override { return false; } + bool fileStatusChanged(const SyncPath &, KDC::SyncFileStatus) final { return true; } + + void clearFileAttributes(const SyncPath &) override { /*VfsOff*/ + } + void dehydrate(const QString &) override { /*VfsOff*/ + } + void hydrate(const QString &) override { /*VfsOff*/ + } protected: - bool startImpl(bool &installationDone, bool &activationDone, bool &connectionDone) override; - void stopImpl(bool /*unregister*/) override {} + ExitInfo startImpl(bool &installationDone, bool &activationDone, bool &connectionDone) override; + void stopImpl(bool /*unregister*/) override { /*VfsOff*/ + } friend class TestWorkers; }; diff --git a/src/libsyncengine/jobs/abstractjob.h b/src/libsyncengine/jobs/abstractjob.h index ecaa76535..687f1efee 100644 --- a/src/libsyncengine/jobs/abstractjob.h +++ b/src/libsyncengine/jobs/abstractjob.h @@ -73,24 +73,26 @@ class AbstractJob : public Poco::Runnable { inline bool isRunning() const { return _isRunning; } inline void setVfsUpdateFetchStatusCallback( - std::function callback) noexcept { + const std::function &callback) noexcept { _vfsUpdateFetchStatus = callback; } - inline void setVfsSetPinStateCallback(std::function callback) noexcept { + inline void setVfsSetPinStateCallback(const std::function &callback) noexcept { _vfsSetPinState = callback; } - inline void setVfsForceStatusCallback(std::function callback) noexcept { + inline void setVfsForceStatusCallback( + const std::function &callback) noexcept { _vfsForceStatus = callback; } - inline void setVfsStatusCallback(std::function callback) noexcept { + inline void setVfsStatusCallback( + const std::function &callback) noexcept { _vfsStatus = callback; } - inline void setVfsUpdateMetadataCallback(std::function - callback) noexcept { + inline void setVfsUpdateMetadataCallback( + const std::function + &callback) noexcept { _vfsUpdateMetadata = callback; } - inline void setVfsCancelHydrateCallback(std::function callback) noexcept { + inline void setVfsCancelHydrateCallback(const std::function &callback) noexcept { _vfsCancelHydrate = callback; } @@ -107,16 +109,16 @@ class AbstractJob : public Poco::Runnable { ExitCode _exitCode = ExitCode::Unknown; ExitCause _exitCause = ExitCause::Unknown; - std::function - _vfsUpdateFetchStatus = nullptr; - std::function _vfsSetPinState = nullptr; - std::function _vfsForceStatus = nullptr; - std::function - _vfsStatus = nullptr; - std::function - _vfsUpdateMetadata = nullptr; - std::function _vfsCancelHydrate = nullptr; + std::function + _vfsUpdateFetchStatus; + std::function _vfsSetPinState; + std::function _vfsForceStatus; + std::function + _vfsStatus; + std::function + _vfsUpdateMetadata; + std::function _vfsCancelHydrate; private: virtual void run() final; diff --git a/src/libsyncengine/jobs/network/API_v2/createdirjob.cpp b/src/libsyncengine/jobs/network/API_v2/createdirjob.cpp index e9f01024b..e8561bab1 100644 --- a/src/libsyncengine/jobs/network/API_v2/createdirjob.cpp +++ b/src/libsyncengine/jobs/network/API_v2/createdirjob.cpp @@ -24,8 +24,8 @@ namespace KDC { CreateDirJob::CreateDirJob(int driveDbId, const SyncPath &filepath, const NodeId &parentId, const SyncName &name, const std::string &color /*= ""*/) : - AbstractTokenNetworkJob(ApiType::Drive, 0, 0, driveDbId, 0), _filePath(filepath), _parentDirId(parentId), _name(name), - _color(color) { + AbstractTokenNetworkJob(ApiType::Drive, 0, 0, driveDbId, 0), + _filePath(filepath), _parentDirId(parentId), _name(name), _color(color) { _httpMethod = Poco::Net::HTTPRequest::HTTP_POST; } @@ -33,16 +33,22 @@ CreateDirJob::CreateDirJob(int driveDbId, const NodeId &parentId, const SyncName CreateDirJob(driveDbId, "", parentId, name) {} CreateDirJob::~CreateDirJob() { - if (_vfsSetPinState && _vfsForceStatus && !_filePath.empty()) { - if (!_vfsSetPinState(_filePath, PinState::AlwaysLocal)) { - LOGW_WARN(_logger, L"Error in CreateDirJob::vfsSetPinState for " << Utility::formatSyncPath(_filePath).c_str()); - } - if (!_vfsForceStatus(_filePath, false, 0, true)) { - LOGW_WARN(_logger, L"Error in CreateDirJob::vfsForceStatus for " << Utility::formatSyncPath(_filePath).c_str()); + if (_filePath.empty()) return; + try { + if (_vfsSetPinState && _vfsForceStatus) { + if (ExitInfo exitInfo = _vfsSetPinState(_filePath, PinState::AlwaysLocal); !exitInfo) { + LOGW_WARN(_logger, L"Error in CreateDirJob::vfsSetPinState for " << Utility::formatSyncPath(_filePath) << L" : " + << exitInfo); + } + if (ExitInfo exitInfo = _vfsForceStatus(_filePath, false, 0, true); !exitInfo) { + LOGW_WARN(_logger, L"Error in CreateDirJob::vfsForceStatus for " << Utility::formatSyncPath(_filePath) << L" : " + << exitInfo); + } } + } catch (const std::bad_function_call &e) { + LOG_WARN(_logger, "Error in CreateDirJob::~CreateDirJob: " << e.what()); } } - std::string CreateDirJob::getSpecificUrl() { std::string str = AbstractTokenNetworkJob::getSpecificUrl(); str += "/files/"; @@ -79,8 +85,11 @@ bool CreateDirJob::handleResponse(std::istream &is) { } } - if (!_filePath.empty() && _vfsForceStatus && !_vfsForceStatus(_filePath, false, 100, true)) { - LOGW_WARN(_logger, L"Error in CreateDirJob::_vfsForceStatus for " << Utility::formatSyncPath(_filePath).c_str()); + if (!_filePath.empty() && _vfsForceStatus) { + if (ExitInfo exitInfo = _vfsForceStatus(_filePath, false, 100, true); !exitInfo) { + LOGW_WARN(_logger, L"Error in CreateDirJob::_vfsForceStatus for " << Utility::formatSyncPath(_filePath) << L" : " + << exitInfo); + } } } diff --git a/src/libsyncengine/jobs/network/API_v2/downloadjob.cpp b/src/libsyncengine/jobs/network/API_v2/downloadjob.cpp index 744c7c7cc..674044e5a 100644 --- a/src/libsyncengine/jobs/network/API_v2/downloadjob.cpp +++ b/src/libsyncengine/jobs/network/API_v2/downloadjob.cpp @@ -59,24 +59,25 @@ DownloadJob::DownloadJob(int driveDbId, const NodeId &remoteFileId, const SyncPa } DownloadJob::~DownloadJob() { + try{ // Remove tmp file // For a remote CREATE operation, the tmp file should no longer exist, but if an error occurred in handleResponse, it must be // deleted if (!removeTmpFile() && !_isCreate) { LOGW_WARN(_logger, L"Failed to remove tmp file: " << Utility::formatSyncPath(_tmpPath)); } - + if (_responseHandlingCanceled) { if (_vfsSetPinState) { - if (!_vfsSetPinState(_localpath, PinState::OnlineOnly)) { - LOGW_WARN(_logger, L"Error in vfsSetPinState: " << Utility::formatSyncPath(_localpath)); + if (ExitInfo exitInfo = _vfsSetPinState(_localpath, PinState::OnlineOnly); !exitInfo) { + LOGW_WARN(_logger, L"Error in vfsSetPinState: " << Utility::formatSyncPath(_localpath) << L" : " << exitInfo); } } // TODO: usefull ? if (_vfsForceStatus) { - if (!_vfsForceStatus(_localpath, false, 0, false)) { - LOGW_WARN(_logger, L"Error in vfsForceStatus: " << Utility::formatSyncPath(_localpath)); + if (ExitInfo exitInfo = _vfsForceStatus(_localpath, false, 0, false); !exitInfo) { + LOGW_WARN(_logger, L"Error in vfsForceStatus: " << Utility::formatSyncPath(_localpath) << L" : " << exitInfo); } } @@ -87,17 +88,22 @@ DownloadJob::~DownloadJob() { } } else { if (_vfsSetPinState) { - if (!_vfsSetPinState(_localpath, _exitCode == ExitCode::Ok ? PinState::AlwaysLocal : PinState::OnlineOnly)) { - LOGW_WARN(_logger, L"Error in vfsSetPinState: " << Utility::formatSyncPath(_localpath)); + if (ExitInfo exitInfo = + _vfsSetPinState(_localpath, _exitCode == ExitCode::Ok ? PinState::AlwaysLocal : PinState::OnlineOnly); + !exitInfo) { + LOGW_WARN(_logger, L"Error in vfsSetPinState: " << Utility::formatSyncPath(_localpath) << L": " << exitInfo); } } if (_vfsForceStatus) { - if (!_vfsForceStatus(_localpath, false, 0, _exitCode == ExitCode::Ok)) { - LOGW_WARN(_logger, L"Error in vfsForceStatus: " << Utility::formatSyncPath(_localpath)); + if (ExitInfo exitInfo = _vfsForceStatus(_localpath, false, 0, _exitCode == ExitCode::Ok); !exitInfo) { + LOGW_WARN(_logger, L"Error in vfsForceStatus: " << Utility::formatSyncPath(_localpath) << L" : " << exitInfo); } } } + } catch (const std::bad_function_call &e) { + LOG_ERROR(_logger, "Error in DownloadJob::~DownloadJob: " << e.what()); + } } std::string DownloadJob::getSpecificUrl() { @@ -142,28 +148,37 @@ void DownloadJob::runJob() noexcept { IoError ioError = IoError::Success; if (!IoHelper::getFileStat(_localpath, &filestat, ioError)) { LOGW_WARN(_logger, L"Error in IoHelper::getFileStat: " << Utility::formatIoError(_localpath, ioError)); + _exitCode = ExitCode::SystemError; + _exitCause = ExitCause::Unknown; return; } - if (ioError == IoError::NoSuchFileOrDirectory) { LOGW_WARN(_logger, L"Item does not exist anymore: " << Utility::formatSyncPath(_localpath)); + _exitCode = ExitCode::SystemError; + _exitCause = ExitCause::NotFound; return; } else if (ioError == IoError::AccessDenied) { LOGW_WARN(_logger, L"Item misses search permission: " << Utility::formatSyncPath(_localpath)); + _exitCode = ExitCode::SystemError; + _exitCause = ExitCause::FileAccessError; return; } - std::string error; - if (!_vfsUpdateMetadata(_localpath, filestat.creationTime, filestat.modtime, _expectedSize, - std::to_string(filestat.inode), error)) { - LOGW_WARN(_logger, L"Update metadata failed: " << Utility::formatSyncPath(_localpath)); + if (ExitInfo exitInfo = _vfsUpdateMetadata(_localpath, filestat.creationTime, filestat.modtime, _expectedSize, + std::to_string(filestat.inode)); + !exitInfo) { + LOGW_WARN(_logger, L"Update metadata failed " << exitInfo << L" " << Utility::formatSyncPath(_localpath)); + _exitCode = exitInfo.code(); + _exitCause = exitInfo.cause(); return; } } if (_vfsForceStatus) { - if (!_vfsForceStatus(_localpath, true, 0, false)) { - LOGW_WARN(_logger, L"Error in vfsForceStatus: " << Utility::formatSyncPath(_localpath)); + if (ExitInfo exitInfo = _vfsForceStatus(_localpath, true, 0, false); !exitInfo) { + LOGW_WARN(_logger, L"Error in vfsForceStatus: " << Utility::formatSyncPath(_localpath) << L" : " << exitInfo); + _exitCode = exitInfo.code(); + _exitCause = exitInfo.cause(); return; } } @@ -314,8 +329,11 @@ bool DownloadJob::handleResponse(std::istream &is) { std::chrono::duration elapsed_seconds = std::chrono::steady_clock::now() - fileProgressTimer; if (elapsed_seconds.count() > NOTIFICATION_DELAY || done) { // Update fetch status - if (!_vfsUpdateFetchStatus(_tmpPath, _localpath, getProgress(), fetchCanceled, fetchFinished)) { - LOGW_WARN(_logger, L"Error in vfsUpdateFetchStatus: " << Utility::formatSyncPath(_localpath)); + if (ExitInfo exitInfo = + _vfsUpdateFetchStatus(_tmpPath, _localpath, getProgress(), fetchCanceled, fetchFinished); + !exitInfo) { + LOGW_WARN(_logger, L"Error in vfsUpdateFetchStatus: " << Utility::formatSyncPath(_localpath) << L": " + << exitInfo); fetchError = true; break; } else if (fetchCanceled) { @@ -351,8 +369,10 @@ bool DownloadJob::handleResponse(std::istream &is) { if (!_responseHandlingCanceled) { if (_vfsUpdateFetchStatus && !fetchFinished) { // Update fetch status - if (!_vfsUpdateFetchStatus(_tmpPath, _localpath, getProgress(), fetchCanceled, fetchFinished)) { - LOGW_WARN(_logger, L"Error in vfsUpdateFetchStatus: " << Utility::formatSyncPath(_localpath)); + if (ExitInfo exitInfo = _vfsUpdateFetchStatus(_tmpPath, _localpath, getProgress(), fetchCanceled, fetchFinished); + !exitInfo) { + LOGW_WARN(_logger, + L"Error in vfsUpdateFetchStatus: " << Utility::formatSyncPath(_localpath) << L" : " << exitInfo); fetchError = true; } else if (fetchCanceled) { LOGW_WARN(_logger, L"Update fetch status canceled: " << Utility::formatSyncPath(_localpath)); diff --git a/src/libsyncengine/jobs/network/API_v2/duplicatejob.cpp b/src/libsyncengine/jobs/network/API_v2/duplicatejob.cpp index 699d9de5b..cf1304b79 100644 --- a/src/libsyncengine/jobs/network/API_v2/duplicatejob.cpp +++ b/src/libsyncengine/jobs/network/API_v2/duplicatejob.cpp @@ -34,12 +34,12 @@ DuplicateJob::~DuplicateJob() { bool isHydrated = false; bool isSyncing = false; int progress = 0; - if (!_vfsStatus(_absoluteFinalPath, isPlaceholder, isHydrated, isSyncing, progress)) { - LOGW_WARN(_logger, L"Error in vfsStatus for path=" << Path2WStr(_absoluteFinalPath).c_str()); + if (ExitInfo exitInfo = _vfsStatus(_absoluteFinalPath, isPlaceholder, isHydrated, isSyncing, progress); !exitInfo) { + LOGW_WARN(_logger, L"Error in vfsStatus for path=" << Path2WStr(_absoluteFinalPath) << L" : " << exitInfo); } - if (!_vfsForceStatus(_absoluteFinalPath, false, 0, false)) { - LOGW_WARN(_logger, L"Error in vfsForceStatus for path=" << Path2WStr(_absoluteFinalPath).c_str()); + if (ExitInfo exitInfo = _vfsForceStatus(_absoluteFinalPath, false, 0, false); !exitInfo) { + LOGW_WARN(_logger, L"Error in vfsForceStatus for path=" << Path2WStr(_absoluteFinalPath) << L" : " << exitInfo); } } } diff --git a/src/libsyncengine/jobs/network/API_v2/movejob.cpp b/src/libsyncengine/jobs/network/API_v2/movejob.cpp index f6e8fde24..573a39419 100644 --- a/src/libsyncengine/jobs/network/API_v2/movejob.cpp +++ b/src/libsyncengine/jobs/network/API_v2/movejob.cpp @@ -25,8 +25,8 @@ namespace KDC { MoveJob::MoveJob(int driveDbId, const SyncPath &destFilepath, const NodeId &fileId, const NodeId &destDirId, const SyncName &name /*= ""*/) : - AbstractTokenNetworkJob(ApiType::Drive, 0, 0, driveDbId, 0), _destFilepath(destFilepath), _fileId(fileId), - _destDirId(destDirId), _name(name) { + AbstractTokenNetworkJob(ApiType::Drive, 0, 0, driveDbId, 0), + _destFilepath(destFilepath), _fileId(fileId), _destDirId(destDirId), _name(name) { _httpMethod = Poco::Net::HTTPRequest::HTTP_POST; } @@ -36,13 +36,14 @@ MoveJob::~MoveJob() { bool isHydrated = false; bool isSyncing = false; int progress = 0; - if (!_vfsStatus(_destFilepath, isPlaceholder, isHydrated, isSyncing, progress)) { - LOGW_WARN(_logger, L"Error in vfsStatus for path=" << Path2WStr(_destFilepath).c_str()); + if (ExitInfo exitInfo = _vfsStatus(_destFilepath, isPlaceholder, isHydrated, isSyncing, progress); !exitInfo) { + LOGW_WARN(_logger, L"Error in vfsStatus for path=" << Path2WStr(_destFilepath) << L" : " << exitInfo); } - if (!_vfsForceStatus(_destFilepath, false, 100, - isHydrated)) { // TODO : to be refactored, some parameters are used on macOS only - LOGW_WARN(_logger, L"Error in vfsForceStatus for path=" << Path2WStr(_destFilepath).c_str()); + if (ExitInfo exitInfo = _vfsForceStatus(_destFilepath, false, 100, + isHydrated); + !exitInfo) { // TODO : to be refactored, some parameters are used on macOS only + LOGW_WARN(_logger, L"Error in vfsForceStatus for path=" << Path2WStr(_destFilepath) << L" : " << exitInfo); } } } diff --git a/src/libsyncengine/jobs/network/API_v2/renamejob.cpp b/src/libsyncengine/jobs/network/API_v2/renamejob.cpp index 3cb2007ae..9b16ef302 100644 --- a/src/libsyncengine/jobs/network/API_v2/renamejob.cpp +++ b/src/libsyncengine/jobs/network/API_v2/renamejob.cpp @@ -33,12 +33,12 @@ RenameJob::~RenameJob() { bool isHydrated = false; bool isSyncing = false; int progress = 0; - if (!_vfsStatus(_absoluteFinalPath, isPlaceholder, isHydrated, isSyncing, progress)) { - LOGW_WARN(_logger, L"Error in vfsStatus for path=" << Path2WStr(_absoluteFinalPath).c_str()); + if (ExitInfo exitInfo = _vfsStatus(_absoluteFinalPath, isPlaceholder, isHydrated, isSyncing, progress); !exitInfo) { + LOGW_WARN(_logger, L"Error in vfsStatus for path=" << Path2WStr(_absoluteFinalPath) << L" : " << exitInfo); } - if (!_vfsForceStatus(_absoluteFinalPath, false, 0, isHydrated)) { - LOGW_WARN(_logger, L"Error in vfsForceStatus for path=" << Path2WStr(_absoluteFinalPath).c_str()); + if (ExitInfo exitInfo = _vfsForceStatus(_absoluteFinalPath, false, 0, isHydrated); !exitInfo) { + LOGW_WARN(_logger, L"Error in vfsForceStatus for path=" << Path2WStr(_absoluteFinalPath) << L" : " << exitInfo); } } } diff --git a/src/libsyncengine/jobs/network/API_v2/upload_session/abstractuploadsession.cpp b/src/libsyncengine/jobs/network/API_v2/upload_session/abstractuploadsession.cpp index 87d1787a3..8f0ae3828 100644 --- a/src/libsyncengine/jobs/network/API_v2/upload_session/abstractuploadsession.cpp +++ b/src/libsyncengine/jobs/network/API_v2/upload_session/abstractuploadsession.cpp @@ -272,7 +272,7 @@ bool AbstractUploadSession::sendChunks() { // "file not found" errors. std::ifstream file; if (ExitInfo exitInfo = IoHelper::openFile(_filePath, file, 10); !exitInfo) { - LOGW_WARN(_logger, L"Failed to open file " << Utility::formatSyncPath(_filePath)); + LOGW_WARN(_logger, L"Failed to open file " << Utility::formatSyncPath(_filePath) << L" " << exitInfo); return exitInfo; } diff --git a/src/libsyncengine/jobs/network/API_v2/upload_session/driveuploadsession.cpp b/src/libsyncengine/jobs/network/API_v2/upload_session/driveuploadsession.cpp index 42b17daa6..1dfd9fbe7 100644 --- a/src/libsyncengine/jobs/network/API_v2/upload_session/driveuploadsession.cpp +++ b/src/libsyncengine/jobs/network/API_v2/upload_session/driveuploadsession.cpp @@ -30,15 +30,17 @@ DriveUploadSession::DriveUploadSession(int driveDbId, std::shared_ptr sy DriveUploadSession::DriveUploadSession(int driveDbId, std::shared_ptr syncDb, const SyncPath &filepath, const SyncName &filename, const NodeId &remoteParentDirId, SyncTime modtime, bool liteSyncActivated, uint64_t nbParalleleThread /*= 1*/) : - AbstractUploadSession(filepath, filename, nbParalleleThread), _driveDbId(driveDbId), _syncDb(syncDb), _modtimeIn(modtime), - _remoteParentDirId(remoteParentDirId) { + AbstractUploadSession(filepath, filename, nbParalleleThread), + _driveDbId(driveDbId), _syncDb(syncDb), _modtimeIn(modtime), _remoteParentDirId(remoteParentDirId) { (void) liteSyncActivated; _uploadSessionType = UploadSessionType::Drive; } DriveUploadSession::~DriveUploadSession() { - if (_vfsForceStatus && !_vfsForceStatus(getFilePath(), false, 100, true)) { - LOGW_WARN(getLogger(), L"Error in vfsForceStatus: " << Utility::formatSyncPath(getFilePath()).c_str()); + if (_vfsForceStatus) { + if (ExitInfo exitInfo = _vfsForceStatus(getFilePath(), false, 100, true); !exitInfo) { + LOGW_WARN(getLogger(), L"Error in vfsForceStatus: " << Utility::formatSyncPath(getFilePath()) << L" : " << exitInfo); + } } } diff --git a/src/libsyncengine/jobs/network/API_v2/upload_session/uploadsessionfinishjob.cpp b/src/libsyncengine/jobs/network/API_v2/upload_session/uploadsessionfinishjob.cpp index db2c9ba9c..03419a518 100644 --- a/src/libsyncengine/jobs/network/API_v2/upload_session/uploadsessionfinishjob.cpp +++ b/src/libsyncengine/jobs/network/API_v2/upload_session/uploadsessionfinishjob.cpp @@ -37,8 +37,8 @@ UploadSessionFinishJob::UploadSessionFinishJob(UploadSessionType uploadType, con UploadSessionFinishJob::~UploadSessionFinishJob() { if (_vfsForceStatus) { - if (!_vfsForceStatus(_filePath, false, 0, true)) { - LOGW_WARN(_logger, L"Error in vfsForceStatus for path=" << Path2WStr(_filePath).c_str()); + if (ExitInfo exitInfo = _vfsForceStatus(_filePath, false, 0, true); !exitInfo) { + LOGW_WARN(_logger, L"Error in vfsForceStatus for path=" << Path2WStr(_filePath) << L" : " << exitInfo); } } } diff --git a/src/libsyncengine/jobs/network/API_v2/uploadjob.cpp b/src/libsyncengine/jobs/network/API_v2/uploadjob.cpp index fe3fb0fcc..27cd63822 100644 --- a/src/libsyncengine/jobs/network/API_v2/uploadjob.cpp +++ b/src/libsyncengine/jobs/network/API_v2/uploadjob.cpp @@ -45,14 +45,14 @@ UploadJob::UploadJob(int driveDbId, const SyncPath &filepath, const NodeId &file UploadJob::~UploadJob() { if (_vfsForceStatus) { - if (!_vfsForceStatus(_filePath, false, 100, true)) { - LOGW_WARN(_logger, L"Error in vfsForceStatus - path=" << Path2WStr(_filePath).c_str()); + if (ExitInfo exitInfo = _vfsForceStatus(_filePath, false, 100, true); !exitInfo) { + LOGW_WARN(_logger, L"Error in vfsForceStatus - path=" << Path2WStr(_filePath) << L" : " << exitInfo); } } if (_vfsSetPinState) { - if (!_vfsSetPinState(_filePath, PinState::AlwaysLocal)) { - LOGW_WARN(_logger, L"Error in vfsSetPinState - path=" << Path2WStr(_filePath).c_str()); + if (ExitInfo exitInfo = _vfsSetPinState(_filePath, PinState::AlwaysLocal); !exitInfo) { + LOGW_WARN(_logger, L"Error in vfsSetPinState - path=" << Path2WStr(_filePath) << L": " << exitInfo); } } } diff --git a/src/libsyncengine/jobs/network/abstractnetworkjob.cpp b/src/libsyncengine/jobs/network/abstractnetworkjob.cpp index bfc5dfd92..525f4469a 100644 --- a/src/libsyncengine/jobs/network/abstractnetworkjob.cpp +++ b/src/libsyncengine/jobs/network/abstractnetworkjob.cpp @@ -140,7 +140,7 @@ void AbstractNetworkJob::runJob() noexcept { bool canceled = false; if (ExitInfo exitInfo = setData(); !exitInfo) { // Must be called before setQueryParameters - LOG_WARN(_logger, "Job " << jobId() << " is cancelled"); + LOG_WARN(_logger, "Job " << jobId() << " is cancelled " << exitInfo); _exitCode = exitInfo.code(); _exitCause = exitInfo.cause(); break; diff --git a/src/libsyncengine/propagation/executor/executorworker.cpp b/src/libsyncengine/propagation/executor/executorworker.cpp index 39d085670..f2b07438d 100644 --- a/src/libsyncengine/propagation/executor/executorworker.cpp +++ b/src/libsyncengine/propagation/executor/executorworker.cpp @@ -230,8 +230,8 @@ void ExecutorWorker::execute() { _syncPal->vfsCleanUpStatuses(); setExitCause(executorExitInfo.cause()); - LOG_SYNCPAL_DEBUG(_logger, "Worker stopped: name=" << name().c_str()); setDone(executorExitInfo.code()); + LOG_SYNCPAL_DEBUG(_logger, "Worker stopped: name=" << name() << " " << executorExitInfo); } void ExecutorWorker::initProgressManager() { @@ -335,7 +335,8 @@ ExitInfo ExecutorWorker::handleCreateOp(SyncOpPtr syncOp, std::shared_ptromit()) { bool isDehydratedPlaceholder = false; if (ExitInfo exitInfo = checkLiteSyncInfoForCreate(syncOp, absoluteLocalFilePath, isDehydratedPlaceholder); !exitInfo) { - LOGW_SYNCPAL_WARN(_logger, L"Error in checkLiteSyncInfoForCreate"); + LOG_SYNCPAL_WARN(_logger, "Error in checkLiteSyncInfoForCreate" + << " " << exitInfo); return exitInfo; } @@ -367,8 +368,8 @@ ExitInfo ExecutorWorker::handleCreateOp(SyncOpPtr syncOp, std::shared_ptrcorrespondingNode()->id().has_value() ? *syncOp->correspondingNode()->id() : std::string(), syncOp->affectedNode()->lastmodified(), node); !exitInfo) { - LOGW_SYNCPAL_WARN(_logger, L"Failed to propagate changes in DB or update tree for " - << Utility::formatSyncName(syncOp->affectedNode()->name())); + LOGW_SYNCPAL_WARN(_logger, L"Failed to propagate changes in DB or update tree for: " + << Utility::formatSyncName(syncOp->affectedNode()->name()) << L" " << exitInfo); return exitInfo; } } else { @@ -413,6 +414,8 @@ ExitInfo ExecutorWorker::handleCreateOp(SyncOpPtr syncOp, std::shared_ptraffectedNode()->name()) + << L" " << exitInfo); return exitInfo; } @@ -425,13 +428,14 @@ ExitInfo ExecutorWorker::handleCreateOp(SyncOpPtr syncOp, std::shared_ptrparentDirId()); !exitInfoCheckAlreadyExcluded) { - LOG_SYNCPAL_WARN(_logger, "Error in ExecutorWorker::checkAlreadyExcluded"); + LOG_SYNCPAL_WARN(_logger, "Error in ExecutorWorker::checkAlreadyExcluded" + << " " << exitInfoCheckAlreadyExcluded); return exitInfoCheckAlreadyExcluded; } if (const ExitInfo exitInfo = handleForbiddenAction(syncOp, relativeLocalFilePath, ignored); !exitInfo) { LOGW_SYNCPAL_WARN(_logger, L"Error in handleForbiddenAction for item: " - << Utility::formatSyncPath(relativeLocalFilePath)); + << Utility::formatSyncPath(relativeLocalFilePath) << L" " << exitInfo); return exitInfo; } return {ExitCode::BackError, ExitCause::FileAccessError}; @@ -442,8 +446,9 @@ ExitInfo ExecutorWorker::handleCreateOp(SyncOpPtr syncOp, std::shared_ptrtargetSide() == ReplicaSide::Remote); !exitInfo) { - LOGW_SYNCPAL_WARN(_logger, L"Failed to convert to placeholder for " - << Utility::formatSyncName(syncOp->affectedNode()->name())); + LOGW_SYNCPAL_WARN(_logger, L"Failed to convert to placeholder for: " + << Utility::formatSyncName(syncOp->affectedNode()->name()) << L" " + << exitInfo); return exitInfo; } @@ -542,8 +547,9 @@ ExitInfo ExecutorWorker::generateCreateJob(SyncOpPtr syncOp, std::shared_ptraffectedNode()->name())); + LOGW_SYNCPAL_WARN(_logger, L"Failed to create placeholder for: " + << Utility::formatSyncName(syncOp->affectedNode()->name()) << L" " + << exitInfo); return exitInfo; } @@ -567,8 +573,9 @@ ExitInfo ExecutorWorker::generateCreateJob(SyncOpPtr syncOp, std::shared_ptraffectedNode()->lastmodified(), newNode); !exitInfo) { - LOGW_SYNCPAL_WARN(_logger, L"Failed to propagate changes in DB or update tree for " - << Utility::formatSyncName(syncOp->affectedNode()->name())); + LOGW_SYNCPAL_WARN(_logger, L"Failed to propagate changes in DB or update tree for: " + << Utility::formatSyncName(syncOp->affectedNode()->name()) << L" " + << exitInfo); return exitInfo; } @@ -636,13 +643,15 @@ ExitInfo ExecutorWorker::generateCreateJob(SyncOpPtr syncOp, std::shared_ptraffectedNode()->type() == NodeType::Directory) { if (ExitInfo exitInfo = convertToPlaceholder(relativeLocalFilePath, syncOp->targetSide() == ReplicaSide::Remote); !exitInfo) { - LOGW_SYNCPAL_WARN(_logger, L"Failed to convert to placeholder for " - << Utility::formatSyncName(syncOp->affectedNode()->name())); + LOGW_SYNCPAL_WARN(_logger, L"Failed to convert to placeholder for: " + << Utility::formatSyncName(syncOp->affectedNode()->name()) << L" " + << exitInfo); _syncPal->setRestart(true); if (!_syncPal->updateTree(ReplicaSide::Local)->deleteNode(syncOp->affectedNode())) { LOGW_SYNCPAL_WARN(_logger, L"Error in UpdateTree::deleteNode: node name=" - << Utility::formatSyncName(syncOp->affectedNode()->name())); + << Utility::formatSyncName(syncOp->affectedNode()->name()) << L" " + << exitInfo); } return exitInfo; @@ -662,16 +671,17 @@ ExitInfo ExecutorWorker::generateCreateJob(SyncOpPtr syncOp, std::shared_ptraffectedNode()->name())); + LOGW_SYNCPAL_WARN(_logger, L"Failed to convert to placeholder for: " + << Utility::formatSyncName(syncOp->affectedNode()->name()) << L" " + << exitInfo); return exitInfo; } #endif uint64_t filesize = 0; if (ExitInfo exitInfo = getFileSize(absoluteLocalFilePath, filesize); !exitInfo) { - LOGW_SYNCPAL_WARN(_logger, - L"Error in ExecutorWorker::getFileSize for " << Utility::formatSyncPath(absoluteLocalFilePath)); + LOGW_SYNCPAL_WARN(_logger, L"Error in ExecutorWorker::getFileSize for " + << Utility::formatSyncPath(absoluteLocalFilePath) << L" " << exitInfo); return exitInfo; } @@ -707,15 +717,14 @@ ExitInfo ExecutorWorker::generateCreateJob(SyncOpPtr syncOp, std::shared_ptrvfsMode() == VirtualFileMode::Mac || _syncPal->vfsMode() == VirtualFileMode::Win) { // Set VFS callbacks - std::function vfsSetPinStateCallback = + std::function vfsSetPinStateCallback = std::bind(&SyncPal::vfsSetPinState, _syncPal, std::placeholders::_1, std::placeholders::_2); job->setVfsSetPinStateCallback(vfsSetPinStateCallback); - std::function + std::function vfsUpdateMetadataCallback = std::bind(&SyncPal::vfsUpdateMetadata, _syncPal, std::placeholders::_1, std::placeholders::_2, - std::placeholders::_3, std::placeholders::_4, std::placeholders::_5, std::placeholders::_6); + std::placeholders::_3, std::placeholders::_4, std::placeholders::_5); job->setVfsUpdateMetadataCallback(vfsUpdateMetadataCallback); std::function vfsCancelHydrateCallback = @@ -723,7 +732,7 @@ ExitInfo ExecutorWorker::generateCreateJob(SyncOpPtr syncOp, std::shared_ptrsetVfsCancelHydrateCallback(vfsCancelHydrateCallback); } - std::function vfsForceStatusCallback = + std::function vfsForceStatusCallback = std::bind(&SyncPal::vfsForceStatus, _syncPal, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4); job->setVfsForceStatusCallback(vfsForceStatusCallback); @@ -744,9 +753,9 @@ ExitInfo ExecutorWorker::checkLiteSyncInfoForCreate(SyncOpPtr syncOp, const Sync bool isHydrated = false; bool isSyncing = false; int progress = 0; - if (!_syncPal->vfsStatus(path, isPlaceholder, isHydrated, isSyncing, progress)) { - LOGW_SYNCPAL_WARN(_logger, L"Error in vfsStatus: " << Utility::formatSyncPath(path)); - return {ExitCode::SystemError, ExitCause::FileAccessError}; + if (ExitInfo exitInfo = _syncPal->vfsStatus(path, isPlaceholder, isHydrated, isSyncing, progress); !exitInfo) { + LOGW_SYNCPAL_WARN(_logger, L"Error in vfsStatus: " << Utility::formatSyncPath(path) << L" " << exitInfo); + return exitInfo; } if (isPlaceholder && !isHydrated && !isSyncing) { @@ -766,29 +775,8 @@ ExitInfo ExecutorWorker::createPlaceholder(const SyncPath &relativeLocalPath) { return {ExitCode::DataError, ExitCause::InvalidSnapshot}; } - bool exists = false; - IoError ioError = IoError::Success; - SyncPath absoluteLocalPath = _syncPal->localPath() / relativeLocalPath; - if (!IoHelper::checkIfPathExists(absoluteLocalPath, exists, ioError)) { - LOGW_SYNCPAL_WARN(_logger, - L"Error in IoHelper::checkIfPathExists: " << Utility::formatIoError(absoluteLocalPath, ioError)); - return ExitCode::SystemError; - } - - if (ioError == IoError::AccessDenied) { - LOGW_WARN(_logger, L"Access denied to " << Path2WStr(absoluteLocalPath).c_str()); - return {ExitCode::SystemError, ExitCause::FileAccessError}; - } - - if (exists) { - LOGW_WARN(_logger, L"Item already exists: " << Utility::formatSyncPath(absoluteLocalPath)); - return {ExitCode::DataError, ExitCause::FileAlreadyExist}; - } - - if (!_syncPal->vfsCreatePlaceholder(relativeLocalPath, syncItem)) { - // TODO: vfs functions should output an ioError parameter - // Check if the item already exists on local replica - return processCreateOrConvertToPlaceholderError(relativeLocalPath, true); + if (ExitInfo exitInfo = _syncPal->vfsCreatePlaceholder(relativeLocalPath, syncItem); !exitInfo) { + return exitInfo; } return ExitCode::Ok; @@ -815,10 +803,9 @@ ExitInfo ExecutorWorker::convertToPlaceholder(const SyncPath &relativeLocalPath, LOGW_SYNCPAL_WARN(_logger, L"Error in IoHelper::getFileStat: " << Utility::formatIoError(absoluteLocalFilePath, ioError)); return ExitCode::SystemError; } - if (ioError == IoError::NoSuchFileOrDirectory) { LOGW_SYNCPAL_WARN(_logger, L"Item does not exist anymore: " << Utility::formatSyncPath(absoluteLocalFilePath)); - return {ExitCode::DataError, ExitCause::InvalidSnapshot}; + return {ExitCode::SystemError, ExitCause::NotFound}; } else if (ioError == IoError::AccessDenied) { LOGW_SYNCPAL_WARN(_logger, L"Item misses search permission: " << Utility::formatSyncPath(absoluteLocalFilePath)); return {ExitCode::SystemError, ExitCause::FileAccessError}; @@ -827,66 +814,20 @@ ExitInfo ExecutorWorker::convertToPlaceholder(const SyncPath &relativeLocalPath, syncItem.setLocalNodeId(std::to_string(fileStat.inode)); #endif - if (!_syncPal->vfsConvertToPlaceholder(absoluteLocalFilePath, syncItem)) { - // TODO: vfs functions should output an ioError parameter - // Check that the item exists on local replica - return processCreateOrConvertToPlaceholderError(relativeLocalPath, false); + if (ExitInfo exitInfo = _syncPal->vfsConvertToPlaceholder(absoluteLocalFilePath, syncItem); !exitInfo) { + return exitInfo; } - if (!_syncPal->vfsSetPinState(absoluteLocalFilePath, hydrated ? PinState::AlwaysLocal : PinState::OnlineOnly)) { - LOGW_SYNCPAL_WARN(_logger, L"Error in vfsSetPinState: " << Utility::formatSyncPath(absoluteLocalFilePath)); - return {ExitCode::SystemError, ExitCause::FileAccessError}; + if (ExitInfo exitInfo = + _syncPal->vfsSetPinState(absoluteLocalFilePath, hydrated ? PinState::AlwaysLocal : PinState::OnlineOnly); + !exitInfo) { + LOGW_SYNCPAL_WARN(_logger, L"Error in vfsSetPinState: " << Utility::formatSyncPath(absoluteLocalFilePath) << exitInfo); + return exitInfo; } return ExitCode::Ok; } -ExitInfo ExecutorWorker::processCreateOrConvertToPlaceholderError(const SyncPath &relativeLocalPath, bool create) { - // TODO: Simplify/remove this function when vfs functions will output an ioError parameter - SyncPath absoluteLocalFilePath = _syncPal->localPath() / relativeLocalPath; - bool exists = false; - IoError ioError = IoError::Success; - if (!IoHelper::checkIfPathExists(absoluteLocalFilePath, exists, ioError)) { - LOGW_SYNCPAL_WARN(_logger, - L"Error in IoHelper::checkIfPathExists: " << Utility::formatIoError(absoluteLocalFilePath, ioError)); - return ExitCode::SystemError; - } - - if (ioError == IoError::AccessDenied) { - LOGW_SYNCPAL_WARN(_logger, L"Item misses search permission: " << Utility::formatSyncPath(absoluteLocalFilePath)); - return {ExitCode::SystemError, ExitCause::FileAccessError}; - } - - if (create && exists) { - return {ExitCode::SystemError, ExitCause::FileAccessError}; - } else if (!create && !exists) { - return {ExitCode::DataError, ExitCause::InvalidSnapshot}; - } - - if (create) { - // Check if the parent folder exists on local replica - bool parentExists = false; - if (!IoHelper::checkIfPathExists(absoluteLocalFilePath.parent_path(), parentExists, ioError)) { - LOGW_WARN(_logger, L"Error in IoHelper::checkIfPathExists: " - << Utility::formatIoError(absoluteLocalFilePath.parent_path(), ioError)); - return ExitCode::SystemError; - } - - if (ioError == IoError::AccessDenied) { - LOGW_WARN(_logger, - L"Item misses search permission: " << Utility::formatSyncPath(absoluteLocalFilePath.parent_path())); - return {ExitCode::SystemError, ExitCause::FileAccessError}; - } - - if (!parentExists) { - return {ExitCode::DataError, ExitCause::InvalidSnapshot}; - } - } - - return {ExitCode::SystemError, ExitCause::FileAccessError}; -} - -// !!! When returning with hasError == true, _executorExitCode and _executorExitCause must be set !!! ExitInfo ExecutorWorker::handleEditOp(SyncOpPtr syncOp, std::shared_ptr &job, bool &ignored) { // The execution of the edit operation consists of three steps: // 1. If omit-flag is False, propagate the file to replicaY, replacing the existing one. @@ -907,7 +848,7 @@ ExitInfo ExecutorWorker::handleEditOp(SyncOpPtr syncOp, std::shared_ptraffectedNode()->name()) + << L" " << exitInfo); return exitInfo; } } @@ -969,20 +912,19 @@ ExitInfo ExecutorWorker::generateEditJob(SyncOpPtr syncOp, std::shared_ptr downloadJob = std::dynamic_pointer_cast(job); if (_syncPal->vfsMode() == VirtualFileMode::Mac || _syncPal->vfsMode() == VirtualFileMode::Win) { - std::function vfsSetPinStateCallback = + std::function vfsSetPinStateCallback = std::bind(&SyncPal::vfsSetPinState, _syncPal, std::placeholders::_1, std::placeholders::_2); downloadJob->setVfsSetPinStateCallback(vfsSetPinStateCallback); - std::function vfsForceStatusCallback = + std::function vfsForceStatusCallback = std::bind(&SyncPal::vfsForceStatus, _syncPal, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4); downloadJob->setVfsForceStatusCallback(vfsForceStatusCallback); - std::function + std::function vfsUpdateMetadataCallback = std::bind(&SyncPal::vfsUpdateMetadata, _syncPal, std::placeholders::_1, std::placeholders::_2, - std::placeholders::_3, std::placeholders::_4, std::placeholders::_5, std::placeholders::_6); + std::placeholders::_3, std::placeholders::_4, std::placeholders::_5); downloadJob->setVfsUpdateMetadataCallback(vfsUpdateMetadataCallback); } } else { @@ -991,7 +933,8 @@ ExitInfo ExecutorWorker::generateEditJob(SyncOpPtr syncOp, std::shared_ptr uploadJob = std::dynamic_pointer_cast(job); if (_syncPal->vfsMode() == VirtualFileMode::Mac || _syncPal->vfsMode() == VirtualFileMode::Win) { - std::function vfsForceStatusCallback = + std::function vfsForceStatusCallback = std::bind(&SyncPal::vfsForceStatus, _syncPal, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4); uploadJob->setVfsForceStatusCallback(vfsForceStatusCallback); @@ -1081,9 +1024,9 @@ ExitInfo ExecutorWorker::checkLiteSyncInfoForEdit(SyncOpPtr syncOp, const SyncPa bool isHydrated = false; bool isSyncingTmp = false; int progress = 0; - if (!_syncPal->vfsStatus(absolutePath, isPlaceholder, isHydrated, isSyncingTmp, progress)) { - LOGW_SYNCPAL_WARN(_logger, L"Error in vfsStatus: " << Utility::formatSyncPath(absolutePath)); - return {ExitCode::SystemError, ExitCause::FileAccessError}; + if (ExitInfo exitInfo = _syncPal->vfsStatus(absolutePath, isPlaceholder, isHydrated, isSyncingTmp, progress); !exitInfo) { + LOGW_SYNCPAL_WARN(_logger, L"Error in vfsStatus: " << Utility::formatSyncPath(absolutePath) << L": " << exitInfo); + return exitInfo; } if (syncOp->targetSide() == ReplicaSide::Remote) { @@ -1116,17 +1059,15 @@ ExitInfo ExecutorWorker::checkLiteSyncInfoForEdit(SyncOpPtr syncOp, const SyncPa } case PinState::OnlineOnly: { // Update metadata - std::string error; - _syncPal->vfsUpdateMetadata( - absolutePath, - syncOp->affectedNode()->createdAt().has_value() ? *syncOp->affectedNode()->createdAt() : 0, - syncOp->affectedNode()->lastmodified().has_value() ? *syncOp->affectedNode()->lastmodified() : 0, - syncOp->affectedNode()->size(), - syncOp->affectedNode()->id().has_value() ? *syncOp->affectedNode()->id() : std::string(), error); - // TODO: Vfs functions should return an ExitInfo struct syncOp->setOmit(true); // Do not propagate change in file system, only in DB - if (!error.empty()) { - return {ExitCode::SystemError, ExitCause::FileAccessError}; + if (ExitInfo exitInfo = _syncPal->vfsUpdateMetadata( + absolutePath, + syncOp->affectedNode()->createdAt().has_value() ? *syncOp->affectedNode()->createdAt() : 0, + syncOp->affectedNode()->lastmodified().has_value() ? *syncOp->affectedNode()->lastmodified() : 0, + syncOp->affectedNode()->size(), + syncOp->affectedNode()->id().has_value() ? *syncOp->affectedNode()->id() : std::string()); + !exitInfo) { + return exitInfo; } break; } @@ -1180,12 +1121,14 @@ ExitInfo ExecutorWorker::handleMoveOp(SyncOpPtr syncOp, bool &ignored, bool &byp } if (ExitInfo exitInfo = propagateMoveToDbAndTree(syncOp); !exitInfo) { - LOGW_SYNCPAL_WARN(_logger, L"Failed to propagate changes in DB or update tree for " - << Utility::formatSyncName(syncOp->affectedNode()->name())); + LOGW_SYNCPAL_WARN(_logger, L"Failed to propagate changes in DB or update tree for: " + << Utility::formatSyncName(syncOp->affectedNode()->name()) << L" " << exitInfo); return exitInfo; } } else { if (ExitInfo exitInfo = generateMoveJob(syncOp, ignored, bypassProgressComplete); !exitInfo) { + LOGW_SYNCPAL_WARN(_logger, L"Failed to generate move job for: " << SyncName2WStr(syncOp->affectedNode()->name()) + << L" " << exitInfo); return exitInfo; } } @@ -1291,12 +1234,12 @@ ExitInfo ExecutorWorker::generateMoveJob(SyncOpPtr syncOp, bool &ignored, bool & // Set callbacks if (_syncPal->vfsMode() == VirtualFileMode::Mac || _syncPal->vfsMode() == VirtualFileMode::Win) { - std::function vfsForceStatusCallback = + std::function vfsForceStatusCallback = std::bind(&SyncPal::vfsForceStatus, _syncPal, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4); job->setVfsForceStatusCallback(vfsForceStatusCallback); - std::function vfsStatusCallback = + std::function vfsStatusCallback = std::bind(&SyncPal::vfsStatus, _syncPal, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5); job->setVfsStatusCallback(vfsStatusCallback); @@ -1311,8 +1254,8 @@ ExitInfo ExecutorWorker::generateMoveJob(SyncOpPtr syncOp, bool &ignored, bool & // Propagate changes to DB and update trees std::shared_ptr newNode = nullptr; if (ExitInfo exitInfo = propagateChangeToDbAndTree(syncOp, job, newNode); !exitInfo) { - LOGW_WARN(_logger, L"Failed to propagate changes in DB or update tree for " - << Utility::formatSyncName(syncOp->affectedNode()->name())); + LOGW_WARN(_logger, L"Failed to propagate changes in DB or update tree for: " + << Utility::formatSyncName(syncOp->affectedNode()->name()) << L" " << exitInfo); return exitInfo; } @@ -1379,8 +1322,8 @@ ExitInfo ExecutorWorker::handleDeleteOp(SyncOpPtr syncOp, bool &ignored, bool &b } if (ExitInfo exitInfo = propagateDeleteToDbAndTree(syncOp); !exitInfo) { - LOGW_SYNCPAL_WARN(_logger, L"Failed to propagate changes in DB or update tree for " - << Utility::formatSyncName(syncOp->affectedNode()->name())); + LOGW_SYNCPAL_WARN(_logger, L"Failed to propagate changes in DB or update tree for: " + << Utility::formatSyncName(syncOp->affectedNode()->name()) << L" " << exitInfo); return exitInfo; } } else { @@ -1405,9 +1348,11 @@ ExitInfo ExecutorWorker::generateDeleteJob(SyncOpPtr syncOp, bool &ignored, bool bool isHydrated = false; bool isSyncing = false; int progress = 0; - if (!_syncPal->vfsStatus(absoluteLocalFilePath, isPlaceholder, isHydrated, isSyncing, progress)) { - LOGW_SYNCPAL_WARN(_logger, L"Error in vfsStatus: " << Utility::formatSyncPath(absoluteLocalFilePath)); - return {ExitCode::SystemError, ExitCause::FileAccessError}; + if (ExitInfo exitInfo = _syncPal->vfsStatus(absoluteLocalFilePath, isPlaceholder, isHydrated, isSyncing, progress); + !exitInfo) { + LOGW_SYNCPAL_WARN( + _logger, L"Error in vfsStatus: " << Utility::formatSyncPath(absoluteLocalFilePath) << L" : " << exitInfo); + return exitInfo; } isDehydratedPlaceholder = isPlaceholder && !isHydrated; } @@ -1685,14 +1630,13 @@ ExitInfo ExecutorWorker::handleFinishedJob(std::shared_ptr job, Syn if (networkJob && (networkJob->getStatusCode() == Poco::Net::HTTPResponse::HTTP_FORBIDDEN || networkJob->getStatusCode() == Poco::Net::HTTPResponse::HTTP_CONFLICT)) { if (ExitInfo exitInfo = handleForbiddenAction(syncOp, relativeLocalPath, ignored); !exitInfo) { - LOGW_SYNCPAL_WARN(_logger, - L"Error in handleForbiddenAction for item: " << Utility::formatSyncPath(relativeLocalPath)); + LOGW_SYNCPAL_WARN(_logger, L"Error in handleForbiddenAction for item: " + << Utility::formatSyncPath(relativeLocalPath) << L" " << exitInfo); return exitInfo; } } else if (!handleExecutorError(syncOp, {job->exitCode(), job->exitCause()})) { // Cancel all queued jobs - LOGW_SYNCPAL_WARN(_logger, - L"Cancelling jobs. exit code: " << job->exitCode() << L" exit cause: " << job->exitCause()); + LOGW_SYNCPAL_WARN(_logger, L"Cancelling jobs. " << ExitInfo(job->exitCode(), job->exitCause())); cancelAllOngoingJobs(); return {job->exitCode(), job->exitCause()}; @@ -2413,8 +2357,8 @@ ExitInfo ExecutorWorker::runCreateDirJob(SyncOpPtr syncOp, std::shared_ptr newNode = nullptr; if (ExitInfo exitInfo = propagateCreateToDbAndTree(syncOp, newNodeId, newModTime, newNode); !exitInfo) { - LOGW_SYNCPAL_WARN(_logger, L"Failed to propagate changes in DB or update tree for " - << Utility::formatSyncName(syncOp->affectedNode()->name())); + LOGW_SYNCPAL_WARN(_logger, L"Failed to propagate changes in DB or update tree for: " + << Utility::formatSyncName(syncOp->affectedNode()->name()) << L" " << exitInfo); return exitInfo; } @@ -2519,7 +2463,7 @@ ExitInfo ExecutorWorker::getFileSize(const SyncPath &path, uint64_t &size) { return ExitCode::Ok; } -ExitInfo ExecutorWorker::handleExecutorError(SyncOpPtr syncOp, ExitInfo opsExitInfo) { +ExitInfo ExecutorWorker::handleExecutorError(SyncOpPtr syncOp, const ExitInfo &opsExitInfo) { assert((syncOp && !opsExitInfo) && "syncOp is nullptr in ExecutorWorker::handleExecutorError"); if (!syncOp) { LOG_WARN(_logger, "syncOp is nullptr in ExecutorWorker::handleExecutorError"); @@ -2529,15 +2473,18 @@ ExitInfo ExecutorWorker::handleExecutorError(SyncOpPtr syncOp, ExitInfo opsExitI return opsExitInfo; } + LOG_WARN(_logger, "Handling " << opsExitInfo << " in ExecutorWorker::handleExecutorError"); + // Handle specific errors switch (static_cast(opsExitInfo)) { case static_cast(ExitInfo(ExitCode::SystemError, ExitCause::FileAccessError)): { - return handleOpsFileAccessError(syncOp, opsExitInfo); + return handleOpsLocalFileAccessError(syncOp, opsExitInfo); } case static_cast(ExitInfo(ExitCode::SystemError, ExitCause::NotFound)): { return handleOpsFileNotFound(syncOp, opsExitInfo); } case static_cast(ExitInfo(ExitCode::BackError, ExitCause::FileAlreadyExist)): + case static_cast(ExitInfo(ExitCode::SystemError, ExitCause::FileAlreadyExist)): case static_cast(ExitInfo(ExitCode::DataError, ExitCause::FileAlreadyExist)): { return handleOpsAlreadyExistError(syncOp, opsExitInfo); } @@ -2545,12 +2492,11 @@ ExitInfo ExecutorWorker::handleExecutorError(SyncOpPtr syncOp, ExitInfo opsExitI break; } }; - LOG_WARN(_logger, - "Unhandled error in ExecutorWorker::handleExecutorError: " << opsExitInfo.code() << " " << opsExitInfo.cause()); + LOG_WARN(_logger, "Unhandled error in ExecutorWorker::handleExecutorError: " << opsExitInfo); return opsExitInfo; } -ExitInfo ExecutorWorker::handleOpsFileAccessError(SyncOpPtr syncOp, ExitInfo opsExitInfo) { +ExitInfo ExecutorWorker::handleOpsLocalFileAccessError(SyncOpPtr syncOp, const ExitInfo &opsExitInfo) { std::shared_ptr localBlacklistedNode = nullptr; std::shared_ptr remoteBlacklistedNode = nullptr; if (syncOp->targetSide() == ReplicaSide::Local && syncOp->type() == OperationType::Create) { @@ -2576,17 +2522,12 @@ ExitInfo ExecutorWorker::handleOpsFileAccessError(SyncOpPtr syncOp, ExitInfo ops return removeDependentOps(localBlacklistedNode, remoteBlacklistedNode, syncOp->type()); } -ExitInfo ExecutorWorker::handleOpsFileNotFound(SyncOpPtr syncOp, ExitInfo opsExitInfo) { - if (syncOp->targetSide() != ReplicaSide::Remote) { - LOGW_SYNCPAL_WARN(_logger, L"Unhandled target side for " << opsExitInfo << L": " << syncOp->targetSide()); - return opsExitInfo; // Unable to handle this error - } - +ExitInfo ExecutorWorker::handleOpsFileNotFound(SyncOpPtr syncOp, [[maybe_unused]] const ExitInfo &opsExitInfo) { _syncPal->setRestart(true); return removeDependentOps(syncOp); } -ExitInfo ExecutorWorker::handleOpsAlreadyExistError(SyncOpPtr syncOp, ExitInfo opsExitInfo) { +ExitInfo ExecutorWorker::handleOpsAlreadyExistError(SyncOpPtr syncOp, const ExitInfo &opsExitInfo) { // If the file/directory already exist either on local or remote side, we blacklist it localy and the remote // verson will be downloaded again. @@ -2655,16 +2596,15 @@ ExitInfo ExecutorWorker::handleOpsAlreadyExistError(SyncOpPtr syncOp, ExitInfo o if (ExitInfo exitInfo = PlatformInconsistencyCheckerUtility::renameLocalFile( absoluteLocalPath, PlatformInconsistencyCheckerUtility::SuffixType::Blacklisted); !exitInfo) { - LOGW_WARN(_logger, L"Failed to blacklist file: " << Utility::formatSyncPath(absoluteLocalPath) << L" ExitCode::" - << exitInfo.code() << L" ExitCause::" << exitInfo.cause()); + LOGW_WARN(_logger, L"Failed to blacklist file: " << Utility::formatSyncPath(absoluteLocalPath) << L" " << exitInfo); return ExitCode::DataError; // The synchronization will be re-started. } _syncPal->setRestart(true); if (ExitInfo exitInfo = propagateDeleteToDbAndTree(syncOp); !exitInfo) { - LOGW_SYNCPAL_WARN(_logger, L"Failed to propagate changes in DB or update tree for " - << Utility::formatSyncName(syncOp->affectedNode()->name())); + LOGW_SYNCPAL_WARN(_logger, L"Failed to propagate changes in DB or update tree for: " + << Utility::formatSyncName(syncOp->affectedNode()->name()) << L" " << exitInfo); return exitInfo; } return removeDependentOps(syncOp); diff --git a/src/libsyncengine/propagation/executor/executorworker.h b/src/libsyncengine/propagation/executor/executorworker.h index aa42f5be8..82977cee4 100644 --- a/src/libsyncengine/propagation/executor/executorworker.h +++ b/src/libsyncengine/propagation/executor/executorworker.h @@ -81,7 +81,6 @@ class ExecutorWorker : public OperationProcessor { ExitInfo checkLiteSyncInfoForCreate(SyncOpPtr syncOp, const SyncPath &path, bool &isDehydratedPlaceholder); ExitInfo createPlaceholder(const SyncPath &relativeLocalPath); ExitInfo convertToPlaceholder(const SyncPath &relativeLocalPath, bool hydrated); - ExitInfo processCreateOrConvertToPlaceholderError(const SyncPath &relativeLocalPath, bool create); ExitInfo handleEditOp(SyncOpPtr syncOp, std::shared_ptr &job, bool &ignored); ExitInfo generateEditJob(SyncOpPtr syncOp, std::shared_ptr &job); @@ -150,10 +149,10 @@ class ExecutorWorker : public OperationProcessor { // This methode will return ExitCode::Ok if the error is safely managed and the executor can continue. Else, it will // return opsExitInfo. - ExitInfo handleExecutorError(SyncOpPtr syncOp, ExitInfo opsExitInfo); - ExitInfo handleOpsFileAccessError(SyncOpPtr syncOp, ExitInfo opsExitInfo); - ExitInfo handleOpsFileNotFound(SyncOpPtr syncOp, ExitInfo opsExitInfo); - ExitInfo handleOpsAlreadyExistError(SyncOpPtr syncOp, ExitInfo opsExitInfo); + ExitInfo handleExecutorError(SyncOpPtr syncOp, const ExitInfo &opsExitInfo); + ExitInfo handleOpsLocalFileAccessError(SyncOpPtr syncOp, const ExitInfo &opsExitInfo); + ExitInfo handleOpsFileNotFound(SyncOpPtr syncOp, const ExitInfo &opsExitInfo); + ExitInfo handleOpsAlreadyExistError(SyncOpPtr syncOp, const ExitInfo &opsExitInfo); ExitInfo removeDependentOps(SyncOpPtr syncOp); ExitInfo removeDependentOps(std::shared_ptr localNode, std::shared_ptr remoteNode, OperationType opType); diff --git a/src/libsyncengine/syncpal/syncpal.cpp b/src/libsyncengine/syncpal/syncpal.cpp index 212a79a8f..37e4a1923 100644 --- a/src/libsyncengine/syncpal/syncpal.cpp +++ b/src/libsyncengine/syncpal/syncpal.cpp @@ -362,126 +362,120 @@ void SyncPal::addCompletedItem(int syncDbId, const SyncFileItem &item) { } bool SyncPal::vfsIsExcluded(const SyncPath &itemPath, bool &isExcluded) { - if (!_vfsIsExcluded) { + if (!_vfs) { return false; } - - return _vfsIsExcluded(syncDbId(), itemPath, isExcluded); + isExcluded = _vfs->isExcluded(itemPath.native()); + return true; } bool SyncPal::vfsExclude(const SyncPath &itemPath) { - if (!_vfsExclude) { + if (!_vfs) { return false; } - - return _vfsExclude(syncDbId(), itemPath); + _vfs->exclude(itemPath); + return true; } bool SyncPal::vfsPinState(const SyncPath &itemPath, PinState &pinState) { - if (!_vfsPinState) { + if (!_vfs) { return false; } - - return _vfsPinState(syncDbId(), itemPath, pinState); + pinState = _vfs->pinState(itemPath); + return true; } -bool SyncPal::vfsSetPinState(const SyncPath &itemPath, PinState pinState) { - if (!_vfsSetPinState) { - return false; +ExitInfo SyncPal::vfsSetPinState(const SyncPath &itemPath, PinState pinState) { + if (!_vfs) { + return ExitCode::LogicError; } - - return _vfsSetPinState(syncDbId(), itemPath, pinState); + return _vfs->setPinState(itemPath, pinState); } -bool SyncPal::vfsStatus(const SyncPath &itemPath, bool &isPlaceholder, bool &isHydrated, bool &isSyncing, int &progress) { - if (!_vfsStatus) { - return false; +ExitInfo SyncPal::vfsStatus(const SyncPath &itemPath, bool &isPlaceholder, bool &isHydrated, bool &isSyncing, int &progress) { + if (!_vfs) { + return ExitCode::LogicError; } - - return _vfsStatus(syncDbId(), itemPath, isPlaceholder, isHydrated, isSyncing, progress); + return _vfs->status(itemPath, isPlaceholder, isHydrated, isSyncing, progress); } -bool SyncPal::vfsCreatePlaceholder(const SyncPath &relativeLocalPath, const SyncFileItem &item) { - if (!_vfsCreatePlaceholder) { - return false; +ExitInfo SyncPal::vfsCreatePlaceholder(const SyncPath &relativeLocalPath, const SyncFileItem &item) { + if (!_vfs) { + return ExitCode::LogicError; } - - return _vfsCreatePlaceholder(syncDbId(), relativeLocalPath, item); + return _vfs->createPlaceholder(relativeLocalPath, item); } -bool SyncPal::vfsConvertToPlaceholder(const SyncPath &path, const SyncFileItem &item) { - if (!_vfsConvertToPlaceholder) { - return false; +ExitInfo SyncPal::vfsConvertToPlaceholder(const SyncPath &path, const SyncFileItem &item) { + if (!_vfs) { + return ExitCode::LogicError; } - - return _vfsConvertToPlaceholder(syncDbId(), path, item); + return _vfs->convertToPlaceholder(path, item); } -bool SyncPal::vfsUpdateMetadata(const SyncPath &path, const SyncTime &creationTime, const SyncTime &modtime, const int64_t size, - const NodeId &id, std::string &error) { - if (!_vfsUpdateMetadata) { - return false; +ExitInfo SyncPal::vfsUpdateMetadata(const SyncPath &path, const SyncTime &creationTime, const SyncTime &modtime, + const int64_t size, const NodeId &id) { + if (!_vfs) { + return ExitCode::LogicError; } - - return _vfsUpdateMetadata(syncDbId(), path, creationTime, modtime, size, id, error); + return _vfs->updateMetadata(path, creationTime, modtime, size, id); } -bool SyncPal::vfsUpdateFetchStatus(const SyncPath &tmpPath, const SyncPath &path, int64_t received, bool &canceled, - bool &finished) { +ExitInfo SyncPal::vfsUpdateFetchStatus(const SyncPath &tmpPath, const SyncPath &path, int64_t received, bool &canceled, + bool &finished) { if (ParametersCache::isExtendedLogEnabled()) { LOGW_SYNCPAL_DEBUG(_logger, L"vfsUpdateFetchStatus: " << Utility::formatSyncPath(path) << L" received=" << received); } - - if (!_vfsUpdateFetchStatus) { - return false; + if (!_vfs) { + return ExitCode::LogicError; } - - return _vfsUpdateFetchStatus(syncDbId(), tmpPath, path, received, canceled, finished); + return _vfs->updateFetchStatus(tmpPath.native(), path.native(), received, canceled, finished); } bool SyncPal::vfsFileStatusChanged(const SyncPath &path, SyncFileStatus status) { - if (!_vfsFileStatusChanged) { + if (!_vfs) { return false; } - - return _vfsFileStatusChanged(syncDbId(), path, status); + return _vfs->fileStatusChanged(path, status); } -bool SyncPal::vfsForceStatus(const SyncPath &path, bool isSyncing, int progress, bool isHydrated) { - if (!_vfsForceStatus) { - return false; +ExitInfo SyncPal::vfsForceStatus(const SyncPath &path, bool isSyncing, int progress, bool isHydrated) { + if (!_vfs) { + return ExitCode::LogicError; } - - return _vfsForceStatus(syncDbId(), path, isSyncing, progress, isHydrated); + return _vfs->forceStatus(path, isSyncing, progress, isHydrated); } bool SyncPal::vfsCleanUpStatuses() { - if (!_vfsCleanUpStatuses) { + if (!_vfs) { return false; } - - return _vfsCleanUpStatuses(syncDbId()); + return _vfs->cleanUpStatuses(); } bool SyncPal::vfsClearFileAttributes(const SyncPath &path) { - if (!_vfsClearFileAttributes) { + if (!_vfs) { return false; } - - return _vfsClearFileAttributes(syncDbId(), path); + _vfs->clearFileAttributes(path); + return true; } bool SyncPal::vfsCancelHydrate(const SyncPath &path) { - if (!_vfsCancelHydrate) { + if (!_vfs) { return false; } - - return _vfsCancelHydrate(syncDbId(), path); + _vfs->cancelHydrate(path); + return true; } bool SyncPal::wipeVirtualFiles() { LOG_SYNCPAL_INFO(_logger, "Wiping virtual files"); - VirtualFilesCleaner virtualFileCleaner(localPath(), syncDbId(), _syncDb, _vfsStatus, _vfsClearFileAttributes); + if (!_vfs) { + addError(Error(syncDbId(), errId(), ExitCode::LogicError, ExitCause::Unknown)); + return false; + } + VirtualFilesCleaner virtualFileCleaner(localPath(), _syncDb, _vfs); if (!virtualFileCleaner.run()) { LOG_SYNCPAL_WARN(_logger, "Error in VirtualFilesCleaner::run"); addError(Error(syncDbId(), errId(), virtualFileCleaner.exitCode(), virtualFileCleaner.exitCause())); @@ -492,7 +486,7 @@ bool SyncPal::wipeVirtualFiles() { bool SyncPal::wipeOldPlaceholders() { LOG_SYNCPAL_INFO(_logger, "Wiping old placeholders files"); - VirtualFilesCleaner virtualFileCleaner(localPath(), syncDbId()); + VirtualFilesCleaner virtualFileCleaner(localPath()); std::vector failedToRemovePlaceholders; if (!virtualFileCleaner.removeDehydratedPlaceholders(failedToRemovePlaceholders)) { LOG_SYNCPAL_WARN(_logger, "Error in VirtualFilesCleaner::removeDehydratedPlaceholders"); @@ -824,7 +818,7 @@ ExitCode SyncPal::addDlDirectJob(const SyncPath &relativePath, const SyncPath &l if (vfsMode() == VirtualFileMode::Mac || vfsMode() == VirtualFileMode::Win) { // Set callbacks - std::function vfsUpdateFetchStatusCallback = + std::function vfsUpdateFetchStatusCallback = std::bind(&SyncPal::vfsUpdateFetchStatus, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5); job->setVfsUpdateFetchStatusCallback(vfsUpdateFetchStatusCallback); @@ -832,20 +826,20 @@ ExitCode SyncPal::addDlDirectJob(const SyncPath &relativePath, const SyncPath &l #ifdef __APPLE__ // Not done in Windows case: the pin state and the status must not be set by the download job because hydration could be // asked for a move and so, the file place will change just after the dl. - std::function vfsSetPinStateCallback = + std::function vfsSetPinStateCallback = std::bind(&SyncPal::vfsSetPinState, this, std::placeholders::_1, std::placeholders::_2); job->setVfsSetPinStateCallback(vfsSetPinStateCallback); - std::function vfsForceStatusCallback = + std::function vfsForceStatusCallback = std::bind(&SyncPal::vfsForceStatus, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4); job->setVfsForceStatusCallback(vfsForceStatusCallback); #endif - std::function + std::function vfsUpdateMetadataCallback = std::bind(&SyncPal::vfsUpdateMetadata, this, std::placeholders::_1, std::placeholders::_2, - std::placeholders::_3, std::placeholders::_4, std::placeholders::_5, std::placeholders::_6); + std::placeholders::_3, std::placeholders::_4, std::placeholders::_5); job->setVfsUpdateMetadataCallback(vfsUpdateMetadataCallback); std::function vfsCancelHydrateCallback = diff --git a/src/libsyncengine/syncpal/syncpal.h b/src/libsyncengine/syncpal/syncpal.h index 47412c405..4e9a740f2 100644 --- a/src/libsyncengine/syncpal/syncpal.h +++ b/src/libsyncengine/syncpal/syncpal.h @@ -29,6 +29,7 @@ #include "reconciliation/syncoperation.h" #include "libcommonserver/log/log.h" #include "libcommon/utility/types.h" +#include "libcommonserver/vfs.h" #include "libparms/db/parmsdb.h" #include @@ -106,54 +107,17 @@ class SYNCENGINE_EXPORT SyncPal : public std::enable_shared_from_this { virtual ~SyncPal(); ExitCode setTargetNodeId(const std::string &targetNodeId); - - inline void setAddErrorCallback(void (*addError)(const Error &)) { _addError = addError; } - inline void setAddCompletedItemCallback(void (*addCompletedItem)(int, const SyncFileItem &, bool)) { + inline void setAddErrorCallback(const std::function &addError) { _addError = addError; } + inline void setAddCompletedItemCallback(const std::function &addCompletedItem) { _addCompletedItem = addCompletedItem; } - inline void setSendSignalCallback(void (*sendSignal)(SignalNum, int, const SigValueType &)) { _sendSignal = sendSignal; } - inline void setVfsIsExcludedCallback(bool (*vfsIsExcluded)(int, const SyncPath &, bool &)) { - _vfsIsExcluded = vfsIsExcluded; - } - inline void setVfsExcludeCallback(bool (*vfsExclude)(int, const SyncPath &)) { _vfsExclude = vfsExclude; } - inline void setVfsPinStateCallback(bool (*vfsPinState)(int, const SyncPath &, PinState &)) { _vfsPinState = vfsPinState; } - inline void setVfsSetPinStateCallback(bool (*vfsSetPinState)(int, const SyncPath &, PinState)) { - _vfsSetPinState = vfsSetPinState; - } - inline void setVfsStatusCallback(bool (*vfsStatus)(int, const SyncPath &, bool &, bool &, bool &, int &)) { - _vfsStatus = vfsStatus; - } - inline void setVfsCreatePlaceholderCallback(bool (*vfsCreatePlaceholder)(int, const SyncPath &, const SyncFileItem &)) { - _vfsCreatePlaceholder = vfsCreatePlaceholder; - } - inline void setVfsConvertToPlaceholderCallback(bool (*vfsConvertToPlaceholder)(int, const SyncPath &, - const SyncFileItem &)) { - _vfsConvertToPlaceholder = vfsConvertToPlaceholder; - } - inline void setVfsUpdateMetadataCallback(bool (*vfsUpdateMetadata)(int, const SyncPath &, const SyncTime &, - const SyncTime &, const int64_t, const NodeId &, - std::string &)) { - _vfsUpdateMetadata = vfsUpdateMetadata; - } - inline void setVfsUpdateFetchStatusCallback(bool (*vfsUpdateFetchStatus)(int, const SyncPath &, const SyncPath &, int64_t, - bool &, bool &)) { - _vfsUpdateFetchStatus = vfsUpdateFetchStatus; - } - inline void setVfsFileStatusChangedCallback(bool (*vfsFileStatusChanged)(int, const SyncPath &, SyncFileStatus)) { - _vfsFileStatusChanged = vfsFileStatusChanged; - } - inline void setVfsForceStatusCallback(bool (*vfsForceStatus)(int, const SyncPath &, bool, int, bool)) { - _vfsForceStatus = vfsForceStatus; - } - inline void setVfsCleanUpStatusesCallback(bool (*vfsCleanUpStatuses)(int)) { _vfsCleanUpStatuses = vfsCleanUpStatuses; } - inline void setVfsClearFileAttributesCallback(bool (*vfsClearFileAttributes)(int, const SyncPath &)) { - _vfsClearFileAttributes = vfsClearFileAttributes; - } - inline void setVfsCancelHydrateCallback(bool (*vfsCancelHydrate)(int, const SyncPath &)) { - _vfsCancelHydrate = vfsCancelHydrate; + inline void setSendSignalCallback(const std::function &sendSignal) { + _sendSignal = sendSignal; } + inline void setVfsPtr(const std::shared_ptr &vfs) { _vfs = vfs; } + // SyncPalInfo [[nodiscard]] inline std::shared_ptr syncDb() const { return _syncDb; } inline const SyncPalInfo &syncInfo() const { return _syncInfo; } @@ -214,16 +178,16 @@ class SYNCENGINE_EXPORT SyncPal : public std::enable_shared_from_this { bool vfsIsExcluded(const SyncPath &itemPath, bool &isExcluded); bool vfsExclude(const SyncPath &itemPath); bool vfsPinState(const SyncPath &itemPath, PinState &pinState); - bool vfsSetPinState(const SyncPath &itemPath, PinState pinState); - bool vfsStatus(const SyncPath &itemPath, bool &isPlaceholder, bool &isHydrated, bool &isSyncing, int &progress); - bool vfsCreatePlaceholder(const SyncPath &relativeLocalPath, const SyncFileItem &item); - bool vfsConvertToPlaceholder(const SyncPath &path, const SyncFileItem &item); - bool vfsUpdateMetadata(const SyncPath &path, const SyncTime &creationTime, const SyncTime &modtime, const int64_t size, - const NodeId &id, std::string &error); - bool vfsUpdateFetchStatus(const SyncPath &tmpPath, const SyncPath &path, int64_t received, bool &canceled, - bool &finished); + ExitInfo vfsSetPinState(const SyncPath &itemPath, PinState pinState); + ExitInfo vfsStatus(const SyncPath &itemPath, bool &isPlaceholder, bool &isHydrated, bool &isSyncing, int &progress); + ExitInfo vfsCreatePlaceholder(const SyncPath &relativeLocalPath, const SyncFileItem &item); + ExitInfo vfsConvertToPlaceholder(const SyncPath &path, const SyncFileItem &item); + ExitInfo vfsUpdateMetadata(const SyncPath &path, const SyncTime &creationTime, const SyncTime &modtime, + const int64_t size, const NodeId &id); + ExitInfo vfsUpdateFetchStatus(const SyncPath &tmpPath, const SyncPath &path, int64_t received, bool &canceled, + bool &finished); bool vfsFileStatusChanged(const SyncPath &path, SyncFileStatus status); - bool vfsForceStatus(const SyncPath &path, bool isSyncing, int progress, bool isHydrated = false); + ExitInfo vfsForceStatus(const SyncPath &path, bool isSyncing, int progress, bool isHydrated = false); bool vfsCleanUpStatuses(); bool vfsClearFileAttributes(const SyncPath &path); bool vfsCancelHydrate(const SyncPath &path); @@ -291,27 +255,10 @@ class SYNCENGINE_EXPORT SyncPal : public std::enable_shared_from_this { std::mutex _directDownloadJobsMapMutex; // Callbacks - void (*_addError)(const Error &error){nullptr}; - void (*_addCompletedItem)(int syncDbId, const SyncFileItem &item, bool notify){nullptr}; - void (*_sendSignal)(SignalNum sigId, int syncDbId, const SigValueType &val){nullptr}; - - bool (*_vfsIsExcluded)(int syncDbId, const SyncPath &itemPath, bool &isExcluded){nullptr}; - bool (*_vfsExclude)(int syncDbId, const SyncPath &itemPath){nullptr}; - bool (*_vfsPinState)(int syncDbId, const SyncPath &itemPath, PinState &pinState){nullptr}; - bool (*_vfsSetPinState)(int syncDbId, const SyncPath &itemPath, PinState pinState){nullptr}; - bool (*_vfsStatus)(int syncDbId, const SyncPath &itemPath, bool &isPlaceholder, bool &isHydrated, bool &isSyncing, - int &progress){nullptr}; - bool (*_vfsCreatePlaceholder)(int syncDbId, const SyncPath &relativeLocalPath, const SyncFileItem &item){nullptr}; - bool (*_vfsConvertToPlaceholder)(int syncDbId, const SyncPath &path, const SyncFileItem &item){nullptr}; - bool (*_vfsUpdateMetadata)(int syncDbId, const SyncPath &path, const SyncTime &creationTime, const SyncTime &modtime, - const int64_t size, const NodeId &id, std::string &error){nullptr}; - bool (*_vfsUpdateFetchStatus)(int syncDbId, const SyncPath &tmpPath, const SyncPath &path, int64_t received, - bool &canceled, bool &finished){nullptr}; - bool (*_vfsFileStatusChanged)(int syncDbId, const SyncPath &path, SyncFileStatus status){nullptr}; - bool (*_vfsForceStatus)(int syncDbId, const SyncPath &path, bool isSyncing, int progress, bool isHydrated){nullptr}; - bool (*_vfsCleanUpStatuses)(int syncDbId){nullptr}; - bool (*_vfsClearFileAttributes)(int syncDbId, const SyncPath &path){nullptr}; - bool (*_vfsCancelHydrate)(int syncDbId, const SyncPath &path){nullptr}; + std::function _addError; + std::function _addCompletedItem; + std::function _sendSignal; + std::shared_ptr _vfs; // DB std::shared_ptr _syncDb{nullptr}; diff --git a/src/libsyncengine/syncpal/syncpalworker.cpp b/src/libsyncengine/syncpal/syncpalworker.cpp index a1de7a259..303a1f617 100644 --- a/src/libsyncengine/syncpal/syncpalworker.cpp +++ b/src/libsyncengine/syncpal/syncpalworker.cpp @@ -574,8 +574,8 @@ bool SyncPalWorker::resetVfsFilesStatus() { bool isHydrated = false; bool isSyncing = false; int progress = 0; - if (!_syncPal->vfsStatus(dirIt->path(), isPlaceholder, isHydrated, isSyncing, progress)) { - LOGW_SYNCPAL_WARN(_logger, L"Error in vfsStatus : " << Utility::formatSyncPath(dirIt->path()).c_str()); + if (ExitInfo exitInfo = _syncPal->vfsStatus(dirIt->path(), isPlaceholder, isHydrated, isSyncing, progress); !exitInfo) { + LOGW_SYNCPAL_WARN(_logger, L"Error in vfsStatus : " << Utility::formatSyncPath(dirIt->path()) << L": " << exitInfo); ok = false; continue; } @@ -590,9 +590,9 @@ bool SyncPalWorker::resetVfsFilesStatus() { if (isPlaceholder) { if (isSyncing) { // Force status to dehydrated - if (!_syncPal->vfsForceStatus(dirIt->path(), false, 0, false)) { - LOGW_SYNCPAL_WARN(_logger, - L"Error in vfsForceStatus : " << Utility::formatSyncPath(dirIt->path()).c_str()); + if (ExitInfo exitInfo = _syncPal->vfsForceStatus(dirIt->path(), false, 0, false); !exitInfo) { + LOGW_SYNCPAL_WARN(_logger, L"Error in vfsForceStatus : " << Utility::formatSyncPath(dirIt->path()) + << L": " << exitInfo); ok = false; continue; } @@ -601,25 +601,25 @@ bool SyncPalWorker::resetVfsFilesStatus() { // Fix pinstate if needed if (isHydrated && pinState != PinState::AlwaysLocal) { - if (!_syncPal->vfsSetPinState(dirIt->path(), PinState::AlwaysLocal)) { + if (ExitInfo exitInfo = _syncPal->vfsSetPinState(dirIt->path(), PinState::AlwaysLocal); !exitInfo) { LOGW_SYNCPAL_WARN(_logger, - L"Error in vfsSetPinState : " << Utility::formatSyncPath(dirIt->path()).c_str()); + L"Error in vfsSetPinState : " << Utility::formatSyncPath(dirIt->path()) << exitInfo); ok = false; continue; } } else if (!isHydrated && pinState != PinState::OnlineOnly) { - if (!_syncPal->vfsSetPinState(dirIt->path(), PinState::OnlineOnly)) { + if (ExitInfo exitInfo = _syncPal->vfsSetPinState(dirIt->path(), PinState::OnlineOnly); !exitInfo) { LOGW_SYNCPAL_WARN(_logger, - L"Error in vfsSetPinState : " << Utility::formatSyncPath(dirIt->path()).c_str()); + L"Error in vfsSetPinState : " << Utility::formatSyncPath(dirIt->path()) << exitInfo); ok = false; continue; } } } else { if (pinState == PinState::AlwaysLocal || pinState == PinState::OnlineOnly) { - if (!_syncPal->vfsSetPinState(dirIt->path(), PinState::Unspecified)) { + if (ExitInfo exitInfo = _syncPal->vfsSetPinState(dirIt->path(), PinState::Unspecified); !exitInfo) { LOGW_SYNCPAL_WARN(_logger, - L"Error in vfsSetPinState : " << Utility::formatSyncPath(dirIt->path()).c_str()); + L"Error in vfsSetPinState : " << Utility::formatSyncPath(dirIt->path()) << exitInfo); ok = false; continue; } diff --git a/src/libsyncengine/syncpal/virtualfilescleaner.cpp b/src/libsyncengine/syncpal/virtualfilescleaner.cpp index e98f1ed88..0326c0db9 100644 --- a/src/libsyncengine/syncpal/virtualfilescleaner.cpp +++ b/src/libsyncengine/syncpal/virtualfilescleaner.cpp @@ -30,19 +30,16 @@ namespace KDC { -VirtualFilesCleaner::VirtualFilesCleaner(const SyncPath &path, int syncDbId, std::shared_ptr syncDb, - bool (*vfsStatus)(int, const SyncPath &, bool &, bool &, bool &, int &), - bool (*vfsClearFileAttributes)(int, const SyncPath &)) : - _logger(Log::instance()->getLogger()), _rootPath(path), _syncDbId(syncDbId), _syncDb(syncDb), _vfsStatus(vfsStatus), - _vfsClearFileAttributes(vfsClearFileAttributes) {} +VirtualFilesCleaner::VirtualFilesCleaner(const SyncPath &path, std::shared_ptr syncDb, const std::shared_ptr &vfs) : + _logger(Log::instance()->getLogger()), _rootPath(path), _syncDb(syncDb), _vfs(vfs) {} -VirtualFilesCleaner::VirtualFilesCleaner(const SyncPath &path, int syncDbId) : - _logger(Log::instance()->getLogger()), _rootPath(path), _syncDbId(syncDbId) {} +VirtualFilesCleaner::VirtualFilesCleaner(const SyncPath &path) : + _logger(Log::instance()->getLogger()), _rootPath(path) {} bool VirtualFilesCleaner::run() { // Clear xattr on root path - assert(_vfsClearFileAttributes); - _vfsClearFileAttributes(_syncDbId, _rootPath); + assert(_vfs); + _vfs->clearFileAttributes(_rootPath); return removePlaceholdersRecursively(_rootPath); } @@ -91,11 +88,12 @@ bool VirtualFilesCleaner::removePlaceholdersRecursively(const SyncPath &parentPa bool isHydrated = false; bool isSyncing = false; int progress = 0; - assert(_vfsStatus); - if (!_vfsStatus(_syncDbId, dirIt->path(), isPlaceholder, isHydrated, isSyncing, progress)) { - LOGW_WARN(_logger, L"Error in vfsStatus for path=" << Path2WStr(dirIt->path()).c_str()); - _exitCode = ExitCode::SystemError; - _exitCause = ExitCause::Unknown; + assert(_vfs); + if (ExitInfo exitInfo = _vfs->status(entryPathStr, isPlaceholder, isHydrated, isSyncing, progress); + !exitInfo) { + LOGW_WARN(_logger, L"Error in vfsStatus for path=" << Path2WStr(dirIt->path()) << L": " << exitInfo); + _exitCode = exitInfo.code(); + _exitCause = exitInfo.cause(); return false; } @@ -164,8 +162,8 @@ bool VirtualFilesCleaner::removePlaceholdersRecursively(const SyncPath &parentPa } // Clear xattr - assert(_vfsClearFileAttributes); - _vfsClearFileAttributes(_syncDbId, dirIt->path()); + assert(_vfs); + _vfs->clearFileAttributes(entryPathStr); } } catch (std::filesystem::filesystem_error &e) { LOG_WARN(_logger, "Error caught in VirtualFilesCleaner::removePlaceholdersRecursively: code=" << e.code() diff --git a/src/libsyncengine/syncpal/virtualfilescleaner.h b/src/libsyncengine/syncpal/virtualfilescleaner.h index 6c5e53db8..1f5a61d7e 100644 --- a/src/libsyncengine/syncpal/virtualfilescleaner.h +++ b/src/libsyncengine/syncpal/virtualfilescleaner.h @@ -19,6 +19,7 @@ #pragma once #include "utility/types.h" +#include "libcommonserver/vfs.h" #include @@ -28,11 +29,9 @@ class SyncDb; class VirtualFilesCleaner { public: - VirtualFilesCleaner(const SyncPath &path, int syncDbId, std::shared_ptr syncDb, - bool (*vfsStatus)(int, const SyncPath &, bool &, bool &, bool &, int &), - bool (*vfsClearFileAttributes)(int, const SyncPath &)); + VirtualFilesCleaner(const SyncPath &path, std::shared_ptr syncDb, const std::shared_ptr &vfs); - VirtualFilesCleaner(const SyncPath &path, int syncDbId); + explicit VirtualFilesCleaner(const SyncPath &path); bool run(); bool removeDehydratedPlaceholders(std::vector &failedToRemovePlaceholders); @@ -48,11 +47,8 @@ class VirtualFilesCleaner { log4cplus::Logger _logger; SyncPath _rootPath; - int _syncDbId{-1}; std::shared_ptr _syncDb = nullptr; - bool (*_vfsStatus)(int syncDbId, const SyncPath &itemPath, bool &isPlaceholder, bool &isHydrated, bool &isSyncing, - int &progress) = nullptr; - bool (*_vfsClearFileAttributes)(int syncDbId, const SyncPath &itemPath) = nullptr; + std::shared_ptr _vfs; ExitCode _exitCode = ExitCode::Unknown; ExitCause _exitCause = ExitCause::Unknown; diff --git a/src/libsyncengine/update_detection/file_system_observer/localfilesystemobserverworker.cpp b/src/libsyncengine/update_detection/file_system_observer/localfilesystemobserverworker.cpp index 8e2278677..8f975e49d 100644 --- a/src/libsyncengine/update_detection/file_system_observer/localfilesystemobserverworker.cpp +++ b/src/libsyncengine/update_detection/file_system_observer/localfilesystemobserverworker.cpp @@ -277,8 +277,10 @@ void LocalFileSystemObserverWorker::changesDetected(const std::listvfsStatus(absolutePath, isPlaceholder, isHydrated, isSyncing, progress)) { - LOGW_SYNCPAL_WARN(_logger, L"Error in vfsStatus: " << Utility::formatSyncPath(absolutePath)); + if (ExitInfo exitInfo = _syncPal->vfsStatus(absolutePath, isPlaceholder, isHydrated, isSyncing, progress); + !exitInfo) { + LOGW_SYNCPAL_WARN(_logger, + L"Error in vfsStatus: " << Utility::formatSyncPath(absolutePath) << L": " << exitInfo); invalidateSnapshot(); return; } @@ -454,6 +456,7 @@ void LocalFileSystemObserverWorker::execute() { break; } if (!_folderWatcher->exitInfo()) { + LOG_SYNCPAL_WARN(_logger, "Error in FolderWatcher: " << _folderWatcher->exitInfo()); exitCode = _folderWatcher->exitInfo().code(); setExitCause(_folderWatcher->exitInfo().cause()); invalidateSnapshot(); @@ -538,9 +541,9 @@ bool LocalFileSystemObserverWorker::canComputeChecksum(const SyncPath &absoluteP bool isHydrated = false; bool isSyncing = false; int progress = 0; - if (!_syncPal->vfsStatus(absolutePath, isPlaceholder, isHydrated, isSyncing, progress)) { - LOGW_WARN(_logger, L"Error in vfsStatus: " << Utility::formatSyncPath(absolutePath)); - return false; + if (ExitInfo exitInfo = _syncPal->vfsStatus(absolutePath, isPlaceholder, isHydrated, isSyncing, progress); !exitInfo) { + LOGW_WARN(_logger, L"Error in vfsStatus: " << Utility::formatSyncPath(absolutePath) << L": " << exitInfo); + return exitInfo; } return !isPlaceholder || (isHydrated && !isSyncing); diff --git a/src/libsyncengine/update_detection/update_detector/updatetree.cpp b/src/libsyncengine/update_detection/update_detector/updatetree.cpp index db49eacb9..c3d724d4c 100644 --- a/src/libsyncengine/update_detection/update_detector/updatetree.cpp +++ b/src/libsyncengine/update_detection/update_detector/updatetree.cpp @@ -181,7 +181,7 @@ bool UpdateTree::updateNodeId(std::shared_ptr node, const NodeId &newId) { } if (ParametersCache::isExtendedLogEnabled() && newId != oldId) { - LOGW_WARN(Log::instance()->getLogger(), _side << L" update tree: Node ID changed from '" << Utility::s2ws(oldId) + LOGW_DEBUG(Log::instance()->getLogger(), _side << L" update tree: Node ID changed from '" << Utility::s2ws(oldId) << L"' to '" << Utility::s2ws(newId) << L"' for node " << Utility::formatSyncName(node->name()) << L"'."); } diff --git a/src/server/CMakeLists.txt b/src/server/CMakeLists.txt index 77e26dd32..520936f22 100644 --- a/src/server/CMakeLists.txt +++ b/src/server/CMakeLists.txt @@ -38,8 +38,6 @@ endif() set(server_SRCS ../libcommonserver/commserver.h ../libcommonserver/commserver.cpp - ../libcommonserver/vfs.h ../libcommonserver/vfs.cpp - ../libcommonserver/plugin.h ../libcommonserver/plugin.cpp navigationpanehelper.h navigationpanehelper.cpp logarchiver/logarchiver.h logarchiver/logarchiver.cpp logarchiver/logarchiverhelper.h logarchiver/logarchiverhelper.cpp diff --git a/src/server/appserver.cpp b/src/server/appserver.cpp index 7791f6bf2..31b91645d 100644 --- a/src/server/appserver.cpp +++ b/src/server/appserver.cpp @@ -1109,11 +1109,13 @@ void AppServer::onRequestReceived(int id, RequestNum num, const QByteArray ¶ return; } - exitCode = tryCreateAndStartVfs(sync); - const bool start = exitCode == ExitCode::Ok; + if (ExitInfo exitInfo = tryCreateAndStartVfs(sync); !exitInfo) { + LOG_WARN(_logger, "Error in tryCreateAndStartVfs for syncDbId=" << sync.dbId() << " " << exitInfo); + return; + } // Create and start SyncPal - exitCode = initSyncPal(sync, blackList, QSet(), whiteList, start, false, true); + exitCode = initSyncPal(sync, blackList, QSet(), whiteList, true, false, true); if (exitCode != ExitCode::Ok) { LOG_WARN(_logger, "Error in initSyncPal for syncDbId=" << syncInfo.dbId() << " code=" << exitCode); addError(Error(errId(), exitCode, exitCause)); @@ -1198,11 +1200,13 @@ void AppServer::onRequestReceived(int id, RequestNum num, const QByteArray ¶ return; } - exitCode = tryCreateAndStartVfs(sync); - const bool start = exitCode == ExitCode::Ok; + if (ExitInfo exitInfo = tryCreateAndStartVfs(sync); !exitInfo) { + LOG_WARN(_logger, "Error in tryCreateAndStartVfs for syncDbId=" << sync.dbId() << " " << exitInfo); + return; + } // Create and start SyncPal - exitCode = initSyncPal(sync, blackList, QSet(), whiteList, start, false, true); + exitCode = initSyncPal(sync, blackList, QSet(), whiteList, true, false, true); if (exitCode != ExitCode::Ok) { LOG_WARN(_logger, "Error in initSyncPal for syncDbId=" << sync.dbId() << " code=" << exitCode); addError(Error(errId(), exitCode, exitCause)); @@ -1938,19 +1942,17 @@ void AppServer::onRequestReceived(int id, RequestNum num, const QByteArray ¶ QDataStream paramsStream(params); paramsStream >> syncDbId; paramsStream >> state; - - if (_vfsMap.find(syncDbId) == _vfsMap.end()) { - LOG_WARN(_logger, "Vfs not found in vfsMap for syncDbId=" << syncDbId); - resultStream << ExitCode::DataError; + std::shared_ptr vfsPtr; + if (ExitInfo exitInfo = getVfsPtr(syncDbId, vfsPtr); !exitInfo) { + LOG_WARN(_logger, "Error in getVfsPtr for syncDbId=" << syncDbId << " " << exitInfo); + resultStream << exitInfo.code(); break; } - - if (!_vfsMap[syncDbId]->setPinState(QString(), state)) { - LOG_WARN(_logger, "Error in Vfs::setPinState for root directory"); - resultStream << ExitCode::SystemError; + if (const ExitInfo exitInfo = vfsPtr->setPinState("", state); !exitInfo) { + LOG_WARN(_logger, "Error in vfsSetPinState for syncDbId=" << syncDbId << " " << exitInfo); + resultStream << exitInfo.code(); break; } - resultStream << ExitCode::Ok; break; } @@ -2307,206 +2309,29 @@ void AppServer::sendSignal(SignalNum sigNum, int syncDbId, const SigValueType &v CommServer::instance()->sendSignal(sigNum, params, id); } -bool AppServer::vfsIsExcluded(int syncDbId, const SyncPath &itemPath, bool &isExcluded) { - if (_vfsMap.find(syncDbId) == _vfsMap.end()) { +ExitInfo AppServer::getVfsPtr(int syncDbId, std::shared_ptr &vfs) { + auto vfsMapIt = _vfsMap.find(syncDbId); + if (vfsMapIt == _vfsMap.end()) { LOG_WARN(Log::instance()->getLogger(), "Vfs not found in vfsMap for syncDbId=" << syncDbId); - return false; + return ExitCode::LogicError; } - - isExcluded = _vfsMap[syncDbId]->isExcluded(SyncName2QStr(itemPath.native())); - - return true; -} - -bool AppServer::vfsExclude(int syncDbId, const SyncPath &itemPath) { - if (_vfsMap.find(syncDbId) == _vfsMap.end()) { - LOG_WARN(Log::instance()->getLogger(), "Vfs not found in vfsMap for syncDbId=" << syncDbId); - return false; - } - - _vfsMap[syncDbId]->exclude(SyncName2QStr(itemPath.native())); - - return true; -} - -bool AppServer::vfsPinState(int syncDbId, const SyncPath &absolutePath, PinState &pinState) { - if (_vfsMap.find(syncDbId) == _vfsMap.end()) { - LOG_WARN(Log::instance()->getLogger(), "Vfs not found in vfsMap for syncDbId=" << syncDbId); - return false; - } - - SyncPath relativePath = CommonUtility::relativePath(_syncPalMap[syncDbId]->localPath(), absolutePath); - PinState tmpPinState = _vfsMap[syncDbId]->pinState(SyncName2QStr(relativePath.native())); - pinState = (tmpPinState != PinState::Inherited) ? tmpPinState : PinState::Unspecified; - return true; -} - -bool AppServer::vfsSetPinState(int syncDbId, const SyncPath &itemPath, PinState pinState) { - if (_vfsMap.find(syncDbId) == _vfsMap.end()) { - LOG_WARN(Log::instance()->getLogger(), "Vfs not found in vfsMap for syncDbId=" << syncDbId); - return false; - } - - SyncPath relativePath = CommonUtility::relativePath(_syncPalMap[syncDbId]->localPath(), itemPath); - if (!_vfsMap[syncDbId]->setPinState(SyncName2QStr(relativePath.native()), pinState)) { - LOGW_WARN(Log::instance()->getLogger(), - L"Error in Vfs::setPinState for syncDbId=" << syncDbId << L" and path=" << Path2WStr(itemPath).c_str()); - return false; - } - - return true; -} - -bool AppServer::vfsStatus(int syncDbId, const SyncPath &itemPath, bool &isPlaceholder, bool &isHydrated, bool &isSyncing, - int &progress) { - if (_vfsMap.find(syncDbId) == _vfsMap.end()) { - LOG_WARN(Log::instance()->getLogger(), "Vfs not found in vfsMap for syncDbId=" << syncDbId); - return false; - } - - return _vfsMap[syncDbId]->status(SyncName2QStr(itemPath.native()), isPlaceholder, isHydrated, isSyncing, progress); -} - -bool AppServer::vfsCreatePlaceholder(int syncDbId, const SyncPath &relativeLocalPath, const SyncFileItem &item) { - auto vfsIt = _vfsMap.find(syncDbId); - if (vfsIt == _vfsMap.end()) { - LOG_WARN(Log::instance()->getLogger(), "Vfs not found in vfsMap for syncDbId=" << syncDbId); - return false; - } - - if (vfsIt->second && !vfsIt->second->createPlaceholder(relativeLocalPath, item)) { - LOGW_WARN(Log::instance()->getLogger(), L"Error in Vfs::createPlaceholder for syncDbId=" - << syncDbId << L" and path=" << Path2WStr(item.path()).c_str()); - return false; - } - - return true; -} - -bool AppServer::vfsConvertToPlaceholder(int syncDbId, const SyncPath &path, const SyncFileItem &item) { - if (_vfsMap.find(syncDbId) == _vfsMap.end()) { - LOG_WARN(Log::instance()->getLogger(), "Vfs not found in vfsMap for syncDbId=" << syncDbId); - return false; - } - - if (!_vfsMap[syncDbId]->convertToPlaceholder(SyncName2QStr(path.native()), item)) { - LOGW_WARN(Log::instance()->getLogger(), L"Error in Vfs::convertToPlaceholder for syncDbId=" - << syncDbId << L" and path=" << Path2WStr(item.path()).c_str()); - return false; - } - - return true; -} - -bool AppServer::vfsUpdateMetadata(int syncDbId, const SyncPath &path, const SyncTime &creationTime, const SyncTime &modtime, - const int64_t size, const NodeId &id, std::string &error) { - if (_vfsMap.find(syncDbId) == _vfsMap.end()) { - LOG_WARN(Log::instance()->getLogger(), "Vfs not found in vfsMap for syncDbId=" << syncDbId); - return false; - } - - const QByteArray fileId(id.c_str()); - QString errorStr; - if (!_vfsMap[syncDbId]->updateMetadata(SyncName2QStr(path.native()), creationTime, modtime, size, fileId, &errorStr)) { - LOGW_WARN(Log::instance()->getLogger(), - L"Error in Vfs::updateMetadata for syncDbId=" << syncDbId << L" and path=" << Path2WStr(path).c_str()); - error = errorStr.toStdString(); - return false; - } - - return true; -} - -bool AppServer::vfsUpdateFetchStatus(int syncDbId, const SyncPath &tmpPath, const SyncPath &path, int64_t received, - bool &canceled, bool &finished) { - if (_vfsMap.find(syncDbId) == _vfsMap.end()) { - LOG_WARN(Log::instance()->getLogger(), "Vfs not found in vfsMap for syncDbId=" << syncDbId); - return false; - } - - if (!_vfsMap[syncDbId]->updateFetchStatus(SyncName2QStr(tmpPath), SyncName2QStr(path), received, canceled, finished)) { - LOGW_WARN(Log::instance()->getLogger(), - L"Error in Vfs::updateFetchStatus for syncDbId=" << syncDbId << L" and path=" << Path2WStr(path).c_str()); - return false; + if (!vfsMapIt->second) { + LOG_WARN(Log::instance()->getLogger(), "Vfs is null for syncDbId=" << syncDbId); + return ExitCode::LogicError; } - - return true; -} - -bool AppServer::vfsFileStatusChanged(int syncDbId, const SyncPath &path, SyncFileStatus status) { - if (_vfsMap.find(syncDbId) == _vfsMap.end()) { - LOG_WARN(Log::instance()->getLogger(), "Vfs not found in vfsMap for syncDbId=" << syncDbId); - return false; - } - - if (!_vfsMap[syncDbId]->fileStatusChanged(SyncName2QStr(path.native()), status)) { - LOGW_WARN(Log::instance()->getLogger(), - L"Error in Vfs::fileStatusChanged for syncDbId=" << syncDbId << L" and path=" << Path2WStr(path).c_str()); - return false; - } - - return true; -} - -bool AppServer::vfsForceStatus(int syncDbId, const SyncPath &path, bool isSyncing, int progress, bool isHydrated) { - if (_vfsMap.find(syncDbId) == _vfsMap.end()) { - LOG_WARN(Log::instance()->getLogger(), "Vfs not found in vfsMap for syncDbId=" << syncDbId); - return false; - } - - if (!_vfsMap[syncDbId]->forceStatus(SyncName2QStr(path.native()), isSyncing, progress, isHydrated)) { - LOGW_WARN(Log::instance()->getLogger(), - L"Error in Vfs::forceStatus for syncDbId=" << syncDbId << L" and path=" << Path2WStr(path).c_str()); - return false; - } - - return true; -} - -bool AppServer::vfsCleanUpStatuses(int syncDbId) { - if (_vfsMap.find(syncDbId) == _vfsMap.end()) { - LOG_WARN(Log::instance()->getLogger(), "Vfs not found in vfsMap for syncDbId=" << syncDbId); - return false; - } - - if (!_vfsMap[syncDbId]->cleanUpStatuses()) { - LOGW_WARN(Log::instance()->getLogger(), L"Error in Vfs::cleanUpStatuses for syncDbId=" << syncDbId); - return false; - } - - return true; -} - -bool AppServer::vfsClearFileAttributes(int syncDbId, const SyncPath &path) { - if (_vfsMap.find(syncDbId) == _vfsMap.end()) { - LOG_WARN(Log::instance()->getLogger(), "Vfs not found in vfsMap for syncDbId=" << syncDbId); - return false; - } - - _vfsMap[syncDbId]->clearFileAttributes(SyncName2QStr(path.native())); - - return true; -} - -bool AppServer::vfsCancelHydrate(int syncDbId, const SyncPath &path) { - if (_vfsMap.find(syncDbId) == _vfsMap.end()) { - LOG_WARN(Log::instance()->getLogger(), "Vfs not found in vfsMap for syncDbId=" << syncDbId); - return false; - } - - _vfsMap[syncDbId]->cancelHydrate(SyncName2QStr(path.native())); - - return true; + vfs = vfsMapIt->second; + return ExitCode::Ok; } void AppServer::syncFileStatus(int syncDbId, const SyncPath &path, SyncFileStatus &status) { - if (_vfsMap.find(syncDbId) == _vfsMap.end()) { - LOG_WARN(Log::instance()->getLogger(), "Vfs not found in vfsMap for syncDbId=" << syncDbId); + auto syncPalMapIt = _syncPalMap.find(syncDbId); + if (syncPalMapIt == _syncPalMap.end()) { + LOG_WARN(Log::instance()->getLogger(), "SyncPal not found in SyncPalMap for syncDbId=" << syncDbId); addError(Error(errId(), ExitCode::DataError, ExitCause::Unknown)); return; } - ExitCode exitCode = _syncPalMap[syncDbId]->fileStatus(ReplicaSide::Local, path, status); + ExitCode exitCode = syncPalMapIt->second->fileStatus(ReplicaSide::Local, path, status); if (exitCode != ExitCode::Ok) { LOG_WARN(Log::instance()->getLogger(), "Error in SyncPal::fileStatus for syncDbId=" << syncDbId); addError(Error(errId(), exitCode, ExitCause::Unknown)); @@ -2514,13 +2339,14 @@ void AppServer::syncFileStatus(int syncDbId, const SyncPath &path, SyncFileStatu } void AppServer::syncFileSyncing(int syncDbId, const SyncPath &path, bool &syncing) { - if (_vfsMap.find(syncDbId) == _vfsMap.end()) { - LOG_WARN(Log::instance()->getLogger(), "Vfs not found in vfsMap for syncDbId=" << syncDbId); + auto syncPalMapIt = _syncPalMap.find(syncDbId); + if (syncPalMapIt == _syncPalMap.end()) { + LOG_WARN(Log::instance()->getLogger(), "SyncPal not found in SyncPalMap for syncDbId=" << syncDbId); addError(Error(errId(), ExitCode::DataError, ExitCause::Unknown)); return; } - ExitCode exitCode = _syncPalMap[syncDbId]->fileSyncing(ReplicaSide::Local, path, syncing); + ExitCode exitCode = syncPalMapIt->second->fileSyncing(ReplicaSide::Local, path, syncing); if (exitCode != ExitCode::Ok) { LOG_WARN(Log::instance()->getLogger(), "Error in SyncPal::fileSyncing for syncDbId=" << syncDbId); addError(Error(errId(), exitCode, ExitCause::Unknown)); @@ -2528,13 +2354,14 @@ void AppServer::syncFileSyncing(int syncDbId, const SyncPath &path, bool &syncin } void AppServer::setSyncFileSyncing(int syncDbId, const SyncPath &path, bool syncing) { - if (_vfsMap.find(syncDbId) == _vfsMap.end()) { - LOG_WARN(Log::instance()->getLogger(), "Vfs not found in vfsMap for syncDbId=" << syncDbId); + auto syncPalMapIt = _syncPalMap.find(syncDbId); + if (syncPalMapIt == _syncPalMap.end()) { + LOG_WARN(Log::instance()->getLogger(), "SyncPal not found in SyncPalMap for syncDbId=" << syncDbId); addError(Error(errId(), ExitCode::DataError, ExitCause::Unknown)); return; } - ExitCode exitCode = _syncPalMap[syncDbId]->setFileSyncing(ReplicaSide::Local, path, syncing); + ExitCode exitCode = syncPalMapIt->second->setFileSyncing(ReplicaSide::Local, path, syncing); if (exitCode != ExitCode::Ok) { LOG_WARN(Log::instance()->getLogger(), "Error in SyncPal::setFileSyncing for syncDbId=" << syncDbId); addError(Error(errId(), exitCode, ExitCause::Unknown)); @@ -2792,18 +2619,16 @@ std::string liteSyncActivationLogMessage(bool enabled, int syncDbId) { } // This function will pause the synchronization in case of errors. -ExitCode AppServer::tryCreateAndStartVfs(Sync &sync) noexcept { +ExitInfo AppServer::tryCreateAndStartVfs(Sync &sync) noexcept { const std::string liteSyncMsg = liteSyncActivationLogMessage(sync.virtualFileMode() != VirtualFileMode::Off, sync.dbId()); LOG_INFO(_logger, liteSyncMsg.c_str()); - - ExitCause exitCause = ExitCause::Unknown; - const ExitCode exitCode = createAndStartVfs(sync, exitCause); - if (exitCode != ExitCode::Ok) { - LOG_WARN(_logger, "Error in createAndStartVfs for syncDbId=" << sync.dbId() << " code=" << exitCode << ", pausing."); - addError(Error(sync.dbId(), errId(), exitCode, exitCause)); + const ExitInfo exitInfo = createAndStartVfs(sync); + if (!exitInfo) { + LOG_WARN(_logger, "Error in createAndStartVfs for syncDbId=" << sync.dbId() << " " << exitInfo << ", pausing."); + addError(Error(sync.dbId(), errId(), exitInfo.code(), exitInfo.cause())); } - return exitCode; + return exitInfo; } ExitCode AppServer::startSyncs(User &user, ExitCause &exitCause) { @@ -2886,8 +2711,12 @@ ExitCode AppServer::startSyncs(User &user, ExitCause &exitCause) { continue; } - exitCode = tryCreateAndStartVfs(sync); - const bool start = exitCode == ExitCode::Ok && !user.keychainKey().empty(); + if (ExitInfo exitInfo = tryCreateAndStartVfs(sync); !exitInfo) { + LOG_WARN(_logger, "Error in tryCreateAndStartVfs for syncDbId=" << sync.dbId() << " " << exitInfo); + mainExitCode = exitInfo.code(); + continue; + } + const bool start = !user.keychainKey().empty(); // Create and start SyncPal exitCode = initSyncPal(sync, blackList, undecidedList, QSet(), start, false, false); @@ -3501,20 +3330,13 @@ ExitCode AppServer::initSyncPal(const Sync &sync, const std::unordered_setsetAddCompletedItemCallback(&addCompletedItem); _syncPalMap[sync.dbId()]->setSendSignalCallback(&sendSignal); - _syncPalMap[sync.dbId()]->setVfsIsExcludedCallback(&vfsIsExcluded); - _syncPalMap[sync.dbId()]->setVfsExcludeCallback(&vfsExclude); - _syncPalMap[sync.dbId()]->setVfsPinStateCallback(&vfsPinState); - _syncPalMap[sync.dbId()]->setVfsSetPinStateCallback(&vfsSetPinState); - _syncPalMap[sync.dbId()]->setVfsStatusCallback(&vfsStatus); - _syncPalMap[sync.dbId()]->setVfsCreatePlaceholderCallback(&vfsCreatePlaceholder); - _syncPalMap[sync.dbId()]->setVfsConvertToPlaceholderCallback(&vfsConvertToPlaceholder); - _syncPalMap[sync.dbId()]->setVfsUpdateMetadataCallback(&vfsUpdateMetadata); - _syncPalMap[sync.dbId()]->setVfsUpdateFetchStatusCallback(&vfsUpdateFetchStatus); - _syncPalMap[sync.dbId()]->setVfsFileStatusChangedCallback(&vfsFileStatusChanged); - _syncPalMap[sync.dbId()]->setVfsForceStatusCallback(&vfsForceStatus); - _syncPalMap[sync.dbId()]->setVfsCleanUpStatusesCallback(&vfsCleanUpStatuses); - _syncPalMap[sync.dbId()]->setVfsClearFileAttributesCallback(&vfsClearFileAttributes); - _syncPalMap[sync.dbId()]->setVfsCancelHydrateCallback(&vfsCancelHydrate); + std::shared_ptr vfsPtr; + if (ExitInfo exitInfo = getVfsPtr(sync.dbId(), vfsPtr); !exitInfo) { + LOG_WARN(_logger, "Error in getVfsPtr for syncDbId=" << sync.dbId() << " " << exitInfo); + return exitInfo.code(); + } + + _syncPalMap[sync.dbId()]->setVfsPtr(vfsPtr); if (blackList != std::unordered_set()) { // Set blackList (create or overwrite the possible existing list in DB) @@ -3620,20 +3442,18 @@ ExitCode AppServer::stopSyncPal(int syncDbId, bool pausedByUser, bool quit, bool return ExitCode::Ok; } -ExitCode AppServer::createAndStartVfs(const Sync &sync, ExitCause &exitCause) noexcept { +ExitInfo AppServer::createAndStartVfs(const Sync &sync) noexcept { // Check that the sync folder exists. bool exists = false; IoError ioError = IoError::Success; if (!IoHelper::checkIfPathExists(sync.localPath(), exists, ioError)) { LOGW_WARN(_logger, L"Error in IoHelper::checkIfPathExists " << Utility::formatIoError(sync.localPath(), ioError).c_str()); - exitCause = ExitCause::Unknown; return ExitCode::SystemError; } if (!exists) { LOGW_WARN(_logger, L"Sync localpath " << Utility::formatSyncPath(sync.localPath()).c_str() << L" doesn't exist."); - exitCause = ExitCause::SyncDirDoesntExist; - return ExitCode::SystemError; + return {ExitCode::SystemError, ExitCause::SyncDirDoesntExist}; } if (_vfsMap.find(sync.dbId()) == _vfsMap.end()) { @@ -3642,37 +3462,31 @@ ExitCode AppServer::createAndStartVfs(const Sync &sync, ExitCause &exitCause) no bool found; if (!ParmsDb::instance()->selectDrive(sync.driveDbId(), drive, found)) { LOG_WARN(_logger, "Error in ParmsDb::selectDrive"); - exitCause = ExitCause::DbAccessError; - return ExitCode::DbError; + return {ExitCode::DbError, ExitCause::DbAccessError}; } if (!found) { LOG_WARN(_logger, "Drive not found in drive table for driveDbId=" << sync.driveDbId()); - exitCause = ExitCause::DbEntryNotFound; - return ExitCode::DataError; + return {ExitCode::DataError, ExitCause::DbEntryNotFound}; } Account account; if (!ParmsDb::instance()->selectAccount(drive.accountDbId(), account, found)) { LOG_WARN(_logger, "Error in ParmsDb::selectAccount"); - exitCause = ExitCause::DbAccessError; - return ExitCode::DbError; + return {ExitCode::DbError, ExitCause::DbAccessError}; } if (!found) { LOG_WARN(_logger, "Account not found in account table for accountDbId=" << drive.accountDbId()); - exitCause = ExitCause::DbEntryNotFound; - return ExitCode::DataError; + return {ExitCode::DataError, ExitCause::DbEntryNotFound}; } User user; if (!ParmsDb::instance()->selectUser(account.userDbId(), user, found)) { LOG_WARN(_logger, "Error in ParmsDb::selectUser"); - exitCause = ExitCause::DbAccessError; - return ExitCode::DbError; + return {ExitCode::DbError, ExitCause::DbAccessError}; } if (!found) { LOG_WARN(_logger, "User not found in user table for userDbId=" << account.userDbId()); - exitCause = ExitCause::DbEntryNotFound; - return ExitCode::DataError; + return {ExitCode::DataError, ExitCause::DbEntryNotFound}; } #endif @@ -3693,8 +3507,7 @@ ExitCode AppServer::createAndStartVfs(const Sync &sync, ExitCause &exitCause) no if (!vfsPtr) { LOG_WARN(_logger, "Error in Vfs::createVfsFromPlugin for mode " << sync.virtualFileMode() << " : " << error.toStdString().c_str()); - exitCause = ExitCause::UnableToCreateVfs; - return ExitCode::SystemError; + return {ExitCode::SystemError, ExitCause::UnableToCreateVfs}; } _vfsMap[sync.dbId()] = vfsPtr; _vfsMap[sync.dbId()]->setExtendedLog(ParametersCache::isExtendedLogEnabled()); @@ -3709,7 +3522,8 @@ ExitCode AppServer::createAndStartVfs(const Sync &sync, ExitCause &exitCause) no } // Start VFS - if (!_vfsMap[sync.dbId()]->start(_vfsInstallationDone, _vfsActivationDone, _vfsConnectionDone)) { + if (ExitInfo exitInfo = _vfsMap[sync.dbId()]->start(_vfsInstallationDone, _vfsActivationDone, _vfsConnectionDone); + !exitInfo) { #ifdef Q_OS_MAC if (sync.virtualFileMode() == VirtualFileMode::Mac) { if (_vfsInstallationDone && !_vfsActivationDone) { @@ -3724,16 +3538,14 @@ ExitCode AppServer::createAndStartVfs(const Sync &sync, ExitCause &exitCause) no LOG_WARN(_logger, "LiteSync extension is not enabled or doesn't have full disk access: " << liteSyncExtErrorDescr.c_str()); } - exitCause = ExitCause::LiteSyncNotAllowed; - return ExitCode::SystemError; + return {ExitCode::SystemError, ExitCause::LiteSyncNotAllowed}; } } } #endif - LOG_WARN(_logger, "Error in Vfs::start"); - exitCause = ExitCause::UnableToCreateVfs; - return ExitCode::SystemError; + LOG_WARN(_logger, "Error in Vfs::start " << exitInfo); + return exitInfo; } #ifdef Q_OS_WIN @@ -3757,13 +3569,11 @@ ExitCode AppServer::createAndStartVfs(const Sync &sync, ExitCause &exitCause) no bool found = false; if (!ParmsDb::instance()->updateSync(tmpSync, found)) { LOG_WARN(_logger, "Error in ParmsDb::updateSync"); - exitCause = ExitCause::DbAccessError; - return ExitCode::DbError; + return {ExitCode::DbError, ExitCause::DbAccessError}; } if (!found) { LOG_WARN(_logger, "Sync not found in sync table for syncDbId=" << tmpSync.dbId()); - exitCause = ExitCause::DbEntryNotFound; - return ExitCode::DataError; + return {ExitCode::DataError, ExitCause::DbEntryNotFound}; } #endif return ExitCode::Ok; @@ -3865,8 +3675,10 @@ ExitCode AppServer::setSupportsVirtualFiles(int syncDbId, bool value) { // Delete previous vfs _vfsMap.erase(syncDbId); - exitCode = tryCreateAndStartVfs(sync); - const bool start = exitCode == ExitCode::Ok; + if (ExitInfo exitInfo = tryCreateAndStartVfs(sync); !exitInfo) { + LOG_WARN(_logger, "Error in tryCreateAndStartVfs " << exitInfo); + return exitInfo; + } QTimer::singleShot(100, this, [=]() { if (newMode != VirtualFileMode::Off) { @@ -3883,9 +3695,7 @@ ExitCode AppServer::setSupportsVirtualFiles(int syncDbId, bool value) { sendVfsConversionCompleted(sync.dbId()); // Re-start sync - if (start) { - _syncPalMap[syncDbId]->start(); - } + _syncPalMap[syncDbId]->start(); }); } @@ -4352,8 +4162,10 @@ void AppServer::onRestartSyncs() { sendErrorsCleared(syncPalMapElt.first); // Start VFS - if (!_vfsMap[syncPalMapElt.first]->start(_vfsInstallationDone, _vfsActivationDone, _vfsConnectionDone)) { - LOG_WARN(Log::instance()->getLogger(), "Error in Vfs::start"); + if (ExitInfo exitInfo = + _vfsMap[syncPalMapElt.first]->start(_vfsInstallationDone, _vfsActivationDone, _vfsConnectionDone); + !exitInfo) { + LOG_WARN(Log::instance()->getLogger(), "Error in Vfs::start: " << exitInfo); continue; } diff --git a/src/server/appserver.h b/src/server/appserver.h index 44fd4dd05..3bd60e24a 100644 --- a/src/server/appserver.h +++ b/src/server/appserver.h @@ -140,9 +140,9 @@ class AppServer : public SharedTools::QtSingleApplication { bool firstInit = false); ExitCode stopSyncPal(int syncDbId, bool pausedByUser = false, bool quit = false, bool clear = false); - ExitCode createAndStartVfs(const Sync &sync, ExitCause &exitCause) noexcept; + ExitInfo createAndStartVfs(const Sync &sync) noexcept; // Call createAndStartVfs. Issue warnings, errors and pause the synchronization `sync` if needed. - [[nodiscard]] ExitCode tryCreateAndStartVfs(Sync &sync) noexcept; + [[nodiscard]] ExitInfo tryCreateAndStartVfs(Sync &sync) noexcept; ExitCode stopVfs(int syncDbId, bool unregister); ExitCode setSupportsVirtualFiles(int syncDbId, bool value); @@ -195,23 +195,7 @@ class AppServer : public SharedTools::QtSingleApplication { static void addCompletedItem(int syncDbId, const SyncFileItem &item, bool notify); static void sendSignal(SignalNum sigNum, int syncDbId, const SigValueType &val); - static bool vfsIsExcluded(int syncDbId, const SyncPath &itemPath, bool &isExcluded); - static bool vfsExclude(int syncDbId, const SyncPath &itemPath); - static bool vfsPinState(int syncDbId, const SyncPath &absolutePath, PinState &pinState); - static bool vfsSetPinState(int syncDbId, const SyncPath &itemPath, PinState pinState); - static bool vfsStatus(int syncDbId, const SyncPath &itemPath, bool &isPlaceholder, bool &isHydrated, bool &isSyncing, - int &progress); - static bool vfsCreatePlaceholder(int syncDbIdconst, const SyncPath &relativeLocalPath, const SyncFileItem &item); - static bool vfsConvertToPlaceholder(int syncDbId, const SyncPath &path, const SyncFileItem &item); - static bool vfsUpdateMetadata(int syncDbId, const SyncPath &path, const SyncTime &creationTime, const SyncTime &modtime, - const int64_t size, const NodeId &id, std::string &error); - static bool vfsUpdateFetchStatus(int syncDbId, const SyncPath &tmpPath, const SyncPath &path, int64_t received, - bool &canceled, bool &finished); - static bool vfsFileStatusChanged(int syncDbId, const SyncPath &path, SyncFileStatus status); - static bool vfsForceStatus(int syncDbId, const SyncPath &path, bool isSyncing, int progress, bool isHydrated = false); - static bool vfsCleanUpStatuses(int syncDbId); - static bool vfsClearFileAttributes(int syncDbId, const SyncPath &path); - static bool vfsCancelHydrate(int syncDbId, const SyncPath &path); + static ExitInfo getVfsPtr(int syncDbId, std::shared_ptr &vfs); static void syncFileStatus(int syncDbId, const KDC::SyncPath &path, KDC::SyncFileStatus &status); static void syncFileSyncing(int syncDbId, const KDC::SyncPath &path, bool &syncing); @@ -255,6 +239,4 @@ class AppServer : public SharedTools::QtSingleApplication { signals: void socketApiExecuteCommandDirect(const QString &commandLine); }; - - } // namespace KDC diff --git a/src/server/socketapi.cpp b/src/server/socketapi.cpp index 22bc2469e..371452c78 100644 --- a/src/server/socketapi.cpp +++ b/src/server/socketapi.cpp @@ -92,7 +92,8 @@ struct ListenerHasSocketPred { SocketApi::SocketApi(const std::unordered_map> &syncPalMap, const std::unordered_map> &vfsMap, QObject *parent) : - QObject(parent), _syncPalMap(syncPalMap), _vfsMap(vfsMap) { + QObject(parent), + _syncPalMap(syncPalMap), _vfsMap(vfsMap) { QString socketPath; if (OldUtility::isWindows()) { @@ -442,7 +443,7 @@ bool SocketApi::syncFileStatus(const FileData &fileData, KDC::SyncFileStatus &st if (vfsMapIt->second->mode() == KDC::VirtualFileMode::Mac || vfsMapIt->second->mode() == KDC::VirtualFileMode::Win) { bool isSyncing = false; - if (!vfsMapIt->second->status(fileData.localPath, isPlaceholder, isHydrated, isSyncing, progress)) { + if (!vfsMapIt->second->status(QStr2Path(fileData.localPath), isPlaceholder, isHydrated, isSyncing, progress)) { LOGW_WARN(KDC::Log::instance()->getLogger(), L"Error in Vfs::status - " << Utility::formatPath(fileData.localPath).c_str()); return false; @@ -477,24 +478,22 @@ std::unordered_map>::const_iterator SocketApi::re return result; } -bool SocketApi::setPinState(const FileData &fileData, KDC::PinState pinState) { - if (!fileData.syncDbId) return false; +ExitInfo SocketApi::setPinState(const FileData &fileData, KDC::PinState pinState) { + if (!fileData.syncDbId) return {ExitCode::LogicError, ExitCause::InvalidArgument}; const auto vfsMapIt = retrieveVfsMapIt(fileData.syncDbId); - if (vfsMapIt == _vfsMap.cend()) return false; - - vfsMapIt->second->setPinState(fileData.relativePath, pinState); + if (vfsMapIt == _vfsMap.cend()) return {ExitCode::SystemError, ExitCause::LiteSyncNotAllowed}; - return true; + return vfsMapIt->second->setPinState(QStr2Path(fileData.relativePath), pinState); } -bool SocketApi::dehydratePlaceholder(const FileData &fileData) { - if (!fileData.syncDbId) return false; +ExitInfo SocketApi::dehydratePlaceholder(const FileData &fileData) { + if (!fileData.syncDbId) return {ExitCode::LogicError, ExitCause::InvalidArgument}; const auto vfsMapIt = retrieveVfsMapIt(fileData.syncDbId); - if (vfsMapIt == _vfsMap.cend()) return false; + if (vfsMapIt == _vfsMap.cend()) return {ExitCode::SystemError, ExitCause::LiteSyncNotAllowed}; - return vfsMapIt->second->dehydratePlaceholder(fileData.relativePath); + return vfsMapIt->second->dehydratePlaceholder(QStr2Path(fileData.relativePath)); } bool SocketApi::addDownloadJob(const FileData &fileData) { @@ -697,16 +696,16 @@ void SocketApi::command_MAKE_ONLINE_ONLY_DIRECT(const QString &filesArg, SocketL } // Set pin state - if (!setPinState(fileData, KDC::PinState::OnlineOnly)) { + if (ExitInfo exitInfo = setPinState(fileData, KDC::PinState::OnlineOnly); !exitInfo) { LOGW_INFO(KDC::Log::instance()->getLogger(), - L"Error in SocketApi::setPinState - " << Utility::formatSyncPath(filePath).c_str()); + L"Error in SocketApi::setPinState - " << Utility::formatSyncPath(filePath) << L": " << exitInfo); continue; } // Dehydrate placeholder - if (!dehydratePlaceholder(fileData)) { + if (ExitInfo exitInfo = dehydratePlaceholder(fileData); !exitInfo) { LOGW_INFO(KDC::Log::instance()->getLogger(), - L"Error in SocketApi::dehydratePlaceholder - " << Utility::formatSyncPath(filePath).c_str()); + L"Error in SocketApi::dehydratePlaceholder - " << Utility::formatSyncPath(filePath) << exitInfo); continue; } @@ -759,7 +758,7 @@ void SocketApi::command_CANCEL_HYDRATION_DIRECT(const QString &filesArg) { auto vfsMapIt = retrieveVfsMapIt(fileData.syncDbId); if (vfsMapIt == _vfsMap.cend()) continue; - vfsMapIt->second->cancelHydrate(filePath); + vfsMapIt->second->cancelHydrate(QStr2Path(filePath)); } #endif } @@ -918,7 +917,7 @@ void SocketApi::command_SET_THUMBNAIL(const QString &filePath) { LOG_DEBUG(KDC::Log::instance()->getLogger(), "Thumbnail fetched - size=" << pixmap.width() << "x" << pixmap.height()); // Set thumbnail - if (!vfsMapIt->second->setThumbnail(fileData.localPath, pixmap)) { + if (!vfsMapIt->second->setThumbnail(QStr2Path(fileData.localPath), pixmap)) { LOGW_WARN(KDC::Log::instance()->getLogger(), L"Error in setThumbnail - " << Utility::formatPath(filePath).c_str()); return; } @@ -1095,7 +1094,7 @@ void SocketApi::command_GET_MENU_ITEMS(const QString &argument, SocketListener * bool isHydrated = false; bool isSyncing = false; int progress = 0; - if (!canCancelHydration && vfsMapIt->second->status(file, isPlaceholder, isHydrated, isSyncing, progress) && + if (!canCancelHydration && vfsMapIt->second->status(QStr2Path(file), isPlaceholder, isHydrated, isSyncing, progress) && isSyncing) { canCancelHydration = syncPalMapIt->second->isDownloadOngoing(QStr2Path(file)); } @@ -1151,7 +1150,7 @@ void SocketApi::manageActionsOnSingleFile(SocketListener *listener, const QStrin if (fileData.localPath.isEmpty()) { return; } - bool isExcluded = vfsMapIt->second->isExcluded(fileData.localPath); + bool isExcluded = vfsMapIt->second->isExcluded(QStr2Path(fileData.localPath)); if (isExcluded) { return; } diff --git a/src/server/socketapi.h b/src/server/socketapi.h index 7c78e4bdd..f468e0c2b 100644 --- a/src/server/socketapi.h +++ b/src/server/socketapi.h @@ -172,8 +172,8 @@ class SocketApi : public QObject { void processFileList(const QStringList &inFileList, std::list &outFileList); bool syncFileStatus(const FileData &fileData, KDC::SyncFileStatus &status, bool &isPlaceholder, bool &isHydrated, int &progress); - bool setPinState(const FileData &fileData, KDC::PinState pinState); - bool dehydratePlaceholder(const FileData &fileData); + ExitInfo setPinState(const FileData &fileData, KDC::PinState pinState); + ExitInfo dehydratePlaceholder(const FileData &fileData); bool addDownloadJob(const FileData &fileData); bool cancelDownloadJobs(int syncDbId, const QStringList &fileList); diff --git a/src/server/vfs/mac/CMakeLists.txt b/src/server/vfs/mac/CMakeLists.txt index c4c46e0c4..0cd70b5a7 100644 --- a/src/server/vfs/mac/CMakeLists.txt +++ b/src/server/vfs/mac/CMakeLists.txt @@ -4,8 +4,6 @@ find_package(Qt6) add_library("${libsyncengine_NAME}_vfs_mac" SHARED vfs_mac.h vfs_mac.cpp litesyncextconnector.h litesyncextconnector.mm - ../../../libcommonserver/vfs.h ../../../libcommonserver/vfs.cpp - ../../../libcommonserver/plugin.h ../../../libcommonserver/plugin.cpp ../../../common/filepermissionholder.h ../../../common/filepermissionholder.cpp ../../../common/filesystembase.h ../../../common/filesystembase.cpp ) diff --git a/src/server/vfs/mac/litesyncextconnector.h b/src/server/vfs/mac/litesyncextconnector.h index 177bd4fc6..6e4b706ea 100644 --- a/src/server/vfs/mac/litesyncextconnector.h +++ b/src/server/vfs/mac/litesyncextconnector.h @@ -77,7 +77,7 @@ class LiteSyncExtConnector { }; bool vfsSetAppExcludeList(const QString &appList); bool vfsGetFetchingAppList(QHash &appTable); - bool vfsUpdateMetadata(const QString &absoluteFilePath, const struct stat *fileStat, QString *error); + bool vfsUpdateMetadata(const QString &absoluteFilePath, const struct stat *fileStat); bool vfsIsExcluded(const QString &path); bool vfsProcessDirStatus(const QString &path, const QString &localSyncPath); void vfsClearFileAttributes(const QString &path); diff --git a/src/server/vfs/mac/litesyncextconnector.mm b/src/server/vfs/mac/litesyncextconnector.mm index 717529d6c..95205b224 100644 --- a/src/server/vfs/mac/litesyncextconnector.mm +++ b/src/server/vfs/mac/litesyncextconnector.mm @@ -1292,12 +1292,11 @@ bool checkIoErrorAndLogIfNeeded(IoError ioError, const std::string &itemType, co return _private->getFetchingAppList(appTable); } -bool LiteSyncExtConnector::vfsUpdateMetadata(const QString &absoluteFilePath, const struct stat *fileStat, QString *error) { +bool LiteSyncExtConnector::vfsUpdateMetadata(const QString &absoluteFilePath, const struct stat *fileStat) { FilePermissionHolder permHolder(absoluteFilePath); if (!fileStat) { LOG_WARN(_logger, "Bad parameters"); - *error = QObject::tr("Bad parameters"); return false; } @@ -1323,7 +1322,6 @@ bool checkIoErrorAndLogIfNeeded(IoError ioError, const std::string &itemType, co fd = open(stdPath.c_str(), FWRITE); if (fd == -1) { LOGW_WARN(_logger, L"Call to open failed - " << Utility::formatPath(absoluteFilePath).c_str() << L" errno=" << errno); - *error = QObject::tr("Call to open failed - path=%1").arg(absoluteFilePath); return false; } } @@ -1331,13 +1329,11 @@ bool checkIoErrorAndLogIfNeeded(IoError ioError, const std::string &itemType, co if (ftruncate(fd, fileStat->st_size) == -1) { LOGW_WARN(_logger, L"Call to ftruncate failed - " << Utility::formatPath(absoluteFilePath).c_str() << L" errno=" << errno); - *error = QObject::tr("Call to ftruncate failed - path=%1").arg(absoluteFilePath); return false; } if (close(fd) == -1) { LOGW_WARN(_logger, L"Call to close failed - " << Utility::formatPath(absoluteFilePath).c_str() << L" errno=" << errno); - *error = QObject::tr("Call to close failed - path=%1").arg(absoluteFilePath); return false; } diff --git a/src/server/vfs/mac/vfs_mac.cpp b/src/server/vfs/mac/vfs_mac.cpp index b9b680d86..2b698c2be 100644 --- a/src/server/vfs/mac/vfs_mac.cpp +++ b/src/server/vfs/mac/vfs_mac.cpp @@ -30,10 +30,7 @@ #include namespace KDC { - -const int s_nb_threads[NB_WORKERS] = {5, 5}; - -VfsMac::VfsMac(KDC::VfsSetupParams &vfsSetupParams, QObject *parent) : +VfsMac::VfsMac(const VfsSetupParams &vfsSetupParams, QObject *parent) : Vfs(vfsSetupParams, parent), _localSyncPath{Path2QStr(_vfsSetupParams._localPath)} { // Initialize LiteSync ext connector LOG_INFO(logger(), "Initialize LiteSyncExtConnector"); @@ -47,59 +44,19 @@ VfsMac::VfsMac(KDC::VfsSetupParams &vfsSetupParams, QObject *parent) : throw std::runtime_error("Unable to initialize LiteSyncExtConnector."); } - // Start hydration/dehydration workers - // !!! Disabled for testing because no QEventLoop !!! - if (qApp) { - // Start worker threads - for (int i = 0; i < NB_WORKERS; i++) { - for (int j = 0; j < s_nb_threads[i]; j++) { - QtLoggingThread *workerThread = new QtLoggingThread(); - _workerInfo[i]._threadList.append(workerThread); - Worker *worker = new Worker(this, i, j, logger()); - worker->moveToThread(workerThread); - connect(workerThread, &QThread::started, worker, &Worker::start); - connect(workerThread, &QThread::finished, worker, &QObject::deleteLater); - connect(workerThread, &QThread::finished, workerThread, &QObject::deleteLater); - workerThread->start(); - } - } - } -} - -VfsMac::~VfsMac() { - // Ask worker threads to stop - for (int i = 0; i < NB_WORKERS; i++) { - _workerInfo[i]._mutex.lock(); - _workerInfo[i]._stop = true; - _workerInfo[i]._mutex.unlock(); - _workerInfo[i]._queueWC.wakeAll(); - } - - // Force threads to stop if needed - for (int i = 0; i < NB_WORKERS; i++) { - for (QThread *thread: qAsConst(_workerInfo[i]._threadList)) { - if (thread) { - thread->quit(); - if (!thread->wait(1000)) { - thread->terminate(); - thread->wait(); - } - } - } - } + starVfsWorkers(); } - VirtualFileMode VfsMac::mode() const { return VirtualFileMode::Mac; } -bool VfsMac::startImpl(bool &installationDone, bool &activationDone, bool &connectionDone) { +ExitInfo VfsMac::startImpl(bool &installationDone, bool &activationDone, bool &connectionDone) { LOG_DEBUG(logger(), "startImpl - syncDbId=" << _vfsSetupParams._syncDbId); if (!_connector) { LOG_WARN(logger(), "LiteSyncExtConnector not initialized!"); - return false; + return ExitCode::LogicError; } if (!installationDone) { @@ -108,21 +65,21 @@ bool VfsMac::startImpl(bool &installationDone, bool &activationDone, bool &conne installationDone = _connector->install(activationDone); if (!installationDone) { LOG_WARN(logger(), "Error in LiteSyncExtConnector::install!"); - return false; + return {ExitCode::SystemError, ExitCause::UnableToCreateVfs}; } } if (!activationDone) { LOG_INFO(logger(), "LiteSync extension activation pending"); connectionDone = false; - return false; + return {ExitCode::SystemError, ExitCause::UnableToCreateVfs}; } if (!connectionDone) { connectionDone = _connector->connect(); if (!connectionDone) { LOG_WARN(logger(), "Error in LiteSyncExtConnector::connect!"); - return false; + return {ExitCode::SystemError, ExitCause::UnableToCreateVfs}; } } @@ -137,7 +94,7 @@ bool VfsMac::startImpl(bool &installationDone, bool &activationDone, bool &conne if (!_connector->vfsStart(_vfsSetupParams._syncDbId, folderPath, isPlaceholder, isSyncing)) { LOG_WARN(logger(), "Error in vfsStart!"); resetLiteSyncConnector(); - return false; + return {ExitCode::SystemError, ExitCause::UnableToCreateVfs}; } QStringList filesToFix; @@ -163,10 +120,10 @@ bool VfsMac::startImpl(bool &installationDone, bool &activationDone, bool &conne ok = false; } } - return ok; + return ok ? ExitInfo(ExitCode::Ok) : ExitInfo(ExitCode::SystemError, ExitCause::UnableToCreateVfs); } - return true; + return ExitCode::Ok; } void VfsMac::stopImpl(bool unregister) { @@ -210,39 +167,33 @@ void VfsMac::hydrate(const QString &path) { _setSyncFileSyncing(_vfsSetupParams._syncDbId, QStr2Path(relativePath), false); } -bool VfsMac::forceStatus(const QString &path, bool isSyncing, int progress, bool isHydrated /*= false*/) { - SyncPath stdPath = QStr2Path(path); - - bool exists = false; - IoError ioError = IoError::Success; - if (!IoHelper::checkIfPathExists(stdPath, exists, ioError)) { - LOGW_WARN(logger(), L"Error in IoHelper::checkIfPathExists: " << Utility::formatIoError(stdPath, ioError).c_str()); - return false; +ExitInfo VfsMac::forceStatus(const SyncPath &pathStd, bool isSyncing, int progress, bool isHydrated /*= false*/) { + const QString path = SyncName2QStr(pathStd.native()); + if (ExitInfo exitInfo = checkIfPathExists(pathStd, true); !exitInfo) { + return exitInfo; } - if (!exists) { - // New file - return true; + if (!_connector->vfsSetStatus(path, _localSyncPath, isSyncing, progress, isHydrated)) { + LOG_WARN(logger(), "Error in vfsSetStatus!"); + return handleVfsError(pathStd); } - return _connector->vfsSetStatus(path, _localSyncPath, isSyncing, progress, isHydrated); + return ExitCode::Ok; } bool VfsMac::cleanUpStatuses() { return _connector->vfsCleanUpStatuses(_localSyncPath); } -void VfsMac::clearFileAttributes(const QString &path) { +void VfsMac::clearFileAttributes(const SyncPath &pathStd) { + QString path = SyncName2QStr(pathStd.native()); _connector->vfsClearFileAttributes(path); } -bool VfsMac::isHydrating() const { - return false; -} - -bool VfsMac::updateMetadata(const QString &absoluteFilePath, time_t creationTime, time_t modtime, qint64 size, - const QByteArray &fileId, QString *error) { - Q_UNUSED(fileId); +ExitInfo VfsMac::updateMetadata(const SyncPath &absoluteFilePathStd, time_t creationTime, time_t modtime, int64_t size, + const NodeId &fileIdStr) { + Q_UNUSED(fileIdStr); + const QString absoluteFilePath = SyncName2QStr(absoluteFilePathStd.native()); if (extendedLog()) { LOGW_DEBUG(logger(), L"updateMetadata - " << Utility::formatPath(absoluteFilePath).c_str()); @@ -250,7 +201,7 @@ bool VfsMac::updateMetadata(const QString &absoluteFilePath, time_t creationTime if (!_connector) { LOG_WARN(logger(), "LiteSyncExtConnector not initialized!"); - return false; + return ExitCode::LogicError; } struct stat fileStat; @@ -260,29 +211,30 @@ bool VfsMac::updateMetadata(const QString &absoluteFilePath, time_t creationTime fileStat.st_birthtimespec = {creationTime, 0}; fileStat.st_mode = S_IFREG; - if (!_connector->vfsUpdateMetadata(absoluteFilePath, &fileStat, error)) { + if (!_connector->vfsUpdateMetadata(absoluteFilePath, &fileStat)) { LOG_WARN(logger(), "Error in vfsUpdateMetadata!"); - return false; + return handleVfsError(QStr2Path(absoluteFilePath)); } - return true; + return ExitCode::Ok; } -bool VfsMac::createPlaceholder(const SyncPath &relativeLocalPath, const SyncFileItem &item) { +ExitInfo VfsMac::createPlaceholder(const SyncPath &relativeLocalPath, const SyncFileItem &item) { if (extendedLog()) { LOGW_DEBUG(logger(), L"createPlaceholder - file = " << Utility::formatSyncPath(relativeLocalPath).c_str()); } - SyncPath fullPath(_vfsSetupParams._localPath / relativeLocalPath); - std::error_code ec; - if (std::filesystem::exists(fullPath, ec)) { - LOGW_WARN(logger(), L"File/directory " << Utility::formatSyncPath(relativeLocalPath).c_str() << L" already exists!"); - return false; + if (relativeLocalPath.empty()) { + LOG_WARN(logger(), "VfsMac::createPlaceholder - relativeLocalPath cannot be empty."); + return {ExitCode::SystemError, ExitCause::InvalidArgument}; } - if (ec) { - LOGW_WARN(logger(), L"Failed to check if path exists " << Utility::formatStdError(fullPath, ec).c_str()); - return false; + SyncPath fullPath(_vfsSetupParams._localPath / relativeLocalPath); + if (ExitInfo exitInfo = checkIfPathExists(fullPath, false); !exitInfo) { + return exitInfo; + } + if (ExitInfo exitInfo = checkIfPathExists(fullPath.parent_path(), true); !exitInfo) { + return exitInfo; } // Create placeholder @@ -299,29 +251,21 @@ bool VfsMac::createPlaceholder(const SyncPath &relativeLocalPath, const SyncFile if (!_connector->vfsCreatePlaceHolder(QString::fromStdString(relativeLocalPath.native()), _localSyncPath, &fileStat)) { LOG_WARN(logger(), "Error in vfsCreatePlaceHolder!"); - return false; + return defaultVfsError(); // handleVfsError is not suitable here, the file dosen't exist but we don't want to return + // NotFound as this make no sense in the context of a create } - return true; + return ExitCode::Ok; } -bool VfsMac::dehydratePlaceholder(const QString &path) { +ExitInfo VfsMac::dehydratePlaceholder(const SyncPath &path) { if (extendedLog()) { - LOGW_DEBUG(logger(), L"dehydratePlaceholder - file " << Utility::formatPath(path).c_str()); + LOGW_DEBUG(logger(), L"dehydratePlaceholder - file " << Utility::formatSyncPath(path)); } - SyncPath fullPath(_vfsSetupParams._localPath / QStr2Path(path)); - std::error_code ec; - if (!std::filesystem::exists(fullPath, ec)) { - if (ec.value() != 0) { - LOGW_WARN(logger(), L"Failed to check if path exists " << Utility::formatSyncPath(fullPath).c_str() << L": " - << KDC::Utility::s2ws(ec.message()).c_str() << L" (" - << ec.value() << L")"); - return false; - } - // File doesn't exist - LOG_WARN(logger(), "File doesn't exist!"); - return false; + SyncPath fullPath(_vfsSetupParams._localPath / path.native()); + if (ExitInfo exitInfo = checkIfPathExists(fullPath, true); !exitInfo) { + return exitInfo; } // Check if the file is a placeholder @@ -331,25 +275,32 @@ bool VfsMac::dehydratePlaceholder(const QString &path) { int progress; if (!_connector->vfsGetStatus(QString::fromStdString(fullPath.native()), isPlaceholder, isHydrated, isSyncing, progress)) { LOG_WARN(logger(), "Error in vfsGetStatus!"); - return false; + return handleVfsError(fullPath); + } + + if (!isPlaceholder) { + // Not a placeholder + LOGW_WARN(logger(), L"Not a placeholder: " << Utility::formatSyncPath(fullPath).c_str()); + return {ExitCode::SystemError, ExitCause::NotPlaceHolder}; } if (isHydrated) { - LOGW_DEBUG(logger(), L"Dehydrate file with " << Utility::formatPath(path).c_str()); + LOGW_DEBUG(logger(), L"Dehydrate file with " << Utility::formatSyncPath(fullPath)); dehydrate(QString::fromStdString(fullPath.string())); } - return true; + return ExitCode::Ok; } -bool VfsMac::convertToPlaceholder(const QString &path, const SyncFileItem &item) { +ExitInfo VfsMac::convertToPlaceholder(const SyncPath &pathStd, const SyncFileItem &item) { + const QString path = SyncName2QStr(pathStd.native()); if (extendedLog()) { LOGW_DEBUG(logger(), L"convertToPlaceholder - " << Utility::formatPath(path).c_str()); } if (path.isEmpty()) { LOG_WARN(logger(), "Invalid parameters"); - return false; + return {ExitCode::SystemError, ExitCause::NotFound}; } SyncPath fullPath(QStr2Path(path)); @@ -361,14 +312,14 @@ bool VfsMac::convertToPlaceholder(const QString &path, const SyncFileItem &item) int progress; if (!_connector->vfsGetStatus(path, isPlaceholder, isHydrated, isSyncing, progress)) { LOG_WARN(logger(), "Error in vfsGetStatus!"); - return false; + return handleVfsError(fullPath); } if (!isPlaceholder) { // Convert to placeholder if (!_connector->vfsConvertToPlaceHolder(QDir::toNativeSeparators(path), !item.dehydrated())) { LOG_WARN(logger(), "Error in vfsConvertToPlaceHolder!"); - return false; + return handleVfsError(fullPath); } // If item is a directory, also convert items inside it @@ -376,19 +327,19 @@ bool VfsMac::convertToPlaceholder(const QString &path, const SyncFileItem &item) if (!IoHelper::getItemType(fullPath, itemType)) { LOGW_WARN(KDC::Log::instance()->getLogger(), L"Error in IoHelper::getItemType : " << Utility::formatSyncPath(fullPath).c_str()); - return false; + return ExitCode::SystemError; } if (itemType.ioError == IoError::NoSuchFileOrDirectory) { LOGW_DEBUG(KDC::Log::instance()->getLogger(), L"Item does not exist anymore : " << Utility::formatSyncPath(fullPath).c_str()); - return true; + return {ExitCode::SystemError, ExitCause::NotFound}; } if (itemType.ioError == IoError::AccessDenied) { LOGW_DEBUG(KDC::Log::instance()->getLogger(), L"Item misses search permission : " << Utility::formatSyncPath(fullPath).c_str()); - return true; + return {ExitCode::SystemError, ExitCause::FileAccessError}; } const bool isLink = itemType.linkType != LinkType::None; @@ -398,7 +349,7 @@ bool VfsMac::convertToPlaceholder(const QString &path, const SyncFileItem &item) if (!isDirectory && itemType.ioError != IoError::Success) { LOGW_WARN(logger(), L"Failed to check if the path is a directory: " << Utility::formatIoError(fullPath, itemType.ioError).c_str()); - return false; + return ExitCode::SystemError; } } @@ -407,7 +358,7 @@ bool VfsMac::convertToPlaceholder(const QString &path, const SyncFileItem &item) } } - return true; + return ExitCode::Ok; } void VfsMac::convertDirContentToPlaceholder(const QString &dirPath, bool isHydratedIn) { @@ -496,25 +447,24 @@ void VfsMac::resetLiteSyncConnector() { } } -bool VfsMac::updateFetchStatus(const QString &tmpPath, const QString &path, qint64 received, bool &canceled, bool &finished) { +ExitInfo VfsMac::updateFetchStatus(const SyncPath &tmpPathStd, const SyncPath &pathStd, int64_t received, bool &canceled, + bool &finished) { + QString tmpPath = SyncName2QStr(tmpPathStd.native()); + QString path = SyncName2QStr(pathStd.native()); if (extendedLog()) { LOGW_INFO(logger(), L"updateFetchStatus file " << Utility::formatPath(path).c_str() << L" - " << received); } - if (tmpPath.isEmpty() || path.isEmpty()) { + if (tmpPath.isEmpty()) { LOG_WARN(logger(), "Invalid parameters"); - return false; + return ExitCode::SystemError; } std::filesystem::path fullPath(QStr2Path(path)); - std::error_code ec; - if (!std::filesystem::exists(fullPath, ec)) { - if (ec.value() != 0) { - LOGW_WARN(logger(), L"Failed to check if path exists : " << Utility::formatSyncPath(fullPath).c_str() << L": " - << Utility::s2ws(ec.message()).c_str() << L" (" << ec.value() - << L")"); - return false; + if (ExitInfo exitInfo = checkIfPathExists(fullPath, true); !exitInfo) { + if (exitInfo == ExitInfo(ExitCode::SystemError, ExitCause::NotFound)) { + return ExitCode::Ok; } - return true; + return exitInfo; } // Check if the file is a placeholder @@ -524,37 +474,27 @@ bool VfsMac::updateFetchStatus(const QString &tmpPath, const QString &path, qint int progress = 0; if (!_connector->vfsGetStatus(Path2QStr(fullPath), isPlaceholder, isHydrated, isSyncing, progress)) { LOG_WARN(logger(), "Error in vfsGetStatus!"); - return false; + return handleVfsError(fullPath); } + finished = false; std::filesystem::path tmpFullPath(QStr2Path(tmpPath)); - auto updateFct = [=, this](bool &canceled, bool &finished, bool &error) { - // Update download progress - finished = false; - if (!_connector->vfsUpdateFetchStatus(Path2QStr(tmpFullPath), Path2QStr(fullPath), _localSyncPath, - static_cast(received), canceled, finished)) { - LOG_WARN(logger(), "Error in vfsUpdateFetchStatus!"); - error = true; - return; - } - - if (finished) { - // Do nothing - } - }; - - // Launch update in a separate thread - bool error = false; - updateFct(canceled, finished, error); + if (!_connector->vfsUpdateFetchStatus(Path2QStr(tmpFullPath), Path2QStr(fullPath), _localSyncPath, + static_cast(received), canceled, finished)) { + LOG_WARN(logger(), "Error in vfsUpdateFetchStatus!"); + return handleVfsError(fullPath); + } - return !error; + return ExitCode::Ok; } -void VfsMac::cancelHydrate(const QString &filePath) { +void VfsMac::cancelHydrate(const SyncPath &filePathStd) { + const QString filePath = SyncName2QStr(filePathStd.native()); _connector->vfsCancelHydrate(filePath); } -bool VfsMac::isDehydratedPlaceholder(const QString &initFilePath, bool isAbsolutePath /*= false*/) { +ExitInfo VfsMac::isDehydratedPlaceholder(const SyncPath &initFilePathStd, bool &isDehydrated, bool isAbsolutePath /*= false*/) { + const QString initFilePath = SyncName2QStr(initFilePathStd.native()); SyncPath filePath(isAbsolutePath ? QStr2Path(initFilePath) : _vfsSetupParams._localPath / QStr2Path(initFilePath)); bool isPlaceholder = false; @@ -563,41 +503,34 @@ bool VfsMac::isDehydratedPlaceholder(const QString &initFilePath, bool isAbsolut int progress = 0; if (!_connector->vfsGetStatus(Path2QStr(filePath), isPlaceholder, isHydrated, isSyncing, progress)) { LOG_WARN(logger(), "Error in vfsGetStatus!"); - return false; + return handleVfsError(filePath); } + isDehydrated = !isHydrated; - return !isHydrated; + return ExitCode::Ok; } -bool VfsMac::setPinState(const QString &fileRelativePath, PinState state) { +ExitInfo VfsMac::setPinState(const SyncPath &fileRelativePathStd, PinState state) { + QString fileRelativePath = SyncName2QStr(fileRelativePathStd.native()); std::filesystem::path fullPath(_vfsSetupParams._localPath / QStr2Path(fileRelativePath)); - bool exists = false; - IoError ioError = IoError::Success; - if (!IoHelper::checkIfPathExists(fullPath, exists, ioError)) { - LOGW_WARN(logger(), L"Error in IoHelper::checkIfPathExists: " << Utility::formatIoError(fullPath, ioError).c_str()); - return false; - } - - if (!exists) { - // New file - LOGW_DEBUG(logger(), L"Item does not exist : " << Utility::formatSyncPath(fullPath).c_str()); - return true; + if (ExitInfo exitInfo = checkIfPathExists(fullPath, true); !exitInfo) { + return exitInfo; } const QString strPath = Path2QStr(fullPath); if (!_connector->vfsSetPinState(strPath, _localSyncPath, (state == PinState::AlwaysLocal ? VFS_PIN_STATE_PINNED : VFS_PIN_STATE_UNPINNED))) { LOG_WARN(logger(), "Error in vfsSetPinState!"); - return false; + return handleVfsError(fullPath); } - return true; + return ExitCode::Ok; } -PinState VfsMac::pinState(const QString &relativePath) { +PinState VfsMac::pinState(const SyncPath &relativePathStd) { // Read pin state from file attributes - SyncPath fullPath(_vfsSetupParams._localPath / QStr2Path(relativePath)); + SyncPath fullPath(_vfsSetupParams._localPath / relativePathStd.native()); QString pinState; if (!_connector->vfsGetPinState(Path2QStr(fullPath), pinState)) { return PinState::Unspecified; @@ -612,17 +545,17 @@ PinState VfsMac::pinState(const QString &relativePath) { return PinState::Unspecified; } -bool VfsMac::status(const QString &filePath, bool &isPlaceholder, bool &isHydrated, bool &isSyncing, int &progress) { - SyncPath fullPath(QStr2Path(filePath)); - if (!_connector->vfsGetStatus(Path2QStr(fullPath), isPlaceholder, isHydrated, isSyncing, progress)) { +ExitInfo VfsMac::status(const SyncPath &filePathStd, bool &isPlaceholder, bool &isHydrated, bool &isSyncing, int &progress) { + if (!_connector->vfsGetStatus(Path2QStr(filePathStd), isPlaceholder, isHydrated, isSyncing, progress)) { LOG_WARN(logger(), "Error in vfsGetStatus!"); - return false; + return handleVfsError(filePathStd); } - return true; + return ExitCode::Ok; } -void VfsMac::exclude(const QString &path) { +void VfsMac::exclude(const SyncPath &pathStd) { + const QString path = SyncName2QStr(pathStd.native()); LOGW_DEBUG(logger(), L"exclude - " << Utility::formatPath(path).c_str()); bool isPlaceholder = false; @@ -657,7 +590,8 @@ void VfsMac::exclude(const QString &path) { } } -bool VfsMac::isExcluded(const QString &filePath) { +bool VfsMac::isExcluded(const SyncPath &filePathStd) { + const QString filePath = SyncName2QStr(filePathStd.native()); bool isPlaceholder; bool isHydrated; bool isSyncing; @@ -674,43 +608,44 @@ bool VfsMac::isExcluded(const QString &filePath) { return false; } -bool VfsMac::setThumbnail(const QString &absoluteFilePath, const QPixmap &pixmap) { +ExitInfo VfsMac::setThumbnail(const SyncPath &absoluteFilePathStd, const QPixmap &pixmap) { + const QString absoluteFilePath = SyncName2QStr(absoluteFilePathStd.native()); if (!_connector->vfsSetThumbnail(absoluteFilePath, pixmap)) { LOG_WARN(logger(), "Error in vfsSetThumbnail!"); - return false; + return handleVfsError(QStr2Path(absoluteFilePath)); } - return true; + return ExitCode::Ok; } -bool VfsMac::setAppExcludeList() { +ExitInfo VfsMac::setAppExcludeList() { QString appExcludeList; _exclusionAppList(appExcludeList); if (!_connector->vfsSetAppExcludeList(appExcludeList)) { LOG_WARN(logger(), "Error in vfsSetAppExcludeList!"); - return false; + return ExitCode::LogicError; } - return true; + return ExitCode::Ok; } -bool VfsMac::getFetchingAppList(QHash &appTable) { +ExitInfo VfsMac::getFetchingAppList(QHash &appTable) { if (!_connector->vfsGetFetchingAppList(appTable)) { LOG_WARN(logger(), "Error in vfsGetFetchingAppList!"); - return false; + return ExitCode::LogicError; } - return true; + return ExitCode::Ok; } -bool VfsMac::fileStatusChanged(const QString &path, SyncFileStatus status) { - LOGW_DEBUG(logger(), L"fileStatusChanged - " << Utility::formatPath(path).c_str() << L" - status = " << status); - - SyncPath fullPath(QStr2Path(path)); +bool VfsMac::fileStatusChanged(const SyncPath &pathStd, SyncFileStatus status) { + LOGW_DEBUG(logger(), L"fileStatusChanged - " << Utility::formatSyncPath(pathStd) << L" - status = " << status); + const QString path = SyncName2QStr(pathStd.native()); + SyncPath fullPath(pathStd.native()); std::error_code ec; if (!std::filesystem::exists(fullPath, ec)) { if (ec.value() != 0) { - LOGW_WARN(logger(), L"Failed to check if path exists : " << Utility::formatSyncPath(fullPath).c_str() << L": " + LOGW_WARN(logger(), L"Failed to check if path exists : " << Utility::formatSyncPath(fullPath) << L": " << Utility::s2ws(ec.message()).c_str() << L" (" << ec.value() << L")"); return false; @@ -718,9 +653,10 @@ bool VfsMac::fileStatusChanged(const QString &path, SyncFileStatus status) { // New file return true; } + SyncPath fileRelativePath = CommonUtility::relativePath(_vfsSetupParams._localPath, fullPath); if (status == SyncFileStatus::Ignored) { - exclude(QString::fromStdString(fullPath.native())); + exclude(fullPath); } else if (status == SyncFileStatus::Success) { // Do nothing } else if (status == SyncFileStatus::Syncing) { @@ -754,28 +690,31 @@ bool VfsMac::fileStatusChanged(const QString &path, SyncFileStatus status) { } if (!isLink && !isDirectory) { - QString fileRelativePath = - QStringView(path).mid(static_cast(_vfsSetupParams._localPath.string().size())).toUtf8(); auto localPinState = pinState(fileRelativePath); - bool isDehydrated = isDehydratedPlaceholder(fileRelativePath); + bool isDehydrated = false; + if (ExitInfo exitInfo = isDehydratedPlaceholder(fileRelativePath, isDehydrated); !exitInfo) { + LOGW_WARN(logger(), + L"Error in isDehydratedPlaceholder : " << Utility::formatSyncPath(fullPath) << L" " << exitInfo); + return false; + } if (localPinState == PinState::OnlineOnly && !isDehydrated) { // Add file path to dehydration queue - _workerInfo[WORKER_DEHYDRATION]._mutex.lock(); - _workerInfo[WORKER_DEHYDRATION]._queue.push_front(path); - _workerInfo[WORKER_DEHYDRATION]._mutex.unlock(); - _workerInfo[WORKER_DEHYDRATION]._queueWC.wakeOne(); + _workerInfo[workerDehydration]._mutex.lock(); + _workerInfo[workerDehydration]._queue.push_front(path); + _workerInfo[workerDehydration]._mutex.unlock(); + _workerInfo[workerDehydration]._queueWC.wakeOne(); } else if (localPinState == PinState::AlwaysLocal && isDehydrated) { bool syncing; - _syncFileSyncing(_vfsSetupParams._syncDbId, QStr2Path(fileRelativePath), syncing); + _syncFileSyncing(_vfsSetupParams._syncDbId, fileRelativePath, syncing); if (!syncing) { // Set hydrating indicator (avoid double hydration) - _setSyncFileSyncing(_vfsSetupParams._syncDbId, QStr2Path(fileRelativePath), true); + _setSyncFileSyncing(_vfsSetupParams._syncDbId, fileRelativePath, true); // Add file path to hydration queue - _workerInfo[WORKER_HYDRATION]._mutex.lock(); - _workerInfo[WORKER_HYDRATION]._queue.push_front(path); - _workerInfo[WORKER_HYDRATION]._mutex.unlock(); - _workerInfo[WORKER_HYDRATION]._queueWC.wakeOne(); + _workerInfo[workerHydration]._mutex.lock(); + _workerInfo[workerHydration]._queue.push_front(path); + _workerInfo[workerHydration]._mutex.unlock(); + _workerInfo[workerHydration]._queueWC.wakeOne(); } } } @@ -785,43 +724,4 @@ bool VfsMac::fileStatusChanged(const QString &path, SyncFileStatus status) { return true; } - -Worker::Worker(VfsMac *vfs, int type, int num, log4cplus::Logger logger) : _vfs(vfs), _type(type), _num(num), _logger(logger) {} - -void Worker::start() { - LOG_DEBUG(logger(), "Worker " << _type << " - " << _num << " started"); - - WorkerInfo &workerInfo = _vfs->_workerInfo[_type]; - - forever { - workerInfo._mutex.lock(); - while (workerInfo._queue.empty() && !workerInfo._stop) { - LOG_DEBUG(logger(), "Worker " << _type << " - " << _num << " waiting"); - workerInfo._queueWC.wait(&workerInfo._mutex); - } - - if (workerInfo._stop) { - workerInfo._mutex.unlock(); - break; - } - - QString path = workerInfo._queue.back(); - workerInfo._queue.pop_back(); - workerInfo._mutex.unlock(); - - LOG_DEBUG(logger(), "Worker " << _type << " - " << _num << " working"); - - switch (_type) { - case WORKER_HYDRATION: - _vfs->hydrate(path); - break; - case WORKER_DEHYDRATION: - _vfs->dehydrate(path); - break; - } - } - - LOG_DEBUG(logger(), "Worker " << _type << " - " << _num << " ended"); -} - } // namespace KDC diff --git a/src/server/vfs/mac/vfs_mac.h b/src/server/vfs/mac/vfs_mac.h index 9d4036319..1341e4b1b 100644 --- a/src/server/vfs/mac/vfs_mac.h +++ b/src/server/vfs/mac/vfs_mac.h @@ -31,70 +31,51 @@ #include #include -#define WORKER_HYDRATION 0 -#define WORKER_DEHYDRATION 1 -#define NB_WORKERS 2 - namespace KDC { -class Worker; - -struct WorkerInfo { - QMutex _mutex; - std::deque _queue; - QWaitCondition _queueWC; - bool _stop = false; - QList _threadList; -}; - class VfsMac : public Vfs { Q_OBJECT Q_INTERFACES(KDC::Vfs) public: - WorkerInfo _workerInfo[NB_WORKERS]; - - explicit VfsMac(KDC::VfsSetupParams &vfsSetupParams, QObject *parent = nullptr); - ~VfsMac(); + explicit VfsMac(const VfsSetupParams &vfsSetupParams, QObject *parent = nullptr); VirtualFileMode mode() const override; bool socketApiPinStateActionsShown() const override { return true; } - bool isHydrating() const override; - bool updateMetadata(const QString &absoluteFilePath, time_t creationTime, time_t modtime, qint64 size, - const QByteArray &fileId, QString *error) override; + ExitInfo updateMetadata(const SyncPath &absoluteFilePath, time_t creationTime, time_t modtime, int64_t size, + const NodeId &fileId) override; - bool createPlaceholder(const SyncPath &relativeLocalPath, const SyncFileItem &item) override; - bool dehydratePlaceholder(const QString &path) override; - bool convertToPlaceholder(const QString &path, const SyncFileItem &item) override; - bool updateFetchStatus(const QString &tmpPath, const QString &path, qint64 received, bool &canceled, + ExitInfo createPlaceholder(const SyncPath &relativeLocalPath, const SyncFileItem &item) override; + ExitInfo dehydratePlaceholder(const SyncPath &path) override; + ExitInfo convertToPlaceholder(const SyncPath &path, const SyncFileItem &item) override; + ExitInfo updateFetchStatus(const SyncPath &tmpPath, const SyncPath &path, int64_t received, bool &canceled, bool &finished) override; - void cancelHydrate(const QString &filePath) override; - bool forceStatus(const QString &path, bool isSyncing, int progress, bool isHydrated = false) override; + void cancelHydrate(const SyncPath &filePath) override; + ExitInfo forceStatus(const SyncPath &path, bool isSyncing, int progress, bool isHydrated = false) override; bool cleanUpStatuses() override; - virtual void clearFileAttributes(const QString &path) override; + virtual void clearFileAttributes(const SyncPath &path) override; - bool needsMetadataUpdate(const SyncFileItem &) override { return false; } - bool isDehydratedPlaceholder(const QString &filePath, bool isAbsolutePath = false) override; + ExitInfo isDehydratedPlaceholder(const SyncPath &filePath, bool &isDehydrated, bool isAbsolutePath = false) override; - bool setPinState(const QString &fileRelativePath, PinState state) override; - PinState pinState(const QString &relativePath) override; - bool status(const QString &filePath, bool &isPlaceholder, bool &isHydrated, bool &isSyncing, int &progress) override; - virtual void exclude(const QString &path) override; - virtual bool isExcluded(const QString &filePath) override; - virtual bool setThumbnail(const QString &absoluteFilePath, const QPixmap &pixmap) override; - virtual bool setAppExcludeList() override; - virtual bool getFetchingAppList(QHash &appTable) override; - virtual bool fileStatusChanged(const QString &path, SyncFileStatus status) override; + ExitInfo setPinState(const SyncPath &fileRelativePath, PinState state) override; + PinState pinState(const SyncPath &relativePath) override; + ExitInfo status(const SyncPath &filePath, bool &isPlaceholder, bool &isHydrated, bool &isSyncing, int &progress) override; + void exclude(const SyncPath &path) override; + bool isExcluded(const SyncPath &filePath) override; + ExitInfo setThumbnail(const SyncPath &absoluteFilePath, const QPixmap &pixmap) override; + ExitInfo setAppExcludeList() override; + ExitInfo getFetchingAppList(QHash &appTable) override; + bool fileStatusChanged(const SyncPath &path, SyncFileStatus status) override; - void dehydrate(const QString &path); - void hydrate(const QString &path); + void dehydrate(const QString &path) final; + void hydrate(const QString &path) final; virtual void convertDirContentToPlaceholder(const QString &filePath, bool isHydratedIn) override; protected: - bool startImpl(bool &installationDone, bool &activationDone, bool &connectionDone) override; + ExitInfo startImpl(bool &installationDone, bool &activationDone, bool &connectionDone) override; void stopImpl(bool unregister) override; friend class TestWorkers; @@ -106,22 +87,6 @@ class VfsMac : public Vfs { const QString _localSyncPath; }; -class Worker : public QObject { - Q_OBJECT - - public: - Worker(VfsMac *vfs, int type, int num, log4cplus::Logger logger); - void start(); - - private: - VfsMac *_vfs; - int _type; - int _num; - log4cplus::Logger _logger; - - inline log4cplus::Logger logger() { return _logger; } -}; - class MacVfsPluginFactory : public QObject, public DefaultPluginFactory { Q_OBJECT Q_PLUGIN_METADATA(IID "org.kdrive.PluginFactory" FILE "../vfspluginmetadata.json") diff --git a/src/server/vfs/win/CMakeLists.txt b/src/server/vfs/win/CMakeLists.txt index c268b189f..4eb455017 100644 --- a/src/server/vfs/win/CMakeLists.txt +++ b/src/server/vfs/win/CMakeLists.txt @@ -2,8 +2,6 @@ find_package(Qt6) set(libsyncengine_vfs_win_SRCS vfs_win.h vfs_win.cpp - ../../../libcommonserver/vfs.h ../../../libcommonserver/vfs.cpp - ../../../libcommonserver/plugin.h ../../../libcommonserver/plugin.cpp ../../../common/filepermissionholder.h ../../../common/filepermissionholder.cpp ../../../common/filesystembase.h ../../../common/filesystembase.cpp ) diff --git a/src/server/vfs/win/vfs_win.cpp b/src/server/vfs/win/vfs_win.cpp index 259aada4b..92a36ea05 100644 --- a/src/server/vfs/win/vfs_win.cpp +++ b/src/server/vfs/win/vfs_win.cpp @@ -37,12 +37,7 @@ #include namespace KDC { - -const int s_nb_threads[NB_WORKERS] = {5, 5}; - -std::unordered_map s_fetchMap; - -VfsWin::VfsWin(VfsSetupParams &vfsSetupParams, QObject *parent) : Vfs(vfsSetupParams, parent) { +VfsWin::VfsWin(const VfsSetupParams &vfsSetupParams, QObject *parent) : Vfs(vfsSetupParams, parent) { // Initialize LiteSync ext connector LOG_INFO(logger(), "Initialize LiteSyncExtConnector"); @@ -59,46 +54,7 @@ VfsWin::VfsWin(VfsSetupParams &vfsSetupParams, QObject *parent) : Vfs(vfsSetupPa return; } - // Start hydration/dehydration workers - // !!! Disabled for testing because no QEventLoop !!! - if (qApp) { - // Start worker threads - for (int i = 0; i < NB_WORKERS; i++) { - for (int j = 0; j < s_nb_threads[i]; j++) { - QThread *workerThread = new QThread(); - _workerInfo[i]._threadList.append(workerThread); - Worker *worker = new Worker(this, i, j, logger()); - worker->moveToThread(workerThread); - connect(workerThread, &QThread::started, worker, &Worker::start); - connect(workerThread, &QThread::finished, worker, &QObject::deleteLater); - connect(workerThread, &QThread::finished, workerThread, &QObject::deleteLater); - workerThread->start(); - } - } - } -} - -VfsWin::~VfsWin() { - // Ask worker threads to stop - for (int i = 0; i < NB_WORKERS; i++) { - _workerInfo[i]._mutex.lock(); - _workerInfo[i]._stop = true; - _workerInfo[i]._mutex.unlock(); - _workerInfo[i]._queueWC.wakeAll(); - } - - // Force threads to stop if needed - for (int i = 0; i < NB_WORKERS; i++) { - for (QThread *thread: qAsConst(_workerInfo[i]._threadList)) { - if (thread) { - thread->quit(); - if (!thread->wait(1000)) { - thread->terminate(); - thread->wait(); - } - } - } - } + starVfsWorkers(); } void VfsWin::debugCbk(TraceLevel level, const wchar_t *msg) { @@ -122,7 +78,7 @@ VirtualFileMode VfsWin::mode() const { return VirtualFileMode::Win; } -bool VfsWin::startImpl(bool &, bool &, bool &) { +ExitInfo VfsWin::startImpl(bool &, bool &, bool &) { LOG_DEBUG(logger(), "startImpl: syncDbId=" << _vfsSetupParams._syncDbId); wchar_t clsid[39] = L""; @@ -131,12 +87,12 @@ bool VfsWin::startImpl(bool &, bool &, bool &) { std::to_wstring(_vfsSetupParams._syncDbId).c_str(), _vfsSetupParams._localPath.filename().native().c_str(), _vfsSetupParams._localPath.lexically_normal().native().c_str(), clsid, &clsidSize) != S_OK) { LOG_WARN(logger(), "Error in vfsStart: syncDbId=" << _vfsSetupParams._syncDbId); - return false; + return {ExitCode::SystemError, ExitCause::UnableToCreateVfs}; } _vfsSetupParams._namespaceCLSID = Utility::ws2s(std::wstring(clsid)); - return true; + return ExitCode::Ok; } void VfsWin::stopImpl(bool unregister) { @@ -175,9 +131,9 @@ void VfsWin::hydrate(const QString &path) { _setSyncFileSyncing(_vfsSetupParams._syncDbId, QStr2Path(relativePath), false); } -void VfsWin::cancelHydrate(const QString &path) { - LOGW_DEBUG(logger(), L"cancelHydrate: " << Utility::formatSyncPath(QStr2Path(path)).c_str()); - +void VfsWin::cancelHydrate(const SyncPath &pathStd) { + LOGW_DEBUG(logger(), L"cancelHydrate: " << Utility::formatSyncPath(pathStd)); + const QString path = SyncName2QStr(pathStd.native()); if (vfsCancelFetch(std::to_wstring(_vfsSetupParams._driveId).c_str(), std::to_wstring(_vfsSetupParams._syncDbId).c_str(), QStr2Path(QDir::toNativeSeparators(path)).c_str()) != S_OK) { LOGW_WARN(logger(), L"Error in vfsCancelFetch: " << Utility::formatSyncPath(QStr2Path(path)).c_str()); @@ -188,7 +144,8 @@ void VfsWin::cancelHydrate(const QString &path) { _setSyncFileSyncing(_vfsSetupParams._syncDbId, QStr2Path(relativePath), false); } -void VfsWin::exclude(const QString &path) { +void VfsWin::exclude(const SyncPath &pathStd) { + const QString path = SyncName2QStr(pathStd.native()); LOGW_DEBUG(logger(), L"exclude: " << Utility::formatSyncPath(QStr2Path(path)).c_str()); DWORD dwAttrs = GetFileAttributesW(QStr2Path(QDir::toNativeSeparators(path)).c_str()); @@ -205,33 +162,23 @@ void VfsWin::exclude(const QString &path) { } } -void VfsWin::setPlaceholderStatus(const QString &path, bool syncOngoing) { - if (vfsSetPlaceHolderStatus(QStr2Path(QDir::toNativeSeparators(path)).c_str(), syncOngoing) != S_OK) { - LOGW_WARN(logger(), L"Error in vfsSetPlaceHolderStatus: " << Utility::formatSyncPath(QStr2Path(path)).c_str()); - return; +ExitInfo VfsWin::setPlaceholderStatus(const QString &path, bool syncOngoing) { + auto stdPath = QStr2Path(QDir::toNativeSeparators(path)); + if (vfsSetPlaceHolderStatus(stdPath.c_str(), syncOngoing) != S_OK) { + LOGW_WARN(logger(), L"Error in vfsSetPlaceHolderStatus: " << Utility::formatSyncPath(stdPath)); + return handleVfsError(stdPath); } + return ExitCode::Ok; } -bool VfsWin::isHydrating() const { - return false; -} - -bool VfsWin::updateMetadata(const QString &filePath, time_t creationTime, time_t modtime, qint64 size, const QByteArray &, - QString *) { +ExitInfo VfsWin::updateMetadata(const SyncPath &filePathStd, time_t creationTime, time_t modtime, int64_t size, const NodeId &) { + const QString filePath = SyncName2QStr(filePathStd.native()); LOGW_DEBUG(logger(), L"updateMetadata: " << Utility::formatSyncPath(QStr2Path(filePath)).c_str() << L" creationTime=" << creationTime << L" modtime=" << modtime); SyncPath fullPath(_vfsSetupParams._localPath / QStr2Path(filePath)); - bool exists = false; - IoError ioError = IoError::Success; - if (!IoHelper::checkIfPathExists(fullPath, exists, ioError)) { - LOGW_WARN(logger(), L"Error in IoHelper::checkIfPathExists: " << Utility::formatIoError(fullPath, ioError).c_str()); - return false; - } - - if (!exists) { - LOGW_WARN(logger(), L"File/directory doesn't exists: " << Utility::formatSyncPath(fullPath).c_str()); - return false; + if (ExitInfo exitInfo = checkIfPathExists(fullPath, true); !exitInfo) { + return exitInfo; } // Update placeholder @@ -244,36 +191,32 @@ bool VfsWin::updateMetadata(const QString &filePath, time_t creationTime, time_t findData.dwFileAttributes = GetFileAttributesW(QStr2Path(filePath).c_str()); if (vfsUpdatePlaceHolder(QStr2Path(QDir::toNativeSeparators(filePath)).c_str(), &findData) != S_OK) { - LOGW_WARN(logger(), L"Error in vfsUpdatePlaceHolder: " << Utility::formatSyncPath(fullPath).c_str()); + LOGW_WARN(logger(), L"Error in vfsUpdatePlaceHolder: " << Utility::formatSyncPath(fullPath)); + return handleVfsError(fullPath); } - return true; + return ExitCode::Ok; } -bool VfsWin::createPlaceholder(const SyncPath &relativeLocalPath, const SyncFileItem &item) { - LOGW_DEBUG(logger(), L"createPlaceholder: " << Utility::formatSyncPath(relativeLocalPath).c_str()); +ExitInfo VfsWin::createPlaceholder(const SyncPath &relativeLocalPath, const SyncFileItem &item) { + LOGW_DEBUG(logger(), L"createPlaceholder: " << Utility::formatSyncPath(relativeLocalPath)); if (relativeLocalPath.empty()) { - LOG_WARN(logger(), "Empty file!"); - return false; + LOG_WARN(logger(), "VfsWin::createPlaceholder - relativeLocalPath cannot be empty."); + return {ExitCode::SystemError, ExitCause::InvalidArgument}; } if (!item.remoteNodeId().has_value()) { - LOGW_WARN(logger(), L"Empty remote nodeId: " << Utility::formatSyncPath(relativeLocalPath).c_str()); - return false; + LOGW_WARN(logger(), L"VfsWin::createPlaceholder - Item has no remote ID: " << Utility::formatSyncPath(relativeLocalPath)); + return {ExitCode::SystemError, ExitCause::InvalidArgument}; } SyncPath fullPath(_vfsSetupParams._localPath / relativeLocalPath); - bool exists = false; - IoError ioError = IoError::Success; - if (!IoHelper::checkIfPathExists(fullPath, exists, ioError)) { - LOGW_WARN(logger(), L"Error in IoHelper::checkIfPathExists: " << Utility::formatIoError(fullPath, ioError).c_str()); - return false; + if (ExitInfo exitInfo = checkIfPathExists(fullPath, false); !exitInfo) { + return exitInfo; } - - if (exists) { - LOGW_WARN(logger(), L"Item already exists: " << Utility::formatSyncPath(fullPath).c_str()); - return false; + if (ExitInfo exitInfo = checkIfPathExists(fullPath.parent_path(), true); !exitInfo) { + return exitInfo; } // Create placeholder @@ -289,51 +232,40 @@ bool VfsWin::createPlaceholder(const SyncPath &relativeLocalPath, const SyncFile relativeLocalPath.lexically_normal().native().c_str(), _vfsSetupParams._localPath.lexically_normal().native().c_str(), &findData) != S_OK) { LOGW_WARN(logger(), L"Error in vfsCreatePlaceHolder: " << Utility::formatSyncPath(fullPath).c_str()); + return defaultVfsError(); // handleVfsError is not suitable here, the file dosen't exist but we don't want to return + // NotFound as this make no sense in the context of a create } // !!! Creating a placeholder DOESN'T triggers any file system event !!! // Setting the pin state triggers an EDIT event and then the insertion into the local snapshot if (vfsSetPinState(fullPath.lexically_normal().native().c_str(), VFS_PIN_STATE_UNPINNED) != S_OK) { LOGW_WARN(logger(), L"Error in vfsSetPinState: " << Utility::formatSyncPath(fullPath).c_str()); - return false; + return defaultVfsError(); // handleVfsError is not suitable here, the file dosen't exist but we don't want to return + // NotFound as this make no sense in the context of a create } - return true; + return ExitCode::Ok; } -bool VfsWin::dehydratePlaceholder(const QString &path) { - LOGW_DEBUG(logger(), L"dehydratePlaceholder: " << Utility::formatSyncPath(QStr2Path(path)).c_str()); +ExitInfo VfsWin::dehydratePlaceholder(const SyncPath &path) { + LOGW_DEBUG(logger(), L"dehydratePlaceholder: " << Utility::formatSyncPath(path)); + SyncPath fullPath(_vfsSetupParams._localPath / path); - if (path.isEmpty()) { - LOG_WARN(logger(), "Empty file!"); - return false; - } - - SyncPath fullPath(_vfsSetupParams._localPath / QStr2Path(path)); - bool exists = false; - IoError ioError = IoError::Success; - if (!IoHelper::checkIfPathExists(fullPath, exists, ioError)) { - LOGW_WARN(logger(), L"Error in IoHelper::checkIfPathExists: " << Utility::formatIoError(fullPath, ioError).c_str()); - return false; - } - - if (!exists) { - // File doesn't exist - LOGW_WARN(logger(), L"File doesn't exist: " << Utility::formatSyncPath(fullPath).c_str()); - return false; + if (ExitInfo exitInfo = checkIfPathExists(fullPath, true); !exitInfo) { + return exitInfo; } // Check if the file is a placeholder bool isPlaceholder; if (vfsGetPlaceHolderStatus(fullPath.lexically_normal().native().c_str(), &isPlaceholder, nullptr, nullptr) != S_OK) { LOGW_WARN(logger(), L"Error in vfsGetPlaceHolderStatus: " << Utility::formatSyncPath(fullPath).c_str()); - return false; + return handleVfsError(fullPath); } if (!isPlaceholder) { // Not a placeholder LOGW_WARN(logger(), L"Not a placeholder: " << Utility::formatSyncPath(fullPath).c_str()); - return false; + return {ExitCode::SystemError, ExitCause::NotPlaceHolder}; } LOGW_DEBUG(logger(), L"Dehydrate file: " << Utility::formatSyncPath(fullPath).c_str()); @@ -341,15 +273,16 @@ bool VfsWin::dehydratePlaceholder(const QString &path) { std::thread dehydrateTask(dehydrateFct); dehydrateTask.detach(); - return true; + return ExitCode::Ok; } -bool VfsWin::convertToPlaceholder(const QString &path, const SyncFileItem &item) { +ExitInfo VfsWin::convertToPlaceholder(const SyncPath &pathStd, const SyncFileItem &item) { + const QString path = SyncName2QStr(pathStd.native()); LOGW_DEBUG(logger(), L"convertToPlaceholder: " << Utility::formatSyncPath(QStr2Path(path)).c_str()); if (path.isEmpty()) { - LOG_WARN(logger(), "Invalid parameters"); - return false; + LOG_WARN(logger(), "Empty path!"); + return {ExitCode::SystemError, ExitCause::NotFound}; } SyncPath fullPath(QStr2Path(path)); @@ -358,36 +291,32 @@ bool VfsWin::convertToPlaceholder(const QString &path, const SyncFileItem &item) DWORD errorCode = GetLastError(); LOGW_WARN(logger(), L"Error in GetFileAttributesW: " << Utility::formatSyncPath(fullPath).c_str() << L" code=" << errorCode); - return false; + return handleVfsError(fullPath); } if (dwAttrs & FILE_ATTRIBUTE_DEVICE) { LOGW_DEBUG(logger(), L"Not a valid file or directory: " << Utility::formatSyncPath(fullPath).c_str()); - return false; + return handleVfsError(fullPath); } // Check if the file is already a placeholder bool isPlaceholder; if (vfsGetPlaceHolderStatus(fullPath.lexically_normal().native().c_str(), &isPlaceholder, nullptr, nullptr) != S_OK) { LOGW_WARN(logger(), L"Error in vfsGetPlaceHolderStatus: " << Utility::formatSyncPath(fullPath).c_str()); - return false; + return handleVfsError(fullPath); } if (!item.localNodeId().has_value()) { LOGW_WARN(logger(), L"Item has no local ID: " << Utility::formatSyncPath(fullPath).c_str()); - return false; + return {ExitCode::LogicError, ExitCause::InvalidArgument}; } - if (!isPlaceholder) { - // Convert to placeholder - if (vfsConvertToPlaceHolder(Utility::s2ws(item.localNodeId().value()).c_str(), - fullPath.lexically_normal().native().c_str()) != S_OK) { - LOGW_WARN(logger(), L"Error in vfsConvertToPlaceHolder: " << Utility::formatSyncPath(fullPath).c_str()); - return false; - } + if (!isPlaceholder && (vfsConvertToPlaceHolder(Utility::s2ws(item.localNodeId().value()).c_str(), + fullPath.lexically_normal().native().c_str()) != S_OK)) { + LOGW_WARN(logger(), L"Error in vfsConvertToPlaceHolder: " << Utility::formatSyncPath(fullPath).c_str()); + return handleVfsError(fullPath); } - - return true; + return ExitCode::Ok; } void VfsWin::convertDirContentToPlaceholder(const QString &filePath, bool isHydratedIn) { @@ -400,17 +329,13 @@ void VfsWin::convertDirContentToPlaceholder(const QString &filePath, bool isHydr } SyncPath fullPath(QStr2Path(tmpPath)); - bool exists = false; - IoError ioError = IoError::Success; - if (!IoHelper::checkIfPathExists(fullPath, exists, ioError)) { - LOGW_WARN(logger(), L"Error in IoHelper::checkIfPathExists: " << Utility::formatIoError(fullPath, ioError).c_str()); - return; - } - if (!exists) { - // File creation and rename - LOGW_DEBUG(logger(), L"File doesn't exist: " << Utility::formatSyncPath(fullPath).c_str()); - continue; + if (ExitInfo exitInfo = checkIfPathExists(fullPath, true); !exitInfo) { + if (exitInfo == ExitInfo(ExitCode::SystemError, ExitCause::NotFound)) { + continue; + } + LOGW_WARN(logger(), L"Error in checkIfPathExists: " << Utility::formatSyncPath(fullPath)); + return; } // Check if the file is already a placeholder @@ -451,95 +376,73 @@ void VfsWin::convertDirContentToPlaceholder(const QString &filePath, bool isHydr } } -void VfsWin::clearFileAttributes(const QString &path) { - std::filesystem::path fullPath(QStr2Path(path)); +void VfsWin::clearFileAttributes(const SyncPath &fullPath) { if (vfsRevertPlaceHolder(fullPath.lexically_normal().native().c_str()) != S_OK) { LOGW_WARN(logger(), L"Error in vfsRevertPlaceHolder: " << Utility::formatSyncPath(fullPath).c_str()); } } -bool VfsWin::updateFetchStatus(const QString &tmpPath, const QString &path, qint64 received, bool &canceled, bool &finished) { +ExitInfo VfsWin::updateFetchStatus(const SyncPath &tmpPathStd, const SyncPath &pathStd, int64_t received, bool &canceled, + bool &finished) { Q_UNUSED(finished) + const QString tmpPath = SyncName2QStr(tmpPathStd.native()); + const QString path = SyncName2QStr(pathStd.native()); LOGW_DEBUG(logger(), L"updateFetchStatus: " << Utility::formatSyncPath(QStr2Path(path)).c_str()); - if (tmpPath.isEmpty() || path.isEmpty()) { + if (tmpPath.isEmpty()) { LOG_WARN(logger(), "Invalid parameters"); - return false; + return ExitCode::SystemError; } SyncPath fullTmpPath(QStr2Path(tmpPath)); SyncPath fullPath(QStr2Path(path)); - bool exists = false; - IoError ioError = IoError::Success; - if (!IoHelper::checkIfPathExists(fullPath, exists, ioError)) { - LOGW_WARN(logger(), L"Error in IoHelper::checkIfPathExists: " << Utility::formatIoError(fullPath, ioError).c_str()); - return false; - } - - if (!exists) { - return true; + if (ExitInfo exitInfo = checkIfPathExists(fullPath, true); !exitInfo) { + if (exitInfo == ExitInfo(ExitCode::SystemError, ExitCause::NotFound)) { + return ExitCode::Ok; + } } // Check if the file is a placeholder bool isPlaceholder; if (vfsGetPlaceHolderStatus(fullPath.lexically_normal().native().c_str(), &isPlaceholder, nullptr, nullptr) != S_OK) { LOGW_WARN(logger(), L"Error in vfsGetPlaceHolderStatus: " << Utility::formatSyncPath(fullPath).c_str()); - return false; + return handleVfsError(fullPath); } - auto updateFct = [=](bool &canceled, bool &finished, bool &error) { - // Update download progress - if (vfsUpdateFetchStatus(std::to_wstring(_vfsSetupParams._driveId).c_str(), - std::to_wstring(_vfsSetupParams._syncDbId).c_str(), fullPath.lexically_normal().native().c_str(), - fullTmpPath.lexically_normal().native().c_str(), received, &canceled, &finished) != S_OK) { - LOGW_WARN(logger(), L"Error in vfsUpdateFetchStatus: " << Utility::formatSyncPath(fullPath).c_str()); - error = true; - return; - } - }; - - // Launch update in a separate thread - bool error = false; - std::thread updateTask(updateFct, std::ref(canceled), std::ref(finished), std::ref(error)); - updateTask.join(); - - return !error; -} - -bool VfsWin::forceStatus(const QString &absolutePath, bool isSyncing, int, bool) { - SyncPath stdPath = QStr2Path(absolutePath); - - bool exists = false; - IoError ioError = IoError::Success; - if (!IoHelper::checkIfPathExists(stdPath, exists, ioError)) { - LOGW_WARN(logger(), L"Error in IoHelper::checkIfPathExists: " << Utility::formatIoError(stdPath, ioError).c_str()); - return false; + if (vfsUpdateFetchStatus(std::to_wstring(_vfsSetupParams._driveId).c_str(), + std::to_wstring(_vfsSetupParams._syncDbId).c_str(), fullPath.lexically_normal().native().c_str(), + fullTmpPath.lexically_normal().native().c_str(), received, &canceled, &finished) != S_OK) { + LOGW_WARN(logger(), L"Error in vfsUpdateFetchStatus: " << Utility::formatSyncPath(fullPath).c_str()); + return handleVfsError(fullPath); } + return ExitCode::Ok; +} - if (!exists) { - // New file - return true; +ExitInfo VfsWin::forceStatus(const SyncPath &absolutePathStd, bool isSyncing, int, bool) { + QString absolutePath = SyncName2QStr(absolutePathStd.native()); + if (ExitInfo exitInfo = checkIfPathExists(absolutePathStd, true); !exitInfo) { + return exitInfo; } - DWORD dwAttrs = GetFileAttributesW(stdPath.native().c_str()); + DWORD dwAttrs = GetFileAttributesW(absolutePathStd.native().c_str()); if (dwAttrs == INVALID_FILE_ATTRIBUTES) { DWORD errorCode = GetLastError(); LOGW_WARN(logger(), - L"Error in GetFileAttributesW: " << Utility::formatSyncPath(stdPath).c_str() << L" code=" << errorCode); - return false; + L"Error in GetFileAttributesW: " << Utility::formatSyncPath(absolutePathStd).c_str() << L" code=" << errorCode); + return handleVfsError(absolutePathStd); } if (dwAttrs & FILE_ATTRIBUTE_DEVICE) { - LOGW_WARN(logger(), L"Not a valid file or directory: " << Utility::formatSyncPath(stdPath).c_str()); - return false; + LOGW_WARN(logger(), L"Not a valid file or directory: " << Utility::formatSyncPath(absolutePathStd).c_str()); + return handleVfsError(absolutePathStd); } bool isPlaceholder = false; - if (vfsGetPlaceHolderStatus(stdPath.native().c_str(), &isPlaceholder, nullptr, nullptr) != S_OK) { - LOGW_WARN(logger(), L"Error in vfsGetPlaceHolderStatus: " << Utility::formatSyncPath(stdPath).c_str()); - return false; + if (vfsGetPlaceHolderStatus(absolutePathStd.native().c_str(), &isPlaceholder, nullptr, nullptr) != S_OK) { + LOGW_WARN(logger(), L"Error in vfsGetPlaceHolderStatus: " << Utility::formatSyncPath(absolutePathStd).c_str()); + return handleVfsError(absolutePathStd); } // Some editors (notepad++) seems to remove the file attributes, therfore we need to verify that the file is still a @@ -547,56 +450,59 @@ bool VfsWin::forceStatus(const QString &absolutePath, bool isSyncing, int, bool) if (!isPlaceholder) { FileStat filestat; IoError ioError = IoError::Success; - if (!IoHelper::getFileStat(stdPath, &filestat, ioError)) { - LOGW_WARN(logger(), L"Error in IoHelper::getFileStat: " << Utility::formatIoError(stdPath, ioError).c_str()); - return false; + if (!IoHelper::getFileStat(absolutePathStd, &filestat, ioError)) { + LOGW_WARN(logger(), L"Error in IoHelper::getFileStat: " << Utility::formatIoError(absolutePathStd, ioError).c_str()); + return ExitCode::SystemError; } - if (ioError == IoError::NoSuchFileOrDirectory) { - LOGW_DEBUG(logger(), L"Item does not exist anymore: " << Utility::formatSyncPath(stdPath).c_str()); - return true; + LOGW_DEBUG(logger(), L"Item does not exist anymore: " << Utility::formatSyncPath(absolutePathStd).c_str()); + return {ExitCode::SystemError, ExitCause::NotFound}; } else if (ioError == IoError::AccessDenied) { - LOGW_WARN(logger(), L"Item: " << Utility::formatSyncPath(stdPath).c_str() << L" rejected because access is denied"); - return true; + LOGW_WARN(logger(), L"Access is denied for item: " << Utility::formatSyncPath(absolutePathStd)); + return {ExitCode::SystemError, ExitCause::FileAccessError}; } NodeId localNodeId = std::to_string(filestat.inode); // Convert to placeholder - if (vfsConvertToPlaceHolder(Utility::s2ws(localNodeId).c_str(), stdPath.native().c_str()) != S_OK) { - LOGW_WARN(logger(), L"Error in vfsConvertToPlaceHolder: " << Utility::formatSyncPath(stdPath).c_str()); - return false; + if (vfsConvertToPlaceHolder(Utility::s2ws(localNodeId).c_str(), absolutePathStd.native().c_str()) != S_OK) { + LOGW_WARN(logger(), L"Error in vfsConvertToPlaceHolder: " << Utility::formatSyncPath(absolutePathStd).c_str()); + return handleVfsError(absolutePathStd); } } // Set status - LOGW_DEBUG(logger(), L"Setting syncing status to: " << isSyncing << L" for file: " - << Utility::formatSyncPath(QStr2Path(absolutePath)).c_str()); - setPlaceholderStatus(absolutePath, isSyncing); + LOGW_DEBUG(logger(), + L"Setting syncing status to: " << isSyncing << L" for file: " << Utility::formatSyncPath(absolutePathStd)); + if (ExitInfo exitInfo = setPlaceholderStatus(absolutePath, isSyncing); !exitInfo) { + LOGW_WARN(logger(), L"Error in setPlaceholderStatus: " << Utility::formatSyncPath(absolutePathStd) << L" " << exitInfo); + return exitInfo; + } - return true; + return ExitCode::Ok; } -bool VfsWin::isDehydratedPlaceholder(const QString &initFilePath, bool isAbsolutePath /*= false*/) { - bool isDehydrated; +ExitInfo VfsWin::isDehydratedPlaceholder(const SyncPath &initFilePathStd, bool &isDehydrated, bool isAbsolutePath /*= false*/) { + QString initFilePath = SyncName2QStr(initFilePathStd.native()); SyncPath filePath(isAbsolutePath ? QStr2Path(initFilePath) : _vfsSetupParams._localPath / QStr2Path(initFilePath)); if (vfsGetPlaceHolderStatus(filePath.lexically_normal().native().c_str(), nullptr, &isDehydrated, nullptr) != S_OK) { LOGW_WARN(logger(), L"Error in vfsGetPlaceHolderStatus: " << Utility::formatSyncPath(filePath).c_str()); - return false; + return handleVfsError(filePath); } - return isDehydrated; + return ExitCode::Ok; } -bool VfsWin::setPinState(const QString &relativePath, PinState state) { +ExitInfo VfsWin::setPinState(const SyncPath &relativePathStd, PinState state) { + QString relativePath = SyncName2QStr(relativePathStd.native()); SyncPath fullPath(_vfsSetupParams._localPath / QStr2Path(relativePath)); DWORD dwAttrs = GetFileAttributesW(fullPath.lexically_normal().native().c_str()); if (dwAttrs == INVALID_FILE_ATTRIBUTES) { DWORD errorCode = GetLastError(); LOGW_WARN(logger(), L"Error in GetFileAttributesW: " << Utility::formatSyncPath(fullPath).c_str() << L" code=" << errorCode); - return false; + return handleVfsError(fullPath); } VfsPinState vfsState; @@ -617,17 +523,17 @@ bool VfsWin::setPinState(const QString &relativePath, PinState state) { if (vfsSetPinState(fullPath.lexically_normal().native().c_str(), vfsState) != S_OK) { LOGW_WARN(logger(), L"Error in vfsSetPinState: " << Utility::formatSyncPath(fullPath).c_str()); - return false; + return handleVfsError(fullPath); } - return true; + return ExitCode::Ok; } -PinState VfsWin::pinState(const QString &relativePath) { +PinState VfsWin::pinState(const SyncPath &relativePathStd) { // TODO: Use vfsGetPinState instead of reading attributes (GetFileAttributesW). In this case return unspecified in case of // VFS_PIN_STATE_INHERIT. // Read pin state from file attributes - SyncPath fullPath(_vfsSetupParams._localPath / QStr2Path(relativePath)); + SyncPath fullPath(_vfsSetupParams._localPath / relativePathStd.native()); DWORD dwAttrs = GetFileAttributesW(fullPath.lexically_normal().native().c_str()); if (dwAttrs == INVALID_FILE_ATTRIBUTES) { @@ -643,131 +549,105 @@ PinState VfsWin::pinState(const QString &relativePath) { return PinState::Unspecified; } -bool VfsWin::status(const QString &filePath, bool &isPlaceholder, bool &isHydrated, bool &isSyncing, int &) { +ExitInfo VfsWin::status(const SyncPath &filePath, bool &isPlaceholder, bool &isHydrated, bool &isSyncing, int &) { // Check if the file is a placeholder - SyncPath fullPath(QStr2Path(filePath)); bool isDehydrated = false; - if (vfsGetPlaceHolderStatus(fullPath.lexically_normal().native().c_str(), &isPlaceholder, &isDehydrated, nullptr) != S_OK) { - LOGW_WARN(logger(), L"Error in vfsGetPlaceHolderStatus: " << Utility::formatSyncPath(fullPath).c_str()); - return false; + if (vfsGetPlaceHolderStatus(filePath.lexically_normal().native().c_str(), &isPlaceholder, &isDehydrated, nullptr) != S_OK) { + LOGW_WARN(logger(), L"Error in vfsGetPlaceHolderStatus: " << Utility::formatSyncPath(filePath).c_str()); + return handleVfsError(filePath); } isHydrated = !isDehydrated; isSyncing = false; - return true; + return ExitCode::Ok; } -bool VfsWin::fileStatusChanged(const QString &path, SyncFileStatus status) { - LOGW_DEBUG(logger(), L"fileStatusChanged: " << Utility::formatSyncPath(QStr2Path(path)).c_str() << L" status = " << status); - - SyncPath fullPath(QStr2Path(path)); - bool exists = false; - IoError ioError = IoError::Success; - if (!IoHelper::checkIfPathExists(fullPath, exists, ioError)) { - LOGW_WARN(logger(), L"Error in IoHelper::checkIfPathExists: " << Utility::formatIoError(fullPath, ioError).c_str()); +bool VfsWin::fileStatusChanged(const SyncPath &pathStd, SyncFileStatus status) { + LOGW_DEBUG(logger(), L"fileStatusChanged: " << Utility::formatSyncPath(pathStd) << L" status = " << status); + const QString path = SyncName2QStr(pathStd.native()); + SyncPath fullPath(pathStd.native()); + if (ExitInfo exitInfo = checkIfPathExists(fullPath, true); !exitInfo) { + if (exitInfo == ExitInfo(ExitCode::SystemError, ExitCause::NotFound)) { + return true; + } return false; } + SyncPath fileRelativePath = CommonUtility::relativePath(_vfsSetupParams._localPath, fullPath); - if (!exists) { - // New file - return true; - } + switch (status) { + case SyncFileStatus::Conflict: + case SyncFileStatus::Ignored: + exclude(fullPath); + break; + case SyncFileStatus::Success: { + bool isDirectory = false; - if (status == SyncFileStatus::Conflict || status == SyncFileStatus::Ignored) { - exclude(path); - } else if (status == SyncFileStatus::Success) { - bool isDirectory = false; - IoError ioError = IoError::Success; - if (!IoHelper::checkIfIsDirectory(fullPath, isDirectory, ioError)) { - LOGW_WARN(logger(), L"Failed to check if path is a directory: " << Utility::formatIoError(fullPath, ioError).c_str()); - return false; - } + if (IoError ioError = IoError::Success; !IoHelper::checkIfIsDirectory(fullPath, isDirectory, ioError)) { + LOGW_WARN(logger(), + L"Failed to check if path is a directory: " << Utility::formatIoError(fullPath, ioError).c_str()); + return false; + } - if (!isDirectory) { - // File - QString fileRelativePath = QStringView{path}.mid(_vfsSetupParams._localPath.native().size() + 1).toUtf8(); - bool isDehydrated = isDehydratedPlaceholder(fileRelativePath); - forceStatus(path, false, 100, !isDehydrated); - } - } else if (status == SyncFileStatus::Syncing) { - bool isDirectory = false; - IoError ioError = IoError::Success; - if (!IoHelper::checkIfIsDirectory(fullPath, isDirectory, ioError)) { - LOGW_WARN(logger(), L"Failed to check if path is a directory: " << Utility::formatIoError(fullPath, ioError).c_str()); - return false; - } - if (!isDirectory) { - // File - QString fileRelativePath = QStringView{path}.mid(_vfsSetupParams._localPath.native().size() + 1).toUtf8(); - auto localPinState = pinState(fileRelativePath); - if (localPinState == PinState::OnlineOnly || localPinState == PinState::AlwaysLocal) { - bool isDehydrated = isDehydratedPlaceholder(fileRelativePath); - if (localPinState == PinState::OnlineOnly && !isDehydrated) { - // Add file path to dehydration queue - _workerInfo[WORKER_DEHYDRATION]._mutex.lock(); - _workerInfo[WORKER_DEHYDRATION]._queue.push_front(path); - _workerInfo[WORKER_DEHYDRATION]._mutex.unlock(); - _workerInfo[WORKER_DEHYDRATION]._queueWC.wakeOne(); - } else if (localPinState == PinState::AlwaysLocal && isDehydrated) { - bool syncing; - _syncFileSyncing(_vfsSetupParams._syncDbId, QStr2Path(fileRelativePath), syncing); - if (!syncing) { - // Set hydrating indicator (avoid double hydration) - _setSyncFileSyncing(_vfsSetupParams._syncDbId, QStr2Path(fileRelativePath), true); - - // Add file path to hydration queue - _workerInfo[WORKER_HYDRATION]._mutex.lock(); - _workerInfo[WORKER_HYDRATION]._queue.push_front(path); - _workerInfo[WORKER_HYDRATION]._mutex.unlock(); - _workerInfo[WORKER_HYDRATION]._queueWC.wakeOne(); - } + if (!isDirectory) { + // File + bool isDehydrated = false; + if (ExitInfo exitInfo = isDehydratedPlaceholder(fileRelativePath, isDehydrated); !exitInfo) { + LOGW_WARN(logger(), + L"Error in isDehydratedPlaceholder: " << Utility::formatSyncPath(fullPath) + << L" - " << exitInfo); + return false; } + forceStatus(fullPath, false, 100, !isDehydrated); } - } - } else if (status == SyncFileStatus::Error) { - // Nothing to do - } - - return true; -} + } break; + case SyncFileStatus::Syncing: { + bool isDirectory = false; -Worker::Worker(VfsWin *vfs, int type, int num, log4cplus::Logger logger) : _vfs(vfs), _type(type), _num(num), _logger(logger) {} + if (IoError ioError = IoError::Success; !IoHelper::checkIfIsDirectory(fullPath, isDirectory, ioError)) { + LOGW_WARN(logger(), + L"Failed to check if path is a directory: " << Utility::formatIoError(fullPath, ioError).c_str()); + return false; + } + if (isDirectory) break; + // File + auto localPinState = pinState(fileRelativePath); -void Worker::start() { - LOG_DEBUG(logger(), "Worker with type=" << _type << " and num=" << _num << " started"); + if (localPinState != PinState::OnlineOnly && localPinState != PinState::AlwaysLocal) break; - WorkerInfo &workerInfo = _vfs->_workerInfo[_type]; + bool isDehydrated = false; + if (ExitInfo exitInfo = isDehydratedPlaceholder(fileRelativePath, isDehydrated); !exitInfo) { + LOGW_WARN(logger(), + L"Error in isDehydratedPlaceholder: " << Utility::formatSyncPath(fullPath) << L" - " + << exitInfo); + return false; + } - forever { - workerInfo._mutex.lock(); - while (workerInfo._queue.empty() && !workerInfo._stop) { - LOG_DEBUG(logger(), "Worker with type=" << _type << " and num=" << _num << " waiting"); - workerInfo._queueWC.wait(&workerInfo._mutex); - } + bool syncing; + _syncFileSyncing(_vfsSetupParams._syncDbId, fileRelativePath, syncing); + + if (localPinState == PinState::OnlineOnly && !isDehydrated) { + // Add file path to dehydration queue + _workerInfo[workerDehydration]._mutex.lock(); + _workerInfo[workerDehydration]._queue.push_front(path); + _workerInfo[workerDehydration]._mutex.unlock(); + _workerInfo[workerDehydration]._queueWC.wakeOne(); + } else if (localPinState == PinState::AlwaysLocal && isDehydrated && !syncing) { + // Set hydrating indicator (avoid double hydration) + _setSyncFileSyncing(_vfsSetupParams._syncDbId, fileRelativePath, true); + + // Add file path to hydration queue + _workerInfo[workerHydration]._mutex.lock(); + _workerInfo[workerHydration]._queue.push_front(path); + _workerInfo[workerHydration]._mutex.unlock(); + _workerInfo[workerHydration]._queueWC.wakeOne(); + } - if (workerInfo._stop) { - workerInfo._mutex.unlock(); + } break; + default: + // Nothing to do break; - } - - QString path = workerInfo._queue.back(); - workerInfo._queue.pop_back(); - workerInfo._mutex.unlock(); - - LOG_DEBUG(logger(), "Worker with type=" << _type << " and num=" << _num << " working"); - - switch (_type) { - case WORKER_HYDRATION: - _vfs->hydrate(path); - break; - case WORKER_DEHYDRATION: - _vfs->dehydrate(path); - break; - } } - - LOG_DEBUG(logger(), "Worker with type=" << _type << " and num=" << _num << " ended"); + return true; } - } // namespace KDC diff --git a/src/server/vfs/win/vfs_win.h b/src/server/vfs/win/vfs_win.h index ec2b421c9..c7a921688 100644 --- a/src/server/vfs/win/vfs_win.h +++ b/src/server/vfs/win/vfs_win.h @@ -30,107 +30,65 @@ #include "debug.h" #include "vfs.h" -#include -#include -#include -#include -#include -#include - -#define WORKER_HYDRATION 0 -#define WORKER_DEHYDRATION 1 -#define NB_WORKERS 2 - namespace KDC { -class Worker; - -struct WorkerInfo { - QMutex _mutex; - std::deque _queue; - QWaitCondition _queueWC; - bool _stop = false; - QList _threadList; -}; - class SYNCENGINEVFS_EXPORT VfsWin : public Vfs { Q_OBJECT Q_INTERFACES(KDC::Vfs) public: - WorkerInfo _workerInfo[NB_WORKERS]; - - explicit VfsWin(VfsSetupParams &vfsSetupParams, QObject *parent = nullptr); - ~VfsWin(); + explicit VfsWin(const VfsSetupParams &vfsSetupParams, QObject *parent = nullptr); void debugCbk(TraceLevel level, const wchar_t *msg); - VirtualFileMode mode() const override; + VirtualFileMode mode() const final; - bool socketApiPinStateActionsShown() const override { return false; } - bool isHydrating() const override; + bool socketApiPinStateActionsShown() const final { return false; } - bool updateMetadata(const QString &filePath, time_t creationTime, time_t modtime, qint64 size, const QByteArray &fileId, - QString *error) override; + ExitInfo updateMetadata(const SyncPath &filePath, time_t creationTime, time_t modtime, int64_t size, + const NodeId &fileId) final; - bool createPlaceholder(const SyncPath &relativeLocalPath, const SyncFileItem &item) override; - bool dehydratePlaceholder(const QString &path) override; - bool convertToPlaceholder(const QString &path, const SyncFileItem &item) override; - void convertDirContentToPlaceholder(const QString &filePath, bool isHydratedIn) override; - virtual void clearFileAttributes(const QString &path) override; + ExitInfo createPlaceholder(const SyncPath &relativeLocalPath, const SyncFileItem &item) final; + ExitInfo dehydratePlaceholder(const SyncPath &path) final; + ExitInfo convertToPlaceholder(const SyncPath &path, const SyncFileItem &item) final; + void convertDirContentToPlaceholder(const QString &filePath, bool isHydratedIn) final; + void clearFileAttributes(const SyncPath &path) final; - bool updateFetchStatus(const QString &tmpPath, const QString &path, qint64 received, bool &canceled, - bool &finished) override; - bool forceStatus(const QString &absolutePath, bool isSyncing, int progress, bool isHydrated = false) override; + ExitInfo updateFetchStatus(const SyncPath &tmpPath, const SyncPath &path, int64_t received, bool &canceled, + bool &finished) final; + ExitInfo forceStatus(const SyncPath &absolutePath, bool isSyncing, int progress, bool isHydrated = false) final; - bool needsMetadataUpdate(const SyncFileItem &) override { return false; } - bool isDehydratedPlaceholder(const QString &filePath, bool isAbsolutePath = false) override; + ExitInfo isDehydratedPlaceholder(const SyncPath &filePath, bool &isDehydrated, bool isAbsolutePath = false) final; - bool setPinState(const QString &fileRelativePath, PinState state) override; - PinState pinState(const QString &relativePath) override; - bool status(const QString &, bool &, bool &, bool &, int &) override; - virtual bool setThumbnail(const QString &, const QPixmap &) override { return true; }; - virtual bool setAppExcludeList() override { return true; } - virtual bool getFetchingAppList(QHash &) override { return true; } + ExitInfo setPinState(const SyncPath &fileRelativePath, PinState state) final; + PinState pinState(const SyncPath &relativePath) final; + ExitInfo status(const SyncPath &, bool &, bool &, bool &, int &) final; + ExitInfo setThumbnail(const SyncPath &, const QPixmap &) final { return ExitCode::Ok; }; + ExitInfo setAppExcludeList() final { return ExitCode::Ok; } + ExitInfo getFetchingAppList(QHash &) final { return ExitCode::Ok; } - bool isExcluded(const QString &) override { return false; } + bool isExcluded(const SyncPath &) final { return false; } virtual bool setCreationDate(const QString &, time_t) { return false; } - virtual void cancelHydrate(const QString &path) override; + void cancelHydrate(const SyncPath &path) final; - void dehydrate(const QString &path); - void hydrate(const QString &path); + void dehydrate(const QString &path) final; + void hydrate(const QString &path) final; public slots: - bool fileStatusChanged(const QString &path, KDC::SyncFileStatus status) override; + bool fileStatusChanged(const SyncPath &path, KDC::SyncFileStatus status) final; protected: - bool startImpl(bool &installationDone, bool &activationDone, bool &connectionDone) override; - void stopImpl(bool unregister) override; + ExitInfo startImpl(bool &installationDone, bool &activationDone, bool &connectionDone) final; + void stopImpl(bool unregister) final; friend class TestWorkers; private: log4cplus::Logger _logger; - void exclude(const QString &path) override; - void setPlaceholderStatus(const QString &path, bool syncOngoing); -}; - -class Worker : public QObject { - Q_OBJECT - - public: - Worker(VfsWin *vfs, int type, int num, log4cplus::Logger logger); - void start(); - - private: - VfsWin *_vfs; - int _type; - int _num; - log4cplus::Logger _logger; - - inline log4cplus::Logger logger() { return _logger; } + void exclude(const SyncPath &path) final; + ExitInfo setPlaceholderStatus(const QString &path, bool syncOngoing); }; class WinVfsPluginFactory : public QObject, public DefaultPluginFactory { diff --git a/test/libcommon/utility/testutility.cpp b/test/libcommon/utility/testutility.cpp index 20ad34182..a81da85a1 100644 --- a/test/libcommon/utility/testutility.cpp +++ b/test/libcommon/utility/testutility.cpp @@ -19,6 +19,7 @@ #include "config.h" #include "testutility.h" #include "libcommon/utility/utility.h" +#include "libcommon/utility/sourcelocation.h" #include "libcommonserver/io/iohelper.h" #include "test_utility/localtemporarydirectory.h" #include @@ -299,6 +300,39 @@ void TestUtility::testCurrentVersion() { CPPUNIT_ASSERT(std::regex_match(test, std::regex(R"(\d{1,2}\.{1}\d{1,2}\.{1}\d{1,2}\.{1}\d{0,8}$)"))); } +SourceLocation testSourceLocationFooFunc(uint32_t &constructLine, SourceLocation location = SourceLocation::currentLoc()) { + constructLine = __LINE__ - 1; + return location; +} + +void TestUtility::testSourceLocation() { + SourceLocation location = SourceLocation::currentLoc(); + uint32_t correctLine = __LINE__ - 1; + + CPPUNIT_ASSERT_EQUAL(std::string("testutility.cpp"), location.fileName()); + CPPUNIT_ASSERT_EQUAL(correctLine, location.line()); + +#ifdef SRC_LOC_AVALAIBALE + CPPUNIT_ASSERT_EQUAL(std::string("testSourceLocation"), location.functionName()); +#else + CPPUNIT_ASSERT_EQUAL(std::string(""), location.functionName()); +#endif + + // Test as a default argument + uint32_t fooFuncLine = 0; + location = testSourceLocationFooFunc(fooFuncLine); + correctLine = __LINE__ - 1; + + CPPUNIT_ASSERT_EQUAL(std::string("testutility.cpp"), location.fileName()); +#ifdef SRC_LOC_AVALAIBALE + CPPUNIT_ASSERT_EQUAL(std::string("testSourceLocation"), location.functionName()); + CPPUNIT_ASSERT_EQUAL(correctLine, location.line()); +#else + CPPUNIT_ASSERT_EQUAL(std::string(""), location.functionName()); + CPPUNIT_ASSERT_EQUAL(fooFuncLine, location.line()); +#endif +} + void TestUtility::testGenerateRandomStringAlphaNum() { { int err = 0; diff --git a/test/libcommon/utility/testutility.h b/test/libcommon/utility/testutility.h index d481473c7..4d3e4a6af 100644 --- a/test/libcommon/utility/testutility.h +++ b/test/libcommon/utility/testutility.h @@ -31,6 +31,7 @@ class TestUtility : public CppUnit::TestFixture { CPPUNIT_TEST(testArgsWriter); CPPUNIT_TEST(testCompressFile); CPPUNIT_TEST(testCurrentVersion); + CPPUNIT_TEST(testSourceLocation); CPPUNIT_TEST(testGenerateRandomStringAlphaNum); #ifdef _WIN32 CPPUNIT_TEST(testGetLastErrorMessage); @@ -44,6 +45,7 @@ class TestUtility : public CppUnit::TestFixture { void testArgsWriter(); void testCompressFile(); void testCurrentVersion(); + void testSourceLocation(); void testGenerateRandomStringAlphaNum(); #ifdef _WIN32 void testGetLastErrorMessage(); diff --git a/test/libsyncengine/CMakeLists.txt b/test/libsyncengine/CMakeLists.txt index d0e78417e..5d65b6f8e 100644 --- a/test/libsyncengine/CMakeLists.txt +++ b/test/libsyncengine/CMakeLists.txt @@ -4,6 +4,8 @@ find_package(SQLite3 3.8.0 REQUIRED) find_package(Poco REQUIRED Foundation) find_package(log4cplus 2.1.0 REQUIRED) +set(CMAKE_AUTOMOC TRUE) + set(testsyncengine_NAME ${APPLICATION_NAME}_test_syncengine) set(testsyncengine_SRCS diff --git a/test/libsyncengine/jobs/network/testnetworkjobs.cpp b/test/libsyncengine/jobs/network/testnetworkjobs.cpp index 743406380..33a91b021 100644 --- a/test/libsyncengine/jobs/network/testnetworkjobs.cpp +++ b/test/libsyncengine/jobs/network/testnetworkjobs.cpp @@ -338,7 +338,7 @@ void TestNetworkJobs::testDownload() { return temporaryDirectory.path(); }; std::function MockRename = - [](const SyncPath &, const SyncPath &, std::error_code &ec) { + []([[maybe_unused]] const SyncPath &, [[maybe_unused]] const SyncPath &, std::error_code &ec) { #ifdef _WIN32 ec = std::make_error_code(static_cast(ERROR_NOT_SAME_DEVICE)); #else diff --git a/test/libsyncengine/propagation/executor/testexecutorworker.cpp b/test/libsyncengine/propagation/executor/testexecutorworker.cpp index e05200e4e..a1365f99c 100644 --- a/test/libsyncengine/propagation/executor/testexecutorworker.cpp +++ b/test/libsyncengine/propagation/executor/testexecutorworker.cpp @@ -86,25 +86,19 @@ void TestExecutorWorker::tearDown() { void TestExecutorWorker::testCheckLiteSyncInfoForCreate() { #ifdef __APPLE__ - // Setup dummy values. Test inputs are set in the callbacks defined below. + // Setup dummy values. Test inputs are set in the callbacks defined below. const auto opPtr = std::make_shared(); opPtr->setTargetSide(ReplicaSide::Remote); - const auto node = std::make_shared(1, ReplicaSide::Local, "test_file.txt", NodeType::File, OperationType::None, "1234", - testhelpers::defaultTime, testhelpers::defaultTime, testhelpers::defaultFileSize, - _syncPal->updateTree(ReplicaSide::Local)->rootNode()); + const auto node = std::make_shared(1, ReplicaSide::Local, Str2SyncName("test_file.txt"), NodeType::File, + OperationType::None, "1234", testhelpers::defaultTime, testhelpers::defaultTime, + testhelpers::defaultFileSize, _syncPal->updateTree(ReplicaSide::Local)->rootNode()); opPtr->setAffectedNode(node); + std::shared_ptr mockVfs = std::make_shared(); + _syncPal->setVfsPtr(mockVfs); // A hydrated placeholder. { - _syncPal->setVfsStatusCallback([]([[maybe_unused]] int syncDbId, [[maybe_unused]] const SyncPath &itemPath, - bool &isPlaceholder, bool &isHydrated, bool &isSyncing, int &progress) -> bool { - isPlaceholder = true; - isHydrated = true; - isSyncing = false; - progress = 0; - return true; - }); - + mockVfs->setVfsStatusOutput(true, true, false, 0); bool isDehydratedPlaceholder = false; _executorWorker->checkLiteSyncInfoForCreate(opPtr, "/", isDehydratedPlaceholder); @@ -113,15 +107,7 @@ void TestExecutorWorker::testCheckLiteSyncInfoForCreate() { // A dehydrated placeholder. { - _syncPal->setVfsStatusCallback([]([[maybe_unused]] int syncDbId, [[maybe_unused]] const SyncPath &itemPath, - bool &isPlaceholder, bool &isHydrated, bool &isSyncing, int &progress) -> bool { - isPlaceholder = true; - isHydrated = false; - isSyncing = false; - progress = 0; - return true; - }); - + mockVfs->setVfsStatusOutput(true, false, false, 0); bool isDehydratedPlaceholder = false; _executorWorker->checkLiteSyncInfoForCreate(opPtr, "/", isDehydratedPlaceholder); @@ -130,15 +116,7 @@ void TestExecutorWorker::testCheckLiteSyncInfoForCreate() { // A partially hydrated placeholder (syncing item). { - _syncPal->setVfsStatusCallback([]([[maybe_unused]] int syncDbId, [[maybe_unused]] const SyncPath &itemPath, - bool &isPlaceholder, bool &isHydrated, bool &isSyncing, int &progress) -> bool { - isPlaceholder = true; - isHydrated = false; - isSyncing = true; - progress = 30; - return true; - }); - + mockVfs->setVfsStatusOutput(true, false, true, 0); bool isDehydratedPlaceholder = false; _executorWorker->checkLiteSyncInfoForCreate(opPtr, "/", isDehydratedPlaceholder); @@ -147,15 +125,7 @@ void TestExecutorWorker::testCheckLiteSyncInfoForCreate() { // Not a placeholder. { - _syncPal->setVfsStatusCallback([]([[maybe_unused]] int syncDbId, [[maybe_unused]] const SyncPath &itemPath, - bool &isPlaceholder, bool &isHydrated, bool &isSyncing, int &progress) -> bool { - isPlaceholder = false; - isHydrated = false; - isSyncing = false; - progress = 0; - return true; - }); - + mockVfs->setVfsStatusOutput(false, false, false, 0); bool isDehydratedPlaceholder = false; _executorWorker->checkLiteSyncInfoForCreate(opPtr, "/", isDehydratedPlaceholder); @@ -210,7 +180,7 @@ SyncOpPtr TestExecutorWorker::generateSyncOperationWithNestedNodes(const DbNodeI class ExecutorWorkerMock : public ExecutorWorker { public: ExecutorWorkerMock(std::shared_ptr syncPal, const std::string &name, const std::string &shortName) : - ExecutorWorker(syncPal, name, shortName) {}; + ExecutorWorker(syncPal, name, shortName){}; using ArgsMap = std::map, std::shared_ptr>; void setCorrespondingNodeInOtherTree(ArgsMap nodeMap) { _correspondingNodeInOtherTree = nodeMap; }; @@ -258,20 +228,6 @@ void TestExecutorWorker::testIsValidDestination() { const auto root = _syncPal->updateTree(ReplicaSide::Remote)->rootNode(); - // False if the item created on the local replica is not at the root of the synchronisation folder and has a - // corresponding parent node with no id. - { - const auto correspondingParentNode = std::make_shared( - 666, ReplicaSide::Remote, Str("parent_dir"), NodeType::Directory, OperationType::None, std::nullopt, - testhelpers::defaultTime, testhelpers::defaultTime, testhelpers::defaultFileSize, root); - - - SyncOpPtr op = generateSyncOperationWithNestedNodes(1, Str("test_file.txt"), OperationType::Create, NodeType::File); - executorWorkerMock->setCorrespondingNodeInOtherTree({{op->affectedNode()->parentNode(), correspondingParentNode}}); - op->setTargetSide(ReplicaSide::Remote); - CPPUNIT_ASSERT(!executorWorkerMock->isValidDestination(op)); - } - const auto correspondingParentCommonDocsNode = std::make_shared( 666, ReplicaSide::Remote, Utility::commonDocumentsFolderName(), NodeType::Directory, OperationType::None, "common_docs_id", testhelpers::defaultTime, testhelpers::defaultTime, testhelpers::defaultFileSize, root); diff --git a/test/libsyncengine/propagation/executor/testexecutorworker.h b/test/libsyncengine/propagation/executor/testexecutorworker.h index 8d2d47a23..6b7bb6a37 100644 --- a/test/libsyncengine/propagation/executor/testexecutorworker.h +++ b/test/libsyncengine/propagation/executor/testexecutorworker.h @@ -24,6 +24,33 @@ namespace KDC { +class MockVfs : public VfsOff { + Q_OBJECT + public: + explicit MockVfs() : VfsOff(vfsSetupParams) {} + void setVfsStatusOutput(bool isPlaceholder, bool isHydrated, bool isSyncing, int progress) { + vfsStatusIsHydrated = isHydrated; + vfsStatusIsSyncing = isSyncing; + vfsStatusIsPlaceholder = isPlaceholder; + vfsStatusProgress = progress; + } + ExitInfo status([[maybe_unused]] const SyncPath &filePath, bool &isPlaceholder, bool &isHydrated, bool &isSyncing, + int &progress) override { + isHydrated = vfsStatusIsHydrated; + isSyncing = vfsStatusIsSyncing; + isPlaceholder = vfsStatusIsPlaceholder; + progress = vfsStatusProgress; + return ExitCode::Ok; + } + + private: + bool vfsStatusIsHydrated = false; + bool vfsStatusIsSyncing = false; + bool vfsStatusIsPlaceholder = false; + int vfsStatusProgress = 0; + VfsSetupParams vfsSetupParams; +}; + class TestExecutorWorker : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(TestExecutorWorker); CPPUNIT_TEST(testCheckLiteSyncInfoForCreate); diff --git a/test/libsyncengine/update_detection/file_system_observer/testlocalfilesystemobserverworker.cpp b/test/libsyncengine/update_detection/file_system_observer/testlocalfilesystemobserverworker.cpp index c55ac792c..81e956976 100644 --- a/test/libsyncengine/update_detection/file_system_observer/testlocalfilesystemobserverworker.cpp +++ b/test/libsyncengine/update_detection/file_system_observer/testlocalfilesystemobserverworker.cpp @@ -84,9 +84,7 @@ void TestLocalFileSystemObserverWorker::setUp() { _syncPal->createSharedObjects(); _syncPal->setLocalPath(_rootFolderPath); _syncPal->_tmpBlacklistManager = std::make_shared(_syncPal); - _syncPal->setVfsStatusCallback(&vfsStatus); // Do nothing - _syncPal->setVfsPinStateCallback(&vfsPinState); // Do nothing - _syncPal->setVfsFileStatusChangedCallback(&vfsFileStatusChanged); // Do nothing + _syncPal->setVfsPtr(std::make_shared()); #if defined(_WIN32) _syncPal->_localFSObserverWorker = std::shared_ptr( diff --git a/test/server/CMakeLists.txt b/test/server/CMakeLists.txt index 596db3937..f36174c0e 100644 --- a/test/server/CMakeLists.txt +++ b/test/server/CMakeLists.txt @@ -10,8 +10,6 @@ set(testserver_NAME ${APPLICATION_NAME}_test_server) set(server_srcs_path ${CMAKE_SOURCE_DIR}/src/server) set(server_SRCS - ${CMAKE_SOURCE_DIR}/src/libcommonserver/vfs.h ${CMAKE_SOURCE_DIR}/src/libcommonserver/vfs.cpp - ${CMAKE_SOURCE_DIR}/src/libcommonserver/plugin.h ${CMAKE_SOURCE_DIR}/src/libcommonserver/plugin.cpp ${server_srcs_path}/logarchiver/logarchiver.h ${server_srcs_path}/logarchiver/logarchiver.cpp ${server_srcs_path}/socketapi.h ${server_srcs_path}/socketapi.cpp ${server_srcs_path}/socketlistener.h ${server_srcs_path}/socketlistener.cpp diff --git a/test/server/workers/testworkers.cpp b/test/server/workers/testworkers.cpp index f01634510..adb207acc 100644 --- a/test/server/workers/testworkers.cpp +++ b/test/server/workers/testworkers.cpp @@ -48,33 +48,6 @@ bool TestWorkers::_vfsConnectionDone = false; constexpr bool connectorsAreAlreadyInstalled = false; #endif -bool TestWorkers::createPlaceholder(int syncDbId, const SyncPath &relativeLocalPath, const SyncFileItem &item) { - (void) syncDbId; - - if (_vfsPtr && !_vfsPtr->createPlaceholder(relativeLocalPath, item)) { - return false; - } - return true; -} - -bool TestWorkers::convertToPlaceholder(int syncDbId, const SyncPath &relativeLocalPath, const SyncFileItem &item) { - (void) syncDbId; - - if (_vfsPtr && !_vfsPtr->convertToPlaceholder(Path2QStr(relativeLocalPath), item)) { - return false; - } - return true; -} - -bool TestWorkers::setPinState(int syncDbId, const SyncPath &relativeLocalPath, PinState pinState) { - (void) syncDbId; - - if (_vfsPtr && !_vfsPtr->setPinState(Path2QStr(relativeLocalPath), pinState)) { - return false; - } - return true; -} - void TestWorkers::setUp() { _logger = Log::instance()->getLogger(); @@ -154,9 +127,7 @@ void TestWorkers::setUp() { _syncPal->createWorkers(); _syncPal->syncDb()->setAutoDelete(true); _syncPal->createProgressInfo(); - _syncPal->setVfsCreatePlaceholderCallback(createPlaceholder); - _syncPal->setVfsConvertToPlaceholderCallback(convertToPlaceholder); - _syncPal->setVfsSetPinStateCallback(setPinState); + _syncPal->setVfsPtr(_vfsPtr); // Setup SocketApi std::unordered_map> syncPalMap; @@ -241,14 +212,12 @@ void TestWorkers::testCreatePlaceholder() { // Folder doesn't exist (normal case) exitInfo = _syncPal->_executorWorker->createPlaceholder(relativeFolderPath); - CPPUNIT_ASSERT_EQUAL(ExitCode::Ok, exitInfo.code()); - CPPUNIT_ASSERT_EQUAL(ExitCause::Unknown, exitInfo.cause()); + CPPUNIT_ASSERT_EQUAL(ExitInfo(ExitCode::Ok), exitInfo); #if defined(__APPLE__) || defined(_WIN32) // Folder already exists exitInfo = _syncPal->_executorWorker->createPlaceholder(relativeFolderPath); - CPPUNIT_ASSERT_EQUAL(ExitCode::DataError, exitInfo.code()); - CPPUNIT_ASSERT_EQUAL(ExitCause::FileAlreadyExist, exitInfo.cause()); + CPPUNIT_ASSERT_EQUAL(ExitInfo(ExitCode::SystemError, ExitCause::FileAlreadyExist), exitInfo); #endif } @@ -276,7 +245,8 @@ void TestWorkers::testCreatePlaceholder() { CPPUNIT_ASSERT_EQUAL(ExitCode::SystemError, exitInfo.code()); CPPUNIT_ASSERT_EQUAL(ExitCause::FileAccessError, exitInfo.cause()); #else - // Strangely (bug?), the Windows api is able to create a placeholder in a folder for which the user does not have rights + // Strangely (bug?), the Windows api is able to create a placeholder in a folder for which the user does not have + // rights CPPUNIT_ASSERT_EQUAL(ExitCode::Ok, exitInfo.code()); CPPUNIT_ASSERT_EQUAL(ExitCause::Unknown, exitInfo.cause()); @@ -302,8 +272,7 @@ void TestWorkers::testCreatePlaceholder() { #if defined(__APPLE__) || defined(_WIN32) // File already exists exitInfo = _syncPal->_executorWorker->createPlaceholder(relativeFilePath); - CPPUNIT_ASSERT_EQUAL(ExitCode::DataError, exitInfo.code()); - CPPUNIT_ASSERT_EQUAL(ExitCause::FileAlreadyExist, exitInfo.cause()); + CPPUNIT_ASSERT_EQUAL(ExitInfo(ExitCode::SystemError, ExitCause::FileAlreadyExist), exitInfo); #endif } } @@ -314,8 +283,7 @@ void TestWorkers::testConvertToPlaceholder() { // Progress not intialized { exitInfo = _syncPal->_executorWorker->convertToPlaceholder(SyncPath("dummy"), true); - CPPUNIT_ASSERT_EQUAL(ExitCode::DataError, exitInfo.code()); - CPPUNIT_ASSERT_EQUAL(ExitCause::InvalidSnapshot, exitInfo.cause()); + CPPUNIT_ASSERT_EQUAL(ExitInfo(ExitCode::DataError, ExitCause::InvalidSnapshot), exitInfo); } // Convert folder operation @@ -330,8 +298,7 @@ void TestWorkers::testConvertToPlaceholder() { #if defined(__APPLE__) || defined(_WIN32) // Folder doesn't exist exitInfo = _syncPal->_executorWorker->convertToPlaceholder(relativeFolderPath, true); - CPPUNIT_ASSERT_EQUAL(ExitCode::DataError, exitInfo.code()); - CPPUNIT_ASSERT_EQUAL(ExitCause::InvalidSnapshot, exitInfo.cause()); + CPPUNIT_ASSERT_EQUAL(ExitInfo(ExitCode::SystemError, ExitCause::NotFound), exitInfo); #endif // Folder already exists (normal case) @@ -339,8 +306,7 @@ void TestWorkers::testConvertToPlaceholder() { CPPUNIT_ASSERT(std::filesystem::create_directory(_syncPal->localPath() / relativeFolderPath, ec) && ec.value() == 0); exitInfo = _syncPal->_executorWorker->convertToPlaceholder(relativeFolderPath, true); - CPPUNIT_ASSERT_EQUAL(ExitCode::Ok, exitInfo.code()); - CPPUNIT_ASSERT_EQUAL(ExitCause::Unknown, exitInfo.cause()); + CPPUNIT_ASSERT_EQUAL(ExitInfo(ExitCode::Ok), exitInfo); } // Convert file operation @@ -350,6 +316,7 @@ void TestWorkers::testConvertToPlaceholder() { syncItem.setPath(relativeFilePath); syncItem.setType(NodeType::File); syncItem.setDirection(SyncDirection::Down); + syncItem.setRemoteNodeId("1"); CPPUNIT_ASSERT(_syncPal->initProgress(syncItem)); #if defined(__APPLE__) || defined(_WIN32) @@ -359,8 +326,15 @@ void TestWorkers::testConvertToPlaceholder() { ioError == IoError::Success); exitInfo = _syncPal->_executorWorker->createPlaceholder(relativeFilePath); - CPPUNIT_ASSERT_EQUAL(ExitCode::SystemError, exitInfo.code()); - CPPUNIT_ASSERT_EQUAL(ExitCause::FileAccessError, exitInfo.cause()); +#if defined(__APPLE__) + CPPUNIT_ASSERT_EQUAL(ExitInfo(ExitCode::SystemError, ExitCause::FileAccessError), exitInfo); +#else + // Strangely (bug?), the Windows api is able to create a placeholder in a folder for which the user does not have + // rights + CPPUNIT_ASSERT_EQUAL(ExitInfo(ExitCode::Ok), exitInfo); + CPPUNIT_ASSERT(IoHelper::deleteItem(_syncPal->localPath() / relativeFilePath, ioError)); + CPPUNIT_ASSERT_EQUAL(IoError::Success, ioError); +#endif ioError = IoError::Unknown; CPPUNIT_ASSERT(IoHelper::setRights(_syncPal->localPath() / relativeFolderPath, true, true, true, ioError) && @@ -368,8 +342,7 @@ void TestWorkers::testConvertToPlaceholder() { // File doesn't exist exitInfo = _syncPal->_executorWorker->convertToPlaceholder(relativeFilePath, true); - CPPUNIT_ASSERT_EQUAL(ExitCode::DataError, exitInfo.code()); - CPPUNIT_ASSERT_EQUAL(ExitCause::InvalidSnapshot, exitInfo.cause()); + CPPUNIT_ASSERT_EQUAL(ExitInfo(ExitCode::SystemError, ExitCause::NotFound), exitInfo); #endif // File already exists (normal case) @@ -379,8 +352,9 @@ void TestWorkers::testConvertToPlaceholder() { } exitInfo = _syncPal->_executorWorker->convertToPlaceholder(relativeFilePath, true); - CPPUNIT_ASSERT_EQUAL(ExitCode::Ok, exitInfo.code()); - CPPUNIT_ASSERT_EQUAL(ExitCause::Unknown, exitInfo.cause()); + (CppUnit::assertEquals((ExitInfo(ExitCode::Ok)), (exitInfo), + CppUnit::SourceLine("C:\\Projects\\desktop-kDrive\\test\\server\\workers\\testworkers.cpp", 374), + "")); } } diff --git a/test/server/workers/testworkers.h b/test/server/workers/testworkers.h index 7ae4d3c8f..891119ae3 100644 --- a/test/server/workers/testworkers.h +++ b/test/server/workers/testworkers.h @@ -48,9 +48,6 @@ class TestWorkers : public CppUnit::TestFixture { protected: static bool startVfs(); - static bool createPlaceholder(int syncDbId, const SyncPath &relativeLocalPath, const SyncFileItem &item); - static bool convertToPlaceholder(int syncDbId, const SyncPath &relativeLocalPath, const SyncFileItem &item); - static bool setPinState(int syncDbId, const SyncPath &relativeLocalPath, PinState pinState); log4cplus::Logger _logger; std::shared_ptr _syncPal;