From mboxrd@z Thu Jan  1 00:00:00 1970
Return-Path: <c.ebner@proxmox.com>
Received: from firstgate.proxmox.com (firstgate.proxmox.com [212.224.123.68])
 (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)
 key-exchange X25519 server-signature RSA-PSS (2048 bits))
 (No client certificate requested)
 by lists.proxmox.com (Postfix) with ESMTPS id 52E3595EE1
 for <pbs-devel@lists.proxmox.com>; Wed, 28 Feb 2024 15:09:49 +0100 (CET)
Received: from firstgate.proxmox.com (localhost [127.0.0.1])
 by firstgate.proxmox.com (Proxmox) with ESMTP id 32065E13E
 for <pbs-devel@lists.proxmox.com>; Wed, 28 Feb 2024 15:09:19 +0100 (CET)
Received: from proxmox-new.maurer-it.com (proxmox-new.maurer-it.com
 [94.136.29.106])
 (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)
 key-exchange X25519 server-signature RSA-PSS (2048 bits))
 (No client certificate requested)
 by firstgate.proxmox.com (Proxmox) with ESMTPS
 for <pbs-devel@lists.proxmox.com>; Wed, 28 Feb 2024 15:09:17 +0100 (CET)
Received: from proxmox-new.maurer-it.com (localhost.localdomain [127.0.0.1])
 by proxmox-new.maurer-it.com (Proxmox) with ESMTP id 0F06A47BBD
 for <pbs-devel@lists.proxmox.com>; Wed, 28 Feb 2024 15:02:50 +0100 (CET)
From: Christian Ebner <c.ebner@proxmox.com>
To: pbs-devel@lists.proxmox.com
Date: Wed, 28 Feb 2024 15:02:08 +0100
Message-Id: <20240228140226.1251979-19-c.ebner@proxmox.com>
X-Mailer: git-send-email 2.39.2
In-Reply-To: <20240228140226.1251979-1-c.ebner@proxmox.com>
References: <20240228140226.1251979-1-c.ebner@proxmox.com>
MIME-Version: 1.0
Content-Transfer-Encoding: 8bit
X-SPAM-LEVEL: Spam detection results:  0
 AWL 0.045 Adjusted score from AWL reputation of From: address
 BAYES_00                 -1.9 Bayes spam probability is 0 to 1%
 DMARC_MISSING             0.1 Missing DMARC policy
 KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment
 SPF_HELO_NONE           0.001 SPF: HELO does not publish an SPF Record
 SPF_PASS               -0.001 SPF: sender matches SPF record
 T_SCC_BODY_TEXT_LINE    -0.01 -
 URIBL_BLOCKED 0.001 ADMINISTRATOR NOTICE: The query to URIBL was blocked. See
 http://wiki.apache.org/spamassassin/DnsBlocklists#dnsbl-block for more
 information. [mount.rs]
Subject: [pbs-devel] [RFC proxmox-backup 18/36] client: mount: make split
 pxar archives mountable
X-BeenThere: pbs-devel@lists.proxmox.com
X-Mailman-Version: 2.1.29
Precedence: list
List-Id: Proxmox Backup Server development discussion
 <pbs-devel.lists.proxmox.com>
List-Unsubscribe: <https://lists.proxmox.com/cgi-bin/mailman/options/pbs-devel>, 
 <mailto:pbs-devel-request@lists.proxmox.com?subject=unsubscribe>
List-Archive: <http://lists.proxmox.com/pipermail/pbs-devel/>
List-Post: <mailto:pbs-devel@lists.proxmox.com>
List-Help: <mailto:pbs-devel-request@lists.proxmox.com?subject=help>
List-Subscribe: <https://lists.proxmox.com/cgi-bin/mailman/listinfo/pbs-devel>, 
 <mailto:pbs-devel-request@lists.proxmox.com?subject=subscribe>
X-List-Received-Date: Wed, 28 Feb 2024 14:09:49 -0000

Cover the cases where the pxar archive was uploaded as split payload
data and metadata streams. Instantiate the required reader and
decoder instances to access the metadata and payload data archives.

Signed-off-by: Christian Ebner <c.ebner@proxmox.com>
---
 proxmox-backup-client/src/mount.rs | 56 ++++++++++++++++++++++--------
 1 file changed, 41 insertions(+), 15 deletions(-)

diff --git a/proxmox-backup-client/src/mount.rs b/proxmox-backup-client/src/mount.rs
index 4a2f8335..c955a7da 100644
--- a/proxmox-backup-client/src/mount.rs
+++ b/proxmox-backup-client/src/mount.rs
@@ -219,19 +219,22 @@ async fn mount_do(param: Value, pipe: Option<OwnedFd>) -> Result<Value, Error> {
         }
     };
 
-    let server_archive_name = if archive_name.ends_with(".pxar") {
-        if target.is_none() {
-            bail!("use the 'mount' command to mount pxar archives");
-        }
-        format!("{}.didx", archive_name)
-    } else if archive_name.ends_with(".img") {
-        if target.is_some() {
-            bail!("use the 'map' command to map drive images");
-        }
-        format!("{}.fidx", archive_name)
-    } else {
-        bail!("Can only mount/map pxar archives and drive images.");
-    };
+    let server_archive_name =
+        if archive_name.ends_with(".pxar") || archive_name.ends_with(".pxar.meta") {
+            if target.is_none() {
+                bail!("use the 'mount' command to mount pxar archives");
+            }
+            format!("{}.didx", archive_name)
+        } else if archive_name.ends_with(".img") {
+            if target.is_some() {
+                bail!("use the 'map' command to map drive images");
+            }
+            format!("{}.fidx", archive_name)
+        } else if archive_name.ends_with(".pxar.pld") {
+            bail!("Use corresponding pxar.meta archive to mount.");
+        } else {
+            bail!("Can only mount/map pxar archives and drive images.");
+        };
 
     let client = BackupReader::start(
         &client,
@@ -289,14 +292,37 @@ async fn mount_do(param: Value, pipe: Option<OwnedFd>) -> Result<Value, Error> {
         let most_used = index.find_most_used_chunks(8);
         let chunk_reader = RemoteChunkReader::new(
             client.clone(),
-            crypt_config,
+            crypt_config.clone(),
             file_info.chunk_crypt_mode(),
             most_used,
         );
         let reader = BufferedDynamicReader::new(index, chunk_reader);
+
         let archive_size = reader.archive_size();
         let reader: pbs_pxar_fuse::Reader = Arc::new(BufferedDynamicReadAt::new(reader));
-        let decoder = pbs_pxar_fuse::Accessor::new(reader, archive_size).await?;
+
+        let mut decoder = pbs_pxar_fuse::Accessor::new(reader, archive_size).await?;
+
+        if let Some(archive_base_name) = server_archive_name.strip_suffix(".pxar.meta.didx") {
+            let payload_archive_name = format!("{archive_base_name}.pxar.pld.didx");
+            let payload_index = client
+                .download_dynamic_index(&manifest, &payload_archive_name)
+                .await?;
+
+            let payload_most_used = payload_index.find_most_used_chunks(8);
+            let payload_chunk_reader = RemoteChunkReader::new(
+                client.clone(),
+                crypt_config,
+                file_info.chunk_crypt_mode(),
+                payload_most_used,
+            );
+
+            let payload_reader = BufferedDynamicReader::new(payload_index, payload_chunk_reader);
+            let payload_reader: pbs_pxar_fuse::Reader =
+                Arc::new(BufferedDynamicReadAt::new(payload_reader));
+
+            decoder = decoder.redirect_payload_input(payload_reader);
+        }
 
         let session =
             pbs_pxar_fuse::Session::mount(decoder, options, false, Path::new(target.unwrap()))
-- 
2.39.2