From bae24a54b00a7dd13f08a17f21859f05ca66e18b Mon Sep 17 00:00:00 2001
From: Jeremy Soller <jackpot51@gmail.com>
Date: Wed, 24 Feb 2016 18:23:25 -0700
Subject: [PATCH] Improve debugging and image creation

---
 .gitignore        |  3 +++
 src/disk.rs       |  1 +
 src/extent.rs     |  9 +++++++++
 src/filesystem.rs | 39 ++++++++++++++++++++++++++++++++-------
 src/header.rs     | 12 ++++++------
 src/lib.rs        |  1 +
 src/node.rs       | 32 +++++++++++++++++++++++++++++++-
 utility/image.rs  | 13 +++++++++----
 utility/main.rs   |  8 ++++----
 9 files changed, 96 insertions(+), 22 deletions(-)

diff --git a/.gitignore b/.gitignore
index f857248..54a3b4d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -10,3 +10,6 @@
 # Generated by Cargo
 Cargo.lock
 /target/
+
+# Images
+*.bin
diff --git a/src/disk.rs b/src/disk.rs
index 495ba4e..1546766 100644
--- a/src/disk.rs
+++ b/src/disk.rs
@@ -2,4 +2,5 @@
 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>;
+    fn size(&mut self) -> Result<u64, E>;
 }
diff --git a/src/extent.rs b/src/extent.rs
index def358c..336ed13 100644
--- a/src/extent.rs
+++ b/src/extent.rs
@@ -5,3 +5,12 @@ pub struct Extent {
     pub block: u64,
     pub length: u64,
 }
+
+impl Extent {
+    pub fn new(block: u64, length: u64) -> Extent {
+        Extent {
+            block: block,
+            length: length
+        }
+    }
+}
diff --git a/src/filesystem.rs b/src/filesystem.rs
index a30128e..63a0e55 100644
--- a/src/filesystem.rs
+++ b/src/filesystem.rs
@@ -1,22 +1,33 @@
 use alloc::boxed::Box;
 
-use super::{Disk, Header, Node};
+use super::{Disk, Extent, Header, Node};
 
 /// A file system
 pub struct FileSystem<E> {
     pub disk: Box<Disk<E>>,
-    pub header: Header,
+    pub header: (u64, Header),
+    pub root: (u64, Node),
+    pub free: (u64, Node)
 }
 
 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 header = (1, Header::default());
+        try!(disk.read_at(header.0, &mut header.1));
+
+        if header.1.valid() {
+            let mut root = (header.1.root, Node::default());
+            try!(disk.read_at(root.0, &mut root.1));
+
+            let mut free = (header.1.free, Node::default());
+            try!(disk.read_at(free.0, &mut free.1));
+
             Ok(Some(FileSystem {
                 disk: disk,
                 header: header,
+                root: root,
+                free: free
             }))
         }else{
             Ok(None)
@@ -25,11 +36,25 @@ impl<E> FileSystem<E> {
 
     /// 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));
+        let size = try!(disk.size());
+
+        assert!(size > 4);
+
+        let mut free = (3, Node::new("free", Node::MODE_DIR));
+        free.1.extents[0] = Extent::new(4, (size - 4 * 512));
+        try!(disk.write_at(free.0, &free.1));
+
+        let root = (2, Node::new("root", Node::MODE_DIR));
+        try!(disk.write_at(root.0, &root.1));
+
+        let header = (1, Header::new(size, root.0, free.0));
+        try!(disk.write_at(header.0, &header.1));
+
         Ok(FileSystem {
             disk: disk,
             header: header,
+            root: root,
+            free: free
         })
     }
 
diff --git a/src/header.rs b/src/header.rs
index 5b5d950..c0306e8 100644
--- a/src/header.rs
+++ b/src/header.rs
@@ -16,7 +16,7 @@ pub struct Header {
     /// Block of root node
     pub root: u64,
     /// Block of free space node
-    pub free_space: u64,
+    pub free: u64,
 }
 
 impl Header {
@@ -27,18 +27,18 @@ impl Header {
             uuid: [0; 16],
             size: 0,
             root: 0,
-            free_space: 0,
+            free: 0,
         }
     }
 
-    pub fn new() -> Header {
+    pub fn new(size: u64, root: u64, free: u64) -> Header {
         Header {
             signature: *b"REDOXFS\0",
             version: 1,
             uuid: [0; 16],
-            size: 0,
-            root: 0,
-            free_space: 0,
+            size: size,
+            root: root,
+            free: free,
         }
     }
 
diff --git a/src/lib.rs b/src/lib.rs
index 412d412..32f1493 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,6 +1,7 @@
 #![crate_name="redoxfs"]
 #![crate_type="lib"]
 #![feature(alloc)]
+#![feature(associated_consts)]
 #![feature(collections)]
 #![no_std]
 
diff --git a/src/node.rs b/src/node.rs
index ef287da..3882f6d 100644
--- a/src/node.rs
+++ b/src/node.rs
@@ -1,3 +1,5 @@
+use collections::Vec;
+
 use core::{fmt, mem, ops, slice, str};
 
 use super::Extent;
@@ -12,6 +14,10 @@ pub struct Node {
 }
 
 impl Node {
+    pub const MODE_MASK: u64 = 0xF000;
+    pub const MODE_FILE: u64 = 0x8000;
+    pub const MODE_DIR: u64 = 0x4000;
+
     pub fn default() -> Node {
         Node {
             name: [0; 256],
@@ -21,6 +27,20 @@ impl Node {
         }
     }
 
+    pub fn new(name: &str, mode: u64) -> Node {
+        let mut bytes = [0; 256];
+        for (mut b, c) in bytes.iter_mut().zip(name.bytes()) {
+            *b = c;
+        }
+
+        Node {
+            name: bytes,
+            mode: mode,
+            next: 0,
+            extents: [Extent::default(); 15]
+        }
+    }
+
     pub fn name(&self) -> Result<&str, str::Utf8Error> {
         let mut len = 0;
 
@@ -33,11 +53,21 @@ impl Node {
 
         str::from_utf8(&self.name[..len])
     }
+
+    pub fn size(&self) -> u64 {
+        self.extents.iter().fold(0, |size, extent| size + extent.length)
+    }
 }
 
 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)
+        let extents: Vec<&Extent> = self.extents.iter().filter(|extent| -> bool { extent.length > 0 }).collect();
+        f.debug_struct("Node")
+            .field("name", &self.name())
+            .field("mode", &self.mode)
+            .field("next", &self.next)
+            .field("extents", &extents)
+            .finish()
     }
 }
 
diff --git a/utility/image.rs b/utility/image.rs
index 77e461c..439b8b0 100644
--- a/utility/image.rs
+++ b/utility/image.rs
@@ -1,4 +1,4 @@
-use std::fs::File;
+use std::fs::{File, OpenOptions};
 use std::io::{Error, Read, Write, Seek, SeekFrom};
 
 use redoxfs::Disk;
@@ -9,14 +9,15 @@ pub struct Image {
 
 impl Image {
     pub fn open(path: &str) -> Result<Image, Error> {
-        let file = try!(File::open(path));
+        let file = try!(OpenOptions::new().read(true).write(true).open(path));
         Ok(Image {
             file: file
         })
     }
 
-    pub fn create(path: &str) -> Result<Image, Error> {
-        let file = try!(File::create(path));
+    pub fn create(path: &str, size: u64) -> Result<Image, Error> {
+        let file = try!(OpenOptions::new().read(true).write(true).create(true).open(path));
+        try!(file.set_len(size));
         Ok(Image {
             file: file
         })
@@ -33,4 +34,8 @@ impl Disk<Error> for Image {
         try!(self.file.seek(SeekFrom::Start(block * 512)));
         self.file.write(buffer)
     }
+
+    fn size(&mut self) -> Result<u64, Error> {
+        self.file.seek(SeekFrom::End(0))
+    }
 }
diff --git a/utility/main.rs b/utility/main.rs
index e956c9d..8e75a88 100644
--- a/utility/main.rs
+++ b/utility/main.rs
@@ -29,9 +29,7 @@ fn shell<E: Display>(mut fs: FileSystem<E>){
             match command {
                 "" => (),
                 "exit" => break,
-                "header" => {
-                    println!("{:#?}", fs.header);
-                },
+                "header" => println!("{:#?}", fs.header),
                 "node" => {
                     if let Some(arg) = args.next() {
                         match arg.parse::<u64>() {
@@ -76,6 +74,7 @@ fn main() {
     let mut args = env::args();
     if let Some(path) = args.nth(1) {
         if Path::new(&path).exists() {
+            //Open an existing image
             match Image::open(&path) {
                 Ok(disk) => match FileSystem::open(Box::new(disk)) {
                     Ok(filesystem_option) => match filesystem_option {
@@ -90,7 +89,8 @@ fn main() {
                 Err(err) => println!("redoxfs: failed to open image {}: {}", path, err)
             }
         }else{
-            match Image::create(&path) {
+            //Create a 1 GB disk image
+            match Image::create(&path, 1024 * 1024 * 1024) {
                 Ok(disk) => match FileSystem::create(Box::new(disk)) {
                     Ok(filesystem) => {
                         println!("redoxfs: created filesystem {}", path);
-- 
GitLab