diff --git a/dlls/kernel32/sync.c b/dlls/kernel32/sync.c index 8b90abbe2ad..eaa0f70dcd9 100644 --- a/dlls/kernel32/sync.c +++ b/dlls/kernel32/sync.c @@ -26,18 +26,6 @@ # include #endif #include -#ifdef HAVE_SYS_IOCTL_H -#include -#endif -#ifdef HAVE_POLL_H -#include -#endif -#ifdef HAVE_SYS_POLL_H -#include -#endif -#ifdef HAVE_SYS_SOCKET_H -#include -#endif #include #include @@ -54,7 +42,6 @@ #include "winioctl.h" #include "ddk/wdm.h" -#include "wine/server.h" #include "wine/unicode.h" #include "wine/winbase16.h" #include "kernel_private.h" @@ -1194,75 +1181,32 @@ HANDLE WINAPI CreateNamedPipeW( LPCWSTR name, DWORD dwOpenMode, BOOL WINAPI PeekNamedPipe( HANDLE hPipe, LPVOID lpvBuffer, DWORD cbBuffer, LPDWORD lpcbRead, LPDWORD lpcbAvail, LPDWORD lpcbMessage ) { -#ifdef FIONREAD - int avail=0, fd, ret, flags; + FILE_PIPE_PEEK_BUFFER local_buffer; + FILE_PIPE_PEEK_BUFFER *buffer = &local_buffer; + IO_STATUS_BLOCK io; + NTSTATUS status; - TRACE("(%p,%p,%u,%p,%p,%p)\n", hPipe, lpvBuffer, cbBuffer, lpcbRead, lpcbAvail, lpcbMessage); - - ret = wine_server_handle_to_fd( hPipe, FILE_READ_DATA, &fd, &flags ); - if (ret) + if (cbBuffer && !(buffer = HeapAlloc( GetProcessHeap(), 0, + FIELD_OFFSET( FILE_PIPE_PEEK_BUFFER, Data[cbBuffer] )))) { - SetLastError( RtlNtStatusToDosError(ret) ); - return FALSE; - } - if (flags & FD_FLAG_RECV_SHUTDOWN) - { - wine_server_release_fd( hPipe, fd ); - SetLastError ( ERROR_PIPE_NOT_CONNECTED ); + SetLastError( ERROR_NOT_ENOUGH_MEMORY ); return FALSE; } - if (ioctl(fd,FIONREAD, &avail ) != 0) + status = NtFsControlFile( hPipe, 0, NULL, NULL, &io, FSCTL_PIPE_PEEK, NULL, 0, + buffer, FIELD_OFFSET( FILE_PIPE_PEEK_BUFFER, Data[cbBuffer] ) ); + if (!status) { - TRACE("FIONREAD failed reason: %s\n",strerror(errno)); - wine_server_release_fd( hPipe, fd ); - return FALSE; + ULONG read_size = io.Information - FIELD_OFFSET( FILE_PIPE_PEEK_BUFFER, Data ); + if (lpcbAvail) *lpcbAvail = buffer->ReadDataAvailable; + if (lpcbRead) *lpcbRead = read_size; + if (lpcbMessage) *lpcbMessage = 0; /* FIXME */ + if (lpvBuffer) memcpy( lpvBuffer, buffer->Data, read_size ); } - if (!avail) /* check for closed pipe */ - { - struct pollfd pollfd; - pollfd.fd = fd; - pollfd.events = POLLIN; - pollfd.revents = 0; - switch (poll( &pollfd, 1, 0 )) - { - case 0: - break; - case 1: /* got something */ - if (!(pollfd.revents & (POLLHUP | POLLERR))) break; - TRACE("POLLHUP | POLLERR\n"); - /* fall through */ - case -1: - wine_server_release_fd( hPipe, fd ); - SetLastError(ERROR_BROKEN_PIPE); - return FALSE; - } - } - TRACE(" 0x%08x bytes available\n", avail ); - ret = TRUE; - if (lpcbAvail) - *lpcbAvail = avail; - if (lpcbRead) - *lpcbRead = 0; - if (avail && lpvBuffer && cbBuffer) - { - int readbytes = (avail < cbBuffer) ? avail : cbBuffer; - readbytes = recv(fd, lpvBuffer, readbytes, MSG_PEEK); - if (readbytes < 0) - { - WARN("failed to peek socket (%d)\n", errno); - ret = FALSE; - } - else if (lpcbRead) - *lpcbRead = readbytes; - } - wine_server_release_fd( hPipe, fd ); - return ret; -#endif /* defined(FIONREAD) */ + else SetLastError( RtlNtStatusToDosError(status) ); - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - FIXME("function not implemented\n"); - return FALSE; + if (buffer != &local_buffer) HeapFree( GetProcessHeap(), 0, buffer ); + return !status; } /*********************************************************************** diff --git a/dlls/ntdll/file.c b/dlls/ntdll/file.c index 18a0e093593..a2157d3c75a 100644 --- a/dlls/ntdll/file.c +++ b/dlls/ntdll/file.c @@ -42,6 +42,15 @@ #ifdef HAVE_SYS_TIME_H # include #endif +#ifdef HAVE_POLL_H +#include +#endif +#ifdef HAVE_SYS_POLL_H +#include +#endif +#ifdef HAVE_SYS_SOCKET_H +#include +#endif #ifdef HAVE_UTIME_H # include #endif @@ -1014,6 +1023,71 @@ NTSTATUS WINAPI NtFsControlFile(HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc } break; + case FSCTL_PIPE_PEEK: + { + FILE_PIPE_PEEK_BUFFER *buffer = out_buffer; + int avail = 0, fd, flags; + + if (out_size < FIELD_OFFSET( FILE_PIPE_PEEK_BUFFER, Data )) + { + io->u.Status = STATUS_INFO_LENGTH_MISMATCH; + break; + } + + if ((io->u.Status = wine_server_handle_to_fd( handle, FILE_READ_DATA, &fd, &flags ))) + break; + + if (flags & FD_FLAG_RECV_SHUTDOWN) + { + wine_server_release_fd( handle, fd ); + io->u.Status = STATUS_PIPE_DISCONNECTED; + break; + } + +#ifdef FIONREAD + if (ioctl( fd, FIONREAD, &avail ) != 0) + { + TRACE("FIONREAD failed reason: %s\n",strerror(errno)); + wine_server_release_fd( handle, fd ); + io->u.Status = FILE_GetNtStatus(); + break; + } +#endif + if (!avail) /* check for closed pipe */ + { + struct pollfd pollfd; + int ret; + + pollfd.fd = fd; + pollfd.events = POLLIN; + pollfd.revents = 0; + ret = poll( &pollfd, 1, 0 ); + if (ret == -1 || (ret == 1 && (pollfd.revents & (POLLHUP|POLLERR)))) + { + wine_server_release_fd( handle, fd ); + io->u.Status = STATUS_PIPE_BROKEN; + break; + } + } + buffer->NamedPipeState = 0; /* FIXME */ + buffer->ReadDataAvailable = avail; + buffer->NumberOfMessages = 0; /* FIXME */ + buffer->MessageLength = 0; /* FIXME */ + io->Information = FIELD_OFFSET( FILE_PIPE_PEEK_BUFFER, Data ); + io->u.Status = STATUS_SUCCESS; + if (avail) + { + ULONG data_size = out_size - FIELD_OFFSET( FILE_PIPE_PEEK_BUFFER, Data ); + if (data_size) + { + int res = recv( fd, buffer->Data, data_size, MSG_PEEK ); + if (res >= 0) io->Information += res; + } + } + wine_server_release_fd( handle, fd ); + } + break; + case FSCTL_PIPE_DISCONNECT: SERVER_START_REQ(disconnect_named_pipe) { diff --git a/include/winioctl.h b/include/winioctl.h index 161d8b7355e..a54c5a588aa 100644 --- a/include/winioctl.h +++ b/include/winioctl.h @@ -411,6 +411,14 @@ typedef struct _FILE_PIPE_WAIT_FOR_BUFFER { WCHAR Name[1]; } FILE_PIPE_WAIT_FOR_BUFFER, *PFILE_PIPE_WAIT_FOR_BUFFER; +typedef struct _FILE_PIPE_PEEK_BUFFER { + ULONG NamedPipeState; + ULONG ReadDataAvailable; + ULONG NumberOfMessages; + ULONG MessageLength; + CHAR Data[1]; +} FILE_PIPE_PEEK_BUFFER, *PFILE_PIPE_PEEK_BUFFER; + /* Device GUIDs */ #ifdef DEFINE_GUID