diff --git a/kernel/scheme/env.rs b/kernel/scheme/env.rs index 8448cfe..3f3f1f5 100644 --- a/kernel/scheme/env.rs +++ b/kernel/scheme/env.rs @@ -1,8 +1,10 @@ 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 { @@ -76,6 +78,20 @@ impl Scheme for EnvScheme { 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) } diff --git a/kernel/scheme/initfs.rs b/kernel/scheme/initfs.rs index 1380c6e..84df203 100644 --- a/kernel/scheme/initfs.rs +++ b/kernel/scheme/initfs.rs @@ -1,8 +1,10 @@ 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 { @@ -48,29 +50,29 @@ impl Scheme for InitFsScheme { Ok(id) } - fn dup(&self, file: usize) -> Result { + fn dup(&self, id: usize) -> Result { let (data, seek) = { let handles = self.handles.read(); - let handle = handles.get(&file).ok_or(Error::new(EBADF))?; + let handle = handles.get(&id).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 { + let new_id = self.next_id.fetch_add(1, Ordering::SeqCst); + self.handles.write().insert(new_id, Handle { data: data, seek: seek }); - Ok(id) + Ok(new_id) } - fn read(&self, file: usize, buffer: &mut [u8]) -> Result { + fn read(&self, id: usize, buf: &mut [u8]) -> Result { let mut handles = self.handles.write(); - let mut handle = handles.get_mut(&file).ok_or(Error::new(EBADF))?; + let mut handle = handles.get_mut(&id).ok_or(Error::new(EBADF))?; let mut i = 0; - while i < buffer.len() && handle.seek < handle.data.len() { - buffer[i] = handle.data[handle.seek]; + while i < buf.len() && handle.seek < handle.data.len() { + buf[i] = handle.data[handle.seek]; i += 1; handle.seek += 1; } @@ -78,11 +80,25 @@ impl Scheme for InitFsScheme { Ok(i) } - fn fsync(&self, _file: usize) -> Result { + 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, _id: usize) -> Result { Ok(0) } - fn close(&self, file: usize) -> Result { - self.handles.write().remove(&file).ok_or(Error::new(EBADF)).and(Ok(0)) + fn close(&self, id: usize) -> Result { + self.handles.write().remove(&id).ok_or(Error::new(EBADF)).and(Ok(0)) } } diff --git a/kernel/scheme/user.rs b/kernel/scheme/user.rs index 9d9ae7e..e5a0167 100644 --- a/kernel/scheme/user.rs +++ b/kernel/scheme/user.rs @@ -9,20 +9,11 @@ use arch::paging::{InactivePageTable, Page, VirtualAddress, entry}; use arch::paging::temporary_page::TemporaryPage; use context::{self, Context}; use context::memory::Grant; +use syscall::data::{Packet, Stat}; use syscall::error::*; use syscall::number::*; use syscall::scheme::Scheme; -#[derive(Copy, Clone, Debug, Default)] -#[repr(packed)] -pub struct Packet { - pub id: usize, - pub a: usize, - pub b: usize, - pub c: usize, - pub d: usize -} - pub struct UserInner { next_id: AtomicUsize, context: Weak>, @@ -224,7 +215,20 @@ impl Scheme for UserScheme { fn write(&self, file: usize, buf: &[u8]) -> Result { let inner = self.inner.upgrade().ok_or(Error::new(ENODEV))?; let address = inner.capture(buf)?; - let result = inner.call(SYS_WRITE, file, buf.as_ptr() as usize, buf.len()); + let result = inner.call(SYS_WRITE, file, address, buf.len()); + let _ = inner.release(address); + result + } + + fn seek(&self, file: usize, position: usize, whence: usize) -> Result { + let inner = self.inner.upgrade().ok_or(Error::new(ENODEV))?; + inner.call(SYS_FSYNC, file, position, whence) + } + + fn fstat(&self, file: usize, stat: &mut Stat) -> Result { + let inner = self.inner.upgrade().ok_or(Error::new(ENODEV))?; + let address = inner.capture_mut(stat)?; + let result = inner.call(SYS_FSTAT, file, address, 0); let _ = inner.release(address); result } @@ -234,6 +238,11 @@ impl Scheme for UserScheme { inner.call(SYS_FSYNC, file, 0, 0) } + fn ftruncate(&self, file: usize, len: usize) -> Result { + let inner = self.inner.upgrade().ok_or(Error::new(ENODEV))?; + inner.call(SYS_FTRUNCATE, file, len, 0) + } + fn close(&self, file: usize) -> Result { let inner = self.inner.upgrade().ok_or(Error::new(ENODEV))?; inner.call(SYS_CLOSE, file, 0, 0) diff --git a/kernel/syscall/fs.rs b/kernel/syscall/fs.rs index a487019..029222b 100644 --- a/kernel/syscall/fs.rs +++ b/kernel/syscall/fs.rs @@ -2,6 +2,7 @@ use context; use scheme; +use syscall::data::Stat; use syscall::error::*; /// Change the current working directory @@ -97,6 +98,24 @@ pub fn dup(fd: usize) -> Result { scheme.dup(file.number) } +/// 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 = { @@ -115,6 +134,24 @@ pub fn fsync(fd: usize) -> Result { scheme.fsync(file.number) } +/// 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 = { diff --git a/kernel/syscall/mod.rs b/kernel/syscall/mod.rs index 70400e7..b37a056 100644 --- a/kernel/syscall/mod.rs +++ b/kernel/syscall/mod.rs @@ -2,14 +2,16 @@ extern crate syscall; -pub use self::syscall::{error, number, scheme}; +pub use self::syscall::{data, error, flag, number, scheme}; -use self::error::{Error, Result, ENOSYS}; -use self::number::*; pub use self::fs::*; pub use self::process::*; pub use self::validate::*; +use self::data::Stat; +use self::error::{Error, Result, ENOSYS}; +use self::number::*; + /// Filesystem syscalls pub mod fs; @@ -32,7 +34,9 @@ pub extern fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize SYS_WAITPID => waitpid(b, c, d), SYS_EXECVE => exec(validate_slice(b as *const u8, c)?, validate_slice(d as *const [usize; 2], e)?), SYS_CHDIR => chdir(validate_slice(b as *const u8, c)?), + SYS_LSEEK => lseek(b, c, d), SYS_GETPID => getpid(), + SYS_FSTAT => fstat(b, &mut validate_slice_mut(b as *mut Stat, 1)?[0]), SYS_DUP => dup(b), SYS_BRK => brk(b), SYS_IOPL => iopl(b), diff --git a/syscall/src/data.rs b/syscall/src/data.rs new file mode 100644 index 0000000..399950b --- /dev/null +++ b/syscall/src/data.rs @@ -0,0 +1,69 @@ +use core::ops::{Deref, DerefMut}; +use core::{mem, slice}; + +#[derive(Copy, Clone, Debug, Default)] +#[repr(packed)] +pub struct Packet { + pub id: usize, + pub a: usize, + pub b: usize, + pub c: usize, + pub d: usize +} + +impl Deref for Packet { + type Target = [u8]; + fn deref(&self) -> &[u8] { + unsafe { + slice::from_raw_parts(self as *const Packet as *const u8, mem::size_of::()) as &[u8] + } + } +} + +impl DerefMut for Packet { + fn deref_mut(&mut self) -> &mut [u8] { + unsafe { + slice::from_raw_parts_mut(self as *mut Packet as *mut u8, mem::size_of::()) as &mut [u8] + } + } +} + +#[derive(Copy, Clone, Debug, Default)] +#[repr(packed)] +pub struct Stat { + pub st_dev: u16, + pub st_ino: u16, + pub st_mode: u16, + pub st_nlink: u16, + pub st_uid: u16, + pub st_gid: u16, + pub st_rdev: u16, + pub st_size: u32, + pub st_atime: u32, + pub st_mtime: u32, + pub st_ctime: u32 +} + +impl Deref for Stat { + type Target = [u8]; + fn deref(&self) -> &[u8] { + unsafe { + slice::from_raw_parts(self as *const Stat as *const u8, mem::size_of::()) as &[u8] + } + } +} + +impl DerefMut for Stat { + fn deref_mut(&mut self) -> &mut [u8] { + unsafe { + slice::from_raw_parts_mut(self as *mut Stat as *mut u8, mem::size_of::()) as &mut [u8] + } + } +} + +#[derive(Copy, Clone, Debug, Default)] +#[repr(packed)] +pub struct TimeSpec { + pub tv_sec: i64, + pub tv_nsec: i32, +} diff --git a/syscall/src/flag.rs b/syscall/src/flag.rs new file mode 100644 index 0000000..fa00558 --- /dev/null +++ b/syscall/src/flag.rs @@ -0,0 +1,40 @@ +pub const CLONE_VM: usize = 0x100; +pub const CLONE_FS: usize = 0x200; +pub const CLONE_FILES: usize = 0x400; +pub const CLONE_VFORK: usize = 0x4000; +/// Mark this clone as supervised. +/// +/// This means that the process can run in supervised mode, even not being connected to +/// a supervisor yet. In other words, the parent can later on supervise the process and handle +/// the potential blocking syscall. +/// +/// This is an important security measure, since otherwise the process would be able to fork it +/// self right after starting, making supervising it impossible. +pub const CLONE_SUPERVISE: usize = 0x400000; +pub const CLOCK_REALTIME: usize = 1; +pub const CLOCK_MONOTONIC: usize = 4; + +pub const MODE_DIR: u16 = 0x4000; +pub const MODE_FILE: u16 = 0x8000; +pub const MODE_ALL: u16 = MODE_DIR | MODE_FILE; + +pub const FUTEX_WAIT: usize = 0; +pub const FUTEX_WAKE: usize = 1; +pub const FUTEX_REQUEUE: usize = 2; + +pub const SEEK_SET: usize = 0; +pub const SEEK_CUR: usize = 1; +pub const SEEK_END: usize = 2; + +pub const O_RDONLY: usize = 0; +pub const O_WRONLY: usize = 1; +pub const O_RDWR: usize = 2; +pub const O_NONBLOCK: usize = 4; +pub const O_APPEND: usize = 8; +pub const O_SHLOCK: usize = 0x10; +pub const O_EXLOCK: usize = 0x20; +pub const O_ASYNC: usize = 0x40; +pub const O_FSYNC: usize = 0x80; +pub const O_CREAT: usize = 0x200; +pub const O_TRUNC: usize = 0x400; +pub const O_EXCL: usize = 0x800; diff --git a/syscall/src/lib.rs b/syscall/src/lib.rs index e55ed44..099f61f 100644 --- a/syscall/src/lib.rs +++ b/syscall/src/lib.rs @@ -2,7 +2,9 @@ #![no_std] pub use self::arch::*; +pub use self::data::*; pub use self::error::*; +pub use self::flag::*; pub use self::number::*; pub use self::scheme::*; @@ -14,76 +16,16 @@ mod arch; #[path="x86_64.rs"] mod arch; +pub mod data; + pub mod error; +pub mod flag; + pub mod number; pub mod scheme; -pub const CLONE_VM: usize = 0x100; -pub const CLONE_FS: usize = 0x200; -pub const CLONE_FILES: usize = 0x400; -pub const CLONE_VFORK: usize = 0x4000; -/// Mark this clone as supervised. -/// -/// This means that the process can run in supervised mode, even not being connected to -/// a supervisor yet. In other words, the parent can later on supervise the process and handle -/// the potential blocking syscall. -/// -/// This is an important security measure, since otherwise the process would be able to fork it -/// self right after starting, making supervising it impossible. -pub const CLONE_SUPERVISE: usize = 0x400000; -pub const CLOCK_REALTIME: usize = 1; -pub const CLOCK_MONOTONIC: usize = 4; - -pub const MODE_DIR: u16 = 0x4000; -pub const MODE_FILE: u16 = 0x8000; -pub const MODE_ALL: u16 = MODE_DIR | MODE_FILE; - -pub const FUTEX_WAIT: usize = 0; -pub const FUTEX_WAKE: usize = 1; -pub const FUTEX_REQUEUE: usize = 2; - -pub const SEEK_SET: usize = 0; -pub const SEEK_CUR: usize = 1; -pub const SEEK_END: usize = 2; - -pub const O_RDONLY: usize = 0; -pub const O_WRONLY: usize = 1; -pub const O_RDWR: usize = 2; -pub const O_NONBLOCK: usize = 4; -pub const O_APPEND: usize = 8; -pub const O_SHLOCK: usize = 0x10; -pub const O_EXLOCK: usize = 0x20; -pub const O_ASYNC: usize = 0x40; -pub const O_FSYNC: usize = 0x80; -pub const O_CREAT: usize = 0x200; -pub const O_TRUNC: usize = 0x400; -pub const O_EXCL: usize = 0x800; - -#[derive(Copy, Clone, Debug, Default)] -#[repr(packed)] -pub struct Stat { - pub st_dev: u16, - pub st_ino: u16, - pub st_mode: u16, - pub st_nlink: u16, - pub st_uid: u16, - pub st_gid: u16, - pub st_rdev: u16, - pub st_size: u32, - pub st_atime: u32, - pub st_mtime: u32, - pub st_ctime: u32 -} - -#[derive(Copy, Clone, Debug, Default)] -#[repr(packed)] -pub struct TimeSpec { - pub tv_sec: i64, - pub tv_nsec: i32, -} - pub unsafe fn brk(addr: usize) -> Result { syscall1(SYS_BRK, addr) } diff --git a/syscall/src/scheme.rs b/syscall/src/scheme.rs index 40405c4..6a857d1 100644 --- a/syscall/src/scheme.rs +++ b/syscall/src/scheme.rs @@ -1,35 +1,7 @@ -use core::ops::{Deref, DerefMut}; -use core::{mem, slice}; +use core::slice; use super::*; -#[derive(Copy, Clone, Debug, Default)] -#[repr(packed)] -pub struct Packet { - pub id: usize, - pub a: usize, - pub b: usize, - pub c: usize, - pub d: usize -} - -impl Deref for Packet { - type Target = [u8]; - fn deref(&self) -> &[u8] { - unsafe { - slice::from_raw_parts(self as *const Packet as *const u8, mem::size_of::()) as &[u8] - } - } -} - -impl DerefMut for Packet { - fn deref_mut(&mut self) -> &mut [u8] { - unsafe { - slice::from_raw_parts_mut(self as *mut Packet as *mut u8, mem::size_of::()) as &mut [u8] - } - } -} - pub trait Scheme { fn handle(&self, packet: &mut Packet) { packet.a = Error::mux(match packet.a { @@ -69,11 +41,6 @@ pub trait Scheme { Err(Error::new(ENOENT)) } - #[allow(unused_variables)] - fn stat(&self, path: &[u8], stat: &mut Stat) -> Result { - Err(Error::new(ENOENT)) - } - #[allow(unused_variables)] fn unlink(&self, path: &[u8]) -> Result { Err(Error::new(ENOENT))