[pbs-devel] [PATCH proxmox-backup 5/8] api: datastore: add optional archive-name to file-restore

Christian Ebner c.ebner at proxmox.com
Fri Jun 7 11:43:10 CEST 2024


Allow to pass the archive name as optional api call parameter instead
of having it as prefix to the path.
If this parameter is given, instead of splitting of the archive name
from the path, the parameter itself is used, leaving the path
untouched.

This allows to restore single files from the archive, without having
to artificially construct the path in case of file restores for split
pxar archives, where the response path of the listing does not
include the archive, as opposed to the response provided by lookup
via the catalog.

Signed-off-by: Christian Ebner <c.ebner at proxmox.com>
---
 src/api2/admin/datastore.rs | 17 +++++++++++++----
 1 file changed, 13 insertions(+), 4 deletions(-)

diff --git a/src/api2/admin/datastore.rs b/src/api2/admin/datastore.rs
index e25a78bca..d33422d13 100644
--- a/src/api2/admin/datastore.rs
+++ b/src/api2/admin/datastore.rs
@@ -1773,6 +1773,7 @@ pub const API_METHOD_PXAR_FILE_DOWNLOAD: ApiMethod = ApiMethod::new(
             ("backup-time", false, &BACKUP_TIME_SCHEMA),
             ("filepath", false, &StringSchema::new("Base64 encoded path").schema()),
             ("tar", true, &BooleanSchema::new("Download as .tar.zst").schema()),
+            ("archive-name", true, &StringSchema::new("Base64 encoded archive name").schema()),
         ]),
     )
 ).access(
@@ -1840,9 +1841,17 @@ pub fn pxar_file_download(
             components.remove(0);
         }
 
-        let mut split = components.splitn(2, |c| *c == b'/');
-        let pxar_name = std::str::from_utf8(split.next().unwrap())?;
-        let file_path = split.next().unwrap_or(b"/");
+        let (pxar_name, file_path) = if let Some(archive_name) = param["archive-name"].as_str() {
+            let archive_name = base64::decode(archive_name)
+                .map_err(|err| format_err!("base64 decode of archive-name failed - {err}"))?;
+            (archive_name, base64::decode(&filepath)?)
+        } else {
+            let mut split = components.splitn(2, |c| *c == b'/');
+            let pxar_name = split.next().unwrap();
+            let file_path = split.next().unwrap_or(b"/");
+            (pxar_name.to_owned(), file_path.to_owned())
+        };
+        let pxar_name = std::str::from_utf8(&pxar_name)?;
         let (manifest, files) = read_backup_index(&backup_dir)?;
         for file in files {
             if file.filename == pxar_name && file.crypt_mode == Some(CryptMode::Encrypt) {
@@ -1865,7 +1874,7 @@ pub fn pxar_file_download(
         let decoder = Accessor::new(reader, archive_size).await?;
 
         let root = decoder.open_root().await?;
-        let path = OsStr::from_bytes(file_path).to_os_string();
+        let path = OsStr::from_bytes(&file_path).to_os_string();
         let file = root
             .lookup(&path)
             .await?
-- 
2.39.2





More information about the pbs-devel mailing list