Skip to content
Merged
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
91 changes: 84 additions & 7 deletions executables/shell/command_line/src/commands/directory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@ use alloc::borrow::ToOwned;
use executable_macros::GetArgs;
use getargs::Options;
use xila::{
file_system::Path,
file_system::{Kind, Path},
virtual_file_system::{self, Directory},
};

use super::{CommandContext, UserCommand};

pub struct CreateDirectoryCommand;
pub struct RemoveCommand;
pub struct RemoveFileCommand;
pub struct RemoveDirectoryCommand;

impl UserCommand for CreateDirectoryCommand {
async fn execute<'a, I, C>(
Expand All @@ -27,7 +28,7 @@ impl UserCommand for CreateDirectoryCommand {
}
}

impl UserCommand for RemoveCommand {
impl UserCommand for RemoveFileCommand {
async fn execute<'a, I, C>(
&self,
context: &mut C,
Expand All @@ -38,7 +39,22 @@ impl UserCommand for RemoveCommand {
I: Iterator<Item = &'a str>,
C: CommandContext,
{
execute_remove(context, options).await
execute_remove_file(context, options).await
}
}

impl UserCommand for RemoveDirectoryCommand {
async fn execute<'a, I, C>(
&self,
context: &mut C,
options: &mut Options<&'a str, I>,
_paths: &[&Path],
) -> Result<()>
where
I: Iterator<Item = &'a str>,
C: CommandContext,
{
execute_remove_directory(context, options).await
}
}

Expand Down Expand Up @@ -73,6 +89,14 @@ fn resolve_path<C: CommandContext>(
}
}

fn can_remove_with_rm(kind: Kind) -> bool {
kind != Kind::Directory
}

fn can_remove_with_rmdir(kind: Kind) -> bool {
kind == Kind::Directory
}

async fn execute_create_directory<'a, I, C>(
context: &mut C,
options: &mut Options<&'a str, I>,
Expand All @@ -94,15 +118,52 @@ where
.map_err(Error::FailedToCreateDirectory)
}

async fn execute_remove<'a, I, C>(context: &mut C, options: &mut Options<&'a str, I>) -> Result<()>
async fn execute_remove_file<'a, I, C>(
context: &mut C,
options: &mut Options<&'a str, I>,
) -> Result<()>
where
I: Iterator<Item = &'a str>,
C: CommandContext,
{
let DirectoryRemoveArguments { path } = DirectoryRemoveArguments::parse(options)?;
let path = resolve_path(context, path)?;

let statistics = virtual_file_system::get_instance()
.get_statistics(&path)
.await
.map_err(Error::FailedToGetMetadata)?;

if !can_remove_with_rm(statistics.kind) {
return Err(Error::InvalidArgument);
}

virtual_file_system::get_instance()
.remove(context.task_id(), &path)
.await
.map_err(Error::FailedToRemoveDirectory)
}

async fn execute_remove_directory<'a, I, C>(
context: &mut C,
options: &mut Options<&'a str, I>,
) -> Result<()>
where
I: Iterator<Item = &'a str>,
C: CommandContext,
{
let DirectoryRemoveArguments { path } = DirectoryRemoveArguments::parse(options)?;
let path = resolve_path(context, path)?;

let statistics = virtual_file_system::get_instance()
.get_statistics(&path)
.await
.map_err(Error::FailedToGetMetadata)?;

if !can_remove_with_rmdir(statistics.kind) {
return Err(Error::InvalidArgument);
}

virtual_file_system::get_instance()
.remove(context.task_id(), &path)
.await
Expand All @@ -111,13 +172,13 @@ where

#[cfg(test)]
mod tests {
use super::resolve_path;
use super::{can_remove_with_rm, can_remove_with_rmdir, resolve_path};
use crate::{Error, Result};
use alloc::borrow::ToOwned;
use core::fmt;
use xila::{
executable::Standard,
file_system::{Path, PathOwned},
file_system::{Kind, Path, PathOwned},
task::TaskIdentifier,
};

Expand Down Expand Up @@ -185,4 +246,20 @@ mod tests {

assert!(matches!(result, Err(Error::InvalidPath)));
}

#[test]
fn rm_rejects_directories() {
assert!(!can_remove_with_rm(Kind::Directory));
}

#[test]
fn rm_accepts_files() {
assert!(can_remove_with_rm(Kind::File));
}

#[test]
fn rmdir_accepts_directories_only() {
assert!(can_remove_with_rmdir(Kind::Directory));
assert!(!can_remove_with_rmdir(Kind::File));
}
}
21 changes: 16 additions & 5 deletions executables/shell/command_line/src/commands/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ use self::{
change_directory::ChangeDirectoryCommand,
clear::ClearCommand,
concatenate::ConcatenateCommand,
directory::{CreateDirectoryCommand, RemoveCommand},
directory::{CreateDirectoryCommand, RemoveDirectoryCommand, RemoveFileCommand},
dns::DnsResolveCommand,
echo::EchoCommand,
environment_variables::{
Expand Down Expand Up @@ -87,7 +87,8 @@ pub enum UserCommandKind {
CreateDirectory,
SetEnvironmentVariable,
RemoveEnvironmentVariable,
Remove,
RemoveFile,
RemoveDirectory,
WebRequest,
DnsResolve,
Ping,
Expand All @@ -112,7 +113,8 @@ pub fn resolve_user_command(name: &str) -> Option<UserCommandKind> {
"mkdir" => Some(UserCommandKind::CreateDirectory),
"export" => Some(UserCommandKind::SetEnvironmentVariable),
"unset" => Some(UserCommandKind::RemoveEnvironmentVariable),
"rm" => Some(UserCommandKind::Remove),
"rm" => Some(UserCommandKind::RemoveFile),
"rmdir" => Some(UserCommandKind::RemoveDirectory),
"web_request" => Some(UserCommandKind::WebRequest),
"dns_resolve" => Some(UserCommandKind::DnsResolve),
"ping" => Some(UserCommandKind::Ping),
Expand Down Expand Up @@ -164,7 +166,12 @@ where
.execute(context, options, paths)
.await
}
UserCommandKind::Remove => RemoveCommand.execute(context, options, paths).await,
UserCommandKind::RemoveFile => RemoveFileCommand.execute(context, options, paths).await,
UserCommandKind::RemoveDirectory => {
RemoveDirectoryCommand
.execute(context, options, paths)
.await
}
UserCommandKind::WebRequest => WebRequestCommand.execute(context, options, paths).await,
UserCommandKind::DnsResolve => DnsResolveCommand.execute(context, options, paths).await,
UserCommandKind::Ping => PingCommand.execute(context, options, paths).await,
Expand Down Expand Up @@ -245,7 +252,11 @@ mod tests {
));
assert!(matches!(
resolve_user_command("rm"),
Some(UserCommandKind::Remove)
Some(UserCommandKind::RemoveFile)
));
assert!(matches!(
resolve_user_command("rmdir"),
Some(UserCommandKind::RemoveDirectory)
));
assert!(matches!(
resolve_user_command("web_request"),
Expand Down
Loading