diff --git a/allowed_bindings.rs b/allowed_bindings.rs index 8f5e958b9..98248f117 100644 --- a/allowed_bindings.rs +++ b/allowed_bindings.rs @@ -226,16 +226,24 @@ bind! { executor_globals, php_core_globals, core_globals, + sapi_globals_struct, + sapi_globals, php_printf, __zend_malloc, tsrm_get_ls_cache, executor_globals_offset, core_globals_offset, + sapi_globals_offset, TRACK_VARS_POST, TRACK_VARS_GET, TRACK_VARS_COOKIE, TRACK_VARS_SERVER, TRACK_VARS_ENV, TRACK_VARS_FILES, - TRACK_VARS_REQUEST + TRACK_VARS_REQUEST, + sapi_request_info, + sapi_header_struct, + zend_is_auto_global, + zend_llist_get_next_ex, + zend_llist_get_prev_ex } diff --git a/docsrs_bindings.rs b/docsrs_bindings.rs index e03003725..5dba20b72 100644 --- a/docsrs_bindings.rs +++ b/docsrs_bindings.rs @@ -1,7 +1,87 @@ /* automatically generated by rust-bindgen 0.65.1 */ +#[repr(C)] +#[derive(Copy, Clone, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] +pub struct __BindgenBitfieldUnit { + storage: Storage, +} +impl __BindgenBitfieldUnit { + #[inline] + pub const fn new(storage: Storage) -> Self { + Self { storage } + } +} +impl __BindgenBitfieldUnit +where + Storage: AsRef<[u8]> + AsMut<[u8]>, +{ + #[inline] + pub fn get_bit(&self, index: usize) -> bool { + debug_assert!(index / 8 < self.storage.as_ref().len()); + let byte_index = index / 8; + let byte = self.storage.as_ref()[byte_index]; + let bit_index = if cfg!(target_endian = "big") { + 7 - (index % 8) + } else { + index % 8 + }; + let mask = 1 << bit_index; + byte & mask == mask + } + #[inline] + pub fn set_bit(&mut self, index: usize, val: bool) { + debug_assert!(index / 8 < self.storage.as_ref().len()); + let byte_index = index / 8; + let byte = &mut self.storage.as_mut()[byte_index]; + let bit_index = if cfg!(target_endian = "big") { + 7 - (index % 8) + } else { + index % 8 + }; + let mask = 1 << bit_index; + if val { + *byte |= mask; + } else { + *byte &= !mask; + } + } + #[inline] + pub fn get(&self, bit_offset: usize, bit_width: u8) -> u64 { + debug_assert!(bit_width <= 64); + debug_assert!(bit_offset / 8 < self.storage.as_ref().len()); + debug_assert!((bit_offset + (bit_width as usize)) / 8 <= self.storage.as_ref().len()); + let mut val = 0; + for i in 0..(bit_width as usize) { + if self.get_bit(i + bit_offset) { + let index = if cfg!(target_endian = "big") { + bit_width as usize - 1 - i + } else { + i + }; + val |= 1 << index; + } + } + val + } + #[inline] + pub fn set(&mut self, bit_offset: usize, bit_width: u8, val: u64) { + debug_assert!(bit_width <= 64); + debug_assert!(bit_offset / 8 < self.storage.as_ref().len()); + debug_assert!((bit_offset + (bit_width as usize)) / 8 <= self.storage.as_ref().len()); + for i in 0..(bit_width as usize) { + let mask = 1 << i; + let val_bit_is_set = val & mask == mask; + let index = if cfg!(target_endian = "big") { + bit_width as usize - 1 - i + } else { + i + }; + self.set_bit(index + bit_offset, val_bit_is_set); + } + } +} pub const ZEND_DEBUG: u32 = 1; -pub const _ZEND_TYPE_NAME_BIT: u32 = 16777216; +pub const _ZEND_TYPE_NAME_BIT: u32 = 8388608; pub const _ZEND_TYPE_NULLABLE_BIT: u32 = 2; pub const HT_MIN_SIZE: u32 = 8; pub const IS_UNDEF: u32 = 0; @@ -20,7 +100,7 @@ pub const IS_CALLABLE: u32 = 12; pub const IS_VOID: u32 = 14; pub const IS_MIXED: u32 = 16; pub const IS_PTR: u32 = 13; -pub const _IS_BOOL: u32 = 18; +pub const _IS_BOOL: u32 = 17; pub const Z_TYPE_FLAGS_SHIFT: u32 = 8; pub const IS_TYPE_REFCOUNTED: u32 = 1; pub const IS_TYPE_COLLECTABLE: u32 = 2; @@ -54,11 +134,13 @@ pub const ZEND_ACC_USE_GUARDS: u32 = 2048; pub const ZEND_ACC_CONSTANTS_UPDATED: u32 = 4096; pub const ZEND_ACC_NO_DYNAMIC_PROPERTIES: u32 = 8192; pub const ZEND_HAS_STATIC_IN_METHODS: u32 = 16384; +pub const ZEND_ACC_PROPERTY_TYPES_RESOLVED: u32 = 32768; +pub const ZEND_ACC_REUSE_GET_ITERATOR: u32 = 65536; pub const ZEND_ACC_RESOLVED_PARENT: u32 = 131072; pub const ZEND_ACC_RESOLVED_INTERFACES: u32 = 262144; pub const ZEND_ACC_UNRESOLVED_VARIANCE: u32 = 524288; pub const ZEND_ACC_NEARLY_LINKED: u32 = 1048576; -pub const ZEND_ACC_NOT_SERIALIZABLE: u32 = 536870912; +pub const ZEND_ACC_HAS_UNLINKED_USES: u32 = 2097152; pub const ZEND_ACC_DEPRECATED: u32 = 2048; pub const ZEND_ACC_RETURN_REFERENCE: u32 = 4096; pub const ZEND_ACC_HAS_RETURN_TYPE: u32 = 8192; @@ -77,9 +159,9 @@ pub const ZEND_ACC_DONE_PASS_TWO: u32 = 33554432; pub const ZEND_ACC_HEAP_RT_CACHE: u32 = 67108864; pub const ZEND_ACC_STRICT_TYPES: u32 = 2147483648; pub const ZEND_ISEMPTY: u32 = 1; -pub const _ZEND_SEND_MODE_SHIFT: u32 = 25; -pub const _ZEND_IS_VARIADIC_BIT: u32 = 134217728; -pub const ZEND_MODULE_API_NO: u32 = 20220829; +pub const _ZEND_SEND_MODE_SHIFT: u32 = 24; +pub const _ZEND_IS_VARIADIC_BIT: u32 = 67108864; +pub const ZEND_MODULE_API_NO: u32 = 20200930; pub const USING_ZTS: u32 = 0; pub const MAY_BE_BOOL: u32 = 12; pub const MAY_BE_ANY: u32 = 1022; @@ -94,8 +176,94 @@ pub const CONST_CS: u32 = 0; pub const CONST_PERSISTENT: u32 = 1; pub const CONST_NO_FILE_CACHE: u32 = 2; pub const CONST_DEPRECATED: u32 = 4; +pub type __uint16_t = ::std::os::raw::c_ushort; +pub type __int32_t = ::std::os::raw::c_int; +pub type __uint32_t = ::std::os::raw::c_uint; +pub type __int64_t = ::std::os::raw::c_longlong; +pub type __uint64_t = ::std::os::raw::c_ulonglong; +pub type __darwin_time_t = ::std::os::raw::c_long; +pub type __darwin_blkcnt_t = __int64_t; +pub type __darwin_blksize_t = __int32_t; +pub type __darwin_dev_t = __int32_t; +pub type __darwin_gid_t = __uint32_t; +pub type __darwin_ino64_t = __uint64_t; +pub type __darwin_mode_t = __uint16_t; +pub type __darwin_off_t = __int64_t; +pub type __darwin_uid_t = __uint32_t; +pub type uid_t = __darwin_uid_t; +pub type dev_t = __darwin_dev_t; +pub type mode_t = __darwin_mode_t; +pub type blkcnt_t = __darwin_blkcnt_t; +pub type blksize_t = __darwin_blksize_t; +pub type gid_t = __darwin_gid_t; +pub type nlink_t = __uint16_t; +pub type off_t = __darwin_off_t; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct timespec { + pub tv_sec: __darwin_time_t, + pub tv_nsec: ::std::os::raw::c_long, +} +pub type fpos_t = __darwin_off_t; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct __sbuf { + pub _base: *mut ::std::os::raw::c_uchar, + pub _size: ::std::os::raw::c_int, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct __sFILEX { + _unused: [u8; 0], +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct __sFILE { + pub _p: *mut ::std::os::raw::c_uchar, + pub _r: ::std::os::raw::c_int, + pub _w: ::std::os::raw::c_int, + pub _flags: ::std::os::raw::c_short, + pub _file: ::std::os::raw::c_short, + pub _bf: __sbuf, + pub _lbfsize: ::std::os::raw::c_int, + pub _cookie: *mut ::std::os::raw::c_void, + pub _close: ::std::option::Option< + unsafe extern "C" fn(arg1: *mut ::std::os::raw::c_void) -> ::std::os::raw::c_int, + >, + pub _read: ::std::option::Option< + unsafe extern "C" fn( + arg1: *mut ::std::os::raw::c_void, + arg2: *mut ::std::os::raw::c_char, + arg3: ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int, + >, + pub _seek: ::std::option::Option< + unsafe extern "C" fn( + arg1: *mut ::std::os::raw::c_void, + arg2: fpos_t, + arg3: ::std::os::raw::c_int, + ) -> fpos_t, + >, + pub _write: ::std::option::Option< + unsafe extern "C" fn( + arg1: *mut ::std::os::raw::c_void, + arg2: *const ::std::os::raw::c_char, + arg3: ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int, + >, + pub _ub: __sbuf, + pub _extra: *mut __sFILEX, + pub _ur: ::std::os::raw::c_int, + pub _ubuf: [::std::os::raw::c_uchar; 3usize], + pub _nbuf: [::std::os::raw::c_uchar; 1usize], + pub _lb: __sbuf, + pub _blksize: ::std::os::raw::c_int, + pub _offset: fpos_t, +} +pub type FILE = __sFILE; pub type zend_long = i64; pub type zend_ulong = u64; +pub type zend_off_t = i64; pub type zend_bool = bool; pub type zend_uchar = ::std::os::raw::c_uchar; pub const ZEND_RESULT_CODE_SUCCESS: ZEND_RESULT_CODE = 0; @@ -180,6 +348,7 @@ pub union _zval_struct__bindgen_ty_2 { pub num_args: u32, pub fe_pos: u32, pub fe_iter_idx: u32, + pub access_flags: u32, pub property_guard: u32, pub constant_flags: u32, pub extra: u32, @@ -221,7 +390,7 @@ pub struct _zend_array { pub gc: zend_refcounted_h, pub u: _zend_array__bindgen_ty_1, pub nTableMask: u32, - pub __bindgen_anon_1: _zend_array__bindgen_ty_2, + pub arData: *mut Bucket, pub nNumUsed: u32, pub nNumOfElements: u32, pub nTableSize: u32, @@ -243,13 +412,6 @@ pub struct _zend_array__bindgen_ty_1__bindgen_ty_1 { pub nIteratorsCount: zend_uchar, pub _unused2: zend_uchar, } -#[repr(C)] -#[derive(Copy, Clone)] -pub union _zend_array__bindgen_ty_2 { - pub arHash: *mut u32, - pub arData: *mut Bucket, - pub arPacked: *mut zval, -} pub type HashPosition = u32; #[repr(C)] #[derive(Debug, Copy, Clone)] @@ -271,7 +433,7 @@ pub struct _zend_object { #[derive(Copy, Clone)] pub struct _zend_resource { pub gc: zend_refcounted_h, - pub handle: zend_long, + pub handle: ::std::os::raw::c_int, pub type_: ::std::os::raw::c_int, pub ptr: *mut ::std::os::raw::c_void, } @@ -335,6 +497,19 @@ pub struct _zend_llist { pub traverse_ptr: *mut zend_llist_element, } pub type zend_llist = _zend_llist; +pub type zend_llist_position = *mut zend_llist_element; +extern "C" { + pub fn zend_llist_get_next_ex( + l: *mut zend_llist, + pos: *mut zend_llist_position, + ) -> *mut ::std::os::raw::c_void; +} +extern "C" { + pub fn zend_llist_get_prev_ex( + l: *mut zend_llist, + pos: *mut zend_llist_position, + ) -> *mut ::std::os::raw::c_void; +} pub type zend_string_init_interned_func_t = ::std::option::Option< unsafe extern "C" fn( str_: *const ::std::os::raw::c_char, @@ -393,7 +568,7 @@ extern "C" { pub fn zend_hash_get_current_key_zval_ex( ht: *const HashTable, key: *mut zval, - pos: *const HashPosition, + pos: *mut HashPosition, ); } extern "C" { @@ -476,13 +651,27 @@ pub struct _zend_class_iterator_funcs { pub type zend_class_iterator_funcs = _zend_class_iterator_funcs; #[repr(C)] #[derive(Debug, Copy, Clone)] -pub struct _zend_class_arrayaccess_funcs { - pub zf_offsetget: *mut zend_function, - pub zf_offsetexists: *mut zend_function, - pub zf_offsetset: *mut zend_function, - pub zf_offsetunset: *mut zend_function, -} -pub type zend_class_arrayaccess_funcs = _zend_class_arrayaccess_funcs; +pub struct stat { + pub st_dev: dev_t, + pub st_mode: mode_t, + pub st_nlink: nlink_t, + pub st_ino: __darwin_ino64_t, + pub st_uid: uid_t, + pub st_gid: gid_t, + pub st_rdev: dev_t, + pub st_atimespec: timespec, + pub st_mtimespec: timespec, + pub st_ctimespec: timespec, + pub st_birthtimespec: timespec, + pub st_size: off_t, + pub st_blocks: blkcnt_t, + pub st_blksize: blksize_t, + pub st_flags: __uint32_t, + pub st_gen: __uint32_t, + pub st_lspare: __int32_t, + pub st_qspare: [__int64_t; 2usize], +} +pub type zend_stat_t = stat; #[repr(C)] #[derive(Debug, Copy, Clone)] pub struct _zend_serialize_data { @@ -528,44 +717,6 @@ pub struct _zend_trait_alias { } pub type zend_trait_alias = _zend_trait_alias; #[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct _zend_class_mutable_data { - pub default_properties_table: *mut zval, - pub constants_table: *mut HashTable, - pub ce_flags: u32, - pub backed_enum_table: *mut HashTable, -} -pub type zend_class_mutable_data = _zend_class_mutable_data; -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct _zend_class_dependency { - pub name: *mut zend_string, - pub ce: *mut zend_class_entry, -} -pub type zend_class_dependency = _zend_class_dependency; -pub type zend_inheritance_cache_entry = _zend_inheritance_cache_entry; -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct _zend_error_info { - pub type_: ::std::os::raw::c_int, - pub lineno: u32, - pub filename: *mut zend_string, - pub message: *mut zend_string, -} -pub type zend_error_info = _zend_error_info; -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct _zend_inheritance_cache_entry { - pub next: *mut zend_inheritance_cache_entry, - pub ce: *mut zend_class_entry, - pub parent: *mut zend_class_entry, - pub dependencies: *mut zend_class_dependency, - pub dependencies_count: u32, - pub num_warnings: u32, - pub warnings: *mut *mut zend_error_info, - pub traits_and_interfaces: [*mut zend_class_entry; 1usize], -} -#[repr(C)] pub struct _zend_class_entry { pub type_: ::std::os::raw::c_char, pub name: *mut zend_string, @@ -576,12 +727,10 @@ pub struct _zend_class_entry { pub default_static_members_count: ::std::os::raw::c_int, pub default_properties_table: *mut zval, pub default_static_members_table: *mut zval, - pub static_members_table__ptr: *mut zval, + pub static_members_table__ptr: *mut *mut zval, pub function_table: HashTable, pub properties_info: HashTable, pub constants_table: HashTable, - pub mutable_data__ptr: *mut zend_class_mutable_data, - pub inheritance_cache: *mut zend_inheritance_cache_entry, pub properties_info_table: *mut *mut _zend_property_info, pub constructor: *mut zend_function, pub destructor: *mut zend_function, @@ -597,7 +746,6 @@ pub struct _zend_class_entry { pub __serialize: *mut zend_function, pub __unserialize: *mut zend_function, pub iterator_funcs_ptr: *mut zend_class_iterator_funcs, - pub arrayaccess_funcs_ptr: *mut zend_class_arrayaccess_funcs, pub __bindgen_anon_2: _zend_class_entry__bindgen_ty_2, pub get_iterator: ::std::option::Option< unsafe extern "C" fn( @@ -636,8 +784,6 @@ pub struct _zend_class_entry { pub trait_aliases: *mut *mut zend_trait_alias, pub trait_precedences: *mut *mut zend_trait_precedence, pub attributes: *mut HashTable, - pub enum_backing_type: u32, - pub backed_enum_table: *mut HashTable, pub info: _zend_class_entry__bindgen_ty_4, } #[repr(C)] @@ -779,10 +925,10 @@ pub type zend_object_get_method_t = ::std::option::Option< >; pub type zend_object_get_constructor_t = ::std::option::Option *mut zend_function>; -pub type zend_object_free_obj_t = - ::std::option::Option; pub type zend_object_dtor_obj_t = ::std::option::Option; +pub type zend_object_free_obj_t = + ::std::option::Option; pub type zend_object_clone_obj_t = ::std::option::Option *mut zend_object>; pub type zend_object_get_class_name_t = @@ -795,10 +941,10 @@ pub type zend_object_cast_t = ::std::option::Option< readobj: *mut zend_object, retval: *mut zval, type_: ::std::os::raw::c_int, - ) -> zend_result, + ) -> ::std::os::raw::c_int, >; pub type zend_object_count_elements_t = ::std::option::Option< - unsafe extern "C" fn(object: *mut zend_object, count: *mut zend_long) -> zend_result, + unsafe extern "C" fn(object: *mut zend_object, count: *mut zend_long) -> ::std::os::raw::c_int, >; pub type zend_object_get_closure_t = ::std::option::Option< unsafe extern "C" fn( @@ -806,8 +952,8 @@ pub type zend_object_get_closure_t = ::std::option::Option< ce_ptr: *mut *mut zend_class_entry, fptr_ptr: *mut *mut zend_function, obj_ptr: *mut *mut zend_object, - check_only: bool, - ) -> zend_result, + check_only: zend_bool, + ) -> ::std::os::raw::c_int, >; pub type zend_object_get_gc_t = ::std::option::Option< unsafe extern "C" fn( @@ -822,7 +968,7 @@ pub type zend_object_do_operation_t = ::std::option::Option< result: *mut zval, op1: *mut zval, op2: *mut zval, - ) -> zend_result, + ) -> ::std::os::raw::c_int, >; #[repr(C)] #[derive(Debug, Copy, Clone)] @@ -885,7 +1031,7 @@ extern "C" { ) -> ::std::os::raw::c_int; } extern "C" { - pub fn zend_is_identical(op1: *mut zval, op2: *mut zval) -> bool; + pub fn zend_is_identical(op1: *mut zval, op2: *mut zval) -> zend_bool; } extern "C" { pub fn zend_is_true(op: *mut zval) -> ::std::os::raw::c_int; @@ -973,13 +1119,13 @@ pub struct _zend_op_array { pub required_num_args: u32, pub arg_info: *mut zend_arg_info, pub attributes: *mut HashTable, - pub T: u32, - pub run_time_cache__ptr: *mut *mut ::std::os::raw::c_void, pub cache_size: ::std::os::raw::c_int, pub last_var: ::std::os::raw::c_int, + pub T: u32, pub last: u32, pub opcodes: *mut zend_op, - pub static_variables_ptr__ptr: *mut HashTable, + pub run_time_cache__ptr: *mut *mut *mut ::std::os::raw::c_void, + pub static_variables_ptr__ptr: *mut *mut HashTable, pub static_variables: *mut HashTable, pub vars: *mut *mut zend_string, pub refcount: *mut u32, @@ -992,9 +1138,7 @@ pub struct _zend_op_array { pub line_end: u32, pub doc_comment: *mut zend_string, pub last_literal: ::std::os::raw::c_int, - pub num_dynamic_func_defs: u32, pub literals: *mut zval, - pub dynamic_func_defs: *mut *mut zend_op_array, pub reserved: [*mut ::std::os::raw::c_void; 6usize], } pub type zif_handler = ::std::option::Option< @@ -1013,8 +1157,6 @@ pub struct _zend_internal_function { pub required_num_args: u32, pub arg_info: *mut zend_internal_arg_info, pub attributes: *mut HashTable, - pub T: u32, - pub run_time_cache__ptr: *mut *mut ::std::os::raw::c_void, pub handler: zif_handler, pub module: *mut _zend_module_entry, pub reserved: [*mut ::std::os::raw::c_void; 6usize], @@ -1042,8 +1184,6 @@ pub struct _zend_function__bindgen_ty_1 { pub required_num_args: u32, pub arg_info: *mut zend_arg_info, pub attributes: *mut HashTable, - pub T: u32, - pub run_time_cache__ptr: *mut *mut ::std::os::raw::c_void, } #[repr(C)] pub struct _zend_execute_data { @@ -1064,12 +1204,6 @@ extern "C" { } #[repr(C)] #[derive(Debug, Copy, Clone)] -pub struct zend_atomic_bool_s { - pub value: u8, -} -pub type zend_atomic_bool = zend_atomic_bool_s; -#[repr(C)] -#[derive(Debug, Copy, Clone)] pub struct _zend_stack { pub size: ::std::os::raw::c_int, pub top: ::std::os::raw::c_int, @@ -1104,18 +1238,6 @@ extern "C" { pub type zend_vm_stack = *mut _zend_vm_stack; pub type zend_ini_entry = _zend_ini_entry; #[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct _zend_fiber_context { - _unused: [u8; 0], -} -pub type zend_fiber_context = _zend_fiber_context; -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct _zend_fiber { - _unused: [u8; 0], -} -pub type zend_fiber = _zend_fiber; -#[repr(C)] pub struct _zend_executor_globals { pub uninitialized_zval: zval, pub error_zval: zval, @@ -1143,10 +1265,10 @@ pub struct _zend_executor_globals { pub persistent_functions_count: u32, pub persistent_classes_count: u32, pub in_autoload: *mut HashTable, - pub full_tables_cleanup: bool, - pub no_extensions: bool, - pub vm_interrupt: zend_atomic_bool, - pub timed_out: zend_atomic_bool, + pub full_tables_cleanup: zend_bool, + pub no_extensions: zend_bool, + pub vm_interrupt: zend_bool, + pub timed_out: zend_bool, pub hard_timeout: zend_long, pub regular_list: HashTable, pub persistent_list: HashTable, @@ -1159,7 +1281,7 @@ pub struct _zend_executor_globals { pub error_handling: zend_error_handling_t, pub exception_class: *mut zend_class_entry, pub timeout_seconds: zend_long, - pub capture_warnings_during_sccp: ::std::os::raw::c_int, + pub lambda_count: ::std::os::raw::c_int, pub ini_directives: *mut HashTable, pub modified_ini_directives: *mut HashTable, pub error_reporting_ini_entry: *mut zend_ini_entry, @@ -1169,7 +1291,7 @@ pub struct _zend_executor_globals { pub opline_before_exception: *const zend_op, pub exception_op: [zend_op; 3usize], pub current_module: *mut _zend_module_entry, - pub active: bool, + pub active: zend_bool, pub flags: zend_uchar, pub assertions: zend_long, pub ht_iterators_count: u32, @@ -1180,20 +1302,14 @@ pub struct _zend_executor_globals { pub trampoline: zend_function, pub call_trampoline_op: zend_op, pub weakrefs: HashTable, - pub exception_ignore_args: bool, + pub exception_ignore_args: zend_bool, pub exception_string_param_max_len: zend_long, pub get_gc_buffer: zend_get_gc_buffer, - pub main_fiber_context: *mut zend_fiber_context, - pub current_fiber_context: *mut zend_fiber_context, - pub active_fiber: *mut zend_fiber, - pub fiber_stack_size: zend_long, - pub record_errors: bool, - pub num_errors: u32, - pub errors: *mut *mut zend_error_info, - pub filename_override: *mut zend_string, - pub lineno_override: zend_long, pub reserved: [*mut ::std::os::raw::c_void; 6usize], } +extern "C" { + pub fn zend_is_auto_global(name: *mut zend_string) -> zend_bool; +} pub type zend_module_entry = _zend_module_entry; #[repr(C)] #[derive(Debug, Copy, Clone)] @@ -1277,6 +1393,15 @@ pub struct _zend_function_entry { pub flags: u32, } pub type zend_function_entry = _zend_function_entry; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _zend_fcall_info_cache { + pub function_handler: *mut zend_function, + pub calling_scope: *mut zend_class_entry, + pub called_scope: *mut zend_class_entry, + pub object: *mut zend_object, +} +pub type zend_fcall_info_cache = _zend_fcall_info_cache; extern "C" { pub fn zend_register_internal_class_ex( class_entry: *mut zend_class_entry, @@ -1288,7 +1413,7 @@ extern "C" { callable: *mut zval, check_flags: u32, callable_name: *mut *mut zend_string, - ) -> bool; + ) -> zend_bool; } extern "C" { pub fn zend_declare_property( @@ -1371,6 +1496,386 @@ extern "C" { extern "C" { pub fn php_printf(format: *const ::std::os::raw::c_char, ...) -> usize; } +pub type php_stream = _php_stream; +pub type php_stream_wrapper = _php_stream_wrapper; +pub type php_stream_context = _php_stream_context; +pub type php_stream_filter = _php_stream_filter; +pub type php_stream_notification_func = ::std::option::Option< + unsafe extern "C" fn( + context: *mut php_stream_context, + notifycode: ::std::os::raw::c_int, + severity: ::std::os::raw::c_int, + xmsg: *mut ::std::os::raw::c_char, + xcode: ::std::os::raw::c_int, + bytes_sofar: usize, + bytes_max: usize, + ptr: *mut ::std::os::raw::c_void, + ), +>; +pub type php_stream_notifier = _php_stream_notifier; +#[repr(C)] +pub struct _php_stream_notifier { + pub func: php_stream_notification_func, + pub dtor: ::std::option::Option, + pub ptr: zval, + pub mask: ::std::os::raw::c_int, + pub progress: usize, + pub progress_max: usize, +} +#[repr(C)] +pub struct _php_stream_context { + pub notifier: *mut php_stream_notifier, + pub options: zval, + pub res: *mut zend_resource, +} +pub type php_stream_bucket = _php_stream_bucket; +pub type php_stream_bucket_brigade = _php_stream_bucket_brigade; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _php_stream_bucket { + pub next: *mut php_stream_bucket, + pub prev: *mut php_stream_bucket, + pub brigade: *mut php_stream_bucket_brigade, + pub buf: *mut ::std::os::raw::c_char, + pub buflen: usize, + pub own_buf: u8, + pub is_persistent: u8, + pub refcount: ::std::os::raw::c_int, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _php_stream_bucket_brigade { + pub head: *mut php_stream_bucket, + pub tail: *mut php_stream_bucket, +} +pub const php_stream_filter_status_t_PSFS_ERR_FATAL: php_stream_filter_status_t = 0; +pub const php_stream_filter_status_t_PSFS_FEED_ME: php_stream_filter_status_t = 1; +pub const php_stream_filter_status_t_PSFS_PASS_ON: php_stream_filter_status_t = 2; +pub type php_stream_filter_status_t = ::std::os::raw::c_uint; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _php_stream_filter_ops { + pub filter: ::std::option::Option< + unsafe extern "C" fn( + stream: *mut php_stream, + thisfilter: *mut php_stream_filter, + buckets_in: *mut php_stream_bucket_brigade, + buckets_out: *mut php_stream_bucket_brigade, + bytes_consumed: *mut usize, + flags: ::std::os::raw::c_int, + ) -> php_stream_filter_status_t, + >, + pub dtor: ::std::option::Option, + pub label: *const ::std::os::raw::c_char, +} +pub type php_stream_filter_ops = _php_stream_filter_ops; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _php_stream_filter_chain { + pub head: *mut php_stream_filter, + pub tail: *mut php_stream_filter, + pub stream: *mut php_stream, +} +pub type php_stream_filter_chain = _php_stream_filter_chain; +#[repr(C)] +pub struct _php_stream_filter { + pub fops: *const php_stream_filter_ops, + pub abstract_: zval, + pub next: *mut php_stream_filter, + pub prev: *mut php_stream_filter, + pub is_persistent: ::std::os::raw::c_int, + pub chain: *mut php_stream_filter_chain, + pub buffer: php_stream_bucket_brigade, + pub res: *mut zend_resource, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _php_stream_statbuf { + pub sb: zend_stat_t, +} +pub type php_stream_statbuf = _php_stream_statbuf; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _php_stream_ops { + pub write: ::std::option::Option< + unsafe extern "C" fn( + stream: *mut php_stream, + buf: *const ::std::os::raw::c_char, + count: usize, + ) -> isize, + >, + pub read: ::std::option::Option< + unsafe extern "C" fn( + stream: *mut php_stream, + buf: *mut ::std::os::raw::c_char, + count: usize, + ) -> isize, + >, + pub close: ::std::option::Option< + unsafe extern "C" fn( + stream: *mut php_stream, + close_handle: ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int, + >, + pub flush: ::std::option::Option< + unsafe extern "C" fn(stream: *mut php_stream) -> ::std::os::raw::c_int, + >, + pub label: *const ::std::os::raw::c_char, + pub seek: ::std::option::Option< + unsafe extern "C" fn( + stream: *mut php_stream, + offset: zend_off_t, + whence: ::std::os::raw::c_int, + newoffset: *mut zend_off_t, + ) -> ::std::os::raw::c_int, + >, + pub cast: ::std::option::Option< + unsafe extern "C" fn( + stream: *mut php_stream, + castas: ::std::os::raw::c_int, + ret: *mut *mut ::std::os::raw::c_void, + ) -> ::std::os::raw::c_int, + >, + pub stat: ::std::option::Option< + unsafe extern "C" fn( + stream: *mut php_stream, + ssb: *mut php_stream_statbuf, + ) -> ::std::os::raw::c_int, + >, + pub set_option: ::std::option::Option< + unsafe extern "C" fn( + stream: *mut php_stream, + option: ::std::os::raw::c_int, + value: ::std::os::raw::c_int, + ptrparam: *mut ::std::os::raw::c_void, + ) -> ::std::os::raw::c_int, + >, +} +pub type php_stream_ops = _php_stream_ops; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _php_stream_wrapper_ops { + pub stream_opener: ::std::option::Option< + unsafe extern "C" fn( + wrapper: *mut php_stream_wrapper, + filename: *const ::std::os::raw::c_char, + mode: *const ::std::os::raw::c_char, + options: ::std::os::raw::c_int, + opened_path: *mut *mut zend_string, + context: *mut php_stream_context, + __php_stream_call_depth: ::std::os::raw::c_int, + __zend_filename: *const ::std::os::raw::c_char, + __zend_lineno: u32, + __zend_orig_filename: *const ::std::os::raw::c_char, + __zend_orig_lineno: u32, + ) -> *mut php_stream, + >, + pub stream_closer: ::std::option::Option< + unsafe extern "C" fn( + wrapper: *mut php_stream_wrapper, + stream: *mut php_stream, + ) -> ::std::os::raw::c_int, + >, + pub stream_stat: ::std::option::Option< + unsafe extern "C" fn( + wrapper: *mut php_stream_wrapper, + stream: *mut php_stream, + ssb: *mut php_stream_statbuf, + ) -> ::std::os::raw::c_int, + >, + pub url_stat: ::std::option::Option< + unsafe extern "C" fn( + wrapper: *mut php_stream_wrapper, + url: *const ::std::os::raw::c_char, + flags: ::std::os::raw::c_int, + ssb: *mut php_stream_statbuf, + context: *mut php_stream_context, + ) -> ::std::os::raw::c_int, + >, + pub dir_opener: ::std::option::Option< + unsafe extern "C" fn( + wrapper: *mut php_stream_wrapper, + filename: *const ::std::os::raw::c_char, + mode: *const ::std::os::raw::c_char, + options: ::std::os::raw::c_int, + opened_path: *mut *mut zend_string, + context: *mut php_stream_context, + __php_stream_call_depth: ::std::os::raw::c_int, + __zend_filename: *const ::std::os::raw::c_char, + __zend_lineno: u32, + __zend_orig_filename: *const ::std::os::raw::c_char, + __zend_orig_lineno: u32, + ) -> *mut php_stream, + >, + pub label: *const ::std::os::raw::c_char, + pub unlink: ::std::option::Option< + unsafe extern "C" fn( + wrapper: *mut php_stream_wrapper, + url: *const ::std::os::raw::c_char, + options: ::std::os::raw::c_int, + context: *mut php_stream_context, + ) -> ::std::os::raw::c_int, + >, + pub rename: ::std::option::Option< + unsafe extern "C" fn( + wrapper: *mut php_stream_wrapper, + url_from: *const ::std::os::raw::c_char, + url_to: *const ::std::os::raw::c_char, + options: ::std::os::raw::c_int, + context: *mut php_stream_context, + ) -> ::std::os::raw::c_int, + >, + pub stream_mkdir: ::std::option::Option< + unsafe extern "C" fn( + wrapper: *mut php_stream_wrapper, + url: *const ::std::os::raw::c_char, + mode: ::std::os::raw::c_int, + options: ::std::os::raw::c_int, + context: *mut php_stream_context, + ) -> ::std::os::raw::c_int, + >, + pub stream_rmdir: ::std::option::Option< + unsafe extern "C" fn( + wrapper: *mut php_stream_wrapper, + url: *const ::std::os::raw::c_char, + options: ::std::os::raw::c_int, + context: *mut php_stream_context, + ) -> ::std::os::raw::c_int, + >, + pub stream_metadata: ::std::option::Option< + unsafe extern "C" fn( + wrapper: *mut php_stream_wrapper, + url: *const ::std::os::raw::c_char, + options: ::std::os::raw::c_int, + value: *mut ::std::os::raw::c_void, + context: *mut php_stream_context, + ) -> ::std::os::raw::c_int, + >, +} +pub type php_stream_wrapper_ops = _php_stream_wrapper_ops; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _php_stream_wrapper { + pub wops: *const php_stream_wrapper_ops, + pub abstract_: *mut ::std::os::raw::c_void, + pub is_url: ::std::os::raw::c_int, +} +#[repr(C)] +pub struct _php_stream { + pub ops: *const php_stream_ops, + pub abstract_: *mut ::std::os::raw::c_void, + pub readfilters: php_stream_filter_chain, + pub writefilters: php_stream_filter_chain, + pub wrapper: *mut php_stream_wrapper, + pub wrapperthis: *mut ::std::os::raw::c_void, + pub wrapperdata: zval, + pub _bitfield_align_1: [u8; 0], + pub _bitfield_1: __BindgenBitfieldUnit<[u8; 1usize]>, + pub fgetss_state: u8, + pub mode: [::std::os::raw::c_char; 16usize], + pub flags: u32, + pub res: *mut zend_resource, + pub stdiocast: *mut FILE, + pub orig_path: *mut ::std::os::raw::c_char, + pub ctx: *mut zend_resource, + pub position: zend_off_t, + pub readbuf: *mut ::std::os::raw::c_uchar, + pub readbuflen: usize, + pub readpos: zend_off_t, + pub writepos: zend_off_t, + pub chunk_size: usize, + pub open_filename: *const ::std::os::raw::c_char, + pub open_lineno: u32, + pub enclosing_stream: *mut _php_stream, +} +impl _php_stream { + #[inline] + pub fn is_persistent(&self) -> u8 { + unsafe { ::std::mem::transmute(self._bitfield_1.get(0usize, 1u8) as u8) } + } + #[inline] + pub fn set_is_persistent(&mut self, val: u8) { + unsafe { + let val: u8 = ::std::mem::transmute(val); + self._bitfield_1.set(0usize, 1u8, val as u64) + } + } + #[inline] + pub fn in_free(&self) -> u8 { + unsafe { ::std::mem::transmute(self._bitfield_1.get(1usize, 2u8) as u8) } + } + #[inline] + pub fn set_in_free(&mut self, val: u8) { + unsafe { + let val: u8 = ::std::mem::transmute(val); + self._bitfield_1.set(1usize, 2u8, val as u64) + } + } + #[inline] + pub fn eof(&self) -> u8 { + unsafe { ::std::mem::transmute(self._bitfield_1.get(3usize, 1u8) as u8) } + } + #[inline] + pub fn set_eof(&mut self, val: u8) { + unsafe { + let val: u8 = ::std::mem::transmute(val); + self._bitfield_1.set(3usize, 1u8, val as u64) + } + } + #[inline] + pub fn __exposed(&self) -> u8 { + unsafe { ::std::mem::transmute(self._bitfield_1.get(4usize, 1u8) as u8) } + } + #[inline] + pub fn set___exposed(&mut self, val: u8) { + unsafe { + let val: u8 = ::std::mem::transmute(val); + self._bitfield_1.set(4usize, 1u8, val as u64) + } + } + #[inline] + pub fn fclose_stdiocast(&self) -> u8 { + unsafe { ::std::mem::transmute(self._bitfield_1.get(5usize, 2u8) as u8) } + } + #[inline] + pub fn set_fclose_stdiocast(&mut self, val: u8) { + unsafe { + let val: u8 = ::std::mem::transmute(val); + self._bitfield_1.set(5usize, 2u8, val as u64) + } + } + #[inline] + pub fn new_bitfield_1( + is_persistent: u8, + in_free: u8, + eof: u8, + __exposed: u8, + fclose_stdiocast: u8, + ) -> __BindgenBitfieldUnit<[u8; 1usize]> { + let mut __bindgen_bitfield_unit: __BindgenBitfieldUnit<[u8; 1usize]> = Default::default(); + __bindgen_bitfield_unit.set(0usize, 1u8, { + let is_persistent: u8 = unsafe { ::std::mem::transmute(is_persistent) }; + is_persistent as u64 + }); + __bindgen_bitfield_unit.set(1usize, 2u8, { + let in_free: u8 = unsafe { ::std::mem::transmute(in_free) }; + in_free as u64 + }); + __bindgen_bitfield_unit.set(3usize, 1u8, { + let eof: u8 = unsafe { ::std::mem::transmute(eof) }; + eof as u64 + }); + __bindgen_bitfield_unit.set(4usize, 1u8, { + let __exposed: u8 = unsafe { ::std::mem::transmute(__exposed) }; + __exposed as u64 + }); + __bindgen_bitfield_unit.set(5usize, 2u8, { + let fclose_stdiocast: u8 = unsafe { ::std::mem::transmute(fclose_stdiocast) }; + fclose_stdiocast as u64 + }); + __bindgen_bitfield_unit + } +} pub type php_core_globals = _php_core_globals; #[repr(C)] pub struct _php_core_globals { @@ -1491,7 +1996,7 @@ extern "C" { pub fn zend_register_bool_constant( name: *const ::std::os::raw::c_char, name_len: usize, - bval: bool, + bval: zend_bool, flags: ::std::os::raw::c_int, module_number: ::std::os::raw::c_int, ); @@ -1600,3 +2105,99 @@ extern "C" { extern "C" { pub static mut zend_ce_stringable: *mut zend_class_entry; } +extern "C" { + pub fn zend_class_serialize_deny( + object: *mut zval, + buffer: *mut *mut ::std::os::raw::c_uchar, + buf_len: *mut usize, + data: *mut zend_serialize_data, + ) -> ::std::os::raw::c_int; +} +extern "C" { + pub fn zend_class_unserialize_deny( + object: *mut zval, + ce: *mut zend_class_entry, + buf: *const ::std::os::raw::c_uchar, + buf_len: usize, + data: *mut zend_unserialize_data, + ) -> ::std::os::raw::c_int; +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct sapi_header_struct { + pub header: *mut ::std::os::raw::c_char, + pub header_len: usize, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct sapi_headers_struct { + pub headers: zend_llist, + pub http_response_code: ::std::os::raw::c_int, + pub send_default_content_type: ::std::os::raw::c_uchar, + pub mimetype: *mut ::std::os::raw::c_char, + pub http_status_line: *mut ::std::os::raw::c_char, +} +pub type sapi_post_entry = _sapi_post_entry; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct sapi_request_info { + pub request_method: *const ::std::os::raw::c_char, + pub query_string: *mut ::std::os::raw::c_char, + pub cookie_data: *mut ::std::os::raw::c_char, + pub content_length: zend_long, + pub path_translated: *mut ::std::os::raw::c_char, + pub request_uri: *mut ::std::os::raw::c_char, + pub request_body: *mut _php_stream, + pub content_type: *const ::std::os::raw::c_char, + pub headers_only: zend_bool, + pub no_headers: zend_bool, + pub headers_read: zend_bool, + pub post_entry: *mut sapi_post_entry, + pub content_type_dup: *mut ::std::os::raw::c_char, + pub auth_user: *mut ::std::os::raw::c_char, + pub auth_password: *mut ::std::os::raw::c_char, + pub auth_digest: *mut ::std::os::raw::c_char, + pub argv0: *mut ::std::os::raw::c_char, + pub current_user: *mut ::std::os::raw::c_char, + pub current_user_length: ::std::os::raw::c_int, + pub argc: ::std::os::raw::c_int, + pub argv: *mut *mut ::std::os::raw::c_char, + pub proto_num: ::std::os::raw::c_int, +} +#[repr(C)] +pub struct _sapi_globals_struct { + pub server_context: *mut ::std::os::raw::c_void, + pub request_info: sapi_request_info, + pub sapi_headers: sapi_headers_struct, + pub read_post_bytes: i64, + pub post_read: ::std::os::raw::c_uchar, + pub headers_sent: ::std::os::raw::c_uchar, + pub global_stat: zend_stat_t, + pub default_mimetype: *mut ::std::os::raw::c_char, + pub default_charset: *mut ::std::os::raw::c_char, + pub rfc1867_uploaded_files: *mut HashTable, + pub post_max_size: zend_long, + pub options: ::std::os::raw::c_int, + pub sapi_started: zend_bool, + pub global_request_time: f64, + pub known_post_content_types: HashTable, + pub callback_func: zval, + pub fci_cache: zend_fcall_info_cache, +} +pub type sapi_globals_struct = _sapi_globals_struct; +extern "C" { + pub static mut sapi_globals: sapi_globals_struct; +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct _sapi_post_entry { + pub content_type: *mut ::std::os::raw::c_char, + pub content_type_len: u32, + pub post_reader: ::std::option::Option, + pub post_handler: ::std::option::Option< + unsafe extern "C" fn( + content_type_dup: *mut ::std::os::raw::c_char, + arg: *mut ::std::os::raw::c_void, + ), + >, +} diff --git a/src/ffi.rs b/src/ffi.rs index a23fcb171..cd3a81c9c 100644 --- a/src/ffi.rs +++ b/src/ffi.rs @@ -27,6 +27,7 @@ extern "C" { pub fn ext_php_rs_zend_object_release(obj: *mut zend_object); pub fn ext_php_rs_executor_globals() -> *mut zend_executor_globals; pub fn ext_php_rs_process_globals() -> *mut php_core_globals; + pub fn ext_php_rs_sapi_globals() -> *mut sapi_globals_struct; } include!(concat!(env!("OUT_DIR"), "/bindings.rs")); diff --git a/src/wrapper.c b/src/wrapper.c index 7a5eba556..514882b6f 100644 --- a/src/wrapper.c +++ b/src/wrapper.c @@ -51,3 +51,16 @@ php_core_globals *ext_php_rs_process_globals() { return &core_globals; #endif } + + +sapi_globals_struct *ext_php_rs_sapi_globals() { +#ifdef ZTS +#ifdef ZEND_ENABLE_STATIC_TSRMLS_CACHE + return TSRMG_FAST_BULK_STATIC(sapi_globals_offset, sapi_globals_struct); +#else + return TSRMG_FAST_BULK(sapi_globals_offset, sapi_globals_struct *); +#endif +#else + return &sapi_globals; +#endif +} diff --git a/src/wrapper.h b/src/wrapper.h index c00ab5b9b..cd8542cdc 100644 --- a/src/wrapper.h +++ b/src/wrapper.h @@ -20,6 +20,8 @@ #include "zend_exceptions.h" #include "zend_inheritance.h" #include "zend_interfaces.h" +#include "SAPI.h" +#include "php_variables.h" zend_string *ext_php_rs_zend_string_init(const char *str, size_t len, bool persistent); void ext_php_rs_zend_string_release(zend_string *zs); @@ -31,3 +33,4 @@ void *ext_php_rs_zend_object_alloc(size_t obj_size, zend_class_entry *ce); void ext_php_rs_zend_object_release(zend_object *obj); zend_executor_globals *ext_php_rs_executor_globals(); php_core_globals *ext_php_rs_process_globals(); +sapi_globals_struct *ext_php_rs_sapi_globals(); diff --git a/src/zend/globals.rs b/src/zend/globals.rs index 7ed5eef41..f7a1e1b68 100644 --- a/src/zend/globals.rs +++ b/src/zend/globals.rs @@ -1,17 +1,22 @@ -//! Types related to the PHP executor globals. - +//! Types related to the PHP executor, sapi and process globals. +use std::ffi::CStr; use std::ops::{Deref, DerefMut}; +use std::slice; +use std::str; use parking_lot::{const_rwlock, RwLock, RwLockReadGuard, RwLockWriteGuard}; use crate::boxed::ZBox; use crate::ffi::{ _zend_executor_globals, ext_php_rs_executor_globals, ext_php_rs_process_globals, - php_core_globals, TRACK_VARS_COOKIE, TRACK_VARS_ENV, TRACK_VARS_FILES, TRACK_VARS_GET, - TRACK_VARS_POST, TRACK_VARS_REQUEST, TRACK_VARS_SERVER, + ext_php_rs_sapi_globals, php_core_globals, sapi_globals_struct, sapi_header_struct, + sapi_headers_struct, sapi_request_info, zend_is_auto_global, TRACK_VARS_COOKIE, TRACK_VARS_ENV, + TRACK_VARS_FILES, TRACK_VARS_GET, TRACK_VARS_POST, TRACK_VARS_REQUEST, TRACK_VARS_SERVER, }; -use crate::types::{ZendHashTable, ZendObject}; +use crate::types::{ZendHashTable, ZendObject, ZendStr}; + +use super::linked_list::ZendLinkedListIterator; /// Stores global variables used in the PHP executor. pub type ExecutorGlobals = _zend_executor_globals; @@ -107,6 +112,12 @@ impl ProcessGlobals { /// Get the HTTP Server variables. Equivalent of $_SERVER. pub fn http_server_vars(&self) -> Option<&ZendHashTable> { + // $_SERVER is lazy-initted, we need to call zend_is_auto_global + // if it's not already populated. + if !self.http_globals[TRACK_VARS_SERVER as usize].is_array() { + let name = ZendStr::new("_SERVER", false).as_mut_ptr(); + unsafe { zend_is_auto_global(name) }; + } if self.http_globals[TRACK_VARS_SERVER as usize].is_array() { self.http_globals[TRACK_VARS_SERVER as usize].array() } else { @@ -157,12 +168,203 @@ impl ProcessGlobals { } } +/// Stores global variables used in the SAPI. +pub type SapiGlobals = sapi_globals_struct; + +impl SapiGlobals { + /// Returns a reference to the PHP process globals. + /// + /// The process globals are guarded by a RwLock. There can be multiple + /// immutable references at one time but only ever one mutable reference. + /// Attempting to retrieve the globals while already holding the global + /// guard will lead to a deadlock. Dropping the globals guard will release + /// the lock. + pub fn get() -> GlobalReadGuard { + // SAFETY: PHP executor globals are statically declared therefore should never + // return an invalid pointer. + let globals = unsafe { &*ext_php_rs_sapi_globals() }; + let guard = SAPI_GLOBALS_LOCK.read(); + GlobalReadGuard { globals, guard } + } + + /// Returns a mutable reference to the PHP executor globals. + /// + /// The executor globals are guarded by a RwLock. There can be multiple + /// immutable references at one time but only ever one mutable reference. + /// Attempting to retrieve the globals while already holding the global + /// guard will lead to a deadlock. Dropping the globals guard will release + /// the lock. + pub fn get_mut() -> GlobalWriteGuard { + // SAFETY: PHP executor globals are statically declared therefore should never + // return an invalid pointer. + let globals = unsafe { &mut *ext_php_rs_sapi_globals() }; + let guard = SAPI_GLOBALS_LOCK.write(); + GlobalWriteGuard { globals, guard } + } + // Get the request info for the Sapi. + pub fn request_info(&self) -> &SapiRequestInfo { + &self.request_info + } + + pub fn sapi_headers(&self) -> &SapiHeaders { + &self.sapi_headers + } +} + +pub type SapiHeaders = sapi_headers_struct; + +impl<'a> SapiHeaders { + pub fn headers(&'a mut self) -> ZendLinkedListIterator<'a, SapiHeader> { + self.headers.iter() + } +} + +pub type SapiHeader = sapi_header_struct; + +impl<'a> SapiHeader { + pub fn as_str(&'a self) -> &'a str { + unsafe { + let slice = slice::from_raw_parts(self.header as *const u8, self.header_len); + str::from_utf8(slice).expect("Invalid header string") + } + } + + pub fn name(&'a self) -> &'a str { + self.as_str().split(':').next().unwrap_or("").trim() + } + + pub fn value(&'a self) -> Option<&'a str> { + self.as_str().split(':').nth(1).map(|s| s.trim()) + } +} + +pub type SapiRequestInfo = sapi_request_info; + +impl SapiRequestInfo { + pub fn request_method(&self) -> Option<&str> { + if self.request_method.is_null() { + return None; + } + unsafe { CStr::from_ptr(self.request_method).to_str().ok() } + } + + pub fn query_string(&self) -> Option<&str> { + if self.query_string.is_null() { + return None; + } + unsafe { CStr::from_ptr(self.query_string).to_str().ok() } + } + + pub fn cookie_data(&self) -> Option<&str> { + if self.cookie_data.is_null() { + return None; + } + unsafe { CStr::from_ptr(self.cookie_data).to_str().ok() } + } + + pub fn content_length(&self) -> i64 { + self.content_length + } + + pub fn path_translated(&self) -> Option<&str> { + if self.path_translated.is_null() { + return None; + } + unsafe { CStr::from_ptr(self.path_translated).to_str().ok() } + } + + pub fn request_uri(&self) -> Option<&str> { + if self.request_uri.is_null() { + return None; + } + unsafe { CStr::from_ptr(self.request_uri).to_str().ok() } + } + + // Todo: request_body _php_stream + + pub fn content_type(&self) -> Option<&str> { + if self.content_type.is_null() { + return None; + } + unsafe { CStr::from_ptr(self.content_type).to_str().ok() } + } + + pub fn headers_only(&self) -> bool { + self.headers_only + } + + pub fn no_headers(&self) -> bool { + self.no_headers + } + + pub fn headers_read(&self) -> bool { + self.headers_read + } + + // Todo: post_entry sapi_post_entry + + pub fn auth_user(&self) -> Option<&str> { + if self.auth_user.is_null() { + return None; + } + unsafe { CStr::from_ptr(self.auth_user).to_str().ok() } + } + + pub fn auth_password(&self) -> Option<&str> { + if self.auth_password.is_null() { + return None; + } + unsafe { CStr::from_ptr(self.auth_password).to_str().ok() } + } + + pub fn auth_digest(&self) -> Option<&str> { + if self.auth_digest.is_null() { + return None; + } + unsafe { CStr::from_ptr(self.auth_digest).to_str().ok() } + } + + pub fn argv0(&self) -> Option<&str> { + if self.argv0.is_null() { + return None; + } + unsafe { CStr::from_ptr(self.argv0).to_str().ok() } + } + + pub fn current_user(&self) -> Option<&str> { + if self.current_user.is_null() { + return None; + } + unsafe { CStr::from_ptr(self.current_user).to_str().ok() } + } + + pub fn current_user_length(&self) -> i32 { + self.current_user_length + } + + pub fn argvc(&self) -> i32 { + self.argc + } + + pub fn argv(&self) -> Option<&str> { + if self.argv.is_null() { + return None; + } + unsafe { CStr::from_ptr(*self.argv).to_str().ok() } + } + + pub fn proto_num(&self) -> i32 { + self.proto_num + } +} + /// Executor globals rwlock. /// /// PHP provides no indication if the executor globals are being accessed so /// this is only effective on the Rust side. static GLOBALS_LOCK: RwLock<()> = const_rwlock(()); static PROCESS_GLOBALS_LOCK: RwLock<()> = const_rwlock(()); +static SAPI_GLOBALS_LOCK: RwLock<()> = const_rwlock(()); /// Wrapper guard that contains a reference to a given type `T`. Dropping a /// guard releases the lock on the relevant rwlock. diff --git a/src/zend/linked_list.rs b/src/zend/linked_list.rs new file mode 100644 index 000000000..481b22979 --- /dev/null +++ b/src/zend/linked_list.rs @@ -0,0 +1,46 @@ +use std::marker::PhantomData; + +use crate::ffi::{zend_llist, zend_llist_element, zend_llist_get_next_ex}; + +pub type ZendLinkedList = zend_llist; + +impl ZendLinkedList { + pub fn iter(&self) -> ZendLinkedListIterator { + ZendLinkedListIterator::new(self) + } +} + +pub struct ZendLinkedListIterator<'a, T> { + list: &'a zend_llist, + position: *mut zend_llist_element, + _marker: PhantomData, +} + +impl<'a, T> ZendLinkedListIterator<'a, T> { + fn new(list: &'a ZendLinkedList) -> Self { + ZendLinkedListIterator { + list, + position: list.head, + _marker: PhantomData, + } + } +} + +impl<'a, T: 'a> Iterator for ZendLinkedListIterator<'a, T> { + type Item = &'a T; + + fn next(&mut self) -> Option { + if self.position.is_null() { + return None; + } + let ptr = unsafe { (*self.position).data.as_mut_ptr() }; + let value = unsafe { &*(ptr as *const T as *mut T) }; + unsafe { + zend_llist_get_next_ex( + self.list as *const ZendLinkedList as *mut ZendLinkedList, + &mut self.position, + ) + }; + Some(value) + } +} diff --git a/src/zend/mod.rs b/src/zend/mod.rs index 2aabd81e4..dfaa0ef9e 100644 --- a/src/zend/mod.rs +++ b/src/zend/mod.rs @@ -7,6 +7,7 @@ mod ex; mod function; mod globals; mod handlers; +mod linked_list; mod module; use crate::{error::Result, ffi::php_printf}; @@ -18,7 +19,9 @@ pub use ex::ExecuteData; pub use function::FunctionEntry; pub use globals::ExecutorGlobals; pub use globals::ProcessGlobals; +pub use globals::SapiGlobals; pub use handlers::ZendObjectHandlers; +pub use linked_list::ZendLinkedList; pub use module::ModuleEntry; // Used as the format string for `php_printf`.