github.com/rstandt/terraform@v0.12.32-0.20230710220336-b1063613405c/states/statemgr/filesystem_lock_windows.go (about)

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