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