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