diff --git a/Cargo.lock b/Cargo.lock index 82a1847..62835d0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -248,7 +248,7 @@ dependencies = [ [[package]] name = "gcsf" -version = "0.1.18" +version = "0.1.19" dependencies = [ "chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/Cargo.toml b/Cargo.toml index 39fe6bb..416d839 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "gcsf" description = "Filesystem based on Google Drive" -version = "0.1.18" +version = "0.1.19" repository = "https://github.com/harababurel/gcsf" authors = ["Sergiu Puscas "] license = "MIT" diff --git a/src/cli.yml b/src/cli.yml index 05c1898..c6f98e8 100644 --- a/src/cli.yml +++ b/src/cli.yml @@ -1,5 +1,5 @@ name: GCSF -version: "0.1.18" +version: "0.1.19" author: Sergiu Puscas about: File system based on Google Drive subcommands: diff --git a/src/gcsf/drive_facade.rs b/src/gcsf/drive_facade.rs index bdbb5a4..c9f7f54 100644 --- a/src/gcsf/drive_facade.rs +++ b/src/gcsf/drive_facade.rs @@ -483,7 +483,7 @@ impl DriveFacade { .add_scope(drive3::Scope::Full) .doit_without_upload() .map(|_| ()) - .map_err(|e| err_msg(format!("DriveFacade::move_to() {}", e))) + .map_err(|e| err_msg(format!("DriveFacade::move_to_trash() {}", e))) } pub fn flush(&mut self, id: &DriveId) -> Result<(), Error> { diff --git a/src/gcsf/file.rs b/src/gcsf/file.rs index b54cdb0..028bda9 100644 --- a/src/gcsf/file.rs +++ b/src/gcsf/file.rs @@ -1,5 +1,6 @@ use chrono::DateTime; use drive3; +use failure::{err_msg, Error}; use fuse::{FileAttr, FileType}; use id_tree::NodeId; use std::collections::HashMap; @@ -142,6 +143,32 @@ impl File { !forbidden.contains(*c) } + /// Whether this file is trashed on Drive. + pub fn is_trashed(&self) -> bool { + self.drive_file + .as_ref() + .map(|f| f.trashed) + .unwrap_or_default() + .unwrap_or(false) + } + + // Trashing a file does not trigger a file update from Drive. Therefore this field must be + // set manually so that GCSF knows that this particular file is trashed and should be deleted + // permanently the next time unlink() is called. + pub fn set_trashed(&mut self, trashed: bool) -> Result<(), Error> { + let ino = self.inode(); + if let Some(ref mut drive_file) = self.drive_file.as_mut() { + drive_file.trashed = Some(trashed); + Ok(()) + } else { + Err(err_msg(format!( + "Could not set trashed={} because there is no drive file associated to {:?}", + trashed, + FileId::Inode(ino) + ))) + } + } + #[allow(dead_code)] pub fn is_drive_document(&self) -> bool { self.drive_file diff --git a/src/gcsf/file_manager.rs b/src/gcsf/file_manager.rs index 8c6ac4c..f0e4a1b 100644 --- a/src/gcsf/file_manager.rs +++ b/src/gcsf/file_manager.rs @@ -450,13 +450,27 @@ impl FileManager { self.tree.move_node(&node_id, ToParent(&trash_id))?; + // File cannot be identified by FileId::ParentAndName now because the parent has changed. + // Using DriveId instead. if also_on_drive { + self.get_mut_file(&FileId::DriveId(drive_id.clone())) + .ok_or(err_msg(format!("Cannot find {:?}", &drive_id)))? + .set_trashed(true)?; self.df.move_to_trash(drive_id)?; } Ok(()) } + /// Whether a file is trashed on Drive. + pub fn file_is_trashed(&mut self, id: &FileId) -> Result { + let file = self + .get_file(id) + .ok_or(err_msg(format!("Cannot find node_id of {:?}", &id)))?; + + Ok(file.is_trashed()) + } + /// Moves/renames a file locally *and* on Drive. pub fn rename( &mut self, diff --git a/src/gcsf/filesystem.rs b/src/gcsf/filesystem.rs index cf31347..58ceeeb 100644 --- a/src/gcsf/filesystem.rs +++ b/src/gcsf/filesystem.rs @@ -319,16 +319,35 @@ impl Filesystem for GCSF { return; } - match self.manager.move_file_to_trash(&id, true) { - Ok(response) => { - debug!("{:?}", response); - reply.ok(); + match self.manager.file_is_trashed(&id) { + Ok(trashed) => { + let ret = if trashed { + debug!("{:?} is already trashed. Deleting permanently.", id); + self.manager.delete(&id) + } else { + debug!( + "{:?} was not trashed. Moving it to Trash instead of deleting permanently.", + id + ); + self.manager.move_file_to_trash(&id, true) + }; + + match ret { + Ok(response) => { + debug!("{:?}", response); + reply.ok(); + } + Err(e) => { + error!("{:?}", e); + reply.error(EREMOTE); + } + }; } Err(e) => { error!("{:?}", e); reply.error(EREMOTE); } - }; + } } fn forget(&mut self, _req: &Request, _ino: u64, _nlookup: u64) {}