diff --git a/src/tape/file_formats.rs b/src/tape/file_formats.rs index 21e513e6..8b0486c8 100644 --- a/src/tape/file_formats.rs +++ b/src/tape/file_formats.rs @@ -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]; lazy_static::lazy_static!{ + /// Map content Uuid to human readable names. pub static ref PROXMOX_BACKUP_CONTENT_NAME: HashMap<&'static [u8;8], &'static str> = { let mut map = HashMap::new(); 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 /// +/// All tape files are written as sequence of blocks. +/// /// Note: this struct is large, never put this on the stack! /// so we use an unsized type to avoid that. /// @@ -51,6 +54,7 @@ lazy_static::lazy_static!{ /// error checking. #[repr(C,packed)] pub struct BlockHeader { + /// fixed value 'PROXMOX_TAPE_BLOCK_HEADER_MAGIC_1_0' pub magic: [u8; 8], pub flags: BlockHeaderFlags, /// 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)] #[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 { + /// fixed value 'PROXMOX_BACKUP_CONTENT_HEADER_MAGIC_1_0' pub magic: [u8; 8], + /// magic number for the content following pub content_magic: [u8; 8], + /// unique ID to identify this data stream pub uuid: [u8; 16], + /// stream creation time pub ctime: i64, + /// Size of header data pub size: u32, + /// Part number for multipart archives. pub part_number: u8, + /// Reserved for future use pub reserved_0: u8, + /// Reserved for future use pub reserved_1: u8, + /// Reserved for future use pub reserved_2: u8, } impl MediaContentHeader { + /// Create a new instance with autogenerated Uuid pub fn new(content_magic: [u8; 8], size: u32) -> Self { let uuid = *proxmox::tools::uuid::Uuid::generate() .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> { if self.magic != PROXMOX_BACKUP_CONTENT_HEADER_MAGIC_1_0 { bail!("MediaContentHeader: wrong magic"); @@ -122,12 +137,25 @@ impl MediaContentHeader { Ok(()) } + /// Returns the content Uuid pub fn content_uuid(&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)] +/// Drive Label +/// +/// Drive Labels are used to uniquely identify a media. They are +/// stored as first file on the tape. pub struct DriveLabel { /// Unique ID pub uuid: Uuid, @@ -139,7 +167,12 @@ pub struct DriveLabel { #[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 { + /// The associated MediaPool pub pool: String, /// MediaSet Uuid. We use the all-zero Uuid to reseve an empty media for a specific pool pub uuid: Uuid, @@ -183,21 +216,24 @@ impl BlockHeader { buffer } + /// Set the size pub fn set_size(&mut self, size: usize) { let size = size.to_le_bytes(); self.size.copy_from_slice(&size[..3]); } + /// Returns the size pub fn size(&self) -> usize { (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) { self.seq_nr = seq_nr.to_le(); } + /// Returns the 'seq_nr' field pub fn seq_nr(&self) -> u32 { u32::from_le(self.seq_nr) } - }