@@ -73,6 +73,8 @@ type Listener struct {
73
73
fd int
74
74
// flags passed to fanotify_init
75
75
flags uint
76
+ // markMask current fanotify mark mask
77
+ markMask uint64
76
78
// mount fd is the file descriptor of the mountpoint
77
79
mountpoint * os.File
78
80
kernelMajorVersion int
@@ -203,14 +205,23 @@ func (l *Listener) Stop() {
203
205
// for - [FileCreated], [FileAttribChanged], [FileMovedTo], [FileMovedFrom], [WatchedFileDeleted],
204
206
// [WatchedFileOrDirectoryDeleted], [FileDeleted], [FileOrDirectoryDeleted]
205
207
func (l * Listener ) WatchMount (eventTypes EventType ) error {
206
- return l .fanotifyMark (l .mountpoint .Name (), unix .FAN_MARK_ADD | unix .FAN_MARK_MOUNT , uint64 (eventTypes ))
208
+ mask := l .getMaskAfterAdd (eventTypes )
209
+ l .clearWatch ()
210
+ l .markMask = uint64 (mask )
211
+ return l .fanotifyMark (l .mountpoint .Name (), unix .FAN_MARK_ADD | unix .FAN_MARK_MOUNT , uint64 (mask ))
207
212
}
208
213
209
214
// UnwatchMount removes the notification marks for the entire mount point.
210
215
// This method returns an [ErrWatchPath] if the listener was not initialized to monitor
211
216
// the entire mount point. To unmark specific files or directories use [DeleteWatch] method.
212
217
func (l * Listener ) UnwatchMount (eventTypes EventType ) error {
213
- return l .fanotifyMark (l .mountpoint .Name (), unix .FAN_MARK_REMOVE | unix .FAN_MARK_MOUNT , uint64 (eventTypes ))
218
+ if l .markMask == 0 {
219
+ return l .clearWatch ()
220
+ }
221
+ remaining := l .getMaskAfterRemove (eventTypes )
222
+ l .clearWatch ()
223
+ l .markMask = uint64 (remaining )
224
+ return l .fanotifyMark (l .mountpoint .Name (), unix .FAN_MARK_ADD | unix .FAN_MARK_MOUNT , uint64 (remaining ))
214
225
}
215
226
216
227
// AddWatch adds or modifies the fanotify mark for the specified path.
@@ -221,14 +232,46 @@ func (l *Listener) UnwatchMount(eventTypes EventType) error {
221
232
// - [FileCreated] cannot be or-ed / combined with [FileClosed]. The fanotify system does not generate any event for this combination.
222
233
// - [FileOpened] with any of the event types containing OrDirectory causes an event flood for the directory and then stopping raising any events at all.
223
234
// - [FileOrDirectoryOpened] with any of the other event types causes an event flood for the directory and then stopping raising any events at all.
235
+ //
236
+ // NOTE:
237
+ // Any event type that contains "OrDirectory" applies the OrDirectory mask to any other applicable
238
+ // marks. For example adding [FileDeleted] and [FileOrDirectoryOpened] will apply "OrDirectory" to
239
+ // [FileDeleted] thus the resulting mask will be set to [FileOrDirectoryOpened] and [FileOrDirectoryDeleted]
224
240
func (l * Listener ) AddWatch (path string , eventTypes EventType ) error {
225
241
if l == nil {
226
242
panic ("nil listener" )
227
243
}
228
244
if l .entireMount {
229
245
return os .ErrInvalid
230
246
}
231
- return l .fanotifyMark (path , unix .FAN_MARK_ADD , uint64 (eventTypes | unix .FAN_EVENT_ON_CHILD ))
247
+ mask := l .getMaskAfterAdd (eventTypes )
248
+ l .clearWatch ()
249
+ l .markMask = uint64 (mask )
250
+ return l .fanotifyMark (path , unix .FAN_MARK_ADD , uint64 (mask | unix .FAN_EVENT_ON_CHILD ))
251
+ }
252
+
253
+ // DeleteWatch removes/unmarks the fanotify mark for the specified path.
254
+ // Calling DeleteWatch on the listener initialized to monitor the entire mount point
255
+ // results in [os.ErrInvalid]. Use [UnwatchMount] for deleting marks on the mount point.
256
+ func (l * Listener ) DeleteWatch (parentDir string , eventTypes EventType ) error {
257
+ if l .entireMount {
258
+ return os .ErrInvalid
259
+ }
260
+ if l .markMask == 0 {
261
+ return l .clearWatch ()
262
+ }
263
+ remaining := l .getMaskAfterRemove (eventTypes )
264
+ l .clearWatch ()
265
+ l .markMask = uint64 (remaining )
266
+ return l .fanotifyMark (parentDir , unix .FAN_MARK_ADD , uint64 (remaining | unix .FAN_EVENT_ON_CHILD ))
267
+ }
268
+
269
+ // ClearWatch stops watching for all event types
270
+ func (l * Listener ) ClearWatch () error {
271
+ if l == nil {
272
+ panic ("nil listener" )
273
+ }
274
+ return l .clearWatch ()
232
275
}
233
276
234
277
// Allow sends an "allowed" response to the permission request event.
@@ -251,28 +294,6 @@ func (l *Listener) Deny(e Event) {
251
294
unix .Write (l .fd , buf .Bytes ())
252
295
}
253
296
254
- // DeleteWatch removes/unmarks the fanotify mark for the specified path.
255
- // Calling DeleteWatch on the listener initialized to monitor the entire mount point
256
- // results in [os.ErrInvalid]. Use [UnwatchMount] for deleting marks on the mount point.
257
- func (l * Listener ) DeleteWatch (parentDir string , eventTypes EventType ) error {
258
- if l .entireMount {
259
- return os .ErrInvalid
260
- }
261
- return l .fanotifyMark (parentDir , unix .FAN_MARK_REMOVE , uint64 (eventTypes | unix .FAN_EVENT_ON_CHILD ))
262
- }
263
-
264
- // ClearWatch stops watching for all event types
265
- func (l * Listener ) ClearWatch () error {
266
- if l == nil {
267
- panic ("nil listener" )
268
- }
269
- if err := unix .FanotifyMark (l .fd , unix .FAN_MARK_FLUSH , 0 , - 1 , "" ); err != nil {
270
- return err
271
- }
272
- l .watches = make (map [string ]bool )
273
- return nil
274
- }
275
-
276
297
// Has returns true if event types (e) contains the passed in event type (et).
277
298
func (e EventType ) Has (et EventType ) bool {
278
299
return e & et == et
0 commit comments