]>
Commit | Line | Data |
---|---|---|
983e929e DM |
1 | use std::io::{Read}; |
2 | ||
3 | use anyhow::{bail, Error}; | |
4 | ||
6ef1b649 | 5 | use proxmox_io::ReadExt; |
983e929e | 6 | |
048b43af | 7 | use pbs_tape::{TapeRead, MediaContentHeader}; |
983e929e DM |
8 | |
9 | /// Read multi volume data streams written by `MultiVolumeWriter` | |
10 | /// | |
11 | /// Note: We do not use this feature currently. | |
12 | pub struct MultiVolumeReader<'a> { | |
13 | reader: Option<Box<dyn TapeRead + 'a>>, | |
14 | next_reader_fn: Box<dyn 'a + FnMut() -> Result<Box<dyn TapeRead +'a>, Error>>, | |
15 | complete: bool, | |
16 | header: MediaContentHeader, | |
17 | } | |
18 | ||
19 | impl <'a> MultiVolumeReader<'a> { | |
20 | ||
21 | /// Creates a new instance | |
22 | pub fn new( | |
23 | reader: Box<dyn TapeRead +'a>, | |
24 | header: MediaContentHeader, | |
25 | next_reader_fn: Box<dyn 'a + FnMut() -> Result<Box<dyn TapeRead +'a>, Error>>, | |
26 | ) -> Result<Self, Error> { | |
27 | ||
28 | if header.part_number != 0 { | |
29 | bail!("MultiVolumeReader::new - got wrong header part_number ({} != 0)", | |
30 | header.part_number); | |
31 | } | |
32 | ||
33 | Ok(Self { | |
34 | reader: Some(reader), | |
35 | next_reader_fn, | |
36 | complete: false, | |
37 | header, | |
38 | }) | |
39 | } | |
40 | } | |
41 | ||
42 | impl <'a> Read for MultiVolumeReader<'a> { | |
43 | ||
44 | fn read(&mut self, buf: &mut [u8]) -> Result<usize, std::io::Error> { | |
45 | if self.complete { | |
46 | return Ok(0); | |
47 | } | |
48 | ||
49 | if self.reader.is_none() { | |
50 | let mut reader = (self.next_reader_fn)() | |
51 | .map_err(|err| proxmox::io_format_err!("multi-volume next failed: {}", err))?; | |
52 | ||
6ef1b649 | 53 | proxmox_lang::try_block!({ |
983e929e DM |
54 | let part_header: MediaContentHeader = unsafe { reader.read_le_value()? }; |
55 | self.reader = Some(reader); | |
56 | ||
57 | if part_header.uuid != self.header.uuid { | |
58 | proxmox::io_bail!("got wrong part uuid"); | |
59 | } | |
60 | if part_header.content_magic!= self.header.content_magic { | |
61 | proxmox::io_bail!("got wrong part content magic"); | |
62 | } | |
63 | ||
64 | let expect_part_number = self.header.part_number + 1; | |
65 | ||
66 | if part_header.part_number != expect_part_number { | |
67 | proxmox::io_bail!("got wrong part number ({} != {})", | |
68 | part_header.part_number, expect_part_number); | |
69 | } | |
70 | ||
71 | self.header.part_number = expect_part_number; | |
72 | ||
73 | Ok(()) | |
74 | }).map_err(|err| { | |
75 | proxmox::io_format_err!("multi-volume read content header failed: {}", err) | |
76 | })?; | |
77 | } | |
78 | ||
79 | match self.reader { | |
80 | None => unreachable!(), | |
81 | Some(ref mut reader) => { | |
82 | match reader.read(buf) { | |
83 | Ok(0) => { | |
84 | if reader.is_incomplete()? { | |
85 | self.reader = None; | |
86 | self.read(buf) | |
87 | } else { | |
88 | self.reader = None; | |
89 | self.complete = true; | |
90 | Ok(0) | |
91 | } | |
92 | } | |
93 | Ok(n) => Ok(n), | |
94 | Err(err) => Err(err) | |
95 | } | |
96 | } | |
97 | } | |
98 | } | |
99 | } |