From 11f3485173cf63d5beea42e9e1ce519d503c56a6 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 27 Sep 2016 21:19:28 -0600 Subject: [PATCH 1/9] Port to new kernel --- Cargo.toml | 9 ++- scheme/cache/mod.rs | 2 +- scheme/image.rs | 2 +- scheme/main.rs | 20 +++---- scheme/resource.rs | 26 ++++---- scheme/scheme.rs | 141 +++++++++++++++++++++++--------------------- src/disk.rs | 2 +- src/filesystem.rs | 2 +- src/lib.rs | 2 +- 9 files changed, 108 insertions(+), 98 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 853435157c..09ee5d6059 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,6 +11,10 @@ authors = ["Jeremy Soller "] name = "redoxfs" path = "src/lib.rs" +[[bin]] +name = "redoxfs" +path = "scheme/main.rs" + [[bin]] name = "redoxfs-fuse" path = "fuse/main.rs" @@ -20,6 +24,9 @@ name = "redoxfs-utility" path = "utility/main.rs" [dependencies] -redox-system = {path = "../system/"} +spin = "*" +syscall = {path = "../../syscall/"} + +[target.'cfg(unix)'.dependencies] fuse = "0.2" time = "*" diff --git a/scheme/cache/mod.rs b/scheme/cache/mod.rs index 0798592a06..3df653b21d 100644 --- a/scheme/cache/mod.rs +++ b/scheme/cache/mod.rs @@ -2,7 +2,7 @@ use std::{cmp, ptr}; use redoxfs::Disk; -use system::error::Result; +use syscall::error::Result; use self::lru_cache::LruCache; diff --git a/scheme/image.rs b/scheme/image.rs index 169727095b..b589c5cb69 100644 --- a/scheme/image.rs +++ b/scheme/image.rs @@ -3,7 +3,7 @@ use std::io::{Read, Write, Seek, SeekFrom}; use redoxfs::Disk; -use system::error::{Error, Result, EIO}; +use syscall::error::{Error, Result, EIO}; macro_rules! try_disk { ($expr:expr) => (match $expr { diff --git a/scheme/main.rs b/scheme/main.rs index e82005a9a9..d739091a64 100644 --- a/scheme/main.rs +++ b/scheme/main.rs @@ -1,16 +1,16 @@ #![deny(warnings)] extern crate redoxfs; - -extern crate system; +extern crate spin; +extern crate syscall; use std::env; use std::fs::File; use std::io::{Read, Write}; use std::mem::size_of; -use std::sync::{Arc, Mutex}; +use std::sync::Arc; use std::thread; -use std::time::Duration; +use spin::Mutex; use cache::Cache; use image::Image; @@ -18,7 +18,7 @@ use scheme::FileScheme; use redoxfs::FileSystem; -use system::scheme::{Packet, Scheme}; +use syscall::{Packet, Scheme}; pub mod cache; pub mod image; @@ -43,9 +43,9 @@ fn main() { Ok(mut socket) => { println!("redoxfs: mounted filesystem {} on file:", path); - *status_daemon.lock().unwrap() = Status::Running; + *status_daemon.lock() = Status::Running; - let mut scheme = FileScheme::new(fs); + let scheme = FileScheme::new(fs); loop { let mut packet = Packet::default(); while socket.read(&mut packet).unwrap() == size_of::() { @@ -61,17 +61,17 @@ fn main() { Err(err) => println!("redoxfs: failed to open image {}: {}", path, err) } - *status_daemon.lock().unwrap() = Status::Stopping; + *status_daemon.lock() = Status::Stopping; }); 'waiting: loop { - match *status_mutex.lock().unwrap() { + match *status_mutex.lock() { Status::Starting => (), Status::Running => break 'waiting, Status::Stopping => break 'waiting, } - thread::sleep(Duration::new(0, 30000000)); + thread::yield_now(); } } else { println!("redoxfs: no disk image provided"); diff --git a/scheme/resource.rs b/scheme/resource.rs index 9f4071302e..4a584eba5f 100644 --- a/scheme/resource.rs +++ b/scheme/resource.rs @@ -2,8 +2,8 @@ use redoxfs::FileSystem; use std::cmp::{min, max}; -use system::error::{Error, Result, EINVAL}; -use system::syscall::{Stat, SEEK_SET, SEEK_CUR, SEEK_END, MODE_DIR, MODE_FILE}; +use syscall::error::{Error, Result, EINVAL}; +use syscall::{Stat, SEEK_SET, SEEK_CUR, SEEK_END, MODE_DIR, MODE_FILE}; pub trait Resource { fn dup(&self) -> Result>; @@ -17,15 +17,15 @@ pub trait Resource { } pub struct DirResource { - path: String, + path: Vec, data: Vec, seek: usize, } impl DirResource { - pub fn new(path: &str, data: Vec) -> DirResource { + pub fn new(path: &[u8], data: Vec) -> DirResource { DirResource { - path: path.to_string(), + path: path.to_vec(), data: data, seek: 0, } @@ -67,9 +67,8 @@ impl Resource for DirResource { fn path(&self, buf: &mut [u8]) -> Result { let mut i = 0; - let path = self.path.as_bytes(); - while i < buf.len() && i < path.len() { - buf[i] = path[i]; + while i < buf.len() && i < self.path.len() { + buf[i] = self.path[i]; i += 1; } Ok(i) @@ -91,16 +90,16 @@ impl Resource for DirResource { } pub struct FileResource { - path: String, + path: Vec, block: u64, seek: u64, size: u64, } impl FileResource { - pub fn new(path: &str, block: u64, size: u64) -> FileResource { + pub fn new(path: &[u8], block: u64, size: u64) -> FileResource { FileResource { - path: path.to_string(), + path: path.to_vec(), block: block, seek: 0, size: size, @@ -146,9 +145,8 @@ impl Resource for FileResource { fn path(&self, buf: &mut [u8]) -> Result { let mut i = 0; - let path = self.path.as_bytes(); - while i < buf.len() && i < path.len() { - buf[i] = path[i]; + while i < buf.len() && i < self.path.len() { + buf[i] = self.path[i]; i += 1; } Ok(i) diff --git a/scheme/scheme.rs b/scheme/scheme.rs index 7deb198b79..627ced349f 100644 --- a/scheme/scheme.rs +++ b/scheme/scheme.rs @@ -1,41 +1,46 @@ use resource::{Resource, DirResource, FileResource}; use redoxfs::{FileSystem, Node}; - +use spin::Mutex; +use std::cell::RefCell; use std::collections::BTreeMap; +use std::str; +use std::sync::atomic::{AtomicUsize, Ordering}; -use system::error::{Error, Result, EEXIST, EISDIR, ENOTDIR, EPERM, ENOENT, EBADF}; -use system::scheme::Scheme; -use system::syscall::{Stat, O_CREAT, O_TRUNC}; +use syscall::error::{Error, Result, EEXIST, EISDIR, ENOTDIR, EPERM, ENOENT, EBADF}; +use syscall::scheme::Scheme; +use syscall::{Stat, O_CREAT, O_TRUNC}; pub struct FileScheme { - fs: FileSystem, - next_id: isize, - files: BTreeMap> + fs: RefCell, + next_id: AtomicUsize, + files: Mutex>> } impl FileScheme { pub fn new(fs: FileSystem) -> FileScheme { FileScheme { - fs: fs, - next_id: 1, - files: BTreeMap::new() + fs: RefCell::new(fs), + next_id: AtomicUsize::new(1), + files: Mutex::new(BTreeMap::new()) } } - fn open_inner(&mut self, url: &str, flags: usize) -> Result> { - let path = url.split(':').nth(1).unwrap_or("").trim_matches('/'); + fn open_inner(&self, url: &[u8], flags: usize) -> Result> { + let path = str::from_utf8(url).unwrap_or("").trim_matches('/'); // println!("Open '{}' {:X}", path, flags); + let mut fs = self.fs.borrow_mut(); + let mut nodes = Vec::new(); - let node_result = self.fs.path_nodes(path, &mut nodes); + let node_result = fs.path_nodes(path, &mut nodes); match node_result { Ok(node) => if node.1.is_dir() { let mut data = Vec::new(); let mut children = Vec::new(); - try!(self.fs.child_nodes(&mut children, node.0)); + try!(fs.child_nodes(&mut children, node.0)); for child in children.iter() { if let Ok(name) = child.1.name() { if ! data.is_empty() { @@ -51,9 +56,9 @@ impl FileScheme { } else { if flags & O_TRUNC == O_TRUNC { // println!("Truncate {}", path); - try!(self.fs.node_set_len(node.0, 0)); + try!(fs.node_set_len(node.0, 0)); } - let size = try!(self.fs.node_len(node.0)); + let size = try!(fs.node_len(node.0)); return Ok(Box::new(FileResource::new(url, node.0, size))); }, Err(err) => if err.errno == ENOENT && flags & O_CREAT == O_CREAT { @@ -65,7 +70,7 @@ impl FileScheme { } if ! last_part.is_empty() { if let Some(parent) = nodes.last() { - let node = try!(self.fs.create_node(Node::MODE_FILE, &last_part, parent.0)); + let node = try!(fs.create_node(Node::MODE_FILE, &last_part, parent.0)); return Ok(Box::new(FileResource::new(url, node.0, 0))); } else { return Err(Error::new(EPERM)); @@ -81,27 +86,24 @@ impl FileScheme { } impl Scheme for FileScheme { - fn open(&mut self, url: &str, flags: usize) -> Result { + fn open(&self, url: &[u8], flags: usize) -> Result { let resource = try!(self.open_inner(url, flags)); - let id = self.next_id as usize; - self.next_id += 1; - if self.next_id < 0 { - self.next_id = 1; - } - - self.files.insert(id, resource); + let id = self.next_id.fetch_add(1, Ordering::SeqCst); + self.files.lock().insert(id, resource); Ok(id) } - fn mkdir(&mut self, url: &str, _mode: usize) -> Result { - let path = url.split(':').nth(1).unwrap_or("").trim_matches('/'); + fn mkdir(&self, url: &[u8], _mode: usize) -> Result { + let path = str::from_utf8(url).unwrap_or("").trim_matches('/'); // println!("Mkdir '{}'", path); + let mut fs = self.fs.borrow_mut(); + let mut nodes = Vec::new(); - match self.fs.path_nodes(path, &mut nodes) { + match fs.path_nodes(path, &mut nodes) { Ok(_node) => Err(Error::new(EEXIST)), Err(err) => if err.errno == ENOENT { let mut last_part = String::new(); @@ -112,7 +114,7 @@ impl Scheme for FileScheme { } if ! last_part.is_empty() { if let Some(parent) = nodes.last() { - self.fs.create_node(Node::MODE_DIR, &last_part, parent.0).and(Ok(0)) + fs.create_node(Node::MODE_DIR, &last_part, parent.0).and(Ok(0)) } else { Err(Error::new(EPERM)) } @@ -125,17 +127,19 @@ impl Scheme for FileScheme { } } - fn rmdir(&mut self, url: &str) -> Result { - let path = url.split(':').nth(1).unwrap_or("").trim_matches('/'); + fn rmdir(&self, url: &[u8]) -> Result { + let path = str::from_utf8(url).unwrap_or("").trim_matches('/'); // println!("Rmdir '{}'", path); + let mut fs = self.fs.borrow_mut(); + let mut nodes = Vec::new(); - let child = try!(self.fs.path_nodes(path, &mut nodes)); + let child = try!(fs.path_nodes(path, &mut nodes)); if let Some(parent) = nodes.last() { if child.1.is_dir() { if let Ok(child_name) = child.1.name() { - self.fs.remove_node(Node::MODE_DIR, child_name, parent.0).and(Ok(0)) + fs.remove_node(Node::MODE_DIR, child_name, parent.0).and(Ok(0)) } else { Err(Error::new(ENOENT)) } @@ -147,22 +151,19 @@ impl Scheme for FileScheme { } } - fn stat(&mut self, url: &str, stat: &mut Stat) -> Result { - let resource = try!(self.open_inner(url, 0)); - resource.stat(stat) - } - - fn unlink(&mut self, url: &str) -> Result { - let path = url.split(':').nth(1).unwrap_or("").trim_matches('/'); + fn unlink(&self, url: &[u8]) -> Result { + let path = str::from_utf8(url).unwrap_or("").trim_matches('/'); // println!("Unlink '{}'", path); + let mut fs = self.fs.borrow_mut(); + let mut nodes = Vec::new(); - let child = try!(self.fs.path_nodes(path, &mut nodes)); + let child = try!(fs.path_nodes(path, &mut nodes)); if let Some(parent) = nodes.last() { if ! child.1.is_dir() { if let Ok(child_name) = child.1.name() { - self.fs.remove_node(Node::MODE_FILE, child_name, parent.0).and(Ok(0)) + fs.remove_node(Node::MODE_FILE, child_name, parent.0).and(Ok(0)) } else { Err(Error::new(ENOENT)) } @@ -176,44 +177,43 @@ impl Scheme for FileScheme { /* Resource operations */ #[allow(unused_variables)] - fn dup(&mut self, old_id: usize) -> Result { + fn dup(&self, old_id: usize) -> Result { // println!("Dup {}", old_id); - let resource = try!(try!(self.files.get(&old_id).ok_or(Error::new(EBADF))).dup()); + let mut files = self.files.lock(); + let resource = try!(try!(files.get(&old_id).ok_or(Error::new(EBADF))).dup()); - let id = self.next_id as usize; - self.next_id += 1; - if self.next_id < 0 { - self.next_id = 1; - } - - self.files.insert(id, resource); + let id = self.next_id.fetch_add(1, Ordering::SeqCst); + files.insert(id, resource); Ok(id) } #[allow(unused_variables)] - fn read(&mut self, id: usize, buf: &mut [u8]) -> Result { + fn read(&self, id: usize, buf: &mut [u8]) -> Result { // println!("Read {}, {:X} {}", id, buf.as_ptr() as usize, buf.len()); - if let Some(mut file) = self.files.get_mut(&id) { - file.read(buf, &mut self.fs) + let mut files = self.files.lock(); + if let Some(mut file) = files.get_mut(&id) { + file.read(buf, &mut self.fs.borrow_mut()) } else { Err(Error::new(EBADF)) } } - fn write(&mut self, id: usize, buf: &[u8]) -> Result { + fn write(&self, id: usize, buf: &[u8]) -> Result { // println!("Write {}, {:X} {}", id, buf.as_ptr() as usize, buf.len()); - if let Some(mut file) = self.files.get_mut(&id) { - file.write(buf, &mut self.fs) + let mut files = self.files.lock(); + if let Some(mut file) = files.get_mut(&id) { + file.write(buf, &mut self.fs.borrow_mut()) } else { Err(Error::new(EBADF)) } } - fn seek(&mut self, id: usize, pos: usize, whence: usize) -> Result { + fn seek(&self, id: usize, pos: usize, whence: usize) -> Result { // println!("Seek {}, {} {}", id, pos, whence); - if let Some(mut file) = self.files.get_mut(&id) { + let mut files = self.files.lock(); + if let Some(mut file) = files.get_mut(&id) { file.seek(pos, whence) } else { Err(Error::new(EBADF)) @@ -222,7 +222,8 @@ impl Scheme for FileScheme { fn fpath(&self, id: usize, buf: &mut [u8]) -> Result { // println!("Fpath {}, {:X} {}", id, buf.as_ptr() as usize, buf.len()); - if let Some(file) = self.files.get(&id) { + let files = self.files.lock(); + if let Some(file) = files.get(&id) { file.path(buf) } else { Err(Error::new(EBADF)) @@ -231,34 +232,38 @@ impl Scheme for FileScheme { fn fstat(&self, id: usize, stat: &mut Stat) -> Result { // println!("Fstat {}, {:X}", id, stat as *mut Stat as usize); - if let Some(file) = self.files.get(&id) { + let files = self.files.lock(); + if let Some(file) = files.get(&id) { file.stat(stat) } else { Err(Error::new(EBADF)) } } - fn fsync(&mut self, id: usize) -> Result { + fn fsync(&self, id: usize) -> Result { // println!("Fsync {}", id); - if let Some(mut file) = self.files.get_mut(&id) { + let mut files = self.files.lock(); + if let Some(mut file) = files.get_mut(&id) { file.sync() } else { Err(Error::new(EBADF)) } } - fn ftruncate(&mut self, id: usize, len: usize) -> Result { + fn ftruncate(&self, id: usize, len: usize) -> Result { // println!("Ftruncate {}, {}", id, len); - if let Some(mut file) = self.files.get_mut(&id) { - file.truncate(len, &mut self.fs) + let mut files = self.files.lock(); + if let Some(mut file) = files.get_mut(&id) { + file.truncate(len, &mut self.fs.borrow_mut()) } else { Err(Error::new(EBADF)) } } - fn close(&mut self, id: usize) -> Result { + fn close(&self, id: usize) -> Result { // println!("Close {}", id); - if self.files.remove(&id).is_some() { + let mut files = self.files.lock(); + if files.remove(&id).is_some() { Ok(0) } else { Err(Error::new(EBADF)) diff --git a/src/disk.rs b/src/disk.rs index 75a9e58ae8..e345ee82cf 100644 --- a/src/disk.rs +++ b/src/disk.rs @@ -1,4 +1,4 @@ -use system::error::Result; +use syscall::error::Result; /// A disk pub trait Disk { diff --git a/src/filesystem.rs b/src/filesystem.rs index bd2b96c8bf..1c36f83b29 100644 --- a/src/filesystem.rs +++ b/src/filesystem.rs @@ -1,6 +1,6 @@ use std::cmp::min; -use system::error::{Result, Error, EEXIST, EISDIR, ENOENT, ENOSPC, ENOTDIR, ENOTEMPTY}; +use syscall::error::{Result, Error, EEXIST, EISDIR, ENOENT, ENOSPC, ENOTDIR, ENOTEMPTY}; use super::{Disk, ExNode, Extent, Header, Node}; diff --git a/src/lib.rs b/src/lib.rs index fcf352966f..f4106c3994 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,7 +4,7 @@ #![deny(warnings)] -extern crate system; +extern crate syscall; pub use self::disk::Disk; pub use self::ex_node::ExNode; From 9bd5d69776e2df6a831e775631549aafcc5597af Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 27 Sep 2016 21:55:57 -0600 Subject: [PATCH 2/9] Compatibility with new kernel --- fuse/image.rs | 3 +-- fuse/main.rs | 2 +- scheme/main.rs | 9 +++++---- src/filesystem.rs | 2 +- utility/image.rs | 3 +-- utility/main.rs | 3 +-- 6 files changed, 10 insertions(+), 12 deletions(-) diff --git a/fuse/image.rs b/fuse/image.rs index ae8bf6f88a..cb1356aadb 100644 --- a/fuse/image.rs +++ b/fuse/image.rs @@ -2,8 +2,7 @@ use std::fs::{File, OpenOptions}; use std::io::{Read, Write, Seek, SeekFrom}; use redoxfs::Disk; - -use system::error::{Error, Result, EIO}; +use syscall::error::{Error, Result, EIO}; macro_rules! try_disk { ($expr:expr) => (match $expr { diff --git a/fuse/main.rs b/fuse/main.rs index 99f6b76ae8..0e01b11c85 100644 --- a/fuse/main.rs +++ b/fuse/main.rs @@ -2,7 +2,7 @@ extern crate fuse; extern crate redoxfs; -extern crate system; +extern crate syscall; extern crate time; use image::Image; diff --git a/scheme/main.rs b/scheme/main.rs index d739091a64..d3a7a51455 100644 --- a/scheme/main.rs +++ b/scheme/main.rs @@ -48,10 +48,11 @@ fn main() { let scheme = FileScheme::new(fs); loop { let mut packet = Packet::default(); - while socket.read(&mut packet).unwrap() == size_of::() { - scheme.handle(&mut packet); - socket.write(&packet).unwrap(); - } + socket.read(&mut packet).unwrap(); + println!("file: {:?}", packet); + scheme.handle(&mut packet); + println!("file: ={}", packet.a); + socket.write(&packet).unwrap(); } }, Err(err) => println!("redoxfs: failed to create file scheme: {}", err) diff --git a/src/filesystem.rs b/src/filesystem.rs index 1c36f83b29..9c77d15714 100644 --- a/src/filesystem.rs +++ b/src/filesystem.rs @@ -14,7 +14,7 @@ pub struct FileSystem { impl FileSystem { /// Open a file system on a disk pub fn open(mut disk: Box) -> Result { - for block in 0..8192 { + for block in 0..65536 { let mut header = (0, Header::default()); try!(disk.read_at(block + header.0, &mut header.1)); diff --git a/utility/image.rs b/utility/image.rs index ae8bf6f88a..cb1356aadb 100644 --- a/utility/image.rs +++ b/utility/image.rs @@ -2,8 +2,7 @@ use std::fs::{File, OpenOptions}; use std::io::{Read, Write, Seek, SeekFrom}; use redoxfs::Disk; - -use system::error::{Error, Result, EIO}; +use syscall::error::{Error, Result, EIO}; macro_rules! try_disk { ($expr:expr) => (match $expr { diff --git a/utility/main.rs b/utility/main.rs index b8c0b471e2..9fe6c439c0 100644 --- a/utility/main.rs +++ b/utility/main.rs @@ -1,8 +1,7 @@ #![deny(warnings)] extern crate redoxfs; - -extern crate system; +extern crate syscall; use std::env; use std::io::{self, Write}; From 9c16bca2a56fea005c0bc16d9411adc590e0bbf8 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 28 Sep 2016 08:58:51 -0600 Subject: [PATCH 3/9] Fix warning --- scheme/main.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/scheme/main.rs b/scheme/main.rs index d3a7a51455..7d7d83fa34 100644 --- a/scheme/main.rs +++ b/scheme/main.rs @@ -7,7 +7,6 @@ extern crate syscall; use std::env; use std::fs::File; use std::io::{Read, Write}; -use std::mem::size_of; use std::sync::Arc; use std::thread; use spin::Mutex; From 36b3cf04a9d35b85d481acdf99494fc535152cf0 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 28 Sep 2016 10:27:32 -0600 Subject: [PATCH 4/9] Add name to fpath --- scheme/main.rs | 4 +--- scheme/scheme.rs | 34 +++++++++++++++++++++++++--------- 2 files changed, 26 insertions(+), 12 deletions(-) diff --git a/scheme/main.rs b/scheme/main.rs index 7d7d83fa34..944223807e 100644 --- a/scheme/main.rs +++ b/scheme/main.rs @@ -44,13 +44,11 @@ fn main() { *status_daemon.lock() = Status::Running; - let scheme = FileScheme::new(fs); + let scheme = FileScheme::new("file", fs); loop { let mut packet = Packet::default(); socket.read(&mut packet).unwrap(); - println!("file: {:?}", packet); scheme.handle(&mut packet); - println!("file: ={}", packet.a); socket.write(&packet).unwrap(); } }, diff --git a/scheme/scheme.rs b/scheme/scheme.rs index 627ced349f..f284f35b62 100644 --- a/scheme/scheme.rs +++ b/scheme/scheme.rs @@ -12,14 +12,16 @@ use syscall::scheme::Scheme; use syscall::{Stat, O_CREAT, O_TRUNC}; pub struct FileScheme { + name: &'static str, fs: RefCell, next_id: AtomicUsize, files: Mutex>> } impl FileScheme { - pub fn new(fs: FileSystem) -> FileScheme { + pub fn new(name: &'static str, fs: FileSystem) -> FileScheme { FileScheme { + name: name, fs: RefCell::new(fs), next_id: AtomicUsize::new(1), files: Mutex::new(BTreeMap::new()) @@ -29,7 +31,7 @@ impl FileScheme { fn open_inner(&self, url: &[u8], flags: usize) -> Result> { let path = str::from_utf8(url).unwrap_or("").trim_matches('/'); - // println!("Open '{}' {:X}", path, flags); + //println!("Open '{}' {:X}", path, flags); let mut fs = self.fs.borrow_mut(); @@ -47,12 +49,9 @@ impl FileScheme { data.push(b'\n'); } data.extend_from_slice(&name.as_bytes()); - if child.1.is_dir() { - data.push(b'/'); - } } } - return Ok(Box::new(DirResource::new(url, data))); + return Ok(Box::new(DirResource::new(path.as_bytes(), data))); } else { if flags & O_TRUNC == O_TRUNC { // println!("Truncate {}", path); @@ -71,7 +70,7 @@ impl FileScheme { if ! last_part.is_empty() { if let Some(parent) = nodes.last() { let node = try!(fs.create_node(Node::MODE_FILE, &last_part, parent.0)); - return Ok(Box::new(FileResource::new(url, node.0, 0))); + return Ok(Box::new(FileResource::new(path.as_bytes(), node.0, 0))); } else { return Err(Error::new(EPERM)); } @@ -181,7 +180,11 @@ impl Scheme for FileScheme { // println!("Dup {}", old_id); let mut files = self.files.lock(); - let resource = try!(try!(files.get(&old_id).ok_or(Error::new(EBADF))).dup()); + let resource = if let Some(old_resource) = files.get(&old_id) { + try!(old_resource.dup()) + } else { + return Err(Error::new(EBADF)); + }; let id = self.next_id.fetch_add(1, Ordering::SeqCst); files.insert(id, resource); @@ -224,7 +227,20 @@ impl Scheme for FileScheme { // println!("Fpath {}, {:X} {}", id, buf.as_ptr() as usize, buf.len()); let files = self.files.lock(); if let Some(file) = files.get(&id) { - file.path(buf) + let name = self.name.as_bytes(); + let mut i = 0; + while i < buf.len() && i < name.len() { + buf[i] = name[i]; + i += 1; + } + if i < buf.len() { + buf[i] = b':'; + i += 1; + } + match file.path(&mut buf[i..]) { + Ok(count) => Ok(i + count), + Err(err) => Err(err) + } } else { Err(Error::new(EBADF)) } From 1488d1ef5661496aff695f2e1bf67997d4654329 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 28 Sep 2016 20:41:45 -0600 Subject: [PATCH 5/9] 64-bit stat size --- scheme/resource.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scheme/resource.rs b/scheme/resource.rs index 4a584eba5f..f506c018f7 100644 --- a/scheme/resource.rs +++ b/scheme/resource.rs @@ -76,7 +76,7 @@ impl Resource for DirResource { fn stat(&self, stat: &mut Stat) -> Result { stat.st_mode = MODE_DIR; - stat.st_size = self.data.len() as u32; + stat.st_size = self.data.len() as u64; Ok(0) } @@ -154,7 +154,7 @@ impl Resource for FileResource { fn stat(&self, stat: &mut Stat) -> Result { stat.st_mode = MODE_FILE; - stat.st_size = self.size as u32; + stat.st_size = self.size as u64; Ok(0) } From 33f218aadb5cf43c678dfc247fef8803e53538a6 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 5 Oct 2016 12:13:45 -0600 Subject: [PATCH 6/9] WIP: Permissions support --- fuse/main.rs | 191 +++++++++++++++++++++------------------------- src/filesystem.rs | 4 +- src/node.rs | 22 +++--- utility/main.rs | 7 +- 4 files changed, 102 insertions(+), 122 deletions(-) diff --git a/fuse/main.rs b/fuse/main.rs index 0e01b11c85..b31d02cd2f 100644 --- a/fuse/main.rs +++ b/fuse/main.rs @@ -21,30 +21,34 @@ struct RedoxFS { fs: redoxfs::FileSystem, } +fn node_attr(node: &(u64, redoxfs::Node)) -> FileAttr { + FileAttr { + ino: node.0, + size: node.1.extents[0].length, + blocks: (node.1.extents[0].length + 511)/512, + atime: CREATE_TIME, + mtime: CREATE_TIME, + ctime: CREATE_TIME, + crtime: CREATE_TIME, + kind: if node.1.is_dir() { + FileType::Directory + } else { + FileType::RegularFile + }, + perm: node.1.mode & redoxfs::Node::MODE_PERM, + nlink: 1, + uid: node.1.uid, + gid: node.1.gid, + rdev: 0, + flags: 0, + } +} + impl Filesystem for RedoxFS { fn lookup(&mut self, _req: &Request, parent_block: u64, name: &Path, reply: ReplyEntry) { match self.fs.find_node(name.to_str().unwrap(), parent_block) { Ok(node) => { - reply.entry(&TTL, &FileAttr { - ino: node.0, - size: node.1.extents[0].length, - blocks: (node.1.extents[0].length + 511)/512, - atime: CREATE_TIME, - mtime: CREATE_TIME, - ctime: CREATE_TIME, - crtime: CREATE_TIME, - kind: if node.1.is_dir() { - FileType::Directory - } else { - FileType::RegularFile - }, - perm: 0o777, - nlink: 1, - uid: 0, - gid: 0, - rdev: 0, - flags: 0, - }, 0); + reply.entry(&TTL, &node_attr(&node), 0); }, Err(err) => { reply.error(err.errno as i32); @@ -55,26 +59,7 @@ impl Filesystem for RedoxFS { fn getattr(&mut self, _req: &Request, block: u64, reply: ReplyAttr) { match self.fs.node(block) { Ok(node) => { - reply.attr(&TTL, &FileAttr { - ino: node.0, - size: node.1.extents[0].length, - blocks: (node.1.extents[0].length + 511)/512, - atime: CREATE_TIME, - mtime: CREATE_TIME, - ctime: CREATE_TIME, - crtime: CREATE_TIME, - kind: if node.1.is_dir() { - FileType::Directory - } else { - FileType::RegularFile - }, - perm: 0o777, - nlink: 1, - uid: 0, - gid: 0, - rdev: 0, - flags: 0, - }); + reply.attr(&TTL, &node_attr(&node)); }, Err(err) => { reply.error(err.errno as i32); @@ -82,39 +67,69 @@ impl Filesystem for RedoxFS { } } - fn setattr(&mut self, _req: &Request, block: u64, _mode: Option, - _uid: Option, _gid: Option, size: Option, + fn setattr(&mut self, _req: &Request, block: u64, mode: Option, + uid: Option, gid: Option, size: Option, _atime: Option, _mtime: Option, _fh: Option, _crtime: Option, _chgtime: Option, _bkuptime: Option, _flags: Option, reply: ReplyAttr) { + if let Some(mode) = mode { + match self.fs.node(block) { + Ok(mut node) => if node.1.mode & redoxfs::Node::MODE_PERM != mode as u16 & redoxfs::Node::MODE_PERM { + node.1.mode = (node.1.mode & ! redoxfs::Node::MODE_PERM) | (mode as u16 & redoxfs::Node::MODE_PERM); + if let Err(err) = self.fs.write_at(node.0, &node.1) { + reply.error(err.errno as i32); + return; + } + }, + Err(err) => { + reply.error(err.errno as i32); + return; + } + } + } + + if let Some(uid) = uid { + match self.fs.node(block) { + Ok(mut node) => if node.1.uid != uid { + node.1.uid = uid; + if let Err(err) = self.fs.write_at(node.0, &node.1) { + reply.error(err.errno as i32); + return; + } + }, + Err(err) => { + reply.error(err.errno as i32); + return; + } + } + } + + if let Some(gid) = gid { + match self.fs.node(block) { + Ok(mut node) => if node.1.gid != gid { + node.1.gid = gid; + if let Err(err) = self.fs.write_at(node.0, &node.1) { + reply.error(err.errno as i32); + return; + } + }, + Err(err) => { + reply.error(err.errno as i32); + return; + } + } + } + if let Some(truncate_size) = size { if let Err(err) = self.fs.node_set_len(block, truncate_size) { reply.error(err.errno as i32); return; } } + match self.fs.node(block) { Ok(node) => { - reply.attr(&TTL, &FileAttr { - ino: node.0, - size: node.1.extents[0].length, - blocks: (node.1.extents[0].length + 511)/512, - atime: CREATE_TIME, - mtime: CREATE_TIME, - ctime: CREATE_TIME, - crtime: CREATE_TIME, - kind: if node.1.is_dir() { - FileType::Directory - } else { - FileType::RegularFile - }, - perm: 0o777, - nlink: 1, - uid: 0, - gid: 0, - rdev: 0, - flags: 0, - }); + reply.attr(&TTL, &node_attr(&node)); }, Err(err) => { reply.error(err.errno as i32); @@ -180,29 +195,11 @@ impl Filesystem for RedoxFS { } } - fn create(&mut self, _req: &Request, parent_block: u64, name: &Path, _mode: u32, flags: u32, reply: ReplyCreate) { - match self.fs.create_node(redoxfs::Node::MODE_FILE, name.to_str().unwrap(), parent_block) { + fn create(&mut self, _req: &Request, parent_block: u64, name: &Path, mode: u32, flags: u32, reply: ReplyCreate) { + match self.fs.create_node(redoxfs::Node::MODE_FILE | (mode as u16 & redoxfs::Node::MODE_PERM), name.to_str().unwrap(), parent_block) { Ok(node) => { - reply.created(&TTL, &FileAttr { - ino: node.0, - size: node.1.extents[0].length, - blocks: (node.1.extents[0].length + 511)/512, - atime: CREATE_TIME, - mtime: CREATE_TIME, - ctime: CREATE_TIME, - crtime: CREATE_TIME, - kind: if node.1.is_dir() { - FileType::Directory - } else { - FileType::RegularFile - }, - perm: 0o777, - nlink: 1, - uid: 0, - gid: 0, - rdev: 0, - flags: 0, - }, 0, 0, flags); + println!("Create {:?}:{:o}:{:o}", node.1.name(), node.1.mode, mode); + reply.created(&TTL, &node_attr(&node), 0, 0, flags); }, Err(error) => { reply.error(error.errno as i32); @@ -210,29 +207,11 @@ impl Filesystem for RedoxFS { } } - fn mkdir(&mut self, _req: &Request, parent_block: u64, name: &Path, _mode: u32, reply: ReplyEntry) { - match self.fs.create_node(redoxfs::Node::MODE_DIR, name.to_str().unwrap(), parent_block) { + fn mkdir(&mut self, _req: &Request, parent_block: u64, name: &Path, mode: u32, reply: ReplyEntry) { + match self.fs.create_node(redoxfs::Node::MODE_DIR | (mode as u16 & redoxfs::Node::MODE_PERM), name.to_str().unwrap(), parent_block) { Ok(node) => { - reply.entry(&TTL, &FileAttr { - ino: node.0, - size: node.1.extents[0].length, - blocks: (node.1.extents[0].length + 511)/512, - atime: CREATE_TIME, - mtime: CREATE_TIME, - ctime: CREATE_TIME, - crtime: CREATE_TIME, - kind: if node.1.is_dir() { - FileType::Directory - } else { - FileType::RegularFile - }, - perm: 0o777, - nlink: 1, - uid: 0, - gid: 0, - rdev: 0, - flags: 0, - }, 0); + println!("Mkdir {:?}:{:o}:{:o}", node.1.name(), node.1.mode, mode); + reply.entry(&TTL, &node_attr(&node), 0); }, Err(error) => { reply.error(error.errno as i32); diff --git a/src/filesystem.rs b/src/filesystem.rs index 9c77d15714..d540e5ff12 100644 --- a/src/filesystem.rs +++ b/src/filesystem.rs @@ -61,11 +61,11 @@ impl FileSystem { } } - fn read_at(&mut self, block: u64, buffer: &mut [u8]) -> Result { + pub fn read_at(&mut self, block: u64, buffer: &mut [u8]) -> Result { self.disk.read_at(self.block + block, buffer) } - fn write_at(&mut self, block: u64, buffer: &[u8]) -> Result { + pub fn write_at(&mut self, block: u64, buffer: &[u8]) -> Result { self.disk.write_at(self.block + block, buffer) } diff --git a/src/node.rs b/src/node.rs index 57e4c1192d..90dd86ef94 100644 --- a/src/node.rs +++ b/src/node.rs @@ -6,9 +6,9 @@ use super::Extent; #[repr(packed)] pub struct Node { pub mode: u16, - pub user: u16, - pub group: u16, - pub name: [u8; 250], + pub uid: u32, + pub gid: u32, + pub name: [u8; 246], pub parent: u64, pub next: u64, pub extents: [Extent; 15], @@ -24,9 +24,9 @@ impl Node { pub fn default() -> Node { Node { mode: 0, - user: 0, - group: 0, - name: [0; 250], + uid: 0, + gid: 0, + name: [0; 246], parent: 0, next: 0, extents: [Extent::default(); 15], @@ -34,15 +34,15 @@ impl Node { } pub fn new(mode: u16, name: &str, parent: u64) -> Node { - let mut bytes = [0; 250]; + let mut bytes = [0; 246]; for (mut b, c) in bytes.iter_mut().zip(name.bytes()) { *b = c; } Node { mode: mode, - user: 0, - group: 0, + uid: 0, + gid: 0, name: bytes, parent: parent, next: 0, @@ -81,8 +81,8 @@ impl fmt::Debug for Node { let extents: Vec<&Extent> = self.extents.iter().filter(|extent| -> bool { extent.length > 0 }).collect(); f.debug_struct("Node") .field("mode", &self.mode) - .field("user", &self.user) - .field("group", &self.group) + .field("uid", &self.uid) + .field("gid", &self.gid) .field("name", &self.name()) .field("next", &self.next) .field("extents", &extents) diff --git a/utility/main.rs b/utility/main.rs index 9fe6c439c0..3331893981 100644 --- a/utility/main.rs +++ b/utility/main.rs @@ -217,9 +217,8 @@ fn main() { }, Err(err) => println!("redoxfs: failed to open image {}: {}", path, err) } - }else{ - //Create a 256 MB disk image - let size = 256 * 1024 * 1024; + }else if let Some(size_str) = args.next() { + let size = size_str.parse::().expect("redoxfs: size is not a valid number") * 1024 * 1024; match Image::create(&path, size) { Ok(disk) => match FileSystem::create(Box::new(disk)) { Ok(filesystem) => { @@ -230,6 +229,8 @@ fn main() { }, Err(err) => println!("redoxfs: failed to create image {}: {}", path, err) } + } else { + println!("redoxfs: no size provided"); } } else { println!("redoxfs: no disk image provided"); From c06edb232b48024a7a8e468dd5316d5b28a3eac9 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 5 Oct 2016 14:07:31 -0600 Subject: [PATCH 7/9] Lookup uid, gid, and mode from block for stat --- fuse/main.rs | 4 +- scheme/resource.rs | 99 ++++++++++++++++++++++++++-------------------- scheme/scheme.rs | 18 ++++----- 3 files changed, 66 insertions(+), 55 deletions(-) diff --git a/fuse/main.rs b/fuse/main.rs index b31d02cd2f..adcb11ca08 100644 --- a/fuse/main.rs +++ b/fuse/main.rs @@ -198,7 +198,7 @@ impl Filesystem for RedoxFS { fn create(&mut self, _req: &Request, parent_block: u64, name: &Path, mode: u32, flags: u32, reply: ReplyCreate) { match self.fs.create_node(redoxfs::Node::MODE_FILE | (mode as u16 & redoxfs::Node::MODE_PERM), name.to_str().unwrap(), parent_block) { Ok(node) => { - println!("Create {:?}:{:o}:{:o}", node.1.name(), node.1.mode, mode); + //println!("Create {:?}:{:o}:{:o}", node.1.name(), node.1.mode, mode); reply.created(&TTL, &node_attr(&node), 0, 0, flags); }, Err(error) => { @@ -210,7 +210,7 @@ impl Filesystem for RedoxFS { fn mkdir(&mut self, _req: &Request, parent_block: u64, name: &Path, mode: u32, reply: ReplyEntry) { match self.fs.create_node(redoxfs::Node::MODE_DIR | (mode as u16 & redoxfs::Node::MODE_PERM), name.to_str().unwrap(), parent_block) { Ok(node) => { - println!("Mkdir {:?}:{:o}:{:o}", node.1.name(), node.1.mode, mode); + //println!("Mkdir {:?}:{:o}:{:o}", node.1.name(), node.1.mode, mode); reply.entry(&TTL, &node_attr(&node), 0); }, Err(error) => { diff --git a/scheme/resource.rs b/scheme/resource.rs index f506c018f7..1276515419 100644 --- a/scheme/resource.rs +++ b/scheme/resource.rs @@ -3,29 +3,31 @@ use redoxfs::FileSystem; use std::cmp::{min, max}; use syscall::error::{Error, Result, EINVAL}; -use syscall::{Stat, SEEK_SET, SEEK_CUR, SEEK_END, MODE_DIR, MODE_FILE}; +use syscall::{Stat, SEEK_SET, SEEK_CUR, SEEK_END}; pub trait Resource { fn dup(&self) -> Result>; fn read(&mut self, buf: &mut [u8], fs: &mut FileSystem) -> Result; fn write(&mut self, buf: &[u8], fs: &mut FileSystem) -> Result; - fn seek(&mut self, offset: usize, whence: usize) -> Result; + fn seek(&mut self, offset: usize, whence: usize, fs: &mut FileSystem) -> Result; fn path(&self, buf: &mut [u8]) -> Result; - fn stat(&self, _stat: &mut Stat) -> Result; + fn stat(&self, _stat: &mut Stat, fs: &mut FileSystem) -> Result; fn sync(&mut self) -> Result; fn truncate(&mut self, len: usize, fs: &mut FileSystem) -> Result; } pub struct DirResource { - path: Vec, + path: String, + block: u64, data: Vec, seek: usize, } impl DirResource { - pub fn new(path: &[u8], data: Vec) -> DirResource { + pub fn new(path: String, block: u64, data: Vec) -> DirResource { DirResource { - path: path.to_vec(), + path: path, + block: block, data: data, seek: 0, } @@ -36,6 +38,7 @@ impl Resource for DirResource { fn dup(&self) -> Result> { Ok(Box::new(DirResource { path: self.path.clone(), + block: self.block, data: self.data.clone(), seek: self.seek })) @@ -55,28 +58,37 @@ impl Resource for DirResource { Err(Error::new(EINVAL)) } - fn seek(&mut self, offset: usize, whence: usize) -> Result { - match whence { - SEEK_SET => self.seek = min(0, max(self.data.len() as isize, offset as isize)) as usize, - SEEK_CUR => self.seek = min(0, max(self.data.len() as isize, self.seek as isize + offset as isize)) as usize, - SEEK_END => self.seek = min(0, max(self.data.len() as isize, self.data.len() as isize + offset as isize)) as usize, + fn seek(&mut self, offset: usize, whence: usize, _fs: &mut FileSystem) -> Result { + self.seek = match whence { + SEEK_SET => min(0, max(self.data.len() as isize, offset as isize)) as usize, + SEEK_CUR => min(0, max(self.data.len() as isize, self.seek as isize + offset as isize)) as usize, + SEEK_END => min(0, max(self.data.len() as isize, self.data.len() as isize + offset as isize)) as usize, _ => return Err(Error::new(EINVAL)) - } + }; + Ok(self.seek) } fn path(&self, buf: &mut [u8]) -> Result { + let path = self.path.as_bytes(); + let mut i = 0; - while i < buf.len() && i < self.path.len() { - buf[i] = self.path[i]; + while i < buf.len() && i < path.len() { + buf[i] = path[i]; i += 1; } + Ok(i) } - fn stat(&self, stat: &mut Stat) -> Result { - stat.st_mode = MODE_DIR; - stat.st_size = self.data.len() as u64; + fn stat(&self, stat: &mut Stat, fs: &mut FileSystem) -> Result { + let node = try!(fs.node(self.block)); + + stat.st_mode = node.1.mode; + stat.st_uid = node.1.uid; + stat.st_gid = node.1.gid; + stat.st_size = try!(fs.node_len(self.block)); + Ok(0) } @@ -90,19 +102,17 @@ impl Resource for DirResource { } pub struct FileResource { - path: Vec, + path: String, block: u64, seek: u64, - size: u64, } impl FileResource { - pub fn new(path: &[u8], block: u64, size: u64) -> FileResource { + pub fn new(path: String, block: u64) -> FileResource { FileResource { - path: path.to_vec(), + path: path, block: block, seek: 0, - size: size, } } } @@ -113,7 +123,6 @@ impl Resource for FileResource { path: self.path.clone(), block: self.block, seek: self.seek, - size: self.size })) } @@ -126,35 +135,42 @@ impl Resource for FileResource { fn write(&mut self, buf: &[u8], fs: &mut FileSystem) -> Result { let count = try!(fs.write_node(self.block, self.seek, buf)); self.seek += count as u64; - if self.seek > self.size { - self.size = self.seek; - } Ok(count) } - fn seek(&mut self, offset: usize, whence: usize) -> Result { - match whence { - SEEK_SET => self.seek = min(0, max(self.size as i64, offset as i64)) as u64, - SEEK_CUR => self.seek = min(0, max(self.size as i64, self.seek as i64 + offset as i64)) as u64, - SEEK_END => self.seek = min(0, max(self.size as i64, self.size as i64 + offset as i64)) as u64, + fn seek(&mut self, offset: usize, whence: usize, fs: &mut FileSystem) -> Result { + let size = try!(fs.node_len(self.block)); + + self.seek = match whence { + SEEK_SET => min(0, max(size as i64, offset as i64)) as u64, + SEEK_CUR => min(0, max(size as i64, self.seek as i64 + offset as i64)) as u64, + SEEK_END => min(0, max(size as i64, size as i64 + offset as i64)) as u64, _ => return Err(Error::new(EINVAL)) - } + }; Ok(self.seek as usize) } fn path(&self, buf: &mut [u8]) -> Result { + let path = self.path.as_bytes(); + let mut i = 0; - while i < buf.len() && i < self.path.len() { - buf[i] = self.path[i]; + while i < buf.len() && i < path.len() { + buf[i] = path[i]; i += 1; } + Ok(i) } - fn stat(&self, stat: &mut Stat) -> Result { - stat.st_mode = MODE_FILE; - stat.st_size = self.size as u64; + fn stat(&self, stat: &mut Stat, fs: &mut FileSystem) -> Result { + let node = try!(fs.node(self.block)); + + stat.st_mode = node.1.mode; + stat.st_uid = node.1.uid; + stat.st_gid = node.1.gid; + stat.st_size = try!(fs.node_len(self.block)); + Ok(0) } @@ -163,11 +179,8 @@ impl Resource for FileResource { } fn truncate(&mut self, len: usize, fs: &mut FileSystem) -> Result { - if let Err(err) = fs.node_set_len(self.block, len as u64) { - Err(err) - } else { - self.size = len as u64; - Ok(0) - } + try!(fs.node_set_len(self.block, len as u64)); + + Ok(0) } } diff --git a/scheme/scheme.rs b/scheme/scheme.rs index f284f35b62..879715b2c5 100644 --- a/scheme/scheme.rs +++ b/scheme/scheme.rs @@ -51,14 +51,13 @@ impl FileScheme { data.extend_from_slice(&name.as_bytes()); } } - return Ok(Box::new(DirResource::new(path.as_bytes(), data))); + return Ok(Box::new(DirResource::new(path.to_string(), node.0, data))); } else { if flags & O_TRUNC == O_TRUNC { // println!("Truncate {}", path); try!(fs.node_set_len(node.0, 0)); } - let size = try!(fs.node_len(node.0)); - return Ok(Box::new(FileResource::new(url, node.0, size))); + return Ok(Box::new(FileResource::new(path.to_string(), node.0))); }, Err(err) => if err.errno == ENOENT && flags & O_CREAT == O_CREAT { let mut last_part = String::new(); @@ -70,7 +69,7 @@ impl FileScheme { if ! last_part.is_empty() { if let Some(parent) = nodes.last() { let node = try!(fs.create_node(Node::MODE_FILE, &last_part, parent.0)); - return Ok(Box::new(FileResource::new(path.as_bytes(), node.0, 0))); + return Ok(Box::new(FileResource::new(path.to_string(), node.0))); } else { return Err(Error::new(EPERM)); } @@ -217,7 +216,7 @@ impl Scheme for FileScheme { // println!("Seek {}, {} {}", id, pos, whence); let mut files = self.files.lock(); if let Some(mut file) = files.get_mut(&id) { - file.seek(pos, whence) + file.seek(pos, whence, &mut self.fs.borrow_mut()) } else { Err(Error::new(EBADF)) } @@ -228,6 +227,7 @@ impl Scheme for FileScheme { let files = self.files.lock(); if let Some(file) = files.get(&id) { let name = self.name.as_bytes(); + let mut i = 0; while i < buf.len() && i < name.len() { buf[i] = name[i]; @@ -237,10 +237,8 @@ impl Scheme for FileScheme { buf[i] = b':'; i += 1; } - match file.path(&mut buf[i..]) { - Ok(count) => Ok(i + count), - Err(err) => Err(err) - } + + file.path(&mut buf[i..]).map(|count| i + count) } else { Err(Error::new(EBADF)) } @@ -250,7 +248,7 @@ impl Scheme for FileScheme { // println!("Fstat {}, {:X}", id, stat as *mut Stat as usize); let files = self.files.lock(); if let Some(file) = files.get(&id) { - file.stat(stat) + file.stat(stat, &mut self.fs.borrow_mut()) } else { Err(Error::new(EBADF)) } From 3dcaad55fe6e82450c1691da5d515861a7deed0a Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 5 Oct 2016 18:00:46 -0600 Subject: [PATCH 8/9] Implement unix permissions --- fuse/main.rs | 11 +++-- scheme/scheme.rs | 119 ++++++++++++++++++++++++++++++++++++++-------- src/filesystem.rs | 2 +- src/node.rs | 17 +++++++ 4 files changed, 122 insertions(+), 27 deletions(-) diff --git a/fuse/main.rs b/fuse/main.rs index adcb11ca08..849e1718a2 100644 --- a/fuse/main.rs +++ b/fuse/main.rs @@ -75,7 +75,8 @@ impl Filesystem for RedoxFS { if let Some(mode) = mode { match self.fs.node(block) { Ok(mut node) => if node.1.mode & redoxfs::Node::MODE_PERM != mode as u16 & redoxfs::Node::MODE_PERM { - node.1.mode = (node.1.mode & ! redoxfs::Node::MODE_PERM) | (mode as u16 & redoxfs::Node::MODE_PERM); + // println!("Chmod {:?}:{:o}:{:o}", node.1.name(), node.1.mode, mode); + node.1.mode = (node.1.mode & redoxfs::Node::MODE_TYPE) | (mode as u16 & redoxfs::Node::MODE_PERM); if let Err(err) = self.fs.write_at(node.0, &node.1) { reply.error(err.errno as i32); return; @@ -120,8 +121,8 @@ impl Filesystem for RedoxFS { } } - if let Some(truncate_size) = size { - if let Err(err) = self.fs.node_set_len(block, truncate_size) { + if let Some(size) = size { + if let Err(err) = self.fs.node_set_len(block, size) { reply.error(err.errno as i32); return; } @@ -198,7 +199,7 @@ impl Filesystem for RedoxFS { fn create(&mut self, _req: &Request, parent_block: u64, name: &Path, mode: u32, flags: u32, reply: ReplyCreate) { match self.fs.create_node(redoxfs::Node::MODE_FILE | (mode as u16 & redoxfs::Node::MODE_PERM), name.to_str().unwrap(), parent_block) { Ok(node) => { - //println!("Create {:?}:{:o}:{:o}", node.1.name(), node.1.mode, mode); + // println!("Create {:?}:{:o}:{:o}", node.1.name(), node.1.mode, mode); reply.created(&TTL, &node_attr(&node), 0, 0, flags); }, Err(error) => { @@ -210,7 +211,7 @@ impl Filesystem for RedoxFS { fn mkdir(&mut self, _req: &Request, parent_block: u64, name: &Path, mode: u32, reply: ReplyEntry) { match self.fs.create_node(redoxfs::Node::MODE_DIR | (mode as u16 & redoxfs::Node::MODE_PERM), name.to_str().unwrap(), parent_block) { Ok(node) => { - //println!("Mkdir {:?}:{:o}:{:o}", node.1.name(), node.1.mode, mode); + // println!("Mkdir {:?}:{:o}:{:o}", node.1.name(), node.1.mode, mode); reply.entry(&TTL, &node_attr(&node), 0); }, Err(error) => { diff --git a/scheme/scheme.rs b/scheme/scheme.rs index 879715b2c5..64b6d8ad4f 100644 --- a/scheme/scheme.rs +++ b/scheme/scheme.rs @@ -7,7 +7,7 @@ use std::collections::BTreeMap; use std::str; use std::sync::atomic::{AtomicUsize, Ordering}; -use syscall::error::{Error, Result, EEXIST, EISDIR, ENOTDIR, EPERM, ENOENT, EBADF}; +use syscall::error::{Error, Result, EACCES, EEXIST, EISDIR, ENOTDIR, EPERM, ENOENT, EBADF}; use syscall::scheme::Scheme; use syscall::{Stat, O_CREAT, O_TRUNC}; @@ -27,8 +27,10 @@ impl FileScheme { files: Mutex::new(BTreeMap::new()) } } +} - fn open_inner(&self, url: &[u8], flags: usize) -> Result> { +impl Scheme for FileScheme { + fn open(&self, url: &[u8], flags: usize, uid: u32, gid: u32) -> Result { let path = str::from_utf8(url).unwrap_or("").trim_matches('/'); //println!("Open '{}' {:X}", path, flags); @@ -37,9 +39,20 @@ impl FileScheme { 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)); + } + } - match node_result { + let resource: Box = match node_result { Ok(node) => if node.1.is_dir() { + if ! node.1.permission(uid, gid, Node::MODE_READ) { + // println!("dir not readable {:o}", node.1.mode); + return Err(Error::new(EACCES)); + } + let mut data = Vec::new(); let mut children = Vec::new(); try!(fs.child_nodes(&mut children, node.0)); @@ -51,13 +64,24 @@ impl FileScheme { data.extend_from_slice(&name.as_bytes()); } } - return Ok(Box::new(DirResource::new(path.to_string(), node.0, data))); + + Box::new(DirResource::new(path.to_string(), node.0, data)) } else { + if ! node.1.permission(uid, gid, Node::MODE_READ) { + // println!("file not readable {:o}", node.1.mode); + return Err(Error::new(EACCES)); + } + if flags & O_TRUNC == O_TRUNC { - // println!("Truncate {}", path); + if ! node.1.permission(uid, gid, Node::MODE_WRITE) { + // println!("file not writable {:o}", node.1.mode); + return Err(Error::new(EACCES)); + } + try!(fs.node_set_len(node.0, 0)); } - return Ok(Box::new(FileResource::new(path.to_string(), node.0))); + + Box::new(FileResource::new(path.to_string(), node.0)) }, Err(err) => if err.errno == ENOENT && flags & O_CREAT == O_CREAT { let mut last_part = String::new(); @@ -68,8 +92,16 @@ impl FileScheme { } if ! last_part.is_empty() { if let Some(parent) = nodes.last() { - let node = try!(fs.create_node(Node::MODE_FILE, &last_part, parent.0)); - return Ok(Box::new(FileResource::new(path.to_string(), node.0))); + if ! parent.1.permission(uid, gid, Node::MODE_WRITE) { + // println!("dir not writable {:o}", parent.1.mode); + return Err(Error::new(EACCES)); + } + + let mut node = try!(fs.create_node(Node::MODE_FILE | (flags as u16 & Node::MODE_PERM), &last_part, parent.0)); + node.1.uid = uid; + node.1.gid = gid; + try!(fs.write_at(node.0, &node.1)); + Box::new(FileResource::new(path.to_string(), node.0)) } else { return Err(Error::new(EPERM)); } @@ -79,13 +111,7 @@ impl FileScheme { } else { return Err(err); } - } - } -} - -impl Scheme for FileScheme { - fn open(&self, url: &[u8], flags: usize) -> Result { - let resource = try!(self.open_inner(url, flags)); + }; let id = self.next_id.fetch_add(1, Ordering::SeqCst); self.files.lock().insert(id, resource); @@ -93,7 +119,7 @@ impl Scheme for FileScheme { Ok(id) } - fn mkdir(&self, url: &[u8], _mode: usize) -> Result { + fn mkdir(&self, url: &[u8], mode: u16, uid: u32, gid: u32) -> Result { let path = str::from_utf8(url).unwrap_or("").trim_matches('/'); // println!("Mkdir '{}'", path); @@ -101,7 +127,15 @@ impl Scheme for FileScheme { let mut fs = self.fs.borrow_mut(); let mut nodes = Vec::new(); - match fs.path_nodes(path, &mut nodes) { + 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)); + } + } + + match node_result { Ok(_node) => Err(Error::new(EEXIST)), Err(err) => if err.errno == ENOENT { let mut last_part = String::new(); @@ -112,7 +146,16 @@ impl Scheme for FileScheme { } if ! last_part.is_empty() { if let Some(parent) = nodes.last() { - fs.create_node(Node::MODE_DIR, &last_part, parent.0).and(Ok(0)) + if ! parent.1.permission(uid, gid, Node::MODE_WRITE) { + // println!("dir not writable {:o}", parent.1.mode); + return Err(Error::new(EACCES)); + } + + let mut node = try!(fs.create_node(Node::MODE_DIR | (mode & Node::MODE_PERM), &last_part, parent.0)); + node.1.uid = uid; + node.1.gid = gid; + try!(fs.write_at(node.0, &node.1)); + Ok(0) } else { Err(Error::new(EPERM)) } @@ -125,7 +168,7 @@ impl Scheme for FileScheme { } } - fn rmdir(&self, url: &[u8]) -> Result { + fn rmdir(&self, url: &[u8], uid: u32, gid: u32) -> Result { let path = str::from_utf8(url).unwrap_or("").trim_matches('/'); // println!("Rmdir '{}'", path); @@ -134,8 +177,25 @@ impl Scheme for FileScheme { let mut nodes = Vec::new(); let child = try!(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 let Some(parent) = nodes.last() { + if ! parent.1.permission(uid, gid, Node::MODE_WRITE) { + // println!("dir not writable {:o}", parent.1.mode); + return Err(Error::new(EACCES)); + } + if child.1.is_dir() { + if ! child.1.permission(uid, gid, Node::MODE_WRITE) { + // println!("dir not writable {:o}", parent.1.mode); + return Err(Error::new(EACCES)); + } + if let Ok(child_name) = child.1.name() { fs.remove_node(Node::MODE_DIR, child_name, parent.0).and(Ok(0)) } else { @@ -149,7 +209,7 @@ impl Scheme for FileScheme { } } - fn unlink(&self, url: &[u8]) -> Result { + fn unlink(&self, url: &[u8], uid: u32, gid: u32) -> Result { let path = str::from_utf8(url).unwrap_or("").trim_matches('/'); // println!("Unlink '{}'", path); @@ -158,8 +218,25 @@ impl Scheme for FileScheme { let mut nodes = Vec::new(); let child = try!(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 let Some(parent) = nodes.last() { + if ! parent.1.permission(uid, gid, Node::MODE_WRITE) { + // println!("dir not writable {:o}", parent.1.mode); + return Err(Error::new(EACCES)); + } + if ! child.1.is_dir() { + if ! child.1.permission(uid, gid, Node::MODE_WRITE) { + // println!("file not writable {:o}", parent.1.mode); + return Err(Error::new(EACCES)); + } + if let Ok(child_name) = child.1.name() { fs.remove_node(Node::MODE_FILE, child_name, parent.0).and(Ok(0)) } else { @@ -237,7 +314,7 @@ impl Scheme for FileScheme { buf[i] = b':'; i += 1; } - + file.path(&mut buf[i..]).map(|count| i + count) } else { Err(Error::new(EBADF)) diff --git a/src/filesystem.rs b/src/filesystem.rs index d540e5ff12..19f8be25a8 100644 --- a/src/filesystem.rs +++ b/src/filesystem.rs @@ -45,7 +45,7 @@ impl FileSystem { free.1.extents[0] = Extent::new(4, size - 4 * 512); try!(disk.write_at(free.0, &free.1)); - let root = (1, Node::new(Node::MODE_DIR, "root", 0)); + let root = (1, Node::new(Node::MODE_DIR | 0o755, "root", 0)); try!(disk.write_at(root.0, &root.1)); let header = (0, Header::new(size, root.0, free.0)); diff --git a/src/node.rs b/src/node.rs index 90dd86ef94..56a1b975e3 100644 --- a/src/node.rs +++ b/src/node.rs @@ -20,6 +20,9 @@ impl Node { pub const MODE_DIR: u16 = 0x4000; pub const MODE_PERM: u16 = 0x0FFF; + pub const MODE_EXEC: u16 = 0o1; + pub const MODE_WRITE: u16 = 0o2; + pub const MODE_READ: u16 = 0o4; pub fn default() -> Node { Node { @@ -71,6 +74,20 @@ impl Node { self.mode & Node::MODE_TYPE == Node::MODE_FILE } + pub fn permission(&self, uid: u32, gid: u32, op: u16) -> bool { + let mut perm = self.mode & 0o7; + if self.uid == uid { + perm |= (self.mode >> 6) & 0o7; + } + if self.gid == gid || gid == 0 { + perm |= (self.mode >> 3) & 0o7; + } + if uid == 0 { + perm |= 0o7; + } + perm & op == op + } + pub fn size(&self) -> u64 { self.extents.iter().fold(0, |size, extent| size + extent.length) } From ec00f58d73de142332e80d097e32f3d93c2a33bf Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 25 Oct 2016 12:16:28 -0600 Subject: [PATCH 9/9] Add buf to dup --- scheme/scheme.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scheme/scheme.rs b/scheme/scheme.rs index 64b6d8ad4f..6f64dc10e8 100644 --- a/scheme/scheme.rs +++ b/scheme/scheme.rs @@ -252,7 +252,7 @@ impl Scheme for FileScheme { /* Resource operations */ #[allow(unused_variables)] - fn dup(&self, old_id: usize) -> Result { + fn dup(&self, old_id: usize, _buf: &[u8]) -> Result { // println!("Dup {}", old_id); let mut files = self.files.lock();