Skip to content
Snippets Groups Projects
scheme.rs 5.35 KiB
Newer Older
Jeremy Soller's avatar
Jeremy Soller committed
use resource::FileResource;

use redoxfs::{FileSystem, Node};

use std::collections::BTreeMap;

use system::error::{Error, Result, EEXIST, EISDIR, ENOTDIR, EPERM, ENOENT, EBADF};
use system::scheme::Scheme;
use system::syscall::{Stat, O_CREAT};

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

impl FileScheme {
    pub fn new(fs: FileSystem) -> FileScheme {
        FileScheme {
            fs: fs,
            next_id: 1,
            files: BTreeMap::new()
        }
    }
}

impl Scheme for FileScheme {
    fn open(&mut self, url: &str, flags: usize, _mode: usize) -> Result<usize> {
        let path = url.split(':').nth(1).unwrap_or("").trim_matches('/');

        let mut nodes = Vec::new();
        let node_result = self.path_nodes(path, &mut nodes);

        let mut data = Vec::new();
        match node_result {
            Ok(node) => 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());
                        if child.1.is_dir() {
                            data.push(b'/');
                        }
                    }
                }
            } else {
                for i in 0..(try!(self.fs.node_len(node.0)) + 511)/512 {
Jeremy Soller's avatar
Jeremy Soller committed
                    let mut sector = [0; 512];
                    try!(self.fs.read_node(node.0, i as u64 * 512, &mut sector));
Jeremy Soller's avatar
Jeremy Soller committed
                    data.extend_from_slice(&sector);
                }
            },
            Err(err) => if err.errno == ENOENT && flags & O_CREAT == O_CREAT {
                let mut last_part = String::new();
                for part in path.split('/') {
                    if ! part.is_empty() {
                        last_part = part.to_string();
                    }
                }
                if ! last_part.is_empty() {
                    if let Some(parent) = nodes.last() {
                        try!(self.fs.create_node(Node::MODE_FILE, &last_part, parent.0));
                    } else {
                        return Err(Error::new(EPERM));
                    }
                } else {
                    return Err(Error::new(EPERM));
                }
            } else {
                return Err(err);
            }
        }
        /*
        if let Some(arg) = args.next() {
            match  {
                Ok(node) => println!("{}: {:#?}", node.0, node.1),
                Err(err) => println!("mk: failed to create {}: {}", arg, err)
            }
        } else {
            println!("mk <file>");
        }
        */

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

    fn mkdir(&mut self, url: &str, _mode: usize) -> Result<usize> {
        let path = url.split(':').nth(1).unwrap_or("").trim_matches('/');
        self.fs.mkdir(path)
Jeremy Soller's avatar
Jeremy Soller committed
    }

    fn rmdir(&mut self, url: &str) -> Result<usize> {
        let path = url.split(':').nth(1).unwrap_or("").trim_matches('/');
        self.fs.rmdir(path)
Jeremy Soller's avatar
Jeremy Soller committed
    }

    fn unlink(&mut self, url: &str) -> Result<usize> {
        let path = url.split(':').nth(1).unwrap_or("").trim_matches('/');
        self.fs.unlink(path)
Jeremy Soller's avatar
Jeremy Soller committed
    }

    /* 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))
        }
    }

    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))
        }
    }

    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))
        }
    }

    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))
        }
    }

    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))
        }
    }

    fn fsync(&mut self, id: usize) -> Result<usize> {
        if let Some(mut file) = self.files.get_mut(&id) {
            file.sync()
        } else {
            Err(Error::new(EBADF))
        }
    }

    fn ftruncate(&mut self, id: usize, len: usize) -> Result<usize> {
        if let Some(mut file) = self.files.get_mut(&id) {
            file.truncate(len)
        } else {
            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))
        }
    }
}