github.com/opentofu/opentofu@v1.7.1/internal/states/statemgr/filesystem_lock_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 statemgr 10 11 import ( 12 "log" 13 "math" 14 "syscall" 15 "unsafe" 16 ) 17 18 var ( 19 modkernel32 = syscall.NewLazyDLL("kernel32.dll") 20 procLockFileEx = modkernel32.NewProc("LockFileEx") 21 procCreateEventW = modkernel32.NewProc("CreateEventW") 22 ) 23 24 const ( 25 // dwFlags defined for LockFileEx 26 // https://msdn.microsoft.com/en-us/library/windows/desktop/aa365203(v=vs.85).aspx 27 _LOCKFILE_FAIL_IMMEDIATELY = 1 28 _LOCKFILE_EXCLUSIVE_LOCK = 2 29 ) 30 31 func (s *Filesystem) lock() error { 32 log.Printf("[TRACE] statemgr.Filesystem: locking %s using LockFileEx", s.path) 33 34 // even though we're failing immediately, an overlapped event structure is 35 // required 36 ol, err := newOverlapped() 37 if err != nil { 38 return err 39 } 40 defer syscall.CloseHandle(ol.HEvent) 41 42 return lockFileEx( 43 syscall.Handle(s.stateFileOut.Fd()), 44 _LOCKFILE_EXCLUSIVE_LOCK|_LOCKFILE_FAIL_IMMEDIATELY, 45 0, // reserved 46 0, // bytes low 47 math.MaxUint32, // bytes high 48 ol, 49 ) 50 } 51 52 func (s *Filesystem) unlock() error { 53 log.Printf("[TRACE] statemgr.Filesystem: unlocked by closing %s", s.path) 54 55 // the file is closed in Unlock 56 return nil 57 } 58 59 func lockFileEx(h syscall.Handle, flags, reserved, locklow, lockhigh uint32, ol *syscall.Overlapped) (err error) { 60 r1, _, e1 := syscall.Syscall6( 61 procLockFileEx.Addr(), 62 6, 63 uintptr(h), 64 uintptr(flags), 65 uintptr(reserved), 66 uintptr(locklow), 67 uintptr(lockhigh), 68 uintptr(unsafe.Pointer(ol)), 69 ) 70 if r1 == 0 { 71 if e1 != 0 { 72 err = error(e1) 73 } else { 74 err = syscall.EINVAL 75 } 76 } 77 return 78 } 79 80 // newOverlapped creates a structure used to track asynchronous 81 // I/O requests that have been issued. 82 func newOverlapped() (*syscall.Overlapped, error) { 83 event, err := createEvent(nil, true, false, nil) 84 if err != nil { 85 return nil, err 86 } 87 return &syscall.Overlapped{HEvent: event}, nil 88 } 89 90 func createEvent(sa *syscall.SecurityAttributes, manualReset bool, initialState bool, name *uint16) (handle syscall.Handle, err error) { 91 var _p0 uint32 92 if manualReset { 93 _p0 = 1 94 } 95 var _p1 uint32 96 if initialState { 97 _p1 = 1 98 } 99 100 r0, _, e1 := syscall.Syscall6( 101 procCreateEventW.Addr(), 102 4, 103 uintptr(unsafe.Pointer(sa)), 104 uintptr(_p0), 105 uintptr(_p1), 106 uintptr(unsafe.Pointer(name)), 107 0, 108 0, 109 ) 110 handle = syscall.Handle(r0) 111 if handle == syscall.InvalidHandle { 112 if e1 != 0 { 113 err = error(e1) 114 } else { 115 err = syscall.EINVAL 116 } 117 } 118 return 119 }