Commit 49925a39 authored by Jeremy Soller's avatar Jeremy Soller

Error type, subdir argument

parent bc2d90f5
......@@ -13,4 +13,4 @@ path = "src/lib.rs"
[[bin]]
name = "redoxfs-utility"
path = "src/utility.rs"
path = "utility/main.rs"
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>;
}
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() {
......
use std::{mem, slice};
use std::ops::{Deref, DerefMut};
use core::{mem, slice};
use core::ops::{Deref, DerefMut};
use super::Extent;
......
#![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;
......
use std::{mem, slice};
use std::ops::{Deref, DerefMut};
use core::{mem, slice};
use core::ops::{Deref, DerefMut};
use super::Extent;
......
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
}
}
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);
}
}
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");
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment