1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
use crate::{OpenOptions, VFile, VMetadata, Vfs, VfsResult};
use async_std::{fs, path::PathBuf};
use async_trait::async_trait;

pub struct OsFs {
    root: PathBuf,
}

struct VOsMetadata {
    path: PathBuf,
    is_file: bool,
    len: u64,
}

impl OsFs {
    pub fn new(root: &str) -> Self {
        OsFs {
            root: PathBuf::from(root),
        }
    }

    fn get_path(&self, path: &str) -> PathBuf {
        let p = if path.starts_with('/') {
            &path[1..]
        } else {
            path
        };
        self.root.join(p)
    }
}

impl VMetadata for VOsMetadata {
    fn name(&self) -> &str {
        self.path.to_str().unwrap()
    }

    fn is_dir(&self) -> bool {
        !self.is_file
    }

    fn is_file(&self) -> bool {
        self.is_file
    }

    fn len(&self) -> u64 {
        self.len
    }
}

#[async_trait]
impl Vfs for OsFs {
    async fn exists(&self, path: &str) -> VfsResult<bool> {
        Ok(self.get_path(path).exists().await)
    }

    async fn metadata(&self, path: &str) -> VfsResult<Box<dyn VMetadata>> {
        let path = self.get_path(path);
        let metadata = path.metadata().await?;
        let vmetadata = if metadata.is_dir() {
            VOsMetadata {
                is_file: false,
                len: 0,
                path,
            }
        } else {
            VOsMetadata {
                is_file: true,
                len: metadata.len(),
                path,
            }
        };
        Ok(Box::new(vmetadata))
    }

    async fn mkdir(&self, path: &str) -> VfsResult<()> {
        Ok(fs::create_dir(self.get_path(path)).await?)
    }

    async fn mv(&self, from: &str, to: &str) -> VfsResult<()> {
        Ok(fs::rename(from, to).await?)
    }

    async fn open(&self, path: &str, options: OpenOptions) -> VfsResult<Box<dyn VFile>> {
        let file = fs::OpenOptions::new()
            .read(options.has_read())
            .write(options.has_write())
            .create(options.has_create())
            .append(options.has_append())
            .truncate(options.has_truncate())
            .open(self.get_path(path))
            .await?;
        Ok(Box::new(file))
    }

    async fn read_dir(
        &self,
        path: &str,
        skip_token: Option<String>,
    ) -> VfsResult<(Vec<Box<dyn VMetadata>>, Option<String>)> {
        todo!()
    }

    async fn rm(&self, path: &str) -> VfsResult<()> {
        let path = self.get_path(path);
        let metadata = path.metadata().await?;
        if metadata.is_dir() {
            Ok(fs::remove_dir(path).await?)
        } else {
            Ok(fs::remove_file(path).await?)
        }
    }
}