From 8d3c44cf00caa13ca042faac5cc312e461bafe1c Mon Sep 17 00:00:00 2001 From: PThorpe92 Date: Thu, 6 Mar 2025 15:24:07 -0500 Subject: [PATCH] Impl IO trait for VfsMod type --- core/io/mod.rs | 10 ++ core/io/vfs.rs | 153 +++++++++++++++++++++++++++++ extensions/core/src/vfs_modules.rs | 2 + 3 files changed, 165 insertions(+) create mode 100644 core/io/vfs.rs diff --git a/core/io/mod.rs b/core/io/mod.rs index 519109565..9e544a0d3 100644 --- a/core/io/mod.rs +++ b/core/io/mod.rs @@ -24,6 +24,15 @@ pub enum OpenFlags { Create, } +impl OpenFlags { + pub fn to_flags(&self) -> i32 { + match self { + Self::None => 0, + Self::Create => 1, + } + } +} + pub trait IO: Send + Sync { fn open_file(&self, path: &str, flags: OpenFlags, direct: bool) -> Result>; @@ -203,5 +212,6 @@ cfg_block! { } mod memory; +mod vfs; pub use memory::MemoryIO; mod common; diff --git a/core/io/vfs.rs b/core/io/vfs.rs new file mode 100644 index 000000000..8ddbbc732 --- /dev/null +++ b/core/io/vfs.rs @@ -0,0 +1,153 @@ +use crate::ext::VfsMod; +use crate::{LimboError, Result}; +use limbo_ext::{VfsFileImpl, VfsImpl}; +use std::cell::RefCell; +use std::ffi::{c_void, CString}; +use std::sync::Arc; + +use super::{Buffer, Completion, File, OpenFlags, IO}; + +impl IO for VfsMod { + fn open_file(&self, path: &str, flags: OpenFlags, direct: bool) -> Result> { + let c_path = CString::new(path).map_err(|_| { + LimboError::ExtensionError("Failed to convert path to CString".to_string()) + })?; + let ctx = self.ctx as *mut c_void; + let vfs = unsafe { &*self.ctx }; + let file = unsafe { (vfs.open)(ctx, c_path.as_ptr(), flags.to_flags(), direct) }; + if file.is_null() { + return Err(LimboError::ExtensionError("File not found".to_string())); + } + Ok(Arc::new(limbo_ext::VfsFileImpl::new(file, self.ctx)?)) + } + + fn run_once(&self) -> Result<()> { + if self.ctx.is_null() { + return Err(LimboError::ExtensionError("VFS is null".to_string())); + } + let vfs = unsafe { &*self.ctx }; + let result = unsafe { (vfs.run_once)(vfs.vfs) }; + if !result.is_ok() { + return Err(LimboError::ExtensionError(result.to_string())); + } + Ok(()) + } + + fn generate_random_number(&self) -> i64 { + if self.ctx.is_null() { + return -1; + } + let vfs = unsafe { &*self.ctx }; + unsafe { (vfs.gen_random_number)() } + } + + fn get_current_time(&self) -> String { + if self.ctx.is_null() { + return "".to_string(); + } + unsafe { + let vfs = &*self.ctx; + let chars = (vfs.current_time)(); + let cstr = CString::from_raw(chars as *mut i8); + cstr.to_string_lossy().into_owned() + } + } +} + +impl File for VfsFileImpl { + fn lock_file(&self, exclusive: bool) -> Result<()> { + let vfs = unsafe { &*self.vfs }; + let result = unsafe { (vfs.lock)(self.file, exclusive) }; + if result.is_ok() { + return Err(LimboError::ExtensionError(result.to_string())); + } + Ok(()) + } + + fn unlock_file(&self) -> Result<()> { + if self.vfs.is_null() { + return Err(LimboError::ExtensionError("VFS is null".to_string())); + } + let vfs = unsafe { &*self.vfs }; + let result = unsafe { (vfs.unlock)(self.file) }; + if result.is_ok() { + return Err(LimboError::ExtensionError(result.to_string())); + } + Ok(()) + } + + fn pread(&self, pos: usize, c: Completion) -> Result<()> { + let r = match &c { + Completion::Read(ref r) => r, + _ => unreachable!(), + }; + let result = { + let mut buf = r.buf_mut(); + let count = buf.len(); + let vfs = unsafe { &*self.vfs }; + unsafe { (vfs.read)(self.file, buf.as_mut_ptr(), count, pos as i64) } + }; + if result < 0 { + Err(LimboError::ExtensionError("pread failed".to_string())) + } else { + c.complete(0); + Ok(()) + } + } + + fn pwrite(&self, pos: usize, buffer: Arc>, c: Completion) -> Result<()> { + let buf = buffer.borrow(); + let count = buf.as_slice().len(); + if self.vfs.is_null() { + return Err(LimboError::ExtensionError("VFS is null".to_string())); + } + let vfs = unsafe { &*self.vfs }; + let result = unsafe { + (vfs.write)( + self.file, + buf.as_slice().as_ptr() as *mut u8, + count, + pos as i64, + ) + }; + + if result < 0 { + Err(LimboError::ExtensionError("pwrite failed".to_string())) + } else { + c.complete(result); + Ok(()) + } + } + + fn sync(&self, c: Completion) -> Result<()> { + let vfs = unsafe { &*self.vfs }; + let result = unsafe { (vfs.sync)(self.file) }; + if result < 0 { + Err(LimboError::ExtensionError("sync failed".to_string())) + } else { + c.complete(0); + Ok(()) + } + } + + fn size(&self) -> Result { + let vfs = unsafe { &*self.vfs }; + let result = unsafe { (vfs.size)(self.file) }; + if result < 0 { + Err(LimboError::ExtensionError("size failed".to_string())) + } else { + Ok(result as u64) + } + } +} + +impl Drop for VfsMod { + fn drop(&mut self) { + if self.ctx.is_null() { + return; + } + unsafe { + let _ = Box::from_raw(self.ctx as *mut VfsImpl); + } + } +} diff --git a/extensions/core/src/vfs_modules.rs b/extensions/core/src/vfs_modules.rs index a95896218..6421596d4 100644 --- a/extensions/core/src/vfs_modules.rs +++ b/extensions/core/src/vfs_modules.rs @@ -90,6 +90,8 @@ pub struct VfsFileImpl { pub file: *const c_void, pub vfs: *const VfsImpl, } +unsafe impl Send for VfsFileImpl {} +unsafe impl Sync for VfsFileImpl {} impl VfsFileImpl { pub fn new(file: *const c_void, vfs: *const VfsImpl) -> ExtResult {