mirror of
https://github.com/OMGeeky/drive_syncer.git
synced 2026-02-23 15:38:31 +01:00
implement rename & move (local & remote)
This commit is contained in:
@@ -21,7 +21,8 @@ pub use handle_flags::HandleFlags;
|
|||||||
use crate::fs::drive_file_provider::{
|
use crate::fs::drive_file_provider::{
|
||||||
ProviderLookupRequest, ProviderMetadataRequest, ProviderOpenFileRequest,
|
ProviderLookupRequest, ProviderMetadataRequest, ProviderOpenFileRequest,
|
||||||
ProviderReadContentRequest, ProviderReadDirRequest, ProviderReleaseFileRequest,
|
ProviderReadContentRequest, ProviderReadDirRequest, ProviderReleaseFileRequest,
|
||||||
ProviderRequest, ProviderResponse, ProviderSetAttrRequest, ProviderWriteContentRequest,
|
ProviderRenameRequest, ProviderRequest, ProviderResponse, ProviderSetAttrRequest,
|
||||||
|
ProviderWriteContentRequest,
|
||||||
};
|
};
|
||||||
use crate::google_drive::DriveId;
|
use crate::google_drive::DriveId;
|
||||||
use crate::{
|
use crate::{
|
||||||
@@ -478,4 +479,51 @@ impl Filesystem for DriveFilesystem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//endregion
|
//endregion
|
||||||
|
//region rename
|
||||||
|
#[instrument(skip(_req, reply, _flags), fields(% self))]
|
||||||
|
fn rename(
|
||||||
|
&mut self,
|
||||||
|
_req: &Request<'_>,
|
||||||
|
parent: u64,
|
||||||
|
name: &OsStr,
|
||||||
|
new_parent: u64,
|
||||||
|
new_name: &OsStr,
|
||||||
|
_flags: u32,
|
||||||
|
reply: ReplyEmpty,
|
||||||
|
) {
|
||||||
|
let (provider_res_tx, mut provider_rx) = tokio::sync::mpsc::channel(1);
|
||||||
|
let parent_id = self.get_id_from_ino(parent);
|
||||||
|
reply_error_o!(
|
||||||
|
parent_id,
|
||||||
|
reply,
|
||||||
|
libc::ENOENT,
|
||||||
|
"Failed to find drive_id for ino: {}",
|
||||||
|
parent
|
||||||
|
);
|
||||||
|
let new_parent_id = self.get_id_from_ino(new_parent);
|
||||||
|
reply_error_o!(
|
||||||
|
new_parent_id,
|
||||||
|
reply,
|
||||||
|
libc::ENOENT,
|
||||||
|
"Failed to find drive_id for ino: {}",
|
||||||
|
new_parent
|
||||||
|
);
|
||||||
|
|
||||||
|
let v = ProviderRequest::Rename(ProviderRenameRequest::new(
|
||||||
|
name.to_os_string(),
|
||||||
|
parent_id.clone(),
|
||||||
|
new_name.to_os_string(),
|
||||||
|
new_parent_id.clone(),
|
||||||
|
provider_res_tx,
|
||||||
|
));
|
||||||
|
send_request!(self.file_provider_sender, v, reply);
|
||||||
|
receive_response!(provider_rx, response, reply);
|
||||||
|
|
||||||
|
match_provider_response!(response, reply, ProviderResponse::Rename, {
|
||||||
|
//
|
||||||
|
debug!("Sending Ok.")
|
||||||
|
reply.ok();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
//endregion
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,12 +4,14 @@ use std::{
|
|||||||
io::SeekFrom,
|
io::SeekFrom,
|
||||||
os::unix::prelude::MetadataExt,
|
os::unix::prelude::MetadataExt,
|
||||||
path::PathBuf,
|
path::PathBuf,
|
||||||
|
result::Result as StdResult,
|
||||||
time::{Duration, SystemTime, UNIX_EPOCH},
|
time::{Duration, SystemTime, UNIX_EPOCH},
|
||||||
};
|
};
|
||||||
|
|
||||||
use anyhow::{anyhow, Context};
|
use anyhow::{anyhow, Context};
|
||||||
use fuser::{FileAttr, FileType};
|
use fuser::{FileAttr, FileType};
|
||||||
use google_drive3::api::StartPageToken;
|
use google_drive3::api::StartPageToken;
|
||||||
|
use libc::c_int;
|
||||||
use tokio::{
|
use tokio::{
|
||||||
fs,
|
fs,
|
||||||
fs::{File, OpenOptions},
|
fs::{File, OpenOptions},
|
||||||
@@ -20,8 +22,10 @@ use tokio::{
|
|||||||
use tracing::{debug, error, instrument, trace, warn};
|
use tracing::{debug, error, instrument, trace, warn};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
common::VecExtension,
|
||||||
fs::drive::{Change, ChangeType},
|
fs::drive::{Change, ChangeType},
|
||||||
fs::drive2::HandleFlags,
|
fs::drive2::HandleFlags,
|
||||||
|
fs::drive_file_provider::ProviderRenameRequest,
|
||||||
fs::drive_file_provider::{
|
fs::drive_file_provider::{
|
||||||
FileMetadata, ProviderLookupRequest, ProviderMetadataRequest, ProviderOpenFileRequest,
|
FileMetadata, ProviderLookupRequest, ProviderMetadataRequest, ProviderOpenFileRequest,
|
||||||
ProviderReadContentRequest, ProviderReadDirRequest, ProviderReadDirResponse,
|
ProviderReadContentRequest, ProviderReadDirRequest, ProviderReadDirResponse,
|
||||||
@@ -57,6 +61,11 @@ pub struct FileData {
|
|||||||
pub attr: FileAttr,
|
pub attr: FileAttr,
|
||||||
pub is_local: bool,
|
pub is_local: bool,
|
||||||
}
|
}
|
||||||
|
impl FileData {
|
||||||
|
fn get_id(&self) -> Option<DriveId> {
|
||||||
|
self.metadata.id.map(|x| DriveId::from(x))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct FileHandleData {
|
pub struct FileHandleData {
|
||||||
@@ -145,6 +154,21 @@ impl DriveFileProvider {
|
|||||||
self.children.insert(parent_id, vec![child_id]);
|
self.children.insert(parent_id, vec![child_id]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn remove_parent_child_relation(&mut self, parent_id: DriveId, child_id: DriveId) {
|
||||||
|
trace!(
|
||||||
|
"removing child-parent relation for child: {:<50} and parent: {:<50}",
|
||||||
|
child_id,
|
||||||
|
parent_id
|
||||||
|
);
|
||||||
|
if let Some(parents) = self.parents.get_mut(&child_id) {
|
||||||
|
parents.remove_first_element(&parent_id);
|
||||||
|
}
|
||||||
|
if let Some(children) = self.children.get_mut(&parent_id) {
|
||||||
|
children.remove_first_element(&child_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//region listeners
|
//region listeners
|
||||||
#[instrument(skip(self, request_reciever, command_receiver))]
|
#[instrument(skip(self, request_reciever, command_receiver))]
|
||||||
pub async fn listen(
|
pub async fn listen(
|
||||||
@@ -202,6 +226,7 @@ impl DriveFileProvider {
|
|||||||
ProviderRequest::ReadContent(r) => self.read_content(r).await,
|
ProviderRequest::ReadContent(r) => self.read_content(r).await,
|
||||||
ProviderRequest::WriteContent(r) => self.write_content(r).await,
|
ProviderRequest::WriteContent(r) => self.write_content(r).await,
|
||||||
ProviderRequest::ReadDir(r) => self.read_dir(r).await,
|
ProviderRequest::ReadDir(r) => self.read_dir(r).await,
|
||||||
|
ProviderRequest::Rename(r) => self.rename(r).await,
|
||||||
ProviderRequest::Lookup(r) => self.lookup(r).await,
|
ProviderRequest::Lookup(r) => self.lookup(r).await,
|
||||||
ProviderRequest::SetAttr(r) => self.set_attr(r).await,
|
ProviderRequest::SetAttr(r) => self.set_attr(r).await,
|
||||||
_ => {
|
_ => {
|
||||||
@@ -244,29 +269,20 @@ impl DriveFileProvider {
|
|||||||
let name = name.unwrap();
|
let name = name.unwrap();
|
||||||
let parent_id = self.get_correct_id(request.parent);
|
let parent_id = self.get_correct_id(request.parent);
|
||||||
debug!("looking up {} under id {}", name, parent_id);
|
debug!("looking up {} under id {}", name, parent_id);
|
||||||
let children = self.children.get(&parent_id);
|
|
||||||
|
|
||||||
// let mut result = vec![];
|
let result = self.find_first_child_by_name(&name, &parent_id);
|
||||||
for child in children.unwrap_or(&vec![]) {
|
|
||||||
if let Some(child) = self.entries.get(child) {
|
if let Some(result) = result {
|
||||||
if child
|
let result = Self::create_file_metadata_from_entry(result);
|
||||||
.metadata
|
let response = ProviderResponse::Lookup(Some(result));
|
||||||
.name
|
return send_response!(request, response);
|
||||||
.as_ref()
|
|
||||||
.unwrap_or(&"NO_NAME".to_string())
|
|
||||||
.eq_ignore_ascii_case(&name)
|
|
||||||
{
|
|
||||||
// let response = result.push(Self::create_file_metadata_from_entry(child));
|
|
||||||
let result = Self::create_file_metadata_from_entry(child);
|
|
||||||
let response = ProviderResponse::Lookup(Some(result));
|
|
||||||
return send_response!(request, response);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
debug!("could not find file: {} in {}", name, parent_id);
|
debug!("could not find file: {} in {}", name, parent_id);
|
||||||
let response = ProviderResponse::Lookup(None);
|
let response = ProviderResponse::Lookup(None);
|
||||||
return send_response!(request, response);
|
return send_response!(request, response);
|
||||||
}
|
}
|
||||||
|
|
||||||
//endregion
|
//endregion
|
||||||
//region read dir
|
//region read dir
|
||||||
#[instrument(skip(request))]
|
#[instrument(skip(request))]
|
||||||
@@ -543,6 +559,105 @@ impl DriveFileProvider {
|
|||||||
let data = data.unwrap();
|
let data = data.unwrap();
|
||||||
send_response!(request, ProviderResponse::ReadContent(data))
|
send_response!(request, ProviderResponse::ReadContent(data))
|
||||||
}
|
}
|
||||||
|
//endregion
|
||||||
|
//region rename
|
||||||
|
|
||||||
|
async fn rename(&mut self, request: ProviderRenameRequest) -> Result<()> {
|
||||||
|
let original_parent = self.get_correct_id(request.original_parent.clone());
|
||||||
|
let original_name = request.original_name.into_string();
|
||||||
|
if let Err(e) = original_name {
|
||||||
|
return send_error_response!(
|
||||||
|
request,
|
||||||
|
anyhow!("Could not convert original name into string: {:?}", e),
|
||||||
|
libc::EIO
|
||||||
|
);
|
||||||
|
}
|
||||||
|
let original_name = original_name.unwrap();
|
||||||
|
let new_parent = self.get_correct_id(request.new_parent.clone());
|
||||||
|
let new_name = request.new_name.into_string();
|
||||||
|
if let Err(e) = new_name {
|
||||||
|
return send_error_response!(
|
||||||
|
request,
|
||||||
|
anyhow!("Could not convert new name into string: {:?}", e),
|
||||||
|
libc::EIO
|
||||||
|
);
|
||||||
|
}
|
||||||
|
let new_name = new_name.unwrap();
|
||||||
|
|
||||||
|
let rename_result = self
|
||||||
|
.rename_inner(&original_parent, &original_name, &new_parent, &new_name)
|
||||||
|
.await;
|
||||||
|
if let Err((msg, code)) = rename_result {
|
||||||
|
return send_error_response!(request, anyhow!("{}", msg), code);
|
||||||
|
}
|
||||||
|
|
||||||
|
send_response!(request, ProviderResponse::Rename)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn rename_inner(
|
||||||
|
&mut self,
|
||||||
|
original_parent: &DriveId,
|
||||||
|
original_name: &String,
|
||||||
|
new_parent: &DriveId,
|
||||||
|
new_name: &String,
|
||||||
|
) -> StdResult<(), (String, c_int)> {
|
||||||
|
let file_entry = self.find_first_child_by_name(&original_name, &original_parent);
|
||||||
|
if file_entry.is_none() {
|
||||||
|
return Err((format!("Could not find rename source"), libc::ENOENT));
|
||||||
|
}
|
||||||
|
let file_entry = file_entry.unwrap();
|
||||||
|
|
||||||
|
let file_id = file_entry.get_id();
|
||||||
|
if file_id.is_none() {
|
||||||
|
return Err((format!("Could not get id from entry"), libc::EINVAL));
|
||||||
|
}
|
||||||
|
let file_id = file_id.unwrap();
|
||||||
|
|
||||||
|
let wait_res = self
|
||||||
|
.wait_for_running_drive_request_if_exists(&file_id)
|
||||||
|
.await;
|
||||||
|
if let Err(e) = wait_res {
|
||||||
|
return Err((e.to_string(), libc::EIO));
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.check_id_exists(&new_parent) {
|
||||||
|
return Err((format!("Folder does not exist"), libc::ENOENT));
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.does_target_name_exist_under_parent(&new_parent, &new_name) {
|
||||||
|
return Err((format!("Target name is already used"), libc::EADDRINUSE));
|
||||||
|
}
|
||||||
|
|
||||||
|
let entry = self
|
||||||
|
.entries
|
||||||
|
.get_mut(&file_id)
|
||||||
|
.expect("We checked shortly before if the entry exists");
|
||||||
|
|
||||||
|
if original_name != new_name {
|
||||||
|
//check if the filename has been changed and update it in the metadata and on google drive
|
||||||
|
entry.changed_metadata.name = Some(new_name.clone());
|
||||||
|
}
|
||||||
|
let now = SystemTime::now();
|
||||||
|
entry.attr.atime = now;
|
||||||
|
entry.attr.mtime = now;
|
||||||
|
//check if the path is changed (child-parent relationships) and modify them accordingly
|
||||||
|
if original_parent != new_parent {
|
||||||
|
entry.changed_metadata.parents = Some(vec![new_parent.to_string()]);
|
||||||
|
self.remove_parent_child_relation(original_parent.clone(), file_id.clone());
|
||||||
|
self.add_parent_child_relation(new_parent.clone(), file_id.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
let upload_result = self.update_remote_metadata(file_id).await;
|
||||||
|
if let Err(e) = upload_result {
|
||||||
|
return Err((
|
||||||
|
format!("Error while uploading Metadata: {:?}", e),
|
||||||
|
libc::EREMOTEIO,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
//endregion
|
//endregion
|
||||||
//region write content
|
//region write content
|
||||||
#[instrument(skip(request))]
|
#[instrument(skip(request))]
|
||||||
@@ -567,6 +682,41 @@ impl DriveFileProvider {
|
|||||||
//endregion
|
//endregion
|
||||||
//region request helpers
|
//region request helpers
|
||||||
|
|
||||||
|
fn does_target_name_exist_under_parent(
|
||||||
|
&self,
|
||||||
|
new_parent: &&DriveId,
|
||||||
|
new_name: &&String,
|
||||||
|
) -> bool {
|
||||||
|
let new_file_entry = self.find_first_child_by_name(&new_name, &new_parent);
|
||||||
|
return new_file_entry.is_some();
|
||||||
|
}
|
||||||
|
fn check_id_exists(&self, id: &DriveId) -> bool {
|
||||||
|
self.entries.contains_key(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// returns the first entry it finds with the specified name that is a child of the parent_id
|
||||||
|
///
|
||||||
|
/// returns ```Option::None``` if none match/the parent does not have any children
|
||||||
|
fn find_first_child_by_name(&self, name: &String, parent_id: &DriveId) -> Option<&FileData> {
|
||||||
|
let mut result = None;
|
||||||
|
let children = self.children.get(&parent_id);
|
||||||
|
for child in children.unwrap_or(&vec![]) {
|
||||||
|
if let Some(child) = self.entries.get(child) {
|
||||||
|
if child
|
||||||
|
.metadata
|
||||||
|
.name
|
||||||
|
.as_ref()
|
||||||
|
.unwrap_or(&"$'\\NO_NAME".to_string())
|
||||||
|
.eq_ignore_ascii_case(&name)
|
||||||
|
{
|
||||||
|
result = Some(child);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
/// gets the file-handle and opens the file if it is marked for open.
|
/// gets the file-handle and opens the file if it is marked for open.
|
||||||
///
|
///
|
||||||
/// If it is not marked for open but the file is None this returns an error
|
/// If it is not marked for open but the file is None this returns an error
|
||||||
@@ -717,6 +867,20 @@ impl DriveFileProvider {
|
|||||||
changes
|
changes
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn update_remote_metadata(&self, id: DriveId) -> Result<()> {
|
||||||
|
let file_data = self.entries.get(&id);
|
||||||
|
if file_data.is_none() {
|
||||||
|
return Err(anyhow!("Could not get entry with id: {}", id));
|
||||||
|
}
|
||||||
|
let file_data = file_data.unwrap();
|
||||||
|
let mut metadata = file_data.changed_metadata.clone();
|
||||||
|
Self::prepare_changed_metadata_for_upload(&id, &mut metadata);
|
||||||
|
self.drive
|
||||||
|
.update_file_metadata_on_drive(metadata, &file_data.metadata);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
/// starts a download of the specified file and puts it in the running_requests map
|
/// starts a download of the specified file and puts it in the running_requests map
|
||||||
///
|
///
|
||||||
/// - will return an Error if another request is already running for the same id, so all callers should make sure of that
|
/// - will return an Error if another request is already running for the same id, so all callers should make sure of that
|
||||||
@@ -758,7 +922,10 @@ impl DriveFileProvider {
|
|||||||
.entries
|
.entries
|
||||||
.get(&id)
|
.get(&id)
|
||||||
.context("could not find data for id")?;
|
.context("could not find data for id")?;
|
||||||
|
|
||||||
let mut metadata = file_data.changed_metadata.clone();
|
let mut metadata = file_data.changed_metadata.clone();
|
||||||
|
Self::prepare_changed_metadata_for_upload(&id, &mut metadata);
|
||||||
|
metadata.mime_type = file_data.metadata.mime_type.clone();
|
||||||
|
|
||||||
let target_path = self.construct_path(&id)?;
|
let target_path = self.construct_path(&id)?;
|
||||||
debug!(
|
debug!(
|
||||||
@@ -766,9 +933,6 @@ impl DriveFileProvider {
|
|||||||
target_path.display(),
|
target_path.display(),
|
||||||
metadata
|
metadata
|
||||||
);
|
);
|
||||||
metadata.id = Some(id.clone().into());
|
|
||||||
metadata.mime_type = file_data.metadata.mime_type.clone();
|
|
||||||
let metadata = remove_volatile_metadata(metadata);
|
|
||||||
let handle: JoinHandle<Result<()>> = tokio::spawn(async move {
|
let handle: JoinHandle<Result<()>> = tokio::spawn(async move {
|
||||||
//TODO1: only send the changed metadata over (+id), not all of it (currently only all data that could change and where changes should be written to the drive), since google drive only wants the changes
|
//TODO1: only send the changed metadata over (+id), not all of it (currently only all data that could change and where changes should be written to the drive), since google drive only wants the changes
|
||||||
drive
|
drive
|
||||||
@@ -780,6 +944,11 @@ impl DriveFileProvider {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn prepare_changed_metadata_for_upload(id: &DriveId, mut metadata: &mut DriveFileMetadata) {
|
||||||
|
metadata.id = Some(id.clone().into());
|
||||||
|
remove_volatile_metadata(&mut metadata);
|
||||||
|
}
|
||||||
|
|
||||||
/// Checks if a drive request for this ID is running and if there is, waits for it.
|
/// Checks if a drive request for this ID is running and if there is, waits for it.
|
||||||
///
|
///
|
||||||
/// After awaiting, it removes the request from the map
|
/// After awaiting, it removes the request from the map
|
||||||
@@ -834,45 +1003,52 @@ impl DriveFileProvider {
|
|||||||
.expect("adding the root entry has to work, otherwise nothing else works");
|
.expect("adding the root entry has to work, otherwise nothing else works");
|
||||||
let entries = self.drive.list_all_files().await?;
|
let entries = self.drive.list_all_files().await?;
|
||||||
for entry in entries {
|
for entry in entries {
|
||||||
let id = &entry.id;
|
self.add_drive_entry_to_entries(entry);
|
||||||
if let Some(id) = id {
|
|
||||||
let id = DriveId::from(id);
|
|
||||||
let attr = self.create_file_attr_from_metadata(&entry);
|
|
||||||
if attr.is_err() {
|
|
||||||
warn!(
|
|
||||||
"error while creating FileAttr from metadata: {:?} entry: {:?}",
|
|
||||||
attr, entry
|
|
||||||
);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
let attr = attr.unwrap();
|
|
||||||
if let Some(parents) = &entry.parents {
|
|
||||||
for parent in parents {
|
|
||||||
let parent_id = DriveId::from(parent);
|
|
||||||
self.add_parent_child_relation(parent_id, id.clone());
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
//file is at root level
|
|
||||||
self.add_parent_child_relation(
|
|
||||||
self.get_correct_id(DriveId::root()),
|
|
||||||
id.clone(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
let entry_data = FileData {
|
|
||||||
metadata: entry,
|
|
||||||
changed_metadata: Default::default(),
|
|
||||||
perma: false, //TODO: read the perma marker from somewhere (maybe only after all files have been checked?)
|
|
||||||
attr,
|
|
||||||
is_local: false,
|
|
||||||
};
|
|
||||||
self.entries.insert(id, entry_data);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// for (i, (id, data)) in self.entries.iter().enumerate() {
|
// for (i, (id, data)) in self.entries.iter().enumerate() {
|
||||||
// info!("entry {:3} id: {:>40} data: {:?}", i, id, data);
|
// info!("entry {:3} id: {:>40} data: {:?}", i, id, data);
|
||||||
// }
|
// }
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn add_drive_entry_to_entries(&mut self, entry: DriveFileMetadata) -> bool {
|
||||||
|
let id = &entry.id;
|
||||||
|
if let Some(id) = id {
|
||||||
|
let id = DriveId::from(id);
|
||||||
|
let attr = self.create_file_attr_from_metadata(&entry);
|
||||||
|
if attr.is_err() {
|
||||||
|
warn!(
|
||||||
|
"error while creating FileAttr from metadata: {:?} entry: {:?}",
|
||||||
|
attr, entry
|
||||||
|
);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
let attr = attr.unwrap();
|
||||||
|
self.add_child_parent_relations(&entry, &id);
|
||||||
|
let entry_data = FileData {
|
||||||
|
metadata: entry,
|
||||||
|
changed_metadata: Default::default(),
|
||||||
|
perma: false, //TODO: read the perma marker from somewhere (maybe only after all files have been checked?)
|
||||||
|
attr,
|
||||||
|
is_local: false,
|
||||||
|
};
|
||||||
|
self.entries.insert(id, entry_data);
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_child_parent_relations(&mut self, entry: &DriveFileMetadata, id: &DriveId) {
|
||||||
|
if let Some(parents) = &entry.parents {
|
||||||
|
for parent in parents {
|
||||||
|
let parent_id = DriveId::from(parent);
|
||||||
|
self.add_parent_child_relation(parent_id, id.clone());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
//file is at root level
|
||||||
|
self.add_parent_child_relation(self.get_correct_id(DriveId::root()), id.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn create_file_attr_from_metadata(&self, metadata: &DriveFileMetadata) -> Result<FileAttr> {
|
fn create_file_attr_from_metadata(&self, metadata: &DriveFileMetadata) -> Result<FileAttr> {
|
||||||
let kind = convert_mime_type_to_file_type(
|
let kind = convert_mime_type_to_file_type(
|
||||||
metadata.mime_type.as_ref().unwrap_or(&"NONE".to_string()),
|
metadata.mime_type.as_ref().unwrap_or(&"NONE".to_string()),
|
||||||
@@ -930,8 +1106,11 @@ impl DriveFileProvider {
|
|||||||
self.entries.insert(root_id, data);
|
self.entries.insert(root_id, data);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// changes alias ids like ```DriveId::root()``` into their actual IDs on the drive
|
||||||
fn get_correct_id(&self, id: DriveId) -> DriveId {
|
fn get_correct_id(&self, id: DriveId) -> DriveId {
|
||||||
if id == DriveId::root() {
|
if id == DriveId::root() {
|
||||||
|
trace!("aliasing DriveId::root() to actual root: {}", id);
|
||||||
return self.alt_root_id.clone();
|
return self.alt_root_id.clone();
|
||||||
}
|
}
|
||||||
return id;
|
return id;
|
||||||
@@ -961,6 +1140,53 @@ impl DriveFileProvider {
|
|||||||
todo!("there was a file/dir added on the remote since this ID is unknown")
|
todo!("there was a file/dir added on the remote since this ID is unknown")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[instrument(skip(self, file_change))]
|
||||||
|
fn process_remote_file_moved(&mut self, id: &DriveId, file_change: &DriveFileMetadata) {
|
||||||
|
if let Some(changed_parents) = &file_change.parents {
|
||||||
|
trace!("parent was changed! {:?}", id);
|
||||||
|
let entry = self.entries.get(&id);
|
||||||
|
if let Some(entry) = entry {
|
||||||
|
trace!(
|
||||||
|
"changed_parents: {:?} before change: {:?}",
|
||||||
|
changed_parents,
|
||||||
|
entry.metadata.parents
|
||||||
|
);
|
||||||
|
if Some(changed_parents) != entry.metadata.parents.as_ref() {
|
||||||
|
if let Some(existing_parents) = entry.metadata.parents.clone() {
|
||||||
|
for e in existing_parents {
|
||||||
|
let old_parent_id = self.get_correct_id(DriveId::from(&e));
|
||||||
|
trace!("(1) converted id from {} to {}", e, old_parent_id);
|
||||||
|
self.remove_parent_child_relation(old_parent_id, id.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
trace!("done removing old parents");
|
||||||
|
for new_parent in changed_parents {
|
||||||
|
let new_parent_id = self.get_correct_id(DriveId::from(new_parent));
|
||||||
|
trace!("(2) converted id from {} to {} ", new_parent, new_parent_id);
|
||||||
|
self.add_parent_child_relation(new_parent_id, id.clone());
|
||||||
|
}
|
||||||
|
trace!("done adding new parents");
|
||||||
|
let entry_m = self.entries.get_mut(id);
|
||||||
|
if let Some(entry_m) = entry_m {
|
||||||
|
entry_m.metadata.parents = file_change.parents.clone();
|
||||||
|
}
|
||||||
|
trace!("done modifying metadata");
|
||||||
|
} else {
|
||||||
|
trace!(
|
||||||
|
"before and after are equal: {:?} == {:?}",
|
||||||
|
Some(changed_parents),
|
||||||
|
entry.metadata.parents
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
warn!(
|
||||||
|
"A remote file was moved but is unknown locally. is this right?: {:?}",
|
||||||
|
id
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#[instrument]
|
#[instrument]
|
||||||
fn process_file_change(entry: &mut FileData, change: DriveFileMetadata) -> Result<()> {
|
fn process_file_change(entry: &mut FileData, change: DriveFileMetadata) -> Result<()> {
|
||||||
@@ -996,8 +1222,7 @@ fn process_file_change(entry: &mut FileData, change: DriveFileMetadata) -> Resul
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remove_volatile_metadata(metadata: DriveFileMetadata) -> DriveFileMetadata {
|
fn remove_volatile_metadata(metadata: &mut DriveFileMetadata) {
|
||||||
let mut metadata = metadata;
|
|
||||||
metadata.size = None;
|
metadata.size = None;
|
||||||
metadata.created_time = None;
|
metadata.created_time = None;
|
||||||
metadata.trashed_time = None;
|
metadata.trashed_time = None;
|
||||||
@@ -1008,11 +1233,9 @@ fn remove_volatile_metadata(metadata: DriveFileMetadata) -> DriveFileMetadata {
|
|||||||
metadata.viewed_by_me_time = None;
|
metadata.viewed_by_me_time = None;
|
||||||
metadata.explicitly_trashed = None;
|
metadata.explicitly_trashed = None;
|
||||||
metadata.md5_checksum = None;
|
metadata.md5_checksum = None;
|
||||||
metadata.parents = None;
|
// metadata.parents = None;
|
||||||
// parents have to be set differently: "The parents field is not directly writable in update requests. Use the addParents and removeParents parameters instead."
|
// parents have to be set differently: "The parents field is not directly writable in update requests. Use the addParents and removeParents parameters instead."
|
||||||
metadata.kind = None;
|
metadata.kind = None;
|
||||||
|
|
||||||
metadata
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn convert_mime_type_to_file_type(mime_type: &str) -> Result<FileType> {
|
fn convert_mime_type_to_file_type(mime_type: &str) -> Result<FileType> {
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ pub enum ProviderResponse {
|
|||||||
Lookup(Option<FileMetadata>),
|
Lookup(Option<FileMetadata>),
|
||||||
ReadContent(Vec<u8>),
|
ReadContent(Vec<u8>),
|
||||||
ReadDir(ProviderReadDirResponse),
|
ReadDir(ProviderReadDirResponse),
|
||||||
|
Rename,
|
||||||
WriteSize(u32),
|
WriteSize(u32),
|
||||||
// Ok,
|
// Ok,
|
||||||
Error(Error, c_int),
|
Error(Error, c_int),
|
||||||
@@ -36,6 +37,7 @@ pub enum ProviderRequest {
|
|||||||
SetAttr(ProviderSetAttrRequest),
|
SetAttr(ProviderSetAttrRequest),
|
||||||
ReadContent(ProviderReadContentRequest),
|
ReadContent(ProviderReadContentRequest),
|
||||||
ReadDir(ProviderReadDirRequest),
|
ReadDir(ProviderReadDirRequest),
|
||||||
|
Rename(ProviderRenameRequest),
|
||||||
WriteContent(ProviderWriteContentRequest),
|
WriteContent(ProviderWriteContentRequest),
|
||||||
Unknown,
|
Unknown,
|
||||||
}
|
}
|
||||||
@@ -279,6 +281,34 @@ impl ProviderWriteContentRequest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct ProviderRenameRequest {
|
||||||
|
pub original_name: OsString,
|
||||||
|
pub original_parent: DriveId,
|
||||||
|
pub new_name: OsString,
|
||||||
|
pub new_parent: DriveId,
|
||||||
|
|
||||||
|
pub response_sender: Sender<ProviderResponse>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ProviderRenameRequest {
|
||||||
|
pub(crate) fn new(
|
||||||
|
original_name: OsString,
|
||||||
|
original_parent: DriveId,
|
||||||
|
new_name: OsString,
|
||||||
|
new_parent: DriveId,
|
||||||
|
response_sender: Sender<ProviderResponse>,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
original_name,
|
||||||
|
original_parent,
|
||||||
|
new_name,
|
||||||
|
new_parent,
|
||||||
|
response_sender,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// endregion
|
// endregion
|
||||||
//region ProviderResponse structs
|
//region ProviderResponse structs
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user