func newInner()

in pkg/lockedfile/lockedfile_windows.go [22:74]


func newInner(filePath string, timeout time.Duration, metadata *Metadata) (*lockedFile, error) {
	name, err := windows.UTF16PtrFromString(filePath)
	if err != nil {
		return nil, err
	}

	// Open for asynchronous I/O so that we can timeout waiting for the lock.
	// Also open shared so that other processes can open the file (but will
	// still need to lock it).
	handle, err := windows.CreateFile(
		name,
		windows.GENERIC_READ|windows.GENERIC_WRITE,
		uint32(windows.FILE_SHARE_READ|windows.FILE_SHARE_WRITE),
		nil,
		windows.OPEN_ALWAYS,
		windows.FILE_FLAG_OVERLAPPED|windows.FILE_ATTRIBUTE_NORMAL,
		0)

	if err != nil {
		return nil, err
	}

	ol, err := getOverlapped()
	if err != nil {
		return nil, err
	}
	defer windows.CloseHandle(ol.HEvent)

	err = windows.LockFileEx(handle, windows.LOCKFILE_EXCLUSIVE_LOCK, reserved, allBytes, allBytes, ol)
	if err == nil {
		return &lockedFile{handle, metadata}, nil
	}

	// ERROR_IO_PENDING is expected when we're waiting on an asynchronous event
	// to occur.
	if err != syscall.ERROR_IO_PENDING {
		return nil, err
	}

	timeoutInMilliseconds := uint32(timeout / time.Millisecond)
	s, err := windows.WaitForSingleObject(ol.HEvent, timeoutInMilliseconds)

	switch s {
	case syscall.WAIT_OBJECT_0:
		// success!
		return &lockedFile{handle, metadata}, nil
	case syscall.WAIT_TIMEOUT:
		windows.CancelIo(handle)
		return nil, &FileLockTimeoutError{"file lock could not be acquired in the specified time"}
	default:
		return nil, err
	}
}