github.com/sunvim/utils@v0.1.0/fs/os_windows.go (about)

     1  //go:build windows
     2  
     3  package fs
     4  
     5  import (
     6  	"os"
     7  	"syscall"
     8  	"unsafe"
     9  )
    10  
    11  var (
    12  	modkernel32    = syscall.NewLazyDLL("kernel32.dll")
    13  	procLockFileEx = modkernel32.NewProc("LockFileEx")
    14  )
    15  
    16  const (
    17  	errorLockViolation = 0x21
    18  )
    19  
    20  func lockfile(f *os.File) error {
    21  	var ol syscall.Overlapped
    22  
    23  	r1, _, err := syscall.Syscall6(
    24  		procLockFileEx.Addr(),
    25  		6,
    26  		uintptr(f.Fd()), // handle
    27  		uintptr(0x0003),
    28  		uintptr(0), // reserved
    29  		uintptr(1), // locklow
    30  		uintptr(0), // lockhigh
    31  		uintptr(unsafe.Pointer(&ol)),
    32  	)
    33  	if r1 == 0 && (err == syscall.ERROR_FILE_EXISTS || err == errorLockViolation) {
    34  		return os.ErrExist
    35  	}
    36  	return nil
    37  }
    38  
    39  func createLockFile(name string, perm os.FileMode) (LockFile, bool, error) {
    40  	acquiredExisting := false
    41  	if _, err := os.Stat(name); err == nil {
    42  		acquiredExisting = true
    43  	}
    44  	fd, err := syscall.CreateFile(&(syscall.StringToUTF16(name)[0]),
    45  		syscall.GENERIC_READ|syscall.GENERIC_WRITE,
    46  		syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE|syscall.FILE_SHARE_DELETE,
    47  		nil,
    48  		syscall.CREATE_ALWAYS,
    49  		syscall.FILE_ATTRIBUTE_NORMAL,
    50  		0)
    51  	if err != nil {
    52  		return nil, false, os.ErrExist
    53  	}
    54  	f := os.NewFile(uintptr(fd), name)
    55  	if err := lockfile(f); err != nil {
    56  		f.Close()
    57  		return nil, false, err
    58  	}
    59  	return &osLockFile{f, name}, acquiredExisting, nil
    60  }