mirror of
https://github.com/nextcloud/desktop.git
synced 2025-10-26 11:17:43 +00:00
Fix CF_PLACEHOLDER_BASIC_INFO.FileIdentity
Signed-off-by: Matthieu Gallien <matthieu.gallien@nextcloud.com> Signed-off-by: Hannah von Reth <h.vonreth@opencloud.eu>
This commit is contained in:
parent
c139f91145
commit
4d2966771d
@ -27,6 +27,7 @@
|
||||
#include "config.h"
|
||||
|
||||
Q_LOGGING_CATEGORY(lcCfApiWrapper, "nextcloud.sync.vfs.cfapi.wrapper", QtInfoMsg)
|
||||
using namespace Qt::Literals::StringLiterals;
|
||||
|
||||
#define FIELD_SIZE( type, field ) ( sizeof( ( (type*)0 )->field ) )
|
||||
#define CF_SIZE_OF_OP_PARAM( field ) \
|
||||
@ -34,6 +35,7 @@ Q_LOGGING_CATEGORY(lcCfApiWrapper, "nextcloud.sync.vfs.cfapi.wrapper", QtInfoMsg
|
||||
FIELD_SIZE( CF_OPERATION_PARAMETERS, field ) )
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr auto syncRootFlagsFull = 34;
|
||||
constexpr auto syncRootFlagsNoCfApiContextMenu = 2;
|
||||
|
||||
@ -41,6 +43,9 @@ constexpr auto syncRootManagerRegKey = R"(SOFTWARE\Microsoft\Windows\CurrentVers
|
||||
|
||||
constexpr auto forbiddenLeadingCharacterInPath = "#";
|
||||
|
||||
}
|
||||
|
||||
|
||||
QString createErrorMessageForPlaceholderUpdateAndCreate(const QString &path, const QString &originalErrorMessage)
|
||||
{
|
||||
const auto pathFromNativeSeparators = QDir::fromNativeSeparators(path);
|
||||
@ -304,47 +309,44 @@ OCC::Result<OCC::Vfs::ConvertToPlaceholderResult, QString> updatePlaceholderStat
|
||||
CfApiUpdateMetadataType updateType)
|
||||
{
|
||||
if (updateType == CfApiUpdateMetadataType::AllMetadata && modtime <= 0) {
|
||||
return {QString{"Could not update metadata due to invalid modification time for %1: %2"}.arg(path).arg(modtime)};
|
||||
}
|
||||
return {QString{"Could not update metadata due to invalid modification time for %1: %2"}.arg(path).arg(modtime)};
|
||||
}
|
||||
|
||||
const auto info = replacesPath.isEmpty() ? OCC::CfApiWrapper::findPlaceholderInfo(path)
|
||||
: OCC::CfApiWrapper::findPlaceholderInfo(replacesPath);
|
||||
if (!info) {
|
||||
return { "Can't update non existing placeholder info" };
|
||||
}
|
||||
const auto info = replacesPath.isEmpty() ? OCC::CfApiWrapper::findPlaceholderInfo(path)
|
||||
: OCC::CfApiWrapper::findPlaceholderInfo(replacesPath);
|
||||
if (!info) {
|
||||
return { "Can't update non existing placeholder info" };
|
||||
}
|
||||
|
||||
const auto previousPinState = cfPinStateToPinState(info->PinState);
|
||||
const auto fileIdentity = QString::fromUtf8(fileId).toStdWString();
|
||||
const auto fileIdentitySize = (fileIdentity.length() + 1) * sizeof(wchar_t);
|
||||
const auto previousPinState = cfPinStateToPinState(info->PinState);
|
||||
|
||||
CF_FS_METADATA metadata;
|
||||
metadata.FileSize.QuadPart = size;
|
||||
OCC::Utility::UnixTimeToLargeIntegerFiletime(modtime, &metadata.BasicInfo.CreationTime);
|
||||
OCC::Utility::UnixTimeToLargeIntegerFiletime(modtime, &metadata.BasicInfo.LastWriteTime);
|
||||
OCC::Utility::UnixTimeToLargeIntegerFiletime(modtime, &metadata.BasicInfo.LastAccessTime);
|
||||
OCC::Utility::UnixTimeToLargeIntegerFiletime(modtime, &metadata.BasicInfo.ChangeTime);
|
||||
metadata.BasicInfo.FileAttributes = 0;
|
||||
CF_FS_METADATA metadata;
|
||||
metadata.FileSize.QuadPart = size;
|
||||
OCC::Utility::UnixTimeToLargeIntegerFiletime(modtime, &metadata.BasicInfo.CreationTime);
|
||||
OCC::Utility::UnixTimeToLargeIntegerFiletime(modtime, &metadata.BasicInfo.LastWriteTime);
|
||||
OCC::Utility::UnixTimeToLargeIntegerFiletime(modtime, &metadata.BasicInfo.LastAccessTime);
|
||||
OCC::Utility::UnixTimeToLargeIntegerFiletime(modtime, &metadata.BasicInfo.ChangeTime);
|
||||
metadata.BasicInfo.FileAttributes = 0;
|
||||
|
||||
OCC::CfApiWrapper::setPinState(path, OCC::PinState::Unspecified, OCC::CfApiWrapper::SetPinRecurseMode::NoRecurse);
|
||||
OCC::CfApiWrapper::setPinState(path, OCC::PinState::Unspecified, OCC::CfApiWrapper::SetPinRecurseMode::NoRecurse);
|
||||
|
||||
qCInfo(lcCfApiWrapper) << "updatePlaceholderState" << path << modtime;
|
||||
const qint64 result = CfUpdatePlaceholder(OCC::CfApiWrapper::handleForPath(path).get(), updateType == CfApiUpdateMetadataType::AllMetadata ? &metadata : nullptr,
|
||||
fileIdentity.data(), sizeToDWORD(fileIdentitySize),
|
||||
nullptr, 0, CF_UPDATE_FLAG_MARK_IN_SYNC, nullptr, nullptr);
|
||||
qCInfo(lcCfApiWrapper) << "updatePlaceholderState" << path << modtime;
|
||||
const qint64 result =
|
||||
CfUpdatePlaceholder(OCC::CfApiWrapper::handleForPath(path).get(), updateType == CfApiUpdateMetadataType::AllMetadata ? &metadata : nullptr,
|
||||
fileId.data(), static_cast<DWORD>(fileId.size()), nullptr, 0, CF_UPDATE_FLAG_MARK_IN_SYNC, nullptr, nullptr);
|
||||
|
||||
if (result != S_OK) {
|
||||
const auto errorMessage = createErrorMessageForPlaceholderUpdateAndCreate(path, "Couldn't update placeholder info");
|
||||
qCWarning(lcCfApiWrapper) << errorMessage << path << ":" << QString::fromWCharArray(_com_error(result).ErrorMessage()) << replacesPath;
|
||||
return errorMessage;
|
||||
}
|
||||
if (result != S_OK) {
|
||||
const auto errorMessage = createErrorMessageForPlaceholderUpdateAndCreate(path, "Couldn't update placeholder info");
|
||||
qCWarning(lcCfApiWrapper) << errorMessage << path << ":" << QString::fromWCharArray(_com_error(result).ErrorMessage()) << replacesPath;
|
||||
return errorMessage;
|
||||
}
|
||||
|
||||
// Pin state tends to be lost on updates, so restore it every time
|
||||
if (!setPinState(path, previousPinState, OCC::CfApiWrapper::NoRecurse)) {
|
||||
return { "Couldn't restore pin state" };
|
||||
}
|
||||
// Pin state tends to be lost on updates, so restore it every time
|
||||
if (!setPinState(path, previousPinState, OCC::CfApiWrapper::NoRecurse)) {
|
||||
return { "Couldn't restore pin state" };
|
||||
}
|
||||
|
||||
return OCC::Vfs::ConvertToPlaceholderResult::Ok;
|
||||
}
|
||||
return OCC::Vfs::ConvertToPlaceholderResult::Ok;
|
||||
}
|
||||
|
||||
void CALLBACK cfApiCancelFetchData(const CF_CALLBACK_INFO *callbackInfo, const CF_CALLBACK_PARAMETERS * /*callbackParameters*/)
|
||||
@ -433,11 +435,6 @@ CF_CALLBACK_REGISTRATION cfApiCallbacks[] = {
|
||||
CF_CALLBACK_REGISTRATION_END
|
||||
};
|
||||
|
||||
void deletePlaceholderInfo(CF_PLACEHOLDER_BASIC_INFO *info)
|
||||
{
|
||||
auto byte = reinterpret_cast<char *>(info);
|
||||
delete[] byte;
|
||||
}
|
||||
|
||||
std::wstring pathForHandle(const OCC::CfApiWrapper::FileHandle &handle)
|
||||
{
|
||||
@ -496,24 +493,18 @@ OCC::CfApiWrapper::FileHandle::FileHandle(void *data, Deleter deleter)
|
||||
{
|
||||
}
|
||||
|
||||
OCC::CfApiWrapper::PlaceHolderInfo::PlaceHolderInfo()
|
||||
: _data(nullptr, [](CF_PLACEHOLDER_BASIC_INFO *) {})
|
||||
{
|
||||
}
|
||||
|
||||
OCC::CfApiWrapper::PlaceHolderInfo::PlaceHolderInfo(CF_PLACEHOLDER_BASIC_INFO *data, Deleter deleter)
|
||||
: _data(data, deleter)
|
||||
OCC::CfApiWrapper::PlaceHolderInfo::PlaceHolderInfo(std::vector<char> &&buffer)
|
||||
: _data(buffer)
|
||||
{
|
||||
}
|
||||
|
||||
OCC::Optional<OCC::PinState> OCC::CfApiWrapper::PlaceHolderInfo::pinState() const
|
||||
{
|
||||
Q_ASSERT(_data);
|
||||
if (!_data) {
|
||||
if (!this) {
|
||||
return {};
|
||||
}
|
||||
|
||||
return cfPinStateToPinState(_data->PinState);
|
||||
return cfPinStateToPinState(get()->PinState);
|
||||
}
|
||||
|
||||
QString convertSidToStringSid(void *sid)
|
||||
@ -665,7 +656,7 @@ OCC::Result<void, QString> OCC::CfApiWrapper::registerSyncRoot(const QString &pa
|
||||
const auto name = std::wstring(providerName.toStdWString().data());
|
||||
const auto version = std::wstring(providerVersion.toStdWString().data());
|
||||
|
||||
CF_SYNC_REGISTRATION info;
|
||||
CF_SYNC_REGISTRATION info = {};
|
||||
info.StructSize = static_cast<ULONG>(sizeof(info) + (name.length() + version.length()) * sizeof(wchar_t));
|
||||
info.ProviderName = name.data();
|
||||
info.ProviderVersion = version.data();
|
||||
@ -829,16 +820,22 @@ OCC::CfApiWrapper::FileHandle OCC::CfApiWrapper::handleForPath(const QString &pa
|
||||
|
||||
OCC::CfApiWrapper::PlaceHolderInfo OCC::CfApiWrapper::findPlaceholderInfo(const QString &path)
|
||||
{
|
||||
constexpr auto fileIdMaxLength = 128;
|
||||
const auto infoSize = sizeof(CF_PLACEHOLDER_BASIC_INFO) + fileIdMaxLength;
|
||||
auto info = PlaceHolderInfo(reinterpret_cast<CF_PLACEHOLDER_BASIC_INFO *>(new char[infoSize]), deletePlaceholderInfo);
|
||||
const qint64 result = CfGetPlaceholderInfo(handleForPath(path).get(), CF_PLACEHOLDER_INFO_BASIC, info.get(), sizeToDWORD(infoSize), nullptr);
|
||||
|
||||
if (result == S_OK) {
|
||||
return info;
|
||||
} else {
|
||||
return {};
|
||||
if (auto handle = handleForPath(path)) {
|
||||
std::vector<char> buffer(512);
|
||||
DWORD actualSize = {};
|
||||
const qint64 result = CfGetPlaceholderInfo(handle.get(), CF_PLACEHOLDER_INFO_BASIC, buffer.data(), static_cast<DWORD>(buffer.size()), &actualSize);
|
||||
if (result == S_OK) {
|
||||
buffer.resize(actualSize);
|
||||
return PlaceHolderInfo(std::move(buffer));
|
||||
} else if (result == HRESULT_FROM_WIN32(ERROR_NOT_A_CLOUD_FILE)) {
|
||||
// native file, not yet converted
|
||||
return {};
|
||||
} else {
|
||||
qCWarning(lcCfApiWrapper) << "Failed to retrieve placeholder info:" << Utility::formatWinError(result);
|
||||
Q_ASSERT(false);
|
||||
}
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
OCC::Result<OCC::Vfs::ConvertToPlaceholderResult, QString> OCC::CfApiWrapper::setPinState(const QString &path, OCC::PinState state, SetPinRecurseMode mode)
|
||||
@ -865,12 +862,9 @@ OCC::Result<void, QString> OCC::CfApiWrapper::createPlaceholderInfo(const QStrin
|
||||
const auto localBasePath = QDir::toNativeSeparators(fileInfo.path()).toStdWString();
|
||||
const auto relativePath = fileInfo.fileName().toStdWString();
|
||||
|
||||
const auto fileIdentity = QString::fromUtf8(fileId).toStdWString();
|
||||
|
||||
CF_PLACEHOLDER_CREATE_INFO cloudEntry;
|
||||
cloudEntry.FileIdentity = fileIdentity.data();
|
||||
const auto fileIdentitySize = (fileIdentity.length() + 1) * sizeof(wchar_t);
|
||||
cloudEntry.FileIdentityLength = sizeToDWORD(fileIdentitySize);
|
||||
CF_PLACEHOLDER_CREATE_INFO cloudEntry = {};
|
||||
cloudEntry.FileIdentity = fileId.data();
|
||||
cloudEntry.FileIdentityLength = static_cast<DWORD>(fileId.length());
|
||||
|
||||
cloudEntry.RelativeFileName = relativePath.data();
|
||||
cloudEntry.Flags = CF_PLACEHOLDER_CREATE_FLAG_MARK_IN_SYNC;
|
||||
@ -915,9 +909,6 @@ OCC::Result<OCC::Vfs::ConvertToPlaceholderResult, QString> OCC::CfApiWrapper::de
|
||||
return {QString{"Could not update metadata due to invalid modification time for %1: %2"}.arg(path).arg(modtime)};
|
||||
}
|
||||
|
||||
const auto fileIdentity = QString::fromUtf8(fileId).toStdWString();
|
||||
const auto fileIdentitySize = (fileIdentity.length() + 1) * sizeof(wchar_t);
|
||||
|
||||
const auto info = findPlaceholderInfo(path);
|
||||
if (info) {
|
||||
setPinState(path, OCC::PinState::OnlineOnly, OCC::CfApiWrapper::NoRecurse);
|
||||
@ -926,27 +917,16 @@ OCC::Result<OCC::Vfs::ConvertToPlaceholderResult, QString> OCC::CfApiWrapper::de
|
||||
dehydrationRange.StartingOffset.QuadPart = 0;
|
||||
dehydrationRange.Length.QuadPart = size;
|
||||
|
||||
const qint64 result = CfUpdatePlaceholder(handleForPath(path).get(),
|
||||
nullptr,
|
||||
fileIdentity.data(),
|
||||
sizeToDWORD(fileIdentitySize),
|
||||
&dehydrationRange,
|
||||
1,
|
||||
CF_UPDATE_FLAG_MARK_IN_SYNC | CF_UPDATE_FLAG_DEHYDRATE,
|
||||
nullptr,
|
||||
nullptr);
|
||||
const qint64 result = CfUpdatePlaceholder(handleForPath(path).get(), nullptr, fileId.data(), static_cast<DWORD>(fileId.size()), &dehydrationRange, 1,
|
||||
CF_UPDATE_FLAG_MARK_IN_SYNC | CF_UPDATE_FLAG_DEHYDRATE, nullptr, nullptr);
|
||||
if (result != S_OK) {
|
||||
const auto errorMessage = createErrorMessageForPlaceholderUpdateAndCreate(path, "Couldn't update placeholder info");
|
||||
qCWarning(lcCfApiWrapper) << errorMessage << path << ":" << QString::fromWCharArray(_com_error(result).ErrorMessage());
|
||||
return errorMessage;
|
||||
}
|
||||
} else {
|
||||
const qint64 result = CfConvertToPlaceholder(handleForPath(path).get(),
|
||||
fileIdentity.data(),
|
||||
sizeToDWORD(fileIdentitySize),
|
||||
CF_CONVERT_FLAG_MARK_IN_SYNC | CF_CONVERT_FLAG_DEHYDRATE,
|
||||
nullptr,
|
||||
nullptr);
|
||||
const qint64 result = CfConvertToPlaceholder(handleForPath(path).get(), fileId.data(), static_cast<DWORD>(fileId.size()),
|
||||
CF_CONVERT_FLAG_MARK_IN_SYNC | CF_CONVERT_FLAG_DEHYDRATE, nullptr, nullptr);
|
||||
|
||||
if (result != S_OK) {
|
||||
const auto errorMessage = createErrorMessageForPlaceholderUpdateAndCreate(path, "Couldn't convert to placeholder");
|
||||
@ -963,9 +943,8 @@ OCC::Result<OCC::Vfs::ConvertToPlaceholderResult, QString> OCC::CfApiWrapper::co
|
||||
Q_UNUSED(modtime);
|
||||
Q_UNUSED(size);
|
||||
|
||||
const auto fileIdentity = QString::fromUtf8(fileId).toStdWString();
|
||||
const auto fileIdentitySize = (fileIdentity.length() + 1) * sizeof(wchar_t);
|
||||
const qint64 result = CfConvertToPlaceholder(handleForPath(path).get(), fileIdentity.data(), sizeToDWORD(fileIdentitySize), CF_CONVERT_FLAG_MARK_IN_SYNC, nullptr, nullptr);
|
||||
const qint64 result =
|
||||
CfConvertToPlaceholder(handleForPath(path).get(), fileId.data(), static_cast<DWORD>(fileId.size()), CF_CONVERT_FLAG_MARK_IN_SYNC, nullptr, nullptr);
|
||||
Q_ASSERT(result == S_OK);
|
||||
if (result != S_OK) {
|
||||
const auto errorMessage = createErrorMessageForPlaceholderUpdateAndCreate(path, "Couldn't convert to placeholder");
|
||||
|
||||
@ -4,13 +4,19 @@
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
// include order is important, this must be included before cfapi
|
||||
#include <windows.h>
|
||||
#include <winternl.h>
|
||||
|
||||
#include <cfapi.h>
|
||||
|
||||
#include "cfapiexport.h"
|
||||
#include "common/pinstate.h"
|
||||
#include "common/result.h"
|
||||
#include "common/vfs.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
struct CF_PLACEHOLDER_BASIC_INFO;
|
||||
|
||||
namespace OCC {
|
||||
@ -48,19 +54,18 @@ private:
|
||||
class NEXTCLOUD_CFAPI_EXPORT PlaceHolderInfo
|
||||
{
|
||||
public:
|
||||
using Deleter = void (*)(CF_PLACEHOLDER_BASIC_INFO *);
|
||||
PlaceHolderInfo(std::vector<char> &&buffer = {});
|
||||
|
||||
PlaceHolderInfo();
|
||||
PlaceHolderInfo(CF_PLACEHOLDER_BASIC_INFO *data, Deleter deleter);
|
||||
inline auto *get() const noexcept { return reinterpret_cast<CF_PLACEHOLDER_BASIC_INFO *>(const_cast<char *>(_data.data())); }
|
||||
inline auto *operator->() const noexcept { return get(); }
|
||||
inline explicit operator bool() const noexcept { return !_data.empty(); }
|
||||
|
||||
inline CF_PLACEHOLDER_BASIC_INFO *get() const noexcept { return _data.get(); }
|
||||
inline CF_PLACEHOLDER_BASIC_INFO *operator->() const noexcept { return _data.get(); }
|
||||
inline explicit operator bool() const noexcept { return static_cast<bool>(_data); }
|
||||
inline auto size() const { return _data.size(); }
|
||||
|
||||
Optional<PinState> pinState() const;
|
||||
|
||||
private:
|
||||
std::unique_ptr<CF_PLACEHOLDER_BASIC_INFO, Deleter> _data;
|
||||
std::vector<char> _data;
|
||||
};
|
||||
|
||||
NEXTCLOUD_CFAPI_EXPORT Result<void, QString> registerSyncRoot(const QString &path, const QString &providerName, const QString &providerVersion, const QString &folderAlias, const QString &navigationPaneClsid, const QString &displayName, const QString &accountDisplayName);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user