From 430ebacd76084dd9d61b4762c6f004c0b4000e29 Mon Sep 17 00:00:00 2001 From: Hannah von Reth Date: Tue, 15 Sep 2026 15:28:25 +0200 Subject: [PATCH] Cfapi: Reuse created handles --- src/gui/folderwatcher_win.cpp | 15 +-- src/gui/folderwatcher_win.h | 1 - src/libsync/common/utility_win.cpp | 11 +- src/libsync/common/utility_win.h | 4 +- src/libsync/owncloudpropagator.cpp | 14 +-- src/plugins/vfs/cfapi/cfapiwrapper.cpp | 155 +++++++++++-------------- src/plugins/vfs/cfapi/cfapiwrapper.h | 28 ++--- src/plugins/vfs/cfapi/vfs_cfapi.cpp | 74 ++++++++---- 8 files changed, 146 insertions(+), 156 deletions(-) diff --git a/src/gui/folderwatcher_win.cpp b/src/gui/folderwatcher_win.cpp index eb0eb747c0..090e55722c 100644 --- a/src/gui/folderwatcher_win.cpp +++ b/src/gui/folderwatcher_win.cpp @@ -40,7 +40,7 @@ WatcherThread::WatchChanges WatcherThread::watchChanges(size_t fileNotifyBufferS QScopeGuard todoBeforeReturn([this]() { CancelIo(_directory); - closeHandle(); + _directory.close(); }); OVERLAPPED overlapped = {}; @@ -155,13 +155,6 @@ void WatcherThread::processEntries(FILE_NOTIFY_INFORMATION *curEntry) } } -void WatcherThread::closeHandle() -{ - if (_directory) { - _directory.close(); - } -} - void WatcherThread::run() { _resultEvent = CreateEvent(nullptr, true, false, nullptr); @@ -195,16 +188,12 @@ WatcherThread::WatcherThread(FolderWatcherPrivate *parent, const QString &path) , _parent(parent) , _path(path + (path.endsWith(QLatin1Char('/')) ? QString() : QStringLiteral("/"))) , _longPath(FileSystem::longWinPath(_path)) - , _directory(nullptr) , _resultEvent(nullptr) , _stopEvent(nullptr) { } -WatcherThread::~WatcherThread() -{ - closeHandle(); -} +WatcherThread::~WatcherThread() { } void WatcherThread::stop() { diff --git a/src/gui/folderwatcher_win.h b/src/gui/folderwatcher_win.h index 4652608b3c..734817f94a 100644 --- a/src/gui/folderwatcher_win.h +++ b/src/gui/folderwatcher_win.h @@ -47,7 +47,6 @@ class WatcherThread : public QThread void run() override; WatchChanges watchChanges(size_t fileNotifyBufferSize); void processEntries(FILE_NOTIFY_INFORMATION *curEntry); - void closeHandle(); Q_SIGNALS: void changed(QSet path); diff --git a/src/libsync/common/utility_win.cpp b/src/libsync/common/utility_win.cpp index 9bf740eb4d..4b4ca640f8 100644 --- a/src/libsync/common/utility_win.cpp +++ b/src/libsync/common/utility_win.cpp @@ -97,10 +97,11 @@ QString Utility::formatWinError(long errorCode) .arg(QString::number(static_cast(errorCode), 16), QString::fromWCharArray(_com_error(errorCode).ErrorMessage())); } -Utility::Handle::Handle(HANDLE h, std::function &&close, uint32_t error) +Utility::Handle::Handle(HANDLE h, const std::filesystem::path &path, std::function &&close, uint32_t error) : _handle(h) , _close(std::move(close)) , _error(error) + , _path(path) { if (_handle == INVALID_HANDLE_VALUE && _error == NO_ERROR) { _error = GetLastError(); @@ -116,13 +117,11 @@ Utility::Handle Utility::Handle::createHandle(const std::filesystem::path &path, if (p.async) { flags |= FILE_FLAG_OVERLAPPED; } - auto handle = Utility::Handle{CreateFileW(path.native().data(), p.accessMode, p.shareMode, nullptr, p.creationFlags, flags, nullptr)}; - handle._path = path; - return handle; + return Utility::Handle{CreateFileW(path.lexically_normal().native().data(), p.accessMode, p.shareMode, nullptr, p.creationFlags, flags, nullptr), path}; } -Utility::Handle::Handle(HANDLE h) - : Handle(h, &CloseHandle) +Utility::Handle::Handle(HANDLE h, const std::filesystem::path &path) + : Handle(h, path, &CloseHandle) { } diff --git a/src/libsync/common/utility_win.h b/src/libsync/common/utility_win.h index 0e8ca1bd72..01dcbd3ce7 100644 --- a/src/libsync/common/utility_win.h +++ b/src/libsync/common/utility_win.h @@ -32,8 +32,8 @@ namespace Utility { * A RAAI for Windows Handles */ Handle() = default; - explicit Handle(HANDLE h); - explicit Handle(HANDLE h, std::function &&close, uint32_t error = NO_ERROR); + explicit Handle(HANDLE h, const std::filesystem::path &path); + explicit Handle(HANDLE h, const std::filesystem::path &path, std::function &&close, uint32_t error = NO_ERROR); struct CreateHandleParameter { diff --git a/src/libsync/owncloudpropagator.cpp b/src/libsync/owncloudpropagator.cpp index 0c51ad5441..86205a3717 100644 --- a/src/libsync/owncloudpropagator.cpp +++ b/src/libsync/owncloudpropagator.cpp @@ -552,15 +552,13 @@ Result OwncloudPropagator::localFileNameClash(const QString &relF } #elif defined(Q_OS_WIN) WIN32_FIND_DATA FindFileData; - const Utility::Handle hFind(FindFirstFileW(reinterpret_cast(FileSystem::longWinPath(fileInfo.filePath()).utf16()), &FindFileData), - [](HANDLE h) { FindClose(h); }); + const auto path = FileSystem::toFilesystemPath(fileInfo.filePath()); + HANDLE hFind = FindFirstFileW(path.c_str(), &FindFileData); if (hFind != INVALID_HANDLE_VALUE) { - const QString realFileName = QString::fromWCharArray(FindFileData.cFileName); - - if (!fileInfo.filePath().endsWith(realFileName, Qt::CaseSensitive)) { - const QString clashName = fileInfo.path() + QLatin1Char('/') + realFileName; - qCWarning(lcPropagator) << u"Detected case clash between" << fileInfo.filePath() << u"and" << clashName; - return clashName; + const Utility::Handle handle(hFind, path.parent_path() / FindFileData.cFileName, [](HANDLE h) { FindClose(h); }); + if (path.compare(handle.path()) != 0) { + qCWarning(lcPropagator) << u"Detected case clash between" << fileInfo.filePath() << u"and" << handle.path().native(); + return FileSystem::fromFilesystemPath(handle.path().native()); } } #else diff --git a/src/plugins/vfs/cfapi/cfapiwrapper.cpp b/src/plugins/vfs/cfapi/cfapiwrapper.cpp index dfa17c16cb..b3be5ae972 100644 --- a/src/plugins/vfs/cfapi/cfapiwrapper.cpp +++ b/src/plugins/vfs/cfapi/cfapiwrapper.cpp @@ -127,14 +127,20 @@ void CALLBACK cfApiFetchDataCallback(const CF_CALLBACK_INFO *callbackInfo, const } OCC::Result updatePlaceholderState( - const QString &path, time_t modtime, qint64 size, const QByteArray &fileId, const QString &replacesPath, bool isHydrated) + const OCC::Utility::Handle &handle, time_t modtime, qint64 size, const QByteArray &fileId, const std::filesystem::path &replacesPath, bool isHydrated) { OCC::CfApiWrapper::PlaceHolderInfo info; - if (!replacesPath.isEmpty()) { - info = OCC::CfApiWrapper::findPlaceholderInfo(replacesPath); + if (!replacesPath.empty()) { + auto replacesHandle = OCC::Utility::Handle::createHandle(replacesPath); + if (!replacesHandle) { + const QString errorMessage = u"Couldn't create handle for placeholder %1 Error: %2"_s.arg(replacesPath.native(), replacesHandle.errorMessage()); + qCWarning(lcCfApiWrapper) << errorMessage; + return errorMessage; + } + info = OCC::CfApiWrapper::findPlaceholderInfo(replacesHandle); } if (!info) { - info = OCC::CfApiWrapper::findPlaceholderInfo(path); + info = OCC::CfApiWrapper::findPlaceholderInfo(handle); } if (!info) { Q_ASSERT(false); @@ -152,25 +158,18 @@ OCC::Result updatePlaceholderStat metadata->BasicInfo.LastAccessTime = metadata->BasicInfo.CreationTime; metadata->BasicInfo.ChangeTime = metadata->BasicInfo.CreationTime; } - - qCInfo(lcCfApiWrapper) << u"updatePlaceholderState" << path << modtime << fileId; - auto handle = OCC::Utility::Handle::createHandle(OCC::FileSystem::toFilesystemPath(path)); - if (!handle) { - const QString errorMessage = u"Couldn't create handle for placeholder %1 Error: %2"_s.arg(path, handle.errorMessage()); - qCWarning(lcCfApiWrapper) << errorMessage << replacesPath; - return errorMessage; - } + qCInfo(lcCfApiWrapper) << u"updatePlaceholderState" << handle.path().native() << modtime << fileId; const qint64 result = CfUpdatePlaceholder(handle, metadata ? &metadata.value() : nullptr, fileId.data(), static_cast(fileId.size()), nullptr, 0, CF_UPDATE_FLAG_MARK_IN_SYNC, nullptr, nullptr); if (result != S_OK) { - const QString errorMessage = u"Couldn't update placeholder info %1 Error: %2"_s.arg(path, OCC::Utility::formatWinError(result)); - qCWarning(lcCfApiWrapper) << errorMessage << replacesPath; + const QString errorMessage = u"Couldn't update placeholder info %1 Error: %2"_s.arg(handle.path().native(), OCC::Utility::formatWinError(result)); + qCWarning(lcCfApiWrapper) << errorMessage << replacesPath.native(); return errorMessage; } // Pin state tends to be lost on updates, so restore it every time - if (!setPinState(path, previousPinState, OCC::CfApiWrapper::NoRecurse)) { + if (!setPinState(handle, previousPinState, OCC::CfApiWrapper::NoRecurse)) { return {u"Couldn't restore pin state"_s}; } @@ -428,11 +427,10 @@ OCC::Result OCC::CfApiWrapper::unregisterSyncRoot(const VfsSetupP return {}; } -OCC::Result OCC::CfApiWrapper::connectSyncRoot(const QString &path, OCC::VfsCfApi *context) +OCC::Result OCC::CfApiWrapper::connectSyncRoot(const std::filesystem::path &path, OCC::VfsCfApi *context) { std::lock_guard lock(sRegister_mutex); CF_CONNECTION_KEY key; - const auto p = QDir::toNativeSeparators(path).toStdWString(); CF_CALLBACK_REGISTRATION cfApiCallbacks[] = {{CF_CALLBACK_TYPE_FETCH_DATA, cfApiFetchDataCallback}, // {CF_CALLBACK_TYPE_CANCEL_FETCH_DATA, cfApiCancelFetchData}, // @@ -444,8 +442,8 @@ OCC::Result OCC::CfApiWrapper::connectSyncRoot(const {CF_CALLBACK_TYPE_NOTIFY_RENAME_COMPLETION, cfApiRenameCompletion}, // CF_CALLBACK_REGISTRATION_END}; - const qint64 result = - CfConnectSyncRoot(p.data(), cfApiCallbacks, context, CF_CONNECT_FLAG_REQUIRE_PROCESS_INFO | CF_CONNECT_FLAG_REQUIRE_FULL_FILE_PATH | CF_CONNECT_FLAG_BLOCK_SELF_IMPLICIT_HYDRATION, &key); + const qint64 result = CfConnectSyncRoot(path.lexically_normal().c_str(), cfApiCallbacks, context, + CF_CONNECT_FLAG_REQUIRE_PROCESS_INFO | CF_CONNECT_FLAG_REQUIRE_FULL_FILE_PATH | CF_CONNECT_FLAG_BLOCK_SELF_IMPLICIT_HYDRATION, &key); Q_ASSERT(result == S_OK); if (result != S_OK) { return OCC::Utility::formatWinError(result); @@ -487,64 +485,50 @@ bool OCC::CfApiWrapper::isDehydratedPlaceholder(const FileSystem::Path &path) } template <> -OCC::CfApiWrapper::PlaceHolderInfo OCC::CfApiWrapper::findPlaceholderInfo(const QString &path, bool withFileIdentity) +OCC::CfApiWrapper::PlaceHolderInfo OCC::CfApiWrapper::findPlaceholderInfo(const Utility::Handle &handle, bool withFileIdentity) { - if (auto handle = OCC::Utility::Handle::createHandle(OCC::FileSystem::toFilesystemPath(path))) { - auto info = getPlaceholderInfo(handle, CF_PLACEHOLDER_INFO_BASIC, withFileIdentity); - if (!info || info->empty()) { - return {std::move(handle), {}}; - } - return PlaceHolderInfo(std::move(handle), std::move(*info)); + auto info = getPlaceholderInfo(handle, CF_PLACEHOLDER_INFO_BASIC, withFileIdentity); + if (!info || info->empty()) { + return {handle, {}}; } - return {}; + return PlaceHolderInfo(handle, std::move(*info)); } template <> -OCC::CfApiWrapper::PlaceHolderInfo OCC::CfApiWrapper::findPlaceholderInfo(const QString &path, bool withFileIdentity) +OCC::CfApiWrapper::PlaceHolderInfo OCC::CfApiWrapper::findPlaceholderInfo(const Utility::Handle &handle, bool withFileIdentity) { - if (auto handle = OCC::Utility::Handle::createHandle(OCC::FileSystem::toFilesystemPath(path))) { - auto info = getPlaceholderInfo(handle, CF_PLACEHOLDER_INFO_STANDARD, withFileIdentity); - if (!info || info->empty()) { - return {std::move(handle), {}}; - } - return PlaceHolderInfo(std::move(handle), std::move(*info)); + auto info = getPlaceholderInfo(handle, CF_PLACEHOLDER_INFO_STANDARD, withFileIdentity); + if (!info || info->empty()) { + return {handle, {}}; } - return {}; + return PlaceHolderInfo(handle, std::move(*info)); } - -OCC::Result OCC::CfApiWrapper::setPinState(const QString &path, OCC::PinState state, SetPinRecurseMode mode) +OCC::Result OCC::CfApiWrapper::setPinState( + const Utility::Handle &handle, OCC::PinState state, SetPinRecurseMode mode) { const auto cfState = pinStateToCfPinState(state); const auto flags = pinRecurseModeToCfSetPinFlags(mode); - auto handle = OCC::Utility::Handle::createHandle(OCC::FileSystem::toFilesystemPath(path)); - if (!handle) { - qCWarning(lcCfApiWrapper) << u"Couldn't create handle for pin state" << path << u":" << handle.errorMessage(); - return {u"Couldn't create handle for pin state: %s"_s.arg(handle.errorMessage())}; - } - const qint64 result = CfSetPinState(handle, cfState, flags, nullptr); if (result == S_OK) { return OCC::Vfs::ConvertToPlaceholderResult::Ok; } else { - qCWarning(lcCfApiWrapper) << u"Couldn't set pin state" << state << u"for" << path << u"with recurse mode" << mode << u":" + qCWarning(lcCfApiWrapper) << u"Couldn't set pin state" << state << u"for" << handle.path().native() << u"with recurse mode" << mode << u":" << OCC::Utility::formatWinError(result); return {u"Couldn't set pin state"_s}; } } -OCC::Result OCC::CfApiWrapper::createPlaceholderInfo(const QString &path, time_t modtime, qint64 size, const QByteArray &fileId) +OCC::Result OCC::CfApiWrapper::createPlaceholderInfo(const std::filesystem::path &path, time_t modtime, qint64 size, const QByteArray &fileId) { - const auto fileInfo = QFileInfo(path); - const auto localBasePath = QDir::toNativeSeparators(fileInfo.path()).toStdWString(); - const auto relativePath = fileInfo.fileName().toStdWString(); - + const auto fileName = path.filename(); + const auto baseDir = path.parent_path().lexically_normal(); CF_PLACEHOLDER_CREATE_INFO cloudEntry = {}; cloudEntry.FileIdentity = fileId.data(); cloudEntry.FileIdentityLength = static_cast(fileId.length()); - cloudEntry.RelativeFileName = relativePath.data(); + cloudEntry.RelativeFileName = fileName.c_str(); cloudEntry.Flags = CF_PLACEHOLDER_CREATE_FLAG_MARK_IN_SYNC; cloudEntry.FsMetadata.FileSize.QuadPart = size; cloudEntry.FsMetadata.BasicInfo.FileAttributes = FILE_ATTRIBUTE_NORMAL; @@ -553,23 +537,36 @@ OCC::Result OCC::CfApiWrapper::createPlaceholderInfo(const QStrin OCC::Utility::UnixTimeToLargeIntegerFiletime(modtime, &cloudEntry.FsMetadata.BasicInfo.LastAccessTime); OCC::Utility::UnixTimeToLargeIntegerFiletime(modtime, &cloudEntry.FsMetadata.BasicInfo.ChangeTime); - if (fileInfo.isDir()) { + if (std::filesystem::is_directory(path)) { cloudEntry.Flags |= CF_PLACEHOLDER_CREATE_FLAG_DISABLE_ON_DEMAND_POPULATION; cloudEntry.FsMetadata.BasicInfo.FileAttributes = FILE_ATTRIBUTE_DIRECTORY; cloudEntry.FsMetadata.FileSize.QuadPart = 0; } - qCDebug(lcCfApiWrapper) << u"CfCreatePlaceholders" << path << modtime; - const qint64 result = CfCreatePlaceholders(localBasePath.data(), &cloudEntry, 1, CF_CREATE_FLAG_NONE, nullptr); + qCDebug(lcCfApiWrapper) << u"CfCreatePlaceholders" << path.native() << modtime; + const qint64 result = CfCreatePlaceholders(baseDir.c_str(), &cloudEntry, 1, CF_CREATE_FLAG_NONE, nullptr); if (result != S_OK) { - qCWarning(lcCfApiWrapper) << u"Couldn't create placeholder info for" << path << u":" << Utility::formatWinError(result); + qCWarning(lcCfApiWrapper) << u"Couldn't create placeholder info for" << path.native() << u":" << Utility::formatWinError(result); return {u"Couldn't create placeholder info"_s}; } - const auto parentInfo = findPlaceholderInfo(QDir::toNativeSeparators(QFileInfo(path).absolutePath())); + const auto parentHandle = OCC::Utility::Handle::createHandle(baseDir); + if (!parentHandle) { + const QString errorMessage = u"Couldn't create handle for placeholder %1 Error: %2"_s.arg(parentHandle.path().native(), parentHandle.errorMessage()); + qCWarning(lcCfApiWrapper) << errorMessage; + return errorMessage; + } + const auto parentInfo = findPlaceholderInfo(parentHandle); + Q_ASSERT(parentInfo); const auto state = parentInfo && parentInfo.pinState() == PinState::OnlineOnly ? PinState::OnlineOnly : PinState::Inherited; - if (!setPinState(path, state, NoRecurse)) { + const auto handle = OCC::Utility::Handle::createHandle(baseDir); + if (!handle) { + const QString errorMessage = u"Couldn't create handle for placeholder %1 Error: %2"_s.arg(handle.path().native(), handle.errorMessage()); + qCWarning(lcCfApiWrapper) << errorMessage; + return errorMessage; + } + if (!setPinState(handle, state, NoRecurse)) { return {u"Couldn't set the default inherit pin state"_s}; } @@ -577,66 +574,48 @@ OCC::Result OCC::CfApiWrapper::createPlaceholderInfo(const QStrin } OCC::Result OCC::CfApiWrapper::updatePlaceholderInfo( - const QString &path, time_t modtime, qint64 size, const QByteArray &fileId, const QString &replacesPath, bool isHydrated) + const Utility::Handle &handle, time_t modtime, qint64 size, const QByteArray &fileId, const std::filesystem::path &replacesPath, bool isHydrated) { - return updatePlaceholderState(path, modtime, size, fileId, replacesPath, isHydrated); + return updatePlaceholderState(handle, modtime, size, fileId, replacesPath, isHydrated); } -OCC::Result OCC::CfApiWrapper::dehydratePlaceholder(const QString &path, const QByteArray &fileId) +OCC::Result OCC::CfApiWrapper::dehydratePlaceholder(const Utility::Handle &handle, const QByteArray &fileId) { - const auto info = findPlaceholderInfo(path); + const auto info = findPlaceholderInfo(handle); if (info) { - auto handle = Utility::Handle::createHandle(OCC::FileSystem::toFilesystemPath(path)); - if (!handle) { - const auto errorMessage = u"Couldn't create handle for placeholder %1 Error: %2"_s.arg(path, handle.errorMessage()); - qCWarning(lcCfApiWrapper) << errorMessage; - return errorMessage; - } const qint64 result = CfUpdatePlaceholder(handle, nullptr, fileId.data(), static_cast(fileId.size()), nullptr, 0, CF_UPDATE_FLAG_MARK_IN_SYNC | CF_UPDATE_FLAG_DEHYDRATE, nullptr, nullptr); if (result != S_OK) { - const auto errorMessage = u"Couldn't update placeholder info %1 Error: %2"_s.arg(path, OCC::Utility::formatWinError(result)); - qCWarning(lcCfApiWrapper) << errorMessage << path; - return errorMessage; - } - } else { - auto handle = Utility::Handle::createHandle(OCC::FileSystem::toFilesystemPath(path)); - if (!handle) { - const auto errorMessage = u"Couldn't create handle for placeholder %1 Error: %2"_s.arg(path, handle.errorMessage()); + const auto errorMessage = u"Couldn't update placeholder info %1 Error: %2"_s.arg(handle.path().native(), OCC::Utility::formatWinError(result)); qCWarning(lcCfApiWrapper) << errorMessage; return errorMessage; } + } else { const qint64 result = CfConvertToPlaceholder( handle, fileId.data(), static_cast(fileId.size()), CF_CONVERT_FLAG_MARK_IN_SYNC | CF_CONVERT_FLAG_DEHYDRATE, nullptr, nullptr); if (result != S_OK) { - const auto errorMessage = u"Couldn't convert to placeholder %1 Error: %2"_s.arg(path, OCC::Utility::formatWinError(result)); + const auto errorMessage = u"Couldn't convert to placeholder %1 Error: %2"_s.arg(handle.path().native(), OCC::Utility::formatWinError(result)); qCWarning(lcCfApiWrapper) << errorMessage; return errorMessage; } - setPinState(path, OCC::PinState::OnlineOnly, OCC::CfApiWrapper::NoRecurse); + setPinState(handle, OCC::PinState::OnlineOnly, OCC::CfApiWrapper::NoRecurse); } return OCC::Vfs::ConvertToPlaceholderResult::Ok; } OCC::Result OCC::CfApiWrapper::convertToPlaceholder( - const QString &path, time_t modtime, qint64 size, const QByteArray &fileId, const QString &replacesPath) + const Utility::Handle &handle, time_t modtime, qint64 size, const QByteArray &fileId, const std::filesystem::path &replacesPath) { - auto handle = Utility::Handle::createHandle(OCC::FileSystem::toFilesystemPath(path)); - if (!handle) { - const auto errorMessage = u"Couldn't create handle for placeholder %1 Error: %2"_s.arg(path, handle.errorMessage()); - qCWarning(lcCfApiWrapper) << errorMessage << path; - return errorMessage; - } const qint64 result = CfConvertToPlaceholder(handle, fileId.data(), static_cast(fileId.size()), CF_CONVERT_FLAG_MARK_IN_SYNC, nullptr, nullptr); Q_ASSERT(result == S_OK); if (result != S_OK) { - const auto errorMessage = u"Couldn't convert to placeholder %1 Error: %2"_s.arg(path, OCC::Utility::formatWinError(result)); - qCWarning(lcCfApiWrapper) << errorMessage << path; + const auto errorMessage = u"Couldn't convert to placeholder %1 Error: %2"_s.arg(handle.path().native(), OCC::Utility::formatWinError(result)); + qCWarning(lcCfApiWrapper) << errorMessage; return errorMessage; } // we are converting an existing file, so it must be hydrated - return updatePlaceholderState(path, modtime, size, fileId, replacesPath, true); + return updatePlaceholderState(handle, modtime, size, fileId, replacesPath, true); } OCC::Result OCC::CfApiWrapper::updatePlaceholderMarkInSync(const Utility::Handle &handle) @@ -653,9 +632,9 @@ OCC::Result OCC::CfApiWrapper::up } } -bool OCC::CfApiWrapper::isPlaceHolderInSync(const QString &filePath) +bool OCC::CfApiWrapper::isPlaceHolderInSync(const Utility::Handle &handle) { - if (const auto originalInfo = findPlaceholderInfo(filePath)) { + if (const auto originalInfo = findPlaceholderInfo(handle)) { return originalInfo->InSyncState == CF_IN_SYNC_STATE_IN_SYNC; } return true; diff --git a/src/plugins/vfs/cfapi/cfapiwrapper.h b/src/plugins/vfs/cfapi/cfapiwrapper.h index 528f7d2fce..378bc272c3 100644 --- a/src/plugins/vfs/cfapi/cfapiwrapper.h +++ b/src/plugins/vfs/cfapi/cfapiwrapper.h @@ -43,8 +43,8 @@ namespace CfApiWrapper { class PlaceHolderInfo { public: - PlaceHolderInfo(Utility::Handle &&handle = {}, const std::vector &&buffer = {}) - : _handle(std::move(handle)) + PlaceHolderInfo(const Utility::Handle &handle = {}, const std::vector &&buffer = {}) + : _handle(&handle) , _data(std::move(buffer)) { } @@ -84,10 +84,10 @@ namespace CfApiWrapper { Q_UNREACHABLE(); } - const Utility::Handle &handle() const { return _handle; } + const Utility::Handle &handle() const { return *_handle; } private: - Utility::Handle _handle; + const Utility::Handle *_handle; std::vector _data; }; @@ -95,7 +95,7 @@ namespace CfApiWrapper { // void unregisterSyncRootShellExtensions(const QString &providerName, const QString &folderAlias, const QString &accountDisplayName); Result unregisterSyncRoot(const VfsSetupParams ¶ms); - Result connectSyncRoot(const QString &path, VfsCfApi *context); + Result connectSyncRoot(const std::filesystem::path &path, VfsCfApi *context); Result disconnectSyncRoot(CF_CONNECTION_KEY &&key); bool isDehydratedPlaceholder(const FileSystem::Path &path); @@ -105,27 +105,27 @@ namespace CfApiWrapper { * If FileIdentity is required withFileIdentity must be set to true. */ template - PlaceHolderInfo findPlaceholderInfo(const QString &path, bool withFileIdentity = false) + PlaceHolderInfo findPlaceholderInfo(const Utility::Handle &handle, bool withFileIdentity = false) { } template <> - PlaceHolderInfo findPlaceholderInfo(const QString &path, bool withFileIdentity); + PlaceHolderInfo findPlaceholderInfo(const Utility::Handle &handle, bool withFileIdentity); template <> - PlaceHolderInfo findPlaceholderInfo(const QString &path, bool withFileIdentity); + PlaceHolderInfo findPlaceholderInfo(const Utility::Handle &handle, bool withFileIdentity); enum SetPinRecurseMode { NoRecurse = 0, Recurse, ChildrenOnly }; - Result setPinState(const QString &path, PinState state, SetPinRecurseMode mode); - Result createPlaceholderInfo(const QString &path, time_t modtime, qint64 size, const QByteArray &fileId); + Result setPinState(const Utility::Handle &handle, PinState state, SetPinRecurseMode mode); + Result createPlaceholderInfo(const std::filesystem::path &path, time_t modtime, qint64 size, const QByteArray &fileId); Result updatePlaceholderInfo( - const QString &path, time_t modtime, qint64 size, const QByteArray &fileId, const QString &replacesPath, bool isHydrated); + const Utility::Handle &handle, time_t modtime, qint64 size, const QByteArray &fileId, const std::filesystem::path &replacesPath, bool isHydrated); Result convertToPlaceholder( - const QString &path, time_t modtime, qint64 size, const QByteArray &fileId, const QString &replacesPath); - Result dehydratePlaceholder(const QString &path, const QByteArray &fileId); + const Utility::Handle &handle, time_t modtime, qint64 size, const QByteArray &fileId, const std::filesystem::path &replacesPath); + Result dehydratePlaceholder(const Utility::Handle &handle, const QByteArray &fileId); Result updatePlaceholderMarkInSync(const Utility::Handle &handle); - bool isPlaceHolderInSync(const QString &filePath); + bool isPlaceHolderInSync(const Utility::Handle &handle); } } // namespace OCC diff --git a/src/plugins/vfs/cfapi/vfs_cfapi.cpp b/src/plugins/vfs/cfapi/vfs_cfapi.cpp index 7ace9cc2e5..585867685e 100644 --- a/src/plugins/vfs/cfapi/vfs_cfapi.cpp +++ b/src/plugins/vfs/cfapi/vfs_cfapi.cpp @@ -118,7 +118,7 @@ void VfsCfApi::startImpl(const VfsSetupParams ¶ms) cfapi::registerSyncRoot(params, [this](const QString &errorMessage) { if (errorMessage.isEmpty()) { - auto connectResult = cfapi::connectSyncRoot(this->params().filesystemPath(), this); + auto connectResult = cfapi::connectSyncRoot(this->params().root(), this); if (!connectResult) { qCCritical(lcCfApi) << u"Initialization failed, couldn't connect sync root:" << connectResult.error(); return; @@ -181,38 +181,45 @@ bool VfsCfApi::socketApiPinStateActionsShown() const Result VfsCfApi::updateMetadata(const SyncFileItem &syncItem, const QString &filePath, const QString &replacesFile) { - const auto localPath = QDir::toNativeSeparators(filePath); - const auto replacesPath = QDir::toNativeSeparators(replacesFile); + const auto replacesPath = !replacesFile.isEmpty() ? FileSystem::toFilesystemPath(replacesFile) : std::filesystem::path{}; + const auto handle = OCC::Utility::Handle::createHandle(FileSystem::toFilesystemPath(filePath)); + if (!handle) { + const QString errorMessage = u"Couldn't create handle for placeholder %1 Error: %2"_s.arg(filePath, handle.errorMessage()); + qCWarning(lcCfApi) << errorMessage << replacesPath.native(); + return errorMessage; + } if (syncItem._type == ItemTypeVirtualFileDehydration) { - auto result = cfapi::dehydratePlaceholder(localPath, syncItem._fileId); + auto result = cfapi::dehydratePlaceholder(handle, syncItem._fileId); // if the dehydration call succeeded, check whether the placeholder is dehydrated Q_ASSERT(!result || isDehydratedPlaceholder(filePath)); return result; } else { - if (cfapi::findPlaceholderInfo(localPath)) { + if (cfapi::findPlaceholderInfo(handle)) { return cfapi::updatePlaceholderInfo( - localPath, syncItem._modtime, syncItem._size, syncItem._fileId, replacesPath, syncItem._type != ItemTypeVirtualFile); + handle, syncItem._modtime, syncItem._size, syncItem._fileId, replacesPath, syncItem._type != ItemTypeVirtualFile); } else { - return cfapi::convertToPlaceholder(localPath, syncItem._modtime, syncItem._size, syncItem._fileId, replacesPath); + return cfapi::convertToPlaceholder(handle, syncItem._modtime, syncItem._size, syncItem._fileId, replacesPath); } } } Result VfsCfApi::createPlaceholder(const SyncFileItem &item) { - const auto localPath = QDir::toNativeSeparators(params().filesystemPath() + item.localName()); - const auto result = cfapi::createPlaceholderInfo(localPath, item._modtime, item._size, item._fileId); - return result; + return cfapi::createPlaceholderInfo(params().root() / item.localName(), item._modtime, item._size, item._fileId); } bool VfsCfApi::needsMetadataUpdate(const SyncFileItem &item) { - const QString path = params().filesystemPath() + item.localName(); - if (!QFileInfo::exists(path)) { + const auto handle = OCC::Utility::Handle::createHandle(params().root() / item.localName()); + if (!handle) { + if (handle.error() == ERROR_FILE_NOT_FOUND || handle.error() == ERROR_PATH_NOT_FOUND) { + return false; + } + qCWarning(lcCfApi) << u"Couldn't create handle for placeholder" << handle.path().native() << u"Error:" << handle.errorMessage(); return false; } - return !cfapi::findPlaceholderInfo(path).isValid(); + return !cfapi::findPlaceholderInfo(handle).isValid(); } bool VfsCfApi::isDehydratedPlaceholder(const QString &filePath) @@ -225,10 +232,14 @@ LocalInfo VfsCfApi::statTypeVirtualFile(const std::filesystem::directory_entry & // only get placeholder info if it's a file if (type == ItemTypeFile) { const auto path = FileSystem::Path(entry); - if (auto placeholderInfo = cfapi::findPlaceholderInfo(path.toString())) { - Q_ASSERT(placeholderInfo.handle()); + const auto handle = OCC::Utility::Handle::createHandle(path); + if (!handle) { + qCWarning(lcCfApi) << u"Couldn't create handle for placeholder" << path; + return {}; + } + if (auto placeholderInfo = cfapi::findPlaceholderInfo(handle)) { FILE_ATTRIBUTE_TAG_INFO attributeInfo = {}; - if (!GetFileInformationByHandleEx(placeholderInfo.handle(), FileAttributeTagInfo, &attributeInfo, sizeof(attributeInfo))) { + if (!GetFileInformationByHandleEx(handle, FileAttributeTagInfo, &attributeInfo, sizeof(attributeInfo))) { const auto error = GetLastError(); qCCritical(lcCfApi) << u"GetFileInformationByHandle failed on" << path << OCC::Utility::formatWinError(error); return {}; @@ -261,14 +272,24 @@ bool VfsCfApi::setPinState(const QString &folderPath, PinState state) { qCDebug(lcCfApi) << u"setPinState" << folderPath << state; - const auto localPath = QDir::toNativeSeparators(params().filesystemPath() + folderPath); - return static_cast(cfapi::setPinState(localPath, state, cfapi::Recurse)); + const auto localPath = params().root() / folderPath; + const auto handle = OCC::Utility::Handle::createHandle(localPath); + if (!handle) { + qCWarning(lcCfApi) << u"Couldn't create handle for placeholder" << localPath; + return false; + } + return static_cast(cfapi::setPinState(handle, state, cfapi::Recurse)); } Optional VfsCfApi::pinState(const QString &folderPath) { - const auto localPath = QDir::toNativeSeparators(params().filesystemPath() + folderPath); - const auto info = cfapi::findPlaceholderInfo(localPath); + const auto localPath = params().root() / folderPath; + const auto handle = OCC::Utility::Handle::createHandle(localPath); + if (!handle) { + qCWarning(lcCfApi) << u"Couldn't create handle for placeholder" << localPath; + return {}; + } + const auto info = cfapi::findPlaceholderInfo(handle); if (!info) { qCDebug(lcCfApi) << u"Couldn't find pin state for regular non-placeholder file" << localPath; return {}; @@ -315,20 +336,25 @@ void VfsCfApi::cancelHydration(const OCC::CfApiWrapper::CallBackContext &context void VfsCfApi::fileStatusChanged(const QString &systemFileName, SyncFileStatus fileStatus) { - if (!QFileInfo::exists(systemFileName)) { + const auto handle = OCC::Utility::Handle::createHandle(FileSystem::toFilesystemPath(systemFileName)); + if (!handle) { + if (handle.error() == ERROR_FILE_NOT_FOUND || handle.error() == ERROR_PATH_NOT_FOUND) { + return; + } + qCWarning(lcCfApi) << u"Couldn't create handle for placeholder" << handle.path().native() << u"Error:" << handle.errorMessage(); return; } if (fileStatus.tag() == SyncFileStatus::StatusUpToDate) { - if (auto info = CfApiWrapper::findPlaceholderInfo(systemFileName)) { + if (auto info = CfApiWrapper::findPlaceholderInfo(handle)) { std::ignore = cfapi::updatePlaceholderMarkInSync(info.handle()); if (info.pinState() == PinState::Excluded) { // clear possible exclude flag // a file usually does not change from excluded to not excluded, but ... - cfapi::setPinState(systemFileName, PinState::Inherited, CfApiWrapper::Recurse); + cfapi::setPinState(handle, PinState::Inherited, CfApiWrapper::Recurse); } } } else if (fileStatus.tag() == SyncFileStatus::StatusExcluded) { - cfapi::setPinState(systemFileName, PinState::Excluded, CfApiWrapper::Recurse); + cfapi::setPinState(handle, PinState::Excluded, CfApiWrapper::Recurse); } }