Skip to content

Commit ef375dc

Browse files
committed
Support type-safe path FDs
Signed-off-by: Alex Saveau <[email protected]>
1 parent b8e8a89 commit ef375dc

17 files changed

+191
-165
lines changed

src/dir.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ impl Dir {
4545

4646
/// Opens the given path as with `fcntl::openat`.
4747
pub fn openat<Fd: AsFd, P: ?Sized + NixPath>(
48-
dirfd: &Fd,
48+
dirfd: Fd,
4949
path: &P,
5050
oflag: OFlag,
5151
mode: sys::stat::Mode,

src/fcntl.rs

+29-27
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ use std::os::unix::io::FromRawFd;
99
use std::os::unix::io::OwnedFd;
1010
use std::os::unix::io::RawFd;
1111

12+
#[cfg(not(target_os = "redox"))]
13+
use crate::AsPathFd;
1214
#[cfg(feature = "fs")]
1315
use crate::{sys::stat::Mode, NixPath, Result};
1416
#[cfg(any(target_os = "android", target_os = "linux"))]
@@ -211,15 +213,15 @@ pub fn open<P: ?Sized + NixPath>(
211213
// The conversion is not identical on all operating systems.
212214
#[allow(clippy::useless_conversion)]
213215
#[cfg(not(target_os = "redox"))]
214-
pub fn openat<Fd: AsFd, P: ?Sized + NixPath>(
215-
dirfd: &Fd,
216+
pub fn openat<Fd: AsPathFd, P: ?Sized + NixPath>(
217+
dirfd: Fd,
216218
path: &P,
217219
oflag: OFlag,
218220
mode: Mode,
219221
) -> Result<OwnedFd> {
220222
let fd = path.with_nix_path(|cstr| unsafe {
221223
libc::openat(
222-
dirfd.as_fd().as_raw_fd(),
224+
dirfd.as_path_fd(),
223225
cstr.as_ptr(),
224226
oflag.bits(),
225227
mode.bits() as c_uint,
@@ -230,18 +232,18 @@ pub fn openat<Fd: AsFd, P: ?Sized + NixPath>(
230232
}
231233

232234
#[cfg(not(target_os = "redox"))]
233-
pub fn renameat<Fd1: AsFd, P1: ?Sized + NixPath, Fd2: AsFd, P2: ?Sized + NixPath>(
234-
old_dirfd: &Fd1,
235+
pub fn renameat<Fd1: AsPathFd, P1: ?Sized + NixPath, Fd2: AsPathFd, P2: ?Sized + NixPath>(
236+
old_dirfd: Fd1,
235237
old_path: &P1,
236-
new_dirfd: &Fd2,
238+
new_dirfd: Fd2,
237239
new_path: &P2,
238240
) -> Result<()> {
239241
let res = old_path.with_nix_path(|old_cstr| {
240242
new_path.with_nix_path(|new_cstr| unsafe {
241243
libc::renameat(
242-
old_dirfd.as_fd().as_raw_fd(),
244+
old_dirfd.as_path_fd(),
243245
old_cstr.as_ptr(),
244-
new_dirfd.as_fd().as_raw_fd(),
246+
new_dirfd.as_path_fd(),
245247
new_cstr.as_ptr(),
246248
)
247249
})
@@ -264,19 +266,19 @@ libc_bitflags! {
264266
feature! {
265267
#![feature = "fs"]
266268
#[cfg(all(target_os = "linux", target_env = "gnu"))]
267-
pub fn renameat2<Fd1: AsFd, P1: ?Sized + NixPath, Fd2: AsFd, P2: ?Sized + NixPath>(
268-
old_dirfd: &Fd1,
269+
pub fn renameat2<Fd1: AsPathFd, P1: ?Sized + NixPath, Fd2: AsPathFd, P2: ?Sized + NixPath>(
270+
old_dirfd: Fd1,
269271
old_path: &P1,
270-
new_dirfd: &Fd2,
272+
new_dirfd: Fd2,
271273
new_path: &P2,
272274
flags: RenameFlags,
273275
) -> Result<()> {
274276
let res = old_path.with_nix_path(|old_cstr| {
275277
new_path.with_nix_path(|new_cstr| unsafe {
276278
libc::renameat2(
277-
old_dirfd.as_fd().as_raw_fd(),
279+
old_dirfd.as_path_fd(),
278280
old_cstr.as_ptr(),
279-
new_dirfd.as_fd().as_raw_fd(),
281+
new_dirfd.as_path_fd(),
280282
new_cstr.as_ptr(),
281283
flags.bits(),
282284
)
@@ -404,10 +406,10 @@ pub fn readlink<P: ?Sized + NixPath>(path: &P) -> Result<OsString> {
404406

405407
#[cfg(not(target_os = "redox"))]
406408
pub fn readlinkat<Fd: AsFd, P: ?Sized + NixPath>(
407-
dirfd: &Fd,
409+
dirfd: Fd,
408410
path: &P,
409411
) -> Result<OsString> {
410-
inner_readlink(Some(dirfd), path)
412+
inner_readlink(Some(&dirfd), path)
411413
}
412414
}
413415

@@ -599,9 +601,9 @@ feature! {
599601
/// returned.
600602
#[cfg(any(target_os = "android", target_os = "linux"))]
601603
pub fn copy_file_range<Fd1: AsFd, Fd2: AsFd>(
602-
fd_in: &Fd1,
604+
fd_in: Fd1,
603605
off_in: Option<&mut libc::loff_t>,
604-
fd_out: &Fd2,
606+
fd_out: Fd2,
605607
off_out: Option<&mut libc::loff_t>,
606608
len: usize,
607609
) -> Result<usize> {
@@ -628,9 +630,9 @@ pub fn copy_file_range<Fd1: AsFd, Fd2: AsFd>(
628630

629631
#[cfg(any(target_os = "linux", target_os = "android"))]
630632
pub fn splice<Fd1: AsFd, Fd2: AsFd>(
631-
fd_in: &Fd1,
633+
fd_in: Fd1,
632634
off_in: Option<&mut libc::loff_t>,
633-
fd_out: &Fd2,
635+
fd_out: Fd2,
634636
off_out: Option<&mut libc::loff_t>,
635637
len: usize,
636638
flags: SpliceFFlags,
@@ -657,8 +659,8 @@ pub fn splice<Fd1: AsFd, Fd2: AsFd>(
657659

658660
#[cfg(any(target_os = "linux", target_os = "android"))]
659661
pub fn tee<Fd1: AsFd, Fd2: AsFd>(
660-
fd_in: &Fd1,
661-
fd_out: &Fd2,
662+
fd_in: Fd1,
663+
fd_out: Fd2,
662664
len: usize,
663665
flags: SpliceFFlags,
664666
) -> Result<usize> {
@@ -675,7 +677,7 @@ pub fn tee<Fd1: AsFd, Fd2: AsFd>(
675677

676678
#[cfg(any(target_os = "linux", target_os = "android"))]
677679
pub fn vmsplice<Fd: AsFd>(
678-
fd: &Fd,
680+
fd: Fd,
679681
iov: &[std::io::IoSlice<'_>],
680682
flags: SpliceFFlags,
681683
) -> Result<usize> {
@@ -734,7 +736,7 @@ feature! {
734736
#[cfg(any(target_os = "linux"))]
735737
#[cfg(feature = "fs")]
736738
pub fn fallocate<Fd: AsFd>(
737-
fd: &Fd,
739+
fd: Fd,
738740
mode: FallocateFlags,
739741
offset: libc::off_t,
740742
len: libc::off_t,
@@ -810,7 +812,7 @@ impl SpacectlRange {
810812
/// ```
811813
#[cfg(target_os = "freebsd")]
812814
pub fn fspacectl<Fd: AsFd>(
813-
fd: &Fd,
815+
fd: Fd,
814816
range: SpacectlRange,
815817
) -> Result<SpacectlRange> {
816818
let mut rqsr = libc::spacectl_range {
@@ -861,7 +863,7 @@ pub fn fspacectl<Fd: AsFd>(
861863
/// ```
862864
#[cfg(target_os = "freebsd")]
863865
pub fn fspacectl_all<Fd: AsFd>(
864-
fd: &Fd,
866+
fd: Fd,
865867
offset: libc::off_t,
866868
len: libc::off_t,
867869
) -> Result<()> {
@@ -917,7 +919,7 @@ mod posix_fadvise {
917919
feature! {
918920
#![feature = "fs"]
919921
pub fn posix_fadvise<Fd: AsFd>(
920-
fd: &Fd,
922+
fd: Fd,
921923
offset: libc::off_t,
922924
len: libc::off_t,
923925
advice: PosixFadviseAdvice,
@@ -950,7 +952,7 @@ mod posix_fadvise {
950952
target_os = "freebsd"
951953
))]
952954
pub fn posix_fallocate<Fd: AsFd>(
953-
fd: &Fd,
955+
fd: Fd,
954956
offset: libc::off_t,
955957
len: libc::off_t,
956958
) -> Result<()> {

src/kmod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ libc_bitflags!(
8080
///
8181
/// See [`man init_module(2)`](https://man7.org/linux/man-pages/man2/init_module.2.html) for more information.
8282
pub fn finit_module<Fd: AsFd>(
83-
fd: &Fd,
83+
fd: Fd,
8484
param_values: &CStr,
8585
flags: ModuleInitFlags,
8686
) -> Result<()> {

src/lib.rs

+22-10
Original file line numberDiff line numberDiff line change
@@ -162,8 +162,7 @@ pub mod unistd;
162162
use std::ffi::{CStr, CString, OsStr};
163163
use std::mem::MaybeUninit;
164164
use std::os::unix::ffi::OsStrExt;
165-
#[cfg(not(target_os = "redox"))]
166-
use std::os::unix::io::BorrowedFd;
165+
use std::os::unix::io::{AsFd, AsRawFd, RawFd};
167166
use std::path::{Path, PathBuf};
168167
use std::{ptr, result, slice};
169168

@@ -184,16 +183,29 @@ pub type Result<T> = result::Result<T, Errno>;
184183
/// ones.
185184
pub type Error = Errno;
186185

187-
/// A file descriptor representing the current working directory.
186+
/// A trait that models requirements for path file descriptors.
187+
pub trait AsPathFd {
188+
/// Extracts the raw file descriptor.
189+
fn as_path_fd(&self) -> RawFd;
190+
}
191+
192+
impl<Fd: AsFd> AsPathFd for Fd {
193+
fn as_path_fd(&self) -> RawFd {
194+
self.as_fd().as_raw_fd()
195+
}
196+
}
197+
198+
/// The `AT_FDCWD` marker FD.
199+
#[cfg(not(target_os = "redox"))]
200+
#[derive(Copy, Clone, Debug)]
201+
pub struct Cwd;
202+
188203
#[cfg(not(target_os = "redox"))]
189-
pub const AT_FDCWD: &BorrowedFd<'static> = unsafe {
190-
&BorrowedFd::borrow_raw(if cfg!(target_os = "haiku") {
191-
// Hack to work around BorrowedFd not allowing -1
192-
-2
193-
} else {
204+
impl AsPathFd for Cwd {
205+
fn as_path_fd(&self) -> RawFd {
194206
libc::AT_FDCWD
195-
})
196-
};
207+
}
208+
}
197209

198210
/// Common trait used to represent file system paths by many Nix functions.
199211
pub trait NixPath {

src/sys/epoll.rs

+40-24
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use crate::errno::Errno;
22
use crate::Result;
33
use libc::{self, c_int};
44
use std::mem;
5-
use std::os::unix::io::{FromRawFd,RawFd, OwnedFd, AsFd, AsRawFd};
5+
use std::os::unix::io::{AsFd, AsRawFd, FromRawFd, OwnedFd, RawFd};
66

77
libc_bitflags!(
88
pub struct EpollFlags: c_int {
@@ -78,22 +78,22 @@ impl EpollEvent {
7878
/// # fn main() -> nix::Result<()> {
7979
/// const DATA: u64 = 17;
8080
/// const MILLIS: u64 = 100;
81-
///
81+
///
8282
/// // Create epoll
8383
/// let epoll = Epoll::new(EpollCreateFlags::empty())?;
84-
///
84+
///
8585
/// // Create eventfd & Add event
8686
/// let eventfd = unsafe { OwnedFd::from_raw_fd(eventfd(0, EfdFlags::empty())?) };
8787
/// epoll.add(&eventfd, EpollEvent::new(EpollFlags::EPOLLIN,DATA))?;
88-
///
88+
///
8989
/// // Arm eventfd & Time wait
90-
/// write(eventfd.as_raw_fd(), &1u64.to_ne_bytes())?;
90+
/// write(&eventfd, &1u64.to_ne_bytes())?;
9191
/// let now = Instant::now();
92-
///
92+
///
9393
/// // Wait on event
9494
/// let mut events = [EpollEvent::empty()];
9595
/// epoll.wait(&mut events, MILLIS as isize)?;
96-
///
96+
///
9797
/// // Assert data correct & timeout didn't occur
9898
/// assert_eq!(events[0].data(), DATA);
9999
/// assert!(now.elapsed() < Duration::from_millis(MILLIS));
@@ -104,7 +104,7 @@ impl EpollEvent {
104104
pub struct Epoll(pub OwnedFd);
105105
impl Epoll {
106106
/// Creates a new epoll instance and returns a file descriptor referring to that instance.
107-
///
107+
///
108108
/// [`epoll_create1`](https://man7.org/linux/man-pages/man2/epoll_create1.2.html).
109109
pub fn new(flags: EpollCreateFlags) -> Result<Self> {
110110
let res = unsafe { libc::epoll_create1(flags.bits()) };
@@ -113,30 +113,38 @@ impl Epoll {
113113
Ok(Self(owned_fd))
114114
}
115115
/// Add an entry to the interest list of the epoll file descriptor for
116-
/// specified in events.
117-
///
116+
/// specified in events.
117+
///
118118
/// [`epoll_ctl`](https://man7.org/linux/man-pages/man2/epoll_ctl.2.html) with `EPOLL_CTL_ADD`.
119119
pub fn add<Fd: AsFd>(&self, fd: Fd, mut event: EpollEvent) -> Result<()> {
120-
self.epoll_ctl(EpollOp::EpollCtlAdd,fd,&mut event)
120+
self.epoll_ctl(EpollOp::EpollCtlAdd, fd, &mut event)
121121
}
122122
/// Remove (deregister) the target file descriptor `fd` from the interest list.
123-
///
123+
///
124124
/// [`epoll_ctl`](https://man7.org/linux/man-pages/man2/epoll_ctl.2.html) with `EPOLL_CTL_DEL` .
125125
pub fn delete<Fd: AsFd>(&self, fd: Fd) -> Result<()> {
126-
self.epoll_ctl(EpollOp::EpollCtlDel,fd,None)
126+
self.epoll_ctl(EpollOp::EpollCtlDel, fd, None)
127127
}
128128
/// Change the settings associated with `fd` in the interest list to the new settings specified
129129
/// in `event`.
130-
///
130+
///
131131
/// [`epoll_ctl`](https://man7.org/linux/man-pages/man2/epoll_ctl.2.html) with `EPOLL_CTL_MOD`.
132-
pub fn modify<Fd: AsFd>(&self,fd: Fd, event: &mut EpollEvent) -> Result<()> {
133-
self.epoll_ctl(EpollOp::EpollCtlMod,fd,event)
132+
pub fn modify<Fd: AsFd>(
133+
&self,
134+
fd: Fd,
135+
event: &mut EpollEvent,
136+
) -> Result<()> {
137+
self.epoll_ctl(EpollOp::EpollCtlMod, fd, event)
134138
}
135139
/// Waits for I/O events, blocking the calling thread if no events are currently available.
136140
/// (This can be thought of as fetching items from the ready list of the epoll instance.)
137-
///
141+
///
138142
/// [`epoll_wait`](https://man7.org/linux/man-pages/man2/epoll_wait.2.html)
139-
pub fn wait(&self, events: &mut [EpollEvent], timeout: isize) -> Result<usize> {
143+
pub fn wait(
144+
&self,
145+
events: &mut [EpollEvent],
146+
timeout: isize,
147+
) -> Result<usize> {
140148
let res = unsafe {
141149
libc::epoll_wait(
142150
self.0.as_raw_fd(),
@@ -145,15 +153,15 @@ impl Epoll {
145153
timeout as c_int,
146154
)
147155
};
148-
156+
149157
Errno::result(res).map(|r| r as usize)
150158
}
151159
/// This system call is used to add, modify, or remove entries in the interest list of the epoll
152160
/// instance referred to by `self`. It requests that the operation `op` be performed for the
153161
/// target file descriptor, `fd`.
154-
///
162+
///
155163
/// When possible prefer [`Epoll::add`], [`Epoll::delete`] and [`Epoll::modify`].
156-
///
164+
///
157165
/// [`epoll_ctl`](https://man7.org/linux/man-pages/man2/epoll_ctl.2.html)
158166
fn epoll_ctl<'a, Fd: AsFd, T>(
159167
&self,
@@ -165,9 +173,17 @@ impl Epoll {
165173
T: Into<Option<&'a mut EpollEvent>>,
166174
{
167175
let event: Option<&mut EpollEvent> = event.into();
168-
let ptr = event.map(|x|&mut x.event as *mut libc::epoll_event).unwrap_or(std::ptr::null_mut());
176+
let ptr = event
177+
.map(|x| &mut x.event as *mut libc::epoll_event)
178+
.unwrap_or(std::ptr::null_mut());
169179
unsafe {
170-
Errno::result(libc::epoll_ctl(self.0.as_raw_fd(), op as c_int, fd.as_fd().as_raw_fd(), ptr)).map(drop)
180+
Errno::result(libc::epoll_ctl(
181+
self.0.as_raw_fd(),
182+
op as c_int,
183+
fd.as_fd().as_raw_fd(),
184+
ptr,
185+
))
186+
.map(drop)
171187
}
172188
}
173189
}
@@ -231,4 +247,4 @@ pub fn epoll_wait(
231247
};
232248

233249
Errno::result(res).map(|r| r as usize)
234-
}
250+
}

src/sys/inotify.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ impl Inotify {
197197
let mut offset = 0;
198198

199199
let nread =
200-
read(unsafe { &BorrowedFd::borrow_raw(self.fd) }, &mut buffer)?;
200+
read(unsafe { BorrowedFd::borrow_raw(self.fd) }, &mut buffer)?;
201201

202202
while (nread - offset) >= header_size {
203203
let event = unsafe {

0 commit comments

Comments
 (0)