Skip to content

Commit

Permalink
windows: fix executable replacement
Browse files Browse the repository at this point in the history
  • Loading branch information
rsteube committed Dec 8, 2024
1 parent 8c08343 commit c1a34c1
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 6 deletions.
7 changes: 1 addition & 6 deletions selfupdate.go
Original file line number Diff line number Diff line change
Expand Up @@ -230,12 +230,7 @@ func (c config) Install(tag, asset string) error {
}
}

c.Printf("moving to %#v\n", target)
if err = os.Rename(fExecutable.Name(), target); err != nil {
return err
}

return nil
return c.swap(fExecutable.Name(), target)
}

func (c config) verify(executable string) error {
Expand Down
14 changes: 14 additions & 0 deletions swap.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
//go:build !windows

package selfupdate

import (
"os"
)

// swap replaces the running executable.
// On most systems this simply renames the source file.
func (c config) swap(source, target string) error {
c.Printf("moving to %#v\n", target)
return os.Rename(source, target)
}
52 changes: 52 additions & 0 deletions swap_windows.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package selfupdate

import (
"os"
"syscall"
)

// swap replaces the running executable.
// On windows it cannot be overwritten/deleted.
// It is thus renamed to an intermediate file (`{target}.old`) and simply hidden.
//
// see https://github.com/minio/selfupdate
// see https://github.com/sanbornm/go-selfupdate
func (c config) swap(source, target string) error {
old := target + ".old"
if _, err := os.Stat(old); err == nil {
if err := c.confirm("remove %#v", old); err != nil {
return err
}
if err := os.Remove(old); err != nil {
return err
}
}

c.Printf("moving current executable to %#v\n", old)
if err := os.Rename(target, old); err != nil {
return err
}

c.Printf("moving new executable to %#v\n", target)
if err := os.Rename(source, target); err != nil {
_ = os.Rename(old, target) // try to restore old executable
return err
}

c.Printf("hiding %#v\n", old)
return hide(old)
}

func hide(path string) error {
p, err := syscall.UTF16PtrFromString(path)
if err != nil {
return err
}

err = syscall.SetFileAttributes(p, syscall.FILE_ATTRIBUTE_HIDDEN)
if err != nil {
return err
}

return nil
}

0 comments on commit c1a34c1

Please sign in to comment.