smb_server_vfs/vfs.rs
1//! The virtual filesystem trait every storage backend implements.
2
3use async_trait::async_trait;
4
5use crate::{Entry, FileMeta, OpenFile, SetOp, VfsResult};
6
7/// Storage abstraction used by the protocol dispatchers.
8///
9/// Implementations own their handle state (inside
10/// [`OpenFile::inner`](crate::OpenFile::inner)) and are responsible for
11/// mapping relative share paths onto physical storage, including refusing
12/// path traversal.
13///
14/// The trait uses `?Send` futures so backends can hold thread-local io_uring
15/// resources (which are `!Send`); the implementor **object** is still
16/// `Send + Sync` so a single backend can be shared across per-core runtimes.
17/// All I/O must be non-blocking (io_uring / async), never blocking the runtime.
18#[async_trait(?Send)]
19pub trait Vfs: Send + Sync {
20 /// Create or open `rel` according to the NT-style parameters.
21 ///
22 /// Returns the populated [`OpenFile`], a metadata snapshot and the create
23 /// action taken (superseded / opened / created / overwritten).
24 async fn create(
25 &self,
26 rel: &str,
27 is_dir: bool,
28 access: u32,
29 disposition: u32,
30 options: u32,
31 attrs: u32,
32 ) -> VfsResult<(Box<OpenFile>, FileMeta, u32)>;
33
34 /// Read up to `len` bytes at `offset`.
35 async fn read(&self, open: &mut OpenFile, offset: u64, len: usize) -> VfsResult<Vec<u8>>;
36
37 /// Write `data` at `offset`, returning bytes written. When `write_through`
38 /// is set the data must reach stable storage before returning.
39 async fn write(
40 &self,
41 open: &mut OpenFile,
42 offset: u64,
43 data: &[u8],
44 write_through: bool,
45 ) -> VfsResult<u64>;
46
47 /// Reposition the file pointer; `mode` follows the SMB1 SEEK semantics
48 /// (0 = from start, 1 = current, 2 = from end) and returns the new offset.
49 async fn seek(&self, open: &mut OpenFile, mode: u16, offset: i64) -> VfsResult<u64>;
50
51 /// Flush one handle.
52 async fn flush(&self, open: &mut OpenFile) -> VfsResult<()>;
53
54 /// Flush every handle the backend currently keeps.
55 async fn flush_all(&self) -> VfsResult<()>;
56
57 /// Close a handle, applying pending deletion when requested.
58 async fn close(&self, open: Box<OpenFile>) -> VfsResult<()>;
59
60 /// Create a directory.
61 async fn mkdir(&self, rel: &str) -> VfsResult<()>;
62
63 /// Remove an (empty) directory.
64 async fn rmdir(&self, rel: &str) -> VfsResult<()>;
65
66 /// Verify a directory exists.
67 async fn check_dir(&self, rel: &str) -> VfsResult<()>;
68
69 /// Delete exactly one file (never directories).
70 async fn unlink(&self, rel: &str) -> VfsResult<()>;
71
72 /// Delete all files matching `pattern` inside directory `dir_rel`;
73 /// returns whether anything was removed. Wildcards `*`/`?` honoured.
74 async fn delete_pattern(&self, dir_rel: &str, pattern: &str) -> VfsResult<bool>;
75
76 /// Rename `old_rel` to `new_rel`.
77 async fn rename(&self, old_rel: &str, new_rel: &str) -> VfsResult<()>;
78
79 /// List entries of `dir_rel` with metadata snapshots.
80 async fn list(&self, dir_rel: &str) -> VfsResult<Vec<Entry>>;
81
82 /// Stat a path without opening it.
83 async fn stat(&self, rel: &str) -> VfsResult<FileMeta>;
84
85 /// Apply one neutral set-information operation to an open handle.
86 async fn set_info_open(&self, open: &mut OpenFile, op: &SetOp) -> VfsResult<()>;
87
88 /// Apply one neutral set-information operation to a path.
89 async fn set_info_path(&self, rel: &str, op: &SetOp) -> VfsResult<()>;
90
91 /// Query disk `(total_units, free_units, sectors_per_unit, bytes_per_sector)`.
92 async fn query_disk(&self) -> VfsResult<(u32, u32, u16, u16)>;
93
94 /// Zero the byte range `[offset, offset + len)` of an open handle
95 /// (FSCTL_SET_ZERO_DATA). The default writes zeros through [`Vfs::write`];
96 /// backends may override to punch a sparse hole.
97 async fn zero_range(&self, open: &mut OpenFile, offset: u64, len: u64) -> VfsResult<()> {
98 const ZERO_CHUNK: usize = 64 * 1024;
99 let zeros = vec![0u8; ZERO_CHUNK];
100 let mut pos = offset;
101 let mut remaining = len;
102 while remaining > 0 {
103 let n = remaining.min(zeros.len() as u64) as usize;
104 self.write(open, pos, &zeros[..n], false).await?;
105 pos += n as u64;
106 remaining -= n as u64;
107 }
108 Ok(())
109 }
110
111 /// Fetch the raw self-relative NT security descriptor stored for `rel`
112 /// ([MS-DTYP] ยง2.4.6), or `None` when the backend has none (the caller then
113 /// synthesises a default). Default backends store nothing.
114 async fn get_security(&self, rel: &str) -> VfsResult<Option<Vec<u8>>> {
115 let _ = rel;
116 Ok(None)
117 }
118
119 /// Persist a raw self-relative NT security descriptor for `rel`. Default
120 /// backends accept and discard it (no ACL storage).
121 async fn set_security(&self, rel: &str, descriptor: &[u8]) -> VfsResult<()> {
122 let _ = (rel, descriptor);
123 Ok(())
124 }
125
126 /// List the alternate data streams of `rel` as `(smb_stream_name, size)`
127 /// pairs (e.g. `:Zone.Identifier:$DATA`), excluding the default `::$DATA`
128 /// stream which the caller derives from the file size. Default: none.
129 async fn list_streams(&self, rel: &str) -> VfsResult<Vec<(String, u64)>> {
130 let _ = rel;
131 Ok(Vec::new())
132 }
133}