diff --git a/.travis.yml b/.travis.yml index 41aa192..e11aaa4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -37,6 +37,9 @@ matrix: - rm -rf target/doc - cargo doc --no-deps --all --all-features - cargo deadlinks --dir target/doc + # also test minimum dependency versions are usable + - cargo generate-lockfile -Z minimal-versions + - cargo test - rust: nightly os: osx @@ -52,6 +55,9 @@ matrix: - rm -rf target/doc - cargo doc --no-deps --all --all-features - cargo deadlinks --dir target/doc + # also test minimum dependency versions are usable + - cargo generate-lockfile -Z minimal-versions + - cargo test - rust: nightly env: DESCRIPTION="WASM via emscripten, stdweb and wasm-bindgen" @@ -97,6 +103,14 @@ matrix: #- cargo build --target=x86_64-unknown-fuchsia --all-features - cargo build --target=x86_64-unknown-netbsd --all-features - cargo build --target=x86_64-unknown-redox --all-features + # also test minimum dependency versions are usable + - cargo generate-lockfile -Z minimal-versions + - cargo build --target=x86_64-sun-solaris --all-features + - cargo build --target=x86_64-unknown-cloudabi --all-features + - cargo build --target=x86_64-unknown-freebsd --all-features + #- cargo build --target=x86_64-unknown-fuchsia --all-features + - cargo build --target=x86_64-unknown-netbsd --all-features + - cargo build --target=x86_64-unknown-redox --all-features # Trust cross-built/emulated targets. We must repeat all non-default values. - rust: stable diff --git a/Cargo.toml b/Cargo.toml index 7109397..99e1dab 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,11 +14,15 @@ members = [ "tests/wasm_bindgen", ] +[dependencies] +log = { version = "0.4", optional = true } + [target.'cfg(unix)'.dependencies] -libc = "0.2" +# In general, we need at least 0.2.27. On Solaris, we need some unknown newer version. +libc = "0.2.50" [target.'cfg(windows)'.dependencies] -winapi = { version = "0.3", features = ["minwindef", "ntsecapi", "winnt"] } +winapi = { version = "0.3.6", features = ["minwindef", "ntsecapi", "winnt"] } [target.'cfg(target_os = "cloudabi")'.dependencies] cloudabi = "0.0.3" @@ -27,5 +31,5 @@ cloudabi = "0.0.3" fuchsia-cprng = "0.1" [target.wasm32-unknown-unknown.dependencies] -wasm-bindgen = { version = "0.2.12", optional = true } -stdweb = { version = "0.4", optional = true } +wasm-bindgen = { version = "0.2.29", optional = true } +stdweb = { version = "0.4.9", optional = true } diff --git a/README.md b/README.md index 4330a17..6d56630 100644 --- a/README.md +++ b/README.md @@ -38,6 +38,9 @@ fn get_random_buf() -> Result<[u8; 32], getrandom::Error> { This library is `no_std` compatible on SGX but requires `std` on most platforms. +The `log` library is supported as an optional dependency. If enabled, error +reporting will be improved on some platforms. + For WebAssembly (`wasm32`), Enscripten targets are supported directly; otherwise one of the following features must be enabled: diff --git a/src/cloudabi.rs b/src/cloudabi.rs index 1230f31..fc5f49d 100644 --- a/src/cloudabi.rs +++ b/src/cloudabi.rs @@ -11,7 +11,7 @@ extern crate cloudabi; use core::num::NonZeroU32; -use error::Error; +use Error; pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { let errno = unsafe { cloudabi::random_get(dest) }; @@ -19,6 +19,10 @@ pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { Ok(()) } else { let code = NonZeroU32::new(errno as u32).unwrap(); + error!("cloudabi::random_get syscall failed with code {}", code); Err(Error::from(code)) } } + +#[inline(always)] +pub fn error_msg_inner(_: NonZeroU32) -> Option<&'static str> { None } diff --git a/src/dragonfly_haiku.rs b/src/dragonfly_haiku.rs index 751266b..8b8b947 100644 --- a/src/dragonfly_haiku.rs +++ b/src/dragonfly_haiku.rs @@ -7,11 +7,12 @@ // except according to those terms. //! Implementation for DragonFly / Haiku -use super::Error; -use super::utils::use_init; +use Error; +use utils::use_init; use std::fs::File; use std::io::Read; use std::cell::RefCell; +use std::num::NonZeroU32; thread_local!(static RNG_FILE: RefCell> = RefCell::new(None)); @@ -23,3 +24,6 @@ pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { ) }) } + +#[inline(always)] +pub fn error_msg_inner(_: NonZeroU32) -> Option<&'static str> { None } diff --git a/src/dummy.rs b/src/dummy.rs index 96acb91..12814a7 100644 --- a/src/dummy.rs +++ b/src/dummy.rs @@ -7,9 +7,14 @@ // except according to those terms. //! A dummy implementation for unsupported targets which always returns -//! `Err(UNAVAILABLE_ERROR)` -use super::UNAVAILABLE_ERROR; +//! `Err(ERROR_UNAVAILABLE)` +use std::num::NonZeroU32; +use {Error, ERROR_UNAVAILABLE}; -pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { - Err(UNAVAILABLE_ERROR) +pub fn getrandom_inner(_: &mut [u8]) -> Result<(), Error> { + error!("no support for this platform"); + Err(ERROR_UNAVAILABLE) } + +#[inline(always)] +pub fn error_msg_inner(_: NonZeroU32) -> Option<&'static str> { None } diff --git a/src/emscripten.rs b/src/emscripten.rs index dd98985..471fc68 100644 --- a/src/emscripten.rs +++ b/src/emscripten.rs @@ -7,11 +7,12 @@ // except according to those terms. //! Implementation for Emscripten -use super::Error; +use Error; use std::fs::File; use std::io::Read; use std::cell::RefCell; -use super::utils::use_init; +use std::num::NonZeroU32; +use utils::use_init; thread_local!(static RNG_FILE: RefCell> = RefCell::new(None)); @@ -29,3 +30,6 @@ pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { }) }) } + +#[inline(always)] +pub fn error_msg_inner(_: NonZeroU32) -> Option<&'static str> { None } diff --git a/src/error.rs b/src/error.rs index 43a03a6..9639478 100644 --- a/src/error.rs +++ b/src/error.rs @@ -12,20 +12,29 @@ use core::fmt; #[cfg(not(target_env = "sgx"))] use std::{io, error}; +// A randomly-chosen 16-bit prefix for our codes +pub(crate) const CODE_PREFIX: u32 = 0x57f40000; +const CODE_UNKNOWN: u32 = CODE_PREFIX | 0; +const CODE_UNAVAILABLE: u32 = CODE_PREFIX | 1; + /// An unknown error. -pub const UNKNOWN_ERROR: Error = Error(unsafe { - NonZeroU32::new_unchecked(0x756e6b6e) // "unkn" +/// +/// This is the following constant: 57F40000 (hex) / 1475608576 (decimal). +pub const ERROR_UNKNOWN: Error = Error(unsafe { + NonZeroU32::new_unchecked(CODE_UNKNOWN) }); /// No generator is available. -pub const UNAVAILABLE_ERROR: Error = Error(unsafe { - NonZeroU32::new_unchecked(0x4e416e61) // "NAna" +/// +/// This is the following constant: 57F40001 (hex) / 1475608577 (decimal). +pub const ERROR_UNAVAILABLE: Error = Error(unsafe { + NonZeroU32::new_unchecked(CODE_UNAVAILABLE) }); /// The error type. /// /// This type is small and no-std compatible. -#[derive(Copy, Clone, Debug, Eq, PartialEq)] +#[derive(Copy, Clone, Eq, PartialEq)] pub struct Error(NonZeroU32); impl Error { @@ -38,14 +47,34 @@ impl Error { pub fn code(&self) -> NonZeroU32 { self.0 } + + fn msg(&self) -> Option<&'static str> { + if let Some(msg) = super::error_msg_inner(self.0) { + Some(msg) + } else { + match *self { + ERROR_UNKNOWN => Some("getrandom: unknown error"), + ERROR_UNAVAILABLE => Some("getrandom: unavailable"), + _ => None + } + } + } +} + +impl fmt::Debug for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + match self.msg() { + Some(msg) => write!(f, "Error(\"{}\")", msg), + None => write!(f, "Error(0x{:08X})", self.0), + } + } } impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - match *self { - UNKNOWN_ERROR => write!(f, "Getrandom Error: unknown"), - UNAVAILABLE_ERROR => write!(f, "Getrandom Error: unavailable"), - code => write!(f, "Getrandom Error: {}", code.0.get()), + match self.msg() { + Some(msg) => write!(f, "{}", msg), + None => write!(f, "getrandom: unknown code 0x{:08X}", self.0), } } } @@ -63,22 +92,31 @@ impl From for Error { .and_then(|code| NonZeroU32::new(code as u32)) .map(|code| Error(code)) // in practice this should never happen - .unwrap_or(UNKNOWN_ERROR) + .unwrap_or(ERROR_UNKNOWN) } } #[cfg(not(target_env = "sgx"))] impl From for io::Error { fn from(err: Error) -> Self { - match err { - UNKNOWN_ERROR => io::Error::new(io::ErrorKind::Other, - "getrandom error: unknown"), - UNAVAILABLE_ERROR => io::Error::new(io::ErrorKind::Other, - "getrandom error: entropy source is unavailable"), - code => io::Error::from_raw_os_error(code.0.get() as i32), + match err.msg() { + Some(msg) => io::Error::new(io::ErrorKind::Other, msg), + None => io::Error::from_raw_os_error(err.0.get() as i32), } } } #[cfg(not(target_env = "sgx"))] impl error::Error for Error { } + +#[cfg(test)] +mod tests { + use std::mem::size_of; + use super::Error; + + #[test] + fn test_size() { + assert_eq!(size_of::(), 4); + assert_eq!(size_of::>(), 4); + } +} diff --git a/src/freebsd.rs b/src/freebsd.rs index 9756d1b..fcad6e5 100644 --- a/src/freebsd.rs +++ b/src/freebsd.rs @@ -9,9 +9,10 @@ //! Implementation for FreeBSD extern crate libc; -use super::Error; +use Error; use core::ptr; use std::io; +use std::num::NonZeroU32; pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { let mib = [libc::CTL_KERN, libc::KERN_ARND]; @@ -25,8 +26,12 @@ pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { ) }; if ret == -1 || len != chunk.len() { + error!("freebsd: kern.arandom syscall failed"); return Err(io::Error::last_os_error().into()); } } Ok(()) } + +#[inline(always)] +pub fn error_msg_inner(_: NonZeroU32) -> Option<&'static str> { None } diff --git a/src/fuchsia.rs b/src/fuchsia.rs index 39741eb..59defc0 100644 --- a/src/fuchsia.rs +++ b/src/fuchsia.rs @@ -9,9 +9,13 @@ //! Implementation for Fuchsia Zircon extern crate fuchsia_cprng; -use super::Error; +use std::num::NonZeroU32; +use Error; pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { fuchsia_cprng::cprng_draw(dest); Ok(()) } + +#[inline(always)] +pub fn error_msg_inner(_: NonZeroU32) -> Option<&'static str> { None } diff --git a/src/lib.rs b/src/lib.rs index b697744..9d6baac 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -111,6 +111,10 @@ extern crate wasm_bindgen; feature = "stdweb"))] #[macro_use] extern crate stdweb; +#[cfg(feature = "log")] #[macro_use] extern crate log; +#[allow(unused)] +#[cfg(not(feature = "log"))] macro_rules! error { ($($x:tt)*) => () } + #[cfg(any( target_os = "android", target_os = "netbsd", @@ -124,8 +128,7 @@ extern crate wasm_bindgen; ))] mod utils; mod error; -pub use error::{Error, UNKNOWN_ERROR, UNAVAILABLE_ERROR}; - +pub use error::{Error, ERROR_UNKNOWN, ERROR_UNAVAILABLE}; // System-specific implementations. // @@ -136,7 +139,7 @@ macro_rules! mod_use { #[$cond] mod $module; #[$cond] - use $module::getrandom_inner; + use $module::{getrandom_inner, error_msg_inner}; } } @@ -221,7 +224,7 @@ mod_use!( /// In general, `getrandom` will be fast enough for interactive usage, though /// significantly slower than a user-space CSPRNG; for the latter consider /// [`rand::thread_rng`](https://docs.rs/rand/*/rand/fn.thread_rng.html). -pub fn getrandom(dest: &mut [u8]) -> Result<(), Error> { +pub fn getrandom(dest: &mut [u8]) -> Result<(), error::Error> { getrandom_inner(dest) } diff --git a/src/linux_android.rs b/src/linux_android.rs index 4bad074..51702c9 100644 --- a/src/linux_android.rs +++ b/src/linux_android.rs @@ -9,12 +9,13 @@ //! Implementation for Linux / Android extern crate libc; -use super::Error; -use super::utils::use_init; +use Error; +use utils::use_init; use std::fs::File; use std::io; use std::io::Read; use std::cell::RefCell; +use std::num::NonZeroU32; use std::sync::atomic::{AtomicBool, Ordering}; static RNG_INIT: AtomicBool = AtomicBool::new(false); @@ -33,6 +34,7 @@ fn syscall_getrandom(dest: &mut [u8]) -> Result<(), io::Error> { libc::syscall(libc::SYS_getrandom, dest.as_mut_ptr(), dest.len(), 0) }; if ret < 0 || (ret as usize) != dest.len() { + error!("Linux getrandom syscall failed with return value {}", ret); return Err(io::Error::last_os_error()); } Ok(()) @@ -80,3 +82,6 @@ fn is_getrandom_available() -> bool { AVAILABLE.load(Ordering::Relaxed) } + +#[inline(always)] +pub fn error_msg_inner(_: NonZeroU32) -> Option<&'static str> { None } diff --git a/src/macos.rs b/src/macos.rs index fb89fb1..776e2a9 100644 --- a/src/macos.rs +++ b/src/macos.rs @@ -9,8 +9,9 @@ //! Implementation for MacOS / iOS extern crate libc; -use super::Error; +use Error; use std::io; +use std::num::NonZeroU32; use self::libc::{c_int, size_t}; enum SecRandom {} @@ -35,8 +36,12 @@ pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { ) }; if ret == -1 { + error!("SecRandomCopyBytes call failed"); Err(io::Error::last_os_error().into()) } else { Ok(()) } } + +#[inline(always)] +pub fn error_msg_inner(_: NonZeroU32) -> Option<&'static str> { None } diff --git a/src/netbsd.rs b/src/netbsd.rs index 089272a..a3a4aee 100644 --- a/src/netbsd.rs +++ b/src/netbsd.rs @@ -8,11 +8,12 @@ //! Implementation for NetBSD -use super::Error; -use super::utils::use_init; +use Error; +use utils::use_init; use std::fs::File; use std::io::Read; use std::cell::RefCell; +use std::num::NonZeroU32; use std::sync::atomic::{AtomicBool, Ordering}; static RNG_INIT: AtomicBool = AtomicBool::new(false); @@ -32,3 +33,6 @@ pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { }, |f| f.read_exact(dest).map_err(From::from)) }) } + +#[inline(always)] +pub fn error_msg_inner(_: NonZeroU32) -> Option<&'static str> { None } diff --git a/src/openbsd_bitrig.rs b/src/openbsd_bitrig.rs index abdea21..fa80bb5 100644 --- a/src/openbsd_bitrig.rs +++ b/src/openbsd_bitrig.rs @@ -9,8 +9,9 @@ //! Implementation for OpenBSD / Bitrig extern crate libc; -use super::Error; +use Error; use std::io; +use std::num::NonZeroU32; pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { for chunk in dest.chunks_mut(256) { @@ -21,8 +22,12 @@ pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { ) }; if ret == -1 { + error!("libc::getentropy call failed"); return Err(io::Error::last_os_error().into()); } } Ok(()) } + +#[inline(always)] +pub fn error_msg_inner(_: NonZeroU32) -> Option<&'static str> { None } diff --git a/src/redox.rs b/src/redox.rs index 2302666..6321fea 100644 --- a/src/redox.rs +++ b/src/redox.rs @@ -7,11 +7,12 @@ // except according to those terms. //! Implementation for Redox -use super::Error; -use super::utils::use_init; +use Error; +use utils::use_init; use std::fs::File; use std::io::Read; use std::cell::RefCell; +use std::num::NonZeroU32; thread_local!(static RNG_FILE: RefCell> = RefCell::new(None)); @@ -23,3 +24,6 @@ pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { ) }).map_err(From::from) } + +#[inline(always)] +pub fn error_msg_inner(_: NonZeroU32) -> Option<&'static str> { None } diff --git a/src/sgx.rs b/src/sgx.rs index 7517d1f..7afd100 100644 --- a/src/sgx.rs +++ b/src/sgx.rs @@ -7,10 +7,11 @@ // except according to those terms. //! Implementation for SGX using RDRAND instruction -use super::{Error, UNKNOWN_ERROR}; +use {Error, ERROR_UNKNOWN}; use core::{mem, ptr}; use core::arch::x86_64::_rdrand64_step; +use core::num::NonZeroU32; #[cfg(not(target_feature = "rdrand"))] compile_error!("enable rdrand target feature!"); @@ -26,7 +27,7 @@ fn get_rand_u64() -> Result { } }; } - Err(UNKNOWN_ERROR) + Err(ERROR_UNKNOWN) } pub fn getrandom_inner(mut dest: &mut [u8]) -> Result<(), Error> { @@ -46,3 +47,6 @@ pub fn getrandom_inner(mut dest: &mut [u8]) -> Result<(), Error> { } Ok(()) } + +#[inline(always)] +pub fn error_msg_inner(_: NonZeroU32) -> Option<&'static str> { None } diff --git a/src/solarish.rs b/src/solarish.rs index 8a84fd2..ec9cff1 100644 --- a/src/solarish.rs +++ b/src/solarish.rs @@ -19,11 +19,12 @@ //! libc::dlsym. extern crate libc; -use super::Error; +use Error; use std::cell::RefCell; use std::fs::File; use std::io; use std::io::Read; +use std::num::NonZeroU32; use utils::use_init; #[cfg(target_os = "illumos")] @@ -44,6 +45,7 @@ fn libc_getrandom(rand: GetRandomFn, dest: &mut [u8]) -> Result<(), Error> { let ret = unsafe { rand(dest.as_mut_ptr(), dest.len(), 0) as libc::ssize_t }; if ret == -1 || ret != dest.len() as libc::ssize_t { + error!("getrandom syscall failed with ret={}", ret); Err(io::Error::last_os_error().into()) } else { Ok(()) @@ -97,3 +99,6 @@ fn fetch_getrandom() -> Option { let ptr = FPTR.load(Ordering::SeqCst); unsafe { mem::transmute::>(ptr) } } + +#[inline(always)] +pub fn error_msg_inner(_: NonZeroU32) -> Option<&'static str> { None } diff --git a/src/utils.rs b/src/utils.rs index 5b70bd1..d7722c0 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -5,7 +5,7 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. -use super::Error; +use Error; use core::cell::RefCell; use core::ops::DerefMut; diff --git a/src/wasm32_bindgen.rs b/src/wasm32_bindgen.rs index 3f04d32..11e2f82 100644 --- a/src/wasm32_bindgen.rs +++ b/src/wasm32_bindgen.rs @@ -10,13 +10,17 @@ use std::cell::RefCell; use std::mem; +use std::num::NonZeroU32; use wasm_bindgen::prelude::*; -use super::__wbg_shims::*; -use super::{Error, UNAVAILABLE_ERROR}; -use super::utils::use_init; +use __wbg_shims::*; +use Error; +use utils::use_init; +const CODE_PREFIX: u32 = ::error::CODE_PREFIX | 0x8e00; +const CODE_CRYPTO_UNDEF: u32 = CODE_PREFIX | 1; +const CODE_GRV_UNDEF: u32 = CODE_PREFIX | 2; #[derive(Clone, Debug)] pub enum RngSource { @@ -75,18 +79,29 @@ fn getrandom_init() -> Result { // we're in an older web browser and the OS RNG isn't available. let crypto = this.crypto(); if crypto.is_undefined() { - let msg = "self.crypto is undefined"; - return Err(UNAVAILABLE_ERROR) // TODO: report msg + return Err(Error::from(unsafe { + NonZeroU32::new_unchecked(CODE_CRYPTO_UNDEF) + })); } // Test if `crypto.getRandomValues` is undefined as well let crypto: BrowserCrypto = crypto.into(); if crypto.get_random_values_fn().is_undefined() { - let msg = "crypto.getRandomValues is undefined"; - return Err(UNAVAILABLE_ERROR) // TODO: report msg + return Err(Error::from(unsafe { + NonZeroU32::new_unchecked(CODE_GRV_UNDEF) + })); } // Ok! `self.crypto.getRandomValues` is a defined value, so let's // assume we can do browser crypto. Ok(RngSource::Browser(crypto)) } + +#[inline(always)] +pub fn error_msg_inner(n: NonZeroU32) -> Option<&'static str> { + match n.get() { + CODE_CRYPTO_UNDEF => Some("getrandom: self.crypto is undefined"), + CODE_GRV_UNDEF => Some("crypto.getRandomValues is undefined"), + _ => None + } +} diff --git a/src/wasm32_stdweb.rs b/src/wasm32_stdweb.rs index 2606eaa..7cf4279 100644 --- a/src/wasm32_stdweb.rs +++ b/src/wasm32_stdweb.rs @@ -10,12 +10,13 @@ use std::cell::RefCell; use std::mem; +use std::num::NonZeroU32; use stdweb::unstable::TryInto; use stdweb::web::error::Error as WebError; -use super::{Error, UNAVAILABLE_ERROR, UNKNOWN_ERROR}; -use super::utils::use_init; +use {Error, ERROR_UNAVAILABLE, ERROR_UNKNOWN}; +use utils::use_init; #[derive(Clone, Debug)] enum RngSource { @@ -65,7 +66,8 @@ fn getrandom_init() -> Result { else { unreachable!() } } else { let err: WebError = js!{ return @{ result }.error }.try_into().unwrap(); - Err(UNAVAILABLE_ERROR) // TODO: forward err + error!("getrandom unavailable: {}", err); + Err(ERROR_UNAVAILABLE) } } @@ -100,8 +102,12 @@ fn getrandom_fill(source: &mut RngSource, dest: &mut [u8]) -> Result<(), Error> if js!{ return @{ result.as_ref() }.success } != true { let err: WebError = js!{ return @{ result }.error }.try_into().unwrap(); - return Err(UNKNOWN_ERROR) // TODO: forward err + error!("getrandom failed: {}", err); + return Err(ERROR_UNKNOWN) } } Ok(()) } + +#[inline(always)] +pub fn error_msg_inner(_: NonZeroU32) -> Option<&'static str> { None } diff --git a/src/windows.rs b/src/windows.rs index 1063bdd..5055783 100644 --- a/src/windows.rs +++ b/src/windows.rs @@ -13,12 +13,19 @@ use self::winapi::shared::minwindef::ULONG; use self::winapi::um::ntsecapi::RtlGenRandom; use self::winapi::um::winnt::PVOID; use std::io; -use super::Error; +use std::num::NonZeroU32; +use Error; pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { let ret = unsafe { RtlGenRandom(dest.as_mut_ptr() as PVOID, dest.len() as ULONG) }; - if ret == 0 { return Err(io::Error::last_os_error().into()); } + if ret == 0 { + error!("RtlGenRandom call failed"); + return Err(io::Error::last_os_error().into()); + } Ok(()) } + +#[inline(always)] +pub fn error_msg_inner(_: NonZeroU32) -> Option<&'static str> { None }