diff options
author | 2024-05-27 15:46:15 +0000 | |
---|---|---|
committer | 2024-05-27 17:46:15 +0200 | |
commit | 1e7b32490dfdccddd04f46d4b0416b48d749d51b (patch) | |
tree | 62a11365933a5a11e0800af64cbdf9172e5e6e7a /vendor/github.com/tetratelabs/wazero/internal/sysfs/file_windows.go | |
parent | [chore] Small styling + link issues (#2933) (diff) | |
download | gotosocial-1e7b32490dfdccddd04f46d4b0416b48d749d51b.tar.xz |
[experiment] add alternative wasm sqlite3 implementation available via build-tag (#2863)
This allows for building GoToSocial with [SQLite transpiled to WASM](https://github.com/ncruces/go-sqlite3) and accessed through [Wazero](https://wazero.io/).
Diffstat (limited to 'vendor/github.com/tetratelabs/wazero/internal/sysfs/file_windows.go')
-rw-r--r-- | vendor/github.com/tetratelabs/wazero/internal/sysfs/file_windows.go | 175 |
1 files changed, 175 insertions, 0 deletions
diff --git a/vendor/github.com/tetratelabs/wazero/internal/sysfs/file_windows.go b/vendor/github.com/tetratelabs/wazero/internal/sysfs/file_windows.go new file mode 100644 index 000000000..37870ea36 --- /dev/null +++ b/vendor/github.com/tetratelabs/wazero/internal/sysfs/file_windows.go @@ -0,0 +1,175 @@ +package sysfs + +import ( + "errors" + "syscall" + "unsafe" + + "github.com/tetratelabs/wazero/experimental/sys" +) + +const ( + nonBlockingFileReadSupported = true + nonBlockingFileWriteSupported = false + + _ERROR_IO_INCOMPLETE = syscall.Errno(996) +) + +var kernel32 = syscall.NewLazyDLL("kernel32.dll") + +// procPeekNamedPipe is the syscall.LazyProc in kernel32 for PeekNamedPipe +var ( + // procPeekNamedPipe is the syscall.LazyProc in kernel32 for PeekNamedPipe + procPeekNamedPipe = kernel32.NewProc("PeekNamedPipe") + // procGetOverlappedResult is the syscall.LazyProc in kernel32 for GetOverlappedResult + procGetOverlappedResult = kernel32.NewProc("GetOverlappedResult") + // procCreateEventW is the syscall.LazyProc in kernel32 for CreateEventW + procCreateEventW = kernel32.NewProc("CreateEventW") +) + +// readFd returns ENOSYS on unsupported platforms. +// +// PeekNamedPipe: https://learn.microsoft.com/en-us/windows/win32/api/namedpipeapi/nf-namedpipeapi-peeknamedpipe +// "GetFileType can assist in determining what device type the handle refers to. A console handle presents as FILE_TYPE_CHAR." +// https://learn.microsoft.com/en-us/windows/console/console-handles +func readFd(fd uintptr, buf []byte) (int, sys.Errno) { + handle := syscall.Handle(fd) + fileType, err := syscall.GetFileType(handle) + if err != nil { + return 0, sys.UnwrapOSError(err) + } + if fileType&syscall.FILE_TYPE_CHAR == 0 { + return -1, sys.ENOSYS + } + n, errno := peekNamedPipe(handle) + if errno == syscall.ERROR_BROKEN_PIPE { + return 0, 0 + } + if n == 0 { + return -1, sys.EAGAIN + } + un, err := syscall.Read(handle, buf[0:n]) + return un, sys.UnwrapOSError(err) +} + +func writeFd(fd uintptr, buf []byte) (int, sys.Errno) { + return -1, sys.ENOSYS +} + +func readSocket(h uintptr, buf []byte) (int, sys.Errno) { + // Poll the socket to ensure that we never perform a blocking/overlapped Read. + // + // When the socket is closed by the remote peer, wsaPoll will return n=1 and + // errno=0, and syscall.ReadFile will return n=0 and errno=0 -- which indicates + // io.EOF. + if n, errno := wsaPoll( + []pollFd{newPollFd(h, _POLLIN, 0)}, 0); !errors.Is(errno, sys.Errno(0)) { + return 0, sys.UnwrapOSError(errno) + } else if n <= 0 { + return 0, sys.EAGAIN + } + + // Properly use overlapped result. + // + // If hFile was opened with FILE_FLAG_OVERLAPPED, the following conditions are in effect: + // - The lpOverlapped parameter must point to a valid and unique OVERLAPPED structure, + // otherwise the function can incorrectly report that the read operation is complete. + // - The lpNumberOfBytesRead parameter should be set to NULL. Use the GetOverlappedResult + // function to get the actual number of bytes read. If the hFile parameter is associated + // with an I/O completion port, you can also get the number of bytes read by calling the + // GetQueuedCompletionStatus function. + // + // We are currently skipping checking if hFile was opened with FILE_FLAG_OVERLAPPED but using + // both lpOverlapped and lpNumberOfBytesRead. + var overlapped syscall.Overlapped + + // Create an event to wait on. + if hEvent, err := createEventW(nil, true, false, nil); err != 0 { + return 0, sys.UnwrapOSError(err) + } else { + overlapped.HEvent = syscall.Handle(hEvent) + } + + var done uint32 + errno := syscall.ReadFile(syscall.Handle(h), buf, &done, &overlapped) + if errors.Is(errno, syscall.ERROR_IO_PENDING) { + errno = syscall.CancelIo(syscall.Handle(h)) + if errno != nil { + return 0, sys.UnwrapOSError(errno) // This is a fatal error. CancelIo failed. + } + + done, errno = getOverlappedResult(syscall.Handle(h), &overlapped, true) // wait for I/O to complete(cancel or finish). Overwrite done and errno. + if errors.Is(errno, syscall.ERROR_OPERATION_ABORTED) { + return int(done), sys.EAGAIN // This is one of the expected behavior, I/O was cancelled(completed) before finished. + } + } + + return int(done), sys.UnwrapOSError(errno) +} + +func writeSocket(fd uintptr, buf []byte) (int, sys.Errno) { + var done uint32 + var overlapped syscall.Overlapped + errno := syscall.WriteFile(syscall.Handle(fd), buf, &done, &overlapped) + if errors.Is(errno, syscall.ERROR_IO_PENDING) { + errno = syscall.EAGAIN + } + return int(done), sys.UnwrapOSError(errno) +} + +// peekNamedPipe partially exposes PeekNamedPipe from the Win32 API +// see https://learn.microsoft.com/en-us/windows/win32/api/namedpipeapi/nf-namedpipeapi-peeknamedpipe +func peekNamedPipe(handle syscall.Handle) (uint32, syscall.Errno) { + var totalBytesAvail uint32 + totalBytesPtr := unsafe.Pointer(&totalBytesAvail) + _, _, errno := syscall.SyscallN( + procPeekNamedPipe.Addr(), + uintptr(handle), // [in] HANDLE hNamedPipe, + 0, // [out, optional] LPVOID lpBuffer, + 0, // [in] DWORD nBufferSize, + 0, // [out, optional] LPDWORD lpBytesRead + uintptr(totalBytesPtr), // [out, optional] LPDWORD lpTotalBytesAvail, + 0) // [out, optional] LPDWORD lpBytesLeftThisMessage + return totalBytesAvail, errno +} + +func rmdir(path string) sys.Errno { + err := syscall.Rmdir(path) + return sys.UnwrapOSError(err) +} + +func getOverlappedResult(handle syscall.Handle, overlapped *syscall.Overlapped, wait bool) (uint32, syscall.Errno) { + var totalBytesAvail uint32 + var bwait uintptr + if wait { + bwait = 0xFFFFFFFF + } + totalBytesPtr := unsafe.Pointer(&totalBytesAvail) + _, _, errno := syscall.SyscallN( + procGetOverlappedResult.Addr(), + uintptr(handle), // [in] HANDLE hFile, + uintptr(unsafe.Pointer(overlapped)), // [in] LPOVERLAPPED lpOverlapped, + uintptr(totalBytesPtr), // [out] LPDWORD lpNumberOfBytesTransferred, + bwait) // [in] BOOL bWait + return totalBytesAvail, errno +} + +func createEventW(lpEventAttributes *syscall.SecurityAttributes, bManualReset bool, bInitialState bool, lpName *uint16) (uintptr, syscall.Errno) { + var manualReset uintptr + var initialState uintptr + if bManualReset { + manualReset = 1 + } + if bInitialState { + initialState = 1 + } + handle, _, errno := syscall.SyscallN( + procCreateEventW.Addr(), + uintptr(unsafe.Pointer(lpEventAttributes)), // [in] LPSECURITY_ATTRIBUTES lpEventAttributes, + manualReset, // [in] BOOL bManualReset, + initialState, // [in] BOOL bInitialState, + uintptr(unsafe.Pointer(lpName)), // [in, opt]LPCWSTR lpName, + ) + + return handle, errno +} |