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 :: Relaxed } ,
11
11
} ;
12
+ use std:: {
13
+ fs, io,
14
+ os:: unix:: io:: { 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
const FD_UNINIT : i32 = i32:: MIN ;
21
25
22
26
// 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> {
32
36
// Returns the file descriptor for the device file used to retrieve random
33
37
// bytes. The file will be opened exactly once. All subsequent calls will
34
38
// 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 > {
37
40
static FD : AtomicI32 = AtomicI32 :: new ( FD_UNINIT ) ;
38
- fn get_fd ( ) -> Option < libc :: c_int > {
41
+ fn get_fd ( ) -> Option < RawFd > {
39
42
match FD . load ( Relaxed ) {
40
43
FD_UNINIT => None ,
41
44
val => Some ( val) ,
42
45
}
43
46
}
44
47
45
48
#[ cold]
46
- fn get_fd_locked ( ) -> Result < libc :: c_int , Error > {
49
+ fn get_fd_locked ( ) -> Result < RawFd , Error > {
47
50
// SAFETY: We use the mutex only in this method, and we always unlock it
48
51
// before returning, making sure we don't violate the pthread_mutex_t API.
49
52
static MUTEX : Mutex = Mutex :: new ( ) ;
@@ -58,7 +61,9 @@ fn get_rng_fd() -> Result<libc::c_int, Error> {
58
61
#[ cfg( any( target_os = "android" , target_os = "linux" ) ) ]
59
62
wait_until_rng_ready ( ) ?;
60
63
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 ( ) ;
62
67
// The fd always fits in a usize without conflicting with FD_UNINIT.
63
68
debug_assert ! ( fd >= 0 ) ;
64
69
const _: ( ) = assert ! ( FD_UNINIT < 0 ) ;
@@ -105,15 +110,14 @@ fn get_rng_fd() -> Result<libc::c_int, Error> {
105
110
// libsodium uses `libc::poll` similarly to this.
106
111
#[ cfg( any( target_os = "android" , target_os = "linux" ) ) ]
107
112
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) ?;
109
116
let mut pfd = libc:: pollfd {
110
- fd,
117
+ fd : file . as_raw_fd ( ) ,
111
118
events : libc:: POLLIN ,
112
119
revents : 0 ,
113
120
} ;
114
- let _guard = DropGuard ( || unsafe {
115
- libc:: close ( fd) ;
116
- } ) ;
117
121
118
122
loop {
119
123
// A negative timeout means an infinite timeout.
@@ -130,6 +134,24 @@ fn wait_until_rng_ready() -> Result<(), Error> {
130
134
}
131
135
}
132
136
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
+
133
155
struct Mutex ( UnsafeCell < libc:: pthread_mutex_t > ) ;
134
156
135
157
impl Mutex {
0 commit comments