Newer
Older
use resource::{Resource, DirResource, FileResource};
use std::str;
use std::sync::atomic::{AtomicUsize, Ordering};
use syscall::error::{Error, Result, EACCES, EEXIST, EISDIR, ENOTDIR, EPERM, ENOENT, EBADF};
use syscall::flag::{O_CREAT, O_TRUNC, O_ACCMODE, O_RDONLY, O_WRONLY, O_RDWR, MODE_PERM};
fs: RefCell<FileSystem>,
next_id: AtomicUsize,
files: Mutex<BTreeMap<usize, Box<Resource>>>
pub fn new(name: &'static str, fs: FileSystem) -> FileScheme {
fs: RefCell::new(fs),
next_id: AtomicUsize::new(1),
files: Mutex::new(BTreeMap::new())
impl Scheme for FileScheme {
fn open(&self, url: &[u8], flags: usize, uid: u32, gid: u32) -> Result<usize> {
let path = str::from_utf8(url).unwrap_or("").trim_matches('/');
for node in nodes.iter() {
if ! node.1.permission(uid, gid, Node::MODE_EXEC) {
// println!("dir not executable {:o}", node.1.mode);
return Err(Error::new(EACCES));
}
if ! node.1.is_dir() {
return Err(Error::new(ENOTDIR));
}
let resource: Box<Resource> = match node_result {
if flags & O_ACCMODE != O_RDONLY {
// println!("dir not opened with O_RDONLY");
return Err(Error::new(EACCES));
}
if ! node.1.permission(uid, gid, Node::MODE_READ) {
// println!("dir not readable {:o}", node.1.mode);
return Err(Error::new(EACCES));
}
let mut data = Vec::new();
for child in children.iter() {
if let Ok(name) = child.1.name() {
if ! data.is_empty() {
data.push(b'\n');
}
data.extend_from_slice(&name.as_bytes());
}
}
Box::new(DirResource::new(path.to_string(), node.0, data))
if (flags & O_ACCMODE == O_RDONLY || flags & O_ACCMODE == O_RDWR) && ! node.1.permission(uid, gid, Node::MODE_READ) {
// println!("file not readable {:o}", node.1.mode);
return Err(Error::new(EACCES));
}
if (flags & O_ACCMODE == O_WRONLY || flags & O_ACCMODE == O_RDWR) && ! node.1.permission(uid, gid, Node::MODE_WRITE) {
// println!("file not writable {:o}", node.1.mode);
return Err(Error::new(EACCES));
}
if ! node.1.permission(uid, gid, Node::MODE_WRITE) {
// println!("file not writable {:o}", node.1.mode);
return Err(Error::new(EACCES));
}
Box::new(FileResource::new(path.to_string(), node.0, flags))
},
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() {
if ! parent.1.permission(uid, gid, Node::MODE_WRITE) {
// println!("dir not writable {:o}", parent.1.mode);
return Err(Error::new(EACCES));
}
let mut node = try!(fs.create_node(Node::MODE_FILE | (flags as u16 & Node::MODE_PERM), &last_part, parent.0));
node.1.uid = uid;
node.1.gid = gid;
try!(fs.write_at(node.0, &node.1));
if (flags & O_ACCMODE == O_RDONLY || flags & O_ACCMODE == O_RDWR) && ! node.1.permission(uid, gid, Node::MODE_READ) {
// println!("file not readable {:o}", node.1.mode);
return Err(Error::new(EACCES));
}
if (flags & O_ACCMODE == O_WRONLY || flags & O_ACCMODE == O_RDWR) && ! node.1.permission(uid, gid, Node::MODE_WRITE) {
// println!("file not writable {:o}", node.1.mode);
return Err(Error::new(EACCES));
}
Box::new(FileResource::new(path.to_string(), node.0, flags))
} else {
return Err(Error::new(EPERM));
}
} else {
return Err(Error::new(EPERM));
}
} else {
return Err(err);
}
let id = self.next_id.fetch_add(1, Ordering::SeqCst);
self.files.lock().insert(id, resource);
fn mkdir(&self, url: &[u8], mode: u16, uid: u32, gid: u32) -> Result<usize> {
let path = str::from_utf8(url).unwrap_or("").trim_matches('/');
let node_result = fs.path_nodes(path, &mut nodes);
for node in nodes.iter() {
if ! node.1.permission(uid, gid, Node::MODE_EXEC) {
// println!("dir not executable {:o}", node.1.mode);
return Err(Error::new(EACCES));
}
if ! node.1.is_dir() {
return Err(Error::new(ENOTDIR));
}
Ok(_node) => Err(Error::new(EEXIST)),
Err(err) => if err.errno == ENOENT {
let mut last_part = String::new();
for part in path.split('/') {
if ! part.is_empty() {
last_part = part.to_owned();
}
}
if ! last_part.is_empty() {
if let Some(parent) = nodes.last() {
if ! parent.1.permission(uid, gid, Node::MODE_WRITE) {
// println!("dir not writable {:o}", parent.1.mode);
return Err(Error::new(EACCES));
}
let mut node = try!(fs.create_node(Node::MODE_DIR | (mode & Node::MODE_PERM), &last_part, parent.0));
node.1.uid = uid;
node.1.gid = gid;
try!(fs.write_at(node.0, &node.1));
Ok(0)
} else {
Err(Error::new(EPERM))
}
} else {
Err(Error::new(EPERM))
}
} else {
Err(err)
}
}
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
fn chmod(&self, url: &[u8], mode: u16, uid: u32, gid: u32) -> Result<usize> {
let path = str::from_utf8(url).unwrap_or("").trim_matches('/');
// println!("Chmod '{}'", path);
let mut fs = self.fs.borrow_mut();
let mut nodes = Vec::new();
let node_result = fs.path_nodes(path, &mut nodes);
for node in nodes.iter() {
if ! node.1.permission(uid, gid, Node::MODE_EXEC) {
// println!("dir not executable {:o}", node.1.mode);
return Err(Error::new(EACCES));
}
if ! node.1.is_dir() {
return Err(Error::new(ENOTDIR));
}
}
let mut node = node_result?;
if node.1.uid == uid || uid == 0 {
node.1.mode = (node.1.mode & ! MODE_PERM) | (mode & MODE_PERM);
try!(fs.write_at(node.0, &node.1));
Ok(0)
} else {
Err(Error::new(EPERM))
}
}
fn rmdir(&self, url: &[u8], uid: u32, gid: u32) -> Result<usize> {
let path = str::from_utf8(url).unwrap_or("").trim_matches('/');
for node in nodes.iter() {
if ! node.1.permission(uid, gid, Node::MODE_EXEC) {
// println!("dir not executable {:o}", node.1.mode);
return Err(Error::new(EACCES));
}
if ! node.1.is_dir() {
return Err(Error::new(ENOTDIR));
}
if let Some(parent) = nodes.last() {
if ! parent.1.permission(uid, gid, Node::MODE_WRITE) {
// println!("dir not writable {:o}", parent.1.mode);
return Err(Error::new(EACCES));
}
if ! child.1.permission(uid, gid, Node::MODE_WRITE) {
// println!("dir not writable {:o}", parent.1.mode);
return Err(Error::new(EACCES));
}
if let Ok(child_name) = child.1.name() {
fs.remove_node(Node::MODE_DIR, child_name, parent.0).and(Ok(0))
} else {
Err(Error::new(ENOENT))
}
} else {
Err(Error::new(ENOTDIR))
}
} else {
Err(Error::new(EPERM))
}
fn unlink(&self, url: &[u8], uid: u32, gid: u32) -> Result<usize> {
let path = str::from_utf8(url).unwrap_or("").trim_matches('/');
for node in nodes.iter() {
if ! node.1.permission(uid, gid, Node::MODE_EXEC) {
// println!("dir not executable {:o}", node.1.mode);
return Err(Error::new(EACCES));
}
if ! node.1.is_dir() {
return Err(Error::new(ENOTDIR));
}
if let Some(parent) = nodes.last() {
if ! parent.1.permission(uid, gid, Node::MODE_WRITE) {
// println!("dir not writable {:o}", parent.1.mode);
return Err(Error::new(EACCES));
}
if ! child.1.permission(uid, gid, Node::MODE_WRITE) {
// println!("file not writable {:o}", parent.1.mode);
return Err(Error::new(EACCES));
}
if let Ok(child_name) = child.1.name() {
fs.remove_node(Node::MODE_FILE, child_name, parent.0).and(Ok(0))
} else {
Err(Error::new(ENOENT))
}
} else {
Err(Error::new(EISDIR))
}
} else {
Err(Error::new(EPERM))
}
fn dup(&self, old_id: usize, buf: &[u8]) -> Result<usize> {
let resource = if let Some(old_resource) = files.get(&old_id) {
let id = self.next_id.fetch_add(1, Ordering::SeqCst);
files.insert(id, resource);
fn read(&self, id: usize, buf: &mut [u8]) -> Result<usize> {
// println!("Read {}, {:X} {}", id, buf.as_ptr() as usize, buf.len());
let mut files = self.files.lock();
if let Some(mut file) = files.get_mut(&id) {
file.read(buf, &mut self.fs.borrow_mut())
fn write(&self, id: usize, buf: &[u8]) -> Result<usize> {
// println!("Write {}, {:X} {}", id, buf.as_ptr() as usize, buf.len());
let mut files = self.files.lock();
if let Some(mut file) = files.get_mut(&id) {
file.write(buf, &mut self.fs.borrow_mut())
fn seek(&self, id: usize, pos: usize, whence: usize) -> Result<usize> {
let mut files = self.files.lock();
if let Some(mut file) = files.get_mut(&id) {
file.seek(pos, whence, &mut self.fs.borrow_mut())
fn fcntl(&self, id: usize, cmd: usize, arg: usize) -> Result<usize> {
let mut files = self.files.lock();
if let Some(mut file) = files.get_mut(&id) {
file.fcntl(cmd, arg)
} else {
Err(Error::new(EBADF))
}
}
fn fpath(&self, id: usize, buf: &mut [u8]) -> Result<usize> {
// println!("Fpath {}, {:X} {}", id, buf.as_ptr() as usize, buf.len());
let files = self.files.lock();
if let Some(file) = files.get(&id) {
let mut i = 0;
while i < buf.len() && i < name.len() {
buf[i] = name[i];
i += 1;
}
if i < buf.len() {
buf[i] = b':';
i += 1;
}
file.path(&mut buf[i..]).map(|count| i + count)
} 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);
let files = self.files.lock();
if let Some(file) = files.get(&id) {
file.stat(stat, &mut self.fs.borrow_mut())
let mut files = self.files.lock();
if let Some(mut file) = files.get_mut(&id) {
file.sync()
} else {
Err(Error::new(EBADF))
}
}
fn ftruncate(&self, id: usize, len: usize) -> Result<usize> {
let mut files = self.files.lock();
if let Some(mut file) = files.get_mut(&id) {
file.truncate(len, &mut self.fs.borrow_mut())
let mut files = self.files.lock();
if files.remove(&id).is_some() {
Ok(0)
} else {
Err(Error::new(EBADF))
}
}
}