1use crate::cache::FileEntry;
2use crate::file_handle::UuidFileHandle;
3use crate::utils::{file_id, get_string};
4use lb_rs::model::file::File;
5use lb_rs::model::file_metadata::FileType;
6use lb_rs::{Lb, Uuid};
7use nfs3_server::nfs3_types::nfs3::{
8 Nfs3Option, fattr3, filename3, nfspath3, nfsstat3, sattr3, set_atime, set_mtime,
9};
10use nfs3_server::vfs::{
11 DirEntry, DirEntryPlus, NfsFileSystem, NfsReadFileSystem, ReadDirIterator, ReadDirPlusIterator,
12};
13use std::collections::HashMap;
14use std::iter::Iterator as StdIterator;
15use std::sync::Arc;
16use tokio::sync::Mutex;
17use tracing::{info, instrument, warn};
18
19type EntriesMap = Arc<Mutex<HashMap<UuidFileHandle, FileEntry>>>;
20
21#[derive(Clone)]
22pub struct Drive {
23 pub lb: Lb,
24
25 pub root: Uuid,
27
28 pub data: EntriesMap,
37}
38
39impl Drive {
40 async fn load_children(
52 &self, dirid: &UuidFileHandle, cookie: u64,
53 ) -> impl StdIterator<Item = File> + 'static {
54 let mut children = self.lb.get_children(dirid.as_uuid()).await.unwrap();
55
56 children.sort_by(|a, b| a.id.cmp(&b.id));
57
58 let mut start_index = 0;
59 if cookie > 0 {
60 start_index = children
61 .iter()
62 .position(|child| file_id(child) > cookie)
63 .unwrap_or_else(|| {
64 warn!("cookie {cookie} not found");
65 children.len()
66 });
67 }
68
69 children.into_iter().skip(start_index)
70 }
71}
72
73impl NfsReadFileSystem for Drive {
74 type Handle = UuidFileHandle;
75
76 #[instrument(skip(self))]
77 fn root_dir(&self) -> Self::Handle {
78 self.root.into()
79 }
80
81 #[instrument(skip(self), fields(dirid = dirid.to_string(), filename = get_string(filename)))]
82 async fn lookup(
83 &self, dirid: &Self::Handle, filename: &filename3<'_>,
84 ) -> Result<Self::Handle, nfsstat3> {
85 let dir = self.data.lock().await.get(dirid).unwrap().file.clone();
86
87 if dir.is_document() {
88 info!("NOTDIR");
89 return Err(nfsstat3::NFS3ERR_NOTDIR);
90 }
91
92 if filename.as_ref() == [b'.'] {
94 info!(". == {dirid}");
95 return Ok(*dirid);
96 }
97
98 if filename.as_ref() == [b'.', b'.'] {
100 info!(".. == {}", dir.parent);
101 return Ok(dir.parent.into());
102 }
103
104 let children = self.lb.get_children(&dir.id).await.unwrap();
105 let file_name = get_string(filename);
106
107 for child in children {
108 if file_name == child.name {
109 info!("{}", child.id);
110 return Ok(child.id.into());
111 }
112 }
113
114 info!("NOENT");
115 Err(nfsstat3::NFS3ERR_NOENT)
116 }
117
118 #[instrument(skip(self), fields(id = id.to_string()))]
119 async fn getattr(&self, id: &Self::Handle) -> Result<fattr3, nfsstat3> {
120 let file = self.data.lock().await.get(id).unwrap().fattr.clone();
121 info!("fattr = {:?}", file);
122 Ok(file)
123 }
124
125 #[instrument(skip(self), fields(id = id.to_string(), offset, count))]
126 async fn read(
127 &self, id: &Self::Handle, offset: u64, count: u32,
128 ) -> Result<(Vec<u8>, bool), nfsstat3> {
129 let offset = offset as usize;
130 let count = count as usize;
131
132 let doc = self.lb.read_document(*id.as_uuid(), false).await.unwrap();
133
134 if offset >= doc.len() {
135 info!("[] EOF");
136 return Ok((vec![], true));
137 }
138
139 if offset + count >= doc.len() {
140 info!("|{}| EOF", doc[offset..].len());
141 return Ok((doc[offset..].to_vec(), true));
142 }
143
144 info!("|{}|", count);
145 return Ok((doc[offset..offset + count].to_vec(), false));
146 }
147
148 #[instrument(skip(self), fields(dirid = dirid.to_string(), start_after = cookie))]
149 async fn readdir(
150 &self, dirid: &Self::Handle, cookie: u64,
151 ) -> Result<impl nfs3_server::vfs::ReadDirIterator, nfsstat3> {
152 let iter = self.load_children(dirid, cookie).await;
153 Ok(Iterator { inner: iter })
154 }
155
156 #[instrument(skip(self), fields(dirid = dirid.to_string(), start_after = cookie))]
157 async fn readdirplus(
158 &self, dirid: &Self::Handle, cookie: u64,
159 ) -> Result<impl ReadDirPlusIterator<UuidFileHandle>, nfsstat3> {
160 let iter = self.load_children(dirid, cookie).await;
161 let data = self.data.lock().await;
162
163 let iter = iter
164 .map(move |file| {
165 let id: UuidFileHandle = file.id.into();
166 let name = file.name.as_bytes().to_vec().into();
167 let fattr = data.get(&id).map(|entry| entry.fattr.clone());
168 DirEntryPlus {
169 fileid: id.fileid(),
170 name,
171 cookie: id.fileid(),
172 name_attributes: fattr,
173 name_handle: Some(id),
174 }
175 })
176 .collect::<Vec<_>>()
177 .into_iter();
178 Ok(IteratorPlus { inner: iter })
179 }
180
181 async fn readlink(&self, _id: &Self::Handle) -> Result<nfspath3<'_>, nfsstat3> {
182 info!("readlink NOTSUPP");
183 Err(nfsstat3::NFS3ERR_NOTSUPP)
184 }
185}
186
187impl NfsFileSystem for Drive {
188 #[instrument(skip(self), fields(id = id.to_string()))]
189 async fn setattr(&self, id: &Self::Handle, setattr: sattr3) -> Result<fattr3, nfsstat3> {
190 let mut data = self.data.lock().await;
191 let now = FileEntry::now();
192 let entry = data.get_mut(id).unwrap();
193
194 if let Nfs3Option::Some(new) = setattr.size
195 && entry.fattr.size != new
196 {
197 let mut doc = self.lb.read_document(*id.as_uuid(), false).await.unwrap();
198 doc.resize(new as usize, 0);
199 self.lb.write_document(*id.as_uuid(), &doc).await.unwrap();
200 entry.fattr.mtime = now;
201 entry.fattr.ctime = now;
202 }
203
204 match setattr.atime {
205 set_atime::DONT_CHANGE => {}
206 set_atime::SET_TO_SERVER_TIME => {
207 entry.fattr.atime = now;
208 }
209 set_atime::SET_TO_CLIENT_TIME(ts) => {
210 entry.fattr.atime = ts;
211 }
212 }
213
214 match setattr.mtime {
215 set_mtime::DONT_CHANGE => {}
216 set_mtime::SET_TO_SERVER_TIME => {
217 entry.fattr.mtime = now;
218 entry.fattr.ctime = now;
219 }
220 set_mtime::SET_TO_CLIENT_TIME(ts) => {
221 entry.fattr.mtime = ts;
222 entry.fattr.ctime = ts;
223 }
224 }
225
226 if let Nfs3Option::Some(uid) = setattr.uid {
227 entry.fattr.uid = uid;
228 entry.fattr.ctime = now;
229 }
230
231 if let Nfs3Option::Some(gid) = setattr.gid {
232 entry.fattr.gid = gid;
233 entry.fattr.ctime = now;
234 }
235
236 if let Nfs3Option::Some(mode) = setattr.mode {
237 entry.fattr.mode = mode;
238 entry.fattr.ctime = now;
239 }
240
241 info!("fattr = {:?}", entry.fattr);
242 Ok(entry.fattr.clone())
243 }
244
245 #[instrument(skip(self), fields(id = id.to_string(), buffer = buffer.len()))]
246 async fn write(
247 &self, id: &Self::Handle, offset: u64, buffer: &[u8],
248 ) -> Result<fattr3, nfsstat3> {
249 let offset = offset as usize;
250
251 let mut data = self.data.lock().await;
252 let entry = data.get_mut(id).unwrap();
253
254 let mut doc = self.lb.read_document(*id.as_uuid(), false).await.unwrap();
255 let mut expanded = false;
256 if offset + buffer.len() > doc.len() {
257 doc.resize(offset + buffer.len(), 0);
258 doc[offset..].copy_from_slice(buffer);
259 expanded = true;
260 } else {
261 for (idx, datum) in buffer.iter().enumerate() {
262 doc[offset + idx] = *datum;
263 }
264 }
265 let doc_size = doc.len();
266 self.lb.write_document(*id.as_uuid(), &doc).await.unwrap();
267
268 entry.fattr.size = doc_size as u64;
269
270 info!("expanded={expanded}, fattr.size = {}", doc_size);
271
272 Ok(entry.fattr.clone())
273 }
274
275 #[instrument(skip(self), fields(dirid = dirid.to_string(), filename = get_string(filename)))]
277 async fn create(
278 &self, dirid: &Self::Handle, filename: &filename3<'_>, attr: sattr3,
279 ) -> Result<(Self::Handle, fattr3), nfsstat3> {
280 let filename = get_string(filename);
281 let file = self
282 .lb
283 .create_file(&filename, dirid.as_uuid(), FileType::Document)
284 .await
285 .unwrap();
286
287 let id = file.id.into();
288 let entry = FileEntry::from_file(file, 0);
289 self.data.lock().await.insert(id, entry);
290
291 let file = self.setattr(&id, attr).await.unwrap();
292
293 info!("({id}, size={})", file.size);
294 Ok((id, file))
295 }
296
297 #[instrument(skip(self), fields(dirid = dirid.to_string(), filename = get_string(filename)))]
298 async fn create_exclusive(
299 &self, dirid: &Self::Handle, filename: &filename3<'_>,
300 createverf: nfs3_server::nfs3_types::nfs3::createverf3,
301 ) -> Result<Self::Handle, nfsstat3> {
302 let filename = get_string(filename);
303 let children = self.lb.get_children(dirid.as_uuid()).await.unwrap();
304 for child in children {
305 if child.name == filename {
306 warn!("exists already");
307 return Err(nfsstat3::NFS3ERR_EXIST);
308 }
309 }
310
311 let file = self
312 .lb
313 .create_file(&filename, dirid.as_uuid(), FileType::Document)
314 .await
315 .unwrap();
316
317 let id = file.id.into();
318 let entry = FileEntry::from_file(file, 0);
319 info!("({id}, size={})", entry.fattr.size);
320 self.data.lock().await.insert(id, entry);
321
322 Ok(id)
323 }
324
325 #[instrument(skip(self), fields(dirid = dirid.to_string(), dirname = get_string(dirname)))]
326 async fn mkdir(
327 &self, dirid: &Self::Handle, dirname: &filename3<'_>,
328 ) -> Result<(Self::Handle, fattr3), nfsstat3> {
329 let filename = get_string(dirname);
330 let file = self
331 .lb
332 .create_file(&filename, dirid.as_uuid(), FileType::Folder)
333 .await
334 .unwrap();
335
336 let id = file.id.into();
337 let entry = FileEntry::from_file(file, 0);
338 let fattr = entry.fattr.clone();
339 self.data.lock().await.insert(id, entry);
340
341 info!("({id}, fattr={fattr:?})");
342 Ok((id, fattr))
343 }
344
345 #[instrument(skip(self), fields(dirid = dirid.to_string(), filename = get_string(filename)))]
349 async fn remove(&self, dirid: &Self::Handle, filename: &filename3<'_>) -> Result<(), nfsstat3> {
350 let mut data = self.data.lock().await;
351
352 let children = self.lb.get_children(dirid.as_uuid()).await.unwrap();
353 let file_name = get_string(filename);
354
355 for child in children {
356 if file_name == child.name {
357 info!("deleted");
358 let _ = self.lb.delete(&child.id).await; data.remove(&child.id.into());
360 return Ok(());
361 }
362 }
363
364 info!("NOENT");
365 Err(nfsstat3::NFS3ERR_NOENT)
366 }
367
368 #[instrument(skip(self), fields(from_dirid = from_dirid.to_string(), from_filename = get_string(from_filename), to_dirid = to_dirid.to_string(), to_filename = get_string(to_filename)))]
370 async fn rename<'a>(
371 &self, from_dirid: &Self::Handle, from_filename: &filename3<'a>, to_dirid: &Self::Handle,
372 to_filename: &filename3<'a>,
373 ) -> Result<(), nfsstat3> {
374 let mut data = self.data.lock().await;
375
376 let from_filename = get_string(from_filename);
377 let to_filename = get_string(to_filename);
378
379 let src_children = self.lb.get_children(from_dirid.as_uuid()).await.unwrap();
380
381 let mut from_id = None;
382 let mut to_id = None;
383 for child in src_children {
384 if child.name == from_filename {
385 from_id = Some(child.id);
386 }
387
388 if to_dirid == from_dirid && child.name == to_filename {
389 to_id = Some(child.id);
390 }
391 }
392
393 if to_dirid != from_dirid {
394 let dst_children = self.lb.get_children(to_dirid.as_uuid()).await.unwrap();
395 for child in dst_children {
396 if child.name == to_filename {
397 to_id = Some(child.id);
398 }
399 }
400 }
401
402 let from_id = from_id.unwrap();
403
404 match to_id {
405 Some(id) => {
407 info!("overwrite {from_id} -> {id}");
408 let from_doc = self.lb.read_document(from_id, false).await.unwrap();
409 info!("|{}|", from_doc.len());
410 let doc_len = from_doc.len() as u64;
411 self.lb.write_document(id, &from_doc).await.unwrap();
412 self.lb.delete(&from_id).await.unwrap();
413
414 let entry = data.get_mut(&id.into()).unwrap();
415 entry.fattr.size = doc_len;
416
417 data.remove(&from_id.into());
418 }
419
420 None => {
422 if from_dirid != to_dirid {
423 info!("move {} -> {}\t", from_id, to_dirid);
424 self.lb
425 .move_file(&from_id, to_dirid.as_uuid())
426 .await
427 .unwrap();
428 }
429
430 if from_filename != to_filename {
431 info!("rename {} -> {}\t", from_id, to_filename);
432 self.lb.rename_file(&from_id, &to_filename).await.unwrap();
433 }
434
435 let entry = data.get_mut(&from_id.into()).unwrap();
436
437 let file = self.lb.get_file_by_id(from_id).await.unwrap();
438 entry.file = file;
439
440 info!("ok");
441 }
442 }
443
444 Ok(())
445 }
446
447 async fn symlink<'a>(
448 &self, _dirid: &Self::Handle, _linkname: &filename3<'a>, _symlink: &nfspath3<'a>,
449 _attr: &sattr3,
450 ) -> Result<(Self::Handle, fattr3), nfsstat3> {
451 info!("symlink NOTSUPP");
452 Err(nfsstat3::NFS3ERR_NOTSUPP)
453 }
454}
455
456pub struct Iterator<I>
457where
458 I: StdIterator<Item = File> + Send + Sync + 'static,
459{
460 inner: I,
461}
462
463impl<I> ReadDirIterator for Iterator<I>
464where
465 I: StdIterator<Item = File> + Send + Sync + 'static,
466{
467 async fn next(&mut self) -> nfs3_server::vfs::NextResult<DirEntry> {
468 match self.inner.next() {
469 Some(entry) => nfs3_server::vfs::NextResult::Ok(DirEntry {
470 fileid: file_id(&entry),
471 name: entry.name.as_bytes().to_vec().into(),
472 cookie: 0,
473 }),
474 None => nfs3_server::vfs::NextResult::Eof,
475 }
476 }
477}
478
479pub struct IteratorPlus<I>
480where
481 I: StdIterator<Item = DirEntryPlus<UuidFileHandle>> + Send + Sync + 'static,
482{
483 inner: I,
484}
485
486impl<I> ReadDirPlusIterator<UuidFileHandle> for IteratorPlus<I>
487where
488 I: StdIterator<Item = DirEntryPlus<UuidFileHandle>> + Send + Sync + 'static,
489{
490 async fn next(&mut self) -> nfs3_server::vfs::NextResult<DirEntryPlus<UuidFileHandle>> {
491 match self.inner.next() {
492 Some(entry) => nfs3_server::vfs::NextResult::Ok(entry),
493 None => nfs3_server::vfs::NextResult::Eof,
494 }
495 }
496}