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:
		@ -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 '{}/{}')",
 | 
				
			||||||
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user