diff --git a/src/disk.rs b/src/disk.rs index c486230eba..495ba4ee8c 100644 --- a/src/disk.rs +++ b/src/disk.rs @@ -1,9 +1,5 @@ -//use core::result::Result; -use core::fmt::Display; - /// A disk -pub trait Disk { - fn name(&self) -> &str; +pub trait Disk { fn read_at(&mut self, block: u64, buffer: &mut [u8]) -> Result; fn write_at(&mut self, block: u64, buffer: &[u8]) -> Result; } diff --git a/src/filesystem.rs b/src/filesystem.rs index c5859de30c..a30128ebaa 100644 --- a/src/filesystem.rs +++ b/src/filesystem.rs @@ -1,50 +1,41 @@ use alloc::boxed::Box; -use collections::{BTreeMap, String}; - -use core::cmp; - -use core::fmt::Display; - use super::{Disk, Header, Node}; /// A file system pub struct FileSystem { pub disk: Box>, pub header: Header, - pub nodes: BTreeMap, } -impl FileSystem { - /// Create a file system from a disk - pub fn new(mut disk: Box>) -> Result { - let mut header = Header::new(); - try!(disk.read_at(1, &mut header).map_err(|err| format!("{}: could not read header: {}", disk.name(), err))); +impl FileSystem { + /// Open a file system on a disk + pub fn open(mut disk: Box>) -> Result, E> { + let mut header = Header::default(); + try!(disk.read_at(1, &mut header)); if header.valid() { - let mut nodes = BTreeMap::new(); - for extent in &header.extents { - if extent.block > 0 && extent.length > 0 { - let current_sectors = (extent.length + 511) / 512; - let max_size = current_sectors * 512; - - let size = cmp::min(extent.length, max_size); - - for i in 0..size / 512 { - let node_block = extent.block + i; - let mut node = Node::new(); - try!(disk.read_at(node_block, &mut node).map_err(|err| format!("{}: could not read node {}: {}", disk.name(), node_block, err))); - nodes.insert(node_block, node); - } - } - } - - Ok(FileSystem { + Ok(Some(FileSystem { disk: disk, header: header, - nodes: nodes, - }) + })) }else{ - Err(format!("{}: invalid header", disk.name())) + Ok(None) } } + + /// Create a file system on a disk + pub fn create(mut disk: Box>) -> Result { + let header = Header::new(); + try!(disk.write_at(1, &header)); + Ok(FileSystem { + disk: disk, + header: header, + }) + } + + pub fn node(&mut self, block: u64) -> Result { + let mut node = Node::default(); + try!(self.disk.read_at(block, &mut node)); + Ok(node) + } } diff --git a/src/header.rs b/src/header.rs index 6e8822c91f..5b5d9507d4 100644 --- a/src/header.rs +++ b/src/header.rs @@ -1,26 +1,44 @@ use core::{mem, slice}; use core::ops::{Deref, DerefMut}; -use super::Extent; - /// The header of the filesystem +#[derive(Debug)] #[repr(packed)] pub struct Header { + /// Signature, should be b"REDOXFS\0" pub signature: [u8; 8], + /// Version, should be 1 pub version: u64, - pub free_space: Extent, - pub padding: [u8; 224], - pub extents: [Extent; 16], + /// Disk ID, a 128-byte unique identifier + pub uuid: [u8; 16], + /// Disk size, in 512-byte sectors + pub size: u64, + /// Block of root node + pub root: u64, + /// Block of free space node + pub free_space: u64, } impl Header { - pub fn new() -> Header { + pub fn default() -> Header { Header { signature: [0; 8], version: 0, - free_space: Extent::default(), - padding: [0; 224], - extents: [Extent::default(); 16] + uuid: [0; 16], + size: 0, + root: 0, + free_space: 0, + } + } + + pub fn new() -> Header { + Header { + signature: *b"REDOXFS\0", + version: 1, + uuid: [0; 16], + size: 0, + root: 0, + free_space: 0, } } @@ -45,3 +63,8 @@ impl DerefMut for Header { } } } + +#[test] +fn header_size_test(){ + assert!(mem::size_of::
() <= 512); +} diff --git a/src/lib.rs b/src/lib.rs index a4cbbafe60..412d412f17 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,5 @@ +#![crate_name="redoxfs"] +#![crate_type="lib"] #![feature(alloc)] #![feature(collections)] #![no_std] diff --git a/src/node.rs b/src/node.rs index 612ec9a90b..ef287daefd 100644 --- a/src/node.rs +++ b/src/node.rs @@ -1,5 +1,4 @@ -use core::{mem, slice}; -use core::ops::{Deref, DerefMut}; +use core::{fmt, mem, ops, slice, str}; use super::Extent; @@ -7,19 +6,42 @@ use super::Extent; #[repr(packed)] pub struct Node { pub name: [u8; 256], - pub extents: [Extent; 16], + pub mode: u64, + pub next: u64, + pub extents: [Extent; 15], } impl Node { - pub fn new() -> Node { + pub fn default() -> Node { Node { name: [0; 256], - extents: [Extent::default(); 16] + mode: 0, + next: 0, + extents: [Extent::default(); 15] } } + + pub fn name(&self) -> Result<&str, str::Utf8Error> { + let mut len = 0; + + for &b in self.name.iter() { + if b == 0 { + break; + } + len += 1; + } + + str::from_utf8(&self.name[..len]) + } } -impl Deref for Node { +impl fmt::Debug for Node { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "Node {{ name: {:?}, mode: {:?}, next: {:?}, extents: {:?} }}", self.name(), self.mode, self.next, self.extents) + } +} + +impl ops::Deref for Node { type Target = [u8]; fn deref(&self) -> &[u8] { unsafe { @@ -28,10 +50,15 @@ impl Deref for Node { } } -impl DerefMut for Node { +impl ops::DerefMut for Node { fn deref_mut(&mut self) -> &mut [u8] { unsafe { slice::from_raw_parts_mut(self as *mut Node as *mut u8, mem::size_of::()) as &mut [u8] } } } + +#[test] +fn node_size_test(){ + assert!(mem::size_of::() <= 512); +} diff --git a/utility/file_disk.rs b/utility/image.rs similarity index 56% rename from utility/file_disk.rs rename to utility/image.rs index 61fd19ffae..77e461cdae 100644 --- a/utility/file_disk.rs +++ b/utility/image.rs @@ -1,34 +1,35 @@ use std::fs::File; -use std::io::{Error, Result, Read, Write, Seek, SeekFrom}; +use std::io::{Error, Read, Write, Seek, SeekFrom}; use redoxfs::Disk; -pub struct FileDisk { - path: String, +pub struct Image { file: File } -impl FileDisk { - pub fn new(path: &str) -> Result { +impl Image { + pub fn open(path: &str) -> Result { let file = try!(File::open(path)); - Ok(FileDisk { - path: path.to_string(), + Ok(Image { + file: file + }) + } + + pub fn create(path: &str) -> Result { + let file = try!(File::create(path)); + Ok(Image { file: file }) } } -impl Disk for FileDisk { - fn name(&self) -> &str { - &self.path - } - - fn read_at(&mut self, block: u64, buffer: &mut [u8]) -> Result { +impl Disk for Image { + fn read_at(&mut self, block: u64, buffer: &mut [u8]) -> Result { try!(self.file.seek(SeekFrom::Start(block * 512))); self.file.read(buffer) } - fn write_at(&mut self, block: u64, buffer: &[u8]) -> Result { + fn write_at(&mut self, block: u64, buffer: &[u8]) -> Result { try!(self.file.seek(SeekFrom::Start(block * 512))); self.file.write(buffer) } diff --git a/utility/main.rs b/utility/main.rs index 2e9a8b850f..e956c9d0ec 100644 --- a/utility/main.rs +++ b/utility/main.rs @@ -1,15 +1,19 @@ +#![deny(warnings)] + extern crate redoxfs; use std::env; +use std::fmt::Display; use std::io::{self, Write}; +use std::path::Path; -use redoxfs::{Disk, FileSystem}; +use redoxfs::FileSystem; -use file_disk::FileDisk; +use image::Image; -pub mod file_disk; +pub mod image; -fn shell(filesystem: FileSystem){ +fn shell(mut fs: FileSystem){ let mut stdout = io::stdout(); let stdin = io::stdin(); @@ -24,7 +28,27 @@ fn shell(filesystem: FileSystem){ if let Some(command) = args.next() { match command { "" => (), + "exit" => break, + "header" => { + println!("{:#?}", fs.header); + }, + "node" => { + if let Some(arg) = args.next() { + match arg.parse::() { + Ok(block) => { + match fs.node(block) { + Ok(node) => println!("{:#?}", node), + Err(err) => println!("node: failed to read {}: {}", block, err) + } + }, + Err(err) => println!("node: invalid block {}: {}", arg, err) + } + } else { + println!("node ") + } + }, "ls" => { + /* let path = args.next().unwrap_or("/"); for (node_block, node) in filesystem.nodes.iter() { let mut name = "/".to_string(); @@ -39,6 +63,8 @@ fn shell(filesystem: FileSystem){ println!("{}: {}", node_block, name); } } + */ + println!("TODO: ls"); }, _ => println!("unknown command: {}", command) } @@ -49,15 +75,30 @@ fn shell(filesystem: FileSystem){ fn main() { let mut args = env::args(); if let Some(path) = args.nth(1) { - match FileDisk::new(&path) { - Ok(disk) => match FileSystem::new(Box::new(disk)) { - Ok(filesystem) => shell(filesystem), - Err(err) => { - println!("redoxfs: failed to open filesystem: {}", err); - } - }, - Err(err) => { - println!("redoxfs: failed to open disk: {}", err); + if Path::new(&path).exists() { + match Image::open(&path) { + Ok(disk) => match FileSystem::open(Box::new(disk)) { + Ok(filesystem_option) => match filesystem_option { + Some(filesystem) => { + println!("redoxfs: opened filesystem {}", path); + shell(filesystem); + }, + None => println!("redoxfs: no filesystem found in {}", path) + }, + Err(err) => println!("redoxfs: failed to open filesystem {}: {}", path, err) + }, + Err(err) => println!("redoxfs: failed to open image {}: {}", path, err) + } + }else{ + match Image::create(&path) { + Ok(disk) => match FileSystem::create(Box::new(disk)) { + Ok(filesystem) => { + println!("redoxfs: created filesystem {}", path); + shell(filesystem); + }, + Err(err) => println!("redoxfs: failed to create filesystem {}: {}", path, err) + }, + Err(err) => println!("redoxfs: failed to create image {}: {}", path, err) } } } else {