Skip to content

Commit ff1fca4

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 1653188 commit ff1fca4

File tree

2 files changed

+37
-44
lines changed

2 files changed

+37
-44
lines changed

src/use_file.rs

Lines changed: 37 additions & 17 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

2125
// Do not inline this when it is the fallback implementation, but don't mark it
2226
// `#[cold]` because it is hot when it is actually used.
@@ -31,20 +35,17 @@ pub fn getrandom_inner(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
3135
// Returns the file descriptor for the device file used to retrieve random
3236
// bytes. The file will be opened exactly once. All subsequent calls will
3337
// return the same file descriptor. This file descriptor is never closed.
34-
fn get_rng_fd() -> Result<libc::c_int, Error> {
35-
const FD_UNINIT: i32 = -1; // libstd guarantees -1 is not a valid file descriptor value.
36-
37-
const _: () = assert!(core::mem::size_of::<libc::c_int>() == core::mem::size_of::<i32>());
38+
fn get_rng_fd() -> Result<RawFd, Error> {
3839
static FD: AtomicI32 = AtomicI32::new(FD_UNINIT);
39-
fn get_fd() -> Option<libc::c_int> {
40+
fn get_fd() -> Option<RawFd> {
4041
match FD.load(Relaxed) {
4142
FD_UNINIT => None,
4243
val => Some(val),
4344
}
4445
}
4546

4647
#[cold]
47-
fn get_fd_locked() -> Result<libc::c_int, Error> {
48+
fn get_fd_locked() -> Result<RawFd, Error> {
4849
// SAFETY: We use the mutex only in this method, and we always unlock it
4950
// before returning, making sure we don't violate the pthread_mutex_t API.
5051
static MUTEX: Mutex = Mutex::new();
@@ -59,7 +60,9 @@ fn get_rng_fd() -> Result<libc::c_int, Error> {
5960
#[cfg(any(target_os = "android", target_os = "linux"))]
6061
wait_until_rng_ready()?;
6162

62-
let fd = open_readonly(FILE_PATH)?;
63+
let file = fs::File::open(FILE_PATH).map_err(map_io_error)?;
64+
65+
let fd = file.into_raw_fd();
6366
// The fd always fits in a usize without conflicting with FD_UNINIT.
6467
debug_assert!(fd >= 0);
6568
const _: () = assert!(FD_UNINIT < 0);
@@ -106,15 +109,14 @@ fn get_rng_fd() -> Result<libc::c_int, Error> {
106109
// libsodium uses `libc::poll` similarly to this.
107110
#[cfg(any(target_os = "android", target_os = "linux"))]
108111
fn wait_until_rng_ready() -> Result<(), Error> {
109-
let fd = open_readonly(b"/dev/random\0")?;
112+
use std::os::unix::io::AsRawFd as _;
113+
114+
let file = fs::File::open("/dev/random").map_err(map_io_error)?;
110115
let mut pfd = libc::pollfd {
111-
fd,
116+
fd: file.as_raw_fd(),
112117
events: libc::POLLIN,
113118
revents: 0,
114119
};
115-
let _guard = DropGuard(|| unsafe {
116-
libc::close(fd);
117-
});
118120

119121
loop {
120122
// A negative timeout means an infinite timeout.
@@ -131,6 +133,24 @@ fn wait_until_rng_ready() -> Result<(), Error> {
131133
}
132134
}
133135

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

136156
impl Mutex {

src/util_libc.rs

Lines changed: 0 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -72,30 +72,3 @@ pub fn sys_fill_exact(
7272
}
7373
Ok(())
7474
}
75-
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-
}

0 commit comments

Comments
 (0)