github.com/mutagen-io/mutagen@v0.18.0-rc1/pkg/filesystem/locking/locker_windows.go (about) 1 // Windows file locking implementation based on (but heavily modified from) 2 // https://github.com/golang/build/blob/4821e1d4e1dd5d386f53f1e869ced293dd18f44a/cmd/builder/filemutex_windows.go. 3 // 4 // The original code license: 5 // 6 // Copyright (c) 2009 The Go Authors. All rights reserved. 7 // 8 // Redistribution and use in source and binary forms, with or without 9 // modification, are permitted provided that the following conditions are 10 // met: 11 // 12 // * Redistributions of source code must retain the above copyright 13 // notice, this list of conditions and the following disclaimer. 14 // * Redistributions in binary form must reproduce the above 15 // copyright notice, this list of conditions and the following disclaimer 16 // in the documentation and/or other materials provided with the 17 // distribution. 18 // * Neither the name of Google Inc. nor the names of its 19 // contributors may be used to endorse or promote products derived from 20 // this software without specific prior written permission. 21 // 22 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 25 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 26 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 27 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 28 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 29 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 30 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 31 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 32 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 // 34 // The original license header inside the code itself: 35 // 36 // Copyright 2013 The Go Authors. All rights reserved. 37 // Use of this source code is governed by a BSD-style 38 // license that can be found in the LICENSE file. 39 40 package locking 41 42 import ( 43 "errors" 44 "syscall" 45 "unsafe" 46 47 "golang.org/x/sys/windows" 48 ) 49 50 var ( 51 kernel32 = windows.NewLazySystemDLL("kernel32.dll") 52 lockFileEx = kernel32.NewProc("LockFileEx") 53 unlockFileEx = kernel32.NewProc("UnlockFileEx") 54 ) 55 56 const ( 57 LOCKFILE_EXCLUSIVE_LOCK = 2 58 LOCKFILE_FAIL_IMMEDIATELY = 1 59 ) 60 61 func callLockFileEx( 62 handle syscall.Handle, 63 flags, 64 reserved, 65 lockLow, 66 lockHigh uint32, 67 overlapped *syscall.Overlapped, 68 ) (err error) { 69 r1, _, e1 := syscall.Syscall6( 70 lockFileEx.Addr(), 71 6, 72 uintptr(handle), 73 uintptr(flags), 74 uintptr(reserved), 75 uintptr(lockLow), 76 uintptr(lockHigh), 77 uintptr(unsafe.Pointer(overlapped)), 78 ) 79 if r1 == 0 { 80 if e1 != 0 { 81 err = error(e1) 82 } else { 83 err = syscall.EINVAL 84 } 85 } 86 return 87 } 88 89 func callunlockFileEx( 90 handle syscall.Handle, 91 reserved, 92 lockLow, 93 lockHigh uint32, 94 overlapped *syscall.Overlapped, 95 ) (err error) { 96 r1, _, e1 := syscall.Syscall6( 97 unlockFileEx.Addr(), 98 5, 99 uintptr(handle), 100 uintptr(reserved), 101 uintptr(lockLow), 102 uintptr(lockHigh), 103 uintptr(unsafe.Pointer(overlapped)), 104 0, 105 ) 106 if r1 == 0 { 107 if e1 != 0 { 108 err = error(e1) 109 } else { 110 err = syscall.EINVAL 111 } 112 } 113 return 114 } 115 116 // Lock attempts to acquire the file lock. 117 func (l *Locker) Lock(block bool) error { 118 // Verify that we don't already hold the lock. 119 if l.held { 120 return errors.New("lock already held") 121 } 122 123 // Create an overlapped structure to manage overlapped I/O. 124 var ol syscall.Overlapped 125 126 // Set up the lock and blocking flags. 127 flags := uint32(LOCKFILE_EXCLUSIVE_LOCK) 128 if !block { 129 flags |= LOCKFILE_FAIL_IMMEDIATELY 130 } 131 132 // Attempt to perform locking. 133 err := callLockFileEx(syscall.Handle(l.file.Fd()), flags, 0, 1, 0, &ol) 134 135 // Check for success and update the internal state. 136 if err == nil { 137 l.held = true 138 } 139 140 // Done. 141 return err 142 } 143 144 // Unlock releases the file lock. 145 func (l *Locker) Unlock() error { 146 // Verify that we hold the lock. 147 if !l.held { 148 return errors.New("lock not held") 149 } 150 151 // Create an overlapped structure to manage overlapped I/O. 152 var ol syscall.Overlapped 153 154 // Attempt to perform unlocking. 155 err := callunlockFileEx(syscall.Handle(l.file.Fd()), 0, 1, 0, &ol) 156 157 // Check for success and update the internal state. 158 if err == nil { 159 l.held = false 160 } 161 162 // Done. 163 return err 164 }