From cf27b3a3ad5dc60bd7976a8b834721589a112bef Mon Sep 17 00:00:00 2001
From: Jeremy Soller <jackpot51@gmail.com>
Date: Sun, 11 Sep 2016 17:31:21 -0600
Subject: [PATCH] Fix close, add dup

---
 context/mod.rs   | 19 +++++++++++++++++++
 scheme/debug.rs  |  4 ++++
 scheme/initfs.rs | 25 ++++++++++++++++++-------
 scheme/mod.rs    | 11 ++++++++---
 syscall/fs.rs    | 24 ++++++++++++++++++++----
 syscall/mod.rs   |  4 ++++
 6 files changed, 73 insertions(+), 14 deletions(-)

diff --git a/context/mod.rs b/context/mod.rs
index 506dde64..8975582c 100644
--- a/context/mod.rs
+++ b/context/mod.rs
@@ -202,4 +202,23 @@ impl Context {
             None
         }
     }
+
+    /// Get a file
+    pub fn get_file(&self, i: usize) -> Option<file::File> {
+        if i < self.files.len() {
+            self.files[i]
+        } else {
+            None
+        }
+    }
+
+    /// Remove a file
+    // TODO: adjust files vector to smaller size if possible
+    pub fn remove_file(&mut self, i: usize) -> Option<file::File> {
+        if i < self.files.len() {
+            self.files[i].take()
+        } else {
+            None
+        }
+    }
 }
diff --git a/scheme/debug.rs b/scheme/debug.rs
index 942cc4a8..0623b8b6 100644
--- a/scheme/debug.rs
+++ b/scheme/debug.rs
@@ -10,6 +10,10 @@ impl Scheme for DebugScheme {
         Ok(0)
     }
 
+    fn dup(&mut self, _file: usize) -> Result<usize> {
+        Ok(0)
+    }
+
     /// Read the file `number` into the `buffer`
     ///
     /// Returns the number of bytes read
diff --git a/scheme/initfs.rs b/scheme/initfs.rs
index 1014fe7c..d947b5ab 100644
--- a/scheme/initfs.rs
+++ b/scheme/initfs.rs
@@ -33,18 +33,33 @@ impl InitFsScheme {
 impl Scheme for InitFsScheme {
     fn open(&mut self, path: &[u8], _flags: usize) -> Result<usize> {
         let data = self.files.get(path).ok_or(Error::NoEntry)?;
+
         let id = self.next_id;
         self.next_id += 1;
         self.handles.insert(id, Handle {
             data: data,
             seek: 0
         });
+
+        Ok(id)
+    }
+
+    fn dup(&mut self, file: usize) -> Result<usize> {
+        let (data, seek) = {
+            let handle = self.handles.get(&file).ok_or(Error::BadFile)?;
+            (handle.data, handle.seek)
+        };
+
+        let id = self.next_id;
+        self.next_id += 1;
+        self.handles.insert(id, Handle {
+            data: data,
+            seek: seek
+        });
+
         Ok(id)
     }
 
-    /// Read the file `number` into the `buffer`
-    ///
-    /// Returns the number of bytes read
     fn read(&mut self, file: usize, buffer: &mut [u8]) -> Result<usize> {
         let mut handle = self.handles.get_mut(&file).ok_or(Error::BadFile)?;
 
@@ -58,14 +73,10 @@ impl Scheme for InitFsScheme {
         Ok(i)
     }
 
-    /// Write the `buffer` to the `file`
-    ///
-    /// Returns the number of bytes written
     fn write(&mut self, _file: usize, _buffer: &[u8]) -> Result<usize> {
         Err(Error::NotPermitted)
     }
 
-    /// Close the file `number`
     fn close(&mut self, file: usize) -> Result<()> {
         self.handles.remove(&file).ok_or(Error::BadFile).and(Ok(()))
     }
diff --git a/scheme/mod.rs b/scheme/mod.rs
index ef86570f..a2a80097 100644
--- a/scheme/mod.rs
+++ b/scheme/mod.rs
@@ -113,16 +113,21 @@ pub trait Scheme {
     /// Returns a file descriptor or an error
     fn open(&mut self, path: &[u8], flags: usize) -> Result<usize>;
 
+    /// Duplicate an open file descriptor
+    ///
+    /// Returns a file descriptor or an error
+    fn dup(&mut self, file: usize) -> Result<usize>;
+
     /// Read from some file descriptor into the `buffer`
     ///
     /// Returns the number of bytes read
-    fn read(&mut self, fd: usize, buffer: &mut [u8]) -> Result<usize>;
+    fn read(&mut self, file: usize, buffer: &mut [u8]) -> Result<usize>;
 
     /// Write the `buffer` to the file descriptor
     ///
     /// Returns the number of bytes written
-    fn write(&mut self, fd: usize, buffer: &[u8]) -> Result<usize>;
+    fn write(&mut self, file: usize, buffer: &[u8]) -> Result<usize>;
 
     /// Close the file descriptor
-    fn close(&mut self, fd: usize) -> Result<()>;
+    fn close(&mut self, file: usize) -> Result<()>;
 }
diff --git a/syscall/fs.rs b/syscall/fs.rs
index fed9bc72..ddb4f8af 100644
--- a/syscall/fs.rs
+++ b/syscall/fs.rs
@@ -11,7 +11,7 @@ pub fn read(fd: usize, buf: &mut [u8]) -> Result<usize> {
         let contexts = context::contexts();
         let context_lock = contexts.current().ok_or(Error::NoProcess)?;
         let context = context_lock.read();
-        let file = context.files.get(fd).ok_or(Error::BadFile)?.ok_or(Error::BadFile)?;
+        let file = context.get_file(fd).ok_or(Error::BadFile)?;
         file
     };
 
@@ -27,7 +27,7 @@ pub fn write(fd: usize, buf: &[u8]) -> Result<usize> {
         let contexts = context::contexts();
         let context_lock = contexts.current().ok_or(Error::NoProcess)?;
         let context = context_lock.read();
-        let file = context.files.get(fd).ok_or(Error::BadFile)?.ok_or(Error::BadFile)?;
+        let file = context.get_file(fd).ok_or(Error::BadFile)?;
         file
     };
 
@@ -65,8 +65,8 @@ pub fn close(fd: usize) -> Result<usize> {
     let file = {
         let contexts = context::contexts();
         let context_lock = contexts.current().ok_or(Error::NoProcess)?;
-        let context = context_lock.read();
-        let file = context.files.get(fd).ok_or(Error::BadFile)?.ok_or(Error::BadFile)?;
+        let mut context = context_lock.write();
+        let file = context.remove_file(fd).ok_or(Error::BadFile)?;
         file
     };
 
@@ -75,3 +75,19 @@ pub fn close(fd: usize) -> Result<usize> {
     let result = scheme_mutex.lock().close(file.number).and(Ok(0));
     result
 }
+
+/// Duplicate file descriptor
+pub fn dup(fd: usize) -> Result<usize> {
+    let file = {
+        let contexts = context::contexts();
+        let context_lock = contexts.current().ok_or(Error::NoProcess)?;
+        let context = context_lock.read();
+        let file = context.get_file(fd).ok_or(Error::BadFile)?;
+        file
+    };
+
+    let schemes = scheme::schemes();
+    let scheme_mutex = schemes.get(file.scheme).ok_or(Error::BadFile)?;
+    let result = scheme_mutex.lock().dup(file.number);
+    result
+}
diff --git a/syscall/mod.rs b/syscall/mod.rs
index 0af46281..3fdb7a57 100644
--- a/syscall/mod.rs
+++ b/syscall/mod.rs
@@ -30,6 +30,8 @@ pub enum Call {
     Exec = 11,
     /// Get process ID
     GetPid = 20,
+    /// Duplicate file descriptor
+    Dup = 41,
     /// Set process break
     Brk = 45,
     /// Set process I/O privilege level
@@ -52,6 +54,7 @@ impl Call {
             6 => Ok(Call::Close),
             11 => Ok(Call::Exec),
             20 => Ok(Call::GetPid),
+            41 => Ok(Call::Dup),
             45 => Ok(Call::Brk),
             110 => Ok(Call::Iopl),
             120 => Ok(Call::Clone),
@@ -112,6 +115,7 @@ pub fn handle(a: usize, b: usize, c: usize, d: usize, e: usize, _f: usize) -> Re
             Call::Close => close(b),
             Call::Exec => exec(convert_slice(b as *const u8, c)?, convert_slice(d as *const [usize; 2], e)?),
             Call::GetPid => getpid(),
+            Call::Dup => dup(b),
             Call::Brk => brk(b),
             Call::Iopl => iopl(b),
             Call::Clone => clone(b),
-- 
GitLab