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 72809ef5b1

See #6287, #5676, #5719
See https://bugreports.qt.io/browse/QTBUG-6925
This commit is contained in:
Christian Kamm 2018-01-10 11:40:02 +01:00 committed by ckamm
parent a476c5420a
commit 7d70f1becb
2 changed files with 61 additions and 3 deletions

View file

@ -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;
}
}

View file

@ -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)