diff --git a/kernel/scheme/debug.rs b/kernel/scheme/debug.rs index 5767507..0555b09 100644 --- a/kernel/scheme/debug.rs +++ b/kernel/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 { + fn read(&mut self, _file: usize, _buffer: &mut [u8]) -> Result { Ok(0) } /// Write the `buffer` to the `file` /// /// Returns the number of bytes written - fn write(&mut self, _file: Fd, buffer: &[u8]) -> Result { + fn write(&mut self, _file: usize, buffer: &[u8]) -> Result { //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/kernel/scheme/fd.rs b/kernel/scheme/fd.rs deleted file mode 100644 index 844f07d..0000000 --- a/kernel/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/kernel/scheme/mod.rs b/kernel/scheme/mod.rs index 2e1c015..99a50a1 100644 --- a/kernel/scheme/mod.rs +++ b/kernel/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, Arc>>>; +pub struct SchemeList { + map: BTreeMap>>>, + names: BTreeMap, 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>>> { + self.map.get(&id) + } + + pub fn get_name(&self, name: &[u8]) -> Option<(usize, &Arc>>)> { + 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>>) -> Result<&Arc>>> { + 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> = Once::new(); /// Initialize schemes, called if needed fn init_schemes() -> RwLock { - 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; + fn read(&mut self, fd: usize, buffer: &mut [u8]) -> Result; /// Write the `buffer` to the file descriptor /// /// Returns the number of bytes written - fn write(&mut self, fd: Fd, buffer: &[u8]) -> Result; + fn write(&mut self, fd: usize, buffer: &[u8]) -> Result; /// Close the file descriptor - fn close(&mut self, fd: Fd) -> Result<()>; + fn close(&mut self, fd: usize) -> Result<()>; } diff --git a/kernel/syscall/fs.rs b/kernel/syscall/fs.rs index 353a1b4..c61478e 100644 --- a/kernel/syscall/fs.rs +++ b/kernel/syscall/fs.rs @@ -8,23 +8,41 @@ use super::{Error, Result}; /// Read syscall pub fn read(fd: usize, buf: &mut [u8]) -> Result { 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 { 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 { 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/kernel/syscall/mod.rs b/kernel/syscall/mod.rs index f42a431..dc3b387 100644 --- a/kernel/syscall/mod.rs +++ b/kernel/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