#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct InotifyFileDescriptor(RawFd);
impl Drop for InotifyFileDescriptor
{
#[inline(always)]
fn drop(&mut self)
{
self.0.close()
}
}
impl AsRawFd for InotifyFileDescriptor
{
#[inline(always)]
fn as_raw_fd(&self) -> RawFd
{
self.0
}
}
impl IntoRawFd for InotifyFileDescriptor
{
#[inline(always)]
fn into_raw_fd(self) -> RawFd
{
self.0
}
}
impl FromRawFd for InotifyFileDescriptor
{
#[inline(always)]
unsafe fn from_raw_fd(fd: RawFd) -> Self
{
Self(fd)
}
}
impl FileDescriptor for InotifyFileDescriptor
{
}
impl InotifyFileDescriptor
{
#[inline(always)]
pub fn new() -> Result<Rc<Self>, CreationError>
{
let result = unsafe { inotify_init1(IN_NONBLOCK | IN_CLOEXEC) };
if likely!(result != -1)
{
Ok(Rc::new(InotifyFileDescriptor(result)))
}
else
{
use self::CreationError::*;
Err
(
match errno().0
{
EMFILE => PerProcessLimitOnNumberOfFileDescriptorsWouldBeExceeded,
ENFILE => SystemWideLimitOnTotalNumberOfFileDescriptorsWouldBeExceeded,
ENOMEM => KernelWouldBeOutOfMemory,
EINVAL => panic!("Invalid arguments"),
_ => unreachable_code(format_args!("")),
}
)
}
}
pub fn add_watch_inefficient(this: &Rc<Self>, path: impl AsRef<Path>, flags: InotifyAddWatchFlags, adjust: bool) -> Result<InotifyWatchDescriptor, InotifyAddError>
{
let path = CString::new(path_bytes_without_trailing_nul(&path)).unwrap();
Self::add_watch(this, &path, flags, adjust)
}
pub fn add_watch(this: &Rc<Self>, path: &CStr, flags: InotifyAddWatchFlags, adjust: bool) -> Result<InotifyWatchDescriptor, InotifyAddError>
{
debug_assert_ne!(flags, InotifyAddWatchFlags::empty(), "flags must not be empty");
let flags = if unlikely!(adjust)
{
flags.add_bitmask()
}
else
{
flags.set_bitmask()
};
let result = unsafe { inotify_add_watch(this.0, path.as_ptr(), flags) };
if likely!(result >= 0)
{
Ok
(
InotifyWatchDescriptor
{
parent: Rc::downgrade(this),
watch_descriptor: result,
}
)
}
else if likely!(result == -1)
{
use self::InotifyAddError::*;
Err
(
match errno().0
{
EACCES => PermissionDenied,
ENOMEM => KernelWouldBeOutOfMemory,
ENOENT => FilePathInvalid,
ENOSPC => MaximumNumberOfWatchesWouldBeExceeded,
EBADF => panic!("`fd` is not a valid file descriptor"),
EFAULT => panic!("`pathname` points outside of the process's accessible address space"),
EINVAL => panic!("The given event `mask` contains no valid events; or `fd` is not an inotify file descriptor"),
_ => unreachable_code(format_args!("")),
}
)
}
else
{
unreachable_code(format_args!(""))
}
}
#[inline(always)]
pub fn read(&self) -> Result<inotify_event, StructReadError>
{
use self::StructReadError::*;
let mut value: inotify_event = inotify_event::unpopulated();
const SizeOfRead: usize = size_of::<inotify_event>();
let result = unsafe { libc::read(self.as_raw_fd(), &mut value as *mut _ as *mut _, SizeOfRead) };
if likely!(result == SizeOfRead as isize)
{
Ok(value)
}
else
{
match result
{
-1 =>
{
let error_number = errno();
match error_number.0
{
EAGAIN => Err(WouldBlock),
ECANCELED => Err(Cancelled),
EINTR => Err(Interrupted),
EIO => Err(Cancelled),
EBADF => panic!("`fd` is not a valid file descriptor or is not open for reading"),
EFAULT => panic!("`buf` is outside your accessible address space"),
EINVAL => panic!("`fd` is attached to an object which is unsuitable for reading OR was created via a call to `timerfd_create()` and the wrong size buffer was given to `read()`"),
EISDIR => panic!("`fd` refers to a directory"),
_ => panic!("Unexpected error `{}`", error_number),
}
}
0 => panic!("End of file but we haven't closed the file descriptor"),
_ => unreachable_code(format_args!("")),
}
}
}
}