Baloo

filewatch.cpp
1/*
2 This file is part of the KDE Project
3 SPDX-FileCopyrightText: 2007-2011 Sebastian Trueg <trueg@kde.org>
4 SPDX-FileCopyrightText: 2012-2014 Vishesh Handa <me@vhanda.in>
5
6 SPDX-License-Identifier: LGPL-2.0-or-later
7*/
8
9#include "filewatch.h"
10#include "metadatamover.h"
11#include "fileindexerconfig.h"
12#include "pendingfilequeue.h"
13#include "regexpcache.h"
14#include "database.h"
15#include "baloodebug.h"
16
17#include "kinotify.h"
18
19#include <QDateTime>
20#include <QFileInfo>
21#include <QDir>
22
23using namespace Baloo;
24
25FileWatch::FileWatch(Database* db, FileIndexerConfig* config, QObject* parent)
26 : QObject(parent)
27 , m_db(db)
28 , m_config(config)
29 , m_dirWatch(nullptr)
30{
31 Q_ASSERT(db);
32 Q_ASSERT(config);
33
34 m_metadataMover = new MetadataMover(m_db, this);
35 connect(m_metadataMover, &MetadataMover::movedWithoutData, this, &FileWatch::indexNewFile);
36 connect(m_metadataMover, &MetadataMover::fileRemoved, this, &FileWatch::fileRemoved);
37
38 m_pendingFileQueue = new PendingFileQueue(this);
39 connect(m_pendingFileQueue, &PendingFileQueue::indexNewFile, this, &FileWatch::indexNewFile);
40 connect(m_pendingFileQueue, &PendingFileQueue::indexModifiedFile, this, &FileWatch::indexModifiedFile);
41 connect(m_pendingFileQueue, &PendingFileQueue::indexXAttr, this, &FileWatch::indexXAttr);
42 connect(m_pendingFileQueue, &PendingFileQueue::removeFileIndex, m_metadataMover, &MetadataMover::removeFileMetadata);
43
44 // monitor the file system for changes (restricted by the inotify limit)
45 m_dirWatch = new KInotify(m_config, this);
46
47 connect(m_dirWatch, &KInotify::moved, this, &FileWatch::slotFileMoved);
48 connect(m_dirWatch, &KInotify::deleted, this, &FileWatch::slotFileDeleted);
49 connect(m_dirWatch, &KInotify::created, this, &FileWatch::slotFileCreated);
50 connect(m_dirWatch, &KInotify::modified, this, &FileWatch::slotFileModified);
51 connect(m_dirWatch, &KInotify::closedWrite, this, &FileWatch::slotFileClosedAfterWrite);
52 connect(m_dirWatch, &KInotify::attributeChanged, this, &FileWatch::slotAttributeChanged);
53 connect(m_dirWatch, &KInotify::watchUserLimitReached, this, &FileWatch::slotInotifyWatchUserLimitReached);
54 connect(m_dirWatch, &KInotify::installedWatches, this, &FileWatch::installedWatches);
55}
56
57FileWatch::~FileWatch()
58{
59}
60
61// FIXME: listen to Create for folders!
62void FileWatch::watchFolder(const QString& path)
63{
64 if (m_dirWatch && !m_dirWatch->watchingPath(path)) {
66 | KInotify::EventCloseWrite | KInotify::EventCreate
68
69 m_dirWatch->addWatch(path, flags, KInotify::FlagOnlyDir);
70 }
71}
72
73void FileWatch::slotFileMoved(const QString& urlFrom, const QString& urlTo)
74{
75 if (m_config->shouldBeIndexed(urlTo)) {
76 m_metadataMover->moveFileMetadata(urlFrom, urlTo);
77 } else {
78 QFileInfo src(urlFrom);
79 QString url = urlFrom;
80
81 if (src.isDir() && !url.endsWith(QLatin1Char('/'))) {
82 url.append(QLatin1Char('/'));
83 }
84
85 PendingFile file(url);
86 file.setDeleted();
87
88 m_pendingFileQueue->enqueue(file);
89 }
90}
91
92void FileWatch::slotFileDeleted(const QString& urlString, bool isDir)
93{
94 // Directories must always end with a trailing slash '/'
95 QString url = urlString;
96 if (isDir && !url.endsWith(QLatin1Char('/'))) {
97 url.append(QLatin1Char('/'));
98 }
99
100 PendingFile file(url);
101 file.setDeleted();
102
103 m_pendingFileQueue->enqueue(file);
104}
105
106void FileWatch::slotFileCreated(const QString& path, bool isDir)
107{
108 Q_UNUSED(isDir);
109 PendingFile file(path);
110 file.setCreated();
111
112 m_pendingFileQueue->enqueue(file);
113}
114
115void FileWatch::slotFileModified(const QString& path)
116{
117 PendingFile file(path);
118 file.setModified();
119
120 //qCDebug(BALOO) << "MOD" << path;
121 m_pendingFileQueue->enqueue(file);
122}
123
124void FileWatch::slotFileClosedAfterWrite(const QString& path)
125{
127 QDateTime fileModification = QFileInfo(path).lastModified();
128 QDateTime dirModification = QFileInfo(QFileInfo(path).absoluteDir().absolutePath()).lastModified();
129
130 // If we have received a FileClosedAfterWrite event, then the file must have been
131 // closed within the last minute.
132 // This is being done cause many applications open the file under write mode, do not
133 // make any modifications and then close the file. This results in us getting
134 // the FileClosedAfterWrite event
135 if (fileModification.secsTo(current) <= 1000 * 60 || dirModification.secsTo(current) <= 1000 * 60) {
136 PendingFile file(path);
137 file.setClosedOnWrite();
138 //qCDebug(BALOO) << "CLOSE" << path;
139 m_pendingFileQueue->enqueue(file);
140 }
141}
142
143void FileWatch::slotAttributeChanged(const QString& path)
144{
145 PendingFile file(path);
146 file.setAttributeChanged();
147
148 m_pendingFileQueue->enqueue(file);
149}
150
151// This slot is connected to a signal emitted in KInotify when
152// inotify_add_watch fails with ENOSPC.
153void FileWatch::slotInotifyWatchUserLimitReached(const QString&)
154{
155 // If we got here, we hit the limit and are not allowed to raise it,
156 // so put something in the log.
157 qCWarning(BALOO) << "KDE Baloo File Indexer has reached the inotify folder watch limit. File changes will be ignored.";
158 // we do it the brutal way for now hoping with new kernels and defaults this will never happen
159 // Delete the KInotify
160 // FIXME: Maybe we should be aborting?
161 if (m_dirWatch) {
162 m_dirWatch->deleteLater();
163 m_dirWatch = nullptr;
164 }
165 Q_EMIT installedWatches();
166}
167
168void FileWatch::updateIndexedFoldersWatches()
169{
170 if (m_dirWatch) {
171 const QStringList excludedFolders = m_config->excludeFolders();
172 const QStringList includedFolders = m_config->includeFolders();
173
174 for (const QString& folder : excludedFolders) {
175 // Remove watch for new excluded folders
176 if (!m_excludedFolders.contains(folder)) {
177 m_dirWatch->removeWatch(folder);
178 }
179 }
180 for (const QString& folder : m_excludedFolders) {
181 // Add no longer excluded folders
182 if (!excludedFolders.contains(folder)) {
183 watchFolder(folder);
184 }
185 }
186
187 for (const QString& folder : m_includedFolders) {
188 // Remove no longer included folders
189 if (!includedFolders.contains(folder)) {
190 m_dirWatch->removeWatch(folder);
191 }
192 }
193 for (const QString& folder : includedFolders) {
194 if (!m_includedFolders.contains(folder)) {
195 watchFolder(folder);
196 }
197 }
198
199 m_excludedFolders = excludedFolders;
200 m_includedFolders = includedFolders;
201 }
202}
203
204#include "moc_filewatch.cpp"
Active config class which emits signals if the config was changed, for example if the KCM saved the c...
QStringList excludeFolders() const
Folders that are excluded from indexing.
bool shouldBeIndexed(const QString &path) const
Check if file or folder path should be indexed taking into account the includeFolders(),...
QStringList includeFolders() const
Folders to search for files to index and analyze.
Represents a file which needs to be indexed.
Definition pendingfile.h:20
A simple wrapper around inotify which only allows to add folders recursively.
Definition kinotify.h:25
void installedWatches()
This is emitted once watches have been installed in all the directories indicated by addWatch.
void created(const QString &file, bool isDir)
Emitted if a new file has been created in one of the watched folders (KInotify::EventCreate)
@ EventDelete
File/directory created in watched directory (compare inotify's IN_CREATE)
Definition kinotify.h:44
@ EventDeleteSelf
Watched file/directory was itself deleted (compare inotify's IN_DELETE_SELF)
Definition kinotify.h:45
@ EventCloseWrite
File opened for writing was closed (compare inotify's IN_CLOSE_WRITE)
Definition kinotify.h:41
@ EventModify
File was modified (compare inotify's IN_MODIFY)
Definition kinotify.h:46
@ EventAttributeChange
Metadata changed (permissions, timestamps, extended attributes, etc., compare inotify's IN_ATTRIB)
Definition kinotify.h:40
void modified(const QString &file)
Emitted if a watched file is modified (KInotify::EventModify)
void moved(const QString &oldName, const QString &newName)
Emitted if a file or folder has been moved or renamed.
void deleted(const QString &file, bool isDir)
Emitted if a watched file or folder has been deleted.
void watchUserLimitReached(const QString &path)
Emitted if during updating the internal watch structures (recursive watches) the inotify user watch l...
void closedWrite(const QString &file)
Emitted if FIXME (KInotify::EventCloseWrite)
@ FlagOnlyDir
Only watch the path if it is a directory (IN_ONLYDIR)
Definition kinotify.h:76
void attributeChanged(const QString &file)
Emitted if file attributes are changed (KInotify::EventAttributeChange)
Implements storage for docIds without any associated data Instantiated for:
Definition coding.cpp:11
QDateTime currentDateTime()
qint64 secsTo(const QDateTime &other) const const
QDateTime lastModified() const const
Q_EMITQ_EMIT
void deleteLater()
QString & append(QChar ch)
bool endsWith(QChar c, Qt::CaseSensitivity cs) const const
bool contains(QLatin1StringView str, Qt::CaseSensitivity cs) const const
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Sat Dec 21 2024 16:56:58 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.