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