redox/kernel/syscall/fs.rs

342 lines
11 KiB
Rust
Raw Normal View History

2016-08-14 23:58:35 +02:00
//! Filesystem syscalls
2016-10-07 02:46:24 +02:00
use core::sync::atomic::Ordering;
2016-08-14 23:58:35 +02:00
2016-08-18 16:30:45 +02:00
use context;
use scheme::{self, FileHandle};
2016-11-01 21:49:51 +01:00
use syscall;
use syscall::data::{Packet, Stat};
use syscall::error::*;
2016-11-01 21:49:51 +01:00
use syscall::flag::{MODE_DIR, MODE_FILE};
2016-08-14 23:58:35 +02:00
pub fn file_op(a: usize, fd: FileHandle, c: usize, d: usize) -> Result<usize> {
2016-10-05 23:43:35 +02:00
let (file, pid, uid, gid) = {
2016-09-25 19:20:59 +02:00
let contexts = context::contexts();
let context_lock = contexts.current().ok_or(Error::new(ESRCH))?;
let context = context_lock.read();
let file = context.get_file(fd).ok_or(Error::new(EBADF))?;
(file, context.id, context.euid, context.egid)
2016-09-25 19:20:59 +02:00
};
let scheme = {
let schemes = scheme::schemes();
let scheme = schemes.get(file.scheme).ok_or(Error::new(EBADF))?;
scheme.clone()
};
let mut packet = Packet {
id: 0,
pid: pid.into(),
2016-10-05 23:43:35 +02:00
uid: uid,
gid: gid,
2016-09-25 19:20:59 +02:00
a: a,
b: file.number,
c: c,
d: d
};
scheme.handle(&mut packet);
Error::demux(packet.a)
}
pub fn file_op_slice(a: usize, fd: FileHandle, slice: &[u8]) -> Result<usize> {
2016-09-25 19:20:59 +02:00
file_op(a, fd, slice.as_ptr() as usize, slice.len())
}
pub fn file_op_mut_slice(a: usize, fd: FileHandle, slice: &mut [u8]) -> Result<usize> {
2016-09-25 19:20:59 +02:00
file_op(a, fd, slice.as_mut_ptr() as usize, slice.len())
}
/// Change the current working directory
pub fn chdir(path: &[u8]) -> Result<usize> {
2016-11-01 21:49:51 +01:00
let fd = open(path, 0)?;
let mut stat = Stat::default();
let stat_res = file_op_mut_slice(syscall::number::SYS_FSTAT, fd, &mut stat);
let _ = close(fd);
stat_res?;
if stat.st_mode & (MODE_FILE | MODE_DIR) == MODE_DIR {
let contexts = context::contexts();
let context_lock = contexts.current().ok_or(Error::new(ESRCH))?;
let context = context_lock.read();
let canonical = context.canonicalize(path);
*context.cwd.lock() = canonical;
Ok(0)
} else {
Err(Error::new(ENOTDIR))
}
}
/// Get the current working directory
pub fn getcwd(buf: &mut [u8]) -> Result<usize> {
let contexts = context::contexts();
let context_lock = contexts.current().ok_or(Error::new(ESRCH))?;
let context = context_lock.read();
let cwd = context.cwd.lock();
let mut i = 0;
while i < buf.len() && i < cwd.len() {
buf[i] = cwd[i];
i += 1;
}
Ok(i)
}
2016-08-14 23:58:35 +02:00
/// Open syscall
pub fn open(path: &[u8], flags: usize) -> Result<FileHandle> {
let (path_canon, uid, gid, scheme_ns) = {
2016-09-18 20:54:10 +02:00
let contexts = context::contexts();
let context_lock = contexts.current().ok_or(Error::new(ESRCH))?;
2016-09-18 20:54:10 +02:00
let context = context_lock.read();
(context.canonicalize(path), context.euid, context.egid, context.scheme_ns)
2016-09-18 20:54:10 +02:00
};
let mut parts = path_canon.splitn(2, |&b| b == b':');
let scheme_name_opt = parts.next();
2016-08-16 19:04:14 +02:00
let reference_opt = parts.next();
let (scheme_id, file_id) = {
let scheme_name = scheme_name_opt.ok_or(Error::new(ENODEV))?;
let (scheme_id, scheme) = {
let schemes = scheme::schemes();
let (scheme_id, scheme) = schemes.get_name(scheme_ns, scheme_name).ok_or(Error::new(ENODEV))?;
(scheme_id, scheme.clone())
};
2016-10-06 02:01:05 +02:00
let file_id = scheme.open(reference_opt.unwrap_or(b""), flags, uid, gid)?;
(scheme_id, file_id)
2016-09-09 03:31:26 +02:00
};
let contexts = context::contexts();
let context_lock = contexts.current().ok_or(Error::new(ESRCH))?;
2016-09-18 20:54:10 +02:00
let context = context_lock.read();
2016-09-09 03:31:26 +02:00
context.add_file(::context::file::File {
scheme: scheme_id,
number: file_id,
event: None,
}).ok_or(Error::new(EMFILE))
2016-08-14 23:58:35 +02:00
}
2016-10-07 02:46:24 +02:00
pub fn pipe2(fds: &mut [usize], flags: usize) -> Result<usize> {
if fds.len() >= 2 {
let scheme_id = ::scheme::pipe::PIPE_SCHEME_ID.load(Ordering::SeqCst);
let (read_id, write_id) = ::scheme::pipe::pipe(flags);
let contexts = context::contexts();
let context_lock = contexts.current().ok_or(Error::new(ESRCH))?;
let context = context_lock.read();
let read_fd = context.add_file(::context::file::File {
scheme: scheme_id,
number: read_id,
event: None,
2016-10-07 02:46:24 +02:00
}).ok_or(Error::new(EMFILE))?;
let write_fd = context.add_file(::context::file::File {
scheme: scheme_id,
number: write_id,
event: None,
2016-10-07 02:46:24 +02:00
}).ok_or(Error::new(EMFILE))?;
fds[0] = read_fd.into();
fds[1] = write_fd.into();
2016-10-07 02:46:24 +02:00
Ok(0)
} else {
Err(Error::new(EFAULT))
}
}
2016-09-28 19:26:49 +02:00
/// mkdir syscall
2016-10-06 02:01:05 +02:00
pub fn mkdir(path: &[u8], mode: u16) -> Result<usize> {
let (path_canon, uid, gid, scheme_ns) = {
2016-09-28 19:26:49 +02:00
let contexts = context::contexts();
let context_lock = contexts.current().ok_or(Error::new(ESRCH))?;
let context = context_lock.read();
(context.canonicalize(path), context.euid, context.egid, context.scheme_ns)
2016-09-28 19:26:49 +02:00
};
let mut parts = path_canon.splitn(2, |&b| b == b':');
let scheme_name_opt = parts.next();
2016-09-28 19:26:49 +02:00
let reference_opt = parts.next();
let scheme_name = scheme_name_opt.ok_or(Error::new(ENODEV))?;
2016-09-28 19:26:49 +02:00
let scheme = {
let schemes = scheme::schemes();
let (_scheme_id, scheme) = schemes.get_name(scheme_ns, scheme_name).ok_or(Error::new(ENODEV))?;
2016-09-28 19:26:49 +02:00
scheme.clone()
};
2016-10-06 02:01:05 +02:00
scheme.mkdir(reference_opt.unwrap_or(b""), mode, uid, gid)
2016-11-16 01:08:14 +01:00
}
/// chmod syscall
pub fn chmod(path: &[u8], mode: u16) -> Result<usize> {
let (path_canon, uid, gid, scheme_ns) = {
2016-11-16 01:08:14 +01:00
let contexts = context::contexts();
let context_lock = contexts.current().ok_or(Error::new(ESRCH))?;
let context = context_lock.read();
(context.canonicalize(path), context.euid, context.egid, context.scheme_ns)
2016-11-16 01:08:14 +01:00
};
let mut parts = path_canon.splitn(2, |&b| b == b':');
let scheme_name_opt = parts.next();
2016-11-16 01:08:14 +01:00
let reference_opt = parts.next();
let scheme_name = scheme_name_opt.ok_or(Error::new(ENODEV))?;
2016-11-16 01:08:14 +01:00
let scheme = {
let schemes = scheme::schemes();
let (_scheme_id, scheme) = schemes.get_name(scheme_ns, scheme_name).ok_or(Error::new(ENODEV))?;
2016-11-16 01:08:14 +01:00
scheme.clone()
};
scheme.chmod(reference_opt.unwrap_or(b""), mode, uid, gid)
2016-09-28 19:26:49 +02:00
}
/// rmdir syscall
pub fn rmdir(path: &[u8]) -> Result<usize> {
let (path_canon, uid, gid, scheme_ns) = {
2016-09-28 19:26:49 +02:00
let contexts = context::contexts();
let context_lock = contexts.current().ok_or(Error::new(ESRCH))?;
let context = context_lock.read();
(context.canonicalize(path), context.euid, context.egid, context.scheme_ns)
2016-09-28 19:26:49 +02:00
};
let mut parts = path_canon.splitn(2, |&b| b == b':');
let scheme_name_opt = parts.next();
2016-09-28 19:26:49 +02:00
let reference_opt = parts.next();
let scheme_name = scheme_name_opt.ok_or(Error::new(ENODEV))?;
2016-09-28 19:26:49 +02:00
let scheme = {
let schemes = scheme::schemes();
let (_scheme_id, scheme) = schemes.get_name(scheme_ns, scheme_name).ok_or(Error::new(ENODEV))?;
2016-09-28 19:26:49 +02:00
scheme.clone()
};
2016-10-06 02:01:05 +02:00
scheme.rmdir(reference_opt.unwrap_or(b""), uid, gid)
2016-09-28 19:26:49 +02:00
}
2016-09-28 19:18:28 +02:00
/// Unlink syscall
pub fn unlink(path: &[u8]) -> Result<usize> {
let (path_canon, uid, gid, scheme_ns) = {
2016-09-28 19:18:28 +02:00
let contexts = context::contexts();
let context_lock = contexts.current().ok_or(Error::new(ESRCH))?;
let context = context_lock.read();
(context.canonicalize(path), context.euid, context.egid, context.scheme_ns)
2016-09-28 19:18:28 +02:00
};
let mut parts = path_canon.splitn(2, |&b| b == b':');
let scheme_name_opt = parts.next();
2016-09-28 19:18:28 +02:00
let reference_opt = parts.next();
let scheme_name = scheme_name_opt.ok_or(Error::new(ENODEV))?;
2016-09-28 19:18:28 +02:00
let scheme = {
let schemes = scheme::schemes();
let (_scheme_id, scheme) = schemes.get_name(scheme_ns, scheme_name).ok_or(Error::new(ENODEV))?;
2016-09-28 19:18:28 +02:00
scheme.clone()
};
2016-10-06 02:01:05 +02:00
scheme.unlink(reference_opt.unwrap_or(b""), uid, gid)
2016-09-28 19:18:28 +02:00
}
2016-08-14 23:58:35 +02:00
/// Close syscall
pub fn close(fd: FileHandle) -> Result<usize> {
let file = {
let contexts = context::contexts();
let context_lock = contexts.current().ok_or(Error::new(ESRCH))?;
2016-09-18 20:54:10 +02:00
let context = context_lock.read();
let file = context.remove_file(fd).ok_or(Error::new(EBADF))?;
file
};
if let Some(event_id) = file.event {
context::event::unregister(fd, file.scheme, event_id);
}
let scheme = {
let schemes = scheme::schemes();
let scheme = schemes.get(file.scheme).ok_or(Error::new(EBADF))?;
scheme.clone()
};
scheme.close(file.number)
2016-08-14 23:58:35 +02:00
}
2016-09-12 01:31:21 +02:00
/// Duplicate file descriptor
pub fn dup(fd: FileHandle, buf: &[u8]) -> Result<FileHandle> {
2016-09-12 01:31:21 +02:00
let file = {
let contexts = context::contexts();
let context_lock = contexts.current().ok_or(Error::new(ESRCH))?;
2016-09-12 01:31:21 +02:00
let context = context_lock.read();
let file = context.get_file(fd).ok_or(Error::new(EBADF))?;
2016-09-12 01:31:21 +02:00
file
};
2016-09-28 19:22:01 +02:00
let new_id = {
let scheme = {
let schemes = scheme::schemes();
let scheme = schemes.get(file.scheme).ok_or(Error::new(EBADF))?;
scheme.clone()
};
scheme.dup(file.number, buf)?
};
2016-09-28 19:22:01 +02:00
let contexts = context::contexts();
let context_lock = contexts.current().ok_or(Error::new(ESRCH))?;
let context = context_lock.read();
context.add_file(::context::file::File {
scheme: file.scheme,
number: new_id,
event: None,
2016-09-28 19:22:01 +02:00
}).ok_or(Error::new(EMFILE))
2016-09-12 01:31:21 +02:00
}
2016-09-23 23:47:53 +02:00
/// Register events for file
pub fn fevent(fd: FileHandle, flags: usize) -> Result<usize> {
2016-09-23 23:47:53 +02:00
let file = {
let contexts = context::contexts();
let context_lock = contexts.current().ok_or(Error::new(ESRCH))?;
let context = context_lock.read();
let mut files = context.files.lock();
let mut file = files.get_mut(fd.into()).ok_or(Error::new(EBADF))?.ok_or(Error::new(EBADF))?;
if let Some(event_id) = file.event.take() {
println!("{:?}: {:?}:{}: events already registered: {}", fd, file.scheme, file.number, event_id);
context::event::unregister(fd, file.scheme, event_id);
}
file.clone()
2016-09-23 23:47:53 +02:00
};
let scheme = {
let schemes = scheme::schemes();
let scheme = schemes.get(file.scheme).ok_or(Error::new(EBADF))?;
scheme.clone()
};
let event_id = scheme.fevent(file.number, flags)?;
{
let contexts = context::contexts();
let context_lock = contexts.current().ok_or(Error::new(ESRCH))?;
let context = context_lock.read();
let mut files = context.files.lock();
let mut file = files.get_mut(fd.into()).ok_or(Error::new(EBADF))?.ok_or(Error::new(EBADF))?;
file.event = Some(event_id);
}
context::event::register(fd, file.scheme, event_id);
Ok(0)
2016-09-23 23:47:53 +02:00
}
pub fn funmap(virtual_address: usize) -> Result<usize> {
if virtual_address == 0 {
Ok(0)
} else {
let contexts = context::contexts();
let context_lock = contexts.current().ok_or(Error::new(ESRCH))?;
let context = context_lock.read();
let mut grants = context.grants.lock();
for i in 0 .. grants.len() {
let start = grants[i].start_address().get();
let end = start + grants[i].size();
if virtual_address >= start && virtual_address < end {
grants.remove(i).unmap();
return Ok(0);
}
}
Err(Error::new(EFAULT))
}
}