extern crate game_kernel_utils;
use std::cell::{Ref, RefCell};
use std::collections::HashMap;
use std::io::{Read, Seek, Write};
use std::ops::{Deref, DerefMut};
use std::sync::{Arc, RwLock, RwLockReadGuard};
use game_kernel_utils::{MapAbstract, MapMap};
mod path;
pub trait OpenVFile: OpenVROFile + Write {}
pub trait OpenVROFile: Read + Seek {}
trait VFile: VROFile {
fn open_rw(&self) -> Box<dyn OpenVROFile>;
}
trait VROFile: AsVROFile {
fn open(&mut self) -> Box<dyn OpenVROFile>;
}
trait AsVROFile {
fn as_ro(&self) -> &VROFile;
}
impl<T: VROFile> AsVROFile for T {
fn as_ro(&self) -> &VROFile {
self
}
}
enum FsObjTypes {
file(Box<VFile>),
ro_file(Box<VROFile>),
directory(Directory),
}
#[derive(Clone)]
pub enum Permissions {
Read,
ReadWrite,
}
pub struct FsObject {
obj_type: FsObjTypes,
name: String,
acl: HashMap<u32, Permissions>,
}
impl FsObject {
pub fn get_acl(&self) -> &HashMap<u32, Permissions> {
&self.acl
}
pub fn get_permissions(&self, user: &u32) -> Option<Permissions> {
self.get_acl().get(user).map(|t| (*t).clone())
}
pub fn can_read(&self, user: &u32) -> bool {
self.get_permissions(user).is_some()
}
pub fn can_write(&self, user: &u32) -> bool {
if let Some(Permissions::ReadWrite) = self.get_permissions(user) {
true
} else {
false
}
}
}
pub struct FileMeta {
name: String,
ro: bool,
acl: HashMap<u32, Permissions>,
}
pub struct Directory {
contents: HashMap<String, Arc<FsObject>>,
driver: Option<Box<dyn FsDriver>>,
driver_path: Option<path::Path>,
read_only: bool,
}
impl Directory {
pub fn new() -> Self {
Self {
contents: HashMap::new(),
driver: None,
driver_path: None,
read_only: false,
}
}
pub fn get_contents(&self) -> HashMap<String, Arc<FsObject>> {
self.contents.clone()
}
pub fn get_contents_mut(&mut self) -> HashMap<String, Arc<FsObject>> {
self.contents.clone()
}
pub fn put_object(&mut self, obj: FsObject) -> Result<(), ()> {
if self.read_only {
return Err(());
}
if let (Some(ref mut driver), Some(ref d_path)) = (&mut self.driver, &self.driver_path) {
driver.put_object(&d_path, obj)
} else {
self.contents.insert(obj.name.clone(), Arc::new(obj));
Ok(())
}
}
pub fn new_file(&mut self, meta: FileMeta) -> Result<&FsObject, ()> {
if self.read_only || self.driver.is_none() {
return Err(());
}
if let (Some(driver), Some(path)) = (&mut self.driver, &self.driver_path) {
driver.put_new_object(meta, path)
} else {
Err(())
}
}
}
pub trait FsDriver {
fn get_root(&self) -> Directory;
fn put_object(&mut self, path: &path::Path, obj: FsObject) -> Result<(), ()>;
fn put_new_object<'a>(
&'a mut self,
meta: FileMeta,
path: &path::Path,
) -> Result<&'a FsObject, ()>;
}
pub struct Vfs {
root: Arc<FsObject>,
}
impl Vfs {
pub fn get_object_mut(&mut self, path: &path::Path) -> Result<Arc<FsObject>, ()> {
let mut curr_obj = self.root.clone();
for obj_name in path.obj_name_iter() {
match (curr_obj.obj_type) {
FsObjTypes::directory(ref dir) => {
let contents = dir.get_contents();
if let Some(obj) = contents.get(obj_name) {
curr_obj = obj.clone();
} else {
return Err(());
}
}
_ => return Err(()),
}
}
Ok(curr_obj)
}
pub fn get_object(&self, path: &path::Path) -> Result<Arc<FsObject>, ()> {
let mut curr_obj = self.root.clone();
for obj_name in path.obj_name_iter() {
match (curr_obj.obj_type) {
FsObjTypes::directory(ref dir) => {
let contents = dir.get_contents();
if let Some(obj) = contents.get(obj_name) {
curr_obj = obj.clone();
} else {
return Err(());
}
}
_ => return Err(()),
}
}
Ok(curr_obj)
}
pub fn put_object(&mut self, path: path::Path) -> Result<(), ()> {
let (path, name) = path.split_at_base();
let mut curr_obj = self.root.clone();
for obj_name in path.obj_name_iter() {
match (curr_obj.obj_type) {
FsObjTypes::directory(ref dir) => {
let contents = dir.get_contents();
if let Some(obj) = contents.get(obj_name) {
curr_obj = obj.clone();
} else {
return Err(());
}
}
_ => return Err(()),
}
}
Ok(())
}
}
pub fn mount<T: FsDriver>(vfs: &mut Vfs, driver: T, path: path::Path) -> Result<(), ()> {
let driver_tobject = Box::new(driver);
let (base, filename) = path.split_at_base();
let mut b = vfs.get_object_mut(&base)?;
let dir = match (&mut Arc::get_mut(&mut b).ok_or(())?.obj_type) {
FsObjTypes::directory(dir) => Ok(dir),
_ => Err(()),
}?;
dir.put_object(FsObject {
obj_type: FsObjTypes::directory(driver_tobject.get_root()),
name: filename,
acl: HashMap::new(),
});
Ok(())
}
pub struct VfsHanfle<'a> {
user: u32,
vfs: &'a Vfs,
}
impl<'a> VfsHanfle<'a> {
pub fn new(user: u32, vfs: &'a mut Vfs) -> Self {
Self { user, vfs }
}
fn check_permission<T>(&self, obj: T, perm: Permissions) -> Result<T, ()>
where
T: Deref<Target = FsObject>,
{
match ((obj.can_read(&self.user), obj.can_write(&self.user), perm)) {
(true, _, Permissions::Read) => Ok(obj),
(true, true, Permissions::ReadWrite) => Ok(obj),
_ => Err(()),
}
}
fn check_permission_mut<T>(&self, obj: T, perm: Permissions) -> Result<T, ()>
where
T: DerefMut<Target = FsObject>,
{
match ((obj.can_read(&self.user), obj.can_write(&self.user), perm)) {
(true, _, Permissions::Read) => Ok(obj),
(true, true, Permissions::ReadWrite) => Ok(obj),
_ => Err(()),
}
}
fn own_acl(&self) -> HashMap<u32, Permissions> {
let mut acl = HashMap::new();
acl.insert(self.user, Permissions::ReadWrite);
acl
}
}