2022-04-25 10:23:20 +08:00
# include "dir-watcher.h"
# include <QDebug>
# include <QDir>
# include <QDBusConnection>
# include <QDBusArgument>
# include <QThread>
# include <fstab.h>
# include <QMutexLocker>
# define CURRENT_INDEXABLE_DIR_SETTINGS QDir::homePath() + " / .config / org.ukui / ukui-search / ukui-search-current-indexable-dir.conf"
# define INDEXABLE_DIR_VALUE "IndexableDir"
static std : : once_flag flag ;
static DirWatcher * global_intance = nullptr ;
QMutex DirWatcher : : s_mutex ;
DirWatcher : : DirWatcher ( QObject * parent ) : QObject ( parent )
{
m_qSettings = new QSettings ( CURRENT_INDEXABLE_DIR_SETTINGS , QSettings : : IniFormat ) ;
initData ( ) ;
initDiskWatcher ( ) ;
m_adaptor = new DirWatcherAdaptor ( this ) ;
}
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 ;
}
}
DirWatcher * DirWatcher : : getDirWatcher ( )
{
std : : call_once ( flag , [ & ] {
global_intance = new DirWatcher ( ) ;
} ) ;
return global_intance ;
}
QStringList DirWatcher : : currentIndexableDir ( )
{
QMutexLocker locker ( & s_mutex ) ;
m_qSettings - > beginGroup ( INDEXABLE_DIR_VALUE ) ;
m_indexableDirList = m_qSettings - > value ( INDEXABLE_DIR_VALUE ) . toStringList ( ) ;
m_qSettings - > endGroup ( ) ;
QStringList indexableDirs = m_indexableDirList ;
return indexableDirs ;
}
QStringList DirWatcher : : currentBlackListOfIndex ( )
{
QMutexLocker locker ( & s_mutex ) ;
QStringList blackListOfIndex = m_blackListOfIndex ;
return blackListOfIndex ;
}
void DirWatcher : : handleIndexItemAppend ( const QString & path , QStringList & blackList )
{
if ( m_indexableDirList . contains ( path ) ) {
qDebug ( ) < < QString ( " index path %1 is already added. " ) . arg ( path ) ;
return ;
}
m_indexableDirList < < path ;
m_qSettings - > beginGroup ( INDEXABLE_DIR_VALUE ) ;
m_qSettings - > setValue ( INDEXABLE_DIR_VALUE , m_indexableDirList ) ;
m_qSettings - > endGroup ( ) ;
Q_EMIT this - > appendIndexItem ( path , blackList ) ;
qDebug ( ) < < " index path: " < < path < < " blacklist: " < < blackList ;
}
void DirWatcher : : handleIndexItemRemove ( const QString & path )
{
m_indexableDirList . removeAll ( path ) ;
m_qSettings - > beginGroup ( INDEXABLE_DIR_VALUE ) ;
m_qSettings - > setValue ( INDEXABLE_DIR_VALUE , m_indexableDirList ) ;
m_qSettings - > endGroup ( ) ;
}
/**
* @ brief DirWatcher : : blackListOfDir 根 据 传 入 目 录 返 回 当 前 目 录 下 的 所 有 不 可 搜 索 目 录 , 没 有 则 返 回 空 列 表
* @ param dirPath 要 搜 索 的 目 录
*/
QStringList DirWatcher : : blackListOfDir ( const QString & dirPath )
{
//new TODO: Optimize the search algorithm.
//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 ( )
{
QDBusConnection sessionBus = QDBusConnection : : sessionBus ( ) ;
if ( ! sessionBus . registerObject ( " /org/ukui/search/fileindex " , this , QDBusConnection : : ExportAdaptors ) ) {
qWarning ( ) < < " ukui-search-fileindex dbus register object failed reason: " < < sessionBus . lastError ( ) ;
}
}
QStringList DirWatcher : : currentSearchableDir ( )
{
QMutexLocker locker ( & s_mutex ) ;
return m_searchableDirList ;
}
QStringList DirWatcher : : searchableDirForSearchApplication ( )
{
QMutexLocker locker ( & s_mutex ) ;
return m_searchableListForApplication ;
}
void DirWatcher : : mountAddCallback ( GVolumeMonitor * monitor , GMount * gmount , DirWatcher * pThis )
{
qDebug ( ) < < " Mount Added " ;
pThis - > handleDisk ( ) ;
}
void DirWatcher : : mountRemoveCallback ( GVolumeMonitor * monitor , GMount * gmount , DirWatcher * pThis )
{
qDebug ( ) < < " Mount Removed " ;
QMutexLocker locker ( & s_mutex ) ;
//处理u盘设备
if ( pThis - > m_removedUDiskDevice ! = NULL ) {
pThis - > m_currentUDiskDeviceInfo . remove ( pThis - > m_removedUDiskDevice ) ;
qDebug ( ) < < " m_currentMountedDeviceInfo: " < < pThis - > m_currentMountedDeviceInfo ;
qDebug ( ) < < " m_repeatedlyMountedDeviceInfo: " < < pThis - > m_repeatedlyMountedDeviceInfo ;
qDebug ( ) < < " m_currentUDiskDeviceInfo: " < < pThis - > m_currentUDiskDeviceInfo ;
qDebug ( ) < < " m_blackListOfIndex: " < < pThis - > m_blackListOfIndex ;
pThis - > m_removedUDiskDevice = " " ;
return ;
}
GMount * mount = ( GMount * ) g_object_ref ( gmount ) ;
GFile * rootFile ;
rootFile = g_mount_get_root ( mount ) ;
if ( ! rootFile ) {
return ;
}
QString mountPoint = g_file_get_uri ( rootFile ) ;
if ( mountPoint . isEmpty ( ) ) {
return ;
}
//处理uri转码,处理子卷情况
if ( mountPoint . startsWith ( " file:/// " ) ) {
QString removedMountPoint = g_filename_from_uri ( mountPoint . toUtf8 ( ) . constData ( ) , nullptr , nullptr ) ;
pThis - > m_blackListOfIndex . removeAll ( removedMountPoint ) ;
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_currentMountedDeviceInfo: " < < pThis - > m_currentMountedDeviceInfo ;
qDebug ( ) < < " m_repeatedlyMountedDeviceInfo: " < < pThis - > m_repeatedlyMountedDeviceInfo ;
qDebug ( ) < < " m_currentUDiskDeviceInfo: " < < pThis - > m_currentUDiskDeviceInfo ;
qDebug ( ) < < " m_blackListOfIndex: " < < pThis - > m_blackListOfIndex ;
} else {
qWarning ( ) < < " There's someting wrong with the MountPoint! " ;
}
g_object_unref ( rootFile ) ;
}
void DirWatcher : : appendIndexableListItem ( const QString & path )
{
QFile file ( path ) ;
if ( ! file . exists ( ) ) {
qWarning ( ) < < QString ( " target path:%1 is not exists! " ) . arg ( path ) ;
return ;
}
if ( path = = " / " ) {
this - > currentIndexableDir ( ) ;
this - > handleIndexItemAppend ( path , m_blackListOfIndex ) ;
return ;
}
QStringList blackList = this - > blackListOfDir ( path ) ;
//处理要添加索引的路径与索引黑名单中路径为父子关系的情况
for ( const QString & blackListPath : m_blackListOfIndex ) {
if ( path . startsWith ( blackListPath + " / " ) ) {
return ;
}
if ( blackListPath . startsWith ( path + " / " ) ) {
blackList . append ( blackListPath ) ;
}
}
this - > currentIndexableDir ( ) ;
qDebug ( ) < < " current indexable dirs: " < < m_indexableDirList ;
//处理要添加索引的路径与已索引路径为父子关系的情况
for ( int i = 0 ; i < m_indexableDirList . length ( ) ; i + + ) {
const QString indexablePath = m_indexableDirList . at ( i ) ;
if ( path . startsWith ( indexablePath + " / " ) ) {
qCritical ( ) < < QString ( " The parent of the path:%1 has been added. " ) . arg ( path ) ;
return ;
}
if ( blackList . contains ( indexablePath ) ) {
qCritical ( ) < < " current path is in repeat mounted devices and another path which is in the device that has the same dev num has been added to the indexable list. " ;
return ;
}
if ( indexablePath . startsWith ( path + " / " ) ) {
m_indexableDirList . removeAll ( indexablePath ) ;
blackList . append ( indexablePath ) ;
}
}
this - > handleIndexItemAppend ( path , blackList ) ;
}
void DirWatcher : : removeIndexableListItem ( const QString & path )
{
this - > currentIndexableDir ( ) ;
this - > handleIndexItemRemove ( path ) ;
Q_EMIT this - > removeIndexItem ( path ) ;
}
void DirWatcher : : initData ( )
{
//适配需求,可索引目录为用户指定。
// m_indexableDirList << "/data" << QDir::homePath();
/* boot里面存放Linux核心文件, 开机选单与开机所需配置文件等
* backup里面是系统备份文件
* bin放置的是在单人维护模式下还能够被操作的指令 , 在 bin底下的指令可以被root与一般账号所使用 。
* dev里面存放设备文件
* etc里面存放了几乎所有的系统主要配置文件 , 包 括 人 员 的 账 号 密 码 文 件 , 各 种 服 务 的 起 始 档 等
* lib放置最基本的共享库和内核模块 , lib32 , lib64 , libx32分别面向32位 , 64 位 以 及 x32 ABI 。 他 们 都 分 别 连 接 到 usr下的lib * 中
* media一般放置可移除的装置 , 包 括 软 盘 , 光 盘 和 一 些 移 动 存 储 设 备 都 自 动 挂 载 到 这 里
* mnt原本和media用途相同 , 现 用 来 放 置 暂 时 挂 载 一 些 额 外 装 置
* usr是Unix操作系统软件资源所放置的目录 , 所 有 系 统 默 认 的 软 件 ( distribution发布者提供的软件 ) 都 会 放 置 到 usr底下
* var目录主要针对常态性变动的文件 , 包 括 缓 存 ( cache ) 、 登 录 档 ( log file ) 以 及 某 些 软 件 运 作 所 产 生 的 文 件 , 包 括 程 序 文 件 ( lock file , run file ) , 或 者 如 MySQL数据库的文件等
*/
2022-04-26 11:07:17 +08:00
//将磁盘分区后其他分区都会挂载到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 " ;
2022-04-25 10:23:20 +08:00
//目前方案:可搜索目录(服务)默认根目录,可搜索目录(应用)默认家目录和/data目录
m_searchableListForApplication < < " /data " < < 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 ) ;
}
}
//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 ( ) < < dbc . connect ( " org.freedesktop.UDisks2 " ,
" /org/freedesktop/UDisks2 " ,
" org.freedesktop.DBus.ObjectManager " ,
" InterfacesAdded " ,
this , SLOT ( handleAddedUDiskDevice ( QDBusMessage ) ) ) ;
qDebug ( ) < < dbc . lastError ( ) ;
qDebug ( ) < < 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 ) {
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 ( ) ;
for ( QStorageInfo & storage : QStorageInfo : : mountedVolumes ( ) ) {
if ( storage . isValid ( ) & & storage . isReady ( ) & & QString ( storage . device ( ) ) . contains ( QRegExp ( " /sd[a-z][1-9] " ) ) ) {
m_currentMountedDeviceInfo [ storage . device ( ) ] . append ( storage . rootPath ( ) ) ;
if ( m_currentMountedDeviceInfo . value ( storage . device ( ) ) . length ( ) > 1 ) {
m_repeatedlyMountedDeviceInfo . insert ( storage . device ( ) , m_currentMountedDeviceInfo . value ( storage . device ( ) ) ) ;
}
if ( storage . rootPath ( ) . startsWith ( " /data " ) | | storage . rootPath ( ) . startsWith ( " /home " ) ) {
m_blackListOfIndex . append ( storage . rootPath ( ) ) ;
}
}
}
//init udisk info
if ( ! m_addedUDiskDeviceList . isEmpty ( ) ) {
for ( QString addedUDiskDevice : m_addedUDiskDeviceList ) {
m_currentUDiskDeviceInfo . insert ( addedUDiskDevice , m_currentMountedDeviceInfo . value ( " /dev/ " + addedUDiskDevice ) ) ;
}
}
//将u盘设备在/data和/home下的所有挂载点添加到索引黑名单
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目录下的设备)
for ( QString autoMountDevice : m_autoMountList ) {
m_blackListOfIndex . removeAll ( autoMountDevice ) ;
}
m_blackListOfIndex . removeDuplicates ( ) ;
qDebug ( ) < < " autoMountList: " < < m_autoMountList ;
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 ( " /sd[a-z][1-9] " ) ) ) {
QMutexLocker locker ( & s_mutex ) ;
m_addedUDiskDeviceList . append ( objPath . path ( ) . section ( " / " , - 1 ) ) ;
qDebug ( ) < < " Add Udisk: " < < m_addedUDiskDeviceList ;
}
}
void DirWatcher : : handleRemovedUDiskDevice ( QDBusMessage msg )
{
Q_EMIT this - > udiskRemoved ( ) ;
QDBusObjectPath objPath = msg . arguments ( ) . at ( 0 ) . value < QDBusObjectPath > ( ) ;
if ( objPath . path ( ) . contains ( QRegExp ( " /sd[a-z][1-9] " ) ) ) {
QMutexLocker locker ( & s_mutex ) ;
m_removedUDiskDevice = objPath . path ( ) . section ( " / " , - 1 ) ;
m_addedUDiskDeviceList . removeAll ( m_removedUDiskDevice ) ;
}
}