github.com/nevins-b/terraform@v0.3.8-0.20170215184714-bbae22007d5a/state/local_lock_windows.go (about) 1 // +build windows 2 3 package state 4 5 import ( 6 "math" 7 "os" 8 "sync" 9 "syscall" 10 "unsafe" 11 ) 12 13 type stateLock struct { 14 handle syscall.Handle 15 } 16 17 var ( 18 modkernel32 = syscall.NewLazyDLL("kernel32.dll") 19 procLockFileEx = modkernel32.NewProc("LockFileEx") 20 procCreateEventW = modkernel32.NewProc("CreateEventW") 21 22 lockedFilesMu sync.Mutex 23 lockedFiles = map[*os.File]syscall.Handle{} 24 ) 25 26 const ( 27 // dwFlags defined for LockFileEx 28 // https://msdn.microsoft.com/en-us/library/windows/desktop/aa365203(v=vs.85).aspx 29 _LOCKFILE_FAIL_IMMEDIATELY = 1 30 _LOCKFILE_EXCLUSIVE_LOCK = 2 31 ) 32 33 func (s *LocalState) lock() error { 34 lockedFilesMu.Lock() 35 defer lockedFilesMu.Unlock() 36 37 name, err := syscall.UTF16PtrFromString(s.PathOut) 38 if err != nil { 39 return err 40 } 41 42 handle, err := syscall.CreateFile( 43 name, 44 syscall.GENERIC_READ|syscall.GENERIC_WRITE, 45 // since this file is already open in out process, we need shared 46 // access here for this call. 47 syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE, 48 nil, 49 syscall.OPEN_EXISTING, 50 syscall.FILE_ATTRIBUTE_NORMAL, 51 0, 52 ) 53 if err != nil { 54 return err 55 } 56 57 lockedFiles[s.stateFileOut] = handle 58 59 // even though we're failing immediately, an overlapped event structure is 60 // required 61 ol, err := newOverlapped() 62 if err != nil { 63 return err 64 } 65 defer syscall.CloseHandle(ol.HEvent) 66 67 return lockFileEx( 68 handle, 69 _LOCKFILE_EXCLUSIVE_LOCK|_LOCKFILE_FAIL_IMMEDIATELY, 70 0, // reserved 71 0, // bytes low 72 math.MaxUint32, // bytes high 73 ol, 74 ) 75 } 76 77 func (s *LocalState) unlock() error { 78 lockedFilesMu.Lock() 79 defer lockedFilesMu.Unlock() 80 81 handle, ok := lockedFiles[s.stateFileOut] 82 if !ok { 83 // we allow multiple Unlock calls 84 return nil 85 } 86 delete(lockedFiles, s.stateFileOut) 87 return syscall.Close(handle) 88 } 89 90 func lockFileEx(h syscall.Handle, flags, reserved, locklow, lockhigh uint32, ol *syscall.Overlapped) (err error) { 91 r1, _, e1 := syscall.Syscall6( 92 procLockFileEx.Addr(), 93 6, 94 uintptr(h), 95 uintptr(flags), 96 uintptr(reserved), 97 uintptr(locklow), 98 uintptr(lockhigh), 99 uintptr(unsafe.Pointer(ol)), 100 ) 101 if r1 == 0 { 102 if e1 != 0 { 103 err = error(e1) 104 } else { 105 err = syscall.EINVAL 106 } 107 } 108 return 109 } 110 111 // newOverlapped creates a structure used to track asynchronous 112 // I/O requests that have been issued. 113 func newOverlapped() (*syscall.Overlapped, error) { 114 event, err := createEvent(nil, true, false, nil) 115 if err != nil { 116 return nil, err 117 } 118 return &syscall.Overlapped{HEvent: event}, nil 119 } 120 121 func createEvent(sa *syscall.SecurityAttributes, manualReset bool, initialState bool, name *uint16) (handle syscall.Handle, err error) { 122 var _p0 uint32 123 if manualReset { 124 _p0 = 1 125 } 126 var _p1 uint32 127 if initialState { 128 _p1 = 1 129 } 130 131 r0, _, e1 := syscall.Syscall6( 132 procCreateEventW.Addr(), 133 4, 134 uintptr(unsafe.Pointer(sa)), 135 uintptr(_p0), 136 uintptr(_p1), 137 uintptr(unsafe.Pointer(name)), 138 0, 139 0, 140 ) 141 handle = syscall.Handle(r0) 142 if handle == syscall.InvalidHandle { 143 if e1 != 0 { 144 err = error(e1) 145 } else { 146 err = syscall.EINVAL 147 } 148 } 149 return 150 }