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
113
114
115
116
117
118
119
120
121
use std::collections::HashMap;
use std::sync::{Arc, Mutex};
use std::io::{Read, Write, Seek, SeekFrom};
use std::path::PathBuf;

pub type Inode = u64;

// future implementation
//struct Inode {
    //number: u64,
    //size: u64,
    //permissions: Permissions,
    //user_id: u32,
    //group_id: u32,
    //ctime: SystemTime,
    //mtime: SystemTime,
    //atime: SystemTime,
    // etc.
//}

pub type FileDescriptor = i32;

#[derive(Debug)]
pub struct File {
    pub inode: Inode,
    pub data: Mutex<Vec<u8>>,
    pub path: PathBuf
}

pub struct OpenFile {
    pub file: Arc<File>,
    pub position: u64,
}

impl Read for OpenFile {
    fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
        let file_data = &self.file.data.lock().unwrap();
        let bytes_to_read = std::cmp::min(buf.len(), (file_data.len() - self.position as usize));
        buf[..bytes_to_read].copy_from_slice(&file_data[self.position as usize..(self.position + bytes_to_read as u64) as usize]);
        self.position += bytes_to_read as u64;
        Ok(bytes_to_read)
    }
}

impl Write for OpenFile {
    fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
         let mut file_data = self.file.data.lock().unwrap();
        let new_size = std::cmp::max(file_data.len(), self.position as usize + buf.len());
        file_data.resize(new_size, 0);
        file_data[self.position as usize..self.position as usize + buf.len()]
            .copy_from_slice(buf);
        self.position += buf.len() as u64;
        Ok(buf.len())
    }

    fn flush(&mut self) -> std::io::Result<()> {
        Ok(())
    }
}

pub struct FileSystem {
    pub files: HashMap<Inode, Arc<File>>,
    pub inodes: Inode,
}

impl FileSystem {
    pub fn new() -> Self {
        Self {
            files: HashMap::new(),
            inodes: 1,
        }
    }

    pub fn lookup_inode(&mut self, path: &PathBuf) -> Option<Inode> {
        let inode = self.files
            .iter()
            .find_map(|(&inode, file)| if file.path == *path { Some(inode) } else { None });
        if inode == None {
            return Some(self.create_file(Vec::new()))
        } else {
            None
        }
    }

    pub fn create_file(&mut self, raw_data: Vec<u8>) -> Inode {
        let inode = self.inodes;
        let data = Mutex::new(raw_data);
        let mut path = PathBuf::new();
        let file = File { inode, data, path};
        self.files.insert(inode, Arc::new(file));
        self.inodes += 1;
        inode
    }
}

// bc st:fs::File is not compiled wth wasm32-unknown-unknown
impl File {
    #[cfg(target_arch = "wasm32")]
        pub fn open(_path: &String) -> io::Result<File> {
            let inode;
            let path_buf = PathBuf::from(_path);

            {
                let fs = unsafe { &mut *FILESYSTEM.as_ref().unwrap().get() };
                inode = fs.lookup_inode(&path_buf).expect("Failed to find the inode for the given path");
            }


            let fd;
            {
                let process = unsafe { &mut *PROCESS.as_ref().unwrap().get() };
                fd = process.open(unsafe { &mut *FILESYSTEM.as_ref().unwrap().get() }, inode).expect("Failed to open the file");
            }

            let data = Mutex::new(Vec::new());
            let file = File { data: data, inode: inode, path: path_buf };

            Ok(file)
        }

}