Skip to content

Commit 1c55085

Browse files
committed
Add StreamWrapper API
This allows extensions to register and unregister custom stream wrappers
1 parent c9db20c commit 1c55085

File tree

6 files changed

+163
-3
lines changed

6 files changed

+163
-3
lines changed

allowed_bindings.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -263,5 +263,13 @@ bind! {
263263
sapi_header_struct,
264264
zend_is_auto_global,
265265
zend_llist_get_next_ex,
266-
zend_llist_get_prev_ex
266+
zend_llist_get_prev_ex,
267+
php_register_url_stream_wrapper,
268+
php_stream_locate_url_wrapper,
269+
php_unregister_url_stream_wrapper,
270+
php_unregister_url_stream_wrapper_volatile,
271+
php_register_url_stream_wrapper_volatile,
272+
php_stream_wrapper,
273+
zend_llist_get_prev_ex,
274+
php_stream_stdio_ops
267275
}

docsrs_bindings.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1986,6 +1986,36 @@ impl _php_stream {
19861986
__bindgen_bitfield_unit
19871987
}
19881988
}
1989+
extern "C" {
1990+
pub static mut php_stream_stdio_ops: php_stream_ops;
1991+
}
1992+
extern "C" {
1993+
pub fn php_register_url_stream_wrapper(
1994+
protocol: *const ::std::os::raw::c_char,
1995+
wrapper: *const php_stream_wrapper,
1996+
) -> zend_result;
1997+
}
1998+
extern "C" {
1999+
pub fn php_unregister_url_stream_wrapper(
2000+
protocol: *const ::std::os::raw::c_char,
2001+
) -> zend_result;
2002+
}
2003+
extern "C" {
2004+
pub fn php_register_url_stream_wrapper_volatile(
2005+
protocol: *mut zend_string,
2006+
wrapper: *mut php_stream_wrapper,
2007+
) -> zend_result;
2008+
}
2009+
extern "C" {
2010+
pub fn php_unregister_url_stream_wrapper_volatile(protocol: *mut zend_string) -> zend_result;
2011+
}
2012+
extern "C" {
2013+
pub fn php_stream_locate_url_wrapper(
2014+
path: *const ::std::os::raw::c_char,
2015+
path_for_open: *mut *const ::std::os::raw::c_char,
2016+
options: ::std::os::raw::c_int,
2017+
) -> *mut php_stream_wrapper;
2018+
}
19892019
pub type php_core_globals = _php_core_globals;
19902020
#[repr(C)]
19912021
pub struct _php_core_globals {

src/zend/ex.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::ffi::{zend_execute_data, ZEND_MM_ALIGNMENT, ZEND_MM_ALIGNMENT_MASK};
1+
use crate::ffi::{zend_execute_data, ZEND_MM_ALIGNMENT, ZEND_MM_ALIGNMENT_MASK, _zend_function};
22

33
use crate::{
44
args::ArgParser,
@@ -231,6 +231,18 @@ impl ExecuteData {
231231
let size = std::mem::size_of::<T>();
232232
((size as isize) + ZEND_MM_ALIGNMENT as isize - 1) & ZEND_MM_ALIGNMENT_MASK as isize
233233
}
234+
235+
pub fn previous(&self) -> Option<&Self> {
236+
unsafe {
237+
self.prev_execute_data.as_ref()
238+
}
239+
}
240+
241+
pub fn function(&self) -> Option<&_zend_function> {
242+
unsafe {
243+
self.func.as_ref()
244+
}
245+
}
234246
}
235247

236248
#[cfg(test)]

src/zend/function.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
33
use std::{fmt::Debug, os::raw::c_char, ptr};
44

5-
use crate::ffi::zend_function_entry;
5+
use crate::{ffi::{zend_function_entry, zend_function}, flags::FunctionType};
66

77
/// A Zend function entry.
88
pub type FunctionEntry = zend_function_entry;
@@ -36,3 +36,11 @@ impl FunctionEntry {
3636
Box::into_raw(Box::new(self))
3737
}
3838
}
39+
40+
pub type Function = zend_function;
41+
42+
impl Function {
43+
pub fn type_(&self) -> FunctionType {
44+
FunctionType::from(unsafe { self.type_ })
45+
}
46+
}

src/zend/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ mod globals;
99
mod handlers;
1010
mod linked_list;
1111
mod module;
12+
mod streams;
1213

1314
use crate::{error::Result, ffi::php_printf};
1415
use std::ffi::CString;
@@ -24,6 +25,7 @@ pub use globals::FileGlobals;
2425
pub use handlers::ZendObjectHandlers;
2526
pub use linked_list::ZendLinkedList;
2627
pub use module::ModuleEntry;
28+
pub use streams::*;
2729

2830
// Used as the format string for `php_printf`.
2931
const FORMAT_STR: &[u8] = b"%s\0";

src/zend/streams.rs

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
use std::ptr::{self, NonNull};
2+
3+
use crate::{
4+
ffi::{
5+
php_register_url_stream_wrapper, php_register_url_stream_wrapper_volatile, php_stream,
6+
php_stream_context, php_stream_locate_url_wrapper, php_stream_wrapper,
7+
php_stream_wrapper_ops, php_unregister_url_stream_wrapper,
8+
php_unregister_url_stream_wrapper_volatile, zend_string,
9+
},
10+
types::ZendStr,
11+
};
12+
13+
pub type StreamWrapper = php_stream_wrapper;
14+
15+
pub type StreamOpener = unsafe extern "C" fn(
16+
*mut StreamWrapper,
17+
*const std::ffi::c_char,
18+
*const std::ffi::c_char,
19+
i32,
20+
*mut *mut zend_string,
21+
*mut php_stream_context,
22+
i32,
23+
*const std::ffi::c_char,
24+
u32,
25+
*const std::ffi::c_char,
26+
u32,
27+
) -> *mut Stream;
28+
29+
impl StreamWrapper {
30+
pub fn get(name: &str) -> Option<&Self> {
31+
unsafe {
32+
let result = php_stream_locate_url_wrapper(name.as_ptr().cast(), ptr::null_mut(), 0);
33+
Some(NonNull::new(result)?.as_ref())
34+
}
35+
}
36+
37+
pub fn get_mut(name: &str) -> Option<&mut Self> {
38+
unsafe {
39+
let result = php_stream_locate_url_wrapper(name.as_ptr().cast(), ptr::null_mut(), 0);
40+
Some(NonNull::new(result)?.as_mut())
41+
}
42+
}
43+
44+
pub fn register(self, name: &str) -> Result<Self, ()> {
45+
// We have to convert it to a static so owned streamwrapper doesn't get dropped.
46+
let copy = Box::new(self);
47+
let copy = Box::leak(copy);
48+
let name = std::ffi::CString::new(name).unwrap();
49+
let result = unsafe { php_register_url_stream_wrapper(name.as_ptr(), copy) };
50+
if result == 0 {
51+
Ok(*copy)
52+
} else {
53+
Err(())
54+
}
55+
}
56+
57+
pub fn register_volatile(self, name: &str) -> Result<Self, ()> {
58+
// We have to convert it to a static so owned streamwrapper doesn't get dropped.
59+
let copy = Box::new(self);
60+
let copy = Box::leak(copy);
61+
let name = ZendStr::new(name, false);
62+
let result =
63+
unsafe { php_register_url_stream_wrapper_volatile((*name).as_ptr() as _, copy) };
64+
if result == 0 {
65+
Ok(*copy)
66+
} else {
67+
Err(())
68+
}
69+
}
70+
71+
pub fn unregister(name: &str) -> Result<(), ()> {
72+
let name = std::ffi::CString::new(name).unwrap();
73+
match unsafe { php_unregister_url_stream_wrapper(name.as_ptr()) } {
74+
0 => Ok(()),
75+
_ => Err(()),
76+
}
77+
}
78+
79+
pub fn unregister_volatile(name: &str) -> Result<(), ()> {
80+
let name = ZendStr::new(name, false);
81+
match unsafe { php_unregister_url_stream_wrapper_volatile((*name).as_ptr() as _) } {
82+
0 => Ok(()),
83+
_ => Err(()),
84+
}
85+
}
86+
87+
pub fn wops(&self) -> &php_stream_wrapper_ops {
88+
unsafe { &*self.wops }
89+
}
90+
91+
pub fn wops_mut(&mut self) -> &mut php_stream_wrapper_ops {
92+
unsafe { &mut *(self.wops as *mut php_stream_wrapper_ops) }
93+
}
94+
}
95+
96+
pub type Stream = php_stream;
97+
98+
pub type StreamWrapperOps = php_stream_wrapper_ops;
99+
100+
impl StreamWrapperOps {}

0 commit comments

Comments
 (0)