use std::io::{Read}; use anyhow::{bail, Error}; use proxmox::tools::io::ReadExt; use pbs_tape::{TapeRead, MediaContentHeader}; /// Read multi volume data streams written by `MultiVolumeWriter` /// /// Note: We do not use this feature currently. pub struct MultiVolumeReader<'a> { reader: Option>, next_reader_fn: Box Result, Error>>, complete: bool, header: MediaContentHeader, } impl <'a> MultiVolumeReader<'a> { /// Creates a new instance pub fn new( reader: Box, header: MediaContentHeader, next_reader_fn: Box Result, Error>>, ) -> Result { if header.part_number != 0 { bail!("MultiVolumeReader::new - got wrong header part_number ({} != 0)", header.part_number); } Ok(Self { reader: Some(reader), next_reader_fn, complete: false, header, }) } } impl <'a> Read for MultiVolumeReader<'a> { fn read(&mut self, buf: &mut [u8]) -> Result { if self.complete { return Ok(0); } if self.reader.is_none() { let mut reader = (self.next_reader_fn)() .map_err(|err| proxmox::io_format_err!("multi-volume next failed: {}", err))?; proxmox::try_block!({ let part_header: MediaContentHeader = unsafe { reader.read_le_value()? }; self.reader = Some(reader); if part_header.uuid != self.header.uuid { proxmox::io_bail!("got wrong part uuid"); } if part_header.content_magic!= self.header.content_magic { proxmox::io_bail!("got wrong part content magic"); } let expect_part_number = self.header.part_number + 1; if part_header.part_number != expect_part_number { proxmox::io_bail!("got wrong part number ({} != {})", part_header.part_number, expect_part_number); } self.header.part_number = expect_part_number; Ok(()) }).map_err(|err| { proxmox::io_format_err!("multi-volume read content header failed: {}", err) })?; } match self.reader { None => unreachable!(), Some(ref mut reader) => { match reader.read(buf) { Ok(0) => { if reader.is_incomplete()? { self.reader = None; self.read(buf) } else { self.reader = None; self.complete = true; Ok(0) } } Ok(n) => Ok(n), Err(err) => Err(err) } } } } }