mirror of
https://github.com/opentofu/opentofu.git
synced 2024-12-27 09:21:14 -06:00
55e6f64977
This originated in the cliconfig code to write out credentials files. The Windows implementation of this in particular was quite onerous to get right because it needs a very specific sequence of operations to avoid running into exclusive file locks, and so by factoring this out with only cosmetic modification we can avoid repeating all of that engineering effort for other atomic file writing use-cases.
41 lines
1.4 KiB
Go
41 lines
1.4 KiB
Go
// +build windows
|
|
|
|
package replacefile
|
|
|
|
import (
|
|
"os"
|
|
"syscall"
|
|
|
|
"golang.org/x/sys/windows"
|
|
)
|
|
|
|
// AtomicRename renames from the source path to the destination path,
|
|
// atomically replacing any file that might already exist at the destination.
|
|
//
|
|
// Typically this operation can succeed only if the source and destination
|
|
// are within the same physical filesystem, so this function is best reserved
|
|
// for cases where the source and destination exist in the same directory and
|
|
// only the local filename differs between them.
|
|
func AtomicRename(source, destination string) error {
|
|
// On Windows, renaming one file over another is not atomic and certain
|
|
// error conditions can result in having only the source file and nothing
|
|
// at the destination file. Instead, we need to call into the MoveFileEx
|
|
// Windows API function, setting two flags to opt in to replacing an
|
|
// existing file.
|
|
srcPtr, err := syscall.UTF16PtrFromString(source)
|
|
if err != nil {
|
|
return &os.LinkError{"replace", source, destination, err}
|
|
}
|
|
destPtr, err := syscall.UTF16PtrFromString(destination)
|
|
if err != nil {
|
|
return &os.LinkError{"replace", source, destination, err}
|
|
}
|
|
|
|
flags := uint32(windows.MOVEFILE_REPLACE_EXISTING | windows.MOVEFILE_WRITE_THROUGH)
|
|
err = windows.MoveFileEx(srcPtr, destPtr, flags)
|
|
if err != nil {
|
|
return &os.LinkError{"replace", source, destination, err}
|
|
}
|
|
return nil
|
|
}
|