//! Filesystem syscalls use context; use scheme; use syscall::data::Stat; use syscall::error::*; /// Change the current working directory pub fn chdir(path: &[u8]) -> Result { let contexts = context::contexts(); let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; let context = context_lock.read(); let canonical = context.canonicalize(path); *context.cwd.lock() = canonical; Ok(0) } /// Get the current working directory pub fn getcwd(buf: &mut [u8]) -> Result { let contexts = context::contexts(); let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; let context = context_lock.read(); let cwd = context.cwd.lock(); let mut i = 0; while i < buf.len() && i < cwd.len() { buf[i] = cwd[i]; i += 1; } Ok(i) } /// Open syscall pub fn open(path: &[u8], flags: usize) -> Result { let path_canon = { let contexts = context::contexts(); let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; let context = context_lock.read(); context.canonicalize(path) }; let mut parts = path_canon.splitn(2, |&b| b == b':'); let namespace_opt = parts.next(); let reference_opt = parts.next(); let (scheme_id, file_id) = { let namespace = namespace_opt.ok_or(Error::new(ENOENT))?; let (scheme_id, scheme) = { let schemes = scheme::schemes(); let (scheme_id, scheme) = schemes.get_name(namespace).ok_or(Error::new(ENOENT))?; (scheme_id, scheme.clone()) }; let file_id = scheme.open(reference_opt.unwrap_or(b""), flags)?; (scheme_id, file_id) }; let contexts = context::contexts(); let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; let context = context_lock.read(); context.add_file(::context::file::File { scheme: scheme_id, number: file_id }).ok_or(Error::new(EMFILE)) } /// Close syscall pub fn close(fd: usize) -> Result { let file = { let contexts = context::contexts(); let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; let context = context_lock.read(); let file = context.remove_file(fd).ok_or(Error::new(EBADF))?; file }; context::event::unregister(fd, file.scheme, file.number); let scheme = { let schemes = scheme::schemes(); let scheme = schemes.get(file.scheme).ok_or(Error::new(EBADF))?; scheme.clone() }; scheme.close(file.number) } /// Duplicate file descriptor pub fn dup(fd: usize) -> Result { let file = { let contexts = context::contexts(); let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; let context = context_lock.read(); let file = context.get_file(fd).ok_or(Error::new(EBADF))?; file }; let scheme = { let schemes = scheme::schemes(); let scheme = schemes.get(file.scheme).ok_or(Error::new(EBADF))?; scheme.clone() }; scheme.dup(file.number) } /// Register events for file pub fn fevent(fd: usize, flags: usize) -> Result { let file = { let contexts = context::contexts(); let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; let context = context_lock.read(); let file = context.get_file(fd).ok_or(Error::new(EBADF))?; file }; let scheme = { let schemes = scheme::schemes(); let scheme = schemes.get(file.scheme).ok_or(Error::new(EBADF))?; scheme.clone() }; scheme.fevent(file.number, flags)?; context::event::register(fd, file.scheme, file.number); Ok(0) } /// Get the canonical path of the file pub fn fpath(fd: usize, buf: &mut [u8]) -> Result { let file = { let contexts = context::contexts(); let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; let context = context_lock.read(); let file = context.get_file(fd).ok_or(Error::new(EBADF))?; file }; let scheme = { let schemes = scheme::schemes(); let scheme = schemes.get(file.scheme).ok_or(Error::new(EBADF))?; scheme.clone() }; scheme.fpath(file.number, buf) } /// Get information about the file pub fn fstat(fd: usize, stat: &mut Stat) -> Result { let file = { let contexts = context::contexts(); let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; let context = context_lock.read(); let file = context.get_file(fd).ok_or(Error::new(EBADF))?; file }; let scheme = { let schemes = scheme::schemes(); let scheme = schemes.get(file.scheme).ok_or(Error::new(EBADF))?; scheme.clone() }; scheme.fstat(file.number, stat) } /// Sync the file descriptor pub fn fsync(fd: usize) -> Result { let file = { let contexts = context::contexts(); let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; let context = context_lock.read(); let file = context.get_file(fd).ok_or(Error::new(EBADF))?; file }; let scheme = { let schemes = scheme::schemes(); let scheme = schemes.get(file.scheme).ok_or(Error::new(EBADF))?; scheme.clone() }; scheme.fsync(file.number) } /// Truncate the file descriptor pub fn ftruncate(fd: usize, len: usize) -> Result { let file = { let contexts = context::contexts(); let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; let context = context_lock.read(); let file = context.get_file(fd).ok_or(Error::new(EBADF))?; file }; let scheme = { let schemes = scheme::schemes(); let scheme = schemes.get(file.scheme).ok_or(Error::new(EBADF))?; scheme.clone() }; scheme.ftruncate(file.number, len) } /// Seek to an offset pub fn lseek(fd: usize, pos: usize, whence: usize) -> Result { let file = { let contexts = context::contexts(); let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; let context = context_lock.read(); let file = context.get_file(fd).ok_or(Error::new(EBADF))?; file }; let scheme = { let schemes = scheme::schemes(); let scheme = schemes.get(file.scheme).ok_or(Error::new(EBADF))?; scheme.clone() }; scheme.seek(file.number, pos, whence) } /// Read syscall pub fn read(fd: usize, buf: &mut [u8]) -> Result { let file = { let contexts = context::contexts(); let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; let context = context_lock.read(); let file = context.get_file(fd).ok_or(Error::new(EBADF))?; file }; let scheme = { let schemes = scheme::schemes(); let scheme = schemes.get(file.scheme).ok_or(Error::new(EBADF))?; scheme.clone() }; scheme.read(file.number, buf) } /// Write syscall pub fn write(fd: usize, buf: &[u8]) -> Result { let file = { let contexts = context::contexts(); let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; let context = context_lock.read(); let file = context.get_file(fd).ok_or(Error::new(EBADF))?; file }; let scheme = { let schemes = scheme::schemes(); let scheme = schemes.get(file.scheme).ok_or(Error::new(EBADF))?; scheme.clone() }; scheme.write(file.number, buf) }