xref: /NovaShell/src/shell/command/mod.rs (revision 6537b36977cef705c78c1800d561b0d464bc0dc0)
1 use help::Help;
2 use regex::{Captures, Regex};
3 use std::io::Read;
4 use std::os::unix::ffi::OsStrExt;
5 use std::{
6     format,
7     fs::{self, File, OpenOptions},
8     io::Write,
9     path::Path,
10     print, println,
11     string::String,
12     vec::Vec,
13 };
14 
15 use crate::shell::Shell;
16 use crate::ROOT_PATH;
17 use crate::{Env, ENV_FILE_PATH};
18 
19 mod help;
20 
21 #[derive(Debug, PartialEq, Eq, Clone)]
22 enum CommandType {
23     InternalCommand(BuildInCmd),
24     ExternalCommand(String),
25 }
26 
27 #[derive(Debug, PartialEq, Eq, Clone)]
28 pub struct Command {
29     args: Vec<String>,
30     cmd_type: CommandType,
31 }
32 
33 #[derive(Debug, PartialEq, Eq, Clone)]
34 pub enum CommandError {
35     CommandNotFound(String),
36     InvalidArgument(String),
37     WrongArgumentCount(usize),
38     EnvironmentVariableNotFound(String),
39     PathNotFound(String),
40     FileNotFound(String),
41     DirectoryNotFound(String),
42     NotDirectory(String),
43     NotFile(String),
44 }
45 
46 impl CommandError {
47     pub fn handle(e: CommandError) {
48         match e {
49             CommandError::CommandNotFound(command) => {
50                 println!("cannot find command: {}", command)
51             }
52             CommandError::InvalidArgument(argument) => {
53                 println!("invalid argument: {}", argument)
54             }
55             CommandError::WrongArgumentCount(count) => {
56                 println!("argument count incorrect: {}", count)
57             }
58             CommandError::EnvironmentVariableNotFound(env) => {
59                 println!("environment variable not found: {}", env);
60             }
61             CommandError::PathNotFound(path) => {
62                 println!("cannot found file or dirctory: {}", path)
63             }
64             CommandError::FileNotFound(path) => {
65                 println!("cannot found file: {}", path)
66             }
67             CommandError::DirectoryNotFound(path) => {
68                 println!("cannot found dirctory: {}", path)
69             }
70             CommandError::NotDirectory(path) => {
71                 println!("path is not a dirctory: {}", path)
72             }
73             CommandError::NotFile(path) => {
74                 println!("path is not a file: {}", path)
75             }
76         };
77     }
78 }
79 
80 impl Command {
81     fn new(name: String, args: Vec<String>) -> Result<Command, CommandError> {
82         for BuildInCmd(cmd) in BuildInCmd::BUILD_IN_CMD {
83             if name == *cmd {
84                 return Ok(Command {
85                     args,
86                     cmd_type: CommandType::InternalCommand(BuildInCmd(cmd)),
87                 });
88             }
89         }
90 
91         return Ok(Command {
92             args,
93             cmd_type: CommandType::ExternalCommand(name),
94         });
95     }
96 
97     fn from_string(str: String) -> Result<Command, CommandError> {
98         let regex: Regex = Regex::new(r#"([^\s'"]|("[^"]*"|'[^']*'))+"#).unwrap();
99         let hay = str.clone();
100         let mut iter = regex
101             .captures_iter(hay.as_str())
102             .map(|c| String::from(c.get(0).unwrap().as_str()));
103         // let mut iter = str.split_ascii_whitespace();
104         let name = iter.next().unwrap();
105         let re: Regex = Regex::new(r"\$[\w_]+").unwrap();
106         let replacement = |caps: &Captures| -> String {
107             match Env::get(&String::from(&caps[0][1..])) {
108                 Some(value) => value,
109                 None => String::from(&caps[0]),
110             }
111         };
112         let mut args: Vec<String> = Vec::new();
113         for arg in iter.collect::<Vec<String>>().iter() {
114             let arg = re.replace_all(arg.as_str(), &replacement).to_string();
115             match re.captures(arg.as_str()) {
116                 Some(caps) => {
117                     return Err(CommandError::EnvironmentVariableNotFound(String::from(
118                         caps.get(0).unwrap().as_str(),
119                     )))
120                 }
121                 None => args.push(arg),
122             }
123         }
124         let cmd = Command::new(name, args);
125         return cmd;
126     }
127 
128     pub fn from_strings(str: String) -> Vec<Command> {
129         str.split(';')
130             .filter_map(|s| match Command::from_string(String::from(s)) {
131                 Ok(s) => Some(s),
132                 Err(e) => {
133                     CommandError::handle(e);
134                     None
135                 }
136             })
137             .collect::<Vec<Command>>()
138     }
139 }
140 
141 #[derive(Debug, PartialEq, Eq, Clone)]
142 pub struct BuildInCmd(pub &'static str);
143 
144 impl BuildInCmd {
145     pub const BUILD_IN_CMD: &[BuildInCmd] = &[
146         BuildInCmd("cd"),
147         BuildInCmd("ls"),
148         BuildInCmd("cat"),
149         BuildInCmd("touch"),
150         BuildInCmd("mkdir"),
151         BuildInCmd("rm"),
152         BuildInCmd("rmdir"),
153         BuildInCmd("pwd"),
154         BuildInCmd("cp"),
155         BuildInCmd("exec"),
156         BuildInCmd("echo"),
157         BuildInCmd("reboot"),
158         BuildInCmd("free"),
159         BuildInCmd("kill"),
160         BuildInCmd("help"),
161         BuildInCmd("export"),
162         BuildInCmd("env"),
163         BuildInCmd("compgen"),
164         BuildInCmd("complete"),
165     ];
166 }
167 
168 impl Shell {
169     pub fn exec_internal_command(
170         &mut self,
171         cmd: &str,
172         args: &Vec<String>,
173     ) -> Result<(), CommandError> {
174         match cmd {
175             "cd" => self.shell_cmd_cd(args),
176             "ls" => self.shell_cmd_ls(args),
177             "cat" => self.shell_cmd_cat(args),
178             "touch" => self.shell_cmd_touch(args),
179             "mkdir" => self.shell_cmd_mkdir(args),
180             "rm" => self.shell_cmd_rm(args),
181             "rmdir" => self.shell_cmd_rmdir(args),
182             "pwd" => self.shell_cmd_pwd(args),
183             "cp" => self.shell_cmd_cp(args),
184             "exec" => self.shell_cmd_exec(args),
185             "echo" => self.shell_cmd_echo(args),
186             "reboot" => self.shell_cmd_reboot(args),
187             "free" => self.shell_cmd_free(args),
188             "kill" => self.shell_cmd_kill(args),
189             "help" => self.shell_cmd_help(args),
190             "export" => self.shell_cmd_export(args),
191             "env" => self.shell_cmd_env(args),
192             "compgen" => self.shell_cmd_compgen(args),
193             "complete" => self.shell_cmd_complete(args),
194 
195             _ => Err(CommandError::CommandNotFound(String::from(cmd))),
196         }
197     }
198 
199     pub fn exec_external_command(&mut self, path: String, args: &Vec<String>) {
200         let mut full_args = args.clone();
201         full_args.insert(0, path.clone());
202         self.shell_cmd_exec(&full_args).unwrap_or_else(|e| {
203             let err = match e {
204                 CommandError::FileNotFound(rp) => CommandError::CommandNotFound(rp),
205                 _ => e,
206             };
207             CommandError::handle(err);
208         })
209     }
210 
211     pub fn exec_command(&mut self, command: &Command) {
212         match &command.cmd_type {
213             CommandType::ExternalCommand(path) => {
214                 self.exec_external_command(path.to_string(), &command.args);
215             }
216 
217             CommandType::InternalCommand(BuildInCmd(cmd)) => {
218                 match self.exec_internal_command(cmd, &command.args) {
219                     Ok(_) => {}
220                     Err(e) => CommandError::handle(e),
221                 }
222                 if command.args.contains(&String::from("--help")) {
223                     Help::shell_help(cmd);
224                 }
225             }
226         }
227     }
228 
229     fn shell_cmd_cd(&mut self, args: &Vec<String>) -> Result<(), CommandError> {
230         if args.len() == 0 {
231             self.set_current_dir(&String::from(ROOT_PATH));
232             return Ok(());
233         }
234         if args.len() == 1 {
235             let mut path = args.get(0).unwrap().clone();
236             match self.is_dir(&path) {
237                 Ok(str) => path = str,
238                 Err(e) => return Err(e),
239             }
240             self.set_current_dir(&path);
241             return Ok(());
242         }
243         return Err(CommandError::WrongArgumentCount(args.len()));
244     }
245 
246     fn shell_cmd_ls(&self, args: &Vec<String>) -> Result<(), CommandError> {
247         let path: String = match args.len() {
248             0 => self.current_dir(),
249             1 => match self.is_dir(args.get(0).unwrap()) {
250                 Ok(str) => str,
251                 Err(e) => return Err(e),
252             },
253             _ => return Err(CommandError::WrongArgumentCount(args.len())),
254         };
255 
256         let dir: fs::ReadDir;
257         match fs::read_dir(Path::new(&path)) {
258             Ok(readdir) => dir = readdir,
259             Err(_) => return Err(CommandError::InvalidArgument(path)),
260         }
261         for entry in dir {
262             let entry = entry.unwrap();
263             if entry.file_type().unwrap().is_dir() {
264                 crate::shell::Printer::print_color(
265                     entry.file_name().as_bytes(),
266                     0x000088ff,
267                     0x00000000,
268                 );
269                 print!("    ");
270             } else {
271                 print!("{}    ", entry.file_name().into_string().unwrap());
272             }
273         }
274         println!();
275         return Ok(());
276     }
277 
278     fn shell_cmd_cat(&self, args: &Vec<String>) -> Result<(), CommandError> {
279         if args.len() > 0 {
280             let mut path = args.get(0).unwrap().clone();
281             let mut buf: Vec<u8> = Vec::new();
282 
283             match self.is_file(&path) {
284                 Ok(str) => path = str,
285                 Err(e) => return Err(e),
286             }
287 
288             File::open(path).unwrap().read_to_end(&mut buf).unwrap();
289             if args.len() == 1 {
290                 println!("{}", String::from_utf8(buf.clone()).unwrap());
291             }
292 
293             if args.len() == 3 {
294                 let mut target_path = args.get(2).unwrap().clone();
295                 match self.is_file(&target_path) {
296                     Ok(str) => target_path = str,
297                     Err(e) => return Err(e),
298                 }
299 
300                 if args[1] == ">" {
301                     match OpenOptions::new().write(true).open(target_path) {
302                         Ok(mut file) => {
303                             file.write_all(&buf).unwrap();
304                         }
305                         Err(e) => print!("{e}"),
306                     }
307                 } else if args[1] == ">>" {
308                     match OpenOptions::new().append(true).open(target_path) {
309                         Ok(mut file) => {
310                             file.write_all(&buf).unwrap();
311                         }
312                         Err(e) => print!("{e}"),
313                     }
314                 }
315             }
316             return Ok(());
317         }
318         return Err(CommandError::WrongArgumentCount(args.len()));
319     }
320 
321     fn shell_cmd_touch(&self, args: &Vec<String>) -> Result<(), CommandError> {
322         if args.len() == 1 {
323             let mut path = args.get(0).unwrap().clone();
324             match self.is_file(&path) {
325                 Ok(str) => path = str,
326                 Err(e) => return Err(e),
327             }
328             File::open(path).unwrap();
329             return Ok(());
330         }
331         return Err(CommandError::WrongArgumentCount(args.len()));
332     }
333 
334     fn shell_cmd_mkdir(&self, args: &Vec<String>) -> Result<(), CommandError> {
335         if args.len() == 1 {
336             let path = args.get(0).unwrap();
337             match fs::create_dir_all(path) {
338                 Ok(_) => {}
339                 Err(e) => {
340                     print!("{e}")
341                 }
342             }
343             return Ok(());
344         } else {
345             return Err(CommandError::WrongArgumentCount(args.len()));
346         }
347     }
348 
349     fn shell_cmd_rm(&self, args: &Vec<String>) -> Result<(), CommandError> {
350         if args.len() == 1 {
351             let mut path = args.get(0).unwrap().clone();
352             // match fs::remove_file(path) {
353             //     Ok(_) => {}
354             //     Err(e) => {
355             //         print!("{e}")
356             //     }
357             // }
358 
359             match self.is_file(&path) {
360                 Ok(str) => path = str,
361                 Err(e) => return Err(e),
362             }
363 
364             let path_cstr = std::ffi::CString::new(path.clone()).unwrap();
365             unsafe {
366                 libc::syscall(libc::SYS_unlinkat, 0, path_cstr.as_ptr(), 0, 0, 0, 0);
367             }
368             return Ok(());
369         }
370         return Err(CommandError::WrongArgumentCount(args.len()));
371     }
372 
373     fn shell_cmd_rmdir(&self, args: &Vec<String>) -> Result<(), CommandError> {
374         if args.len() == 1 {
375             let mut path = args.get(0).unwrap().clone();
376             match self.is_dir(&path) {
377                 Ok(str) => path = str,
378                 Err(e) => return Err(e),
379             }
380 
381             let path_cstr = std::ffi::CString::new(path).unwrap();
382             unsafe { libc::unlinkat(0, path_cstr.as_ptr(), libc::AT_REMOVEDIR) };
383             return Ok(());
384         }
385         return Err(CommandError::WrongArgumentCount(args.len()));
386     }
387 
388     fn shell_cmd_pwd(&self, args: &Vec<String>) -> Result<(), CommandError> {
389         if args.len() == 0 {
390             println!("{}", self.current_dir());
391             return Ok(());
392         }
393         return Err(CommandError::WrongArgumentCount(args.len()));
394     }
395 
396     fn shell_cmd_cp(&self, args: &Vec<String>) -> Result<(), CommandError> {
397         if args.len() == 2 {
398             let mut src_path = args.get(0).unwrap().clone();
399             let mut target_path = args.get(1).unwrap().clone();
400 
401             match self.is_file(&src_path) {
402                 Ok(str) => src_path = str,
403                 Err(e) => return Err(e),
404             }
405 
406             match self.is_file_or_dir(&target_path) {
407                 Ok(str) => target_path = str,
408                 Err(e) => {
409                     let prefix = &target_path[..target_path.rfind('/').unwrap_or(0)];
410                     if !Path::new(prefix).is_dir() {
411                         return Err(e);
412                     }
413                 }
414             }
415 
416             if Path::new(&src_path).is_dir() {
417                 let name = &src_path[src_path.rfind('/').unwrap_or(0)..];
418                 target_path = format!("{}/{}", target_path, name);
419             }
420 
421             let mut src_file = File::open(&src_path).unwrap();
422             let mut target_file = File::create(target_path).unwrap();
423             let mut buf: Vec<u8> = Vec::new();
424             src_file.read_to_end(&mut buf).unwrap();
425             target_file.write_all(&buf).unwrap();
426             return Ok(());
427         }
428         return Err(CommandError::WrongArgumentCount(args.len()));
429     }
430 
431     pub fn shell_cmd_exec(&self, args: &Vec<String>) -> Result<(), CommandError> {
432         // println!("shell_cmd_exec: {:?}", args);
433         let mut args = args.clone();
434         if args.len() <= 0 {
435             return Err(CommandError::WrongArgumentCount(args.len()));
436         }
437         let path = args.get(0).unwrap();
438         let mut real_path = String::new();
439         if !path.contains('/') {
440             let mut dir_collection = Env::path();
441             dir_collection.insert(0, self.current_dir());
442             for dir in dir_collection {
443                 let possible_path = format!("{}/{}", dir, path);
444                 if Path::new(&possible_path).is_file() {
445                     real_path = possible_path;
446                     break;
447                 }
448             }
449             if real_path.is_empty() {
450                 return Err(CommandError::FileNotFound(path.clone()));
451             }
452         } else {
453             match self.is_file(path) {
454                 Ok(path) => real_path = path,
455                 Err(e) => return Err(e),
456             }
457         }
458 
459         // 如果文件不存在,返回错误
460         if !Path::new(&real_path).is_file() {
461             // println!("{}: command not found", real_path);
462             return Err(CommandError::FileNotFound(real_path.clone()));
463         }
464 
465         let pid: libc::pid_t = unsafe {
466             libc::syscall(libc::SYS_fork, 0, 0, 0, 0, 0, 0)
467                 .try_into()
468                 .unwrap()
469         };
470 
471         let name = &real_path[real_path.rfind('/').map(|pos| pos + 1).unwrap_or(0)..];
472         *args.get_mut(0).unwrap() = name.to_string();
473         let mut retval = 0;
474         if pid == 0 {
475             let path_cstr = std::ffi::CString::new(real_path).unwrap();
476             let args_cstr = args
477                 .iter()
478                 .map(|str| std::ffi::CString::new(str.as_str()).unwrap())
479                 .collect::<Vec<std::ffi::CString>>();
480             let mut args_ptr = args_cstr
481                 .iter()
482                 .map(|c_str| c_str.as_ptr())
483                 .collect::<Vec<*const i8>>();
484             args_ptr.push(std::ptr::null());
485             let argv = args_ptr.as_ptr();
486 
487             unsafe {
488                 libc::execv(path_cstr.as_ptr(), argv);
489             }
490         } else {
491             if args.last().unwrap() != &"&" {
492                 unsafe { libc::waitpid(pid, &mut retval as *mut i32, 0) };
493             } else {
494                 println!("[1] {}", pid);
495             }
496         }
497         return Ok(());
498     }
499 
500     fn shell_cmd_echo(&self, args: &Vec<String>) -> Result<(), CommandError> {
501         if args.len() > 0 {
502             let str = args.get(0).unwrap();
503             if args.len() == 1 {
504                 println!("{str}");
505             }
506 
507             if args.len() == 3 {
508                 let mut target_path = args.get(2).unwrap().clone();
509                 match self.is_file(&target_path) {
510                     Ok(str) => target_path = str,
511                     Err(e) => return Err(e),
512                 }
513 
514                 if args[1] == ">" {
515                     match OpenOptions::new().write(true).open(target_path) {
516                         Ok(mut file) => {
517                             file.write_all(str.as_bytes()).unwrap();
518                         }
519                         Err(e) => print!("{e}"),
520                     }
521                 } else if args[1] == ">>" {
522                     match OpenOptions::new().append(true).open(target_path) {
523                         Ok(mut file) => {
524                             file.write_all(str.as_bytes()).unwrap();
525                         }
526                         Err(e) => print!("{e}"),
527                     }
528                 }
529             }
530             return Ok(());
531         }
532         return Err(CommandError::WrongArgumentCount(args.len()));
533     }
534 
535     fn shell_cmd_reboot(&self, args: &Vec<String>) -> Result<(), CommandError> {
536         if args.len() == 0 {
537             unsafe { libc::syscall(libc::SYS_reboot, 0, 0, 0, 0, 0, 0) };
538             return Ok(());
539         } else {
540             return Err(CommandError::WrongArgumentCount(args.len()));
541         }
542     }
543 
544     fn shell_cmd_free(&self, args: &Vec<String>) -> Result<(), CommandError> {
545         if args.len() == 1 && args.get(0).unwrap() != "-m" {
546             return Err(CommandError::InvalidArgument(
547                 args.get(0).unwrap().to_string(),
548             ));
549         }
550 
551         struct Mstat {
552             total: u64,      // 计算机的总内存数量大小
553             used: u64,       // 已使用的内存大小
554             free: u64,       // 空闲物理页所占的内存大小
555             shared: u64,     // 共享的内存大小
556             cache_used: u64, // 位于slab缓冲区中的已使用的内存大小
557             cache_free: u64, // 位于slab缓冲区中的空闲的内存大小
558             available: u64,  // 系统总空闲内存大小(包括kmalloc缓冲区)
559         }
560 
561         let mut mst = Mstat {
562             total: 0,
563             used: 0,
564             free: 0,
565             shared: 0,
566             cache_used: 0,
567             cache_free: 0,
568             available: 0,
569         };
570 
571         let mut info_file = File::open("/proc/meminfo").unwrap();
572         let mut buf: Vec<u8> = Vec::new();
573         info_file.read_to_end(&mut buf).unwrap();
574         let str = String::from_utf8(buf).unwrap();
575         let info = str
576             .split(&['\n', '\t', ' '])
577             .filter_map(|str| str.parse::<u64>().ok())
578             .collect::<Vec<u64>>();
579         mst.total = *info.get(0).unwrap();
580         mst.free = *info.get(1).unwrap();
581         mst.used = mst.total - mst.free;
582 
583         print!("\ttotal\t\tused\t\tfree\t\tshared\t\tcache_used\tcache_free\tavailable\n");
584         print!("Mem:\t");
585 
586         if args.len() == 0 {
587             print!(
588                 "{}\t\t{}\t\t{}\t\t{}\t\t{}\t\t{}\t\t{}\n",
589                 mst.total,
590                 mst.used,
591                 mst.free,
592                 mst.shared,
593                 mst.cache_used,
594                 mst.cache_free,
595                 mst.available
596             );
597         } else {
598             print!(
599                 "{}\t\t{}\t\t{}\t\t{}\t\t{}\t\t{}\n",
600                 mst.total >> 10,
601                 mst.used >> 10,
602                 mst.free >> 10,
603                 mst.shared >> 10,
604                 mst.cache_used >> 10,
605                 mst.available >> 10
606             );
607         }
608         Ok(())
609     }
610 
611     fn shell_cmd_kill(&self, args: &Vec<String>) -> Result<(), CommandError> {
612         if args.len() == 1 {
613             let pid: i32;
614             match args.get(0).unwrap().parse::<i32>() {
615                 Ok(x) => pid = x,
616                 Err(_) => {
617                     return Err(CommandError::InvalidArgument(
618                         args.get(0).unwrap().to_string(),
619                     ))
620                 }
621             }
622             unsafe {
623                 libc::kill(pid, libc::SIGTERM);
624             }
625             return Ok(());
626         } else {
627             return Err(CommandError::WrongArgumentCount(args.len()));
628         }
629     }
630 
631     fn shell_cmd_help(&self, args: &Vec<String>) -> Result<(), CommandError> {
632         if args.len() == 0 {
633             for BuildInCmd(cmd) in BuildInCmd::BUILD_IN_CMD {
634                 Help::shell_help(cmd)
635             }
636             return Ok(());
637         }
638         return Err(CommandError::WrongArgumentCount(args.len()));
639     }
640 
641     fn shell_cmd_export(&self, args: &Vec<String>) -> Result<(), CommandError> {
642         if args.len() == 1 {
643             let pair = args.get(0).unwrap().split('=').collect::<Vec<&str>>();
644 
645             if pair.len() == 2 && !pair.contains(&"") {
646                 let name = pair.get(0).unwrap().to_string();
647                 let value = pair.get(1).unwrap().to_string();
648                 Env::insert(name, value);
649                 return Ok(());
650             } else {
651                 return Err(CommandError::InvalidArgument(args.get(0).unwrap().clone()));
652             }
653         }
654         return Err(CommandError::WrongArgumentCount(args.len()));
655     }
656 
657     fn shell_cmd_env(&self, args: &Vec<String>) -> Result<(), CommandError> {
658         if args.len() == 0 {
659             let mut file = File::open(ENV_FILE_PATH).unwrap();
660             let mut buf: Vec<u8> = Vec::new();
661             file.read_to_end(&mut buf).unwrap();
662             println!("{}", String::from_utf8(buf).unwrap());
663             return Ok(());
664         } else {
665             return Err(CommandError::InvalidArgument(args.get(0).unwrap().clone()));
666         }
667     }
668 
669     fn shell_cmd_compgen(&self, _args: &Vec<String>) -> Result<(), CommandError> {
670         Ok(())
671     }
672 
673     fn shell_cmd_complete(&self, _args: &Vec<String>) -> Result<(), CommandError> {
674         Ok(())
675     }
676 
677     fn path_format(&self, path: &String) -> Result<String, CommandError> {
678         let mut abs_path = path.clone();
679         if !path.starts_with('/') {
680             abs_path = format!("{}/{}", self.current_dir(), path);
681         }
682         if let Ok(path) = Path::new(&abs_path).canonicalize() {
683             let mut fmt_path = path.to_str().unwrap().to_string();
684             let replacement = |_caps: &regex::Captures| -> String { String::from("/") };
685             let re = regex::Regex::new(r"\/{2,}").unwrap();
686             fmt_path = re.replace_all(fmt_path.as_str(), replacement).to_string();
687             return Ok(fmt_path);
688         } else {
689             return Err(CommandError::PathNotFound(path.clone()));
690         }
691     }
692 
693     fn is_file(&self, path_str: &String) -> Result<String, CommandError> {
694         match self.path_format(path_str) {
695             Ok(path_str) => {
696                 let path = Path::new(&path_str);
697                 if !path.is_file() {
698                     return Err(CommandError::NotFile(path_str.clone()));
699                 };
700                 Ok(path_str)
701             }
702             Err(_) => Err(CommandError::FileNotFound(path_str.clone())),
703         }
704     }
705 
706     fn is_dir(&self, path_str: &String) -> Result<String, CommandError> {
707         match self.path_format(path_str) {
708             Ok(path_str) => {
709                 let path = Path::new(&path_str);
710                 if !path.is_dir() {
711                     return Err(CommandError::NotDirectory(path_str.clone()));
712                 };
713                 Ok(path_str)
714             }
715             Err(_) => Err(CommandError::DirectoryNotFound(path_str.clone())),
716         }
717     }
718 
719     fn is_file_or_dir(&self, path_str: &String) -> Result<String, CommandError> {
720         match self.path_format(path_str) {
721             Ok(path_str) => Ok(path_str),
722             Err(_) => Err(CommandError::PathNotFound(path_str.clone())),
723         }
724     }
725 }
726