diff --git a/src/dfm-search/dfm-search-client/main.cpp b/src/dfm-search/dfm-search-client/main.cpp index 7865ca9..e3105c4 100644 --- a/src/dfm-search/dfm-search-client/main.cpp +++ b/src/dfm-search/dfm-search-client/main.cpp @@ -24,6 +24,7 @@ #include #include #include +#include "../dfm-search-lib/utils/filenameblacklistmatcher.h" using namespace dfmsearch; @@ -522,6 +523,56 @@ void testAnythingStatus() */ } +void doFileNameBlacklistMatchTest(const std::string &caseName, + const QString &inputPath, + const QStringList &blacklistEntries, + bool expected) +{ + const bool actual = Global::BlacklistMatcher::isPathBlacklisted(inputPath, blacklistEntries); + std::cout << "文件名黑名单测试 [" << caseName << "]\t" + << "输入路径: " << inputPath.toStdString() << "\t" + << "黑名单: " << blacklistEntries.join(", ").toStdString() << "\t" + << "预期结果: " << (expected ? "命中" : "不命中") << "\t" + << "实际结果: " << (actual ? "命中" : "不命中") << "\t" + << "状态: " << (actual == expected ? "通过" : "失败") << "\n" + << "---------------------------------\n"; +} + +void testFileNameBlacklistMatcher() +{ + std::cout << "====== 开始文件名黑名单规则测试 ======\n"; + + doFileNameBlacklistMatchTest("绝对路径-自身命中", + "/home/test/workspace", + { "/home/test/workspace" }, + true); + + doFileNameBlacklistMatchTest("绝对路径-子路径命中", + "/home/test/workspace/a.txt", + { "/home/test/workspace" }, + true); + + doFileNameBlacklistMatchTest("绝对路径-边界不误匹配", + "/home/test/workspace2", + { "/home/test/workspace" }, + false); + + doFileNameBlacklistMatchTest("目录名-直接命中", + "/home/test/workspace", + { "workspace" }, + true); + + doFileNameBlacklistMatchTest("目录名-深层命中", + "/home/test/aa/bb/workspace", + { "workspace" }, + true); + + doFileNameBlacklistMatchTest("目录名-不命中相似名称", + "/home/test/aa/bb/myworkspace", + { "workspace" }, + false); +} + int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); @@ -531,6 +582,7 @@ int main(int argc, char *argv[]) testPinyin(); testPinyinAcronym(); testAnythingStatus(); + testFileNameBlacklistMatcher(); #endif QCommandLineParser parser; diff --git a/src/dfm-search/dfm-search-lib/utils/filenameblacklistmatcher.cpp b/src/dfm-search/dfm-search-lib/utils/filenameblacklistmatcher.cpp new file mode 100644 index 0000000..f997ef4 --- /dev/null +++ b/src/dfm-search/dfm-search-lib/utils/filenameblacklistmatcher.cpp @@ -0,0 +1,59 @@ +// SPDX-FileCopyrightText: 2025 - 2026 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later +#include "filenameblacklistmatcher.h" + +#include + +DFM_SEARCH_BEGIN_NS +namespace Global { +namespace BlacklistMatcher { + +QString normalizePathForBlacklistMatch(const QString &path) +{ + return QDir::cleanPath(path.trimmed()); +} + +static bool isAbsolutePathMatch(const QString &normalizedPath, const QString &blacklistAbsolutePath) +{ + const QString normalizedRulePath = normalizePathForBlacklistMatch(blacklistAbsolutePath); + if (normalizedRulePath.isEmpty()) { + return false; + } + + if (normalizedRulePath == "/") { + return normalizedPath.startsWith('/'); + } + + return normalizedPath == normalizedRulePath || normalizedPath.startsWith(normalizedRulePath + '/'); +} + +bool isPathBlacklisted(const QString &inputPath, const QStringList &blacklistEntries) +{ + const QString normalizedPath = normalizePathForBlacklistMatch(inputPath); + const QStringList pathSegments = normalizedPath.split('/', Qt::SkipEmptyParts); + + for (const QString &entry : blacklistEntries) { + const QString trimmedEntry = entry.trimmed(); + if (trimmedEntry.isEmpty()) { + continue; + } + + if (QDir::isAbsolutePath(trimmedEntry)) { + if (isAbsolutePathMatch(normalizedPath, trimmedEntry)) { + return true; + } + continue; + } + + if (pathSegments.contains(trimmedEntry)) { + return true; + } + } + + return false; +} + +} // namespace BlacklistMatcher +} // namespace Global +DFM_SEARCH_END_NS diff --git a/src/dfm-search/dfm-search-lib/utils/filenameblacklistmatcher.h b/src/dfm-search/dfm-search-lib/utils/filenameblacklistmatcher.h new file mode 100644 index 0000000..743e31b --- /dev/null +++ b/src/dfm-search/dfm-search-lib/utils/filenameblacklistmatcher.h @@ -0,0 +1,23 @@ +// SPDX-FileCopyrightText: 2025 - 2026 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later +#ifndef FILENAMEBLACKLISTMATCHER_H +#define FILENAMEBLACKLISTMATCHER_H + +#include +#include + +#include + +DFM_SEARCH_BEGIN_NS +namespace Global { +namespace BlacklistMatcher { + +QString normalizePathForBlacklistMatch(const QString &path); +bool isPathBlacklisted(const QString &inputPath, const QStringList &blacklistEntries); + +} // namespace BlacklistMatcher +} // namespace Global +DFM_SEARCH_END_NS + +#endif // FILENAMEBLACKLISTMATCHER_H diff --git a/src/dfm-search/dfm-search-lib/utils/searchutility.cpp b/src/dfm-search/dfm-search-lib/utils/searchutility.cpp index 250ae93..2c0dbb1 100644 --- a/src/dfm-search/dfm-search-lib/utils/searchutility.cpp +++ b/src/dfm-search/dfm-search-lib/utils/searchutility.cpp @@ -2,6 +2,7 @@ // // SPDX-License-Identifier: GPL-3.0-or-later #include "searchutility.h" +#include "filenameblacklistmatcher.h" #include @@ -631,6 +632,9 @@ bool isPathInFileNameIndexDirectory(const QString &path) if (!isFileNameIndexDirectoryAvailable()) return false; + if (BlacklistMatcher::isPathBlacklisted(path, defaultBlacklistPaths())) + return false; + const QStringList &dirs = defaultIndexedDirectory(); return std::any_of(dirs.cbegin(), dirs.cend(), [&path](const QString &dir) { return path.startsWith(dir); });