Discovery: Handle the blacklistFiles from the server capabilities
authorOlivier Goffart <ogoffart@woboq.com>
Thu, 29 Nov 2018 16:00:16 +0000 (17:00 +0100)
committerKevin Ottens <kevin.ottens@nextcloud.com>
Tue, 15 Dec 2020 09:58:30 +0000 (10:58 +0100)
Issue #434

Ideally one could add the blacklist to the exlucde reggexp, but this
is simpler

src/csync/csync_exclude.h
src/libsync/capabilities.cpp
src/libsync/capabilities.h
src/libsync/discovery.cpp
src/libsync/discovery.h
src/libsync/discoveryphase.h
src/libsync/syncengine.cpp
test/testlocaldiscovery.cpp

index 0656371e792fe9ec91622a248b2db288e8e810c5..d06c5e107d35956531552daeb93de3c943d23694 100644 (file)
@@ -43,7 +43,8 @@ enum CSYNC_EXCLUDE_TYPE {
   CSYNC_FILE_EXCLUDE_HIDDEN,
   CSYNC_FILE_EXCLUDE_STAT_FAILED,
   CSYNC_FILE_EXCLUDE_CONFLICT,
-  CSYNC_FILE_EXCLUDE_CANNOT_ENCODE
+  CSYNC_FILE_EXCLUDE_CANNOT_ENCODE,
+  CSYNC_FILE_EXCLUDE_SERVER_BLACKLISTED,
 };
 
 class ExcludedFilesTest;
index b6a689fcdafe7d33cd3f78c55808a6823f7f89a6..1ea4a58dca39ef5003cc482a4e87f1def7f2ee1e 100644 (file)
@@ -208,6 +208,11 @@ bool Capabilities::uploadConflictFiles() const
     return _capabilities[QStringLiteral("uploadConflictFiles")].toBool();
 }
 
+QStringList Capabilities::blacklistedFiles() const
+{
+    return _capabilities["files"].toMap()["blacklisted_files"].toStringList();
+}
+
 /*-------------------------------------------------------------------------------------*/
 
 // Direct Editing
index dae0d586643a3ac4775f3f9fcbbca8f3d79d9cf2..e64f68d0b71f0477d3614dabc3fd8e7ec1a467a9 100644 (file)
@@ -126,6 +126,11 @@ public:
      */
     QString invalidFilenameRegex() const;
 
+    /**
+     * return the list of filename that should not be uploaded
+     */
+    QStringList blacklistedFiles() const;
+
     /**
      * Whether conflict files should remain local (default) or should be uploaded.
      */
index 64984f7ea137542a4251fb8938c68a94fab3056f..13f013efc5f5d9c015a14a331bcb63eb7b09ad5c 100644 (file)
@@ -142,7 +142,9 @@ void ProcessDirectoryJob::process()
         // local stat function.
         // Recall file shall not be ignored (#4420)
         bool isHidden = e.localEntry.isHidden || (f.first[0] == '.' && f.first != QLatin1String(".sys.admin#recall#"));
-        if (handleExcluded(path._target, e.localEntry.isDirectory || e.serverEntry.isDirectory, isHidden, e.localEntry.isSymLink))
+        if (handleExcluded(path._target, e.localEntry.name,
+                e.localEntry.isDirectory || e.serverEntry.isDirectory, isHidden,
+                e.localEntry.isSymLink))
             continue;
 
         if (_queryServer == InBlackList || _discoveryData->isInSelectiveSyncBlackList(path._original)) {
@@ -154,7 +156,7 @@ void ProcessDirectoryJob::process()
     QTimer::singleShot(0, _discoveryData, &DiscoveryPhase::scheduleMoreJobs);
 }
 
-bool ProcessDirectoryJob::handleExcluded(const QString &path, bool isDirectory, bool isHidden, bool isSymlink)
+bool ProcessDirectoryJob::handleExcluded(const QString &path, const QString &localName, bool isDirectory, bool isHidden, bool isSymlink)
 {
     auto excluded = _discoveryData->_excludes->traversalPatternMatch(path, isDirectory ? ItemTypeDirectory : ItemTypeFile);
 
@@ -169,6 +171,11 @@ bool ProcessDirectoryJob::handleExcluded(const QString &path, bool isDirectory,
     if (excluded == CSYNC_NOT_EXCLUDED && _discoveryData->_ignoreHiddenFiles && isHidden) {
         excluded = CSYNC_FILE_EXCLUDE_HIDDEN;
     }
+    if (excluded == CSYNC_NOT_EXCLUDED && !localName.isEmpty()
+            && _discoveryData->_serverBlacklistedFiles.contains(localName)) {
+        excluded = CSYNC_FILE_EXCLUDE_SERVER_BLACKLISTED;
+        isInvalidPattern = true;
+    }
 
     auto localCodec = QTextCodec::codecForLocale();
     if (localCodec->mibEnum() != 106) {
@@ -248,6 +255,9 @@ bool ProcessDirectoryJob::handleExcluded(const QString &path, bool isDirectory,
         case CSYNC_FILE_EXCLUDE_CANNOT_ENCODE:
             item->_errorString = tr("The filename cannot be encoded on your file system.");
             break;
+        case CSYNC_FILE_EXCLUDE_SERVER_BLACKLISTED:
+            item->_errorString = tr("The filename is blacklisted on the server.");
+            break;
         }
     }
 
index 99d0013b12f5a6ad0e540c88e83077b9c7011328..0ec44b9408454ab7cf163661825295f77f364576 100644 (file)
@@ -116,8 +116,10 @@ private:
      */
     void process();
 
-    // return true if the file is excluded
-    bool handleExcluded(const QString &path, bool isDirectory, bool isHidden, bool isSymlink);
+    // return true if the file is excluded.
+    // path is the full relative path of the file. localName is the base name of the local entry.
+    bool handleExcluded(const QString &path, const QString &localName, bool isDirectory,
+        bool isHidden, bool isSymlink);
 
     /** Reconcile local/remote/db information for a single item.
      *
index 6f6b4ffd6bb8d5c1488633387e9f30c98b4a25a9..738c2d2122b38eb58925fa5163dc10f0ac13c350 100644 (file)
@@ -170,6 +170,7 @@ public:
     QStringList _selectiveSyncWhiteList;
     ExcludedFiles *_excludes;
     QRegExp _invalidFilenameRx; // FIXME: maybe move in ExcludedFiles
+    QStringList _serverBlacklistedFiles; // The blacklist from the capabilities
     bool _ignoreHiddenFiles = false;
     std::function<bool(const QString &)> _shouldDiscoverLocaly;
 
index 418d494fcd1c4b8b39a9f6f1ebf0bdeceb7d61e0..ba1d0d6bae0e2901c50ba8ccc4e376139798b61b 100644 (file)
@@ -608,6 +608,7 @@ void SyncEngine::slotStartDiscovery()
     }
     if (!invalidFilenamePattern.isEmpty())
         _discoveryPhase->_invalidFilenameRx = QRegExp(invalidFilenamePattern);
+    _discoveryPhase->_serverBlacklistedFiles = _account->capabilities().blacklistedFiles();
     _discoveryPhase->_ignoreHiddenFiles = ignoreHiddenFiles();
 
     connect(_discoveryPhase.data(), &DiscoveryPhase::itemDiscovered, this, &SyncEngine::slotItemDiscovered);
index babc91bd8a8d3fc73aeeabfc972ca4e33d43a349..d1831a56da0ebcfdd263f0b5d1ed65d1c2f4861d 100644 (file)
@@ -185,7 +185,25 @@ private slots:
         QCOMPARE(fakeFolder.currentRemoteState(), expectedState);
     }
 
+    // Tests the behavior of invalid filename detection
+    void testServerBlacklist()
+    {
+        FakeFolder fakeFolder { FileInfo::A12_B12_C12_S12() };
+        QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
+
+        fakeFolder.syncEngine().account()->setCapabilities({ { "files",
+            QVariantMap { { "blacklisted_files", QVariantList { ".foo", "bar" } } } } });
+        fakeFolder.localModifier().insert("C/.foo");
+        fakeFolder.localModifier().insert("C/bar");
+        fakeFolder.localModifier().insert("C/moo");
+        fakeFolder.localModifier().insert("C/.moo");
 
+        QVERIFY(fakeFolder.syncOnce());
+        QVERIFY(fakeFolder.currentRemoteState().find("C/moo"));
+        QVERIFY(fakeFolder.currentRemoteState().find("C/.moo"));
+        QVERIFY(!fakeFolder.currentRemoteState().find("C/.foo"));
+        QVERIFY(!fakeFolder.currentRemoteState().find("C/bar"));
+    }
 };
 
 QTEST_GUILESS_MAIN(TestLocalDiscovery)