From e2ec6fd2201dc0d9e193a38c6d360d345f217f9e Mon Sep 17 00:00:00 2001
From: Jeremy Soller <jackpot51@gmail.com>
Date: Tue, 20 Sep 2016 16:57:45 -0600
Subject: [PATCH] Implement more system calls

---
 scheme/env.rs    | 16 ++++++++++++++++
 scheme/initfs.rs | 40 ++++++++++++++++++++++++++++------------
 scheme/user.rs   | 31 ++++++++++++++++++++-----------
 syscall/fs.rs    | 37 +++++++++++++++++++++++++++++++++++++
 syscall/mod.rs   | 10 +++++++---
 5 files changed, 108 insertions(+), 26 deletions(-)

diff --git a/scheme/env.rs b/scheme/env.rs
index 8448cfe4..3f3f1f56 100644
--- a/scheme/env.rs
+++ b/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<usize> {
+        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<usize> {
         Ok(0)
     }
diff --git a/scheme/initfs.rs b/scheme/initfs.rs
index 1380c6ea..84df203d 100644
--- a/scheme/initfs.rs
+++ b/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<usize> {
+    fn dup(&self, id: usize) -> Result<usize> {
         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<usize> {
+    fn read(&self, id: usize, buf: &mut [u8]) -> Result<usize> {
         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<usize> {
+    fn seek(&self, id: usize, pos: usize, whence: usize) -> Result<usize> {
+        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<usize> {
         Ok(0)
     }
 
-    fn close(&self, file: usize) -> Result<usize> {
-        self.handles.write().remove(&file).ok_or(Error::new(EBADF)).and(Ok(0))
+    fn close(&self, id: usize) -> Result<usize> {
+        self.handles.write().remove(&id).ok_or(Error::new(EBADF)).and(Ok(0))
     }
 }
diff --git a/scheme/user.rs b/scheme/user.rs
index 9d9ae7e9..e5a01675 100644
--- a/scheme/user.rs
+++ b/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<RwLock<Context>>,
@@ -224,7 +215,20 @@ impl Scheme for UserScheme {
     fn write(&self, file: usize, buf: &[u8]) -> Result<usize> {
         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<usize> {
+        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<usize> {
+        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<usize> {
+        let inner = self.inner.upgrade().ok_or(Error::new(ENODEV))?;
+        inner.call(SYS_FTRUNCATE, file, len, 0)
+    }
+
     fn close(&self, file: usize) -> Result<usize> {
         let inner = self.inner.upgrade().ok_or(Error::new(ENODEV))?;
         inner.call(SYS_CLOSE, file, 0, 0)
diff --git a/syscall/fs.rs b/syscall/fs.rs
index a487019b..029222b7 100644
--- a/syscall/fs.rs
+++ b/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<usize> {
     scheme.dup(file.number)
 }
 
+/// Get information about the file
+pub fn fstat(fd: usize, stat: &mut Stat) -> Result<usize> {
+    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<usize> {
     let file = {
@@ -115,6 +134,24 @@ pub fn fsync(fd: usize) -> Result<usize> {
     scheme.fsync(file.number)
 }
 
+/// Seek to an offset
+pub fn lseek(fd: usize, pos: usize, whence: usize) -> Result<usize> {
+    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<usize> {
     let file = {
diff --git a/syscall/mod.rs b/syscall/mod.rs
index 70400e79..b37a056b 100644
--- a/syscall/mod.rs
+++ b/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),
-- 
GitLab