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