Skip to content

Commit cdb34e3

Browse files
committed
use_file: Use std::File instead of DropGuard.
For now, still use `libc::{poll,read}`. But use `File::open` to open the files, instead of using `DropGuard`. While doing this, switch to the `RawFd` type alias from `libc::c_int`.
1 parent 7e2590f commit cdb34e3

File tree

2 files changed

+37
-42
lines changed

2 files changed

+37
-42
lines changed

src/use_file.rs

Lines changed: 37 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,26 @@
11
//! Implementations that just need to read from a file
2-
use crate::{
3-
util_libc::{open_readonly, sys_fill_exact},
4-
Error,
5-
};
2+
3+
extern crate std;
4+
5+
use crate::{util_libc::sys_fill_exact, Error};
66
use core::{
77
cell::UnsafeCell,
88
ffi::c_void,
99
mem::MaybeUninit,
1010
sync::atomic::{AtomicI32, Ordering::Relaxed},
1111
};
12+
use std::{
13+
fs, io,
14+
os::unix::io::{IntoRawFd as _, RawFd},
15+
};
1216

1317
/// For all platforms, we use `/dev/urandom` rather than `/dev/random`.
1418
/// For more information see the linked man pages in lib.rs.
1519
/// - On Linux, "/dev/urandom is preferred and sufficient in all use cases".
1620
/// - On Redox, only /dev/urandom is provided.
1721
/// - On AIX, /dev/urandom will "provide cryptographically secure output".
1822
/// - On Haiku and QNX Neutrino they are identical.
19-
const FILE_PATH: &[u8] = b"/dev/urandom\0";
23+
const FILE_PATH: &str = "/dev/urandom";
2024
const FD_UNINIT: i32 = i32::MIN;
2125

2226
// Do not inline this when it is the fallback implementation, but don't mark it
@@ -32,18 +36,17 @@ pub fn getrandom_inner(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
3236
// Returns the file descriptor for the device file used to retrieve random
3337
// bytes. The file will be opened exactly once. All subsequent calls will
3438
// return the same file descriptor. This file descriptor is never closed.
35-
fn get_rng_fd() -> Result<libc::c_int, Error> {
36-
const _: () = assert!(core::mem::size_of::<libc::c_int>() == core::mem::size_of::<i32>());
39+
fn get_rng_fd() -> Result<RawFd, Error> {
3740
static FD: AtomicI32 = AtomicI32::new(FD_UNINIT);
38-
fn get_fd() -> Option<libc::c_int> {
41+
fn get_fd() -> Option<RawFd> {
3942
match FD.load(Relaxed) {
4043
FD_UNINIT => None,
4144
val => Some(val),
4245
}
4346
}
4447

4548
#[cold]
46-
fn get_fd_locked() -> Result<libc::c_int, Error> {
49+
fn get_fd_locked() -> Result<RawFd, Error> {
4750
// SAFETY: We use the mutex only in this method, and we always unlock it
4851
// before returning, making sure we don't violate the pthread_mutex_t API.
4952
static MUTEX: Mutex = Mutex::new();
@@ -58,7 +61,9 @@ fn get_rng_fd() -> Result<libc::c_int, Error> {
5861
#[cfg(any(target_os = "android", target_os = "linux"))]
5962
wait_until_rng_ready()?;
6063

61-
let fd = open_readonly(FILE_PATH)?;
64+
let file = fs::File::open(FILE_PATH).map_err(map_io_error)?;
65+
66+
let fd = file.into_raw_fd();
6267
// The fd always fits in a usize without conflicting with FD_UNINIT.
6368
debug_assert!(fd >= 0);
6469
const _: () = assert!(FD_UNINIT < 0);
@@ -105,15 +110,14 @@ fn get_rng_fd() -> Result<libc::c_int, Error> {
105110
// libsodium uses `libc::poll` similarly to this.
106111
#[cfg(any(target_os = "android", target_os = "linux"))]
107112
fn wait_until_rng_ready() -> Result<(), Error> {
108-
let fd = open_readonly(b"/dev/random\0")?;
113+
use std::os::unix::io::AsRawFd as _;
114+
115+
let file = fs::File::open("/dev/random").map_err(map_io_error)?;
109116
let mut pfd = libc::pollfd {
110-
fd,
117+
fd: file.as_raw_fd(),
111118
events: libc::POLLIN,
112119
revents: 0,
113120
};
114-
let _guard = DropGuard(|| unsafe {
115-
libc::close(fd);
116-
});
117121

118122
loop {
119123
// A negative timeout means an infinite timeout.
@@ -130,6 +134,24 @@ fn wait_until_rng_ready() -> Result<(), Error> {
130134
}
131135
}
132136

137+
fn map_io_error(err: io::Error) -> Error {
138+
// TODO(MSRV feature(raw_os_error_ty)): Use `std::io::RawOsError`.
139+
type RawOsError = i32;
140+
141+
err.raw_os_error()
142+
.map_or(Error::UNEXPECTED, |errno: RawOsError| {
143+
// RawOsError-to-u32 conversion is lossless for nonnegative values
144+
// if they are the same size.
145+
const _: () =
146+
assert!(core::mem::size_of::<RawOsError>() == core::mem::size_of::<u32>());
147+
148+
match u32::try_from(errno) {
149+
Ok(code) if code != 0 => Error::from_os_error(code),
150+
_ => Error::ERRNO_NOT_POSITIVE,
151+
}
152+
})
153+
}
154+
133155
struct Mutex(UnsafeCell<libc::pthread_mutex_t>);
134156

135157
impl Mutex {

src/util_libc.rs

Lines changed: 0 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -73,33 +73,6 @@ pub fn sys_fill_exact(
7373
Ok(())
7474
}
7575

76-
/// Open a file in read-only mode.
77-
///
78-
/// # Panics
79-
/// If `path` does not contain any zeros.
80-
// TODO: Move `path` to `CStr` and use `CStr::from_bytes_until_nul` (MSRV 1.69)
81-
// or C-string literals (MSRV 1.77) for statics
82-
#[inline(always)]
83-
pub fn open_readonly(path: &[u8]) -> Result<libc::c_int, Error> {
84-
assert!(path.iter().any(|&b| b == 0));
85-
loop {
86-
let fd = unsafe {
87-
libc::open(
88-
path.as_ptr().cast::<libc::c_char>(),
89-
libc::O_RDONLY | libc::O_CLOEXEC,
90-
)
91-
};
92-
if fd >= 0 {
93-
return Ok(fd);
94-
}
95-
let err = last_os_error();
96-
// We should try again if open() was interrupted.
97-
if err.raw_os_error() != Some(libc::EINTR) {
98-
return Err(err);
99-
}
100-
}
101-
}
102-
10376
/// Thin wrapper around the `getrandom()` Linux system call
10477
#[cfg(any(target_os = "android", target_os = "linux"))]
10578
pub fn getrandom_syscall(buf: &mut [MaybeUninit<u8>]) -> libc::ssize_t {

0 commit comments

Comments
 (0)