dav_server/
memfs.rs

1//! Simple in-memory filesystem.
2//!
3//! This implementation has state, so if you create a
4//! new instance in a handler(), it will be empty every time.
5//!
6//! This means you have to create the instance once, using `MemFs::new`, store
7//! it in your handler struct, and clone() it every time you pass
8//! it to the DavHandler. As a MemFs struct is just a handle, cloning is cheap.
9use 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/// Ephemeral in-memory filesystem.
28#[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    /// Create a new "memfs" filesystem.
73    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            // source must exist.
233            let snode_id = tree.lookup(from.as_bytes())?;
234
235            // make sure destination exists, create if needed.
236            {
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            // copy.
244            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                    // the below map was added to signify if the remove succeeded or
281                    // failed. however it seems that removing non-existant properties
282                    // always succeed, so just return success.
283                    //  .map(|_| StatusCode::OK).unwrap_or(StatusCode::NOT_FOUND)
284                    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
322// small helper.
323fn propkey(ns: &Option<String>, name: &str) -> String {
324    ns.to_owned().as_ref().unwrap_or(&"".to_string()).clone() + name
325}
326
327// small helper.
328fn 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    // helper to create MemFsDirEntry from a node.
493    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    // pop the last segment off the path, do a lookup, then
582    // check if the result is a directory.
583    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
597// helper
598fn 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}