From c0d4e24dd1eae42f24e36ff423923e815100238c Mon Sep 17 00:00:00 2001 From: krande Date: Sat, 26 Oct 2024 15:55:30 +0200 Subject: [PATCH 1/4] add tolerant tar extraction on windows --- src/source/extract.rs | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/src/source/extract.rs b/src/source/extract.rs index db2e3d295..5a042865f 100644 --- a/src/source/extract.rs +++ b/src/source/extract.rs @@ -1,6 +1,6 @@ //! Helpers to extract archives use std::{ffi::OsStr, io::BufRead, path::Path}; - +use tar::EntryType; use crate::console_utils::LoggingOutputHandler; use fs_err as fs; @@ -136,9 +136,29 @@ pub(crate) fn extract_tar( )); let tmp_extraction_dir = tempfile::Builder::new().tempdir_in(target_directory)?; - archive - .unpack(&tmp_extraction_dir) - .map_err(|e| SourceError::TarExtractionError(e.to_string()))?; + for entry in archive.entries()? { + match entry { + Ok(mut file) => { + let path = tmp_extraction_dir.path().join(file.path()?); + + // Attempt to unpack symlinks, log errors if they fail on Windows + if file.header().entry_type() == EntryType::Symlink && cfg!(target_os = "windows") { + if let Err(e) = file.unpack(&path) { + println!("Warning: failed to extract symlink {:?} due to {:?}", path, e); + } + continue; + } + + // Attempt to unpack other files individually, handle errors gracefully + if let Err(e) = file.unpack(&path) { + println!("Warning: failed to unpack {:?} due to {:?}", path, e); + } + } + Err(e) => { + println!("Warning: failed to read an entry due to {:?}", e); + } + } + } move_extracted_dir(tmp_extraction_dir.path(), target_directory)?; progress_bar.finish_with_message("Extracted..."); @@ -170,7 +190,7 @@ pub(crate) fn extract_zip( let mut archive = zip::ZipArchive::new(progress_bar.wrap_read( File::open(archive).map_err(|_| SourceError::FileNotFound(archive.to_path_buf()))?, )) - .map_err(|e| SourceError::InvalidZip(e.to_string()))?; + .map_err(|e| SourceError::InvalidZip(e.to_string()))?; let tmp_extraction_dir = tempfile::Builder::new().tempdir_in(target_directory)?; archive From 0a7c1d73d191e42e2a6494b7ec9c2a9d2360f909 Mon Sep 17 00:00:00 2001 From: krande Date: Mon, 28 Oct 2024 10:25:40 +0100 Subject: [PATCH 2/4] fix linting --- src/source/extract.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/source/extract.rs b/src/source/extract.rs index 5a042865f..7af48e033 100644 --- a/src/source/extract.rs +++ b/src/source/extract.rs @@ -1,7 +1,7 @@ //! Helpers to extract archives +use crate::console_utils::LoggingOutputHandler; use std::{ffi::OsStr, io::BufRead, path::Path}; use tar::EntryType; -use crate::console_utils::LoggingOutputHandler; use fs_err as fs; use fs_err::File; @@ -144,7 +144,10 @@ pub(crate) fn extract_tar( // Attempt to unpack symlinks, log errors if they fail on Windows if file.header().entry_type() == EntryType::Symlink && cfg!(target_os = "windows") { if let Err(e) = file.unpack(&path) { - println!("Warning: failed to extract symlink {:?} due to {:?}", path, e); + println!( + "Warning: failed to extract symlink {:?} due to {:?}", + path, e + ); } continue; } @@ -190,7 +193,7 @@ pub(crate) fn extract_zip( let mut archive = zip::ZipArchive::new(progress_bar.wrap_read( File::open(archive).map_err(|_| SourceError::FileNotFound(archive.to_path_buf()))?, )) - .map_err(|e| SourceError::InvalidZip(e.to_string()))?; + .map_err(|e| SourceError::InvalidZip(e.to_string()))?; let tmp_extraction_dir = tempfile::Builder::new().tempdir_in(target_directory)?; archive From 15df949b28bea63096cfdc9d7309dd889a544598 Mon Sep 17 00:00:00 2001 From: krande Date: Tue, 29 Oct 2024 17:09:23 +0100 Subject: [PATCH 3/4] fix end to end testing by making sure intermediate directories are built up front --- src/source/extract.rs | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/src/source/extract.rs b/src/source/extract.rs index 7af48e033..7580f4419 100644 --- a/src/source/extract.rs +++ b/src/source/extract.rs @@ -141,20 +141,23 @@ pub(crate) fn extract_tar( Ok(mut file) => { let path = tmp_extraction_dir.path().join(file.path()?); - // Attempt to unpack symlinks, log errors if they fail on Windows - if file.header().entry_type() == EntryType::Symlink && cfg!(target_os = "windows") { - if let Err(e) = file.unpack(&path) { - println!( - "Warning: failed to extract symlink {:?} due to {:?}", - path, e - ); - } - continue; + // Ensure all intermediate directories exist before unpacking + if let Some(parent) = path.parent() { + fs::create_dir_all(parent)?; } - // Attempt to unpack other files individually, handle errors gracefully - if let Err(e) = file.unpack(&path) { - println!("Warning: failed to unpack {:?} due to {:?}", path, e); + // Attempt to unpack symlinks and regular files, logging any issues + match file.header().entry_type() { + EntryType::Symlink if cfg!(target_os = "windows") => { + if let Err(e) = file.unpack(&path) { + println!("Warning: failed to extract symlink {:?} due to {:?}", path, e); + } + } + _ => { + if let Err(e) = file.unpack(&path) { + println!("Warning: failed to unpack {:?} due to {:?}", path, e); + } + } } } Err(e) => { From 1ab3042a759cfc0a948562c5db16f136d21a6b9c Mon Sep 17 00:00:00 2001 From: krande Date: Tue, 29 Oct 2024 17:18:01 +0100 Subject: [PATCH 4/4] fix lint --- src/source/extract.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/source/extract.rs b/src/source/extract.rs index 7580f4419..323b0e5ca 100644 --- a/src/source/extract.rs +++ b/src/source/extract.rs @@ -150,7 +150,10 @@ pub(crate) fn extract_tar( match file.header().entry_type() { EntryType::Symlink if cfg!(target_os = "windows") => { if let Err(e) = file.unpack(&path) { - println!("Warning: failed to extract symlink {:?} due to {:?}", path, e); + println!( + "Warning: failed to extract symlink {:?} due to {:?}", + path, e + ); } } _ => {