github.com/opentofu/opentofu@v1.7.1/internal/replacefile/replacefile_windows.go (about) 1 // Copyright (c) The OpenTofu Authors 2 // SPDX-License-Identifier: MPL-2.0 3 // Copyright (c) 2023 HashiCorp, Inc. 4 // SPDX-License-Identifier: MPL-2.0 5 6 //go:build windows 7 // +build windows 8 9 package replacefile 10 11 import ( 12 "os" 13 "syscall" 14 15 "golang.org/x/sys/windows" 16 ) 17 18 // AtomicRename renames from the source path to the destination path, 19 // atomically replacing any file that might already exist at the destination. 20 // 21 // Typically this operation can succeed only if the source and destination 22 // are within the same physical filesystem, so this function is best reserved 23 // for cases where the source and destination exist in the same directory and 24 // only the local filename differs between them. 25 func AtomicRename(source, destination string) error { 26 // On Windows, renaming one file over another is not atomic and certain 27 // error conditions can result in having only the source file and nothing 28 // at the destination file. Instead, we need to call into the MoveFileEx 29 // Windows API function, setting two flags to opt in to replacing an 30 // existing file. 31 srcPtr, err := syscall.UTF16PtrFromString(source) 32 if err != nil { 33 return &os.LinkError{"replace", source, destination, err} 34 } 35 destPtr, err := syscall.UTF16PtrFromString(destination) 36 if err != nil { 37 return &os.LinkError{"replace", source, destination, err} 38 } 39 40 flags := uint32(windows.MOVEFILE_REPLACE_EXISTING | windows.MOVEFILE_WRITE_THROUGH) 41 err = windows.MoveFileEx(srcPtr, destPtr, flags) 42 if err != nil { 43 return &os.LinkError{"replace", source, destination, err} 44 } 45 return nil 46 }