tape: improve catalog consistency checks
Try to check if we read the correct catalog by verifying uuid, media_set_uuid and seq_nr. Note: this changes the catalog format again.
This commit is contained in:
parent
caf76ec592
commit
237314ad0d
|
@ -432,7 +432,7 @@ pub fn list_content(
|
||||||
.generate_media_set_name(&set.uuid, template)
|
.generate_media_set_name(&set.uuid, template)
|
||||||
.unwrap_or_else(|_| set.uuid.to_string());
|
.unwrap_or_else(|_| set.uuid.to_string());
|
||||||
|
|
||||||
let catalog = MediaCatalog::open(status_path, &media_id.label.uuid, false, false)?;
|
let catalog = MediaCatalog::open(status_path, &media_id, false, false)?;
|
||||||
|
|
||||||
for (store, content) in catalog.content() {
|
for (store, content) in catalog.content() {
|
||||||
for snapshot in content.snapshot_index.keys() {
|
for snapshot in content.snapshot_index.keys() {
|
||||||
|
|
|
@ -213,6 +213,17 @@ pub struct SnapshotArchiveHeader {
|
||||||
pub store: String,
|
pub store: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Serialize)]
|
||||||
|
/// Header for Catalog archives
|
||||||
|
pub struct CatalogArchiveHeader {
|
||||||
|
/// The uuid of the media the catalog is for
|
||||||
|
pub uuid: Uuid,
|
||||||
|
/// The media set uuid the catalog is for
|
||||||
|
pub media_set_uuid: Uuid,
|
||||||
|
/// Media sequence number
|
||||||
|
pub seq_nr: u64,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Serialize,Deserialize,Clone,Debug)]
|
#[derive(Serialize,Deserialize,Clone,Debug)]
|
||||||
/// Media Label
|
/// Media Label
|
||||||
///
|
///
|
||||||
|
|
|
@ -26,6 +26,7 @@ use crate::{
|
||||||
backup::BackupDir,
|
backup::BackupDir,
|
||||||
tape::{
|
tape::{
|
||||||
MediaId,
|
MediaId,
|
||||||
|
file_formats::MediaSetLabel,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -136,11 +137,13 @@ impl MediaCatalog {
|
||||||
/// Open a catalog database, load into memory
|
/// Open a catalog database, load into memory
|
||||||
pub fn open(
|
pub fn open(
|
||||||
base_path: &Path,
|
base_path: &Path,
|
||||||
uuid: &Uuid,
|
media_id: &MediaId,
|
||||||
write: bool,
|
write: bool,
|
||||||
create: bool,
|
create: bool,
|
||||||
) -> Result<Self, Error> {
|
) -> Result<Self, Error> {
|
||||||
|
|
||||||
|
let uuid = &media_id.label.uuid;
|
||||||
|
|
||||||
let mut path = base_path.to_owned();
|
let mut path = base_path.to_owned();
|
||||||
path.push(uuid.to_string());
|
path.push(uuid.to_string());
|
||||||
path.set_extension("log");
|
path.set_extension("log");
|
||||||
|
@ -169,7 +172,7 @@ impl MediaCatalog {
|
||||||
pending: Vec::new(),
|
pending: Vec::new(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let found_magic_number = me.load_catalog(&mut file)?;
|
let found_magic_number = me.load_catalog(&mut file, media_id.media_set_label.as_ref())?;
|
||||||
|
|
||||||
if !found_magic_number {
|
if !found_magic_number {
|
||||||
me.pending.extend(&Self::PROXMOX_BACKUP_MEDIA_CATALOG_MAGIC_1_1);
|
me.pending.extend(&Self::PROXMOX_BACKUP_MEDIA_CATALOG_MAGIC_1_1);
|
||||||
|
@ -230,10 +233,10 @@ impl MediaCatalog {
|
||||||
|
|
||||||
me.pending.extend(&Self::PROXMOX_BACKUP_MEDIA_CATALOG_MAGIC_1_1);
|
me.pending.extend(&Self::PROXMOX_BACKUP_MEDIA_CATALOG_MAGIC_1_1);
|
||||||
|
|
||||||
me.register_label(&media_id.label.uuid, 0)?;
|
me.register_label(&media_id.label.uuid, 0, 0)?;
|
||||||
|
|
||||||
if let Some(ref set) = media_id.media_set_label {
|
if let Some(ref set) = media_id.media_set_label {
|
||||||
me.register_label(&set.uuid, 1)?;
|
me.register_label(&set.uuid, set.seq_nr, 1)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
me.commit()?;
|
me.commit()?;
|
||||||
|
@ -364,12 +367,16 @@ impl MediaCatalog {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_register_label(&self, file_number: u64) -> Result<(), Error> {
|
fn check_register_label(&self, file_number: u64, uuid: &Uuid) -> Result<(), Error> {
|
||||||
|
|
||||||
if file_number >= 2 {
|
if file_number >= 2 {
|
||||||
bail!("register label failed: got wrong file number ({} >= 2)", file_number);
|
bail!("register label failed: got wrong file number ({} >= 2)", file_number);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if file_number == 0 && uuid != &self.uuid {
|
||||||
|
bail!("register label failed: uuid does not match");
|
||||||
|
}
|
||||||
|
|
||||||
if self.current_archive.is_some() {
|
if self.current_archive.is_some() {
|
||||||
bail!("register label failed: inside chunk archive");
|
bail!("register label failed: inside chunk archive");
|
||||||
}
|
}
|
||||||
|
@ -389,15 +396,21 @@ impl MediaCatalog {
|
||||||
/// Register media labels (file 0 and 1)
|
/// Register media labels (file 0 and 1)
|
||||||
pub fn register_label(
|
pub fn register_label(
|
||||||
&mut self,
|
&mut self,
|
||||||
uuid: &Uuid, // Uuid form MediaContentHeader
|
uuid: &Uuid, // Media/MediaSet Uuid
|
||||||
|
seq_nr: u64, // onyl used for media set labels
|
||||||
file_number: u64,
|
file_number: u64,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
|
|
||||||
self.check_register_label(file_number)?;
|
self.check_register_label(file_number, uuid)?;
|
||||||
|
|
||||||
|
if file_number == 0 && seq_nr != 0 {
|
||||||
|
bail!("register_label failed - seq_nr should be 0 - iternal error");
|
||||||
|
}
|
||||||
|
|
||||||
let entry = LabelEntry {
|
let entry = LabelEntry {
|
||||||
file_number,
|
file_number,
|
||||||
uuid: *uuid.as_bytes(),
|
uuid: *uuid.as_bytes(),
|
||||||
|
seq_nr,
|
||||||
};
|
};
|
||||||
|
|
||||||
if self.log_to_stdout {
|
if self.log_to_stdout {
|
||||||
|
@ -608,7 +621,11 @@ impl MediaCatalog {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_catalog(&mut self, file: &mut File) -> Result<bool, Error> {
|
fn load_catalog(
|
||||||
|
&mut self,
|
||||||
|
file: &mut File,
|
||||||
|
media_set_label: Option<&MediaSetLabel>,
|
||||||
|
) -> Result<bool, Error> {
|
||||||
|
|
||||||
let mut file = BufReader::new(file);
|
let mut file = BufReader::new(file);
|
||||||
let mut found_magic_number = false;
|
let mut found_magic_number = false;
|
||||||
|
@ -713,7 +730,18 @@ impl MediaCatalog {
|
||||||
let file_number = entry.file_number;
|
let file_number = entry.file_number;
|
||||||
let uuid = Uuid::from(entry.uuid);
|
let uuid = Uuid::from(entry.uuid);
|
||||||
|
|
||||||
self.check_register_label(file_number)?;
|
self.check_register_label(file_number, &uuid)?;
|
||||||
|
|
||||||
|
if file_number == 1 {
|
||||||
|
if let Some(set) = media_set_label {
|
||||||
|
if set.uuid != uuid {
|
||||||
|
bail!("got unexpected media set uuid");
|
||||||
|
}
|
||||||
|
if set.seq_nr != entry.seq_nr {
|
||||||
|
bail!("got unexpected media set sequence number");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
self.last_entry = Some((uuid, file_number));
|
self.last_entry = Some((uuid, file_number));
|
||||||
}
|
}
|
||||||
|
@ -789,6 +817,7 @@ impl MediaSetCatalog {
|
||||||
struct LabelEntry {
|
struct LabelEntry {
|
||||||
file_number: u64,
|
file_number: u64,
|
||||||
uuid: [u8;16],
|
uuid: [u8;16],
|
||||||
|
seq_nr: u64, // only used for media set labels
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Endian)]
|
#[derive(Endian)]
|
||||||
|
|
|
@ -253,9 +253,10 @@ impl PoolWriter {
|
||||||
|
|
||||||
// load all catalogs read-only at start
|
// load all catalogs read-only at start
|
||||||
for media_uuid in pool.current_media_list()? {
|
for media_uuid in pool.current_media_list()? {
|
||||||
|
let media_info = pool.lookup_media(media_uuid).unwrap();
|
||||||
let media_catalog = MediaCatalog::open(
|
let media_catalog = MediaCatalog::open(
|
||||||
Path::new(TAPE_STATUS_DIR),
|
Path::new(TAPE_STATUS_DIR),
|
||||||
&media_uuid,
|
media_info.id(),
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
)?;
|
)?;
|
||||||
|
@ -655,7 +656,7 @@ fn update_media_set_label(
|
||||||
if new_set.encryption_key_fingerprint != media_set_label.encryption_key_fingerprint {
|
if new_set.encryption_key_fingerprint != media_set_label.encryption_key_fingerprint {
|
||||||
bail!("detected changed encryption fingerprint - internal error");
|
bail!("detected changed encryption fingerprint - internal error");
|
||||||
}
|
}
|
||||||
media_catalog = MediaCatalog::open(status_path, &media_id.label.uuid, true, false)?;
|
media_catalog = MediaCatalog::open(status_path, &media_id, true, false)?;
|
||||||
} else {
|
} else {
|
||||||
worker.log(
|
worker.log(
|
||||||
format!("wrinting new media set label (overwrite '{}/{}')",
|
format!("wrinting new media set label (overwrite '{}/{}')",
|
||||||
|
|
Loading…
Reference in New Issue