blob: 81ff0052958d7aefdd0ae04d275137be30335967 [file] [log] [blame] [edit]
use std::{
hash::{
Hash,
Hasher,
},
cmp::Ordering,
os::raw::c_int,
sync::Weak,
};
use inotify_sys as ffi;
use crate::fd_guard::FdGuard;
bitflags! {
/// Describes a file system watch
///
/// Passed to [`Inotify::add_watch`], to describe what file system events
/// to watch for, and how to do that.
///
/// # Examples
///
/// `WatchMask` constants can be passed to [`Inotify::add_watch`] as is. For
/// example, here's how to create a watch that triggers an event when a file
/// is accessed:
///
/// ``` rust
/// # use inotify::{
/// # Inotify,
/// # WatchMask,
/// # };
/// #
/// # let mut inotify = Inotify::init().unwrap();
/// #
/// # // Create a temporary file, so `add_watch` won't return an error.
/// # use std::fs::File;
/// # File::create("/tmp/inotify-rs-test-file")
/// # .expect("Failed to create test file");
/// #
/// inotify.add_watch("/tmp/inotify-rs-test-file", WatchMask::ACCESS)
/// .expect("Error adding watch");
/// ```
///
/// You can also combine multiple `WatchMask` constants. Here we add a watch
/// this is triggered both when files are created or deleted in a directory:
///
/// ``` rust
/// # use inotify::{
/// # Inotify,
/// # WatchMask,
/// # };
/// #
/// # let mut inotify = Inotify::init().unwrap();
/// inotify.add_watch("/tmp/", WatchMask::CREATE | WatchMask::DELETE)
/// .expect("Error adding watch");
/// ```
///
/// [`Inotify::add_watch`]: struct.Inotify.html#method.add_watch
pub struct WatchMask: u32 {
/// File was accessed
///
/// When watching a directory, this event is only triggered for objects
/// inside the directory, not the directory itself.
///
/// See [`inotify_sys::IN_ACCESS`].
///
/// [`inotify_sys::IN_ACCESS`]: ../inotify_sys/constant.IN_ACCESS.html
const ACCESS = ffi::IN_ACCESS;
/// Metadata (permissions, timestamps, ...) changed
///
/// When watching a directory, this event can be triggered for the
/// directory itself, as well as objects inside the directory.
///
/// See [`inotify_sys::IN_ATTRIB`].
///
/// [`inotify_sys::IN_ATTRIB`]: ../inotify_sys/constant.IN_ATTRIB.html
const ATTRIB = ffi::IN_ATTRIB;
/// File opened for writing was closed
///
/// When watching a directory, this event is only triggered for objects
/// inside the directory, not the directory itself.
///
/// See [`inotify_sys::IN_CLOSE_WRITE`].
///
/// [`inotify_sys::IN_CLOSE_WRITE`]: ../inotify_sys/constant.IN_CLOSE_WRITE.html
const CLOSE_WRITE = ffi::IN_CLOSE_WRITE;
/// File or directory not opened for writing was closed
///
/// When watching a directory, this event can be triggered for the
/// directory itself, as well as objects inside the directory.
///
/// See [`inotify_sys::IN_CLOSE_NOWRITE`].
///
/// [`inotify_sys::IN_CLOSE_NOWRITE`]: ../inotify_sys/constant.IN_CLOSE_NOWRITE.html
const CLOSE_NOWRITE = ffi::IN_CLOSE_NOWRITE;
/// File/directory created in watched directory
///
/// When watching a directory, this event is only triggered for objects
/// inside the directory, not the directory itself.
///
/// See [`inotify_sys::IN_CREATE`].
///
/// [`inotify_sys::IN_CREATE`]: ../inotify_sys/constant.IN_CREATE.html
const CREATE = ffi::IN_CREATE;
/// File/directory deleted from watched directory
///
/// When watching a directory, this event is only triggered for objects
/// inside the directory, not the directory itself.
///
/// See [`inotify_sys::IN_DELETE`].
///
/// [`inotify_sys::IN_DELETE`]: ../inotify_sys/constant.IN_DELETE.html
const DELETE = ffi::IN_DELETE;
/// Watched file/directory was deleted
///
/// See [`inotify_sys::IN_DELETE_SELF`].
///
/// [`inotify_sys::IN_DELETE_SELF`]: ../inotify_sys/constant.IN_DELETE_SELF.html
const DELETE_SELF = ffi::IN_DELETE_SELF;
/// File was modified
///
/// When watching a directory, this event is only triggered for objects
/// inside the directory, not the directory itself.
///
/// See [`inotify_sys::IN_MODIFY`].
///
/// [`inotify_sys::IN_MODIFY`]: ../inotify_sys/constant.IN_MODIFY.html
const MODIFY = ffi::IN_MODIFY;
/// Watched file/directory was moved
///
/// See [`inotify_sys::IN_MOVE_SELF`].
///
/// [`inotify_sys::IN_MOVE_SELF`]: ../inotify_sys/constant.IN_MOVE_SELF.html
const MOVE_SELF = ffi::IN_MOVE_SELF;
/// File was renamed/moved; watched directory contained old name
///
/// When watching a directory, this event is only triggered for objects
/// inside the directory, not the directory itself.
///
/// See [`inotify_sys::IN_MOVED_FROM`].
///
/// [`inotify_sys::IN_MOVED_FROM`]: ../inotify_sys/constant.IN_MOVED_FROM.html
const MOVED_FROM = ffi::IN_MOVED_FROM;
/// File was renamed/moved; watched directory contains new name
///
/// When watching a directory, this event is only triggered for objects
/// inside the directory, not the directory itself.
///
/// See [`inotify_sys::IN_MOVED_TO`].
///
/// [`inotify_sys::IN_MOVED_TO`]: ../inotify_sys/constant.IN_MOVED_TO.html
const MOVED_TO = ffi::IN_MOVED_TO;
/// File or directory was opened
///
/// When watching a directory, this event can be triggered for the
/// directory itself, as well as objects inside the directory.
///
/// See [`inotify_sys::IN_OPEN`].
///
/// [`inotify_sys::IN_OPEN`]: ../inotify_sys/constant.IN_OPEN.html
const OPEN = ffi::IN_OPEN;
/// Watch for all events
///
/// This constant is simply a convenient combination of the following
/// other constants:
///
/// - [`ACCESS`]
/// - [`ATTRIB`]
/// - [`CLOSE_WRITE`]
/// - [`CLOSE_NOWRITE`]
/// - [`CREATE`]
/// - [`DELETE`]
/// - [`DELETE_SELF`]
/// - [`MODIFY`]
/// - [`MOVE_SELF`]
/// - [`MOVED_FROM`]
/// - [`MOVED_TO`]
/// - [`OPEN`]
///
/// See [`inotify_sys::IN_ALL_EVENTS`].
///
/// [`ACCESS`]: #associatedconstant.ACCESS
/// [`ATTRIB`]: #associatedconstant.ATTRIB
/// [`CLOSE_WRITE`]: #associatedconstant.CLOSE_WRITE
/// [`CLOSE_NOWRITE`]: #associatedconstant.CLOSE_NOWRITE
/// [`CREATE`]: #associatedconstant.CREATE
/// [`DELETE`]: #associatedconstant.DELETE
/// [`DELETE_SELF`]: #associatedconstant.DELETE_SELF
/// [`MODIFY`]: #associatedconstant.MODIFY
/// [`MOVE_SELF`]: #associatedconstant.MOVE_SELF
/// [`MOVED_FROM`]: #associatedconstant.MOVED_FROM
/// [`MOVED_TO`]: #associatedconstant.MOVED_TO
/// [`OPEN`]: #associatedconstant.OPEN
/// [`inotify_sys::IN_ALL_EVENTS`]: ../inotify_sys/constant.IN_ALL_EVENTS.html
const ALL_EVENTS = ffi::IN_ALL_EVENTS;
/// Watch for all move events
///
/// This constant is simply a convenient combination of the following
/// other constants:
///
/// - [`MOVED_FROM`]
/// - [`MOVED_TO`]
///
/// See [`inotify_sys::IN_MOVE`].
///
/// [`MOVED_FROM`]: #associatedconstant.MOVED_FROM
/// [`MOVED_TO`]: #associatedconstant.MOVED_TO
/// [`inotify_sys::IN_MOVE`]: ../inotify_sys/constant.IN_MOVE.html
const MOVE = ffi::IN_MOVE;
/// Watch for all close events
///
/// This constant is simply a convenient combination of the following
/// other constants:
///
/// - [`CLOSE_WRITE`]
/// - [`CLOSE_NOWRITE`]
///
/// See [`inotify_sys::IN_CLOSE`].
///
/// [`CLOSE_WRITE`]: #associatedconstant.CLOSE_WRITE
/// [`CLOSE_NOWRITE`]: #associatedconstant.CLOSE_NOWRITE
/// [`inotify_sys::IN_CLOSE`]: ../inotify_sys/constant.IN_CLOSE.html
const CLOSE = ffi::IN_CLOSE;
/// Don't dereference the path if it is a symbolic link
///
/// See [`inotify_sys::IN_DONT_FOLLOW`].
///
/// [`inotify_sys::IN_DONT_FOLLOW`]: ../inotify_sys/constant.IN_DONT_FOLLOW.html
const DONT_FOLLOW = ffi::IN_DONT_FOLLOW;
/// Filter events for directory entries that have been unlinked
///
/// See [`inotify_sys::IN_EXCL_UNLINK`].
///
/// [`inotify_sys::IN_EXCL_UNLINK`]: ../inotify_sys/constant.IN_EXCL_UNLINK.html
const EXCL_UNLINK = ffi::IN_EXCL_UNLINK;
/// If a watch for the inode exists, amend it instead of replacing it
///
/// See [`inotify_sys::IN_MASK_ADD`].
///
/// [`inotify_sys::IN_MASK_ADD`]: ../inotify_sys/constant.IN_MASK_ADD.html
const MASK_ADD = ffi::IN_MASK_ADD;
/// Only receive one event, then remove the watch
///
/// See [`inotify_sys::IN_ONESHOT`].
///
/// [`inotify_sys::IN_ONESHOT`]: ../inotify_sys/constant.IN_ONESHOT.html
const ONESHOT = ffi::IN_ONESHOT;
/// Only watch path, if it is a directory
///
/// See [`inotify_sys::IN_ONLYDIR`].
///
/// [`inotify_sys::IN_ONLYDIR`]: ../inotify_sys/constant.IN_ONLYDIR.html
const ONLYDIR = ffi::IN_ONLYDIR;
}
}
/// Represents a watch on an inode
///
/// Can be obtained from [`Inotify::add_watch`] or from an [`Event`]. A watch
/// descriptor can be used to get inotify to stop watching an inode by passing
/// it to [`Inotify::rm_watch`].
///
/// [`Inotify::add_watch`]: struct.Inotify.html#method.add_watch
/// [`Inotify::rm_watch`]: struct.Inotify.html#method.rm_watch
/// [`Event`]: struct.Event.html
#[derive(Clone, Debug)]
pub struct WatchDescriptor{
pub(crate) id: c_int,
pub(crate) fd: Weak<FdGuard>,
}
impl Eq for WatchDescriptor {}
impl PartialEq for WatchDescriptor {
fn eq(&self, other: &Self) -> bool {
let self_fd = self.fd.upgrade();
let other_fd = other.fd.upgrade();
self.id == other.id && self_fd.is_some() && self_fd == other_fd
}
}
impl Ord for WatchDescriptor {
fn cmp(&self, other: &Self) -> Ordering {
self.id.cmp(&other.id)
}
}
impl PartialOrd for WatchDescriptor {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Hash for WatchDescriptor {
fn hash<H: Hasher>(&self, state: &mut H) {
// This function only takes `self.id` into account, as `self.fd` is a
// weak pointer that might no longer be available. Since neither
// panicking nor changing the hash depending on whether it's available
// is acceptable, we just don't look at it at all.
// I don't think that this influences storage in a `HashMap` or
// `HashSet` negatively, as storing `WatchDescriptor`s from different
// `Inotify` instances seems like something of an anti-pattern anyway.
self.id.hash(state);
}
}