Skip to content

Commit

Permalink
Merge branch 'master' into master
Browse files Browse the repository at this point in the history
  • Loading branch information
mickenordin authored Dec 6, 2023
2 parents d98faf5 + 2c5281c commit c0481e5
Show file tree
Hide file tree
Showing 15 changed files with 144 additions and 92 deletions.
29 changes: 19 additions & 10 deletions src/common/vfs.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,17 @@
*/
#pragma once

#include "ocsynclib.h"
#include "result.h"
#include "syncfilestatus.h"
#include "pinstate.h"

#include <QObject>
#include <QScopedPointer>
#include <QSharedPointer>

#include <memory>

#include "ocsynclib.h"
#include "result.h"
#include "syncfilestatus.h"
#include "pinstate.h"

using csync_file_stat_t = struct csync_file_stat_s;

namespace OCC {
Expand Down Expand Up @@ -113,6 +113,15 @@ class OCSYNC_EXPORT Vfs : public QObject
};
Q_ENUM(ConvertToPlaceholderResult)

enum UpdateMetadataType {
DatabaseMetadata = 1 << 0,
FileMetadata = 1 << 1,
AllMetadata = DatabaseMetadata | FileMetadata,
};

Q_DECLARE_FLAGS(UpdateMetadataTypes, UpdateMetadataType)
Q_FLAG(UpdateMetadataType)

static QString modeToString(Mode mode);
static Optional<Mode> modeFromString(const QString &str);

Expand Down Expand Up @@ -203,10 +212,10 @@ class OCSYNC_EXPORT Vfs : public QObject
* new placeholder shall supersede, for rename-replace actions with new downloads,
* for example.
*/
Q_REQUIRED_RESULT virtual Result<Vfs::ConvertToPlaceholderResult, QString> convertToPlaceholder(
const QString &filename,
const SyncFileItem &item,
const QString &replacesFile = QString()) = 0;
Q_REQUIRED_RESULT virtual Result<Vfs::ConvertToPlaceholderResult, QString> convertToPlaceholder(const QString &filename,
const SyncFileItem &item,
const QString &replacesFile = {},
UpdateMetadataTypes updateType = AllMetadata) = 0;

/// Determine whether the file at the given absolute path is a dehydrated placeholder.
Q_REQUIRED_RESULT virtual bool isDehydratedPlaceholder(const QString &filePath) = 0;
Expand Down Expand Up @@ -311,7 +320,7 @@ class OCSYNC_EXPORT VfsOff : public Vfs
Result<void, QString> updateMetadata(const QString &, time_t, qint64, const QByteArray &) override { return {}; }
Result<void, QString> createPlaceholder(const SyncFileItem &) override { return {}; }
Result<void, QString> dehydratePlaceholder(const SyncFileItem &) override { return {}; }
Result<ConvertToPlaceholderResult, QString> convertToPlaceholder(const QString &, const SyncFileItem &, const QString &) override { return ConvertToPlaceholderResult::Ok; }
Result<ConvertToPlaceholderResult, QString> convertToPlaceholder(const QString &, const SyncFileItem &, const QString &, UpdateMetadataTypes) override { return ConvertToPlaceholderResult::Ok; }

bool needsMetadataUpdate(const SyncFileItem &) override { return false; }
bool isDehydratedPlaceholder(const QString &) override { return false; }
Expand Down
1 change: 1 addition & 0 deletions src/gui/folderwatcher.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ void FolderWatcher::startNotificationTestWhenReady()
auto path = _testNotificationPath;
if (QFile::exists(path)) {
auto mtime = FileSystem::getModTime(path);
qCDebug(lcFolderWatcher()) << "setModTime" << path << (mtime + 1);
FileSystem::setModTime(path, mtime + 1);
} else {
QFile f(path);
Expand Down
2 changes: 1 addition & 1 deletion src/libsync/bulkpropagatorjob.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -479,7 +479,7 @@ void BulkPropagatorJob::adjustLastJobTimeout(AbstractNetworkJob *job, qint64 fil
void BulkPropagatorJob::finalizeOneFile(const BulkUploadItem &oneFile)
{
// Update the database entry
const auto result = propagator()->updateMetadata(*oneFile._item);
const auto result = propagator()->updateMetadata(*oneFile._item, Vfs::UpdateMetadataType::DatabaseMetadata);
if (!result) {
done(oneFile._item, SyncFileItem::FatalError, tr("Error updating metadata: %1").arg(result.error()), ErrorCategory::GenericError);
return;
Expand Down
16 changes: 10 additions & 6 deletions src/libsync/owncloudpropagator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1001,16 +1001,19 @@ QString OwncloudPropagator::adjustRenamedPath(const QString &original) const
return OCC::adjustRenamedPath(_renamedDirectories, original);
}

Result<Vfs::ConvertToPlaceholderResult, QString> OwncloudPropagator::updateMetadata(const SyncFileItem &item)
Result<Vfs::ConvertToPlaceholderResult, QString> OwncloudPropagator::updateMetadata(const SyncFileItem &item, Vfs::UpdateMetadataTypes updateType)
{
return OwncloudPropagator::staticUpdateMetadata(item, _localDir, syncOptions()._vfs.data(), _journal);
return OwncloudPropagator::staticUpdateMetadata(item, _localDir, syncOptions()._vfs.data(), _journal, updateType);
}

Result<Vfs::ConvertToPlaceholderResult, QString> OwncloudPropagator::staticUpdateMetadata(const SyncFileItem &item, const QString localDir,
Vfs *vfs, SyncJournalDb *const journal)
Result<Vfs::ConvertToPlaceholderResult, QString> OwncloudPropagator::staticUpdateMetadata(const SyncFileItem &item,
const QString localDir,
Vfs *vfs,
SyncJournalDb *const journal,
Vfs::UpdateMetadataTypes updateType)
{
const QString fsPath = localDir + item.destination();
const auto result = vfs->convertToPlaceholder(fsPath, item);
const auto result = vfs->convertToPlaceholder(fsPath, item, {}, updateType);
if (!result) {
return result.error();
} else if (*result == Vfs::ConvertToPlaceholderResult::Locked) {
Expand Down Expand Up @@ -1375,6 +1378,7 @@ void PropagateDirectory::slotSubJobsFinished(SyncFileItem::Status status)
qCWarning(lcDirectory) << "Error writing to the database for file" << _item->_file;
}

qCDebug(lcPropagator()) << "setModTime" << propagator()->fullLocalPath(_item->destination()) << _item->_modtime;
FileSystem::setModTime(propagator()->fullLocalPath(_item->destination()), _item->_modtime);
}

Expand Down Expand Up @@ -1582,7 +1586,7 @@ void CleanupPollsJob::slotPollFinished()
} else if (job->_item->_status != SyncFileItem::Success) {
qCWarning(lcCleanupPolls) << "There was an error with file " << job->_item->_file << job->_item->_errorString;
} else {
if (!OwncloudPropagator::staticUpdateMetadata(*job->_item, _localPath, _vfs.data(), _journal)) {
if (!OwncloudPropagator::staticUpdateMetadata(*job->_item, _localPath, _vfs.data(), _journal, Vfs::AllMetadata)) {
qCWarning(lcCleanupPolls) << "database error";
job->_item->_status = SyncFileItem::FatalError;
job->_item->_errorString = tr("Error writing metadata to the database");
Expand Down
15 changes: 10 additions & 5 deletions src/libsync/owncloudpropagator.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,15 @@

#include "accountfwd.h"
#include "bandwidthmanager.h"
#include "common/syncjournaldb.h"
#include "common/utility.h"
#include "csync.h"
#include "progressdispatcher.h"
#include "syncfileitem.h"
#include "syncoptions.h"

#include "common/syncjournaldb.h"
#include "common/utility.h"
#include "common/vfs.h"

#include <deque>

namespace OCC {
Expand Down Expand Up @@ -592,7 +594,7 @@ class OWNCLOUDSYNC_EXPORT OwncloudPropagator : public QObject
*
* Will also trigger a Vfs::convertToPlaceholder.
*/
Result<Vfs::ConvertToPlaceholderResult, QString> updateMetadata(const SyncFileItem &item);
Result<Vfs::ConvertToPlaceholderResult, QString> updateMetadata(const SyncFileItem &item, Vfs::UpdateMetadataTypes updateType = Vfs::AllMetadata);

/** Update the database for an item.
*
Expand All @@ -601,8 +603,11 @@ class OWNCLOUDSYNC_EXPORT OwncloudPropagator : public QObject
*
* Will also trigger a Vfs::convertToPlaceholder.
*/
static Result<Vfs::ConvertToPlaceholderResult, QString> staticUpdateMetadata(const SyncFileItem &item, const QString localDir,
Vfs *vfs, SyncJournalDb * const journal);
static Result<Vfs::ConvertToPlaceholderResult, QString> staticUpdateMetadata(const SyncFileItem &item,
const QString localDir,
Vfs *vfs,
SyncJournalDb * const journal,
Vfs::UpdateMetadataTypes updateType);

Q_REQUIRED_RESULT bool isDelayedUploadItem(const SyncFileItemPtr &item) const;

Expand Down
2 changes: 2 additions & 0 deletions src/libsync/propagatedownload.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -606,6 +606,7 @@ void PropagateDownloadFile::conflictChecksumComputed(const QByteArray &checksumT
}
if (_item->_modtime != _item->_previousModtime) {
Q_ASSERT(_item->_modtime > 0);
qCDebug(lcPropagateDownload()) << "setModTime" << fn << _item->_modtime;
FileSystem::setModTime(fn, _item->_modtime);
emit propagator()->touchedFile(fn);
}
Expand Down Expand Up @@ -1162,6 +1163,7 @@ void PropagateDownloadFile::downloadFinished()
if (_item->_modtime <= 0) {
qCWarning(lcPropagateDownload()) << "invalid modified time" << _item->_file << _item->_modtime;
}
qCDebug(lcPropagateDownload()) << "setModTime" << _tmpFile.fileName() << _item->_modtime;
FileSystem::setModTime(_tmpFile.fileName(), _item->_modtime);
// We need to fetch the time again because some file systems such as FAT have worse than a second
// Accuracy, and we really need the time from the file system. (#3103)
Expand Down
2 changes: 1 addition & 1 deletion src/libsync/propagateupload.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -800,7 +800,7 @@ void PropagateUploadFileCommon::finalize()
quotaIt.value() -= _fileToUpload._size;

// Update the database entry
const auto result = propagator()->updateMetadata(*_item);
const auto result = propagator()->updateMetadata(*_item, Vfs::DatabaseMetadata);
if (!result) {
done(SyncFileItem::FatalError, tr("Error updating metadata: %1").arg(result.error()));
return;
Expand Down
140 changes: 78 additions & 62 deletions src/libsync/vfs/cfapi/cfapiwrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,30 @@ constexpr auto syncRootFlagsNoCfApiContextMenu = 2;

constexpr auto syncRootManagerRegKey = R"(SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\SyncRootManager)";

DWORD sizeToDWORD(size_t size)
{
return OCC::Utility::convertSizeToDWORD(size);
}

OCC::PinState cfPinStateToPinState(CF_PIN_STATE state)
{
switch (state) {
case CF_PIN_STATE_UNSPECIFIED:
return OCC::PinState::Unspecified;
case CF_PIN_STATE_PINNED:
return OCC::PinState::AlwaysLocal;
case CF_PIN_STATE_UNPINNED:
return OCC::PinState::OnlineOnly;
case CF_PIN_STATE_INHERIT:
return OCC::PinState::Inherited;
case CF_PIN_STATE_EXCLUDED:
return OCC::PinState::Excluded;
default:
Q_UNREACHABLE();
return OCC::PinState::Inherited;
}
}

void cfApiSendTransferInfo(const CF_CONNECTION_KEY &connectionKey, const CF_TRANSFER_KEY &transferKey, NTSTATUS status, void *buffer, qint64 offset, qint64 currentBlockLength, qint64 totalLength)
{

Expand Down Expand Up @@ -237,6 +261,53 @@ void CALLBACK cfApiFetchDataCallback(const CF_CALLBACK_INFO *callbackInfo, const
sendTransferError();
}
}

enum class CfApiUpdateMetadataType {
OnlyBasicMetadata,
AllMetadata,
};

OCC::Result<OCC::Vfs::ConvertToPlaceholderResult, QString> updatePlaceholderState(const QString &path, time_t modtime, qint64 size, const QByteArray &fileId, const QString &replacesPath, 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)};
}

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);

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;

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);

if (result != S_OK) {
qCWarning(lcCfApiWrapper) << "Couldn't update placeholder info for" << path << ":" << QString::fromWCharArray(_com_error(result).ErrorMessage()) << replacesPath;
return { "Couldn't update placeholder info" };
}

// 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;
}
}

void CALLBACK cfApiCancelFetchData(const CF_CALLBACK_INFO *callbackInfo, const CF_CALLBACK_PARAMETERS * /*callbackParameters*/)
Expand All @@ -262,11 +333,6 @@ CF_CALLBACK_REGISTRATION cfApiCallbacks[] = {
CF_CALLBACK_REGISTRATION_END
};

DWORD sizeToDWORD(size_t size)
{
return OCC::Utility::convertSizeToDWORD(size);
}

void deletePlaceholderInfo(CF_PLACEHOLDER_BASIC_INFO *info)
{
auto byte = reinterpret_cast<char *>(info);
Expand All @@ -281,25 +347,6 @@ std::wstring pathForHandle(const OCC::CfApiWrapper::FileHandle &handle)
return std::wstring(buffer);
}

OCC::PinState cfPinStateToPinState(CF_PIN_STATE state)
{
switch (state) {
case CF_PIN_STATE_UNSPECIFIED:
return OCC::PinState::Unspecified;
case CF_PIN_STATE_PINNED:
return OCC::PinState::AlwaysLocal;
case CF_PIN_STATE_UNPINNED:
return OCC::PinState::OnlineOnly;
case CF_PIN_STATE_INHERIT:
return OCC::PinState::Inherited;
case CF_PIN_STATE_EXCLUDED:
return OCC::PinState::Excluded;
default:
Q_UNREACHABLE();
return OCC::PinState::Inherited;
}
}

CF_PIN_STATE pinStateToCfPinState(OCC::PinState state)
{
switch (state) {
Expand Down Expand Up @@ -732,6 +779,7 @@ OCC::Result<void, QString> OCC::CfApiWrapper::createPlaceholderInfo(const QStrin
cloudEntry.FsMetadata.FileSize.QuadPart = 0;
}

qCDebug(lcCfApiWrapper) << "CfCreatePlaceholders" << path << modtime;
const qint64 result = CfCreatePlaceholders(localBasePath.data(), &cloudEntry, 1, CF_CREATE_FLAG_NONE, nullptr);
if (result != S_OK) {
qCWarning(lcCfApiWrapper) << "Couldn't create placeholder info for" << path << ":" << QString::fromWCharArray(_com_error(result).ErrorMessage());
Expand All @@ -750,44 +798,7 @@ OCC::Result<void, QString> OCC::CfApiWrapper::createPlaceholderInfo(const QStrin

OCC::Result<OCC::Vfs::ConvertToPlaceholderResult, QString> OCC::CfApiWrapper::updatePlaceholderInfo(const QString &path, time_t modtime, qint64 size, const QByteArray &fileId, const QString &replacesPath)
{

if (modtime <= 0) {
return {QString{"Could not update metadata due to invalid modification time for %1: %2"}.arg(path).arg(modtime)};
}

const auto info = replacesPath.isEmpty() ? findPlaceholderInfo(path)
: 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);

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;

const qint64 result = CfUpdatePlaceholder(handleForPath(path).get(), &metadata,
fileIdentity.data(), sizeToDWORD(fileIdentitySize),
nullptr, 0, CF_UPDATE_FLAG_MARK_IN_SYNC, nullptr, nullptr);

if (result != S_OK) {
qCWarning(lcCfApiWrapper) << "Couldn't update placeholder info for" << path << ":" << QString::fromWCharArray(_com_error(result).ErrorMessage()) << replacesPath;
return { "Couldn't update placeholder info" };
}

// Pin state tends to be lost on updates, so restore it every time
if (!setPinState(path, previousPinState, NoRecurse)) {
return { "Couldn't restore pin state" };
}

return OCC::Vfs::ConvertToPlaceholderResult::Ok;
return updatePlaceholderState(path, modtime, size, fileId, replacesPath, CfApiUpdateMetadataType::AllMetadata);
}

OCC::Result<OCC::Vfs::ConvertToPlaceholderResult, QString> OCC::CfApiWrapper::dehydratePlaceholder(const QString &path, time_t modtime, qint64 size, const QByteArray &fileId)
Expand Down Expand Up @@ -862,3 +873,8 @@ OCC::Result<OCC::Vfs::ConvertToPlaceholderResult, QString> OCC::CfApiWrapper::co
return stateResult;
}
}

OCC::Result<OCC::Vfs::ConvertToPlaceholderResult, QString> OCC::CfApiWrapper::updatePlaceholderMarkInSync(const QString &path, const QByteArray &fileId, const QString &replacesPath)
{
return updatePlaceholderState(path, {}, {}, fileId, replacesPath, CfApiUpdateMetadataType::OnlyBasicMetadata);
}
1 change: 1 addition & 0 deletions src/libsync/vfs/cfapi/cfapiwrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ NEXTCLOUD_CFAPI_EXPORT Result<void, QString> createPlaceholderInfo(const QString
NEXTCLOUD_CFAPI_EXPORT Result<OCC::Vfs::ConvertToPlaceholderResult, QString> updatePlaceholderInfo(const QString &path, time_t modtime, qint64 size, const QByteArray &fileId, const QString &replacesPath = QString());
NEXTCLOUD_CFAPI_EXPORT Result<OCC::Vfs::ConvertToPlaceholderResult, QString> convertToPlaceholder(const QString &path, time_t modtime, qint64 size, const QByteArray &fileId, const QString &replacesPath);
NEXTCLOUD_CFAPI_EXPORT Result<OCC::Vfs::ConvertToPlaceholderResult, QString> dehydratePlaceholder(const QString &path, time_t modtime, qint64 size, const QByteArray &fileId);
NEXTCLOUD_CFAPI_EXPORT Result<OCC::Vfs::ConvertToPlaceholderResult, QString> updatePlaceholderMarkInSync(const QString &path, const QByteArray &fileId, const QString &replacesPath = QString());

}

Expand Down
Loading

0 comments on commit c0481e5

Please sign in to comment.