Skip to content

Commit 5d8bbce

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 267639e commit 5d8bbce

File tree

3 files changed

+40
-44
lines changed

3 files changed

+40
-44
lines changed

.github/workflows/workspace.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ jobs:
5656
- name: SOLID (solid.rs)
5757
run: cargo clippy -Zbuild-std=core --target aarch64-kmc-solid_asp3
5858
- name: Redox (use_file.rs)
59-
run: cargo clippy -Zbuild-std=core --target x86_64-unknown-redox
59+
run: cargo clippy -Zbuild-std=std --target x86_64-unknown-redox
6060
- name: VxWorks (vxworks.rs)
6161
run: cargo clippy -Zbuild-std=core --target x86_64-wrs-vxworks
6262
- name: WASI (wasi.rs)

src/use_file.rs

+39-16
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},
1111
};
12+
use std::{
13+
fs, io,
14+
os::fd::{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,11 +35,11 @@ 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> {
38+
fn get_rng_fd() -> Result<RawFd, Error> {
3539
// std::os::fd::{BorrowedFd, OwnedFd} guarantee that -1 is not a valid file descriptor.
36-
const FD_UNINIT: libc::c_int = -1;
40+
const FD_UNINIT: RawFd = -1;
3741

38-
// In theory `libc::c_int` could be something other than `i32`, but for the
42+
// In theory `RawFd` could be something other than `i32`, but for the
3943
// targets we currently support that use `use_file`, it is always `i32`.
4044
// If/when we add support for a target where that isn't the case, we may
4145
// need to use a different atomic type or make other accomodations. The
@@ -51,15 +55,15 @@ fn get_rng_fd() -> Result<libc::c_int, Error> {
5155
// `Ordering::Acquire` to synchronize with it.
5256
static FD: AtomicI32 = AtomicI32::new(FD_UNINIT);
5357

54-
fn get_fd() -> Option<libc::c_int> {
58+
fn get_fd() -> Option<RawFd> {
5559
match FD.load(Ordering::Acquire) {
5660
FD_UNINIT => None,
5761
val => Some(val),
5862
}
5963
}
6064

6165
#[cold]
62-
fn get_fd_locked() -> Result<libc::c_int, Error> {
66+
fn get_fd_locked() -> Result<RawFd, Error> {
6367
// This mutex is used to prevent multiple threads from opening file
6468
// descriptors concurrently, which could run into the limit on the
6569
// number of open file descriptors. Our goal is to have no more than one
@@ -79,7 +83,9 @@ fn get_rng_fd() -> Result<libc::c_int, Error> {
7983
#[cfg(any(target_os = "android", target_os = "linux"))]
8084
wait_until_rng_ready()?;
8185

82-
let fd = open_readonly(FILE_PATH)?;
86+
let file = fs::File::open(FILE_PATH).map_err(map_io_error)?;
87+
88+
let fd = file.into_raw_fd();
8389
debug_assert!(fd != FD_UNINIT);
8490
FD.store(fd, Ordering::Release);
8591

@@ -124,15 +130,14 @@ fn get_rng_fd() -> Result<libc::c_int, Error> {
124130
// libsodium uses `libc::poll` similarly to this.
125131
#[cfg(any(target_os = "android", target_os = "linux"))]
126132
fn wait_until_rng_ready() -> Result<(), Error> {
127-
let fd = open_readonly(b"/dev/random\0")?;
133+
use std::os::unix::io::AsRawFd as _;
134+
135+
let file = fs::File::open("/dev/random").map_err(map_io_error)?;
128136
let mut pfd = libc::pollfd {
129-
fd,
137+
fd: file.as_raw_fd(),
130138
events: libc::POLLIN,
131139
revents: 0,
132140
};
133-
let _guard = DropGuard(|| unsafe {
134-
libc::close(fd);
135-
});
136141

137142
loop {
138143
// A negative timeout means an infinite timeout.
@@ -149,6 +154,24 @@ fn wait_until_rng_ready() -> Result<(), Error> {
149154
}
150155
}
151156

157+
fn map_io_error(err: io::Error) -> Error {
158+
// TODO(MSRV feature(raw_os_error_ty)): Use `std::io::RawOsError`.
159+
type RawOsError = i32;
160+
161+
err.raw_os_error()
162+
.map_or(Error::UNEXPECTED, |errno: RawOsError| {
163+
// RawOsError-to-u32 conversion is lossless for nonnegative values
164+
// if they are the same size.
165+
const _: () =
166+
assert!(core::mem::size_of::<RawOsError>() == core::mem::size_of::<u32>());
167+
168+
match u32::try_from(errno) {
169+
Ok(code) if code != 0 => Error::from_os_error(code),
170+
_ => Error::ERRNO_NOT_POSITIVE,
171+
}
172+
})
173+
}
174+
152175
struct Mutex(UnsafeCell<libc::pthread_mutex_t>);
153176

154177
impl Mutex {

src/util_libc.rs

-27
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)