ChangeLog:
- made async.h ready for use in ntdll
+ moved it to include/wine
+ replaced all calls to kernel32 functions with ntdll equivalent
- replaced status setter/getter for wine async structures with direct access to a (now included) IO_STATUS_BLOCK structure
- since we now have a IO_STATUS_BLOCK in async_private, we no longer need in most of the user (derivated) structures a field for LPOVERLAPPED (it's stored as the IO_STATUS_BLOCK)
- rewrote the async.h users accordingly
- implemented ntdll.Nt{Read|Write}File and let kernel32.{Read|Write}File(Ex)? use those new ntdll functions
- rewrote smb read/write interfaces to be more ntdll stylish (no overlapped yet)
A+ -- Eric Pouech
diff -u -N -r -x '*~' -x '.#*' -x CVS dlls/kernel29/comm.c dlls/kernel/comm.c --- dlls/kernel29/comm.c 2003-03-15 08:44:52.000000000 +0100 +++ dlls/kernel/comm.c 2003-06-07 11:00:00.000000000 +0200 @@ -84,11 +84,13 @@ # include <sys/strtio.h> #endif +#define NONAMELESSUNION +#define NONAMELESSSTRUCT #include "winbase.h" #include "winerror.h" #include "wine/server.h" -#include "async.h" +#include "wine/async.h" #include "file.h" #include "heap.h" @@ -104,15 +106,11 @@ * 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 @@ 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 @@ 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 @@ 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 -u -N -r -x '*~' -x '.#*' -x CVS dlls/kernel29/file.c dlls/kernel/file.c --- dlls/kernel29/file.c 2003-06-24 19:22:51.000000000 +0200 +++ dlls/kernel/file.c 2003-06-24 21:22:15.000000000 +0200 @@ -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 "wine/async.h" WINE_DEFAULT_DEBUG_CHANNEL(file); @@ -45,6 +46,106 @@ **************************************************************************/ /*********************************************************************** + * 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.@) */ LONG WINAPI _hread( HFILE hFile, LPVOID buffer, LONG count) diff -u -N -r -x '*~' -x '.#*' -x CVS dlls/ntdll29/file.c dlls/ntdll/file.c --- dlls/ntdll29/file.c 2003-06-24 21:41:18.000000000 +0200 +++ dlls/ntdll/file.c 2003-06-24 21:55:27.000000000 +0200 @@ -23,6 +23,7 @@ #include <string.h> #include <stdio.h> #include <errno.h> +#include <assert.h> #ifdef HAVE_UNISTD_H # include <unistd.h> #endif @@ -35,15 +36,16 @@ #include "wine/unicode.h" #include "wine/debug.h" #include "wine/server.h" +#include "wine/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 @@ 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 = +{ + 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) { - switch (val) + 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,163 @@ * 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; + + 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); + + case FD_TYPE_DEFAULT: + /* normal unix files */ + if (unix_handle == -1) return STATUS_INVALID_HANDLE; + break; - close( fd ); + default: + FIXME("Unsupported type of fd %d\n", type); + if (unix_handle == -1) close(unix_handle); + return STATUS_INVALID_HANDLE; + } - if (result == -1) - { - return IoStatusBlock->u.Status = NTFILE_errno_to_status(errno); - } + if (offset) + { + FILE_POSITION_INFORMATION fpi; - IoStatusBlock->Information = result; - IoStatusBlock->u.Status = 0; + 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) || (errno == EFAULT)) continue; + io_status->u.Status = FILE_GetNtStatus(); + break; + } + close( unix_handle ); + return io_status->u.Status; +} - return STATUS_SUCCESS; +/*********************************************************************** + * 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 +497,111 @@ * 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 - */ -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) + * 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 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) || (errno == EFAULT)) continue; + 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 +988,7 @@ hEvent = reply->event; } SERVER_END_REQ; - if( !ret && hEvent ) + if (!ret && hEvent) { ret = NtWaitForSingleObject( hEvent, FALSE, NULL ); NtClose( hEvent ); diff -u -N -r -x '*~' -x '.#*' -x CVS dlls/ntdll29/sync.c dlls/ntdll/sync.c --- dlls/ntdll29/sync.c 2003-06-21 10:24:20.000000000 +0200 +++ dlls/ntdll/sync.c 2003-06-07 10:24:38.000000000 +0200 @@ -44,7 +44,7 @@ #define NONAMELESSSTRUCT #include "winternl.h" -#include "async.h" +#include "wine/async.h" #include "thread.h" #include "wine/server.h" #include "wine/unicode.h" @@ -446,9 +446,9 @@ 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 -u -N -r -x '*~' -x '.#*' -x CVS dlls/winsock29/socket.c dlls/winsock/socket.c --- dlls/winsock29/socket.c 2003-06-21 10:24:46.000000000 +0200 +++ dlls/winsock/socket.c 2003-06-21 14:30:52.000000000 +0200 @@ -107,6 +107,8 @@ # include <sys/time.h> #endif +#define NONAMELESSUNION +#define NONAMELESSSTRUCT #include "wine/winbase16.h" #include "wingdi.h" #include "winuser.h" @@ -145,18 +147,14 @@ /**************************************************************** * Async IO declarations ****************************************************************/ -#include "async.h" +#include "wine/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_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 @@ 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 @@ * 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ { /* 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 @@ } 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 @@ 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 @@ err = NtStatusToWSAError ( ret ); if ( !lpOverlapped ) - HeapFree ( GetProcessHeap(), 0, wsa->overlapped ); + HeapFree ( GetProcessHeap(), 0, wsa->async.iosb ); HeapFree ( GetProcessHeap(), 0, wsa ); goto err_free; } diff -u -N -r -x '*~' -x '.#*' -x CVS files29/file.c files/file.c --- files29/file.c 2003-06-24 19:20:51.000000000 +0200 +++ files/file.c 2003-06-24 21:16:59.000000000 +0200 @@ -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 @@ #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 * @@ -218,42 +139,6 @@ /*********************************************************************** - * 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. @@ -1533,575 +1418,180 @@ } -/*********************************************************************** - * GetOverlappedResult (KERNEL32.@) - * - * 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 +/****************************************************************** + * FILE_ReadWriteApc (internal) * - * 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; + LPOVERLAPPED_COMPLETION_ROUTINE cr = (LPOVERLAPPED_COMPLETION_ROUTINE)apc_user; - 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; + cr(RtlNtStatusToDosError(io_status->u.Status), len, (LPOVERLAPPED)io_status); } /*********************************************************************** - * 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) + * ReadFileEx (KERNEL32.@) */ -static BOOL FILE_ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead, - LPOVERLAPPED overlapped, - LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine, - HANDLE hEvent) +BOOL WINAPI ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead, + LPOVERLAPPED overlapped, + LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine) { - async_fileio *ovp; - int fd; - int flags; - enum fd_type type; + LARGE_INTEGER offset; + NTSTATUS status; + PIO_STATUS_BLOCK io_status; - 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) + if (!overlapped) { 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; + 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); -/*********************************************************************** - * ReadFileEx (KERNEL32.@) - */ -BOOL WINAPI ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead, - LPOVERLAPPED overlapped, - LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine) -{ - overlapped->InternalHigh = 0; - return FILE_ReadFileEx(hFile,buffer,bytesToRead,overlapped,lpCompletionRoutine, INVALID_HANDLE_VALUE); -} - -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 (status) { - if(FILE_ReadFileEx(hFile, buffer, bytesToRead, &ov, NULL, ov.hEvent)) - { - r = GetOverlappedResult(hFile, &ov, bytesRead, TRUE); - } + SetLastError( RtlNtStatusToDosError(status) ); + return FALSE; } - CloseHandle(ov.hEvent); - return r; + 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) - { - close(unix_handle); - return FILE_TimeoutRead(hFile, buffer, bytesToRead, bytesRead); - } - switch(type) - { - case FD_TYPE_SMB: - return SMB_ReadFile(hFile, buffer, bytesToRead, bytesRead, NULL); + io_status->u.Status = STATUS_PENDING; + io_status->Information = 0; - 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; + status = NtReadFile(hFile, hEvent, NULL, NULL, io_status, buffer, bytesToRead, poffset, NULL); - default: - if (unix_handle == -1) - return FALSE; - } + if (status != STATUS_PENDING && bytesRead) + *bytesRead = io_status->Information; - if(overlapped) + if (status && status != STATUS_END_OF_FILE) { - 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; } - - /* 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. - */ -static void FILE_AsyncWriteService(struct 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); - - /* 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 + * WriteFileEx (KERNEL32.@) */ -static BOOL FILE_WriteFileEx(HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite, - LPOVERLAPPED overlapped, - LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine, - HANDLE hEvent) +BOOL WINAPI WriteFileEx(HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite, + LPOVERLAPPED overlapped, + LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine) { - async_fileio *ovp; - int fd; - int flags; - enum fd_type type; + LARGE_INTEGER offset; + NTSTATUS status; + PIO_STATUS_BLOCK io_status; - 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; - } - - 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_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; -} + io_status = (PIO_STATUS_BLOCK)overlapped; + io_status->u.Status = STATUS_PENDING; -/*********************************************************************** - * WriteFileEx (KERNEL32.@) - */ -BOOL WINAPI WriteFileEx(HANDLE hFile, LPCVOID buffer, DWORD bytesToWrite, - LPOVERLAPPED overlapped, - LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine) -{ - overlapped->InternalHigh = 0; + status = NtWriteFile(hFile, NULL, FILE_ReadWriteApc, lpCompletionRoutine, + io_status, buffer, bytesToWrite, &offset, NULL); - 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; - - TRACE("%p %p %ld %p %p\n", hFile, buffer, bytesToWrite, - bytesWritten, overlapped ); + HANDLE hEvent = NULL; + LARGE_INTEGER offset; + PLARGE_INTEGER poffset = NULL; + NTSTATUS status; + IO_STATUS_BLOCK iosb; + PIO_STATUS_BLOCK piosb = &iosb; - 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 -u -N -r -x '*~' -x '.#*' -x CVS files29/smb.c files/smb.c --- files29/smb.c 2003-06-24 21:41:24.000000000 +0200 +++ files/smb.c 2003-06-24 21:35:37.000000000 +0200 @@ -100,6 +100,8 @@ #include <netdb.h> #endif +#define NONAMELESSUNION +#define NONAMELESSSTRUCT #include "winerror.h" #include "windef.h" #include "winbase.h" @@ -202,7 +204,7 @@ * replacing separators with null characters */ -USHORT SMB_MultiplexId = 0; +static USHORT SMB_MultiplexId = 0; struct NB_Buffer { @@ -1532,16 +1534,15 @@ 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 @@ } 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 @@ 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 -u -N -r -x '*~' -x '.#*' -x CVS files29/smb.h files/smb.h --- files29/smb.h 2003-06-24 21:41:24.000000000 +0200 +++ files/smb.h 2003-06-24 21:34:54.000000000 +0200 @@ -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 -u -N -r -x '*~' -x '.#*' -x CVS include29/async.h include/async.h --- include29/async.h 2002-05-07 23:07:27.000000000 +0200 +++ include/async.h 1970-01-01 01:00:00.000000000 +0100 @@ -1,135 +0,0 @@ -/* - * Structures and static functions for handling asynchronous I/O. - * - * Copyright (C) 2002 Mike McCormack, Martin Wilck - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* - * This file declares static functions. - * It should only be included by those source files that implement async I/O requests. - */ - -#ifndef __WINE_ASYNC_H -#define __WINE_ASYNC_H - -#include "wine/server.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; -} 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; -} async_private; - -/* All functions declared static for Dll separation purposes */ - -inline static void finish_async( async_private *ovp ) -{ - if(ovp->prev) - ovp->prev->next = ovp->next; - else - NtCurrentTeb()->pending_list = ovp->next; - - if(ovp->next) - ovp->next->prev = ovp->prev; - - ovp->next = ovp->prev = NULL; - - 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 ); - else - ovp->ops->cleanup ( ovp ); -} - -inline static BOOL __register_async( async_private *ovp, const DWORD status ) -{ - BOOL ret; - - SERVER_START_REQ( register_async ) - { - req->handle = ovp->handle; - req->overlapped = ovp; - req->type = ovp->type; - req->count = ovp->ops->get_count( ovp ); - req->status = status; - ret = wine_server_call( req ); - } - SERVER_END_REQ; - - if ( ret ) { - SetLastError( RtlNtStatusToDosError(ret) ); - ovp->ops->set_status ( ovp, ret ); - } - - if ( ovp->ops->get_status (ovp) != STATUS_PENDING ) - finish_async (ovp); - - return ret; -} - -#define register_old_async(ovp) \ - __register_async (ovp, ovp->ops->get_status( ovp )); - -inline static BOOL register_new_async( async_private *ovp ) -{ - ovp->ops->set_status ( ovp, STATUS_PENDING ); - - ovp->next = NtCurrentTeb()->pending_list; - ovp->prev = NULL; - if ( ovp->next ) ovp->next->prev = ovp; - NtCurrentTeb()->pending_list = ovp; - - return __register_async( ovp, STATUS_PENDING ); -} - -inline static BOOL 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 ); -} - -#endif /* __WINE_ASYNC_H */ diff -u -N -r -x '*~' -x '.#*' -x CVS include29/wine/async.h include/wine/async.h --- include29/wine/async.h 1970-01-01 01:00:00.000000000 +0100 +++ include/wine/async.h 2003-06-07 10:25:41.000000000 +0200 @@ -0,0 +1,136 @@ +/* + * Structures and static functions for handling asynchronous I/O. + * + * Copyright (C) 2002 Mike McCormack, Martin Wilck + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + * This file declares static functions. + * It should only be included by those source files that implement async I/O requests. + */ + +#ifndef __WINE_ASYNC_H +#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_count)(const struct async_private *ovp); +typedef void (*async_cleanup)(struct async_private *ovp); + +typedef struct async_ops +{ + async_get_count get_count; + async_call_completion_func call_completion; + async_cleanup cleanup; +} async_ops; + +typedef struct async_private +{ + 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) + ovp->prev->next = ovp->next; + else + NtCurrentTeb()->pending_list = ovp->next; + + if (ovp->next) + ovp->next->prev = ovp->prev; + + ovp->next = ovp->prev = NULL; + + close(ovp->fd); + if ( ovp->event != INVALID_HANDLE_VALUE ) + NtSetEvent( ovp->event, NULL ); + + if ( ovp->ops->call_completion ) + NtQueueApcThread( GetCurrentThread(), call_user_apc, + (ULONG_PTR)ovp->ops->call_completion, (ULONG_PTR)ovp, 0 ); + else + ovp->ops->cleanup( ovp ); +} + +inline static NTSTATUS __register_async( async_private *ovp, const DWORD status ) +{ + NTSTATUS ret; + + SERVER_START_REQ( register_async ) + { + req->handle = ovp->handle; + req->overlapped = ovp; + req->type = ovp->type; + req->count = ovp->ops->get_count( ovp ); + req->status = status; + ret = wine_server_call( req ); + } + SERVER_END_REQ; + + if (ret) ovp->iosb->u.Status = ret; + + if ( ovp->iosb->u.Status != STATUS_PENDING ) + finish_async(ovp); + + return ret; +} + +#define register_old_async(ovp) \ + __register_async(ovp, ovp->iosb->u.Status); + +inline static NTSTATUS register_new_async( async_private *ovp ) +{ + ovp->iosb->u.Status = STATUS_PENDING; + + ovp->next = NtCurrentTeb()->pending_list; + ovp->prev = NULL; + if ( ovp->next ) ovp->next->prev = ovp; + NtCurrentTeb()->pending_list = ovp; + + return __register_async( ovp, STATUS_PENDING ); +} + +inline static NTSTATUS cancel_async( async_private *ovp ) +{ + /* avoid multiple cancellations */ + 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 -u -N -r -x '*~' -x '.#*' -x CVS include29/winternl.h include/winternl.h --- include29/winternl.h 2003-06-24 19:19:27.000000000 +0200 +++ include/winternl.h 2003-06-24 21:14:05.000000000 +0200 @@ -991,6 +991,7 @@ 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);