From c1aa76bf3c952a63685ec7e743f8eea30afb2e67 Mon Sep 17 00:00:00 2001
From: Jeremy Soller <jackpot51@gmail.com>
Date: Mon, 14 Feb 2022 09:57:24 -0700
Subject: [PATCH] Fill in st_dev in fstat

---
 src/syscall/fs.rs       | 21 +++++++++++++++++++++
 src/syscall/mod.rs      |  7 +++++--
 src/syscall/validate.rs | 10 ++++++++++
 3 files changed, 36 insertions(+), 2 deletions(-)

diff --git a/src/syscall/fs.rs b/src/syscall/fs.rs
index a271e5d3..0dee4987 100644
--- a/src/syscall/fs.rs
+++ b/src/syscall/fs.rs
@@ -448,6 +448,27 @@ pub fn frename(fd: FileHandle, path: &str) -> Result<usize> {
     }
 }
 
+/// File status
+pub fn fstat(fd: FileHandle, 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();
+        context.get_file(fd).ok_or(Error::new(EBADF))?
+    };
+
+    let description = file.description.read();
+
+    let scheme = {
+        let schemes = scheme::schemes();
+        let scheme = schemes.get(description.scheme).ok_or(Error::new(EBADF))?;
+        Arc::clone(&scheme)
+    };
+    // Fill in scheme number as device number
+    stat.st_dev = description.scheme.into() as u64;
+    scheme.fstat(description.number, stat)
+}
+
 pub fn funmap_old(virtual_address: usize) -> Result<usize> {
     if virtual_address == 0 {
         Ok(0)
diff --git a/src/syscall/mod.rs b/src/syscall/mod.rs
index 3955af57..cb64c4c1 100644
--- a/src/syscall/mod.rs
+++ b/src/syscall/mod.rs
@@ -25,7 +25,7 @@ pub use self::process::*;
 pub use self::time::*;
 pub use self::validate::*;
 
-use self::data::{Map, SigAction, TimeSpec};
+use self::data::{Map, SigAction, Stat, TimeSpec};
 use self::error::{Error, Result, ENOSYS};
 use self::flag::{CloneFlags, MapFlags, PhysmapFlags, WaitFlags};
 use self::number::*;
@@ -74,7 +74,10 @@ pub fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, bp: u
                         },
                         _ => file_op_slice(a, fd, validate_slice(c as *const u8, d)?),
                     }
-                    SYS_ARG_MSLICE => file_op_mut_slice(a, fd, validate_slice_mut(c as *mut u8, d)?),
+                    SYS_ARG_MSLICE => match a {
+                        SYS_FSTAT => fstat(fd, unsafe { validate_ref_mut(c as *mut Stat, d)? }),
+                        _ => file_op_mut_slice(a, fd, validate_slice_mut(c as *mut u8, d)?),
+                    },
                     _ => match a {
                         SYS_CLOSE => close(fd),
                         SYS_DUP => dup(fd, validate_slice(c as *const u8, d)?).map(FileHandle::into),
diff --git a/src/syscall/validate.rs b/src/syscall/validate.rs
index c5f3e23e..2aac27a4 100644
--- a/src/syscall/validate.rs
+++ b/src/syscall/validate.rs
@@ -41,6 +41,16 @@ pub unsafe fn validate_ref<T>(ptr: *const T, size: usize) -> Result<&'static T>
     }
 }
 
+/// Convert a pointer and length to mutable reference, if valid
+pub unsafe fn validate_ref_mut<T>(ptr: *mut T, size: usize) -> Result<&'static mut T> {
+    if size == mem::size_of::<T>() {
+        validate(ptr as usize, mem::size_of::<T>(), false)?;
+        Ok(&mut *ptr)
+    } else {
+        Err(Error::new(EINVAL))
+    }
+}
+
 /// Convert a pointer and length to slice, if valid
 //TODO: Mark unsafe
 pub fn validate_slice<T>(ptr: *const T, len: usize) -> Result<&'static [T]> {
-- 
GitLab