2023-04-11 10:19:35 +08:00
|
|
|
|
/*
|
|
|
|
|
*
|
|
|
|
|
* Copyright (C) 2023, KylinSoft Co., Ltd.
|
|
|
|
|
*
|
|
|
|
|
* This program is free software: you can redistribute it and/or modify
|
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
|
|
|
* (at your option) any later version.
|
|
|
|
|
*
|
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
|
*
|
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
|
*
|
|
|
|
|
* Authors: iaom <zhangpengfei@kylinos.cn>
|
|
|
|
|
*/
|
2023-04-06 10:39:10 +08:00
|
|
|
|
#include "search-dir.h"
|
2023-04-08 16:54:01 +08:00
|
|
|
|
#include "config.h"
|
|
|
|
|
#include "volume-manager.h"
|
|
|
|
|
#include <QFile>
|
2023-04-06 10:39:10 +08:00
|
|
|
|
|
|
|
|
|
SearchDir::SearchDir(const QString &path, bool generateBlackList)
|
|
|
|
|
{
|
2023-04-08 16:54:01 +08:00
|
|
|
|
if (!QFile::exists(path)) {
|
|
|
|
|
m_error = NotExists;
|
|
|
|
|
} else {
|
|
|
|
|
m_path = path;
|
|
|
|
|
if(generateBlackList) {
|
|
|
|
|
this->handleBlackListGenerate();
|
|
|
|
|
}
|
2023-04-06 10:39:10 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-08 11:45:59 +08:00
|
|
|
|
bool SearchDir::operator ==(const SearchDir &rhs) const
|
|
|
|
|
{
|
|
|
|
|
return (m_path == rhs.m_path);
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-06 10:39:10 +08:00
|
|
|
|
SearchDir::ErrorInfo SearchDir::error()
|
|
|
|
|
{
|
|
|
|
|
return m_error;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString SearchDir::errorString()
|
|
|
|
|
{
|
|
|
|
|
switch (m_error) {
|
|
|
|
|
case ErrorInfo::Successful:
|
2023-04-08 16:54:01 +08:00
|
|
|
|
return "Add search dir successful";
|
2023-04-06 10:39:10 +08:00
|
|
|
|
case ErrorInfo::Duplicated:
|
2023-04-08 16:54:01 +08:00
|
|
|
|
return "Path or its parent dir has been added";
|
2023-04-06 10:39:10 +08:00
|
|
|
|
case ErrorInfo::UnderBlackList:
|
2023-04-08 16:54:01 +08:00
|
|
|
|
return "Path is or under blacklist";
|
2023-04-06 10:39:10 +08:00
|
|
|
|
case ErrorInfo::RepeatMount1:
|
2023-04-08 16:54:01 +08:00
|
|
|
|
return "Path is in repeat mounted devices and another path which is in the same device has been indexed";
|
2023-04-06 10:39:10 +08:00
|
|
|
|
case ErrorInfo::RepeatMount2:
|
2023-04-08 16:54:01 +08:00
|
|
|
|
return "Another path which is in the same device has been indexed";
|
2023-04-06 10:39:10 +08:00
|
|
|
|
case ErrorInfo::NotExists:
|
2023-04-08 16:54:01 +08:00
|
|
|
|
return "Path is not exists";
|
2023-04-06 10:39:10 +08:00
|
|
|
|
}
|
2023-04-08 16:54:01 +08:00
|
|
|
|
return QString();
|
2023-04-06 10:39:10 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString SearchDir::getPath() const
|
|
|
|
|
{
|
|
|
|
|
return m_path;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SearchDir::setBlackList(const QStringList &blackList)
|
|
|
|
|
{
|
|
|
|
|
m_blackList = blackList;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QStringList SearchDir::getBlackList() const
|
|
|
|
|
{
|
|
|
|
|
return m_blackList;
|
|
|
|
|
}
|
2023-04-08 11:45:59 +08:00
|
|
|
|
|
|
|
|
|
void SearchDir::generateBlackList()
|
|
|
|
|
{
|
2023-04-08 16:54:01 +08:00
|
|
|
|
m_blackList.clear();
|
|
|
|
|
this->handleBlackListGenerate();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QStringList SearchDir::blackListOfDir(const QString &dirPath)
|
|
|
|
|
{
|
2024-04-24 17:48:36 +08:00
|
|
|
|
//手动刷新挂载信息
|
|
|
|
|
VolumeManager::self()->refresh();
|
2023-04-08 16:54:01 +08:00
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-04-11 20:47:40 +08:00
|
|
|
|
blackListOfDir << handleSubVolumes4SingleDir(dirPath);
|
2023-04-08 16:54:01 +08:00
|
|
|
|
return blackListOfDir;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SearchDir::handleBlackListGenerate()
|
|
|
|
|
{
|
2024-04-24 17:48:36 +08:00
|
|
|
|
//手动刷新挂载信息
|
|
|
|
|
VolumeManager::self()->refresh();
|
2023-04-08 16:54:01 +08:00
|
|
|
|
QStringList searchDirs = Config::self()->searchDirs();
|
|
|
|
|
|
2023-04-25 10:14:43 +08:00
|
|
|
|
//目录已被索引(根目录被添加过直接返回)
|
|
|
|
|
for (const QString searchDir : searchDirs) {
|
|
|
|
|
if (searchDir == m_path || searchDir == "/") {
|
|
|
|
|
m_error = Duplicated;
|
|
|
|
|
return;
|
|
|
|
|
}
|
2023-04-08 16:54:01 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//根目录特殊处理
|
|
|
|
|
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;
|
|
|
|
|
}
|
2024-04-11 20:47:40 +08:00
|
|
|
|
m_blackList.append(handleSubVolumes4SingleDir("/"));
|
2023-04-08 16:54:01 +08:00
|
|
|
|
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();
|
2023-04-08 11:45:59 +08:00
|
|
|
|
}
|
2024-04-11 20:47:40 +08:00
|
|
|
|
|
|
|
|
|
QStringList SearchDir::handleSubVolumes4SingleDir(const QString &searchDir) {
|
|
|
|
|
QStringList blackList;
|
|
|
|
|
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(); //子卷对应目录
|
|
|
|
|
|
|
|
|
|
if (searchDir == "/") {
|
|
|
|
|
blackList << spec;
|
|
|
|
|
} else {
|
|
|
|
|
//排除搜索列表指定多个目录时子卷会重复包含的情况,比如同时指定/home和/data/home
|
|
|
|
|
QString tmp = searchDir;
|
|
|
|
|
if (searchDir.startsWith(subMountPoint + "/")) {
|
|
|
|
|
blackList << tmp.replace(0, subMountPoint.length(), spec);
|
|
|
|
|
}
|
|
|
|
|
//要添加目录下存在子卷(要添加/data,但挂到/home的/data/home是子卷),若添加了/home则将/data/home排除
|
|
|
|
|
if (searchDir.startsWith(spec + "/")) {
|
|
|
|
|
blackList << tmp.replace(0, spec.length(), subMountPoint);
|
|
|
|
|
}
|
|
|
|
|
if (spec.startsWith(searchDir + "/")) {
|
|
|
|
|
if (searchDir == subMountPoint || subMountPoint.startsWith(searchDir + "/")) {
|
|
|
|
|
blackList << spec;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return blackList;
|
|
|
|
|
}
|