New Discovery algorithm
authorOlivier Goffart <ogoffart@woboq.com>
Mon, 16 Jul 2018 16:35:35 +0000 (18:35 +0200)
committerKevin Ottens <kevin.ottens@nextcloud.com>
Tue, 15 Dec 2020 09:57:58 +0000 (10:57 +0100)
Some error handling. In particular for the case where there is a conflict
between files and directories.

SyncEngineTest and SyncMoveTest passes

src/csync/csync_update.cpp
src/libsync/discovery.cpp
src/libsync/discoveryphase.h
src/libsync/syncengine.cpp

index f440dcdc7c94f5c0c8bd6bea8077e1fe50a6bd66..eb1395a67905983161d57891330085865582536c 100644 (file)
@@ -547,17 +547,10 @@ int csync_ftw(CSYNC *ctx, const char *uri, csync_walker_fn fn,
       }
       /* permission denied */
       ctx->status_code = csync_errno_to_status(errno, CSYNC_STATUS_OPENDIR_ERROR);
-      if (errno == EACCES) {
-          qCWarning(lcUpdate, "Permission denied.");
-          if (mark_current_item_ignored(ctx, previous_fs, CSYNC_STATUS_PERMISSION_DENIED)) {
-              return 0;
-          }
-      } else if(errno == ENOENT) {
-          ctx->error_string = QString::fromUtf8(uri);
-      }
+
       // 403 Forbidden can be sent by the server if the file firewall is active.
       // A file or directory should be ignored and sync must continue. See #3490
-      else if(errno == ERRNO_FORBIDDEN) {
+      if (errno == ERRNO_FORBIDDEN) {
           qCWarning(lcUpdate, "Directory access Forbidden (File Firewall?)");
           if( mark_current_item_ignored(ctx, previous_fs, CSYNC_STATUS_FORBIDDEN) ) {
               return 0;
index 726ac937925d9967bbcc3cb13e6a173a732688b2..4387826b669fcf1e76b3a8b8d02af8ba8fd9ba0d 100644 (file)
@@ -64,8 +64,9 @@ void ProcessDirectoryJob::start()
 {
     qCInfo(lcDisco) << "STARTING" << _currentFolder._server << _queryServer << _currentFolder._local << _queryLocal;
 
+    DiscoverServerJob *serverJob = nullptr;
     if (_queryServer == NormalQuery) {
-        auto serverJob = new DiscoverServerJob(_discoveryData->_account, _discoveryData->_remoteFolder + _currentFolder._server, this);
+        serverJob = new DiscoverServerJob(_discoveryData->_account, _discoveryData->_remoteFolder + _currentFolder._server, this);
         connect(serverJob, &DiscoverServerJob::finished, this, [this](const auto &results) {
             if (results) {
                 _serverEntries = *results;
@@ -92,9 +93,36 @@ void ProcessDirectoryJob::start()
         }*/
         auto dh = csync_vio_local_opendir((_discoveryData->_localDir + _currentFolder._local).toUtf8());
         if (!dh) {
-            qDebug() << "COULD NOT OPEN" << (_discoveryData->_localDir + _currentFolder._local);
-            qFatal("TODO: ERROR HANDLING");
-            // should be the same as in csync_update;
+            qCInfo(lcDisco) << "Error while opening directory" << (_discoveryData->_localDir + _currentFolder._local) << errno;
+            serverJob->abort();
+            QString errorString = tr("Error while opening directory %1").arg(_discoveryData->_localDir + _currentFolder._local);
+            if (errno == EACCES) {
+                errorString = tr("Directory not accessible on client, permission denied");
+                if (_dirItem) {
+                    _dirItem->_instruction = CSYNC_INSTRUCTION_IGNORE;
+                    _dirItem->_errorString = errorString;
+                    emit finished();
+                    return;
+                }
+            } else if (errno == ENOENT) {
+                errorString = tr("Directory not found: %1").arg(_discoveryData->_localDir + _currentFolder._local);
+                if (_dirItem) {
+                    _dirItem->_instruction = CSYNC_INSTRUCTION_IGNORE;
+                    _dirItem->_errorString = errorString;
+                    emit finished();
+                    return;
+                }
+            } else if (errno == ENOTDIR) {
+                // Not a directory..
+                // Just consider it is empty
+                _hasLocalEntries = true;
+                if (_hasServerEntries)
+                    process();
+                return;
+            }
+            emit _discoveryData->fatalError(errorString);
+            emit finished();
+            return;
         }
         while (auto dirent = csync_vio_local_readdir(dh)) {
             LocalInfo i;
@@ -434,12 +462,12 @@ void ProcessDirectoryJob::processFile(PathTuple path,
                             qCInfo(lcDisco) << "Local file does not exist anymore." << originalPath;
                             return;
                         }
-                        if (buf.modtime != base._modtime || buf.size != base._fileSize) {
+                        if (buf.modtime != base._modtime || buf.size != base._fileSize || buf.type != ItemTypeFile) {
                             qCInfo(lcDisco) << "File has changed locally, not a rename." << originalPath;
                             return;
                         }
                     } else {
-                        if (!QFile::exists(_discoveryData->_localDir + originalPath)) {
+                        if (!QFileInfo(_discoveryData->_localDir + originalPath).isDir()) {
                             qCInfo(lcDisco) << "Local directory does not exist anymore." << originalPath;
                             return;
                         }
index 51b2fc16f86339f559f4f9013d028119cfd02c6d..4b09f6fc602d307ae5fe91c2623c804dd00b7dba 100644 (file)
@@ -123,7 +123,7 @@ public:
     QString adjustRenamedPath(const QString &original) const;
 
 signals:
-    void finished(int result);
+    void fatalError(const QString &errorString);
     void folderDiscovered(bool local, QString folderUrl);
 
     // A new folder was discovered and was not synced because of the confirmation feature
index 2d9ae138fed58beda1d16a93ada46ba3f216ffec..56130442e5929fc018fe009f4ee64d3919eca62f 100644 (file)
@@ -558,10 +558,6 @@ int SyncEngine::treewalkFile(csync_file_stat_t * /*file*/, csync_file_stat_t * /
         item->_status = SyncFileItem::SoftError;
         _temporarilyUnavailablePaths.insert(item->_file);
         break;
-    case CSYNC_STATUS_PERMISSION_DENIED:
-        item->_errorString = QLatin1String("Directory not accessible on client, permission denied.");
-        item->_status = SyncFileItem::SoftError;
-        break;
 
     }
 
@@ -920,7 +916,10 @@ void SyncEngine::slotStartDiscovery()
 
     connect(_discoveryPhase.data(), &DiscoveryPhase::folderDiscovered, this, &SyncEngine::slotFolderDiscovered);
     connect(_discoveryPhase.data(), &DiscoveryPhase::newBigFolder, this, &SyncEngine::newBigFolder);
-
+    connect(_discoveryPhase.data(), &DiscoveryPhase::fatalError, this, [this](const QString &errorString) {
+        csyncError(errorString);
+        finalize(false);
+    });
 
     _discoveryJob = new ProcessDirectoryJob(SyncFileItemPtr(), ProcessDirectoryJob::NormalQuery, ProcessDirectoryJob::NormalQuery,
         _discoveryPhase.data(), this);