Skip to main content

nfs3_server/vfs/adapters/
mod.rs

1//! Adapters VFS types
2
3mod iterator;
4
5pub use iterator::ReadDirPlusToReadDir;
6use nfs3_types::nfs3::{fattr3, filename3, nfsstat3, sattr3};
7
8use super::{
9    DirEntryPlus, NextResult, NfsFileSystem, NfsReadFileSystem, ReadDirIterator,
10    ReadDirPlusIterator, VFSCapabilities,
11};
12use crate::vfs::FileHandle;
13
14/// An internal adapter that allows to reuse the same code with `ReadOnly` filesystems.
15///
16/// In general, you should not use this adapter directly. Instead, use the
17/// [`NFSTcpListener::bind_ro`][1] method to bind a read-only NFS server.
18///
19/// [1]: crate::tcp::NFSTcpListener::bind_ro
20pub struct ReadOnlyAdapter<T>(T);
21
22impl<T> ReadOnlyAdapter<T>
23where
24    T: NfsReadFileSystem,
25{
26    pub const fn new(inner: T) -> Self {
27        Self(inner)
28    }
29}
30
31impl<T> NfsReadFileSystem for ReadOnlyAdapter<T>
32where
33    T: NfsReadFileSystem,
34{
35    type Handle = T::Handle;
36
37    fn root_dir(&self) -> Self::Handle {
38        self.0.root_dir()
39    }
40
41    async fn lookup(
42        &self,
43        dirid: &Self::Handle,
44        filename: &filename3<'_>,
45    ) -> Result<Self::Handle, nfsstat3> {
46        self.0.lookup(dirid, filename).await
47    }
48
49    async fn getattr(&self, id: &Self::Handle) -> Result<fattr3, nfsstat3> {
50        let mut result = self.0.getattr(id).await;
51        if let Ok(attr) = &mut result {
52            remove_write_permissions(attr);
53        }
54        result
55    }
56
57    async fn read(
58        &self,
59        id: &Self::Handle,
60        offset: u64,
61        count: u32,
62    ) -> Result<(Vec<u8>, bool), nfsstat3> {
63        self.0.read(id, offset, count).await
64    }
65
66    async fn readdir(
67        &self,
68        dirid: &Self::Handle,
69        cookie3: u64,
70    ) -> Result<impl ReadDirIterator, nfsstat3> {
71        self.0.readdir(dirid, cookie3).await
72    }
73
74    async fn readdirplus(
75        &self,
76        dirid: &Self::Handle,
77        cookie3: u64,
78    ) -> Result<impl ReadDirPlusIterator<Self::Handle>, nfsstat3> {
79        self.0
80            .readdirplus(dirid, cookie3)
81            .await
82            .map(ReadOnlyIterator)
83    }
84
85    async fn readlink(
86        &self,
87        id: &Self::Handle,
88    ) -> Result<nfs3_types::nfs3::nfspath3<'_>, nfsstat3> {
89        self.0.readlink(id).await
90    }
91}
92
93impl<T> NfsFileSystem for ReadOnlyAdapter<T>
94where
95    T: NfsReadFileSystem,
96{
97    fn capabilities(&self) -> VFSCapabilities {
98        VFSCapabilities::ReadOnly
99    }
100
101    async fn setattr(&self, _id: &Self::Handle, _setattr: sattr3) -> Result<fattr3, nfsstat3> {
102        Err(nfsstat3::NFS3ERR_ROFS)
103    }
104
105    async fn write(
106        &self,
107        _id: &Self::Handle,
108        _offset: u64,
109        _data: &[u8],
110        _stable: nfs3_types::nfs3::stable_how,
111    ) -> Result<(fattr3, nfs3_types::nfs3::stable_how), nfsstat3> {
112        Err(nfsstat3::NFS3ERR_ROFS)
113    }
114
115    async fn create(
116        &self,
117        _dirid: &Self::Handle,
118        _filename: &filename3<'_>,
119        _attr: sattr3,
120    ) -> Result<(Self::Handle, fattr3), nfsstat3> {
121        Err(nfsstat3::NFS3ERR_ROFS)
122    }
123
124    async fn create_exclusive(
125        &self,
126        _dirid: &Self::Handle,
127        _filename: &filename3<'_>,
128        _createverf: nfs3_types::nfs3::createverf3,
129    ) -> Result<Self::Handle, nfsstat3> {
130        Err(nfsstat3::NFS3ERR_ROFS)
131    }
132
133    async fn mkdir(
134        &self,
135        _dirid: &Self::Handle,
136        _dirname: &filename3<'_>,
137    ) -> Result<(Self::Handle, fattr3), nfsstat3> {
138        Err(nfsstat3::NFS3ERR_ROFS)
139    }
140
141    async fn remove(
142        &self,
143        _dirid: &Self::Handle,
144        _filename: &filename3<'_>,
145    ) -> Result<(), nfsstat3> {
146        Err(nfsstat3::NFS3ERR_ROFS)
147    }
148
149    async fn rename<'a>(
150        &self,
151        _from_dirid: &Self::Handle,
152        _from_filename: &filename3<'a>,
153        _to_dirid: &Self::Handle,
154        _to_filename: &filename3<'a>,
155    ) -> Result<(), nfsstat3> {
156        Err(nfsstat3::NFS3ERR_ROFS)
157    }
158
159    async fn symlink<'a>(
160        &self,
161        _dirid: &Self::Handle,
162        _linkname: &filename3<'a>,
163        _symlink: &nfs3_types::nfs3::nfspath3<'a>,
164        _attr: &sattr3,
165    ) -> Result<(Self::Handle, fattr3), nfsstat3> {
166        Err(nfsstat3::NFS3ERR_ROFS)
167    }
168
169    async fn commit(&self, _id: &Self::Handle, _offset: u64, _count: u32) -> Result<(), nfsstat3> {
170        Err(nfsstat3::NFS3ERR_ROFS)
171    }
172}
173
174#[derive(Debug)]
175struct ReadOnlyIterator<T>(T);
176
177impl<H, T> ReadDirPlusIterator<H> for ReadOnlyIterator<T>
178where
179    H: FileHandle,
180    T: ReadDirPlusIterator<H>,
181{
182    async fn next(&mut self) -> NextResult<DirEntryPlus<H>> {
183        let mut result = self.0.next().await;
184        if let NextResult::Ok(entry) = &mut result {
185            if let Some(attr) = &mut entry.name_attributes {
186                remove_write_permissions(attr);
187            }
188        }
189        result
190    }
191}
192
193const fn remove_write_permissions(attr: &mut fattr3) {
194    attr.mode &= 0o555; // Read-only permissions
195}