From 1c550852abd59af8886827ae131511330aaaa5ca Mon Sep 17 00:00:00 2001 From: Joe Hoyle Date: Wed, 19 Jul 2023 10:59:32 +0200 Subject: [PATCH 1/4] Add StreamWrapper API This allows extensions to register and unregister custom stream wrappers --- allowed_bindings.rs | 10 ++++- docsrs_bindings.rs | 30 +++++++++++++ src/zend/ex.rs | 14 +++++- src/zend/function.rs | 10 ++++- src/zend/mod.rs | 2 + src/zend/streams.rs | 100 +++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 163 insertions(+), 3 deletions(-) create mode 100644 src/zend/streams.rs diff --git a/allowed_bindings.rs b/allowed_bindings.rs index 8578480..5b96e76 100644 --- a/allowed_bindings.rs +++ b/allowed_bindings.rs @@ -263,5 +263,13 @@ bind! { sapi_header_struct, zend_is_auto_global, zend_llist_get_next_ex, - zend_llist_get_prev_ex + zend_llist_get_prev_ex, + php_register_url_stream_wrapper, + php_stream_locate_url_wrapper, + php_unregister_url_stream_wrapper, + php_unregister_url_stream_wrapper_volatile, + php_register_url_stream_wrapper_volatile, + php_stream_wrapper, + zend_llist_get_prev_ex, + php_stream_stdio_ops } diff --git a/docsrs_bindings.rs b/docsrs_bindings.rs index 22817ac..5a5fbd3 100644 --- a/docsrs_bindings.rs +++ b/docsrs_bindings.rs @@ -1986,6 +1986,36 @@ impl _php_stream { __bindgen_bitfield_unit } } +extern "C" { + pub static mut php_stream_stdio_ops: php_stream_ops; +} +extern "C" { + pub fn php_register_url_stream_wrapper( + protocol: *const ::std::os::raw::c_char, + wrapper: *const php_stream_wrapper, + ) -> zend_result; +} +extern "C" { + pub fn php_unregister_url_stream_wrapper( + protocol: *const ::std::os::raw::c_char, + ) -> zend_result; +} +extern "C" { + pub fn php_register_url_stream_wrapper_volatile( + protocol: *mut zend_string, + wrapper: *mut php_stream_wrapper, + ) -> zend_result; +} +extern "C" { + pub fn php_unregister_url_stream_wrapper_volatile(protocol: *mut zend_string) -> zend_result; +} +extern "C" { + pub fn php_stream_locate_url_wrapper( + path: *const ::std::os::raw::c_char, + path_for_open: *mut *const ::std::os::raw::c_char, + options: ::std::os::raw::c_int, + ) -> *mut php_stream_wrapper; +} pub type php_core_globals = _php_core_globals; #[repr(C)] pub struct _php_core_globals { diff --git a/src/zend/ex.rs b/src/zend/ex.rs index dada00e..a90a2f4 100644 --- a/src/zend/ex.rs +++ b/src/zend/ex.rs @@ -1,4 +1,4 @@ -use crate::ffi::{zend_execute_data, ZEND_MM_ALIGNMENT, ZEND_MM_ALIGNMENT_MASK}; +use crate::ffi::{zend_execute_data, ZEND_MM_ALIGNMENT, ZEND_MM_ALIGNMENT_MASK, _zend_function}; use crate::{ args::ArgParser, @@ -231,6 +231,18 @@ impl ExecuteData { let size = std::mem::size_of::(); ((size as isize) + ZEND_MM_ALIGNMENT as isize - 1) & ZEND_MM_ALIGNMENT_MASK as isize } + + pub fn previous(&self) -> Option<&Self> { + unsafe { + self.prev_execute_data.as_ref() + } + } + + pub fn function(&self) -> Option<&_zend_function> { + unsafe { + self.func.as_ref() + } + } } #[cfg(test)] diff --git a/src/zend/function.rs b/src/zend/function.rs index ba889d7..51d3e8c 100644 --- a/src/zend/function.rs +++ b/src/zend/function.rs @@ -2,7 +2,7 @@ use std::{fmt::Debug, os::raw::c_char, ptr}; -use crate::ffi::zend_function_entry; +use crate::{ffi::{zend_function_entry, zend_function}, flags::FunctionType}; /// A Zend function entry. pub type FunctionEntry = zend_function_entry; @@ -36,3 +36,11 @@ impl FunctionEntry { Box::into_raw(Box::new(self)) } } + +pub type Function = zend_function; + +impl Function { + pub fn type_(&self) -> FunctionType { + FunctionType::from(unsafe { self.type_ }) + } +} diff --git a/src/zend/mod.rs b/src/zend/mod.rs index ddd815e..d2ff753 100644 --- a/src/zend/mod.rs +++ b/src/zend/mod.rs @@ -9,6 +9,7 @@ mod globals; mod handlers; mod linked_list; mod module; +mod streams; use crate::{error::Result, ffi::php_printf}; use std::ffi::CString; @@ -24,6 +25,7 @@ pub use globals::FileGlobals; pub use handlers::ZendObjectHandlers; pub use linked_list::ZendLinkedList; pub use module::ModuleEntry; +pub use streams::*; // Used as the format string for `php_printf`. const FORMAT_STR: &[u8] = b"%s\0"; diff --git a/src/zend/streams.rs b/src/zend/streams.rs new file mode 100644 index 0000000..1045a0c --- /dev/null +++ b/src/zend/streams.rs @@ -0,0 +1,100 @@ +use std::ptr::{self, NonNull}; + +use crate::{ + ffi::{ + php_register_url_stream_wrapper, php_register_url_stream_wrapper_volatile, php_stream, + php_stream_context, php_stream_locate_url_wrapper, php_stream_wrapper, + php_stream_wrapper_ops, php_unregister_url_stream_wrapper, + php_unregister_url_stream_wrapper_volatile, zend_string, + }, + types::ZendStr, +}; + +pub type StreamWrapper = php_stream_wrapper; + +pub type StreamOpener = unsafe extern "C" fn( + *mut StreamWrapper, + *const std::ffi::c_char, + *const std::ffi::c_char, + i32, + *mut *mut zend_string, + *mut php_stream_context, + i32, + *const std::ffi::c_char, + u32, + *const std::ffi::c_char, + u32, +) -> *mut Stream; + +impl StreamWrapper { + pub fn get(name: &str) -> Option<&Self> { + unsafe { + let result = php_stream_locate_url_wrapper(name.as_ptr().cast(), ptr::null_mut(), 0); + Some(NonNull::new(result)?.as_ref()) + } + } + + pub fn get_mut(name: &str) -> Option<&mut Self> { + unsafe { + let result = php_stream_locate_url_wrapper(name.as_ptr().cast(), ptr::null_mut(), 0); + Some(NonNull::new(result)?.as_mut()) + } + } + + pub fn register(self, name: &str) -> Result { + // We have to convert it to a static so owned streamwrapper doesn't get dropped. + let copy = Box::new(self); + let copy = Box::leak(copy); + let name = std::ffi::CString::new(name).unwrap(); + let result = unsafe { php_register_url_stream_wrapper(name.as_ptr(), copy) }; + if result == 0 { + Ok(*copy) + } else { + Err(()) + } + } + + pub fn register_volatile(self, name: &str) -> Result { + // We have to convert it to a static so owned streamwrapper doesn't get dropped. + let copy = Box::new(self); + let copy = Box::leak(copy); + let name = ZendStr::new(name, false); + let result = + unsafe { php_register_url_stream_wrapper_volatile((*name).as_ptr() as _, copy) }; + if result == 0 { + Ok(*copy) + } else { + Err(()) + } + } + + pub fn unregister(name: &str) -> Result<(), ()> { + let name = std::ffi::CString::new(name).unwrap(); + match unsafe { php_unregister_url_stream_wrapper(name.as_ptr()) } { + 0 => Ok(()), + _ => Err(()), + } + } + + pub fn unregister_volatile(name: &str) -> Result<(), ()> { + let name = ZendStr::new(name, false); + match unsafe { php_unregister_url_stream_wrapper_volatile((*name).as_ptr() as _) } { + 0 => Ok(()), + _ => Err(()), + } + } + + pub fn wops(&self) -> &php_stream_wrapper_ops { + unsafe { &*self.wops } + } + + pub fn wops_mut(&mut self) -> &mut php_stream_wrapper_ops { + unsafe { &mut *(self.wops as *mut php_stream_wrapper_ops) } + } +} + +pub type Stream = php_stream; + +pub type StreamWrapperOps = php_stream_wrapper_ops; + +impl StreamWrapperOps {} From cb89c7b4d895a8f4d6b09ebbc610a6829d4b2bed Mon Sep 17 00:00:00 2001 From: Joe Hoyle Date: Wed, 19 Jul 2023 11:02:56 +0200 Subject: [PATCH 2/4] Revert change to function --- src/zend/function.rs | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/src/zend/function.rs b/src/zend/function.rs index 51d3e8c..ba889d7 100644 --- a/src/zend/function.rs +++ b/src/zend/function.rs @@ -2,7 +2,7 @@ use std::{fmt::Debug, os::raw::c_char, ptr}; -use crate::{ffi::{zend_function_entry, zend_function}, flags::FunctionType}; +use crate::ffi::zend_function_entry; /// A Zend function entry. pub type FunctionEntry = zend_function_entry; @@ -36,11 +36,3 @@ impl FunctionEntry { Box::into_raw(Box::new(self)) } } - -pub type Function = zend_function; - -impl Function { - pub fn type_(&self) -> FunctionType { - FunctionType::from(unsafe { self.type_ }) - } -} From 52525f249f84ae0ecb85abf0dff3d0fd6533fa46 Mon Sep 17 00:00:00 2001 From: Joe Hoyle Date: Wed, 19 Jul 2023 11:36:08 +0200 Subject: [PATCH 3/4] Fix allowed bindings duplication --- allowed_bindings.rs | 1 - src/zend/ex.rs | 10 +++------- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/allowed_bindings.rs b/allowed_bindings.rs index 5b96e76..d67347a 100644 --- a/allowed_bindings.rs +++ b/allowed_bindings.rs @@ -270,6 +270,5 @@ bind! { php_unregister_url_stream_wrapper_volatile, php_register_url_stream_wrapper_volatile, php_stream_wrapper, - zend_llist_get_prev_ex, php_stream_stdio_ops } diff --git a/src/zend/ex.rs b/src/zend/ex.rs index a90a2f4..fac1b93 100644 --- a/src/zend/ex.rs +++ b/src/zend/ex.rs @@ -1,4 +1,4 @@ -use crate::ffi::{zend_execute_data, ZEND_MM_ALIGNMENT, ZEND_MM_ALIGNMENT_MASK, _zend_function}; +use crate::ffi::{_zend_function, zend_execute_data, ZEND_MM_ALIGNMENT, ZEND_MM_ALIGNMENT_MASK}; use crate::{ args::ArgParser, @@ -233,15 +233,11 @@ impl ExecuteData { } pub fn previous(&self) -> Option<&Self> { - unsafe { - self.prev_execute_data.as_ref() - } + unsafe { self.prev_execute_data.as_ref() } } pub fn function(&self) -> Option<&_zend_function> { - unsafe { - self.func.as_ref() - } + unsafe { self.func.as_ref() } } } From 87ab71846c80bf04e05cc095faad7d9758159872 Mon Sep 17 00:00:00 2001 From: Joe Hoyle Date: Wed, 19 Jul 2023 15:35:19 +0200 Subject: [PATCH 4/4] Remove additional unrelated functions --- src/zend/ex.rs | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/zend/ex.rs b/src/zend/ex.rs index fac1b93..0baf564 100644 --- a/src/zend/ex.rs +++ b/src/zend/ex.rs @@ -231,14 +231,6 @@ impl ExecuteData { let size = std::mem::size_of::(); ((size as isize) + ZEND_MM_ALIGNMENT as isize - 1) & ZEND_MM_ALIGNMENT_MASK as isize } - - pub fn previous(&self) -> Option<&Self> { - unsafe { self.prev_execute_data.as_ref() } - } - - pub fn function(&self) -> Option<&_zend_function> { - unsafe { self.func.as_ref() } - } } #[cfg(test)]