From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: 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 A7978628C6 for ; Mon, 21 Dec 2020 12:25:39 +0100 (CET) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id A2D2B1ECB9 for ; Mon, 21 Dec 2020 12:25:09 +0100 (CET) Received: from proxmox-new.maurer-it.com (proxmox-new.maurer-it.com [212.186.127.180]) (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 id 456A41EC95 for ; Mon, 21 Dec 2020 12:25:08 +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 0A714454A3 for ; Mon, 21 Dec 2020 12:25:08 +0100 (CET) From: Dominik Csapak To: pbs-devel@lists.proxmox.com Date: Mon, 21 Dec 2020 12:25:03 +0100 Message-Id: <20201221112507.30450-1-d.csapak@proxmox.com> X-Mailer: git-send-email 2.20.1 MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-SPAM-LEVEL: Spam detection results: 0 AWL 0.280 Adjusted score from AWL reputation of From: address KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment RCVD_IN_DNSWL_MED -2.3 Sender listed at https://www.dnswl.org/, medium trust SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_PASS -0.001 SPF: sender matches SPF record Subject: [pbs-devel] [RFC PATCH proxmox-backup 1/5] api2/admin/datastore: refactor list_dir_content in catalog_reader X-BeenThere: pbs-devel@lists.proxmox.com X-Mailman-Version: 2.1.29 Precedence: list List-Id: Proxmox Backup Server development discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 21 Dec 2020 11:25:39 -0000 we will reuse that later in the client, so we need it somewhere we can use from there Signed-off-by: Dominik Csapak --- src/api2/admin/datastore.rs | 52 ++++------------------------- src/backup/catalog.rs | 65 +++++++++++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+), 45 deletions(-) diff --git a/src/api2/admin/datastore.rs b/src/api2/admin/datastore.rs index 16fee943..5f06a2bf 100644 --- a/src/api2/admin/datastore.rs +++ b/src/api2/admin/datastore.rs @@ -1302,7 +1302,7 @@ fn catalog( _param: Value, _info: &ApiMethod, rpcenv: &mut dyn RpcEnvironment, -) -> Result { +) -> Result, Error> { let datastore = DataStore::lookup_datastore(&store)?; let auth_id: Authid = rpcenv.get_auth_id().unwrap().parse()?; @@ -1334,52 +1334,14 @@ fn catalog( let reader = BufferedDynamicReader::new(index, chunk_reader); let mut catalog_reader = CatalogReader::new(reader); - let mut current = catalog_reader.root()?; - let mut components = vec![]; - - if filepath != "root" { - components = base64::decode(filepath)?; - if components.len() > 0 && components[0] == '/' as u8 { - components.remove(0); - } - for component in components.split(|c| *c == '/' as u8) { - if let Some(entry) = catalog_reader.lookup(¤t, component)? { - current = entry; - } else { - bail!("path {:?} not found in catalog", &String::from_utf8_lossy(&components)); - } - } - } - - let mut res = Vec::new(); - - for direntry in catalog_reader.read_dir(¤t)? { - let mut components = components.clone(); - components.push('/' as u8); - components.extend(&direntry.name); - let path = base64::encode(components); - let text = String::from_utf8_lossy(&direntry.name); - let mut entry = json!({ - "filepath": path, - "text": text, - "type": CatalogEntryType::from(&direntry.attr).to_string(), - "leaf": true, - }); - match direntry.attr { - DirEntryAttribute::Directory { start: _ } => { - entry["leaf"] = false.into(); - }, - DirEntryAttribute::File { size, mtime } => { - entry["size"] = size.into(); - entry["mtime"] = mtime.into(); - }, - _ => {}, - } - res.push(entry); - } + let path = if filepath != "root" { + base64::decode(filepath)? + } else { + vec![b'/'] + }; - Ok(res.into()) + catalog_reader.list_dir_content(&path) } fn recurse_files<'a, T, W>( diff --git a/src/backup/catalog.rs b/src/backup/catalog.rs index b500fb93..5f8e85a6 100644 --- a/src/backup/catalog.rs +++ b/src/backup/catalog.rs @@ -5,6 +5,7 @@ use std::io::{Read, Write, Seek, SeekFrom}; use std::os::unix::ffi::OsStrExt; use anyhow::{bail, format_err, Error}; +use serde_json::{json, Value}; use pathpatterns::{MatchList, MatchType}; use proxmox::tools::io::ReadExt; @@ -474,6 +475,32 @@ impl CatalogReader { Ok(entry_list) } + /// Lookup a DirEntry from an absolute path + pub fn lookup_recursive( + &mut self, + path: &[u8], + ) -> Result { + let mut current = self.root()?; + if path == b"/" { + return Ok(current); + } + + let components = if path.len() > 0 && path[0] == b'/' { + &path[1..] + } else { + path + }.split(|c| *c == b'/'); + + for comp in components { + if let Some(entry) = self.lookup(¤t, comp)? { + current = entry; + } else { + bail!("path {:?} not found in catalog", String::from_utf8_lossy(&path)); + } + } + Ok(current) + } + /// Lockup a DirEntry inside a parent directory pub fn lookup( &mut self, @@ -554,6 +581,44 @@ impl CatalogReader { }) } + /// Returns the list of content of the given path as json + pub fn list_dir_content(&mut self, path: &[u8]) -> Result, Error> { + let dir = self.lookup_recursive(path)?; + let mut res = vec![]; + let mut path = path.to_vec(); + if path.len() > 0 && path[0] == b'/' { + path.remove(0); + } + + for direntry in self.read_dir(&dir)? { + let mut components = path.clone(); + components.push(b'/'); + components.extend(&direntry.name); + let path = base64::encode(&components); + let text = String::from_utf8_lossy(&direntry.name); + let mut entry = json!({ + "filepath": path, + "text": text, + "name": direntry.name.clone(), + "type": CatalogEntryType::from(&direntry.attr).to_string(), + "leaf": true, + }); + match direntry.attr { + DirEntryAttribute::Directory { start: _ } => { + entry["leaf"] = false.into(); + }, + DirEntryAttribute::File { size, mtime } => { + entry["size"] = size.into(); + entry["mtime"] = mtime.into(); + }, + _ => {}, + } + res.push(entry); + } + + Ok(res) + } + /// Finds all entries matching the given match patterns and calls the /// provided callback on them. pub fn find( -- 2.20.1