notify/
inotify.rs

1//! Watcher implementation for the inotify Linux API
2//!
3//! The inotify API provides a mechanism for monitoring filesystem events.  Inotify can be used to
4//! monitor individual files, or to monitor directories.  When a directory is monitored, inotify
5//! will return events for the directory itself, and for files inside the directory.
6
7use super::event::*;
8use super::{Config, Error, ErrorKind, EventHandler, RecursiveMode, Result, Watcher};
9use crate::{BoundSender, Receiver, Sender, bounded, unbounded};
10use inotify as inotify_sys;
11use inotify_sys::{EventMask, Inotify, WatchDescriptor, WatchMask};
12use std::collections::HashMap;
13use std::env;
14use std::ffi::OsStr;
15use std::fs::metadata;
16use std::os::unix::io::AsRawFd;
17use std::path::{Path, PathBuf};
18use std::sync::Arc;
19use std::thread;
20use walkdir::WalkDir;
21
22const INOTIFY: mio::Token = mio::Token(0);
23const MESSAGE: mio::Token = mio::Token(1);
24
25// The EventLoop will set up a mio::Poll and use it to wait for the following:
26//
27// -  messages telling it what to do
28//
29// -  events telling it that something has happened on one of the watched files.
30
31struct EventLoop {
32    running: bool,
33    poll: mio::Poll,
34    event_loop_waker: Arc<mio::Waker>,
35    event_loop_tx: Sender<EventLoopMsg>,
36    event_loop_rx: Receiver<EventLoopMsg>,
37    inotify: Option<Inotify>,
38    event_handler: Box<dyn EventHandler>,
39    /// PathBuf -> (WatchDescriptor, WatchMask, is_recursive, is_dir)
40    watches: HashMap<PathBuf, (WatchDescriptor, WatchMask, bool, bool)>,
41    paths: HashMap<WatchDescriptor, PathBuf>,
42    rename_event: Option<Event>,
43    follow_links: bool,
44}
45
46/// Watcher implementation based on inotify
47#[derive(Debug)]
48pub struct INotifyWatcher {
49    channel: Sender<EventLoopMsg>,
50    waker: Arc<mio::Waker>,
51}
52
53enum EventLoopMsg {
54    AddWatch(PathBuf, RecursiveMode, Sender<Result<()>>),
55    RemoveWatch(PathBuf, Sender<Result<()>>),
56    Shutdown,
57    Configure(Config, BoundSender<Result<bool>>),
58}
59
60#[inline]
61fn add_watch_by_event(
62    path: &PathBuf,
63    event: &inotify_sys::Event<&OsStr>,
64    watches: &HashMap<PathBuf, (WatchDescriptor, WatchMask, bool, bool)>,
65    add_watches: &mut Vec<PathBuf>,
66) {
67    if event.mask.contains(EventMask::ISDIR)
68        && let Some(parent_path) = path.parent()
69        && let Some(&(_, _, is_recursive, _)) = watches.get(parent_path)
70        && is_recursive
71    {
72        add_watches.push(path.to_owned());
73    }
74}
75
76#[inline]
77fn remove_watch_by_event(
78    path: &PathBuf,
79    watches: &HashMap<PathBuf, (WatchDescriptor, WatchMask, bool, bool)>,
80    remove_watches: &mut Vec<PathBuf>,
81) {
82    if watches.contains_key(path) {
83        remove_watches.push(path.to_owned());
84    }
85}
86
87impl EventLoop {
88    pub fn new(
89        inotify: Inotify,
90        event_handler: Box<dyn EventHandler>,
91        follow_links: bool,
92    ) -> Result<Self> {
93        let (event_loop_tx, event_loop_rx) = unbounded::<EventLoopMsg>();
94        let poll = mio::Poll::new()?;
95
96        let event_loop_waker = Arc::new(mio::Waker::new(poll.registry(), MESSAGE)?);
97
98        let inotify_fd = inotify.as_raw_fd();
99        let mut evented_inotify = mio::unix::SourceFd(&inotify_fd);
100        poll.registry()
101            .register(&mut evented_inotify, INOTIFY, mio::Interest::READABLE)?;
102
103        let event_loop = EventLoop {
104            running: true,
105            poll,
106            event_loop_waker,
107            event_loop_tx,
108            event_loop_rx,
109            inotify: Some(inotify),
110            event_handler,
111            watches: HashMap::new(),
112            paths: HashMap::new(),
113            rename_event: None,
114            follow_links,
115        };
116        Ok(event_loop)
117    }
118
119    // Run the event loop.
120    pub fn run(self) {
121        let _ = thread::Builder::new()
122            .name("notify-rs inotify loop".to_string())
123            .spawn(|| self.event_loop_thread());
124    }
125
126    fn event_loop_thread(mut self) {
127        let mut events = mio::Events::with_capacity(16);
128        loop {
129            // Wait for something to happen.
130            match self.poll.poll(&mut events, None) {
131                Err(ref e) if matches!(e.kind(), std::io::ErrorKind::Interrupted) => {
132                    // System call was interrupted, we will retry
133                    // TODO: Not covered by tests (to reproduce likely need to setup signal handlers)
134                }
135                Err(e) => panic!("poll failed: {}", e),
136                Ok(()) => {}
137            }
138
139            // Process whatever happened.
140            for event in &events {
141                self.handle_event(event);
142            }
143
144            // Stop, if we're done.
145            if !self.running {
146                break;
147            }
148        }
149    }
150
151    // Handle a single event.
152    fn handle_event(&mut self, event: &mio::event::Event) {
153        match event.token() {
154            MESSAGE => {
155                // The channel is readable - handle messages.
156                self.handle_messages()
157            }
158            INOTIFY => {
159                // inotify has something to tell us.
160                self.handle_inotify()
161            }
162            _ => unreachable!(),
163        }
164    }
165
166    fn handle_messages(&mut self) {
167        while let Ok(msg) = self.event_loop_rx.try_recv() {
168            match msg {
169                EventLoopMsg::AddWatch(path, recursive_mode, tx) => {
170                    let _ = tx.send(self.add_watch(path, recursive_mode.is_recursive(), true));
171                }
172                EventLoopMsg::RemoveWatch(path, tx) => {
173                    let _ = tx.send(self.remove_watch(path, false));
174                }
175                EventLoopMsg::Shutdown => {
176                    let _ = self.remove_all_watches();
177                    if let Some(inotify) = self.inotify.take() {
178                        let _ = inotify.close();
179                    }
180                    self.running = false;
181                    break;
182                }
183                EventLoopMsg::Configure(config, tx) => {
184                    self.configure_raw_mode(config, tx);
185                }
186            }
187        }
188    }
189
190    fn configure_raw_mode(&mut self, _config: Config, tx: BoundSender<Result<bool>>) {
191        tx.send(Ok(false))
192            .expect("configuration channel disconnected");
193    }
194
195    fn handle_inotify(&mut self) {
196        let mut add_watches = Vec::new();
197        let mut remove_watches = Vec::new();
198
199        if let Some(ref mut inotify) = self.inotify {
200            let mut buffer = [0; 1024];
201            // Read all buffers available.
202            loop {
203                match inotify.read_events(&mut buffer) {
204                    Ok(events) => {
205                        let mut num_events = 0;
206                        for event in events {
207                            log::trace!("inotify event: {event:?}");
208
209                            num_events += 1;
210                            if event.mask.contains(EventMask::Q_OVERFLOW) {
211                                let ev = Ok(Event::new(EventKind::Other).set_flag(Flag::Rescan));
212                                self.event_handler.handle_event(ev);
213                            }
214
215                            let path = match event.name {
216                                Some(name) => self.paths.get(&event.wd).map(|root| root.join(name)),
217                                None => self.paths.get(&event.wd).cloned(),
218                            };
219
220                            let path = match path {
221                                Some(path) => path,
222                                None => {
223                                    log::debug!("inotify event with unknown descriptor: {event:?}");
224                                    continue;
225                                }
226                            };
227
228                            let mut evs = Vec::new();
229
230                            if event.mask.contains(EventMask::MOVED_FROM) {
231                                remove_watch_by_event(&path, &self.watches, &mut remove_watches);
232
233                                let event = Event::new(EventKind::Modify(ModifyKind::Name(
234                                    RenameMode::From,
235                                )))
236                                .add_path(path.clone())
237                                .set_tracker(event.cookie as usize);
238
239                                self.rename_event = Some(event.clone());
240
241                                evs.push(event);
242                            } else if event.mask.contains(EventMask::MOVED_TO) {
243                                evs.push(
244                                    Event::new(EventKind::Modify(ModifyKind::Name(RenameMode::To)))
245                                        .set_tracker(event.cookie as usize)
246                                        .add_path(path.clone()),
247                                );
248
249                                let trackers_match =
250                                    self.rename_event.as_ref().and_then(|e| e.tracker())
251                                        == Some(event.cookie as usize);
252
253                                if trackers_match {
254                                    let rename_event = self.rename_event.take().unwrap(); // unwrap is safe because `rename_event` must be set at this point
255                                    evs.push(
256                                        Event::new(EventKind::Modify(ModifyKind::Name(
257                                            RenameMode::Both,
258                                        )))
259                                        .set_tracker(event.cookie as usize)
260                                        .add_some_path(rename_event.paths.first().cloned())
261                                        .add_path(path.clone()),
262                                    );
263                                }
264                                add_watch_by_event(&path, &event, &self.watches, &mut add_watches);
265                            }
266                            if event.mask.contains(EventMask::MOVE_SELF) {
267                                evs.push(
268                                    Event::new(EventKind::Modify(ModifyKind::Name(
269                                        RenameMode::From,
270                                    )))
271                                    .add_path(path.clone()),
272                                );
273                                // TODO stat the path and get to new path
274                                // - emit To and Both events
275                                // - change prefix for further events
276                            }
277                            if event.mask.contains(EventMask::CREATE) {
278                                evs.push(
279                                    Event::new(EventKind::Create(
280                                        if event.mask.contains(EventMask::ISDIR) {
281                                            CreateKind::Folder
282                                        } else {
283                                            CreateKind::File
284                                        },
285                                    ))
286                                    .add_path(path.clone()),
287                                );
288                                add_watch_by_event(&path, &event, &self.watches, &mut add_watches);
289                            }
290                            if event.mask.contains(EventMask::DELETE) {
291                                evs.push(
292                                    Event::new(EventKind::Remove(
293                                        if event.mask.contains(EventMask::ISDIR) {
294                                            RemoveKind::Folder
295                                        } else {
296                                            RemoveKind::File
297                                        },
298                                    ))
299                                    .add_path(path.clone()),
300                                );
301                                remove_watch_by_event(&path, &self.watches, &mut remove_watches);
302                            }
303                            if event.mask.contains(EventMask::DELETE_SELF) {
304                                let remove_kind = match self.watches.get(&path) {
305                                    Some(&(_, _, _, true)) => RemoveKind::Folder,
306                                    Some(&(_, _, _, false)) => RemoveKind::File,
307                                    None => RemoveKind::Other,
308                                };
309                                evs.push(
310                                    Event::new(EventKind::Remove(remove_kind))
311                                        .add_path(path.clone()),
312                                );
313                                remove_watch_by_event(&path, &self.watches, &mut remove_watches);
314                            }
315                            if event.mask.contains(EventMask::MODIFY) {
316                                evs.push(
317                                    Event::new(EventKind::Modify(ModifyKind::Data(
318                                        DataChange::Any,
319                                    )))
320                                    .add_path(path.clone()),
321                                );
322                            }
323                            if event.mask.contains(EventMask::CLOSE_WRITE) {
324                                evs.push(
325                                    Event::new(EventKind::Access(AccessKind::Close(
326                                        AccessMode::Write,
327                                    )))
328                                    .add_path(path.clone()),
329                                );
330                            }
331                            if event.mask.contains(EventMask::CLOSE_NOWRITE) {
332                                evs.push(
333                                    Event::new(EventKind::Access(AccessKind::Close(
334                                        AccessMode::Read,
335                                    )))
336                                    .add_path(path.clone()),
337                                );
338                            }
339                            if event.mask.contains(EventMask::ATTRIB) {
340                                evs.push(
341                                    Event::new(EventKind::Modify(ModifyKind::Metadata(
342                                        MetadataKind::Any,
343                                    )))
344                                    .add_path(path.clone()),
345                                );
346                            }
347                            if event.mask.contains(EventMask::OPEN) {
348                                evs.push(
349                                    Event::new(EventKind::Access(AccessKind::Open(
350                                        AccessMode::Any,
351                                    )))
352                                    .add_path(path.clone()),
353                                );
354                            }
355
356                            for ev in evs {
357                                self.event_handler.handle_event(Ok(ev));
358                            }
359                        }
360
361                        // All events read. Break out.
362                        if num_events == 0 {
363                            break;
364                        }
365                    }
366                    Err(e) if e.kind() == std::io::ErrorKind::WouldBlock => {
367                        // No events read. Break out.
368                        break;
369                    }
370                    Err(e) => {
371                        self.event_handler.handle_event(Err(Error::io(e)));
372                    }
373                }
374            }
375        }
376
377        for path in remove_watches {
378            self.remove_watch(path, true).ok();
379        }
380
381        for path in add_watches {
382            if let Err(add_watch_error) = self.add_watch(path, true, false) {
383                // The handler should be notified if we have reached the limit.
384                // Otherwise, the user might expect that a recursive watch
385                // is continuing to work correctly, but it's not.
386                if let ErrorKind::MaxFilesWatch = add_watch_error.kind {
387                    self.event_handler.handle_event(Err(add_watch_error));
388
389                    // After that kind of a error we should stop adding watches,
390                    // because the limit has already reached and all next calls
391                    // will return us only the same error.
392                    break;
393                }
394            }
395        }
396    }
397
398    fn add_watch(&mut self, path: PathBuf, is_recursive: bool, mut watch_self: bool) -> Result<()> {
399        // If the watch is not recursive, or if we determine (by stat'ing the path to get its
400        // metadata) that the watched path is not a directory, add a single path watch.
401        if !is_recursive || !metadata(&path).map_err(Error::io_watch)?.is_dir() {
402            return self.add_single_watch(path, false, true);
403        }
404
405        for entry in WalkDir::new(path)
406            .follow_links(self.follow_links)
407            .into_iter()
408            .filter_map(filter_dir)
409        {
410            self.add_single_watch(entry.into_path(), is_recursive, watch_self)?;
411            watch_self = false;
412        }
413
414        Ok(())
415    }
416
417    fn add_single_watch(
418        &mut self,
419        path: PathBuf,
420        is_recursive: bool,
421        watch_self: bool,
422    ) -> Result<()> {
423        let mut watchmask = WatchMask::ATTRIB
424            | WatchMask::CREATE
425            | WatchMask::OPEN
426            | WatchMask::DELETE
427            | WatchMask::CLOSE_WRITE
428            | WatchMask::MODIFY
429            | WatchMask::MOVED_FROM
430            | WatchMask::MOVED_TO;
431
432        if watch_self {
433            watchmask.insert(WatchMask::DELETE_SELF);
434            watchmask.insert(WatchMask::MOVE_SELF);
435        }
436
437        if let Some(&(_, old_watchmask, _, _)) = self.watches.get(&path) {
438            watchmask.insert(old_watchmask);
439            watchmask.insert(WatchMask::MASK_ADD);
440        }
441
442        if let Some(ref mut inotify) = self.inotify {
443            log::trace!("adding inotify watch: {}", path.display());
444
445            match inotify.watches().add(&path, watchmask) {
446                Err(e) => {
447                    Err(if e.raw_os_error() == Some(libc::ENOSPC) {
448                        // do not report inotify limits as "no more space" on linux #266
449                        Error::new(ErrorKind::MaxFilesWatch)
450                    } else if e.kind() == std::io::ErrorKind::NotFound {
451                        Error::new(ErrorKind::PathNotFound)
452                    } else {
453                        Error::io(e)
454                    }
455                    .add_path(path))
456                }
457                Ok(w) => {
458                    watchmask.remove(WatchMask::MASK_ADD);
459                    let is_dir = metadata(&path).map_err(Error::io)?.is_dir();
460                    self.watches
461                        .insert(path.clone(), (w.clone(), watchmask, is_recursive, is_dir));
462                    self.paths.insert(w, path);
463                    Ok(())
464                }
465            }
466        } else {
467            Ok(())
468        }
469    }
470
471    fn remove_watch(&mut self, path: PathBuf, remove_recursive: bool) -> Result<()> {
472        match self.watches.remove(&path) {
473            None => return Err(Error::watch_not_found().add_path(path)),
474            Some((w, _, is_recursive, _)) => {
475                if let Some(ref mut inotify) = self.inotify {
476                    let mut inotify_watches = inotify.watches();
477                    log::trace!("removing inotify watch: {}", path.display());
478
479                    inotify_watches
480                        .remove(w.clone())
481                        .map_err(|e| Error::io(e).add_path(path.clone()))?;
482                    self.paths.remove(&w);
483
484                    if is_recursive || remove_recursive {
485                        let mut remove_list = Vec::new();
486                        for (w, p) in &self.paths {
487                            if p.starts_with(&path) {
488                                inotify_watches
489                                    .remove(w.clone())
490                                    .map_err(|e| Error::io(e).add_path(p.into()))?;
491                                self.watches.remove(p);
492                                remove_list.push(w.clone());
493                            }
494                        }
495                        for w in remove_list {
496                            self.paths.remove(&w);
497                        }
498                    }
499                }
500            }
501        }
502        Ok(())
503    }
504
505    fn remove_all_watches(&mut self) -> Result<()> {
506        if let Some(ref mut inotify) = self.inotify {
507            let mut inotify_watches = inotify.watches();
508            for (w, p) in &self.paths {
509                inotify_watches
510                    .remove(w.clone())
511                    .map_err(|e| Error::io(e).add_path(p.into()))?;
512            }
513            self.watches.clear();
514            self.paths.clear();
515        }
516        Ok(())
517    }
518}
519
520/// return `DirEntry` when it is a directory
521fn filter_dir(e: walkdir::Result<walkdir::DirEntry>) -> Option<walkdir::DirEntry> {
522    if let Ok(e) = e
523        && let Ok(metadata) = e.metadata()
524        && metadata.is_dir()
525    {
526        return Some(e);
527    }
528    None
529}
530
531impl INotifyWatcher {
532    fn from_event_handler(
533        event_handler: Box<dyn EventHandler>,
534        follow_links: bool,
535    ) -> Result<Self> {
536        let inotify = Inotify::init()?;
537        let event_loop = EventLoop::new(inotify, event_handler, follow_links)?;
538        let channel = event_loop.event_loop_tx.clone();
539        let waker = event_loop.event_loop_waker.clone();
540        event_loop.run();
541        Ok(INotifyWatcher { channel, waker })
542    }
543
544    fn watch_inner(&mut self, path: &Path, recursive_mode: RecursiveMode) -> Result<()> {
545        let pb = if path.is_absolute() {
546            path.to_owned()
547        } else {
548            let p = env::current_dir().map_err(Error::io)?;
549            p.join(path)
550        };
551        let (tx, rx) = unbounded();
552        let msg = EventLoopMsg::AddWatch(pb, recursive_mode, tx);
553
554        // we expect the event loop to live and reply => unwraps must not panic
555        self.channel.send(msg).unwrap();
556        self.waker.wake().unwrap();
557        rx.recv().unwrap()
558    }
559
560    fn unwatch_inner(&mut self, path: &Path) -> Result<()> {
561        let pb = if path.is_absolute() {
562            path.to_owned()
563        } else {
564            let p = env::current_dir().map_err(Error::io)?;
565            p.join(path)
566        };
567        let (tx, rx) = unbounded();
568        let msg = EventLoopMsg::RemoveWatch(pb, tx);
569
570        // we expect the event loop to live and reply => unwraps must not panic
571        self.channel.send(msg).unwrap();
572        self.waker.wake().unwrap();
573        rx.recv().unwrap()
574    }
575}
576
577impl Watcher for INotifyWatcher {
578    /// Create a new watcher.
579    fn new<F: EventHandler>(event_handler: F, config: Config) -> Result<Self> {
580        Self::from_event_handler(Box::new(event_handler), config.follow_symlinks())
581    }
582
583    fn watch(&mut self, path: &Path, recursive_mode: RecursiveMode) -> Result<()> {
584        self.watch_inner(path, recursive_mode)
585    }
586
587    fn unwatch(&mut self, path: &Path) -> Result<()> {
588        self.unwatch_inner(path)
589    }
590
591    fn configure(&mut self, config: Config) -> Result<bool> {
592        let (tx, rx) = bounded(1);
593        self.channel.send(EventLoopMsg::Configure(config, tx))?;
594        self.waker.wake()?;
595        rx.recv()?
596    }
597
598    fn kind() -> crate::WatcherKind {
599        crate::WatcherKind::Inotify
600    }
601}
602
603impl Drop for INotifyWatcher {
604    fn drop(&mut self) {
605        // we expect the event loop to live => unwrap must not panic
606        self.channel.send(EventLoopMsg::Shutdown).unwrap();
607        self.waker.wake().unwrap();
608    }
609}
610
611#[cfg(test)]
612mod tests {
613    use std::{
614        path::{Path, PathBuf},
615        sync::{Arc, atomic::AtomicBool, mpsc},
616        thread::{self, available_parallelism},
617        time::Duration,
618    };
619
620    use super::{Config, Error, ErrorKind, Event, INotifyWatcher, RecursiveMode, Result, Watcher};
621
622    use crate::test::*;
623
624    fn watcher() -> (TestWatcher<INotifyWatcher>, Receiver) {
625        channel()
626    }
627
628    #[test]
629    fn inotify_watcher_is_send_and_sync() {
630        fn check<T: Send + Sync>() {}
631        check::<INotifyWatcher>();
632    }
633
634    #[test]
635    fn native_error_type_on_missing_path() {
636        let mut watcher = INotifyWatcher::new(|_| {}, Config::default()).unwrap();
637
638        let result = watcher.watch(
639            &PathBuf::from("/some/non/existant/path"),
640            RecursiveMode::NonRecursive,
641        );
642
643        assert!(matches!(
644            result,
645            Err(Error {
646                paths: _,
647                kind: ErrorKind::PathNotFound
648            })
649        ))
650    }
651
652    /// Runs manually.
653    ///
654    /// * Save actual value of the limit: `MAX_USER_WATCHES=$(sysctl -n fs.inotify.max_user_watches)`
655    /// * Run the test.
656    /// * Set the limit to 0: `sudo sysctl fs.inotify.max_user_watches=0` while test is running
657    /// * Wait for the test to complete
658    /// * Restore the limit `sudo sysctl fs.inotify.max_user_watches=$MAX_USER_WATCHES`
659    #[test]
660    #[ignore = "requires changing sysctl fs.inotify.max_user_watches while test is running"]
661    fn recursive_watch_calls_handler_if_creating_a_file_raises_max_files_watch() {
662        use std::time::Duration;
663
664        let tmpdir = tempfile::tempdir().unwrap();
665        let (tx, rx) = std::sync::mpsc::channel();
666        let (proc_changed_tx, proc_changed_rx) = std::sync::mpsc::channel();
667        let proc_path = Path::new("/proc/sys/fs/inotify/max_user_watches");
668        let mut watcher = INotifyWatcher::new(
669            move |result: Result<Event>| match result {
670                Ok(event) => {
671                    if event.paths.first().is_some_and(|path| path == proc_path) {
672                        proc_changed_tx.send(()).unwrap();
673                    }
674                }
675                Err(e) => tx.send(e).unwrap(),
676            },
677            Config::default(),
678        )
679        .unwrap();
680
681        watcher
682            .watch(tmpdir.path(), RecursiveMode::Recursive)
683            .unwrap();
684        watcher
685            .watch(proc_path, RecursiveMode::NonRecursive)
686            .unwrap();
687
688        // give the time to set the limit
689        proc_changed_rx
690            .recv_timeout(Duration::from_secs(30))
691            .unwrap();
692
693        let child_dir = tmpdir.path().join("child");
694        std::fs::create_dir(child_dir).unwrap();
695
696        let result = rx.recv_timeout(Duration::from_millis(500));
697
698        assert!(
699            matches!(
700                &result,
701                Ok(Error {
702                    kind: ErrorKind::MaxFilesWatch,
703                    paths: _,
704                })
705            ),
706            "expected {:?}, found: {:#?}",
707            ErrorKind::MaxFilesWatch,
708            result
709        );
710    }
711
712    /// https://github.com/notify-rs/notify/issues/678
713    #[test]
714    fn race_condition_on_unwatch_and_pending_events_with_deleted_descriptor() {
715        let tmpdir = tempfile::tempdir().expect("tmpdir");
716        let (tx, rx) = mpsc::channel();
717        let mut inotify = INotifyWatcher::new(
718            move |e: Result<Event>| {
719                let e = match e {
720                    Ok(e) if e.paths.is_empty() => e,
721                    Ok(_) | Err(_) => return,
722                };
723                let _ = tx.send(e);
724            },
725            Config::default(),
726        )
727        .expect("inotify creation");
728
729        let dir_path = tmpdir.path();
730        let file_path = dir_path.join("foo");
731        std::fs::File::create(&file_path).unwrap();
732
733        let stop = Arc::new(AtomicBool::new(false));
734
735        let handles: Vec<_> = (0..available_parallelism().unwrap().get().max(4))
736            .map(|_| {
737                let file_path = file_path.clone();
738                let stop = stop.clone();
739                thread::spawn(move || {
740                    while !stop.load(std::sync::atomic::Ordering::Relaxed) {
741                        let _ = std::fs::File::open(&file_path).unwrap();
742                    }
743                })
744            })
745            .collect();
746
747        let non_recursive = RecursiveMode::NonRecursive;
748        for _ in 0..(handles.len() * 4) {
749            inotify.watch(dir_path, non_recursive).unwrap();
750            inotify.unwatch(dir_path).unwrap();
751        }
752
753        stop.store(true, std::sync::atomic::Ordering::Relaxed);
754        handles
755            .into_iter()
756            .for_each(|handle| handle.join().ok().unwrap_or_default());
757
758        drop(inotify);
759
760        let events: Vec<_> = rx.into_iter().map(|e| format!("{e:?}")).collect();
761
762        const LOG_LEN: usize = 10;
763        let events_len = events.len();
764        assert!(
765            events.is_empty(),
766            "expected no events without path, but got {events_len}. first 10: {:#?}",
767            &events[..LOG_LEN.min(events_len)]
768        );
769    }
770
771    #[test]
772    fn create_file() {
773        let tmpdir = testdir();
774        let (mut watcher, mut rx) = watcher();
775        watcher.watch_recursively(&tmpdir);
776
777        let path = tmpdir.path().join("entry");
778        std::fs::File::create_new(&path).expect("create");
779
780        rx.wait_ordered_exact([
781            expected(&path).create_file(),
782            expected(&path).access_open_any(),
783            expected(&path).access_close_write(),
784        ]);
785    }
786
787    #[test]
788    fn write_file() {
789        let tmpdir = testdir();
790        let (mut watcher, mut rx) = watcher();
791
792        let path = tmpdir.path().join("entry");
793        std::fs::File::create_new(&path).expect("create");
794
795        watcher.watch_recursively(&tmpdir);
796        std::fs::write(&path, b"123").expect("write");
797
798        rx.wait_ordered_exact([
799            expected(&path).access_open_any(),
800            expected(&path).modify_data_any().multiple(),
801            expected(&path).access_close_write(),
802        ])
803        .ensure_no_tail();
804    }
805
806    #[test]
807    fn chmod_file() {
808        let tmpdir = testdir();
809        let (mut watcher, mut rx) = watcher();
810
811        let path = tmpdir.path().join("entry");
812        let file = std::fs::File::create_new(&path).expect("create");
813        let mut permissions = file.metadata().expect("metadata").permissions();
814        permissions.set_readonly(true);
815
816        watcher.watch_recursively(&tmpdir);
817        file.set_permissions(permissions).expect("set_permissions");
818
819        rx.wait_ordered_exact([expected(&path).modify_meta_any()]);
820    }
821
822    #[test]
823    fn rename_file() {
824        let tmpdir = testdir();
825        let (mut watcher, mut rx) = watcher();
826
827        let path = tmpdir.path().join("entry");
828        std::fs::File::create_new(&path).expect("create");
829
830        watcher.watch_recursively(&tmpdir);
831        let new_path = tmpdir.path().join("renamed");
832
833        std::fs::rename(&path, &new_path).expect("rename");
834
835        rx.wait_ordered_exact([
836            expected(&path).rename_from(),
837            expected(&new_path).rename_to(),
838            expected([path, new_path]).rename_both(),
839        ])
840        .ensure_trackers_len(1)
841        .ensure_no_tail();
842    }
843
844    #[test]
845    fn delete_file() {
846        let tmpdir = testdir();
847        let (mut watcher, mut rx) = watcher();
848        let file = tmpdir.path().join("file");
849        std::fs::write(&file, "").expect("write");
850
851        watcher.watch_nonrecursively(&tmpdir);
852
853        std::fs::remove_file(&file).expect("remove");
854
855        rx.wait_ordered_exact([expected(&file).remove_file()]);
856    }
857
858    #[test]
859    fn delete_self_file() {
860        let tmpdir = testdir();
861        let (mut watcher, mut rx) = watcher();
862        let file = tmpdir.path().join("file");
863        std::fs::write(&file, "").expect("write");
864
865        watcher.watch_nonrecursively(&file);
866
867        std::fs::remove_file(&file).expect("remove");
868
869        rx.wait_ordered_exact([
870            expected(&file).modify_meta_any(),
871            expected(&file).remove_file(),
872        ]);
873    }
874
875    #[test]
876    fn create_write_overwrite() {
877        let tmpdir = testdir();
878        let (mut watcher, mut rx) = watcher();
879        let overwritten_file = tmpdir.path().join("overwritten_file");
880        let overwriting_file = tmpdir.path().join("overwriting_file");
881        std::fs::write(&overwritten_file, "123").expect("write1");
882
883        watcher.watch_nonrecursively(&tmpdir);
884
885        std::fs::File::create(&overwriting_file).expect("create");
886        std::fs::write(&overwriting_file, "321").expect("write2");
887        std::fs::rename(&overwriting_file, &overwritten_file).expect("rename");
888
889        rx.wait_ordered_exact([
890            expected(&overwriting_file).create_file(),
891            expected(&overwriting_file).access_open_any(),
892            expected(&overwriting_file).access_close_write(),
893            expected(&overwriting_file).access_open_any(),
894            expected(&overwriting_file).modify_data_any().multiple(),
895            expected(&overwriting_file).access_close_write(),
896            expected(&overwriting_file).rename_from(),
897            expected(&overwritten_file).rename_to(),
898            expected([overwriting_file, overwritten_file]).rename_both(),
899        ])
900        .ensure_no_tail()
901        .ensure_trackers_len(1);
902    }
903
904    #[test]
905    fn create_dir() {
906        let tmpdir = testdir();
907        let (mut watcher, mut rx) = watcher();
908        watcher.watch_recursively(&tmpdir);
909
910        let path = tmpdir.path().join("entry");
911        std::fs::create_dir(&path).expect("create");
912
913        rx.wait_ordered_exact([expected(&path).create_folder()]);
914    }
915
916    #[test]
917    fn chmod_dir() {
918        let tmpdir = testdir();
919        let (mut watcher, mut rx) = watcher();
920
921        let path = tmpdir.path().join("entry");
922        std::fs::create_dir(&path).expect("create_dir");
923        let mut permissions = std::fs::metadata(&path).expect("metadata").permissions();
924        permissions.set_readonly(true);
925
926        watcher.watch_recursively(&tmpdir);
927        std::fs::set_permissions(&path, permissions).expect("set_permissions");
928
929        rx.wait_ordered_exact([
930            expected(&path).access_open_any().optional(),
931            expected(&path).modify_meta_any(),
932            expected(&path).modify_meta_any(),
933        ])
934        .ensure_no_tail();
935    }
936
937    #[test]
938    fn rename_dir() {
939        let tmpdir = testdir();
940        let (mut watcher, mut rx) = watcher();
941
942        let path = tmpdir.path().join("entry");
943        let new_path = tmpdir.path().join("new_path");
944        std::fs::create_dir(&path).expect("create_dir");
945
946        watcher.watch_recursively(&tmpdir);
947
948        std::fs::rename(&path, &new_path).expect("rename");
949
950        rx.wait_ordered_exact([
951            expected(&path).access_open_any().optional(),
952            expected(&path).rename_from(),
953            expected(&new_path).rename_to(),
954            expected([path, new_path]).rename_both(),
955        ])
956        .ensure_trackers_len(1);
957    }
958
959    #[test]
960    fn delete_dir() {
961        let tmpdir = testdir();
962        let (mut watcher, mut rx) = watcher();
963
964        let path = tmpdir.path().join("entry");
965        std::fs::create_dir(&path).expect("create_dir");
966
967        watcher.watch_recursively(&tmpdir);
968        std::fs::remove_dir(&path).expect("remove");
969
970        rx.wait_ordered_exact([
971            expected(&path).access_open_any().optional(),
972            expected(&path).remove_folder(),
973        ])
974        .ensure_no_tail();
975    }
976
977    #[test]
978    fn rename_dir_twice() {
979        let tmpdir = testdir();
980        let (mut watcher, mut rx) = watcher();
981
982        let path = tmpdir.path().join("entry");
983        let new_path = tmpdir.path().join("new_path");
984        let new_path2 = tmpdir.path().join("new_path2");
985        std::fs::create_dir(&path).expect("create_dir");
986
987        watcher.watch_recursively(&tmpdir);
988        std::fs::rename(&path, &new_path).expect("rename");
989        std::fs::rename(&new_path, &new_path2).expect("rename2");
990
991        rx.wait_ordered_exact([
992            expected(&path).access_open_any().optional(),
993            expected(&path).rename_from(),
994            expected(&new_path).rename_to(),
995            expected([&path, &new_path]).rename_both(),
996            expected(&new_path).access_open_any().optional(),
997            expected(&new_path).rename_from(),
998            expected(&new_path2).rename_to(),
999            expected([&new_path, &new_path2]).rename_both(),
1000        ])
1001        .ensure_trackers_len(2);
1002    }
1003
1004    #[test]
1005    fn move_out_of_watched_dir() {
1006        let tmpdir = testdir();
1007        let subdir = tmpdir.path().join("subdir");
1008        let (mut watcher, mut rx) = watcher();
1009
1010        let path = subdir.join("entry");
1011        std::fs::create_dir_all(&subdir).expect("create_dir_all");
1012        std::fs::File::create_new(&path).expect("create");
1013
1014        watcher.watch_recursively(&subdir);
1015        let new_path = tmpdir.path().join("entry");
1016
1017        std::fs::rename(&path, &new_path).expect("rename");
1018
1019        let event = rx.recv();
1020        let tracker = event.attrs.tracker();
1021        assert_eq!(event, expected(path).rename_from());
1022        assert!(tracker.is_some(), "tracker is none: [event:#?]");
1023        rx.ensure_empty();
1024    }
1025
1026    #[test]
1027    fn create_write_write_rename_write_remove() {
1028        let tmpdir = testdir();
1029        let (mut watcher, mut rx) = watcher();
1030
1031        let file1 = tmpdir.path().join("entry");
1032        let file2 = tmpdir.path().join("entry2");
1033        std::fs::File::create_new(&file2).expect("create file2");
1034        let new_path = tmpdir.path().join("renamed");
1035
1036        watcher.watch_recursively(&tmpdir);
1037        std::fs::write(&file1, "123").expect("write 1");
1038        std::fs::write(&file2, "321").expect("write 2");
1039        std::fs::rename(&file1, &new_path).expect("rename");
1040        std::fs::write(&new_path, b"1").expect("write 3");
1041        std::fs::remove_file(&new_path).expect("remove");
1042
1043        rx.wait_ordered_exact([
1044            expected(&file1).create_file(),
1045            expected(&file1).access_open_any(),
1046            expected(&file1).modify_data_any().multiple(),
1047            expected(&file1).access_close_write(),
1048            expected(&file2).access_open_any(),
1049            expected(&file2).modify_data_any().multiple(),
1050            expected(&file2).access_close_write(),
1051            expected(&file1).access_open_any().optional(),
1052            expected(&file1).rename_from(),
1053            expected(&new_path).rename_to(),
1054            expected([&file1, &new_path]).rename_both(),
1055            expected(&new_path).access_open_any(),
1056            expected(&new_path).modify_data_any().multiple(),
1057            expected(&new_path).access_close_write(),
1058            expected(&new_path).remove_file(),
1059        ]);
1060    }
1061
1062    #[test]
1063    fn rename_twice() {
1064        let tmpdir = testdir();
1065        let (mut watcher, mut rx) = watcher();
1066
1067        let path = tmpdir.path().join("entry");
1068        std::fs::File::create_new(&path).expect("create");
1069
1070        watcher.watch_recursively(&tmpdir);
1071        let new_path1 = tmpdir.path().join("renamed1");
1072        let new_path2 = tmpdir.path().join("renamed2");
1073
1074        std::fs::rename(&path, &new_path1).expect("rename1");
1075        std::fs::rename(&new_path1, &new_path2).expect("rename2");
1076
1077        rx.wait_ordered_exact([
1078            expected(&path).access_open_any().optional(),
1079            expected(&path).rename_from(),
1080            expected(&new_path1).rename_to(),
1081            expected([&path, &new_path1]).rename_both(),
1082            expected(&new_path1).access_open_any().optional(),
1083            expected(&new_path1).rename_from(),
1084            expected(&new_path2).rename_to(),
1085            expected([&new_path1, &new_path2]).rename_both(),
1086        ])
1087        .ensure_no_tail()
1088        .ensure_trackers_len(2);
1089    }
1090
1091    #[test]
1092    fn set_file_mtime() {
1093        let tmpdir = testdir();
1094        let (mut watcher, mut rx) = watcher();
1095
1096        let path = tmpdir.path().join("entry");
1097        let file = std::fs::File::create_new(&path).expect("create");
1098
1099        watcher.watch_recursively(&tmpdir);
1100
1101        file.set_modified(
1102            std::time::SystemTime::now()
1103                .checked_sub(Duration::from_secs(60 * 60))
1104                .expect("time"),
1105        )
1106        .expect("set_time");
1107
1108        assert_eq!(rx.recv(), expected(&path).modify_data_any());
1109        rx.ensure_empty();
1110    }
1111
1112    #[test]
1113    fn write_file_non_recursive_watch() {
1114        let tmpdir = testdir();
1115        let (mut watcher, mut rx) = watcher();
1116
1117        let path = tmpdir.path().join("entry");
1118        std::fs::File::create_new(&path).expect("create");
1119
1120        watcher.watch_nonrecursively(&path);
1121
1122        std::fs::write(&path, b"123").expect("write");
1123
1124        rx.wait_ordered_exact([
1125            expected(&path).access_open_any(),
1126            expected(&path).modify_data_any().multiple(),
1127            expected(&path).access_close_write(),
1128        ])
1129        .ensure_no_tail();
1130    }
1131
1132    #[test]
1133    fn watch_recursively_then_unwatch_child_stops_events_from_child() {
1134        let tmpdir = testdir();
1135        let (mut watcher, mut rx) = watcher();
1136
1137        let subdir = tmpdir.path().join("subdir");
1138        let file = subdir.join("file");
1139        std::fs::create_dir(&subdir).expect("create");
1140
1141        watcher.watch_recursively(&tmpdir);
1142
1143        std::fs::File::create(&file).expect("create");
1144
1145        rx.wait_ordered_exact([
1146            expected(&subdir).access_open_any().optional(),
1147            expected(&file).create_file(),
1148            expected(&file).access_open_any(),
1149            expected(&file).access_close_write(),
1150        ])
1151        .ensure_no_tail();
1152
1153        watcher.watcher.unwatch(&subdir).expect("unwatch");
1154
1155        std::fs::write(&file, b"123").expect("write");
1156
1157        std::fs::remove_dir_all(&subdir).expect("remove_dir_all");
1158
1159        rx.wait_ordered_exact([
1160            expected(&subdir).access_open_any().optional(),
1161            expected(&subdir).remove_folder(),
1162        ])
1163        .ensure_no_tail();
1164    }
1165
1166    #[test]
1167    fn write_to_a_hardlink_pointed_to_the_watched_file_triggers_an_event() {
1168        let tmpdir = testdir();
1169        let (mut watcher, mut rx) = watcher();
1170
1171        let subdir = tmpdir.path().join("subdir");
1172        let file = subdir.join("file");
1173        let hardlink = tmpdir.path().join("hardlink");
1174
1175        std::fs::create_dir(&subdir).expect("create");
1176        std::fs::write(&file, "").expect("file");
1177        std::fs::hard_link(&file, &hardlink).expect("hardlink");
1178
1179        watcher.watch_nonrecursively(&file);
1180
1181        std::fs::write(&hardlink, "123123").expect("write to the hard link");
1182
1183        rx.wait_ordered_exact([
1184            expected(&file).access_open_any(),
1185            expected(&file).modify_data_any().multiple(),
1186            expected(&file).access_close_write(),
1187        ]);
1188    }
1189
1190    #[test]
1191    fn write_to_a_hardlink_pointed_to_the_file_in_the_watched_dir_doesnt_trigger_an_event() {
1192        let tmpdir = testdir();
1193        let (mut watcher, mut rx) = watcher();
1194
1195        let subdir = tmpdir.path().join("subdir");
1196        let file = subdir.join("file");
1197        let hardlink = tmpdir.path().join("hardlink");
1198
1199        std::fs::create_dir(&subdir).expect("create");
1200        std::fs::write(&file, "").expect("file");
1201        std::fs::hard_link(&file, &hardlink).expect("hardlink");
1202
1203        watcher.watch_nonrecursively(&subdir);
1204
1205        std::fs::write(&hardlink, "123123").expect("write to the hard link");
1206
1207        let events = rx.iter().collect::<Vec<_>>();
1208        assert!(events.is_empty(), "unexpected events: {events:#?}");
1209    }
1210
1211    #[test]
1212    #[ignore = "see https://github.com/notify-rs/notify/issues/727"]
1213    fn recursive_creation() {
1214        let tmpdir = testdir();
1215        let nested1 = tmpdir.path().join("1");
1216        let nested2 = tmpdir.path().join("1/2");
1217        let nested3 = tmpdir.path().join("1/2/3");
1218        let nested4 = tmpdir.path().join("1/2/3/4");
1219        let nested5 = tmpdir.path().join("1/2/3/4/5");
1220        let nested6 = tmpdir.path().join("1/2/3/4/5/6");
1221        let nested7 = tmpdir.path().join("1/2/3/4/5/6/7");
1222        let nested8 = tmpdir.path().join("1/2/3/4/5/6/7/8");
1223        let nested9 = tmpdir.path().join("1/2/3/4/5/6/7/8/9");
1224
1225        let (mut watcher, mut rx) = watcher();
1226
1227        watcher.watch_recursively(&tmpdir);
1228
1229        std::fs::create_dir_all(&nested9).expect("create_dir_all");
1230        rx.wait_ordered([
1231            expected(&nested1).create_folder(),
1232            expected(&nested2).create_folder(),
1233            expected(&nested3).create_folder(),
1234            expected(&nested4).create_folder(),
1235            expected(&nested5).create_folder(),
1236            expected(&nested6).create_folder(),
1237            expected(&nested7).create_folder(),
1238            expected(&nested8).create_folder(),
1239            expected(&nested9).create_folder(),
1240        ]);
1241    }
1242}