diff --git a/src/fcntl.rs b/src/fcntl.rs index a711a41170..52d00b3808 100644 --- a/src/fcntl.rs +++ b/src/fcntl.rs @@ -1,10 +1,13 @@ use crate::errno::Errno; +#[cfg(target_os = "freebsd")] +use core::slice; use libc::{self, c_int, c_uint, size_t, ssize_t}; #[cfg(any( target_os = "netbsd", target_os = "macos", target_os = "ios", target_os = "dragonfly", + target_os = "freebsd", ))] use std::ffi::CStr; use std::ffi::OsString; @@ -18,6 +21,7 @@ use std::os::unix::io::RawFd; target_os = "macos", target_os = "ios", target_os = "dragonfly", + target_os = "freebsd", ))] use std::path::PathBuf; #[cfg(any( @@ -505,6 +509,8 @@ pub enum FcntlArg<'a> { F_SETPIPE_SZ(c_int), #[cfg(any(target_os = "netbsd", target_os = "dragonfly", target_os = "macos", target_os = "ios"))] F_GETPATH(&'a mut PathBuf), + #[cfg(target_os = "freebsd")] + F_KINFO(&'a mut PathBuf), // TODO: Rest of flags } @@ -574,6 +580,18 @@ pub fn fcntl(fd: RawFd, arg: FcntlArg) -> Result { *path = PathBuf::from(OsString::from(optr.to_str().unwrap())); return Ok(ok_res) }, + #[cfg(target_os = "freebsd")] + F_KINFO(path) => { + let mut info: libc::kinfo_file = std::mem::zeroed(); + info.kf_structsize = std::mem::size_of::() as i32; + let res = libc::fcntl(fd, libc::F_KINFO, &mut info); + let ok_res = Errno::result(res)?; + let p = info.kf_path; + let u8_slice = slice::from_raw_parts(p.as_ptr().cast(), p.len()); + let optr = CStr::from_bytes_until_nul(u8_slice).unwrap(); + *path = PathBuf::from(OsString::from(optr.to_str().unwrap())); + return Ok(ok_res) + }, } }; diff --git a/test/test_fcntl.rs b/test/test_fcntl.rs index 0faf39d237..981188d8c2 100644 --- a/test/test_fcntl.rs +++ b/test/test_fcntl.rs @@ -584,3 +584,18 @@ fn test_f_get_path() { tmp.path().canonicalize().unwrap() ); } + +#[cfg(target_os = "freebsd")] +#[test] +fn test_f_kinfo() { + use nix::fcntl::*; + use std::{os::unix::io::AsRawFd, path::PathBuf}; + + let tmp = NamedTempFile::new().unwrap(); + let tmp2 = File::open(tmp.path()).unwrap(); + let fd = tmp2.as_raw_fd(); + let mut path = PathBuf::new(); + let res = fcntl(fd, FcntlArg::F_KINFO(&mut path)).expect("get path failed"); + assert_ne!(res, -1); + assert_eq!(path, tmp.path()); +}