File indexing completed on 2024-05-12 03:54:55
0001 /* 0002 This file is part of the KDE libraries 0003 0004 SPDX-FileCopyrightText: 1998 Sven Radej <sven@lisa.exp.univie.ac.at> 0005 SPDX-FileCopyrightText: 2006 Dirk Mueller <mueller@kde.org> 0006 SPDX-FileCopyrightText: 2007 Flavio Castelli <flavio.castelli@gmail.com> 0007 SPDX-FileCopyrightText: 2008 Jarosław Staniek <staniek@kde.org> 0008 SPDX-FileCopyrightText: 2020 Harald Sitter <sitter@kde.org> 0009 0010 SPDX-License-Identifier: LGPL-2.0-only 0011 0012 Private Header for class of KDirWatchPrivate 0013 this separate header file is needed for MOC processing 0014 because KDirWatchPrivate has signals and slots 0015 */ 0016 0017 #ifndef KDIRWATCH_P_H 0018 #define KDIRWATCH_P_H 0019 0020 #include "kdirwatch.h" 0021 #include <io/config-kdirwatch.h> 0022 0023 #ifndef QT_NO_FILESYSTEMWATCHER 0024 #define HAVE_QFILESYSTEMWATCHER 1 0025 #else 0026 #define HAVE_QFILESYSTEMWATCHER 0 0027 #endif 0028 0029 #include <QList> 0030 #include <QMap> 0031 #include <QObject> 0032 #include <QSet> 0033 #include <QString> 0034 #include <QTimer> 0035 class QSocketNotifier; 0036 0037 #include <ctime> 0038 #include <sys/types.h> // time_t, ino_t 0039 0040 #define invalid_ctime (static_cast<time_t>(-1)) 0041 0042 #if HAVE_QFILESYSTEMWATCHER 0043 #include <QFileSystemWatcher> 0044 #endif // HAVE_QFILESYSTEMWATCHER 0045 0046 #if HAVE_SYS_INOTIFY_H 0047 struct inotify_event; 0048 #endif 0049 0050 /* KDirWatchPrivate is a singleton and does the watching 0051 * for every KDirWatch instance in the application. 0052 */ 0053 class KDirWatchPrivate : public QObject 0054 { 0055 Q_OBJECT 0056 public: 0057 enum entryStatus { 0058 Normal = 0, 0059 NonExistent, 0060 }; 0061 enum entryMode { 0062 UnknownMode = 0, 0063 StatMode, 0064 INotifyMode, 0065 QFSWatchMode, 0066 }; 0067 enum { 0068 NoChange = 0, 0069 Changed = 1, 0070 Created = 2, 0071 Deleted = 4, 0072 }; 0073 0074 struct Client { 0075 Client(KDirWatch *inst, KDirWatch::WatchModes watchModes) 0076 : instance(inst) 0077 , count(1) 0078 , watchingStopped(inst->isStopped()) 0079 , pending(NoChange) 0080 , m_watchModes(watchModes) 0081 { 0082 } 0083 0084 // The compiler needs a copy ctor for Client when Entry is inserted into m_mapEntries 0085 // (even though the vector of clients is empty at that point, so no performance penalty there) 0086 // Client(const Client &) = delete; 0087 // Client &operator=(const Client &) = delete; 0088 // Client(Client &&) = default; 0089 // Client &operator=(Client &&) = default; 0090 0091 KDirWatch *instance; 0092 int count; 0093 // did the instance stop watching 0094 bool watchingStopped; 0095 // events blocked when stopped 0096 int pending; 0097 KDirWatch::WatchModes m_watchModes; 0098 }; 0099 0100 class Entry 0101 { 0102 public: 0103 ~Entry(); 0104 // instances interested in events 0105 std::vector<Client> m_clients; 0106 // nonexistent entries of this directory 0107 QList<Entry *> m_entries; 0108 QString path; 0109 0110 // the last observed modification time 0111 time_t m_ctime; 0112 // last observed inode 0113 ino_t m_ino; 0114 // the last observed link count 0115 int m_nlink; 0116 entryStatus m_status; 0117 entryMode m_mode; 0118 int msecLeft, freq; 0119 bool isDir; 0120 0121 QString parentDirectory() const; 0122 void addClient(KDirWatch *, KDirWatch::WatchModes); 0123 void removeClient(KDirWatch *); 0124 int clientCount() const; 0125 bool isValid() 0126 { 0127 return !m_clients.empty() || !m_entries.empty(); 0128 } 0129 0130 Entry *findSubEntry(const QString &path) const 0131 { 0132 for (Entry *sub_entry : std::as_const(m_entries)) { 0133 if (sub_entry->path == path) { 0134 return sub_entry; 0135 } 0136 } 0137 return nullptr; 0138 } 0139 0140 bool dirty; 0141 void propagate_dirty(); 0142 0143 QList<const Client *> clientsForFileOrDir(const QString &tpath, bool *isDir) const; 0144 QList<const Client *> inotifyClientsForFileOrDir(bool isDir) const; 0145 0146 std::vector<Client>::iterator findInstance(KDirWatch *other) 0147 { 0148 return std::find_if(m_clients.begin(), m_clients.end(), [other](const Client &client) { 0149 return client.instance == other; 0150 }); 0151 } 0152 0153 #if HAVE_SYS_INOTIFY_H 0154 int wd; 0155 // Creation and Deletion of files happens infrequently, so 0156 // can safely be reported as they occur. File changes i.e. those that emit "dirty()" can 0157 // happen many times per second, though, so maintain a list of files in this directory 0158 // that can be emitted and flushed at the next slotRescan(...). 0159 // This will be unused if the Entry is not a directory. 0160 QList<QString> m_pendingFileChanges; 0161 #endif 0162 }; 0163 0164 typedef QMap<QString, Entry> EntryMap; 0165 0166 KDirWatchPrivate(); 0167 ~KDirWatchPrivate() override; 0168 0169 void resetList(KDirWatch *instance, bool skippedToo); 0170 void useFreq(Entry *e, int newFreq); 0171 void addEntry(KDirWatch *instance, const QString &_path, Entry *sub_entry, bool isDir, KDirWatch::WatchModes watchModes = KDirWatch::WatchDirOnly); 0172 void removeEntry(KDirWatch *instance, const QString &path, Entry *sub_entry); 0173 void removeEntry(KDirWatch *instance, Entry *e, Entry *sub_entry); 0174 bool stopEntryScan(KDirWatch *instance, Entry *e); 0175 bool restartEntryScan(KDirWatch *instance, Entry *e, bool notify); 0176 void stopScan(KDirWatch *instance); 0177 void startScan(KDirWatch *instance, bool notify, bool skippedToo); 0178 0179 void removeEntries(KDirWatch *instance); 0180 0181 void addWatch(Entry *entry); 0182 void removeWatch(Entry *entry); 0183 Entry *entry(const QString &_path); 0184 int scanEntry(Entry *e); 0185 void emitEvent(Entry *e, int event, const QString &fileName = QString()); 0186 0187 static bool isNoisyFile(const char *filename); 0188 0189 void ref(KDirWatch *watch); 0190 void unref(KDirWatch *watch); 0191 0192 #if HAVE_SYS_INOTIFY_H 0193 QString inotifyEventName(const inotify_event *event) const; 0194 #endif 0195 0196 public Q_SLOTS: 0197 void slotRescan(); 0198 void inotifyEventReceived(); // for inotify 0199 void slotRemoveDelayed(); 0200 void fswEventReceived(const QString &path); // for QFileSystemWatcher 0201 0202 public: 0203 QTimer m_statRescanTimer; 0204 EntryMap m_mapEntries; 0205 0206 KDirWatch::Method m_preferredMethod, m_nfsPreferredMethod; 0207 int freq; 0208 int statEntries; 0209 int m_nfsPollInterval, m_PollInterval; 0210 bool useStat(Entry *e); 0211 0212 // removeList is allowed to contain any entry at most once 0213 QSet<Entry *> removeList; 0214 bool delayRemove; 0215 0216 bool rescan_all; 0217 QTimer rescan_timer; 0218 0219 #if HAVE_SYS_INOTIFY_H 0220 QSocketNotifier *mSn; 0221 bool supports_inotify; 0222 int m_inotify_fd; 0223 QHash<int, Entry *> m_inotify_wd_to_entry; 0224 0225 bool useINotify(Entry *e); 0226 #endif 0227 #if HAVE_QFILESYSTEMWATCHER 0228 QFileSystemWatcher *fsWatcher; 0229 bool useQFSWatch(Entry *e); 0230 #endif 0231 0232 bool _isStopped; 0233 0234 private: 0235 // Public objects that reference this thread-local private instance. 0236 QList<KDirWatch *> m_referencesObjects; 0237 }; 0238 0239 QDebug operator<<(QDebug debug, const KDirWatchPrivate &dwp); 0240 QDebug operator<<(QDebug debug, const KDirWatchPrivate::Entry &entry); 0241 0242 #endif // KDIRWATCH_P_H