mirror of
https://github.com/opentofu/opentofu.git
synced 2024-12-28 01:41:48 -06:00
6cb3b0f4cf
This was a mistake while adapting this code from the old state.LocalState. Since the lock is held on the output file (s.path) the metadata should live adjacent to that rather than being built from the read path (s.readPath) that is used only as the initial snapshot on first instantiation. This also includes more logging, continuing the trend of other recent commits in these files. The local state behavior is sufficiently complex that these trace logs are a great help in debugging issues such as this one with the wrong files being used or actions being taken in the wrong order.
114 lines
2.3 KiB
Go
114 lines
2.3 KiB
Go
// +build windows
|
|
|
|
package statemgr
|
|
|
|
import (
|
|
"log"
|
|
"math"
|
|
"syscall"
|
|
"unsafe"
|
|
)
|
|
|
|
var (
|
|
modkernel32 = syscall.NewLazyDLL("kernel32.dll")
|
|
procLockFileEx = modkernel32.NewProc("LockFileEx")
|
|
procCreateEventW = modkernel32.NewProc("CreateEventW")
|
|
)
|
|
|
|
const (
|
|
// dwFlags defined for LockFileEx
|
|
// https://msdn.microsoft.com/en-us/library/windows/desktop/aa365203(v=vs.85).aspx
|
|
_LOCKFILE_FAIL_IMMEDIATELY = 1
|
|
_LOCKFILE_EXCLUSIVE_LOCK = 2
|
|
)
|
|
|
|
func (s *Filesystem) lock() error {
|
|
log.Printf("[TRACE] statemgr.Filesystem: locking %s using LockFileEx", s.path)
|
|
|
|
// even though we're failing immediately, an overlapped event structure is
|
|
// required
|
|
ol, err := newOverlapped()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer syscall.CloseHandle(ol.HEvent)
|
|
|
|
return lockFileEx(
|
|
syscall.Handle(s.stateFileOut.Fd()),
|
|
_LOCKFILE_EXCLUSIVE_LOCK|_LOCKFILE_FAIL_IMMEDIATELY,
|
|
0, // reserved
|
|
0, // bytes low
|
|
math.MaxUint32, // bytes high
|
|
ol,
|
|
)
|
|
}
|
|
|
|
func (s *Filesystem) unlock() error {
|
|
log.Printf("[TRACE] statemgr.Filesystem: unlocked by closing %s", s.path)
|
|
|
|
// the file is closed in Unlock
|
|
return nil
|
|
}
|
|
|
|
func lockFileEx(h syscall.Handle, flags, reserved, locklow, lockhigh uint32, ol *syscall.Overlapped) (err error) {
|
|
r1, _, e1 := syscall.Syscall6(
|
|
procLockFileEx.Addr(),
|
|
6,
|
|
uintptr(h),
|
|
uintptr(flags),
|
|
uintptr(reserved),
|
|
uintptr(locklow),
|
|
uintptr(lockhigh),
|
|
uintptr(unsafe.Pointer(ol)),
|
|
)
|
|
if r1 == 0 {
|
|
if e1 != 0 {
|
|
err = error(e1)
|
|
} else {
|
|
err = syscall.EINVAL
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
// newOverlapped creates a structure used to track asynchronous
|
|
// I/O requests that have been issued.
|
|
func newOverlapped() (*syscall.Overlapped, error) {
|
|
event, err := createEvent(nil, true, false, nil)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &syscall.Overlapped{HEvent: event}, nil
|
|
}
|
|
|
|
func createEvent(sa *syscall.SecurityAttributes, manualReset bool, initialState bool, name *uint16) (handle syscall.Handle, err error) {
|
|
var _p0 uint32
|
|
if manualReset {
|
|
_p0 = 1
|
|
}
|
|
var _p1 uint32
|
|
if initialState {
|
|
_p1 = 1
|
|
}
|
|
|
|
r0, _, e1 := syscall.Syscall6(
|
|
procCreateEventW.Addr(),
|
|
4,
|
|
uintptr(unsafe.Pointer(sa)),
|
|
uintptr(_p0),
|
|
uintptr(_p1),
|
|
uintptr(unsafe.Pointer(name)),
|
|
0,
|
|
0,
|
|
)
|
|
handle = syscall.Handle(r0)
|
|
if handle == syscall.InvalidHandle {
|
|
if e1 != 0 {
|
|
err = error(e1)
|
|
} else {
|
|
err = syscall.EINVAL
|
|
}
|
|
}
|
|
return
|
|
}
|