github.com/terramate-io/tf@v0.0.0-20230830114523-fce866b4dfcd/states/statemgr/filesystem_lock_windows.go (about)

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