diff options
Diffstat (limited to 'crates/shirabe-php-shim')
| -rw-r--r-- | crates/shirabe-php-shim/src/runtime.rs | 7 | ||||
| -rw-r--r-- | crates/shirabe-php-shim/src/zip.rs | 36 |
2 files changed, 25 insertions, 18 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 { |
