Skip to content
This repository was archived by the owner on Jul 23, 2022. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions src/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -351,6 +355,15 @@ 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() {
Expand Down Expand Up @@ -993,6 +1006,25 @@ 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";
Expand Down
38 changes: 38 additions & 0 deletions src/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1025,6 +1025,44 @@ 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));
Expand Down
11 changes: 11 additions & 0 deletions src/storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,9 @@ pub trait StorageBackend {
/// Delete the given file.
fn del<P: AsRef<Path>>(&self, path: P) -> Box<Future<Item = (), Error = Self::Error> + Send>;

/// Delete the given directory.
fn rmd<P: AsRef<Path>>(&self, path: P) -> Box<Future<Item = (), Error = Self::Error> + Send>;

/// Create the given directory.
fn mkd<P: AsRef<Path>>(&self, path: P) -> Box<Future<Item = (), Error = Self::Error> + Send>;

Expand Down Expand Up @@ -357,6 +360,14 @@ impl StorageBackend for Filesystem {
Box::new(tokio::fs::remove_file(full_path).map_err(|_| Error::IOError))
}

fn rmd<P: AsRef<Path>>(&self, path: P) -> Box<Future<Item = (), Error = Self::Error> + 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<P: AsRef<Path>>(&self, path: P) -> Box<Future<Item = (), Error = Self::Error> + Send> {
let full_path = match self.full_path(path) {
Ok(path) => path,
Expand Down