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  }