diff --git a/src/libsync/path.cpp b/src/libsync/path.cpp index bdb57b6bc..8f0916f57 100644 --- a/src/libsync/path.cpp +++ b/src/libsync/path.cpp @@ -46,3 +46,8 @@ bool OCC::FileSystem::Path::exists() const } return exists; } + +QDebug operator<<(QDebug debug, const OCC::FileSystem::Path &path) +{ + return debug << u"Path(" << path.toString() << u")"; +} diff --git a/src/libsync/path.h b/src/libsync/path.h index 5d53cfe86..c52dd2c2f 100644 --- a/src/libsync/path.h +++ b/src/libsync/path.h @@ -74,3 +74,6 @@ namespace FileSystem { }; } } + + +OPENCLOUD_SYNC_EXPORT QDebug operator<<(QDebug debug, const OCC::FileSystem::Path &path); diff --git a/src/plugins/vfs/cfapi/cfapiwrapper.cpp b/src/plugins/vfs/cfapi/cfapiwrapper.cpp index 5a89ad0c9..98869e8db 100644 --- a/src/plugins/vfs/cfapi/cfapiwrapper.cpp +++ b/src/plugins/vfs/cfapi/cfapiwrapper.cpp @@ -476,13 +476,24 @@ OCC::Result OCC::CfApiWrapper::disconnectSyncRoot(CF_CONNECTION_K return {}; } } - - -bool OCC::CfApiWrapper::isSparseFile(const QString &path) +bool OCC::CfApiWrapper::isDehydratedPlaceholder(const FileSystem::Path &path) { - const auto p = path.toStdWString(); - const auto attributes = GetFileAttributes(p.data()); - return (attributes & FILE_ATTRIBUTE_SPARSE_FILE) != 0; + const auto handle = OCC::Utility::Handle::createHandle(path); + if (!handle) { + qCWarning(lcCfApiWrapper) << u"Failed to get file handle" << path << handle.errorMessage(); + return false; + } + FILE_ATTRIBUTE_TAG_INFO targInfo = {}; + if (!GetFileInformationByHandleEx(handle, FileAttributeTagInfo, &targInfo, sizeof(targInfo))) { + const auto error = GetLastError(); + qCWarning(lcCfApiWrapper) << u"Failed to get file attribute tag info for" << path << OCC::Utility::formatWinError(error); + return false; + } + const CF_PLACEHOLDER_STATE state = CfGetPlaceholderStateFromAttributeTag(targInfo.FileAttributes, targInfo.ReparseTag); + if (state == CF_PLACEHOLDER_STATE_NO_STATES) { + return false; + } + return state & CF_PLACEHOLDER_STATE_PARTIAL; } template <> @@ -575,17 +586,12 @@ OCC::Result OCC::CfApiWrapper::up return updatePlaceholderState(path, modtime, size, fileId, replacesPath); } -OCC::Result OCC::CfApiWrapper::dehydratePlaceholder(const QString &path, qint64 size, const QByteArray &fileId) +OCC::Result OCC::CfApiWrapper::dehydratePlaceholder(const QString &path, const QByteArray &fileId) { const auto info = findPlaceholderInfo(path); if (info) { - setPinState(path, OCC::PinState::OnlineOnly, OCC::CfApiWrapper::NoRecurse); - - CF_FILE_RANGE dehydrationRange = {}; - dehydrationRange.Length.QuadPart = size; - const qint64 result = CfUpdatePlaceholder(Utility::Handle::createHandle(OCC::FileSystem::toFilesystemPath(path)), nullptr, fileId.data(), - static_cast(fileId.size()), &dehydrationRange, 1, CF_UPDATE_FLAG_MARK_IN_SYNC | CF_UPDATE_FLAG_DEHYDRATE, nullptr, nullptr); + 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 = createErrorMessageForPlaceholderUpdateAndCreate(path, u"Couldn't update placeholder info"_s); qCWarning(lcCfApiWrapper) << errorMessage << path << u":" << OCC::Utility::formatWinError(result); @@ -600,8 +606,8 @@ OCC::Result OCC::CfApiWrapper::de qCWarning(lcCfApiWrapper) << errorMessage << path << u":" << OCC::Utility::formatWinError(result); return errorMessage; } + setPinState(path, OCC::PinState::OnlineOnly, OCC::CfApiWrapper::NoRecurse); } - return OCC::Vfs::ConvertToPlaceholderResult::Ok; } diff --git a/src/plugins/vfs/cfapi/cfapiwrapper.h b/src/plugins/vfs/cfapi/cfapiwrapper.h index b3e49fd6c..df68148d9 100644 --- a/src/plugins/vfs/cfapi/cfapiwrapper.h +++ b/src/plugins/vfs/cfapi/cfapiwrapper.h @@ -98,7 +98,7 @@ namespace CfApiWrapper { Result connectSyncRoot(const QString &path, VfsCfApi *context); Result disconnectSyncRoot(CF_CONNECTION_KEY &&key); - bool isSparseFile(const QString &path); + bool isDehydratedPlaceholder(const FileSystem::Path &path); /** * The placeholder info can have a dynamic size, by default we don't query FileIdentity @@ -123,7 +123,7 @@ namespace CfApiWrapper { const QString &path, time_t modtime, qint64 size, const QByteArray &fileId, const QString &replacesPath = QString()); Result convertToPlaceholder( const QString &path, time_t modtime, qint64 size, const QByteArray &fileId, const QString &replacesPath); - Result dehydratePlaceholder(const QString &path, qint64 size, const QByteArray &fileId); + Result dehydratePlaceholder(const QString &path, const QByteArray &fileId); Result updatePlaceholderMarkInSync(const Utility::Handle &handle); bool isPlaceHolderInSync(const QString &filePath); } diff --git a/src/plugins/vfs/cfapi/vfs_cfapi.cpp b/src/plugins/vfs/cfapi/vfs_cfapi.cpp index 666fc410e..5c1dae996 100644 --- a/src/plugins/vfs/cfapi/vfs_cfapi.cpp +++ b/src/plugins/vfs/cfapi/vfs_cfapi.cpp @@ -134,7 +134,7 @@ void VfsCfApi::startImpl(const VfsSetupParams ¶ms) }); } -Result CfApiVfsPluginFactory::prepare(const QString &path, const QUuid &accountUuid) const +Result CfApiVfsPluginFactory::prepare(const QString &path, const QUuid &) const { if (QDir(path).isRoot()) { return tr("The Virtual filesystem feature does not support a drive as sync root"); @@ -185,7 +185,10 @@ Result VfsCfApi::updateMetadata(const const auto replacesPath = QDir::toNativeSeparators(replacesFile); if (syncItem._type == ItemTypeVirtualFileDehydration) { - return cfapi::dehydratePlaceholder(localPath, syncItem._size, syncItem._fileId); + auto result = cfapi::dehydratePlaceholder(localPath, 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)) { return cfapi::updatePlaceholderInfo(localPath, syncItem._modtime, syncItem._size, syncItem._fileId, replacesPath); @@ -213,20 +216,20 @@ bool VfsCfApi::needsMetadataUpdate(const SyncFileItem &item) bool VfsCfApi::isDehydratedPlaceholder(const QString &filePath) { - const auto path = QDir::toNativeSeparators(filePath); - return cfapi::isSparseFile(path); + return cfapi::isDehydratedPlaceholder(FileSystem::Path(filePath)); } -LocalInfo VfsCfApi::statTypeVirtualFile(const std::filesystem::directory_entry &path, ItemType type) +LocalInfo VfsCfApi::statTypeVirtualFile(const std::filesystem::directory_entry &entry, ItemType type) { // only get placeholder info if it's a file if (type == ItemTypeFile) { - if (auto placeholderInfo = cfapi::findPlaceholderInfo(FileSystem::fromFilesystemPath(path))) { + const auto path = FileSystem::Path(entry); + if (auto placeholderInfo = cfapi::findPlaceholderInfo(path.toString())) { Q_ASSERT(placeholderInfo.handle()); FILE_ATTRIBUTE_TAG_INFO attributeInfo = {}; if (!GetFileInformationByHandleEx(placeholderInfo.handle(), FileAttributeTagInfo, &attributeInfo, sizeof(attributeInfo))) { const auto error = GetLastError(); - qCCritical(lcCfApi) << u"GetFileInformationByHandle failed on" << path.path() << OCC::Utility::formatWinError(error); + qCCritical(lcCfApi) << u"GetFileInformationByHandle failed on" << path << OCC::Utility::formatWinError(error); return {}; } const CF_PLACEHOLDER_STATE placeholderState = CfGetPlaceholderStateFromAttributeTag(attributeInfo.FileAttributes, attributeInfo.ReparseTag); @@ -250,7 +253,7 @@ LocalInfo VfsCfApi::statTypeVirtualFile(const std::filesystem::directory_entry & } } } - return LocalInfo(path, type); + return LocalInfo(entry, type); } bool VfsCfApi::setPinState(const QString &folderPath, PinState state) diff --git a/src/plugins/vfs/cfapi/vfs_cfapi.h b/src/plugins/vfs/cfapi/vfs_cfapi.h index 80962318b..161443f02 100644 --- a/src/plugins/vfs/cfapi/vfs_cfapi.h +++ b/src/plugins/vfs/cfapi/vfs_cfapi.h @@ -58,7 +58,7 @@ class VfsCfApi : public Vfs void cancelHydration(const OCC::CfApiWrapper::CallBackContext &context); - LocalInfo statTypeVirtualFile(const std::filesystem::directory_entry &path, ItemType type) override; + LocalInfo statTypeVirtualFile(const std::filesystem::directory_entry &entry, ItemType type) override; public Q_SLOTS: void fileStatusChanged(const QString &systemFileName, OCC::SyncFileStatus fileStatus) override; diff --git a/src/plugins/vfs/xattr/vfs_xattr.cpp b/src/plugins/vfs/xattr/vfs_xattr.cpp index eab625bf5..f6496419d 100644 --- a/src/plugins/vfs/xattr/vfs_xattr.cpp +++ b/src/plugins/vfs/xattr/vfs_xattr.cpp @@ -66,7 +66,7 @@ OpenVfsAttributes::PlaceHolderAttributes placeHolderAttributes(const std::filesy { const auto data = OCC::FileSystem::Xattr::getxattr(path, QString::fromUtf8(OpenVfsConstants::XAttributeNames::Data)); if (!data) { - qCWarning(lcVfsXAttr) << "No OpenVFS xattr found for" << path; + qCWarning(lcVfsXAttr) << u"No OpenVFS xattr found for" << path.native(); } return OpenVfsAttributes::PlaceHolderAttributes::fromData(path, data ? std::vector{data->cbegin(), data->cend()} : std::vector{}); } @@ -388,7 +388,7 @@ void VfsXAttr::slotHydrateJobFinished() const auto targetPath = FileSystem::toFilesystemPath(hydration->targetFileName()); Q_ASSERT(!targetPath.empty()); - qCInfo(lcVfsXAttr) << u"Hydration Job finished for" << targetPath; + qCInfo(lcVfsXAttr) << u"Hydration Job finished for" << targetPath.native(); if (std::filesystem::exists(targetPath)) { auto item = OCC::SyncFileItem::fromSyncJournalFileRecord(hydration->record()); @@ -398,17 +398,17 @@ void VfsXAttr::slotHydrateJobFinished() if (auto inode = FileSystem::getInode(targetPath)) { item->_inode = inode.value(); } else { - qCWarning(lcVfsXAttr) << u"Failed to get inode for" << targetPath; + qCWarning(lcVfsXAttr) << u"Failed to get inode for" << targetPath.native(); } // Update the client sync journal database if the file modifications have been successful const auto result = this->params().journal->setFileRecord(SyncJournalFileRecord::fromSyncFileItem(*item)); if (!result) { qCWarning(lcVfsXAttr) << u"Error when setting the file record to the database" << result.error(); } else { - qCInfo(lcVfsXAttr) << u"Hydration succeeded" << targetPath; + qCInfo(lcVfsXAttr) << u"Hydration succeeded" << targetPath.native(); } } else { - qCWarning(lcVfsXAttr) << u"Hydration succeeded but the file appears to be moved" << targetPath; + qCWarning(lcVfsXAttr) << u"Hydration succeeded but the file appears to be moved" << targetPath.native(); } hydration->deleteLater(); diff --git a/test/testutility.cpp b/test/testutility.cpp index e4beeed04..945441dfe 100644 --- a/test/testutility.cpp +++ b/test/testutility.cpp @@ -383,7 +383,7 @@ private Q_SLOTS: if (SUCCEEDED(hres)) { hres = ppf->Save(target.native().data(), true); if (SUCCEEDED(hres)) { - qDebug() << u"Created lnk" << target << u"->" << path; + qDebug() << u"Created lnk" << target.native() << u"->" << path; } else { qCritical() << u"Failed to create lnk: Save" << OCC::Utility::formatWinError(hres); }