diff --git a/ext2-rs/Cargo.toml b/ext2-rs/Cargo.toml
deleted file mode 100644
index f72ff11..0000000
--- a/ext2-rs/Cargo.toml
+++ /dev/null
@@ -1,16 +0,0 @@
-[package]
-name = "ext2"
-version = "0.1.1"
-authors = ["Szymon Walter <walter.szymon.98@gmail.com>",
-"able <abl3theabove@gmail.com>"]
-
-
-[dependencies]
-bitflags = "1.0"
-rlibc = { version = "1.0", optional = true }
-spin = "0.9.2"
-genfs = "^0.1.4"
-
-[features]
-default = ["no_std"]
-no_std = ["rlibc"]
diff --git a/ext2-rs/LICENSE.md b/ext2-rs/LICENSE.md
deleted file mode 100644
index 9894777..0000000
--- a/ext2-rs/LICENSE.md
+++ /dev/null
@@ -1,22 +0,0 @@
-# ext2-rs
-## an ext2 implementation
-
-Copyright © 2018, Szymon Walter
-
-This software is provided 'as-is', without any express or implied warranty.
-In no event will the authors be held liable for any damages arising from
-the use of this software.
-
-Permission is granted to anyone to use this software for any purpose,
-including commercial applications, and to alter it and redistribute it
-freely, subject to the following restrictions:
-
-1. The origin of this software must not be misrepresented; you must not
-   claim that you wrote the original software. If you use this software
-   in a product, an acknowledgment in the product documentation would be
-   appreciated but is not required.
-2. Altered source versions must be plainly marked as such, and must not
-   be misrepresented as being the original software.
-3. This notice may not be removed or altered from any source distribution.
-
-#### walter.szymon.98@gmail.com
diff --git a/ext2-rs/README.md b/ext2-rs/README.md
deleted file mode 100644
index 8dd53d6..0000000
--- a/ext2-rs/README.md
+++ /dev/null
@@ -1,3 +0,0 @@
-# ext2-rs
-
-An OS and architecture independent implementation of ext2 in pure Rust.
diff --git a/ext2-rs/rustfmt.toml b/ext2-rs/rustfmt.toml
deleted file mode 100644
index 3450fc4..0000000
--- a/ext2-rs/rustfmt.toml
+++ /dev/null
@@ -1,2 +0,0 @@
-max_width = 80
-wrap_comments = true
diff --git a/ext2-rs/src/error.rs b/ext2-rs/src/error.rs
deleted file mode 100644
index f506ae9..0000000
--- a/ext2-rs/src/error.rs
+++ /dev/null
@@ -1,124 +0,0 @@
-//! Errors
-use {
-    alloc::string::String,
-    core::fmt::{self, Display},
-};
-
-#[cfg(any(test, not(feature = "no_std")))]
-use std::io;
-
-/// The set of all possible errors
-#[derive(Debug)]
-pub enum Error {
-    /// Generic error
-    Other(String),
-    /// Bad magic number
-    BadMagic {
-        /// The magic number
-        magic: u16,
-    },
-    /// Out of bounds error
-    OutOfBounds {
-        /// index
-        index: usize,
-    },
-    /// Address out of bounds
-    AddressOutOfBounds {
-        ///
-        sector: u32,
-        ///
-        offset: u32,
-
-        ///
-        size: usize,
-    },
-    /// Bad block group count
-    BadBlockGroupCount {
-        ///
-        by_blocks: u32,
-        ///
-        by_inodes: u32,
-    },
-    /// Inode Not Found
-    InodeNotFound {
-        /// inode number
-        inode: u32,
-    },
-    /// Inode is not a directory
-    NotADirectory {
-        /// inode number
-        inode: u32,
-        /// inode name
-        name: String,
-    },
-    /// Not Absolute Path
-    NotAbsolute {
-        /// path name
-        name: String,
-    },
-
-    /// Not Found
-    NotFound {
-        /// inode name
-        name: String,
-    },
-    // #[cfg(any(test, not(feature = "no_std")))]
-    // Io { inner: io::Error },
-}
-
-impl Display for Error {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        match *self {
-            Error::Other(ref msg) => write!(f, "{}", msg),
-            Error::BadMagic {
-                magic,
-            } => write!(f, "invalid magic value: {}", magic),
-            Error::OutOfBounds {
-                index,
-            } => write!(f, "index ouf of bounds: {}", index),
-            Error::AddressOutOfBounds {
-                sector,
-                offset,
-                size,
-            } => write!(f, "address ouf of bounds: {}:{} with a block size of: {}",
-                   sector, offset, size),
-            Error::BadBlockGroupCount {
-                by_blocks,
-                by_inodes,
-            } => write!(f, "conflicting block group count data; by blocks: {}, by inodes: {}", by_blocks, by_inodes),
-            Error::InodeNotFound {
-                inode,
-            } => write!(f, "couldn't find inode no. {}", &inode),
-            Error::NotADirectory {
-                inode,
-                ref name,
-            } => write!(f, "inode no. {} at: {} is not a directory", inode, &name),
-            Error::NotAbsolute {
-                ref name,
-            } => write!(f, "{} is not an absolute path", &name),
-            Error::NotFound {
-                ref name,
-            } => write!(f, "couldn't find {}", &name),
-            #[cfg(any(test, not(feature = "no_std")))]
-            Error::Io {
-                ref inner,
-            } => write!(f, "io error: {}", inner),
-        }
-    }
-}
-
-impl From<Infallible> for Error {
-    fn from(_: Infallible) -> Error {
-        unreachable!()
-    }
-}
-
-#[cfg(any(test, not(feature = "no_std")))]
-impl From<io::Error> for Error {
-    fn from(inner: io::Error) -> Error {
-        Error::Io { inner }
-    }
-}
-
-/// Infalliable
-pub enum Infallible {}
diff --git a/ext2-rs/src/fs/mod.rs b/ext2-rs/src/fs/mod.rs
deleted file mode 100644
index 1844e31..0000000
--- a/ext2-rs/src/fs/mod.rs
+++ /dev/null
@@ -1,177 +0,0 @@
-//!
-
-use {
-    alloc::vec::Vec,
-    core::mem,
-    error::Error,
-    sector::{Address, SectorSize},
-    sys::{
-        block_group::BlockGroupDescriptor, inode::Inode as RawInode,
-        superblock::Superblock,
-    },
-    volume::Volume,
-};
-
-pub mod sync;
-
-#[allow(dead_code)]
-pub(crate) struct Struct<T, S: SectorSize> {
-    pub inner: T,
-    pub offset: Address<S>,
-}
-
-impl<T, S: SectorSize> From<(T, Address<S>)> for Struct<T, S> {
-    #[inline]
-    fn from((inner, offset): (T, Address<S>)) -> Struct<T, S> {
-        Struct { inner, offset }
-    }
-}
-
-/// Safe wrapper for raw sys structs
-pub struct Ext2<S: SectorSize, V: Volume<u8, S>> {
-    // TODO: should this have some different vis?
-    pub(crate) volume: V,
-    pub(crate) superblock: Struct<Superblock, S>,
-    pub(crate) block_groups: Struct<Vec<BlockGroupDescriptor>, S>,
-}
-
-impl<S: SectorSize, V: Volume<u8, S>> Ext2<S, V> {
-    ///
-    pub fn new(volume: V) -> Result<Ext2<S, V>, Error> {
-        let superblock = unsafe { Struct::from(Superblock::find(&volume)?) };
-        let block_groups_offset = Address::with_block_size(
-            superblock.inner.first_data_block + 1,
-            0,
-            superblock.inner.log_block_size + 10,
-        );
-        let block_groups_count = superblock
-            .inner
-            .block_group_count()
-            .map(|count| count as usize)
-            .map_err(|(a, b)| Error::BadBlockGroupCount {
-                by_blocks: a,
-                by_inodes: b,
-            })?;
-        let block_groups = unsafe {
-            BlockGroupDescriptor::find_descriptor_table(
-                &volume,
-                block_groups_offset,
-                block_groups_count,
-            )?
-        };
-        let block_groups = Struct::from(block_groups);
-        Ok(Ext2 {
-            volume,
-            superblock,
-            block_groups,
-        })
-    }
-    /// Return the version of the filesystem
-    pub fn version(&self) -> (u32, u16) {
-        (
-            self.superblock.inner.rev_major,
-            self.superblock.inner.rev_minor,
-        )
-    }
-    /// Return inode size
-    pub fn inode_size(&self) -> usize {
-        if self.version().0 == 0 {
-            mem::size_of::<RawInode>()
-        } else {
-            // note: inodes bigger than 128 are not supported
-            self.superblock.inner.inode_size as usize
-        }
-    }
-    ///
-    pub fn inodes_count(&self) -> usize {
-        self.superblock.inner.inodes_per_group as _
-    }
-    ///
-    pub fn total_inodes_count(&self) -> usize {
-        self.superblock.inner.inodes_count as _
-    }
-    ///
-    pub fn block_group_count(&self) -> Result<usize, Error> {
-        self.superblock
-            .inner
-            .block_group_count()
-            .map(|count| count as usize)
-            .map_err(|(a, b)| Error::BadBlockGroupCount {
-                by_blocks: a,
-                by_inodes: b,
-            })
-    }
-    ///
-    pub fn total_block_count(&self) -> usize {
-        self.superblock.inner.blocks_count as _
-    }
-    ///
-    pub fn free_block_count(&self) -> usize {
-        self.superblock.inner.free_blocks_count as _
-    }
-    ///
-    pub fn block_size(&self) -> usize {
-        self.superblock.inner.block_size()
-    }
-    ///
-    pub fn log_block_size(&self) -> u32 {
-        self.superblock.inner.log_block_size + 10
-    }
-    ///
-    pub fn sector_size(&self) -> usize {
-        S::SIZE
-    }
-    ///
-    pub fn log_sector_size(&self) -> u32 {
-        S::LOG_SIZE
-    }
-}
-
-#[cfg(test)]
-mod tests {
-    use std::cell::RefCell;
-    use std::fs::File;
-
-    use sector::{Address, Size512};
-    use volume::Volume;
-
-    use super::Ext2;
-
-    #[test]
-    fn file_len() {
-        let file = RefCell::new(File::open("ext2.img").unwrap());
-        assert_eq!(
-            Address::<Size512>::from(2048_u64)
-                - Address::<Size512>::from(1024_u64),
-            Address::<Size512>::new(2, 0)
-        );
-        assert_eq!(
-            unsafe {
-                file.slice_unchecked(
-                    Address::<Size512>::from(1024_u64)
-                        ..Address::<Size512>::from(2048_u64),
-                )
-                .len()
-            },
-            1024
-        );
-    }
-
-    #[test]
-    fn file() {
-        let file = RefCell::new(File::open("ext2.img").unwrap());
-        let fs = Ext2::<Size512, _>::new(file);
-
-        assert!(
-            fs.is_ok(),
-            "Err({:?})",
-            fs.err().unwrap_or_else(|| unreachable!()),
-        );
-
-        let fs = fs.unwrap();
-
-        let vers = fs.version();
-        println!("version: {}.{}", vers.0, vers.1);
-        assert_eq!(128, fs.inode_size());
-    }
-}
diff --git a/ext2-rs/src/fs/sync.rs b/ext2-rs/src/fs/sync.rs
deleted file mode 100644
index bda8360..0000000
--- a/ext2-rs/src/fs/sync.rs
+++ /dev/null
@@ -1,905 +0,0 @@
-//!
-
-use crate::sys::inode::TypePerm;
-
-use {
-    super::Ext2,
-    alloc::{
-        sync::Arc,
-        {string::String, vec::Vec},
-    },
-    core::{
-        fmt::{self, Debug},
-        iter::Iterator,
-        num::NonZeroU32,
-    },
-    error::Error,
-    genfs::*,
-    sector::{Address, SectorSize},
-    spin::{Mutex, MutexGuard},
-    sys::inode::Inode as RawInode,
-    volume::Volume,
-};
-/// DOCME: what is this?
-pub struct Synced<T> {
-    inner: Arc<Mutex<T>>,
-}
-
-impl<T> Synced<T> {
-    /// DOCME: what is this?
-    pub fn with_inner(inner: T) -> Synced<T> {
-        Synced {
-            inner: Arc::new(Mutex::new(inner)),
-        }
-    }
-
-    /// DOCME: what is this?
-    pub fn inner<'a>(&'a self) -> MutexGuard<'a, T> {
-        self.inner.lock()
-    }
-}
-
-impl<T> Clone for Synced<T> {
-    fn clone(&self) -> Self {
-        Synced {
-            inner: self.inner.clone(),
-        }
-    }
-}
-
-impl<S: SectorSize, V: Volume<u8, S>> Synced<Ext2<S, V>> {
-    /// DOCME: what is this?
-    pub fn new(volume: V) -> Result<Synced<Ext2<S, V>>, Error> {
-        Ext2::new(volume).map(Synced::with_inner)
-    }
-    /// Get the root inode.
-    pub fn root_inode(&self) -> Inode<S, V> {
-        self.inode_nth(2).unwrap()
-    }
-    /// Get the inode at the given index.
-    pub fn inode_nth(&self, index: usize) -> Option<Inode<S, V>> {
-        self.inodes_nth(index).next()
-    }
-    /// DOCME: what is this?
-    pub fn inodes(&self) -> Inodes<S, V> {
-        self.inodes_nth(1)
-    }
-    /// DOCME: what is this?
-    pub fn inodes_nth(&self, index: usize) -> Inodes<S, V> {
-        assert!(index > 0, "inodes are 1-indexed");
-        let inner = self.inner();
-        Inodes {
-            fs: self.clone(),
-            log_block_size: inner.log_block_size(),
-            inode_size: inner.inode_size(),
-            inodes_per_group: inner.inodes_count(),
-            inodes_count: inner.total_inodes_count(),
-            index,
-        }
-    }
-    /// DOCME: what is this?
-    pub fn sector_size(&self) -> usize {
-        S::SIZE
-    }
-    /// DOCME: what is this?
-    pub fn log_sector_size(&self) -> u32 {
-        S::LOG_SIZE
-    }
-}
-
-impl<S: SectorSize, V: Volume<u8, S>> Fs for Synced<Ext2<S, V>> {
-    type Path = [u8];
-    type PathOwned = Vec<u8>;
-    type File = Inode<S, V>;
-    type Dir = Directory<S, V>;
-    type DirEntry = DirectoryEntry;
-    type Metadata = (); // TODO
-    type Permissions = (); // TODO
-    type Error = Error;
-
-    fn open(
-        &self,
-        abs_path: &Self::Path,
-        _options: &OpenOptions<Self::Permissions>,
-    ) -> Result<Self::File, Self::Error> {
-        fn inner<'a, S, V, I>(
-            fs: &Synced<Ext2<S, V>>,
-            inode: Inode<S, V>,
-            mut path: I,
-            abs_path: &[u8],
-        ) -> Result<Inode<S, V>, Error>
-        where
-            S: SectorSize,
-            V: Volume<u8, S>,
-            I: Iterator<Item = &'a [u8]>,
-        {
-            let name = match path.next() {
-                Some(name) => name,
-                None => return Ok(inode),
-            };
-
-            let mut dir =
-                inode.directory().ok_or_else(|| Error::NotADirectory {
-                    inode: inode.num,
-                    name: String::from_utf8_lossy(abs_path).into_owned(),
-                })?;
-
-            let entry = dir
-                .find(|entry| {
-                    entry.is_err() || entry.as_ref().unwrap().name == name
-                })
-                .ok_or_else(|| Error::NotFound {
-                    name: String::from_utf8_lossy(abs_path).into_owned(),
-                })??;
-
-            let inode = fs
-                .inode_nth(entry.inode)
-                .ok_or(Error::InodeNotFound { inode: inode.num })?;
-
-            inner(fs, inode, path, abs_path)
-        }
-
-        if abs_path.is_empty() || abs_path[0] != b'/' {
-            return Err(Error::NotAbsolute {
-                name: String::from_utf8_lossy(abs_path).into_owned(),
-            });
-        }
-
-        if abs_path == b"/" {
-            return Ok(self.root_inode());
-        }
-
-        let mut path = abs_path.split(|byte| *byte == b'/');
-        path.next();
-        let root = self.root_inode();
-
-        inner(self, root, path, abs_path)
-    }
-
-    fn remove_file(&mut self, _path: &Self::Path) -> Result<(), Self::Error> {
-        unimplemented!()
-    }
-
-    fn metadata(
-        &self,
-        _path: &Self::Path,
-    ) -> Result<Self::Metadata, Self::Error> {
-        unimplemented!()
-    }
-
-    fn symlink_metadata(
-        &self,
-        _path: &Self::Path,
-    ) -> Result<Self::Metadata, Self::Error> {
-        unimplemented!()
-    }
-
-    fn rename(
-        &mut self,
-        _from: &Self::Path,
-        _to: &Self::Path,
-    ) -> Result<(), Self::Error> {
-        unimplemented!()
-    }
-
-    fn copy(
-        &mut self,
-        _from: &Self::Path,
-        _to: &Self::Path,
-    ) -> Result<u64, Self::Error> {
-        unimplemented!()
-    }
-
-    fn hard_link(
-        &mut self,
-        _src: &Self::Path,
-        _dst: &Self::Path,
-    ) -> Result<(), Self::Error> {
-        unimplemented!()
-    }
-
-    fn symlink(
-        &mut self,
-        _src: &Self::Path,
-        _dst: &Self::Path,
-    ) -> Result<(), Self::Error> {
-        unimplemented!()
-    }
-
-    fn read_link(
-        &self,
-        _path: &Self::Path,
-    ) -> Result<Self::PathOwned, Self::Error> {
-        unimplemented!()
-    }
-
-    fn canonicalize(
-        &self,
-        _path: &Self::Path,
-    ) -> Result<Self::PathOwned, Self::Error> {
-        unimplemented!()
-    }
-
-    fn create_dir(
-        &mut self,
-        _path: &Self::Path,
-        _options: &DirOptions<Self::Permissions>,
-    ) -> Result<(), Self::Error> {
-        unimplemented!()
-    }
-
-    fn remove_dir(&mut self, _path: &Self::Path) -> Result<(), Self::Error> {
-        unimplemented!()
-    }
-
-    fn remove_dir_all(
-        &mut self,
-        _path: &Self::Path,
-    ) -> Result<(), Self::Error> {
-        unimplemented!()
-    }
-
-    fn read_dir(&self, path: &Self::Path) -> Result<Self::Dir, Self::Error> {
-        let inode = self.open(path, OpenOptions::new().read(true))?;
-        inode.directory().ok_or(Error::NotADirectory {
-            inode: inode.num,
-            name: String::from_utf8_lossy(path).into_owned(),
-        })
-    }
-
-    fn set_permissions(
-        &mut self,
-        _path: &Self::Path,
-        _perm: Self::Permissions,
-    ) -> Result<(), Self::Error> {
-        unimplemented!()
-    }
-}
-
-impl<S: SectorSize, V: Volume<u8, S>> Debug for Synced<Ext2<S, V>> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "Synced<Ext2<{}>>", S::SIZE)
-    }
-}
-
-#[derive(Debug, Clone)]
-/// A collection of inodes.
-pub struct Inodes<S: SectorSize, V: Volume<u8, S>> {
-    fs: Synced<Ext2<S, V>>,
-    log_block_size: u32,
-    inode_size: usize,
-    inodes_per_group: usize,
-    inodes_count: usize,
-    index: usize,
-}
-
-impl<S: SectorSize, V: Volume<u8, S>> Iterator for Inodes<S, V> {
-    type Item = Inode<S, V>;
-
-    fn next(&mut self) -> Option<Self::Item> {
-        if self.index < self.inodes_count {
-            let block_group = (self.index - 1) / self.inodes_per_group;
-            let index = (self.index - 1) % self.inodes_per_group;
-            self.index += 1;
-
-            let fs = self.fs.inner();
-
-            let inodes_block =
-                fs.block_groups.inner[block_group].inode_table_block;
-
-            let offset = Address::with_block_size(
-                inodes_block,
-                (index * self.inode_size) as i32,
-                self.log_block_size,
-            );
-            let raw = unsafe {
-                RawInode::find_inode(&fs.volume, offset, self.inode_size).ok()
-            };
-            raw.map(|(raw, offset)| {
-                Inode::new(
-                    self.fs.clone(),
-                    raw,
-                    offset,
-                    (self.index - 1) as u32,
-                )
-            })
-        } else {
-            None
-        }
-    }
-}
-
-#[derive(Debug)]
-/// A single inode in an ext2 filesystem.
-pub struct Inode<S: SectorSize, V: Volume<u8, S>> {
-    fs: Synced<Ext2<S, V>>,
-    inner: RawInode,
-    addr: Address<S>,
-    num: u32,
-}
-
-impl<S: SectorSize, V: Volume<u8, S>> Clone for Inode<S, V> {
-    fn clone(&self) -> Self {
-        Inode {
-            fs: self.fs.clone(),
-            inner: self.inner,
-            addr: self.addr,
-            num: self.num,
-        }
-    }
-}
-
-impl<S: SectorSize, V: Volume<u8, S>> Inode<S, V> {
-    ///
-    pub fn new(
-        fs: Synced<Ext2<S, V>>,
-        inner: RawInode,
-        addr: Address<S>,
-        num: u32,
-    ) -> Inode<S, V> {
-        Inode {
-            fs,
-            inner,
-            addr,
-            num,
-        }
-    }
-    /// Read to the end of a buffer.
-    pub fn read_to_end(&self, buf: &mut Vec<u8>) -> Result<usize, Error> {
-        let total_size = self.size();
-        let capacity = buf.capacity();
-        if capacity < total_size {
-            buf.reserve_exact(total_size - capacity);
-        }
-        unsafe {
-            buf.set_len(total_size);
-        }
-        let size = self.read(&mut buf[..]);
-        size.map(|size| {
-            unsafe {
-                buf.set_len(size);
-            }
-            size
-        })
-        .map_err(|err| {
-            unsafe {
-                buf.set_len(0);
-            }
-            err
-        })
-    }
-    /// Return blocks on a sector
-    pub fn blocks(&self) -> InodeBlocks<S, V> {
-        InodeBlocks {
-            inode: self.clone(),
-            index: 0,
-        }
-    }
-    /// return a directory iterator
-    pub fn directory(&self) -> Option<Directory<S, V>> {
-        if self.is_dir() {
-            Some(Directory {
-                blocks: self.blocks(),
-                offset: 0,
-                buffer: None,
-                block_size: {
-                    let fs = self.fs.inner();
-                    fs.block_size()
-                },
-            })
-        } else {
-            None
-        }
-    }
-    /// Determine if an inode is a directory
-    pub fn is_dir(&self) -> bool {
-        { self.inner.type_perm }.contains(TypePerm::DIRECTORY)
-        // self.inner.type_perm.contains(TypePerm::DIRECTORY)
-    }
-    ///
-    pub fn block(&self, index: usize) -> Option<NonZeroU32> {
-        self.try_block(index).ok().and_then(|block| block)
-    }
-    /// Try to get a block
-    pub fn try_block(
-        &self,
-        mut index: usize,
-    ) -> Result<Option<NonZeroU32>, Error> {
-        // number of blocks in direct table: 12
-        // number of blocks in indirect table: block_size/4
-        //   why?
-        //     - a block is n bytes long
-        //     - a block address occupies 32 bits, or 4 bytes
-        //     - thus, n/4
-        // number of blocks in doubly table: (block_size/4)^2
-        //   why?
-        //     - every entry in the doubly table points to another block
-        //     - that's n/4 blocks, where n is the block size
-        //     - every block contains n/4 block pointers
-        //     - that's n/4 blocks with n/4 pointers each = (n/4)^2
-        // number of blocks in triply table: (block_size/4)^3
-
-        fn block_index<S: SectorSize, V: Volume<u8, S>>(
-            volume: &V,
-            block: u32,
-            index: usize,
-            log_block_size: u32,
-        ) -> Result<Option<NonZeroU32>, Error> {
-            let offset = (index * 4) as i32;
-            let end = offset + 4;
-            let addr = Address::with_block_size(block, offset, log_block_size);
-            let end = Address::with_block_size(block, end, log_block_size);
-            let block = volume.slice(addr..end);
-            match block {
-                Ok(block) => unsafe {
-                    Ok(NonZeroU32::new(block.dynamic_cast::<u32>().0))
-                },
-                Err(err) => Err(err.into()),
-            }
-        }
-
-        let fs = self.fs.inner();
-
-        let bs4 = fs.block_size() / 4;
-        let log_block_size = fs.log_block_size();
-
-        if index < 12 {
-            return Ok(NonZeroU32::new(self.inner.direct_pointer[index]));
-        }
-
-        index -= 12;
-
-        if index < bs4 {
-            let block = self.inner.indirect_pointer;
-            return block_index(&fs.volume, block, index, log_block_size);
-        }
-
-        index -= bs4;
-
-        if index < bs4 * bs4 {
-            let indirect_index = index >> (log_block_size + 2);
-            let block = match block_index(
-                &fs.volume,
-                self.inner.doubly_indirect,
-                indirect_index,
-                log_block_size,
-            ) {
-                Ok(Some(block)) => block.get(),
-                Ok(None) => return Ok(None),
-                Err(err) => return Err(err),
-            };
-            return block_index(
-                &fs.volume,
-                block,
-                index & (bs4 - 1),
-                log_block_size,
-            );
-        }
-
-        index -= bs4 * bs4;
-
-        if index < bs4 * bs4 * bs4 {
-            let doubly_index = index >> (2 * log_block_size + 4);
-            let indirect = match block_index(
-                &fs.volume,
-                self.inner.triply_indirect,
-                doubly_index,
-                log_block_size,
-            ) {
-                Ok(Some(block)) => block.get(),
-                Ok(None) => return Ok(None),
-                Err(err) => return Err(err),
-            };
-            let indirect_index = (index >> (log_block_size + 2)) & (bs4 - 1);
-            let block = match block_index(
-                &fs.volume,
-                indirect as u32,
-                indirect_index,
-                log_block_size,
-            ) {
-                Ok(Some(block)) => block.get(),
-                Ok(None) => return Ok(None),
-                Err(err) => return Err(err),
-            };
-            return block_index(
-                &fs.volume,
-                block,
-                index & (bs4 - 1),
-                log_block_size,
-            );
-        }
-
-        Ok(None)
-    }
-    ///
-    pub fn in_use(&self) -> bool {
-        self.inner.hard_links > 0
-    }
-    /// return the uid
-    pub fn uid(&self) -> u16 {
-        self.inner.uid
-    }
-    ///
-    pub fn sectors(&self) -> usize {
-        self.inner.sectors_count as usize
-    }
-    ///
-    pub fn size32(&self) -> u32 {
-        self.inner.size_low
-    }
-    ///
-    pub fn size64(&self) -> u64 {
-        self.inner.size_low as u64 | (self.inner.size_high as u64) << 32
-    }
-    ///
-    #[cfg(target_pointer_width = "64")]
-    #[inline]
-    pub fn size(&self) -> usize {
-        self.size64() as usize
-    }
-
-    #[cfg(target_pointer_width = "32")]
-    #[inline]
-    pub fn size(&self) -> usize {
-        self.size32() as usize
-    }
-
-    /// ableOS: expose type_perm
-    pub fn type_perm(&self) -> TypePerm {
-        self.inner.type_perm
-    }
-}
-
-impl<S: SectorSize, V: Volume<u8, S>> File for Inode<S, V> {
-    type Error = Error;
-
-    fn read(&self, buf: &mut [u8]) -> Result<usize, Error> {
-        let total_size = self.size();
-        let block_size = {
-            let fs = self.fs.inner();
-            fs.block_size()
-        };
-        let mut offset = 0;
-
-        for block in self.blocks() {
-            match block {
-                Ok((data, _)) => {
-                    let data_size = block_size
-                        .min(total_size - offset)
-                        .min(buf.len() - offset);
-                    let end = offset + data_size;
-                    buf[offset..end].copy_from_slice(&data[..data_size]);
-                    offset += data_size;
-                }
-                Err(err) => return Err(err),
-            }
-        }
-
-        Ok(offset)
-    }
-
-    fn write(&mut self, _buf: &[u8]) -> Result<usize, Self::Error> {
-        unimplemented!()
-    }
-
-    fn flush(&mut self) -> Result<(), Self::Error> {
-        unimplemented!()
-    }
-
-    fn seek(&mut self, _pos: SeekFrom) -> Result<u64, Self::Error> {
-        unimplemented!()
-    }
-}
-
-///
-#[derive(Debug, Clone)]
-pub struct InodeBlocks<S: SectorSize, V: Volume<u8, S>> {
-    inode: Inode<S, V>,
-    index: usize,
-}
-
-impl<S: SectorSize, V: Volume<u8, S>> Iterator for InodeBlocks<S, V> {
-    type Item = Result<(Vec<u8>, Address<S>), Error>;
-
-    fn next(&mut self) -> Option<Self::Item> {
-        let block = self.inode.try_block(self.index);
-        let block = match block {
-            Ok(Some(ok)) => ok,
-            Ok(None) => return None,
-            Err(err) => return Some(Err(err)),
-        };
-
-        self.index += 1;
-        let fs = self.inode.fs.inner();
-
-        let block = block.get();
-        let log_block_size = fs.log_block_size();
-        let offset = Address::with_block_size(block, 0, log_block_size);
-        let end = Address::with_block_size(block + 1, 0, log_block_size);
-
-        let slice = fs
-            .volume
-            .slice(offset..end)
-            .map(|slice| (slice.to_vec(), offset))
-            .map_err(|err| err.into());
-        Some(slice)
-    }
-}
-
-#[derive(Debug, Clone)]
-/// A directory structure
-pub struct Directory<S: SectorSize, V: Volume<u8, S>> {
-    blocks: InodeBlocks<S, V>,
-    offset: usize,
-    buffer: Option<Vec<u8>>,
-    block_size: usize,
-}
-
-impl<S: SectorSize, V: Volume<u8, S>> Dir<DirectoryEntry, Error>
-    for Directory<S, V>
-{
-}
-
-impl<S: SectorSize, V: Volume<u8, S>> Iterator for Directory<S, V> {
-    type Item = Result<DirectoryEntry, Error>;
-
-    fn next(&mut self) -> Option<Self::Item> {
-        if self.buffer.is_none() || self.offset >= self.block_size {
-            self.buffer = match self.blocks.next() {
-                None => return None,
-                Some(Ok((block, _))) => Some(block),
-                Some(Err(err)) => return Some(Err(err)),
-            };
-
-            self.offset = 0;
-        }
-
-        let buffer = &self.buffer.as_ref().unwrap()[self.offset..];
-
-        let inode = buffer[0] as u32
-            | (buffer[1] as u32) << 8
-            | (buffer[2] as u32) << 16
-            | (buffer[3] as u32) << 24;
-        if inode == 0 {
-            return None;
-        }
-
-        let size = buffer[4] as u16 | (buffer[5] as u16) << 8;
-        let len = buffer[6];
-        let ty = buffer[7];
-
-        let name = buffer[8..8 + len as usize].to_vec();
-
-        self.offset += size as usize;
-
-        Some(Ok(DirectoryEntry {
-            name,
-            inode: inode as usize,
-            ty,
-        }))
-    }
-}
-
-#[derive(Clone)]
-/// A directory entry
-pub struct DirectoryEntry {
-    /// The name of the entry
-    pub name: Vec<u8>,
-    /// The inode of the entry
-    pub inode: usize,
-    ///
-    pub ty: u8,
-}
-
-impl DirEntry for DirectoryEntry {
-    type Path = [u8];
-    type PathOwned = Vec<u8>;
-    type Metadata = (); // TODO
-    type FileType = u8; // TODO: enum FileType
-    type Error = Error;
-
-    fn path(&self) -> Self::PathOwned {
-        unimplemented!()
-    }
-
-    fn metadata(&self) -> Result<Self::Metadata, Self::Error> {
-        unimplemented!()
-    }
-
-    fn file_type(&self) -> Result<Self::FileType, Self::Error> {
-        Ok(self.ty)
-    }
-
-    fn file_name(&self) -> &Self::Path {
-        &self.name
-    }
-}
-
-impl DirectoryEntry {
-    /// Turns a filename into a string for display
-    pub fn file_name_string(&self) -> String {
-        let mut filename = String::new();
-        for ch in &self.name {
-            filename.push(*ch as char);
-        }
-        filename
-    }
-}
-
-#[cfg(test)]
-mod tests {
-    use std::cell::RefCell;
-    use std::fs::File;
-
-    use genfs::{File as GenFile, Fs, OpenOptions};
-
-    use sector::{SectorSize, Size512};
-    use volume::Volume;
-
-    use super::{Ext2, Inode, Synced};
-
-    #[test]
-    fn file() {
-        let file = RefCell::new(File::open("ext2.img").unwrap());
-        let fs = Synced::<Ext2<Size512, _>>::new(file);
-
-        assert!(
-            fs.is_ok(),
-            "Err({:?})",
-            fs.err().unwrap_or_else(|| unreachable!()),
-        );
-
-        let fs = fs.unwrap();
-        let inner = fs.inner();
-
-        let vers = inner.version();
-        println!("version: {}.{}", vers.0, vers.1);
-        assert_eq!(128, inner.inode_size());
-    }
-
-    #[test]
-    fn inodes() {
-        let file = RefCell::new(File::open("ext2.img").unwrap());
-        let fs = Synced::<Ext2<Size512, _>>::new(file);
-
-        assert!(
-            fs.is_ok(),
-            "Err({:?})",
-            fs.err().unwrap_or_else(|| unreachable!()),
-        );
-
-        let fs = fs.unwrap();
-
-        let inodes = fs.inodes().filter(|inode| inode.in_use());
-        for inode in inodes {
-            println!("{:?}", inode);
-        }
-    }
-
-    #[test]
-    fn inode_blocks() {
-        use std::str;
-        let file = RefCell::new(File::open("ext2.img").unwrap());
-        let fs = Synced::<Ext2<Size512, _>>::new(file).unwrap();
-
-        let inodes = fs.inodes().filter(|inode| {
-            inode.in_use() && inode.uid() == 1000 && inode.size() < 1024
-        });
-        for inode in inodes {
-            println!("{:?}", inode);
-            let size = inode.size();
-            for block in inode.blocks() {
-                let (data, _) = block.unwrap();
-                assert_eq!(data.len(), {
-                    let fs = fs.inner();
-                    fs.block_size()
-                });
-                println!("{:?}", &data[..size]);
-                let _ = str::from_utf8(&data[..size])
-                    .map(|string| println!("{}", string));
-            }
-        }
-    }
-
-    #[test]
-    fn read_inode() {
-        let file = RefCell::new(File::open("ext2.img").unwrap());
-        let fs = Synced::<Ext2<Size512, _>>::new(file).unwrap();
-
-        let inodes = fs.inodes().filter(|inode| {
-            inode.in_use() && inode.uid() == 1000 && inode.size() < 1024
-        });
-        for inode in inodes {
-            let mut buf = Vec::with_capacity(inode.size());
-            unsafe {
-                buf.set_len(inode.size());
-            }
-            let size = inode.read(&mut buf[..]);
-            assert!(size.is_ok());
-            let size = size.unwrap();
-            assert_eq!(size, inode.size());
-            unsafe {
-                buf.set_len(size);
-            }
-        }
-    }
-
-    #[test]
-    fn read_big() {
-        let file = RefCell::new(File::open("ext2.img").unwrap());
-        let fs = Synced::<Ext2<Size512, _>>::new(file).unwrap();
-
-        let inodes = fs.inodes().filter(|inode| {
-            inode.in_use() && inode.uid() == 1000 && inode.size() == 537600
-        });
-        for inode in inodes {
-            let mut buf = Vec::with_capacity(inode.size());
-            unsafe {
-                buf.set_len(inode.size());
-            }
-            let size = inode.read(&mut buf[..]);
-            assert!(size.is_ok());
-            let size = size.unwrap();
-            assert_eq!(size, inode.size());
-            unsafe {
-                buf.set_len(size);
-            }
-
-            for (i, &x) in buf.iter().enumerate() {
-                if i & 1 == 0 {
-                    assert_eq!(x, b'u', "{}", i);
-                } else {
-                    assert_eq!(x, b'\n', "{}", i);
-                }
-            }
-        }
-    }
-
-    #[test]
-    fn walkdir() {
-        use std::str;
-
-        fn walk<'vol, S: SectorSize, V: Volume<u8, S>>(
-            fs: &'vol Synced<Ext2<S, V>>,
-            inode: Inode<S, V>,
-            name: String,
-        ) {
-            inode.directory().map(|dir| {
-                for entry in dir {
-                    assert!(entry.is_ok());
-                    let entry = entry.unwrap();
-                    let entry_name = str::from_utf8(&entry.name).unwrap_or("?");
-                    println!("{}/{} => {}", name, entry_name, entry.inode,);
-                    if entry_name != "." && entry_name != ".." {
-                        walk(
-                            fs,
-                            fs.inode_nth(entry.inode).unwrap(),
-                            format!("{}/{}", name, entry_name),
-                        );
-                    }
-                }
-            });
-        }
-
-        let file = RefCell::new(File::open("ext2.img").unwrap());
-        let fs = Synced::<Ext2<Size512, _>>::new(file).unwrap();
-
-        let root = fs.root_inode();
-        walk(&fs, root, String::new());
-    }
-
-    #[test]
-    fn find() {
-        use std::str;
-        let file = RefCell::new(File::open("ext2.img").unwrap());
-        let fs = Synced::<Ext2<Size512, _>>::new(file).unwrap();
-
-        let found = fs.open(b"/home/funky/README.md", &OpenOptions::new());
-
-        assert!(found.is_ok());
-        let inode = found.unwrap();
-        let mut vec = Vec::new();
-        assert!(inode.read_to_end(&mut vec).is_ok());
-        println!("{}", str::from_utf8(&vec).unwrap());
-    }
-}
diff --git a/ext2-rs/src/lib.rs b/ext2-rs/src/lib.rs
deleted file mode 100644
index 506163a..0000000
--- a/ext2-rs/src/lib.rs
+++ /dev/null
@@ -1,36 +0,0 @@
-//! Ext2 crate for ableOS
-
-#![deny(missing_docs)]
-#![feature(min_specialization, step_trait, associated_type_defaults)]
-#![cfg_attr(all(not(test), feature = "no_std"), no_std)]
-
-extern crate alloc;
-
-#[macro_use]
-extern crate bitflags;
-extern crate genfs;
-extern crate spin;
-
-#[cfg(any(test, not(feature = "no_std")))]
-extern crate core;
-
-pub mod error;
-pub mod fs;
-pub mod sector;
-pub mod sys;
-pub mod volume;
-
-#[cfg(test)]
-mod tests {
-    use sys::block_group::*;
-    use sys::inode::*;
-    use sys::superblock::*;
-
-    #[test]
-    fn sizes() {
-        use std::mem::size_of;
-        assert_eq!(size_of::<Superblock>(), 1024);
-        assert_eq!(size_of::<BlockGroupDescriptor>(), 32);
-        assert_eq!(size_of::<Inode>(), 128);
-    }
-}
diff --git a/ext2-rs/src/sector.rs b/ext2-rs/src/sector.rs
deleted file mode 100644
index f657e3a..0000000
--- a/ext2-rs/src/sector.rs
+++ /dev/null
@@ -1,242 +0,0 @@
-//! Sector data.
-
-use core::{
-    fmt::{self, Debug, Display, LowerHex},
-    iter::Step,
-    marker::PhantomData,
-    ops::{Add, Sub},
-};
-/// Size of a sector in bytes
-pub trait SectorSize: Clone + Copy + PartialEq + PartialOrd + 'static {
-    /// DOCME: What is this?
-    const LOG_SIZE: u32;
-    /// DOCME: What is this?
-    const SIZE: usize = 1 << Self::LOG_SIZE;
-    /// DOCME: What is this?
-    const OFFSET_MASK: u32 = (Self::SIZE - 1) as u32;
-}
-
-#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
-/// DOCME: What is this?    
-pub struct Size512;
-impl SectorSize for Size512 {
-    const LOG_SIZE: u32 = 9;
-}
-
-#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
-/// DOCME: What is this?
-pub struct Size1024;
-impl SectorSize for Size1024 {
-    const LOG_SIZE: u32 = 10;
-}
-/// DOCME: What is this?
-#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
-pub struct Size2048;
-impl SectorSize for Size2048 {
-    const LOG_SIZE: u32 = 11;
-}
-
-#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
-/// DOCME: What is this?
-pub struct Size4096;
-impl SectorSize for Size4096 {
-    const LOG_SIZE: u32 = 12;
-}
-
-/// Address in a physical sector
-#[derive(Clone, Debug, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
-pub struct Address<S: SectorSize> {
-    sector: u32,
-    offset: u32,
-    _phantom: PhantomData<S>,
-}
-
-impl<S: SectorSize> Address<S> {
-    ///
-    pub unsafe fn new_unchecked(sector: u32, offset: u32) -> Address<S> {
-        assert!((offset as usize) < S::SIZE, "offset out of sector bounds");
-        let _phantom = PhantomData;
-        Address {
-            sector,
-            offset,
-            _phantom,
-        }
-    }
-    ///
-    pub fn new(sector: u32, offset: i32) -> Address<S> {
-        let sector = (sector as i32 + (offset >> S::LOG_SIZE)) as u32;
-        let offset = offset.unsigned_abs() & S::OFFSET_MASK;
-        unsafe { Address::new_unchecked(sector, offset) }
-    }
-    ///
-    pub fn with_block_size(
-        block: u32,
-        offset: i32,
-        log_block_size: u32,
-    ) -> Address<S> {
-        let block = (block as i32 + (offset >> log_block_size)) as u32;
-        let offset = offset.unsigned_abs() & ((1 << log_block_size) - 1);
-
-        let log_diff = log_block_size as i32 - S::LOG_SIZE as i32;
-        let top_offset = offset >> S::LOG_SIZE;
-        let offset = offset & ((1 << S::LOG_SIZE) - 1);
-        let sector = block << log_diff | top_offset;
-        unsafe { Address::new_unchecked(sector, offset) }
-    }
-    ///
-    pub fn into_index(&self) -> u64 {
-        ((self.sector as u64) << S::LOG_SIZE) + self.offset as u64
-    }
-    /// Get the size of the sector
-    pub const fn sector_size(&self) -> usize {
-        S::SIZE
-    }
-    /// DOCME: What is this?
-    pub const fn log_sector_size(&self) -> u32 {
-        S::LOG_SIZE
-    }
-    /// Return the sector number
-    pub fn sector(&self) -> u32 {
-        self.sector
-    }
-    /// Return the offset in the sector
-    pub fn offset(&self) -> u32 {
-        self.offset
-    }
-}
-
-impl<S: SectorSize> Step for Address<S> {
-    fn steps_between(start: &Self, end: &Self) -> Option<usize> {
-        if end.sector >= start.sector {
-            Some(end.sector as usize - start.sector as usize)
-        } else {
-            None
-        }
-    }
-
-    /*
-    fn replace_one(&mut self) -> Self {
-        mem::replace(self, Address::new(1, 0))
-    }
-
-    fn replace_zero(&mut self) -> Self {
-        mem::replace(self, Address::new(0, 0))
-    }
-
-    fn add_one(&self) -> Self {
-        Address::new(self.sector + 1, 0)
-    }
-
-    fn sub_one(&self) -> Self {
-        Address::new(self.sector - 1, 0)
-    }
-
-    fn add_usize(&self, n: usize) -> Option<Self> {
-        self.sector
-        .checked_add(n as u32)
-        .map(|sector| Address::new(sector, 0))
-    }
-    */
-
-    fn forward_checked(_start: Self, count: usize) -> Option<Self> {
-        todo!("forward_checked:  count: {}", count);
-    }
-
-    fn backward_checked(_start: Self, count: usize) -> Option<Self> {
-        todo!("backward_checked count: {}", count);
-    }
-}
-
-impl<S: SectorSize> Display for Address<S> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "{}:{}", self.sector, self.offset)
-    }
-}
-
-impl<S: SectorSize> LowerHex for Address<S> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "{:x}:{:x}", self.sector, self.offset)
-    }
-}
-
-impl<S: SectorSize> From<u64> for Address<S> {
-    fn from(idx: u64) -> Address<S> {
-        let sector = idx >> S::LOG_SIZE;
-        let offset = idx & S::OFFSET_MASK as u64;
-        Address::new(sector as u32, offset as i32)
-    }
-}
-
-impl<S: SectorSize> From<usize> for Address<S> {
-    fn from(idx: usize) -> Address<S> {
-        let sector = idx >> S::LOG_SIZE;
-        let offset = idx & S::OFFSET_MASK as usize;
-        Address::new(sector as u32, offset as i32)
-    }
-}
-
-impl<S: SectorSize> Add for Address<S> {
-    type Output = Address<S>;
-    fn add(self, rhs: Address<S>) -> Address<S> {
-        Address::new(
-            self.sector + rhs.sector,
-            (self.offset + rhs.offset) as i32,
-        )
-    }
-}
-
-impl<S: SectorSize> Sub for Address<S> {
-    type Output = Address<S>;
-    fn sub(self, rhs: Address<S>) -> Address<S> {
-        Address::new(
-            self.sector - rhs.sector,
-            self.offset as i32 - rhs.offset as i32,
-        )
-    }
-}
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-
-    #[test]
-    fn conv() {
-        assert_eq!(Address::<Size512>::new(0, 1024).into_index(), 1024);
-        assert_eq!(Address::<Size512>::from(1024_u64).into_index(), 1024);
-        assert_eq!(
-            Address::<Size512>::with_block_size(1, 256, 10).into_index(),
-            1024 + 256
-        );
-        assert_eq!(
-            Address::<Size512>::with_block_size(2, 0, 10).into_index(),
-            2048
-        );
-        assert_eq!(
-            Address::<Size512>::with_block_size(0, 1792, 10).into_index(),
-            1792
-        );
-    }
-
-    #[test]
-    fn arithmetic() {
-        assert_eq!(
-            Address::<Size512>::new(0, 512),
-            Address::<Size512>::new(1, 0),
-        );
-
-        assert_eq!(
-            Address::<Size512>::new(2, -256),
-            Address::<Size512>::new(1, 256),
-        );
-
-        let a = Address::<Size2048>::new(0, 1024);
-        let b = Address::<Size2048>::new(0, 1024);
-        assert_eq!(a + b, Address::<Size2048>::new(1, 0));
-        assert_eq!((a + b).into_index(), 2048);
-
-        let a = Address::<Size512>::new(0, 2048);
-        let b = Address::<Size512>::new(0, 256);
-        assert_eq!(a - b, Address::<Size512>::new(3, 256));
-        assert_eq!((a - b).into_index(), 1792);
-    }
-}
diff --git a/ext2-rs/src/sys/block_group.rs b/ext2-rs/src/sys/block_group.rs
deleted file mode 100644
index 90bf165..0000000
--- a/ext2-rs/src/sys/block_group.rs
+++ /dev/null
@@ -1,116 +0,0 @@
-//!
-
-use {
-    alloc::vec::Vec,
-    core::{fmt::Debug, mem},
-    error::Error,
-    sector::{Address, SectorSize},
-    volume::Volume,
-};
-
-/// The Block Group Descriptor Table contains a descriptor for each block group
-/// within the file system. The number of block groups within the file system,
-/// and correspondingly, the number of entries in the Block Group Descriptor
-/// Table, is described above. Each descriptor contains information regarding
-/// where important data structures for that group are located.
-///
-/// The (`BlockGroupDescriptor`) table is located in the block immediately
-/// following the Superblock. So if the block size (determined from a field in
-/// the superblock) is 1024 bytes per block, the Block Group Descriptor Table
-/// will begin at block 2. For any other block size, it will begin at block 1.
-/// Remember that blocks are numbered starting at 0, and that block numbers
-/// don't usually correspond to physical block addresses.
-#[repr(C, packed)]
-#[derive(Clone, Debug, Copy)]
-pub struct BlockGroupDescriptor {
-    /// Block address of block usage bitmap
-    pub block_usage_addr: u32,
-    /// Block address of inode usage bitmap
-    pub inode_usage_addr: u32,
-    /// Starting block address of inode table
-    pub inode_table_block: u32,
-    /// Number of unallocated blocks in group
-    pub free_blocks_count: u16,
-    /// Number of unallocated inodes in group
-    pub free_inodes_count: u16,
-    /// Number of directories in group
-    pub dirs_count: u16,
-    #[doc(hidden)]
-    _reserved: [u8; 14],
-}
-
-impl BlockGroupDescriptor {
-    /// Find a descriptor in a descriptor table
-    pub unsafe fn find_descriptor<S: SectorSize, V: Volume<u8, S>>(
-        haystack: &V,
-        offset: Address<S>,
-    ) -> Result<(BlockGroupDescriptor, Address<S>), Error> {
-        let end =
-            offset + Address::from(mem::size_of::<BlockGroupDescriptor>());
-        if haystack.size() < end {
-            return Err(Error::AddressOutOfBounds {
-                sector: end.sector(),
-                offset: end.offset(),
-                size: end.sector_size(),
-            });
-        }
-
-        let descr = haystack
-            .slice_unchecked(offset..end)
-            .dynamic_cast::<BlockGroupDescriptor>();
-
-        Ok(descr)
-    }
-    /// find a descriptor table
-    pub unsafe fn find_descriptor_table<S: SectorSize, V: Volume<u8, S>>(
-        haystack: &V,
-        offset: Address<S>,
-        count: usize,
-    ) -> Result<(Vec<BlockGroupDescriptor>, Address<S>), Error> {
-        let end = offset
-            + Address::from(count * mem::size_of::<BlockGroupDescriptor>());
-        if haystack.size() < end {
-            return Err(Error::AddressOutOfBounds {
-                sector: end.sector(),
-                offset: end.offset(),
-                size: end.sector_size(),
-            });
-        }
-
-        let mut vec = Vec::with_capacity(count);
-        for i in 0..count {
-            let offset = offset
-                + Address::from(i * mem::size_of::<BlockGroupDescriptor>());
-            vec.push({
-                BlockGroupDescriptor::find_descriptor(haystack, offset)?.0
-            });
-        }
-
-        Ok((vec, offset))
-    }
-}
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-    use sector::{Address, Size512};
-
-    #[test]
-    fn find() {
-        let volume = vec![0_u8; 4096];
-        let table = unsafe {
-            BlockGroupDescriptor::find_descriptor_table(
-                &volume,
-                Address::<Size512>::new(4, 0),
-                8,
-            )
-        };
-        assert!(
-            table.is_ok(),
-            "Err({:?})",
-            table.err().unwrap_or_else(|| unreachable!()),
-        );
-        let table = table.unwrap_or_else(|_| unreachable!());
-        assert_eq!(table.0.len(), 8);
-    }
-}
diff --git a/ext2-rs/src/sys/inode.rs b/ext2-rs/src/sys/inode.rs
deleted file mode 100644
index 0a129b6..0000000
--- a/ext2-rs/src/sys/inode.rs
+++ /dev/null
@@ -1,188 +0,0 @@
-//!
-use {
-    core::{fmt::Debug, mem},
-    error::Error,
-    sector::{Address, SectorSize},
-    volume::Volume,
-};
-
-/// An inode is a structure on the disk that represents a file, directory,
-/// symbolic link, etc. Inodes do not contain the data of the file / directory /
-/// etc. that they represent. Instead, they link to the blocks that actually
-/// contain the data. This lets the inodes themselves have a well-defined size
-/// which lets them be placed in easily indexed arrays. Each block group has an
-/// array of inodes it is responsible for, and conversely every inode within a
-/// file system belongs to one of such tables (and one of such block groups).
-#[repr(C, packed)]
-#[derive(Clone, Debug, Copy)]
-pub struct Inode {
-    /// Type and Permissions (see below)
-    pub type_perm: TypePerm,
-    /// User ID
-    pub uid: u16,
-    /// Lower 32 bits of size in bytes
-    pub size_low: u32,
-    /// Last Access Time (in POSIX time)
-    pub atime: u32,
-    /// Creation Time (in POSIX time)
-    pub ctime: u32,
-    /// Last Modification time (in POSIX time)
-    pub mtime: u32,
-    /// Deletion time (in POSIX time)
-    pub dtime: u32,
-    /// Group ID
-    pub gid: u16,
-    /// Count of hard links (directory entries) to this inode. When this
-    /// reaches 0, the data blocks are marked as unallocated.
-    pub hard_links: u16,
-    /// Count of disk sectors (not Ext2 blocks) in use by this inode, not
-    /// counting the actual inode structure nor directory entries linking
-    /// to the inode.
-    pub sectors_count: u32,
-    /// Flags
-    pub flags: Flags,
-    /// Operating System Specific value #1
-    pub _os_specific_1: [u8; 4],
-    /// Direct block pointers
-    pub direct_pointer: [u32; 12],
-    /// Singly Indirect Block Pointer (Points to a block that is a list of
-    /// block pointers to data)
-    pub indirect_pointer: u32,
-    /// Doubly Indirect Block Pointer (Points to a block that is a list of
-    /// block pointers to Singly Indirect Blocks)
-    pub doubly_indirect: u32,
-    /// Triply Indirect Block Pointer (Points to a block that is a list of
-    /// block pointers to Doubly Indirect Blocks)
-    pub triply_indirect: u32,
-    /// Generation number (Primarily used for NFS)
-    pub gen_number: u32,
-    /// In Ext2 version 0, this field is reserved. In version >= 1,
-    /// Extended attribute block (File ACL).
-    pub ext_attribute_block: u32,
-    /// In Ext2 version 0, this field is reserved. In version >= 1, Upper
-    /// 32 bits of file size (if feature bit set) if it's a file,
-    /// Directory ACL if it's a directory
-    pub size_high: u32,
-    /// Block address of fragment
-    pub frag_block_addr: u32,
-    /// Operating System Specific Value #2
-    pub _os_specific_2: [u8; 12],
-}
-
-impl Inode {
-    /// Discover the inode location on the disk.
-    pub unsafe fn find_inode<S: SectorSize, V: Volume<u8, S>>(
-        haystack: &V,
-        offset: Address<S>,
-        size: usize,
-    ) -> Result<(Inode, Address<S>), Error> {
-        if size != mem::size_of::<Inode>() {
-            unimplemented!("inodes with a size != 128");
-        }
-
-        let end = offset + Address::from(size);
-        if haystack.size() < end {
-            return Err(Error::AddressOutOfBounds {
-                sector: end.sector(),
-                offset: end.offset(),
-                size: end.sector_size(),
-            });
-        }
-
-        let inode = haystack
-            .slice_unchecked(offset..end)
-            .dynamic_cast::<Inode>();
-
-        Ok(inode)
-    }
-}
-
-bitflags! {
-    ///
-    // #[derive(Copy)]
-    pub struct TypePerm: u16 {
-        /// FIFO
-        const FIFO = 0x1000;
-        /// Character device
-        const CHAR_DEVICE = 0x2000;
-        /// Directory
-        const DIRECTORY = 0x4000;
-        /// Block device
-        const BLOCK_DEVICE = 0x6000;
-        /// Regular file
-        const FILE = 0x8000;
-        /// Symbolic link
-        const SYMLINK = 0xA000;
-        /// Unix socket
-        const SOCKET = 0xC000;
-        /// Other—execute permission
-        const O_EXEC = 0x001;
-        /// Other—write permission
-        const O_WRITE = 0x002;
-        /// Other—read permission
-        const O_READ = 0x004;
-        /// Group—execute permission
-        const G_EXEC = 0x008;
-        /// Group—write permission
-        const G_WRITE = 0x010;
-        /// Group—read permission
-        const G_READ = 0x020;
-        /// User—execute permission
-        const U_EXEC = 0x040;
-        /// User—write permission
-        const U_WRITE = 0x080;
-        /// User—read permission
-        const U_READ = 0x100;
-        /// Sticky Bit
-        const STICKY = 0x200;
-        /// Set group ID
-        const SET_GID = 0x400;
-        /// Set user ID
-        const SET_UID = 0x800;
-    }
-}
-
-bitflags! {
-    /// Flags
-    pub struct Flags: u32 {
-        /// Secure deletion (not used)
-        const SECURE_DEL = 0x00000001;
-        /// Keep a copy of data when deleted (not used)
-        const KEEP_COPY = 0x00000002;
-        /// File compression (not used)
-        const COMPRESSION = 0x00000004;
-        /// Synchronous updates—new data is written immediately to disk
-        const SYNC_UPDATE = 0x00000008;
-        /// Immutable file (content cannot be changed)
-        const IMMUTABLE = 0x00000010;
-        /// Append only
-        const APPEND_ONLY = 0x00000020;
-        /// File is not included in 'dump' command
-        const NODUMP = 0x00000040;
-        /// Last accessed time should not updated
-        const DONT_ATIME = 0x00000080;
-        /// Hash indexed directory
-        const HASH_DIR = 0x00010000;
-        /// AFS directory
-        const AFS_DIR = 0x00020000;
-        /// Journal file data
-        const JOURNAL_DATA = 0x00040000;
-    }
-}
-
-/// Unknown entry type
-pub const UNKNOWN: u8 = 0;
-/// FIFO entry type
-pub const FIFO: u8 = 1;
-/// Character device entry type
-pub const CHAR_DEVICE: u8 = 2;
-/// Directory entry type
-pub const DIRECTORY: u8 = 3;
-/// Block device entry type
-pub const BLOCK_DEVICE: u8 = 4;
-/// Regular file entry type
-pub const FILE: u8 = 5;
-/// Symbolic link entry type
-pub const SYMLINK: u8 = 6;
-/// Unix socket entry type
-pub const SOCKET: u8 = 7;
diff --git a/ext2-rs/src/sys/mod.rs b/ext2-rs/src/sys/mod.rs
deleted file mode 100644
index 32ec8fb..0000000
--- a/ext2-rs/src/sys/mod.rs
+++ /dev/null
@@ -1,5 +0,0 @@
-//!
-
-pub mod block_group;
-pub mod inode;
-pub mod superblock;
diff --git a/ext2-rs/src/sys/superblock.rs b/ext2-rs/src/sys/superblock.rs
deleted file mode 100644
index d97952e..0000000
--- a/ext2-rs/src/sys/superblock.rs
+++ /dev/null
@@ -1,284 +0,0 @@
-//! Superblock information
-
-use {
-    core::{fmt::Debug, mem},
-    error::Error,
-    sector::{Address, SectorSize},
-    volume::Volume,
-};
-
-/// Ext2 signature (0xef53), used to help confirm the presence of Ext2 on a
-/// volume
-pub const EXT2_MAGIC: u16 = 0xef53;
-
-/// Filesystem is free of errors
-pub const FS_CLEAN: u16 = 1;
-/// Filesystem has errors
-pub const FS_ERR: u16 = 2;
-
-/// Ignore errors
-pub const ERR_IGNORE: u16 = 1;
-/// Remount as read-only on error
-pub const ERR_RONLY: u16 = 2;
-/// Panic on error
-pub const ERR_PANIC: u16 = 3;
-
-/// Creator OS is Linux
-pub const OS_LINUX: u32 = 0;
-/// Creator OS is Hurd
-pub const OS_HURD: u32 = 1;
-/// Creator OS is Masix
-pub const OS_MASIX: u32 = 2;
-/// Creator OS is FreeBSD
-pub const OS_FREEBSD: u32 = 3;
-/// Creator OS is a BSD4.4-Lite derivative
-pub const OS_LITE: u32 = 4;
-
-/// The Superblock contains all information about the layout of the file system
-/// and possibly contains other important information like what optional
-/// features were used to create the file system.
-///
-/// The Superblock is always located at byte 1024 from the beginning of the
-/// volume and is exactly 1024 bytes in length. For example, if the disk uses
-/// 512 byte sectors, the Superblock will begin at LBA 2 and will occupy all of
-/// sector 2 and 3.
-#[repr(C, packed)]
-#[derive(Clone, Debug, Copy)]
-pub struct Superblock {
-    // taken from https://wiki.osdev.org/Ext2
-    /// Total number of inodes in file system
-    pub inodes_count: u32,
-    /// Total number of blocks in file system
-    pub blocks_count: u32,
-    /// Number of blocks reserved for superuser (see offset 80)
-    pub r_blocks_count: u32,
-    /// Total number of unallocated blocks
-    pub free_blocks_count: u32,
-    /// Total number of unallocated inodes
-    pub free_inodes_count: u32,
-    /// Block number of the block containing the superblock
-    pub first_data_block: u32,
-    /// log2 (block size) - 10. (In other words, the number to shift 1,024
-    /// to the left by to obtain the block size)
-    pub log_block_size: u32,
-    /// log2 (fragment size) - 10. (In other words, the number to shift
-    /// 1,024 to the left by to obtain the fragment size)
-    pub log_frag_size: i32,
-    /// Number of blocks in each block group
-    pub blocks_per_group: u32,
-    /// Number of fragments in each block group
-    pub frags_per_group: u32,
-    /// Number of inodes in each block group
-    pub inodes_per_group: u32,
-    /// Last mount time (in POSIX time)
-    pub mtime: u32,
-    /// Last written time (in POSIX time)
-    pub wtime: u32,
-    /// Number of times the volume has been mounted since its last
-    /// consistency check (fsck)
-    pub mnt_count: u16,
-    /// Number of mounts allowed before a consistency check (fsck) must be
-    /// done
-    pub max_mnt_count: i16,
-    /// Ext2 signature (0xef53), used to help confirm the presence of Ext2
-    /// on a volume
-    pub magic: u16,
-    /// File system state (see `FS_CLEAN` and `FS_ERR`)
-    pub state: u16,
-    /// What to do when an error is detected (see `ERR_IGNORE`, `ERR_RONLY` and
-    /// `ERR_PANIC`)
-    pub errors: u16,
-    /// Minor portion of version (combine with Major portion below to
-    /// construct full version field)
-    pub rev_minor: u16,
-    /// POSIX time of last consistency check (fsck)
-    pub lastcheck: u32,
-    /// Interval (in POSIX time) between forced consistency checks (fsck)
-    pub checkinterval: u32,
-    /// Operating system ID from which the filesystem on this volume was
-    /// created
-    pub creator_os: u32,
-    /// Major portion of version (combine with Minor portion above to
-    /// construct full version field)
-    pub rev_major: u32,
-    /// User ID that can use reserved blocks
-    pub block_uid: u16,
-    /// Group ID that can use reserved blocks
-    pub block_gid: u16,
-
-    /// First non-reserved inode in file system.
-    pub first_inode: u32,
-    /// SectorSize of each inode structure in bytes.
-    pub inode_size: u16,
-    /// Block group that this superblock is part of (if backup copy)
-    pub block_group: u16,
-    /// Optional features present (features that are not required to read
-    /// or write, but usually result in a performance increase)
-    pub features_opt: FeaturesOptional,
-    /// Required features present (features that are required to be
-    /// supported to read or write)
-    pub features_req: FeaturesRequired,
-    /// Features that if not supported, the volume must be mounted
-    /// read-only)
-    pub features_ronly: FeaturesROnly,
-    /// File system ID (what is output by blkid)
-    pub fs_id: [u8; 16],
-    /// Volume name (C-style string: characters terminated by a 0 byte)
-    pub volume_name: [u8; 16],
-    /// Path volume was last mounted to (C-style string: characters
-    /// terminated by a 0 byte)
-    pub last_mnt_path: [u8; 64],
-    /// Compression algorithms used (see Required features above)
-    pub compression: u32,
-    /// Number of blocks to preallocate for files
-    pub prealloc_blocks_files: u8,
-    /// Number of blocks to preallocate for directories
-    pub prealloc_blocks_dirs: u8,
-    #[doc(hidden)]
-    _unused: [u8; 2],
-    /// Journal ID (same style as the File system ID above)
-    pub journal_id: [u8; 16],
-    /// Journal inode
-    pub journal_inode: u32,
-    /// Journal device
-    pub journal_dev: u32,
-    /// Head of orphan inode list
-    pub journal_orphan_head: u32,
-    #[doc(hidden)]
-    _reserved: [u8; 788],
-}
-impl Superblock {
-    /// Discover the location of the superblock in the given block device.
-    pub unsafe fn find<S: SectorSize, V: Volume<u8, S>>(
-        haystack: &V,
-    ) -> Result<(Superblock, Address<S>), Error> {
-        let offset = Address::from(1024_usize);
-        let end = offset + Address::from(mem::size_of::<Superblock>());
-        if haystack.size() < end {
-            return Err(Error::AddressOutOfBounds {
-                sector: end.sector(),
-                offset: end.offset(),
-                size: end.sector_size(),
-            });
-        }
-
-        let superblock = {
-            haystack
-                .slice_unchecked(offset..end)
-                .dynamic_cast::<Superblock>()
-        };
-
-        if superblock.0.magic != EXT2_MAGIC {
-            Err(Error::BadMagic {
-                magic: superblock.0.magic,
-            })
-        } else {
-            Ok(superblock)
-        }
-    }
-
-    #[inline]
-    /// Return the block size
-    pub fn block_size(&self) -> usize {
-        1024 << self.log_block_size
-    }
-
-    #[inline]
-    /// Return the fragment size
-    pub fn frag_size(&self) -> usize {
-        1024 << self.log_frag_size
-    }
-    /// Return the number of blocks per group
-    pub fn block_group_count(&self) -> Result<u32, (u32, u32)> {
-        let blocks_mod = self.blocks_count % self.blocks_per_group;
-        let inodes_mod = self.inodes_count % self.inodes_per_group;
-        let blocks_inc = if blocks_mod == 0 { 0 } else { 1 };
-        let inodes_inc = if inodes_mod == 0 { 0 } else { 1 };
-        let by_blocks = self.blocks_count / self.blocks_per_group + blocks_inc;
-        let by_inodes = self.inodes_count / self.inodes_per_group + inodes_inc;
-        if by_blocks == by_inodes {
-            Ok(by_blocks)
-        } else {
-            Err((by_blocks, by_inodes))
-        }
-    }
-}
-
-bitflags! {
-    /// Optional features
-    pub struct FeaturesOptional: u32 {
-        /// Preallocate some number of (contiguous?) blocks (see
-        /// `Superblock::prealloc_blocks_dirs`) to a directory when creating a new one
-        const PREALLOCATE = 0x0001;
-        /// AFS server inodes exist
-        const AFS = 0x0002;
-        /// File system has a journal (Ext3)
-        const JOURNAL = 0x0004;
-        /// Inodes have extended attributes
-        const EXTENDED_INODE = 0x0008;
-        /// File system can resize itself for larger partitions
-        const SELF_RESIZE = 0x0010;
-        /// Directories use hash index
-        const HASH_INDEX = 0x0020;
-    }
-}
-
-bitflags! {
-    /// Required features. If these are not supported; can't mount
-    pub struct FeaturesRequired: u32 {
-        /// Compression is used
-        const REQ_COMPRESSION = 0x0001;
-        /// Directory entries contain a type field
-        const REQ_DIRECTORY_TYPE = 0x0002;
-        /// File system needs to replay its journal
-        const REQ_REPLAY_JOURNAL = 0x0004;
-        /// File system uses a journal device
-        const REQ_JOURNAL_DEVICE = 0x0008;
-    }
-}
-
-bitflags! {
-    /// ROnly features. If these are not supported; remount as read-only
-    pub struct FeaturesROnly: u32 {
-        /// Sparse superblocks and group descriptor tables
-        const RONLY_SPARSE = 0x0001;
-        /// File system uses a 64-bit file size
-        const RONLY_FILE_SIZE_64 = 0x0002;
-        /// Directory contents are stored in the form of a Binary Tree
-        const RONLY_BTREE_DIRECTORY = 0x0004;
-    }
-}
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-    use sector::Size512;
-
-    #[test]
-    fn find() {
-        let mut volume = vec![0_u8; 4096];
-        // magic
-        volume[1024 + 56] = EXT2_MAGIC as u8;
-        volume[1024 + 57] = (EXT2_MAGIC >> 8) as u8;
-        let superblock = unsafe { Superblock::find::<Size512, _>(&volume) };
-        assert!(
-            superblock.is_ok(),
-            "Err({:?})",
-            superblock.err().unwrap_or_else(|| unreachable!()),
-        );
-    }
-
-    #[test]
-    fn superblock() {
-        use std::cell::RefCell;
-        use std::fs::File;
-
-        let file = RefCell::new(File::open("ext2.img").unwrap());
-        let superblock = unsafe { Superblock::find::<Size512, _>(&file) };
-        assert!(
-            superblock.is_ok(),
-            "Err({:?})",
-            superblock.err().unwrap_or_else(|| unreachable!()),
-        );
-    }
-}
diff --git a/ext2-rs/src/volume/mod.rs b/ext2-rs/src/volume/mod.rs
deleted file mode 100644
index d3d23b6..0000000
--- a/ext2-rs/src/volume/mod.rs
+++ /dev/null
@@ -1,371 +0,0 @@
-#![allow(missing_docs)]
-use {
-    alloc::{
-        borrow::{Cow, ToOwned},
-        boxed::Box,
-        vec::Vec,
-    },
-    core::{
-        mem,
-        ops::{Deref, DerefMut, Range},
-        slice,
-    },
-    error::Error,
-    sector::{Address, SectorSize},
-};
-
-pub mod size;
-use self::size::Size;
-
-pub trait Volume<T: Clone, S: SectorSize> {
-    type Error: Into<Error>;
-
-    fn size(&self) -> Size<S>;
-    fn commit(
-        &mut self,
-        slice: Option<VolumeCommit<T, S>>,
-    ) -> Result<(), Self::Error>;
-    unsafe fn slice_unchecked<'a>(
-        &'a self,
-        range: Range<Address<S>>,
-    ) -> VolumeSlice<'a, T, S>;
-
-    fn slice<'a>(
-        &'a self,
-        range: Range<Address<S>>,
-    ) -> Result<VolumeSlice<'a, T, S>, Self::Error>;
-}
-
-#[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct VolumeSlice<'a, T: 'a + Clone, S: SectorSize> {
-    inner: Cow<'a, [T]>,
-    index: Address<S>,
-}
-
-impl<T: Clone, S: SectorSize> VolumeSlice<'static, T, S> {
-    pub fn with_static(inner: &'static [T]) -> VolumeSlice<'static, T, S> {
-        VolumeSlice {
-            inner: Cow::Borrowed(inner),
-            index: Address::new(0, 0),
-        }
-    }
-
-    pub fn new_owned(
-        inner: <[T] as ToOwned>::Owned,
-        index: Address<S>,
-    ) -> VolumeSlice<'static, T, S> {
-        VolumeSlice {
-            inner: Cow::Owned(inner),
-            index,
-        }
-    }
-}
-
-impl<'a, T: Clone, S: SectorSize> VolumeSlice<'a, T, S> {
-    pub fn new(inner: &'a [T], index: Address<S>) -> VolumeSlice<'a, T, S> {
-        VolumeSlice {
-            inner: Cow::Borrowed(inner),
-            index,
-        }
-    }
-
-    pub fn is_mutated(&self) -> bool {
-        match self.inner {
-            Cow::Borrowed(_) => false,
-            Cow::Owned(_) => true,
-        }
-    }
-
-    pub fn address(&self) -> Address<S> {
-        self.index
-    }
-}
-
-impl<'a, S: SectorSize> VolumeSlice<'a, u8, S> {
-    pub unsafe fn dynamic_cast<T: Copy>(&self) -> (T, Address<S>) {
-        assert!(self.inner.len() >= mem::size_of::<T>());
-        let index = self.index;
-        let cast = self.inner.as_ptr().cast::<T>().read_unaligned();
-
-        // mem::transmute_copy(self.inner.as_ptr().as_ref().unwrap());
-        (cast, index)
-    }
-
-    pub fn from_cast<T: Copy>(
-        cast: &'a T,
-        index: Address<S>,
-    ) -> VolumeSlice<'a, u8, S> {
-        let len = mem::size_of::<T>();
-        let ptr = cast as *const T as *const u8;
-        let slice = unsafe { slice::from_raw_parts(ptr, len) };
-        VolumeSlice::new(slice, index)
-    }
-}
-
-impl<'a, T: Clone, S: SectorSize> VolumeSlice<'a, T, S> {
-    pub fn commit(self) -> Option<VolumeCommit<T, S>> {
-        if self.is_mutated() {
-            Some(VolumeCommit::new(self.inner.into_owned(), self.index))
-        } else {
-            None
-        }
-    }
-}
-
-impl<'a, T: Clone, S: SectorSize> AsRef<[T]> for VolumeSlice<'a, T, S> {
-    fn as_ref(&self) -> &[T] {
-        self.inner.as_ref()
-    }
-}
-
-impl<'a, T: Clone, S: SectorSize> AsMut<[T]> for VolumeSlice<'a, T, S> {
-    fn as_mut(&mut self) -> &mut [T] {
-        self.inner.to_mut().as_mut()
-    }
-}
-
-impl<'a, T: Clone, S: SectorSize> Deref for VolumeSlice<'a, T, S> {
-    type Target = [T];
-
-    fn deref(&self) -> &Self::Target {
-        self.as_ref()
-    }
-}
-
-impl<'a, T: Clone, S: SectorSize> DerefMut for VolumeSlice<'a, T, S> {
-    fn deref_mut(&mut self) -> &mut Self::Target {
-        self.as_mut()
-    }
-}
-
-pub struct VolumeCommit<T, S: SectorSize> {
-    inner: Vec<T>,
-    index: Address<S>,
-}
-
-impl<T: Clone, S: SectorSize> VolumeCommit<T, S> {
-    pub fn with_vec(inner: Vec<T>) -> VolumeCommit<T, S> {
-        VolumeCommit {
-            inner,
-            index: Address::new(0, 0),
-        }
-    }
-}
-
-impl<T: Clone, S: SectorSize> VolumeCommit<T, S> {
-    pub fn new(inner: Vec<T>, index: Address<S>) -> VolumeCommit<T, S> {
-        VolumeCommit { inner, index }
-    }
-
-    pub fn into_inner(self) -> Vec<T> {
-        self.inner
-    }
-
-    pub fn address(&self) -> Address<S> {
-        self.index
-    }
-}
-
-impl<T: Clone, S: SectorSize> AsRef<[T]> for VolumeCommit<T, S> {
-    fn as_ref(&self) -> &[T] {
-        self.inner.as_ref()
-    }
-}
-
-impl<T: Clone, S: SectorSize> AsMut<[T]> for VolumeCommit<T, S> {
-    fn as_mut(&mut self) -> &mut [T] {
-        self.inner.as_mut()
-    }
-}
-
-impl<T: Clone, S: SectorSize> Deref for VolumeCommit<T, S> {
-    type Target = [T];
-
-    fn deref(&self) -> &Self::Target {
-        self.as_ref()
-    }
-}
-
-impl<T: Clone, S: SectorSize> DerefMut for VolumeCommit<T, S> {
-    fn deref_mut(&mut self) -> &mut Self::Target {
-        self.as_mut()
-    }
-}
-
-macro_rules! impl_slice {
-    (@inner $volume:ty $( , $lt:lifetime )* ) => {
-        impl<$( $lt, )* T: Clone, S: SectorSize> Volume<T, S>
-            for $volume
-        {
-            type Error = Error;
-
-            fn size(&self) -> Size<S> {
-                Size::Bounded(
-                    Address::from(<Self as AsRef<[T]>>::as_ref(self).len())
-                )
-            }
-
-            fn commit(
-                &mut self,
-                slice: Option<VolumeCommit<T, S>>,
-            ) -> Result<(), Self::Error> {
-                slice.map(|slice| {
-                    let index = slice.address().into_index() as usize;
-                    let end = index + slice.as_ref().len();
-                    // XXX: it would be much better to drop the contents of dst
-                    // and move the contents of slice instead of cloning
-                    let dst =
-                        &mut <Self as AsMut<[T]>>::as_mut(self)[index..end];
-                    dst.clone_from_slice(slice.as_ref());
-                });
-                Ok(())
-            }
-
-            unsafe fn slice_unchecked<'a>(
-                &'a self,
-                range: Range<Address<S>>,
-            ) -> VolumeSlice<'a, T, S> {
-                let index = range.start;
-                let range = range.start.into_index() as usize
-                    ..range.end.into_index() as usize;
-                VolumeSlice::new(
-                    <Self as AsRef<[T]>>::as_ref(self).get_unchecked(range),
-                    index,
-                )
-            }
-
-            fn slice<'a>(
-                &'a self,
-                range: Range<Address<S>>,
-            ) -> Result<VolumeSlice<'a, T, S>, Self::Error> {
-                if self.size() >= range.end {
-                    unsafe { Ok(self.slice_unchecked(range)) }
-                } else {
-                    Err(Error::AddressOutOfBounds {
-                        sector: range.end.sector(),
-                        offset: range.end.offset(),
-                        size: range.end.sector_size()
-                    })
-                }
-            }
-        }
-    };
-    ($volume:ty) => {
-        impl_slice!(@inner $volume);
-    };
-    ($volume:ty $( , $lt:lifetime )* ) => {
-        impl_slice!(@inner $volume $( , $lt )* );
-    };
-}
-
-impl_slice!(&'b mut [T], 'b);
-impl_slice!(Vec<T>);
-impl_slice!(Box<[T]>);
-
-#[cfg(any(test, not(feature = "no_std")))]
-mod file {
-    use std::cell::RefCell;
-    use std::fs::File;
-    use std::io::{self, Read, Seek, SeekFrom, Write};
-    use std::ops::Range;
-
-    use sector::{Address, SectorSize};
-
-    use super::size::Size;
-    use super::{Volume, VolumeCommit, VolumeSlice};
-
-    impl<S: SectorSize> Volume<u8, S> for RefCell<File> {
-        type Error = io::Error;
-
-        fn size(&self) -> Size<S> {
-            Size::Bounded(
-                self.borrow()
-                    .metadata()
-                    .map(|data| Address::from(data.len()))
-                    .unwrap_or(Address::new(0, 0)),
-            )
-        }
-
-        fn commit(
-            &mut self,
-            slice: Option<VolumeCommit<u8, S>>,
-        ) -> Result<(), Self::Error> {
-            slice
-                .map(|slice| {
-                    let index = slice.address();
-                    let mut refmut = self.borrow_mut();
-                    refmut
-                        .seek(SeekFrom::Start(index.into_index()))
-                        .and_then(|_| refmut.write(slice.as_ref()))
-                        .map(|_| ())
-                })
-                .unwrap_or(Ok(()))
-        }
-
-        unsafe fn slice_unchecked<'a>(
-            &'a self,
-            range: Range<Address<S>>,
-        ) -> VolumeSlice<'a, u8, S> {
-            let index = range.start;
-            let len = range.end - range.start;
-            let mut vec = Vec::with_capacity(len.into_index() as usize);
-            vec.set_len(len.into_index() as usize);
-            let mut refmut = self.borrow_mut();
-            refmut
-                .seek(SeekFrom::Start(index.into_index()))
-                .and_then(|_| refmut.read_exact(&mut vec[..]))
-                .unwrap_or_else(|err| {
-                    panic!("could't read from File Volume: {:?}", err)
-                });
-            VolumeSlice::new_owned(vec, index)
-        }
-
-        fn slice<'a>(
-            &'a self,
-            range: Range<Address<S>>,
-        ) -> Result<VolumeSlice<'a, u8, S>, Self::Error> {
-            let index = range.start;
-            let mut vec = Vec::with_capacity(
-                (range.end - range.start).into_index() as usize,
-            );
-            unsafe {
-                vec.set_len((range.end - range.start).into_index() as usize);
-            }
-            let mut refmut = self.borrow_mut();
-            refmut
-                .seek(SeekFrom::Start(index.into_index()))
-                .and_then(|_| refmut.read_exact(&mut vec[..]))
-                .map(move |_| VolumeSlice::new_owned(vec, index))
-        }
-    }
-}
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-    use sector::{Address, Size512};
-
-    #[test]
-    fn volume() {
-        let mut volume = vec![0; 1024];
-        let commit = {
-            let mut slice = volume
-                .slice(
-                    Address::<Size512>::from(256_u64)
-                        ..Address::<Size512>::from(512_u64),
-                )
-                .unwrap();
-            slice.iter_mut().for_each(|x| *x = 1);
-            slice.commit()
-        };
-        assert!(volume.commit(commit).is_ok());
-
-        for (i, &x) in volume.iter().enumerate() {
-            if i < 256 || i >= 512 {
-                assert_eq!(x, 0);
-            } else {
-                assert_eq!(x, 1);
-            }
-        }
-    }
-}
diff --git a/ext2-rs/src/volume/size.rs b/ext2-rs/src/volume/size.rs
deleted file mode 100644
index b8b5b26..0000000
--- a/ext2-rs/src/volume/size.rs
+++ /dev/null
@@ -1,115 +0,0 @@
-//!
-
-use {
-    core::{
-        cmp::Ordering,
-        fmt::{self, Display},
-    },
-    sector::{Address, SectorSize},
-};
-
-#[derive(Clone, Copy, Debug, Hash)]
-/// A size
-pub enum Size<S: SectorSize> {
-    /// An unbounded size
-    Unbounded,
-    /// A bounded size
-    Bounded(Address<S>),
-}
-
-impl<S: SectorSize> Size<S> {
-    /// Try to get the length of the sector
-    pub fn try_len(&self) -> Option<Address<S>> {
-        match *self {
-            Size::Unbounded => None,
-            Size::Bounded(n) => Some(n),
-        }
-    }
-    /// Get the length of the sector unsafely
-    ///
-    /// # Safety
-    ///
-    /// This function is unsafe because it does not check that the size is
-    /// bounded.
-    pub unsafe fn len(&self) -> Address<S> {
-        match *self {
-            Size::Unbounded => panic!(
-                "attempt to convert `Size::Unbounded` to a concrete length"
-            ),
-            Size::Bounded(n) => n,
-        }
-    }
-}
-
-impl<S: SectorSize> Size<S> {
-    /// Check if the size is unbounded
-    pub fn is_bounded(&self) -> bool {
-        match *self {
-            Size::Unbounded => false,
-            Size::Bounded(_) => true,
-        }
-    }
-}
-
-impl<S: SectorSize> Display for Size<S> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        match *self {
-            Size::Unbounded => write!(f, "Unbounded"),
-            Size::Bounded(n) => write!(f, "Bounded({})", n),
-        }
-    }
-}
-
-impl<S: SectorSize> PartialEq for Size<S> {
-    fn eq(&self, rhs: &Self) -> bool {
-        match (self, rhs) {
-            (&Size::Unbounded, _) => false,
-            (_, &Size::Unbounded) => false,
-            (&Size::Bounded(ref a), &Size::Bounded(ref b)) => a.eq(b),
-        }
-    }
-
-    fn ne(&self, rhs: &Self) -> bool {
-        match (self, rhs) {
-            (&Size::Unbounded, _) => false,
-            (_, &Size::Unbounded) => false,
-            (&Size::Bounded(ref a), &Size::Bounded(ref b)) => a.ne(b),
-        }
-    }
-}
-
-impl<S: SectorSize> PartialEq<Address<S>> for Size<S> {
-    fn eq(&self, rhs: &Address<S>) -> bool {
-        match *self {
-            Size::Unbounded => false,
-            Size::Bounded(ref n) => n.eq(rhs),
-        }
-    }
-
-    fn ne(&self, rhs: &Address<S>) -> bool {
-        match *self {
-            Size::Unbounded => false,
-            Size::Bounded(ref n) => n.eq(rhs),
-        }
-    }
-}
-
-impl<S: SectorSize> PartialOrd for Size<S> {
-    fn partial_cmp(&self, rhs: &Self) -> Option<Ordering> {
-        match (self, rhs) {
-            (&Size::Unbounded, &Size::Unbounded) => None,
-            (&Size::Unbounded, _) => Some(Ordering::Greater),
-            (_, &Size::Unbounded) => Some(Ordering::Less),
-            (&Size::Bounded(ref a), &Size::Bounded(ref b)) => a.partial_cmp(b),
-        }
-    }
-}
-
-impl<S: SectorSize> PartialOrd<Address<S>> for Size<S> {
-    fn partial_cmp(&self, rhs: &Address<S>) -> Option<Ordering> {
-        match *self {
-            Size::Unbounded => Some(Ordering::Greater),
-            Size::Bounded(ref n) => n.partial_cmp(rhs),
-        }
-    }
-}