tape: rust fmt
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
This commit is contained in:
@ -4,19 +4,9 @@ use std::io::Read;
|
||||
use proxmox_sys::error::SysError;
|
||||
use proxmox_uuid::Uuid;
|
||||
|
||||
use pbs_tape::{
|
||||
PROXMOX_TAPE_BLOCK_SIZE,
|
||||
TapeWrite, MediaContentHeader,
|
||||
};
|
||||
use pbs_tape::{MediaContentHeader, TapeWrite, PROXMOX_TAPE_BLOCK_SIZE};
|
||||
|
||||
use crate::{
|
||||
tape::{
|
||||
file_formats::{
|
||||
PROXMOX_BACKUP_CATALOG_ARCHIVE_MAGIC_1_0,
|
||||
CatalogArchiveHeader,
|
||||
},
|
||||
},
|
||||
};
|
||||
use crate::tape::file_formats::{CatalogArchiveHeader, PROXMOX_BACKUP_CATALOG_ARCHIVE_MAGIC_1_0};
|
||||
|
||||
/// Write a media catalog to the tape
|
||||
///
|
||||
@ -32,17 +22,20 @@ pub fn tape_write_catalog<'a>(
|
||||
seq_nr: usize,
|
||||
file: &mut File,
|
||||
) -> Result<Option<Uuid>, std::io::Error> {
|
||||
|
||||
let archive_header = CatalogArchiveHeader {
|
||||
uuid: uuid.clone(),
|
||||
media_set_uuid: media_set_uuid.clone(),
|
||||
seq_nr: seq_nr as u64,
|
||||
};
|
||||
|
||||
let header_data = serde_json::to_string_pretty(&archive_header)?.as_bytes().to_vec();
|
||||
let header_data = serde_json::to_string_pretty(&archive_header)?
|
||||
.as_bytes()
|
||||
.to_vec();
|
||||
|
||||
let header = MediaContentHeader::new(
|
||||
PROXMOX_BACKUP_CATALOG_ARCHIVE_MAGIC_1_0, header_data.len() as u32);
|
||||
PROXMOX_BACKUP_CATALOG_ARCHIVE_MAGIC_1_0,
|
||||
header_data.len() as u32,
|
||||
);
|
||||
let content_uuid: Uuid = header.uuid.into();
|
||||
|
||||
let leom = writer.write_header(&header, &header_data)?;
|
||||
@ -54,7 +47,6 @@ pub fn tape_write_catalog<'a>(
|
||||
let mut file_copy_buffer = proxmox_io::vec::undefined(PROXMOX_TAPE_BLOCK_SIZE);
|
||||
|
||||
let result: Result<(), std::io::Error> = proxmox_lang::try_block!({
|
||||
|
||||
let file_size = file.metadata()?.len();
|
||||
let mut remaining = file_size;
|
||||
|
||||
@ -71,7 +63,7 @@ pub fn tape_write_catalog<'a>(
|
||||
}
|
||||
Ok(())
|
||||
});
|
||||
|
||||
|
||||
match result {
|
||||
Ok(()) => {
|
||||
writer.finish(false)?;
|
||||
|
@ -7,16 +7,11 @@ use proxmox_io::ReadExt;
|
||||
use proxmox_uuid::Uuid;
|
||||
|
||||
use pbs_datastore::DataBlob;
|
||||
use pbs_tape::{
|
||||
PROXMOX_TAPE_BLOCK_SIZE,
|
||||
TapeWrite, MediaContentHeader,
|
||||
};
|
||||
use pbs_tape::{MediaContentHeader, TapeWrite, PROXMOX_TAPE_BLOCK_SIZE};
|
||||
|
||||
use crate::tape::file_formats::{
|
||||
ChunkArchiveEntryHeader, ChunkArchiveHeader, PROXMOX_BACKUP_CHUNK_ARCHIVE_ENTRY_MAGIC_1_0,
|
||||
PROXMOX_BACKUP_CHUNK_ARCHIVE_MAGIC_1_1,
|
||||
PROXMOX_BACKUP_CHUNK_ARCHIVE_ENTRY_MAGIC_1_0,
|
||||
ChunkArchiveHeader,
|
||||
ChunkArchiveEntryHeader,
|
||||
};
|
||||
|
||||
/// Writes chunk archives to tape.
|
||||
@ -32,8 +27,7 @@ pub struct ChunkArchiveWriter<'a> {
|
||||
close_on_leom: bool,
|
||||
}
|
||||
|
||||
impl <'a> ChunkArchiveWriter<'a> {
|
||||
|
||||
impl<'a> ChunkArchiveWriter<'a> {
|
||||
pub const MAGIC: [u8; 8] = PROXMOX_BACKUP_CHUNK_ARCHIVE_MAGIC_1_1;
|
||||
|
||||
/// Creates a new instance
|
||||
@ -41,10 +35,13 @@ impl <'a> ChunkArchiveWriter<'a> {
|
||||
mut writer: Box<dyn TapeWrite + 'a>,
|
||||
store: &str,
|
||||
close_on_leom: bool,
|
||||
) -> Result<(Self,Uuid), Error> {
|
||||
|
||||
let archive_header = ChunkArchiveHeader { store: store.to_string() };
|
||||
let header_data = serde_json::to_string_pretty(&archive_header)?.as_bytes().to_vec();
|
||||
) -> Result<(Self, Uuid), Error> {
|
||||
let archive_header = ChunkArchiveHeader {
|
||||
store: store.to_string(),
|
||||
};
|
||||
let header_data = serde_json::to_string_pretty(&archive_header)?
|
||||
.as_bytes()
|
||||
.to_vec();
|
||||
|
||||
let header = MediaContentHeader::new(Self::MAGIC, header_data.len() as u32);
|
||||
writer.write_header(&header, &header_data)?;
|
||||
@ -69,8 +66,9 @@ impl <'a> ChunkArchiveWriter<'a> {
|
||||
fn write_all(&mut self, data: &[u8]) -> Result<bool, std::io::Error> {
|
||||
match self.writer {
|
||||
Some(ref mut writer) => writer.write_all(data),
|
||||
None => proxmox_lang::io_bail!(
|
||||
"detected write after archive finished - internal error"),
|
||||
None => {
|
||||
proxmox_lang::io_bail!("detected write after archive finished - internal error")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -80,10 +78,9 @@ impl <'a> ChunkArchiveWriter<'a> {
|
||||
/// In that case the archive only contains parts of the last chunk.
|
||||
pub fn try_write_chunk(
|
||||
&mut self,
|
||||
digest: &[u8;32],
|
||||
digest: &[u8; 32],
|
||||
blob: &DataBlob,
|
||||
) -> Result<bool, std::io::Error> {
|
||||
|
||||
if self.writer.is_none() {
|
||||
return Ok(false);
|
||||
}
|
||||
@ -95,9 +92,11 @@ impl <'a> ChunkArchiveWriter<'a> {
|
||||
};
|
||||
|
||||
let head = head.to_le();
|
||||
let data = unsafe { std::slice::from_raw_parts(
|
||||
&head as *const ChunkArchiveEntryHeader as *const u8,
|
||||
std::mem::size_of::<ChunkArchiveEntryHeader>())
|
||||
let data = unsafe {
|
||||
std::slice::from_raw_parts(
|
||||
&head as *const ChunkArchiveEntryHeader as *const u8,
|
||||
std::mem::size_of::<ChunkArchiveEntryHeader>(),
|
||||
)
|
||||
};
|
||||
|
||||
self.write_all(data)?;
|
||||
@ -150,8 +149,7 @@ pub struct ChunkArchiveDecoder<R> {
|
||||
reader: R,
|
||||
}
|
||||
|
||||
impl <R: Read> ChunkArchiveDecoder<R> {
|
||||
|
||||
impl<R: Read> ChunkArchiveDecoder<R> {
|
||||
/// Creates a new instance
|
||||
pub fn new(reader: R) -> Self {
|
||||
Self { reader }
|
||||
@ -163,8 +161,7 @@ impl <R: Read> ChunkArchiveDecoder<R> {
|
||||
}
|
||||
|
||||
/// Returns the next chunk (if any).
|
||||
pub fn next_chunk(&mut self) -> Result<Option<([u8;32], DataBlob)>, Error> {
|
||||
|
||||
pub fn next_chunk(&mut self) -> Result<Option<([u8; 32], DataBlob)>, Error> {
|
||||
let mut header = ChunkArchiveEntryHeader {
|
||||
magic: [0u8; 8],
|
||||
digest: [0u8; 32],
|
||||
@ -173,11 +170,12 @@ impl <R: Read> ChunkArchiveDecoder<R> {
|
||||
let data = unsafe {
|
||||
std::slice::from_raw_parts_mut(
|
||||
(&mut header as *mut ChunkArchiveEntryHeader) as *mut u8,
|
||||
std::mem::size_of::<ChunkArchiveEntryHeader>())
|
||||
std::mem::size_of::<ChunkArchiveEntryHeader>(),
|
||||
)
|
||||
};
|
||||
|
||||
match self.reader.read_exact_or_eof(data) {
|
||||
Ok(true) => {},
|
||||
Ok(true) => {}
|
||||
Ok(false) => {
|
||||
// last chunk is allowed to be incomplete - simply report EOD
|
||||
return Ok(None);
|
||||
@ -189,7 +187,7 @@ impl <R: Read> ChunkArchiveDecoder<R> {
|
||||
bail!("wrong magic number");
|
||||
}
|
||||
|
||||
let raw_data = match self.reader.read_exact_allocated(header.size as usize) {
|
||||
let raw_data = match self.reader.read_exact_allocated(header.size as usize) {
|
||||
Ok(data) => data,
|
||||
Err(err) if err.kind() == std::io::ErrorKind::UnexpectedEof => {
|
||||
// last chunk is allowed to be incomplete - simply report EOD
|
||||
|
@ -37,7 +37,8 @@ pub const PROXMOX_BACKUP_CHUNK_ARCHIVE_MAGIC_1_0: [u8; 8] = [62, 173, 167, 95, 4
|
||||
pub const PROXMOX_BACKUP_CHUNK_ARCHIVE_MAGIC_1_1: [u8; 8] = [109, 49, 99, 109, 215, 2, 131, 191];
|
||||
|
||||
// openssl::sha::sha256(b"Proxmox Backup Chunk Archive Entry v1.0")[0..8]
|
||||
pub const PROXMOX_BACKUP_CHUNK_ARCHIVE_ENTRY_MAGIC_1_0: [u8; 8] = [72, 87, 109, 242, 222, 66, 143, 220];
|
||||
pub const PROXMOX_BACKUP_CHUNK_ARCHIVE_ENTRY_MAGIC_1_0: [u8; 8] =
|
||||
[72, 87, 109, 242, 222, 66, 143, 220];
|
||||
|
||||
// openssl::sha::sha256(b"Proxmox Backup Snapshot Archive v1.0")[0..8];
|
||||
// only used in unreleased version - no longer supported
|
||||
@ -46,9 +47,10 @@ pub const PROXMOX_BACKUP_SNAPSHOT_ARCHIVE_MAGIC_1_0: [u8; 8] = [9, 182, 2, 31, 1
|
||||
pub const PROXMOX_BACKUP_SNAPSHOT_ARCHIVE_MAGIC_1_1: [u8; 8] = [218, 22, 21, 208, 17, 226, 154, 98];
|
||||
|
||||
// openssl::sha::sha256(b"Proxmox Backup Catalog Archive v1.0")[0..8];
|
||||
pub const PROXMOX_BACKUP_CATALOG_ARCHIVE_MAGIC_1_0: [u8; 8] = [183, 207, 199, 37, 158, 153, 30, 115];
|
||||
pub const PROXMOX_BACKUP_CATALOG_ARCHIVE_MAGIC_1_0: [u8; 8] =
|
||||
[183, 207, 199, 37, 158, 153, 30, 115];
|
||||
|
||||
lazy_static::lazy_static!{
|
||||
lazy_static::lazy_static! {
|
||||
// Map content magic numbers to human readable names.
|
||||
static ref PROXMOX_TAPE_CONTENT_NAME: HashMap<&'static [u8;8], &'static str> = {
|
||||
let mut map = HashMap::new();
|
||||
@ -65,10 +67,11 @@ lazy_static::lazy_static!{
|
||||
|
||||
/// Map content magic numbers to human readable names.
|
||||
pub fn proxmox_tape_magic_to_text(magic: &[u8; 8]) -> Option<String> {
|
||||
PROXMOX_TAPE_CONTENT_NAME.get(magic).map(|s| String::from(*s))
|
||||
PROXMOX_TAPE_CONTENT_NAME
|
||||
.get(magic)
|
||||
.map(|s| String::from(*s))
|
||||
}
|
||||
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
/// Header for chunk archives
|
||||
pub struct ChunkArchiveHeader {
|
||||
@ -77,7 +80,7 @@ pub struct ChunkArchiveHeader {
|
||||
}
|
||||
|
||||
#[derive(Endian)]
|
||||
#[repr(C,packed)]
|
||||
#[repr(C, packed)]
|
||||
/// Header for data blobs inside a chunk archive
|
||||
pub struct ChunkArchiveEntryHeader {
|
||||
/// fixed value `PROXMOX_BACKUP_CHUNK_ARCHIVE_ENTRY_MAGIC_1_0`
|
||||
@ -108,7 +111,7 @@ pub struct CatalogArchiveHeader {
|
||||
pub seq_nr: u64,
|
||||
}
|
||||
|
||||
#[derive(Serialize,Deserialize,Clone,Debug)]
|
||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||
/// Media Label
|
||||
///
|
||||
/// Media labels are used to uniquely identify a media. They are
|
||||
@ -122,8 +125,7 @@ pub struct MediaLabel {
|
||||
pub ctime: i64,
|
||||
}
|
||||
|
||||
|
||||
#[derive(Serialize,Deserialize,Clone,Debug)]
|
||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||
/// `MediaSet` Label
|
||||
///
|
||||
/// Used to uniquely identify a `MediaSet`. They are stored as second
|
||||
@ -138,12 +140,11 @@ pub struct MediaSetLabel {
|
||||
/// Creation time stamp
|
||||
pub ctime: i64,
|
||||
/// Encryption key finkerprint (if encryped)
|
||||
#[serde(skip_serializing_if="Option::is_none")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub encryption_key_fingerprint: Option<Fingerprint>,
|
||||
}
|
||||
|
||||
impl MediaSetLabel {
|
||||
|
||||
pub fn with_data(
|
||||
pool: &str,
|
||||
uuid: Uuid,
|
||||
@ -160,4 +161,3 @@ impl MediaSetLabel {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,33 +1,33 @@
|
||||
use std::io::{Read};
|
||||
use std::io::Read;
|
||||
|
||||
use anyhow::{bail, Error};
|
||||
|
||||
use proxmox_io::ReadExt;
|
||||
|
||||
use pbs_tape::{TapeRead, MediaContentHeader};
|
||||
use pbs_tape::{MediaContentHeader, TapeRead};
|
||||
|
||||
/// 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>>,
|
||||
next_reader_fn: Box<dyn 'a + FnMut() -> Result<Box<dyn TapeRead +'a>, Error>>,
|
||||
next_reader_fn: Box<dyn 'a + FnMut() -> Result<Box<dyn TapeRead + 'a>, Error>>,
|
||||
complete: bool,
|
||||
header: MediaContentHeader,
|
||||
}
|
||||
|
||||
impl <'a> MultiVolumeReader<'a> {
|
||||
|
||||
impl<'a> MultiVolumeReader<'a> {
|
||||
/// Creates a new instance
|
||||
pub fn new(
|
||||
reader: Box<dyn TapeRead +'a>,
|
||||
reader: Box<dyn TapeRead + 'a>,
|
||||
header: MediaContentHeader,
|
||||
next_reader_fn: Box<dyn 'a + FnMut() -> Result<Box<dyn TapeRead +'a>, Error>>,
|
||||
next_reader_fn: Box<dyn 'a + FnMut() -> Result<Box<dyn TapeRead + 'a>, Error>>,
|
||||
) -> Result<Self, Error> {
|
||||
|
||||
if header.part_number != 0 {
|
||||
bail!("MultiVolumeReader::new - got wrong header part_number ({} != 0)",
|
||||
header.part_number);
|
||||
bail!(
|
||||
"MultiVolumeReader::new - got wrong header part_number ({} != 0)",
|
||||
header.part_number
|
||||
);
|
||||
}
|
||||
|
||||
Ok(Self {
|
||||
@ -39,8 +39,7 @@ impl <'a> MultiVolumeReader<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a> Read for MultiVolumeReader<'a> {
|
||||
|
||||
impl<'a> Read for MultiVolumeReader<'a> {
|
||||
fn read(&mut self, buf: &mut [u8]) -> Result<usize, std::io::Error> {
|
||||
if self.complete {
|
||||
return Ok(0);
|
||||
@ -57,43 +56,45 @@ impl <'a> Read for MultiVolumeReader<'a> {
|
||||
if part_header.uuid != self.header.uuid {
|
||||
proxmox_lang::io_bail!("got wrong part uuid");
|
||||
}
|
||||
if part_header.content_magic!= self.header.content_magic {
|
||||
if part_header.content_magic != self.header.content_magic {
|
||||
proxmox_lang::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_lang::io_bail!("got wrong part number ({} != {})",
|
||||
part_header.part_number, expect_part_number);
|
||||
proxmox_lang::io_bail!(
|
||||
"got wrong part number ({} != {})",
|
||||
part_header.part_number,
|
||||
expect_part_number
|
||||
);
|
||||
}
|
||||
|
||||
self.header.part_number = expect_part_number;
|
||||
|
||||
Ok(())
|
||||
}).map_err(|err| {
|
||||
})
|
||||
.map_err(|err| {
|
||||
proxmox_lang::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)
|
||||
}
|
||||
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)
|
||||
}
|
||||
}
|
||||
Ok(n) => Ok(n),
|
||||
Err(err) => Err(err),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,14 +2,14 @@ use anyhow::Error;
|
||||
|
||||
use proxmox_uuid::Uuid;
|
||||
|
||||
use pbs_tape::{TapeWrite, MediaContentHeader};
|
||||
use pbs_tape::{MediaContentHeader, TapeWrite};
|
||||
|
||||
/// Writes data streams using multiple volumes
|
||||
///
|
||||
/// Note: We do not use this feature currently.
|
||||
pub struct MultiVolumeWriter<'a> {
|
||||
writer: Option<Box<dyn TapeWrite + 'a>>,
|
||||
next_writer_fn: Box<dyn 'a + FnMut() -> Result<Box<dyn TapeWrite +'a>, Error>>,
|
||||
next_writer_fn: Box<dyn 'a + FnMut() -> Result<Box<dyn TapeWrite + 'a>, Error>>,
|
||||
got_leom: bool,
|
||||
finished: bool,
|
||||
wrote_header: bool,
|
||||
@ -18,16 +18,14 @@ pub struct MultiVolumeWriter<'a> {
|
||||
bytes_written: usize, // does not include bytes from current writer
|
||||
}
|
||||
|
||||
impl <'a> MultiVolumeWriter<'a> {
|
||||
|
||||
impl<'a> MultiVolumeWriter<'a> {
|
||||
/// Creates a new instance
|
||||
pub fn new(
|
||||
writer: Box<dyn TapeWrite +'a>,
|
||||
writer: Box<dyn TapeWrite + 'a>,
|
||||
content_magic: [u8; 8],
|
||||
header_data: Vec<u8>,
|
||||
next_writer_fn: Box<dyn 'a + FnMut() -> Result<Box<dyn TapeWrite + 'a>, Error>>,
|
||||
) -> Self {
|
||||
|
||||
let header = MediaContentHeader::new(content_magic, header_data.len() as u32);
|
||||
|
||||
Self {
|
||||
@ -48,21 +46,21 @@ impl <'a> MultiVolumeWriter<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a> TapeWrite for MultiVolumeWriter<'a> {
|
||||
|
||||
impl<'a> TapeWrite for MultiVolumeWriter<'a> {
|
||||
fn write_all(&mut self, buf: &[u8]) -> Result<bool, std::io::Error> {
|
||||
|
||||
if self.finished {
|
||||
proxmox_lang::io_bail!("multi-volume writer already finished: internal error");
|
||||
}
|
||||
|
||||
if self.got_leom {
|
||||
if !self.wrote_header {
|
||||
proxmox_lang::io_bail!("multi-volume writer: got LEOM before writing anything - internal error");
|
||||
proxmox_lang::io_bail!(
|
||||
"multi-volume writer: got LEOM before writing anything - internal error"
|
||||
);
|
||||
}
|
||||
let mut writer = match self.writer.take() {
|
||||
Some(writer) => writer,
|
||||
None => proxmox_lang::io_bail!("multi-volume writer: no writer -internal error"),
|
||||
None => proxmox_lang::io_bail!("multi-volume writer: no writer -internal error"),
|
||||
};
|
||||
self.bytes_written = writer.bytes_written();
|
||||
writer.finish(true)?;
|
||||
@ -72,10 +70,9 @@ impl <'a> TapeWrite for MultiVolumeWriter<'a> {
|
||||
if self.header.part_number == u8::MAX {
|
||||
proxmox_lang::io_bail!("multi-volume writer: too many parts");
|
||||
}
|
||||
self.writer = Some(
|
||||
(self.next_writer_fn)()
|
||||
.map_err(|err| proxmox_lang::io_format_err!("multi-volume get next volume failed: {}", err))?
|
||||
);
|
||||
self.writer = Some((self.next_writer_fn)().map_err(|err| {
|
||||
proxmox_lang::io_format_err!("multi-volume get next volume failed: {}", err)
|
||||
})?);
|
||||
self.got_leom = false;
|
||||
self.wrote_header = false;
|
||||
self.header.part_number += 1;
|
||||
@ -92,7 +89,9 @@ impl <'a> TapeWrite for MultiVolumeWriter<'a> {
|
||||
}
|
||||
};
|
||||
|
||||
if leom { self.got_leom = true; }
|
||||
if leom {
|
||||
self.got_leom = true;
|
||||
}
|
||||
|
||||
Ok(false)
|
||||
}
|
||||
@ -108,12 +107,14 @@ impl <'a> TapeWrite for MultiVolumeWriter<'a> {
|
||||
fn finish(&mut self, incomplete: bool) -> Result<bool, std::io::Error> {
|
||||
if incomplete {
|
||||
proxmox_lang::io_bail!(
|
||||
"incomplete flag makes no sense for multi-volume stream: internal error");
|
||||
"incomplete flag makes no sense for multi-volume stream: internal error"
|
||||
);
|
||||
}
|
||||
|
||||
match self.writer.take() {
|
||||
None if self.finished => proxmox_lang::io_bail!(
|
||||
"multi-volume writer already finished: internal error"),
|
||||
None if self.finished => {
|
||||
proxmox_lang::io_bail!("multi-volume writer already finished: internal error")
|
||||
}
|
||||
None => Ok(false),
|
||||
Some(ref mut writer) => {
|
||||
self.finished = true;
|
||||
@ -129,5 +130,4 @@ impl <'a> TapeWrite for MultiVolumeWriter<'a> {
|
||||
fn logical_end_of_media(&self) -> bool {
|
||||
self.got_leom
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -5,17 +5,10 @@ use std::task::{Context, Poll};
|
||||
use proxmox_sys::error::SysError;
|
||||
use proxmox_uuid::Uuid;
|
||||
|
||||
use pbs_tape::{
|
||||
PROXMOX_TAPE_BLOCK_SIZE,
|
||||
TapeWrite, MediaContentHeader,
|
||||
};
|
||||
use pbs_datastore::SnapshotReader;
|
||||
use pbs_tape::{MediaContentHeader, TapeWrite, PROXMOX_TAPE_BLOCK_SIZE};
|
||||
|
||||
use crate::tape::file_formats::{
|
||||
PROXMOX_BACKUP_SNAPSHOT_ARCHIVE_MAGIC_1_1,
|
||||
SnapshotArchiveHeader,
|
||||
};
|
||||
|
||||
use crate::tape::file_formats::{SnapshotArchiveHeader, PROXMOX_BACKUP_SNAPSHOT_ARCHIVE_MAGIC_1_1};
|
||||
|
||||
/// Write a set of files as `pxar` archive to the tape
|
||||
///
|
||||
@ -29,17 +22,20 @@ pub fn tape_write_snapshot_archive<'a>(
|
||||
writer: &mut (dyn TapeWrite + 'a),
|
||||
snapshot_reader: &SnapshotReader,
|
||||
) -> Result<Option<Uuid>, std::io::Error> {
|
||||
|
||||
let snapshot = snapshot_reader.snapshot().to_string();
|
||||
let store = snapshot_reader.datastore_name().to_string();
|
||||
let file_list = snapshot_reader.file_list();
|
||||
|
||||
let archive_header = SnapshotArchiveHeader { snapshot, store };
|
||||
|
||||
let header_data = serde_json::to_string_pretty(&archive_header)?.as_bytes().to_vec();
|
||||
let header_data = serde_json::to_string_pretty(&archive_header)?
|
||||
.as_bytes()
|
||||
.to_vec();
|
||||
|
||||
let header = MediaContentHeader::new(
|
||||
PROXMOX_BACKUP_SNAPSHOT_ARCHIVE_MAGIC_1_1, header_data.len() as u32);
|
||||
PROXMOX_BACKUP_SNAPSHOT_ARCHIVE_MAGIC_1_1,
|
||||
header_data.len() as u32,
|
||||
);
|
||||
let content_uuid = header.uuid.into();
|
||||
|
||||
let root_metadata = pxar::Metadata::dir_builder(0o0664).build();
|
||||
@ -47,18 +43,20 @@ pub fn tape_write_snapshot_archive<'a>(
|
||||
let mut file_copy_buffer = proxmox_io::vec::undefined(PROXMOX_TAPE_BLOCK_SIZE);
|
||||
|
||||
let result: Result<(), std::io::Error> = proxmox_lang::try_block!({
|
||||
|
||||
let leom = writer.write_header(&header, &header_data)?;
|
||||
if leom {
|
||||
return Err(std::io::Error::from_raw_os_error(nix::errno::Errno::ENOSPC as i32));
|
||||
return Err(std::io::Error::from_raw_os_error(
|
||||
nix::errno::Errno::ENOSPC as i32,
|
||||
));
|
||||
}
|
||||
|
||||
let mut encoder = pxar::encoder::sync::Encoder::new(PxarTapeWriter::new(writer), &root_metadata)?;
|
||||
let mut encoder =
|
||||
pxar::encoder::sync::Encoder::new(PxarTapeWriter::new(writer), &root_metadata)?;
|
||||
|
||||
for filename in file_list.iter() {
|
||||
|
||||
let mut file = snapshot_reader.open_file(filename)
|
||||
.map_err(|err| proxmox_lang::io_format_err!("open file '{}' failed - {}", filename, err))?;
|
||||
let mut file = snapshot_reader.open_file(filename).map_err(|err| {
|
||||
proxmox_lang::io_format_err!("open file '{}' failed - {}", filename, err)
|
||||
})?;
|
||||
let metadata = file.metadata()?;
|
||||
let file_size = metadata.len();
|
||||
|
||||
@ -77,7 +75,6 @@ pub fn tape_write_snapshot_archive<'a>(
|
||||
}
|
||||
out.write_all(&file_copy_buffer[..got])?;
|
||||
remaining -= got as u64;
|
||||
|
||||
}
|
||||
if remaining > 0 {
|
||||
proxmox_lang::io_bail!("file '{}' shrunk while reading", filename);
|
||||
@ -117,7 +114,6 @@ impl<'a, T: TapeWrite + ?Sized> PxarTapeWriter<'a, T> {
|
||||
}
|
||||
|
||||
impl<'a, T: TapeWrite + ?Sized> pxar::encoder::SeqWrite for PxarTapeWriter<'a, T> {
|
||||
|
||||
fn poll_seq_write(
|
||||
self: Pin<&mut Self>,
|
||||
_cx: &mut Context,
|
||||
@ -127,7 +123,9 @@ impl<'a, T: TapeWrite + ?Sized> pxar::encoder::SeqWrite for PxarTapeWriter<'a, T
|
||||
Poll::Ready(match this.inner.write_all(buf) {
|
||||
Ok(leom) => {
|
||||
if leom {
|
||||
Err(std::io::Error::from_raw_os_error(nix::errno::Errno::ENOSPC as i32))
|
||||
Err(std::io::Error::from_raw_os_error(
|
||||
nix::errno::Errno::ENOSPC as i32,
|
||||
))
|
||||
} else {
|
||||
Ok(buf.len())
|
||||
}
|
||||
|
Reference in New Issue
Block a user