Skip to main content

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}