xref: /NovaShell/src/shell/command/mod.rs (revision 4160a0a0de9055be382715fac34b66ac9b15cd74)
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 mut path = String::new();
248         if args.len() == 0 {
249             path = self.current_dir();
250         }
251         if args.len() == 1 {
252             path = args.get(0).unwrap().clone();
253             match self.is_dir(&path) {
254                 Ok(str) => path = str,
255                 Err(e) => return Err(e),
256             }
257         }
258 
259         if path.is_empty() {
260             return Err(CommandError::WrongArgumentCount(args.len()));
261         }
262 
263         let dir: fs::ReadDir;
264         match fs::read_dir(Path::new(&path)) {
265             Ok(readdir) => dir = readdir,
266             Err(_) => return Err(CommandError::InvalidArgument(path)),
267         }
268         for entry in dir {
269             let entry = entry.unwrap();
270             if entry.file_type().unwrap().is_dir() {
271                 crate::shell::Printer::print_color(
272                     entry.file_name().as_bytes(),
273                     0x000088ff,
274                     0x00000000,
275                 );
276                 print!("    ");
277             } else {
278                 print!("{}    ", entry.file_name().into_string().unwrap());
279             }
280         }
281         println!();
282         return Ok(());
283     }
284 
285     fn shell_cmd_cat(&self, args: &Vec<String>) -> Result<(), CommandError> {
286         if args.len() > 0 {
287             let mut path = args.get(0).unwrap().clone();
288             let mut buf: Vec<u8> = Vec::new();
289 
290             match self.is_file(&path) {
291                 Ok(str) => path = str,
292                 Err(e) => return Err(e),
293             }
294 
295             File::open(path).unwrap().read_to_end(&mut buf).unwrap();
296             if args.len() == 1 {
297                 println!("{}", String::from_utf8(buf.clone()).unwrap());
298             }
299 
300             if args.len() == 3 {
301                 let mut target_path = args.get(2).unwrap().clone();
302                 match self.is_file(&target_path) {
303                     Ok(str) => target_path = str,
304                     Err(e) => return Err(e),
305                 }
306 
307                 if args[1] == ">" {
308                     match OpenOptions::new().write(true).open(target_path) {
309                         Ok(mut file) => {
310                             file.write_all(&buf).unwrap();
311                         }
312                         Err(e) => print!("{e}"),
313                     }
314                 } else if args[1] == ">>" {
315                     match OpenOptions::new().append(true).open(target_path) {
316                         Ok(mut file) => {
317                             file.write_all(&buf).unwrap();
318                         }
319                         Err(e) => print!("{e}"),
320                     }
321                 }
322             }
323             return Ok(());
324         }
325         return Err(CommandError::WrongArgumentCount(args.len()));
326     }
327 
328     fn shell_cmd_touch(&self, args: &Vec<String>) -> Result<(), CommandError> {
329         if args.len() == 1 {
330             let mut path = args.get(0).unwrap().clone();
331             match self.is_file(&path) {
332                 Ok(str) => path = str,
333                 Err(e) => return Err(e),
334             }
335             File::open(path).unwrap();
336             return Ok(());
337         }
338         return Err(CommandError::WrongArgumentCount(args.len()));
339     }
340 
341     fn shell_cmd_mkdir(&self, args: &Vec<String>) -> Result<(), CommandError> {
342         if args.len() == 1 {
343             let path = args.get(0).unwrap();
344             match fs::create_dir_all(path) {
345                 Ok(_) => {}
346                 Err(e) => {
347                     print!("{e}")
348                 }
349             }
350             return Ok(());
351         } else {
352             return Err(CommandError::WrongArgumentCount(args.len()));
353         }
354     }
355 
356     fn shell_cmd_rm(&self, args: &Vec<String>) -> Result<(), CommandError> {
357         if args.len() == 1 {
358             let mut path = args.get(0).unwrap().clone();
359             // match fs::remove_file(path) {
360             //     Ok(_) => {}
361             //     Err(e) => {
362             //         print!("{e}")
363             //     }
364             // }
365 
366             match self.is_file(&path) {
367                 Ok(str) => path = str,
368                 Err(e) => return Err(e),
369             }
370 
371             let path_cstr = std::ffi::CString::new(path.clone()).unwrap();
372             unsafe {
373                 libc::syscall(libc::SYS_unlinkat, 0, path_cstr.as_ptr(), 0, 0, 0, 0);
374             }
375             return Ok(());
376         }
377         return Err(CommandError::WrongArgumentCount(args.len()));
378     }
379 
380     fn shell_cmd_rmdir(&self, args: &Vec<String>) -> Result<(), CommandError> {
381         if args.len() == 1 {
382             let mut path = args.get(0).unwrap().clone();
383             match self.is_dir(&path) {
384                 Ok(str) => path = str,
385                 Err(e) => return Err(e),
386             }
387 
388             let path_cstr = std::ffi::CString::new(path).unwrap();
389             unsafe { libc::unlinkat(0, path_cstr.as_ptr(), libc::AT_REMOVEDIR) };
390             return Ok(());
391         }
392         return Err(CommandError::WrongArgumentCount(args.len()));
393     }
394 
395     fn shell_cmd_pwd(&self, args: &Vec<String>) -> Result<(), CommandError> {
396         if args.len() == 0 {
397             println!("{}", self.current_dir());
398             return Ok(());
399         }
400         return Err(CommandError::WrongArgumentCount(args.len()));
401     }
402 
403     fn shell_cmd_cp(&self, args: &Vec<String>) -> Result<(), CommandError> {
404         if args.len() == 2 {
405             let mut src_path = args.get(0).unwrap().clone();
406             let mut target_path = args.get(1).unwrap().clone();
407 
408             match self.is_file(&src_path) {
409                 Ok(str) => src_path = str,
410                 Err(e) => return Err(e),
411             }
412 
413             match self.is_file_or_dir(&target_path) {
414                 Ok(str) => target_path = str,
415                 Err(e) => {
416                     let prefix = &target_path[..target_path.rfind('/').unwrap_or(0)];
417                     if !Path::new(prefix).is_dir() {
418                         return Err(e);
419                     }
420                 }
421             }
422 
423             if Path::new(&src_path).is_dir() {
424                 let name = &src_path[src_path.rfind('/').unwrap_or(0)..];
425                 target_path = format!("{}/{}", target_path, name);
426             }
427 
428             let mut src_file = File::open(&src_path).unwrap();
429             let mut target_file = File::create(target_path).unwrap();
430             let mut buf: Vec<u8> = Vec::new();
431             src_file.read_to_end(&mut buf).unwrap();
432             target_file.write_all(&buf).unwrap();
433             return Ok(());
434         }
435         return Err(CommandError::WrongArgumentCount(args.len()));
436     }
437 
438     pub fn shell_cmd_exec(&self, args: &Vec<String>) -> Result<(), CommandError> {
439         // println!("shell_cmd_exec: {:?}", args);
440         let mut args = args.clone();
441         if args.len() <= 0 {
442             return Err(CommandError::WrongArgumentCount(args.len()));
443         }
444         let path = args.get(0).unwrap();
445         let mut real_path = String::new();
446         if !path.contains('/') {
447             let mut dir_collection = Env::path();
448             dir_collection.insert(0, self.current_dir());
449             for dir in dir_collection {
450                 let possible_path = format!("{}/{}", dir, path);
451                 if Path::new(&possible_path).is_file() {
452                     real_path = possible_path;
453                     break;
454                 }
455             }
456             if real_path.is_empty() {
457                 return Err(CommandError::FileNotFound(path.clone()));
458             }
459         } else {
460             match self.is_file(path) {
461                 Ok(path) => real_path = path,
462                 Err(e) => return Err(e),
463             }
464         }
465 
466         // 如果文件不存在,返回错误
467         if !Path::new(&real_path).is_file() {
468             // println!("{}: command not found", real_path);
469             return Err(CommandError::FileNotFound(real_path.clone()));
470         }
471 
472         let pid: libc::pid_t = unsafe {
473             libc::syscall(libc::SYS_fork, 0, 0, 0, 0, 0, 0)
474                 .try_into()
475                 .unwrap()
476         };
477 
478         let name = &real_path[real_path.rfind('/').map(|pos| pos + 1).unwrap_or(0)..];
479         *args.get_mut(0).unwrap() = name.to_string();
480         let mut retval = 0;
481         if pid == 0 {
482             let path_cstr = std::ffi::CString::new(real_path).unwrap();
483             let args_cstr = args
484                 .iter()
485                 .map(|str| std::ffi::CString::new(str.as_str()).unwrap())
486                 .collect::<Vec<std::ffi::CString>>();
487             let mut args_ptr = args_cstr
488                 .iter()
489                 .map(|c_str| c_str.as_ptr())
490                 .collect::<Vec<*const i8>>();
491             args_ptr.push(std::ptr::null());
492             let argv = args_ptr.as_ptr();
493 
494             unsafe {
495                 libc::execv(path_cstr.as_ptr(), argv);
496             }
497         } else {
498             if args.last().unwrap() != &"&" {
499                 unsafe { libc::waitpid(pid, &mut retval as *mut i32, 0) };
500             } else {
501                 println!("[1] {}", pid);
502             }
503         }
504         return Ok(());
505     }
506 
507     fn shell_cmd_echo(&self, args: &Vec<String>) -> Result<(), CommandError> {
508         if args.len() > 0 {
509             let str = args.get(0).unwrap();
510             if args.len() == 1 {
511                 println!("{str}");
512             }
513 
514             if args.len() == 3 {
515                 let mut target_path = args.get(2).unwrap().clone();
516                 match self.is_file(&target_path) {
517                     Ok(str) => target_path = str,
518                     Err(e) => return Err(e),
519                 }
520 
521                 if args[1] == ">" {
522                     match OpenOptions::new().write(true).open(target_path) {
523                         Ok(mut file) => {
524                             file.write_all(str.as_bytes()).unwrap();
525                         }
526                         Err(e) => print!("{e}"),
527                     }
528                 } else if args[1] == ">>" {
529                     match OpenOptions::new().append(true).open(target_path) {
530                         Ok(mut file) => {
531                             file.write_all(str.as_bytes()).unwrap();
532                         }
533                         Err(e) => print!("{e}"),
534                     }
535                 }
536             }
537             return Ok(());
538         }
539         return Err(CommandError::WrongArgumentCount(args.len()));
540     }
541 
542     fn shell_cmd_reboot(&self, args: &Vec<String>) -> Result<(), CommandError> {
543         if args.len() == 0 {
544             unsafe { libc::syscall(libc::SYS_reboot, 0, 0, 0, 0, 0, 0) };
545             return Ok(());
546         } else {
547             return Err(CommandError::WrongArgumentCount(args.len()));
548         }
549     }
550 
551     fn shell_cmd_free(&self, args: &Vec<String>) -> Result<(), CommandError> {
552         if args.len() == 1 && args.get(0).unwrap() != "-m" {
553             return Err(CommandError::InvalidArgument(
554                 args.get(0).unwrap().to_string(),
555             ));
556         }
557 
558         struct Mstat {
559             total: u64,      // 计算机的总内存数量大小
560             used: u64,       // 已使用的内存大小
561             free: u64,       // 空闲物理页所占的内存大小
562             shared: u64,     // 共享的内存大小
563             cache_used: u64, // 位于slab缓冲区中的已使用的内存大小
564             cache_free: u64, // 位于slab缓冲区中的空闲的内存大小
565             available: u64,  // 系统总空闲内存大小(包括kmalloc缓冲区)
566         }
567 
568         let mut mst = Mstat {
569             total: 0,
570             used: 0,
571             free: 0,
572             shared: 0,
573             cache_used: 0,
574             cache_free: 0,
575             available: 0,
576         };
577 
578         let mut info_file = File::open("/proc/meminfo").unwrap();
579         let mut buf: Vec<u8> = Vec::new();
580         info_file.read_to_end(&mut buf).unwrap();
581         let str = String::from_utf8(buf).unwrap();
582         let info = str
583             .split(&['\n', '\t', ' '])
584             .filter_map(|str| str.parse::<u64>().ok())
585             .collect::<Vec<u64>>();
586         mst.total = *info.get(0).unwrap();
587         mst.free = *info.get(1).unwrap();
588         mst.used = mst.total - mst.free;
589 
590         print!("\ttotal\t\tused\t\tfree\t\tshared\t\tcache_used\tcache_free\tavailable\n");
591         print!("Mem:\t");
592 
593         if args.len() == 0 {
594             print!(
595                 "{}\t\t{}\t\t{}\t\t{}\t\t{}\t\t{}\t\t{}\n",
596                 mst.total,
597                 mst.used,
598                 mst.free,
599                 mst.shared,
600                 mst.cache_used,
601                 mst.cache_free,
602                 mst.available
603             );
604         } else {
605             print!(
606                 "{}\t\t{}\t\t{}\t\t{}\t\t{}\t\t{}\n",
607                 mst.total >> 10,
608                 mst.used >> 10,
609                 mst.free >> 10,
610                 mst.shared >> 10,
611                 mst.cache_used >> 10,
612                 mst.available >> 10
613             );
614         }
615         Ok(())
616     }
617 
618     fn shell_cmd_kill(&self, args: &Vec<String>) -> Result<(), CommandError> {
619         if args.len() == 1 {
620             let pid: i32;
621             match args.get(0).unwrap().parse::<i32>() {
622                 Ok(x) => pid = x,
623                 Err(_) => {
624                     return Err(CommandError::InvalidArgument(
625                         args.get(0).unwrap().to_string(),
626                     ))
627                 }
628             }
629             unsafe {
630                 libc::kill(pid, libc::SIGTERM);
631             }
632             return Ok(());
633         } else {
634             return Err(CommandError::WrongArgumentCount(args.len()));
635         }
636     }
637 
638     fn shell_cmd_help(&self, args: &Vec<String>) -> Result<(), CommandError> {
639         if args.len() == 0 {
640             for BuildInCmd(cmd) in BuildInCmd::BUILD_IN_CMD {
641                 Help::shell_help(cmd)
642             }
643             return Ok(());
644         }
645         return Err(CommandError::WrongArgumentCount(args.len()));
646     }
647 
648     fn shell_cmd_export(&self, args: &Vec<String>) -> Result<(), CommandError> {
649         if args.len() == 1 {
650             let pair = args.get(0).unwrap().split('=').collect::<Vec<&str>>();
651 
652             if pair.len() == 2 && !pair.contains(&"") {
653                 let name = pair.get(0).unwrap().to_string();
654                 let value = pair.get(1).unwrap().to_string();
655                 Env::insert(name, value);
656                 return Ok(());
657             } else {
658                 return Err(CommandError::InvalidArgument(args.get(0).unwrap().clone()));
659             }
660         }
661         return Err(CommandError::WrongArgumentCount(args.len()));
662     }
663 
664     fn shell_cmd_env(&self, args: &Vec<String>) -> Result<(), CommandError> {
665         if args.len() == 0 {
666             let mut file = File::open(ENV_FILE_PATH).unwrap();
667             let mut buf: Vec<u8> = Vec::new();
668             file.read_to_end(&mut buf).unwrap();
669             println!("{}", String::from_utf8(buf).unwrap());
670             return Ok(());
671         } else {
672             return Err(CommandError::InvalidArgument(args.get(0).unwrap().clone()));
673         }
674     }
675 
676     fn shell_cmd_compgen(&self, _args: &Vec<String>) -> Result<(), CommandError> {
677         Ok(())
678     }
679 
680     fn shell_cmd_complete(&self, _args: &Vec<String>) -> Result<(), CommandError> {
681         Ok(())
682     }
683 
684     fn path_format(&self, path: &String) -> Result<String, CommandError> {
685         let mut abs_path = path.clone();
686         if !path.starts_with('/') {
687             abs_path = format!("{}/{}", self.current_dir(), path);
688         }
689         if let Ok(path) = Path::new(&abs_path).canonicalize() {
690             let mut fmt_path = path.to_str().unwrap().to_string();
691             let replacement = |_caps: &regex::Captures| -> String { String::from("/") };
692             let re = regex::Regex::new(r"\/{2,}").unwrap();
693             fmt_path = re.replace_all(fmt_path.as_str(), replacement).to_string();
694             return Ok(fmt_path);
695         } else {
696             return Err(CommandError::PathNotFound(path.clone()));
697         }
698     }
699 
700     fn is_file(&self, path_str: &String) -> Result<String, CommandError> {
701         match self.path_format(path_str) {
702             Ok(path_str) => {
703                 let path = Path::new(&path_str);
704                 if !path.is_file() {
705                     return Err(CommandError::NotFile(path_str.clone()));
706                 };
707                 Ok(path_str)
708             }
709             Err(_) => Err(CommandError::FileNotFound(path_str.clone())),
710         }
711     }
712 
713     fn is_dir(&self, path_str: &String) -> Result<String, CommandError> {
714         match self.path_format(path_str) {
715             Ok(path_str) => {
716                 let path = Path::new(&path_str);
717                 if !path.is_dir() {
718                     return Err(CommandError::NotDirectory(path_str.clone()));
719                 };
720                 Ok(path_str)
721             }
722             Err(_) => Err(CommandError::DirectoryNotFound(path_str.clone())),
723         }
724     }
725 
726     fn is_file_or_dir(&self, path_str: &String) -> Result<String, CommandError> {
727         match self.path_format(path_str) {
728             Ok(path_str) => Ok(path_str),
729             Err(_) => Err(CommandError::PathNotFound(path_str.clone())),
730         }
731     }
732 }
733