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
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,20 +35,17 @@ 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 > {
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 > {
38
39
static FD : AtomicI32 = AtomicI32 :: new ( FD_UNINIT ) ;
39
- fn get_fd ( ) -> Option < libc :: c_int > {
40
+ fn get_fd ( ) -> Option < RawFd > {
40
41
match FD . load ( Relaxed ) {
41
42
FD_UNINIT => None ,
42
43
val => Some ( val) ,
43
44
}
44
45
}
45
46
46
47
#[ cold]
47
- fn get_fd_locked ( ) -> Result < libc :: c_int , Error > {
48
+ fn get_fd_locked ( ) -> Result < RawFd , Error > {
48
49
// SAFETY: We use the mutex only in this method, and we always unlock it
49
50
// before returning, making sure we don't violate the pthread_mutex_t API.
50
51
static MUTEX : Mutex = Mutex :: new ( ) ;
@@ -59,7 +60,9 @@ fn get_rng_fd() -> Result<libc::c_int, Error> {
59
60
#[ cfg( any( target_os = "android" , target_os = "linux" ) ) ]
60
61
wait_until_rng_ready ( ) ?;
61
62
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 ( ) ;
63
66
// The fd always fits in a usize without conflicting with FD_UNINIT.
64
67
debug_assert ! ( fd >= 0 ) ;
65
68
const _: ( ) = assert ! ( FD_UNINIT < 0 ) ;
@@ -106,15 +109,14 @@ fn get_rng_fd() -> Result<libc::c_int, Error> {
106
109
// libsodium uses `libc::poll` similarly to this.
107
110
#[ cfg( any( target_os = "android" , target_os = "linux" ) ) ]
108
111
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) ?;
110
115
let mut pfd = libc:: pollfd {
111
- fd,
116
+ fd : file . as_raw_fd ( ) ,
112
117
events : libc:: POLLIN ,
113
118
revents : 0 ,
114
119
} ;
115
- let _guard = DropGuard ( || unsafe {
116
- libc:: close ( fd) ;
117
- } ) ;
118
120
119
121
loop {
120
122
// A negative timeout means an infinite timeout.
@@ -131,6 +133,24 @@ fn wait_until_rng_ready() -> Result<(), Error> {
131
133
}
132
134
}
133
135
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
+
134
154
struct Mutex ( UnsafeCell < libc:: pthread_mutex_t > ) ;
135
155
136
156
impl Mutex {
0 commit comments