//! inotify support for working with inotify objects. //! //! # Examples //! //! ``` //! use rustix::fs::inotify; //! use rustix::io; //! use std::mem::MaybeUninit; //! //! # fn test() -> io::Result<()> { //! // Create an inotify object. In this example, we use `NONBLOCK` so that the //! // reader fails with `WOULDBLOCK` when no events are ready. Otherwise it //! // will block until at least one event is ready. //! let inotify = inotify::init(inotify::CreateFlags::NONBLOCK)?; //! //! // Add a directory to watch. //! inotify::add_watch( //! &inotify, //! "/path/to/some/directory/to/watch", //! inotify::WatchFlags::ALL_EVENTS, //! )?; //! //! // Generate some events in the watched directory… //! //! // Loop over pending events. //! let mut buf = [MaybeUninit::uninit(); 512]; //! let mut iter = inotify::Reader::new(inotify, &mut buf); //! loop { //! let entry = match iter.next() { //! // Stop iterating if there are no more events for now. //! Err(io::Errno::WOULDBLOCK) => break, //! Err(e) => return Err(e), //! Ok(entry) => entry, //! }; //! //! // Use `entry`… //! } //! //! # Ok(()) //! # }
#![allow(unused_qualifications)]
usesuper::inotify; pubusecrate::backend::fs::inotify::{CreateFlags, ReadFlags, WatchFlags}; usecrate::backend::fs::syscalls; usecrate::fd::{AsFd, OwnedFd}; usecrate::ffi::CStr; usecrate::io; usecrate::io::{read, Errno}; use core::mem::{align_of, size_of, MaybeUninit}; use linux_raw_sys::general::inotify_event;
/// `inotify_init1(flags)`—Creates a new inotify object. /// /// Use the [`CreateFlags::CLOEXEC`] flag to prevent the resulting file /// descriptor from being implicitly passed across `exec` boundaries. #[doc(alias = "inotify_init1")] #[inline] pubfn init(flags: inotify::CreateFlags) -> io::Result<OwnedFd> {
syscalls::inotify_init1(flags)
}
/// `inotify_add_watch(self, path, flags)`—Adds a watch to inotify. /// /// This registers or updates a watch for the filesystem path `path` and /// returns a watch descriptor corresponding to this watch. /// /// Note: Due to the existence of hardlinks, providing two different paths to /// this method may result in it returning the same watch descriptor. An /// application should keep track of this externally to avoid logic errors. #[doc(alias = "inotify_add_watch")] #[inline] pubfn add_watch<P: crate::path::Arg, Fd: AsFd>(
inot: Fd,
path: P,
flags: inotify::WatchFlags,
) -> io::Result<i32> {
path.into_with_c_str(|path| syscalls::inotify_add_watch(inot.as_fd(), path, flags))
}
/// `inotify_rm_watch(self, wd)`—Removes a watch from this inotify. /// /// The watch descriptor provided should have previously been returned by /// [`inotify::add_watch`] and not previously have been removed. #[doc(alias = "inotify_rm_watch")] #[inline] pubfn remove_watch<Fd: AsFd>(inot: Fd, wd: i32) -> io::Result<()> {
syscalls::inotify_rm_watch(inot.as_fd(), wd)
}
/// An inotify event iterator implemented with the read syscall. /// /// See the [`RawDir`] API for more details and usage examples as this API is /// based on it. /// /// [`RawDir`]: crate::fs::raw_dir::RawDir pubstruct Reader<'buf, Fd: AsFd> {
fd: Fd,
buf: &'buf mut [MaybeUninit<u8>],
initialized: usize,
offset: usize,
}
impl<'buf, Fd: AsFd> Reader<'buf, Fd> { /// Create a new iterator from the given file descriptor and buffer. pubfn new(fd: Fd, buf: &'buf mut [MaybeUninit<u8>]) -> Self { Self {
fd,
buf: { let offset = buf.as_ptr().align_offset(align_of::<inotify_event>()); if offset < buf.len() {
&mut buf[offset..]
} else {
&mut []
}
},
initialized: 0,
offset: 0,
}
}
}
impl<'a> Event<'a> { /// Returns the watch for which this event occurs. #[inline] pubfn wd(&self) -> i32 { self.wd
}
/// Returns a description of the events. #[inline] #[doc(alias = "mask")] pubfn events(&self) -> ReadFlags { self.events
}
/// Returns the unique cookie associating related events. #[inline] pubfn cookie(&self) -> u32 { self.cookie
}
/// Returns the file name of this event, if any. #[inline] pubfn file_name(&self) -> Option<&CStr> { self.file_name
}
}
impl<'buf, Fd: AsFd> Reader<'buf, Fd> { /// Read the next inotify event. /// /// This is similar to [`Iterator::next`] except that it doesn't return an /// `Option`, because the stream doesn't have an ending. It always returns /// events or errors. /// /// If there are no events in the buffer and none ready to be read: /// - If the file descriptor was opened with /// [`inotify::CreateFlags::NONBLOCK`], this will fail with /// [`Errno::AGAIN`]. /// - Otherwise this will block until at least one event is ready or an /// error occurs. #[allow(unsafe_code)] #[allow(clippy::should_implement_trait)] pubfn next(&mutself) -> io::Result<Event<'_>> { ifself.is_buffer_empty() { match read(self.fd.as_fd(), &mut *self.buf).map(|(init, _)| init.len()) {
Ok(0) => return Err(Errno::INVAL),
Ok(bytes_read) => { self.initialized = bytes_read; self.offset = 0;
}
Err(e) => return Err(e),
}
}
let ptr = self.buf[self.offset..].as_ptr();
// SAFETY: // - This data is initialized by the check above. // - Assumption: the kernel will not give us partial structs. // - Assumption: the kernel uses proper alignment between structs. // - The starting pointer is aligned (performed in `Reader::new`). let event = unsafe { &*ptr.cast::<inotify_event>() };
/// Returns true if the internal buffer is empty and will be refilled when /// calling [`next`]. This is useful to avoid further blocking reads. /// /// [`next`]: Self::next pubfn is_buffer_empty(&self) -> bool { self.offset >= self.initialized
}
}
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.23 Sekunden
(vorverarbeitet am 2026-08-25)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.