use anyhow::Error; use proxmox::tools::Uuid; use crate::tape::{ TapeWrite, file_formats::MediaContentHeader, }; /// Writes data streams using multiple volumes /// /// Note: We do not use this feature currently. pub struct MultiVolumeWriter<'a> { writer: Option>, next_writer_fn: Box Result, Error>>, got_leom: bool, finished: bool, wrote_header: bool, header: MediaContentHeader, header_data: Vec, bytes_written: usize, // does not include bytes from current writer } impl <'a> MultiVolumeWriter<'a> { /// Creates a new instance pub fn new( writer: Box, content_magic: [u8; 8], header_data: Vec, next_writer_fn: Box Result, Error>>, ) -> Self { let header = MediaContentHeader::new(content_magic, header_data.len() as u32); Self { writer: Some(writer), next_writer_fn, got_leom: false, finished: false, header, header_data, wrote_header: false, bytes_written: 0, } } /// Returns the cuntent Uuid with the current part number pub fn uuid_and_part_number(&self) -> (Uuid, usize) { (self.header.uuid.into(), self.header.part_number as usize) } } impl <'a> TapeWrite for MultiVolumeWriter<'a> { fn write_all(&mut self, buf: &[u8]) -> Result { if self.finished { proxmox::io_bail!("multi-volume writer already finished: internal error"); } if self.got_leom { if !self.wrote_header { proxmox::io_bail!("multi-volume writer: got LEOM before writing anything - internal error"); } let mut writer = match self.writer.take() { Some(writer) => writer, None => proxmox::io_bail!("multi-volume writer: no writer -internal error"), }; self.bytes_written = writer.bytes_written(); writer.finish(true)?; } if self.writer.is_none() { if self.header.part_number >= 255 { proxmox::io_bail!("multi-volume writer: too many parts"); } self.writer = Some( (self.next_writer_fn)() .map_err(|err| proxmox::io_format_err!("multi-volume get next volume failed: {}", err))? ); self.got_leom = false; self.wrote_header = false; self.header.part_number += 1; } let leom = match self.writer { None => unreachable!(), Some(ref mut writer) => { if !self.wrote_header { writer.write_header(&self.header, &self.header_data)?; self.wrote_header = true; } writer.write_all(buf)? } }; if leom { self.got_leom = true; } Ok(false) } fn bytes_written(&self) -> usize { let mut bytes_written = self.bytes_written; if let Some(ref writer) = self.writer { bytes_written += writer.bytes_written(); } bytes_written } fn finish(&mut self, incomplete: bool) -> Result { if incomplete { proxmox::io_bail!( "incomplete flag makes no sense for multi-volume stream: internal error"); } match self.writer.take() { None if self.finished => proxmox::io_bail!( "multi-volume writer already finished: internal error"), None => Ok(false), Some(ref mut writer) => { self.finished = true; if !self.wrote_header { writer.write_header(&self.header, &self.header_data)?; self.wrote_header = true; } writer.finish(false) } } } fn logical_end_of_media(&self) -> bool { self.got_leom } }