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