Skip to content

Commit aa3aac3

Browse files
committed
Added support for retrieving the appended name on an Fid Record
1 parent b283943 commit aa3aac3

File tree

1 file changed

+58
-17
lines changed

1 file changed

+58
-17
lines changed

src/sys/fanotify.rs

Lines changed: 58 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ use crate::errno::Errno;
1414
use crate::fcntl::OFlag;
1515
use crate::unistd::{close, read, write};
1616
use crate::{NixPath, Result};
17+
use std::ffi::CStr;
1718
use std::marker::PhantomData;
1819
use std::mem::{size_of, MaybeUninit};
1920
use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, OwnedFd, RawFd};
@@ -272,6 +273,7 @@ pub struct LibcFanotifyFidRecord(libc::fanotify_event_info_fid);
272273
pub struct FanotifyFidRecord {
273274
record: LibcFanotifyFidRecord,
274275
file_handle_bytes: [u8; MAX_HANDLE_SZ],
276+
name: Option<String>,
275277
}
276278

277279
impl FanotifyFidRecord {
@@ -293,10 +295,20 @@ impl FanotifyFidRecord {
293295

294296
/// The specific info_type for this Fid Record. Fanotify can return an Fid Record
295297
/// with many different possible info_types. The info_type is not always necessary
296-
/// but can be useful for connecting similar events together (like a FAN_RENAME)
298+
/// but can be useful for connecting similar events together (like a FAN_RENAME)
297299
pub fn info_type(&self) -> FanotifyFidEventInfoType {
298300
FanotifyFidEventInfoType::try_from(self.record.0.hdr.info_type).unwrap()
299301
}
302+
303+
/// The name attached to the end of this Fid Record. This will only contain a value
304+
/// if the info_type is expected to return a name (like `FanotifyFidEventInfoType::FAN_EVENT_INFO_TYPE_DFID_NAME`)
305+
pub fn name(&self) -> Option<&str> {
306+
if let Some(name) = self.name.as_ref() {
307+
Some(name)
308+
} else {
309+
None
310+
}
311+
}
300312
}
301313

302314
/// Abstract over [`libc::fanotify_event_info_error`], which represents an
@@ -599,7 +611,7 @@ impl Fanotify {
599611
/// In particular, `EAGAIN` is returned when no event is available on a
600612
/// group that has been initialized with the flag `InitFlags::FAN_NONBLOCK`,
601613
/// thus making this method nonblocking.
602-
#[allow(clippy::cast_ptr_alignment)] // False positive
614+
#[allow(clippy::cast_ptr_alignment)] // False positive
603615
pub fn read_events_with_info_records(
604616
&self,
605617
) -> Result<Vec<(FanotifyEvent, Vec<FanotifyInfoRecord>)>> {
@@ -628,9 +640,12 @@ impl Fanotify {
628640
let mut current_event_offset = offset + metadata_size;
629641

630642
while remaining_len > 0 {
631-
let header_info_type = unsafe { buffer.as_ptr().add(current_event_offset).read() };
643+
let header_info_type =
644+
unsafe { buffer.as_ptr().add(current_event_offset).read() };
632645
// The +2 here represents the offset between the info_type and the length (which is 2 u8s apart)
633-
let info_type_length = unsafe { buffer.as_ptr().add(current_event_offset + 2).read() };
646+
let info_type_length = unsafe {
647+
buffer.as_ptr().add(current_event_offset + 2).read()
648+
};
634649

635650
let info_record = match header_info_type {
636651
// FanotifyFidRecord can be returned for any of the following info_type.
@@ -647,18 +662,24 @@ impl Fanotify {
647662
current_event_offset,
648663
);
649664

650-
let record_ptr: *const libc::fanotify_event_info_fid = unsafe {
651-
buffer.as_ptr().add(current_event_offset)
652-
as *const libc::fanotify_event_info_fid
665+
let file_handle_ptr = unsafe {
666+
(buffer.as_ptr().add(current_event_offset)
667+
as *const libc::fanotify_event_info_fid)
668+
.add(1) as *const u8
669+
};
670+
671+
// Read the entire file_handle. The struct can be found here:
672+
// https://man7.org/linux/man-pages/man2/open_by_handle_at.2.html
673+
let file_handle_length = unsafe {
674+
size_of::<u32>()
675+
+ size_of::<i32>()
676+
+ file_handle_ptr.cast::<u32>().read() as usize
653677
};
654678

655679
let file_handle = unsafe {
656-
let file_handle_ptr = record_ptr.add(1) as *const u8;
657-
let mut file_handle = MaybeUninit::<[u8; MAX_HANDLE_SZ]>::uninit();
680+
let mut file_handle =
681+
MaybeUninit::<[u8; MAX_HANDLE_SZ]>::uninit();
658682

659-
// Read the entire file_handle. The struct can be found here:
660-
// https://man7.org/linux/man-pages/man2/open_by_handle_at.2.html
661-
let file_handle_length = size_of::<u32>() + size_of::<i32>() + file_handle_ptr.cast::<u32>().read() as usize;
662683
std::ptr::copy_nonoverlapping(
663684
file_handle_ptr,
664685
file_handle.as_mut_ptr().cast(),
@@ -667,9 +688,32 @@ impl Fanotify {
667688
file_handle.assume_init()
668689
};
669690

691+
let name: Option<String> = match header_info_type {
692+
libc::FAN_EVENT_INFO_TYPE_DFID_NAME
693+
| libc::FAN_EVENT_INFO_TYPE_NEW_DFID_NAME
694+
| libc::FAN_EVENT_INFO_TYPE_OLD_DFID_NAME => unsafe {
695+
let name_ptr =
696+
file_handle_ptr.add(file_handle_length);
697+
if !name_ptr.is_null() {
698+
let name_as_c_str =
699+
CStr::from_ptr(name_ptr.cast())
700+
.to_str();
701+
if let Ok(name) = name_as_c_str {
702+
Some(name.to_owned())
703+
} else {
704+
None
705+
}
706+
} else {
707+
None
708+
}
709+
},
710+
_ => None,
711+
};
712+
670713
Some(FanotifyInfoRecord::Fid(FanotifyFidRecord {
671714
record: LibcFanotifyFidRecord(record),
672715
file_handle_bytes: file_handle,
716+
name,
673717
}))
674718
}
675719
#[cfg(target_env = "gnu")]
@@ -752,8 +796,7 @@ impl AsFd for Fanotify {
752796
}
753797

754798
impl AsRawFd for Fanotify {
755-
fn as_raw_fd(&self) -> RawFd
756-
{
799+
fn as_raw_fd(&self) -> RawFd {
757800
self.fd.as_raw_fd()
758801
}
759802
}
@@ -771,8 +814,6 @@ impl Fanotify {
771814
///
772815
/// `OwnedFd` is a valid `Fanotify`.
773816
pub unsafe fn from_owned_fd(fd: OwnedFd) -> Self {
774-
Self {
775-
fd
776-
}
817+
Self { fd }
777818
}
778819
}

0 commit comments

Comments
 (0)