github.com/wasilibs/wazerox@v0.0.0-20240124024944-4923be63ab5f/internal/sysfs/file_windows.go (about)

     1  package sysfs
     2  
     3  import (
     4  	"syscall"
     5  	"unsafe"
     6  
     7  	"github.com/wasilibs/wazerox/experimental/sys"
     8  )
     9  
    10  const (
    11  	nonBlockingFileReadSupported  = true
    12  	nonBlockingFileWriteSupported = false
    13  )
    14  
    15  var kernel32 = syscall.NewLazyDLL("kernel32.dll")
    16  
    17  // procPeekNamedPipe is the syscall.LazyProc in kernel32 for PeekNamedPipe
    18  var procPeekNamedPipe = kernel32.NewProc("PeekNamedPipe")
    19  
    20  // readFd returns ENOSYS on unsupported platforms.
    21  //
    22  // PeekNamedPipe: https://learn.microsoft.com/en-us/windows/win32/api/namedpipeapi/nf-namedpipeapi-peeknamedpipe
    23  // "GetFileType can assist in determining what device type the handle refers to. A console handle presents as FILE_TYPE_CHAR."
    24  // https://learn.microsoft.com/en-us/windows/console/console-handles
    25  func readFd(fd uintptr, buf []byte) (int, sys.Errno) {
    26  	handle := syscall.Handle(fd)
    27  	fileType, err := syscall.GetFileType(handle)
    28  	if err != nil {
    29  		return 0, sys.UnwrapOSError(err)
    30  	}
    31  	if fileType&syscall.FILE_TYPE_CHAR == 0 {
    32  		return -1, sys.ENOSYS
    33  	}
    34  	n, errno := peekNamedPipe(handle)
    35  	if errno == syscall.ERROR_BROKEN_PIPE {
    36  		return 0, 0
    37  	}
    38  	if n == 0 {
    39  		return -1, sys.EAGAIN
    40  	}
    41  	un, err := syscall.Read(handle, buf[0:n])
    42  	return un, sys.UnwrapOSError(err)
    43  }
    44  
    45  func writeFd(fd uintptr, buf []byte) (int, sys.Errno) {
    46  	return -1, sys.ENOSYS
    47  }
    48  
    49  func readSocket(h syscall.Handle, buf []byte) (int, sys.Errno) {
    50  	var overlapped syscall.Overlapped
    51  	var done uint32
    52  	errno := syscall.ReadFile(h, buf, &done, &overlapped)
    53  	if errno == syscall.ERROR_IO_PENDING {
    54  		errno = sys.EAGAIN
    55  	}
    56  	return int(done), sys.UnwrapOSError(errno)
    57  }
    58  
    59  func writeSocket(fd uintptr, buf []byte) (int, sys.Errno) {
    60  	var done uint32
    61  	var overlapped syscall.Overlapped
    62  	errno := syscall.WriteFile(syscall.Handle(fd), buf, &done, &overlapped)
    63  	if errno == syscall.ERROR_IO_PENDING {
    64  		errno = syscall.EAGAIN
    65  	}
    66  	return int(done), sys.UnwrapOSError(errno)
    67  }
    68  
    69  // peekNamedPipe partially exposes PeekNamedPipe from the Win32 API
    70  // see https://learn.microsoft.com/en-us/windows/win32/api/namedpipeapi/nf-namedpipeapi-peeknamedpipe
    71  func peekNamedPipe(handle syscall.Handle) (uint32, syscall.Errno) {
    72  	var totalBytesAvail uint32
    73  	totalBytesPtr := unsafe.Pointer(&totalBytesAvail)
    74  	_, _, errno := syscall.SyscallN(
    75  		procPeekNamedPipe.Addr(),
    76  		uintptr(handle),        // [in]            HANDLE  hNamedPipe,
    77  		0,                      // [out, optional] LPVOID  lpBuffer,
    78  		0,                      // [in]            DWORD   nBufferSize,
    79  		0,                      // [out, optional] LPDWORD lpBytesRead
    80  		uintptr(totalBytesPtr), // [out, optional] LPDWORD lpTotalBytesAvail,
    81  		0)                      // [out, optional] LPDWORD lpBytesLeftThisMessage
    82  	return totalBytesAvail, errno
    83  }
    84  
    85  func rmdir(path string) sys.Errno {
    86  	err := syscall.Rmdir(path)
    87  	return sys.UnwrapOSError(err)
    88  }