use std::any::Any;
use std::ffi::OsString;
use std::io;
use serde::{Deserialize, Serialize};
use crate::path::RelPath;
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Serialize, Deserialize)]
pub struct FileId {
pub dev: u64,
pub ino: u64,
}
#[derive(Clone, Copy, PartialEq, Eq, Debug, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum Kind {
File,
Dir,
Symlink,
Other,
}
#[derive(Clone, Copy, Debug)]
pub struct Meta {
pub kind: Kind,
pub id: FileId,
pub len: u64,
pub mode: u32,
pub nlink: u64,
}
#[derive(Clone, Copy, Debug)]
pub enum Probe {
ParentMismatch,
Missing,
Present(Meta),
}
pub type LockGuard = Box<dyn Any + Send>;
#[derive(Debug)]
pub struct ParentMismatch;
impl std::fmt::Display for ParentMismatch {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str("parent directory identity does not match the journal")
}
}
impl std::error::Error for ParentMismatch {}
pub(crate) fn parent_mismatch() -> io::Error {
io::Error::other(ParentMismatch)
}
pub trait Vfs: Send + Sync {
fn root_id(&self) -> io::Result<FileId>;
fn stat(&self, p: &RelPath) -> io::Result<Option<Meta>>;
fn read_file(&self, p: &RelPath) -> io::Result<Vec<u8>>;
fn read_dir(&self, p: &RelPath) -> io::Result<Vec<OsString>>;
fn create_file(&self, p: &RelPath, data: &[u8], mode: Option<u32>) -> io::Result<Meta>;
fn append(&self, p: &RelPath, data: &[u8]) -> io::Result<()>;
fn mkdir(&self, p: &RelPath) -> io::Result<Meta>;
fn rename_noreplace(
&self,
from: &RelPath,
expect_from_parent: Option<FileId>,
to: &RelPath,
expect_to_parent: Option<FileId>,
) -> io::Result<()>;
fn unlink(&self, p: &RelPath, expect_parent: Option<FileId>) -> io::Result<()>;
fn rmdir(&self, p: &RelPath) -> io::Result<()>;
fn sync_file(&self, p: &RelPath) -> io::Result<()>;
fn sync_dir(&self, p: &RelPath) -> io::Result<()>;
fn lock(&self, exclusive: bool) -> io::Result<LockGuard>;
fn untrusted_fs_type(&self) -> io::Result<Option<&'static str>> {
Ok(None)
}
fn probe_cache_key(&self) -> Option<FileId> {
None
}
fn probe(&self, p: &RelPath, expect_parent: FileId) -> io::Result<Probe> {
let parent = p.parent().unwrap_or_default();
match self.stat(&parent)? {
Some(m) if m.kind == Kind::Dir && m.id == expect_parent => {}
_ => return Ok(Probe::ParentMismatch),
}
Ok(match self.stat(p)? {
Some(m) => Probe::Present(m),
None => Probe::Missing,
})
}
fn event(&self, _name: &'static str) {}
}