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"); + } +}