1 //! inotify support for working with inotifies
2 
3 use crate::backend::c;
4 use crate::backend::conv::{borrowed_fd, c_str, ret, ret_c_int, ret_owned_fd};
5 use crate::fd::{BorrowedFd, OwnedFd};
6 use crate::io;
7 use bitflags::bitflags;
8 
9 bitflags! {
10     /// `IN_*` for use with [`inotify_init`].
11     ///
12     /// [`inotify_init`]: crate::fs::inotify::inotify_init
13     #[repr(transparent)]
14     #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
15     pub struct CreateFlags: u32 {
16         /// `IN_CLOEXEC`
17         const CLOEXEC = bitcast!(c::IN_CLOEXEC);
18         /// `IN_NONBLOCK`
19         const NONBLOCK = bitcast!(c::IN_NONBLOCK);
20 
21         /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags>
22         const _ = !0;
23     }
24 }
25 
26 bitflags! {
27     /// `IN*` for use with [`inotify_add_watch`].
28     ///
29     /// [`inotify_add_watch`]: crate::fs::inotify::inotify_add_watch
30     #[repr(transparent)]
31     #[derive(Default, Copy, Clone, Eq, PartialEq, Hash, Debug)]
32     pub struct WatchFlags: u32 {
33         /// `IN_ACCESS`
34         const ACCESS = c::IN_ACCESS;
35         /// `IN_ATTRIB`
36         const ATTRIB = c::IN_ATTRIB;
37         /// `IN_CLOSE_NOWRITE`
38         const CLOSE_NOWRITE = c::IN_CLOSE_NOWRITE;
39         /// `IN_CLOSE_WRITE`
40         const CLOSE_WRITE = c::IN_CLOSE_WRITE;
41         /// `IN_CREATE`
42         const CREATE = c::IN_CREATE;
43         /// `IN_DELETE`
44         const DELETE = c::IN_DELETE;
45         /// `IN_DELETE_SELF`
46         const DELETE_SELF = c::IN_DELETE_SELF;
47         /// `IN_MODIFY`
48         const MODIFY = c::IN_MODIFY;
49         /// `IN_MOVE_SELF`
50         const MOVE_SELF = c::IN_MOVE_SELF;
51         /// `IN_MOVED_FROM`
52         const MOVED_FROM = c::IN_MOVED_FROM;
53         /// `IN_MOVED_TO`
54         const MOVED_TO = c::IN_MOVED_TO;
55         /// `IN_OPEN`
56         const OPEN = c::IN_OPEN;
57 
58         /// `IN_CLOSE`
59         const CLOSE = c::IN_CLOSE;
60         /// `IN_MOVE`
61         const MOVE = c::IN_MOVE;
62         /// `IN_ALL_EVENTS`
63         const ALL_EVENTS = c::IN_ALL_EVENTS;
64 
65         /// `IN_DONT_FOLLOW`
66         const DONT_FOLLOW = c::IN_DONT_FOLLOW;
67         /// `IN_EXCL_UNLINK`
68         const EXCL_UNLINK = 1;
69         /// `IN_MASK_ADD`
70         const MASK_ADD = 1;
71         /// `IN_MASK_CREATE`
72         const MASK_CREATE = 1;
73         /// `IN_ONESHOT`
74         const ONESHOT = c::IN_ONESHOT;
75         /// `IN_ONLYDIR`
76         const ONLYDIR = c::IN_ONLYDIR;
77 
78         /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags>
79         const _ = !0;
80     }
81 }
82 
83 /// `inotify_init1(flags)`—Creates a new inotify object.
84 ///
85 /// Use the [`CreateFlags::CLOEXEC`] flag to prevent the resulting file
86 /// descriptor from being implicitly passed across `exec` boundaries.
87 #[doc(alias = "inotify_init1")]
inotify_init(flags: CreateFlags) -> io::Result<OwnedFd>88 pub fn inotify_init(flags: CreateFlags) -> io::Result<OwnedFd> {
89     // SAFETY: `inotify_init1` has no safety preconditions.
90     unsafe { ret_owned_fd(c::inotify_init1(bitflags_bits!(flags))) }
91 }
92 
93 /// `inotify_add_watch(self, path, flags)`—Adds a watch to inotify.
94 ///
95 /// This registers or updates a watch for the filesystem path `path` and
96 /// returns a watch descriptor corresponding to this watch.
97 ///
98 /// Note: Due to the existence of hardlinks, providing two different paths to
99 /// this method may result in it returning the same watch descriptor. An
100 /// application should keep track of this externally to avoid logic errors.
inotify_add_watch<P: crate::path::Arg>( inot: BorrowedFd<'_>, path: P, flags: WatchFlags, ) -> io::Result<i32>101 pub fn inotify_add_watch<P: crate::path::Arg>(
102     inot: BorrowedFd<'_>,
103     path: P,
104     flags: WatchFlags,
105 ) -> io::Result<i32> {
106     path.into_with_c_str(|path| {
107         // SAFETY: The fd and path we are passing is guaranteed valid by the
108         // type system.
109         unsafe {
110             ret_c_int(c::inotify_add_watch(
111                 borrowed_fd(inot),
112                 c_str(path),
113                 flags.bits(),
114             ))
115         }
116     })
117 }
118 
119 /// `inotify_rm_watch(self, wd)`—Removes a watch from this inotify.
120 ///
121 /// The watch descriptor provided should have previously been returned by
122 /// [`inotify_add_watch`] and not previously have been removed.
123 #[doc(alias = "inotify_rm_watch")]
inotify_remove_watch(inot: BorrowedFd<'_>, wd: i32) -> io::Result<()>124 pub fn inotify_remove_watch(inot: BorrowedFd<'_>, wd: i32) -> io::Result<()> {
125     // Android's `inotify_rm_watch` takes `u32` despite that
126     // `inotify_add_watch` expects a `i32`.
127     #[cfg(target_os = "android")]
128     let wd = wd as u32;
129     // SAFETY: The fd is valid and closing an arbitrary wd is valid.
130     unsafe { ret(c::inotify_rm_watch(borrowed_fd(inot), wd)) }
131 }
132