]> git.proxmox.com Git - proxmox-backup.git/blame - src/tape/file_formats/multi_volume_writer.rs
update to first proxmox crate split
[proxmox-backup.git] / src / tape / file_formats / multi_volume_writer.rs
CommitLineData
983e929e
DM
1use anyhow::Error;
2
6ef1b649 3use proxmox_uuid::Uuid;
983e929e 4
048b43af 5use pbs_tape::{TapeWrite, MediaContentHeader};
983e929e
DM
6
7/// Writes data streams using multiple volumes
8///
9/// Note: We do not use this feature currently.
10pub struct MultiVolumeWriter<'a> {
11 writer: Option<Box<dyn TapeWrite + 'a>>,
12 next_writer_fn: Box<dyn 'a + FnMut() -> Result<Box<dyn TapeWrite +'a>, Error>>,
13 got_leom: bool,
14 finished: bool,
15 wrote_header: bool,
16 header: MediaContentHeader,
17 header_data: Vec<u8>,
18 bytes_written: usize, // does not include bytes from current writer
19}
20
21impl <'a> MultiVolumeWriter<'a> {
22
23 /// Creates a new instance
24 pub fn new(
25 writer: Box<dyn TapeWrite +'a>,
26 content_magic: [u8; 8],
27 header_data: Vec<u8>,
28 next_writer_fn: Box<dyn 'a + FnMut() -> Result<Box<dyn TapeWrite + 'a>, Error>>,
29 ) -> Self {
30
31 let header = MediaContentHeader::new(content_magic, header_data.len() as u32);
32
33 Self {
34 writer: Some(writer),
35 next_writer_fn,
36 got_leom: false,
37 finished: false,
38 header,
39 header_data,
40 wrote_header: false,
41 bytes_written: 0,
42 }
43 }
44
45 /// Returns the cuntent Uuid with the current part number
46 pub fn uuid_and_part_number(&self) -> (Uuid, usize) {
47 (self.header.uuid.into(), self.header.part_number as usize)
48 }
49}
50
51impl <'a> TapeWrite for MultiVolumeWriter<'a> {
52
53 fn write_all(&mut self, buf: &[u8]) -> Result<bool, std::io::Error> {
54
55 if self.finished {
56 proxmox::io_bail!("multi-volume writer already finished: internal error");
57 }
58
59 if self.got_leom {
60 if !self.wrote_header {
61 proxmox::io_bail!("multi-volume writer: got LEOM before writing anything - internal error");
62 }
63 let mut writer = match self.writer.take() {
64 Some(writer) => writer,
65 None => proxmox::io_bail!("multi-volume writer: no writer -internal error"),
66 };
67 self.bytes_written = writer.bytes_written();
68 writer.finish(true)?;
69 }
70
71 if self.writer.is_none() {
72 if self.header.part_number >= 255 {
73 proxmox::io_bail!("multi-volume writer: too many parts");
74 }
75 self.writer = Some(
76 (self.next_writer_fn)()
77 .map_err(|err| proxmox::io_format_err!("multi-volume get next volume failed: {}", err))?
78 );
79 self.got_leom = false;
80 self.wrote_header = false;
81 self.header.part_number += 1;
82 }
83
84 let leom = match self.writer {
85 None => unreachable!(),
86 Some(ref mut writer) => {
87 if !self.wrote_header {
88 writer.write_header(&self.header, &self.header_data)?;
89 self.wrote_header = true;
90 }
91 writer.write_all(buf)?
92 }
93 };
94
95 if leom { self.got_leom = true; }
96
97 Ok(false)
98 }
99
100 fn bytes_written(&self) -> usize {
101 let mut bytes_written = self.bytes_written;
102 if let Some(ref writer) = self.writer {
103 bytes_written += writer.bytes_written();
104 }
105 bytes_written
106 }
107
108 fn finish(&mut self, incomplete: bool) -> Result<bool, std::io::Error> {
109 if incomplete {
110 proxmox::io_bail!(
111 "incomplete flag makes no sense for multi-volume stream: internal error");
112 }
113
114 match self.writer.take() {
115 None if self.finished => proxmox::io_bail!(
116 "multi-volume writer already finished: internal error"),
117 None => Ok(false),
118 Some(ref mut writer) => {
119 self.finished = true;
120 if !self.wrote_header {
121 writer.write_header(&self.header, &self.header_data)?;
122 self.wrote_header = true;
123 }
124 writer.finish(false)
125 }
126 }
127 }
128
129 fn logical_end_of_media(&self) -> bool {
130 self.got_leom
131 }
132
133}