starnix_core/vfs/
inotify_hook.rs1use crate::vfs::{FileHandleKey, FsStr, WdNumber, WeakFileHandle};
6use starnix_sync::{InotifyWatchersLock, LockDepMutex};
7use starnix_uapi::error;
8use starnix_uapi::errors::Errno;
9use starnix_uapi::file_mode::FileMode;
10use starnix_uapi::inotify_mask::InotifyMask;
11use std::collections::BTreeMap;
12
13#[derive(Clone)]
14pub struct InotifyWatcher {
15 pub watch_id: WdNumber,
16 pub mask: InotifyMask,
17}
18
19#[derive(Default)]
20pub struct InotifyWatchers {
21 pub watchers: LockDepMutex<BTreeMap<FileHandleKey, InotifyWatcher>, InotifyWatchersLock>,
22}
23
24impl InotifyWatchers {
25 pub fn add(&self, mask: InotifyMask, watch_id: WdNumber, inotify: FileHandleKey) {
26 let mut watchers = self.watchers.lock();
27 watchers.insert(inotify, InotifyWatcher { watch_id, mask });
28 }
29
30 pub fn maybe_update(
37 &self,
38 mask: InotifyMask,
39 inotify: &FileHandleKey,
40 ) -> Result<Option<WdNumber>, Errno> {
41 let combine_existing = mask.contains(InotifyMask::MASK_ADD);
42 let create_new = mask.contains(InotifyMask::MASK_CREATE);
43 if combine_existing && create_new {
44 return error!(EINVAL);
45 }
46
47 let mut watchers = self.watchers.lock();
48 if let Some(watcher) = watchers.get_mut(inotify) {
49 if create_new {
50 return error!(EEXIST);
51 }
52
53 if combine_existing {
54 watcher.mask.insert(mask);
55 } else {
56 watcher.mask = mask;
57 }
58 Ok(Some(watcher.watch_id))
59 } else {
60 Ok(None)
61 }
62 }
63
64 pub fn get(&self, inotify: &FileHandleKey) -> Option<InotifyWatcher> {
65 self.watchers.lock().get(inotify).cloned()
66 }
67
68 pub fn remove(&self, inotify: &FileHandleKey) {
69 let mut watchers = self.watchers.lock();
70 watchers.remove(inotify);
71 }
72
73 pub fn remove_by_ref(&self, inotify: &WeakFileHandle) {
74 let mut watchers = self.watchers.lock();
75 watchers.retain(|weak_key, _| weak_key.0.strong_count() > 0 && weak_key != inotify)
76 }
77}
78
79pub trait NotifyHook: Send + Sync + 'static {
80 fn notify(
81 &self,
82 watchers: &InotifyWatchers,
83 event_mask: InotifyMask,
84 cookie: u32,
85 name: &FsStr,
86 mode: FileMode,
87 is_dead: bool,
88 );
89
90 fn get_next_cookie(&self) -> u32;
91}