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