From 9ca4285a9f3e889c9490b9d123921cde981c4ef4 Mon Sep 17 00:00:00 2001 From: Martin Wilck Date: Thu, 25 Apr 2002 22:58:59 +0000 Subject: [PATCH] Fixed ReadFile() semantics when reading asynchronously on sockets. Provide more accurate status codes than STATUS_UNSUCCESSFUL. --- files/file.c | 76 ++++++++++++++++++++++++++++++++++-------- include/wine/server_protocol.h | 1 + server/protocol.def | 1 + server/sock.c | 2 +- 4 files changed, 65 insertions(+), 15 deletions(-) diff --git a/files/file.c b/files/file.c index e0b8b4920e4..65b264c9b2f 100644 --- a/files/file.c +++ b/files/file.c @@ -115,6 +115,7 @@ typedef struct async_fileio LPOVERLAPPED_COMPLETION_ROUTINE completion_func; char *buffer; int count; + enum fd_type fd_type; } async_fileio; static DWORD fileio_get_async_status (const struct async_private *ovp) @@ -209,6 +210,42 @@ int FILE_strncasecmp( const char *str1, const char *str2, int len ) /*********************************************************************** + * FILE_GetNtStatus(void) + * + * Retrieve the Nt Status code from errno. + * Try to be consistent with FILE_SetDosError(). + */ +DWORD FILE_GetNtStatus(void) +{ + int err = errno; + DWORD nt; + TRACE ( "errno = %d\n", errno ); + switch ( err ) + { + case EAGAIN: nt = STATUS_SHARING_VIOLATION; break; + case EBADF: nt = STATUS_INVALID_HANDLE; break; + case ENOSPC: nt = STATUS_DISK_FULL; break; + case EPERM: + case EROFS: + case EACCES: nt = STATUS_ACCESS_DENIED; break; + case ENOENT: nt = STATUS_SHARING_VIOLATION; break; + case EISDIR: nt = STATUS_FILE_IS_A_DIRECTORY; break; + case EMFILE: + case ENFILE: nt = STATUS_NO_MORE_FILES; break; + case EINVAL: + case ENOTEMPTY: nt = STATUS_DIRECTORY_NOT_EMPTY; break; + case EPIPE: nt = STATUS_PIPE_BROKEN; break; + case ENOEXEC: /* ?? */ + case ESPIPE: /* ?? */ + case EEXIST: /* ?? */ + default: + FIXME ( "Converting errno %d to STATUS_UNSUCCESSFUL\n", err ); + nt = STATUS_UNSUCCESSFUL; + } + return nt; +} + +/*********************************************************************** * FILE_SetDosError * * Set the DOS error code from errno. @@ -1460,10 +1497,15 @@ static void FILE_AsyncReadService(async_private *ovp) /* check to see if the data is ready (non-blocking) */ - result = pread (ovp->fd, &fileio->buffer[already], fileio->count - already, - OVERLAPPED_OFFSET (lpOverlapped) + already); - if ((result < 0) && (errno == ESPIPE)) + if ( fileio->fd_type == FD_TYPE_SOCKET ) result = read (ovp->fd, &fileio->buffer[already], fileio->count - already); + else + { + result = pread (ovp->fd, &fileio->buffer[already], fileio->count - already, + OVERLAPPED_OFFSET (lpOverlapped) + already); + if ((result < 0) && (errno == ESPIPE)) + result = read (ovp->fd, &fileio->buffer[already], fileio->count - already); + } if ( (result<0) && ((errno == EAGAIN) || (errno == EINTR))) { @@ -1475,18 +1517,17 @@ static void FILE_AsyncReadService(async_private *ovp) /* check to see if the transfer is complete */ if(result<0) { - TRACE("read returned errno %d\n",errno); - r = STATUS_UNSUCCESSFUL; + r = FILE_GetNtStatus (); goto async_end; } lpOverlapped->InternalHigh += result; TRACE("read %d more bytes %ld/%d so far\n",result,lpOverlapped->InternalHigh,fileio->count); - if(lpOverlapped->InternalHigh < fileio->count) - r = STATUS_PENDING; - else + if(lpOverlapped->InternalHigh >= fileio->count || fileio->fd_type == FD_TYPE_SOCKET ) r = STATUS_SUCCESS; + else + r = STATUS_PENDING; async_end: lpOverlapped->Internal = r; @@ -1545,6 +1586,7 @@ static BOOL FILE_ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead, ovp->count = bytesToRead; ovp->completion_func = lpCompletionRoutine; ovp->buffer = buffer; + ovp->fd_type = type; return !register_new_async (&ovp->async); @@ -1684,10 +1726,15 @@ static void FILE_AsyncWriteService(struct async_private *ovp) /* write some data (non-blocking) */ - result = pwrite(ovp->fd, &fileio->buffer[already], fileio->count - already, - OVERLAPPED_OFFSET (lpOverlapped) + already); - if ((result < 0) && (errno == ESPIPE)) + if ( fileio->fd_type == FD_TYPE_SOCKET ) result = write(ovp->fd, &fileio->buffer[already], fileio->count - already); + else + { + result = pwrite(ovp->fd, &fileio->buffer[already], fileio->count - already, + OVERLAPPED_OFFSET (lpOverlapped) + already); + if ((result < 0) && (errno == ESPIPE)) + result = write(ovp->fd, &fileio->buffer[already], fileio->count - already); + } if ( (result<0) && ((errno == EAGAIN) || (errno == EINTR))) { @@ -1698,7 +1745,7 @@ static void FILE_AsyncWriteService(struct async_private *ovp) /* check to see if the transfer is complete */ if(result<0) { - r = STATUS_UNSUCCESSFUL; + r = FILE_GetNtStatus (); goto async_end; } @@ -1728,8 +1775,8 @@ static BOOL FILE_WriteFileEx(HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite, int flags; enum fd_type type; - TRACE("file %d to buf %p num %ld %p func %p stub\n", - hFile, buffer, bytesToWrite, overlapped, lpCompletionRoutine); + TRACE("file %d to buf %p num %ld %p func %p handle %d\n", + hFile, buffer, bytesToWrite, overlapped, lpCompletionRoutine, hEvent); if (overlapped == NULL) { @@ -1767,6 +1814,7 @@ static BOOL FILE_WriteFileEx(HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite, ovp->buffer = (LPVOID) buffer; ovp->count = bytesToWrite; ovp->completion_func = lpCompletionRoutine; + ovp->fd_type = type; return !register_new_async (&ovp->async); diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h index f6d5d4aba56..ddc2afde232 100644 --- a/include/wine/server_protocol.h +++ b/include/wine/server_protocol.h @@ -791,6 +791,7 @@ enum fd_type FD_TYPE_INVALID, FD_TYPE_DEFAULT, FD_TYPE_CONSOLE, + FD_TYPE_SOCKET, FD_TYPE_SMB }; #define FD_FLAG_OVERLAPPED 0x01 diff --git a/server/protocol.def b/server/protocol.def index e75373eaefd..e1d49c31646 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -608,6 +608,7 @@ enum fd_type FD_TYPE_INVALID, FD_TYPE_DEFAULT, FD_TYPE_CONSOLE, + FD_TYPE_SOCKET, FD_TYPE_SMB }; #define FD_FLAG_OVERLAPPED 0x01 diff --git a/server/sock.c b/server/sock.c index 06db1aca4c0..d8362afcccd 100644 --- a/server/sock.c +++ b/server/sock.c @@ -421,7 +421,7 @@ static int sock_get_info( struct object *obj, struct get_file_info_reply *reply, if (sock->flags & WSA_FLAG_OVERLAPPED) *flags |= FD_FLAG_OVERLAPPED; if ( !(sock->state & FD_READ ) ) *flags |= FD_FLAG_RECV_SHUTDOWN; if ( !(sock->state & FD_WRITE ) ) *flags |= FD_FLAG_SEND_SHUTDOWN; - return FD_TYPE_DEFAULT; + return FD_TYPE_SOCKET; } static void sock_queue_async(struct object *obj, void *ptr, unsigned int status, int type, int count) -- 2.11.4.GIT