Improve implementation & actually mount it for testing

This commit is contained in:
OMGeeky
2024-02-18 18:33:42 +01:00
parent e498ec3f94
commit 267167e276
11 changed files with 249 additions and 17 deletions

2
Cargo.lock generated
View File

@@ -432,11 +432,13 @@ dependencies = [
"directories",
"futures",
"lazy_static",
"libc",
"serde",
"serde_json",
"tarpc",
"thiserror",
"tokio",
"tracing",
]
[[package]]

View File

@@ -14,6 +14,7 @@ tarpc = { version = "0.34", features = ["full"] }
futures="0.3"
lazy_static="1.4"
chrono="0.4"
libc = "0.2"
[patch.crates-io]
#tarpc = {path = "../../Documents/git/OMGeeky/tarpc/tarpc/"}

View File

@@ -1,9 +1,12 @@
use chrono::Duration;
use gdriver_common::ipc::gdriver_service::errors::*;
use gdriver_common::{
drive_structure::drive_id::{DriveId, ROOT_ID},
ipc::gdriver_service::*,
};
use std::ffi::OsString;
use std::{path::PathBuf, sync::Arc, thread};
use tarpc::context::Context;
use tokio::sync::Mutex;
use crate::drive::Drive;
@@ -15,6 +18,20 @@ struct GdriverServer {
drive: Arc<Mutex<Drive>>,
}
impl GDriverService for GdriverServer {
async fn get_settings(self, _: Context) -> StdResult<GDriverSettings, GetSettingsError> {
Ok(GDriverSettings::default()) //todo actually implement this
}
async fn get_file_by_name(
self,
context: Context,
name: OsString,
parent: DriveId,
) -> StdResult<DriveId, GetFileByPathError> {
dbg!(context, name, parent);
Err(GetFileByPathError::Other)
}
async fn get_file_by_path(
self,
context: ::tarpc::context::Context,

View File

@@ -10,11 +10,11 @@ tarpc.workspace = true
tokio.workspace = true
tracing.workspace = true
serde.workspace = true
libc.workspace = true
anyhow = "1.0"
futures-sink = "0.3.30"
fuser = "0.14.0"
bimap = "0.6"
libc = "0.2.152"
futures = "0.3"
thiserror = "1.0.56"

View File

@@ -5,11 +5,13 @@ use std::time::Duration;
use anyhow::anyhow;
use bimap::BiMap;
use fuser::{KernelConfig, ReplyEntry, Request};
use fuser::{KernelConfig, ReplyEntry, ReplyOpen, Request};
use tarpc::context::current as current_context;
use tracing::*;
use gdriver_common::drive_structure::drive_id::{DriveId, ROOT_ID};
use gdriver_common::drive_structure::meta::read_metadata_file;
use gdriver_common::drive_structure::file_handle_flags::HandleFlags;
use gdriver_common::ipc::gdriver_service::{
errors::GDriverServiceError, GDriverServiceClient, GDriverSettings,
};
@@ -18,7 +20,6 @@ use crate::filesystem::attributes::read_inode_attributes_from_meta_file;
use crate::filesystem::errors::FilesystemError;
use crate::prelude::macros::*;
use crate::prelude::*;
use tarpc::context::current as current_context;
mod macros;
@@ -26,24 +27,25 @@ mod macros;
const TTL: Duration = Duration::from_secs(2);
type Inode = u64;
type FileHandle = u64;
#[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
struct FileIdentifier {
parent: Inode,
name: OsString,
}
pub struct Filesystem {
#[derive(Debug)]
pub struct DriveFilesystem {
gdriver_client: GDriverServiceClient,
entry_ids: BiMap<Inode, DriveId>,
ino_to_file_handles: HashMap<Inode, Vec<u64>>,
ino_to_file_handles: HashMap<Inode, Vec<FileHandle>>,
next_ino: u64,
gdriver_settings: GDriverSettings,
entry_name_parent_to_ino: BiMap<FileIdentifier, Inode>,
}
impl Filesystem {
impl DriveFilesystem {
pub fn new(gdriver_client: GDriverServiceClient) -> Self {
Self {
gdriver_client,
@@ -62,7 +64,7 @@ impl Filesystem {
}
//region DriveFilesystem ino_to_id
impl Filesystem {
impl DriveFilesystem {
fn get_id_from_ino(&self, ino: Inode) -> Option<&DriveId> {
self.entry_ids.get_by_left(&ino)
}
@@ -91,7 +93,7 @@ impl Filesystem {
//endregion
mod attributes;
impl fuser::Filesystem for Filesystem {
impl fuser::Filesystem for DriveFilesystem {
//region init
fn init(&mut self, _req: &Request<'_>, _config: &mut KernelConfig) -> StdResult<(), c_int> {
self.entry_ids.insert(1, ROOT_ID.clone());
@@ -111,6 +113,9 @@ impl fuser::Filesystem for Filesystem {
//endregion
//region lookup
fn lookup(&mut self, _req: &Request<'_>, parent: u64, name: &OsStr, reply: ReplyEntry) {
if name.to_str().unwrap().contains('/') {
todo!("The name in lookup can contain multiple path segments, not just a single name, directly under the parent")
}
let metadata = utils::lookup::lookup(self, parent, name.to_os_string());
match metadata {
Ok(metadata) => {
@@ -133,12 +138,37 @@ impl fuser::Filesystem for Filesystem {
}
}
//endregion
//region open
fn open(&mut self, _req: &Request<'_>, ino: u64, flags: i32, reply: ReplyOpen) {
let data = utils::lookup::open(self, ino, HandleFlags::from(flags));
match data {
Ok((file_header, flags)) => {
reply.opened(file_header, flags.into());
}
Err(e) => {
error!("Got an error during open: {e:?}");
match e {
FilesystemError::Rpc(_) => reply.error(libc::EREMOTEIO),
FilesystemError::NotFound => reply.error(libc::ENOENT),
FilesystemError::IO(_) => reply.error(libc::EIO),
e => {
dbg!(e);
todo!("Handle other errors and decide what error code should be used here")
}
}
}
}
}
//endregion
}
mod errors {
use gdriver_common::ipc::gdriver_service::errors::GDriverServiceError;
use std::error::Error;
use tarpc::client::RpcError;
use gdriver_common::ipc::gdriver_service::errors::GDriverServiceError;
#[derive(Debug, thiserror::Error)]
pub enum FilesystemError {
#[error("Error while executing RPC: {0}")]
@@ -153,17 +183,22 @@ mod errors {
Other(#[source] Box<dyn Error>),
}
}
mod utils {
use super::*;
pub mod lookup {
use super::*;
use crate::filesystem::attributes::InodeAttributes;
use crate::filesystem::errors::FilesystemError;
use futures::TryFutureExt;
use gdriver_common::ipc::gdriver_service::errors::GetFileByPathError;
use crate::filesystem::attributes::InodeAttributes;
use crate::filesystem::errors::FilesystemError;
use super::*;
pub fn lookup(
fs: &mut Filesystem,
fs: &mut DriveFilesystem,
parent: Inode,
name: OsString,
) -> StdResult<InodeAttributes, FilesystemError> {
@@ -216,5 +251,14 @@ mod utils {
.map_err(FilesystemError::IO)?;
Ok(metadata)
}
pub(crate) fn open(
fs: &mut DriveFilesystem,
inode: Inode,
flags: HandleFlags,
) -> StdResult<(FileHandle, HandleFlags), FilesystemError> {
dbg!(&fs, inode, flags);
todo!()
}
}
}

View File

@@ -1,5 +1,10 @@
use fuser::{mount2, MountOption};
use std::path::Path;
use std::{error::Error, net::IpAddr, result::Result as StdResult};
use crate::filesystem::DriveFilesystem;
use crate::service::create_client;
use gdriver_common::ipc::gdriver_service::GDriverServiceClient;
use gdriver_common::{ipc::sample::*, prelude::*};
use tarpc::{client, tokio_serde::formats::Json};
@@ -7,7 +12,14 @@ type Result<T> = StdResult<T, Box<dyn Error>>;
#[tokio::main]
async fn main() -> Result<()> {
service::start().await?;
println!("Hello, world!");
let config = &CONFIGURATION;
println!("Config: {:?}", **config);
let client: GDriverServiceClient = create_client(config.ip, config.port).await?;
let fs = DriveFilesystem::new(client);
mount2(fs, Path::new("/tmp/gdriver"), &[MountOption::RW])?;
// service::start().await?;
Ok(())
}
pub mod prelude;

View File

@@ -8,6 +8,8 @@ edition = "2021"
[dependencies]
serde.workspace = true
tarpc.workspace = true
tracing.workspace = true
libc.workspace = true
tokio.workspace = true
futures.workspace = true
lazy_static.workspace = true

View File

@@ -1,2 +1,3 @@
pub mod drive_id;
pub mod file_handle_flags;
pub mod meta;

View File

@@ -0,0 +1,149 @@
use crate::prelude::*;
#[derive(Debug, Copy, Clone, Default)]
pub struct HandleFlags {
// File status flags used for open() and fcntl() are as follows:
/// append mode.
o_append: bool,
/// [SIO](https://pubs.opengroup.org/onlinepubs/009695399/help/codes.html#SIO) Write according to synchronized I/O data integrity completion.
o_dsync: bool,
/// Non-blocking mode.
o_nonblock: bool,
/// [SIO](https://pubs.opengroup.org/onlinepubs/009695399/help/codes.html#SIO) Synchronized read I/O operations.
o_rsync: bool,
/// Write according to synchronized I/O file integrity completion.
o_sync: bool,
// Mask for use with file access modes is as follows:
/// Mask for file access modes.
// O_ACCMODE
// File access modes used for open() and fcntl() are as follows:
/// Open for reading only.
o_rdonly: bool,
/// Open for reading and writing.
o_rdwr: bool,
/// Open for writing only.
o_wronly: bool,
}
impl HandleFlags {
pub(crate) fn can_write(&self) -> bool {
self.o_wronly || self.o_rdwr
}
pub(crate) fn can_read(&self) -> bool {
self.o_rdonly || self.o_rdwr
}
}
impl From<i32> for HandleFlags {
fn from(value: i32) -> Self {
debug!("Creating HandleFlags from an i32: {:x}", value);
let s = Self {
o_append: value & libc::O_APPEND != 0,
o_dsync: value & libc::O_DSYNC != 0,
o_nonblock: value & libc::O_NONBLOCK != 0,
o_rsync: value & libc::O_RSYNC != 0,
o_sync: value & libc::O_SYNC != 0,
o_rdonly: value & libc::O_ACCMODE == libc::O_RDONLY,
o_rdwr: value & libc::O_ACCMODE == libc::O_RDWR,
o_wronly: value & libc::O_ACCMODE == libc::O_WRONLY,
};
#[cfg(test)]
{
let o_accmode = value & libc::O_ACCMODE;
let o_rdonly = o_accmode == libc::O_RDONLY;
let o_rdwr = o_accmode == libc::O_RDWR;
let o_wronly = o_accmode == libc::O_WRONLY;
debug!(
"accmode {:x} rdonly {} rdwr {} wronly {}",
o_accmode, o_rdonly, o_rdwr, o_wronly
);
}
debug!("created HandleFlags: {:?}", s);
s
}
}
impl Into<i32> for HandleFlags {
fn into(self) -> i32 {
let mut flags = 0;
if self.o_append {
flags |= libc::O_APPEND;
}
if self.o_dsync {
flags |= libc::O_DSYNC;
}
if self.o_nonblock {
flags |= libc::O_NONBLOCK;
}
if self.o_rsync {
flags |= libc::O_RSYNC;
}
if self.o_sync {
flags |= libc::O_SYNC;
}
if self.o_rdonly {
flags |= libc::O_RDONLY;
}
if self.o_rdwr {
flags |= libc::O_RDWR;
}
if self.o_wronly {
flags |= libc::O_WRONLY;
}
flags
}
}
impl Into<u32> for HandleFlags {
fn into(self) -> u32 {
let i_num: i32 = self.into();
i_num as u32
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn handle_flags_ro() {
let flags = 0;
let handle_flags = HandleFlags::from(flags);
debug!("flags: {:x} => {:?}", flags, handle_flags);
assert!(handle_flags.can_read());
assert!(!handle_flags.can_write());
let flags = 32768;
let handle_flags = HandleFlags::from(flags);
debug!("flags: {:x} => {:?}", flags, handle_flags);
assert!(handle_flags.can_read());
assert!(!handle_flags.can_write());
}
#[test]
fn handle_flags_wo() {
let flags = 1;
let handle_flags = HandleFlags::from(flags);
debug!("flags: {:x} => {:?}", flags, handle_flags);
assert!(handle_flags.can_write());
assert!(!handle_flags.can_read());
}
#[test]
fn handle_flags_rw() {
let flags = 2;
let handle_flags = HandleFlags::from(flags);
debug!("flags: {:x} => {:?}", flags, handle_flags);
debug!("test432");
assert!(handle_flags.can_write());
assert!(handle_flags.can_read());
}
#[test]
fn handle_flags_into_rw() {
debug!("test123");
let mut x = HandleFlags::default();
x.o_rdwr = true;
assert!(x.can_write());
assert!(x.can_read());
let flags: i32 = x.into();
assert_eq!(2, flags);
}
}

View File

@@ -125,7 +125,10 @@ pub mod errors {
}
#[derive(Debug, Serialize, Deserialize, thiserror::Error)]
pub enum GetFileByPathError {}
pub enum GetFileByPathError {
#[error("Other")]
Other,
}
#[derive(Debug, Serialize, Deserialize, thiserror::Error)]
pub enum UpdateChangesError {}

View File

@@ -8,3 +8,4 @@ pub mod result {
pub use std::result::Result as StdResult;
}
pub(crate) use result::*;
pub(crate) use tracing::*;