diff --git a/proxmox/src/tools/io/read.rs b/proxmox/src/tools/io/read.rs index 1bd331e6..9bba54b4 100644 --- a/proxmox/src/tools/io/read.rs +++ b/proxmox/src/tools/io/read.rs @@ -222,6 +222,19 @@ pub trait ReadExt { /// This should only used for types with a defined storage representation, usually /// `#[repr(C)]`, otherwise the results may be inconsistent. unsafe fn read_host_value_boxed(&mut self) -> io::Result>; + + /// Try to read the exact number of bytes required to fill buf. + /// + /// This function reads as many bytes as necessary to completely + /// fill the specified buffer buf. If this function encounters an + /// "end of file" before getting any data, it returns Ok(false). + /// If there is some data, but not enough, it return an error of + /// the kind ErrorKind::UnexpectedEof. The contents of buf are + /// unspecified in this case. + fn read_exact_or_eof(&mut self, buf: &mut [u8]) -> io::Result; + + /// Read until EOF + fn skip_to_end(&mut self) -> io::Result; } impl ReadExt for R { @@ -279,4 +292,40 @@ impl ReadExt for R { ))?; Ok(Box::from_raw(ptr)) } + + fn read_exact_or_eof(&mut self, mut buf: &mut [u8]) -> io::Result { + let mut read_bytes = 0; + loop { + match self.read(&mut buf) { + Ok(0) => { + if read_bytes == 0 { return Ok(false); } + return Err(io::Error::new( + io::ErrorKind::UnexpectedEof, + "failed to fill whole buffer") + ); + } + Ok(n) => { + let tmp = buf; + buf = &mut tmp[n..]; + read_bytes += n; + if buf.is_empty() { return Ok(true); } + } + Err(ref e) if e.kind() == std::io::ErrorKind::Interrupted => {} + Err(e) => return Err(e), + } + } + } + + fn skip_to_end(&mut self) -> io::Result { + let mut skipped_bytes = 0; + let mut buf = unsafe { vec::uninitialized(32*1024) }; + loop { + match self.read(&mut buf) { + Ok(0) => return Ok(skipped_bytes), + Ok(n) => skipped_bytes += n, + Err(ref e) if e.kind() == std::io::ErrorKind::Interrupted => {} + Err(e) => return Err(e), + } + } + } }