use std::collections::HashMap;
use std::sync::{Arc, Mutex};
use std::io::{Read, Write, Seek, SeekFrom};
use std::path::PathBuf;
pub type Inode = u64;
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
}
}
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)
}
}