github.com/ActiveState/cli@v0.0.0-20240508170324-6801f60cd051/internal/osutils/lockfile/flock_syscall_windows.go (about)

     1  // Copyright (c) 2015, Tim Heckman
     2  // All rights reserved.
     3  //
     4  // Redistribution and use in source and binary forms, with or without
     5  // modification, are permitted provided that the following conditions are met:
     6  //
     7  // * Redistributions of source code must retain the above copyright notice, this
     8  //   list of conditions and the following disclaimer.
     9  //
    10  // * Redistributions in binary form must reproduce the above copyright notice,
    11  //   this list of conditions and the following disclaimer in the documentation
    12  //   and/or other materials provided with the distribution.
    13  //
    14  // * Neither the name of linode-netint nor the names of its
    15  //   contributors may be used to endorse or promote products derived from
    16  //   this software without specific prior written permission.
    17  //
    18  // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    19  // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    20  // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
    21  // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
    22  // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
    23  // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
    24  // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
    25  // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
    26  // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    27  // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    28  
    29  //go:build windows
    30  // +build windows
    31  
    32  package lockfile
    33  
    34  import (
    35  	"syscall"
    36  	"unsafe"
    37  )
    38  
    39  var (
    40  	kernel32, _         = syscall.LoadLibrary("kernel32.dll")
    41  	procLockFileEx, _   = syscall.GetProcAddress(kernel32, "LockFileEx")
    42  	procUnlockFileEx, _ = syscall.GetProcAddress(kernel32, "UnlockFileEx")
    43  )
    44  
    45  const (
    46  	winLockfileFailImmediately = 0x00000001
    47  	winLockfileExclusiveLock   = 0x00000002
    48  	winLockfileSharedLock      = 0x00000000
    49  )
    50  
    51  // Use of 0x00000000 for the shared lock is a guess based on some the MS Windows
    52  // `LockFileEX` docs, which document the `LOCKFILE_EXCLUSIVE_LOCK` flag as:
    53  //
    54  // > The function requests an exclusive lock. Otherwise, it requests a shared
    55  // > lock.
    56  //
    57  // https://msdn.microsoft.com/en-us/library/windows/desktop/aa365203(v=vs.85).aspx
    58  
    59  func lockFileEx(handle syscall.Handle, flags uint32, reserved uint32, numberOfBytesToLockLow uint32, numberOfBytesToLockHigh uint32, offset *syscall.Overlapped) (bool, syscall.Errno) {
    60  	r1, _, errNo := syscall.Syscall6(
    61  		uintptr(procLockFileEx),
    62  		6,
    63  		uintptr(handle),
    64  		uintptr(flags),
    65  		uintptr(reserved),
    66  		uintptr(numberOfBytesToLockLow),
    67  		uintptr(numberOfBytesToLockHigh),
    68  		uintptr(unsafe.Pointer(offset)))
    69  
    70  	if r1 != 1 {
    71  		if errNo == 0 {
    72  			return false, syscall.EINVAL
    73  		}
    74  
    75  		return false, errNo
    76  	}
    77  
    78  	return true, 0
    79  }
    80  
    81  func unlockFileEx(handle syscall.Handle, reserved uint32, numberOfBytesToLockLow uint32, numberOfBytesToLockHigh uint32, offset *syscall.Overlapped) (bool, syscall.Errno) {
    82  	r1, _, errNo := syscall.Syscall6(
    83  		uintptr(procUnlockFileEx),
    84  		5,
    85  		uintptr(handle),
    86  		uintptr(reserved),
    87  		uintptr(numberOfBytesToLockLow),
    88  		uintptr(numberOfBytesToLockHigh),
    89  		uintptr(unsafe.Pointer(offset)),
    90  		0)
    91  
    92  	if r1 != 1 {
    93  		if errNo == 0 {
    94  			return false, syscall.EINVAL
    95  		}
    96  
    97  		return false, errNo
    98  	}
    99  
   100  	return true, 0
   101  }