From e99a1bc14706390cb1b84900a91bea0318e5dde5 Mon Sep 17 00:00:00 2001 From: omikuji Date: Wed, 30 Jan 2019 11:16:13 +0900 Subject: [PATCH 1/2] added RMD command --- src/commands.rs | 25 ++++++++++++++++++++++++- src/server.rs | 26 +++++++++++++++++++++++++- src/storage.rs | 11 +++++++++++ 3 files changed, 60 insertions(+), 2 deletions(-) diff --git a/src/commands.rs b/src/commands.rs index d009b6e..9121d0b 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -134,6 +134,10 @@ pub enum Command { /// The (regular) file to delete. path: String, }, + Rmd { + /// The (regular) directory to delete. + path: String, + }, /// The `QUIT` command Quit, /// The `MKD` command @@ -350,7 +354,17 @@ impl Command { let path = String::from_utf8_lossy(&path).to_string(); Command::Dele { path } - } + }, + b"RMD" | b"rmd" => { + let path = parse_to_eol(cmd_params)?; + if path.is_empty() { + return Err(ParseErrorKind::InvalidCommand)? + } + + let path = String::from_utf8_lossy(&path).to_string(); + Command::Rmd{ path } + + }, b"QUIT" | b"quit" => { let params = parse_to_eol(cmd_params)?; if !params.is_empty() { @@ -993,6 +1007,15 @@ mod tests { ); } + #[test] + fn parse_rmd() { + let input = "RMD\r\n"; + assert_eq!(Command::parse(input), Err(ParseError{inner: Context::new(ParseErrorKind::InvalidCommand)})); + + let input = "RMD some_directory\r\n"; + assert_eq!(Command::parse(input), Ok(Command::Rmd{path: "some_directory".into()})); + } + #[test] fn parse_quit() { let input = "QUIT\r\n"; diff --git a/src/server.rs b/src/server.rs index 1904bf6..6bd97be 100644 --- a/src/server.rs +++ b/src/server.rs @@ -1024,7 +1024,31 @@ where }), ); Ok(Reply::none()) - } + }, + Command::Rmd{path} => { + ensure_authenticated!(); + let session = session.lock()?; + let storage = Arc::clone(&session.storage); + let tx_success = tx.clone(); + let tx_fail = tx.clone(); + tokio::spawn( + storage.rmd(path) + .map_err(|_| std::io::Error::new(ErrorKind::Other, "Failed to delete directory")) + .and_then(|_| { + tx_success.send(InternalMsg::DelSuccess) + .map_err(|_| std::io::Error::new(ErrorKind::Other, "Failed to send 'DelSuccess' to data channel")) + }) + .or_else(|_| { + tx_fail.send(InternalMsg::DelFail) + .map_err(|_| std::io::Error::new(ErrorKind::Other, "Failed to send 'DelFail' to data channel")) + }) + .map(|_| ()) + .map_err(|e| { + warn!("Failed to delete directory: {}", e); + }) + ); + Ok(Reply::none()) + }, Command::Quit => { let tx = tx.clone(); spawn!(tx.send(InternalMsg::Quit)); diff --git a/src/storage.rs b/src/storage.rs index 3e903f7..5595e26 100644 --- a/src/storage.rs +++ b/src/storage.rs @@ -203,6 +203,9 @@ pub trait StorageBackend { /// Delete the given file. fn del>(&self, path: P) -> Box + Send>; + /// Delete the given directory. + fn rmd>(&self, path: P) -> Box + Send>; + /// Create the given directory. fn mkd>(&self, path: P) -> Box + Send>; @@ -357,6 +360,14 @@ impl StorageBackend for Filesystem { Box::new(tokio::fs::remove_file(full_path).map_err(|_| Error::IOError)) } + fn rmd>(&self, path: P) -> Box + Send> { + let full_path = match self.full_path(path) { + Ok(path) => path, + Err(e) => return Box::new(future::err(e)), + }; + Box::new(tokio::fs::remove_dir(full_path).map_err(|_| Error::IOError)) + } + fn mkd>(&self, path: P) -> Box + Send> { let full_path = match self.full_path(path) { Ok(path) => path, From eea14c9f5b185eb10a5b05095e69c24b97b2e41d Mon Sep 17 00:00:00 2001 From: omikuji Date: Tue, 4 Jun 2019 11:43:54 +0900 Subject: [PATCH 2/2] fix format --- src/commands.rs | 23 ++++++++++++++++------- src/server.rs | 34 ++++++++++++++++++++++++---------- 2 files changed, 40 insertions(+), 17 deletions(-) diff --git a/src/commands.rs b/src/commands.rs index 9121d0b..575fea6 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -354,17 +354,16 @@ impl Command { let path = String::from_utf8_lossy(&path).to_string(); Command::Dele { path } - }, + } b"RMD" | b"rmd" => { let path = parse_to_eol(cmd_params)?; if path.is_empty() { - return Err(ParseErrorKind::InvalidCommand)? + return Err(ParseErrorKind::InvalidCommand)?; } let path = String::from_utf8_lossy(&path).to_string(); - Command::Rmd{ path } - - }, + Command::Rmd { path } + } b"QUIT" | b"quit" => { let params = parse_to_eol(cmd_params)?; if !params.is_empty() { @@ -1010,10 +1009,20 @@ mod tests { #[test] fn parse_rmd() { let input = "RMD\r\n"; - assert_eq!(Command::parse(input), Err(ParseError{inner: Context::new(ParseErrorKind::InvalidCommand)})); + assert_eq!( + Command::parse(input), + Err(ParseError { + inner: Context::new(ParseErrorKind::InvalidCommand) + }) + ); let input = "RMD some_directory\r\n"; - assert_eq!(Command::parse(input), Ok(Command::Rmd{path: "some_directory".into()})); + assert_eq!( + Command::parse(input), + Ok(Command::Rmd { + path: "some_directory".into() + }) + ); } #[test] diff --git a/src/server.rs b/src/server.rs index 6bd97be..dd2a3d2 100644 --- a/src/server.rs +++ b/src/server.rs @@ -1024,31 +1024,45 @@ where }), ); Ok(Reply::none()) - }, - Command::Rmd{path} => { + } + Command::Rmd { path } => { ensure_authenticated!(); let session = session.lock()?; let storage = Arc::clone(&session.storage); let tx_success = tx.clone(); let tx_fail = tx.clone(); tokio::spawn( - storage.rmd(path) - .map_err(|_| std::io::Error::new(ErrorKind::Other, "Failed to delete directory")) + storage + .rmd(path) + .map_err(|_| { + std::io::Error::new( + ErrorKind::Other, + "Failed to delete directory", + ) + }) .and_then(|_| { - tx_success.send(InternalMsg::DelSuccess) - .map_err(|_| std::io::Error::new(ErrorKind::Other, "Failed to send 'DelSuccess' to data channel")) + tx_success.send(InternalMsg::DelSuccess).map_err(|_| { + std::io::Error::new( + ErrorKind::Other, + "Failed to send 'DelSuccess' to data channel", + ) + }) }) .or_else(|_| { - tx_fail.send(InternalMsg::DelFail) - .map_err(|_| std::io::Error::new(ErrorKind::Other, "Failed to send 'DelFail' to data channel")) + tx_fail.send(InternalMsg::DelFail).map_err(|_| { + std::io::Error::new( + ErrorKind::Other, + "Failed to send 'DelFail' to data channel", + ) + }) }) .map(|_| ()) .map_err(|e| { warn!("Failed to delete directory: {}", e); - }) + }), ); Ok(Reply::none()) - }, + } Command::Quit => { let tx = tx.clone(); spawn!(tx.send(InternalMsg::Quit));