getrandom/utils/sys_fill_exact.rs
1use crate::Error;
2use core::mem::MaybeUninit;
3
4mod get_errno;
5mod sanitizer;
6
7pub(crate) use get_errno::get_errno;
8
9/// Fill a buffer by repeatedly invoking `sys_fill`.
10///
11/// The `sys_fill` function:
12/// - should return -1 and set errno on failure
13/// - should return the number of bytes written on success
14pub(crate) fn sys_fill_exact(
15 mut buf: &mut [MaybeUninit<u8>],
16 sys_fill: impl Fn(&mut [MaybeUninit<u8>]) -> libc::ssize_t,
17) -> Result<(), Error> {
18 while !buf.is_empty() {
19 let res = sys_fill(buf);
20 match res {
21 res if res > 0 => {
22 let len = usize::try_from(res).map_err(|_| Error::UNEXPECTED)?;
23 let (l, r) = buf.split_at_mut_checked(len).ok_or(Error::UNEXPECTED)?;
24 unsafe { sanitizer::unpoison(l) };
25 buf = r;
26 }
27 -1 => {
28 let errno = get_errno();
29 // We should try again if the call was interrupted.
30 if errno != libc::EINTR {
31 return Err(Error::from_errno(errno));
32 }
33 }
34 // Negative return codes not equal to -1 should be impossible.
35 // EOF (ret = 0) should be impossible, as the data we are reading
36 // should be an infinite stream of random bytes.
37 _ => return Err(Error::UNEXPECTED),
38 }
39 }
40 Ok(())
41}