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 03C298A834 for ; Thu, 18 Aug 2022 13:07:17 +0200 (CEST) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id 01C342FDD4 for ; Thu, 18 Aug 2022 13:07:17 +0200 (CEST) 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) server-digest SHA256) (No client certificate requested) by firstgate.proxmox.com (Proxmox) with ESMTPS for ; Thu, 18 Aug 2022 13:07:15 +0200 (CEST) Received: from proxmox-new.maurer-it.com (localhost.localdomain [127.0.0.1]) by proxmox-new.maurer-it.com (Proxmox) with ESMTP id D69FE44B30 for ; Thu, 18 Aug 2022 13:07:08 +0200 (CEST) From: Markus Frank To: pbs-devel@lists.proxmox.com Date: Thu, 18 Aug 2022 13:06:52 +0200 Message-Id: <20220818110654.56988-2-m.frank@proxmox.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20220818110654.56988-1-m.frank@proxmox.com> References: <20220818110654.56988-1-m.frank@proxmox.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-SPAM-LEVEL: Spam detection results: 0 AWL -0.121 Adjusted score from AWL reputation of From: address BAYES_00 -1.9 Bayes spam probability is 0 to 1% KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment PROLO_LEO1 0.1 Meta Catches all Leo drug variations so far 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 - Subject: [pbs-devel] [PATCH proxmox-backup v2 1/3] pbs-client: added overwrite-existing-files to PxarExtractOptions. 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: Thu, 18 Aug 2022 11:07:17 -0000 If overwrite-existing-files is true, O_TRUNC is set (to clean the leftovers) instead of O_EXCL and therefore overwrites the files and does not error out. Signed-off-by: Markus Frank --- v2: add O_TRUNC to oflags if overwrite_existing_files is true. pbs-client/src/catalog_shell.rs | 4 ++-- pbs-client/src/pxar/extract.rs | 28 +++++++++++++++++++++++++--- pxar-bin/src/main.rs | 7 +++++++ 3 files changed, 34 insertions(+), 5 deletions(-) diff --git a/pbs-client/src/catalog_shell.rs b/pbs-client/src/catalog_shell.rs index b11901ed..25e27b37 100644 --- a/pbs-client/src/catalog_shell.rs +++ b/pbs-client/src/catalog_shell.rs @@ -984,7 +984,7 @@ impl Shell { .clone(); let extractor = - crate::pxar::extract::Extractor::new(rootdir, root_meta, true, Flags::DEFAULT); + crate::pxar::extract::Extractor::new(rootdir, root_meta, true, false, Flags::DEFAULT); let mut extractor = ExtractorState::new( &mut self.catalog, @@ -1172,7 +1172,7 @@ impl<'a> ExtractorState<'a> { let file_name = CString::new(entry.file_name().as_bytes())?; let mut contents = entry.contents().await?; self.extractor - .async_extract_file(&file_name, entry.metadata(), *size, &mut contents) + .async_extract_file(&file_name, entry.metadata(), *size, &mut contents, false) .await } _ => { diff --git a/pbs-client/src/pxar/extract.rs b/pbs-client/src/pxar/extract.rs index 161d2cef..36600789 100644 --- a/pbs-client/src/pxar/extract.rs +++ b/pbs-client/src/pxar/extract.rs @@ -34,6 +34,7 @@ pub struct PxarExtractOptions<'a> { pub match_list: &'a [MatchEntry], pub extract_match_default: bool, pub allow_existing_dirs: bool, + pub overwrite_existing_files: bool, pub on_error: Option, } @@ -80,6 +81,7 @@ where dir, root.metadata().clone(), options.allow_existing_dirs, + options.overwrite_existing_files, feature_flags, ); @@ -198,6 +200,7 @@ where &mut decoder.contents().ok_or_else(|| { format_err!("found regular file entry without contents in archive") })?, + extractor.overwrite_existing_files, ), (false, _) => Ok(()), // skip this } @@ -215,6 +218,7 @@ where pub struct Extractor { feature_flags: Flags, allow_existing_dirs: bool, + overwrite_existing_files: bool, dir_stack: PxarDirStack, /// For better error output we need to track the current path in the Extractor state. @@ -231,11 +235,13 @@ impl Extractor { root_dir: Dir, metadata: Metadata, allow_existing_dirs: bool, + overwrite_existing_files: bool, feature_flags: Flags, ) -> Self { Self { dir_stack: PxarDirStack::new(root_dir, metadata), allow_existing_dirs, + overwrite_existing_files, feature_flags, current_path: Arc::new(Mutex::new(OsString::new())), on_error: Box::new(Err), @@ -392,14 +398,21 @@ impl Extractor { metadata: &Metadata, size: u64, contents: &mut dyn io::Read, + overwrite_existing_files: bool, ) -> Result<(), Error> { let parent = self.parent_fd()?; + let mut oflags = OFlag::O_CREAT | OFlag::O_WRONLY | OFlag::O_CLOEXEC; + if overwrite_existing_files { + oflags = oflags | OFlag::O_TRUNC; + } else { + oflags = oflags | OFlag::O_EXCL; + } let mut file = unsafe { std::fs::File::from_raw_fd( nix::fcntl::openat( parent, file_name, - OFlag::O_CREAT | OFlag::O_EXCL | OFlag::O_WRONLY | OFlag::O_CLOEXEC, + oflags, Mode::from_bits(0o600).unwrap(), ) .map_err(|err| format_err!("failed to create file {:?}: {}", file_name, err))?, @@ -448,14 +461,21 @@ impl Extractor { metadata: &Metadata, size: u64, contents: &mut T, + overwrite_existing_files: bool, ) -> Result<(), Error> { let parent = self.parent_fd()?; + let mut oflags = OFlag::O_CREAT | OFlag::O_WRONLY | OFlag::O_CLOEXEC; + if overwrite_existing_files { + oflags = oflags | OFlag::O_TRUNC; + } else { + oflags = oflags | OFlag::O_EXCL; + } let mut file = tokio::fs::File::from_std(unsafe { std::fs::File::from_raw_fd( nix::fcntl::openat( parent, file_name, - OFlag::O_CREAT | OFlag::O_EXCL | OFlag::O_WRONLY | OFlag::O_CLOEXEC, + oflags, Mode::from_bits(0o600).unwrap(), ) .map_err(|err| format_err!("failed to create file {:?}: {}", file_name, err))?, @@ -818,7 +838,7 @@ where ) })?; - Ok(Extractor::new(dir, metadata, false, Flags::DEFAULT)) + Ok(Extractor::new(dir, metadata, false, false, Flags::DEFAULT)) } pub async fn extract_sub_dir( @@ -951,6 +971,7 @@ where &mut file.contents().await.map_err(|_| { format_err!("found regular file entry without contents in archive") })?, + extractor.overwrite_existing_files, ) .await? } @@ -998,6 +1019,7 @@ where &mut decoder.contents().ok_or_else(|| { format_err!("found regular file entry without contents in archive") })?, + extractor.overwrite_existing_files, ) .await? } diff --git a/pxar-bin/src/main.rs b/pxar-bin/src/main.rs index 3714eb03..1dd34deb 100644 --- a/pxar-bin/src/main.rs +++ b/pxar-bin/src/main.rs @@ -75,6 +75,11 @@ fn extract_archive_from_reader( optional: true, default: false, }, + "overwrite_existing_files": { + description: "overwrite already existing files", + optional: true, + default: false, + }, "files-from": { description: "File containing match pattern for files to restore.", optional: true, @@ -112,6 +117,7 @@ fn extract_archive( no_fcaps: bool, no_acls: bool, allow_existing_dirs: bool, + overwrite_existing_files: bool, files_from: Option, no_device_nodes: bool, no_fifos: bool, @@ -179,6 +185,7 @@ fn extract_archive( let options = PxarExtractOptions { match_list: &match_list, allow_existing_dirs, + overwrite_existing_files, extract_match_default, on_error, }; -- 2.30.2