coreshift_core/
inotify.rs1use crate::CoreError;
16use crate::error::syscall_ret;
17use crate::reactor::Fd;
18
19#[derive(Clone, Debug, PartialEq, Eq)]
23pub struct InotifyEvent {
24 pub wd: i32,
26 pub mask: u32,
28 pub name: Option<Vec<u8>>,
33}
34
35pub const MODIFY_MASK: u32 = libc::IN_MODIFY;
37pub const PACKAGE_FILE_MASK: u32 = libc::IN_MODIFY | libc::IN_DELETE_SELF | libc::IN_MOVE_SELF;
39pub const PARENT_WATCH_MASK: u32 = libc::IN_CREATE
41 | libc::IN_MOVED_TO
42 | libc::IN_CLOSE_WRITE
43 | libc::IN_MODIFY
44 | libc::IN_DELETE_SELF
45 | libc::IN_MOVE_SELF;
46pub const QUEUE_OVERFLOW_MASK: u32 = libc::IN_Q_OVERFLOW;
48pub const IGNORED_MASK: u32 = libc::IN_IGNORED;
50pub const UNMOUNT_MASK: u32 = libc::IN_UNMOUNT;
52pub const DELETE_SELF_MASK: u32 = libc::IN_DELETE_SELF;
54pub const MOVE_SELF_MASK: u32 = libc::IN_MOVE_SELF;
56
57pub fn init() -> Result<Fd, CoreError> {
59 let fd = unsafe { libc::inotify_init1(libc::IN_CLOEXEC | libc::IN_NONBLOCK) };
60 syscall_ret(fd, "inotify_init1")?;
61 Fd::new(fd, "inotify_init1")
62}
63
64pub fn add_watch(fd: &Fd, path: &str, mask: u32) -> Result<i32, CoreError> {
74 let path = std::ffi::CString::new(path)
75 .map_err(|_| CoreError::sys(libc::EINVAL, "inotify path contains nul"))?;
76 let wd = unsafe { libc::inotify_add_watch(fd.raw(), path.as_ptr(), mask) };
77 if wd < 0 {
78 return Err(CoreError::sys(
79 std::io::Error::last_os_error().raw_os_error().unwrap_or(0),
80 "inotify_add_watch",
81 ));
82 }
83 Ok(wd)
84}
85
86pub fn remove_watch(fd: &Fd, wd: i32) -> Result<(), CoreError> {
88 #[cfg(target_os = "android")]
89 let raw_wd = u32::try_from(wd).map_err(|_| CoreError::sys(libc::EINVAL, "inotify_rm_watch"))?;
90
91 #[cfg(not(target_os = "android"))]
92 let raw_wd = wd;
93
94 let ret = unsafe { libc::inotify_rm_watch(fd.raw(), raw_wd) };
95 syscall_ret(ret, "inotify_rm_watch")
96}
97
98pub fn read_events(fd: &Fd) -> Result<Vec<InotifyEvent>, CoreError> {
106 let mut all_events = Vec::new();
107 let mut buf = vec![0u8; 4096];
108
109 loop {
110 match fd.read_slice(&mut buf) {
111 Ok(Some(0)) => break,
112 Ok(Some(n)) => {
113 all_events.extend(decode_events(&buf[..n])?);
114 }
115 Ok(None) => break, Err(e) => return Err(e),
117 }
118 }
119
120 Ok(all_events)
121}
122
123pub fn decode_events(buf: &[u8]) -> Result<Vec<InotifyEvent>, CoreError> {
128 let mut events = Vec::new();
129 let mut offset = 0;
130 let base = std::mem::size_of::<libc::inotify_event>();
131
132 while offset + base <= buf.len() {
133 let event: libc::inotify_event = unsafe {
136 std::ptr::read_unaligned(buf.as_ptr().add(offset) as *const libc::inotify_event)
137 };
138
139 let Some(size) = base.checked_add(event.len as usize) else {
140 return Err(CoreError::sys(libc::EINVAL, "decode_inotify_event"));
141 };
142 if offset + size > buf.len() {
143 return Err(CoreError::sys(libc::EINVAL, "decode_inotify_event"));
144 }
145
146 let name = if event.len > 0 {
147 let name_buf = &buf[offset + base..offset + base + event.len as usize];
148 name_buf.split(|&b| b == 0).next().map(|s| s.to_vec())
150 } else {
151 None
152 };
153
154 events.push(InotifyEvent {
155 wd: event.wd,
156 mask: event.mask,
157 name,
158 });
159 offset += size;
160 }
161
162 if offset != buf.len() {
163 return Err(CoreError::sys(libc::EINVAL, "decode_inotify_event"));
164 }
165
166 Ok(events)
167}