1use super::protocol::*;
5use lxutil::LxCreateOptions;
6use lxutil::LxFile;
7use lxutil::LxVolume;
8use lxutil::PathBufExt;
9use parking_lot::RwLock;
10use std::path::PathBuf;
11use std::sync::Arc;
12
13pub trait Fid: Send + Sync {
16 fn get_attr(&self) -> lx::Result<(Qid, lx::Stat)> {
17 Err(lx::Error::EINVAL)
18 }
19
20 fn walk(&self, _name: &lx::LxStr) -> lx::Result<Qid> {
21 Err(lx::Error::EINVAL)
22 }
23
24 fn open(&self, _flags: u32) -> lx::Result<Qid> {
25 Err(lx::Error::EINVAL)
26 }
27
28 fn create(&self, _name: &lx::LxStr, _flags: u32, _mode: u32, _gid: u32) -> lx::Result<Qid> {
29 Err(lx::Error::EINVAL)
30 }
31
32 fn read(&self, _offset: u64, _buffer: &mut [u8]) -> lx::Result<u32> {
33 Err(lx::Error::EINVAL)
34 }
35
36 fn write(&self, _offset: u64, _buffer: &[u8]) -> lx::Result<u32> {
37 Err(lx::Error::EINVAL)
38 }
39
40 fn read_dir(&self, _offset: u64, _buffer: &mut [u8]) -> lx::Result<u32> {
41 Err(lx::Error::EINVAL)
42 }
43
44 fn mkdir(&self, _name: &lx::LxStr, _mode: u32, _gid: u32) -> lx::Result<Qid> {
45 Err(lx::Error::EINVAL)
46 }
47
48 fn unlink_at(&self, _name: &lx::LxStr, _flags: u32) -> lx::Result<()> {
49 Err(lx::Error::EINVAL)
50 }
51
52 fn fid_clone(&self) -> Arc<dyn Fid>;
53
54 fn clunk(&self) -> lx::Result<()> {
55 Ok(())
56 }
57}
58
59pub struct FileState {
61 root: Arc<LxVolume>,
62 path: PathBuf,
63 qid: Qid,
64 file: Option<LxFile>,
65}
66
67impl FileState {
68 fn new(root: Arc<LxVolume>) -> lx::Result<FileState> {
70 let mut state = FileState {
71 root,
72 path: PathBuf::new(),
73 qid: Default::default(),
74 file: None,
75 };
76
77 state.validate_exists()?;
78 Ok(state)
79 }
80
81 fn fid_clone(&self) -> FileState {
83 FileState {
84 root: Arc::clone(&self.root),
85 path: self.path.clone(),
86 file: None,
87 ..*self
88 }
89 }
90
91 fn validate_exists(&mut self) -> lx::Result<()> {
93 let (qid, _) = self.get_attributes()?;
94 self.qid = qid;
95 Ok(())
96 }
97
98 fn open(&mut self, flags: u32) -> lx::Result<Qid> {
100 self.check_not_open()?;
101
102 let flags = Self::open_flags_to_o_flags(flags) | lx::O_NOFOLLOW;
103 let file = self.root.open(&self.path, flags, None)?;
104 self.file = Some(file);
105 Ok(self.qid)
106 }
107
108 fn create(
110 &mut self,
111 name: &lx::LxStr,
112 flags: u32,
113 options: LxCreateOptions,
114 ) -> lx::Result<Qid> {
115 self.check_not_open()?;
116
117 let flags = Self::open_flags_to_o_flags(flags) | lx::O_CREAT | lx::O_NOFOLLOW;
118 let child_path = self.child_path(name)?;
119
120 let file = self.root.open(&child_path, flags, Some(options))?;
121 let (qid, _) = Self::get_file_attributes(&file)?;
122 self.path = child_path;
123 self.file = Some(file);
124 self.qid = qid;
125 Ok(qid)
126 }
127
128 fn read_dir(&mut self, offset: u64, buffer: &mut [u8]) -> lx::Result<u32> {
130 let mut writer = SliceWriter::new_raw(buffer);
131 let file = self.file.as_mut().ok_or(lx::Error::EBADF)?;
132
133 let mut has_entry = false;
134 let self_qid = self.qid;
135 file.read_dir(offset as lx::off_t, |entry| {
136 has_entry = true;
137
138 let qid = if entry.inode_nr == 0 {
141 self_qid
142 } else {
143 Qid {
144 path: entry.inode_nr,
145 version: 0,
146 qid_type: Self::get_qid_type_from_mode((entry.file_type as u32) << 12),
147 }
148 };
149
150 Ok(writer.dir_entry(&entry.name, &qid, entry.offset as u64, entry.file_type))
151 })?;
152
153 if has_entry && writer.size() == 0 {
155 return Err(lx::Error::EINVAL);
156 }
157
158 Ok(writer.size() as u32)
159 }
160
161 pub fn read(&self, offset: u64, buffer: &mut [u8]) -> lx::Result<u32> {
162 assert!(buffer.len() < u32::MAX as usize);
163
164 let file = self.file.as_ref().ok_or(lx::Error::EBADF)?;
165 let size = file.pread(buffer, offset as i64)?;
166 Ok(size as u32)
167 }
168
169 pub fn write(&self, offset: u64, buffer: &[u8], request_uid: lx::uid_t) -> lx::Result<u32> {
170 assert!(buffer.len() < u32::MAX as usize);
171
172 let file = self.file.as_ref().ok_or(lx::Error::EBADF)?;
173 let size = file.pwrite(buffer, offset as i64, request_uid)?;
174 Ok(size as u32)
175 }
176
177 fn child_path(&self, name: &lx::LxStr) -> lx::Result<PathBuf> {
178 let mut path = self.path.clone();
179 path.push_lx(name)?;
180 Ok(path)
181 }
182
183 fn get_qid_type_from_mode(mode: u32) -> u8 {
185 match mode & lx::S_IFMT {
186 lx::S_IFLNK => QID_TYPE_SYMLINK,
187 lx::S_IFDIR => QID_TYPE_DIRECTORY,
188 _ => QID_TYPE_FILE,
189 }
190 }
191
192 fn stat_to_qid(stat: &lx::Stat) -> Qid {
193 Qid {
194 path: stat.inode_nr,
195 version: 0,
196 qid_type: Self::get_qid_type_from_mode(stat.mode),
197 }
198 }
199
200 fn open_flags_to_o_flags(flags: u32) -> i32 {
202 let mut result = (flags & !OPEN_FLAG_DIRECTORY) as i32;
203
204 if flags & OPEN_FLAG_DIRECTORY != 0 {
206 result |= lx::O_DIRECTORY;
207 }
208
209 result
210 }
211
212 fn check_not_open(&self) -> lx::Result<()> {
214 if self.file.is_some() {
215 return Err(lx::Error::EINVAL);
216 }
217
218 Ok(())
219 }
220
221 fn get_attributes(&self) -> lx::Result<(Qid, lx::Stat)> {
223 let stat = if let Some(file) = self.file.as_ref() {
224 file.fstat()?
225 } else {
226 self.root.lstat(&self.path)?
227 };
228
229 Ok((Self::stat_to_qid(&stat), stat))
230 }
231
232 fn get_file_attributes(file: &LxFile) -> lx::Result<(Qid, lx::Stat)> {
233 let stat = file.fstat()?;
234 Ok((Self::stat_to_qid(&stat), stat))
235 }
236}
237
238pub struct File {
240 uid: u32,
241 state: RwLock<FileState>,
242}
243
244impl File {
245 pub fn new(root: Arc<LxVolume>, uid: u32) -> lx::Result<(File, Qid)> {
247 let state = FileState::new(root)?;
248 let qid = state.qid;
249 let file = File {
250 uid,
251 state: RwLock::new(state),
252 };
253
254 Ok((file, qid))
255 }
256}
257
258impl Fid for File {
259 fn get_attr(&self) -> lx::Result<(Qid, lx::Stat)> {
261 self.state.read().get_attributes()
262 }
263
264 fn walk(&self, name: &lx::LxStr) -> lx::Result<Qid> {
266 let mut state = self.state.write();
267 state.path.push_lx(name)?;
268 state.validate_exists()?;
269 Ok(state.qid)
270 }
271
272 fn fid_clone(&self) -> Arc<dyn Fid> {
274 let state = self.state.read().fid_clone();
275 let clone = File {
276 state: RwLock::new(state),
277 ..*self
278 };
279
280 Arc::new(clone)
281 }
282
283 fn open(&self, flags: u32) -> lx::Result<Qid> {
285 self.state.write().open(flags)
286 }
287
288 fn create(&self, name: &lx::LxStr, flags: u32, mode: u32, gid: u32) -> lx::Result<Qid> {
290 self.state
293 .write()
294 .create(name, flags, LxCreateOptions::new(mode, self.uid, gid))
295 }
296
297 fn read(&self, offset: u64, buffer: &mut [u8]) -> lx::Result<u32> {
299 let state = self.state.read();
300 state.read(offset, buffer)
301 }
302
303 fn write(&self, offset: u64, buffer: &[u8]) -> lx::Result<u32> {
305 let state = self.state.read();
306 state.write(offset, buffer, self.uid)
307 }
308
309 fn read_dir(&self, offset: u64, buffer: &mut [u8]) -> lx::Result<u32> {
311 let mut state = self.state.write();
312 state.read_dir(offset, buffer)
313 }
314
315 fn mkdir(&self, name: &lx::LxStr, mode: u32, gid: u32) -> lx::Result<Qid> {
317 let state = self.state.read();
320 let child_path = state.child_path(name)?;
321 let stat = state
322 .root
323 .mkdir_stat(child_path, LxCreateOptions::new(mode, self.uid, gid))?;
324
325 Ok(FileState::stat_to_qid(&stat))
326 }
327
328 fn unlink_at(&self, name: &lx::LxStr, flags: u32) -> lx::Result<()> {
330 let state = self.state.read();
331 let child_path = state.child_path(name)?;
332 state.root.unlink(child_path, flags as i32)
333 }
334}