use super::{Handle, Inode};
use btlib::{
bterr, crypto::ConcretePub, BlockMetaSecrets, DirEntry, DirEntryKind, Epoch, IssuedProcRec,
};
use bttp::CallMsg;
use core::time::Duration;
use paste::paste;
use serde::{Deserialize, Serialize};
use std::{
fmt::Display,
io,
ops::{BitOr, BitOrAssign},
};
#[derive(Serialize, Deserialize)]
pub enum FsMsg<'a> {
#[serde(borrow)]
Lookup(Lookup<'a>),
#[serde(borrow)]
Create(Create<'a>),
Open(Open),
Read(Read),
#[serde(borrow)]
Write(Write<&'a [u8]>),
Flush(Flush),
ReadDir(ReadDir),
#[serde(borrow)]
Link(Link<'a>),
#[serde(borrow)]
Unlink(Unlink<'a>),
ReadMeta(ReadMeta),
WriteMeta(WriteMeta),
Allocate(Allocate),
Close(Close),
Forget(Forget),
Lock(Lock),
Unlock(Unlock),
AddReadcap(AddReadcap),
GrantAccess(GrantAccess),
}
#[derive(Serialize, Deserialize)]
pub enum FsReply<'a> {
Ack(()),
Lookup(LookupReply),
Create(CreateReply),
Open(OpenReply),
#[serde(borrow)]
Read(ReadReply<'a>),
Write(WriteReply),
ReadDir(ReadDirReply),
Link(LinkReply),
ReadMeta(ReadMetaReply),
WriteMeta(WriteMetaReply),
}
impl<'a> CallMsg<'a> for FsMsg<'a> {
type Reply<'b> = FsReply<'b>;
}
#[repr(u64)]
pub enum SpecInodes {
RootDir = 1,
Sb = 2,
FirstFree = 11,
}
impl SpecInodes {
pub fn value(self) -> Inode {
self as Inode
}
}
impl From<SpecInodes> for Inode {
fn from(special: SpecInodes) -> Self {
special.value()
}
}
#[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize, Deserialize)]
#[repr(u32)] pub enum FileType {
Dir = libc::S_IFDIR,
Reg = libc::S_IFREG,
}
impl FileType {
pub fn value(self) -> libc::mode_t {
self as libc::mode_t
}
pub fn from_value(value: libc::mode_t) -> btlib::Result<Self> {
if (value & libc::S_IFDIR) != 0 {
return Ok(FileType::Dir);
}
if (value & libc::S_IFREG) != 0 {
return Ok(FileType::Reg);
}
Err(bterr!("unknown file type: 0o{value:0o}"))
}
pub fn dir_entry_kind(self) -> DirEntryKind {
match self {
Self::Dir => DirEntryKind::Directory,
Self::Reg => DirEntryKind::File,
}
}
}
impl From<FileType> for libc::mode_t {
fn from(file_type: FileType) -> Self {
file_type.value()
}
}
impl TryFrom<libc::mode_t> for FileType {
type Error = btlib::Error;
fn try_from(value: libc::mode_t) -> btlib::Result<Self> {
Self::from_value(value)
}
}
impl From<FileType> for DirEntryKind {
fn from(value: FileType) -> Self {
value.dir_entry_kind()
}
}
impl BitOr<libc::mode_t> for FileType {
type Output = libc::mode_t;
fn bitor(self, rhs: libc::mode_t) -> Self::Output {
self.value() | rhs
}
}
#[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize, Deserialize)]
#[repr(i32)]
pub enum FlagValue {
ReadOnly = libc::O_RDONLY,
WriteOnly = libc::O_WRONLY,
ReadWrite = libc::O_RDWR,
AccMode = libc::O_ACCMODE,
Create = libc::O_CREAT,
Exclusive = libc::O_EXCL,
NoCtty = libc::O_NOCTTY,
Truncate = libc::O_TRUNC,
Append = libc::O_APPEND,
NonBlock = libc::O_NONBLOCK,
Dsync = libc::O_DSYNC,
Async = libc::O_ASYNC,
Direct = libc::O_DIRECT,
Directory = libc::O_DIRECTORY,
NoFollow = libc::O_NOFOLLOW,
NoAtime = libc::O_NOATIME,
CloseExec = libc::O_CLOEXEC,
Rsync = libc::O_RSYNC,
Path = libc::O_PATH,
TmpFile = libc::O_TMPFILE,
Process = 0x01000000,
Server = 0x02000000,
}
impl FlagValue {
pub const fn value(self) -> i32 {
self as i32
}
}
impl Copy for FlagValue {}
impl From<FlagValue> for i32 {
fn from(flag_value: FlagValue) -> Self {
flag_value.value()
}
}
impl BitOr for FlagValue {
type Output = Flags;
fn bitor(self, rhs: Self) -> Self::Output {
Flags::new(self.value() | rhs.value())
}
}
#[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize, Deserialize)]
pub struct Flags(i32);
impl Copy for Flags {}
impl Flags {
pub const fn new(value: i32) -> Self {
Self(value)
}
pub const fn value(self) -> i32 {
self.0
}
pub const fn writeable(self) -> bool {
const MASK: i32 = FlagValue::ReadWrite.value() | FlagValue::WriteOnly.value();
self.0 & MASK != 0
}
pub const fn readable(self) -> bool {
!self.write_only()
}
pub const fn read_only(self) -> bool {
self.0 == FlagValue::ReadOnly.value()
}
pub const fn write_only(self) -> bool {
self.0 & FlagValue::WriteOnly.value() != 0
}
pub const fn directory(self) -> bool {
self.0 & FlagValue::Directory.value() != 0
}
pub const fn process(self) -> bool {
self.0 & FlagValue::Process.value() != 0
}
pub const fn server(self) -> bool {
self.0 & FlagValue::Server.value() != 0
}
pub fn assert_readable(self) -> Result<(), io::Error> {
if !self.readable() {
Err(io::Error::from_raw_os_error(libc::EACCES))
} else {
Ok(())
}
}
pub fn assert_writeable(self) -> Result<(), io::Error> {
if !self.writeable() {
Err(io::Error::from_raw_os_error(libc::EACCES))
} else {
Ok(())
}
}
}
impl From<i32> for Flags {
fn from(value: i32) -> Self {
Self::new(value)
}
}
impl From<Flags> for i32 {
fn from(flags: Flags) -> Self {
flags.value()
}
}
impl From<FlagValue> for Flags {
fn from(flag_value: FlagValue) -> Self {
Self::new(flag_value.value())
}
}
impl BitOr<Flags> for Flags {
type Output = Flags;
fn bitor(self, rhs: Flags) -> Self::Output {
Self::new(self.value() | rhs.value())
}
}
impl BitOr<FlagValue> for Flags {
type Output = Flags;
fn bitor(self, rhs: FlagValue) -> Self::Output {
Self::new(self.value() | rhs.value())
}
}
impl Display for Flags {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.value().fmt(f)
}
}
impl Default for Flags {
fn default() -> Self {
Self::new(0)
}
}
#[derive(Serialize, Deserialize, PartialEq, Eq, Clone, Hash, Default)]
pub struct Attrs {
pub mode: u32,
pub uid: u32,
pub gid: u32,
pub atime: Epoch,
pub mtime: Epoch,
pub ctime: Epoch,
pub tags: Vec<(String, Vec<u8>)>,
}
#[derive(Serialize, Deserialize, PartialEq, Eq, Clone, Hash)]
pub struct AttrsSet(u16);
macro_rules! field {
($index:expr, $name:ident) => {
pub const $name: AttrsSet = AttrsSet::new(1 << $index);
paste! {
pub fn [<$name:lower>](self) -> bool {
const MASK: u16 = 1 << $index;
self.0 & MASK != 0
}
}
};
}
impl AttrsSet {
field!(0, MODE);
field!(1, UID);
field!(2, GID);
field!(3, ATIME);
field!(4, MTIME);
field!(5, CTIME);
pub const ALL: Self = Self::new(
Self::MODE.0 | Self::UID.0 | Self::GID.0 | Self::ATIME.0 | Self::MTIME.0 | Self::CTIME.0,
);
pub const fn new(value: u16) -> Self {
Self(value)
}
pub const fn none() -> Self {
Self(0)
}
pub const fn value(self) -> u16 {
self.0
}
}
impl Copy for AttrsSet {}
impl From<u16> for AttrsSet {
fn from(value: u16) -> Self {
Self::new(value)
}
}
impl From<AttrsSet> for u16 {
fn from(attr: AttrsSet) -> Self {
attr.value()
}
}
impl BitOr<Self> for AttrsSet {
type Output = Self;
fn bitor(self, rhs: Self) -> Self::Output {
AttrsSet::new(self.value() | rhs.value())
}
}
impl BitOrAssign<Self> for AttrsSet {
fn bitor_assign(&mut self, rhs: Self) {
self.0 |= rhs.0
}
}
#[derive(Debug, Serialize, Deserialize)]
pub struct Entry {
pub attr: BlockMetaSecrets,
pub attr_timeout: Duration,
pub entry_timeout: Duration,
}
#[derive(Serialize, Deserialize)]
pub struct Lookup<'a> {
pub parent: Inode,
pub name: &'a str,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct LookupReply {
pub inode: Inode,
pub generation: u64,
pub entry: Entry,
}
#[derive(Serialize, Deserialize)]
pub struct Create<'a> {
pub parent: Inode,
pub name: &'a str,
pub flags: Flags,
pub mode: u32,
pub umask: u32,
}
#[derive(Serialize, Deserialize)]
pub struct CreateReply {
pub inode: Inode,
pub handle: Handle,
pub entry: Entry,
}
#[derive(Serialize, Deserialize)]
pub struct Open {
pub inode: Inode,
pub flags: Flags,
}
#[derive(Serialize, Deserialize)]
pub struct OpenReply {
pub handle: Handle,
}
#[derive(Serialize, Deserialize)]
pub struct Read {
pub inode: Inode,
pub handle: Handle,
pub offset: u64,
pub size: u64,
}
#[derive(Serialize, Deserialize)]
pub struct ReadReply<'a> {
pub data: &'a [u8],
}
#[derive(Serialize, Deserialize)]
pub struct Write<R> {
pub inode: Inode,
pub handle: Handle,
pub offset: u64,
pub data: R,
}
#[derive(Serialize, Deserialize)]
pub struct WriteReply {
pub written: u64,
}
#[derive(Serialize, Deserialize)]
pub struct Flush {
pub inode: Inode,
pub handle: Handle,
}
#[derive(Serialize, Deserialize)]
pub struct ReadDir {
pub inode: Inode,
pub handle: Handle,
pub limit: u32,
pub state: u64,
}
#[derive(Serialize, Deserialize)]
pub struct ReadDirReply {
pub entries: Vec<(String, DirEntry)>,
pub new_state: u64,
}
#[derive(Serialize, Deserialize)]
pub struct Link<'a> {
pub inode: Inode,
pub new_parent: Inode,
pub name: &'a str,
}
#[derive(Serialize, Deserialize)]
pub struct LinkReply {
pub entry: Entry,
}
#[derive(Serialize, Deserialize)]
pub struct Unlink<'a> {
pub parent: Inode,
pub name: &'a str,
}
#[derive(Serialize, Deserialize)]
pub struct ReadMeta {
pub inode: Inode,
pub handle: Option<Handle>,
}
#[derive(Serialize, Deserialize)]
pub struct ReadMetaReply {
pub attrs: BlockMetaSecrets,
pub valid_for: Duration,
}
#[derive(Serialize, Deserialize)]
pub struct WriteMeta {
pub inode: Inode,
pub handle: Option<Handle>,
pub attrs: Attrs,
pub attrs_set: AttrsSet,
}
#[derive(Serialize, Deserialize)]
pub struct WriteMetaReply {
pub attrs: BlockMetaSecrets,
pub valid_for: Duration,
}
#[derive(Serialize, Deserialize)]
pub struct Allocate {
pub inode: Inode,
pub handle: Handle,
pub offset: Option<u64>,
pub size: u64,
}
#[derive(Serialize, Deserialize)]
pub struct Close {
pub inode: Inode,
pub handle: Handle,
}
#[derive(Serialize, Deserialize)]
pub struct Forget {
pub inode: Inode,
pub count: u64,
}
#[derive(Serialize, Deserialize)]
pub struct LockDesc {
pub offset: u64,
pub size: u64,
pub exclusive: bool,
}
#[derive(Serialize, Deserialize)]
pub struct Lock {
pub inode: Inode,
pub handle: Handle,
pub desc: LockDesc,
}
#[derive(Serialize, Deserialize)]
pub struct Unlock {
pub inode: Inode,
pub handle: Handle,
}
#[derive(Serialize, Deserialize)]
pub struct AddReadcap {
pub inode: Inode,
pub handle: Handle,
pub pub_creds: ConcretePub,
}
#[derive(Serialize, Deserialize)]
pub struct GrantAccess {
pub inode: Inode,
pub record: IssuedProcRec,
}