From 77848132ea8bb89fbc92b007c66840e3bc834f0c Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 9 Mar 2016 14:10:56 -0700 Subject: [PATCH] Fuse fixes, file read/write implemented --- fuse/main.rs | 166 +++++++++++++++++++++++++++++++++++++++++----- scheme/scheme.rs | 59 +++++++++++++++- src/filesystem.rs | 71 ++------------------ 3 files changed, 209 insertions(+), 87 deletions(-) diff --git a/fuse/main.rs b/fuse/main.rs index 208a2a4a5a..63bb228bdc 100644 --- a/fuse/main.rs +++ b/fuse/main.rs @@ -9,8 +9,7 @@ use image::Image; use std::env; use std::path::Path; use time::Timespec; -use fuse::{FileType, FileAttr, Filesystem, Request, ReplyData, ReplyEntry, ReplyAttr, ReplyDirectory}; -use system::error::ENOENT; +use fuse::{FileType, FileAttr, Filesystem, Request, ReplyData, ReplyEntry, ReplyAttr, ReplyCreate, ReplyDirectory, ReplyEmpty, ReplyWrite}; pub mod image; @@ -23,12 +22,10 @@ struct RedoxFS { } impl Filesystem for RedoxFS { - fn lookup (&mut self, _req: &Request, ino: u64, name: &Path, reply: ReplyEntry) { + fn lookup(&mut self, _req: &Request, ino: u64, name: &Path, reply: ReplyEntry) { let parent_block = self.fs.header.0 + ino; - println!("lookup: {} {:?}", parent_block, name); match self.fs.find_node(name.to_str().unwrap(), parent_block) { Ok(node) => { - println!("lookup: {:?}", node); reply.entry(&TTL, &FileAttr { ino: node.0 - self.fs.header.0, size: node.1.extents[0].length, @@ -48,21 +45,18 @@ impl Filesystem for RedoxFS { gid: 0, rdev: 0, flags: 0, - }, 0) + }, 0); }, Err(err) => { - println!("lookup: {}", err); reply.error(err.errno as i32); } } } - fn getattr (&mut self, _req: &Request, ino: u64, reply: ReplyAttr) { + fn getattr(&mut self, _req: &Request, ino: u64, reply: ReplyAttr) { let block = self.fs.header.0 + ino; - println!("getattr: {}", block); match self.fs.node(block) { Ok(node) => { - println!("getattr: {:?}", node); reply.attr(&TTL, &FileAttr { ino: node.0 - self.fs.header.0, size: node.1.extents[0].length, @@ -85,15 +79,49 @@ impl Filesystem for RedoxFS { }); }, Err(err) => { - println!("getattr: {}", err); reply.error(err.errno as i32); } } } - fn read (&mut self, _req: &Request, ino: u64, _fh: u64, offset: u64, size: u32, reply: ReplyData) { + fn setattr(&mut self, _req: &Request, ino: 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) { + //TODO: Implement truncate + let block = self.fs.header.0 + ino; + match self.fs.node(block) { + Ok(node) => { + reply.attr(&TTL, &FileAttr { + ino: node.0 - self.fs.header.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, + }); + }, + Err(err) => { + reply.error(err.errno as i32); + } + } + } + + fn read(&mut self, _req: &Request, ino: u64, _fh: u64, offset: u64, size: u32, reply: ReplyData) { let block = self.fs.header.0 + ino; - println!("read: {} at {}, size {}", block, offset, size); let mut data = vec![0; size as usize]; match self.fs.read_node(block, offset, &mut data) { Ok(count) => { @@ -105,9 +133,28 @@ impl Filesystem for RedoxFS { } } - fn readdir (&mut self, _req: &Request, ino: u64, _fh: u64, offset: u64, mut reply: ReplyDirectory) { + fn write(&mut self, _req: &Request, ino: u64, _fh: u64, offset: u64, data: &[u8], _flags: u32, reply: ReplyWrite) { + let block = self.fs.header.0 + ino; + match self.fs.write_node(block, offset, &data) { + Ok(count) => { + reply.written(count as u32); + }, + Err(err) => { + reply.error(err.errno as i32); + } + } + } + + fn flush(&mut self, _req: &Request, _ino: u64, _fh: u64, _lock_owner: u64, reply: ReplyEmpty) { + reply.ok(); + } + + fn fsync(&mut self, _req: &Request, _ino: u64, _fh: u64, _datasync: bool, reply: ReplyEmpty) { + reply.ok(); + } + + fn readdir(&mut self, _req: &Request, ino: u64, _fh: u64, offset: u64, mut reply: ReplyDirectory) { let parent_block = self.fs.header.0 + ino; - println!("readdir: {}", parent_block); let mut children = Vec::new(); match self.fs.child_nodes(&mut children, parent_block) { Ok(()) => { @@ -129,14 +176,99 @@ impl Filesystem for RedoxFS { reply.ok(); }, Err(err) => { - println!("readdir: {}", err); + reply.error(err.errno as i32); + } + } + } + + fn create(&mut self, _req: &Request, ino: u64, name: &Path, _mode: u32, flags: u32, reply: ReplyCreate) { + let parent_block = self.fs.header.0 + ino; + match self.fs.create_node(redoxfs::Node::MODE_FILE, name.to_str().unwrap(), parent_block) { + Ok(node) => { + reply.created(&TTL, &FileAttr { + ino: node.0 - self.fs.header.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); + }, + Err(error) => { + reply.error(error.errno as i32); + } + } + } + + fn mkdir(&mut self, _req: &Request, ino: u64, name: &Path, _mode: u32, reply: ReplyEntry) { + let parent_block = self.fs.header.0 + ino; + match self.fs.create_node(redoxfs::Node::MODE_DIR, name.to_str().unwrap(), parent_block) { + Ok(node) => { + reply.entry(&TTL, &FileAttr { + ino: node.0 - self.fs.header.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); + }, + Err(error) => { + reply.error(error.errno as i32); + } + } + } + + fn rmdir(&mut self, _req: &Request, ino: u64, name: &Path, reply: ReplyEmpty) { + let parent_block = self.fs.header.0 + ino; + match self.fs.remove_node(redoxfs::Node::MODE_DIR, name.to_str().unwrap(), parent_block) { + Ok(()) => { + reply.ok(); + }, + Err(err) => { + reply.error(err.errno as i32); + } + } + } + + fn unlink(&mut self, _req: &Request, ino: u64, name: &Path, reply: ReplyEmpty) { + let parent_block = self.fs.header.0 + ino; + match self.fs.remove_node(redoxfs::Node::MODE_FILE, name.to_str().unwrap(), parent_block) { + Ok(()) => { + reply.ok(); + }, + Err(err) => { reply.error(err.errno as i32); } } } } -fn main () { +fn main() { if let Some(path) = env::args().nth(1) { //Open an existing image match Image::open(&path) { diff --git a/scheme/scheme.rs b/scheme/scheme.rs index 60e2f6605f..e157624ff2 100644 --- a/scheme/scheme.rs +++ b/scheme/scheme.rs @@ -96,17 +96,70 @@ impl Scheme for FileScheme { fn mkdir(&mut self, url: &str, _mode: usize) -> Result { let path = url.split(':').nth(1).unwrap_or("").trim_matches('/'); - self.fs.mkdir(path) + + let mut nodes = Vec::new(); + match self.path_nodes(path, &mut nodes) { + Ok(_node) => Err(Error::new(EEXIST)), + Err(err) => if err.errno == ENOENT { + let mut last_part = String::new(); + for part in path.split('/') { + if ! part.is_empty() { + last_part = part.to_owned(); + } + } + if ! last_part.is_empty() { + if let Some(parent) = nodes.last() { + self.create_node(Node::MODE_DIR, &last_part, parent.0).and(Ok(0)) + } else { + Err(Error::new(EPERM)) + } + } else { + Err(Error::new(EPERM)) + } + } else { + Err(err) + } + } } fn rmdir(&mut self, url: &str) -> Result { let path = url.split(':').nth(1).unwrap_or("").trim_matches('/'); - self.fs.rmdir(path) + + let mut nodes = Vec::new(); + let child = try!(self.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.remove_node(Node::MODE_DIR, child_name, parent.0).and(Ok(0)) + } else { + Err(Error::new(ENOENT)) + } + } else { + Err(Error::new(ENOTDIR)) + } + } else { + Err(Error::new(EPERM)) + } } fn unlink(&mut self, url: &str) -> Result { let path = url.split(':').nth(1).unwrap_or("").trim_matches('/'); - self.fs.unlink(path) + + let mut nodes = Vec::new(); + let child = try!(self.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.remove_node(Node::MODE_FILE, child_name, parent.0).and(Ok(0)) + } else { + Err(Error::new(ENOENT)) + } + } else { + Err(Error::new(EISDIR)) + } + } else { + Err(Error::new(EPERM)) + } } /* Resource operations */ diff --git a/src/filesystem.rs b/src/filesystem.rs index 993dfac6fa..19c8750e5b 100644 --- a/src/filesystem.rs +++ b/src/filesystem.rs @@ -1,9 +1,8 @@ use alloc::boxed::Box; -use collections::{String, Vec}; -use collections::borrow::ToOwned; +use collections::Vec; -use system::error::{Result, Error, EEXIST, EISDIR, ENOENT, ENOSPC, ENOTDIR, ENOTEMPTY, EPERM}; +use system::error::{Result, Error, EEXIST, EISDIR, ENOENT, ENOSPC, ENOTDIR, ENOTEMPTY}; use super::{Disk, ExNode, Extent, Header, Node}; @@ -142,7 +141,7 @@ impl FileSystem { self.find_node(name, parent.1.next) } - fn path_nodes(&mut self, path: &str, nodes: &mut Vec<(u64, Node)>) -> Result<(u64, Node)> { + pub fn path_nodes(&mut self, path: &str, nodes: &mut Vec<(u64, Node)>) -> Result<(u64, Node)> { let mut block = self.header.1.root; nodes.push(try!(self.node(block))); @@ -221,7 +220,7 @@ impl FileSystem { let mut replace_option = None; let mut parent = try!(self.node(parent_block)); for mut extent in parent.1.extents.iter_mut() { - if block >= extent.block && block + length <= extent.block + length/512 { + if block >= extent.block && block + length <= extent.block + extent.length/512 { //Inside removed = true; @@ -423,66 +422,4 @@ impl FileSystem { Ok(size) } } - - pub fn mkdir(&mut self, path: &str) -> Result { - let mut nodes = Vec::new(); - match self.path_nodes(path, &mut nodes) { - Ok(_node) => Err(Error::new(EEXIST)), - Err(err) => if err.errno == ENOENT { - let mut last_part = String::new(); - for part in path.split('/') { - if ! part.is_empty() { - last_part = part.to_owned(); - } - } - if ! last_part.is_empty() { - if let Some(parent) = nodes.last() { - self.create_node(Node::MODE_DIR, &last_part, parent.0).and(Ok(0)) - } else { - Err(Error::new(EPERM)) - } - } else { - Err(Error::new(EPERM)) - } - } else { - Err(err) - } - } - } - - pub fn rmdir(&mut self, path: &str) -> Result { - let mut nodes = Vec::new(); - let child = try!(self.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.remove_node(Node::MODE_DIR, child_name, parent.0).and(Ok(0)) - } else { - Err(Error::new(ENOENT)) - } - } else { - Err(Error::new(ENOTDIR)) - } - } else { - Err(Error::new(EPERM)) - } - } - - pub fn unlink(&mut self, path: &str) -> Result { - let mut nodes = Vec::new(); - let child = try!(self.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.remove_node(Node::MODE_FILE, child_name, parent.0).and(Ok(0)) - } else { - Err(Error::new(ENOENT)) - } - } else { - Err(Error::new(EISDIR)) - } - } else { - Err(Error::new(EPERM)) - } - } }