Handle Encoding Problems

TestSyncEngine now passes
This commit is contained in:
Olivier Goffart 2018-07-10 16:56:15 +02:00 committed by Kevin Ottens
parent 501da58b10
commit 92ddc60900
No known key found for this signature in database
GPG key ID: 074BBBCB8DECC9E2
3 changed files with 30 additions and 42 deletions

View file

@ -148,21 +148,6 @@ static int _csync_detect_update(CSYNC *ctx, std::unique_ptr<csync_file_stat_t> f
}
}
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.
*
* 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')) {
qCInfo(lcUpdate, "cannot encode %s to local encoding %d",
fs->path.constData(), localCodec->mibEnum());
excluded = CSYNC_FILE_EXCLUDE_CANNOT_ENCODE;
}
}
if (fs->type == ItemTypeFile ) {
if (fs->modtime == 0) {

View file

@ -19,10 +19,12 @@
#include <algorithm>
#include <set>
#include <QDirIterator>
#include <QTextCodec>
#include "vio/csync_vio_local.h"
#include "common/checksums.h"
#include "csync_exclude.h"
namespace OCC {
Q_LOGGING_CATEGORY(lcDisco, "sync.discovery", QtInfoMsg)
@ -97,7 +99,20 @@ void ProcessDirectoryJob::start()
}
while (auto dirent = csync_vio_local_readdir(dh)) {
LocalInfo i;
i.name = QString::fromUtf8(dirent->path); // FIXME! conversion errors
static QTextCodec *codec = QTextCodec::codecForName("UTF-8");
ASSERT(codec);
QTextCodec::ConverterState state;
i.name = codec->toUnicode(dirent->path, dirent->path.size(), &state);
if (state.invalidChars > 0 || state.remainingChars > 0) {
_childIgnored = true;
auto item = SyncFileItemPtr::create();
item->_file = _currentFolder + i.name;
item->_instruction = CSYNC_INSTRUCTION_IGNORE;
item->_status = SyncFileItem::NormalError;
item->_errorString = tr("Filename encoding is not valid");
emit itemDiscovered(item);
continue;
}
i.modtime = dirent->modtime;
i.size = dirent->size;
i.inode = dirent->inode;
@ -194,6 +209,20 @@ bool ProcessDirectoryJob::handleExcluded(const QString &path, bool isDirectory,
excluded = CSYNC_FILE_EXCLUDE_HIDDEN;
}
auto localCodec = QTextCodec::codecForLocale();
if (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.
//
// 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(path).contains('\0')) {
qCWarning(lcDisco) << "Cannot encode " << path << " to local encoding " << localCodec->name();
excluded = CSYNC_FILE_EXCLUDE_CANNOT_ENCODE;
}
}
if (excluded == CSYNC_NOT_EXCLUDED /* FIXME && item->_type != ItemTypeSoftLink */) {
return false;
} else if (excluded == CSYNC_FILE_SILENTLY_EXCLUDED || excluded == CSYNC_FILE_EXCLUDE_AND_REMOVE) {

View file

@ -387,28 +387,7 @@ int SyncEngine::treewalkFile(csync_file_stat_t * /*file*/, csync_file_stat_t * /
// Decode utf8 path and rename_path QByteArrays to QStrings
QString fileUtf8;
QString renameTarget;
bool utf8DecodeError = false;
{
const auto toUnicode = [](QByteArray utf8, QString *result) {
static QTextCodec *codec = QTextCodec::codecForName("UTF-8");
ASSERT(codec);
QTextCodec::ConverterState state;
*result = codec->toUnicode(utf8, utf8.size(), &state);
return !(state.invalidChars > 0 || state.remainingChars > 0);
};
if (!toUnicode(file->path, &fileUtf8)) {
qCWarning(lcEngine) << "File ignored because of invalid utf-8 sequence: " << file->path;
instruction = CSYNC_INSTRUCTION_IGNORE;
utf8DecodeError = true;
}
if (!toUnicode(file->rename_path, &renameTarget)) {
qCWarning(lcEngine) << "File ignored because of invalid utf-8 sequence in the rename_path: " << file->path << file->rename_path;
instruction = CSYNC_INSTRUCTION_IGNORE;
utf8DecodeError = true;
}
}
// key is the handle that the SyncFileItem will have in the map.
QString key = fileUtf8;
@ -513,11 +492,6 @@ int SyncEngine::treewalkFile(csync_file_stat_t * /*file*/, csync_file_stat_t * /
}
if (item->_instruction == CSYNC_INSTRUCTION_IGNORE && utf8DecodeError) {
item->_status = SyncFileItem::NormalError;
//item->_instruction = CSYNC_INSTRUCTION_ERROR;
item->_errorString = tr("Filename encoding is not valid");
}
bool isDirectory = file->type == ItemTypeDirectory;