Cleanup, add node and header commands
This commit is contained in:
+1
-5
@@ -1,9 +1,5 @@
|
||||
//use core::result::Result;
|
||||
use core::fmt::Display;
|
||||
|
||||
/// A disk
|
||||
pub trait Disk<E: Display> {
|
||||
fn name(&self) -> &str;
|
||||
pub trait Disk<E> {
|
||||
fn read_at(&mut self, block: u64, buffer: &mut [u8]) -> Result<usize, E>;
|
||||
fn write_at(&mut self, block: u64, buffer: &[u8]) -> Result<usize, E>;
|
||||
}
|
||||
|
||||
+24
-33
@@ -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<E> {
|
||||
pub disk: Box<Disk<E>>,
|
||||
pub header: Header,
|
||||
pub nodes: BTreeMap<u64, Node>,
|
||||
}
|
||||
|
||||
impl<E: Display> FileSystem<E> {
|
||||
/// Create a file system from a disk
|
||||
pub fn new(mut disk: Box<Disk<E>>) -> Result<Self, String> {
|
||||
let mut header = Header::new();
|
||||
try!(disk.read_at(1, &mut header).map_err(|err| format!("{}: could not read header: {}", disk.name(), err)));
|
||||
impl<E> FileSystem<E> {
|
||||
/// Open a file system on a disk
|
||||
pub fn open(mut disk: Box<Disk<E>>) -> Result<Option<Self>, 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<Disk<E>>) -> Result<Self, E> {
|
||||
let header = Header::new();
|
||||
try!(disk.write_at(1, &header));
|
||||
Ok(FileSystem {
|
||||
disk: disk,
|
||||
header: header,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn node(&mut self, block: u64) -> Result<Node, E> {
|
||||
let mut node = Node::default();
|
||||
try!(self.disk.read_at(block, &mut node));
|
||||
Ok(node)
|
||||
}
|
||||
}
|
||||
|
||||
+32
-9
@@ -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::<Header>() <= 512);
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
#![crate_name="redoxfs"]
|
||||
#![crate_type="lib"]
|
||||
#![feature(alloc)]
|
||||
#![feature(collections)]
|
||||
#![no_std]
|
||||
|
||||
+34
-7
@@ -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::<Node>()) as &mut [u8]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn node_size_test(){
|
||||
assert!(mem::size_of::<Node>() <= 512);
|
||||
}
|
||||
|
||||
@@ -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<FileDisk> {
|
||||
impl Image {
|
||||
pub fn open(path: &str) -> Result<Image, Error> {
|
||||
let file = try!(File::open(path));
|
||||
Ok(FileDisk {
|
||||
path: path.to_string(),
|
||||
Ok(Image {
|
||||
file: file
|
||||
})
|
||||
}
|
||||
|
||||
pub fn create(path: &str) -> Result<Image, Error> {
|
||||
let file = try!(File::create(path));
|
||||
Ok(Image {
|
||||
file: file
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Disk<Error> for FileDisk {
|
||||
fn name(&self) -> &str {
|
||||
&self.path
|
||||
}
|
||||
|
||||
fn read_at(&mut self, block: u64, buffer: &mut [u8]) -> Result<usize> {
|
||||
impl Disk<Error> for Image {
|
||||
fn read_at(&mut self, block: u64, buffer: &mut [u8]) -> Result<usize, Error> {
|
||||
try!(self.file.seek(SeekFrom::Start(block * 512)));
|
||||
self.file.read(buffer)
|
||||
}
|
||||
|
||||
fn write_at(&mut self, block: u64, buffer: &[u8]) -> Result<usize> {
|
||||
fn write_at(&mut self, block: u64, buffer: &[u8]) -> Result<usize, Error> {
|
||||
try!(self.file.seek(SeekFrom::Start(block * 512)));
|
||||
self.file.write(buffer)
|
||||
}
|
||||
+54
-13
@@ -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<E>(filesystem: FileSystem<E>){
|
||||
fn shell<E: Display>(mut fs: FileSystem<E>){
|
||||
let mut stdout = io::stdout();
|
||||
let stdin = io::stdin();
|
||||
|
||||
@@ -24,7 +28,27 @@ fn shell<E>(filesystem: FileSystem<E>){
|
||||
if let Some(command) = args.next() {
|
||||
match command {
|
||||
"" => (),
|
||||
"exit" => break,
|
||||
"header" => {
|
||||
println!("{:#?}", fs.header);
|
||||
},
|
||||
"node" => {
|
||||
if let Some(arg) = args.next() {
|
||||
match arg.parse::<u64>() {
|
||||
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 <block>")
|
||||
}
|
||||
},
|
||||
"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<E>(filesystem: FileSystem<E>){
|
||||
println!("{}: {}", node_block, name);
|
||||
}
|
||||
}
|
||||
*/
|
||||
println!("TODO: ls");
|
||||
},
|
||||
_ => println!("unknown command: {}", command)
|
||||
}
|
||||
@@ -49,15 +75,30 @@ fn shell<E>(filesystem: FileSystem<E>){
|
||||
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 {
|
||||
|
||||
Reference in New Issue
Block a user