diff --git a/Cargo.toml b/Cargo.toml
index 0eb14b8af490c07f1f5051e33de41e4d3860c082..3b28a1b41a032b8312986be8ac37d3c6cdfb70f1 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -13,4 +13,4 @@ path = "src/lib.rs"
 
 [[bin]]
 name = "redoxfs-utility"
-path = "src/utility.rs"
+path = "utility/main.rs"
diff --git a/src/disk.rs b/src/disk.rs
index d87dea1b60f345449fdcd19f3f5efc752e8048a8..c486230eba3e5e1f4414318a752eb80687465c64 100644
--- a/src/disk.rs
+++ b/src/disk.rs
@@ -1,8 +1,9 @@
-use std::io::Result;
+//use core::result::Result;
+use core::fmt::Display;
 
 /// A disk
-pub trait Disk {
+pub trait Disk<E: Display> {
     fn name(&self) -> &str;
-    fn read_at(&mut self, block: u64, buffer: &mut [u8]) -> Result<usize>;
-    fn write_at(&mut self, block: u64, buffer: &[u8]) -> Result<usize>;
+    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>;
 }
diff --git a/src/filesystem.rs b/src/filesystem.rs
index 660b0016d545a591c491b9ff9c2b9307d2a6b84a..c5859de30c7a9379aeef76b65793dc068f973369 100644
--- a/src/filesystem.rs
+++ b/src/filesystem.rs
@@ -1,18 +1,23 @@
-use std::cmp;
-use std::collections::BTreeMap;
+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<Disk>,
+pub struct FileSystem<E> {
+    pub disk: Box<Disk<E>>,
     pub header: Header,
     pub nodes: BTreeMap<u64, Node>,
 }
 
-impl FileSystem {
+impl<E: Display> FileSystem<E> {
     /// Create a file system from a disk
-    pub fn new(mut disk: Box<Disk>) -> Result<Self, String> {
+    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)));
         if header.valid() {
diff --git a/src/header.rs b/src/header.rs
index 3575d248b08afb6350fd908de952baaa34cb921f..6e8822c91f8f0fc74300548af0d96bd259fcc0b9 100644
--- a/src/header.rs
+++ b/src/header.rs
@@ -1,5 +1,5 @@
-use std::{mem, slice};
-use std::ops::{Deref, DerefMut};
+use core::{mem, slice};
+use core::ops::{Deref, DerefMut};
 
 use super::Extent;
 
diff --git a/src/lib.rs b/src/lib.rs
index 5d035e74b3bdc5c4243e2bb88ff32a434aca19e7..a4cbbafe600bb882e7878dc0f1b9cdbb9cd23438 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,3 +1,15 @@
+#![feature(alloc)]
+#![feature(collections)]
+#![no_std]
+
+#![deny(warnings)]
+
+#[macro_use]
+extern crate alloc;
+
+#[macro_use]
+extern crate collections;
+
 pub use self::disk::Disk;
 pub use self::extent::Extent;
 pub use self::filesystem::FileSystem;
diff --git a/src/node.rs b/src/node.rs
index 946ceced6f28d37259a32522b0daeb3486335d3c..612ec9a90b63b695058b298e0cb7eb5d2a65e8a5 100644
--- a/src/node.rs
+++ b/src/node.rs
@@ -1,5 +1,5 @@
-use std::{mem, slice};
-use std::ops::{Deref, DerefMut};
+use core::{mem, slice};
+use core::ops::{Deref, DerefMut};
 
 use super::Extent;
 
diff --git a/src/scheme.rs b/src/scheme.rs
deleted file mode 100644
index 972947e7a2f0687f85644e6daf20ea693246df5f..0000000000000000000000000000000000000000
--- a/src/scheme.rs
+++ /dev/null
@@ -1,381 +0,0 @@
-use common::slice::GetSlice;
-
-use alloc::boxed::Box;
-
-use arch::memory::Memory;
-
-use collections::slice;
-use collections::string::{String, ToString};
-use collections::vec::Vec;
-
-use common::debug;
-
-use core::cmp;
-
-use disk::Disk;
-use disk::ide::Extent;
-
-use fs::redoxfs::{FileSystem, Node, NodeData};
-
-use fs::{KScheme, Resource, ResourceSeek, Url, VecResource};
-
-use syscall::{Error, Result, O_CREAT, ENOENT, EIO};
-
-/// A file resource
-pub struct FileResource {
-    pub scheme: *mut FileScheme,
-    pub node: Node,
-    pub vec: Vec<u8>,
-    pub seek: usize,
-    pub dirty: bool,
-}
-
-impl Resource for FileResource {
-    fn dup(&self) -> Result<Box<Resource>> {
-        Ok(Box::new(FileResource {
-            scheme: self.scheme,
-            node: self.node.clone(),
-            vec: self.vec.clone(),
-            seek: self.seek,
-            dirty: self.dirty,
-        }))
-    }
-
-    fn path(&self, buf: &mut [u8]) -> Result<usize> {
-        let path_a = b"file:/";
-        let path_b = self.node.name.as_bytes();
-        for (b, p) in buf.iter_mut().zip(path_a.iter().chain(path_b.iter())) {
-            *b = *p;
-        }
-
-        Ok(cmp::min(buf.len(), path_a.len() + path_b.len()))
-    }
-
-    fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
-        let mut i = 0;
-        while i < buf.len() && self.seek < self.vec.len() {
-            match self.vec.get(self.seek) {
-                Some(b) => buf[i] = *b,
-                None => (),
-            }
-            self.seek += 1;
-            i += 1;
-        }
-        Ok(i)
-    }
-
-    fn write(&mut self, buf: &[u8]) -> Result<usize> {
-        let mut i = 0;
-        while i < buf.len() && self.seek < self.vec.len() {
-            self.vec[self.seek] = buf[i];
-            self.seek += 1;
-            i += 1;
-        }
-        while i < buf.len() {
-            self.vec.push(buf[i]);
-            self.seek += 1;
-            i += 1;
-        }
-        if i > 0 {
-            self.dirty = true;
-        }
-        Ok(i)
-    }
-
-    fn seek(&mut self, pos: ResourceSeek) -> Result<usize> {
-        match pos {
-            ResourceSeek::Start(offset) => self.seek = offset,
-            ResourceSeek::Current(offset) =>
-                self.seek = cmp::max(0, self.seek as isize + offset) as usize,
-            ResourceSeek::End(offset) =>
-                self.seek = cmp::max(0, self.vec.len() as isize + offset) as usize,
-        }
-        while self.vec.len() < self.seek {
-            self.vec.push(0);
-        }
-        Ok(self.seek)
-    }
-
-    // TODO: Check to make sure proper amount of bytes written. See Disk::write
-    // TODO: Allow reallocation
-    fn sync(&mut self) -> Result<()> {
-        if self.dirty {
-            let mut node_dirty = false;
-            let mut pos = 0;
-            let mut remaining = self.vec.len() as isize;
-            for ref mut extent in &mut self.node.extents {
-                if remaining > 0 && extent.empty() {
-                    debug::d("Reallocate file, extra: ");
-                    debug::ds(remaining);
-                    debug::dl();
-
-                    unsafe {
-                        let sectors = ((remaining + 511) / 512) as u64;
-                        if (*self.scheme).fs.header.free_space.length >= sectors * 512 {
-                            extent.block = (*self.scheme).fs.header.free_space.block;
-                            extent.length = remaining as u64;
-                            (*self.scheme).fs.header.free_space.block = (*self.scheme)
-                                                                            .fs
-                                                                            .header
-                                                                            .free_space
-                                                                            .block +
-                                                                        sectors;
-                            (*self.scheme).fs.header.free_space.length = (*self.scheme)
-                                                                             .fs
-                                                                             .header
-                                                                             .free_space
-                                                                             .length -
-                                                                         sectors * 512;
-
-                            node_dirty = true;
-                        }
-                    }
-                }
-
-                // Make sure it is a valid extent
-                if !extent.empty() {
-                    let current_sectors = (extent.length as usize + 511) / 512;
-                    let max_size = current_sectors * 512;
-
-                    let size = cmp::min(remaining as usize, max_size);
-
-                    if size as u64 != extent.length {
-                        extent.length = size as u64;
-                        node_dirty = true;
-                    }
-
-                    while self.vec.len() < pos + max_size {
-                        self.vec.push(0);
-                    }
-
-                    unsafe {
-                        let _ = (*self.scheme).fs.disk.write(extent.block, &self.vec[pos .. pos + max_size]);
-                    }
-
-                    self.vec.truncate(pos + size);
-
-                    pos += size;
-                    remaining -= size as isize;
-                }
-            }
-
-            if node_dirty {
-                debug::d("Node dirty, rewrite\n");
-
-                if self.node.block > 0 {
-                    unsafe {
-                        if let Some(mut node_data) = Memory::<NodeData>::new(1) {
-                            node_data.write(0, self.node.data());
-
-                            let mut buffer = slice::from_raw_parts(node_data.address() as *mut u8, 512);
-                            let _ = (*self.scheme).fs.disk.write(self.node.block, &mut buffer);
-
-                            debug::d("Renode\n");
-
-                            for mut node in (*self.scheme).fs.nodes.iter_mut() {
-                                if node.block == self.node.block {
-                                    *node = self.node.clone();
-                                }
-                            }
-                        }
-                    }
-                } else {
-                    debug::d("Need to place Node block\n");
-                }
-            }
-
-            self.dirty = false;
-
-            if remaining > 0 {
-                debug::d("Need to defragment file, extra: ");
-                debug::ds(remaining);
-                debug::dl();
-                return Err(Error::new(EIO));
-            }
-        }
-        Ok(())
-    }
-
-    fn truncate(&mut self, len: usize) -> Result<()> {
-        while len > self.vec.len() {
-            self.vec.push(0);
-        }
-        self.vec.truncate(len);
-        self.seek = cmp::min(self.seek, self.vec.len());
-        self.dirty = true;
-        Ok(())
-    }
-}
-
-impl Drop for FileResource {
-    fn drop(&mut self) {
-        let _ = self.sync();
-    }
-}
-
-/// A file scheme (pci + fs)
-pub struct FileScheme {
-    fs: FileSystem,
-}
-
-impl FileScheme {
-    /// Create a new file scheme from an array of Disks
-    pub fn new(mut disks: Vec<Box<Disk>>) -> Option<Box<Self>> {
-        while ! disks.is_empty() {
-            if let Some(fs) = FileSystem::from_disk(disks.remove(0)) {
-                return Some(Box::new(FileScheme { fs: fs }));
-            }
-        }
-
-        None
-    }
-}
-
-impl KScheme for FileScheme {
-    fn on_irq(&mut self, _irq: u8) {
-        /*if irq == self.fs.disk.irq {
-        }*/
-    }
-
-    fn scheme(&self) -> &str {
-        "file"
-    }
-
-    fn open(&mut self, url: &Url, flags: usize) -> Result<Box<Resource>> {
-        let mut path = url.reference();
-        while path.starts_with('/') {
-            path = &path[1..];
-        }
-        if path.is_empty() || path.ends_with('/') {
-            let mut list = String::new();
-            let mut dirs: Vec<String> = Vec::new();
-
-            for file in self.fs.list(path).iter() {
-                let mut line = String::new();
-                match file.find('/') {
-                    Some(index) => {
-                        let dirname = file.get_slice(..index + 1).to_string();
-                        let mut found = false;
-                        for dir in dirs.iter() {
-                            if dirname == *dir {
-                                found = true;
-                                break;
-                            }
-                        }
-                        if found {
-                            line.clear();
-                        } else {
-                            line = dirname.clone();
-                            dirs.push(dirname);
-                        }
-                    }
-                    None => line = file.clone(),
-                }
-                if !line.is_empty() {
-                    if !list.is_empty() {
-                        list = list + "\n" + &line;
-                    } else {
-                        list = line;
-                    }
-                }
-            }
-
-            if list.len() > 0 {
-                Ok(Box::new(VecResource::new(&url.string, list.into_bytes())))
-            } else {
-                Err(Error::new(ENOENT))
-            }
-        } else {
-            match self.fs.node(path) {
-                Some(node) => {
-                    let mut vec: Vec<u8> = Vec::new();
-                    for extent in &node.extents {
-                        if extent.block > 0 && extent.length > 0 {
-                            let current_sectors = (extent.length as usize + 511) / 512;
-                            let max_size = current_sectors * 512;
-
-                            let size = cmp::min(extent.length as usize, max_size);
-
-                            let pos = vec.len();
-
-                            while vec.len() < pos + max_size {
-                                vec.push(0);
-                            }
-
-                            let _ = self.fs.disk.read(extent.block, &mut vec[pos..pos + max_size]);
-
-                            vec.truncate(pos + size);
-                        }
-                    }
-
-                    Ok(Box::new(FileResource {
-                        scheme: self,
-                        node: node,
-                        vec: vec,
-                        seek: 0,
-                        dirty: false,
-                    }))
-                }
-                None => {
-                    if flags & O_CREAT == O_CREAT {
-                        // TODO: Create file
-                        let mut node = Node {
-                            block: 0,
-                            name: path.to_string(),
-                            extents: [Extent {
-                                block: 0,
-                                length: 0,
-                            }; 16],
-                        };
-
-                        if self.fs.header.free_space.length >= 512 {
-                            node.block = self.fs.header.free_space.block;
-                            self.fs.header.free_space.block = self.fs.header.free_space.block + 1;
-                            self.fs.header.free_space.length = self.fs.header.free_space.length -
-                                                               512;
-                        }
-
-                        self.fs.nodes.push(node.clone());
-
-                        Ok(Box::new(FileResource {
-                            scheme: self,
-                            node: node,
-                            vec: Vec::new(),
-                            seek: 0,
-                            dirty: false,
-                        }))
-                    } else {
-                        Err(Error::new(ENOENT))
-                    }
-                }
-            }
-        }
-    }
-
-    fn unlink(&mut self, url: &Url) -> Result<()> {
-        let mut ret = Err(Error::new(ENOENT));
-
-        let mut path = url.reference();
-        while path.starts_with('/') {
-            path = &path[1..];
-        }
-
-        let mut i = 0;
-        while i < self.fs.nodes.len() {
-            let mut remove = false;
-
-            if let Some(node) = self.fs.nodes.get(i) {
-                remove = node.name == path;
-            }
-
-            if remove {
-                self.fs.nodes.remove(i);
-                ret = Ok(());
-            } else {
-                i += 1;
-            }
-        }
-
-        ret
-    }
-}
diff --git a/src/utility.rs b/utility/file_disk.rs
similarity index 58%
rename from src/utility.rs
rename to utility/file_disk.rs
index c1fbdd2525ecb272758e6b67b72e806a299ae3f6..61fd19ffae6e9f8f2ed4bd1f0d5eaade8edcb9af 100644
--- a/src/utility.rs
+++ b/utility/file_disk.rs
@@ -1,10 +1,7 @@
-extern crate redoxfs;
-
 use std::fs::File;
-use std::io::{Result, Read, Write, Seek, SeekFrom};
-use std::str;
+use std::io::{Error, Result, Read, Write, Seek, SeekFrom};
 
-use redoxfs::{Disk, FileSystem};
+use redoxfs::Disk;
 
 pub struct FileDisk {
     path: String,
@@ -21,7 +18,7 @@ impl FileDisk {
     }
 }
 
-impl Disk for FileDisk {
+impl Disk<Error> for FileDisk {
     fn name(&self) -> &str {
         &self.path
     }
@@ -36,12 +33,3 @@ impl Disk for FileDisk {
         self.file.write(buffer)
     }
 }
-
-fn main() {
-    let disk = FileDisk::new("../../build/i386-unknown-redox/debug/harddrive.bin").unwrap();
-    let filesystem = FileSystem::new(Box::new(disk)).unwrap();
-    for (node_block, node) in filesystem.nodes.iter() {
-        let name = unsafe { str::from_utf8_unchecked(&node.name) };
-        println!("{}: {}", node_block, name);
-    }
-}
diff --git a/utility/main.rs b/utility/main.rs
new file mode 100644
index 0000000000000000000000000000000000000000..d037b1098d5bf229e42fc55e033b24fb4f8726b5
--- /dev/null
+++ b/utility/main.rs
@@ -0,0 +1,46 @@
+extern crate redoxfs;
+
+use std::env;
+
+use redoxfs::{Disk, FileSystem};
+
+use file_disk::FileDisk;
+
+pub mod file_disk;
+
+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) => {
+                    let path = args.next().unwrap_or(String::new());
+                    for (node_block, node) in filesystem.nodes.iter() {
+                        let mut name = "/".to_string();
+                        for &b in node.name.iter() {
+                            if b == 0 {
+                                break;
+                            } else {
+                                unsafe { name.as_mut_vec().push(b); }
+                            }
+                        }
+                        if name == path {
+                            println!("{}: {}: cat", node_block, name);
+                            break;
+                        } else if name.starts_with(&path) {
+                            println!("{}: {}", node_block, name);
+                        }
+                    }
+                },
+                Err(err) => {
+                    println!("redoxfs: failed to open filesystem: {}", err);
+                }
+            },
+            Err(err) => {
+                println!("redoxfs: failed to open disk: {}", err);
+            }
+        }
+    } else {
+        println!("redoxfs: no disk image provided");
+    }
+}