| 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 | |
| 16 | pub fn read_into_buffer(fd: RawFd, buffer: &mut [u8]) -> isize { |
| 17 | unsafe { |
| 18 | ffi::read( |
| 19 | fd, |
| 20 | buf:buffer.as_mut_ptr() as *mut c_void, |
| 21 | count: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. |
| 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. |
| 61 | 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) = path.parent() { |
| 66 | parent_path.as_os_str().len() |
| 67 | } else { |
| 68 | 0 |
| 69 | } |
| 70 | } |
| 71 | |