Fixed ReadFile() semantics when reading asynchronously on sockets.
Provide more accurate status codes than STATUS_UNSUCCESSFUL.
This commit is contained in:
parent
894b188fcf
commit
9ca4285a9f
76
files/file.c
76
files/file.c
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
Loading…
Reference in New Issue