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 3FF008A228 for ; Tue, 16 Aug 2022 11:26:56 +0200 (CEST) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id 3CB311AA99 for ; Tue, 16 Aug 2022 11:26:56 +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)) (No client certificate requested) by firstgate.proxmox.com (Proxmox) with ESMTPS for ; Tue, 16 Aug 2022 11:26:54 +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 BE30943315 for ; Tue, 16 Aug 2022 11:20:02 +0200 (CEST) From: Markus Frank To: pbs-devel@lists.proxmox.com Date: Tue, 16 Aug 2022 11:19:27 +0200 Message-Id: <20220816091929.26309-2-m.frank@proxmox.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20220816091929.26309-1-m.frank@proxmox.com> References: <20220816091929.26309-1-m.frank@proxmox.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-SPAM-LEVEL: Spam detection results: 0 AWL -0.083 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 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. [extract.rs, main.rs] Subject: [pbs-devel] [PATCH proxmox-backup 1/3] added overwrite-existing-files as 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: Tue, 16 Aug 2022 09:26:56 -0000 If true, O_EXCL is not set and therefore overwrites the files and does not error out. Signed-off-by: Markus Frank --- pbs-client/src/catalog_shell.rs | 4 ++-- pbs-client/src/pxar/extract.rs | 24 +++++++++++++++++++++--- pxar-bin/src/main.rs | 7 +++++++ 3 files changed, 30 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..3b9151aa 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,19 @@ 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_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 +459,19 @@ 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_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 +834,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 +967,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 +1015,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..4b49df51 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 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