aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--crates/shirabe-php-shim/src/runtime.rs7
-rw-r--r--crates/shirabe-php-shim/src/zip.rs36
-rw-r--r--crates/shirabe/src/package/archiver/zip_archiver.rs22
3 files changed, 36 insertions, 29 deletions
diff --git a/crates/shirabe-php-shim/src/runtime.rs b/crates/shirabe-php-shim/src/runtime.rs
index c00c8f51..13513b9d 100644
--- a/crates/shirabe-php-shim/src/runtime.rs
+++ b/crates/shirabe-php-shim/src/runtime.rs
@@ -77,14 +77,9 @@ pub fn defined(name: &str) -> bool {
// `Composer\Autoload\ClassLoader` (and its `getRegisteredLoaders`) is absent from the running
// process; the class-name form therefore reports no such method. The object form needs runtime
// reflection that PhpMixed::Object does not carry.
-pub fn method_exists(object_or_class: &PhpMixed, method_name: &str) -> bool {
+pub fn method_exists(object_or_class: &PhpMixed, _method_name: &str) -> bool {
match object_or_class {
PhpMixed::String(_) => false,
- // `ZipArchiver::archive` guards `$zip->setExternalAttributesName(...)` with
- // `method_exists($zip, 'setExternalAttributesName')` (only available with libzip >= 0.11.2).
- // The `zip`-crate-backed shim cannot amend an already-written entry's external attributes,
- // so the method is deliberately absent here and the guard reports it missing.
- PhpMixed::Null if method_name == "setExternalAttributesName" => false,
_ => todo!(),
}
}
diff --git a/crates/shirabe-php-shim/src/zip.rs b/crates/shirabe-php-shim/src/zip.rs
index 7284b029..f028ffd0 100644
--- a/crates/shirabe-php-shim/src/zip.rs
+++ b/crates/shirabe-php-shim/src/zip.rs
@@ -218,17 +218,23 @@ impl ZipArchive {
)))
}
- pub fn add_empty_dir(&self, local_name: &str) -> bool {
+ pub fn add_empty_dir(&self, local_name: &str, opsys: i64, attr: i64) -> bool {
let mut state = self.state.borrow_mut();
let ZipState::Writer { writer, .. } = &mut *state else {
return false;
};
writer
- .add_directory(local_name, SimpleFileOptions::default())
+ .add_directory(local_name, Self::entry_options(opsys, attr))
.is_ok()
}
- pub fn add_file(&self, filepath: impl AsRef<std::path::Path>, local_name: &str) -> bool {
+ pub fn add_file(
+ &self,
+ filepath: impl AsRef<std::path::Path>,
+ local_name: &str,
+ opsys: i64,
+ attr: i64,
+ ) -> bool {
let contents = match std::fs::read(filepath.as_ref()) {
Ok(c) => c,
Err(_) => return false,
@@ -238,21 +244,27 @@ impl ZipArchive {
return false;
};
let options =
- SimpleFileOptions::default().compression_method(zip::CompressionMethod::Deflated);
+ Self::entry_options(opsys, attr).compression_method(zip::CompressionMethod::Deflated);
if writer.start_file(local_name, options).is_err() {
return false;
}
std::io::Write::write_all(writer, &contents).is_ok()
}
- pub fn set_external_attributes_name(&self, _name: &str, _opsys: i64, _attr: i64) -> bool {
- // TODO(phase-c): PHP's setExternalAttributesName mutates an already-added
- // entry's external attributes (e.g. Unix permissions) after addFile. The
- // `zip` crate fixes external attributes at start_file time via FileOptions
- // and exposes no API to amend a written entry, so this cannot be faithfully
- // reproduced without re-architecting add_file. Left unimplemented rather
- // than silently dropping the permission bits.
- todo!()
+ /// `opsys` and `attr` carry what PHP passes to `setExternalAttributesName`, which
+ /// amends an entry after `addFile`. The `zip` crate fixes external attributes when
+ /// the entry is started, so they are taken up front instead. `unix_permissions`
+ /// keeps only the low 9 mode bits, on top of which the crate restores `S_IFREG` for
+ /// files and `S_IFDIR` for directories; libzip stores `attr` verbatim, so
+ /// setuid/setgid/sticky bits and the remaining file types do not survive.
+ fn entry_options(opsys: i64, attr: i64) -> SimpleFileOptions {
+ let system = match opsys {
+ Self::OPSYS_UNIX => zip::System::Unix,
+ _ => todo!(),
+ };
+ SimpleFileOptions::default()
+ .system(system)
+ .unix_permissions((attr >> 16) as u32)
}
pub fn get_status_string(&self) -> String {
diff --git a/crates/shirabe/src/package/archiver/zip_archiver.rs b/crates/shirabe/src/package/archiver/zip_archiver.rs
index e5bb613d..5604c07d 100644
--- a/crates/shirabe/src/package/archiver/zip_archiver.rs
+++ b/crates/shirabe/src/package/archiver/zip_archiver.rs
@@ -5,9 +5,7 @@ use crate::package::archiver::ArchiverInterface;
use crate::util::Filesystem;
use crate::util::Platform;
use indexmap::IndexMap;
-use shirabe_php_shim::{
- PhpMixed, RuntimeException, ZipArchive, class_exists, fileperms, method_exists, realpath,
-};
+use shirabe_php_shim::{RuntimeException, ZipArchive, class_exists, fileperms, realpath};
use std::path::PathBuf;
#[derive(Debug)]
@@ -71,16 +69,18 @@ impl ArchiverInterface for ZipArchiver {
));
}
+ // Ensure to preserve the permission umasks for the filepath in the archive.
+ let perms = fileperms(&filepath);
+
if filepath.is_dir() {
- zip.add_empty_dir(&relative_path.to_string_lossy());
+ zip.add_empty_dir(
+ &relative_path.to_string_lossy(),
+ ZipArchive::OPSYS_UNIX,
+ perms << 16,
+ );
} else {
- zip.add_file(&filepath, &relative_path.to_string_lossy());
- }
-
- // setExternalAttributesName() is only available with libzip 0.11.2 or above
- if method_exists(&PhpMixed::Null, "setExternalAttributesName") {
- let perms = fileperms(&filepath);
- zip.set_external_attributes_name(
+ zip.add_file(
+ &filepath,
&relative_path.to_string_lossy(),
ZipArchive::OPSYS_UNIX,
perms << 16,