implement a lot fs syscalls without test

This commit is contained in:
WangRunji 2019-03-06 17:15:26 +08:00 committed by Tate Tian
parent 3b38c3b75a
commit 7c855d7f5f
5 changed files with 484 additions and 3 deletions

@ -9,6 +9,11 @@ pub trait File: Debug + Sync + Send {
fn readv<'a, 'b>(&self, bufs: &'a mut [&'b mut [u8]]) -> Result<usize, Error>;
fn writev<'a, 'b>(&self, bufs: &'a [&'b [u8]]) -> Result<usize, Error>;
fn seek(&self, pos: SeekFrom) -> Result<off_t, Error>;
fn metadata(&self) -> Result<Metadata, Error>;
fn set_len(&self, len: u64) -> Result<(), Error>;
fn sync_all(&self) -> Result<(), Error>;
fn sync_data(&self) -> Result<(), Error>;
fn read_entry(&self) -> Result<String, Error>;
}
pub type FileRef = Arc<Box<File>>;
@ -72,6 +77,26 @@ impl File for SgxFile {
let inner = inner_guard.borrow_mut();
inner.seek(pos)
}
fn metadata(&self) -> Result<Metadata, Error> {
unimplemented!()
}
fn set_len(&self, len: u64) -> Result<(), Error> {
unimplemented!()
}
fn sync_all(&self) -> Result<(), Error> {
unimplemented!()
}
fn sync_data(&self) -> Result<(), Error> {
unimplemented!()
}
fn read_entry(&self) -> Result<String, Error> {
unimplemented!()
}
}
#[derive(Clone)]
@ -307,6 +332,26 @@ impl File for StdoutFile {
fn seek(&self, seek_pos: SeekFrom) -> Result<off_t, Error> {
Err(Error::new(Errno::ESPIPE, "Stdout does not support seek"))
}
fn metadata(&self) -> Result<Metadata, Error> {
unimplemented!()
}
fn set_len(&self, len: u64) -> Result<(), Error> {
unimplemented!()
}
fn sync_all(&self) -> Result<(), Error> {
unimplemented!()
}
fn sync_data(&self) -> Result<(), Error> {
unimplemented!()
}
fn read_entry(&self) -> Result<String, Error> {
unimplemented!()
}
}
impl Debug for StdoutFile {
@ -376,6 +421,26 @@ impl File for StdinFile {
fn writev<'a, 'b>(&self, bufs: &'a [&'b [u8]]) -> Result<usize, Error> {
Err(Error::new(Errno::EBADF, "Stdin does not support write"))
}
fn metadata(&self) -> Result<Metadata, Error> {
unimplemented!()
}
fn set_len(&self, len: u64) -> Result<(), Error> {
unimplemented!()
}
fn sync_all(&self) -> Result<(), Error> {
unimplemented!()
}
fn sync_data(&self) -> Result<(), Error> {
unimplemented!()
}
fn read_entry(&self) -> Result<String, Error> {
unimplemented!()
}
}
impl Debug for StdinFile {

@ -70,6 +70,40 @@ impl File for INodeFile {
};
Ok(*offset as i64)
}
fn metadata(&self) -> Result<Metadata, Error> {
let metadata = self.inode.metadata()?;
Ok(metadata)
}
fn set_len(&self, len: u64) -> Result<(), Error> {
if !self.options.write {
return Err(Error::new(EBADF, "File not writable. Can't set len."));
}
self.inode.resize(len as usize)?;
Ok(())
}
fn sync_all(&self) -> Result<(), Error> {
self.inode.sync()?;
Ok(())
}
fn sync_data(&self) -> Result<(), Error> {
// TODO: add sync_data to VFS
self.inode.sync()?;
Ok(())
}
fn read_entry(&self) -> Result<String, Error> {
if !self.options.read {
return Err(Error::new(EBADF, "File not readable. Can't read entry."));
}
let mut offset = self.offset.lock().unwrap();
let name = self.inode.get_entry(*offset)?;
*offset += 1;
Ok(name)
}
}
impl INodeFile {

@ -12,8 +12,9 @@ pub use self::file::{File, FileRef, SgxFile, StdinFile, StdoutFile};
pub use self::file_table::{FileDesc, FileTable};
pub use self::pipe::Pipe;
pub use self::inode_file::{INodeFile, ROOT_INODE};
use rcore_fs::vfs::{FsError, FileType, INode};
use rcore_fs::vfs::{FsError, FileType, INode, Metadata, Timespec};
use self::inode_file::OpenOptions;
use process::Process;
// TODO: use the type defined in Rust libc.
//
@ -87,6 +88,31 @@ pub fn do_readv<'a, 'b>(fd: FileDesc, bufs: &'a mut [&'b mut [u8]]) -> Result<us
file_ref.readv(bufs)
}
pub fn do_stat(path: &str) -> Result<Stat, Error> {
warn!("stat is partial implemented as lstat");
do_lstat(path)
}
pub fn do_fstat(fd: u32) -> Result<Stat, Error> {
info!("fstat: fd: {}", fd);
let current_ref = process::get_current();
let current_process = current_ref.lock().unwrap();
let file_ref = current_process.get_files().get(fd)?;
let stat = Stat::from(file_ref.metadata()?);
// TODO: handle symlink
Ok(stat)
}
pub fn do_lstat(path: &str) -> Result<Stat, Error> {
info!("lstat: path: {}", path);
let current_ref = process::get_current();
let current_process = current_ref.lock().unwrap();
let inode = current_process.lookup_inode(&path)?;
let stat = Stat::from(inode.metadata()?);
Ok(stat)
}
pub fn do_lseek<'a, 'b>(fd: FileDesc, offset: SeekFrom) -> Result<off_t, Error> {
let current_ref = process::get_current();
let current_process = current_ref.lock().unwrap();
@ -94,6 +120,63 @@ pub fn do_lseek<'a, 'b>(fd: FileDesc, offset: SeekFrom) -> Result<off_t, Error>
file_ref.seek(offset)
}
pub fn do_fsync(fd: FileDesc) -> Result<(), Error> {
info!("fsync: fd: {}", fd);
let current_ref = process::get_current();
let current_process = current_ref.lock().unwrap();
let file_ref = current_process.get_files().get(fd)?;
file_ref.sync_all()?;
Ok(())
}
pub fn do_fdatasync(fd: FileDesc) -> Result<(), Error> {
info!("fdatasync: fd: {}", fd);
let current_ref = process::get_current();
let current_process = current_ref.lock().unwrap();
let file_ref = current_process.get_files().get(fd)?;
file_ref.sync_data()?;
Ok(())
}
pub fn do_truncate(path: &str, len: usize) -> Result<(), Error> {
info!("truncate: path: {:?}, len: {}", path, len);
let current_ref = process::get_current();
let current_process = current_ref.lock().unwrap();
current_process.lookup_inode(&path)?.resize(len)?;
Ok(())
}
pub fn do_ftruncate(fd: FileDesc, len: usize) -> Result<(), Error> {
info!("ftruncate: fd: {}, len: {}", fd, len);
let current_ref = process::get_current();
let current_process = current_ref.lock().unwrap();
let file_ref = current_process.get_files().get(fd)?;
file_ref.set_len(len as u64)?;
Ok(())
}
pub fn do_getdents64(fd: FileDesc, buf: &mut [u8]) -> Result<usize, Error> {
info!("getdents64: fd: {}, buf: {:?}, buf_size: {}", fd, buf.as_ptr(), buf.len());
let current_ref = process::get_current();
let current_process = current_ref.lock().unwrap();
let file_ref = current_process.get_files().get(fd)?;
let info = file_ref.metadata()?;
if info.type_ != FileType::Dir {
return Err(Error::new(ENOTDIR, ""));
}
let mut writer = unsafe { DirentBufWriter::new(buf) };
loop {
let name = match file_ref.read_entry() {
Err(e) if e.errno == ENOENT => break,
r => r,
}?;
// TODO: get ino from dirent
let ok = writer.try_write(0, 0, &name);
if !ok { break; }
}
Ok(writer.written_size)
}
pub fn do_close(fd: FileDesc) -> Result<(), Error> {
let current_ref = process::get_current();
let mut current_process = current_ref.lock().unwrap();
@ -160,6 +243,14 @@ extern "C" {
fn ocall_sync() -> sgx_status_t;
}
impl Process {
fn lookup_inode(&self, path: &str) -> Result<Arc<INode>, Error> {
let cwd = self.get_exec_path().split_at(1).1; // skip start '/'
let inode = ROOT_INODE.lookup(cwd)?.lookup(path)?;
Ok(inode)
}
}
/// Split a `path` str to `(base_path, file_name)`
fn split_path(path: &str) -> (&str, &str) {
let mut split = path.trim_end_matches('/').rsplitn(2, '/');
@ -206,3 +297,190 @@ impl OpenFlags {
}
}
}
#[derive(Debug)]
#[repr(packed)] // Don't use 'C'. Or its size will align up to 8 bytes.
pub struct LinuxDirent64 {
/// Inode number
ino: u64,
/// Offset to next structure
offset: u64,
/// Size of this dirent
reclen: u16,
/// File type
type_: u8,
/// Filename (null-terminated)
name: [u8; 0],
}
struct DirentBufWriter<'a> {
buf: &'a mut [u8],
rest_size: usize,
written_size: usize,
}
impl<'a> DirentBufWriter<'a> {
unsafe fn new(buf: &'a mut [u8]) -> Self {
let rest_size = buf.len();
DirentBufWriter {
buf,
rest_size,
written_size: 0,
}
}
fn try_write(&mut self, inode: u64, type_: u8, name: &str) -> bool {
let len = ::core::mem::size_of::<LinuxDirent64>() + name.len() + 1;
let len = (len + 7) / 8 * 8; // align up
if self.rest_size < len {
return false;
}
let dent = LinuxDirent64 {
ino: inode,
offset: 0,
reclen: len as u16,
type_,
name: [],
};
unsafe {
let ptr = self.buf.as_mut_ptr().add(self.written_size) as *mut LinuxDirent64;
ptr.write(dent);
let name_ptr = ptr.add(1) as _;
write_cstr(name_ptr, name);
}
self.rest_size -= len;
self.written_size += len;
true
}
}
#[repr(C)]
pub struct Stat {
/// ID of device containing file
dev: u64,
/// inode number
ino: u64,
/// number of hard links
nlink: u64,
/// file type and mode
mode: StatMode,
/// user ID of owner
uid: u32,
/// group ID of owner
gid: u32,
/// padding
_pad0: u32,
/// device ID (if special file)
rdev: u64,
/// total size, in bytes
size: u64,
/// blocksize for filesystem I/O
blksize: u64,
/// number of 512B blocks allocated
blocks: u64,
/// last access time
atime: Timespec,
/// last modification time
mtime: Timespec,
/// last status change time
ctime: Timespec,
}
bitflags! {
pub struct StatMode: u32 {
const NULL = 0;
/// Type
const TYPE_MASK = 0o170000;
/// FIFO
const FIFO = 0o010000;
/// character device
const CHAR = 0o020000;
/// directory
const DIR = 0o040000;
/// block device
const BLOCK = 0o060000;
/// ordinary regular file
const FILE = 0o100000;
/// symbolic link
const LINK = 0o120000;
/// socket
const SOCKET = 0o140000;
/// Set-user-ID on execution.
const SET_UID = 0o4000;
/// Set-group-ID on execution.
const SET_GID = 0o2000;
/// Read, write, execute/search by owner.
const OWNER_MASK = 0o700;
/// Read permission, owner.
const OWNER_READ = 0o400;
/// Write permission, owner.
const OWNER_WRITE = 0o200;
/// Execute/search permission, owner.
const OWNER_EXEC = 0o100;
/// Read, write, execute/search by group.
const GROUP_MASK = 0o70;
/// Read permission, group.
const GROUP_READ = 0o40;
/// Write permission, group.
const GROUP_WRITE = 0o20;
/// Execute/search permission, group.
const GROUP_EXEC = 0o10;
/// Read, write, execute/search by others.
const OTHER_MASK = 0o7;
/// Read permission, others.
const OTHER_READ = 0o4;
/// Write permission, others.
const OTHER_WRITE = 0o2;
/// Execute/search permission, others.
const OTHER_EXEC = 0o1;
}
}
impl StatMode {
fn from_type_mode(type_: FileType, mode: u16) -> Self {
let type_ = match type_ {
FileType::File => StatMode::FILE,
FileType::Dir => StatMode::DIR,
FileType::SymLink => StatMode::LINK,
FileType::CharDevice => StatMode::CHAR,
FileType::BlockDevice => StatMode::BLOCK,
FileType::Socket => StatMode::SOCKET,
FileType::NamedPipe => StatMode::FIFO,
_ => StatMode::NULL,
};
let mode = StatMode::from_bits_truncate(mode as u32);
type_ | mode
}
}
impl From<Metadata> for Stat {
fn from(info: Metadata) -> Self {
Stat {
dev: info.dev as u64,
ino: info.inode as u64,
mode: StatMode::from_type_mode(info.type_, info.mode as u16),
nlink: info.nlinks as u64,
uid: info.uid as u32,
gid: info.gid as u32,
rdev: 0,
size: info.size as u64,
blksize: info.blk_size as u64,
blocks: info.blocks as u64,
atime: info.atime,
mtime: info.mtime,
ctime: info.ctime,
_pad0: 0
}
}
}
/// Write a Rust string to C string
pub unsafe fn write_cstr(ptr: *mut u8, s: &str) {
ptr.copy_from(s.as_ptr(), s.len());
ptr.add(s.len()).write(0);
}

@ -77,6 +77,26 @@ impl File for PipeReader {
fn seek(&self, pos: SeekFrom) -> Result<off_t, Error> {
Err(Error::new(Errno::ESPIPE, "Pipe does not support seek"))
}
fn metadata(&self) -> Result<Metadata, Error> {
unimplemented!()
}
fn set_len(&self, len: u64) -> Result<(), Error> {
unimplemented!()
}
fn sync_all(&self) -> Result<(), Error> {
unimplemented!()
}
fn sync_data(&self) -> Result<(), Error> {
unimplemented!()
}
fn read_entry(&self) -> Result<String, Error> {
unimplemented!()
}
}
unsafe impl Send for PipeReader {}
@ -128,6 +148,26 @@ impl File for PipeWriter {
fn seek(&self, seek_pos: SeekFrom) -> Result<off_t, Error> {
Err(Error::new(Errno::ESPIPE, "Pipe does not support seek"))
}
fn metadata(&self) -> Result<Metadata, Error> {
unimplemented!()
}
fn set_len(&self, len: u64) -> Result<(), Error> {
unimplemented!()
}
fn sync_all(&self) -> Result<(), Error> {
unimplemented!()
}
fn sync_data(&self) -> Result<(), Error> {
unimplemented!()
}
fn read_entry(&self) -> Result<String, Error> {
unimplemented!()
}
}
unsafe impl Send for PipeWriter {}

@ -34,7 +34,15 @@ pub extern "C" fn dispatch_syscall(
SYS_write => do_write(arg0 as FileDesc, arg1 as *const u8, arg2 as usize),
SYS_readv => do_readv(arg0 as FileDesc, arg1 as *mut iovec_t, arg2 as i32),
SYS_writev => do_writev(arg0 as FileDesc, arg1 as *mut iovec_t, arg2 as i32),
SYS_stat => do_stat(arg0 as *const i8, arg1 as *mut fs::Stat),
SYS_fstat => do_fstat(arg0 as FileDesc, arg1 as *mut fs::Stat),
SYS_lstat => do_lstat(arg0 as *const i8, arg1 as *mut fs::Stat),
SYS_lseek => do_lseek(arg0 as FileDesc, arg1 as off_t, arg2 as i32),
SYS_fsync => do_fsync(arg0 as FileDesc),
SYS_fdatasync => do_fdatasync(arg0 as FileDesc),
SYS_truncate => do_truncate(arg0 as *const i8, arg1 as usize),
SYS_ftruncate => do_ftruncate(arg0 as FileDesc, arg1 as usize),
SYS_getdents64 => do_getdents64(arg0 as FileDesc, arg1 as *mut u8, arg2 as usize),
SYS_sync => do_sync(),
SYS_getcwd => do_getcwd(arg0 as *mut u8, arg1 as usize),
@ -159,8 +167,8 @@ fn do_spawn(
Ok(0)
}
fn do_open(path_buf: *const i8, flags: u32, mode: u32) -> Result<isize, Error> {
let path = unsafe { CStr::from_ptr(path_buf).to_string_lossy().into_owned() };
fn do_open(path: *const i8, flags: u32, mode: u32) -> Result<isize, Error> {
let path = clone_cstring_safely(path)?.to_string_lossy().into_owned();
let fd = fs::do_open(&path, flags, mode)?;
Ok(fd as isize)
}
@ -238,6 +246,32 @@ fn do_readv(fd: FileDesc, iov: *mut iovec_t, count: i32) -> Result<isize, Error>
Ok(len as isize)
}
fn do_stat(path: *const i8, stat_buf: *mut fs::Stat) -> Result<isize, Error> {
let path = clone_cstring_safely(path)?.to_string_lossy().into_owned();
check_mut_ptr(stat_buf)?;
let stat = fs::do_stat(&path)?;
unsafe { stat_buf.write(stat); }
Ok(0)
}
fn do_fstat(fd: FileDesc, stat_buf: *mut fs::Stat) -> Result<isize, Error> {
check_mut_ptr(stat_buf)?;
let stat = fs::do_fstat(fd)?;
unsafe { stat_buf.write(stat); }
Ok(0)
}
fn do_lstat(path: *const i8, stat_buf: *mut fs::Stat) -> Result<isize, Error> {
let path = clone_cstring_safely(path)?.to_string_lossy().into_owned();
check_mut_ptr(stat_buf)?;
let stat = fs::do_lstat(&path)?;
unsafe { stat_buf.write(stat); }
Ok(0)
}
fn do_lseek(fd: FileDesc, offset: off_t, whence: i32) -> Result<isize, Error> {
let seek_from = match whence {
0 => {
@ -264,6 +298,36 @@ fn do_lseek(fd: FileDesc, offset: off_t, whence: i32) -> Result<isize, Error> {
Ok(offset as isize)
}
fn do_fsync(fd: FileDesc) -> Result<isize, Error> {
fs::do_fsync(fd)?;
Ok(0)
}
fn do_fdatasync(fd: FileDesc) -> Result<isize, Error> {
fs::do_fdatasync(fd)?;
Ok(0)
}
fn do_truncate(path: *const i8, len: usize) -> Result<isize, Error> {
let path = clone_cstring_safely(path)?.to_string_lossy().into_owned();
fs::do_truncate(&path, len)?;
Ok(0)
}
fn do_ftruncate(fd: FileDesc, len: usize) -> Result<isize, Error> {
fs::do_ftruncate(fd, len)?;
Ok(0)
}
fn do_getdents64(fd: FileDesc, buf: *mut u8, buf_size: usize) -> Result<isize, Error> {
let safe_buf = {
check_mut_array(buf, buf_size)?;
unsafe { std::slice::from_raw_parts_mut(buf, buf_size) }
};
let len = fs::do_getdents64(fd, safe_buf)?;
Ok(len as isize)
}
fn do_sync() -> Result<isize, Error> {
fs::do_sync()?;
Ok(0)