From 3837b2606fbd1fce41d42d9677de90d8e6729cc0 Mon Sep 17 00:00:00 2001
From: Jeremy Soller <jackpot51@gmail.com>
Date: Thu, 8 Sep 2016 20:06:33 -0600
Subject: [PATCH] Connect schemes so that they can be used

---
 scheme/debug.rs |  8 ++---
 scheme/fd.rs    |  5 ----
 scheme/mod.rs   | 77 ++++++++++++++++++++++++++++++++++++++++++-------
 syscall/fs.rs   | 50 ++++++++++++++++++++++----------
 syscall/mod.rs  |  2 ++
 5 files changed, 106 insertions(+), 36 deletions(-)
 delete mode 100644 scheme/fd.rs

diff --git a/scheme/debug.rs b/scheme/debug.rs
index 57675079..0555b091 100644
--- a/scheme/debug.rs
+++ b/scheme/debug.rs
@@ -1,7 +1,7 @@
 use core::str;
 
 use syscall::Result;
-use super::{Scheme, Fd};
+use super::Scheme;
 
 pub struct DebugScheme;
 
@@ -14,21 +14,21 @@ impl Scheme for DebugScheme {
     /// Read the file `number` into the `buffer`
     ///
     /// Returns the number of bytes read
-    fn read(&mut self, _file: Fd, _buffer: &mut [u8]) -> Result<usize> {
+    fn read(&mut self, _file: usize, _buffer: &mut [u8]) -> Result<usize> {
         Ok(0)
     }
 
     /// Write the `buffer` to the `file`
     ///
     /// Returns the number of bytes written
-    fn write(&mut self, _file: Fd, buffer: &[u8]) -> Result<usize> {
+    fn write(&mut self, _file: usize, buffer: &[u8]) -> Result<usize> {
         //TODO: Write bytes, do not convert to str
         print!("{}", unsafe { str::from_utf8_unchecked(buffer) });
         Ok(buffer.len())
     }
 
     /// Close the file `number`
-    fn close(&mut self, _file: Fd) -> Result<()> {
+    fn close(&mut self, _file: usize) -> Result<()> {
         Ok(())
     }
 }
diff --git a/scheme/fd.rs b/scheme/fd.rs
deleted file mode 100644
index 844f07d9..00000000
--- a/scheme/fd.rs
+++ /dev/null
@@ -1,5 +0,0 @@
-/// A file descriptor.
-#[derive(PartialEq, Eq, PartialOrd, Ord, Hash)]
-pub struct Fd {
-    inner: usize,
-}
diff --git a/scheme/mod.rs b/scheme/mod.rs
index 2e1c0155..99a50a10 100644
--- a/scheme/mod.rs
+++ b/scheme/mod.rs
@@ -13,27 +13,82 @@ use collections::BTreeMap;
 
 use spin::{Once, Mutex, RwLock, RwLockReadGuard, RwLockWriteGuard};
 
-use syscall::Result;
+use syscall::{Error, Result};
 
 use self::debug::DebugScheme;
 
-pub use self::fd::Fd;
-
 /// Debug scheme
 pub mod debug;
-mod fd;
+
+/// Limit on number of schemes
+pub const SCHEME_MAX_SCHEMES: usize = 65536;
 
 /// Scheme list type
-pub type SchemeList = BTreeMap<Box<[u8]>, Arc<Mutex<Box<Scheme + Send>>>>;
+pub struct SchemeList {
+    map: BTreeMap<usize, Arc<Mutex<Box<Scheme + Send>>>>,
+    names: BTreeMap<Box<[u8]>, usize>,
+    next_id: usize
+}
+
+impl SchemeList {
+    /// Create a new scheme list.
+    pub fn new() -> Self {
+        SchemeList {
+            map: BTreeMap::new(),
+            names: BTreeMap::new(),
+            next_id: 1
+        }
+    }
+
+    /// Get the nth scheme.
+    pub fn get(&self, id: usize) -> Option<&Arc<Mutex<Box<Scheme + Send>>>> {
+        self.map.get(&id)
+    }
+
+    pub fn get_name(&self, name: &[u8]) -> Option<(usize, &Arc<Mutex<Box<Scheme + Send>>>)> {
+        if let Some(&id) = self.names.get(name) {
+            self.get(id).map(|scheme| (id, scheme))
+        } else {
+            None
+        }
+    }
+
+    /// Create a new context.
+    pub fn insert(&mut self, name: Box<[u8]>, scheme: Arc<Mutex<Box<Scheme + Send>>>) -> Result<&Arc<Mutex<Box<Scheme + Send>>>> {
+        if self.names.contains_key(&name) {
+            return Err(Error::FileExists);
+        }
+
+        if self.next_id >= SCHEME_MAX_SCHEMES {
+            self.next_id = 1;
+        }
+
+        while self.map.contains_key(&self.next_id) {
+            self.next_id += 1;
+        }
+
+        if self.next_id >= SCHEME_MAX_SCHEMES {
+            return Err(Error::TryAgain);
+        }
+
+        let id = self.next_id;
+        self.next_id += 1;
+
+        assert!(self.map.insert(id, scheme).is_none());
+        assert!(self.names.insert(name, id).is_none());
+
+        Ok(self.map.get(&id).expect("Failed to insert new scheme. ID is out of bounds."))
+    }
+}
 
 /// Schemes list
 static SCHEMES: Once<RwLock<SchemeList>> = Once::new();
 
 /// Initialize schemes, called if needed
 fn init_schemes() -> RwLock<SchemeList> {
-    let mut map: SchemeList = BTreeMap::new();
-    map.insert(Box::new(*b"debug"), Arc::new(Mutex::new(Box::new(DebugScheme))));
-    RwLock::new(map)
+    let mut list: SchemeList = SchemeList::new();
+    list.insert(Box::new(*b"debug"), Arc::new(Mutex::new(Box::new(DebugScheme)))).expect("failed to insert debug: scheme");
+    RwLock::new(list)
 }
 
 /// Get the global schemes list, const
@@ -56,13 +111,13 @@ pub trait Scheme {
     /// Read from some file descriptor into the `buffer`
     ///
     /// Returns the number of bytes read
-    fn read(&mut self, fd: Fd, buffer: &mut [u8]) -> Result<usize>;
+    fn read(&mut self, fd: usize, buffer: &mut [u8]) -> Result<usize>;
 
     /// Write the `buffer` to the file descriptor
     ///
     /// Returns the number of bytes written
-    fn write(&mut self, fd: Fd, buffer: &[u8]) -> Result<usize>;
+    fn write(&mut self, fd: usize, buffer: &[u8]) -> Result<usize>;
 
     /// Close the file descriptor
-    fn close(&mut self, fd: Fd) -> Result<()>;
+    fn close(&mut self, fd: usize) -> Result<()>;
 }
diff --git a/syscall/fs.rs b/syscall/fs.rs
index 353a1b45..c61478e0 100644
--- a/syscall/fs.rs
+++ b/syscall/fs.rs
@@ -8,23 +8,41 @@ use super::{Error, Result};
 /// Read syscall
 pub fn read(fd: usize, buf: &mut [u8]) -> Result<usize> {
     println!("Read {}: {:X} {}", fd, buf.as_ptr() as usize, buf.len());
-    let contexts = context::contexts();
-    let context_lock = contexts.current().ok_or(Error::NoProcess)?;
-    let context = context_lock.read();
-    let file = context.files.get(fd).ok_or(Error::BadFile)?;
+
+    let file = {
+        let contexts = context::contexts();
+        let context_lock = contexts.current().ok_or(Error::NoProcess)?;
+        let context = context_lock.read();
+        let file = context.files.get(fd).ok_or(Error::BadFile)?.ok_or(Error::BadFile)?;
+        file
+    };
+
     println!("{:?}", file);
-    Ok(0)
+
+    let schemes = scheme::schemes();
+    let scheme_mutex = schemes.get(file.scheme).ok_or(Error::BadFile)?;
+    let result = scheme_mutex.lock().read(file.number, buf);
+    result
 }
 
 /// Write syscall
 pub fn write(fd: usize, buf: &[u8]) -> Result<usize> {
     println!("Write {}: {:X} {}", fd, buf.as_ptr() as usize, buf.len());
-    let contexts = context::contexts();
-    let context_lock = contexts.current().ok_or(Error::NoProcess)?;
-    let context = context_lock.read();
-    let file = context.files.get(fd).ok_or(Error::BadFile);
+
+    let file = {
+        let contexts = context::contexts();
+        let context_lock = contexts.current().ok_or(Error::NoProcess)?;
+        let context = context_lock.read();
+        let file = context.files.get(fd).ok_or(Error::BadFile)?.ok_or(Error::BadFile)?;
+        file
+    };
+
     println!("{:?}: {:?}", file, ::core::str::from_utf8(buf));
-    Ok(buf.len())
+
+    let schemes = scheme::schemes();
+    let scheme_mutex = schemes.get(file.scheme).ok_or(Error::BadFile)?;
+    let result = scheme_mutex.lock().write(file.number, buf);
+    result
 }
 
 /// Open syscall
@@ -34,20 +52,20 @@ pub fn open(path: &[u8], flags: usize) -> Result<usize> {
     let reference_opt = parts.next();
     println!("Open namespace {:?} reference {:?}: {:X}", namespace_opt.map(::core::str::from_utf8), reference_opt.map(::core::str::from_utf8), flags);
 
-    let file = {
+    let (scheme_id, file_id) = {
         let namespace = namespace_opt.ok_or(Error::NoEntry)?;
         let schemes = scheme::schemes();
-        let scheme_mutex = schemes.get(namespace).ok_or(Error::NoEntry)?;
-        let file = scheme_mutex.lock().open(reference_opt.unwrap_or(b""), flags)?;
-        file
+        let (scheme_id, scheme_mutex) = schemes.get_name(namespace).ok_or(Error::NoEntry)?;
+        let file_id = scheme_mutex.lock().open(reference_opt.unwrap_or(b""), flags)?;
+        (scheme_id, file_id)
     };
 
     let contexts = context::contexts();
     let context_lock = contexts.current().ok_or(Error::NoProcess)?;
     let mut context = context_lock.write();
     context.add_file(::context::file::File {
-        scheme: 0,
-        number: file
+        scheme: scheme_id,
+        number: file_id
     }).ok_or(Error::TooManyFiles)
 }
 
diff --git a/syscall/mod.rs b/syscall/mod.rs
index f42a431b..dc3b387e 100644
--- a/syscall/mod.rs
+++ b/syscall/mod.rs
@@ -64,6 +64,8 @@ pub enum Error {
     BadFile = 9,
     /// Try again
     TryAgain = 11,
+    /// File exists
+    FileExists = 17,
     /// Invalid argument
     InvalidValue = 22,
     /// Too many open files
-- 
GitLab