fix: preserve executable bits when extracting Java runtimes (#873)
Co-authored-by: LynithDev <61880709+LynithDev@users.noreply.github.com>
This commit is contained in:
parent
d632c47320
commit
7ca7ac04cf
3 changed files with 60 additions and 10 deletions
|
|
@ -81,15 +81,6 @@ pub async fn install_package(
|
||||||
.map_err(|err| polyio::IOError::from(std::io::Error::other(err)))?
|
.map_err(|err| polyio::IOError::from(std::io::Error::other(err)))?
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(unix)]
|
|
||||||
{
|
|
||||||
let _ = tokio::process::Command::new("chmod")
|
|
||||||
.arg("755")
|
|
||||||
.arg(&executable)
|
|
||||||
.output()
|
|
||||||
.await;
|
|
||||||
}
|
|
||||||
|
|
||||||
let _ = polyio::remove_file(&archive_path).await;
|
let _ = polyio::remove_file(&archive_path).await;
|
||||||
|
|
||||||
tracing::info!(vendor = %package.vendor, major, "installed Java runtime");
|
tracing::info!(vendor = %package.vendor, major, "installed Java runtime");
|
||||||
|
|
@ -136,6 +127,52 @@ pub fn is_launcher_managed(executable: &Path) -> bool {
|
||||||
managed_install_root(executable).is_ok_and(|root| root.is_some())
|
managed_install_root(executable).is_ok_and(|root| root.is_some())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
|
pub(crate) fn restore_executable_bits(executable: &Path) {
|
||||||
|
use std::os::unix::fs::PermissionsExt;
|
||||||
|
|
||||||
|
let Ok(executable) = polyio::canonicalize(executable) else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
if !is_launcher_managed(&executable) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let Some(home) = executable.parent().and_then(Path::parent) else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
let jre = home.join("jre");
|
||||||
|
|
||||||
|
let entries = |dir: PathBuf| {
|
||||||
|
std::fs::read_dir(dir)
|
||||||
|
.into_iter()
|
||||||
|
.flatten()
|
||||||
|
.flatten()
|
||||||
|
.map(|entry| entry.path())
|
||||||
|
};
|
||||||
|
let tools = entries(home.join("bin")).chain(entries(jre.join("bin")));
|
||||||
|
let helpers = ["jspawnhelper", "jexec"].map(|name| home.join("lib").join(name));
|
||||||
|
let jre_helpers = std::iter::once(jre.join("lib"))
|
||||||
|
.chain(entries(jre.join("lib")))
|
||||||
|
.map(|dir| dir.join("jspawnhelper"));
|
||||||
|
|
||||||
|
for path in tools.chain(helpers).chain(jre_helpers) {
|
||||||
|
let Ok(metadata) = std::fs::metadata(&path) else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
let mode = metadata.permissions().mode();
|
||||||
|
if !metadata.is_file() || mode & 0o111 != 0 {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
match std::fs::set_permissions(&path, std::fs::Permissions::from_mode(mode | 0o111)) {
|
||||||
|
Ok(()) => tracing::info!(path = %path.display(), "restored missing executable bit"),
|
||||||
|
Err(err) => {
|
||||||
|
tracing::warn!(path = %path.display(), "could not restore executable bit: {err}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Only ever touches OneClient's own java dir a runtime the user added from
|
/// Only ever touches OneClient's own java dir a runtime the user added from
|
||||||
/// their own folder is left on disk untouched
|
/// their own folder is left on disk untouched
|
||||||
#[tracing::instrument(level = "debug")]
|
#[tracing::instrument(level = "debug")]
|
||||||
|
|
|
||||||
|
|
@ -94,6 +94,9 @@ impl JavaService {
|
||||||
|
|
||||||
#[tracing::instrument(level = "debug", skip(self))]
|
#[tracing::instrument(level = "debug", skip(self))]
|
||||||
async fn revalidate(&self, runtime: JavaRuntime) -> JavaResult<Option<JavaRuntime>> {
|
async fn revalidate(&self, runtime: JavaRuntime) -> JavaResult<Option<JavaRuntime>> {
|
||||||
|
#[cfg(unix)]
|
||||||
|
crate::install::restore_executable_bits(Path::new(&runtime.absolute_path));
|
||||||
|
|
||||||
if runtime.probe_version == PROBE_VERSION {
|
if runtime.probe_version == PROBE_VERSION {
|
||||||
if Path::new(&runtime.absolute_path).is_file() {
|
if Path::new(&runtime.absolute_path).is_file() {
|
||||||
return Ok(Some(runtime));
|
return Ok(Some(runtime));
|
||||||
|
|
|
||||||
|
|
@ -216,6 +216,14 @@ pub async fn extract_zip_filtered(
|
||||||
let entry_reader = reader.reader_without_entry(index).await?;
|
let entry_reader = reader.reader_without_entry(index).await?;
|
||||||
|
|
||||||
futures_lite::io::copy(entry_reader, &mut writer.compat_write()).await?;
|
futures_lite::io::copy(entry_reader, &mut writer.compat_write()).await?;
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
|
if let Some(mode) = entry.unix_permissions().filter(|mode| mode & 0o777 != 0) {
|
||||||
|
use std::os::unix::fs::PermissionsExt;
|
||||||
|
|
||||||
|
let mode = u32::from(mode & 0o777) | 0o600;
|
||||||
|
tokio::fs::set_permissions(&path, std::fs::Permissions::from_mode(mode)).await?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -353,7 +361,9 @@ pub async fn extract_tar_gz(
|
||||||
let buf_reader = tokio::io::BufReader::new(file);
|
let buf_reader = tokio::io::BufReader::new(file);
|
||||||
let gzip_decoder = async_compression::tokio::bufread::GzipDecoder::new(buf_reader);
|
let gzip_decoder = async_compression::tokio::bufread::GzipDecoder::new(buf_reader);
|
||||||
|
|
||||||
let mut tar_archive = tokio_tar::Archive::new(gzip_decoder);
|
let mut tar_archive = tokio_tar::ArchiveBuilder::new(gzip_decoder)
|
||||||
|
.set_preserve_permissions(true)
|
||||||
|
.build();
|
||||||
tar_archive.unpack(dest).await?;
|
tar_archive.unpack(dest).await?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue