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