1#![cfg(not(target_arch = "wasm32"))]
13
14use memmap2::MmapOptions;
15use std::path::{Path, PathBuf};
16use std::sync::{Arc, RwLock};
17
18#[cfg(target_os = "macos")]
22mod darwin {
23 pub const F_NOCACHE: libc::c_int = 48;
24 pub const MADV_WILLNEED: libc::c_int = 3;
25 pub const MADV_FREE: libc::c_int = 5;
26
27 pub use std::path::Path;
28
29 extern "C" {
30 pub fn clonefile(
32 src: *const libc::c_char,
33 dst: *const libc::c_char,
34 flags: libc::c_uint,
35 ) -> libc::c_int;
36 }
37
38 pub unsafe fn madvise_willneed(ptr: *mut libc::c_void, len: libc::size_t) {
43 libc::madvise(ptr, len, MADV_WILLNEED);
44 }
45
46 pub unsafe fn madvise_free(ptr: *mut libc::c_void, len: libc::size_t) {
52 libc::madvise(ptr, len, MADV_FREE);
53 }
54
55 pub unsafe fn set_nocache(fd: libc::c_int) {
61 libc::fcntl(fd, F_NOCACHE, 1i32);
62 }
63
64 pub fn clonefile_paths(src: &Path, dst: &Path) -> std::io::Result<()> {
66 use std::ffi::CString;
67 let s = CString::new(src.to_str().ok_or_else(|| {
68 std::io::Error::new(std::io::ErrorKind::InvalidInput, "non-UTF-8 src path")
69 })?)
70 .map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidInput, e))?;
71 let d = CString::new(dst.to_str().ok_or_else(|| {
72 std::io::Error::new(std::io::ErrorKind::InvalidInput, "non-UTF-8 dst path")
73 })?)
74 .map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidInput, e))?;
75 let rc = unsafe { clonefile(s.as_ptr(), d.as_ptr(), 0) };
77 if rc == 0 {
78 Ok(())
79 } else {
80 Err(std::io::Error::last_os_error())
81 }
82 }
83}
84
85#[derive(Debug, Clone)]
90pub enum StorageError {
91 Io(String),
92 NotFound(String),
93 OutOfSpace(String),
94 HardwareUnavailable(String),
95 PermissionDenied(String),
96 Unsupported(String),
97}
98
99impl std::fmt::Display for StorageError {
100 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
101 match self {
102 StorageError::Io(m) => write!(f, "I/O: {m}"),
103 StorageError::NotFound(m) => write!(f, "not found: {m}"),
104 StorageError::OutOfSpace(m) => write!(f, "out of space: {m}"),
105 StorageError::HardwareUnavailable(m) => write!(f, "hardware unavailable: {m}"),
106 StorageError::PermissionDenied(m) => write!(f, "permission denied: {m}"),
107 StorageError::Unsupported(m) => write!(f, "unsupported on platform: {m}"),
108 }
109 }
110}
111impl std::error::Error for StorageError {}
112
113#[derive(Debug, Clone, PartialEq)]
118pub enum DriverKind {
119 Zns,
120 WinNvme,
121 MmapApfs,
122 Mmap,
123}
124
125#[derive(Debug, Clone)]
126pub struct DriverCapabilities {
127 pub kind: DriverKind,
128 pub zone_append: bool,
129 pub free_snapshots: bool,
130 pub csd_dispatch: bool,
131 pub max_writers: u32,
132}
133
134pub trait StorageDriver: Send + Sync {
139 fn capabilities(&self) -> DriverCapabilities;
140 fn write(&self, key: &str, data: &[u8]) -> Result<(), StorageError>;
141 fn append(&self, key: &str, data: &[u8]) -> Result<(), StorageError>;
142 fn read(&self, key: &str) -> Result<Vec<u8>, StorageError>;
143 fn read_range(&self, key: &str, offset: usize, len: usize) -> Result<Vec<u8>, StorageError>;
144 fn delete(&self, key: &str) -> Result<(), StorageError>;
145 fn snapshot(&self, snapshot_id: &str) -> Result<(), StorageError>;
148 fn flush(&self) -> Result<(), StorageError>;
149 fn prefetch_hint(&self, key: &str);
150 fn eviction_hint(&self, key: &str);
151 fn describe(&self) -> &str;
152}
153
154fn key_to_filename(key: &str) -> String {
159 key.chars()
160 .map(|c| {
161 if c.is_alphanumeric() || c == '-' || c == '.' {
162 c
163 } else {
164 '_'
165 }
166 })
167 .collect()
168}
169
170fn key_path(root: &Path, key: &str) -> PathBuf {
171 root.join(key_to_filename(key))
172}
173
174fn snap_dir(root: &Path, snapshot_id: &str) -> PathBuf {
175 root.join(format!(".snap_{}", key_to_filename(snapshot_id)))
176}
177
178pub struct MmapDriver {
186 root: PathBuf,
187 _guard: Arc<RwLock<()>>,
189}
190
191impl MmapDriver {
192 pub fn new<P: AsRef<Path>>(root: P) -> Self {
193 let root = root.as_ref().to_path_buf();
194 let _ = std::fs::create_dir_all(&root);
195 Self {
196 root,
197 _guard: Arc::new(RwLock::new(())),
198 }
199 }
200}
201
202impl StorageDriver for MmapDriver {
203 fn capabilities(&self) -> DriverCapabilities {
204 DriverCapabilities {
205 kind: DriverKind::Mmap,
206 zone_append: false,
207 free_snapshots: false,
208 csd_dispatch: false,
209 max_writers: 1,
210 }
211 }
212
213 fn write(&self, key: &str, data: &[u8]) -> Result<(), StorageError> {
214 std::fs::write(key_path(&self.root, key), data).map_err(|e| StorageError::Io(e.to_string()))
215 }
216
217 fn append(&self, key: &str, data: &[u8]) -> Result<(), StorageError> {
218 use std::io::Write;
219 let mut f = std::fs::OpenOptions::new()
220 .create(true)
221 .append(true)
222 .open(key_path(&self.root, key))
223 .map_err(|e| StorageError::Io(e.to_string()))?;
224 f.write_all(data)
225 .map_err(|e| StorageError::Io(e.to_string()))
226 }
227
228 fn read(&self, key: &str) -> Result<Vec<u8>, StorageError> {
229 let path = key_path(&self.root, key);
230 let f = std::fs::File::open(&path).map_err(|_| StorageError::NotFound(key.to_string()))?;
231 if f.metadata().map(|m| m.len()).unwrap_or(0) == 0 {
232 return Ok(Vec::new());
233 }
234 let mmap =
236 unsafe { MmapOptions::new().map(&f) }.map_err(|e| StorageError::Io(e.to_string()))?;
237 Ok(mmap.to_vec())
238 }
239
240 fn read_range(&self, key: &str, offset: usize, len: usize) -> Result<Vec<u8>, StorageError> {
241 let data = self.read(key)?;
242 let end = (offset + len).min(data.len());
243 if offset > data.len() {
244 return Err(StorageError::Io(format!(
245 "offset {offset} past end {}",
246 data.len()
247 )));
248 }
249 Ok(data[offset..end].to_vec())
250 }
251
252 fn delete(&self, key: &str) -> Result<(), StorageError> {
253 let path = key_path(&self.root, key);
254 if path.exists() {
255 std::fs::remove_file(path).map_err(|e| StorageError::Io(e.to_string()))?;
256 }
257 Ok(())
258 }
259
260 fn snapshot(&self, snapshot_id: &str) -> Result<(), StorageError> {
261 let dst = snap_dir(&self.root, snapshot_id);
262 std::fs::create_dir_all(&dst).map_err(|e| StorageError::Io(e.to_string()))?;
263 for entry in std::fs::read_dir(&self.root).map_err(|e| StorageError::Io(e.to_string()))? {
264 let entry = entry.map_err(|e| StorageError::Io(e.to_string()))?;
265 let p = entry.path();
266 if p.is_file() {
267 let name = p.file_name().unwrap_or_default();
268 std::fs::copy(&p, dst.join(name)).map_err(|e| StorageError::Io(e.to_string()))?;
269 }
270 }
271 Ok(())
272 }
273
274 fn flush(&self) -> Result<(), StorageError> {
275 Ok(())
276 }
277 fn prefetch_hint(&self, _key: &str) {}
278 fn eviction_hint(&self, _key: &str) {}
279 fn describe(&self) -> &str {
280 "MmapDriver (file-backed memmap2, portable)"
281 }
282}
283
284pub struct MmapApfsDriver {
295 inner: MmapDriver,
296}
297
298impl MmapApfsDriver {
299 pub fn new<P: AsRef<Path>>(root: P) -> Self {
300 Self {
301 inner: MmapDriver::new(root),
302 }
303 }
304}
305
306impl StorageDriver for MmapApfsDriver {
307 fn capabilities(&self) -> DriverCapabilities {
308 DriverCapabilities {
309 kind: DriverKind::MmapApfs,
310 zone_append: false,
311 free_snapshots: cfg!(any(target_os = "macos", target_os = "ios")),
312 csd_dispatch: false,
313 max_writers: 4,
314 }
315 }
316
317 fn write(&self, key: &str, data: &[u8]) -> Result<(), StorageError> {
318 self.inner.write(key, data)
319 }
320
321 fn append(&self, key: &str, data: &[u8]) -> Result<(), StorageError> {
322 #[cfg(target_os = "macos")]
325 {
326 use std::io::Write;
327 use std::os::unix::io::AsRawFd;
328 let path = key_path(&self.inner.root, key);
329 let f = std::fs::OpenOptions::new()
330 .create(true)
331 .append(true)
332 .open(&path)
333 .map_err(|e| StorageError::Io(e.to_string()))?;
334 unsafe {
336 darwin::set_nocache(f.as_raw_fd());
337 }
338 let mut f = f;
339 f.write_all(data)
340 .map_err(|e| StorageError::Io(e.to_string()))?;
341 return Ok(());
342 }
343 #[cfg(not(target_os = "macos"))]
344 self.inner.append(key, data)
345 }
346
347 fn read(&self, key: &str) -> Result<Vec<u8>, StorageError> {
348 let data = self.inner.read(key)?;
349 #[cfg(target_os = "macos")]
352 if !data.is_empty() {
353 unsafe {
355 darwin::madvise_willneed(
356 data.as_ptr() as *mut libc::c_void,
357 data.len() as libc::size_t,
358 );
359 }
360 }
361 Ok(data)
362 }
363
364 fn read_range(&self, key: &str, offset: usize, len: usize) -> Result<Vec<u8>, StorageError> {
365 self.inner.read_range(key, offset, len)
366 }
367
368 fn delete(&self, key: &str) -> Result<(), StorageError> {
369 self.eviction_hint(key);
370 self.inner.delete(key)
371 }
372
373 fn snapshot(&self, snapshot_id: &str) -> Result<(), StorageError> {
374 let src = &self.inner.root;
375 let dst = snap_dir(src, snapshot_id);
376
377 #[cfg(target_os = "macos")]
378 {
379 if dst.exists() {
382 std::fs::remove_dir_all(&dst).map_err(|e| StorageError::Io(e.to_string()))?;
383 }
384 return darwin::clonefile_paths(src, &dst)
385 .map_err(|e| StorageError::Io(format!("clonefile: {e}")));
386 }
387
388 #[cfg(not(target_os = "macos"))]
389 {
390 let _ = dst;
391 self.inner.snapshot(snapshot_id)
392 }
393 }
394
395 fn flush(&self) -> Result<(), StorageError> {
396 #[cfg(target_os = "macos")]
397 {
398 let sentinel = self.inner.root.join(".flush");
402 let _ = std::fs::OpenOptions::new()
403 .create(true)
404 .write(true)
405 .open(&sentinel)
406 .map(|f| {
407 use std::os::unix::io::AsRawFd;
408 unsafe {
410 libc::fcntl(f.as_raw_fd(), libc::F_FULLFSYNC);
411 }
412 });
413 }
414 Ok(())
415 }
416
417 fn prefetch_hint(&self, key: &str) {
418 #[cfg(target_os = "macos")]
419 {
420 if let Ok(data) = self.inner.read(key) {
421 if !data.is_empty() {
422 unsafe {
424 darwin::madvise_willneed(
425 data.as_ptr() as *mut libc::c_void,
426 data.len() as libc::size_t,
427 );
428 }
429 }
430 }
431 }
432 #[cfg(not(target_os = "macos"))]
433 let _ = key;
434 }
435
436 fn eviction_hint(&self, key: &str) {
437 #[cfg(target_os = "macos")]
438 {
439 if let Ok(data) = self.inner.read(key) {
440 if !data.is_empty() {
441 unsafe {
445 darwin::madvise_free(
446 data.as_ptr() as *mut libc::c_void,
447 data.len() as libc::size_t,
448 );
449 }
450 }
451 }
452 }
453 #[cfg(not(target_os = "macos"))]
454 let _ = key;
455 }
456
457 fn describe(&self) -> &str {
458 "MmapApfsDriver (Darwin UMA + APFS clonefile + madvise + F_NOCACHE)"
459 }
460}
461
462pub struct ZnsDriver {
470 manager: Arc<std::sync::Mutex<crate::zns_storage::ZnsZoneManager>>,
471 overlay: MmapDriver,
472}
473
474impl ZnsDriver {
475 pub fn new<P: AsRef<Path>>(
476 manager: crate::zns_storage::ZnsZoneManager,
477 overlay_dir: P,
478 ) -> Self {
479 Self {
480 manager: Arc::new(std::sync::Mutex::new(manager)),
481 overlay: MmapDriver::new(overlay_dir),
482 }
483 }
484}
485
486impl StorageDriver for ZnsDriver {
487 fn capabilities(&self) -> DriverCapabilities {
488 DriverCapabilities {
489 kind: DriverKind::Zns,
490 zone_append: true,
491 free_snapshots: false,
492 csd_dispatch: false,
493 max_writers: 8,
494 }
495 }
496
497 fn write(&self, key: &str, data: &[u8]) -> Result<(), StorageError> {
498 self.overlay.write(key, data)
502 }
503 fn append(&self, key: &str, data: &[u8]) -> Result<(), StorageError> {
504 let zone_type = crate::zns_storage::ZoneType::Sequential;
506 let size = data.len() as u64;
507 let result = {
508 let mut mgr = self
509 .manager
510 .lock()
511 .map_err(|_| StorageError::Io("ZNS lock poisoned".into()))?;
512 mgr.allocate_zone(zone_type, size)
513 .and_then(|handle| mgr.write_zone(&handle, data))
514 .map_err(|e| StorageError::Io(e.to_string()))
515 };
516 if result.is_ok() {
517 result
518 } else {
519 self.overlay.append(key, data)
520 }
521 }
522 fn read(&self, key: &str) -> Result<Vec<u8>, StorageError> {
523 self.overlay.read(key)
524 }
525 fn read_range(&self, key: &str, offset: usize, len: usize) -> Result<Vec<u8>, StorageError> {
526 self.overlay.read_range(key, offset, len)
527 }
528 fn delete(&self, key: &str) -> Result<(), StorageError> {
529 self.overlay.delete(key)
530 }
531 fn snapshot(&self, snapshot_id: &str) -> Result<(), StorageError> {
532 self.overlay.snapshot(snapshot_id)
533 }
534 fn flush(&self) -> Result<(), StorageError> {
535 Ok(())
536 }
537 fn prefetch_hint(&self, _key: &str) {}
538 fn eviction_hint(&self, _key: &str) {}
539 fn describe(&self) -> &str {
540 "ZnsDriver (Linux ZNS NVMe zone-append + overlay)"
541 }
542}
543
544pub struct WinNvmeDriver {
557 overlay: MmapDriver,
558 pub hardware_present: bool,
559 device_path: String,
560}
561
562impl WinNvmeDriver {
563 const IOCTL_STORAGE_QUERY_PROPERTY: u32 = 0x002D_1400;
566
567 pub fn new<P: AsRef<Path>>(overlay_dir: P) -> Self {
568 let (hw, path) = Self::probe_devices();
569 Self {
570 overlay: MmapDriver::new(overlay_dir),
571 hardware_present: hw,
572 device_path: path,
573 }
574 }
575
576 fn probe_devices() -> (bool, String) {
577 for i in 0..8u32 {
578 let path = format!(r"\\.\PhysicalDrive{}", i);
579 if Self::probe_nvme(&path) {
580 return (true, path);
581 }
582 }
583 (false, String::new())
584 }
585
586 fn probe_nvme(device_path: &str) -> bool {
587 #[cfg(all(target_os = "windows", target_arch = "x86_64"))]
588 {
589 use windows::core::PCWSTR;
590 use windows::Win32::Foundation::{GENERIC_READ, INVALID_HANDLE_VALUE};
591 use windows::Win32::Storage::FileSystem::{
592 CreateFileW, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ, FILE_SHARE_WRITE,
593 OPEN_EXISTING,
594 };
595 use windows::Win32::System::IO::DeviceIoControl;
596
597 let wide: Vec<u16> = device_path
598 .encode_utf16()
599 .chain(std::iter::once(0))
600 .collect();
601 let handle = unsafe {
602 CreateFileW(
603 PCWSTR(wide.as_ptr()),
604 GENERIC_READ.0,
605 FILE_SHARE_READ | FILE_SHARE_WRITE,
606 None,
607 OPEN_EXISTING,
608 FILE_ATTRIBUTE_NORMAL,
609 None,
610 )
611 };
612 let handle = match handle {
613 Ok(h) if h != INVALID_HANDLE_VALUE => h,
614 _ => return false,
615 };
616
617 #[repr(C)]
619 struct StoragePropertyQuery {
620 property_id: u32,
621 query_type: u32,
622 additional: [u8; 1],
623 }
624 let query = StoragePropertyQuery {
625 property_id: 0,
626 query_type: 0,
627 additional: [0],
628 };
629 let mut buf = [0u8; 512];
630 let mut returned = 0u32;
631
632 let ok = unsafe {
633 DeviceIoControl(
634 handle,
635 Self::IOCTL_STORAGE_QUERY_PROPERTY,
636 Some(&query as *const _ as *const _),
637 std::mem::size_of::<StoragePropertyQuery>() as u32,
638 Some(buf.as_mut_ptr() as *mut _),
639 buf.len() as u32,
640 Some(&mut returned),
641 None,
642 )
643 };
644 let _ = unsafe { windows::Win32::Foundation::CloseHandle(handle) };
645 ok.is_ok() && returned > 0
647 }
648 #[cfg(not(all(target_os = "windows", target_arch = "x86_64")))]
649 false
650 }
651}
652
653impl StorageDriver for WinNvmeDriver {
654 fn capabilities(&self) -> DriverCapabilities {
655 DriverCapabilities {
656 kind: DriverKind::WinNvme,
657 zone_append: self.hardware_present,
658 free_snapshots: false,
659 csd_dispatch: self.hardware_present,
660 max_writers: if self.hardware_present { 4 } else { 1 },
661 }
662 }
663
664 fn write(&self, key: &str, data: &[u8]) -> Result<(), StorageError> {
665 self.overlay.write(key, data)
666 }
667 fn append(&self, key: &str, data: &[u8]) -> Result<(), StorageError> {
668 self.overlay.append(key, data)
669 }
670 fn read(&self, key: &str) -> Result<Vec<u8>, StorageError> {
671 self.overlay.read(key)
672 }
673 fn read_range(&self, key: &str, offset: usize, len: usize) -> Result<Vec<u8>, StorageError> {
674 self.overlay.read_range(key, offset, len)
675 }
676 fn delete(&self, key: &str) -> Result<(), StorageError> {
677 self.overlay.delete(key)
678 }
679 fn snapshot(&self, snapshot_id: &str) -> Result<(), StorageError> {
680 self.overlay.snapshot(snapshot_id)
681 }
682 fn flush(&self) -> Result<(), StorageError> {
683 self.overlay.flush()
684 }
685 fn prefetch_hint(&self, _key: &str) {}
686 fn eviction_hint(&self, _key: &str) {}
687
688 fn describe(&self) -> &str {
689 if self.hardware_present {
690 "WinNvmeDriver (Windows DeviceIoControl NVMe passthrough — hardware found)"
691 } else {
692 "WinNvmeDriver (fallback — no admin/hardware, using file-backed overlay)"
693 }
694 }
695}
696
697pub fn running_under_wsl2() -> bool {
711 #[cfg(target_os = "linux")]
712 {
713 std::fs::read_to_string("/proc/version")
714 .map(|v| v.to_ascii_lowercase().contains("microsoft"))
715 .unwrap_or(false)
716 }
717 #[cfg(not(target_os = "linux"))]
718 false
719}
720
721pub fn log_startup_diagnostics() {
724 if running_under_wsl2() {
725 log::warn!(
726 "[storage] Running inside WSL2. ZNS/CSD hardware is inaccessible \
727 through the Hyper-V storage layer — falling back to MmapDriver. \
728 Port 4242 may not be reachable from the Windows LAN. \
729 Enable Mirrored Mode: add `networkingMode=mirrored` under [wsl2] \
730 in ~/.wslconfig, then `wsl --shutdown` to apply."
731 );
732 }
733 #[cfg(target_os = "windows")]
734 log::info!("[storage] Platform: Windows x64 — probing NVMe via DeviceIoControl");
735 #[cfg(target_os = "macos")]
736 log::info!(
737 "[storage] Platform: macOS — using MmapApfsDriver \
738 (madvise + APFS clonefile + F_NOCACHE WAL)"
739 );
740 #[cfg(all(target_os = "linux", not(target_arch = "wasm32")))]
741 if !running_under_wsl2() {
742 log::info!("[storage] Platform: Linux — probing ZNS NVMe devices");
743 }
744}
745
746pub fn open_storage<P: AsRef<Path>>(data_dir: P) -> Box<dyn StorageDriver> {
754 let data_dir = data_dir.as_ref().to_path_buf();
755 let _ = std::fs::create_dir_all(&data_dir);
756
757 #[cfg(target_os = "linux")]
759 {
760 if !running_under_wsl2() {
761 for i in 0..4u32 {
762 let dev = format!("/dev/nvme{}", i);
763 if let Ok(mgr) = crate::zns_storage::ZnsZoneManager::new(&dev) {
764 log::info!("[storage] ZnsDriver selected: {dev}");
765 return Box::new(ZnsDriver::new(mgr, data_dir));
766 }
767 }
768 }
769 log::info!("[storage] MmapDriver selected (Linux fallback)");
770 return Box::new(MmapDriver::new(data_dir));
771 }
772
773 #[cfg(target_os = "windows")]
775 {
776 let drv = WinNvmeDriver::new(&data_dir);
777 if drv.hardware_present {
778 log::info!("[storage] WinNvmeDriver selected: {}", drv.device_path);
779 } else {
780 log::info!("[storage] MmapDriver selected (Windows, no NVMe hardware/admin)");
781 }
782 return Box::new(drv);
783 }
784
785 #[cfg(any(target_os = "macos", target_os = "ios"))]
787 {
788 log::info!("[storage] MmapApfsDriver selected (Darwin UMA + APFS)");
789 return Box::new(MmapApfsDriver::new(data_dir));
790 }
791
792 #[cfg(not(any(
794 target_os = "linux",
795 target_os = "windows",
796 target_os = "macos",
797 target_os = "ios",
798 )))]
799 {
800 log::info!("[storage] MmapDriver selected (portable fallback)");
801 return Box::new(MmapDriver::new(data_dir));
802 }
803
804 #[allow(unreachable_code)]
805 Box::new(MmapDriver::new(data_dir))
806}
807
808#[derive(Debug, Clone, PartialEq)]
813pub enum NetworkFilterKind {
814 EbpfLinux,
815 WfpWindows,
816 MacNetworkExtension,
817 AndroidVpnService,
818 Noop,
819}
820
821pub trait NetworkFilter: Send + Sync {
822 fn kind(&self) -> NetworkFilterKind;
823 fn allow(&self, rule: &str) -> Result<(), StorageError>;
824 fn deny(&self, rule: &str) -> Result<(), StorageError>;
825 fn remove(&self, rule: &str) -> Result<(), StorageError>;
826 fn describe(&self) -> &str;
827}
828
829pub struct NoopFilter;
830impl NetworkFilter for NoopFilter {
831 fn kind(&self) -> NetworkFilterKind {
832 NetworkFilterKind::Noop
833 }
834 fn allow(&self, _: &str) -> Result<(), StorageError> {
835 Ok(())
836 }
837 fn deny(&self, _: &str) -> Result<(), StorageError> {
838 Ok(())
839 }
840 fn remove(&self, _: &str) -> Result<(), StorageError> {
841 Ok(())
842 }
843 fn describe(&self) -> &str {
844 "NoopFilter (no kernel packet filtering on this platform)"
845 }
846}
847
848pub fn open_network_filter() -> Box<dyn NetworkFilter> {
851 crate::ebpf_filter::open_platform_filter()
852}
853
854#[cfg(test)]
859mod tests {
860 use super::*;
861 use std::env;
862
863 fn tmpdir(suffix: &str) -> PathBuf {
864 let d = env::temp_dir().join(format!("qualiadb_storage_test_{suffix}"));
865 let _ = std::fs::remove_dir_all(&d);
866 d
867 }
868
869 #[test]
870 fn test_mmap_write_read() {
871 let d = MmapDriver::new(tmpdir("wr"));
872 d.write("key1", b"hello world").unwrap();
873 assert_eq!(d.read("key1").unwrap(), b"hello world");
874 }
875
876 #[test]
877 fn test_mmap_append() {
878 let d = MmapDriver::new(tmpdir("ap"));
879 d.write("k", b"foo").unwrap();
880 d.append("k", b"bar").unwrap();
881 assert_eq!(d.read("k").unwrap(), b"foobar");
882 }
883
884 #[test]
885 fn test_mmap_read_range() {
886 let d = MmapDriver::new(tmpdir("rr"));
887 d.write("k", b"0123456789").unwrap();
888 assert_eq!(d.read_range("k", 3, 4).unwrap(), b"3456");
889 }
890
891 #[test]
892 fn test_mmap_delete() {
893 let d = MmapDriver::new(tmpdir("del"));
894 d.write("k", b"data").unwrap();
895 d.delete("k").unwrap();
896 assert!(d.read("k").is_err());
897 }
898
899 #[test]
900 fn test_mmap_snapshot() {
901 let d = MmapDriver::new(tmpdir("snap"));
902 d.write("a", b"before").unwrap();
903 d.snapshot("s1").unwrap();
904 d.write("a", b"after").unwrap();
905 assert_eq!(d.read("a").unwrap(), b"after");
907 let snap_path = snap_dir(&d.root, "s1").join("a");
908 let snap_data = std::fs::read(&snap_path).unwrap();
909 assert_eq!(snap_data, b"before");
910 }
911
912 #[test]
913 fn test_open_storage_portable() {
914 let drv = open_storage(tmpdir("factory"));
915 drv.write("platform_test", b"ok").unwrap();
916 assert_eq!(drv.read("platform_test").unwrap(), b"ok");
917 }
918
919 #[test]
920 fn test_apfs_driver() {
921 let d = MmapApfsDriver::new(tmpdir("apfs"));
922 d.write("k", b"apfs_data").unwrap();
923 assert_eq!(d.read("k").unwrap(), b"apfs_data");
924 d.prefetch_hint("k");
925 d.eviction_hint("k");
926 d.flush().unwrap();
927 }
928
929 #[test]
930 fn test_wsl2_detection_no_panic() {
931 let _ = running_under_wsl2();
932 }
933
934 #[test]
935 fn test_noop_filter() {
936 let f = NoopFilter;
937 assert!(f.allow("any").is_ok());
938 assert!(f.deny("any").is_ok());
939 assert!(f.remove("any").is_ok());
940 }
941
942 #[test]
943 fn test_key_sanitisation() {
944 assert_eq!(key_to_filename("foo/bar:baz"), "foo_bar_baz");
945 assert_eq!(key_to_filename("hello-world.bin"), "hello-world.bin");
946 }
947}