xref: /NovaShell/src/shell/command/mod.rs (revision ca68cd1723b501f23494a5b3decf5e2dd33ed6ae)
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                 let possible_path = format!("{}/{}", dir, path);
446                 if Path::new(&path).is_file() {
447                     real_path = possible_path;
448                     break;
449                 }
450             }
451             if real_path.is_empty() {
452                 return Err(CommandError::FileNotFound(path.clone()));
453             }
454         } else {
455             match self.is_file(path) {
456                 Ok(path) => real_path = path,
457                 Err(e) => return Err(e),
458             }
459         }
460 
461         let pid: libc::pid_t = unsafe {
462             libc::syscall(libc::SYS_fork, 0, 0, 0, 0, 0, 0)
463                 .try_into()
464                 .unwrap()
465         };
466 
467         let name = &real_path[real_path.rfind('/').unwrap_or(0)..];
468         *args.get_mut(0).unwrap() = name.to_string();
469         let mut retval = 0;
470         if pid == 0 {
471             let path_cstr = std::ffi::CString::new(real_path).unwrap();
472             let args_cstr = args
473                 .iter()
474                 .map(|str| std::ffi::CString::new(str.as_str()).unwrap())
475                 .collect::<Vec<std::ffi::CString>>();
476             let mut args_ptr = args_cstr
477                 .iter()
478                 .map(|c_str| c_str.as_ptr())
479                 .collect::<Vec<*const i8>>();
480             args_ptr.push(std::ptr::null());
481             let argv = args_ptr.as_ptr();
482 
483             unsafe {
484                 libc::execv(path_cstr.as_ptr(), argv);
485             }
486         } else {
487             if args.last().unwrap() != &"&" {
488                 unsafe { libc::waitpid(pid, &mut retval as *mut i32, 0) };
489             } else {
490                 println!("[1] {}", pid);
491             }
492         }
493         return Ok(());
494     }
495 
496     fn shell_cmd_echo(&self, args: &Vec<String>) -> Result<(), CommandError> {
497         if args.len() > 0 {
498             let str = args.get(0).unwrap();
499             if args.len() == 1 {
500                 println!("{str}");
501             }
502 
503             if args.len() == 3 {
504                 let mut target_path = args.get(2).unwrap().clone();
505                 match self.is_file(&target_path) {
506                     Ok(str) => target_path = str,
507                     Err(e) => return Err(e),
508                 }
509 
510                 if args[1] == ">" {
511                     match OpenOptions::new().write(true).open(target_path) {
512                         Ok(mut file) => {
513                             file.write_all(str.as_bytes()).unwrap();
514                         }
515                         Err(e) => print!("{e}"),
516                     }
517                 } else if args[1] == ">>" {
518                     match OpenOptions::new().append(true).open(target_path) {
519                         Ok(mut file) => {
520                             file.write_all(str.as_bytes()).unwrap();
521                         }
522                         Err(e) => print!("{e}"),
523                     }
524                 }
525             }
526             return Ok(());
527         }
528         return Err(CommandError::WrongArgumentCount(args.len()));
529     }
530 
531     fn shell_cmd_reboot(&self, args: &Vec<String>) -> Result<(), CommandError> {
532         if args.len() == 0 {
533             unsafe { libc::syscall(libc::SYS_reboot, 0, 0, 0, 0, 0, 0) };
534             return Ok(());
535         } else {
536             return Err(CommandError::WrongArgumentCount(args.len()));
537         }
538     }
539 
540     fn shell_cmd_free(&self, args: &Vec<String>) -> Result<(), CommandError> {
541         if args.len() == 1 && args.get(0).unwrap() != "-m" {
542             return Err(CommandError::InvalidArgument(
543                 args.get(0).unwrap().to_string(),
544             ));
545         }
546 
547         struct Mstat {
548             total: u64,      // 计算机的总内存数量大小
549             used: u64,       // 已使用的内存大小
550             free: u64,       // 空闲物理页所占的内存大小
551             shared: u64,     // 共享的内存大小
552             cache_used: u64, // 位于slab缓冲区中的已使用的内存大小
553             cache_free: u64, // 位于slab缓冲区中的空闲的内存大小
554             available: u64,  // 系统总空闲内存大小(包括kmalloc缓冲区)
555         }
556 
557         let mut mst = Mstat {
558             total: 0,
559             used: 0,
560             free: 0,
561             shared: 0,
562             cache_used: 0,
563             cache_free: 0,
564             available: 0,
565         };
566 
567         let mut info_file = File::open("/proc/meminfo").unwrap();
568         let mut buf: Vec<u8> = Vec::new();
569         info_file.read_to_end(&mut buf).unwrap();
570         let str = String::from_utf8(buf).unwrap();
571         let info = str
572             .split(&['\n', '\t', ' '])
573             .filter_map(|str| str.parse::<u64>().ok())
574             .collect::<Vec<u64>>();
575         mst.total = *info.get(0).unwrap();
576         mst.free = *info.get(1).unwrap();
577         mst.used = mst.total - mst.free;
578 
579         print!("\ttotal\t\tused\t\tfree\t\tshared\t\tcache_used\tcache_free\tavailable\n");
580         print!("Mem:\t");
581 
582         if args.len() == 0 {
583             print!(
584                 "{}\t\t{}\t\t{}\t\t{}\t\t{}\t\t{}\t\t{}\n",
585                 mst.total,
586                 mst.used,
587                 mst.free,
588                 mst.shared,
589                 mst.cache_used,
590                 mst.cache_free,
591                 mst.available
592             );
593         } else {
594             print!(
595                 "{}\t\t{}\t\t{}\t\t{}\t\t{}\t\t{}\n",
596                 mst.total >> 10,
597                 mst.used >> 10,
598                 mst.free >> 10,
599                 mst.shared >> 10,
600                 mst.cache_used >> 10,
601                 mst.available >> 10
602             );
603         }
604         Ok(())
605     }
606 
607     fn shell_cmd_kill(&self, args: &Vec<String>) -> Result<(), CommandError> {
608         if args.len() == 1 {
609             let pid: i32;
610             match args.get(0).unwrap().parse::<i32>() {
611                 Ok(x) => pid = x,
612                 Err(_) => {
613                     return Err(CommandError::InvalidArgument(
614                         args.get(0).unwrap().to_string(),
615                     ))
616                 }
617             }
618             unsafe {
619                 libc::kill(pid, libc::SIGKILL);
620             }
621             return Ok(());
622         } else {
623             return Err(CommandError::WrongArgumentCount(args.len()));
624         }
625     }
626 
627     fn shell_cmd_help(&self, args: &Vec<String>) -> Result<(), CommandError> {
628         if args.len() == 0 {
629             for BuildInCmd(cmd) in BuildInCmd::BUILD_IN_CMD {
630                 Help::shell_help(cmd)
631             }
632             return Ok(());
633         }
634         return Err(CommandError::WrongArgumentCount(args.len()));
635     }
636 
637     fn shell_cmd_export(&self, args: &Vec<String>) -> Result<(), CommandError> {
638         if args.len() == 1 {
639             let pair = args.get(0).unwrap().split('=').collect::<Vec<&str>>();
640 
641             if pair.len() == 2 && !pair.contains(&"") {
642                 let name = pair.get(0).unwrap().to_string();
643                 let value = pair.get(1).unwrap().to_string();
644                 Env::insert(name, value);
645                 return Ok(());
646             } else {
647                 return Err(CommandError::InvalidArgument(args.get(0).unwrap().clone()));
648             }
649         }
650         return Err(CommandError::WrongArgumentCount(args.len()));
651     }
652 
653     fn shell_cmd_env(&self, args: &Vec<String>) -> Result<(), CommandError> {
654         if args.len() == 0 {
655             let mut file = File::open("/etc/profile").unwrap();
656             let mut buf: Vec<u8> = Vec::new();
657             file.read_to_end(&mut buf).unwrap();
658             println!("{}", String::from_utf8(buf).unwrap());
659             return Ok(());
660         } else {
661             return Err(CommandError::InvalidArgument(args.get(0).unwrap().clone()));
662         }
663     }
664 
665     fn shell_cmd_compgen(&self, _args: &Vec<String>) -> Result<(), CommandError> {
666         Ok(())
667     }
668 
669     fn shell_cmd_complete(&self, _args: &Vec<String>) -> Result<(), CommandError> {
670         Ok(())
671     }
672 
673     fn path_format(&self, path: &String) -> Result<String, CommandError> {
674         let mut abs_path = path.clone();
675         if !path.starts_with('/') {
676             abs_path = format!("{}/{}", self.current_dir(), path);
677         }
678         if let Ok(path) = Path::new(&abs_path).canonicalize() {
679             let mut fmt_path = path.to_str().unwrap().to_string();
680             let replacement = |_caps: &regex::Captures| -> String { String::from("/") };
681             let re = regex::Regex::new(r"\/{2,}").unwrap();
682             fmt_path = re.replace_all(fmt_path.as_str(), replacement).to_string();
683             return Ok(fmt_path);
684         } else {
685             return Err(CommandError::PathNotFound(path.clone()));
686         }
687     }
688 
689     fn is_file(&self, path_str: &String) -> Result<String, CommandError> {
690         match self.path_format(path_str) {
691             Ok(path_str) => {
692                 let path = Path::new(&path_str);
693                 if !path.is_file() {
694                     return Err(CommandError::NotFile(path_str.clone()));
695                 };
696                 Ok(path_str)
697             }
698             Err(_) => Err(CommandError::FileNotFound(path_str.clone())),
699         }
700     }
701 
702     fn is_dir(&self, path_str: &String) -> Result<String, CommandError> {
703         match self.path_format(path_str) {
704             Ok(path_str) => {
705                 let path = Path::new(&path_str);
706                 if !path.is_dir() {
707                     return Err(CommandError::NotDirectory(path_str.clone()));
708                 };
709                 Ok(path_str)
710             }
711             Err(_) => Err(CommandError::DirectoryNotFound(path_str.clone())),
712         }
713     }
714 
715     fn is_file_or_dir(&self, path_str: &String) -> Result<String, CommandError> {
716         match self.path_format(path_str) {
717             Ok(path_str) => Ok(path_str),
718             Err(_) => Err(CommandError::PathNotFound(path_str.clone())),
719         }
720     }
721 }
722