use bitflags::bitflags;
use std::io::{self, prelude::*};
#[derive(Debug)]
pub enum HostErrno {
EPERM = 1,
ENOENT = 2,
EINTR = 4,
EBADF = 9,
EACCES = 13,
EFAULT = 14,
EBUSY = 16,
EEXIST = 17,
ENODEV = 19,
ENOTDIR = 20,
EISDIR = 21,
EINVAL = 22,
ENFILE = 23,
EMFILE = 24,
EFBIG = 27,
ENOSPC = 28,
ESPIPE = 29,
EROFS = 30,
ENAMETOOLONG = 91,
EUNKNOWN = 9999,
}
pub type IOResult<T> = Result<Result<T, HostErrno>, ()>;
bitflags! {
pub struct HostMode: u32 {
const S_IFREG = 0o100000;
const S_IFDIR = 0o40000;
const S_IRUSR = 0o400;
const S_IWUSR = 0o200;
const S_IXUSR = 0o100;
const S_IRGRP = 0o40;
const S_IWGRP = 0o20;
const S_IXGRP = 0o10;
const S_IROTH = 0o4;
const S_IWOTH = 0o2;
const S_IXOTH = 0o1;
}
}
bitflags! {
pub struct HostOpenFlags: u32 {
const O_RDONLY = 0x0;
const O_WRONLY = 0x1;
const O_RDWR = 0x2;
const O_APPEND = 0x8;
const O_CREAT = 0x200;
const O_TRUNC = 0x400;
const O_EXCL = 0x800;
}
}
#[derive(Debug)]
pub struct HostStat {
pub st_dev: u32,
pub st_ino: u32,
pub st_mode: HostMode,
pub st_nlink: u32,
pub st_uid: u32,
pub st_gid: u32,
pub st_rdev: u32,
pub st_size: u64,
pub st_blksize: u64,
pub st_blocks: u64,
pub st_atime: u32,
pub st_mtime: u32,
pub st_ctime: u32,
}
pub fn write_stat<W>(writer: &mut W, stat: HostStat) -> io::Result<()>
where
W: Write,
{
use byteorder::{BigEndian, WriteBytesExt};
writer.write_u32::<BigEndian>(stat.st_dev)?;
writer.write_u32::<BigEndian>(stat.st_ino)?;
writer.write_u32::<BigEndian>(stat.st_mode.bits())?;
writer.write_u32::<BigEndian>(stat.st_nlink)?;
writer.write_u32::<BigEndian>(stat.st_uid)?;
writer.write_u32::<BigEndian>(stat.st_gid)?;
writer.write_u32::<BigEndian>(stat.st_rdev)?;
writer.write_u64::<BigEndian>(stat.st_size)?;
writer.write_u64::<BigEndian>(stat.st_blksize)?;
writer.write_u64::<BigEndian>(stat.st_blocks)?;
writer.write_u32::<BigEndian>(stat.st_atime)?;
writer.write_u32::<BigEndian>(stat.st_mtime)?;
writer.write_u32::<BigEndian>(stat.st_ctime)
}
#[allow(dead_code)]
pub fn read_stat(v: &[u8]) -> io::Result<HostStat> {
use byteorder::{BigEndian, ReadBytesExt};
use std::io::Cursor;
let mut r = Cursor::new(v);
let st_dev = r.read_u32::<BigEndian>()?;
let st_ino = r.read_u32::<BigEndian>()?;
let st_mode = HostMode::from_bits_truncate(r.read_u32::<BigEndian>()?);
let st_nlink = r.read_u32::<BigEndian>()?;
let st_uid = r.read_u32::<BigEndian>()?;
let st_gid = r.read_u32::<BigEndian>()?;
let st_rdev = r.read_u32::<BigEndian>()?;
let st_size = r.read_u64::<BigEndian>()?;
let st_blksize = r.read_u64::<BigEndian>()?;
let st_blocks = r.read_u64::<BigEndian>()?;
let st_atime = r.read_u32::<BigEndian>()?;
let st_mtime = r.read_u32::<BigEndian>()?;
let st_ctime = r.read_u32::<BigEndian>()?;
Ok(HostStat {
st_dev,
st_ino,
st_mode,
st_nlink,
st_uid,
st_gid,
st_rdev,
st_size,
st_blksize,
st_blocks,
st_atime,
st_mtime,
st_ctime,
})
}
pub trait FileSystem {
fn host_open(&self, _filename: Vec<u8>, _flags: HostOpenFlags, _mode: HostMode) -> IOResult<u64> {
Err(())
}
fn host_close(&self, _fd: u64) -> IOResult<()> {
Err(())
}
fn host_pread(&self, _fd: u64, _count: u64, _offset: u64) -> IOResult<Vec<u8>> {
Err(())
}
fn host_pwrite(&self, _fd: u64, _offset: u64, _data: Vec<u8>) -> IOResult<u64> {
Err(())
}
fn host_fstat(&self, _fd: u64) -> IOResult<HostStat> {
Err(())
}
fn host_unlink(&self, _filename: Vec<u8>) -> IOResult<()> {
Err(())
}
fn host_readlink(&self, _filename: Vec<u8>) -> IOResult<Vec<u8>> {
Err(())
}
fn host_setfs(&self, _pid: u64) -> IOResult<()> {
Err(())
}
}
#[test]
fn stat_size() {
use std::mem;
assert_eq!(mem::size_of::<HostStat>(), 4 * 10 + 8 * 3);
}