Fixed ReadFile() semantics when reading asynchronously on sockets.

Provide more accurate status codes than STATUS_UNSUCCESSFUL.
This commit is contained in:
Martin Wilck 2002-04-25 22:58:59 +00:00 committed by Alexandre Julliard
parent 894b188fcf
commit 9ca4285a9f
4 changed files with 65 additions and 15 deletions

View File

@ -115,6 +115,7 @@ typedef struct async_fileio
LPOVERLAPPED_COMPLETION_ROUTINE completion_func; LPOVERLAPPED_COMPLETION_ROUTINE completion_func;
char *buffer; char *buffer;
int count; int count;
enum fd_type fd_type;
} async_fileio; } async_fileio;
static DWORD fileio_get_async_status (const struct async_private *ovp) static DWORD fileio_get_async_status (const struct async_private *ovp)
@ -208,6 +209,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 * FILE_SetDosError
* *
@ -1460,10 +1497,15 @@ static void FILE_AsyncReadService(async_private *ovp)
/* check to see if the data is ready (non-blocking) */ /* check to see if the data is ready (non-blocking) */
result = pread (ovp->fd, &fileio->buffer[already], fileio->count - already, if ( fileio->fd_type == FD_TYPE_SOCKET )
OVERLAPPED_OFFSET (lpOverlapped) + already);
if ((result < 0) && (errno == ESPIPE))
result = read (ovp->fd, &fileio->buffer[already], fileio->count - already); 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))) 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 */ /* check to see if the transfer is complete */
if(result<0) if(result<0)
{ {
TRACE("read returned errno %d\n",errno); r = FILE_GetNtStatus ();
r = STATUS_UNSUCCESSFUL;
goto async_end; goto async_end;
} }
lpOverlapped->InternalHigh += result; lpOverlapped->InternalHigh += result;
TRACE("read %d more bytes %ld/%d so far\n",result,lpOverlapped->InternalHigh,fileio->count); TRACE("read %d more bytes %ld/%d so far\n",result,lpOverlapped->InternalHigh,fileio->count);
if(lpOverlapped->InternalHigh < fileio->count) if(lpOverlapped->InternalHigh >= fileio->count || fileio->fd_type == FD_TYPE_SOCKET )
r = STATUS_PENDING;
else
r = STATUS_SUCCESS; r = STATUS_SUCCESS;
else
r = STATUS_PENDING;
async_end: async_end:
lpOverlapped->Internal = r; lpOverlapped->Internal = r;
@ -1545,6 +1586,7 @@ static BOOL FILE_ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead,
ovp->count = bytesToRead; ovp->count = bytesToRead;
ovp->completion_func = lpCompletionRoutine; ovp->completion_func = lpCompletionRoutine;
ovp->buffer = buffer; ovp->buffer = buffer;
ovp->fd_type = type;
return !register_new_async (&ovp->async); return !register_new_async (&ovp->async);
@ -1684,10 +1726,15 @@ static void FILE_AsyncWriteService(struct async_private *ovp)
/* write some data (non-blocking) */ /* write some data (non-blocking) */
result = pwrite(ovp->fd, &fileio->buffer[already], fileio->count - already, if ( fileio->fd_type == FD_TYPE_SOCKET )
OVERLAPPED_OFFSET (lpOverlapped) + already);
if ((result < 0) && (errno == ESPIPE))
result = write(ovp->fd, &fileio->buffer[already], fileio->count - already); 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))) 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 */ /* check to see if the transfer is complete */
if(result<0) if(result<0)
{ {
r = STATUS_UNSUCCESSFUL; r = FILE_GetNtStatus ();
goto async_end; goto async_end;
} }
@ -1728,8 +1775,8 @@ static BOOL FILE_WriteFileEx(HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
int flags; int flags;
enum fd_type type; enum fd_type type;
TRACE("file %d to buf %p num %ld %p func %p stub\n", TRACE("file %d to buf %p num %ld %p func %p handle %d\n",
hFile, buffer, bytesToWrite, overlapped, lpCompletionRoutine); hFile, buffer, bytesToWrite, overlapped, lpCompletionRoutine, hEvent);
if (overlapped == NULL) if (overlapped == NULL)
{ {
@ -1767,6 +1814,7 @@ static BOOL FILE_WriteFileEx(HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite,
ovp->buffer = (LPVOID) buffer; ovp->buffer = (LPVOID) buffer;
ovp->count = bytesToWrite; ovp->count = bytesToWrite;
ovp->completion_func = lpCompletionRoutine; ovp->completion_func = lpCompletionRoutine;
ovp->fd_type = type;
return !register_new_async (&ovp->async); return !register_new_async (&ovp->async);

View File

@ -791,6 +791,7 @@ enum fd_type
FD_TYPE_INVALID, FD_TYPE_INVALID,
FD_TYPE_DEFAULT, FD_TYPE_DEFAULT,
FD_TYPE_CONSOLE, FD_TYPE_CONSOLE,
FD_TYPE_SOCKET,
FD_TYPE_SMB FD_TYPE_SMB
}; };
#define FD_FLAG_OVERLAPPED 0x01 #define FD_FLAG_OVERLAPPED 0x01

View File

@ -608,6 +608,7 @@ enum fd_type
FD_TYPE_INVALID, FD_TYPE_INVALID,
FD_TYPE_DEFAULT, FD_TYPE_DEFAULT,
FD_TYPE_CONSOLE, FD_TYPE_CONSOLE,
FD_TYPE_SOCKET,
FD_TYPE_SMB FD_TYPE_SMB
}; };
#define FD_FLAG_OVERLAPPED 0x01 #define FD_FLAG_OVERLAPPED 0x01

View File

@ -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->flags & WSA_FLAG_OVERLAPPED) *flags |= FD_FLAG_OVERLAPPED;
if ( !(sock->state & FD_READ ) ) *flags |= FD_FLAG_RECV_SHUTDOWN; if ( !(sock->state & FD_READ ) ) *flags |= FD_FLAG_RECV_SHUTDOWN;
if ( !(sock->state & FD_WRITE ) ) *flags |= FD_FLAG_SEND_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) static void sock_queue_async(struct object *obj, void *ptr, unsigned int status, int type, int count)