change up a lot of things to make writing to drive work pretty well (conflicts not so well)

This commit is contained in:
OMGeeky
2023-05-20 14:12:44 +02:00
parent 327e0e1564
commit a8171c5fca
11 changed files with 940 additions and 815 deletions

View File

@@ -27,3 +27,5 @@ ignore = "0.4.20"
tracing = "0.1.37"
tracing-subscriber = "0.3.17"
console-subscriber = "0.1.9"
bimap = "0.6.3"
md-5 = "0.10"

View File

@@ -27,7 +27,7 @@ pub trait CommonEntry {
// ) -> Self;
}
#[async_trait]
pub trait CommonFilesystem<Entry: CommonEntry> {
pub trait CommonFilesystem<Entry: CommonEntry > {
fn get_entries(&self) -> &HashMap<Inode, Entry>;
fn get_entries_mut(&mut self) -> &mut HashMap<Inode, Entry>;
fn get_children(&self) -> &HashMap<Inode, Vec<Inode>>;
@@ -135,13 +135,13 @@ pub trait CommonFilesystem<Entry: CommonEntry> {
debug!("add_file_entry: {}:{:?}; {}", parent, name, mode);
let ino = self
.add_entry(name, mode, FileType::RegularFile, parent, size)
.add_entry_new(name, mode, FileType::RegularFile, parent, size)
.await?;
Ok(ino)
}
async fn add_entry(
async fn add_entry_new(
&mut self,
name: &OsStr,
mode: u16,
@@ -150,6 +150,21 @@ pub trait CommonFilesystem<Entry: CommonEntry> {
size: u64,
) -> Result<Inode>;
fn add_entry(
&mut self,
entry: Entry,
parent_ino: impl Into<Inode> + Debug,
) -> Inode
where Entry: Debug{
let ino = entry.get_ino();
self.get_entries_mut().insert(
ino,entry,
);
self.add_child(parent_ino, &ino);
ino
}
fn add_child(&mut self, parent_ino: impl Into<Inode>, ino: impl Into<Inode>) {
let parents_child_list = self
.get_children_mut()

View File

@@ -1,3 +1,4 @@
use tracing::{error, instrument};
use anyhow::{anyhow, Context};
use drive3::api::{Drive, File};
use drive3::chrono::{DateTime, Utc};
@@ -39,10 +40,16 @@ pub struct Change {
impl TryFrom<DriveChange> for Change {
type Error = anyhow::Error;
#[instrument]
fn try_from(drive_change: DriveChange) -> anyhow::Result<Self> {
let removed = drive_change.removed.unwrap_or(false);
let drive_id = drive_change.file_id.context("drive_id is missing");
if let Err(e) = drive_id {
error!("drive_id is missing: {:?}", e);
return Err(anyhow!("drive_id is missing: {:?}", e));
}
Ok(Self {
drive_id: DriveId::from(drive_change.drive_id.context("drive_id is missing")?),
drive_id: DriveId::from(drive_id?),
kind: ChangeType::from_drive_change(drive_change.change_type, drive_change.file, drive_change.drive, removed)?,
time: drive_change.time.context("time is missing")?,
removed,

View File

@@ -3,6 +3,9 @@ use crate::fs::{CommonEntry, Inode};
use crate::google_drive::DriveId;
use fuser::FileAttr;
use std::ffi::{OsStr, OsString};
use std::path::PathBuf;
use tracing::instrument;
#[derive(Debug, Clone)]
pub struct DriveEntry {
pub ino: Inode,
@@ -10,49 +13,70 @@ pub struct DriveEntry {
pub name: OsString,
// pub drive_path: OsString,
pub local_path: LocalPath,
pub local_path: Option<LocalPath>,
pub attr: FileAttr,
pub drive_metadata: Option<drive3::api::File>,
pub has_upstream_content_changes: bool,
pub md5_checksum: Option<String>,
pub local_md5_checksum: Option<String>,
}
impl DriveEntry {
#[instrument]
pub(crate) fn set_md5_checksum(&mut self, md5_checksum: Option<String>) {
self.md5_checksum = md5_checksum.clone();
self.local_md5_checksum = md5_checksum;
}
}
impl DriveEntry {
pub fn new(
ino: impl Into<Inode>,
name: impl Into<OsString>,
drive_id: impl Into<DriveId>,
local_path: impl Into<LocalPath>,
// local_path: impl Into<LocalPath>,
attr: FileAttr,
drive_metadata: Option<drive3::api::File>,
) -> Self {
let name = name.into();
let path = local_path.into();
// let path = local_path.into();
Self {
ino: ino.into(),
drive_id: drive_id.into(),
name,
// drive_path: path.clone().into(),
local_path: path,
local_path: None,
attr,
drive_metadata,
has_upstream_content_changes: true,
md5_checksum:None,
local_md5_checksum:None,
}
}
pub fn build_local_path(&mut self, parent: Option<LocalPath>){
if let Some(parent_path) = parent {
let path = parent_path.join(&self.name);
self.local_path = Some(LocalPath::from(path));
}else{
self.local_path = Some(LocalPath::from(PathBuf::from("")));
}
}
}
impl CommonEntry for DriveEntry {
fn get_ino(&self) -> Inode {
self.ino
}
fn get_name(&self) -> &OsStr {
&self.name
}
fn get_local_path(&self) -> &LocalPath {
&self.local_path
}
fn get_attr(&self) -> &FileAttr {
&self.attr
}
}
// impl CommonEntry for DriveEntry {
// fn get_ino(&self) -> Inode {
// self.ino
// }
//
// fn get_name(&self) -> &OsStr {
// &self.name
// }
//
// fn get_local_path(&self) -> &LocalPath {
// &self.local_path
// }
//
// fn get_attr(&self) -> &FileAttr {
// &self.attr
// }
// }

View File

@@ -153,7 +153,7 @@ impl<'a> DriveFileUploader {
self.running_uploads.remove(drive_id);
}
}
#[instrument(skip(file_metadata))]
#[instrument(skip(file_metadata, rc), fields(drive=%drive))]
async fn upload_file(drive: GoogleDrive,
file_metadata: drive3::api::File,
local_path: PathBuf,

File diff suppressed because it is too large Load Diff

View File

@@ -152,7 +152,7 @@ impl CommonFilesystem<SampleEntry> for SampleFilesystem {
fn get_root_path(&self) -> LocalPath {
self.source.clone().into()
}
async fn add_entry(
async fn add_entry_new(
&mut self,
name: &OsStr,
mode: u16,
@@ -202,7 +202,7 @@ impl SampleFilesystem {
ino = parent_ino;
} else {
ino = self
.add_entry(
.add_entry_new(
folder_path.file_name().unwrap(),
/*TODO: correct permissions*/
0o755,

View File

@@ -28,11 +28,88 @@ use tracing::field::debug;
use crate::google_drive::{drive, DriveId, helpers};
use crate::prelude::*;
const FIELDS_FILE: &str = "id, name, size, mimeType, kind, md5Checksum, parents,trashed, createdTime, modifiedTime, viewedByMeTime";
#[derive(Clone)]
pub struct GoogleDrive {
hub: DriveHub<HttpsConnector<HttpConnector>>,
}
impl GoogleDrive {
#[instrument]
pub(crate) async fn list_all_files(&self) -> anyhow::Result<Vec<File>> {
let mut files = Vec::new();
let mut page_token: Option<String> = None;
loop {
debug!("list_files: page_token: {:?}", page_token);
let mut request =
self
.hub
.files()
.list()
.param(
"fields",
&format!("nextPageToken, files({})", FIELDS_FILE),
);
if let Some(page_token) = page_token {
request = request.page_token(&page_token);
}
let (response, result) = request
.doit()
.await?;
let result_files = result.files.ok_or(anyhow!("no file list returned"))?;
debug!("list_files: response: {:?}", result_files.len());
files.extend(result_files);
page_token = result.next_page_token;
if page_token.is_none() {
break;
}
}
Ok(files)
}
//
// #[instrument]
// pub async fn list_files(&self, folder_id: DriveId) -> anyhow::Result<Vec<File>> {
// debug!("list_files: folder_id: {:?}", folder_id);
// let folder_id: OsString = folder_id.into();
// let folder_id = match folder_id.into_string() {
// Ok(folder_id) => folder_id,
// Err(_) => return Err(anyhow!("invalid folder_id")),
// };
// if folder_id.is_empty() {
// return Err(anyhow!("folder_id is empty"));
// }
// if folder_id.contains('\'') {
// return Err(anyhow!("folder_id contains invalid character"));
// }
// let mut files = Vec::new();
// let mut page_token = None;
// loop {
// debug!("list_files: page_token: {:?}", page_token);
// let (response, result) = self
// .hub
// .files()
// .list()
// .param(
// "fields",
// &format!("nextPageToken, files({})", FIELDS_FILE),
// )
// // .page_token(page_token.as_ref().map(String::as_str))
// .q(format!("'{}' in parents", folder_id).as_str())
// .doit()
// .await?;
// let result_files = result.files.ok_or(anyhow!("no file list returned"))?;
// debug!("list_files: response: {:?}", result_files.len());
// files.extend(result_files);
// page_token = result.next_page_token;
// if page_token.is_none() {
// break;
// }
// }
// Ok(files)
// }
}
impl GoogleDrive {
#[instrument]
pub(crate) async fn get_start_page_token(&self) -> anyhow::Result<StartPageToken> {
@@ -48,20 +125,28 @@ impl GoogleDrive {
let mut page_token: Option<String> = None;
loop {
debug!("getting changes since {:?} page: {:?}", start_page_token, page_token);
let file_spec = &format!("file({})", FIELDS_FILE);
let mut request = self
.hub
.changes()
.list(&start_page_token
.start_page_token
.as_ref()
.context("no start_page_token")?);
.context("no start_page_token")?)
.param("fields", &format!("changes({}, changeType, removed, fileId, \
driveId, drive, time), newStartPageToken, nextPageToken", file_spec));
if let Some(page_token) = &page_token {
request = request.page_token(page_token);
}
let (_response, change_list) = request
let response = request
.doit()
.await
.context("could not get changes")?;
.context("could not get changes");
if let Err(e) = &response {
error!("error getting changes: {:?}", e);
return Err(anyhow!("error getting changes: {:?}", e));
}
let (_response, change_list) = response?;
if let Some(change_list) = change_list.changes {
changes.extend(change_list);
}
@@ -82,12 +167,12 @@ impl GoogleDrive {
impl GoogleDrive {
#[instrument]
pub(crate) async fn get_metadata_for_file(&self, drive_id: DriveId) -> anyhow::Result<File> {
let drive_id = drive_id.into_string().map_err(|_| anyhow!("invalid drive_id"))?;
let drive_id = drive_id.to_string();
let (response, file) = self
.hub
.files()
.get(&drive_id)
.param("fields", "id, name, modifiedTime, driveId, size, createdTime, viewedByMeTime")
.param("fields", &FIELDS_FILE)
.doit().await?;
Ok(file)
@@ -120,10 +205,7 @@ impl GoogleDrive {
file_id,
target_file.display()
);
let file_id: String = match file_id.try_into() {
Ok(file_id) => file_id,
Err(e) => return Err(anyhow!("invalid file_id: {:?}", e).into()),
};
let file_id: String = file_id.to_string();
let file = download_file_by_id(&self, file_id, target_file.as_path()).await;
debug!("download_file: completed");
@@ -245,7 +327,7 @@ impl GoogleDrive {
.list()
.param(
"fields",
"nextPageToken, files(id, name, size, mimeType, kind)",
&format!("nextPageToken, files({})", FIELDS_FILE),
)
// .page_token(page_token.as_ref().map(String::as_str))
.q(format!("'{}' in parents", folder_id).as_str())
@@ -318,10 +400,11 @@ async fn download_file_by_id(
) -> Result<File> {
use tokio::fs::File;
use tokio::io::AsyncWriteExt;
let id = id.into();
let (response, content): (Response<Body>, google_drive3::api::File) = hub
.hub
.files()
.get(&id.into())
.get(&id)
.add_scope(Scope::Readonly)
.acknowledge_abuse(true)
.param("alt", "media")
@@ -331,8 +414,17 @@ async fn download_file_by_id(
debug!("download_file_by_id(): response: {:?}", response);
debug!("download_file_by_id(): content: {:?}", content);
write_body_to_file(response, target_path).await?;
let (_, file) = hub
.hub
.files()
.get(&id)
.add_scope(Scope::Readonly)
.param("fields", FIELDS_FILE)
.doit()
.await?;
debug!("download_file_by_id(): file: {:?}", file);
Ok(content)
Ok(file)
}
async fn write_body_to_file(response: Response<Body>, target_path: &Path) -> Result<()> {
@@ -477,7 +569,7 @@ async fn update_file_content_on_drive(
.hub
.files()
.update(file, &id)
.upload(stream, mime_type)
.upload_resumable(stream, mime_type)
.await?;
debug!("upload done!");
debug!("update_file_on_drive(): response: {:?}", response);

View File

@@ -1,49 +1,69 @@
use std::ffi::OsString;
use std::fmt::{Display, Pointer};
use anyhow::Context;
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct DriveId(OsString);
pub struct DriveId(String);
impl DriveId {
pub(crate) fn root() -> DriveId {
DriveId(OsString::from("root"))
DriveId(String::from("root"))
}
pub fn as_str(&self) -> Option<&str> {
self.0.to_str()
}
pub fn into_string(self) -> Result<String, OsString> {
self.0.into_string()
pub fn as_str(&self) -> &str {
self.0.as_str()
}
}
impl Into<OsString> for DriveId {
fn into(self) -> OsString {
self.0
OsString::from(self.0)
}
}
impl TryInto<String> for DriveId {
type Error = OsString;
fn try_into(self) -> Result<String, Self::Error> {
self.0.into_string()
}
}
impl From<OsString> for DriveId {
fn from(value: OsString) -> Self {
DriveId(value)
impl TryFrom<OsString> for DriveId {
type Error = anyhow::Error;
fn try_from(value: OsString) -> anyhow::Result<Self> {
let result = value.into_string();
if let Err(e) = result {
return Err(anyhow::anyhow!("Failed to convert OsString to String: {:?}", e));
}
Ok(DriveId::new(result.unwrap()))
}
}
impl From<String> for DriveId {
fn from(value: String) -> Self {
OsString::from(value).into()
DriveId::new(value)
}
}
impl From<&str> for DriveId {
fn from(s: &str) -> Self {
DriveId(OsString::from(s))
DriveId::new(s)
}
}
impl From<&DriveId> for DriveId {
fn from(s: &DriveId) -> Self {
s.clone()
}
}
impl From<&String> for DriveId {
fn from(s: &String) -> Self {
DriveId::new(s)
}
}
impl DriveId {
pub fn new(id: impl Into<OsString>) -> Self {
pub fn new(id: impl Into<String>) -> Self {
Self(id.into())
}
}
}
impl Display for DriveId {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(&self.0)
}
}

View File

@@ -13,38 +13,38 @@ pub fn get_mime_from_file_metadata(file: &File) -> anyhow::Result<Mime> {
&file.mime_type.as_ref().unwrap_or(&"*/*".to_string()),
)?)
}
pub fn get_drive_id_from_local_path(drive: &DriveFilesystem, path: &Path) -> Result<DriveId> {
let drive_mount_point: &PathBuf = &drive.get_root_path().into();
debug!("get_drive_id_from_path(): (0) path: '{}'", path.display());
let path = match path.strip_prefix(drive_mount_point) {
Err(e) => {
return Err(anyhow!(
"Path {:?} is not a prefix of {:?}",
drive_mount_point,
path
))?
}
Ok(path) => path,
};
debug!("get_drive_id_from_path(): (1) path: '{}'", path.display());
if path == Path::new("/") || path == Path::new("") {
debug!(
"get_drive_id_from_path(): (1) path is root: '{}'",
path.display()
);
return Ok("root".into());
}
let mut parent_ino: Inode = 5u32.into();
// let mut parent_ino : Inode =Inode::from(5u32);//.into();
for part in path.iter() {
debug!("get_drive_id_from_path(): (2..) path: '{:?}'", part);
let children = drive.get_children().get(&parent_ino);
debug!("get_drive_id_from_path(): (2..) children: '{:?}'", children);
}
todo!("get_drive_id_from_path()")
}
// pub fn get_drive_id_from_local_path(drive: &DriveFilesystem, path: &Path) -> Result<DriveId> {
// let drive_mount_point: &PathBuf = &drive.get_root_path().into();
// debug!("get_drive_id_from_path(): (0) path: '{}'", path.display());
// let path = match path.strip_prefix(drive_mount_point) {
// Err(e) => {
// return Err(anyhow!(
// "Path {:?} is not a prefix of {:?}",
// drive_mount_point,
// path
// ))?
// }
// Ok(path) => path,
// };
// debug!("get_drive_id_from_path(): (1) path: '{}'", path.display());
// if path == Path::new("/") || path == Path::new("") {
// debug!(
// "get_drive_id_from_path(): (1) path is root: '{}'",
// path.display()
// );
// return Ok("root".into());
// }
//
// let mut parent_ino: Inode = 5u32.into();
// // let mut parent_ino : Inode =Inode::from(5u32);//.into();
// for part in path.iter() {
// debug!("get_drive_id_from_path(): (2..) path: '{:?}'", part);
//
// let children = drive.get_children().get(&parent_ino);
// debug!("get_drive_id_from_path(): (2..) children: '{:?}'", children);
// }
// todo!("get_drive_id_from_path()")
// }
mod test {
use super::*;
// #[tokio::test]

View File

@@ -1,27 +1,23 @@
#![allow(dead_code, unused)]
// #![allow(dead_code, unused)]
extern crate google_drive3 as drive3;
use std::error::Error;
use std::ffi::OsStr;
use std::path::Path;
use std::time::{Duration, SystemTime};
use std::time::UNIX_EPOCH;
use async_trait::async_trait;
use drive3::{DriveHub, hyper, hyper_rustls, oauth2};
use drive3::api::Channel;
use fuser::{FileAttr, Filesystem, FileType, FUSE_ROOT_ID, MountOption, ReplyAttr, ReplyData, ReplyDirectory, ReplyEmpty, ReplyEntry, ReplyOpen, ReplyWrite, ReplyXattr, Request, Session, SessionUnmounter, TimeOrNow};
use google_drive3::oauth2::read_application_secret;
use std::path::Path;
use std::time::{Duration};
use fuser::{Session, SessionUnmounter,MountOption};
// use nix;
use notify::{INotifyWatcher, recommended_watcher, RecommendedWatcher};
use tempfile::TempDir;
use tokio::io::{AsyncReadExt, stdin};
use tokio::runtime::Runtime;
// use tokio::io::{AsyncReadExt, stdin};
// use tokio::runtime::Runtime;
use tokio::sync::mpsc;
use tokio::sync::mpsc::{channel, Sender};
use tokio::sync::mpsc::{ Sender};
use tokio::task::JoinHandle;
use tracing::{debug, error, info, trace, warn};
use tracing::{debug, info};
use prelude::*;
@@ -37,378 +33,6 @@ pub mod google_drive;
pub mod prelude;
pub mod config;
#[cfg(test)]
mod tests {
use super::*;
fn init_logger() {
todo!("init logger (tracing)")
}
#[tokio::test]
async fn does_it_work() {
init_logger();
list_files().await;
}
}
pub async fn sample() -> Result<()> {
//Test file id: "1IotISYu3cF7JrOdfFPKNOkgYg1-ii5Qs"
list_files().await
}
async fn list_files() -> Result<()> {
debug!("Hello, world!");
let secret: oauth2::ApplicationSecret = read_application_secret("auth/client_secret.json")
.await
.expect("failed to read client secret file");
let auth = oauth2::InstalledFlowAuthenticator::builder(
secret,
oauth2::InstalledFlowReturnMethod::HTTPRedirect,
)
.persist_tokens_to_disk("auth/token_store.json")
.build()
.await?;
let hub = DriveHub::new(
hyper::Client::builder().build(
hyper_rustls::HttpsConnectorBuilder::new()
.with_native_roots()
.https_or_http()
.enable_http1()
.enable_http2()
.build(),
),
auth,
);
let result = hub
.files()
.get("1IotISYu3cF7JrOdfFPKNOkgYg1-ii5Qs")
.doit()
.await?;
// debug!("Result: {:?}", result);
let (body, file) = result;
debug!("Body: {:?}", body);
debug!("File: {:?}", file);
// let result = hub.files().list().corpus("user").doit().await;
// debug!("Result: {:?}", result);
info!("Filename: {:?}", file.name.unwrap_or("NO NAME".to_string()));
info!(
"Description: {:?}",
file.description.unwrap_or("NO DESCRIPTION".to_string())
);
Ok(())
}
#[derive(Default)]
struct MyFS {
/// how long the responses can/should be cached
time_to_live: Duration,
main_ino: u64,
main_size: u64,
main_blksize: u64,
main_uid: u32,
main_gid: u32,
main_flags: u32,
main_content: Vec<u8>,
main_file_type: Option<FileType>,
main_name: String,
}
struct DirEntry {
ino: u64,
name: String,
file_type: FileType,
}
impl MyFS {
fn get_attr(&self, ino: u64) -> Option<FileAttr> {
// Get the file attributes based on the inode number
if ino == FUSE_ROOT_ID {
Some(FileAttr {
ino: FUSE_ROOT_ID,
size: 0,
blocks: 0,
atime: UNIX_EPOCH,
mtime: UNIX_EPOCH,
ctime: UNIX_EPOCH,
crtime: UNIX_EPOCH,
kind: FileType::Directory,
perm: 0o755,
nlink: 0,
uid: 0,
gid: 0,
rdev: 0,
blksize: 0,
flags: 0,
})
} else if ino == self.main_ino {
Some(FileAttr {
ino: FUSE_ROOT_ID,
size: self.main_size,
blocks: 0,
atime: UNIX_EPOCH,
mtime: UNIX_EPOCH,
ctime: UNIX_EPOCH,
crtime: UNIX_EPOCH,
kind: self.main_file_type.unwrap_or(FileType::RegularFile),
perm: 0o755,
nlink: 0,
uid: self.main_uid,
gid: self.main_gid,
rdev: 0,
blksize: self.main_blksize as u32,
flags: self.main_flags,
})
} else {
None
}
}
fn set_attr(
&mut self,
ino: u64,
mode: Option<u32>,
uid: Option<u32>,
gid: Option<u32>,
size: Option<u64>,
flags: Option<u32>,
) -> Option<FileAttr> {
debug!(
"set_attr=> ino: {}; mode: {:?}; uid: {:?}; gid: {:?}; size: {:?}; flags: {:?}",
ino, mode, uid, gid, size, flags
);
// Get the file attributes based on the inode number
if ino == self.main_ino {
self.main_size = size.unwrap_or(self.main_size);
self.main_flags = flags.unwrap_or(self.main_flags);
self.main_uid = uid.unwrap_or(self.main_uid);
self.main_gid = gid.unwrap_or(self.main_gid);
return self.get_attr(ino);
} else {
None
}
}
fn write_file(
&mut self,
ino: u64,
fh: u64,
offset: i64,
data: &[u8],
flags: i32,
) -> Option<usize> {
// Write the file and reply with the number of bytes written
debug!(
"write_file=> ino: {}; fh: {}; offset: {}; data: {:?}; flags: {}",
ino, fh, offset, data, flags
);
if ino == self.main_ino {
self.main_content = data.to_vec();
// todo!("write the file and reply with the number of bytes written");
return Some(data.len());
} else {
None
}
}
fn read_file(&self, ino: u64, fh: u64, offset: i64, size: u32) -> Option<Vec<u8>> {
debug!(
"read_file=> ino: {}; fh: {}; offset: {}; size: {}",
ino, fh, offset, size
);
if ino == self.main_ino {
// Read the file and reply with the data
let data = &self.main_content.clone(); //b"Hello World!";
let offset_usize = offset as usize;
let size_usize = size as usize;
if data.len() <= offset_usize {
let result = vec![libc::EOF as u8];
debug!("read_file=> (0) result: {:?}", result);
return Some(result);
}
if offset_usize + size_usize > data.len() {
//return the rest of the data + EOF
let mut result = data[1..].to_vec();
result.push(libc::EOF as u8);
debug!("read_file=> (1) result: {:?}", result);
return Some(result);
// todo!("output the rest of the data + EOF, not just EOF");
return None;
}
let result = data[offset_usize..offset_usize + size_usize].to_vec();
debug!("read_file=> (2) result: {:?}", result);
return Some(result);
} else {
None
}
}
fn read_dir(&self, ino: u64) -> Option<Vec<DirEntry>> {
if ino == FUSE_ROOT_ID {
let mut entries = Vec::new();
let dir_entry = DirEntry {
ino: self.main_ino,
name: self.main_name.clone(),
file_type: self.main_file_type.unwrap_or(FileType::RegularFile),
};
entries.push(dir_entry);
Some(entries)
} else {
None
}
}
}
#[async_trait]
impl Filesystem for MyFS {
fn open(&mut self, _req: &Request<'_>, _ino: u64, _flags: i32, reply: ReplyOpen) {
if _ino == self.main_ino {
reply.opened(0, 0);
} else {
reply.error(libc::ENOENT);
}
}
fn access(&mut self, _req: &Request<'_>, ino: u64, mask: i32, reply: ReplyEmpty) {
if ino == self.main_ino {
reply.ok()
} else {
reply.error(libc::ENOENT)
}
}
fn getattr(&mut self, _req: &Request, ino: u64, reply: ReplyAttr) {
if let Some(attr) = self.get_attr(ino) {
reply.attr(&self.time_to_live, &attr);
} else {
reply.error(libc::ENOENT);
}
}
fn write(
&mut self,
_req: &Request<'_>,
ino: u64,
fh: u64,
offset: i64,
data: &[u8],
write_flags: u32,
flags: i32,
lock_owner: Option<u64>,
reply: ReplyWrite,
) {
if let Some(size) = self.write_file(ino, fh, offset, data, flags) {
reply.written(size as u32);
} else {
reply.error(libc::ENOENT);
}
}
fn setattr(
&mut self,
_req: &Request<'_>,
ino: u64,
mode: Option<u32>,
uid: Option<u32>,
gid: Option<u32>,
size: Option<u64>,
_atime: Option<TimeOrNow>,
_mtime: Option<TimeOrNow>,
_ctime: Option<SystemTime>,
fh: Option<u64>,
_crtime: Option<SystemTime>,
_chgtime: Option<SystemTime>,
_bkuptime: Option<SystemTime>,
flags: Option<u32>,
reply: ReplyAttr,
) {
if let Some(attr) = self.set_attr(ino, mode, uid, gid, size, flags) {
reply.attr(&self.time_to_live, &attr);
} else {
reply.error(libc::ENOENT);
}
}
fn read(
&mut self,
_req: &Request<'_>,
ino: u64,
fh: u64,
offset: i64,
size: u32,
flags: i32,
lock_owner: Option<u64>,
reply: ReplyData,
) {
if let Some(data) = self.read_file(ino, fh, offset, size) {
let data = data.as_slice();
reply.data(data);
} else {
reply.error(libc::ENOENT);
}
}
fn readdir(
&mut self,
_req: &Request<'_>,
ino: u64,
fh: u64,
offset: i64,
mut reply: ReplyDirectory,
) {
debug!("readdir=> ino: {}; fh: {}; offset: {}", ino, fh, offset);
if let Some(entries) = self.read_dir(ino) {
for (i, entry) in entries.iter().enumerate().skip(offset as usize) {
if reply.add(entry.ino, (i + 1) as i64, entry.file_type, &entry.name) {
break;
}
}
reply.ok();
} else {
reply.error(libc::ENOENT);
}
}
fn lookup(&mut self, _req: &Request<'_>, parent: u64, name: &OsStr, reply: ReplyEntry) {
let main_path = OsStr::new(&self.main_name);
debug!(
"lookup=> parent: {}; name: {:?}; main_path: {:?}",
parent, name, main_path
);
if name.eq_ignore_ascii_case(main_path) {
let attr = self.get_attr(self.main_ino).unwrap();
reply.entry(&self.time_to_live, &attr, 0);
} else {
reply.error(libc::ENOENT);
}
}
}
pub async fn watch_file_reading() -> Result<()> {
let mountpoint = "/tmp/fuse/1";
let options = vec![
MountOption::RW,
// MountOption::FSName("myfs".to_string()),
// MountOption::AllowOther,
// MountOption::AutoUnmount,
];
debug!("Mounting fuse filesystem at {}", mountpoint);
fuser::mount2(
MyFS {
time_to_live: Duration::from_secs(5),
main_ino: 2,
main_name: "1.txt".to_string(),
main_file_type: Some(FileType::RegularFile),
main_content: b"Hello World!".to_vec(),
..Default::default()
},
mountpoint,
&options,
)
.unwrap();
debug!("Exiting...");
Ok(())
}
pub async fn sample_fs() -> Result<()> {
let mountpoint = "/tmp/fuse/1";
let source = "/tmp/fuse/2";
@@ -425,7 +49,7 @@ pub async fn sample_fs() -> Result<()> {
pub async fn sample_drive_fs() -> Result<()> {
let mountpoint = "/tmp/fuse/3";
let upload_ignore_path = Path::new("config/.upload_ignore");
let settings_path = Path::new("config/settings.json");
// let settings_path = Path::new("config/settings.json");
let cache_dir = get_cache_dir()?;
let upload_ignore = CommonFileFilter::from_path(upload_ignore_path)?;
@@ -484,11 +108,11 @@ async fn mount(fs: DriveFilesystem,
let mut session = Session::new(fs, mountpoint.as_ref(), options)?;
let session_ender = session.unmount_callable();
let end_program_signal_handle = tokio::spawn(async move {
end_program_signal_awaiter(sender, session_ender).await;
let _ = end_program_signal_awaiter(sender, session_ender).await;
});
debug!("Mounting fuse filesystem" );
session.run();
debug!("Finished with mounting");
let _ = session.run();
debug!("Stopped with mounting");
// Ok(session_ender)
Ok(end_program_signal_handle)
}