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