1 | use std::{ |
2 | hash::{ |
3 | Hash, |
4 | Hasher, |
5 | }, |
6 | cmp::Ordering, |
7 | os::raw::c_int, |
8 | sync::Weak, |
9 | }; |
10 | |
11 | use inotify_sys as ffi; |
12 | |
13 | use crate::fd_guard::FdGuard; |
14 | |
15 | |
16 | bitflags! { |
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)] |
288 | pub struct WatchDescriptor{ |
289 | pub(crate) id: c_int, |
290 | pub(crate) fd: Weak<FdGuard>, |
291 | } |
292 | |
293 | impl Eq for WatchDescriptor {} |
294 | |
295 | impl 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 | |
304 | impl Ord for WatchDescriptor { |
305 | fn cmp(&self, other: &Self) -> Ordering { |
306 | self.id.cmp(&other.id) |
307 | } |
308 | } |
309 | |
310 | impl PartialOrd for WatchDescriptor { |
311 | fn partial_cmp(&self, other: &Self) -> Option<Ordering> { |
312 | Some(self.cmp(other)) |
313 | } |
314 | } |
315 | |
316 | impl 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 | |