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