Переглянути джерело

Ignore files that can't be encoded for the filesystem

There's an upstream bug where QTextCodec::canEncode returns true even
though it should be false. This works around that issue and adds a test.

The original work was done in 72809ef5b1aeb578976e4360ed267ac1c4d71ea6

See #6287, #5676, #5719
See https://bugreports.qt.io/browse/QTBUG-6925
Christian Kamm 8 роки тому
батько
коміт
7d70f1becb
2 змінених файлів з 61 додано та 3 видалено
  1. 11 3
      src/csync/csync_update.cpp
  2. 50 0
      test/testsyncengine.cpp

+ 11 - 3
src/csync/csync_update.cpp

@@ -150,10 +150,18 @@ static int _csync_detect_update(CSYNC *ctx, std::unique_ptr<csync_file_stat_t> f
       }
   }
 
-  if (ctx->current == REMOTE_REPLICA && QTextCodec::codecForLocale()->mibEnum() != 106) {
+  auto localCodec = QTextCodec::codecForLocale();
+  if (ctx->current == REMOTE_REPLICA && localCodec->mibEnum() != 106) {
       /* If the locale codec is not UTF-8, we must check that the filename from the server can
-       * be encoded in the local file system. */
-      if (!QTextCodec::codecForLocale()->canEncode(QString::fromUtf8(fs->path))) {
+       * be encoded in the local file system.
+       *
+       * We cannot use QTextCodec::canEncode() since that can incorrectly return true, see
+       * https://bugreports.qt.io/browse/QTBUG-6925.
+       */
+      QTextEncoder encoder(localCodec, QTextCodec::ConvertInvalidToNull);
+      if (encoder.fromUnicode(QString::fromUtf8(fs->path)).contains('\0')) {
+          qCDebug(lcUpdate, "cannot encode %s to local encoding %d",
+              fs->path.constData(), localCodec->mibEnum());
           excluded = CSYNC_FILE_EXCLUDE_CANNOT_ENCODE;
       }
   }

+ 50 - 0
test/testsyncengine.cpp

@@ -586,6 +586,56 @@ private slots:
         QVERIFY(localFileExists("A/.hidden"));
         QVERIFY(fakeFolder.currentRemoteState().find("B/.hidden"));
     }
+
+    void testNoLocalEncoding()
+    {
+        auto utf8Locale = QTextCodec::codecForLocale();
+        if (utf8Locale->mibEnum() != 106) {
+            QSKIP("Test only works for UTF8 locale");
+        }
+
+        FakeFolder fakeFolder{ FileInfo::A12_B12_C12_S12() };
+        QVERIFY(fakeFolder.syncOnce());
+        QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
+
+        // Utf8 locale can sync both
+        fakeFolder.remoteModifier().insert("A/tößt");
+        fakeFolder.remoteModifier().insert("A/t𠜎t");
+        QVERIFY(fakeFolder.syncOnce());
+        QVERIFY(fakeFolder.currentLocalState().find("A/tößt"));
+        QVERIFY(fakeFolder.currentLocalState().find("A/t𠜎t"));
+
+        // Try again with a locale that can represent ö but not 𠜎 (4-byte utf8).
+        QTextCodec::setCodecForLocale(QTextCodec::codecForName("ISO-8859-15"));
+        QVERIFY(QTextCodec::codecForLocale()->mibEnum() == 111);
+
+        fakeFolder.remoteModifier().insert("B/tößt");
+        fakeFolder.remoteModifier().insert("B/t𠜎t");
+        QVERIFY(fakeFolder.syncOnce());
+        QVERIFY(fakeFolder.currentLocalState().find("B/tößt"));
+        QVERIFY(!fakeFolder.currentLocalState().find("B/t𠜎t"));
+        QVERIFY(!fakeFolder.currentLocalState().find("B/t?t"));
+        QVERIFY(!fakeFolder.currentLocalState().find("B/t??t"));
+        QVERIFY(!fakeFolder.currentLocalState().find("B/t???t"));
+        QVERIFY(!fakeFolder.currentLocalState().find("B/t????t"));
+        QVERIFY(fakeFolder.syncOnce());
+        QVERIFY(fakeFolder.currentRemoteState().find("B/tößt"));
+        QVERIFY(fakeFolder.currentRemoteState().find("B/t𠜎t"));
+
+        // Try again with plain ascii
+        QTextCodec::setCodecForLocale(QTextCodec::codecForName("ASCII"));
+        QVERIFY(QTextCodec::codecForLocale()->mibEnum() == 3);
+
+        fakeFolder.remoteModifier().insert("C/tößt");
+        QVERIFY(fakeFolder.syncOnce());
+        QVERIFY(!fakeFolder.currentLocalState().find("C/tößt"));
+        QVERIFY(!fakeFolder.currentLocalState().find("C/t??t"));
+        QVERIFY(!fakeFolder.currentLocalState().find("C/t????t"));
+        QVERIFY(fakeFolder.syncOnce());
+        QVERIFY(fakeFolder.currentRemoteState().find("C/tößt"));
+
+        QTextCodec::setCodecForLocale(utf8Locale);
+    }
 };
 
 QTEST_GUILESS_MAIN(TestSyncEngine)