From: Olivier Goffart Date: Wed, 25 Jul 2018 16:31:36 +0000 (+0200) Subject: New Discovery Algo: Permsission check X-Git-Tag: archive/raspbian/3.16.7-1_deb13u1+rpi1~1^2~12^2~21^2~468^2~539 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=ac24cdbde69b33fd2778eb73142033c2a69b28a8;p=nextcloud-desktop.git New Discovery Algo: Permsission check --- diff --git a/CMakeLists.txt b/CMakeLists.txt index 8e5ddb885..383f00ae2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -168,16 +168,6 @@ if(OWNCLOUD_5XX_NO_BLACKLIST) add_definitions(-DOWNCLOUD_5XX_NO_BLACKLIST=1) endif() -# When this option is enabled, a rename that is not allowed will be renamed back -# do the original as a restoration step. Withut this option, the restoration will -# re-download the file instead. -# The default is off because we don't want to rename the files back behind the user's back -# Added for IL issue #550 -option(OWNCLOUD_RESTORE_RENAME "OWNCLOUD_RESTORE_RENAME" OFF) -if(OWNCLOUD_RESTORE_RENAME) - add_definitions(-DOWNCLOUD_RESTORE_RENAME=1) -endif() - # Disable shibboleth. # So the client can be built without QtWebKit option(NO_SHIBBOLETH "Build without Shibboleth support. Allow to build the client without QtWebKit" OFF) diff --git a/src/libsync/discovery.cpp b/src/libsync/discovery.cpp index a579cc1a8..0e7920335 100644 --- a/src/libsync/discovery.cpp +++ b/src/libsync/discovery.cpp @@ -35,7 +35,8 @@ void ProcessDirectoryJob::start() DiscoverySingleDirectoryJob *serverJob = nullptr; if (_queryServer == NormalQuery) { - serverJob = new DiscoverySingleDirectoryJob(_discoveryData->_account, _discoveryData->_remoteFolder + _currentFolder._server, this); + serverJob = new DiscoverySingleDirectoryJob(_discoveryData->_account, + _discoveryData->_remoteFolder + _currentFolder._server, this); connect(serverJob, &DiscoverySingleDirectoryJob::finished, this, [this](const auto &results) { if (results) { _serverEntries = *results; @@ -71,6 +72,8 @@ void ProcessDirectoryJob::start() emit finished(); } }); + connect(serverJob, &DiscoverySingleDirectoryJob::firstDirectoryPermissions, this, + [this](const RemotePermissions &perms) { _rootPermissions = perms; }); serverJob->start(); } else { _hasServerEntries = true; @@ -555,7 +558,6 @@ void ProcessDirectoryJob::processFile(PathTuple path, } qCInfo(lcDisco) << "Discovered" << item->_file << item->_instruction << item->_direction << item->isDirectory(); - if (item->isDirectory()) { auto job = new ProcessDirectoryJob(item, recurseQueryServer, item->_instruction == CSYNC_INSTRUCTION_RENAME ? NormalQuery : ParentDontExist, @@ -742,40 +744,78 @@ void ProcessDirectoryJob::processFile(PathTuple path, if (!_dirItem || _dirItem->_direction == SyncFileItem::Down) { _childModified = true; } - // Check if it is a rename + // Check if it is a move OCC::SyncJournalFileRecord base; if (!_discoveryData->_statedb->getFileRecordByInode(localEntry.inode, &base)) { qFatal("TODO: handle DB Errors"); } - bool isRename = base.isValid() && base._type == item->_type + bool isMove = base.isValid() && base._type == item->_type && ((base._modtime == localEntry.modtime && base._fileSize == localEntry.size) || item->_type == ItemTypeDirectory); - if (isRename) { + if (isMove) { // The old file must have been deleted. - isRename = !QFile::exists(_discoveryData->_localDir + base._path); + isMove = !QFile::exists(_discoveryData->_localDir + base._path); } // Verify the checksum where possible - if (isRename && !base._checksumHeader.isEmpty() && item->_type == ItemTypeFile) { + if (isMove && !base._checksumHeader.isEmpty() && item->_type == ItemTypeFile) { if (computeLocalChecksum(parseChecksumHeaderType(base._checksumHeader), path._original)) { qCInfo(lcDisco) << "checking checksum of potential rename " << path._original << item->_checksumHeader << base._checksumHeader; - isRename = item->_checksumHeader == base._checksumHeader; + isMove = item->_checksumHeader == base._checksumHeader; } } auto originalPath = QString::fromUtf8(base._path); - if (isRename && _discoveryData->_renamedItems.contains(originalPath)) - isRename = false; - if (isRename) { + if (isMove && _discoveryData->_renamedItems.contains(originalPath)) + isMove = false; + + //Check local permission if we are allowed to put move the file here + if (isMove) { + auto destPerms = !_rootPermissions.isNull() ? _rootPermissions + : _dirItem ? _dirItem->_remotePerm : _rootPermissions; + auto filePerms = base._remotePerm; // Technicly we should use the one from the server, but we'll assume it is the same + //true when it is just a rename in the same directory. (not a move) + bool isRename = originalPath.startsWith(_currentFolder._original) + && originalPath.lastIndexOf('/') == _currentFolder._original.size(); + // Check if we are allowed to move to the destination. + bool destinationOK = true; + if (isRename || destPerms.isNull()) { + // no need to check for the destination dir permission + destinationOK = true; + } else if (item->isDirectory() && !destPerms.hasPermission(RemotePermissions::CanAddSubDirectories)) { + destinationOK = false; + } else if (!item->isDirectory() && !destPerms.hasPermission(RemotePermissions::CanAddFile)) { + destinationOK = false; + } + + // check if we are allowed to move from the source + bool sourceOK = true; + if (!filePerms.isNull() + && ((isRename && !filePerms.hasPermission(RemotePermissions::CanRename)) + || (!isRename && !filePerms.hasPermission(RemotePermissions::CanMove)))) { + // We are not allowed to move or rename this file + sourceOK = false; + } + if (!sourceOK || !destinationOK) { + qCInfo(lcDisco) << "Not a move because permission does not allow it." << sourceOK << destinationOK; + if (!sourceOK) { + // This is the behavior that we had in the client <= 2.5. + _discoveryData->_statedb->avoidRenamesOnNextSync(base._path); + } + isMove = false; + } + } + + if (isMove) { QByteArray oldEtag; auto it = _discoveryData->_deletedItem.find(originalPath); if (it != _discoveryData->_deletedItem.end()) { if ((*it)->_instruction != CSYNC_INSTRUCTION_REMOVE) - isRename = false; + isMove = false; else (*it)->_instruction = CSYNC_INSTRUCTION_NONE; oldEtag = (*it)->_etag; if (!item->isDirectory() && oldEtag != base._etag) { - isRename = false; + isMove = false; } } if (auto deleteJob = static_cast(_discoveryData->_queuedDeletedDirectories.value(originalPath).data())) { @@ -800,10 +840,10 @@ void ProcessDirectoryJob::processFile(PathTuple path, path._server = adjustedOriginalPath; qCInfo(lcDisco) << "Rename detected (up) " << item->_file << " -> " << item->_renameTarget; }; - if (isRename && !oldEtag.isEmpty()) { + if (isMove && !oldEtag.isEmpty()) { recurseQueryServer = oldEtag == base._etag ? ParentNotChanged : NormalQuery; processRename(path); - } else if (isRename) { + } else if (isMove) { // We must query the server to know if the etag has not changed _pendingAsyncJobs++; auto job = new RequestEtagJob(_discoveryData->_account, originalPath, this); @@ -825,7 +865,8 @@ void ProcessDirectoryJob::processFile(PathTuple path, } qCInfo(lcDisco) << "Discovered" << item->_file << item->_instruction << item->_direction << item->isDirectory(); - if (item->isDirectory()) { + bool recurse = checkPremission(item); + if (recurse && item->isDirectory()) { auto job = new ProcessDirectoryJob(item, recurseQueryServer, NormalQuery, _discoveryData, this); job->_currentFolder = path; connect(job, &ProcessDirectoryJob::itemDiscovered, this, &ProcessDirectoryJob::itemDiscovered); @@ -884,7 +925,14 @@ void ProcessDirectoryJob::processFile(PathTuple path, item->_type = ItemTypeVirtualFile; item->_file.append(_discoveryData->_syncOptions._virtualFileSuffix); } else if (!serverModified) { - if (!dbEntry._serverHasIgnoredFiles) { + // Removed locally: also remove on the server. + if (_dirItem && _dirItem->_isRestoration && _dirItem->_instruction == CSYNC_INSTRUCTION_NEW) { + // Also restore everything + item->_instruction = CSYNC_INSTRUCTION_NEW; + item->_direction = SyncFileItem::Down; + item->_isRestoration = true; + item->_errorString = tr("Not allowed to remove, restoring"); + } else if (!dbEntry._serverHasIgnoredFiles) { item->_instruction = CSYNC_INSTRUCTION_REMOVE; item->_direction = SyncFileItem::Up; } @@ -904,8 +952,11 @@ void ProcessDirectoryJob::processFile(PathTuple path, if (item->isDirectory() && item->_instruction == CSYNC_INSTRUCTION_SYNC) item->_instruction = CSYNC_INSTRUCTION_UPDATE_METADATA; + bool recurse = item->isDirectory() || localEntry.isDirectory || serverEntry.isDirectory; - if (_queryLocal != NormalQuery && _queryServer != NormalQuery) + if (!checkPremission(item)) + recurse = false; + if (_queryLocal != NormalQuery && _queryServer != NormalQuery && !item->_isRestoration) recurse = false; if (recurse) { auto job = new ProcessDirectoryJob(item, recurseQueryServer, @@ -960,6 +1011,77 @@ void ProcessDirectoryJob::processBlacklisted(const PathTuple &path, const OCC::L } } +bool ProcessDirectoryJob::checkPremission(const OCC::SyncFileItemPtr &item) +{ + if (item->_direction != SyncFileItem::Up) { + // Currently we only check server-side permissions + return true; + } + + switch (item->_instruction) { + case CSYNC_INSTRUCTION_TYPE_CHANGE: + case CSYNC_INSTRUCTION_NEW: { + const auto perms = !_rootPermissions.isNull() ? _rootPermissions + : _dirItem ? _dirItem->_remotePerm : _rootPermissions; + if (perms.isNull()) { + // No permissions set + return true; + } else if (item->isDirectory() && !perms.hasPermission(RemotePermissions::CanAddSubDirectories)) { + qCWarning(lcDisco) << "checkForPermission: ERROR" << item->_file; + item->_instruction = CSYNC_INSTRUCTION_ERROR; + item->_status = SyncFileItem::NormalError; + item->_errorString = tr("Not allowed because you don't have permission to add subfolders to that folder"); + return false; + } else if (!item->isDirectory() && !perms.hasPermission(RemotePermissions::CanAddFile)) { + qCWarning(lcDisco) << "checkForPermission: ERROR" << item->_file; + item->_instruction = CSYNC_INSTRUCTION_ERROR; + item->_status = SyncFileItem::NormalError; + item->_errorString = tr("Not allowed because you don't have permission to add files in that folder"); + return false; + } + break; + } + case CSYNC_INSTRUCTION_SYNC: { + const auto perms = item->_remotePerm; + if (perms.isNull()) { + // No permissions set + return true; + } + if (!perms.hasPermission(RemotePermissions::CanWrite)) { + qCWarning(lcDisco) << "checkForPermission: RESTORING" << item->_file; + item->_instruction = CSYNC_INSTRUCTION_CONFLICT; + item->_errorString = tr("Not allowed to upload this file because it is read-only on the server, restoring"); + item->_direction = SyncFileItem::Down; + item->_isRestoration = true; + // Take the things to write to the db from the "other" node (i.e: info from server). + // Do a lookup into the csync remote tree to get the metadata we need to restore. + qSwap(item->_size, item->_previousSize); + qSwap(item->_modtime, item->_previousModtime); + return false; + } + break; + } + case CSYNC_INSTRUCTION_REMOVE: { + const auto perms = item->_remotePerm; + if (perms.isNull()) { + // No permissions set + return true; + } + if (!perms.hasPermission(RemotePermissions::CanDelete)) { + qCWarning(lcDisco) << "checkForPermission: RESTORING" << item->_file; + item->_instruction = CSYNC_INSTRUCTION_NEW; + item->_direction = SyncFileItem::Down; + item->_isRestoration = true; + item->_errorString = tr("Not allowed to remove, restoring"); + return true; // (we need to recurse to restore sub items) + } + break; + } + default: + break; + } + return true; +} void ProcessDirectoryJob::subJobFinished() { diff --git a/src/libsync/discovery.h b/src/libsync/discovery.h index 638aa9024..c7f62e9c5 100644 --- a/src/libsync/discovery.h +++ b/src/libsync/discovery.h @@ -75,12 +75,15 @@ private: // return true if the file is excluded bool handleExcluded(const QString &path, bool isDirectory, bool isHidden); void processFile(PathTuple, const LocalInfo &, const RemoteInfo &, const SyncJournalFileRecord &dbEntry); + // Return false if there is an error and that a directory must not be recursively be taken + bool checkPremission(const SyncFileItemPtr &item); void processBlacklisted(const PathTuple &, const LocalInfo &, const SyncJournalFileRecord &dbEntry); void subJobFinished(); void progress(); QVector _serverEntries; QVector _localEntries; + RemotePermissions _rootPermissions; bool _hasServerEntries = false; bool _hasLocalEntries = false; int _pendingAsyncJobs = 0; diff --git a/src/libsync/syncengine.cpp b/src/libsync/syncengine.cpp index 68b778a7c..dc8380a12 100644 --- a/src/libsync/syncengine.cpp +++ b/src/libsync/syncengine.cpp @@ -251,13 +251,6 @@ static bool isFileTransferInstruction(csync_instructions_e instruction) || instruction == CSYNC_INSTRUCTION_TYPE_CHANGE; } -static bool isFileModifyingInstruction(csync_instructions_e instruction) -{ - return isFileTransferInstruction(instruction) - || instruction == CSYNC_INSTRUCTION_RENAME - || instruction == CSYNC_INSTRUCTION_REMOVE; -} - void SyncEngine::deleteStaleDownloadInfos(const SyncFileItemVector &syncItems) { // Find all downloadinfo paths that we want to preserve. @@ -1127,239 +1120,6 @@ void SyncEngine::slotProgress(const SyncFileItem &item, quint64 current) } -/** - * - * Make sure that we are allowed to do what we do by checking the permissions and the selective sync list - * - */ -void SyncEngine::checkForPermission(SyncFileItemVector &syncItems) -{ - bool selectiveListOk = false; - auto selectiveSyncBlackList = _journal->getSelectiveSyncList(SyncJournalDb::SelectiveSyncBlackList, &selectiveListOk); - std::sort(selectiveSyncBlackList.begin(), selectiveSyncBlackList.end()); - SyncFileItemPtr needle; - - for (SyncFileItemVector::iterator it = syncItems.begin(); it != syncItems.end(); ++it) { - if ((*it)->_direction != SyncFileItem::Up - || !isFileModifyingInstruction((*it)->_instruction)) { - // Currently we only check server-side permissions - continue; - } - - // Do not propagate anything in the server if it is in the selective sync blacklist - const QString path = (*it)->destination() + QLatin1Char('/'); - - switch ((*it)->_instruction) { - case CSYNC_INSTRUCTION_TYPE_CHANGE: - case CSYNC_INSTRUCTION_NEW: { - int slashPos = (*it)->_file.lastIndexOf('/'); - QString parentDir = slashPos <= 0 ? "" : (*it)->_file.mid(0, slashPos); - const auto perms = getPermissions(parentDir); - if (perms.isNull()) { - // No permissions set - break; - } else if ((*it)->isDirectory() && !perms.hasPermission(RemotePermissions::CanAddSubDirectories)) { - qCWarning(lcEngine) << "checkForPermission: ERROR" << (*it)->_file; - (*it)->_instruction = CSYNC_INSTRUCTION_ERROR; - (*it)->_status = SyncFileItem::NormalError; - (*it)->_errorString = tr("Not allowed because you don't have permission to add subfolders to that folder"); - - for (SyncFileItemVector::iterator it_next = it + 1; it_next != syncItems.end() && (*it_next)->destination().startsWith(path); ++it_next) { - it = it_next; - if ((*it)->_instruction == CSYNC_INSTRUCTION_RENAME) { - // The file was most likely moved in this directory. - // If the file was read only or could not be moved or removed, it should - // be restored. Do that in the next sync by not considering as a rename - // but delete and upload. It will then be restored if needed. - _journal->avoidRenamesOnNextSync((*it)->_file); - _anotherSyncNeeded = ImmediateFollowUp; - qCWarning(lcEngine) << "Moving of " << (*it)->_file << " canceled because no permission to add parent folder"; - } - (*it)->_instruction = CSYNC_INSTRUCTION_ERROR; - (*it)->_status = SyncFileItem::SoftError; - (*it)->_errorString = tr("Not allowed because you don't have permission to add parent folder"); - } - - } else if (!(*it)->isDirectory() && !perms.hasPermission(RemotePermissions::CanAddFile)) { - qCWarning(lcEngine) << "checkForPermission: ERROR" << (*it)->_file; - (*it)->_instruction = CSYNC_INSTRUCTION_ERROR; - (*it)->_status = SyncFileItem::NormalError; - (*it)->_errorString = tr("Not allowed because you don't have permission to add files in that folder"); - } - break; - } - case CSYNC_INSTRUCTION_SYNC: { - const auto perms = getPermissions((*it)->_file); - if (perms.isNull()) { - // No permissions set - break; - } - if (!perms.hasPermission(RemotePermissions::CanWrite)) { - qCWarning(lcEngine) << "checkForPermission: RESTORING" << (*it)->_file; - (*it)->_instruction = CSYNC_INSTRUCTION_CONFLICT; - (*it)->_direction = SyncFileItem::Down; - (*it)->_isRestoration = true; - /*// Take the things to write to the db from the "other" node (i.e: info from server). - // Do a lookup into the csync remote tree to get the metadata we need to restore. - auto csyncIt = _csync_ctx->remote.files.find((*it)->_file.toUtf8()); - if (csyncIt != _csync_ctx->remote.files.end()) { - (*it)->_modtime = csyncIt->second->modtime; - (*it)->_size = csyncIt->second->size; - (*it)->_fileId = csyncIt->second->file_id; - (*it)->_etag = csyncIt->second->etag; - }*/ - (*it)->_errorString = tr("Not allowed to upload this file because it is read-only on the server, restoring"); - continue; - } - break; - } - case CSYNC_INSTRUCTION_REMOVE: { - const auto perms = getPermissions((*it)->_file); - if (perms.isNull()) { - // No permissions set - break; - } - if (!perms.hasPermission(RemotePermissions::CanDelete)) { - qCWarning(lcEngine) << "checkForPermission: RESTORING" << (*it)->_file; - (*it)->_instruction = CSYNC_INSTRUCTION_NEW; - (*it)->_direction = SyncFileItem::Down; - (*it)->_isRestoration = true; - (*it)->_errorString = tr("Not allowed to remove, restoring"); - - if ((*it)->isDirectory()) { - // restore all sub items - for (SyncFileItemVector::iterator it_next = it + 1; - it_next != syncItems.end() && (*it_next)->_file.startsWith(path); ++it_next) { - it = it_next; - - if ((*it)->_instruction != CSYNC_INSTRUCTION_REMOVE) { - qCWarning(lcEngine) << "non-removed job within a removed folder" - << (*it)->_file << (*it)->_instruction; - continue; - } - - qCWarning(lcEngine) << "checkForPermission: RESTORING" << (*it)->_file; - - (*it)->_instruction = CSYNC_INSTRUCTION_NEW; - (*it)->_direction = SyncFileItem::Down; - (*it)->_isRestoration = true; - (*it)->_errorString = tr("Not allowed to remove, restoring"); - } - } - } else if (perms.hasPermission(RemotePermissions::IsShared) - && perms.hasPermission(RemotePermissions::CanDelete)) { - // this is a top level shared dir which can be removed to unshare it, - // regardless if it is a read only share or not. - // To avoid that we try to restore files underneath this dir which have - // not delete permission we fast forward the iterator and leave the - // delete jobs intact. It is not physically tried to remove this files - // underneath, propagator sees that. - if ((*it)->isDirectory()) { - // put a more descriptive message if a top level share dir really is removed. - if (it == syncItems.begin() || !(path.startsWith((*(it - 1))->_file))) { - (*it)->_errorString = tr("Local files and share folder removed."); - } - - for (SyncFileItemVector::iterator it_next = it + 1; - it_next != syncItems.end() && (*it_next)->_file.startsWith(path); ++it_next) { - it = it_next; - } - } - } - break; - } - - case CSYNC_INSTRUCTION_RENAME: { - int slashPos = (*it)->_renameTarget.lastIndexOf('/'); - const QString parentDir = slashPos <= 0 ? "" : (*it)->_renameTarget.mid(0, slashPos); - const auto destPerms = getPermissions(parentDir); - const auto filePerms = getPermissions((*it)->_file); - - //true when it is just a rename in the same directory. (not a move) - const bool isRename = (*it)->_file.startsWith(parentDir) && (*it)->_file.lastIndexOf('/') == slashPos; - - const bool isForbiddenSubDirectoryCreation = (*it)->isDirectory() && !destPerms.hasPermission(RemotePermissions::CanAddSubDirectories); - const bool isForbiddenFileCreation = !(*it)->isDirectory() && !destPerms.hasPermission(RemotePermissions::CanAddFile); - - // Check if we are allowed to move to the destination. - bool destinationOK = true; - if (isRename || destPerms.isNull()) { - // no need to check for the destination dir permission - destinationOK = true; - } else if (isForbiddenSubDirectoryCreation || isForbiddenFileCreation) { - destinationOK = false; - } - - // check if we are allowed to move from the source - bool sourceOK = true; - if (!filePerms.isNull() - && ((isRename && !filePerms.hasPermission(RemotePermissions::CanRename)) - || (!isRename && !filePerms.hasPermission(RemotePermissions::CanMove)))) { - // We are not allowed to move or rename this file - sourceOK = false; - - if (filePerms.hasPermission(RemotePermissions::CanDelete) && destinationOK) { - // but we are allowed to delete it - // TODO! simulate delete & upload - } - } - -#ifdef OWNCLOUD_RESTORE_RENAME /* We don't like the idea of renaming behind user's back, as the user may be working with the files */ - if (!sourceOK && (!destinationOK || isRename) - // (not for directory because that's more complicated with the contents that needs to be adjusted) - && !(*it)->isDirectory()) { - // Both the source and the destination won't allow move. Move back to the original - std::swap((*it)->_file, (*it)->_renameTarget); - (*it)->_direction = SyncFileItem::Down; - (*it)->_errorString = tr("Move not allowed, item restored"); - (*it)->_isRestoration = true; - qCWarning(lcEngine) << "checkForPermission: MOVING BACK" << (*it)->_file; - // in case something does wrong, we will not do it next time - _journal->avoidRenamesOnNextSync((*it)->_file); - } else -#endif - if (!sourceOK || !destinationOK) { - // One of them is not possible, just throw an error - (*it)->_instruction = CSYNC_INSTRUCTION_ERROR; - (*it)->_status = SyncFileItem::NormalError; - const QString errorString = tr("Move not allowed because %1 is read-only").arg(sourceOK ? tr("the destination") : tr("the source")); - (*it)->_errorString = errorString; - - qCWarning(lcEngine) << "checkForPermission: ERROR MOVING" << (*it)->_file << errorString; - - // Avoid a rename on next sync: - // TODO: do the resolution now already so we don't need two sync - // At this point we would need to go back to the propagate phase on both remote to take - // the decision. - _journal->avoidRenamesOnNextSync((*it)->_file); - _anotherSyncNeeded = ImmediateFollowUp; - - - if ((*it)->isDirectory()) { - for (SyncFileItemVector::iterator it_next = it + 1; - it_next != syncItems.end() && (*it_next)->destination().startsWith(path); ++it_next) { - it = it_next; - (*it)->_instruction = CSYNC_INSTRUCTION_ERROR; - (*it)->_status = SyncFileItem::NormalError; - (*it)->_errorString = errorString; - qCWarning(lcEngine) << "checkForPermission: ERROR MOVING" << (*it)->_file; - } - } - } - break; - } - default: - break; - } - } -} - -RemotePermissions SyncEngine::getPermissions(const QString &file) const -{ - qFatal("FIXME"); - return RemotePermissions(); -} - void SyncEngine::restoreOldFiles(SyncFileItemVector &syncItems) { /* When the server is trying to send us lots of file in the past, this means that a backup diff --git a/test/testpermissions.cpp b/test/testpermissions.cpp index a5a3470b2..fdcef6860 100644 --- a/test/testpermissions.cpp +++ b/test/testpermissions.cpp @@ -196,11 +196,7 @@ private slots: //new directory should be uploaded fakeFolder.localModifier().rename("readonlyDirectory_PERM_M_/subdir_PERM_CK_", "normalDirectory_PERM_CKDNV_/subdir_PERM_CKDNV_"); applyPermissionsFromName(fakeFolder.remoteModifier()); - fakeFolder.syncOnce(); - if (fakeFolder.syncEngine().isAnotherSyncNeeded() == ImmediateFollowUp) { - QVERIFY(fakeFolder.syncOnce()); - } - assertCsyncJournalOk(fakeFolder.syncJournal()); + QVERIFY(fakeFolder.syncOnce()); currentLocalState = fakeFolder.currentLocalState(); // old name restored @@ -212,12 +208,14 @@ private slots: QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState()); + //###################################################################### qInfo( "rename a directory in a read only folder and move a directory to a read-only" ); // do a sync to update the database applyPermissionsFromName(fakeFolder.remoteModifier()); QVERIFY(fakeFolder.syncOnce()); + assertCsyncJournalOk(fakeFolder.syncJournal()); //1. rename a directory in a read only folder //Missing directory should be restored @@ -229,10 +227,6 @@ private slots: // error: can't upload to readonly! QVERIFY(!fakeFolder.syncOnce()); - if (fakeFolder.syncEngine().isAnotherSyncNeeded() == ImmediateFollowUp) { - QVERIFY(!fakeFolder.syncOnce()); - } - assertCsyncJournalOk(fakeFolder.syncJournal()); currentLocalState = fakeFolder.currentLocalState(); //1.