| 1 | use crate::Error; | 
| 2 | use core::mem::MaybeUninit; | 
|---|
| 3 |  | 
|---|
| 4 | cfg_if! { | 
|---|
| 5 | if #[cfg(any(target_os = "netbsd", target_os = "openbsd", target_os = "android"))] { | 
|---|
| 6 | use libc::__errno as errno_location; | 
|---|
| 7 | } else if #[cfg(any(target_os = "linux", target_os = "emscripten", target_os = "hurd", target_os = "redox", target_os = "dragonfly"))] { | 
|---|
| 8 | use libc::__errno_location as errno_location; | 
|---|
| 9 | } else if #[cfg(any(target_os = "solaris", target_os = "illumos"))] { | 
|---|
| 10 | use libc::___errno as errno_location; | 
|---|
| 11 | } else if #[cfg(any(target_os = "macos", target_os = "freebsd"))] { | 
|---|
| 12 | use libc::__error as errno_location; | 
|---|
| 13 | } else if #[cfg(target_os = "haiku")] { | 
|---|
| 14 | use libc::_errnop as errno_location; | 
|---|
| 15 | } else if #[cfg(target_os = "nto")] { | 
|---|
| 16 | use libc::__get_errno_ptr as errno_location; | 
|---|
| 17 | } else if #[cfg(any(all(target_os = "horizon", target_arch = "arm"), target_os = "vita"))] { | 
|---|
| 18 | extern "C"{ | 
|---|
| 19 | // Not provided by libc: https://github.com/rust-lang/libc/issues/1995 | 
|---|
| 20 | fn __errno() -> *mut libc::c_int; | 
|---|
| 21 | } | 
|---|
| 22 | use __errno as errno_location; | 
|---|
| 23 | } else if #[cfg(target_os = "aix")] { | 
|---|
| 24 | use libc::_Errno as errno_location; | 
|---|
| 25 | } | 
|---|
| 26 | } | 
|---|
| 27 |  | 
|---|
| 28 | cfg_if! { | 
|---|
| 29 | if #[cfg(target_os = "vxworks")] { | 
|---|
| 30 | use libc::errnoGet as get_errno; | 
|---|
| 31 | } else { | 
|---|
| 32 | unsafe fn get_errno() -> libc::c_int { *errno_location() } | 
|---|
| 33 | } | 
|---|
| 34 | } | 
|---|
| 35 |  | 
|---|
| 36 | pub(crate) fn last_os_error() -> Error { | 
|---|
| 37 | let errno: libc::c_int = unsafe { get_errno() }; | 
|---|
| 38 |  | 
|---|
| 39 | // c_int-to-u32 conversion is lossless for nonnegative values if they are the same size. | 
|---|
| 40 | const _: () = assert!(core::mem::size_of::<libc::c_int>() == core::mem::size_of::<u32>()); | 
|---|
| 41 |  | 
|---|
| 42 | match u32::try_from(errno) { | 
|---|
| 43 | Ok(code: u32) if code != 0 => Error::from_os_error(code), | 
|---|
| 44 | _ => Error::ERRNO_NOT_POSITIVE, | 
|---|
| 45 | } | 
|---|
| 46 | } | 
|---|
| 47 |  | 
|---|
| 48 | /// Fill a buffer by repeatedly invoking `sys_fill`. | 
|---|
| 49 | /// | 
|---|
| 50 | /// The `sys_fill` function: | 
|---|
| 51 | ///   - should return -1 and set errno on failure | 
|---|
| 52 | ///   - should return the number of bytes written on success | 
|---|
| 53 | #[ allow(dead_code)] | 
|---|
| 54 | pub(crate) fn sys_fill_exact( | 
|---|
| 55 | mut buf: &mut [MaybeUninit<u8>], | 
|---|
| 56 | sys_fill: impl Fn(&mut [MaybeUninit<u8>]) -> libc::ssize_t, | 
|---|
| 57 | ) -> Result<(), Error> { | 
|---|
| 58 | while !buf.is_empty() { | 
|---|
| 59 | let res: isize = sys_fill(buf); | 
|---|
| 60 | match res { | 
|---|
| 61 | res: isize if res > 0 => { | 
|---|
| 62 | let len: usize = usize::try_from(res).map_err(|_| Error::UNEXPECTED)?; | 
|---|
| 63 | buf = buf.get_mut(len..).ok_or(err:Error::UNEXPECTED)?; | 
|---|
| 64 | } | 
|---|
| 65 | -1 => { | 
|---|
| 66 | let err: Error = last_os_error(); | 
|---|
| 67 | // We should try again if the call was interrupted. | 
|---|
| 68 | if err.raw_os_error() != Some(libc::EINTR) { | 
|---|
| 69 | return Err(err); | 
|---|
| 70 | } | 
|---|
| 71 | } | 
|---|
| 72 | // Negative return codes not equal to -1 should be impossible. | 
|---|
| 73 | // EOF (ret = 0) should be impossible, as the data we are reading | 
|---|
| 74 | // should be an infinite stream of random bytes. | 
|---|
| 75 | _ => return Err(Error::UNEXPECTED), | 
|---|
| 76 | } | 
|---|
| 77 | } | 
|---|
| 78 | Ok(()) | 
|---|
| 79 | } | 
|---|
| 80 |  | 
|---|