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