File indexing completed on 2024-04-14 03:49:45
0001 /* 0002 This file is part of the KDE Project 0003 SPDX-FileCopyrightText: 2007-2011 Sebastian Trueg <trueg@kde.org> 0004 SPDX-FileCopyrightText: 2012-2014 Vishesh Handa <me@vhanda.in> 0005 0006 SPDX-License-Identifier: LGPL-2.0-or-later 0007 */ 0008 0009 #include "filewatch.h" 0010 #include "metadatamover.h" 0011 #include "fileindexerconfig.h" 0012 #include "pendingfilequeue.h" 0013 #include "regexpcache.h" 0014 #include "database.h" 0015 #include "baloodebug.h" 0016 0017 #include "kinotify.h" 0018 0019 #include <QDateTime> 0020 #include <QFileInfo> 0021 #include <QDir> 0022 0023 using namespace Baloo; 0024 0025 FileWatch::FileWatch(Database* db, FileIndexerConfig* config, QObject* parent) 0026 : QObject(parent) 0027 , m_db(db) 0028 , m_config(config) 0029 , m_dirWatch(nullptr) 0030 { 0031 Q_ASSERT(db); 0032 Q_ASSERT(config); 0033 0034 m_metadataMover = new MetadataMover(m_db, this); 0035 connect(m_metadataMover, &MetadataMover::movedWithoutData, this, &FileWatch::indexNewFile); 0036 connect(m_metadataMover, &MetadataMover::fileRemoved, this, &FileWatch::fileRemoved); 0037 0038 m_pendingFileQueue = new PendingFileQueue(this); 0039 connect(m_pendingFileQueue, &PendingFileQueue::indexNewFile, this, &FileWatch::indexNewFile); 0040 connect(m_pendingFileQueue, &PendingFileQueue::indexModifiedFile, this, &FileWatch::indexModifiedFile); 0041 connect(m_pendingFileQueue, &PendingFileQueue::indexXAttr, this, &FileWatch::indexXAttr); 0042 connect(m_pendingFileQueue, &PendingFileQueue::removeFileIndex, m_metadataMover, &MetadataMover::removeFileMetadata); 0043 0044 // monitor the file system for changes (restricted by the inotify limit) 0045 m_dirWatch = new KInotify(m_config, this); 0046 0047 connect(m_dirWatch, &KInotify::moved, this, &FileWatch::slotFileMoved); 0048 connect(m_dirWatch, &KInotify::deleted, this, &FileWatch::slotFileDeleted); 0049 connect(m_dirWatch, &KInotify::created, this, &FileWatch::slotFileCreated); 0050 connect(m_dirWatch, &KInotify::modified, this, &FileWatch::slotFileModified); 0051 connect(m_dirWatch, &KInotify::closedWrite, this, &FileWatch::slotFileClosedAfterWrite); 0052 connect(m_dirWatch, &KInotify::attributeChanged, this, &FileWatch::slotAttributeChanged); 0053 connect(m_dirWatch, &KInotify::watchUserLimitReached, this, &FileWatch::slotInotifyWatchUserLimitReached); 0054 connect(m_dirWatch, &KInotify::installedWatches, this, &FileWatch::installedWatches); 0055 } 0056 0057 FileWatch::~FileWatch() 0058 { 0059 } 0060 0061 // FIXME: listen to Create for folders! 0062 void FileWatch::watchFolder(const QString& path) 0063 { 0064 if (m_dirWatch && !m_dirWatch->watchingPath(path)) { 0065 KInotify::WatchEvents flags(KInotify::EventMove | KInotify::EventDelete | KInotify::EventDeleteSelf 0066 | KInotify::EventCloseWrite | KInotify::EventCreate 0067 | KInotify::EventAttributeChange | KInotify::EventModify); 0068 0069 m_dirWatch->addWatch(path, flags, KInotify::FlagOnlyDir); 0070 } 0071 } 0072 0073 void FileWatch::slotFileMoved(const QString& urlFrom, const QString& urlTo) 0074 { 0075 if (m_config->shouldBeIndexed(urlTo)) { 0076 m_metadataMover->moveFileMetadata(urlFrom, urlTo); 0077 } else { 0078 QFileInfo src(urlFrom); 0079 QString url = urlFrom; 0080 0081 if (src.isDir() && !url.endsWith(QLatin1Char('/'))) { 0082 url.append(QLatin1Char('/')); 0083 } 0084 0085 PendingFile file(url); 0086 file.setDeleted(); 0087 0088 m_pendingFileQueue->enqueue(file); 0089 } 0090 } 0091 0092 void FileWatch::slotFileDeleted(const QString& urlString, bool isDir) 0093 { 0094 // Directories must always end with a trailing slash '/' 0095 QString url = urlString; 0096 if (isDir && !url.endsWith(QLatin1Char('/'))) { 0097 url.append(QLatin1Char('/')); 0098 } 0099 0100 PendingFile file(url); 0101 file.setDeleted(); 0102 0103 m_pendingFileQueue->enqueue(file); 0104 } 0105 0106 void FileWatch::slotFileCreated(const QString& path, bool isDir) 0107 { 0108 Q_UNUSED(isDir); 0109 PendingFile file(path); 0110 file.setCreated(); 0111 0112 m_pendingFileQueue->enqueue(file); 0113 } 0114 0115 void FileWatch::slotFileModified(const QString& path) 0116 { 0117 PendingFile file(path); 0118 file.setModified(); 0119 0120 //qCDebug(BALOO) << "MOD" << path; 0121 m_pendingFileQueue->enqueue(file); 0122 } 0123 0124 void FileWatch::slotFileClosedAfterWrite(const QString& path) 0125 { 0126 QDateTime current = QDateTime::currentDateTime(); 0127 QDateTime fileModification = QFileInfo(path).lastModified(); 0128 QDateTime dirModification = QFileInfo(QFileInfo(path).absoluteDir().absolutePath()).lastModified(); 0129 0130 // If we have received a FileClosedAfterWrite event, then the file must have been 0131 // closed within the last minute. 0132 // This is being done cause many applications open the file under write mode, do not 0133 // make any modifications and then close the file. This results in us getting 0134 // the FileClosedAfterWrite event 0135 if (fileModification.secsTo(current) <= 1000 * 60 || dirModification.secsTo(current) <= 1000 * 60) { 0136 PendingFile file(path); 0137 file.setClosedOnWrite(); 0138 //qCDebug(BALOO) << "CLOSE" << path; 0139 m_pendingFileQueue->enqueue(file); 0140 } 0141 } 0142 0143 void FileWatch::slotAttributeChanged(const QString& path) 0144 { 0145 PendingFile file(path); 0146 file.setAttributeChanged(); 0147 0148 m_pendingFileQueue->enqueue(file); 0149 } 0150 0151 // This slot is connected to a signal emitted in KInotify when 0152 // inotify_add_watch fails with ENOSPC. 0153 void FileWatch::slotInotifyWatchUserLimitReached(const QString&) 0154 { 0155 // If we got here, we hit the limit and are not allowed to raise it, 0156 // so put something in the log. 0157 qCWarning(BALOO) << "KDE Baloo File Indexer has reached the inotify folder watch limit. File changes will be ignored."; 0158 // we do it the brutal way for now hoping with new kernels and defaults this will never happen 0159 // Delete the KInotify 0160 // FIXME: Maybe we should be aborting? 0161 if (m_dirWatch) { 0162 m_dirWatch->deleteLater(); 0163 m_dirWatch = nullptr; 0164 } 0165 Q_EMIT installedWatches(); 0166 } 0167 0168 void FileWatch::updateIndexedFoldersWatches() 0169 { 0170 if (m_dirWatch) { 0171 const QStringList excludedFolders = m_config->excludeFolders(); 0172 const QStringList includedFolders = m_config->includeFolders(); 0173 0174 for (const QString& folder : excludedFolders) { 0175 // Remove watch for new excluded folders 0176 if (!m_excludedFolders.contains(folder)) { 0177 m_dirWatch->removeWatch(folder); 0178 } 0179 } 0180 for (const QString& folder : m_excludedFolders) { 0181 // Add no longer excluded folders 0182 if (!excludedFolders.contains(folder)) { 0183 watchFolder(folder); 0184 } 0185 } 0186 0187 for (const QString& folder : m_includedFolders) { 0188 // Remove no longer included folders 0189 if (!includedFolders.contains(folder)) { 0190 m_dirWatch->removeWatch(folder); 0191 } 0192 } 0193 for (const QString& folder : includedFolders) { 0194 if (!m_includedFolders.contains(folder)) { 0195 watchFolder(folder); 0196 } 0197 } 0198 0199 m_excludedFolders = excludedFolders; 0200 m_includedFolders = includedFolders; 0201 } 0202 } 0203 0204 #include "moc_filewatch.cpp"