diff --git a/Cargo.lock b/Cargo.lock index 8acf70b..0874b8e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -432,11 +432,13 @@ dependencies = [ "directories", "futures", "lazy_static", + "libc", "serde", "serde_json", "tarpc", "thiserror", "tokio", + "tracing", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 5361674..2a59c78 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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/"} diff --git a/gdriver-backend/src/service.rs b/gdriver-backend/src/service.rs index 3b4148e..bb69780 100644 --- a/gdriver-backend/src/service.rs +++ b/gdriver-backend/src/service.rs @@ -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>, } impl GDriverService for GdriverServer { + async fn get_settings(self, _: Context) -> StdResult { + Ok(GDriverSettings::default()) //todo actually implement this + } + + async fn get_file_by_name( + self, + context: Context, + name: OsString, + parent: DriveId, + ) -> StdResult { + dbg!(context, name, parent); + Err(GetFileByPathError::Other) + } + async fn get_file_by_path( self, context: ::tarpc::context::Context, diff --git a/gdriver-client/Cargo.toml b/gdriver-client/Cargo.toml index 0851930..dabbee9 100644 --- a/gdriver-client/Cargo.toml +++ b/gdriver-client/Cargo.toml @@ -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" diff --git a/gdriver-client/src/filesystem.rs b/gdriver-client/src/filesystem.rs index 19f7a14..a3f60b5 100644 --- a/gdriver-client/src/filesystem.rs +++ b/gdriver-client/src/filesystem.rs @@ -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, - ino_to_file_handles: HashMap>, + ino_to_file_handles: HashMap>, next_ino: u64, gdriver_settings: GDriverSettings, entry_name_parent_to_ino: BiMap, } -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), } } + 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 { @@ -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!() + } } } diff --git a/gdriver-client/src/main.rs b/gdriver-client/src/main.rs index d8d9d9f..5bfc90d 100644 --- a/gdriver-client/src/main.rs +++ b/gdriver-client/src/main.rs @@ -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 = StdResult>; #[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; diff --git a/gdriver-common/Cargo.toml b/gdriver-common/Cargo.toml index 7718525..ff3c2bb 100644 --- a/gdriver-common/Cargo.toml +++ b/gdriver-common/Cargo.toml @@ -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 diff --git a/gdriver-common/src/drive_structure.rs b/gdriver-common/src/drive_structure.rs index 5ef6a77..95cd1f5 100644 --- a/gdriver-common/src/drive_structure.rs +++ b/gdriver-common/src/drive_structure.rs @@ -1,2 +1,3 @@ pub mod drive_id; +pub mod file_handle_flags; pub mod meta; diff --git a/gdriver-common/src/drive_structure/file_handle_flags.rs b/gdriver-common/src/drive_structure/file_handle_flags.rs new file mode 100644 index 0000000..3eb8ca0 --- /dev/null +++ b/gdriver-common/src/drive_structure/file_handle_flags.rs @@ -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 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 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 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); + } +} diff --git a/gdriver-common/src/ipc/gdriver_service.rs b/gdriver-common/src/ipc/gdriver_service.rs index 6d65e2c..1f4f647 100644 --- a/gdriver-common/src/ipc/gdriver_service.rs +++ b/gdriver-common/src/ipc/gdriver_service.rs @@ -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 {} diff --git a/gdriver-common/src/prelude.rs b/gdriver-common/src/prelude.rs index a24c75a..063075f 100644 --- a/gdriver-common/src/prelude.rs +++ b/gdriver-common/src/prelude.rs @@ -8,3 +8,4 @@ pub mod result { pub use std::result::Result as StdResult; } pub(crate) use result::*; +pub(crate) use tracing::*;