Optimize Dir Watcher.

This commit is contained in:
baijunjie 2023-04-08 16:54:01 +08:00 committed by iaom
parent 45f0654e21
commit 9c1d2f482b
12 changed files with 411 additions and 719 deletions

View File

@ -101,9 +101,25 @@ QStringList DirWatcher::searchableDirForSearchApplication()
return reply.value(); return reply.value();
} }
void DirWatcher::appendSearchDir(const QString &path)
{
QDBusReply<int> reply = m_dbusInterface->call("appendSearchDir", path);
if (!reply.isValid()) {
qCritical() << "appendSearchDir call filed!";
}
}
void DirWatcher::removeSearchDir(const QString &path)
{
QDBusReply<void> reply = m_dbusInterface->call("removeSearchDir", path);
if (!reply.isValid()) {
qCritical() << "removeSearchDir call filed!";
}
}
void DirWatcher::appendIndexableListItem(const QString &path) void DirWatcher::appendIndexableListItem(const QString &path)
{ {
QDBusReply<void> reply = m_dbusInterface->call("appendIndexableListItem", path); QDBusReply<int> reply = m_dbusInterface->call("appendIndexableListItem", path);
if (!reply.isValid()) { if (!reply.isValid()) {
qCritical() << "appendIndexableListItem call filed!"; qCritical() << "appendIndexableListItem call filed!";
} }

View File

@ -21,6 +21,8 @@ public Q_SLOTS:
QStringList searchableDirForSearchApplication(); QStringList searchableDirForSearchApplication();
QStringList blackListOfDir(const QString &dirPath); QStringList blackListOfDir(const QString &dirPath);
void appendSearchDir(const QString &path);
void removeSearchDir(const QString &path);
void appendIndexableListItem(const QString &path); void appendIndexableListItem(const QString &path);
void removeIndexableListItem(const QString &path); void removeIndexableListItem(const QString &path);
void sendAppendSignal(const QString &path, const QStringList &blockList); void sendAppendSignal(const QString &path, const QStringList &blockList);

View File

@ -469,22 +469,22 @@ void Search::initFileDialog()
qDebug() << "Selected a folder in onAddSearchDirBtnClicked(): " << selectedDir; qDebug() << "Selected a folder in onAddSearchDirBtnClicked(): " << selectedDir;
int returnCode = setSearchDir(selectedDir, true); int returnCode = setSearchDir(selectedDir, true);
switch (returnCode) { switch (returnCode) {
case 1: case 0:
qDebug() << "Add search folder succeed! path = " << selectedDir; qDebug() << "Add search folder succeed! path = " << selectedDir;
break; break;
case -1: case 1:
QMessageBox::warning(m_pluginWidget, tr("Warning"), tr("Add search folder failed, choosen path or its parent dir has been added!")); QMessageBox::warning(m_pluginWidget, tr("Warning"), tr("Add search folder failed, choosen path or its parent dir has been added!"));
break; break;
case -2: case 2:
QMessageBox::warning(m_pluginWidget, tr("Warning"), tr("Add search folder failed, choosen path is not supported currently!")); QMessageBox::warning(m_pluginWidget, tr("Warning"), tr("Add search folder failed, choosen path is not supported currently!"));
break; break;
case -3: case 3:
QMessageBox::warning(m_pluginWidget, tr("Warning"), tr("Add search folder failed, choosen path is in repeat mounted devices and another path which is in the same device has been added!")); QMessageBox::warning(m_pluginWidget, tr("Warning"), tr("Add search folder failed, choosen path is in repeat mounted devices and another path which is in the same device has been added!"));
break; break;
case -4: case 4:
QMessageBox::warning(m_pluginWidget, tr("Warning"), tr("Add search folder failed, another path which is in the same device has been added!")); QMessageBox::warning(m_pluginWidget, tr("Warning"), tr("Add search folder failed, another path which is in the same device has been added!"));
break; break;
case -5: case 5:
QMessageBox::warning(m_pluginWidget, tr("Warning"), tr("Add search folder failed, choosen path is not exists!")); QMessageBox::warning(m_pluginWidget, tr("Warning"), tr("Add search folder failed, choosen path is not exists!"));
break; break;
default: default:
@ -581,7 +581,7 @@ void Search::initSearchDirs()
int Search::setSearchDir(const QString &dirPath, const bool isAdd) int Search::setSearchDir(const QString &dirPath, const bool isAdd)
{ {
if (!m_setSearchDirInterface->isValid()) { if (!m_setSearchDirInterface->isValid()) {
return 0; return -1;
} }
if (isAdd) { if (isAdd) {
@ -593,7 +593,7 @@ int Search::setSearchDir(const QString &dirPath, const bool isAdd)
QDBusReply<int> appendIndexRpl = m_setSearchDirInterface->call("appendIndexableListItem", dirPath); QDBusReply<int> appendIndexRpl = m_setSearchDirInterface->call("appendIndexableListItem", dirPath);
if (appendIndexRpl.isValid()) { if (appendIndexRpl.isValid()) {
if (appendIndexRpl.value() == 1) { if (appendIndexRpl.value() == 0) {
this->appendSearchDirToList(dirPath); this->appendSearchDirToList(dirPath);
if (!indexDirs.isEmpty()) { if (!indexDirs.isEmpty()) {
indexDirsRpl = m_interface->call("currentIndexableDir"); indexDirsRpl = m_interface->call("currentIndexableDir");

View File

@ -9,5 +9,12 @@
<arg type="b" direction="out"/> <arg type="b" direction="out"/>
<arg name="path" type="s" direction="in"/> <arg name="path" type="s" direction="in"/>
</method> </method>
<method name="appendSearchDir">
<arg type="i" direction="out"/>
<arg name="path" type="s" direction="in"/>
</method>
<method name="removeSearchDir">
<arg name="path" type="s" direction="in"/>
</method>
</interface> </interface>
</node> </node>

View File

@ -14,7 +14,6 @@ static const QStringList GLOBAL_BLACK_LIST{"/proc", "/sys", "/dev", "/tmp", "/ru
static const QString GLOBAL_SETTINGS_GROUP = "GlobalSettings"; static const QString GLOBAL_SETTINGS_GROUP = "GlobalSettings";
static const QString SEARCH_DIRS_GROUP = "SearchDirs"; static const QString SEARCH_DIRS_GROUP = "SearchDirs";
static std::once_flag flag; static std::once_flag flag;
static Config *global_instance = nullptr; static Config *global_instance = nullptr;
Config *Config::self() Config *Config::self()
@ -95,7 +94,7 @@ QVector<SearchDir> Config::searchDirObjects()
Config::Config() Config::Config()
{ {
m_settings = new QSettings(CURRENT_INDEXABLE_DIR_SETTINGS, QSettings::IniFormat); m_settings = new QSettings(CURRENT_INDEXABLE_DIR_SETTINGS, QSettings::IniFormat);
if(!(m_settings->value(CONFIG_VERSION_KEY).toString() == CONFIG_VERSION)) { if(!(m_settings->value(GLOBAL_SETTINGS_GROUP + "/" + CONFIG_VERSION_KEY).toString() == CONFIG_VERSION)) {
m_compatibilityMode = true; m_compatibilityMode = true;
for(const QString& path : m_settings->value(INDEXABLE_DIR_KEY + "/" + INDEXABLE_DIR_KEY).toStringList()) { for(const QString& path : m_settings->value(INDEXABLE_DIR_KEY + "/" + INDEXABLE_DIR_KEY).toStringList()) {
if(QFile::exists(path)) { if(QFile::exists(path)) {
@ -121,6 +120,7 @@ Config::Config()
} }
m_settings->endGroup(); m_settings->endGroup();
} }
m_settings->beginGroup(GLOBAL_SETTINGS_GROUP); m_settings->beginGroup(GLOBAL_SETTINGS_GROUP);
if(m_settings->value(GLOBAL_BLACK_LIST_KEY).isNull()) { if(m_settings->value(GLOBAL_BLACK_LIST_KEY).isNull()) {
m_settings->setValue(GLOBAL_BLACK_LIST_KEY, GLOBAL_BLACK_LIST); m_settings->setValue(GLOBAL_BLACK_LIST_KEY, GLOBAL_BLACK_LIST);
@ -142,11 +142,19 @@ void Config::processCompatibleCache()
{ {
if(this->isCompatibilityMode()) { if(this->isCompatibilityMode()) {
m_settings->beginGroup(SEARCH_DIRS_GROUP); m_settings->beginGroup(SEARCH_DIRS_GROUP);
for(SearchDir dir : m_compatibleCache) { if (m_compatibleCache.isEmpty()) {
dir.generateBlackList(); SearchDir defaultDir(QDir::homePath());
if(dir.error() == SearchDir::ErrorInfo::Successful) { if (defaultDir.error() == SearchDir::ErrorInfo::Successful) {
m_searchDirs.append(dir); m_searchDirs.append(defaultDir);
m_settings->setValue(QUrl::fromLocalFile(dir.getPath()).toString(), dir.getBlackList()); m_settings->setValue(QUrl::fromLocalFile(defaultDir.getPath()).toString(), defaultDir.getBlackList());
}
} else {
for (SearchDir dir : m_compatibleCache) {
dir.generateBlackList();
if (dir.error() == SearchDir::ErrorInfo::Successful) {
m_searchDirs.append(dir);
m_settings->setValue(QUrl::fromLocalFile(dir.getPath()).toString(), dir.getBlackList());
}
} }
} }
m_settings->endGroup(); m_settings->endGroup();

View File

@ -41,6 +41,14 @@ int DirWatcherAdaptor::appendIndexableListItem(const QString &path)
return out0; return out0;
} }
int DirWatcherAdaptor::appendSearchDir(const QString &path)
{
// handle method call org.ukui.search.fileindex.appendSearchDir
int out0;
QMetaObject::invokeMethod(parent(), "appendSearchDir", Q_RETURN_ARG(int, out0), Q_ARG(QString, path));
return out0;
}
bool DirWatcherAdaptor::removeIndexableListItem(const QString &path) bool DirWatcherAdaptor::removeIndexableListItem(const QString &path)
{ {
// handle method call org.ukui.search.fileindex.removeIndexableListItem // handle method call org.ukui.search.fileindex.removeIndexableListItem
@ -49,3 +57,9 @@ bool DirWatcherAdaptor::removeIndexableListItem(const QString &path)
return out0; return out0;
} }
void DirWatcherAdaptor::removeSearchDir(const QString &path)
{
// handle method call org.ukui.search.fileindex.removeSearchDir
QMetaObject::invokeMethod(parent(), "removeSearchDir", Q_ARG(QString, path));
}

View File

@ -40,6 +40,13 @@ class DirWatcherAdaptor: public QDBusAbstractAdaptor
" <arg direction=\"out\" type=\"b\"/>\n" " <arg direction=\"out\" type=\"b\"/>\n"
" <arg direction=\"in\" type=\"s\" name=\"path\"/>\n" " <arg direction=\"in\" type=\"s\" name=\"path\"/>\n"
" </method>\n" " </method>\n"
" <method name=\"appendSearchDir\">\n"
" <arg direction=\"out\" type=\"i\"/>\n"
" <arg direction=\"in\" type=\"s\" name=\"path\"/>\n"
" </method>\n"
" <method name=\"removeSearchDir\">\n"
" <arg direction=\"in\" type=\"s\" name=\"path\"/>\n"
" </method>\n"
" </interface>\n" " </interface>\n"
"") "")
public: public:
@ -49,7 +56,9 @@ public:
public: // PROPERTIES public: // PROPERTIES
public Q_SLOTS: // METHODS public Q_SLOTS: // METHODS
int appendIndexableListItem(const QString &path); int appendIndexableListItem(const QString &path);
int appendSearchDir(const QString &path);
bool removeIndexableListItem(const QString &path); bool removeIndexableListItem(const QString &path);
void removeSearchDir(const QString &path);
Q_SIGNALS: // SIGNALS Q_SIGNALS: // SIGNALS
}; };

View File

@ -15,38 +15,18 @@
static std::once_flag flag; static std::once_flag flag;
static DirWatcher *global_intance = nullptr; static DirWatcher *global_intance = nullptr;
QMutex DirWatcher::s_mutex;
DirWatcher::DirWatcher(QObject *parent) : QObject(parent) DirWatcher::DirWatcher(QObject *parent) : QObject(parent)
{ {
//兼容旧版配置 //兼容旧版配置
// Config::self()->processCompatibleCache(); Config::self()->processCompatibleCache();
m_qSettings = new QSettings(CURRENT_INDEXABLE_DIR_SETTINGS, QSettings::IniFormat);
this->currentIndexableDir();
if (m_indexableDirList.isEmpty()) {
qDebug() << QString("use the path: %1 as default indexable dir.").arg(DEFAULT_INDEXABLE_DIR);
m_qSettings->beginGroup(INDEXABLE_DIR_VALUE);
m_qSettings->setValue(INDEXABLE_DIR_VALUE, DEFAULT_INDEXABLE_DIR);
m_qSettings->endGroup();
}
initDiskWatcher();
initData();
m_adaptor = new DirWatcherAdaptor(this); m_adaptor = new DirWatcherAdaptor(this);
} }
DirWatcher::~DirWatcher() DirWatcher::~DirWatcher()
{ {
if (m_volumeMonitor) {
g_signal_handler_disconnect(m_volumeMonitor, m_mountAddHandle);
g_signal_handler_disconnect(m_volumeMonitor, m_mountRemoveHandle);
m_volumeMonitor = nullptr;
}
if(m_qSettings){
delete m_qSettings;
}
m_qSettings = nullptr;
} }
DirWatcher *DirWatcher::getDirWatcher() DirWatcher *DirWatcher::getDirWatcher()
@ -59,90 +39,13 @@ DirWatcher *DirWatcher::getDirWatcher()
QStringList DirWatcher::currentIndexableDir() QStringList DirWatcher::currentIndexableDir()
{ {
QMutexLocker locker(&s_mutex); return currentSearchDirs();
this->updateIndexableDirs();
return m_indexableDirList;
} }
void DirWatcher::updateIndexableDirs()
{
m_qSettings->beginGroup(INDEXABLE_DIR_VALUE);
m_indexableDirList = m_qSettings->value(INDEXABLE_DIR_VALUE).toStringList();
m_qSettings->endGroup();
QStringList indexableDirs = m_indexableDirList;
bool changed(false);
for (const QString& dir : m_indexableDirList) {
if (!QFileInfo(dir).isDir()) {
indexableDirs.removeAll(dir);
changed = true;
}
}
if (changed) {
m_qSettings->beginGroup(INDEXABLE_DIR_VALUE);
m_qSettings->setValue(INDEXABLE_DIR_VALUE, indexableDirs);
m_qSettings->endGroup();
m_indexableDirList = indexableDirs;
Q_EMIT this->indexDirsChanged();
}
}
QStringList DirWatcher::currentBlackListOfIndex() QStringList DirWatcher::currentBlackListOfIndex()
{ {
QMutexLocker locker(&s_mutex); return currentBlackList();
QStringList blackListOfIndex = m_blackListOfIndex;
return blackListOfIndex;
}
bool DirWatcher::handleIndexItemAppend(const QString &path, QStringList &blackList)
{
//排除要添加的路径已被索引的情况
if (m_indexableDirList.contains(path)) {
qDebug() << QString("index path %1 is already added.").arg(path);
return false;
}
//处理添加路径非根目录时,要添加索引的路径与已索引路径为父子关系的情况
if (path != "/") {
QString indexablePath;
QStringList tmp = m_indexableDirList;
for (int i = 0; i < m_indexableDirList.length(); i++) {
indexablePath = m_indexableDirList.at(i);
if (path.startsWith(indexablePath + "/")) {
qCritical() << QString("The parent of the path:%1 has been added.").arg(path);
return false;
}
if (indexablePath.startsWith(path + "/")) {
tmp.removeAll(indexablePath);
blackList.append(indexablePath);
}
}
m_indexableDirList = tmp;
}
m_indexableDirList << path;
m_qSettings->beginGroup(INDEXABLE_DIR_VALUE);
m_qSettings->setValue(INDEXABLE_DIR_VALUE, m_indexableDirList);
m_qSettings->endGroup();
blackList.removeDuplicates();
Q_EMIT this->appendIndexItem(path, blackList);
qDebug() << "index path:" << path << "blacklist:" << blackList;
return true;
}
bool DirWatcher::handleIndexItemRemove(const QString &path)
{
this->currentIndexableDir();
QMutexLocker locker(&s_mutex);
if (!m_indexableDirList.contains(path)) {
qWarning() << QString("The path: %1 is not indexed").arg(path);
return false;
}
m_indexableDirList.removeAll(path);
m_qSettings->beginGroup(INDEXABLE_DIR_VALUE);
m_qSettings->setValue(INDEXABLE_DIR_VALUE, m_indexableDirList);
m_qSettings->endGroup();
return true;
} }
/** /**
@ -151,67 +54,7 @@ bool DirWatcher::handleIndexItemRemove(const QString &path)
*/ */
QStringList DirWatcher::blackListOfDir(const QString &dirPath) QStringList DirWatcher::blackListOfDir(const QString &dirPath)
{ {
//new TODO: Optimize the search algorithm. return SearchDir::blackListOfDir(dirPath);
//There is no processing for the subvolumes.May be a bug.
QStringList blackListOfDir;
QMutexLocker locker(&s_mutex);
for (auto t = m_repeatedlyMountedDeviceInfo.constBegin(); t != m_repeatedlyMountedDeviceInfo.constEnd(); t++) {
QString topRepeatedMountPoint;
for (QString mountPoint: t.value()) {
if (mountPoint.startsWith(dirPath)) {
if (topRepeatedMountPoint.isEmpty()) {
topRepeatedMountPoint = mountPoint;
continue;
} else if (topRepeatedMountPoint.startsWith(mountPoint)) {
blackListOfDir.append(topRepeatedMountPoint);
topRepeatedMountPoint = mountPoint;
} else {
blackListOfDir.append(mountPoint);
}
}
}
}
for (auto i = m_infoOfSubvolume.constBegin(); i != m_infoOfSubvolume.constEnd(); i++) {
QString mountPoint = i.value();
QString spec = i.key();
//排除搜索列表指定多个目录时子卷会重复包含的情况,比如同时指定/home和/data/home
QString tmp = dirPath;
if (dirPath.startsWith(mountPoint)) {
blackListOfDir.append(tmp.replace(0, mountPoint.length(), spec));
}
if (dirPath.startsWith(spec)) {
blackListOfDir.append(tmp.replace(0, spec.length(), mountPoint));
}
}
return blackListOfDir;
}
void DirWatcher::appendBlackListItemOfIndex(const QString &path)
{
QMutexLocker locker(&s_mutex);
m_blackListOfIndex.append(path);
m_blackListOfIndex = m_blackListOfIndex.toSet().toList();
}
void DirWatcher::appendBlackListItemOfIndex(const QStringList &pathList)
{
QMutexLocker locker(&s_mutex);
m_blackListOfIndex.append(pathList);
m_blackListOfIndex = m_blackListOfIndex.toSet().toList();
}
void DirWatcher::removeBlackListItemOfIndex(const QString &path)
{
QMutexLocker locker(&s_mutex);
m_blackListOfIndex.removeAll(path);
}
void DirWatcher::removeBlackListItemOfIndex(const QStringList &pathList)
{
QMutexLocker locker(&s_mutex);
for (QString path: pathList) {
m_blackListOfIndex.removeAll(path);
}
} }
void DirWatcher::initDbusService() void DirWatcher::initDbusService()
@ -224,323 +67,58 @@ void DirWatcher::initDbusService()
QStringList DirWatcher::currentSearchableDir() QStringList DirWatcher::currentSearchableDir()
{ {
QMutexLocker locker(&s_mutex); return currentSearchDirs();
return m_searchableDirList;
} }
QStringList DirWatcher::searchableDirForSearchApplication() QStringList DirWatcher::searchableDirForSearchApplication()
{ {
QMutexLocker locker(&s_mutex); return currentSearchDirs();
return m_searchableListForApplication;
}
void DirWatcher::mountAddCallback(GVolumeMonitor *monitor, GMount *gmount, DirWatcher *pThis)
{
qDebug() << "Mount Added";
GMount* mount = (GMount*)g_object_ref(gmount);
GVolume* volume = g_mount_get_volume(mount);
if (volume) {
bool canEject = g_volume_can_eject(volume);
QString devName = g_volume_get_identifier(volume, G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE);
if (canEject and devName.contains(QRegExp("/nvme[0-9]+n[0-9]+p[0-9]+|/sd[a-z][0-9]+"))) {
QMutexLocker locker(&s_mutex);
pThis->m_currentUDiskDeviceList.append(devName.section("/", -1));
}
qDebug() << "added device name:" << devName.section("/", -1);
g_object_unref(volume);
} else {
qWarning() << "GVolume(add) is NULL.";
}
pThis->handleDisk();
}
void DirWatcher::mountRemoveCallback(GVolumeMonitor *monitor, GMount *gmount, DirWatcher *pThis)
{
qDebug() << "Mount Removed";
pThis->handleDisk();
QMutexLocker locker(&s_mutex);
//处理u盘设备
if (pThis->m_removedUDiskDevice != NULL) {
pThis->updateIndexableDirs();//更新索引名单,排除失效目录
pThis->m_currentUDiskDeviceInfo.remove(pThis->m_removedUDiskDevice);
qDebug() << "m_currentUDiskDeviceInfo(after remove):" << pThis->m_currentUDiskDeviceInfo;
pThis->m_removedUDiskDevice = "";
return;
}
GMount* mount = (GMount*)g_object_ref(gmount);
GFile* rootFile;
rootFile = g_mount_get_root(mount);
if (!rootFile) {
return;
}
QString removedUri = g_file_get_uri(rootFile);
if (removedUri.isEmpty()) {
return;
}
//处理uri转码
if (removedUri.startsWith("file:///")) {
QString removedMountPoint = g_filename_from_uri(removedUri.toUtf8().constData(), nullptr, nullptr);
pThis->m_blackListOfIndex.removeAll(removedMountPoint);
locker.unlock();
QStringList indexableDirList = pThis->currentIndexableDir();
//卸载目录下存在已索引目录时,通知索引服务删除对应目录
for (const QString &indexableDir : indexableDirList) {
if (indexableDir.startsWith(removedMountPoint + "/") or !indexableDir.compare(removedMountPoint)) {
Q_EMIT pThis->removeIndexItem(indexableDir);
}
}
//处理子卷情况
locker.relock();
for (auto t = pThis->m_infoOfSubvolume.constBegin(); t != pThis->m_infoOfSubvolume.constEnd(); t++) {
if (removedMountPoint.startsWith(t.value() + "/")) {
pThis->m_blackListOfIndex.removeAll(removedMountPoint.replace(t.value(), t.key()));
}
if (removedMountPoint.startsWith(t.key() + "/")) {
pThis->m_blackListOfIndex.removeAll(removedMountPoint.replace(t.key(), t.value()));
}
}
qDebug() << "m_blackListOfIndex(after remove):" << pThis->m_blackListOfIndex;
} else {
qWarning() << QString("Removed uri:%1 is not starts with 'file:///', there's no handling of it.").arg(removedUri);
}
g_object_unref(rootFile);
} }
int DirWatcher::appendIndexableListItem(const QString &path) int DirWatcher::appendIndexableListItem(const QString &path)
{ {
int resultCode = 1; return appendSearchDir(path);
/* code: /* code:
* 1: successful * 0: successful
* -1: path or its parent dir has been added * 1: path or its parent dir has been added
* -2: path is or under blacklist * 2: path is or under blacklist
* -3: path is in repeat mounted devices and another path which is in the same device has been indexed * 3: path is in repeat mounted devices and another path which is in the same device has been indexed
* -4: another path which is in the same device has been indexed * 4: another path which is in the same device has been indexed
* -5: path is not exists * 5: path is not exists
*/ */
//排除path不存在的情况
QFile file(path);
if (!file.exists()) {
qWarning() << QString("target path:%1 is not exists!").arg(path);
resultCode = -5;
return resultCode;
}
//同步配置文件中的已索引目录
this->currentIndexableDir();
qDebug() << "current indexable dirs:" << m_indexableDirList;
QStringList blackList;
QMutexLocker locker(&s_mutex);
//根目录特殊处理
if (path == "/") {
if (!this->handleIndexItemAppend(path, m_blackListOfIndex)) {
resultCode = -1;
}
return resultCode;
}
//处理要添加索引的路径与索引黑名单中路径为父子关系的情况
for (const QString& blackListPath : m_blackListOfIndex) {
if (path.startsWith(blackListPath + "/") or path == blackListPath) {
qCritical() << QString("path:%1 is or under the blacklistpath:%2.").arg(path, blackListPath);
resultCode = -2;
return resultCode;
}
if (blackListPath.startsWith(path + "/")) {
blackList.append(blackListPath);
}
}
//排除要添加的目录为某设备的重复挂载目录,并且之前已索引过该设备其他挂载目录或其父目录的情况
for (auto i = m_repeatedlyMountedDeviceInfo.constBegin(); i != m_repeatedlyMountedDeviceInfo.constEnd(); i++) {
bool pathToBeAddedIsRepeatedDevice = false;
bool pathToBeAddedHasRepeatedDevice = false;
bool addedPathIsRepeatedDevice = false;
bool addedPathHasRepeatedDevice = false;
QString addedRelativeDir;
QString repeatedDir;
for (const QString &addedPath : m_indexableDirList) {
for (const QString &mountPoint : i.value()) {
//要添加索引路径在重复挂载设备路径下(1)
if (path.startsWith(mountPoint + "/") or mountPoint == path) {
repeatedDir = mountPoint;
pathToBeAddedIsRepeatedDevice = true;
}
//重复挂载设备路径在要添加索引路径下(2)
if (mountPoint.startsWith(path + "/")) {
repeatedDir = mountPoint;
pathToBeAddedHasRepeatedDevice = true;
}
//已索引路径在重复挂载设备路径下(3)
if (addedPath.startsWith(mountPoint + "/") or mountPoint == addedPath) {
addedRelativeDir = addedPath;
addedRelativeDir.remove(mountPoint);
addedPathIsRepeatedDevice = true;
}
//重复挂载设备路径在已索引路径下(4)
if (mountPoint.startsWith(addedPath + "/")) {
addedPathHasRepeatedDevice = true;
}
//(1)(4)直接返回
if (pathToBeAddedIsRepeatedDevice and addedPathHasRepeatedDevice) {
qCritical() << "current path is in repeat mounted devices and another path which is in the same device has been indexed!";
resultCode = -3;
return resultCode;
}
//(2)(4)将要添加索引目录相应的重复挂载路径添加到黑名单
if (pathToBeAddedHasRepeatedDevice and addedPathHasRepeatedDevice) {
blackList.append(repeatedDir);
break;
}
//(1)(3)将已索引路径的前缀替换为要添加路径的前缀前缀为mountPoint判断替换后路径是否在要索引路径下如果是则返回否则将替换后路径添加到黑名单
if (pathToBeAddedIsRepeatedDevice and addedPathIsRepeatedDevice) {
QString pathAfterReplace = repeatedDir + addedRelativeDir;
if (path.startsWith(pathAfterReplace) or path == pathAfterReplace) {
qCritical() << QString("another path:%1 which is in the same device has been indexed").arg(pathAfterReplace);
resultCode = -4;
return resultCode;
} else {
blackList.append(pathAfterReplace);
break;
}
}
//(2)(3)将替换前缀后的已索引路径添加到黑名单
if (pathToBeAddedHasRepeatedDevice and addedPathIsRepeatedDevice) {
blackList.append(repeatedDir + addedRelativeDir);
break;
}
}
}
}
//排除重复挂载设备的目录
for (auto i = m_repeatedlyMountedDeviceInfo.constBegin(); i != m_repeatedlyMountedDeviceInfo.constEnd(); i++) {
QString topRepeatedMountPoint;
for (const QString &mountPoint : i.value()) {
if (mountPoint.startsWith(path + "/") or mountPoint == path) {
if (topRepeatedMountPoint.isEmpty()) {
topRepeatedMountPoint = mountPoint;
continue;
} else if (topRepeatedMountPoint.startsWith(mountPoint)) {
blackList.append(topRepeatedMountPoint);
topRepeatedMountPoint = mountPoint;
} else {
blackList.append(mountPoint);
}
}
}
}
//处理自动挂载子卷下的目录
for (auto t = m_infoOfSubvolume.constBegin(); t != m_infoOfSubvolume.constEnd(); t++) {
QString mountPoint = t.value();
QString spec = t.key();
//要添加目录下存在子卷(要添加/data但挂到/home的/data/home是子卷若添加了/home则将/data/home排除
if (spec.startsWith(path + "/")) {
for (QString &indexDir : m_indexableDirList) {
if (indexDir == mountPoint || mountPoint.startsWith(indexDir + "/")) {
blackList << spec;
}
if (indexDir.startsWith(mountPoint + "/")) {
blackList << indexDir.replace(0, mountPoint.length(), spec);
}
}
}
//要添加目录下存在子卷挂载点,同上
if (mountPoint.startsWith(path + "/")) {
for (QString &indexDir : m_indexableDirList) {
if (indexDir == spec || spec.startsWith(indexDir + "/")) {
blackList << mountPoint;
}
if (indexDir.startsWith(spec + "/")) {
blackList << indexDir.replace(0, spec.length(), mountPoint);
}
}
}
//要添加的目录是子卷或在子卷下(/data/home or /data/home/xxx
if (path.startsWith(spec + "/") || path == spec) {
for (QString &indexDir : m_indexableDirList) {
//已添加挂载点或其上层目录
if (mountPoint.startsWith(indexDir + "/") || indexDir == mountPoint) {
qCritical() << "Fail to add" << path << "The mount point or its father:" << indexDir << "has been added";
resultCode = -3;
return resultCode;
}
//已添加挂载点下其他目录
if (indexDir.startsWith(mountPoint + "/")) {
QString tmp = indexDir;
tmp.replace(0, mountPoint.length(), spec);
if (tmp == path) {
qCritical() << "Fail to add" << path << "The same path which is in the subvolume has been added.";
resultCode = -4;
return resultCode;
} else if (tmp.startsWith(path + "/")) {//已添加的子卷子目录替换前缀后在要添加目录下
blackList << tmp;
}
}
}
}
//要添加的目录是挂载点或在挂载点下(/home or /home/xxx
if (path.startsWith(mountPoint + "/") || path == mountPoint) {
for (QString &indexDir : m_indexableDirList) {
//已添加子卷或其上层目录
if (spec.startsWith(indexDir + "/") || indexDir == spec) {
qCritical() << "Fail to add" << path << "The subvolume or its father:" << indexDir << "has been added";
resultCode = -3;
return resultCode;
}
//已添加子卷下其他目录
if (indexDir.startsWith(spec + "/")) {
QString tmp = indexDir;
tmp.replace(0, spec.length(), mountPoint);
if (tmp == path) {
qCritical() << "Fail to add" << path << "The same path which is in the mount point has been added.";
resultCode = -4;
return resultCode;
} else if (tmp.startsWith(path + "/")) {//已添加的子卷子目录替换前缀后在要添加目录下
blackList << tmp;
}
}
}
}
}
if (!this->handleIndexItemAppend(path, blackList)) {
resultCode = -1;
}
return resultCode;
} }
bool DirWatcher::removeIndexableListItem(const QString &path) bool DirWatcher::removeIndexableListItem(const QString &path)
{ {
bool res = this->handleIndexItemRemove(path); removeSearchDir(path);
Q_EMIT this->removeIndexItem(path); return true;
return res;
} }
int DirWatcher::appendSearchDir(const QString &path) int DirWatcher::appendSearchDir(const QString &path)
{ {
SearchDir dir(path); SearchDir dir(path);
Config::self()->addDir(dir); if (dir.error() == SearchDir::Successful) {
return 0; Q_EMIT this->appendIndexItem(path, dir.getBlackList());
qDebug() << "Add search dir:" << path << "blacklist:" << dir.getBlackList();
//要添加已索引目录的父目录,先添加索引,再同步配置文件,从而使得下次读取配置文件时不会将子目录排除掉
for (const QString &searchDir : Config::self()->searchDirs()) {
if (searchDir.startsWith(path + "/") || path == "/") {
SearchDir subDir(searchDir);
Config::self()->removeDir(subDir);
}
}
dir.generateBlackList();
Config::self()->addDir(dir);
}
qWarning() << dir.getPath() << dir.errorString();
return dir.error();
} }
void DirWatcher::removeSearchDir(const QString &path) void DirWatcher::removeSearchDir(const QString &path)
{ {
SearchDir dir(path, false); SearchDir dir(path, false);
Config::self()->removeDir(dir); Config::self()->removeDir(dir);
Q_EMIT this->removeIndexItem(path);
return; return;
} }
@ -553,184 +131,3 @@ QStringList DirWatcher::currentBlackList()
{ {
return Config::self()->blackDirs(); return Config::self()->blackDirs();
} }
void DirWatcher::initData()
{
//适配需求,可索引目录为用户指定。
// m_indexableDirList << "/data" << QDir::homePath();
/* boot里面存放Linux核心文件开机选单与开机所需配置文件等
* backup里面是系统备份文件
* bin放置的是在单人维护模式下还能够被操作的指令bin底下的指令可以被root与一般账号所使用
* dev里面存放设备文件
* etc里面存放了几乎所有的系统主要配置文件
* lib放置最基本的共享库和内核模块lib32lib64libx32分别面向32位64x32 ABIusr下的lib*
* media一般放置可移除的装置
* mnt原本和media用途相同
* usr是Unix操作系统软件资源所放置的目录,(distribution发布者提供的软件)usr底下
* var目录主要针对常态性变动的文件(cache)(log file)(lock file, run file)MySQL数据库的文件等
*/
//将磁盘分区后其他分区都会挂载到media下多块硬盘也会挂到media因此media放开mnt同理
//backup是备份文件tmp是临时文件也都放开
// m_blackListOfIndex << "/boot" << "/bin" << "/dev" << "/etc" << "/usr" << "/var"
// << "/lib" << "/lib32" << "/lib64" << "/libx32" << "/cdrom"
// << "/sys" << "/proc" << "/srv" << "/sbin" << "/run" << "/opt";
//专用机需求:只屏蔽/proc, /sys, /dev, /tmp, /run
m_blackListOfIndex << "/proc" << "/sys" << "/dev" << "/tmp" << "/run";
//目前方案:可搜索目录(服务)默认根目录,可搜索目录(应用)默认家目录和/data目录
QDir dir("/data");
if (dir.exists()) {
m_searchableListForApplication << "/data";
}
m_searchableListForApplication << QDir::homePath();
m_searchableDirList << "/";
//init auto mounted device list
setfsent();
while (1) {
fstab *myFstab = getfsent();
if (!myFstab) {
endfsent();
break;
}
QString automaticMountPoint = myFstab->fs_file;
QString spec = myFstab->fs_spec;
//目前只索引data和home因此只存这两个文件夹下的挂载点
if (automaticMountPoint.contains("/data") || automaticMountPoint.contains("/home")) {
m_autoMountList.append(automaticMountPoint);
}
//存储所有子卷自动挂载
if (!spec.startsWith("UUID")) {
m_infoOfSubvolume.insert(spec, automaticMountPoint);
}
}
GList *list = g_volume_monitor_get_volumes(m_volumeMonitor);
if (!list) {
qDebug() << "Fail to init glist of volume monitor!";
handleDisk();
return;
}
for (guint i = 0; i < g_list_length(list); i++) {
GVolume *volume = (GVolume*)g_list_nth_data(list, i);
QString udiskDevName = g_volume_get_identifier(volume, G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE);
bool canEject = g_volume_can_eject(volume);
if (canEject and udiskDevName.contains(QRegExp("/nvme[0-9]+n[0-9]+p[0-9]+|/sd[a-z][0-9]+"))) {
qDebug() << "udiskDevName:" << udiskDevName.section("/",-1);
m_currentUDiskDeviceList.append(udiskDevName.section("/",-1));
}
}
//init disk data, refresh the black list
handleDisk();
}
void DirWatcher::initDiskWatcher()
{
//use Dbus to monitor the hot plug of Udisk.
QDBusConnection dbc = QDBusConnection::systemBus();
qDebug() << "Connect The Signal:InterfacesAdded" << dbc.connect("org.freedesktop.UDisks2",
"/org/freedesktop/UDisks2",
"org.freedesktop.DBus.ObjectManager",
"InterfacesAdded",
this, SLOT(handleAddedUDiskDevice(QDBusMessage)));
qDebug() << dbc.lastError();
qDebug() << "Connect The Signal:InterfacesRemove" << dbc.connect("org.freedesktop.UDisks2",
"/org/freedesktop/UDisks2",
"org.freedesktop.DBus.ObjectManager",
"InterfacesRemoved",
this, SLOT(handleRemovedUDiskDevice(QDBusMessage)));
m_volumeMonitor = g_volume_monitor_get();
if (!m_volumeMonitor) {
qDebug() << "Fail to init volume monitor";
return;
}
m_mountAddHandle = g_signal_connect(m_volumeMonitor, "mount-added", G_CALLBACK(mountAddCallback), this);
m_mountRemoveHandle = g_signal_connect(m_volumeMonitor, "mount-removed", G_CALLBACK(mountRemoveCallback), this);
}
void DirWatcher::handleDisk()
{
//init current mounted device info
QMutexLocker locker(&s_mutex);
m_currentMountedDeviceInfo.clear();
m_repeatedlyMountedDeviceInfo.clear();
for (QStorageInfo &storage: QStorageInfo::mountedVolumes()) {
//遍历当前系统所有挂载的且以sd*和nvme开头的存储设备
if (storage.isValid() and storage.isReady() and QString(storage.device()).contains(QRegExp("/nvme[0-9]+n[0-9]+p[0-9]+|/sd[a-z][0-9]+"))) {
m_currentMountedDeviceInfo[storage.device()].append(storage.rootPath());
//存储非子卷的重复挂载设备
if (m_currentMountedDeviceInfo.value(storage.device()).length() > 1 and storage.subvolume().isEmpty()) {
m_repeatedlyMountedDeviceInfo.insert(storage.device(), m_currentMountedDeviceInfo.value(storage.device()));
}
//排除挂载到data和home下挂载的所有其他设备后面需要修改
// if (storage.rootPath().startsWith("/data") || storage.rootPath().startsWith("/home")) {
// m_blackListOfIndex.append(storage.rootPath());
// }
}
}
//根据设备号(key)更新u盘信息
if (!m_currentUDiskDeviceList.isEmpty()) {
for (const QString &udiskDevice: m_currentUDiskDeviceList) {
QStringList udiskMountPointList = m_currentMountedDeviceInfo.value("/dev/" + udiskDevice);
if (udiskMountPointList.isEmpty()) {
m_currentUDiskDeviceInfo.remove(udiskDevice);
} else {
m_currentUDiskDeviceInfo.insert(udiskDevice, udiskMountPointList);
}
}
}
//将u盘设备添加到索引黑名单
if (!m_currentUDiskDeviceInfo.isEmpty()) {
for (auto t = m_currentUDiskDeviceInfo.constBegin(); t != m_currentUDiskDeviceInfo.constEnd(); t++) {
for (QString udiskDevice: t.value()) {
// if (udiskDevice.startsWith("/data") || udiskDevice.startsWith("/home")) {
// m_blackListOfIndex.append(udiskDevice);
// }
}
}
}
//从索引黑名单中移除所有自动挂载设备(目前只包含自动挂载到/data和/home目录下的设备m_infoOfSubvolume存储全部fstab文件中的子卷自动挂载
for (const QString &autoMountDevice: m_autoMountList) {
m_blackListOfIndex.removeAll(autoMountDevice);
}
m_blackListOfIndex.removeDuplicates();
qDebug() << "m_infoOfSubvolume" << m_infoOfSubvolume;
qDebug() << "m_currentMountedDeviceInfo:" << m_currentMountedDeviceInfo;
qDebug() << "m_repeatedlyMountedDeviceInfo:" << m_repeatedlyMountedDeviceInfo;
qDebug() << "m_currentUDiskDeviceInfo:" << m_currentUDiskDeviceInfo;
qDebug() << "m_blackListOfIndex:" << m_blackListOfIndex;
}
void DirWatcher::handleAddedUDiskDevice(QDBusMessage msg)
{
QDBusObjectPath objPath = msg.arguments().at(0).value<QDBusObjectPath>();
if (objPath.path().contains(QRegExp("/nvme[0-9]+n[0-9]+p[0-9]+|/sd[a-z][0-9]+"))) {
QMutexLocker locker(&s_mutex);
m_currentUDiskDeviceList.append(objPath.path().section("/",-1));
qDebug() << "Add Udisk:" << m_currentUDiskDeviceList;
}
}
void DirWatcher::handleRemovedUDiskDevice(QDBusMessage msg)
{
Q_EMIT this->udiskRemoved();
QDBusObjectPath objPath = msg.arguments().at(0).value<QDBusObjectPath>();
if (objPath.path().contains(QRegExp("/nvme[0-9]+n[0-9]+p[0-9]+|/sd[a-z][0-9]+"))) {
QMutexLocker locker(&s_mutex);
m_removedUDiskDevice = objPath.path().section("/",-1);
m_currentUDiskDeviceList.removeAll(m_removedUDiskDevice);
}
}

View File

@ -4,23 +4,13 @@
#include "dir-watcher-adaptor.h" #include "dir-watcher-adaptor.h"
#include <QObject> #include <QObject>
#include <QStorageInfo> #include <QStringList>
#include <QHash>
#include <QDBusMessage> #include <QDBusMessage>
#include <QDBusObjectPath> #include <QDBusObjectPath>
#include <QMutex>
#include <QSettings>
#include <QDBusConnection> #include <QDBusConnection>
#include <QDBusInterface> #include <QDBusInterface>
#include <QDBusReply> #include <QDBusReply>
#undef slots
#undef signals
#undef emit
#include <gio/gio.h>
#include <gio/gunixmounts.h>
class DirWatcher : public QObject class DirWatcher : public QObject
{ {
Q_OBJECT Q_OBJECT
@ -29,13 +19,6 @@ class DirWatcher : public QObject
public: public:
static DirWatcher *getDirWatcher(); static DirWatcher *getDirWatcher();
static void mountAddCallback(GVolumeMonitor *monitor, GMount *gmount, DirWatcher *pThis);
static void mountRemoveCallback(GVolumeMonitor *monitor, GMount *gmount, DirWatcher *pThis);
void appendBlackListItemOfIndex(const QString &path);
void appendBlackListItemOfIndex(const QStringList &pathList);
void removeBlackListItemOfIndex(const QString &path);
void removeBlackListItemOfIndex(const QStringList &pathList);
public Q_SLOTS: public Q_SLOTS:
@ -53,19 +36,19 @@ public Q_SLOTS:
* add a item to indexable dirs * add a item to indexable dirs
* @param path: the path to be added to the index dirs list * @param path: the path to be added to the index dirs list
* @return int: the result code * @return int: the result code
* 1: successful * 0: successful
* -1: path or its parent dir has been added * 1: path or its parent dir has been added
* -2: path is or under blacklist * 2: path is or under blacklist
* -3: path is in repeat mounted devices and another path which is in the same device has been indexed * 3: path is in repeat mounted devices and another path which is in the same device has been indexed
* -4: another path which is in the same device has been indexed * 4: another path which is in the same device has been indexed
* -5: path is not exists * 5: path is not exists
*/ */
Q_SCRIPTABLE int appendIndexableListItem(const QString &path); Q_SCRIPTABLE int appendIndexableListItem(const QString &path);
Q_SCRIPTABLE bool removeIndexableListItem(const QString &path); Q_SCRIPTABLE bool removeIndexableListItem(const QString &path);
//新接口 //新接口
int appendSearchDir(const QString &path); Q_SCRIPTABLE int appendSearchDir(const QString &path);
void removeSearchDir(const QString &path); Q_SCRIPTABLE void removeSearchDir(const QString &path);
QStringList currentSearchDirs(); QStringList currentSearchDirs();
QStringList currentBlackList(); QStringList currentBlackList();
@ -74,46 +57,16 @@ public Q_SLOTS:
private: private:
DirWatcher(QObject *parent = nullptr); DirWatcher(QObject *parent = nullptr);
~DirWatcher(); ~DirWatcher();
void initData();
void initDiskWatcher();
void updateIndexableDirs();
void handleDisk();
bool handleIndexItemAppend(const QString &path, QStringList &blackList);
bool handleIndexItemRemove(const QString &path);
static QMutex s_mutex; static QMutex s_mutex;
DirWatcherAdaptor *m_adaptor = nullptr; DirWatcherAdaptor *m_adaptor = nullptr;
GVolumeMonitor *m_volumeMonitor = nullptr;
quint64 m_mountAddHandle;
quint64 m_mountRemoveHandle;
QSettings *m_qSettings = nullptr;
QStringList m_blackListOfIndex;
QStringList m_indexableDirList;
QStringList m_searchableDirList;
QStringList m_searchableListForApplication;
QStringList m_autoMountList;
QMultiMap<QString, QString> m_infoOfSubvolume;
QMap<QString, QStringList> m_currentMountedDeviceInfo;
QMap<QString, QStringList> m_repeatedlyMountedDeviceInfo;
QStringList m_currentUDiskDeviceList;
QString m_removedUDiskDevice;
QMap<QString, QStringList> m_currentUDiskDeviceInfo;
private Q_SLOTS:
void handleAddedUDiskDevice(QDBusMessage msg);
void handleRemovedUDiskDevice(QDBusMessage msg);
Q_SIGNALS: Q_SIGNALS:
void udiskRemoved();
void appendIndexItem(const QString&, const QStringList&); void appendIndexItem(const QString&, const QStringList&);
void removeIndexItem(const QString&); void removeIndexItem(const QString&);
//abondoned
void udiskRemoved();
void indexDirsChanged(); void indexDirsChanged();
}; };

View File

@ -1,10 +1,17 @@
#include "search-dir.h" #include "search-dir.h"
#include "config.h"
#include "volume-manager.h"
#include <QFile>
SearchDir::SearchDir(const QString &path, bool generateBlackList) SearchDir::SearchDir(const QString &path, bool generateBlackList)
{ {
m_path = path; if (!QFile::exists(path)) {
if(generateBlackList) { m_error = NotExists;
//根据VulumeManager和Congig的数据计算黑名单here } else {
m_path = path;
if(generateBlackList) {
this->handleBlackListGenerate();
}
} }
} }
@ -22,18 +29,19 @@ QString SearchDir::errorString()
{ {
switch (m_error) { switch (m_error) {
case ErrorInfo::Successful: case ErrorInfo::Successful:
return ""; return "Add search dir successful";
case ErrorInfo::Duplicated: case ErrorInfo::Duplicated:
return ""; return "Path or its parent dir has been added";
case ErrorInfo::UnderBlackList: case ErrorInfo::UnderBlackList:
return ""; return "Path is or under blacklist";
case ErrorInfo::RepeatMount1: case ErrorInfo::RepeatMount1:
return ""; return "Path is in repeat mounted devices and another path which is in the same device has been indexed";
case ErrorInfo::RepeatMount2: case ErrorInfo::RepeatMount2:
return ""; return "Another path which is in the same device has been indexed";
case ErrorInfo::NotExists: case ErrorInfo::NotExists:
return ""; return "Path is not exists";
} }
return QString();
} }
QString SearchDir::getPath() const QString SearchDir::getPath() const
@ -53,5 +61,275 @@ QStringList SearchDir::getBlackList() const
void SearchDir::generateBlackList() void SearchDir::generateBlackList()
{ {
//生成黑名单 m_blackList.clear();
this->handleBlackListGenerate();
}
QStringList SearchDir::blackListOfDir(const QString &dirPath)
{
QStringList blackListOfDir;
for (const QStringList & mountPoints: VolumeManager::self()->getDuplicates()) {
QString topRepeatedMountPoint;
for (const QString &mountPoint : mountPoints) {
//该目录下是否有两个文件夹(有可能为父子关系)是重复挂载的关系
if (mountPoint.startsWith(dirPath + "/") or mountPoint == dirPath) {
if (topRepeatedMountPoint.isEmpty()) {
topRepeatedMountPoint = mountPoint;
continue;
}
//重复挂载时保留最上层的挂载点
if (topRepeatedMountPoint.startsWith(mountPoint + "/")) {
blackListOfDir.append(topRepeatedMountPoint);
topRepeatedMountPoint = mountPoint;
} else {
blackListOfDir.append(mountPoint);
}
}
}
}
for (const Volume &volume : VolumeManager::self()->volumesHaveSubVolumes()) {
for (const QString &duplicateMountPoint : volume.mountPoints()) {
QMap<QString, QString> subVolumeInfo = volume.subVolumes();
if (subVolumeInfo.keys().contains(duplicateMountPoint)) {
continue;
}
for (auto it = subVolumeInfo.constBegin(); it != subVolumeInfo.constEnd(); it++) {
QString spec = it.key();
QString subMountPoint = duplicateMountPoint + it.value();
//排除搜索列表指定多个目录时子卷会重复包含的情况,比如同时指定/home和/data/home
QString tmp = dirPath;
if (dirPath.startsWith(subMountPoint)) {
blackListOfDir.append(tmp.replace(0, subMountPoint.length(), spec));
}
if (dirPath.startsWith(spec)) {
blackListOfDir.append(tmp.replace(0, spec.length(), subMountPoint));
}
}
}
}
return blackListOfDir;
}
void SearchDir::handleBlackListGenerate()
{
QStringList searchDirs = Config::self()->searchDirs();
//目录已被索引
if (searchDirs.contains(m_path)) {
m_error = Duplicated;
return;
}
//根目录特殊处理
if (m_path == "/") {
m_blackList << Config::self()->globalBlackList() << searchDirs;
for (const QStringList &mountPoints: VolumeManager::self()->getDuplicates()) {
QStringList repeatMountPoints = mountPoints;
if (mountPoints.contains("/")) {
repeatMountPoints.removeAll("/");
m_blackList << repeatMountPoints;
continue;
}
bool excludeAll(false);
for (const QString &mountPoint : mountPoints) {
for (const QString &searchDir : searchDirs) {
//之前已索引重复挂载设备挂载点或其子目录,则排除其他目录
if (searchDir.startsWith(mountPoint + "/") || searchDir == mountPoint) {
repeatMountPoints.removeAll(mountPoint);
break;
}
//重复挂载点在已索引目录下,该挂载点全排除
if (mountPoint.startsWith(searchDir + "/")) {
excludeAll = true;
break;
}
}
if (excludeAll) {
m_blackList << repeatMountPoints;
break;
}
}
//不需要全排除且没有需要特别保留的挂载点,默认留第一个
if (!excludeAll && repeatMountPoints == mountPoints) {
repeatMountPoints.removeFirst();
}
m_blackList << repeatMountPoints;
}
m_blackList.removeDuplicates();
return;
}
//处理要添加索引的路径与全局黑名单中路径为父子关系的情况
for (const QString& blackListPath : Config::self()->globalBlackList()) {
if (m_path.startsWith(blackListPath + "/") or m_path == blackListPath) {
m_error = UnderBlackList;
return;
}
if (blackListPath.startsWith(m_path + "/")) {
m_blackList.append(blackListPath);
}
}
//重复挂载情况
for (const QStringList & mountPoints: VolumeManager::self()->getDuplicates()) {
QString topRepeatedMountPoint;
for (const QString &mountPoint : mountPoints) {
if (mountPoint.startsWith(m_path + "/") or mountPoint == m_path) {
if (topRepeatedMountPoint.isEmpty()) {
topRepeatedMountPoint = mountPoint;
continue;
} else if (topRepeatedMountPoint.startsWith(mountPoint)) {
m_blackList.append(topRepeatedMountPoint);
topRepeatedMountPoint = mountPoint;
} else {
m_blackList.append(mountPoint);
}
}
}
//排除要添加的目录为某设备的重复挂载目录,并且之前已索引过该设备其他挂载目录或其父目录的情况
bool pathToBeAddedIsRepeatedDevice = false;
bool pathToBeAddedHasRepeatedDevice = false;
bool addedPathIsRepeatedDevice = false;
bool addedPathHasRepeatedDevice = false;
QString addedRelativeDir;
QString repeatedDir;
for (const QString &addedPath : searchDirs) {
for (const QString &mountPoint : mountPoints) {
//要添加索引路径在重复挂载设备路径下(1)
if (m_path.startsWith(mountPoint + "/") or mountPoint == m_path) {
repeatedDir = mountPoint;
pathToBeAddedIsRepeatedDevice = true;
}
//重复挂载设备路径在要添加索引路径下(2)
if (mountPoint.startsWith(m_path + "/")) {
repeatedDir = mountPoint;
pathToBeAddedHasRepeatedDevice = true;
}
//已索引路径在重复挂载设备路径下(3)
if (addedPath.startsWith(mountPoint + "/") or mountPoint == addedPath) {
addedRelativeDir = addedPath;
addedRelativeDir.remove(0, mountPoint.length());
addedPathIsRepeatedDevice = true;
}
//重复挂载设备路径在已索引路径下(4)
if (mountPoint.startsWith(addedPath + "/")) {
addedPathHasRepeatedDevice = true;
}
//(1)(4)直接返回
if (pathToBeAddedIsRepeatedDevice and addedPathHasRepeatedDevice) {
m_error = RepeatMount1;
return;
}
//(2)(4)将要添加索引目录相应的重复挂载路径添加到黑名单
if (pathToBeAddedHasRepeatedDevice and addedPathHasRepeatedDevice) {
m_blackList.append(repeatedDir);
break;
}
//(1)(3)将已索引路径的前缀替换为要添加路径的前缀前缀为mountPoint判断替换后路径是否在要索引路径下如果是则返回否则将替换后路径添加到黑名单
if (pathToBeAddedIsRepeatedDevice and addedPathIsRepeatedDevice) {
QString pathAfterReplace = repeatedDir + addedRelativeDir;
if (m_path.startsWith(pathAfterReplace) or m_path == pathAfterReplace) {
m_error = RepeatMount2;
return;
} else {
m_blackList.append(pathAfterReplace);
break;
}
}
//(2)(3)将替换前缀后的已索引路径添加到黑名单
if (pathToBeAddedHasRepeatedDevice and addedPathIsRepeatedDevice) {
m_blackList.append(repeatedDir + addedRelativeDir);
break;
}
}
}
}
//处理自动挂载子卷下的目录
for (const Volume &volume : VolumeManager::self()->volumesHaveSubVolumes()) {
QMap<QString, QString> subVolumeInfo = volume.subVolumes();
for (auto it = subVolumeInfo.constBegin(); it != subVolumeInfo.constEnd(); it++) {
QString subMountPoint = it.key();
for (const QString &duplicateMountPoint : volume.mountPoints()) {
if (subVolumeInfo.keys().contains(duplicateMountPoint)) {
continue;
}
QString spec = duplicateMountPoint + it.value(); //子卷对应目录
//要添加目录下存在子卷(要添加/data但挂到/home的/data/home是子卷若添加了/home则将/data/home排除
if (spec.startsWith(m_path + "/")) {
for (QString &searchDir : searchDirs) {
if (searchDir == subMountPoint || subMountPoint.startsWith(searchDir + "/")) {
m_blackList << spec;
}
if (searchDir.startsWith(subMountPoint + "/")) {
m_blackList << searchDir.replace(0, subMountPoint.length(), spec);
}
}
}
//要添加的目录是子卷或在子卷下(/data/home or /data/home/xxx
if (m_path.startsWith(spec + "/") || m_path == spec) {
for (QString &searchDir : searchDirs) {
//已添加挂载点或其上层目录
if (subMountPoint.startsWith(searchDir + "/") || searchDir == subMountPoint) {
m_error = RepeatMount1;
return;
}
//已添加挂载点下其他目录
if (searchDir.startsWith(subMountPoint + "/")) {
QString tmp = searchDir;
tmp.replace(0, subMountPoint.length(), spec);
if (tmp == m_path) {
m_error = RepeatMount2;
return;
} else if (tmp.startsWith(m_path + "/")) {//已添加的子卷子目录替换前缀后在要添加目录下
m_blackList << tmp;
}
}
}
}
//要添加的目录是挂载点或在挂载点下(/home or /home/xxx
if (m_path.startsWith(subMountPoint + "/") || m_path == subMountPoint) {
for (QString &searchDir : searchDirs) {
//已添加子卷或其上层目录
if (spec.startsWith(searchDir + "/") || searchDir == spec) {
m_error = RepeatMount1;
return;
}
//已添加子卷下其他目录
if (searchDir.startsWith(spec + "/")) {
QString tmp = searchDir;
tmp.replace(0, spec.length(), subMountPoint);
if (tmp == m_path) {
m_error = RepeatMount2;
return;
} else if (tmp.startsWith(m_path + "/")) {//已添加的子卷子目录替换前缀后在要添加目录下
m_blackList << tmp;
}
}
}
}
}
}
}
//要添加目录下存在已索引目录
for (const QString &searchDir : searchDirs) {
if (m_path.startsWith(searchDir + "/")) {
m_error = Duplicated;
return;
}
if (searchDir.startsWith(m_path + "/")) {
m_blackList.append(searchDir);
}
}
m_blackList.removeDuplicates();
} }

View File

@ -12,6 +12,7 @@ public:
RepeatMount2, RepeatMount2,
NotExists NotExists
}; };
SearchDir() = default;
SearchDir(const QString& path, bool generateBlackList = true); SearchDir(const QString& path, bool generateBlackList = true);
bool operator == (const SearchDir& rhs) const; bool operator == (const SearchDir& rhs) const;
ErrorInfo error(); ErrorInfo error();
@ -23,7 +24,9 @@ public:
* @brief * @brief
*/ */
void generateBlackList(); void generateBlackList();
static QStringList blackListOfDir(const QString &dirPath);
private: private:
void handleBlackListGenerate();
QString m_path; QString m_path;
QStringList m_blackList; QStringList m_blackList;
ErrorInfo m_error = ErrorInfo::Successful; ErrorInfo m_error = ErrorInfo::Successful;

View File

@ -1,5 +1,10 @@
#ifndef VOLUMEMANAGER_H #ifndef VOLUMEMANAGER_H
#define VOLUMEMANAGER_H #define VOLUMEMANAGER_H
#undef slots
#undef signals
#undef emit
#include <gio/gio.h> #include <gio/gio.h>
#include <gio/gunixmounts.h> #include <gio/gunixmounts.h>
#include <QObject> #include <QObject>