diff options
| author | 2026-01-15 17:49:26 +0800 | |
|---|---|---|
| committer | 2026-01-15 17:49:26 +0800 | |
| commit | 32a9aceee42a2261b64f9e6effda522639576a5e (patch) | |
| tree | 4cae8d216c3093421addaa0450bc8004c537e373 /src-tauri/src/utils | |
| parent | ce4b0c2053d5d16f7091d74840d4a502401f1a4e (diff) | |
| parent | 31077dbd39a25eecd24a1dca0f8c9d1879265277 (diff) | |
| download | DropOut-32a9aceee42a2261b64f9e6effda522639576a5e.tar.gz DropOut-32a9aceee42a2261b64f9e6effda522639576a5e.zip | |
Merge pull request #30 from HsiangNianian/main
Diffstat (limited to 'src-tauri/src/utils')
| -rw-r--r-- | src-tauri/src/utils/zip.rs | 75 |
1 files changed, 75 insertions, 0 deletions
diff --git a/src-tauri/src/utils/zip.rs b/src-tauri/src/utils/zip.rs index a03c975..dfe1214 100644 --- a/src-tauri/src/utils/zip.rs +++ b/src-tauri/src/utils/zip.rs @@ -1,5 +1,7 @@ +use flate2::read::GzDecoder; use std::fs; use std::path::Path; +use tar::Archive; pub fn extract_zip(zip_path: &Path, extract_to: &Path) -> Result<(), String> { let file = fs::File::open(zip_path) @@ -38,3 +40,76 @@ pub fn extract_zip(zip_path: &Path, extract_to: &Path) -> Result<(), String> { Ok(()) } + +/// Extract a tar.gz archive +/// +/// Adoptium's tar.gz archives usually contain a top-level directory, such as `jdk-21.0.5+11-jre/`. +/// This function returns the name of that directory to facilitate locating `bin/java` afterwards. +pub fn extract_tar_gz(archive_path: &Path, extract_to: &Path) -> Result<String, String> { + let file = fs::File::open(archive_path) + .map_err(|e| format!("Failed to open tar.gz {}: {}", archive_path.display(), e))?; + + let decoder = GzDecoder::new(file); + let mut archive = Archive::new(decoder); + + // Ensure the target directory exists + fs::create_dir_all(extract_to) + .map_err(|e| format!("Failed to create extract directory: {}", e))?; + + // Track the top-level directory name + let mut top_level_dir: Option<String> = None; + + for entry in archive + .entries() + .map_err(|e| format!("Failed to read tar entries: {}", e))? + { + let mut entry = entry.map_err(|e| format!("Failed to read tar entry: {}", e))?; + let entry_path = entry + .path() + .map_err(|e| format!("Failed to get entry path: {}", e))? + .into_owned(); + + // Extract the top-level directory name (the first path component) + if top_level_dir.is_none() { + if let Some(first_component) = entry_path.components().next() { + let component_str = first_component.as_os_str().to_string_lossy().to_string(); + if !component_str.is_empty() && component_str != "." { + top_level_dir = Some(component_str); + } + } + } + + let outpath = extract_to.join(&entry_path); + + if entry.header().entry_type().is_dir() { + fs::create_dir_all(&outpath) + .map_err(|e| format!("Failed to create directory {}: {}", outpath.display(), e))?; + } else { + // Ensure parent directory exists + if let Some(parent) = outpath.parent() { + if !parent.exists() { + fs::create_dir_all(parent) + .map_err(|e| format!("Failed to create parent dir: {}", e))?; + } + } + + let mut outfile = fs::File::create(&outpath) + .map_err(|e| format!("Failed to create file {}: {}", outpath.display(), e))?; + + std::io::copy(&mut entry, &mut outfile) + .map_err(|e| format!("Failed to extract file: {}", e))?; + + // Set executable permissions on Unix systems + #[cfg(unix)] + { + use std::os::unix::fs::PermissionsExt; + if let Ok(mode) = entry.header().mode() { + let permissions = fs::Permissions::from_mode(mode); + let _ = fs::set_permissions(&outpath, permissions); + } + } + } + } + + top_level_dir.ok_or_else(|| "Archive appears to be empty".to_string()) +} |