When moving is allowed but deleting is not, do not restore moved items

Issue #7293
This commit is contained in:
Olivier Goffart 2019-10-10 13:24:24 +02:00 committed by Kevin Ottens
parent ee611e6004
commit 83d743b66b
No known key found for this signature in database
GPG key ID: 074BBBCB8DECC9E2
3 changed files with 50 additions and 3 deletions

View file

@ -1108,6 +1108,7 @@ void ProcessDirectoryJob::processFileFinalize(
if (item->isDirectory() && item->_instruction == CSYNC_INSTRUCTION_SYNC)
item->_instruction = CSYNC_INSTRUCTION_UPDATE_METADATA;
bool removed = item->_instruction == CSYNC_INSTRUCTION_REMOVE;
if (checkPermissions(item)) {
if (item->_isRestoration && item->isDirectory())
recurse = true;
@ -1116,7 +1117,7 @@ void ProcessDirectoryJob::processFileFinalize(
}
if (recurse) {
auto job = new ProcessDirectoryJob(path, item, recurseQueryLocal, recurseQueryServer, this);
if (item->_instruction == CSYNC_INSTRUCTION_REMOVE) {
if (removed) {
job->setParent(_discoveryData);
_discoveryData->_queuedDeletedDirectories[path._original] = job;
} else {
@ -1124,7 +1125,7 @@ void ProcessDirectoryJob::processFileFinalize(
_queuedJobs.push_back(job);
}
} else {
if (item->_instruction == CSYNC_INSTRUCTION_REMOVE
if (removed
// For the purpose of rename deletion, restored deleted placeholder is as if it was deleted
|| (item->_type == ItemTypeVirtualFile && item->_instruction == CSYNC_INSTRUCTION_NEW)) {
_discoveryData->_deletedItem[path._original] = item;

View file

@ -161,7 +161,9 @@ QPair<bool, QByteArray> DiscoveryPhase::findAndCancelDeletedJob(const QString &o
if (it != _deletedItem.end()) {
ENFORCE((*it)->_instruction == CSYNC_INSTRUCTION_REMOVE
// re-creation of virtual files count as a delete
|| ((*it)->_type == ItemTypeVirtualFile && (*it)->_instruction == CSYNC_INSTRUCTION_NEW));
|| ((*it)->_type == ItemTypeVirtualFile && (*it)->_instruction == CSYNC_INSTRUCTION_NEW)
|| ((*it)->_isRestoration && (*it)->_instruction == CSYNC_INSTRUCTION_NEW)
);
(*it)->_instruction = CSYNC_INSTRUCTION_NONE;
result = true;
oldEtag = (*it)->_etag;

View file

@ -465,6 +465,50 @@ private slots:
QVERIFY(cls.find("zallowed/sub2"));
QVERIFY(cls.find("zallowed/sub2/file"));
}
// Test for issue #7293
void testAllowedMoveForbiddenDelete() {
FakeFolder fakeFolder{FileInfo{}};
// Some of this test depends on the order of discovery. With threading
// that order becomes effectively random, but we want to make sure to test
// all cases and thus disable threading.
auto syncOpts = fakeFolder.syncEngine().syncOptions();
syncOpts._parallelNetworkJobs = 1;
fakeFolder.syncEngine().setSyncOptions(syncOpts);
auto &lm = fakeFolder.localModifier();
auto &rm = fakeFolder.remoteModifier();
rm.mkdir("changeonly");
rm.mkdir("changeonly/sub1");
rm.insert("changeonly/sub1/file1");
rm.insert("changeonly/sub1/filetorname1a");
rm.insert("changeonly/sub1/filetorname1z");
rm.mkdir("changeonly/sub2");
rm.insert("changeonly/sub2/file2");
rm.insert("changeonly/sub2/filetorname2a");
rm.insert("changeonly/sub2/filetorname2z");
setAllPerm(rm.find("changeonly"), RemotePermissions::fromServerString("NSV"));
QVERIFY(fakeFolder.syncOnce());
lm.rename("changeonly/sub1/filetorname1a", "changeonly/sub1/aaa1_renamed");
lm.rename("changeonly/sub1/filetorname1z", "changeonly/sub1/zzz1_renamed");
lm.rename("changeonly/sub2/filetorname2a", "changeonly/sub2/aaa2_renamed");
lm.rename("changeonly/sub2/filetorname2z", "changeonly/sub2/zzz2_renamed");
lm.rename("changeonly/sub1", "changeonly/aaa");
lm.rename("changeonly/sub2", "changeonly/zzz");
auto expectedState = fakeFolder.currentLocalState();
QVERIFY(fakeFolder.syncOnce());
QCOMPARE(fakeFolder.currentLocalState(), expectedState);
QCOMPARE(fakeFolder.currentRemoteState(), expectedState);
}
};
QTEST_GUILESS_MAIN(TestPermissions)