Create placeholder while dehydrating if needed

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 #4274

Signed-off-by: Dries Mys <dries.mys@my-dreams.be>
This commit is contained in:
Dries Mys 2023-07-16 00:05:20 +02:00 committed by Matthieu Gallien
parent 759c2a246c
commit 9256417612
2 changed files with 62 additions and 18 deletions

View file

@ -796,20 +796,19 @@ 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)}; 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 fileIdentity = QString::fromUtf8(fileId).toStdWString();
const auto fileIdentitySize = (fileIdentity.length() + 1) * sizeof(wchar_t); const auto fileIdentitySize = (fileIdentity.length() + 1) * sizeof(wchar_t);
const auto info = findPlaceholderInfo(path);
if (info) {
CF_FILE_RANGE dehydrationRange; CF_FILE_RANGE dehydrationRange;
dehydrationRange.StartingOffset.QuadPart = 0; dehydrationRange.StartingOffset.QuadPart = 0;
dehydrationRange.Length.QuadPart = size; dehydrationRange.Length.QuadPart = size;
const qint64 result = CfUpdatePlaceholder(handleForPath(path).get(), nullptr, const qint64 result = CfUpdatePlaceholder(handleForPath(path).get(),
fileIdentity.data(), sizeToDWORD(fileIdentitySize), nullptr,
fileIdentity.data(),
sizeToDWORD(fileIdentitySize),
&dehydrationRange, &dehydrationRange,
1, 1,
CF_UPDATE_FLAG_MARK_IN_SYNC | CF_UPDATE_FLAG_DEHYDRATE, CF_UPDATE_FLAG_MARK_IN_SYNC | CF_UPDATE_FLAG_DEHYDRATE,
@ -820,6 +819,19 @@ OCC::Result<OCC::Vfs::ConvertToPlaceholderResult, QString> OCC::CfApiWrapper::de
qCWarning(lcCfApiWrapper) << "Couldn't update placeholder info for" << path << ":" << QString::fromWCharArray(_com_error(result).ErrorMessage()); qCWarning(lcCfApiWrapper) << "Couldn't update placeholder info for" << path << ":" << QString::fromWCharArray(_com_error(result).ErrorMessage());
return {"Couldn't update placeholder info"}; return {"Couldn't update placeholder info"};
} }
} else {
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 placeholder" << path << ":" << QString::fromWCharArray(_com_error(result).ErrorMessage());
return {"Couldn't convert to placeholder"};
}
}
return OCC::Vfs::ConvertToPlaceholderResult::Ok; return OCC::Vfs::ConvertToPlaceholderResult::Ok;
} }

View file

@ -120,6 +120,38 @@ private slots:
QTest::newRow("skip local discovery") << false; 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() void testVirtualFileLifecycle()
{ {
QFETCH(bool, doLocalDiscovery); QFETCH(bool, doLocalDiscovery);