summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar bigfoot547 <[email protected]>2025-01-17 00:42:01 -0600
committerLibravatar bigfoot547 <[email protected]>2025-01-17 00:42:01 -0600
commitb8d81cc328dc88dd419485f5f80e1170ada79bd7 (patch)
tree917902b398e206d474cf0f6c19dd9c8f67842b1d
parentextracting natives (diff)
fix bugs
-rw-r--r--ozone-cli/src/main.rs2
-rw-r--r--src/launcher.rs44
-rw-r--r--src/launcher/extract.rs109
-rw-r--r--src/version.rs3
4 files changed, 100 insertions, 58 deletions
diff --git a/ozone-cli/src/main.rs b/ozone-cli/src/main.rs
index dd59f9d..965d27f 100644
--- a/ozone-cli/src/main.rs
+++ b/ozone-cli/src/main.rs
@@ -15,7 +15,7 @@ async fn main() -> Result<(), Box<dyn Error>> {
let launcher = o3launcher::launcher::Launcher::new(PathBuf::from("./work").as_path(), true).await?;
let profile = Profile {
- version_id: "1.8.9".into(),
+ version_id: "1.21.4".into(),
java_runtime: None,
instance: "".into()
};
diff --git a/src/launcher.rs b/src/launcher.rs
index eac79bb..0b1ea90 100644
--- a/src/launcher.rs
+++ b/src/launcher.rs
@@ -268,18 +268,6 @@ impl Launcher {
lib.natives.as_ref().map_or(None, |n| n.get(&self.system_info.os)).map(|s| s.as_str())
}
- fn create_extract_job(&self, lib: &Library) -> Option<LibraryExtractJob> {
- if lib.natives.is_none() {
- debug!("Not extracting natives for {}, no \"natives\".", lib.name);
- return None; // do not extract this one
- }
-
- Some(LibraryExtractJob {
- source: self.libraries.get_full_artifact_path(lib.name.as_str(), self.choose_lib_classifier(lib))?,
- rule: lib.extract.clone()
- })
- }
-
async fn ensure_file(&self, path: &Path, dlinfo: &DownloadInfo) -> Result<(), LaunchError> {
// verify the file
match util::verify_file(path, dlinfo.size, dlinfo.sha1).await {
@@ -406,7 +394,7 @@ impl Launcher {
* - (done) of the libraries we need, check which have correct size and sha1
* - (done) redownload necessary libraries
* - (done) (if offline mode and there are libraries to download, then explode violently)
- * - extract natives
+ * - (done) extract natives
* - (done) logging
* - (done) download the config if present and necessary
* - (done) (explode if offline mode and we need to download stuff)
@@ -439,6 +427,7 @@ impl Launcher {
info!("Resolved launch version {}!", ver.id);
let mut libs = Vec::new();
+ let mut extract_jobs = Vec::new();
let mut downloads = Vec::new();
for lib in ver.libraries.values() {
@@ -449,6 +438,14 @@ impl Launcher {
libs.push(lib);
if let Some(dl) = self.libraries.create_download(lib, self.choose_lib_classifier(lib)) {
dl.make_dirs().await.map_err(|e| LaunchError::LibraryDirError(dl.get_path().to_path_buf(), e))?;
+
+ if lib.natives.is_some() {
+ extract_jobs.push(LibraryExtractJob {
+ source: dl.get_path().to_owned(),
+ rule: lib.extract.clone()
+ });
+ }
+
downloads.push(dl);
}
}
@@ -512,9 +509,7 @@ impl Launcher {
// extract natives (execute this function unconditionally because we still need the natives dir to exist)
info!("Extracting natives.");
- let natives_dir = self.libraries.extract_natives(libs.iter().filter_map(|lib| {
- self.create_extract_job(*lib)
- }).collect::<Vec<_>>()).await?;
+ let natives_dir = self.libraries.extract_natives(extract_jobs).await?;
//todo!()
Ok(())
@@ -545,6 +540,7 @@ impl Error for LibraryError {
}
}
+#[derive(Debug)]
struct LibraryExtractJob {
source: PathBuf,
rule: Option<LibraryExtractRule>
@@ -571,14 +567,14 @@ impl LibraryRepository {
if let Some(classifier) = classifier {
match n.len() {
- 3 => Some(PathBuf::from(strsub::replace_thru(format!("{}-{}-{}.jar", n[1], n[2], classifier), Self::lib_replace))),
- 4 => Some(PathBuf::from(strsub::replace_thru(format!("{}-{}-{}-{}.jar", n[1], n[2], classifier, n[3]), Self::lib_replace))),
+ 2 => Some(PathBuf::from(strsub::replace_thru(format!("{}-{}-{}.jar", n[0], n[1], classifier), Self::lib_replace))),
+ 3 => Some(PathBuf::from(strsub::replace_thru(format!("{}-{}-{}-{}.jar", n[0], n[1], classifier, n[2]), Self::lib_replace))),
_ => None
}
} else {
match n.len() {
- 3 => Some(PathBuf::from(strsub::replace_thru(format!("{}-{}.jar", n[1], n[2]), Self::lib_replace))),
- 4 => Some(PathBuf::from(strsub::replace_thru(format!("{}-{}-{}.jar", n[1], n[2], n[3]), Self::lib_replace))),
+ 2 => Some(PathBuf::from(strsub::replace_thru(format!("{}-{}.jar", n[0], n[1]), Self::lib_replace))),
+ 3 => Some(PathBuf::from(strsub::replace_thru(format!("{}-{}-{}.jar", n[0], n[1], n[2]), Self::lib_replace))),
_ => None
}
}
@@ -592,10 +588,6 @@ impl LibraryRepository {
p.push(Self::get_artifact_filename(name, classifier)?);
Some(p)
}
-
- fn get_full_artifact_path(&self, name: &str, classifier: Option<&str>) -> Option<PathBuf> {
- Some(self.home.join(Self::get_artifact_path(name, classifier)?))
- }
fn create_download(&self, lib: &Library, classifier: Option<&str>) -> Option<VerifiedDownload> {
if lib.url.is_some() || lib.downloads.is_none() {
@@ -660,6 +652,7 @@ impl LibraryRepository {
}
async fn extract_natives<'lib>(&self, libs: Vec<LibraryExtractJob>) -> Result<PathBuf, LaunchError> {
+ let libs = libs;
fs::create_dir_all(&self.natives).await.map_err(|e| LaunchError::IO {
what: "creating natives directory",
error: e
@@ -678,10 +671,11 @@ impl LibraryRepository {
let mut tally = 0usize;
for job in libs {
+ debug!("Extracting natives for {}", job.source.display());
tally += extract::extract_zip(&job.source, &natives_dir, |name|
job.rule.as_ref().is_some_and(|rules|
rules.exclude.iter().filter(|ex|
- name.starts_with(ex.as_str())).next().is_some()))?;
+ name.starts_with(ex.as_str())).next().is_none()))?;
}
Ok((natives_dir, tally))
diff --git a/src/launcher/extract.rs b/src/launcher/extract.rs
index c9e0dc9..206d34f 100644
--- a/src/launcher/extract.rs
+++ b/src/launcher/extract.rs
@@ -1,10 +1,10 @@
use std::error::Error;
use std::fmt::{Display, Formatter};
-use std::{fs, io};
+use std::{fs, io, os};
use std::fs::File;
-use std::io::{BufReader, Error as IOError};
+use std::io::{BufReader, Error as IOError, Read};
use std::path::{Component, Path, PathBuf};
-use log::debug;
+use log::{debug, trace};
use zip::result::ZipError;
use zip::ZipArchive;
@@ -47,58 +47,105 @@ impl Error for ZipExtractError {
}
}
+fn check_entry_path(name: &str) -> Result<&Path, ZipExtractError> {
+ let entry_path: &Path = Path::new(name);
+
+ let mut depth = 0usize;
+ for component in entry_path.components() {
+ depth = match component {
+ Component::Prefix(_) | Component::RootDir =>
+ return Err(ZipExtractError::InvalidEntry {
+ why: "root path component in entry",
+ name: name.to_owned()
+ }),
+ Component::ParentDir => depth.checked_sub(1)
+ .map_or_else(|| Err(ZipExtractError::InvalidEntry {
+ why: "entry path escapes extraction root",
+ name: name.to_owned()
+ }), |s| Ok(s))?,
+ Component::Normal(_) => depth + 1,
+ _ => depth
+ }
+ }
+
+ Ok(entry_path)
+}
+
+#[cfg(unix)]
+fn extract_symlink(path: impl AsRef<Path>, target: &str) -> io::Result<()> {
+ os::unix::fs::symlink(target, path)
+}
+
+#[cfg(windows)]
+fn extract_symlink(path: impl AsRef<Path>, target: &str) -> io::Result<()> {
+ os::windows::fs::symlink_file(target, path)
+}
+
+#[cfg(not(any(unix, windows)))]
+fn extract_symlink(path: impl AsRef<Path>, _target: &str) -> io::Result<()> {
+ warn!("Refusing to extract symbolic link to {}. I don't know how to do it on this platform!", path.as_ref().display());
+ Ok(())
+}
+
pub fn extract_zip<F>(zip_path: impl AsRef<Path>, extract_root: impl AsRef<Path>, condition: F) -> Result<usize, ZipExtractError>
where
F: Fn(&str) -> bool
{
debug!("Extracting zip file {} into {}", zip_path.as_ref().display(), extract_root.as_ref().display());
-
+
fs::create_dir_all(&extract_root).map_err(|e| ZipExtractError::from(("create extract root", e)))?;
let mut extracted = 0usize;
- let file = File::open(zip_path).map_err(|e| ZipExtractError::from(("extract zip file (open)", e)))?;
+ let file = File::open(&zip_path).map_err(|e| ZipExtractError::from(("extract zip file (open)", e)))?;
let read = BufReader::new(file);
let mut archive = ZipArchive::new(read).map_err(|e| ZipExtractError::from(("read zip archive", e)))?;
+ // create directories
for n in 0..archive.len() {
- let mut entry = archive.by_index(n).map_err(|e| ZipExtractError::from(("access zip entry", e)))?;
- let name = entry.name();
+ let entry = archive.by_index(n).map_err(|e| ZipExtractError::from(("read zip entry (1)", e)))?;
+ if !entry.is_dir() { continue; }
+ let name = entry.name();
if !condition(name) {
continue;
}
- let entry_path: &Path = Path::new(name);
- let mut depth = 0usize;
- for component in entry_path.components() {
- depth = match component {
- Component::Prefix(_) | Component::RootDir =>
- return Err(ZipExtractError::InvalidEntry {
- why: "root path component in entry",
- name: name.to_owned()
- }),
- Component::ParentDir => depth.checked_sub(1)
- .map_or_else(|| Err(ZipExtractError::InvalidEntry {
- why: "entry path escapes extraction root",
- name: name.to_owned()
- }), |s| Ok(s))?,
- Component::Normal(_) => depth + 1,
- _ => depth
- }
+ let entry_path = check_entry_path(name)?;
+ let entry_path: PathBuf = [extract_root.as_ref(), entry_path].iter().collect();
+
+ trace!("Extracting directory {} from {}", entry.name(), zip_path.as_ref().display());
+ fs::create_dir_all(entry_path).map_err(|e| ZipExtractError::from(("extract directory", e)))?;
+ }
+
+ // extract the files
+ for n in 0..archive.len() {
+ let mut entry = archive.by_index(n).map_err(|e| ZipExtractError::from(("read zip entry (2)", e)))?;
+ let name = entry.name();
+
+ if entry.is_dir() { continue; }
+
+ if !condition(name) {
+ continue;
}
+ let entry_path = check_entry_path(name)?;
let entry_path: PathBuf = [extract_root.as_ref(), entry_path].iter().collect();
- // hmm some redundant directory creations will be happening here on linux :(
- if let Some(parent) = entry_path.parent() {
- fs::create_dir_all(parent).map_err(|e| ZipExtractError::from(("create entry directory", e)))?;
- }
+ if entry.is_symlink() {
+ let mut target = String::new();
+ entry.read_to_string(&mut target).map_err(|e| ZipExtractError::from(("read to symlink target", e)))?;
+
+ trace!("Extracting symbolic link {} -> {} from {}", entry.name(), target, zip_path.as_ref().display());
+ extract_symlink(entry_path.as_path(), target.as_str()).map_err(|e| ZipExtractError::from(("extract symlink", e)))?;
+ } else if entry.is_file() {
+ let mut outfile = File::create(&entry_path).map_err(|e| ZipExtractError::from(("extract zip entry (open)", e)))?;
- let mut outfile = File::create(&entry_path).map_err(|e| ZipExtractError::from(("extract zip entry (open)", e)))?;
- io::copy(&mut entry, &mut outfile).map_err(|e| ZipExtractError::from(("extract zip entry (write)", e)))?;
- extracted += 1;
+ trace!("Extracting file {} from {}", entry.name(), zip_path.as_ref().display());
+ io::copy(&mut entry, &mut outfile).map_err(|e| ZipExtractError::from(("extract zip entry (write)", e)))?;
+ extracted += 1;
+ }
}
Ok(extracted)
diff --git a/src/version.rs b/src/version.rs
index 545a487..1424b18 100644
--- a/src/version.rs
+++ b/src/version.rs
@@ -403,7 +403,8 @@ where
let mut map = HashMap::new();
while let Some(lib) = seq.next_element::<Library>()? {
- map.insert(canonicalize_library_name(lib.name.as_str()), lib);
+ //map.insert(canonicalize_library_name(lib.name.as_str()), lib);
+ map.insert(lib.name.as_str().to_owned(), lib);
}
Ok(map)