Skip to content

Commit

Permalink
Create placeholder while dehydrating if needed
Browse files Browse the repository at this point in the history
When replacing an OnlineOnly file by another one, the file maintains it
OnlineOnly pin state, but it is converted to a regular file. So, the
dehydration should convert the regular file to a (dehydrated)
placeholder instead of trying to update the (non-existing) placeholder.

Closes nextcloud#4274
  • Loading branch information
m7913d committed Jul 15, 2023
1 parent 36832f4 commit 6957439
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 20 deletions.
53 changes: 33 additions & 20 deletions src/libsync/vfs/cfapi/cfapiwrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -792,29 +792,42 @@ 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 info = findPlaceholderInfo(path);
if (!info) {
return { "Can't update non existing placeholder info" };
}

const auto fileIdentity = QString::fromUtf8(fileId).toStdWString();
const auto fileIdentitySize = (fileIdentity.length() + 1) * sizeof(wchar_t);

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

if (result != S_OK) {
qCWarning(lcCfApiWrapper) << "Couldn't update placeholder info for" << path << ":" << QString::fromWCharArray(_com_error(result).ErrorMessage());
return { "Couldn't update placeholder info" };
const auto info = findPlaceholderInfo(path);
if (info) {
CF_FILE_RANGE dehydrationRange;
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);

if (result != S_OK) {
qCWarning(lcCfApiWrapper) << "Couldn't update placeholder info for" << path << ":" << QString::fromWCharArray(_com_error(result).ErrorMessage());
return {"Couldn't update placeholder info"};
}
} else {
return {"Can't update non existing placeholder info"};
const qint64 result = CfConvertToPlaceholder(handleForPath(path).get(),
fileIdentity.data(),
sizeToDWORD(fileIdentitySize),
CF_CONVERT_FLAG_MARK_IN_SYNC | CF_CONVERT_FLAG_DEHYDRATE,
nullptr,
nullptr);

if (result != S_OK) {
qCWarning(lcCfApiWrapper) << "Couldn't convert to placeholderr" << path << ":" << QString::fromWCharArray(_com_error(result).ErrorMessage());
return {"Couldn't convert to placeholder"};
}
}

return OCC::Vfs::ConvertToPlaceholderResult::Ok;
Expand Down
32 changes: 32 additions & 0 deletions test/testsynccfapi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,38 @@ private slots:
QTest::newRow("skip local discovery") << false;
}

void testReplaceOnlineOnlyFile()
{
FakeFolder fakeFolder{FileInfo{}};
auto vfs = setupVfs(fakeFolder);

// Create a new local (non-placeholder) file
fakeFolder.localModifier().insert("file");
QVERIFY(!vfs->pinState("file").isValid());

CopyFile(QString(fakeFolder.localPath() + "file").toStdWString().data(), QString(fakeFolder.localPath() + "file1").toStdWString().data(), false);

// Sync the files: files should be converted to placeholder files
QVERIFY(fakeFolder.syncOnce());
QVERIFY(vfs->pinState("file").isValid());

// Convert to Online Only
::setPinState(fakeFolder.localPath() + "file", PinState::OnlineOnly, cfapi::Recurse);

QVERIFY(fakeFolder.syncOnce());
QCOMPARE(*vfs->pinState("file"), PinState::OnlineOnly);
CFVERIFY_VIRTUAL(fakeFolder, "file");

// Replace the file
CopyFile(QString(fakeFolder.localPath() + "file1").toStdWString().data(), QString(fakeFolder.localPath() + "file").toStdWString().data(), false);

// Sync again: file should be correctly dehydrated again without error.
QVERIFY(fakeFolder.syncOnce());
QVERIFY(vfs->pinState("file").isValid());
QCOMPARE(*vfs->pinState("file"), PinState::OnlineOnly);
CFVERIFY_VIRTUAL(fakeFolder, "file");
}

void testVirtualFileLifecycle()
{
QFETCH(bool, doLocalDiscovery);
Expand Down

0 comments on commit 6957439

Please sign in to comment.