Exclude: do everything with QString wiuthout converting to char*
authorOlivier Goffart <ogoffart@woboq.com>
Thu, 26 Nov 2020 15:22:50 +0000 (16:22 +0100)
committerKevin Ottens <kevin.ottens@nextcloud.com>
Tue, 15 Dec 2020 09:58:19 +0000 (10:58 +0100)
src/csync/csync_exclude.cpp
src/csync/csync_exclude.h
src/libsync/capabilities.cpp
src/libsync/discovery.cpp
test/csync/csync_tests/check_csync_exclude.cpp

index 2398d10dd02babc8154e1f4837a02da76f7e8ce2..c21b1e00c601808e10902aa9871d147796b0c16c 100644 (file)
@@ -93,9 +93,9 @@ static const char *win_reserved_words_n[] = { "CLOCK$", "$Recycle.Bin" };
  * @param file_name filename
  * @return true if file is reserved, false otherwise
  */
-bool csync_is_windows_reserved_word(const char *filename)
+bool csync_is_windows_reserved_word(const QStringRef &filename)
 {
-    size_t len_filename = strlen(filename);
+    size_t len_filename = filename.size();
 
     // Drive letters
     if (len_filename == 2 && filename[1] == ':') {
@@ -109,7 +109,7 @@ bool csync_is_windows_reserved_word(const char *filename)
 
     if (len_filename == 3 || (len_filename > 3 && filename[3] == '.')) {
         for (const char *word : win_reserved_words_3) {
-            if (c_strncasecmp(filename, word, 3) == 0) {
+            if (filename.left(3).compare(QLatin1String(word), Qt::CaseInsensitive) == 0) {
                 return true;
             }
         }
@@ -117,15 +117,14 @@ bool csync_is_windows_reserved_word(const char *filename)
 
     if (len_filename == 4 || (len_filename > 4 && filename[4] == '.')) {
         for (const char *word : win_reserved_words_4) {
-            if (c_strncasecmp(filename, word, 4) == 0) {
+            if (filename.left(4).compare(QLatin1String(word), Qt::CaseInsensitive) == 0) {
                 return true;
             }
         }
     }
 
     for (const char *word : win_reserved_words_n) {
-        size_t len_word = strlen(word);
-        if (len_word == len_filename && c_strncasecmp(filename, word, len_word) == 0) {
+        if (filename.compare(QLatin1String(word), Qt::CaseInsensitive) == 0) {
             return true;
         }
     }
@@ -133,43 +132,30 @@ bool csync_is_windows_reserved_word(const char *filename)
     return false;
 }
 
-static CSYNC_EXCLUDE_TYPE _csync_excluded_common(const char *path, bool excludeConflictFiles)
+static CSYNC_EXCLUDE_TYPE _csync_excluded_common(const QString &path, bool excludeConflictFiles)
 {
-    const char *bname = nullptr;
-    size_t blen = 0;
     int rc = -1;
     CSYNC_EXCLUDE_TYPE match = CSYNC_NOT_EXCLUDED;
 
     /* split up the path */
-    bname = strrchr(path, '/');
-    if (bname) {
-        bname += 1; // don't include the /
-    } else {
-        bname = path;
+    QStringRef bname(&path);
+    int lastSlash = path.lastIndexOf('/');
+    if (lastSlash >= 0) {
+        bname = path.midRef(lastSlash + 1);
     }
-    blen = strlen(bname);
 
+    size_t blen = bname.size();
     // 9 = strlen(".sync_.db")
     if (blen >= 9 && bname[0] == '.') {
-        rc = csync_fnmatch("._sync_*.db*", bname, 0);
-        if (rc == 0) {
-            match = CSYNC_FILE_SILENTLY_EXCLUDED;
-            goto out;
-        }
-        rc = csync_fnmatch(".sync_*.db*", bname, 0);
-        if (rc == 0) {
-            match = CSYNC_FILE_SILENTLY_EXCLUDED;
-            goto out;
-        }
-        rc = csync_fnmatch(".csync_journal.db*", bname, 0);
-        if (rc == 0) {
-            match = CSYNC_FILE_SILENTLY_EXCLUDED;
-            goto out;
+        if (bname.contains(QLatin1String(".db"))) {
+            if (bname.startsWith(QLatin1String("._sync_"), Qt::CaseInsensitive)  // "._sync_*.db*"
+                || bname.startsWith(QLatin1String(".sync_"), Qt::CaseInsensitive) // ".sync_*.db*"
+                || bname.startsWith(QLatin1String(".csync_journal.db"), Qt::CaseInsensitive)) { // ".csync_journal.db*"
+                return CSYNC_FILE_SILENTLY_EXCLUDED;
+            }
         }
-        rc = csync_fnmatch(".owncloudsync.log*", bname, 0);
-        if (rc == 0) {
-            match = CSYNC_FILE_SILENTLY_EXCLUDED;
-            goto out;
+        if (bname.startsWith(QLatin1String(".owncloudsync.log"), Qt::CaseInsensitive)) { // ".owncloudsync.log*"
+            return CSYNC_FILE_SILENTLY_EXCLUDED;
         }
     }
 
@@ -201,8 +187,8 @@ static CSYNC_EXCLUDE_TYPE _csync_excluded_common(const char *path, bool excludeC
     }
 
     // Filter out characters not allowed in a filename on windows
-    for (const char *p = path; *p; p++) {
-        switch (*p) {
+    for (auto p : path) {
+        switch (p.unicode()) {
         case '\\':
         case ':':
         case '?':
@@ -221,14 +207,14 @@ static CSYNC_EXCLUDE_TYPE _csync_excluded_common(const char *path, bool excludeC
 
     /* We create a Desktop.ini on Windows for the sidebar icon, make sure we don't sync it. */
     if (blen == 11 && path == bname) {
-        rc = csync_fnmatch("Desktop.ini", bname, 0);
+        rc = bname.compare(QLatin1String("Desktop.ini"), Qt::CaseInsensitive);
         if (rc == 0) {
             match = CSYNC_FILE_SILENTLY_EXCLUDED;
             goto out;
         }
     }
 
-    if (excludeConflictFiles && OCC::Utility::isConflictFile(bname)) {
+    if (excludeConflictFiles && OCC::Utility::isConflictFile(path)) {
         match = CSYNC_FILE_EXCLUDE_CONFLICT;
         goto out;
     }
@@ -439,10 +425,10 @@ bool ExcludedFiles::isExcluded(
         relativePath.chop(1);
     }
 
-    return fullPatternMatch(relativePath.toUtf8(), type) != CSYNC_NOT_EXCLUDED;
+    return fullPatternMatch(relativePath, type) != CSYNC_NOT_EXCLUDED;
 }
 
-CSYNC_EXCLUDE_TYPE ExcludedFiles::traversalPatternMatch(const char *path, ItemType filetype)
+CSYNC_EXCLUDE_TYPE ExcludedFiles::traversalPatternMatch(const QString &path, ItemType filetype)
 {
     auto match = _csync_excluded_common(path, _excludeConflictFiles);
     if (match != CSYNC_NOT_EXCLUDED)
@@ -463,16 +449,13 @@ CSYNC_EXCLUDE_TYPE ExcludedFiles::traversalPatternMatch(const char *path, ItemTy
 
     // Check the bname part of the path to see whether the full
     // regex should be run.
-
-    const char *bname = strrchr(path, '/');
-    if (bname) {
-        bname += 1; // don't include the /
-    } else {
-        bname = path;
+    QStringRef bnameStr(&path);
+    int lastSlash = path.lastIndexOf('/');
+    if (lastSlash >= 0) {
+        bnameStr = path.midRef(lastSlash + 1);
     }
-    QString bnameStr = QString::fromUtf8(bname);
 
-    QByteArray basePath(_localPath.toUtf8() + path);
+    QByteArray basePath(_localPath.toUtf8() + path.toUtf8());
     while (basePath.size() > _localPath.size()) {
         basePath = leftIncludeLast(basePath, '/');
         QRegularExpressionMatch m;
@@ -496,17 +479,16 @@ CSYNC_EXCLUDE_TYPE ExcludedFiles::traversalPatternMatch(const char *path, ItemTy
     }
 
     // third capture: full path matching is triggered
-    QString pathStr = QString::fromUtf8(path);
-    basePath = _localPath.toUtf8() + path;
+    basePath = _localPath.toUtf8() + path.toUtf8();
     while (basePath.size() > _localPath.size()) {
         basePath = leftIncludeLast(basePath, '/');
         QRegularExpressionMatch m;
         if (filetype == ItemTypeDirectory
             && _fullTraversalRegexDir.contains(basePath)) {
-            m = _fullTraversalRegexDir[basePath].match(pathStr);
+            m = _fullTraversalRegexDir[basePath].match(path);
         } else if (filetype == ItemTypeFile
             && _fullTraversalRegexFile.contains(basePath)) {
-            m = _fullTraversalRegexFile[basePath].match(pathStr);
+            m = _fullTraversalRegexFile[basePath].match(path);
         } else {
             continue;
         }
@@ -522,21 +504,21 @@ CSYNC_EXCLUDE_TYPE ExcludedFiles::traversalPatternMatch(const char *path, ItemTy
     return CSYNC_NOT_EXCLUDED;
 }
 
-CSYNC_EXCLUDE_TYPE ExcludedFiles::fullPatternMatch(const char *path, ItemType filetype) const
+CSYNC_EXCLUDE_TYPE ExcludedFiles::fullPatternMatch(const QString &p, ItemType filetype) const
 {
-    auto match = _csync_excluded_common(path, _excludeConflictFiles);
+    auto match = _csync_excluded_common(p, _excludeConflictFiles);
     if (match != CSYNC_NOT_EXCLUDED)
         return match;
     if (_allExcludes.isEmpty())
         return CSYNC_NOT_EXCLUDED;
 
-    QString p = QString::fromUtf8(path);
     // `path` seems to always be relative to `_localPath`, the tests however have not been
     // written that way... this makes the tests happy for now. TODO Fix the tests at some point
+    QString path = p;
     if (path[0] == '/')
-        ++path;
+        path = path.mid(1);
 
-    QByteArray basePath(_localPath.toUtf8() + path);
+    QByteArray basePath(_localPath.toUtf8() + path.toUtf8());
     while (basePath.size() > _localPath.size()) {
         basePath = leftIncludeLast(basePath, '/');
         QRegularExpressionMatch m;
index 10eb65e3636c9f359814fbf8e30023e3373d6c86..4f68a5d0bf3d4911980da970bb3e5015e2a20f58 100644 (file)
@@ -137,7 +137,7 @@ public:
      * Note that this only matches patterns. It does not check whether the file
      * or directory pointed to is hidden (or whether it even exists).
      */
-    CSYNC_EXCLUDE_TYPE traversalPatternMatch(const char *path, ItemType filetype);
+    CSYNC_EXCLUDE_TYPE traversalPatternMatch(const QString &path, ItemType filetype);
 
 public slots:
     /**
@@ -175,7 +175,7 @@ private:
      * Note that this only matches patterns. It does not check whether the file
      * or directory pointed to is hidden (or whether it even exists).
      */
-    CSYNC_EXCLUDE_TYPE fullPatternMatch(const char *path, ItemType filetype) const;
+    CSYNC_EXCLUDE_TYPE fullPatternMatch(const QString &path, ItemType filetype) const;
 
     // Our BasePath need to end with '/'
     class BasePathByteArray : public QByteArray
index 47b96068fa15e67981b2f0810fbf43a78f8cae32..b6a689fcdafe7d33cd3f78c55808a6823f7f89a6 100644 (file)
@@ -195,7 +195,7 @@ QList<int> Capabilities::httpErrorCodesThatResetFailingChunkedUploads() const
 
 QString Capabilities::invalidFilenameRegex() const
 {
-    return _capabilities["dav"].toMap()["invalidFilenameRegex"].toString();
+    return _capabilities[QStringLiteral("dav")].toMap()[QStringLiteral("invalidFilenameRegex")].toString();
 }
 
 bool Capabilities::uploadConflictFiles() const
@@ -205,7 +205,7 @@ bool Capabilities::uploadConflictFiles() const
     if (envIsSet)
         return envValue != 0;
 
-    return _capabilities["uploadConflictFiles"].toBool();
+    return _capabilities[QStringLiteral("uploadConflictFiles")].toBool();
 }
 
 /*-------------------------------------------------------------------------------------*/
index 4abb07cb7d625ec02f1dad3e967ce9980b6d26ea..79560e7856d247f2a686ad6236f2a5bd52764a38 100644 (file)
@@ -155,8 +155,7 @@ void ProcessDirectoryJob::process()
 
 bool ProcessDirectoryJob::handleExcluded(const QString &path, bool isDirectory, bool isHidden, bool isSymlink)
 {
-    // FIXME! call directly, without char* conversion
-    auto excluded = _discoveryData->_excludes->traversalPatternMatch(path.toUtf8(), isDirectory ? ItemTypeDirectory : ItemTypeFile);
+    auto excluded = _discoveryData->_excludes->traversalPatternMatch(path, isDirectory ? ItemTypeDirectory : ItemTypeFile);
 
     // FIXME: move to ExcludedFiles 's regexp ?
     bool isInvalidPattern = false;
index 61f7283e2526cb09c1e8cde27fa9fb007bff5ac8..c4d9a91d9a2fdff889fade5d148e0113210b26ff 100644 (file)
@@ -583,6 +583,11 @@ static void check_csync_bname_trigger(void **)
 
 static void check_csync_is_windows_reserved_word(void **)
 {
+    auto csync_is_windows_reserved_word = [](const char *fn) {
+        QString s = QString::fromLatin1(fn);
+        return ::csync_is_windows_reserved_word(&s);
+    };
+
     assert_true(csync_is_windows_reserved_word("CON"));
     assert_true(csync_is_windows_reserved_word("con"));
     assert_true(csync_is_windows_reserved_word("CON."));