//! Storage protocol: a client `Attach`es to get a shared buffer; paths and //! data travel through it, message words carry only lengths and handles. use server_framework::{Decode, Encode}; use crate::filesystem::FileHandle; pub use types::storage::{BUFFER_PAGES, BUFFER_SIZE, DIR_ENTRY_SIZE, DIR_NAME_SIZE, MAX_PATH}; use types::storage::{op, reply}; #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum StorageRequest { Attach, /// The path is the first `path_len` bytes of the buffer. Open { path_len: usize }, /// Reads up to `len` bytes into the buffer. Read { handle: FileHandle, len: usize }, /// Writes the first `len` bytes of the buffer. Write { handle: FileHandle, len: usize }, Close { handle: FileHandle }, FileSize { handle: FileHandle }, /// Fills the buffer with `DIR_ENTRY_SIZE` records. ListDir { path_len: usize }, Create { path_len: usize }, Delete { path_len: usize }, Mkdir { path_len: usize }, /// Carries the endpoint to print to. SetLog, } #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum StorageResponse { /// Carries the buffer capability; `size` bytes are usable. Attached { size: usize }, Handle(FileHandle), Data { bytes: usize }, Written { bytes: usize }, Ok, DirEntries { count: usize }, Size(usize), NotFound, Error, /// The disk cannot be written. ReadOnly, /// The client has not attached a buffer yet. NotAttached, } fn handle(word: usize) -> Option { u16::try_from(word).ok().map(FileHandle::new) } impl Encode for StorageRequest { fn encode(&self) -> [usize; 4] { use StorageRequest::*; match *self { Attach => [op::ATTACH, 0, 0, 0], Open { path_len } => [op::OPEN, path_len, 0, 0], Read { handle, len } => [op::READ, handle.raw() as usize, len, 0], Write { handle, len } => [op::WRITE, handle.raw() as usize, len, 0], Close { handle } => [op::CLOSE, handle.raw() as usize, 0, 0], FileSize { handle } => [op::FILE_SIZE, handle.raw() as usize, 0, 0], ListDir { path_len } => [op::LIST_DIR, path_len, 0, 0], Create { path_len } => [op::CREATE, path_len, 0, 0], Delete { path_len } => [op::DELETE, path_len, 0, 0], Mkdir { path_len } => [op::MKDIR, path_len, 0, 0], SetLog => [op::SET_LOG, 0, 0, 0], } } } impl Decode for StorageRequest { fn decode(w: [usize; 4]) -> Option { use StorageRequest::*; Some(match w[0] { op::ATTACH => Attach, op::OPEN => Open { path_len: w[1] }, op::READ => Read { handle: handle(w[1])?, len: w[2] }, op::WRITE => Write { handle: handle(w[1])?, len: w[2] }, op::CLOSE => Close { handle: handle(w[1])? }, op::FILE_SIZE => FileSize { handle: handle(w[1])? }, op::LIST_DIR => ListDir { path_len: w[1] }, op::CREATE => Create { path_len: w[1] }, op::DELETE => Delete { path_len: w[1] }, op::MKDIR => Mkdir { path_len: w[1] }, op::SET_LOG => SetLog, _ => return None, }) } } impl Encode for StorageResponse { fn encode(&self) -> [usize; 4] { use StorageResponse::*; match *self { Attached { size } => [reply::ATTACHED, size, 0, 0], Handle(h) => [reply::HANDLE, h.raw() as usize, 0, 0], Data { bytes } => [reply::DATA, bytes, 0, 0], Written { bytes } => [reply::WRITTEN, bytes, 0, 0], Ok => [reply::OK, 0, 0, 0], DirEntries { count } => [reply::DIR_ENTRIES, count, 0, 0], Size(s) => [reply::SIZE, s, 0, 0], NotFound => [reply::NOT_FOUND, 0, 0, 0], Error => [reply::ERROR, 0, 0, 0], ReadOnly => [reply::READ_ONLY, 0, 0, 0], NotAttached => [reply::NOT_ATTACHED, 0, 0, 0], } } } impl Decode for StorageResponse { fn decode(w: [usize; 4]) -> Option { use StorageResponse::*; Some(match w[0] { reply::ATTACHED => Attached { size: w[1] }, reply::HANDLE => Handle(handle(w[1])?), reply::DATA => Data { bytes: w[1] }, reply::WRITTEN => Written { bytes: w[1] }, reply::OK => Ok, reply::DIR_ENTRIES => DirEntries { count: w[1] }, reply::SIZE => Size(w[1]), reply::NOT_FOUND => NotFound, reply::ERROR => Error, reply::READ_ONLY => ReadOnly, reply::NOT_ATTACHED => NotAttached, _ => return None, }) } }