Fixed ReadFile() semantics when reading asynchronously on sockets.
Provide more accurate status codes than STATUS_UNSUCCESSFUL.
diff --git a/files/file.c b/files/file.c
index e0b8b49..65b264c 100644
--- a/files/file.c
+++ b/files/file.c
@@ -115,6 +115,7 @@
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 @@
/***********************************************************************
+ * 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 @@
/* 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 @@
/* 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 @@
ovp->count = bytesToRead;
ovp->completion_func = lpCompletionRoutine;
ovp->buffer = buffer;
+ ovp->fd_type = type;
return !register_new_async (&ovp->async);
@@ -1684,10 +1726,15 @@
/* 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 @@
/* check to see if the transfer is complete */
if(result<0)
{
- r = STATUS_UNSUCCESSFUL;
+ r = FILE_GetNtStatus ();
goto async_end;
}
@@ -1728,8 +1775,8 @@
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 @@
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 f6d5d4a..ddc2afd 100644
--- a/include/wine/server_protocol.h
+++ b/include/wine/server_protocol.h
@@ -791,6 +791,7 @@
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 e75373e..e1d49c3 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -608,6 +608,7 @@
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 06db1ac..d8362af 100644
--- a/server/sock.c
+++ b/server/sock.c
@@ -421,7 +421,7 @@
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)