1use crate::{
2 exec_cmd_utf8,
3 types::*,
4 vmware::{read_vmware_inventory, read_vmware_preferences},
5};
6use std::{borrow::Cow, process::Command, time::Duration};
7
8pub enum HostType {
9 Player,
10 Workstation,
11 Fusion,
12}
13
14impl HostType {
15 pub fn as_str(&self) -> &'static str {
16 match self {
17 Self::Player => "player",
18 Self::Workstation => "ws",
19 Self::Fusion => "fusion",
20 }
21 }
22}
23
24impl ToString for HostType {
25 fn to_string(&self) -> String { self.as_str().to_string() }
26}
27
28impl<T: AsRef<str>> From<T> for HostType {
29 fn from(x: T) -> Self {
30 match x.as_ref() {
31 "player" => Self::Player,
32 "ws" => Self::Workstation,
33 "fusion" => Self::Fusion,
34 x => panic!("Unexpected HostType: {}", x),
35 }
36 }
37}
38
39pub enum WriteVar<'a> {
40 GuestVar(&'a str, &'a str),
41 RuntimeConfig(&'a str, &'a str),
42 GuestEnv(&'a str, &'a str),
43}
44
45pub enum ReadVar<'a> {
46 GuestVar(&'a str),
47 RuntimeConfig(&'a str),
48 GuestEnv(&'a str),
49}
50
51#[derive(Debug, Clone, Eq, PartialEq)]
52pub struct ProcInfo {
53 pub pid: u32,
54 pub owner: String,
55 pub cmd: String,
56}
57
58#[derive(Debug, Clone)]
59pub struct VmRun {
60 host_type: &'static str,
61 executable_path: String,
62 use_inventory: bool,
63 vm_path: Option<String>,
64 vm_password: Option<String>,
65 guest_username: Option<String>,
66 guest_password: Option<String>,
67 gui: bool,
68}
69
70impl Default for VmRun {
71 fn default() -> Self { Self::new() }
72}
73
74impl VmRun {
75 pub fn new() -> Self {
76 Self {
77 host_type: "ws",
78 executable_path: "vmrun".to_string(),
79 use_inventory: true,
80 vm_path: None,
81 vm_password: None,
82 guest_username: None,
83 guest_password: None,
84 gui: true,
85 }
86 }
87
88 impl_setter!(
89 executable_path: String
91 );
92
93 pub fn host_type<T: Into<HostType>>(&mut self, host_type: T) -> &mut Self {
94 let host_type = host_type.into();
95 match host_type {
96 HostType::Player => self.use_inventory = false,
97 _ => self.use_inventory = true,
98 }
99 self.host_type = host_type.as_str();
100 self
101 }
102
103 impl_setter!(@opt vm_path: String);
104 impl_setter!(@opt vm_password: String);
105 impl_setter!(@opt guest_username: String);
106 impl_setter!(@opt guest_password: String);
107 impl_setter!(use_inventory: bool);
108 impl_setter!(gui: bool);
109
110 #[inline]
111 fn build_auth(&self) -> Vec<&str> {
112 let mut v = Vec::with_capacity(6);
113 if let Some(x) = &self.guest_username {
114 v.extend(&["-gu", x]);
115 }
116 if let Some(x) = &self.guest_password {
117 v.extend(&["-gp", x]);
118 }
119 if let Some(x) = &self.vm_password {
120 v.extend(&["-vp", x]);
121 }
122 v
123 }
124
125 fn get_vm(&self) -> VmResult<&str> {
126 self.vm_path
127 .as_deref()
128 .ok_or_else(|| VmError::from(ErrorKind::VmIsNotSpecified))
129 }
130
131 #[inline]
132 fn cmd(&self) -> Command {
133 let mut cmd = Command::new(&self.executable_path);
134 cmd.args(&["-T", self.host_type]);
135 cmd.args(&self.build_auth());
136 cmd
137 }
138
139 #[inline]
140 fn handle_error(s: &str) -> VmError {
141 use ErrorKind::*;
142 use VmPowerState::*;
143 starts_err!(s, "No Vm name provided", VmIsNotSpecified);
144 starts_err!(s, "Cannot open VM: ", VmNotFound);
145 starts_err!(
146 s,
147 "The virtual machine is not powered on: ",
148 InvalidPowerState(NotRunning)
149 );
150 starts_err!(
151 s,
152 "A snapshot with the name already exists",
153 SnapshotExists
154 );
155 starts_err!(
156 s,
157 "Invalid user name or password for the guest OS",
158 AuthenticationFailed
159 );
160 starts_err!(
161 s,
162 "The VMware Tools are not running in the virtual machine: ",
163 ServiceIsNotRunning
164 );
165 starts_err!(s, "Unrecognized command: ", UnsupportedCommand);
166 VmError::from(Repr::Unknown(format!("Unknown error: {}", s)))
167 }
168
169 #[inline]
170 fn check(s: String) -> VmResult<String> {
171 match s.strip_prefix("Error: ") {
172 Some(s) => Err(Self::handle_error(s.trim())),
173 None => Ok(s),
174 }
175 }
176
177 fn exec(cmd: &mut Command) -> VmResult<String> {
178 let (stdout, stderr) = exec_cmd_utf8(cmd)?;
179 if !stderr.is_empty() {
180 Self::check(stderr)
181 } else {
182 Self::check(stdout)
183 }
184 }
185
186 pub fn version(&self) -> VmResult<String> {
188 let s = Self::exec(&mut self.cmd())?;
189 let v = s
190 .lines()
191 .nth(2)
192 .unwrap()
193 .strip_prefix("vmrun version ")
194 .unwrap();
195 Ok(v.to_string())
196 }
197
198 pub fn start_vm(&self, gui: bool) -> VmResult<()> {
199 let mut cmd = self.cmd();
200 cmd.args(&["start", self.get_vm()?]);
201 if !gui {
202 cmd.arg("nogui");
203 }
204 Self::exec(&mut cmd)?;
205 Ok(())
206 }
207
208 pub fn stop_vm(&self, hard_stop: Option<bool>) -> VmResult<()> {
209 let mut cmd = self.cmd();
210 cmd.args(&["stop", self.get_vm()?]);
211 if let Some(hard_stop) = hard_stop {
212 cmd.arg(if hard_stop { "soft" } else { "hard" });
213 }
214 Self::exec(&mut cmd)?;
215 Ok(())
216 }
217
218 pub fn reset_vm(&self, hard_stop: Option<bool>) -> VmResult<()> {
219 let mut cmd = self.cmd();
220 cmd.args(&["reset", self.get_vm()?]);
221 if let Some(hard_stop) = hard_stop {
222 cmd.arg(if hard_stop { "soft" } else { "hard" });
223 }
224 Self::exec(&mut cmd)?;
225 Ok(())
226 }
227
228 pub fn suspend_vm(&self, hard_stop: Option<bool>) -> VmResult<()> {
229 let mut cmd = self.cmd();
230 cmd.args(&["suspend", self.get_vm()?]);
231 if let Some(hard_stop) = hard_stop {
232 cmd.arg(if hard_stop { "soft" } else { "hard" });
233 }
234 Self::exec(&mut cmd)?;
235 Ok(())
236 }
237
238 pub fn pause_vm(&self) -> VmResult<()> {
239 let mut cmd = self.cmd();
240 cmd.args(&["pause", self.get_vm()?]);
241 Self::exec(&mut cmd)?;
242 Ok(())
243 }
244
245 pub fn unpause_vm(&self) -> VmResult<()> {
246 let mut cmd = self.cmd();
247 cmd.args(&["unpause", self.get_vm()?]);
248 Self::exec(&mut cmd)?;
249 Ok(())
250 }
251
252 pub fn list_all_vms(&self) -> VmResult<Vec<Vm>> {
253 let p = std::env::var("APPDATA").expect("Failed to get %APPDATA%");
254 let vms = if self.use_inventory {
255 read_vmware_inventory(&format!(r"{}\VMware\inventory.vmls", p))?
256 } else {
257 read_vmware_preferences(&format!(r"{}\VMware\preferences.ini", p))?
258 };
259
260 if vms.is_none() {
261 return vmerr!(Repr::Unknown(
262 "Cannot parse preferences file".to_string()
263 ));
264 }
265 Ok(vms.unwrap())
266 }
267
268 pub fn list_running_vms(&self) -> VmResult<Vec<Vm>> {
269 let mut cmd = self.cmd();
270 cmd.arg("list");
271 let s = Self::exec(&mut cmd)?;
272 let mut l = s.lines();
273 let n = match l.next() {
274 Some(s) => s
275 .strip_prefix("Total running VMs: ")
276 .expect("Unexpected list response")
277 .parse::<usize>()
278 .expect("Failed to parse to usize"),
279 None => return Ok(vec![]),
280 };
281 let mut ret = Vec::with_capacity(n);
282 for s in l {
283 ret.push(Vm {
284 id: None,
285 name: None,
286 path: Some(s.to_string()),
287 });
288 }
289 Ok(ret)
290 }
291
292 pub fn list_snapshots(&self) -> VmResult<Vec<Snapshot>> {
293 let mut cmd = self.cmd();
294 cmd.args(&["listSnapshots", self.get_vm()?]);
295 let s = Self::exec(&mut cmd)?;
296 let mut l = s.lines();
297 let n = match l.next() {
298 Some(s) => s
299 .strip_prefix("Total snapshots: ")
300 .expect("Unexpected list response")
301 .parse::<usize>()
302 .expect("Failed to parse to usize"),
303 None => return Ok(vec![]),
304 };
305 let mut ret = Vec::with_capacity(n);
306 for s in l {
307 ret.push(Snapshot {
308 id: None,
309 name: Some(s.to_string()),
310 detail: None,
311 });
312 }
313 Ok(ret)
314 }
315
316 pub fn is_snapshot_exists(&self, name: &str) -> VmResult<bool> {
317 let ss = self.list_snapshots()?;
318 Ok(ss.iter().any(|x| x.name.as_deref().unwrap() == name))
319 }
320
321 pub fn snapshot(&self, name: &str) -> VmResult<()> {
322 let mut cmd = self.cmd();
323 cmd.args(&["snapshot", self.get_vm()?, name]);
324 Self::exec(&mut cmd)?;
325 Ok(())
326 }
327
328 pub fn delete_snapshot(
329 &self,
330 name: &str,
331 delete_children: bool,
332 ) -> VmResult<()> {
333 let mut cmd = self.cmd();
334 cmd.args(&["deleteSnapshot", self.get_vm()?, name]);
335 if delete_children {
336 cmd.arg("andDeleteChildren");
337 }
338 Self::exec(&mut cmd)?;
339 Ok(())
340 }
341
342 pub fn revert_to_snapshot(&self, name: &str) -> VmResult<()> {
343 let mut cmd = self.cmd();
344 cmd.args(&["revertToSnapshot", self.get_vm()?, name]);
345 Self::exec(&mut cmd)?;
346 Ok(())
347 }
348
349 pub fn run_program_in_guest(
350 &self,
351 no_wait: bool,
352 active_window: bool,
353 interactive: bool,
354 program_args: &[&str],
355 ) -> VmResult<()> {
356 let mut cmd = self.cmd();
357 cmd.args(&["runProgramInGuest", self.get_vm()?]);
358 if no_wait {
359 cmd.arg("-noWait");
360 }
361 if active_window {
362 cmd.arg("-activeWindow");
363 }
364 if interactive {
365 cmd.arg("-interactive");
366 }
367 cmd.args(program_args);
368 Self::exec(&mut cmd)?;
369 Ok(())
370 }
371
372 pub fn file_exists_in_guest(&self, guest_path: &str) -> VmResult<bool> {
373 let s = Self::exec(self.cmd().args(&[
374 "fileExistsInGuest",
375 self.get_vm()?,
376 guest_path,
377 ]))?;
378 match s.as_str().trim() {
379 "The file exists." => Ok(true),
380 "The file does not exist." => Ok(false),
381 _ => vmerr!(ErrorKind::UnexpectedResponse(s)),
382 }
383 }
384
385 pub fn directory_exists_in_guest(
386 &self,
387 guest_path: &str,
388 ) -> VmResult<bool> {
389 let s = Self::exec(self.cmd().args(&[
390 "directoryExistsInGuest",
391 self.get_vm()?,
392 guest_path,
393 ]))?;
394 match s.as_str().trim() {
395 "The directory exists." => Ok(true),
396 "The directory does not exist." => Ok(false),
397 _ => vmerr!(ErrorKind::UnexpectedResponse(s)),
398 }
399 }
400
401 pub fn set_shared_folder_state(
402 &self,
403 name: &str,
404 host_path: &str,
405 writable: bool,
406 ) -> VmResult<()> {
407 let mut cmd = self.cmd();
408 cmd.args(&["setSharedFolderState", name, host_path]);
409 cmd.arg(if writable { "writable" } else { "readonly" });
410 Self::exec(&mut cmd)?;
411 Ok(())
412 }
413
414 pub fn add_shared_folder(
415 &self,
416 name: &str,
417 host_path: &str,
418 ) -> VmResult<()> {
419 let mut cmd = self.cmd();
420 cmd.args(&["addSharedFolder", name, host_path]);
421 Self::exec(&mut cmd)?;
422 Ok(())
423 }
424
425 pub fn remove_shared_folder(&self, name: &str) -> VmResult<()> {
426 let mut cmd = self.cmd();
427 cmd.args(&["removeSharedFolder", name]);
428 Self::exec(&mut cmd)?;
429 Ok(())
430 }
431
432 pub fn enable_shared_folders(
433 &self,
434 name: &str,
435 only_runtime: bool,
436 ) -> VmResult<()> {
437 let mut cmd = self.cmd();
438 cmd.args(&["enableSharedFolders", name]);
439 if only_runtime {
440 cmd.arg("runtime");
441 }
442 Self::exec(&mut cmd)?;
443 Ok(())
444 }
445
446 pub fn disable_shared_folders(
447 &self,
448 name: &str,
449 only_runtime: bool,
450 ) -> VmResult<()> {
451 let mut cmd = self.cmd();
452 cmd.args(&["disableSharedFolders", name]);
453 if only_runtime {
454 cmd.arg("runtime");
455 }
456 Self::exec(&mut cmd)?;
457 Ok(())
458 }
459
460 pub fn list_processes_in_guest(&self) -> VmResult<Vec<ProcInfo>> {
461 let s = Self::exec(
462 self.cmd().args(&["listProcessesInGuest", self.get_vm()?]),
463 )?;
464 let mut l = s.lines();
465 let n = match l.next() {
466 Some(s) => s
467 .strip_prefix("Process list: ")
468 .expect("Unexpected list response")
469 .parse::<usize>()
470 .expect("Failed to parse to usize"),
471 None => return Ok(vec![]),
472 };
473 let mut ret = Vec::with_capacity(n);
474 for l in l {
475 let v: Vec<&str> = l.splitn(3, ", ").collect();
476 assert_eq!(v.len(), 3);
477 let (pid, owner, cmd) = (v[0], v[1], v[2]);
478 let pid = pid.strip_prefix("pid=").expect("Unexpected pid");
479 let pid: u32 = pid.parse().unwrap();
480 let owner = owner
481 .strip_prefix("owner=")
482 .expect("Unexpected owner")
483 .to_string();
484 let cmd = cmd
485 .strip_prefix("cmd=")
486 .expect("Unexpected process command")
487 .to_string();
488 ret.push(ProcInfo { pid, owner, cmd })
489 }
490 Ok(ret)
491 }
492
493 pub fn kill_process_in_guest(&self, pid: u32) -> VmResult<()> {
494 Self::exec(self.cmd().args(&[
495 "killProcessInGuest",
496 self.get_vm()?,
497 &pid.to_string(),
498 ]))?;
499 Ok(())
500 }
501
502 pub fn delete_file_in_guest(&self, guest_path: &str) -> VmResult<()> {
503 Self::exec(self.cmd().args(&[
504 "deleteFileInGuest",
505 self.get_vm()?,
506 guest_path,
507 ]))?;
508 Ok(())
509 }
510
511 pub fn create_directory_in_guest(&self, guest_path: &str) -> VmResult<()> {
512 Self::exec(self.cmd().args(&[
513 "createDirectoryInGuest",
514 self.get_vm()?,
515 guest_path,
516 ]))?;
517 Ok(())
518 }
519
520 pub fn delete_directory_in_guest(&self, guest_path: &str) -> VmResult<()> {
521 Self::exec(self.cmd().args(&[
522 "deleteDirectoryInGuest",
523 self.get_vm()?,
524 guest_path,
525 ]))?;
526 Ok(())
527 }
528
529 pub fn create_temp_file_in_guest(&self) -> VmResult<String> {
533 let s = Self::exec(
534 self.cmd().args(&["createTempFileInGuest", self.get_vm()?]),
535 )?;
536 Ok(s)
537 }
538
539 pub fn list_directory_in_guest(
540 &self,
541 guest_path: &str,
542 ) -> VmResult<Vec<String>> {
543 let s = Self::exec(self.cmd().args(&[
544 "listDirectoryInGuest",
545 self.get_vm()?,
546 guest_path,
547 ]))?;
548 Ok(s.lines().skip(1).map(|x| x.to_string()).collect())
549 }
550
551 pub fn copy_file_from_host_to_guest(
552 &self,
553 host_path: &str,
554 guest_path: &str,
555 ) -> VmResult<()> {
556 Self::exec(self.cmd().args(&[
557 "CopyFileFromHostToGuest",
558 self.get_vm()?,
559 host_path,
560 guest_path,
561 ]))?;
562 Ok(())
563 }
564
565 pub fn copy_file_from_guest_to_host(
566 &self,
567 guest_path: &str,
568 host_path: &str,
569 ) -> VmResult<()> {
570 Self::exec(self.cmd().args(&[
571 "CopyFileFromGuestToHost",
572 self.get_vm()?,
573 guest_path,
574 host_path,
575 ]))?;
576 Ok(())
577 }
578
579 pub fn rename_file_in_guest(
580 &self,
581 old_path: &str,
582 new_path: &str,
583 ) -> VmResult<()> {
584 Self::exec(self.cmd().args(&[
585 "renameFileInGuest",
586 self.get_vm()?,
587 old_path,
588 new_path,
589 ]))?;
590 Ok(())
591 }
592
593 pub fn type_keystrokes_in_guest(&self, keystroke: &str) -> VmResult<()> {
594 Self::exec(self.cmd().args(&[
595 "typeKeystrokesInGuest",
596 self.get_vm()?,
597 keystroke,
598 ]))?;
599 Ok(())
600 }
601
602 pub fn capture_screen(&self, host_path: &str) -> VmResult<()> {
603 Self::exec(self.cmd().args(&[
604 "captureScreen",
605 self.get_vm()?,
606 host_path,
607 ]))?;
608 Ok(())
609 }
610
611 pub fn write_variable(&self, variable: WriteVar) -> VmResult<()> {
612 let mut cmd = self.cmd();
613 cmd.args(&["writeVariable", self.get_vm()?]);
614 match variable {
615 WriteVar::GuestVar(name, value) => {
616 cmd.args(&["guestVar", name, value])
617 }
618 WriteVar::RuntimeConfig(name, value) => {
619 cmd.args(&["runtimeConfig", name, value])
620 }
621 WriteVar::GuestEnv(name, value) => {
622 cmd.args(&["guestEnv", name, value])
623 }
624 };
625 Self::exec(&mut cmd)?;
626 Ok(())
627 }
628
629 pub fn read_variable(&self, variable: ReadVar) -> VmResult<Option<String>> {
630 let mut cmd = self.cmd();
631 cmd.args(&["readVariable", self.get_vm()?]);
632 match variable {
633 ReadVar::GuestVar(name) => cmd.args(&["guestVar", name]),
634 ReadVar::RuntimeConfig(name) => cmd.args(&["runtimeConfig", name]),
635 ReadVar::GuestEnv(name) => cmd.args(&["guestEnv", name]),
636 };
637 let s = Self::exec(&mut cmd)?;
638 Ok(if s.is_empty() { None } else { Some(s) })
639 }
640
641 pub fn get_guest_ip_address(&self, wait: bool) -> VmResult<String> {
642 let mut cmd = self.cmd();
643 cmd.args(&["getGuestIPAddress", self.get_vm()?]);
644 if wait {
645 cmd.arg("-wait");
646 }
647 let s = Self::exec(&mut cmd)?;
648 Ok(s)
649 }
650
651 pub fn install_tools(&self) -> VmResult<()> {
652 Self::exec(self.cmd().args(&["installTools", self.get_vm()?]))?;
653 Ok(())
654 }
655
656 pub fn check_tools_state(&self) -> VmResult<bool> {
657 let s =
658 Self::exec(self.cmd().args(&["checkToolsState", self.get_vm()?]))?;
659 match s.as_str() {
660 "installed" => Ok(true),
661 "unknown" => Ok(false),
662 "running" => Ok(true),
663 _ => vmerr!(ErrorKind::UnexpectedResponse(s)),
664 }
665 }
666
667 pub fn delete_vm(&self) -> VmResult<()> {
668 Self::exec(self.cmd().args(&["deleteVM", self.get_vm()?]))?;
669 Ok(())
670 }
671}
672
673impl VmCmd for VmRun {
674 fn list_vms(&self) -> VmResult<Vec<Vm>> { self.list_all_vms() }
675
676 fn set_vm_by_id(&mut self, _id: &str) -> VmResult<()> {
678 vmerr!(ErrorKind::UnsupportedCommand)
679 }
680
681 fn set_vm_by_name(&mut self, name: &str) -> VmResult<()> {
682 for vm in self.list_vms()? {
683 if vm.name.as_deref() == Some(name) {
684 self.vm_path = vm.path;
685 return Ok(());
686 }
687 }
688 vmerr!(ErrorKind::VmNotFound)
689 }
690
691 fn set_vm_by_path(&mut self, path: &str) -> VmResult<()> {
692 for vm in self.list_vms()? {
693 if vm.path.as_deref() == Some(path) {
694 self.vm_path = vm.path;
695 return Ok(());
696 }
697 }
698 vmerr!(ErrorKind::VmNotFound)
699 }
700}
701
702impl PowerCmd for VmRun {
703 fn start(&self) -> VmResult<()> {
704 if self.is_running()? {
705 return vmerr!(ErrorKind::InvalidPowerState(VmPowerState::Running));
706 }
707 self.start_vm(self.gui)
708 }
709
710 fn stop<D: Into<Option<Duration>>>(&self, _timeout: D) -> VmResult<()> {
711 self.stop_vm(Some(false))
712 }
713
714 fn hard_stop(&self) -> VmResult<()> { self.stop_vm(Some(true)) }
715
716 fn suspend(&self) -> VmResult<()> { self.suspend_vm(Some(true)) }
717
718 fn resume(&self) -> VmResult<()> { self.start() }
719
720 fn is_running(&self) -> VmResult<bool> {
721 let vm_path = self.get_vm()?;
722 Ok(self
723 .list_running_vms()?
724 .iter()
725 .any(|vm| vm.path.as_deref().unwrap() == vm_path))
726 }
727
728 fn reboot<D: Into<Option<Duration>>>(&self, _timeout: D) -> VmResult<()> {
729 self.reset_vm(Some(false))
730 }
731
732 fn hard_reboot(&self) -> VmResult<()> { self.reset_vm(Some(true)) }
733
734 fn pause(&self) -> VmResult<()> { self.pause_vm() }
735
736 fn unpause(&self) -> VmResult<()> { self.unpause_vm() }
737}
738
739impl SnapshotCmd for VmRun {
740 fn list_snapshots(&self) -> VmResult<Vec<Snapshot>> {
741 Self::list_snapshots(self)
742 }
743
744 fn take_snapshot(&self, name: &str) -> VmResult<()> { self.snapshot(name) }
745
746 fn revert_snapshot(&self, name: &str) -> VmResult<()> {
747 if !self.is_snapshot_exists(name)? {
748 return vmerr!(ErrorKind::SnapshotNotFound);
749 }
750 self.revert_to_snapshot(name)
751 }
752
753 fn delete_snapshot(&self, name: &str) -> VmResult<()> {
754 if !self.is_snapshot_exists(name)? {
755 return vmerr!(ErrorKind::SnapshotNotFound);
756 }
757 self.delete_snapshot(name, true)
758 }
759}
760
761impl GuestCmd for VmRun {
762 fn exec_cmd(&self, guest_args: &[&str]) -> VmResult<()> {
763 self.run_program_in_guest(true, true, false, guest_args)
764 }
765
766 fn copy_from_guest_to_host(
767 &self,
768 from_guest_path: &str,
769 to_host_path: &str,
770 ) -> VmResult<()> {
771 self.copy_file_from_guest_to_host(from_guest_path, to_host_path)
772 }
773
774 fn copy_from_host_to_guest(
775 &self,
776 from_host_path: &str,
777 to_guest_path: &str,
778 ) -> VmResult<()> {
779 fn get_file_name<'a>(
780 p: &'a std::path::Path,
781 from_host_path: &str,
782 ) -> VmResult<Cow<'a, str>> {
783 p.file_name().map(|x| x.to_string_lossy()).ok_or_else(|| {
784 vmerr!(@r ErrorKind::InvalidParameter(
785 from_host_path.to_string()
786 ))
787 })
788 }
789 let host_path = std::path::Path::new(from_host_path);
790 if !host_path.exists() {
791 return vmerr!(ErrorKind::HostFileNotFound);
792 }
793 if to_guest_path.is_empty() {
794 return vmerr!(ErrorKind::GuestFileNotFound);
795 }
796
797 if to_guest_path.ends_with('\\') || to_guest_path.ends_with('/') {
799 let file_name = get_file_name(host_path, from_host_path)?;
801 let to_guest_path = format!("{}{}", to_guest_path, file_name);
802 self.copy_file_from_host_to_guest(from_host_path, &to_guest_path)
803 } else if self.directory_exists_in_guest(to_guest_path)? {
804 let file_name = get_file_name(host_path, from_host_path)?;
806 let guest_path_separator =
807 if to_guest_path.chars().next().unwrap() == '/' {
808 '/'
809 } else {
810 '\\'
811 };
812 let to_guest_path = format!(
813 "{}{}{}",
814 to_guest_path, guest_path_separator, file_name
815 );
816 self.copy_file_from_host_to_guest(from_host_path, &to_guest_path)
817 } else {
818 self.copy_file_from_host_to_guest(from_host_path, to_guest_path)
820 }
821 }
822}