From c771487933badee05c7c62cceac213261e40f85e Mon Sep 17 00:00:00 2001 From: Nikita Sivukhin Date: Thu, 21 Aug 2025 14:38:17 +0400 Subject: [PATCH] add remove_file method to the IO --- core/io/generic.rs | 6 ++++++ core/io/io_uring.rs | 5 +++++ core/io/memory.rs | 5 +++++ core/io/mod.rs | 3 +++ core/io/unix.rs | 5 +++++ core/io/vfs.rs | 13 +++++++++++++ extensions/core/src/vfs_modules.rs | 4 ++++ extensions/tests/src/lib.rs | 6 ++++++ macros/src/ext/vfs_derive.rs | 19 +++++++++++++++++++ simulator/runner/io.rs | 5 +++++ 10 files changed, 71 insertions(+) diff --git a/core/io/generic.rs b/core/io/generic.rs index df4199139..9a87c6c63 100644 --- a/core/io/generic.rs +++ b/core/io/generic.rs @@ -34,6 +34,12 @@ impl IO for GenericIO { memory_io: Arc::new(MemoryIO::new()), })) } + + fn remove_file(&self, path: &str) -> Result<()> { + trace!("remove_file(path = {})", path); + std::fs::remove_file(path)?; + Ok(()) + } fn run_once(&self) -> Result<()> { Ok(()) diff --git a/core/io/io_uring.rs b/core/io/io_uring.rs index 40104db44..0c727560d 100644 --- a/core/io/io_uring.rs +++ b/core/io/io_uring.rs @@ -502,6 +502,11 @@ impl IO for UringIO { Ok(uring_file) } + fn remove_file(&self, path: &str) -> Result<()> { + std::fs::remove_file(path)?; + Ok(()) + } + fn run_once(&self) -> Result<()> { trace!("run_once()"); let mut inner = self.inner.borrow_mut(); diff --git a/core/io/memory.rs b/core/io/memory.rs index 933209e25..cea17b199 100644 --- a/core/io/memory.rs +++ b/core/io/memory.rs @@ -64,6 +64,11 @@ impl IO for MemoryIO { } Ok(files.get(path).unwrap().clone()) } + fn remove_file(&self, path: &str) -> Result<()> { + let mut files = self.files.lock().unwrap(); + files.remove(path); + Ok(()) + } fn run_once(&self) -> Result<()> { // nop diff --git a/core/io/mod.rs b/core/io/mod.rs index beb674d67..f376b5a3c 100644 --- a/core/io/mod.rs +++ b/core/io/mod.rs @@ -84,6 +84,9 @@ impl Default for OpenFlags { pub trait IO: Clock + Send + Sync { fn open_file(&self, path: &str, flags: OpenFlags, direct: bool) -> Result>; + // remove_file is used in the sync-engine + fn remove_file(&self, path: &str) -> Result<()>; + fn run_once(&self) -> Result<()>; fn wait_for_completion(&self, c: Completion) -> Result<()> { diff --git a/core/io/unix.rs b/core/io/unix.rs index 0fe95aa4b..94b82fb44 100644 --- a/core/io/unix.rs +++ b/core/io/unix.rs @@ -116,6 +116,11 @@ impl IO for UnixIO { Ok(unix_file) } + fn remove_file(&self, path: &str) -> Result<()> { + std::fs::remove_file(path)?; + Ok(()) + } + #[instrument(err, skip_all, level = Level::TRACE)] fn run_once(&self) -> Result<()> { Ok(()) diff --git a/core/io/vfs.rs b/core/io/vfs.rs index 89c8040cb..1b9535e9e 100644 --- a/core/io/vfs.rs +++ b/core/io/vfs.rs @@ -32,6 +32,19 @@ impl IO for VfsMod { Ok(Arc::new(turso_ext::VfsFileImpl::new(file, self.ctx)?)) } + fn remove_file(&self, path: &str) -> 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 result = unsafe { (vfs.remove)(ctx, c_path.as_ptr()) }; + if !result.is_ok() { + return Err(LimboError::ExtensionError(result.to_string())); + } + Ok(()) + } + fn run_once(&self) -> Result<()> { if self.ctx.is_null() { return Err(LimboError::ExtensionError("VFS is null".to_string())); diff --git a/extensions/core/src/vfs_modules.rs b/extensions/core/src/vfs_modules.rs index 8e7915e01..9dee25158 100644 --- a/extensions/core/src/vfs_modules.rs +++ b/extensions/core/src/vfs_modules.rs @@ -19,6 +19,7 @@ pub trait VfsExtension: Default + Send + Sync { const NAME: &'static str; type File: VfsFile; fn open_file(&self, path: &str, flags: i32, direct: bool) -> ExtResult; + fn remove_file(&self, path: &str) -> ExtResult<()>; fn run_once(&self) -> ExtResult<()> { Ok(()) } @@ -54,6 +55,7 @@ pub struct VfsImpl { pub name: *const c_char, pub vfs: *const c_void, pub open: VfsOpen, + pub remove: VfsRemove, pub close: VfsClose, pub read: VfsRead, pub write: VfsWrite, @@ -197,6 +199,8 @@ pub type VfsGetCurrentTime = unsafe extern "C" fn() -> *const c_char; pub type VfsGenerateRandomNumber = unsafe extern "C" fn() -> i64; +pub type VfsRemove = unsafe extern "C" fn(ctx: *const c_void, path: *const c_char) -> ResultCode; + #[repr(C)] pub struct VfsFileImpl { pub file: *const c_void, diff --git a/extensions/tests/src/lib.rs b/extensions/tests/src/lib.rs index 1a5685e30..639465088 100644 --- a/extensions/tests/src/lib.rs +++ b/extensions/tests/src/lib.rs @@ -337,6 +337,12 @@ impl VfsExtension for TestFS { io: self.callbacks.clone(), }) } + + fn remove_file(&self, path: &str) -> ExtResult<()> { + let _ = env_logger::try_init(); + log::debug!("remove file with testing VFS: {path}"); + std::fs::remove_file(path).map_err(|_| ResultCode::Error) + } } #[cfg(not(target_family = "wasm"))] diff --git a/macros/src/ext/vfs_derive.rs b/macros/src/ext/vfs_derive.rs index 2f3befa90..7e781d2af 100644 --- a/macros/src/ext/vfs_derive.rs +++ b/macros/src/ext/vfs_derive.rs @@ -8,6 +8,7 @@ pub fn derive_vfs_module(input: TokenStream) -> TokenStream { let register_fn_name = format_ident!("register_{}", struct_name); let register_static = format_ident!("register_static_{}", struct_name); let open_fn_name = format_ident!("{}_open", struct_name); + let remove_fn_name = format_ident!("{}_remove", struct_name); let close_fn_name = format_ident!("{}_close", struct_name); let read_fn_name = format_ident!("{}_read", struct_name); let write_fn_name = format_ident!("{}_write", struct_name); @@ -30,6 +31,7 @@ pub fn derive_vfs_module(input: TokenStream) -> TokenStream { vfs: ctx, name, open: #open_fn_name, + remove: #remove_fn_name, close: #close_fn_name, read: #read_fn_name, write: #write_fn_name, @@ -54,6 +56,7 @@ pub fn derive_vfs_module(input: TokenStream) -> TokenStream { vfs: ctx, name, open: #open_fn_name, + remove: #remove_fn_name, close: #close_fn_name, read: #read_fn_name, write: #write_fn_name, @@ -99,6 +102,22 @@ pub fn derive_vfs_module(input: TokenStream) -> TokenStream { ::std::boxed::Box::into_raw(::std::boxed::Box::new(vfs_file)) as *const ::std::ffi::c_void } + #[no_mangle] + pub unsafe extern "C" fn #remove_fn_name( + ctx: *const ::std::ffi::c_void, + path: *const ::std::ffi::c_char, + ) -> ::turso_ext::ResultCode { + let ctx = &*(ctx as *const ::turso_ext::VfsImpl); + let Ok(path_str) = ::std::ffi::CStr::from_ptr(path).to_str() else { + return ::turso_ext::ResultCode::Error; + }; + let vfs = &*(ctx.vfs as *const #struct_name); + if let Err(e) = <#struct_name as ::turso_ext::VfsExtension>::remove_file(vfs, path_str) { + return e; + }; + ::turso_ext::ResultCode::OK + } + #[no_mangle] pub unsafe extern "C" fn #close_fn_name(file_ptr: *const ::std::ffi::c_void) -> ::turso_ext::ResultCode { if file_ptr.is_null() { diff --git a/simulator/runner/io.rs b/simulator/runner/io.rs index ae50106b7..ea8c606f4 100644 --- a/simulator/runner/io.rs +++ b/simulator/runner/io.rs @@ -109,6 +109,11 @@ impl IO for SimulatorIO { Ok(file) } + fn remove_file(&self, path: &str) -> Result<()> { + self.files.borrow_mut().retain(|x| x.path != path); + Ok(()) + } + fn run_once(&self) -> Result<()> { if self.fault.get() { self.nr_run_once_faults