From 31605167ceb20bc3e2ffb6ef0b15fc05ca16ad7c Mon Sep 17 00:00:00 2001
From: Jeremy Soller <jackpot51@gmail.com>
Date: Tue, 15 Nov 2016 17:07:37 -0700
Subject: [PATCH] Add chmod

---
 scheme/resource.rs |  2 +-
 scheme/scheme.rs   | 31 ++++++++++++++++++++++++++++++-
 2 files changed, 31 insertions(+), 2 deletions(-)

diff --git a/scheme/resource.rs b/scheme/resource.rs
index ea044d2..f985092 100644
--- a/scheme/resource.rs
+++ b/scheme/resource.rs
@@ -178,7 +178,7 @@ impl Resource for FileResource {
             F_SETFL => {
                 self.flags = arg & ! O_ACCMODE;
                 Ok(0)
-            }
+            },
             _ => Err(Error::new(EINVAL))
         }
     }
diff --git a/scheme/scheme.rs b/scheme/scheme.rs
index a87c2b7..c6ff37b 100644
--- a/scheme/scheme.rs
+++ b/scheme/scheme.rs
@@ -9,7 +9,7 @@ use std::sync::atomic::{AtomicUsize, Ordering};
 
 use syscall::data::Stat;
 use syscall::error::{Error, Result, EACCES, EEXIST, EISDIR, ENOTDIR, EPERM, ENOENT, EBADF};
-use syscall::flag::{O_CREAT, O_TRUNC, O_ACCMODE, O_RDONLY, O_WRONLY, O_RDWR};
+use syscall::flag::{O_CREAT, O_TRUNC, O_ACCMODE, O_RDONLY, O_WRONLY, O_RDWR, MODE_PERM};
 use syscall::scheme::Scheme;
 
 pub struct FileScheme {
@@ -196,6 +196,35 @@ impl Scheme for FileScheme {
         }
     }
 
+    fn chmod(&self, url: &[u8], mode: u16, uid: u32, gid: u32) -> Result<usize> {
+        let path = str::from_utf8(url).unwrap_or("").trim_matches('/');
+
+        // println!("Chmod '{}'", path);
+
+        let mut fs = self.fs.borrow_mut();
+
+        let mut nodes = Vec::new();
+        let node_result = fs.path_nodes(path, &mut nodes);
+        for node in nodes.iter() {
+            if ! node.1.permission(uid, gid, Node::MODE_EXEC) {
+                // println!("dir not executable {:o}", node.1.mode);
+                return Err(Error::new(EACCES));
+            }
+            if ! node.1.is_dir() {
+                return Err(Error::new(ENOTDIR));
+            }
+        }
+
+        let mut node = node_result?;
+        if node.1.uid == uid || uid == 0 {
+            node.1.mode = (node.1.mode & ! MODE_PERM) | (mode & MODE_PERM);
+            try!(fs.write_at(node.0, &node.1));
+            Ok(0)
+        } else {
+            Err(Error::new(EPERM))
+        }
+    }
+
     fn rmdir(&self, url: &[u8], uid: u32, gid: u32) -> Result<usize> {
         let path = str::from_utf8(url).unwrap_or("").trim_matches('/');
 
-- 
GitLab