Skip to content

Commit efcc1ef

Browse files
committed
Added FanotifyFidRecord, FanotifyErrorRecord, FanotifyPidfdRecord
1 parent da44a40 commit efcc1ef

File tree

1 file changed

+104
-16
lines changed

1 file changed

+104
-16
lines changed

src/sys/fanotify.rs

+104-16
Original file line numberDiff line numberDiff line change
@@ -238,13 +238,89 @@ libc_bitflags! {
238238
/// Compile version number of fanotify API.
239239
pub const FANOTIFY_METADATA_VERSION: u8 = libc::FANOTIFY_METADATA_VERSION;
240240

241-
/// Abstract over [`libc::fanotify_event_metadata`], which represents an event
242-
/// received via [`Fanotify::read_events`].
241+
/// Abstract over [`libc::fanotify_event_info_fid`], which represents an
242+
/// information record received via [`Fanotify::read_events_with_info_records`].
243243
// Is not Clone due to fd field, to avoid use-after-close scenarios.
244244
#[derive(Debug, Eq, Hash, PartialEq)]
245245
#[repr(transparent)]
246246
#[allow(missing_copy_implementations)]
247-
pub struct FanotifyEvent(libc::fanotify_event_metadata);
247+
pub struct FanotifyFidRecord(libc::fanotify_event_info_fid);
248+
249+
impl FanotifyFidRecord {
250+
/// The filesystem id where this event occurred. The value this method returns
251+
/// differs depending on the host system. Please read the statfs(2) documentation
252+
/// for more information:
253+
/// https://man7.org/linux/man-pages/man2/statfs.2.html#VERSIONS
254+
pub fn fsid(&self) -> libc::__kernel_fsid_t {
255+
self.0.fsid
256+
}
257+
258+
/// The file handle for the filesystem object where the event occurred. The handle is
259+
/// represented as a 0-length u8 array, but it actually points to variable-length
260+
/// file_handle struct.For more information:
261+
/// https://man7.org/linux/man-pages/man2/open_by_handle_at.2.html
262+
pub fn handle(&self) -> [u8; 0] {
263+
self.0.handle
264+
}
265+
}
266+
267+
/// Abstract over [`libc::fanotify_event_info_error`], which represents an
268+
/// information record received via [`Fanotify::read_events_with_info_records`].
269+
// Is not Clone due to fd field, to avoid use-after-close scenarios.
270+
#[derive(Debug, Eq, Hash, PartialEq)]
271+
#[repr(transparent)]
272+
#[allow(missing_copy_implementations)]
273+
pub struct FanotifyErrorRecord(libc::fanotify_event_info_error);
274+
275+
impl FanotifyErrorRecord {
276+
/// Errno of the FAN_FS_ERROR that occurred.
277+
pub fn err(&self) -> Errno {
278+
Errno::from_raw(self.0.error)
279+
}
280+
281+
/// Number of errors that occurred in the filesystem Fanotify in watching.
282+
/// Only a single FAN_FS_ERROR is stored per filesystem at once. As such, Fanotify
283+
/// suppresses subsequent error messages and only increments the `err_count` value.
284+
pub fn err_count(&self) -> u32 {
285+
self.0.error_count
286+
}
287+
}
288+
289+
/// Abstract over [`libc::fanotify_event_info_pidfd`], which represents an
290+
/// information record received via [`Fanotify::read_events_with_info_records`].
291+
// Is not Clone due to fd field, to avoid use-after-close scenarios.
292+
#[derive(Debug, Eq, Hash, PartialEq)]
293+
#[repr(transparent)]
294+
#[allow(missing_copy_implementations)]
295+
pub struct FanotifyPidfdRecord(libc::fanotify_event_info_pidfd);
296+
297+
impl FanotifyPidfdRecord {
298+
/// The process file descriptor that refers to the process responsible for
299+
/// generating this event. If the underlying pidfd_create fails, `None` is returned.
300+
pub fn pidfd(&self) -> Option<BorrowedFd> {
301+
if self.0.pidfd == libc::FAN_NOPIDFD || self.0.pidfd == libc::FAN_EPIDFD
302+
{
303+
None
304+
} else {
305+
// SAFETY: self.0.pidfd will be opened for the lifetime of `Self`,
306+
// which is longer than the lifetime of the returned BorrowedFd, so
307+
// it is safe.
308+
Some(unsafe { BorrowedFd::borrow_raw(self.0.pidfd) })
309+
}
310+
}
311+
}
312+
313+
impl Drop for FanotifyPidfdRecord {
314+
fn drop(&mut self) {
315+
if self.0.pidfd == libc::FAN_NOFD {
316+
return;
317+
}
318+
let e = close(self.0.pidfd);
319+
if !std::thread::panicking() && e == Err(Errno::EBADF) {
320+
panic!("Closing an invalid file descriptor!");
321+
};
322+
}
323+
}
248324

249325
/// After a [`libc::fanotify_event_metadata`], there can be 0 or more event_info
250326
/// structs depending on which InitFlags were used in [`Fanotify::init`].
@@ -258,21 +334,28 @@ pub enum FanotifyInfoRecord {
258334
/// a result of passing [`InitFlags::FAN_REPORT_FID`] or [`InitFlags::FAN_REPORT_DIR_FID`]
259335
/// into [`Fanotify::init`]. The containing struct includes a `file_handle` for
260336
/// use with `open_by_handle_at(2)`.
261-
Fid(libc::fanotify_event_info_fid),
337+
Fid(FanotifyFidRecord),
262338

263-
/// A [`libc::FAN_FS_ERROR`] event was received. This event occurs when
264-
/// a filesystem event is detected. Only a single [`libc::FAN_FS_ERROR`] is
265-
/// stored per filesystem at once, extra error messages are suppressed and
266-
/// accounted for in the error_count field.
267-
Error(libc::fanotify_event_info_error),
339+
/// A [`libc::fanotify_event_info_error`] event was recieved.
340+
/// This occurs when a FAN_FS_ERROR occurs, indicating an error with
341+
/// the watch filesystem object. (such as a bad file or bad link lookup)
342+
Error(FanotifyErrorRecord),
268343

269344
/// A [`libc::fanotify_event_info_pidfd`] event was recieved, usually as
270345
/// a result of passing [`InitFlags::FAN_REPORT_PIDFD`] into [`Fanotify::init`].
271346
/// The containing struct includes a `pidfd` for reliably determining
272347
/// whether the process responsible for generating an event has been recycled or terminated
273-
Pidfd(libc::fanotify_event_info_pidfd),
348+
Pidfd(FanotifyPidfdRecord),
274349
}
275350

351+
/// Abstract over [`libc::fanotify_event_metadata`], which represents an event
352+
/// received via [`Fanotify::read_events`].
353+
// Is not Clone due to fd field, to avoid use-after-close scenarios.
354+
#[derive(Debug, Eq, Hash, PartialEq)]
355+
#[repr(transparent)]
356+
#[allow(missing_copy_implementations)]
357+
pub struct FanotifyEvent(libc::fanotify_event_metadata);
358+
276359
impl FanotifyEvent {
277360
/// Version number for the structure. It must be compared to
278361
/// `FANOTIFY_METADATA_VERSION` to verify compile version and runtime
@@ -513,28 +596,33 @@ impl Fanotify {
513596

514597
let info_record = match header.info_type {
515598
libc::FAN_EVENT_INFO_TYPE_FID => {
516-
let event_fid = self
599+
let record = self
517600
.get_struct::<libc::fanotify_event_info_fid>(
518601
&buffer,
519602
current_event_offset,
520603
);
521-
Some(FanotifyInfoRecord::Fid(event_fid))
604+
Some(FanotifyInfoRecord::Fid(FanotifyFidRecord(record)))
522605
}
523606
libc::FAN_EVENT_INFO_TYPE_ERROR => {
524-
let error_fid = self
607+
let record = self
525608
.get_struct::<libc::fanotify_event_info_error>(
526609
&buffer,
527610
current_event_offset,
528611
);
529-
Some(FanotifyInfoRecord::Error(error_fid))
612+
613+
Some(FanotifyInfoRecord::Error(FanotifyErrorRecord(
614+
record,
615+
)))
530616
}
531617
libc::FAN_EVENT_INFO_TYPE_PIDFD => {
532-
let error_fid = self
618+
let record = self
533619
.get_struct::<libc::fanotify_event_info_pidfd>(
534620
&buffer,
535621
current_event_offset,
536622
);
537-
Some(FanotifyInfoRecord::Pidfd(error_fid))
623+
Some(FanotifyInfoRecord::Pidfd(FanotifyPidfdRecord(
624+
record,
625+
)))
538626
}
539627
// Ignore unsupported events
540628
_ => None,

0 commit comments

Comments
 (0)