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