New Discovery Algo: Permsission check
authorOlivier Goffart <ogoffart@woboq.com>
Wed, 25 Jul 2018 16:31:36 +0000 (18:31 +0200)
committerKevin Ottens <kevin.ottens@nextcloud.com>
Tue, 15 Dec 2020 09:58:01 +0000 (10:58 +0100)
CMakeLists.txt
src/libsync/discovery.cpp
src/libsync/discovery.h
src/libsync/syncengine.cpp
test/testpermissions.cpp

index 8e5ddb8850e3c6e03fd72f941bad9f79c80d9883..383f00ae2362e6216ff46a30a5fecf8321b77616 100644 (file)
@@ -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)
index a579cc1a892a09f86227ef039e13170c791b29ec..0e79203351b8436e2d330d5895ec326e25dd2ec3 100644 (file)
@@ -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<ProcessDirectoryJob *>(_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()
 {
index 638aa902423a29eddc21b9ae898837432d83073f..c7f62e9c58e91b14d2735889629e937eb8b51761 100644 (file)
@@ -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<RemoteInfo> _serverEntries;
     QVector<LocalInfo> _localEntries;
+    RemotePermissions _rootPermissions;
     bool _hasServerEntries = false;
     bool _hasLocalEntries = false;
     int _pendingAsyncJobs = 0;
index 68b778a7cd8e3ce2f678828bd3ec787ba6f99626..dc8380a12083546fc0fa23a8075f63421f8e3a5f 100644 (file)
@@ -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
index a5a3470b247553d0faa32d62d016ef1ccc99581d..fdcef6860590b72a90d3ed54ee2536cbd23eaf26 100644 (file)
@@ -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.