diff --git a/dlls/kernel/comm.c b/dlls/kernel/comm.c index e6468422f79..ec9aed25fe3 100644 --- a/dlls/kernel/comm.c +++ b/dlls/kernel/comm.c @@ -84,6 +84,8 @@ # include #endif +#define NONAMELESSUNION +#define NONAMELESSSTRUCT #include "winbase.h" #include "winerror.h" @@ -104,15 +106,11 @@ WINE_DEFAULT_DEBUG_CHANNEL(comm); * Asynchronous I/O for asynchronous wait requests * */ -static DWORD commio_get_async_status (const async_private *ovp); static DWORD commio_get_async_count (const async_private *ovp); -static void commio_set_async_status (async_private *ovp, const DWORD status); static void commio_async_cleanup (async_private *ovp); static async_ops commio_async_ops = { - commio_get_async_status, /* get_status */ - commio_set_async_status, /* set_status */ commio_get_async_count, /* get_count */ NULL, /* call_completion */ commio_async_cleanup /* cleanup */ @@ -121,20 +119,9 @@ static async_ops commio_async_ops = typedef struct async_commio { struct async_private async; - LPOVERLAPPED lpOverlapped; char *buffer; } async_commio; -static DWORD commio_get_async_status (const struct async_private *ovp) -{ - return ((async_commio*) ovp)->lpOverlapped->Internal; -} - -static void commio_set_async_status (async_private *ovp, const DWORD status) -{ - ((async_commio*) ovp)->lpOverlapped->Internal = status; -} - static DWORD commio_get_async_count (const struct async_private *ovp) { return 0; @@ -1664,14 +1651,14 @@ BOOL WINAPI GetCommModemStatus( static void COMM_WaitCommEventService(async_private *ovp) { async_commio *commio = (async_commio*) ovp; - LPOVERLAPPED lpOverlapped = commio->lpOverlapped; + IO_STATUS_BLOCK* iosb = commio->async.iosb; - TRACE("overlapped %p\n",lpOverlapped); + TRACE("iosb %p\n",iosb); /* FIXME: detect other events */ *commio->buffer = EV_RXCHAR; - lpOverlapped->Internal = STATUS_SUCCESS; + iosb->u.Status = STATUS_SUCCESS; } @@ -1714,7 +1701,7 @@ static BOOL COMM_WaitCommEvent( ovp->async.type = ASYNC_TYPE_WAIT; ovp->async.func = COMM_WaitCommEventService; ovp->async.event = lpOverlapped->hEvent; - ovp->lpOverlapped = lpOverlapped; + ovp->async.iosb = (IO_STATUS_BLOCK*)lpOverlapped; ovp->buffer = (char *)lpdwEvents; lpOverlapped->InternalHigh = 0; diff --git a/dlls/kernel/file.c b/dlls/kernel/file.c index dca832c604f..d1b812278b8 100644 --- a/dlls/kernel/file.c +++ b/dlls/kernel/file.c @@ -32,11 +32,12 @@ #include "windef.h" #include "winbase.h" #include "winternl.h" - +#include "wincon.h" #include "kernel_private.h" #include "wine/unicode.h" #include "wine/debug.h" +#include "async.h" WINE_DEFAULT_DEBUG_CHANNEL(file); @@ -44,6 +45,106 @@ WINE_DEFAULT_DEBUG_CHANNEL(file); * Operations on file handles * **************************************************************************/ +/*********************************************************************** + * GetOverlappedResult (KERNEL32.@) + * + * Check the result of an Asynchronous data transfer from a file. + * + * Parameters + * HANDLE hFile [in] handle of file to check on + * LPOVERLAPPED lpOverlapped [in/out] pointer to overlapped + * LPDWORD lpTransferred [in/out] number of bytes transferred + * BOOL bWait [in] wait for the transfer to complete ? + * + * RETURNS + * TRUE on success + * FALSE on failure + * + * If successful (and relevant) lpTransferred will hold the number of + * bytes transferred during the async operation. + * + * BUGS + * + * Currently only works for WaitCommEvent, ReadFile, WriteFile + * with communications ports. + * + */ +BOOL WINAPI GetOverlappedResult(HANDLE hFile, LPOVERLAPPED lpOverlapped, + LPDWORD lpTransferred, BOOL bWait) +{ + DWORD r; + + TRACE("(%p %p %p %x)\n", hFile, lpOverlapped, lpTransferred, bWait); + + if (lpOverlapped==NULL) + { + ERR("lpOverlapped was null\n"); + return FALSE; + } + if (!lpOverlapped->hEvent) + { + ERR("lpOverlapped->hEvent was null\n"); + return FALSE; + } + + if ( bWait ) + { + do { + TRACE("waiting on %p\n",lpOverlapped); + r = WaitForSingleObjectEx(lpOverlapped->hEvent, INFINITE, TRUE); + TRACE("wait on %p returned %ld\n",lpOverlapped,r); + } while (r==STATUS_USER_APC); + } + else if ( lpOverlapped->Internal == STATUS_PENDING ) + { + /* Wait in order to give APCs a chance to run. */ + /* This is cheating, so we must set the event again in case of success - + it may be a non-manual reset event. */ + do { + TRACE("waiting on %p\n",lpOverlapped); + r = WaitForSingleObjectEx(lpOverlapped->hEvent, 0, TRUE); + TRACE("wait on %p returned %ld\n",lpOverlapped,r); + } while (r==STATUS_USER_APC); + if ( r == WAIT_OBJECT_0 ) + NtSetEvent ( lpOverlapped->hEvent, NULL ); + } + + if(lpTransferred) + *lpTransferred = lpOverlapped->InternalHigh; + + switch ( lpOverlapped->Internal ) + { + case STATUS_SUCCESS: + return TRUE; + case STATUS_PENDING: + SetLastError ( ERROR_IO_INCOMPLETE ); + if ( bWait ) ERR ("PENDING status after waiting!\n"); + return FALSE; + default: + SetLastError ( RtlNtStatusToDosError ( lpOverlapped->Internal ) ); + return FALSE; + } +} + +/*********************************************************************** + * CancelIo (KERNEL32.@) + */ +BOOL WINAPI CancelIo(HANDLE handle) +{ + async_private *ovp,*t; + + TRACE("handle = %p\n",handle); + + for (ovp = NtCurrentTeb()->pending_list; ovp; ovp = t) + { + t = ovp->next; + if ( ovp->handle == handle ) + cancel_async ( ovp ); + } + WaitForMultipleObjectsEx(0,NULL,FALSE,1,TRUE); + return TRUE; +} + /*********************************************************************** * _hread (KERNEL32.@) */ diff --git a/dlls/ntdll/file.c b/dlls/ntdll/file.c index d57bc1d13b1..7e7f665e8fd 100644 --- a/dlls/ntdll/file.c +++ b/dlls/ntdll/file.c @@ -23,6 +23,7 @@ #include #include #include +#include #ifdef HAVE_UNISTD_H # include #endif @@ -35,15 +36,16 @@ #include "wine/unicode.h" #include "wine/debug.h" #include "wine/server.h" +#include "async.h" #include "ntdll_misc.h" #include "file.h" /* FIXME */ +#include "../files/smb.h" #include "winternl.h" #include "winioctl.h" WINE_DEFAULT_DEBUG_CHANNEL(ntdll); - /************************************************************************** * NtOpenFile [NTDLL.@] * ZwOpenFile [NTDLL.@] @@ -154,31 +156,175 @@ NTSTATUS WINAPI NtCreateFile( return 0; } -/* set the last error depending on errno */ -NTSTATUS NTFILE_errno_to_status(int val) +/*********************************************************************** + * Asynchronous file I/O * + */ +static DWORD fileio_get_async_count(const async_private *ovp); +static void CALLBACK fileio_call_completion_func(ULONG_PTR data); +static void fileio_async_cleanup(async_private *ovp); + +static async_ops fileio_async_ops = { - switch (val) + fileio_get_async_count, /* get_count */ + fileio_call_completion_func, /* call_completion */ + fileio_async_cleanup /* cleanup */ +}; + +static async_ops fileio_nocomp_async_ops = +{ + fileio_get_async_count, /* get_count */ + NULL, /* call_completion */ + fileio_async_cleanup /* cleanup */ +}; + +typedef struct async_fileio +{ + struct async_private async; + PIO_APC_ROUTINE apc; + void* apc_user; + char *buffer; + unsigned int count; + unsigned long offset; + enum fd_type fd_type; +} async_fileio; + +static DWORD fileio_get_async_count(const struct async_private *ovp) +{ + async_fileio *fileio = (async_fileio*) ovp; + + if (fileio->count < fileio->async.iosb->Information) + return 0; + return fileio->count - fileio->async.iosb->Information; +} + +static void CALLBACK fileio_call_completion_func(ULONG_PTR data) +{ + async_fileio *ovp = (async_fileio*) data; + TRACE("data: %p\n", ovp); + + ovp->apc( ovp->apc_user, ovp->async.iosb, ovp->async.iosb->Information ); + + fileio_async_cleanup( &ovp->async ); +} + +static void fileio_async_cleanup( struct async_private *ovp ) +{ + RtlFreeHeap( ntdll_get_process_heap(), 0, ovp ); +} + +/*********************************************************************** + * FILE_GetUnixHandleType + * + * Retrieve the Unix handle corresponding to a file handle. + * Returns -1 on failure. + */ +static int FILE_GetUnixHandleType( HANDLE handle, DWORD access, enum fd_type *type, int *flags_ptr, int *fd ) +{ + int ret, flags; + + *fd = -1; + ret = wine_server_handle_to_fd( handle, access, fd, type, &flags ); + if (flags_ptr) *flags_ptr = flags; + if (!ret && (((access & GENERIC_READ) && (flags & FD_FLAG_RECV_SHUTDOWN)) || + ((access & GENERIC_WRITE) && (flags & FD_FLAG_SEND_SHUTDOWN)))) { - case EAGAIN: return ( STATUS_SHARING_VIOLATION ); - case ESPIPE: - case EBADF: return ( STATUS_INVALID_HANDLE ); - case ENOSPC: return ( STATUS_DISK_FULL ); - case EACCES: - case ESRCH: - case EPERM: return ( STATUS_ACCESS_DENIED ); - case EROFS: return ( STATUS_MEDIA_WRITE_PROTECTED ); - case EBUSY: return ( STATUS_FILE_LOCK_CONFLICT ); - case ENOENT: return ( STATUS_NO_SUCH_FILE ); - case EISDIR: return ( STATUS_FILE_IS_A_DIRECTORY ); - case ENFILE: - case EMFILE: return ( STATUS_NO_MORE_FILES ); - case EEXIST: return ( STATUS_OBJECT_NAME_COLLISION ); - case EINVAL: return ( STATUS_INVALID_PARAMETER ); - case ENOTEMPTY: return ( STATUS_DIRECTORY_NOT_EMPTY ); - case EIO: return ( STATUS_ACCESS_VIOLATION ); + close(*fd); + ret = STATUS_PIPE_DISCONNECTED; } - perror("file_set_error"); - return ( STATUS_INVALID_PARAMETER ); + return ret; +} + +/*********************************************************************** + * FILE_GetNtStatus(void) + * + * Retrieve the Nt Status code from errno. + * Try to be consistent with FILE_SetDosError(). + */ +static 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_AsyncReadService (INTERNAL) + * + * This function is called while the client is waiting on the + * server, so we can't make any server calls here. + */ +static void FILE_AsyncReadService(async_private *ovp) +{ + async_fileio *fileio = (async_fileio*) ovp; + IO_STATUS_BLOCK* io_status = fileio->async.iosb; + int result; + int already = io_status->Information; + + TRACE("%p %p\n", io_status, fileio->buffer ); + + /* check to see if the data is ready (non-blocking) */ + + 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, + fileio->offset + already); + if ((result < 0) && (errno == ESPIPE)) + result = read(ovp->fd, &fileio->buffer[already], fileio->count - already); + } + + if ((result < 0) && ((errno == EAGAIN) || (errno == EINTR))) + { + TRACE("Deferred read %d\n",errno); + io_status->u.Status = STATUS_PENDING; + return; + } + + /* check to see if the transfer is complete */ + if (result < 0) + { + io_status->u.Status = FILE_GetNtStatus(); + return; + } + else if (result == 0) + { + io_status->u.Status = io_status->Information ? STATUS_SUCCESS : STATUS_END_OF_FILE; + return; + } + + io_status->Information += result; + if (io_status->Information >= fileio->count || fileio->fd_type == FD_TYPE_SOCKET ) + io_status->u.Status = STATUS_SUCCESS; + else + io_status->u.Status = STATUS_PENDING; + + TRACE("read %d more bytes %ld/%d so far\n", + result, io_status->Information, fileio->count); } @@ -187,67 +333,164 @@ NTSTATUS NTFILE_errno_to_status(int val) * ZwReadFile [NTDLL.@] * * Parameters - * HANDLE32 FileHandle - * HANDLE32 Event OPTIONAL - * PIO_APC_ROUTINE ApcRoutine OPTIONAL - * PVOID ApcContext OPTIONAL - * PIO_STATUS_BLOCK IoStatusBlock - * PVOID Buffer - * ULONG Length - * PLARGE_INTEGER ByteOffset OPTIONAL - * PULONG Key OPTIONAL + * HANDLE32 hFile + * HANDLE32 hEvent OPTIONAL + * PIO_APC_ROUTINE apc OPTIONAL + * PVOID apc_user OPTIONAL + * PIO_STATUS_BLOCK io_status + * PVOID buffer + * ULONG length + * PLARGE_INTEGER offset OPTIONAL + * PULONG key OPTIONAL * * IoStatusBlock->Information contains the number of bytes read on return. */ -NTSTATUS WINAPI NtReadFile ( - HANDLE FileHandle, - HANDLE EventHandle, - PIO_APC_ROUTINE ApcRoutine, - PVOID ApcContext, - PIO_STATUS_BLOCK IoStatusBlock, - PVOID Buffer, - ULONG Length, - PLARGE_INTEGER ByteOffset, - PULONG Key) +NTSTATUS WINAPI NtReadFile(HANDLE hFile, HANDLE hEvent, + PIO_APC_ROUTINE apc, void* apc_user, + PIO_STATUS_BLOCK io_status, void* buffer, ULONG length, + PLARGE_INTEGER offset, PULONG key) { - int fd, result, flags, ret; - enum fd_type type; + int unix_handle, flags; + enum fd_type type; - FIXME("(%p,%p,%p,%p,%p,%p,0x%08lx,%p,%p),partial stub!\n", - FileHandle,EventHandle,ApcRoutine,ApcContext,IoStatusBlock,Buffer,Length,ByteOffset,Key); + TRACE("(%p,%p,%p,%p,%p,%p,0x%08lx,%p,%p),partial stub!\n", + hFile,hEvent,apc,apc_user,io_status,buffer,length,offset,key); - if (IsBadWritePtr( Buffer, Length ) || - IsBadWritePtr( IoStatusBlock, sizeof(*IoStatusBlock)) || - IsBadWritePtr( ByteOffset, sizeof(*ByteOffset)) ) - return STATUS_ACCESS_VIOLATION; + io_status->Information = 0; + io_status->u.Status = FILE_GetUnixHandleType( hFile, GENERIC_READ, &type, &flags, &unix_handle ); + if (io_status->u.Status) return io_status->u.Status; - IoStatusBlock->Information = 0; + if (flags & FD_FLAG_TIMEOUT) + { + if (hEvent) + { + /* this shouldn't happen, but check it */ + FIXME("NIY-hEvent\n"); + return STATUS_NOT_IMPLEMENTED; + } + io_status->u.Status = NtCreateEvent(&hEvent, SYNCHRONIZE, NULL, 0, 0); + if (io_status->u.Status) return io_status->u.Status; + } + + if (flags & (FD_FLAG_OVERLAPPED|FD_FLAG_TIMEOUT)) + { + async_fileio* ovp; - ret = wine_server_handle_to_fd( FileHandle, GENERIC_READ, &fd, &type, &flags ); - if(ret) - return ret; + if (unix_handle < 0) return STATUS_INVALID_HANDLE; - /* FIXME: this code only does synchronous reads so far */ + ovp = RtlAllocateHeap(ntdll_get_process_heap(), 0, sizeof(async_fileio)); + if (!ovp) return STATUS_NO_MEMORY; - /* FIXME: depending on how libc implements this, between two processes - there could be a race condition between the seek and read here */ - do - { - result = pread( fd, Buffer, Length, ByteOffset->QuadPart); - } - while ( (result == -1) && ((errno == EAGAIN) || (errno == EINTR)) ); + ovp->async.ops = (apc ? &fileio_async_ops : &fileio_nocomp_async_ops ); + ovp->async.handle = hFile; + ovp->async.fd = unix_handle; + ovp->async.type = ASYNC_TYPE_READ; + ovp->async.func = FILE_AsyncReadService; + ovp->async.event = hEvent; + ovp->async.iosb = io_status; + ovp->count = length; + ovp->offset = offset->s.LowPart; + if (offset->s.HighPart) FIXME("NIY-high part\n"); + ovp->apc = apc; + ovp->apc_user = apc_user; + ovp->buffer = buffer; + ovp->fd_type = type; - close( fd ); + io_status->Information = 0; + io_status->u.Status = register_new_async(&ovp->async); + if (io_status->u.Status == STATUS_PENDING && hEvent) + { + finish_async(&ovp->async); + close(unix_handle); + } + return io_status->u.Status; + } + switch (type) + { + case FD_TYPE_SMB: + FIXME("NIY-SMB\n"); + close(unix_handle); + return SMB_ReadFile(hFile, buffer, length, io_status); - if (result == -1) - { - return IoStatusBlock->u.Status = NTFILE_errno_to_status(errno); - } + case FD_TYPE_DEFAULT: + /* normal unix files */ + if (unix_handle == -1) return STATUS_INVALID_HANDLE; + break; - IoStatusBlock->Information = result; - IoStatusBlock->u.Status = 0; + default: + FIXME("Unsupported type of fd %d\n", type); + if (unix_handle == -1) close(unix_handle); + return STATUS_INVALID_HANDLE; + } - return STATUS_SUCCESS; + if (offset) + { + FILE_POSITION_INFORMATION fpi; + + fpi.CurrentByteOffset = *offset; + io_status->u.Status = NtSetInformationFile(hFile, io_status, &fpi, sizeof(fpi), + FilePositionInformation); + if (io_status->u.Status) + { + close(unix_handle); + return io_status->u.Status; + } + } + /* code for synchronous reads */ + while ((io_status->Information = read( unix_handle, buffer, length )) == -1) + { + if ((errno == EAGAIN) || (errno == EINTR)) continue; + if (errno == EFAULT) FIXME( "EFAULT handling broken for now\n" ); + io_status->u.Status = FILE_GetNtStatus(); + break; + } + close( unix_handle ); + return io_status->u.Status; +} + +/*********************************************************************** + * FILE_AsyncWriteService (INTERNAL) + * + * This function is called while the client is waiting on the + * server, so we can't make any server calls here. + */ +static void FILE_AsyncWriteService(struct async_private *ovp) +{ + async_fileio *fileio = (async_fileio *) ovp; + PIO_STATUS_BLOCK io_status = fileio->async.iosb; + int result; + int already = io_status->Information; + + TRACE("(%p %p)\n",io_status,fileio->buffer); + + /* write some data (non-blocking) */ + + 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, + fileio->offset + already); + if ((result < 0) && (errno == ESPIPE)) + result = write(ovp->fd, &fileio->buffer[already], fileio->count - already); + } + + if ((result < 0) && ((errno == EAGAIN) || (errno == EINTR))) + { + io_status->u.Status = STATUS_PENDING; + return; + } + + /* check to see if the transfer is complete */ + if (result < 0) + { + io_status->u.Status = FILE_GetNtStatus(); + return; + } + + io_status->Information += result; + io_status->u.Status = (io_status->Information < fileio->count) ? STATUS_PENDING : STATUS_SUCCESS; + TRACE("wrote %d more bytes %ld/%d so far\n",result,io_status->Information,fileio->count); } /****************************************************************************** @@ -255,30 +498,112 @@ NTSTATUS WINAPI NtReadFile ( * ZwWriteFile [NTDLL.@] * * Parameters - * HANDLE32 FileHandle - * HANDLE32 Event OPTIONAL - * PIO_APC_ROUTINE ApcRoutine OPTIONAL - * PVOID ApcContext OPTIONAL - * PIO_STATUS_BLOCK IoStatusBlock - * PVOID Buffer - * ULONG Length - * PLARGE_INTEGER ByteOffset OPTIONAL - * PULONG Key OPTIONAL + * HANDLE32 hFile + * HANDLE32 hEvent OPTIONAL + * PIO_APC_ROUTINE apc OPTIONAL + * PVOID apc_user OPTIONAL + * PIO_STATUS_BLOCK io_status + * PVOID buffer + * ULONG length + * PLARGE_INTEGER offset OPTIONAL + * PULONG key OPTIONAL */ -NTSTATUS WINAPI NtWriteFile ( - HANDLE FileHandle, - HANDLE EventHandle, - PIO_APC_ROUTINE ApcRoutine, - PVOID ApcContext, - PIO_STATUS_BLOCK IoStatusBlock, - PVOID Buffer, - ULONG Length, - PLARGE_INTEGER ByteOffset, - PULONG Key) +NTSTATUS WINAPI NtWriteFile(HANDLE hFile, HANDLE hEvent, + PIO_APC_ROUTINE apc, void* apc_user, + PIO_STATUS_BLOCK io_status, + const void* buffer, ULONG length, + PLARGE_INTEGER offset, PULONG key) { - FIXME("(%p,%p,%p,%p,%p,%p,0x%08lx,%p,%p),stub!\n", - FileHandle,EventHandle,ApcRoutine,ApcContext,IoStatusBlock,Buffer,Length,ByteOffset,Key); - return 0; + int unix_handle, flags; + enum fd_type type; + + TRACE("(%p,%p,%p,%p,%p,%p,0x%08lx,%p,%p)!\n", + hFile,hEvent,apc,apc_user,io_status,buffer,length,offset,key); + + TRACE("(%p,%p,%p,%p,%p,%p,0x%08lx,%p,%p),partial stub!\n", + hFile,hEvent,apc,apc_user,io_status,buffer,length,offset,key); + + io_status->Information = 0; + + io_status->u.Status = FILE_GetUnixHandleType( hFile, GENERIC_WRITE, &type, &flags, &unix_handle ); + if (io_status->u.Status) return io_status->u.Status; + + if (flags & (FD_FLAG_OVERLAPPED|FD_FLAG_TIMEOUT)) + { + async_fileio* ovp; + + if (unix_handle < 0) return STATUS_INVALID_HANDLE; + + ovp = RtlAllocateHeap(ntdll_get_process_heap(), 0, sizeof(async_fileio)); + if (!ovp) return STATUS_NO_MEMORY; + + ovp->async.ops = (apc ? &fileio_async_ops : &fileio_nocomp_async_ops ); + ovp->async.handle = hFile; + ovp->async.fd = unix_handle; + ovp->async.type = ASYNC_TYPE_WRITE; + ovp->async.func = FILE_AsyncWriteService; + ovp->async.event = hEvent; + ovp->async.iosb = io_status; + ovp->count = length; + ovp->offset = offset->s.LowPart; + if (offset->s.HighPart) FIXME("NIY-high part\n"); + ovp->apc = apc; + ovp->apc_user = apc_user; + ovp->buffer = (void*)buffer; + ovp->fd_type = type; + + io_status->Information = 0; + io_status->u.Status = register_new_async(&ovp->async); + if (io_status->u.Status == STATUS_PENDING && hEvent) + { + finish_async(&ovp->async); + close(unix_handle); + } + return io_status->u.Status; + } + switch (type) + { + case FD_TYPE_SMB: + FIXME("NIY-SMB\n"); + close(unix_handle); + return STATUS_NOT_IMPLEMENTED; + + case FD_TYPE_DEFAULT: + /* normal unix files */ + if (unix_handle == -1) return STATUS_INVALID_HANDLE; + break; + + default: + FIXME("Unsupported type of fd %d\n", type); + if (unix_handle == -1) close(unix_handle); + return STATUS_INVALID_HANDLE; + } + + if (offset) + { + FILE_POSITION_INFORMATION fpi; + + fpi.CurrentByteOffset = *offset; + io_status->u.Status = NtSetInformationFile(hFile, io_status, &fpi, sizeof(fpi), + FilePositionInformation); + if (io_status->u.Status) + { + close(unix_handle); + return io_status->u.Status; + } + } + + /* synchronous file write */ + while ((io_status->Information = write( unix_handle, buffer, length )) == -1) + { + if ((errno == EAGAIN) || (errno == EINTR)) continue; + if (errno == EFAULT) FIXME( "EFAULT handling broken for now\n" ); + if (errno == ENOSPC) io_status->u.Status = STATUS_DISK_FULL; + else io_status->u.Status = FILE_GetNtStatus(); + break; + } + close( unix_handle ); + return io_status->u.Status; } /************************************************************************** @@ -665,7 +990,7 @@ NTSTATUS WINAPI NtFlushBuffersFile( HANDLE hFile, IO_STATUS_BLOCK* IoStatusBlock hEvent = reply->event; } SERVER_END_REQ; - if( !ret && hEvent ) + if (!ret && hEvent) { ret = NtWaitForSingleObject( hEvent, FALSE, NULL ); NtClose( hEvent ); diff --git a/dlls/ntdll/sync.c b/dlls/ntdll/sync.c index e00141ee3c2..3b381810bc5 100644 --- a/dlls/ntdll/sync.c +++ b/dlls/ntdll/sync.c @@ -446,9 +446,9 @@ static void WINAPI check_async_list(async_private *asp, DWORD status) if( status != STATUS_ALERTED ) { ovp_status = status; - ovp->ops->set_status (ovp, status); + ovp->iosb->u.Status = status; } - else ovp_status = ovp->ops->get_status (ovp); + else ovp_status = ovp->iosb->u.Status; if( ovp_status == STATUS_PENDING ) ovp->func( ovp ); diff --git a/dlls/winsock/socket.c b/dlls/winsock/socket.c index 794dc3614d2..38dfd872827 100644 --- a/dlls/winsock/socket.c +++ b/dlls/winsock/socket.c @@ -107,6 +107,8 @@ # include #endif +#define NONAMELESSUNION +#define NONAMELESSSTRUCT #include "wine/winbase16.h" #include "wingdi.h" #include "winuser.h" @@ -147,16 +149,12 @@ extern CRITICAL_SECTION csWSgetXXXbyYYY; ****************************************************************/ #include "async.h" -static DWORD ws2_async_get_status (const struct async_private *ovp); static DWORD ws2_async_get_count (const struct async_private *ovp); -static void ws2_async_set_status (struct async_private *ovp, const DWORD status); static void CALLBACK ws2_async_call_completion (ULONG_PTR data); static void ws2_async_cleanup ( struct async_private *ovp ); static struct async_ops ws2_async_ops = { - ws2_async_get_status, - ws2_async_set_status, ws2_async_get_count, ws2_async_call_completion, ws2_async_cleanup @@ -164,8 +162,6 @@ static struct async_ops ws2_async_ops = static struct async_ops ws2_nocomp_async_ops = { - ws2_async_get_status, - ws2_async_set_status, ws2_async_get_count, NULL, /* call_completion */ ws2_async_cleanup @@ -174,12 +170,11 @@ static struct async_ops ws2_nocomp_async_ops = typedef struct ws2_async { async_private async; - LPWSAOVERLAPPED overlapped; LPWSAOVERLAPPED user_overlapped; LPWSAOVERLAPPED_COMPLETION_ROUTINE completion_func; struct iovec *iovec; int n_iovecs; - struct WS_sockaddr *addr; + struct WS_sockaddr *addr; union { int val; /* for send operations */ int *ptr; /* for recv operations */ @@ -1021,31 +1016,24 @@ inline void ws_sockaddr_free(const struct sockaddr* uaddr, const struct WS_socka * Functions for handling overlapped I/O **************************************************************************/ -static DWORD ws2_async_get_status (const struct async_private *ovp) -{ - return ((ws2_async*) ovp)->overlapped->Internal; -} - -static VOID ws2_async_set_status (struct async_private *ovp, const DWORD status) -{ - ((ws2_async*) ovp)->overlapped->Internal = status; -} - static DWORD ws2_async_get_count (const struct async_private *ovp) { - return ((ws2_async*) ovp)->overlapped->InternalHigh; + return ovp->iosb->Information; } static void ws2_async_cleanup ( struct async_private *ap ) { struct ws2_async *as = (struct ws2_async*) ap; - TRACE ( "as: %p uovl %p ovl %p\n", as, as->user_overlapped, as->overlapped ); + TRACE ( "as: %p uovl %p ovl %p\n", as, as->user_overlapped, as->async.iosb ); if ( !as->user_overlapped ) { +#if 0 + /* FIXME: I don't think this is really used */ if ( as->overlapped->hEvent != INVALID_HANDLE_VALUE ) WSACloseEvent ( as->overlapped->hEvent ); - HeapFree ( GetProcessHeap(), 0, as->overlapped ); +#endif + HeapFree ( GetProcessHeap(), 0, as->async.iosb ); } if ( as->iovec ) @@ -1060,8 +1048,8 @@ static void CALLBACK ws2_async_call_completion (ULONG_PTR data) TRACE ("data: %p\n", as); - as->completion_func ( NtStatusToWSAError (as->overlapped->Internal), - as->overlapped->InternalHigh, + as->completion_func ( NtStatusToWSAError (as->async.iosb->u.Status), + as->async.iosb->Information, as->user_overlapped, as->flags ); ws2_async_cleanup ( &as->async ); @@ -1114,22 +1102,22 @@ WS2_make_async (SOCKET s, int fd, int type, struct iovec *iovec, DWORD dwBufferC if ( lpOverlapped ) { - wsa->overlapped = lpOverlapped; + wsa->async.iosb = (IO_STATUS_BLOCK*)lpOverlapped; wsa->async.event = ( lpCompletionRoutine ? INVALID_HANDLE_VALUE : lpOverlapped->hEvent ); } else { - wsa->overlapped = HeapAlloc ( GetProcessHeap(), 0, - sizeof (WSAOVERLAPPED) ); - if ( !wsa->overlapped ) + wsa->async.iosb = HeapAlloc ( GetProcessHeap(), 0, + sizeof (IO_STATUS_BLOCK) ); + if ( !wsa->async.iosb ) goto error; - wsa->async.event = wsa->overlapped->hEvent = INVALID_HANDLE_VALUE; + wsa->async.event = INVALID_HANDLE_VALUE; } - wsa->overlapped->InternalHigh = 0; - TRACE ( "wsa %p, ops %p, h %p, ev %p, fd %d, func %p, ov %p, uov %p, cfunc %p\n", + wsa->async.iosb->Information = 0; + TRACE ( "wsa %p, ops %p, h %p, ev %p, fd %d, func %p, iosb %p, uov %p, cfunc %p\n", wsa, wsa->async.ops, wsa->async.handle, wsa->async.event, wsa->async.fd, wsa->async.func, - wsa->overlapped, wsa->user_overlapped, wsa->completion_func ); + wsa->async.iosb, wsa->user_overlapped, wsa->completion_func ); return wsa; @@ -1220,9 +1208,9 @@ static void WS2_async_recv ( async_private *as ) TRACE ( "async %p\n", wsa ); - if ( wsa->overlapped->Internal != STATUS_PENDING ) + if ( wsa->async.iosb->u.Status != STATUS_PENDING ) { - TRACE ( "status: %ld\n", wsa->overlapped->Internal ); + TRACE ( "status: %ld\n", wsa->async.iosb->u.Status ); return; } @@ -1231,8 +1219,8 @@ static void WS2_async_recv ( async_private *as ) if (result >= 0) { - wsa->overlapped->Internal = STATUS_SUCCESS; - wsa->overlapped->InternalHigh = result; + wsa->async.iosb->u.Status = STATUS_SUCCESS; + wsa->async.iosb->Information = result; TRACE ( "received %d bytes\n", result ); _enable_event ( wsa->async.handle, FD_READ, 0, 0 ); return; @@ -1241,13 +1229,13 @@ static void WS2_async_recv ( async_private *as ) err = wsaErrno (); if ( err == WSAEINTR || err == WSAEWOULDBLOCK ) /* errno: EINTR / EAGAIN */ { - wsa->overlapped->Internal = STATUS_PENDING; + wsa->async.iosb->u.Status = STATUS_PENDING; _enable_event ( wsa->async.handle, FD_READ, 0, 0 ); TRACE ( "still pending\n" ); } else { - wsa->overlapped->Internal = err; + wsa->async.iosb->u.Status = err; TRACE ( "Error: %x\n", err ); } } @@ -1312,9 +1300,9 @@ static void WS2_async_send ( async_private *as ) TRACE ( "async %p\n", wsa ); - if ( wsa->overlapped->Internal != STATUS_PENDING ) + if ( wsa->async.iosb->u.Status != STATUS_PENDING ) { - TRACE ( "status: %ld\n", wsa->overlapped->Internal ); + TRACE ( "status: %ld\n", wsa->async.iosb->u.Status ); return; } @@ -1323,8 +1311,8 @@ static void WS2_async_send ( async_private *as ) if (result >= 0) { - wsa->overlapped->Internal = STATUS_SUCCESS; - wsa->overlapped->InternalHigh = result; + wsa->async.iosb->u.Status = STATUS_SUCCESS; + wsa->async.iosb->Information = result; TRACE ( "sent %d bytes\n", result ); _enable_event ( wsa->async.handle, FD_WRITE, 0, 0 ); return; @@ -1333,7 +1321,7 @@ static void WS2_async_send ( async_private *as ) err = wsaErrno (); if ( err == WSAEINTR ) { - wsa->overlapped->Internal = STATUS_PENDING; + wsa->async.iosb->u.Status = STATUS_PENDING; _enable_event ( wsa->async.handle, FD_WRITE, 0, 0 ); TRACE ( "still pending\n" ); } @@ -1341,7 +1329,7 @@ static void WS2_async_send ( async_private *as ) { /* We set the status to a winsock error code and check for that later in NtStatusToWSAError () */ - wsa->overlapped->Internal = err; + wsa->async.iosb->u.Status = err; TRACE ( "Error: %x\n", err ); } } @@ -1370,9 +1358,9 @@ static void WS2_async_shutdown ( async_private *as ) } if ( err ) - wsa->overlapped->Internal = wsaErrno (); + wsa->async.iosb->u.Status = wsaErrno (); else - wsa->overlapped->Internal = STATUS_SUCCESS; + wsa->async.iosb->u.Status = STATUS_SUCCESS; } /*********************************************************************** @@ -2461,7 +2449,7 @@ INT WINAPI WSASendTo( SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount, err = NtStatusToWSAError ( ret ); if ( !lpOverlapped ) - HeapFree ( GetProcessHeap(), 0, wsa->overlapped ); + HeapFree ( GetProcessHeap(), 0, wsa->async.iosb ); HeapFree ( GetProcessHeap(), 0, wsa ); goto err_free; } @@ -3918,7 +3906,7 @@ INT WINAPI WSARecvFrom( SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount, err = NtStatusToWSAError ( ret ); if ( !lpOverlapped ) - HeapFree ( GetProcessHeap(), 0, wsa->overlapped ); + HeapFree ( GetProcessHeap(), 0, wsa->async.iosb ); HeapFree ( GetProcessHeap(), 0, wsa ); goto err_free; } diff --git a/files/file.c b/files/file.c index e14332bf020..a53ed8d3a2c 100644 --- a/files/file.c +++ b/files/file.c @@ -66,7 +66,6 @@ #include "drive.h" #include "file.h" -#include "async.h" #include "heap.h" #include "msdos.h" #include "wincon.h" @@ -82,87 +81,9 @@ WINE_DEFAULT_DEBUG_CHANNEL(file); #define MAP_ANON MAP_ANONYMOUS #endif -/* Macro to derive file offset from OVERLAPPED struct */ -#define OVERLAPPED_OFFSET(overlapped) ((off_t) (overlapped)->Offset + ((off_t) (overlapped)->OffsetHigh << 32)) - HANDLE dos_handles[DOS_TABLE_SIZE]; mode_t FILE_umask; -extern HANDLE WINAPI FILE_SmbOpen(LPCSTR name); - -/*********************************************************************** - * Asynchronous file I/O * - */ -static DWORD fileio_get_async_status (const async_private *ovp); -static DWORD fileio_get_async_count (const async_private *ovp); -static void fileio_set_async_status (async_private *ovp, const DWORD status); -static void CALLBACK fileio_call_completion_func (ULONG_PTR data); -static void fileio_async_cleanup (async_private *ovp); - -static async_ops fileio_async_ops = -{ - fileio_get_async_status, /* get_status */ - fileio_set_async_status, /* set_status */ - fileio_get_async_count, /* get_count */ - fileio_call_completion_func, /* call_completion */ - fileio_async_cleanup /* cleanup */ -}; - -static async_ops fileio_nocomp_async_ops = -{ - fileio_get_async_status, /* get_status */ - fileio_set_async_status, /* set_status */ - fileio_get_async_count, /* get_count */ - NULL, /* call_completion */ - fileio_async_cleanup /* cleanup */ -}; - -typedef struct async_fileio -{ - struct async_private async; - LPOVERLAPPED lpOverlapped; - LPOVERLAPPED_COMPLETION_ROUTINE completion_func; - char *buffer; - unsigned int count; - enum fd_type fd_type; -} async_fileio; - -static DWORD fileio_get_async_status (const struct async_private *ovp) -{ - return ((async_fileio*) ovp)->lpOverlapped->Internal; -} - -static void fileio_set_async_status (async_private *ovp, const DWORD status) -{ - ((async_fileio*) ovp)->lpOverlapped->Internal = status; -} - -static DWORD fileio_get_async_count (const struct async_private *ovp) -{ - async_fileio *fileio = (async_fileio*) ovp; - - if (fileio->count < fileio->lpOverlapped->InternalHigh) - return 0; - return fileio->count - fileio->lpOverlapped->InternalHigh; -} - -static void CALLBACK fileio_call_completion_func (ULONG_PTR data) -{ - async_fileio *ovp = (async_fileio*) data; - TRACE ("data: %p\n", ovp); - - ovp->completion_func( RtlNtStatusToDosError ( ovp->lpOverlapped->Internal ), - ovp->lpOverlapped->InternalHigh, - ovp->lpOverlapped ); - - fileio_async_cleanup ( &ovp->async ); -} - -static void fileio_async_cleanup ( struct async_private *ovp ) -{ - HeapFree ( GetProcessHeap(), 0, ovp ); -} - /*********************************************************************** * FILE_ConvertOFMode * @@ -217,42 +138,6 @@ 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 * @@ -1533,575 +1418,180 @@ HFILE16 WINAPI _lclose16( HFILE16 hFile ) } -/*********************************************************************** - * GetOverlappedResult (KERNEL32.@) +/****************************************************************** + * FILE_ReadWriteApc (internal) * - * Check the result of an Asynchronous data transfer from a file. - * - * RETURNS - * TRUE on success - * FALSE on failure - * - * If successful (and relevant) lpTransferred will hold the number of - * bytes transferred during the async operation. - * - * BUGS - * - * Currently only works for WaitCommEvent, ReadFile, WriteFile - * with communications ports. * */ -BOOL WINAPI GetOverlappedResult( - HANDLE hFile, /* [in] handle of file to check on */ - LPOVERLAPPED lpOverlapped, /* [in/out] pointer to overlapped */ - LPDWORD lpTransferred, /* [in/out] number of bytes transferred */ - BOOL bWait /* [in] wait for the transfer to complete ? */ -) { - DWORD r; - - TRACE("(%p %p %p %x)\n", hFile, lpOverlapped, lpTransferred, bWait); - - if(lpOverlapped==NULL) - { - ERR("lpOverlapped was null\n"); - return FALSE; - } - if(!lpOverlapped->hEvent) - { - ERR("lpOverlapped->hEvent was null\n"); - return FALSE; - } - - if ( bWait ) - { - do { - TRACE("waiting on %p\n",lpOverlapped); - r = WaitForSingleObjectEx(lpOverlapped->hEvent, INFINITE, TRUE); - TRACE("wait on %p returned %ld\n",lpOverlapped,r); - } while (r==STATUS_USER_APC); - } - else if ( lpOverlapped->Internal == STATUS_PENDING ) - { - /* Wait in order to give APCs a chance to run. */ - /* This is cheating, so we must set the event again in case of success - - it may be a non-manual reset event. */ - do { - TRACE("waiting on %p\n",lpOverlapped); - r = WaitForSingleObjectEx(lpOverlapped->hEvent, 0, TRUE); - TRACE("wait on %p returned %ld\n",lpOverlapped,r); - } while (r==STATUS_USER_APC); - if ( r == WAIT_OBJECT_0 ) - NtSetEvent ( lpOverlapped->hEvent, NULL ); - } - - if(lpTransferred) - *lpTransferred = lpOverlapped->InternalHigh; - - switch ( lpOverlapped->Internal ) - { - case STATUS_SUCCESS: - return TRUE; - case STATUS_PENDING: - SetLastError ( ERROR_IO_INCOMPLETE ); - if ( bWait ) ERR ("PENDING status after waiting!\n"); - return FALSE; - default: - SetLastError ( RtlNtStatusToDosError ( lpOverlapped->Internal ) ); - return FALSE; - } -} - -/*********************************************************************** - * CancelIo (KERNEL32.@) - */ -BOOL WINAPI CancelIo(HANDLE handle) +static void WINAPI FILE_ReadWriteApc(void* apc_user, PIO_STATUS_BLOCK io_status, ULONG len) { - async_private *ovp,*t; - - TRACE("handle = %p\n",handle); - - for (ovp = NtCurrentTeb()->pending_list; ovp; ovp = t) - { - t = ovp->next; - if ( ovp->handle == handle ) - cancel_async ( ovp ); - } - WaitForMultipleObjectsEx(0,NULL,FALSE,1,TRUE); - return TRUE; -} - -/*********************************************************************** - * FILE_AsyncReadService (INTERNAL) - * - * This function is called while the client is waiting on the - * server, so we can't make any server calls here. - */ -static void FILE_AsyncReadService(async_private *ovp) -{ - async_fileio *fileio = (async_fileio*) ovp; - LPOVERLAPPED lpOverlapped = fileio->lpOverlapped; - int result, r; - int already = lpOverlapped->InternalHigh; - - TRACE("%p %p\n", lpOverlapped, fileio->buffer ); - - /* check to see if the data is ready (non-blocking) */ - - 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))) - { - TRACE("Deferred read %d\n",errno); - r = STATUS_PENDING; - goto async_end; - } - - /* check to see if the transfer is complete */ - if(result<0) - { - r = FILE_GetNtStatus (); - goto async_end; - } - else if ( result == 0 ) - { - r = ( lpOverlapped->InternalHigh ? STATUS_SUCCESS : STATUS_END_OF_FILE ); - 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 || fileio->fd_type == FD_TYPE_SOCKET ) - r = STATUS_SUCCESS; - else - r = STATUS_PENDING; - -async_end: - lpOverlapped->Internal = r; -} - -/*********************************************************************** - * FILE_ReadFileEx (INTERNAL) - */ -static BOOL FILE_ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead, - LPOVERLAPPED overlapped, - LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine, - HANDLE hEvent) -{ - async_fileio *ovp; - int fd; - int flags; - enum fd_type type; - - TRACE("file %p to buf %p num %ld %p func %p\n", - hFile, buffer, bytesToRead, overlapped, lpCompletionRoutine); - - /* check that there is an overlapped struct */ - if (overlapped==NULL) - { - SetLastError(ERROR_INVALID_PARAMETER); - return FALSE; - } - - fd = FILE_GetUnixHandleType ( hFile, GENERIC_READ, &type, &flags); - if ( fd < 0 ) - { - WARN ( "Couldn't get FD\n" ); - return FALSE; - } - - ovp = (async_fileio*) HeapAlloc(GetProcessHeap(), 0, sizeof (async_fileio)); - if(!ovp) - { - TRACE("HeapAlloc Failed\n"); - SetLastError(ERROR_NOT_ENOUGH_MEMORY); - goto error; - } - - ovp->async.ops = ( lpCompletionRoutine ? &fileio_async_ops : &fileio_nocomp_async_ops ); - ovp->async.handle = hFile; - ovp->async.fd = fd; - ovp->async.type = ASYNC_TYPE_READ; - ovp->async.func = FILE_AsyncReadService; - ovp->async.event = hEvent; - ovp->lpOverlapped = overlapped; - ovp->count = bytesToRead; - ovp->completion_func = lpCompletionRoutine; - ovp->buffer = buffer; - ovp->fd_type = type; - - return !register_new_async (&ovp->async); - -error: - close (fd); - return FALSE; + LPOVERLAPPED_COMPLETION_ROUTINE cr = (LPOVERLAPPED_COMPLETION_ROUTINE)apc_user; + cr(RtlNtStatusToDosError(io_status->u.Status), len, (LPOVERLAPPED)io_status); } /*********************************************************************** * ReadFileEx (KERNEL32.@) */ BOOL WINAPI ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead, - LPOVERLAPPED overlapped, - LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine) + LPOVERLAPPED overlapped, + LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine) { - overlapped->InternalHigh = 0; - return FILE_ReadFileEx(hFile,buffer,bytesToRead,overlapped,lpCompletionRoutine, INVALID_HANDLE_VALUE); -} + LARGE_INTEGER offset; + NTSTATUS status; + PIO_STATUS_BLOCK io_status; -static BOOL FILE_TimeoutRead(HANDLE hFile, LPVOID buffer, DWORD bytesToRead, LPDWORD bytesRead) -{ - OVERLAPPED ov; - BOOL r = FALSE; - - TRACE("%p %p %ld %p\n", hFile, buffer, bytesToRead, bytesRead ); - - ZeroMemory(&ov, sizeof (OVERLAPPED)); - if(STATUS_SUCCESS==NtCreateEvent(&ov.hEvent, SYNCHRONIZE, NULL, 0, 0)) + if (!overlapped) { - if(FILE_ReadFileEx(hFile, buffer, bytesToRead, &ov, NULL, ov.hEvent)) - { - r = GetOverlappedResult(hFile, &ov, bytesRead, TRUE); - } + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; } - CloseHandle(ov.hEvent); - return r; + + offset.s.LowPart = overlapped->Offset; + offset.s.HighPart = overlapped->OffsetHigh; + io_status = (PIO_STATUS_BLOCK)overlapped; + io_status->u.Status = STATUS_PENDING; + + status = NtReadFile(hFile, NULL, FILE_ReadWriteApc, lpCompletionRoutine, + io_status, buffer, bytesToRead, &offset, NULL); + + if (status) + { + SetLastError( RtlNtStatusToDosError(status) ); + return FALSE; + } + return TRUE; } /*********************************************************************** * ReadFile (KERNEL32.@) */ BOOL WINAPI ReadFile( HANDLE hFile, LPVOID buffer, DWORD bytesToRead, - LPDWORD bytesRead, LPOVERLAPPED overlapped ) + LPDWORD bytesRead, LPOVERLAPPED overlapped ) { - int unix_handle, result, flags; - enum fd_type type; - + LARGE_INTEGER offset; + PLARGE_INTEGER poffset = NULL; + IO_STATUS_BLOCK iosb; + PIO_STATUS_BLOCK io_status = &iosb; + HANDLE hEvent = 0; + NTSTATUS status; + TRACE("%p %p %ld %p %p\n", hFile, buffer, bytesToRead, bytesRead, overlapped ); if (bytesRead) *bytesRead = 0; /* Do this before anything else */ if (!bytesToRead) return TRUE; + if (IsBadReadPtr(buffer, bytesToRead)) + { + SetLastError(ERROR_WRITE_FAULT); /* FIXME */ + return FALSE; + } if (is_console_handle(hFile)) return FILE_ReadConsole(hFile, buffer, bytesToRead, bytesRead, NULL); - unix_handle = FILE_GetUnixHandleType( hFile, GENERIC_READ, &type, &flags ); - - if (flags & FD_FLAG_OVERLAPPED) + if (overlapped != NULL) { - if (unix_handle == -1) return FALSE; - if ( (overlapped==NULL) || NtResetEvent( overlapped->hEvent, NULL ) ) - { - TRACE("Overlapped not specified or invalid event flag\n"); - close(unix_handle); - SetLastError(ERROR_INVALID_PARAMETER); - return FALSE; - } - - close(unix_handle); - overlapped->InternalHigh = 0; - - if(!FILE_ReadFileEx(hFile, buffer, bytesToRead, overlapped, NULL, overlapped->hEvent)) - return FALSE; - - if ( !GetOverlappedResult (hFile, overlapped, bytesRead, FALSE) ) - { - if ( GetLastError() == ERROR_IO_INCOMPLETE ) - SetLastError ( ERROR_IO_PENDING ); - return FALSE; - } - - return TRUE; + offset.s.LowPart = overlapped->Offset; + offset.s.HighPart = overlapped->OffsetHigh; + poffset = &offset; + hEvent = overlapped->hEvent; + io_status = (PIO_STATUS_BLOCK)overlapped; } - if (flags & FD_FLAG_TIMEOUT) + io_status->u.Status = STATUS_PENDING; + io_status->Information = 0; + + status = NtReadFile(hFile, hEvent, NULL, NULL, io_status, buffer, bytesToRead, poffset, NULL); + + if (status != STATUS_PENDING && bytesRead) + *bytesRead = io_status->Information; + + if (status && status != STATUS_END_OF_FILE) { - close(unix_handle); - return FILE_TimeoutRead(hFile, buffer, bytesToRead, bytesRead); + SetLastError( RtlNtStatusToDosError(status) ); + return FALSE; } - switch(type) - { - case FD_TYPE_SMB: - return SMB_ReadFile(hFile, buffer, bytesToRead, bytesRead, NULL); - - case FD_TYPE_DEFAULT: - /* normal unix files */ - if (unix_handle == -1) return FALSE; - if (overlapped) - { - DWORD highOffset = overlapped->OffsetHigh; - if ( (INVALID_SET_FILE_POINTER == SetFilePointer(hFile, overlapped->Offset, - &highOffset, FILE_BEGIN)) && - (GetLastError() != NO_ERROR) ) - { - close(unix_handle); - return FALSE; - } - } - break; - - default: - if (unix_handle == -1) - return FALSE; - } - - if(overlapped) - { - off_t offset = OVERLAPPED_OFFSET(overlapped); - if(lseek(unix_handle, offset, SEEK_SET) == -1) - { - close(unix_handle); - SetLastError(ERROR_INVALID_PARAMETER); - return FALSE; - } - } - - /* code for synchronous reads */ - while ((result = read( unix_handle, buffer, bytesToRead )) == -1) - { - if ((errno == EAGAIN) || (errno == EINTR)) continue; - if ((errno == EFAULT) && !IsBadWritePtr( buffer, bytesToRead )) continue; - FILE_SetDosError(); - break; - } - close( unix_handle ); - if (result == -1) return FALSE; - if (bytesRead) *bytesRead = result; return TRUE; } /*********************************************************************** - * FILE_AsyncWriteService (INTERNAL) - * - * This function is called while the client is waiting on the - * server, so we can't make any server calls here. + * WriteFileEx (KERNEL32.@) */ -static void FILE_AsyncWriteService(struct async_private *ovp) +BOOL WINAPI WriteFileEx(HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite, + LPOVERLAPPED overlapped, + LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine) { - async_fileio *fileio = (async_fileio *) ovp; - LPOVERLAPPED lpOverlapped = fileio->lpOverlapped; - int result, r; - int already = lpOverlapped->InternalHigh; + LARGE_INTEGER offset; + NTSTATUS status; + PIO_STATUS_BLOCK io_status; - TRACE("(%p %p)\n",lpOverlapped,fileio->buffer); - - /* write some data (non-blocking) */ - - 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))) - { - r = STATUS_PENDING; - goto async_end; - } - - /* check to see if the transfer is complete */ - if(result<0) - { - r = FILE_GetNtStatus (); - goto async_end; - } - - lpOverlapped->InternalHigh += result; - - TRACE("wrote %d more bytes %ld/%d so far\n",result,lpOverlapped->InternalHigh,fileio->count); - - if(lpOverlapped->InternalHigh < fileio->count) - r = STATUS_PENDING; - else - r = STATUS_SUCCESS; - -async_end: - lpOverlapped->Internal = r; -} - -/*********************************************************************** - * FILE_WriteFileEx - */ -static BOOL FILE_WriteFileEx(HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite, - LPOVERLAPPED overlapped, - LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine, - HANDLE hEvent) -{ - async_fileio *ovp; - int fd; - int flags; - enum fd_type type; - - TRACE("file %p to buf %p num %ld %p func %p handle %p\n", - hFile, buffer, bytesToWrite, overlapped, lpCompletionRoutine, hEvent); + TRACE("%p %p %ld %p %p\n", + hFile, buffer, bytesToWrite, overlapped, lpCompletionRoutine); if (overlapped == NULL) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } + offset.s.LowPart = overlapped->Offset; + offset.s.HighPart = overlapped->OffsetHigh; - fd = FILE_GetUnixHandleType ( hFile, GENERIC_WRITE, &type, &flags ); - if ( fd < 0 ) - { - TRACE( "Couldn't get FD\n" ); - return FALSE; - } + io_status = (PIO_STATUS_BLOCK)overlapped; + io_status->u.Status = STATUS_PENDING; - ovp = (async_fileio*) HeapAlloc(GetProcessHeap(), 0, sizeof (async_fileio)); - if(!ovp) - { - TRACE("HeapAlloc Failed\n"); - SetLastError(ERROR_NOT_ENOUGH_MEMORY); - goto error; - } + status = NtWriteFile(hFile, NULL, FILE_ReadWriteApc, lpCompletionRoutine, + io_status, buffer, bytesToWrite, &offset, NULL); - ovp->async.ops = ( lpCompletionRoutine ? &fileio_async_ops : &fileio_nocomp_async_ops ); - ovp->async.handle = hFile; - ovp->async.fd = fd; - ovp->async.type = ASYNC_TYPE_WRITE; - ovp->async.func = FILE_AsyncWriteService; - ovp->lpOverlapped = overlapped; - ovp->async.event = hEvent; - ovp->buffer = (LPVOID) buffer; - ovp->count = bytesToWrite; - ovp->completion_func = lpCompletionRoutine; - ovp->fd_type = type; - - return !register_new_async (&ovp->async); - -error: - close (fd); - return FALSE; -} - -/*********************************************************************** - * WriteFileEx (KERNEL32.@) - */ -BOOL WINAPI WriteFileEx(HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite, - LPOVERLAPPED overlapped, - LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine) -{ - overlapped->InternalHigh = 0; - - return FILE_WriteFileEx(hFile, buffer, bytesToWrite, overlapped, lpCompletionRoutine, INVALID_HANDLE_VALUE); + if (status) SetLastError( RtlNtStatusToDosError(status) ); + return !status; } /*********************************************************************** * WriteFile (KERNEL32.@) */ BOOL WINAPI WriteFile( HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite, - LPDWORD bytesWritten, LPOVERLAPPED overlapped ) + LPDWORD bytesWritten, LPOVERLAPPED overlapped ) { - int unix_handle, result, flags; - enum fd_type type; + HANDLE hEvent = NULL; + LARGE_INTEGER offset; + PLARGE_INTEGER poffset = NULL; + NTSTATUS status; + IO_STATUS_BLOCK iosb; + PIO_STATUS_BLOCK piosb = &iosb; - TRACE("%p %p %ld %p %p\n", hFile, buffer, bytesToWrite, - bytesWritten, overlapped ); - - if (bytesWritten) *bytesWritten = 0; /* Do this before anything else */ - if (!bytesToWrite) return TRUE; + TRACE("%p %p %ld %p %p\n", + hFile, buffer, bytesToWrite, bytesWritten, overlapped ); if (is_console_handle(hFile)) return FILE_WriteConsole(hFile, buffer, bytesToWrite, bytesWritten, NULL); - - unix_handle = FILE_GetUnixHandleType( hFile, GENERIC_WRITE, &type, &flags ); - - if (flags & FD_FLAG_OVERLAPPED) + + if (IsBadReadPtr(buffer, bytesToWrite)) { - if (unix_handle == -1) return FALSE; - if ( (overlapped==NULL) || NtResetEvent( overlapped->hEvent, NULL ) ) - { - TRACE("Overlapped not specified or invalid event flag\n"); - close(unix_handle); - SetLastError(ERROR_INVALID_PARAMETER); - return FALSE; - } - - close(unix_handle); - overlapped->InternalHigh = 0; - - if(!FILE_WriteFileEx(hFile, buffer, bytesToWrite, overlapped, NULL, overlapped->hEvent)) - return FALSE; - - if ( !GetOverlappedResult (hFile, overlapped, bytesWritten, FALSE) ) - { - if ( GetLastError() == ERROR_IO_INCOMPLETE ) - SetLastError ( ERROR_IO_PENDING ); - return FALSE; - } - - return TRUE; + SetLastError(ERROR_READ_FAULT); /* FIXME */ + return FALSE; } - switch(type) + if (overlapped) { - case FD_TYPE_DEFAULT: - if (unix_handle == -1) return FALSE; - - if(overlapped) - { - DWORD highOffset = overlapped->OffsetHigh; - if ( (INVALID_SET_FILE_POINTER == SetFilePointer(hFile, overlapped->Offset, - &highOffset, FILE_BEGIN)) && - (GetLastError() != NO_ERROR) ) - { - close(unix_handle); - return FALSE; - } - } - break; - - default: - if (unix_handle == -1) - return FALSE; - if (overlapped) - { - close(unix_handle); - SetLastError(ERROR_INVALID_PARAMETER); - return FALSE; - } - break; + offset.s.LowPart = overlapped->Offset; + offset.s.HighPart = overlapped->OffsetHigh; + poffset = &offset; + hEvent = overlapped->hEvent; + piosb = (PIO_STATUS_BLOCK)overlapped; } + piosb->u.Status = STATUS_PENDING; + piosb->Information = 0; - if(overlapped) + status = NtWriteFile(hFile, hEvent, NULL, NULL, piosb, + buffer, bytesToWrite, poffset, NULL); + if (status) { - off_t offset = OVERLAPPED_OFFSET(overlapped); - if(lseek(unix_handle, offset, SEEK_SET) == -1) - { - close(unix_handle); - SetLastError(ERROR_INVALID_PARAMETER); - return FALSE; - } + SetLastError( RtlNtStatusToDosError(status) ); + return FALSE; } + if (bytesWritten) *bytesWritten = piosb->Information; - /* synchronous file write */ - while ((result = write( unix_handle, buffer, bytesToWrite )) == -1) - { - if ((errno == EAGAIN) || (errno == EINTR)) continue; - if ((errno == EFAULT) && !IsBadReadPtr( buffer, bytesToWrite )) continue; - if (errno == ENOSPC) - SetLastError( ERROR_DISK_FULL ); - else - FILE_SetDosError(); - break; - } - close( unix_handle ); - if (result == -1) return FALSE; - if (bytesWritten) *bytesWritten = result; return TRUE; } diff --git a/files/smb.c b/files/smb.c index d727f7950ef..ee7ed18b447 100644 --- a/files/smb.c +++ b/files/smb.c @@ -100,6 +100,8 @@ #include #endif +#define NONAMELESSUNION +#define NONAMELESSSTRUCT #include "winerror.h" #include "windef.h" #include "winbase.h" @@ -202,7 +204,7 @@ static inline CHAR *SMB_nextSepA (CHAR *s) {while (*s && !SMB_isSepA (*s)) s++; * replacing separators with null characters */ -USHORT SMB_MultiplexId = 0; +static USHORT SMB_MultiplexId = 0; struct NB_Buffer { @@ -1532,16 +1534,15 @@ done: return handle; } -static BOOL SMB_GetSmbInfo(HANDLE hFile, USHORT *tree_id, USHORT *user_id, USHORT *dialect, USHORT *file_id, LPDWORD offset) +static NTSTATUS SMB_GetSmbInfo(HANDLE hFile, USHORT *tree_id, USHORT *user_id, USHORT *dialect, USHORT *file_id, LPDWORD offset) { - int r; + NTSTATUS status; SERVER_START_REQ( get_smb_info ) { req->handle = hFile; req->flags = 0; - SetLastError(0); - r = wine_server_call_err( req ); + status = wine_server_call( req ); if(tree_id) *tree_id = reply->tree_id; if(user_id) @@ -1555,12 +1556,12 @@ static BOOL SMB_GetSmbInfo(HANDLE hFile, USHORT *tree_id, USHORT *user_id, USHOR } SERVER_END_REQ; - return !r; + return status; } -static BOOL SMB_SetOffset(HANDLE hFile, DWORD offset) +static NTSTATUS SMB_SetOffset(HANDLE hFile, DWORD offset) { - int r; + NTSTATUS status; TRACE("offset = %08lx\n",offset); @@ -1569,61 +1570,53 @@ static BOOL SMB_SetOffset(HANDLE hFile, DWORD offset) req->handle = hFile; req->flags = SMBINFO_SET_OFFSET; req->offset = offset; - SetLastError(0); - r = wine_server_call_err( req ); + status = wine_server_call( req ); /* if(offset) *offset = reply->offset; */ } SERVER_END_REQ; - return !r; + return status; } -BOOL WINAPI SMB_ReadFile(HANDLE hFile, LPVOID buffer, DWORD bytesToRead, LPDWORD bytesRead, LPOVERLAPPED lpOverlapped) +NTSTATUS WINAPI SMB_ReadFile(HANDLE hFile, LPVOID buffer, DWORD bytesToRead, + PIO_STATUS_BLOCK io_status) { int fd; - DWORD total, count, offset; + DWORD count, offset; USHORT user_id, tree_id, dialect, file_id, read; - BOOL r=TRUE; - TRACE("%p %p %ld %p\n", hFile, buffer, bytesToRead, bytesRead); + TRACE("%p %p %ld %p\n", hFile, buffer, bytesToRead, io_status); - if(!SMB_GetSmbInfo(hFile, &tree_id, &user_id, &dialect, &file_id, &offset)) - return FALSE; + io_status->Information = 0; + + io_status->u.Status = SMB_GetSmbInfo(hFile, &tree_id, &user_id, &dialect, &file_id, &offset); + if (io_status->u.Status) return io_status->u.Status; fd = FILE_GetUnixHandle(hFile, GENERIC_READ); - if(fd<0) - return FALSE; + if (fd<0) return io_status->u.Status = STATUS_INVALID_HANDLE; - total = 0; while(1) { - count = bytesToRead - total; + count = bytesToRead - io_status->Information; if(count>0x400) count = 0x400; if(count==0) break; read = 0; - r = SMB_Read(fd, tree_id, user_id, dialect, file_id, offset, buffer, count, &read); - if(!r) + if (!SMB_Read(fd, tree_id, user_id, dialect, file_id, offset, buffer, count, &read)) break; if(!read) break; - total += read; + io_status->Information += read; buffer = (char*)buffer + read; offset += read; - if(total>=bytesToRead) + if(io_status->Information >= bytesToRead) break; } close(fd); - if(bytesRead) - *bytesRead = total; - - if(!SMB_SetOffset(hFile, offset)) - return FALSE; - - return r; + return io_status->u.Status = SMB_SetOffset(hFile, offset); } SMB_DIR* WINAPI SMB_FindFirst(LPCWSTR name) diff --git a/files/smb.h b/files/smb.h index e6dc5c9808f..21635531235 100644 --- a/files/smb.h +++ b/files/smb.h @@ -22,7 +22,8 @@ extern inline int SMB_isSepW (WCHAR c) {return (c == '\\' || c == '/');} extern inline int SMB_isUNCW (LPCWSTR filename) {return (filename && SMB_isSepW (filename[0]) && SMB_isSepW (filename[1]));} -extern BOOL WINAPI SMB_ReadFile(HANDLE hFile, LPVOID buffer, DWORD bytesToRead, LPDWORD bytesRead, LPOVERLAPPED lpOverlapped); +NTSTATUS WINAPI SMB_ReadFile(HANDLE hFile, LPVOID buffer, DWORD bytesToRead, + PIO_STATUS_BLOCK io_status); extern HANDLE WINAPI SMB_CreateFileW( LPCWSTR filename, DWORD access, DWORD sharing, LPSECURITY_ATTRIBUTES sa, DWORD creation, DWORD attributes, HANDLE template ); diff --git a/include/async.h b/include/async.h index ea23e62ecbd..a620f7271ea 100644 --- a/include/async.h +++ b/include/async.h @@ -27,20 +27,17 @@ #define __WINE_ASYNC_H #include "wine/server.h" +#include "winternl.h" struct async_private; typedef void (*async_handler)(struct async_private *ovp); typedef void (CALLBACK *async_call_completion_func)(ULONG_PTR data); -typedef DWORD (*async_get_status)(const struct async_private *ovp); typedef DWORD (*async_get_count)(const struct async_private *ovp); -typedef void (*async_set_status)(struct async_private *ovp, const DWORD status); typedef void (*async_cleanup)(struct async_private *ovp); typedef struct async_ops { - async_get_status get_status; - async_set_status set_status; async_get_count get_count; async_call_completion_func call_completion; async_cleanup cleanup; @@ -48,43 +45,50 @@ typedef struct async_ops typedef struct async_private { - struct async_ops *ops; - HANDLE handle; - HANDLE event; - int fd; - async_handler func; - int type; - struct async_private *next; - struct async_private *prev; + struct async_ops* ops; + HANDLE handle; + HANDLE event; + int fd; + async_handler func; + int type; + IO_STATUS_BLOCK* iosb; + struct async_private* next; + struct async_private* prev; } async_private; /* All functions declared static for Dll separation purposes */ +static void CALLBACK call_user_apc( ULONG_PTR arg1, ULONG_PTR arg2, ULONG_PTR arg3 ) +{ + PAPCFUNC func = (PAPCFUNC)arg1; + func( arg2 ); +} inline static void finish_async( async_private *ovp ) { - if(ovp->prev) + if (ovp->prev) ovp->prev->next = ovp->next; else NtCurrentTeb()->pending_list = ovp->next; - if(ovp->next) + if (ovp->next) ovp->next->prev = ovp->prev; ovp->next = ovp->prev = NULL; - close( ovp->fd ); - if( ovp->event != INVALID_HANDLE_VALUE ) + close(ovp->fd); + if ( ovp->event != INVALID_HANDLE_VALUE ) NtSetEvent( ovp->event, NULL ); if ( ovp->ops->call_completion ) - QueueUserAPC( ovp->ops->call_completion, GetCurrentThread(), (ULONG_PTR)ovp ); + NtQueueApcThread( GetCurrentThread(), call_user_apc, + (ULONG_PTR)ovp->ops->call_completion, (ULONG_PTR)ovp, 0 ); else - ovp->ops->cleanup ( ovp ); + ovp->ops->cleanup( ovp ); } -inline static BOOL __register_async( async_private *ovp, const DWORD status ) +inline static NTSTATUS __register_async( async_private *ovp, const DWORD status ) { - BOOL ret; + NTSTATUS ret; SERVER_START_REQ( register_async ) { @@ -97,23 +101,20 @@ inline static BOOL __register_async( async_private *ovp, const DWORD status ) } SERVER_END_REQ; - if ( ret ) { - SetLastError( RtlNtStatusToDosError(ret) ); - ovp->ops->set_status ( ovp, ret ); - } + if (ret) ovp->iosb->u.Status = ret; - if ( ovp->ops->get_status (ovp) != STATUS_PENDING ) - finish_async (ovp); + if ( ovp->iosb->u.Status != STATUS_PENDING ) + finish_async(ovp); return ret; } #define register_old_async(ovp) \ - __register_async (ovp, ovp->ops->get_status( ovp )); + __register_async(ovp, ovp->iosb->u.Status); -inline static BOOL register_new_async( async_private *ovp ) +inline static NTSTATUS register_new_async( async_private *ovp ) { - ovp->ops->set_status ( ovp, STATUS_PENDING ); + ovp->iosb->u.Status = STATUS_PENDING; ovp->next = NtCurrentTeb()->pending_list; ovp->prev = NULL; @@ -123,13 +124,13 @@ inline static BOOL register_new_async( async_private *ovp ) return __register_async( ovp, STATUS_PENDING ); } -inline static BOOL cancel_async ( async_private *ovp ) +inline static NTSTATUS cancel_async( async_private *ovp ) { /* avoid multiple cancellations */ - if ( ovp->ops->get_status( ovp ) != STATUS_PENDING ) - return 0; - ovp->ops->set_status ( ovp, STATUS_CANCELLED ); - return __register_async ( ovp, STATUS_CANCELLED ); + if ( ovp->iosb->u.Status != STATUS_PENDING ) + return STATUS_SUCCESS; + ovp->iosb->u.Status = STATUS_CANCELLED; + return __register_async( ovp, STATUS_CANCELLED ); } #endif /* __WINE_ASYNC_H */ diff --git a/include/winternl.h b/include/winternl.h index 446b4203cb8..5eb36af00b5 100644 --- a/include/winternl.h +++ b/include/winternl.h @@ -991,6 +991,7 @@ NTSTATUS WINAPI NtUnlockVirtualMemory(HANDLE,PVOID*,ULONG*,ULONG); NTSTATUS WINAPI NtUnmapViewOfSection(HANDLE,PVOID); NTSTATUS WINAPI NtWaitForSingleObject(HANDLE,BOOLEAN,PLARGE_INTEGER); NTSTATUS WINAPI NtWaitForMultipleObjects(ULONG,const HANDLE*,BOOLEAN,BOOLEAN,PLARGE_INTEGER); +NTSTATUS WINAPI NtWriteFile(HANDLE,HANDLE,PIO_APC_ROUTINE,PVOID,PIO_STATUS_BLOCK,const void*,ULONG,PLARGE_INTEGER,PULONG); void WINAPI RtlAcquirePebLock(void); BYTE WINAPI RtlAcquireResourceExclusive(LPRTL_RWLOCK,BYTE);