1
1
//! 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 } ;
6
6
use core:: {
7
7
cell:: UnsafeCell ,
8
8
ffi:: c_void,
9
9
mem:: MaybeUninit ,
10
10
sync:: atomic:: { AtomicI32 , Ordering } ,
11
11
} ;
12
+ use std:: {
13
+ fs, io,
14
+ os:: fd:: { IntoRawFd as _, RawFd } ,
15
+ } ;
12
16
13
17
/// For all platforms, we use `/dev/urandom` rather than `/dev/random`.
14
18
/// For more information see the linked man pages in lib.rs.
15
19
/// - On Linux, "/dev/urandom is preferred and sufficient in all use cases".
16
20
/// - On Redox, only /dev/urandom is provided.
17
21
/// - On AIX, /dev/urandom will "provide cryptographically secure output".
18
22
/// - On Haiku and QNX Neutrino they are identical.
19
- const FILE_PATH : & [ u8 ] = b "/dev/urandom\0 ";
23
+ const FILE_PATH : & str = "/dev/urandom" ;
20
24
21
25
// Do not inline this when it is the fallback implementation, but don't mark it
22
26
// `#[cold]` because it is hot when it is actually used.
@@ -31,11 +35,11 @@ pub fn getrandom_inner(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
31
35
// Returns the file descriptor for the device file used to retrieve random
32
36
// bytes. The file will be opened exactly once. All subsequent calls will
33
37
// 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 > {
35
39
// 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 ;
37
41
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
39
43
// targets we currently support that use `use_file`, it is always `i32`.
40
44
// If/when we add support for a target where that isn't the case, we may
41
45
// 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> {
51
55
// `Ordering::Acquire` to synchronize with it.
52
56
static FD : AtomicI32 = AtomicI32 :: new ( FD_UNINIT ) ;
53
57
54
- fn get_fd ( ) -> Option < libc :: c_int > {
58
+ fn get_fd ( ) -> Option < RawFd > {
55
59
match FD . load ( Ordering :: Acquire ) {
56
60
FD_UNINIT => None ,
57
61
val => Some ( val) ,
58
62
}
59
63
}
60
64
61
65
#[ cold]
62
- fn get_fd_locked ( ) -> Result < libc :: c_int , Error > {
66
+ fn get_fd_locked ( ) -> Result < RawFd , Error > {
63
67
// This mutex is used to prevent multiple threads from opening file
64
68
// descriptors concurrently, which could run into the limit on the
65
69
// 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> {
79
83
#[ cfg( any( target_os = "android" , target_os = "linux" ) ) ]
80
84
wait_until_rng_ready ( ) ?;
81
85
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 ( ) ;
83
89
debug_assert ! ( fd != FD_UNINIT ) ;
84
90
FD . store ( fd, Ordering :: Release ) ;
85
91
@@ -124,15 +130,14 @@ fn get_rng_fd() -> Result<libc::c_int, Error> {
124
130
// libsodium uses `libc::poll` similarly to this.
125
131
#[ cfg( any( target_os = "android" , target_os = "linux" ) ) ]
126
132
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) ?;
128
136
let mut pfd = libc:: pollfd {
129
- fd,
137
+ fd : file . as_raw_fd ( ) ,
130
138
events : libc:: POLLIN ,
131
139
revents : 0 ,
132
140
} ;
133
- let _guard = DropGuard ( || unsafe {
134
- libc:: close ( fd) ;
135
- } ) ;
136
141
137
142
loop {
138
143
// A negative timeout means an infinite timeout.
@@ -149,6 +154,24 @@ fn wait_until_rng_ready() -> Result<(), Error> {
149
154
}
150
155
}
151
156
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
+
152
175
struct Mutex ( UnsafeCell < libc:: pthread_mutex_t > ) ;
153
176
154
177
impl Mutex {
0 commit comments