use collections::BTreeMap; use core::cmp; use core::sync::atomic::{AtomicUsize, Ordering}; use spin::RwLock; use syscall::error::*; use syscall::flag::{SEEK_SET, SEEK_CUR, SEEK_END}; use syscall::scheme::Scheme; struct Handle { data: &'static [u8], seek: usize } pub struct EnvScheme { next_id: AtomicUsize, files: BTreeMap<&'static [u8], &'static [u8]>, handles: RwLock> } impl EnvScheme { pub fn new() -> EnvScheme { let mut files: BTreeMap<&'static [u8], &'static [u8]> = BTreeMap::new(); files.insert(b"HOME", b"initfs:bin/"); files.insert(b"PWD", b"initfs:bin/"); files.insert(b"PATH", b"initfs:bin/"); files.insert(b"COLUMNS", b"80"); files.insert(b"LINES", b"30"); EnvScheme { next_id: AtomicUsize::new(0), files: files, handles: RwLock::new(BTreeMap::new()) } } } impl Scheme for EnvScheme { fn open(&self, path: &[u8], _flags: usize) -> Result { let data = self.files.get(path).ok_or(Error::new(ENOENT))?; let id = self.next_id.fetch_add(1, Ordering::SeqCst); self.handles.write().insert(id, Handle { data: data, seek: 0 }); Ok(id) } fn dup(&self, file: usize) -> Result { let (data, seek) = { let handles = self.handles.read(); let handle = handles.get(&file).ok_or(Error::new(EBADF))?; (handle.data, handle.seek) }; let id = self.next_id.fetch_add(1, Ordering::SeqCst); self.handles.write().insert(id, Handle { data: data, seek: seek }); Ok(id) } fn read(&self, file: usize, buffer: &mut [u8]) -> Result { let mut handles = self.handles.write(); let mut handle = handles.get_mut(&file).ok_or(Error::new(EBADF))?; let mut i = 0; while i < buffer.len() && handle.seek < handle.data.len() { buffer[i] = handle.data[handle.seek]; i += 1; handle.seek += 1; } Ok(i) } fn seek(&self, id: usize, pos: usize, whence: usize) -> Result { let mut handles = self.handles.write(); let mut handle = handles.get_mut(&id).ok_or(Error::new(EBADF))?; handle.seek = match whence { SEEK_SET => cmp::min(handle.data.len(), pos), SEEK_CUR => cmp::max(0, cmp::min(handle.data.len() as isize, handle.seek as isize + pos as isize)) as usize, SEEK_END => cmp::max(0, cmp::min(handle.data.len() as isize, handle.data.len() as isize + pos as isize)) as usize, _ => return Err(Error::new(EINVAL)) }; Ok(handle.seek) } fn fsync(&self, _file: usize) -> Result { Ok(0) } fn close(&self, file: usize) -> Result { self.handles.write().remove(&file).ok_or(Error::new(EBADF)).and(Ok(0)) } }