Skip to content
Snippets Groups Projects
main.rs 7.19 KiB
Newer Older
Jeremy Soller's avatar
Jeremy Soller committed
extern crate redoxfs;

extern crate system;

use std::cmp::{min, max};
use std::collections::BTreeMap;
use std::env;
use std::fs::File;
use std::io::{Read, Write};
use std::mem::size_of;

use image::Image;

Jeremy Soller's avatar
Jeremy Soller committed
use redoxfs::{FileSystem, Node};
Jeremy Soller's avatar
Jeremy Soller committed

use system::error::{Error, Result, ENOENT, EBADF, EINVAL};
use system::scheme::{Packet, Scheme};
use system::syscall::{Stat, SEEK_SET, SEEK_CUR, SEEK_END};

pub mod image;

struct FileResource {
    path: String,
    data: Vec<u8>,
    seek: usize,
}

impl FileResource {
Jeremy Soller's avatar
Jeremy Soller committed
    fn new(path: &str, data: Vec<u8>) -> FileResource {
Jeremy Soller's avatar
Jeremy Soller committed
        FileResource {
            path: path.to_string(),
Jeremy Soller's avatar
Jeremy Soller committed
            data: data,
Jeremy Soller's avatar
Jeremy Soller committed
            seek: 0,
        }
    }

    fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
        let mut i = 0;
        while i < buf.len() && self.seek < self.data.len() {
            buf[i] = self.data[self.seek];
            i += 1;
            self.seek += 1;
        }
        Ok(i)
    }

    fn write(&mut self, buf: &[u8]) -> Result<usize> {
        let mut i = 0;
        while i < buf.len() && self.seek < self.data.len() {
            self.data[self.seek] = buf[i];
            i += 1;
            self.seek += 1;
        }
        Ok(i)
    }

    fn seek(&mut self, offset: usize, whence: usize) -> Result<usize> {
        match whence {
            SEEK_SET => {
                self.seek = min(0, max(self.data.len() as isize, offset as isize)) as usize;
                Ok(self.seek)
            },
            SEEK_CUR => {
                self.seek = min(0, max(self.data.len() as isize, self.seek as isize + offset as isize)) as usize;
                Ok(self.seek)
            },
            SEEK_END => {
                self.seek = min(0, max(self.data.len() as isize, self.data.len() as isize + offset as isize)) as usize;
                Ok(self.seek)
            },
            _ => Err(Error::new(EINVAL))
        }
    }

    fn path(&self, buf: &mut [u8]) -> Result<usize> {
        let mut i = 0;
        let path = self.path.as_bytes();
        while i < buf.len() && i < path.len() {
            buf[i] = path[i];
            i += 1;
        }
        Ok(i)
    }

    fn stat(&self, _stat: &mut Stat) -> Result<usize> {
        Ok(0)
    }

    fn sync(&mut self) -> Result<usize> {
        Ok(0)
    }
}

struct FileScheme {
    fs: FileSystem,
    next_id: isize,
    files: BTreeMap<usize, FileResource>
}

impl FileScheme {
    fn new(fs: FileSystem) -> FileScheme {
        FileScheme {
            fs: fs,
            next_id: 1,
            files: BTreeMap::new()
        }
    }
Jeremy Soller's avatar
Jeremy Soller committed

    fn path_node(&mut self, path: &str) -> Result<(u64, Node)> {
        let mut block = self.fs.header.1.root;
        for part in path.split('/') {
            if ! part.is_empty() {
                let next = try!(self.fs.find_node(part, block));
                block = next.0;
            }
        }

        self.fs.node(block)
    }
Jeremy Soller's avatar
Jeremy Soller committed
}

impl Scheme for FileScheme {
Jeremy Soller's avatar
Jeremy Soller committed
    fn open(&mut self, url: &str, flags: usize, mode: usize) -> Result<usize> {
        let path = url.split(':').nth(1).unwrap_or("").trim_matches('/');
        let node = try!(self.path_node(path));

        let mut data = Vec::new();
        if node.1.is_dir() {
            let mut children = Vec::new();
            try!(self.fs.child_nodes(&mut children, node.0));
            for child in children.iter() {
                if let Ok(name) = child.1.name() {
                    if ! data.is_empty() {
                        data.push('\n' as u8);
                    }
                    data.extend_from_slice(&name.as_bytes());
                }
            }
        } else {
            data.extend_from_slice(&format!("{:#?}", node).as_bytes());
        }

Jeremy Soller's avatar
Jeremy Soller committed
        let id = self.next_id as usize;
        self.next_id += 1;
        if self.next_id < 0 {
            self.next_id = 1;
        }
Jeremy Soller's avatar
Jeremy Soller committed
        self.files.insert(id, FileResource::new(url, data));
Jeremy Soller's avatar
Jeremy Soller committed
        Ok(id)
    }

    #[allow(unused_variables)]
    fn unlink(&mut self, path: &str) -> Result<usize> {
        println!("unlink {}", path);
        Err(Error::new(ENOENT))
    }

    #[allow(unused_variables)]
    fn mkdir(&mut self, path: &str, mode: usize) -> Result<usize> {
        println!("mkdir {}, {:X}", path, mode);
        Err(Error::new(ENOENT))
    }

    /* Resource operations */
    #[allow(unused_variables)]
    fn read(&mut self, id: usize, buf: &mut [u8]) -> Result<usize> {
        if let Some(mut file) = self.files.get_mut(&id) {
            file.read(buf)
        } else {
            Err(Error::new(EBADF))
        }
    }

    #[allow(unused_variables)]
    fn write(&mut self, id: usize, buf: &[u8]) -> Result<usize> {
        if let Some(mut file) = self.files.get_mut(&id) {
            file.write(buf)
        } else {
            Err(Error::new(EBADF))
        }
    }

    #[allow(unused_variables)]
    fn seek(&mut self, id: usize, pos: usize, whence: usize) -> Result<usize> {
        if let Some(mut file) = self.files.get_mut(&id) {
            file.seek(pos, whence)
        } else {
            Err(Error::new(EBADF))
        }
    }

    #[allow(unused_variables)]
    fn fpath(&self, id: usize, buf: &mut [u8]) -> Result<usize> {
        if let Some(file) = self.files.get(&id) {
            file.path(buf)
        } else {
            Err(Error::new(EBADF))
        }
    }

    #[allow(unused_variables)]
    fn fstat(&self, id: usize, stat: &mut Stat) -> Result<usize> {
        println!("fstat {}, {:X}", id, stat as *mut Stat as usize);
        if let Some(file) = self.files.get(&id) {
            file.stat(stat)
        } else {
            Err(Error::new(EBADF))
        }
    }

    #[allow(unused_variables)]
    fn fsync(&mut self, id: usize) -> Result<usize> {
        println!("fsync {}", id);
        if let Some(mut file) = self.files.get_mut(&id) {
            file.sync()
        } else {
            Err(Error::new(EBADF))
        }
    }

    #[allow(unused_variables)]
    fn ftruncate(&mut self, id: usize, len: usize) -> Result<usize> {
        println!("ftruncate {}, {}", id, len);
        Err(Error::new(EBADF))
    }

    fn close(&mut self, id: usize) -> Result<usize> {
        if self.files.remove(&id).is_some() {
            Ok(0)
        } else {
            Err(Error::new(EBADF))
        }
    }
}

fn scheme(fs: FileSystem) {
   //In order to handle example:, we create :example
   let mut scheme = FileScheme::new(fs);
   let mut socket = File::create(":redoxfs").unwrap();
   loop {
       let mut packet = Packet::default();
       while socket.read(&mut packet).unwrap() == size_of::<Packet>() {
           scheme.handle(&mut packet);
           socket.write(&packet).unwrap();
       }
   }
}

fn main() {
    let mut args = env::args();
    if let Some(path) = args.nth(1) {
        //Open an existing image
        match Image::open(&path) {
            Ok(disk) => match FileSystem::open(Box::new(disk)) {
                Ok(filesystem) => {
                    println!("redoxfs: opened filesystem {}", path);
                    scheme(filesystem);
                },
                Err(err) => println!("redoxfs: failed to open filesystem {}: {}", path, err)
            },
            Err(err) => println!("redoxfs: failed to open image {}: {}", path, err)
        }
    } else {
        println!("redoxfs: no disk image provided");
    }
}