Skip to content
Snippets Groups Projects
Commit 49925a39 authored by Jeremy Soller's avatar Jeremy Soller
Browse files

Error type, subdir argument

parent bc2d90f5
No related branches found
No related tags found
No related merge requests found
......@@ -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");
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment