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

Signed-off-by: Dries Mys <[email protected]>
  • Loading branch information
m7913d authored and backportbot-nextcloud[bot] committed Jul 20, 2023
1 parent f8dae64 commit 241101b
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 20 deletions.
52 changes: 32 additions & 20 deletions src/libsync/vfs/cfapi/cfapiwrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -796,29 +796,41 @@ 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 {
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;
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 241101b

Please sign in to comment.