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