| 1 | /* |
| 2 | This file is part of the KDE libraries |
| 3 | SPDX-FileCopyrightText: 2007-2010 Sebastian Trueg <trueg@kde.org> |
| 4 | |
| 5 | SPDX-License-Identifier: LGPL-2.0-or-later |
| 6 | */ |
| 7 | |
| 8 | #ifndef KINOTIFY_H_ |
| 9 | #define KINOTIFY_H_ |
| 10 | |
| 11 | #include <QObject> |
| 12 | |
| 13 | namespace Baloo { |
| 14 | class FileIndexerConfig; |
| 15 | } |
| 16 | |
| 17 | /** |
| 18 | * A simple wrapper around inotify which only allows |
| 19 | * to add folders recursively. |
| 20 | * |
| 21 | * Warning: moving of top-level folders is not supported and |
| 22 | * results in undefined behaviour. |
| 23 | */ |
| 24 | class KInotify : public QObject |
| 25 | { |
| 26 | Q_OBJECT |
| 27 | |
| 28 | public: |
| 29 | explicit KInotify(Baloo::FileIndexerConfig* config, QObject* parent = nullptr); |
| 30 | ~KInotify() override; |
| 31 | |
| 32 | /** |
| 33 | * Inotify events that can occur. Use with addWatch |
| 34 | * to define the events that should be watched. |
| 35 | * |
| 36 | * These flags correspond to the native Linux inotify flags. |
| 37 | */ |
| 38 | enum WatchEvent { |
| 39 | EventAccess = 0x00000001, /**< File was accessed (read, compare inotify's IN_ACCESS) */ |
| 40 | EventAttributeChange = 0x00000004, /**< Metadata changed (permissions, timestamps, extended attributes, etc., compare inotify's IN_ATTRIB) */ |
| 41 | EventCloseWrite = 0x00000008, /**< File opened for writing was closed (compare inotify's IN_CLOSE_WRITE) */ |
| 42 | EventCloseRead = 0x00000010, /**< File not opened for writing was closed (compare inotify's IN_CLOSE_NOWRITE) */ |
| 43 | EventCreate = 0x00000100, /** File/directory created in watched directory (compare inotify's IN_CREATE) */ |
| 44 | EventDelete = 0x00000200, /**< File/directory deleted from watched directory (compare inotify's IN_DELETE) */ |
| 45 | EventDeleteSelf = 0x00000400, /**< Watched file/directory was itself deleted (compare inotify's IN_DELETE_SELF) */ |
| 46 | EventModify = 0x00000002, /**< File was modified (compare inotify's IN_MODIFY) */ |
| 47 | EventMoveSelf = 0x00000800, /**< Watched file/directory was itself moved (compare inotify's IN_MOVE_SELF) */ |
| 48 | EventMoveFrom = 0x00000040, /**< File moved out of watched directory (compare inotify's IN_MOVED_FROM) */ |
| 49 | EventMoveTo = 0x00000080, /**< File moved into watched directory (compare inotify's IN_MOVED_TO) */ |
| 50 | EventOpen = 0x00000020, /**< File was opened (compare inotify's IN_OPEN) */ |
| 51 | EventUnmount = 0x00002000, /**< Backing fs was unmounted (compare inotify's IN_UNMOUNT) */ |
| 52 | EventQueueOverflow = 0x00004000, /**< Event queued overflowed (compare inotify's IN_Q_OVERFLOW) */ |
| 53 | EventIgnored = 0x00008000, /**< File was ignored (compare inotify's IN_IGNORED) */ |
| 54 | EventMove = (EventMoveFrom | EventMoveTo), |
| 55 | EventAll = (EventAccess | |
| 56 | EventAttributeChange | |
| 57 | EventCloseWrite | |
| 58 | EventCloseRead | |
| 59 | EventCreate | |
| 60 | EventDelete | |
| 61 | EventDeleteSelf | |
| 62 | EventModify | |
| 63 | EventMoveSelf | |
| 64 | EventMoveFrom | |
| 65 | EventMoveTo | |
| 66 | EventOpen), |
| 67 | }; |
| 68 | Q_DECLARE_FLAGS(WatchEvents, WatchEvent) |
| 69 | |
| 70 | /** |
| 71 | * Watch flags |
| 72 | * |
| 73 | * These flags correspond to the native Linux inotify flags. |
| 74 | */ |
| 75 | enum WatchFlag { |
| 76 | FlagOnlyDir = 0x01000000, /**< Only watch the path if it is a directory (IN_ONLYDIR) */ |
| 77 | FlagDoNotFollow = 0x02000000, /**< Don't follow a sym link (IN_DONT_FOLLOW) */ |
| 78 | FlagOneShot = 0x80000000, /**< Only send event once (IN_ONESHOT) */ |
| 79 | FlagExclUnlink = 0x04000000, /**< Do not generate events for unlinked files (IN_EXCL_UNLINK) */ |
| 80 | }; |
| 81 | Q_DECLARE_FLAGS(WatchFlags, WatchFlag) |
| 82 | |
| 83 | bool watchingPath(const QString& path) const; |
| 84 | |
| 85 | /** |
| 86 | * Call this when the inotify limit has been increased. |
| 87 | */ |
| 88 | void resetUserLimit(); |
| 89 | |
| 90 | public Q_SLOTS: |
| 91 | bool addWatch(const QString& path, WatchEvents modes, WatchFlags flags = WatchFlags()); |
| 92 | bool removeWatch(const QString& path); |
| 93 | |
| 94 | Q_SIGNALS: |
| 95 | /** |
| 96 | * Emitted if a file is accessed (KInotify::EventAccess) |
| 97 | */ |
| 98 | void accessed(const QString& file); |
| 99 | |
| 100 | /** |
| 101 | * Emitted if file attributes are changed (KInotify::EventAttributeChange) |
| 102 | */ |
| 103 | void attributeChanged(const QString& file); |
| 104 | |
| 105 | /** |
| 106 | * Emitted if FIXME (KInotify::EventCloseWrite) |
| 107 | */ |
| 108 | void closedWrite(const QString& file); |
| 109 | |
| 110 | /** |
| 111 | * Emitted if FIXME (KInotify::EventCloseRead) |
| 112 | */ |
| 113 | void closedRead(const QString& file); |
| 114 | |
| 115 | /** |
| 116 | * Emitted if a new file has been created in one of the watched |
| 117 | * folders (KInotify::EventCreate) |
| 118 | */ |
| 119 | void created(const QString& file, bool isDir); |
| 120 | |
| 121 | /** |
| 122 | * Emitted if a watched file or folder has been deleted. |
| 123 | * This includes files in watched folders (KInotify::EventDelete and KInotify::EventDeleteSelf) |
| 124 | */ |
| 125 | void deleted(const QString& file, bool isDir); |
| 126 | |
| 127 | /** |
| 128 | * Emitted if a watched file is modified (KInotify::EventModify) |
| 129 | */ |
| 130 | void modified(const QString& file); |
| 131 | |
| 132 | /** |
| 133 | * Emitted if a file or folder has been moved or renamed. |
| 134 | * |
| 135 | * \warning The moved signal will only be emitted if both the source and target folder |
| 136 | * are being watched. |
| 137 | */ |
| 138 | void moved(const QString& oldName, const QString& newName); |
| 139 | |
| 140 | /** |
| 141 | * Emitted if a file is opened (KInotify::EventOpen) |
| 142 | */ |
| 143 | void opened(const QString& file); |
| 144 | |
| 145 | /** |
| 146 | * Emitted if a watched path has been unmounted (KInotify::EventUnmount) |
| 147 | */ |
| 148 | void unmounted(const QString& file); |
| 149 | |
| 150 | /** |
| 151 | * Emitted if during updating the internal watch structures (recursive watches) |
| 152 | * the inotify user watch limit was reached. |
| 153 | * |
| 154 | * This means that not all requested paths can be watched until the user watch |
| 155 | * limit is increased. |
| 156 | * |
| 157 | * The argument is the path being added when the limit was reached. |
| 158 | * |
| 159 | * This signal will only be emitted once until resetUserLimit is called. |
| 160 | */ |
| 161 | void watchUserLimitReached(const QString& path); |
| 162 | |
| 163 | /** |
| 164 | * This is emitted once watches have been installed in all the directories |
| 165 | * indicated by addWatch |
| 166 | */ |
| 167 | void installedWatches(); |
| 168 | |
| 169 | private Q_SLOTS: |
| 170 | void slotEvent(int); |
| 171 | void slotClearCookies(); |
| 172 | |
| 173 | private: |
| 174 | class Private; |
| 175 | Private* const d; |
| 176 | |
| 177 | /** |
| 178 | * Recursively iterates over all files/folders inside @param path |
| 179 | * (that are not excluded by the config); |
| 180 | * emits created() signal for each entry (excluding @param path) |
| 181 | * and installs watches for all subdirectories (including @param path) |
| 182 | */ |
| 183 | void handleDirCreated(const QString& path); |
| 184 | }; |
| 185 | |
| 186 | #endif |
| 187 | |