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 path = args.get(0).unwrap(); 324 325 //路径中提取目录和文件名 326 let dir = &path[..path.rfind('/').unwrap_or(0)]; 327 let file_name = &path[path.rfind('/').unwrap_or(0)..]; 328 329 //判断文件所在目录是否存在 330 match self.is_dir(&dir.to_string()) { 331 Ok(str) => { 332 let abs_path = format!("{}/{}", str, file_name); 333 //判断文件是否存在,存在时不操作,不存在时创建文件 334 if !Path::new(&abs_path).exists() { 335 File::create(&abs_path).unwrap(); 336 } 337 } 338 Err(e) => { 339 return Err(e); 340 } 341 }; 342 343 return Ok(()); 344 } 345 return Err(CommandError::WrongArgumentCount(args.len())); 346 } 347 348 fn shell_cmd_mkdir(&self, args: &Vec<String>) -> Result<(), CommandError> { 349 if args.len() == 1 { 350 let path = args.get(0).unwrap(); 351 match fs::create_dir_all(path) { 352 Ok(_) => {} 353 Err(e) => { 354 print!("{e}") 355 } 356 } 357 return Ok(()); 358 } else { 359 return Err(CommandError::WrongArgumentCount(args.len())); 360 } 361 } 362 363 fn shell_cmd_rm(&self, args: &Vec<String>) -> Result<(), CommandError> { 364 if args.len() == 1 { 365 let mut path = args.get(0).unwrap().clone(); 366 // match fs::remove_file(path) { 367 // Ok(_) => {} 368 // Err(e) => { 369 // print!("{e}") 370 // } 371 // } 372 373 match self.is_file(&path) { 374 Ok(str) => path = str, 375 Err(e) => return Err(e), 376 } 377 378 let path_cstr = std::ffi::CString::new(path.clone()).unwrap(); 379 unsafe { 380 libc::syscall(libc::SYS_unlinkat, 0, path_cstr.as_ptr(), 0, 0, 0, 0); 381 } 382 return Ok(()); 383 } 384 return Err(CommandError::WrongArgumentCount(args.len())); 385 } 386 387 fn shell_cmd_rmdir(&self, args: &Vec<String>) -> Result<(), CommandError> { 388 if args.len() == 1 { 389 let mut path = args.get(0).unwrap().clone(); 390 match self.is_dir(&path) { 391 Ok(str) => path = str, 392 Err(e) => return Err(e), 393 } 394 395 let path_cstr = std::ffi::CString::new(path).unwrap(); 396 unsafe { libc::unlinkat(0, path_cstr.as_ptr(), libc::AT_REMOVEDIR) }; 397 return Ok(()); 398 } 399 return Err(CommandError::WrongArgumentCount(args.len())); 400 } 401 402 fn shell_cmd_pwd(&self, args: &Vec<String>) -> Result<(), CommandError> { 403 if args.len() == 0 { 404 println!("{}", self.current_dir()); 405 return Ok(()); 406 } 407 return Err(CommandError::WrongArgumentCount(args.len())); 408 } 409 410 fn shell_cmd_cp(&self, args: &Vec<String>) -> Result<(), CommandError> { 411 if args.len() == 2 { 412 let mut src_path = args.get(0).unwrap().clone(); 413 let mut target_path = args.get(1).unwrap().clone(); 414 415 match self.is_file(&src_path) { 416 Ok(str) => src_path = str, 417 Err(e) => return Err(e), 418 } 419 420 match self.is_file_or_dir(&target_path) { 421 Ok(str) => target_path = str, 422 Err(e) => { 423 let prefix = &target_path[..target_path.rfind('/').unwrap_or(0)]; 424 if !Path::new(prefix).is_dir() { 425 return Err(e); 426 } 427 } 428 } 429 430 if Path::new(&src_path).is_dir() { 431 let name = &src_path[src_path.rfind('/').unwrap_or(0)..]; 432 target_path = format!("{}/{}", target_path, name); 433 } 434 435 let mut src_file = File::open(&src_path).unwrap(); 436 let mut target_file = File::create(target_path).unwrap(); 437 let mut buf: Vec<u8> = Vec::new(); 438 src_file.read_to_end(&mut buf).unwrap(); 439 target_file.write_all(&buf).unwrap(); 440 return Ok(()); 441 } 442 return Err(CommandError::WrongArgumentCount(args.len())); 443 } 444 445 pub fn shell_cmd_exec(&self, args: &Vec<String>) -> Result<(), CommandError> { 446 // println!("shell_cmd_exec: {:?}", args); 447 let mut args = args.clone(); 448 if args.len() <= 0 { 449 return Err(CommandError::WrongArgumentCount(args.len())); 450 } 451 let path = args.get(0).unwrap(); 452 let mut real_path = String::new(); 453 if !path.contains('/') { 454 let mut dir_collection = Env::path(); 455 dir_collection.insert(0, self.current_dir()); 456 for dir in dir_collection { 457 let possible_path = format!("{}/{}", dir, path); 458 if Path::new(&possible_path).is_file() { 459 real_path = possible_path; 460 break; 461 } 462 } 463 if real_path.is_empty() { 464 return Err(CommandError::FileNotFound(path.clone())); 465 } 466 } else { 467 match self.is_file(path) { 468 Ok(path) => real_path = path, 469 Err(e) => return Err(e), 470 } 471 } 472 473 // 如果文件不存在,返回错误 474 if !Path::new(&real_path).is_file() { 475 // println!("{}: command not found", real_path); 476 return Err(CommandError::FileNotFound(real_path.clone())); 477 } 478 479 let pid: libc::pid_t = unsafe { 480 libc::syscall(libc::SYS_fork, 0, 0, 0, 0, 0, 0) 481 .try_into() 482 .unwrap() 483 }; 484 485 let name = &real_path[real_path.rfind('/').map(|pos| pos + 1).unwrap_or(0)..]; 486 *args.get_mut(0).unwrap() = name.to_string(); 487 let mut retval = 0; 488 if pid == 0 { 489 let path_cstr = std::ffi::CString::new(real_path).unwrap(); 490 let args_cstr = args 491 .iter() 492 .map(|str| std::ffi::CString::new(str.as_str()).unwrap()) 493 .collect::<Vec<std::ffi::CString>>(); 494 let mut args_ptr = args_cstr 495 .iter() 496 .map(|c_str| c_str.as_ptr()) 497 .collect::<Vec<*const i8>>(); 498 args_ptr.push(std::ptr::null()); 499 let argv = args_ptr.as_ptr(); 500 501 unsafe { 502 libc::execv(path_cstr.as_ptr(), argv); 503 } 504 } else { 505 if args.last().unwrap() != &"&" { 506 unsafe { libc::waitpid(pid, &mut retval as *mut i32, 0) }; 507 } else { 508 println!("[1] {}", pid); 509 } 510 } 511 return Ok(()); 512 } 513 514 fn shell_cmd_echo(&self, args: &Vec<String>) -> Result<(), CommandError> { 515 if args.len() > 0 { 516 let str = args.get(0).unwrap(); 517 if args.len() == 1 { 518 println!("{str}"); 519 } 520 521 if args.len() == 3 { 522 let mut target_path = args.get(2).unwrap().clone(); 523 match self.is_file(&target_path) { 524 Ok(str) => target_path = str, 525 Err(e) => return Err(e), 526 } 527 528 if args[1] == ">" { 529 match OpenOptions::new().write(true).open(target_path) { 530 Ok(mut file) => { 531 file.write_all(str.as_bytes()).unwrap(); 532 } 533 Err(e) => print!("{e}"), 534 } 535 } else if args[1] == ">>" { 536 match OpenOptions::new().append(true).open(target_path) { 537 Ok(mut file) => { 538 file.write_all(str.as_bytes()).unwrap(); 539 } 540 Err(e) => print!("{e}"), 541 } 542 } 543 } 544 return Ok(()); 545 } 546 return Err(CommandError::WrongArgumentCount(args.len())); 547 } 548 549 fn shell_cmd_reboot(&self, args: &Vec<String>) -> Result<(), CommandError> { 550 if args.len() == 0 { 551 unsafe { libc::syscall(libc::SYS_reboot, 0, 0, 0, 0, 0, 0) }; 552 return Ok(()); 553 } else { 554 return Err(CommandError::WrongArgumentCount(args.len())); 555 } 556 } 557 558 fn shell_cmd_free(&self, args: &Vec<String>) -> Result<(), CommandError> { 559 if args.len() == 1 && args.get(0).unwrap() != "-m" { 560 return Err(CommandError::InvalidArgument( 561 args.get(0).unwrap().to_string(), 562 )); 563 } 564 565 struct Mstat { 566 total: u64, // 计算机的总内存数量大小 567 used: u64, // 已使用的内存大小 568 free: u64, // 空闲物理页所占的内存大小 569 shared: u64, // 共享的内存大小 570 cache_used: u64, // 位于slab缓冲区中的已使用的内存大小 571 cache_free: u64, // 位于slab缓冲区中的空闲的内存大小 572 available: u64, // 系统总空闲内存大小(包括kmalloc缓冲区) 573 } 574 575 let mut mst = Mstat { 576 total: 0, 577 used: 0, 578 free: 0, 579 shared: 0, 580 cache_used: 0, 581 cache_free: 0, 582 available: 0, 583 }; 584 585 let mut info_file = File::open("/proc/meminfo").unwrap(); 586 let mut buf: Vec<u8> = Vec::new(); 587 info_file.read_to_end(&mut buf).unwrap(); 588 let str = String::from_utf8(buf).unwrap(); 589 let info = str 590 .split(&['\n', '\t', ' ']) 591 .filter_map(|str| str.parse::<u64>().ok()) 592 .collect::<Vec<u64>>(); 593 mst.total = *info.get(0).unwrap(); 594 mst.free = *info.get(1).unwrap(); 595 mst.used = mst.total - mst.free; 596 597 print!("\ttotal\t\tused\t\tfree\t\tshared\t\tcache_used\tcache_free\tavailable\n"); 598 print!("Mem:\t"); 599 600 if args.len() == 0 { 601 print!( 602 "{}\t\t{}\t\t{}\t\t{}\t\t{}\t\t{}\t\t{}\n", 603 mst.total, 604 mst.used, 605 mst.free, 606 mst.shared, 607 mst.cache_used, 608 mst.cache_free, 609 mst.available 610 ); 611 } else { 612 print!( 613 "{}\t\t{}\t\t{}\t\t{}\t\t{}\t\t{}\n", 614 mst.total >> 10, 615 mst.used >> 10, 616 mst.free >> 10, 617 mst.shared >> 10, 618 mst.cache_used >> 10, 619 mst.available >> 10 620 ); 621 } 622 Ok(()) 623 } 624 625 fn shell_cmd_kill(&self, args: &Vec<String>) -> Result<(), CommandError> { 626 if args.len() == 1 { 627 let pid: i32; 628 match args.get(0).unwrap().parse::<i32>() { 629 Ok(x) => pid = x, 630 Err(_) => { 631 return Err(CommandError::InvalidArgument( 632 args.get(0).unwrap().to_string(), 633 )) 634 } 635 } 636 unsafe { 637 libc::kill(pid, libc::SIGTERM); 638 } 639 return Ok(()); 640 } else { 641 return Err(CommandError::WrongArgumentCount(args.len())); 642 } 643 } 644 645 fn shell_cmd_help(&self, args: &Vec<String>) -> Result<(), CommandError> { 646 if args.len() == 0 { 647 for BuildInCmd(cmd) in BuildInCmd::BUILD_IN_CMD { 648 Help::shell_help(cmd) 649 } 650 return Ok(()); 651 } 652 return Err(CommandError::WrongArgumentCount(args.len())); 653 } 654 655 fn shell_cmd_export(&self, args: &Vec<String>) -> Result<(), CommandError> { 656 if args.len() == 1 { 657 let pair = args.get(0).unwrap().split('=').collect::<Vec<&str>>(); 658 659 if pair.len() == 2 && !pair.contains(&"") { 660 let name = pair.get(0).unwrap().to_string(); 661 let value = pair.get(1).unwrap().to_string(); 662 Env::insert(name, value); 663 return Ok(()); 664 } else { 665 return Err(CommandError::InvalidArgument(args.get(0).unwrap().clone())); 666 } 667 } 668 return Err(CommandError::WrongArgumentCount(args.len())); 669 } 670 671 fn shell_cmd_env(&self, args: &Vec<String>) -> Result<(), CommandError> { 672 if args.len() == 0 { 673 let mut file = File::open(ENV_FILE_PATH).unwrap(); 674 let mut buf: Vec<u8> = Vec::new(); 675 file.read_to_end(&mut buf).unwrap(); 676 println!("{}", String::from_utf8(buf).unwrap()); 677 return Ok(()); 678 } else { 679 return Err(CommandError::InvalidArgument(args.get(0).unwrap().clone())); 680 } 681 } 682 683 fn shell_cmd_compgen(&self, _args: &Vec<String>) -> Result<(), CommandError> { 684 Ok(()) 685 } 686 687 fn shell_cmd_complete(&self, _args: &Vec<String>) -> Result<(), CommandError> { 688 Ok(()) 689 } 690 691 fn path_format(&self, path: &String) -> Result<String, CommandError> { 692 let mut abs_path = path.clone(); 693 if !path.starts_with('/') { 694 abs_path = format!("{}/{}", self.current_dir(), path); 695 } 696 if let Ok(path) = Path::new(&abs_path).canonicalize() { 697 let mut fmt_path = path.to_str().unwrap().to_string(); 698 let replacement = |_caps: ®ex::Captures| -> String { String::from("/") }; 699 let re = regex::Regex::new(r"\/{2,}").unwrap(); 700 fmt_path = re.replace_all(fmt_path.as_str(), replacement).to_string(); 701 return Ok(fmt_path); 702 } else { 703 return Err(CommandError::PathNotFound(path.clone())); 704 } 705 } 706 707 fn is_file(&self, path_str: &String) -> Result<String, CommandError> { 708 match self.path_format(path_str) { 709 Ok(path_str) => { 710 let path = Path::new(&path_str); 711 if !path.is_file() { 712 return Err(CommandError::NotFile(path_str.clone())); 713 }; 714 Ok(path_str) 715 } 716 Err(_) => Err(CommandError::FileNotFound(path_str.clone())), 717 } 718 } 719 720 fn is_dir(&self, path_str: &String) -> Result<String, CommandError> { 721 match self.path_format(path_str) { 722 Ok(path_str) => { 723 let path = Path::new(&path_str); 724 if !path.is_dir() { 725 return Err(CommandError::NotDirectory(path_str.clone())); 726 }; 727 Ok(path_str) 728 } 729 Err(_) => Err(CommandError::DirectoryNotFound(path_str.clone())), 730 } 731 } 732 733 fn is_file_or_dir(&self, path_str: &String) -> Result<String, CommandError> { 734 match self.path_format(path_str) { 735 Ok(path_str) => Ok(path_str), 736 Err(_) => Err(CommandError::PathNotFound(path_str.clone())), 737 } 738 } 739 } 740