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)
 | 
			
		||||
            .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 snapshot in content.snapshot_index.keys() {
 | 
			
		||||
 | 
			
		||||
@ -213,6 +213,17 @@ pub struct SnapshotArchiveHeader {
 | 
			
		||||
    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)]
 | 
			
		||||
/// Media Label
 | 
			
		||||
///
 | 
			
		||||
 | 
			
		||||
@ -26,6 +26,7 @@ use crate::{
 | 
			
		||||
    backup::BackupDir,
 | 
			
		||||
    tape::{
 | 
			
		||||
        MediaId,
 | 
			
		||||
        file_formats::MediaSetLabel,
 | 
			
		||||
    },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -136,11 +137,13 @@ impl MediaCatalog {
 | 
			
		||||
    /// Open a catalog database, load into memory
 | 
			
		||||
    pub fn open(
 | 
			
		||||
        base_path: &Path,
 | 
			
		||||
        uuid: &Uuid,
 | 
			
		||||
        media_id: &MediaId,
 | 
			
		||||
        write: bool,
 | 
			
		||||
        create: bool,
 | 
			
		||||
    ) -> Result<Self, Error> {
 | 
			
		||||
 | 
			
		||||
        let uuid = &media_id.label.uuid;
 | 
			
		||||
 | 
			
		||||
        let mut path = base_path.to_owned();
 | 
			
		||||
        path.push(uuid.to_string());
 | 
			
		||||
        path.set_extension("log");
 | 
			
		||||
@ -169,7 +172,7 @@ impl MediaCatalog {
 | 
			
		||||
                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 {
 | 
			
		||||
                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.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 {
 | 
			
		||||
                me.register_label(&set.uuid, 1)?;
 | 
			
		||||
                me.register_label(&set.uuid, set.seq_nr, 1)?;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            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 {
 | 
			
		||||
            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() {
 | 
			
		||||
            bail!("register label failed: inside chunk archive");
 | 
			
		||||
        }
 | 
			
		||||
@ -389,15 +396,21 @@ impl MediaCatalog {
 | 
			
		||||
    /// Register media labels (file 0 and 1)
 | 
			
		||||
    pub fn register_label(
 | 
			
		||||
        &mut self,
 | 
			
		||||
        uuid: &Uuid, // Uuid form MediaContentHeader
 | 
			
		||||
        uuid: &Uuid, // Media/MediaSet Uuid
 | 
			
		||||
        seq_nr: u64, // onyl used for media set labels
 | 
			
		||||
        file_number: u64,
 | 
			
		||||
    ) -> 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 {
 | 
			
		||||
            file_number,
 | 
			
		||||
            uuid: *uuid.as_bytes(),
 | 
			
		||||
            seq_nr,
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        if self.log_to_stdout {
 | 
			
		||||
@ -608,7 +621,11 @@ impl MediaCatalog {
 | 
			
		||||
        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 found_magic_number = false;
 | 
			
		||||
@ -713,7 +730,18 @@ impl MediaCatalog {
 | 
			
		||||
                    let file_number = entry.file_number;
 | 
			
		||||
                    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));
 | 
			
		||||
                }
 | 
			
		||||
@ -789,6 +817,7 @@ impl MediaSetCatalog {
 | 
			
		||||
struct LabelEntry {
 | 
			
		||||
    file_number: u64,
 | 
			
		||||
    uuid: [u8;16],
 | 
			
		||||
    seq_nr: u64, // only used for media set labels
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Endian)]
 | 
			
		||||
 | 
			
		||||
@ -253,9 +253,10 @@ impl PoolWriter {
 | 
			
		||||
 | 
			
		||||
        // load all catalogs read-only at start
 | 
			
		||||
        for media_uuid in pool.current_media_list()? {
 | 
			
		||||
            let media_info = pool.lookup_media(media_uuid).unwrap();
 | 
			
		||||
            let media_catalog = MediaCatalog::open(
 | 
			
		||||
                Path::new(TAPE_STATUS_DIR),
 | 
			
		||||
                &media_uuid,
 | 
			
		||||
                media_info.id(),
 | 
			
		||||
                false,
 | 
			
		||||
                false,
 | 
			
		||||
            )?;
 | 
			
		||||
@ -655,7 +656,7 @@ fn update_media_set_label(
 | 
			
		||||
                if new_set.encryption_key_fingerprint != media_set_label.encryption_key_fingerprint {
 | 
			
		||||
                    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 {
 | 
			
		||||
                worker.log(
 | 
			
		||||
                    format!("wrinting new media set label (overwrite '{}/{}')",
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user