1use std::{
2 hash::{
3 Hash,
4 Hasher,
5 },
6 cmp::Ordering,
7 os::raw::c_int,
8 sync::Weak,
9};
10
11use inotify_sys as ffi;
12
13use crate::fd_guard::FdGuard;
14
15
16bitflags! {
17 /// Describes a file system watch
18 ///
19 /// Passed to [`Inotify::add_watch`], to describe what file system events
20 /// to watch for, and how to do that.
21 ///
22 /// # Examples
23 ///
24 /// `WatchMask` constants can be passed to [`Inotify::add_watch`] as is. For
25 /// example, here's how to create a watch that triggers an event when a file
26 /// is accessed:
27 ///
28 /// ``` rust
29 /// # use inotify::{
30 /// # Inotify,
31 /// # WatchMask,
32 /// # };
33 /// #
34 /// # let mut inotify = Inotify::init().unwrap();
35 /// #
36 /// # // Create a temporary file, so `add_watch` won't return an error.
37 /// # use std::fs::File;
38 /// # File::create("/tmp/inotify-rs-test-file")
39 /// # .expect("Failed to create test file");
40 /// #
41 /// inotify.add_watch("/tmp/inotify-rs-test-file", WatchMask::ACCESS)
42 /// .expect("Error adding watch");
43 /// ```
44 ///
45 /// You can also combine multiple `WatchMask` constants. Here we add a watch
46 /// this is triggered both when files are created or deleted in a directory:
47 ///
48 /// ``` rust
49 /// # use inotify::{
50 /// # Inotify,
51 /// # WatchMask,
52 /// # };
53 /// #
54 /// # let mut inotify = Inotify::init().unwrap();
55 /// inotify.add_watch("/tmp/", WatchMask::CREATE | WatchMask::DELETE)
56 /// .expect("Error adding watch");
57 /// ```
58 ///
59 /// [`Inotify::add_watch`]: struct.Inotify.html#method.add_watch
60 pub struct WatchMask: u32 {
61 /// File was accessed
62 ///
63 /// When watching a directory, this event is only triggered for objects
64 /// inside the directory, not the directory itself.
65 ///
66 /// See [`inotify_sys::IN_ACCESS`].
67 ///
68 /// [`inotify_sys::IN_ACCESS`]: ../inotify_sys/constant.IN_ACCESS.html
69 const ACCESS = ffi::IN_ACCESS;
70
71 /// Metadata (permissions, timestamps, ...) changed
72 ///
73 /// When watching a directory, this event can be triggered for the
74 /// directory itself, as well as objects inside the directory.
75 ///
76 /// See [`inotify_sys::IN_ATTRIB`].
77 ///
78 /// [`inotify_sys::IN_ATTRIB`]: ../inotify_sys/constant.IN_ATTRIB.html
79 const ATTRIB = ffi::IN_ATTRIB;
80
81 /// File opened for writing was closed
82 ///
83 /// When watching a directory, this event is only triggered for objects
84 /// inside the directory, not the directory itself.
85 ///
86 /// See [`inotify_sys::IN_CLOSE_WRITE`].
87 ///
88 /// [`inotify_sys::IN_CLOSE_WRITE`]: ../inotify_sys/constant.IN_CLOSE_WRITE.html
89 const CLOSE_WRITE = ffi::IN_CLOSE_WRITE;
90
91 /// File or directory not opened for writing was closed
92 ///
93 /// When watching a directory, this event can be triggered for the
94 /// directory itself, as well as objects inside the directory.
95 ///
96 /// See [`inotify_sys::IN_CLOSE_NOWRITE`].
97 ///
98 /// [`inotify_sys::IN_CLOSE_NOWRITE`]: ../inotify_sys/constant.IN_CLOSE_NOWRITE.html
99 const CLOSE_NOWRITE = ffi::IN_CLOSE_NOWRITE;
100
101 /// File/directory created in watched directory
102 ///
103 /// When watching a directory, this event is only triggered for objects
104 /// inside the directory, not the directory itself.
105 ///
106 /// See [`inotify_sys::IN_CREATE`].
107 ///
108 /// [`inotify_sys::IN_CREATE`]: ../inotify_sys/constant.IN_CREATE.html
109 const CREATE = ffi::IN_CREATE;
110
111 /// File/directory deleted from watched directory
112 ///
113 /// When watching a directory, this event is only triggered for objects
114 /// inside the directory, not the directory itself.
115 ///
116 /// See [`inotify_sys::IN_DELETE`].
117 ///
118 /// [`inotify_sys::IN_DELETE`]: ../inotify_sys/constant.IN_DELETE.html
119 const DELETE = ffi::IN_DELETE;
120
121 /// Watched file/directory was deleted
122 ///
123 /// See [`inotify_sys::IN_DELETE_SELF`].
124 ///
125 /// [`inotify_sys::IN_DELETE_SELF`]: ../inotify_sys/constant.IN_DELETE_SELF.html
126 const DELETE_SELF = ffi::IN_DELETE_SELF;
127
128 /// File was modified
129 ///
130 /// When watching a directory, this event is only triggered for objects
131 /// inside the directory, not the directory itself.
132 ///
133 /// See [`inotify_sys::IN_MODIFY`].
134 ///
135 /// [`inotify_sys::IN_MODIFY`]: ../inotify_sys/constant.IN_MODIFY.html
136 const MODIFY = ffi::IN_MODIFY;
137
138 /// Watched file/directory was moved
139 ///
140 /// See [`inotify_sys::IN_MOVE_SELF`].
141 ///
142 /// [`inotify_sys::IN_MOVE_SELF`]: ../inotify_sys/constant.IN_MOVE_SELF.html
143 const MOVE_SELF = ffi::IN_MOVE_SELF;
144
145 /// File was renamed/moved; watched directory contained old name
146 ///
147 /// When watching a directory, this event is only triggered for objects
148 /// inside the directory, not the directory itself.
149 ///
150 /// See [`inotify_sys::IN_MOVED_FROM`].
151 ///
152 /// [`inotify_sys::IN_MOVED_FROM`]: ../inotify_sys/constant.IN_MOVED_FROM.html
153 const MOVED_FROM = ffi::IN_MOVED_FROM;
154
155 /// File was renamed/moved; watched directory contains new name
156 ///
157 /// When watching a directory, this event is only triggered for objects
158 /// inside the directory, not the directory itself.
159 ///
160 /// See [`inotify_sys::IN_MOVED_TO`].
161 ///
162 /// [`inotify_sys::IN_MOVED_TO`]: ../inotify_sys/constant.IN_MOVED_TO.html
163 const MOVED_TO = ffi::IN_MOVED_TO;
164
165 /// File or directory was opened
166 ///
167 /// When watching a directory, this event can be triggered for the
168 /// directory itself, as well as objects inside the directory.
169 ///
170 /// See [`inotify_sys::IN_OPEN`].
171 ///
172 /// [`inotify_sys::IN_OPEN`]: ../inotify_sys/constant.IN_OPEN.html
173 const OPEN = ffi::IN_OPEN;
174
175 /// Watch for all events
176 ///
177 /// This constant is simply a convenient combination of the following
178 /// other constants:
179 ///
180 /// - [`ACCESS`]
181 /// - [`ATTRIB`]
182 /// - [`CLOSE_WRITE`]
183 /// - [`CLOSE_NOWRITE`]
184 /// - [`CREATE`]
185 /// - [`DELETE`]
186 /// - [`DELETE_SELF`]
187 /// - [`MODIFY`]
188 /// - [`MOVE_SELF`]
189 /// - [`MOVED_FROM`]
190 /// - [`MOVED_TO`]
191 /// - [`OPEN`]
192 ///
193 /// See [`inotify_sys::IN_ALL_EVENTS`].
194 ///
195 /// [`ACCESS`]: #associatedconstant.ACCESS
196 /// [`ATTRIB`]: #associatedconstant.ATTRIB
197 /// [`CLOSE_WRITE`]: #associatedconstant.CLOSE_WRITE
198 /// [`CLOSE_NOWRITE`]: #associatedconstant.CLOSE_NOWRITE
199 /// [`CREATE`]: #associatedconstant.CREATE
200 /// [`DELETE`]: #associatedconstant.DELETE
201 /// [`DELETE_SELF`]: #associatedconstant.DELETE_SELF
202 /// [`MODIFY`]: #associatedconstant.MODIFY
203 /// [`MOVE_SELF`]: #associatedconstant.MOVE_SELF
204 /// [`MOVED_FROM`]: #associatedconstant.MOVED_FROM
205 /// [`MOVED_TO`]: #associatedconstant.MOVED_TO
206 /// [`OPEN`]: #associatedconstant.OPEN
207 /// [`inotify_sys::IN_ALL_EVENTS`]: ../inotify_sys/constant.IN_ALL_EVENTS.html
208 const ALL_EVENTS = ffi::IN_ALL_EVENTS;
209
210 /// Watch for all move events
211 ///
212 /// This constant is simply a convenient combination of the following
213 /// other constants:
214 ///
215 /// - [`MOVED_FROM`]
216 /// - [`MOVED_TO`]
217 ///
218 /// See [`inotify_sys::IN_MOVE`].
219 ///
220 /// [`MOVED_FROM`]: #associatedconstant.MOVED_FROM
221 /// [`MOVED_TO`]: #associatedconstant.MOVED_TO
222 /// [`inotify_sys::IN_MOVE`]: ../inotify_sys/constant.IN_MOVE.html
223 const MOVE = ffi::IN_MOVE;
224
225 /// Watch for all close events
226 ///
227 /// This constant is simply a convenient combination of the following
228 /// other constants:
229 ///
230 /// - [`CLOSE_WRITE`]
231 /// - [`CLOSE_NOWRITE`]
232 ///
233 /// See [`inotify_sys::IN_CLOSE`].
234 ///
235 /// [`CLOSE_WRITE`]: #associatedconstant.CLOSE_WRITE
236 /// [`CLOSE_NOWRITE`]: #associatedconstant.CLOSE_NOWRITE
237 /// [`inotify_sys::IN_CLOSE`]: ../inotify_sys/constant.IN_CLOSE.html
238 const CLOSE = ffi::IN_CLOSE;
239
240 /// Don't dereference the path if it is a symbolic link
241 ///
242 /// See [`inotify_sys::IN_DONT_FOLLOW`].
243 ///
244 /// [`inotify_sys::IN_DONT_FOLLOW`]: ../inotify_sys/constant.IN_DONT_FOLLOW.html
245 const DONT_FOLLOW = ffi::IN_DONT_FOLLOW;
246
247 /// Filter events for directory entries that have been unlinked
248 ///
249 /// See [`inotify_sys::IN_EXCL_UNLINK`].
250 ///
251 /// [`inotify_sys::IN_EXCL_UNLINK`]: ../inotify_sys/constant.IN_EXCL_UNLINK.html
252 const EXCL_UNLINK = ffi::IN_EXCL_UNLINK;
253
254 /// If a watch for the inode exists, amend it instead of replacing it
255 ///
256 /// See [`inotify_sys::IN_MASK_ADD`].
257 ///
258 /// [`inotify_sys::IN_MASK_ADD`]: ../inotify_sys/constant.IN_MASK_ADD.html
259 const MASK_ADD = ffi::IN_MASK_ADD;
260
261 /// Only receive one event, then remove the watch
262 ///
263 /// See [`inotify_sys::IN_ONESHOT`].
264 ///
265 /// [`inotify_sys::IN_ONESHOT`]: ../inotify_sys/constant.IN_ONESHOT.html
266 const ONESHOT = ffi::IN_ONESHOT;
267
268 /// Only watch path, if it is a directory
269 ///
270 /// See [`inotify_sys::IN_ONLYDIR`].
271 ///
272 /// [`inotify_sys::IN_ONLYDIR`]: ../inotify_sys/constant.IN_ONLYDIR.html
273 const ONLYDIR = ffi::IN_ONLYDIR;
274 }
275}
276
277
278/// Represents a watch on an inode
279///
280/// Can be obtained from [`Inotify::add_watch`] or from an [`Event`]. A watch
281/// descriptor can be used to get inotify to stop watching an inode by passing
282/// it to [`Inotify::rm_watch`].
283///
284/// [`Inotify::add_watch`]: struct.Inotify.html#method.add_watch
285/// [`Inotify::rm_watch`]: struct.Inotify.html#method.rm_watch
286/// [`Event`]: struct.Event.html
287#[derive(Clone, Debug)]
288pub struct WatchDescriptor{
289 pub(crate) id: c_int,
290 pub(crate) fd: Weak<FdGuard>,
291}
292
293impl Eq for WatchDescriptor {}
294
295impl PartialEq for WatchDescriptor {
296 fn eq(&self, other: &Self) -> bool {
297 let self_fd: Option> = self.fd.upgrade();
298 let other_fd: Option> = other.fd.upgrade();
299
300 self.id == other.id && self_fd.is_some() && self_fd == other_fd
301 }
302}
303
304impl Ord for WatchDescriptor {
305 fn cmp(&self, other: &Self) -> Ordering {
306 self.id.cmp(&other.id)
307 }
308}
309
310impl PartialOrd for WatchDescriptor {
311 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
312 Some(self.cmp(other))
313 }
314}
315
316impl Hash for WatchDescriptor {
317 fn hash<H: Hasher>(&self, state: &mut H) {
318 // This function only takes `self.id` into account, as `self.fd` is a
319 // weak pointer that might no longer be available. Since neither
320 // panicking nor changing the hash depending on whether it's available
321 // is acceptable, we just don't look at it at all.
322 // I don't think that this influences storage in a `HashMap` or
323 // `HashSet` negatively, as storing `WatchDescriptor`s from different
324 // `Inotify` instances seems like something of an anti-pattern anyway.
325 self.id.hash(state);
326 }
327}
328