inotify/util.rs
1use std::{
2 io,
3 mem,
4 os::unix::io::RawFd,
5 path::Path,
6};
7
8use inotify_sys as ffi;
9use libc::{
10 c_void,
11 size_t,
12};
13
14const INOTIFY_EVENT_SIZE: usize = mem::size_of::<ffi::inotify_event>() + 257;
15
16pub fn read_into_buffer(fd: RawFd, buffer: &mut [u8]) -> isize {
17 unsafe {
18 ffi::read(
19 fd,
20 buffer.as_mut_ptr() as *mut c_void,
21 buffer.len() as size_t
22 )
23 }
24}
25
26/// Get the inotify event buffer size
27///
28/// The maximum size of an inotify event and thus the buffer size to hold it
29/// can be calculated using this formula:
30/// `sizeof(struct inotify_event) + NAME_MAX + 1`
31///
32/// See: <https://man7.org/linux/man-pages/man7/inotify.7.html>
33///
34/// The NAME_MAX size formula is:
35/// `ABSOLUTE_PARENT_PATH_LEN + 1 + 255`
36///
37/// - `ABSOLUTE_PARENT_PATH_LEN` will be calculated at runtime.
38/// - Add 1 to account for a `/`, either in between the parent path and a filename
39/// or for the root directory.
40/// - Add the maximum number of chars in a filename, 255.
41///
42/// See: <https://github.com/torvalds/linux/blob/master/include/uapi/linux/limits.h>
43///
44/// Unfortunately, we can't just do the same with max path length itself.
45///
46/// See: <https://eklitzke.org/path-max-is-tricky>
47///
48/// This function is really just a fallible wrapper around `get_absolute_path_buffer_size()`.
49///
50/// path: A relative or absolute path for the inotify events.
51pub fn get_buffer_size(path: &Path) -> io::Result<usize> {
52 Ok(get_absolute_path_buffer_size(&path.canonicalize()?))
53}
54
55/// Get the inotify event buffer size for an absolute path
56///
57/// For relative paths, consider using `get_buffer_size()` which provides a fallible wrapper
58/// for this function.
59///
60/// path: An absolute path for the inotify events.
61pub fn get_absolute_path_buffer_size(path: &Path) -> usize {
62 INOTIFY_EVENT_SIZE
63 // Get the length of the absolute parent path, if the path is not the root directory.
64 // Because we canonicalize the path, we do not need to worry about prefixes.
65 + if let Some(parent_path) = path.parent() {
66 parent_path.as_os_str().len()
67 } else {
68 0
69 }
70}