[pbs-devel] [PATCH v6 proxmox-backup 23/29] catalog: use format version 2 conditionally
Christian Ebner
c.ebner at proxmox.com
Thu Jan 25 14:26:02 CET 2024
Only use the catalog format version 2 when performing backups with the
change detection mode set to metadata.
This makes sure to remain compatible with older clients which do not
support the format version 2 at least for backups created using the
regular mode.
Signed-off-by: Christian Ebner <c.ebner at proxmox.com>
---
Changes since v5:
- fix formatting using `cargo fmt`
- changed patch ordering for more logical flow
pbs-datastore/src/catalog.rs | 69 +++++++++++++++++++++++++------
proxmox-backup-client/src/main.rs | 30 ++++++++++----
2 files changed, 80 insertions(+), 19 deletions(-)
diff --git a/pbs-datastore/src/catalog.rs b/pbs-datastore/src/catalog.rs
index 220313c6..0ca2ce23 100644
--- a/pbs-datastore/src/catalog.rs
+++ b/pbs-datastore/src/catalog.rs
@@ -64,6 +64,12 @@ pub enum CatalogEntryType {
Socket = b's',
}
+#[derive(PartialEq)]
+pub enum CatalogFormatVersion {
+ V1,
+ V2,
+}
+
impl TryFrom<u8> for CatalogEntryType {
type Error = Error;
@@ -555,17 +561,22 @@ pub struct CatalogWriter<W> {
writer: W,
dirstack: Vec<DirInfo>,
pos: u64,
+ version: CatalogFormatVersion,
}
impl<W: Write> CatalogWriter<W> {
/// Create a new CatalogWriter instance
- pub fn new(writer: W) -> Result<Self, Error> {
+ pub fn new(writer: W, version: CatalogFormatVersion) -> Result<Self, Error> {
let mut me = Self {
writer,
dirstack: vec![DirInfo::new_rootdir()],
pos: 0,
+ version,
};
- me.write_all(&PROXMOX_CATALOG_FILE_MAGIC_2_0)?;
+ match me.version {
+ CatalogFormatVersion::V1 => me.write_all(&PROXMOX_CATALOG_FILE_MAGIC_1_0)?,
+ CatalogFormatVersion::V2 => me.write_all(&PROXMOX_CATALOG_FILE_MAGIC_2_0)?,
+ }
Ok(me)
}
@@ -599,6 +610,10 @@ impl<W: Write> CatalogWriter<W> {
impl<W: Write> BackupCatalogWriter for CatalogWriter<W> {
fn start_archive(&mut self, name: &CStr) -> Result<(), Error> {
+ if self.version == CatalogFormatVersion::V1 {
+ return self.start_directory(name);
+ }
+
let new = DirInfo::new(name.to_owned());
self.dirstack.push(new);
Ok(())
@@ -608,6 +623,9 @@ impl<W: Write> BackupCatalogWriter for CatalogWriter<W> {
&mut self,
appendix: Option<pxar::encoder::AppendixStartOffset>,
) -> Result<(), Error> {
+ if self.version == CatalogFormatVersion::V1 {
+ return self.end_directory();
+ }
let (start, name) = match self.dirstack.pop() {
Some(dir) => {
let start = self.pos;
@@ -688,17 +706,30 @@ impl<W: Write> BackupCatalogWriter for CatalogWriter<W> {
.last_mut()
.ok_or_else(|| format_err!("outside root"))?;
let name = name.to_bytes().to_vec();
- let file_offset = FileOffset {
- offset: file_offset.raw(),
- };
- dir.entries.push(DirEntry {
- name,
- attr: DirEntryAttribute::File {
- size,
- mtime,
- extension: Some(CatalogV2Extension { ctime, file_offset }),
+ let entry = match self.version {
+ CatalogFormatVersion::V1 => DirEntry {
+ name,
+ attr: DirEntryAttribute::File {
+ size,
+ mtime,
+ extension: None,
+ },
},
- });
+ CatalogFormatVersion::V2 => {
+ let file_offset = FileOffset {
+ offset: file_offset.raw(),
+ };
+ DirEntry {
+ name,
+ attr: DirEntryAttribute::File {
+ size,
+ mtime,
+ extension: Some(CatalogV2Extension { ctime, file_offset }),
+ },
+ }
+ }
+ };
+ dir.entries.push(entry);
Ok(())
}
@@ -710,6 +741,9 @@ impl<W: Write> BackupCatalogWriter for CatalogWriter<W> {
ctime: i64,
appendix_ref_offset: pxar::encoder::AppendixRefOffset,
) -> Result<(), Error> {
+ if self.version == CatalogFormatVersion::V1 {
+ bail!("unsupported by catalog format version 1");
+ }
let dir = self
.dirstack
.last_mut()
@@ -856,6 +890,17 @@ impl<R: Read + Seek> CatalogReader<R> {
})
}
+ pub fn format_version(&mut self) -> Result<CatalogFormatVersion, Error> {
+ self.reader.seek(SeekFrom::Start(0))?;
+ let mut magic = [0u8; 8];
+ self.reader.read_exact(&mut magic)?;
+ match magic {
+ PROXMOX_CATALOG_FILE_MAGIC_1_0 => Ok(CatalogFormatVersion::V1),
+ PROXMOX_CATALOG_FILE_MAGIC_2_0 => Ok(CatalogFormatVersion::V2),
+ _ => bail!("got unexpected magic number for catalog"),
+ }
+ }
+
pub fn appendix_offset(
&mut self,
archive_name: &[u8],
diff --git a/proxmox-backup-client/src/main.rs b/proxmox-backup-client/src/main.rs
index 470399e8..0a3f24c0 100644
--- a/proxmox-backup-client/src/main.rs
+++ b/proxmox-backup-client/src/main.rs
@@ -49,7 +49,7 @@ use pbs_client::{
BackupStats, BackupWriter, ChunkStream, FixedChunkStream, HttpClient, PxarBackupStream,
RemoteChunkReader, UploadOptions, BACKUP_DETECTION_MODE_SPEC, BACKUP_SOURCE_SCHEMA,
};
-use pbs_datastore::catalog::{CatalogReader, CatalogWriter};
+use pbs_datastore::catalog::{CatalogFormatVersion, CatalogReader, CatalogWriter};
use pbs_datastore::chunk_store::verify_chunk_size;
use pbs_datastore::dynamic_index::{BufferedDynamicReader, DynamicIndexReader};
use pbs_datastore::fixed_index::FixedIndexReader;
@@ -536,6 +536,7 @@ struct CatalogUploadResult {
fn spawn_catalog_upload(
client: Arc<BackupWriter>,
encrypt: bool,
+ catalog_format_version: CatalogFormatVersion,
) -> Result<CatalogUploadResult, Error> {
let (catalog_tx, catalog_rx) = std::sync::mpsc::sync_channel(10); // allow to buffer 10 writes
let catalog_stream = proxmox_async::blocking::StdChannelStream(catalog_rx);
@@ -549,9 +550,10 @@ fn spawn_catalog_upload(
injections.clone(),
);
- let catalog_writer = Arc::new(Mutex::new(CatalogWriter::new(TokioWriterAdapter::new(
- StdChannelWriter::new(catalog_tx),
- ))?));
+ let catalog_writer = Arc::new(Mutex::new(CatalogWriter::new(
+ TokioWriterAdapter::new(StdChannelWriter::new(catalog_tx)),
+ catalog_format_version,
+ )?));
let (catalog_result_tx, catalog_result_rx) = tokio::sync::oneshot::channel();
@@ -1015,8 +1017,17 @@ async fn create_backup(
(BackupSpecificationType::PXAR, false) => {
// start catalog upload on first use
if catalog.is_none() {
- let catalog_upload_res =
- spawn_catalog_upload(client.clone(), crypto.mode == CryptMode::Encrypt)?;
+ let catalog_format_version =
+ if let BackupDetectionMode::Metadata(_) = detection_mode {
+ CatalogFormatVersion::V2
+ } else {
+ CatalogFormatVersion::V1
+ };
+ let catalog_upload_res = spawn_catalog_upload(
+ client.clone(),
+ crypto.mode == CryptMode::Encrypt,
+ catalog_format_version,
+ )?;
catalog = Some(catalog_upload_res.catalog_writer);
catalog_result_rx = Some(catalog_upload_res.result);
}
@@ -1215,8 +1226,13 @@ async fn download_reference_catalog(
.map_err(|err| format_err!("failed to download reference catalog - {}", err))?;
catalogfile.seek(SeekFrom::Start(0))?;
+ let mut reader = CatalogReader::new(catalogfile);
- Ok(CatalogReader::new(catalogfile))
+ match reader.format_version() {
+ Ok(CatalogFormatVersion::V2) => Ok(reader),
+ Ok(CatalogFormatVersion::V1) => Err(format_err!("unsupported catalog format version")),
+ Err(err) => Err(err),
+ }
}
async fn dump_image<W: Write>(
--
2.39.2
More information about the pbs-devel
mailing list