diff --git a/demo.bat b/demo.bat index 9091bb2..a4319fc 100644 --- a/demo.bat +++ b/demo.bat @@ -7,6 +7,15 @@ if not exist target\debug\examples\deletes-itself.exe ( echo deletes-itself.exe was successfully deleted ) +echo. +echo Run deletes-itself-at.exe +target\debug\examples\deletes-itself-at.exe +if not exist target\debug\examples\deletes-itself-at.exe ( + if not exist target\debug\examples\deletes-itself-renamed.exe ( + echo deletes-itself-at.exe and deletes-itself-renamed.exe were successfully deleted + ) +) + echo. echo Run hello.exe target\debug\examples\hello.exe diff --git a/demo.sh b/demo.sh index 27ca014..f439db2 100755 --- a/demo.sh +++ b/demo.sh @@ -7,6 +7,14 @@ if [ ! -f target/debug/examples/deletes-itself ]; then echo " deletes-itself.exe was successfully deleted" fi +echo +echo "Run deletes-itself-at.exe" +target/debug/examples/deletes-itself-at + +if [ ! -f target/debug/examples/deletes-itself-renamed ] && [ ! -f target/debug/examples/deletes-itself-at ]; then + echo " deletes-itself-at.exe and deletes-itself-renamed.exe were successfully deleted" +fi + echo echo "Run hello.exe" target/debug/examples/hello diff --git a/examples/deletes-itself-at.rs b/examples/deletes-itself-at.rs new file mode 100644 index 0000000..f2d862d --- /dev/null +++ b/examples/deletes-itself-at.rs @@ -0,0 +1,15 @@ +fn main() { + println!("When I finish, I am deleted"); + let exe = std::env::current_exe().unwrap().canonicalize().unwrap(); + let exe_renamed = exe.with_file_name(format!( + "deletes-itself-renamed{}", + std::env::consts::EXE_SUFFIX + )); + + std::fs::rename(exe, &exe_renamed).unwrap(); + self_replace::self_delete_at(exe_renamed).unwrap(); + + if std::env::var("FORCE_EXIT").ok().as_deref() == Some("1") { + std::process::exit(0); + } +} diff --git a/src/lib.rs b/src/lib.rs index 5c24702..eaf8708 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -133,13 +133,20 @@ mod windows; /// # Ok(()) } /// ``` pub fn self_delete() -> Result<(), io::Error> { + self_delete_at(std::env::current_exe()?) +} + +/// Like [`self_delete`] but accepts a path which is assumed to be the current executable path. +/// +/// This can be useful if the executable was moved to a different location while it was running. +pub fn self_delete_at>(exe: P) -> Result<(), io::Error> { #[cfg(unix)] { - crate::unix::self_delete() + crate::unix::self_delete(exe.as_ref()) } #[cfg(windows)] { - crate::windows::self_delete(None) + crate::windows::self_delete(exe.as_ref(), None) } } @@ -150,14 +157,15 @@ pub fn self_delete() -> Result<(), io::Error> { /// of the deletion operation. This is necessary to demolish folder more complex folder /// structures on Windows. pub fn self_delete_outside_path>(p: P) -> Result<(), io::Error> { + let exe = std::env::current_exe()?; #[cfg(unix)] { let _ = p; - crate::unix::self_delete() + crate::unix::self_delete(&exe) } #[cfg(windows)] { - crate::windows::self_delete(Some(p.as_ref())) + crate::windows::self_delete(&exe, Some(p.as_ref())) } } diff --git a/src/unix.rs b/src/unix.rs index 98e0c7f..56535c8 100644 --- a/src/unix.rs +++ b/src/unix.rs @@ -4,8 +4,8 @@ use std::io; use std::path::Path; /// On Unix a running executable can be safely deleted. -pub fn self_delete() -> Result<(), io::Error> { - let exe = env::current_exe()?.canonicalize()?; +pub fn self_delete(exe: &Path) -> Result<(), io::Error> { + let exe = exe.canonicalize()?; fs::remove_file(exe)?; Ok(()) } diff --git a/src/windows.rs b/src/windows.rs index d75deb6..27da2e2 100644 --- a/src/windows.rs +++ b/src/windows.rs @@ -273,9 +273,8 @@ fn get_directory_of(p: &Path) -> Result<&Path, io::Error> { /// actually shuts down. /// 4. In `self_delete_on_init` spawn a dummy process so that windows deletes the /// copy too. -pub fn self_delete(protected_path: Option<&Path>) -> Result<(), io::Error> { - let exe = env::current_exe()?.canonicalize()?; - schedule_self_deletion_on_shutdown(&exe, protected_path)?; +pub fn self_delete(exe: &Path, protected_path: Option<&Path>) -> Result<(), io::Error> { + schedule_self_deletion_on_shutdown(exe, protected_path)?; Ok(()) }