1 use std::{ 2 io, 3 os::unix::io::{ 4 AsFd, 5 AsRawFd, 6 BorrowedFd, 7 FromRawFd, 8 IntoRawFd, 9 OwnedFd, 10 RawFd, 11 }, 12 path::Path, 13 sync::{ 14 atomic::AtomicBool, 15 Arc, 16 } 17 }; 18 19 use inotify_sys as ffi; 20 use libc::{ 21 F_GETFL, 22 F_SETFL, 23 O_NONBLOCK, 24 fcntl, 25 }; 26 27 use crate::events::Events; 28 use crate::fd_guard::FdGuard; 29 use crate::util::read_into_buffer; 30 use crate::watches::{ 31 WatchDescriptor, 32 WatchMask, 33 Watches, 34 }; 35 36 37 #[cfg(feature = "stream")] 38 use crate::stream::EventStream; 39 40 41 /// Idiomatic Rust wrapper around Linux's inotify API 42 /// 43 /// `Inotify` is a wrapper around an inotify instance. It generally tries to 44 /// adhere to the underlying inotify API closely, while making access to it 45 /// safe and convenient. 46 /// 47 /// Please refer to the [top-level documentation] for further details and a 48 /// usage example. 49 /// 50 /// [top-level documentation]: crate 51 #[derive(Debug)] 52 pub struct Inotify { 53 fd: Arc<FdGuard>, 54 } 55 56 impl Inotify { 57 /// Creates an [`Inotify`] instance 58 /// 59 /// Initializes an inotify instance by calling [`inotify_init1`]. 60 /// 61 /// This method passes both flags accepted by [`inotify_init1`], not giving 62 /// the user any choice in the matter, as not passing the flags would be 63 /// inappropriate in the context of this wrapper: 64 /// 65 /// - [`IN_CLOEXEC`] prevents leaking file descriptors to other processes. 66 /// - [`IN_NONBLOCK`] controls the blocking behavior of the inotify API, 67 /// which is entirely managed by this wrapper. 68 /// 69 /// # Errors 70 /// 71 /// Directly returns the error from the call to [`inotify_init1`], without 72 /// adding any error conditions of its own. 73 /// 74 /// # Examples 75 /// 76 /// ``` 77 /// use inotify::Inotify; 78 /// 79 /// let inotify = Inotify::init() 80 /// .expect("Failed to initialize an inotify instance"); 81 /// ``` 82 /// 83 /// [`inotify_init1`]: inotify_sys::inotify_init1 84 /// [`IN_CLOEXEC`]: inotify_sys::IN_CLOEXEC 85 /// [`IN_NONBLOCK`]: inotify_sys::IN_NONBLOCK init() -> io::Result<Inotify>86 pub fn init() -> io::Result<Inotify> { 87 let fd = unsafe { 88 // Initialize inotify and pass both `IN_CLOEXEC` and `IN_NONBLOCK`. 89 // 90 // `IN_NONBLOCK` is needed, because `Inotify` manages blocking 91 // behavior for the API consumer, and the way we do that is to make 92 // everything non-blocking by default and later override that as 93 // required. 94 // 95 // Passing `IN_CLOEXEC` prevents leaking file descriptors to 96 // processes executed by this process and seems to be a best 97 // practice. I don't grasp this issue completely and failed to find 98 // any authoritative sources on the topic. There's some discussion in 99 // the open(2) and fcntl(2) man pages, but I didn't find that 100 // helpful in understanding the issue of leaked file descriptors. 101 // For what it's worth, there's a Rust issue about this: 102 // https://github.com/rust-lang/rust/issues/12148 103 ffi::inotify_init1(ffi::IN_CLOEXEC | ffi::IN_NONBLOCK) 104 }; 105 106 if fd == -1 { 107 return Err(io::Error::last_os_error()); 108 } 109 110 Ok(Inotify { 111 fd: Arc::new(FdGuard { 112 fd, 113 close_on_drop: AtomicBool::new(true), 114 }), 115 }) 116 } 117 118 /// Gets an interface that allows adding and removing watches. 119 /// See [`Watches::add`] and [`Watches::remove`]. watches(&self) -> Watches120 pub fn watches(&self) -> Watches { 121 Watches::new(self.fd.clone()) 122 } 123 124 /// Deprecated: use `Inotify.watches().add()` instead 125 #[deprecated = "use `Inotify.watches().add()` instead"] add_watch<P>(&mut self, path: P, mask: WatchMask) -> io::Result<WatchDescriptor> where P: AsRef<Path>126 pub fn add_watch<P>(&mut self, path: P, mask: WatchMask) 127 -> io::Result<WatchDescriptor> 128 where P: AsRef<Path> 129 { 130 self.watches().add(path, mask) 131 } 132 133 /// Deprecated: use `Inotify.watches().remove()` instead 134 #[deprecated = "use `Inotify.watches().remove()` instead"] rm_watch(&mut self, wd: WatchDescriptor) -> io::Result<()>135 pub fn rm_watch(&mut self, wd: WatchDescriptor) -> io::Result<()> { 136 self.watches().remove(wd) 137 } 138 139 /// Waits until events are available, then returns them 140 /// 141 /// Blocks the current thread until at least one event is available. If this 142 /// is not desirable, please consider [`Inotify::read_events`]. 143 /// 144 /// This method calls [`Inotify::read_events`] internally and behaves 145 /// essentially the same, apart from the blocking behavior. Please refer to 146 /// the documentation of [`Inotify::read_events`] for more information. read_events_blocking<'a>(&mut self, buffer: &'a mut [u8]) -> io::Result<Events<'a>>147 pub fn read_events_blocking<'a>(&mut self, buffer: &'a mut [u8]) 148 -> io::Result<Events<'a>> 149 { 150 unsafe { 151 let res = fcntl(**self.fd, F_GETFL); 152 if res == -1 { 153 return Err(io::Error::last_os_error()); 154 } 155 if fcntl(**self.fd, F_SETFL, res & !O_NONBLOCK) == -1 { 156 return Err(io::Error::last_os_error()); 157 } 158 }; 159 let result = self.read_events(buffer); 160 unsafe { 161 let res = fcntl(**self.fd, F_GETFL); 162 if res == -1 { 163 return Err(io::Error::last_os_error()); 164 } 165 if fcntl(**self.fd, F_SETFL, res | O_NONBLOCK) == -1 { 166 return Err(io::Error::last_os_error()); 167 } 168 }; 169 170 result 171 } 172 173 /// Returns one buffer's worth of available events 174 /// 175 /// Reads as many events as possible into `buffer`, and returns an iterator 176 /// over them. If no events are available, an iterator is still returned. If 177 /// you need a method that will block until at least one event is available, 178 /// please consider [`read_events_blocking`]. 179 /// 180 /// Please note that inotify will merge identical successive unread events 181 /// into a single event. This means this method can not be used to count the 182 /// number of file system events. 183 /// 184 /// The `buffer` argument, as the name indicates, is used as a buffer for 185 /// the inotify events. Its contents may be overwritten. 186 /// 187 /// # Errors 188 /// 189 /// This function directly returns all errors from the call to [`read`]. 190 /// In addition, [`ErrorKind::UnexpectedEof`] is returned, if the call to 191 /// [`read`] returns `0`, signaling end-of-file. 192 /// 193 /// If `buffer` is too small, this will result in an error with 194 /// [`ErrorKind::InvalidInput`]. On very old Linux kernels, 195 /// [`ErrorKind::UnexpectedEof`] will be returned instead. 196 /// 197 /// # Examples 198 /// 199 /// ```no_run 200 /// use inotify::Inotify; 201 /// use std::io::ErrorKind; 202 /// 203 /// let mut inotify = Inotify::init() 204 /// .expect("Failed to initialize an inotify instance"); 205 /// 206 /// let mut buffer = [0; 1024]; 207 /// let events = loop { 208 /// match inotify.read_events(&mut buffer) { 209 /// Ok(events) => break events, 210 /// Err(error) if error.kind() == ErrorKind::WouldBlock => continue, 211 /// _ => panic!("Error while reading events"), 212 /// } 213 /// }; 214 /// 215 /// for event in events { 216 /// // Handle event 217 /// } 218 /// ``` 219 /// 220 /// [`read_events_blocking`]: Self::read_events_blocking 221 /// [`read`]: libc::read 222 /// [`ErrorKind::UnexpectedEof`]: std::io::ErrorKind::UnexpectedEof 223 /// [`ErrorKind::InvalidInput`]: std::io::ErrorKind::InvalidInput read_events<'a>(&mut self, buffer: &'a mut [u8]) -> io::Result<Events<'a>>224 pub fn read_events<'a>(&mut self, buffer: &'a mut [u8]) 225 -> io::Result<Events<'a>> 226 { 227 let num_bytes = read_into_buffer(**self.fd, buffer); 228 229 let num_bytes = match num_bytes { 230 0 => { 231 return Err( 232 io::Error::new( 233 io::ErrorKind::UnexpectedEof, 234 "`read` return `0`, signaling end-of-file" 235 ) 236 ); 237 } 238 -1 => { 239 let error = io::Error::last_os_error(); 240 return Err(error); 241 }, 242 _ if num_bytes < 0 => { 243 panic!("{} {} {} {} {} {}", 244 "Unexpected return value from `read`. Received a negative", 245 "value that was not `-1`. According to the `read` man page", 246 "this shouldn't happen, as either `-1` is returned on", 247 "error, `0` on end-of-file, or a positive value for the", 248 "number of bytes read. Returned value:", 249 num_bytes, 250 ); 251 } 252 _ => { 253 // The value returned by `read` should be `isize`. Let's quickly 254 // verify this with the following assignment, so we can be sure 255 // our cast below is valid. 256 let num_bytes: isize = num_bytes; 257 258 // The type returned by `read` is `isize`, and we've ruled out 259 // all negative values with the match arms above. This means we 260 // can safely cast to `usize`. 261 debug_assert!(num_bytes > 0); 262 num_bytes as usize 263 } 264 }; 265 266 Ok(Events::new(Arc::downgrade(&self.fd), buffer, num_bytes)) 267 } 268 269 /// Deprecated: use `into_event_stream()` instead, which enforces a single `Stream` and predictable reads. 270 /// Using this method to create multiple `EventStream` instances from one `Inotify` is unsupported, 271 /// as they will contend over one event source and each produce unpredictable stream contents. 272 #[deprecated = "use `into_event_stream()` instead, which enforces a single Stream and predictable reads"] 273 #[cfg(feature = "stream")] event_stream<T>(&mut self, buffer: T) -> io::Result<EventStream<T>> where T: AsMut<[u8]> + AsRef<[u8]>,274 pub fn event_stream<T>(&mut self, buffer: T) 275 -> io::Result<EventStream<T>> 276 where 277 T: AsMut<[u8]> + AsRef<[u8]>, 278 { 279 EventStream::new(self.fd.clone(), buffer) 280 } 281 282 /// Create a stream which collects events. Consumes the `Inotify` instance. 283 /// 284 /// Returns a `Stream` over all events that are available. This stream is an 285 /// infinite source of events. 286 /// 287 /// An internal buffer which can hold the largest possible event is used. 288 #[cfg(feature = "stream")] into_event_stream<T>(self, buffer: T) -> io::Result<EventStream<T>> where T: AsMut<[u8]> + AsRef<[u8]>,289 pub fn into_event_stream<T>(self, buffer: T) 290 -> io::Result<EventStream<T>> 291 where 292 T: AsMut<[u8]> + AsRef<[u8]>, 293 { 294 EventStream::new(self.fd, buffer) 295 } 296 297 /// Creates an `Inotify` instance using the file descriptor which was originally 298 /// initialized in `Inotify::init`. This is intended to be used to transform an 299 /// `EventStream` back into an `Inotify`. Do not attempt to clone `Inotify` with this. 300 #[cfg(feature = "stream")] from_file_descriptor(fd: Arc<FdGuard>) -> Self301 pub(crate) fn from_file_descriptor(fd: Arc<FdGuard>) -> Self 302 { 303 Inotify { 304 fd, 305 } 306 } 307 308 /// Closes the inotify instance 309 /// 310 /// Closes the file descriptor referring to the inotify instance. The user 311 /// usually doesn't have to call this function, as the underlying inotify 312 /// instance is closed automatically, when [`Inotify`] is dropped. 313 /// 314 /// # Errors 315 /// 316 /// Directly returns the error from the call to [`close`], without adding any 317 /// error conditions of its own. 318 /// 319 /// # Examples 320 /// 321 /// ``` 322 /// use inotify::Inotify; 323 /// 324 /// let mut inotify = Inotify::init() 325 /// .expect("Failed to initialize an inotify instance"); 326 /// 327 /// inotify.close() 328 /// .expect("Failed to close inotify instance"); 329 /// ``` 330 /// 331 /// [`close`]: libc::close close(self) -> io::Result<()>332 pub fn close(self) -> io::Result<()> { 333 // `self` will be dropped when this method returns. If this is the only 334 // owner of `fd`, the `Arc` will also be dropped. The `Drop` 335 // implementation for `FdGuard` will attempt to close the file descriptor 336 // again, unless this flag here is cleared. 337 self.fd.should_not_close(); 338 339 match unsafe { ffi::close(**self.fd) } { 340 0 => Ok(()), 341 _ => Err(io::Error::last_os_error()), 342 } 343 } 344 } 345 346 impl AsRawFd for Inotify { 347 #[inline] as_raw_fd(&self) -> RawFd348 fn as_raw_fd(&self) -> RawFd { 349 self.fd.as_raw_fd() 350 } 351 } 352 353 impl FromRawFd for Inotify { from_raw_fd(fd: RawFd) -> Self354 unsafe fn from_raw_fd(fd: RawFd) -> Self { 355 Inotify { 356 fd: Arc::new(FdGuard::from_raw_fd(fd)) 357 } 358 } 359 } 360 361 impl IntoRawFd for Inotify { 362 #[inline] into_raw_fd(self) -> RawFd363 fn into_raw_fd(self) -> RawFd { 364 self.fd.should_not_close(); 365 self.fd.fd 366 } 367 } 368 369 impl AsFd for Inotify { 370 #[inline] as_fd(&self) -> BorrowedFd<'_>371 fn as_fd(&self) -> BorrowedFd<'_> { 372 self.fd.as_fd() 373 } 374 } 375 376 impl From<Inotify> for OwnedFd { from(fd: Inotify) -> OwnedFd377 fn from(fd: Inotify) -> OwnedFd { 378 unsafe { OwnedFd::from_raw_fd(fd.into_raw_fd()) } 379 } 380 } 381 382 impl From<OwnedFd> for Inotify { from(fd: OwnedFd) -> Inotify383 fn from(fd: OwnedFd) -> Inotify { 384 unsafe { Inotify::from_raw_fd(fd.into_raw_fd()) } 385 } 386 } 387