2022-04-10 15:49:03 +00:00
|
|
|
use std::io::Read;
|
2021-02-04 07:36:35 +00:00
|
|
|
|
|
|
|
use anyhow::{bail, Error};
|
|
|
|
|
2021-10-08 09:19:37 +00:00
|
|
|
use proxmox_io::ReadExt;
|
2021-02-04 07:36:35 +00:00
|
|
|
|
2022-04-10 15:49:03 +00:00
|
|
|
use pbs_tape::{MediaContentHeader, TapeRead};
|
2021-02-04 07:36:35 +00:00
|
|
|
|
|
|
|
/// Read multi volume data streams written by `MultiVolumeWriter`
|
|
|
|
///
|
|
|
|
/// Note: We do not use this feature currently.
|
|
|
|
pub struct MultiVolumeReader<'a> {
|
|
|
|
reader: Option<Box<dyn TapeRead + 'a>>,
|
2022-04-10 15:49:03 +00:00
|
|
|
next_reader_fn: Box<dyn 'a + FnMut() -> Result<Box<dyn TapeRead + 'a>, Error>>,
|
2021-02-04 07:36:35 +00:00
|
|
|
complete: bool,
|
|
|
|
header: MediaContentHeader,
|
|
|
|
}
|
|
|
|
|
2022-04-10 15:49:03 +00:00
|
|
|
impl<'a> MultiVolumeReader<'a> {
|
2021-02-04 07:36:35 +00:00
|
|
|
/// Creates a new instance
|
|
|
|
pub fn new(
|
2022-04-10 15:49:03 +00:00
|
|
|
reader: Box<dyn TapeRead + 'a>,
|
2021-02-04 07:36:35 +00:00
|
|
|
header: MediaContentHeader,
|
2022-04-10 15:49:03 +00:00
|
|
|
next_reader_fn: Box<dyn 'a + FnMut() -> Result<Box<dyn TapeRead + 'a>, Error>>,
|
2021-02-04 07:36:35 +00:00
|
|
|
) -> Result<Self, Error> {
|
|
|
|
if header.part_number != 0 {
|
2022-04-10 15:49:03 +00:00
|
|
|
bail!(
|
|
|
|
"MultiVolumeReader::new - got wrong header part_number ({} != 0)",
|
|
|
|
header.part_number
|
|
|
|
);
|
2021-02-04 07:36:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Ok(Self {
|
|
|
|
reader: Some(reader),
|
|
|
|
next_reader_fn,
|
|
|
|
complete: false,
|
|
|
|
header,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-10 15:49:03 +00:00
|
|
|
impl<'a> Read for MultiVolumeReader<'a> {
|
2021-02-04 07:36:35 +00:00
|
|
|
fn read(&mut self, buf: &mut [u8]) -> Result<usize, std::io::Error> {
|
|
|
|
if self.complete {
|
|
|
|
return Ok(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
if self.reader.is_none() {
|
|
|
|
let mut reader = (self.next_reader_fn)()
|
2022-02-21 10:39:18 +00:00
|
|
|
.map_err(|err| proxmox_lang::io_format_err!("multi-volume next failed: {}", err))?;
|
2021-02-04 07:36:35 +00:00
|
|
|
|
2021-10-08 09:19:37 +00:00
|
|
|
proxmox_lang::try_block!({
|
2021-02-04 07:36:35 +00:00
|
|
|
let part_header: MediaContentHeader = unsafe { reader.read_le_value()? };
|
|
|
|
self.reader = Some(reader);
|
|
|
|
|
|
|
|
if part_header.uuid != self.header.uuid {
|
2022-02-21 10:39:18 +00:00
|
|
|
proxmox_lang::io_bail!("got wrong part uuid");
|
2021-02-04 07:36:35 +00:00
|
|
|
}
|
2022-04-10 15:49:03 +00:00
|
|
|
if part_header.content_magic != self.header.content_magic {
|
2022-02-21 10:39:18 +00:00
|
|
|
proxmox_lang::io_bail!("got wrong part content magic");
|
2021-02-04 07:36:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
let expect_part_number = self.header.part_number + 1;
|
|
|
|
|
|
|
|
if part_header.part_number != expect_part_number {
|
2022-04-10 15:49:03 +00:00
|
|
|
proxmox_lang::io_bail!(
|
|
|
|
"got wrong part number ({} != {})",
|
|
|
|
part_header.part_number,
|
|
|
|
expect_part_number
|
|
|
|
);
|
2021-02-04 07:36:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
self.header.part_number = expect_part_number;
|
|
|
|
|
|
|
|
Ok(())
|
2022-04-10 15:49:03 +00:00
|
|
|
})
|
|
|
|
.map_err(|err| {
|
2022-02-21 10:39:18 +00:00
|
|
|
proxmox_lang::io_format_err!("multi-volume read content header failed: {}", err)
|
2021-02-04 07:36:35 +00:00
|
|
|
})?;
|
2022-04-10 15:49:03 +00:00
|
|
|
}
|
2021-02-04 07:36:35 +00:00
|
|
|
|
|
|
|
match self.reader {
|
|
|
|
None => unreachable!(),
|
2022-04-10 15:49:03 +00:00
|
|
|
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)
|
2021-02-04 07:36:35 +00:00
|
|
|
}
|
|
|
|
}
|
2022-04-10 15:49:03 +00:00
|
|
|
Ok(n) => Ok(n),
|
|
|
|
Err(err) => Err(err),
|
|
|
|
},
|
2021-02-04 07:36:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|