Skip to content

Commit 1426f2e

Browse files
committed
Remove libstd for opening/reading files
1 parent 0931408 commit 1426f2e

File tree

2 files changed

+52
-19
lines changed

2 files changed

+52
-19
lines changed

src/use_file.rs

+34-19
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,13 @@
99
//! Implementations that just need to read from a file
1010
extern crate std;
1111

12-
use crate::util_libc::{last_os_error, LazyFd};
12+
use crate::util_libc::{last_os_error, open_readonly, sys_fill_exact, LazyFd};
1313
use crate::Error;
14-
use core::mem::ManuallyDrop;
15-
use std::os::unix::io::{FromRawFd, IntoRawFd, RawFd};
16-
use std::{fs::File, io::Read};
1714

1815
#[cfg(target_os = "redox")]
19-
const FILE_PATH: &str = "rand:";
16+
const FILE_PATH: &str = "rand:\0";
2017
#[cfg(any(target_os = "android", target_os = "linux", target_os = "netbsd"))]
21-
const FILE_PATH: &str = "/dev/urandom";
18+
const FILE_PATH: &str = "/dev/urandom\0";
2219
#[cfg(any(
2320
target_os = "dragonfly",
2421
target_os = "emscripten",
@@ -27,32 +24,50 @@ const FILE_PATH: &str = "/dev/urandom";
2724
target_os = "solaris",
2825
target_os = "illumos"
2926
))]
30-
const FILE_PATH: &str = "/dev/random";
27+
const FILE_PATH: &str = "/dev/random\0";
3128

3229
pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
3330
static FD: LazyFd = LazyFd::new();
3431
let fd = FD.init(init_file).ok_or(last_os_error())?;
35-
let file = ManuallyDrop::new(unsafe { File::from_raw_fd(fd) });
36-
let mut file_ref: &File = &file;
32+
let read = |buf: &mut [u8]| unsafe { libc::read(fd, buf.as_mut_ptr() as *mut _, buf.len()) };
3733

3834
if cfg!(target_os = "emscripten") {
3935
// `Crypto.getRandomValues` documents `dest` should be at most 65536 bytes.
4036
for chunk in dest.chunks_mut(65536) {
41-
file_ref.read_exact(chunk)?;
37+
sys_fill_exact(chunk, read)?;
4238
}
4339
} else {
44-
file_ref.read_exact(dest)?;
40+
sys_fill_exact(dest, read)?;
4541
}
4642
Ok(())
4743
}
4844

49-
fn init_file() -> Option<RawFd> {
50-
if FILE_PATH == "/dev/urandom" {
51-
// read one byte from "/dev/random" to ensure that OS RNG has initialized
52-
File::open("/dev/random")
53-
.ok()?
54-
.read_exact(&mut [0u8; 1])
55-
.ok()?;
45+
fn init_file() -> Option<libc::c_int> {
46+
if FILE_PATH == "/dev/urandom\0" {
47+
// Poll /dev/random to make sure it is ok to read from /dev/urandom.
48+
let mut pfd = libc::pollfd {
49+
fd: unsafe { open_readonly("/dev/random\0")? },
50+
events: libc::POLLIN,
51+
revents: 0,
52+
};
53+
54+
let mut res = -1;
55+
while res <= 0 {
56+
// A negative timeout means an infinite timeout.
57+
res = unsafe { libc::poll(&mut pfd, 1, -1) };
58+
if res < 0 {
59+
match last_os_error().raw_os_error() {
60+
Some(libc::EINTR) | Some(libc::EAGAIN) => {}
61+
_ => break,
62+
}
63+
}
64+
}
65+
66+
unsafe { libc::close(pfd.fd) };
67+
if res != 1 {
68+
// We either hard failed, or poll() returned the wrong pfd.
69+
return None;
70+
}
5671
}
57-
Some(File::open(FILE_PATH).ok()?.into_raw_fd())
72+
unsafe { open_readonly(FILE_PATH) }
5873
}

src/util_libc.rs

+18
Original file line numberDiff line numberDiff line change
@@ -121,3 +121,21 @@ impl LazyFd {
121121
}
122122
}
123123
}
124+
125+
cfg_if! {
126+
if #[cfg(any(target_os = "linux", target_os = "emscripten", target_os = "l4re"))] {
127+
use libc::open64 as open;
128+
} else {
129+
use libc::open;
130+
}
131+
}
132+
133+
// SAFETY: path must be null terminated, FD must be manually closed.
134+
pub unsafe fn open_readonly(path: &str) -> Option<libc::c_int> {
135+
let fd = open(path.as_ptr() as *mut _, libc::O_RDONLY | libc::O_CLOEXEC);
136+
if fd < 0 {
137+
None
138+
} else {
139+
Some(fd)
140+
}
141+
}

0 commit comments

Comments
 (0)