diff --git a/src/flags.rs b/src/flags.rs index b5254ae..3699b74 100644 --- a/src/flags.rs +++ b/src/flags.rs @@ -178,3 +178,29 @@ impl From for LockLevel { } } } + +#[derive(Copy, Clone, Debug)] +pub enum ShmLockMode { + LockShared, + LockExclusive, + UnlockShared, + UnlockExclusive, +} + +impl TryFrom for ShmLockMode { + type Error = i32; + + fn try_from(flags: i32) -> Result { + const LOCK_SHARED: i32 = vars::SQLITE_SHM_LOCK | vars::SQLITE_SHM_SHARED; + const LOCK_EXCLUSIVE: i32 = vars::SQLITE_SHM_LOCK | vars::SQLITE_SHM_EXCLUSIVE; + const UNLOCK_SHARED: i32 = vars::SQLITE_SHM_UNLOCK | vars::SQLITE_SHM_SHARED; + const UNLOCK_EXCLUSIVE: i32 = vars::SQLITE_SHM_UNLOCK | vars::SQLITE_SHM_EXCLUSIVE; + Ok(match flags { + LOCK_SHARED => Self::LockShared, + LOCK_EXCLUSIVE => Self::LockExclusive, + UNLOCK_SHARED => Self::UnlockShared, + UNLOCK_EXCLUSIVE => Self::UnlockExclusive, + _ => return Err(vars::SQLITE_IOERR), + }) + } +} diff --git a/src/vfs.rs b/src/vfs.rs index 62e48ba..4b94ab9 100644 --- a/src/vfs.rs +++ b/src/vfs.rs @@ -1,4 +1,4 @@ -use crate::flags::{AccessFlags, LockLevel, OpenOpts}; +use crate::flags::{AccessFlags, LockLevel, OpenOpts, ShmLockMode}; use crate::logger::SqliteLogger; use crate::vars::SQLITE_ERROR; use crate::{ffi, vars}; @@ -11,7 +11,7 @@ use core::mem::{ManuallyDrop, size_of}; use core::slice; use core::{ ffi::{CStr, c_char, c_int, c_void}, - ptr::null_mut, + ptr::{NonNull, null_mut}, }; /// The minimim supported `SQLite` version. @@ -186,6 +186,32 @@ pub trait Vfs: Send + Sync { fn device_characteristics(&self, handle: &mut Self::Handle) -> VfsResult { Ok(DEFAULT_DEVICE_CHARACTERISTICS) } + + fn shm_map( + &self, + handle: &mut Self::Handle, + region_idx: usize, + region_size: usize, + extend: bool, + ) -> VfsResult>> { + Err(vars::SQLITE_READONLY_CANTINIT) + } + + fn shm_lock( + &self, + handle: &mut Self::Handle, + offset: u32, + count: u32, + mode: ShmLockMode, + ) -> VfsResult<()> { + Err(vars::SQLITE_IOERR) + } + + fn shm_barrier(&self, handle: &mut Self::Handle) {} + + fn shm_unmap(&self, handle: &mut Self::Handle, delete: bool) -> VfsResult<()> { + Err(vars::SQLITE_IOERR) + } } #[derive(Clone)] @@ -300,10 +326,10 @@ fn register_inner( xFileControl: Some(x_file_control::), xSectorSize: Some(x_sector_size::), xDeviceCharacteristics: Some(x_device_characteristics::), - xShmMap: None, - xShmLock: None, - xShmBarrier: None, - xShmUnmap: None, + xShmMap: Some(x_shm_map::), + xShmLock: Some(x_shm_lock::), + xShmBarrier: Some(x_shm_barrier::), + xShmUnmap: Some(x_shm_unmap::), xFetch: None, xUnfetch: None, }; @@ -657,6 +683,69 @@ unsafe extern "C" fn x_device_characteristics(p_file: *mut ffi::sqlite3_ }) } +unsafe extern "C" fn x_shm_map( + p_file: *mut ffi::sqlite3_file, + pg: c_int, + pgsz: c_int, + extend: c_int, + p_page: *mut *mut c_void, +) -> c_int { + fallible(|| { + let file = unwrap_file!(p_file, T)?; + let vfs = unwrap_vfs!(file.vfs, T)?; + if let Some(region) = vfs.shm_map( + &mut file.handle, + pg.try_into().map_err(|_| vars::SQLITE_IOERR)?, + pgsz.try_into().map_err(|_| vars::SQLITE_IOERR)?, + extend != 0, + )? { + unsafe { *p_page = region.as_ptr() as *mut c_void } + } else { + unsafe { *p_page = null_mut() } + } + Ok(vars::SQLITE_OK) + }) +} + +unsafe extern "C" fn x_shm_lock( + p_file: *mut ffi::sqlite3_file, + offset: c_int, + n: c_int, + flags: c_int, +) -> c_int { + fallible(|| { + let file = unwrap_file!(p_file, T)?; + let vfs = unwrap_vfs!(file.vfs, T)?; + vfs.shm_lock( + &mut file.handle, + offset.try_into().map_err(|_| vars::SQLITE_IOERR)?, + n.try_into().map_err(|_| vars::SQLITE_IOERR)?, + ShmLockMode::try_from(flags)?, + )?; + Ok(vars::SQLITE_OK) + }) +} + +unsafe extern "C" fn x_shm_barrier(p_file: *mut ffi::sqlite3_file) { + if let Ok(file) = unwrap_file!(p_file, T) { + if let Ok(vfs) = unwrap_vfs!(file.vfs, T) { + vfs.shm_barrier(&mut file.handle) + } + } +} + +unsafe extern "C" fn x_shm_unmap( + p_file: *mut ffi::sqlite3_file, + delete_flag: c_int, +) -> c_int { + fallible(|| { + let file = unwrap_file!(p_file, T)?; + let vfs = unwrap_vfs!(file.vfs, T)?; + vfs.shm_unmap(&mut file.handle, delete_flag != 0)?; + Ok(vars::SQLITE_OK) + }) +} + // the following functions are wrappers around the base vfs functions unsafe extern "C" fn x_dlopen(