- made async.h ready for use in ntdll: 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)
This commit is contained in:
Eric Pouech 2003-06-26 02:08:17 +00:00 committed by Alexandre Julliard
parent 6235e9359c
commit 9bd4f6bf15
10 changed files with 728 additions and 841 deletions

View File

@ -84,6 +84,8 @@
# include <sys/strtio.h>
#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;

View File

@ -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.@)
*/

View File

@ -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 "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 );

View File

@ -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 );

View File

@ -107,6 +107,8 @@
# include <sys/time.h>
#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;
}

View File

@ -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;
}

View File

@ -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 @@ 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)

View File

@ -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 );

View File

@ -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 */

View File

@ -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);