1 use std::{
2     io,
3     mem,
4     os::unix::io::RawFd,
5     path::Path,
6 };
7 
8 use inotify_sys as ffi;
9 use libc::{
10     c_void,
11     size_t,
12 };
13 
14 const INOTIFY_EVENT_SIZE: usize = mem::size_of::<ffi::inotify_event>() + 257;
15 
read_into_buffer(fd: RawFd, buffer: &mut [u8]) -> isize16 pub 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.
get_buffer_size(path: &Path) -> io::Result<usize>51 pub 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.
get_absolute_path_buffer_size(path: &Path) -> usize61 pub 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 }
71