mirror of
https://github.com/OMGeeky/gdriver2.git
synced 2026-01-01 17:29:56 +01:00
start to create filesystem implementation
This commit is contained in:
141
gdriver-client/src/filesystem.rs
Normal file
141
gdriver-client/src/filesystem.rs
Normal file
@@ -0,0 +1,141 @@
|
||||
use std::collections::HashMap;
|
||||
use std::ffi::OsStr;
|
||||
use std::os::raw::c_int;
|
||||
use std::time::Duration;
|
||||
|
||||
use anyhow::anyhow;
|
||||
use bimap::BiMap;
|
||||
use fuser::{KernelConfig, ReplyEntry, Request};
|
||||
use tracing::*;
|
||||
|
||||
use gdriver_common::drive_structure::drive_id::{DriveId, ROOT_ID};
|
||||
use gdriver_common::ipc::gdriver_service::{
|
||||
errors::GDriverServiceError, GDriverServiceClient, GDriverSettings,
|
||||
};
|
||||
|
||||
use crate::prelude::*;
|
||||
use crate::{
|
||||
reply_error_e, reply_error_o, send_request, send_request_handled, send_request_handled2,
|
||||
send_request_handled2_consuming,
|
||||
};
|
||||
|
||||
mod macros;
|
||||
|
||||
//TODO2: Decide if this is a good TTL
|
||||
const TTL: Duration = Duration::from_secs(2);
|
||||
|
||||
pub struct Filesystem {
|
||||
gdriver_client: GDriverServiceClient,
|
||||
|
||||
entry_ids: BiMap<u64, DriveId>,
|
||||
ino_to_file_handles: HashMap<u64, Vec<u64>>,
|
||||
next_ino: u64,
|
||||
gdriver_settings: GDriverSettings,
|
||||
}
|
||||
|
||||
impl Filesystem {
|
||||
pub fn new(gdriver_client: GDriverServiceClient) -> Self {
|
||||
Self {
|
||||
gdriver_client,
|
||||
entry_ids: BiMap::new(),
|
||||
ino_to_file_handles: HashMap::new(),
|
||||
next_ino: 222,
|
||||
gdriver_settings: GDriverSettings::default(),
|
||||
}
|
||||
}
|
||||
fn generate_ino(&mut self) -> u64 {
|
||||
let ino = self.next_ino;
|
||||
self.next_ino += 1;
|
||||
ino
|
||||
}
|
||||
}
|
||||
|
||||
//region DriveFilesystem ino_to_id
|
||||
impl Filesystem {
|
||||
fn get_id_from_ino(&self, ino: u64) -> Option<&DriveId> {
|
||||
self.entry_ids.get_by_left(&ino)
|
||||
}
|
||||
fn get_ino_from_id(&mut self, id: DriveId) -> u64 {
|
||||
let x = self.entry_ids.get_by_right(&id);
|
||||
if let Some(ino) = x {
|
||||
return *ino;
|
||||
}
|
||||
self.add_id(id)
|
||||
}
|
||||
fn remove_id(&mut self, id: DriveId) -> Result<u64> {
|
||||
if let Some((ino, _)) = self.entry_ids.remove_by_right(&id) {
|
||||
Ok(ino)
|
||||
} else {
|
||||
Err(Box::from(anyhow!("could not find id {}", id)))
|
||||
}
|
||||
}
|
||||
fn add_id(&mut self, id: DriveId) -> u64 {
|
||||
let ino = self.generate_ino();
|
||||
trace!("adding new ino for drive id: {} => {}", id, ino);
|
||||
self.entry_ids.insert(ino, id);
|
||||
ino
|
||||
}
|
||||
}
|
||||
|
||||
//endregion
|
||||
mod attributes;
|
||||
impl fuser::Filesystem for Filesystem {
|
||||
//region init
|
||||
fn init(&mut self, _req: &Request<'_>, _config: &mut KernelConfig) -> StdResult<(), c_int> {
|
||||
self.entry_ids.insert(1, ROOT_ID.clone());
|
||||
self.gdriver_settings =
|
||||
send_request!(self.gdriver_client.get_settings(tarpc::context::current()))
|
||||
.map_err(|e| {
|
||||
error!("Got a connection error while fetching settings: {e}");
|
||||
libc::ECONNREFUSED
|
||||
})?
|
||||
.map_err(|e| {
|
||||
error!("Got an error while fetching settings: {e}");
|
||||
trace!("details: {e:?}");
|
||||
libc::EBADMSG
|
||||
})?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
//endregion
|
||||
//region lookup
|
||||
fn lookup(&mut self, _req: &Request<'_>, parent: u64, name: &OsStr, reply: ReplyEntry) {
|
||||
let parent_id = self.entry_ids.get_by_left(&parent);
|
||||
let parent_id = reply_error_o!(
|
||||
parent_id,
|
||||
reply,
|
||||
libc::ENOENT,
|
||||
"Failed to find drive_id for parent ino: {}",
|
||||
parent
|
||||
);
|
||||
trace!(
|
||||
"looking for child of parent:{} with name: {:?}",
|
||||
parent_id,
|
||||
name
|
||||
);
|
||||
|
||||
let id = reply_error_e!(
|
||||
send_request_handled2!(
|
||||
self.gdriver_client.get_file_by_name(
|
||||
tarpc::context::current(),
|
||||
name.to_os_string(),
|
||||
parent_id.clone()
|
||||
),
|
||||
reply
|
||||
),
|
||||
reply,
|
||||
libc::ENOENT,
|
||||
"Could not find file by name '{:?}' under parent: {}",
|
||||
name,
|
||||
parent_id
|
||||
);
|
||||
send_request_handled2_consuming!(
|
||||
self.gdriver_client
|
||||
.get_metadata_for_file(tarpc::context::current(), id),
|
||||
reply,
|
||||
parent
|
||||
);
|
||||
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
132
gdriver-client/src/filesystem/attributes.rs
Normal file
132
gdriver-client/src/filesystem/attributes.rs
Normal file
@@ -0,0 +1,132 @@
|
||||
use std::collections::BTreeMap;
|
||||
use std::os::raw::c_int;
|
||||
use std::time::{Duration, SystemTime, UNIX_EPOCH};
|
||||
use tarpc::serde::{Deserialize, Serialize};
|
||||
|
||||
type Inode = u64;
|
||||
const BLOCK_SIZE: u64 = 512;
|
||||
|
||||
#[derive(Serialize, Deserialize, Copy, Clone, PartialEq)]
|
||||
enum FileKind {
|
||||
File,
|
||||
Directory,
|
||||
Symlink,
|
||||
}
|
||||
|
||||
impl From<FileKind> for fuser::FileType {
|
||||
fn from(kind: FileKind) -> Self {
|
||||
match kind {
|
||||
FileKind::File => fuser::FileType::RegularFile,
|
||||
FileKind::Directory => fuser::FileType::Directory,
|
||||
FileKind::Symlink => fuser::FileType::Symlink,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum XattrNamespace {
|
||||
Security,
|
||||
System,
|
||||
Trusted,
|
||||
User,
|
||||
}
|
||||
|
||||
fn parse_xattr_namespace(key: &[u8]) -> Result<XattrNamespace, c_int> {
|
||||
let user = b"user.";
|
||||
if key.len() < user.len() {
|
||||
return Err(libc::ENOTSUP);
|
||||
}
|
||||
if key[..user.len()].eq(user) {
|
||||
return Ok(XattrNamespace::User);
|
||||
}
|
||||
|
||||
let system = b"system.";
|
||||
if key.len() < system.len() {
|
||||
return Err(libc::ENOTSUP);
|
||||
}
|
||||
if key[..system.len()].eq(system) {
|
||||
return Ok(XattrNamespace::System);
|
||||
}
|
||||
|
||||
let trusted = b"trusted.";
|
||||
if key.len() < trusted.len() {
|
||||
return Err(libc::ENOTSUP);
|
||||
}
|
||||
if key[..trusted.len()].eq(trusted) {
|
||||
return Ok(XattrNamespace::Trusted);
|
||||
}
|
||||
|
||||
let security = b"security";
|
||||
if key.len() < security.len() {
|
||||
return Err(libc::ENOTSUP);
|
||||
}
|
||||
if key[..security.len()].eq(security) {
|
||||
return Ok(XattrNamespace::Security);
|
||||
}
|
||||
|
||||
return Err(libc::ENOTSUP);
|
||||
}
|
||||
fn time_now() -> (i64, u32) {
|
||||
time_from_system_time(&SystemTime::now())
|
||||
}
|
||||
|
||||
fn system_time_from_time(secs: i64, nsecs: u32) -> SystemTime {
|
||||
if secs >= 0 {
|
||||
UNIX_EPOCH + Duration::new(secs as u64, nsecs)
|
||||
} else {
|
||||
UNIX_EPOCH - Duration::new((-secs) as u64, nsecs)
|
||||
}
|
||||
}
|
||||
|
||||
fn time_from_system_time(system_time: &SystemTime) -> (i64, u32) {
|
||||
// Convert to signed 64-bit time with epoch at 0
|
||||
match system_time.duration_since(UNIX_EPOCH) {
|
||||
Ok(duration) => (duration.as_secs() as i64, duration.subsec_nanos()),
|
||||
Err(before_epoch_error) => (
|
||||
-(before_epoch_error.duration().as_secs() as i64),
|
||||
before_epoch_error.duration().subsec_nanos(),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct InodeAttributes {
|
||||
pub inode: Inode,
|
||||
pub open_file_handles: u64, // Ref count of open file handles to this inode
|
||||
pub size: u64,
|
||||
pub last_accessed: (i64, u32),
|
||||
pub last_modified: (i64, u32),
|
||||
pub last_metadata_changed: (i64, u32),
|
||||
pub kind: FileKind,
|
||||
// Permissions and special mode bits
|
||||
pub mode: u16,
|
||||
pub hardlinks: u32,
|
||||
pub uid: u32,
|
||||
pub gid: u32,
|
||||
pub xattrs: BTreeMap<Vec<u8>, Vec<u8>>,
|
||||
}
|
||||
|
||||
impl From<InodeAttributes> for fuser::FileAttr {
|
||||
fn from(attrs: InodeAttributes) -> Self {
|
||||
fuser::FileAttr {
|
||||
ino: attrs.inode,
|
||||
size: attrs.size,
|
||||
blocks: (attrs.size + BLOCK_SIZE - 1) / BLOCK_SIZE,
|
||||
atime: system_time_from_time(attrs.last_accessed.0, attrs.last_accessed.1),
|
||||
mtime: system_time_from_time(attrs.last_modified.0, attrs.last_modified.1),
|
||||
ctime: system_time_from_time(
|
||||
attrs.last_metadata_changed.0,
|
||||
attrs.last_metadata_changed.1,
|
||||
),
|
||||
crtime: SystemTime::UNIX_EPOCH,
|
||||
kind: attrs.kind.into(),
|
||||
perm: attrs.mode,
|
||||
nlink: attrs.hardlinks,
|
||||
uid: attrs.uid,
|
||||
gid: attrs.gid,
|
||||
rdev: 0,
|
||||
blksize: BLOCK_SIZE as u32,
|
||||
flags: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
77
gdriver-client/src/filesystem/macros.rs
Normal file
77
gdriver-client/src/filesystem/macros.rs
Normal file
@@ -0,0 +1,77 @@
|
||||
mod reply {
|
||||
#[macro_export]
|
||||
macro_rules! reply_error_o {
|
||||
($option_in:expr, $reply:ident, $error_code:expr, $error_msg:expr) => {
|
||||
reply_error_o!($option_in, $reply, $error_code, $error_msg,)
|
||||
};
|
||||
($option_in:expr, $reply:ident, $error_code:expr, $error_msg:expr, $($arg:tt)*) => {{
|
||||
match $option_in {
|
||||
None=>{
|
||||
::tracing::error!($error_msg, $($arg)*);
|
||||
$reply.error($error_code);
|
||||
return;
|
||||
},
|
||||
Some(x) => x,
|
||||
}
|
||||
}};
|
||||
}
|
||||
#[macro_export]
|
||||
macro_rules! reply_error_e {
|
||||
($result_in:expr, $reply:ident, $error_code:expr, $error_msg:expr) => {
|
||||
reply_error_e!($result_in, $reply, $error_code, $error_msg,)
|
||||
};
|
||||
($result:expr, $reply:ident, $error_code:expr, $error_msg:expr, $($arg:tt)*) => {{
|
||||
match $result {
|
||||
Ok(x) => x,
|
||||
Err(e) => {
|
||||
error!("{}; e:{}",format!($error_msg, $($arg)*), e);
|
||||
$reply.error($error_code);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}};
|
||||
}
|
||||
}
|
||||
|
||||
mod send_requests {
|
||||
#[macro_export]
|
||||
macro_rules! send_request {
|
||||
($func:expr ) => {{
|
||||
let handle = ::tokio::runtime::Handle::current();
|
||||
let _ = handle.enter();
|
||||
futures::executor::block_on($func)
|
||||
}};
|
||||
}
|
||||
#[macro_export]
|
||||
macro_rules! send_request_handled {
|
||||
($func:expr ,$reply:ident, $error_code:expr, $error_msg:expr, $($arg:tt)*) => {{
|
||||
let x = send_request!($func);
|
||||
reply_error_e!(x, $reply, $error_code, $error_msg, $($arg)*)
|
||||
}};
|
||||
}
|
||||
#[macro_export]
|
||||
macro_rules! send_request_handled2 {
|
||||
($func:expr ,$reply:ident) => {
|
||||
send_request_handled2!($func, $reply, "")
|
||||
};
|
||||
($func:expr ,$reply:ident, $error_msg:expr) => {
|
||||
send_request_handled!(
|
||||
$func,
|
||||
$reply,
|
||||
::libc::EREMOTEIO,
|
||||
"Failed send request: {}",
|
||||
$error_msg
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! send_request_handled2_consuming {
|
||||
($func:expr ,$reply:ident) => {
|
||||
send_request_handled2_consuming!($func, $reply, "");
|
||||
};
|
||||
($func:expr ,$reply:ident, $error_msg:expr) => {
|
||||
let _ = send_request_handled2!($func, $reply, $error_msg);
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,8 @@ async fn main() -> Result<()> {
|
||||
service::start().await?;
|
||||
Ok(())
|
||||
}
|
||||
pub mod prelude;
|
||||
mod sample;
|
||||
|
||||
mod filesystem;
|
||||
mod service;
|
||||
|
||||
Reference in New Issue
Block a user