From a11b8764f1be5124b5a81a39809cfeb520f4a96d Mon Sep 17 00:00:00 2001 From: bigfoot547 Date: Tue, 21 Jan 2025 16:36:33 -0600 Subject: strip verbatim prefix \\?\ from paths on windows without this, java freaks out (amended to remove an artifact, arguments.txt) --- src/launcher.rs | 8 ++++---- src/launcher/runner.rs | 18 +++++++++-------- src/util.rs | 53 +++++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 66 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/src/launcher.rs b/src/launcher.rs index 348639d..40d9742 100644 --- a/src/launcher.rs +++ b/src/launcher.rs @@ -16,7 +16,7 @@ use std::ffi::{OsStr, OsString}; use std::fmt::{Display, Formatter}; use std::io::ErrorKind; use std::io::ErrorKind::AlreadyExists; -use std::path::{Component, Path, PathBuf}; +use std::path::{Component, Path, PathBuf, Prefix}; use std::{env, process}; use std::env::JoinPathsError; use std::time::{Instant, SystemTime, UNIX_EPOCH}; @@ -36,7 +36,7 @@ use version::{VersionList, VersionResolveError, VersionResult}; use crate::version::{Logging, Library, OSRestriction, OperatingSystem, DownloadType, DownloadInfo, LibraryExtractRule, CompleteVersion, FeatureMatcher}; use assets::{AssetError, AssetRepository}; -use crate::util::{self, FileVerifyError, IntegrityError}; +use crate::util::{self, AsJavaPath, FileVerifyError, IntegrityError}; pub use settings::*; pub use runner::run_the_game; @@ -551,8 +551,8 @@ impl Launcher { info!("Building classpath"); let classpath = env::join_paths(downloads.iter() - .map(|job| job.get_path()) - .chain(client_jar_path.iter().map(|p| p.as_path()))) + .map(|job| job.get_path().as_java_path()) + .chain(client_jar_path.iter().map(|p| p.as_path().as_java_path()))) .map_err(|e| LaunchError::LibraryClasspathError(e))? .into_string() .unwrap_or_else(|os| { diff --git a/src/launcher/runner.rs b/src/launcher/runner.rs index 0f65b49..41b3ed1 100644 --- a/src/launcher/runner.rs +++ b/src/launcher/runner.rs @@ -2,6 +2,7 @@ use std::borrow::Cow; use std::ffi::{OsStr, OsString}; use std::iter; use std::process::Command; +use crate::util::AsJavaPath; use crate::version::{CompleteVersion, FeatureMatcher, OperatingSystem}; use super::rules::CompatCheck; use super::strsub::{self, SubFunc}; @@ -14,7 +15,7 @@ impl<'rep, 'l, F: FeatureMatcher> SubFunc<'rep> for LaunchArgSub<'rep, 'l, F> { fn substitute(&self, key: &str) -> Option> { match key { "assets_index_name" => self.0.asset_index_name.as_ref().map(|s| Cow::Borrowed(s.as_str())), - "assets_root" => Some(self.0.launcher.assets.get_home().to_string_lossy()), + "assets_root" => Some(self.0.launcher.assets.get_home().as_java_path().to_string_lossy()), "auth_access_token" => Some(Cow::Borrowed("-")), // TODO "auth_player_name" => Some(Cow::Borrowed("Player")), // TODO "auth_session" => Some(Cow::Borrowed("-")), // TODO @@ -22,14 +23,15 @@ impl<'rep, 'l, F: FeatureMatcher> SubFunc<'rep> for LaunchArgSub<'rep, 'l, F> { "auth_xuid" => Some(Cow::Borrowed("00000000-0000-0000-0000-000000000000")), // TODO "classpath" => Some(Cow::Borrowed(self.0.classpath.as_str())), // TODO "classpath_separator" => None, // FIXME - "game_assets" => self.0.virtual_assets_path.as_ref().map(|s| s.to_string_lossy()), - "game_directory" => Some(self.0.instance_home.to_string_lossy()), + "game_assets" => self.0.virtual_assets_path.as_ref() + .map(|s| s.as_path().as_java_path().to_string_lossy()), + "game_directory" => Some(self.0.instance_home.as_java_path().to_string_lossy()), "language" => Some(Cow::Borrowed("en-us")), // ??? "launcher_name" => Some(Cow::Borrowed("ozone (olauncher 3)")), // TODO "launcher_version" => Some(Cow::Borrowed("yeah")), // TODO - "library_directory" => Some(self.0.launcher.libraries.home.to_string_lossy()), - "natives_directory" => Some(self.0.natives_path.to_string_lossy()), - "primary_jar" => self.0.client_jar.as_ref().map(|p| p.to_string_lossy()), + "library_directory" => Some(self.0.launcher.libraries.home.as_java_path().to_string_lossy()), + "natives_directory" => Some(self.0.natives_path.as_java_path().to_string_lossy()), + "primary_jar" => self.0.client_jar.as_ref().map(|p| p.as_path().as_java_path().to_string_lossy()), "quickPlayMultiplayer" => None, // TODO "quickPlayPath" => None, // TODO "quickPlayRealms" => None, // TODO @@ -45,7 +47,7 @@ impl<'rep, 'l, F: FeatureMatcher> SubFunc<'rep> for LaunchArgSub<'rep, 'l, F> { if let Some(asset_key) = key.strip_prefix("asset=") { return self.0.asset_index.as_ref() .map_or(None, |idx| idx.objects.get(asset_key)) - .map(|obj| Cow::Owned(self.0.launcher.assets.get_object_path(obj).to_string_lossy().into_owned())) + .map(|obj| Cow::Owned(self.0.launcher.assets.get_object_path(obj).as_java_path().to_string_lossy().into_owned())) } None @@ -116,7 +118,7 @@ pub fn run_the_game(launch: &Launch) -> Result<(), Box> { .map(|o| o.as_os_str()) .chain(iter::once(OsStr::new(launch.main_class.as_str()))) .chain(launch.game_args.iter().map(|o| o.as_os_str()))) - .current_dir(launch.instance_path.as_path()).spawn()?.wait()?; + .current_dir(launch.instance_path.as_path().as_java_path()).spawn()?.wait()?; Ok(()) } diff --git a/src/util.rs b/src/util.rs index a7c2d5e..7927620 100644 --- a/src/util.rs +++ b/src/util.rs @@ -1,11 +1,13 @@ use std::error::Error; +use std::ffi::OsStr; use std::fmt::{Display, Formatter}; use std::io::ErrorKind; -use std::path::{Component, Path, PathBuf}; +use std::path::{Component, Path, PathBuf, Prefix}; use log::debug; use sha1_smol::{Digest, Sha1}; use tokio::fs::File; use tokio::io::AsyncReadExt; +use crate::util; #[derive(Debug)] pub enum IntegrityError { @@ -128,3 +130,52 @@ pub fn check_path(name: &str) -> Result<&Path, &'static str> { Ok(entry_path) } + +#[cfg(windows)] +pub fn strip_verbatim(path: &Path) -> &Path { + let Some(Component::Prefix(p)) = path.components().next() else { + return path; + }; + + match p.kind() { + Prefix::VerbatimDisk(_) => + Path::new(unsafe { OsStr::from_encoded_bytes_unchecked(&path.as_os_str().as_encoded_bytes()[4..]) }), + _ => path + } +} + +#[cfg(not(windows))] +pub fn strip_verbatim(path: &Path) -> &Path { + path +} + +pub trait AsJavaPath { + fn as_java_path(&self) -> &Path; +} + +impl AsJavaPath for Path { + fn as_java_path(&self) -> &Path { + strip_verbatim(self) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + #[cfg(windows)] + fn test_strip_verbatim() { + let path = Path::new(r"\\?\C:\Some\Verbatim\Path"); + match path.components().next().unwrap() { + Component::Prefix(p) => assert!(matches!(p.kind(), Prefix::VerbatimDisk(_)), "(TEST BUG) path does not start with verbatim disk"), + _ => panic!("(TEST BUG) path does not start with prefix") + } + + let path2 = path.as_java_path(); + match path2.components().next().unwrap() { + Component::Prefix(p) => assert!(matches!(p.kind(), Prefix::Disk(_))), + _ => panic!("path does not begin with prefix") + } + } +} -- cgit v1.2.3-70-g09d2