tape: improve file format docu
This commit is contained in:
parent
af07ec8f29
commit
410611b4f2
@ -29,6 +29,7 @@ pub const PROXMOX_BACKUP_CHUNK_ARCHIVE_ENTRY_MAGIC_1_0: [u8; 8] = [72, 87, 109,
|
|||||||
pub const PROXMOX_BACKUP_SNAPSHOT_ARCHIVE_MAGIC_1_0: [u8; 8] = [9, 182, 2, 31, 125, 232, 114, 133];
|
pub const PROXMOX_BACKUP_SNAPSHOT_ARCHIVE_MAGIC_1_0: [u8; 8] = [9, 182, 2, 31, 125, 232, 114, 133];
|
||||||
|
|
||||||
lazy_static::lazy_static!{
|
lazy_static::lazy_static!{
|
||||||
|
/// Map content Uuid to human readable names.
|
||||||
pub static ref PROXMOX_BACKUP_CONTENT_NAME: HashMap<&'static [u8;8], &'static str> = {
|
pub static ref PROXMOX_BACKUP_CONTENT_NAME: HashMap<&'static [u8;8], &'static str> = {
|
||||||
let mut map = HashMap::new();
|
let mut map = HashMap::new();
|
||||||
map.insert(&PROXMOX_BACKUP_DRIVE_LABEL_MAGIC_1_0, "Proxmox Backup Tape Label v1.0");
|
map.insert(&PROXMOX_BACKUP_DRIVE_LABEL_MAGIC_1_0, "Proxmox Backup Tape Label v1.0");
|
||||||
@ -41,6 +42,8 @@ lazy_static::lazy_static!{
|
|||||||
|
|
||||||
/// Tape Block Header with data payload
|
/// Tape Block Header with data payload
|
||||||
///
|
///
|
||||||
|
/// All tape files are written as sequence of blocks.
|
||||||
|
///
|
||||||
/// Note: this struct is large, never put this on the stack!
|
/// Note: this struct is large, never put this on the stack!
|
||||||
/// so we use an unsized type to avoid that.
|
/// so we use an unsized type to avoid that.
|
||||||
///
|
///
|
||||||
@ -51,6 +54,7 @@ lazy_static::lazy_static!{
|
|||||||
/// error checking.
|
/// error checking.
|
||||||
#[repr(C,packed)]
|
#[repr(C,packed)]
|
||||||
pub struct BlockHeader {
|
pub struct BlockHeader {
|
||||||
|
/// fixed value 'PROXMOX_TAPE_BLOCK_HEADER_MAGIC_1_0'
|
||||||
pub magic: [u8; 8],
|
pub magic: [u8; 8],
|
||||||
pub flags: BlockHeaderFlags,
|
pub flags: BlockHeaderFlags,
|
||||||
/// size as 3 bytes unsigned, little endian
|
/// size as 3 bytes unsigned, little endian
|
||||||
@ -69,30 +73,40 @@ bitflags! {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Endian)]
|
|
||||||
#[repr(C,packed)]
|
|
||||||
pub struct ChunkArchiveEntryHeader {
|
|
||||||
pub magic: [u8; 8],
|
|
||||||
pub digest: [u8; 32],
|
|
||||||
pub size: u64,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Endian, Copy, Clone, Debug)]
|
#[derive(Endian, Copy, Clone, Debug)]
|
||||||
#[repr(C,packed)]
|
#[repr(C,packed)]
|
||||||
|
/// Media Content Header
|
||||||
|
///
|
||||||
|
/// All tape files start with this header. The header may contain some
|
||||||
|
/// informational data indicated by 'size'.
|
||||||
|
///
|
||||||
|
/// '| MediaContentHeader | header data (size) | stream data |'
|
||||||
|
///
|
||||||
|
/// Note: The stream data following may be of any size.
|
||||||
pub struct MediaContentHeader {
|
pub struct MediaContentHeader {
|
||||||
|
/// fixed value 'PROXMOX_BACKUP_CONTENT_HEADER_MAGIC_1_0'
|
||||||
pub magic: [u8; 8],
|
pub magic: [u8; 8],
|
||||||
|
/// magic number for the content following
|
||||||
pub content_magic: [u8; 8],
|
pub content_magic: [u8; 8],
|
||||||
|
/// unique ID to identify this data stream
|
||||||
pub uuid: [u8; 16],
|
pub uuid: [u8; 16],
|
||||||
|
/// stream creation time
|
||||||
pub ctime: i64,
|
pub ctime: i64,
|
||||||
|
/// Size of header data
|
||||||
pub size: u32,
|
pub size: u32,
|
||||||
|
/// Part number for multipart archives.
|
||||||
pub part_number: u8,
|
pub part_number: u8,
|
||||||
|
/// Reserved for future use
|
||||||
pub reserved_0: u8,
|
pub reserved_0: u8,
|
||||||
|
/// Reserved for future use
|
||||||
pub reserved_1: u8,
|
pub reserved_1: u8,
|
||||||
|
/// Reserved for future use
|
||||||
pub reserved_2: u8,
|
pub reserved_2: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MediaContentHeader {
|
impl MediaContentHeader {
|
||||||
|
|
||||||
|
/// Create a new instance with autogenerated Uuid
|
||||||
pub fn new(content_magic: [u8; 8], size: u32) -> Self {
|
pub fn new(content_magic: [u8; 8], size: u32) -> Self {
|
||||||
let uuid = *proxmox::tools::uuid::Uuid::generate()
|
let uuid = *proxmox::tools::uuid::Uuid::generate()
|
||||||
.into_inner();
|
.into_inner();
|
||||||
@ -109,6 +123,7 @@ impl MediaContentHeader {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Helper to check magic numbers and size constraints
|
||||||
pub fn check(&self, content_magic: [u8; 8], min_size: u32, max_size: u32) -> Result<(), Error> {
|
pub fn check(&self, content_magic: [u8; 8], min_size: u32, max_size: u32) -> Result<(), Error> {
|
||||||
if self.magic != PROXMOX_BACKUP_CONTENT_HEADER_MAGIC_1_0 {
|
if self.magic != PROXMOX_BACKUP_CONTENT_HEADER_MAGIC_1_0 {
|
||||||
bail!("MediaContentHeader: wrong magic");
|
bail!("MediaContentHeader: wrong magic");
|
||||||
@ -122,12 +137,25 @@ impl MediaContentHeader {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the content Uuid
|
||||||
pub fn content_uuid(&self) -> Uuid {
|
pub fn content_uuid(&self) -> Uuid {
|
||||||
Uuid::from(self.uuid)
|
Uuid::from(self.uuid)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Endian)]
|
||||||
|
#[repr(C,packed)]
|
||||||
|
pub struct ChunkArchiveEntryHeader {
|
||||||
|
pub magic: [u8; 8],
|
||||||
|
pub digest: [u8; 32],
|
||||||
|
pub size: u64,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Serialize,Deserialize,Clone,Debug)]
|
#[derive(Serialize,Deserialize,Clone,Debug)]
|
||||||
|
/// Drive Label
|
||||||
|
///
|
||||||
|
/// Drive Labels are used to uniquely identify a media. They are
|
||||||
|
/// stored as first file on the tape.
|
||||||
pub struct DriveLabel {
|
pub struct DriveLabel {
|
||||||
/// Unique ID
|
/// Unique ID
|
||||||
pub uuid: Uuid,
|
pub uuid: Uuid,
|
||||||
@ -139,7 +167,12 @@ pub struct DriveLabel {
|
|||||||
|
|
||||||
|
|
||||||
#[derive(Serialize,Deserialize,Clone,Debug)]
|
#[derive(Serialize,Deserialize,Clone,Debug)]
|
||||||
|
/// MediaSet Label
|
||||||
|
///
|
||||||
|
/// Used to uniquely identify a MediaSet. They are stored as second
|
||||||
|
/// file on the tape.
|
||||||
pub struct MediaSetLabel {
|
pub struct MediaSetLabel {
|
||||||
|
/// The associated MediaPool
|
||||||
pub pool: String,
|
pub pool: String,
|
||||||
/// MediaSet Uuid. We use the all-zero Uuid to reseve an empty media for a specific pool
|
/// MediaSet Uuid. We use the all-zero Uuid to reseve an empty media for a specific pool
|
||||||
pub uuid: Uuid,
|
pub uuid: Uuid,
|
||||||
@ -183,21 +216,24 @@ impl BlockHeader {
|
|||||||
buffer
|
buffer
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set the size
|
||||||
pub fn set_size(&mut self, size: usize) {
|
pub fn set_size(&mut self, size: usize) {
|
||||||
let size = size.to_le_bytes();
|
let size = size.to_le_bytes();
|
||||||
self.size.copy_from_slice(&size[..3]);
|
self.size.copy_from_slice(&size[..3]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the size
|
||||||
pub fn size(&self) -> usize {
|
pub fn size(&self) -> usize {
|
||||||
(self.size[0] as usize) + ((self.size[1] as usize)<<8) + ((self.size[2] as usize)<<16)
|
(self.size[0] as usize) + ((self.size[1] as usize)<<8) + ((self.size[2] as usize)<<16)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set the 'seq_nr' field
|
||||||
pub fn set_seq_nr(&mut self, seq_nr: u32) {
|
pub fn set_seq_nr(&mut self, seq_nr: u32) {
|
||||||
self.seq_nr = seq_nr.to_le();
|
self.seq_nr = seq_nr.to_le();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the 'seq_nr' field
|
||||||
pub fn seq_nr(&self) -> u32 {
|
pub fn seq_nr(&self) -> u32 {
|
||||||
u32::from_le(self.seq_nr)
|
u32::from_le(self.seq_nr)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user