1use std::collections::HashMap;
10use std::io::{Error, ErrorKind, SeekFrom};
11use std::sync::{Arc, Mutex};
12use std::time::SystemTime;
13
14use bytes::{Buf, Bytes};
15use futures_util::{
16 StreamExt, future,
17 future::{BoxFuture, FutureExt},
18};
19use http::StatusCode;
20
21use crate::davpath::DavPath;
22use crate::fs::*;
23use crate::tree;
24
25type Tree = tree::Tree<Vec<u8>, MemFsNode>;
26
27#[derive(Debug)]
29pub struct MemFs {
30 tree: Arc<Mutex<Tree>>,
31}
32
33#[derive(Debug, Clone)]
34enum MemFsNode {
35 Dir(MemFsDirNode),
36 File(MemFsFileNode),
37}
38
39#[derive(Debug, Clone)]
40struct MemFsDirNode {
41 props: HashMap<String, DavProp>,
42 mtime: SystemTime,
43 crtime: SystemTime,
44}
45
46#[derive(Debug, Clone)]
47struct MemFsFileNode {
48 props: HashMap<String, DavProp>,
49 mtime: SystemTime,
50 crtime: SystemTime,
51 data: Vec<u8>,
52}
53
54#[derive(Debug, Clone)]
55struct MemFsDirEntry {
56 mtime: SystemTime,
57 crtime: SystemTime,
58 is_dir: bool,
59 name: Vec<u8>,
60 size: u64,
61}
62
63#[derive(Debug)]
64struct MemFsFile {
65 tree: Arc<Mutex<Tree>>,
66 node_id: u64,
67 pos: usize,
68 append: bool,
69}
70
71impl MemFs {
72 pub fn new() -> Box<MemFs> {
74 let root = MemFsNode::new_dir();
75 Box::new(MemFs {
76 tree: Arc::new(Mutex::new(Tree::new(root))),
77 })
78 }
79
80 fn do_open(
81 &self,
82 tree: &mut Tree,
83 path: &[u8],
84 options: OpenOptions,
85 ) -> FsResult<Box<dyn DavFile>> {
86 let node_id = match tree.lookup(path) {
87 Ok(n) => {
88 if options.create_new {
89 return Err(FsError::Exists);
90 }
91 n
92 }
93 Err(FsError::NotFound) => {
94 if !options.create {
95 return Err(FsError::NotFound);
96 }
97 let parent_id = tree.lookup_parent(path)?;
98 tree.add_child(parent_id, file_name(path), MemFsNode::new_file(), true)?
99 }
100 Err(e) => return Err(e),
101 };
102 let node = tree.get_node_mut(node_id).unwrap();
103 if node.is_dir() {
104 return Err(FsError::Forbidden);
105 }
106 if options.truncate {
107 node.as_file_mut()?.data.truncate(0);
108 node.update_mtime(SystemTime::now());
109 }
110 Ok(Box::new(MemFsFile {
111 tree: self.tree.clone(),
112 node_id,
113 pos: 0,
114 append: options.append,
115 }))
116 }
117}
118
119impl Clone for MemFs {
120 fn clone(&self) -> Self {
121 MemFs {
122 tree: Arc::clone(&self.tree),
123 }
124 }
125}
126
127impl DavFileSystem for MemFs {
128 fn metadata<'a>(&'a self, path: &'a DavPath) -> FsFuture<'a, Box<dyn DavMetaData>> {
129 async move {
130 let tree = &*self.tree.lock().unwrap();
131 let node_id = tree.lookup(path.as_bytes())?;
132 let meta = tree.get_node(node_id)?.as_dirent(path.as_bytes());
133 Ok(Box::new(meta) as Box<dyn DavMetaData>)
134 }
135 .boxed()
136 }
137
138 fn read_dir<'a>(
139 &'a self,
140 path: &'a DavPath,
141 _meta: ReadDirMeta,
142 ) -> FsFuture<'a, FsStream<Box<dyn DavDirEntry>>> {
143 async move {
144 let tree = &*self.tree.lock().unwrap();
145 let node_id = tree.lookup(path.as_bytes())?;
146 if !tree.get_node(node_id)?.is_dir() {
147 return Err(FsError::Forbidden);
148 }
149 let mut v: Vec<Box<dyn DavDirEntry>> = Vec::new();
150 for (name, dnode_id) in tree.get_children(node_id)? {
151 if let Ok(node) = tree.get_node(dnode_id) {
152 v.push(Box::new(node.as_dirent(&name)));
153 }
154 }
155 let strm = futures_util::stream::iter(v).map(Ok);
156 Ok(Box::pin(strm) as FsStream<Box<dyn DavDirEntry>>)
157 }
158 .boxed()
159 }
160
161 fn open<'a>(
162 &'a self,
163 path: &'a DavPath,
164 options: OpenOptions,
165 ) -> FsFuture<'a, Box<dyn DavFile>> {
166 async move {
167 let tree = &mut *self.tree.lock().unwrap();
168 self.do_open(tree, path.as_bytes(), options)
169 }
170 .boxed()
171 }
172
173 fn create_dir<'a>(&'a self, path: &'a DavPath) -> FsFuture<'a, ()> {
174 async move {
175 trace!("FS: create_dir {path:?}");
176 let tree = &mut *self.tree.lock().unwrap();
177 let path = path.as_bytes();
178 let parent_id = tree.lookup_parent(path)?;
179 tree.add_child(parent_id, file_name(path), MemFsNode::new_dir(), false)?;
180 tree.get_node_mut(parent_id)?
181 .update_mtime(SystemTime::now());
182 Ok(())
183 }
184 .boxed()
185 }
186
187 fn remove_file<'a>(&'a self, path: &'a DavPath) -> FsFuture<'a, ()> {
188 async move {
189 let tree = &mut *self.tree.lock().unwrap();
190 let parent_id = tree.lookup_parent(path.as_bytes())?;
191 let node_id = tree.lookup(path.as_bytes())?;
192 tree.delete_node(node_id)?;
193 tree.get_node_mut(parent_id)?
194 .update_mtime(SystemTime::now());
195 Ok(())
196 }
197 .boxed()
198 }
199
200 fn remove_dir<'a>(&'a self, path: &'a DavPath) -> FsFuture<'a, ()> {
201 async move {
202 let tree = &mut *self.tree.lock().unwrap();
203 let parent_id = tree.lookup_parent(path.as_bytes())?;
204 let node_id = tree.lookup(path.as_bytes())?;
205 tree.delete_node(node_id)?;
206 tree.get_node_mut(parent_id)?
207 .update_mtime(SystemTime::now());
208 Ok(())
209 }
210 .boxed()
211 }
212
213 fn rename<'a>(&'a self, from: &'a DavPath, to: &'a DavPath) -> FsFuture<'a, ()> {
214 async move {
215 let tree = &mut *self.tree.lock().unwrap();
216 let node_id = tree.lookup(from.as_bytes())?;
217 let parent_id = tree.lookup_parent(from.as_bytes())?;
218 let dst_id = tree.lookup_parent(to.as_bytes())?;
219 tree.move_node(node_id, dst_id, file_name(to.as_bytes()), true)?;
220 tree.get_node_mut(parent_id)?
221 .update_mtime(SystemTime::now());
222 tree.get_node_mut(dst_id)?.update_mtime(SystemTime::now());
223 Ok(())
224 }
225 .boxed()
226 }
227
228 fn copy<'a>(&'a self, from: &'a DavPath, to: &'a DavPath) -> FsFuture<'a, ()> {
229 async move {
230 let tree = &mut *self.tree.lock().unwrap();
231
232 let snode_id = tree.lookup(from.as_bytes())?;
234
235 {
237 let mut oo = OpenOptions::write();
238 oo.create = true;
239 self.do_open(tree, to.as_bytes(), oo)?;
240 }
241 let dnode_id = tree.lookup(to.as_bytes())?;
242
243 let mut data = (*tree.get_node_mut(snode_id)?).clone();
245 match data {
246 MemFsNode::Dir(ref mut d) => d.crtime = SystemTime::now(),
247 MemFsNode::File(ref mut f) => f.crtime = SystemTime::now(),
248 }
249 *tree.get_node_mut(dnode_id)? = data;
250
251 Ok(())
252 }
253 .boxed()
254 }
255
256 fn have_props<'a>(&'a self, _path: &'a DavPath) -> BoxFuture<'a, bool> {
257 future::ready(true).boxed()
258 }
259
260 fn patch_props<'a>(
261 &'a self,
262 path: &'a DavPath,
263 mut patch: Vec<(bool, DavProp)>,
264 ) -> FsFuture<'a, Vec<(StatusCode, DavProp)>> {
265 async move {
266 let tree = &mut *self.tree.lock().unwrap();
267 let node_id = tree.lookup(path.as_bytes())?;
268 let node = tree.get_node_mut(node_id)?;
269 let props = node.get_props_mut();
270
271 let mut res = Vec::new();
272
273 for (set, p) in patch.drain(..) {
274 let prop = cloneprop(&p);
275 let status = if set {
276 props.insert(propkey(&p.namespace, &p.name), p);
277 StatusCode::OK
278 } else {
279 props.remove(&propkey(&p.namespace, &p.name));
280 StatusCode::OK
285 };
286 res.push((status, prop));
287 }
288 Ok(res)
289 }
290 .boxed()
291 }
292
293 fn get_props<'a>(&'a self, path: &'a DavPath, do_content: bool) -> FsFuture<'a, Vec<DavProp>> {
294 async move {
295 let tree = &mut *self.tree.lock().unwrap();
296 let node_id = tree.lookup(path.as_bytes())?;
297 let node = tree.get_node(node_id)?;
298 let mut res = Vec::new();
299 for p in node.get_props().values() {
300 res.push(if do_content { p.clone() } else { cloneprop(p) });
301 }
302 Ok(res)
303 }
304 .boxed()
305 }
306
307 fn get_prop<'a>(&'a self, path: &'a DavPath, prop: DavProp) -> FsFuture<'a, Vec<u8>> {
308 async move {
309 let tree = &mut *self.tree.lock().unwrap();
310 let node_id = tree.lookup(path.as_bytes())?;
311 let node = tree.get_node(node_id)?;
312 let p = node
313 .get_props()
314 .get(&propkey(&prop.namespace, &prop.name))
315 .ok_or(FsError::NotFound)?;
316 p.xml.clone().ok_or(FsError::NotFound)
317 }
318 .boxed()
319 }
320}
321
322fn propkey(ns: &Option<String>, name: &str) -> String {
324 ns.to_owned().as_ref().unwrap_or(&"".to_string()).clone() + name
325}
326
327fn cloneprop(p: &DavProp) -> DavProp {
329 DavProp {
330 name: p.name.clone(),
331 namespace: p.namespace.clone(),
332 prefix: p.prefix.clone(),
333 xml: None,
334 }
335}
336
337impl DavDirEntry for MemFsDirEntry {
338 fn metadata(&'_ self) -> FsFuture<'_, Box<dyn DavMetaData>> {
339 let meta = (*self).clone();
340 Box::pin(future::ok(Box::new(meta) as Box<dyn DavMetaData>))
341 }
342
343 fn name(&self) -> Vec<u8> {
344 self.name.clone()
345 }
346}
347
348impl DavFile for MemFsFile {
349 fn metadata(&'_ mut self) -> FsFuture<'_, Box<dyn DavMetaData>> {
350 async move {
351 let tree = &*self.tree.lock().unwrap();
352 let node = tree.get_node(self.node_id)?;
353 let meta = node.as_dirent(b"");
354 Ok(Box::new(meta) as Box<dyn DavMetaData>)
355 }
356 .boxed()
357 }
358
359 fn read_bytes(&'_ mut self, count: usize) -> FsFuture<'_, Bytes> {
360 async move {
361 let tree = &*self.tree.lock().unwrap();
362 let node = tree.get_node(self.node_id)?;
363 let file = node.as_file()?;
364 let curlen = file.data.len();
365 let mut start = self.pos;
366 let mut end = self.pos + count;
367 if start > curlen {
368 start = curlen
369 }
370 if end > curlen {
371 end = curlen
372 }
373 let cnt = end - start;
374 self.pos += cnt;
375 Ok(Bytes::copy_from_slice(&file.data[start..end]))
376 }
377 .boxed()
378 }
379
380 fn write_bytes(&'_ mut self, buf: Bytes) -> FsFuture<'_, ()> {
381 async move {
382 let tree = &mut *self.tree.lock().unwrap();
383 let node = tree.get_node_mut(self.node_id)?;
384 let file = node.as_file_mut()?;
385 if self.append {
386 self.pos = file.data.len();
387 }
388 let end = self.pos + buf.len();
389 if end > file.data.len() {
390 file.data.resize(end, 0);
391 }
392 file.data[self.pos..end].copy_from_slice(&buf);
393 self.pos = end;
394 Ok(())
395 }
396 .boxed()
397 }
398
399 fn write_buf(&'_ mut self, mut buf: Box<dyn Buf + Send>) -> FsFuture<'_, ()> {
400 async move {
401 let tree = &mut *self.tree.lock().unwrap();
402 let node = tree.get_node_mut(self.node_id)?;
403 let file = node.as_file_mut()?;
404 if self.append {
405 self.pos = file.data.len();
406 }
407 let end = self.pos + buf.remaining();
408 if end > file.data.len() {
409 file.data.resize(end, 0);
410 }
411 while buf.has_remaining() {
412 let b = buf.chunk();
413 let len = b.len();
414 file.data[self.pos..self.pos + len].copy_from_slice(b);
415 buf.advance(len);
416 self.pos += len;
417 }
418 Ok(())
419 }
420 .boxed()
421 }
422
423 fn flush(&'_ mut self) -> FsFuture<'_, ()> {
424 future::ok(()).boxed()
425 }
426
427 fn seek(&'_ mut self, pos: SeekFrom) -> FsFuture<'_, u64> {
428 async move {
429 let (start, offset): (u64, i64) = match pos {
430 SeekFrom::Start(npos) => {
431 self.pos = npos as usize;
432 return Ok(npos);
433 }
434 SeekFrom::Current(npos) => (self.pos as u64, npos),
435 SeekFrom::End(npos) => {
436 let tree = &*self.tree.lock().unwrap();
437 let node = tree.get_node(self.node_id)?;
438 let curlen = node.as_file()?.data.len() as u64;
439 (curlen, npos)
440 }
441 };
442 if offset < 0 {
443 if -offset as u64 > start {
444 return Err(Error::new(ErrorKind::InvalidInput, "invalid seek").into());
445 }
446 self.pos = (start - (-offset as u64)) as usize;
447 } else {
448 self.pos = (start + offset as u64) as usize;
449 }
450 Ok(self.pos as u64)
451 }
452 .boxed()
453 }
454}
455
456impl DavMetaData for MemFsDirEntry {
457 fn len(&self) -> u64 {
458 self.size
459 }
460
461 fn created(&self) -> FsResult<SystemTime> {
462 Ok(self.crtime)
463 }
464
465 fn modified(&self) -> FsResult<SystemTime> {
466 Ok(self.mtime)
467 }
468
469 fn is_dir(&self) -> bool {
470 self.is_dir
471 }
472}
473
474impl MemFsNode {
475 fn new_dir() -> MemFsNode {
476 MemFsNode::Dir(MemFsDirNode {
477 crtime: SystemTime::now(),
478 mtime: SystemTime::now(),
479 props: HashMap::new(),
480 })
481 }
482
483 fn new_file() -> MemFsNode {
484 MemFsNode::File(MemFsFileNode {
485 crtime: SystemTime::now(),
486 mtime: SystemTime::now(),
487 props: HashMap::new(),
488 data: Vec::new(),
489 })
490 }
491
492 fn as_dirent(&self, name: &[u8]) -> MemFsDirEntry {
494 let (is_dir, size, mtime, crtime) = match *self {
495 MemFsNode::File(ref file) => (false, file.data.len() as u64, file.mtime, file.crtime),
496 MemFsNode::Dir(ref dir) => (true, 0, dir.mtime, dir.crtime),
497 };
498 MemFsDirEntry {
499 name: name.to_vec(),
500 mtime,
501 crtime,
502 is_dir,
503 size,
504 }
505 }
506
507 fn update_mtime(&mut self, tm: std::time::SystemTime) {
508 match *self {
509 MemFsNode::Dir(ref mut d) => d.mtime = tm,
510 MemFsNode::File(ref mut f) => f.mtime = tm,
511 }
512 }
513
514 fn is_dir(&self) -> bool {
515 match *self {
516 MemFsNode::Dir(_) => true,
517 MemFsNode::File(_) => false,
518 }
519 }
520
521 fn as_file(&self) -> FsResult<&MemFsFileNode> {
522 match *self {
523 MemFsNode::File(ref n) => Ok(n),
524 _ => Err(FsError::Forbidden),
525 }
526 }
527
528 fn as_file_mut(&mut self) -> FsResult<&mut MemFsFileNode> {
529 match *self {
530 MemFsNode::File(ref mut n) => Ok(n),
531 _ => Err(FsError::Forbidden),
532 }
533 }
534
535 fn get_props(&self) -> &HashMap<String, DavProp> {
536 match *self {
537 MemFsNode::File(ref n) => &n.props,
538 MemFsNode::Dir(ref d) => &d.props,
539 }
540 }
541
542 fn get_props_mut(&mut self) -> &mut HashMap<String, DavProp> {
543 match *self {
544 MemFsNode::File(ref mut n) => &mut n.props,
545 MemFsNode::Dir(ref mut d) => &mut d.props,
546 }
547 }
548}
549
550trait TreeExt {
551 fn lookup_segs(&self, segs: Vec<&[u8]>) -> FsResult<u64>;
552 fn lookup(&self, path: &[u8]) -> FsResult<u64>;
553 fn lookup_parent(&self, path: &[u8]) -> FsResult<u64>;
554}
555
556impl TreeExt for Tree {
557 fn lookup_segs(&self, segs: Vec<&[u8]>) -> FsResult<u64> {
558 let mut node_id = tree::ROOT_ID;
559 let mut is_dir = true;
560 for seg in segs.into_iter() {
561 if !is_dir {
562 return Err(FsError::Forbidden);
563 }
564 if self.get_node(node_id)?.is_dir() {
565 node_id = self.get_child(node_id, seg)?;
566 } else {
567 is_dir = false;
568 }
569 }
570 Ok(node_id)
571 }
572
573 fn lookup(&self, path: &[u8]) -> FsResult<u64> {
574 self.lookup_segs(
575 path.split(|&c| c == b'/')
576 .filter(|s| !s.is_empty())
577 .collect(),
578 )
579 }
580
581 fn lookup_parent(&self, path: &[u8]) -> FsResult<u64> {
584 let mut segs: Vec<&[u8]> = path
585 .split(|&c| c == b'/')
586 .filter(|s| !s.is_empty())
587 .collect();
588 segs.pop();
589 let node_id = self.lookup_segs(segs)?;
590 if !self.get_node(node_id)?.is_dir() {
591 return Err(FsError::Forbidden);
592 }
593 Ok(node_id)
594 }
595}
596
597fn file_name(path: &[u8]) -> Vec<u8> {
599 path.split(|&c| c == b'/')
600 .filter(|s| !s.is_empty())
601 .next_back()
602 .unwrap_or(b"")
603 .to_vec()
604}