Skip to content

Commit a56ddf2

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

File tree

11 files changed

+169
-145
lines changed

11 files changed

+169
-145
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

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

12+
use crate::IntoPathFd;
1213
#[cfg(feature = "fs")]
1314
use crate::{sys::stat::Mode, NixPath, Result};
1415
#[cfg(any(target_os = "android", target_os = "linux"))]
@@ -211,15 +212,15 @@ pub fn open<P: ?Sized + NixPath>(
211212
// The conversion is not identical on all operating systems.
212213
#[allow(clippy::useless_conversion)]
213214
#[cfg(not(target_os = "redox"))]
214-
pub fn openat<Fd: AsFd, P: ?Sized + NixPath>(
215-
dirfd: &Fd,
215+
pub fn openat<Fd: IntoPathFd, P: ?Sized + NixPath>(
216+
dirfd: Fd,
216217
path: &P,
217218
oflag: OFlag,
218219
mode: Mode,
219220
) -> Result<OwnedFd> {
220221
let fd = path.with_nix_path(|cstr| unsafe {
221222
libc::openat(
222-
dirfd.as_fd().as_raw_fd(),
223+
dirfd.as_raw_path_fd(),
223224
cstr.as_ptr(),
224225
oflag.bits(),
225226
mode.bits() as c_uint,
@@ -230,18 +231,18 @@ pub fn openat<Fd: AsFd, P: ?Sized + NixPath>(
230231
}
231232

232233
#[cfg(not(target_os = "redox"))]
233-
pub fn renameat<Fd1: AsFd, P1: ?Sized + NixPath, Fd2: AsFd, P2: ?Sized + NixPath>(
234-
old_dirfd: &Fd1,
234+
pub fn renameat<Fd1: IntoPathFd, P1: ?Sized + NixPath, Fd2: IntoPathFd, P2: ?Sized + NixPath>(
235+
old_dirfd: Fd1,
235236
old_path: &P1,
236-
new_dirfd: &Fd2,
237+
new_dirfd: Fd2,
237238
new_path: &P2,
238239
) -> Result<()> {
239240
let res = old_path.with_nix_path(|old_cstr| {
240241
new_path.with_nix_path(|new_cstr| unsafe {
241242
libc::renameat(
242-
old_dirfd.as_fd().as_raw_fd(),
243+
old_dirfd.as_raw_path_fd(),
243244
old_cstr.as_ptr(),
244-
new_dirfd.as_fd().as_raw_fd(),
245+
new_dirfd.as_raw_path_fd(),
245246
new_cstr.as_ptr(),
246247
)
247248
})
@@ -264,19 +265,19 @@ libc_bitflags! {
264265
feature! {
265266
#![feature = "fs"]
266267
#[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,
268+
pub fn renameat2<Fd1: IntoPathFd, P1: ?Sized + NixPath, Fd2: IntoPathFd, P2: ?Sized + NixPath>(
269+
old_dirfd: Fd1,
269270
old_path: &P1,
270-
new_dirfd: &Fd2,
271+
new_dirfd: Fd2,
271272
new_path: &P2,
272273
flags: RenameFlags,
273274
) -> Result<()> {
274275
let res = old_path.with_nix_path(|old_cstr| {
275276
new_path.with_nix_path(|new_cstr| unsafe {
276277
libc::renameat2(
277-
old_dirfd.as_fd().as_raw_fd(),
278+
old_dirfd.as_raw_path_fd(),
278279
old_cstr.as_ptr(),
279-
new_dirfd.as_fd().as_raw_fd(),
280+
new_dirfd.as_raw_path_fd(),
280281
new_cstr.as_ptr(),
281282
flags.bits(),
282283
)
@@ -404,10 +405,10 @@ pub fn readlink<P: ?Sized + NixPath>(path: &P) -> Result<OsString> {
404405

405406
#[cfg(not(target_os = "redox"))]
406407
pub fn readlinkat<Fd: AsFd, P: ?Sized + NixPath>(
407-
dirfd: &Fd,
408+
dirfd: Fd,
408409
path: &P,
409410
) -> Result<OsString> {
410-
inner_readlink(Some(dirfd), path)
411+
inner_readlink(Some(&dirfd), path)
411412
}
412413
}
413414

@@ -599,9 +600,9 @@ feature! {
599600
/// returned.
600601
#[cfg(any(target_os = "android", target_os = "linux"))]
601602
pub fn copy_file_range<Fd1: AsFd, Fd2: AsFd>(
602-
fd_in: &Fd1,
603+
fd_in: Fd1,
603604
off_in: Option<&mut libc::loff_t>,
604-
fd_out: &Fd2,
605+
fd_out: Fd2,
605606
off_out: Option<&mut libc::loff_t>,
606607
len: usize,
607608
) -> Result<usize> {
@@ -628,9 +629,9 @@ pub fn copy_file_range<Fd1: AsFd, Fd2: AsFd>(
628629

629630
#[cfg(any(target_os = "linux", target_os = "android"))]
630631
pub fn splice<Fd1: AsFd, Fd2: AsFd>(
631-
fd_in: &Fd1,
632+
fd_in: Fd1,
632633
off_in: Option<&mut libc::loff_t>,
633-
fd_out: &Fd2,
634+
fd_out: Fd2,
634635
off_out: Option<&mut libc::loff_t>,
635636
len: usize,
636637
flags: SpliceFFlags,
@@ -657,8 +658,8 @@ pub fn splice<Fd1: AsFd, Fd2: AsFd>(
657658

658659
#[cfg(any(target_os = "linux", target_os = "android"))]
659660
pub fn tee<Fd1: AsFd, Fd2: AsFd>(
660-
fd_in: &Fd1,
661-
fd_out: &Fd2,
661+
fd_in: Fd1,
662+
fd_out: Fd2,
662663
len: usize,
663664
flags: SpliceFFlags,
664665
) -> Result<usize> {
@@ -675,7 +676,7 @@ pub fn tee<Fd1: AsFd, Fd2: AsFd>(
675676

676677
#[cfg(any(target_os = "linux", target_os = "android"))]
677678
pub fn vmsplice<Fd: AsFd>(
678-
fd: &Fd,
679+
fd: Fd,
679680
iov: &[std::io::IoSlice<'_>],
680681
flags: SpliceFFlags,
681682
) -> Result<usize> {
@@ -734,7 +735,7 @@ feature! {
734735
#[cfg(any(target_os = "linux"))]
735736
#[cfg(feature = "fs")]
736737
pub fn fallocate<Fd: AsFd>(
737-
fd: &Fd,
738+
fd: Fd,
738739
mode: FallocateFlags,
739740
offset: libc::off_t,
740741
len: libc::off_t,
@@ -810,7 +811,7 @@ impl SpacectlRange {
810811
/// ```
811812
#[cfg(target_os = "freebsd")]
812813
pub fn fspacectl<Fd: AsFd>(
813-
fd: &Fd,
814+
fd: Fd,
814815
range: SpacectlRange,
815816
) -> Result<SpacectlRange> {
816817
let mut rqsr = libc::spacectl_range {
@@ -861,7 +862,7 @@ pub fn fspacectl<Fd: AsFd>(
861862
/// ```
862863
#[cfg(target_os = "freebsd")]
863864
pub fn fspacectl_all<Fd: AsFd>(
864-
fd: &Fd,
865+
fd: Fd,
865866
offset: libc::off_t,
866867
len: libc::off_t,
867868
) -> Result<()> {
@@ -917,7 +918,7 @@ mod posix_fadvise {
917918
feature! {
918919
#![feature = "fs"]
919920
pub fn posix_fadvise<Fd: AsFd>(
920-
fd: &Fd,
921+
fd: Fd,
921922
offset: libc::off_t,
922923
len: libc::off_t,
923924
advice: PosixFadviseAdvice,
@@ -950,7 +951,7 @@ mod posix_fadvise {
950951
target_os = "freebsd"
951952
))]
952953
pub fn posix_fallocate<Fd: AsFd>(
953-
fd: &Fd,
954+
fd: Fd,
954955
offset: libc::off_t,
955956
len: libc::off_t,
956957
) -> 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 IntoPathFd {
188+
/// Extracts the raw file descriptor.
189+
fn as_raw_path_fd(&self) -> RawFd;
190+
}
191+
192+
impl<Fd: AsFd> IntoPathFd for Fd {
193+
fn as_raw_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 IntoPathFd for Cwd {
205+
fn as_raw_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+
}

0 commit comments

Comments
 (0)